diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 00000000..46a4f0b9 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,5 @@ +reviews: + auto_review: + enabled: true + auto_incremental_review: true + drafts: false diff --git a/.gemini/config.yaml b/.gemini/config.yaml new file mode 100644 index 00000000..3b5e413e --- /dev/null +++ b/.gemini/config.yaml @@ -0,0 +1,23 @@ +have_fun: false + +ignore_patterns: + - "**/charts/**" + - "**/vendor/**" + - "**/zz_generated.*.go" + - "**/pkg/generated/**" + - "**/_out/**" + - "**/*.tgz" + - "**/dashboards/**/*.json" + - "**/*.patch" + - "**/*.diff" + - "**/images/*.json" + +code_review: + disable: false + comment_severity_threshold: LOW + max_review_comments: 50 + pull_request_opened: + help: false + summary: true + code_review: true + include_drafts: false diff --git a/.gemini/styleguide.md b/.gemini/styleguide.md new file mode 100644 index 00000000..7185a625 --- /dev/null +++ b/.gemini/styleguide.md @@ -0,0 +1,110 @@ +# Cozystack Review Guidelines + +## Project Architecture + +Cozystack is a Kubernetes-based PaaS built on Helm umbrella charts and FluxCD. +Packages live in `packages/{core,system,apps,extra,library,tests}/`. The `library/` group holds reusable helper charts; the `tests/` group exists because library charts are not directly testable. +Each package wraps one or more upstream Helm charts. +Go code in `cmd/`, `internal/`, `pkg/` implements Kubernetes controllers and API server. +Static CRDs are generated by `hack/update-codegen.sh` from types under `api/v1alpha1/`, `api/backups/`, and `api/dashboard/`. +App Kinds (like `Postgres`, `Kafka`) live in `api/apps/v1alpha1/` but are registered dynamically at runtime from `ApplicationDefinition` resources — they are not static CRDs. + +## Vendored Code — Critical Rules + +**Never suggest editing files inside any `charts/` directory under `packages/`.** +Those are upstream Helm charts vendored via `make update` (which runs `helm pull`). +Any direct edit is overwritten on the next update and provides zero value. + +If you find an issue that appears to live in vendored chart code: + +- For configuration-level changes: suggest overrides in the package root `values.yaml`. +- For structural changes: suggest a patch file in `packages//patches/` applied by the Makefile. +- For source-code changes in images: suggest a patch in `packages//images//patches/`. +- For true upstream bugs: point to the upstream repository and suggest an upstream issue/PR. +- Do NOT suggest creating `charts/patches/` — patches never live inside `charts/`. + +Similarly, never propose edits to: + +- `vendor/` — Go dependencies. Changes go through `go get` and `go mod tidy`. +- `zz_generated.*.go` — regenerated by `make generate`. +- `pkg/generated/` — auto-generated Kubernetes client code. +- Image digest values in `values.yaml` — set by CI via `make image`, not by humans. +- `go.mod` / `go.sum` by hand — use `go get` and `go mod tidy`. + +## Commit and PR Requirements + +Each commit must follow [Conventional Commits](https://www.conventionalcommits.org/) format: `type(scope): brief description`. + +Valid types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`. + +Valid scopes: + +- System: `dashboard`, `platform`, `cilium`, `kube-ovn`, `linstor`, `fluxcd`, `cluster-api` +- Apps: `postgres`, `mariadb`, `redis`, `kafka`, `clickhouse`, `kubernetes`, `virtual-machine` +- Meta: `api`, `hack`, `tests`, `ci`, `docs` +- Package-specific: any `` matching a directory under `packages/` + +Breaking changes: append `!` after type/scope (`feat(api)!: ...`) or add a `BREAKING CHANGE:` footer. + +Each commit must have a `Signed-off-by:` trailer (produced by `git commit --signoff`). + +PR body must contain a release note block: + +````text +```release-note +type(scope): human-readable changelog entry +``` +```` + +Flag any PR whose commits lack the Conventional Commits format or signoff, or whose body has no release-note block. + +## Helm Chart Conventions + +Packages follow an umbrella chart pattern: + +- `charts/` — vendored upstream, read-only +- `templates/` — Cozystack-specific extra manifests +- `values.yaml` — override values for the upstream chart +- `values.schema.json` — JSON Schema for dashboard UI and input validation + +When reviewing `values.schema.json`: + +- `make generate` regenerates this file and strips `title`, `description`, and `x-*` custom annotations. Do not suggest adding fields that will be stripped on the next regeneration. +- Focus on type correctness, `required` fields, `enum` values, and default values. +- Flag breaking changes: removing a field, changing its type, or narrowing its enum. + +## Sensitive Components + +**`packages/core/platform/`**: the platform chart that deploys everything. Changes here can require updates to the migration flow — the Helm hook in `packages/core/platform/templates/migration-hook.yaml` and the runner image with scripts in `packages/core/platform/images/migrations/`. Flag any change to this package that lacks a corresponding migration update or an explicit note that backward compatibility is preserved. + +**`api/apps/v1alpha1/`**: app CRD Kinds are registered at runtime from `ApplicationDefinition` resources and the matching `values.schema.json`. Suggest changes to the relevant package schema rather than hand-editing generated types. + +**RBAC, ServiceAccounts, and SecurityContext**: flag overly broad RBAC (`*` on resources or verbs without justification), missing `securityContext`, containers running as root without an explicit reason, and `hostPath`/`hostNetwork` usage without clear rationale. + +## Go Code Standards + +- Use controller-runtime patterns for reconcilers. +- Use structured logging via `logr` — flag `fmt.Print*` and `log.Print*` in controller code. +- Handle errors explicitly. Discarding meaningful errors with `_` is a bug. +- Propagate `context.Context` through call chains. Flag `context.Background()` created inside a reconciler or request handler. +- Prefer `ctrl.Result{RequeueAfter: ...}` over empty requeue for predictable reconciliation loops. +- Tests live beside the code (`*_test.go`). New behavior without tests is worth flagging. + +## What to Review Carefully + +- Logic errors, off-by-one bugs, nil dereferences. +- Missing error handling, especially in reconcilers and API handlers. +- Helm template correctness: missing `quote`, incorrect indentation, wrong scope in `with`/`range`. +- Security: permissive RBAC, privileged containers, secrets in environment variables, hardcoded credentials. +- Missing resource requests/limits on new workloads. +- Breaking changes in `values.schema.json`: removed fields, tightened types, narrower enums. + +## Anti-patterns — Do Not Flag These + +- Large JSON files in `dashboards/` — imported from upstream Grafana sources, not hand-written. +- Files under any `charts/` directory — vendored upstream, left as-is intentionally. +- Whitespace or formatting in `*.patch` / `*.diff` files — machine-applied, not authored. +- Missing comments on generated code. +- `go.sum` changes accompanying `go.mod` changes — expected and correct. +- Fork relationships for vendored tooling images — intentional (e.g., `cozystack/kilo` fork is expected). +- Absence of unit tests for vendored chart overrides — covered by E2E tests in `hack/e2e-apps/`. diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 83e427c1..2482712d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @kvaps @lllamnyp @klinch0 +* @kvaps @lllamnyp @lexfrei @androndo @IvanHunters @sircthulhu @myasnikovdaniil diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..fefdab82 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,50 @@ +--- +name: Bug report +about: Create a report to help us improve +labels: 'kind/bug' +assignees: '' + +--- + + +**Describe the bug** +A clear and concise description of what the bug is. + +**Environment** +- Cozystack version +- Provider: on-prem, Hetzner, and so on + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behaviour** +When taking the steps to reproduce, what should have happened differently? + +**Actual behaviour** +A clear and concise description of what happens when the bug occurs. Explain how the system currently behaves, including error messages, unexpected results, or incorrect functionality observed during execution. + + +**Logs** +``` +Paste any relevant logs here. Please redact tokens, passwords, private keys. +``` + +**Screenshots** +If applicable, add screenshots to help explain the problem. + +**Additional context** +Add any other context about the problem here. + +**Checklist** +- [ ] I have checked the documentation +- [ ] I have searched for similar issues +- [ ] I have included all required information +- [ ] I have provided clear steps to reproduce +- [ ] I have included relevant logs diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9a52457c..044dd6a0 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,8 +1,11 @@ + ### Release note ```release-note -[] + ``` \ No newline at end of file diff --git a/.github/labels.yml b/.github/labels.yml new file mode 100644 index 00000000..2ce04130 --- /dev/null +++ b/.github/labels.yml @@ -0,0 +1,371 @@ +# Cozystack repository labels +# +# Label conventions follow the Kubernetes scheme: +# https://github.com/kubernetes/test-infra/blob/master/label_sync/labels.md +# +# Synced into the repository by .github/workflows/labels.yaml +# (EndBug/label-sync@v2). Edit this file via pull request — UI changes +# will be overwritten on the next sync. +# +# Constraints (enforced by the validate job in labels.yaml): +# - description ≤ 100 characters (GitHub REST API limit) +# - color is a 6-character hex string (no leading #) +# - label names are unique +# - aliases do not collide with top-level names +# +# Categories: +# kind/ issue or PR type +# priority/ urgency +# triage/ review state +# lifecycle/ issue or PR lifecycle +# area/ subsystem; extensible — add when 3+ open issues exist +# do-not-merge/ PR merge blockers +# security/ security-finding severity and status (Cozystack-specific) +# size: PR size (auto-applied) +# +# `aliases:` lets EndBug/label-sync rename existing labels without losing +# references on already-tagged issues and PRs. +# +# GitHub-default labels not migrated here (`wontfix`, `invalid`) currently +# carry zero issues/PRs in this repo and will be removed in a follow-up +# cleanup PR rather than aliased to a different namespace. + +# ────────────────────────────────────────────── +# kind/ — issue or PR type +# ────────────────────────────────────────────── + +- name: kind/bug + color: 'd73a4a' + description: Categorizes issue or PR as related to a bug + aliases: ['bug'] + +- name: kind/feature + color: 'a2eeef' + description: Categorizes issue or PR as related to a new feature + aliases: ['enhancement'] + +- name: kind/documentation + color: '0075ca' + description: Categorizes issue or PR as related to documentation + aliases: ['documentation'] + +- name: kind/support + color: 'd876e3' + description: Categorizes issue as a support question + aliases: ['question'] + +- name: kind/cleanup + color: 'c7def8' + description: Categorizes issue or PR as related to cleanup of code, process, or technical debt + +- name: kind/regression + color: 'e11d21' + description: Categorizes issue or PR as related to a regression from a prior release + +- name: kind/flake + color: 'f7c6c7' + description: Categorizes issue or PR as related to a flaky test + +- name: kind/failing-test + color: 'e11d21' + description: Categorizes issue or PR as related to a consistently or frequently failing test + +- name: kind/api-change + color: 'c7def8' + description: Categorizes issue or PR as related to adding, removing, or otherwise changing an API + +- name: kind/breaking-change + color: 'e11d21' + description: Indicates the change introduces a breaking API or behaviour change + +# ────────────────────────────────────────────── +# priority/ — urgency +# ────────────────────────────────────────────── + +- name: priority/critical-urgent + color: 'e11d21' + description: Highest priority. Must be actively worked on as someone's top priority right now + +- name: priority/important-soon + color: 'eb6420' + description: Must be staffed and worked on either currently, or very soon, ideally in time for the next release + +- name: priority/important-longterm + color: 'fbca04' + description: Important over the long term, but may not be staffed and/or may need multiple releases to complete + +- name: priority/backlog + color: 'fef2c0' + description: General backlog priority. Lower than priority/important-longterm + +# ────────────────────────────────────────────── +# triage/ — review state +# ────────────────────────────────────────────── + +- name: triage/needs-triage + color: 'ededed' + description: Indicates an issue needs triage by a maintainer + +- name: triage/accepted + color: '0e8a16' + description: Indicates an issue is ready to be actively worked on + +- name: triage/needs-information + color: 'fbca04' + description: Indicates an issue needs more information in order to work on it + +- name: triage/not-reproducible + color: 'fbca04' + description: Indicates an issue can not be reproduced as described + +- name: triage/duplicate + color: 'cfd3d7' + description: Indicates an issue is a duplicate of another issue + aliases: ['duplicate'] + +- name: triage/unresolved + color: 'cfd3d7' + description: Indicates an issue that can not or will not be resolved + +# ────────────────────────────────────────────── +# lifecycle/ — issue or PR lifecycle +# ────────────────────────────────────────────── + +- name: lifecycle/active + color: '1d76db' + description: Indicates that an issue or PR is actively being worked on by a contributor + +- name: lifecycle/frozen + color: 'db5dd6' + description: Indicates that an issue or PR should not be auto-closed due to staleness + aliases: ['frozen'] + +- name: lifecycle/stale + color: 'dadada' + description: Denotes an issue or PR has remained open with no activity and has become stale + aliases: ['stale'] + +- name: lifecycle/rotten + color: '795548' + description: Denotes an issue or PR that has aged beyond stale and will be auto-closed + +# ────────────────────────────────────────────── +# area/ — subsystem (extensible) +# Add a new area/* when there are 3+ open issues on the topic. +# ────────────────────────────────────────────── + +- name: area/api + color: 'bfd4f2' + description: Issues or PRs related to the cozystack-api aggregated API server + +- name: area/ai + color: 'bfd4f2' + description: Issues or PRs related to AI agent guides, AGENTS.md, docs/agents/ + +- name: area/build + color: 'bfd4f2' + description: Issues or PRs related to image build infrastructure, multi-arch support + +- name: area/ci + color: 'bfd4f2' + description: Issues or PRs related to CI workflows, GitHub Actions, automation + +- name: area/dashboard + color: 'bfd4f2' + description: Issues or PRs related to the dashboard / UI + +- name: area/extra + color: 'bfd4f2' + description: Issues or PRs related to tenant-specific modules (packages/extra/) + +- name: area/database + color: 'bfd4f2' + description: Issues or PRs related to managed databases (postgres, mariadb, redis, etcd, kafka, clickhouse) + +- name: area/kubernetes + color: 'bfd4f2' + description: Issues or PRs related to the tenant Kubernetes app + +- name: area/monitoring + color: 'bfd4f2' + description: Issues or PRs related to the monitoring stack (vlogs, vmstack, grafana, workloadmonitor) + +- name: area/networking + color: 'bfd4f2' + description: Issues or PRs related to networking (ingress, gateway, vpn, metallb, cilium, kube-ovn) + +- name: area/platform + color: 'bfd4f2' + description: Issues or PRs related to platform infrastructure (bundle, flux, talos, installer) + +- name: area/release + color: 'bfd4f2' + description: Issues or PRs related to release tooling (changelog, backport, release pipeline) + +- name: area/storage + color: 'bfd4f2' + description: Issues or PRs related to storage (linstor, seaweedfs, bucket, velero, harbor) + +- name: area/testing + color: 'bfd4f2' + description: Issues or PRs related to testing (e2e, bats, unit tests) + +- name: area/virtualization + color: 'bfd4f2' + description: Issues or PRs related to virtualization (kubevirt, cdi, vmi, vm-import) + +- name: area/uncategorized + color: 'fbca04' + description: PR auto-labeler could not map title scope to a known area/*; please review + +# ────────────────────────────────────────────── +# do-not-merge/ — PR merge blockers (Prow convention) +# ────────────────────────────────────────────── + +- name: do-not-merge/work-in-progress + color: 'e11d21' + description: Indicates that a PR should not merge because it is a work in progress + # Both legacy spellings collapse here. EndBug processes aliases sequentially; + # the second rename hits a name collision and logs a warning — the legacy + # label survives and gets cleaned up in the follow-up dedup PR. + aliases: ['do-not-merge', 'do not merge'] + +- name: do-not-merge/hold + color: 'e11d21' + description: Indicates that a PR should not merge because someone has issued /hold + +# ────────────────────────────────────────────── +# Cozystack-specific (preserved) +# ────────────────────────────────────────────── + +- name: epic + color: 'a335ee' + description: A large development increment that brings definite value to Cozystack users + +- name: community + color: '97458a' + description: Community contributions are welcome in this issue + +- name: help wanted + color: '008672' + description: Extra attention is needed + +- name: good first issue + color: '7057ff' + description: Good for newcomers + +- name: quality-of-life + color: 'aaaaaa' + description: QoL improvements + +- name: upstream-issue + color: 'aaaaaa' + description: Requires resolving an issue in an upstream project + +- name: backport + color: 'fbca04' + description: Should change be backported on previous release + +- name: backport-previous + color: 'fbd876' + description: Backport target — previous release line + +- name: release + color: 'aaaaaa' + description: Releasing a new Cozystack version + +- name: automated + color: 'ededed' + description: Created by automation + +- name: debug + color: '704479' + description: Debugging in progress + +- name: sponsored + color: '00ff00' + description: Sponsored work + +- name: lgtm + color: '238636' + description: This PR has been approved by a maintainer + +- name: ok-to-test + color: '00ff00' + description: Indicates a non-member PR is safe to run CI on + +# ────────────────────────────────────────────── +# size: — PR size (auto-applied by sizing bot) +# ────────────────────────────────────────────── + +- name: 'size:XS' + color: '00ff00' + description: This PR changes 0-9 lines, ignoring generated files + +- name: 'size:S' + color: '77b800' + description: This PR changes 10-29 lines, ignoring generated files + +- name: 'size:M' + color: 'ebb800' + description: This PR changes 30-99 lines, ignoring generated files + +- name: 'size:L' + color: 'eb9500' + description: This PR changes 100-499 lines, ignoring generated files + +- name: 'size:XL' + color: 'ff823f' + description: This PR changes 500-999 lines, ignoring generated files + +- name: 'size:XXL' + color: 'ffb8b8' + description: This PR changes 1000+ lines, ignoring generated files + +# ────────────────────────────────────────────── +# security/ — security-finding severity and status +# ────────────────────────────────────────────── + +- name: security + color: 'aaaaaa' + description: Security-related issues and features + +- name: security/critical + color: 'd73a4a' + description: Critical security vulnerability + +- name: security/high + color: 'e99695' + description: High severity security finding + +- name: security/medium + color: 'f9c513' + description: Medium severity security finding + +- name: security/low + color: '0e8a16' + description: Low severity security finding + +- name: security/triage-needed + color: 'fbca04' + description: Needs security triage + +- name: security/confirmed + color: '1d76db' + description: Confirmed vulnerability + +- name: security/false-positive + color: 'c5def5' + description: Triaged as false positive + +- name: security/accepted-risk + color: 'bfd4f2' + description: Risk accepted with justification + +- name: security/in-progress + color: '0075ca' + description: Fix in progress + +- name: security/fixed + color: '0e8a16' + description: Fix released diff --git a/.github/workflows/auto-release.yaml b/.github/workflows/auto-release.yaml new file mode 100644 index 00000000..44ca8ca6 --- /dev/null +++ b/.github/workflows/auto-release.yaml @@ -0,0 +1,196 @@ +name: Auto Patch Release + +on: + schedule: + # Run daily at 2:00 AM CET (1:00 UTC in winter, 0:00 UTC in summer) + # Using 1:00 UTC to approximate 2:00 AM CET + - cron: '0 1 * * *' + workflow_dispatch: # Allow manual trigger + +concurrency: + group: auto-release-${{ github.workflow }} + cancel-in-progress: false + +jobs: + auto-release: + name: Auto Patch Release + runs-on: [self-hosted] + permissions: + contents: write + pull-requests: read + + steps: + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} + private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} + owner: cozystack + + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Configure git + env: + APP_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + git config user.name "cozystack-ci[bot]" + git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com" + git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY} + git config --unset-all http.https://github.com/.extraheader || true + + - name: Process release branches + uses: actions/github-script@v7 + env: + APP_TOKEN: ${{ steps.app-token.outputs.token }} + with: + github-token: ${{ steps.app-token.outputs.token }} + script: | + const { execSync } = require('child_process'); + + // Configure git to use GitHub App token for authentication + execSync('git config user.name "cozystack-ci[bot]"', { encoding: 'utf8' }); + execSync('git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com"', { encoding: 'utf8' }); + execSync(`git remote set-url origin https://x-access-token:${process.env.APP_TOKEN}@github.com/${process.env.GITHUB_REPOSITORY}`, { encoding: 'utf8' }); + // Remove GITHUB_TOKEN extraheader to ensure App token is used (needed to trigger other workflows) + execSync('git config --unset-all http.https://github.com/.extraheader || true', { encoding: 'utf8' }); + + // Get all release-X.Y branches + const branches = execSync('git branch -r | grep -E "origin/release-[0-9]+\\.[0-9]+$" | sed "s|origin/||" | tr -d " "', { encoding: 'utf8' }) + .split('\n') + .filter(b => b.trim()) + .filter(b => /^release-\d+\.\d+$/.test(b)); + + console.log(`Found ${branches.length} release branches: ${branches.join(', ')}`); + + // Get all published releases (not draft) + const allReleases = await github.rest.repos.listReleases({ + owner: context.repo.owner, + repo: context.repo.repo, + per_page: 100 + }); + + // Filter to only published releases (not draft) with tags matching vX.Y.Z (no suffixes) + const publishedReleases = allReleases.data + .filter(r => !r.draft) + .filter(r => /^v\d+\.\d+\.\d+$/.test(r.tag_name)); + + console.log(`Found ${publishedReleases.length} published releases without suffixes`); + + for (const branch of branches) { + console.log(`\n=== Processing branch: ${branch} ===`); + + // Extract X.Y from branch name (release-X.Y) + const match = branch.match(/^release-(\d+\.\d+)$/); + if (!match) { + console.log(` ⚠️ Branch ${branch} doesn't match pattern, skipping`); + continue; + } + + const [major, minor] = match[1].split('.'); + const versionPrefix = `v${major}.${minor}.`; + + console.log(` Looking for releases with prefix: ${versionPrefix}`); + + // Find the latest published release for this branch (vX.Y.Z without suffixes) + const branchReleases = publishedReleases + .filter(r => r.tag_name.startsWith(versionPrefix)) + .filter(r => /^v\d+\.\d+\.\d+$/.test(r.tag_name)); // Ensure no suffixes + + if (branchReleases.length === 0) { + console.log(` ⚠️ No published releases found for ${branch}, skipping`); + continue; + } + + // Sort by version (descending) to get the latest + branchReleases.sort((a, b) => { + const aVersion = a.tag_name.match(/^v(\d+)\.(\d+)\.(\d+)$/); + const bVersion = b.tag_name.match(/^v(\d+)\.(\d+)\.(\d+)$/); + if (!aVersion || !bVersion) return 0; + + const aNum = parseInt(aVersion[1]) * 10000 + parseInt(aVersion[2]) * 100 + parseInt(aVersion[3]); + const bNum = parseInt(bVersion[1]) * 10000 + parseInt(bVersion[2]) * 100 + parseInt(bVersion[3]); + return bNum - aNum; + }); + + const latestRelease = branchReleases[0]; + console.log(` ✅ Latest published release: ${latestRelease.tag_name}`); + + // Get the commit SHA for this release tag + let releaseCommitSha; + try { + releaseCommitSha = execSync(`git rev-list -n 1 ${latestRelease.tag_name}`, { encoding: 'utf8' }).trim(); + console.log(` Release commit SHA: ${releaseCommitSha}`); + } catch (error) { + console.log(` ⚠️ Could not find commit for tag ${latestRelease.tag_name}, skipping`); + continue; + } + + // Checkout the branch + execSync(`git fetch origin ${branch}:${branch}`, { encoding: 'utf8' }); + execSync(`git checkout ${branch}`, { encoding: 'utf8' }); + + // Get the latest commit on the branch + const latestBranchCommit = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim(); + console.log(` Latest branch commit: ${latestBranchCommit}`); + + // Check if there are new commits after the release + const commitsAfterRelease = execSync( + `git rev-list ${releaseCommitSha}..HEAD --oneline`, + { encoding: 'utf8' } + ).trim(); + + if (!commitsAfterRelease) { + console.log(` ℹ️ No new commits after ${latestRelease.tag_name}, skipping`); + continue; + } + + console.log(` ✅ Found new commits after release:`); + console.log(commitsAfterRelease); + + // Calculate next version (Z+1) + const versionMatch = latestRelease.tag_name.match(/^v(\d+)\.(\d+)\.(\d+)$/); + if (!versionMatch) { + console.log(` ❌ Could not parse version from ${latestRelease.tag_name}, skipping`); + continue; + } + + const nextPatch = parseInt(versionMatch[3]) + 1; + const nextTag = `v${versionMatch[1]}.${versionMatch[2]}.${nextPatch}`; + + console.log(` 🏷️ Creating new tag: ${nextTag} on commit ${latestBranchCommit}`); + + // Create and push the tag with base_ref for workflow triggering + try { + // Delete local tag if exists to force update + try { + execSync(`git tag -d ${nextTag}`, { encoding: 'utf8' }); + } catch (e) { + // Tag doesn't exist locally, that's fine + } + + // Delete remote tag if exists + try { + execSync(`git push origin :refs/tags/${nextTag}`, { encoding: 'utf8' }); + } catch (e) { + // Tag doesn't exist remotely, that's fine + } + + // Create tag locally + execSync(`git tag ${nextTag} ${latestBranchCommit}`, { encoding: 'utf8' }); + + // Push tag with HEAD reference to preserve base_ref + execSync(`git push origin HEAD:refs/tags/${nextTag}`, { encoding: 'utf8' }); + console.log(` ✅ Successfully created and pushed tag ${nextTag}`); + } catch (error) { + console.log(` ❌ Error creating/pushing tag ${nextTag}: ${error.message}`); + core.setFailed(`Failed to create tag ${nextTag} for branch ${branch}`); + } + } + + console.log(`\n✅ Finished processing all release branches`); + diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index 10968e38..ed427827 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -2,7 +2,7 @@ name: Automatic Backport on: pull_request_target: - types: [closed] # fires when PR is closed (merged) + types: [closed, labeled] # fires when PR is closed (merged) or labeled concurrency: group: backport-${{ github.workflow }}-${{ github.event.pull_request.number }} @@ -13,22 +13,46 @@ permissions: pull-requests: write jobs: - backport: + # Determine which backports are needed + prepare: if: | github.event.pull_request.merged == true && - contains(github.event.pull_request.labels.*.name, 'backport') + ( + contains(github.event.pull_request.labels.*.name, 'backport') || + contains(github.event.pull_request.labels.*.name, 'backport-previous') || + (github.event.action == 'labeled' && (github.event.label.name == 'backport' || github.event.label.name == 'backport-previous')) + ) runs-on: [self-hosted] - + outputs: + backport_current: ${{ steps.labels.outputs.backport }} + backport_previous: ${{ steps.labels.outputs.backport_previous }} + current_branch: ${{ steps.branches.outputs.current_branch }} + previous_branch: ${{ steps.branches.outputs.previous_branch }} steps: - # 1. Decide which maintenance branch should receive the back‑port - - name: Determine target maintenance branch - id: target + - name: Check which labels are present + id: labels uses: actions/github-script@v7 with: script: | - let rel; + const pr = context.payload.pull_request; + const labels = pr.labels.map(l => l.name); + const isBackport = labels.includes('backport'); + const isBackportPrevious = labels.includes('backport-previous'); + + core.setOutput('backport', isBackport ? 'true' : 'false'); + core.setOutput('backport_previous', isBackportPrevious ? 'true' : 'false'); + + console.log(`backport label: ${isBackport}, backport-previous label: ${isBackportPrevious}`); + + - name: Determine target branches + id: branches + uses: actions/github-script@v7 + with: + script: | + // Get latest release + let latestRelease; try { - rel = await github.rest.repos.getLatestRelease({ + latestRelease = await github.rest.repos.getLatestRelease({ owner: context.repo.owner, repo: context.repo.repo }); @@ -36,18 +60,70 @@ jobs: core.setFailed('No existing releases found; cannot determine backport target.'); return; } - const [maj, min] = rel.data.tag_name.replace(/^v/, '').split('.'); - const branch = `release-${maj}.${min}`; - core.setOutput('branch', branch); - console.log(`Latest release ${rel.data.tag_name}; backporting to ${branch}`); + + const [maj, min] = latestRelease.data.tag_name.replace(/^v/, '').split('.'); + const currentBranch = `release-${maj}.${min}`; + const prevMin = parseInt(min) - 1; + const previousBranch = prevMin >= 0 ? `release-${maj}.${prevMin}` : ''; + + core.setOutput('current_branch', currentBranch); + core.setOutput('previous_branch', previousBranch); + + console.log(`Current branch: ${currentBranch}, Previous branch: ${previousBranch || 'N/A'}`); + + // Verify previous branch exists if we need it + if (previousBranch && '${{ steps.labels.outputs.backport_previous }}' === 'true') { + try { + await github.rest.repos.getBranch({ + owner: context.repo.owner, + repo: context.repo.repo, + branch: previousBranch + }); + console.log(`Previous branch ${previousBranch} exists`); + } catch (e) { + core.setFailed(`Previous branch ${previousBranch} does not exist.`); + return; + } + } + + backport: + needs: prepare + if: | + github.event.pull_request.merged == true && + (needs.prepare.outputs.backport_current == 'true' || needs.prepare.outputs.backport_previous == 'true') + runs-on: [self-hosted] + strategy: + matrix: + backport_type: [current, previous] + steps: + # 1. Determine target branch based on matrix + - name: Set target branch + id: target + if: | + (matrix.backport_type == 'current' && needs.prepare.outputs.backport_current == 'true') || + (matrix.backport_type == 'previous' && needs.prepare.outputs.backport_previous == 'true') + run: | + if [ "${{ matrix.backport_type }}" == "current" ]; then + echo "branch=${{ needs.prepare.outputs.current_branch }}" >> $GITHUB_OUTPUT + echo "Target branch: ${{ needs.prepare.outputs.current_branch }}" + else + echo "branch=${{ needs.prepare.outputs.previous_branch }}" >> $GITHUB_OUTPUT + echo "Target branch: ${{ needs.prepare.outputs.previous_branch }}" + fi + # 2. Checkout (required by backport‑action) - name: Checkout repository + if: steps.target.outcome == 'success' uses: actions/checkout@v4 # 3. Create the back‑port pull request - name: Create back‑port PR - uses: korthout/backport-action@v3 + id: backport + if: steps.target.outcome == 'success' + uses: korthout/backport-action@v3.2.1 with: github_token: ${{ secrets.GITHUB_TOKEN }} label_pattern: '' # don't read labels for targets target_branches: ${{ steps.target.outputs.branch }} + merge_commits: skip + conflict_resolution: draft_commit_conflicts diff --git a/.github/workflows/codegen-drift.yml b/.github/workflows/codegen-drift.yml new file mode 100644 index 00000000..a26caf5e --- /dev/null +++ b/.github/workflows/codegen-drift.yml @@ -0,0 +1,61 @@ +name: Codegen Drift Check + +on: + pull_request: + types: [opened, synchronize, reopened] + paths: + - 'api/**' + - 'pkg/apis/**' + - 'pkg/generated/**' + - 'internal/crdinstall/manifests/**' + - 'packages/system/cozystack-controller/definitions/**' + - 'packages/system/application-definition-crd/definition/**' + - 'packages/system/backup-controller/definitions/**' + - 'packages/system/backupstrategy-controller/definitions/**' + - 'hack/update-codegen.sh' + - 'hack/boilerplate.go.txt' + - 'Makefile' + - 'go.mod' + - 'go.sum' + - '.github/workflows/codegen-drift.yml' + +concurrency: + group: codegen-drift-${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + codegen-drift: + name: Verify generated code is up to date + runs-on: ubuntu-22.04 + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Pre-fetch k8s.io/code-generator module + # hack/update-codegen.sh sources kube_codegen.sh from the Go module cache. + # The module is not declared in go.mod, so fetch it explicitly at the + # version pinned in the script. + run: | + version=$(grep -oP 'code-generator@\Kv[0-9.]+' hack/update-codegen.sh) + tmpdir=$(mktemp -d) + cd "$tmpdir" + go mod init codegen-fetch + go get "k8s.io/code-generator@${version}" + + - name: Run make generate + run: make generate + + - name: Fail on drift + run: | + if [ -n "$(git status --porcelain)" ]; then + echo "::error::'make generate' produced changes. Run 'make generate' locally and commit the result." + git status --short + git diff --color=always + exit 1 + fi diff --git a/.github/workflows/labels.yaml b/.github/workflows/labels.yaml new file mode 100644 index 00000000..69c18329 --- /dev/null +++ b/.github/workflows/labels.yaml @@ -0,0 +1,84 @@ +name: Labels + +on: + pull_request: + paths: + - .github/labels.yml + - .github/workflows/labels.yaml + push: + branches: [main] + paths: + - .github/labels.yml + - .github/workflows/labels.yaml + workflow_dispatch: + schedule: + - cron: '17 4 * * 1' # Mondays at 04:17 UTC + +permissions: + contents: read + +concurrency: + group: labels-sync + cancel-in-progress: false + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Validate labels.yml schema + run: | + python3 - <<'PY' + import re, sys, yaml + + path = '.github/labels.yml' + data = yaml.safe_load(open(path)) + errors = [] + + # 1. description ≤ 100 chars (GitHub REST API limit) + for label in data: + desc = label.get('description', '') or '' + if len(desc) > 100: + errors.append(f"{label['name']}: description {len(desc)} chars (max 100)") + + # 2. color is 6-char hex without leading # + for label in data: + color = label.get('color', '') or '' + if not re.match(r'^[0-9A-Fa-f]{6}$', color): + errors.append(f"{label['name']}: bad color {color!r} (must be 6-char hex without #)") + + # 3. unique top-level names + names = [label['name'] for label in data] + dups = sorted({n for n in names if names.count(n) > 1}) + for n in dups: + errors.append(f"duplicate name: {n}") + + # 4. aliases do not collide with any top-level name + name_set = set(names) + for label in data: + for alias in (label.get('aliases') or []): + if alias in name_set: + errors.append(f"alias {alias!r} (under {label['name']!r}) collides with a top-level name") + + if errors: + for err in errors: + print(f"::error::{err}") + sys.exit(1) + + print(f"labels.yml schema OK ({len(data)} labels)") + PY + + sync: + needs: validate + if: github.event_name != 'pull_request' + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/checkout@v4 + - uses: EndBug/label-sync@v2 + with: + config-file: .github/labels.yml + delete-other-labels: false diff --git a/.github/workflows/pr-labeler.yaml b/.github/workflows/pr-labeler.yaml new file mode 100644 index 00000000..6e6f3017 --- /dev/null +++ b/.github/workflows/pr-labeler.yaml @@ -0,0 +1,206 @@ +name: PR Auto-Label + +on: + pull_request_target: + types: [opened, edited, reopened, synchronize] + +permissions: + contents: read + pull-requests: write + +jobs: + label: + runs-on: ubuntu-latest + steps: + - name: Apply labels from PR title + uses: actions/github-script@v7 + with: + script: | + // Conventional Commits types accepted by Cozystack (per docs/agents/contributing.md): + // feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert + // Mapping below maps a subset to kind/* — types not listed do not produce a kind/*. + const typeToKind = { + feat: 'kind/feature', + fix: 'kind/bug', + docs: 'kind/documentation', + chore: 'kind/cleanup', + refactor: 'kind/cleanup', + // style, perf, test, build, ci, revert — no kind mapping + }; + + // scope -> area/* mapping. Keys are the scopes observed in cozystack issues + // and PRs. Add new entries when a scope recurs (3+ times). + const scopeToArea = { + // area/api + 'api': 'area/api', + 'cozystack-api': 'area/api', + + // area/ai + 'agents': 'area/ai', + 'ai': 'area/ai', + + // area/build + 'build': 'area/build', + + // area/ci + 'ci': 'area/ci', + + // area/dashboard + 'dashboard': 'area/dashboard', + + // area/database + 'postgres': 'area/database', + 'postgres-operator': 'area/database', + 'mariadb': 'area/database', + 'mariadb-operator': 'area/database', + 'redis': 'area/database', + 'etcd': 'area/database', + 'kafka': 'area/database', + 'clickhouse': 'area/database', + + // area/extra + 'extra': 'area/extra', + + // area/kubernetes + 'kubernetes': 'area/kubernetes', + 'apps/kubernetes': 'area/kubernetes', + + // area/monitoring + 'monitoring': 'area/monitoring', + 'vlogs': 'area/monitoring', + 'vmstack': 'area/monitoring', + 'grafana': 'area/monitoring', + 'workloadmonitor': 'area/monitoring', + + // area/networking + 'ingress': 'area/networking', + 'ingress-nginx': 'area/networking', + 'gateway': 'area/networking', + 'vpn': 'area/networking', + 'metallb': 'area/networking', + 'cilium': 'area/networking', + 'kube-ovn': 'area/networking', + 'tcp-balancer': 'area/networking', + 'securitygroups': 'area/networking', + 'cozy-proxy': 'area/networking', + + // area/platform + 'platform': 'area/platform', + 'bundle': 'area/platform', + 'flux': 'area/platform', + 'fluxcd': 'area/platform', + 'cluster-api': 'area/platform', + 'talos': 'area/platform', + 'installer': 'area/platform', + 'cozyctl': 'area/platform', + 'cozystack-engine': 'area/platform', + 'cozy-lib': 'area/platform', + + // area/release + 'backport': 'area/release', + 'release': 'area/release', + + // area/storage + 'seaweedfs': 'area/storage', + 'seaweedfs-cosi-driver': 'area/storage', + 'bucket': 'area/storage', + 'linstor': 'area/storage', + 'velero': 'area/storage', + 'harbor': 'area/storage', + 'backups': 'area/storage', + + // area/testing + 'tests': 'area/testing', + 'e2e': 'area/testing', + + // area/virtualization + 'kubevirt': 'area/virtualization', + 'cdi': 'area/virtualization', + 'vmi': 'area/virtualization', + 'vm-import': 'area/virtualization', + 'virtual-machine': 'area/virtualization', + 'hami': 'area/virtualization', + 'gpu-operator': 'area/virtualization', + }; + + const pr = context.payload.pull_request; + const title = pr.title || ''; + const body = pr.body || ''; + const existing = new Set((pr.labels || []).map(l => l.name)); + const toAdd = new Set(); + + // 1. Strip "[Backport release-1.x]" prefix if present. + const backportMatch = title.match(/^\[Backport ([^\]]+)\]\s+(.+)$/); + const cleanTitle = backportMatch ? backportMatch[2] : title; + if (backportMatch) { + toAdd.add('area/release'); + toAdd.add('backport'); + } + + // 2. Try Conventional Commits form: type(scope)?(!)?: description + const conv = cleanTitle.match(/^([a-z]+)(?:\(([^)]+)\))?(!)?:\s*.+$/); + // 3. Fall back to bracket form: [scope] description + const bracket = !conv && cleanTitle.match(/^\[([^\]]+)\]\s+.+$/); + + let type = null, scopeStr = null, breaking = false; + if (conv) { + type = conv[1]; + scopeStr = conv[2] || null; + breaking = !!conv[3]; + } else if (bracket) { + scopeStr = bracket[1]; + } + + // 4. Detect BREAKING CHANGE: or BREAKING-CHANGE: footer in body. + // Conventional Commits 1.0 spec item 16 treats them as synonymous. + if (/^BREAKING[ -]CHANGE:/m.test(body)) { + breaking = true; + } + + // 5. Apply kind/* from type. + if (type) { + if (typeToKind[type]) { + toAdd.add(typeToKind[type]); + } else { + core.warning(`type "${type}" has no kind/* mapping — typo or new type? See .github/workflows/pr-labeler.yaml typeToKind`); + } + } + + // 6. Apply area/* from scope. Composite scopes split on comma. + const scopes = (scopeStr || '') + .split(/,\s*/) + .map(s => s.trim()) + .filter(Boolean); + for (const s of scopes) { + if (scopeToArea[s]) { + toAdd.add(scopeToArea[s]); + } else { + core.warning(`scope "${s}" has no area/* mapping — consider extending scopeToArea in .github/workflows/pr-labeler.yaml if it recurs`); + } + } + + // 7. kind/breaking-change. + if (breaking) { + toAdd.add('kind/breaking-change'); + } + + // 8. Fallback: no area/* applied -> area/uncategorized. + const hasArea = [...toAdd].some(l => l.startsWith('area/')); + if (!hasArea) { + toAdd.add('area/uncategorized'); + } + + // 9. Additive only — never remove existing labels. + const newLabels = [...toAdd].filter(l => !existing.has(l)); + if (newLabels.length === 0) { + core.info('No new labels to apply'); + return; + } + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + labels: newLabels, + }); + core.info(`Applied labels: ${newLabels.join(', ')}`); diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 8dcd859e..b2d82ff3 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -28,16 +28,7 @@ jobs: - name: Install generate run: | - sudo apt update - sudo apt install curl -y - sudo apt install nodejs -y - sudo apt install npm -y - - git clone --branch 2.7.0 --depth 1 https://github.com/bitnami/readme-generator-for-helm.git - cd ./readme-generator-for-helm - npm install - npm install -g @yao-pkg/pkg - pkg . -o /usr/local/bin/readme-generator + curl -sSL https://github.com/cozystack/cozyvalues-gen/releases/download/v1.3.0/cozyvalues-gen-linux-amd64.tar.gz | tar -xzvf- -C /usr/local/bin/ cozyvalues-gen - name: Run pre-commit hooks run: | diff --git a/.github/workflows/pull-requests-release.yaml b/.github/workflows/pull-requests-release.yaml index 7b047474..bb7f5da5 100644 --- a/.github/workflows/pull-requests-release.yaml +++ b/.github/workflows/pull-requests-release.yaml @@ -23,6 +23,14 @@ jobs: contains(github.event.pull_request.labels.*.name, 'release') steps: + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} + private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} + owner: cozystack + # Extract tag from branch name (branch = release-X.Y.Z*) - name: Extract tag from branch name id: get_tag @@ -46,7 +54,12 @@ jobs: fetch-depth: 0 - name: Create tag on merge commit + env: + APP_TOKEN: ${{ steps.app-token.outputs.token }} run: | + git config user.name "cozystack-ci[bot]" + git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com" + git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY} git tag -f ${{ steps.get_tag.outputs.tag }} ${{ github.sha }} git push -f origin ${{ steps.get_tag.outputs.tag }} @@ -54,7 +67,7 @@ jobs: - name: Ensure maintenance branch release-X.Y uses: actions/github-script@v7 with: - github-token: ${{ secrets.GH_PAT }} + github-token: ${{ steps.app-token.outputs.token }} 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\.]+)?$/); @@ -105,67 +118,95 @@ jobs: } } - # Get the latest published release - - name: Get the latest published release - id: latest_release - uses: actions/github-script@v7 - with: - script: | - try { - const rel = await github.rest.repos.getLatestRelease({ - owner: context.repo.owner, - repo: context.repo.repo - }); - core.setOutput('tag', rel.data.tag_name); - } catch (_) { - core.setOutput('tag', ''); - } - - # Compare current tag vs latest using semver-utils - - name: Semver compare - id: semver - uses: madhead/semver-utils@v4.3.0 - with: - version: ${{ steps.get_tag.outputs.tag }} - compare-to: ${{ steps.latest_release.outputs.tag }} - - # Derive flags: prerelease? make_latest? - - name: Calculate publish flags - id: flags - uses: actions/github-script@v7 - with: - script: | - 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-(alpha|beta|rc).N'`); - return; - } - 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 }}' === '<'; - core.setOutput('make_latest', isRc || outdated ? 'false' : 'legacy'); - - # Publish draft release with correct flags + # Publish draft release and ensure correct latest flag - name: Publish draft release uses: actions/github-script@v7 with: script: | const tag = '${{ steps.get_tag.outputs.tag }}'; + 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-(alpha|beta|rc).N'`); + return; + } + const isRc = Boolean(m[2]); + + // Parse semver string to comparable numbers + function parseSemver(v) { + const match = v.replace(/^v/, '').match(/^(\d+)\.(\d+)\.(\d+)/); + if (!match) return null; + return { + major: parseInt(match[1]), + minor: parseInt(match[2]), + patch: parseInt(match[3]) + }; + } + + // Compare two semver objects + function compareSemver(a, b) { + if (a.major !== b.major) return a.major - b.major; + if (a.minor !== b.minor) return a.minor - b.minor; + return a.patch - b.patch; + } + + const currentSemver = parseSemver(tag); + + // Get all releases const releases = await github.rest.repos.listReleases({ owner: context.repo.owner, - repo: context.repo.repo - }); - const draft = releases.data.find(r => r.tag_name === tag && r.draft); - if (!draft) throw new Error(`Draft release for ${tag} not found`); - await github.rest.repos.updateRelease({ - owner: context.repo.owner, - repo: context.repo.repo, - release_id: draft.id, - draft: false, - prerelease: ${{ steps.flags.outputs.is_rc }}, - make_latest: '${{ steps.flags.outputs.make_latest }}' + repo: context.repo.repo, + per_page: 100 }); - console.log(`🚀 Published release for ${tag}`); + // Find draft release to publish + const draft = releases.data.find(r => r.tag_name === tag && r.draft); + if (!draft) throw new Error(`Draft release for ${tag} not found`); + + // Find max semver among published releases (excluding current draft) + const publishedReleases = releases.data + .filter(r => !r.draft && !r.prerelease) + .filter(r => /^v\d+\.\d+\.\d+$/.test(r.tag_name)) + .map(r => ({ id: r.id, tag: r.tag_name, semver: parseSemver(r.tag_name) })) + .filter(r => r.semver !== null); + + let maxRelease = null; + for (const rel of publishedReleases) { + if (!maxRelease || compareSemver(rel.semver, maxRelease.semver) > 0) { + maxRelease = rel; + } + } + + // Determine if this release should be latest + const isOutdated = maxRelease && compareSemver(currentSemver, maxRelease.semver) < 0; + const makeLatest = (isRc || isOutdated) ? 'false' : 'true'; + + if (isRc) { + console.log(`🏷️ ${tag} is a prerelease, make_latest: false`); + } else if (isOutdated) { + console.log(`🏷️ ${tag} < ${maxRelease.tag} (max semver), make_latest: false`); + } else { + console.log(`🏷️ ${tag} is the highest version, make_latest: true`); + } + + // Publish the release + await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: draft.id, + draft: false, + prerelease: isRc, + make_latest: makeLatest + }); + console.log(`🚀 Published release ${tag}`); + + // If this is a backport/outdated release, ensure the correct release is marked as latest + if (isOutdated && maxRelease) { + console.log(`🔧 Ensuring ${maxRelease.tag} remains the latest release...`); + await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: maxRelease.id, + make_latest: 'true' + }); + console.log(`✅ Restored ${maxRelease.tag} as latest release`); + } diff --git a/.github/workflows/pull-requests.yaml b/.github/workflows/pull-requests.yaml index 262748d8..d9898616 100644 --- a/.github/workflows/pull-requests.yaml +++ b/.github/workflows/pull-requests.yaml @@ -1,10 +1,11 @@ name: Pull Request +env: + # TODO: unhardcode this + REGISTRY: iad.ocir.io/idyksih5sir9/cozystack on: pull_request: types: [opened, synchronize, reopened] - paths-ignore: - - 'docs/**/*' # Cancel in‑flight runs for the same PR when a new push arrives. concurrency: @@ -12,16 +13,32 @@ concurrency: cancel-in-progress: true jobs: + detect-changes: + name: Detect changes + runs-on: ubuntu-latest + outputs: + code: ${{ steps.filter.outputs.code }} + steps: + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + code: + - '!docs/**' + build: name: Build runs-on: [self-hosted] + timeout-minutes: 30 permissions: contents: read packages: write - # Never run when the PR carries the "release" label. + needs: ["detect-changes"] + # Never run when the PR carries the "release" label or only docs changed. if: | - !contains(github.event.pull_request.labels.*.name, 'release') + needs.detect-changes.outputs.code == 'true' + && !contains(github.event.pull_request.labels.*.name, 'release') steps: - name: Checkout code @@ -30,12 +47,22 @@ jobs: fetch-depth: 0 fetch-tags: true + - name: Run unit tests + run: make unit-tests + + - name: Set up Docker config + run: | + if [ -d ~/.docker ]; then + cp -r ~/.docker "${{ runner.temp }}/.docker" + fi + - name: Login to GitHub Container Registry + if: ${{ !github.event.pull_request.head.repo.fork }} uses: docker/login-action@v3 with: - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - registry: ghcr.io + username: ${{ secrets.OCIR_USER}} + password: ${{ secrets.OCIR_TOKEN }} + registry: iad.ocir.io env: DOCKER_CONFIG: ${{ runner.temp }}/.docker @@ -45,7 +72,7 @@ jobs: DOCKER_CONFIG: ${{ runner.temp }}/.docker - name: Build Talos image - run: make -C packages/core/installer talos-nocloud + run: make -C packages/core/talos talos-nocloud - name: Save git diff as patch if: "!contains(github.event.pull_request.labels.*.name, 'release')" @@ -58,12 +85,6 @@ jobs: name: pr-patch path: _out/assets/pr.patch - - name: Upload installer - uses: actions/upload-artifact@v4 - with: - name: cozystack-installer - path: _out/assets/cozystack-installer.yaml - - name: Upload Talos image uses: actions/upload-artifact@v4 with: @@ -75,10 +96,17 @@ jobs: runs-on: ubuntu-latest if: contains(github.event.pull_request.labels.*.name, 'release') outputs: - installer_id: ${{ steps.fetch_assets.outputs.installer_id }} - disk_id: ${{ steps.fetch_assets.outputs.disk_id }} + disk_id: ${{ steps.fetch_assets.outputs.disk_id }} steps: + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} + private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} + owner: cozystack + - name: Checkout code if: contains(github.event.pull_request.labels.*.name, 'release') uses: actions/checkout@v4 @@ -105,7 +133,7 @@ jobs: id: fetch_assets uses: actions/github-script@v7 with: - github-token: ${{ secrets.GH_PAT }} + github-token: ${{ steps.app-token.outputs.token }} script: | const tag = '${{ steps.get_tag.outputs.tag }}'; const releases = await github.rest.repos.listReleases({ @@ -119,19 +147,19 @@ jobs: return; } const find = (n) => draft.assets.find(a => a.name === n)?.id; - const installerId = find('cozystack-installer.yaml'); - const diskId = find('nocloud-amd64.raw.xz'); - if (!installerId || !diskId) { + const diskId = find('nocloud-amd64.raw.xz'); + if (!diskId) { core.setFailed('Required assets missing in draft release'); return; } - core.setOutput('installer_id', installerId); - core.setOutput('disk_id', diskId); + core.setOutput('disk_id', diskId); - prepare_env: - name: "Prepare environment" - runs-on: [self-hosted] + e2e: + name: "E2E Tests" + runs-on: ${{ contains(github.event.pull_request.labels.*.name, 'debug') && 'self-hosted' || 'oracle-vm-24cpu-96gb-x86-64' }} + #runs-on: [oracle-vm-32cpu-128gb-x86-64] + timeout-minutes: 120 permissions: contents: read packages: read @@ -139,6 +167,15 @@ jobs: if: ${{ always() && (needs.build.result == 'success' || needs.resolve_assets.result == 'success') }} steps: + - name: Generate GitHub App token + if: contains(github.event.pull_request.labels.*.name, 'release') + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} + private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} + owner: cozystack + # ▸ Checkout and prepare the codebase - name: Checkout code uses: actions/checkout@v4 @@ -168,16 +205,16 @@ jobs: if: contains(github.event.pull_request.labels.*.name, 'release') run: | mkdir -p _out/assets - curl -sSL -H "Authorization: token ${GH_PAT}" -H "Accept: application/octet-stream" \ + curl -sSL -H "Authorization: token ${APP_TOKEN}" -H "Accept: application/octet-stream" \ -o _out/assets/nocloud-amd64.raw.xz \ "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/assets/${{ needs.resolve_assets.outputs.disk_id }}" env: - GH_PAT: ${{ secrets.GH_PAT }} + APP_TOKEN: ${{ steps.app-token.outputs.token }} - name: Set sandbox ID run: echo "SANDBOX_NAME=cozy-e2e-sandbox-$(echo "${GITHUB_REPOSITORY}:${GITHUB_WORKFLOW}:${GITHUB_REF}" | sha256sum | cut -c1-10)" >> $GITHUB_ENV - # ▸ Start actual job steps + # ▸ Prepare environment - name: Prepare workspace run: | rm -rf /tmp/$SANDBOX_NAME @@ -197,47 +234,7 @@ jobs: done echo "✅ The task completed successfully after $attempt attempts" - install_cozystack: - name: "Install Cozystack" - runs-on: [self-hosted] - permissions: - contents: read - packages: read - needs: ["prepare_env", "resolve_assets"] - if: ${{ always() && needs.prepare_env.result == 'success' }} - - steps: - - name: Prepare _out/assets directory - run: mkdir -p _out/assets - - # ▸ Regular PR path – download artefacts produced by the *build* job - - name: "Download installer (regular PR)" - if: "!contains(github.event.pull_request.labels.*.name, 'release')" - uses: actions/download-artifact@v4 - with: - name: cozystack-installer - path: _out/assets - - # ▸ Release PR path – fetch artefacts from the corresponding draft release - - name: Download assets from draft release (release PR) - if: contains(github.event.pull_request.labels.*.name, 'release') - run: | - mkdir -p _out/assets - curl -sSL -H "Authorization: token ${GH_PAT}" -H "Accept: application/octet-stream" \ - -o _out/assets/cozystack-installer.yaml \ - "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/assets/${{ needs.resolve_assets.outputs.installer_id }}" - env: - GH_PAT: ${{ secrets.GH_PAT }} - - # ▸ Start actual job steps - - name: Set sandbox ID - run: echo "SANDBOX_NAME=cozy-e2e-sandbox-$(echo "${GITHUB_REPOSITORY}:${GITHUB_WORKFLOW}:${GITHUB_REF}" | sha256sum | cut -c1-10)" >> $GITHUB_ENV - - - name: Sync _out/assets directory - run: | - mkdir -p /tmp/$SANDBOX_NAME/_out/assets - mv _out/assets/* /tmp/$SANDBOX_NAME/_out/assets/ - + # ▸ Install Cozystack - name: Install Cozystack into sandbox run: | cd /tmp/$SANDBOX_NAME @@ -250,102 +247,77 @@ jobs: fi echo "❌ Attempt $attempt failed, retrying..." done - echo "✅ The task completed successfully after $attempt attempts." - - detect_test_matrix: - name: "Detect e2e test matrix" - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.set.outputs.matrix }} - - steps: - - uses: actions/checkout@v4 - - id: set - run: | - apps=$(find hack/e2e-apps -maxdepth 1 -mindepth 1 -name '*.bats' | \ - awk -F/ '{sub(/\..+/, "", $NF); print $NF}' | jq -R . | jq -cs .) - echo "matrix={\"app\":$apps}" >> "$GITHUB_OUTPUT" - - test_apps: - strategy: - matrix: ${{ fromJson(needs.detect_test_matrix.outputs.matrix) }} - name: Test ${{ matrix.app }} - runs-on: [self-hosted] - needs: [install_cozystack,detect_test_matrix] - if: ${{ always() && (needs.install_cozystack.result == 'success' && needs.detect_test_matrix.result == 'success') }} - - steps: - - name: Set sandbox ID - run: echo "SANDBOX_NAME=cozy-e2e-sandbox-$(echo "${GITHUB_REPOSITORY}:${GITHUB_WORKFLOW}:${GITHUB_REF}" | sha256sum | cut -c1-10)" >> $GITHUB_ENV - - - name: E2E Apps - run: | - cd /tmp/$SANDBOX_NAME - attempt=0 - until make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME test-apps-${{ matrix.app }}; do - attempt=$((attempt + 1)) - if [ $attempt -ge 3 ]; then - echo "❌ Attempt $attempt failed, exiting..." - exit 1 - fi - echo "❌ Attempt $attempt failed, retrying..." - done echo "✅ The task completed successfully after $attempt attempts" - collect_debug_information: - name: Collect debug information - runs-on: [self-hosted] - needs: [test_apps] - if: ${{ always() }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set sandbox ID - run: echo "SANDBOX_NAME=cozy-e2e-sandbox-$(echo "${GITHUB_REPOSITORY}:${GITHUB_WORKFLOW}:${GITHUB_REF}" | sha256sum | cut -c1-10)" >> $GITHUB_ENV - - - name: Collect report + - name: Run OpenAPI tests run: | cd /tmp/$SANDBOX_NAME - make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME collect-report + make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME test-openapi + + # ▸ Run E2E tests + - name: Run E2E tests + id: e2e_tests + run: | + cd /tmp/$SANDBOX_NAME + failed_tests="" + for app in $(ls hack/e2e-apps/*.bats | xargs -n1 basename | cut -d. -f1); do + echo "::group::Testing $app" + attempt=0 + success=false + until [ $attempt -ge 3 ]; do + if make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME test-apps-$app; then + success=true + break + fi + attempt=$((attempt + 1)) + echo "❌ Attempt $attempt failed, retrying..." + done + if [ "$success" = true ]; then + echo "✅ Test $app completed successfully" + else + echo "❌ Test $app failed after $attempt attempts" + failed_tests="$failed_tests $app" + fi + echo "::endgroup::" + done + if [ -n "$failed_tests" ]; then + echo "❌ Failed tests:$failed_tests" + exit 1 + fi + echo "✅ All E2E tests passed" + + # ▸ Collect debug information (always runs) + - name: Collect report + if: always() + run: | + cd /tmp/$SANDBOX_NAME + make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME collect-report || true - name: Upload cozyreport.tgz + if: always() uses: actions/upload-artifact@v4 with: name: cozyreport path: /tmp/${{ env.SANDBOX_NAME }}/_out/cozyreport.tgz - name: Collect images list + if: always() run: | cd /tmp/$SANDBOX_NAME - make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME collect-images + make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME collect-images || true - name: Upload image list + if: always() uses: actions/upload-artifact@v4 with: name: image-list path: /tmp/${{ env.SANDBOX_NAME }}/_out/images.txt - cleanup: - name: Tear down environment - runs-on: [self-hosted] - needs: [collect_debug_information] - if: ${{ always() && needs.test_apps.result == 'success' }} - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - fetch-tags: true - - - name: Set sandbox ID - run: echo "SANDBOX_NAME=cozy-e2e-sandbox-$(echo "${GITHUB_REPOSITORY}:${GITHUB_WORKFLOW}:${GITHUB_REF}" | sha256sum | cut -c1-10)" >> $GITHUB_ENV - + # ▸ Tear down environment (always runs) - name: Tear down sandbox - run: make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME delete + if: always() + run: make -C packages/core/testing SANDBOX_NAME=$SANDBOX_NAME delete || true - name: Remove workspace + if: always() run: rm -rf /tmp/$SANDBOX_NAME - - diff --git a/.github/workflows/retest.yaml b/.github/workflows/retest.yaml new file mode 100644 index 00000000..46ce8036 --- /dev/null +++ b/.github/workflows/retest.yaml @@ -0,0 +1,78 @@ +name: Retest + +on: + issue_comment: + types: [created] + +jobs: + retest: + name: Retest PR + runs-on: ubuntu-latest + if: | + github.event.issue.pull_request && + contains(github.event.comment.body, '/retest') + permissions: + actions: write + pull-requests: read + + steps: + - name: Rerun from Prepare environment + uses: actions/github-script@v7 + with: + script: | + const prNumber = context.issue.number; + + // Get the PR to find the head SHA + const pr = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber + }); + + // Find the latest workflow run for this PR + const runs = await github.rest.actions.listWorkflowRuns({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'pull-requests.yaml', + head_sha: pr.data.head.sha + }); + + if (runs.data.workflow_runs.length === 0) { + core.setFailed('No workflow runs found for this PR'); + return; + } + + const latestRun = runs.data.workflow_runs[0]; + console.log(`Found workflow run: ${latestRun.id} (${latestRun.status})`); + + // Check if workflow is waiting for approval (fork PRs) + if (latestRun.conclusion === 'action_required') { + core.setFailed('Workflow is waiting for approval. A maintainer must approve the workflow first.'); + return; + } + + // Get jobs for this run + const jobs = await github.rest.actions.listJobsForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: latestRun.id + }); + + // Find "Prepare environment" job + const prepareJob = jobs.data.jobs.find(j => j.name === 'Prepare environment'); + + if (!prepareJob) { + core.setFailed('Could not find "Prepare environment" job'); + return; + } + + console.log(`Found job: ${prepareJob.name} (id: ${prepareJob.id}, status: ${prepareJob.status})`); + + // Rerun the job + await github.rest.actions.reRunJobForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + job_id: prepareJob.id + }); + + console.log(`✅ Triggered rerun of job "${prepareJob.name}" (${prepareJob.id})`); diff --git a/.github/workflows/tags.yaml b/.github/workflows/tags.yaml index e2418962..1b68ee32 100644 --- a/.github/workflows/tags.yaml +++ b/.github/workflows/tags.yaml @@ -16,6 +16,8 @@ jobs: prepare-release: name: Prepare Release runs-on: [self-hosted] + outputs: + skip: ${{ steps.check_release.outputs.skip }} permissions: contents: write packages: write @@ -23,6 +25,14 @@ jobs: actions: write steps: + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} + private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} + owner: cozystack + # Check if a non-draft release with this tag already exists - name: Check if release already exists id: check_release @@ -113,72 +123,59 @@ jobs: - name: Commit release artifacts if: steps.check_release.outputs.skip == 'false' env: - GH_PAT: ${{ secrets.GH_PAT }} + APP_TOKEN: ${{ steps.app-token.outputs.token }} run: | - git config user.name "cozystack-bot" - git config user.email "217169706+cozystack-bot@users.noreply.github.com" - git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY} + git config user.name "cozystack-ci[bot]" + git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com" + git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY} git config --unset-all http.https://github.com/.extraheader || true git add . git commit -m "Prepare release ${GITHUB_REF#refs/tags/}" -s || echo "No changes to commit" - git push origin HEAD || true - # Get `latest_version` from latest published release - - name: Get latest published release + # Tag the api/apps/v1alpha1 submodule for pkg.go.dev + - name: Tag API submodule if: steps.check_release.outputs.skip == 'false' - id: latest_release - uses: actions/github-script@v7 - with: - script: | - try { - const rel = await github.rest.repos.getLatestRelease({ - owner: context.repo.owner, - repo: context.repo.repo - }); - core.setOutput('tag', rel.data.tag_name); - } catch (_) { - core.setOutput('tag', ''); - } + env: + APP_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + VTAG="${{ steps.tag.outputs.tag }}" + SUBTAG="api/apps/v1alpha1/${VTAG}" + git config user.name "cozystack-ci[bot]" + git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com" + git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY} + TARGET="$(git rev-parse "${VTAG}^{}")" + git tag -f "${SUBTAG}" "$TARGET" + git push -f origin "refs/tags/${SUBTAG}" - # Compare tag (A) with latest (B) - - name: Semver compare - if: steps.check_release.outputs.skip == 'false' - id: semver - uses: madhead/semver-utils@v4.3.0 - with: - version: ${{ steps.tag.outputs.tag }} # A - compare-to: ${{ steps.latest_release.outputs.tag }} # B - - # Create or reuse DRAFT GitHub Release + # Create or reuse draft release - name: Create / reuse draft release if: steps.check_release.outputs.skip == 'false' id: release uses: actions/github-script@v7 with: script: | - const tag = '${{ steps.tag.outputs.tag }}'; - const isRc = ${{ steps.tag.outputs.is_rc }}; - const outdated = '${{ steps.semver.outputs.comparison-result }}' === '<'; - const makeLatest = outdated ? false : 'legacy'; - const releases = await github.rest.repos.listReleases({ + const tag = '${{ steps.tag.outputs.tag }}'; + const isRc = ${{ steps.tag.outputs.is_rc }}; + const releases = await github.rest.repos.listReleases({ owner: context.repo.owner, repo: context.repo.repo }); - let rel = releases.data.find(r => r.tag_name === tag); + + let rel = releases.data.find(r => r.tag_name === tag); if (!rel) { rel = await github.rest.repos.createRelease({ owner: context.repo.owner, repo: context.repo.repo, - tag_name: tag, - name: tag, - draft: true, - prerelease: isRc, - make_latest: makeLatest + tag_name: tag, + name: tag, + draft: true, + prerelease: isRc // no make_latest for drafts }); console.log(`Draft release created for ${tag}`); } else { console.log(`Re-using existing release ${tag}`); } + core.setOutput('upload_url', rel.upload_url); # Build + upload assets (optional) @@ -194,11 +191,11 @@ jobs: - name: Create release branch if: steps.check_release.outputs.skip == 'false' env: - GH_PAT: ${{ secrets.GH_PAT }} + APP_TOKEN: ${{ steps.app-token.outputs.token }} run: | - git config user.name "cozystack-bot" - git config user.email "217169706+cozystack-bot@users.noreply.github.com" - git remote set-url origin https://cozystack-bot:${GH_PAT}@github.com/${GITHUB_REPOSITORY} + git config user.name "cozystack-ci[bot]" + git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com" + git remote set-url origin https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY} BRANCH="release-${GITHUB_REF#refs/tags/v}" git branch -f "$BRANCH" git push -f origin "$BRANCH" @@ -208,7 +205,7 @@ jobs: if: steps.check_release.outputs.skip == 'false' uses: actions/github-script@v7 with: - github-token: ${{ secrets.GH_PAT }} + github-token: ${{ steps.app-token.outputs.token }} script: | const version = context.ref.replace('refs/tags/v', ''); const base = '${{ steps.get_base.outputs.branch }}'; @@ -226,7 +223,7 @@ jobs: repo: context.repo.repo, head, base, - title: `Release v${version}`, + title: `chore(release): cut v${version}`, body: `This PR prepares the release \`v${version}\`.`, draft: false }); @@ -240,3 +237,312 @@ jobs: } else { console.log(`PR already exists from ${head} to ${base}`); } + + generate-changelog: + name: Generate Changelog + runs-on: [self-hosted] + needs: [prepare-release] + permissions: + contents: write + pull-requests: write + if: needs.prepare-release.result == 'success' + steps: + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} + private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} + owner: cozystack + + # Read-only token for the AI step. Minting a separate scoped token + # means the Generate changelog using AI step cannot push branches, + # open PRs, or mutate any repository even with --allow-all-tools, + # regardless of whether the agent follows the prompt's instructions. + - name: Generate read-only GitHub App token + id: app-token-read + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} + private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} + owner: cozystack + permission-contents: read + permission-pull-requests: read + permission-metadata: read + + - name: Parse tag + id: tag + uses: actions/github-script@v7 + with: + script: | + const ref = context.ref.replace('refs/tags/', ''); + const m = ref.match(/^v(\d+\.\d+\.\d+)(-(?:alpha|beta|rc)\.\d+)?$/); + if (!m) { + core.setFailed(`❌ tag '${ref}' must match 'vX.Y.Z' or 'vX.Y.Z-(alpha|beta|rc).N'`); + return; + } + const version = m[1] + (m[2] ?? ''); + + core.setOutput('version', version); + core.setOutput('tag', ref); + + - name: Checkout main branch + uses: actions/checkout@v4 + with: + ref: main + fetch-depth: 0 + fetch-tags: true + token: ${{ steps.app-token.outputs.token }} + + - name: Check if changelog already exists + id: check_changelog + run: | + CHANGELOG_FILE="docs/changelogs/v${{ steps.tag.outputs.version }}.md" + if [ -f "$CHANGELOG_FILE" ]; then + echo "exists=true" >> $GITHUB_OUTPUT + echo "Changelog file $CHANGELOG_FILE already exists" + else + echo "exists=false" >> $GITHUB_OUTPUT + echo "Changelog file $CHANGELOG_FILE does not exist" + fi + + - name: Setup Node.js + if: steps.check_changelog.outputs.exists == 'false' + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Install GitHub Copilot CLI + if: steps.check_changelog.outputs.exists == 'false' + run: npm i -g @github/copilot + + - name: Generate changelog using AI + if: steps.check_changelog.outputs.exists == 'false' + timeout-minutes: 30 + env: + COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + GH_TOKEN: ${{ steps.app-token-read.outputs.token }} + VERSION: ${{ steps.tag.outputs.version }} + run: | + copilot \ + --prompt "Generate the release changelog for tag v${VERSION}. Follow the instructions in @docs/agents/changelog.md exactly, including the 'Scope and boundaries' section at the top. Your deliverable is the single file docs/changelogs/v${VERSION}.md — write it and exit; this workflow handles branching, committing, pushing, and opening the PR." \ + --allow-all-tools --allow-all-paths < /dev/null + + - name: Create changelog branch and commit + if: steps.check_changelog.outputs.exists == 'false' + env: + APP_TOKEN: ${{ steps.app-token.outputs.token }} + VERSION: ${{ steps.tag.outputs.version }} + run: | + set -euo pipefail + + CHANGELOG_FILE="docs/changelogs/v${VERSION}.md" + CHANGELOG_BRANCH="changelog-v${VERSION}" + + if [ ! -f "$CHANGELOG_FILE" ]; then + echo "::error::Changelog file $CHANGELOG_FILE was not produced by the Generate changelog using AI step" + exit 1 + fi + if [ ! -s "$CHANGELOG_FILE" ]; then + echo "::error::Changelog file $CHANGELOG_FILE is empty" + exit 1 + fi + + # Snapshot the file across the branch switch — the checkout below + # resets tracked files to match origin/main. + TEMP_FILE="$(mktemp)" + trap 'rm -f "$TEMP_FILE"' EXIT + cp "$CHANGELOG_FILE" "$TEMP_FILE" + + git config user.name "cozystack-ci[bot]" + git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com" + git remote set-url origin "https://x-access-token:${APP_TOKEN}@github.com/${GITHUB_REPOSITORY}" + + git fetch origin main + git branch -D "$CHANGELOG_BRANCH" 2>/dev/null || true + git checkout -b "$CHANGELOG_BRANCH" origin/main + + mkdir -p "$(dirname "$CHANGELOG_FILE")" + cp "$TEMP_FILE" "$CHANGELOG_FILE" + + # The `check_changelog` step gated this job on the file being absent + # from origin/main, so `git add` + `git commit` must produce a diff. + # If they don't, something is wrong (e.g. empty file) — fail loud. + git add "$CHANGELOG_FILE" + git commit -m "docs: add changelog for v${VERSION}" -s + git push -f origin "$CHANGELOG_BRANCH" + + - name: Create PR for changelog + if: steps.check_changelog.outputs.exists == 'false' + uses: actions/github-script@v7 + with: + github-token: ${{ steps.app-token.outputs.token }} + script: | + const version = '${{ steps.tag.outputs.version }}'; + const changelogBranch = `changelog-v${version}`; + const baseBranch = 'main'; + + // Check if PR already exists + const prs = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + head: `${context.repo.owner}:${changelogBranch}`, + base: baseBranch, + state: 'open' + }); + + if (prs.data.length > 0) { + const pr = prs.data[0]; + console.log(`PR #${pr.number} already exists for changelog branch ${changelogBranch}`); + + // Update PR body with latest info + const body = `This PR adds the changelog for release \`v${version}\`.\n\n✅ Changelog has been automatically generated in \`docs/changelogs/v${version}.md\`.`; + await github.rest.pulls.update({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pr.number, + body: body + }); + console.log(`Updated existing PR #${pr.number}`); + } else { + // Create new PR + const pr = await github.rest.pulls.create({ + owner: context.repo.owner, + repo: context.repo.repo, + head: changelogBranch, + base: baseBranch, + title: `docs(release): add changelog for v${version}`, + body: `This PR adds the changelog for release \`v${version}\`.\n\n✅ Changelog has been automatically generated in \`docs/changelogs/v${version}.md\`.`, + draft: false + }); + + // Add label if needed + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.data.number, + labels: ['kind/documentation', 'automated'] + }); + + console.log(`Created PR #${pr.data.number} for changelog`); + } + + update-website-docs: + name: Update Website Docs + runs-on: [self-hosted] + needs: [generate-changelog, prepare-release] + if: needs.generate-changelog.result == 'success' && needs.prepare-release.outputs.skip != 'true' + permissions: + contents: read + steps: + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.COZYSTACK_CI_APP_ID }} + private-key: ${{ secrets.COZYSTACK_CI_PRIVATE_KEY }} + owner: cozystack + + - name: Parse tag + id: tag + uses: actions/github-script@v7 + with: + script: | + const ref = context.ref.replace('refs/tags/', ''); + const m = ref.match(/^v(\d+\.\d+\.\d+)(-(?:alpha|beta|rc)\.\d+)?$/); + if (!m) { + core.setFailed(`❌ tag '${ref}' must match 'vX.Y.Z' or 'vX.Y.Z-(alpha|beta|rc).N'`); + return; + } + const version = m[1] + (m[2] ?? ''); + core.setOutput('tag', ref); // v0.22.0 + core.setOutput('version', version); // 0.22.0 + + - name: Checkout website repo + uses: actions/checkout@v4 + with: + repository: cozystack/website + token: ${{ steps.app-token.outputs.token }} + ref: main + + # Decide whether this release promotes the `next/` trunk to a new released + # version directory. Per the website repo's contract (see website#495): + # - `make release-next` runs only for new minor/major final releases + # (tag matches `vX.Y.Z` with no prerelease suffix AND `vX.Y/` does + # not yet exist on disk). + # - Prereleases and patch releases skip this step and let + # `make update-all` handle routing on its own. + - name: Determine if this release promotes next/ + id: promote + env: + TAG: ${{ steps.tag.outputs.tag }} + run: | + if [[ ! "$TAG" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then + echo "promote=false" >> "$GITHUB_OUTPUT" + echo "Prerelease tag '$TAG' — skipping release-next." + exit 0 + fi + MAJOR="${BASH_REMATCH[1]}" + MINOR="${BASH_REMATCH[2]}" + if [[ "$MAJOR" == "0" ]]; then + DOC_VERSION="v0" + else + DOC_VERSION="v${MAJOR}.${MINOR}" + fi + if [[ -d "content/en/docs/${DOC_VERSION}" ]]; then + echo "promote=false" >> "$GITHUB_OUTPUT" + echo "content/en/docs/${DOC_VERSION}/ already exists — patch release, skipping release-next." + else + echo "promote=true" >> "$GITHUB_OUTPUT" + echo "New minor/major release ${DOC_VERSION} — will promote next/ → ${DOC_VERSION}/." + fi + + - name: Promote next/ to released version + if: steps.promote.outputs.promote == 'true' + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + TAG: ${{ steps.tag.outputs.tag }} + run: make release-next RELEASE_TAG="$TAG" + + - name: Update docs from release branch + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + TAG: ${{ steps.tag.outputs.tag }} + VERSION: ${{ steps.tag.outputs.version }} + run: make update-all BRANCH="release-$VERSION" RELEASE_TAG="$TAG" + + - name: Commit and push + id: commit + run: | + git config user.name "cozystack-ci[bot]" + git config user.email "274107086+cozystack-ci[bot]@users.noreply.github.com" + git add content hugo.yaml + if git diff --cached --quiet; then + echo "No changes to commit" + echo "changed=false" >> $GITHUB_OUTPUT + exit 0 + fi + BRANCH="update-docs-v${{ steps.tag.outputs.version }}" + git branch -D "$BRANCH" 2>/dev/null || true + git checkout -b "$BRANCH" + git commit --signoff -m "[docs] Update managed apps reference for v${{ steps.tag.outputs.version }}" + git push --force --set-upstream origin "$BRANCH" + echo "changed=true" >> $GITHUB_OUTPUT + + - name: Open pull request + if: steps.commit.outputs.changed == 'true' + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + BRANCH="update-docs-v${{ steps.tag.outputs.version }}" + pr_state=$(gh pr view "$BRANCH" --repo cozystack/website --json state --jq .state 2>/dev/null || echo "") + if [[ "$pr_state" == "OPEN" ]]; then + echo "PR already open, skipping creation." + else + gh pr create \ + --repo cozystack/website \ + --title "[docs] Update managed apps reference for v${{ steps.tag.outputs.version }}" \ + --body "Automated docs update for release \`v${{ steps.tag.outputs.version }}\`." \ + --head "update-docs-v${{ steps.tag.outputs.version }}" \ + --base main + fi diff --git a/.github/workflows/update-releasenotes.yaml b/.github/workflows/update-releasenotes.yaml new file mode 100644 index 00000000..b475511f --- /dev/null +++ b/.github/workflows/update-releasenotes.yaml @@ -0,0 +1,92 @@ +name: Update Release Notes + +on: + push: + branches: + - main + +concurrency: + group: update-releasenotes-${{ github.workflow }} + cancel-in-progress: false + +jobs: + update-releasenotes: + name: Update Release Notes + runs-on: [self-hosted] + permissions: + contents: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Update release notes from changelogs + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const path = require('path'); + + const changelogDir = 'docs/changelogs'; + + // Get releases from first page + const releases = await github.rest.repos.listReleases({ + owner: context.repo.owner, + repo: context.repo.repo, + per_page: 30 + }); + + console.log(`Found ${releases.data.length} releases (first page only)`); + + // Process each release + for (const release of releases.data) { + const tag = release.tag_name; + const changelogFile = `${tag}.md`; + const changelogPath = path.join(changelogDir, changelogFile); + + console.log(`\nProcessing release: ${tag}`); + + // Check if changelog file exists + if (!fs.existsSync(changelogPath)) { + console.log(` ⚠️ Changelog file ${changelogFile} does not exist, skipping...`); + continue; + } + + // Read changelog file content + let changelogContent; + try { + changelogContent = fs.readFileSync(changelogPath, 'utf8'); + } catch (error) { + console.log(` ❌ Error reading file ${changelogPath}: ${error.message}`); + continue; + } + + if (!changelogContent.trim()) { + console.log(` ⚠️ Changelog file ${changelogFile} is empty, skipping...`); + continue; + } + + // Check if content is already up to date + const currentBody = release.body || ''; + if (currentBody.trim() === changelogContent.trim()) { + console.log(` ✓ Content is already up to date, skipping...`); + continue; + } + + // Update release notes + try { + await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release.id, + body: changelogContent + }); + console.log(` ✅ Successfully updated release notes for ${tag}`); + } catch (error) { + console.log(` ❌ Error updating release ${tag}: ${error.message}`); + core.setFailed(`Failed to update release notes for ${tag}`); + } + } + diff --git a/.gitignore b/.gitignore index de476be5..61003de5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ _out +_repos .git .idea .vscode @@ -77,3 +78,9 @@ fabric.properties .DS_Store **/.DS_Store + +tmp/ + +# build revision marker (generated by make image-packages) +packages/core/platform/.build-revision +.claude/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9f94db8e..6492b92d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,24 +1,28 @@ repos: - repo: local hooks: - - id: gen-versions-map - name: Generate versions map and check for changes - entry: sh -c 'make -C packages/apps check-version-map && make -C packages/extra check-version-map' + - id: run-make-generate-root + name: Run 'make generate' at repo root + entry: | + flock -x .git/pre-commit.lock sh -c ' + echo "Running make generate at repo root" + make generate || exit $? + git diff --color=always | cat + ' language: system - types: [file] + files: ^(api/|pkg/apis/|pkg/generated/|internal/crdinstall/manifests/|packages/system/cozystack-controller/definitions/|packages/system/application-definition-crd/definition/|packages/system/backup-controller/definitions/|packages/system/backupstrategy-controller/definitions/|hack/update-codegen\.sh$|hack/boilerplate\.go\.txt$|Makefile$) pass_filenames: false - description: Run the script and fail if it generates changes - id: run-make-generate name: Run 'make generate' in all app directories entry: | - /bin/bash -c ' - for dir in ./packages/apps/*/; do + flock -x .git/pre-commit.lock sh -c ' + for dir in ./packages/apps/*/ ./packages/extra/*/; do if [ -d "$dir" ]; then echo "Running make generate in $dir" - (cd "$dir" && make generate) + make generate -C "$dir" || exit $? fi done git diff --color=always | cat ' - language: script + language: system files: ^.*$ diff --git a/ADOPTERS.md b/ADOPTERS.md index 80dbbce1..d6cacdc5 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -30,3 +30,6 @@ This list is sorted in chronological order, based on the submission date. | [Bootstack](https://bootstack.app/) | @mrkhachaturov | 2024-08-01| At Bootstack, we utilize a Kubernetes operator specifically designed to simplify and streamline cloud infrastructure creation.| | [gohost](https://gohost.kz/) | @karabass_off | 2024-02-01 | Our company has been working in the market of Kazakhstan for more than 15 years, providing clients with a standard set of services: VPS/VDC, IaaS, shared hosting, etc. Now we are expanding the lineup by introducing Bare Metal Kubenetes cluster under Cozystack management. | | [Urmanac](https://urmanac.com) | @kingdonb | 2024-12-04 | Urmanac is the future home of a hosting platform for the knowledge base of a community of personal server enthusiasts. We use Cozystack to provide support services for web sites hosted using both conventional deployments and on SpinKube, with WASM. | +| [Hidora](https://hikube.cloud) | @matthieu-robin | 2025-09-17 | Hidora is a Swiss cloud provider delivering managed services and infrastructure solutions through datacenters located in Switzerland, ensuring data sovereignty and reliability. Its sovereign cloud platform, Hikube, is designed to run workloads with high availability across multiple datacenters, providing enterprises with a secure and scalable foundation for their applications based on Cozystack. | +| [QOSI](https://qosi.kz) | @tabu-a | 2025-10-04 | QOSI is a non-profit organization driving open-source adoption and digital sovereignty across Kazakhstan and Central Asia. We use Cozystack as a platform for deploying sovereign, GPU-enabled clouds and educational environments under the National AI Program. Our goal is to accelerate the region’s transition toward open, self-hosted cloud-native technologies | +| [Cloupard](https://cloupard.kz/) | @serjiott | 2025-12-18 | Cloupard is a public cloud provider offering IaaS and PaaS services via datacenters in Kazakhstan and Uzbekistan. Uses CozyStack on bare metal to extend its managed PaaS offerings. | diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..1e9c4d15 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,68 @@ +# AI Agents Overview + +This file provides structured guidance for AI coding assistants and agents +working with the **Cozystack** project. + +## Activation + +**CRITICAL**: When the user asks you to do something that matches the scope of a documented process, you MUST read the corresponding documentation file and follow the instructions exactly as written. + +- **Commits, PRs, git operations** (e.g., "create a commit", "make a PR", "fix review comments", "rebase", "cherry-pick") + - Read: [`contributing.md`](./docs/agents/contributing.md) + - Action: Read the entire file and follow ALL instructions step-by-step + +- **Changelog generation** (e.g., "generate changelog", "create changelog", "prepare changelog for version X") + - Read: [`changelog.md`](./docs/agents/changelog.md) + - Action: Read the entire file and follow ALL steps in the checklist. Do NOT skip any mandatory steps + +- **Release creation** (e.g., "create release", "prepare release", "tag release", "make a release") + - Read: [`releasing.md`](./docs/agents/releasing.md) + - Action: Read the file and follow the referenced release process in `docs/release.md` + +- **Project structure, conventions, code layout** (e.g., "where should I put X", "what's the convention for Y", "how is the project organized") + - Read: [`overview.md`](./docs/agents/overview.md) + - Action: Read relevant sections to understand project structure and conventions + +- **General questions about contributing** + - Read: [`contributing.md`](./docs/agents/contributing.md) + - Action: Read the file to understand git workflow, commit format, PR process + +- **Issue and PR labeling, triage** (e.g., "label this issue", "what label should I use", "triage this", "categorize") + - Read: [`.github/labels.yml`](./.github/labels.yml) + - Action: Use labels defined there. Conventions follow the Kubernetes scheme — `kind/*` (type), `area/*` (subsystem), `priority/*` (urgency), `triage/*` (review state), `lifecycle/*` (auto-close), `do-not-merge/*` (PR blockers), `security/*` (severity) + - For `area/*`: accuracy outweighs reuse. If no existing `area/*` truly fits the change, propose a new one via PR (extend `.github/labels.yml` and the scope mapping in `.github/workflows/pr-labeler.yaml`) — do not shoehorn the change into a wrong area. `area/uncategorized` is the auto-labeler fallback; treat it as a signal to pick a fit, create a new area, or correct the PR title + - PR titles: a Conventional Commits header (`type(scope): description`, types from [`contributing.md`](./docs/agents/contributing.md)) auto-applies `kind/*` and `area/*` via `.github/workflows/pr-labeler.yaml`. Append `!` (or add a `BREAKING CHANGE:` footer) to apply `kind/breaking-change` + +**Important rules:** +- ✅ **ONLY read the file if the task matches the documented process scope** - do not read files for tasks that don't match their purpose +- ✅ **ALWAYS read the file FIRST** before starting the task (when applicable) +- ✅ **Follow instructions EXACTLY** as written in the documentation +- ✅ **Do NOT skip mandatory steps** (especially in changelog.md) +- ✅ **Do NOT assume** you know the process - always check the documentation when the task matches +- ❌ **Do NOT read files** for tasks that are outside their documented scope +- 📖 **Note**: [`overview.md`](./docs/agents/overview.md) can be useful as a reference to understand project structure and conventions, even when not explicitly required by the task + +## Project Overview + +**Cozystack** is a Kubernetes-based platform for building cloud infrastructure with managed services (databases, VMs, K8s clusters), multi-tenancy, and GitOps delivery. + +## Quick Reference + +### Code Structure +- `packages/core/` - Core platform charts (installer, platform) +- `packages/system/` - System components (CSI, CNI, operators) +- `packages/apps/` - User-facing applications in catalog +- `packages/extra/` - Tenant-specific modules +- `cmd/`, `internal/`, `pkg/` - Go code +- `api/` - Kubernetes CRDs + +### Conventions +- **Helm Charts**: Umbrella pattern, vendored upstream charts in `charts/` +- **Go Code**: Controller-runtime patterns, kubebuilder style +- **Git Commits**: Conventional Commits (`type(scope): description`) with `--signoff` + +### What NOT to Do +- ❌ Edit `/vendor/`, `zz_generated.*.go`, upstream charts directly +- ❌ Modify `go.mod`/`go.sum` manually (use `go get`) +- ❌ Force push to main/master +- ❌ Commit built artifacts from `_out` diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index fcc2428d..47ffec55 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,22 @@ # Code of Conduct Cozystack follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). + +# Cozystack Vendor Neutrality Manifesto + +Cozystack exists for the cloud-native community. We are committed to a project culture where no single company, product, or commercial agenda directs our roadmap, governance, brand, or releases. Our North Star is user value, technical excellence, and open collaboration under the CNCF umbrella. + +## Our Commitments + +- **Community-first:** Decisions prioritize the broader community over any vendor interest. +- **Open collaboration:** Ideas, discussions, and outcomes happen in public spaces; contributions are welcomed from all. +- **Merit over affiliation:** Proposals are evaluated on technical merit and user impact, not on who submits them. +- **Inclusive stewardship:** Leadership and maintenance are open to contributors who demonstrate sustained, constructive impact. +- **Technology choice:** We prefer open, pluggable designs that interoperate with multiple ecosystems and providers. +- **Neutral brand & voice:** Our name, logo, website, and documentation do not imply endorsement or preference for any vendor. +- **Transparent practices:** Funding acknowledgments, partnerships, and potential conflicts are communicated openly. +- **User trust:** Security handling, releases, and communications aim to be timely, transparent, and fair to all users. + +By contributing to Cozystack, we affirm these principles and work together to keep the project open, welcoming, and vendor-neutral. + +*— The Cozystack community* diff --git a/CONTRIBUTOR_LADDER.md b/CONTRIBUTOR_LADDER.md new file mode 100644 index 00000000..e41f6a93 --- /dev/null +++ b/CONTRIBUTOR_LADDER.md @@ -0,0 +1,151 @@ +# Contributor Ladder + +* [Contributor Ladder](#contributor-ladder) + * [Community Participant](#community-participant) + * [Contributor](#contributor) + * [Reviewer](#reviewer) + * [Maintainer](#maintainer) +* [Inactivity](#inactivity) +* [Involuntary Removal](#involuntary-removal-or-demotion) +* [Stepping Down/Emeritus Process](#stepping-downemeritus-process) +* [Contact](#contact) + + +## Contributor Ladder + +Hello! We are excited that you want to learn more about our project contributor ladder! This contributor ladder outlines the different contributor roles within the project, along with the responsibilities and privileges that come with them. Community members generally start at the first levels of the "ladder" and advance up it as their involvement in the project grows. Our project members are happy to help you advance along the contributor ladder. + +Each of the contributor roles below is organized into lists of three types of things. "Responsibilities" are things that a contributor is expected to do. "Requirements" are qualifications a person needs to meet to be in that role, and "Privileges" are things contributors on that level are entitled to. + + +### Community Participant +Description: A Community Participant engages with the project and its community, contributing their time, thoughts, etc. Community participants are usually users who have stopped being anonymous and started being active in project discussions. + +* Responsibilities: + * Must follow the [CNCF CoC](https://github.com/cncf/foundation/blob/main/code-of-conduct.md) +* How users can get involved with the community: + * Participating in community discussions + * Helping other users + * Submitting bug reports + * Commenting on issues + * Trying out new releases + * Attending community events + + +### Contributor +Description: A Contributor contributes directly to the project and adds value to it. Contributions need not be code. People at the Contributor level may be new contributors, or they may only contribute occasionally. + +* Responsibilities include: + * Follow the [CNCF CoC](https://github.com/cncf/foundation/blob/main/code-of-conduct.md) + * Follow the project [contributing guide] (https://github.com/cozystack/cozystack/blob/main/CONTRIBUTING.md) +* Requirements (one or several of the below): + * Report and sometimes resolve issues + * Occasionally submit PRs + * Contribute to the documentation + * Show up at meetings, takes notes + * Answer questions from other community members + * Submit feedback on issues and PRs + * Test releases and patches and submit reviews + * Run or helps run events + * Promote the project in public + * Help run the project infrastructure +* Privileges: + * Invitations to contributor events + * Eligible to become a Maintainer + + +### Reviewer +Description: A Reviewer has responsibility for specific code, documentation, test, or other project areas. They are collectively responsible, with other Reviewers, for reviewing all changes to those areas and indicating whether those changes are ready to merge. They have a track record of contribution and review in the project. + +Reviewers are responsible for a "specific area." This can be a specific code directory, driver, chapter of the docs, test job, event, or other clearly-defined project component that is smaller than an entire repository or subproject. Most often it is one or a set of directories in one or more Git repositories. The "specific area" below refers to this area of responsibility. + +Reviewers have all the rights and responsibilities of a Contributor, plus: + +* Responsibilities include: + * Continues to contribute regularly, as demonstrated by having at least 15 PRs a year, as demonstrated by [Cozystack devstats](https://cozystack.devstats.cncf.io). + * Following the reviewing guide + * Reviewing most Pull Requests against their specific areas of responsibility + * Reviewing at least 40 PRs per year + * Helping other contributors become reviewers +* Requirements: + * Must have successful contributions to the project, including at least one of the following: + * 10 accepted PRs, + * Reviewed 20 PRs, + * Resolved and closed 20 Issues, + * Become responsible for a key project management area, + * Or some equivalent combination or contribution + * Must have been contributing for at least 6 months + * Must be actively contributing to at least one project area + * Must have two sponsors who are also Reviewers or Maintainers, at least one of whom does not work for the same employer + * Has reviewed, or helped review, at least 20 Pull Requests + * Has analyzed and resolved test failures in their specific area + * Has demonstrated an in-depth knowledge of the specific area + * Commits to being responsible for that specific area + * Is supportive of new and occasional contributors and helps get useful PRs in shape to commit +* Additional privileges: + * Has GitHub or CI/CD rights to approve pull requests in specific directories + * Can recommend and review other contributors to become Reviewers + * May be assigned Issues and Reviews + * May give commands to CI/CD automation + * Can recommend other contributors to become Reviewers + + +The process of becoming a Reviewer is: +1. The contributor is nominated by opening a PR against the appropriate repository, which adds their GitHub username to the OWNERS file for one or more directories. +2. At least two members of the team that owns that repository or main directory, who are already Approvers, approve the PR. + + +### Maintainer +Description: Maintainers are very established contributors who are responsible for the entire project. As such, they have the ability to approve PRs against any area of the project, and are expected to participate in making decisions about the strategy and priorities of the project. + +A Maintainer must meet the responsibilities and requirements of a Reviewer, plus: + +* Responsibilities include: + * Reviewing at least 40 PRs per year, especially PRs that involve multiple parts of the project + * Mentoring new Reviewers + * Writing refactoring PRs + * Participating in CNCF maintainer activities + * Determining strategy and policy for the project + * Participating in, and leading, community meetings +* Requirements + * Experience as a Reviewer for at least 6 months + * Demonstrates a broad knowledge of the project across multiple areas + * Is able to exercise judgment for the good of the project, independent of their employer, friends, or team + * Mentors other contributors + * Can commit to spending at least 10 hours per month working on the project +* Additional privileges: + * Approve PRs to any area of the project + * Represent the project in public as a Maintainer + * Communicate with the CNCF on behalf of the project + * Have a vote in Maintainer decision-making meetings + + +Process of becoming a maintainer: +1. Any current Maintainer may nominate a current Reviewer to become a new Maintainer, by opening a PR against the root of the cozystack repository adding the nominee as an Approver in the [MAINTAINERS](https://github.com/cozystack/cozystack/blob/main/MAINTAINERS.md) file. +2. The nominee will add a comment to the PR testifying that they agree to all requirements of becoming a Maintainer. +3. A majority of the current Maintainers must then approve the PR. + + +## Inactivity +It is important for contributors to be and stay active to set an example and show commitment to the project. Inactivity is harmful to the project as it may lead to unexpected delays, contributor attrition, and a lost of trust in the project. + +* Inactivity is measured by: + * Periods of no contributions for longer than 6 months + * Periods of no communication for longer than 3 months +* Consequences of being inactive include: + * Involuntary removal or demotion + * Being asked to move to Emeritus status + +## Involuntary Removal or Demotion + +Involuntary removal/demotion of a contributor happens when responsibilities and requirements aren't being met. This may include repeated patterns of inactivity, extended period of inactivity, a period of failing to meet the requirements of your role, and/or a violation of the Code of Conduct. This process is important because it protects the community and its deliverables while also opens up opportunities for new contributors to step in. + +Involuntary removal or demotion is handled through a vote by a majority of the current Maintainers. + +## Stepping Down/Emeritus Process +If and when contributors' commitment levels change, contributors can consider stepping down (moving down the contributor ladder) vs moving to emeritus status (completely stepping away from the project). + +Contact the Maintainers about changing to Emeritus status, or reducing your contributor level. + +## Contact +* For inquiries, please reach out to: @kvaps, @tym83 diff --git a/MAINTAINERS.md b/MAINTAINERS.md index ba191681..d7061941 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -7,6 +7,8 @@ | Kingdon Barrett | [@kingdonb](https://github.com/kingdonb) | Urmanac | FluxCD and flux-operator | | Timofei Larkin | [@lllamnyp](https://github.com/lllamnyp) | 3commas | Etcd-operator Lead | | Artem Bortnikov | [@aobort](https://github.com/aobort) | Timescale | Etcd-operator Lead | -| Andrei Gumilev | [@chumkaska](https://github.com/chumkaska) | Ænix | Platform Documentation | | Timur Tukaev | [@tym83](https://github.com/tym83) | Ænix | Cozystack Website, Marketing, Community Management | | Kirill Klinchenkov | [@klinch0](https://github.com/klinch0) | Ænix | Core Maintainer | +| Nikita Bykov | [@nbykov0](https://github.com/nbykov0) | Ænix | Maintainer of ARM and stuff | +| Matthieu Robin | [@matthieu-robin](https://github.com/matthieu-robin) | Hidora | Managed Applications, Platform Quality & Benchmarking | +| Mattia Eleuteri | [@mattia-eleuteri](https://github.com/mattia-eleuteri) | Hidora | CSI, Storage, Networking & Security | diff --git a/Makefile b/Makefile index 8cc1b01e..acc9b6f6 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,6 @@ -.PHONY: manifests repos assets +.PHONY: manifests assets unit-tests helm-unit-tests bats-unit-tests preflight + +include hack/common-envs.mk build-deps: @command -V find docker skopeo jq gh helm > /dev/null @@ -9,45 +11,118 @@ build-deps: build: build-deps make -C packages/apps/http-cache image - make -C packages/apps/mysql image + make -C packages/apps/mariadb image make -C packages/apps/clickhouse image make -C packages/apps/kubernetes image - make -C packages/extra/monitoring image + make -C packages/system/monitoring image make -C packages/system/cozystack-api image make -C packages/system/cozystack-controller image + make -C packages/system/backup-controller image + make -C packages/system/backupstrategy-controller image + make -C packages/system/lineage-controller-webhook image make -C packages/system/cilium image - make -C packages/system/kubeovn image + make -C packages/system/linstor image + make -C packages/system/linstor-gui image make -C packages/system/kubeovn-webhook image + make -C packages/system/kubeovn-plunger image make -C packages/system/dashboard image make -C packages/system/metallb image make -C packages/system/kamaji image + make -C packages/system/multus image make -C packages/system/bucket image + make -C packages/system/objectstorage-controller image + make -C packages/system/grafana-operator image make -C packages/core/testing image + make -C packages/core/talos image + make -C packages/core/platform image make -C packages/core/installer image make manifests -repos: - rm -rf _out - make -C packages/apps check-version-map - make -C packages/extra check-version-map - make -C packages/system repo - make -C packages/apps repo - make -C packages/extra repo - mkdir -p _out/logos - cp ./packages/apps/*/logos/*.svg ./packages/extra/*/logos/*.svg _out/logos/ - - manifests: mkdir -p _out/assets - (cd packages/core/installer/; helm template -n cozy-installer installer .) > _out/assets/cozystack-installer.yaml + cat internal/crdinstall/manifests/*.yaml > _out/assets/cozystack-crds.yaml + # Talos variant (default) + helm template installer packages/core/installer -n cozy-system \ + --show-only templates/cozystack-operator.yaml \ + > _out/assets/cozystack-operator-talos.yaml + # Generic Kubernetes variant (k3s, kubeadm, RKE2) + helm template installer packages/core/installer -n cozy-system \ + --set cozystackOperator.variant=generic \ + --set cozystack.apiServerHost=REPLACE_ME \ + --show-only templates/cozystack-operator.yaml \ + > _out/assets/cozystack-operator-generic.yaml + # Hosted variant (managed Kubernetes) + helm template installer packages/core/installer -n cozy-system \ + --set cozystackOperator.variant=hosted \ + --show-only templates/cozystack-operator.yaml \ + > _out/assets/cozystack-operator-hosted.yaml -assets: - make -C packages/core/installer assets +cozypkg: + go build -ldflags "-X github.com/cozystack/cozystack/cmd/cozypkg/cmd.Version=v$(COZYSTACK_VERSION)" -o _out/bin/cozypkg ./cmd/cozypkg + +assets: assets-talos assets-cozypkg openapi-json + +openapi-json: + mkdir -p _out/assets + VERSION=$(shell git describe --tags --always 2>/dev/null || echo dev) go run ./tools/openapi-gen/ 2>/dev/null > _out/assets/openapi.json + +assets-talos: + make -C packages/core/talos assets + +assets-cozypkg: assets-cozypkg-linux-amd64 assets-cozypkg-linux-arm64 assets-cozypkg-darwin-amd64 assets-cozypkg-darwin-arm64 assets-cozypkg-windows-amd64 assets-cozypkg-windows-arm64 + (cd _out/assets/ && sha256sum cozypkg-*.tar.gz) > _out/assets/cozypkg-checksums.txt + +assets-cozypkg-%: + $(eval EXT := $(if $(filter windows,$(firstword $(subst -, ,$*))),.exe,)) + mkdir -p _out/assets + GOOS=$(firstword $(subst -, ,$*)) GOARCH=$(lastword $(subst -, ,$*)) go build -ldflags "-X github.com/cozystack/cozystack/cmd/cozypkg/cmd.Version=v$(COZYSTACK_VERSION)" -o _out/bin/cozypkg-$*/cozypkg$(EXT) ./cmd/cozypkg + cp LICENSE _out/bin/cozypkg-$*/LICENSE + tar -C _out/bin/cozypkg-$* -czf _out/assets/cozypkg-$*.tar.gz LICENSE cozypkg$(EXT) test: make -C packages/core/testing apply make -C packages/core/testing test +unit-tests: helm-unit-tests bats-unit-tests go-unit-tests + +helm-unit-tests: + hack/helm-unit-tests.sh + +# Scoped go test over the cozystack-api surface that this repo owns. Kept +# narrow intentionally - running `go test ./...` pulls in generated code +# round-trip suites whose behavior depends on tool versions outside this +# repo's control (kubebuilder, openapi-gen, etc.) and is better exercised +# from their generator workflows. +go-unit-tests: + go test ./pkg/registry/... ./pkg/config/... ./pkg/cmd/server/... + +# Discover every hack/*.bats file that is NOT an e2e test and run it +# through cozytest.sh. Drop a new *.bats file in hack/ and it is picked +# up automatically on the next `make unit-tests` run. +# +# Caveat: $(wildcard ...) returns space-separated names, so a filename +# containing a literal space would split into multiple tokens here. All +# current bats files use hyphen-separated names; if the project ever +# introduces whitespace-bearing filenames this recipe must be rewritten +# (e.g. to use `find ... -print0 | xargs -0`). +BATS_UNIT_FILES := $(filter-out hack/e2e-%.bats,$(wildcard hack/*.bats)) + +bats-unit-tests: + @if [ -z "$(BATS_UNIT_FILES)" ]; then \ + echo "ERROR: no hack/*.bats unit test files found"; \ + exit 1; \ + fi + @for f in $(BATS_UNIT_FILES); do \ + echo "--- running $$f ---"; \ + hack/cozytest.sh "$$f" || exit 1; \ + done + +# Operator-facing host preflight check. Warns about a standalone +# containerd.service or docker.service running alongside the embedded +# k3s runtime. Safe to run at any time; always exits 0. +preflight: + @hack/check-host-runtime.sh + prepare-env: make -C packages/core/testing apply make -C packages/core/testing prepare-cluster diff --git a/README.md b/README.md index 7d466ab7..5bc8d7be 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,12 @@ [![Support](https://img.shields.io/badge/$-support-12a0df.svg?style=flat)](https://cozystack.io/support/) [![Active](http://img.shields.io/badge/Status-Active-green.svg)](https://github.com/cozystack/cozystack) [![GitHub Release](https://img.shields.io/github/release/cozystack/cozystack.svg?style=flat)](https://github.com/cozystack/cozystack/releases/latest) -[![GitHub Commit](https://img.shields.io/github/commit-activity/y/cozystack/cozystack)](https://github.com/cozystack/cozystack/graphs/contributors) +[![GitHub Commit](https://img.shields.io/github/commit-activity/y/cozystack/cozystack)](https://github.com/cozystack/cozystack/graphs/contributors) +[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/10177/badge)](https://www.bestpractices.dev/projects/10177) # Cozystack -**Cozystack** is a free PaaS platform and framework for building clouds. +**Cozystack** is a free platform and framework for building clouds. Cozystack is a [CNCF Sandbox Level Project](https://www.cncf.io/sandbox-projects/) that was originally built and sponsored by [Ænix](https://aenix.io/). @@ -19,7 +20,7 @@ Database-as-a-Service, virtual machines, load balancers, HTTP caching services, Use Cozystack to build your own cloud or provide a cost-effective development environment. -![Cozystack user interface](https://cozystack.io/img/screenshot.png) +![Cozystack user interface](https://cozystack.io/img/screenshot-dark.png) ## Use-Cases diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..b64e533b --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,102 @@ +# Security Policy + +## Scope + +This policy applies to the [`cozystack/cozystack`](https://github.com/cozystack/cozystack) repository and to release artifacts produced from it, including Cozystack core components, operators, packaged manifests, container images, and installation assets published by the project. + +Cozystack integrates and ships many upstream cloud native components. If you believe a vulnerability originates in an upstream project rather than in Cozystack-specific code, packaging, defaults, or integration logic, please report it to the upstream project as well. If you are unsure, report it to Cozystack first and we will help route or coordinate the issue. + +## Supported Versions + +As of March 17, 2026, the Cozystack project maintains multiple release lines. Security fixes are prioritized for the latest stable release line and, when needed, backported to other supported lines. + +| Version line | Status | Notes | +| --- | --- | --- | +| `v1.1.x` | Supported | Current stable release line. | +| `v1.0.x` | Supported | Previous stable release line; receives security and important maintenance fixes. | +| `v0.41.x` | Limited support | Legacy pre-v1 line during the v0 to v1 transition; critical security and upgrade-blocking fixes may be backported at maintainer discretion. | +| `< v0.41` | Not supported | Please upgrade to a supported release line before requesting a security fix. | +| `alpha`, `beta`, `rc` releases | Not supported | Pre-release builds are for testing and evaluation only. | + +Supported versions may change over time as new release lines are cut. The authoritative source for current releases is the GitHub Releases page: + + + +## Reporting a Vulnerability + +Please do **not** report security vulnerabilities through public GitHub issues, discussions, pull requests, Telegram, Slack, or other public community channels. + +At the moment, this repository does not publish a dedicated private security mailbox in-tree. If you need to report a vulnerability: + +1. Contact one of the project maintainers listed in `CODEOWNERS` using an existing private channel you already have. +2. If you do not already have a private maintainer contact, use a public community channel only to request a private contact path, without disclosing any vulnerability details. + +Please do not include exploit details, credentials, tokens, private keys, customer data, or other sensitive material in any public message. + +When reporting a vulnerability, please include as much of the following as possible: + +- affected Cozystack version, tag, or commit +- affected component or package, for example operator, API server, dashboard, installer, or a packaged system component +- deployment environment and provider, for example bare metal, Hetzner, Oracle Cloud, or other infrastructure +- prerequisites and exact reproduction steps +- impact, attack scenario, and expected blast radius +- whether authentication, tenant access, cluster-admin access, or network adjacency is required +- known mitigations or workarounds +- whether you believe the issue also affects an upstream dependency + +## What to Expect + +The maintainers will aim to: + +- acknowledge receipt within 3 business days +- perform an initial triage and severity assessment within 7 business days +- keep the reporter informed as the fix and disclosure plan are developed + +Resolution timelines depend on severity, complexity, release branch applicability, and whether coordination with upstream projects is required. + +## Disclosure Process + +The Cozystack project follows a coordinated disclosure model. + +- We ask reporters to keep details private until a fix or mitigation is available and users have had a reasonable opportunity to upgrade. +- When appropriate, maintainers may use GitHub Security Advisories or equivalent coordinated disclosure tooling to manage remediation and public disclosure. +- If appropriate, the project may request or publish a GHSA and/or CVE as part of the disclosure process. +- Fixes will normally be released in the supported version lines affected by the issue, subject to severity and feasibility. + +Public disclosure will typically happen through one or more of the following: + +- GitHub Releases and release notes +- project changelogs and documentation updates +- GitHub Security Advisories, when used for coordinated disclosure + +## Project Security Practices + +Security is part of the normal Cozystack development and release process. Current project practices include: + +- maintainer-owned review through pull requests and `CODEOWNERS` +- automated pull request checks, including pre-commit validation, unit tests, builds, and end-to-end testing +- release automation with patch releases, release branches, and backport workflows +- ongoing maintenance of packaged dependencies and platform integrations across supported release lines + +Because Cozystack is an integration-heavy platform, some vulnerabilities may require coordination across multiple repositories or with upstream maintainers before a public fix can be released. + +## Security Fixes and Announcements + +Security fixes are published in normal release artifacts whenever possible. Users should monitor: + +- GitHub Releases: +- project changelogs in this repository +- the Cozystack website and documentation: + +## Out of Scope + +The following are generally out of scope for private security reporting unless there is a clear Cozystack-specific impact: + +- vulnerabilities in unsupported or end-of-life Cozystack versions +- issues that require access already equivalent to cluster-admin, node root, or direct infrastructure administrator privileges, unless they bypass an expected Cozystack security boundary +- vulnerabilities that exist only in an upstream dependency and are not introduced or materially worsened by Cozystack packaging, configuration, or defaults +- requests for security best-practice advice without a concrete vulnerability + +## Credits + +We appreciate responsible disclosure and will credit reporters in public advisories or release notes unless anonymous disclosure is requested. diff --git a/api/.gitattributes b/api/.gitattributes new file mode 100644 index 00000000..39e882c9 --- /dev/null +++ b/api/.gitattributes @@ -0,0 +1 @@ +zz_generated_deepcopy.go linguist-generated diff --git a/api/api-rules/cozystack_api_violation_exceptions.list b/api/api-rules/cozystack_api_violation_exceptions.list index 1092b88b..8442e3ed 100644 --- a/api/api-rules/cozystack_api_violation_exceptions.list +++ b/api/api-rules/cozystack_api_violation_exceptions.list @@ -1,4 +1,5 @@ API rule violation: list_type_missing,github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1,ApplicationStatus,Conditions +API rule violation: list_type_missing,github.com/cozystack/cozystack/pkg/apis/core/v1alpha1,TenantModuleStatus,Conditions API rule violation: names_match,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,JSONSchemaProps,Ref API rule violation: names_match,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,JSONSchemaProps,Schema API rule violation: names_match,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,JSONSchemaProps,XEmbeddedResource diff --git a/api/apps/v1alpha1/bucket/types.go b/api/apps/v1alpha1/bucket/types.go new file mode 100644 index 00000000..96082a67 --- /dev/null +++ b/api/apps/v1alpha1/bucket/types.go @@ -0,0 +1,33 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package bucket + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Provisions bucket from the `-lock` BucketClass (with object lock enabled). + // +kubebuilder:default:=false + Locking bool `json:"locking"` + // Selects a specific BucketClass by storage pool name. + // +kubebuilder:default:="" + StoragePool string `json:"storagePool,omitempty"` + // Users configuration map. + // +kubebuilder:default:={} + Users map[string]User `json:"users,omitempty"` +} + +type User struct { + // Whether the user has read-only access. + Readonly bool `json:"readonly,omitempty"` +} diff --git a/api/apps/v1alpha1/bucket/zz_generated.deepcopy.go b/api/apps/v1alpha1/bucket/zz_generated.deepcopy.go new file mode 100644 index 00000000..26f925cd --- /dev/null +++ b/api/apps/v1alpha1/bucket/zz_generated.deepcopy.go @@ -0,0 +1,88 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package bucket + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + if in.Users != nil { + in, out := &in.Users, &out.Users + *out = make(map[string]User, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *User) DeepCopyInto(out *User) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User. +func (in *User) DeepCopy() *User { + if in == nil { + return nil + } + out := new(User) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/clickhouse/types.go b/api/apps/v1alpha1/clickhouse/types.go new file mode 100644 index 00000000..153ff5e0 --- /dev/null +++ b/api/apps/v1alpha1/clickhouse/types.go @@ -0,0 +1,112 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package clickhouse + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Number of ClickHouse replicas. + // +kubebuilder:default:=2 + Replicas int `json:"replicas"` + // Number of ClickHouse shards. + // +kubebuilder:default:=1 + Shards int `json:"shards"` + // Explicit CPU and memory configuration for each ClickHouse replica. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="small" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` + // Persistent Volume Claim size available for application data. + // +kubebuilder:default:="10Gi" + Size resource.Quantity `json:"size"` + // StorageClass used to store the data. + // +kubebuilder:default:="" + StorageClass string `json:"storageClass"` + // Size of Persistent Volume for logs. + // +kubebuilder:default:="2Gi" + LogStorageSize resource.Quantity `json:"logStorageSize"` + // TTL (expiration time) for `query_log` and `query_thread_log`. + // +kubebuilder:default:=15 + LogTTL int `json:"logTTL"` + // Users configuration map. + // +kubebuilder:default:={} + Users map[string]User `json:"users,omitempty"` + // Backup configuration. + // +kubebuilder:default:={} + Backup Backup `json:"backup"` + // ClickHouse Keeper configuration. + // +kubebuilder:default:={} + ClickhouseKeeper ClickHouseKeeper `json:"clickhouseKeeper"` +} + +type Backup struct { + // Retention strategy for cleaning up old backups. + // +kubebuilder:default:="--keep-last=3 --keep-daily=3 --keep-within-weekly=1m" + CleanupStrategy string `json:"cleanupStrategy"` + // Enable regular backups (default: false). + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` + // Password for Restic backup encryption. + // +kubebuilder:default:="" + ResticPassword string `json:"resticPassword"` + // Access key for S3 authentication. + // +kubebuilder:default:="" + S3AccessKey string `json:"s3AccessKey"` + // S3 bucket used for storing backups. + // +kubebuilder:default:="s3.example.org/clickhouse-backups" + S3Bucket string `json:"s3Bucket"` + // AWS S3 region where backups are stored. + // +kubebuilder:default:="us-east-1" + S3Region string `json:"s3Region"` + // Secret key for S3 authentication. + // +kubebuilder:default:="" + S3SecretKey string `json:"s3SecretKey"` + // Cron schedule for automated backups. + // +kubebuilder:default:="0 2 * * *" + Schedule string `json:"schedule"` +} + +type ClickHouseKeeper struct { + // Deploy ClickHouse Keeper for cluster coordination. + // +kubebuilder:default:=true + Enabled bool `json:"enabled,omitempty"` + // Number of Keeper replicas. + // +kubebuilder:default:=3 + Replicas int `json:"replicas,omitempty"` + // Default sizing preset. + // +kubebuilder:default:="micro" + ResourcesPreset ResourcesPreset `json:"resourcesPreset,omitempty"` + // Persistent Volume Claim size available for application data. + // +kubebuilder:default:="1Gi" + Size resource.Quantity `json:"size,omitempty"` +} + +type Resources struct { + // CPU available to each replica. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available to each replica. + Memory resource.Quantity `json:"memory,omitempty"` +} + +type User struct { + // Password for the user. + Password string `json:"password,omitempty"` + // User is readonly (default: false). + Readonly bool `json:"readonly,omitempty"` +} + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string diff --git a/api/apps/v1alpha1/clickhouse/zz_generated.deepcopy.go b/api/apps/v1alpha1/clickhouse/zz_generated.deepcopy.go new file mode 100644 index 00000000..2c3a6ed8 --- /dev/null +++ b/api/apps/v1alpha1/clickhouse/zz_generated.deepcopy.go @@ -0,0 +1,141 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package clickhouse + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Backup) DeepCopyInto(out *Backup) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Backup. +func (in *Backup) DeepCopy() *Backup { + if in == nil { + return nil + } + out := new(Backup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClickHouseKeeper) DeepCopyInto(out *ClickHouseKeeper) { + *out = *in + out.Size = in.Size.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClickHouseKeeper. +func (in *ClickHouseKeeper) DeepCopy() *ClickHouseKeeper { + if in == nil { + return nil + } + out := new(ClickHouseKeeper) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + out.Size = in.Size.DeepCopy() + out.LogStorageSize = in.LogStorageSize.DeepCopy() + if in.Users != nil { + in, out := &in.Users, &out.Users + *out = make(map[string]User, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + out.Backup = in.Backup + in.ClickhouseKeeper.DeepCopyInto(&out.ClickhouseKeeper) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *User) DeepCopyInto(out *User) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User. +func (in *User) DeepCopy() *User { + if in == nil { + return nil + } + out := new(User) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/foundationdb/types.go b/api/apps/v1alpha1/foundationdb/types.go new file mode 100644 index 00000000..5b0e5920 --- /dev/null +++ b/api/apps/v1alpha1/foundationdb/types.go @@ -0,0 +1,162 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package foundationdb + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Cluster configuration. + // +kubebuilder:default:={} + Cluster Cluster `json:"cluster"` + // Storage configuration. + // +kubebuilder:default:={} + Storage Storage `json:"storage"` + // Explicit CPU and memory configuration for each FoundationDB instance. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="medium" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` + // Backup configuration. + // +kubebuilder:default:={} + Backup Backup `json:"backup"` + // Monitoring configuration. + // +kubebuilder:default:={} + Monitoring Monitoring `json:"monitoring"` + // Custom parameters to pass to FoundationDB. + // +kubebuilder:default:={} + CustomParameters []string `json:"customParameters,omitempty"` + // Container image deployment type. + // +kubebuilder:default:="unified" + ImageType ImageType `json:"imageType"` + // Security context for containers. + // +kubebuilder:default:={} + SecurityContext SecurityContext `json:"securityContext"` + // Enable automatic pod replacements. + // +kubebuilder:default:=true + AutomaticReplacements bool `json:"automaticReplacements"` +} + +type Backup struct { + // Enable backups. + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` + // Retention policy for backups. + // +kubebuilder:default:="7d" + RetentionPolicy string `json:"retentionPolicy"` + // S3 configuration for backups. + // +kubebuilder:default:={} + S3 BackupS3 `json:"s3"` +} + +type BackupS3 struct { + // S3 bucket name. + // +kubebuilder:default:="" + Bucket string `json:"bucket"` + // S3 credentials. + // +kubebuilder:default:={} + Credentials BackupS3Credentials `json:"credentials"` + // S3 endpoint URL. + // +kubebuilder:default:="" + Endpoint string `json:"endpoint"` + // S3 region. + // +kubebuilder:default:="us-east-1" + Region string `json:"region"` +} + +type BackupS3Credentials struct { + // S3 access key ID. + // +kubebuilder:default:="" + AccessKeyId string `json:"accessKeyId"` + // S3 secret access key. + // +kubebuilder:default:="" + SecretAccessKey string `json:"secretAccessKey"` +} + +type Cluster struct { + // Fault domain configuration. + // +kubebuilder:default:={} + FaultDomain ClusterFaultDomain `json:"faultDomain"` + // Process counts for different roles. + // +kubebuilder:default:={} + ProcessCounts ClusterProcessCounts `json:"processCounts"` + // Database redundancy mode (single, double, triple, three_datacenter, three_datacenter_fallback). + // +kubebuilder:default:="double" + RedundancyMode string `json:"redundancyMode"` + // Storage engine (ssd-2, ssd-redwood-v1, ssd-rocksdb-v1, memory). + // +kubebuilder:default:="ssd-2" + StorageEngine string `json:"storageEngine"` + // Version of FoundationDB to use. + // +kubebuilder:default:="7.3.63" + Version string `json:"version"` +} + +type ClusterFaultDomain struct { + // Fault domain key. + // +kubebuilder:default:="kubernetes.io/hostname" + Key string `json:"key"` + // Fault domain value source. + // +kubebuilder:default:="spec.nodeName" + ValueFrom string `json:"valueFrom"` +} + +type ClusterProcessCounts struct { + // Number of cluster controller processes. + // +kubebuilder:default:=1 + ClusterController int `json:"cluster_controller"` + // Number of stateless processes (-1 for automatic). + // +kubebuilder:default:=-1 + Stateless int `json:"stateless"` + // Number of storage processes (determines cluster size). + // +kubebuilder:default:=3 + Storage int `json:"storage"` +} + +type Monitoring struct { + // Enable WorkloadMonitor integration. + // +kubebuilder:default:=true + Enabled bool `json:"enabled"` +} + +type Resources struct { + // CPU available to each instance. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available to each instance. + Memory resource.Quantity `json:"memory,omitempty"` +} + +type SecurityContext struct { + // Group ID to run the container. + // +kubebuilder:default:=4059 + RunAsGroup int `json:"runAsGroup"` + // User ID to run the container. + // +kubebuilder:default:=4059 + RunAsUser int `json:"runAsUser"` +} + +type Storage struct { + // Size of persistent volumes for each instance. + // +kubebuilder:default:="16Gi" + Size resource.Quantity `json:"size"` + // Storage class (if not set, uses cluster default). + // +kubebuilder:default:="" + StorageClass string `json:"storageClass"` +} + +// +kubebuilder:validation:Enum="unified";"split" +type ImageType string + +// +kubebuilder:validation:Enum="small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string diff --git a/api/apps/v1alpha1/foundationdb/zz_generated.deepcopy.go b/api/apps/v1alpha1/foundationdb/zz_generated.deepcopy.go new file mode 100644 index 00000000..92d80421 --- /dev/null +++ b/api/apps/v1alpha1/foundationdb/zz_generated.deepcopy.go @@ -0,0 +1,234 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package foundationdb + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Backup) DeepCopyInto(out *Backup) { + *out = *in + out.S3 = in.S3 +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Backup. +func (in *Backup) DeepCopy() *Backup { + if in == nil { + return nil + } + out := new(Backup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupS3) DeepCopyInto(out *BackupS3) { + *out = *in + out.Credentials = in.Credentials +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupS3. +func (in *BackupS3) DeepCopy() *BackupS3 { + if in == nil { + return nil + } + out := new(BackupS3) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupS3Credentials) DeepCopyInto(out *BackupS3Credentials) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupS3Credentials. +func (in *BackupS3Credentials) DeepCopy() *BackupS3Credentials { + if in == nil { + return nil + } + out := new(BackupS3Credentials) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Cluster) DeepCopyInto(out *Cluster) { + *out = *in + out.FaultDomain = in.FaultDomain + out.ProcessCounts = in.ProcessCounts +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cluster. +func (in *Cluster) DeepCopy() *Cluster { + if in == nil { + return nil + } + out := new(Cluster) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterFaultDomain) DeepCopyInto(out *ClusterFaultDomain) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterFaultDomain. +func (in *ClusterFaultDomain) DeepCopy() *ClusterFaultDomain { + if in == nil { + return nil + } + out := new(ClusterFaultDomain) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterProcessCounts) DeepCopyInto(out *ClusterProcessCounts) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterProcessCounts. +func (in *ClusterProcessCounts) DeepCopy() *ClusterProcessCounts { + if in == nil { + return nil + } + out := new(ClusterProcessCounts) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + out.Cluster = in.Cluster + in.Storage.DeepCopyInto(&out.Storage) + in.Resources.DeepCopyInto(&out.Resources) + out.Backup = in.Backup + out.Monitoring = in.Monitoring + if in.CustomParameters != nil { + in, out := &in.CustomParameters, &out.CustomParameters + *out = make([]string, len(*in)) + copy(*out, *in) + } + out.SecurityContext = in.SecurityContext +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Monitoring) DeepCopyInto(out *Monitoring) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Monitoring. +func (in *Monitoring) DeepCopy() *Monitoring { + if in == nil { + return nil + } + out := new(Monitoring) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityContext) DeepCopyInto(out *SecurityContext) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityContext. +func (in *SecurityContext) DeepCopy() *SecurityContext { + if in == nil { + return nil + } + out := new(SecurityContext) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Storage) DeepCopyInto(out *Storage) { + *out = *in + out.Size = in.Size.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Storage. +func (in *Storage) DeepCopy() *Storage { + if in == nil { + return nil + } + out := new(Storage) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/go.mod b/api/apps/v1alpha1/go.mod new file mode 100644 index 00000000..d5d57383 --- /dev/null +++ b/api/apps/v1alpha1/go.mod @@ -0,0 +1,24 @@ +module github.com/cozystack/cozystack/api/apps/v1alpha1 + +go 1.25.0 + +require k8s.io/apimachinery v0.35.2 + +require ( + github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect + github.com/x448/float16 v0.8.4 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/text v0.31.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect +) diff --git a/api/apps/v1alpha1/go.sum b/api/apps/v1alpha1/go.sum new file mode 100644 index 00000000..d9b1cf31 --- /dev/null +++ b/api/apps/v1alpha1/go.sum @@ -0,0 +1,56 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= +go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/apimachinery v0.35.2 h1:NqsM/mmZA7sHW02JZ9RTtk3wInRgbVxL8MPfzSANAK8= +k8s.io/apimachinery v0.35.2/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/api/apps/v1alpha1/harbor/types.go b/api/apps/v1alpha1/harbor/types.go new file mode 100644 index 00000000..974576b3 --- /dev/null +++ b/api/apps/v1alpha1/harbor/types.go @@ -0,0 +1,114 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package harbor + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Hostname for external access to Harbor (defaults to 'harbor' subdomain for the tenant host). + // +kubebuilder:default:="" + Host string `json:"host,omitempty"` + // StorageClass used to store the data. + // +kubebuilder:default:="" + StorageClass string `json:"storageClass"` + // Core API server configuration. + // +kubebuilder:default:={} + Core Core `json:"core"` + // Container image registry configuration. + // +kubebuilder:default:={} + Registry Registry `json:"registry"` + // Background job service configuration. + // +kubebuilder:default:={} + Jobservice Jobservice `json:"jobservice"` + // Trivy vulnerability scanner configuration. + // +kubebuilder:default:={} + Trivy Trivy `json:"trivy"` + // PostgreSQL database configuration. + // +kubebuilder:default:={} + Database Database `json:"database"` + // Redis cache configuration. + // +kubebuilder:default:={} + Redis Redis `json:"redis"` +} + +type Core struct { + // Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="small" + ResourcesPreset ResourcesPreset `json:"resourcesPreset,omitempty"` +} + +type Database struct { + // Number of database instances. + // +kubebuilder:default:=2 + Replicas int `json:"replicas"` + // Persistent Volume size for database storage. + // +kubebuilder:default:="5Gi" + Size resource.Quantity `json:"size"` +} + +type Jobservice struct { + // Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="nano" + ResourcesPreset ResourcesPreset `json:"resourcesPreset,omitempty"` +} + +type Redis struct { + // Number of Redis replicas. + // +kubebuilder:default:=2 + Replicas int `json:"replicas"` + // Persistent Volume size for cache storage. + // +kubebuilder:default:="1Gi" + Size resource.Quantity `json:"size"` +} + +type Registry struct { + // Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="small" + ResourcesPreset ResourcesPreset `json:"resourcesPreset,omitempty"` +} + +type Resources struct { + // Number of CPU cores allocated. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Amount of memory allocated. + Memory resource.Quantity `json:"memory,omitempty"` +} + +type Trivy struct { + // Enable or disable the vulnerability scanner. + // +kubebuilder:default:=true + Enabled bool `json:"enabled"` + // Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="nano" + ResourcesPreset ResourcesPreset `json:"resourcesPreset,omitempty"` + // Persistent Volume size for vulnerability database cache. + // +kubebuilder:default:="5Gi" + Size resource.Quantity `json:"size"` +} + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string diff --git a/api/apps/v1alpha1/harbor/zz_generated.deepcopy.go b/api/apps/v1alpha1/harbor/zz_generated.deepcopy.go new file mode 100644 index 00000000..3e7338ad --- /dev/null +++ b/api/apps/v1alpha1/harbor/zz_generated.deepcopy.go @@ -0,0 +1,186 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package harbor + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + in.Core.DeepCopyInto(&out.Core) + in.Registry.DeepCopyInto(&out.Registry) + in.Jobservice.DeepCopyInto(&out.Jobservice) + in.Trivy.DeepCopyInto(&out.Trivy) + in.Database.DeepCopyInto(&out.Database) + in.Redis.DeepCopyInto(&out.Redis) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Core) DeepCopyInto(out *Core) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Core. +func (in *Core) DeepCopy() *Core { + if in == nil { + return nil + } + out := new(Core) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Database) DeepCopyInto(out *Database) { + *out = *in + out.Size = in.Size.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Database. +func (in *Database) DeepCopy() *Database { + if in == nil { + return nil + } + out := new(Database) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Jobservice) DeepCopyInto(out *Jobservice) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Jobservice. +func (in *Jobservice) DeepCopy() *Jobservice { + if in == nil { + return nil + } + out := new(Jobservice) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Redis) DeepCopyInto(out *Redis) { + *out = *in + out.Size = in.Size.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Redis. +func (in *Redis) DeepCopy() *Redis { + if in == nil { + return nil + } + out := new(Redis) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Registry) DeepCopyInto(out *Registry) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Registry. +func (in *Registry) DeepCopy() *Registry { + if in == nil { + return nil + } + out := new(Registry) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Trivy) DeepCopyInto(out *Trivy) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + out.Size = in.Size.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Trivy. +func (in *Trivy) DeepCopy() *Trivy { + if in == nil { + return nil + } + out := new(Trivy) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/httpcache/types.go b/api/apps/v1alpha1/httpcache/types.go new file mode 100644 index 00000000..30bb10ba --- /dev/null +++ b/api/apps/v1alpha1/httpcache/types.go @@ -0,0 +1,72 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package httpcache + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Persistent Volume Claim size available for application data. + // +kubebuilder:default:="10Gi" + Size resource.Quantity `json:"size"` + // StorageClass used to store the data. + // +kubebuilder:default:="" + StorageClass string `json:"storageClass"` + // Enable external access from outside the cluster. + // +kubebuilder:default:=false + External bool `json:"external"` + // Endpoints configuration, as a list of . + // +kubebuilder:default:={} + Endpoints []string `json:"endpoints,omitempty"` + // HAProxy configuration. + // +kubebuilder:default:={} + Haproxy HAProxy `json:"haproxy"` + // Nginx configuration. + // +kubebuilder:default:={} + Nginx Nginx `json:"nginx"` +} + +type HAProxy struct { + // Number of HAProxy replicas. + // +kubebuilder:default:=2 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="nano" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` +} + +type Nginx struct { + // Number of Nginx replicas. + // +kubebuilder:default:=2 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="nano" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` +} + +type Resources struct { + // CPU available to each replica. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available to each replica. + Memory resource.Quantity `json:"memory,omitempty"` +} + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string diff --git a/api/apps/v1alpha1/httpcache/zz_generated.deepcopy.go b/api/apps/v1alpha1/httpcache/zz_generated.deepcopy.go new file mode 100644 index 00000000..47da2baa --- /dev/null +++ b/api/apps/v1alpha1/httpcache/zz_generated.deepcopy.go @@ -0,0 +1,123 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package httpcache + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + out.Size = in.Size.DeepCopy() + if in.Endpoints != nil { + in, out := &in.Endpoints, &out.Endpoints + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.Haproxy.DeepCopyInto(&out.Haproxy) + in.Nginx.DeepCopyInto(&out.Nginx) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HAProxy) DeepCopyInto(out *HAProxy) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxy. +func (in *HAProxy) DeepCopy() *HAProxy { + if in == nil { + return nil + } + out := new(HAProxy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Nginx) DeepCopyInto(out *Nginx) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Nginx. +func (in *Nginx) DeepCopy() *Nginx { + if in == nil { + return nil + } + out := new(Nginx) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/kafka/types.go b/api/apps/v1alpha1/kafka/types.go new file mode 100644 index 00000000..485f34ee --- /dev/null +++ b/api/apps/v1alpha1/kafka/types.go @@ -0,0 +1,90 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package kafka + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" + k8sRuntime "k8s.io/apimachinery/pkg/runtime" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Enable external access from outside the cluster. + // +kubebuilder:default:=false + External bool `json:"external"` + // Topics configuration. + // +kubebuilder:default:={} + Topics []Topic `json:"topics,omitempty"` + // Kafka configuration. + // +kubebuilder:default:={} + Kafka Kafka `json:"kafka"` + // ZooKeeper configuration. + // +kubebuilder:default:={} + Zookeeper ZooKeeper `json:"zookeeper"` +} + +type Kafka struct { + // Number of Kafka replicas. + // +kubebuilder:default:=3 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="small" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` + // Persistent Volume size for Kafka. + // +kubebuilder:default:="10Gi" + Size resource.Quantity `json:"size"` + // StorageClass used to store the Kafka data. + // +kubebuilder:default:="" + StorageClass string `json:"storageClass"` +} + +type Resources struct { + // CPU available to each replica. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available to each replica. + Memory resource.Quantity `json:"memory,omitempty"` +} + +type Topic struct { + // Topic configuration. + Config k8sRuntime.RawExtension `json:"config"` + // Topic name. + Name string `json:"name"` + // Number of partitions. + Partitions int `json:"partitions"` + // Number of replicas. + Replicas int `json:"replicas"` +} + +type ZooKeeper struct { + // Number of ZooKeeper replicas. + // +kubebuilder:default:=3 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="small" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` + // Persistent Volume size for ZooKeeper. + // +kubebuilder:default:="5Gi" + Size resource.Quantity `json:"size"` + // StorageClass used to store the ZooKeeper data. + // +kubebuilder:default:="" + StorageClass string `json:"storageClass"` +} + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string diff --git a/api/apps/v1alpha1/kafka/zz_generated.deepcopy.go b/api/apps/v1alpha1/kafka/zz_generated.deepcopy.go new file mode 100644 index 00000000..c2d39077 --- /dev/null +++ b/api/apps/v1alpha1/kafka/zz_generated.deepcopy.go @@ -0,0 +1,142 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package kafka + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + if in.Topics != nil { + in, out := &in.Topics, &out.Topics + *out = make([]Topic, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.Kafka.DeepCopyInto(&out.Kafka) + in.Zookeeper.DeepCopyInto(&out.Zookeeper) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Kafka) DeepCopyInto(out *Kafka) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + out.Size = in.Size.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Kafka. +func (in *Kafka) DeepCopy() *Kafka { + if in == nil { + return nil + } + out := new(Kafka) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Topic) DeepCopyInto(out *Topic) { + *out = *in + in.Config.DeepCopyInto(&out.Config) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Topic. +func (in *Topic) DeepCopy() *Topic { + if in == nil { + return nil + } + out := new(Topic) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZooKeeper) DeepCopyInto(out *ZooKeeper) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + out.Size = in.Size.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZooKeeper. +func (in *ZooKeeper) DeepCopy() *ZooKeeper { + if in == nil { + return nil + } + out := new(ZooKeeper) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/kubernetes/types.go b/api/apps/v1alpha1/kubernetes/types.go new file mode 100644 index 00000000..88a3c97e --- /dev/null +++ b/api/apps/v1alpha1/kubernetes/types.go @@ -0,0 +1,279 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package kubernetes + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" + k8sRuntime "k8s.io/apimachinery/pkg/runtime" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // StorageClass used to store the data. + // +kubebuilder:default:="replicated" + StorageClass string `json:"storageClass"` + // Worker nodes configuration map. + // +kubebuilder:default:={"md0":{"ephemeralStorage":"20Gi","gpus":{},"instanceType":"u1.medium","maxReplicas":10,"minReplicas":0,"resources":{},"roles":{"ingress-nginx"}}} + NodeGroups map[string]NodeGroup `json:"nodeGroups,omitempty"` + // Kubernetes major.minor version to deploy + // +kubebuilder:default:="v1.35" + Version Version `json:"version"` + // External hostname for Kubernetes cluster. Defaults to `.` if empty. + // +kubebuilder:default:="" + Host string `json:"host"` + // Cluster addons configuration. + // +kubebuilder:default:={} + Addons Addons `json:"addons"` + // Kubernetes control-plane configuration. + // +kubebuilder:default:={} + ControlPlane ControlPlane `json:"controlPlane"` + // Optional image overrides for air-gapped or rate-limited registries. + // +kubebuilder:default:={} + Images Images `json:"images"` +} + +type APIServer struct { + // CPU and memory resources for API Server. + // +kubebuilder:default:={} + Resources Resources `json:"resources"` + // Preset if `resources` omitted. + // +kubebuilder:default:="large" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` +} + +type Addons struct { + // Cert-manager addon. + // +kubebuilder:default:={} + CertManager CertManagerAddon `json:"certManager"` + // Cilium CNI plugin. + // +kubebuilder:default:={} + Cilium CiliumAddon `json:"cilium"` + // CoreDNS addon. + // +kubebuilder:default:={} + Coredns CoreDNSAddon `json:"coredns"` + // FluxCD GitOps operator. + // +kubebuilder:default:={} + Fluxcd FluxCDAddon `json:"fluxcd"` + // Gateway API addon. + // +kubebuilder:default:={} + GatewayAPI GatewayAPIAddon `json:"gatewayAPI"` + // NVIDIA GPU Operator. + // +kubebuilder:default:={} + GpuOperator GPUOperatorAddon `json:"gpuOperator"` + // HAMi GPU virtualization middleware. + // +kubebuilder:default:={} + Hami HAMiAddon `json:"hami"` + // Ingress-NGINX controller. + // +kubebuilder:default:={} + IngressNginx IngressNginxAddon `json:"ingressNginx"` + // Monitoring agents. + // +kubebuilder:default:={} + MonitoringAgents MonitoringAgentsAddon `json:"monitoringAgents"` + // Velero backup/restore addon. + // +kubebuilder:default:={} + Velero VeleroAddon `json:"velero"` + // Vertical Pod Autoscaler. + // +kubebuilder:default:={} + VerticalPodAutoscaler VerticalPodAutoscalerAddon `json:"verticalPodAutoscaler"` +} + +type CertManagerAddon struct { + // Enable cert-manager. + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` + // Custom Helm values overrides. + // +kubebuilder:default:={} + ValuesOverride k8sRuntime.RawExtension `json:"valuesOverride"` +} + +type CiliumAddon struct { + // Custom Helm values overrides. + // +kubebuilder:default:={} + ValuesOverride k8sRuntime.RawExtension `json:"valuesOverride"` +} + +type ControlPlane struct { + // API Server configuration. + // +kubebuilder:default:={} + ApiServer APIServer `json:"apiServer"` + // Controller Manager configuration. + // +kubebuilder:default:={} + ControllerManager ControllerManager `json:"controllerManager"` + // Konnectivity configuration. + // +kubebuilder:default:={} + Konnectivity Konnectivity `json:"konnectivity"` + // Number of control-plane replicas. + // +kubebuilder:default:=2 + Replicas int `json:"replicas"` + // Scheduler configuration. + // +kubebuilder:default:={} + Scheduler Scheduler `json:"scheduler"` +} + +type ControllerManager struct { + // CPU and memory resources for Controller Manager. + // +kubebuilder:default:={} + Resources Resources `json:"resources"` + // Preset if `resources` omitted. + // +kubebuilder:default:="micro" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` +} + +type CoreDNSAddon struct { + // Custom Helm values overrides. + // +kubebuilder:default:={} + ValuesOverride k8sRuntime.RawExtension `json:"valuesOverride"` +} + +type FluxCDAddon struct { + // Enable FluxCD. + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` + // Custom Helm values overrides. + // +kubebuilder:default:={} + ValuesOverride k8sRuntime.RawExtension `json:"valuesOverride"` +} + +type GPU struct { + // Name of GPU, such as "nvidia.com/AD102GL_L40S". + Name string `json:"name"` +} + +type GPUOperatorAddon struct { + // Enable GPU Operator. + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` + // Custom Helm values overrides. + // +kubebuilder:default:={} + ValuesOverride k8sRuntime.RawExtension `json:"valuesOverride"` +} + +type GatewayAPIAddon struct { + // Enable Gateway API. + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` +} + +type HAMiAddon struct { + // Enable HAMi (requires GPU Operator). + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` + // Custom Helm values overrides. + // +kubebuilder:default:={} + ValuesOverride k8sRuntime.RawExtension `json:"valuesOverride"` +} + +type Images struct { + // Image used by the wait-for-kubeconfig init container. Empty falls back to images/busybox.tag. + // +kubebuilder:default:="" + WaitForKubeconfig string `json:"waitForKubeconfig,omitempty"` +} + +type IngressNginxAddon struct { + // Enable the controller (requires nodes labeled `ingress-nginx`). + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` + // Method to expose the controller. Allowed values: `Proxied`, `LoadBalancer`. + // +kubebuilder:default:="Proxied" + ExposeMethod IngressNginxExposeMethod `json:"exposeMethod"` + // Domains routed to this tenant cluster when `exposeMethod` is `Proxied`. + // +kubebuilder:default:={} + Hosts []string `json:"hosts,omitempty"` + // Custom Helm values overrides. + // +kubebuilder:default:={} + ValuesOverride k8sRuntime.RawExtension `json:"valuesOverride"` +} + +type Konnectivity struct { + // Konnectivity Server configuration. + // +kubebuilder:default:={} + Server KonnectivityServer `json:"server"` +} + +type KonnectivityServer struct { + // CPU and memory resources for Konnectivity. + // +kubebuilder:default:={} + Resources Resources `json:"resources"` + // Preset if `resources` omitted. + // +kubebuilder:default:="micro" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` +} + +type MonitoringAgentsAddon struct { + // Enable monitoring agents. + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` + // Custom Helm values overrides. + // +kubebuilder:default:={} + ValuesOverride k8sRuntime.RawExtension `json:"valuesOverride"` +} + +type NodeGroup struct { + // Ephemeral storage size. + // +kubebuilder:default:="20Gi" + EphemeralStorage resource.Quantity `json:"ephemeralStorage"` + // List of GPUs to attach (NVIDIA driver requires at least 4 GiB RAM). + Gpus []GPU `json:"gpus,omitempty"` + // Virtual machine instance type. + // +kubebuilder:default:="u1.medium" + InstanceType string `json:"instanceType"` + // Maximum number of replicas. + // +kubebuilder:default:=10 + MaxReplicas int `json:"maxReplicas"` + // Minimum number of replicas. + // +kubebuilder:default:=0 + MinReplicas int `json:"minReplicas"` + // CPU and memory resources for each worker node. + Resources Resources `json:"resources"` + // List of node roles. + Roles []string `json:"roles,omitempty"` +} + +type Resources struct { + // CPU available. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available. + Memory resource.Quantity `json:"memory,omitempty"` +} + +type Scheduler struct { + // CPU and memory resources for Scheduler. + // +kubebuilder:default:={} + Resources Resources `json:"resources"` + // Preset if `resources` omitted. + // +kubebuilder:default:="micro" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` +} + +type VeleroAddon struct { + // Enable Velero. + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` + // Custom Helm values overrides. + // +kubebuilder:default:={} + ValuesOverride k8sRuntime.RawExtension `json:"valuesOverride"` +} + +type VerticalPodAutoscalerAddon struct { + // Custom Helm values overrides. + // +kubebuilder:default:={} + ValuesOverride k8sRuntime.RawExtension `json:"valuesOverride"` +} + +// +kubebuilder:validation:Enum="Proxied";"LoadBalancer" +type IngressNginxExposeMethod string + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string + +// +kubebuilder:validation:Enum="v1.35";"v1.34";"v1.33";"v1.32";"v1.31";"v1.30" +type Version string diff --git a/api/apps/v1alpha1/kubernetes/zz_generated.deepcopy.go b/api/apps/v1alpha1/kubernetes/zz_generated.deepcopy.go new file mode 100644 index 00000000..e021fbaa --- /dev/null +++ b/api/apps/v1alpha1/kubernetes/zz_generated.deepcopy.go @@ -0,0 +1,455 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package kubernetes + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *APIServer) DeepCopyInto(out *APIServer) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIServer. +func (in *APIServer) DeepCopy() *APIServer { + if in == nil { + return nil + } + out := new(APIServer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Addons) DeepCopyInto(out *Addons) { + *out = *in + in.CertManager.DeepCopyInto(&out.CertManager) + in.Cilium.DeepCopyInto(&out.Cilium) + in.Coredns.DeepCopyInto(&out.Coredns) + in.Fluxcd.DeepCopyInto(&out.Fluxcd) + out.GatewayAPI = in.GatewayAPI + in.GpuOperator.DeepCopyInto(&out.GpuOperator) + in.Hami.DeepCopyInto(&out.Hami) + in.IngressNginx.DeepCopyInto(&out.IngressNginx) + in.MonitoringAgents.DeepCopyInto(&out.MonitoringAgents) + in.Velero.DeepCopyInto(&out.Velero) + in.VerticalPodAutoscaler.DeepCopyInto(&out.VerticalPodAutoscaler) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Addons. +func (in *Addons) DeepCopy() *Addons { + if in == nil { + return nil + } + out := new(Addons) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CertManagerAddon) DeepCopyInto(out *CertManagerAddon) { + *out = *in + in.ValuesOverride.DeepCopyInto(&out.ValuesOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CertManagerAddon. +func (in *CertManagerAddon) DeepCopy() *CertManagerAddon { + if in == nil { + return nil + } + out := new(CertManagerAddon) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CiliumAddon) DeepCopyInto(out *CiliumAddon) { + *out = *in + in.ValuesOverride.DeepCopyInto(&out.ValuesOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CiliumAddon. +func (in *CiliumAddon) DeepCopy() *CiliumAddon { + if in == nil { + return nil + } + out := new(CiliumAddon) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + if in.NodeGroups != nil { + in, out := &in.NodeGroups, &out.NodeGroups + *out = make(map[string]NodeGroup, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + in.Addons.DeepCopyInto(&out.Addons) + in.ControlPlane.DeepCopyInto(&out.ControlPlane) + out.Images = in.Images +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControlPlane) DeepCopyInto(out *ControlPlane) { + *out = *in + in.ApiServer.DeepCopyInto(&out.ApiServer) + in.ControllerManager.DeepCopyInto(&out.ControllerManager) + in.Konnectivity.DeepCopyInto(&out.Konnectivity) + in.Scheduler.DeepCopyInto(&out.Scheduler) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlane. +func (in *ControlPlane) DeepCopy() *ControlPlane { + if in == nil { + return nil + } + out := new(ControlPlane) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControllerManager) DeepCopyInto(out *ControllerManager) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerManager. +func (in *ControllerManager) DeepCopy() *ControllerManager { + if in == nil { + return nil + } + out := new(ControllerManager) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CoreDNSAddon) DeepCopyInto(out *CoreDNSAddon) { + *out = *in + in.ValuesOverride.DeepCopyInto(&out.ValuesOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CoreDNSAddon. +func (in *CoreDNSAddon) DeepCopy() *CoreDNSAddon { + if in == nil { + return nil + } + out := new(CoreDNSAddon) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FluxCDAddon) DeepCopyInto(out *FluxCDAddon) { + *out = *in + in.ValuesOverride.DeepCopyInto(&out.ValuesOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FluxCDAddon. +func (in *FluxCDAddon) DeepCopy() *FluxCDAddon { + if in == nil { + return nil + } + out := new(FluxCDAddon) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GPU) DeepCopyInto(out *GPU) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GPU. +func (in *GPU) DeepCopy() *GPU { + if in == nil { + return nil + } + out := new(GPU) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GPUOperatorAddon) DeepCopyInto(out *GPUOperatorAddon) { + *out = *in + in.ValuesOverride.DeepCopyInto(&out.ValuesOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GPUOperatorAddon. +func (in *GPUOperatorAddon) DeepCopy() *GPUOperatorAddon { + if in == nil { + return nil + } + out := new(GPUOperatorAddon) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GatewayAPIAddon) DeepCopyInto(out *GatewayAPIAddon) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayAPIAddon. +func (in *GatewayAPIAddon) DeepCopy() *GatewayAPIAddon { + if in == nil { + return nil + } + out := new(GatewayAPIAddon) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HAMiAddon) DeepCopyInto(out *HAMiAddon) { + *out = *in + in.ValuesOverride.DeepCopyInto(&out.ValuesOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAMiAddon. +func (in *HAMiAddon) DeepCopy() *HAMiAddon { + if in == nil { + return nil + } + out := new(HAMiAddon) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Images) DeepCopyInto(out *Images) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Images. +func (in *Images) DeepCopy() *Images { + if in == nil { + return nil + } + out := new(Images) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IngressNginxAddon) DeepCopyInto(out *IngressNginxAddon) { + *out = *in + if in.Hosts != nil { + in, out := &in.Hosts, &out.Hosts + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.ValuesOverride.DeepCopyInto(&out.ValuesOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressNginxAddon. +func (in *IngressNginxAddon) DeepCopy() *IngressNginxAddon { + if in == nil { + return nil + } + out := new(IngressNginxAddon) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Konnectivity) DeepCopyInto(out *Konnectivity) { + *out = *in + in.Server.DeepCopyInto(&out.Server) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Konnectivity. +func (in *Konnectivity) DeepCopy() *Konnectivity { + if in == nil { + return nil + } + out := new(Konnectivity) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KonnectivityServer) DeepCopyInto(out *KonnectivityServer) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KonnectivityServer. +func (in *KonnectivityServer) DeepCopy() *KonnectivityServer { + if in == nil { + return nil + } + out := new(KonnectivityServer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MonitoringAgentsAddon) DeepCopyInto(out *MonitoringAgentsAddon) { + *out = *in + in.ValuesOverride.DeepCopyInto(&out.ValuesOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonitoringAgentsAddon. +func (in *MonitoringAgentsAddon) DeepCopy() *MonitoringAgentsAddon { + if in == nil { + return nil + } + out := new(MonitoringAgentsAddon) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeGroup) DeepCopyInto(out *NodeGroup) { + *out = *in + out.EphemeralStorage = in.EphemeralStorage.DeepCopy() + if in.Gpus != nil { + in, out := &in.Gpus, &out.Gpus + *out = make([]GPU, len(*in)) + copy(*out, *in) + } + in.Resources.DeepCopyInto(&out.Resources) + if in.Roles != nil { + in, out := &in.Roles, &out.Roles + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeGroup. +func (in *NodeGroup) DeepCopy() *NodeGroup { + if in == nil { + return nil + } + out := new(NodeGroup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Scheduler) DeepCopyInto(out *Scheduler) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Scheduler. +func (in *Scheduler) DeepCopy() *Scheduler { + if in == nil { + return nil + } + out := new(Scheduler) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VeleroAddon) DeepCopyInto(out *VeleroAddon) { + *out = *in + in.ValuesOverride.DeepCopyInto(&out.ValuesOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VeleroAddon. +func (in *VeleroAddon) DeepCopy() *VeleroAddon { + if in == nil { + return nil + } + out := new(VeleroAddon) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VerticalPodAutoscalerAddon) DeepCopyInto(out *VerticalPodAutoscalerAddon) { + *out = *in + in.ValuesOverride.DeepCopyInto(&out.ValuesOverride) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VerticalPodAutoscalerAddon. +func (in *VerticalPodAutoscalerAddon) DeepCopy() *VerticalPodAutoscalerAddon { + if in == nil { + return nil + } + out := new(VerticalPodAutoscalerAddon) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/mariadb/types.go b/api/apps/v1alpha1/mariadb/types.go new file mode 100644 index 00000000..b3b6c414 --- /dev/null +++ b/api/apps/v1alpha1/mariadb/types.go @@ -0,0 +1,109 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package mariadb + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Number of MariaDB replicas. + // +kubebuilder:default:=2 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration for each MariaDB replica. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="nano" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` + // Persistent Volume Claim size available for application data. + // +kubebuilder:default:="10Gi" + Size resource.Quantity `json:"size"` + // StorageClass used to store the data. + // +kubebuilder:default:="" + StorageClass string `json:"storageClass"` + // Enable external access from outside the cluster. + // +kubebuilder:default:=false + External bool `json:"external"` + // MariaDB major.minor version to deploy + // +kubebuilder:default:="v11.8" + Version Version `json:"version"` + // Users configuration map. + // +kubebuilder:default:={} + Users map[string]User `json:"users,omitempty"` + // Databases configuration map. + // +kubebuilder:default:={} + Databases map[string]Database `json:"databases,omitempty"` + // Backup configuration. + // +kubebuilder:default:={} + Backup Backup `json:"backup"` +} + +type Backup struct { + // Retention strategy for cleaning up old backups. + // +kubebuilder:default:="--keep-last=3 --keep-daily=3 --keep-within-weekly=1m" + CleanupStrategy string `json:"cleanupStrategy"` + // Enable regular backups (default: false). + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` + // Password for Restic backup encryption. + // +kubebuilder:default:="" + ResticPassword string `json:"resticPassword"` + // Access key for S3 authentication. + // +kubebuilder:default:="" + S3AccessKey string `json:"s3AccessKey"` + // S3 bucket used for storing backups. + // +kubebuilder:default:="s3.example.org/mariadb-backups" + S3Bucket string `json:"s3Bucket"` + // AWS S3 region where backups are stored. + // +kubebuilder:default:="us-east-1" + S3Region string `json:"s3Region"` + // Secret key for S3 authentication. + // +kubebuilder:default:="" + S3SecretKey string `json:"s3SecretKey"` + // Cron schedule for automated backups. + // +kubebuilder:default:="0 2 * * *" + Schedule string `json:"schedule"` +} + +type Database struct { + // Roles assigned to users. + Roles DatabaseRoles `json:"roles,omitempty"` +} + +type DatabaseRoles struct { + // List of users with admin privileges. + Admin []string `json:"admin,omitempty"` + // List of users with read-only privileges. + Readonly []string `json:"readonly,omitempty"` +} + +type Resources struct { + // CPU available to each replica. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available to each replica. + Memory resource.Quantity `json:"memory,omitempty"` +} + +type User struct { + // Maximum number of connections. + MaxUserConnections int `json:"maxUserConnections"` + // Password for the user. + Password string `json:"password"` +} + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string + +// +kubebuilder:validation:Enum="v11.8";"v11.4";"v10.11";"v10.6" +type Version string diff --git a/api/apps/v1alpha1/mariadb/zz_generated.deepcopy.go b/api/apps/v1alpha1/mariadb/zz_generated.deepcopy.go new file mode 100644 index 00000000..4cc5a94f --- /dev/null +++ b/api/apps/v1alpha1/mariadb/zz_generated.deepcopy.go @@ -0,0 +1,171 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package mariadb + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Backup) DeepCopyInto(out *Backup) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Backup. +func (in *Backup) DeepCopy() *Backup { + if in == nil { + return nil + } + out := new(Backup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + out.Size = in.Size.DeepCopy() + if in.Users != nil { + in, out := &in.Users, &out.Users + *out = make(map[string]User, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Databases != nil { + in, out := &in.Databases, &out.Databases + *out = make(map[string]Database, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + out.Backup = in.Backup +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Database) DeepCopyInto(out *Database) { + *out = *in + in.Roles.DeepCopyInto(&out.Roles) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Database. +func (in *Database) DeepCopy() *Database { + if in == nil { + return nil + } + out := new(Database) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DatabaseRoles) DeepCopyInto(out *DatabaseRoles) { + *out = *in + if in.Admin != nil { + in, out := &in.Admin, &out.Admin + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Readonly != nil { + in, out := &in.Readonly, &out.Readonly + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DatabaseRoles. +func (in *DatabaseRoles) DeepCopy() *DatabaseRoles { + if in == nil { + return nil + } + out := new(DatabaseRoles) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *User) DeepCopyInto(out *User) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User. +func (in *User) DeepCopy() *User { + if in == nil { + return nil + } + out := new(User) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/mongodb/types.go b/api/apps/v1alpha1/mongodb/types.go new file mode 100644 index 00000000..886b716c --- /dev/null +++ b/api/apps/v1alpha1/mongodb/types.go @@ -0,0 +1,149 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package mongodb + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Number of MongoDB replicas in replica set. + // +kubebuilder:default:=3 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration for each MongoDB replica. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="small" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` + // Persistent Volume Claim size available for application data. + // +kubebuilder:default:="10Gi" + Size resource.Quantity `json:"size"` + // StorageClass used to store the data. + // +kubebuilder:default:="" + StorageClass string `json:"storageClass"` + // Enable external access from outside the cluster. + // +kubebuilder:default:=false + External bool `json:"external"` + // MongoDB major version to deploy. + // +kubebuilder:default:="v8" + Version Version `json:"version"` + // Enable sharded cluster mode. When disabled, deploys a replica set. + // +kubebuilder:default:=false + Sharding bool `json:"sharding"` + // Configuration for sharded cluster mode. + // +kubebuilder:default:={} + ShardingConfig ShardingConfig `json:"shardingConfig"` + // Users configuration map. + // +kubebuilder:default:={} + Users map[string]User `json:"users,omitempty"` + // Databases configuration map. + // +kubebuilder:default:={} + Databases map[string]Database `json:"databases,omitempty"` + // Backup configuration. + // +kubebuilder:default:={} + Backup Backup `json:"backup"` + // Bootstrap configuration. + // +kubebuilder:default:={} + Bootstrap Bootstrap `json:"bootstrap"` +} + +type Backup struct { + // Destination path for backups (e.g. s3://bucket/path/). + // +kubebuilder:default:="s3://bucket/path/to/folder/" + DestinationPath string `json:"destinationPath,omitempty"` + // Enable regular backups. + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` + // S3 endpoint URL for uploads. + // +kubebuilder:default:="http://minio-gateway-service:9000" + EndpointURL string `json:"endpointURL,omitempty"` + // Retention policy (e.g. "30d"). + // +kubebuilder:default:="30d" + RetentionPolicy string `json:"retentionPolicy,omitempty"` + // Access key for S3 authentication. + // +kubebuilder:default:="" + S3AccessKey string `json:"s3AccessKey,omitempty"` + // Secret key for S3 authentication. + // +kubebuilder:default:="" + S3SecretKey string `json:"s3SecretKey,omitempty"` + // Cron schedule for automated backups. + // +kubebuilder:default:="0 2 * * *" + Schedule string `json:"schedule,omitempty"` +} + +type Bootstrap struct { + // Name of backup to restore from. + // +kubebuilder:default:="" + BackupName string `json:"backupName"` + // Whether to restore from a backup. + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` + // Timestamp for point-in-time recovery; empty means latest. + // +kubebuilder:default:="" + RecoveryTime string `json:"recoveryTime,omitempty"` +} + +type Database struct { + // Roles assigned to users. + Roles DatabaseRoles `json:"roles,omitempty"` +} + +type DatabaseRoles struct { + // List of users with admin privileges (readWrite + dbAdmin). + Admin []string `json:"admin,omitempty"` + // List of users with read-only privileges. + Readonly []string `json:"readonly,omitempty"` +} + +type Resources struct { + // CPU available to each replica. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available to each replica. + Memory resource.Quantity `json:"memory,omitempty"` +} + +type Shard struct { + // Shard name. + Name string `json:"name"` + // Number of replicas in this shard. + Replicas int `json:"replicas"` + // PVC size for this shard. + Size resource.Quantity `json:"size"` +} + +type ShardingConfig struct { + // PVC size for config servers. + // +kubebuilder:default:="3Gi" + ConfigServerSize resource.Quantity `json:"configServerSize"` + // Number of config server replicas. + // +kubebuilder:default:=3 + ConfigServers int `json:"configServers"` + // Number of mongos router replicas. + // +kubebuilder:default:=2 + Mongos int `json:"mongos"` + // List of shard configurations. + // +kubebuilder:default:={{"name":"rs0","replicas":3,"size":"10Gi"}} + Shards []Shard `json:"shards,omitempty"` +} + +type User struct { + // Password for the user (auto-generated if omitted). + Password string `json:"password,omitempty"` +} + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string + +// +kubebuilder:validation:Enum="v8";"v7";"v6" +type Version string diff --git a/api/apps/v1alpha1/mongodb/zz_generated.deepcopy.go b/api/apps/v1alpha1/mongodb/zz_generated.deepcopy.go new file mode 100644 index 00000000..694009f4 --- /dev/null +++ b/api/apps/v1alpha1/mongodb/zz_generated.deepcopy.go @@ -0,0 +1,227 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package mongodb + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Backup) DeepCopyInto(out *Backup) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Backup. +func (in *Backup) DeepCopy() *Backup { + if in == nil { + return nil + } + out := new(Backup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Bootstrap) DeepCopyInto(out *Bootstrap) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Bootstrap. +func (in *Bootstrap) DeepCopy() *Bootstrap { + if in == nil { + return nil + } + out := new(Bootstrap) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + out.Size = in.Size.DeepCopy() + in.ShardingConfig.DeepCopyInto(&out.ShardingConfig) + if in.Users != nil { + in, out := &in.Users, &out.Users + *out = make(map[string]User, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Databases != nil { + in, out := &in.Databases, &out.Databases + *out = make(map[string]Database, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + out.Backup = in.Backup + out.Bootstrap = in.Bootstrap +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Database) DeepCopyInto(out *Database) { + *out = *in + in.Roles.DeepCopyInto(&out.Roles) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Database. +func (in *Database) DeepCopy() *Database { + if in == nil { + return nil + } + out := new(Database) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DatabaseRoles) DeepCopyInto(out *DatabaseRoles) { + *out = *in + if in.Admin != nil { + in, out := &in.Admin, &out.Admin + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Readonly != nil { + in, out := &in.Readonly, &out.Readonly + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DatabaseRoles. +func (in *DatabaseRoles) DeepCopy() *DatabaseRoles { + if in == nil { + return nil + } + out := new(DatabaseRoles) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Shard) DeepCopyInto(out *Shard) { + *out = *in + out.Size = in.Size.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Shard. +func (in *Shard) DeepCopy() *Shard { + if in == nil { + return nil + } + out := new(Shard) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ShardingConfig) DeepCopyInto(out *ShardingConfig) { + *out = *in + out.ConfigServerSize = in.ConfigServerSize.DeepCopy() + if in.Shards != nil { + in, out := &in.Shards, &out.Shards + *out = make([]Shard, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ShardingConfig. +func (in *ShardingConfig) DeepCopy() *ShardingConfig { + if in == nil { + return nil + } + out := new(ShardingConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *User) DeepCopyInto(out *User) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User. +func (in *User) DeepCopy() *User { + if in == nil { + return nil + } + out := new(User) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/nats/types.go b/api/apps/v1alpha1/nats/types.go new file mode 100644 index 00000000..5437355d --- /dev/null +++ b/api/apps/v1alpha1/nats/types.go @@ -0,0 +1,78 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package nats + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" + k8sRuntime "k8s.io/apimachinery/pkg/runtime" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Number of replicas. + // +kubebuilder:default:=2 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration for each NATS replica. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="nano" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` + // StorageClass used to store the data. + // +kubebuilder:default:="" + StorageClass string `json:"storageClass"` + // Enable external access from outside the cluster. + // +kubebuilder:default:=false + External bool `json:"external"` + // Users configuration map. + // +kubebuilder:default:={} + Users map[string]User `json:"users,omitempty"` + // Jetstream configuration. + // +kubebuilder:default:={} + Jetstream Jetstream `json:"jetstream"` + // NATS configuration. + // +kubebuilder:default:={} + Config ValuesConfig `json:"config"` +} + +type ValuesConfig struct { + // Additional configuration to merge into NATS config. + // +kubebuilder:default:={} + Merge *k8sRuntime.RawExtension `json:"merge,omitempty"` + // Additional resolver configuration to merge into NATS config. + // +kubebuilder:default:={} + Resolver *k8sRuntime.RawExtension `json:"resolver,omitempty"` +} + +type Jetstream struct { + // Enable or disable Jetstream for persistent messaging in NATS. + // +kubebuilder:default:=true + Enabled bool `json:"enabled"` + // Jetstream persistent storage size. + // +kubebuilder:default:="10Gi" + Size resource.Quantity `json:"size"` +} + +type Resources struct { + // CPU available to each replica. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available to each replica. + Memory resource.Quantity `json:"memory,omitempty"` +} + +type User struct { + // Password for the user. + Password string `json:"password,omitempty"` +} + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string diff --git a/api/apps/v1alpha1/nats/zz_generated.deepcopy.go b/api/apps/v1alpha1/nats/zz_generated.deepcopy.go new file mode 100644 index 00000000..f6c23cb1 --- /dev/null +++ b/api/apps/v1alpha1/nats/zz_generated.deepcopy.go @@ -0,0 +1,149 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package nats + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + if in.Users != nil { + in, out := &in.Users, &out.Users + *out = make(map[string]User, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + in.Jetstream.DeepCopyInto(&out.Jetstream) + in.Config.DeepCopyInto(&out.Config) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Jetstream) DeepCopyInto(out *Jetstream) { + *out = *in + out.Size = in.Size.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Jetstream. +func (in *Jetstream) DeepCopy() *Jetstream { + if in == nil { + return nil + } + out := new(Jetstream) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *User) DeepCopyInto(out *User) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User. +func (in *User) DeepCopy() *User { + if in == nil { + return nil + } + out := new(User) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ValuesConfig) DeepCopyInto(out *ValuesConfig) { + *out = *in + if in.Merge != nil { + in, out := &in.Merge, &out.Merge + *out = new(runtime.RawExtension) + (*in).DeepCopyInto(*out) + } + if in.Resolver != nil { + in, out := &in.Resolver, &out.Resolver + *out = new(runtime.RawExtension) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ValuesConfig. +func (in *ValuesConfig) DeepCopy() *ValuesConfig { + if in == nil { + return nil + } + out := new(ValuesConfig) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/openbao/types.go b/api/apps/v1alpha1/openbao/types.go new file mode 100644 index 00000000..bb5d12d9 --- /dev/null +++ b/api/apps/v1alpha1/openbao/types.go @@ -0,0 +1,51 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package openbao + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Number of OpenBAO replicas. HA with Raft is automatically enabled when replicas > 1. Switching between standalone (file storage) and HA (Raft storage) modes requires data migration. + // +kubebuilder:default:=1 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration for each OpenBAO replica. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="small" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` + // Persistent Volume Claim size for data storage. + // +kubebuilder:default:="10Gi" + Size resource.Quantity `json:"size"` + // StorageClass used to store the data. + // +kubebuilder:default:="" + StorageClass string `json:"storageClass"` + // Enable external access from outside the cluster. + // +kubebuilder:default:=false + External bool `json:"external"` + // Enable the OpenBAO web UI. + // +kubebuilder:default:=true + Ui bool `json:"ui"` +} + +type Resources struct { + // CPU available to each replica. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available to each replica. + Memory resource.Quantity `json:"memory,omitempty"` +} + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string diff --git a/api/apps/v1alpha1/openbao/zz_generated.deepcopy.go b/api/apps/v1alpha1/openbao/zz_generated.deepcopy.go new file mode 100644 index 00000000..baa1258b --- /dev/null +++ b/api/apps/v1alpha1/openbao/zz_generated.deepcopy.go @@ -0,0 +1,85 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package openbao + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + out.Size = in.Size.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/opensearch/types.go b/api/apps/v1alpha1/opensearch/types.go new file mode 100644 index 00000000..b188cdfa --- /dev/null +++ b/api/apps/v1alpha1/opensearch/types.go @@ -0,0 +1,115 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package opensearch + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Number of OpenSearch nodes in the cluster. + // +kubebuilder:default:=3 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration for each OpenSearch node. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. OpenSearch requires minimum 2Gi memory. + // +kubebuilder:default:="large" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` + // Persistent Volume Claim size available for application data. + // +kubebuilder:default:="10Gi" + Size resource.Quantity `json:"size"` + // StorageClass used to store the data. + // +kubebuilder:default:="" + StorageClass string `json:"storageClass"` + // Enable external access from outside the cluster. + // +kubebuilder:default:=false + External bool `json:"external"` + // How strictly to enforce pod distribution across nodes and zones. + // +kubebuilder:default:="soft" + TopologySpreadPolicy TopologySpreadPolicy `json:"topologySpreadPolicy"` + // OpenSearch major version to deploy. + // +kubebuilder:default:="v2" + Version Version `json:"version"` + // Container images used by the operator. + // +kubebuilder:default:={} + Images Images `json:"images"` + // Node roles configuration. + // +kubebuilder:default:={} + NodeRoles NodeRoles `json:"nodeRoles"` + // Custom OpenSearch users configuration map. + // +kubebuilder:default:={} + Users map[string]User `json:"users,omitempty"` + // OpenSearch Dashboards configuration. + // +kubebuilder:default:={} + Dashboards Dashboards `json:"dashboards"` +} + +type Dashboards struct { + // Enable OpenSearch Dashboards deployment. + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` + // Number of Dashboards replicas. + // +kubebuilder:default:=1 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration for Dashboards. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset for Dashboards. + // +kubebuilder:default:="medium" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` +} + +type Images struct { + // OpenSearch image. + // +kubebuilder:default:="" + Opensearch string `json:"opensearch"` +} + +type NodeRoles struct { + // Enable data role. + // +kubebuilder:default:=true + Data bool `json:"data"` + // Enable ingest role. + // +kubebuilder:default:=true + Ingest bool `json:"ingest"` + // Enable cluster_manager role. + // +kubebuilder:default:=true + Master bool `json:"master"` + // Enable machine learning role. + // +kubebuilder:default:=false + Ml bool `json:"ml"` +} + +type Resources struct { + // CPU available to each node. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available to each node. + Memory resource.Quantity `json:"memory,omitempty"` +} + +type User struct { + // Password for the user (auto-generated if omitted). + Password string `json:"password,omitempty"` + // List of OpenSearch roles. + Roles []string `json:"roles,omitempty"` +} + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string + +// +kubebuilder:validation:Enum="soft";"hard" +type TopologySpreadPolicy string + +// +kubebuilder:validation:Enum="v3";"v2";"v1" +type Version string diff --git a/api/apps/v1alpha1/opensearch/zz_generated.deepcopy.go b/api/apps/v1alpha1/opensearch/zz_generated.deepcopy.go new file mode 100644 index 00000000..f7f2daef --- /dev/null +++ b/api/apps/v1alpha1/opensearch/zz_generated.deepcopy.go @@ -0,0 +1,161 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package opensearch + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + out.Size = in.Size.DeepCopy() + out.Images = in.Images + out.NodeRoles = in.NodeRoles + if in.Users != nil { + in, out := &in.Users, &out.Users + *out = make(map[string]User, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + in.Dashboards.DeepCopyInto(&out.Dashboards) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Dashboards) DeepCopyInto(out *Dashboards) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Dashboards. +func (in *Dashboards) DeepCopy() *Dashboards { + if in == nil { + return nil + } + out := new(Dashboards) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Images) DeepCopyInto(out *Images) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Images. +func (in *Images) DeepCopy() *Images { + if in == nil { + return nil + } + out := new(Images) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeRoles) DeepCopyInto(out *NodeRoles) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeRoles. +func (in *NodeRoles) DeepCopy() *NodeRoles { + if in == nil { + return nil + } + out := new(NodeRoles) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *User) DeepCopyInto(out *User) { + *out = *in + if in.Roles != nil { + in, out := &in.Roles, &out.Roles + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User. +func (in *User) DeepCopy() *User { + if in == nil { + return nil + } + out := new(User) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/postgresql/types.go b/api/apps/v1alpha1/postgresql/types.go new file mode 100644 index 00000000..a2ff77a8 --- /dev/null +++ b/api/apps/v1alpha1/postgresql/types.go @@ -0,0 +1,153 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package postgresql + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Number of Postgres replicas. + // +kubebuilder:default:=2 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration for each PostgreSQL replica. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="micro" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` + // Persistent Volume Claim size available for application data. + // +kubebuilder:default:="10Gi" + Size resource.Quantity `json:"size"` + // StorageClass used to store the data. + // +kubebuilder:default:="" + StorageClass string `json:"storageClass"` + // Enable external access from outside the cluster. + // +kubebuilder:default:=false + External bool `json:"external"` + // PostgreSQL major version to deploy + // +kubebuilder:default:="v18" + Version Version `json:"version"` + // PostgreSQL server configuration. + // +kubebuilder:default:={} + Postgresql PostgreSQL `json:"postgresql"` + // Quorum configuration for synchronous replication. + // +kubebuilder:default:={} + Quorum Quorum `json:"quorum"` + // Users configuration map. + // +kubebuilder:default:={} + Users map[string]User `json:"users,omitempty"` + // Databases configuration map. + // +kubebuilder:default:={} + Databases map[string]Database `json:"databases,omitempty"` + // Backup configuration. + // +kubebuilder:default:={} + Backup Backup `json:"backup"` + // Bootstrap configuration. + // +kubebuilder:default:={} + Bootstrap Bootstrap `json:"bootstrap"` +} + +type Backup struct { + // Destination path for backups (e.g. s3://bucket/path/). + // +kubebuilder:default:="s3://bucket/path/to/folder/" + DestinationPath string `json:"destinationPath,omitempty"` + // Enable regular backups. + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` + // S3 endpoint URL for uploads. + // +kubebuilder:default:="http://minio-gateway-service:9000" + EndpointURL string `json:"endpointURL,omitempty"` + // Retention policy (e.g. "30d"). + // +kubebuilder:default:="30d" + RetentionPolicy string `json:"retentionPolicy,omitempty"` + // Access key for S3 authentication. + // +kubebuilder:default:="" + S3AccessKey string `json:"s3AccessKey,omitempty"` + // Secret key for S3 authentication. + // +kubebuilder:default:="" + S3SecretKey string `json:"s3SecretKey,omitempty"` + // Cron schedule for automated backups. + // +kubebuilder:default:="0 2 * * * *" + Schedule string `json:"schedule,omitempty"` +} + +type Bootstrap struct { + // Whether to restore from a backup. + // +kubebuilder:default:=false + Enabled bool `json:"enabled"` + // Previous cluster name before deletion. + // +kubebuilder:default:="" + OldName string `json:"oldName"` + // Timestamp (RFC3339) for point-in-time recovery; empty means latest. + // +kubebuilder:default:="" + RecoveryTime string `json:"recoveryTime,omitempty"` + // Barman server name (S3 path prefix) used by the original cluster when writing backups. Set this only when the original cluster had an explicit barmanObjectStore.serverName that differed from its Kubernetes resource name. + // +kubebuilder:default:="" + ServerName string `json:"serverName,omitempty"` +} + +type Database struct { + // List of enabled PostgreSQL extensions. + Extensions []string `json:"extensions,omitempty"` + // Roles assigned to users. + Roles DatabaseRoles `json:"roles,omitempty"` +} + +type DatabaseRoles struct { + // List of users with admin privileges. + Admin []string `json:"admin,omitempty"` + // List of users with read-only privileges. + Readonly []string `json:"readonly,omitempty"` +} + +type PostgreSQL struct { + // PostgreSQL server parameters. + // +kubebuilder:default:={} + Parameters PostgreSQLParameters `json:"parameters,omitempty"` +} + +type PostgreSQLParameters struct { + // Maximum number of concurrent connections to the database server. + // +kubebuilder:default:=100 + MaxConnections int `json:"max_connections,omitempty"` +} + +type Quorum struct { + // Maximum number of synchronous replicas allowed (must be less than total replicas). + // +kubebuilder:default:=0 + MaxSyncReplicas int `json:"maxSyncReplicas"` + // Minimum number of synchronous replicas required for commit. + // +kubebuilder:default:=0 + MinSyncReplicas int `json:"minSyncReplicas"` +} + +type Resources struct { + // CPU available to each replica. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available to each replica. + Memory resource.Quantity `json:"memory,omitempty"` +} + +type User struct { + // Password for the user. + Password string `json:"password,omitempty"` + // Whether the user has replication privileges. + Replication bool `json:"replication,omitempty"` +} + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string + +// +kubebuilder:validation:Enum="v18";"v17";"v16";"v15";"v14";"v13" +type Version string diff --git a/api/apps/v1alpha1/postgresql/zz_generated.deepcopy.go b/api/apps/v1alpha1/postgresql/zz_generated.deepcopy.go new file mode 100644 index 00000000..5fba855e --- /dev/null +++ b/api/apps/v1alpha1/postgresql/zz_generated.deepcopy.go @@ -0,0 +1,240 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package postgresql + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Backup) DeepCopyInto(out *Backup) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Backup. +func (in *Backup) DeepCopy() *Backup { + if in == nil { + return nil + } + out := new(Backup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Bootstrap) DeepCopyInto(out *Bootstrap) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Bootstrap. +func (in *Bootstrap) DeepCopy() *Bootstrap { + if in == nil { + return nil + } + out := new(Bootstrap) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + out.Size = in.Size.DeepCopy() + out.Postgresql = in.Postgresql + out.Quorum = in.Quorum + if in.Users != nil { + in, out := &in.Users, &out.Users + *out = make(map[string]User, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Databases != nil { + in, out := &in.Databases, &out.Databases + *out = make(map[string]Database, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + out.Backup = in.Backup + out.Bootstrap = in.Bootstrap +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Database) DeepCopyInto(out *Database) { + *out = *in + if in.Extensions != nil { + in, out := &in.Extensions, &out.Extensions + *out = make([]string, len(*in)) + copy(*out, *in) + } + in.Roles.DeepCopyInto(&out.Roles) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Database. +func (in *Database) DeepCopy() *Database { + if in == nil { + return nil + } + out := new(Database) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DatabaseRoles) DeepCopyInto(out *DatabaseRoles) { + *out = *in + if in.Admin != nil { + in, out := &in.Admin, &out.Admin + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Readonly != nil { + in, out := &in.Readonly, &out.Readonly + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DatabaseRoles. +func (in *DatabaseRoles) DeepCopy() *DatabaseRoles { + if in == nil { + return nil + } + out := new(DatabaseRoles) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PostgreSQL) DeepCopyInto(out *PostgreSQL) { + *out = *in + out.Parameters = in.Parameters +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PostgreSQL. +func (in *PostgreSQL) DeepCopy() *PostgreSQL { + if in == nil { + return nil + } + out := new(PostgreSQL) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PostgreSQLParameters) DeepCopyInto(out *PostgreSQLParameters) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PostgreSQLParameters. +func (in *PostgreSQLParameters) DeepCopy() *PostgreSQLParameters { + if in == nil { + return nil + } + out := new(PostgreSQLParameters) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Quorum) DeepCopyInto(out *Quorum) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Quorum. +func (in *Quorum) DeepCopy() *Quorum { + if in == nil { + return nil + } + out := new(Quorum) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *User) DeepCopyInto(out *User) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User. +func (in *User) DeepCopy() *User { + if in == nil { + return nil + } + out := new(User) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/qdrant/types.go b/api/apps/v1alpha1/qdrant/types.go new file mode 100644 index 00000000..203e9a97 --- /dev/null +++ b/api/apps/v1alpha1/qdrant/types.go @@ -0,0 +1,48 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package qdrant + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Number of Qdrant replicas. Cluster mode is automatically enabled when replicas > 1. + // +kubebuilder:default:=1 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration for each Qdrant replica. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="small" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` + // Persistent Volume Claim size available for vector data storage. + // +kubebuilder:default:="10Gi" + Size resource.Quantity `json:"size"` + // StorageClass used to store the data. + // +kubebuilder:default:="" + StorageClass string `json:"storageClass"` + // Enable external access from outside the cluster. + // +kubebuilder:default:=false + External bool `json:"external"` +} + +type Resources struct { + // CPU available to each replica. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available to each replica. + Memory resource.Quantity `json:"memory,omitempty"` +} + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string diff --git a/api/apps/v1alpha1/qdrant/zz_generated.deepcopy.go b/api/apps/v1alpha1/qdrant/zz_generated.deepcopy.go new file mode 100644 index 00000000..2abfd37e --- /dev/null +++ b/api/apps/v1alpha1/qdrant/zz_generated.deepcopy.go @@ -0,0 +1,85 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package qdrant + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + out.Size = in.Size.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/rabbitmq/types.go b/api/apps/v1alpha1/rabbitmq/types.go new file mode 100644 index 00000000..f67c4402 --- /dev/null +++ b/api/apps/v1alpha1/rabbitmq/types.go @@ -0,0 +1,77 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package rabbitmq + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Number of RabbitMQ replicas. + // +kubebuilder:default:=3 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration for each RabbitMQ replica. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="nano" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` + // Persistent Volume Claim size available for application data. + // +kubebuilder:default:="10Gi" + Size resource.Quantity `json:"size"` + // StorageClass used to store the data. + // +kubebuilder:default:="" + StorageClass string `json:"storageClass"` + // Enable external access from outside the cluster. + // +kubebuilder:default:=false + External bool `json:"external"` + // RabbitMQ major.minor version to deploy + // +kubebuilder:default:="v4.2" + Version Version `json:"version"` + // Users configuration map. + // +kubebuilder:default:={} + Users map[string]User `json:"users,omitempty"` + // Virtual hosts configuration map. + // +kubebuilder:default:={} + Vhosts map[string]Vhost `json:"vhosts,omitempty"` +} + +type Resources struct { + // CPU available to each replica. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available to each replica. + Memory resource.Quantity `json:"memory,omitempty"` +} + +type Roles struct { + // List of admin users. + Admin []string `json:"admin,omitempty"` + // List of readonly users. + Readonly []string `json:"readonly,omitempty"` +} + +type User struct { + // Password for the user. + Password string `json:"password,omitempty"` +} + +type Vhost struct { + // Virtual host roles list. + Roles Roles `json:"roles"` +} + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string + +// +kubebuilder:validation:Enum="v4.2";"v4.1";"v4.0";"v3.13" +type Version string diff --git a/api/apps/v1alpha1/rabbitmq/zz_generated.deepcopy.go b/api/apps/v1alpha1/rabbitmq/zz_generated.deepcopy.go new file mode 100644 index 00000000..a1d55f89 --- /dev/null +++ b/api/apps/v1alpha1/rabbitmq/zz_generated.deepcopy.go @@ -0,0 +1,155 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package rabbitmq + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + out.Size = in.Size.DeepCopy() + if in.Users != nil { + in, out := &in.Users, &out.Users + *out = make(map[string]User, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Vhosts != nil { + in, out := &in.Vhosts, &out.Vhosts + *out = make(map[string]Vhost, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Roles) DeepCopyInto(out *Roles) { + *out = *in + if in.Admin != nil { + in, out := &in.Admin, &out.Admin + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Readonly != nil { + in, out := &in.Readonly, &out.Readonly + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Roles. +func (in *Roles) DeepCopy() *Roles { + if in == nil { + return nil + } + out := new(Roles) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *User) DeepCopyInto(out *User) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User. +func (in *User) DeepCopy() *User { + if in == nil { + return nil + } + out := new(User) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Vhost) DeepCopyInto(out *Vhost) { + *out = *in + in.Roles.DeepCopyInto(&out.Roles) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Vhost. +func (in *Vhost) DeepCopy() *Vhost { + if in == nil { + return nil + } + out := new(Vhost) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/redis/types.go b/api/apps/v1alpha1/redis/types.go new file mode 100644 index 00000000..e9a02c72 --- /dev/null +++ b/api/apps/v1alpha1/redis/types.go @@ -0,0 +1,57 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package redis + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Number of Redis replicas. + // +kubebuilder:default:=2 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration for each Redis replica. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="nano" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` + // Persistent Volume Claim size available for application data. + // +kubebuilder:default:="1Gi" + Size resource.Quantity `json:"size"` + // StorageClass used to store the data. + // +kubebuilder:default:="" + StorageClass string `json:"storageClass"` + // Enable external access from outside the cluster. + // +kubebuilder:default:=false + External bool `json:"external"` + // Redis major version to deploy + // +kubebuilder:default:="v8" + Version Version `json:"version"` + // Enable password generation. + // +kubebuilder:default:=true + AuthEnabled bool `json:"authEnabled"` +} + +type Resources struct { + // CPU available to each replica. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available to each replica. + Memory resource.Quantity `json:"memory,omitempty"` +} + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string + +// +kubebuilder:validation:Enum="v8";"v7" +type Version string diff --git a/api/apps/v1alpha1/redis/zz_generated.deepcopy.go b/api/apps/v1alpha1/redis/zz_generated.deepcopy.go new file mode 100644 index 00000000..6390200c --- /dev/null +++ b/api/apps/v1alpha1/redis/zz_generated.deepcopy.go @@ -0,0 +1,85 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package redis + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + out.Size = in.Size.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/tcpbalancer/types.go b/api/apps/v1alpha1/tcpbalancer/types.go new file mode 100644 index 00000000..aa99cd6d --- /dev/null +++ b/api/apps/v1alpha1/tcpbalancer/types.go @@ -0,0 +1,75 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package tcpbalancer + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Number of HAProxy replicas. + // +kubebuilder:default:=2 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration for each TCP Balancer replica. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="nano" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` + // Enable external access from outside the cluster. + // +kubebuilder:default:=false + External bool `json:"external"` + // HTTP and HTTPS configuration. + // +kubebuilder:default:={} + HttpAndHttps HttpAndHttps `json:"httpAndHttps"` + // Secure HTTP by whitelisting client networks (default: false). + // +kubebuilder:default:=false + WhitelistHTTP bool `json:"whitelistHTTP"` + // List of allowed client networks. + // +kubebuilder:default:={} + Whitelist []string `json:"whitelist,omitempty"` +} + +type HttpAndHttps struct { + // Endpoint addresses list. + // +kubebuilder:default:={} + Endpoints []string `json:"endpoints,omitempty"` + // Mode for balancer. + // +kubebuilder:default:="tcp" + Mode Mode `json:"mode"` + // Target ports configuration. + // +kubebuilder:default:={} + TargetPorts TargetPorts `json:"targetPorts"` +} + +type Resources struct { + // CPU available to each replica. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available to each replica. + Memory resource.Quantity `json:"memory,omitempty"` +} + +type TargetPorts struct { + // HTTP port number. + // +kubebuilder:default:=80 + Http int `json:"http"` + // HTTPS port number. + // +kubebuilder:default:=443 + Https int `json:"https"` +} + +// +kubebuilder:validation:Enum="tcp";"tcp-with-proxy" +type Mode string + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string diff --git a/api/apps/v1alpha1/tcpbalancer/zz_generated.deepcopy.go b/api/apps/v1alpha1/tcpbalancer/zz_generated.deepcopy.go new file mode 100644 index 00000000..1c63eafc --- /dev/null +++ b/api/apps/v1alpha1/tcpbalancer/zz_generated.deepcopy.go @@ -0,0 +1,126 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package tcpbalancer + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + in.HttpAndHttps.DeepCopyInto(&out.HttpAndHttps) + if in.Whitelist != nil { + in, out := &in.Whitelist, &out.Whitelist + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HttpAndHttps) DeepCopyInto(out *HttpAndHttps) { + *out = *in + if in.Endpoints != nil { + in, out := &in.Endpoints, &out.Endpoints + *out = make([]string, len(*in)) + copy(*out, *in) + } + out.TargetPorts = in.TargetPorts +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HttpAndHttps. +func (in *HttpAndHttps) DeepCopy() *HttpAndHttps { + if in == nil { + return nil + } + out := new(HttpAndHttps) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetPorts) DeepCopyInto(out *TargetPorts) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetPorts. +func (in *TargetPorts) DeepCopy() *TargetPorts { + if in == nil { + return nil + } + out := new(TargetPorts) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/tenant/types.go b/api/apps/v1alpha1/tenant/types.go new file mode 100644 index 00000000..60f8bb22 --- /dev/null +++ b/api/apps/v1alpha1/tenant/types.go @@ -0,0 +1,41 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package tenant + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // The hostname used to access tenant services (defaults to using the tenant name as a subdomain for its parent tenant host). + // +kubebuilder:default:="" + Host string `json:"host,omitempty"` + // Deploy own Etcd cluster. + // +kubebuilder:default:=false + Etcd bool `json:"etcd"` + // Deploy own Monitoring Stack. + // +kubebuilder:default:=false + Monitoring bool `json:"monitoring"` + // Deploy own Ingress Controller. + // +kubebuilder:default:=false + Ingress bool `json:"ingress"` + // Deploy own SeaweedFS. + // +kubebuilder:default:=false + Seaweedfs bool `json:"seaweedfs"` + // The name of a SchedulingClass CR to apply scheduling constraints for this tenant's workloads. + // +kubebuilder:default:="" + SchedulingClass string `json:"schedulingClass,omitempty"` + // Define resource quotas for the tenant. + // +kubebuilder:default:={} + ResourceQuotas map[string]resource.Quantity `json:"resourceQuotas,omitempty"` +} diff --git a/api/apps/v1alpha1/tenant/zz_generated.deepcopy.go b/api/apps/v1alpha1/tenant/zz_generated.deepcopy.go new file mode 100644 index 00000000..784a8f25 --- /dev/null +++ b/api/apps/v1alpha1/tenant/zz_generated.deepcopy.go @@ -0,0 +1,74 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package tenant + +import ( + "k8s.io/apimachinery/pkg/api/resource" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + if in.ResourceQuotas != nil { + in, out := &in.ResourceQuotas, &out.ResourceQuotas + *out = make(map[string]resource.Quantity, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/vmdisk/types.go b/api/apps/v1alpha1/vmdisk/types.go new file mode 100644 index 00000000..c493f49c --- /dev/null +++ b/api/apps/v1alpha1/vmdisk/types.go @@ -0,0 +1,61 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package vmdisk + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // The source image location used to create a disk. + // +kubebuilder:default:={} + Source Source `json:"source"` + // Defines if disk should be considered optical. + // +kubebuilder:default:=false + Optical bool `json:"optical"` + // The size of the disk allocated for the virtual machine. + // +kubebuilder:default:="5Gi" + Storage resource.Quantity `json:"storage"` + // StorageClass used to store the data. + // +kubebuilder:default:="replicated" + StorageClass string `json:"storageClass"` +} + +type Source struct { + // Clone an existing vm-disk. + Disk *SourceDisk `json:"disk,omitempty"` + // Download image from an HTTP source. + Http *SourceHTTP `json:"http,omitempty"` + // Use image by name from default collection. + Image *SourceImage `json:"image,omitempty"` + // Upload local image. + Upload *SourceUpload `json:"upload,omitempty"` +} + +type SourceDisk struct { + // Name of the vm-disk to clone. + Name string `json:"name"` +} + +type SourceHTTP struct { + // URL to download the image. + Url string `json:"url"` +} + +type SourceImage struct { + // Name of the image to use. + Name string `json:"name"` +} + +type SourceUpload struct { +} diff --git a/api/apps/v1alpha1/vmdisk/zz_generated.deepcopy.go b/api/apps/v1alpha1/vmdisk/zz_generated.deepcopy.go new file mode 100644 index 00000000..301bb1d9 --- /dev/null +++ b/api/apps/v1alpha1/vmdisk/zz_generated.deepcopy.go @@ -0,0 +1,163 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package vmdisk + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + in.Source.DeepCopyInto(&out.Source) + out.Storage = in.Storage.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Source) DeepCopyInto(out *Source) { + *out = *in + if in.Disk != nil { + in, out := &in.Disk, &out.Disk + *out = new(SourceDisk) + **out = **in + } + if in.Http != nil { + in, out := &in.Http, &out.Http + *out = new(SourceHTTP) + **out = **in + } + if in.Image != nil { + in, out := &in.Image, &out.Image + *out = new(SourceImage) + **out = **in + } + if in.Upload != nil { + in, out := &in.Upload, &out.Upload + *out = new(SourceUpload) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Source. +func (in *Source) DeepCopy() *Source { + if in == nil { + return nil + } + out := new(Source) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SourceDisk) DeepCopyInto(out *SourceDisk) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceDisk. +func (in *SourceDisk) DeepCopy() *SourceDisk { + if in == nil { + return nil + } + out := new(SourceDisk) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SourceHTTP) DeepCopyInto(out *SourceHTTP) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceHTTP. +func (in *SourceHTTP) DeepCopy() *SourceHTTP { + if in == nil { + return nil + } + out := new(SourceHTTP) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SourceImage) DeepCopyInto(out *SourceImage) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceImage. +func (in *SourceImage) DeepCopy() *SourceImage { + if in == nil { + return nil + } + out := new(SourceImage) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SourceUpload) DeepCopyInto(out *SourceUpload) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceUpload. +func (in *SourceUpload) DeepCopy() *SourceUpload { + if in == nil { + return nil + } + out := new(SourceUpload) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/vminstance/types.go b/api/apps/v1alpha1/vminstance/types.go new file mode 100644 index 00000000..9c48724a --- /dev/null +++ b/api/apps/v1alpha1/vminstance/types.go @@ -0,0 +1,100 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package vminstance + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Enable external access from outside the cluster. + // +kubebuilder:default:=false + External bool `json:"external"` + // Method to pass through traffic to the VM. + // +kubebuilder:default:="PortList" + ExternalMethod ExternalMethod `json:"externalMethod"` + // Ports to forward from outside the cluster. + // +kubebuilder:default:={22} + ExternalPorts []int `json:"externalPorts,omitempty"` + // Whether to accept ICMP traffic to the VM in PortList mode (preserves ping and PMTU discovery). No effect in WholeIP mode. Default true so ping behaves as users expect even when port filtering is in effect. + // +kubebuilder:default:=true + ExternalAllowICMP bool `json:"externalAllowICMP"` + // Requested running state of the VirtualMachineInstance + // +kubebuilder:default:="Always" + RunStrategy RunStrategy `json:"runStrategy"` + // Virtual Machine instance type. + // +kubebuilder:default:="u1.medium" + InstanceType string `json:"instanceType"` + // Virtual Machine preferences profile. + // +kubebuilder:default:="ubuntu" + InstanceProfile string `json:"instanceProfile"` + // List of disks to attach. + // +kubebuilder:default:={} + Disks []Disk `json:"disks,omitempty"` + // Networks to attach the VM to. + // +kubebuilder:default:={} + Networks []Network `json:"networks,omitempty"` + // Deprecated: use networks instead. + // +kubebuilder:default:={} + Subnets []Network `json:"subnets,omitempty"` + // List of GPUs to attach (NVIDIA driver requires at least 4 GiB RAM). + // +kubebuilder:default:={} + Gpus []GPU `json:"gpus,omitempty"` + // Model specifies the CPU model inside the VMI. List of available models https://github.com/libvirt/libvirt/tree/master/src/cpu_map + // +kubebuilder:default:="" + CpuModel string `json:"cpuModel"` + // Resource configuration for the virtual machine. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // List of SSH public keys for authentication. + // +kubebuilder:default:={} + SshKeys []string `json:"sshKeys,omitempty"` + // Cloud-init user data. + // +kubebuilder:default:="" + CloudInit string `json:"cloudInit"` + // Seed string to generate SMBIOS UUID for the VM. + // +kubebuilder:default:="" + CloudInitSeed string `json:"cloudInitSeed"` +} + +type Disk struct { + // Disk bus type (e.g. "sata"). + Bus string `json:"bus,omitempty"` + // Disk name. + Name string `json:"name"` +} + +type GPU struct { + // The name of the GPU resource to attach. + Name string `json:"name"` +} + +type Network struct { + // Network attachment name. + Name string `json:"name,omitempty"` +} + +type Resources struct { + // Number of CPU cores allocated. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Amount of memory allocated. + Memory resource.Quantity `json:"memory,omitempty"` + // Number of CPU sockets (vCPU topology). + Sockets resource.Quantity `json:"sockets,omitempty"` +} + +// +kubebuilder:validation:Enum="PortList";"WholeIP" +type ExternalMethod string + +// +kubebuilder:validation:Enum="Always";"Halted";"Manual";"RerunOnFailure";"Once" +type RunStrategy string diff --git a/api/apps/v1alpha1/vminstance/zz_generated.deepcopy.go b/api/apps/v1alpha1/vminstance/zz_generated.deepcopy.go new file mode 100644 index 00000000..86d5ddfc --- /dev/null +++ b/api/apps/v1alpha1/vminstance/zz_generated.deepcopy.go @@ -0,0 +1,160 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package vminstance + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + if in.ExternalPorts != nil { + in, out := &in.ExternalPorts, &out.ExternalPorts + *out = make([]int, len(*in)) + copy(*out, *in) + } + if in.Disks != nil { + in, out := &in.Disks, &out.Disks + *out = make([]Disk, len(*in)) + copy(*out, *in) + } + if in.Networks != nil { + in, out := &in.Networks, &out.Networks + *out = make([]Network, len(*in)) + copy(*out, *in) + } + if in.Subnets != nil { + in, out := &in.Subnets, &out.Subnets + *out = make([]Network, len(*in)) + copy(*out, *in) + } + if in.Gpus != nil { + in, out := &in.Gpus, &out.Gpus + *out = make([]GPU, len(*in)) + copy(*out, *in) + } + in.Resources.DeepCopyInto(&out.Resources) + if in.SshKeys != nil { + in, out := &in.SshKeys, &out.SshKeys + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Disk) DeepCopyInto(out *Disk) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Disk. +func (in *Disk) DeepCopy() *Disk { + if in == nil { + return nil + } + out := new(Disk) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GPU) DeepCopyInto(out *GPU) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GPU. +func (in *GPU) DeepCopy() *GPU { + if in == nil { + return nil + } + out := new(GPU) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Network) DeepCopyInto(out *Network) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Network. +func (in *Network) DeepCopy() *Network { + if in == nil { + return nil + } + out := new(Network) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() + out.Sockets = in.Sockets.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/vpc/types.go b/api/apps/v1alpha1/vpc/types.go new file mode 100644 index 00000000..fed72f58 --- /dev/null +++ b/api/apps/v1alpha1/vpc/types.go @@ -0,0 +1,49 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package vpc + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Subnets of a VPC + // +kubebuilder:default:={} + Subnets []Subnet `json:"subnets,omitempty"` + // VPC peering connections (bidirectional declaration required) + // +kubebuilder:default:={} + Peers []Peer `json:"peers,omitempty"` + // Static routes for the VPC + // +kubebuilder:default:={} + Routes []Route `json:"routes,omitempty"` +} + +type Peer struct { + // Namespace of the remote tenant + TenantNamespace string `json:"tenantNamespace"` + // Logical name of the remote VPC (without "virtualprivatecloud-" prefix) + VpcName string `json:"vpcName"` +} + +type Route struct { + // Destination CIDR + Cidr string `json:"cidr"` + // Next hop IP address + NextHopIP string `json:"nextHopIP"` +} + +type Subnet struct { + // IP address range + Cidr string `json:"cidr,omitempty"` + // Subnet name + Name string `json:"name"` +} diff --git a/api/apps/v1alpha1/vpc/zz_generated.deepcopy.go b/api/apps/v1alpha1/vpc/zz_generated.deepcopy.go new file mode 100644 index 00000000..3cda29c4 --- /dev/null +++ b/api/apps/v1alpha1/vpc/zz_generated.deepcopy.go @@ -0,0 +1,126 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package vpc + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + if in.Subnets != nil { + in, out := &in.Subnets, &out.Subnets + *out = make([]Subnet, len(*in)) + copy(*out, *in) + } + if in.Peers != nil { + in, out := &in.Peers, &out.Peers + *out = make([]Peer, len(*in)) + copy(*out, *in) + } + if in.Routes != nil { + in, out := &in.Routes, &out.Routes + *out = make([]Route, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Peer) DeepCopyInto(out *Peer) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Peer. +func (in *Peer) DeepCopy() *Peer { + if in == nil { + return nil + } + out := new(Peer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Route) DeepCopyInto(out *Route) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Route. +func (in *Route) DeepCopy() *Route { + if in == nil { + return nil + } + out := new(Route) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Subnet) DeepCopyInto(out *Subnet) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Subnet. +func (in *Subnet) DeepCopy() *Subnet { + if in == nil { + return nil + } + out := new(Subnet) + in.DeepCopyInto(out) + return out +} diff --git a/api/apps/v1alpha1/vpn/types.go b/api/apps/v1alpha1/vpn/types.go new file mode 100644 index 00000000..7ec0b0e3 --- /dev/null +++ b/api/apps/v1alpha1/vpn/types.go @@ -0,0 +1,56 @@ +// Code generated by values-gen. DO NOT EDIT. +// +kubebuilder:object:generate=true +// +groupName=apps.cozystack.io +// +versionName=v1alpha1 +package vpn + +import ( + resource "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +type Config struct { + v1.TypeMeta `json:",inline"` + v1.ObjectMeta `json:"metadata,omitempty"` + Spec ConfigSpec `json:"spec,omitempty"` +} + +type ConfigSpec struct { + // Number of VPN server replicas. + // +kubebuilder:default:=2 + Replicas int `json:"replicas"` + // Explicit CPU and memory configuration for each VPN server replica. When omitted, the preset defined in `resourcesPreset` is applied. + // +kubebuilder:default:={} + Resources Resources `json:"resources,omitempty"` + // Default sizing preset used when `resources` is omitted. + // +kubebuilder:default:="nano" + ResourcesPreset ResourcesPreset `json:"resourcesPreset"` + // Enable external access from outside the cluster. + // +kubebuilder:default:=false + External bool `json:"external"` + // Host used to substitute into generated URLs. + // +kubebuilder:default:="" + Host string `json:"host"` + // Users configuration map. + // +kubebuilder:default:={} + Users map[string]User `json:"users,omitempty"` + // List of externalIPs for service. Optional. If not specified, will use LoadBalancer service by default. + // +kubebuilder:default:={} + ExternalIPs []string `json:"externalIPs,omitempty"` +} + +type Resources struct { + // CPU available to each replica. + Cpu resource.Quantity `json:"cpu,omitempty"` + // Memory (RAM) available to each replica. + Memory resource.Quantity `json:"memory,omitempty"` +} + +type User struct { + // Password for the user (autogenerated if not provided). + Password string `json:"password,omitempty"` +} + +// +kubebuilder:validation:Enum="nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" +type ResourcesPreset string diff --git a/api/apps/v1alpha1/vpn/zz_generated.deepcopy.go b/api/apps/v1alpha1/vpn/zz_generated.deepcopy.go new file mode 100644 index 00000000..a3595bb0 --- /dev/null +++ b/api/apps/v1alpha1/vpn/zz_generated.deepcopy.go @@ -0,0 +1,111 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package vpn + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Config) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + if in.Users != nil { + in, out := &in.Users, &out.Users + *out = make(map[string]User, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.ExternalIPs != nil { + in, out := &in.ExternalIPs, &out.ExternalIPs + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. +func (in *ConfigSpec) DeepCopy() *ConfigSpec { + if in == nil { + return nil + } + out := new(ConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resources) DeepCopyInto(out *Resources) { + *out = *in + out.Cpu = in.Cpu.DeepCopy() + out.Memory = in.Memory.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resources. +func (in *Resources) DeepCopy() *Resources { + if in == nil { + return nil + } + out := new(Resources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *User) DeepCopyInto(out *User) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User. +func (in *User) DeepCopy() *User { + if in == nil { + return nil + } + out := new(User) + in.DeepCopyInto(out) + return out +} diff --git a/api/backups/strategy/v1alpha1/groupversion_info.go b/api/backups/strategy/v1alpha1/groupversion_info.go new file mode 100644 index 00000000..6cbfc8c2 --- /dev/null +++ b/api/backups/strategy/v1alpha1/groupversion_info.go @@ -0,0 +1,37 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1alpha1 contains API Schema definitions for the v1alpha1 API group. +// +kubebuilder:object:generate=true +// +groupName=strategy.backups.cozystack.io +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + GroupVersion = schema.GroupVersion{Group: "strategy.backups.cozystack.io", Version: "v1alpha1"} + SchemeBuilder = runtime.NewSchemeBuilder(addGroupVersion) + AddToScheme = SchemeBuilder.AddToScheme +) + +func addGroupVersion(scheme *runtime.Scheme) error { + metav1.AddToGroupVersion(scheme, GroupVersion) + return nil +} diff --git a/api/backups/strategy/v1alpha1/job_types.go b/api/backups/strategy/v1alpha1/job_types.go new file mode 100644 index 00000000..583b478a --- /dev/null +++ b/api/backups/strategy/v1alpha1/job_types.go @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: Apache-2.0 +// Package v1alpha1 defines strategy.backups.cozystack.io API types. +// +// Group: strategy.backups.cozystack.io +// Version: v1alpha1 +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +func init() { + SchemeBuilder.Register(func(s *runtime.Scheme) error { + s.AddKnownTypes(GroupVersion, + &Job{}, + &JobList{}, + ) + return nil + }) +} + +const ( + JobStrategyKind = "Job" +) + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster + +// Job defines a backup strategy using a one-shot Job +type Job struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec JobSpec `json:"spec,omitempty"` + Status JobStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// JobList contains a list of backup Jobs. +type JobList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Job `json:"items"` +} + +// JobSpec specifies the desired behavior of a backup job. +type JobSpec struct { + // Template holds a PodTemplateSpec with the right shape to + // run a single pod to completion and create a tarball with + // a given apps data. Helm-like Go templates are supported. + // The values of the source application are available under + // `.Values`. `.Release.Name` and `.Release.Namespace` are + // also exported. + Template corev1.PodTemplateSpec `json:"template"` +} + +type JobStatus struct { + Conditions []metav1.Condition `json:"conditions,omitempty"` +} diff --git a/api/backups/strategy/v1alpha1/velero_types.go b/api/backups/strategy/v1alpha1/velero_types.go new file mode 100644 index 00000000..2bfeabb7 --- /dev/null +++ b/api/backups/strategy/v1alpha1/velero_types.go @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: Apache-2.0 +// Package v1alpha1 defines strategy.backups.cozystack.io API types. +// +// Group: strategy.backups.cozystack.io +// Version: v1alpha1 +package v1alpha1 + +import ( + velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +func init() { + SchemeBuilder.Register(func(s *runtime.Scheme) error { + s.AddKnownTypes(GroupVersion, + &Velero{}, + &VeleroList{}, + ) + return nil + }) +} + +const ( + VeleroStrategyKind = "Velero" +) + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster + +// Velero defines a backup strategy using Velero as the driver. +type Velero struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VeleroSpec `json:"spec,omitempty"` + Status VeleroStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// VeleroList contains a list of Velero backup strategies. +type VeleroList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Velero `json:"items"` +} + +// VeleroSpec specifies the desired strategy for backing up with Velero. +type VeleroSpec struct { + Template VeleroTemplate `json:"template"` +} + +// VeleroTemplate describes the data a backup.velero.io should have when +// templated from a Velero backup strategy. +type VeleroTemplate struct { + Spec velerov1.BackupSpec `json:"spec"` + // +optional + RestoreSpec *velerov1.RestoreSpec `json:"restoreSpec,omitempty"` +} + +type VeleroStatus struct { + Conditions []metav1.Condition `json:"conditions,omitempty"` +} diff --git a/api/backups/strategy/v1alpha1/zz_generated.deepcopy.go b/api/backups/strategy/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000..7f109878 --- /dev/null +++ b/api/backups/strategy/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,242 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Job) DeepCopyInto(out *Job) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Job. +func (in *Job) DeepCopy() *Job { + if in == nil { + return nil + } + out := new(Job) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Job) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JobList) DeepCopyInto(out *JobList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Job, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobList. +func (in *JobList) DeepCopy() *JobList { + if in == nil { + return nil + } + out := new(JobList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *JobList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JobSpec) DeepCopyInto(out *JobSpec) { + *out = *in + in.Template.DeepCopyInto(&out.Template) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobSpec. +func (in *JobSpec) DeepCopy() *JobSpec { + if in == nil { + return nil + } + out := new(JobSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JobStatus) DeepCopyInto(out *JobStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobStatus. +func (in *JobStatus) DeepCopy() *JobStatus { + if in == nil { + return nil + } + out := new(JobStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Velero) DeepCopyInto(out *Velero) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Velero. +func (in *Velero) DeepCopy() *Velero { + if in == nil { + return nil + } + out := new(Velero) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Velero) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VeleroList) DeepCopyInto(out *VeleroList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Velero, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VeleroList. +func (in *VeleroList) DeepCopy() *VeleroList { + if in == nil { + return nil + } + out := new(VeleroList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VeleroList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VeleroSpec) DeepCopyInto(out *VeleroSpec) { + *out = *in + in.Template.DeepCopyInto(&out.Template) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VeleroSpec. +func (in *VeleroSpec) DeepCopy() *VeleroSpec { + if in == nil { + return nil + } + out := new(VeleroSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VeleroStatus) DeepCopyInto(out *VeleroStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VeleroStatus. +func (in *VeleroStatus) DeepCopy() *VeleroStatus { + if in == nil { + return nil + } + out := new(VeleroStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VeleroTemplate) DeepCopyInto(out *VeleroTemplate) { + *out = *in + in.Spec.DeepCopyInto(&out.Spec) + if in.RestoreSpec != nil { + in, out := &in.RestoreSpec, &out.RestoreSpec + *out = new(velerov1.RestoreSpec) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VeleroTemplate. +func (in *VeleroTemplate) DeepCopy() *VeleroTemplate { + if in == nil { + return nil + } + out := new(VeleroTemplate) + in.DeepCopyInto(out) + return out +} diff --git a/api/backups/v1alpha1/DESIGN.md b/api/backups/v1alpha1/DESIGN.md new file mode 100644 index 00000000..7ba06fae --- /dev/null +++ b/api/backups/v1alpha1/DESIGN.md @@ -0,0 +1,478 @@ +# Cozystack Backups – Core API & Contracts (Draft) + +## 1. Overview + +Cozystack’s backup subsystem provides a generic, composable way to back up and restore managed applications: + +* Every **application instance** can have one or more **backup plans**. +* Backups are stored in configurable **storage locations**. +* The mechanics of *how* a backup/restore is performed are delegated to **strategy drivers**, each implementing driver-specific **BackupStrategy** CRDs. + +The core API: + +* Orchestrates **when** backups happen and **where** they’re stored. +* Tracks **what** backups exist and their status. +* Defines contracts with drivers via shared resources (`BackupJob`, `Backup`, `RestoreJob`). + +It does **not** implement the backup logic itself. + +This document covers only the **core** API and its contracts with drivers, not driver implementations. + +--- + +## 2. Goals and non-goals + +### Goals + +* Provide a **stable core API** for: + + * Declaring **backup plans** per application. + * Configuring **storage targets** (S3, in-cluster bucket, etc.). + * Tracking **backup artifacts**. + * Initiating and tracking **restores**. +* Allow multiple **strategy drivers** to plug in, each supporting specific kinds of applications and strategies. +* Let application/product authors implement backup for their kinds by: + + * Creating **Plan** objects referencing a **driver-specific strategy**. + * Not having to write a backup engine themselves. + +### Non-goals + +* Implement backup logic for any specific application or storage backend. +* Define the internal structure of driver-specific strategy CRDs. +* Handle tenant-facing UI/UX (that’s built on top of these APIs). + +--- + +## 3. Architecture + +High-level components: + +* **Core backups controller(s)** (Cozystack-owned): + + * Group: `backups.cozystack.io` + * Own: + + * `Plan` + * `BackupJob` + * `Backup` + * `RestoreJob` + * Responsibilities: + + * Schedule backups based on `Plan`. + * Create `BackupJob` objects when due. + * Provide stable contracts for drivers to: + + * Perform backups and create `Backup`s. + * Perform restores based on `Backup`s. + +* **Strategy drivers** (pluggable, possibly third-party): + + * Their own API groups, e.g. `jobdriver.backups.cozystack.io`. + * Own **strategy CRDs** (e.g. `JobBackupStrategy`). + * Implement controllers that: + + * Watch `BackupJob` / `RestoreJob`. + * Match runs whose `strategyRef` GVK they support. + * Execute backup/restore logic. + * Create and update `Backup` and run statuses. + +Strategy drivers and core communicate entirely via Kubernetes objects; there are no webhook/HTTP calls between them. + +* **Storage drivers** (pluggable, possibly third-party): + + * **TBD** + +--- + +## 4. Core API resources + +### 4.1 Plan + +**Group/Kind** +`backups.cozystack.io/v1alpha1, Kind=Plan` + +**Purpose** +Describe **when**, **how**, and **where** to back up a specific managed application. + +**Key fields (spec)** + +```go +type PlanSpec struct { + // Application to back up. + // If apiGroup is not specified, it defaults to "apps.cozystack.io". + ApplicationRef corev1.TypedLocalObjectReference `json:"applicationRef"` + + // BackupClassName references a BackupClass that contains strategy and other parameters (e.g. storage reference). + // The BackupClass will be resolved to determine the appropriate strategy and parameters + // based on the ApplicationRef. + BackupClassName string `json:"backupClassName"` + + // When backups should run. + Schedule PlanSchedule `json:"schedule"` +} +``` + +`PlanSchedule` (initially) supports only cron: + +```go +type PlanScheduleType string + +const ( + PlanScheduleTypeEmpty PlanScheduleType = "" + PlanScheduleTypeCron PlanScheduleType = "cron" +) +``` + +```go +type PlanSchedule struct { + // Type is the schedule type. Currently only "cron" is supported. + // Defaults to "cron". + Type PlanScheduleType `json:"type,omitempty"` + + // Cron expression (required for cron type). + Cron string `json:"cron,omitempty"` +} +``` + +**Plan reconciliation contract** + +Core Plan controller: + +1. **Read schedule** from `spec.schedule` and compute the next fire time. +2. When due: + + * Create a `BackupJob` in the same namespace: + + * `spec.planRef.name = plan.Name` + * `spec.applicationRef = plan.spec.applicationRef` (normalized with default apiGroup if not specified) + * `spec.backupClassName = plan.spec.backupClassName` + * Set `ownerReferences` so the `BackupJob` is owned by the `Plan`. + +**Note:** The `BackupJob` controller resolves the `BackupClass` to determine the appropriate strategy and parameters, based on the `ApplicationRef`. The strategy template is processed with a context containing the `Application` object and `Parameters` from the `BackupClass`. + +The Plan controller does **not**: + +* Execute backups itself. +* Modify driver resources or `Backup` objects. +* Touch `BackupJob.spec` after creation. + +--- + +### 4.2 BackupClass + +**Group/Kind** +`backups.cozystack.io/v1alpha1, Kind=BackupClass` + +**Purpose** +Define a class of backup configurations that encapsulate strategy and parameters per application type. `BackupClass` is a cluster-scoped resource that allows admins to configure backup strategies and parameters in a reusable way. + +**Key fields (spec)** + +```go +type BackupClassSpec struct { + // Strategies is a list of backup strategies, each matching a specific application type. + Strategies []BackupClassStrategy `json:"strategies"` +} + +type BackupClassStrategy struct { + // StrategyRef references the driver-specific BackupStrategy (e.g., Velero). + StrategyRef corev1.TypedLocalObjectReference `json:"strategyRef"` + + // Application specifies which application types this strategy applies to. + // If apiGroup is not specified, it defaults to "apps.cozystack.io". + Application ApplicationSelector `json:"application"` + + // Parameters holds strategy-specific parameters, like storage reference. + // Common parameters include: + // - backupStorageLocationName: Name of Velero BackupStorageLocation + // +optional + Parameters map[string]string `json:"parameters,omitempty"` +} + +type ApplicationSelector struct { + // APIGroup is the API group of the application. + // If not specified, defaults to "apps.cozystack.io". + // +optional + APIGroup *string `json:"apiGroup,omitempty"` + + // Kind is the kind of the application (e.g., VirtualMachine, MariaDB). + Kind string `json:"kind"` +} +``` + +**BackupClass resolution** + +* When a `BackupJob` or `Plan` references a `BackupClass` via `backupClassName`, the controller: + 1. Fetches the `BackupClass` by name. + 2. Matches the `ApplicationRef` against strategies in the `BackupClass`: + * Normalizes `ApplicationRef.apiGroup` (defaults to `"apps.cozystack.io"` if not specified). + * Finds a strategy where `ApplicationSelector` matches the `ApplicationRef` (apiGroup and kind). + 3. Returns the matched `StrategyRef` and `Parameters`. +* Strategy templates (e.g., Velero's `backupTemplate.spec`) are processed with a context containing: + * `Application`: The application object being backed up. + * `Parameters`: The parameters from the matched `BackupClassStrategy`. + +**Parameters** + +* Parameters are passed via `Parameters` in the `BackupClass` (e.g., `backupStorageLocationName` for Velero). +* The driver uses these parameters to resolve the actual resources (e.g., Velero's `BackupStorageLocation` CRD). + +--- + +### 4.3 BackupJob + +**Group/Kind** +`backups.cozystack.io/v1alpha1, Kind=BackupJob` + +**Purpose** +Represent a single **execution** of a backup operation, typically created when a `Plan` fires or when a user triggers an ad-hoc backup. + +**Key fields (spec)** + +```go +type BackupJobSpec struct { + // Plan that triggered this run, if any. + PlanRef *corev1.LocalObjectReference `json:"planRef,omitempty"` + + // Application to back up. + // If apiGroup is not specified, it defaults to "apps.cozystack.io". + ApplicationRef corev1.TypedLocalObjectReference `json:"applicationRef"` + + // BackupClassName references a BackupClass that contains strategy and related parameters + // The BackupClass will be resolved to determine the appropriate strategy and parameters + // based on the ApplicationRef. + BackupClassName string `json:"backupClassName"` +} +``` + +**Key fields (status)** + +```go +type BackupJobStatus struct { + Phase BackupJobPhase `json:"phase,omitempty"` + BackupRef *corev1.LocalObjectReference `json:"backupRef,omitempty"` + StartedAt *metav1.Time `json:"startedAt,omitempty"` + CompletedAt *metav1.Time `json:"completedAt,omitempty"` + Message string `json:"message,omitempty"` + Conditions []metav1.Condition `json:"conditions,omitempty"` +} +``` + +`BackupJobPhase` is one of: `Pending`, `Running`, `Succeeded`, `Failed`. + +**BackupJob contract with drivers** + +* Core **creates** `BackupJob` and must treat `spec` as immutable afterwards. +* Each driver controller: + + * Watches `BackupJob`. + * Resolves the `BackupClass` referenced by `spec.backupClassName`. + * Matches the `ApplicationRef` against strategies in the `BackupClass` to find the appropriate strategy. + * Reconciles runs where the resolved strategy's `apiGroup/kind` matches its **strategy type(s)**. +* Driver responsibilities: + + 1. On first reconcile: + + * Set `status.startedAt` if unset. + * Set `status.phase = Running`. + 2. Resolve inputs: + + * Resolve `BackupClass` from `spec.backupClassName`. + * Match `ApplicationRef` against `BackupClass` strategies to get `StrategyRef` and `Parameters`. + * Read `Strategy` (driver-owned CRD) from `StrategyRef`. + * Read `Application` from `ApplicationRef`. + * Extract parameters from `Parameters` (e.g., `backupStorageLocationName` for Velero). + * Process strategy template with context: `Application` object and `Parameters` from `BackupClass`. + 3. Execute backup logic (implementation-specific). + 4. On success: + + * Create a `Backup` resource (see below). + * Set `status.backupRef` to the created `Backup`. + * Set `status.completedAt`. + * Set `status.phase = Succeeded`. + 5. On failure: + + * Set `status.completedAt`. + * Set `status.phase = Failed`. + * Set `status.message` and conditions. + +Drivers must **not** modify `BackupJob.spec` or delete `BackupJob` themselves. + +--- + +### 4.4 Backup + +**Group/Kind** +`backups.cozystack.io/v1alpha1, Kind=Backup` + +**Purpose** +Represent a single **backup artifact** for a given application, decoupled from a particular run. usable as a stable, listable “thing you can restore from”. + +**Key fields (spec)** + +```go +type BackupSpec struct { + ApplicationRef corev1.TypedLocalObjectReference `json:"applicationRef"` + PlanRef *corev1.LocalObjectReference `json:"planRef,omitempty"` + StrategyRef corev1.TypedLocalObjectReference `json:"strategyRef"` + TakenAt metav1.Time `json:"takenAt"` + DriverMetadata map[string]string `json:"driverMetadata,omitempty"` +} +``` + +**Note:** Parameters are not stored directly in `Backup`. Instead, they are resolved from `BackupClass` parameters when the backup was created. The storage location is managed by the driver (e.g., Velero's `BackupStorageLocation`) and referenced via parameters in the `BackupClass`. + +**Key fields (status)** + +```go +type BackupStatus struct { + Phase BackupPhase `json:"phase,omitempty"` // Pending, Ready, Failed, etc. + Artifact *BackupArtifact `json:"artifact,omitempty"` + Conditions []metav1.Condition `json:"conditions,omitempty"` +} +``` + +`BackupArtifact` describes the artifact (URI, size, checksum). + +**Backup contract with drivers** + +* On successful completion of a `BackupJob`, the **driver**: + + * Creates a `Backup` in the same namespace (typically owned by the `BackupJob`). + * Populates `spec` fields with: + + * The application reference. + * The strategy reference (resolved from `BackupClass` during `BackupJob` execution). + * `takenAt`. + * Optional `driverMetadata`. + * Sets `status` with: + + * `phase = Ready` (or equivalent when fully usable). + * `artifact` describing the stored object. +* Core: + + * Treats `Backup` spec as mostly immutable and opaque. + * Uses it to: + + * List backups for a given application/plan. + * Anchor `RestoreJob` operations. + * Implement higher-level policies (retention) if needed. + +**Note:** Parameters are resolved from `BackupClass` when the `BackupJob` is created. The driver uses these parameters to determine where to store backups. The storage location itself is managed by the driver (e.g., Velero's `BackupStorageLocation` CRD) and is not directly referenced in the `Backup` resource. When restoring, the driver resolves the storage location from the original `BackupClass` parameters or from the driver's own metadata. + +--- + +### 4.5 RestoreJob + +**Group/Kind** +`backups.cozystack.io/v1alpha1, Kind=RestoreJob` + +**Purpose** +Represent a single **restore operation** from a `Backup`, either back into the same application or into a new target application. + +**Key fields (spec)** + +```go +type RestoreJobSpec struct { + // Backup to restore from. + BackupRef corev1.LocalObjectReference `json:"backupRef"` + + // Target application; if omitted, drivers SHOULD restore into + // backup.spec.applicationRef. + TargetApplicationRef *corev1.TypedLocalObjectReference `json:"targetApplicationRef,omitempty"` +} +``` + +**Key fields (status)** + +```go +type RestoreJobStatus struct { + Phase RestoreJobPhase `json:"phase,omitempty"` // Pending, Running, Succeeded, Failed + StartedAt *metav1.Time `json:"startedAt,omitempty"` + CompletedAt *metav1.Time `json:"completedAt,omitempty"` + Message string `json:"message,omitempty"` + Conditions []metav1.Condition `json:"conditions,omitempty"` +} +``` + +**RestoreJob contract with drivers** + +* RestoreJob is created either manually or by core. +* Driver controller: + + 1. Watches `RestoreJob`. + 2. On reconcile: + + * Fetches the referenced `Backup`. + * Determines effective: + + * **Strategy**: `backup.spec.strategyRef`. + * **Storage**: Resolved from driver metadata or `BackupClass` parameters (e.g., `backupStorageLocationName` stored in `driverMetadata` or resolved from the original `BackupClass`). + * **Target application**: `spec.targetApplicationRef` or `backup.spec.applicationRef`. + * If effective strategy’s GVK is one of its supported strategy types → driver is responsible. + 3. Behaviour: + + * On first reconcile, set `status.startedAt` and `phase = Running`. + * Resolve `Backup`, storage location (from driver metadata or `BackupClass`), `Strategy`, target application. + * Execute restore logic (implementation-specific). + * On success: + + * Set `status.completedAt`. + * Set `status.phase = Succeeded`. + * On failure: + + * Set `status.completedAt`. + * Set `status.phase = Failed`. + * Set `status.message` and conditions. + +Drivers must not modify `RestoreJob.spec` or delete `RestoreJob`. + +--- + +## 5. Strategy drivers (high-level) + +Strategy drivers are separate controllers that: + +* Define their own **strategy CRDs** (e.g. `JobBackupStrategy`) in their own API groups: + + * e.g. `jobdriver.backups.cozystack.io/v1alpha1, Kind=JobBackupStrategy` +* Implement the **BackupJob contract**: + + * Watch `BackupJob`. + * Filter by `spec.strategyRef.apiGroup/kind`. + * Execute backup logic. + * Create/update `Backup`. +* Implement the **RestoreJob contract**: + + * Watch `RestoreJob`. + * Resolve `Backup`, then effective `strategyRef`. + * Filter by effective strategy GVK. + * Execute restore logic. + +The core backups API **does not** dictate: + +* The fields and structure of driver strategy specs. +* How drivers implement backup/restore internally (Jobs, snapshots, native operator CRDs, etc.). + +Drivers are interchangeable as long as they respect: + +* The `BackupJob` and `RestoreJob` contracts. +* The shapes and semantics of `Backup` objects. + +--- + +## 6. Summary + +The Cozystack backups core API: + +* Uses a single group, `backups.cozystack.io`, for all core CRDs. +* Cleanly separates: + + * **When** (Plan schedule) – core-owned. + * **How & where** (BackupClass) – central configuration unit that encapsulates strategy and parameters (e.g., storage reference) per application type, resolved per BackupJob/Plan. + * **Execution** (BackupJob) – created by Plan when schedule fires, resolves BackupClass to get strategy and parameters, then delegates to driver. + * **What backup artifacts exist** (Backup) – driver-created but cluster-visible. + * **Restore lifecycle** (RestoreJob) – shared contract boundary. +* Allows multiple strategy drivers to implement backup/restore logic without entangling their implementation with the core API. + diff --git a/api/backups/v1alpha1/backup_types.go b/api/backups/v1alpha1/backup_types.go new file mode 100644 index 00000000..e46212f6 --- /dev/null +++ b/api/backups/v1alpha1/backup_types.go @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: Apache-2.0 +// Package v1alpha1 defines backups.cozystack.io API types. +// +// Group: backups.cozystack.io +// Version: v1alpha1 +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +func init() { + SchemeBuilder.Register(func(s *runtime.Scheme) error { + s.AddKnownTypes(GroupVersion, + &Backup{}, + &BackupList{}, + ) + return nil + }) +} + +// BackupPhase represents the lifecycle phase of a Backup. +type BackupPhase string + +const ( + BackupPhaseEmpty BackupPhase = "" + BackupPhasePending BackupPhase = "Pending" + BackupPhaseReady BackupPhase = "Ready" + BackupPhaseFailed BackupPhase = "Failed" +) + +// BackupArtifact describes the stored backup object (tarball, snapshot, etc.). +type BackupArtifact struct { + // URI is a driver-/storage-specific URI pointing to the backup artifact. + // For example: s3://bucket/prefix/file.tar.gz + URI string `json:"uri"` + + // SizeBytes is the size of the artifact in bytes, if known. + // +optional + SizeBytes int64 `json:"sizeBytes,omitempty"` + + // Checksum is the checksum of the artifact, if computed. + // For example: "sha256:". + // +optional + Checksum string `json:"checksum,omitempty"` +} + +// BackupSpec describes an immutable backup artifact produced by a BackupJob. +type BackupSpec struct { + // ApplicationRef refers to the application that was backed up. + ApplicationRef corev1.TypedLocalObjectReference `json:"applicationRef"` + + // PlanRef refers to the Plan that produced this backup, if any. + // For manually triggered backups, this can be omitted. + // +optional + PlanRef *corev1.LocalObjectReference `json:"planRef,omitempty"` + + // StrategyRef refers to the driver-specific BackupStrategy that was used + // to create this backup. This allows the driver to later perform restores. + StrategyRef corev1.TypedLocalObjectReference `json:"strategyRef"` + + // TakenAt is the time at which the backup was taken (as reported by the + // driver). It may differ slightly from metadata.creationTimestamp. + TakenAt metav1.Time `json:"takenAt"` + + // DriverMetadata holds driver-specific, opaque metadata associated with + // this backup (for example snapshot IDs, schema versions, etc.). + // This data is not interpreted by the core backup controllers. + // +optional + DriverMetadata map[string]string `json:"driverMetadata,omitempty"` +} + +// DataVolumeResource describes a dataVolume associated with the backed-up application. +type DataVolumeResource struct { + // DataVolumeName is the name of the dataVolume/PVC (e.g., "vm-disk-ubuntu-source"). + DataVolumeName string `json:"dataVolumeName"` + + // ApplicationName is the cozystack application name for this disk (e.g., "ubuntu-source"). + ApplicationName string `json:"applicationName"` +} + +// BackupStatus represents the observed state of a Backup. +type BackupStatus struct { + // Phase is a simple, high-level summary of the backup's state. + // Typical values are: Pending, Ready, Failed. + // +optional + Phase BackupPhase `json:"phase,omitempty"` + + // Artifact describes the stored backup object, if available. + // +optional + Artifact *BackupArtifact `json:"artifact,omitempty"` + + // UnderlyingResources holds application-specific resource metadata discovered + // during backup (e.g., VM disks, network configuration). The payload is a + // self-typed JSON object carrying an inlined TypeMeta (kind/apiVersion) so + // the consuming controller can dispatch on the application kind. + // +optional + // +kubebuilder:pruning:PreserveUnknownFields + // +kubebuilder:validation:Type=object + UnderlyingResources *runtime.RawExtension `json:"underlyingResources,omitempty"` + + // Conditions represents the latest available observations of a Backup's state. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// The field indexing on applicationRef will be needed later to display per-app backup resources. + +// +kubebuilder:object:root=true +// +kubebuilder:selectablefield:JSONPath=`.spec.applicationRef.apiGroup` +// +kubebuilder:selectablefield:JSONPath=`.spec.applicationRef.kind` +// +kubebuilder:selectablefield:JSONPath=`.spec.applicationRef.name` + +// Backup represents a single backup artifact for a given application. +type Backup struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec BackupSpec `json:"spec,omitempty"` + Status BackupStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// BackupList contains a list of Backups. +type BackupList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Backup `json:"items"` +} diff --git a/api/backups/v1alpha1/backupclass_types.go b/api/backups/v1alpha1/backupclass_types.go new file mode 100644 index 00000000..2b2dc7ff --- /dev/null +++ b/api/backups/v1alpha1/backupclass_types.go @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: Apache-2.0 +// Package v1alpha1 defines backups.cozystack.io API types. +// +// Group: backups.cozystack.io +// Version: v1alpha1 +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +func init() { + SchemeBuilder.Register(func(s *runtime.Scheme) error { + s.AddKnownTypes(GroupVersion, + &BackupClass{}, + &BackupClassList{}, + ) + return nil + }) +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster +// +kubebuilder:subresource:status + +// BackupClass defines a class of backup configurations that can be referenced +// by BackupJob and Plan resources. It encapsulates strategy and storage configuration +// per application type. +type BackupClass struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec BackupClassSpec `json:"spec,omitempty"` + Status BackupClassStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// BackupClassList contains a list of BackupClasses. +type BackupClassList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []BackupClass `json:"items"` +} + +// BackupClassSpec defines the desired state of a BackupClass. +type BackupClassSpec struct { + // Strategies is a list of backup strategies, each matching a specific application type. + Strategies []BackupClassStrategy `json:"strategies"` +} + +// BackupClassStrategy defines a backup strategy for a specific application type. +type BackupClassStrategy struct { + // StrategyRef references the driver-specific BackupStrategy (e.g., Velero). + StrategyRef corev1.TypedLocalObjectReference `json:"strategyRef"` + + // Application specifies which application types this strategy applies to. + Application ApplicationSelector `json:"application"` + + // Parameters holds strategy-specific and storage-specific parameters. + // Common parameters include: + // - backupStorageLocationName: Name of Velero BackupStorageLocation + // +optional + Parameters map[string]string `json:"parameters,omitempty"` +} + +// ApplicationSelector specifies which application types a strategy applies to. +type ApplicationSelector struct { + // APIGroup is the API group of the application. + // If not specified, defaults to "apps.cozystack.io". + // +optional + APIGroup *string `json:"apiGroup,omitempty"` + + // Kind is the kind of the application (e.g., VirtualMachine, MariaDB). + Kind string `json:"kind"` +} + +// BackupClassStatus defines the observed state of a BackupClass. +type BackupClassStatus struct { + // Conditions represents the latest available observations of a BackupClass's state. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` +} diff --git a/api/backups/v1alpha1/backupjob_types.go b/api/backups/v1alpha1/backupjob_types.go new file mode 100644 index 00000000..111b5f1d --- /dev/null +++ b/api/backups/v1alpha1/backupjob_types.go @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: Apache-2.0 +// Package v1alpha1 defines backups.cozystack.io API types. +// +// Group: backups.cozystack.io +// Version: v1alpha1 +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +func init() { + SchemeBuilder.Register(func(s *runtime.Scheme) error { + s.AddKnownTypes(GroupVersion, + &BackupJob{}, + &BackupJobList{}, + ) + return nil + }) +} + +const ( + OwningJobNameLabel = thisGroup + "/owned-by.BackupJobName" + OwningJobNamespaceLabel = thisGroup + "/owned-by.BackupJobNamespace" + + // DefaultApplicationAPIGroup is the default API group for applications + // when not specified in ApplicationRef or ApplicationSelector. + DefaultApplicationAPIGroup = "apps.cozystack.io" +) + +// BackupJobPhase represents the lifecycle phase of a BackupJob. +type BackupJobPhase string + +const ( + BackupJobPhaseEmpty BackupJobPhase = "" + BackupJobPhasePending BackupJobPhase = "Pending" + BackupJobPhaseRunning BackupJobPhase = "Running" + BackupJobPhaseSucceeded BackupJobPhase = "Succeeded" + BackupJobPhaseFailed BackupJobPhase = "Failed" +) + +// BackupJobSpec describes the execution of a single backup operation. +type BackupJobSpec struct { + // PlanRef refers to the Plan that requested this backup run. + // For ad-hoc/manual backups, this can be omitted. + // +optional + PlanRef *corev1.LocalObjectReference `json:"planRef,omitempty"` + + // ApplicationRef holds a reference to the managed application whose state + // is being backed up. + // If apiGroup is not specified, it defaults to "apps.cozystack.io". + ApplicationRef corev1.TypedLocalObjectReference `json:"applicationRef"` + + // BackupClassName references a BackupClass that contains strategy and storage configuration. + // The BackupClass will be resolved to determine the appropriate strategy and storage + // based on the ApplicationRef. + // This field is immutable once the BackupJob is created. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="backupClassName is immutable" + BackupClassName string `json:"backupClassName"` +} + +// BackupJobStatus represents the observed state of a BackupJob. +type BackupJobStatus struct { + // Phase is a high-level summary of the run's state. + // Typical values: Pending, Running, Succeeded, Failed. + // +optional + Phase BackupJobPhase `json:"phase,omitempty"` + + // BackupRef refers to the Backup object created by this run, if any. + // +optional + BackupRef *corev1.LocalObjectReference `json:"backupRef,omitempty"` + + // StartedAt is the time at which the backup run started. + // +optional + StartedAt *metav1.Time `json:"startedAt,omitempty"` + + // CompletedAt is the time at which the backup run completed (successfully + // or otherwise). + // +optional + CompletedAt *metav1.Time `json:"completedAt,omitempty"` + + // Message is a human-readable message indicating details about why the + // backup run is in its current phase, if any. + // +optional + Message string `json:"message,omitempty"` + + // Conditions represents the latest available observations of a BackupJob's state. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// The field indexing on applicationRef will be needed later to display per-app backup resources. + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",priority=0 +// +kubebuilder:selectablefield:JSONPath=`.spec.applicationRef.apiGroup` +// +kubebuilder:selectablefield:JSONPath=`.spec.applicationRef.kind` +// +kubebuilder:selectablefield:JSONPath=`.spec.applicationRef.name` + +// BackupJob represents a single execution of a backup. +// It is typically created by a Plan controller when a schedule fires. +type BackupJob struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec BackupJobSpec `json:"spec,omitempty"` + Status BackupJobStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// BackupJobList contains a list of BackupJobs. +type BackupJobList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []BackupJob `json:"items"` +} + +// NormalizeApplicationRef sets the default apiGroup to DefaultApplicationAPIGroup if it's not specified. +// This function is exported so it can be used by other packages (e.g., controllers, factories). +func NormalizeApplicationRef(ref corev1.TypedLocalObjectReference) corev1.TypedLocalObjectReference { + if ref.APIGroup == nil || *ref.APIGroup == "" { + apiGroup := DefaultApplicationAPIGroup + ref.APIGroup = &apiGroup + } + return ref +} diff --git a/api/backups/v1alpha1/groupversion_info.go b/api/backups/v1alpha1/groupversion_info.go new file mode 100644 index 00000000..87ad6f38 --- /dev/null +++ b/api/backups/v1alpha1/groupversion_info.go @@ -0,0 +1,42 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1alpha1 contains API Schema definitions for the v1alpha1 API group. +// +kubebuilder:object:generate=true +// +groupName=backups.cozystack.io +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +const ( + thisGroup = "backups.cozystack.io" + thisVersion = "v1alpha1" +) + +var ( + GroupVersion = schema.GroupVersion{Group: thisGroup, Version: thisVersion} + SchemeBuilder = runtime.NewSchemeBuilder(addGroupVersion) + AddToScheme = SchemeBuilder.AddToScheme +) + +func addGroupVersion(scheme *runtime.Scheme) error { + metav1.AddToGroupVersion(scheme, GroupVersion) + return nil +} diff --git a/api/backups/v1alpha1/plan_types.go b/api/backups/v1alpha1/plan_types.go new file mode 100644 index 00000000..df807eb5 --- /dev/null +++ b/api/backups/v1alpha1/plan_types.go @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: Apache-2.0 +// Package v1alpha1 defines backups.cozystack.io API types. +// +// Group: backups.cozystack.io +// Version: v1alpha1 +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +func init() { + SchemeBuilder.Register(func(s *runtime.Scheme) error { + s.AddKnownTypes(GroupVersion, + &Plan{}, + &PlanList{}, + ) + return nil + }) +} + +type PlanScheduleType string + +const ( + PlanScheduleTypeEmpty PlanScheduleType = "" + PlanScheduleTypeCron PlanScheduleType = "cron" +) + +// Condtions +const ( + PlanConditionError = "Error" +) + +// The field indexing on applicationRef will be needed later to display per-app backup resources. + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:selectablefield:JSONPath=`.spec.applicationRef.apiGroup` +// +kubebuilder:selectablefield:JSONPath=`.spec.applicationRef.kind` +// +kubebuilder:selectablefield:JSONPath=`.spec.applicationRef.name` + +// Plan describes the schedule, method and storage location for the +// backup of a given target application. +type Plan struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec PlanSpec `json:"spec,omitempty"` + Status PlanStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// PlanList contains a list of backup Plans. +type PlanList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Plan `json:"items"` +} + +// PlanSpec references the storage, the strategy, the application to be +// backed up and specifies the timetable on which the backups will run. +type PlanSpec struct { + // ApplicationRef holds a reference to the managed application, + // whose state and configuration must be backed up. + // If apiGroup is not specified, it defaults to "apps.cozystack.io". + ApplicationRef corev1.TypedLocalObjectReference `json:"applicationRef"` + + // BackupClassName references a BackupClass that contains strategy and storage configuration. + // The BackupClass will be resolved to determine the appropriate strategy and storage + // based on the ApplicationRef. + BackupClassName string `json:"backupClassName"` + + // Schedule specifies when backup copies are created. + Schedule PlanSchedule `json:"schedule"` +} + +// PlanSchedule specifies when backup copies are created. +type PlanSchedule struct { + // Type is the type of schedule specification. Supported values are + // [`cron`]. If omitted, defaults to `cron`. + // +optional + Type PlanScheduleType `json:"type,omitempty"` + + // Cron contains the cron spec for scheduling backups. Must be + // specified if the schedule type is `cron`. Since only `cron` is + // supported, omitting this field is not allowed. + // +optional + Cron string `json:"cron,omitempty"` +} + +type PlanStatus struct { + Conditions []metav1.Condition `json:"conditions,omitempty"` +} diff --git a/api/backups/v1alpha1/restorejob_types.go b/api/backups/v1alpha1/restorejob_types.go new file mode 100644 index 00000000..9817e8c1 --- /dev/null +++ b/api/backups/v1alpha1/restorejob_types.go @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: Apache-2.0 +// Package v1alpha1 defines backups.cozystack.io API types. +// +// Group: backups.cozystack.io +// Version: v1alpha1 +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +func init() { + SchemeBuilder.Register(func(s *runtime.Scheme) error { + s.AddKnownTypes(GroupVersion, + &RestoreJob{}, + &RestoreJobList{}, + ) + return nil + }) +} + +// RestoreJobPhase represents the lifecycle phase of a RestoreJob. +type RestoreJobPhase string + +const ( + RestoreJobPhaseEmpty RestoreJobPhase = "" + RestoreJobPhasePending RestoreJobPhase = "Pending" + RestoreJobPhaseRunning RestoreJobPhase = "Running" + RestoreJobPhaseSucceeded RestoreJobPhase = "Succeeded" + RestoreJobPhaseFailed RestoreJobPhase = "Failed" +) + +// RestoreJobSpec describes the execution of a single restore operation. +type RestoreJobSpec struct { + // BackupRef refers to the Backup that should be restored. + BackupRef corev1.LocalObjectReference `json:"backupRef"` + + // TargetApplicationRef refers to the application into which the backup + // should be restored. If omitted, the driver SHOULD restore into the same + // application as referenced by backup.spec.applicationRef. + // +optional + TargetApplicationRef *corev1.TypedLocalObjectReference `json:"targetApplicationRef,omitempty"` + + // Options is a driver-specific blob of restore options, typed based on + // targetApplicationRef and the current controller implementation. + // +optional + // +kubebuilder:pruning:PreserveUnknownFields + Options *runtime.RawExtension `json:"options,omitempty"` +} + +// RestoreJobStatus represents the observed state of a RestoreJob. +type RestoreJobStatus struct { + // Phase is a high-level summary of the run's state. + // Typical values: Pending, Running, Succeeded, Failed. + // +optional + Phase RestoreJobPhase `json:"phase,omitempty"` + + // StartedAt is the time at which the restore run started. + // +optional + StartedAt *metav1.Time `json:"startedAt,omitempty"` + + // CompletedAt is the time at which the restore run completed (successfully + // or otherwise). + // +optional + CompletedAt *metav1.Time `json:"completedAt,omitempty"` + + // Message is a human-readable message indicating details about why the + // restore run is in its current phase, if any. + // +optional + Message string `json:"message,omitempty"` + + // Conditions represents the latest available observations of a RestoreJob's state. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase",priority=0 + +// RestoreJob represents a single execution of a restore from a Backup. +type RestoreJob struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec RestoreJobSpec `json:"spec,omitempty"` + Status RestoreJobStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// RestoreJobList contains a list of RestoreJobs. +type RestoreJobList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []RestoreJob `json:"items"` +} diff --git a/api/backups/v1alpha1/zz_generated.deepcopy.go b/api/backups/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000..61b8f839 --- /dev/null +++ b/api/backups/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,668 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationSelector) DeepCopyInto(out *ApplicationSelector) { + *out = *in + if in.APIGroup != nil { + in, out := &in.APIGroup, &out.APIGroup + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationSelector. +func (in *ApplicationSelector) DeepCopy() *ApplicationSelector { + if in == nil { + return nil + } + out := new(ApplicationSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Backup) DeepCopyInto(out *Backup) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Backup. +func (in *Backup) DeepCopy() *Backup { + if in == nil { + return nil + } + out := new(Backup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Backup) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupArtifact) DeepCopyInto(out *BackupArtifact) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupArtifact. +func (in *BackupArtifact) DeepCopy() *BackupArtifact { + if in == nil { + return nil + } + out := new(BackupArtifact) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupClass) DeepCopyInto(out *BackupClass) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupClass. +func (in *BackupClass) DeepCopy() *BackupClass { + if in == nil { + return nil + } + out := new(BackupClass) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BackupClass) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupClassList) DeepCopyInto(out *BackupClassList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]BackupClass, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupClassList. +func (in *BackupClassList) DeepCopy() *BackupClassList { + if in == nil { + return nil + } + out := new(BackupClassList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BackupClassList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupClassSpec) DeepCopyInto(out *BackupClassSpec) { + *out = *in + if in.Strategies != nil { + in, out := &in.Strategies, &out.Strategies + *out = make([]BackupClassStrategy, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupClassSpec. +func (in *BackupClassSpec) DeepCopy() *BackupClassSpec { + if in == nil { + return nil + } + out := new(BackupClassSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupClassStatus) DeepCopyInto(out *BackupClassStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupClassStatus. +func (in *BackupClassStatus) DeepCopy() *BackupClassStatus { + if in == nil { + return nil + } + out := new(BackupClassStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupClassStrategy) DeepCopyInto(out *BackupClassStrategy) { + *out = *in + in.StrategyRef.DeepCopyInto(&out.StrategyRef) + in.Application.DeepCopyInto(&out.Application) + if in.Parameters != nil { + in, out := &in.Parameters, &out.Parameters + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupClassStrategy. +func (in *BackupClassStrategy) DeepCopy() *BackupClassStrategy { + if in == nil { + return nil + } + out := new(BackupClassStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupJob) DeepCopyInto(out *BackupJob) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupJob. +func (in *BackupJob) DeepCopy() *BackupJob { + if in == nil { + return nil + } + out := new(BackupJob) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BackupJob) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupJobList) DeepCopyInto(out *BackupJobList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]BackupJob, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupJobList. +func (in *BackupJobList) DeepCopy() *BackupJobList { + if in == nil { + return nil + } + out := new(BackupJobList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BackupJobList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupJobSpec) DeepCopyInto(out *BackupJobSpec) { + *out = *in + if in.PlanRef != nil { + in, out := &in.PlanRef, &out.PlanRef + *out = new(v1.LocalObjectReference) + **out = **in + } + in.ApplicationRef.DeepCopyInto(&out.ApplicationRef) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupJobSpec. +func (in *BackupJobSpec) DeepCopy() *BackupJobSpec { + if in == nil { + return nil + } + out := new(BackupJobSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupJobStatus) DeepCopyInto(out *BackupJobStatus) { + *out = *in + if in.BackupRef != nil { + in, out := &in.BackupRef, &out.BackupRef + *out = new(v1.LocalObjectReference) + **out = **in + } + if in.StartedAt != nil { + in, out := &in.StartedAt, &out.StartedAt + *out = (*in).DeepCopy() + } + if in.CompletedAt != nil { + in, out := &in.CompletedAt, &out.CompletedAt + *out = (*in).DeepCopy() + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupJobStatus. +func (in *BackupJobStatus) DeepCopy() *BackupJobStatus { + if in == nil { + return nil + } + out := new(BackupJobStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupList) DeepCopyInto(out *BackupList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Backup, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupList. +func (in *BackupList) DeepCopy() *BackupList { + if in == nil { + return nil + } + out := new(BackupList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BackupList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupSpec) DeepCopyInto(out *BackupSpec) { + *out = *in + in.ApplicationRef.DeepCopyInto(&out.ApplicationRef) + if in.PlanRef != nil { + in, out := &in.PlanRef, &out.PlanRef + *out = new(v1.LocalObjectReference) + **out = **in + } + in.StrategyRef.DeepCopyInto(&out.StrategyRef) + in.TakenAt.DeepCopyInto(&out.TakenAt) + if in.DriverMetadata != nil { + in, out := &in.DriverMetadata, &out.DriverMetadata + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupSpec. +func (in *BackupSpec) DeepCopy() *BackupSpec { + if in == nil { + return nil + } + out := new(BackupSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BackupStatus) DeepCopyInto(out *BackupStatus) { + *out = *in + if in.Artifact != nil { + in, out := &in.Artifact, &out.Artifact + *out = new(BackupArtifact) + **out = **in + } + if in.UnderlyingResources != nil { + in, out := &in.UnderlyingResources, &out.UnderlyingResources + *out = new(runtime.RawExtension) + (*in).DeepCopyInto(*out) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupStatus. +func (in *BackupStatus) DeepCopy() *BackupStatus { + if in == nil { + return nil + } + out := new(BackupStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DataVolumeResource) DeepCopyInto(out *DataVolumeResource) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataVolumeResource. +func (in *DataVolumeResource) DeepCopy() *DataVolumeResource { + if in == nil { + return nil + } + out := new(DataVolumeResource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plan) DeepCopyInto(out *Plan) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plan. +func (in *Plan) DeepCopy() *Plan { + if in == nil { + return nil + } + out := new(Plan) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Plan) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PlanList) DeepCopyInto(out *PlanList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Plan, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlanList. +func (in *PlanList) DeepCopy() *PlanList { + if in == nil { + return nil + } + out := new(PlanList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PlanList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PlanSchedule) DeepCopyInto(out *PlanSchedule) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlanSchedule. +func (in *PlanSchedule) DeepCopy() *PlanSchedule { + if in == nil { + return nil + } + out := new(PlanSchedule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PlanSpec) DeepCopyInto(out *PlanSpec) { + *out = *in + in.ApplicationRef.DeepCopyInto(&out.ApplicationRef) + out.Schedule = in.Schedule +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlanSpec. +func (in *PlanSpec) DeepCopy() *PlanSpec { + if in == nil { + return nil + } + out := new(PlanSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PlanStatus) DeepCopyInto(out *PlanStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlanStatus. +func (in *PlanStatus) DeepCopy() *PlanStatus { + if in == nil { + return nil + } + out := new(PlanStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RestoreJob) DeepCopyInto(out *RestoreJob) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RestoreJob. +func (in *RestoreJob) DeepCopy() *RestoreJob { + if in == nil { + return nil + } + out := new(RestoreJob) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RestoreJob) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RestoreJobList) DeepCopyInto(out *RestoreJobList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]RestoreJob, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RestoreJobList. +func (in *RestoreJobList) DeepCopy() *RestoreJobList { + if in == nil { + return nil + } + out := new(RestoreJobList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RestoreJobList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RestoreJobSpec) DeepCopyInto(out *RestoreJobSpec) { + *out = *in + out.BackupRef = in.BackupRef + if in.TargetApplicationRef != nil { + in, out := &in.TargetApplicationRef, &out.TargetApplicationRef + *out = new(v1.TypedLocalObjectReference) + (*in).DeepCopyInto(*out) + } + if in.Options != nil { + in, out := &in.Options, &out.Options + *out = new(runtime.RawExtension) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RestoreJobSpec. +func (in *RestoreJobSpec) DeepCopy() *RestoreJobSpec { + if in == nil { + return nil + } + out := new(RestoreJobSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RestoreJobStatus) DeepCopyInto(out *RestoreJobStatus) { + *out = *in + if in.StartedAt != nil { + in, out := &in.StartedAt, &out.StartedAt + *out = (*in).DeepCopy() + } + if in.CompletedAt != nil { + in, out := &in.CompletedAt, &out.CompletedAt + *out = (*in).DeepCopy() + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RestoreJobStatus. +func (in *RestoreJobStatus) DeepCopy() *RestoreJobStatus { + if in == nil { + return nil + } + out := new(RestoreJobStatus) + in.DeepCopyInto(out) + return out +} diff --git a/api/dashboard/v1alpha1/dashboard_resources.go b/api/dashboard/v1alpha1/dashboard_resources.go new file mode 100644 index 00000000..afac0b05 --- /dev/null +++ b/api/dashboard/v1alpha1/dashboard_resources.go @@ -0,0 +1,277 @@ +// SPDX-License-Identifier: Apache-2.0 +// Package v1alpha1 defines front.in-cloud.io API types. +// +// Group: dashboard.cozystack.io +// Version: v1alpha1 +package v1alpha1 + +import ( + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ----------------------------------------------------------------------------- +// Shared shapes +// ----------------------------------------------------------------------------- + +// CommonStatus is a generic Status block with Kubernetes conditions. +type CommonStatus struct { + // ObservedGeneration reflects the most recent generation observed by the controller. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // Conditions represent the latest available observations of an object's state. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// ArbitrarySpec holds schemaless user data and preserves unknown fields. +// We map the entire .spec to a single JSON payload to mirror the CRDs you provided. +// NOTE: Using apiextensionsv1.JSON avoids losing arbitrary structure during round-trips. +type ArbitrarySpec struct { + // +kubebuilder:validation:XPreserveUnknownFields + // +kubebuilder:pruning:PreserveUnknownFields + v1.JSON `json:",inline"` +} + +// ----------------------------------------------------------------------------- +// Sidebar +// ----------------------------------------------------------------------------- + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=sidebars,scope=Cluster +// +kubebuilder:subresource:status +type Sidebar struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ArbitrarySpec `json:"spec"` + Status CommonStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +type SidebarList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Sidebar `json:"items"` +} + +// ----------------------------------------------------------------------------- +// CustomFormsPrefill (shortName: cfp) +// ----------------------------------------------------------------------------- + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=customformsprefills,scope=Cluster,shortName=cfp +// +kubebuilder:subresource:status +type CustomFormsPrefill struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ArbitrarySpec `json:"spec"` + Status CommonStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +type CustomFormsPrefillList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CustomFormsPrefill `json:"items"` +} + +// ----------------------------------------------------------------------------- +// BreadcrumbInside +// ----------------------------------------------------------------------------- + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=breadcrumbsinside,scope=Cluster +// +kubebuilder:subresource:status +type BreadcrumbInside struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ArbitrarySpec `json:"spec"` + Status CommonStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +type BreadcrumbInsideList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []BreadcrumbInside `json:"items"` +} + +// ----------------------------------------------------------------------------- +// CustomFormsOverride (shortName: cfo) +// ----------------------------------------------------------------------------- + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=customformsoverrides,scope=Cluster,shortName=cfo +// +kubebuilder:subresource:status +type CustomFormsOverride struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ArbitrarySpec `json:"spec"` + Status CommonStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +type CustomFormsOverrideList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CustomFormsOverride `json:"items"` +} + +// ----------------------------------------------------------------------------- +// TableUriMapping +// ----------------------------------------------------------------------------- + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=tableurimappings,scope=Cluster +// +kubebuilder:subresource:status +type TableUriMapping struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ArbitrarySpec `json:"spec"` + Status CommonStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +type TableUriMappingList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []TableUriMapping `json:"items"` +} + +// ----------------------------------------------------------------------------- +// Breadcrumb +// ----------------------------------------------------------------------------- + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=breadcrumbs,scope=Cluster +// +kubebuilder:subresource:status +type Breadcrumb struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ArbitrarySpec `json:"spec"` + Status CommonStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +type BreadcrumbList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Breadcrumb `json:"items"` +} + +// ----------------------------------------------------------------------------- +// MarketplacePanel +// ----------------------------------------------------------------------------- + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=marketplacepanels,scope=Cluster +// +kubebuilder:subresource:status +type MarketplacePanel struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ArbitrarySpec `json:"spec"` + Status CommonStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +type MarketplacePanelList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []MarketplacePanel `json:"items"` +} + +// ----------------------------------------------------------------------------- +// Navigation +// ----------------------------------------------------------------------------- + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=navigations,scope=Cluster +// +kubebuilder:subresource:status +type Navigation struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ArbitrarySpec `json:"spec"` + Status CommonStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +type NavigationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Navigation `json:"items"` +} + +// ----------------------------------------------------------------------------- +// CustomColumnsOverride +// ----------------------------------------------------------------------------- + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=customcolumnsoverrides,scope=Cluster +// +kubebuilder:subresource:status +type CustomColumnsOverride struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ArbitrarySpec `json:"spec"` + Status CommonStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +type CustomColumnsOverrideList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CustomColumnsOverride `json:"items"` +} + +// ----------------------------------------------------------------------------- +// Factory +// ----------------------------------------------------------------------------- + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=factories,scope=Cluster +// +kubebuilder:subresource:status +type Factory struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ArbitrarySpec `json:"spec"` + Status CommonStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +type FactoryList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Factory `json:"items"` +} + +// ----------------------------------------------------------------------------- +// CustomFormsOverrideMapping +// ----------------------------------------------------------------------------- + +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=cfomappings,scope=Cluster +// +kubebuilder:subresource:status +type CFOMapping struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ArbitrarySpec `json:"spec"` + Status CommonStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true +type CFOMappingList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CFOMapping `json:"items"` +} diff --git a/api/dashboard/v1alpha1/groupversion_info.go b/api/dashboard/v1alpha1/groupversion_info.go new file mode 100644 index 00000000..659401a7 --- /dev/null +++ b/api/dashboard/v1alpha1/groupversion_info.go @@ -0,0 +1,78 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1alpha1 contains API Schema definitions for the v1alpha1 API group. +// +kubebuilder:object:generate=true +// +groupName=dashboard.cozystack.io +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + // GroupVersion is group version used to register these objects. + GroupVersion = schema.GroupVersion{Group: "dashboard.cozystack.io", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) + +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes( + GroupVersion, + + &Sidebar{}, + &SidebarList{}, + + &CustomFormsPrefill{}, + &CustomFormsPrefillList{}, + + &BreadcrumbInside{}, + &BreadcrumbInsideList{}, + + &CustomFormsOverride{}, + &CustomFormsOverrideList{}, + + &TableUriMapping{}, + &TableUriMappingList{}, + + &Breadcrumb{}, + &BreadcrumbList{}, + + &MarketplacePanel{}, + &MarketplacePanelList{}, + + &Navigation{}, + &NavigationList{}, + + &CustomColumnsOverride{}, + &CustomColumnsOverrideList{}, + + &Factory{}, + &FactoryList{}, + + &CFOMapping{}, + &CFOMappingList{}, + ) + metav1.AddToGroupVersion(scheme, GroupVersion) + return nil +} diff --git a/api/dashboard/v1alpha1/zz_generated.deepcopy.go b/api/dashboard/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000..25d97a79 --- /dev/null +++ b/api/dashboard/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,713 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ArbitrarySpec) DeepCopyInto(out *ArbitrarySpec) { + *out = *in + in.JSON.DeepCopyInto(&out.JSON) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArbitrarySpec. +func (in *ArbitrarySpec) DeepCopy() *ArbitrarySpec { + if in == nil { + return nil + } + out := new(ArbitrarySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Breadcrumb) DeepCopyInto(out *Breadcrumb) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Breadcrumb. +func (in *Breadcrumb) DeepCopy() *Breadcrumb { + if in == nil { + return nil + } + out := new(Breadcrumb) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Breadcrumb) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BreadcrumbInside) DeepCopyInto(out *BreadcrumbInside) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BreadcrumbInside. +func (in *BreadcrumbInside) DeepCopy() *BreadcrumbInside { + if in == nil { + return nil + } + out := new(BreadcrumbInside) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BreadcrumbInside) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BreadcrumbInsideList) DeepCopyInto(out *BreadcrumbInsideList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]BreadcrumbInside, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BreadcrumbInsideList. +func (in *BreadcrumbInsideList) DeepCopy() *BreadcrumbInsideList { + if in == nil { + return nil + } + out := new(BreadcrumbInsideList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BreadcrumbInsideList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BreadcrumbList) DeepCopyInto(out *BreadcrumbList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Breadcrumb, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BreadcrumbList. +func (in *BreadcrumbList) DeepCopy() *BreadcrumbList { + if in == nil { + return nil + } + out := new(BreadcrumbList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BreadcrumbList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CFOMapping) DeepCopyInto(out *CFOMapping) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CFOMapping. +func (in *CFOMapping) DeepCopy() *CFOMapping { + if in == nil { + return nil + } + out := new(CFOMapping) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CFOMapping) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CFOMappingList) DeepCopyInto(out *CFOMappingList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CFOMapping, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CFOMappingList. +func (in *CFOMappingList) DeepCopy() *CFOMappingList { + if in == nil { + return nil + } + out := new(CFOMappingList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CFOMappingList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommonStatus) DeepCopyInto(out *CommonStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonStatus. +func (in *CommonStatus) DeepCopy() *CommonStatus { + if in == nil { + return nil + } + out := new(CommonStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomColumnsOverride) DeepCopyInto(out *CustomColumnsOverride) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomColumnsOverride. +func (in *CustomColumnsOverride) DeepCopy() *CustomColumnsOverride { + if in == nil { + return nil + } + out := new(CustomColumnsOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CustomColumnsOverride) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomColumnsOverrideList) DeepCopyInto(out *CustomColumnsOverrideList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CustomColumnsOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomColumnsOverrideList. +func (in *CustomColumnsOverrideList) DeepCopy() *CustomColumnsOverrideList { + if in == nil { + return nil + } + out := new(CustomColumnsOverrideList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CustomColumnsOverrideList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomFormsOverride) DeepCopyInto(out *CustomFormsOverride) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomFormsOverride. +func (in *CustomFormsOverride) DeepCopy() *CustomFormsOverride { + if in == nil { + return nil + } + out := new(CustomFormsOverride) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CustomFormsOverride) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomFormsOverrideList) DeepCopyInto(out *CustomFormsOverrideList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CustomFormsOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomFormsOverrideList. +func (in *CustomFormsOverrideList) DeepCopy() *CustomFormsOverrideList { + if in == nil { + return nil + } + out := new(CustomFormsOverrideList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CustomFormsOverrideList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomFormsPrefill) DeepCopyInto(out *CustomFormsPrefill) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomFormsPrefill. +func (in *CustomFormsPrefill) DeepCopy() *CustomFormsPrefill { + if in == nil { + return nil + } + out := new(CustomFormsPrefill) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CustomFormsPrefill) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomFormsPrefillList) DeepCopyInto(out *CustomFormsPrefillList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CustomFormsPrefill, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomFormsPrefillList. +func (in *CustomFormsPrefillList) DeepCopy() *CustomFormsPrefillList { + if in == nil { + return nil + } + out := new(CustomFormsPrefillList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CustomFormsPrefillList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Factory) DeepCopyInto(out *Factory) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Factory. +func (in *Factory) DeepCopy() *Factory { + if in == nil { + return nil + } + out := new(Factory) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Factory) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FactoryList) DeepCopyInto(out *FactoryList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Factory, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FactoryList. +func (in *FactoryList) DeepCopy() *FactoryList { + if in == nil { + return nil + } + out := new(FactoryList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FactoryList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MarketplacePanel) DeepCopyInto(out *MarketplacePanel) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MarketplacePanel. +func (in *MarketplacePanel) DeepCopy() *MarketplacePanel { + if in == nil { + return nil + } + out := new(MarketplacePanel) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MarketplacePanel) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MarketplacePanelList) DeepCopyInto(out *MarketplacePanelList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]MarketplacePanel, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MarketplacePanelList. +func (in *MarketplacePanelList) DeepCopy() *MarketplacePanelList { + if in == nil { + return nil + } + out := new(MarketplacePanelList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *MarketplacePanelList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Navigation) DeepCopyInto(out *Navigation) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Navigation. +func (in *Navigation) DeepCopy() *Navigation { + if in == nil { + return nil + } + out := new(Navigation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Navigation) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NavigationList) DeepCopyInto(out *NavigationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Navigation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NavigationList. +func (in *NavigationList) DeepCopy() *NavigationList { + if in == nil { + return nil + } + out := new(NavigationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NavigationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Sidebar) DeepCopyInto(out *Sidebar) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Sidebar. +func (in *Sidebar) DeepCopy() *Sidebar { + if in == nil { + return nil + } + out := new(Sidebar) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Sidebar) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SidebarList) DeepCopyInto(out *SidebarList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Sidebar, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SidebarList. +func (in *SidebarList) DeepCopy() *SidebarList { + if in == nil { + return nil + } + out := new(SidebarList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SidebarList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TableUriMapping) DeepCopyInto(out *TableUriMapping) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TableUriMapping. +func (in *TableUriMapping) DeepCopy() *TableUriMapping { + if in == nil { + return nil + } + out := new(TableUriMapping) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TableUriMapping) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TableUriMappingList) DeepCopyInto(out *TableUriMappingList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TableUriMapping, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TableUriMappingList. +func (in *TableUriMappingList) DeepCopy() *TableUriMappingList { + if in == nil { + return nil + } + out := new(TableUriMappingList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TableUriMappingList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/api/v1alpha1/applicationdefinitions_types.go b/api/v1alpha1/applicationdefinitions_types.go new file mode 100644 index 00000000..4a4cd226 --- /dev/null +++ b/api/v1alpha1/applicationdefinitions_types.go @@ -0,0 +1,177 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + helmv2 "github.com/fluxcd/helm-controller/api/v2" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster + +// ApplicationDefinition is the Schema for the applicationdefinitions API +type ApplicationDefinition struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ApplicationDefinitionSpec `json:"spec,omitempty"` +} + +// +kubebuilder:object:root=true + +// ApplicationDefinitionList contains a list of ApplicationDefinitions +type ApplicationDefinitionList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ApplicationDefinition `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ApplicationDefinition{}, &ApplicationDefinitionList{}) +} + +type ApplicationDefinitionSpec struct { + // Application configuration + Application ApplicationDefinitionApplication `json:"application"` + // Release configuration + Release ApplicationDefinitionRelease `json:"release"` + + // Secret selectors + Secrets ApplicationDefinitionResources `json:"secrets,omitempty"` + // Service selectors + Services ApplicationDefinitionResources `json:"services,omitempty"` + // Ingress selectors + Ingresses ApplicationDefinitionResources `json:"ingresses,omitempty"` + + // Dashboard configuration for this resource + Dashboard *ApplicationDefinitionDashboard `json:"dashboard,omitempty"` +} + +type ApplicationDefinitionApplication struct { + // Kind of the application, used for UI and API + Kind string `json:"kind"` + // OpenAPI schema for the application, used for API validation + OpenAPISchema string `json:"openAPISchema"` + // Plural name of the application, used for UI and API + Plural string `json:"plural"` + // Singular name of the application, used for UI and API + Singular string `json:"singular"` +} + +type ApplicationDefinitionRelease struct { + // Reference to the chart source + ChartRef *helmv2.CrossNamespaceSourceReference `json:"chartRef"` + // Labels for the release + Labels map[string]string `json:"labels,omitempty"` + // Prefix for the release name + Prefix string `json:"prefix"` +} + +// ApplicationDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support. +// A resource matches this selector only if it satisfies ALL criteria: +// - Label selector conditions (matchExpressions and matchLabels) +// - AND has a name that matches one of the names in resourceNames (if specified) +// +// The resourceNames field supports Go templates with the following variables available: +// - {{ .name }}: The name of the managing application (from apps.cozystack.io/application.name) +// - {{ .kind }}: The lowercased kind of the managing application (from apps.cozystack.io/application.kind) +// - {{ .namespace }}: The namespace of the resource being processed +// +// Example YAML: +// +// secrets: +// include: +// - matchExpressions: +// - key: badlabel +// operator: DoesNotExist +// matchLabels: +// goodlabel: goodvalue +// resourceNames: +// - "{{ .name }}-secret" +// - "{{ .kind }}-{{ .name }}-tls" +// - "specificname" +type ApplicationDefinitionResourceSelector struct { + metav1.LabelSelector `json:",inline"` + // ResourceNames is a list of resource names to match + // If specified, the resource must have one of these exact names to match the selector + // +optional + ResourceNames []string `json:"resourceNames,omitempty"` +} + +type ApplicationDefinitionResources struct { + // Exclude contains an array of resource selectors that target resources. + // If a resource matches the selector in any of the elements in the array, it is + // hidden from the user, regardless of the matches in the include array. + Exclude []*ApplicationDefinitionResourceSelector `json:"exclude,omitempty"` + // Include contains an array of resource selectors that target resources. + // If a resource matches the selector in any of the elements in the array, and + // matches none of the selectors in the exclude array that resource is marked + // as a tenant resource and is visible to users. + Include []*ApplicationDefinitionResourceSelector `json:"include,omitempty"` +} + +// ---- Dashboard types ---- + +// DashboardTab enumerates allowed UI tabs. +// +kubebuilder:validation:Enum=workloads;ingresses;services;secrets;yaml +type DashboardTab string + +const ( + DashboardTabWorkloads DashboardTab = "workloads" + DashboardTabIngresses DashboardTab = "ingresses" + DashboardTabServices DashboardTab = "services" + DashboardTabSecrets DashboardTab = "secrets" + DashboardTabYAML DashboardTab = "yaml" +) + +// ApplicationDefinitionDashboard describes how this resource appears in the UI. +type ApplicationDefinitionDashboard struct { + // Human-readable name shown in the UI (e.g., "Bucket") + Singular string `json:"singular"` + // Plural human-readable name (e.g., "Buckets") + Plural string `json:"plural"` + // Hard-coded name used in the UI (e.g., "bucket") + // +optional + Name string `json:"name,omitempty"` + // Whether this resource is singular (not a collection) in the UI + // +optional + SingularResource bool `json:"singularResource,omitempty"` + // Order weight for sorting resources in the UI (lower first) + // +optional + Weight int `json:"weight,omitempty"` + // Short description shown in catalogs or headers (e.g., "S3 compatible storage") + // +optional + Description string `json:"description,omitempty"` + // Icon encoded as a string (e.g., inline SVG, base64, or data URI) + // +optional + Icon string `json:"icon,omitempty"` + // Category used to group resources in the UI (e.g., "Storage", "Networking") + Category string `json:"category"` + // Free-form tags for search and filtering + // +optional + Tags []string `json:"tags,omitempty"` + // Which tabs to show for this resource + // +optional + Tabs []DashboardTab `json:"tabs,omitempty"` + // Order of keys in the YAML view + // +optional + KeysOrder [][]string `json:"keysOrder,omitempty"` + // Whether this resource is a module (tenant module) + // +optional + Module bool `json:"module,omitempty"` +} diff --git a/api/v1alpha1/package_types.go b/api/v1alpha1/package_types.go new file mode 100644 index 00000000..288d456d --- /dev/null +++ b/api/v1alpha1/package_types.go @@ -0,0 +1,100 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster,shortName={pkg,pkgs} +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Variant",type="string",JSONPath=".spec.variant",description="Selected variant" +// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status",description="Ready status" +// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].message",description="Ready message" + +// Package is the Schema for the packages API +type Package struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec PackageSpec `json:"spec,omitempty"` + Status PackageStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// PackageList contains a list of Packages +type PackageList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Package `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Package{}, &PackageList{}) +} + +// PackageSpec defines the desired state of Package +type PackageSpec struct { + // Variant is the name of the variant to use from the PackageSource + // If not specified, defaults to "default" + // +optional + Variant string `json:"variant,omitempty"` + + // IgnoreDependencies is a list of package source dependencies to ignore + // Dependencies listed here will not be installed even if they are specified in the PackageSource + // +optional + IgnoreDependencies []string `json:"ignoreDependencies,omitempty"` + + // Components is a map of release name to component overrides + // Allows overriding values and enabling/disabling specific components from the PackageSource + // +optional + Components map[string]PackageComponent `json:"components,omitempty"` +} + +// PackageComponent defines overrides for a specific component +type PackageComponent struct { + // Enabled indicates whether this component should be installed + // If false, the component will be disabled even if it's defined in the PackageSource + // +optional + Enabled *bool `json:"enabled,omitempty"` + + // Values contains Helm chart values as a JSON object + // These values will be merged with the default values from the PackageSource + // +optional + Values *apiextensionsv1.JSON `json:"values,omitempty"` +} + +// PackageStatus defines the observed state of Package +type PackageStatus struct { + // Conditions represents the latest available observations of a Package's state + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // Dependencies tracks the readiness status of each dependency + // Key is the dependency package name, value indicates if the dependency is ready + // +optional + Dependencies map[string]DependencyStatus `json:"dependencies,omitempty"` +} + +// DependencyStatus represents the readiness status of a dependency +type DependencyStatus struct { + // Ready indicates whether the dependency is ready + Ready bool `json:"ready"` +} diff --git a/api/v1alpha1/packagesource_types.go b/api/v1alpha1/packagesource_types.go new file mode 100644 index 00000000..75bf217b --- /dev/null +++ b/api/v1alpha1/packagesource_types.go @@ -0,0 +1,181 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster,shortName={pks} +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Variants",type="string",JSONPath=".status.variants",description="Package variants (comma-separated)" +// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status",description="Ready status" +// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].message",description="Ready message" + +// PackageSource is the Schema for the packagesources API +type PackageSource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec PackageSourceSpec `json:"spec,omitempty"` + Status PackageSourceStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// PackageSourceList contains a list of PackageSources +type PackageSourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []PackageSource `json:"items"` +} + +func init() { + SchemeBuilder.Register(&PackageSource{}, &PackageSourceList{}) +} + +// PackageSourceSpec defines the desired state of PackageSource +type PackageSourceSpec struct { + // SourceRef is the source reference for the package source charts + // +optional + SourceRef *PackageSourceRef `json:"sourceRef,omitempty"` + + // Variants is a list of package source variants + // Each variant defines components, applications, dependencies, and libraries for a specific configuration + // +optional + Variants []Variant `json:"variants,omitempty"` +} + +// Variant defines a single variant configuration +type Variant struct { + // Name is the unique identifier for this variant + // +required + Name string `json:"name"` + + // DependsOn is a list of package source dependencies + // For example: "cozystack.networking" + // +optional + DependsOn []string `json:"dependsOn,omitempty"` + + // Libraries is a list of Helm library charts used by components in this variant + // +optional + Libraries []Library `json:"libraries,omitempty"` + + // Components is a list of Helm releases to be installed as part of this variant + // +optional + Components []Component `json:"components,omitempty"` +} + +// Library defines a Helm library chart +type Library struct { + // Name is the optional name for library placed in charts + // +optional + Name string `json:"name,omitempty"` + + // Path is the path to the library chart directory + // +required + Path string `json:"path"` +} + +// PackageSourceRef defines the source reference for package source charts +type PackageSourceRef struct { + // Kind of the source reference + // +kubebuilder:validation:Enum=GitRepository;OCIRepository + // +required + Kind string `json:"kind"` + + // Name of the source reference + // +required + Name string `json:"name"` + + // Namespace of the source reference + // +required + Namespace string `json:"namespace"` + + // Path is the base path where packages are located in the source. + // For GitRepository, defaults to "packages" if not specified. + // For OCIRepository, defaults to empty string (root) if not specified. + // +optional + Path string `json:"path,omitempty"` +} + +// ComponentInstall defines installation parameters for a component +type ComponentInstall struct { + // ReleaseName is the name of the HelmRelease resource that will be created + // If not specified, defaults to the component Name field + // +optional + ReleaseName string `json:"releaseName,omitempty"` + + // Namespace is the Kubernetes namespace where the release will be installed + // +optional + Namespace string `json:"namespace,omitempty"` + + // Privileged indicates whether this release requires privileged access + // +optional + Privileged bool `json:"privileged,omitempty"` + + // DependsOn is a list of component names that must be installed before this component + // +optional + DependsOn []string `json:"dependsOn,omitempty"` + + // UpgradeCRDs controls how CRDs from the chart's crds/ directory are + // handled on HelmRelease upgrades. Maps to HelmRelease.Spec.Upgrade.CRDs. + // Empty string (default) preserves the helm-controller default (Skip). + // Use "CreateReplace" for operators that evolve their CRD set between + // versions. Warning: CreateReplace overwrites CRDs and may cause data + // loss if upstream drops fields from a CRD with live objects. + // +optional + // +kubebuilder:validation:Enum=Skip;Create;CreateReplace + UpgradeCRDs string `json:"upgradeCRDs,omitempty"` +} + +// Component defines a single Helm release component within a package source +type Component struct { + // Name is the unique identifier for this component within the package source + // +required + Name string `json:"name"` + + // Path is the path to the Helm chart directory + // +required + Path string `json:"path"` + + // Install defines installation parameters for this component + // +optional + Install *ComponentInstall `json:"install,omitempty"` + + // Libraries is a list of library names that this component depends on + // These libraries must be defined at the variant level + // +optional + Libraries []string `json:"libraries,omitempty"` + + // ValuesFiles is a list of values file names to use + // +optional + ValuesFiles []string `json:"valuesFiles,omitempty"` +} + +// PackageSourceStatus defines the observed state of PackageSource +type PackageSourceStatus struct { + // Variants is a comma-separated list of package variant names + // This field is populated by the controller based on spec.variants keys + // +optional + Variants string `json:"variants,omitempty"` + + // Conditions represents the latest available observations of a PackageSource's state + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index f510e197..c1adf95c 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -21,10 +21,575 @@ limitations under the License. package v1alpha1 import ( + "github.com/fluxcd/helm-controller/api/v2" + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationDefinition) DeepCopyInto(out *ApplicationDefinition) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinition. +func (in *ApplicationDefinition) DeepCopy() *ApplicationDefinition { + if in == nil { + return nil + } + out := new(ApplicationDefinition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApplicationDefinition) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationDefinitionApplication) DeepCopyInto(out *ApplicationDefinitionApplication) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionApplication. +func (in *ApplicationDefinitionApplication) DeepCopy() *ApplicationDefinitionApplication { + if in == nil { + return nil + } + out := new(ApplicationDefinitionApplication) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationDefinitionDashboard) DeepCopyInto(out *ApplicationDefinitionDashboard) { + *out = *in + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Tabs != nil { + in, out := &in.Tabs, &out.Tabs + *out = make([]DashboardTab, len(*in)) + copy(*out, *in) + } + if in.KeysOrder != nil { + in, out := &in.KeysOrder, &out.KeysOrder + *out = make([][]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionDashboard. +func (in *ApplicationDefinitionDashboard) DeepCopy() *ApplicationDefinitionDashboard { + if in == nil { + return nil + } + out := new(ApplicationDefinitionDashboard) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationDefinitionList) DeepCopyInto(out *ApplicationDefinitionList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ApplicationDefinition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionList. +func (in *ApplicationDefinitionList) DeepCopy() *ApplicationDefinitionList { + if in == nil { + return nil + } + out := new(ApplicationDefinitionList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApplicationDefinitionList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationDefinitionRelease) DeepCopyInto(out *ApplicationDefinitionRelease) { + *out = *in + if in.ChartRef != nil { + in, out := &in.ChartRef, &out.ChartRef + *out = new(v2.CrossNamespaceSourceReference) + **out = **in + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionRelease. +func (in *ApplicationDefinitionRelease) DeepCopy() *ApplicationDefinitionRelease { + if in == nil { + return nil + } + out := new(ApplicationDefinitionRelease) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationDefinitionResourceSelector) DeepCopyInto(out *ApplicationDefinitionResourceSelector) { + *out = *in + in.LabelSelector.DeepCopyInto(&out.LabelSelector) + if in.ResourceNames != nil { + in, out := &in.ResourceNames, &out.ResourceNames + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionResourceSelector. +func (in *ApplicationDefinitionResourceSelector) DeepCopy() *ApplicationDefinitionResourceSelector { + if in == nil { + return nil + } + out := new(ApplicationDefinitionResourceSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationDefinitionResources) DeepCopyInto(out *ApplicationDefinitionResources) { + *out = *in + if in.Exclude != nil { + in, out := &in.Exclude, &out.Exclude + *out = make([]*ApplicationDefinitionResourceSelector, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(ApplicationDefinitionResourceSelector) + (*in).DeepCopyInto(*out) + } + } + } + if in.Include != nil { + in, out := &in.Include, &out.Include + *out = make([]*ApplicationDefinitionResourceSelector, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(ApplicationDefinitionResourceSelector) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionResources. +func (in *ApplicationDefinitionResources) DeepCopy() *ApplicationDefinitionResources { + if in == nil { + return nil + } + out := new(ApplicationDefinitionResources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationDefinitionSpec) DeepCopyInto(out *ApplicationDefinitionSpec) { + *out = *in + out.Application = in.Application + in.Release.DeepCopyInto(&out.Release) + in.Secrets.DeepCopyInto(&out.Secrets) + in.Services.DeepCopyInto(&out.Services) + in.Ingresses.DeepCopyInto(&out.Ingresses) + if in.Dashboard != nil { + in, out := &in.Dashboard, &out.Dashboard + *out = new(ApplicationDefinitionDashboard) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationDefinitionSpec. +func (in *ApplicationDefinitionSpec) DeepCopy() *ApplicationDefinitionSpec { + if in == nil { + return nil + } + out := new(ApplicationDefinitionSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Component) DeepCopyInto(out *Component) { + *out = *in + if in.Install != nil { + in, out := &in.Install, &out.Install + *out = new(ComponentInstall) + (*in).DeepCopyInto(*out) + } + if in.Libraries != nil { + in, out := &in.Libraries, &out.Libraries + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ValuesFiles != nil { + in, out := &in.ValuesFiles, &out.ValuesFiles + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Component. +func (in *Component) DeepCopy() *Component { + if in == nil { + return nil + } + out := new(Component) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ComponentInstall) DeepCopyInto(out *ComponentInstall) { + *out = *in + if in.DependsOn != nil { + in, out := &in.DependsOn, &out.DependsOn + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ComponentInstall. +func (in *ComponentInstall) DeepCopy() *ComponentInstall { + if in == nil { + return nil + } + out := new(ComponentInstall) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DependencyStatus) DeepCopyInto(out *DependencyStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DependencyStatus. +func (in *DependencyStatus) DeepCopy() *DependencyStatus { + if in == nil { + return nil + } + out := new(DependencyStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Library) DeepCopyInto(out *Library) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Library. +func (in *Library) DeepCopy() *Library { + if in == nil { + return nil + } + out := new(Library) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Package) DeepCopyInto(out *Package) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Package. +func (in *Package) DeepCopy() *Package { + if in == nil { + return nil + } + out := new(Package) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Package) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageComponent) DeepCopyInto(out *PackageComponent) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) + **out = **in + } + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = new(v1.JSON) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageComponent. +func (in *PackageComponent) DeepCopy() *PackageComponent { + if in == nil { + return nil + } + out := new(PackageComponent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageList) DeepCopyInto(out *PackageList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Package, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageList. +func (in *PackageList) DeepCopy() *PackageList { + if in == nil { + return nil + } + out := new(PackageList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PackageList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageSource) DeepCopyInto(out *PackageSource) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageSource. +func (in *PackageSource) DeepCopy() *PackageSource { + if in == nil { + return nil + } + out := new(PackageSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PackageSource) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageSourceList) DeepCopyInto(out *PackageSourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PackageSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageSourceList. +func (in *PackageSourceList) DeepCopy() *PackageSourceList { + if in == nil { + return nil + } + out := new(PackageSourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PackageSourceList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageSourceRef) DeepCopyInto(out *PackageSourceRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageSourceRef. +func (in *PackageSourceRef) DeepCopy() *PackageSourceRef { + if in == nil { + return nil + } + out := new(PackageSourceRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageSourceSpec) DeepCopyInto(out *PackageSourceSpec) { + *out = *in + if in.SourceRef != nil { + in, out := &in.SourceRef, &out.SourceRef + *out = new(PackageSourceRef) + **out = **in + } + if in.Variants != nil { + in, out := &in.Variants, &out.Variants + *out = make([]Variant, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageSourceSpec. +func (in *PackageSourceSpec) DeepCopy() *PackageSourceSpec { + if in == nil { + return nil + } + out := new(PackageSourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageSourceStatus) DeepCopyInto(out *PackageSourceStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageSourceStatus. +func (in *PackageSourceStatus) DeepCopy() *PackageSourceStatus { + if in == nil { + return nil + } + out := new(PackageSourceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageSpec) DeepCopyInto(out *PackageSpec) { + *out = *in + if in.IgnoreDependencies != nil { + in, out := &in.IgnoreDependencies, &out.IgnoreDependencies + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Components != nil { + in, out := &in.Components, &out.Components + *out = make(map[string]PackageComponent, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageSpec. +func (in *PackageSpec) DeepCopy() *PackageSpec { + if in == nil { + return nil + } + out := new(PackageSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PackageStatus) DeepCopyInto(out *PackageStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Dependencies != nil { + in, out := &in.Dependencies, &out.Dependencies + *out = make(map[string]DependencyStatus, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PackageStatus. +func (in *PackageStatus) DeepCopy() *PackageStatus { + if in == nil { + return nil + } + out := new(PackageStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in Selector) DeepCopyInto(out *Selector) { { @@ -46,6 +611,38 @@ func (in Selector) DeepCopy() Selector { return *out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Variant) DeepCopyInto(out *Variant) { + *out = *in + if in.DependsOn != nil { + in, out := &in.DependsOn, &out.DependsOn + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Libraries != nil { + in, out := &in.Libraries, &out.Libraries + *out = make([]Library, len(*in)) + copy(*out, *in) + } + if in.Components != nil { + in, out := &in.Components, &out.Components + *out = make([]Component, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Variant. +func (in *Variant) DeepCopy() *Variant { + if in == nil { + return nil + } + out := new(Variant) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Workload) DeepCopyInto(out *Workload) { *out = *in diff --git a/cmd/backup-controller/main.go b/cmd/backup-controller/main.go new file mode 100644 index 00000000..16dfc44c --- /dev/null +++ b/cmd/backup-controller/main.go @@ -0,0 +1,181 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "crypto/tls" + "flag" + "os" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + _ "k8s.io/client-go/plugin/pkg/client/auth" + + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/metrics/filters" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" + "github.com/cozystack/cozystack/internal/backupcontroller" + // +kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + utilruntime.Must(backupsv1alpha1.AddToScheme(scheme)) + // +kubebuilder:scaffold:scheme +} + +func main() { + var metricsAddr string + var enableLeaderElection bool + var probeAddr string + var secureMetrics bool + var enableHTTP2 bool + var tlsOpts []func(*tls.Config) + flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ + "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") + flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + flag.BoolVar(&enableLeaderElection, "leader-elect", false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.") + flag.BoolVar(&secureMetrics, "metrics-secure", true, + "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.") + flag.BoolVar(&enableHTTP2, "enable-http2", false, + "If set, HTTP/2 will be enabled for the metrics and webhook servers") + opts := zap.Options{ + Development: false, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + // if the enable-http2 flag is false (the default), http/2 should be disabled + // due to its vulnerabilities. More specifically, disabling http/2 will + // prevent from being vulnerable to the HTTP/2 Stream Cancellation and + // Rapid Reset CVEs. For more information see: + // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3 + // - https://github.com/advisories/GHSA-4374-p667-p6c8 + disableHTTP2 := func(c *tls.Config) { + setupLog.Info("disabling http/2") + c.NextProtos = []string{"http/1.1"} + } + + if !enableHTTP2 { + tlsOpts = append(tlsOpts, disableHTTP2) + } + + webhookServer := webhook.NewServer(webhook.Options{ + TLSOpts: tlsOpts, + }) + + // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server. + // More info: + // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/server + // - https://book.kubebuilder.io/reference/metrics.html + metricsServerOptions := metricsserver.Options{ + BindAddress: metricsAddr, + SecureServing: secureMetrics, + TLSOpts: tlsOpts, + } + + if secureMetrics { + // FilterProvider is used to protect the metrics endpoint with authn/authz. + // These configurations ensure that only authorized users and service accounts + // can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info: + // https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/filters#WithAuthenticationAndAuthorization + metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization + + // TODO(user): If CertDir, CertName, and KeyName are not specified, controller-runtime will automatically + // generate self-signed certificates for the metrics server. While convenient for development and testing, + // this setup is not recommended for production. + } + + // Configure rate limiting for the Kubernetes client + config := ctrl.GetConfigOrDie() + config.QPS = 50.0 // Increased from default 5.0 + config.Burst = 100 // Increased from default 10 + + mgr, err := ctrl.NewManager(config, ctrl.Options{ + Scheme: scheme, + Metrics: metricsServerOptions, + WebhookServer: webhookServer, + HealthProbeBindAddress: probeAddr, + LeaderElection: enableLeaderElection, + LeaderElectionID: "core.backups.cozystack.io", + Cache: cache.Options{ + ByObject: map[client.Object]cache.ByObject{ + &backupsv1alpha1.BackupClass{}: {}, + }, + }, + // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily + // when the Manager ends. This requires the binary to immediately end when the + // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly + // speeds up voluntary leader transitions as the new leader don't have to wait + // LeaseDuration time first. + // + // In the default scaffold provided, the program ends immediately after + // the manager stops, so would be fine to enable this option. However, + // if you are doing or is intended to do any operation such as perform cleanups + // after the manager stops then its usage might be unsafe. + // LeaderElectionReleaseOnCancel: true, + }) + if err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + if err = (&backupcontroller.PlanReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Plan") + os.Exit(1) + } + + // +kubebuilder:scaffold:builder + + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up health check") + os.Exit(1) + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up ready check") + os.Exit(1) + } + + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/cmd/backupstrategy-controller/main.go b/cmd/backupstrategy-controller/main.go new file mode 100644 index 00000000..03396979 --- /dev/null +++ b/cmd/backupstrategy-controller/main.go @@ -0,0 +1,204 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "crypto/tls" + "flag" + "os" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + _ "k8s.io/client-go/plugin/pkg/client/auth" + + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/metrics/filters" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + strategyv1alpha1 "github.com/cozystack/cozystack/api/backups/strategy/v1alpha1" + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" + "github.com/cozystack/cozystack/internal/backupcontroller" + velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + // +kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + utilruntime.Must(backupsv1alpha1.AddToScheme(scheme)) + utilruntime.Must(strategyv1alpha1.AddToScheme(scheme)) + utilruntime.Must(velerov1.AddToScheme(scheme)) + // +kubebuilder:scaffold:scheme +} + +func main() { + var metricsAddr string + var enableLeaderElection bool + var probeAddr string + var secureMetrics bool + var enableHTTP2 bool + var tlsOpts []func(*tls.Config) + flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ + "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") + flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + flag.BoolVar(&enableLeaderElection, "leader-elect", false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.") + flag.BoolVar(&secureMetrics, "metrics-secure", true, + "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.") + flag.BoolVar(&enableHTTP2, "enable-http2", false, + "If set, HTTP/2 will be enabled for the metrics and webhook servers") + opts := zap.Options{ + Development: false, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + // if the enable-http2 flag is false (the default), http/2 should be disabled + // due to its vulnerabilities. More specifically, disabling http/2 will + // prevent from being vulnerable to the HTTP/2 Stream Cancellation and + // Rapid Reset CVEs. For more information see: + // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3 + // - https://github.com/advisories/GHSA-4374-p667-p6c8 + disableHTTP2 := func(c *tls.Config) { + setupLog.Info("disabling http/2") + c.NextProtos = []string{"http/1.1"} + } + + if !enableHTTP2 { + tlsOpts = append(tlsOpts, disableHTTP2) + } + + webhookServer := webhook.NewServer(webhook.Options{ + TLSOpts: tlsOpts, + }) + + // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server. + // More info: + // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/server + // - https://book.kubebuilder.io/reference/metrics.html + metricsServerOptions := metricsserver.Options{ + BindAddress: metricsAddr, + SecureServing: secureMetrics, + TLSOpts: tlsOpts, + } + + if secureMetrics { + // FilterProvider is used to protect the metrics endpoint with authn/authz. + // These configurations ensure that only authorized users and service accounts + // can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info: + // https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/filters#WithAuthenticationAndAuthorization + metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization + + // TODO(user): If CertDir, CertName, and KeyName are not specified, controller-runtime will automatically + // generate self-signed certificates for the metrics server. While convenient for development and testing, + // this setup is not recommended for production. + } + + // Configure rate limiting for the Kubernetes client + config := ctrl.GetConfigOrDie() + config.QPS = 50.0 // Increased from default 5.0 + config.Burst = 100 // Increased from default 10 + + mgr, err := ctrl.NewManager(config, ctrl.Options{ + Scheme: scheme, + Metrics: metricsServerOptions, + WebhookServer: webhookServer, + HealthProbeBindAddress: probeAddr, + LeaderElection: enableLeaderElection, + LeaderElectionID: "strategy.backups.cozystack.io", + Cache: cache.Options{ + ByObject: map[client.Object]cache.ByObject{ + &backupsv1alpha1.BackupClass{}: {}, + }, + }, + // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily + // when the Manager ends. This requires the binary to immediately end when the + // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly + // speeds up voluntary leader transitions as the new leader don't have to wait + // LeaseDuration time first. + // + // In the default scaffold provided, the program ends immediately after + // the manager stops, so would be fine to enable this option. However, + // if you are doing or is intended to do any operation such as perform cleanups + // after the manager stops then its usage might be unsafe. + // LeaderElectionReleaseOnCancel: true, + }) + if err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + if err = (&backupcontroller.BackupJobReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Recorder: mgr.GetEventRecorderFor("backup-controller"), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "BackupJob") + os.Exit(1) + } + + if err = (&backupcontroller.RestoreJobReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Recorder: mgr.GetEventRecorderFor("restore-controller"), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "RestoreJob") + os.Exit(1) + } + + if err = (&backupcontroller.BackupReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Recorder: mgr.GetEventRecorderFor("backup-controller"), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Backup") + os.Exit(1) + } + + // +kubebuilder:scaffold:builder + + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up health check") + os.Exit(1) + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up ready check") + os.Exit(1) + } + + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/cmd/cozypkg/cmd/add.go b/cmd/cozypkg/cmd/add.go new file mode 100644 index 00000000..055da3f0 --- /dev/null +++ b/cmd/cozypkg/cmd/add.go @@ -0,0 +1,549 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "bufio" + "context" + "fmt" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/spf13/cobra" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer/yaml" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + _ "k8s.io/client-go/plugin/pkg/client/auth" +) + +var addCmdFlags struct { + files []string + kubeconfig string +} + +var addCmd = &cobra.Command{ + Use: "add [package]...", + Short: "Install PackageSource and its dependencies interactively", + Long: `Install PackageSource and its dependencies interactively. + +You can specify packages as arguments or use -f flag to read from files. +Multiple -f flags can be specified, and they can point to files or directories.`, + Args: cobra.ArbitraryArgs, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + // Collect package names from arguments and files + packageNames := make(map[string]bool) + packagesFromFiles := make(map[string]string) // packageName -> filePath + + for _, arg := range args { + packageNames[arg] = true + } + + // Read packages from files + for _, filePath := range addCmdFlags.files { + packages, err := readPackagesFromFile(filePath) + if err != nil { + return fmt.Errorf("failed to read packages from %s: %w", filePath, err) + } + for _, pkg := range packages { + packageNames[pkg] = true + if oldPath, ok := packagesFromFiles[pkg]; ok { + fmt.Fprintf(os.Stderr, "warning: package %q is defined in both %s and %s, using the latter\n", pkg, oldPath, filePath) + } + packagesFromFiles[pkg] = filePath + } + } + + if len(packageNames) == 0 { + return fmt.Errorf("no packages specified") + } + + // Create Kubernetes client config + var config *rest.Config + var err error + + if addCmdFlags.kubeconfig != "" { + config, err = clientcmd.BuildConfigFromFlags("", addCmdFlags.kubeconfig) + if err != nil { + return fmt.Errorf("failed to load kubeconfig from %s: %w", addCmdFlags.kubeconfig, err) + } + } else { + config, err = ctrl.GetConfig() + if err != nil { + return fmt.Errorf("failed to get kubeconfig: %w", err) + } + } + + scheme := runtime.NewScheme() + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(cozyv1alpha1.AddToScheme(scheme)) + + k8sClient, err := client.New(config, client.Options{Scheme: scheme}) + if err != nil { + return fmt.Errorf("failed to create k8s client: %w", err) + } + + // Process each package + for packageName := range packageNames { + // Check if package comes from a file + if filePath, fromFile := packagesFromFiles[packageName]; fromFile { + // Try to create Package directly from file + if err := createPackageFromFile(ctx, k8sClient, filePath, packageName); err == nil { + fmt.Fprintf(os.Stderr, "✓ Added Package %s\n", packageName) + continue + } + // If failed, fall back to interactive installation + } + + // Interactive installation from PackageSource + if err := installPackage(ctx, k8sClient, packageName); err != nil { + return err + } + } + + return nil + }, +} + +func readPackagesFromFile(filePath string) ([]string, error) { + info, err := os.Stat(filePath) + if err != nil { + return nil, err + } + + var packages []string + + if info.IsDir() { + // Read all YAML files from directory + err := filepath.Walk(filePath, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() || !strings.HasSuffix(path, ".yaml") && !strings.HasSuffix(path, ".yml") { + return nil + } + + pkgs, err := readPackagesFromYAMLFile(path) + if err != nil { + return fmt.Errorf("failed to read %s: %w", path, err) + } + packages = append(packages, pkgs...) + return nil + }) + if err != nil { + return nil, err + } + } else { + packages, err = readPackagesFromYAMLFile(filePath) + if err != nil { + return nil, err + } + } + + return packages, nil +} + +func readPackagesFromYAMLFile(filePath string) ([]string, error) { + data, err := os.ReadFile(filePath) + if err != nil { + return nil, err + } + + var packages []string + + // Split YAML documents (in case of multiple resources) + documents := strings.Split(string(data), "---") + + for _, doc := range documents { + doc = strings.TrimSpace(doc) + if doc == "" { + continue + } + + // Parse using Kubernetes decoder + decoder := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme) + obj := &unstructured.Unstructured{} + _, _, err := decoder.Decode([]byte(doc), nil, obj) + if err != nil { + continue + } + + // Check if it's a Package + if obj.GetKind() == "Package" { + name := obj.GetName() + if name != "" { + packages = append(packages, name) + } + continue + } + + // Check if it's a PackageSource + if obj.GetKind() == "PackageSource" { + name := obj.GetName() + if name != "" { + packages = append(packages, name) + } + continue + } + + // Try to parse as PackageList or PackageSourceList + if obj.GetKind() == "PackageList" || obj.GetKind() == "PackageSourceList" { + items, found, err := unstructured.NestedSlice(obj.Object, "items") + if err == nil && found { + for _, item := range items { + if itemMap, ok := item.(map[string]interface{}); ok { + if metadata, ok := itemMap["metadata"].(map[string]interface{}); ok { + if name, ok := metadata["name"].(string); ok && name != "" { + packages = append(packages, name) + } + } + } + } + } + continue + } + } + + // Return empty list if no packages found - don't error out + // The check for whether any packages were specified at all is handled later in RunE + return packages, nil +} + +// buildDependencyTree builds a dependency tree starting from the root PackageSource +// Returns both the dependency tree and a map of dependencies to their requesters +func buildDependencyTree(ctx context.Context, k8sClient client.Client, rootName string) (map[string][]string, map[string]string, error) { + tree := make(map[string][]string) + dependencyRequesters := make(map[string]string) // dep -> requester + visited := make(map[string]bool) + + // Ensure root is in tree even if it has no dependencies + tree[rootName] = []string{} + + var buildTree func(string) error + buildTree = func(pkgName string) error { + if visited[pkgName] { + return nil + } + visited[pkgName] = true + + // Get PackageSource + ps := &cozyv1alpha1.PackageSource{} + if err := k8sClient.Get(ctx, client.ObjectKey{Name: pkgName}, ps); err != nil { + // If PackageSource doesn't exist, just skip it + return nil + } + + // Collect all dependencies from all variants + deps := make(map[string]bool) + for _, variant := range ps.Spec.Variants { + for _, dep := range variant.DependsOn { + deps[dep] = true + } + } + + // Add dependencies to tree + for dep := range deps { + if _, exists := tree[pkgName]; !exists { + tree[pkgName] = []string{} + } + tree[pkgName] = append(tree[pkgName], dep) + // Track who requested this dependency + dependencyRequesters[dep] = pkgName + // Recursively build tree for dependencies + if err := buildTree(dep); err != nil { + return err + } + } + + return nil + } + + if err := buildTree(rootName); err != nil { + return nil, nil, err + } + + return tree, dependencyRequesters, nil +} + +// topologicalSort performs topological sort on the dependency tree +// Returns order from root to leaves (dependencies first) +func topologicalSort(tree map[string][]string) ([]string, error) { + // Build reverse graph (dependencies -> dependents) + reverseGraph := make(map[string][]string) + allNodes := make(map[string]bool) + + for node, deps := range tree { + allNodes[node] = true + for _, dep := range deps { + allNodes[dep] = true + reverseGraph[dep] = append(reverseGraph[dep], node) + } + } + + // Calculate in-degrees (how many dependencies a node has) + inDegree := make(map[string]int) + for node := range allNodes { + inDegree[node] = 0 + } + for node, deps := range tree { + inDegree[node] = len(deps) + } + + // Kahn's algorithm - start with nodes that have no dependencies + var queue []string + for node, degree := range inDegree { + if degree == 0 { + queue = append(queue, node) + } + } + + var result []string + for len(queue) > 0 { + node := queue[0] + queue = queue[1:] + result = append(result, node) + + // Process dependents (nodes that depend on this node) + for _, dependent := range reverseGraph[node] { + inDegree[dependent]-- + if inDegree[dependent] == 0 { + queue = append(queue, dependent) + } + } + } + + // Check for cycles + if len(result) != len(allNodes) { + return nil, fmt.Errorf("dependency cycle detected") + } + + return result, nil +} + +// createPackageFromFile creates a Package resource directly from a YAML file +func createPackageFromFile(ctx context.Context, k8sClient client.Client, filePath string, packageName string) error { + data, err := os.ReadFile(filePath) + if err != nil { + return err + } + + // Split YAML documents + documents := strings.Split(string(data), "---") + + for _, doc := range documents { + doc = strings.TrimSpace(doc) + if doc == "" { + continue + } + + // Parse using Kubernetes decoder + decoder := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme) + obj := &unstructured.Unstructured{} + _, _, err := decoder.Decode([]byte(doc), nil, obj) + if err != nil { + continue + } + + // Check if it's a Package with matching name + if obj.GetKind() == "Package" && obj.GetName() == packageName { + // Convert to Package + var pkg cozyv1alpha1.Package + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &pkg); err != nil { + return fmt.Errorf("failed to convert Package: %w", err) + } + + // Create Package + if err := k8sClient.Create(ctx, &pkg); err != nil { + return fmt.Errorf("failed to create Package: %w", err) + } + + return nil + } + } + + return fmt.Errorf("Package %s not found in file", packageName) +} + +func installPackage(ctx context.Context, k8sClient client.Client, packageSourceName string) error { + // Get PackageSource + packageSource := &cozyv1alpha1.PackageSource{} + if err := k8sClient.Get(ctx, client.ObjectKey{Name: packageSourceName}, packageSource); err != nil { + return fmt.Errorf("failed to get PackageSource %s: %w", packageSourceName, err) + } + + // Build dependency tree + dependencyTree, dependencyRequesters, err := buildDependencyTree(ctx, k8sClient, packageSourceName) + if err != nil { + return fmt.Errorf("failed to build dependency tree: %w", err) + } + + // Topological sort (install from root to leaves) + installOrder, err := topologicalSort(dependencyTree) + if err != nil { + return fmt.Errorf("failed to sort dependencies: %w", err) + } + + // Get all PackageSources for variant selection + var allPackageSources cozyv1alpha1.PackageSourceList + if err := k8sClient.List(ctx, &allPackageSources); err != nil { + return fmt.Errorf("failed to list PackageSources: %w", err) + } + + packageSourceMap := make(map[string]*cozyv1alpha1.PackageSource) + for i := range allPackageSources.Items { + packageSourceMap[allPackageSources.Items[i].Name] = &allPackageSources.Items[i] + } + + // Get all installed Packages + var installedPackages cozyv1alpha1.PackageList + if err := k8sClient.List(ctx, &installedPackages); err != nil { + return fmt.Errorf("failed to list Packages: %w", err) + } + + installedMap := make(map[string]*cozyv1alpha1.Package) + for i := range installedPackages.Items { + installedMap[installedPackages.Items[i].Name] = &installedPackages.Items[i] + } + + // First, collect all variant selections + fmt.Fprintf(os.Stderr, "Installing %s and its dependencies...\n\n", packageSourceName) + packageVariants := make(map[string]string) // packageName -> variant + + for _, pkgName := range installOrder { + // Check if already installed + if installed, exists := installedMap[pkgName]; exists { + variant := installed.Spec.Variant + if variant == "" { + variant = "default" + } + fmt.Fprintf(os.Stderr, "✓ %s (already installed, variant: %s)\n", pkgName, variant) + packageVariants[pkgName] = variant + continue + } + + // Get PackageSource for this dependency + ps, exists := packageSourceMap[pkgName] + if !exists { + requester := dependencyRequesters[pkgName] + if requester != "" { + return fmt.Errorf("PackageSource %s not found (required by %s)", pkgName, requester) + } + return fmt.Errorf("PackageSource %s not found", pkgName) + } + + // Select variant interactively + variant, err := selectVariantInteractive(ps) + if err != nil { + return fmt.Errorf("failed to select variant for %s: %w", pkgName, err) + } + + packageVariants[pkgName] = variant + } + + // Now create all Package resources + for _, pkgName := range installOrder { + // Skip if already installed + if _, exists := installedMap[pkgName]; exists { + continue + } + + variant := packageVariants[pkgName] + + // Create Package + pkg := &cozyv1alpha1.Package{ + ObjectMeta: metav1.ObjectMeta{ + Name: pkgName, + }, + Spec: cozyv1alpha1.PackageSpec{ + Variant: variant, + }, + } + + if err := k8sClient.Create(ctx, pkg); err != nil { + return fmt.Errorf("failed to create Package %s: %w", pkgName, err) + } + + fmt.Fprintf(os.Stderr, "✓ Added Package %s\n", pkgName) + } + + return nil +} + +// selectVariantInteractive prompts user to select a variant +func selectVariantInteractive(ps *cozyv1alpha1.PackageSource) (string, error) { + if len(ps.Spec.Variants) == 0 { + return "", fmt.Errorf("no variants available for PackageSource %s", ps.Name) + } + + reader := bufio.NewReader(os.Stdin) + + fmt.Fprintf(os.Stderr, "\nPackageSource: %s\n", ps.Name) + fmt.Fprintf(os.Stderr, "Available variants:\n") + for i, variant := range ps.Spec.Variants { + fmt.Fprintf(os.Stderr, " %d. %s\n", i+1, variant.Name) + } + + // If only one variant, use it as default + defaultVariant := ps.Spec.Variants[0].Name + var prompt string + if len(ps.Spec.Variants) == 1 { + prompt = "Select variant [1]: " + } else { + prompt = fmt.Sprintf("Select variant (1-%d): ", len(ps.Spec.Variants)) + } + + for { + fmt.Fprintf(os.Stderr, prompt) + input, err := reader.ReadString('\n') + if err != nil { + return "", fmt.Errorf("failed to read input: %w", err) + } + + input = strings.TrimSpace(input) + + // If input is empty and there's a default variant, use it + if input == "" && len(ps.Spec.Variants) == 1 { + return defaultVariant, nil + } + + choice, err := strconv.Atoi(input) + if err != nil || choice < 1 || choice > len(ps.Spec.Variants) { + fmt.Fprintf(os.Stderr, "Invalid choice. Please enter a number between 1 and %d.\n", len(ps.Spec.Variants)) + continue + } + + return ps.Spec.Variants[choice-1].Name, nil + } +} + +func init() { + rootCmd.AddCommand(addCmd) + addCmd.Flags().StringArrayVarP(&addCmdFlags.files, "file", "f", []string{}, "Read packages from file or directory (can be specified multiple times)") + addCmd.Flags().StringVar(&addCmdFlags.kubeconfig, "kubeconfig", "", "Path to kubeconfig file (defaults to ~/.kube/config or KUBECONFIG env var)") +} + diff --git a/cmd/cozypkg/cmd/del.go b/cmd/cozypkg/cmd/del.go new file mode 100644 index 00000000..6b2e37f5 --- /dev/null +++ b/cmd/cozypkg/cmd/del.go @@ -0,0 +1,396 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "bufio" + "context" + "fmt" + "os" + "strings" + + "github.com/spf13/cobra" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + _ "k8s.io/client-go/plugin/pkg/client/auth" +) + +var delCmdFlags struct { + files []string + kubeconfig string +} + +var delCmd = &cobra.Command{ + Use: "del [package]...", + Short: "Delete Package resources", + Long: `Delete Package resources. + +You can specify packages as arguments or use -f flag to read from files. +Multiple -f flags can be specified, and they can point to files or directories.`, + Args: cobra.ArbitraryArgs, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + // Collect package names from arguments and files + packageNames := make(map[string]bool) + packagesFromFiles := make(map[string]string) // packageName -> filePath + + for _, arg := range args { + packageNames[arg] = true + } + + // Read packages from files (reuse function from add.go) + for _, filePath := range delCmdFlags.files { + packages, err := readPackagesFromFile(filePath) + if err != nil { + return fmt.Errorf("failed to read packages from %s: %w", filePath, err) + } + for _, pkg := range packages { + packageNames[pkg] = true + if oldPath, ok := packagesFromFiles[pkg]; ok { + fmt.Fprintf(os.Stderr, "warning: package %q is defined in both %s and %s, using the latter\n", pkg, oldPath, filePath) + } + packagesFromFiles[pkg] = filePath + } + } + + if len(packageNames) == 0 { + return fmt.Errorf("no packages specified") + } + + // Create Kubernetes client config + var config *rest.Config + var err error + + if delCmdFlags.kubeconfig != "" { + config, err = clientcmd.BuildConfigFromFlags("", delCmdFlags.kubeconfig) + if err != nil { + return fmt.Errorf("failed to load kubeconfig from %s: %w", delCmdFlags.kubeconfig, err) + } + } else { + config, err = ctrl.GetConfig() + if err != nil { + return fmt.Errorf("failed to get kubeconfig: %w", err) + } + } + + scheme := runtime.NewScheme() + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(cozyv1alpha1.AddToScheme(scheme)) + + k8sClient, err := client.New(config, client.Options{Scheme: scheme}) + if err != nil { + return fmt.Errorf("failed to create k8s client: %w", err) + } + + // Check which requested packages are installed + var installedPackages cozyv1alpha1.PackageList + if err := k8sClient.List(ctx, &installedPackages); err != nil { + return fmt.Errorf("failed to list Packages: %w", err) + } + installedMap := make(map[string]bool) + for _, pkg := range installedPackages.Items { + installedMap[pkg.Name] = true + } + + // Warn about requested packages that are not installed + for pkgName := range packageNames { + if !installedMap[pkgName] { + fmt.Fprintf(os.Stderr, "⚠ Package %s is not installed, skipping\n", pkgName) + } + } + + // Find all packages to delete (including dependents) + packagesToDelete, err := findPackagesToDelete(ctx, k8sClient, packageNames) + if err != nil { + return fmt.Errorf("failed to analyze dependencies: %w", err) + } + + if len(packagesToDelete) == 0 { + fmt.Fprintf(os.Stderr, "No packages found to delete\n") + return nil + } + + // Show packages to be deleted and ask for confirmation + if err := confirmDeletion(packagesToDelete, packageNames); err != nil { + return err + } + + // Delete packages in reverse topological order (dependents first, then dependencies) + deleteOrder, err := getDeleteOrder(ctx, k8sClient, packagesToDelete) + if err != nil { + return fmt.Errorf("failed to determine delete order: %w", err) + } + + // Delete each package + for _, packageName := range deleteOrder { + pkg := &cozyv1alpha1.Package{} + pkg.Name = packageName + if err := k8sClient.Delete(ctx, pkg); err != nil { + if apierrors.IsNotFound(err) { + fmt.Fprintf(os.Stderr, "⚠ Package %s not found, skipping\n", packageName) + continue + } + return fmt.Errorf("failed to delete Package %s: %w", packageName, err) + } + fmt.Fprintf(os.Stderr, "✓ Deleted Package %s\n", packageName) + } + + return nil + }, +} + +// findPackagesToDelete finds all packages that need to be deleted, including dependents +func findPackagesToDelete(ctx context.Context, k8sClient client.Client, requestedPackages map[string]bool) (map[string]bool, error) { + // Get all installed Packages + var installedPackages cozyv1alpha1.PackageList + if err := k8sClient.List(ctx, &installedPackages); err != nil { + return nil, fmt.Errorf("failed to list Packages: %w", err) + } + + installedMap := make(map[string]bool) + for _, pkg := range installedPackages.Items { + installedMap[pkg.Name] = true + } + + // Get all PackageSources to build dependency graph + var packageSources cozyv1alpha1.PackageSourceList + if err := k8sClient.List(ctx, &packageSources); err != nil { + return nil, fmt.Errorf("failed to list PackageSources: %w", err) + } + + // Build reverse dependency graph (dependents -> dependencies) + // This tells us: for each package, which packages depend on it + reverseDeps := make(map[string][]string) + for _, ps := range packageSources.Items { + // Only consider installed packages + if !installedMap[ps.Name] { + continue + } + for _, variant := range ps.Spec.Variants { + for _, dep := range variant.DependsOn { + // Only consider installed dependencies + if installedMap[dep] { + reverseDeps[dep] = append(reverseDeps[dep], ps.Name) + } + } + } + } + + // Find all packages to delete (requested + their dependents) + packagesToDelete := make(map[string]bool) + visited := make(map[string]bool) + + var findDependents func(string) + findDependents = func(pkgName string) { + if visited[pkgName] { + return + } + visited[pkgName] = true + + // Only add if it's installed + if installedMap[pkgName] { + packagesToDelete[pkgName] = true + } + + // Recursively find all dependents + for _, dependent := range reverseDeps[pkgName] { + if installedMap[dependent] { + findDependents(dependent) + } + } + } + + // Start from requested packages + for pkgName := range requestedPackages { + if !installedMap[pkgName] { + continue + } + findDependents(pkgName) + } + + return packagesToDelete, nil +} + +// confirmDeletion shows the list of packages to be deleted and asks for user confirmation +func confirmDeletion(packagesToDelete map[string]bool, requestedPackages map[string]bool) error { + // Separate requested packages from dependents + var requested []string + var dependents []string + + for pkg := range packagesToDelete { + if requestedPackages[pkg] { + requested = append(requested, pkg) + } else { + dependents = append(dependents, pkg) + } + } + + fmt.Fprintf(os.Stderr, "\nThe following packages will be deleted:\n\n") + + if len(requested) > 0 { + fmt.Fprintf(os.Stderr, "Requested packages:\n") + for _, pkg := range requested { + fmt.Fprintf(os.Stderr, " - %s\n", pkg) + } + fmt.Fprintf(os.Stderr, "\n") + } + + if len(dependents) > 0 { + fmt.Fprintf(os.Stderr, "Dependent packages (will also be deleted):\n") + for _, pkg := range dependents { + fmt.Fprintf(os.Stderr, " - %s\n", pkg) + } + fmt.Fprintf(os.Stderr, "\n") + } + + fmt.Fprintf(os.Stderr, "Total: %d package(s)\n\n", len(packagesToDelete)) + fmt.Fprintf(os.Stderr, "Do you want to continue? [y/N]: ") + + reader := bufio.NewReader(os.Stdin) + input, err := reader.ReadString('\n') + if err != nil { + return fmt.Errorf("failed to read input: %w", err) + } + + input = strings.TrimSpace(strings.ToLower(input)) + if input != "y" && input != "yes" { + return fmt.Errorf("deletion cancelled") + } + + return nil +} + +// getDeleteOrder returns packages in reverse topological order (dependents first, then dependencies) +// This ensures we delete dependents before their dependencies +func getDeleteOrder(ctx context.Context, k8sClient client.Client, packagesToDelete map[string]bool) ([]string, error) { + // Get all PackageSources to build dependency graph + var packageSources cozyv1alpha1.PackageSourceList + if err := k8sClient.List(ctx, &packageSources); err != nil { + return nil, fmt.Errorf("failed to list PackageSources: %w", err) + } + + // Build forward dependency graph (package -> dependencies) + dependencyGraph := make(map[string][]string) + for _, ps := range packageSources.Items { + if !packagesToDelete[ps.Name] { + continue + } + deps := make(map[string]bool) + for _, variant := range ps.Spec.Variants { + for _, dep := range variant.DependsOn { + if packagesToDelete[dep] { + deps[dep] = true + } + } + } + var depList []string + for dep := range deps { + depList = append(depList, dep) + } + dependencyGraph[ps.Name] = depList + } + + // Build reverse graph for topological sort + reverseGraph := make(map[string][]string) + allNodes := make(map[string]bool) + + for node, deps := range dependencyGraph { + allNodes[node] = true + for _, dep := range deps { + allNodes[dep] = true + reverseGraph[dep] = append(reverseGraph[dep], node) + } + } + + // Add nodes that have no dependencies + for pkg := range packagesToDelete { + if !allNodes[pkg] { + allNodes[pkg] = true + dependencyGraph[pkg] = []string{} + } + } + + // Calculate in-degrees + inDegree := make(map[string]int) + for node := range allNodes { + inDegree[node] = 0 + } + for node, deps := range dependencyGraph { + inDegree[node] = len(deps) + } + + // Kahn's algorithm - start with nodes that have no dependencies + var queue []string + for node, degree := range inDegree { + if degree == 0 { + queue = append(queue, node) + } + } + + var result []string + for len(queue) > 0 { + node := queue[0] + queue = queue[1:] + result = append(result, node) + + // Process dependents + for _, dependent := range reverseGraph[node] { + inDegree[dependent]-- + if inDegree[dependent] == 0 { + queue = append(queue, dependent) + } + } + } + + // Check for cycles: if not all nodes were processed, there's a cycle + if len(result) != len(allNodes) { + // Find unprocessed nodes + processed := make(map[string]bool) + for _, node := range result { + processed[node] = true + } + var unprocessed []string + for node := range allNodes { + if !processed[node] { + unprocessed = append(unprocessed, node) + } + } + return nil, fmt.Errorf("dependency cycle detected: the following packages form a cycle and cannot be deleted: %v", unprocessed) + } + + // Reverse the result to get dependents first, then dependencies + for i, j := 0, len(result)-1; i < j; i, j = i+1, j-1 { + result[i], result[j] = result[j], result[i] + } + + return result, nil +} + +func init() { + rootCmd.AddCommand(delCmd) + delCmd.Flags().StringArrayVarP(&delCmdFlags.files, "file", "f", []string{}, "Read packages from file or directory (can be specified multiple times)") + delCmd.Flags().StringVar(&delCmdFlags.kubeconfig, "kubeconfig", "", "Path to kubeconfig file (defaults to ~/.kube/config or KUBECONFIG env var)") +} + diff --git a/cmd/cozypkg/cmd/dependencies.go b/cmd/cozypkg/cmd/dependencies.go new file mode 100644 index 00000000..7db71d4a --- /dev/null +++ b/cmd/cozypkg/cmd/dependencies.go @@ -0,0 +1,564 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "context" + "fmt" + "os" + "strings" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + "github.com/emicklei/dot" + "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + _ "k8s.io/client-go/plugin/pkg/client/auth" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var dotCmdFlags struct { + installed bool + components bool + files []string + kubeconfig string +} + +var dotCmd = &cobra.Command{ + Use: "dot [package]...", + Short: "Generate dependency graph as graphviz DOT format", + Long: `Generate dependency graph as graphviz DOT format. + +Pipe the output through the "dot" program (part of graphviz package) to render the graph: + + cozypkg dot | dot -Tpng > graph.png + +By default, shows dependencies for all PackageSource resources. +Use --installed to show only installed Package resources. +Specify packages as arguments or use -f flag to read from files.`, + Args: cobra.ArbitraryArgs, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + // Collect package names from arguments and files + packageNames := make(map[string]bool) + for _, arg := range args { + packageNames[arg] = true + } + + // Read packages from files (reuse function from add.go) + for _, filePath := range dotCmdFlags.files { + packages, err := readPackagesFromFile(filePath) + if err != nil { + return fmt.Errorf("failed to read packages from %s: %w", filePath, err) + } + for _, pkg := range packages { + packageNames[pkg] = true + } + } + + // Convert to slice, empty means all packages + var selectedPackages []string + if len(packageNames) > 0 { + for pkg := range packageNames { + selectedPackages = append(selectedPackages, pkg) + } + } + + // If multiple packages specified, show graph for all of them + // If single package, use packageName for backward compatibility + var packageName string + if len(selectedPackages) == 1 { + packageName = selectedPackages[0] + } else if len(selectedPackages) > 1 { + // Multiple packages - pass empty string to packageName, use selectedPackages + packageName = "" + } + + // packagesOnly is inverse of components flag (if components=false, then packagesOnly=true) + packagesOnly := !dotCmdFlags.components + graph, allNodes, edgeVariants, packageNames, err := buildGraphFromCluster(ctx, dotCmdFlags.kubeconfig, packagesOnly, dotCmdFlags.installed, packageName, selectedPackages) + if err != nil { + return fmt.Errorf("error getting PackageSource dependencies: %w", err) + } + + dotGraph := generateDOTGraph(graph, allNodes, packagesOnly, edgeVariants, packageNames) + dotGraph.Write(os.Stdout) + + return nil + }, +} + +func init() { + rootCmd.AddCommand(dotCmd) + dotCmd.Flags().BoolVarP(&dotCmdFlags.installed, "installed", "i", false, "show dependencies only for installed Package resources") + dotCmd.Flags().BoolVar(&dotCmdFlags.components, "components", false, "show component-level dependencies") + dotCmd.Flags().StringArrayVarP(&dotCmdFlags.files, "file", "f", []string{}, "Read packages from file or directory (can be specified multiple times)") + dotCmd.Flags().StringVar(&dotCmdFlags.kubeconfig, "kubeconfig", "", "Path to kubeconfig file (defaults to ~/.kube/config or KUBECONFIG env var)") +} + +var ( + dependenciesScheme = runtime.NewScheme() +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(dependenciesScheme)) + utilruntime.Must(cozyv1alpha1.AddToScheme(dependenciesScheme)) +} + +// buildGraphFromCluster builds a dependency graph from PackageSource resources in the cluster. +// Returns: graph, allNodes, edgeVariants (map[edgeKey]variants), packageNames, error +func buildGraphFromCluster(ctx context.Context, kubeconfig string, packagesOnly bool, installedOnly bool, packageName string, selectedPackages []string) (map[string][]string, map[string]bool, map[string][]string, map[string]bool, error) { + // Create Kubernetes client config + var config *rest.Config + var err error + + if kubeconfig != "" { + // Load kubeconfig from explicit path + config, err = clientcmd.BuildConfigFromFlags("", kubeconfig) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("failed to load kubeconfig from %s: %w", kubeconfig, err) + } + } else { + // Use default kubeconfig loading (from env var or ~/.kube/config) + config, err = ctrl.GetConfig() + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("failed to get kubeconfig: %w", err) + } + } + + k8sClient, err := client.New(config, client.Options{Scheme: dependenciesScheme}) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("failed to create k8s client: %w", err) + } + + // Get installed Packages if needed + installedPackages := make(map[string]bool) + if installedOnly { + var packageList cozyv1alpha1.PackageList + if err := k8sClient.List(ctx, &packageList); err != nil { + return nil, nil, nil, nil, fmt.Errorf("failed to list Packages: %w", err) + } + for _, pkg := range packageList.Items { + installedPackages[pkg.Name] = true + } + } + + // List all PackageSource resources + var packageSourceList cozyv1alpha1.PackageSourceList + if err := k8sClient.List(ctx, &packageSourceList); err != nil { + return nil, nil, nil, nil, fmt.Errorf("failed to list PackageSources: %w", err) + } + + // Build map of existing packages and components + packageNames := make(map[string]bool) + allExistingComponents := make(map[string]bool) // "package.component" -> true + for _, ps := range packageSourceList.Items { + if ps.Name != "" { + packageNames[ps.Name] = true + for _, variant := range ps.Spec.Variants { + for _, component := range variant.Components { + if component.Install != nil { + componentFullName := fmt.Sprintf("%s.%s", ps.Name, component.Name) + allExistingComponents[componentFullName] = true + } + } + } + } + } + + graph := make(map[string][]string) + allNodes := make(map[string]bool) + edgeVariants := make(map[string][]string) // key: "source->target", value: list of variant names + existingEdges := make(map[string]bool) // key: "source->target" to avoid duplicates + componentHasLocalDeps := make(map[string]bool) // componentName -> has local component dependencies + + // Process each PackageSource + for _, ps := range packageSourceList.Items { + psName := ps.Name + if psName == "" { + continue + } + + // Filter by package name if specified + if packageName != "" && psName != packageName { + continue + } + + // Filter by selected packages if specified + if len(selectedPackages) > 0 { + found := false + for _, selected := range selectedPackages { + if psName == selected { + found = true + break + } + } + if !found { + continue + } + } + + // Filter by installed packages if flag is set + if installedOnly && !installedPackages[psName] { + continue + } + + allNodes[psName] = true + + // Track package dependencies per variant + packageDepVariants := make(map[string]map[string]bool) // dep -> variant -> true + allVariantNames := make(map[string]bool) + for _, v := range ps.Spec.Variants { + allVariantNames[v.Name] = true + } + + // Track component dependencies per variant + componentDepVariants := make(map[string]map[string]map[string]bool) // componentName -> dep -> variant -> true + componentVariants := make(map[string]map[string]bool) // componentName -> variant -> true + + // Extract dependencies from variants + for _, variant := range ps.Spec.Variants { + // Variant-level dependencies (package-level) + for _, dep := range variant.DependsOn { + // If installedOnly is set, only include dependencies that are installed + if installedOnly && !installedPackages[dep] { + continue + } + + // Track which variant this dependency comes from + if packageDepVariants[dep] == nil { + packageDepVariants[dep] = make(map[string]bool) + } + packageDepVariants[dep][variant.Name] = true + + edgeKey := fmt.Sprintf("%s->%s", psName, dep) + if !existingEdges[edgeKey] { + graph[psName] = append(graph[psName], dep) + existingEdges[edgeKey] = true + } + + // Add to allNodes only if package exists + if packageNames[dep] { + allNodes[dep] = true + } + // If package doesn't exist, don't add to allNodes - it will be shown as missing (red) + } + + // Component-level dependencies + if !packagesOnly { + for _, component := range variant.Components { + // Skip components without install section + if component.Install == nil { + continue + } + + componentName := fmt.Sprintf("%s.%s", psName, component.Name) + allNodes[componentName] = true + + // Track which variants this component appears in + if componentVariants[componentName] == nil { + componentVariants[componentName] = make(map[string]bool) + } + componentVariants[componentName][variant.Name] = true + + if component.Install != nil { + if componentDepVariants[componentName] == nil { + componentDepVariants[componentName] = make(map[string]map[string]bool) + } + + for _, dep := range component.Install.DependsOn { + // Track which variant this dependency comes from + if componentDepVariants[componentName][dep] == nil { + componentDepVariants[componentName][dep] = make(map[string]bool) + } + componentDepVariants[componentName][dep][variant.Name] = true + + // Check if it's a local component dependency or external + if strings.Contains(dep, ".") { + // External component dependency (package.component format) + // Mark that this component has local dependencies (for edge to package logic) + componentHasLocalDeps[componentName] = true + + // Check if target component exists + if allExistingComponents[dep] { + // Component exists + edgeKey := fmt.Sprintf("%s->%s", componentName, dep) + if !existingEdges[edgeKey] { + graph[componentName] = append(graph[componentName], dep) + existingEdges[edgeKey] = true + } + allNodes[dep] = true + } else { + // Component doesn't exist - create missing component node + edgeKey := fmt.Sprintf("%s->%s", componentName, dep) + if !existingEdges[edgeKey] { + graph[componentName] = append(graph[componentName], dep) + existingEdges[edgeKey] = true + } + // Don't add to allNodes - will be shown as missing (red) + + // Add edge from missing component to its package + parts := strings.SplitN(dep, ".", 2) + if len(parts) == 2 { + depPackageName := parts[0] + missingEdgeKey := fmt.Sprintf("%s->%s", dep, depPackageName) + if !existingEdges[missingEdgeKey] { + graph[dep] = append(graph[dep], depPackageName) + existingEdges[missingEdgeKey] = true + } + // Add package to allNodes only if it exists + if packageNames[depPackageName] { + allNodes[depPackageName] = true + } + // If package doesn't exist, it will be shown as missing (red) + } + } + } else { + // Local component dependency (same package) + // Mark that this component has local dependencies + componentHasLocalDeps[componentName] = true + + localDep := fmt.Sprintf("%s.%s", psName, dep) + + // Check if target component exists + if allExistingComponents[localDep] { + // Component exists + edgeKey := fmt.Sprintf("%s->%s", componentName, localDep) + if !existingEdges[edgeKey] { + graph[componentName] = append(graph[componentName], localDep) + existingEdges[edgeKey] = true + } + allNodes[localDep] = true + } else { + // Component doesn't exist - create missing component node + edgeKey := fmt.Sprintf("%s->%s", componentName, localDep) + if !existingEdges[edgeKey] { + graph[componentName] = append(graph[componentName], localDep) + existingEdges[edgeKey] = true + } + // Don't add to allNodes - will be shown as missing (red) + + // Add edge from missing component to its package + missingEdgeKey := fmt.Sprintf("%s->%s", localDep, psName) + if !existingEdges[missingEdgeKey] { + graph[localDep] = append(graph[localDep], psName) + existingEdges[missingEdgeKey] = true + } + } + } + } + } + } + } + } + + // Store variant information for package dependencies that are not in all variants + for dep, variants := range packageDepVariants { + if len(variants) < len(allVariantNames) { + var variantList []string + for v := range variants { + variantList = append(variantList, v) + } + edgeKey := fmt.Sprintf("%s->%s", psName, dep) + edgeVariants[edgeKey] = variantList + } + } + + // Add component->package edges for components without local dependencies + if !packagesOnly { + for componentName := range componentVariants { + // Only add edge to package if component has no local component dependencies + if !componentHasLocalDeps[componentName] { + edgeKey := fmt.Sprintf("%s->%s", componentName, psName) + if !existingEdges[edgeKey] { + graph[componentName] = append(graph[componentName], psName) + existingEdges[edgeKey] = true + } + + // If component is not in all variants, store variant info for component->package edge + componentAllVariants := componentVariants[componentName] + if len(componentAllVariants) < len(allVariantNames) { + var variantList []string + for v := range componentAllVariants { + variantList = append(variantList, v) + } + edgeVariants[edgeKey] = variantList + } + } + } + } + + // Store variant information for component dependencies that are not in all variants + for componentName, deps := range componentDepVariants { + componentAllVariants := componentVariants[componentName] + for dep, variants := range deps { + if len(variants) < len(componentAllVariants) { + var variantList []string + for v := range variants { + variantList = append(variantList, v) + } + // Determine the actual target name + var targetName string + if strings.Contains(dep, ".") { + targetName = dep + } else { + targetName = fmt.Sprintf("%s.%s", psName, dep) + } + edgeKey := fmt.Sprintf("%s->%s", componentName, targetName) + edgeVariants[edgeKey] = variantList + } + } + } + } + + return graph, allNodes, edgeVariants, packageNames, nil +} + +// generateDOTGraph generates a DOT graph from the dependency graph. +func generateDOTGraph(graph map[string][]string, allNodes map[string]bool, packagesOnly bool, edgeVariants map[string][]string, packageNames map[string]bool) *dot.Graph { + g := dot.NewGraph(dot.Directed) + g.Attr("rankdir", "RL") + g.Attr("nodesep", "0.5") + g.Attr("ranksep", "1.0") + + // Helper function to check if a node is a package + // A node is a package if: + // 1. It's directly in packageNames + // 2. It doesn't contain a dot (simple package name) + // 3. It contains a dot but the part before the first dot is a package name + isPackage := func(nodeName string) bool { + if packageNames[nodeName] { + return true + } + if !strings.Contains(nodeName, ".") { + return true + } + // If it contains a dot, check if the part before the first dot is a package + parts := strings.SplitN(nodeName, ".", 2) + if len(parts) > 0 { + return packageNames[parts[0]] + } + return false + } + + // Add nodes + for node := range allNodes { + if packagesOnly && !isPackage(node) { + // Skip component nodes when packages-only is enabled + continue + } + + n := g.Node(node) + + // Style nodes based on type + if isPackage(node) { + // Package node + n.Attr("shape", "box") + n.Attr("style", "rounded,filled") + n.Attr("fillcolor", "lightblue") + n.Attr("label", node) + } else { + // Component node + n.Attr("shape", "box") + n.Attr("style", "rounded,filled") + n.Attr("fillcolor", "lightyellow") + // Extract component name (part after last dot) + parts := strings.Split(node, ".") + if len(parts) > 0 { + n.Attr("label", parts[len(parts)-1]) + } else { + n.Attr("label", node) + } + } + } + + // Add edges + for source, targets := range graph { + if packagesOnly && !isPackage(source) { + // Skip component edges when packages-only is enabled + continue + } + + for _, target := range targets { + if packagesOnly && !isPackage(target) { + // Skip component edges when packages-only is enabled + continue + } + + // Check if target exists + targetExists := allNodes[target] + + // Determine edge type for coloring + sourceIsPackage := isPackage(source) + targetIsPackage := isPackage(target) + + // Add edge + edge := g.Edge(g.Node(source), g.Node(target)) + + // Set edge color based on type (if target exists) + if targetExists { + if sourceIsPackage && targetIsPackage { + // Package -> Package: black (default) + edge.Attr("color", "black") + } else { + // Component -> Package or Component -> Component: green + edge.Attr("color", "green") + } + } + + // If target doesn't exist, mark it as missing (red color) + if !targetExists { + edge.Attr("color", "red") + edge.Attr("style", "dashed") + + // Also add the missing node with red color + missingNode := g.Node(target) + missingNode.Attr("shape", "box") + missingNode.Attr("style", "rounded,filled,dashed") + missingNode.Attr("fillcolor", "lightcoral") + + // Determine label based on node type + if isPackage(target) { + // Package node + missingNode.Attr("label", target) + } else { + // Component node - extract component name + parts := strings.Split(target, ".") + if len(parts) > 0 { + missingNode.Attr("label", parts[len(parts)-1]) + } else { + missingNode.Attr("label", target) + } + } + } else { + // Check if this edge has variant information (dependency not in all variants) + edgeKey := fmt.Sprintf("%s->%s", source, target) + if variants, hasVariants := edgeVariants[edgeKey]; hasVariants { + // Add label with variant names + edge.Attr("label", strings.Join(variants, ",")) + } + } + } + } + + return g +} diff --git a/cmd/cozypkg/cmd/list.go b/cmd/cozypkg/cmd/list.go new file mode 100644 index 00000000..6f737502 --- /dev/null +++ b/cmd/cozypkg/cmd/list.go @@ -0,0 +1,220 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "context" + "fmt" + "os" + "strings" + "text/tabwriter" + + "github.com/spf13/cobra" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + _ "k8s.io/client-go/plugin/pkg/client/auth" +) + +var listCmdFlags struct { + installed bool + components bool + kubeconfig string +} + +var listCmd = &cobra.Command{ + Use: "list", + Short: "List PackageSource or Package resources", + Long: `List PackageSource or Package resources in table format. + +By default, lists PackageSource resources. Use --installed flag to list installed Package resources. +Use --components flag to show components on separate lines.`, + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + // Create Kubernetes client config + var config *rest.Config + var err error + + if listCmdFlags.kubeconfig != "" { + config, err = clientcmd.BuildConfigFromFlags("", listCmdFlags.kubeconfig) + if err != nil { + return fmt.Errorf("failed to load kubeconfig from %s: %w", listCmdFlags.kubeconfig, err) + } + } else { + config, err = ctrl.GetConfig() + if err != nil { + return fmt.Errorf("failed to get kubeconfig: %w", err) + } + } + + scheme := runtime.NewScheme() + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(cozyv1alpha1.AddToScheme(scheme)) + + k8sClient, err := client.New(config, client.Options{Scheme: scheme}) + if err != nil { + return fmt.Errorf("failed to create k8s client: %w", err) + } + + if listCmdFlags.installed { + return listPackages(ctx, k8sClient, listCmdFlags.components) + } + return listPackageSources(ctx, k8sClient, listCmdFlags.components) + }, +} + +func listPackageSources(ctx context.Context, k8sClient client.Client, showComponents bool) error { + var psList cozyv1alpha1.PackageSourceList + if err := k8sClient.List(ctx, &psList); err != nil { + return fmt.Errorf("failed to list PackageSources: %w", err) + } + + // Use tabwriter for better column alignment + w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0) + defer w.Flush() + + // Print header + fmt.Fprintln(w, "NAME\tVARIANTS\tREADY\tSTATUS") + + // Print rows + for _, ps := range psList.Items { + // Get variants + var variants []string + for _, variant := range ps.Spec.Variants { + variants = append(variants, variant.Name) + } + variantsStr := strings.Join(variants, ",") + if len(variantsStr) > 28 { + variantsStr = variantsStr[:25] + "..." + } + + // Get Ready condition + ready := "Unknown" + status := "" + for _, condition := range ps.Status.Conditions { + if condition.Type == "Ready" { + ready = string(condition.Status) + status = condition.Message + if len(status) > 48 { + status = status[:45] + "..." + } + break + } + } + + fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", ps.Name, variantsStr, ready, status) + + // Show components if requested + if showComponents { + for _, variant := range ps.Spec.Variants { + for _, component := range variant.Components { + fmt.Fprintf(w, " %s\t%s\t\t\n", + fmt.Sprintf("%s.%s", ps.Name, component.Name), + variant.Name) + } + } + } + } + + return nil +} + +func listPackages(ctx context.Context, k8sClient client.Client, showComponents bool) error { + var pkgList cozyv1alpha1.PackageList + if err := k8sClient.List(ctx, &pkgList); err != nil { + return fmt.Errorf("failed to list Packages: %w", err) + } + + // Fetch all PackageSource resources once if components are requested + var psMap map[string]*cozyv1alpha1.PackageSource + if showComponents { + var psList cozyv1alpha1.PackageSourceList + if err := k8sClient.List(ctx, &psList); err != nil { + return fmt.Errorf("failed to list PackageSources: %w", err) + } + psMap = make(map[string]*cozyv1alpha1.PackageSource) + for i := range psList.Items { + psMap[psList.Items[i].Name] = &psList.Items[i] + } + } + + // Use tabwriter for better column alignment + w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0) + defer w.Flush() + + // Print header + fmt.Fprintln(w, "NAME\tVARIANT\tREADY\tSTATUS") + + // Print rows + for _, pkg := range pkgList.Items { + variant := pkg.Spec.Variant + if variant == "" { + variant = "default" + } + + // Get Ready condition + ready := "Unknown" + status := "" + for _, condition := range pkg.Status.Conditions { + if condition.Type == "Ready" { + ready = string(condition.Status) + status = condition.Message + if len(status) > 48 { + status = status[:45] + "..." + } + break + } + } + + fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", pkg.Name, variant, ready, status) + + // Show components if requested + if showComponents { + // Look up PackageSource from map instead of making API call + if ps, exists := psMap[pkg.Name]; exists { + // Find the variant + for _, v := range ps.Spec.Variants { + if v.Name == variant { + for _, component := range v.Components { + fmt.Fprintf(w, " %s\t%s\t\t\n", + fmt.Sprintf("%s.%s", pkg.Name, component.Name), + variant) + } + break + } + } + } + } + } + + return nil +} + +func init() { + rootCmd.AddCommand(listCmd) + listCmd.Flags().BoolVarP(&listCmdFlags.installed, "installed", "i", false, "list installed Package resources instead of PackageSource resources") + listCmd.Flags().BoolVar(&listCmdFlags.components, "components", false, "show components on separate lines") + listCmd.Flags().StringVar(&listCmdFlags.kubeconfig, "kubeconfig", "", "Path to kubeconfig file (defaults to ~/.kube/config or KUBECONFIG env var)") +} + diff --git a/cmd/cozypkg/cmd/root.go b/cmd/cozypkg/cmd/root.go new file mode 100644 index 00000000..69b0ea6d --- /dev/null +++ b/cmd/cozypkg/cmd/root.go @@ -0,0 +1,52 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +// Version is set at build time via -ldflags. +var Version = "dev" + +// rootCmd represents the base command when called without any subcommands. +var rootCmd = &cobra.Command{ + Use: "cozypkg", + Short: "A CLI for managing Cozystack packages", + Long: ``, + SilenceErrors: true, + SilenceUsage: true, + DisableAutoGenTag: true, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() error { + if err := rootCmd.Execute(); err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + return err + } + return nil +} + +func init() { + rootCmd.Version = Version +} + diff --git a/cmd/cozypkg/main.go b/cmd/cozypkg/main.go new file mode 100644 index 00000000..7f6b9ead --- /dev/null +++ b/cmd/cozypkg/main.go @@ -0,0 +1,30 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "os" + + "github.com/cozystack/cozystack/cmd/cozypkg/cmd" +) + +func main() { + if err := cmd.Execute(); err != nil { + os.Exit(1) + } +} + diff --git a/cmd/cozystack-api/main.go b/cmd/cozystack-api/main.go index b78edcb0..7fe0a1bb 100644 --- a/cmd/cozystack-api/main.go +++ b/cmd/cozystack-api/main.go @@ -26,8 +26,8 @@ import ( func main() { ctx := genericapiserver.SetupSignalContext() - options := server.NewAppsServerOptions(os.Stdout, os.Stderr) - cmd := server.NewCommandStartAppsServer(ctx, options) + options := server.NewCozyServerOptions(os.Stdout, os.Stderr) + cmd := server.NewCommandStartCozyServer(ctx, options) code := cli.Run(cmd) os.Exit(code) } diff --git a/cmd/cozystack-assets-server/main.go b/cmd/cozystack-assets-server/main.go deleted file mode 100644 index 75563712..00000000 --- a/cmd/cozystack-assets-server/main.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "flag" - "log" - "net/http" - "path/filepath" -) - -func main() { - addr := flag.String("address", ":8123", "Address to listen on") - dir := flag.String("dir", "/cozystack/assets", "Directory to serve files from") - flag.Parse() - - absDir, err := filepath.Abs(*dir) - if err != nil { - log.Fatalf("Error getting absolute path for %s: %v", *dir, err) - } - - fs := http.FileServer(http.Dir(absDir)) - http.Handle("/", fs) - - log.Printf("Server starting on %s, serving directory %s", *addr, absDir) - - err = http.ListenAndServe(*addr, nil) - if err != nil { - log.Fatalf("Server failed to start: %v", err) - } -} diff --git a/cmd/cozystack-controller/main.go b/cmd/cozystack-controller/main.go index 3ffc3027..bcaca9c9 100644 --- a/cmd/cozystack-controller/main.go +++ b/cmd/cozystack-controller/main.go @@ -38,9 +38,11 @@ import ( cozystackiov1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" "github.com/cozystack/cozystack/internal/controller" + "github.com/cozystack/cozystack/internal/controller/dashboard" "github.com/cozystack/cozystack/internal/telemetry" helmv2 "github.com/fluxcd/helm-controller/api/v2" + cosiv1alpha1 "sigs.k8s.io/container-object-storage-interface-api/apis/objectstorage/v1alpha1" // +kubebuilder:scaffold:imports ) @@ -53,7 +55,9 @@ func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(cozystackiov1alpha1.AddToScheme(scheme)) + utilruntime.Must(dashboard.AddToScheme(scheme)) utilruntime.Must(helmv2.AddToScheme(scheme)) + utilruntime.Must(cosiv1alpha1.AddToScheme(scheme)) // +kubebuilder:scaffold:scheme } @@ -66,7 +70,6 @@ func main() { var disableTelemetry bool var telemetryEndpoint string var telemetryInterval string - var cozystackVersion string var tlsOpts []func(*tls.Config) flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") @@ -84,8 +87,6 @@ func main() { "Endpoint for sending telemetry data") flag.StringVar(&telemetryInterval, "telemetry-interval", "15m", "Interval between telemetry data collection (e.g. 15m, 1h)") - flag.StringVar(&cozystackVersion, "cozystack-version", "unknown", - "Version of Cozystack") opts := zap.Options{ Development: false, } @@ -101,10 +102,9 @@ func main() { // Configure telemetry telemetryConfig := telemetry.Config{ - Disabled: disableTelemetry, - Endpoint: telemetryEndpoint, - Interval: interval, - CozystackVersion: cozystackVersion, + Disabled: disableTelemetry, + Endpoint: telemetryEndpoint, + Interval: interval, } ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) @@ -150,7 +150,12 @@ func main() { // this setup is not recommended for production. } - mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + // Configure rate limiting for the Kubernetes client + config := ctrl.GetConfigOrDie() + config.QPS = 50.0 // Increased from default 5.0 + config.Burst = 100 // Increased from default 10 + + mgr, err := ctrl.NewManager(config, ctrl.Options{ Scheme: scheme, Metrics: metricsServerOptions, WebhookServer: webhookServer, @@ -190,19 +195,28 @@ func main() { os.Exit(1) } - if err = (&controller.TenantHelmReconciler{ + if err = (&controller.ApplicationDefinitionReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "TenantHelmReconciler") + setupLog.Error(err, "unable to create controller", "controller", "ApplicationDefinitionReconciler") os.Exit(1) } - if err = (&controller.CozystackConfigReconciler{ + if err = (&controller.ApplicationDefinitionHelmReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "CozystackConfigReconciler") + setupLog.Error(err, "unable to create controller", "controller", "ApplicationDefinitionHelmReconciler") + os.Exit(1) + } + + dashboardManager := &dashboard.Manager{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + } + if err = dashboardManager.SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "DashboardReconciler") os.Exit(1) } @@ -231,7 +245,9 @@ func main() { } setupLog.Info("starting manager") - if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + ctx := ctrl.SetupSignalHandler() + dashboardManager.InitializeStaticResources(ctx) + if err := mgr.Start(ctx); err != nil { setupLog.Error(err, "problem running manager") os.Exit(1) } diff --git a/cmd/cozystack-operator/main.go b/cmd/cozystack-operator/main.go new file mode 100644 index 00000000..e215b779 --- /dev/null +++ b/cmd/cozystack-operator/main.go @@ -0,0 +1,653 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "time" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + _ "k8s.io/client-go/plugin/pkg/client/auth" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + helmv2 "github.com/fluxcd/helm-controller/api/v2" + sourcev1 "github.com/fluxcd/source-controller/api/v1" + sourcewatcherv1beta1 "github.com/fluxcd/source-watcher/api/v2/v1beta1" + corev1 "k8s.io/api/core/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + "github.com/cozystack/cozystack/internal/cozyvaluesreplicator" + "github.com/cozystack/cozystack/internal/crdinstall" + "github.com/cozystack/cozystack/internal/fluxinstall" + "github.com/cozystack/cozystack/internal/operator" + "github.com/cozystack/cozystack/internal/telemetry" + // +kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(apiextensionsv1.AddToScheme(scheme)) + utilruntime.Must(cozyv1alpha1.AddToScheme(scheme)) + utilruntime.Must(helmv2.AddToScheme(scheme)) + utilruntime.Must(sourcev1.AddToScheme(scheme)) + utilruntime.Must(sourcewatcherv1beta1.AddToScheme(scheme)) + // +kubebuilder:scaffold:scheme +} + +func main() { + var metricsAddr string + var enableLeaderElection bool + var probeAddr string + var secureMetrics bool + var enableHTTP2 bool + var installCRDs bool + var installFlux bool + var disableTelemetry bool + var telemetryEndpoint string + var telemetryInterval string + var cozyValuesSecretName string + var cozyValuesSecretNamespace string + var cozyValuesNamespaceSelector string + var platformSourceURL string + var platformSourceName string + var platformSourceRef string + + flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") + flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + flag.BoolVar(&enableLeaderElection, "leader-elect", false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.") + flag.BoolVar(&secureMetrics, "metrics-secure", false, + "If set the metrics endpoint is served securely") + flag.BoolVar(&enableHTTP2, "enable-http2", false, + "If set, HTTP/2 will be enabled for the metrics and webhook servers") + flag.BoolVar(&installCRDs, "install-crds", false, "Install Cozystack CRDs before starting reconcile loop") + flag.BoolVar(&installFlux, "install-flux", false, "Install Flux components before starting reconcile loop") + flag.BoolVar(&disableTelemetry, "disable-telemetry", false, + "Disable telemetry collection") + flag.StringVar(&telemetryEndpoint, "telemetry-endpoint", "https://telemetry.cozystack.io", + "Endpoint for sending telemetry data") + flag.StringVar(&telemetryInterval, "telemetry-interval", "15m", + "Interval between telemetry data collection (e.g. 15m, 1h)") + flag.StringVar(&platformSourceURL, "platform-source-url", "", "Platform source URL (oci:// or https://). If specified, generates OCIRepository or GitRepository resource.") + flag.StringVar(&platformSourceName, "platform-source-name", "cozystack-platform", "Name for the generated platform source resource and PackageSource") + flag.StringVar(&platformSourceRef, "platform-source-ref", "", "Reference specification as key=value pairs (e.g., 'branch=main' or 'digest=sha256:...,tag=v1.0'). For OCI: digest, semver, semverFilter, tag. For Git: branch, tag, semver, name, commit.") + flag.StringVar(&cozyValuesSecretName, "cozy-values-secret-name", "cozystack-values", "The name of the secret containing cluster-wide configuration values.") + flag.StringVar(&cozyValuesSecretNamespace, "cozy-values-secret-namespace", "cozy-system", "The namespace of the secret containing cluster-wide configuration values.") + flag.StringVar(&cozyValuesNamespaceSelector, "cozy-values-namespace-selector", "cozystack.io/system=true", "The label selector for namespaces where the cluster-wide configuration values must be replicated.") + + opts := zap.Options{ + Development: true, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + config := ctrl.GetConfigOrDie() + + // Create a direct client (without cache) for pre-start operations + directClient, err := client.New(config, client.Options{Scheme: scheme}) + if err != nil { + setupLog.Error(err, "unable to create direct client") + os.Exit(1) + } + + targetNSSelector, err := labels.Parse(cozyValuesNamespaceSelector) + if err != nil { + setupLog.Error(err, "could not parse namespace label selector") + os.Exit(1) + } + + // Initialize the controller manager + mgr, err := ctrl.NewManager(config, ctrl.Options{ + Scheme: scheme, + Cache: cache.Options{ + ByObject: map[client.Object]cache.ByObject{ + // Cache only Secrets named (in any namespace) + &corev1.Secret{}: { + Field: fields.OneTermEqualSelector("metadata.name", cozyValuesSecretName), + }, + + // Cache only Namespaces that match a label selector + &corev1.Namespace{}: { + Label: targetNSSelector, + }, + }, + }, + Metrics: metricsserver.Options{ + BindAddress: metricsAddr, + SecureServing: secureMetrics, + }, + WebhookServer: webhook.NewServer(webhook.Options{ + Port: 9443, + }), + HealthProbeBindAddress: probeAddr, + LeaderElection: enableLeaderElection, + LeaderElectionID: "cozystack-operator.cozystack.io", + // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily + // when the Manager ends. This requires the binary to immediately end when the + // Manager is stopped, otherwise, setting this significantly speeds up voluntary + // leader transitions as the new leader don't have to wait LeaseDuration time first. + // + // In the default scaffold provided, the program ends immediately after + // the manager stops, so would be fine to enable this option. However, + // if you are doing or is intended to do any operation such as perform cleanups + // after the manager stops then its usage might be unsafe. + // LeaderElectionReleaseOnCancel: true, + }) + if err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + // Set up signal handler early so install phases respect SIGTERM + mgrCtx := ctrl.SetupSignalHandler() + + // Install Cozystack CRDs before starting reconcile loop + if installCRDs { + setupLog.Info("Installing Cozystack CRDs before starting reconcile loop") + installCtx, installCancel := context.WithTimeout(mgrCtx, 2*time.Minute) + defer installCancel() + + if err := crdinstall.Install(installCtx, directClient, crdinstall.WriteEmbeddedManifests); err != nil { + setupLog.Error(err, "failed to install CRDs") + os.Exit(1) + } + setupLog.Info("CRD installation completed successfully") + } + + // Install Flux before starting reconcile loop + if installFlux { + setupLog.Info("Installing Flux components before starting reconcile loop") + installCtx, installCancel := context.WithTimeout(mgrCtx, 5*time.Minute) + defer installCancel() + + // Use direct client for pre-start operations (cache is not ready yet) + if err := fluxinstall.Install(installCtx, directClient, fluxinstall.WriteEmbeddedManifests); err != nil { + setupLog.Error(err, "failed to install Flux") + os.Exit(1) + } + setupLog.Info("Flux installation completed successfully") + } + + // Generate and install platform source resource if specified + if platformSourceURL != "" { + setupLog.Info("Generating platform source resource", "url", platformSourceURL, "name", platformSourceName, "ref", platformSourceRef) + installCtx, installCancel := context.WithTimeout(mgrCtx, 2*time.Minute) + defer installCancel() + + // Use direct client for pre-start operations (cache is not ready yet) + if err := installPlatformSourceResource(installCtx, directClient, platformSourceURL, platformSourceName, platformSourceRef); err != nil { + setupLog.Error(err, "failed to install platform source resource") + os.Exit(1) + } else { + setupLog.Info("Platform source resource installation completed successfully") + } + } + + // Create platform PackageSource when CRDs are managed by the operator and + // a platform source URL is configured. Without a URL there is no Flux source + // resource to reference, so creating a PackageSource would leave a dangling SourceRef. + if installCRDs && platformSourceURL != "" { + sourceRefKind := "OCIRepository" + sourceType, _, err := parsePlatformSourceURL(platformSourceURL) + if err != nil { + setupLog.Error(err, "failed to parse platform source URL for PackageSource") + os.Exit(1) + } + if sourceType == "git" { + sourceRefKind = "GitRepository" + } + setupLog.Info("Creating platform PackageSource", "platformSourceName", platformSourceName) + psCtx, psCancel := context.WithTimeout(mgrCtx, 2*time.Minute) + defer psCancel() + if err := installPlatformPackageSource(psCtx, directClient, platformSourceName, sourceRefKind); err != nil { + setupLog.Error(err, "failed to create platform PackageSource") + os.Exit(1) + } + setupLog.Info("Platform PackageSource creation completed successfully") + } + + // Setup PackageSource reconciler + if err := (&operator.PackageSourceReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "PackageSource") + os.Exit(1) + } + + // Setup Package reconciler + if err := (&operator.PackageReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Package") + os.Exit(1) + } + + // Setup CozyValuesReplicator reconciler + if err := (&cozyvaluesreplicator.SecretReplicatorReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + SourceNamespace: cozyValuesSecretNamespace, + SecretName: cozyValuesSecretName, + TargetNamespaceSelector: targetNSSelector, + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "CozyValuesReplicator") + os.Exit(1) + } + + // +kubebuilder:scaffold:builder + + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up health check") + os.Exit(1) + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up ready check") + os.Exit(1) + } + + // Parse telemetry interval + interval, err := time.ParseDuration(telemetryInterval) + if err != nil { + setupLog.Error(err, "invalid telemetry interval") + os.Exit(1) + } + + // Configure telemetry + telemetryConfig := telemetry.Config{ + Disabled: disableTelemetry, + Endpoint: telemetryEndpoint, + Interval: interval, + } + + // Initialize telemetry collector + // Use APIReader (non-cached) because the manager's cache is filtered + // and doesn't include resources needed for telemetry (e.g., kube-system namespace, nodes, etc.) + collector, err := telemetry.NewOperatorCollector(mgr.GetAPIReader(), &telemetryConfig, config) + if err != nil { + setupLog.V(1).Info("unable to create telemetry collector, telemetry will be disabled", "error", err) + } + + if collector != nil { + if err := mgr.Add(collector); err != nil { + setupLog.V(1).Info("unable to set up telemetry collector, continuing without telemetry", "error", err) + } + } + + setupLog.Info("Starting controller manager") + if err := mgr.Start(mgrCtx); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} + +// installPlatformSourceResource generates and installs a Flux source resource (OCIRepository or GitRepository) +// based on the platform source URL +func installPlatformSourceResource(ctx context.Context, k8sClient client.Client, sourceURL, resourceName, refSpec string) error { + logger := log.FromContext(ctx) + + // Parse the source URL to determine type + sourceType, repoURL, err := parsePlatformSourceURL(sourceURL) + if err != nil { + return fmt.Errorf("failed to parse platform source URL: %w", err) + } + + // Parse reference specification + refMap, err := parseRefSpec(refSpec) + if err != nil { + return fmt.Errorf("failed to parse reference specification: %w", err) + } + + var obj client.Object + switch sourceType { + case "oci": + obj, err = generateOCIRepository(resourceName, repoURL, refMap) + if err != nil { + return fmt.Errorf("failed to generate OCIRepository: %w", err) + } + case "git": + obj, err = generateGitRepository(resourceName, repoURL, refMap) + if err != nil { + return fmt.Errorf("failed to generate GitRepository: %w", err) + } + default: + return fmt.Errorf("unsupported source type: %s (expected oci:// or https://)", sourceType) + } + + // Apply the resource (create or update) + logger.Info("Applying platform source resource", + "apiVersion", obj.GetObjectKind().GroupVersionKind().GroupVersion().String(), + "kind", obj.GetObjectKind().GroupVersionKind().Kind, + "name", obj.GetName(), + "namespace", obj.GetNamespace(), + ) + + existing := obj.DeepCopyObject().(client.Object) + key := client.ObjectKeyFromObject(obj) + + err = k8sClient.Get(ctx, key, existing) + if err != nil { + if client.IgnoreNotFound(err) == nil { + // Resource doesn't exist, create it + if err := k8sClient.Create(ctx, obj); err != nil { + return fmt.Errorf("failed to create resource %s/%s: %w", obj.GetObjectKind().GroupVersionKind().Kind, obj.GetName(), err) + } + logger.Info("Created platform source resource", "kind", obj.GetObjectKind().GroupVersionKind().Kind, "name", obj.GetName()) + } else { + return fmt.Errorf("failed to check if resource exists: %w", err) + } + } else { + // Resource exists, update it + obj.SetResourceVersion(existing.GetResourceVersion()) + if err := k8sClient.Update(ctx, obj); err != nil { + return fmt.Errorf("failed to update resource %s/%s: %w", obj.GetObjectKind().GroupVersionKind().Kind, obj.GetName(), err) + } + logger.Info("Updated platform source resource", "kind", obj.GetObjectKind().GroupVersionKind().Kind, "name", obj.GetName()) + } + + return nil +} + +// parsePlatformSourceURL parses the source URL and returns the source type and repository URL. +// Supports formats: +// - oci://registry.example.com/repo +// - https://github.com/user/repo +// - http://github.com/user/repo +// - ssh://git@github.com/user/repo +func parsePlatformSourceURL(sourceURL string) (sourceType, repoURL string, err error) { + sourceURL = strings.TrimSpace(sourceURL) + + if strings.HasPrefix(sourceURL, "oci://") { + return "oci", sourceURL, nil + } + + if strings.HasPrefix(sourceURL, "https://") || strings.HasPrefix(sourceURL, "http://") || strings.HasPrefix(sourceURL, "ssh://") { + return "git", sourceURL, nil + } + + return "", "", fmt.Errorf("unsupported source URL scheme (expected oci://, https://, http://, or ssh://): %s", sourceURL) +} + +// parseRefSpec parses a reference specification string in the format "key1=value1,key2=value2". +// Returns a map of key-value pairs. +func parseRefSpec(refSpec string) (map[string]string, error) { + result := make(map[string]string) + + refSpec = strings.TrimSpace(refSpec) + if refSpec == "" { + return result, nil + } + + pairs := strings.Split(refSpec, ",") + for _, pair := range pairs { + pair = strings.TrimSpace(pair) + if pair == "" { + continue + } + + // Split on first '=' only to allow '=' in values (e.g., digest=sha256:...) + idx := strings.Index(pair, "=") + if idx == -1 { + return nil, fmt.Errorf("invalid reference specification format: %q (expected key=value)", pair) + } + + key := strings.TrimSpace(pair[:idx]) + value := strings.TrimSpace(pair[idx+1:]) + + if key == "" { + return nil, fmt.Errorf("empty key in reference specification: %q", pair) + } + if value == "" { + return nil, fmt.Errorf("empty value for key %q in reference specification", key) + } + + result[key] = value + } + + return result, nil +} + +// Valid reference keys for OCI repositories +var validOCIRefKeys = map[string]bool{ + "digest": true, + "semver": true, + "semverFilter": true, + "tag": true, +} + +// Valid reference keys for Git repositories +var validGitRefKeys = map[string]bool{ + "branch": true, + "tag": true, + "semver": true, + "name": true, + "commit": true, +} + +// validateOCIRef validates reference keys for OCI repositories +func validateOCIRef(refMap map[string]string) error { + for key := range refMap { + if !validOCIRefKeys[key] { + return fmt.Errorf("invalid OCI reference key %q (valid keys: digest, semver, semverFilter, tag)", key) + } + } + + // Validate digest format if provided + if digest, ok := refMap["digest"]; ok { + if !strings.HasPrefix(digest, "sha256:") { + return fmt.Errorf("digest must be in format 'sha256:', got: %s", digest) + } + } + + return nil +} + +// validateGitRef validates reference keys for Git repositories +func validateGitRef(refMap map[string]string) error { + for key := range refMap { + if !validGitRefKeys[key] { + return fmt.Errorf("invalid Git reference key %q (valid keys: branch, tag, semver, name, commit)", key) + } + } + + // Validate commit format if provided (should be a hex string) + if commit, ok := refMap["commit"]; ok { + if len(commit) < 7 { + return fmt.Errorf("commit SHA should be at least 7 characters, got: %s", commit) + } + for _, c := range commit { + if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { + return fmt.Errorf("commit SHA should be a hexadecimal string, got: %s", commit) + } + } + } + + return nil +} + +// generateOCIRepository creates an OCIRepository resource +func generateOCIRepository(name, repoURL string, refMap map[string]string) (*sourcev1.OCIRepository, error) { + if err := validateOCIRef(refMap); err != nil { + return nil, err + } + + obj := &sourcev1.OCIRepository{ + TypeMeta: metav1.TypeMeta{ + APIVersion: sourcev1.GroupVersion.String(), + Kind: sourcev1.OCIRepositoryKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: "cozy-system", + }, + Spec: sourcev1.OCIRepositorySpec{ + URL: repoURL, + Interval: metav1.Duration{Duration: 5 * time.Minute}, + }, + } + + // Set reference if any ref options are provided + if len(refMap) > 0 { + obj.Spec.Reference = &sourcev1.OCIRepositoryRef{ + Digest: refMap["digest"], + SemVer: refMap["semver"], + SemverFilter: refMap["semverFilter"], + Tag: refMap["tag"], + } + } + + return obj, nil +} + +// generateGitRepository creates a GitRepository resource +func generateGitRepository(name, repoURL string, refMap map[string]string) (*sourcev1.GitRepository, error) { + if err := validateGitRef(refMap); err != nil { + return nil, err + } + + obj := &sourcev1.GitRepository{ + TypeMeta: metav1.TypeMeta{ + APIVersion: sourcev1.GroupVersion.String(), + Kind: sourcev1.GitRepositoryKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: "cozy-system", + }, + Spec: sourcev1.GitRepositorySpec{ + URL: repoURL, + Interval: metav1.Duration{Duration: 5 * time.Minute}, + }, + } + + // Set reference if any ref options are provided + if len(refMap) > 0 { + obj.Spec.Reference = &sourcev1.GitRepositoryRef{ + Branch: refMap["branch"], + Tag: refMap["tag"], + SemVer: refMap["semver"], + Name: refMap["name"], + Commit: refMap["commit"], + } + } + + return obj, nil +} + +// installPlatformPackageSource creates the platform PackageSource resource +// that references the Flux source resource (OCIRepository or GitRepository). +// +// The variant list is intentionally hardcoded here. These are platform-defined +// deployment profiles (not user-extensible), matching what was previously in +// the Helm template. Changes require a new operator build and release. +func installPlatformPackageSource(ctx context.Context, k8sClient client.Client, platformSourceName, sourceRefKind string) error { + logger := log.FromContext(ctx) + + packageSourceName := "cozystack." + platformSourceName + + ps := &cozyv1alpha1.PackageSource{ + TypeMeta: metav1.TypeMeta{ + APIVersion: cozyv1alpha1.GroupVersion.String(), + Kind: "PackageSource", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: packageSourceName, + Annotations: map[string]string{ + "operator.cozystack.io/skip-cozystack-values": "true", + }, + }, + Spec: cozyv1alpha1.PackageSourceSpec{ + SourceRef: &cozyv1alpha1.PackageSourceRef{ + Kind: sourceRefKind, + Name: platformSourceName, + Namespace: "cozy-system", + Path: "/", + }, + }, + } + + variantData := []struct { + name string + valuesFiles []string + }{ + {"default", []string{"values.yaml"}}, + {"isp-full", []string{"values.yaml", "values-isp-full.yaml"}}, + {"isp-hosted", []string{"values.yaml", "values-isp-hosted.yaml"}}, + {"isp-full-generic", []string{"values.yaml", "values-isp-full-generic.yaml"}}, + } + + variants := make([]cozyv1alpha1.Variant, len(variantData)) + for i, v := range variantData { + variants[i] = cozyv1alpha1.Variant{ + Name: v.name, + Components: []cozyv1alpha1.Component{ + { + Name: "platform", + Path: "core/platform", + Install: &cozyv1alpha1.ComponentInstall{ + Namespace: "cozy-system", + ReleaseName: "cozystack-platform", + }, + ValuesFiles: v.valuesFiles, + }, + }, + } + } + ps.Spec.Variants = variants + + logger.Info("Applying platform PackageSource", "name", packageSourceName) + + patchOptions := &client.PatchOptions{ + FieldManager: "cozystack-operator", + Force: func() *bool { b := true; return &b }(), + } + + if err := k8sClient.Patch(ctx, ps, client.Apply, patchOptions); err != nil { + return fmt.Errorf("failed to apply PackageSource %s: %w", packageSourceName, err) + } + + logger.Info("Applied platform PackageSource", "name", packageSourceName) + return nil +} diff --git a/cmd/cozystack-operator/main_test.go b/cmd/cozystack-operator/main_test.go new file mode 100644 index 00000000..a69bc9b5 --- /dev/null +++ b/cmd/cozystack-operator/main_test.go @@ -0,0 +1,574 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "context" + "testing" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +func newTestScheme() *runtime.Scheme { + s := runtime.NewScheme() + _ = cozyv1alpha1.AddToScheme(s) + return s +} + +func TestInstallPlatformPackageSource_Creates(t *testing.T) { + s := newTestScheme() + k8sClient := fake.NewClientBuilder().WithScheme(s).Build() + + err := installPlatformPackageSource(context.Background(), k8sClient, "cozystack-platform", "OCIRepository") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + ps := &cozyv1alpha1.PackageSource{} + if err := k8sClient.Get(context.Background(), client.ObjectKey{Name: "cozystack.cozystack-platform"}, ps); err != nil { + t.Fatalf("PackageSource not found: %v", err) + } + + // Verify name + if ps.Name != "cozystack.cozystack-platform" { + t.Errorf("expected name %q, got %q", "cozystack.cozystack-platform", ps.Name) + } + + // Verify annotation + if ps.Annotations["operator.cozystack.io/skip-cozystack-values"] != "true" { + t.Errorf("expected skip-cozystack-values annotation to be 'true', got %q", ps.Annotations["operator.cozystack.io/skip-cozystack-values"]) + } + + // Verify sourceRef + if ps.Spec.SourceRef == nil { + t.Fatal("expected SourceRef to be set") + } + if ps.Spec.SourceRef.Kind != "OCIRepository" { + t.Errorf("expected sourceRef.kind %q, got %q", "OCIRepository", ps.Spec.SourceRef.Kind) + } + if ps.Spec.SourceRef.Name != "cozystack-platform" { + t.Errorf("expected sourceRef.name %q, got %q", "cozystack-platform", ps.Spec.SourceRef.Name) + } + if ps.Spec.SourceRef.Namespace != "cozy-system" { + t.Errorf("expected sourceRef.namespace %q, got %q", "cozy-system", ps.Spec.SourceRef.Namespace) + } + if ps.Spec.SourceRef.Path != "/" { + t.Errorf("expected sourceRef.path %q, got %q", "/", ps.Spec.SourceRef.Path) + } + + // Verify variants + expectedVariants := []string{"default", "isp-full", "isp-hosted", "isp-full-generic"} + if len(ps.Spec.Variants) != len(expectedVariants) { + t.Fatalf("expected %d variants, got %d", len(expectedVariants), len(ps.Spec.Variants)) + } + for i, name := range expectedVariants { + if ps.Spec.Variants[i].Name != name { + t.Errorf("expected variant[%d].name %q, got %q", i, name, ps.Spec.Variants[i].Name) + } + if len(ps.Spec.Variants[i].Components) != 1 { + t.Errorf("expected variant[%d] to have 1 component, got %d", i, len(ps.Spec.Variants[i].Components)) + } + } +} + +func TestInstallPlatformPackageSource_Updates(t *testing.T) { + s := newTestScheme() + + existing := &cozyv1alpha1.PackageSource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cozystack.cozystack-platform", + ResourceVersion: "1", + Labels: map[string]string{ + "custom-label": "should-be-preserved", + }, + }, + Spec: cozyv1alpha1.PackageSourceSpec{ + SourceRef: &cozyv1alpha1.PackageSourceRef{ + Kind: "OCIRepository", + Name: "old-name", + Namespace: "cozy-system", + }, + }, + } + + k8sClient := fake.NewClientBuilder().WithScheme(s).WithObjects(existing).Build() + + err := installPlatformPackageSource(context.Background(), k8sClient, "cozystack-platform", "OCIRepository") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + ps := &cozyv1alpha1.PackageSource{} + if err := k8sClient.Get(context.Background(), client.ObjectKey{Name: "cozystack.cozystack-platform"}, ps); err != nil { + t.Fatalf("PackageSource not found: %v", err) + } + + // Verify sourceRef was updated + if ps.Spec.SourceRef.Name != "cozystack-platform" { + t.Errorf("expected updated sourceRef.name %q, got %q", "cozystack-platform", ps.Spec.SourceRef.Name) + } + + // Verify all 4 variants are present after update + if len(ps.Spec.Variants) != 4 { + t.Errorf("expected 4 variants after update, got %d", len(ps.Spec.Variants)) + } + + // Verify that labels set by other controllers are preserved (SSA does not overwrite unmanaged fields) + if ps.Labels["custom-label"] != "should-be-preserved" { + t.Errorf("expected custom-label to be preserved, got %q", ps.Labels["custom-label"]) + } +} + +func TestParsePlatformSourceURL(t *testing.T) { + tests := []struct { + name string + url string + wantType string + wantURL string + wantErr bool + }{ + { + name: "OCI URL", + url: "oci://ghcr.io/cozystack/cozystack/cozystack-packages", + wantType: "oci", + wantURL: "oci://ghcr.io/cozystack/cozystack/cozystack-packages", + }, + { + name: "HTTPS URL", + url: "https://github.com/cozystack/cozystack", + wantType: "git", + wantURL: "https://github.com/cozystack/cozystack", + }, + { + name: "SSH URL", + url: "ssh://git@github.com/cozystack/cozystack", + wantType: "git", + wantURL: "ssh://git@github.com/cozystack/cozystack", + }, + { + name: "empty URL", + url: "", + wantErr: true, + }, + { + name: "unsupported scheme", + url: "ftp://example.com/repo", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sourceType, repoURL, err := parsePlatformSourceURL(tt.url) + if tt.wantErr { + if err == nil { + t.Fatalf("expected error for URL %q, got nil", tt.url) + } + return + } + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if sourceType != tt.wantType { + t.Errorf("expected type %q, got %q", tt.wantType, sourceType) + } + if repoURL != tt.wantURL { + t.Errorf("expected URL %q, got %q", tt.wantURL, repoURL) + } + }) + } +} + +func TestInstallPlatformPackageSource_VariantValuesFiles(t *testing.T) { + s := newTestScheme() + k8sClient := fake.NewClientBuilder().WithScheme(s).Build() + + err := installPlatformPackageSource(context.Background(), k8sClient, "cozystack-platform", "OCIRepository") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + ps := &cozyv1alpha1.PackageSource{} + if err := k8sClient.Get(context.Background(), client.ObjectKey{Name: "cozystack.cozystack-platform"}, ps); err != nil { + t.Fatalf("PackageSource not found: %v", err) + } + + expectedValuesFiles := map[string][]string{ + "default": {"values.yaml"}, + "isp-full": {"values.yaml", "values-isp-full.yaml"}, + "isp-hosted": {"values.yaml", "values-isp-hosted.yaml"}, + "isp-full-generic": {"values.yaml", "values-isp-full-generic.yaml"}, + } + + for _, v := range ps.Spec.Variants { + expected, ok := expectedValuesFiles[v.Name] + if !ok { + t.Errorf("unexpected variant %q", v.Name) + continue + } + + if len(v.Components) != 1 { + t.Errorf("variant %q: expected 1 component, got %d", v.Name, len(v.Components)) + continue + } + + comp := v.Components[0] + if comp.Name != "platform" { + t.Errorf("variant %q: expected component name %q, got %q", v.Name, "platform", comp.Name) + } + if comp.Path != "core/platform" { + t.Errorf("variant %q: expected component path %q, got %q", v.Name, "core/platform", comp.Path) + } + if comp.Install == nil { + t.Errorf("variant %q: expected Install to be set", v.Name) + } else { + if comp.Install.Namespace != "cozy-system" { + t.Errorf("variant %q: expected install namespace %q, got %q", v.Name, "cozy-system", comp.Install.Namespace) + } + if comp.Install.ReleaseName != "cozystack-platform" { + t.Errorf("variant %q: expected install releaseName %q, got %q", v.Name, "cozystack-platform", comp.Install.ReleaseName) + } + } + + if len(comp.ValuesFiles) != len(expected) { + t.Errorf("variant %q: expected %d valuesFiles, got %d", v.Name, len(expected), len(comp.ValuesFiles)) + continue + } + for i, f := range expected { + if comp.ValuesFiles[i] != f { + t.Errorf("variant %q: expected valuesFiles[%d] %q, got %q", v.Name, i, f, comp.ValuesFiles[i]) + } + } + } +} + +func TestInstallPlatformPackageSource_CustomName(t *testing.T) { + s := newTestScheme() + k8sClient := fake.NewClientBuilder().WithScheme(s).Build() + + err := installPlatformPackageSource(context.Background(), k8sClient, "custom-source", "OCIRepository") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + ps := &cozyv1alpha1.PackageSource{} + if err := k8sClient.Get(context.Background(), client.ObjectKey{Name: "cozystack.custom-source"}, ps); err != nil { + t.Fatalf("PackageSource not found: %v", err) + } + + if ps.Name != "cozystack.custom-source" { + t.Errorf("expected name %q, got %q", "cozystack.custom-source", ps.Name) + } + if ps.Spec.SourceRef.Name != "custom-source" { + t.Errorf("expected sourceRef.name %q, got %q", "custom-source", ps.Spec.SourceRef.Name) + } +} + +func TestInstallPlatformPackageSource_GitRepository(t *testing.T) { + s := newTestScheme() + k8sClient := fake.NewClientBuilder().WithScheme(s).Build() + + err := installPlatformPackageSource(context.Background(), k8sClient, "my-source", "GitRepository") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + ps := &cozyv1alpha1.PackageSource{} + if err := k8sClient.Get(context.Background(), client.ObjectKey{Name: "cozystack.my-source"}, ps); err != nil { + t.Fatalf("PackageSource not found: %v", err) + } + + if ps.Spec.SourceRef.Kind != "GitRepository" { + t.Errorf("expected sourceRef.kind %q, got %q", "GitRepository", ps.Spec.SourceRef.Kind) + } + if ps.Spec.SourceRef.Name != "my-source" { + t.Errorf("expected sourceRef.name %q, got %q", "my-source", ps.Spec.SourceRef.Name) + } +} + +func TestParseRefSpec(t *testing.T) { + tests := []struct { + name string + input string + want map[string]string + wantErr bool + }{ + { + name: "empty string", + input: "", + want: map[string]string{}, + }, + { + name: "single key-value", + input: "tag=v1.0", + want: map[string]string{"tag": "v1.0"}, + }, + { + name: "multiple key-values", + input: "digest=sha256:abc123,tag=v1.0", + want: map[string]string{"digest": "sha256:abc123", "tag": "v1.0"}, + }, + { + name: "whitespace around pairs", + input: " tag=v1.0 , branch=main ", + want: map[string]string{"tag": "v1.0", "branch": "main"}, + }, + { + name: "equals sign in value", + input: "digest=sha256:abc=123", + want: map[string]string{"digest": "sha256:abc=123"}, + }, + { + name: "missing equals sign", + input: "tag", + wantErr: true, + }, + { + name: "empty key", + input: "=value", + wantErr: true, + }, + { + name: "empty value", + input: "tag=", + wantErr: true, + }, + { + name: "trailing comma", + input: "tag=v1.0,", + want: map[string]string{"tag": "v1.0"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseRefSpec(tt.input) + if tt.wantErr { + if err == nil { + t.Fatalf("expected error for input %q, got nil", tt.input) + } + return + } + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(got) != len(tt.want) { + t.Fatalf("expected %d entries, got %d: %v", len(tt.want), len(got), got) + } + for k, v := range tt.want { + if got[k] != v { + t.Errorf("expected %q=%q, got %q=%q", k, v, k, got[k]) + } + } + }) + } +} + +func TestValidateOCIRef(t *testing.T) { + tests := []struct { + name string + refMap map[string]string + wantErr bool + }{ + { + name: "valid tag", + refMap: map[string]string{"tag": "v1.0"}, + }, + { + name: "valid digest", + refMap: map[string]string{"digest": "sha256:abc123def456"}, + }, + { + name: "valid semver", + refMap: map[string]string{"semver": ">=1.0.0"}, + }, + { + name: "multiple valid keys", + refMap: map[string]string{"tag": "v1.0", "digest": "sha256:abc"}, + }, + { + name: "empty map", + refMap: map[string]string{}, + }, + { + name: "invalid key", + refMap: map[string]string{"branch": "main"}, + wantErr: true, + }, + { + name: "invalid digest format", + refMap: map[string]string{"digest": "md5:abc"}, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := validateOCIRef(tt.refMap) + if tt.wantErr && err == nil { + t.Fatal("expected error, got nil") + } + if !tt.wantErr && err != nil { + t.Fatalf("unexpected error: %v", err) + } + }) + } +} + +func TestValidateGitRef(t *testing.T) { + tests := []struct { + name string + refMap map[string]string + wantErr bool + }{ + { + name: "valid branch", + refMap: map[string]string{"branch": "main"}, + }, + { + name: "valid commit", + refMap: map[string]string{"commit": "abc1234"}, + }, + { + name: "valid tag and branch", + refMap: map[string]string{"tag": "v1.0", "branch": "release"}, + }, + { + name: "empty map", + refMap: map[string]string{}, + }, + { + name: "invalid key", + refMap: map[string]string{"digest": "sha256:abc"}, + wantErr: true, + }, + { + name: "commit too short", + refMap: map[string]string{"commit": "abc"}, + wantErr: true, + }, + { + name: "commit not hex", + refMap: map[string]string{"commit": "zzzzzzz"}, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := validateGitRef(tt.refMap) + if tt.wantErr && err == nil { + t.Fatal("expected error, got nil") + } + if !tt.wantErr && err != nil { + t.Fatalf("unexpected error: %v", err) + } + }) + } +} + +func TestGenerateOCIRepository(t *testing.T) { + refMap := map[string]string{"tag": "v1.0", "digest": "sha256:abc123"} + obj, err := generateOCIRepository("my-repo", "oci://registry.example.com/repo", refMap) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if obj.Name != "my-repo" { + t.Errorf("expected name %q, got %q", "my-repo", obj.Name) + } + if obj.Namespace != "cozy-system" { + t.Errorf("expected namespace %q, got %q", "cozy-system", obj.Namespace) + } + if obj.Spec.URL != "oci://registry.example.com/repo" { + t.Errorf("expected URL %q, got %q", "oci://registry.example.com/repo", obj.Spec.URL) + } + if obj.Spec.Reference == nil { + t.Fatal("expected Reference to be set") + } + if obj.Spec.Reference.Tag != "v1.0" { + t.Errorf("expected tag %q, got %q", "v1.0", obj.Spec.Reference.Tag) + } + if obj.Spec.Reference.Digest != "sha256:abc123" { + t.Errorf("expected digest %q, got %q", "sha256:abc123", obj.Spec.Reference.Digest) + } +} + +func TestGenerateOCIRepository_NoRef(t *testing.T) { + obj, err := generateOCIRepository("my-repo", "oci://registry.example.com/repo", map[string]string{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if obj.Spec.Reference != nil { + t.Error("expected Reference to be nil for empty refMap") + } +} + +func TestGenerateOCIRepository_InvalidRef(t *testing.T) { + _, err := generateOCIRepository("my-repo", "oci://registry.example.com/repo", map[string]string{"branch": "main"}) + if err == nil { + t.Fatal("expected error for invalid OCI ref key, got nil") + } +} + +func TestGenerateGitRepository(t *testing.T) { + refMap := map[string]string{"branch": "main", "commit": "abc1234def5678"} + obj, err := generateGitRepository("my-repo", "https://github.com/user/repo", refMap) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if obj.Name != "my-repo" { + t.Errorf("expected name %q, got %q", "my-repo", obj.Name) + } + if obj.Namespace != "cozy-system" { + t.Errorf("expected namespace %q, got %q", "cozy-system", obj.Namespace) + } + if obj.Spec.URL != "https://github.com/user/repo" { + t.Errorf("expected URL %q, got %q", "https://github.com/user/repo", obj.Spec.URL) + } + if obj.Spec.Reference == nil { + t.Fatal("expected Reference to be set") + } + if obj.Spec.Reference.Branch != "main" { + t.Errorf("expected branch %q, got %q", "main", obj.Spec.Reference.Branch) + } + if obj.Spec.Reference.Commit != "abc1234def5678" { + t.Errorf("expected commit %q, got %q", "abc1234def5678", obj.Spec.Reference.Commit) + } +} + +func TestGenerateGitRepository_NoRef(t *testing.T) { + obj, err := generateGitRepository("my-repo", "https://github.com/user/repo", map[string]string{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if obj.Spec.Reference != nil { + t.Error("expected Reference to be nil for empty refMap") + } +} + +func TestGenerateGitRepository_InvalidRef(t *testing.T) { + _, err := generateGitRepository("my-repo", "https://github.com/user/repo", map[string]string{"digest": "sha256:abc"}) + if err == nil { + t.Fatal("expected error for invalid Git ref key, got nil") + } +} diff --git a/cmd/flux-plunger/main.go b/cmd/flux-plunger/main.go new file mode 100644 index 00000000..13fe88cd --- /dev/null +++ b/cmd/flux-plunger/main.go @@ -0,0 +1,151 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "crypto/tls" + "flag" + "os" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + _ "k8s.io/client-go/plugin/pkg/client/auth" + + helmv2 "github.com/fluxcd/helm-controller/api/v2" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + + "github.com/cozystack/cozystack/internal/controller/fluxplunger" + // +kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(helmv2.AddToScheme(scheme)) + + // +kubebuilder:scaffold:scheme +} + +func main() { + var metricsAddr string + var enableLeaderElection bool + var probeAddr string + var secureMetrics bool + var enableHTTP2 bool + var tlsOpts []func(*tls.Config) + + flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ + "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") + flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + flag.BoolVar(&enableLeaderElection, "leader-elect", false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.") + flag.BoolVar(&secureMetrics, "metrics-secure", true, + "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.") + flag.BoolVar(&enableHTTP2, "enable-http2", false, + "If set, HTTP/2 will be enabled for the metrics server") + + opts := zap.Options{ + Development: false, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + // if the enable-http2 flag is false (the default), http/2 should be disabled + // due to its vulnerabilities. More specifically, disabling http/2 will + // prevent from being vulnerable to the HTTP/2 Stream Cancellation and + // Rapid Reset CVEs. For more information see: + // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3 + // - https://github.com/advisories/GHSA-4374-p667-p6c8 + disableHTTP2 := func(c *tls.Config) { + setupLog.Info("disabling http/2") + c.NextProtos = []string{"http/1.1"} + } + + if !enableHTTP2 { + tlsOpts = append(tlsOpts, disableHTTP2) + } + + // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server. + // More info: + // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/server + // - https://book.kubebuilder.io/reference/metrics.html + metricsServerOptions := metricsserver.Options{ + BindAddress: metricsAddr, + SecureServing: secureMetrics, + TLSOpts: tlsOpts, + } + + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, + Metrics: metricsServerOptions, + HealthProbeBindAddress: probeAddr, + LeaderElection: enableLeaderElection, + LeaderElectionID: "flux-plunger.cozystack.io", + // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily + // when the Manager ends. This requires the binary to immediately end when the + // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly + // speeds up voluntary leader transitions as the new leader don't have to wait + // LeaseDuration time first. + // + // In the default scaffold provided, the program ends immediately after + // the manager stops, so would be fine to enable this option. However, + // if you are doing or is intended to do any operation such as perform cleanups + // after the manager stops then its usage might be unsafe. + // LeaderElectionReleaseOnCancel: true, + }) + if err != nil { + setupLog.Error(err, "unable to create manager") + os.Exit(1) + } + + if err = (&fluxplunger.FluxPlunger{ + Client: mgr.GetClient(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "FluxPlunger") + os.Exit(1) + } + + // +kubebuilder:scaffold:builder + + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up health check") + os.Exit(1) + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up ready check") + os.Exit(1) + } + + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/cmd/kubeovn-plunger/main.go b/cmd/kubeovn-plunger/main.go new file mode 100644 index 00000000..611d030b --- /dev/null +++ b/cmd/kubeovn-plunger/main.go @@ -0,0 +1,182 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "crypto/tls" + "flag" + "os" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + _ "k8s.io/client-go/plugin/pkg/client/auth" + + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/metrics" + "sigs.k8s.io/controller-runtime/pkg/metrics/filters" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + "github.com/cozystack/cozystack/internal/controller/kubeovnplunger" + // +kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + // +kubebuilder:scaffold:scheme +} + +func main() { + var metricsAddr string + var enableLeaderElection bool + var probeAddr string + var kubeOVNNamespace string + var ovnCentralName string + var secureMetrics bool + var enableHTTP2 bool + var disableTelemetry bool + var tlsOpts []func(*tls.Config) + flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ + "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") + flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + flag.StringVar(&kubeOVNNamespace, "kube-ovn-namespace", "cozy-kubeovn", "Namespace where kube-OVN is deployed.") + flag.StringVar(&ovnCentralName, "ovn-central-name", "ovn-central", "Ovn-central deployment name.") + flag.BoolVar(&enableLeaderElection, "leader-elect", false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.") + flag.BoolVar(&secureMetrics, "metrics-secure", true, + "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.") + flag.BoolVar(&enableHTTP2, "enable-http2", false, + "If set, HTTP/2 will be enabled for the metrics and webhook servers") + flag.BoolVar(&disableTelemetry, "disable-telemetry", false, + "Disable telemetry collection") + opts := zap.Options{ + Development: false, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + // if the enable-http2 flag is false (the default), http/2 should be disabled + // due to its vulnerabilities. More specifically, disabling http/2 will + // prevent from being vulnerable to the HTTP/2 Stream Cancellation and + // Rapid Reset CVEs. For more information see: + // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3 + // - https://github.com/advisories/GHSA-4374-p667-p6c8 + disableHTTP2 := func(c *tls.Config) { + setupLog.Info("disabling http/2") + c.NextProtos = []string{"http/1.1"} + } + + if !enableHTTP2 { + tlsOpts = append(tlsOpts, disableHTTP2) + } + + webhookServer := webhook.NewServer(webhook.Options{ + TLSOpts: tlsOpts, + }) + + // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server. + // More info: + // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/server + // - https://book.kubebuilder.io/reference/metrics.html + metricsServerOptions := metricsserver.Options{ + BindAddress: metricsAddr, + SecureServing: secureMetrics, + TLSOpts: tlsOpts, + } + + if secureMetrics { + // FilterProvider is used to protect the metrics endpoint with authn/authz. + // These configurations ensure that only authorized users and service accounts + // can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info: + // https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/filters#WithAuthenticationAndAuthorization + metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization + + // TODO(user): If CertDir, CertName, and KeyName are not specified, controller-runtime will automatically + // generate self-signed certificates for the metrics server. While convenient for development and testing, + // this setup is not recommended for production. + } + + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, + Metrics: metricsServerOptions, + WebhookServer: webhookServer, + HealthProbeBindAddress: probeAddr, + LeaderElection: enableLeaderElection, + LeaderElectionID: "29a0338b.cozystack.io", + Cache: cache.Options{ + DefaultNamespaces: map[string]cache.Config{ + kubeOVNNamespace: {}, + }, + }, + // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily + // when the Manager ends. This requires the binary to immediately end when the + // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly + // speeds up voluntary leader transitions as the new leader don't have to wait + // LeaseDuration time first. + // + // In the default scaffold provided, the program ends immediately after + // the manager stops, so would be fine to enable this option. However, + // if you are doing or is intended to do any operation such as perform cleanups + // after the manager stops then its usage might be unsafe. + // LeaderElectionReleaseOnCancel: true, + }) + if err != nil { + setupLog.Error(err, "unable to create manager") + os.Exit(1) + } + + if err = (&kubeovnplunger.KubeOVNPlunger{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Registry: metrics.Registry, + }).SetupWithManager(mgr, kubeOVNNamespace, ovnCentralName); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "KubeOVNPlunger") + os.Exit(1) + } + + // +kubebuilder:scaffold:builder + + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up health check") + os.Exit(1) + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up ready check") + os.Exit(1) + } + + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/cmd/lineage-controller-webhook/main.go b/cmd/lineage-controller-webhook/main.go new file mode 100644 index 00000000..ffe0942b --- /dev/null +++ b/cmd/lineage-controller-webhook/main.go @@ -0,0 +1,179 @@ +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "crypto/tls" + "flag" + "os" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + _ "k8s.io/client-go/plugin/pkg/client/auth" + + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/metrics/filters" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + cozystackiov1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + lcw "github.com/cozystack/cozystack/internal/lineagecontrollerwebhook" + // +kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + utilruntime.Must(cozystackiov1alpha1.AddToScheme(scheme)) + // +kubebuilder:scaffold:scheme +} + +func main() { + var metricsAddr string + var enableLeaderElection bool + var probeAddr string + var secureMetrics bool + var enableHTTP2 bool + var tlsOpts []func(*tls.Config) + flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ + "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") + flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") + flag.BoolVar(&enableLeaderElection, "leader-elect", false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.") + flag.BoolVar(&secureMetrics, "metrics-secure", true, + "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.") + flag.BoolVar(&enableHTTP2, "enable-http2", false, + "If set, HTTP/2 will be enabled for the metrics and webhook servers") + opts := zap.Options{ + Development: false, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + // if the enable-http2 flag is false (the default), http/2 should be disabled + // due to its vulnerabilities. More specifically, disabling http/2 will + // prevent from being vulnerable to the HTTP/2 Stream Cancellation and + // Rapid Reset CVEs. For more information see: + // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3 + // - https://github.com/advisories/GHSA-4374-p667-p6c8 + disableHTTP2 := func(c *tls.Config) { + setupLog.Info("disabling http/2") + c.NextProtos = []string{"http/1.1"} + } + + if !enableHTTP2 { + tlsOpts = append(tlsOpts, disableHTTP2) + } + + webhookServer := webhook.NewServer(webhook.Options{ + TLSOpts: tlsOpts, + }) + + // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server. + // More info: + // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/server + // - https://book.kubebuilder.io/reference/metrics.html + metricsServerOptions := metricsserver.Options{ + BindAddress: metricsAddr, + SecureServing: secureMetrics, + TLSOpts: tlsOpts, + } + + if secureMetrics { + // FilterProvider is used to protect the metrics endpoint with authn/authz. + // These configurations ensure that only authorized users and service accounts + // can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info: + // https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/metrics/filters#WithAuthenticationAndAuthorization + metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization + + // TODO(user): If CertDir, CertName, and KeyName are not specified, controller-runtime will automatically + // generate self-signed certificates for the metrics server. While convenient for development and testing, + // this setup is not recommended for production. + } + + // Configure rate limiting for the Kubernetes client + config := ctrl.GetConfigOrDie() + config.QPS = 50.0 // Increased from default 5.0 + config.Burst = 100 // Increased from default 10 + + mgr, err := ctrl.NewManager(config, ctrl.Options{ + Scheme: scheme, + Metrics: metricsServerOptions, + WebhookServer: webhookServer, + HealthProbeBindAddress: probeAddr, + LeaderElection: enableLeaderElection, + LeaderElectionID: "8796f12d.cozystack.io", + // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily + // when the Manager ends. This requires the binary to immediately end when the + // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly + // speeds up voluntary leader transitions as the new leader don't have to wait + // LeaseDuration time first. + // + // In the default scaffold provided, the program ends immediately after + // the manager stops, so would be fine to enable this option. However, + // if you are doing or is intended to do any operation such as perform cleanups + // after the manager stops then its usage might be unsafe. + // LeaderElectionReleaseOnCancel: true, + }) + if err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + lineageControllerWebhook := &lcw.LineageControllerWebhook{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + } + if err := lineageControllerWebhook.SetupWithManagerAsController(mgr); err != nil { + setupLog.Error(err, "unable to setup controller", "controller", "LineageController") + os.Exit(1) + } + if err := lineageControllerWebhook.SetupWithManagerAsWebhook(mgr); err != nil { + setupLog.Error(err, "unable to setup webhook", "webhook", "LineageWebhook") + os.Exit(1) + } + + // +kubebuilder:scaffold:builder + + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up health check") + os.Exit(1) + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up ready check") + os.Exit(1) + } + + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/dashboards/gpu/gpu-efficiency.json b/dashboards/gpu/gpu-efficiency.json new file mode 100644 index 00000000..28a24568 --- /dev/null +++ b/dashboards/gpu/gpu-efficiency.json @@ -0,0 +1,819 @@ +{ + "uid": "gpu-efficiency", + "title": "GPU Efficiency Score", + "description": "Tensor saturation, util/watt and throttling — reveals inefficient GPU workloads", + "tags": [ + "gpu", + "efficiency", + "finops" + ], + "timezone": "browser", + "editable": true, + "graphTooltip": 1, + "time": { + "from": "now-1h", + "to": "now" + }, + "fiscalYearStartMonth": 0, + "schemaVersion": 42, + "panels": [ + { + "type": "row", + "collapsed": false, + "title": "Overall efficiency metrics", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "panels": [] + }, + { + "type": "stat", + "id": 2, + "targets": [ + { + "expr": "avg(gpu:tensor_saturation:avg5m) * 100", + "refId": "A" + } + ], + "title": "Avg Tensor Saturation", + "description": "Mean tensor core saturation across all GPUs. \u003c10% means GPUs are used inefficiently (workloads could move to CPU or optimize their code). Cluster-wide — DCGM metrics cannot be attributed to workload namespaces.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "area", + "colorMode": "background", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "red" + }, + { + "value": 10, + "color": "orange" + }, + { + "value": 30, + "color": "yellow" + }, + { + "value": 60, + "color": "green" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 3, + "targets": [ + { + "expr": "avg(gpu:util_per_watt:avg5m)", + "refId": "A" + } + ], + "title": "Avg Utilization per Watt", + "description": "NVML utilization % per watt across all GPUs. Higher value = more efficient workload. Cluster-wide — DCGM metrics cannot be attributed to workload namespaces.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "area", + "colorMode": "background", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "none", + "decimals": 3, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "red" + }, + { + "value": 0.5, + "color": "yellow" + }, + { + "value": 1, + "color": "green" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 4, + "targets": [ + { + "expr": "avg(gpu:power_throttle_fraction:rate5m)", + "refId": "A" + } + ], + "title": "Avg Power Throttling", + "description": "Fraction of time GPUs hit the TDP cap and lose performance. \u003e5% means tenants underutilize billed FLOPS. Cluster-wide — rule aggregates by (Hostname, gpu, UUID) and drops namespace label.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "area", + "colorMode": "background", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "percentunit", + "decimals": 2, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 0.05, + "color": "yellow" + }, + { + "value": 0.2, + "color": "red" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "row", + "collapsed": false, + "title": "NVML vs Tensor (mismatch detector)", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 10, + "panels": [] + }, + { + "type": "timeseries", + "id": 11, + "targets": [ + { + "expr": "DCGM_FI_DEV_GPU_UTIL", + "legendFormat": "{{Hostname}}/{{gpu}}", + "refId": "A" + } + ], + "title": "NVML GPU Utilization", + "description": "Classic utilization metric. Shows activity of any engine (SM, copy, encoder). Cluster-wide — DCGM namespace is the exporter's own namespace, not the workload namespace.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 7 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 10, + "showPoints": "never" + } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "id": 12, + "targets": [ + { + "expr": "DCGM_FI_PROF_PIPE_TENSOR_ACTIVE * 100", + "legendFormat": "{{Hostname}}/{{gpu}}", + "refId": "A" + } + ], + "title": "Tensor Pipe Active", + "description": "Real tensor core load (HMMA). For AI/LLM inference it should be ≥20%, otherwise the workload is unoptimized. Cluster-wide — DCGM namespace is the exporter's own namespace, not the workload namespace.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 7 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 10, + "showPoints": "never" + } + }, + "overrides": [] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Per-GPU ranking", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 20, + "panels": [] + }, + { + "type": "table", + "id": 21, + "targets": [ + { + "expr": "topk(20, gpu:tensor_saturation:avg5m * 100)", + "instant": true, + "range": false, + "format": "table", + "refId": "A" + } + ], + "title": "Tensor Saturation per GPU (5m avg)", + "description": "Which GPUs are exercising tensor cores and which are not. Sorted descending. Grouped by Hostname/gpu/UUID — DCGM metrics cannot be attributed to workload namespaces.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "repeatDirection": "h", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "DCGM_FI_DRIVER_VERSION": true, + "Time": true, + "__name__": true, + "cluster": true, + "container": true, + "device": true, + "endpoint": true, + "gpu_driver_version": true, + "instance": true, + "job": true, + "modelName": true, + "namespace": true, + "pci_bus_id": true, + "pod": true, + "prometheus": true, + "service": true, + "tenant": true, + "tier": true, + "uid": true, + "unit": true + }, + "indexByName": { + "Hostname": 0, + "UUID": 2, + "Value": 3, + "gpu": 1 + }, + "renameByName": { + "Hostname": "Node", + "UUID": "UUID", + "Value": "Saturation", + "gpu": "GPU" + } + } + } + ], + "options": { + "frameIndex": 0, + "showHeader": true, + "showTypeIcons": false, + "sortBy": [ + { + "displayName": "Saturation", + "desc": true + } + ], + "footer": { + "show": false, + "reducer": [] + }, + "cellHeight": "sm" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Saturation" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + }, + { + "id": "min", + "value": 0 + }, + { + "id": "max", + "value": 100 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "red" + }, + { + "color": "orange", + "value": 10 + }, + { + "color": "yellow", + "value": 30 + }, + { + "color": "green", + "value": 60 + } + ] + } + } + ] + } + ] + } + }, + { + "type": "table", + "id": 22, + "targets": [ + { + "expr": "topk(20, gpu:util_per_watt:avg5m)", + "instant": true, + "range": false, + "format": "table", + "refId": "A" + } + ], + "title": "Utilization / Watt per GPU (5m avg)", + "description": "How efficiently each GPU spends watts. Low value = poor optimization. Grouped by Hostname/gpu/UUID — DCGM metrics cannot be attributed to workload namespaces.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 16 + }, + "repeatDirection": "h", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "DCGM_FI_DRIVER_VERSION": true, + "Time": true, + "__name__": true, + "cluster": true, + "container": true, + "device": true, + "endpoint": true, + "gpu_driver_version": true, + "instance": true, + "job": true, + "modelName": true, + "namespace": true, + "pci_bus_id": true, + "pod": true, + "prometheus": true, + "service": true, + "tenant": true, + "tier": true, + "uid": true, + "unit": true + }, + "indexByName": { + "Hostname": 0, + "UUID": 2, + "Value": 3, + "gpu": 1 + }, + "renameByName": { + "Hostname": "Node", + "UUID": "UUID", + "Value": "Util/Watt", + "gpu": "GPU" + } + } + } + ], + "options": { + "frameIndex": 0, + "showHeader": true, + "showTypeIcons": false, + "sortBy": [ + { + "displayName": "Util/Watt", + "desc": true + } + ], + "footer": { + "show": false, + "reducer": [] + }, + "cellHeight": "sm" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Util/Watt" + }, + "properties": [ + { + "id": "unit", + "value": "none" + }, + { + "id": "decimals", + "value": 3 + }, + { + "id": "min", + "value": 0 + }, + { + "id": "max", + "value": 1.5 + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "red" + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + } + ] + } + ] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Throttling", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 24 + }, + "id": 30, + "panels": [] + }, + { + "type": "timeseries", + "id": 31, + "targets": [ + { + "expr": "gpu:power_throttle_fraction:rate5m", + "legendFormat": "{{Hostname}}/{{gpu}}", + "refId": "A" + } + ], + "title": "Power throttle fraction per GPU", + "description": "Fraction of time the GPU was power-throttled. 1.0 = always throttled. Cluster-wide — rule aggregates by (Hostname, gpu, UUID) and drops namespace label.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 25 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "percentunit", + "min": 0, + "max": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 0.05, + "color": "yellow" + }, + { + "value": 0.2, + "color": "red" + } + ] + }, + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 25, + "showPoints": "never" + } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "id": 32, + "targets": [ + { + "expr": "gpu:thermal_throttle_fraction:rate5m", + "legendFormat": "{{Hostname}}/{{gpu}}", + "refId": "A" + } + ], + "title": "Thermal throttle fraction per GPU", + "description": "Fraction of time the GPU was thermal-throttled. Cluster-wide — rule aggregates by (Hostname, gpu, UUID) and drops namespace label.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 25 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "percentunit", + "min": 0, + "max": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 0.05, + "color": "yellow" + }, + { + "value": 0.2, + "color": "red" + } + ] + }, + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 25, + "showPoints": "never" + } + }, + "overrides": [] + } + } + ], + "templating": { + "list": [ + { + "type": "datasource", + "name": "ds_prometheus", + "label": "Prometheus", + "skipUrlSync": false, + "query": "prometheus", + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "multi": false, + "allowCustomValue": true, + "includeAll": false, + "regex": "", + "auto": false, + "auto_min": "10s", + "auto_count": 30 + } + ] + }, + "annotations": {} +} diff --git a/dashboards/gpu/gpu-fleet.json b/dashboards/gpu/gpu-fleet.json new file mode 100644 index 00000000..60c12bfb --- /dev/null +++ b/dashboards/gpu/gpu-fleet.json @@ -0,0 +1,1157 @@ +{ + "uid": "gpu-fleet", + "title": "GPU Fleet Overview", + "description": "Cluster-wide GPU inventory, capacity, utilization and health — admin view across the whole fleet.", + "tags": [ + "gpu", + "fleet", + "admin" + ], + "timezone": "browser", + "editable": true, + "graphTooltip": 1, + "time": { + "from": "now-6h", + "to": "now" + }, + "fiscalYearStartMonth": 0, + "schemaVersion": 42, + "panels": [ + { + "type": "row", + "collapsed": false, + "title": "Cluster snapshot", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "panels": [] + }, + { + "type": "stat", + "id": 2, + "targets": [ + { + "expr": "cluster:gpu_count:total", + "refId": "A" + } + ], + "title": "Total GPUs", + "description": "Physical GPUs discovered by DCGM across all nodes.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "value", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "blue" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 3, + "targets": [ + { + "expr": "cluster:gpu_count:allocated", + "refId": "A" + } + ], + "title": "Allocated", + "description": "Sum of kube GPU requests across all pods. Billable view — includes Pending pods.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "background", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "blue" + }, + { + "value": 1, + "color": "green" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 4, + "targets": [ + { + "expr": "cluster:gpu_count:free", + "refId": "A" + } + ], + "title": "Free", + "description": "Unallocated capacity available for new tenants.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "background", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "red" + }, + { + "value": 1, + "color": "yellow" + }, + { + "value": 2, + "color": "green" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 5, + "targets": [ + { + "expr": "count(count by (Hostname) (DCGM_FI_DEV_GPU_UTIL))", + "refId": "A" + } + ], + "title": "Nodes with GPU", + "description": "Nodes reporting at least one GPU to DCGM. Counted via DCGM_FI_DEV_GPU_UTIL because kube-state-metrics does not expose node labels by default.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 12, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "value", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "blue" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 6, + "targets": [ + { + "expr": "cluster:gpu_util:avg", + "refId": "A" + } + ], + "title": "Average utilization", + "description": "Legacy NVML utilization across all tenant GPUs.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "area", + "colorMode": "value", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "blue" + }, + { + "value": 30, + "color": "green" + }, + { + "value": 80, + "color": "orange" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 7, + "targets": [ + { + "expr": "cluster:gpu_power_watts:sum", + "refId": "A" + } + ], + "title": "Total power", + "description": "Live power draw summed across the fleet.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "area", + "colorMode": "value", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "watt", + "decimals": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Per-node GPU activity", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 10, + "panels": [] + }, + { + "type": "bargauge", + "id": 11, + "targets": [ + { + "expr": "avg by (Hostname) (DCGM_FI_DEV_GPU_UTIL)", + "legendFormat": "{{Hostname}}", + "refId": "A" + } + ], + "title": "GPU utilization per node", + "description": "Average NVML utilization per node — spot idle or saturated hosts at a glance.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 6 + }, + "repeatDirection": "h", + "options": { + "displayMode": "gradient", + "valueMode": "color", + "namePlacement": "auto", + "showUnfilled": true, + "sizing": "auto", + "minVizWidth": 8, + "minVizHeight": 16, + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false, + "calcs": [] + }, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "maxVizHeight": 300, + "orientation": "horizontal" + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "blue" + }, + { + "value": 30, + "color": "green" + }, + { + "value": 80, + "color": "orange" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "bargauge", + "id": 12, + "targets": [ + { + "expr": "sum by (Hostname) (DCGM_FI_DEV_POWER_USAGE) / clamp_min(sum by (Hostname) (DCGM_FI_DEV_POWER_MGMT_LIMIT), 1) * 100", + "legendFormat": "{{Hostname}}", + "refId": "A" + } + ], + "title": "Power draw per node (% of TDP)", + "description": "GPU power usage as a fraction of the node's combined TDP cap. Works across GPU SKUs without per-model thresholds. Requires DCGM_FI_DEV_POWER_MGMT_LIMIT from custom DCGM CSV (see packages/system/gpu-operator/examples/dcgm-custom-metrics.yaml).", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 6 + }, + "repeatDirection": "h", + "options": { + "displayMode": "gradient", + "valueMode": "color", + "namePlacement": "auto", + "showUnfilled": true, + "sizing": "auto", + "minVizWidth": 8, + "minVizHeight": 16, + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false, + "calcs": [] + }, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "maxVizHeight": 300, + "orientation": "horizontal" + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 60, + "color": "yellow" + }, + { + "value": 80, + "color": "orange" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Usage trends", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 20, + "panels": [] + }, + { + "type": "timeseries", + "id": 21, + "targets": [ + { + "expr": "avg by (Hostname) (DCGM_FI_DEV_GPU_UTIL)", + "legendFormat": "{{Hostname}}", + "refId": "A" + } + ], + "title": "GPU utilization per node (trend)", + "description": "Per-node NVML utilization over time — shows shifting workload across hosts.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 15 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 20, + "showPoints": "never" + } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "id": 22, + "targets": [ + { + "expr": "sum by (Hostname) (DCGM_FI_DEV_POWER_USAGE)", + "legendFormat": "{{Hostname}}", + "refId": "A" + } + ], + "title": "Power draw per node (trend)", + "description": "Per-node GPU power consumption over time.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 15 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "watt", + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 20, + "showPoints": "never" + } + }, + "overrides": [] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Health", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 30, + "panels": [] + }, + { + "type": "stat", + "id": 31, + "targets": [ + { + "expr": "count((max by (Hostname, gpu) (DCGM_FI_DEV_XID_ERRORS)) \u003e 0) or vector(0)", + "refId": "A" + } + ], + "title": "GPUs with XID errors", + "description": "Count of GPUs reporting a non-zero XID code. XID = NVIDIA hardware/driver error — any non-zero value needs investigation.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 24 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "background", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 1, + "color": "red" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 32, + "targets": [ + { + "expr": "avg(gpu:power_throttle_fraction:rate5m)", + "refId": "A" + } + ], + "title": "Power throttling (cluster avg)", + "description": "Fraction of time the fleet spent power-throttled. \u003e5% = billed FLOPS are being underdelivered.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 24 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "background", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "percentunit", + "decimals": 2, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 0.05, + "color": "yellow" + }, + { + "value": 0.2, + "color": "red" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 33, + "targets": [ + { + "expr": "avg(gpu:thermal_throttle_fraction:rate5m)", + "refId": "A" + } + ], + "title": "Thermal throttling (cluster avg)", + "description": "Fraction of time the fleet spent thermal-throttled. Indicates cooling/datacenter issues.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 24 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "background", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "percentunit", + "decimals": 2, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 0.05, + "color": "yellow" + }, + { + "value": 0.2, + "color": "red" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 34, + "targets": [ + { + "expr": "max(DCGM_FI_DEV_GPU_TEMP)", + "refId": "A" + } + ], + "title": "Max GPU temperature", + "description": "Hottest GPU in the fleet right now. Adjust thresholds to match your GPU model specifications.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 24 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "background", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "celsius", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 75, + "color": "yellow" + }, + { + "value": 85, + "color": "red" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "id": 35, + "targets": [ + { + "expr": "DCGM_FI_DEV_GPU_TEMP", + "legendFormat": "{{Hostname}}/{{gpu}}", + "refId": "A" + } + ], + "title": "Temperature per GPU", + "description": "Per-GPU temperature trace. Sustained red zone = cooling issue or aggressive workload.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 29 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "celsius", + "min": 20, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 75, + "color": "yellow" + }, + { + "value": 85, + "color": "red" + } + ] + }, + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 10, + "showPoints": "never" + } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "id": 36, + "targets": [ + { + "expr": "gpu:power_throttle_fraction:rate5m", + "legendFormat": "power {{Hostname}}/{{gpu}}", + "refId": "A" + }, + { + "expr": "gpu:thermal_throttle_fraction:rate5m", + "legendFormat": "thermal {{Hostname}}/{{gpu}}", + "refId": "B" + } + ], + "title": "Throttle fraction per GPU", + "description": "Red = power throttle, blue = thermal throttle. Both on same chart to compare causes.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 29 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "percentunit", + "min": 0, + "max": 1, + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 25, + "showPoints": "never" + } + }, + "overrides": [] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Hardware inventory", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 37 + }, + "id": 40, + "panels": [] + }, + { + "type": "table", + "id": 41, + "targets": [ + { + "expr": "group by (Hostname, modelName, gpu, UUID) (DCGM_FI_DEV_GPU_UTIL)", + "instant": true, + "range": false, + "format": "table", + "refId": "A" + } + ], + "title": "GPU inventory", + "description": "One row per physical GPU. Model / index / UUID sourced from DCGM labels.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 38 + }, + "repeatDirection": "h", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true, + "__name__": true, + "cluster": true, + "container": true, + "device": true, + "endpoint": true, + "instance": true, + "job": true, + "pci_bus_id": true, + "prometheus": true, + "service": true, + "tenant": true, + "tier": true, + "uid": true, + "unit": true + }, + "indexByName": { + "Hostname": 0, + "UUID": 3, + "gpu": 2, + "modelName": 1 + }, + "renameByName": { + "Hostname": "Node", + "UUID": "UUID", + "gpu": "Index", + "modelName": "GPU Model" + } + } + } + ], + "options": { + "frameIndex": 0, + "showHeader": true, + "showTypeIcons": false, + "footer": { + "show": false, + "reducer": [] + }, + "cellHeight": "sm" + } + } + ], + "templating": { + "list": [ + { + "type": "datasource", + "name": "ds_prometheus", + "label": "Prometheus", + "skipUrlSync": false, + "query": "prometheus", + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "multi": false, + "allowCustomValue": true, + "includeAll": false, + "regex": "", + "auto": false, + "auto_min": "10s", + "auto_count": 30 + } + ] + }, + "annotations": {} +} diff --git a/dashboards/gpu/gpu-performance.json b/dashboards/gpu/gpu-performance.json new file mode 100644 index 00000000..aed9c69a --- /dev/null +++ b/dashboards/gpu/gpu-performance.json @@ -0,0 +1,957 @@ +{ + "uid": "gpu-performance", + "title": "GPU Performance", + "tags": [ + "gpu", + "dcgm" + ], + "timezone": "browser", + "editable": true, + "graphTooltip": 1, + "time": { + "from": "now-1h", + "to": "now" + }, + "fiscalYearStartMonth": 0, + "schemaVersion": 42, + "panels": [ + { + "type": "row", + "collapsed": false, + "title": "Overview", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "panels": [] + }, + { + "type": "stat", + "id": 2, + "targets": [ + { + "expr": "cluster:gpu_count:total", + "refId": "A" + } + ], + "title": "Total GPUs", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "value", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "blue" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 3, + "targets": [ + { + "expr": "cluster:gpu_count:allocated", + "refId": "A" + } + ], + "title": "Allocated", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "value", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 1, + "color": "yellow" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 4, + "targets": [ + { + "expr": "cluster:gpu_util:avg", + "refId": "A" + } + ], + "title": "Average utilization", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "area", + "colorMode": "value", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "blue" + }, + { + "value": 30, + "color": "green" + }, + { + "value": 80, + "color": "orange" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 5, + "targets": [ + { + "expr": "cluster:gpu_power_watts:sum", + "refId": "A" + } + ], + "title": "Power draw", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "area", + "colorMode": "value", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "watt", + "decimals": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Utilization", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 10, + "panels": [] + }, + { + "type": "timeseries", + "id": 11, + "targets": [ + { + "expr": "DCGM_FI_DEV_GPU_UTIL{Hostname=~\"$Hostname\"}", + "legendFormat": "{{Hostname}}/{{gpu}} {{pod}}", + "refId": "A" + } + ], + "title": "GPU Utilization (NVML)", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 6 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 10, + "showPoints": "never", + "spanNulls": false + } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "id": 12, + "targets": [ + { + "expr": "DCGM_FI_PROF_PIPE_TENSOR_ACTIVE{Hostname=~\"$Hostname\"} * 100", + "legendFormat": "{{Hostname}}/{{gpu}} {{pod}}", + "refId": "A" + } + ], + "title": "Tensor Pipe Active (realistic load for LLM/AI)", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 6 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 10, + "showPoints": "never", + "spanNulls": false + } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "id": 13, + "targets": [ + { + "expr": "DCGM_FI_PROF_GR_ENGINE_ACTIVE{Hostname=~\"$Hostname\"} * 100", + "legendFormat": "{{Hostname}}/{{gpu}} {{pod}}", + "refId": "A" + } + ], + "title": "Graphics Engine Active", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 14 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 10, + "showPoints": "never", + "spanNulls": false + } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "id": 14, + "targets": [ + { + "expr": "DCGM_FI_DEV_MEM_COPY_UTIL{Hostname=~\"$Hostname\"}", + "legendFormat": "{{Hostname}}/{{gpu}} {{pod}}", + "refId": "A" + } + ], + "title": "Memory Copy Utilization", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 14 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 10, + "showPoints": "never", + "spanNulls": false + } + }, + "overrides": [] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Memory", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 22 + }, + "id": 20, + "panels": [] + }, + { + "type": "timeseries", + "id": 21, + "targets": [ + { + "expr": "DCGM_FI_DEV_FB_USED{Hostname=~\"$Hostname\"} * 1048576", + "legendFormat": "{{Hostname}}/{{gpu}} {{pod}}", + "refId": "A" + } + ], + "title": "VRAM Used", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 23 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "bytes", + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 25, + "showPoints": "never" + } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "id": 22, + "targets": [ + { + "expr": "DCGM_FI_DEV_FB_FREE{Hostname=~\"$Hostname\"} * 1048576", + "legendFormat": "{{Hostname}}/{{gpu}}", + "refId": "A" + } + ], + "title": "VRAM Free", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 23 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "min" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "bytes", + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 10, + "showPoints": "never" + } + }, + "overrides": [] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Power \u0026 Temperature", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 30, + "panels": [] + }, + { + "type": "timeseries", + "id": 31, + "targets": [ + { + "expr": "DCGM_FI_DEV_POWER_USAGE{Hostname=~\"$Hostname\"}", + "legendFormat": "{{Hostname}}/{{gpu}}", + "refId": "A" + } + ], + "title": "Power Usage per GPU", + "description": "Hardware-level metric — shown cluster-wide regardless of namespace filter.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 32 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "watt", + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 10, + "showPoints": "never" + } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "id": 32, + "targets": [ + { + "expr": "DCGM_FI_DEV_GPU_TEMP{Hostname=~\"$Hostname\"}", + "legendFormat": "{{Hostname}}/{{gpu}}", + "refId": "A" + } + ], + "title": "GPU Temperature", + "description": "Hardware-level metric — shown cluster-wide regardless of namespace filter.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 32 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "celsius", + "min": 20, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 75, + "color": "yellow" + }, + { + "value": 85, + "color": "red" + } + ] + }, + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 10, + "showPoints": "never" + } + }, + "overrides": [] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Health", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 40 + }, + "id": 40, + "panels": [] + }, + { + "type": "stat", + "id": 41, + "targets": [ + { + "expr": "max by (Hostname, gpu) (DCGM_FI_DEV_XID_ERRORS{Hostname=~\"$Hostname\"})", + "legendFormat": "{{Hostname}}/{{gpu}}", + "refId": "A" + } + ], + "title": "XID errors (latest)", + "description": "Hardware-level metric — shown cluster-wide regardless of namespace filter.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 41 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "background", + "justifyMode": "auto", + "textMode": "value_and_name", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 1, + "color": "red" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "id": 42, + "targets": [ + { + "expr": "rate(DCGM_FI_DEV_POWER_VIOLATION{Hostname=~\"$Hostname\"}[5m])", + "legendFormat": "{{Hostname}}/{{gpu}}", + "refId": "A" + } + ], + "title": "Power Violation (µs/s throttled due to power)", + "description": "Hardware-level metric — shown cluster-wide regardless of namespace filter.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 41 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false, + "calcs": [] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "µs", + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 10, + "showPoints": "never" + } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "id": 43, + "targets": [ + { + "expr": "rate(DCGM_FI_DEV_THERMAL_VIOLATION{Hostname=~\"$Hostname\"}[5m])", + "legendFormat": "{{Hostname}}/{{gpu}}", + "refId": "A" + } + ], + "title": "Thermal Violation (µs/s throttled due to thermals)", + "description": "Hardware-level metric — shown cluster-wide regardless of namespace filter.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 41 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false, + "calcs": [] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "µs", + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 10, + "showPoints": "never" + } + }, + "overrides": [] + } + } + ], + "templating": { + "list": [ + { + "type": "datasource", + "name": "ds_prometheus", + "label": "Prometheus", + "skipUrlSync": false, + "query": "prometheus", + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "multi": false, + "allowCustomValue": true, + "includeAll": false, + "regex": "", + "auto": false, + "auto_min": "10s", + "auto_count": 30 + }, + { + "type": "query", + "name": "Hostname", + "label": "Host", + "skipUrlSync": false, + "query": "label_values(DCGM_FI_DEV_GPU_UTIL, Hostname)", + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "current": { + "selected": true, + "text": "All", + "value": "$__all" + }, + "multi": true, + "allowCustomValue": true, + "refresh": 2, + "sort": 1, + "includeAll": true, + "auto": false, + "auto_min": "10s", + "auto_count": 30 + } + ] + }, + "annotations": {} +} diff --git a/dashboards/gpu/gpu-quotas.json b/dashboards/gpu/gpu-quotas.json new file mode 100644 index 00000000..865fb95c --- /dev/null +++ b/dashboards/gpu/gpu-quotas.json @@ -0,0 +1,637 @@ +{ + "uid": "gpu-quotas", + "title": "GPU Quotas \u0026 Allocation", + "tags": [ + "gpu", + "quotas" + ], + "timezone": "browser", + "editable": true, + "graphTooltip": 1, + "time": { + "from": "now-6h", + "to": "now" + }, + "fiscalYearStartMonth": 0, + "schemaVersion": 42, + "panels": [ + { + "type": "row", + "collapsed": false, + "title": "Allocation overview", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "panels": [] + }, + { + "type": "stat", + "id": 2, + "targets": [ + { + "expr": "sum(kube_node_status_allocatable{resource=\"nvidia_com_gpu\"})", + "refId": "A" + } + ], + "title": "GPU allocatable", + "description": "Total GPU capacity the cluster can schedule to pods.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "value", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "blue" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 3, + "targets": [ + { + "expr": "cluster:gpu_count:allocated", + "refId": "A" + } + ], + "title": "GPU requested", + "description": "Sum of GPU requests across all pods cluster-wide, including system namespaces.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "value", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 1, + "color": "yellow" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "gauge", + "id": 4, + "targets": [ + { + "expr": "cluster:gpu_count:allocated / sum(kube_node_status_allocatable{resource=\"nvidia_com_gpu\"}) * 100", + "refId": "A" + } + ], + "title": "Allocation ratio", + "description": "Percentage of allocatable GPUs currently requested by pods.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto", + "minVizWidth": 75, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "minVizHeight": 75, + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "blue" + }, + { + "value": 40, + "color": "green" + }, + { + "value": 80, + "color": "yellow" + }, + { + "value": 95, + "color": "red" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 5, + "targets": [ + { + "expr": "count((sum by (namespace, pod) (kube_pod_container_resource_requests{resource=\"nvidia_com_gpu\"}) \u003e 0) * on(namespace, pod) group_left() (kube_pod_status_phase{phase=\"Pending\"} == 1)) or vector(0)", + "refId": "A" + } + ], + "title": "Pending pods (GPU)", + "description": "Pods requesting GPUs that are stuck in Pending state — indicates capacity shortage.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "background", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 1, + "color": "red" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Per namespace", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 10, + "panels": [] + }, + { + "type": "bargauge", + "id": 11, + "targets": [ + { + "expr": "sum by (namespace) (namespace:gpu_count:allocated{namespace=~\"$namespace\"})", + "legendFormat": "{{namespace}}", + "refId": "A" + } + ], + "title": "GPU requested per namespace", + "description": "GPU allocation breakdown by namespace — spot top consumers at a glance.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 6 + }, + "repeatDirection": "h", + "options": { + "displayMode": "gradient", + "valueMode": "color", + "namePlacement": "auto", + "showUnfilled": true, + "sizing": "auto", + "minVizWidth": 8, + "minVizHeight": 16, + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false, + "calcs": [] + }, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "maxVizHeight": 300, + "orientation": "horizontal" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "min": 0, + "max": 8, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "id": 12, + "targets": [ + { + "expr": "sum(kube_node_status_allocatable{resource=\"nvidia_com_gpu\"})", + "legendFormat": "Allocatable (total)", + "refId": "A" + }, + { + "expr": "sum(namespace:gpu_count:allocated{namespace=~\"$namespace\"})", + "legendFormat": "Requested", + "refId": "B" + } + ], + "title": "GPU allocated over time", + "description": "Requested vs allocatable GPUs over time — shows allocation pressure trends.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 6 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false, + "calcs": [] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "custom": { + "drawStyle": "line", + "lineInterpolation": "stepAfter", + "fillOpacity": 10, + "showPoints": "never" + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Allocatable (total)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Pods with GPU", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 20, + "panels": [] + }, + { + "type": "table", + "id": 21, + "targets": [ + { + "expr": "kube_pod_container_resource_requests{resource=\"nvidia_com_gpu\", namespace=~\"$namespace\"} * on(namespace, pod) group_left(phase) (kube_pod_status_phase{phase=~\"Running|Pending\"} == 1)", + "instant": true, + "range": false, + "format": "table", + "refId": "requested" + }, + { + "expr": "kube_pod_container_resource_limits{resource=\"nvidia_com_gpu\", namespace=~\"$namespace\"} * on(namespace, pod) group_left() (kube_pod_status_phase{phase=~\"Running|Pending\"} == 1)", + "instant": true, + "range": false, + "format": "table", + "refId": "limits" + } + ], + "title": "Pods requesting GPU", + "description": "Per-pod GPU requests and limits with scheduling status — Running or Pending.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 15 + }, + "repeatDirection": "h", + "transformations": [ + { + "id": "joinByField", + "options": { + "byField": "pod", + "mode": "outer" + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Time 1": true, + "Time 2": true, + "__name__": true, + "__name__ 1": true, + "__name__ 2": true, + "cluster": true, + "cluster 1": true, + "cluster 2": true, + "container 2": true, + "endpoint": true, + "endpoint 1": true, + "endpoint 2": true, + "instance": true, + "instance 1": true, + "instance 2": true, + "job": true, + "job 1": true, + "job 2": true, + "namespace 2": true, + "node 2": true, + "prometheus": true, + "prometheus 1": true, + "prometheus 2": true, + "resource": true, + "resource 1": true, + "resource 2": true, + "service": true, + "service 1": true, + "service 2": true, + "tenant": true, + "tenant 1": true, + "tenant 2": true, + "tier": true, + "tier 1": true, + "tier 2": true, + "uid": true, + "uid 1": true, + "uid 2": true, + "unit": true, + "unit 1": true, + "unit 2": true + }, + "indexByName": { + "Value #limits": 5, + "Value #requested": 4, + "container 1": 2, + "namespace 1": 0, + "node 1": 3, + "phase": 6, + "pod": 1 + }, + "renameByName": { + "Value #limits": "Limit", + "Value #requested": "Req", + "container 1": "Container", + "namespace 1": "Namespace", + "node 1": "Node", + "phase": "Status" + } + } + } + ], + "options": { + "frameIndex": 0, + "showHeader": true, + "showTypeIcons": false, + "footer": { + "show": false, + "reducer": [] + }, + "cellHeight": "sm" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Status" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "mode": "basic", + "type": "color-background" + } + }, + { + "id": "mappings", + "value": [ + { + "options": { + "Failed": { + "color": "red", + "index": 2 + }, + "Pending": { + "color": "orange", + "index": 1 + }, + "Running": { + "color": "green", + "index": 0 + } + }, + "type": "value" + } + ] + } + ] + } + ] + } + } + ], + "templating": { + "list": [ + { + "type": "datasource", + "name": "ds_prometheus", + "label": "Prometheus", + "skipUrlSync": false, + "query": "prometheus", + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "multi": false, + "allowCustomValue": true, + "includeAll": false, + "regex": "", + "auto": false, + "auto_min": "10s", + "auto_count": 30 + }, + { + "type": "query", + "name": "namespace", + "label": "Namespace", + "skipUrlSync": false, + "query": "label_values(kube_pod_container_resource_requests{resource=\"nvidia_com_gpu\"}, namespace)", + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "current": { + "selected": true, + "text": "All", + "value": "$__all" + }, + "multi": true, + "allowCustomValue": true, + "refresh": 2, + "sort": 1, + "includeAll": true, + "auto": false, + "auto_min": "10s", + "auto_count": 30 + } + ] + }, + "annotations": {} +} diff --git a/dashboards/gpu/gpu-tenants.json b/dashboards/gpu/gpu-tenants.json new file mode 100644 index 00000000..7fef321d --- /dev/null +++ b/dashboards/gpu/gpu-tenants.json @@ -0,0 +1,1098 @@ +{ + "uid": "gpu-tenants", + "title": "GPU Tenant Usage", + "description": "Per-tenant GPU consumption: live allocation, utilization, tensor saturation, power, and 24h GPU-hours / kWh — admin view across all namespaces.", + "tags": [ + "gpu", + "tenants", + "admin" + ], + "timezone": "browser", + "editable": true, + "graphTooltip": 1, + "time": { + "from": "now-24h", + "to": "now" + }, + "fiscalYearStartMonth": 0, + "schemaVersion": 42, + "panels": [ + { + "type": "row", + "collapsed": false, + "title": "Tenant fleet snapshot", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "panels": [] + }, + { + "type": "stat", + "id": 2, + "targets": [ + { + "expr": "count(namespace:gpu_count:allocated{namespace=~\"$namespace\"} \u003e 0)", + "refId": "A" + } + ], + "title": "Active tenants", + "description": "Namespaces with at least one GPU request (Pending + Running).", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "value", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "blue" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 3, + "targets": [ + { + "expr": "sum(namespace:gpu_count:allocated{namespace=~\"$namespace\"})", + "refId": "A" + } + ], + "title": "Allocated GPUs", + "description": "Sum of kube GPU requests across tenants. Billable view — includes Pending pods.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "background", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "blue" + }, + { + "value": 1, + "color": "green" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 4, + "targets": [ + { + "expr": "cluster:gpu_util:avg", + "refId": "A" + } + ], + "title": "Avg cluster GPU util", + "description": "Average NVML utilization across all GPUs in the cluster. Cluster-wide — DCGM hardware metrics cannot be attributed to workload namespaces.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "area", + "colorMode": "value", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "blue" + }, + { + "value": 30, + "color": "green" + }, + { + "value": 80, + "color": "orange" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 5, + "targets": [ + { + "expr": "cluster:gpu_power_watts:sum", + "refId": "A" + } + ], + "title": "Total GPU power", + "description": "Live power draw summed across all GPUs in the cluster. Cluster-wide — DCGM hardware metrics cannot be attributed to workload namespaces.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 12, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "area", + "colorMode": "value", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "watt", + "decimals": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 6, + "targets": [ + { + "expr": "sum(sum_over_time(node:power_watts:sum[24h:1m])) / 60 / 1000", + "refId": "A" + } + ], + "title": "Energy (last 24h)", + "description": "Integrated cluster-wide GPU power draw over 24h. Cluster-wide — DCGM hardware metrics cannot be attributed to workload namespaces.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "value", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "kwatth", + "decimals": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "stat", + "id": 7, + "targets": [ + { + "expr": "sum(sum_over_time(namespace:gpu_count:allocated{namespace=~\"$namespace\"}[24h:1m])) / 60", + "refId": "A" + } + ], + "title": "GPU-hours (last 24h)", + "description": "Sum of (GPU count × time requested) across all tenants over the last 24h. Integrated from kube requests, so Pending pods count.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 1 + }, + "repeatDirection": "h", + "options": { + "graphMode": "none", + "colorMode": "value", + "justifyMode": "auto", + "textMode": "value", + "wideLayout": true, + "showPercentChange": false, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "percentChangeColorMode": "standard", + "orientation": "" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "decimals": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "blue" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Current allocation", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 10, + "panels": [] + }, + { + "type": "bargauge", + "id": 11, + "targets": [ + { + "expr": "namespace:gpu_count:allocated{namespace=~\"$namespace\"}", + "legendFormat": "{{namespace}}", + "refId": "A" + } + ], + "title": "GPUs per namespace", + "description": "Kube GPU requests per tenant (billable). Includes Pending pods.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 6 + }, + "repeatDirection": "h", + "options": { + "displayMode": "gradient", + "valueMode": "color", + "namePlacement": "auto", + "showUnfilled": true, + "sizing": "auto", + "minVizWidth": 8, + "minVizHeight": 16, + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false, + "calcs": [] + }, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "maxVizHeight": 300, + "orientation": "horizontal" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "bargauge", + "id": 12, + "targets": [ + { + "expr": "node:fb_used_bytes:sum", + "legendFormat": "{{Hostname}}", + "refId": "A" + } + ], + "title": "VRAM used per node", + "description": "FB memory actively used per node. DCGM hardware metrics cannot be attributed to workload namespaces — shown per-node instead.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 6 + }, + "repeatDirection": "h", + "options": { + "displayMode": "gradient", + "valueMode": "color", + "namePlacement": "auto", + "showUnfilled": true, + "sizing": "auto", + "minVizWidth": 8, + "minVizHeight": 16, + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false, + "calcs": [] + }, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "maxVizHeight": 300, + "orientation": "horizontal" + }, + "fieldConfig": { + "defaults": { + "unit": "bytes", + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Utilization (per-node)", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 20, + "panels": [] + }, + { + "type": "timeseries", + "id": 21, + "targets": [ + { + "expr": "node:gpu_util:avg", + "legendFormat": "{{Hostname}}", + "refId": "A" + } + ], + "title": "NVML utilization per node", + "description": "Per-node NVML utilization. Stacked to show fleet-wide pressure over time. DCGM hardware metrics cannot be attributed to workload namespaces — shown per-node instead.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 15 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 40, + "showPoints": "never", + "stacking": { + "mode": "normal" + } + } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "id": 22, + "targets": [ + { + "expr": "node:tensor_active:avg * 100", + "legendFormat": "{{Hostname}}", + "refId": "A" + } + ], + "title": "Tensor saturation per node", + "description": "Real tensor core load per node. Useful to spot nodes with idle tensor cores. DCGM hardware metrics cannot be attributed to workload namespaces — shown per-node instead.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 15 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 40, + "showPoints": "never", + "stacking": { + "mode": "normal" + } + } + }, + "overrides": [] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Power \u0026 allocation trend", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 30, + "panels": [] + }, + { + "type": "timeseries", + "id": 31, + "targets": [ + { + "expr": "node:power_watts:sum", + "legendFormat": "{{Hostname}}", + "refId": "A" + } + ], + "title": "Power draw per node", + "description": "Per-node GPU power draw. Stacked to see cluster-wide energy burn over time. DCGM hardware metrics cannot be attributed to workload namespaces — shown per-node instead.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 24 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "watt", + "min": 0, + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "fillOpacity": 40, + "showPoints": "never", + "stacking": { + "mode": "normal" + } + } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "id": 32, + "targets": [ + { + "expr": "namespace:gpu_count:allocated{namespace=~\"$namespace\"}", + "legendFormat": "{{namespace}}", + "refId": "A" + } + ], + "title": "Allocated GPUs per namespace", + "description": "Kube-requested GPU count per tenant over time. Step-after interpolation reflects discrete allocation changes.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 24 + }, + "repeatDirection": "h", + "options": { + "legend": { + "displayMode": "table", + "placement": "bottom", + "showLegend": false, + "calcs": [ + "mean", + "max" + ] + }, + "tooltip": { + "mode": "multi", + "sort": "" + } + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "min": 0, + "custom": { + "drawStyle": "line", + "lineInterpolation": "stepAfter", + "fillOpacity": 40, + "showPoints": "never", + "stacking": { + "mode": "normal" + } + } + }, + "overrides": [] + } + }, + { + "type": "row", + "collapsed": false, + "title": "Top consumers (live)", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 40, + "panels": [] + }, + { + "type": "table", + "id": 41, + "targets": [ + { + "expr": "namespace:gpu_count:allocated{namespace=~\"$namespace\"}", + "instant": true, + "range": false, + "format": "table", + "refId": "gpus" + } + ], + "title": "Top consumers (allocation)", + "description": "Live ranking of tenants by GPU allocation. Hardware metrics (util, tensor, power, VRAM) cannot be attributed to workload namespaces — see Fleet and Performance dashboards for per-node/per-GPU hardware views.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 33 + }, + "repeatDirection": "h", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Time 1": true, + "Time 2": true, + "Time 3": true, + "Time 4": true, + "Time 5": true, + "__name__": true, + "__name__ 1": true, + "__name__ 2": true, + "__name__ 3": true, + "__name__ 4": true, + "__name__ 5": true, + "cluster": true, + "cluster 1": true, + "cluster 2": true, + "cluster 3": true, + "cluster 4": true, + "cluster 5": true, + "endpoint": true, + "endpoint 1": true, + "endpoint 2": true, + "endpoint 3": true, + "endpoint 4": true, + "endpoint 5": true, + "instance": true, + "instance 1": true, + "instance 2": true, + "instance 3": true, + "instance 4": true, + "instance 5": true, + "job": true, + "job 1": true, + "job 2": true, + "job 3": true, + "job 4": true, + "job 5": true, + "prometheus": true, + "prometheus 1": true, + "prometheus 2": true, + "prometheus 3": true, + "prometheus 4": true, + "prometheus 5": true, + "service": true, + "service 1": true, + "service 2": true, + "service 3": true, + "service 4": true, + "service 5": true, + "tenant": true, + "tenant 1": true, + "tenant 2": true, + "tenant 3": true, + "tenant 4": true, + "tenant 5": true, + "tier": true, + "tier 1": true, + "tier 2": true, + "tier 3": true, + "tier 4": true, + "tier 5": true, + "uid": true, + "uid 1": true, + "uid 2": true, + "uid 3": true, + "uid 4": true, + "uid 5": true, + "unit": true, + "unit 1": true, + "unit 2": true, + "unit 3": true, + "unit 4": true, + "unit 5": true + }, + "indexByName": { + "Value #gpus": 1, + "namespace": 0 + }, + "renameByName": { + "Value #gpus": "GPUs", + "namespace": "Namespace" + } + } + } + ], + "options": { + "frameIndex": 0, + "showHeader": true, + "showTypeIcons": false, + "sortBy": [ + { + "displayName": "GPUs", + "desc": true + } + ], + "footer": { + "show": false, + "reducer": [] + }, + "cellHeight": "sm" + } + }, + { + "type": "row", + "collapsed": false, + "title": "Historical usage (last 24h)", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 43 + }, + "id": 50, + "panels": [] + }, + { + "type": "bargauge", + "id": 51, + "targets": [ + { + "expr": "sum_over_time(namespace:gpu_count:allocated{namespace=~\"$namespace\"}[24h:1m]) / 60", + "legendFormat": "{{namespace}}", + "refId": "A" + } + ], + "title": "GPU-hours per namespace (last 24h)", + "description": "Billable GPU-hours per tenant over the last 24h window.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 44 + }, + "repeatDirection": "h", + "options": { + "displayMode": "gradient", + "valueMode": "color", + "namePlacement": "auto", + "showUnfilled": true, + "sizing": "auto", + "minVizWidth": 8, + "minVizHeight": 16, + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false, + "calcs": [] + }, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "maxVizHeight": 300, + "orientation": "horizontal" + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "decimals": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "blue" + } + ] + } + }, + "overrides": [] + } + }, + { + "type": "bargauge", + "id": 52, + "targets": [ + { + "expr": "sum_over_time(node:power_watts:sum[24h:1m]) / 60 / 1000", + "legendFormat": "{{Hostname}}", + "refId": "A" + } + ], + "title": "Energy per node (last 24h)", + "description": "kWh consumed per node over the last 24h. Integrated from 1-minute power samples. DCGM hardware metrics cannot be attributed to workload namespaces — shown per-node instead.", + "transparent": false, + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 44 + }, + "repeatDirection": "h", + "options": { + "displayMode": "gradient", + "valueMode": "color", + "namePlacement": "auto", + "showUnfilled": true, + "sizing": "auto", + "minVizWidth": 8, + "minVizHeight": 16, + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false, + "calcs": [] + }, + "reduceOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "maxVizHeight": 300, + "orientation": "horizontal" + }, + "fieldConfig": { + "defaults": { + "unit": "kwatth", + "decimals": 2, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + } + ] + } + }, + "overrides": [] + } + } + ], + "templating": { + "list": [ + { + "type": "datasource", + "name": "ds_prometheus", + "label": "Prometheus", + "skipUrlSync": false, + "query": "prometheus", + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "multi": false, + "allowCustomValue": true, + "includeAll": false, + "regex": "", + "auto": false, + "auto_min": "10s", + "auto_count": 30 + }, + { + "type": "query", + "name": "namespace", + "label": "Namespace", + "skipUrlSync": false, + "query": "label_values(namespace:gpu_count:allocated, namespace)", + "datasource": { + "type": "prometheus", + "uid": "$ds_prometheus" + }, + "current": { + "selected": true, + "text": "All", + "value": "$__all" + }, + "multi": true, + "allowCustomValue": true, + "refresh": 2, + "sort": 1, + "includeAll": true, + "auto": false, + "auto_min": "10s", + "auto_count": 30 + } + ] + }, + "annotations": {} +} diff --git a/dashboards/hubble/dns-namespace.json b/dashboards/hubble/dns-namespace.json new file mode 100644 index 00000000..57f804cf --- /dev/null +++ b/dashboards/hubble/dns-namespace.json @@ -0,0 +1,602 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "bargauge", + "name": "Bar gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.4.7" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": 16612, + "graphTooltip": 0, + "id": null, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "cilium-overview" + ], + "targetBlank": false, + "title": "Cilium Overviews", + "tooltip": "", + "type": "dashboards", + "url": "" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": true, + "tags": [ + "hubble" + ], + "targetBlank": false, + "title": "Hubble", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "panels": [], + "title": "DNS", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 37, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_dns_queries_total{cluster=~\"$cluster\", source_namespace=~\"$source_namespace\", destination_namespace=~\"$destination_namespace\"}[$__rate_interval])) by (source) > 0", + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "DNS queries", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 41, + "options": { + "displayMode": "gradient", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "topk(10, sum(rate(hubble_dns_queries_total{cluster=~\"$cluster\", source_namespace=~\"$source_namespace\", destination_namespace=~\"$destination_namespace\"}[$__rate_interval])*60) by (query))", + "legendFormat": "{{query}}", + "range": true, + "refId": "A" + } + ], + "title": "Top 10 DNS queries", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 10 + }, + "id": 39, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "round(sum(rate(hubble_dns_queries_total{cluster=~\"$cluster\", source_namespace=~\"$source_namespace\", destination_namespace=~\"$destination_namespace\"}[$__rate_interval])) by (source) - sum(label_replace(sum(rate(hubble_dns_responses_total{cluster=~\"$cluster\", source_namespace=~\"$destination_namespace\", destination_namespace=~\"$source_namespace\"}[$__rate_interval])) by (destination), \"source\", \"$1\", \"destination\", \"(.*)\")) without (destination), 0.001) > 0", + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Missing DNS responses", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 10 + }, + "id": 43, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_dns_responses_total{cluster=~\"$cluster\", source_namespace=~\"$destination_namespace\", destination_namespace=~\"$source_namespace\", rcode!=\"No Error\"}[$__rate_interval])) by (destination, rcode) > 0", + "legendFormat": "{{destination}}: {{rcode}}", + "range": true, + "refId": "A" + } + ], + "title": "DNS errors", + "type": "timeseries" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [ + "kubecon-demo" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "hide": 0, + "includeAll": false, + "label": "Data Source", + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "(?!grafanacloud-usage|grafanacloud-ml-metrics).+", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(cilium_version, cluster)", + "hide": 0, + "includeAll": true, + "multi": true, + "name": "cluster", + "options": [], + "query": { + "query": "label_values(cilium_version, cluster)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": ".*", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(source_namespace)", + "hide": 0, + "includeAll": true, + "label": "Source Namespace", + "multi": true, + "name": "source_namespace", + "options": [], + "query": { + "query": "label_values(source_namespace)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": ".*", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(destination_namespace)", + "hide": 0, + "includeAll": true, + "label": "Destination Namespace", + "multi": true, + "name": "destination_namespace", + "options": [], + "query": { + "query": "label_values(destination_namespace)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Hubble / DNS Overview (Namespace)", + "uid": "_f0DUpY4k", + "version": 26, + "weekStart": "" + } + \ No newline at end of file diff --git a/dashboards/hubble/l7-http-metrics.json b/dashboards/hubble/l7-http-metrics.json new file mode 100644 index 00000000..b21004a6 --- /dev/null +++ b/dashboards/hubble/l7-http-metrics.json @@ -0,0 +1,1394 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.4.7" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 14, + "panels": [], + "title": "General", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 16, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "round(sum(rate(hubble_http_requests_total{reporter=~\"${reporter}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\"}[$__rate_interval])), 0.001)", + "refId": "A" + } + ], + "title": "Incoming Request Volume", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 17, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(rate(hubble_http_requests_total{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\", status!~\"5.*\"}[$__rate_interval]))\n/\nsum(rate(hubble_http_requests_total{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "{{ cluster }} {{ method }} {{ source_namespace }}/{{ source_workload }}", + "range": true, + "refId": "A" + } + ], + "title": "Incoming Request Success Rate (non-5xx responses)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 18, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.0.5", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "histogram_quantile(0.50, sum(rate(hubble_http_request_duration_seconds_bucket{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\"}[$__rate_interval])) by (le))", + "interval": "", + "legendFormat": "P50", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "histogram_quantile(0.95, sum(rate(hubble_http_request_duration_seconds_bucket{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\"}[$__rate_interval])) by (le))", + "hide": false, + "interval": "", + "legendFormat": "P95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "histogram_quantile(0.99, sum(rate(hubble_http_request_duration_seconds_bucket{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\"}[$__rate_interval])) by (le))", + "hide": false, + "interval": "", + "legendFormat": "P99", + "range": true, + "refId": "C" + } + ], + "title": "Request Duration", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 6, + "panels": [], + "title": "Requests by Source", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 3, + "options": { + "legend": { + "calcs": [ + "max", + "mean", + "sum", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum(rate(hubble_http_requests_total{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\", source_namespace=~\"${source_namespace}\", source_workload=~\"${source_workload}\"}[$__rate_interval])) by (cluster, source_namespace, source_workload, status), 0.001)", + "interval": "", + "legendFormat": "{{ cluster }} {{ method }} {{ source_namespace }}/{{ source_workload }}: {{ status }}", + "range": true, + "refId": "A" + } + ], + "title": "Incoming Requests by Source and Response Code", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 7, + "options": { + "legend": { + "calcs": [ + "mean", + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(rate(hubble_http_requests_total{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\", source_namespace=~\"${source_namespace}\", source_workload=~\"${source_workload}\",status!~\"5.*\"}[$__rate_interval])) by (cluster, source_namespace, source_workload)\n/\nsum(rate(hubble_http_requests_total{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\", source_namespace=~\"${source_namespace}\", source_workload=~\"${source_workload}\"}[$__rate_interval])) by (cluster, source_namespace, source_workload)", + "interval": "", + "legendFormat": "{{ cluster }} {{ method }} {{ source_namespace }}/{{ source_workload }}", + "range": true, + "refId": "A" + } + ], + "title": "Incoming Request Success Rate (non-5xx responses) By Source", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 17 + }, + "id": 4, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "mean", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": true, + "expr": "histogram_quantile(0.50, sum(rate(hubble_http_request_duration_seconds_bucket{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\", source_namespace=~\"${source_namespace}\", source_workload=~\"${source_workload}\"}[$__rate_interval])) by (cluster, source_namespace, source_workload, le))", + "interval": "", + "legendFormat": "{{ cluster }} {{ source_namespace }}/{{ source_workload }} P50", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": true, + "expr": "histogram_quantile(0.95, sum(rate(hubble_http_request_duration_seconds_bucket{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\", source_namespace=~\"${source_namespace}\", source_workload=~\"${source_workload}\"}[$__rate_interval])) by (cluster, source_namespace, source_workload, le))", + "hide": false, + "interval": "", + "legendFormat": "{{ cluster }} {{ source_namespace }}/{{ source_workload }} P95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": true, + "expr": "histogram_quantile(0.99, sum(rate(hubble_http_request_duration_seconds_bucket{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\", source_namespace=~\"${source_namespace}\", source_workload=~\"${source_workload}\"}[$__rate_interval])) by (cluster, source_namespace, source_workload, le))", + "hide": false, + "interval": "", + "legendFormat": "{{ cluster }} {{ source_namespace }}/{{ source_workload }} P99", + "range": true, + "refId": "C" + } + ], + "title": "HTTP Request Duration by Source", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 17 + }, + "id": 20, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "mean", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~\"${cluster}\", namespace=~\"${destination_namespace}\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"${cluster}\", namespace=~\"${destination_namespace}\", workload=~\"${source_workload}\"}\n) by (namespace, workload)", + "interval": "", + "legendFormat": "{{ cluster }} {{ namespace }}/{{ workload }}", + "range": true, + "refId": "A" + } + ], + "title": "CPU Usage by Source", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 9, + "panels": [], + "title": "Requests by Destination", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 28 + }, + "id": 10, + "options": { + "legend": { + "calcs": [ + "max", + "mean", + "sum", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "round(sum(rate(hubble_http_requests_total{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\", source_namespace=~\"${source_namespace}\", source_workload=~\"${source_workload}\"}[$__rate_interval])) by (cluster, destination_namespace, destination_workload, status), 0.001)", + "interval": "", + "legendFormat": "{{ cluster }} {{ method }} {{ destination_namespace }}/{{ destination_workload }}: {{ status }}", + "range": true, + "refId": "A" + } + ], + "title": "Incoming Requests by Destination and Response Code", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 11, + "options": { + "legend": { + "calcs": [ + "mean", + "min", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(rate(hubble_http_requests_total{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\", source_namespace=~\"${source_namespace}\", source_workload=~\"${source_workload}\",status!~\"5.*\"}[$__rate_interval])) by (cluster, destination_namespace, destination_workload)\n/\nsum(rate(hubble_http_requests_total{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\", source_namespace=~\"${source_namespace}\", source_workload=~\"${source_workload}\"}[$__rate_interval])) by (cluster, destination_namespace, destination_workload)", + "interval": "", + "legendFormat": "{{ cluster }} {{ method }} {{ destination_namespace }}/{{ destination_workload }}", + "range": true, + "refId": "A" + } + ], + "title": "Incoming Request Success Rate (non-5xx responses) By Destination", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 38 + }, + "id": 12, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "mean", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": true, + "expr": "histogram_quantile(0.50, sum(rate(hubble_http_request_duration_seconds_bucket{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\", source_namespace=~\"${source_namespace}\", source_workload=~\"${source_workload}\"}[$__rate_interval])) by (cluster, destination_namespace, destination_workload, le))", + "interval": "", + "legendFormat": "{{ cluster }} {{ destination_namespace }}/{{ destination_workload }} P50", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": true, + "expr": "histogram_quantile(0.95, sum(rate(hubble_http_request_duration_seconds_bucket{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\", source_namespace=~\"${source_namespace}\", source_workload=~\"${source_workload}\"}[$__rate_interval])) by (cluster, destination_namespace, destination_workload, le))", + "hide": false, + "interval": "", + "legendFormat": "{{ cluster }} {{ destination_namespace }}/{{ destination_workload }} P95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": true, + "expr": "histogram_quantile(0.99, sum(rate(hubble_http_request_duration_seconds_bucket{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", reporter=\"${reporter}\", source_namespace=~\"${source_namespace}\", source_workload=~\"${source_workload}\"}[$__rate_interval])) by (cluster, destination_namespace, destination_workload, le))", + "hide": false, + "interval": "", + "legendFormat": "{{ cluster }} {{ destination_namespace }}/{{ destination_workload }} P99", + "range": true, + "refId": "C" + } + ], + "title": "HTTP Request Duration by Destination", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 38 + }, + "id": 19, + "options": { + "legend": { + "calcs": [ + "min", + "max", + "mean", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=~\"${cluster}\", namespace=~\"${destination_namespace}\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=~\"${cluster}\", namespace=~\"${destination_namespace}\", workload=\"${destination_workload}\"}\n) by (namespace, workload)", + "interval": "", + "legendFormat": "{{ cluster }} {{ namespace }}/{{ workload }}", + "range": true, + "refId": "A" + } + ], + "title": "CPU Usage by Destination", + "type": "timeseries" + } + ], + "refresh": "30s", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": {}, + "hide": 0, + "includeAll": false, + "label": "Prometheus", + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(hubble_http_requests_total, cluster)", + "hide": 0, + "includeAll": false, + "label": "Cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": { + "query": "label_values(hubble_http_requests_total, cluster)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 2, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(hubble_http_requests_total{cluster=~\"${cluster}\"}, destination_namespace)", + "description": "", + "hide": 0, + "includeAll": false, + "label": "Destination Namespace", + "multi": false, + "name": "destination_namespace", + "options": [], + "query": { + "query": "label_values(hubble_http_requests_total{cluster=~\"${cluster}\"}, destination_namespace)", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 2, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(hubble_http_requests_total{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\"}, destination_workload)", + "hide": 0, + "includeAll": false, + "label": "Destination Workload", + "multi": false, + "name": "destination_workload", + "options": [], + "query": { + "query": "label_values(hubble_http_requests_total{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\"}, destination_workload)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 2, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(hubble_http_requests_total, reporter)", + "hide": 0, + "includeAll": false, + "label": "Reporter", + "multi": false, + "name": "reporter", + "options": [], + "query": { + "query": "label_values(hubble_http_requests_total, reporter)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(hubble_http_requests_total{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\"}, source_namespace)", + "hide": 0, + "includeAll": true, + "label": "Source Namespace", + "multi": true, + "name": "source_namespace", + "options": [], + "query": { + "query": "label_values(hubble_http_requests_total{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\"}, source_namespace)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(hubble_http_requests_total{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", source_namespace=~\"${source_namespace}\"}, source_workload)", + "hide": 0, + "includeAll": true, + "label": "Source Workload", + "multi": true, + "name": "source_workload", + "options": [], + "query": { + "query": "label_values(hubble_http_requests_total{cluster=~\"${cluster}\", destination_namespace=~\"${destination_namespace}\", destination_workload=~\"${destination_workload}\", source_namespace=~\"${source_namespace}\"}, source_workload)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Hubble L7 HTTP Metrics by Workload", + "uid": "3g264CZVz", + "version": 3, + "weekStart": "" +} diff --git a/dashboards/hubble/network-overview.json b/dashboards/hubble/network-overview.json new file mode 100644 index 00000000..cddb473d --- /dev/null +++ b/dashboards/hubble/network-overview.json @@ -0,0 +1,1001 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "bargauge", + "name": "Bar gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "9.4.7" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": 16612, + "graphTooltip": 0, + "id": null, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "cilium-overview" + ], + "targetBlank": false, + "title": "Cilium Overviews", + "tooltip": "", + "type": "dashboards", + "url": "" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": false, + "keepTime": true, + "tags": [ + "hubble" + ], + "targetBlank": false, + "title": "Hubble", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "panels": [], + "title": "Flows processed", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_flows_processed_total{cluster=~\"$cluster\", source_namespace=~\"$source_namespace\", destination_namespace=~\"$destination_namespace\"}[$__rate_interval])) by (type, subtype)", + "legendFormat": "{{type}}/{{subtype}}", + "range": true, + "refId": "A" + } + ], + "title": "Flows processed by type", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 35, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_flows_processed_total{cluster=~\"$cluster\", source_namespace=~\"$source_namespace\", destination_namespace=~\"$destination_namespace\"}[$__rate_interval])) by (verdict)", + "legendFormat": "{{verdict}}", + "range": true, + "refId": "A" + } + ], + "title": "Flows processed by verdict", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 10 + }, + "id": 36, + "options": { + "displayMode": "gradient", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "topk(10, sum(rate(hubble_flows_processed_total{cluster=~\"$cluster\", source_namespace=~\"$source_namespace\", destination_namespace=~\"$destination_namespace\"}[$__rate_interval])) by (source))", + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Top 10 sources", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 10 + }, + "id": 37, + "options": { + "displayMode": "gradient", + "minVizHeight": 10, + "minVizWidth": 0, + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true + }, + "pluginVersion": "9.4.7", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "topk(10, sum(rate(hubble_flows_processed_total{cluster=~\"$cluster\", source_namespace=~\"$source_namespace\", destination_namespace=~\"$destination_namespace\"}[$__rate_interval])) by (destination))", + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Top 10 destinations", + "type": "bargauge" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 10, + "panels": [], + "title": "Connection drops", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 20 + }, + "id": 23, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_tcp_flags_total{cluster=~\"$cluster\", source_namespace=~\"$source_namespace\", destination_namespace=~\"$destination_namespace\", flag=\"SYN\"}[$__rate_interval])) by (source) - sum(label_replace(sum(rate(hubble_tcp_flags_total{cluster=~\"$cluster\", source_namespace=~\"$destination_namespace\", destination_namespace=~\"$source_namespace\", flag=\"SYN-ACK\"}[$__rate_interval])) by (destination), \"source\", \"$1\", \"destination\", \"(.*)\")) without (destination) > 0", + "hide": false, + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Missing TCP SYN-ACKs", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 20 + }, + "id": 34, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_icmp_total{cluster=~\"$cluster\", source_namespace=~\"$source_namespace\", destination_namespace=~\"$destination_namespace\", type=\"EchoRequest\"}[$__rate_interval])) by (source) - sum(label_replace(sum(rate(hubble_icmp_total{cluster=~\"$cluster\", source_namespace=~\"$destination_namespace\", destination_namespace=~\"$source_namespace\", type=\"EchoReply\"}[$__rate_interval])) by (destination), \"source\", \"$1\", \"destination\", \"(.*)\")) without (destination) > 0", + "legendFormat": "{{source}}", + "range": true, + "refId": "A" + } + ], + "title": "Missing ICMP Echo Replys", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 29 + }, + "id": 6, + "panels": [], + "title": "Network Policy drops", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 30 + }, + "id": 29, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_drop_total{cluster=~\"$cluster\", source_namespace=~\"$source_namespace\", destination_namespace=~\"$destination_namespace\"}[$__rate_interval])) by (source, reason) > 0", + "legendFormat": "{{source}}: {{reason}}", + "range": true, + "refId": "A" + } + ], + "title": "Network Policy drops by source", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "pps" + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "kube-dns-7d44cdb5d5-g85vg: UNSUPPORTED_PROTOCOL_FOR_NAT_MASQUERADE" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 30, + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(hubble_drop_total{cluster=~\"$cluster\", source_namespace=~\"$source_namespace\", destination_namespace=~\"$destination_namespace\"}[$__rate_interval])) by (destination, reason) > 0", + "legendFormat": "{{destination}}: {{reason}}", + "range": true, + "refId": "A" + } + ], + "title": "Network Policy drops by destination", + "type": "timeseries" + } + ], + "refresh": "", + "revision": 1, + "schemaVersion": 38, + "style": "dark", + "tags": [ + "kubecon-demo" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "hide": 0, + "includeAll": false, + "label": "Data Source", + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "(?!grafanacloud-usage|grafanacloud-ml-metrics).+", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(cilium_version, cluster)", + "hide": 0, + "includeAll": true, + "multi": true, + "name": "cluster", + "options": [], + "query": { + "query": "label_values(cilium_version, cluster)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": ".*", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(source_namespace)", + "hide": 0, + "includeAll": true, + "label": "Source Namespace", + "multi": true, + "name": "source_namespace", + "options": [], + "query": { + "query": "label_values(source_namespace)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": ".*", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(destination_namespace)", + "hide": 0, + "includeAll": true, + "label": "Destination Namespace", + "multi": true, + "name": "destination_namespace", + "options": [], + "query": { + "query": "label_values(destination_namespace)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Hubble / Network Overview (Namespace)", + "uid": "nlsO8tYVz", + "version": 18, + "weekStart": "" + } + \ No newline at end of file diff --git a/dashboards/hubble/overview.json b/dashboards/hubble/overview.json new file mode 100644 index 00000000..783aa131 --- /dev/null +++ b/dashboards/hubble/overview.json @@ -0,0 +1,3357 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 3, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 14, + "panels": [], + "title": "General Processing", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "max", + "fillBelowTo": "avg", + "lines": false + }, + { + "alias": "avg", + "fill": 0, + "fillBelowTo": "min" + }, + { + "alias": "min", + "lines": false + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg(sum(rate(hubble_flows_processed_total[1m])) by (pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "avg", + "refId": "A" + }, + { + "expr": "min(sum(rate(hubble_flows_processed_total[1m])) by (pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "min", + "refId": "B" + }, + { + "expr": "max(sum(rate(hubble_flows_processed_total[1m])) by (pod))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "max", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Flows processed Per Node", + "tooltip": { + "shared": true, + "sort": 1, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_flows_processed_total[1m])) by (pod, type)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Flows Types", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 6 + }, + "id": 59, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_flows_processed_total{type=\"L7\"}[1m])) by (pod, subtype)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{subtype}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "L7 Flow Distribution", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 6 + }, + "id": 60, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_flows_processed_total{type=\"Trace\"}[1m])) by (pod, subtype)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{subtype}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Trace Flow Distribution", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 16, + "panels": [], + "title": "Network", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 12 + }, + "id": 33, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_flows_processed_total[1m])) by (pod, verdict)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{verdict}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Forwarded vs Dropped", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 12 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_drop_total[1m])) by (pod, reason)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{reason}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Drop Reason", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 17 + }, + "id": 34, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": true, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum (rate(hubble_port_distribution_total[1m])) by (pod, protocol)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{protocol}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Protocol Usage", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 17 + }, + "id": 18, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "topk(10, sum (rate(hubble_port_distribution_total{port!=\"0\"}[1m])) by (pod, port, protocol))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{port}}/{{protocol}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Top 10 Port Distribution", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 22 + }, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "fin", + "yaxis": 1 + }, + { + "alias": "FIN", + "yaxis": 2 + }, + { + "alias": "RST", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_tcp_flags_total{family=\"IPv4\"}[1m])) by (pod, flag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{flag}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCPv4", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 0.2 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Missing TCP SYN-ACK", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 22 + }, + "id": 62, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "fin", + "yaxis": 1 + }, + { + "alias": "FIN", + "yaxis": 2 + }, + { + "alias": "RST", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_tcp_flags_total{family=\"IPv4\", flag=\"SYN\"}[1m])) by (pod) - sum(rate(hubble_tcp_flags_total{family=\"IPv4\", flag=\"SYN-ACK\"}[1m])) by (pod)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Missing SYN-ACK", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0.2 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Missing TCPv4 SYN-ACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 27 + }, + "id": 35, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "fin", + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_tcp_flags_total{family=\"IPv6\"}[1m])) by (pod, flag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{flag}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "TCPv6", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 0.2 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Missing TCPv6 SYN-ACKs alert", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 27 + }, + "id": 63, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "fin", + "yaxis": 1 + }, + { + "alias": "FIN", + "yaxis": 2 + }, + { + "alias": "RST", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_tcp_flags_total{family=\"IPv6\", flag=\"SYN\"}[1m])) by (pod) - sum(rate(hubble_tcp_flags_total{family=\"IPv6\", flag=\"SYN-ACK\"}[1m])) by (pod)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Missing SYN-ACK", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0.2 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Missing TCPv6 SYN-ACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 32 + }, + "id": 31, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_icmp_total{family=\"IPv4\"}[1m])) by (pod, type)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "ICMPv4", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 0.1 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Missing ICMPv4 Echo-Reply alert", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 32 + }, + "id": 64, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_icmp_total{family=\"IPv4\", type=\"EchoRequest\"}[1m])) by (pod) - sum(rate(hubble_icmp_total{family=\"IPv4\", type=\"EchoReply\"}[1m])) by (pod)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Missing ICMP Echo-Reply", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0.1 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Missing ICMPv4 Echo-Reply", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 37 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_icmp_total{family=\"IPv6\"}[1m])) by (pod, type)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "ICMPv6", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 37 + }, + "id": 65, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_icmp_total{family=\"IPv6\", type=\"EchoRequest\"}[1m])) by (pod) - sum(rate(hubble_icmp_total{family=\"IPv6\", type=\"EchoReply\"}[1m])) by (pod)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Missing ICMP Echo-Reply", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Missing ICMPv6 Echo-Reply", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 42 + }, + "id": 42, + "panels": [], + "title": "Network Policy", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 43 + }, + "id": 43, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_drop_total{reason=\"POLICY_DENIED\"}[1m])) by (pod, reason)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{reason}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Denies by Reason", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 43 + }, + "id": 61, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_drop_total{reason=\"POLICY_DENIED\"}[1m])) by (pod, protocol)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{protocol}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Denied Packets by Protocol", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 55, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "topk(10, sum(rate(hubble_drop_total{reason=\"POLICY_DENIED\"}[1m])) by (pod, source))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{source}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Top 10 Source Pods with Denied Packets", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 54, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "topk(10, sum(rate(hubble_drop_total{reason=\"POLICY_DENIED\"}[1m])) by (pod, destination))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{destination}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Top 10 Destination Pods with Denied Packets", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 52 + }, + "id": 47, + "panels": [], + "title": "HTTP", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 53 + }, + "id": 45, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_http_requests_total[1m])) by (pod, method)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{method}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "HTTP Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "reqps", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 53 + }, + "id": 49, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_http_responses_total[1m])) by (pod, status)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{status}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "HTTP responses", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 59 + }, + "id": 51, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, rate(hubble_http_request_duration_seconds_bucket[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{method}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "HTTP Request/Response Latency (p50)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 59 + }, + "id": 58, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, rate(hubble_http_request_duration_seconds_bucket[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{method}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "HTTP Request/Response Latency (p99)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 64 + }, + "id": 53, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": true, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_http_requests_total[5m])) by (pod, protocol)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{protocol}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "HTTP Protocol Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 69 + }, + "id": 6, + "panels": [], + "title": "DNS", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 70 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_dns_queries_total[1m])) by (pod, qtypes)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{qtypes}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "DNS Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 70 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_dns_responses_total{rcode=\"No Error\"}[1m])) by (pod, qtypes)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{qtypes}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "DNS responses", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 0.5 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "DNS Request/Response Symmetry alert", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 70 + }, + "id": 66, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_dns_queries_total[1m])) by (pod, qtypes) - sum(rate(hubble_dns_responses_total[1m])) by (pod, qtypes)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{qtypes}}", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0.5 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Missing DNS Responses", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 75 + }, + "id": 40, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_dns_response_types_total[1m])) by (pod, type)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "DNS Response Record Type", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 75 + }, + "id": 57, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_dns_responses_total{rcode=\"No Error\"}[1m])) by (pod,ips_returned)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ips_returned}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "DNS Response IPs Returned", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 80 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(hubble_dns_responses_total{rcode!=\"No Error\"}[1m])) by (pod, qtypes, rcode)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{rcode}} ({{qtypes}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "DNS Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 4, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 80 + }, + "id": 56, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "topk(10,sum(rate(hubble_dns_responses_total{rcode!=\"No Error\"}[1m])) by (pod, destination))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{destination}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pods with DNS errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 4, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fill": 1, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 85 + }, + "id": 20, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": {}, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "topk(10, sum(rate(hubble_dns_queries_total[10m])*60) by (query, qtypes))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{query}} ({{qtypes}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Top 10 DNS Queries per minute", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "30s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": {}, + "hide": 0, + "includeAll": false, + "label": "Prometheus", + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Hubble Metrics and Monitoring", + "uid": "5HftnJAWz", + "version": 24 +} diff --git a/dashboards/mongodb/mongodb-inmemory.json b/dashboards/mongodb/mongodb-inmemory.json new file mode 100644 index 00000000..c774a314 --- /dev/null +++ b/dashboards/mongodb/mongodb-inmemory.json @@ -0,0 +1,1640 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "MongoDB WiredTiger InMemory Details", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "links": [ + { + "asDropdown": false, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "mongodb" + ], + "targetBlank": false, + "title": "Related Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Amount of data currently stored InMemory in its uncompressed format.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgb(31, 120, 193)", + "mode": "fixed" + }, + "decimals": 2, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 0 + }, + "hideTimeOverride": true, + "id": 1, + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "text": { + "valueSize": 20 + }, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "editorMode": "code", + "expr": "avg(mongodb_mongod_wiredtiger_cache_bytes{job=\"$job\", type=\"total\"})", + "interval": "5m", + "range": true, + "refId": "A" + } + ], + "timeFrom": "1m", + "title": "InMemory Data Size", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Maximum size the InMemory data can grow to. Configurable via storage.wiredTiger.inMemory.cacheSizeGB.", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgb(31, 120, 193)", + "mode": "fixed" + }, + "decimals": 2, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 0 + }, + "hideTimeOverride": true, + "id": 2, + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "text": { + "valueSize": 20 + }, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "editorMode": "code", + "expr": "avg(mongodb_mongod_wiredtiger_cache_max_bytes{job=\"$job\"})", + "interval": "5m", + "range": true, + "refId": "A" + } + ], + "timeFrom": "1m", + "title": "InMemory Max Data Size", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Amount of memory left available for InMemory databases.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 90 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 95 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 0 + }, + "id": 3, + "interval": "$interval", + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "text": { + "valueSize": 20 + }, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "1-(avg(mongodb_mongod_wiredtiger_cache_bytes{job=\"$job\", type=\"total\"})/avg(mongodb_mongod_wiredtiger_cache_max_bytes{job=\"$job\"}))", + "interval": "5m", + "legendFormat": "", + "refId": "A" + } + ], + "title": "InMemory Available", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Percentage of InMemory pages that have been changed and not yet had the modified data consolidated.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(42, 150, 37, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 30 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 50 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 4, + "interval": "$interval", + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "text": { + "valueSize": 20 + }, + "textMode": "auto", + "wideLayout": true + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg(mongodb_mongod_wiredtiger_cache_pages{job=\"$job\",type=\"dirty\"})/avg(mongodb_mongod_wiredtiger_cache_pages{job=\"$job\",type=\"total\"})", + "interval": "5m", + "legendFormat": "", + "refId": "A" + } + ], + "title": "InMemory Dirty Pages", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "WiredTiger internal transactions", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 3 + }, + "id": 5, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg by (type) (rate(mongodb_mongod_wiredtiger_transactions_total{job=\"$job\"}[$interval]) or irate(mongodb_mongod_wiredtiger_transactions_total{job=\"$job\"}[5m]))", + "interval": "$interval", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "title": "InMemory Transactions", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Configured max and current size of the WiredTiger cache.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 3 + }, + "id": 6, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg(mongodb_mongod_wiredtiger_cache_max_bytes{job=\"$job\"})", + "interval": "$interval", + "legendFormat": "Maximum", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg(mongodb_mongod_wiredtiger_cache_bytes{job=\"$job\", type=\"total\"})", + "interval": "$interval", + "legendFormat": "Used", + "refId": "B" + } + ], + "title": "InMemory Capacity", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Internal WiredTiger storage engine cursors and sessions currently open.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 7, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg(mongodb_mongod_wiredtiger_session_open_cursors_total{job=\"$job\"})", + "interval": "$interval", + "legendFormat": "Cursors", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg(mongodb_mongod_wiredtiger_session_open_sessions_total{job=\"$job\"})", + "interval": "$interval", + "legendFormat": "Sessions", + "refId": "B" + } + ], + "title": "InMemory Sessions", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Pages in the WiredTiger cache", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 8, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg by (type) (mongodb_mongod_wiredtiger_cache_pages{job=\"$job\"})", + "interval": "$interval", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "title": "InMemory Pages", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "A WiredTiger 'ticket' is assigned for every operation running simultaneously in the storage engine.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^write_/" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 19 + }, + "id": 9, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg by (type) (mongodb_mongod_wiredtiger_concurrent_transactions_total_tickets{job=\"$job\"}-mongodb_mongod_wiredtiger_concurrent_transactions_out_tickets{job=\"$job\"})", + "interval": "$interval", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "title": "InMemory Concurrency Tickets", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Operations queued due to a lock", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 19 + }, + "id": 10, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg by (type) (mongodb_mongod_global_lock_current_queue{job=\"$job\"})", + "interval": "$interval", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "title": "Queued Operations", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Documents per second inserted, updated, deleted or returned.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 27 + }, + "id": 11, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg by (state) (rate(mongodb_mongod_metrics_document_total{job=\"$job\"}[$interval]) or irate(mongodb_mongod_metrics_document_total{job=\"$job\"}[5m]))", + "interval": "$interval", + "legendFormat": "{{state}}", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg(rate(mongodb_mongod_op_counters_repl_total{job=\"$job\", type=\"delete\"}[$interval]) or irate(mongodb_mongod_op_counters_repl_total{job=\"$job\", type=\"delete\"}[5m]))", + "interval": "$interval", + "legendFormat": "repl_deleted", + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg(rate(mongodb_mongod_op_counters_repl_total{job=\"$job\", type=\"update\"}[$interval]) or irate(mongodb_mongod_op_counters_repl_total{job=\"$job\", type=\"update\"}[5m]))", + "interval": "$interval", + "legendFormat": "repl_updated", + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg(rate(mongodb_mongod_op_counters_repl_total{job=\"$job\", type=\"insert\"}[$interval]) or irate(mongodb_mongod_op_counters_repl_total{job=\"$job\", type=\"insert\"}[5m]))", + "interval": "$interval", + "legendFormat": "repl_inserted", + "refId": "D" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg(rate(mongodb_mongod_metrics_ttl_deleted_documents_total{job=\"$job\"}[$interval]) or irate(mongodb_mongod_metrics_ttl_deleted_documents_total{job=\"$job\"}[5m]))", + "interval": "$interval", + "legendFormat": "ttl_deleted", + "refId": "E" + } + ], + "title": "Document Changes", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Number of pages evicted from the WiredTiger cache. The InMemory storage engine only evicts modified pages.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Pages / sec", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 60, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 27 + }, + "id": 12, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg(rate(mongodb_mongod_wiredtiger_cache_evicted_total{job=\"$job\",type=\"modified\"}[$interval]) or irate(mongodb_mongod_wiredtiger_cache_evicted_total{job=\"$job\",type=\"modified\"}[5m]))", + "interval": "$interval", + "legendFormat": "Evicted", + "refId": "A" + } + ], + "title": "InMemory Cache Eviction", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Number of objects scanned (data and index) and documents moved to a new location.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 13, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg by (state) (rate(mongodb_mongod_metrics_query_executor_total{job=\"$job\"}[$interval]) or irate(mongodb_mongod_metrics_query_executor_total{job=\"$job\"}[5m]))", + "interval": "$interval", + "legendFormat": "{{state}}", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg(rate(mongodb_mongod_metrics_record_moves_total{job=\"$job\"}[$interval]) or irate(mongodb_mongod_metrics_record_moves_total{job=\"$job\"}[5m]))", + "interval": "$interval", + "legendFormat": "moved", + "refId": "B" + } + ], + "title": "Scanned and Moved Objects", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Memory page faults. Not necessarily from MongoDB.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 2, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 14, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "avg(rate(mongodb_mongod_extra_info_page_faults_total{job=\"$job\"}[$interval]) or irate(mongodb_mongod_extra_info_page_faults_total{job=\"$job\"}[5m]) or rate(mongodb_extra_info_page_faults_total{job=\"$job\"}[$interval]) or irate(mongodb_extra_info_page_faults_total{job=\"$job\"}[5m]))", + "interval": "$interval", + "legendFormat": "Faults", + "refId": "A" + } + ], + "title": "Page Faults", + "type": "timeseries" + } + ], + "preload": false, + "refresh": "30s", + "schemaVersion": 39, + "tags": [ + "mongodb" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "hide": 0, + "includeAll": false, + "label": "Datasource", + "multi": false, + "name": "ds_prometheus", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "auto": true, + "auto_count": 200, + "auto_min": "1s", + "current": { + "selected": false, + "text": "auto", + "value": "$__auto_interval_interval" + }, + "hide": 0, + "label": "Interval", + "name": "interval", + "options": [ + { + "selected": true, + "text": "auto", + "value": "$__auto_interval_interval" + }, + { + "selected": false, + "text": "1s", + "value": "1s" + }, + { + "selected": false, + "text": "5s", + "value": "5s" + }, + { + "selected": false, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + } + ], + "query": "1s,5s,1m,5m,1h,6h,1d", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + }, + { + "current": { + "selected": false, + "text": "", + "value": "" + }, + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "definition": "label_values(mongodb_up, job)", + "hide": 0, + "includeAll": false, + "label": "Service", + "multi": false, + "name": "job", + "options": [], + "query": { + "query": "label_values(mongodb_up, job)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "MongoDB InMemory Details", + "uid": "mongodb-inmemory", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/dashboards/mongodb/mongodb-overview.json b/dashboards/mongodb/mongodb-overview.json new file mode 100644 index 00000000..558c8490 --- /dev/null +++ b/dashboards/mongodb/mongodb-overview.json @@ -0,0 +1,1460 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "MongoDB Overview Dashboard", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "links": [ + { + "asDropdown": false, + "icon": "external link", + "includeVars": true, + "keepTime": true, + "tags": [ + "mongodb" + ], + "targetBlank": false, + "title": "Related Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Shows how many times a command is executed per second on average during the selected interval.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "editorMode": "code", + "expr": "rate(mongodb_mongod_op_counters_total{job=~\"$job\", type!=\"command\"}[$interval]) or \nirate(mongodb_mongod_op_counters_total{job=~\"$job\", type!=\"command\"}[5m]) or \nrate(mongodb_mongos_op_counters_total{job=~\"$job\", type!=\"command\"}[$interval]) or \nirate(mongodb_mongos_op_counters_total{job=~\"$job\", type!=\"command\"}[5m])", + "interval": "$interval", + "legendFormat": "{{type}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "rate(mongodb_mongod_op_counters_repl_total{job=~\"$job\", type!~\"(command|query|getmore)\"}[$interval]) or \nirate(mongodb_mongod_op_counters_repl_total{job=~\"$job\", type!~\"(command|query|getmore)\"}[5m]) or\nrate(mongodb_mongos_op_counters_repl_total{job=~\"$job\", type!~\"(command|query|getmore)\"}[$interval]) or \nirate(mongodb_mongos_op_counters_repl_total{job=~\"$job\", type!~\"(command|query|getmore)\"}[5m])", + "interval": "$interval", + "legendFormat": "repl_{{type}}", + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "rate(mongodb_mongod_metrics_ttl_deleted_documents_total{job=~\"$job\"}[$interval]) or \nirate(mongodb_mongod_metrics_ttl_deleted_documents_total{job=~\"$job\"}[5m]) or\nrate(mongodb_mongos_metrics_ttl_deleted_documents_total{job=~\"$job\"}[$interval]) or \nirate(mongodb_mongos_metrics_ttl_deleted_documents_total{job=~\"$job\"}[5m])", + "interval": "$interval", + "legendFormat": "ttl_delete", + "refId": "C" + } + ], + "title": "Command Operations", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Keep in mind the hard limit on the maximum number of connections set by your distribution.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 2, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "editorMode": "code", + "expr": "mongodb_connections{job=~\"$job\", state=\"current\"}", + "interval": "$interval", + "legendFormat": "{{pod}}", + "range": true, + "refId": "A" + } + ], + "title": "Connections", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Helps identify why connections are increasing. Shows active cursors compared to cursors being automatically killed after 10 minutes due to an application not closing the connection.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 3, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "mongodb_mongod_metrics_cursor_open{job=~\"$job\"} or\nmongodb_mongod_cursors{job=~\"$job\"} or\nmongodb_mongos_metrics_cursor_open{job=~\"$job\"} or \nmongodb_mongos_cursors{job=~\"$job\"}", + "interval": "$interval", + "legendFormat": "{{state}}", + "refId": "A" + } + ], + "title": "Cursors", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "When used in combination with 'Command Operations', this graph can help identify write amplification.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 4, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "rate(mongodb_mongod_metrics_document_total{job=~\"$job\"}[$interval]) or \nirate(mongodb_mongod_metrics_document_total{job=~\"$job\"}[5m])", + "interval": "$interval", + "legendFormat": "{{state}}", + "refId": "A" + } + ], + "title": "Document Operations", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Any number of queued operations for long periods of time is an indication of possible issues. Find the cause and fix it before requests get stuck in the queue.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 5, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "mongodb_mongod_global_lock_current_queue{job=~\"$job\"}", + "interval": "$interval", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "title": "Queued Operations", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Ratio of scanned objects/indexes to returned documents. High values indicate inefficient queries.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 21 + }, + "id": 6, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "sum(increase(mongodb_mongod_metrics_query_executor_total{job=~\"$job\", state=\"scanned_objects\"}[5m]))/sum(increase(mongodb_mongod_metrics_document_total{job=~\"$job\", state=\"returned\"}[5m]))", + "interval": "$interval", + "legendFormat": "Document", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "sum(increase(mongodb_mongod_metrics_query_executor_total{job=~\"$job\", state=\"scanned\"}[5m]))/sum(increase(mongodb_mongod_metrics_document_total{job=~\"$job\", state=\"returned\"}[5m]))", + "interval": "$interval", + "legendFormat": "Index", + "refId": "B" + } + ], + "title": "Query Efficiency", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Number of objects scanned during queries and number of documents moved.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 21 + }, + "id": 7, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "rate(mongodb_mongod_metrics_query_executor_total{job=~\"$job\"}[$interval]) or irate(mongodb_mongod_metrics_query_executor_total{job=~\"$job\"}[5m])", + "interval": "$interval", + "legendFormat": "{{state}}", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "rate(mongodb_mongod_metrics_record_moves_total{job=~\"$job\"}[$interval]) or irate(mongodb_mongod_metrics_record_moves_total{job=~\"$job\"}[5m])", + "interval": "$interval", + "legendFormat": "moved", + "refId": "B" + } + ], + "title": "Scanned and Moved Objects", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Useful for write-heavy workloads to understand how long it takes to verify writes.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 28 + }, + "id": 8, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "rate(mongodb_mongod_metrics_get_last_error_wtime_total_milliseconds{job=~\"$job\"}[$interval]) or \nirate(mongodb_mongod_metrics_get_last_error_wtime_total_milliseconds{job=~\"$job\"}[5m]) or\nrate(mongodb_mongos_metrics_get_last_error_wtime_total_milliseconds{job=~\"$job\"}[$interval]) or \nirate(mongodb_mongos_metrics_get_last_error_wtime_total_milliseconds{job=~\"$job\"}[5m])", + "interval": "$interval", + "legendFormat": "Write Wait Time", + "refId": "A" + } + ], + "title": "getLastError Write Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Useful for write-heavy workloads to understand how many concurrent writes are occurring.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 9, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "rate(mongodb_mongod_metrics_get_last_error_wtime_num_total{job=~\"$job\"}[$interval]) or \nirate(mongodb_mongod_metrics_get_last_error_wtime_num_total{job=~\"$job\"}[5m]) or\nrate(mongodb_mongos_metrics_get_last_error_wtime_num_total{job=~\"$job\"}[$interval]) or \nirate(mongodb_mongos_metrics_get_last_error_wtime_num_total{job=~\"$job\"}[5m])", + "interval": "$interval", + "legendFormat": "Total", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "rate(mongodb_mongod_metrics_get_last_error_wtimeouts_total{job=~\"$job\"}[$interval]) or\nirate(mongodb_mongod_metrics_get_last_error_wtimeouts_total{job=~\"$job\"}[5m]) or\nrate(mongodb_mongos_metrics_get_last_error_wtimeouts_total{job=~\"$job\"}[$interval]) or\nirate(mongodb_mongos_metrics_get_last_error_wtimeouts_total{job=~\"$job\"}[5m])", + "interval": "$interval", + "legendFormat": "Timeouts", + "refId": "B" + } + ], + "title": "getLastError Write Operations", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Asserts are not important by themselves, but you can correlate spikes with other graphs.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 10, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "rate(mongodb_mongod_asserts_total{job=~\"$job\"}[$interval]) or \nirate(mongodb_mongod_asserts_total{job=~\"$job\"}[5m]) or\nrate(mongodb_mongos_asserts_total{job=~\"$job\"}[$interval]) or \nirate(mongodb_mongos_asserts_total{job=~\"$job\"}[5m])", + "interval": "$interval", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "title": "Assert Events", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "description": "Page faults indicate that requests are processed from disk either because an index is missing or there is not enough memory for the data set.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 11, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "min" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "expr": "rate(mongodb_mongod_extra_info_page_faults_total{job=~\"$job\"}[$interval]) or \nirate(mongodb_mongod_extra_info_page_faults_total{job=~\"$job\"}[5m]) or\nrate(mongodb_mongos_extra_info_page_faults_total{job=~\"$job\"}[$interval]) or \nirate(mongodb_mongos_extra_info_page_faults_total{job=~\"$job\"}[5m])", + "interval": "$interval", + "legendFormat": "Faults", + "refId": "A" + } + ], + "title": "Page Faults", + "type": "timeseries" + } + ], + "preload": false, + "refresh": "30s", + "schemaVersion": 39, + "tags": [ + "mongodb" + ], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "default", + "value": "default" + }, + "hide": 0, + "includeAll": false, + "label": "Datasource", + "multi": false, + "name": "ds_prometheus", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "auto": true, + "auto_count": 200, + "auto_min": "1s", + "current": { + "selected": false, + "text": "auto", + "value": "$__auto_interval_interval" + }, + "hide": 0, + "label": "Interval", + "name": "interval", + "options": [ + { + "selected": true, + "text": "auto", + "value": "$__auto_interval_interval" + }, + { + "selected": false, + "text": "1s", + "value": "1s" + }, + { + "selected": false, + "text": "5s", + "value": "5s" + }, + { + "selected": false, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + } + ], + "query": "1s,5s,1m,5m,1h,6h,1d", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + }, + { + "current": { + "selected": false, + "text": "", + "value": "" + }, + "datasource": { + "type": "prometheus", + "uid": "${ds_prometheus}" + }, + "definition": "label_values(mongodb_up, job)", + "hide": 0, + "includeAll": true, + "label": "Service", + "multi": true, + "name": "job", + "options": [], + "query": { + "query": "label_values(mongodb_up, job)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "type": "query" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "MongoDB Overview", + "uid": "mongodb-overview", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/dashboards/nats/nats-jetstream.json b/dashboards/nats/nats-jetstream.json new file mode 100644 index 00000000..d2312e7e --- /dev/null +++ b/dashboards/nats/nats-jetstream.json @@ -0,0 +1,1541 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "NATS JetStream Dashboard", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": 90, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 13, + "x": 0, + "y": 0 + }, + "id": 34, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "irate(nats_stream_total_messages{server_id=~\"$server\"}[5m])", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "messages per second", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "min": 0, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 13, + "y": 0 + }, + "id": 32, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(nats_varz_jetstream_stats_memory{server_id=\"$server\"})", + "interval": "", + "legendFormat": "", + "range": true, + "refId": "A" + } + ], + "title": "Memory Used", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 14, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(nats_varz_connections{server_id=~\"$server\"})", + "interval": "", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Connections", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "min": 0, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 5, + "x": 13, + "y": 3 + }, + "id": 33, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(nats_varz_jetstream_config_max_memory{server_id=~\"$server\"})", + "interval": "", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Total Memory", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 29, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(nats_server_total_consumers{server_id=~\"$server\"})", + "interval": "", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Total Consumers", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "decimals": 3, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 0.75 + }, + { + "color": "red", + "value": 0.9 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 8 + }, + "id": 28, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(nats_varz_jetstream_stats_storage{server_id=~\"$server\"})/sum(nats_varz_jetstream_config_max_storage{server_id=~\"$server\"})", + "interval": "", + "legendFormat": "", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "", + "interval": "", + "legendFormat": "", + "refId": "B" + } + ], + "title": "Storage Used", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "min": 0, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 4, + "y": 8 + }, + "id": 15, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(nats_varz_jetstream_stats_storage{server_id=~\"$server\"})", + "interval": "", + "legendFormat": "", + "range": true, + "refId": "A" + } + ], + "title": "Total Storage Used", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "decimals": 3, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 0.75 + }, + { + "color": "red", + "value": 0.9 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 9, + "y": 8 + }, + "id": 31, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(nats_varz_jetstream_stats_memory{server_id=~\"$server\"})/sum(nats_varz_jetstream_config_max_memory{server_id=~\"$server\"})", + "interval": "", + "legendFormat": "", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "", + "interval": "", + "legendFormat": "", + "refId": "B" + } + ], + "title": "Memory Used", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "mappings": [], + "min": 0, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 5, + "x": 4, + "y": 11 + }, + "id": 30, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(nats_varz_jetstream_config_max_storage{server_id=~\"$server\"})", + "interval": "", + "legendFormat": "", + "range": true, + "refId": "A" + } + ], + "title": "Max Storage", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 19, + "panels": [], + "title": "Stream metrics", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(nats_stream_total_bytes) by (stream_name)", + "interval": "", + "legendFormat": "{{stream_name}}", + "range": true, + "refId": "A" + } + ], + "title": "Stream data size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 24, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(nats_stream_total_messages) by (stream_name)", + "interval": "", + "legendFormat": "{{stream_name}}", + "range": true, + "refId": "A" + } + ], + "title": "Stream message count", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "mps" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(rate(nats_stream_total_messages{server_id=~\"$server\",stream_name=~\"$stream\"}[$__rate_interval])) by (stream_name)", + "hide": false, + "interval": "", + "legendFormat": "{{stream_name}}", + "range": true, + "refId": "A" + } + ], + "title": "Message Rate (per second)", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 23, + "panels": [], + "title": "Consumer Metrics", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Messages added & processed per minute per consumer", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "mps" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 22 + }, + "id": 25, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(rate(nats_consumer_num_pending{server_id=~\"$server\",stream_name=~\"$stream\",consumer_name=~\"$consumer\"}[$__rate_interval])+rate(nats_consumer_delivered_consumer_seq{server_id=~\"$server\",stream_name=~\"$stream\",consumer_name=~\"$consumer\"}[$__rate_interval])) by (consumer_name)", + "hide": false, + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{consumer_name}} +", + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "- sum(rate(nats_consumer_delivered_consumer_seq{server_id=~\"$server\",stream_name=~\"$stream\",consumer_name=~\"$consumer\",consumer_name=~\"$consumer\"}[$__rate_interval])) by (consumer_name)", + "hide": false, + "interval": "", + "legendFormat": "{{consumer_name}} -", + "range": true, + "refId": "A" + } + ], + "title": "Messages per second (++/--)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 28 + }, + "id": 21, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(nats_consumer_delivered_consumer_seq{server_id=~\"$server\",stream_name=~\"$stream\",consumer_name=~\"$consumer\"}) by (consumer_name)", + "hide": false, + "interval": "", + "legendFormat": "{{consumer_name}}", + "range": true, + "refId": "A" + } + ], + "title": "Total delivered messages", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 28 + }, + "id": 26, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(nats_consumer_num_pending{server_id=~\"$server\",stream_name=~\"$stream\",consumer_name=~\"$consumer\"}) by (consumer_name)", + "hide": false, + "interval": "", + "legendFormat": "{{consumer_name}}", + "range": true, + "refId": "A" + } + ], + "title": "Pending messages", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 28 + }, + "id": 27, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "editorMode": "code", + "expr": "sum(nats_consumer_num_ack_pending{server_id=~\"$server\",stream_name=~\"$stream\",consumer_name=~\"$consumer\"}) by (consumer_name)", + "hide": false, + "interval": "", + "legendFormat": "{{consumer_name}}", + "range": true, + "refId": "A" + } + ], + "title": "Message Acks Pending", + "type": "timeseries" + } + ], + "preload": false, + "refresh": "10s", + "schemaVersion": 40, + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "vm-shortterm", + "value": "59e01639-a99e-4945-bb94-10821e415ad5" + }, + "description": "", + "label": "datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "current": { + "text": "", + "value": "" + }, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(nats_varz_jetstream_stats_memory,namespace)", + "includeAll": false, + "name": "namespace", + "options": [], + "query": { + "query": "label_values(nats_varz_jetstream_stats_memory,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(nats_server_total_streams{namespace=\"$namespace\"},server_id)", + "hide": 2, + "includeAll": true, + "label": "Server", + "name": "server", + "options": [], + "query": { + "query": "label_values(nats_server_total_streams{namespace=\"$namespace\"},server_id)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(nats_stream_last_seq{server_id=~\"$server\"},stream_name)", + "includeAll": true, + "label": "Stream", + "multi": true, + "name": "stream", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(nats_stream_last_seq{server_id=~\"$server\"},stream_name)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "type": "query" + }, + { + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(nats_consumer_num_pending,consumer_name)", + "includeAll": true, + "label": "Consumer", + "multi": true, + "name": "consumer", + "options": [], + "query": { + "query": "label_values(nats_consumer_num_pending,consumer_name)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "NATS JetStream", + "uid": "yQUo5l17k", + "version": 6, + "weekStart": "" +} diff --git a/dashboards/nats/nats-server.json b/dashboards/nats/nats-server.json new file mode 100644 index 00000000..02aa39b2 --- /dev/null +++ b/dashboards/nats/nats-server.json @@ -0,0 +1,1463 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "NATS Server Dashboard for use with built-in Prometheus NATS Exporter into nats official helm charts", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 91, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 10, + "panels": [], + "title": "OS Metrics", + "type": "row" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 1, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "nats_varz_cpu", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{server_id}}", + "metric": "nats_varz_cpu", + "refId": "A", + "step": 4 + } + ], + "title": "Server CPU", + "type": "timeseries" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 3, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "nats_varz_mem", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{server_id}}", + "metric": "nats_varz_mem", + "refId": "A", + "step": 4 + } + ], + "title": "Server Memory", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 11, + "panels": [], + "title": "Throughput", + "type": "row" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 9 + }, + "id": 7, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "nats_varz_in_bytes", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{server_id}}", + "metric": "nats_varz_in_bytes", + "refId": "A", + "step": 10 + } + ], + "title": "Bytes In", + "type": "timeseries" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 9 + }, + "id": 8, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "nats_varz_in_msgs", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{server_id}}", + "metric": "nats_varz_in_msgs", + "refId": "A", + "step": 10 + } + ], + "title": "NATS Msgs In", + "type": "timeseries" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 9 + }, + "id": 5, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "nats_varz_out_bytes", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{server_id}}", + "metric": "nats_varz_out_bytes", + "refId": "A", + "step": 10 + } + ], + "title": "Bytes Out", + "type": "timeseries" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 9 + }, + "id": 6, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "nats_varz_out_msgs", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{server_id}}", + "metric": "nats_varz_out_msgs", + "refId": "A", + "step": 10 + } + ], + "title": "NATS Msgs Out", + "type": "timeseries" + }, + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 16 + }, + "id": 15, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "sum(rate(nats_varz_in_bytes[1m]))", + "interval": "", + "intervalFactor": 2, + "legendFormat": "", + "metric": "nats_varz_in_bytes", + "refId": "A", + "step": 10 + } + ], + "title": "rate(Bytes In)", + "type": "timeseries" + }, + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 16 + }, + "id": 13, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "sum(rate(nats_varz_in_msgs[1m]))", + "interval": "", + "intervalFactor": 2, + "legendFormat": "", + "metric": "nats_varz_in_msgs", + "refId": "A", + "step": 10 + } + ], + "title": "rate(NATS Msgs In)", + "type": "timeseries" + }, + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 16 + }, + "id": 16, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "sum(rate(nats_varz_out_bytes[1m]))", + "interval": "", + "intervalFactor": 2, + "legendFormat": "", + "metric": "nats_varz_out_bytes", + "refId": "A", + "step": 10 + } + ], + "title": "rate(Bytes Out)", + "type": "timeseries" + }, + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 16 + }, + "id": 14, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "sum(rate(nats_varz_out_msgs[1m]))", + "interval": "", + "intervalFactor": 2, + "legendFormat": "", + "metric": "nats_varz_out_msgs", + "refId": "A", + "step": 10 + } + ], + "title": "rate(NATS Msgs Out)", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 12, + "panels": [], + "title": "Client Metrics", + "type": "row" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "points", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 6, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 24 + }, + "id": 2, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "nats_varz_connections", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{server_id}}", + "metric": "nats_varz_connections", + "refId": "A", + "step": 2 + } + ], + "title": "Connections", + "type": "timeseries" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "points", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 6, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 24 + }, + "id": 4, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "nats_varz_subscriptions", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{server_id}}", + "metric": "nats_varz_subscriptions", + "refId": "A", + "step": 4 + } + ], + "title": "Subscriptions", + "type": "timeseries" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "points", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 6, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 24 + }, + "id": 9, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.4.0", + "targets": [ + { + "datasource": { + "datasource": "PBFA97CFB590B2093", + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "nats_varz_slow_consumers", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{server_id}}", + "metric": "nats_varz_slow_consumers", + "refId": "A", + "step": 2 + } + ], + "title": "Slow Consumers", + "type": "timeseries" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 40, + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "vm-shortterm", + "value": "59e01639-a99e-4945-bb94-10821e415ad5" + }, + "label": "datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "NATS Server Dashboard", + "uid": "4_zbf287k", + "version": 2, + "weekStart": "" +} diff --git a/dashboards/seaweedfs/seaweedfs.json b/dashboards/seaweedfs/seaweedfs.json new file mode 100644 index 00000000..30b43f86 --- /dev/null +++ b/dashboards/seaweedfs/seaweedfs.json @@ -0,0 +1,3359 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": 10423, + "graphTooltip": 0, + "id": 160, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 67, + "panels": [], + "title": "Master", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Whether master is leader or not", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "bool_yes_no", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 57, + "links": [], + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "text": {}, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "exemplar": true, + "expr": "sum by (pod) (SeaweedFS_master_is_leader{job=\"seaweedfs-master\", namespace=\"$NAMESPACE\"})", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{pod}}", + "refId": "A", + "step": 60 + } + ], + "title": "Raft leader", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Count times leader changed", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 68, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.1.2", + "targets": [ + { + "exemplar": true, + "expr": "sum by (pod) (SeaweedFS_master_leader_changes{job=\"seaweedfs-master\", type=~\".+\", namespace=\"$NAMESPACE\"})", + "format": "time_series", + "hide": false, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{pod}}", + "refId": "A", + "step": 60 + } + ], + "title": "Master leader changes", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Heartbeats received from components", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 69, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.1.2", + "targets": [ + { + "exemplar": true, + "expr": "sum by (type) (increase(SeaweedFS_master_received_heartbeats{job=\"seaweedfs-master\", namespace=\"$NAMESPACE\"}[$__rate_interval]))", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{type}}", + "refId": "A", + "step": 60 + } + ], + "title": "Received heartbeats", + "type": "timeseries" + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "message": "", + "name": "Replica Placement Mismatch alert", + "noDataState": "ok", + "notifications": [] + }, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Count replica placement mismatch", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 7 + }, + "id": 70, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.1.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": true, + "expr": "sum (SeaweedFS_master_replica_placement_mismatch{job=\"seaweedfs-master\", namespace=\"$NAMESPACE\"} > 0) by (pod)", + "format": "time_series", + "hide": false, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{pod}}", + "refId": "A", + "step": 60 + } + ], + "thresholds": [ + { + "colorMode": "critical", + "op": "gt", + "value": 0, + "visible": true + } + ], + "title": "Replica Placement Mismatch", + "type": "timeseries" + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1, + 1 + ], + "type": "outside_range" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "message": "Raft leader count of master-servers not equal to 1", + "name": "Raft leader alert", + "noDataState": "no_data", + "notifications": [] + }, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Total count of raft leaders", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 7 + }, + "id": 71, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "8.1.2", + "targets": [ + { + "exemplar": true, + "expr": "sum (SeaweedFS_master_is_leader{job=\"seaweedfs-master\", namespace=\"$NAMESPACE\"})", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Leaders", + "refId": "A", + "step": 60 + } + ], + "thresholds": [ + { + "colorMode": "critical", + "op": "lt", + "value": 1, + "visible": true + }, + { + "colorMode": "critical", + "op": "gt", + "value": 1, + "visible": true + } + ], + "title": "Raft leader count", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Whether cluster locked or not", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "bool_yes_no", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 7 + }, + "id": 74, + "links": [], + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "text": {}, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": true, + "expr": "SeaweedFS_master_admin_lock{job=\"seaweedfs-master\", namespace=\"$NAMESPACE\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Client IP: {{client}}", + "range": true, + "refId": "A", + "step": 60 + } + ], + "title": "Admin lock", + "type": "stat" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 60, + "panels": [], + "title": "Filer", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 14 + }, + "id": 46, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "histogram_quantile(0.90, sum(rate(SeaweedFS_filer_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "average", + "refId": "A", + "step": 60 + }, + { + "expr": "histogram_quantile(0.90, sum(rate(SeaweedFS_filer_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le, type))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{type}}", + "refId": "B", + "step": 60 + } + ], + "title": "Filer Request Duration 90th percentile", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 14 + }, + "id": 49, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(SeaweedFS_filer_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "average", + "refId": "A", + "step": 60 + }, + { + "expr": "histogram_quantile(0.95, sum(rate(SeaweedFS_filer_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le, type))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{type}}", + "refId": "B", + "step": 60 + }, + { + "expr": "", + "format": "time_series", + "intervalFactor": 2, + "refId": "C" + } + ], + "title": "Filer Request Duration 95th percentile", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 14 + }, + "id": 45, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(SeaweedFS_filer_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "average", + "refId": "A", + "step": 60 + }, + { + "expr": "histogram_quantile(0.99, sum(rate(SeaweedFS_filer_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le, type))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{type}}", + "refId": "B", + "step": 60 + }, + { + "expr": "", + "format": "time_series", + "intervalFactor": 2, + "refId": "C" + } + ], + "title": "Filer Request Duration 99th percentile", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short", + "unitScale": true + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "total" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsNull", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 2, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "width": 250 + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "exemplar": true, + "expr": "sum by (type) (rate(SeaweedFS_filer_request_total{namespace=\"$NAMESPACE\"}[$__rate_interval]))", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{type}}", + "refId": "A", + "step": 30 + } + ], + "title": "Filer QPS", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 28 + }, + "id": 61, + "panels": [], + "title": "S3 Gateway", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 29 + }, + "id": 65, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "histogram_quantile(0.90, sum(rate(SeaweedFS_s3_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "average", + "refId": "A", + "step": 60 + }, + { + "expr": "histogram_quantile(0.90, sum(rate(SeaweedFS_s3_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le, type))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{type}}", + "refId": "B", + "step": 60 + } + ], + "title": "S3 Request Duration 90th percentile", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 29 + }, + "id": 56, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(SeaweedFS_s3_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "average", + "refId": "A", + "step": 60 + }, + { + "expr": "histogram_quantile(0.95, sum(rate(SeaweedFS_s3_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le, type))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{type}}", + "refId": "B", + "step": 60 + } + ], + "title": "S3 Request Duration 95th percentile", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 29 + }, + "id": 58, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(SeaweedFS_s3_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "average", + "refId": "A", + "step": 60 + }, + { + "exemplar": true, + "expr": "histogram_quantile(0.99, sum(rate(SeaweedFS_s3_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le, type))", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{type}}", + "refId": "B", + "step": 60 + } + ], + "title": "S3 Request Duration 99th percentile", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 84, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "sum(rate(SeaweedFS_s3_bucket_traffic_received_bytes_total{namespace=\"$NAMESPACE\"}[$__interval])) by (bucket)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{bucket}}", + "refId": "A" + } + ], + "title": "S3 Bucket Traffic Received", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 85, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "sum(rate(SeaweedFS_s3_bucket_traffic_sent_bytes_total{namespace=\"$NAMESPACE\"}[$__interval])) by (bucket)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{bucket}}", + "refId": "A" + } + ], + "title": "S3 Bucket Traffic Sent", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 72, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "histogram_quantile(0.99, sum(rate(SeaweedFS_s3_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le))", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "average", + "refId": "A", + "step": 60 + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "histogram_quantile(0.99, sum(rate(SeaweedFS_s3_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le, type, pod))", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{type}}-{{pod}}", + "refId": "B", + "step": 60 + } + ], + "title": "S3 Request. Duration 99th percentile per instance", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 50 + }, + "id": 73, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "histogram_quantile(0.99, sum(rate(SeaweedFS_s3_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le, type, bucket))", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{type}}-{{bucket}}", + "refId": "B", + "step": 60 + } + ], + "title": "S3 Request Duration 99th percentile per bucket", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short", + "unitScale": true + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "total" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsNull", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 57 + }, + "id": 55, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "width": 250 + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum (rate(SeaweedFS_s3_request_total{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (type)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{type}}", + "refId": "A", + "step": 30 + } + ], + "title": "S3 API QPS", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Cost in US$", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "currencyUSD", + "unitScale": true + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "total" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsNull", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 64 + }, + "hideTimeOverride": false, + "id": 59, + "links": [], + "options": { + "legend": { + "calcs": [ + "lastNotNull", + "max" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true, + "width": 250 + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "sum by (type) (SeaweedFS_s3_request_total{type=~'PUT|COPY|POST|LIST', namespace=\"$NAMESPACE\"})*0.000005", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{type}} requests", + "refId": "A", + "step": 30 + }, + { + "expr": "sum (SeaweedFS_s3_request_total{type=~'PUT|COPY|POST|LIST', namespace=\"$NAMESPACE\"})*0.000005", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "All PUT, COPY, POST, LIST", + "refId": "C", + "step": 30 + }, + { + "expr": "sum (SeaweedFS_s3_request_total{type!~'PUT|COPY|POST|LIST', namespace=\"$NAMESPACE\"})*0.0000004", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "GET and all other", + "refId": "B" + }, + { + "expr": "sum by (type) (SeaweedFS_s3_request_total{type!~'PUT|COPY|POST|LIST', namespace=\"$NAMESPACE\"})*0.0000004", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{type}} requests", + "refId": "D" + } + ], + "timeFrom": "1M", + "title": "S3 API Monthly Cost if on AWS", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 71 + }, + "id": 62, + "panels": [], + "title": "Volume Server", + "type": "row" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 72 + }, + "id": 47, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(SeaweedFS_volumeServer_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le, exported_instance))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{exported_instance}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(SeaweedFS_volumeServer_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "average", + "refId": "C" + } + ], + "title": "Volume Server Request Duration 99th percentile", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short", + "unitScale": true + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsNull", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 72 + }, + "id": 40, + "links": [], + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "sum(rate(SeaweedFS_volumeServer_request_total{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (type)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{type}}", + "refId": "A", + "step": 4 + } + ], + "title": "Volume Server QPS", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 79 + }, + "id": 48, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(SeaweedFS_volumeServer_volumes{namespace=\"$NAMESPACE\"}) by (collection, type)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{collection}} {{type}}", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(SeaweedFS_volumeServer_volumes{namespace=\"$NAMESPACE\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Total", + "refId": "B" + } + ], + "title": "Volume Count", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 86 + }, + "id": 50, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "sum(SeaweedFS_volumeServer_total_disk_size{namespace=\"$NAMESPACE\"}) by (collection, type)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{collection}} {{type}}", + "refId": "A" + }, + { + "expr": "sum(SeaweedFS_volumeServer_total_disk_size{namespace=\"$NAMESPACE\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Total", + "refId": "B" + } + ], + "title": "Used Disk Space by Collection and Type", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 93 + }, + "id": 51, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "sum(SeaweedFS_volumeServer_total_disk_size{namespace=\"$NAMESPACE\"}) by (exported_instance)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{exported_instance}}", + "refId": "A" + } + ], + "title": "Used Disk Space by Host", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 93 + }, + "id": 63, + "panels": [], + "title": "Filer Store", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 101 + }, + "id": 12, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(SeaweedFS_filerStore_request_seconds_bucket{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (le, type))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{type}}", + "refId": "B" + } + ], + "title": "Filer Store Request Duration 99th percentile", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 101 + }, + "id": 14, + "links": [], + "options": { + "legend": { + "calcs": [ + "mean", + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "sum(rate(SeaweedFS_filerStore_request_total{namespace=\"$NAMESPACE\"}[$__rate_interval])) by (type)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{type}}", + "refId": "B" + } + ], + "title": "Filer Store QPS", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 108 + }, + "id": 64, + "panels": [], + "title": "Filer Instances", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 109 + }, + "id": 52, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "exemplar": true, + "expr": "go_memstats_alloc_bytes{job=\"seaweedfs-filer\", namespace=\"$NAMESPACE\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "bytes allocated", + "refId": "B" + }, + { + "exemplar": true, + "expr": "rate(go_memstats_alloc_bytes_total{job=\"seaweedfs-filer\", namespace=\"$NAMESPACE\"}[$__rate_interval])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "alloc rate", + "refId": "A" + }, + { + "exemplar": true, + "expr": "go_memstats_stack_inuse_bytes{job=\"seaweedfs-filer\", namespace=\"$NAMESPACE\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "stack inuse", + "refId": "C" + }, + { + "exemplar": true, + "expr": "go_memstats_heap_inuse_bytes{job=\"seaweedfs-filer\", namespace=\"$NAMESPACE\"}", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "heap inuse", + "refId": "D" + } + ], + "title": "Filer Go Memory Stats", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 109 + }, + "id": 54, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "exemplar": true, + "expr": "go_gc_duration_seconds{job=\"seaweedfs-filer\", namespace=\"$NAMESPACE\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{quantile}}", + "refId": "B" + } + ], + "title": "Filer Go GC duration quantiles", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 116 + }, + "id": 53, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "exemplar": true, + "expr": "go_goroutines{job=\"seaweedfs-filer\", namespace=\"$NAMESPACE\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{exported_instance}}", + "refId": "B" + } + ], + "title": "Filer Go Routines", + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Prometheus", + "value": "PBFA97CFB590B2093" + }, + "hide": 0, + "includeAll": false, + "label": "Datasource", + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": { + "selected": false, + "text": "mes", + "value": "mes" + }, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(SeaweedFS_master_is_leader,namespace)", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "NAMESPACE", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(SeaweedFS_master_is_leader,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 2, + "type": "query" + } + ] + }, + "time": { + "from": "now-1d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "SeaweedFS", + "uid": "a24009d7-cbda-4443-a132-1cc1c4677304", + "version": 1, + "weekStart": "" +} diff --git a/docs/agents/changelog.md b/docs/agents/changelog.md new file mode 100644 index 00000000..2fde1224 --- /dev/null +++ b/docs/agents/changelog.md @@ -0,0 +1,684 @@ +# Changelog Generation Instructions + +This file contains detailed instructions for AI-powered IDE on how to generate changelogs for Cozystack releases. + +## When to use these instructions + +Follow these instructions when the user explicitly asks to generate a changelog. + +## Scope and boundaries + +**Your single deliverable is the file `docs/changelogs/v.md`.** Write the complete, verified changelog to that path. That is the entire task. Exit as soon as the file is written and verified against the checklist in Step 9. + +Unless the caller explicitly instructs otherwise: + +- **In the cozystack working tree**, do not run `git commit`, `git push`, `git checkout` (to switch branches), `git branch`, `git tag`, `git reset`, `git merge`, or `git rebase`. Do not write to local branches, tags, or HEAD. `git fetch` is expected and fine (see the read-only analysis list below). +- **Do not** push to any remote, open pull requests, or issue GitHub API write calls (POST / PATCH / DELETE) for any repository. +- In the cozystack working tree, the **only** file you create or modify is `docs/changelogs/v.md`. Cloning auxiliary repositories under `_repos/` for cross-repo analysis (see Step 6) is fine; local git operations inside those disposable clones (`git checkout`, `git pull`, etc.) are allowed — just never push from them or open PRs against them. + +The caller — a GitHub Actions workflow in CI, or a developer running you interactively — owns branching, committing, pushing, and PR creation. They will perform those actions after you exit. Do not pre-empt them even if the working tree looks ready. + +Read-only analysis is expected and encouraged: `git log`, `git show`, `git fetch`, `git diff`, `gh pr view`, `gh api` GET requests, and reading any file in the repository. + +## Required Tools + +Before generating changelogs, ensure you have access to `gh` (GitHub CLI) tool, which is used to fetch commit and PR author information. The GitHub CLI is used to correctly identify PR authors from commits and pull requests. + +## Changelog Generation Process + +When the user asks to generate a changelog, follow these steps in the specified order: + +**CHECKLIST - All actions that must be completed:** +- [ ] Step 1: Update information from remote (git fetch) +- [ ] Step 2: Check current branch (must be main) +- [ ] Step 3: Determine release type and previous version (minor vs patch release) +- [ ] Step 4: Determine versions and analyze existing changelogs +- [ ] Step 5: Get the list of commits for the release period +- [ ] Step 6: Check additional repositories (website is REQUIRED, optional repos if tags exist) + - [ ] **MANDATORY**: Check website repository for documentation changes WITH authors and PR links via GitHub CLI + - [ ] **MANDATORY**: Check ALL optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy, external-apps-example, ansible-cozystack) for tags during release period + - [ ] **MANDATORY**: For ALL commits from additional repos, get GitHub username via CLI, prioritizing PR author over commit author. +- [ ] Step 7: Analyze commits (extract PR numbers, authors, user impact) + - [ ] **MANDATORY**: For EVERY PR in main repo, get PR author via `gh pr view --json author --jq .author.login` (do NOT skip this step) + - [ ] **MANDATORY**: Extract PR numbers from commit messages, then use `gh pr view` for each PR to get the PR author. Do NOT use commit author. Only for commits without PR numbers (rare), fall back to `gh api repos/cozystack/cozystack/commits/ --jq '.author.login'` +- [ ] Step 8: Form new changelog (structure, format, generate contributors list) +- [ ] Step 9: Verify completeness and save + +### 1. Updating information from remote + +```bash +git fetch --tags --force --prune +``` + +This is necessary to get up-to-date information about tags and commits from the remote repository. + +### 2. Checking current branch + +Make sure we are on the `main` branch: + +```bash +git branch --show-current +``` + +### 3. Determining release type and previous version + +**Important**: Determine if you're generating a changelog for a **minor release** (vX.Y.0) or a **patch release** (vX.Y.Z where Z > 0). + +**For minor releases (vX.Y.0):** +- Each minor version lives and evolves in its own branch (`release-X.Y`) +- You MUST compare with the **previous minor version** (v(X-1).Y.0), not the last patch release +- This ensures you capture all changes from the entire minor version cycle, including all patch releases +- Example: For v0.38.0, compare with v0.37.0 (not v0.37.8) +- Run a separate cycle to check the diff with the zero version of the previous minor release + +**For patch releases (vX.Y.Z where Z > 0):** +- Compare with the previous patch version (vX.Y.(Z-1)) +- Example: For v0.37.2, compare with v0.37.1 + +### 4. Determining versions and analyzing existing changelogs + +**Determine the last published version:** +1. Get the list of version tags: + ```bash + git tag -l 'v[0-9]*.[0-9]*.[0-9]*' | sort -V + ``` + +2. Get the last tag: + ```bash + git tag -l 'v[0-9]*.[0-9]*.[0-9]*' | sort -V | tail -1 + ``` + +3. Compare tags with existing changelog files in `docs/changelogs/` to determine the last published version (the newest file `vX.Y.Z.md`) + +**Study existing changelog format:** +- Review recent changelog files to understand the format and structure +- Pay attention to: + - **Feature Highlights format** (for minor releases): Use `## Feature Highlights` with `### Feature Name` subsections containing detailed descriptions (2-4 paragraphs each). See v0.35.0 and v0.36.0 for examples. + - Section structure (Major Features and Improvements, Security, Fixes, Dependencies, etc.) + - PR link format (e.g., `[**@username**](https://github.com/username) in #1234`) + - Change description style + - Presence of Breaking changes sections, etc. + +### 5. Getting the list of commits + +**Important**: Determine if you're generating a changelog for a **minor release** (vX.Y.0) or a **patch release** (vX.Y.Z where Z > 0). + +**For patch releases (vX.Y.Z where Z > 0):** +Get the list of commits starting from the previous patch version to HEAD: + +**⚠️ CRITICAL: Do NOT use --first-parent flag! It will skip merge commits including backports!** + +```bash +# Get all commits including merge commits (backports) +git log ..HEAD --pretty=format:"%h - %s (%an, %ar)" +``` + +For example, if generating changelog for `v0.37.2`: +```bash +git log v0.37.1..HEAD --pretty=format:"%h - %s (%an, %ar)" +``` + +**⚠️ IMPORTANT: Check for backports:** +- Look for commits with "[Backport release-X.Y]" in the commit message +- For backport PRs, find the original PR number mentioned in the backport commit message or PR description +- Use the original PR author (not the backport PR author) when creating changelog entries +- Include both the original PR number and backport PR number in the changelog entry (e.g., `#1606, #1609`) + +**For minor releases (vX.Y.0):** +Minor releases must include **all changes** from patch releases of the previous minor version. Get commits from the previous minor release: + +**⚠️ CRITICAL: Do NOT use --first-parent flag! It will skip merge commits including backports!** + +```bash +# For v0.38.0, get all commits since v0.37.0 (including all patch releases v0.37.1, v0.37.2, etc.) +git log v..HEAD --pretty=format:"%h - %s (%an, %ar)" +``` + +For example, if generating changelog for `v0.38.0`: +```bash +git log v0.37.0..HEAD --pretty=format:"%h - %s (%an, %ar)" +``` + +This will include all commits from v0.37.1, v0.37.2, v0.37.3, etc., up to v0.38.0. + +**⚠️ IMPORTANT: Always check merge commits:** +- Merge commits may contain backports that need to be included +- Check all commits in the range, including merge commits +- For backports, always find and reference the original PR + +### 6. Analyzing additional repositories + +**⚠️ CRITICAL: This step is MANDATORY and must NOT be skipped!** + +Cozystack release may include changes from related repositories. Check and include commits from these repositories if tags were released during the release period: + +**Required repositories:** +- **Documentation**: [https://github.com/cozystack/website](https://github.com/cozystack/website) + - **MANDATORY**: Always check this repository for documentation changes during the release period + - **MANDATORY**: Get GitHub username for EVERY commit. Extract PR number from commit message, then use `gh pr view --repo cozystack/website --json author --jq .author.login` to get PR author. Only if no PR number, fall back to `gh api repos/cozystack/website/commits/ --jq '.author.login'` + +**Optional repositories (MUST check ALL of them for tags during release period):** +- [https://github.com/cozystack/talm](https://github.com/cozystack/talm) +- [https://github.com/cozystack/boot-to-talos](https://github.com/cozystack/boot-to-talos) +- [https://github.com/cozystack/cozyhr](https://github.com/cozystack/cozyhr) +- [https://github.com/cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) +- [https://github.com/cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) +- [https://github.com/cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) + +**⚠️ IMPORTANT**: You MUST check ALL optional repositories for tags created during the release period. Do NOT skip this step even if you think there might not be any tags. Use the process below to verify. + +**Process for each repository:** + +1. **Get release period dates:** + ```bash + # Get dates for the release period + cd /path/to/cozystack + RELEASE_START=$(git log -1 --format=%ai v) + RELEASE_END=$(git log -1 --format=%ai HEAD) + ``` + +2. **Check for commits in website repository (always required):** + ```bash + # Ensure website repository is cloned and up-to-date + mkdir -p _repos + if [ ! -d "_repos/website" ]; then + cd _repos && git clone https://github.com/cozystack/website.git && cd .. + fi + cd _repos/website + git fetch --all --tags --force + git checkout main 2>/dev/null || git checkout master + git pull + + # Get commits between release dates (with some buffer) + git log --since="$RELEASE_START" --until="$RELEASE_END" --format="%H|%s|%an" | while IFS='|' read -r commit_hash subject author_name; do + # Extract PR number from commit message + PR_NUMBER=$(git log -1 --format="%B" "$commit_hash" | grep -oE '#[0-9]+' | head -1 | tr -d '#') + + # ALWAYS use PR author if PR number found, not commit author + if [ -n "$PR_NUMBER" ]; then + GITHUB_USERNAME=$(gh pr view "$PR_NUMBER" --repo cozystack/website --json author --jq '.author.login // empty' 2>/dev/null) + echo "$commit_hash|$subject|$author_name|$GITHUB_USERNAME|cozystack/website#$PR_NUMBER" + else + # Only fallback to commit author if no PR number found (rare) + GITHUB_USERNAME=$(gh api repos/cozystack/website/commits/$commit_hash --jq '.author.login // empty') + echo "$commit_hash|$subject|$author_name|$GITHUB_USERNAME|cozystack/website@${commit_hash:0:7}" + fi + done + + # Look for documentation updates, new pages, or significant content changes + # Include these in the "Documentation" section of the changelog WITH authors and PR links + ``` + +3. **For optional repositories, check if tags exist during release period:** + + **⚠️ MANDATORY: You MUST check ALL optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy, external-apps-example, ansible-cozystack). Do NOT skip any repository!** + + **Use the helper script:** + ```bash + # Get release period dates + RELEASE_START=$(git log -1 --format=%ai v) + RELEASE_END=$(git log -1 --format=%ai HEAD) + + # Run the script to check all optional repositories + ./docs/changelogs/hack/check-optional-repos.sh "$RELEASE_START" "$RELEASE_END" + ``` + + The script will: + - Check ALL optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy, external-apps-example, ansible-cozystack) + - Look for tags created during the release period + - Get commits between tags (if tags exist) or by date range (if no tags) + - Extract PR numbers from commit messages + - For EVERY commit with PR number, get PR author via CLI: `gh pr view --repo cozystack/ --json author --jq .author.login` (ALWAYS use PR author, not commit author) + - For commits without PR numbers (rare), fallback to: `gh api repos/cozystack//commits/ --jq '.author.login'` + - Output results in format: `commit_hash|subject|author_name|github_username|cozystack/repo#PR_NUMBER` or `cozystack/repo@commit_hash` + +4. **Extract PR numbers and authors using GitHub CLI:** + - **ALWAYS use PR author, not commit author** for commits from additional repositories + - For each commit, extract PR number from commit message first: Extract `#123` pattern from commit message + - If PR number found, use `gh pr view --repo cozystack/ --json author --jq .author.login` to get PR author (the person who wrote the code) + - Only if no PR number found (rare), fallback to commit author: `gh api repos/cozystack//commits/ --jq '.author.login'` + - **Prefer PR numbers**: Use format `cozystack/website#123` if PR number found in commit message + - **Fallback to commit hash**: Use format `cozystack/website@abc1234` if no PR number + - **ALWAYS include author**: Every entry from additional repositories MUST include author in format `([**@username**](https://github.com/username) in cozystack/repo#123)` + - Determine user impact and categorize appropriately + - Format entries with repository prefix: `[website]`, `[talm]`, etc. + +**Example entry format for additional repositories:** +```markdown +# If PR number found in commit message (REQUIRED format): +* **[website] Update installation documentation**: Improved installation guide with new examples ([**@username**](https://github.com/username) in cozystack/website#123). + +# If no PR number (fallback, use commit hash): +* **[website] Update installation documentation**: Improved installation guide with new examples ([**@username**](https://github.com/username) in cozystack/website@abc1234). + +# For optional repositories: +* **[talm] Add new feature**: Description of the change ([**@username**](https://github.com/username) in cozystack/talm#456). +``` + +**CRITICAL**: +- **ALWAYS include author** for every entry from additional repositories +- **ALWAYS include PR link or commit hash** for every entry +- Never add entries without author and PR/commit reference +- **ALWAYS use PR author, not commit author**: Extract PR number from commit message, then use `gh pr view --repo cozystack/ --json author --jq .author.login` to get the PR author (the person who wrote the code) +- Only if no PR number found (rare), fallback to commit author: `gh api repos/cozystack//commits/ --jq '.author.login'` +- The commit author (especially for squash/merge commits) is usually the person who merged the PR, not the person who wrote the code + +### 7. Analyzing commits and PRs + +**⚠️ CRITICAL: You MUST get the author from PR, not from commit! Always use `gh pr view` to get the PR author. Do NOT use commit author!** + +**Get all PR numbers from commits:** +**⚠️ CRITICAL: Do NOT use --no-merges flag! It will skip merge commits including backports!** + +```bash +# Extract all PR numbers from commit messages in the release range (including merge commits) +git log .. --format="%s%n%b" | grep -oE '#[0-9]+' | sort -u | tr -d '#' +``` + +**⚠️ IMPORTANT: Handle backports correctly:** +- Backport PRs have format: `[Backport release-X.Y] (#BACKPORT_PR_NUMBER)` +- The backport commit message or PR description usually mentions the original PR number +- For backport entries in changelog, use the original PR author (not the backport PR author) +- Include both original and backport PR numbers in the changelog entry (e.g., `#1606, #1609`) +- To find original PR from backport: Check the backport PR description or commit message for "Backport of #ORIGINAL_PR" + +**For each PR number, get the author:** + + **CRITICAL**: The commit author (especially for squash/merge commits) is usually the person who merged the PR (or GitHub bot), NOT the person who wrote the code. **ALWAYS use the PR author**, not the commit author. + + **⚠️ MANDATORY: ALWAYS use `gh pr view` to get the PR author. Do NOT use commit author!** + + **ALWAYS use GitHub CLI** to get the PR author: + + ```bash + # Usage: Get PR author - MANDATORY for EVERY PR + # Loop through ALL PR numbers and get PR author (including backports) + git log .. --format="%s%n%b" | grep -oE '#[0-9]+' | sort -u | tr -d '#' | while read PR_NUMBER; do + # Check if this is a backport PR + BACKPORT_INFO=$(gh pr view "$PR_NUMBER" --json body --jq '.body' 2>/dev/null | grep -i "backport of #" || echo "") + if [ -n "$BACKPORT_INFO" ]; then + # Extract original PR number from backport description + ORIGINAL_PR=$(echo "$BACKPORT_INFO" | grep -oE 'backport of #([0-9]+)' | grep -oE '[0-9]+' | head -1) + if [ -n "$ORIGINAL_PR" ]; then + # Use original PR author + GITHUB_USERNAME=$(gh pr view "$ORIGINAL_PR" --json author --jq '.author.login // empty') + PR_TITLE=$(gh pr view "$ORIGINAL_PR" --json title --jq '.title // empty') + echo "$PR_NUMBER|$ORIGINAL_PR|$GITHUB_USERNAME|$PR_TITLE|BACKPORT" + else + # Fallback to backport PR author if original not found + GITHUB_USERNAME=$(gh pr view "$PR_NUMBER" --json author --jq '.author.login // empty') + PR_TITLE=$(gh pr view "$PR_NUMBER" --json title --jq '.title // empty') + echo "$PR_NUMBER||$GITHUB_USERNAME|$PR_TITLE|BACKPORT" + fi + else + # Regular PR + GITHUB_USERNAME=$(gh pr view "$PR_NUMBER" --json author --jq '.author.login // empty') + PR_TITLE=$(gh pr view "$PR_NUMBER" --json title --jq '.title // empty') + echo "$PR_NUMBER||$GITHUB_USERNAME|$PR_TITLE|REGULAR" + fi + done + ``` + + **⚠️ IMPORTANT**: You must run this for EVERY PR in the release period. Do NOT skip any PRs or assume the GitHub username based on the git author name. + + **CRITICAL**: Always use `gh pr view --json author --jq .author.login` to get the PR author. This correctly identifies the person who wrote the code, not the person who merged it (which is especially important for squash merges). + + **Why this matters**: Using the wrong author in changelogs gives incorrect credit and can confuse contributors. The merge/squash commit is created by the person who clicks "Merge" in GitHub, not the PR author. + +**For commits without PR numbers (rare):** +- Only if a commit has no PR number, fall back to commit author: `gh api repos/cozystack/cozystack/commits/ --jq '.author.login'` +- But this should be very rare - most commits should have PR numbers + +**Extract PR number from commit messages:** +- Check commit message subject (`%s`) and body (`%b`) for PR references: `#1234` or `(#1234)` +- **Primary method**: Extract from commit message format `(#PR_NUMBER)` or `in #PR_NUMBER` or `Merge pull request #1234` +- Use regex: `grep -oE '#[0-9]+'` to find all PR numbers + +**⚠️ CRITICAL: Verify PR numbers match commit messages!** +- Always verify that the PR number in the changelog matches the PR number in the commit message +- Common mistake: Using wrong PR number (e.g., #1614 instead of #1617) when multiple similar commits exist +- To verify: Check the actual commit message: `git log -1 --format="%s%n%b" | grep -oE '#[0-9]+'` +- If multiple PR numbers appear in a commit, use the one that matches the PR title/description +- For merge commits, check the merged branch commits, not just the merge commit message + +3. **Understand the change:** + ```bash + # Get PR details (preferred method) + gh pr view --json title,body,url + + # Or get commit details if no PR number + git show --stat + git show + ``` + - Review PR description and changed files + - Understand functionality added/changed/fixed + - **Determine user impact**: What can users do now? What problems are fixed? What improvements do users experience? + +4. **For release branches (backports):** + - If commit is from `release-X.Y` branch, check if it's a backport + - Find original commit in `main` to get correct PR number: + ```bash + git log origin/main --grep="" --oneline + ``` + +### 8. Forming a new changelog + +Create a new changelog file in the format matching previous versions: + +1. **Determine the release type:** + - **Minor release (vX.Y.0)** - use full format with **Feature Highlights** section. **Must include all changes from patch releases of the previous minor version** (e.g., v0.38.0 should include changes from v0.37.1, v0.37.2, v0.37.3, etc.) + - **Patch release (vX.Y.Z, where Z > 0)** - use more compact format, includes only changes since the previous patch release + + **Feature Highlights format for minor releases:** + - Use section header: `## Feature Highlights` + - Include 3-6 major features as subsections with `### Feature Name` headers + - Each feature subsection should contain: + - **Detailed description** (2-4 paragraphs) explaining: + - What the feature is and what problem it solves + - How it works and what users can do with it + - How to use it (if applicable) + - Benefits and impact for users + - **Links to documentation** when available (use markdown links) + - **Code examples or configuration snippets** if helpful + - Focus on user value and practical implications, not just technical details + - Each feature should be substantial enough to warrant its own subsection + - Order features by importance/impact (most important first) + - Example format: + ```markdown + ## Feature Highlights + + ### Feature Name + + Detailed description paragraph explaining what the feature is... + + Another paragraph explaining how it works and what users can do... + + Learn more in the [documentation](https://cozystack.io/docs/...). + ``` + + **Important for minor releases**: After collecting all commits, **systematically verify** that all PRs from patch releases are included: + ```bash + # Extract all PR numbers from patch release changelogs + grep -h "#[0-9]\+" docs/changelogs/v.*.md | sort -u + + # Extract all PR numbers from the new minor release changelog + grep -h "#[0-9]\+" docs/changelogs/v.0.md | sort -u + + # Compare and identify missing PRs + # Ensure every PR from patch releases appears in the minor release changelog + ``` + +2. **Structure changes by categories:** + + **For minor releases (vX.Y.0):** + - **Feature Highlights** (required) - see format above + - **Major Features and Improvements** - detailed list of all major features and improvements + - **Improvements (minor)** - smaller improvements and enhancements + - **Bug fixes** - all bug fixes + - **Security** - security-related changes + - **Dependencies & version updates** - dependency updates + - **System Configuration** - system-level configuration changes + - **Development, Testing, and CI/CD** - development and testing improvements + - **Documentation** (include changes from website repository here - **MUST include authors and PR links for all entries**) + - **Breaking changes & upgrade notes** (if any) + - **Refactors & chores** (if any) + + **For patch releases (vX.Y.Z where Z > 0):** + - **Features and Improvements** - new features and improvements + - **Fixes** - bug fixes + - **Security** - security-related changes + - **Dependencies** - dependency updates + - **System Configuration** - system-level configuration changes + - **Development, Testing, and CI/CD** - development and testing improvements + - **Documentation** (include changes from website repository here - **MUST include authors and PR links for all entries**) + - **Migration and Upgrades** (if applicable) + + **Note**: When including changes from additional repositories, group them logically with main repository changes, or create separate subsections if there are many changes from a specific repository. + +3. **Entry format:** + - Use the format: `* **Brief description**: detailed description ([**@username**](https://github.com/username) in #PR_NUMBER)` + - **CRITICAL - Get authorship correctly**: + - **ALWAYS use PR author, not commit author**: Extract PR number from commit message, then use `gh pr view` to get the PR author. The commit author (especially for squash/merge commits) is usually the person who merged the PR (or GitHub bot), NOT the person who wrote the code. + ```bash + # Get PR author from GitHub CLI (correct method) + # Step 1: Extract PR number from commit message + PR_NUMBER=$(git log -1 --format="%s%n%b" | grep -oE '#[0-9]+' | head -1 | tr -d '#') + + # Step 2: Get PR author (the person who wrote the code) + if [ -n "$PR_NUMBER" ]; then + GITHUB_USERNAME=$(gh pr view "$PR_NUMBER" --json author --jq '.author.login') + else + # Only fallback to commit author if no PR number found (rare) + GITHUB_USERNAME=$(gh api repos/cozystack/cozystack/commits/ --jq '.author.login') + fi + ``` + **Example**: For PR #1507, the squash commit has author "kvaps" (who merged), but the PR author is "lllamnyp" (who wrote the code). Using `gh pr view 1507 --json author --jq .author.login` correctly returns "lllamnyp". + - **For regular commits**: Use the commit author directly: + ```bash + git log -1 --format="%an|%ae" + ``` + - **Validation**: Before adding to changelog, verify the author by checking: + - For merge commits: Compare merge commit author vs PR author (they should be different) + - Check existing changelogs for author name to GitHub username mappings + - Verify with: `git log ^1..^2 --format="%an" --no-merges` + - **Map author name to GitHub username**: Check existing changelogs for author name mappings, or extract from PR links in commit messages + - **Always include user impact**: Each entry must explain how the change affects users + - For new features: explain what users can now do + - For bug fixes: explain what problem is solved for users + - For improvements: explain what users will experience better + - For breaking changes: clearly state what users need to do + - Group related changes + - Use bold font for important components/modules + - Focus on user value, not just technical details + +4. **Add a link to the full changelog:** + + **For patch releases (vX.Y.Z where Z > 0):** + ```markdown + **Full Changelog**: https://github.com/cozystack/cozystack/compare/v...v + ``` + Example: For v0.37.2, use `v0.37.1...v0.37.2` + + **For minor releases (vX.Y.0):** + ```markdown + **Full Changelog**: https://github.com/cozystack/cozystack/compare/v...v + ``` + Example: For v0.38.0, use `v0.37.0...v0.38.0` (NOT `v0.37.8...v0.38.0`) + + **Important**: Minor releases must reference the previous minor release (vX.Y.0), not the last patch release, to include all changes from the entire minor version cycle. + +5. **Generate contributors list:** + + **⚠️ SIMPLIFIED APPROACH: Extract contributors from the generated changelog itself!** + + Since you've already generated the changelog with all PR authors correctly identified, simply extract GitHub usernames from the changelog entries: + + ```bash + # Extract all GitHub usernames from the current release changelog + # This method is simpler and more reliable than extracting from git history + + # For patch releases: extract from the current changelog file + grep -oE '\[@[a-zA-Z0-9_-]+\]' docs/changelogs/v.md | \ + sed 's/\[@/@/' | sed 's/\]//' | \ + sort -u + + # For minor releases: extract from the current changelog file + grep -oE '\[@[a-zA-Z0-9_-]+\]' docs/changelogs/v.md | \ + sed 's/\[@/@/' | sed 's/\]//' | \ + sort -u + ``` + + **Get all previous contributors (to identify new ones):** + ```bash + # Extract GitHub usernames from all previous changelogs + grep -hE '\[@[a-zA-Z0-9_-]+\]' docs/changelogs/v*.md | \ + grep -oE '@[a-zA-Z0-9_-]+' | \ + sort -u > /tmp/previous_contributors.txt + ``` + + **Identify new contributors (first-time contributors):** + ```bash + # Get current release contributors from the changelog + grep -oE '@[a-zA-Z0-9_-]+' docs/changelogs/v.md | \ + sort -u > /tmp/current_contributors.txt + + # Get all previous contributors + grep -hE '@[a-zA-Z0-9_-]+' docs/changelogs/v*.md | \ + grep -oE '@[a-zA-Z0-9_-]+' | \ + sort -u > /tmp/all_previous_contributors.txt + + # Find new contributors (those in current but not in previous) + comm -23 <(sort /tmp/current_contributors.txt) <(sort /tmp/all_previous_contributors.txt) + ``` + + **Why this approach is better:** + - ✅ Uses the already-verified PR authors from the changelog (no need to query GitHub API again) + - ✅ Automatically handles backports correctly (original PR authors are already in the changelog) + - ✅ Simpler and faster (no git log parsing or API calls) + - ✅ More reliable (matches exactly what's in the changelog) + - ✅ Works for both patch and minor releases + + **Add contributors section to changelog:** + + Place the contributors section at the end of the changelog, before the "Full Changelog" link: + ```markdown + ## Contributors + + We'd like to thank all contributors who made this release possible: + + * [**@username1**](https://github.com/username1) + * [**@username2**](https://github.com/username2) + * [**@username3**](https://github.com/username3) + * ... + + ### New Contributors + + We're excited to welcome our first-time contributors: + + * [**@newuser1**](https://github.com/newuser1) - First contribution! + * [**@newuser2**](https://github.com/newuser2) - First contribution! + ``` + + **Formatting guidelines:** + - List contributors in alphabetical order by GitHub username + - Use the format: `* [**@username**](https://github.com/username)` + - For new contributors, add " - First contribution!" note + - If GitHub username cannot be determined, you can skip that contributor or use their git author name + + **When to include:** + - **For patch releases**: Contributors section is optional, but can be included for significant releases + - **For minor releases (vX.Y.0)**: Contributors section is required - you must generate and include the contributors list + - Always verify GitHub usernames by checking commit messages, PR links in changelog entries, or by examining PR details + +6. **Add a comment with a link to the GitHub release:** + ```markdown + + ``` + +### 9. Verification and saving + +**Before saving, verify completeness:** + +**For ALL releases:** +- [ ] Step 5 completed: **ALL commits included** (including merge commits and backports) - do not skip any commits +- [ ] Step 5 completed: **Backports identified and handled correctly** - original PR author used, both original and backport PR numbers included +- [ ] Step 6 completed: Website repository checked for documentation changes WITH authors and PR links via GitHub CLI +- [ ] Step 6 completed: **ALL** optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy, external-apps-example, ansible-cozystack) checked for tags during release period +- [ ] Step 6 completed: For ALL commits from additional repos, GitHub username obtained via GitHub CLI (not skipped). For commits with PR numbers, PR author used via `gh pr view` (not commit author) +- [ ] Step 7 completed: For EVERY PR in main repo (including backports), PR author obtained via `gh pr view --json author --jq .author.login` (not skipped or assumed). Commit author NOT used - always use PR author +- [ ] Step 7 completed: **Backports verified** - for each backport PR, original PR found and original PR author used in changelog +- [ ] Step 8 completed: Contributors list generated +- [ ] All commits from main repository included (including merge commits) +- [ ] User impact described for each change +- [ ] Format matches existing changelogs + +**For patch releases:** +- [ ] All commits from the release period are included (including merge commits with backports) +- [ ] PR numbers match commit messages +- [ ] Backports are properly identified and linked to original PRs + +**For minor releases (vX.Y.0):** +- [ ] All changes from patch releases (vX.Y.1, vX.Y.2, etc.) are included +- [ ] Contributors section is present and complete +- [ ] Full Changelog link references previous minor version (vX.Y.0), not last patch +- [ ] Verify all PRs from patch releases are included: + ```bash + # Extract and compare PR numbers + PATCH_PRS=$(grep -hE "#[0-9]+" docs/changelogs/v.*.md | grep -oE "#[0-9]+" | sort -u) + MINOR_PRS=$(grep -hE "#[0-9]+" docs/changelogs/v.0.md | grep -oE "#[0-9]+" | sort -u) + MISSING=$(comm -23 <(echo "$PATCH_PRS") <(echo "$MINOR_PRS")) + + if [ -n "$MISSING" ]; then + echo "Missing PRs from patch releases:" + echo "$MISSING" + # For each missing PR, check if it's a backport and verify change is included by description + fi + ``` + +**Only proceed to save after all checkboxes are verified!** + +**Save the changelog:** +Save the changelog to file `docs/changelogs/v.md` according to the version for which the changelog is being generated. + +**Then exit.** Do not commit, push, create a branch, or open a pull request — the caller handles all git and GitHub operations after you return. See the "Scope and boundaries" section at the top of this document. + +### Important notes + +- **After fetch with --force** local tags are up-to-date, use them for work +- **For release branches** always check original commits in `main` to get correct PR numbers +- **Preserve the format** of existing changelog files +- **Group related changes** logically +- **Be accurate** in describing changes, based on actual commit diffs +- **Check for PR numbers** and commit authors +- **CRITICAL - Get authorship from PR, not from commit**: + - **ALWAYS use PR author**: Extract PR number from commit message, then use `gh pr view --json author --jq .author.login` to get the PR author + - Do NOT use commit author - the commit author (especially for squash/merge commits) is usually the person who merged the PR, not the person who wrote the code + - For commits without PR numbers (rare), fall back to commit author: `gh api repos/cozystack/cozystack/commits/ --jq '.author.login'` + - **Workflow**: Extract PR numbers from commits → Use `gh pr view` for each PR → Get PR author (the person who wrote the code) + - Example: For PR #1507, the commit author is `@kvaps` (who merged), but `gh pr view 1507 --json author --jq .author.login` correctly returns `@lllamnyp` (who wrote the code) + - Check existing changelogs for author name to GitHub username mappings + - **Validation**: Before adding to changelog, always verify the author using `gh pr view` - never use commit author for PRs +- **MANDATORY**: Always describe user impact: Every changelog entry must explain how the change affects end users, not just what was changed technically. Focus on user value and practical implications. + +**Required steps:** + +- **Additional repositories (Step 6) - MANDATORY**: + - **⚠️ CRITICAL**: Always check the **website** repository for documentation changes during the release period. This is a required step and MUST NOT be skipped. + - **⚠️ CRITICAL**: You MUST check ALL optional repositories (talm, boot-to-talos, cozyhr, cozy-proxy, external-apps-example, ansible-cozystack) for tags during the release period. Do NOT skip any repository even if you think there might not be tags. + - **CRITICAL**: For ALL entries from additional repositories (website and optional), you MUST: + - **MANDATORY**: Extract PR number from commit message first + - **MANDATORY**: For commits with PR numbers, ALWAYS use `gh pr view --repo cozystack/ --json author --jq .author.login` to get PR author (not commit author) + - **MANDATORY**: Only for commits without PR numbers (rare), fallback to: `gh api repos/cozystack//commits/ --jq '.author.login'` + - **MANDATORY**: Do NOT skip getting GitHub username via CLI - do this for EVERY commit + - **MANDATORY**: Do NOT use commit author for PRs - always use PR author + - Include PR link or commit hash reference + - Format: `* **[repo] Description**: details ([**@username**](https://github.com/username) in cozystack/repo#123)` + - For **optional repositories** (talm, boot-to-talos, cozyhr, cozy-proxy, external-apps-example, ansible-cozystack), you MUST check ALL of them for tags during the release period. Use the loop provided in Step 6 to check each repository systematically. + - When including changes from additional repositories, use the format: `[repo-name] Description` and link to the repository's PR/issue if available + - **Prefer PR numbers over commit hashes**: For commits from additional repositories, extract PR number from commit message using GitHub API. Use PR format (`cozystack/website#123`) instead of commit hash (`cozystack/website@abc1234`) when available + - **Never add entries without author and PR/commit reference**: Every entry from additional repositories must have both author and link + - Group changes from additional repositories with main repository changes, or create separate subsections if there are many changes from a specific repository + +- **PR author verification (Step 7) - MANDATORY**: + - **⚠️ CRITICAL**: You MUST get the author from PR using `gh pr view`, NOT from commit + - **⚠️ CRITICAL**: Extract PR numbers from commit messages, then use `gh pr view --json author --jq .author.login` for each PR + - **⚠️ CRITICAL**: Do NOT use commit author - commit author is usually the person who merged, not the person who wrote the code + - **⚠️ CRITICAL**: Do NOT skip this step for any PR, even if the author seems obvious + - For commits without PR numbers (rare), fall back to: `gh api repos/cozystack/cozystack/commits/ --jq '.author.login'` + - This ensures correct attribution and prevents errors in changelog entries (especially important for squash/merge commits) + +- **Contributors list (Step 8)**: + - For minor releases (vX.Y.0): You must generate a list of all contributors and identify first-time contributors. + - For patch releases: Contributors section is optional, but recommended for significant releases + - Extract GitHub usernames from PR links in commit messages or changelog entries + - This helps recognize community contributions and welcome new contributors +- **Minor releases (vX.Y.0)**: + - Must include **all changes** from patch releases of the previous minor version (e.g., v0.38.0 includes all changes from v0.37.1, v0.37.2, v0.37.3, etc.) + - The "Full Changelog" link must reference the previous minor release (v0.37.0...v0.38.0), NOT the last patch release (v0.37.8...v0.38.0) + - This ensures users can see the complete set of changes for the entire minor version cycle + - **Verification step**: After creating the changelog, extract all PR numbers from patch release changelogs and verify they all appear in the minor release changelog to prevent missing entries + - **Backport handling**: Patch releases may contain backports with different PR numbers (e.g., #1624 in patch release vs #1622 in main). For minor releases, use original PR numbers from main when available, but verify that all changes from patch releases are included regardless of PR number differences + - **Content verification**: Don't rely solely on PR number matching - verify that change descriptions from patch releases appear in the minor release changelog, as backports may have different PR numbers + diff --git a/docs/agents/contributing.md b/docs/agents/contributing.md new file mode 100644 index 00000000..88b062ea --- /dev/null +++ b/docs/agents/contributing.md @@ -0,0 +1,188 @@ +# Contributing Conventions for AI Agents + +Project-side conventions for commits, branches, and pull requests in Cozystack. + +## Checklist for Creating a Pull Request + +- [ ] Commit message follows Conventional Commits format +- [ ] Commit is signed off with `--signoff` +- [ ] Branch is rebased on `upstream/main` (no extra commits) +- [ ] PR body includes description and release note +- [ ] Ran `make generate` in every package whose `values.yaml`, `values.schema.json`, `Chart.yaml`, or `README.md` was touched, and committed the regenerated files + +## Regenerate Artifacts Before Committing + +Several files in each package are produced by `make generate` from `values.yaml` + `values.schema.json` and must stay in sync with the hand-edited sources: + +- `packages/(apps|extra)//README.md` — regenerated by `cozyvalues-gen` (parameter table, formatting). +- `packages/(apps|extra)//values.schema.json` — `cozyvalues-gen` rewrites ordering and derived fields. +- `packages/system/-rd/cozyrds/.yaml` — produced by `hack/update-crd.sh`, which `make generate` invokes. + +**Before committing edits to any of those sources**, run `make generate` inside the package and stage the full diff: + +```bash +make -C packages// generate +git add packages/// packages/system/-rd/ +``` + +The repo's pre-commit CI job runs `make generate` in every package and then `git diff --exit-code`. Any unstaged generator output fails the job with exit code 123 and blocks the PR. Also rerun `make generate` after a `git commit --amend` if the amended change touched any of the sources above. + +To locate packages a WIP branch likely needs to be regenerated: + +```bash +git diff --name-only | xargs -n1 dirname | sort -u | grep ^packages/ +``` + +## Commit Format + +Follow [Conventional Commits](https://www.conventionalcommits.org/) with `--signoff`: + +```bash +git commit --signoff -m "type(scope): brief description" +``` + +**Types:** `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore` + +**Scopes** (examples — not an exhaustive list; pick the most specific scope that describes the change, and introduce a new one if a genuinely new area needs its own): + +- System, e.g.: `dashboard`, `platform`, `operator`, `cilium`, `kube-ovn`, `linstor`, `fluxcd`, `cluster-api` +- Apps, e.g.: `postgres`, `mariadb`, `redis`, `kafka`, `clickhouse`, `virtual-machine`, `kubernetes` +- Other, e.g.: `api`, `hack`, `tests`, `ci`, `docs`, `agents`, `maintenance` + +Breaking changes: append `!` after type/scope (`feat(api)!: ...`) or add a `BREAKING CHANGE:` footer. + +**Examples:** +```bash +git commit --signoff -m "feat(dashboard): add config hash annotations to restart pods on config changes" +git commit --signoff -m "fix(postgres): update operator to version 1.2.3" +git commit --signoff -m "docs(contributing): add installation guide" +``` + +## PR Title Auto-Labeling + +`.github/workflows/pr-labeler.yaml` parses the PR title on `opened`, `edited`, `reopened`, and `synchronize` events and applies labels additively (never removes). The title is expected to follow Conventional Commits — same format as commit messages above. + +**Type → `kind/*`:** + +| type | label | +| --------- | ------------------ | +| feat | kind/feature | +| fix | kind/bug | +| docs | kind/documentation | +| chore | kind/cleanup | +| refactor | kind/cleanup | +| style, perf, test, build, ci, revert | (no kind label) | + +**Scope → `area/*`** (full mapping in `.github/workflows/pr-labeler.yaml`): + +| scope (examples) | label | +| --- | --- | +| agents, ai | area/ai | +| api, cozystack-api | area/api | +| build | area/build | +| ci | area/ci | +| dashboard | area/dashboard | +| postgres, mariadb, redis, etcd, kafka, clickhouse, postgres-operator, mariadb-operator | area/database | +| extra | area/extra | +| kubernetes | area/kubernetes | +| monitoring, vlogs, vmstack, grafana, workloadmonitor | area/monitoring | +| ingress, gateway, vpn, metallb, cilium, kube-ovn, cozy-proxy, ... | area/networking | +| platform, bundle, flux, fluxcd, cluster-api, talos, installer, cozyctl, cozystack-engine, cozy-lib | area/platform | +| backport, release | area/release | +| seaweedfs, bucket, linstor, velero, harbor, backups | area/storage | +| tests, e2e | area/testing | +| kubevirt, cdi, vmi, vm-import, virtual-machine, hami, gpu-operator | area/virtualization | + +**Special handling:** + +- `[Backport release-1.x]` prefix is stripped before parsing; `area/release` and `backport` labels are added. +- Composite scope (`feat(platform, system, apps): ...`) — each comma-separated part is mapped independently. +- `!` after type or `BREAKING CHANGE:` footer in the body → `kind/breaking-change`. +- Unmapped scope or non-conventional title → `area/uncategorized` (signals the PR needs manual area selection). +- Bracket-style fallback (`[scope] description`) maps `scope` → `area/*` but cannot infer `kind/*`. + +### AI Agent Attribution + +When an AI agent authors or materially assists with a commit, add an `Assisted-By:` trailer naming the model: + +```text +Assisted-By: Claude +Assisted-By: GPT-5 +Assisted-By: Gemini +``` + +This sits alongside the `Signed-off-by:` trailer produced by `--signoff`. Use one trailer per model if multiple contributed. + +## Rebasing on upstream/main + +If the branch has extra commits, clean it up: + +```bash +git fetch upstream +git checkout -b my-feature upstream/main +git cherry-pick +git push -f origin my-feature +``` + +## Pull Request Body + +Fill in the template at [`.github/PULL_REQUEST_TEMPLATE.md`](../../.github/PULL_REQUEST_TEMPLATE.md). It includes the required `release-note` block. + +Create the PR with `gh pr create --title "type(scope): brief description" --body-file `. + +## Fetching Unresolved Review Comments + +Cozystack uses GitHub review threads with resolution status. Only unresolved threads are actionable — resolved threads are already handled. + +The REST endpoint `/pulls/{pr}/reviews` returns review summaries, not individual review comments. Use the GraphQL API to access `reviewThreads` with `isResolved` status: + +```bash +gh api graphql -F owner=cozystack -F repo=cozystack -F pr= -f query=' +query($owner: String!, $repo: String!, $pr: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $pr) { + reviewThreads(first: 100) { + nodes { + isResolved + comments(first: 100) { + nodes { + id + path + line + author { login } + bodyText + url + createdAt + } + } + } + } + } + } +}' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .comments.nodes[]' +``` + +Compact one-line variant: + +```bash +gh api graphql -F owner=cozystack -F repo=cozystack -F pr= -f query=' +query($owner: String!, $repo: String!, $pr: Int!) { + repository(owner: $owner, name: $repo) { + pullRequest(number: $pr) { + reviewThreads(first: 100) { + nodes { + isResolved + comments(first: 100) { + nodes { + path + line + author { login } + bodyText + } + } + } + } + } + } +}' --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .comments.nodes[] | "\(.path):\(.line // "N/A") - \(.author.login): \(.bodyText[:150])"' +``` diff --git a/docs/agents/overview.md b/docs/agents/overview.md new file mode 100644 index 00000000..ae0fd1c4 --- /dev/null +++ b/docs/agents/overview.md @@ -0,0 +1,122 @@ +# Cozystack Project Overview + +This document provides detailed information about Cozystack project structure and conventions for AI agents. + +## About Cozystack + +Cozystack is an open-source Kubernetes-based platform and framework for building cloud infrastructure. It provides: + +- **Managed Services**: Databases, VMs, Kubernetes clusters, object storage, and more +- **Multi-tenancy**: Full isolation and self-service for tenants +- **GitOps-driven**: FluxCD-based continuous delivery +- **Modular Architecture**: Extensible with custom packages and services +- **Developer Experience**: Simplified local development with cozyhr tool + +The platform exposes infrastructure services via the Kubernetes API with ready-made configs, built-in monitoring, and alerts. + +## Code Layout + +``` +. +├── packages/ # Main directory for cozystack packages +│ ├── core/ # Core platform logic charts (installer, platform) +│ ├── system/ # System charts (CSI, CNI, operators, etc.) +│ ├── apps/ # User-facing charts shown in dashboard catalog +│ └── extra/ # Tenant-specific modules, singleton charts which are used as dependencies +├── dashboards/ # Grafana dashboards for monitoring +├── hack/ # Helper scripts for local development +│ └── e2e-apps/ # End-to-end application tests +├── scripts/ # Scripts used by cozystack container +│ └── migrations/ # Version migration scripts +├── docs/ # Documentation +│ ├── agents/ # AI agent instructions +│ └── changelogs/ # Release changelogs +├── cmd/ # Go command entry points +│ ├── cozystack-api/ +│ ├── cozystack-controller/ +│ └── cozystack-assets-server/ +├── internal/ # Internal Go packages +│ ├── controller/ # Controller implementations +│ └── lineagecontrollerwebhook/ +├── pkg/ # Public Go packages +│ ├── apis/ +│ ├── apiserver/ +│ └── registry/ +└── api/ # Kubernetes API definitions (CRDs) + └── v1alpha1/ +``` + +## Package Structure + +Every package is a Helm chart following the umbrella chart pattern: + +``` +packages/// +├── Chart.yaml # Chart definition and parameter docs +├── Makefile # Development workflow targets +├── charts/ # Vendored upstream charts +├── images/ # Dockerfiles and image build context +├── patches/ # Optional upstream chart patches +├── templates/ # Additional manifests +├── templates/dashboard-resourcemap.yaml # Dashboard resource mapping +├── values.yaml # Override values for upstream +└── values.schema.json # JSON schema for validation and UI +``` + +## Conventions + +### Helm Charts +- Follow **umbrella chart** pattern for system components +- Include upstream charts in `charts/` directory (vendored, not referenced) +- Override configuration in root `values.yaml` +- Use `values.schema.json` for input validation and dashboard UI rendering + +### Go Code +- Follow standard **Go conventions** and idioms +- Use **controller-runtime** patterns for Kubernetes controllers +- Prefer **kubebuilder** for API definitions and controllers +- Add proper error handling and structured logging + +### Git Commits +- Follow [Conventional Commits](https://www.conventionalcommits.org/) format: `type(scope): description` +- Always use `--signoff` flag +- Reference PR numbers when available +- Keep commits atomic and focused + +### PackageSource CRD upgrade policy + +Each component in a `PackageSource` may set `install.upgradeCRDs` to control how CRDs from the chart's `crds/` directory are handled on `HelmRelease` upgrades. Allowed values: `Skip` (default — helm-controller does not touch CRDs on upgrade), `Create` (create new CRDs only), `CreateReplace` (create new and overwrite existing). + +Set `upgradeCRDs: CreateReplace` for operators whose upstream regularly adds new CRDs between versions (etcd-operator, cnpg, kubevirt, kamaji). Without it, new CRDs from a chart bump do not land on existing clusters — only fresh installs get them. + +Do **not** set `CreateReplace` blindly: it overwrites every CRD in `crds/` and can cause silent data loss if upstream drops a field from a CRD that has live objects. Only enable it for operators whose schema evolution is additive-only. When in doubt, leave it unset and apply new CRDs manually. + +### Documentation + +Documentation is organized as follows: +- `docs/` - General documentation +- `docs/agents/` - Instructions for AI agents +- `docs/changelogs/` - Release changelogs +- Main website: https://github.com/cozystack/website + +## Things Agents Should Not Do + +### Never Edit These +- Do not modify files in `/vendor/` (Go dependencies) +- Do not edit generated files: `zz_generated.*.go` +- Do not change `go.mod`/`go.sum` manually (use `go get`) +- Do not edit upstream charts in `packages/*/charts/` directly (use patches) +- Do not modify image digests in `values.yaml` (generated by build) + +### Version Control +- Do not commit built artifacts from `_out` +- Do not commit test artifacts or temporary files + +### Git Operations +- Do not force push to main/master +- Do not update git config +- Do not perform destructive operations without explicit request + +### Core Components +- Do not modify `packages/core/platform/` without understanding migration impact + diff --git a/docs/agents/releasing.md b/docs/agents/releasing.md new file mode 100644 index 00000000..b1005638 --- /dev/null +++ b/docs/agents/releasing.md @@ -0,0 +1,29 @@ +# Release Process + +This document provides instructions for AI agents on how to handle release-related tasks. + +## When to Use + +Follow these instructions when the user asks to: +- Create a new release +- Prepare a release +- Tag a release +- Perform release-related tasks + +## Instructions + +For detailed release process instructions, follow the steps documented in: + +**[docs/release.md](../release.md)** + +## Quick Reference + +The release process typically involves: +1. Preparing the release branch +2. Generating changelog +3. Updating version numbers +4. Creating git tags +5. Building and publishing artifacts + +All detailed steps are documented in `docs/release.md`. + diff --git a/docs/changelogs/patch-template.md b/docs/changelogs/patch-template.md new file mode 100644 index 00000000..69ad49ba --- /dev/null +++ b/docs/changelogs/patch-template.md @@ -0,0 +1,18 @@ + + + +## Features and Improvements + +## Security + +## Fixes + +## Dependencies + +## Development, Testing, and CI/CD + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.36.0...main diff --git a/docs/changelogs/template.md b/docs/changelogs/template.md new file mode 100644 index 00000000..a939e23a --- /dev/null +++ b/docs/changelogs/template.md @@ -0,0 +1,20 @@ + + + +## Major Features and Improvements + +## Security + +## Fixes + +## Dependencies + +## Documentation + +## Development, Testing, and CI/CD + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.0...v0.35.0 diff --git a/docs/changelogs/v0.31.0.md b/docs/changelogs/v0.31.0.md index 0aedda55..0d786234 100644 --- a/docs/changelogs/v0.31.0.md +++ b/docs/changelogs/v0.31.0.md @@ -129,7 +129,7 @@ For more information, read the [Cozystack Release Workflow](https://github.com/c * [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] Refactor dashboard values. (@kvaps in https://github.com/cozystack/cozystack/pull/928, patched by @lllamnyp 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) diff --git a/docs/changelogs/v0.31.1.md b/docs/changelogs/v0.31.1.md new file mode 100644 index 00000000..d2763e4d --- /dev/null +++ b/docs/changelogs/v0.31.1.md @@ -0,0 +1,8 @@ +## Fixes + +* [build] Update Talos Linux v1.10.3 and fix assets. (@kvaps in https://github.com/cozystack/cozystack/pull/1006) +* [ci] Fix uploading released artifacts to GitHub. (@kvaps in https://github.com/cozystack/cozystack/pull/1009) +* [ci] Separate build and testing jobs. (@kvaps in https://github.com/cozystack/cozystack/pull/1005) +* [docs] Write a full release post for v0.31.1. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/999) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.31.0...v0.31.1 \ No newline at end of file diff --git a/docs/changelogs/v0.31.2.md b/docs/changelogs/v0.31.2.md new file mode 100644 index 00000000..69d0c888 --- /dev/null +++ b/docs/changelogs/v0.31.2.md @@ -0,0 +1,12 @@ +## Security + +* Resolve a security problem that allowed a tenant administrator to gain enhanced privileges outside the tenant. (@kvaps in https://github.com/cozystack/cozystack/pull/1062, backported in https://github.com/cozystack/cozystack/pull/1066) + +## Fixes + +* [platform] Fix dependencies in `distro-full` bundle. (@klinch0 in https://github.com/cozystack/cozystack/pull/1056, backported in https://github.com/cozystack/cozystack/pull/1064) +* [platform] Fix RBAC for annotating namespaces. (@kvaps in https://github.com/cozystack/cozystack/pull/1031, backported in https://github.com/cozystack/cozystack/pull/1037) +* [platform] Reduce system resource consumption by using smaller resource presets for VerticalPodAutoscaler, SeaweedFS, and KubeOVN. (@klinch0 in https://github.com/cozystack/cozystack/pull/1054, backported in https://github.com/cozystack/cozystack/pull/1058) +* [dashboard] Fix a number of issues in the Cozystack Dashboard (@kvaps in https://github.com/cozystack/cozystack/pull/1042, backported in https://github.com/cozystack/cozystack/pull/1066) +* [apps] Specify minimal working resource presets. (@kvaps in https://github.com/cozystack/cozystack/pull/1040, backported in https://github.com/cozystack/cozystack/pull/1041) +* [apps] Update built-in documentation and configuration reference for managed Clickhouse application. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/1059, backported in https://github.com/cozystack/cozystack/pull/1065) diff --git a/docs/changelogs/v0.32.1.md b/docs/changelogs/v0.32.1.md new file mode 100644 index 00000000..6863292d --- /dev/null +++ b/docs/changelogs/v0.32.1.md @@ -0,0 +1,38 @@ +## Major Features and Improvements + +* [postgres] Introduce new functionality for backup and restore in PostgreSQL. (@klinch0 in https://github.com/cozystack/cozystack/pull/1086) +* [apps] Refactor resources in managed applications. (@kvaps in https://github.com/cozystack/cozystack/pull/1106) +* [system] Make VMAgent's `extraArgs` tunable. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1091) + +## Fixes + +* [postgres] Escape users and database names. (@kvaps in https://github.com/cozystack/cozystack/pull/1087) +* [tenant] Fix monitoring agents HelmReleases for tenant clusters. (@klinch0 in https://github.com/cozystack/cozystack/pull/1079) +* [kubernetes] Wrap cert-manager CRDs in a conditional. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1076) +* [kubernetes] Remove `useCustomSecretForPatchContainerd` option and enable it by default. (@kvaps in https://github.com/cozystack/cozystack/pull/1104) +* [apps] Increase default resource presets for Clickhouse and Kafka from `nano` to `small`. Update OpenAPI specs and readme's. (@kvaps in https://github.com/cozystack/cozystack/pull/1103 and https://github.com/cozystack/cozystack/pull/1105) +* [linstor] Add configurable DRBD network options for connection and timeout settings, replacing scripted logic for detecting devices that lost connection. (@kvaps in https://github.com/cozystack/cozystack/pull/1094) + +## Dependencies + +* Update cozy-proxy to v0.2.0 (@kvaps in https://github.com/cozystack/cozystack/pull/1081) +* Update Kafka Operator to 0.45.1-rc1 (@kvaps in https://github.com/cozystack/cozystack/pull/1082 and https://github.com/cozystack/cozystack/pull/1102) +* Update Flux Operator to 0.23.0 (@kingdonb in https://github.com/cozystack/cozystack/pull/1078) + +## Documentation + +* [docs] Release notes for v0.32.0 and two beta-versions. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/1043) + +## Development, Testing, and CI/CD + +* [tests] Add Kafka, Redis. (@gwynbleidd2106 in https://github.com/cozystack/cozystack/pull/1077) +* [tests] Increase disk space for VMs in tests. (@kvaps in https://github.com/cozystack/cozystack/pull/1097) +* [tests] Upd Kubernetes v1.33. (@kvaps in https://github.com/cozystack/cozystack/pull/1083) +* [tests] increase postgres timeouts. (@kvaps in https://github.com/cozystack/cozystack/pull/1108) +* [tests] don't wait for postgres ro service. (@kvaps in https://github.com/cozystack/cozystack/pull/1109) +* [ci] Setup systemd timer to tear down sandbox. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1092) +* [ci] Split testing job into several. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1075) +* [ci] Run E2E tests as separate parallel jobs. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1093) +* [ci] Refactor GitHub workflows. (@kvaps in https://github.com/cozystack/cozystack/pull/1107) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.32.0...v0.32.1 \ No newline at end of file diff --git a/docs/changelogs/v0.33.0.md b/docs/changelogs/v0.33.0.md new file mode 100644 index 00000000..bf4843d3 --- /dev/null +++ b/docs/changelogs/v0.33.0.md @@ -0,0 +1,91 @@ +> [!WARNING] +> A patch release [0.33.2](github.com/cozystack/cozystack/releases/tag/v0.33.2) fixing a regression in 0.33.0 has been released. +> It is recommended to skip this version and upgrade to [0.33.2](github.com/cozystack/cozystack/releases/tag/v0.33.2) instead. + +## Feature Highlights + +### Unified CPU and Memory Allocation Management + +Since version 0.31.0, Cozystack introduced a single-point-of-truth configuration variable `cpu-allocation-ratio`, +making CPU resource requests and limits uniform in Virtual Machines managed by KubeVirt. +The new release 0.33.0 introduces `memory-allocation-ratio` and expands both variables to all managed applications and tenant resource quotas. + +Resource presets also respect the allocation ratios and behave in the same way as explicit resource definitions. +The new resource definition format is concise and simple for platform users. + +```yaml +# resource definition in the configuration +resources: + cpu: + memory: +``` + +It results in Kubernetes resource requests and limits, based on defined values and the universal allocation ratios: + +```yaml +# actual requests and limits, provided to the application +resources: + limits: + cpu: + memory: + requests: + cpu: + memory: +``` + +When updating from earlier Cozystack versions, resource configuration in managed applications will be automatically migrated to the new format. + +### Backing up and Restoring Data in Tenant Kubernetes + +One of the main features of the release is backup capability for PVCs in tenant Kubernetes clusters. +It enables platform and tenant administrators to back up and restore data used by services in the tenant clusters. + +This new functionality in Cozystack is powered by [Velero](https://velero.io/) and needs an external S3-compatible storage. + +## Support for NFS Storage + +Cozystack now supports using NFS shared storage with a new optional system module. +See the documentation: https://cozystack.io/docs/operations/storage/nfs/. + +## Features and Improvements + +* [kubernetes] Enable PVC backups in tenant Kubernetes clusters, powered by [Velero](https://velero.io/). (@klinch0 in https://github.com/cozystack/cozystack/pull/1132) +* [nfs-driver] Enable NFS support by introducing a new optional system module `nfs-driver`. (@kvaps in https://github.com/cozystack/cozystack/pull/1133) +* [virtual-machine] Configure CPU sockets available to VMs with the `resources.cpu.sockets` configuration value. (@klinch0 in https://github.com/cozystack/cozystack/pull/1131) +* [virtual-machine] Add support for using pre-imported "golden image" disks for virtual machines, enabling faster provisioning by referencing existing images instead of downloading via HTTP. (@gwynbleidd2106 in https://github.com/cozystack/cozystack/pull/1112) +* [kubernetes] Add an option to expose the Ingress-NGINX controller in tenant Kubernetes cluster via LoadBalancer. New configuration value `exposeMethod` offers a choice of `Proxied` and `LoadBalancer`. (@kvaps in https://github.com/cozystack/cozystack/pull/1114) +* [apps] When updating from earlier Cozystack versions, automatically migrate to the new resource definition format: from `resources.requests.[cpu,memory]` and `resources.limits.[cpu,memory]` to `resources.[cpu,memory]`. (@kvaps in https://github.com/cozystack/cozystack/pull/1127) +* [apps] Give examples of new resource definitions in the managed app README's. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/1120) +* [tenant] Respect `cpu-allocation-ratio` in tenant's `resourceQuotas`.(@kvaps in https://github.com/cozystack/cozystack/pull/1119) +* [cozy-lib] Introduce helper function to calculate Java heap params based on memory requests and limits. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1157) + +## Security + +* [monitoring] Disable sign up in Alerta. (@klinch0 in https://github.com/cozystack/cozystack/pull/1129) + +## Fixes + +* [platform] Always set resources for managed apps . (@lllamnyp in https://github.com/cozystack/cozystack/pull/1156) +* [platform] Remove the memory limit for Keycloak deployment. (@klinch0 in https://github.com/cozystack/cozystack/pull/1122) +* [kubernetes] Fix a condition in the ingress template for tenant Kubernetes. (@kvaps in https://github.com/cozystack/cozystack/pull/1143) +* [kubernetes] Fix a deadlock on reattaching a KubeVirt-CSI volume. (@kvaps in https://github.com/cozystack/cozystack/pull/1135) +* [mysql] MySQL applications with a single replica now correctly create a `LoadBalancer` service. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1113) +* [etcd] Fix resources and headless services in the etcd application. (@kvaps in https://github.com/cozystack/cozystack/pull/1128) +* [apps] Enable selecting `resourcePreset` from a drop-down list for all applications by adding enum of allowed values in the config scheme. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/1117) +* [apps] Refactor resource presets provided to managed apps by `cozy-lib`. (@kvaps in https://github.com/cozystack/cozystack/pull/1155) +* [keycloak] Calculate and pass Java heap parameters explicitly to prevent OOM errors. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1157) + + +## Development, Testing, and CI/CD + +* [dx] Introduce cozyreport tool and gather reports in CI. (@kvaps in https://github.com/cozystack/cozystack/pull/1139) +* [ci] Use Nexus as a pull-through cache for CI. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1124) +* [ci] Save a list of observed images after each workflow run. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1089) +* [ci] Skip Cozystack tests on PRs that only change the docs. Don't restart CI when a PR is labeled. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/1136) +* [dx] Fix Makefile variables for `capi-providers`. (@kvaps in https://github.com/cozystack/cozystack/pull/1115) +* [tests] Introduce self-destructing testing environments. (@kvaps in https://github.com/cozystack/cozystack/pull/1138, https://github.com/cozystack/cozystack/pull/1140, https://github.com/cozystack/cozystack/pull/1141, https://github.com/cozystack/cozystack/pull/1142) +* [e2e] Retry flaky application tests to improve total test time. (@kvaps in https://github.com/cozystack/cozystack/pull/1123) +* [maintenance] Add a PR template. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/1121) + + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.32.1...v0.33.0 \ No newline at end of file diff --git a/docs/changelogs/v0.33.1.md b/docs/changelogs/v0.33.1.md new file mode 100644 index 00000000..577d7066 --- /dev/null +++ b/docs/changelogs/v0.33.1.md @@ -0,0 +1,3 @@ +## Fixes + +* [kubevirt-csi] Fix a regression by updating the role of the CSI controller. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1165) diff --git a/docs/changelogs/v0.33.2.md b/docs/changelogs/v0.33.2.md new file mode 100644 index 00000000..71fd9ed5 --- /dev/null +++ b/docs/changelogs/v0.33.2.md @@ -0,0 +1,19 @@ +## Features and Improvements + +* [vm-instance] Enable running [Windows](https://cozystack.io/docs/operations/virtualization/windows/) and [MikroTik RouterOS](https://cozystack.io/docs/operations/virtualization/mikrotik/) in Cozystack. Add `bus` option and always specify `bootOrder` for all disks. (@kvaps in https://github.com/cozystack/cozystack/pull/1168) +* [cozystack-api] Refactor OpenAPI Schema and support reading it from config. (@kvaps in https://github.com/cozystack/cozystack/pull/1173) +* [cozystack-api] Enable using singular resource names in Cozystack API. For example, `kubectl get tenant` is now a valid command, in addition to `kubectl get tenants`. (@kvaps in https://github.com/cozystack/cozystack/pull/1169) +* [postgres] Explain how to back up and restore PostgreSQL using Velero backups. (@klinch0 and @NickVolynkin in https://github.com/cozystack/cozystack/pull/1141) + +## Fixes + +* [virtual-machine,vm-instance] Adjusted RBAC role to let users read the service associated with the VMs they create. Consequently, users can now see details of the service in the dashboard and therefore read the IP address of the VM. (@klinch0 in https://github.com/cozystack/cozystack/pull/1161) +* [cozystack-api] Fix an error with `resourceVersion` which resulted in message 'failed to update HelmRelease: helmreleases.helm.toolkit.fluxcd.io "xxx" is invalid...'. (@kvaps in https://github.com/cozystack/cozystack/pull/1170) +* [cozystack-api] Fix an error in updating lists in Cozystack objects, which resulted in message "Warning: resource ... is missing the kubectl.kubernetes.io/last-applied-configuration annotation". (@kvaps in https://github.com/cozystack/cozystack/pull/1171) +* [cozystack-api] Disable `startegic-json-patch` support. (@kvaps in https://github.com/cozystack/cozystack/pull/1179) +* [dashboard] Fix the code for removing dashboard comments which used to mistakenly remove shebang from cloudInit scripts. (@kvaps in https://github.com/cozystack/cozystack/pull/1175). +* [virtual-machine] Fix cloudInit and sshKeys processing. (@kvaps in https://github.com/cozystack/cozystack/pull/1175 and https://github.com/cozystack/cozystack/commit/da3ee5d0ea9e87529c8adc4fcccffabe8782292e) +* [applications] Fix a typo in preset resource tables in the built-in documentation of managed applications. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/1172) +* [kubernetes] Enable deleting Velero component from a tenant Kubernetes cluster. (@klinch0 in https://github.com/cozystack/cozystack/pull/1176) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.33.1...v0.33.2 diff --git a/docs/changelogs/v0.34.0.md b/docs/changelogs/v0.34.0.md new file mode 100644 index 00000000..26db8547 --- /dev/null +++ b/docs/changelogs/v0.34.0.md @@ -0,0 +1,87 @@ +Cozystack v0.34.0 is a stable release. +It focuses on cluster reliability, virtualization capabilities, and enhancements to the Cozystack API. + + + +> [!WARNING] +> A regression was found in this release and fixed in patch [0.34.3](https://github.com/cozystack/cozystack/releases/tag/v0.34.3). +> When upgrading Cozystack, it's recommended to skip this version and upgrade directly to [0.34.3](https://github.com/cozystack/cozystack/releases/tag/v0.34.3). + + +## Major Features and Improvements + +* [kubernetes] Enable users to select Kubernetes versions in tenant clusters. Supported versions range from 1.28 to 1.33, updated to the latest patches. (@lllamnyp and @IvanHunters in https://github.com/cozystack/cozystack/pull/1202) +* [kubernetes] Enable PVC snapshot capability in tenant Kubernetes clusters. (@klinch0 in https://github.com/cozystack/cozystack/pull/1203) +* [vpa] Implement autoscaling for the Vertical Pod Autoscaler itself, ensuring that VPA has sufficient resources and reducing the number of configuration parameters that platform administrators have to manage. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1198) +* [vm-instance] Enable running [Windows](https://cozystack.io/docs/operations/virtualization/windows/) and [MikroTik RouterOS](https://cozystack.io/docs/operations/virtualization/mikrotik/) in Cozystack. Add `bus` option and always specify `bootOrder` for all disks. (@kvaps in https://github.com/cozystack/cozystack/pull/1168) +* [cozystack-api] Specify OpenAPI schema for apps. (@kvaps in https://github.com/cozystack/cozystack/pull/1174) +* [cozystack-api] Refactor OpenAPI Schema and support reading it from config. (@kvaps in https://github.com/cozystack/cozystack/pull/1173) +* [cozystack-api] Enable using singular resource names in Cozystack API. For example, `kubectl get tenant` is now a valid command, in addition to `kubectl get tenants`. (@kvaps in https://github.com/cozystack/cozystack/pull/1169) +* [postgres] Explain how to back up and restore PostgreSQL using Velero backups. (@klinch0 and @NickVolynkin in https://github.com/cozystack/cozystack/pull/1141) +* [seaweedfs] Support multi-zone configuration for S3 storage. (@kvaps in https://github.com/cozystack/cozystack/pull/1194) +* [dashboard] Put YAML editor first when deploying and upgrading applications, as a more powerful option. Fix handling multiline strings. (@kvaps in https://github.com/cozystack/cozystack/pull/1227) + +## Security + +* [seaweedfs] Ensure that JWT signing keys in the SeaweedFS security configuration remain consistent across Helm upgrades. Resolve an upstream issue. (@kvaps in https://github.com/cozystack/cozystack/pull/1193 and https://github.com/seaweedfs/seaweedfs/pull/6967) + +## Fixes + +* [cozystack-controller] Fix stale workloads not being deleted when marked for deletion. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1210, @kvaps in https://github.com/cozystack/cozystack/pull/1229) +* [cozystack-controller] Improve reliability when updating HelmRelease objects to prevent unintended changes during reconciliation. (@klinch0 in https://github.com/cozystack/cozystack/pull/1205) +* [kubevirt-csi] Fix a regression by updating the role of the CSI controller. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1165) +* [virtual-machine,vm-instance] Adjusted RBAC role to let users read the service associated with the VMs they create. Consequently, users can now see details of the service in the dashboard and therefore read the IP address of the VM. (@klinch0 in https://github.com/cozystack/cozystack/pull/1161) +* [virtual-machine] Fix cloudInit and sshKeys processing. (@kvaps in https://github.com/cozystack/cozystack/pull/1175 and https://github.com/cozystack/cozystack/commit/da3ee5d0ea9e87529c8adc4fcccffabe8782292e) +* [cozystack-api] Fix an error with `resourceVersion` which resulted in message 'failed to update HelmRelease: helmreleases.helm.toolkit.fluxcd.io "xxx" is invalid...'. (@kvaps in https://github.com/cozystack/cozystack/pull/1170) +* [cozystack-api] Fix an error in updating lists in Cozystack objects, which resulted in message "Warning: resource ... is missing the kubectl.kubernetes.io/last-applied-configuration annotation". (@kvaps in https://github.com/cozystack/cozystack/pull/1171) +* [cozystack-api] Disable `strategic-json-patch` support. (@kvaps in https://github.com/cozystack/cozystack/pull/1179) +* [cozystack-api] Fix non-existing OpenAPI references. (@kvaps in https://github.com/cozystack/cozystack/pull/1208) +* [dashboard] Fix the code for removing dashboard comments which used to mistakenly remove shebang from `cloudInit` scripts. (@kvaps in https://github.com/cozystack/cozystack/pull/1175). +* [applications] Reorder configuration values in application README's for better readability. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/1214) +* [applications] Disallow selecting `resourcePreset = none` in the visual editor when deploying and upgrading applications. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/1196) +* [applications] Fix a typo in preset resource tables in the built-in documentation of managed applications. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/1172) +* [kubernetes] Enable deleting Velero component from a tenant Kubernetes cluster. (@klinch0 in https://github.com/cozystack/cozystack/pull/1176) +* [kubernetes] Explicitly mention available K8s versions for tenant clusters in the README. (@NickVolynkin in https://github.com/cozystack/cozystack/pull/1212) +* [oidc] Enable deleting Keycloak service. (@klinch0 in https://github.com/cozystack/cozystack/pull/1178) +* [tenant] Enable deleting extra applications from a tenant. (@klinch0 and @kvaps and in https://github.com/cozystack/cozystack/pull/1162) +* [nats] Fix a typo in the application template. (@klinch0 in https://github.com/cozystack/cozystack/pull/1195) +* [postgres] Resolve an issue with the visibility of PostgreSQL load balancer on the dashboard. (@klinch0 https://github.com/cozystack/cozystack/pull/1204) +* [objectstorage] Update COSI controller and sidecar, including fixes from upstream. (@kvaps in https://github.com/cozystack/cozystack/pull/1209, https://github.com/kubernetes-sigs/container-object-storage-interface/pull/89, and https://github.com/kubernetes-sigs/container-object-storage-interface/pull/90) + + +## Dependencies + +* Update FerretDB from v1 to v2.4.0.
**Breaking change:** before upgrading FerretDB instances, back up and restore the data following the [migration guide](https://docs.ferretdb.io/migration/migrating-from-v1/). (@kvaps in https://github.com/cozystack/cozystack/pull/1206) +* Update Talos Linux to v1.10.5. (@kvaps in https://github.com/cozystack/cozystack/pull/1186) +* Update LINSTOR to v1.31.2. (@kvaps in https://github.com/cozystack/cozystack/pull/1180) +* Update KubeVirt to v1.5.2. (@kvaps in https://github.com/cozystack/cozystack/pull/1183) +* Update CDI to v1.62.0. (@kvaps in https://github.com/cozystack/cozystack/pull/1183) +* Update Flux Operator to 0.24.0. (@kingdonb in https://github.com/cozystack/cozystack/pull/1167) +* Update Kamaji to edge-25.7.1. (@kvaps in https://github.com/cozystack/cozystack/pull/1184) +* Update Kube-OVN to v1.13.14. (@kvaps in https://github.com/cozystack/cozystack/pull/1182) +* Update Cilium to v1.17.5. (@kvaps in https://github.com/cozystack/cozystack/pull/1181) +* Update MariaDB Operator to v0.38.1. (@kvaps in https://github.com/cozystack/cozystack/pull/1188) +* Update SeaweedFS to v3.94. (@kvaps in https://github.com/cozystack/cozystack/pull/1194) + + +## Documentation + +* [Updated Cozystack Roadmap and Backlog for 2024-2026](https://cozystack.io/docs/roadmap/). (@tym83 and @kvapsova in https://github.com/cozystack/website/pull/249) +* [Running Windows VMs](https://cozystack.io/docs/operations/virtualization/windows/). (@kvaps and @NickVolynkin in https://github.com/cozystack/website/pull/246) +* [Running MikroTik RouterOS VMs](https://cozystack.io/docs/operations/virtualization/mikrotik/). (@kvaps and @NickVolynkin in https://github.com/cozystack/website/pull/247) +* [Public-network Kubernetes Deployment](https://cozystack.io/docs/operations/faq/#public-network-kubernetes-deployment). (@klinch0 and @NickVolynkin in https://github.com/cozystack/website/pull/242) +* [How to allocate space on system disk for user storage](https://cozystack.io/docs/operations/faq/#how-to-allocate-space-on-system-disk-for-user-storage). (@klinch0 and @NickVolynkin in https://github.com/cozystack/website/pull/242) +* [Resource Management in Cozystack](https://cozystack.io/docs/guides/resource-management/). (@NickVolynkin in https://github.com/cozystack/website/pull/233) +* [Key Concepts of Cozystack](https://cozystack.io/docs/guides/concepts/). (@NickVolynkin in https://github.com/cozystack/website/pull/254) +* [Cozystack Architecture and Platform Stack](https://cozystack.io/docs/guides/platform-stack/). (@NickVolynkin in https://github.com/cozystack/website/pull/252) +* Fixed a parameter in Kubespan: `cluster.discovery.enabled = true`. (@lb0o in https://github.com/cozystack/website/pull/241) +* Updated the Linux Foundation trademark text on the Cozystack website. (@krook in https://github.com/cozystack/website/pull/251) +* Auto-update the managed applications reference pages. (@NickVolynkin in https://github.com/cozystack/website/pull/243 and https://github.com/cozystack/website/pull/245) + +## Development, Testing, and CI/CD + +* [ci] Improve workflow for contributors submitting PRs from forks. Use Oracle Cloud Infrastructure Registry for non-release PRs, bypassing restrictions preventing pushing to ghcr.io with default GitHub token. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1226) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.33.0...v0.34.0 \ No newline at end of file diff --git a/docs/changelogs/v0.34.1.md b/docs/changelogs/v0.34.1.md new file mode 100644 index 00000000..0f5ec907 --- /dev/null +++ b/docs/changelogs/v0.34.1.md @@ -0,0 +1,15 @@ + + +> [!WARNING] +> A regression was found in this release and fixed in patch [0.34.3](https://github.com/cozystack/cozystack/releases/tag/v0.34.3). +> When upgrading Cozystack, it's recommended to skip this version and upgrade directly to [0.34.3](https://github.com/cozystack/cozystack/releases/tag/v0.34.3). + + +## Fixes + +* [kubernetes] Fix regression in `volumesnapshotclass` installation from https://github.com/cozystack/cozystack/pull/1203. (@kvaps in https://github.com/cozystack/cozystack/pull/1238) +* [objectstorage] Fix building objectstorage images. (@kvaps in https://github.com/cozystack/cozystack/commit/a9e9dfca1fadde1bf2b4e100753e0731bbcfe923) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.0...v0.34.1 \ No newline at end of file diff --git a/docs/changelogs/v0.34.2.md b/docs/changelogs/v0.34.2.md new file mode 100644 index 00000000..c84fe4cf --- /dev/null +++ b/docs/changelogs/v0.34.2.md @@ -0,0 +1,14 @@ + + +> [!WARNING] +> A regression was found in this release and fixed in patch [0.34.3](https://github.com/cozystack/cozystack/releases/tag/v0.34.3). +> When upgrading Cozystack, it's recommended to skip this version and upgrade directly to [0.34.3](https://github.com/cozystack/cozystack/releases/tag/v0.34.3). + + +## Fixes + +* [objectstorage] Fix recording image in objectstorage. (@kvaps in https://github.com/cozystack/cozystack/commit/4d9a8389d6bc7e86d63dd976ec853b374a91a637) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.1...v0.34.2 \ No newline at end of file diff --git a/docs/changelogs/v0.34.3.md b/docs/changelogs/v0.34.3.md new file mode 100644 index 00000000..9eb77f7b --- /dev/null +++ b/docs/changelogs/v0.34.3.md @@ -0,0 +1,13 @@ + + +## Fixes + +* [tenant] Fix tenant network policy to allow traffic to additional tenant-related services across namespace hierarchies. (@klinch0 in https://github.com/cozystack/cozystack/pull/1232, backported in https://github.com/cozystack/cozystack/pull/1272) +* [kubernetes] Add dependency for snapshot CRD and migration to latest version. (@kvaps in https://github.com/cozystack/cozystack/pull/1275, backported in https://github.com/cozystack/cozystack/pull/1279) +* [seaweedfs] Add support for whitelisting and exporting via nginx-ingress. Update cosi-driver. (@kvaps in https://github.com/cozystack/cozystack/pull/1277) +* [kubevirt] Fix building Kubevirt CCM (@kvaps in 3c7e256906e1dbb0f957dc3a205fa77a147d419d) +* [virtual-machine] Fix a regression with field `optional=true`. (@kvaps in https://github.com/cozystack/cozystack/commit/01053f7c3180d1bd045d7c5fb949984c2bdaf19d) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.2...v0.34.3 \ No newline at end of file diff --git a/docs/changelogs/v0.34.4.md b/docs/changelogs/v0.34.4.md new file mode 100644 index 00000000..03b863e9 --- /dev/null +++ b/docs/changelogs/v0.34.4.md @@ -0,0 +1,21 @@ + + +## Security + +* [keycloak] Store administrative passwords in the management cluster's secrets. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1286) +* [keycloak] Update Keycloak client redirect URI to use HTTPS instead of HTTP. Enable `cookie-secure`. (@klinch0 in https://github.com/cozystack/cozystack/pull/1287, backported in https://github.com/cozystack/cozystack/pull/1291) + + +## Fixes + +* [kubernetes] Resolve problems with pod names exceeding allowed length by shortening the name of volume snapshot CRD from `*-volumesnapshot-crd-for-tenant-k8s` to `*-vsnap-crd`. To apply this change, update each affected tenant Kubernetes cluster after updating Cozystack. (@klinch0 in https://github.com/cozystack/cozystack/pull/1284) +* [cozystack-api] Show correct `kind` values of `ApplicationList`. (@kvaps in https://github.com/cozystack/cozystack/pull/1290, backported in https://github.com/cozystack/cozystack/pull/1293) + + +## Development, Testing, and CI/CD + +* [tests] Add tests for S3 buckets. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1283, backported in https://github.com/cozystack/cozystack/pull/1292) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.3...v0.34.4 \ No newline at end of file diff --git a/docs/changelogs/v0.34.5.md b/docs/changelogs/v0.34.5.md new file mode 100644 index 00000000..2ad4d168 --- /dev/null +++ b/docs/changelogs/v0.34.5.md @@ -0,0 +1,11 @@ + + + +## Fixes + +* [virtual-machine] Enable using custom `instanceType` values in `virtual-machine` and `vm-instance` by disabling field validation. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1300, backported in https://github.com/cozystack/cozystack/pull/1303) +* [kubernetes] Disable VPA for VPA in tenant Kubernetes clusters. Tenant clusters have no need for this feature, and it was not designed to work in a tenant cluster, but was enabled by mistake. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1301, backported in https://github.com/cozystack/cozystack/pull/1305) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.4...v0.34.5 \ No newline at end of file diff --git a/docs/changelogs/v0.34.6.md b/docs/changelogs/v0.34.6.md new file mode 100644 index 00000000..bc4ac3dc --- /dev/null +++ b/docs/changelogs/v0.34.6.md @@ -0,0 +1,9 @@ + + +## Fixes + +* [dashboard] Fix filling multiline values in the visual editor. (@kvaps in https://github.com/cozystack/cozystack/commit/56fca9bd75efeca25f9483f6c514b6fec26d5d22 and https://github.com/cozystack/kubeapps/commit/4926bc68fabb0914afab574006643c85a597b371) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.5...v0.34.6 \ No newline at end of file diff --git a/docs/changelogs/v0.34.7.md b/docs/changelogs/v0.34.7.md new file mode 100644 index 00000000..b89df812 --- /dev/null +++ b/docs/changelogs/v0.34.7.md @@ -0,0 +1,11 @@ + + +## Fixes + +* [seaweedfs] Disable proxy buffering and proxy request buffering for ingress. (@kvaps in https://github.com/cozystack/cozystack/pull/1330, backported in https://github.com/cozystack/cozystack/commit/96d462e911d4458704b596533d3f10e4b5e80862) +* [linstor] Update LINSTOR monitoring configuration to use label `controller_node` instead of `node`. (@kvaps in https://github.com/cozystack/cozystack/pull/1326, backported in https://github.com/cozystack/cozystack/pull/1327) +* [kubernetes] Disable VPA for VPA in tenant Kubernetes clusters, patched a fix from v0.34.5. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1318, backported in https://github.com/cozystack/cozystack/pull/1319) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.6...v0.34.7 diff --git a/docs/changelogs/v0.34.8.md b/docs/changelogs/v0.34.8.md new file mode 100644 index 00000000..55b0a00c --- /dev/null +++ b/docs/changelogs/v0.34.8.md @@ -0,0 +1,11 @@ + + +## Fixes + +* [etcd] Fix `topologySpreadConstraints`. (@klinch0 in https://github.com/cozystack/cozystack/pull/1331, backported in https://github.com/cozystack/cozystack/pull/1332) +* [linstor] Update LINSTOR monitoring configuration: switch labels on `linstor-satellite` and `linstor-controller`. (@kvaps in https://github.com/cozystack/cozystack/pull/1335, backported in https://github.com/cozystack/cozystack/pull/1336) +* [kamaji] Fix broken migration jobs originating from missing environment variables in the in-tree build. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1338, backported in https://github.com/cozystack/cozystack/pull/1340) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.7...v0.34.8 diff --git a/docs/changelogs/v0.35.0.md b/docs/changelogs/v0.35.0.md new file mode 100644 index 00000000..ed2cc87a --- /dev/null +++ b/docs/changelogs/v0.35.0.md @@ -0,0 +1,138 @@ + + +## Feature Highlights + +### External Application Sources in Cozystack + +Cozystack now supports adding external application packages to the platform's application catalog. +Platform administrators can include custom or third-party applications alongside built-in ones, using the Cozystack API. + +Adding an application requires making an application package, similar to the ones included in Cozystack +under [`packages/apps`](https://github.com/cozystack/cozystack/tree/main/packages/apps). +Using external packages is enabled by a new CustomResourceDefinition (CRD) called `CozystackResourceDefinition` and +a corresponding controller (reconciler) that watches for these resources. + +Add your own managed application using the [documentation](https://cozystack.io/docs/applications/external/) +and an example at [github.com/cozystack/external-apps-example](https://github.com/cozystack/external-apps-example). + + + + +### Cozystack API Improvements + +This release brings significant improvements to the OpenAPI specs for all managed applications in Cozystack, +including databases, tenant Kubernetes, virtual machines, monitoring, and others. +These changes include more precise type definitions for fields that were previously defined only as generic objects, +and many fields now have value constraints. +Now many possible misconfigurations are detected immediately upon API request, and not later, with a failed deployment. + +The Cozystack API now also displays default values for the application resources. +Most other fields now have sane default values when such values are possible. + +All these changes pave the road for the new Cozystack UI, which is currently under development. + +### Hetzner RobotLB Support + +MetalLB, the default load balancer included in Cozystack, is built for bare metal and self-hosted VMs, +but is not supported on most cloud providers. +For example, Hetzner provides its own RobotLB service, which Cozystack now supports as an optional component. + +Read the updated guide on [deploying Cozystack on Hetzner.com](https://cozystack.io/docs/install/providers/hetzner/) +to learn more and deploy your own Cozystack cluster on Hetzner. + +### S3 Service: Dedicated Clusters and Monitoring + +You can now deploy dedicated Cozystack clusters to run the S3 service, powered by SeaweedFS. +Thanks to the support for [integration with remote filer endpoints](https://cozystack.io/docs/operations/stretched/seaweedfs-multidc/), +you can connect your primary Cozystack cluster to use S3 storage in a dedicated cluster. + +For security, platform administrators can now configure the SeaweedFS application with +a list of IP addresses or CIDR ranges that are allowed to access the filer service. + +SeaweedFS has also been integrated into the monitoring stack and now has its own Grafana dashboard. +Together, these enhancements help Cozystack users build a more reliable, scalable, and observable S3 service. + +### ClickHouse Keeper + +The ClickHouse application now includes a ClickHouse Keeper service to improve cluster reliability and availability. +This component is deployed by default with every ClickHouse cluster. + +Learn more in the [ClickHouse configuration reference](https://cozystack.io/docs/applications/clickhouse/#clickhouse-keeper-parameters). + +## Major Features and Improvements + +* [platform] Enable using external application packages by adding a `CozystackResourceDefinition` reconciler. Read the documentation on [adding external applications to Cozystack](https://cozystack.io/docs/applications/external/) to learn more. (@klinch0 in https://github.com/cozystack/cozystack/pull/1313) +* [cozystack-api, apps] Add default values, clear type definitions, value constraints and other improvements to the OpenAPI specs and READMEs by migrating to [cozyvalue-gen](https://github.com/cozystack/cozyvalues-gen). (@kvaps and @NickVolynkin in https://github.com/cozystack/cozystack/pull/1216, https://github.com/cozystack/cozystack/pull/1314, https://github.com/cozystack/cozystack/pull/1316, https://github.com/cozystack/cozystack/pull/1321, and https://github.com/cozystack/cozystack/pull/1333) +* [cozystack-api] Show default values from the OpenAPI spec in the application resources. (@kvaps in https://github.com/cozystack/cozystack/pull/1241) +* [cozystack-api] Provide an API for administrators to define custom managed applications alongside existing managed apps. (@klinch in https://github.com/cozystack/cozystack/pull/1230) +* [robotlb] Introduce the Hetzner RobotLB balancer. (@IvanHunters and @gwynbleidd2106 in https://github.com/cozystack/cozystack/pull/1233) +* [platform, robotlb] Autodetect if node ports should be assigned to load balancer services. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1271) +* [seaweedfs] Enable [integration with remote filer endpoints](https://cozystack.io/docs/operations/stretched/seaweedfs-multidc/) by adding new `Client` topology. (@kvaps in https://github.com/cozystack/cozystack/pull/1239) +* [seaweedfs] Add support for whitelisting and exporting via nginx-ingress. Update cosi-driver. (@kvaps in https://github.com/cozystack/cozystack/pull/1277) +* [monitoring, seaweedfs] Add monitoring and Grafana dashboard for SeaweedFS. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1285) +* [clickhouse] Add the ClickHouse Keeper component. (@klinch0 in https://github.com/cozystack/cozystack/pull/1298 and https://github.com/cozystack/cozystack/pull/1320) + +## Security + +* [keycloak] Store administrative passwords in the management cluster's secrets. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1286) +* [keycloak] Update Keycloak client redirect URI to use HTTPS instead of HTTP. Enable `cookie-secure`. (@klinch0 in https://github.com/cozystack/cozystack/pull/1287) + +## Fixes + +* [platform] Introduce a fixed 2-second delay at the start of reconciliation for system and tenant Helm operations. (@klinch0 in https://github.com/cozystack/cozystack/pull/1343) +* [kubernetes] Add dependency for snapshot CRD and migration to the latest version. (@kvaps in https://github.com/cozystack/cozystack/pull/1275) +* [kubernetes] Fix regression in `volumesnapshotclass` installation from https://github.com/cozystack/cozystack/pull/1203. (@kvaps in https://github.com/cozystack/cozystack/pull/1238) +* [kubernetes] Resolve problems with pod names exceeding allowed length by shortening the name of volume snapshot CRD from `*-volumesnapshot-crd-for-tenant-k8s` to `*-vsnap-crd`. To apply this change, update each affected tenant Kubernetes cluster after updating Cozystack. (@klinch0 in https://github.com/cozystack/cozystack/pull/1284) +* [kubernetes] Disable VPA for VPA in tenant Kubernetes clusters. Tenant clusters have no need for this feature, and it was not designed to work in a tenant cluster, but was enabled by mistake. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1301 and https://github.com/cozystack/cozystack/pull/1318) +* [kamaji] Fix broken migration jobs originating from missing environment variables in the in-tree build. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1338) +* [etcd] Fix the `topologySpreadConstraints` for etcd. (@klinch0 in https://github.com/cozystack/cozystack/pull/1331) +* [tenant] Fix tenant network policy to allow traffic to additional tenant-related services across namespace hierarchies. (@klinch0 in https://github.com/cozystack/cozystack/pull/1232) +* [tenant, monitoring] Improve the reliability of tenant monitoring by increasing the timeout and number of retries. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1294) +* [kubevirt] Fix building KubeVirt CCM image. (@kvaps in https://github.com/cozystack/cozystack/commit/3c7e256906e1dbb0f957dc3a205fa77a147d419d) +* [virtual-machine] Fix a regression with `optional=true` field. (@kvaps in https://github.com/cozystack/cozystack/commit/01053f7c3180d1bd045d7c5fb949984c2bdaf19d) +* [virtual-machine] Enable using custom `instanceType` values in `virtual-machine` and `vm-instance` by disabling field validation. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1300, backported in https://github.com/cozystack/cozystack/pull/1303) +* [cozystack-api] Show correct `kind` values of `ApplicationList`. (@kvaps in https://github.com/cozystack/cozystack/pull/1290) +* [cozystack-api] Add missing roles to allow cozystack-controller to read Kubernetes deployments. (@klinch0 in https://github.com/cozystack/cozystack/pull/1342) +* [linstor] Update LINSTOR monitoring configuration to use label `controller_node` instead of `node`. (@kvaps in https://github.com/cozystack/cozystack/pull/1326 and https://github.com/cozystack/cozystack/pull/1335) +* [seaweedfs] Fix SeaweedFS volume configuration. Increase the volume size limit from 100MB to 30,000MB. (@kvaps in https://github.com/cozystack/cozystack/pull/1328) +* [seaweedfs] Disable proxy buffering and proxy request buffering for ingress. (@kvaps in https://github.com/cozystack/cozystack/pull/1330) + + +## Dependencies + +* Update flux-operator to 0.28.0. (@kingdonb in https://github.com/cozystack/cozystack/pull/1315 and https://github.com/cozystack/cozystack/pull/1344) + +## Documentation + +* [Reimplement Cozystack Roadmap as a GitHub project](https://github.com/orgs/cozystack/projects/1). (@cozystack team) +* [SeaweedFS Multi-DC Configuration](https://cozystack.io/docs/operations/stretched/seaweedfs-multidc/). (@kvaps and @NickVolynkin in https://github.com/cozystack/website/pull/272) +* [Troubleshooting Kube-OVN](https://cozystack.io/docs/operations/troubleshooting/#kube-ovn-crash). (@kvaps and @NickVolynkin in https://github.com/cozystack/website/pull/273) +* [Removing failed nodes from Cozystack cluster](https://cozystack.io/docs/operations/troubleshooting/#remove-a-failed-node-from-the-cluster). (@kvaps and @NickVolynkin in https://github.com/cozystack/website/pull/273) +* [Installing Talos with `kexec`](https://cozystack.io/docs/talos/install/kexec/). (@kvaps and @NickVolynkin in https://github.com/cozystack/website/pull/268) +* [Rewrite Cozystack tutorial](https://cozystack.io/docs/getting-started/). (@NickVolynkin in https://github.com/cozystack/website/pull/262 and https://github.com/cozystack/website/pull/268) +* [How to install Cozystack in Hetzner](https://cozystack.io/docs/install/providers/hetzner/). (@NickVolynkin and @IvanHunters in https://github.com/cozystack/website/pull/280) +* [Adding External Applications to Cozystack Catalog](https://cozystack.io/docs/applications/external/). (@klinch0 and @NickVolynkin in https://github.com/cozystack/website/pull/283) +* [Creating and Using Named VM Images (Golden Images)](https://cozystack.io/docs/virtualization/vm-image/) (@NickVolynkin and @kvaps in https://github.com/cozystack/website/pull/276) +* [Creating Encrypted Storage on LINSTOR](https://cozystack.io/docs/operations/storage/disk-encryption/). (@kvaps and @NickVolynkin in https://github.com/cozystack/website/pull/282) +* [Adding and removing components on Cozystack installation using `bundle-enable` and `bundle-disable`](https://cozystack.io/docs/operations/bundles/#how-to-enable-and-disable-bundle-components) (@NickVolynkin in https://github.com/cozystack/website/pull/281) +* Restructure Cozystack documentation. Bring [managed Kubernetes](https://cozystack.io/docs/kubernetes/), [managed applications](https://cozystack.io/docs/applications/), [virtualization](https://cozystack.io/docs/virtualization/), and [networking](https://cozystack.io/docs/networking/) guides to the top level. (@NickVolynkin in https://github.com/cozystack/website/pull/266) + + +## Development, Testing, and CI/CD + +* [tests] Add tests for S3 buckets. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1283) +* [tests, ci] Simplify test discovery logic; run two k8s tests as separate jobs; delete Clickhouse application after a successful test. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1236) +* [dx] When running `make` commands with `BUILDER` value specified, `PLATFORM` is optional. (@kvaps in https://github.com/cozystack/cozystack/pull/1288) +* [tests] Fix resource specification in virtual machine tests. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1308) +* [tests] Increase available space for e2e tests. (@kvaps in https://github.com/cozystack/cozystack/commit/168a24ffdf1202b3bf2e7d2b5ef54b72b7403baf) +* [tests, ci] Continue application tests after one of them fails. (@NickVolynkin in https://github.com/cozystack/cozystack/commit/634b77edad6c32c101f3e5daea6a5ffc0c83d904) +* [ci] Use a subdomain of aenix.org for Nexus service in CI. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1322) + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.34.0...v0.35.0 diff --git a/docs/changelogs/v0.35.1.md b/docs/changelogs/v0.35.1.md new file mode 100644 index 00000000..21333eee --- /dev/null +++ b/docs/changelogs/v0.35.1.md @@ -0,0 +1,10 @@ + + + +## Fixes + +* [cozy-lib] Fix malformed retrieval of `cozyConfig` in the cozy-lib template. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1348) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.35.0...v0.35.1 diff --git a/docs/changelogs/v0.35.2.md b/docs/changelogs/v0.35.2.md new file mode 100644 index 00000000..b35b2f48 --- /dev/null +++ b/docs/changelogs/v0.35.2.md @@ -0,0 +1,22 @@ + + + +## Features and Improvements + +* [talos] Add LLDPD (`ghcr.io/siderolabs/lldpd`) as a built-in system extension, enabling LLDP-based neighbor discovery out of the box. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1351 and https://github.com/cozystack/cozystack/pull/1360) + +## Fixes + +* [cozystack-api] Sanitize the OpenAPI v2 schema. (@kvaps in https://github.com/cozystack/cozystack/pull/1353) +* [seaweedfs] Fix a problem where S3 gateway would be moved to an external pod, resulting in authentication failure. (@kvaps in https://github.com/cozystack/cozystack/pull/1361) + + +## Dependencies + +* Update LINSTOR to v1.31.3. (@kvaps in https://github.com/cozystack/cozystack/pull/1358) +* Update SeaweedFS to v3.96. (@kvaps in https://github.com/cozystack/cozystack/pull/1361) + + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.35.1...v0.35.2 diff --git a/docs/changelogs/v0.35.3.md b/docs/changelogs/v0.35.3.md new file mode 100644 index 00000000..38b31111 --- /dev/null +++ b/docs/changelogs/v0.35.3.md @@ -0,0 +1,10 @@ + + + +## Fixes + +* [seaweedfs] Add a liveness check for the SeaweedFS S3 endpoint to improve health monitoring and enable automatic recovery. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1368) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.35.2...v0.35.3 diff --git a/docs/changelogs/v0.35.4.md b/docs/changelogs/v0.35.4.md new file mode 100644 index 00000000..ba16e26d --- /dev/null +++ b/docs/changelogs/v0.35.4.md @@ -0,0 +1,14 @@ + + + +## Fixes + +* [virtual-machine] Fix the regression in VM update hook introduced in https://github.com/cozystack/cozystack/pull/1169 by targeting the correct API resource and avoiding conflicts with KubeVirt resources. (@kvaps in https://github.com/cozystack/cozystack/pull/1376, backported in https://github.com/cozystack/cozystack/pull/1377) +* [cozy-lib] Add the missing template `cozy-lib.resources.flatten`. (@kvaps in https://github.com/cozystack/cozystack/pull/1372, backported in https://github.com/cozystack/cozystack/pull/1375) +* [platform] Fix a boolean override bug in Helm merge. ConfigMap values now correctly take precedence over bundle defaults. (@dyudin0821 in https://github.com/cozystack/cozystack/pull/1385, backported in https://github.com/cozystack/cozystack/pull/1388) +* [seaweedfs] Resolve connectivity issues in SeaweedFS. Increase Nginx ingress timeouts for SeaweedFS S3 endpoint. (@kvaps in https://github.com/cozystack/cozystack/pull/1386, backported in https://github.com/cozystack/cozystack/pull/1390) +* [dx] Remove the BUILDER and PLATFORM autodetect logic in Makefiles. (@kvaps in https://github.com/cozystack/cozystack/pull/1391, backported in https://github.com/cozystack/cozystack/pull/1392) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.35.3...v0.35.4 diff --git a/docs/changelogs/v0.35.5.md b/docs/changelogs/v0.35.5.md new file mode 100644 index 00000000..02c744d6 --- /dev/null +++ b/docs/changelogs/v0.35.5.md @@ -0,0 +1,11 @@ + + + +## Fixes + +* [etcd] Ensure that TopologySpreadConstraints consistently target etcd pods. (@kvaps in https://github.com/cozystack/cozystack/pull/1405, backported in https://github.com/cozystack/cozystack/pull/1406) +* [tests] Add resource quota for testing namespaces. (@IvanHunters in https://github.com/cozystack/cozystack/commit/4982cdf5024c8bb9aa794b91d55545ea6b105d17) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.35.4...v0.35.5 diff --git a/docs/changelogs/v0.36.0.md b/docs/changelogs/v0.36.0.md new file mode 100644 index 00000000..c300a852 --- /dev/null +++ b/docs/changelogs/v0.36.0.md @@ -0,0 +1,117 @@ + + + + +## Feature Highlights + +Release v0.36.0 focuses on the stability, observability, and flexible configuration of managed applications. + +### Per-Namespace Resource Limits for Tenants + +Resource management for Cozystack tenants has received a final patch and is now graduated to a stable feature. +Platform administrators can define explicit CPU, memory, and storage limits for each tenant's namespace +via the tenant specification. +This prevents any single tenant from consuming more than their share of cluster resources, +ensuring cluster stability and a guaranteed service level for each tenant. + +### Kube-OVN Cluster Health Monitor + +A new component called the Kube-OVN Plunger continuously monitors the health of the Kube-OVN network's central control cluster. +This external agent gathers OVN cluster status and consensus information, exposing Prometheus metrics and live events stream via SSE. +As a result, it provides much better visibility of the virtual network layer and helps maintain a reliable and observable network in Cozystack. +This change opens the road to automated Kube-OVN database operations and recovery in specific corner cases. + +### Configurable CoreDNS Addon for Kubernetes + +Cozystack introduces a dedicated CoreDNS addon for managing cluster DNS with greater flexibility. +CoreDNS is now deployed via a Helm chart and can be tuned through custom values in the cluster specification, +including autoscaling, replica count, and adjusting service IP. +CoreDNS can now be configured in the dashboard and using Cozystack API. + +### Granular SeaweedFS Service Configuration + +The SeaweedFS S3 storage service in Cozystack is now far more configurable at a component level. +The Helm chart for SeaweedFS now includes independent configuration for each component and its resources. +It includes the master nodes, volume servers with support for multiple zones, filers, the backing database, and the S3 gateway. +Administrators can set per-component parameters such as the number of replicas, available CPU, memory, and storage size. + +### Server-side Encryption for S3 + +Cozystack v0.36.0 includes SeaweedFS 3.97, bringing support for server-side encryption of S3 buckets (SSE-C, SSE-KMS, and SSE-S3). + +**Breaking change:** upon updating Cozystack, SeaweedFS will be updated to a newer version, and the services specification +will be converted to the new format. + +### Custom Resource Profiles for Ingress Controller + +NGINX controller is now configurable on a per-replica basis. +Configurations include the ingress controller pods' CPU and memory requests/limits, either with direct values or using one of the available presets. + +### Cozystack REST API Documentation + +[Cozystack REST API reference](https://cozystack.io/docs/cozystack-api/rest/) is now published on the website. +It includes endpoints and methods for listing, creating, updating, and removing each managed application, defined as Cozystack CRD. + + +### Built-in LLDP-Based Neighbor Discovery in Talos + +Cozystack now includes the LLDPD extension in its Talos OS image, enabling Link Layer Discovery Protocol (LLDP) out of the box. +This means each node can automatically discover and advertise its network neighbors and topology without any manual setup. + +### Use external IP for Egress Traffic in VMs + +When a virtual machine has an external IP assigned to it, it will now always use it for egress traffic, independently of the external method used. + +## Major Features and Improvements + +* [talos] Add LLDPD (`ghcr.io/siderolabs/lldpd`) as a built-in system extension, enabling LLDP-based neighbor discovery out of the box. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1351 and https://github.com/cozystack/cozystack/pull/1360) +* [kubernetes] Add a configurable CoreDNS addon with valuesOverride, packaged chart, and managed deployment (metrics, autoscaling, HPA, customizable Service). (@klinch0 in https://github.com/cozystack/cozystack/pull/1362) +* [kube-ovn] Implement the Kube-OVN plunger, an external monitoring agent for the ovn-central cluster. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1380, patched in https://github.com/cozystack/cozystack/pull/1414 and https://github.com/cozystack/cozystack/pull/1418) +* [tenant] Enable per-namespace resource quota settings in tenants, with explicit cpu, memory, and storage values. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1389) +* [seaweedfs] Add detailed resource configuration for each component of the SeaweedFS service. (@klinch0 and @kvaps in https://github.com/cozystack/cozystack/pull/1415) +* [ingress] Enable per-replica resource configuration to the ingress controller. (@kvaps in https://github.com/cozystack/cozystack/pull/1416) +* [virtual-machine] Use external IP for egress traffic with `PortList` method. (@kvaps in https://github.com/cozystack/cozystack/pull/1349) + + +## Fixes + +* [cozy-lib] Fix malformed retrieval of `cozyConfig` in the cozy-lib template. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1348) +* [cozy-lib] Add the missing template `cozy-lib.resources.flatten`. (@kvaps in https://github.com/cozystack/cozystack/pull/1372) +* [cozystack-api] Sanitize the OpenAPI v2 schema. (@kvaps in https://github.com/cozystack/cozystack/pull/1353) +* [kube-ovn] Improve northd leader detection. Patch the northd leader check to test against all endpoints instead of just the first one marked as ready. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1363) +* [seaweedfs] Add a liveness check for the SeaweedFS S3 endpoint to improve health monitoring and enable automatic recovery. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1368) +* [seaweedfs] Resolve race conditions in SeaweedFS. Increase deployment timeouts and set install/upgrade remediation to unlimited retries to improve deployment resilience. (@IvanHunters in https://github.com/cozystack/cozystack/pull/1371) +* [seaweedfs] Resolve connectivity issues in SeaweedFS. Increase Nginx ingress timeouts for SeaweedFS S3 endpoint. (@kvaps in https://github.com/cozystack/cozystack/pull/1386) +* [virtual-machine] Fix the reg ression in VM update hook introduced in https://github.com/cozystack/cozystack/pull/1169. Target the correct API resource and avoid conflicts with KubeVirt resources. (@kvaps in https://github.com/cozystack/cozystack/pull/1376) +* [virtual-machine] Correct app version references in `virtual-machine` and `vm-instance`, ensuring accurate versioning during migrations. (@kvaps in https://github.com/cozystack/cozystack/pull/1378). +* [cozyreport] Fix an error where cozyreport tried to parse non-existent objects and generated garbage output in CI debug logs. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1383) +* [platform] Fix a boolean override bug in Helm merge. ConfigMap values now correctly take precedence over bundle defaults. (@dyudin0821 in https://github.com/cozystack/cozystack/pull/1385) +* [kubernetes] CoreDNS release now installs and stores state in the `kube-system` namespace. (@kvaps in https://github.com/cozystack/cozystack/pull/1395) +* [kubernetes] Expose configuration for CoreDNS, enabling setting the image repository and replica count via `values.yaml`. (@kvaps in https://github.com/cozystack/cozystack/pull/1410) +* [etcd] Ensure that TopologySpreadConstraints consistently target etcd pods. (@kvaps in https://github.com/cozystack/cozystack/pull/1405) +* [tenant] Use force-upgrade for ingress controller charts. (@klinch0 in https://github.com/cozystack/cozystack/pull/1404) +* [cozystack-controller] Fix an RBAC error that prevented the workload labelling feature from working. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1419) +* [seaweedfs] Remove VerticalPodAutoscaler for SeaweedFS. (@kvaps in https://github.com/cozystack/cozystack/pull/1421) + + +## Dependencies + +* Update LINSTOR to v1.31.3. (@kvaps in https://github.com/cozystack/cozystack/pull/1358) +* Update SeaweedFS to v3.97. (@kvaps in https://github.com/cozystack/cozystack/pull/1361 and https://github.com/cozystack/cozystack/pull/1373) +* Update Kube-OVN to 1.14.5. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1363) +* Replace Bitnami images with alternatives in all charts. (@kvaps in https://github.com/cozystack/cozystack/pull/1374) + +## Documentation + +## Development, Testing, and CI/CD + +* [dx] Remove the BUILDER and PLATFORM autodetect logic in Makefiles. (@kvaps in https://github.com/cozystack/cozystack/pull/1391) +* [ci] Use the host buildx config in CI. (@kvaps in https://github.com/cozystack/cozystack/pull/1015) +* [ci] Add `jq` and `git` to the installer image. (@kvaps in https://github.com/cozystack/cozystack/pull/1417) +* [ci] Source the `REGISTRY` environment variable from actions' variables, not secrets, so external pull requests can work. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1423) + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.35.0...v0.36.0 diff --git a/docs/changelogs/v0.36.1.md b/docs/changelogs/v0.36.1.md new file mode 100644 index 00000000..3bac9e72 --- /dev/null +++ b/docs/changelogs/v0.36.1.md @@ -0,0 +1,22 @@ + + + +## Major Features and Improvements + +* [cozystack-api] Implement recursive, Kubernetes-like defaulting for applications: missing fields in nested objects and arrays are auto-populated safely without mutating shared defaults. (@kvaps in https://github.com/cozystack/cozystack/pull/1432) + +## Fixes + +* [cozystack-api] Update defaulting API schemas. (@kvaps in https://github.com/cozystack/cozystack/pull/1433) +* [dashboard] Fix Bitnami dependencies. (@kvaps in https://github.com/cozystack/cozystack/pull/1431) +* [seaweedfs] Fix SeaweedFS migration. (@kvaps in https://github.com/cozystack/cozystack/pull/1430) + +## Development, Testing, and CI/CD + +* [adopters] Add [Hidora](https://hikube.cloud) to the Cozystack adopters list. (@matthieu-robin in https://github.com/cozystack/cozystack/pull/1429) + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.36.0...v0.36.1 diff --git a/docs/changelogs/v0.36.2.md b/docs/changelogs/v0.36.2.md new file mode 100644 index 00000000..cb44308a --- /dev/null +++ b/docs/changelogs/v0.36.2.md @@ -0,0 +1,21 @@ + + + +## Features and Improvements + +* [vm-disk] New SVG icon for VM disk application. (@kvaps and @kvapsova in https://github.com/cozystack/cozystack/pull/1435) + +## Fixes + +* [kubernetes] Pin CoreDNS image tag to v1.12.4 for consistent, reproducible deployments. (@kvaps in https://github.com/cozystack/cozystack/pull/1469) +* [dashboard] Fix FerretDB spec typo that prevented deploy/display in the web UI. (@lllamnyp in https://github.com/cozystack/cozystack/pull/1440) + +## Dependencies + +## Development, Testing, and CI/CD + +--- + +**Full Changelog**: [v0.36.1...v0.36.2](https://github.com/cozystack/cozystack/compare/v0.36.1...v0.36.2) diff --git a/docs/changelogs/v0.37.0.md b/docs/changelogs/v0.37.0.md new file mode 100644 index 00000000..87dd3c9d --- /dev/null +++ b/docs/changelogs/v0.37.0.md @@ -0,0 +1,117 @@ +# Cozystack v0.37 — “OpenAPI Dashboard & Lineage Everywhere” + +We’ve shipped a big usability push this cycle: a brand-new **OpenAPI-driven dashboard**, lineage labeling across core resource types, and several reliability improvements to smooth upgrades from 0.36→ 0.37. Below are the highlights and the full categorized lists. + +## Highlights + +* **New OpenAPI-based Dashboard** replaces the old UI, adds module-aware navigation, dynamic branding, and richer Kubernetes resource views ([**@kvaps**](https://github.com/kvaps) in #1269, #1463, #1460). +* **Lineage Webhook** tags Pods, PVCs, Services, Ingresses, and Secrets, adding labels referencing the managing Cozystack application ([**@lllamnyp**](https://github.com/lllamnyp) in #1448, #1452, #1477, #1486, #1497; [**@kvaps**](https://github.com/kvaps) in #1454). +* **Smoother upgrades** with installer and migration hardening, decoupled CRDs vs. API server ([**@lllamnyp**](https://github.com/lllamnyp) in #1494, #1498; [**@kvaps**](https://github.com/kvaps) in #1506). +* **Operations quality**: Kubernetes tests with smarter waits/readiness checks ([**@IvanHunters**](https://github.com/IvanHunters) in #1485). + +--- + +## New features + +### Dashboard + +* Introduce the OpenAPI-based dashboard and controller; implement TenantNamespace, TenantModules, TenantSecret/SecretsTable resources ([**@kvaps**](https://github.com/kvaps) in #1269). +* Module-aware navigation, richer detail views (Services/Secrets/Ingresses), improved sidebars; “Tenant Modules” grouping ([**@kvaps**](https://github.com/kvaps) in #1463). +* Dynamic branding via cluster config (tenant name, footer/title, logo/icon SVGs) ([**@kvaps**](https://github.com/kvaps) in #1460). +* Dashboard: fix namespace listing for unprivileged users and stabilize streamed requests; build-time patching ([**@kvaps**](https://github.com/kvaps) in #1456). +* Dashboard UX set: marketplace hides module resources; consistent navigation/links; prefill “name” in forms; ingress factory; formatted TenantNamespaces tables ([**@kvaps**](https://github.com/kvaps) in #1463). +* **Dashboard**: list modules reliably; remove Tenant from Marketplace; fix field override while typing ([**@kvaps**](https://github.com/kvaps) in #1501, #1503). +* **Dashboard**: correct API group for applications; sidebars; disable auto-expand; fix `/docs` redirect ([**@kvaps**](https://github.com/kvaps) in #1463, #1465, #1462). +* **Dashboard**: show Secrets with empty values correctly ([**@kvaps**](https://github.com/kvaps) in #1480). +* Dashboard configuration refactor: generate static resources at startup; auto-cleanup stale objects; higher controller client throughput ([**@kvaps**](https://github.com/kvaps) in #1457). + +### Migration to v0.37 +* **Installer/Migrations**: prevent unintended deletion of platform resource definitions; resilient timestamping; tolerant annotations; stronger migrate-then-reconcile flow ([**@kvaps**](https://github.com/kvaps) in #1475; Andrei Kvapil & [**@lllamnyp**](https://github.com/lllamnyp) in #1498). +* Installer hardening for **migration #20**: packaged apply, ordered waits/readiness checks, RFC3339(nano) stamping; Helm in installer image (Andrei Kvapil & [**@lllamnyp**](https://github.com/lllamnyp) in #1498). +* **Decoupled API & CozyRDs**: You can now upgrade the Cozystack API server independently of CRDs/CozyRD instances, easing 0.36 → 0.37 migrations ([**@lllamnyp**](https://github.com/lllamnyp) in #1494). +* **Migration #20**: The installer runs migration from packaged Helm charts with ordered waits/readiness checks; annotations are tolerant; timestamps are environment-robust (Andrei Kvapil & [**@lllamnyp**](https://github.com/lllamnyp) in #1498; [**@kvaps**](https://github.com/kvaps) in #1475). + +### Webhook / Lineage + +* Add a lineage mutating webhook to auto-label Pods/Secrets/PVCs/Ingresses/WorkloadMonitors with owning app ([**@lllamnyp**](https://github.com/lllamnyp) in #1448, #1497, [**@kvaps**](https://github.com/kvaps) in #1454). +* **Name-based** selectors for Secret visibility (templates supported) ([**@lllamnyp**](https://github.com/lllamnyp) in #1477). +* Select **Services** and **Ingresses** in CRDs/API; treat them as user-facing when configured ([**@lllamnyp**](https://github.com/lllamnyp) in #1486). +* **VictoriaMetrics integration**: Lineage labels are explicitly set on VM resources; `managedMetadata` is configured to avoid controller “fights” over labels ([**@lllamnyp**](https://github.com/lllamnyp) in #1452). +* Webhook **excludes** `default` and `kube-system` to avoid unintended mutations (part of the installer/migration hardening by Andrei Kvapil & [**@lllamnyp**](https://github.com/lllamnyp) in #1498). + +### API / Platform + +* Decouple the Cozystack API from Cozystack Resource Definitions to allow independent upgrades ([**@lllamnyp**](https://github.com/lllamnyp) in #1494). +* Add **label selectors** to app definitions for Secret include/exclude ([**@lllamnyp**](https://github.com/lllamnyp) in #1447). + +### Monitoring & Ops + +* Reduce node labelsets in target relabeling configs on cadvisor/kubelet metrics to reduce cardinality while keeping useful CPU metrics ([**@IvanHunters**](https://github.com/IvanHunters) in #1455). + +### Storage & Backups + +* PVC expansion in tenant clusters via KubeVirt CSI resizer; RBAC updates (Klinch0 in #1438). +* Velero upgraded to **v1.17.0**; node agent enabled by default and a raft of usability features ([**@kvaps**](https://github.com/kvaps) in #1484). + +### Kubernetes/tests & Tooling + +* Smarter Kubernetes test flows: node readiness checks, kubelet version validation, longer rollout waits, per-component readiness ([**@IvanHunters**](https://github.com/IvanHunters) in #1485). + +### UI/Icons + +* New **VM-Disk** SVG icon ([**@kvapsova**](https://github.com/kvapsova) in #1435). + +--- + +## Improvements (minor) + +* Make the **Info** app deploy irrespective of OIDC settings ([**klinch0**](https://github.com/klinch0) in #1474). +* Move SA token Secret creation to **Info** app ([**@lllamnyp**](https://github.com/lllamnyp) in #1446). +* Explicitly set lineage labels for VictoriaMetrics resources ([**@lllamnyp**](https://github.com/lllamnyp) in #1452). + +--- + +## Bug fixes + +* **Kubernetes**: fix MachineDeployment `spec.selector` mismatch to ensure proper targeting ([**@kvaps**](https://github.com/kvaps) in #1502). +* **Old dashboard**: FerretDB spec typo prevented deploy/display ([**@lllamnyp**](https://github.com/lllamnyp) in #1440). +* **SeaweedFS**: fix per-zone size fallback for multi-DC volumes; make migrations more robust ([**@kvaps**](https://github.com/kvaps) in #1476, #1430). +* **CoreDNS**: pin tag to v1.12.4 ([**@kvaps**](https://github.com/kvaps) in #1469). +* **OIDC**: avoid creating KeycloakRealmGroup before operator API is available ([**@lllamnyp**](https://github.com/lllamnyp) in #1495). +* **Kafka**: disable noisy alerts when Kafka isn’t deployed ([**@lllamnyp**](https://github.com/lllamnyp) in #1488). + +--- + +## Dependency & version updates + +* **Velero → v1.17.0**; Helm chart v11; node agent default-on ([**@kvaps**](https://github.com/kvaps) in #1484). +* **Cilium → v1.17.8** ([**@kvaps**](https://github.com/kvaps) in #1473). +* **Flux Operator → v0.29.0** (Kingdon Barrett in #1466). + +--- + +## Refactors & chores + +* Remove legacy `versions_map`; unify packaging targets; tighten HelmRelease defaults; replace many chart versions with build-time placeholders ([**@kvaps**](https://github.com/kvaps) in #1453). +* Pin CoreDNS image and refresh numerous images ([**@kvaps**](https://github.com/kvaps) in #1469; related image refreshes across #1448 work). + +--- + +## Documentation & governance + +* **Contributor Ladder** created and later updated (Timur Tukaev in #1224; Andrei Kvapil & Timur Tukaev in #1492). +* **Code of Conduct** updated with a Vendor Neutrality Manifesto (Timur Tukaev in #1493). +* **Adopters**: add Hidora (Matthieu Robin in #1429). +* **MAINTAINERS**: add/remove entries (Nikita Bykov in #1487; Timur Tukaev in #1491). +* **Issue templates**: new bug-report template and tweaks (Moriarti). +* **README**: updated dark-theme screenshot ([**@kvaps**](https://github.com/kvaps) in #1459). + +--- + +## Breaking changes & upgrade notes + + +--- + +## Security & stability + diff --git a/docs/changelogs/v0.37.1.md b/docs/changelogs/v0.37.1.md new file mode 100644 index 00000000..fb0e3068 --- /dev/null +++ b/docs/changelogs/v0.37.1.md @@ -0,0 +1,31 @@ + + + +## Features and Improvements + +* **[api] Efficient listing of TenantNamespaces**: Optimized TenantNamespace listing by replacing per-namespace SubjectAccessReview calls with group-based rolebinding checks, significantly reducing API latency and improving performance ([**@lllamnyp**](https://github.com/lllamnyp) in #1507). + +## Fixes + +* **[api] Fix RBAC for listing of TenantNamespaces and handle system:masters**: Fixed regression in TenantNamespace listing RBAC and added proper handling for system:masters group to ensure correct authorization ([**@kvaps**](https://github.com/kvaps) in #1511). +* **[dashboard] Fix logout**: Fixed dashboard logout functionality to properly clear session and redirect users ([**@kvaps**](https://github.com/kvaps) in #1510). +* **[installer] Add additional check to wait for lineage-webhook**: Added additional readiness check to ensure lineage-webhook is fully ready before proceeding with installation, improving upgrade reliability ([**@kvaps**](https://github.com/kvaps) in #1506). + +## Development, Testing, and CI/CD + +* **[tests] Make Kubernetes tests POSIX-compatible**: Replaced bash-specific constructs with POSIX-compliant code, ensuring tests work reliably with /bin/sh and improving compatibility across different shell environments ([**@IvanHunters**](https://github.com/IvanHunters) in #1509). + +## Documentation + +* **[website] Update troubleshooting documentation**: Updated Kubernetes installation troubleshooting guide with additional information and fixes ([**@lb0o**](https://github.com/lb0o) in cozystack/website@82beddd). +* **[website] Add LLDPD disabling documentation**: Added minimal patch documentation for disabling lldpd based on official LLDPD usage guide ([**@lb0o**](https://github.com/lb0o) in cozystack/website@7ec5d7b). +* **[website] Fix typo in utility command**: Fixed typo in utility command documentation ([**@lb0o**](https://github.com/lb0o) in cozystack/website@6c76cb5). +* **[website] Update backup and recovery docs**: Updated backup and recovery documentation with latest information ([**@kvaps**](https://github.com/kvaps) in cozystack/website@2781aa5). +* **[website] Add Troubleshooting checklist**: Added troubleshooting checklist to help users diagnose and resolve common issues ([**@kvaps**](https://github.com/kvaps) in cozystack/website@59fc304). + +--- + +**Full Changelog**: [v0.37.0...v0.37.1](https://github.com/cozystack/cozystack/compare/v0.37.0...v0.37.1) + diff --git a/docs/changelogs/v0.37.10.md b/docs/changelogs/v0.37.10.md new file mode 100644 index 00000000..18f0dd8b --- /dev/null +++ b/docs/changelogs/v0.37.10.md @@ -0,0 +1,16 @@ + + +## Features and Improvements + +* **[virtual-machine] Improve check for resizing job**: Improved storage resize logic to only expand persistent volume claims when storage is being increased, preventing unintended storage reduction operations. Added validation to accurately compare current and desired storage sizes before triggering resize operations ([**@kvaps**](https://github.com/kvaps) in #1688, #1702). + +## Fixes + +* **[dashboard] Fix CustomFormsOverride schema to nest properties under spec.properties**: Fixed the logic for generating CustomFormsOverride schema to properly nest properties under `spec.properties` instead of directly under `properties`, ensuring correct form schema generation in the dashboard ([**@kvaps**](https://github.com/kvaps) in #1692, #1699). + +--- + +**Full Changelog**: [v0.37.9...v0.37.10](https://github.com/cozystack/cozystack/compare/v0.37.9...v0.37.10) + diff --git a/docs/changelogs/v0.37.2.md b/docs/changelogs/v0.37.2.md new file mode 100644 index 00000000..8cdcb05b --- /dev/null +++ b/docs/changelogs/v0.37.2.md @@ -0,0 +1,21 @@ + + + +## Features and Improvements + +* **[lineage] Separate webhook from cozy controller**: Separated the lineage-controller-webhook from cozystack-controller into a separate daemonset component deployed on all control-plane nodes, reducing API server latency and improving performance by decreasing outgoing API calls. Introduced internal label to track resources already handled by the webhook ([**@lllamnyp**](https://github.com/lllamnyp) in #1515). + +## Fixes + +* **[api] Fix listing tenantnamespaces for non-oidc users**: Fixed TenantNamespace listing functionality for users not using OIDC authentication, ensuring proper namespace visibility for all authentication methods ([**@kvaps**](https://github.com/kvaps) in #1517, #1519). + +## Migration and Upgrades + +* **[platform] Better migration for 0.36.2->0.37.2+**: Improved migration script for users upgrading directly from 0.36.2 to 0.37.2+, ensuring the new lineage webhook daemonset is properly deployed and fixing a bug where webhook readiness was not appropriately verified during migration ([**@lllamnyp**](https://github.com/lllamnyp) in #1521, #1522). + +--- + +**Full Changelog**: [v0.37.1...v0.37.2](https://github.com/cozystack/cozystack/compare/v0.37.1...v0.37.2) + diff --git a/docs/changelogs/v0.37.3.md b/docs/changelogs/v0.37.3.md new file mode 100644 index 00000000..58ff3977 --- /dev/null +++ b/docs/changelogs/v0.37.3.md @@ -0,0 +1,45 @@ + + + +## Features and Improvements + +* **[apps] Make VM service user facing**: Virtual machine services are now marked as user-facing, improving service discovery and visibility in the dashboard ([**@lllamnyp**](https://github.com/lllamnyp) in #1523). +* **[seaweedfs] Allow users to discover their buckets**: Users can now discover and list their S3 buckets in SeaweedFS, improving usability and bucket management ([**@kvaps**](https://github.com/kvaps) in #1528). +* **[seaweedfs] Update SeaweedFS v3.99 and deploy S3 as stacked service**: Updated SeaweedFS to version 3.99 and deployed S3 gateway as a stacked service for better integration and performance ([**@kvaps**](https://github.com/kvaps) in #1562). +* **[dashboard] Show service LB IP**: Fixed JSON path issue to correctly display Service LoadBalancer IPs in the dashboard table view, improving visibility of service endpoints ([**@lllamnyp**](https://github.com/lllamnyp) in #1524). +* **[dashboard] Update openapi-ui v1.0.3 + fixes**: Updated OpenAPI UI to version 1.0.3 with various fixes and improvements ([**@kvaps**](https://github.com/kvaps) in #1564). +* **[kubernetes] Use controlPlane.replicas field**: Fixed managed Kubernetes app to properly use the `controlPlane.replicas` field instead of hardcoding the value, allowing users to configure control plane replica count ([**@lllamnyp**](https://github.com/lllamnyp) in #1556). +* **[monitoring] add settings alert for slack**: Added Slack integration configuration for Alerta alerts, enabling notifications to Slack channels ([**@scooby87**](https://github.com/scooby87) in #1545). + +## Fixes + +* **[lineage] Check for nil chart in HelmRelease**: Added nil check to prevent crashes when lineage webhook encounters HelmReleases using `chartRef` instead of `chart`, improving stability ([**@lllamnyp**](https://github.com/lllamnyp) in #1525). +* **[kamaji] Respect 3rd party labels**: Applied patch to Kamaji controller to respect third-party labels, preventing reconciliation loops between lineage webhook and Kamaji controller ([**@lllamnyp**](https://github.com/lllamnyp) in #1531, #1534). +* **[redis-operator] Build patched operator in-tree**: Moved Redis operator build into Cozystack organization and patched it to prevent overwriting third-party labels on owned resources ([**@lllamnyp**](https://github.com/lllamnyp) in #1547). +* **[mariadb-operator] Add post-delete job to remove PVCs**: Added post-delete job to automatically remove PersistentVolumeClaims when MariaDB instances are deleted, preventing orphaned storage resources ([**@IvanHunters**](https://github.com/IvanHunters) in #1553). +* **[velero] Set defaultItemOperationTimeout=24h**: Set default item operation timeout to 24 hours for Velero backups, preventing timeouts on large backup operations ([**@kvaps**](https://github.com/kvaps) in #1542). + +## Dependencies + +* **Update LINSTOR v1.32.3**: Updated LINSTOR to version 1.32.3 with latest features and bug fixes ([**@kvaps**](https://github.com/kvaps) in #1565). + +## System Configuration + +* **[system] kube-ovn: turn off enableLb**: Disabled load balancer functionality in Kube-OVN configuration ([**@nbykov0**](https://github.com/nbykov0) in #1548). + +## Documentation + +* **[website] Update LINSTOR documentation**: Updated LINSTOR guide and set failmode=continue for ZFS configurations ([**@kvaps**](https://github.com/kvaps) in cozystack/website@033804e). +* **[website] Update managed apps reference**: Updated managed applications reference documentation ([**@kvaps**](https://github.com/kvaps) in cozystack/website@b886a74). +* **[website] Update external apps documentation**: Updated documentation for external applications ([**@kvaps**](https://github.com/kvaps) in cozystack/website@565dad9). +* **[website] Add naming conventions**: Added naming conventions documentation ([**@kvaps**](https://github.com/kvaps) in cozystack/website@b227abb). +* **[website] Update golden image documentation**: Updated documentation for creating golden images for virtual machines ([**@kvaps**](https://github.com/kvaps) in cozystack/website@34c2f3a, cozystack/website@ef65593). +* **[website] Fix documentation formatting**: Fixed alerts, infoboxes, tabs styles and main page formatting ([**@kvaps**](https://github.com/kvaps) in cozystack/website@e992e97, cozystack/website@b2c4dee). +* **[website] Fix typo in blog article**: Fixed typo in blog article ([**@kvaps**](https://github.com/kvaps) in cozystack/website@0a4bbf3). + +--- + +**Full Changelog**: [v0.37.2...v0.37.3](https://github.com/cozystack/cozystack/compare/v0.37.2...v0.37.3) + diff --git a/docs/changelogs/v0.37.4.md b/docs/changelogs/v0.37.4.md new file mode 100644 index 00000000..a7eea2fc --- /dev/null +++ b/docs/changelogs/v0.37.4.md @@ -0,0 +1,29 @@ + + + +## Features and Improvements + +* **[tenant] Allow listing workloads**: Enabled listing of workloads for tenants, improving visibility and management of tenant resources ([**@kvaps**](https://github.com/kvaps) in #1576, #1577). + +## Fixes + +* **[seaweedfs] Fix migration to v3.99**: Fixed migration issues when upgrading SeaweedFS to version 3.99, ensuring smooth upgrades ([**@kvaps**](https://github.com/kvaps) in #1572, #1575). +* **[nats] Merge container spec, not podTemplate**: Fixed NATS configuration to properly merge container specifications instead of podTemplate, ensuring correct container configuration ([**@lllamnyp**](https://github.com/lllamnyp) in #1571, #1574). + +## Development, Testing, and CI/CD + +* **[e2e] Increase Kubernetes connection timeouts**: Increased connection and request timeouts in E2E tests when communicating with Kubernetes API, improving test stability under high load and slow cluster response conditions ([**@IvanHunters**](https://github.com/IvanHunters) in #1570, #1573). + +## Documentation + +* **[website] Optimize website for mobile devices**: Improved website layout and responsiveness for mobile devices ([**@kvaps**](https://github.com/kvaps) in cozystack/website@3ab2338). +* **[website] Add OpenAPI UI**: Added OpenAPI UI documentation and integration ([**@kvaps**](https://github.com/kvaps) in cozystack/website@b1c1668). +* **[website] Update Cozystack video in hero banner**: Updated hero banner with new Cozystack video ([**@kvaps**](https://github.com/kvaps) in cozystack/website@e351137). +* **[website] Add screenshots carousel**: Added screenshots carousel to showcase Cozystack features ([**@kvaps**](https://github.com/kvaps) in cozystack/website@8422bd0). + +--- + +**Full Changelog**: [v0.37.3...v0.37.4](https://github.com/cozystack/cozystack/compare/v0.37.3...v0.37.4) + diff --git a/docs/changelogs/v0.37.5.md b/docs/changelogs/v0.37.5.md new file mode 100644 index 00000000..f355b651 --- /dev/null +++ b/docs/changelogs/v0.37.5.md @@ -0,0 +1,28 @@ + + + +## Features and Improvements + +* **[dashboard-controller] Move badges generation logic to internal dashboard component**: Moved badges generation logic to internal dashboard component for better code organization and maintainability ([**@kvaps**](https://github.com/kvaps) in #1567). + +## Security + +* **[redis] Bump Redis image version for security fixes**: Updated Redis image version to include latest security fixes, improving cluster security ([**@IvanHunters**](https://github.com/IvanHunters) in #1580). +* **[flux] Close Flux Operator ports to external access**: Removed hostPort and hostNetwork from Flux Operator Deployment, ensuring ports 8080 and 8081 are only accessible within the cluster, preventing external exposure and improving security ([**@IvanHunters**](https://github.com/IvanHunters) in #1581). +* **[ingress] Enforce HTTPS-only for API**: Added force-ssl-redirect annotation to default API Ingress, ensuring all HTTP traffic is redirected to HTTPS, preventing unencrypted external access and improving security ([**@IvanHunters**](https://github.com/IvanHunters) in #1582, #1585). + +## Fixes + +* **[nats] Fixes for NATS App Helm chart, fix template issues with config.merge**: Fixed template issues in NATS Helm chart related to config.merge value, ensuring correct configuration ([**@insignia96**](https://github.com/insignia96) in #1583, #1591). +* **[kubevirt] Fix: kubevirt metrics rule**: Fixed KubeVirt metrics rule configuration ([**@kvaps**](https://github.com/kvaps) in #1584, #1588). + +## System Configuration + +* **[core] rm talos lldp extension**: Removed Talos LLDP extension from core configuration ([**@nbykov0**](https://github.com/nbykov0) in #1586). + +--- + +**Full Changelog**: [v0.37.4...v0.37.5](https://github.com/cozystack/cozystack/compare/v0.37.4...v0.37.5) + diff --git a/docs/changelogs/v0.37.6.md b/docs/changelogs/v0.37.6.md new file mode 100644 index 00000000..57d6e0eb --- /dev/null +++ b/docs/changelogs/v0.37.6.md @@ -0,0 +1,30 @@ + + + +## Features and Improvements + +* **[api] Use shared informer cache**: Optimized API server by using shared informer cache, reducing API server load and improving performance ([**@lllamnyp**](https://github.com/lllamnyp) in #1539). +* **[dashboard] sync with upstream & enhancements**: Synchronized dashboard with upstream and added various enhancements ([**@kvaps**](https://github.com/kvaps) in #1603). +* **[cozystack-api][dashboard] Fix filtering for application services/ingresses/secrets**: Fixed filtering functionality for application services, ingresses, and secrets in both API and dashboard ([**@kvaps**](https://github.com/kvaps) in #1612). + +## Fixes + +* **[controller] Remove crdmem, handle DaemonSet**: Removed crdmem and improved DaemonSet handling in controller ([**@lllamnyp**](https://github.com/lllamnyp) in #1555). +* **[dashboard] Revert reconciler removal**: Reverted reconciler removal to restore proper dashboard functionality ([**@lllamnyp**](https://github.com/lllamnyp) in #1559). +* **[dashboard-controller] Fix static resources reconciliation and showing secrets**: Fixed static resources reconciliation and improved secret display in dashboard controller ([**@kvaps**](https://github.com/kvaps) in #1605). +* **[api,lineage] Ensure node-local traffic**: Ensured node-local traffic handling for API and lineage components ([**@lllamnyp**](https://github.com/lllamnyp) in #1606). +* **[virtual-machine] Revert per-vm network policies**: Reverted per-VM network policies to previous behavior ([**@lllamnyp**](https://github.com/lllamnyp) in #1611). +* **[cozy-lib] Fix: handling resources=nil**: Fixed handling of nil resources in cozy-lib templates ([**@kvaps**](https://github.com/kvaps) in #1607). +* **[nats] Use dig function to check for existing secret and prevent nil indexing**: Fixed NATS app chart to use dig function for checking existing secrets and prevent nil indexing errors ([**@kvaps**](https://github.com/kvaps) in #1609, #1610). + +## Development, Testing, and CI/CD + +* **[cozystack-controller] improve API tests**: Improved API tests for cozystack-controller ([**@lllamnyp**](https://github.com/lllamnyp) in #1599). +* **[kubernetes] Helm hooks for cleanup**: Added Helm hooks for cleanup operations in Kubernetes app ([**@lllamnyp**](https://github.com/lllamnyp) in #1616). + +--- + +**Full Changelog**: [v0.37.5...v0.37.6](https://github.com/cozystack/cozystack/compare/v0.37.5...v0.37.6) + diff --git a/docs/changelogs/v0.37.7.md b/docs/changelogs/v0.37.7.md new file mode 100644 index 00000000..ff167a21 --- /dev/null +++ b/docs/changelogs/v0.37.7.md @@ -0,0 +1,18 @@ + + + +## Fixes + +* **[kubernetes] Cleanup loadbalancer services**: Added cleanup functionality for load balancer services in Kubernetes app ([**@lllamnyp**](https://github.com/lllamnyp) in #1622). +* **[rbac] Fix permissions for high-privilege users**: Fixed RBAC permissions for high-privilege users, ensuring proper access control ([**@lllamnyp**](https://github.com/lllamnyp) in #1624). + +## System Configuration + +* **[system] kubeovn: increase limits**: Increased resource limits for Kube-OVN components to improve stability and performance ([**@nbykov0**](https://github.com/nbykov0) in #1629). + +--- + +**Full Changelog**: [v0.37.6...v0.37.7](https://github.com/cozystack/cozystack/compare/v0.37.6...v0.37.7) + diff --git a/docs/changelogs/v0.37.8.md b/docs/changelogs/v0.37.8.md new file mode 100644 index 00000000..aa6802b4 --- /dev/null +++ b/docs/changelogs/v0.37.8.md @@ -0,0 +1,19 @@ + + + +## Fixes + +* **[cozy-lib] Fix malformed ResourceQuota rendering for LoadBalancer services**: Fixed malformed ResourceQuota rendering for LoadBalancer services in cozy-lib templates ([**@IvanHunters**](https://github.com/IvanHunters) in #1642). +* **[extra] ingress: rm spaces from external ip list**: Removed spaces from external IP list in ingress configuration, fixing formatting issues ([**@nbykov0**](https://github.com/nbykov0) in #1652). +* **scripts: fix 20 migration**: Fixed migration script #20 to ensure proper execution during upgrades ([**@nbykov0**](https://github.com/nbykov0) in #1653). + +## System Configuration + +* **Increase strimzi memory limit**: Increased memory limit for Strimzi Kafka operator to improve stability and performance ([**@nbykov0**](https://github.com/nbykov0) in #1651). + +--- + +**Full Changelog**: [v0.37.7...v0.37.8](https://github.com/cozystack/cozystack/compare/v0.37.7...v0.37.8) + diff --git a/docs/changelogs/v0.37.9.md b/docs/changelogs/v0.37.9.md new file mode 100644 index 00000000..59704863 --- /dev/null +++ b/docs/changelogs/v0.37.9.md @@ -0,0 +1,19 @@ + + + +## Improvements + +* **[seaweedfs] Extended CA certificate duration to reduce disruptive CA rotations**: Extended CA certificate duration to reduce disruptive CA rotations. ([**@IvanHunters**](https://github.com/IvanHunters) in #1657, #1666). +* **[dashboard] Add config hash annotations to restart pods on config changes**: Added config hash annotations to restart pods when configuration changes, ensuring pods are automatically restarted when their configuration is updated ([**@kvaps**](https://github.com/kvaps) in #1662, #1665). + +## Fixes + +* **[tenant][kubernetes] Introduce better cleanup logic**: Improved cleanup logic for tenant Kubernetes resources, ensuring proper resource cleanup when tenants are deleted or updated ([**@kvaps**](https://github.com/kvaps) in #1661). +* **[dashboard] Fix loading arrays in forms when editing existing objects**: Fixed issue where arrays in forms were not loading correctly when editing existing objects in the dashboard ([**@kvaps**](https://github.com/kvaps)). + +--- + +**Full Changelog**: [v0.37.8...v0.37.9](https://github.com/cozystack/cozystack/compare/v0.37.8...v0.37.9) + diff --git a/docs/changelogs/v0.38.0.md b/docs/changelogs/v0.38.0.md new file mode 100644 index 00000000..99c233b0 --- /dev/null +++ b/docs/changelogs/v0.38.0.md @@ -0,0 +1,235 @@ +# Cozystack v0.38 — "VPC & Enhanced Networking" + +This release introduces **Virtual Private Cloud (VPC)** support, enabling advanced networking capabilities for tenant applications. We've also added VNC console support in the dashboard, made Kubernetes worker versions configurable, and delivered numerous improvements and fixes across the platform. + +### Virtual Private Cloud (VPC) Networking + +Cozystack v0.38.0 introduces Virtual Private Cloud (VPC) support, enabling platform administrators to create isolated network segments for tenant applications. VPCs provide network isolation and allow fine-grained control over network topology, subnets, and routing. Each VPC can contain multiple subnets, and administrators can configure subnet details including IP ranges, gateway settings, and DNS configuration. + +The VPC feature integrates seamlessly with the Cozystack dashboard, allowing users to view and manage VPCs and their subnets through an intuitive interface. Subnet details are exposed in the dashboard as tables, making it easy to understand network configuration at a glance. VPC configuration is stored in ConfigMaps with predictable naming, ensuring reliable access to subnet information. + +This feature is particularly valuable for multi-tenant environments where network isolation is critical, and for applications that require specific network configurations or routing rules. + +### VNC Console for Virtual Machines + +The Cozystack dashboard now includes a built-in VNC console for virtual machines, enabling users to access VM console directly from the web interface without requiring external tools. This feature provides immediate access to virtual machine consoles for troubleshooting, configuration, and maintenance tasks. The VNC console integration streamlines VM management workflows and improves the user experience by keeping all VM operations within the Cozystack dashboard. + +## Highlights + +* **Virtual Private Cloud (VPC)**: New VPC system module enables advanced networking with Multus CNI, subnet management, and network isolation for tenant applications ([**@nbykov0**](https://github.com/nbykov0) in #1543; [**@lllamnyp**](https://github.com/lllamnyp) in #1587, #1590, #1600, #1621, #1638). +* **VNC Console in Dashboard**: Users can now access virtual machine consoles directly from the dashboard, improving VM management experience ([**@kvaps**](https://github.com/kvaps) in #1627). +* **Configurable Kubernetes Worker Versions**: Platform administrators can now configure Kubernetes worker node versions independently, providing more flexibility in cluster management ([**@lllamnyp**](https://github.com/lllamnyp) in #1619). +* **Security Enhancements**: Multiple security improvements including HTTPS-only enforcement for API, closed Flux Operator ports, and Redis security updates ([**@IvanHunters**](https://github.com/IvanHunters) in #1580, #1581, #1582). +* **Cozy-lib Improvements**: Enhanced flatten function with better ResourceQuota handling and nil resource support ([**@lllamnyp**](https://github.com/lllamnyp) in #1647; [**@IvanHunters**](https://github.com/IvanHunters) in #1642; [**@kvaps**](https://github.com/kvaps) in #1607). + +--- + +## New features + +### VPC (Virtual Private Cloud) + +* **[system] Add VPC**: Introduced Virtual Private Cloud system module with Multus CNI integration, enabling advanced networking capabilities for tenant applications ([**@nbykov0**](https://github.com/nbykov0) in #1543). +* **[vpc] Install Multus by default**: Multus CNI is now installed by default when VPC is enabled, providing multi-network interface support ([**@lllamnyp**](https://github.com/lllamnyp) in #1587). +* **[vpc] Give predictable name to subnet configmap**: Subnet configuration maps now use predictable naming for better management and debugging ([**@lllamnyp**](https://github.com/lllamnyp) in #1590). +* **[vpc] Entry per subnet in the subnets configmap**: Each subnet now has its own entry in the subnets configmap, improving subnet organization and management ([**@lllamnyp**](https://github.com/lllamnyp) in #1600). +* **[vpc,dashboard] Print subnet details as table**: Subnet details are now displayed as a table in the dashboard, improving visibility and management ([**@lllamnyp**](https://github.com/lllamnyp) in #1621). +* **[apps] Add VPC app**: Added VPC application for tenant use, enabling users to create and manage VPCs ([**@nbykov0**](https://github.com/nbykov0) in #1543). + +### Dashboard + +* **[dashboard] Introduce VNC console**: Added VNC console support in the dashboard, allowing users to access virtual machine consoles directly from the web interface ([**@kvaps**](https://github.com/kvaps) in #1627). +* **[dashboard] sync with upstream & enhancements**: Synchronized dashboard with upstream project and added various enhancements ([**@kvaps**](https://github.com/kvaps) in #1603). +* **[dashboard] Migrate patches to upstream project**: Migrated dashboard patches to upstream project for better maintainability ([**@kvaps**](https://github.com/kvaps) in #1569). + +### Kubernetes + +* **[kubernetes] Make worker version configurable**: Platform administrators can now configure Kubernetes worker node versions independently from control plane versions, providing more flexibility ([**@lllamnyp**](https://github.com/lllamnyp) in #1619). +* **[kubernetes] Use controlPlane.replicas field**: Fixed managed Kubernetes app to properly use the `controlPlane.replicas` field instead of hardcoding the value ([**@lllamnyp**](https://github.com/lllamnyp) in #1556). +* **[kubernetes] Helm hooks for cleanup**: Added Helm hooks for cleanup operations in Kubernetes app ([**@lllamnyp**](https://github.com/lllamnyp) in #1606). + +### API & Platform + +* **[api] Efficient listing of TenantNamespaces**: Optimized TenantNamespace listing by replacing per-namespace SubjectAccessReview calls with group-based rolebinding checks, significantly reducing API latency ([**@lllamnyp**](https://github.com/lllamnyp) in #1507). +* **[api] Use shared informer cache**: Optimized API server by using shared informer cache, reducing API server load and improving performance ([**@lllamnyp**](https://github.com/lllamnyp) in #1539). +* **[api] Fix representation of dynamic list kinds**: Fixed API representation of dynamic list kinds for better compatibility ([**@lllamnyp**](https://github.com/lllamnyp) in #1630). +* **[api] Delete previous instance when changing type**: API now properly deletes previous instance when changing application type ([**@lllamnyp**](https://github.com/lllamnyp) in #1579). + +### Applications + +* **[tenant] Allow listing workloads**: Enabled listing of workloads for tenants, improving visibility and management of tenant resources ([**@kvaps**](https://github.com/kvaps) in #1576). +* **[apps] Make VM service user facing**: Virtual machine services are now marked as user-facing, improving service discovery and visibility in the dashboard ([**@lllamnyp**](https://github.com/lllamnyp) in #1523). +* **[foundationdb] Upgrade FDB app for latest Cozy**: Upgraded FoundationDB application for compatibility with latest Cozystack version ([**@lllamnyp**](https://github.com/lllamnyp) in #1505). + +### Storage & Backups + +* **[seaweedfs] Update SeaweedFS v3.99 and deploy S3 as stacked service**: Updated SeaweedFS to version 3.99 and deployed S3 gateway as a stacked service for better integration and performance ([**@kvaps**](https://github.com/kvaps) in #1562). +* **[seaweedfs] Allow users to discover their buckets**: Users can now discover and list their S3 buckets in SeaweedFS, improving usability and bucket management ([**@kvaps**](https://github.com/kvaps) in #1528). +* **[velero] Set defaultItemOperationTimeout=24h**: Set default item operation timeout to 24 hours for Velero backups, preventing timeouts on large backup operations ([**@kvaps**](https://github.com/kvaps) in #1542). + +### Monitoring & Operations + +* **[monitoring] add settings alert for slack**: Added Slack integration configuration for Alerta alerts, enabling notifications to Slack channels ([**@scooby87**](https://github.com/scooby87) in #1545). + +--- + +## Improvements (minor) + +* **[lineage] Separate webhook from cozy controller**: Separated the lineage-controller-webhook from cozystack-controller into a separate daemonset component deployed on all control-plane nodes, reducing API server latency ([**@lllamnyp**](https://github.com/lllamnyp) in #1515). +* **[dashboard] Show service LB IP**: Fixed JSON path issue to correctly display Service LoadBalancer IPs in the dashboard table view ([**@lllamnyp**](https://github.com/lllamnyp) in #1524). +* **[dashboard] Update openapi-ui v1.0.3 + fixes**: Updated OpenAPI UI to version 1.0.3 with various fixes and improvements ([**@kvaps**](https://github.com/kvaps) in #1564). +* **[dashboard-controller] Move badges generation logic to internal dashboard component**: Moved badges generation logic to internal dashboard component for better code organization ([**@kvaps**](https://github.com/kvaps) in #1567). +* **[bucket] Expose bucket name in secrets**: Bucket names are now exposed in secrets for better integration with applications ([**@lllamnyp**](https://github.com/lllamnyp) in #1518). +* **[platform] Better migration for 0.36.2->0.37.2+**: Improved migration script for users upgrading directly from 0.36.2 to 0.37.2+ ([**@lllamnyp**](https://github.com/lllamnyp) in #1521). +* **[cozy-lib] Improve flatten function**: Improved flatten function in cozy-lib with better handling of complex resource structures ([**@lllamnyp**](https://github.com/lllamnyp) in #1647). +* **[dx] JSDoc compatible syntax for values.yaml**: Added JSDoc compatible syntax for values.yaml documentation ([**@kvaps**](https://github.com/kvaps) in #1536). +* **[system] Tune kubevirt rollout and eviction settings**: Tuned KubeVirt rollout and eviction settings for better stability ([**@nbykov0**](https://github.com/nbykov0) in #1544). +* **[system] multus: update to the latest version**: Updated Multus CNI to the latest version ([**@nbykov0**](https://github.com/nbykov0) in #1628). +* **[system] kubeovn: increase limits**: Increased resource limits for Kube-OVN components to improve stability and performance ([**@nbykov0**](https://github.com/nbykov0) in #1629). +* **[linstor] Update Piraeus Operator to v2.10.1 to enable RWX support**: Updated Piraeus Operator to v2.10.1, enabling ReadWriteMany (RWX) volume support ([**@kvaps**](https://github.com/kvaps) in #1650). +* **[ci,dx] Bump MariaDB operator version**: Bumped MariaDB operator version for latest features and bug fixes ([**@IvanHunters**](https://github.com/IvanHunters) in #1646). + +--- + +## Bug fixes + +* **[api] Fix RBAC for listing of TenantNamespaces and handle system:masters**: Fixed regression in TenantNamespace listing RBAC and added proper handling for system:masters group ([**@kvaps**](https://github.com/kvaps) in #1511). +* **[api] Fix listing tenantnamespaces for non-oidc users**: Fixed TenantNamespace listing functionality for users not using OIDC authentication ([**@kvaps**](https://github.com/kvaps) in #1517). +* **[dashboard] Fix logout**: Fixed dashboard logout functionality to properly clear session and redirect users ([**@kvaps**](https://github.com/kvaps) in #1510). +* **[installer] Add additional check to wait for lineage-webhook**: Added additional readiness check to ensure lineage-webhook is fully ready before proceeding with installation ([**@kvaps**](https://github.com/kvaps) in #1506). +* **[lineage] Check for nil chart in HelmRelease**: Added nil check to prevent crashes when lineage webhook encounters HelmReleases using `chartRef` instead of `chart` ([**@lllamnyp**](https://github.com/lllamnyp) in #1525). +* **[kamaji] Respect 3rd party labels**: Applied patch to Kamaji controller to respect third-party labels, preventing reconciliation loops ([**@lllamnyp**](https://github.com/lllamnyp) in #1531). +* **[redis-operator] Build patched operator in-tree**: Moved Redis operator build into Cozystack organization and patched it to prevent overwriting third-party labels ([**@lllamnyp**](https://github.com/lllamnyp) in #1547). +* **[mariadb-operator] Add post-delete job to remove PVCs**: Added post-delete job to automatically remove PersistentVolumeClaims when MariaDB instances are deleted ([**@IvanHunters**](https://github.com/IvanHunters) in #1553). +* **[seaweedfs] Fix migration to v3.99**: Fixed migration issues when upgrading SeaweedFS to version 3.99 ([**@kvaps**](https://github.com/kvaps) in #1572). +* **[nats] Merge container spec, not podTemplate**: Fixed NATS configuration to properly merge container specifications instead of podTemplate ([**@lllamnyp**](https://github.com/lllamnyp) in #1571). +* **[nats] Fixes for NATS App Helm chart, fix template issues with config.merge**: Fixed template issues in NATS Helm chart related to config.merge value ([**@insignia96**](https://github.com/insignia96) in #1583). +* **[nats] Fix NATS app chart to use existing secret credentials when present**: Fixed NATS app chart to use existing secret credentials when present, preventing credential regeneration ([**@insignia96**](https://github.com/insignia96) in #1599). +* **[kubevirt] Fix: kubevirt metrics rule**: Fixed KubeVirt metrics rule configuration ([**@kvaps**](https://github.com/kvaps) in #1584). +* **[controller] Remove crdmem, handle DaemonSet**: Removed crdmem and improved DaemonSet handling in controller ([**@lllamnyp**](https://github.com/lllamnyp) in #1555). +* **[dashboard] Revert reconciler removal**: Reverted reconciler removal to restore proper dashboard functionality ([**@lllamnyp**](https://github.com/lllamnyp) in #1559). +* **[dashboard-controller] Fix static resources reconciliation and showing secrets**: Fixed static resources reconciliation and improved secret display in dashboard controller ([**@kvaps**](https://github.com/kvaps) in #1615). +* **[cozystack-api][dashboard] Fix filtering for application services/ingresses/secrets**: Fixed filtering functionality for application services, ingresses, and secrets in both API and dashboard ([**@kvaps**](https://github.com/kvaps) in #1612). +* **[virtual-machine] Revert per-vm network policies**: Reverted per-VM network policies to previous behavior ([**@kvaps**](https://github.com/kvaps) in #1611). +* **[cozy-lib] Fix: handling resources=nil**: Fixed handling of nil resources in cozy-lib templates ([**@kvaps**](https://github.com/kvaps) in #1607). +* **[cozy-lib] Fix malformed ResourceQuota rendering for LoadBalancer services**: Fixed malformed ResourceQuota rendering for LoadBalancer services in cozy-lib templates ([**@IvanHunters**](https://github.com/IvanHunters) in #1642). +* **[kubernetes] Cleanup loadbalancer services**: Added cleanup functionality for load balancer services in Kubernetes app ([**@lllamnyp**](https://github.com/lllamnyp) in #1631). +* **[rbac] Fix permissions for high-privilege users**: Fixed RBAC permissions for high-privilege users, ensuring proper access control ([**@lllamnyp**](https://github.com/lllamnyp) in #1622). +* **[vpc] Fix access to subnet details configmap**: Fixed access to subnet details configmap in VPC functionality ([**@lllamnyp**](https://github.com/lllamnyp) in #1638). +* **[api,lineage] Ensure node-local traffic**: Ensured node-local traffic handling for API and lineage components ([**@lllamnyp**](https://github.com/lllamnyp) in #1554). +* **[extra] ingress: rm spaces from external ip list**: Removed spaces from external IP list in ingress configuration, fixing formatting issues ([**@nbykov0**](https://github.com/nbykov0) in #1652). +* **scripts: fix 20 migration**: Fixed migration script #20 to ensure proper execution during upgrades ([**@nbykov0**](https://github.com/nbykov0) in #1653). + +--- + +## Security + +* **[redis] Bump Redis image version for security fixes**: Updated Redis image version to include latest security fixes, improving cluster security ([**@IvanHunters**](https://github.com/IvanHunters) in #1580). +* **[flux] Close Flux Operator ports to external access**: Removed hostPort and hostNetwork from Flux Operator Deployment, ensuring ports 8080 and 8081 are only accessible within the cluster ([**@IvanHunters**](https://github.com/IvanHunters) in #1581). +* **[ingress] Enforce HTTPS-only for API**: Added force-ssl-redirect annotation to default API Ingress, ensuring all HTTP traffic is redirected to HTTPS ([**@IvanHunters**](https://github.com/IvanHunters) in #1582). + +--- + +## Dependencies & version updates + +* **Update LINSTOR v1.32.3**: Updated LINSTOR to version 1.32.3 with latest features and bug fixes ([**@kvaps**](https://github.com/kvaps) in #1565). +* **Update Talos Linux v1.11.3**: Updated Talos Linux to version 1.11.3 ([**@kvaps**](https://github.com/kvaps) in #1527). +* **Update Kube-OVN v1.14.11**: Updated Kube-OVN to version 1.14.11 ([**@kvaps**](https://github.com/kvaps) in #1514). +* **[linstor] Update Piraeus Operator to v2.10.1**: Updated Piraeus Operator to v2.10.1 to enable RWX support ([**@kvaps**](https://github.com/kvaps) in #1650). +* **[system] multus: update to the latest version**: Updated Multus CNI to the latest version ([**@nbykov0**](https://github.com/nbykov0) in #1628). +* **[ci,dx] Bump MariaDB operator version**: Bumped MariaDB operator version ([**@IvanHunters**](https://github.com/IvanHunters) in #1646). +* **Increase strimzi memory limit**: Increased memory limit for Strimzi Kafka operator to improve stability and performance ([**@nbykov0**](https://github.com/nbykov0) in #1651). + +--- + +## System Configuration + +* **[system] kube-ovn: turn off enableLb**: Disabled load balancer functionality in Kube-OVN configuration ([**@nbykov0**](https://github.com/nbykov0) in #1548). +* **[core] rm talos lldp extension**: Removed Talos LLDP extension from core configuration ([**@nbykov0**](https://github.com/nbykov0) in #1586). + +--- + +## Development, Testing, and CI/CD + +* **[tests] Make Kubernetes tests POSIX-compatible**: Replaced bash-specific constructs with POSIX-compliant code, ensuring tests work reliably with /bin/sh ([**@IvanHunters**](https://github.com/IvanHunters) in #1509). +* **[ferretdb] fix tests**: Fixed FerretDB tests to ensure proper execution ([**@IvanHunters**](https://github.com/IvanHunters) in #1540). +* **[e2e] Increase Kubernetes connection timeouts**: Increased connection and request timeouts in E2E tests when communicating with Kubernetes API ([**@IvanHunters**](https://github.com/IvanHunters) in #1570). +* **[cozystack-controller] improve API tests**: Improved API tests for cozystack-controller ([**@kvaps**](https://github.com/kvaps) in #1617). +* **[ci] Fix build from external forks**: Fixed build process to work correctly from external forks ([**@kvaps**](https://github.com/kvaps) in #1530). +* **[ci,dx] Add unit tests for cozy-lib**: Added unit tests for cozy-lib to improve code quality and reliability ([**@lllamnyp**](https://github.com/lllamnyp) in #1643). + +--- + +## Documentation + +* **[website] Add VPC page**: Added VPC documentation page explaining VPC features and usage ([**@nbykov0**](https://github.com/nbykov0) in cozystack/website@9ccac78). +* **[website] Add VPC to auto-update list**: Added VPC to auto-update list in documentation ([**@nbykov0**](https://github.com/nbykov0) in cozystack/website@ca2bce6). +* **[website] Update dashboard part in OIDC configuration doc**: Updated OIDC configuration documentation with dashboard information ([**@nbykov0**](https://github.com/nbykov0) in cozystack/website@6c44b93). +* **[website] Update storage requirements**: Updated storage requirements documentation ([**@nbykov0**](https://github.com/nbykov0) in cozystack/website@cac3af6). +* **[website] Add System Resource Planning Recommendations**: Added system resource planning recommendations documentation ([**@kvaps**](https://github.com/kvaps) in cozystack/website@c877c2a). +* **[website] Optimize website for mobile devices**: Improved website layout and responsiveness for mobile devices ([**@kvaps**](https://github.com/kvaps) in cozystack/website@3ab2338). +* **[website] Add OpenAPI UI**: Added OpenAPI UI documentation and integration ([**@kvaps**](https://github.com/kvaps) in cozystack/website@b1c1668). +* **[website] Update Cozystack video in hero banner**: Updated hero banner with new Cozystack video ([**@kvaps**](https://github.com/kvaps) in cozystack/website@e351137). +* **[website] Add screenshots carousel**: Added screenshots carousel to showcase Cozystack features ([**@kvaps**](https://github.com/kvaps) in cozystack/website@8422bd0). +* **[website] Update LINSTOR documentation**: Updated LINSTOR guide and set failmode=continue for ZFS configurations ([**@kvaps**](https://github.com/kvaps) in cozystack/website@033804e). +* **[website] Update managed apps reference**: Updated managed applications reference documentation ([**@kvaps**](https://github.com/kvaps) in cozystack/website@b886a74, cozystack/website@41c1849, cozystack/website@0ab71fd). +* **[website] Update external apps documentation**: Updated documentation for external applications ([**@kvaps**](https://github.com/kvaps) in cozystack/website@565dad9). +* **[website] Add naming conventions**: Added naming conventions documentation ([**@kvaps**](https://github.com/kvaps) in cozystack/website@b227abb). +* **[website] Update golden image documentation**: Updated documentation for creating golden images for virtual machines ([**@kvaps**](https://github.com/kvaps) in cozystack/website@34c2f3a, cozystack/website@ef65593). +* **[website] Fix documentation formatting**: Fixed alerts, infoboxes, tabs styles and main page formatting ([**@kvaps**](https://github.com/kvaps) in cozystack/website@e992e97, cozystack/website@b2c4dee). +* **[website] Fix typo in blog article**: Fixed typo in blog article ([**@kvaps**](https://github.com/kvaps) in cozystack/website@0a4bbf3). +* **[apps] vpc: more docs**: Added more VPC documentation ([**@nbykov0**](https://github.com/nbykov0) in #1594). +* **[apps] vpc: fix typo in README**: Fixed typo in VPC README ([**@nbykov0**](https://github.com/nbykov0) in #1637). + +--- + +## Additional Repositories + +### boot-to-talos + +* **[boot-to-talos] Introduce boot/install mode**: Introduced boot/install mode in boot-to-talos tool ([**@kvaps**](https://github.com/kvaps) in cozystack/boot-to-talos#5). + +### cozypkg + +* **[cozypkg] Handle valuesFiles from cozypkg.cozystack.io/values-files annotation**: Added support for handling valuesFiles from annotation in cozypkg ([**@kvaps**](https://github.com/kvaps) in cozystack/cozypkg#8). + +--- + +## Refactors & chores + +* **[dashboard] Migrate patches to upstream project**: Migrated dashboard patches to upstream project for better maintainability ([**@kvaps**](https://github.com/kvaps) in #1569). +* **Update CODEOWNERS**: Updated CODEOWNERS file ([**@nbykov0**](https://github.com/nbykov0) in #1537). +* **Add QOSI to ADOPTERS.md**: Added QOSI to adopters list ([**@tabu-a**](https://github.com/tabu-a) in #1589). + +--- + +## Breaking changes & upgrade notes + +No breaking changes in this release. + +--- + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@IvanHunters**](https://github.com/IvanHunters) +* [**@insignia96**](https://github.com/insignia96) +* [**@kvaps**](https://github.com/kvaps) +* [**@lllamnyp**](https://github.com/lllamnyp) +* [**@nbykov0**](https://github.com/nbykov0) +* [**@scooby87**](https://github.com/scooby87) +* [**@tabu-a**](https://github.com/tabu-a) + +### New Contributors + +We're excited to welcome our first-time contributors: + +* [**@tabu-a**](https://github.com/tabu-a) - First contribution! + +--- + +**Full Changelog**: [v0.37.0...v0.38.0](https://github.com/cozystack/cozystack/compare/v0.37.0...v0.38.0) + + diff --git a/docs/changelogs/v0.38.1.md b/docs/changelogs/v0.38.1.md new file mode 100644 index 00000000..a3f49a7b --- /dev/null +++ b/docs/changelogs/v0.38.1.md @@ -0,0 +1,19 @@ + + + +## Improvements + +* **[seaweedfs] Extended CA certificate duration to reduce disruptive CA rotations**: Extended CA certificate duration to reduce disruptive CA rotations. ([**@IvanHunters**](https://github.com/IvanHunters) in #1657, #1666). +* **[dashboard] Add config hash annotations to restart pods on config changes**: Added config hash annotations to restart pods when configuration changes, ensuring pods are automatically restarted when their configuration is updated ([**@kvaps**](https://github.com/kvaps) in #1662, #1665). + +## Fixes + +* **[tenant][kubernetes] Introduce better cleanup logic**: Improved cleanup logic for tenant Kubernetes resources, ensuring proper resource cleanup when tenants are deleted or updated ([**@kvaps**](https://github.com/kvaps) in #1661). +* **[dashboard] Fix loading arrays in forms when editing existing objects**: Fixed issue where arrays in forms were not loading correctly when editing existing objects in the dashboard ([**@kvaps**](https://github.com/kvaps)). + +--- + +**Full Changelog**: [v0.38.0...v0.38.1](https://github.com/cozystack/cozystack/compare/v0.38.0...v0.38.1) + diff --git a/docs/changelogs/v0.38.2.md b/docs/changelogs/v0.38.2.md new file mode 100644 index 00000000..feb80d1f --- /dev/null +++ b/docs/changelogs/v0.38.2.md @@ -0,0 +1,13 @@ + + + +## Fixes + +* **[api] Revert dynamic list kinds representation fix (fixes namespace deletion regression)**: Reverted changes from #1630 that caused a regression affecting namespace deletion and upgrades from previous versions. The regression caused namespace deletion failures with errors like "content is not a list: []unstructured.Unstructured" during namespace finalization. This revert restores compatibility with namespace deletion controller and fixes upgrade issues from previous versions, particularly when running migration 20 ([**@kvaps**](https://github.com/kvaps) in #1677). + +--- + +**Full Changelog**: [v0.38.1...v0.38.2](https://github.com/cozystack/cozystack/compare/v0.38.1...v0.38.2) + diff --git a/docs/changelogs/v0.38.3.md b/docs/changelogs/v0.38.3.md new file mode 100644 index 00000000..5aa44d30 --- /dev/null +++ b/docs/changelogs/v0.38.3.md @@ -0,0 +1,14 @@ + + +## Improvements + +* **[core:installer] Address buildx warnings for installer image builds**: Aligns Dockerfile syntax casing to remove buildx warnings, keeping installer builds clean ([**@nbykov0**](https://github.com/nbykov0) in #1682). +* **[system:coredns] Align CoreDNS app labels with Talos defaults**: Matches CoreDNS labels to Talos conventions so services select pods consistently across platform and tenant clusters ([**@nbykov0**](https://github.com/nbykov0) in #1675). +* **[system:monitoring-agents] Rename CoreDNS metrics service to avoid conflicts**: Renames the metrics service so it no longer clashes with the CoreDNS service used for name resolution in tenant clusters ([**@nbykov0**](https://github.com/nbykov0) in #1676). + +--- + +**Full Changelog**: [v0.38.2...v0.38.3](https://github.com/cozystack/cozystack/compare/v0.38.2...v0.38.3) + diff --git a/docs/changelogs/v0.38.4.md b/docs/changelogs/v0.38.4.md new file mode 100644 index 00000000..94ea46fe --- /dev/null +++ b/docs/changelogs/v0.38.4.md @@ -0,0 +1,18 @@ + + +## Fixes + +* **[linstor] Update piraeus-operator v2.10.2 to handle fsck checks reliably**: Upgrades LINSTOR CSI to avoid failed mounts when fsck sees mounted volumes, improving volume publish reliability ([**@kvaps**](https://github.com/kvaps) in #1689, #1697). +* **[dashboard] Nest CustomFormsOverride properties under spec.properties**: Fixes schema generation so custom form properties are placed under `spec.properties`, preventing mis-rendered or missing form fields ([**@kvaps**](https://github.com/kvaps) in #1692, #1700). +* **[virtual-machine] Guard PVC resize to only expand storage**: Ensures resize jobs run only when storage size increases, avoiding unintended shrink attempts during VM updates ([**@kvaps**](https://github.com/kvaps) in #1688, #1701). + +## Documentation + +* **[website] Clarify GPU check command**: Makes the kubectl command for validating GPU binding more explicit, including namespace context ([**@nbykov0**](https://github.com/nbykov0) in cozystack/website#379). + +--- + +**Full Changelog**: [v0.38.3...v0.38.4](https://github.com/cozystack/cozystack/compare/v0.38.3...v0.38.4) + diff --git a/docs/changelogs/v0.38.5.md b/docs/changelogs/v0.38.5.md new file mode 100644 index 00000000..0cae8b2a --- /dev/null +++ b/docs/changelogs/v0.38.5.md @@ -0,0 +1,18 @@ + + +## Features and Improvements + +* **[virtual-machine,vm-instance] Add nodeAffinity for Windows VMs based on scheduling config**: Added nodeAffinity configuration to virtual-machine and vm-instance charts to support dedicated nodes for Windows VMs. When `dedicatedNodesForWindowsVMs` is enabled in the `cozystack-scheduling` ConfigMap, Windows VMs are scheduled on nodes with label `scheduling.cozystack.io/vm-windows=true`, while non-Windows VMs prefer nodes without this label ([**@kvaps**](https://github.com/kvaps) in #1693, #1744). +* **[cilium] Enable automatic pod rollout on configmap updates**: Cilium and Cilium operator pods now automatically restart when the cilium-config ConfigMap is updated, ensuring configuration changes are applied immediately without manual intervention ([**@kvaps**](https://github.com/kvaps) in #1728, #1745). +* **Update SeaweedFS v4.02**: Updated SeaweedFS to version 4.02 with improved S3 daemon performance and fixes. This update includes better S3 compatibility and performance improvements ([**@kvaps**](https://github.com/kvaps) in #1725, #1732). + +## Fixes + +* **[apps] Refactor apiserver to use typed objects and fix UnstructuredList GVK**: Refactored the apiserver REST handlers to use typed objects (`appsv1alpha1.Application`) instead of `unstructured.Unstructured`, eliminating the need for runtime conversions and simplifying the codebase. Additionally, fixed an issue where `UnstructuredList` objects were using the first registered kind from `typeToGVK` instead of the kind from the object's field when multiple kinds are registered with the same Go type. This fix includes the upstream fix from kubernetes/kubernetes#135537 ([**@kvaps**](https://github.com/kvaps) in #1679, #1709). + +--- + +**Full Changelog**: [v0.38.4...v0.38.5](https://github.com/cozystack/cozystack/compare/v0.38.4...v0.38.5) + diff --git a/docs/changelogs/v0.38.6.md b/docs/changelogs/v0.38.6.md new file mode 100644 index 00000000..9c39b66d --- /dev/null +++ b/docs/changelogs/v0.38.6.md @@ -0,0 +1,12 @@ + + +## Development, Testing, and CI/CD + +* **[kubernetes] Add lb tests for tenant k8s**: Added load balancer tests for tenant Kubernetes clusters, improving test coverage and ensuring proper load balancer functionality in tenant environments ([**@IvanHunters**](https://github.com/IvanHunters) in #1783, #1792). + +--- + +**Full Changelog**: [v0.38.5...v0.38.6](https://github.com/cozystack/cozystack/compare/v0.38.5...v0.38.6) + diff --git a/docs/changelogs/v0.38.7.md b/docs/changelogs/v0.38.7.md new file mode 100644 index 00000000..3edfd94c --- /dev/null +++ b/docs/changelogs/v0.38.7.md @@ -0,0 +1,13 @@ + + +## Fixes + +* **[kubevirt-operator] Fix typo in VMNotRunningFor10Minutes alert**: Fixed typo in VM alert name, ensuring proper alert triggering and monitoring for virtual machines that are not running for extended periods ([**@lexfrei**](https://github.com/lexfrei) in #1770). +* **[kubevirt-operator] Revert incorrect case change in VM alerts**: Reverted incorrect case change in VM alert names to maintain consistency with alert naming conventions ([**@lexfrei**](https://github.com/lexfrei) in #1804, #1805). + +--- + +**Full Changelog**: [v0.38.6...v0.38.7](https://github.com/cozystack/cozystack/compare/v0.38.6...v0.38.7) + diff --git a/docs/changelogs/v0.38.8.md b/docs/changelogs/v0.38.8.md new file mode 100644 index 00000000..0dbfe7b8 --- /dev/null +++ b/docs/changelogs/v0.38.8.md @@ -0,0 +1,12 @@ + + +## Improvements + +* **[multus] Remove memory limit**: Removed memory limit for Multus daemonset due to unpredictable memory consumption spikes during startup after node reboots (reported up to 3Gi). This temporary change prevents out-of-memory issues while the root cause is addressed in future releases ([**@nbykov0**](https://github.com/nbykov0) in #1834). + +--- + +**Full Changelog**: [v0.38.7...v0.38.8](https://github.com/cozystack/cozystack/compare/v0.38.7...v0.38.8) + diff --git a/docs/changelogs/v0.39.0.md b/docs/changelogs/v0.39.0.md new file mode 100644 index 00000000..ff498258 --- /dev/null +++ b/docs/changelogs/v0.39.0.md @@ -0,0 +1,95 @@ +# Cozystack v0.39 — "Enhanced Networking & Monitoring" + +This release introduces topology-aware routing for Cilium services, automatic pod rollouts on configuration changes, improved monitoring capabilities, and numerous bug fixes and improvements across the platform. + +## Highlights + +* **Topology-Aware Routing**: Enabled topology-aware routing for Cilium services, improving traffic distribution and reducing latency by routing traffic to endpoints in the same zone when possible ([**@nbykov0**](https://github.com/nbykov0) in #1734). +* **Automatic Pod Rollouts**: Cilium and Cilium operator pods now automatically restart when configuration changes, ensuring configuration updates are applied immediately ([**@kvaps**](https://github.com/kvaps) in #1728). +* **Windows VM Scheduling**: Added nodeAffinity configuration for Windows VMs based on scheduling config, enabling dedicated nodes for Windows workloads ([**@kvaps**](https://github.com/kvaps) in #1693). +* **SeaweedFS Updates**: Updated to SeaweedFS v4.02 with improved S3 daemon performance and fixes ([**@kvaps**](https://github.com/kvaps) in #1725). + +--- + +## Major Features and Improvements + +### Networking + +* **[system/cilium] Enable topology-aware routing for services**: Enabled topology-aware routing for services, improving traffic distribution and reducing latency by routing traffic to endpoints in the same zone when possible. This feature helps optimize network performance in multi-zone deployments ([**@nbykov0**](https://github.com/nbykov0) in #1734). +* **[cilium] Enable automatic pod rollout on configmap updates**: Cilium and Cilium operator pods now automatically restart when the cilium-config ConfigMap is updated, ensuring configuration changes are applied immediately without manual intervention ([**@kvaps**](https://github.com/kvaps) in #1728). + +### Virtual Machines + +* **[virtual-machine,vm-instance] Add nodeAffinity for Windows VMs based on scheduling config**: Added nodeAffinity configuration to virtual-machine and vm-instance charts to support dedicated nodes for Windows VMs. When `dedicatedNodesForWindowsVMs` is enabled in the `cozystack-scheduling` ConfigMap, Windows VMs are scheduled on nodes with label `scheduling.cozystack.io/vm-windows=true`, while non-Windows VMs prefer nodes without this label ([**@kvaps**](https://github.com/kvaps) in #1693). + +### Storage + +* **Update SeaweedFS v4.02**: Updated SeaweedFS to version 4.02 with improved performance for S3 daemon and fixes for known issues. This update includes better S3 compatibility and performance improvements ([**@kvaps**](https://github.com/kvaps) in #1725). + +### Tools + +* **[talm] feat(init)!: require --name flag for cluster name**: Breaking change: The `talm init` command now requires the `--name` flag to specify the cluster name. This ensures consistent cluster naming and prevents accidental initialization without a name ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm#86). +* **[talm] feat(template): preserve extra YAML documents in output**: Templates now preserve extra YAML documents in the output, allowing for more flexible template processing ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm#87). +* **[talm] feat: add directory expansion for -f flag**: Added directory expansion support for the `-f` flag, allowing users to specify directories instead of individual files ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@ca5713e). +* **[talm] Introduce automatic root detection**: Added automatic root detection logic to simplify talm usage and reduce manual configuration ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@d165162). +* **[talm] Introduce talm kubeconfig --login command**: Added new `talm kubeconfig --login` command for easier kubeconfig management ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@5f7e05b). +* **[talm] Introduce encryption**: Added encryption support to talm for secure configuration management ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#81). +* **[talm] Replace code-generation with wrapper on talosctl**: Refactored talm to use a wrapper on talosctl instead of code generation, simplifying the codebase and improving maintainability ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#80). +* **[talm] Use go embed instead of code generation**: Migrated from code generation to go embed for better build performance and simpler dependency management ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#79). +* **[boot-to-talos] Cozystack: Update Talos Linux v1.11.3**: Updated boot-to-talos to use Talos Linux v1.11.3 ([**@kvaps**](https://github.com/kvaps) in cozystack/boot-to-talos#7). + +## Improvements + +* **[seaweedfs] Extended CA certificate duration to reduce disruptive CA rotations**: Extended CA certificate duration to reduce disruptive CA rotations, improving long-term certificate management and reducing operational overhead ([**@IvanHunters**](https://github.com/IvanHunters) in #1657). +* **[dashboard] Add config hash annotations to restart pods on config changes**: Added config hash annotations to dashboard deployment templates to ensure pods are automatically restarted when their configuration changes, ensuring configuration updates are applied immediately ([**@kvaps**](https://github.com/kvaps) in #1662). +* **[tenant][kubernetes] Introduce better cleanup logic**: Improved cleanup logic for tenant Kubernetes resources, ensuring proper resource cleanup when tenants are deleted or updated. Added automated pre-delete cleanup job for tenant namespaces to remove tenant-related releases during uninstall ([**@kvaps**](https://github.com/kvaps) in #1661). +* **[system:coredns] update coredns app labels to match Talos coredns labels**: Updated coredns app labels to match Talos coredns labels, ensuring consistency across the platform ([**@nbykov0**](https://github.com/nbykov0) in #1675). +* **[system:monitoring-agents] rename coredns metrics service**: Renamed coredns metrics service to avoid interference with coredns service used for name resolution in tenant k8s clusters ([**@nbykov0**](https://github.com/nbykov0) in #1676). +* **[core:installer] Address buildx warnings**: Fixed Dockerfile syntax warnings from buildx, ensuring clean builds without warnings ([**@nbykov0**](https://github.com/nbykov0) in #1682). +* **[talm] Refactor root detection logic into single file**: Improved code organization by consolidating root detection logic into a single file ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@487b479). +* **[talm] Refactor init logic, better upgrade**: Improved initialization logic and upgrade process for better reliability ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@c512777). +* **[talm] Sugar for kubeconfig command**: Added convenience features to the kubeconfig command for improved usability ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@a4010b3). +* **[talm] wrap upgrade command**: Wrapped upgrade command for better integration and error handling ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@2e1afbf). +* **[talm] docs(readme): add Homebrew installation option**: Added Homebrew installation option to the README for easier installation on macOS ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm@12bd4f2). +* **[talm] cozystack: disable nodeCIDRs allocation**: Disabled nodeCIDRs allocation in talm for better network configuration control ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#82). +* **[talm] Update license to Apache2.0**: Updated license to Apache 2.0 for better compatibility and clarity ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@eda1032). + +## Fixes + +* **[apps] Refactor apiserver to use typed objects and fix UnstructuredList GVK**: Refactored the apiserver REST handlers to use typed objects (`appsv1alpha1.Application`) instead of `unstructured.Unstructured`, eliminating the need for runtime conversions and simplifying the codebase. Additionally, fixed an issue where `UnstructuredList` objects were using the first registered kind from `typeToGVK` instead of the kind from the object's field when multiple kinds are registered with the same Go type. This fix includes the upstream fix from kubernetes/kubernetes#135537 ([**@kvaps**](https://github.com/kvaps) in #1679). +* **[dashboard] Fix CustomFormsOverride schema to nest properties under spec.properties**: Fixed the logic for generating CustomFormsOverride schema to properly nest properties under `spec.properties` instead of directly under `properties`, ensuring correct form schema generation ([**@kvaps**](https://github.com/kvaps) in #1692). +* **[virtual-machine] Improve check for resizing job**: Improved storage resize logic to only expand persistent volume claims when storage is being increased, preventing unintended storage reduction operations. Added validation to accurately compare current and desired storage sizes before triggering resize operations ([**@kvaps**](https://github.com/kvaps) in #1688). +* **[linstor] Update piraeus-operator v2.10.2**: Updated LINSTOR CSI to fix issues with the new fsck behaviour, resolving mount failures when fsck attempts to run on mounted devices ([**@kvaps**](https://github.com/kvaps) in #1689). +* **[api] Revert dynamic list kinds representation fix (fixes namespace deletion regression)**: Reverted changes from #1630 that caused a regression affecting namespace deletion and upgrades from previous versions. The regression caused namespace deletion failures with errors like "content is not a list: []unstructured.Unstructured" during namespace finalization. This revert restores compatibility with namespace deletion controller and fixes upgrade issues from previous versions ([**@kvaps**](https://github.com/kvaps) in #1677). +* **[talm] fix: normalize template paths for Windows compatibility**: Fixed template path handling to ensure Windows compatibility by normalizing paths ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm#88). + +## Dependencies + +* **Update SeaweedFS v4.02**: Updated SeaweedFS to version 4.02 ([**@kvaps**](https://github.com/kvaps) in #1725). +* **[linstor] Update piraeus-operator v2.10.2**: Updated piraeus-operator to version 2.10.2 ([**@kvaps**](https://github.com/kvaps) in #1689). +* **[talm] Cozystack: Update Talos Linux v1.11.3**: Updated talm to use Talos Linux v1.11.3 ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#83). + +## Documentation + +* **[website] Add article: Talm v0.17: Built-in Age Encryption for Secrets Management**: Added comprehensive blog post announcing Talm v0.17 and its built-in age-based encryption for secrets. Covers initial setup and key generation, encryption/decryption workflows, idempotent encryption behavior, automatic .gitignore handling, file permission safeguards, security best practices, and guidance for GitOps and CI/CD integration ([**@kvaps**](https://github.com/kvaps) in [cozystack/website#384](https://github.com/cozystack/website/pull/384)). +* **[website] docs(talm): update talm init syntax for mandatory --preset and --name flags**: Updated documentation to reflect breaking changes in talm, adding mandatory `--preset` and `--name` flags to the talm init command ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#386). + +--- + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@IvanHunters**](https://github.com/IvanHunters) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@nbykov0**](https://github.com/nbykov0) + +--- + +**Full Changelog**: [v0.38.0...v0.39.0](https://github.com/cozystack/cozystack/compare/v0.38.0...v0.39.0) + + + diff --git a/docs/changelogs/v0.39.1.md b/docs/changelogs/v0.39.1.md new file mode 100644 index 00000000..569271ee --- /dev/null +++ b/docs/changelogs/v0.39.1.md @@ -0,0 +1,12 @@ + + +## Features and Improvements + +* **[monitoring] Add SLACK_SEVERITY_FILTER field and VMAgent for tenant monitoring**: Introduced the SLACK_SEVERITY_FILTER environment variable in the Alerta deployment to enable filtering of alert severities for Slack notifications based on the disabledSeverity configuration. Additionally, added a VMAgent resource template for scraping metrics within tenant namespaces, improving monitoring granularity and control. This enhancement allows administrators to configure which alert severities are sent to Slack and enables tenant-specific metrics collection for better observability ([**@IvanHunters**](https://github.com/IvanHunters) in #1712). + +--- + +**Full Changelog**: [v0.39.0...v0.39.1](https://github.com/cozystack/cozystack/compare/v0.39.0...v0.39.1) + diff --git a/docs/changelogs/v0.39.2.md b/docs/changelogs/v0.39.2.md new file mode 100644 index 00000000..dacb094f --- /dev/null +++ b/docs/changelogs/v0.39.2.md @@ -0,0 +1,19 @@ + + +## Features and Improvements + +* **[vm] Always expose VMs with a service**: Virtual machines are now always exposed with at least a ClusterIP service, ensuring they have in-cluster DNS names and can be accessed from other pods even without public IP addresses ([**@lllamnyp**](https://github.com/lllamnyp) in #1738, #1751). +* **[tenant] Allow egress to parent ingress pods**: Updated tenant network policies to allow egress traffic to parent cluster ingress pods, enabling proper communication patterns between tenant namespaces and parent cluster ingress controllers ([**@lexfrei**](https://github.com/lexfrei) in #1765, #1776). +* **[system] Add resource requests and limits to etcd-defrag**: Added resource requests and limits to etcd-defrag job to ensure proper resource allocation and prevent resource contention during etcd maintenance operations ([**@matthieu-robin**](https://github.com/matthieu-robin) in #1785, #1786). +* **[tenant] Run cleanup job from system namespace**: Moved tenant cleanup job to run from system namespace, improving security and resource isolation for tenant cleanup operations ([**@lllamnyp**](https://github.com/lllamnyp) in #1774, #1777). + +## Fixes + +* **[kubevirt-operator] Fix typo in VMNotRunningFor10Minutes alert**: Fixed typo in VM alert name, ensuring proper alert triggering and monitoring for virtual machines that are not running for extended periods ([**@lexfrei**](https://github.com/lexfrei) in #1770, #1775). + +--- + +**Full Changelog**: [v0.39.1...v0.39.2](https://github.com/cozystack/cozystack/compare/v0.39.1...v0.39.2) + diff --git a/docs/changelogs/v0.39.3.md b/docs/changelogs/v0.39.3.md new file mode 100644 index 00000000..f493795b --- /dev/null +++ b/docs/changelogs/v0.39.3.md @@ -0,0 +1,36 @@ + + +## Features and Improvements + +* **[seaweedfs] Traffic locality**: Upgraded SeaweedFS to v4.05 with traffic locality capabilities, new admin component with web-based UI, worker component for distributed operations, and enhanced S3 monitoring with Grafana dashboards. Improves S3 service performance by routing requests to nearest available volume servers ([**@nbykov0**](https://github.com/nbykov0) in #1748, #1830). +* **[kube-ovn] Update to v1.14.25**: Updated Kube-OVN to version 1.14.25 with improved stability and new features ([**@kvaps**](https://github.com/kvaps) in #1819, #1837). +* **[linstor] Build linstor-server with custom patches**: Added custom patches to linstor-server build process, enabling platform-specific optimizations and fixes ([**@kvaps**](https://github.com/kvaps) in #1726, #1818). +* **[api, lineage] Tolerate all taints**: Updated API and lineage webhook to tolerate all taints, ensuring controllers can run on any node regardless of taint configuration ([**@nbykov0**](https://github.com/nbykov0) in #1781, #1827). +* **[ingress] Add topology anti-affinities**: Added topology anti-affinity rules to ingress controller deployment for better pod distribution across nodes ([**@kvaps**](https://github.com/kvaps) in commit 25f31022). + +## Fixes + +* **[linstor] fix: prevent DRBD device race condition in updateDiscGran**: Fixed race condition in DRBD device management during granularity updates, preventing potential data corruption or device conflicts ([**@kvaps**](https://github.com/kvaps) in #1829, #1836). +* **fix(linstor): prevent orphaned DRBD devices during toggle-disk retry**: Fixed issue where retry logic during disk toggle operations could leave orphaned DRBD devices, now properly cleans up devices during retry attempts ([**@kvaps**](https://github.com/kvaps) in #1823, #1825). +* **[kubernetes] Fix endpoints for cilium-gateway**: Fixed endpoint configuration for cilium-gateway, ensuring proper service discovery and connectivity ([**@kvaps**](https://github.com/kvaps) in #1729, #1808). +* **[kubevirt-operator] Revert incorrect case change in VM alerts**: Reverted incorrect case change in VM alert names to maintain consistency with alert naming conventions ([**@lexfrei**](https://github.com/lexfrei) in #1804, #1806). + +## System Configuration + +* **[kubeovn] Package from external repo**: Extracted Kube-OVN packaging from main repository to external repository, improving modularity ([**@lllamnyp**](https://github.com/lllamnyp) in #1535). + +## Development, Testing, and CI/CD + +* **[testing] Add aliases and autocomplete**: Added shell aliases and autocomplete support for testing commands, improving developer experience ([**@lllamnyp**](https://github.com/lllamnyp) in #1803, #1809). + +## Dependencies + +* **[seaweedfs] Traffic locality**: Upgraded SeaweedFS to v4.05 with traffic locality capabilities ([**@nbykov0**](https://github.com/nbykov0) in #1748, #1830). +* **[kube-ovn] Update to v1.14.25**: Updated Kube-OVN to version 1.14.25 ([**@kvaps**](https://github.com/kvaps) in #1819, #1837). + +--- + +**Full Changelog**: [v0.39.2...v0.39.3](https://github.com/cozystack/cozystack/compare/v0.39.2...v0.39.3) + diff --git a/docs/changelogs/v0.39.4.md b/docs/changelogs/v0.39.4.md new file mode 100644 index 00000000..36d9f016 --- /dev/null +++ b/docs/changelogs/v0.39.4.md @@ -0,0 +1,12 @@ + + +## Features and Improvements + +* **[paas-full] Add multus dependencies similar to other CNIs**: Added Multus as a dependency in the paas-full package, consistent with how other CNIs are included. This ensures proper dependency management and simplifies the installation process for environments using Multus networking ([**@nbykov0**](https://github.com/nbykov0) in #1835). + +--- + +**Full Changelog**: [v0.39.3...v0.39.4](https://github.com/cozystack/cozystack/compare/v0.39.3...v0.39.4) + diff --git a/docs/changelogs/v0.39.5.md b/docs/changelogs/v0.39.5.md new file mode 100644 index 00000000..de352b1c --- /dev/null +++ b/docs/changelogs/v0.39.5.md @@ -0,0 +1,11 @@ + + +## Fixes + +* **[linstor] Update piraeus-server patches with critical fixes**: Backported critical patches to piraeus-server that address storage stability issues and improve DRBD resource handling. These patches fix edge cases in device management and ensure more reliable storage operations ([**@kvaps**](https://github.com/kvaps) in #1850, #1853). + +--- + +**Full Changelog**: [v0.39.4...v0.39.5](https://github.com/cozystack/cozystack/compare/v0.39.4...v0.39.5) diff --git a/docs/changelogs/v0.40.0.md b/docs/changelogs/v0.40.0.md new file mode 100644 index 00000000..caaa08f6 --- /dev/null +++ b/docs/changelogs/v0.40.0.md @@ -0,0 +1,206 @@ +# Cozystack v0.40 — "Enhanced Storage & Platform Architecture" + +This release introduces LINSTOR scheduler for optimal pod placement, SeaweedFS traffic locality, a new valuesFrom-based configuration mechanism, auto-diskful for LINSTOR, automated version management systems, and numerous improvements across the platform. + +## Feature Highlights + +### LINSTOR Scheduler for Optimal Pod Placement + +Cozystack now includes a custom Kubernetes scheduler extender that works alongside the default kube-scheduler to optimize pod placement on nodes with LINSTOR storage. When a pod requests LINSTOR-backed storage, the scheduler communicates with the LINSTOR controller to find nodes that have local replicas of the requested volumes, prioritizing placement on nodes with existing data to minimize network traffic and improve I/O performance. + +The scheduler includes an admission webhook that automatically routes pods using LINSTOR CSI volumes to the custom scheduler, ensuring seamless integration without manual configuration. This feature significantly improves performance for workloads using LINSTOR storage by reducing network latency and improving data locality. + +Learn more about LINSTOR in the [documentation](https://cozystack.io/docs/operations/storage/linstor/). + +### SeaweedFS Traffic Locality + +SeaweedFS has been upgraded to version 4.05 with new traffic locality capabilities that optimize S3 service traffic distribution. The update includes a new admin component with a web-based UI and authentication support, as well as a worker component for distributed operations. These enhancements improve S3 service performance and provide better visibility through enhanced Grafana dashboard panels for buckets, API calls, costs, and performance metrics. + +The traffic locality feature ensures that S3 requests are routed to the nearest available volume servers, reducing latency and improving overall performance for distributed storage operations. TLS certificate support for admin and worker components adds an extra layer of security for management operations. + +### ValuesFrom Configuration Mechanism + +Cozystack now uses FluxCD's valuesFrom mechanism to replace Helm lookup functions for configuration propagation. This architectural improvement provides cleaner config propagation and eliminates the need for force reconcile controllers. Configuration from ConfigMaps (cozystack, cozystack-branding, cozystack-scheduling) and namespace service references (etcd, host, ingress, monitoring, seaweedfs) is now centrally managed through a `cozystack-values` Secret in each namespace. + +This change simplifies Helm chart templates by replacing complex lookup functions with direct value references, improves configuration consistency, and reduces the reconciliation overhead. All HelmReleases now automatically receive cluster and namespace configuration through the valuesFrom mechanism, making configuration management more transparent and maintainable. + +### Auto-diskful for LINSTOR + +The LINSTOR integration now includes automatic diskful functionality that converts diskless nodes to diskful when they hold DRBD resources in Primary state for an extended period (30 minutes). This feature addresses scenarios where workloads are scheduled on nodes without local storage replicas by automatically creating local disk replicas when needed, improving I/O performance for long-running workloads. + +When enabled with cleanup options, the system can automatically remove disk replicas that are no longer needed, preventing storage waste from temporary replicas. This intelligent storage management reduces network traffic for frequently accessed data while maintaining efficient storage utilization. + +### Automated Version Management Systems + +Cozystack now includes automated version management systems for PostgreSQL, Kubernetes, MariaDB, and Redis applications. These systems automatically track upstream versions and provide mechanisms for automated version updates, ensuring that platform users always have access to the latest stable versions while maintaining compatibility with existing deployments. + +The version management systems integrate with the Cozystack API and dashboard, providing administrators with visibility into available versions and update paths. This infrastructure sets the foundation for future automated upgrade workflows and version compatibility management. + +--- + +## Major Features and Improvements + +### Storage + +* **[linstor] Add linstor-scheduler package**: Added LINSTOR scheduler extender for optimal pod placement on nodes with LINSTOR storage. Includes admission webhook that automatically routes pods using LINSTOR CSI volumes to the custom scheduler, ensuring pods are placed on nodes with local replicas to minimize network traffic and improve I/O performance ([**@kvaps**](https://github.com/kvaps) in #1824). +* **[linstor] Enable auto-diskful for diskless nodes**: Enabled DRBD auto-diskful functionality to automatically convert diskless nodes to diskful when they hold volumes in Primary state for more than 30 minutes. Improves I/O performance for long-running workloads by creating local replicas and includes automatic cleanup options to prevent storage waste ([**@kvaps**](https://github.com/kvaps) in #1826). +* **[linstor] Build linstor-server with custom patches**: Added custom patches to linstor-server build process, enabling platform-specific optimizations and fixes ([**@kvaps**](https://github.com/kvaps) in #1726). +* **[seaweedfs] Traffic locality**: Upgraded SeaweedFS to v4.05 with traffic locality capabilities, new admin component with web-based UI, worker component for distributed operations, and enhanced S3 monitoring with Grafana dashboards. Improves S3 service performance by routing requests to nearest available volume servers ([**@nbykov0**](https://github.com/nbykov0) in #1748). +* **[linstor] fix: prevent DRBD device race condition in updateDiscGran**: Fixed race condition in DRBD device management during granularity updates, preventing potential data corruption or device conflicts ([**@kvaps**](https://github.com/kvaps) in #1829). +* **fix(linstor): prevent orphaned DRBD devices during toggle-disk retry**: Fixed issue where retry logic during disk toggle operations could leave orphaned DRBD devices, now properly cleans up devices during retry attempts ([**@kvaps**](https://github.com/kvaps) in #1823). + +### Platform Architecture + +* **[platform] Replace Helm lookup with valuesFrom mechanism**: Replaced Helm lookup functions with FluxCD valuesFrom mechanism for configuration propagation. Configuration from ConfigMaps and namespace references is now managed through `cozystack-values` Secret, simplifying templates and eliminating force reconcile controllers ([**@kvaps**](https://github.com/kvaps) in #1787). +* **[platform] refactor: split cozystack-resource-definitions into separate packages**: Refactored cozystack-resource-definitions into separate packages for better organization and maintainability, improving code structure and reducing coupling between components ([**@kvaps**](https://github.com/kvaps) in #1778). +* **[platform] Separate assets server into dedicated deployment**: Separated assets server from main platform deployment, improving scalability and allowing independent scaling of asset delivery infrastructure ([**@kvaps**](https://github.com/kvaps) in #1705). +* **[core] Extract Talos package from installer**: Extracted Talos package configuration from installer into a separate package, improving modularity and enabling independent updates ([**@kvaps**](https://github.com/kvaps) in #1724). +* **[registry] Add application labels and update filtering mechanism**: Added application labels to registry resources and improved filtering mechanism for better resource discovery and organization ([**@kvaps**](https://github.com/kvaps) in #1707). +* **fix(registry): implement field selector filtering for label-based resources**: Implemented field selector filtering for label-based resources in the registry, improving query performance and resource lookup efficiency ([**@kvaps**](https://github.com/kvaps) in #1845). +* **[platform] Add alphabetical sorting to registry resource lists**: Added alphabetical sorting to registry resource lists in the API and dashboard, improving user experience when browsing available applications ([**@lexfrei**](https://github.com/lexfrei) in #1764). + +### Version Management + +* **[postgres] Add version management system with automated version updates**: Introduced version management system for PostgreSQL with automated version tracking and update mechanisms ([**@kvaps**](https://github.com/kvaps) in #1671). +* **[kubernetes] Add version management system with automated version updates**: Added version management system for Kubernetes tenant clusters with automated version tracking and update capabilities ([**@kvaps**](https://github.com/kvaps) in #1672). +* **[mariadb] Add version management system with automated version updates**: Implemented version management system for MariaDB with automated version tracking and update mechanisms ([**@kvaps**](https://github.com/kvaps) in #1680). +* **[redis] Add version management system with automated version updates**: Added version management system for Redis with automated version tracking and update capabilities ([**@kvaps**](https://github.com/kvaps) in #1681). + +### Networking + +* **[kube-ovn] Update to v1.14.25**: Updated Kube-OVN to version 1.14.25 with improved stability and new features ([**@kvaps**](https://github.com/kvaps) in #1819). +* **[kubeovn] Package from external repo**: Extracted Kube-OVN packaging from main repository to external repository, improving modularity ([**@lllamnyp**](https://github.com/lllamnyp) in #1535). +* **[cilium] Update Cilium to v1.18.5**: Updated Cilium to version 1.18.5 with latest features and bug fixes ([**@lexfrei**](https://github.com/lexfrei) in #1769). +* **[system/cilium] Enable topology-aware routing for services**: Enabled topology-aware routing for Cilium services, improving traffic distribution and reducing latency by routing traffic to endpoints in the same zone when possible ([**@nbykov0**](https://github.com/nbykov0) in #1734). +* **[cilium] Enable automatic pod rollout on configmap updates**: Cilium and Cilium operator pods now automatically restart when the cilium-config ConfigMap is updated, ensuring configuration changes are applied immediately ([**@kvaps**](https://github.com/kvaps) in #1728). +* **[kubernetes] Fix endpoints for cilium-gateway**: Fixed endpoint configuration for cilium-gateway, ensuring proper service discovery and connectivity ([**@kvaps**](https://github.com/kvaps) in #1729). +* **[multus] Increase memory limit**: Increased memory limits for Multus components to handle larger network configurations and reduce out-of-memory issues ([**@nbykov0**](https://github.com/nbykov0) in #1773). +* **[main][paas-full] Add multus dependencies similar to other CNIs**: Added Multus as a dependency in the paas-full package, consistent with how other CNIs are included ([**@nbykov0**](https://github.com/nbykov0) in #1842). + +### Virtual Machines + +* **[vm] Always expose VMs with a service**: Virtual machines are now always exposed with at least a ClusterIP service, ensuring they have in-cluster DNS names and can be accessed from other pods even without public IP addresses ([**@lllamnyp**](https://github.com/lllamnyp) in #1738). +* **[virtual-machine] Improve check for resizing job**: Improved storage resize logic to only expand persistent volume claims when storage is being increased, preventing unintended storage reduction operations ([**@kvaps**](https://github.com/kvaps) in #1688). +* **[virtual-machine,vm-instance] Add nodeAffinity for Windows VMs based on scheduling config**: Added nodeAffinity configuration to virtual-machine and vm-instance charts to support dedicated nodes for Windows VMs ([**@kvaps**](https://github.com/kvaps) in #1693). + +### Monitoring + +* **[monitoring] Add SLACK_SEVERITY_FILTER field and VMAgent for tenant monitoring**: Introduced SLACK_SEVERITY_FILTER environment variable in Alerta deployment to enable filtering of alert severities for Slack notifications. Added VMAgent resource template for scraping metrics within tenant namespaces, improving monitoring granularity ([**@IvanHunters**](https://github.com/IvanHunters) in #1712). +* **[monitoring] Improve tenant metrics collection**: Improved tenant metrics collection mechanisms for better observability and monitoring coverage ([**@IvanHunters**](https://github.com/IvanHunters) in #1684). + +### System Configuration + +* **[api, lineage] Tolerate all taints**: Updated API and lineage webhook to tolerate all taints, ensuring controllers can run on any node regardless of taint configuration ([**@nbykov0**](https://github.com/nbykov0) in #1781). +* **[system] Add resource requests and limits to etcd-defrag**: Added resource requests and limits to etcd-defrag job to ensure proper resource allocation and prevent resource contention ([**@matthieu-robin**](https://github.com/matthieu-robin) in #1785). +* **[system:coredns] update coredns app labels to match Talos coredns labels**: Updated coredns app labels to match Talos coredns labels, ensuring consistency across the platform ([**@nbykov0**](https://github.com/nbykov0) in #1675). +* **[system:monitoring-agents] rename coredns metrics service**: Renamed coredns metrics service to avoid interference with coredns service used for name resolution in tenant k8s clusters ([**@nbykov0**](https://github.com/nbykov0) in #1676). + +### Tenants and Namespaces + +* **[tenant] Allow egress to parent ingress pods**: Updated tenant network policies to allow egress traffic to parent cluster ingress pods, enabling proper communication patterns ([**@lexfrei**](https://github.com/lexfrei) in #1765). +* **[tenant] Run cleanup job from system namespace**: Moved tenant cleanup job to run from system namespace, improving security and resource isolation ([**@lllamnyp**](https://github.com/lllamnyp) in #1774). + +### FluxCD + +* **[fluxcd] Add flux-aio module and migration**: Added FluxCD all-in-one module with migration support, simplifying FluxCD installation and management ([**@kvaps**](https://github.com/kvaps) in #1698). +* **[fluxcd] Enable source-watcher**: Enabled source-watcher in FluxCD configuration for improved GitOps synchronization and faster update detection ([**@kvaps**](https://github.com/kvaps) in #1706). + +### Applications + +* **[dashboard] Fix CustomFormsOverride schema to nest properties under spec.properties**: Fixed CustomFormsOverride schema generation to properly nest properties under `spec.properties` instead of directly under `properties`, ensuring correct form schema generation ([**@kvaps**](https://github.com/kvaps) in #1692). +* **[apps] Refactor apiserver to use typed objects and fix UnstructuredList GVK**: Refactored apiserver REST handlers to use typed objects instead of unstructured.Unstructured, eliminating runtime conversions. Fixed UnstructuredList GVK issue where objects were using the first registered kind instead of the correct kind ([**@kvaps**](https://github.com/kvaps) in #1679). +* **[keycloak] Make kubernetes client public**: Made Kubernetes client public in Keycloak configuration, enabling broader access patterns for Kubernetes integrations ([**@lllamnyp**](https://github.com/lllamnyp) in #1802). + +## Improvements + +* **[granular kubernetes application extensions dependencies]**: Improved dependency management for Kubernetes application extensions with more granular control over dependencies ([**@nbykov0**](https://github.com/nbykov0) in #1683). +* **[core:installer] Address buildx warnings**: Fixed Dockerfile syntax warnings from buildx, ensuring clean builds without warnings ([**@nbykov0**](https://github.com/nbykov0) in #1682). +* **[linstor] Update piraeus-operator v2.10.2**: Updated LINSTOR CSI to version 2.10.2 with improved stability and bug fixes ([**@kvaps**](https://github.com/kvaps) in #1689). +* **Update SeaweedFS v4.02**: Updated SeaweedFS to version 4.02 with improved S3 daemon performance and fixes ([**@kvaps**](https://github.com/kvaps) in #1725). +* **[installer,dx] Rename cozypkg to cozyhr**: Renamed cozypkg tool to cozyhr for better branding and consistency ([**@kvaps**](https://github.com/kvaps) in #1763). + +## Fixes + +* **fix(platform): fix migrations for v0.40 release**: Fixed platform migrations for v0.40 release, ensuring smooth upgrades from previous versions ([**@kvaps**](https://github.com/kvaps) in #1846). +* **[platform] fix migration for removing fluxcd-operator**: Fixed migration logic for removing fluxcd-operator, ensuring clean removal without leaving orphaned resources ([**@kvaps**](https://github.com/kvaps) in commit 4a83d2c7). +* **[kubevirt-operator] Fix typo in VMNotRunningFor10Minutes alert**: Fixed typo in VM alert name, ensuring proper alert triggering and monitoring ([**@kvaps**](https://github.com/kvaps) in #1770). +* **[kubevirt-operator] Revert incorrect case change in VM alerts**: Reverted incorrect case change in VM alert names to maintain consistency ([**@lexfrei**](https://github.com/lexfrei) in #1804). +* **[cozystack-controller] Fix: move crds to definitions**: Fixed CRD placement by moving them to definitions directory, ensuring proper resource organization ([**@kvaps**](https://github.com/kvaps) in #1759). + +## Dependencies + +* **Update SeaweedFS v4.02**: Updated SeaweedFS to version 4.02 ([**@kvaps**](https://github.com/kvaps) in #1725). +* **[seaweedfs] Traffic locality**: Upgraded SeaweedFS to v4.05 with traffic locality capabilities ([**@nbykov0**](https://github.com/nbykov0) in #1748). +* **[linstor] Update piraeus-operator v2.10.2**: Updated piraeus-operator to version 2.10.2 ([**@kvaps**](https://github.com/kvaps) in #1689). +* **[kube-ovn] Update to v1.14.25**: Updated Kube-OVN to version 1.14.25 ([**@kvaps**](https://github.com/kvaps) in #1819). +* **[cilium] Update Cilium to v1.18.5**: Updated Cilium to version 1.18.5 ([**@lexfrei**](https://github.com/lexfrei) in #1769). +* **Update go modules**: Updated Go modules to latest versions ([**@kvaps**](https://github.com/kvaps) in #1736). + +## Development, Testing, and CI/CD + +* **[ci] Fix auto-release workflow**: Fixed auto-release workflow to ensure correct release publishing and tagging ([**@kvaps**](https://github.com/kvaps) in commit 526af294). +* **fix(ci): ensure correct latest release after backport publishing**: Fixed CI workflow to correctly identify and tag the latest release after backport publishing ([**@kvaps**](https://github.com/kvaps) in #1800). +* **[workflows] Add auto patch release workflow**: Added automated patch release workflow for streamlined release management ([**@kvaps**](https://github.com/kvaps) in #1754). +* **[workflow] Add GitHub Action to update release notes from changelogs**: Added GitHub Action to automatically update release notes from changelog files ([**@kvaps**](https://github.com/kvaps) in #1752). +* **[ci] Improve backport workflow with merge_commits skip and conflict resolution**: Improved backport workflow with better merge commit handling and conflict resolution ([**@kvaps**](https://github.com/kvaps) in #1694). +* **[testing] Add aliases and autocomplete**: Added shell aliases and autocomplete support for testing commands, improving developer experience ([**@lllamnyp**](https://github.com/lllamnyp) in #1803). +* **[kubernetes] Add lb tests for tenant k8s**: Added load balancer tests for tenant Kubernetes clusters, improving test coverage ([**@IvanHunters**](https://github.com/IvanHunters) in #1783). +* **[agents] Add instructions for working with unresolved code review comments**: Added documentation and instructions for working with unresolved code review comments in agent workflows ([**@kvaps**](https://github.com/kvaps) in #1710). +* **feat(ci): add /retest command to rerun tests from Prepare environment**: Added `/retest` command to rerun tests from Prepare environment workflow ([**@kvaps**](https://github.com/kvaps) in commit 30c1041e). +* **fix(ci): remove GITHUB_TOKEN extraheader to trigger workflows**: Removed GITHUB_TOKEN extraheader to properly trigger workflows ([**@kvaps**](https://github.com/kvaps) in commit 68a639b3). +* **Fix: Add missing components to `distro-full` bundle**: Fixed missing components in distro-full bundle, ensuring all required components are included ([**@LoneExile**](https://github.com/LoneExile) in #1620). +* **Update Flux Operator (v0.33.0)**: Updated Flux Operator to version 0.33.0 ([**@kingdonb**](https://github.com/kingdonb) in #1649). +* **Add changelogs for v0.38.3 and v.0.38.4**: Added missing changelogs for v0.38.3 and v0.38.4 releases ([**@androndo**](https://github.com/androndo) in #1743). +* **Add changelogs to v.0.39.1**: Added changelog for v0.39.1 release ([**@androndo**](https://github.com/androndo) in #1750). +* **Add Cloupard to ADOPTERS.md**: Added Cloupard to the adopters list ([**@SerjioTT**](https://github.com/SerjioTT) in #1733). + +## Documentation + +* **[website] docs: expand monitoring and alerting documentation**: Expanded monitoring and alerting documentation with comprehensive guides, examples, and troubleshooting information ([**@IvanHunters**](https://github.com/IvanHunters) in [cozystack/website#388](https://github.com/cozystack/website/pull/388)). +* **[website] fix auto-generation of documentation**: Fixed automatic documentation generation process, ensuring all documentation is properly generated and formatted ([**@IvanHunters**](https://github.com/IvanHunters) in [cozystack/website#391](https://github.com/cozystack/website/pull/391)). +* **[website] secure boot**: Added documentation for Secure Boot support in Talos Linux ([**@kvaps**](https://github.com/kvaps) in [cozystack/website#387](https://github.com/cozystack/website/pull/387)). + +## Tools + +* **[talm] feat(helpers): add bond interface discovery helpers**: Added bond interface discovery helpers to talm for easier network configuration ([**@kvaps**](https://github.com/kvaps) in [cozystack/talm#94](https://github.com/cozystack/talm/pull/94)). +* **[talm] feat(talosconfig): add certificate regeneration from secrets.yaml**: Added certificate regeneration functionality to talm talosconfig command, allowing certificates to be regenerated from secrets.yaml ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@1319dde). +* **[talm] fix(init): make name optional for -u flag**: Made name parameter optional for init command with -u flag, improving flexibility ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@da29320). +* **[talm] fix(wrapper): copy NoOptDefVal when remapping -f to -F flag**: Fixed wrapper to properly copy NoOptDefVal when remapping flags, ensuring correct default value handling ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@f6a6f1d). +* **[talm] fix(root): detect project root with secrets.encrypted.yaml**: Fixed root detection to properly identify project root when secrets.encrypted.yaml is present ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@cf56780). +* **[talm] Fix interfaces helper for Talos v1.12**: Fixed interfaces helper to work correctly with Talos v1.12 ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@34984ae). +* **[talm] Fix typo on README.md**: Fixed typo in README documentation ([**@diegolakatos**](https://github.com/diegolakatos) in [cozystack/talm#92](https://github.com/cozystack/talm/pull/92)). +* **[talm] fix(template): return error for invalid YAML in template output**: Fixed template command to return proper error for invalid YAML output ([**@kvaps**](https://github.com/kvaps) in [cozystack/talm#93](https://github.com/cozystack/talm/pull/93)). +* **[talm] feat(cozystack): enable allocateNodeCIDRs by default**: Enabled allocateNodeCIDRs by default in talm cozystack preset ([**@lexfrei**](https://github.com/lexfrei) in [cozystack/talm#91](https://github.com/cozystack/talm/pull/91)). +* **[boot-to-talos] feat(network): add VLAN interface support via netlink**: Added VLAN interface support via netlink in boot-to-talos for advanced network configuration ([**@kvaps**](https://github.com/kvaps) in cozystack/boot-to-talos@02874d7). +* **[boot-to-talos] feat(network): add bond interface support via netlink**: Added bond interface support via netlink in boot-to-talos for network bonding configurations ([**@kvaps**](https://github.com/kvaps) in cozystack/boot-to-talos@067822d). +* **[boot-to-talos] Draft EFI Support**: Added draft EFI support in boot-to-talos for UEFI boot scenarios ([**@kvaps**](https://github.com/kvaps) in cozystack/boot-to-talos@e194bc8). +* **[boot-to-talos] Change default install image size from 2GB to 3GB**: Changed default install image size from 2GB to 3GB to accommodate larger installations ([**@kvaps**](https://github.com/kvaps) in cozystack/boot-to-talos@3bfb035). +* **[cozyhr] feat(values): add valuesFrom support for HelmRelease**: Added valuesFrom support for HelmRelease in cozyhr tool, enabling better configuration management ([**@kvaps**](https://github.com/kvaps) in cozystack/cozyhr@7dff0c8). +* **[cozyhr] Rename cozypkg to cozyhr**: Renamed cozypkg tool to cozyhr for better branding ([**@kvaps**](https://github.com/kvaps) in cozystack/cozyhr@1029461). + +--- + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@IvanHunters**](https://github.com/IvanHunters) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@lllamnyp**](https://github.com/lllamnyp) +* [**@nbykov0**](https://github.com/nbykov0) +* [**@LoneExile**](https://github.com/LoneExile) +* [**@kingdonb**](https://github.com/kingdonb) +* [**@androndo**](https://github.com/androndo) +* [**@SerjioTT**](https://github.com/SerjioTT) +* [**@matthieu-robin**](https://github.com/matthieu-robin) +* [**@diegolakatos**](https://github.com/diegolakatos) + +--- + +**Full Changelog**: [v0.39.0...v0.40.0](https://github.com/cozystack/cozystack/compare/v0.39.0...v0.40.0) + + + diff --git a/docs/changelogs/v0.40.1.md b/docs/changelogs/v0.40.1.md new file mode 100644 index 00000000..ee718b47 --- /dev/null +++ b/docs/changelogs/v0.40.1.md @@ -0,0 +1,11 @@ + + +## Fixes + +* **[linstor] Update piraeus-server patches with critical fixes**: Backported critical patches to piraeus-server that address storage stability issues and improve DRBD resource handling. These patches fix edge cases in device management and ensure more reliable storage operations ([**@kvaps**](https://github.com/kvaps) in #1850, #1852). + +--- + +**Full Changelog**: [v0.40.0...v0.40.1](https://github.com/cozystack/cozystack/compare/v0.40.0...v0.40.1) diff --git a/docs/changelogs/v0.40.2.md b/docs/changelogs/v0.40.2.md new file mode 100644 index 00000000..5c686b92 --- /dev/null +++ b/docs/changelogs/v0.40.2.md @@ -0,0 +1,15 @@ + + +## Improvements + +* **[linstor] Refactor node-level RWX validation**: Refactored the node-level ReadWriteMany (RWX) validation logic in LINSTOR CSI. The validation has been moved to the CSI driver level with a custom linstor-csi image build, providing more reliable RWX volume handling and clearer error messages when RWX requirements cannot be satisfied ([**@kvaps**](https://github.com/kvaps) in #1856, #1857). + +## Fixes + +* **[linstor] Remove node-level RWX validation**: Removed the problematic node-level RWX validation that was causing issues with volume provisioning. The validation logic has been refactored and moved to a more appropriate location in the LINSTOR CSI driver ([**@kvaps**](https://github.com/kvaps) in #1851). + +--- + +**Full Changelog**: [v0.40.1...v0.40.2](https://github.com/cozystack/cozystack/compare/v0.40.1...v0.40.2) diff --git a/docs/changelogs/v0.40.3.md b/docs/changelogs/v0.40.3.md new file mode 100644 index 00000000..a62a70bc --- /dev/null +++ b/docs/changelogs/v0.40.3.md @@ -0,0 +1,15 @@ + + +## Fixes + +* **[apiserver] Fix Watch resourceVersion and bookmark handling**: Fixed issues with Watch API handling of resourceVersion and bookmarks, ensuring proper event streaming and state synchronization for API clients ([**@kvaps**](https://github.com/kvaps) in #1860). + +## Dependencies + +* **[cilium] Update Cilium to v1.18.6**: Updated Cilium CNI to v1.18.6 with security fixes and performance improvements ([**@sircthulhu**](https://github.com/sircthulhu) in #1868, #1870). + +--- + +**Full Changelog**: [v0.40.2...v0.40.3](https://github.com/cozystack/cozystack/compare/v0.40.2...v0.40.3) diff --git a/docs/changelogs/v0.40.4.md b/docs/changelogs/v0.40.4.md new file mode 100644 index 00000000..ec175486 --- /dev/null +++ b/docs/changelogs/v0.40.4.md @@ -0,0 +1,23 @@ + + +## Improvements + +* **[kubernetes] Increase default apiServer resourcesPreset to large**: Increased the default resource preset for kube-apiserver to `large` to ensure more reliable operation under higher workloads and prevent resource constraints ([**@kvaps**](https://github.com/kvaps) in #1875, #1882). + +* **[kubernetes] Increase kube-apiserver startup probe threshold**: Increased the startup probe threshold for kube-apiserver to allow more time for the API server to become ready, especially in scenarios with slow storage or high load ([**@kvaps**](https://github.com/kvaps) in #1876, #1883). + +* **[etcd] Increase probe thresholds for better recovery**: Increased etcd probe thresholds to provide more time for recovery operations, improving cluster resilience during network issues or temporary slowdowns ([**@kvaps**](https://github.com/kvaps) in #1874, #1878). + +## Fixes + +* **[dashboard] Fix view of loadbalancer IP in services window**: Fixed an issue where load balancer IP addresses were not displayed correctly in the services window of the dashboard ([**@IvanHunters**](https://github.com/IvanHunters) in #1884, #1887). + +## Dependencies + +* **Update Talos Linux v1.11.6**: Updated Talos Linux to v1.11.6 with latest security patches and improvements ([**@kvaps**](https://github.com/kvaps) in #1879). + +--- + +**Full Changelog**: [v0.40.3...v0.40.4](https://github.com/cozystack/cozystack/compare/v0.40.3...v0.40.4) diff --git a/docs/changelogs/v0.40.5.md b/docs/changelogs/v0.40.5.md new file mode 100644 index 00000000..40ebd107 --- /dev/null +++ b/docs/changelogs/v0.40.5.md @@ -0,0 +1,15 @@ + + +## Improvements + +* **[dashboard] Improve dashboard session params**: Improved session parameter handling in the dashboard for better user experience and more reliable session management ([**@lllamnyp**](https://github.com/lllamnyp) in #1913, #1919). + +## Dependencies + +* **Update cozyhr to v1.6.1**: Updated cozyhr to v1.6.1, which fixes a critical bug causing helm-controller v0.37.0+ to unexpectedly uninstall HelmReleases after cozyhr apply by correcting history snapshot fields for helm-controller compatibility ([**@kvaps**](https://github.com/kvaps) in cozystack/cozyhr#10). + +--- + +**Full Changelog**: [v0.40.4...v0.40.5](https://github.com/cozystack/cozystack/compare/v0.40.4...v0.40.5) diff --git a/docs/changelogs/v0.40.6.md b/docs/changelogs/v0.40.6.md new file mode 100644 index 00000000..40e499f5 --- /dev/null +++ b/docs/changelogs/v0.40.6.md @@ -0,0 +1,11 @@ + + +## Fixes + +* **[kubernetes] Fix manifests for kubernetes deployment**: Fixed incorrect manifests that prevented proper Kubernetes deployment, restoring correct application behavior ([**@IvanHunters**](https://github.com/IvanHunters) in #1943, #1944). + +--- + +**Full Changelog**: [v0.40.5...v0.40.6](https://github.com/cozystack/cozystack/compare/v0.40.5...v0.40.6) diff --git a/docs/changelogs/v0.40.7.md b/docs/changelogs/v0.40.7.md new file mode 100644 index 00000000..f1b7a52e --- /dev/null +++ b/docs/changelogs/v0.40.7.md @@ -0,0 +1,11 @@ + + +## Security + +* **[dashboard] Verify JWT token**: Added JWT token verification to the dashboard, ensuring that authentication tokens are properly validated before granting access. This prevents unauthorized access through forged or expired tokens ([**@lllamnyp**](https://github.com/lllamnyp) in #1980, #1984). + +--- + +**Full Changelog**: [v0.40.6...v0.40.7](https://github.com/cozystack/cozystack/compare/v0.40.6...v0.40.7) diff --git a/docs/changelogs/v0.41.0.md b/docs/changelogs/v0.41.0.md new file mode 100644 index 00000000..3084e493 --- /dev/null +++ b/docs/changelogs/v0.41.0.md @@ -0,0 +1,63 @@ + + +# Cozystack v0.41.0 — "MongoDB" + +This release introduces MongoDB as a new managed application, expanding Cozystack's database offerings alongside existing PostgreSQL, MySQL, and Redis services. The release also includes storage improvements, Kubernetes stability enhancements, and updated documentation. + +## Feature Highlights + +### MongoDB Managed Application + +Cozystack now includes MongoDB as a fully managed database service. Users can deploy production-ready MongoDB instances directly from the application catalog with minimal configuration. + +Key capabilities: +- **Replica Set deployment**: Automatic configuration of MongoDB replica sets for high availability +- **Persistent storage**: Integration with Cozystack storage backends for reliable data persistence +- **Resource management**: Configurable CPU, memory, and storage resources +- **Monitoring integration**: Built-in metrics export for platform monitoring + +Deploy MongoDB through the Cozystack dashboard or using the standard application deployment workflow ([**@lexfrei**](https://github.com/lexfrei) in #1822, #1881). + +## Improvements + +* **[linstor] Update piraeus-server patches with critical fixes**: Backported critical patches to piraeus-server that address storage stability issues and improve DRBD resource handling. These patches fix edge cases in device management and ensure more reliable storage operations ([**@kvaps**](https://github.com/kvaps) in #1850, #1852). + +* **[linstor] Refactor node-level RWX validation**: Refactored the node-level ReadWriteMany (RWX) validation logic in LINSTOR CSI. The validation has been moved to the CSI driver level with a custom linstor-csi image build, providing more reliable RWX volume handling and clearer error messages when RWX requirements cannot be satisfied ([**@kvaps**](https://github.com/kvaps) in #1856, #1857). + +* **[kubernetes] Increase default apiServer resourcesPreset to large**: Increased the default resource preset for kube-apiserver to `large` to ensure more reliable operation under higher workloads and prevent resource constraints ([**@kvaps**](https://github.com/kvaps) in #1875, #1882). + +* **[kubernetes] Increase kube-apiserver startup probe threshold**: Increased the startup probe threshold for kube-apiserver to allow more time for the API server to become ready, especially in scenarios with slow storage or high load ([**@kvaps**](https://github.com/kvaps) in #1876, #1883). + +* **[etcd] Increase probe thresholds for better recovery**: Increased etcd probe thresholds to provide more time for recovery operations, improving cluster resilience during network issues or temporary slowdowns ([**@kvaps**](https://github.com/kvaps) in #1874, #1878). + +## Fixes + +* **[linstor] Remove node-level RWX validation**: Removed the problematic node-level RWX validation that was causing issues with volume provisioning. The validation logic has been refactored and moved to a more appropriate location in the LINSTOR CSI driver ([**@kvaps**](https://github.com/kvaps) in #1851). + +* **[apiserver] Fix Watch resourceVersion and bookmark handling**: Fixed issues with Watch API handling of resourceVersion and bookmarks, ensuring proper event streaming and state synchronization for API clients ([**@kvaps**](https://github.com/kvaps) in #1860). + +* **[dashboard] Fix view of loadbalancer IP in services window**: Fixed an issue where load balancer IP addresses were not displayed correctly in the services window of the dashboard ([**@IvanHunters**](https://github.com/IvanHunters) in #1884, #1887). + +## Dependencies + +* **[cilium] Update cilium to v1.18.6**: Updated Cilium CNI to v1.18.6 with security fixes and performance improvements ([**@sircthulhu**](https://github.com/sircthulhu) in #1868, #1870). + +* **Update Talos Linux v1.11.6**: Updated Talos Linux to v1.11.6 with latest security patches and improvements ([**@kvaps**](https://github.com/kvaps) in #1879). + +## Documentation + +* **[website] Add documentation for creating and managing cloned virtual machines**: Added comprehensive guide for VM cloning operations ([**@sircthulhu**](https://github.com/sircthulhu) in [cozystack/website#401](https://github.com/cozystack/website/pull/401)). + +* **[website] Simplify NFS driver setup instructions**: Improved NFS driver setup documentation with clearer instructions ([**@kvaps**](https://github.com/kvaps) in [cozystack/website#399](https://github.com/cozystack/website/pull/399)). + +* **[website] Update Talos installation docs for Hetzner and Servers.com**: Updated installation documentation with improved instructions for Hetzner and Servers.com environments ([**@kvaps**](https://github.com/kvaps) in [cozystack/website#395](https://github.com/cozystack/website/pull/395)). + +* **[website] Add Hetzner RobotLB documentation**: Added documentation for configuring public IP with Hetzner RobotLB ([**@kvaps**](https://github.com/kvaps) in [cozystack/website#394](https://github.com/cozystack/website/pull/394)). + +* **[website] Add Hidora organization support details**: Added Hidora to the support page with organization details ([**@matthieu-robin**](https://github.com/matthieu-robin) in [cozystack/website#397](https://github.com/cozystack/website/pull/397), [cozystack/website#398](https://github.com/cozystack/website/pull/398)). + +--- + +**Full Changelog**: [v0.40.0...v0.41.0](https://github.com/cozystack/cozystack/compare/v0.40.0...v0.41.0) diff --git a/docs/changelogs/v0.41.1.md b/docs/changelogs/v0.41.1.md new file mode 100644 index 00000000..d084d644 --- /dev/null +++ b/docs/changelogs/v0.41.1.md @@ -0,0 +1,11 @@ + + +## Improvements + +* **[kubernetes] Add enum validation for IngressNginx exposeMethod**: Added enum validation for the `exposeMethod` field in IngressNginx configuration, preventing invalid values and improving user experience with clear valid options ([**@sircthulhu**](https://github.com/sircthulhu) in #1895, #1897). + +--- + +**Full Changelog**: [v0.41.0...v0.41.1](https://github.com/cozystack/cozystack/compare/v0.41.0...v0.41.1) diff --git a/docs/changelogs/v0.41.2.md b/docs/changelogs/v0.41.2.md new file mode 100644 index 00000000..8b3a8261 --- /dev/null +++ b/docs/changelogs/v0.41.2.md @@ -0,0 +1,13 @@ + + +## Improvements + +* **[monitoring-agents] Set minReplicas to 1 for VPA for VMAgent**: Configured VPA (Vertical Pod Autoscaler) to maintain at least 1 replica for VMAgent, ensuring monitoring availability during scaling operations ([**@sircthulhu**](https://github.com/sircthulhu) in #1894, #1905). + +* **[mongodb] Remove user-configurable images from MongoDB chart**: Removed user-configurable image options from the MongoDB chart to simplify configuration and ensure consistency with tested image versions ([**@kvaps**](https://github.com/kvaps) in #1901, #1904). + +--- + +**Full Changelog**: [v0.41.1...v0.41.2](https://github.com/cozystack/cozystack/compare/v0.41.1...v0.41.2) diff --git a/docs/changelogs/v0.41.3.md b/docs/changelogs/v0.41.3.md new file mode 100644 index 00000000..6d04dad3 --- /dev/null +++ b/docs/changelogs/v0.41.3.md @@ -0,0 +1,15 @@ + + +## Improvements + +* **[kubernetes] Show Service and Ingress resources for Kubernetes app in dashboard**: Added visibility of Service and Ingress resources for Kubernetes applications in the dashboard, improving resource management and monitoring capabilities ([**@sircthulhu**](https://github.com/sircthulhu) in #1912, #1915). + +## Fixes + +* **[dashboard] Fix filtering on Pods tab for Service**: Fixed an issue where pod filtering was not working correctly on the Pods tab when viewing Services in the dashboard ([**@sircthulhu**](https://github.com/sircthulhu) in #1909, #1914). + +--- + +**Full Changelog**: [v0.41.2...v0.41.3](https://github.com/cozystack/cozystack/compare/v0.41.2...v0.41.3) diff --git a/docs/changelogs/v0.41.4.md b/docs/changelogs/v0.41.4.md new file mode 100644 index 00000000..70f1daeb --- /dev/null +++ b/docs/changelogs/v0.41.4.md @@ -0,0 +1,11 @@ + + +## Dependencies + +* **Update cozyhr to v1.6.1**: Updated cozyhr to v1.6.1, which fixes a critical bug causing helm-controller v0.37.0+ to unexpectedly uninstall HelmReleases after cozyhr apply by correcting history snapshot fields for helm-controller compatibility ([**@kvaps**](https://github.com/kvaps) in cozystack/cozyhr#10). + +--- + +**Full Changelog**: [v0.41.3...v0.41.4](https://github.com/cozystack/cozystack/compare/v0.41.3...v0.41.4) diff --git a/docs/changelogs/v0.41.5.md b/docs/changelogs/v0.41.5.md new file mode 100644 index 00000000..fb96fcf4 --- /dev/null +++ b/docs/changelogs/v0.41.5.md @@ -0,0 +1,21 @@ + + +## Features and Improvements + +* **[dashboard] Add "Edit" button to all resources**: Added an "Edit" button across all resource views in the dashboard, allowing users to modify resource configurations directly from the UI ([**@sircthulhu**](https://github.com/sircthulhu) in #1928, #1931). + +* **[dashboard] Add resource quota usage to tenant details page**: Added resource quota usage display to the tenant details page, giving administrators visibility into how much of allocated resources each tenant is consuming ([**@sircthulhu**](https://github.com/sircthulhu) in #1929, #1932). + +* **[branding] Separate values for keycloak**: Separated Keycloak branding values into dedicated configuration, allowing more granular customization of Keycloak appearance without affecting other branding settings ([**@nbykov0**](https://github.com/nbykov0) in #1946). + +* **Add instance profile label to workload monitor**: Added instance profile metadata labels to the workload monitor, enabling better resource tracking and monitoring by instance profile type ([**@matthieu-robin**](https://github.com/matthieu-robin) in #1954, #1957). + +## Fixes + +* **[kubernetes] Fix manifests for kubernetes deployment**: Fixed incorrect manifests that prevented proper Kubernetes deployment, restoring correct application behavior ([**@IvanHunters**](https://github.com/IvanHunters) in #1943, #1945). + +--- + +**Full Changelog**: [v0.41.4...v0.41.5](https://github.com/cozystack/cozystack/compare/v0.41.4...v0.41.5) diff --git a/docs/changelogs/v0.41.6.md b/docs/changelogs/v0.41.6.md new file mode 100644 index 00000000..8e7783df --- /dev/null +++ b/docs/changelogs/v0.41.6.md @@ -0,0 +1,17 @@ + + +## Improvements + +* **[vm] Allow changing field external after creation**: Users can now modify the external network field on virtual machines after initial creation, providing more flexibility in VM networking configuration without requiring recreation ([**@sircthulhu**](https://github.com/sircthulhu) in #1956, #1962). + +* **[branding] Separate values for keycloak**: Separated Keycloak branding values into dedicated configuration for more granular customization of Keycloak appearance ([**@nbykov0**](https://github.com/nbykov0) in #1947, #1963). + +## Fixes + +* **[kubernetes] Fix coredns serviceaccount to match kubernetes bootstrap RBAC**: Configured the CoreDNS chart to create a `kube-dns` ServiceAccount matching the Kubernetes bootstrap ClusterRoleBinding, fixing RBAC errors (`Failed to watch`) when CoreDNS pods restart ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #1958, #1978). + +--- + +**Full Changelog**: [v0.41.5...v0.41.6](https://github.com/cozystack/cozystack/compare/v0.41.5...v0.41.6) diff --git a/docs/changelogs/v0.41.7.md b/docs/changelogs/v0.41.7.md new file mode 100644 index 00000000..5a77664d --- /dev/null +++ b/docs/changelogs/v0.41.7.md @@ -0,0 +1,15 @@ + + +## Security + +* **[dashboard] Verify JWT token**: Added JWT token verification to the dashboard, ensuring that authentication tokens are properly validated before granting access. This prevents unauthorized access through forged or expired tokens ([**@lllamnyp**](https://github.com/lllamnyp) in #1980, #1983). + +## Fixes + +* **[postgres-operator] Correct PromQL syntax in CNPGClusterOffline alert**: Fixed incorrect PromQL syntax in the `CNPGClusterOffline` alert rule for CloudNativePG, ensuring the alert fires correctly when all instances of a PostgreSQL cluster are offline ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #1981, #1989). + +--- + +**Full Changelog**: [v0.41.6...v0.41.7](https://github.com/cozystack/cozystack/compare/v0.41.6...v0.41.7) diff --git a/docs/changelogs/v0.41.8.md b/docs/changelogs/v0.41.8.md new file mode 100644 index 00000000..9984c87d --- /dev/null +++ b/docs/changelogs/v0.41.8.md @@ -0,0 +1,17 @@ + + +## Features and Improvements + +* **[kubernetes] Auto-enable Gateway API support in cert-manager**: cert-manager now automatically enables `enableGatewayAPI` when the Gateway API addon is active in the Kubernetes application. Users no longer need to manually configure this setting, and the option can still be overridden via `valuesOverride` ([**@kvaps**](https://github.com/kvaps) in #1997, #2012). + +* **[vm] Allow switching between instancetype and custom resources**: Users can now switch virtual machines between instancetype-based and custom resource configurations after creation. The upgrade hook atomically patches VM resources, providing more flexibility in adjusting VM sizing without recreation ([**@sircthulhu**](https://github.com/sircthulhu) in #2008, #2013). + +## Fixes + +* **[dashboard] Add startupProbe to prevent container restarts on slow hardware**: Added `startupProbe` to both `bff` and `web` containers in the dashboard deployment. On slow hardware, kubelet was killing containers because the `livenessProbe` only allowed ~33 seconds for startup. The `startupProbe` gives containers up to 60 seconds to start before `livenessProbe` kicks in ([**@kvaps**](https://github.com/kvaps) in #1996, #2014). + +--- + +**Full Changelog**: [v0.41.7...v0.41.8](https://github.com/cozystack/cozystack/compare/v0.41.7...v0.41.8) diff --git a/docs/changelogs/v0.41.9.md b/docs/changelogs/v0.41.9.md new file mode 100644 index 00000000..d0cd3ff9 --- /dev/null +++ b/docs/changelogs/v0.41.9.md @@ -0,0 +1,15 @@ + + +## Fixes + +* **[cozystack-basics] Deny resourcequotas deletion for tenant admin**: Prevented tenant administrators from deleting resource quotas, ensuring that resource limits set by platform administrators cannot be bypassed by tenant-level users ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2076). + +## Dependencies + +* **Update Kube-OVN to v1.15.3**: Updated Kube-OVN CNI to v1.15.3 with latest bug fixes and improvements ([**@kvaps**](https://github.com/kvaps)). + +--- + +**Full Changelog**: [v0.41.8...v0.41.9](https://github.com/cozystack/cozystack/compare/v0.41.8...v0.41.9) diff --git a/docs/changelogs/v1.0.0-alpha.1.md b/docs/changelogs/v1.0.0-alpha.1.md new file mode 100644 index 00000000..4411b35f --- /dev/null +++ b/docs/changelogs/v1.0.0-alpha.1.md @@ -0,0 +1,134 @@ +# Cozystack v1.0.0-alpha.1 — "Package-Based Architecture" + +This alpha release introduces a fundamental architectural shift from HelmRelease bundles to Package-based deployment managed by the new cozystack-operator. It includes a comprehensive backup system with Velero integration, significant API changes that rename the core CRD, Flux sharding for improved tenant workload distribution, enhanced monitoring capabilities, and various improvements to virtual machines, tenants, and the build workflow. + +> **⚠️ Alpha Release Warning**: This is a pre-release version intended for testing and early adoption. Breaking changes may occur before the stable v1.0.0 release. + +## Breaking Changes + +### API Rename: CozystackResourceDefinition → ApplicationDefinition + +The `CozystackResourceDefinition` CRD has been renamed to `ApplicationDefinition` for better clarity and consistency. This change affects: +- All Go types and controller files +- CRD Helm chart renamed from `cozystack-resource-definition-crd` to `application-definition-crd` +- All cozyrds YAML manifests updated to use `kind: ApplicationDefinition` + +A migration (v24) is included to handle the transition automatically. + +### Package-Based Deployment + +The platform now uses Package resources managed by cozystack-operator instead of HelmRelease bundles. Key changes: +- Restructured values.yaml with full configuration support (networking, publishing, authentication, scheduling, branding, resources) +- Added values-isp-full.yaml and values-isp-hosted.yaml for bundle variants +- Package resources replace old HelmRelease templates +- PackageSources moved from sources/ to templates/sources/ +- Migration script `hack/migrate-to-version-1.0.sh` provided for converting ConfigMaps to Package resources + +--- + +## Major Features and Improvements + +### Cozystack Operator + +A new operator has been introduced to manage Package and PackageSource resources, providing declarative package management for the platform: + +* **[cozystack-operator] Introduce API objects: packages and packagesources**: Added new CRDs for declarative package management, defining the API for Package and PackageSource resources ([**@kvaps**](https://github.com/kvaps) in #1740). +* **[cozystack-operator] Introduce Cozystack-operator core logic**: Implemented core reconciliation logic for the operator, handling Package and PackageSource lifecycle management ([**@kvaps**](https://github.com/kvaps) in #1741). +* **[cozystack-operator] Add Package and PackageSource reconcilers**: Added controllers for Package and PackageSource resources with full reconciliation support ([**@kvaps**](https://github.com/kvaps) in #1755). +* **[cozystack-operator] Add deployment files**: Added Kubernetes deployment manifests for running cozystack-operator in the cluster ([**@kvaps**](https://github.com/kvaps) in #1761). +* **[platform] Add PackageSources for cozystack-operator**: Added PackageSource definitions for cozystack-operator integration ([**@kvaps**](https://github.com/kvaps) in #1760). +* **[cozypkg] Add tool for managing Package and PackageSources**: Added CLI tool for managing Package and PackageSource resources ([**@kvaps**](https://github.com/kvaps) in #1756). + +### Backup System + +Comprehensive backup functionality has been added with Velero integration for managing application backups: + +* **[backups] Implement core backup Plan controller**: Core controller for managing backup schedules and plans, providing the foundation for backup orchestration ([**@lllamnyp**](https://github.com/lllamnyp) in #1640). +* **[backups] Build and deploy backup controller**: Deployment infrastructure for the backup controller, including container image builds and Kubernetes manifests ([**@lllamnyp**](https://github.com/lllamnyp) in #1685). +* **[backups] Scaffold a backup strategy API group**: Added API group for backup strategies, enabling pluggable backup implementations ([**@lllamnyp**](https://github.com/lllamnyp) in #1687). +* **[backups] Add indices to core backup resources**: Added indices to backup resources for improved query performance ([**@lllamnyp**](https://github.com/lllamnyp) in #1719). +* **[backups] Stub the Job backup strategy controller**: Added stub implementation for Job-based backup strategy ([**@lllamnyp**](https://github.com/lllamnyp) in #1720). +* **[backups] Implement Velero strategy controller**: Integration with Velero for backup operations, enabling enterprise-grade backup capabilities ([**@androndo**](https://github.com/androndo) in #1762). +* **[backups,dashboard] User-facing UI**: Dashboard interface for managing backups and backup jobs, providing visibility into backup status and history ([**@lllamnyp**](https://github.com/lllamnyp) in #1737). + +### Platform Architecture + +* **[platform] Migrate from HelmRelease bundles to Package-based deployment**: Replaced HelmRelease bundle system with Package resources managed by cozystack-operator. Includes restructured values.yaml with full configuration support and migration tooling ([**@kvaps**](https://github.com/kvaps) in #1816). +* **refactor(api): rename CozystackResourceDefinition to ApplicationDefinition**: Renamed CRD and all related types for better clarity and consistency. Updated all Go types, controllers, and 25+ YAML manifests ([**@kvaps**](https://github.com/kvaps) in #1864). +* **feat(flux): implement flux sharding for tenant HelmReleases**: Added Flux sharding support to distribute tenant HelmRelease reconciliation across multiple controllers, improving scalability in multi-tenant environments ([**@kvaps**](https://github.com/kvaps) in #1816). +* **refactor(installer): migrate installer to cozystack-operator**: Moved installer functionality to cozystack-operator for unified management ([**@kvaps**](https://github.com/kvaps) in #1816). +* **feat(api): add chartRef to ApplicationDefinition**: Added chartRef field to support ExternalArtifact references for flexible chart sourcing ([**@kvaps**](https://github.com/kvaps) in #1816). +* **feat(api): show only hash in version column for applications and modules**: Simplified version display in API responses for cleaner output ([**@kvaps**](https://github.com/kvaps) in #1816). + +### Virtual Machines + +* **[vm] Always expose VMs with a service**: Virtual machines are now always exposed with at least a ClusterIP service, ensuring they have in-cluster DNS names and can be accessed from other pods even without public IP addresses ([**@lllamnyp**](https://github.com/lllamnyp) in #1738, #1751). + +### Monitoring + +* **[monitoring] Add SLACK_SEVERITY_FILTER field and VMAgent for tenant monitoring**: Introduced the SLACK_SEVERITY_FILTER environment variable in the Alerta deployment to enable filtering of alert severities for Slack notifications based on the disabledSeverity configuration. Additionally, added a VMAgent resource template for scraping metrics within tenant namespaces, improving monitoring granularity and control ([**@IvanHunters**](https://github.com/IvanHunters) in #1712). + +### Tenants + +* **[tenant] Allow egress to parent ingress pods**: Updated tenant network policies to allow egress traffic to parent cluster ingress pods, enabling proper communication patterns between tenant namespaces and parent cluster ingress controllers ([**@lexfrei**](https://github.com/lexfrei) in #1765, #1776). +* **[tenant] Run cleanup job from system namespace**: Moved tenant cleanup job to run from system namespace, improving security and resource isolation for tenant cleanup operations ([**@lllamnyp**](https://github.com/lllamnyp) in #1774, #1777). + +### System + +* **[system] Add resource requests and limits to etcd-defrag**: Added resource requests and limits to etcd-defrag job to ensure proper resource allocation and prevent resource contention during etcd maintenance operations ([**@matthieu-robin**](https://github.com/matthieu-robin) in #1785, #1786). + +### Development and Build + +* **feat(cozypkg): add cross-platform build targets with version injection**: Added cross-platform build targets (linux/amd64, linux/arm64, darwin/amd64, darwin/arm64) for cozypkg/cozyhr tool with automatic version injection from git tags ([**@kvaps**](https://github.com/kvaps) in #1862). +* **refactor: move scripts to hack directory**: Reorganized scripts to standard hack/ location following Kubernetes project conventions ([**@kvaps**](https://github.com/kvaps) in #1863). + +## Fixes + +* **fix(talos): skip rebuilding assets if files already exist**: Improved Talos package build process to avoid redundant asset rebuilds when files are already present, reducing build time ([**@kvaps**](https://github.com/kvaps)). +* **[kubevirt-operator] Fix typo in VMNotRunningFor10Minutes alert**: Fixed typo in VM alert name, ensuring proper alert triggering and monitoring for virtual machines that are not running for extended periods ([**@lexfrei**](https://github.com/lexfrei) in #1770, #1775). +* **[backups] Fix malformed glob and split in template**: Fixed malformed glob pattern and split operation in backup template processing ([**@lllamnyp**](https://github.com/lllamnyp) in #1708). + +## Documentation + +* **[website] docs(storage): simplify NFS driver setup instructions**: Simplified NFS driver setup documentation with clearer instructions ([**@kvaps**](https://github.com/kvaps) in [cozystack/website#399](https://github.com/cozystack/website/pull/399)). +* **[website] Add Hidora organization support details**: Added Hidora to the support page with organization details ([**@matthieu-robin**](https://github.com/matthieu-robin) in [cozystack/website#397](https://github.com/cozystack/website/pull/397)). +* **[website] Update LinkedIn link for Hidora organization**: Updated LinkedIn link for Hidora organization on the support page ([**@matthieu-robin**](https://github.com/matthieu-robin) in [cozystack/website#398](https://github.com/cozystack/website/pull/398)). + +--- + +## Migration Guide + +### From v0.38.x / v0.39.x to v1.0.0-alpha.1 + +1. **Backup your cluster** before upgrading +2. Run the migration script: `hack/migrate-to-version-1.0.sh` +3. The migration will: + - Convert ConfigMaps to Package resources + - Rename CozystackResourceDefinition to ApplicationDefinition + - Update HelmRelease references to use Package-based deployment + +### Known Issues + +- This is an alpha release; some features may be incomplete or change before stable release +- Migration script should be tested in a non-production environment first + +--- + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@androndo**](https://github.com/androndo) +* [**@IvanHunters**](https://github.com/IvanHunters) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@lllamnyp**](https://github.com/lllamnyp) +* [**@matthieu-robin**](https://github.com/matthieu-robin) + +--- + +**Full Changelog**: [v0.38.0...v1.0.0-alpha.1](https://github.com/cozystack/cozystack/compare/v0.38.0...v1.0.0-alpha.1) + + diff --git a/docs/changelogs/v1.0.0-alpha.2.md b/docs/changelogs/v1.0.0-alpha.2.md new file mode 100644 index 00000000..14bd89a2 --- /dev/null +++ b/docs/changelogs/v1.0.0-alpha.2.md @@ -0,0 +1,71 @@ + + +> **⚠️ Alpha Release Warning**: This is a pre-release version intended for testing and early adoption. Breaking changes may occur before the stable v1.0.0 release. + +## Major Features and Improvements + +### New Applications + +* **[apps] Add MongoDB managed application**: Added MongoDB as a new managed application, providing a fully managed MongoDB database with automatic scaling, backups, and high availability support ([**@lexfrei**](https://github.com/lexfrei) in #1822). + +### Networking + +* **[kilo] Introduce kilo**: Added Kilo WireGuard mesh networking support. Kilo provides secure WireGuard-based VPN mesh for connecting Kubernetes nodes across different networks and regions ([**@kvaps**](https://github.com/kvaps) in #1691). + +* **[local-ccm] Add local-ccm package**: Added local cloud controller manager package for managing load balancer services in local/bare-metal environments without a cloud provider ([**@kvaps**](https://github.com/kvaps) in #1831). + +### Platform + +* **[platform] Add flux-plunger controller**: Added flux-plunger controller to automatically fix stuck HelmRelease errors by cleaning up failed resources and retrying reconciliation ([**@kvaps**](https://github.com/kvaps) in #1843). + +* **[platform] Split telemetry between operator and controller**: Separated telemetry collection between cozystack-operator and cozystack-controller for better metrics isolation and monitoring capabilities ([**@kvaps**](https://github.com/kvaps) in #1869). + +* **[platform] Remove cozystack.io/ui label**: Cleaned up deprecated `cozystack.io/ui` labels from platform components ([**@kvaps**](https://github.com/kvaps) in #1872). + +## Improvements + +* **[kubernetes] Increase default apiServer resourcesPreset to large**: Increased the default resource preset for kube-apiserver to `large` to ensure more reliable operation under higher workloads ([**@kvaps**](https://github.com/kvaps) in #1875). + +* **[kubernetes] Increase kube-apiserver startup probe threshold**: Increased the startup probe threshold for kube-apiserver to allow more time for the API server to become ready ([**@kvaps**](https://github.com/kvaps) in #1876). + +* **[etcd] Increase probe thresholds for better recovery**: Increased etcd probe thresholds to provide more time for recovery operations, improving cluster resilience ([**@kvaps**](https://github.com/kvaps) in #1874). + +## Fixes + +* **[apiserver] Fix Watch resourceVersion and bookmark handling**: Fixed issues with Watch API handling of resourceVersion and bookmarks, ensuring proper event streaming and state synchronization ([**@kvaps**](https://github.com/kvaps) in #1860). + +* **[dashboard] Fix view of loadbalancer IP in services window**: Fixed an issue where load balancer IP addresses were not displayed correctly in the services window of the dashboard ([**@IvanHunters**](https://github.com/IvanHunters) in #1884). + +## Dependencies + +* **[cilium] Update cilium to v1.18.6**: Updated Cilium CNI to v1.18.6 with security fixes and performance improvements ([**@sircthulhu**](https://github.com/sircthulhu) in #1868). + +* **Update Talos Linux v1.12.1**: Updated Talos Linux to v1.12.1 with latest features, security patches and improvements ([**@kvaps**](https://github.com/kvaps) in #1877). + +## Documentation + +* **[website] Add documentation for creating and managing cloned virtual machines**: Added comprehensive guide for VM cloning operations ([**@sircthulhu**](https://github.com/sircthulhu) in [cozystack/website#401](https://github.com/cozystack/website/pull/401)). + +* **[website] Simplify NFS driver setup instructions**: Improved NFS driver setup documentation with clearer instructions ([**@kvaps**](https://github.com/kvaps) in [cozystack/website#399](https://github.com/cozystack/website/pull/399)). + +* **[website] Update Talos installation docs for Hetzner and Servers.com**: Updated installation documentation with improved instructions for Hetzner and Servers.com environments ([**@kvaps**](https://github.com/kvaps) in [cozystack/website#395](https://github.com/cozystack/website/pull/395)). + +* **[website] Add Hetzner RobotLB documentation**: Added documentation for configuring public IP with Hetzner RobotLB ([**@kvaps**](https://github.com/kvaps) in [cozystack/website#394](https://github.com/cozystack/website/pull/394)). + +* **[website] Add Hidora organization support details**: Added Hidora to the support page with organization details ([**@matthieu-robin**](https://github.com/matthieu-robin) in [cozystack/website#397](https://github.com/cozystack/website/pull/397), [cozystack/website#398](https://github.com/cozystack/website/pull/398)). + +--- + +## Contributors + +* [**@IvanHunters**](https://github.com/IvanHunters) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@matthieu-robin**](https://github.com/matthieu-robin) +* [**@sircthulhu**](https://github.com/sircthulhu) + +--- + +**Full Changelog**: [v1.0.0-alpha.1...v1.0.0-alpha.2](https://github.com/cozystack/cozystack/compare/v1.0.0-alpha.1...v1.0.0-alpha.2) diff --git a/docs/changelogs/v1.0.0-beta.3.md b/docs/changelogs/v1.0.0-beta.3.md new file mode 100644 index 00000000..45d654a7 --- /dev/null +++ b/docs/changelogs/v1.0.0-beta.3.md @@ -0,0 +1,144 @@ + + +> **⚠️ Beta Release Warning**: This is a pre-release version intended for testing and early adoption. Breaking changes may occur before the stable v1.0.0 release. + +## Major Features and Improvements + +### New Applications + +* **[qdrant] Add Qdrant vector database application**: Added Qdrant as a new managed application, providing a high-performance vector database for AI and machine learning workloads. Supports single replica or clustered mode, persistent storage, resource presets, API key authentication, and optional external LoadBalancer access ([**@lexfrei**](https://github.com/lexfrei) in #1987). + +### System Components + +* **[system] Add cluster-autoscaler package for Hetzner and Azure**: Added cluster-autoscaler system package with support for multiple cloud providers (Hetzner and Azure) to automatically scale management cluster nodes. Includes comprehensive documentation for Hetzner setup with Talos Linux, vSwitch configuration, and Kilo mesh networking integration ([**@kvaps**](https://github.com/kvaps) in #1964). + +* **[system] Add clustersecret-operator package**: Added clustersecret-operator system package for managing secrets across multiple namespaces in Kubernetes clusters ([**@sircthulhu**](https://github.com/sircthulhu) in #2025). + +### Networking + +* **[kilo] Update to v0.7.0 and add configurable MTU**: Updated Kilo WireGuard mesh networking to v0.7.0 from cozystack fork with pre-built images. Added configurable MTU parameter (default: auto) for WireGuard interface, allowing automatic MTU detection or manual override ([**@kvaps**](https://github.com/kvaps) in #2003). + +* **[local-ccm] Add node-lifecycle-controller component**: Added optional node-lifecycle-controller to local-ccm package that automatically deletes unreachable NotReady nodes from the cluster. Solves the "zombie" node problem when cluster autoscaler deletes cloud instances but node objects remain in Kubernetes. Supports configurable node selectors, protected labels, and HA deployment with leader election ([**@IvanHunters**](https://github.com/IvanHunters) in #1992). + +### Virtual Machines + +* **[vm] Add cpuModel field to specify CPU model without instanceType**: Added cpuModel field to VirtualMachine API, allowing users to specify CPU model directly without using instanceType, providing more granular control over VM CPU configuration ([**@sircthulhu**](https://github.com/sircthulhu) in #2007). + +* **[vm] Allow switching between instancetype and custom resources**: Implemented atomic upgrade hook that allows switching between instanceType-based and custom resource-based VM configuration, providing more flexibility in VM resource management ([**@sircthulhu**](https://github.com/sircthulhu) in #2008). + +* **[vm] Migrate to runStrategy instead of running**: Migrated VirtualMachine API from deprecated `running` field to `runStrategy` field, following KubeVirt upstream best practices ([**@sircthulhu**](https://github.com/sircthulhu) in #2004). + +### Backups + +* **[backups] Add comprehensive backup and restore functionality**: Major update to backup system including BackupClass for Velero, virtual machine backup strategies, RestoreJob resource with end-to-end restore workflows, Velero integration with polling and status tracking, and enhanced backup plans UI with simplified Plan/BackupJob API ([**@androndo**](https://github.com/androndo) in #1967, [**@lllamnyp**](https://github.com/lllamnyp) in #1968). + +* **[backups] Add kubevirt plugin to velero**: Added KubeVirt plugin to Velero for proper virtual machine backup support, enabling consistent snapshots of VM state and data ([**@lllamnyp**](https://github.com/lllamnyp) in #2017). + +* **[backups] Install backupstrategy controller by default**: Enabled backupstrategy controller by default to provide automatic backup scheduling and management for managed applications ([**@lllamnyp**](https://github.com/lllamnyp) in #2020). + +* **[backups] Better selectors for VM strategy**: Improved VM backup strategy selectors for more accurate and reliable backup targeting ([**@lllamnyp**](https://github.com/lllamnyp) in #2023). + +### Platform + +* **[kubernetes] Auto-enable Gateway API support in cert-manager**: Added automatic Gateway API support in cert-manager for tenant Kubernetes clusters, enabling automatic certificate management for Gateway API resources ([**@kvaps**](https://github.com/kvaps) in #1997). + +* **[tenant,rbac] Use shared clusterroles**: Refactored tenant RBAC to use shared ClusterRoles, improving maintainability and consistency across tenant namespaces ([**@lllamnyp**](https://github.com/lllamnyp) in #1999). + +* **[mongodb] Unify users and databases configuration**: Simplified MongoDB user and database configuration with a more unified API structure ([**@kvaps**](https://github.com/kvaps) in #1923). + +## Improvements + +* **[keycloak-configure,dashboard] Enable insecure TLS verification by default**: Made SSL certificate verification configurable with insecure mode enabled by default for easier local development and testing ([**@IvanHunters**](https://github.com/IvanHunters) in #2005). + +* **[dashboard] Add startupProbe to prevent container restarts on slow hardware**: Added startup probe to dashboard pods to prevent unnecessary container restarts on slow hardware or during high load ([**@kvaps**](https://github.com/kvaps) in #1996). + +* **[cilium] Change cilium-operator replicas to 1**: Reduced Cilium operator replicas from 2 to 1 to decrease resource consumption in smaller deployments ([**@IvanHunters**](https://github.com/IvanHunters) in #1784). + +* **[monitoring] Enable monitoring for core components**: Enhanced monitoring capabilities with better dashboards and metrics collection for core Cozystack components ([**@IvanHunters**](https://github.com/IvanHunters) in #1937). + +* **[branding] Separate values for Keycloak**: Separated Keycloak branding values for better customization capabilities ([**@nbykov0**](https://github.com/nbykov0) in #1947). + +* **[kubernetes] Use ingress-nginx nodeport service**: Changed Kubernetes managed clusters to use ingress-nginx NodePort service for improved compatibility and flexibility ([**@sircthulhu**](https://github.com/sircthulhu) in #1948). + +## Fixes + +* **[linstor] Extract piraeus-operator CRDs into separate package**: Fixed issue where Helm did not reliably install all CRDs from large crds.yaml files by creating dedicated piraeus-operator-crds package. This ensures the linstorsatellites.io CRD is properly installed, preventing satellite pod creation failures ([**@IvanHunters**](https://github.com/IvanHunters) in #1991). + +* **[platform] Fix cozystack-values secret race condition**: Fixed race condition in cozystack-values secret creation that could cause platform initialization failures ([**@lllamnyp**](https://github.com/lllamnyp) in #2024). + +* **[seaweedfs] Increase certificate duration to 10 years**: Increased SeaweedFS certificate validity from 1 year to 10 years to reduce certificate rotation overhead and prevent unexpected certificate expiration issues ([**@IvanHunters**](https://github.com/IvanHunters) in #1986). + +* **[monitoring] Remove cozystack-controller dependency**: Fixed monitoring package to remove unnecessary dependency on cozystack-controller, allowing monitoring to be installed independently ([**@IvanHunters**](https://github.com/IvanHunters) in #1990). + +* **[monitoring] Remove duplicate dashboards.list from extra/monitoring**: Fixed duplicate dashboards.list configuration in extra/monitoring package ([**@IvanHunters**](https://github.com/IvanHunters) in #2016). + +* **[mongodb] Fix pre-commit check**: Fixed pre-commit linting issues in MongoDB package ([**@kvaps**](https://github.com/kvaps) in #1753). + +* **[mongodb] Update MongoDB logo**: Updated MongoDB application logo in the dashboard to use the correct branding ([**@kvaps**](https://github.com/kvaps) in #2027). + +* **[bootbox] Auto-create bootbox-application as dependency**: Fixed bootbox package to automatically create required bootbox-application dependency ([**@kvaps**](https://github.com/kvaps) in #1974). + +* **[migrations] Add migration 25 for v1.0 upgrade cleanup**: Added migration script to handle cleanup during v1.0 upgrade path ([**@kvaps**](https://github.com/kvaps) in #1975). + +* **[build] Fix platform migrations image build**: Fixed Docker image build process for platform migrations ([**@kvaps**](https://github.com/kvaps) in #1976). + +* **[postgres-operator] Correct PromQL syntax in CNPGClusterOffline alert**: Fixed incorrect PromQL syntax in CNPGClusterOffline Prometheus alert for PostgreSQL clusters ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #1981). + +* **[coredns] Fix serviceaccount to match kubernetes bootstrap RBAC**: Fixed CoreDNS service account configuration to correctly match Kubernetes bootstrap RBAC requirements ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #1958). + +* **[dashboard] Verify JWT token**: Added JWT token verification to dashboard for improved security ([**@lllamnyp**](https://github.com/lllamnyp) in #1980). + +* **[talm] Skip config loading for completion subcommands**: Fixed talm CLI to skip unnecessary config loading for shell completion commands ([**@kitsunoff**](https://github.com/kitsunoff) in [cozystack/talm#109](https://github.com/cozystack/talm/pull/109)). + +## Dependencies + +* **[kube-ovn] Update Kube-OVN to v1.15.3**: Updated Kube-OVN CNI to v1.15.3 with performance improvements and bug fixes ([**@kvaps**](https://github.com/kvaps) in #2022). + +* **[local-ccm] Update to v0.3.0**: Updated local cloud controller manager to v0.3.0 with node-lifecycle-controller support ([**@kvaps**](https://github.com/kvaps) in #1992). + +* **[kilo] Update to v0.7.0**: Updated Kilo to v0.7.0 from cozystack fork with improved MTU handling ([**@kvaps**](https://github.com/kvaps) in #2003). + +## Development, Testing, and CI/CD + +* **[ci] Use GitHub Copilot CLI for changelog generation**: Automated changelog generation using GitHub Copilot CLI to improve release process efficiency ([**@androndo**](https://github.com/androndo) in #1753). + +* **[ci] Choose runner conditional on label**: Added conditional runner selection in CI based on PR labels for more flexible CI/CD workflows ([**@lllamnyp**](https://github.com/lllamnyp) in #1998). + +* **[backups] Add restore jobs controller**: Added controller for managing backup restore jobs ([**@androndo**](https://github.com/androndo) in #1811). + +* **Update CODEOWNERS**: Updated CODEOWNERS file to include new maintainers ([**@lllamnyp**](https://github.com/lllamnyp) in #1972, [**@IvanHunters**](https://github.com/IvanHunters) in #2015). + +## Documentation + +* **[website] Add LINSTOR disk preparation guide**: Added comprehensive documentation for preparing disks for LINSTOR storage system ([**@IvanHunters**](https://github.com/IvanHunters) in [cozystack/website#411](https://github.com/cozystack/website/pull/411)). + +* **[website] Add Proxmox VM migration guide**: Added detailed guide for migrating virtual machines from Proxmox to Cozystack ([**@IvanHunters**](https://github.com/IvanHunters) in [cozystack/website#410](https://github.com/cozystack/website/pull/410)). + +* **[website] Describe operator-based and HelmRelease-based package patterns**: Added development documentation explaining operator-based and HelmRelease-based package patterns for Cozystack ([**@kvaps**](https://github.com/kvaps) in [cozystack/website#413](https://github.com/cozystack/website/pull/413)). + +* **[website] Correct typo in kubeconfig reference in Kubernetes installation guide**: Fixed documentation typo in kubeconfig reference ([**@shkarface**](https://github.com/shkarface) in [cozystack/website#414](https://github.com/cozystack/website/pull/414)). + +* **[website] Check quotas before an upgrade**: Added troubleshooting documentation for checking resource quotas before performing upgrades ([**@nbykov0**](https://github.com/nbykov0) in [cozystack/website#405](https://github.com/cozystack/website/pull/405)). + +--- + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@IvanHunters**](https://github.com/IvanHunters) +* [**@androndo**](https://github.com/androndo) +* [**@kitsunoff**](https://github.com/kitsunoff) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@lllamnyp**](https://github.com/lllamnyp) +* [**@mattia-eleuteri**](https://github.com/mattia-eleuteri) +* [**@nbykov0**](https://github.com/nbykov0) +* [**@shkarface**](https://github.com/shkarface) +* [**@sircthulhu**](https://github.com/sircthulhu) + +--- + +**Full Changelog**: [v1.0.0-beta.2...v1.0.0-beta.3](https://github.com/cozystack/cozystack/compare/v1.0.0-beta.2...v1.0.0-beta.3) diff --git a/docs/changelogs/v1.0.0-beta.4.md b/docs/changelogs/v1.0.0-beta.4.md new file mode 100644 index 00000000..c5694a73 --- /dev/null +++ b/docs/changelogs/v1.0.0-beta.4.md @@ -0,0 +1,96 @@ + + +> **⚠️ Beta Release Warning**: This is a pre-release version intended for testing and early adoption. Breaking changes may occur before the stable v1.0.0 release. + +## Major Features and Improvements + +### Virtual Machines + +* **[vm-instance] Complete migration from virtual-machine to vm-disk and vm-instance**: Completed the architectural redesign of virtual machine management by fully migrating from the legacy `virtual-machine` application to the new `vm-disk` and `vm-instance` applications. This includes automatic migration scripts (migration 28) that convert existing virtual machines, handle CDI webhook configurations, and update cloud-init references. The new architecture provides better separation of concerns between disk management and VM lifecycle, enabling more flexible VM configuration and improved resource management ([**@kvaps**](https://github.com/kvaps) in #2040). + +* **[vm-instance] Port advanced VM features**: Ported critical VM features from the legacy virtual-machine application including cpuModel field for direct CPU model specification, support for switching between instanceType and custom resource configurations, and migration from deprecated `running` field to `runStrategy` field following KubeVirt best practices ([**@kvaps**](https://github.com/kvaps) in #2040). + +### Storage and CSI + +* **[kubevirt-csi-driver] Add RWX Filesystem (NFS) support**: Added Read-Write-Many (RWX) filesystem support to kubevirt-csi-driver, enabling multiple pods to mount the same persistent volume simultaneously via NFS. This provides native NFS support for shared storage use cases without requiring external NFS provisioners, with automatic NFS server deployment per PVC and seamless integration with KubeVirt's storage layer ([**@kvaps**](https://github.com/kvaps) in #2042). + +### Platform and Infrastructure + +* **[cozystack-api] Switch from DaemonSet to Deployment**: Migrated cozystack-api from DaemonSet to Deployment with PreferClose topology spread constraints, improving resource efficiency while maintaining high availability. The Deployment approach reduces resource consumption compared to running API pods on every node, while topology spreading ensures resilient pod placement across the cluster ([**@kvaps**](https://github.com/kvaps) in #2041, #2048). + +* **[linstor] Move CRDs installation to dedicated chart**: Refactored LINSTOR CRDs installation by moving them to a dedicated `piraeus-operator-crds` chart, solving Helm's limitation with large CRD files that could cause unreliable installations. This ensures all LINSTOR CRDs (including linstorsatellites.io) are properly installed before the operator starts, preventing satellite pod creation failures. Includes automatic migration script to reassign existing CRDs to the new chart ([**@kvaps**](https://github.com/kvaps) in #2036). + +* **[installer] Unify operator templates**: Merged separate operator templates into a single variant-based template, simplifying the installation process and reducing configuration duplication. The new template supports different deployment variants (Talos, non-Talos) through a unified configuration approach ([**@kvaps**](https://github.com/kvaps) in #2034). + +### Applications + +* **[mariadb] Rename mysql application to mariadb**: Renamed the MySQL application to MariaDB to accurately reflect the underlying database engine being used. Includes automatic migration script (migration 27) that handles resource renaming and ensures seamless upgrade path for existing MySQL deployments. All resources, including databases, users, backups, and configurations, are automatically migrated to use the mariadb naming ([**@kvaps**](https://github.com/kvaps) in #2026). + +* **[ferretdb] Remove FerretDB application**: Removed the FerretDB application from the catalog as it has been superseded by native MongoDB support with improved performance and features ([**@kvaps**](https://github.com/kvaps) in #2028). + +## Improvements + +* **[rbac] Use hierarchical naming scheme**: Refactored RBAC configuration to use hierarchical naming scheme for cluster roles and role bindings, improving organization and maintainability of permission structures across the platform ([**@lllamnyp**](https://github.com/lllamnyp) in #2019). + +* **[backups] Create RBAC for backup resources**: Added comprehensive RBAC configuration for backup resources, enabling proper permission management for backup operations and restore jobs across different user roles ([**@lllamnyp**](https://github.com/lllamnyp) in #2018). + +* **[etcd-operator] Add vertical-pod-autoscaler dependency**: Added vertical-pod-autoscaler as a dependency to etcd-operator package, ensuring proper resource scaling and optimization for etcd clusters ([**@sircthulhu**](https://github.com/sircthulhu) in #2047). + +## Fixes + +* **[cozystack-operator] Preserve existing suspend field in package reconciler**: Fixed package reconciler to properly preserve the existing suspend field state during reconciliation, preventing unintended resumption of suspended packages ([**@sircthulhu**](https://github.com/sircthulhu) in #2043). + +* **[cozystack-operator] Fix namespace privileged flag resolution**: Fixed operator to correctly resolve namespace privileged flag by checking all Packages in the namespace, not just the first one. This ensures namespaces are properly marked as privileged when any package requires elevated permissions ([**@kvaps**](https://github.com/kvaps) in #2046). + +* **[cozystack-operator] Fix namespace reconciliation field ownership**: Fixed Server-Side Apply (SSA) field ownership conflicts by using per-Package field owner for namespace reconciliation, preventing conflicts when multiple packages reconcile the same namespace ([**@kvaps**](https://github.com/kvaps) in #2046). + +* **[platform] Clean up Helm secrets for removed releases**: Added cleanup logic to migration 23 to remove orphaned Helm secrets from removed -rd releases, preventing secret accumulation and reducing cluster resource usage ([**@kvaps**](https://github.com/kvaps) in #2035). + +* **[monitoring] Fix YAML parse error in vmagent template**: Fixed YAML parsing error in monitoring-agents vmagent template that could cause monitoring stack deployment failures ([**@kvaps**](https://github.com/kvaps) in #2037). + +* **[talm] Fix metadata.id type casting in physical_links_info**: Fixed Prometheus query in physical_links_info chart to properly cast metadata.id to string for regexMatch operations, preventing query failures with numeric interface IDs ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#110). + +## Dependencies + +* **[kilo] Update to v0.7.1**: Updated Kilo WireGuard mesh networking to v0.7.1 with bug fixes and improvements ([**@kvaps**](https://github.com/kvaps) in #2049). + +## Development, Testing, and CI/CD + +* **[ci] Improve cozyreport functionality**: Enhanced cozyreport tool with improved reporting capabilities for CI/CD pipelines, providing better visibility into test results and build status ([**@lllamnyp**](https://github.com/lllamnyp) in #2032). + +* **[e2e] Increase HelmRelease readiness timeout for kubernetes test**: Increased HelmRelease readiness timeout in Kubernetes end-to-end tests to prevent false failures on slower hardware or during high load conditions, specifically targeting ingress-nginx component which may take longer to become ready ([**@lexfrei**](https://github.com/lexfrei) in #2033). + +## Documentation + +* **[website] Add documentation versioning**: Implemented comprehensive documentation versioning system with separate v0 and v1 documentation trees, version selector in the UI, proper URL redirects for unversioned docs, and improved navigation for users working with different Cozystack versions ([**@IvanStukov**](https://github.com/IvanStukov) in cozystack/website#415). + +* **[website] Describe upgrade to v1.0**: Added detailed upgrade instructions for migrating from v0.x to v1.0, including prerequisites, upgrade steps, and troubleshooting guidance ([**@nbykov0**](https://github.com/nbykov0) in cozystack/website@21bbe84). + +* **[website] Update support documentation**: Updated support documentation with current contact information and support channels ([**@xrmtech-isk**](https://github.com/xrmtech-isk) in cozystack/website#420). + +--- + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@IvanStukov**](https://github.com/IvanStukov) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@lllamnyp**](https://github.com/lllamnyp) +* [**@nbykov0**](https://github.com/nbykov0) +* [**@sircthulhu**](https://github.com/sircthulhu) +* [**@xrmtech-isk**](https://github.com/xrmtech-isk) + +### New Contributors + +We're excited to welcome our first-time contributors: + +* [**@IvanStukov**](https://github.com/IvanStukov) - First contribution! +* [**@xrmtech-isk**](https://github.com/xrmtech-isk) - First contribution! + +--- + +**Full Changelog**: [v1.0.0-beta.3...v1.0.0-beta.4](https://github.com/cozystack/cozystack/compare/v1.0.0-beta.3...v1.0.0-beta.4) diff --git a/docs/changelogs/v1.0.0-beta.5.md b/docs/changelogs/v1.0.0-beta.5.md new file mode 100644 index 00000000..b8bc306c --- /dev/null +++ b/docs/changelogs/v1.0.0-beta.5.md @@ -0,0 +1,36 @@ + + +> **⚠️ Beta Release Warning**: This is a pre-release version intended for testing and early adoption. Breaking changes may occur before the stable v1.0.0 release. + +## Features and Improvements + +* **[installer] Add variant-aware templates for generic Kubernetes support**: Extended the installer chart to support generic and hosted Kubernetes deployments via the existing `cozystackOperator.variant` parameter. When using `variant=generic`, the installer now renders separate templates for the Cozystack operator, skipping Talos-specific components. This enables users to deploy Cozystack on standard Kubernetes distributions and hosted Kubernetes services, expanding platform compatibility beyond Talos Linux ([**@lexfrei**](https://github.com/lexfrei) in #2010). + +* **[kilo] Add Cilium compatibility variant**: Added a new `cilium` variant to the kilo PackageSource that deploys kilo with the `--compatibility=cilium` flag. This enables Cilium-aware IPIP encapsulation where the outer packet IP matches the inner packet source, allowing Cilium's network policies to function correctly with kilo's WireGuard mesh networking. Users can now run kilo alongside Cilium CNI while maintaining full network policy enforcement capabilities ([**@kvaps**](https://github.com/kvaps) in #2055). + +* **[cluster-autoscaler] Enable enforce-node-group-min-size by default**: Enabled the `enforce-node-group-min-size` option for the system cluster-autoscaler chart. This ensures node groups are always scaled up to their configured minimum size, even when current workload demands are lower, preventing unexpected scale-down below minimum thresholds and improving cluster stability for production workloads ([**@kvaps**](https://github.com/kvaps) in #2050). + +* **[dashboard] Upgrade dashboard to version 1.4.0**: Updated the Cozystack dashboard to version 1.4.0 with new features and improvements for better user experience and cluster management capabilities ([**@sircthulhu**](https://github.com/sircthulhu) in #2051). + +## Breaking Changes & Upgrade Notes + +* **[vpc] Migrate subnets definition from map to array format**: Migrated VPC subnets definition from map format (`map[string]Subnet`) to array format (`[]Subnet`) with an explicit `name` field. This aligns VPC subnet definitions with the vm-instance `networks` field pattern and provides more intuitive configuration. Existing VPC deployments are automatically migrated via migration 30, which converts the subnet map to an array while preserving all existing subnet configurations and network connectivity ([**@kvaps**](https://github.com/kvaps) in #2052). + +## Dependencies + +* **[kilo] Update to v0.8.0**: Updated Kilo WireGuard mesh networking to v0.8.0 with performance improvements, bug fixes, and new compatibility features ([**@kvaps**](https://github.com/kvaps) in #2053). + +* **[talm] Skip config loading for __complete command**: Fixed CLI completion behavior by skipping config loading for the `__complete` command, preventing errors during shell completion when configuration files are not available or misconfigured ([**@kitsunoff**](https://github.com/kitsunoff) in cozystack/talm#109). + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@kitsunoff**](https://github.com/kitsunoff) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@sircthulhu**](https://github.com/sircthulhu) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.0-beta.4...v1.0.0-beta.5 diff --git a/docs/changelogs/v1.0.0-beta.6.md b/docs/changelogs/v1.0.0-beta.6.md new file mode 100644 index 00000000..99e565d7 --- /dev/null +++ b/docs/changelogs/v1.0.0-beta.6.md @@ -0,0 +1,46 @@ + + +> **⚠️ Beta Release Warning**: This is a pre-release version intended for testing and early adoption. Breaking changes may occur before the stable v1.0.0 release. + +## Features and Improvements + +* **[platform] Add cilium-kilo networking variant**: Added a new `cilium-kilo` networking variant that combines Cilium CNI with Kilo WireGuard mesh overlay. This variant enables `enable-ipip-termination` in Cilium for proper IPIP packet handling and deploys Kilo with `--compatibility=cilium` flag. Users can now select `cilium-kilo` as their networking variant during platform setup, simplifying the multi-location WireGuard setup compared to manually combining Cilium and standalone Kilo ([**@kvaps**](https://github.com/kvaps) in #2064). + +* **[nats] Add monitoring**: Added Grafana dashboards for NATS JetStream and server metrics monitoring, along with Prometheus monitoring support with TLS-aware endpoint configuration. Includes updated image customization options (digest and full image name) and component version upgrades for the NATS exporter and utilities. Users now have full observability into NATS message broker performance and health ([**@klinch0**](https://github.com/klinch0) in #1381). + +* **[platform] Add DNS-1035 validation for Application names**: Added dynamic DNS-1035 label validation for Application names in the Cozystack API, using `IsDNS1035Label` from `k8s.io/apimachinery`. Validation is performed at creation time and accounts for the root host length to prevent names that would exceed Kubernetes resource naming limits. This prevents creation of resources with invalid names that would fail downstream Kubernetes resource creation ([**@lexfrei**](https://github.com/lexfrei) in #1771). + +* **[operator] Add automatic CRD installation at startup**: Added `--install-crds` flag to the Cozystack operator that installs embedded CRD manifests at startup, ensuring CRDs exist before the operator begins reconciliation. CRD manifests are now embedded in the operator binary and verified for consistency with the Helm `crds/` directory via a new CI Makefile check. This eliminates ordering issues during initial cluster setup where CRDs might not yet be present ([**@lexfrei**](https://github.com/lexfrei) in #2060). + +## Fixes + +* **[platform] Adopt tenant-root into cozystack-basics during migration**: Added migration 31 to adopt existing `tenant-root` Namespace and HelmRelease into the `cozystack-basics` Helm release when upgrading from v0.41.x to v1.0. Previously these resources were applied via `kubectl apply` with no Helm release tracking, causing Helm to treat them as foreign resources and potentially delete them during reconciliation. This migration ensures a safe upgrade path by annotating and labeling these resources for Helm adoption ([**@kvaps**](https://github.com/kvaps) in #2065). + +* **[platform] Preserve tenant-root HelmRelease during migration**: Fixed a data-loss risk during migration from v0.41.x to v1.0.0-beta where the `tenant-root` HelmRelease (and the namespace it manages) could be deleted, causing tenant service outages. Added safety annotation to the HelmRelease and lookup logic to preserve current parameters during migration, preventing unwanted deletion of tenant-root resources ([**@sircthulhu**](https://github.com/sircthulhu) in #2063). + +* **[codegen] Add gen_client to update-codegen.sh and regenerate applyconfiguration**: Fixed a build error in `pkg/generated/applyconfiguration/utils.go` caused by a reference to `testing.TypeConverter` which was removed in client-go v0.34.1. The root cause was that `hack/update-codegen.sh` never called `gen_client`, leaving the generated applyconfiguration code stale. Running the full code generation now produces a consistent and compilable codebase ([**@lexfrei**](https://github.com/lexfrei) in #2061). + +* **[e2e] Make kubernetes test retries effective by cleaning up stale resources**: Fixed E2E test retries for the Kubernetes tenant test by adding pre-creation cleanup of backend deployment/service and NFS pod/PVC in `run-kubernetes.sh`. Previously, retries would fail immediately because stale resources from a failed attempt blocked re-creation. Also increased the tenant deployment wait timeout from 90s to 300s to handle CI resource pressure ([**@lexfrei**](https://github.com/lexfrei) in #2062). + +## Development, Testing, and CI/CD + +* **[e2e] Use helm install instead of kubectl apply for cozystack installation**: Replaced the pre-rendered static YAML application flow (`kubectl apply`) with direct `helm upgrade --install` of the `packages/core/installer` chart in E2E tests. Removed the CRD/operator artifact upload/download steps from the CI workflow, simplifying the pipeline. The chart with correct values is already present in the sandbox via workspace copy and `pr.patch` ([**@lexfrei**](https://github.com/lexfrei) in #2060). + +## Documentation + +* **[website] Improve Azure autoscaling troubleshooting guide**: Enhanced the Azure autoscaling troubleshooting documentation with serial console instructions for debugging VMSS worker nodes, a troubleshooting section for nodes stuck in maintenance mode due to invalid or missing machine config, `az vmss update --custom-data` instructions for updating machine config, and a warning that Azure does not support reading back `customData` ([**@kvaps**](https://github.com/kvaps) in cozystack/website#424). + +* **[website] Update multi-location documentation for cilium-kilo variant**: Updated multi-location networking documentation to reflect the new integrated `cilium-kilo` variant selection during platform setup, replacing the previous manual Kilo installation and Cilium configuration steps. Added explanation of `enable-ipip-termination` and updated the troubleshooting section ([**@kvaps**](https://github.com/kvaps) in cozystack/website@02d63f0). + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@klinch0**](https://github.com/klinch0) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@sircthulhu**](https://github.com/sircthulhu) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.0-beta.5...v1.0.0-beta.6 diff --git a/docs/changelogs/v1.0.0-rc.1.md b/docs/changelogs/v1.0.0-rc.1.md new file mode 100644 index 00000000..0fabe1b6 --- /dev/null +++ b/docs/changelogs/v1.0.0-rc.1.md @@ -0,0 +1,65 @@ + + +> **⚠️ Release Candidate Warning**: This is a release candidate intended for final validation before the stable v1.0.0 release. Breaking changes are not expected at this stage, but please test thoroughly before deploying to production. + +## Features and Improvements + +* **[harbor] Add managed Harbor container registry**: Added Harbor v2.14.2 as a managed tenant-level container registry service. The application uses CloudNativePG for PostgreSQL, the Redis operator for caching, and S3 via COSI BucketClaim (from SeaweedFS) for registry image storage. Auto-generated admin credentials are persisted across upgrades, TLS is handled by cert-manager, and Trivy vulnerability scanner is included. Users can now deploy a fully managed, production-ready OCI container registry within their tenant ([**@lexfrei**](https://github.com/lexfrei) in #2058). + +* **[kubernetes] Update supported Kubernetes versions to v1.30–v1.35**: Updated the tenant Kubernetes version matrix to v1.30, v1.31, v1.32, v1.33, v1.34, and v1.35 (now the default). EOL versions v1.28 and v1.29 are removed. Kamaji is updated to edge-26.2.4 with full Kubernetes 1.35 support, and the CAPI Kamaji provider is updated to v0.16.0. A compatibility patch ensures kubelets older than v1.35 are not broken by Kamaji injecting 1.35-specific kubelet fields ([**@lexfrei**](https://github.com/lexfrei) in #2073). + +* **[platform] Make cluster issuer name and ACME solver configurable**: Added `publishing.certificates.solver` (`http01` or `dns01`) and `publishing.certificates.issuerName` (default: `letsencrypt-prod`) parameters to the platform chart. This allows operators to point all ingress TLS annotations at any ClusterIssuer — custom ACME, self-signed, or internal CA — without modifying individual package templates. See the Breaking Changes section for the rename from the previous `issuerType` field ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2077). + +* **[dashboard] VMInstance dropdowns for disks and instanceType**: The VM instance creation form now renders API-backed dropdowns for the `instanceType` field (populated from `VirtualMachineClusterInstancetype` cluster resources) and for disk `name` fields (populated from `VMDisk` resources in the same namespace). Default values are read from the ApplicationDefinition's OpenAPI schema. This eliminates manual lookups and reduces misconfiguration when attaching disks or selecting VM instance types ([**@sircthulhu**](https://github.com/sircthulhu) in #2071). + +* **[installer] Remove CRDs from Helm chart, delegate lifecycle to operator**: The `cozy-installer` Helm chart no longer ships CRDs in its `crds/` directory. CRD lifecycle is now fully managed by the Cozystack operator via the `--install-crds` flag, which applies embedded CRD manifests on every startup using server-side apply. The platform PackageSource is also created by the operator instead of a Helm template. This ensures CRDs and the PackageSource are always up to date after each operator restart, eliminating stale CRDs from Helm's install-only behavior ([**@lexfrei**](https://github.com/lexfrei) in #2074). + +## Fixes + +* **[kubevirt] Update KubeVirt to v1.6.4 and CDI to v1.64.0, fix VM pod initialization**: Updated KubeVirt operator to v1.6.4 and CDI operator to v1.64.0, including live migration of existing VMs during the upgrade. Additionally, disabled serial console logging globally via the KubeVirt CR to prevent a known v1.6.x issue ([upstream #15989](https://github.com/kubevirt/kubevirt/issues/15989)) where the `guest-console-log` init container blocked virt-launcher pods from starting, causing all VMs to get stuck in `PodInitializing` state ([**@nbykov0**](https://github.com/nbykov0) in #1833; [**@kvaps**](https://github.com/kvaps) in 7dfb819). + +* **[linstor] Fix DRBD+LUKS+STORAGE resource creation failure**: All newly created encrypted volumes were failing because the DRBD `.res` file was never written due to a missing `setExists(true)` call in the `LuksLayer`. Applied the upstream `skip-adjust-when-device-inaccessible` patch ([LINBIT/linstor-server#477](https://github.com/LINBIT/linstor-server/pull/477)) which fixes the root cause and also prevents unnecessary lsblk calls when devices are not yet physically present ([**@kvaps**](https://github.com/kvaps) in #2072). + +* **[system] Fix monitoring-agents FQDN resolution for tenant workload clusters**: Monitoring agents (`vmagent`, `fluent-bit`) in tenant workload clusters were failing to deliver metrics and logs because service addresses used short DNS names without the cluster domain suffix. Fixed by appending the configured cluster domain from `_cluster.cluster-domain` (with fallback to `cluster.local`) to all vmagent remoteWrite URLs and fluent-bit output hosts ([**@IvanHunters**](https://github.com/IvanHunters) in #2075). + +* **[cozystack-basics] Preserve existing HelmRelease values during reconciliations**: Fixed a data-loss bug where changes made to the `tenant-root` HelmRelease were silently dropped on the next forced or upgrade reconciliation of the `cozystack-basics` HelmRelease. The reconciler now merges new configuration with existing values instead of overwriting them ([**@sircthulhu**](https://github.com/sircthulhu) in #2068). + +* **[cozystack-basics] Deny resourcequotas deletion for tenant admin**: Fixed the `cozy:tenant:admin:base` ClusterRole to explicitly deny deletion of `ResourceQuota` objects for tenant admins and superadmins, preventing accidental removal of tenant resource limits ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2076). + +## Breaking Changes & Upgrade Notes + +* **[platform] Certificate issuer configuration parameters renamed**: The `publishing.certificates.issuerType` field is renamed to `publishing.certificates.solver`, and the value `cloudflare` is renamed to `dns01` to align with standard ACME terminology. A new `publishing.certificates.issuerName` field (default: `letsencrypt-prod`) is introduced to allow pointing all ingresses at a custom ClusterIssuer. Migration 32 is included and automatically converts existing configurations during upgrade — no manual action is required ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2077). + +## Documentation + +* **[website] Migrate ConfigMap references to Platform Package in v1 documentation**: Updated the entire v1 documentation tree to replace legacy ConfigMap-based configuration references with the new Platform Package API, ensuring guides are consistent with the v1 configuration model ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#426). + +* **[website] Add generic Kubernetes deployment guide for v1**: Added a new installation guide covering Cozystack deployment on any generic Kubernetes cluster, expanding the set of supported deployment targets beyond provider-specific guides ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#408). + +* **[website] Refactor resource planning documentation**: Improved the resource planning guide with a clearer structure and more comprehensive coverage of planning considerations for Cozystack deployments ([**@IvanStukov**](https://github.com/IvanStukov) in cozystack/website#423). + +* **[website] Add ServiceAccount API access documentation and update FAQ**: Added a new article documenting ServiceAccount API access token configuration and updated the FAQ to include related troubleshooting guidance ([**@IvanStukov**](https://github.com/IvanStukov) in cozystack/website#421). + +* **[website] Update networking-mesh allowed-location-ips example**: Replaced provider-specific CLI usage with standard `kubectl` commands in the multi-location networking guide's `allowed-location-ips` example, making the documentation more universally applicable ([**@kvaps**](https://github.com/kvaps) in cozystack/website#425). + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@IvanHunters**](https://github.com/IvanHunters) +* [**@IvanStukov**](https://github.com/IvanStukov) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@myasnikovdaniil**](https://github.com/myasnikovdaniil) +* [**@nbykov0**](https://github.com/nbykov0) +* [**@sircthulhu**](https://github.com/sircthulhu) + +### New Contributors + +We're excited to welcome our first-time contributors: + +* [**@myasnikovdaniil**](https://github.com/myasnikovdaniil) - First contribution! + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.0-beta.6...v1.0.0-rc.1 diff --git a/docs/changelogs/v1.0.0-rc.2.md b/docs/changelogs/v1.0.0-rc.2.md new file mode 100644 index 00000000..a056ff8f --- /dev/null +++ b/docs/changelogs/v1.0.0-rc.2.md @@ -0,0 +1,57 @@ + + +> **⚠️ Release Candidate Warning**: This is a release candidate intended for final validation before the stable v1.0.0 release. Breaking changes are not expected at this stage, but please test thoroughly before deploying to production. + +## Features and Improvements + +* **[keycloak] Allow custom Ingress hostname via values**: Added an `ingress.host` field to the cozy-keycloak chart values, allowing operators to override the default `keycloak.` Ingress hostname. The custom hostname is applied to both the Ingress resource and the `KC_HOSTNAME` environment variable in the StatefulSet. When left empty, the original behavior is preserved (fully backward compatible) ([**@sircthulhu**](https://github.com/sircthulhu) in #2101). + +## Fixes + +* **[platform] Fix upgrade issues in migrations, etcd timeout, and migration script**: Fixed multiple upgrade failures discovered during v0.41.1 → v1.0 upgrade testing. Migration 26 now uses the `cozystack.io/ui=true` label (always present on v0.41.1) instead of the new label that depends on migration 22 having run, and adds robust Helm secret deletion with fallback and verification. Migrations 28 and 29 wrap `grep` calls to prevent `pipefail` exits and fix the reconcile annotation to use RFC3339 format. Migration 27 now skips missing CRDs and adds a name-pattern fallback for Helm secret deletion. The etcd HelmRelease timeout is increased from 10m to 30m to accommodate TLS cert rotation hooks. The `migrate-to-version-1.0.sh` script gains the missing `bundle-disable`, `bundle-enable`, `expose-ingress`, and `expose-services` field mappings ([**@kvaps**](https://github.com/kvaps) in #2096). + +* **[platform] Fix orphaned -rd HelmReleases after application renames**: After the `ferretdb→mongodb`, `mysql→mariadb`, and `virtual-machine→vm-disk+vm-instance` renames, the system-level `-rd` HelmReleases in `cozy-system` (`ferretdb-rd`, `mysql-rd`, `virtual-machine-rd`) were left orphaned, referencing ExternalArtifacts that no longer exist and causing persistent reconciliation failures. Migrations 28 and 29 are updated to remove these resources, and migration 33 is added as a safety net for clusters that already passed those migrations ([**@kvaps**](https://github.com/kvaps) in #2102). + +* **[monitoring-agents] Fix FQDN resolution regression in tenant workload clusters**: The fix introduced in #2075 used `_cluster.cluster-domain` references in `values.yaml`, but `_cluster` values are not accessible from Helm subchart contexts — meaning fluent-bit received empty hostnames and failed to forward logs. This PR replaces the `_cluster` references with a new `global.clusterDomain` variable (empty by default for management clusters, set to the cluster domain for tenant clusters), which is correctly shared with all subcharts ([**@kvaps**](https://github.com/kvaps) in #2086). + +* **[dashboard] Fix legacy templating and cluster identifier in sidebar links**: Standardized the cluster identifier used across dashboard menu links, administration links, and API request paths, resolving incorrect or broken link targets for the Backups and External IPs sidebar sections ([**@androndo**](https://github.com/androndo) in #2093). + +* **[dashboard] Fix backupjobs creation form and sidebar backup category identifier**: Fixed the backup job creation form configuration, adding the required Name, Namespace, Plan Name, Application, and Backup Class fields. Fixed the sidebar backup category identifier that was causing incorrect navigation ([**@androndo**](https://github.com/androndo) in #2103). + +## Documentation + +* **[website] Add Helm chart development principles guide**: Added a new developer guide section documenting Cozystack's four core Helm chart principles: easy upstream updates, local-first artifacts, local dev/test workflow, and no external dependencies ([**@kvaps**](https://github.com/kvaps) in cozystack/website#418). + +* **[website] Add network architecture overview**: Added comprehensive network architecture documentation covering the multi-layered networking stack — MetalLB (L2/BGP), Cilium eBPF (kube-proxy replacement), Kube-OVN (centralized IPAM), and tenant isolation with identity-based eBPF policies — with Mermaid diagrams for all major traffic flows ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/website#422). + +* **[website] Update documentation to use jsonpatch for service exposure**: Improved `kubectl patch` commands throughout installation and configuration guides to use JSON Patch `add` operations for extending arrays instead of replacing them wholesale, making the documented commands safer and more precise ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#427). + +* **[website] Update certificates section in Platform Package documentation**: Updated the certificate configuration documentation to reflect the new `solver` and `issuerName` fields introduced in v1.0.0-rc.1, replacing the legacy `issuerType` references ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#429). + +* **[website] Add tenant Kubernetes cluster log querying guide**: Added documentation for querying logs from tenant Kubernetes clusters in Grafana using VictoriaLogs labels (`tenant`, `kubernetes_namespace_name`, `kubernetes_pod_name`), including the `monitoringAgents` addon prerequisite and step-by-step filtering examples ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/website#430). + +* **[website] Replace non-idempotent commands with idempotent alternatives**: Updated `helm install` to `helm upgrade --install`, `kubectl create -f` to `kubectl apply -f`, and `kubectl create ns` to the dry-run+apply pattern across all installation and deployment guides so commands can be safely re-run ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#431). + +* **[website] Fix broken documentation links with `.md` suffix**: Fixed incorrect internal links with `.md` suffix across virtualization guides for both v0 and v1 documentation, standardizing link text to "Developer Guide" ([**@cheese**](https://github.com/cheese) in cozystack/website#432). + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@androndo**](https://github.com/androndo) +* [**@cheese**](https://github.com/cheese) +* [**@IvanHunters**](https://github.com/IvanHunters) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@myasnikovdaniil**](https://github.com/myasnikovdaniil) +* [**@sircthulhu**](https://github.com/sircthulhu) + +### New Contributors + +We're excited to welcome our first-time contributors: + +* [**@cheese**](https://github.com/cheese) - First contribution! + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.0-rc.1...v1.0.0-rc.2 diff --git a/docs/changelogs/v1.0.0.md b/docs/changelogs/v1.0.0.md new file mode 100644 index 00000000..469ea1db --- /dev/null +++ b/docs/changelogs/v1.0.0.md @@ -0,0 +1,289 @@ + + +# Cozystack v1.0.0 — "Stable" + +We are thrilled to announce **Cozystack v1.0.0**, the first stable major release of the Cozystack platform. This milestone represents a fundamental architectural evolution from the v0.x series, introducing a fully operator-driven package management system, a comprehensive backup and restore framework, a redesigned virtual machine architecture, and a rich set of new managed applications — all hardened through an extensive alpha, beta, and release-candidate cycle. + +## Feature Highlights + +### Package-Based Architecture with Cozystack Operator + +The most significant architectural change in v1.0.0 is the replacement of HelmRelease bundle deployments with a declarative **Package** and **PackageSource** model managed by the new `cozystack-operator`. Operators now define their platform configuration in a structured `values.yaml` and the operator reconciles the desired state by managing Package and PackageSource resources across the cluster. + +The operator also takes ownership of CRD lifecycle — installing and updating CRDs from embedded manifests at every startup — eliminating the stale-CRD problem that affected Helm-only installations. Flux sharding has been added to distribute tenant HelmRelease reconciliation across multiple Flux controllers, providing horizontal scalability in large multi-tenant environments. + +A migration script (`hack/migrate-to-version-1.0.sh`) is provided for upgrading existing v0.x clusters, along with 33 incremental migration steps that automate resource renaming, secret cleanup, and configuration conversion. + +### Comprehensive Backup and Restore System + +v1.0.0 ships a fully featured, production-ready backup and restore framework built on Velero integration. Users can define **BackupClass** resources to describe backup storage targets, create **BackupPlan** schedules, and trigger **RestoreJob** resources for end-to-end application recovery. + +Virtual machine backups are supported natively via the Velero KubeVirt plugin, which captures consistent VM disk snapshots alongside metadata. The backup controller and the backup strategy sub-controllers (including the VM-specific strategy) are installed by default, and a full dashboard UI allows users to monitor backup status, view backup job history, and initiate restore workflows. + +### Redesigned Virtual Machine Architecture + +The legacy `virtual-machine` application has been replaced with a two-resource architecture: **`vm-disk`** for managing persistent disks and **`vm-instance`** for managing VM lifecycle. This separation provides cleaner disk/instance management, allows disks to be reused across VM instances, and aligns with modern KubeVirt patterns. + +New capabilities include: a `cpuModel` field for direct CPU model specification without using an instanceType; the ability to switch between `instanceType`-based and custom resource-based configurations; migration from the deprecated `running` field to `runStrategy`; and native **RWX (NFS) filesystem support** in the KubeVirt CSI driver, enabling multiple pods to mount the same persistent volume simultaneously. + +### New Managed Applications + +v1.0.0 expands the application catalog significantly: + +- **MongoDB**: A fully managed MongoDB replica set with persistent storage, monitoring integration, and unified user/database configuration API. +- **Qdrant**: A high-performance vector database for AI and machine learning workloads, supporting single-replica and clustered modes with API key authentication and optional external LoadBalancer access. +- **Harbor**: A fully managed OCI container registry backed by CloudNativePG, Redis operator, and COSI BucketClaim (SeaweedFS). Includes Trivy vulnerability scanner, auto-generated admin credentials, and TLS via cert-manager. +- **NATS**: Enhanced with full Grafana monitoring dashboards for JetStream and server metrics, Prometheus support with TLS-aware configuration, and updated image customization options. +- **MariaDB**: The `mysql` application is renamed to `mariadb`, accurately reflecting the underlying engine. An automatic migration (migration 27) converts all existing MySQL resources to use the `mariadb` naming. + +FerretDB has been removed from the catalog as it is superseded by native MongoDB support. + +### Multi-Location Networking with Kilo and cilium-kilo + +Cozystack v1.0.0 introduces first-class support for multi-location clusters via the **Kilo** WireGuard mesh networking package. Kilo automatically establishes encrypted WireGuard tunnels between nodes in different network segments, enabling seamless cross-region communication. + +A new integrated **`cilium-kilo`** networking variant combines Cilium eBPF CNI with Kilo's WireGuard overlay in a single platform configuration selection. This variant enables `enable-ipip-termination` in Cilium and deploys Kilo with `--compatibility=cilium`, allowing Cilium network policies to function correctly over the WireGuard mesh — without any manual configuration of the two components. + +### Flux Sharding for Scalable Multi-Tenancy + +Tenant HelmRelease reconciliation is now distributed across multiple Flux controllers via sharding labels. Each tenant workload is assigned to a shard based on a deterministic hash, preventing a single Flux controller from becoming a bottleneck in large multi-tenant environments. The platform operator manages the shard assignment automatically, and new shards can be added by scaling the Flux deployment. + +## Major Features and Improvements + +### Cozystack Operator + +* **[cozystack-operator] Introduce Package and PackageSource APIs**: Added new CRDs for declarative package management, defining the full API for Package and PackageSource resources ([**@kvaps**](https://github.com/kvaps) in #1740, #1741, #1755, #1756, #1760, #1761). +* **[platform] Migrate from HelmRelease bundles to Package-based deployment**: Replaced HelmRelease bundle system with Package resources managed by cozystack-operator, including restructured values.yaml with full configuration support for networking, publishing, authentication, scheduling, branding, and resources ([**@kvaps**](https://github.com/kvaps) in #1816). +* **[cozystack-operator] Add automatic CRD installation at startup**: Added `--install-crds` flag to install embedded CRD manifests on every startup via server-side apply, ensuring CRDs and the PackageSource are always up to date ([**@lexfrei**](https://github.com/lexfrei) in #2060). +* **[installer] Remove CRDs from Helm chart, delegate lifecycle to operator**: The `cozy-installer` Helm chart no longer ships CRDs; CRD lifecycle is fully managed by the Cozystack operator ([**@lexfrei**](https://github.com/lexfrei) in #2074). +* **[cozystack-operator] Preserve existing suspend field in package reconciler**: Fixed package reconciler to properly preserve the suspend field state during reconciliation ([**@sircthulhu**](https://github.com/sircthulhu) in #2043). +* **[cozystack-operator] Fix namespace privileged flag resolution and field ownership**: Fixed operator to correctly check all Packages in a namespace when determining privileged status, and resolved SSA field ownership conflicts ([**@kvaps**](https://github.com/kvaps) in #2046). +* **[platform] Add flux-plunger controller**: Added flux-plunger controller to automatically fix stuck HelmRelease errors by cleaning up failed resources and retrying reconciliation ([**@kvaps**](https://github.com/kvaps) in #1843). +* **[installer] Add variant-aware templates for generic Kubernetes support**: Extended the installer to support generic and hosted Kubernetes deployments via the `cozystackOperator.variant=generic` parameter ([**@lexfrei**](https://github.com/lexfrei) in #2010). +* **[installer] Unify operator templates**: Merged separate operator templates into a single variant-based template supporting Talos and non-Talos deployments ([**@kvaps**](https://github.com/kvaps) in #2034). + +### API and Platform + +* **[api] Rename CozystackResourceDefinition to ApplicationDefinition**: Renamed CRD and all related types for clarity and consistency, with migration 24 handling the transition automatically ([**@kvaps**](https://github.com/kvaps) in #1864). +* **[platform] Add DNS-1035 validation for Application names**: Added dynamic DNS-1035 label validation for Application names at creation time, preventing resources with invalid names that would fail downstream ([**@lexfrei**](https://github.com/lexfrei) in #1771). +* **[platform] Make cluster issuer name and ACME solver configurable**: Added `publishing.certificates.solver` and `publishing.certificates.issuerName` parameters to allow pointing all ingress TLS annotations at any ClusterIssuer ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2077). +* **[platform] Add cilium-kilo networking variant**: Added integrated `cilium-kilo` networking variant combining Cilium CNI with Kilo WireGuard mesh overlay ([**@kvaps**](https://github.com/kvaps) in #2064). +* **[cozystack-api] Switch from DaemonSet to Deployment**: Migrated cozystack-api to a Deployment with PreferClose topology spread constraints, reducing resource consumption while maintaining high availability ([**@kvaps**](https://github.com/kvaps) in #2041, #2048). + +### Virtual Machines + +* **[vm-instance] Complete migration from virtual-machine to vm-disk and vm-instance**: Fully migrated from `virtual-machine` to the new `vm-disk` and `vm-instance` architecture, with automatic migration script (migration 28) for existing VMs ([**@kvaps**](https://github.com/kvaps) in #2040). +* **[kubevirt-csi-driver] Add RWX Filesystem (NFS) support**: Added Read-Write-Many filesystem support to kubevirt-csi-driver via automatic NFS server deployment per PVC ([**@kvaps**](https://github.com/kvaps) in #2042). +* **[vm] Add cpuModel field to specify CPU model without instanceType**: Added cpuModel field to VirtualMachine API for granular CPU control ([**@sircthulhu**](https://github.com/sircthulhu) in #2007). +* **[vm] Allow switching between instancetype and custom resources**: Implemented atomic upgrade hook for switching between instanceType-based and custom resource VM configurations ([**@sircthulhu**](https://github.com/sircthulhu) in #2008). +* **[vm] Migrate to runStrategy instead of running**: Migrated VirtualMachine API from deprecated `running` field to `runStrategy` ([**@sircthulhu**](https://github.com/sircthulhu) in #2004). +* **[vm] Always expose VMs with a service**: Virtual machines are now always exposed with at least a ClusterIP service, ensuring in-cluster DNS names ([**@lllamnyp**](https://github.com/lllamnyp) in #1738, #1751). +* **[dashboard] VMInstance dropdowns for disks and instanceType**: VM instance creation form now renders API-backed dropdowns for `instanceType` and disk `name` fields ([**@sircthulhu**](https://github.com/sircthulhu) in #2071). + +### Backup System + +* **[backups] Implement comprehensive backup and restore functionality**: Core backup Plan controller, Velero strategy controller, RestoreJob resource with end-to-end restore workflows, and enhanced backup plans UI ([**@lllamnyp**](https://github.com/lllamnyp) in #1640, #1685, #1687, #1719, #1720, #1737, #1967; [**@androndo**](https://github.com/androndo) in #1762, #1967, #1968, #1811). +* **[backups] Add kubevirt plugin to velero**: Added KubeVirt plugin to Velero for consistent VM state and data snapshots ([**@lllamnyp**](https://github.com/lllamnyp) in #2017). +* **[backups] Install backupstrategy controller by default**: Enabled backupstrategy controller by default for automatic backup scheduling ([**@lllamnyp**](https://github.com/lllamnyp) in #2020). +* **[backups] Better selectors for VM strategy**: Improved VM backup strategy selectors for accurate and reliable backup targeting ([**@lllamnyp**](https://github.com/lllamnyp) in #2023). +* **[backups] Create RBAC for backup resources**: Added comprehensive RBAC configuration for backup operations and restore jobs ([**@lllamnyp**](https://github.com/lllamnyp) in #2018). + +### Networking + +* **[kilo] Introduce Kilo WireGuard mesh networking**: Added Kilo as a system package providing secure WireGuard-based VPN mesh for connecting Kubernetes nodes across different networks and regions ([**@kvaps**](https://github.com/kvaps) in #1691). +* **[kilo] Add Cilium compatibility variant**: Added `cilium` variant enabling Cilium-aware IPIP encapsulation for full network policy enforcement with Kilo mesh ([**@kvaps**](https://github.com/kvaps) in #2055). +* **[kilo] Update to v0.8.0 with configurable MTU**: Updated Kilo to v0.8.0 with configurable MTU parameter and performance improvements ([**@kvaps**](https://github.com/kvaps) in #2003, #2049, #2053). +* **[local-ccm] Add local-ccm package**: Added local cloud controller manager for managing load balancer services in bare-metal environments ([**@kvaps**](https://github.com/kvaps) in #1831). +* **[local-ccm] Add node-lifecycle-controller component**: Added optional node-lifecycle-controller that automatically deletes unreachable NotReady nodes, solving the "zombie" node problem in autoscaled clusters ([**@IvanHunters**](https://github.com/IvanHunters) in #1992). +* **[tenant] Allow egress to parent ingress pods**: Updated tenant network policies to allow egress traffic to parent cluster ingress pods ([**@lexfrei**](https://github.com/lexfrei) in #1765, #1776). + +### New Applications + +* **[mongodb] Add MongoDB managed application**: Added MongoDB as a fully managed database with replica sets, persistent storage, and unified user/database configuration ([**@lexfrei**](https://github.com/lexfrei) in #1822; [**@kvaps**](https://github.com/kvaps) in #1923). +* **[qdrant] Add Qdrant vector database**: Added Qdrant as a high-performance vector database for AI/ML workloads with API key authentication and optional LoadBalancer access ([**@lexfrei**](https://github.com/lexfrei) in #1987). +* **[harbor] Add managed Harbor container registry**: Added Harbor v2.14.2 as a managed tenant-level container registry with CloudNativePG, Redis operator, COSI BucketClaim storage, and Trivy scanner ([**@lexfrei**](https://github.com/lexfrei) in #2058). +* **[nats] Add monitoring**: Added Grafana dashboards for NATS JetStream and server metrics, Prometheus monitoring with TLS support ([**@klinch0**](https://github.com/klinch0) in #1381). +* **[mariadb] Rename mysql application to mariadb**: Renamed MySQL application to MariaDB with automatic migration (migration 27) for all existing resources ([**@kvaps**](https://github.com/kvaps) in #2026). +* **[ferretdb] Remove FerretDB application**: Removed FerretDB, superseded by native MongoDB support ([**@kvaps**](https://github.com/kvaps) in #2028). + +### Kubernetes and System Components + +* **[kubernetes] Update supported Kubernetes versions to v1.30–v1.35**: Updated the tenant Kubernetes version matrix, with v1.35 as the new default. Kamaji updated to edge-26.2.4 and CAPI Kamaji provider to v0.16.0 ([**@lexfrei**](https://github.com/lexfrei) in #2073). +* **[kubernetes] Auto-enable Gateway API support in cert-manager**: Added automatic Gateway API support in cert-manager for tenant clusters ([**@kvaps**](https://github.com/kvaps) in #1997). +* **[kubernetes] Use ingress-nginx nodeport service**: Changed tenant Kubernetes clusters to use ingress-nginx NodePort service for improved compatibility ([**@sircthulhu**](https://github.com/sircthulhu) in #1948). +* **[system] Add cluster-autoscaler for Hetzner and Azure**: Added cluster-autoscaler system package for automatically scaling management cluster nodes on Hetzner and Azure ([**@kvaps**](https://github.com/kvaps) in #1964). +* **[cluster-autoscaler] Enable enforce-node-group-min-size by default**: Ensures node groups are always scaled up to their configured minimum size ([**@kvaps**](https://github.com/kvaps) in #2050). +* **[system] Add clustersecret-operator package**: Added clustersecret-operator for managing secrets across multiple namespaces ([**@sircthulhu**](https://github.com/sircthulhu) in #2025). + +### Monitoring + +* **[monitoring] Enable monitoring for core components**: Enhanced monitoring capabilities with dashboards and metrics for core Cozystack components ([**@IvanHunters**](https://github.com/IvanHunters) in #1937). +* **[monitoring] Add SLACK_SEVERITY_FILTER and VMAgent for tenant monitoring**: Added SLACK_SEVERITY_FILTER for Slack alert filtering and VMAgent for tenant namespace metrics scraping ([**@IvanHunters**](https://github.com/IvanHunters) in #1712). +* **[monitoring-agents] Fix FQDN resolution for tenant workload clusters**: Fixed monitoring agents in tenant clusters to use full DNS names with cluster domain suffix ([**@IvanHunters**](https://github.com/IvanHunters) in #2075; [**@kvaps**](https://github.com/kvaps) in #2086). + +### Storage + +* **[linstor] Move CRDs to dedicated piraeus-operator-crds chart**: Moved LINSTOR CRDs to a dedicated chart, ensuring reliable installation of all CRDs including `linstorsatellites.io` ([**@kvaps**](https://github.com/kvaps) in #2036; [**@IvanHunters**](https://github.com/IvanHunters) in #1991). +* **[seaweedfs] Increase certificate duration to 10 years**: Increased SeaweedFS certificate validity to 10 years to reduce rotation overhead ([**@IvanHunters**](https://github.com/IvanHunters) in #1986). + +## Improvements + +* **[dashboard] Upgrade dashboard to version 1.4.0**: Updated Cozystack dashboard to v1.4.0 with new features and improvements ([**@sircthulhu**](https://github.com/sircthulhu) in #2051). +* **[dashboard] Hide Ingresses/Services/Secrets tabs when no selectors defined**: Tabs are now conditionally shown based on whether the ApplicationDefinition has resource selectors configured, reducing UI clutter ([**@kvaps**](https://github.com/kvaps) in #2087). +* **[dashboard] Add startupProbe to prevent container restarts on slow hardware**: Added startup probe to dashboard pods to prevent unnecessary restarts ([**@kvaps**](https://github.com/kvaps) in #1996). +* **[keycloak] Allow custom Ingress hostname via values**: Added `ingress.host` field to cozy-keycloak chart values for overriding the default `keycloak.` hostname ([**@sircthulhu**](https://github.com/sircthulhu) in #2101). +* **[branding] Separate values for Keycloak**: Separated Keycloak branding values for better customization capabilities ([**@nbykov0**](https://github.com/nbykov0) in #1947). +* **[rbac] Use hierarchical naming scheme**: Refactored RBAC to use hierarchical naming for cluster roles and role bindings ([**@lllamnyp**](https://github.com/lllamnyp) in #2019). +* **[tenant,rbac] Use shared clusterroles**: Refactored tenant RBAC to use shared ClusterRoles for improved consistency ([**@lllamnyp**](https://github.com/lllamnyp) in #1999). +* **[kubernetes] Increase default apiServer resourcesPreset to large**: Increased kube-apiserver resource preset to `large` for more reliable operation under higher workloads ([**@kvaps**](https://github.com/kvaps) in #1875). +* **[kubernetes] Increase kube-apiserver startup probe threshold**: Increased startup probe threshold to allow more time for API server readiness ([**@kvaps**](https://github.com/kvaps) in #1876). +* **[etcd] Increase probe thresholds for better recovery**: Increased etcd probe thresholds to improve cluster resilience during temporary slowdowns ([**@kvaps**](https://github.com/kvaps) in #1874). +* **[etcd-operator] Add vertical-pod-autoscaler dependency**: Added VPA as a dependency to etcd-operator for proper resource scaling ([**@sircthulhu**](https://github.com/sircthulhu) in #2047). +* **[cilium] Change cilium-operator replicas to 1**: Reduced Cilium operator replicas to decrease resource consumption in smaller deployments ([**@IvanHunters**](https://github.com/IvanHunters) in #1784). +* **[keycloak-configure,dashboard] Enable insecure TLS verification by default**: Made SSL certificate verification configurable with insecure mode enabled by default for local development ([**@IvanHunters**](https://github.com/IvanHunters) in #2005). +* **[platform] Split telemetry between operator and controller**: Separated telemetry collection for better metrics isolation ([**@kvaps**](https://github.com/kvaps) in #1869). +* **[system] Add resource requests and limits to etcd-defrag**: Added resource requests and limits to etcd-defrag job to prevent resource contention ([**@matthieu-robin**](https://github.com/matthieu-robin) in #1785, #1786). + +## Fixes + +* **[dashboard] Fix sidebar visibility on cluster-level pages**: Fixed broken URLs with double `//` on cluster-level pages by hiding namespace-scoped sidebar items when no tenant is selected ([**@sircthulhu**](https://github.com/sircthulhu) in #2106). +* **[platform] Fix upgrade issues in migrations, etcd timeout, and migration script**: Fixed multiple upgrade failures discovered during v0.41.1 → v1.0 upgrade testing, including migration 26-29 fixes, RFC3339 format for annotations, and extended etcd HelmRelease timeout to 30m ([**@kvaps**](https://github.com/kvaps) in #2096). +* **[platform] Fix orphaned -rd HelmReleases after application renames**: Migrations 28-29 updated to remove orphaned `-rd` HelmReleases in `cozy-system` after `ferretdb→mongodb`, `mysql→mariadb`, and `virtual-machine→vm-disk+vm-instance` renames, with migration 33 as a safety net ([**@kvaps**](https://github.com/kvaps) in #2102). +* **[platform] Adopt tenant-root into cozystack-basics during migration**: Added migration 31 to adopt existing `tenant-root` Namespace and HelmRelease into `cozystack-basics` for a safe v0.41.x → v1.0 upgrade path ([**@kvaps**](https://github.com/kvaps) in #2065). +* **[platform] Preserve tenant-root HelmRelease during migration**: Fixed data-loss risk during migration where `tenant-root` HelmRelease could be deleted ([**@sircthulhu**](https://github.com/sircthulhu) in #2063). +* **[platform] Fix cozystack-values secret race condition**: Fixed race condition in cozystack-values secret creation that could cause initialization failures ([**@lllamnyp**](https://github.com/lllamnyp) in #2024). +* **[cozystack-basics] Preserve existing HelmRelease values during reconciliations**: Fixed data-loss bug where changes to `tenant-root` HelmRelease were dropped on the next reconciliation ([**@sircthulhu**](https://github.com/sircthulhu) in #2068). +* **[cozystack-basics] Deny resourcequotas deletion for tenant admin**: Fixed `cozy:tenant:admin:base` ClusterRole to explicitly deny deletion of ResourceQuota objects ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2076). +* **[dashboard] Fix legacy templating and cluster identifier in sidebar links**: Standardized cluster identifier across dashboard menu links resolving broken link targets for Backups and External IPs ([**@androndo**](https://github.com/androndo) in #2093). +* **[dashboard] Fix backupjobs creation form and sidebar backup category identifier**: Fixed backup job creation form fields and fixed sidebar backup category identifier ([**@androndo**](https://github.com/androndo) in #2103). +* **[kubevirt] Update KubeVirt to v1.6.4 and CDI to v1.64.0, fix VM pod initialization**: Updated KubeVirt and CDI and disabled serial console logging globally to fix the `guest-console-log` init container blocking virt-launcher pods ([**@nbykov0**](https://github.com/nbykov0) in #1833; [**@kvaps**](https://github.com/kvaps)). +* **[linstor] Fix DRBD+LUKS+STORAGE resource creation failure**: Applied upstream fix for all newly created encrypted volumes failing due to missing `setExists(true)` call in `LuksLayer` ([**@kvaps**](https://github.com/kvaps) in #2072). +* **[platform] Clean up Helm secrets for removed releases**: Added cleanup logic to migration 23 to remove orphaned Helm secrets from removed `-rd` releases ([**@kvaps**](https://github.com/kvaps) in #2035). +* **[monitoring] Fix YAML parse error in vmagent template**: Fixed YAML parsing error in monitoring-agents vmagent template ([**@kvaps**](https://github.com/kvaps) in #2037). +* **[monitoring] Remove cozystack-controller dependency**: Fixed monitoring package to remove unnecessary cozystack-controller dependency ([**@IvanHunters**](https://github.com/IvanHunters) in #1990). +* **[monitoring] Remove duplicate dashboards.list**: Fixed duplicate dashboards.list configuration in extra/monitoring package ([**@IvanHunters**](https://github.com/IvanHunters) in #2016). +* **[linstor] Update piraeus-server patches with critical fixes**: Backported critical patches fixing edge cases in device management and DRBD resource handling ([**@kvaps**](https://github.com/kvaps) in #1850). +* **[apiserver] Fix Watch resourceVersion and bookmark handling**: Fixed Watch API handling of resourceVersion and bookmarks for proper event streaming ([**@kvaps**](https://github.com/kvaps) in #1860). +* **[bootbox] Auto-create bootbox-application as dependency**: Fixed bootbox package to automatically create required bootbox-application dependency ([**@kvaps**](https://github.com/kvaps) in #1974). +* **[postgres-operator] Correct PromQL syntax in CNPGClusterOffline alert**: Fixed incorrect PromQL syntax in the CNPGClusterOffline Prometheus alert ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #1981). +* **[coredns] Fix serviceaccount to match kubernetes bootstrap RBAC**: Fixed CoreDNS service account to correctly match Kubernetes bootstrap RBAC requirements ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #1958). +* **[dashboard] Verify JWT token**: Added JWT token verification to dashboard for improved security ([**@lllamnyp**](https://github.com/lllamnyp) in #1980). +* **[codegen] Fix missing gen_client in update-codegen.sh**: Fixed build error in `pkg/generated/applyconfiguration/utils.go` by including `gen_client` in the codegen script ([**@lexfrei**](https://github.com/lexfrei) in #2061). +* **[kubevirt-operator] Fix typo in VMNotRunningFor10Minutes alert**: Fixed typo in VM alert name ensuring proper alert triggering ([**@lexfrei**](https://github.com/lexfrei) in #1770, #1775). + +## Security + +* **[dashboard] Verify JWT token**: Added JWT token verification to the dashboard for improved authentication security ([**@lllamnyp**](https://github.com/lllamnyp) in #1980). + +## Dependencies + +* **[cilium] Update to v1.18.6**: Updated Cilium CNI to v1.18.6 with security fixes and performance improvements ([**@sircthulhu**](https://github.com/sircthulhu) in #1868). +* **[kube-ovn] Update to v1.15.3**: Updated Kube-OVN CNI to v1.15.3 with performance improvements and bug fixes ([**@kvaps**](https://github.com/kvaps) in #2022). +* **[kilo] Update to v0.8.0**: Updated Kilo WireGuard mesh to v0.8.0 with performance improvements and new compatibility features ([**@kvaps**](https://github.com/kvaps) in #2053). +* **Update Talos Linux to v1.12.1**: Updated Talos Linux to v1.12.1 with latest features and security patches ([**@kvaps**](https://github.com/kvaps) in #1877). + +## System Configuration + +* **[vpc] Migrate subnets definition from map to array format**: Migrated VPC subnets from `map[string]Subnet` to `[]Subnet` with explicit `name` field, with automatic migration via migration 30 ([**@kvaps**](https://github.com/kvaps) in #2052). +* **[migrations] Add migrations 23-33 for v1.0 upgrade path**: Added 11 incremental migrations handling CRD ownership, resource renaming, secret cleanup, Helm adoption, and configuration conversion for the v0.41.x → v1.0.0 upgrade path ([**@kvaps**](https://github.com/kvaps) in #1975, #2035, #2036, #2040, #2026, #2065, #2052, #2102). +* **[tenant] Run cleanup job from system namespace**: Moved tenant cleanup job to system namespace for improved security and resource isolation ([**@lllamnyp**](https://github.com/lllamnyp) in #1774, #1777). + +## Development, Testing, and CI/CD + +* **[ci] Use GitHub Copilot CLI for changelog generation**: Automated changelog generation using GitHub Copilot CLI ([**@androndo**](https://github.com/androndo) in #1753). +* **[ci] Choose runner conditional on label**: Added conditional runner selection in CI based on PR labels ([**@lllamnyp**](https://github.com/lllamnyp) in #1998). +* **[e2e] Use helm install instead of kubectl apply for cozystack installation**: Replaced static YAML apply flow with direct `helm upgrade --install` of the installer chart in E2E tests ([**@lexfrei**](https://github.com/lexfrei) in #2060). +* **[e2e] Make kubernetes test retries effective by cleaning up stale resources**: Fixed E2E test retries by adding pre-creation cleanup and increasing deployment wait timeout to 300s ([**@lexfrei**](https://github.com/lexfrei) in #2062). +* **[e2e] Increase HelmRelease readiness timeout for kubernetes test**: Increased HelmRelease readiness timeout to prevent false failures on slower hardware ([**@lexfrei**](https://github.com/lexfrei) in #2033). +* **[ci] Improve cozyreport functionality**: Enhanced cozyreport tool with improved reporting for CI/CD pipelines ([**@lllamnyp**](https://github.com/lllamnyp) in #2032). +* **feat(cozypkg): add cross-platform build targets with version injection**: Added cross-platform build targets for cozypkg/cozyhr tool for linux/amd64, linux/arm64, darwin/amd64, darwin/arm64 ([**@kvaps**](https://github.com/kvaps) in #1862). +* **refactor: move scripts to hack directory**: Reorganized scripts to the standard `hack/` location ([**@kvaps**](https://github.com/kvaps) in #1863). +* **Update CODEOWNERS**: Updated CODEOWNERS to include new maintainers ([**@lllamnyp**](https://github.com/lllamnyp) in #1972; [**@IvanHunters**](https://github.com/IvanHunters) in #2015). +* **[talm] Skip config loading for completion subcommands**: Fixed talm CLI to skip config loading for shell completion commands ([**@kitsunoff**](https://github.com/kitsunoff) in cozystack/talm#109). +* **[talm] Fix metadata.id type casting in physical_links_info**: Fixed Prometheus query to properly cast metadata.id to string for regexMatch operations ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#110). + +## Documentation + +* **[website] Add documentation versioning**: Implemented comprehensive documentation versioning with separate v0 and v1 documentation trees and a version selector in the UI ([**@IvanStukov**](https://github.com/IvanStukov) in cozystack/website#415). +* **[website] Describe upgrade to v1.0**: Added detailed upgrade instructions for migrating from v0.x to v1.0 ([**@nbykov0**](https://github.com/nbykov0) in cozystack/website@21bbe84). +* **[website] Migrate ConfigMap references to Platform Package in v1 docs**: Updated entire v1 documentation to replace legacy ConfigMap-based configuration with the new Platform Package API ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#426). +* **[website] Add generic Kubernetes deployment guide for v1**: Added installation guide for deploying Cozystack on any generic Kubernetes cluster ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#408). +* **[website] Describe operator-based and HelmRelease-based package patterns**: Added development documentation explaining operator-based and HelmRelease-based package patterns ([**@kvaps**](https://github.com/kvaps) in cozystack/website#413). +* **[website] Add Helm chart development principles guide**: Added developer guide documenting Cozystack's four core Helm chart principles ([**@kvaps**](https://github.com/kvaps) in cozystack/website#418). +* **[website] Add network architecture overview**: Added comprehensive network architecture documentation covering the multi-layered networking stack with Mermaid diagrams ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/website#422). +* **[website] Add LINSTOR disk preparation guide**: Added comprehensive documentation for preparing disks for LINSTOR storage ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/website#411). +* **[website] Add Proxmox VM migration guide**: Added detailed guide for migrating virtual machines from Proxmox to Cozystack ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/website#410). +* **[website] Add cluster autoscaler documentation**: Added documentation for Hetzner setup with Talos, vSwitch, and Kilo mesh integration ([**@kvaps**](https://github.com/kvaps) in #1964). +* **[website] Improve Azure autoscaling troubleshooting guide**: Enhanced Azure autoscaling documentation with serial console instructions and `az vmss update --custom-data` guidance ([**@kvaps**](https://github.com/kvaps) in cozystack/website#424). +* **[website] Update multi-location documentation for cilium-kilo variant**: Updated multi-location networking docs to reflect the integrated `cilium-kilo` variant selection ([**@kvaps**](https://github.com/kvaps) in cozystack/website@02d63f0). +* **[website] Update documentation to use jsonpatch for service exposure**: Improved `kubectl patch` commands to use JSON Patch `add` operations ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#427). +* **[website] Update certificates section in Platform Package documentation**: Updated certificate configuration docs to reflect new `solver` and `issuerName` fields ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#429). +* **[website] Add tenant Kubernetes cluster log querying guide**: Added documentation for querying logs from tenant clusters in Grafana using VictoriaLogs labels ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/website#430). +* **[website] Replace non-idempotent commands with idempotent alternatives**: Updated `helm install` to `helm upgrade --install` and `kubectl create` to `kubectl apply` across all installation guides ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#431). +* **[website] Fix broken documentation links with .md suffix**: Fixed incorrect internal links across virtualization guides for v0 and v1 documentation ([**@cheese**](https://github.com/cheese) in cozystack/website#432). +* **[website] Refactor resource planning documentation**: Improved resource planning guide with clearer structure and more comprehensive coverage ([**@IvanStukov**](https://github.com/IvanStukov) in cozystack/website#423). +* **[website] Add ServiceAccount API access documentation and update FAQ**: Added documentation for ServiceAccount API access token configuration and updated FAQ ([**@IvanStukov**](https://github.com/IvanStukov) in cozystack/website#421). +* **[website] Update networking-mesh allowed-location-ips example**: Replaced provider-specific CLI with standard `kubectl` commands in multi-location networking guide ([**@kvaps**](https://github.com/kvaps) in cozystack/website#425). +* **[website] docs(storage): simplify NFS driver setup instructions**: Simplified NFS driver setup documentation ([**@kvaps**](https://github.com/kvaps) in cozystack/website#399). +* **[website] Add Hetzner RobotLB documentation**: Added documentation for configuring public IP with Hetzner RobotLB ([**@kvaps**](https://github.com/kvaps) in cozystack/website#394). +* **[website] Add documentation for creating and managing cloned VMs**: Added comprehensive guide for VM cloning operations ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#401). +* **[website] Update Talos installation docs for Hetzner and Servers.com**: Updated installation documentation for Hetzner and Servers.com environments ([**@kvaps**](https://github.com/kvaps) in cozystack/website#395). +* **[website] Add Hidora organization support details**: Added Hidora to the support page ([**@matthieu-robin**](https://github.com/matthieu-robin) in cozystack/website#397, cozystack/website#398). +* **[website] Check quotas before an upgrade**: Added troubleshooting documentation for checking resource quotas before upgrades ([**@nbykov0**](https://github.com/nbykov0) in cozystack/website#405). +* **[website] Update support documentation**: Updated support documentation with current contact information ([**@xrmtech-isk**](https://github.com/xrmtech-isk) in cozystack/website#420). +* **[website] Correct typo in kubeconfig reference in Kubernetes installation guide**: Fixed documentation typo in kubeconfig reference ([**@shkarface**](https://github.com/shkarface) in cozystack/website#414). + +## Breaking Changes & Upgrade Notes + +* **[api] CozystackResourceDefinition renamed to ApplicationDefinition**: The `CozystackResourceDefinition` CRD has been renamed to `ApplicationDefinition`. Migration 24 handles the transition automatically during upgrade ([**@kvaps**](https://github.com/kvaps) in #1864). + +* **[platform] Certificate issuer configuration parameters renamed**: The `publishing.certificates.issuerType` field is renamed to `publishing.certificates.solver`, and the value `cloudflare` is renamed to `dns01`. A new `publishing.certificates.issuerName` field (default: `letsencrypt-prod`) is added. Migration 32 automatically converts existing configurations — no manual action required ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2077). + +* **[vpc] VPC subnets definition migrated from map to array format**: VPC subnets are now defined as `[]Subnet` with an explicit `name` field instead of `map[string]Subnet`. Migration 30 handles the conversion automatically ([**@kvaps**](https://github.com/kvaps) in #2052). + +* **[vm] virtual-machine application replaced by vm-disk and vm-instance**: The legacy `virtual-machine` application has been fully replaced. Migration 28 automatically converts existing VMs to the new architecture ([**@kvaps**](https://github.com/kvaps) in #2040). + +* **[mysql] mysql application renamed to mariadb**: Existing MySQL deployments are automatically renamed to MariaDB via migration 27 ([**@kvaps**](https://github.com/kvaps) in #2026). + +### Upgrade Guide + +To upgrade from v0.41.x to v1.0.0: +1. **Backup your cluster** before upgrading. +2. Run the provided migration script: `hack/migrate-to-version-1.0.sh`. +3. The 33 incremental migration steps will automatically handle all resource renaming, configuration conversion, CRD adoption, and secret cleanup. +4. Refer to the [upgrade documentation](https://cozystack.io/docs/v1/upgrade) for detailed instructions and troubleshooting. + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@androndo**](https://github.com/androndo) +* [**@cheese**](https://github.com/cheese) +* [**@IvanHunters**](https://github.com/IvanHunters) +* [**@IvanStukov**](https://github.com/IvanStukov) +* [**@kitsunoff**](https://github.com/kitsunoff) +* [**@klinch0**](https://github.com/klinch0) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@lllamnyp**](https://github.com/lllamnyp) +* [**@matthieu-robin**](https://github.com/matthieu-robin) +* [**@mattia-eleuteri**](https://github.com/mattia-eleuteri) +* [**@myasnikovdaniil**](https://github.com/myasnikovdaniil) +* [**@nbykov0**](https://github.com/nbykov0) +* [**@shkarface**](https://github.com/shkarface) +* [**@sircthulhu**](https://github.com/sircthulhu) +* [**@xrmtech-isk**](https://github.com/xrmtech-isk) + +### New Contributors + +We're excited to welcome our first-time contributors: + +* [**@cheese**](https://github.com/cheese) - First contribution! +* [**@IvanStukov**](https://github.com/IvanStukov) - First contribution! +* [**@kitsunoff**](https://github.com/kitsunoff) - First contribution! +* [**@shkarface**](https://github.com/shkarface) - First contribution! +* [**@xrmtech-isk**](https://github.com/xrmtech-isk) - First contribution! + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v0.41.0...v1.0.0 diff --git a/docs/changelogs/v1.0.1.md b/docs/changelogs/v1.0.1.md new file mode 100644 index 00000000..2faf2755 --- /dev/null +++ b/docs/changelogs/v1.0.1.md @@ -0,0 +1,21 @@ + + +## Fixes + +* **[platform] Prevent cozystack-version ConfigMap from deletion**: Added resource protection to prevent the `cozystack-version` ConfigMap from being accidentally deleted, improving platform stability and reliability ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2112, #2114). + +* **[installer] Add keep annotation to Namespace and update migration script**: Added `helm.sh/resource-policy: keep` annotation to the `cozy-system` Namespace in the installer Helm chart to prevent Helm from deleting the namespace (and all HelmReleases within it) when the installer release is removed. The v1.0 migration script is also updated to annotate the `cozy-system` namespace and `cozystack-version` ConfigMap with this policy before migration ([**@kvaps**](https://github.com/kvaps) in #2122, #2123). + +* **[dashboard] Add FlowSchema to exempt BFF from API throttling**: Added a `cozy-dashboard-exempt` FlowSchema to exempt the dashboard Back-End-for-Frontend (BFF) service account from Kubernetes API Priority and Fairness throttling. Previously, the BFF fell under the `workload-low` priority level, causing 429 (Too Many Requests) errors under load, resulting in dashboard unresponsiveness ([**@kvaps**](https://github.com/kvaps) in #2121, #2124). + +## Documentation + +* **[website] Replace bundles documentation with variants**: Renamed the "Bundles" documentation section to "Variants" to match current Cozystack terminology. Removed deprecated variants (`iaas-full`, `distro-full`, `distro-hosted`) and added new variants: `default` (PackageSources only, for manual package management via cozypkg) and `isp-full-generic` (full PaaS/IaaS on k3s, kubeadm, or RKE2). Updated all cross-references throughout the documentation ([**@kvaps**](https://github.com/kvaps) in cozystack/website#433). + +* **[website] Add step to protect namespace before upgrading**: Updated the cluster upgrade guide and v0.41→v1.0 migration guide with a required step to annotate the `cozy-system` namespace and `cozystack-version` ConfigMap with `helm.sh/resource-policy=keep` before running `helm upgrade`, preventing accidental namespace deletion ([**@kvaps**](https://github.com/kvaps) in cozystack/website#435). + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.0...v1.0.1 diff --git a/docs/changelogs/v1.0.2.md b/docs/changelogs/v1.0.2.md new file mode 100644 index 00000000..fad9275e --- /dev/null +++ b/docs/changelogs/v1.0.2.md @@ -0,0 +1,19 @@ + + +## Fixes + +* **[platform] Suspend cozy-proxy if it conflicts with installer release during migration**: Added a check in the v0.41→v1.0 migration script to detect and automatically suspend the `cozy-proxy` HelmRelease when its `releaseName` is set to `cozystack`, which conflicts with the installer release and would cause `cozystack-operator` deletion during the upgrade ([**@kvaps**](https://github.com/kvaps) in #2128, #2130). + +* **[platform] Fix off-by-one error in run-migrations script**: Fixed a bug in the migration runner where the first required migration was always skipped due to an off-by-one error in the migration range calculation, ensuring all upgrade steps execute correctly ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2126, #2132). + +* **[system] Fix Keycloak proxy configuration for v26.x**: Replaced the deprecated `KC_PROXY=edge` environment variable with `KC_PROXY_HEADERS=xforwarded` and `KC_HTTP_ENABLED=true` in the Keycloak StatefulSet template. `KC_PROXY` was removed in Keycloak 26.x, previously causing "Non-secure context detected" warnings and broken cookie handling when running behind a reverse proxy with TLS termination ([**@sircthulhu**](https://github.com/sircthulhu) in #2125, #2134). + +* **[dashboard] Allow clearing instanceType field and preserve newlines in secret copy**: Added `allowEmpty: true` to the `instanceType` field in the VMInstance form so users can explicitly clear it to use custom KubeVirt resources without a named instance type. Also fixed newline preservation when copying secrets with CMD+C ([**@sircthulhu**](https://github.com/sircthulhu) in #2135, #2137). + +* **[dashboard] Restore stock-instance sidebars for namespace-level pages**: Restored `stock-instance-api-form`, `stock-instance-api-table`, `stock-instance-builtin-form`, and `stock-instance-builtin-table` sidebar resources that were inadvertently removed in #2106. Without these sidebars, namespace-level pages such as Backup Plans rendered as empty pages with no interactive content ([**@sircthulhu**](https://github.com/sircthulhu) in #2136, #2138). + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.1...v1.0.2 diff --git a/docs/changelogs/v1.0.3.md b/docs/changelogs/v1.0.3.md new file mode 100644 index 00000000..27ae6720 --- /dev/null +++ b/docs/changelogs/v1.0.3.md @@ -0,0 +1,17 @@ + + +## Fixes + +* **[platform] Fix package name conversion in migration script**: Fixed the `migrate-to-version-1.0.sh` script to correctly prepend the `cozystack.` prefix when converting `BUNDLE_DISABLE` and `BUNDLE_ENABLE` package name lists, ensuring packages are properly identified during the v0.41→v1.0 upgrade ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2144, #2148). + +## Documentation + +* **[website] Add white labeling guide**: Added a comprehensive guide for configuring white labeling (branding) in Cozystack v1, covering Dashboard fields (`titleText`, `footerText`, `tenantText`, `logoText`, `logoSvg`, `iconSvg`) and Keycloak fields (`brandName`, `brandHtmlName`). Includes SVG preparation workflow with theme-aware template variables, portable base64 encoding, and migration notes from the v0 ConfigMap approach ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#441). + +* **[website] Actualize backup and recovery documentation**: Reworked the backup and recovery docs to be user-focused, separating operator and tenant workflows. Added tenant-facing documentation for `BackupJob` and `Plan` resources and status inspection commands, and added a new Velero administration guide for operators covering storage credentials and backup storage configuration ([**@androndo**](https://github.com/androndo) in cozystack/website#434). + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.2...v1.0.3 diff --git a/docs/changelogs/v1.0.4.md b/docs/changelogs/v1.0.4.md new file mode 100644 index 00000000..4c55e2f3 --- /dev/null +++ b/docs/changelogs/v1.0.4.md @@ -0,0 +1,25 @@ + + +## Fixes + +* **[system] Fix Keycloak probe crashloop with management port health endpoints**: Fixed a crashloop where Keycloak 26.x was endlessly restarting because liveness and readiness probes were sending HTTP requests to port 8080. Keycloak 26.x redirects all requests on port 8080 to `KC_HOSTNAME` (HTTPS), and since kubelet does not follow redirects, probes failed, eventually triggering container restarts. The fix switches probes to the dedicated management port 9000 (`/health/live`, `/health/ready`) enabled via `KC_HEALTH_ENABLED=true`, exposes management port 9000, and adds a `startupProbe` with appropriate failure thresholds for better startup tolerance ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2162, #2178). + +* **[system] Fix etcd-operator deprecated kube-rbac-proxy image**: Replaced the deprecated `gcr.io/kubebuilder/kube-rbac-proxy:v0.16.0` image with `quay.io/brancz/kube-rbac-proxy:v0.18.1` in the vendored etcd-operator chart. The GCR-hosted image became unavailable after March 18, 2025, causing etcd-operator pods to fail on image pull ([**@kvaps**](https://github.com/kvaps) in #2181, #2183). + +* **[platform] Fix VM MAC address not preserved during virtual-machine to vm-instance migration**: During the `virtual-machine` → `vm-instance` migration (script 29), VM MAC addresses were not preserved. Kube-OVN reads MAC addresses exclusively from the pod annotation `ovn.kubernetes.io/mac_address`, not from `spec.macAddress` of the IP resource. Without this annotation, migrated VMs received a new random MAC address, breaking OS-level network configuration that matches by MAC (e.g., netplan). The fix adds a Helm `lookup` in the vm-instance chart template to read the Kube-OVN IP resource and automatically inject the MAC and IP addresses as pod annotations ([**@sircthulhu**](https://github.com/sircthulhu) in #2169, #2191). + +* **[dashboard] Fix External IPs page showing empty rows**: Fixed the External IPs administration page displaying empty rows instead of service data. The `EnrichedTable` configuration in the `external-ips` factory was using incorrect property names — replaced `clusterNamePartOfUrl` with `cluster` and changed `pathToItems` from array format to dot-path string format, matching the convention used by all other `EnrichedTable` instances ([**@IvanHunters**](https://github.com/IvanHunters) in #2175, #2192). + +* **[dashboard] Fix disabled/hidden state reset on MarketplacePanel reconciliation**: Fixed a bug where the dashboard controller was hardcoding `disabled=false` and `hidden=false` on every reconcile loop, overwriting changes made through the dashboard UI. Services disabled or hidden via the marketplace panel now correctly retain their state after controller reconciliation ([**@IvanHunters**](https://github.com/IvanHunters) in #2176, #2202). + +* **[dashboard] Fix hidden MarketplacePanel resources appearing in sidebar menu**: Fixed the sidebar navigation showing all resources regardless of their MarketplacePanel `hidden` state. The controller now fetches MarketplacePanels during sidebar reconciliation and filters out resources where `hidden=true`, ensuring that hiding a resource from the marketplace also removes it from the sidebar navigation. Listing failures are non-fatal — if the configuration fetch fails, no hiding is applied and the dashboard remains functional ([**@IvanHunters**](https://github.com/IvanHunters) in #2177, #2204). + +## Documentation + +* **[website] Add OIDC self-signed certificates configuration guide**: Added a comprehensive guide for configuring OIDC authentication with Keycloak when using self-signed certificates (the default in Cozystack). Covers Talos machine configuration with certificate mounting and host entries, kubelogin setup instructions, and a troubleshooting section. The guide is available for both v0 and v1 versioned documentation paths ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/website#443). + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.3...v1.0.4 diff --git a/docs/changelogs/v1.0.5.md b/docs/changelogs/v1.0.5.md new file mode 100644 index 00000000..51f01143 --- /dev/null +++ b/docs/changelogs/v1.0.5.md @@ -0,0 +1,29 @@ + + +## Fixes + +* **[api] Fix spurious OpenAPI post-processing errors for non-apps group versions**: The API server no longer logs false errors while generating OpenAPI specs for core and other non-`apps.cozystack.io` group versions. The post-processor now exits early when the base `Application` schemas are absent, reducing noisy startup logs without affecting application schema generation ([**@kvaps**](https://github.com/kvaps) in #2212, #2216). + +## Documentation + +* **[website] Add `DependenciesNotReady` troubleshooting and correct packages management build target**: Added a troubleshooting guide for packages stuck in `DependenciesNotReady`, including how to inspect operator logs and identify missing dependencies, and fixed the outdated `make image-cozystack` command to `make image-packages` in the packages management guide ([**@kvaps**](https://github.com/kvaps) in cozystack/website#450). + +* **[website] Clarify operator-first installation order**: Reordered the platform installation guide and tutorial so users install the Cozystack operator before preparing and applying the Platform Package, matching the rest of the installation docs and reducing setup confusion during fresh installs ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#449). + +* **[website] Add automated installation guide for Ansible**: Added end-to-end documentation for deploying Cozystack with the `cozystack.installer` Ansible collection, including inventory examples, distro-specific playbooks, configuration reference, verification steps, and explicit version pinning guidance to help operators automate installs safely ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#442). + +* **[website] Expand CA rotation operations guide**: Completed the CA rotation documentation with separate Talos and Kubernetes certificate rotation procedures, dry-run preview steps, and post-rotation guidance for fetching updated `talosconfig` and `kubeconfig` files after certificate changes ([**@kvaps**](https://github.com/kvaps) in cozystack/website#406). + +* **[website] Improve backup operations documentation**: Enhanced the operator backup and recovery guide with clearer Velero enablement steps, concrete provider and bucket examples, and more useful commands for inspecting backups, schedules, restores, CRD status, and logs ([**@androndo**](https://github.com/androndo) in cozystack/website#440). + +* **[website] Add custom metrics collection guide**: Added a monitoring guide showing how tenants can expose their own Prometheus exporters through `VMServiceScrape` and `VMPodScrape`, including namespace labeling requirements, example manifests, verification steps, and troubleshooting advice ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/website#444). + +* **[website] Document PackageSource and Package architecture**: Added a Key Concepts reference covering `PackageSource` and `Package` reconciliation flow, dependency handling, update propagation, rollback behavior, FluxPlunger recovery, and the `cozypkg` CLI for package management ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/website#445). + +* **[website] Refresh v1 application and platform documentation**: Fixed the documentation auto-update flow and published a broad v1 documentation refresh covering newly documented applications, updated naming and navigation, virtualization and platform content updates, and reorganized versioned docs pages ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#439). + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.4...v1.0.5 diff --git a/docs/changelogs/v1.0.6.md b/docs/changelogs/v1.0.6.md new file mode 100644 index 00000000..c65c5fd5 --- /dev/null +++ b/docs/changelogs/v1.0.6.md @@ -0,0 +1,21 @@ + + +## Fixes + +* **[kubernetes] Fix CiliumNetworkPolicy endpointSelector for multi-node RWX volumes**: When an NFS-backed RWX volume is published to multiple VMs, the network policy's `endpointSelector` was only capturing the first VM. Subsequent volume publications added owner references but never broadened the selector, causing Cilium to block NFS egress and making mounts hang on all nodes except the first. The fix switches from `matchLabels` to `matchExpressions` (`operator: In`) so the selector lists all VM names and is rebuilt whenever owner references change ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2227, #2228). + +* **[dashboard] Fix dashboard authentication failures after secret recreation**: Added a `secret-hash` annotation containing the SHA256 hash of the client secret to the dashboard `KeycloakClient` resource. Without this annotation, if the `dashboard-client` Secret was recreated (e.g. after an upgrade or reinstall), the `KeycloakClient` spec stayed unchanged, the EDP Keycloak operator skipped reconciliation, and Keycloak kept the stale secret — causing dashboard authentication failures. Now any secret value change updates the annotation hash, triggering operator reconciliation and syncing the new secret to Keycloak ([**@sircthulhu**](https://github.com/sircthulhu) in #2231, #2240). + +* **[etcd] Fix defrag CronJob accumulating pods during cluster upgrades**: Added protective limits to the etcd defragmentation CronJob to prevent job pile-up when etcd is temporarily unavailable during upgrades. Without `concurrencyPolicy: Forbid`, new jobs kept being created hourly while previous ones were still failing, accumulating hundreds of running/failed pods across tenants. The fix adds `concurrencyPolicy: Forbid`, a `startingDeadlineSeconds: 300` guard against missed schedules, a 30-minute job timeout, and limits retries to 2 ([**@sircthulhu**](https://github.com/sircthulhu) in #2233, #2235). + +## Documentation + +* **[website] Document `keycloakInternalUrl` platform value**: Added documentation for the `authentication.oidc.keycloakInternalUrl` platform value to the Platform Package Reference, Self-Signed Certificates guide, and Enable OIDC Server pages. This value routes dashboard backend OIDC requests through the internal Keycloak service, which is useful in environments with self-signed certificates ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#452). + +* **[website] Publish Cozystack v1.0 release announcement**: Added the official Cozystack v1.0 release announcement blog post and supporting images, celebrating the first stable release of the platform ([**@tym83**](https://github.com/tym83) in cozystack/website#453, cozystack/website#454). + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.5...v1.0.6 diff --git a/docs/changelogs/v1.0.7.md b/docs/changelogs/v1.0.7.md new file mode 100644 index 00000000..942115bf --- /dev/null +++ b/docs/changelogs/v1.0.7.md @@ -0,0 +1,27 @@ + + +## Fixes + +* **[platform] Fix tenant admins unable to create FoundationDB, Harbor, MongoDB, OpenBAO, OpenSearch, Qdrant, and VPN applications**: The `cozy:tenant:admin:base` ClusterRole was missing RBAC entries for `foundationdbs`, `harbors`, `mongodbs`, `openbaos`, `opensearches`, `qdrants`, and `vpns` resources from `apps.cozystack.io`. Without these permissions, tenant admins could not create these applications — the "Add" button was inactive in the dashboard. The fix adds all seven missing resource verbs ([**@sircthulhu**](https://github.com/sircthulhu) in #2268, #2271). + +* **[system] Fix 403 error on Service details page for tenant users**: The `cozy:tenant:base` and `cozy:tenant:view:base` ClusterRoles were missing read permissions for `discovery.k8s.io/endpointslices`. The dashboard requests EndpointSlices to display the "Pod serving" section on the Service details page, and without this permission tenant users received a 403 error. The fix adds `get`, `list`, and `watch` verbs for endpointslices to both tenant roles ([**@sircthulhu**](https://github.com/sircthulhu) in #2257, #2284). + +* **[dashboard] Fix "Pod serving" table showing "Raw:" prefixes and "Invalid Date" on Service details page**: The EndpointSlice table on the service details page displayed raw data and broken timestamps because the `EnrichedTable` component referenced the `factory-kube-service-details-endpointslice` customization ID which had no corresponding `CustomColumnsOverride`. The fix adds column definitions for Pod (`.targetRef.name`), Addresses (`.addresses`), Ready (`.conditions.ready`), and Node (`.nodeName`) ([**@sircthulhu**](https://github.com/sircthulhu) in #2266, #2282). + +* **[dashboard] Fix broken backup menu links missing cluster context**: Backup resources (plans, backupjobs, backups) are not `ApplicationDefinitions`, so `ensureNavigation()` never created their `baseFactoriesMapping` entries. Without these mappings, the OpenUI frontend could not resolve the `{cluster}` context for backup pages, producing broken sidebar links with an empty cluster segment (e.g. `/openapi-ui//tenant-root/...` instead of `/openapi-ui/default/tenant-root/...`). The fix adds the three missing static entries to the Navigation resource ([**@sircthulhu**](https://github.com/sircthulhu) in #2232, #2270). + +* **[linstor] Fix swapped VMPodScrape job labels causing incorrect alerts**: The `job` labels in the `cozy-linstor` VictoriaMetrics `VMPodScrape` templates were swapped: `linstor-satellite` metrics were relabeled as `job=linstor-controller` and vice versa. This caused `linstorControllerOffline` alerts to fire against satellite endpoints (`:9942`) while reporting the controller as unreachable. The fix ensures `linstor-satellite` metrics keep `job=linstor-satellite` and `linstor-controller` metrics keep `job=linstor-controller`, restoring consistent alerting and dashboard semantics ([**@sasha-sup**](https://github.com/sasha-sup) in #2264, #2288). + +* **[piraeus-operator] Fix LINSTOR satellite alert annotations and reduce false-positive alerts**: Two issues in the LINSTOR alerts shipped by `cozy-piraeus-operator` were fixed. First, `linstorSatelliteErrorRate` used a non-existent `name` label in annotations, resulting in `Satellite ""` in alert notifications — corrected to use `{{ $labels.hostname }}`. Second, `linstorSatelliteErrorRate` produced false positives when the `linstor-controller` scrape flapped and historical `linstor_error_reports_count` counters reappeared inside the alert window — fixed by requiring stable `up{job="linstor-controller"}` for the full 15-minute window. Additionally, the controller availability alert was split to add a dedicated warning for metrics scrape failures with a 10-minute hold time to reduce transient noise ([**@sasha-sup**](https://github.com/sasha-sup) in #2265, #2287). + +## Documentation + +* **[website] Add Backup and Recovery guide for VMInstance and VMDisk**: Replaced the generic Kubernetes Backup and Recovery guide with a virtualization-focused Backup and Recovery doc covering VMInstance and VMDisk one-off and scheduled backups, restores, status checks, and troubleshooting (including Velero-related notes) ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#456). + +* **[website] Update developer guide with operator-driven architecture and OCIRepository/migration flow**: Rewrote the development guide to describe the operator-driven in-cluster architecture, bootstrap flow, operator responsibilities, and platform install/update sequence. Added documentation for OCIRepositories and the migration flow with migration hook examples and sequencing rules for pre-upgrade/install migrations. Also updated the concepts guide with the two-repository update model, dependency ordering rules, namespace creation behavior, and cluster-wide values injection ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#458). + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.6...v1.0.7 diff --git a/docs/changelogs/v1.1.0.md b/docs/changelogs/v1.1.0.md new file mode 100644 index 00000000..ad61c1a6 --- /dev/null +++ b/docs/changelogs/v1.1.0.md @@ -0,0 +1,126 @@ + + +# Cozystack v1.1.0 + +Cozystack v1.1.0 delivers a major expansion of the managed application catalog with **OpenBAO** (open-source HashiCorp Vault fork) for secrets management, comprehensive **tiered object storage** with SeaweedFS storage pools, a new bucket **user model** with per-user credentials and S3 login support, **RabbitMQ version selection**, and **MongoDB Grafana dashboards**. The dashboard gains storageClass dropdowns for all stateful apps. This release also incorporates all fixes from the v1.0.x patch series. + +## Feature Highlights + +### OpenBAO: Managed Secrets Management Service + +Cozystack now ships **OpenBAO** as a fully managed PaaS application — an open-source fork of HashiCorp Vault providing enterprise-grade secrets management. Users can deploy OpenBAO instances in standalone mode (single replica with file storage) or in high-availability Raft mode (multiple replicas with integrated Raft consensus), with the mode switching automatically based on the `replicas` field. + +Each OpenBAO instance gets TLS enabled by default via cert-manager self-signed certificates, with DNS SANs covering all service endpoints and pod addresses. The Vault injector and CSI provider are intentionally disabled (they are cluster-scoped components not safe for per-tenant use). OpenBAO requires manual initialization and unsealing by design — no auto-unseal is configured. + +A full end-to-end E2E test covers the complete lifecycle: deploy, wait for certificate and API readiness, init, unseal, verify, and cleanup. OpenBAO is available in the application catalog for tenant namespaces. + +### SeaweedFS Tiered Storage Pools + +SeaweedFS now supports **tiered storage pools** — operators can define separate storage pools per disk type (SSD, HDD, NVMe) in the `volume.pools` field (Simple topology) or `volume.zones[name].pools` (MultiZone topology). Each pool creates an additional Volume StatefulSet alongside the default one, with SeaweedFS distinguishing storage via the `-disk=` flag on volume servers. + +Each pool automatically generates its own set of COSI resources: a standard `BucketClass`, a `-lock` BucketClass (COMPLIANCE mode, 365-day retention), a read-write `BucketAccessClass`, and a `-readonly` BucketAccessClass. This allows applications to place data on specific storage tiers and request appropriate access policies per pool. + +In MultiZone topology, pools are defined per zone and each zone × pool combination creates a dedicated StatefulSet (e.g., `us-east-ssd`, `us-west-hdd`), with nodes selected via `topology.kubernetes.io/zone` labels. Existing deployments with no pools defined produce output identical to previous versions — no migration is required. + +### Bucket User Model with S3 Login + +The bucket application introduces a new **user model** for access management. Instead of a single implicit BucketAccess resource, operators now define a `users` map where each entry creates a dedicated `BucketAccess` with its own credentials secret and an optional `readonly` flag. The S3 Manager UI has been updated with a login screen that uses per-session credentials from the user's own secret, replacing the previous basic-auth approach. + +Two new bucket parameters are available: `locking` provisions from the `-lock` BucketClass (COMPLIANCE mode, 365-day object lock retention) for write-once-read-many use cases, and `storagePool` selects a specific pool's BucketClass for tiered storage placement. The COSI driver has been updated to v0.3.0 to support the new `diskType` parameter. + +**⚠️ Breaking change**: The implicit default BucketAccess resource is no longer created. Existing buckets that relied on the single auto-generated BucketAccess will need to explicitly define users in the `users` map after upgrading. + +### RabbitMQ Version Selection + +RabbitMQ instances now support a configurable **version selector** (`version` field with values: `v4.2`, `v4.1`, `v4.0`, `v3.13`; default `v4.2`). The chart validates the selection at deploy time and uses it to pin the runtime image, giving operators control over the RabbitMQ release channel per instance. An automatic migration backfills the `version` field on all existing RabbitMQ resources to `v4.2`. + +## Major Features and Improvements + +* **[apps] Add OpenBAO as a managed secrets management service**: Deployed as a PaaS application with standalone (file storage) and HA Raft modes, TLS enabled by default via cert-manager, injector and CSI provider disabled for tenant safety, and a full E2E lifecycle test ([**@lexfrei**](https://github.com/lexfrei) in #2059). + +* **[seaweedfs] Add storage pools support for tiered storage**: Added `volume.pools` (Simple) and `volume.zones[name].pools` (MultiZone) for per-disk-type StatefulSets, zone overrides (`nodeSelector`, `storageClass`, `dataCenter`), per-pool COSI BucketClass and BucketAccessClass resources, and bumped seaweedfs-cosi-driver to v0.3.0 ([**@sircthulhu**](https://github.com/sircthulhu) in #2097). + +* **[apps][system] Add bucket user model with locking and storage pool selection**: Replaced implicit BucketAccess with per-user `users` map, added `locking` and `storagePool` parameters, renamed COSI BucketClass suffix from `-worm` to `-lock`, added `-readonly` BucketAccessClass for all topologies, and updated S3 Manager with login screen using per-user credentials ([**@IvanHunters**](https://github.com/IvanHunters) in #2119). + +* **[rabbitmq] Add version selection for RabbitMQ instances**: Added `version` field (`v4.2`, `v4.1`, `v4.0`, `v3.13`) with chart-level validation, default `v4.2`, and an automatic migration to backfill the field on existing instances ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2092). + +* **[system] Add MongoDB Overview and InMemory Details Grafana dashboards**: Added two comprehensive Grafana dashboards for MongoDB monitoring — Overview (command operations, connections, cursors, query efficiency, write time) and InMemory Details (WiredTiger cache, transactions, concurrency, eviction). Dashboards are registered in `dashboards.list` for automatic GrafanaDashboard CRD generation ([**@IvanHunters**](https://github.com/IvanHunters) in #2158). + +* **[dashboard] Add storageClass dropdown for all stateful apps**: Replaced the free-text `storageClass` input with an API-backed dropdown listing available StorageClasses from the cluster. Affects ClickHouse, Harbor, HTTPCache, Kubernetes, MariaDB, MongoDB, NATS, OpenBAO, Postgres, Qdrant, RabbitMQ, Redis, VMDisk (top-level `storageClass`), FoundationDB (`storage.storageClass`), and Kafka (`kafka.storageClass`, `zookeeper.storageClass`) ([**@sircthulhu**](https://github.com/sircthulhu) in #2131). + +* **[bucket] Add readonly S3 access credentials**: Added a readonly `BucketAccessClass` to the SeaweedFS COSI chart and updated the bucket application to automatically provision two sets of S3 credentials per bucket: read-write (for UI) and readonly ([**@IvanHunters**](https://github.com/IvanHunters) in #2105). + +* **[dashboard] Hide sidebar on cluster-level pages when no tenant selected**: Fixed broken URLs with double `//` on the main cluster page (before tenant selection) by clearing `CUSTOMIZATION_SIDEBAR_FALLBACK_ID` so no sidebar renders when no namespace is selected ([**@sircthulhu**](https://github.com/sircthulhu) in #2106). + +* **[cert-manager] Update cert-manager to v1.19.3**: Upgraded cert-manager with new CRDs moved into a dedicated CRD package, added global `nodeSelector` and `hostUsers` (pod user-namespace isolation), and renamed `ServiceMonitor` targetPort default to `http-metrics` ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2070). + +* **[dashboard] Add backupClasses dropdown to Plan/BackupJob forms**: Replaced free-text input for `backupClass` field with an API-backed dropdown populated with available BackupClass resources, making it easier to select the correct backup target ([**@androndo**](https://github.com/androndo) in #2104). + +## Fixes + +* **[platform] Fix package name conversion in migration script**: Fixed the `migrate-to-version-1.0.sh` script to correctly prepend the `cozystack.` prefix when converting `BUNDLE_DISABLE` and `BUNDLE_ENABLE` package name lists, ensuring packages are properly identified during the v0.41→v1.0 upgrade ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2144, #2148). + +* **[backups] Fix RBAC for backup controllers**: Updated RBAC permissions for the backup strategy controller to support enhanced backup and restore capabilities, including Velero integration and status management ([**@androndo**](https://github.com/androndo) in #2145). + +* **[kubernetes] Set explicit MTU for Cilium in tenant clusters**: Set explicit MTU 1350 for Cilium in KubeVirt-based tenant Kubernetes clusters to prevent packet drops caused by VXLAN encapsulation overhead. Cilium's auto-detection does not account for VXLAN overhead (50 bytes) when the VM interface inherits MTU 1400 from the parent OVN/Geneve overlay, causing intermittent connectivity issues and HTTP 499 errors under load ([**@IvanHunters**](https://github.com/IvanHunters) in #2147). + +* **[platform] Prevent cozystack-version ConfigMap from deletion**: Added resource protection annotations to prevent the `cozystack-version` ConfigMap from being accidentally deleted, improving platform stability ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2112, #2114). + +* **[installer] Add keep annotation to Namespace and update migration script**: Added `helm.sh/resource-policy: keep` annotation to the `cozy-system` Namespace in the installer Helm chart to prevent Helm from deleting the namespace and all HelmReleases within it when the installer release is removed. The v1.0 migration script is also updated to annotate the namespace and `cozystack-version` ConfigMap before migration ([**@kvaps**](https://github.com/kvaps) in #2122, #2123). + +* **[dashboard] Add FlowSchema to exempt BFF from API throttling**: Added a `cozy-dashboard-exempt` FlowSchema to exempt the dashboard Back-End-for-Frontend service account from Kubernetes API Priority and Fairness throttling, preventing 429 errors under load ([**@kvaps**](https://github.com/kvaps) in #2121, #2124). + +* **[platform] Suspend cozy-proxy if it conflicts with installer release during migration**: Added a check in the v0.41→v1.0 migration script to detect and suspend the `cozy-proxy` HelmRelease when its `releaseName` is set to `cozystack`, which conflicts with the installer release and would cause `cozystack-operator` deletion during the upgrade ([**@kvaps**](https://github.com/kvaps) in #2128, #2130). + +* **[platform] Fix off-by-one error in run-migrations script**: Fixed a bug in the migration runner where the first required migration was always skipped due to an off-by-one error in the migration range calculation ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2126, #2132). + +* **[system] Fix Keycloak proxy configuration for v26.x**: Replaced the deprecated `KC_PROXY=edge` environment variable with `KC_PROXY_HEADERS=xforwarded` and `KC_HTTP_ENABLED=true` in the Keycloak StatefulSet. `KC_PROXY` was removed in Keycloak 26.x, previously causing "Non-secure context detected" warnings and broken cookie handling behind a reverse proxy with TLS termination ([**@sircthulhu**](https://github.com/sircthulhu) in #2125, #2134). + +* **[dashboard] Allow clearing instanceType field and preserve newlines in secret copy**: Added `allowEmpty: true` to the `instanceType` field in the VMInstance form so users can explicitly clear it to use custom KubeVirt resources without a named instance type. Also fixed newline preservation when copying secrets with CMD+C ([**@sircthulhu**](https://github.com/sircthulhu) in #2135, #2137). + +* **[dashboard] Restore stock-instance sidebars for namespace-level pages**: Restored `stock-instance-api-form`, `stock-instance-api-table`, `stock-instance-builtin-form`, and `stock-instance-builtin-table` sidebar resources that were inadvertently removed in #2106. Without these sidebars, namespace-level pages such as Backup Plans rendered as empty pages ([**@sircthulhu**](https://github.com/sircthulhu) in #2136, #2138). + +## System Configuration + +* **[platform] Disable private key rotation in CA certs**: Set `rotationPolicy: Never` for all CA/root certificates used by system components (ingress-nginx, linstor, linstor-scheduler, seaweedfs, victoria-metrics-operator, kubeovn-webhook, lineage-controller-webhook, cozystack-api, etcd, linstor API/internal) to prevent trust chain problems when CA certificates are reissued ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2113). + +## Development, Testing, and CI/CD + +* **[ci] Add debug improvements for CI tests**: Added extra debug commands for Kubernetes startup diagnostics and improved error output in CI test runs ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2111). + +## Documentation + +* **[website] Add object storage guide (pools, buckets, users)**: Added a comprehensive guide covering SeaweedFS object storage configuration including storage pools for tiered storage, bucket creation with access classes, per-user credential management, and credential rotation procedures ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#438). + +* **[website] Add Build Your Own Platform (BYOP) guide**: Added a new "Build Your Own Platform" guide and split the installation documentation into platform installation and BYOP sub-pages, with cross-references throughout the documentation ([**@kvaps**](https://github.com/kvaps) in cozystack/website#437). + +* **[website] Add white labeling guide**: Added a comprehensive guide for configuring white labeling (branding) in Cozystack v1, covering Dashboard fields (`titleText`, `footerText`, `tenantText`, `logoText`, `logoSvg`, `iconSvg`) and Keycloak fields (`brandName`, `brandHtmlName`). Includes SVG preparation workflow with theme-aware template variables and portable base64 encoding ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#441). + +* **[website] Actualize backup and recovery documentation**: Reworked the backup and recovery docs to be user-focused, separating operator and tenant workflows. Added tenant-facing documentation for `BackupJob` and `Plan` resources and a new Velero administration guide for operators ([**@androndo**](https://github.com/androndo) in cozystack/website#434). + +* **[website] Add step to protect namespace before upgrading**: Updated the cluster upgrade guide and v0.41→v1.0 migration guide with a required step to annotate the `cozy-system` namespace and `cozystack-version` ConfigMap with `helm.sh/resource-policy=keep` before running `helm upgrade` ([**@kvaps**](https://github.com/kvaps) in cozystack/website#435). + +* **[website] Replace bundles documentation with variants**: Renamed the "Bundles" documentation section to "Variants" to match current Cozystack terminology. Removed deprecated variants and added new ones: `default` and `isp-full-generic` ([**@kvaps**](https://github.com/kvaps) in cozystack/website#433). + +* **[website] Fix component values override instructions**: Corrected the component values override documentation to reflect current configuration patterns ([**@kvaps**](https://github.com/kvaps) in cozystack/website#436). + +## Breaking Changes & Upgrade Notes + +* **[bucket] Bucket user model now requires explicit user definitions**: The implicit default `BucketAccess` resource is no longer created automatically. Existing buckets that relied on a single auto-generated credential secret will need to define users explicitly in the `users` map after upgrading. Each user entry creates its own `BucketAccess` resource and credential secret (optionally with `readonly: true`). The COSI BucketClass suffix has also been renamed from `-worm` to `-lock` ([**@IvanHunters**](https://github.com/IvanHunters) in #2119). + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@androndo**](https://github.com/androndo) +* [**@IvanHunters**](https://github.com/IvanHunters) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@myasnikovdaniil**](https://github.com/myasnikovdaniil) +* [**@sircthulhu**](https://github.com/sircthulhu) + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.0.0...v1.1.0 diff --git a/docs/changelogs/v1.1.1.md b/docs/changelogs/v1.1.1.md new file mode 100644 index 00000000..18bb6814 --- /dev/null +++ b/docs/changelogs/v1.1.1.md @@ -0,0 +1,23 @@ + + +## Fixes + +* **[dashboard] Fix hidden MarketplacePanel resources appearing in sidebar menu**: The sidebar was generated independently from MarketplacePanels, always showing all resources regardless of their `hidden` state. Fixed by fetching MarketplacePanels during sidebar reconciliation and skipping resources where `hidden=true`, so hiding a resource from the marketplace also removes it from the sidebar navigation ([**@IvanHunters**](https://github.com/IvanHunters) in #2177, #2203). + +* **[dashboard] Fix disabled/hidden state overwritten on every MarketplacePanel reconciliation**: The controller was hardcoding `disabled=false` and `hidden=false` on every reconciliation, silently overwriting any user changes made through the dashboard UI. Fixed by reading and preserving the current `disabled`/`hidden` values from the existing resource before updating ([**@IvanHunters**](https://github.com/IvanHunters) in #2176, #2201). + +* **[dashboard] Fix External IPs factory EnrichedTable rendering**: The external-IPs table displayed empty rows because the factory used incorrect `EnrichedTable` properties. Replaced `clusterNamePartOfUrl` with `cluster` and changed `pathToItems` from array to dot-path string format, consistent with all other working `EnrichedTable` instances ([**@IvanHunters**](https://github.com/IvanHunters) in #2175, #2193). + +* **[platform] Fix VM MAC address not preserved during virtual-machine to vm-instance migration**: Kube-OVN reads MAC address exclusively from the pod annotation `ovn.kubernetes.io/mac_address`, not from the IP resource `spec.macAddress`. Without the annotation, migrated VMs received a new random MAC, breaking OS-level network configurations that match by MAC (e.g. netplan). Added a Helm `lookup` for the Kube-OVN IP resource in the vm-instance chart so that MAC and IP addresses are automatically injected as pod annotations when the resource exists ([**@sircthulhu**](https://github.com/sircthulhu) in #2169, #2190). + +* **[etcd-operator] Replace deprecated kube-rbac-proxy image**: The `gcr.io/kubebuilder/kube-rbac-proxy` image became unavailable after Google Container Registry was deprecated. Replaced it with `quay.io/brancz/kube-rbac-proxy` from the original upstream author, restoring etcd-operator functionality ([**@kvaps**](https://github.com/kvaps) in #2181, #2182). + +* **[migrations] Handle missing RabbitMQ CRD in migration 34**: Migration 34 failed with an error when the `rabbitmqs.apps.cozystack.io` CRD did not exist — which occurs on clusters where RabbitMQ was never installed. Added a CRD presence check before attempting to list resources so that migration 34 completes cleanly on such clusters ([**@IvanHunters**](https://github.com/IvanHunters) in #2168, #2180). + +* **[keycloak] Fix Keycloak crashloop due to misconfigured health probes**: Keycloak 26.x redirects all HTTP requests on port 8080 to the configured HTTPS hostname; since kubelet does not follow redirects, liveness and readiness probes failed causing a crashloop. Fixed by enabling `KC_HEALTH_ENABLED=true`, exposing management port 9000, and switching all probes to `/health/live` and `/health/ready` on port 9000. Also added a `startupProbe` for improved startup tolerance ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2162, #2179). + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.1.0...v1.1.1 diff --git a/docs/changelogs/v1.1.2.md b/docs/changelogs/v1.1.2.md new file mode 100644 index 00000000..29dba321 --- /dev/null +++ b/docs/changelogs/v1.1.2.md @@ -0,0 +1,25 @@ + + +## Fixes + +* **[bucket] Fix S3 Manager endpoint mismatch with COSI credentials**: The S3 Manager UI previously constructed an `s3..` endpoint even though COSI-issued bucket credentials point to the root-level S3 endpoint. This caused login failures with "invalid credentials" despite valid secrets. The deployment now uses the actual endpoint from `BucketInfo`, with the old namespace-based endpoint kept only as a fallback before `BucketAccess` secrets exist ([**@IvanHunters**](https://github.com/IvanHunters) in #2211, #2215). + +* **[platform] Fix spurious OpenAPI post-processing errors on cozystack-api startup**: The OpenAPI post-processor was being invoked for non-`apps.cozystack.io` group versions where the base `Application*` schemas do not exist, producing noisy startup errors on every API server launch. It now skips those non-apps group versions gracefully instead of returning an error ([**@kvaps**](https://github.com/kvaps) in #2212, #2217). + +## Documentation + +* **[website] Add troubleshooting for packages stuck in `DependenciesNotReady`**: Added an operations guide that explains how to diagnose missing package dependencies in operator logs and corrected the packages management development docs to use the current `make image-packages` target ([**@kvaps**](https://github.com/kvaps) in cozystack/website#450). + +* **[website] Reorder installation docs to install the operator before the platform package**: Updated the platform installation guide and tutorial so the setup sequence consistently installs the Cozystack operator first, then prepares and applies the Platform Package, matching the rest of the documentation set ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#449). + +* **[website] Add automated installation guide for the Ansible collection**: Added a full guide for deploying Cozystack with the `cozystack.installer` collection, including inventory examples, distro-specific playbooks, configuration reference, and explicit version pinning guidance ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#442). + +* **[website] Expand monitoring and platform architecture reference docs**: Added a tenant custom metrics collection guide for `VMServiceScrape` and `VMPodScrape`, and documented `PackageSource`/`Package` architecture, reconciliation flow, rollback behavior, and the `cozypkg` workflow in Key Concepts ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/website#444, cozystack/website#445). + +* **[website] Improve operations guides for CA rotation and Velero backups**: Completed the CA rotation documentation with dry-run and post-rotation credential retrieval steps, and expanded the backup configuration guide with concrete examples, verification commands, and clearer operator procedures ([**@kvaps**](https://github.com/kvaps) in cozystack/website#406; [**@androndo**](https://github.com/androndo) in cozystack/website#440). + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.1.1...v1.1.2 diff --git a/docs/changelogs/v1.1.3.md b/docs/changelogs/v1.1.3.md new file mode 100644 index 00000000..f589476e --- /dev/null +++ b/docs/changelogs/v1.1.3.md @@ -0,0 +1,19 @@ + + +## Fixes + +* **[kubernetes] Fix CiliumNetworkPolicy endpointSelector not updated for multi-node RWX volumes**: When an NFS-backed RWX volume was published to multiple VMs, the `CiliumNetworkPolicy` `endpointSelector.matchLabels` was set only for the first VM and never broadened on subsequent `ControllerPublishVolume` calls. This caused Cilium to block NFS egress so that mounts hung on all nodes except the first. The selector now uses `matchExpressions` with `operator: In` and is rebuilt whenever owner references are added or removed ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2227, #2229). + +* **[dashboard] Fix dashboard-client secret desynchronization with Keycloak after upgrades**: When the `dashboard-client` Kubernetes Secret was recreated with a new value after an upgrade or reinstall, the `KeycloakClient` spec remained unchanged and the EDP Keycloak operator skipped reconciliation, leaving Keycloak with the stale secret and causing authentication failures for the dashboard. A `secret-hash` annotation containing the SHA256 hash of the client secret is now added to the `KeycloakClient` resource; any secret rotation updates the hash in metadata, triggering operator reconciliation and syncing the new secret to Keycloak ([**@sircthulhu**](https://github.com/sircthulhu) in #2231, #2241). + +* **[etcd] Fix defrag CronJob accumulating hundreds of pods during cluster upgrades**: After upgrading CozyStack, the etcd defrag CronJob could accumulate hundreds of running and failed pods when etcd was temporarily unavailable during the upgrade, because no concurrency or retry limits were configured. Added `concurrencyPolicy: Forbid` to prevent parallel jobs, `startingDeadlineSeconds: 300` to discard missed schedules older than 5 minutes, `failedJobsHistoryLimit: 1` to limit failure retention, `activeDeadlineSeconds: 1800` for a 30-minute per-job timeout, and `backoffLimit: 2` to cap retries ([**@sircthulhu**](https://github.com/sircthulhu) in #2233, #2234). + +## Documentation + +* **[website] Document `keycloakInternalUrl` platform value**: Added reference documentation for the `authentication.oidc.keycloakInternalUrl` platform value to the Platform Package Reference, Self-Signed Certificates guide, and Enable OIDC Server guide, explaining how to route dashboard backend OIDC requests through the internal Keycloak service URL ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#452). + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.1.2...v1.1.3 diff --git a/docs/changelogs/v1.1.4.md b/docs/changelogs/v1.1.4.md new file mode 100644 index 00000000..f1e4ede9 --- /dev/null +++ b/docs/changelogs/v1.1.4.md @@ -0,0 +1,41 @@ + + +## Features and Improvements + +* **[boot-to-talos] Add support for ISO, RAW, and HTTP image sources**: The `boot-to-talos` tool can now use ISO files, raw disk images, and HTTP URLs as Talos image sources in addition to container registry images. This allows bootstrapping nodes in air-gapped environments or from locally stored images without requiring a container registry ([**@lexfrei**](https://github.com/lexfrei) in cozystack/boot-to-talos#13). + +* **[boot-to-talos] Use permanent MAC address for predictable network interface names**: Interface name detection now reads the permanent MAC address directly from sysfs instead of relying on udev data, providing a stable hardware MAC that is unaffected by user modifications to the active MAC address. This makes network interface naming more reliable across reboots and hardware changes ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/boot-to-talos#14). + +## Fixes + +* **[dashboard] Fix broken backup menu links missing cluster context**: Backup resources (plans, backupjobs, backups) are not `ApplicationDefinition`s, so `ensureNavigation()` never created their `baseFactoriesMapping` entries. Without these entries the OpenUI frontend could not resolve the `{cluster}` context for backup pages, producing broken sidebar links with an empty cluster segment (e.g. `/openapi-ui//tenant-root/...`). The missing `baseFactoriesMapping` entries for all backup resource types are now added to the static `Navigation` resource ([**@sircthulhu**](https://github.com/sircthulhu) in #2232, #2269). + +* **[platform] Fix tenant admins unable to create FoundationDB, Harbor, MongoDB, OpenBAO, OpenSearch, Qdrant, and VPN applications**: The `cozy:tenant:admin:base` `ClusterRole` was missing seven application resources from `apps.cozystack.io` (`foundationdbs`, `harbors`, `mongodbs`, `openbaos`, `opensearches`, `qdrants`, `vpns`). Without these permissions, tenant admins could not create these applications — the "Add" button was inactive in the dashboard. The missing resources have been added to the ClusterRole ([**@sircthulhu**](https://github.com/sircthulhu) in #2268, #2272). + +* **[dashboard] Fix StorageClass dropdown showing "Error" in application forms**: The dashboard UI fetches `StorageClass` resources to populate dropdowns (e.g. in the Postgres form), but the `cozystack-dashboard-readonly` `ClusterRole` did not include `storage.k8s.io/storageclasses`. This caused authenticated users to see "Error" instead of the StorageClass name. `get`/`list`/`watch` permissions for `storageclasses` have been added to the dashboard readonly role ([**@sircthulhu**](https://github.com/sircthulhu) in #2267, #2274). + +* **[system] Fix 403 error on Service details page by granting tenants read access to EndpointSlices**: The dashboard requested `EndpointSlices` from the `discovery.k8s.io` API group to display the "Pod serving" section on the Service details page, but `cozy:tenant:base` and `cozy:tenant:view:base` `ClusterRole`s lacked permissions for this resource. Tenant users received a 403 error when opening the Service details page. `get`/`list`/`watch` permissions for `endpointslices` have been added to both tenant ClusterRoles ([**@sircthulhu**](https://github.com/sircthulhu) in #2257, #2285). + +* **[dashboard] Fix "Pod serving" table displaying "Raw:" and "Invalid Date" on Service details page**: The Service details page `EndpointSlice` table showed "Raw:" prefixes and "Invalid Date" values because the `EnrichedTable` referenced `customizationId` `factory-kube-service-details-endpointslice` which had no corresponding `CustomColumnsOverride`. Column definitions for Pod (`.targetRef.name`), Addresses (`.addresses`), Ready (`.conditions.ready`), and Node (`.nodeName`) have been added ([**@sircthulhu**](https://github.com/sircthulhu) in #2266, #2283). + +* **[piraeus-operator] Fix LINSTOR satellite alert labels, reduce scrape-flap false positives, and improve controller alerting**: Three alerting issues in `cozy-piraeus-operator` have been addressed: (1) `linstorSatelliteErrorRate` used a non-existent `name` label in annotations, resulting in `Satellite ""` in alert notifications — corrected to `{{ $labels.hostname }}`; (2) `linstorSatelliteErrorRate` could produce false positives when the `linstor-controller` scrape flapped and historical `linstor_error_reports_count` counters reappeared inside the alert window — fixed by adding a minimum scrape-count guard; (3) The `LinstorControllerOffline` alert has been split into separate availability and metrics-availability alerts with configurable hold time to reduce noise during brief connectivity interruptions ([**@sasha-sup**](https://github.com/sasha-sup) in #2265, #2286). + +* **[linstor] Fix swapped VMPodScrape job labels causing incorrect controller offline alerts**: The `cozy-linstor` VictoriaMetrics `VMPodScrape` templates had the `job` relabeling rules swapped: `linstor-satellite` metrics were labeled as `job=linstor-controller` and vice versa. This caused `linstorControllerOffline` alerts to fire for satellite endpoints (`:9942`) while reporting that the controller was unreachable. The `job` labels are now correctly assigned to their respective targets ([**@sasha-sup**](https://github.com/sasha-sup) in #2264, #2289). + +* **[boot-to-talos] Fix triple-fault on hosts with 5-level paging (LA57) enabled**: On hosts with `CONFIG_X86_5LEVEL=y` in the kernel, kexec into Talos caused a triple-fault because the Talos kernel does not support 5-level page tables. `boot-to-talos` now detects LA57 before kexec and automatically patches GRUB with `no5lvl`, runs `update-grub`, and reboots. After reboot with 5-level paging disabled, `boot-to-talos` proceeds normally ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/boot-to-talos#15). + +* **[boot-to-talos] Fix EFI boot entry creation when using loop device images**: Talos installer skips EFI variable creation when running on loop devices. `boot-to-talos` now creates a proper UEFI boot entry with an `HD()` device path pointing to the real target disk's ESP by reading the GPT partition table from the target disk after image copy, instead of relying on the Talos installer ([**@kvaps**](https://github.com/kvaps) in cozystack/boot-to-talos#16). + +* **[talm] Fix silent empty output when no template files are specified**: Running `talm template` without `--file` or `--template` flags previously produced minimal or empty output without any error. Validation has been added to `engine.Render` to return a clear error message when no template files are specified, making misconfigured invocations immediately apparent ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#112). + +## Documentation + +* **[website] Add documentation for VMInstance and VMDisk backups**: Added a new virtualization-focused Backup and Recovery guide covering one-off and scheduled backups for `VMInstance` and `VMDisk` resources, restore procedures, status verification commands, and troubleshooting notes including Velero-related issues ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#456). + +* **[website] Update developer guide with operator-driven architecture and OCIRepository migration flow**: Rewrote the development guide to describe the operator-driven in-cluster architecture, bootstrap flow, operator responsibilities, and the platform install/update sequence. Added an "OCIRepositories and Migration Flow" section with migration hook examples and sequencing rules for pre-upgrade hooks ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#458). + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.1.3...v1.1.4 diff --git a/docs/changelogs/v1.1.5.md b/docs/changelogs/v1.1.5.md new file mode 100644 index 00000000..e756bdd9 --- /dev/null +++ b/docs/changelogs/v1.1.5.md @@ -0,0 +1,13 @@ + + +## Fixes + +* **[platform] Prevent installed packages deletion**: Added the `helm.sh/resource-policy: keep` annotation to all platform packages. Previously, moving a package to `disabledPackages` or removing it from `enabledPackages` caused Helm to automatically delete it, contradicting the documented behavior that requires the platform administrator to manually delete packages when needed ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2273, #2298). + +* **[linstor] Fix TCP port mismatches after toggle-disk operations causing DRBD resources to enter StandAlone state**: During toggle-disk operations, `removeLayerData()` freed TCP ports from the number pool and `ensureStackDataExists()` could then allocate different ports. If a satellite missed the resulting update (e.g. due to a controller restart), it retained the old ports while peers received the new ones, causing DRBD connections to fail with StandAlone state. The fix introduces `copyDrbdTcpPortsIfExists()`, which preserves existing TCP ports in the `LayerPayload` before `removeLayerData()` releases them ([**@kvaps**](https://github.com/kvaps) in #2292, #2300). + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.1.4...v1.1.5 diff --git a/docs/changelogs/v1.1.6.md b/docs/changelogs/v1.1.6.md new file mode 100644 index 00000000..77c49475 --- /dev/null +++ b/docs/changelogs/v1.1.6.md @@ -0,0 +1,19 @@ + + +## Fixes + +* **[build] Filter git describe to match only v* tags**: Adds `--match 'v*'` to all `git describe` calls in `hack/common-envs.mk`. The `api/apps/v1alpha1/*` subtags share the same commit as release tags, causing `git describe --exact-match` to pick `api/apps/v1alpha1/vX.Y.Z` instead of `vX.Y.Z`, producing invalid Docker image tags ([**@kvaps**](https://github.com/kvaps) in #2386, #2388). + +## Development, Testing, and CI/CD + +* **[ci] Replace cozystack-bot PAT with cozystack-ci GitHub App**: Replaces the long-lived `cozystack-bot` personal access token with short-lived, scoped tokens from the `cozystack-ci` GitHub App across all release workflows. Improves security and auditability of CI operations ([**@tym83**](https://github.com/tym83) in #2351). + +* **[ci] Replace GH_PAT with cozystack-ci GitHub App token in pull-requests workflow**: Switches the pull-requests release workflow to use the cozystack-ci GitHub App token instead of the personal access token ([**@kvaps**](https://github.com/kvaps) in #2383). + +* **[ci] Use cozystack org noreply email for bot commits**: Updates CI workflows to use the cozystack organization noreply email for bot commits ([**@kvaps**](https://github.com/kvaps) in #2392). + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.1.5...v1.1.6 diff --git a/docs/changelogs/v1.2.0.md b/docs/changelogs/v1.2.0.md new file mode 100644 index 00000000..7c5b5e24 --- /dev/null +++ b/docs/changelogs/v1.2.0.md @@ -0,0 +1,204 @@ + + +# Cozystack v1.2.0 + +> **⚠️ WARNING: Do not use this release.** This version includes CloudNativePG operator, which updates the default PostgreSQL image to version 18. CNPG is unable to perform the migration from the previous major version automatically, which will cause PostgreSQL clusters to fail to start after the upgrade. Please use [v1.2.1](https://github.com/cozystack/cozystack/releases/tag/v1.2.1) instead. + +Cozystack v1.2.0 delivers significant platform enhancements: a fully managed **OpenSearch** service joining the application catalog, **VPC peering** for secure inter-tenant networking, tenant workload placement control via the new **SchedulingClass** system, a highly-available **VictoriaLogs cluster** replacing the single-node setup, and **Linstor volume relocation** for optimized clone and snapshot restore placement. Additional highlights include external-dns as a standalone extra package, multi-node RWX volume fixes, and a wave of dashboard and monitoring improvements. + +## Feature Highlights + +### OpenSearch: Managed Search and Analytics Service + +Cozystack now ships **OpenSearch** as a fully managed PaaS application — supporting OpenSearch v1, v2, and v3 in a multi-role topology with dedicated master, data, ingest, coordinating, and ML nodes. TLS is enabled by default, HTTP Basic auth is provided out of the box, and custom user definitions allow per-application credentials. The optional **OpenSearch Dashboards** UI can be enabled alongside the engine. External access, topology spread policies, and a comprehensive JSON schema are all included. + +A companion `opensearch-operator` system package wraps the upstream Opster OpenSearch Operator v2.8.0 and adds a sysctl DaemonSet to configure the required `vm.max_map_count` kernel parameter on every node automatically. An ApplicationDefinition package ties everything into the Cozystack platform dashboard with schema validation and resource management. + +### SchedulingClass: Tenant Workload Placement + +Cozystack now supports a **SchedulingClass** CRD that allows platform operators to define cluster-wide scheduling constraints — pinning tenant workloads to specific data centers, hardware generations, or node groups without requiring tenants to manage scheduler configuration themselves. Tenants declare a `schedulingClass` in their Tenant spec; the platform injects the appropriate `schedulerName` into all workloads in that namespace. + +The `lineage-controller-webhook` has been extended to verify the referenced SchedulingClass CR before injection, and child tenants inherit their parent's scheduling constraints (children cannot override). A **SchedulingClass dropdown** in the Tenant creation form in the dashboard makes the feature fully self-service. The underlying `cozystack-scheduler` — a custom kube-scheduler extension with SchedulingClass-aware affinity plugins — is now installed and enabled by default as part of the platform. + +### VPC Peering for Multi-Tenant Environments + +The `vpc` application gains bilateral **VPC peering** using Kube-OVN's native `vpcPeerings` mechanism, allowing tenants to securely interconnect their private networks without routing traffic through public endpoints. Peering link-local IPs (`169.254.0.0/16`) are allocated deterministically from a hash of the sorted VPC pair names, ensuring stable addresses across reconciliations. Static route support (`staticRoutes`) enables fine-grained inter-VPC routing policies. A `cozy-lib` helper (`hexToInt`) performs the deterministic IP allocation, and a JSON Schema validation enforces the `^tenant-` namespace pattern for peered VPCs. + +### VictoriaLogs: Clustered Mode for High Availability + +The platform's log storage has been upgraded from the deprecated single-node `VLogs` CR to a **VLCluster** deployment with separate vlinsert, vlselect, and vlstorage components, each running with 2 replicas by default — consistent with the existing VMCluster setup. This brings horizontal scalability and resilience to the logging tier. VPA autoscaling is enabled for all VLCluster components, and the victoria-metrics-operator has been upgraded from v0.55.0 to v0.68.1 to add VLCluster CRD support. + +### Linstor CSI: Volume Relocation After Clone and Restore + +The Linstor CSI driver now carries upstream patches enabling **automatic replica relocation** after PVC clone and snapshot restore operations. Two new parameters control the behavior: `linstor.csi.linbit.com/relocateAfterClone` on StorageClasses moves replicas to optimal nodes after a clone, and `snap.linstor.csi.linbit.com/relocate-after-restore` on VolumeSnapshotClasses does the same after a restore. VolumeSnapshotClasses for Velero and Kasten use cases are pre-configured. This enables full PVC-level backup and restore workflows with automatic data rebalancing, a key prerequisite for production Velero/Kasten integrations. + +## Major Features and Improvements + +* **[apps] Add managed OpenSearch service**: Deployed as a PaaS application supporting OpenSearch v1/v2/v3 with multi-role node topology, TLS, HTTP Basic auth, custom users, optional OpenSearch Dashboards UI, external access, and topology spread policies; backed by the opster OpenSearch Operator v2.8.0 and a sysctl DaemonSet for `vm.max_map_count` ([**@matthieu-robin**](https://github.com/matthieu-robin) in #1953). + +* **[vpc] Add VPC peering support for multi-tenant environments**: Bilateral VPC peering via Kube-OVN's `vpcPeerings`, deterministic link-local IP allocation from sorted VPC pair hash, static routes support, ConfigMap peer discovery enrichment, and JSON Schema validation enforcing `^tenant-` namespace pattern ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2152). + +* **[monitoring] Migrate VictoriaLogs from VLogs to VLCluster**: Replaced deprecated single-node `VLogs` CR with clustered `VLCluster` (vlinsert/vlselect/vlstorage, 2 replicas each), added VPA for all components, upgraded victoria-metrics-operator to v0.68.1 ([**@sircthulhu**](https://github.com/sircthulhu) in #2153). + +* **[scheduler] Integrate SchedulingClass support for tenant workloads**: Added `schedulingClass` Tenant parameter with inheritance enforcement, `scheduling.cozystack.io/class` namespace label, lineage-webhook extension to verify and inject `schedulerName`, SchedulingClass dropdown in Tenant dashboard form ([**@sircthulhu**](https://github.com/sircthulhu) in #2223). + +* **[cozystack-scheduler] Add custom scheduler as an optional system package**: Vendored `cozystack-scheduler` from github.com/cozystack/cozystack-scheduler — a kube-scheduler extension with SchedulingClass-aware affinity plugins, including Helm chart with RBAC, ConfigMap, Deployment, and CRD ([**@lllamnyp**](https://github.com/lllamnyp) in #2205). + +* **[platform] Enable cozystack-scheduler by default**: The cozystack-scheduler and SchedulingClass CRD are now installed as default system packages; the backup tool has been moved to optional packages ([**@lllamnyp**](https://github.com/lllamnyp) in #2253). + +* **[extra] Add external-dns as a standalone extra package**: Packaged external-dns as an installable extra (tenant-level) component for automatic DNS record management from Kubernetes Service and Ingress resources ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #1988). + +* **[linstor] Add linstor-csi patches for clone/snapshot relocation**: New patch enabling `relocateAfterClone` StorageClass parameter and `relocate-after-restore` VolumeSnapshotClass parameter; pre-configured VolumeSnapshotClasses for Velero and relocation workflows; CDI switched to csi-clone strategy ([**@kvaps**](https://github.com/kvaps) in #2133). + +* **[monitoring] Add inlineScrapeConfig support to tenant vmagent**: Tenants can now define inline scrape configurations directly in their VMAgent spec, enabling custom metrics collection from services that are not discoverable via standard Kubernetes service discovery ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2200). + +* **[monitoring] Add Slack dashboard URL, vmagent environment label, and dynamictext Grafana plugin**: Added `SLACK_DASHBOARD_URL` and `SLACK_SUMMARY_FMT` environment variables for richer alert notifications, per-vmagent `environment` label for metric source identification, and the `dynamictext-panel` plugin for Grafana dashboards ([**@vnyakas**](https://github.com/vnyakas) in #2210). + +* **[monitoring] Scope infrastructure dashboards to tenant-root only**: Infrastructure-level Grafana dashboards are now scoped to the tenant-root namespace only, preventing them from appearing in tenant sub-namespaces and reducing dashboard noise ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2197). + +* **[tenant] Allow egress to virt-handler for VM metrics scraping**: Extended tenant NetworkPolicy to permit egress to virt-handler pods, enabling Prometheus to scrape VM-level metrics from KubeVirt without additional policy exceptions ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2199). + +* **[dashboard] Add keycloakInternalUrl for backend-to-backend OIDC requests**: Added a `keycloakInternalUrl` platform value for the dashboard backend to perform OIDC token introspection via an internal cluster URL, avoiding external round-trips and improving reliability in air-gapped environments ([**@sircthulhu**](https://github.com/sircthulhu) in #2224). + +* **[dashboard] Add secret-hash annotation to KeycloakClient for secret sync**: Added a `secret-hash` annotation to the KeycloakClient resource so that changes to the client secret trigger automatic reconciliation and propagation to dependent components ([**@sircthulhu**](https://github.com/sircthulhu) in #2231). + +* **[docs] Add OpenAPI and Go types code generation for apps**: Added tooling to generate OpenAPI schemas and Go types from Helm chart values, enabling type-safe programmatic access to managed application configurations and automatic API reference generation ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2214). + +## Improvements (minor) + +* **[cozystack-scheduler] Update to v0.2.0**: Updated the cozystack-scheduler to v0.2.0 with improved SchedulingClass affinity handling ([**@lllamnyp**](https://github.com/lllamnyp) in #2244). + +* **[platform] Ensure cozystack-packages OCIRepository updates reliably**: Added configuration to ensure the `cozystack-packages` OCIRepository resource is consistently reconciled and reflects the latest package versions on upgrade ([**@sircthulhu**](https://github.com/sircthulhu) in #2246). + +* **[etcd] Add protective limits to defrag CronJob**: Added CPU and memory resource limits to the etcd defragmentation CronJob to prevent it from starving other workloads during scheduled defragmentation runs ([**@sircthulhu**](https://github.com/sircthulhu) in #2233). + +* **[platform] Add missing apps to tenant admin RBAC**: Extended the tenant admin ClusterRole to include RBAC permissions for recently added applications that were missing from the role binding ([**@sircthulhu**](https://github.com/sircthulhu) in #2268). + +## Bug Fixes + +* **[keycloak] Fix health probe configuration for Keycloak v26.x+**: Replaced deprecated `KC_PROXY=edge` with `KC_PROXY_HEADERS=xforwarded`/`KC_HTTP_ENABLED=true`; replaced liveness/readiness probes with management port endpoints (`/health/live`, `/health/ready`) and added a `startupProbe` to handle slow Keycloak startup without triggering premature restarts ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2162). + +* **[migrations] Handle missing RabbitMQ CRD in migration 34**: Fixed a crash in migration script 34 that occurred when the RabbitMQ CRD was not yet installed, allowing upgrades from environments where RabbitMQ was never deployed ([**@IvanHunters**](https://github.com/IvanHunters) in #2168). + +* **[platform] Fix VM MAC address not preserved during migration**: Fixed the `virtual-machine` to `vm-instance` migration script to correctly carry over the MAC address, preventing network identity changes after upgrading existing VM resources ([**@sircthulhu**](https://github.com/sircthulhu) in #2169). + +* **[dashboard] Fix External IPs factory EnrichedTable rendering**: Corrected the External IPs factory component to use the EnrichedTable renderer, resolving blank/broken rendering of the external IP address list in the dashboard ([**@IvanHunters**](https://github.com/IvanHunters) in #2175). + +* **[dashboard] Preserve disabled/hidden state on MarketplacePanel reconciliation**: Fixed a regression where MarketplacePanel reconciliation would reset the `disabled` and `hidden` flags set by operators, causing hidden applications to reappear in the catalog ([**@IvanHunters**](https://github.com/IvanHunters) in #2176). + +* **[dashboard] Exclude hidden MarketplacePanel resources from sidebar menu**: Fixed the sidebar to omit applications that have been hidden via MarketplacePanel flags, preventing inaccessible menu entries from being displayed to users ([**@IvanHunters**](https://github.com/IvanHunters) in #2177). + +* **[etcd-operator] Replace deprecated kube-rbac-proxy image**: Replaced the unmaintained `gcr.io/kubebuilder/kube-rbac-proxy` sidecar with the actively maintained `quay.io/brancz/kube-rbac-proxy` image to eliminate deprecation warnings and ensure continued security updates ([**@kvaps**](https://github.com/kvaps) in #2181). + +* **[backups] Fix RBAC and backupstrategy-controller location**: Corrected role bindings and the deployment location for the backup strategy controller to restore full backup and restore functionality ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2149). + +* **[api] Skip OpenAPI post-processor for non-apps group versions**: Fixed the API server to bypass OpenAPI schema post-processing for non-`apps` group versions, preventing schema corruption in unrelated API groups ([**@kvaps**](https://github.com/kvaps) in #2212). + +* **[bucket] Fix s3manager endpoint mismatch with COSI credentials**: Corrected the S3 Manager UI to use the actual S3 endpoint from the BucketInfo COSI resource rather than a hardcoded value, resolving connection failures when the S3 endpoint differs from the default ([**@IvanHunters**](https://github.com/IvanHunters) in #2211). + +* **[kubernetes] Fix tenant Kubernetes cluster creation for versions < 1.32**: Resolved a template rendering error that prevented creation of tenant Kubernetes clusters with versions older than 1.32 ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2209). + +* **[kube-ovn] Fix MASTER_NODES detection for multi-master Kubernetes clusters**: Updated kube-ovn configuration to discover control-plane nodes via the standard `node-role.kubernetes.io/control-plane` label rather than relying on static node lists, fixing OVN connectivity issues in multi-master generic Kubernetes deployments ([**@lexfrei**](https://github.com/lexfrei) in #2245). + +* **[kubernetes] Fix CiliumNetworkPolicy endpointSelector for multi-node RWX volumes**: Corrected the CiliumNetworkPolicy endpoint selector for NFS-based ReadWriteMany volumes to properly allow NFS traffic when data is spread across multiple Linstor storage nodes ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2227). + +* **[csi] Hide disk.img and lost+found from RWX NFS mounts**: Fixed the Linstor CSI NFS server to exclude internal files (`disk.img`, `lost+found`) from being visible inside NFS-mounted volumes, preventing application errors caused by unexpected files in volume root directories ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2243). + +* **[dashboard] Fix broken backup menu links missing cluster context**: Restored cluster context in backup-related sidebar navigation links, fixing 404 errors when navigating to BackupJob and Plan pages from the cluster-level dashboard view ([**@kvaps**](https://github.com/kvaps) in #2232). + +* **[dashboard] Fix StorageClass dropdown "Error" state by granting RBAC read access**: Added a ClusterRole/ClusterRoleBinding to grant authenticated users read access to StorageClass resources, resolving the "Error" state displayed in StorageClass dropdowns on application forms ([**@sircthulhu**](https://github.com/sircthulhu) in #2267). + +* **[postgres] Fix database deletion lifecycle management**: Added cleanup stages to delete databases and orphaned roles when removed from `values.databases`, enabling declarative database lifecycle management and preventing stale data retention ([**@sircthulhu**](https://github.com/sircthulhu) in #2247). + +* **[dashboard] Fix JSONPath crash on Tenant details with resourceQuotas**: Restored fallback protection for unresolved flatMap placeholders in the ResourceQuota "Used" column, preventing JSONPath parser crashes on the Tenant details page ([**@sircthulhu**](https://github.com/sircthulhu) in #2249). + +* **[system] Fix tenant RBAC for endpointslices read access**: Added `discovery.k8s.io/endpointslices` read permissions to tenant ClusterRoles, resolving 403 errors on the Service details page when displaying the "Pod serving" section ([**@sircthulhu**](https://github.com/sircthulhu) in #2257). + +* **[linstor] Fix swapped VMPodScrape job labels**: Corrected the `job` label relabeling in LINSTOR VictoriaMetrics PodScrape templates, fixing `linstorControllerOffline` alerts that incorrectly reported satellite endpoints as controller failures ([**@sasha-sup**](https://github.com/sasha-sup) in #2264). + +* **[piraeus-operator] Fix LINSTOR satellite alert labels and scrape flapping false positives**: Fixed non-existent `name` label in `linstorSatelliteErrorRate` alert annotations (changed to `hostname`) and prevented false positives caused by scrape flapping and stale metric counters ([**@sasha-sup**](https://github.com/sasha-sup) in #2265). + +* **[dashboard] Fix EndpointSlice column definitions for Pod serving table**: Added missing `CustomColumnsOverride` for the EndpointSlice table on service details page, replacing "Raw:" prefixes and "Invalid Date" values with proper Pod, Addresses, Ready, and Node columns ([**@sircthulhu**](https://github.com/sircthulhu) in #2266). + +## Dependencies & Version Updates + +* **[cilium] Update Cilium to v1.19.1**: Upgraded the Cilium CNI to v1.19.1 with latest bug fixes and performance improvements ([**@BROngineer**](https://github.com/BROngineer) in #2173). + +* **[keycloak-operator] Update to v1.32.0**: Updated the Keycloak Operator to v1.32.0 (based on epam/edp-keycloak-operator with upstream patches), bumping Keycloak to 26.5.2 ([**@lllamnyp**](https://github.com/lllamnyp) in #2206). + +* **[postgres-operator] Update to v1.27.3**: Upgraded the Postgres Operator (Patroni-based) to v1.27.3 with latest upstream fixes ([**@dmpopoff**](https://github.com/dmpopoff) in #2226). + +* **[objectstorage-controller] Update to v0.2.2, drop upstreamed patches**: Updated the object storage controller to v0.2.2 and removed patches that were accepted upstream, reducing the maintenance delta ([**@lexfrei**](https://github.com/lexfrei) in #2261). + +* **[kilo] Switch from fork to upstream squat/kilo**: Replaced the Cozystack-maintained Kilo fork with the upstream `squat/kilo` image now that required patches (`--internal-cidr`, allowed-location-ips fix, preferred source for WireGuard routes, Cilium IPIP overlay support) have been merged upstream ([**@lexfrei**](https://github.com/lexfrei) in #2259). + +* **[talos] Bump Talos to v1.12.6**: Updated the pinned Talos version to v1.12.6 ([**@kvaps**](https://github.com/kvaps) in #2254). + +* **[talm] Release v0.22.4** (github.com/cozystack/talm): Fixed `--file`/`--template` flag requirement to prevent ambiguous invocations ([**@kvaps**](https://github.com/kvaps) in cozystack/talm#112). + +* **[boot-to-talos] Release v0.7.0** (github.com/cozystack/boot-to-talos): Added support for ISO, RAW, and HTTP image sources ([**@lexfrei**](https://github.com/lexfrei) in cozystack/boot-to-talos#13); permanent MAC addresses for predictable interface names ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/boot-to-talos#14); detection and workaround for 5-level paging (LA57) incompatibility with kexec ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/boot-to-talos#15). + +* **[boot-to-talos] Release v0.7.1** (github.com/cozystack/boot-to-talos): Fixed EFI boot entry creation to use the target disk rather than relying on the installer disk, preventing boot failures on bare-metal systems ([**@kvaps**](https://github.com/kvaps) in cozystack/boot-to-talos#16). + +## Development, Testing, and CI/CD + +* **[tests] Stabilize E2E Kubernetes tests**: Comprehensive improvements to E2E test stability: pre-cleanup of leftover resources, fixes for port-forward race conditions and leaks, improved NFS PVC timeout and debug output, proper EXIT trap handling, and increased CAPI deployment timeouts ([**@lexfrei**](https://github.com/lexfrei) in #2262). + +* **[ci] Fix E2E check blocking docs-only PRs**: Moved path filtering to the job level so that documentation-only pull requests are not blocked by pending E2E CI checks ([**@IvanHunters**](https://github.com/IvanHunters) in #2170). + +* **[ci] Add timeout-minutes to Build and E2E jobs**: Added explicit `timeout-minutes` constraints to Build and E2E workflow jobs to prevent stuck runners from consuming CI resources indefinitely. + +## Documentation + +* **[website] Complete CA rotation documentation**: Added comprehensive CA certificate rotation procedures for all Cozystack system components ([**@kvaps**](https://github.com/kvaps) in cozystack/website#406). + +* **[website] Add Ansible automated installation guide**: Added a step-by-step guide for automated Cozystack installation using Ansible playbooks ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#442). + +* **[website] Add self-signed certificates configuration guide for OIDC**: Added documentation for configuring Cozystack to use self-signed TLS certificates with OIDC providers, covering certificate authority setup and kubeconfig integration ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/website#443). + +* **[website] Add custom metrics collection guide**: Added a guide explaining how to configure custom Prometheus scrape targets using the new `inlineScrapeConfig` feature of tenant VMAgent ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/website#444). + +* **[website] Add PackageSource/Package architecture to Key Concepts**: Documented the PackageSource and Package CRD architecture, explaining how operators extend the platform with custom application catalogs ([**@IvanHunters**](https://github.com/IvanHunters) in cozystack/website#445). + +* **[website] Add SchedulingClass operations guide**: Added a guide covering SchedulingClass CRD creation, tenant assignment, and workload placement verification ([**@lllamnyp**](https://github.com/lllamnyp) in cozystack/website#455). + +* **[website] Add VMInstance and VMDisk backups documentation**: Added user-facing documentation for backing up and restoring virtual machine instances and VM disk images using Velero ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#456). + +* **[website] Update developer guide**: Updated the developer guide with current build, test, and contribution workflows including OCIRepository and migration tooling ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#458). + +* **[website] Document keycloakInternalUrl platform value**: Added documentation explaining how to configure `keycloakInternalUrl` for backend-to-backend OIDC token introspection in cluster-internal environments ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#452). + +* **[website] Add DependenciesNotReady troubleshooting guide**: Added a troubleshooting article explaining how to diagnose and resolve the `DependenciesNotReady` package status condition ([**@kvaps**](https://github.com/kvaps) in cozystack/website#450). + +* **[website] Reorder installation steps for operator-before-platform**: Updated the installation guide to install the cozystack-operator before applying the platform package, reflecting the correct dependency order ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#449). + +* **[website] Update managed apps reference**: Updated the automatically generated managed applications reference documentation to reflect new apps and schema changes in this release ([**@app/github-actions**](https://github.com/apps/github-actions) in cozystack/website#448). + +* **[website] Update screenshots for Cozystack v1.1**: Refreshed dashboard screenshots to reflect the updated UI in Cozystack v1.1 ([**@kvaps**](https://github.com/kvaps) in cozystack/website#447). + +* **[website] Enhance operator backups guide**: Improved the backup and recovery guide for operators with additional recovery scenarios and procedures ([**@androndo**](https://github.com/androndo) in cozystack/website#440). + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@androndo**](https://github.com/androndo) +* [**@BROngineer**](https://github.com/BROngineer) +* [**@dmpopoff**](https://github.com/dmpopoff) +* [**@IvanHunters**](https://github.com/IvanHunters) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@lllamnyp**](https://github.com/lllamnyp) +* [**@mattia-eleuteri**](https://github.com/mattia-eleuteri) +* [**@matthieu-robin**](https://github.com/matthieu-robin) +* [**@myasnikovdaniil**](https://github.com/myasnikovdaniil) +* [**@sasha-sup**](https://github.com/sasha-sup) +* [**@sircthulhu**](https://github.com/sircthulhu) +* [**@tym83**](https://github.com/tym83) +* [**@vnyakas**](https://github.com/vnyakas) + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.1.0...v1.2.0 diff --git a/docs/changelogs/v1.2.1.md b/docs/changelogs/v1.2.1.md new file mode 100644 index 00000000..29e3fdf6 --- /dev/null +++ b/docs/changelogs/v1.2.1.md @@ -0,0 +1,31 @@ + + +## Features and Improvements + +* **[postgres] Hardcode PostgreSQL 17 for monitoring databases and add migration**: CloudNativePG operator defaults to PostgreSQL 18.3 when no explicit image is specified, but monitoring queries in Grafana and Alerta rely on PostgreSQL 17 features such as `pg_stat_checkpointer` and the updated `pg_stat_bgwriter`. This mismatch could break monitoring after fresh installs or database recreation. PostgreSQL 17.7 images are now hardcoded for monitoring databases, and migration 37 is added to set version v17 for any existing PostgreSQL resources ([**@IvanHunters**](https://github.com/IvanHunters) in #2304, #2309). + +## Fixes + +* **[platform] Prevent installed packages deletion**: Added the `helm.sh/resource-policy: keep` annotation to all platform packages. Previously, moving a package to `disabledPackages` or removing it from `enabledPackages` caused Helm to automatically delete the corresponding resource, contradicting the documented behavior that requires the platform administrator to manually delete packages when needed ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2273, #2297). + +* **[linstor] Preserve TCP ports during toggle-disk operations**: During toggle-disk operations, `removeLayerData()` freed TCP ports from the number pool and `ensureStackDataExists()` could then allocate different ports. If a satellite missed the resulting update (e.g. due to a controller restart), it retained the old ports while peers received the new ones, causing DRBD connections to fail with StandAlone state. The fix adds `copyDrbdTcpPortsIfExists()` which saves existing TCP ports into the `LayerPayload` before `removeLayerData()` deletes them ([**@kvaps**](https://github.com/kvaps) in #2292, #2299). + +* **[platform] Fix resource allocation ratios not propagated to managed packages**: A regression introduced in the bundle restructure caused `cpuAllocationRatio`, `memoryAllocationRatio`, and `ephemeralStorageAllocationRatio` set in `platform/values.yaml` to become no-ops — they were never written to the `cozystack-values` Secret that cozy-lib reads in child packages. This meant all managed applications silently used the hardcoded defaults (10, 1, 40) regardless of operator-configured values. The fix restores propagation by writing the ratios into the `_cluster` section of the `cozystack-values` Secret and passing `cpuAllocationRatio` to the KubeVirt Package component ([**@sircthulhu**](https://github.com/sircthulhu) in #2296, #2301). + +* **[linstor] Fix DRBD connectivity failures on kernels without `crct10dif` by setting verify-alg to `crc32c`**: LINSTOR's auto-verify algorithm selection defaults to `crct10dif`, but this kernel crypto module is no longer available in newer kernels (e.g. Talos v1.12.6, kernel 6.18.18). When `crct10dif` is unavailable, DRBD peer connections fail with `VERIFYAlgNotAvail: failed to allocate crct10dif for verify`, causing all DRBD resources to enter Diskless state and lose quorum. `DrbdOptions/Net/verify-alg` is now set to `crc32c` at the controller level ([**@kvaps**](https://github.com/kvaps) in #2303, #2312). + +* **[multus] Fix stale sandbox reservations permanently blocking pod creation after CNI ADD failure**: After a node disruption (e.g. DRBD or kube-ovn issues during upgrade), containerd accumulated stale sandbox name reservations. Cleanup failed because multus called delegate plugins for DEL without cached state and they rejected the incomplete config, causing DEL to fail instead of succeeding. Stale entries were never released, permanently blocking new pod creation on the affected node. A custom multus-cni image is now built with a patch that returns success from DEL when CNI ADD never completed ([**@kvaps**](https://github.com/kvaps) in #2313, #2314). + +* **[multus] Pin master CNI to `05-cilium.conflist` to prevent race condition at boot**: During node boot or Talos upgrade, multus auto-detects the master CNI conflist by scanning the CNI config directory. If kube-ovn writes `10-kube-ovn.conflist` before Cilium writes `05-cilium.conflist`, multus selects the wrong file and pods bypass the Cilium chain entirely, have no Cilium endpoint, and their traffic is blocked by cluster-wide network policies. `multusMasterCNI` is now pinned to `05-cilium.conflist` ([**@kvaps**](https://github.com/kvaps) in #2315, #2316). + +## Documentation + +* **[website] Add custom Keycloak themes documentation**: Added documentation for custom Keycloak theme injection to the White Labeling guide, covering the theme image contract (`/themes/` directory structure), configuration via the `cozystack.keycloak` Package resource, `imagePullSecrets` for private registries, and theme activation in the Keycloak admin console ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#463). + +* **[website] Add documentation for Go types usage**: Added a guide for using the generated Go types for Cozystack managed applications as a Go module, including installation instructions, programmatic resource management examples, and deployment approaches ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#465). + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.2.0...v1.2.1 diff --git a/docs/changelogs/v1.2.2.md b/docs/changelogs/v1.2.2.md new file mode 100644 index 00000000..2b6a1ae5 --- /dev/null +++ b/docs/changelogs/v1.2.2.md @@ -0,0 +1,63 @@ + + +## Features and Improvements + +* **[linstor] Update piraeus-server to v1.33.2 with selected backports**: Bumps LINSTOR server from v1.33.1 to v1.33.2 and adds backported patches for improved storage reliability: a stale bitmap adjust retry mechanism for automatic recovery after bitmap attach errors, LUKS2 header sizing and optimal I/O size detection improvements for more reliable disk formatting, and the maintainer implementation backport. All patches verified against upstream v1.33.2 with `git apply --check` and `gradlew compileJava` ([**@kvaps**](https://github.com/kvaps) in #2331, #2377). + +## Fixes + +* **[postgres] Fix system PostgreSQL images to 17.7-standard-trixie**: Hardcodes PostgreSQL 17.7-standard-trixie images for system PostgreSQL instances. This ensures system databases use the correct image variant consistent with the monitoring stack requirements introduced in v1.2.1 ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2364, #2369). + +* **[cilium] Opt-out of cri-containerd.apparmor.d for nsenter init containers**: On Ubuntu 22.04+, Debian, and other distributions that load the `cri-containerd.apparmor.d` AppArmor profile by default for containerd workloads, the kernel denied `nsenter` namespace entry in cilium-agent init containers (`mount-cgroup`, `apply-sysctl-overwrites`, `clean-cilium-state`), causing the agent to land in `Init:CrashLoopBackOff` and cascading platform failures. Per-container `container.apparmor.security.beta.kubernetes.io` annotations now opt the affected containers out of this profile, applied only on non-Talos cilium variants (`cilium-generic`, `kubeovn-cilium-generic`). The vendored daemonset template is also patched to strip the upstream `semverCompare "<1.30.0"` AppArmor block, preventing duplicate annotation keys. Talos variants are untouched as Talos does not load the AppArmor LSM ([**@lexfrei**](https://github.com/lexfrei) in #2370, #2378). + +* **[virtual-machine] Exclude external VM services from Cilium BPF LB**: Adds the `service.kubernetes.io/service-proxy-name: "cozy-proxy"` label to VM LoadBalancer services when `external: true`, telling Cilium to skip BPF processing entirely for these services. This fixes two issues: inter-tenant connectivity via public LB IPs (Cilium's DNAT caused cross-tenant pod-to-pod flow classification, triggering CiliumClusterwideNetworkPolicy blocks) and WholeIP broken on Cilium 1.19+ (wildcard service drop entries blocked traffic to LB IPs on undeclared ports before it reached netfilter/cozy-proxy). MetalLB L2 advertisement and kube-ovn routing remain unaffected ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2357, #2361). + +* **[monitoring] Fix infra dashboards missing in default variant**: The default platform variant deploys the monitoring chart to the `cozy-monitoring` namespace, but the dashboard rendering condition introduced in #2197 only checked for `tenant-root`. Infrastructure dashboards were not rendered in the default variant. The `cozy-monitoring` namespace is now included in the rendering condition, consistent with the existing pattern in `vmagent.yaml` ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2365, #2367). + +* **[build] Filter git describe to match only v* tags**: Adds `--match 'v*'` to all `git describe` calls in `hack/common-envs.mk`. The `api/apps/v1alpha1/*` subtags share the same commit as release tags, causing `git describe --exact-match` to pick `api/apps/v1alpha1/vX.Y.Z` instead of `vX.Y.Z`, producing invalid Docker image tags ([**@kvaps**](https://github.com/kvaps) in #2386, #2389). + +## Development, Testing, and CI/CD + +* **[ci] Replace cozystack-bot PAT with cozystack-ci GitHub App**: Replaces the long-lived `cozystack-bot` personal access token with short-lived, scoped tokens from the `cozystack-ci` GitHub App across all release workflows (`tags.yaml`, `auto-release.yaml`, `pull-requests-release.yaml`). Improves security and auditability of CI operations ([**@tym83**](https://github.com/tym83) in #2351). + +* **[ci] Use cozystack org noreply email for bot commits**: Updates CI workflows to use the cozystack organization noreply email for bot commits ([**@kvaps**](https://github.com/kvaps) in #2392, #2393). + +* **[ci] Replace GH_PAT with cozystack-ci GitHub App token in pull-requests workflow**: Switches the pull-requests release workflow to use the cozystack-ci GitHub App token instead of the personal access token ([**@kvaps**](https://github.com/kvaps) in #2383, #2384). + +## Documentation + +* **[website] Add ApplicationDefinition naming convention reference**: Added reference documentation on ApplicationDefinition naming conventions and how `cozystack-api` resolves kinds to their backing definitions ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#478). + +* **[website] Document Talos / talosctl / Cozystack version pairing**: Added documentation covering Talos, talosctl, and Cozystack version compatibility matrix for installation ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#484). + +* **[website] Fix KubeOVN MASTER_NODES example path and key in troubleshooting**: Corrected the MASTER_NODES example path and key in the KubeOVN troubleshooting guide ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#483). + +* **[website] Prefix bundle package names with cozystack. in v1 examples**: Updated documentation examples to use the correct `cozystack.` prefix for bundle package names in enabled/disabledPackages ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#482). + +* **[website] Finish isolated-field removal and document opt-in policy labels**: Removed the obsolete `isolated` field from tenant documentation and documented the new opt-in policy labels approach ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#481). + +* **[website] Add --take-ownership flag and describe networking.* fields**: Added documentation for the `--take-ownership` flag and described the `networking.*` fields in the installation guide ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#480). + +* **[website] Add bonding (LACP) configuration how-to guide**: Added a guide for configuring network bonding with LACP on Cozystack installations ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#459). + +* **[website] Improve registry mirrors for tenant Kubernetes in air-gapped guide**: Improved documentation for configuring registry mirrors in tenant Kubernetes clusters for air-gapped environments ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#461). + +* **[website] Update backup/restore documentation for VMI/VMDisk**: Updated backup documentation with information related to VM instance and VM disk restore improvements ([**@androndo**](https://github.com/androndo) in cozystack/website#466). + +* **[website] Add updated OpenAPI spec**: Updated the OpenAPI specification for managed applications reference ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#469). + +* **[website] Add OSS Health pages and OpenSSF badge**: Added OSS Health section with OpenSSF Scorecard and Best Practices badge to the website footer ([**@tym83**](https://github.com/tym83) in cozystack/website#470). + +* **[website] Add CozySummit Virtual 2026 program announcement**: Published the CozySummit Virtual 2026 program announcement blog post ([**@tym83**](https://github.com/tym83) in cozystack/website#472). + +* **[website] Add missing release announcements for v0.1–v0.41**: Backfilled missing release announcement blog posts for Cozystack versions v0.1 through v0.41 ([**@tym83**](https://github.com/tym83) in cozystack/website#468). + +* **[talm] Render templates online in apply to resolve lookups**: Fixed talm `apply` command to render templates online, resolving template lookup failures when using modeline templates ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/talm#119). + +* **[talm] Update default Talos image to v1.12.6**: Updated the default Talos image version to v1.12.6 in talm ([**@kvaps**](https://github.com/kvaps) in cozystack/talm@03e9b6e). + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.2.1...v1.2.2 diff --git a/docs/changelogs/v1.2.3.md b/docs/changelogs/v1.2.3.md new file mode 100644 index 00000000..6d1b3b74 --- /dev/null +++ b/docs/changelogs/v1.2.3.md @@ -0,0 +1,58 @@ + + +# v1.2.3 (2026-04-20) + +A patch release with bug fixes and documentation updates. + +## Features and Improvements + +_No notable features in this patch release._ + +## Fixes + +* **fix(kubernetes): set explicit ephemeral-storage on virt-launcher pods**: Prevents VM crashes caused by ephemeral-storage eviction by setting explicit `domain.resources` ephemeral-storage on the VirtualMachine spec. Uses sanitized limits and requests so virt-launcher pods do not inherit too-small namespace defaults. ([**@kvaps**](https://github.com/kvaps) in #2317, backport #2423). + +## Documentation + +* **[website] feat: add Telemetry page under OSS Health section**: Add Telemetry page and initial data seeding to OSS Health docs ([**@tym83**](https://github.com/tym83) in cozystack/website#471). +* **[website] Refactor docs versions to major.minor variants**: Move docs to major.minor versioning for v1.x series ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#477). +* **[website] docs(tenants): document namespace layout and parent/child derivation** ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#479). +* **[website] docs(tenants): document the checkbox-then-edit-CR customization pattern** ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#485). +* **[website] docs: fix 14 broken links and stale talm anchor across v1 docs** ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#486). +* **[website] fix(og): update social badge image and title** ([**@tym83**](https://github.com/tym83) in cozystack/website#487). +* **[website] docs(external-apps): rewrite guide for ApplicationDefinition API** ([**@kitsunoff**](https://github.com/kitsunoff) in cozystack/website#488). +* **[website] docs: add CLAUDE.md for AI agent guidance** ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#489). +* **[website] fix: update /docs/v1/ redirect to latest v1.2** ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#492). +* **[website] fix(ci): add OpenAPI spec download to GitHub Pages build** ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#494). +* **[website] feat(blog): add managed PostgreSQL with synchronous replication post** ([**@tym83**](https://github.com/tym83) in cozystack/website#497). +* **[website] chore(blog): add images frontmatter for social preview on existing posts** ([**@tym83**](https://github.com/tym83) in cozystack/website#498). +* **[website] feat(blog): taxonomies and client-side filter UI** ([**@tym83**](https://github.com/tym83) in cozystack/website#499). +* **[website] style(oss-health): add breathing room between navbar and hero** ([**@tym83**](https://github.com/tym83) in cozystack/website#500). + +## Other repositories + +* **[talm] feat(config): migrate to Talos v1.12 multi-document config format**: Upgrade Talos config format and modernize configuration handling ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm#116). +* **[talm] chore(deps): bump dependencies and modernize codebase** ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm#124). +* **[external-apps-example] feat: replace MongoDB example with Minecraft apps from cozylex** ([**@lexfrei**](https://github.com/lexfrei) in cozystack/external-apps-example#2). +* **[ansible-cozystack] fix(examples): add v prefix to collection version in requirements.yml** ([**@lexfrei**](https://github.com/lexfrei) in cozystack/ansible-cozystack#23). +* **[ansible-cozystack] fix(plugins): replace ansible.utils.ipaddr with stdlib-based test plugin** ([**@lexfrei**](https://github.com/lexfrei) in cozystack/ansible-cozystack#24). +* **[ansible-cozystack] feat(examples): comprehensive node prerequisites audit (fixes #19)** ([**@lexfrei**](https://github.com/lexfrei) in cozystack/ansible-cozystack#27). +* **[ansible-cozystack] chore(deps): update dependency cozystack.installer to v1.2.3** ([**@app/renovate**](https://github.com/apps/renovate) in cozystack/ansible-cozystack#29). +* **[ansible-cozystack] feat(role): expose publishing.externalIPs and tenant-root ingress via role variables** ([**@lexfrei**](https://github.com/lexfrei) in cozystack/ansible-cozystack#30). + +## Contributors + +Thanks to everyone who contributed to this patch release: + +* [**@app/github-actions**](https://github.com/apps/github-actions) +* [**@app/renovate**](https://github.com/apps/renovate) +* [**@kitsunoff**](https://github.com/kitsunoff) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@myasnikovdaniil**](https://github.com/myasnikovdaniil) +* [**@tym83**](https://github.com/tym83) + + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.2.2...v1.2.3 diff --git a/docs/changelogs/v1.3.0-rc.1.md b/docs/changelogs/v1.3.0-rc.1.md new file mode 100644 index 00000000..9b63c106 --- /dev/null +++ b/docs/changelogs/v1.3.0-rc.1.md @@ -0,0 +1,173 @@ + + +# Cozystack v1.3.0-rc.1 + +Cozystack v1.3.0-rc.1 is the first release candidate for v1.3.0, bringing **storage-aware scheduling** via the LINSTOR scheduler extender, a managed **LINSTOR GUI** web UI with Keycloak SSO, a **VM Default Images** catalog for out-of-the-box virtual machine provisioning, **WorkloadsReady conditions** with a real-time Events tab in the dashboard, and **cross-namespace VM backup restore** capabilities. Additional highlights include stricter tenant name validation, VM network selector improvements, Keycloak theme injection and SMTP configuration, and a comprehensive host runtime preflight check. + +> **Note:** Fixes marked with *(backported to v1.2.x)* were also included in v1.2.1 or v1.2.2 patch releases. + +## Feature Highlights + +### Storage-Aware Scheduling via LINSTOR Extender + +The `cozystack-scheduler` now calls the **LINSTOR scheduler extender** for storage-locality-aware pod placement. When a pod declares both a `SchedulingClass` and LINSTOR-backed PVCs, the scheduler consults LINSTOR to prefer nodes where volume replicas already exist — reducing cross-node replication traffic and improving I/O latency for storage-heavy workloads ([**@lllamnyp**](https://github.com/lllamnyp) in #2330). + +### LINSTOR GUI: Managed Web UI for Storage Administration + +A new opt-in `linstor-gui` system package deploys **LINBIT's linstor-gui web UI** alongside the LINSTOR controller with mTLS client authentication, non-root security context, and ClusterIP-only service. An optional **Keycloak-protected Ingress** (via oauth2-proxy) can be enabled for SSO-authenticated browser access when OIDC is configured on the platform ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2382, #2390). + +### VM Default Images: Out-of-the-Box VM Provisioning + +The new `vm-default-images` package provides a curated set of **cluster-wide virtual machine images** (Ubuntu, Debian, CentOS Stream, and others) as pre-populated DataVolumes. The package is opt-in via the `iaas` bundle and defaults to replicated storage for high availability. A companion migration (migration 38) renames legacy `vm-image-*` DataVolumes to the new `vm-default-images-*` naming scheme. The `vm-disk` chart also gains a new "disk" source type for cloning from existing vm-disks in the same namespace ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2258). + +### WorkloadsReady Condition and Events Tab + +Applications now expose a **WorkloadsReady** condition on their status by querying associated WorkloadMonitor resources, giving operators a single place to check whether all underlying workloads (Deployments, StatefulSets, DaemonSets) are healthy. The dashboard gains a new **Events tab** showing namespace-scoped Kubernetes events for each application, with fallback to `.firstTimestamp` when `.eventTime` is absent. A bug where WorkloadMonitor's `Operational` status was never persisted is also fixed ([**@lexfrei**](https://github.com/lexfrei) in #2356). + +### Cross-Namespace VM Backup Restore + +The backup system now supports **restoring VMInstance backups into a different namespace** (cross-namespace copy restores), with IP/MAC preservation and safe rename semantics. In-place backup/restores for VMDisk and VMInstance are improved: HelmReleases and DataVolumes are properly handled, and Velero failure messages are propagated to the Application status. The backup status structure has been refactored to store underlying resources as a generic opaque JSON object, enabling arbitrary application-specific metadata ([**@androndo**](https://github.com/androndo) in #2251, #2329, #2319). + +## Major Features and Improvements + +* **[api] Reject tenant names with dashes at Create time**: Enforces alphanumeric-only naming for Tenants at the API level, preventing names with hyphens that would silently fail during Helm reconciliation. A corresponding regex tightening and regression test suite hardens the validation ([**@lexfrei**](https://github.com/lexfrei) in #2380). + +* **[platform] Validate computed tenant namespace length**: Rejects Tenant creation when the computed ancestor-chain namespace would exceed the 63-character Kubernetes namespace limit, preventing opaque HelmRelease reconcile errors downstream ([**@lexfrei**](https://github.com/lexfrei) in #2376). + +* **[vm-instance] Rename subnets to networks and add dropdown selector**: Renames the misleading `subnets` field to `networks` in VMInstance for clarity, adds a dropdown selector for available networks in the dashboard form, and includes a migration to copy existing `subnets` values. The old field remains supported for backward compatibility ([**@sircthulhu**](https://github.com/sircthulhu) in #2263). + +* **[keycloak] Enable injecting themes**: Cozystack administrators can now inject custom Keycloak themes via `initContainers` for UI white-labeling and customization ([**@lllamnyp**](https://github.com/lllamnyp) in #2142). + +* **[keycloak-configure] Add email verification and SMTP configuration**: Adds configurable Keycloak settings for user self-registration, email verification, and SMTP server configuration, enabling automated user onboarding flows ([**@BROngineer**](https://github.com/BROngineer) in #2318). + +* **[postgres] Hardcode PostgreSQL 17 for monitoring databases**: Pins PostgreSQL 17.7 images for system databases (Grafana, Alerta, Harbor, Keycloak, SeaweedFS) and adds migration 37 to backfill `spec.version=v17` for existing PostgreSQL resources, preventing CNPG from defaulting to PostgreSQL 18 *(backported to v1.2.1)* ([**@IvanHunters**](https://github.com/IvanHunters) in #2304). + +* **[hack] Add host runtime preflight check**: New `check-host-runtime.sh` script and `make preflight` target that warns operators when a standalone containerd or docker runtime is running alongside the embedded k3s runtime, helping diagnose container runtime conflicts ([**@lexfrei**](https://github.com/lexfrei) in #2371). + +* **[hack] Add check-readiness.sh diagnostic script**: A new diagnostic script for tracking platform reconciliation by checking readiness of Packages, ArtifactGenerators, ExternalArtifacts, and HelmReleases, with support for watch mode and continuous monitoring ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2294). + +* **[mariadb] Always enable replication for consistent service naming**: MariaDB now always enables replication, creating `-primary`/`-secondary` services even for single-replica instances. This fixes dashboard visibility and backup functionality for single-replica setups ([**@sircthulhu**](https://github.com/sircthulhu) in #2279). + +* **[platform] Prevent installed packages deletion**: Adds `helm.sh/resource-policy: keep` annotation to packages, preventing automatic deletion when packages are disabled and restoring documented behavior *(backported to v1.2.1)* ([**@kvaps**](https://github.com/kvaps) in #2273). + +## Bug Fixes + +* **[cilium] Opt-out of cri-containerd.apparmor.d for nsenter init containers**: Opts cilium-agent init containers out of the `cri-containerd.apparmor.d` AppArmor profile on non-Talos variants, fixing `Init:CrashLoopBackOff` on Ubuntu 22.04+ and Debian *(backported to v1.2.2)* ([**@lexfrei**](https://github.com/lexfrei) in #2370). + +* **[virtual-machine] Exclude external VM services from Cilium BPF LB**: Adds `service-proxy-name: cozy-proxy` label to VM LoadBalancer services, telling Cilium to skip BPF processing. Fixes inter-tenant connectivity via public LB IPs and WholeIP functionality on Cilium 1.19+ *(backported to v1.2.2)* ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2357). + +* **[monitoring] Fix infra dashboards missing in default variant**: Includes `cozy-monitoring` namespace in the dashboard rendering condition, fixing infrastructure Grafana dashboards not rendering in the default platform variant *(backported to v1.2.2)* ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2365). + +* **[postgres] Fix system PostgreSQL images to 17.7-standard-trixie**: Normalizes system PostgreSQL image tags to use `17.7-standard-trixie` variant with migration logic for existing CNPG clusters *(backported to v1.2.2)* ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2364). + +* **[build] Filter git describe to match only v\* tags**: Adds `--match 'v*'` to `git describe` calls, preventing API subtags from being picked up instead of release tags and producing invalid Docker image tags *(backported to v1.2.2)* ([**@kvaps**](https://github.com/kvaps) in #2386). + +* **[platform] Fix resource allocation ratios not propagated to packages**: Restores propagation of CPU, memory, and ephemeral-storage allocation ratios to managed applications and KubeVirt, which were silently ignored since the bundle restructure *(backported to v1.2.1)* ([**@sircthulhu**](https://github.com/sircthulhu) in #2296). + +* **[kubernetes] Set explicit ephemeral-storage on virt-launcher pods**: Sets explicit `domain.resources` with ephemeral-storage on VirtualMachine spec to prevent virt-launcher pods from being evicted due to LimitRange defaults being too low for actual emptyDisk capacity ([**@kvaps**](https://github.com/kvaps) in #2317). + +* **[multus] Pin master CNI to 05-cilium.conflist**: Prevents a boot-time race condition where multus could auto-detect kube-ovn's conflist instead of Cilium's *(backported to v1.2.1)* ([**@kvaps**](https://github.com/kvaps) in #2315). + +* **[multus] Build custom image with DEL cache fix**: Fixes sandbox cleanup deadlock when CNI ADD never completes, preventing stale sandbox name reservations from permanently blocking pod creation *(backported to v1.2.1)* ([**@kvaps**](https://github.com/kvaps) in #2313). + +* **[linstor] Set verify-alg to crc32c**: Prevents DRBD connection failures on kernels where `crct10dif` is unavailable (e.g., Talos v1.12.6 with kernel 6.18.18) *(backported to v1.2.1)* ([**@kvaps**](https://github.com/kvaps) in #2303). + +* **[linstor] Preserve TCP ports during toggle-disk operations**: Fixes TCP port mismatches after toggle-disk operations that could cause DRBD resources to enter StandAlone state *(backported to v1.2.1)* ([**@kvaps**](https://github.com/kvaps) in #2292). + +## Dependencies & Version Updates + +* **[linstor] Update piraeus-server to v1.33.2 with selected backports**: Bumps LINSTOR server from v1.33.1 to v1.33.2 with backported patches for stale bitmap adjust retry, LUKS2 header sizing, and optimal I/O size detection *(backported to v1.2.2)* ([**@kvaps**](https://github.com/kvaps) in #2331). + +* **[kamaji] Update to 26.3.5-edge, drop upstreamed patches**: Updates Kamaji from edge-26.2.4 to 26.3.5-edge and removes two patches accepted upstream. Adds configurable probe tuning and DataStore readiness conditions ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2260). + +* **[talm] Release v0.23.0, v0.23.1, v0.24.0** (github.com/cozystack/talm): Migrates to the Talos v1.12 multi-document machine config format ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm#116); fixes template rendering in `apply` command to resolve lookups ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/talm#119); bumps dependencies and modernizes codebase ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm#124). + +* **[ansible-cozystack] Release v1.2.1, v1.2.2** (github.com/cozystack/ansible-cozystack): Exposes `publishing.externalIPs` and tenant-root ingress via role variables ([**@lexfrei**](https://github.com/lexfrei) in cozystack/ansible-cozystack#30); adds comprehensive node prerequisites audit ([**@lexfrei**](https://github.com/lexfrei) in cozystack/ansible-cozystack#27); replaces `ansible.utils.ipaddr` with a stdlib-based test plugin ([**@lexfrei**](https://github.com/lexfrei) in cozystack/ansible-cozystack#24). + +## Security + +* **docs: add SECURITY.md**: Adds vulnerability reporting procedures, disclosure expectations, and supported release lines ([**@kvaps**](https://github.com/kvaps) in #2230). + +* **docs: add OpenSSF Best Practices badge to README**: Adds the OpenSSF Best Practices passing badge to the project README ([**@lexfrei**](https://github.com/lexfrei) in #2320). + +## Development, Testing, and CI/CD + +* **[ci] Replace cozystack-bot PAT with cozystack-ci GitHub App**: Replaces the long-lived cozystack-bot personal access token with short-lived, scoped tokens from the cozystack-ci GitHub App across all CI release workflows ([**@tym83**](https://github.com/tym83) in #2351; [**@kvaps**](https://github.com/kvaps) in #2383, #2392). + +* **[ci] Add Gemini Code Assist and CodeRabbit configuration**: Adds repository-level configuration for AI code reviewers with ignore patterns for vendored/generated code and incremental review settings ([**@lexfrei**](https://github.com/lexfrei) in #2385). + +* **[ci] Make tags workflow idempotent on re-runs**: Fixes CI to force-update API subtags and handle re-runs gracefully ([**@kvaps**](https://github.com/kvaps)). + +* **[tests] Fix Kafka E2E test timeout and retry race condition**: Increases Kafka E2E test timeout from 60s to 300s and fixes a retry race condition where `kubectl apply` could hit a still-deleting resource ([**@lexfrei**](https://github.com/lexfrei) in #2358). + +* **docs: adopt Conventional Commits for commit and PR titles**: Standardizes commit and PR title format to `type(scope): description` across all contributing docs and the PR template ([**@lexfrei**](https://github.com/lexfrei) in #2395). + +* **docs(ci): require screenshots for UI changes in PR template**: Adds a mandatory screenshots section to the PR template for UI-related changes ([**@kitsunoff**](https://github.com/kitsunoff) in #2407). + +## Documentation + +* **[website] Add ApplicationDefinition naming convention reference**: Documents how `cozystack-api` resolves kinds to their backing definitions ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#478). + +* **[website] Document Talos / talosctl / Cozystack version pairing**: Adds version compatibility matrix for installation ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#484). + +* **[website] Document namespace layout and parent/child derivation**: Explains tenant namespace hierarchy and parent/child namespace derivation rules ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#479). + +* **[website] Document the checkbox-then-edit-CR customization pattern for tenants**: Describes the workflow for customizing tenant settings via the CR after initial checkbox-based creation ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#485). + +* **[website] Add custom Keycloak themes documentation**: Covers the theme image contract, configuration, `imagePullSecrets`, and theme activation in the Keycloak admin console ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#463). + +* **[website] Add bonding (LACP) configuration how-to guide**: Covers network bonding configuration for Cozystack installations ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#459). + +* **[website] Improve registry mirrors for tenant Kubernetes in air-gapped guide**: Improved documentation for configuring registry mirrors in air-gapped environments ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#461). + +* **[website] Rewrite guide for ApplicationDefinition API (external-apps)**: Comprehensive rewrite of the external apps guide using the ApplicationDefinition API ([**@kitsunoff**](https://github.com/kitsunoff) in cozystack/website#488). + +* **[website] Add documentation for Go types usage**: Guide for using generated Go types for Cozystack managed applications as a Go module ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#465). + +* **[website] Update backup/restore documentation for VMI/VMDisk**: Updated backup documentation with VM instance and VM disk restore improvements ([**@androndo**](https://github.com/androndo) in cozystack/website#466). + +* **[website] Add OSS Health pages and OpenSSF badge**: Added OSS Health section with OpenSSF Scorecard and Best Practices badge to the website ([**@tym83**](https://github.com/tym83) in cozystack/website#470). + +* **[website] Add CozySummit Virtual 2026 program announcement**: Published the CozySummit Virtual 2026 program announcement blog post ([**@tym83**](https://github.com/tym83) in cozystack/website#472). + +* **[website] Add missing release announcements for v0.1–v0.41**: Backfilled missing release announcement blog posts for historical Cozystack versions ([**@tym83**](https://github.com/tym83) in cozystack/website#468). + +* **[website] Fix broken links and stale anchors across v1 docs**: Fixes 14 broken links and stale talm anchors ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#486). + +* **[website] Prefix bundle package names with cozystack. in v1 examples**: Corrects package naming in documentation examples ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#482). + +* **[website] Finish isolated-field removal and document opt-in policy labels**: Removes obsolete `isolated` field from tenant documentation and documents the new approach ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#481). + +* **[website] Add --take-ownership flag and describe networking.* fields**: Documents the `--take-ownership` flag and `networking.*` fields in the installation guide ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#480). + +* **[website] Fix KubeOVN MASTER_NODES example path and key in troubleshooting**: Corrects the MASTER_NODES example path ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#483). + +* **[external-apps-example] Replace MongoDB example with Minecraft apps**: Refactors the external apps example to use ApplicationDefinition API with Minecraft server applications ([**@lexfrei**](https://github.com/lexfrei) in cozystack/external-apps-example#2). + +## Governance + +* **Add Mattia Eleuteri ([@mattia-eleuteri](https://github.com/mattia-eleuteri)) as Maintainer**: CSI, Storage, Networking & Security ([**@tym83**](https://github.com/tym83) in #2345). + +* **Add Matthieu Robin ([@matthieu-robin](https://github.com/matthieu-robin)) as Maintainer**: Managed applications, platform quality, and benchmarking ([**@tym83**](https://github.com/tym83) in #2346). + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@androndo**](https://github.com/androndo) +* [**@BROngineer**](https://github.com/BROngineer) +* [**@IvanHunters**](https://github.com/IvanHunters) +* [**@kitsunoff**](https://github.com/kitsunoff) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@lllamnyp**](https://github.com/lllamnyp) +* [**@mattia-eleuteri**](https://github.com/mattia-eleuteri) +* [**@myasnikovdaniil**](https://github.com/myasnikovdaniil) +* [**@sircthulhu**](https://github.com/sircthulhu) +* [**@tym83**](https://github.com/tym83) + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.2.0...v1.3.0-rc.1 diff --git a/docs/changelogs/v1.3.0.md b/docs/changelogs/v1.3.0.md new file mode 100644 index 00000000..60c800a8 --- /dev/null +++ b/docs/changelogs/v1.3.0.md @@ -0,0 +1,238 @@ + + +# Cozystack v1.3.0 + +Cozystack v1.3.0 brings **storage-aware pod scheduling** via a LINSTOR scheduler extender, a managed **LINSTOR GUI** web console with Keycloak SSO, a curated **VM Default Images** catalog for out-of-the-box virtual-machine provisioning, a new **WorkloadsReady / Events** observability surface with S3 bucket metering, and **cross-namespace VMInstance backup restore** with a full **RestoreJob dashboard** flow. The release also ships stricter tenant-name validation, VMInstance network-selector improvements, Keycloak theme injection and SMTP configuration, a host-runtime preflight check, and rolls up every fix from the v1.2.1 → v1.2.4 patch line. + +> **Note:** Items marked *(backported to v1.2.x)* were also shipped in v1.2.1, v1.2.2, v1.2.3, or v1.2.4 patch releases. + +## Feature Highlights + +### Storage-Aware Scheduling via the LINSTOR Extender + +The `cozystack-scheduler` now calls a **LINSTOR scheduler extender** for storage-locality-aware pod placement. When a pod declares both a `SchedulingClass` and LINSTOR-backed PVCs, the scheduler consults LINSTOR to prefer nodes where volume replicas already exist — reducing cross-node replication traffic and improving I/O latency for storage-heavy workloads such as databases, object stores, and VMs. + +The integration builds on the existing `SchedulingClass` tenant workload placement system introduced in v1.2.0 and requires no tenant-side configuration — workloads simply benefit once a SchedulingClass is assigned. Administrators can mix storage locality with the existing data-center / hardware-generation constraints defined on SchedulingClass CRs ([**@lllamnyp**](https://github.com/lllamnyp) in #2330). + +### LINSTOR GUI: Managed Web Console for Storage Administration + +A new opt-in `linstor-gui` system package deploys **LINBIT's linstor-gui web UI** alongside the LINSTOR controller with mTLS client authentication, non-root security context, and a ClusterIP-only service by default. When OIDC is configured on the platform, an optional **Keycloak-protected Ingress** (via oauth2-proxy) exposes the UI for browser access. Access is restricted to members of the `cozystack-cluster-admin` Keycloak group, consistent with host-cluster admin RBAC, and the gatekeeper blocks in-app LINSTOR authentication setup at the nginx proxy layer so the managed configuration cannot be subverted through the UI. + +Operators who prefer CLI access keep the existing `linstor` command; the GUI is strictly additive and stays disabled by default ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2382, #2390, #2415, #2419). + +### VM Default Images: Out-of-the-Box VM Provisioning + +The new `vm-default-images` package provides a curated set of **cluster-wide virtual-machine images** (Ubuntu, Debian, CentOS Stream, and others) as pre-populated DataVolumes, so tenants can provision VMs against well-known base images without first having to upload them. The package is opt-in via the `iaas` bundle and defaults to replicated storage for high availability. Migration 38 renames legacy `vm-image-*` DataVolumes to the new `vm-default-images-*` naming scheme, and the `vm-disk` chart gains a new "disk" source type for cloning from existing vm-disks in the same namespace ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2258). + +### Application Observability: WorkloadsReady, Events, and S3 Bucket Metering + +Applications now expose a **WorkloadsReady** condition on their status by querying associated WorkloadMonitor resources, giving operators a single place to check whether all underlying workloads (Deployments, StatefulSets, DaemonSets, PVCs) are healthy. The dashboard gains a new **Events tab** showing namespace-scoped Kubernetes events per application, with fallback to `.firstTimestamp` when `.eventTime` is absent. A long-standing bug where WorkloadMonitor's `Operational` status was never persisted is fixed in the same change ([**@lexfrei**](https://github.com/lexfrei) in #2356). + +The WorkloadMonitor reconciler is extended to track **COSI BucketClaim** objects as first-class Workloads, and the bucket controller now queries SeaweedFS logical and physical bucket-size metrics from VictoriaMetrics via a namespace-scoped monitoring endpoint, enabling S3 billing integration on par with Pods and PVCs ([**@kitsunoff**](https://github.com/kitsunoff) in #2391). Workloads are also enriched with `workloads.cozystack.io/resource-preset` and source-object labels so downstream billing pipelines can correlate monitors with the tenant preset that produced them ([**@androndo**](https://github.com/androndo) in #2416). + +### Cross-Namespace VM Backup Restore and RestoreJob Dashboard + +The backup system now supports **restoring VMInstance backups into a different namespace** (cross-namespace copy restores) with IP/MAC preservation and safe rename semantics. In-place backup and restore flows for VMDisk and VMInstance are improved: HelmReleases and DataVolumes are properly handled, and Velero failure messages are propagated to the Application status. The backup status structure has been refactored to store underlying resources as a generic opaque JSON object, enabling arbitrary application-specific metadata without status-schema churn ([**@androndo**](https://github.com/androndo) in #2251, #2319, #2329). + +The dashboard now ships a complete **RestoreJob experience**: list view, details page, create form, and sidebar entry, with a "Same as backup" fallback rendering when `spec.targetApplicationRef` is omitted. Non-CRD-backed sidebar factories (`kube-*`, `plan`, `backupjob`, `backup`, `restorejob`) are marked static so they pick up consistent managed-by labels across reconciles ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2437). + +## Major Features and Improvements + +* **[api] Reject tenant names with dashes at Create time**: Enforces alphanumeric-only naming for Tenants at the API level, preventing names with hyphens that would silently fail during Helm reconciliation. A corresponding regex tightening and regression test suite hardens the validation ([**@lexfrei**](https://github.com/lexfrei) in #2380). + +* **[platform] Validate computed tenant namespace length**: Rejects Tenant creation when the computed ancestor-chain namespace would exceed the 63-character Kubernetes namespace limit, preventing opaque HelmRelease reconcile errors downstream ([**@lexfrei**](https://github.com/lexfrei) in #2376). + +* **[vm-instance] Rename subnets to networks and add dropdown selector**: Renames the misleading `subnets` field to `networks` in VMInstance for clarity, adds a dropdown selector for available networks in the dashboard form, and includes migration 36 to copy existing `subnets` values. The old field remains supported for backward compatibility ([**@sircthulhu**](https://github.com/sircthulhu) in #2263). + +* **[keycloak] Enable injecting themes**: Cozystack administrators can now inject custom Keycloak themes via `initContainers` for UI white-labeling and customization ([**@lllamnyp**](https://github.com/lllamnyp) in #2142). + +* **[keycloak-configure] Add email verification and SMTP configuration**: Adds configurable Keycloak settings for user self-registration, email verification, and SMTP server configuration, enabling automated user onboarding flows ([**@BROngineer**](https://github.com/BROngineer) in #2318). + +* **[postgres] Pin system PostgreSQL to 17.7-standard-trixie**: Pins the PostgreSQL image for system databases (Grafana, Alerta, Harbor, Keycloak, SeaweedFS) to `17.7-standard-trixie` across chart templates and `values.yaml`, and ships migration 37 to patch existing CNPG Cluster `imageName` fields to the same variant (handling unset, any PG 17 tag, and bare-version tags). This prevents CNPG from defaulting to PostgreSQL 18 and locks system databases to the trixie variant consistent with the monitoring stack requirements *(related backports shipped in v1.2.1 via #2309 and v1.2.2 via #2364)* ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2369). + +* **[platform] Prevent installed packages deletion**: Adds the `helm.sh/resource-policy: keep` annotation to platform packages so disabling a package no longer triggers automatic Helm deletion, restoring the documented behavior where operators must explicitly delete a package *(backported to v1.2.1)* ([**@kvaps**](https://github.com/kvaps) in #2273). + +* **[mariadb] Always enable replication for consistent service naming**: MariaDB now always enables replication, creating `-primary`/`-secondary` services even for single-replica instances. This fixes dashboard visibility and backup functionality for single-replica setups ([**@sircthulhu**](https://github.com/sircthulhu) in #2279). + +* **[hack] Add host runtime preflight check**: New `check-host-runtime.sh` script and `make preflight` target that warns operators when a standalone containerd or docker runtime is running alongside the embedded k3s runtime, helping diagnose container-runtime conflicts early in an installation ([**@lexfrei**](https://github.com/lexfrei) in #2371). + +* **[hack] Add check-readiness.sh diagnostic script**: A new diagnostic script for tracking platform reconciliation by checking readiness of Packages, ArtifactGenerators, ExternalArtifacts, and HelmReleases, with support for watch mode and continuous monitoring ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2294). + +* **[platform] Add resourcePreset labels to WorkloadMonitor labels**: WorkloadMonitor labels with the `workloads.cozystack.io/` prefix are now propagated onto created Workloads; created Workloads always include the reserved `workloads.cozystack.io/monitor` label, and Helm app charts add `workloads.cozystack.io/resource-preset` metadata to WorkloadMonitor manifests, enabling downstream billing pipelines to correlate monitors with the tenant preset that produced them ([**@androndo**](https://github.com/androndo) in #2416). + +## Bug Fixes + +* **[platform] Migrate ACME HTTP-01 to ingressClassName API**: Switches ACME HTTP-01 issuance from the deprecated `acme.cert-manager.io/http01-ingress-class` annotation to the modern `ingressClassName` field on `ClusterIssuer` and solver pods. Previously, ClusterIssuers referenced a non-existent `nginx` class while each Ingress individually overrode it via annotation — producing `ingressClassName and class cannot be set at the same time` errors when tenants attempted to migrate to the modern field. The migration is atomic: both the ClusterIssuer and consuming Ingresses are updated together *(backported to v1.2.4)* ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2436). + +* **[harbor] Remove incorrect tenant module flags**: Harbor is a PaaS service, not a tenant module. Incorrect `spec.dashboard.module: true` and `internal.cozystack.io/tenantmodule` flags caused Harbor to appear in the sidebar "Modules" section and be misclassified by controllers handling tenant modules. The flags are now removed so Harbor is displayed in its proper PaaS category and is no longer treated as a tenant-scoped HelmRelease ([**@kvaps**](https://github.com/kvaps) in #2444). + +* **[kube-ovn] Resolve kubeovn-plunger RBAC forbidden on deployments**: Grants `kube-ovn-plunger` the RBAC needed to list Deployments so it can reconcile `ovn-central`, fixing `deployments.apps is forbidden` errors in `cozy-kubeovn` ([**@kvaps**](https://github.com/kvaps) in #2441). + +* **[cilium] Opt-out of cri-containerd.apparmor.d for nsenter init containers**: Opts cilium-agent init containers out of the `cri-containerd.apparmor.d` AppArmor profile on non-Talos variants (`cilium-generic`, `kubeovn-cilium-generic`), fixing `Init:CrashLoopBackOff` on Ubuntu 22.04+ and Debian where the profile denies `nsenter` namespace entry. Talos variants are untouched as Talos does not load the AppArmor LSM *(backported to v1.2.2)* ([**@lexfrei**](https://github.com/lexfrei) in #2370). + +* **[virtual-machine] Exclude external VM services from Cilium BPF LB**: Adds the `service.kubernetes.io/service-proxy-name: cozy-proxy` label to VM LoadBalancer services with `external: true`, telling Cilium to skip BPF processing entirely. Fixes inter-tenant connectivity via public LB IPs (Cilium's DNAT caused cross-tenant pod-to-pod flow classification, triggering CiliumClusterwideNetworkPolicy blocks) and restores WholeIP behavior on Cilium 1.19+ where wildcard service drop entries previously blocked traffic to LB IPs on undeclared ports *(backported to v1.2.2)* ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2357). + +* **[monitoring] Fix infra dashboards missing in default variant**: Includes the `cozy-monitoring` namespace in the dashboard rendering condition, fixing infrastructure Grafana dashboards not rendering in the default platform variant (only the `tenant-root` namespace was previously checked) *(backported to v1.2.2)* ([**@mattia-eleuteri**](https://github.com/mattia-eleuteri) in #2365). + +* **[build] Filter git describe to match only v* tags**: Adds `--match 'v*'` to all `git describe` calls in `hack/common-envs.mk`, preventing the `api/apps/v1alpha1/vX.Y.Z` subtag from being picked up instead of the release tag and producing invalid Docker image tags *(backported to v1.2.2)* ([**@kvaps**](https://github.com/kvaps) in #2386). + +* **[platform] Fix resource allocation ratios not propagated to packages**: Restores propagation of `cpuAllocationRatio`, `memoryAllocationRatio`, and `ephemeralStorageAllocationRatio` from `platform/values.yaml` to the `cozystack-values` Secret that managed applications and KubeVirt read, fixing a regression introduced in the bundle restructure that silently ignored operator-configured ratios *(backported to v1.2.1)* ([**@sircthulhu**](https://github.com/sircthulhu) in #2296). + +* **[kubernetes] Set explicit ephemeral-storage on virt-launcher pods**: Sets explicit `domain.resources` ephemeral-storage on the VirtualMachine spec to prevent virt-launcher pods from being evicted because LimitRange defaults were too small for the actual emptyDisk capacity *(backported to v1.2.3)* ([**@kvaps**](https://github.com/kvaps) in #2317). + +* **[multus] Pin master CNI to 05-cilium.conflist**: Prevents a boot-time race where multus could auto-detect kube-ovn's conflist instead of Cilium's, which would cause pods to bypass the Cilium chain entirely and lose their endpoint *(backported to v1.2.1)* ([**@kvaps**](https://github.com/kvaps) in #2315). + +* **[multus] Build custom image with DEL cache fix**: Fixes sandbox cleanup deadlock when CNI ADD never completes, preventing stale sandbox name reservations from permanently blocking pod creation after a node disruption *(backported to v1.2.1)* ([**@kvaps**](https://github.com/kvaps) in #2313). + +* **[linstor] Set verify-alg to crc32c**: Prevents DRBD connection failures on kernels where `crct10dif` is unavailable (e.g., Talos v1.12.6 with kernel 6.18.18) by setting the LINSTOR verify-alg controller default to `crc32c` *(backported to v1.2.1)* ([**@kvaps**](https://github.com/kvaps) in #2303). + +* **[linstor] Preserve TCP ports during toggle-disk operations**: Saves existing TCP ports into the `LayerPayload` before `removeLayerData()` deletes them, preventing DRBD resources from entering StandAlone state when a satellite misses the resulting update *(backported to v1.2.1)* ([**@kvaps**](https://github.com/kvaps) in #2292). + +* **[linstor] Increase satellite startup probe failure threshold**: Raises the LINSTOR satellite `startupProbe` `failureThreshold` from 3 to 30 (30s → 300s) in the `LinstorSatelliteConfiguration` pod template, giving satellites with slow storage initialization enough time to come up without being killed and restarted ([**@Arsolitt**](https://github.com/Arsolitt) in #2425). + +## Security + +* **docs: add SECURITY.md**: Adds vulnerability reporting procedures, disclosure expectations, and supported release lines ([**@kvaps**](https://github.com/kvaps) in #2230). + +* **docs: add OpenSSF Best Practices badge to README**: Adds the OpenSSF Best Practices passing badge to the project README ([**@lexfrei**](https://github.com/lexfrei) in #2320). + +## Dependencies & Version Updates + +* **[kube-ovn] Bump kube-ovn to v1.15.10 with port-group regression fix**: Updates `packages/system/kubeovn` to upstream v1.15.10 (from v1.15.3) and carries a patch for `pkg/controller/pod.go` that preserves a VM LSP's port-group memberships when Kubernetes GCs a completed virt-launcher pod while another virt-launcher pod of the same VM is still running. Without the patch, the destination pod of a successful live migration lost its security groups, network policies, and node-scoped routing until `kube-ovn-controller` was restarted ([**@kvaps**](https://github.com/kvaps) in #2443). + +* **[monitoring] Upgrade victoria-metrics-operator to v0.68.4**: Bumps the vendored `victoria-metrics-operator` Helm chart from 0.59.1 to 0.61.0 (operator appVersion v0.68.1 → v0.68.4), picking up upstream fixes for `VMPodScrape` port routing on VMAgent/VLAgent and `StatefulSet` pod deletion (not eviction) when `maxUnavailable=100%` ([**@lexfrei**](https://github.com/lexfrei) in #2426). + +* **[linstor] Update piraeus-server to v1.33.2 with selected backports**: Bumps LINSTOR server from v1.33.1 to v1.33.2 with backported patches for stale bitmap adjust retry, LUKS2 header sizing, optimal I/O size detection, and the maintainer implementation. All patches verified against upstream v1.33.2 with `git apply --check` and `gradlew compileJava` *(backported to v1.2.2)* ([**@kvaps**](https://github.com/kvaps) in #2331). + +* **[kamaji] Update to 26.3.5-edge, drop upstreamed patches**: Updates Kamaji from edge-26.2.4 to 26.3.5-edge and removes two patches accepted upstream. Adds configurable probe tuning and DataStore readiness conditions ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2260). + +* **[talm] Release v0.23.0, v0.23.1, v0.24.0** (github.com/cozystack/talm): Migrates to the Talos v1.12 multi-document machine config format ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm#116); renders templates online in `apply` to resolve lookups ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/talm#119); bumps dependencies and modernizes the codebase ([**@lexfrei**](https://github.com/lexfrei) in cozystack/talm#124). + +* **[ansible-cozystack] Release v1.2.1, v1.2.2, v1.2.4** (github.com/cozystack/ansible-cozystack): Exposes `publishing.externalIPs` and tenant-root ingress via role variables ([**@lexfrei**](https://github.com/lexfrei) in cozystack/ansible-cozystack#30); adds a comprehensive node prerequisites audit ([**@lexfrei**](https://github.com/lexfrei) in cozystack/ansible-cozystack#27); replaces `ansible.utils.ipaddr` with a stdlib-based test plugin ([**@lexfrei**](https://github.com/lexfrei) in cozystack/ansible-cozystack#24); adds `v` prefix to collection version in requirements.yml examples ([**@lexfrei**](https://github.com/lexfrei) in cozystack/ansible-cozystack#23); tracks installer releases v1.2.1 through v1.2.4 ([**@app/renovate**](https://github.com/apps/renovate) in cozystack/ansible-cozystack#20, #22, #29, #31, #32). + +## Development, Testing, and CI/CD + +* **[ci] Replace cozystack-bot PAT with cozystack-ci GitHub App**: Replaces the long-lived `cozystack-bot` personal access token with short-lived, scoped tokens from the `cozystack-ci` GitHub App across all release workflows (`tags.yaml`, `auto-release.yaml`, `pull-requests-release.yaml`), improving security and auditability of CI operations ([**@tym83**](https://github.com/tym83) in #2351; [**@kvaps**](https://github.com/kvaps) in #2383, #2392). + +* **[ci] Add Gemini Code Assist and CodeRabbit configuration**: Adds repository-level configuration for AI code reviewers with ignore patterns for vendored/generated code and incremental review settings ([**@lexfrei**](https://github.com/lexfrei) in #2385). + +* **[ci] Promote next/ trunk on new minor/major releases**: Updates `update-website-docs` in `tags.yaml` to match the new docs-versioning contract — the website repo replaces the old "pre-create `vX.Y/` draft directory" scheme with a permanent `content/en/docs/next/` trunk, and released version directories are promoted explicitly by the release workflow ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2433). + +* **[tests] Fix Kafka E2E test timeout and retry race condition**: Increases Kafka E2E test timeout from 60s to 300s and fixes a retry race where `kubectl apply` could hit a still-deleting resource ([**@lexfrei**](https://github.com/lexfrei) in #2358). + +* **docs: adopt Conventional Commits for commit and PR titles**: Standardizes commit and PR title format to `type(scope): description` across all contributing docs and the PR template ([**@lexfrei**](https://github.com/lexfrei) in #2395). + +* **docs(ci): require screenshots for UI changes in PR template**: Adds a mandatory screenshots section to the PR template for UI-related changes ([**@kitsunoff**](https://github.com/kitsunoff) in #2407). + +* **chore(maintenance): add @myasnikovdaniil to CODEOWNERS**: Adds @myasnikovdaniil to the default owners in `.github/CODEOWNERS` for automatic review requests ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2434). + +## Documentation + +* **[website] Add ApplicationDefinition naming convention reference**: Documents how `cozystack-api` resolves kinds to their backing definitions ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#478). + +* **[website] Document Talos / talosctl / Cozystack version pairing**: Adds a version compatibility matrix for installation ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#484). + +* **[website] Document namespace layout and parent/child derivation**: Explains tenant namespace hierarchy and parent/child namespace derivation rules ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#479). + +* **[website] Document the checkbox-then-edit-CR customization pattern for tenants**: Describes the workflow for customizing tenant settings via the CR after initial checkbox-based creation ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#485). + +* **[website] Add custom Keycloak themes documentation**: Covers the theme image contract, configuration, `imagePullSecrets`, and theme activation in the Keycloak admin console ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#463). + +* **[website] Add bonding (LACP) configuration how-to guide**: Covers network bonding configuration for Cozystack installations ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#459). + +* **[website] Improve registry mirrors for tenant Kubernetes in air-gapped guide**: Improves documentation for configuring registry mirrors in air-gapped environments ([**@sircthulhu**](https://github.com/sircthulhu) in cozystack/website#461). + +* **[website] Rewrite guide for ApplicationDefinition API (external-apps)**: Comprehensive rewrite of the external apps guide using the ApplicationDefinition API with Minecraft server examples ([**@kitsunoff**](https://github.com/kitsunoff) in cozystack/website#488). + +* **[website] Add documentation for Go types usage**: Guide for using generated Go types for Cozystack managed applications as a Go module ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#465). + +* **[website] Update backup/restore documentation for VMI/VMDisk**: Updates backup documentation with VM instance and VM disk restore improvements ([**@androndo**](https://github.com/androndo) in cozystack/website#466). + +* **[website] Refactor docs versions to major.minor variants**: Moves docs to major.minor versioning for the v1.x series ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#477). + +* **[website] Trunk-based versioning with permanent next/ directory**: Replaces the old "pre-create `vX.Y/` draft directory" scheme with a permanent `content/en/docs/next/` trunk; released version directories are promoted explicitly by `hack/release_next.sh` on new minor/major releases, and routing between `next/` and `vX.Y/` is Makefile-driven ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#495). + +* **[website] Add updated OpenAPI spec**: Updates the OpenAPI specification for managed applications reference ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#469). + +* **[website] Add OpenAPI spec download to GitHub Pages build**: Fixes the GitHub Pages build to include the OpenAPI spec download ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#494). + +* **[website] Add OSS Health pages and OpenSSF badge**: Adds OSS Health section with OpenSSF Scorecard and Best Practices badges to the website ([**@tym83**](https://github.com/tym83) in cozystack/website#470). + +* **[website] Add Telemetry page under OSS Health section**: Adds the Telemetry page with initial data seeding to the OSS Health docs ([**@tym83**](https://github.com/tym83) in cozystack/website#471, cozystack/website#504). + +* **[website] Blog: OSS Health section launch announcement**: Publishes the announcement blog post for the OSS Health section ([**@tym83**](https://github.com/tym83) in cozystack/website#474). + +* **[website] Fix OpenSSF canonical status URL**: Changes the OpenSSF canonical status URL from pt-BR to en ([**@tym83**](https://github.com/tym83) in cozystack/website#475). + +* **[website] Add CozySummit Virtual 2026 program announcement**: Publishes the CozySummit Virtual 2026 program announcement blog post ([**@tym83**](https://github.com/tym83) in cozystack/website#472). + +* **[website] Add missing release announcements for v0.1–v0.41**: Backfills missing release announcement blog posts for historical Cozystack versions ([**@tym83**](https://github.com/tym83) in cozystack/website#468). + +* **[website] Blog: managed PostgreSQL with synchronous replication**: Adds a post covering the managed PostgreSQL synchronous-replication feature ([**@tym83**](https://github.com/tym83) in cozystack/website#497). + +* **[website] Blog taxonomies and client-side filter UI**: Registers article-type and topic taxonomies and adds a client-side filter on the blog list page ([**@tym83**](https://github.com/tym83) in cozystack/website#499). + +* **[website] Add images frontmatter for social preview on existing posts**: Adds images frontmatter for social preview on existing blog posts ([**@tym83**](https://github.com/tym83) in cozystack/website#498). + +* **[website] Fix broken links and stale anchors across v1 docs**: Fixes 14 broken links and stale talm anchors ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#486). + +* **[website] Prefix bundle package names with cozystack. in v1 examples**: Corrects package naming in documentation examples ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#482). + +* **[website] Finish isolated-field removal and document opt-in policy labels**: Removes the obsolete `isolated` field from tenant documentation and documents the new opt-in policy labels approach ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#481). + +* **[website] Add --take-ownership flag and describe networking.* fields**: Documents the `--take-ownership` flag and `networking.*` fields in the installation guide ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#480). + +* **[website] Fix KubeOVN MASTER_NODES example path and key in troubleshooting**: Corrects the MASTER_NODES example path and key ([**@lexfrei**](https://github.com/lexfrei) in cozystack/website#483). + +* **[website] Add CLAUDE.md for AI agent guidance**: Adds a CLAUDE.md file describing the trunk-based docs architecture for AI agent guidance ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#489). + +* **[website] Update /docs/v1/ redirect to latest v1.2**: Updates the `/docs/v1/` redirect target to point to the latest v1.2 docs on GitHub Pages ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#492). + +* **[website] Remove nbykov from CODEOWNERS and CLAUDE.md**: Cleans up CODEOWNERS and CLAUDE.md entries ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in cozystack/website#491). + +* **[website] Add Ahrefs Analytics tracker**: Adds the Ahrefs Analytics tracker to the website ([**@tym83**](https://github.com/tym83) in cozystack/website#503). + +* **[website] Add breathing room between navbar and hero on OSS Health**: Minor styling fix for the OSS Health section ([**@tym83**](https://github.com/tym83) in cozystack/website#500). + +* **[website] Fix og social badge image and title**: Updates the social badge image and title ([**@tym83**](https://github.com/tym83) in cozystack/website#487). + +* **[website] Update managed apps reference for v1.2.1**: Automated managed-apps reference update ([**@cozystack-bot**](https://github.com/cozystack-bot) in cozystack/website#464). + +* **[external-apps-example] Replace MongoDB example with Minecraft apps**: Refactors the external apps example to use the ApplicationDefinition API with Minecraft server applications ([**@lexfrei**](https://github.com/lexfrei) in cozystack/external-apps-example#2). + +* **docs: update README introductory description**: Refines the platform positioning and improves clarity on core capabilities in the main README ([**@tym83**](https://github.com/tym83) in #2409). + +## Governance + +* **Add Mattia Eleuteri ([@mattia-eleuteri](https://github.com/mattia-eleuteri)) as Maintainer**: CSI, Storage, Networking & Security ([**@tym83**](https://github.com/tym83) in #2345). + +* **Add Matthieu Robin ([@matthieu-robin](https://github.com/matthieu-robin)) as Maintainer**: Managed applications, platform quality, and benchmarking ([**@tym83**](https://github.com/tym83) in #2346). + +## Contributors + +We'd like to thank all contributors who made this release possible: + +* [**@androndo**](https://github.com/androndo) +* [**@Arsolitt**](https://github.com/Arsolitt) +* [**@BROngineer**](https://github.com/BROngineer) +* [**@IvanHunters**](https://github.com/IvanHunters) +* [**@kitsunoff**](https://github.com/kitsunoff) +* [**@kvaps**](https://github.com/kvaps) +* [**@lexfrei**](https://github.com/lexfrei) +* [**@lllamnyp**](https://github.com/lllamnyp) +* [**@mattia-eleuteri**](https://github.com/mattia-eleuteri) +* [**@myasnikovdaniil**](https://github.com/myasnikovdaniil) +* [**@sircthulhu**](https://github.com/sircthulhu) +* [**@tym83**](https://github.com/tym83) + +### New Contributors + +We're excited to welcome our first-time contributors: + +* [**@Arsolitt**](https://github.com/Arsolitt) — First contribution! + +--- + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.2.0...v1.3.0 diff --git a/docs/changelogs/v1.3.1.md b/docs/changelogs/v1.3.1.md new file mode 100644 index 00000000..0f149d0d --- /dev/null +++ b/docs/changelogs/v1.3.1.md @@ -0,0 +1,37 @@ + + +# v1.3.1 (2026-04-28) + +Patch release covering a TenantNamespace IDOR fix in the API, a destructive `post-upgrade` hook removed from the etcd chart, kamaji controller stability, a `linstor-csi` bump that fixes live migration on Protocol-A/B DRBD resources, the missing `linstor-gui` build wiring, and a velero RBAC fix that unblocked installs on bundles without Velero. + +## Security + +* **fix(api): prevent IDOR in TenantNamespace Get and Watch handlers**: Two IDOR (Insecure Direct Object Reference) vulnerabilities allowed authenticated users to read TenantNamespace metadata they had no RoleBinding for. The `Get` and `Watch` handlers now go through a new `hasAccessToNamespace()` helper that lists RoleBindings scoped only to the target namespace (orders of magnitude faster than the previous all-cluster scan), returns `NotFound` instead of leaking existence on unauthorized access, and applies the same check on the `Watch` filter path. Includes regression tests for the unauthorized paths. ([**@IvanHunters**](https://github.com/IvanHunters) in #2471, backport #2524) + +## Features + +* **feat(linstor): bump linstor-csi to v1.10.6 with Protocol-C dual-attach fix**: Live migration of KubeVirt VMs on Protocol-A/B (async) DRBD volumes no longer fails with `Protocol C required`. `linstor-csi` v1.10.6 now installs a `Protocol=C` override on the resource-definition during dual-attach and reverts it on detach, so `replicated-async` StorageClasses and other Protocol-A/B resource groups support live migration without manual `drbdadm adjust` intervention. ([**@kvaps**](https://github.com/kvaps) in #2496, backport #2505) + +## Fixes + +* **fix(backups): move velero-configmap Role to velero chart**: The `backupstrategy-controller` (a default package) declared a Role/RoleBinding scoped to the `cozy-velero` namespace for managing `ResourceModifier` ConfigMaps. On bundles where Velero was not enabled, that namespace did not exist and the HelmRelease failed with `namespaces "cozy-velero" not found`, blocking installation. The Role/RoleBinding now lives in the velero chart, so it is created only when velero is actually deployed. ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2459, backport #2467) + +* **fix(etcd): remove destructive post-upgrade cert-regeneration hook**: The etcd chart ran a `post-upgrade` Helm hook on every upgrade that deleted etcd TLS Secrets (`etcd-ca-tls`, `etcd-peer-ca-tls`, `etcd-client-tls`, `etcd-peer-tls`, `etcd-server-tls`) and then deleted etcd pods, forcing cert-manager to re-issue the entire etcd CA chain. On clusters with Kamaji-managed tenant control planes this put every tenant `kube-apiserver` into CrashLoopBackOff until each DataStore was manually re-reconciled. The hook was a one-shot `2.6.0 → 2.6.1` migration that became a permanent footgun once chart versioning moved to `0.0.0+` (always `< 2.6.1` per semver) and after the underlying `rotationPolicy: Always` issue was fixed in `47d81f70`. The hook is now removed entirely. ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2462, backport #2511) + +* **fix(kamaji): increase memory limits and add startup probe**: The kamaji controller frequently entered CrashLoopBackOff due to OOMKills (exit 137) within ~20–25 seconds of startup, with the readiness probe failing while the controller was still finishing initialization. Memory limit raised from 500Mi to 512Mi, request from 100Mi to 256Mi, and a 60-second startup probe (12 attempts × 5s periods) is added so the controller has room to boot before liveness/readiness probes engage. ([**@IvanHunters**](https://github.com/IvanHunters) in #2421, backport #2491) + +## Build + +* **build(linstor): include linstor-gui in root image build target**: The `linstor-gui` package (added in #2382) was never wired into the root `Makefile`'s `build:` target, so CI never built or published the image. `ghcr.io/cozystack/cozystack/linstor-gui` returned `NAME_UNKNOWN` and `values.yaml` stayed pinned to `tag: 2.3.0` without a digest. The missing build line is added so the next CI run publishes the image and the per-package `Makefile` digest-pins `values.yaml` automatically. ([**@myasnikovdaniil**](https://github.com/myasnikovdaniil) in #2498, backport #2518) + +## Contributors + +Thanks to everyone who contributed to this patch release: + +* [**@IvanHunters**](https://github.com/IvanHunters) +* [**@kvaps**](https://github.com/kvaps) +* [**@myasnikovdaniil**](https://github.com/myasnikovdaniil) + +**Full Changelog**: https://github.com/cozystack/cozystack/compare/v1.3.0...v1.3.1 diff --git a/docs/hubble-observability.md b/docs/hubble-observability.md new file mode 100644 index 00000000..33597eec --- /dev/null +++ b/docs/hubble-observability.md @@ -0,0 +1,99 @@ +# Enabling Hubble for Network Observability + +Hubble is a network and security observability platform built on top of Cilium. It provides deep visibility into the communication and behavior of services in your Kubernetes cluster. + +## Prerequisites + +- Cozystack platform running with Cilium as the CNI +- Monitoring hub enabled for Grafana access + +## Configuration + +Hubble is disabled by default in Cozystack. To enable it, update the Cilium configuration. + +### Enable Hubble + +Edit the Cilium values in your platform configuration to enable Hubble: + +```yaml +cilium: + hubble: + enabled: true + relay: + enabled: true + ui: + enabled: true + metrics: + enabled: + - dns + - drop + - tcp + - flow + - port-distribution + - icmp + - httpV2:exemplars=true;labelsContext=source_ip,source_namespace,source_workload,destination_ip,destination_namespace,destination_workload,traffic_direction +``` + +### Components + +When Hubble is enabled, the following components become available: + +- **Hubble Relay**: Aggregates flow data from all Cilium agents +- **Hubble UI**: Web-based interface for exploring network flows +- **Hubble Metrics**: Prometheus metrics for network observability + +## Grafana Dashboards + +Once Hubble is enabled and the monitoring hub is deployed, the following dashboards become available in Grafana under the `hubble` folder: + +| Dashboard | Description | +|-----------|-------------| +| **Overview** | General Hubble metrics including processing statistics | +| **DNS Namespace** | DNS query and response metrics by namespace | +| **L7 HTTP Metrics** | HTTP layer 7 metrics by workload | +| **Network Overview** | Network flow overview by namespace | + +### Accessing Dashboards + +1. Navigate to Grafana via the monitoring hub +2. Browse to the `hubble` folder in the dashboard browser +3. Select a dashboard to view network observability data + +## Metrics Available + +Hubble exposes various metrics that can be queried in Grafana: + +- `hubble_flows_processed_total`: Total number of flows processed +- `hubble_dns_queries_total`: DNS queries by type +- `hubble_dns_responses_total`: DNS responses by status +- `hubble_drop_total`: Dropped packets by reason +- `hubble_tcp_flags_total`: TCP connections by flag +- `hubble_http_requests_total`: HTTP requests by method and status + +## Troubleshooting + +### Verify Hubble Status + +Check if Hubble is running: + +```bash +kubectl get pods -n cozy-cilium -l k8s-app=hubble-relay +kubectl get pods -n cozy-cilium -l k8s-app=hubble-ui +``` + +### Check Metrics Endpoint + +Verify Hubble metrics are being scraped: + +```bash +kubectl port-forward -n cozy-cilium svc/hubble-metrics 9965:9965 +curl http://localhost:9965/metrics +``` + +### Verify ServiceMonitor + +Ensure the ServiceMonitor is created for Prometheus scraping: + +```bash +kubectl get servicemonitor -n cozy-cilium +``` diff --git a/examples/backups/vmi/00-helpers.sh b/examples/backups/vmi/00-helpers.sh new file mode 100755 index 00000000..38405495 --- /dev/null +++ b/examples/backups/vmi/00-helpers.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# Helper functions and variables for the VMInstance backup/restore demo +# Source this file in other scripts: source "$(dirname "$0")/00-helpers.sh" + +# ANSI color codes +export RED='\033[0;31m' +export GREEN='\033[0;32m' +export YELLOW='\033[1;33m' +export BLUE='\033[0;34m' +export MAGENTA='\033[0;35m' +export CYAN='\033[0;36m' +export WHITE='\033[1;37m' +export NC='\033[0m' # No Color +export BOLD='\033[1m' + +# Default settings +export NAMESPACE="${NAMESPACE:-tenant-root}" +export BACKUP_STORAGE_LOCATION="${BACKUP_STORAGE_LOCATION:-default}" + +# Logging functions (output to stderr to avoid polluting captured output) +log_info() { + echo -e "${BLUE}ℹ${NC} $*" >&2 +} + +log_success() { + echo -e "${GREEN}✔${NC} $*" >&2 +} + +log_warning() { + echo -e "${YELLOW}⚠${NC} $*" >&2 +} + +log_error() { + echo -e "${RED}✖${NC} $*" >&2 +} + +log_step() { + echo -e "\n${MAGENTA}${BOLD}▶ $*${NC}" >&2 +} + +log_substep() { + echo -e "${CYAN} → $*${NC}" >&2 +} + +log_command() { + echo -e "${WHITE} \$ $*${NC}" >&2 +} + +# Wait for user to press Enter +wait_for_enter() { + echo -e "\n${CYAN}Press Enter to continue...${NC}" >&2 + read -r +} + +# Check if a Kubernetes resource exists +resource_exists() { + local resource_type="$1" + local resource_name="$2" + local namespace="${3:-}" + + if [[ -n "$namespace" ]]; then + kubectl get "$resource_type" "$resource_name" -n "$namespace" &>/dev/null + else + kubectl get "$resource_type" "$resource_name" &>/dev/null + fi +} + +# Wait for a resource field to reach a desired value +wait_for_field() { + local resource_type="$1" + local resource_name="$2" + local jsonpath="$3" + local desired="$4" + local namespace="${5:-}" + local timeout="${6:-300}" + + log_substep "Waiting for $resource_type/$resource_name $jsonpath to become '$desired'..." + + local elapsed=0 + local ns_flag="" + [[ -n "$namespace" ]] && ns_flag="-n $namespace" + + while true; do + local current + # shellcheck disable=SC2086 + current=$(kubectl get "$resource_type" "$resource_name" $ns_flag -o jsonpath="$jsonpath" 2>/dev/null || true) + if [[ "$current" == "$desired" ]]; then + log_success "$resource_type/$resource_name reached '$desired'" + return 0 + fi + if [[ $elapsed -ge $timeout ]]; then + log_error "Timeout waiting for $resource_type/$resource_name (current: '$current', expected: '$desired')" + return 1 + fi + sleep 5 + elapsed=$((elapsed + 5)) + echo -n "." >&2 + done +} + +# Print a separator line +separator() { + echo -e "\n${CYAN}────────────────────────────────────────────────────────────${NC}\n" >&2 +} + +# Print script header +print_header() { + local title="$1" + echo -e "\n${MAGENTA}${BOLD}╔════════════════════════════════════════════════════════════╗${NC}" >&2 + echo -e "${MAGENTA}${BOLD}║${NC} ${WHITE}${BOLD}$title${NC}" >&2 + echo -e "${MAGENTA}${BOLD}╚════════════════════════════════════════════════════════════╝${NC}\n" >&2 +} diff --git a/examples/backups/vmi/01-create-strategies.sh b/examples/backups/vmi/01-create-strategies.sh new file mode 100755 index 00000000..78aa34d3 --- /dev/null +++ b/examples/backups/vmi/01-create-strategies.sh @@ -0,0 +1,145 @@ +#!/bin/bash +# Step 01: Create Velero backup/restore strategies for VMInstance and VMDisk +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/00-helpers.sh" + +print_header "Step 1: Create Velero Strategies" + +log_step "Creating VMInstance strategy..." +log_command "kubectl apply -f - (Velero strategy: vminstance-strategy)" + +kubectl apply -f - <<'EOF' +apiVersion: strategy.backups.cozystack.io/v1alpha1 +kind: Velero +metadata: + name: vminstance-strategy +spec: + template: + # Symmetric restore filters: kubevirt-velero-plugin requires launcher pods in the backup, + # but restore orLabelSelectors limit what is applied from the tarball (e.g. skip another + # VM's pod that Velero added via PVC item action). VMDisk OR branches are appended by + # the controller from backup.status.underlyingResources or the Velero backup annotation. + restoreSpec: + existingResourcePolicy: update + includedNamespaces: + - '{{ .Application.metadata.namespace }}' + orLabelSelectors: + - matchLabels: + app.kubernetes.io/instance: 'vm-instance-{{ .Application.metadata.name }}' + - matchLabels: + apps.cozystack.io/application.kind: '{{ .Application.kind }}' + apps.cozystack.io/application.name: '{{ .Application.metadata.name }}' + includedResources: + - helmreleases.helm.toolkit.fluxcd.io + - virtualmachines.kubevirt.io + - virtualmachineinstances.kubevirt.io + - pods + - persistentvolumeclaims + - configmaps + - secrets + - controllerrevisions.apps + includeClusterResources: false + excludedResources: + # Required to avoid conflict with restored DV from HR VMDisk + - datavolumes.cdi.kubevirt.io + + spec: # see https://velero.io/docs/v1.17/api-types/backup/ + includedNamespaces: + - '{{ .Application.metadata.namespace }}' + orLabelSelectors: + # VM resources (VirtualMachine, DataVolume, PVC, etc.) + - matchLabels: + app.kubernetes.io/instance: 'vm-instance-{{ .Application.metadata.name }}' + # HelmRelease (the Cozystack app object) + - matchLabels: + apps.cozystack.io/application.kind: '{{ .Application.kind }}' + apps.cozystack.io/application.name: '{{ .Application.metadata.name }}' + includedResources: + - helmreleases.helm.toolkit.fluxcd.io + - virtualmachines.kubevirt.io + - virtualmachineinstances.kubevirt.io + # Required by kubevirt-velero-plugin for running VMs ("launcher pod must be in backup"). + - pods + # Required by kubevirt-velero-plugin requires DV to be in backup of VM, but it excludes in restores + - datavolumes.cdi.kubevirt.io + - persistentvolumeclaims + - configmaps + - secrets + - controllerrevisions.apps + includeClusterResources: false + storageLocation: '{{ .Parameters.backupStorageLocationName }}' + volumeSnapshotLocations: + - '{{ .Parameters.backupStorageLocationName }}' + snapshotVolumes: true + snapshotMoveData: true + ttl: 720h0m0s + itemOperationTimeout: 24h0m0s +EOF + +log_success "VMInstance strategy created" + +separator + +log_step "Creating VMDisk strategy..." +log_command "kubectl apply -f - (Velero strategy: vmdisk-strategy)" + +kubectl apply -f - <<'EOF' +apiVersion: strategy.backups.cozystack.io/v1alpha1 +kind: Velero +metadata: + name: vmdisk-strategy +spec: + template: + restoreSpec: + existingResourcePolicy: update + includedNamespaces: + - '{{ .Application.metadata.namespace }}' + orLabelSelectors: + - matchLabels: + app.kubernetes.io/instance: 'vm-disk-{{ .Application.metadata.name }}' + - matchLabels: + apps.cozystack.io/application.kind: '{{ .Application.kind }}' + apps.cozystack.io/application.name: '{{ .Application.metadata.name }}' + includedResources: + - helmreleases.helm.toolkit.fluxcd.io + - persistentvolumeclaims + - configmaps + includeClusterResources: false + + spec: + includedNamespaces: + - '{{ .Application.metadata.namespace }}' + orLabelSelectors: + - matchLabels: + app.kubernetes.io/instance: 'vm-disk-{{ .Application.metadata.name }}' + - matchLabels: + apps.cozystack.io/application.kind: '{{ .Application.kind }}' + apps.cozystack.io/application.name: '{{ .Application.metadata.name }}' + includedResources: + - helmreleases.helm.toolkit.fluxcd.io + - persistentvolumeclaims + - configmaps + includeClusterResources: false + storageLocation: '{{ .Parameters.backupStorageLocationName }}' + volumeSnapshotLocations: + - '{{ .Parameters.backupStorageLocationName }}' + snapshotVolumes: true + snapshotMoveData: true + ttl: 720h0m0s + itemOperationTimeout: 24h0m0s +EOF + +log_success "VMDisk strategy created" + +separator + +log_step "Verifying strategies..." +log_command "kubectl get velero.strategy.backups.cozystack.io" +kubectl get velero.strategy.backups.cozystack.io + +separator + +log_success "Velero strategies are ready" +echo -e "\n${GREEN}${BOLD}Next step:${NC} ./02-create-backupclass.sh" diff --git a/examples/backups/vmi/02-create-backupclass.sh b/examples/backups/vmi/02-create-backupclass.sh new file mode 100755 index 00000000..08c29fc1 --- /dev/null +++ b/examples/backups/vmi/02-create-backupclass.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# Step 02: Create BackupClass that binds strategies to application types +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/00-helpers.sh" + +print_header "Step 2: Create BackupClass" + +log_step "Creating BackupClass 'velero'..." +log_info "BackupClass maps application kinds (VMInstance, VMDisk) to their Velero strategies" +log_command "kubectl apply -f - (BackupClass: velero)" + +kubectl apply -f - < + external: false + externalMethod: PortList + externalPorts: + - 22 +EOF + +log_success "VMInstance created" + +separator + +log_step "Verifying VMInstance..." +log_command "kubectl get vminstance test -n $NAMESPACE" +kubectl get vminstance test -n "$NAMESPACE" + +separator + +log_success "VMInstance is ready" +echo -e "\n${GREEN}${BOLD}Next step:${NC} ./05-create-backupjob.sh" diff --git a/examples/backups/vmi/05-create-backupjob.sh b/examples/backups/vmi/05-create-backupjob.sh new file mode 100755 index 00000000..581490a4 --- /dev/null +++ b/examples/backups/vmi/05-create-backupjob.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# Step 05: Create a BackupJob to back up the VMInstance +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/00-helpers.sh" + +print_header "Step 5: Create BackupJob" + +log_step "Creating BackupJob 'test-backup' in namespace $NAMESPACE..." +log_info "This triggers a Velero backup of VMInstance 'test' and all its disks" +log_command "kubectl apply -f - (BackupJob: test-backup)" + +kubectl apply -f - <-orig-`, only for in-place restore + keepOriginalIpAndMac: true # restores original IP and MAC address of VMI via OVN annotations +EOF + +log_success "RestoreJob created" + +separator + +log_step "Waiting for RestoreJob to complete..." +wait_for_field restorejob restore-in-place-test '{.status.phase}' Succeeded "$NAMESPACE" 600 + +separator + +log_step "Verifying RestoreJob result..." +log_command "kubectl get restorejob restore-in-place-test -n $NAMESPACE -o yaml" +kubectl get restorejob restore-in-place-test -n "$NAMESPACE" -o wide + +separator + +log_success "In-place restore completed successfully" +echo -e "\n${GREEN}${BOLD}Next step:${NC} ./07-restore-to-copy.sh" diff --git a/examples/backups/vmi/07-restore-to-copy.sh b/examples/backups/vmi/07-restore-to-copy.sh new file mode 100755 index 00000000..9b84ce55 --- /dev/null +++ b/examples/backups/vmi/07-restore-to-copy.sh @@ -0,0 +1,68 @@ +#!/bin/bash +# Step 07: Restore the VMInstance to a copy in a different namespace +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/00-helpers.sh" + +TARGET_NAMESPACE="${TARGET_NAMESPACE:-tenant-root-copy}" + +print_header "Step 7: Restore VMInstance to Copy (Cross-Namespace)" + +log_info "Restoring to the same namespace with a different app name is not supported" +log_info "due to Velero DataUpload limitations. Cross-namespace restore uses Velero's namespaceMapping." + +separator + +log_step "Ensuring target namespace '$TARGET_NAMESPACE' exists..." +kubectl create namespace "$TARGET_NAMESPACE" --dry-run=client -o yaml | kubectl apply -f - +log_success "Namespace '$TARGET_NAMESPACE' is ready" + +separator + +log_step "Creating RestoreJob 'restore-to-copy-test' in namespace $NAMESPACE..." +log_info "The backup will be restored into namespace '$TARGET_NAMESPACE' using Velero namespaceMapping" +log_command "kubectl apply -f - (RestoreJob: restore-to-copy-test)" + +kubectl apply -f - <-orig-`, only for in-place restore + keepOriginalIpAndMac: false # restores original IP and MAC address of VMI via OVN annotations +EOF + +log_success "RestoreJob created" + +separator + +log_step "Waiting for RestoreJob to complete..." +wait_for_field restorejob restore-to-copy-test '{.status.phase}' Succeeded "$NAMESPACE" 600 + +separator + +log_step "Verifying RestoreJob result..." +log_command "kubectl get restorejob restore-to-copy-test -n $NAMESPACE -o yaml" +kubectl get restorejob restore-to-copy-test -n "$NAMESPACE" -o wide + +separator + +log_step "Checking resources in target namespace..." +log_command "kubectl get all -n $TARGET_NAMESPACE" +kubectl get all -n "$TARGET_NAMESPACE" 2>/dev/null || log_warning "No resources found in $TARGET_NAMESPACE" + +separator + +log_success "Cross-namespace restore completed successfully" diff --git a/examples/backups/vmi/cleanup.sh b/examples/backups/vmi/cleanup.sh new file mode 100755 index 00000000..5965c3f0 --- /dev/null +++ b/examples/backups/vmi/cleanup.sh @@ -0,0 +1,70 @@ +#!/bin/bash +# Clean up all resources created by the demo +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/00-helpers.sh" + +TARGET_NAMESPACE="${TARGET_NAMESPACE:-tenant-root-copy}" + +print_header "Cleanup Demo Resources" + +log_warning "This script will delete all resources created during the demo" +echo -e "\n${YELLOW}The following will be deleted:${NC}" +echo " - RestoreJobs (restore-in-place-test, restore-to-copy-test)" +echo " - BackupJob (test-backup) and associated Backup" +echo " - VMInstance (test)" +echo " - VMDisk (ubuntu-source)" +echo " - BackupClass (velero)" +echo " - Velero strategies (vminstance-strategy, vmdisk-strategy)" +echo " - Target namespace ($TARGET_NAMESPACE)" +echo "" + +read -p "Continue? (y/N): " -n 1 -r +echo +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + log_info "Cancelled" + exit 0 +fi + +separator + +log_step "Deleting RestoreJobs..." +kubectl delete restorejob restore-to-copy-test -n "$NAMESPACE" 2>/dev/null || log_warning "RestoreJob restore-to-copy-test not found" +kubectl delete restorejob restore-in-place-test -n "$NAMESPACE" 2>/dev/null || log_warning "RestoreJob restore-in-place-test not found" + +separator + +log_step "Deleting BackupJob and Backup..." +kubectl delete backupjob test-backup -n "$NAMESPACE" 2>/dev/null || log_warning "BackupJob test-backup not found" +kubectl delete backup test-backup -n "$NAMESPACE" 2>/dev/null || log_warning "Backup test-backup not found" + +separator + +log_step "Deleting VMInstance..." +kubectl delete vminstance test -n "$NAMESPACE" 2>/dev/null || log_warning "VMInstance test not found" + +log_step "Deleting VMDisk..." +kubectl delete vmdisk ubuntu-source -n "$NAMESPACE" 2>/dev/null || log_warning "VMDisk ubuntu-source not found" + +separator + +log_step "Deleting BackupClass..." +kubectl delete backupclass velero 2>/dev/null || log_warning "BackupClass velero not found" + +separator + +log_step "Deleting Velero strategies..." +kubectl delete velero.strategy.backups.cozystack.io vminstance-strategy 2>/dev/null || log_warning "Strategy vminstance-strategy not found" +kubectl delete velero.strategy.backups.cozystack.io vmdisk-strategy 2>/dev/null || log_warning "Strategy vmdisk-strategy not found" + +separator + +log_step "Deleting target namespace..." +kubectl delete namespace "$TARGET_NAMESPACE" 2>/dev/null || log_warning "Namespace $TARGET_NAMESPACE not found" + +separator + +log_success "Cleanup complete" +log_info "All demo resources have been deleted" +echo -e "\n${GREEN}${BOLD}To re-run the demo:${NC} ./01-create-strategies.sh" diff --git a/examples/backups/vmi/run-all.sh b/examples/backups/vmi/run-all.sh new file mode 100755 index 00000000..b58f4b9d --- /dev/null +++ b/examples/backups/vmi/run-all.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# Run the full VMInstance backup/restore demo sequentially +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/00-helpers.sh" + +print_header "VMInstance Backup & Restore Demo" + +log_info "This script will run all demo steps sequentially" +log_info "There will be a pause between steps for observation" +echo "" + +SCRIPTS=( + "01-create-strategies.sh" + "02-create-backupclass.sh" + "03-create-vmdisk.sh" + "04-create-vminstance.sh" + "05-create-backupjob.sh" + "06-restore-in-place.sh" + "07-restore-to-copy.sh" +) + +echo -e "${CYAN}Demo steps:${NC}" +for i in "${!SCRIPTS[@]}"; do + echo " $((i+1)). ${SCRIPTS[$i]}" +done +echo "" + +read -p "Run demo? (y/N): " -n 1 -r +echo +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + log_info "Cancelled" + exit 0 +fi + +separator + +for script in "${SCRIPTS[@]}"; do + if [[ -x "$SCRIPT_DIR/$script" ]]; then + "$SCRIPT_DIR/$script" + separator + wait_for_enter + else + log_error "Script not found or not executable: $script" + exit 1 + fi +done + +print_header "Demo Complete" + +log_success "All steps completed successfully!" +echo "" +log_info "What was demonstrated:" +echo " 1. Created Velero backup strategies for VMInstance and VMDisk" +echo " 2. Created BackupClass binding strategies to application types" +echo " 3. Provisioned a VMDisk and VMInstance" +echo " 4. Created a backup of the VMInstance via BackupJob" +echo " 5. Restored the VMInstance in-place" +echo " 6. Restored the VMInstance to a copy in a different namespace" +echo "" +log_info "To clean up resources: ./cleanup.sh" diff --git a/examples/backups/vmi/scenario-admin-prepare.md b/examples/backups/vmi/scenario-admin-prepare.md new file mode 100644 index 00000000..edfca5d1 --- /dev/null +++ b/examples/backups/vmi/scenario-admin-prepare.md @@ -0,0 +1,73 @@ +# Scenario: Cluster Administrator Configures Backups + +This scenario walks through the cluster-level setup required before users can +back up and restore their virtual machines. A cluster administrator creates +Velero strategies and a BackupClass that binds those strategies to Cozystack +application types. + +## Prerequisites + +- A running Cozystack cluster with the backup-controller installed. +- Velero deployed in the `cozy-velero` namespace with a configured + BackupStorageLocation (default: `default`). +- `kubectl` access with cluster-admin privileges. + +## Steps + +### 1. Create Velero Strategies + +```bash +./01-create-strategies.sh +``` + +This creates two cluster-scoped `Velero` strategy objects: + +| Strategy | Purpose | +|---|---| +| `vminstance-strategy` | Defines backup and restore templates for `VMInstance` applications. Includes VirtualMachine, PVCs, HelmReleases, pods (required by kubevirt-velero-plugin), and supporting resources. Uses `snapshotMoveData: true` for portable volume snapshots. | +| `vmdisk-strategy` | Defines backup and restore templates for standalone `VMDisk` applications. Covers HelmReleases, PVCs, and ConfigMaps. | + +Both strategies use Go templates with `{{ .Application.metadata.name }}`, +`{{ .Application.metadata.namespace }}`, and `{{ .Parameters.backupStorageLocationName }}` +so they can be reused across any application instance. + +**Key design details:** + +- `orLabelSelectors` scope backups to only the resources belonging to a + specific application, preventing cross-contamination between VMs in the + same namespace. +- The restore spec excludes `datavolumes.cdi.kubevirt.io` to avoid conflicts + when the HelmRelease of VMDisk recreates DataVolumes after restore. +- `existingResourcePolicy: update` allows restoring over existing resources + during in-place restore. + +### 2. Create BackupClass + +```bash +./02-create-backupclass.sh +``` + +Creates a `BackupClass` named `velero` that maps application types to their +strategies: + +| Application Kind | Strategy | Parameters | +|---|---|---| +| `VMInstance` (`apps.cozystack.io`) | `vminstance-strategy` | `backupStorageLocationName: default` | +| `VMDisk` (`apps.cozystack.io`) | `vmdisk-strategy` | `backupStorageLocationName: default` | + +The `backupStorageLocationName` parameter can be overridden via the +`BACKUP_STORAGE_LOCATION` environment variable if your Velero installation +uses a non-default storage location. + +## Configuration + +| Variable | Default | Description | +|---|---|---| +| `BACKUP_STORAGE_LOCATION` | `default` | Velero BackupStorageLocation name | + +## Result + +After completing these steps the cluster is ready for users to create backups +of their `VMInstance` and `VMDisk` applications by referencing the `velero` +BackupClass. No further admin action is required for individual backup or +restore operations. diff --git a/examples/backups/vmi/scenario-user-backup.md b/examples/backups/vmi/scenario-user-backup.md new file mode 100644 index 00000000..31241fd9 --- /dev/null +++ b/examples/backups/vmi/scenario-user-backup.md @@ -0,0 +1,91 @@ +# Scenario: User Creates a VM Backup + +This scenario demonstrates how a tenant user provisions a virtual machine and +creates a backup of it. The backup captures the VM definition, its disks, and +network identity so it can be restored later. + +## Prerequisites + +- Cluster administrator has completed the setup from + [scenario-admin.md](scenario-admin.md) (strategies and BackupClass exist). +- A tenant namespace (default: `tenant-root`). +- `kubectl` access scoped to the tenant namespace. + +## Steps + +### 1. Create a VMDisk + +```bash +./03-create-vmdisk.sh +``` + +Creates a `VMDisk` named `ubuntu-source` that downloads the Ubuntu Noble cloud +image and provisions a 20Gi replicated PVC. The disk serves as the boot volume +for the virtual machine. + +Wait for the image download to complete before proceeding. You can monitor +progress with: + +```bash +kubectl get vmdisk ubuntu-source -n tenant-root -w +``` + +### 2. Create a VMInstance + +```bash +./04-create-vminstance.sh +``` + +Creates a `VMInstance` named `test` that references the `ubuntu-source` disk. +The VM boots with the `ubuntu` instance profile on a `u1.medium` instance type. + +Verify the VM is running: + +```bash +kubectl get vmi -n tenant-root +``` + +### 3. Create a BackupJob + +```bash +./05-create-backupjob.sh +``` + +Creates a `BackupJob` named `test-backup` that triggers a full backup of the +`test` VMInstance. The backup controller: + +1. Resolves the `velero` BackupClass to find the matching `vminstance-strategy`. +2. Discovers underlying resources (DataVolumes, OVN IP/MAC from the VM pod). +3. Creates a Velero Backup in the `cozy-velero` namespace with label selectors + scoped to this specific VM and its disks. +4. Velero snapshots and moves the volume data to the configured storage + location. + +The script waits up to 10 minutes for the BackupJob to reach the `Succeeded` +phase. On completion, a `Backup` object is created in the same namespace +containing: + +- `spec.applicationRef` — reference to the backed-up VMInstance. +- `spec.strategyRef` — reference to the Velero strategy used. +- `spec.driverMetadata` — Velero backup name for later restore. +- `status.underlyingResources` — captured DataVolume names and OVN IP/MAC + addresses. + +You can inspect the resulting Backup: + +```bash +kubectl get backups -n tenant-root +kubectl get backup test-backup -n tenant-root -o yaml +``` + +## Configuration + +| Variable | Default | Description | +|---|---|---| +| `NAMESPACE` | `tenant-root` | Tenant namespace for all resources | + +## Result + +After completing these steps you have a `Backup` artifact that can be used to +restore the VM either in-place or to a different namespace. See +[scenario-user-restore.md](scenario-user-restore.md) for restore options. diff --git a/examples/backups/vmi/scenario-user-restore.md b/examples/backups/vmi/scenario-user-restore.md new file mode 100644 index 00000000..1d35b22b --- /dev/null +++ b/examples/backups/vmi/scenario-user-restore.md @@ -0,0 +1,101 @@ +# Scenario: User Restores a VM + +This scenario demonstrates two restore methods: in-place restore (rollback the +VM to a previous state) and cross-namespace restore (create a copy of the VM in +a different namespace). + +## Prerequisites + +- A completed backup from [scenario-user-backup.md](scenario-user-backup.md) + (the `test-backup` Backup object exists in the tenant namespace). +- `kubectl` access scoped to the tenant namespace. + +## Method 1: In-Place Restore + +```bash +./06-restore-in-place.sh +``` + +Creates a `RestoreJob` that restores the `test` VMInstance back to the state +captured in the `test-backup` Backup. The `targetApplicationRef` points to the +same application as the original backup. + +The backup controller performs the following steps automatically: + +1. **Suspends HelmReleases** — prevents Flux from reconciling the VM and its + disks during restore. +2. **Halts the VirtualMachine** — sets `runStrategy: Halted` and waits for the + VirtualMachineInstance (launcher pod) to terminate. +3. **Renames existing PVCs** — moves each PVC to `-orig-` to + preserve the current disk data as a safety net. +4. **Deletes DataVolumes** — removes DVs so CDI does not recreate PVCs before + Velero restores them. +5. **Creates Velero Restore** — restores resources from the backup with: + - `existingResourcePolicy: update` to overwrite existing objects. + - Resource modifier rules that add `cdi.kubevirt.io/allowClaimAdoption=true` + to restored PVCs so CDI can adopt them. + - OVN IP/MAC annotations to preserve the VM's network identity. + +After the Velero Restore completes, the HelmReleases resume and the VM boots +with the restored disk data while retaining its original IP and MAC addresses. + +## Method 2: Cross-Namespace Restore (Copy) + +```bash +./07-restore-to-copy.sh +``` + +Creates a `RestoreJob` with `spec.options.targetNamespace` set to a different namespace +(default: `tenant-root-copy`). This creates an independent copy of the VM +without affecting the original. + +Key differences from in-place restore: + +| Aspect | In-Place | Cross-Namespace | +|---|---|---| +| Source VM affected | Yes (halted, PVCs renamed) | No (untouched) | +| Velero namespaceMapping | Not used | Maps source NS to target NS | +| OVN IP/MAC | Preserved from backup | Skipped (new IP/MAC assigned) | +| Pre-restore preparation | Full (suspend, halt, rename, delete) | Skipped | + +The script ensures the target namespace exists before creating the RestoreJob. +Velero's `namespaceMapping` redirects all resources from the source namespace to +the target namespace during restore. + +### Important limitation + +Restoring to the **same namespace** with a **different application name** is not +supported. Velero's DataUpload always writes volume data to PVCs with the +original name regardless of resource modifiers, which causes conflicts. If you +attempt this, the RestoreJob will fail with an error message suggesting +cross-namespace restore instead. + +## Configuration + +| Variable | Default | Description | +|---|---|---| +| `NAMESPACE` | `tenant-root` | Source namespace (where the Backup lives) | +| `TARGET_NAMESPACE` | `tenant-root-copy` | Target namespace for cross-namespace restore | + +## Verify + +After either restore method, verify the VM is running: + +```bash +# In-place +kubectl get vmi -n tenant-root + +# Cross-namespace copy +kubectl get vmi -n tenant-root-copy +``` + +## Cleanup + +To remove all resources created by the demo: + +```bash +./cleanup.sh +``` + +This deletes RestoreJobs, BackupJobs, Backups, VMInstance, VMDisk, BackupClass, +strategies, and the target namespace. diff --git a/go.mod b/go.mod index 35f9bc60..7b7d5bc4 100644 --- a/go.mod +++ b/go.mod @@ -2,33 +2,43 @@ module github.com/cozystack/cozystack -go 1.23.0 +go 1.25.0 require ( - github.com/fluxcd/helm-controller/api v1.1.0 + github.com/cozystack/cozystack-scheduler/pkg/apis v0.1.1 + github.com/emicklei/dot v1.10.0 + github.com/fluxcd/helm-controller/api v1.4.3 + github.com/fluxcd/source-controller/api v1.7.4 + github.com/fluxcd/source-watcher/api/v2 v2.0.3 + github.com/go-logr/logr v1.4.3 + github.com/go-logr/zapr v1.3.0 github.com/google/gofuzz v1.2.0 - github.com/onsi/ginkgo/v2 v2.19.0 - github.com/onsi/gomega v1.33.1 - github.com/spf13/cobra v1.8.1 - github.com/stretchr/testify v1.9.0 - gopkg.in/yaml.v2 v2.4.0 - k8s.io/api v0.31.2 - k8s.io/apiextensions-apiserver v0.31.2 - k8s.io/apimachinery v0.31.2 - k8s.io/apiserver v0.31.2 - k8s.io/client-go v0.31.2 - k8s.io/component-base v0.31.2 + github.com/onsi/ginkgo/v2 v2.23.3 + github.com/onsi/gomega v1.37.0 + github.com/prometheus/client_golang v1.22.0 + github.com/robfig/cron/v3 v3.0.1 + github.com/spf13/cobra v1.9.1 + github.com/vmware-tanzu/velero v1.17.1 + go.uber.org/zap v1.27.0 + k8s.io/api v0.34.1 + k8s.io/apiextensions-apiserver v0.34.1 + k8s.io/apimachinery v0.34.2 + k8s.io/apiserver v0.34.1 + k8s.io/client-go v0.34.1 + k8s.io/component-base v0.34.1 k8s.io/klog/v2 v2.130.1 - k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 - sigs.k8s.io/controller-runtime v0.19.0 - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 + k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b + k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d + sigs.k8s.io/container-object-storage-interface-api v0.1.0 + sigs.k8s.io/controller-runtime v0.22.4 + sigs.k8s.io/structured-merge-diff/v6 v6.3.0 + sigs.k8s.io/yaml v1.6.0 ) require ( + cel.dev/expr v0.24.0 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect @@ -36,83 +46,88 @@ require ( github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch v4.12.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.9.0 // indirect + github.com/emicklei/go-restful/v3 v3.12.2 // indirect + github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fluxcd/pkg/apis/kustomize v1.6.1 // indirect - github.com/fluxcd/pkg/apis/meta v1.6.1 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/fluxcd/pkg/apis/acl v0.9.0 // indirect + github.com/fluxcd/pkg/apis/kustomize v1.13.0 // indirect + github.com/fluxcd/pkg/apis/meta v1.23.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/cel-go v0.21.0 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/cel-go v0.26.0 // indirect + github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect - github.com/imdario/mergo v0.3.6 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect + github.com/mailru/easyjson v0.9.0 // indirect + github.com/moby/spdystream v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.65.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/pflag v1.0.7 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect - go.etcd.io/etcd/api/v3 v3.5.16 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.16 // indirect - go.etcd.io/etcd/client/v3 v3.5.16 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/sdk v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.etcd.io/etcd/api/v3 v3.6.4 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect + go.etcd.io/etcd/client/v3 v3.6.4 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect + go.opentelemetry.io/otel v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect + go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/sdk v1.37.0 // indirect + go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.31.0 // indirect + go.yaml.in/yaml/v2 v2.4.2 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/crypto v0.42.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/net v0.33.0 // indirect - golang.org/x/oauth2 v0.23.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/term v0.27.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/time v0.7.0 // indirect - golang.org/x/tools v0.26.0 // indirect + golang.org/x/net v0.45.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.36.0 // indirect + golang.org/x/term v0.35.0 // indirect + golang.org/x/text v0.29.0 // indirect + golang.org/x/time v0.12.0 // indirect + golang.org/x/tools v0.37.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/grpc v1.65.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect + google.golang.org/grpc v1.73.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/kms v0.31.2 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 // indirect - sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect + k8s.io/kms v0.34.1 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect ) + +// See: issues.k8s.io/135537 +replace k8s.io/apimachinery => github.com/cozystack/apimachinery v0.0.0-20251219010959-1f91eabae46c diff --git a/go.sum b/go.sum index c7aaa336..81e1779f 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,11 @@ +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= @@ -16,45 +18,54 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cozystack/apimachinery v0.0.0-20251219010959-1f91eabae46c h1:C2wIfH/OzhU9XOK/e6Ik9cg7nZ1z6fN4lf6a3yFdik8= +github.com/cozystack/apimachinery v0.0.0-20251219010959-1f91eabae46c/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +github.com/cozystack/cozystack-scheduler/pkg/apis v0.1.1 h1:9uLa/8J4lRx3sNuaVH8UZqgZvnskHATPo5GxEKh0iSM= +github.com/cozystack/cozystack-scheduler/pkg/apis v0.1.1/go.mod h1:kPeS9YPB4ENbvNINEkkp0SX8FB+gvwoOHGOHMT3Tg9Y= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/dot v1.10.0 h1:z17n0ce/FBMz3QbShSzVGhiW447Qhu7fljzvp3Gs6ig= +github.com/emicklei/dot v1.10.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= +github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= +github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= -github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fluxcd/helm-controller/api v1.1.0 h1:NS5Wm3U6Kv4w7Cw2sDOV++vf2ecGfFV00x1+2Y3QcOY= -github.com/fluxcd/helm-controller/api v1.1.0/go.mod h1:BgHMgMY6CWynzl4KIbHpd6Wpn3FN9BqgkwmvoKCp6iE= -github.com/fluxcd/pkg/apis/kustomize v1.6.1 h1:22FJc69Mq4i8aCxnKPlddHhSMyI4UPkQkqiAdWFcqe0= -github.com/fluxcd/pkg/apis/kustomize v1.6.1/go.mod h1:5dvQ4IZwz0hMGmuj8tTWGtarsuxW0rWsxJOwC6i+0V8= -github.com/fluxcd/pkg/apis/meta v1.6.1 h1:maLhcRJ3P/70ArLCY/LF/YovkxXbX+6sTWZwZQBeNq0= -github.com/fluxcd/pkg/apis/meta v1.6.1/go.mod h1:YndB/gxgGZmKfqpAfFxyCDNFJFP0ikpeJzs66jwq280= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/fluxcd/helm-controller/api v1.4.3 h1:CdZwjL1liXmYCWyk2jscmFEB59tICIlnWB9PfDDW5q4= +github.com/fluxcd/helm-controller/api v1.4.3/go.mod h1:0XrBhKEaqvxyDj/FziG1Q8Fmx2UATdaqLgYqmZh6wW4= +github.com/fluxcd/pkg/apis/acl v0.9.0 h1:wBpgsKT+jcyZEcM//OmZr9RiF8klL3ebrDp2u2ThsnA= +github.com/fluxcd/pkg/apis/acl v0.9.0/go.mod h1:TttNS+gocsGLwnvmgVi3/Yscwqrjc17+vhgYfqkfrV4= +github.com/fluxcd/pkg/apis/kustomize v1.13.0 h1:GGf0UBVRIku+gebY944icVeEIhyg1P/KE3IrhOyJJnE= +github.com/fluxcd/pkg/apis/kustomize v1.13.0/go.mod h1:TLKVqbtnzkhDuhWnAsN35977HvRfIjs+lgMuNro/LEc= +github.com/fluxcd/pkg/apis/meta v1.23.0 h1:fLis5YcHnOsyKYptzBtituBm5EWNx13I0bXQsy0FG4s= +github.com/fluxcd/pkg/apis/meta v1.23.0/go.mod h1:UWsIbBPCxYvoVklr2mV2uLFBf/n17dNAmKFjRfApdDo= +github.com/fluxcd/source-controller/api v1.7.4 h1:+EOVnRA9LmLxOx7J273l7IOEU39m+Slt/nQGBy69ygs= +github.com/fluxcd/source-controller/api v1.7.4/go.mod h1:ruf49LEgZRBfcP+eshl2n9SX1MfHayCcViAIGnZcaDY= +github.com/fluxcd/source-watcher/api/v2 v2.0.3 h1:SsVGAaMBxzvcgrOz/Kl6c2ybMHVqoiEFwtI+bDuSeSs= +github.com/fluxcd/source-watcher/api/v2 v2.0.3/go.mod h1:Nx3QZweVyuhaOtSNrw+oxifG+qrakPvjgNAN9qlUTb0= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= @@ -62,158 +73,172 @@ github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/cel-go v0.21.0 h1:cl6uW/gxN+Hy50tNYvI691+sXxioCnstFzLp2WO4GCI= -github.com/google/cel-go v0.21.0/go.mod h1:rHUlWCcBKgyEk+eV03RPdZUekPp6YcJwV0FxuUksYxc= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI= +github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= +github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= +github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0 h1:FbSCl+KggFl+Ocym490i/EyXF4lPgLoUtcSWquBM0Rs= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0/go.mod h1:qOchhhIlmRcqk/O9uCo/puJlyo07YINaIqdZfZG3Jkc= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= -github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= -github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= +github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= +github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= +github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= +github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= +github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= +github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= +github.com/vmware-tanzu/velero v1.17.1 h1:ldKeiTuUwkThOw7zrUucNA1NwnLG66zl13YetWAoE0I= +github.com/vmware-tanzu/velero v1.17.1/go.mod h1:3KTxuUN6Un38JzmYAX+8U6j2k6EexGoNNxa8jrJML8U= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk= +github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= -go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= -go.etcd.io/etcd/api/v3 v3.5.16 h1:WvmyJVbjWqK4R1E+B12RRHz3bRGy9XVfh++MgbN+6n0= -go.etcd.io/etcd/api/v3 v3.5.16/go.mod h1:1P4SlIP/VwkDmGo3OlOD7faPeP8KDIFhqvciH5EfN28= -go.etcd.io/etcd/client/pkg/v3 v3.5.16 h1:ZgY48uH6UvB+/7R9Yf4x574uCO3jIx0TRDyetSfId3Q= -go.etcd.io/etcd/client/pkg/v3 v3.5.16/go.mod h1:V8acl8pcEK0Y2g19YlOV9m9ssUe6MgiDSobSoaBAM0E= -go.etcd.io/etcd/client/v2 v2.305.13 h1:RWfV1SX5jTU0lbCvpVQe3iPQeAHETWdOTb6pxhd77C8= -go.etcd.io/etcd/client/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg= -go.etcd.io/etcd/client/v3 v3.5.16 h1:sSmVYOAHeC9doqi0gv7v86oY/BTld0SEFGaxsU9eRhE= -go.etcd.io/etcd/client/v3 v3.5.16/go.mod h1:X+rExSGkyqxvu276cr2OwPLBaeqFu1cIl4vmRjAD/50= -go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M= -go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0= -go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA= -go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw= -go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok= -go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= -go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= -go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I= +go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM= +go.etcd.io/etcd/api/v3 v3.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo= +go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk= +go.etcd.io/etcd/client/pkg/v3 v3.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0= +go.etcd.io/etcd/client/pkg/v3 v3.6.4/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI= +go.etcd.io/etcd/client/v3 v3.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A= +go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo= +go.etcd.io/etcd/pkg/v3 v3.6.4 h1:fy8bmXIec1Q35/jRZ0KOes8vuFxbvdN0aAFqmEfJZWA= +go.etcd.io/etcd/pkg/v3 v3.6.4/go.mod h1:kKcYWP8gHuBRcteyv6MXWSN0+bVMnfgqiHueIZnKMtE= +go.etcd.io/etcd/server/v3 v3.6.4 h1:LsCA7CzjVt+8WGrdsnh6RhC0XqCsLkBly3ve5rTxMAU= +go.etcd.io/etcd/server/v3 v3.6.4/go.mod h1:aYCL/h43yiONOv0QIR82kH/2xZ7m+IWYjzRmyQfnCAg= +go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ= +go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= +go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= +go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= +go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -222,50 +247,48 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= +golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= +golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= +google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= +google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -275,39 +298,38 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= -k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= -k8s.io/apiextensions-apiserver v0.31.2 h1:W8EwUb8+WXBLu56ser5IudT2cOho0gAKeTOnywBLxd0= -k8s.io/apiextensions-apiserver v0.31.2/go.mod h1:i+Geh+nGCJEGiCGR3MlBDkS7koHIIKWVfWeRFiOsUcM= -k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= -k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/apiserver v0.31.2 h1:VUzOEUGRCDi6kX1OyQ801m4A7AUPglpsmGvdsekmcI4= -k8s.io/apiserver v0.31.2/go.mod h1:o3nKZR7lPlJqkU5I3Ove+Zx3JuoFjQobGX1Gctw6XuE= -k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= -k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= -k8s.io/component-base v0.31.2 h1:Z1J1LIaC0AV+nzcPRFqfK09af6bZ4D1nAOpWsy9owlA= -k8s.io/component-base v0.31.2/go.mod h1:9PeyyFN/drHjtJZMCTkSpQJS3U9OXORnHQqMLDz0sUQ= +k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM= +k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk= +k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI= +k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc= +k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA= +k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0= +k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY= +k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8= +k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A= +k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kms v0.31.2 h1:pyx7l2qVOkClzFMIWMVF/FxsSkgd+OIGH7DecpbscJI= -k8s.io/kms v0.31.2/go.mod h1:OZKwl1fan3n3N5FFxnW5C4V3ygrah/3YXeJWS3O6+94= -k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 h1:GKE9U8BH16uynoxQii0auTjmmmuZ3O0LFMN6S0lPPhI= -k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 h1:CPT0ExVicCzcpeN4baWEV2ko2Z/AsiZgEdwgcfwLgMo= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= -sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +k8s.io/kms v0.34.1 h1:iCFOvewDPzWM9fMTfyIPO+4MeuZ0tcZbugxLNSHFG4w= +k8s.io/kms v0.34.1/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM= +k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA= +k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts= +k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d h1:wAhiDyZ4Tdtt7e46e9M5ZSAJ/MnPGPs+Ki1gHw4w1R0= +k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/container-object-storage-interface-api v0.1.0 h1:8tB6JFQhbQIC1hwGQ+q4+tmSSNfjKemb7bFI6C0CK/4= +sigs.k8s.io/container-object-storage-interface-api v0.1.0/go.mod h1:YiB+i/UGkzqgODDhRG3u7jkbWkQcoUeLEJ7hwOT/2Qk= +sigs.k8s.io/controller-runtime v0.22.4 h1:GEjV7KV3TY8e+tJ2LCTxUTanW4z/FmNB7l327UfMq9A= +sigs.k8s.io/controller-runtime v0.22.4/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/hack/admin-kubeconfig-invariant.bats b/hack/admin-kubeconfig-invariant.bats new file mode 100644 index 00000000..a4b98b00 --- /dev/null +++ b/hack/admin-kubeconfig-invariant.bats @@ -0,0 +1,145 @@ +#!/usr/bin/env bats +# ----------------------------------------------------------------------------- +# Chart-wide invariant for packages/apps/kubernetes: +# +# Every Deployment in this chart that mounts -admin-kubeconfig as a +# Secret volume MUST: +# - declare that volume optional: true (so kubelet does not FailedMount +# while Kamaji is still provisioning the Secret), AND +# - include the wait-for-kubeconfig init container (so the pod becomes +# Ready only after Kamaji publishes the Secret). +# +# The per-template unittests in packages/apps/kubernetes/tests/ lock in +# today's three Deployments (cluster-autoscaler, kccm, csi controller) by +# name. This invariant is stricter: any future Deployment added to this +# chart that mounts the same Secret but forgets the guard will fail here. +# +# Requires: helm, yq (mikefarah v4+), jq. All three are available on the +# project's CI runners and on the maintainer workstation. +# ----------------------------------------------------------------------------- + +@test "every Deployment mounting admin-kubeconfig has optional:true and wait-for-kubeconfig init" { + values_file="packages/apps/kubernetes/tests/values-ci.yaml" + [ -f "$values_file" ] + + tmp=$(mktemp -d) + trap 'rm -rf "$tmp"' EXIT + + helm template invariant packages/apps/kubernetes \ + --namespace tenant-root \ + --values "$values_file" \ + 2>/dev/null > "$tmp/rendered.yaml" + + # yq streams one JSON object per input document. jq -s slurps the stream + # into an array so we can treat all Deployments as a single collection. + yq --output-format=json eval-all '.' "$tmp/rendered.yaml" \ + | jq -s --raw-output ' + map(select(.kind == "Deployment")) | + map({ + name: .metadata.name, + volumes: (.spec.template.spec.volumes // []), + initNames: ((.spec.template.spec.initContainers // []) | map(.name)), + }) | + map( + .name as $n | + .initNames as $ins | + (.volumes[] | select(.secret.secretName | test("-admin-kubeconfig$")?)) + | { + name: $n, + optional: (.secret.optional == true), + hasInit: ($ins | index("wait-for-kubeconfig") != null), + } + ) + ' > "$tmp/summary.json" + + # At least one Deployment must match; if a refactor removes every + # admin-kubeconfig volume from this chart, the test must be updated + # deliberately rather than silently passing. + matched=$(jq 'length' "$tmp/summary.json") + [ "$matched" -ge 1 ] + + offenders=$(jq --raw-output '.[] | select(.optional != true or .hasInit != true) | .name' "$tmp/summary.json") + + if [ -n "$offenders" ]; then + echo "Deployments mounting *-admin-kubeconfig without optional:true + wait-for-kubeconfig init:" >&2 + echo "$offenders" >&2 + echo "Full summary:" >&2 + cat "$tmp/summary.json" >&2 + exit 1 + fi + + echo "Invariant holds for $matched Deployment(s)" +} + +@test "chart emits zero admin-kubeconfig Deployments when tenant has no etcd DataStore" { + # Without a DataStore (parent Tenant has not populated _namespace.etcd yet) + # the control-plane-side Deployments must NOT render at all. If they did, + # the wait-for-kubeconfig init would CrashLoopBackOff indefinitely - there + # would be no KamajiControlPlane to provision the Secret - consuming the + # HelmRelease wait budget and triggering exactly the remediation cycle the + # rest of this chart tries to avoid. This test renders the whole chart + # with etcd empty and asserts no Deployment references the admin-kubeconfig + # Secret. + tmp=$(mktemp -d) + trap 'rm -rf "$tmp"' EXIT + + helm template invariant packages/apps/kubernetes \ + --namespace tenant-root \ + --values packages/apps/kubernetes/tests/values-ci-no-etcd.yaml \ + 2>/dev/null > "$tmp/rendered.yaml" + + matched=$( + yq --output-format=json eval-all '.' "$tmp/rendered.yaml" \ + | jq -s ' + map(select(.kind == "Deployment")) | + map(select( + (.spec.template.spec.volumes // []) + | any(.secret.secretName | test("-admin-kubeconfig$")?) + )) | + length + ' + ) + + if [ "$matched" -ne 0 ]; then + echo "Expected zero Deployments mounting *-admin-kubeconfig when etcd is empty, got $matched:" >&2 + yq --output-format=json eval-all '.' "$tmp/rendered.yaml" \ + | jq -s 'map(select(.kind == "Deployment") | .metadata.name)' >&2 + exit 1 + fi + + echo "No admin-kubeconfig Deployments rendered for empty etcd (as expected)" +} + +@test "chart emits zero admin-kubeconfig HelmReleases when tenant has no etcd DataStore" { + # Same principle as the Deployment variant above, extended to every child + # HelmRelease (cilium, coredns, csi, cert-manager, ...). They reference + # *-admin-kubeconfig via kubeConfig.secretRef and would otherwise sit in + # NotReady forever on an etcd-less tenant, polluting the HelmRelease list + # the operator sees and contradicting the "awaiting-etcd beacon only" + # contract of the soft-skip path. + tmp=$(mktemp -d) + trap 'rm -rf "$tmp"' EXIT + + helm template invariant packages/apps/kubernetes \ + --namespace tenant-root \ + --values packages/apps/kubernetes/tests/values-ci-no-etcd.yaml \ + 2>/dev/null > "$tmp/rendered.yaml" + + matched=$( + yq --output-format=json eval-all '.' "$tmp/rendered.yaml" \ + | jq -s ' + map(select(.kind == "HelmRelease")) | + map(select(.spec.kubeConfig.secretRef.name | test("-admin-kubeconfig$")?)) | + length + ' + ) + + if [ "$matched" -ne 0 ]; then + echo "Expected zero HelmReleases referencing *-admin-kubeconfig when etcd is empty, got $matched:" >&2 + yq --output-format=json eval-all '.' "$tmp/rendered.yaml" \ + | jq -s 'map(select(.kind == "HelmRelease") | .metadata.name)' >&2 + exit 1 + fi + + echo "No admin-kubeconfig HelmReleases rendered for empty etcd (as expected)" +} diff --git a/hack/cdi_golden_image_create.sh b/hack/cdi_golden_image_create.sh index be1558d0..f19f9970 100644 --- a/hack/cdi_golden_image_create.sh +++ b/hack/cdi_golden_image_create.sh @@ -16,7 +16,7 @@ kubectl create -f - <:(:)+ +# where each is [a-z0-9_]. Raw DCGM metrics (DCGM_FI_*), +# kube-state-metrics (kube_*) and similar uppercase / single-word metric +# names do not match because the leading segment must be lowercase and the +# whole expression must contain at least two ':' characters. +extract_refs() { + json_file=$1 + # Prometheus convention allows 2-segment rule names (level:metric); this + # regex is tuned to the 3+ segment convention used in this repo + # (level:metric:op — e.g. cluster:gpu_count:total). Update if future + # rules use 2 segments, otherwise they will be silently skipped. + grep -hoE '[a-z][a-z0-9_]*:[a-z0-9_]+:[a-z0-9_]+' "$json_file" | sort -u +} + +# Resolve "gpu/foo" -> "$DASHBOARDS_DIR/gpu/foo.json" +list_tracked_gpu_dashboards() { + awk '/^gpu\// { print $0 ".json" }' "$DASHBOARDS_LIST" +} + +# Extract the set of DCGM_FI_* metric names declared in a CSV file. Handles +# both the upstream-style default CSV (unindented) and the ConfigMap-style +# custom CSV (YAML-indented). A declaration line starts — after any leading +# whitespace — with "DCGM_FI_," ; comment lines begin with "#" and are +# skipped. Uses POSIX awk's match()+RSTART/RLENGTH so no GNU extensions +# are required. +extract_csv_metrics() { + file=$1 + awk ' + { + line = $0 + sub(/^[[:space:]]+/, "", line) + if (line ~ /^#/) next + if (match(line, /^DCGM_FI_[A-Z0-9_]+/)) { + print substr(line, RSTART, RLENGTH) + } + } + ' "$file" | sort -u +} + +# Extract the set of DCGM_FI_* metric references from a text file (dashboard +# JSON or rules YAML). A DCGM metric name has at least two underscore-delimited +# segments after the "DCGM_FI_" prefix (e.g. DCGM_FI_DEV_GPU_UTIL, DCGM_FI_PROF_ +# PIPE_TENSOR_ACTIVE, DCGM_FI_DRIVER_VERSION). Requiring two segments keeps +# the matcher from latching onto glob stubs like "DCGM_FI_DEV_*_VIOLATION" that +# appear in comments. +extract_dcgm_refs() { + file=$1 + grep -hoE 'DCGM_FI_[A-Z0-9]+(_[A-Z0-9]+)+' "$file" | sort -u +} + +@test "every recording rule reference in tracked GPU dashboards has a matching record" { + TMP=$(mktemp -d) + trap 'rm -rf "$TMP"' EXIT + + extract_rules > "$TMP/rules.txt" + [ -s "$TMP/rules.txt" ] || { echo "no recording rules extracted from $RULES_FILE" >&2; exit 1; } + + list_tracked_gpu_dashboards > "$TMP/dashboards.txt" + [ -s "$TMP/dashboards.txt" ] || { echo "no gpu/* dashboards listed in $DASHBOARDS_LIST" >&2; exit 1; } + + failed=0 + while IFS= read -r dashboard_rel; do + dashboard="$DASHBOARDS_DIR/$dashboard_rel" + if [ ! -f "$dashboard" ]; then + echo "ERROR: dashboard listed but file missing: $dashboard" >&2 + failed=1 + continue + fi + + extract_refs "$dashboard" > "$TMP/refs.txt" + # comm -23: lines unique to refs.txt (referenced but not defined) + # Both inputs must be sorted; extract_* helpers already sort. + comm -23 "$TMP/refs.txt" "$TMP/rules.txt" > "$TMP/missing.txt" + if [ -s "$TMP/missing.txt" ]; then + echo "ERROR: $dashboard_rel references undefined recording rules:" >&2 + sed 's/^/ - /' "$TMP/missing.txt" >&2 + failed=1 + fi + done < "$TMP/dashboards.txt" + + [ "$failed" -eq 0 ] +} + +@test "every DCGM metric referenced in tracked dashboards and rules is declared" { + TMP=$(mktemp -d) + trap 'rm -rf "$TMP"' EXIT + + [ -f "$DCGM_DEFAULT_CSV" ] || { echo "missing $DCGM_DEFAULT_CSV" >&2; exit 1; } + [ -f "$DCGM_CUSTOM_CSV" ] || { echo "missing $DCGM_CUSTOM_CSV" >&2; exit 1; } + + { + extract_csv_metrics "$DCGM_DEFAULT_CSV" + extract_csv_metrics "$DCGM_CUSTOM_CSV" + } | sort -u > "$TMP/declared.txt" + [ -s "$TMP/declared.txt" ] || { echo "no DCGM metrics extracted from CSVs" >&2; exit 1; } + + list_tracked_gpu_dashboards > "$TMP/dashboards.txt" + [ -s "$TMP/dashboards.txt" ] || { echo "no gpu/* dashboards listed in $DASHBOARDS_LIST" >&2; exit 1; } + + failed=0 + + # Dashboard coverage — every dashboard's DCGM references must resolve. + while IFS= read -r dashboard_rel; do + dashboard="$DASHBOARDS_DIR/$dashboard_rel" + [ -f "$dashboard" ] || continue # handled by the existence test + extract_dcgm_refs "$dashboard" > "$TMP/refs.txt" + [ -s "$TMP/refs.txt" ] || continue # dashboard relies entirely on recording rules + comm -23 "$TMP/refs.txt" "$TMP/declared.txt" > "$TMP/missing.txt" + if [ -s "$TMP/missing.txt" ]; then + echo "ERROR: $dashboard_rel references DCGM metrics not declared in any CSV:" >&2 + sed 's/^/ - /' "$TMP/missing.txt" >&2 + failed=1 + fi + done < "$TMP/dashboards.txt" + + # Rules coverage — recording rules consume DCGM directly, so their set + # must be declared too, otherwise derived series on every dashboard + # collapse to empty. + extract_dcgm_refs "$RULES_FILE" > "$TMP/rule-refs.txt" + if [ -s "$TMP/rule-refs.txt" ]; then + comm -23 "$TMP/rule-refs.txt" "$TMP/declared.txt" > "$TMP/rule-missing.txt" + if [ -s "$TMP/rule-missing.txt" ]; then + echo "ERROR: gpu-recording.rules.yaml references DCGM metrics not declared in any CSV:" >&2 + sed 's/^/ - /' "$TMP/rule-missing.txt" >&2 + failed=1 + fi + fi + + [ "$failed" -eq 0 ] +} + +@test "every tracked GPU dashboard listed in dashboards-infra.list exists on disk" { + TMP=$(mktemp -d) + trap 'rm -rf "$TMP"' EXIT + + list_tracked_gpu_dashboards > "$TMP/dashboards.txt" + [ -s "$TMP/dashboards.txt" ] || { echo "no gpu/* dashboards listed in $DASHBOARDS_LIST" >&2; exit 1; } + + failed=0 + while IFS= read -r dashboard_rel; do + dashboard="$DASHBOARDS_DIR/$dashboard_rel" + if [ ! -f "$dashboard" ]; then + echo "ERROR: $dashboard_rel listed in dashboards-infra.list but $dashboard does not exist" >&2 + failed=1 + fi + done < "$TMP/dashboards.txt" + + [ "$failed" -eq 0 ] +} diff --git a/hack/check-host-runtime.bats b/hack/check-host-runtime.bats new file mode 100644 index 00000000..b121b31b --- /dev/null +++ b/hack/check-host-runtime.bats @@ -0,0 +1,415 @@ +#!/usr/bin/env bats +# ----------------------------------------------------------------------------- +# Unit tests for hack/check-host-runtime.sh +# +# The script warns when a standalone containerd.service or docker.service is +# active alongside the embedded k3s runtime on Ubuntu hosts running the +# cozystack "generic" variant. Warnings go to stderr; exit code is always 0. +# +# Test strategy: each test builds its own temporary stub directory and prepends +# it to PATH to inject a fake `systemctl` (and optionally `du`) binary. The +# script itself honors a small set of COZYSTACK_PREFLIGHT_* environment +# variables to redirect socket/dir probes into the stub tree, so tests do not +# need root privileges or a real systemd host. +# +# Each test installs a `trap 'rm -rf "$STUB_DIR"' EXIT` immediately after +# creating the stub dir so cleanup runs even when an assertion fails mid-test +# under `set -e`. cozytest.sh runs each @test in its own subshell, so traps +# scope per test and do not leak across tests. +# +# Tests are otherwise self-contained — no shared setup/teardown helpers, +# because cozytest.sh's awk parser only recognizes @test blocks and treats a +# bare `}` on its own line as the end of a test function. +# +# Title syntax constraints (inherited from cozytest.sh's awk parser): +# - Titles must be delimited by ASCII double quotes; embedded literal +# double quotes are NOT escaped and will silently truncate the title. +# - Only alphanumeric characters from the title survive into the shell +# function name (everything else becomes '_'), so titles that differ +# only in punctuation collapse to the same function name. Keep titles +# distinctive in their alphanumeric run. +# +# Run with: hack/cozytest.sh hack/check-host-runtime.bats +# (or `bats hack/check-host-runtime.bats` if the bats binary is +# installed; cozytest.sh is the CI path.) +# ----------------------------------------------------------------------------- + +@test "clean host with no runtime services exits silently" { + STUB_DIR=$(mktemp -d) + trap 'rm -rf "$STUB_DIR"' EXIT + + cat >"$STUB_DIR/systemctl" <<'STUBEOF' +#!/bin/sh +if [ "$1" = "--version" ]; then + echo "systemd stub" + exit 0 +fi +exit 1 +STUBEOF + chmod +x "$STUB_DIR/systemctl" + + STDERR_FILE="$STUB_DIR/stderr" + COZYSTACK_CONTAINERD_SOCKET="$STUB_DIR/missing-containerd.sock" \ + COZYSTACK_DOCKER_SOCKET_PATHS="$STUB_DIR/missing-docker1.sock $STUB_DIR/missing-docker2.sock" \ + COZYSTACK_CONTAINERD_DIR="$STUB_DIR/missing-containerd-dir" \ + COZYSTACK_DOCKER_DIR="$STUB_DIR/missing-docker-dir" \ + PATH="$STUB_DIR:$PATH" \ + bash hack/check-host-runtime.sh >"$STUB_DIR/stdout" 2>"$STDERR_FILE" + + [ ! -s "$STDERR_FILE" ] + [ ! -s "$STUB_DIR/stdout" ] +} + +@test "standalone containerd service active prints warning" { + STUB_DIR=$(mktemp -d) + trap 'rm -rf "$STUB_DIR"' EXIT + + cat >"$STUB_DIR/systemctl" <<'STUBEOF' +#!/bin/sh +if [ "$1" = "--version" ]; then + echo "systemd stub" + exit 0 +fi +if [ "$1" = "is-active" ] && [ "$2" = "containerd.service" ]; then + echo active + exit 0 +fi +exit 1 +STUBEOF + chmod +x "$STUB_DIR/systemctl" + + mkdir -p "$STUB_DIR/var-lib-containerd" + echo dummy >"$STUB_DIR/var-lib-containerd/dummy" + + STDERR_FILE="$STUB_DIR/stderr" + COZYSTACK_CONTAINERD_SOCKET="$STUB_DIR/missing-containerd.sock" \ + COZYSTACK_DOCKER_SOCKET_PATHS="$STUB_DIR/missing-docker.sock" \ + COZYSTACK_CONTAINERD_DIR="$STUB_DIR/var-lib-containerd" \ + COZYSTACK_DOCKER_DIR="$STUB_DIR/missing-docker-dir" \ + PATH="$STUB_DIR:$PATH" \ + bash hack/check-host-runtime.sh 2>"$STDERR_FILE" + + grep -q 'standalone containerd.service' "$STDERR_FILE" + if grep -q 'standalone docker.service' "$STDERR_FILE"; then + echo "unexpected docker warning found:" >&2 + cat "$STDERR_FILE" >&2 + exit 1 + fi + # HINT line must name only the detected service, not advise disabling + # docker.service when only containerd.service is running. The sudo + # prefix is also required — without it the command silently no-ops + # for a non-root operator, so the prefix is part of the contract. + grep -q 'sudo systemctl disable --now containerd.service' "$STDERR_FILE" + if grep -q 'systemctl disable --now.*docker' "$STDERR_FILE"; then + echo "HINT unexpectedly mentions docker:" >&2 + cat "$STDERR_FILE" >&2 + exit 1 + fi +} + +@test "standalone docker service active prints warning" { + STUB_DIR=$(mktemp -d) + trap 'rm -rf "$STUB_DIR"' EXIT + + cat >"$STUB_DIR/systemctl" <<'STUBEOF' +#!/bin/sh +if [ "$1" = "--version" ]; then + echo "systemd stub" + exit 0 +fi +if [ "$1" = "is-active" ] && [ "$2" = "docker.service" ]; then + echo active + exit 0 +fi +exit 1 +STUBEOF + chmod +x "$STUB_DIR/systemctl" + + mkdir -p "$STUB_DIR/var-lib-docker" + echo dummy >"$STUB_DIR/var-lib-docker/dummy" + + STDERR_FILE="$STUB_DIR/stderr" + COZYSTACK_CONTAINERD_SOCKET="$STUB_DIR/missing-containerd.sock" \ + COZYSTACK_DOCKER_SOCKET_PATHS="$STUB_DIR/missing-docker.sock" \ + COZYSTACK_CONTAINERD_DIR="$STUB_DIR/missing-containerd-dir" \ + COZYSTACK_DOCKER_DIR="$STUB_DIR/var-lib-docker" \ + PATH="$STUB_DIR:$PATH" \ + bash hack/check-host-runtime.sh 2>"$STDERR_FILE" + + grep -q 'standalone docker.service' "$STDERR_FILE" + if grep -q 'standalone containerd.service' "$STDERR_FILE"; then + echo "unexpected containerd warning found:" >&2 + cat "$STDERR_FILE" >&2 + exit 1 + fi + # HINT line must name only the detected service. As in the + # containerd test, the sudo prefix is part of the contract. + grep -q 'sudo systemctl disable --now docker.service' "$STDERR_FILE" + if grep -q 'systemctl disable --now.*containerd' "$STDERR_FILE"; then + echo "HINT unexpectedly mentions containerd:" >&2 + cat "$STDERR_FILE" >&2 + exit 1 + fi +} + +@test "both services active prints two warnings and the HINT block" { + STUB_DIR=$(mktemp -d) + trap 'rm -rf "$STUB_DIR"' EXIT + + cat >"$STUB_DIR/systemctl" <<'STUBEOF' +#!/bin/sh +if [ "$1" = "--version" ]; then + echo "systemd stub" + exit 0 +fi +if [ "$1" = "is-active" ]; then + case "$2" in + containerd.service|docker.service) echo active; exit 0 ;; + esac +fi +exit 1 +STUBEOF + chmod +x "$STUB_DIR/systemctl" + + mkdir -p "$STUB_DIR/var-lib-containerd" "$STUB_DIR/var-lib-docker" + + STDERR_FILE="$STUB_DIR/stderr" + # Capture exit code explicitly: the script contract says exit 0 + # unconditionally (warning, not blocker). `set -e` in the test + # function body would already fail on a nonzero exit, but an + # explicit status check locks in the contract and makes a + # regression show up as "expected 0, got N" rather than as a + # generic test failure. + status=0 + COZYSTACK_CONTAINERD_SOCKET="$STUB_DIR/missing-containerd.sock" \ + COZYSTACK_DOCKER_SOCKET_PATHS="$STUB_DIR/missing-docker.sock" \ + COZYSTACK_CONTAINERD_DIR="$STUB_DIR/var-lib-containerd" \ + COZYSTACK_DOCKER_DIR="$STUB_DIR/var-lib-docker" \ + PATH="$STUB_DIR:$PATH" \ + bash hack/check-host-runtime.sh 2>"$STDERR_FILE" || status=$? + + [ "$status" -eq 0 ] + grep -q 'standalone containerd.service' "$STDERR_FILE" + grep -q 'standalone docker.service' "$STDERR_FILE" + # HINT block must fire whenever warnings exist; otherwise a future silent + # removal of the HINT would go unnoticed. When both services fire the HINT + # must list both in a single sudo systemctl disable invocation — the sudo + # prefix is as important as the systemctl verb, otherwise the operator + # would be told to run it as a non-root user and quietly fail. + grep -q 'HINT:' "$STDERR_FILE" + grep -q 'sudo systemctl disable --now containerd.service docker.service' "$STDERR_FILE" +} + +@test "failing du does not suppress the containerd warning" { + STUB_DIR=$(mktemp -d) + trap 'rm -rf "$STUB_DIR"' EXIT + + cat >"$STUB_DIR/systemctl" <<'STUBEOF' +#!/bin/sh +if [ "$1" = "--version" ]; then + echo "systemd stub" + exit 0 +fi +if [ "$1" = "is-active" ] && [ "$2" = "containerd.service" ]; then + echo active + exit 0 +fi +exit 1 +STUBEOF + chmod +x "$STUB_DIR/systemctl" + cat >"$STUB_DIR/du" <<'DUEOF' +#!/bin/sh +exit 1 +DUEOF + chmod +x "$STUB_DIR/du" + + mkdir -p "$STUB_DIR/var-lib-containerd" + + STDERR_FILE="$STUB_DIR/stderr" + COZYSTACK_CONTAINERD_SOCKET="$STUB_DIR/missing-containerd.sock" \ + COZYSTACK_DOCKER_SOCKET_PATHS="$STUB_DIR/missing-docker.sock" \ + COZYSTACK_CONTAINERD_DIR="$STUB_DIR/var-lib-containerd" \ + COZYSTACK_DOCKER_DIR="$STUB_DIR/missing-docker-dir" \ + PATH="$STUB_DIR:$PATH" \ + bash hack/check-host-runtime.sh 2>"$STDERR_FILE" + + grep -q 'standalone containerd.service' "$STDERR_FILE" +} + +@test "containerd socket fallback fires when systemctl is unavailable" { + STUB_DIR=$(mktemp -d) + trap 'rm -rf "$STUB_DIR"' EXIT + + # The script uses `[ -e "$sock" ]`, not `[ -S ... ]`, so a regular + # file is a valid stand-in for a unix socket in tests. This also + # removes any optional runtime dependency on python3 and makes the + # test unconditional on every CI runner. + SOCK="$STUB_DIR/containerd.sock" + touch "$SOCK" + + STDERR_FILE="$STUB_DIR/stderr" + COZYSTACK_PREFLIGHT_FORCE_NO_SYSTEMCTL=1 \ + COZYSTACK_CONTAINERD_SOCKET="$SOCK" \ + COZYSTACK_DOCKER_SOCKET_PATHS="$STUB_DIR/missing-docker.sock" \ + COZYSTACK_CONTAINERD_DIR="$STUB_DIR/missing-containerd-dir" \ + COZYSTACK_DOCKER_DIR="$STUB_DIR/missing-docker-dir" \ + bash hack/check-host-runtime.sh 2>"$STDERR_FILE" + + grep -q 'standalone containerd.service' "$STDERR_FILE" +} + +@test "docker socket fallback fires when systemctl is unavailable" { + STUB_DIR=$(mktemp -d) + trap 'rm -rf "$STUB_DIR"' EXIT + + SOCK="$STUB_DIR/docker.sock" + touch "$SOCK" + + STDERR_FILE="$STUB_DIR/stderr" + COZYSTACK_PREFLIGHT_FORCE_NO_SYSTEMCTL=1 \ + COZYSTACK_CONTAINERD_SOCKET="$STUB_DIR/missing-containerd.sock" \ + COZYSTACK_DOCKER_SOCKET_PATHS="$SOCK" \ + COZYSTACK_CONTAINERD_DIR="$STUB_DIR/missing-containerd-dir" \ + COZYSTACK_DOCKER_DIR="$STUB_DIR/missing-docker-dir" \ + bash hack/check-host-runtime.sh 2>"$STDERR_FILE" + + grep -q 'standalone docker.service' "$STDERR_FILE" + if grep -q 'standalone containerd.service' "$STDERR_FILE"; then + echo "unexpected containerd warning found:" >&2 + cat "$STDERR_FILE" >&2 + exit 1 + fi +} + +@test "clean host without systemctl exits silently" { + STUB_DIR=$(mktemp -d) + trap 'rm -rf "$STUB_DIR"' EXIT + + STDERR_FILE="$STUB_DIR/stderr" + COZYSTACK_PREFLIGHT_FORCE_NO_SYSTEMCTL=1 \ + COZYSTACK_CONTAINERD_SOCKET="$STUB_DIR/missing-containerd.sock" \ + COZYSTACK_DOCKER_SOCKET_PATHS="$STUB_DIR/missing-docker1.sock $STUB_DIR/missing-docker2.sock" \ + COZYSTACK_CONTAINERD_DIR="$STUB_DIR/missing-containerd-dir" \ + COZYSTACK_DOCKER_DIR="$STUB_DIR/missing-docker-dir" \ + bash hack/check-host-runtime.sh >"$STUB_DIR/stdout" 2>"$STDERR_FILE" + + [ ! -s "$STDERR_FILE" ] + [ ! -s "$STUB_DIR/stdout" ] +} + +@test "docker service plus socket still emits exactly one warning" { + STUB_DIR=$(mktemp -d) + trap 'rm -rf "$STUB_DIR"' EXIT + + cat >"$STUB_DIR/systemctl" <<'STUBEOF' +#!/bin/sh +if [ "$1" = "--version" ]; then + echo "systemd stub" + exit 0 +fi +if [ "$1" = "is-active" ] && [ "$2" = "docker.service" ]; then + echo active + exit 0 +fi +exit 1 +STUBEOF + chmod +x "$STUB_DIR/systemctl" + + SOCK="$STUB_DIR/docker.sock" + touch "$SOCK" + + mkdir -p "$STUB_DIR/var-lib-docker" + + STDERR_FILE="$STUB_DIR/stderr" + COZYSTACK_CONTAINERD_SOCKET="$STUB_DIR/missing-containerd.sock" \ + COZYSTACK_DOCKER_SOCKET_PATHS="$SOCK" \ + COZYSTACK_CONTAINERD_DIR="$STUB_DIR/missing-containerd-dir" \ + COZYSTACK_DOCKER_DIR="$STUB_DIR/var-lib-docker" \ + PATH="$STUB_DIR:$PATH" \ + bash hack/check-host-runtime.sh 2>"$STDERR_FILE" + + count=$(grep -c 'standalone docker.service' "$STDERR_FILE") + if [ "$count" != "1" ]; then + echo "expected exactly one docker warning, got $count" >&2 + cat "$STDERR_FILE" >&2 + exit 1 + fi +} + +@test "docker socket paths with glob chars do not expand" { + STUB_DIR=$(mktemp -d) + trap 'rm -rf "$STUB_DIR"' EXIT + + # Create two directories that a naive `for sock in $PATHS` loop + # would glob-expand and treat as existing "sockets". With the + # array-based parsing the literal path "$STUB_DIR/var-lib-*" does + # not exist and no warning must fire. + mkdir -p "$STUB_DIR/var-lib-docker" "$STUB_DIR/var-lib-containerd" + + cat >"$STUB_DIR/systemctl" <<'STUBEOF' +#!/bin/sh +if [ "$1" = "--version" ]; then + echo "systemd stub" + exit 0 +fi +exit 1 +STUBEOF + chmod +x "$STUB_DIR/systemctl" + + STDERR_FILE="$STUB_DIR/stderr" + COZYSTACK_CONTAINERD_SOCKET="$STUB_DIR/missing-containerd.sock" \ + COZYSTACK_DOCKER_SOCKET_PATHS="$STUB_DIR/var-lib-*" \ + COZYSTACK_CONTAINERD_DIR="$STUB_DIR/missing-containerd-dir" \ + COZYSTACK_DOCKER_DIR="$STUB_DIR/missing-docker-dir" \ + PATH="$STUB_DIR:$PATH" \ + bash hack/check-host-runtime.sh 2>"$STDERR_FILE" + + if grep -q 'standalone docker.service' "$STDERR_FILE"; then + echo "glob pattern expanded — docker warning should not fire:" >&2 + cat "$STDERR_FILE" >&2 + exit 1 + fi +} + +@test "containerd service plus socket still emits exactly one warning" { + STUB_DIR=$(mktemp -d) + trap 'rm -rf "$STUB_DIR"' EXIT + + cat >"$STUB_DIR/systemctl" <<'STUBEOF' +#!/bin/sh +if [ "$1" = "--version" ]; then + echo "systemd stub" + exit 0 +fi +if [ "$1" = "is-active" ] && [ "$2" = "containerd.service" ]; then + echo active + exit 0 +fi +exit 1 +STUBEOF + chmod +x "$STUB_DIR/systemctl" + + # The script uses `[ -e "$sock" ]`, not `[ -S ... ]`, so a regular + # file is a valid stand-in for a unix socket in tests. This also + # removes any optional runtime dependency on python3 and makes the + # test unconditional on every CI runner. + SOCK="$STUB_DIR/containerd.sock" + touch "$SOCK" + + mkdir -p "$STUB_DIR/var-lib-containerd" + + STDERR_FILE="$STUB_DIR/stderr" + COZYSTACK_CONTAINERD_SOCKET="$SOCK" \ + COZYSTACK_DOCKER_SOCKET_PATHS="$STUB_DIR/missing-docker.sock" \ + COZYSTACK_CONTAINERD_DIR="$STUB_DIR/var-lib-containerd" \ + COZYSTACK_DOCKER_DIR="$STUB_DIR/missing-docker-dir" \ + PATH="$STUB_DIR:$PATH" \ + bash hack/check-host-runtime.sh 2>"$STDERR_FILE" + + count=$(grep -c 'standalone containerd.service' "$STDERR_FILE") + if [ "$count" != "1" ]; then + echo "expected exactly one containerd warning, got $count" >&2 + cat "$STDERR_FILE" >&2 + exit 1 + fi +} diff --git a/hack/check-host-runtime.sh b/hack/check-host-runtime.sh new file mode 100755 index 00000000..917453d2 --- /dev/null +++ b/hack/check-host-runtime.sh @@ -0,0 +1,161 @@ +#!/usr/bin/env bash +# ----------------------------------------------------------------------------- +# check-host-runtime.sh — operator preflight warning +# +# Purpose: +# Warn when a standalone containerd.service or docker.service is running on +# the host alongside the embedded k3s runtime. This mismatch is silent on +# day 0 (k3s uses its own containerd at /run/k3s/containerd/containerd.sock +# and /var/lib/rancher/k3s/agent/containerd) but over time the standalone +# runtime accumulates unpruned images and build cache in /var/lib/containerd +# — enough to trigger DiskPressure and crash cozystack-api with eviction +# loops. The script does NOT block install; it only prints a warning. +# +# When to run: +# Before `helm install cozy-installer` on an Ubuntu host prepared with k3s +# or kubeadm (cozystack "generic" variant). Irrelevant on Talos where the +# container runtime lifecycle is fully managed. Discoverable via +# `make preflight` from the repository root. +# +# Exit code: +# Always 0 (warning, not a blocker). Warnings go to stderr. +# +# Environment variables (test hooks — override default probe paths): +# COZYSTACK_CONTAINERD_SOCKET standalone containerd socket path +# COZYSTACK_DOCKER_SOCKET_PATHS space-separated list of docker socket paths +# COZYSTACK_CONTAINERD_DIR standalone containerd data directory +# COZYSTACK_DOCKER_DIR standalone docker data directory +# COZYSTACK_PREFLIGHT_FORCE_NO_SYSTEMCTL=1 pretend systemctl is absent +# ----------------------------------------------------------------------------- +set -euo pipefail + +if [ -t 2 ]; then + YELLOW=$'\033[1;33m' + RESET=$'\033[0m' +else + YELLOW='' + RESET='' +fi + +CONTAINERD_SOCKET=${COZYSTACK_CONTAINERD_SOCKET:-/run/containerd/containerd.sock} +DOCKER_SOCKET_PATHS=${COZYSTACK_DOCKER_SOCKET_PATHS:-/run/docker.sock /var/run/docker.sock} +CONTAINERD_DIR=${COZYSTACK_CONTAINERD_DIR:-/var/lib/containerd} +DOCKER_DIR=${COZYSTACK_DOCKER_DIR:-/var/lib/docker} + +CONTAINERD_WARN=0 +DOCKER_WARN=0 + +warn() { + printf '%sWARNING:%s %s\n' "$YELLOW" "$RESET" "$1" >&2 +} + +detect_systemctl() { + if [ "${COZYSTACK_PREFLIGHT_FORCE_NO_SYSTEMCTL:-0}" = "1" ]; then + return 1 + fi + if command -v systemctl >/dev/null 2>&1 && systemctl --version >/dev/null 2>&1; then + return 0 + fi + return 1 +} + +disk_usage() { + local path=$1 + local usage + if [ -d "$path" ]; then + # Wrap `du` in `timeout 5s` so a container data directory with + # millions of files (the exact scenario this script exists to + # warn about) cannot stall the preflight indefinitely. If the + # `timeout` binary is absent the pipeline still exits 0 via + # `|| true` and `usage` stays empty; the warning itself is + # still printed, just without the size detail. + usage=$(timeout 5s du -sh "$path" 2>/dev/null | awk '{print $1}' || true) + if [ -n "${usage:-}" ]; then + printf ' (%s uses %s)' "$path" "$usage" + fi + fi +} + +service_active() { + local service=$1 + if [ "$HAS_SYSTEMCTL" = "1" ]; then + if systemctl is-active "$service" >/dev/null 2>&1; then + return 0 + fi + fi + return 1 +} + +check_containerd() { + local detail="" + local found=0 + if service_active containerd.service; then + found=1 + fi + if [ "$found" -eq 0 ] && [ -e "$CONTAINERD_SOCKET" ]; then + found=1 + fi + if [ "$found" -eq 1 ]; then + detail=$(disk_usage "$CONTAINERD_DIR") + warn "standalone containerd.service detected alongside k3s embedded runtime${detail}" + CONTAINERD_WARN=1 + fi +} + +check_docker() { + local detail="" + local found=0 + if service_active docker.service; then + found=1 + fi + if [ "$found" -eq 0 ]; then + # DOCKER_SOCKET_PATHS is a space separated list of paths. Parse + # it into an array via `read -ra` so that word splitting is + # explicit AND glob expansion is suppressed — `for sock in + # $DOCKER_SOCKET_PATHS` would both word split and glob, so a + # path containing a literal `*` or `?` could expand into + # directory entries and produce false positives. + local -a _socks + read -ra _socks <<<"$DOCKER_SOCKET_PATHS" + for sock in "${_socks[@]}"; do + if [ -e "$sock" ]; then + found=1 + break + fi + done + fi + if [ "$found" -eq 1 ]; then + detail=$(disk_usage "$DOCKER_DIR") + warn "standalone docker.service detected alongside k3s embedded runtime${detail}" + DOCKER_WARN=1 + fi +} + +if detect_systemctl; then + HAS_SYSTEMCTL=1 +else + HAS_SYSTEMCTL=0 +fi + +check_containerd +check_docker + +if [ "$CONTAINERD_WARN" -eq 1 ] || [ "$DOCKER_WARN" -eq 1 ]; then + services="" + if [ "$CONTAINERD_WARN" -eq 1 ]; then + services="containerd.service" + fi + if [ "$DOCKER_WARN" -eq 1 ]; then + if [ -n "$services" ]; then + services="$services docker.service" + else + services="docker.service" + fi + fi + printf '%sHINT:%s cozystack runs its own containerd under k3s. To stop the shadow runtime:\n' "$YELLOW" "$RESET" >&2 + printf ' sudo systemctl disable --now %s\n' "$services" >&2 + printf 'Inspect and reclaim standalone runtime storage separately — it may contain container data\n' >&2 + printf 'that the operator still needs; do not delete it blindly.\n' >&2 +fi + +exit 0 diff --git a/hack/check-optional-repos.sh b/hack/check-optional-repos.sh new file mode 100755 index 00000000..1faa6d2c --- /dev/null +++ b/hack/check-optional-repos.sh @@ -0,0 +1,145 @@ +#!/bin/bash +############################################################################### +# check-optional-repos.sh - Check optional repositories for tags and commits # +# during a release period # +############################################################################### +set -eu + +# Function to ensure repository is cloned and up-to-date +update_repo() { + local repo_name=$1 + local repo_url="https://github.com/cozystack/${repo_name}.git" + + mkdir -p _repos + cd _repos + + if [ -d "$repo_name" ]; then + cd "$repo_name" + git fetch --all --tags --force + git checkout main 2>/dev/null || git checkout master + git pull + else + git clone "$repo_url" + cd "$repo_name" + fi + + cd ../.. +} + +# Check if required parameters are provided +if [ $# -lt 2 ]; then + echo "Usage: $0 " + echo "Example: $0 '2025-10-10 12:27:31 +0400' '2025-10-13 16:04:33 +0200'" + exit 1 +fi + +RELEASE_START="$1" +RELEASE_END="$2" + +# Get the script directory to return to it later +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +COZYSTACK_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" + +cd "$COZYSTACK_ROOT" + +echo "Checking optional repositories for tags and commits between:" +echo " Start: $RELEASE_START" +echo " End: $RELEASE_END" +echo "" + +# Loop through ALL optional repositories +for repo_name in talm boot-to-talos cozyhr cozy-proxy; do + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "Checking repository: $repo_name" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + # Update/clone repository + update_repo "$repo_name" + + cd "_repos/$repo_name" + REPO_NAME=$(basename "$(pwd)") + git fetch --all --tags --force + + # Check for tags matching release version pattern or created during release period + TAGS=$(git for-each-ref --format='%(refname:short) %(creatordate)' refs/tags 2>/dev/null | \ + awk -v start="$RELEASE_START" -v end="$RELEASE_END" '$2 >= start && $2 <= end {print $1}' || true) + + if [ -n "$TAGS" ]; then + echo "Found tags in $repo_name: $TAGS" + PREV_TAG=$(echo "$TAGS" | head -1) + NEW_TAG=$(echo "$TAGS" | tail -1) + + echo "" + echo "Commits between $PREV_TAG and $NEW_TAG:" + # Include merge commits to capture backports + git log "$PREV_TAG..$NEW_TAG" --format="%H|%s|%an" 2>/dev/null | while IFS='|' read -r commit_hash subject author_name; do + if [ -z "$commit_hash" ]; then + continue + fi + + # Get PR number from commit message + COMMIT_MSG=$(git log -1 --format=%B "$commit_hash" 2>/dev/null || echo "") + PR_NUMBER=$(echo "$COMMIT_MSG" | grep -oE '#[0-9]+' | head -1 | tr -d '#' || echo "") + + # Get author: prioritize PR author, fallback to commit author + GITHUB_USERNAME="" + if [ -n "$PR_NUMBER" ]; then + GITHUB_USERNAME=$(gh pr view "$PR_NUMBER" --repo "cozystack/$REPO_NAME" --json author --jq '.author.login // empty' 2>/dev/null || echo "") + fi + if [ -z "$GITHUB_USERNAME" ]; then + GITHUB_USERNAME=$(gh api "repos/cozystack/$REPO_NAME/commits/$commit_hash" --jq '.author.login // empty' 2>/dev/null || echo "") + fi + + if [ -n "$PR_NUMBER" ]; then + echo " $commit_hash|$subject|$author_name|$GITHUB_USERNAME|cozystack/$REPO_NAME#$PR_NUMBER" + else + echo " $commit_hash|$subject|$author_name|$GITHUB_USERNAME|cozystack/$REPO_NAME@${commit_hash:0:7}" + fi + done + else + echo "No tags found in $repo_name during release period" + + # Check for commits by dates if no exact version tags + # Include merge commits to capture backports + COMMITS=$(git log --since="$RELEASE_START" --until="$RELEASE_END" --format="%H|%s|%an" 2>/dev/null || true) + + if [ -n "$COMMITS" ]; then + echo "" + echo "Commits found by date range:" + echo "$COMMITS" | while IFS='|' read -r commit_hash subject author_name; do + if [ -z "$commit_hash" ]; then + continue + fi + + # Get PR number from commit message + COMMIT_MSG=$(git log -1 --format=%B "$commit_hash" 2>/dev/null || echo "") + PR_NUMBER=$(echo "$COMMIT_MSG" | grep -oE '#[0-9]+' | head -1 | tr -d '#' || echo "") + + # Get author: prioritize PR author, fallback to commit author + GITHUB_USERNAME="" + if [ -n "$PR_NUMBER" ]; then + GITHUB_USERNAME=$(gh pr view "$PR_NUMBER" --repo "cozystack/$REPO_NAME" --json author --jq '.author.login // empty' 2>/dev/null || echo "") + fi + if [ -z "$GITHUB_USERNAME" ]; then + GITHUB_USERNAME=$(gh api "repos/cozystack/$REPO_NAME/commits/$commit_hash" --jq '.author.login // empty' 2>/dev/null || echo "") + fi + + if [ -n "$PR_NUMBER" ]; then + echo " $commit_hash|$subject|$author_name|$GITHUB_USERNAME|cozystack/$REPO_NAME#$PR_NUMBER" + else + echo " $commit_hash|$subject|$author_name|$GITHUB_USERNAME|cozystack/$REPO_NAME@${commit_hash:0:7}" + fi + done + else + echo "No commits found in $repo_name during release period" + fi + fi + + echo "" + cd "$COZYSTACK_ROOT" +done + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "Finished checking all optional repositories" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + diff --git a/hack/check-readiness.sh b/hack/check-readiness.sh new file mode 100755 index 00000000..bd3a3ffc --- /dev/null +++ b/hack/check-readiness.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +# Check readiness of Packages, ArtifactGenerators, ExternalArtifacts, and HelmReleases +# Shows only non-ready resources +# +# Usage: check-readiness.sh [-w [INTERVAL]] +# -w [INTERVAL] Watch mode: refresh continuously every INTERVAL seconds (default: 5) + +set -euo pipefail + +KUBECTL="kubectl" +if [[ -n "${KUBECONFIG:-}" ]]; then + KUBECTL="kubectl --kubeconfig=${KUBECONFIG}" +fi + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BOLD='\033[1m' +RESET='\033[0m' + +WATCH=0 +INTERVAL=5 + +while [[ $# -gt 0 ]]; do + case "$1" in + -w|--watch) + WATCH=1 + if [[ $# -gt 1 && "$2" =~ ^[0-9]+$ ]]; then + INTERVAL="$2" + shift + fi + shift + ;; + *) echo "Unknown argument: $1"; exit 2 ;; + esac +done + +check_resource() { + local kind="$1" + local header_printed=0 + + while IFS= read -r line; do + if [[ "$line" =~ ^(NAME|NAMESPACE) ]]; then + continue + fi + if ! echo "$line" | awk '{for(i=1;i<=NF;i++) if($i=="True") exit 0; exit 1}'; then + if [[ $header_printed -eq 0 ]]; then + echo -e "${BOLD}${YELLOW}=== ${kind} (not ready) ===${RESET}" + header_printed=1 + fi + echo -e "${RED}${line}${RESET}" + found_issues=1 + fi + done < <($KUBECTL get "$kind" -A 2>/dev/null) + + return 0 +} + +run_once() { + found_issues=0 + + check_resource packages.cozystack.io + check_resource artifactgenerators.source.extensions.fluxcd.io + check_resource externalartifacts.source.toolkit.fluxcd.io + check_resource helmreleases.helm.toolkit.fluxcd.io + + if [[ $found_issues -eq 0 ]]; then + echo -e "${GREEN}${BOLD}All resources are ready.${RESET}" + fi +} + +if [[ $WATCH -eq 1 ]]; then + while true; do + output=$(run_once 2>&1) + clear + echo -e "${BOLD}Last updated: $(date) (refreshing every ${INTERVAL}s, Ctrl+C to stop)${RESET}\n" + echo -e "$output" + sleep "$INTERVAL" + done +else + run_once + [[ $found_issues -eq 0 ]] || exit 1 +fi diff --git a/hack/common-envs.mk b/hack/common-envs.mk new file mode 100644 index 00000000..9b8db5db --- /dev/null +++ b/hack/common-envs.mk @@ -0,0 +1,33 @@ +# macOS-compatible sed in-place +ifeq ($(shell uname),Darwin) + SED_INPLACE := sed -i '' +else + SED_INPLACE := sed -i +endif + +REGISTRY ?= ghcr.io/cozystack/cozystack +TAG = $(shell git describe --tags --exact-match --match 'v*' 2>/dev/null || echo latest) +PUSH := 1 +LOAD := 0 +BUILDER ?= +PLATFORM ?= +BUILDX_EXTRA_ARGS ?= +COZYSTACK_VERSION = $(patsubst v%,%,$(shell git describe --tags --match 'v*')) + +BUILDX_ARGS := --provenance=false --push=$(PUSH) --load=$(LOAD) \ + --label org.opencontainers.image.source=https://github.com/cozystack/cozystack \ + $(if $(strip $(BUILDER)),--builder=$(BUILDER)) \ + $(if $(strip $(PLATFORM)),--platform=$(PLATFORM)) \ + $(BUILDX_EXTRA_ARGS) + +# Returns 'latest' if the git tag is not assigned, otherwise returns the provided value +define settag +$(if $(filter $(TAG),latest),latest,$(1)) +endef + +ifeq ($(COZYSTACK_VERSION),) + $(shell git remote add upstream https://github.com/cozystack/cozystack.git || true) + $(shell git fetch upstream --tags) + COZYSTACK_VERSION = $(patsubst v%,%,$(shell git describe --tags --match 'v*')) +endif + diff --git a/hack/cozyreport.sh b/hack/cozyreport.sh index 3d3e22cf..565fd435 100755 --- a/hack/cozyreport.sh +++ b/hack/cozyreport.sh @@ -48,7 +48,7 @@ kubectl get ns --no-headers | awk '$2 != "Active"' | echo "Collecting helmreleases..." kubectl get hr -A > $REPORT_DIR/kubernetes/helmreleases.txt 2>&1 -kubectl get hr -A | awk '$4 != "True"' | \ +kubectl get hr -A --no-headers | awk '$4 != "True"' | \ while read NAMESPACE NAME _; do DIR=$REPORT_DIR/kubernetes/helmreleases/$NAMESPACE/$NAME mkdir -p $DIR @@ -56,13 +56,33 @@ kubectl get hr -A | awk '$4 != "True"' | \ kubectl describe hr -n $NAMESPACE $NAME > $DIR/describe.txt 2>&1 done +echo "Collecting packages..." +kubectl get packages > $REPORT_DIR/kubernetes/packages.txt 2>&1 +kubectl get packages --no-headers | awk '$3 != "True"' | \ + while read NAME _; do + DIR=$REPORT_DIR/kubernetes/packages/$NAME + mkdir -p $DIR + kubectl get package $NAME -o yaml > $DIR/package.yaml 2>&1 + kubectl describe package $NAME > $DIR/describe.txt 2>&1 + done + +echo "Collecting packagesources..." +kubectl get packagesources > $REPORT_DIR/kubernetes/packagesources.txt 2>&1 +kubectl get packagesources --no-headers | awk '$3 != "True"' | \ + while read NAME _; do + DIR=$REPORT_DIR/kubernetes/packagesources/$NAME + mkdir -p $DIR + kubectl get packagesource $NAME -o yaml > $DIR/packagesource.yaml 2>&1 + kubectl describe packagesource $NAME > $DIR/describe.txt 2>&1 + done + echo "Collecting pods..." kubectl get pod -A -o wide > $REPORT_DIR/kubernetes/pods.txt 2>&1 kubectl get pod -A --no-headers | awk '$4 !~ /Running|Succeeded|Completed/' | while read NAMESPACE NAME _ STATE _; do DIR=$REPORT_DIR/kubernetes/pods/$NAMESPACE/$NAME mkdir -p $DIR - CONTAINERS=$(kubectl get pod -o jsonpath='{.spec.containers[*].name}' -n $NAMESPACE $NAME) + CONTAINERS=$(kubectl get pod -o jsonpath='{.spec.containers[*].name} {.spec.initContainers[*].name}' -n $NAMESPACE $NAME) kubectl get pod -n $NAMESPACE $NAME -o yaml > $DIR/pod.yaml 2>&1 kubectl describe pod -n $NAMESPACE $NAME > $DIR/describe.txt 2>&1 if [ "$STATE" != "Pending" ]; then @@ -105,7 +125,7 @@ kubectl get svc -A --no-headers | awk '$4 == ""' | echo "Collecting pvcs..." kubectl get pvc -A > $REPORT_DIR/kubernetes/pvcs.txt 2>&1 -kubectl get pvc -A | awk '$3 != "Bound"' | +kubectl get pvc -A --no-headers | awk '$3 != "Bound"' | while read NAMESPACE NAME _; do DIR=$REPORT_DIR/kubernetes/pvc/$NAMESPACE/$NAME mkdir -p $DIR diff --git a/hack/cozytest.sh b/hack/cozytest.sh index acf0db35..a3955fd1 100755 --- a/hack/cozytest.sh +++ b/hack/cozytest.sh @@ -10,7 +10,11 @@ PATTERN=${2:-*} LINE='----------------------------------------------------------------' cols() { stty size 2>/dev/null | awk '{print $2}' || echo 80; } -MAXW=$(( $(cols) - 12 )); [ "$MAXW" -lt 40 ] && MAXW=70 +if [ -t 1 ]; then + MAXW=$(( $(cols) - 12 )); [ "$MAXW" -lt 40 ] && MAXW=70 +else + MAXW=0 # no truncation when not a tty (e.g. CI) +fi BEGIN=$(date +%s) timestamp() { s=$(( $(date +%s) - BEGIN )); printf '[%02d:%02d]' $((s/60)) $((s%60)); } @@ -24,7 +28,7 @@ run_one() { echo "╭ » Run test: $title" START=$(date +%s) - skip_next="+ $fn" # первую строку трассировки с именем функции пропустим + skip_next="+ $fn" { ( @@ -45,7 +49,7 @@ run_one() { *) out=$line ;; esac now=$(( $(date +%s) - START )) - [ ${#out} -gt "$MAXW" ] && out="$(printf '%.*s…' "$MAXW" "$out")" + [ "$MAXW" -gt 0 ] && [ ${#out} -gt "$MAXW" ] && out="$(printf '%.*s…' "$MAXW" "$out")" printf '┊[%02d:%02d] %s\n' $((now/60)) $((now%60)) "$out" done @@ -61,6 +65,7 @@ run_one() { echo "----- captured output -----------------------------------------" grep -v '^__RC__' "$log" echo "$LINE" + rm -rf "$tmp" exit "$rc" fi @@ -83,11 +88,11 @@ awk ' } printf("### %s\n", title) printf("%s() {\n", fname) - print " set -e" # ошибка → падение теста + print " set -e" next } /^}$/ { - print " return 0" # если автор не сделал exit 1 — тест ОК + print " return 0" print "}" next } diff --git a/hack/dcgm-default-counters.csv b/hack/dcgm-default-counters.csv new file mode 100644 index 00000000..b5e94540 --- /dev/null +++ b/hack/dcgm-default-counters.csv @@ -0,0 +1,104 @@ +# Snapshot of the upstream DCGM Exporter default-counters.csv used as a +# fixture by hack/check-gpu-recording-rules.bats. The test verifies that +# every DCGM_FI_* metric referenced by a tracked GPU dashboard is either +# declared here (upstream defaults) or in +# packages/system/gpu-operator/examples/dcgm-custom-metrics.yaml +# (the project's custom CSV). +# +# Source: https://github.com/NVIDIA/dcgm-exporter/blob/4.1.1-4.0.4/etc/default-counters.csv +# Pinned to the DCGM Exporter image tag shipped by the gpu-operator +# chart under packages/system/gpu-operator/charts/gpu-operator/values.yaml +# (dcgmExporter.version = 4.1.1-4.0.4-ubuntu22.04). When that image is +# bumped, refresh this file from the matching tag in the NVIDIA/dcgm-exporter +# repo and re-run `./hack/cozytest.sh hack/check-gpu-recording-rules.bats`. + +# Format +# If line starts with a '#' it is considered a comment +# DCGM FIELD, Prometheus metric type, help message + +# Clocks +DCGM_FI_DEV_SM_CLOCK, gauge, SM clock frequency (in MHz). +DCGM_FI_DEV_MEM_CLOCK, gauge, Memory clock frequency (in MHz). + +# Temperature +DCGM_FI_DEV_MEMORY_TEMP, gauge, Memory temperature (in C). +DCGM_FI_DEV_GPU_TEMP, gauge, GPU temperature (in C). + +# Power +DCGM_FI_DEV_POWER_USAGE, gauge, Power draw (in W). +DCGM_FI_DEV_TOTAL_ENERGY_CONSUMPTION, counter, Total energy consumption since boot (in mJ). + +# PCIE +# DCGM_FI_PROF_PCIE_TX_BYTES, counter, Total number of bytes transmitted through PCIe TX via NVML. +# DCGM_FI_PROF_PCIE_RX_BYTES, counter, Total number of bytes received through PCIe RX via NVML. +DCGM_FI_DEV_PCIE_REPLAY_COUNTER, counter, Total number of PCIe retries. + +# Utilization (the sample period varies depending on the product) +DCGM_FI_DEV_GPU_UTIL, gauge, GPU utilization (in %). +DCGM_FI_DEV_MEM_COPY_UTIL, gauge, Memory utilization (in %). +DCGM_FI_DEV_ENC_UTIL, gauge, Encoder utilization (in %). +DCGM_FI_DEV_DEC_UTIL , gauge, Decoder utilization (in %). + +# Errors and violations +DCGM_FI_DEV_XID_ERRORS, gauge, Value of the last XID error encountered. +# DCGM_FI_DEV_POWER_VIOLATION, counter, Throttling duration due to power constraints (in us). +# DCGM_FI_DEV_THERMAL_VIOLATION, counter, Throttling duration due to thermal constraints (in us). +# DCGM_FI_DEV_SYNC_BOOST_VIOLATION, counter, Throttling duration due to sync-boost constraints (in us). +# DCGM_FI_DEV_BOARD_LIMIT_VIOLATION, counter, Throttling duration due to board limit constraints (in us). +# DCGM_FI_DEV_LOW_UTIL_VIOLATION, counter, Throttling duration due to low utilization (in us). +# DCGM_FI_DEV_RELIABILITY_VIOLATION, counter, Throttling duration due to reliability constraints (in us). + +# Memory usage +DCGM_FI_DEV_FB_FREE, gauge, Framebuffer memory free (in MiB). +DCGM_FI_DEV_FB_USED, gauge, Framebuffer memory used (in MiB). + +# ECC +# DCGM_FI_DEV_ECC_SBE_VOL_TOTAL, counter, Total number of single-bit volatile ECC errors. +# DCGM_FI_DEV_ECC_DBE_VOL_TOTAL, counter, Total number of double-bit volatile ECC errors. +# DCGM_FI_DEV_ECC_SBE_AGG_TOTAL, counter, Total number of single-bit persistent ECC errors. +# DCGM_FI_DEV_ECC_DBE_AGG_TOTAL, counter, Total number of double-bit persistent ECC errors. + +# Retired pages +# DCGM_FI_DEV_RETIRED_SBE, counter, Total number of retired pages due to single-bit errors. +# DCGM_FI_DEV_RETIRED_DBE, counter, Total number of retired pages due to double-bit errors. +# DCGM_FI_DEV_RETIRED_PENDING, counter, Total number of pages pending retirement. + +# NVLink +# DCGM_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_TOTAL, counter, Total number of NVLink flow-control CRC errors. +# DCGM_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_TOTAL, counter, Total number of NVLink data CRC errors. +# DCGM_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_TOTAL, counter, Total number of NVLink retries. +# DCGM_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_TOTAL, counter, Total number of NVLink recovery errors. +DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL, counter, Total number of NVLink bandwidth counters for all lanes. +# DCGM_FI_DEV_NVLINK_BANDWIDTH_L0, counter, The number of bytes of active NVLink rx or tx data including both header and payload. + +# VGPU License status +DCGM_FI_DEV_VGPU_LICENSE_STATUS, gauge, vGPU License status + +# Remapped rows +DCGM_FI_DEV_UNCORRECTABLE_REMAPPED_ROWS, counter, Number of remapped rows for uncorrectable errors +DCGM_FI_DEV_CORRECTABLE_REMAPPED_ROWS, counter, Number of remapped rows for correctable errors +DCGM_FI_DEV_ROW_REMAP_FAILURE, gauge, Whether remapping of rows has failed + +# Static configuration information. These appear as labels on the other metrics +DCGM_FI_DRIVER_VERSION, label, Driver Version +# DCGM_FI_NVML_VERSION, label, NVML Version +# DCGM_FI_DEV_BRAND, label, Device Brand +# DCGM_FI_DEV_SERIAL, label, Device Serial Number +# DCGM_FI_DEV_OEM_INFOROM_VER, label, OEM inforom version +# DCGM_FI_DEV_ECC_INFOROM_VER, label, ECC inforom version +# DCGM_FI_DEV_POWER_INFOROM_VER, label, Power management object inforom version +# DCGM_FI_DEV_INFOROM_IMAGE_VER, label, Inforom image version +# DCGM_FI_DEV_VBIOS_VERSION, label, VBIOS version of the device + +# Datacenter Profiling (DCP) metrics +# NOTE: supported on Nvidia datacenter Volta GPUs and newer +DCGM_FI_PROF_GR_ENGINE_ACTIVE, gauge, Ratio of time the graphics engine is active. +# DCGM_FI_PROF_SM_ACTIVE, gauge, The ratio of cycles an SM has at least 1 warp assigned. +# DCGM_FI_PROF_SM_OCCUPANCY, gauge, The ratio of number of warps resident on an SM. +DCGM_FI_PROF_PIPE_TENSOR_ACTIVE, gauge, Ratio of cycles the tensor (HMMA) pipe is active. +DCGM_FI_PROF_DRAM_ACTIVE, gauge, Ratio of cycles the device memory interface is active sending or receiving data. +# DCGM_FI_PROF_PIPE_FP64_ACTIVE, gauge, Ratio of cycles the fp64 pipes are active. +# DCGM_FI_PROF_PIPE_FP32_ACTIVE, gauge, Ratio of cycles the fp32 pipes are active. +# DCGM_FI_PROF_PIPE_FP16_ACTIVE, gauge, Ratio of cycles the fp16 pipes are active. +DCGM_FI_PROF_PCIE_TX_BYTES, gauge, The rate of data transmitted over the PCIe bus - including both protocol headers and data payloads - in bytes per second. +DCGM_FI_PROF_PCIE_RX_BYTES, gauge, The rate of data received over the PCIe bus - including both protocol headers and data payloads - in bytes per second. diff --git a/hack/download-dashboards.sh b/hack/download-dashboards.sh index ade7ca0b..d761f71c 100755 --- a/hack/download-dashboards.sh +++ b/hack/download-dashboards.sh @@ -81,7 +81,10 @@ modules/340-monitoring-kubernetes/monitoring/grafana-dashboards//main/capacity-p modules/340-monitoring-kubernetes/monitoring/grafana-dashboards//flux/flux-control-plane.json modules/340-monitoring-kubernetes/monitoring/grafana-dashboards//flux/flux-stats.json modules/340-monitoring-kubernetes/monitoring/grafana-dashboards//kafka/strimzi-kafka.json +modules/340-monitoring-kubernetes/monitoring/grafana-dashboards//seaweedfs/seaweedfs.json modules/340-monitoring-kubernetes/monitoring/grafana-dashboards//goldpinger/goldpinger.json +modules/340-monitoring-kubernetes/monitoring/grafana-dashboards//nats/nats-jetstream.json +modules/340-monitoring-kubernetes/monitoring/grafana-dashboards//nats/nats-server.json EOT diff --git a/hack/e2e-apps/backup.bats.disabled b/hack/e2e-apps/backup.bats.disabled new file mode 100755 index 00000000..0a5c13d9 --- /dev/null +++ b/hack/e2e-apps/backup.bats.disabled @@ -0,0 +1,226 @@ +#!/usr/bin/env bats + +# Test variables - stored for teardown +TEST_NAMESPACE='tenant-test' +TEST_BUCKET_NAME='test-backup-bucket' +TEST_VM_NAME='test-backup-vm' +TEST_BACKUPJOB_NAME='test-backup-job' + +teardown() { + # Clean up resources (runs even if test fails) + namespace="${TEST_NAMESPACE}" + bucket_name="${TEST_BUCKET_NAME}" + vm_name="${TEST_VM_NAME}" + backupjob_name="${TEST_BACKUPJOB_NAME}" + + # Clean up port-forward if still running + pkill -f "kubectl.*port-forward.*seaweedfs-s3" 2>/dev/null || true + + # Clean up Velero resources in cozy-velero namespace + # Find Velero backup by pattern matching namespace-backupjob + for backup in $(kubectl -n cozy-velero get backups.velero.io -o jsonpath='{.items[*].metadata.name}' 2>/dev/null || true); do + if echo "$backup" | grep -q "^${namespace}-${backupjob_name}-"; then + kubectl -n cozy-velero delete backups.velero.io ${backup} --wait=false 2>/dev/null || true + fi + done + + # Clean up BackupStorageLocation and VolumeSnapshotLocation (named: namespace-backupjob) + BSL_NAME="${namespace}-${backupjob_name}" + kubectl -n cozy-velero delete backupstoragelocations.velero.io ${BSL_NAME} --wait=false 2>/dev/null || true + kubectl -n cozy-velero delete volumesnapshotlocations.velero.io ${BSL_NAME} --wait=false 2>/dev/null || true + + # Clean up Velero credentials secret + SECRET_NAME="backup-${namespace}-${backupjob_name}-s3-credentials" + kubectl -n cozy-velero delete secret ${SECRET_NAME} --wait=false 2>/dev/null || true + + # Clean up BackupJob + kubectl -n ${namespace} delete backupjob ${backupjob_name} --wait=false 2>/dev/null || true + + # Clean up Virtual Machine + kubectl -n ${namespace} delete virtualmachines.apps.cozystack.io ${vm_name} --wait=false 2>/dev/null || true + + # Clean up Bucket + kubectl -n ${namespace} delete bucket.apps.cozystack.io ${bucket_name} --wait=false 2>/dev/null || true + + # Clean up temporary files + rm -f /tmp/bucket-backup-credentials.json +} + +print_log() { + echo "# $1" >&3 +} + +@test "Create Backup for Virtual Machine" { + # Test variables + bucket_name="${TEST_BUCKET_NAME}" + vm_name="${TEST_VM_NAME}" + backupjob_name="${TEST_BACKUPJOB_NAME}" + namespace="${TEST_NAMESPACE}" + + print_log "Step 0:Ensure BackupJob and Velero strategy CRDs are installed" + kubectl apply -f packages/system/backup-controller/definitions/backups.cozystack.io_backupjobs.yaml + kubectl apply -f packages/system/backupstrategy-controller/definitions/strategy.backups.cozystack.io_veleroes.yaml + # Wait for CRDs to be ready + kubectl wait --for condition=established --timeout=30s crd backupjobs.backups.cozystack.io + kubectl wait --for condition=established --timeout=30s crd veleroes.strategy.backups.cozystack.io + + # Ensure velero-strategy-default resource exists + kubectl apply -f packages/system/backup-controller/templates/strategy.yaml + + print_log "Step 1: Create the bucket resource" + kubectl apply -f - < /tmp/bucket-backup-credentials.json + ACCESS_KEY=$(jq -r '.spec.secretS3.accessKeyID' /tmp/bucket-backup-credentials.json) + SECRET_KEY=$(jq -r '.spec.secretS3.accessSecretKey' /tmp/bucket-backup-credentials.json) + BUCKET_NAME=$(jq -r '.spec.bucketName' /tmp/bucket-backup-credentials.json) + + print_log "Step 2: Create the Virtual Machine" + kubectl apply -f - </dev/null); do + if echo "$backup" | grep -q "^${namespace}-${backupjob_name}-"; then + VELERO_BACKUP_NAME=$backup + VELERO_BACKUP_PHASE=$(kubectl -n cozy-velero get backups.velero.io $backup -o jsonpath='{.status.phase}' 2>/dev/null || echo "") + break + fi + done + + print_log "Verify Velero Backup was found" + [ -n "$VELERO_BACKUP_NAME" ] + + echo '# Wait for Velero Backup to complete' >&3 + until kubectl -n cozy-velero get backups.velero.io ${VELERO_BACKUP_NAME} -o jsonpath='{.status.phase}' | grep -q 'Completed\|Failed'; do + sleep 5 + done + + print_log "Verify Velero Backup is Completed" + timeout 90 sh -ec "until [ \"\$(kubectl -n cozy-velero get backups.velero.io ${VELERO_BACKUP_NAME} -o jsonpath='{.status.phase}' 2>/dev/null)\" = \"Completed\" ]; do sleep 30; done" + + # Final verification + VELERO_BACKUP_PHASE=$(kubectl -n cozy-velero get backups.velero.io ${VELERO_BACKUP_NAME} -o jsonpath='{.status.phase}' 2>/dev/null || echo "") + [ "$VELERO_BACKUP_PHASE" = "Completed" ] + + print_log "Step 4: Verify S3 has backup data" + # Start port-forwarding to S3 service (with timeout to keep it alive) + bash -c 'timeout 100s kubectl port-forward service/seaweedfs-s3 -n tenant-root 8333:8333 > /dev/null 2>&1 &' + + # Wait for port-forward to be ready + timeout 30 sh -ec "until nc -z localhost 8333; do sleep 1; done" + + # Wait a bit for backup data to be written to S3 + sleep 30 + + # Set up MinIO client with insecure flag (use environment variable for all commands) + export MC_INSECURE=1 + mc alias set local https://localhost:8333 $ACCESS_KEY $SECRET_KEY + + # Verify backup directory exists in S3 + BACKUP_PATH="${BUCKET_NAME}/backups/${VELERO_BACKUP_NAME}" + mc ls local/${BACKUP_PATH}/ 2>/dev/null + [ $? -eq 0 ] + + # Verify backup files exist (at least metadata files) + BACKUP_FILES=$(mc ls local/${BACKUP_PATH}/ 2>/dev/null | wc -l || echo "0") + [ "$BACKUP_FILES" -gt "0" ] +} + diff --git a/hack/e2e-apps/bucket.bats b/hack/e2e-apps/bucket.bats new file mode 100644 index 00000000..31e7efb0 --- /dev/null +++ b/hack/e2e-apps/bucket.bats @@ -0,0 +1,73 @@ +#!/usr/bin/env bats + +@test "Create and Verify Seeweedfs Bucket" { + # Create the bucket resource with readwrite and readonly users + name='test' + kubectl -n tenant-test delete bucket.apps.cozystack.io $name --ignore-not-found --timeout=2m || true + pkill -f "port-forward.*8333:" 2>/dev/null || true + kubectl apply -f - < bucket-admin-credentials.json + ADMIN_ACCESS_KEY=$(jq -r '.spec.secretS3.accessKeyID' bucket-admin-credentials.json) + ADMIN_SECRET_KEY=$(jq -r '.spec.secretS3.accessSecretKey' bucket-admin-credentials.json) + BUCKET_NAME=$(jq -r '.spec.bucketName' bucket-admin-credentials.json) + + # Get viewer (readonly) credentials + kubectl -n tenant-test get secret bucket-${name}-viewer -ojsonpath='{.data.BucketInfo}' | base64 -d > bucket-viewer-credentials.json + VIEWER_ACCESS_KEY=$(jq -r '.spec.secretS3.accessKeyID' bucket-viewer-credentials.json) + VIEWER_SECRET_KEY=$(jq -r '.spec.secretS3.accessSecretKey' bucket-viewer-credentials.json) + + # Start port-forwarding + bash -c 'timeout 100s kubectl port-forward service/seaweedfs-s3 -n tenant-root 8333:8333 > /dev/null 2>&1 &' + + # Wait for port-forward to be ready + timeout 30 sh -ec 'until nc -z localhost 8333; do sleep 1; done' + + # --- Test readwrite user (admin) --- + mc alias set rw-user https://localhost:8333 $ADMIN_ACCESS_KEY $ADMIN_SECRET_KEY --insecure + + # Admin can upload + echo "readwrite test" > /tmp/rw-test.txt + mc cp --insecure /tmp/rw-test.txt rw-user/$BUCKET_NAME/rw-test.txt + + # Admin can list + mc ls --insecure rw-user/$BUCKET_NAME/rw-test.txt + + # Admin can download + mc cp --insecure rw-user/$BUCKET_NAME/rw-test.txt /tmp/rw-test-download.txt + + # --- Test readonly user (viewer) --- + mc alias set ro-user https://localhost:8333 $VIEWER_ACCESS_KEY $VIEWER_SECRET_KEY --insecure + + # Viewer can list + mc ls --insecure ro-user/$BUCKET_NAME/rw-test.txt + + # Viewer can download + mc cp --insecure ro-user/$BUCKET_NAME/rw-test.txt /tmp/ro-test-download.txt + + # Viewer cannot upload (must fail with Access Denied) + echo "readonly test" > /tmp/ro-test.txt + ! mc cp --insecure /tmp/ro-test.txt ro-user/$BUCKET_NAME/ro-test.txt + + # --- Cleanup --- + mc rm --insecure rw-user/$BUCKET_NAME/rw-test.txt + kubectl -n tenant-test delete bucket.apps.cozystack.io ${name} +} diff --git a/hack/e2e-apps/clickhouse.bats b/hack/e2e-apps/clickhouse.bats index 95d86d02..fbc9f906 100644 --- a/hack/e2e-apps/clickhouse.bats +++ b/hack/e2e-apps/clickhouse.bats @@ -2,6 +2,7 @@ @test "Create DB ClickHouse" { name='test' + kubectl -n tenant-test delete clickhouse.apps.cozystack.io $name --ignore-not-found --timeout=2m || true kubectl apply -f- </dev/null || true +} + +@test "Create and Verify ExternalDNS with inmemory provider" { + name='test' + kubectl apply -f - </dev/null; do sleep 10; done" +} \ No newline at end of file diff --git a/hack/e2e-apps/harbor.bats b/hack/e2e-apps/harbor.bats new file mode 100644 index 00000000..26f407ea --- /dev/null +++ b/hack/e2e-apps/harbor.bats @@ -0,0 +1,74 @@ +#!/usr/bin/env bats + +@test "Create Harbor" { + name='test' + release="harbor-$name" + + # Clean up stale resources from previous failed runs + kubectl -n tenant-test delete harbor.apps.cozystack.io $name 2>/dev/null || true + kubectl -n tenant-test wait hr $release --timeout=60s --for=delete 2>/dev/null || true + + kubectl apply -f- <&1 || true + echo "=== Pods ===" + kubectl -n tenant-test get pods 2>&1 || true + echo "=== Events ===" + kubectl -n tenant-test get events --sort-by='.lastTimestamp' 2>&1 | tail -30 || true + echo "=== ExternalArtifact ===" + kubectl -n cozy-system get externalartifact cozystack-harbor-application-default-harbor-system -o yaml 2>&1 || true + echo "=== BucketClaim status ===" + kubectl -n tenant-test get bucketclaims.objectstorage.k8s.io $release-registry -o yaml 2>&1 || true + echo "=== BucketAccess status ===" + kubectl -n tenant-test get bucketaccesses.objectstorage.k8s.io $release-registry -o yaml 2>&1 || true + echo "=== BucketAccess Secret ===" + kubectl -n tenant-test get secret $release-registry-bucket -o jsonpath='{.data.BucketInfo}' 2>&1 | base64 -d 2>&1 || true + false + } + kubectl -n tenant-test wait deploy $release-core --timeout=120s --for=condition=available + kubectl -n tenant-test wait deploy $release-registry --timeout=120s --for=condition=available + kubectl -n tenant-test wait deploy $release-portal --timeout=120s --for=condition=available + kubectl -n tenant-test get secret $release-credentials -o jsonpath='{.data.admin-password}' | base64 --decode | grep -q '.' + kubectl -n tenant-test get secret $release-credentials -o jsonpath='{.data.url}' | base64 --decode | grep -q 'https://' + kubectl -n tenant-test get svc $release -o jsonpath='{.spec.ports[0].port}' | grep -q '80' + kubectl -n tenant-test delete harbor.apps.cozystack.io $name +} diff --git a/hack/e2e-apps/kafka.bats b/hack/e2e-apps/kafka.bats index ceaf2cde..d85837bd 100644 --- a/hack/e2e-apps/kafka.bats +++ b/hack/e2e-apps/kafka.bats @@ -2,6 +2,8 @@ @test "Create Kafka" { name='test' + kubectl -n tenant-test delete kafka.apps.cozystack.io $name --ignore-not-found --timeout=2m || true + kubectl -n tenant-test wait kafka.apps.cozystack.io $name --for=delete --timeout=2m 2>/dev/null || true kubectl apply -f- </dev/null | grep -q true; do sleep 5; done"; then + echo "=== DEBUG: Container did not start in time ===" >&2 + kubectl -n tenant-test describe pod openbao-$name-0 >&2 || true + kubectl -n tenant-test logs openbao-$name-0 --previous >&2 || true + kubectl -n tenant-test logs openbao-$name-0 >&2 || true + return 1 + fi + + # Wait for OpenBAO API to accept connections + # bao status exit codes: 0 = unsealed, 1 = error/not ready, 2 = sealed but responsive + if ! timeout 60 sh -ec "until kubectl -n tenant-test exec openbao-$name-0 -- bao status >/dev/null 2>&1; rc=\$?; test \$rc -eq 0 -o \$rc -eq 2; do sleep 3; done"; then + echo "=== DEBUG: OpenBAO API did not become responsive ===" >&2 + kubectl -n tenant-test describe pod openbao-$name-0 >&2 || true + kubectl -n tenant-test logs openbao-$name-0 --previous >&2 || true + kubectl -n tenant-test logs openbao-$name-0 >&2 || true + return 1 + fi + + # Initialize OpenBAO (single key share for testing simplicity) + init_output=$(kubectl -n tenant-test exec openbao-$name-0 -- bao operator init -key-shares=1 -key-threshold=1 -format=json) + unseal_key=$(echo "$init_output" | jq -r '.unseal_keys_b64[0]') + if [ -z "$unseal_key" ] || [ "$unseal_key" = "null" ]; then + echo "Failed to extract unseal key. Init output: $init_output" >&2 + return 1 + fi + + # Unseal OpenBAO + kubectl -n tenant-test exec openbao-$name-0 -- bao operator unseal "$unseal_key" + + # Now wait for pod to become ready (readiness probe checks seal status) + kubectl -n tenant-test wait sts openbao-$name --timeout=90s --for=jsonpath='{.status.readyReplicas}'=1 + kubectl -n tenant-test wait pvc data-openbao-$name-0 --timeout=50s --for=jsonpath='{.status.phase}'=Bound + kubectl -n tenant-test delete openbao.apps.cozystack.io $name + kubectl -n tenant-test delete pvc data-openbao-$name-0 --ignore-not-found +} diff --git a/hack/e2e-apps/postgres.bats b/hack/e2e-apps/postgres.bats index 024ce086..b86bc664 100644 --- a/hack/e2e-apps/postgres.bats +++ b/hack/e2e-apps/postgres.bats @@ -2,6 +2,7 @@ @test "Create DB PostgreSQL" { name='test' + kubectl -n tenant-test delete postgreses.apps.cozystack.io $name --ignore-not-found --timeout=2m || true kubectl apply -f - </dev/null || true + kubectl -n tenant-test wait kuberneteses.apps.cozystack.io "${test_name}" --for=delete --timeout=2m 2>/dev/null || true + + kubectl apply -f - < "tenantkubeconfig-${test_name}" + + # Update the kubeconfig to use localhost for the API server + yq -i ".clusters[0].cluster.server = \"https://localhost:${port}\"" "tenantkubeconfig-${test_name}" + + + # Kill any stale port-forward on this port from a previous retry + pkill -f "port-forward.*${port}:" 2>/dev/null || true + sleep 1 + + # Set up port forwarding to the Kubernetes API server + # No timeout — process is killed at end of test or by job-level timeout-minutes + kubectl port-forward service/kubernetes-"${test_name}" -n tenant-test "${port}":6443 > /dev/null 2>&1 & + # Wait for port-forward to be ready before using it + timeout 15 sh -ec 'until curl -sk https://localhost:'"${port}"' >/dev/null 2>&1; do sleep 1; done' + # Verify the Kubernetes version matches what we expect (retry for up to 20 seconds) + timeout 20 sh -ec 'until kubectl --kubeconfig tenantkubeconfig-'"${test_name}"' version 2>/dev/null | grep -Fq "Server Version: ${k8s_version}"; do sleep 1; done' + + # Wait for at least 2 nodes to join (timeout after 8 minutes) + timeout 8m bash -c ' + until [ "$(kubectl --kubeconfig tenantkubeconfig-'"${test_name}"' get nodes -o jsonpath="{.items[*].metadata.name}" | wc -w)" -ge 2 ]; do + sleep 2 + done + ' + # Verify the nodes are ready + if ! kubectl --kubeconfig "tenantkubeconfig-${test_name}" wait node --all --timeout=3m --for=condition=Ready; then + # Dump debug info and fail fast — no point running LB/NFS tests without Ready nodes + kubectl --kubeconfig "tenantkubeconfig-${test_name}" describe nodes + kubectl -n tenant-test get hr + exit 1 + fi + kubectl --kubeconfig "tenantkubeconfig-${test_name}" get nodes -o wide + + # Verify the kubelet version matches what we expect + versions=$(kubectl --kubeconfig "tenantkubeconfig-${test_name}" \ + get nodes -o jsonpath='{.items[*].status.nodeInfo.kubeletVersion}') + + node_ok=true + + for v in $versions; do + case "$v" in + "${k8s_version}" | "${k8s_version}".* | "${k8s_version}"-*) + # acceptable + ;; + *) + node_ok=false + break + ;; + esac + done + + if [ "$node_ok" != true ]; then + echo "Kubelet versions did not match expected ${k8s_version}" >&2 + exit 1 + fi + + + kubectl --kubeconfig "tenantkubeconfig-${test_name}" apply -f - <&2 + exit 1 + fi + + lb_ok=false + for i in $(seq 1 20); do + echo "Attempt $i" + if curl --silent --fail "http://${LB_ADDR}"; then + lb_ok=true + break + fi + sleep 3 + done + + if [ "$lb_ok" != true ]; then + echo "LoadBalancer not reachable" >&2 + exit 1 + fi + + # Cleanup + kubectl delete deployment --kubeconfig "tenantkubeconfig-${test_name}" "${test_name}-backend" -n tenant-test + kubectl delete service --kubeconfig "tenantkubeconfig-${test_name}" "${test_name}-backend" -n tenant-test + + # Clean up NFS test resources from any previous failed attempt + kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pod nfs-test-pod \ + -n tenant-test --ignore-not-found --timeout=60s || true + kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pvc nfs-test-pvc \ + -n tenant-test --ignore-not-found --timeout=60s || true + + # Test RWX NFS mount in tenant cluster (uses kubevirt CSI driver with RWX support) + kubectl --kubeconfig "tenantkubeconfig-${test_name}" apply -f - < /data/test.txt && cat /data/test.txt"] + volumeMounts: + - name: nfs-vol + mountPath: /data + volumes: + - name: nfs-vol + persistentVolumeClaim: + claimName: nfs-test-pvc + restartPolicy: Never +EOF + + # Wait for Pod to complete successfully + if ! kubectl --kubeconfig "tenantkubeconfig-${test_name}" wait pod nfs-test-pod -n tenant-test --timeout=5m --for=jsonpath='{.status.phase}'=Succeeded; then + echo "=== NFS test pod did not complete ===" >&2 + kubectl --kubeconfig "tenantkubeconfig-${test_name}" describe pod nfs-test-pod -n tenant-test >&2 || true + kubectl --kubeconfig "tenantkubeconfig-${test_name}" get events -n tenant-test --sort-by='.lastTimestamp' >&2 || true + exit 1 + fi + + # Verify NFS data integrity + nfs_result=$(kubectl --kubeconfig "tenantkubeconfig-${test_name}" logs nfs-test-pod -n tenant-test) + if [ "$nfs_result" != "nfs-mount-ok" ]; then + echo "NFS mount test failed: expected 'nfs-mount-ok', got '$nfs_result'" >&2 + kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pod nfs-test-pod -n tenant-test --wait=false 2>/dev/null || true + kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pvc nfs-test-pvc -n tenant-test --wait=false 2>/dev/null || true + exit 1 + fi + + # Cleanup NFS test resources in tenant cluster + kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pod nfs-test-pod -n tenant-test --wait + kubectl --kubeconfig "tenantkubeconfig-${test_name}" delete pvc nfs-test-pvc -n tenant-test + + # Wait for all machine deployment replicas to be ready (timeout after 10 minutes) + kubectl wait machinedeployment kubernetes-${test_name}-md0 -n tenant-test --timeout=10m --for=jsonpath='{.status.v1beta2.readyReplicas}'=2 + + for component in cilium coredns csi vsnap-crd; do + kubectl wait hr kubernetes-${test_name}-${component} -n tenant-test --timeout=1m --for=condition=ready + done + kubectl wait hr kubernetes-${test_name}-ingress-nginx -n tenant-test --timeout=5m --for=condition=ready + + # Guard: parent HelmRelease must not have entered an install/upgrade remediation cycle. + # A non-zero installFailures/upgradeFailures indicates the helm-wait budget expired while + # admin-kubeconfig was still being provisioned, which would trigger uninstall remediation + # and churn the Cluster CR. + # Flux helm-controller v2 retains per-revision release Snapshots in + # .status.history; each Snapshot's .status reflects the Helm release + # state (deployed/superseded/failed/uninstalled). A remediation cycle + # leaves a "failed" or "uninstalled" entry behind that survives a later + # successful reinstall, unlike the installFailures/upgradeFailures + # counters (which ClearFailures zeroes on every successful reconcile). + # The shape is pinned by hack/remediation-guard.bats; the upstream + # types are github.com/fluxcd/helm-controller/api v2 Snapshot. + history_statuses=$(kubectl get hr -n tenant-test "kubernetes-${test_name}" \ + -ojsonpath='{range .status.history[*]}{.status}{"\n"}{end}') + # Always emit the raw value so a silent future-Flux field rename shows + # up as "empty history on a Ready HR" in CI logs rather than vanishing. + echo "Parent HelmRelease history statuses:" + printf '%s\n' "${history_statuses:-}" + if [ -z "${history_statuses}" ]; then + echo "Unexpected empty .status.history on a Ready HelmRelease - Flux API shape may have changed." >&2 + kubectl -n tenant-test describe hr "kubernetes-${test_name}" >&2 + exit 1 + fi + if helmrelease_has_remediation_cycle "${history_statuses}"; then + echo "Parent HelmRelease entered remediation cycle." >&2 + kubectl -n tenant-test describe hr "kubernetes-${test_name}" >&2 + exit 1 + fi + + # Clean up + pkill -f "port-forward.*${port}:" 2>/dev/null || true + rm -f "tenantkubeconfig-${test_name}" + kubectl -n tenant-test delete kuberneteses.apps.cozystack.io "${test_name}" --ignore-not-found --wait=false 2>/dev/null || true + +} diff --git a/hack/e2e-apps/virtualmachine.bats b/hack/e2e-apps/virtualmachine.bats deleted file mode 100644 index a0bbe8f4..00000000 --- a/hack/e2e-apps/virtualmachine.bats +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bats - -@test "Create a Virtual Machine" { - name='test' - kubectl apply -f - <&2 +@test "Required installer chart exists" { + if [ ! -f packages/core/installer/Chart.yaml ]; then + echo "Missing: packages/core/installer/Chart.yaml" >&2 exit 1 fi } @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 - + # Install cozy-installer chart (operator installs CRDs on startup via --install-crds) + helm upgrade installer packages/core/installer \ + --install \ + --namespace cozy-system \ + --create-namespace \ + --wait \ + --timeout 2m - # Apply installer manifests from file - kubectl apply -f _out/assets/cozystack-installer.yaml + # Verify the operator deployment is available + kubectl wait deployment/cozystack-operator -n cozy-system --timeout=1m --for=condition=Available - # Wait for the installer deployment to become available - kubectl wait deployment/cozystack -n cozy-system --timeout=1m --for=condition=Available + # Wait for operator to install CRDs (happens at startup before reconcile loop). + # kubectl wait fails immediately if the CRD does not exist yet, so poll until it appears first. + timeout 120 sh -ec 'until kubectl wait crd/packages.cozystack.io --for=condition=Established --timeout=10s 2>/dev/null; do sleep 2; done' + timeout 120 sh -ec 'until kubectl wait crd/packagesources.cozystack.io --for=condition=Established --timeout=10s 2>/dev/null; do sleep 2; done' + + # Wait for operator to create the platform PackageSource + timeout 120 sh -ec 'until kubectl get packagesource cozystack.cozystack-platform >/dev/null 2>&1; do sleep 2; done' + + # Create platform Package with isp-full variant + kubectl apply -f - </dev/null | wc -l) -gt 10 ]; do sleep 1; done' sleep 5 - kubectl get hr -A -l cozystack.io/system-app=true | awk 'NR>1 {print "kubectl wait --timeout=15m --for=condition=ready -n "$1" hr/"$2" &"} END {print "wait"}' | sh -ex + 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 @@ -40,8 +65,8 @@ @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 + timeout 120 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=2m --for=condition=available } @test "Wait for LINSTOR and configure storage" { @@ -118,23 +143,31 @@ EOF } @test "Check Cozystack API service" { - kubectl wait --for=condition=Available apiservices/v1alpha1.apps.cozystack.io --timeout=2m + kubectl wait --for=condition=Available apiservices/v1alpha1.apps.cozystack.io apiservices/v1alpha1.core.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 + kubectl patch tenants/root -n tenant-root --type merge -p '{"spec":{"host":"example.org","ingress":true,"monitoring":true,"etcd":true,"isolated":true, "seaweedfs": true}}' + timeout 60 sh -ec 'until kubectl get hr -n tenant-root etcd ingress monitoring seaweedfs tenant-root >/dev/null 2>&1; do sleep 1; done' + kubectl wait hr/etcd hr/ingress hr/tenant-root hr/seaweedfs -n tenant-root --timeout=4m --for=condition=ready + + # TODO: Workaround ingress unvailability issue 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 + if ! kubectl wait hr/seaweedfs-system -n tenant-root --timeout=2m --for=condition=ready; then + flux reconcile hr seaweedfs-system -n tenant-root --force + kubectl wait hr/seaweedfs-system -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"}}' + kubectl patch package cozystack.cozystack-platform --type merge -p '{"spec":{"components":{"platform":{"values":{"publishing":{"exposedServices":["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' @@ -144,9 +177,9 @@ EOF 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 + kubectl wait vmalert/vmalert-shortterm vmalertmanager/alertmanager -n tenant-root --for=jsonpath='{.status.updateStatus}'=operational --timeout=15m + kubectl wait vlclusters/generic -n tenant-root --for=jsonpath='{.status.updateStatus}'=operational --timeout=5m + kubectl wait vmcluster/shortterm vmcluster/longterm -n tenant-root --for=jsonpath='{.status.updateStatus}'=operational --timeout=5m # Grafana kubectl wait clusters.postgresql.cnpg.io/grafana-db -n tenant-root --for=condition=ready --timeout=5m @@ -161,14 +194,66 @@ EOF } @test "Keycloak OIDC stack is healthy" { - kubectl patch configmap/cozystack -n cozy-system --type merge -p '{"data":{"oidc-enabled":"true"}}' + kubectl patch package cozystack.cozystack-platform --type merge -p '{"spec":{"components":{"platform":{"values":{"authentication":{"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 } +@test "Aggregated API rejects Tenant name with dashes" { + # Regression guard: the tenant Helm chart's tenant.name helper splits the + # Release.Name on "-" and fails unless the result is exactly + # ["tenant", ""]. The aggregated API must catch tenant names + # containing dashes up-front with a tenant-specific error, instead of + # silently accepting the Application and letting Flux fail later. + + # Defensive cleanup: if a prior regression left foo-bar in the cluster, + # remove it before exercising the validation so we are not observing + # stale state. Safe even in the happy path because of --ignore-not-found. + kubectl delete tenants.apps.cozystack.io foo-bar -n tenant-root --ignore-not-found + + # Preflight: tenant-root is created by earlier tests in this suite. Fail + # loudly if it is missing so this test does not silently trigger an + # unrelated "namespace not found" error and misreport as a pass. + kubectl get namespace tenant-root + + # --validate=ignore forces kubectl to skip client-side OpenAPI validation + # and send the payload straight to the aggregated API. This guarantees the + # server-side name check runs and the error we grep for is the tenant + # contract error, not a kubectl schema rejection. (--validate=false is the + # deprecated alias.) + local output rc + # Run the apply in its own subshell so we can capture BOTH stdout+stderr + # AND the exit code explicitly, without `|| true` swallowing a real failure + # mode (e.g. network error, auth failure) that should also fail the test. + output=$( + kubectl apply --validate=ignore -f - 2>&1 </dev/null | wc -l)" -ge 1 ]; do sleep 1; done' + kubectl get quota -n tenant-test \ + -o jsonpath='{range .items[*]}{.spec.hard.requests\.memory}{" "}{.spec.hard.requests\.storage}{"\n"}{end}' \ + | grep -qx '137438953472 100Gi' + + # Assert LimitRange defaults for containers + kubectl get limitrange -n tenant-test \ + -o jsonpath='{range .items[*].spec.limits[*]}{.default.cpu}{" "}{.default.memory}{" "}{.defaultRequest.cpu}{" "}{.defaultRequest.memory}{"\n"}{end}' \ + | grep -qx '250m 128Mi 25m 128Mi' } diff --git a/hack/e2e-prepare-cluster.bats b/hack/e2e-prepare-cluster.bats index 512a621b..df90b91a 100644 --- a/hack/e2e-prepare-cluster.bats +++ b/hack/e2e-prepare-cluster.bats @@ -82,7 +82,7 @@ EOF for i in 1 2 3; do cp nocloud-amd64.raw srv${i}/system.img qemu-img resize srv${i}/system.img 50G - qemu-img create srv${i}/data.img 100G + qemu-img create srv${i}/data.img 200G done } @@ -136,25 +136,28 @@ machine: mirrors: docker.io: endpoints: - - https://dockerio.nexus.lllamnyp.su - cr.fluentbit.io: - endpoints: - - https://fluentbit.nexus.lllamnyp.su - docker-registry3.mariadb.com: - endpoints: - - https://mariadb.nexus.lllamnyp.su - gcr.io: - endpoints: - - https://gcr.nexus.lllamnyp.su - ghcr.io: - endpoints: - - https://ghcr.nexus.lllamnyp.su - quay.io: - endpoints: - - https://quay.nexus.lllamnyp.su - registry.k8s.io: - endpoints: - - https://k8s.nexus.lllamnyp.su + - https://mirror.gcr.io + #docker.io: + # endpoints: + # - https://dockerio.nexus.aenix.org + #cr.fluentbit.io: + # endpoints: + # - https://fluentbit.nexus.aenix.org + #docker-registry3.mariadb.com: + # endpoints: + # - https://mariadb.nexus.aenix.org + #gcr.io: + # endpoints: + # - https://gcr.nexus.aenix.org + #ghcr.io: + # endpoints: + # - https://ghcr.nexus.aenix.org + #quay.io: + # endpoints: + # - https://quay.nexus.aenix.org + #registry.k8s.io: + # endpoints: + # - https://k8s.nexus.aenix.org files: - content: | [plugins] @@ -236,7 +239,10 @@ EOF 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' + if ! 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'; then + talosctl dmesg -n 192.168.123.11,192.168.123.12,192.168.123.13 -e 192.168.123.10 || true + exit 1 + fi 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 diff --git a/hack/e2e-test-openapi.bats b/hack/e2e-test-openapi.bats new file mode 100644 index 00000000..88ed734b --- /dev/null +++ b/hack/e2e-test-openapi.bats @@ -0,0 +1,53 @@ +#!/usr/bin/env bats +# ----------------------------------------------------------------------------- +# Test OpenAPI endpoints in a Kubernetes cluster +# ----------------------------------------------------------------------------- + +@test "Test OpenAPI v2 endpoint" { + kubectl get -v7 --raw '/openapi/v2?timeout=32s' > /dev/null +} + +@test "Test OpenAPI v3 endpoint" { + kubectl get -v7 --raw '/openapi/v3/apis/apps.cozystack.io/v1alpha1' > /dev/null + kubectl get -v7 --raw '/openapi/v3/apis/core.cozystack.io/v1alpha1' > /dev/null +} + +@test "Test OpenAPI v2 endpoint (protobuf)" { + ( + kubectl proxy --port=21234 & sleep 0.5 + trap "kill $!" EXIT + curl -sS --fail 'http://localhost:21234/openapi/v2?timeout=32s' -H 'Accept: application/com.github.proto-openapi.spec.v2@v1.0+protobuf' > /dev/null + ) +} + +@test "Test kinds" { + val=$(kubectl get --raw /apis/apps.cozystack.io/v1alpha1/tenants | jq -r '.kind') + if [ "$val" != "TenantList" ]; then + echo "Expected kind to be TenantList, got $val" + exit 1 + fi + val=$(kubectl get --raw /apis/apps.cozystack.io/v1alpha1/tenants | jq -r '.items[0].kind') + if [ "$val" != "Tenant" ]; then + echo "Expected kind to be Tenant, got $val" + exit 1 + fi + val=$(kubectl get --raw /apis/apps.cozystack.io/v1alpha1/ingresses | jq -r '.kind') + if [ "$val" != "IngressList" ]; then + echo "Expected kind to be IngressList, got $val" + exit 1 + fi + val=$(kubectl get --raw /apis/apps.cozystack.io/v1alpha1/ingresses | jq -r '.items[0].kind') + if [ "$val" != "Ingress" ]; then + echo "Expected kind to be Ingress, got $val" + exit 1 + fi +} + +@test "Create and delete namespace" { + kubectl create ns cozy-test-create-and-delete-namespace --dry-run=client -o yaml | kubectl apply -f - + if ! kubectl delete ns cozy-test-create-and-delete-namespace; then + echo "Failed to delete namespace" + kubectl describe ns cozy-test-create-and-delete-namespace + exit 1 + fi +} diff --git a/hack/gen_versions_map.sh b/hack/gen_versions_map.sh deleted file mode 100755 index 60ede8ba..00000000 --- a/hack/gen_versions_map.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/sh -set -e - -file=versions_map - -charts=$(find . -mindepth 2 -maxdepth 2 -name Chart.yaml | awk 'sub("/Chart.yaml", "")') - -new_map=$( - for chart in $charts; do - awk '/^name:/ {chart=$2} /^version:/ {version=$2} END{printf "%s %s %s\n", chart, version, "HEAD"}' "$chart/Chart.yaml" - done -) - -if [ ! -f "$file" ] || [ ! -s "$file" ]; then - echo "$new_map" > "$file" - exit 0 -fi - -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=$( - 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" - continue - fi - - # if commit is not HEAD, check if it's valid - if [ "$commit" != "HEAD" ]; then - if [ "$(git show "${commit}:./${chart}/Chart.yaml" | awk '$1 == "version:" {print $2}')" != "${version}" ]; then - echo "Commit $commit for $chart $version is not valid" >&2 - exit 1 - fi - - commit=$(git rev-parse --short "$commit") - echo "$chart $version $commit" - continue - fi - - # if commit is HEAD, but version is not found in HEAD, check all tags - found_tag="" - for tag in $search_commits; do - if [ "$(git show "${tag}:./${chart}/Chart.yaml" | awk '$1 == "version:" {print $2}')" = "${version}" ]; then - found_tag=$(git rev-parse --short "${tag}") - break - fi - done - - if [ -z "$found_tag" ]; then - echo "Can't find $chart $version in any version tag, removing it" >&2 - continue - fi - - echo "$chart $version $found_tag" - done < $miss_map -) - -printf "%s\n" "$new_map" "$resolved_miss_map" | sort -k1,1 -k2,2 -V | awk '$1' > "$file" diff --git a/hack/helm-unit-tests.sh b/hack/helm-unit-tests.sh new file mode 100755 index 00000000..d97042a2 --- /dev/null +++ b/hack/helm-unit-tests.sh @@ -0,0 +1,59 @@ +#!/bin/sh +set -eu + +# Script to run unit tests for all Helm charts. +# It iterates through directories in packages/apps, packages/extra, +# packages/system, and packages/library and runs the 'test' Makefile +# target if it exists. + +FAILED_DIRS_FILE="$(mktemp)" +trap 'rm -f "$FAILED_DIRS_FILE"' EXIT + +tests_found=0 + +check_and_run_test() { + dir="$1" + makefile="$dir/Makefile" + + if [ ! -f "$makefile" ]; then + return 0 + fi + + if make -C "$dir" -n test >/dev/null 2>&1; then + echo "Running tests in $dir" + tests_found=$((tests_found + 1)) + if ! make -C "$dir" test; then + printf '%s\n' "$dir" >> "$FAILED_DIRS_FILE" + return 1 + fi + fi + + return 0 +} + +for package_dir in packages/apps packages/extra packages/system packages/library; do + if [ ! -d "$package_dir" ]; then + echo "Warning: Directory $package_dir does not exist, skipping..." >&2 + continue + fi + + for dir in "$package_dir"/*; do + [ -d "$dir" ] || continue + check_and_run_test "$dir" || true + done +done + +if [ "$tests_found" -eq 0 ]; then + echo "No directories with 'test' Makefile targets found." + exit 0 +fi + +if [ -s "$FAILED_DIRS_FILE" ]; then + echo "ERROR: Tests failed in the following directories:" >&2 + while IFS= read -r dir; do + echo " - $dir" >&2 + done < "$FAILED_DIRS_FILE" + exit 1 +fi + +echo "All Helm unit tests passed." \ No newline at end of file diff --git a/hack/migrate-to-version-1.0.sh b/hack/migrate-to-version-1.0.sh new file mode 100755 index 00000000..a7c3f9b4 --- /dev/null +++ b/hack/migrate-to-version-1.0.sh @@ -0,0 +1,263 @@ +#!/bin/bash +# Migration script from Cozystack ConfigMaps to Package-based configuration +# This script converts cozystack, cozystack-branding, and cozystack-scheduling +# ConfigMaps into a Package resource with the new values structure. + +set -e + +NAMESPACE="cozy-system" + +echo "=============================" +echo " Cozystack Migration to v1.0 " +echo "=============================" +echo "" +echo "This script will convert existing ConfigMaps to a Package resource." +echo "" + +# Check if kubectl is available +if ! command -v kubectl &> /dev/null; then + echo "Error: kubectl is not installed or not in PATH" + exit 1 +fi + +# Check if jq is available +if ! command -v jq &> /dev/null; then + echo "Error: jq is not installed or not in PATH" + exit 1 +fi + +# Check if we can access the cluster +if ! kubectl get namespace "$NAMESPACE" &> /dev/null; then + echo "Error: Cannot access namespace $NAMESPACE" + exit 1 +fi + +# Step 0: Annotate critical resources to prevent Helm from deleting them +echo "Step 0: Protect critical resources from Helm deletion" +echo "" +echo "The following resources will be annotated with helm.sh/resource-policy=keep" +echo "to prevent Helm from deleting them when the installer release is removed:" +echo " - Namespace: $NAMESPACE" +echo " - ConfigMap: $NAMESPACE/cozystack-version" +echo "" +read -p "Do you want to annotate these resources? (y/N) " -n 1 -r +echo "" + +if [[ $REPLY =~ ^[Yy]$ ]]; then + echo "Annotating namespace $NAMESPACE..." + kubectl annotate namespace "$NAMESPACE" helm.sh/resource-policy=keep --overwrite + echo "Annotating ConfigMap cozystack-version..." + kubectl annotate configmap -n "$NAMESPACE" cozystack-version helm.sh/resource-policy=keep --overwrite 2>/dev/null || echo " ConfigMap cozystack-version not found, skipping." + echo "" + echo "Resources annotated successfully." +else + echo "WARNING: Skipping annotation. If you remove the Helm installer release," + echo "the namespace and its contents may be deleted!" +fi +echo "" + +# Step 1: Check for cozy-proxy HelmRelease with conflicting releaseName +# In v0.41.x, cozy-proxy was incorrectly configured with releaseName "cozystack", +# which conflicts with the installer helm release name. If not suspended, cozy-proxy +# HelmRelease will overwrite the installer release and delete cozystack-operator. +COZY_PROXY_RELEASE_NAME=$(kubectl get hr -n "$NAMESPACE" cozy-proxy -o jsonpath='{.spec.releaseName}' 2>/dev/null || true) +if [ "$COZY_PROXY_RELEASE_NAME" = "cozystack" ]; then + echo "WARNING: HelmRelease cozy-proxy has releaseName 'cozystack', which conflicts" + echo "with the installer release. It must be suspended before proceeding, otherwise" + echo "it will overwrite the installer and delete cozystack-operator." + echo "" + read -p "Suspend HelmRelease cozy-proxy? (y/N) " -n 1 -r + echo "" + if [[ $REPLY =~ ^[Yy]$ ]]; then + kubectl -n "$NAMESPACE" patch hr cozy-proxy --type=merge --field-manager=flux-client-side-apply -p '{"spec":{"suspend":true}}' + echo "HelmRelease cozy-proxy suspended." + else + echo "ERROR: Cannot proceed with conflicting cozy-proxy HelmRelease active." + echo "Please suspend it manually:" + echo " kubectl -n $NAMESPACE patch hr cozy-proxy --type=merge -p '{\"spec\":{\"suspend\":true}}'" + exit 1 + fi + echo "" +fi + +# Read ConfigMap cozystack +echo "Reading ConfigMap cozystack..." +COZYSTACK_CM=$(kubectl get configmap -n "$NAMESPACE" cozystack -o json 2>/dev/null || echo "{}") + +# Read ConfigMap cozystack-branding +echo "Reading ConfigMap cozystack-branding..." +BRANDING_CM=$(kubectl get configmap -n "$NAMESPACE" cozystack-branding -o json 2>/dev/null || echo "{}") + +# Read ConfigMap cozystack-scheduling +echo "Reading ConfigMap cozystack-scheduling..." +SCHEDULING_CM=$(kubectl get configmap -n "$NAMESPACE" cozystack-scheduling -o json 2>/dev/null || echo "{}") + +# Extract values from cozystack ConfigMap +CLUSTER_DOMAIN=$(echo "$COZYSTACK_CM" | jq -r '.data["cluster-domain"] // "cozy.local"') +ROOT_HOST=$(echo "$COZYSTACK_CM" | jq -r '.data["root-host"] // "example.org"') +API_SERVER_ENDPOINT=$(echo "$COZYSTACK_CM" | jq -r '.data["api-server-endpoint"] // ""') +OIDC_ENABLED=$(echo "$COZYSTACK_CM" | jq -r '.data["oidc-enabled"] // "false"') +KEYCLOAK_REDIRECTS=$(echo "$COZYSTACK_CM" | jq -r '.data["extra-keycloak-redirect-uri-for-dashboard"] // ""' ) +TELEMETRY_ENABLED=$(echo "$COZYSTACK_CM" | jq -r '.data["telemetry-enabled"] // "true"') +BUNDLE_NAME=$(echo "$COZYSTACK_CM" | jq -r '.data["bundle-name"] // "paas-full"') +BUNDLE_DISABLE=$(echo "$COZYSTACK_CM" | jq -r '.data["bundle-disable"] // ""') +BUNDLE_ENABLE=$(echo "$COZYSTACK_CM" | jq -r '.data["bundle-enable"] // ""') +EXPOSE_INGRESS=$(echo "$COZYSTACK_CM" | jq -r '.data["expose-ingress"] // "tenant-root"') +EXPOSE_SERVICES=$(echo "$COZYSTACK_CM" | jq -r '.data["expose-services"] // ""') + +# Certificate issuer configuration (old undocumented field: clusterissuer) +OLD_CLUSTER_ISSUER=$(echo "$COZYSTACK_CM" | jq -r '.data["clusterissuer"] // ""') + +# Convert old clusterissuer value to new solver/issuerName fields +SOLVER="" +ISSUER_NAME="" +case "$OLD_CLUSTER_ISSUER" in + cloudflare) + SOLVER="dns01" + ISSUER_NAME="letsencrypt-prod" + ;; + http01) + SOLVER="http01" + ISSUER_NAME="letsencrypt-prod" + ;; + "") + # Field not set; omit from Package so chart defaults apply + ;; + *) + # Unrecognised value — treat as custom ClusterIssuer name with no solver override + ISSUER_NAME="$OLD_CLUSTER_ISSUER" + ;; +esac + +# Build certificates YAML block (empty string when no override needed) +if [ -n "$SOLVER" ] || [ -n "$ISSUER_NAME" ]; then + CERTIFICATES_SECTION=" certificates: + solver: \"${SOLVER}\" + issuerName: \"${ISSUER_NAME}\"" +else + CERTIFICATES_SECTION="" +fi + +# Network configuration +POD_CIDR=$(echo "$COZYSTACK_CM" | jq -r '.data["ipv4-pod-cidr"] // "10.244.0.0/16"') +POD_GATEWAY=$(echo "$COZYSTACK_CM" | jq -r '.data["ipv4-pod-gateway"] // "10.244.0.1"') +SVC_CIDR=$(echo "$COZYSTACK_CM" | jq -r '.data["ipv4-svc-cidr"] // "10.96.0.0/16"') +JOIN_CIDR=$(echo "$COZYSTACK_CM" | jq -r '.data["ipv4-join-cidr"] // "100.64.0.0/16"') + +EXTERNAL_IPS=$(echo "$COZYSTACK_CM" | jq -r '.data["expose-external-ips"] // ""') +if [ -z "$EXTERNAL_IPS" ]; then + EXTERNAL_IPS="[]" +else + EXTERNAL_IPS=$(echo "$EXTERNAL_IPS" | sed 's/,/\n/g' | awk 'BEGIN{print}{print " - "$0}') +fi + +# Convert comma-separated lists to YAML arrays +if [ -z "$BUNDLE_DISABLE" ]; then + DISABLED_PACKAGES="[]" +else + DISABLED_PACKAGES=$(echo "$BUNDLE_DISABLE" | sed 's/,/\n/g' | awk 'BEGIN{print}{print " - cozystack."$0}') +fi + +if [ -z "$BUNDLE_ENABLE" ]; then + ENABLED_PACKAGES="[]" +else + ENABLED_PACKAGES=$(echo "$BUNDLE_ENABLE" | sed 's/,/\n/g' | awk 'BEGIN{print}{print " - cozystack."$0}') +fi + +if [ -z "$EXPOSE_SERVICES" ]; then + EXPOSED_SERVICES_YAML="[]" +else + EXPOSED_SERVICES_YAML=$(echo "$EXPOSE_SERVICES" | sed 's/,/\n/g' | awk 'BEGIN{print}{print " - "$0}') +fi + +# Update bundle naming +BUNDLE_NAME=$(echo "$BUNDLE_NAME" | sed 's/paas/isp/') + +# Extract branding if available +BRANDING=$(echo "$BRANDING_CM" | jq -r '.data // {} | to_entries[] | "\(.key): \"\(.value)\""') +if [ -z "$BRANDING" ]; then + BRANDING="{}" +else + BRANDING=$(echo "$BRANDING" | awk 'BEGIN{print}{print " " $0}') +fi + +# Extract scheduling if available +SCHEDULING_CONSTRAINTS=$(echo "$SCHEDULING_CM" | jq -r '.data["globalAppTopologySpreadConstraints"] // ""') +if [ -z "$SCHEDULING_CONSTRAINTS" ]; then + SCHEDULING_CONSTRAINTS='""' +else + SCHEDULING_CONSTRAINTS=$(echo "$SCHEDULING_CONSTRAINTS" | awk 'BEGIN{print}{print " " $0}') +fi + +echo "" +echo "Extracted configuration:" +echo " Cluster Domain: $CLUSTER_DOMAIN" +echo " Root Host: $ROOT_HOST" +echo " API Server Endpoint: $API_SERVER_ENDPOINT" +echo " OIDC Enabled: $OIDC_ENABLED" +echo " Bundle Name: $BUNDLE_NAME" +echo " Certificate Solver: ${SOLVER:-http01 (default)}" +echo " Issuer Name: ${ISSUER_NAME:-letsencrypt-prod (default)}" +echo "" + +# Generate Package YAML +PACKAGE_YAML=$(cat <&2; exit 1; fi diff --git a/hack/package_chart.sh b/hack/package_chart.sh deleted file mode 100755 index f8ab297f..00000000 --- a/hack/package_chart.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/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/remediation-guard.bats b/hack/remediation-guard.bats new file mode 100644 index 00000000..092fe06d --- /dev/null +++ b/hack/remediation-guard.bats @@ -0,0 +1,127 @@ +#!/usr/bin/env bats +# ----------------------------------------------------------------------------- +# Unit tests for hack/e2e-apps/remediation-guard.sh +# +# helmrelease_has_remediation_cycle takes a newline-delimited list of +# HelmRelease history snapshot status values (deployed/superseded/failed/ +# uninstalled/...) and returns 0 when any entry is "failed" or "uninstalled" +# (meaning flux helm-controller performed install/upgrade remediation). +# +# This is used by the e2e script after the HelmRelease reaches Ready. The +# failure/upgrade counters (.status.installFailures / .status.upgradeFailures) +# are useless there because flux's ClearFailures zeroes them on successful +# reconciliation; .status.history retains the snapshot trail. +# +# cozytest.sh's awk parser recognizes only @test blocks and a bare `}` on +# its own line; there is no bats `run` or `$status`. Assertions are +# expressed as direct shell tests that exit non-zero on failure. +# +# Run with: hack/cozytest.sh hack/remediation-guard.bats +# ----------------------------------------------------------------------------- + +@test "empty history returns not-detected" { + . hack/e2e-apps/remediation-guard.sh + if helmrelease_has_remediation_cycle ""; then + echo "expected not-detected for empty history" >&2 + exit 1 + fi +} + +@test "single deployed snapshot returns not-detected" { + . hack/e2e-apps/remediation-guard.sh + if helmrelease_has_remediation_cycle "deployed"; then + echo "expected not-detected for deployed-only history" >&2 + exit 1 + fi +} + +@test "deployed then superseded returns not-detected" { + . hack/e2e-apps/remediation-guard.sh + statuses=$(printf 'deployed\nsuperseded\n') + if helmrelease_has_remediation_cycle "${statuses}"; then + echo "expected not-detected for deployed+superseded history" >&2 + exit 1 + fi +} + +@test "single failed snapshot returns detected" { + . hack/e2e-apps/remediation-guard.sh + if ! helmrelease_has_remediation_cycle "failed"; then + echo "expected detected when history contains failed snapshot" >&2 + exit 1 + fi +} + +@test "single uninstalled snapshot returns detected" { + # The exact signature of the install-remediation race: the first install + # exceeded flux's wait budget, remediation uninstalled, the next retry + # eventually succeeded. History still carries the uninstalled snapshot. + . hack/e2e-apps/remediation-guard.sh + if ! helmrelease_has_remediation_cycle "uninstalled"; then + echo "expected detected when history contains uninstalled snapshot" >&2 + exit 1 + fi +} + +@test "uninstalled then deployed still returns detected" { + . hack/e2e-apps/remediation-guard.sh + statuses=$(printf 'uninstalled\ndeployed\n') + if ! helmrelease_has_remediation_cycle "${statuses}"; then + echo "expected detected despite later successful deploy" >&2 + exit 1 + fi +} + +@test "deployed then failed still returns detected" { + . hack/e2e-apps/remediation-guard.sh + statuses=$(printf 'deployed\nfailed\n') + if ! helmrelease_has_remediation_cycle "${statuses}"; then + echo "expected detected when any entry is failed" >&2 + exit 1 + fi +} + +@test "status.history extraction pins HR v2 status.history shape" { + # Pins the Flux HelmRelease v2 .status.history[].status shape that + # run-kubernetes.sh relies on. If a future flux release renames the + # field, the jsonpath returns nothing, the guard reports no cycle, + # and real remediation loops slip past the e2e assertion. This test + # uses yq to read the exact path used in the e2e script; the upstream + # Snapshot type lives at + # github.com/fluxcd/helm-controller/api/v2.Snapshot (via go.mod). + tmp=$(mktemp -d) + trap 'rm -rf "$tmp"' EXIT + + cat > "$tmp/hr.yaml" <<'YAML' +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: kubernetes-test + namespace: tenant-test +status: + history: + - name: kubernetes-test + namespace: tenant-test + version: 1 + status: uninstalled + - name: kubernetes-test + namespace: tenant-test + version: 2 + status: deployed +YAML + + # Default yq output is yaml scalar format, which for string values emits + # bare unquoted tokens - matching what kubectl -o jsonpath produces in + # e2e. Do not switch to JSON output here; that would quote the values + # and break the loop in helmrelease_has_remediation_cycle. + statuses=$(yq '.status.history[].status' "$tmp/hr.yaml") + + [ -n "$statuses" ] + echo "$statuses" | grep --quiet '^uninstalled$' + + . hack/e2e-apps/remediation-guard.sh + if ! helmrelease_has_remediation_cycle "$statuses"; then + echo "expected detected for pinned HR snippet with uninstalled + deployed history" >&2 + exit 1 + fi +} diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index a2a3b581..f3a47e78 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -19,19 +19,31 @@ set -o nounset set -o pipefail SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. -CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)} +CODEGEN_PKG=${CODEGEN_PKG:-~/go/pkg/mod/k8s.io/code-generator@v0.34.1} API_KNOWN_VIOLATIONS_DIR="${API_KNOWN_VIOLATIONS_DIR:-"${SCRIPT_ROOT}/api/api-rules"}" UPDATE_API_KNOWN_VIOLATIONS="${UPDATE_API_KNOWN_VIOLATIONS:-true}" CONTROLLER_GEN="go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.4" +TMPDIR=$(mktemp -d) +OPERATOR_CRDDIR=internal/crdinstall/manifests +COZY_CONTROLLER_CRDDIR=packages/system/cozystack-controller/definitions +COZY_RD_CRDDIR=packages/system/application-definition-crd/definition +BACKUPS_CORE_CRDDIR=packages/system/backup-controller/definitions +BACKUPSTRATEGY_CRDDIR=packages/system/backupstrategy-controller/definitions + +trap 'rm -rf ${TMPDIR}' EXIT source "${CODEGEN_PKG}/kube_codegen.sh" -THIS_PKG="k8s.io/sample-apiserver" +THIS_PKG="github.com/cozystack/cozystack" kube::codegen::gen_helpers \ --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \ "${SCRIPT_ROOT}/pkg/apis" +kube::codegen::gen_helpers \ + --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \ + "${SCRIPT_ROOT}/api" + if [[ -n "${API_KNOWN_VIOLATIONS_DIR:-}" ]]; then report_filename="${API_KNOWN_VIOLATIONS_DIR}/cozystack_api_violation_exceptions.list" if [[ "${UPDATE_API_KNOWN_VIOLATIONS:-}" == "true" ]]; then @@ -48,5 +60,32 @@ kube::codegen::gen_openapi \ --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \ "${SCRIPT_ROOT}/pkg/apis" +kube::codegen::gen_client \ + --with-applyconfig \ + --output-dir "${SCRIPT_ROOT}/pkg/generated" \ + --output-pkg "${THIS_PKG}/pkg/generated" \ + --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \ + "${SCRIPT_ROOT}/pkg/apis" + $CONTROLLER_GEN object:headerFile="hack/boilerplate.go.txt" paths="./api/..." -$CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/..." output:crd:artifacts:config=packages/system/cozystack-controller/templates/crds +$CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/v1alpha1/..." paths="./api/backups/..." paths="./api/dashboard/..." output:crd:artifacts:config=${TMPDIR} + +mv ${TMPDIR}/cozystack.io_packages.yaml ${OPERATOR_CRDDIR}/cozystack.io_packages.yaml +mv ${TMPDIR}/cozystack.io_packagesources.yaml ${OPERATOR_CRDDIR}/cozystack.io_packagesources.yaml + +mv ${TMPDIR}/cozystack.io_applicationdefinitions.yaml \ + ${COZY_RD_CRDDIR}/cozystack.io_applicationdefinitions.yaml + +mv ${TMPDIR}/backups.cozystack.io*.yaml ${BACKUPS_CORE_CRDDIR}/ +mv ${TMPDIR}/strategy.backups.cozystack.io*.yaml ${BACKUPSTRATEGY_CRDDIR}/ + +mv ${TMPDIR}/*.yaml ${COZY_CONTROLLER_CRDDIR}/ + +# Tidy dependencies for standalone api/apps/v1alpha1 submodule +(cd "${SCRIPT_ROOT}/api/apps/v1alpha1" && go mod tidy) + +# Generate deepcopy for standalone api/apps/v1alpha1 submodule (separate Go module) +# Use absolute path for headerFile since we cd into the submodule directory +APPS_API_ROOT="$(cd "${SCRIPT_ROOT}" && pwd)" +(cd "${APPS_API_ROOT}/api/apps/v1alpha1" && $CONTROLLER_GEN object:headerFile="${APPS_API_ROOT}/hack/boilerplate.go.txt" paths="./...") + diff --git a/hack/update-crd.sh b/hack/update-crd.sh new file mode 100755 index 00000000..81172406 --- /dev/null +++ b/hack/update-crd.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Requirements: yq (v4), jq, base64 +need() { command -v "$1" >/dev/null 2>&1 || { echo "need $1"; exit 1; }; } +need yq; need jq; need base64 + +CHART_YAML="${CHART_YAML:-Chart.yaml}" +VALUES_YAML="${VALUES_YAML:-values.yaml}" +SCHEMA_JSON="${SCHEMA_JSON:-values.schema.json}" + +[[ -f "$CHART_YAML" ]] || { echo "No $CHART_YAML found"; exit 1; } +[[ -f "$SCHEMA_JSON" ]] || { echo "No $SCHEMA_JSON found"; exit 1; } + +# Read basics from Chart.yaml +NAME="$(yq -r '.name // ""' "$CHART_YAML")" +DESC="$(yq -r '.description // ""' "$CHART_YAML")" +ICON_PATH_RAW="$(yq -r '.icon // ""' "$CHART_YAML")" + +if [[ -z "$NAME" ]]; then + echo "Chart.yaml: .name is empty"; exit 1 +fi + +CRD_DIR="../../system/${NAME}-rd/cozyrds" + +# Resolve icon path +# Accepts: +# /logos/foo.svg -> ./logos/foo.svg +# logos/foo.svg -> logos/foo.svg +# ./logos/foo.svg -> ./logos/foo.svg +# Fallback: ./logos/${NAME}.svg +resolve_icon_path() { + local p="$1" + if [[ -z "$p" || "$p" == "null" ]]; then + echo "./logos/${NAME}.svg"; return + fi + if [[ "$p" == /* ]]; then + echo ".${p}" + else + echo "$p" + fi +} +ICON_PATH="$(resolve_icon_path "$ICON_PATH_RAW")" + +if [[ ! -f "$ICON_PATH" ]]; then + # try fallback + ALT="./logos/${NAME}.svg" + if [[ -f "$ALT" ]]; then + ICON_PATH="$ALT" + else + echo "Icon not found: $ICON_PATH"; exit 1 + fi +fi + +# Base64 (portable: no -w / -b options) +ICON_B64="$(base64 < "$ICON_PATH" | tr -d '\n' | tr -d '\r')" + +# Decide which HelmRepository name to use based on path +# .../apps/... -> cozystack-apps +# .../extra/... -> cozystack-extra +# default: cozystack-apps +SOURCE_NAME="cozystack-apps" +case "$PWD" in + *"/apps/"*) SOURCE_NAME="cozystack-apps" ;; + *"/extra/"*) SOURCE_NAME="cozystack-extra" ;; +esac + +# Determine variant from PackageSource file +# Look for packages/core/platform/sources/${NAME}-application.yaml +PACKAGE_SOURCE_FILE="../../core/platform/sources/${NAME}-application.yaml" +if [[ -f "$PACKAGE_SOURCE_FILE" ]]; then + VARIANT="$(yq -r '.spec.variants[0].name // "default"' "$PACKAGE_SOURCE_FILE")" +else + VARIANT="default" +fi + +# If file doesn't exist, create a minimal skeleton +OUT="${OUT:-$CRD_DIR/$NAME.yaml}" +if [[ ! -f "$OUT" ]]; then + cat >"$OUT" <0)) # drop root + | map(map(select(type != "number"))) # drop array indices + | map(["spec"] + .) # prepend "spec" + ) + ' +)" + +# Update only necessary fields in-place +# - openAPISchema is loaded from file as a multi-line string (block scalar) +# - prefix = "-" or "" for extra +# - chartRef points to ExternalArtifact created by Package controller +yq -i ' + .apiVersion = (.apiVersion // "cozystack.io/v1alpha1") | + .kind = (.kind // "ApplicationDefinition") | + .metadata.name = strenv(RES_NAME) | + .spec.application.openAPISchema = strenv(SCHEMA_JSON_MIN) | + (.spec.application.openAPISchema style="literal") | + .spec.release.prefix = (strenv(PREFIX)) | + del(.spec.release.labels."cozystack.io/application") | + del(.spec.release.labels."cozystack.io/ui") | + .spec.release.chartRef.kind = "ExternalArtifact" | + .spec.release.chartRef.name = ("cozystack-" + strenv(RES_NAME) + "-application-" + strenv(VARIANT) + "-" + strenv(RES_NAME)) | + .spec.release.chartRef.namespace = "cozy-system" | + .spec.dashboard.description = strenv(DESCRIPTION) | + .spec.dashboard.icon = strenv(ICON_B64) | + .spec.dashboard.keysOrder = env(KEYS_ORDER) +' "$OUT" + +echo "Updated $OUT" diff --git a/hack/upload-assets.sh b/hack/upload-assets.sh index 9788c04f..2f7f9813 100755 --- a/hack/upload-assets.sh +++ b/hack/upload-assets.sh @@ -3,9 +3,15 @@ set -xe version=${VERSION:-$(git describe --tags)} -gh release upload --clobber $version _out/assets/cozystack-installer.yaml +gh release upload --clobber $version _out/assets/cozystack-crds.yaml +gh release upload --clobber $version _out/assets/cozystack-operator-talos.yaml +gh release upload --clobber $version _out/assets/cozystack-operator-generic.yaml +gh release upload --clobber $version _out/assets/cozystack-operator-hosted.yaml gh release upload --clobber $version _out/assets/metal-amd64.iso gh release upload --clobber $version _out/assets/metal-amd64.raw.xz gh release upload --clobber $version _out/assets/nocloud-amd64.raw.xz gh release upload --clobber $version _out/assets/kernel-amd64 gh release upload --clobber $version _out/assets/initramfs-metal-amd64.xz +gh release upload --clobber $version _out/assets/cozypkg-*.tar.gz +gh release upload --clobber $version _out/assets/cozypkg-checksums.txt +gh release upload --clobber $version _out/assets/openapi.json diff --git a/hack/upload-releasenotes.sh b/hack/upload-releasenotes.sh new file mode 100755 index 00000000..2b23f803 --- /dev/null +++ b/hack/upload-releasenotes.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +if [ $# -ne 1 ]; then + echo "Usage: $0 " + echo "Example: 0.37.*" + exit 1 +fi + +VERSION_PATTERN="$1" + +# Collect matching files first +FILES=$(find docs/changelogs -name "v${VERSION_PATTERN}.md" 2>/dev/null || true) + +if [ -z "$FILES" ]; then + echo "No changelog files found matching pattern: v${VERSION_PATTERN}.md" + exit 1 +fi + +# Process each file +echo "$FILES" | while IFS= read -r file; do + if [ -z "$file" ]; then + continue + fi + + # Extract version from filename safely (basename without extension) + version=$(basename "$file" .md) + + if [ -z "$version" ]; then + echo "Warning: Could not extract version from file: $file" + continue + fi + + echo "Uploading release notes for version: $version" + + # Check exit status of gh release edit + if ! gh release edit "$version" --notes-file "docs/changelogs/${version}.md"; then + echo "Error: Failed to upload release notes for version: $version" + exit 1 + fi +done diff --git a/internal/backupcontroller/backup_controller.go b/internal/backupcontroller/backup_controller.go new file mode 100644 index 00000000..486a24ae --- /dev/null +++ b/internal/backupcontroller/backup_controller.go @@ -0,0 +1,136 @@ +package backupcontroller + +import ( + "context" + "fmt" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" + + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" + velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" +) + +const backupFinalizer = "backups.cozystack.io/cleanup-velero" + +// BackupReconciler reconciles Backup objects. +// It manages a finalizer that ensures the underlying Velero backup is deleted +// when the cozystack Backup resource is deleted. +type BackupReconciler struct { + client.Client + Scheme *runtime.Scheme + Recorder record.EventRecorder +} + +func (r *BackupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + logger.V(1).Info("reconciling Backup", "namespace", req.Namespace, "name", req.Name) + + backup := &backupsv1alpha1.Backup{} + if err := r.Get(ctx, types.NamespacedName{Namespace: req.Namespace, Name: req.Name}, backup); err != nil { + if apierrors.IsNotFound(err) { + return ctrl.Result{}, nil + } + return ctrl.Result{}, err + } + + // Handle deletion: clean up Velero backup + if !backup.DeletionTimestamp.IsZero() { + if controllerutil.ContainsFinalizer(backup, backupFinalizer) { + if err := r.cleanupVeleroBackup(ctx, backup); err != nil { + logger.Error(err, "failed to clean up Velero backup") + return ctrl.Result{}, err + } + + controllerutil.RemoveFinalizer(backup, backupFinalizer) + if err := r.Update(ctx, backup); err != nil { + return ctrl.Result{}, err + } + logger.V(1).Info("removed finalizer and cleaned up Velero backup", "backup", backup.Name) + } + return ctrl.Result{}, nil + } + + // Ensure finalizer is present + if !controllerutil.ContainsFinalizer(backup, backupFinalizer) { + controllerutil.AddFinalizer(backup, backupFinalizer) + if err := r.Update(ctx, backup); err != nil { + return ctrl.Result{}, err + } + logger.V(1).Info("added finalizer to Backup", "backup", backup.Name) + } + + return ctrl.Result{}, nil +} + +// cleanupVeleroBackup deletes the Velero backup and its data from storage +// by creating a Velero DeleteBackupRequest. A direct Delete of the +// backup.velero.io resource only removes the Kubernetes object; Velero's +// BSL sync will recreate it from the object store. The DeleteBackupRequest +// tells Velero to also purge the data, preventing resurrection. +func (r *BackupReconciler) cleanupVeleroBackup(ctx context.Context, backup *backupsv1alpha1.Backup) error { + logger := log.FromContext(ctx) + + veleroBackupName, ok := backup.Spec.DriverMetadata[veleroBackupNameMetadataKey] + if !ok || veleroBackupName == "" { + logger.V(1).Info("no Velero backup name in driverMetadata, nothing to clean up") + return nil + } + + veleroBackupNamespace := backup.Spec.DriverMetadata[veleroBackupNamespaceMetadataKey] + if veleroBackupNamespace == "" { + veleroBackupNamespace = veleroNamespace + } + + // Check if the Velero Backup still exists + veleroBackup := &velerov1.Backup{} + err := r.Get(ctx, types.NamespacedName{ + Namespace: veleroBackupNamespace, + Name: veleroBackupName, + }, veleroBackup) + if err != nil { + if apierrors.IsNotFound(err) { + logger.V(1).Info("Velero backup already deleted", "name", veleroBackupName) + return nil + } + return fmt.Errorf("failed to get Velero backup %s/%s: %w", veleroBackupNamespace, veleroBackupName, err) + } + + // Create a DeleteBackupRequest so Velero removes backup data from storage. + // Without this, BSL sync will recreate the backup.velero.io resource. + dbr := &velerov1.DeleteBackupRequest{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: veleroBackupName + "-", + Namespace: veleroBackupNamespace, + }, + Spec: velerov1.DeleteBackupRequestSpec{ + BackupName: veleroBackupName, + }, + } + if err := r.Create(ctx, dbr); err != nil { + if apierrors.IsAlreadyExists(err) { + logger.V(1).Info("DeleteBackupRequest already exists", "backup", veleroBackupName) + return nil + } + return fmt.Errorf("failed to create DeleteBackupRequest for %s/%s: %w", veleroBackupNamespace, veleroBackupName, err) + } + + logger.Info("created DeleteBackupRequest for Velero backup", + "name", veleroBackupName, "namespace", veleroBackupNamespace, + "deleteRequest", dbr.Name) + return nil +} + +// SetupWithManager registers the BackupReconciler with the Manager. +func (r *BackupReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&backupsv1alpha1.Backup{}). + Complete(r) +} diff --git a/internal/backupcontroller/backupclass_resolver.go b/internal/backupcontroller/backupclass_resolver.go new file mode 100644 index 00000000..a1449c49 --- /dev/null +++ b/internal/backupcontroller/backupclass_resolver.go @@ -0,0 +1,75 @@ +package backupcontroller + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" +) + +const ( + // DefaultApplicationAPIGroup is the default API group for applications + // when not specified in ApplicationRef or ApplicationSelector. + // Deprecated: Use backupsv1alpha1.DefaultApplicationAPIGroup instead. + DefaultApplicationAPIGroup = backupsv1alpha1.DefaultApplicationAPIGroup +) + +// NormalizeApplicationRef sets the default apiGroup to DefaultApplicationAPIGroup if it's not specified. +// Deprecated: Use backupsv1alpha1.NormalizeApplicationRef instead. +func NormalizeApplicationRef(ref corev1.TypedLocalObjectReference) corev1.TypedLocalObjectReference { + return backupsv1alpha1.NormalizeApplicationRef(ref) +} + +// ResolvedBackupConfig contains the resolved strategy and storage configuration +// from a BackupClass. +type ResolvedBackupConfig struct { + StrategyRef corev1.TypedLocalObjectReference + Parameters map[string]string +} + +// ResolveBackupClass resolves a BackupClass and finds the matching strategy for the given application. +// It normalizes the applicationRef's apiGroup (defaults to apps.cozystack.io if not specified) +// and matches it against the strategies in the BackupClass. +func ResolveBackupClass( + ctx context.Context, + c client.Client, + backupClassName string, + applicationRef corev1.TypedLocalObjectReference, +) (*ResolvedBackupConfig, error) { + // Normalize applicationRef (default apiGroup if not specified) + applicationRef = NormalizeApplicationRef(applicationRef) + + // Get BackupClass + backupClass := &backupsv1alpha1.BackupClass{} + if err := c.Get(ctx, client.ObjectKey{Name: backupClassName}, backupClass); err != nil { + return nil, fmt.Errorf("failed to get BackupClass %s: %w", backupClassName, err) + } + + // Determine application API group (already normalized, but extract for matching) + appAPIGroup := backupsv1alpha1.DefaultApplicationAPIGroup + if applicationRef.APIGroup != nil { + appAPIGroup = *applicationRef.APIGroup + } + + // Find matching strategy + for _, strategy := range backupClass.Spec.Strategies { + // Normalize strategy's application selector (default apiGroup if not specified) + strategyAPIGroup := backupsv1alpha1.DefaultApplicationAPIGroup + if strategy.Application.APIGroup != nil && *strategy.Application.APIGroup != "" { + strategyAPIGroup = *strategy.Application.APIGroup + } + + if strategyAPIGroup == appAPIGroup && strategy.Application.Kind == applicationRef.Kind { + return &ResolvedBackupConfig{ + StrategyRef: strategy.StrategyRef, + Parameters: strategy.Parameters, + }, nil + } + } + + return nil, fmt.Errorf("no matching strategy found in BackupClass %s for application %s/%s", + backupClassName, appAPIGroup, applicationRef.Kind) +} diff --git a/internal/backupcontroller/backupclass_resolver_test.go b/internal/backupcontroller/backupclass_resolver_test.go new file mode 100644 index 00000000..cd65f22a --- /dev/null +++ b/internal/backupcontroller/backupclass_resolver_test.go @@ -0,0 +1,371 @@ +package backupcontroller + +import ( + "context" + "testing" + + corev1 "k8s.io/api/core/v1" + apiequality "k8s.io/apimachinery/pkg/api/equality" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + strategyv1alpha1 "github.com/cozystack/cozystack/api/backups/strategy/v1alpha1" + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" +) + +func TestNormalizeApplicationRef(t *testing.T) { + tests := []struct { + name string + input corev1.TypedLocalObjectReference + expected corev1.TypedLocalObjectReference + }{ + { + name: "apiGroup not specified - should default to apps.cozystack.io", + input: corev1.TypedLocalObjectReference{ + Kind: "VirtualMachine", + Name: "vm1", + }, + expected: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr(DefaultApplicationAPIGroup), + Kind: "VirtualMachine", + Name: "vm1", + }, + }, + { + name: "apiGroup is nil - should default to apps.cozystack.io", + input: corev1.TypedLocalObjectReference{ + APIGroup: nil, + Kind: "VirtualMachine", + Name: "vm1", + }, + expected: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr(DefaultApplicationAPIGroup), + Kind: "VirtualMachine", + Name: "vm1", + }, + }, + { + name: "apiGroup is empty string - should default to apps.cozystack.io", + input: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr(""), + Kind: "VirtualMachine", + Name: "vm1", + }, + expected: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr(DefaultApplicationAPIGroup), + Kind: "VirtualMachine", + Name: "vm1", + }, + }, + { + name: "apiGroup is explicitly set - should keep it", + input: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("custom.api.group.io"), + Kind: "CustomApp", + Name: "custom-app", + }, + expected: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("custom.api.group.io"), + Kind: "CustomApp", + Name: "custom-app", + }, + }, + { + name: "apiGroup is apps.cozystack.io - should keep it", + input: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr(DefaultApplicationAPIGroup), + Kind: "VirtualMachine", + Name: "vm1", + }, + expected: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr(DefaultApplicationAPIGroup), + Kind: "VirtualMachine", + Name: "vm1", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := NormalizeApplicationRef(tt.input) + if !apiequality.Semantic.DeepEqual(result, tt.expected) { + t.Errorf("NormalizeApplicationRef() = %v, want %v", result, tt.expected) + } + }) + } +} + +func TestResolveBackupClass(t *testing.T) { + scheme := runtime.NewScheme() + err := backupsv1alpha1.AddToScheme(scheme) + if err != nil { + t.Fatalf("Failed to add backupsv1alpha1 to scheme: %v", err) + } + err = strategyv1alpha1.AddToScheme(scheme) + if err != nil { + t.Fatalf("Failed to add strategyv1alpha1 to scheme: %v", err) + } + + tests := []struct { + name string + backupClass *backupsv1alpha1.BackupClass + applicationRef corev1.TypedLocalObjectReference + backupClassName string + wantErr bool + expectedStrategyRef *corev1.TypedLocalObjectReference + expectedParams map[string]string + }{ + { + name: "successful resolution - matches VirtualMachine strategy", + backupClass: &backupsv1alpha1.BackupClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "velero", + }, + Spec: backupsv1alpha1.BackupClassSpec{ + Strategies: []backupsv1alpha1.BackupClassStrategy{ + { + StrategyRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("strategy.backups.cozystack.io"), + Kind: "Velero", + Name: "velero-strategy-vm", + }, + Application: backupsv1alpha1.ApplicationSelector{ + Kind: "VirtualMachine", + }, + Parameters: map[string]string{ + "backupStorageLocationName": "default", + }, + }, + { + StrategyRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("strategy.backups.cozystack.io"), + Kind: "Velero", + Name: "velero-strategy-mariadb", + }, + Application: backupsv1alpha1.ApplicationSelector{ + Kind: "MariaDB", + }, + Parameters: map[string]string{ + "backupStorageLocationName": "mariadb-storage", + }, + }, + }, + }, + }, + applicationRef: corev1.TypedLocalObjectReference{ + Kind: "VirtualMachine", + Name: "vm1", + }, + backupClassName: "velero", + wantErr: false, + expectedStrategyRef: &corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("strategy.backups.cozystack.io"), + Kind: "Velero", + Name: "velero-strategy-vm", + }, + expectedParams: map[string]string{ + "backupStorageLocationName": "default", + }, + }, + { + name: "successful resolution - matches MariaDB strategy with explicit apiGroup", + backupClass: &backupsv1alpha1.BackupClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "velero", + }, + Spec: backupsv1alpha1.BackupClassSpec{ + Strategies: []backupsv1alpha1.BackupClassStrategy{ + { + StrategyRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("strategy.backups.cozystack.io"), + Kind: "Velero", + Name: "velero-strategy-mariadb", + }, + Application: backupsv1alpha1.ApplicationSelector{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: "MariaDB", + }, + Parameters: map[string]string{ + "backupStorageLocationName": "mariadb-storage", + }, + }, + }, + }, + }, + applicationRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: "MariaDB", + Name: "mariadb1", + }, + backupClassName: "velero", + wantErr: false, + expectedStrategyRef: &corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("strategy.backups.cozystack.io"), + Kind: "Velero", + Name: "velero-strategy-mariadb", + }, + expectedParams: map[string]string{ + "backupStorageLocationName": "mariadb-storage", + }, + }, + { + name: "successful resolution - applicationRef without apiGroup defaults correctly", + backupClass: &backupsv1alpha1.BackupClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "velero", + }, + Spec: backupsv1alpha1.BackupClassSpec{ + Strategies: []backupsv1alpha1.BackupClassStrategy{ + { + StrategyRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("strategy.backups.cozystack.io"), + Kind: "Velero", + Name: "velero-strategy-vm", + }, + Application: backupsv1alpha1.ApplicationSelector{ + Kind: "VirtualMachine", + }, + Parameters: map[string]string{ + "backupStorageLocationName": "default", + }, + }, + }, + }, + }, + applicationRef: corev1.TypedLocalObjectReference{ + // No APIGroup specified + Kind: "VirtualMachine", + Name: "vm1", + }, + backupClassName: "velero", + wantErr: false, + expectedStrategyRef: &corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("strategy.backups.cozystack.io"), + Kind: "Velero", + Name: "velero-strategy-vm", + }, + expectedParams: map[string]string{ + "backupStorageLocationName": "default", + }, + }, + { + name: "error - BackupClass not found", + backupClass: &backupsv1alpha1.BackupClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "velero", + }, + Spec: backupsv1alpha1.BackupClassSpec{ + Strategies: []backupsv1alpha1.BackupClassStrategy{}, + }, + }, + applicationRef: corev1.TypedLocalObjectReference{ + Kind: "VirtualMachine", + Name: "vm1", + }, + backupClassName: "nonexistent", + wantErr: true, + }, + { + name: "error - no matching strategy found", + backupClass: &backupsv1alpha1.BackupClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "velero", + }, + Spec: backupsv1alpha1.BackupClassSpec{ + Strategies: []backupsv1alpha1.BackupClassStrategy{ + { + StrategyRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("strategy.backups.cozystack.io"), + Kind: "Velero", + Name: "velero-strategy-vm", + }, + Application: backupsv1alpha1.ApplicationSelector{ + Kind: "VirtualMachine", + }, + }, + }, + }, + }, + applicationRef: corev1.TypedLocalObjectReference{ + Kind: "PostgreSQL", // Not in BackupClass + Name: "pg1", + }, + backupClassName: "velero", + wantErr: true, + }, + { + name: "error - apiGroup mismatch", + backupClass: &backupsv1alpha1.BackupClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "velero", + }, + Spec: backupsv1alpha1.BackupClassSpec{ + Strategies: []backupsv1alpha1.BackupClassStrategy{ + { + StrategyRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("strategy.backups.cozystack.io"), + Kind: "Velero", + Name: "velero-strategy-vm", + }, + Application: backupsv1alpha1.ApplicationSelector{ + APIGroup: stringPtr("custom.api.group.io"), + Kind: "VirtualMachine", + }, + }, + }, + }, + }, + applicationRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), // Different apiGroup + Kind: "VirtualMachine", + Name: "vm1", + }, + backupClassName: "velero", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(tt.backupClass). + Build() + + resolved, err := ResolveBackupClass(ctx, fakeClient, tt.backupClassName, tt.applicationRef) + + if tt.wantErr { + if err == nil { + t.Errorf("ResolveBackupClass() expected error but got none") + } + return + } + + if err != nil { + t.Errorf("ResolveBackupClass() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if resolved == nil { + t.Errorf("ResolveBackupClass() returned nil, expected ResolvedBackupConfig") + return + } + + // Verify strategy ref using apimachinery equality + if tt.expectedStrategyRef != nil { + if !apiequality.Semantic.DeepEqual(resolved.StrategyRef, *tt.expectedStrategyRef) { + t.Errorf("ResolveBackupClass() StrategyRef = %v, want %v", resolved.StrategyRef, *tt.expectedStrategyRef) + } + } + + // Verify parameters using apimachinery equality + if tt.expectedParams != nil { + if !apiequality.Semantic.DeepEqual(resolved.Parameters, tt.expectedParams) { + t.Errorf("ResolveBackupClass() Parameters = %v, want %v", resolved.Parameters, tt.expectedParams) + } + } + }) + } +} diff --git a/internal/backupcontroller/backupjob_controller.go b/internal/backupcontroller/backupjob_controller.go new file mode 100644 index 00000000..b926722f --- /dev/null +++ b/internal/backupcontroller/backupjob_controller.go @@ -0,0 +1,142 @@ +package backupcontroller + +import ( + "context" + "net/http" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + "sigs.k8s.io/controller-runtime/pkg/log" + + strategyv1alpha1 "github.com/cozystack/cozystack/api/backups/strategy/v1alpha1" + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" +) + +// BackupJobReconciler reconciles BackupJob with a strategy from the +// strategy.backups.cozystack.io API group. +type BackupJobReconciler struct { + client.Client + dynamic.Interface + meta.RESTMapper + Scheme *runtime.Scheme + Recorder record.EventRecorder +} + +func (r *BackupJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + logger.Info("reconciling BackupJob", "namespace", req.Namespace, "name", req.Name) + + j := &backupsv1alpha1.BackupJob{} + err := r.Get(ctx, types.NamespacedName{Namespace: req.Namespace, Name: req.Name}, j) + if err != nil { + if apierrors.IsNotFound(err) { + logger.V(1).Info("BackupJob not found, skipping") + return ctrl.Result{}, nil + } + logger.Error(err, "failed to get BackupJob") + return ctrl.Result{}, err + } + + // Normalize ApplicationRef (default apiGroup if not specified) + normalizedAppRef := NormalizeApplicationRef(j.Spec.ApplicationRef) + + // Resolve BackupClass + resolved, err := ResolveBackupClass(ctx, r.Client, j.Spec.BackupClassName, normalizedAppRef) + if err != nil { + logger.Error(err, "failed to resolve BackupClass", "backupClassName", j.Spec.BackupClassName) + return ctrl.Result{}, err + } + + strategyRef := resolved.StrategyRef + + // Validate strategyRef + if strategyRef.APIGroup == nil { + logger.V(1).Info("BackupJob resolved StrategyRef has nil APIGroup, skipping", "backupjob", j.Name) + return ctrl.Result{}, nil + } + + if *strategyRef.APIGroup != strategyv1alpha1.GroupVersion.Group { + logger.V(1).Info("BackupJob resolved StrategyRef.APIGroup doesn't match, skipping", + "backupjob", j.Name, + "expected", strategyv1alpha1.GroupVersion.Group, + "got", *strategyRef.APIGroup) + return ctrl.Result{}, nil + } + + logger.Info("processing BackupJob", "backupjob", j.Name, "strategyKind", strategyRef.Kind, "backupClassName", j.Spec.BackupClassName) + switch strategyRef.Kind { + case strategyv1alpha1.JobStrategyKind: + return r.reconcileJob(ctx, j, resolved) + case strategyv1alpha1.VeleroStrategyKind: + return r.reconcileVelero(ctx, j, resolved) + default: + logger.V(1).Info("BackupJob resolved StrategyRef.Kind not supported, skipping", + "backupjob", j.Name, + "kind", strategyRef.Kind, + "supported", []string{strategyv1alpha1.JobStrategyKind, strategyv1alpha1.VeleroStrategyKind}) + return ctrl.Result{}, nil + } +} + +// SetupWithManager registers our controller with the Manager and sets up watches. +func (r *BackupJobReconciler) SetupWithManager(mgr ctrl.Manager) error { + // index BackupJob by backupClassName for efficient lookups when BackupClass changes + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &backupsv1alpha1.BackupJob{}, "spec.backupClassName", func(obj client.Object) []string { + job := obj.(*backupsv1alpha1.BackupJob) + if job.Spec.BackupClassName == "" { + return []string{} + } + return []string{job.Spec.BackupClassName} + }); err != nil { + return err + } + + cfg := mgr.GetConfig() + var err error + if r.Interface, err = dynamic.NewForConfig(cfg); err != nil { + return err + } + var h *http.Client + if h, err = rest.HTTPClientFor(cfg); err != nil { + return err + } + if r.RESTMapper, err = apiutil.NewDynamicRESTMapper(cfg, h); err != nil { + return err + } + return ctrl.NewControllerManagedBy(mgr). + For(&backupsv1alpha1.BackupJob{}). + Complete(r) +} + +func (r *BackupJobReconciler) markBackupJobFailed(ctx context.Context, backupJob *backupsv1alpha1.BackupJob, message string) (ctrl.Result, error) { + logger := getLogger(ctx) + now := metav1.Now() + backupJob.Status.CompletedAt = &now + backupJob.Status.Phase = backupsv1alpha1.BackupJobPhaseFailed + backupJob.Status.Message = message + + // Add condition + backupJob.Status.Conditions = append(backupJob.Status.Conditions, metav1.Condition{ + Type: "Ready", + Status: metav1.ConditionFalse, + Reason: "BackupFailed", + Message: message, + LastTransitionTime: now, + }) + + if err := r.Status().Update(ctx, backupJob); err != nil { + logger.Error(err, "failed to update BackupJob status to Failed") + return ctrl.Result{}, err + } + logger.Debug("BackupJob failed", "message", message) + return ctrl.Result{}, nil +} diff --git a/internal/backupcontroller/factory/backupjob.go b/internal/backupcontroller/factory/backupjob.go new file mode 100644 index 00000000..1c51d434 --- /dev/null +++ b/internal/backupcontroller/factory/backupjob.go @@ -0,0 +1,30 @@ +package factory + +import ( + "fmt" + "time" + + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func BackupJob(p *backupsv1alpha1.Plan, scheduledFor time.Time) *backupsv1alpha1.BackupJob { + // Normalize ApplicationRef (default apiGroup if not specified) + appRef := backupsv1alpha1.NormalizeApplicationRef(*p.Spec.ApplicationRef.DeepCopy()) + + job := &backupsv1alpha1.BackupJob{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%d", p.Name, scheduledFor.Unix()/60), + Namespace: p.Namespace, + }, + Spec: backupsv1alpha1.BackupJobSpec{ + PlanRef: &corev1.LocalObjectReference{ + Name: p.Name, + }, + ApplicationRef: appRef, + BackupClassName: p.Spec.BackupClassName, + }, + } + return job +} diff --git a/internal/backupcontroller/factory/backupjob_test.go b/internal/backupcontroller/factory/backupjob_test.go new file mode 100644 index 00000000..afe1f155 --- /dev/null +++ b/internal/backupcontroller/factory/backupjob_test.go @@ -0,0 +1,167 @@ +package factory + +import ( + "testing" + "time" + + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestBackupJob(t *testing.T) { + tests := []struct { + name string + plan *backupsv1alpha1.Plan + scheduled time.Time + validate func(*testing.T, *backupsv1alpha1.BackupJob) + }{ + { + name: "creates BackupJob with BackupClassName", + plan: &backupsv1alpha1.Plan{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-plan", + Namespace: "default", + }, + Spec: backupsv1alpha1.PlanSpec{ + ApplicationRef: corev1.TypedLocalObjectReference{ + Kind: "VirtualMachine", + Name: "vm1", + }, + BackupClassName: "velero", + Schedule: backupsv1alpha1.PlanSchedule{ + Type: backupsv1alpha1.PlanScheduleTypeCron, + Cron: "0 2 * * *", + }, + }, + }, + scheduled: time.Date(2024, 1, 1, 2, 0, 0, 0, time.UTC), + validate: func(t *testing.T, job *backupsv1alpha1.BackupJob) { + if job.Name == "" { + t.Error("BackupJob name should be set") + } + if job.Namespace != "default" { + t.Errorf("BackupJob namespace = %v, want default", job.Namespace) + } + if job.Spec.BackupClassName != "velero" { + t.Errorf("BackupJob BackupClassName = %v, want velero", job.Spec.BackupClassName) + } + if job.Spec.ApplicationRef.Kind != "VirtualMachine" { + t.Errorf("BackupJob ApplicationRef.Kind = %v, want VirtualMachine", job.Spec.ApplicationRef.Kind) + } + if job.Spec.ApplicationRef.Name != "vm1" { + t.Errorf("BackupJob ApplicationRef.Name = %v, want vm1", job.Spec.ApplicationRef.Name) + } + if job.Spec.PlanRef == nil || job.Spec.PlanRef.Name != "test-plan" { + t.Errorf("BackupJob PlanRef = %v, want {Name: test-plan}", job.Spec.PlanRef) + } + }, + }, + { + name: "normalizes ApplicationRef apiGroup", + plan: &backupsv1alpha1.Plan{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-plan", + Namespace: "default", + }, + Spec: backupsv1alpha1.PlanSpec{ + ApplicationRef: corev1.TypedLocalObjectReference{ + // No APIGroup specified + Kind: "MariaDB", + Name: "mariadb1", + }, + BackupClassName: "velero", + Schedule: backupsv1alpha1.PlanSchedule{ + Type: backupsv1alpha1.PlanScheduleTypeCron, + Cron: "0 2 * * *", + }, + }, + }, + scheduled: time.Date(2024, 1, 1, 2, 0, 0, 0, time.UTC), + validate: func(t *testing.T, job *backupsv1alpha1.BackupJob) { + if job.Spec.ApplicationRef.APIGroup == nil { + t.Error("BackupJob ApplicationRef.APIGroup should be set (normalized)") + return + } + if *job.Spec.ApplicationRef.APIGroup != "apps.cozystack.io" { + t.Errorf("BackupJob ApplicationRef.APIGroup = %v, want apps.cozystack.io", *job.Spec.ApplicationRef.APIGroup) + } + }, + }, + { + name: "preserves explicit ApplicationRef apiGroup", + plan: &backupsv1alpha1.Plan{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-plan", + Namespace: "default", + }, + Spec: backupsv1alpha1.PlanSpec{ + ApplicationRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("custom.api.group.io"), + Kind: "CustomApp", + Name: "custom1", + }, + BackupClassName: "velero", + Schedule: backupsv1alpha1.PlanSchedule{ + Type: backupsv1alpha1.PlanScheduleTypeCron, + Cron: "0 2 * * *", + }, + }, + }, + scheduled: time.Date(2024, 1, 1, 2, 0, 0, 0, time.UTC), + validate: func(t *testing.T, job *backupsv1alpha1.BackupJob) { + if job.Spec.ApplicationRef.APIGroup == nil { + t.Error("BackupJob ApplicationRef.APIGroup should be preserved") + return + } + if *job.Spec.ApplicationRef.APIGroup != "custom.api.group.io" { + t.Errorf("BackupJob ApplicationRef.APIGroup = %v, want custom.api.group.io", *job.Spec.ApplicationRef.APIGroup) + } + }, + }, + { + name: "generates unique job name based on timestamp", + plan: &backupsv1alpha1.Plan{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-plan", + Namespace: "default", + }, + Spec: backupsv1alpha1.PlanSpec{ + ApplicationRef: corev1.TypedLocalObjectReference{ + Kind: "VirtualMachine", + Name: "vm1", + }, + BackupClassName: "velero", + Schedule: backupsv1alpha1.PlanSchedule{ + Type: backupsv1alpha1.PlanScheduleTypeCron, + Cron: "0 2 * * *", + }, + }, + }, + scheduled: time.Date(2024, 1, 1, 2, 0, 0, 0, time.UTC), + validate: func(t *testing.T, job *backupsv1alpha1.BackupJob) { + if job.Name == "" { + t.Error("BackupJob name should be generated") + } + // Name should start with plan name + if len(job.Name) < len("test-plan") { + t.Errorf("BackupJob name = %v, should start with test-plan", job.Name) + } + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + job := BackupJob(tt.plan, tt.scheduled) + if job == nil { + t.Fatal("BackupJob() returned nil") + } + tt.validate(t, job) + }) + } +} + +func stringPtr(s string) *string { + return &s +} diff --git a/internal/backupcontroller/jobstrategy_controller.go b/internal/backupcontroller/jobstrategy_controller.go new file mode 100644 index 00000000..aaa54c19 --- /dev/null +++ b/internal/backupcontroller/jobstrategy_controller.go @@ -0,0 +1,21 @@ +package backupcontroller + +import ( + "context" + + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/log" + + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" +) + +func (r *BackupJobReconciler) reconcileJob(ctx context.Context, j *backupsv1alpha1.BackupJob, resolved *ResolvedBackupConfig) (ctrl.Result, error) { + _ = log.FromContext(ctx) + _ = resolved // Use resolved BackupClass parameters when implementing your job strategy + return ctrl.Result{}, nil +} + +func (r *RestoreJobReconciler) reconcileJobRestore(ctx context.Context, restoreJob *backupsv1alpha1.RestoreJob, backup *backupsv1alpha1.Backup) (ctrl.Result, error) { + _ = log.FromContext(ctx) + return ctrl.Result{}, nil +} diff --git a/internal/backupcontroller/plan_controller.go b/internal/backupcontroller/plan_controller.go new file mode 100644 index 00000000..4945802d --- /dev/null +++ b/internal/backupcontroller/plan_controller.go @@ -0,0 +1,104 @@ +package backupcontroller + +import ( + "context" + "fmt" + "time" + + cron "github.com/robfig/cron/v3" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" + + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" + "github.com/cozystack/cozystack/internal/backupcontroller/factory" +) + +const ( + minRequeueDelay = 30 * time.Second + startingDeadline = 300 * time.Second +) + +// PlanReconciler reconciles a Plan object +type PlanReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +func (r *PlanReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := log.FromContext(ctx) + + log.V(2).Info("reconciling") + + p := &backupsv1alpha1.Plan{} + + if err := r.Get(ctx, client.ObjectKey{Namespace: req.Namespace, Name: req.Name}, p); err != nil { + if apierrors.IsNotFound(err) { + log.V(3).Info("Plan not found") + return ctrl.Result{}, nil + } + return ctrl.Result{}, err + } + + tCheck := time.Now().Add(-startingDeadline) + sch, err := cron.ParseStandard(p.Spec.Schedule.Cron) + if err != nil { + errWrapped := fmt.Errorf("could not parse cron %s: %w", p.Spec.Schedule.Cron, err) + log.Error(err, "could not parse cron", "cron", p.Spec.Schedule.Cron) + meta.SetStatusCondition(&p.Status.Conditions, metav1.Condition{ + Type: backupsv1alpha1.PlanConditionError, + Status: metav1.ConditionTrue, + Reason: "Failed to parse cron spec", + Message: errWrapped.Error(), + }) + if err := r.Status().Update(ctx, p); err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, nil + } + + // Clear error condition if cron parsing succeeds + if condition := meta.FindStatusCondition(p.Status.Conditions, backupsv1alpha1.PlanConditionError); condition != nil && condition.Status == metav1.ConditionTrue { + meta.SetStatusCondition(&p.Status.Conditions, metav1.Condition{ + Type: backupsv1alpha1.PlanConditionError, + Status: metav1.ConditionFalse, + Reason: "Cron spec is valid", + Message: "The cron schedule has been successfully parsed", + }) + if err := r.Status().Update(ctx, p); err != nil { + return ctrl.Result{}, err + } + } + + tNext := sch.Next(tCheck) + + if time.Now().Before(tNext) { + return ctrl.Result{RequeueAfter: time.Until(tNext)}, nil + } + + job := factory.BackupJob(p, tNext) + if err := controllerutil.SetControllerReference(p, job, r.Scheme); err != nil { + return ctrl.Result{}, err + } + + if err := r.Create(ctx, job); err != nil { + if apierrors.IsAlreadyExists(err) { + return ctrl.Result{RequeueAfter: startingDeadline}, nil + } + return ctrl.Result{}, err + } + + return ctrl.Result{RequeueAfter: startingDeadline}, nil +} + +// SetupWithManager registers our controller with the Manager and sets up watches. +func (r *PlanReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&backupsv1alpha1.Plan{}). + Complete(r) +} diff --git a/internal/backupcontroller/restorejob_controller.go b/internal/backupcontroller/restorejob_controller.go new file mode 100644 index 00000000..f0062064 --- /dev/null +++ b/internal/backupcontroller/restorejob_controller.go @@ -0,0 +1,194 @@ +package backupcontroller + +import ( + "context" + "fmt" + "net/http" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" + + strategyv1alpha1 "github.com/cozystack/cozystack/api/backups/strategy/v1alpha1" + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" + velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" +) + +const restoreJobFinalizer = "backups.cozystack.io/cleanup-velero-restore" + +// RestoreJobReconciler reconciles RestoreJob objects. +// It routes RestoreJobs to strategy-specific handlers based on the strategy +// referenced in the Backup that the RestoreJob is restoring from. +type RestoreJobReconciler struct { + client.Client + dynamic.Interface + meta.RESTMapper + Scheme *runtime.Scheme + Recorder record.EventRecorder +} + +func (r *RestoreJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + logger.Info("reconciling RestoreJob", "namespace", req.Namespace, "name", req.Name) + + restoreJob := &backupsv1alpha1.RestoreJob{} + err := r.Get(ctx, types.NamespacedName{Namespace: req.Namespace, Name: req.Name}, restoreJob) + if err != nil { + if apierrors.IsNotFound(err) { + logger.V(1).Info("RestoreJob not found, skipping") + return ctrl.Result{}, nil + } + logger.Error(err, "failed to get RestoreJob") + return ctrl.Result{}, err + } + + // Handle deletion: clean up Velero Restore + if !restoreJob.DeletionTimestamp.IsZero() { + if controllerutil.ContainsFinalizer(restoreJob, restoreJobFinalizer) { + r.cleanupVeleroRestore(ctx, restoreJob) + controllerutil.RemoveFinalizer(restoreJob, restoreJobFinalizer) + if err := r.Update(ctx, restoreJob); err != nil { + return ctrl.Result{}, err + } + logger.V(1).Info("removed finalizer and cleaned up Velero Restore", "restoreJob", restoreJob.Name) + } + return ctrl.Result{}, nil + } + + // Ensure finalizer is present + if !controllerutil.ContainsFinalizer(restoreJob, restoreJobFinalizer) { + controllerutil.AddFinalizer(restoreJob, restoreJobFinalizer) + if err := r.Update(ctx, restoreJob); err != nil { + return ctrl.Result{}, err + } + } + + // If already completed, no need to reconcile + if restoreJob.Status.Phase == backupsv1alpha1.RestoreJobPhaseSucceeded || + restoreJob.Status.Phase == backupsv1alpha1.RestoreJobPhaseFailed { + logger.V(1).Info("RestoreJob already completed, skipping", "phase", restoreJob.Status.Phase) + return ctrl.Result{}, nil + } + + // Step 1: Fetch the referenced Backup + backup := &backupsv1alpha1.Backup{} + backupKey := types.NamespacedName{Namespace: req.Namespace, Name: restoreJob.Spec.BackupRef.Name} + if err := r.Get(ctx, backupKey, backup); err != nil { + return r.markRestoreJobFailed(ctx, restoreJob, fmt.Sprintf("failed to get Backup: %v", err)) + } + + // Step 2: Determine effective strategy from backup.spec.strategyRef + if backup.Spec.StrategyRef.APIGroup == nil { + return r.markRestoreJobFailed(ctx, restoreJob, "Backup has nil StrategyRef.APIGroup") + } + + if *backup.Spec.StrategyRef.APIGroup != strategyv1alpha1.GroupVersion.Group { + return r.markRestoreJobFailed(ctx, restoreJob, + fmt.Sprintf("StrategyRef.APIGroup doesn't match: %s", *backup.Spec.StrategyRef.APIGroup)) + } + + logger.Info("processing RestoreJob", "restorejob", restoreJob.Name, "backup", backup.Name, "strategyKind", backup.Spec.StrategyRef.Kind) + switch backup.Spec.StrategyRef.Kind { + case strategyv1alpha1.JobStrategyKind: + return r.reconcileJobRestore(ctx, restoreJob, backup) + case strategyv1alpha1.VeleroStrategyKind: + return r.reconcileVeleroRestore(ctx, restoreJob, backup) + default: + return r.markRestoreJobFailed(ctx, restoreJob, fmt.Sprintf("StrategyRef.Kind not supported: %s", backup.Spec.StrategyRef.Kind)) + } +} + +// SetupWithManager registers our controller with the Manager and sets up watches. +func (r *RestoreJobReconciler) SetupWithManager(mgr ctrl.Manager) error { + cfg := mgr.GetConfig() + var err error + if r.Interface, err = dynamic.NewForConfig(cfg); err != nil { + return err + } + var h *http.Client + if h, err = rest.HTTPClientFor(cfg); err != nil { + return err + } + if r.RESTMapper, err = apiutil.NewDynamicRESTMapper(cfg, h); err != nil { + return err + } + return ctrl.NewControllerManagedBy(mgr). + For(&backupsv1alpha1.RestoreJob{}). + Complete(r) +} + +// markRestoreJobFailed updates the RestoreJob status to Failed with the given message. +func (r *RestoreJobReconciler) markRestoreJobFailed(ctx context.Context, restoreJob *backupsv1alpha1.RestoreJob, message string) (ctrl.Result, error) { + logger := getLogger(ctx) + now := metav1.Now() + restoreJob.Status.CompletedAt = &now + restoreJob.Status.Phase = backupsv1alpha1.RestoreJobPhaseFailed + restoreJob.Status.Message = message + + // Add condition + restoreJob.Status.Conditions = append(restoreJob.Status.Conditions, metav1.Condition{ + Type: "Ready", + Status: metav1.ConditionFalse, + Reason: "RestoreFailed", + Message: message, + LastTransitionTime: now, + }) + + if err := r.Status().Update(ctx, restoreJob); err != nil { + logger.Error(err, "failed to update RestoreJob status to Failed") + return ctrl.Result{}, err + } + logger.Debug("RestoreJob failed", "message", message) + return ctrl.Result{}, nil +} + +// cleanupResourceModifierConfigMaps deletes resource modifier ConfigMaps owned +// by this RestoreJob. Called on completion (success or failure) to avoid leaking +// ConfigMaps in cozy-velero when RestoreJobs are not immediately deleted. +func (r *RestoreJobReconciler) cleanupResourceModifierConfigMaps(ctx context.Context, restoreJob *backupsv1alpha1.RestoreJob) { + logger := log.FromContext(ctx) + opts := []client.DeleteAllOfOption{ + client.InNamespace(veleroNamespace), + client.MatchingLabels{ + backupsv1alpha1.OwningJobNameLabel: restoreJob.Name, + backupsv1alpha1.OwningJobNamespaceLabel: restoreJob.Namespace, + }, + } + if err := r.DeleteAllOf(ctx, &corev1.ConfigMap{}, opts...); err != nil { + logger.Error(err, "failed to clean up resourceModifiers ConfigMap(s)") + } +} + +// cleanupVeleroRestore deletes all Velero Restores and resourceModifier +// ConfigMaps owned by this RestoreJob (identified by labels). +func (r *RestoreJobReconciler) cleanupVeleroRestore(ctx context.Context, restoreJob *backupsv1alpha1.RestoreJob) { + logger := log.FromContext(ctx) + opts := []client.DeleteAllOfOption{ + client.InNamespace(veleroNamespace), + client.MatchingLabels{ + backupsv1alpha1.OwningJobNameLabel: restoreJob.Name, + backupsv1alpha1.OwningJobNamespaceLabel: restoreJob.Namespace, + }, + } + + if err := r.DeleteAllOf(ctx, &velerov1.Restore{}, opts...); err != nil { + logger.Error(err, "failed to delete Velero Restore(s)") + r.Recorder.Event(restoreJob, corev1.EventTypeWarning, "CleanupFailed", + fmt.Sprintf("Failed to delete Velero Restore: %v", err)) + } + + if err := r.DeleteAllOf(ctx, &corev1.ConfigMap{}, opts...); err != nil { + logger.Error(err, "failed to delete resourceModifiers ConfigMap(s)") + } +} diff --git a/internal/backupcontroller/velerostrategy_controller.go b/internal/backupcontroller/velerostrategy_controller.go new file mode 100644 index 00000000..8b063519 --- /dev/null +++ b/internal/backupcontroller/velerostrategy_controller.go @@ -0,0 +1,1481 @@ +package backupcontroller + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "strings" + "time" + + "sigs.k8s.io/yaml" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + strategyv1alpha1 "github.com/cozystack/cozystack/api/backups/strategy/v1alpha1" + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" + "github.com/cozystack/cozystack/internal/template" + + "github.com/go-logr/logr" + velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" +) + +func getLogger(ctx context.Context) loggerWithDebug { + return loggerWithDebug{Logger: log.FromContext(ctx)} +} + +// loggerWithDebug wraps a logr.Logger and provides a Debug() method +// that maps to V(1).Info() for convenience. +type loggerWithDebug struct { + logr.Logger +} + +// Debug logs at debug level (equivalent to V(1).Info()) +func (l loggerWithDebug) Debug(msg string, keysAndValues ...interface{}) { + l.Logger.V(1).Info(msg, keysAndValues...) +} + +const ( + defaultRequeueAfter = 5 * time.Second + defaultActiveJobPollingInterval = defaultRequeueAfter + defaultRestoreRequeueAfter = 5 * time.Second + defaultActiveRestorePollingInterval = defaultRestoreRequeueAfter + // Velero requires API objects and secrets to be in the cozy-velero namespace + veleroNamespace = "cozy-velero" + veleroBackupNameMetadataKey = "velero.io/backup-name" + veleroBackupNamespaceMetadataKey = "velero.io/backup-namespace" + + // Annotation key for persisting underlying resources on the Velero Backup object + underlyingResourcesAnnotation = "backups.cozystack.io/underlying-resources" + + // VM-specific constants + vmInstanceKind = "VMInstance" + vmDiskAppKind = "VMDisk" + vmNamePrefix = "vm-instance-" + vmDiskNamePrefix = "vm-disk-" + appKindLabel = "apps.cozystack.io/application.kind" + appNameLabel = "apps.cozystack.io/application.name" + vmPodNameLabel = "vm.kubevirt.io/name" + ovnIPAnnotation = "ovn.kubernetes.io/ip_address" + ovnMACAnnotation = "ovn.kubernetes.io/mac_address" + cdiAllowClaimAdoption = "cdi.kubevirt.io/allowClaimAdoption" +) + +func stringPtr(s string) *string { + return &s +} + +// boolPtr returns a pointer to a bool value. +func boolPtr(b bool) *bool { + return &b +} + +// boolDefault returns the value of a *bool pointer, or the given default if nil. +func boolDefault(p *bool, def bool) bool { + if p != nil { + return *p + } + return def +} + +// CommonRestoreOptions contains driver-agnostic restore options shared across +// all application kinds. +type CommonRestoreOptions struct { + // TargetNamespace is the namespace to restore into. When set (and differs + // from the backup namespace), a cross-namespace restore (copy) is performed + // using Velero's namespaceMapping. + TargetNamespace string `json:"targetNamespace,omitempty"` + // FailIfTargetExists makes the restore fail if the target resource already + // exists. Defaults to true when omitted. + FailIfTargetExists *bool `json:"failIfTargetExists,omitempty"` +} + +// RestoreOptions is the typed representation of RestoreJob.Spec.Options for the +// Velero driver. The struct is deserialized from runtime.RawExtension and used +// for all application kinds. VMInstance-specific fields (KeepOriginalPVC, +// KeepOriginalIpAndMac) are only effective when the application kind is VMInstance. +type RestoreOptions struct { + CommonRestoreOptions `json:",inline"` + // KeepOriginalPVC renames the original PVC to -orig- before restore. + // Only effective for in-place VMInstance restore (no targetNamespace). Defaults to true when omitted. + KeepOriginalPVC *bool `json:"keepOriginalPVC,omitempty"` + // KeepOriginalIpAndMac preserves the original IP and MAC address via OVN + // annotations. Only effective for VMInstance restores. Defaults to true when omitted. + KeepOriginalIpAndMac *bool `json:"keepOriginalIpAndMac,omitempty"` +} + +// GetFailIfTargetExists returns the effective value (default: true). +func (o *CommonRestoreOptions) GetFailIfTargetExists() bool { + return boolDefault(o.FailIfTargetExists, true) +} + +// GetKeepOriginalPVC returns the effective value (default: true). +func (o *RestoreOptions) GetKeepOriginalPVC() bool { + return boolDefault(o.KeepOriginalPVC, true) +} + +// GetKeepOriginalIpAndMac returns the effective value (default: true). +func (o *RestoreOptions) GetKeepOriginalIpAndMac() bool { + return boolDefault(o.KeepOriginalIpAndMac, true) +} + +// parseRestoreOptions deserializes RestoreJob.Spec.Options into RestoreOptions. +// Returns zero-value RestoreOptions if options is nil. +func parseRestoreOptions(opts *runtime.RawExtension) (RestoreOptions, error) { + var ro RestoreOptions + if opts == nil || len(opts.Raw) == 0 { + return ro, nil + } + if err := json.Unmarshal(opts.Raw, &ro); err != nil { + return ro, fmt.Errorf("failed to parse restore options: %w", err) + } + return ro, nil +} + +// restoreTarget holds the resolved target namespace and app identity for a restore operation. +type restoreTarget struct { + Namespace string + AppName string + AppKind string + IsCopy bool // true when targetNamespace differs from backup namespace + IsRenamed bool // true when target app name differs from source app name +} + +// resolveRestoreTarget computes the effective restore target from RestoreJob, Backup, and options. +func resolveRestoreTarget(restoreJob *backupsv1alpha1.RestoreJob, backup *backupsv1alpha1.Backup, opts RestoreOptions) restoreTarget { + targetNS := backup.Namespace + isCopy := false + if opts.TargetNamespace != "" && opts.TargetNamespace != backup.Namespace { + targetNS = opts.TargetNamespace + isCopy = true + } + targetAppName := backup.Spec.ApplicationRef.Name + if restoreJob.Spec.TargetApplicationRef != nil && restoreJob.Spec.TargetApplicationRef.Name != "" { + targetAppName = restoreJob.Spec.TargetApplicationRef.Name + } + targetAppKind := backup.Spec.ApplicationRef.Kind + if restoreJob.Spec.TargetApplicationRef != nil && restoreJob.Spec.TargetApplicationRef.Kind != "" { + targetAppKind = restoreJob.Spec.TargetApplicationRef.Kind + } + return restoreTarget{ + Namespace: targetNS, + AppName: targetAppName, + AppKind: targetAppKind, + IsCopy: isCopy, + IsRenamed: targetAppName != backup.Spec.ApplicationRef.Name, + } +} + +// vmInstanceResources contains VM-specific underlying resources discovered during backup. +type vmInstanceResources struct { + DataVolumes []backupsv1alpha1.DataVolumeResource `json:"dataVolumes,omitempty"` + IP string `json:"ip,omitempty"` + MAC string `json:"mac,omitempty"` +} + +// marshalUnderlyingResources serializes application-specific data into a +// runtime.RawExtension suitable for Backup.Status.UnderlyingResources. +func marshalUnderlyingResources(data interface{}) (*runtime.RawExtension, error) { + raw, err := json.Marshal(data) + if err != nil { + return nil, err + } + return &runtime.RawExtension{Raw: raw}, nil +} + +// getVMInstanceResources extracts VMInstance-specific resources from the opaque blob. +// The caller is responsible for checking that the application kind is VMInstance +// (via backup.Spec.ApplicationRef.Kind) before calling this function. +// Returns nil if ur is nil or has no VM-specific data. +func getVMInstanceResources(ur *runtime.RawExtension) *vmInstanceResources { + if ur == nil || len(ur.Raw) == 0 { + return nil + } + var res vmInstanceResources + if err := json.Unmarshal(ur.Raw, &res); err != nil { + return nil + } + if len(res.DataVolumes) == 0 && res.IP == "" && res.MAC == "" { + return nil + } + return &res +} + +func (r *BackupJobReconciler) reconcileVelero(ctx context.Context, j *backupsv1alpha1.BackupJob, resolved *ResolvedBackupConfig) (ctrl.Result, error) { + logger := getLogger(ctx) + logger.Debug("reconciling Velero strategy", "backupjob", j.Name, "phase", j.Status.Phase) + + // If already completed, no need to reconcile + if j.Status.Phase == backupsv1alpha1.BackupJobPhaseSucceeded || + j.Status.Phase == backupsv1alpha1.BackupJobPhaseFailed { + logger.Debug("BackupJob already completed, skipping", "phase", j.Status.Phase) + return ctrl.Result{}, nil + } + + // Step 1: On first reconcile, set startedAt (but not phase yet - phase will be set after backup creation) + logger.Debug("checking BackupJob status", "startedAt", j.Status.StartedAt, "phase", j.Status.Phase) + if j.Status.StartedAt == nil { + logger.Debug("setting BackupJob StartedAt") + now := metav1.Now() + j.Status.StartedAt = &now + // Don't set phase to Running yet - will be set after Velero backup is successfully created + if err := r.Status().Update(ctx, j); err != nil { + logger.Error(err, "failed to update BackupJob status") + return ctrl.Result{}, err + } + logger.Debug("set BackupJob StartedAt", "startedAt", j.Status.StartedAt) + } else { + logger.Debug("BackupJob already started", "startedAt", j.Status.StartedAt, "phase", j.Status.Phase) + } + + // Step 2: Resolve inputs - Read Strategy from resolved config + logger.Debug("fetching Velero strategy", "strategyName", resolved.StrategyRef.Name) + veleroStrategy := &strategyv1alpha1.Velero{} + if err := r.Get(ctx, client.ObjectKey{Name: resolved.StrategyRef.Name}, veleroStrategy); err != nil { + if errors.IsNotFound(err) { + logger.Error(err, "Velero strategy not found", "strategyName", resolved.StrategyRef.Name) + return r.markBackupJobFailed(ctx, j, fmt.Sprintf("Velero strategy not found: %s", resolved.StrategyRef.Name)) + } + logger.Error(err, "failed to get Velero strategy") + return ctrl.Result{}, err + } + logger.Debug("fetched Velero strategy", "strategyName", veleroStrategy.Name) + + // Step 3: Execute backup logic + // Check if we already created a Velero Backup + if j.Status.StartedAt == nil { + logger.Error(nil, "StartedAt is nil after status update, this should not happen") + return ctrl.Result{RequeueAfter: defaultRequeueAfter}, nil + } + logger.Debug("checking for existing Velero Backup", "namespace", veleroNamespace) + veleroBackupList := &velerov1.BackupList{} + opts := []client.ListOption{ + client.InNamespace(veleroNamespace), + client.MatchingLabels{ + backupsv1alpha1.OwningJobNamespaceLabel: j.Namespace, + backupsv1alpha1.OwningJobNameLabel: j.Name, + }, + } + + if err := r.List(ctx, veleroBackupList, opts...); err != nil { + logger.Error(err, "failed to get Velero Backup") + return ctrl.Result{}, err + } + + if len(veleroBackupList.Items) == 0 { + // Create Velero Backup + logger.Debug("Velero Backup not found, creating new one") + if err := r.createVeleroBackup(ctx, j, veleroStrategy, resolved); err != nil { + logger.Error(err, "failed to create Velero Backup") + return r.markBackupJobFailed(ctx, j, fmt.Sprintf("failed to create Velero Backup: %v", err)) + } + // After successful Velero backup creation, set phase to Running + if j.Status.Phase != backupsv1alpha1.BackupJobPhaseRunning { + logger.Debug("setting BackupJob phase to Running after successful Velero backup creation") + j.Status.Phase = backupsv1alpha1.BackupJobPhaseRunning + if err := r.Status().Update(ctx, j); err != nil { + logger.Error(err, "failed to update BackupJob phase to Running") + return ctrl.Result{}, err + } + } + logger.Debug("created Velero Backup, requeuing") + // Requeue to check status + return ctrl.Result{RequeueAfter: defaultRequeueAfter}, nil + } + + if len(veleroBackupList.Items) > 1 { + logger.Error(fmt.Errorf("too many Velero backups for BackupJob"), "found more than one Velero Backup referencing a single BackupJob as owner") + j.Status.Phase = backupsv1alpha1.BackupJobPhaseFailed + if err := r.Status().Update(ctx, j); err != nil { + logger.Error(err, "failed to update BackupJob status") + } + return ctrl.Result{}, nil + } + + veleroBackup := veleroBackupList.Items[0].DeepCopy() + logger.Debug("found existing Velero Backup", "phase", veleroBackup.Status.Phase) + + // If Velero backup exists but phase is not Running, set it to Running + // This handles the case where the backup was created but phase wasn't set yet + if j.Status.Phase != backupsv1alpha1.BackupJobPhaseRunning { + logger.Debug("setting BackupJob phase to Running (Velero backup already exists)") + j.Status.Phase = backupsv1alpha1.BackupJobPhaseRunning + if err := r.Status().Update(ctx, j); err != nil { + logger.Error(err, "failed to update BackupJob phase to Running") + return ctrl.Result{}, err + } + } + + // Check Velero Backup status + phase := string(veleroBackup.Status.Phase) + if phase == "" { + // Still in progress, requeue + return ctrl.Result{RequeueAfter: defaultActiveJobPollingInterval}, nil + } + + // Step 4: On success - Create Backup resource and update status + if phase == "Completed" { + // Check if we already created the Backup resource + if j.Status.BackupRef == nil { + backup, err := r.createBackupResource(ctx, j, veleroBackup, resolved) + if err != nil { + return r.markBackupJobFailed(ctx, j, fmt.Sprintf("failed to create Backup resource: %v", err)) + } + + now := metav1.Now() + j.Status.BackupRef = &corev1.LocalObjectReference{Name: backup.Name} + j.Status.CompletedAt = &now + j.Status.Phase = backupsv1alpha1.BackupJobPhaseSucceeded + if err := r.Status().Update(ctx, j); err != nil { + logger.Error(err, "failed to update BackupJob status") + return ctrl.Result{}, err + } + logger.Debug("BackupJob succeeded", "backup", backup.Name) + } + return ctrl.Result{}, nil + } + + // Step 5: On failure + if phase == "Failed" || phase == "PartiallyFailed" { + message := formatVeleroBackupFailureMessageForBackupJob(ctx, r.Client, veleroBackup) + return r.markBackupJobFailed(ctx, j, message) + } + + // Still in progress (InProgress, New, etc.) + return ctrl.Result{RequeueAfter: 5 * time.Second}, nil +} + +// collectUnderlyingResources discovers resources associated with an application +// that need to be backed up and restored. Returns a map keyed by application kind. +// Returns nil if the application type has no underlying resources to collect. +func (r *BackupJobReconciler) collectUnderlyingResources(ctx context.Context, app *unstructured.Unstructured, appKind, ns string) (*runtime.RawExtension, error) { + logger := getLogger(ctx) + + if appKind != vmInstanceKind { + logger.Debug("application is not a VMInstance, skipping underlying resource collection", "kind", appKind) + return nil, nil + } + + appName := app.GetName() + + // Extract disk names from VMInstance spec.disks[].name + disks, found, err := unstructured.NestedSlice(app.Object, "spec", "disks") + if err != nil { + return nil, fmt.Errorf("failed to read spec.disks from application: %w", err) + } + + var dataVolumes []backupsv1alpha1.DataVolumeResource + if found { + for _, d := range disks { + disk, ok := d.(map[string]interface{}) + if !ok { + continue + } + name, ok := disk["name"].(string) + if !ok || name == "" { + continue + } + dataVolumes = append(dataVolumes, backupsv1alpha1.DataVolumeResource{ + DataVolumeName: vmDiskNamePrefix + name, + ApplicationName: name, + }) + } + } + logger.Debug("collected dataVolumes from VMInstance", "count", len(dataVolumes), "appName", appName) + + // Find VM Pod to extract OVN IP/MAC addresses + vmName := vmNamePrefix + appName + podList := &corev1.PodList{} + if err := r.List(ctx, podList, + client.InNamespace(ns), + client.MatchingLabels{vmPodNameLabel: vmName}, + ); err != nil { + logger.Error(err, "failed to list VM pods for IP/MAC collection", "vmName", vmName) + // Non-fatal: we can still proceed without IP/MAC + } + + var ip, mac string + if len(podList.Items) > 0 { + pod := podList.Items[0] + ip = pod.Annotations[ovnIPAnnotation] + mac = pod.Annotations[ovnMACAnnotation] + logger.Debug("collected OVN network info from VM pod", "ip", ip, "mac", mac, "pod", pod.Name) + } else { + logger.Debug("no VM pod found for OVN info", "vmName", vmName) + } + + if len(dataVolumes) == 0 && ip == "" && mac == "" { + return nil, nil + } + + return marshalUnderlyingResources(vmInstanceResources{ + DataVolumes: dataVolumes, + IP: ip, + MAC: mac, + }) +} + +func (r *BackupJobReconciler) createVeleroBackup(ctx context.Context, backupJob *backupsv1alpha1.BackupJob, strategy *strategyv1alpha1.Velero, resolved *ResolvedBackupConfig) error { + logger := getLogger(ctx) + logger.Debug("createVeleroBackup called", "strategy", strategy.Name) + + mapping, err := r.RESTMapping(schema.GroupKind{Group: *backupJob.Spec.ApplicationRef.APIGroup, Kind: backupJob.Spec.ApplicationRef.Kind}) + if err != nil { + return err + } + ns := backupJob.Namespace + if mapping.Scope.Name() != meta.RESTScopeNameNamespace { + ns = "" + } + app, err := r.Resource(mapping.Resource).Namespace(ns).Get(ctx, backupJob.Spec.ApplicationRef.Name, metav1.GetOptions{}) + if err != nil { + return err + } + + // Collect underlying resources (VM disks, IP/MAC) + underlyingResources, err := r.collectUnderlyingResources(ctx, app, backupJob.Spec.ApplicationRef.Kind, backupJob.Namespace) + if err != nil { + logger.Error(err, "failed to collect underlying resources, proceeding without them") + // Non-fatal: proceed with backup even if collection fails + } + + templateContext := map[string]interface{}{ + "Application": app.Object, + "Parameters": resolved.Parameters, + } + + veleroBackupSpec, err := template.Template(&strategy.Spec.Template.Spec, templateContext) + if err != nil { + return err + } + + // Add label selectors for underlying VMDisk HelmReleases + if vmRes := getVMInstanceResources(underlyingResources); vmRes != nil { + for _, dv := range vmRes.DataVolumes { + veleroBackupSpec.OrLabelSelectors = append(veleroBackupSpec.OrLabelSelectors, &metav1.LabelSelector{ + MatchLabels: map[string]string{ + appKindLabel: vmDiskAppKind, + appNameLabel: dv.ApplicationName, + }, + }) + } + if len(vmRes.DataVolumes) > 0 { + logger.Debug("added VMDisk label selectors to Velero backup", "count", len(vmRes.DataVolumes)) + } + } + + // Serialize underlying resources as annotation to persist across reconcile cycles + annotations := map[string]string{} + if underlyingResources != nil && len(underlyingResources.Raw) > 0 { + annotations[underlyingResourcesAnnotation] = string(underlyingResources.Raw) + } + + veleroBackup := &velerov1.Backup{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: fmt.Sprintf("%s.%s-", backupJob.Namespace, backupJob.Name), + Namespace: veleroNamespace, + Labels: map[string]string{ + backupsv1alpha1.OwningJobNameLabel: backupJob.Name, + backupsv1alpha1.OwningJobNamespaceLabel: backupJob.Namespace, + }, + Annotations: annotations, + }, + Spec: *veleroBackupSpec, + } + name := veleroBackup.GenerateName + if err := r.Create(ctx, veleroBackup); err != nil { + if veleroBackup.Name != "" { + name = veleroBackup.Name + } + logger.Error(err, "failed to create Velero Backup", "name", veleroBackup.Name) + r.Recorder.Event(backupJob, corev1.EventTypeWarning, "VeleroBackupCreationFailed", + fmt.Sprintf("Failed to create Velero Backup %s/%s: %v", veleroNamespace, name, err)) + return err + } + + logger.Debug("created Velero Backup", "name", veleroBackup.Name, "namespace", veleroBackup.Namespace) + r.Recorder.Event(backupJob, corev1.EventTypeNormal, "VeleroBackupCreated", + fmt.Sprintf("Created Velero Backup %s/%s", veleroNamespace, name)) + return nil +} + +func (r *BackupJobReconciler) createBackupResource(ctx context.Context, backupJob *backupsv1alpha1.BackupJob, veleroBackup *velerov1.Backup, resolved *ResolvedBackupConfig) (*backupsv1alpha1.Backup, error) { + logger := getLogger(ctx) + + // Get takenAt from Velero Backup creation timestamp or status + takenAt := metav1.Now() + if veleroBackup.Status.StartTimestamp != nil { + takenAt = *veleroBackup.Status.StartTimestamp + } else if !veleroBackup.CreationTimestamp.IsZero() { + takenAt = veleroBackup.CreationTimestamp + } + + // Extract driver metadata (e.g., Velero backup name) + driverMetadata := map[string]string{ + veleroBackupNameMetadataKey: veleroBackup.Name, + veleroBackupNamespaceMetadataKey: veleroBackup.Namespace, + } + + // Create a basic artifact referencing the Velero backup + artifact := &backupsv1alpha1.BackupArtifact{ + URI: fmt.Sprintf("velero://%s/%s", veleroBackup.Namespace, veleroBackup.Name), + } + + // Read underlying resources from Velero Backup annotation + var underlyingResources *runtime.RawExtension + if urJSON, ok := veleroBackup.Annotations[underlyingResourcesAnnotation]; ok && urJSON != "" { + underlyingResources = &runtime.RawExtension{Raw: []byte(urJSON)} + } + + // Note: No OwnerReferences set on Backup. The Backup must survive BackupJob deletion + // so users don't lose their backup artifacts when cleaning up completed jobs. + backup := &backupsv1alpha1.Backup{ + ObjectMeta: metav1.ObjectMeta{ + Name: backupJob.Name, + Namespace: backupJob.Namespace, + }, + Spec: backupsv1alpha1.BackupSpec{ + ApplicationRef: backupJob.Spec.ApplicationRef, + StrategyRef: resolved.StrategyRef, + TakenAt: takenAt, + DriverMetadata: driverMetadata, + }, + Status: backupsv1alpha1.BackupStatus{ + Phase: backupsv1alpha1.BackupPhaseReady, + Artifact: artifact, + UnderlyingResources: underlyingResources, + }, + } + + if backupJob.Spec.PlanRef != nil { + backup.Spec.PlanRef = backupJob.Spec.PlanRef + } + + if err := r.Create(ctx, backup); err != nil { + logger.Error(err, "failed to create Backup resource") + return nil, err + } + + logger.Debug("created Backup resource", "name", backup.Name, + "hasUnderlyingResources", underlyingResources != nil) + return backup, nil +} + +// reconcileVeleroRestore handles restore operations for Velero strategy. +func (r *RestoreJobReconciler) reconcileVeleroRestore(ctx context.Context, restoreJob *backupsv1alpha1.RestoreJob, backup *backupsv1alpha1.Backup) (ctrl.Result, error) { + logger := getLogger(ctx) + logger.Debug("reconciling Velero strategy restore", "restorejob", restoreJob.Name, "backup", backup.Name) + + // Parse restore options from the opaque blob + restoreOpts, err := parseRestoreOptions(restoreJob.Spec.Options) + if err != nil { + return r.markRestoreJobFailed(ctx, restoreJob, fmt.Sprintf("invalid restore options: %v", err)) + } + + target := resolveRestoreTarget(restoreJob, backup, restoreOpts) + logger.Debug("resolved restore target", "targetNS", target.Namespace, "targetApp", target.AppName, "isCopy", target.IsCopy) + + // Validate: target namespace must exist for cross-namespace copies + if target.IsCopy { + targetNS := &corev1.Namespace{} + if err := r.Get(ctx, client.ObjectKey{Name: target.Namespace}, targetNS); err != nil { + if errors.IsNotFound(err) { + return r.markRestoreJobFailed(ctx, restoreJob, fmt.Sprintf( + "target namespace %q does not exist; create it before requesting a cross-namespace restore", + target.Namespace)) + } + return ctrl.Result{}, fmt.Errorf("failed to check target namespace %q: %w", target.Namespace, err) + } + } + + // Validate: same-namespace restore with a different app name is not supported + // due to Velero DataUpload always writing to PVCs with the original name. + if !target.IsCopy && target.AppName != backup.Spec.ApplicationRef.Name { + return r.markRestoreJobFailed(ctx, restoreJob, + "restoring to the same namespace with a different application name is not supported "+ + "due to Velero DataUpload limitations: data is always uploaded to PVCs with the original name. "+ + "Use options.targetNamespace to restore into a different namespace") + } + + // Step 1: On first reconcile, set startedAt and phase = Running + if restoreJob.Status.StartedAt == nil { + logger.Debug("setting RestoreJob StartedAt and phase to Running") + now := metav1.Now() + restoreJob.Status.StartedAt = &now + restoreJob.Status.Phase = backupsv1alpha1.RestoreJobPhaseRunning + if err := r.Status().Update(ctx, restoreJob); err != nil { + logger.Error(err, "failed to update RestoreJob status") + return ctrl.Result{}, err + } + return ctrl.Result{RequeueAfter: defaultRestoreRequeueAfter}, nil + } + + // Step 2: Resolve inputs - Read Strategy, Storage, target Application + logger.Debug("fetching Velero strategy", "strategyName", backup.Spec.StrategyRef.Name) + veleroStrategy := &strategyv1alpha1.Velero{} + if err := r.Get(ctx, client.ObjectKey{Name: backup.Spec.StrategyRef.Name}, veleroStrategy); err != nil { + if errors.IsNotFound(err) { + logger.Error(err, "Velero strategy not found", "strategyName", backup.Spec.StrategyRef.Name) + return r.markRestoreJobFailed(ctx, restoreJob, fmt.Sprintf("Velero strategy not found: %s", backup.Spec.StrategyRef.Name)) + } + logger.Error(err, "failed to get Velero strategy") + return ctrl.Result{}, err + } + logger.Debug("fetched Velero strategy", "strategyName", veleroStrategy.Name) + + // Get Velero backup name from Backup's driverMetadata + veleroBackupName, ok := backup.Spec.DriverMetadata[veleroBackupNameMetadataKey] + if !ok { + return r.markRestoreJobFailed(ctx, restoreJob, fmt.Sprintf("Backup missing Velero backup name in driverMetadata (key: %s)", veleroBackupNameMetadataKey)) + } + + // Step 3: Execute restore logic + // Check if we already created a Velero Restore + logger.Debug("checking for existing Velero Restore", "namespace", veleroNamespace) + veleroRestoreList := &velerov1.RestoreList{} + opts := []client.ListOption{ + client.InNamespace(veleroNamespace), + client.MatchingLabels{ + backupsv1alpha1.OwningJobNameLabel: restoreJob.Name, + backupsv1alpha1.OwningJobNamespaceLabel: restoreJob.Namespace, + }, + } + + if err := r.List(ctx, veleroRestoreList, opts...); err != nil { + logger.Error(err, "failed to get Velero Restore") + return ctrl.Result{}, err + } + + if len(veleroRestoreList.Items) == 0 { + // For copy restores, enforce failIfTargetExists before touching anything. + // In-place restores are excluded: the source application is expected to exist + // and will be halted/overwritten deliberately. + if target.IsCopy && restoreOpts.GetFailIfTargetExists() { + targetHRName := helmReleaseNameForApp(target.AppKind, target.AppName) + exists, err := r.targetHelmReleaseExists(ctx, target.AppKind, targetHRName, target.Namespace) + if err != nil { + logger.Error(err, "failed to check whether target HelmRelease exists") + return ctrl.Result{}, err + } + if exists { + return r.markRestoreJobFailed(ctx, restoreJob, fmt.Sprintf( + "target application %q already exists in namespace %q; "+ + "set options.failIfTargetExists=false to overwrite", + target.AppName, target.Namespace)) + } + } + + // Resolve underlying resources once; prefer Backup status, fall back to Velero annotation. + ur := r.resolveUnderlyingResourcesForRestore(ctx, backup, veleroBackupName) + + // Pre-restore: graceful shutdown, suspend HRs, rename PVCs (skipped for copy) + ready, result, err := r.prepareForRestore(ctx, restoreJob, backup, ur, target, restoreOpts) + if err != nil { + return r.markRestoreJobFailed(ctx, restoreJob, fmt.Sprintf("pre-restore preparation failed: %v", err)) + } + if !ready { + logger.Debug("pre-restore preparation in progress, requeuing") + return result, nil + } + + // Create Velero Restore + logger.Debug("Velero Restore not found, creating new one") + if err := r.createVeleroRestore(ctx, restoreJob, backup, veleroStrategy, veleroBackupName, ur, target, restoreOpts); err != nil { + logger.Error(err, "failed to create Velero Restore") + return r.markRestoreJobFailed(ctx, restoreJob, fmt.Sprintf("failed to create Velero Restore: %v", err)) + } + logger.Debug("created Velero Restore, requeuing") + // Requeue to check status + return ctrl.Result{RequeueAfter: defaultRestoreRequeueAfter}, nil + } + + if len(veleroRestoreList.Items) > 1 { + logger.Error(fmt.Errorf("too many Velero restores for RestoreJob"), "found more than one Velero Restore referencing a single RestoreJob as owner") + return r.markRestoreJobFailed(ctx, restoreJob, "found multiple Velero Restores for this RestoreJob") + } + + veleroRestore := veleroRestoreList.Items[0].DeepCopy() + logger.Debug("found existing Velero Restore", "phase", veleroRestore.Status.Phase) + + // Check Velero Restore status + phase := string(veleroRestore.Status.Phase) + if phase == "" { + // Still in progress, requeue + return ctrl.Result{RequeueAfter: defaultActiveRestorePollingInterval}, nil + } + + // Step 4: On success + if phase == "Completed" { + // Post-restore: rename resources if target app name differs from source. + // Velero resource modifiers cannot change metadata.name, so we do it after restore. + if target.IsRenamed { + if err := r.postRestoreRename(ctx, restoreJob, backup, target); err != nil { + r.cleanupResourceModifierConfigMaps(ctx, restoreJob) + return r.markRestoreJobFailed(ctx, restoreJob, fmt.Sprintf("post-restore rename failed: %v", err)) + } + } + + // Clean up resource modifier ConfigMaps now that the restore is complete. + r.cleanupResourceModifierConfigMaps(ctx, restoreJob) + + now := metav1.Now() + restoreJob.Status.CompletedAt = &now + restoreJob.Status.Phase = backupsv1alpha1.RestoreJobPhaseSucceeded + if err := r.Status().Update(ctx, restoreJob); err != nil { + logger.Error(err, "failed to update RestoreJob status") + return ctrl.Result{}, err + } + logger.Debug("RestoreJob succeeded") + return ctrl.Result{}, nil + } + + // Step 5: On failure + if phase == "Failed" || phase == "PartiallyFailed" { + r.cleanupResourceModifierConfigMaps(ctx, restoreJob) + message := fmt.Sprintf("Velero Restore failed with phase: %s", phase) + if veleroRestore.Status.FailureReason != "" { + message = fmt.Sprintf("%s: %s", message, veleroRestore.Status.FailureReason) + } + return r.markRestoreJobFailed(ctx, restoreJob, message) + } + + // Still in progress (InProgress, New, etc.) + return ctrl.Result{RequeueAfter: defaultRestoreRequeueAfter}, nil +} + +// Velero resource modifier types (local mirrors of the internal Velero types). + +type resourceModifiers struct { + Version string `yaml:"version"` + ResourceModifierRules []resourceModifierRule `yaml:"resourceModifierRules"` +} + +type resourceModifierRule struct { + Conditions resourceModifierConditions `yaml:"conditions"` + MergePatches []mergePatch `yaml:"mergePatches,omitempty"` + Patches []jsonPatch `yaml:"patches,omitempty"` +} + +type resourceModifierConditions struct { + GroupResource string `yaml:"groupResource"` + ResourceNameRegex string `yaml:"resourceNameRegex,omitempty"` + Namespaces []string `yaml:"namespaces,omitempty"` +} + +type mergePatch struct { + PatchData string `yaml:"patchData"` +} + +type jsonPatch struct { + Operation string `yaml:"operation"` + Path string `yaml:"path"` + Value string `yaml:"value,omitempty"` +} + +// marshalPatchData marshals an arbitrary object to YAML for use as +// mergePatch.PatchData in Velero resource modifiers. +func marshalPatchData(v interface{}) (string, error) { + b, err := yaml.Marshal(v) + if err != nil { + return "", fmt.Errorf("failed to marshal patch data: %w", err) + } + return string(b), nil +} + +// createResourceModifiersConfigMap creates a Velero resource modifiers ConfigMap +// that patches VM resources during restore: +// - PVC adoption: always adds cdi.kubevirt.io/allowClaimAdoption=true to all +// restored PVCs so CDI can adopt them when a HelmRelease of VMDisk recreates a DV. +// - OVN IP/MAC: sets OVN annotations on the VirtualMachine for correct ssh access to restored VM. +func (r *RestoreJobReconciler) createResourceModifiersConfigMap(ctx context.Context, restoreJob *backupsv1alpha1.RestoreJob, backup *backupsv1alpha1.Backup, ur *runtime.RawExtension, target restoreTarget, opts RestoreOptions) (*corev1.ConfigMap, error) { + logger := getLogger(ctx) + + targetNS := target.Namespace + + var rules []resourceModifierRule + + // PVC adoption: allow CDI to adopt restored PVCs when the HelmRelease recreates a DV. + pvcPatch, err := marshalPatchData(map[string]interface{}{ + "metadata": map[string]interface{}{ + "annotations": map[string]string{ + cdiAllowClaimAdoption: "true", + }, + }, + }) + if err != nil { + return nil, err + } + rules = append(rules, resourceModifierRule{ + Conditions: resourceModifierConditions{ + GroupResource: "persistentvolumeclaims", + ResourceNameRegex: ".*", + Namespaces: []string{targetNS}, + }, + MergePatches: []mergePatch{{PatchData: pvcPatch}}, + }) + + // For cross-namespace restore: strip Velero's dynamic PV restore selector and + // volumeName from PVCs so the storage provisioner can dynamically provision new PVs. + // Without this, Velero's CSI PVCAction adds spec.selector with a velero.io/dynamic-pv-restore + // label that prevents dynamic provisioning when PVs are not included in the restore. + // Uses merge patch (null values) instead of JSON Patch remove to avoid RFC 6902 + // failures when the fields don't exist on the PVC (e.g. statically provisioned PVCs). + if target.IsCopy { + pvcStripPatch, err := marshalPatchData(map[string]interface{}{ + "spec": map[string]interface{}{ + "selector": nil, + "volumeName": nil, + }, + }) + if err != nil { + return nil, err + } + rules = append(rules, resourceModifierRule{ + Conditions: resourceModifierConditions{ + GroupResource: "persistentvolumeclaims", + ResourceNameRegex: ".*", + Namespaces: []string{targetNS}, + }, + MergePatches: []mergePatch{{PatchData: pvcStripPatch}}, + }) + } + + // OVN IP/MAC annotations on VirtualMachine for correct network identity after restore. + // Only applied when keepOriginalIpAndMac is true; for restore-to-copy the copy + // should get new IP/MAC from the network to avoid conflicts. + if opts.GetKeepOriginalIpAndMac() { + if vmRes := getVMInstanceResources(ur); vmRes != nil && (vmRes.IP != "" || vmRes.MAC != "") { + ovnAnnotations := map[string]string{} + if vmRes.IP != "" { + ovnAnnotations[ovnIPAnnotation] = vmRes.IP + } + if vmRes.MAC != "" { + ovnAnnotations[ovnMACAnnotation] = vmRes.MAC + } + vmPatch, err := marshalPatchData(map[string]interface{}{ + "spec": map[string]interface{}{ + "template": map[string]interface{}{ + "metadata": map[string]interface{}{ + "annotations": ovnAnnotations, + }, + }, + }, + }) + if err != nil { + return nil, err + } + rules = append(rules, resourceModifierRule{ + Conditions: resourceModifierConditions{ + GroupResource: "virtualmachines.kubevirt.io", + ResourceNameRegex: ".*", + Namespaces: []string{targetNS}, + }, + MergePatches: []mergePatch{{PatchData: vmPatch}}, + }) + } + } + + rulesYAML, err := yaml.Marshal(resourceModifiers{ + Version: "v1", + ResourceModifierRules: rules, + }) + if err != nil { + return nil, fmt.Errorf("failed to marshal resource modifier rules: %w", err) + } + + cmName := fmt.Sprintf("restore-modifiers-%s-%s", restoreJob.Namespace, restoreJob.Name) + // Truncate name to fit Kubernetes 253-char limit + if len(cmName) > 253 { + cmName = cmName[:253] + } + + cm := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: cmName, + Namespace: veleroNamespace, + Labels: map[string]string{ + backupsv1alpha1.OwningJobNameLabel: restoreJob.Name, + backupsv1alpha1.OwningJobNamespaceLabel: restoreJob.Namespace, + }, + }, + Data: map[string]string{ + "resource-modifier-rules.yaml": string(rulesYAML), + }, + } + + if err := r.Create(ctx, cm); err != nil { + if errors.IsAlreadyExists(err) { + // ConfigMap already exists (e.g. RestoreJob recreated with same name). + // Update its data to reflect the current backup's underlying resources. + existing := &corev1.ConfigMap{} + if err := r.Get(ctx, client.ObjectKey{Namespace: veleroNamespace, Name: cmName}, existing); err != nil { + return nil, fmt.Errorf("failed to get existing resourceModifiers ConfigMap: %w", err) + } + existing.Data = cm.Data + if err := r.Update(ctx, existing); err != nil { + return nil, fmt.Errorf("failed to update existing resourceModifiers ConfigMap: %w", err) + } + logger.Debug("updated existing resourceModifiers ConfigMap", "name", cmName) + return existing, nil + } + return nil, fmt.Errorf("failed to create resourceModifiers ConfigMap: %w", err) + } + + logger.Debug("created resourceModifiers ConfigMap", "name", cm.Name, "namespace", cm.Namespace) + return cm, nil +} + +// resolveUnderlyingResourcesForRestore returns underlying resources for symmetric +// restore label selectors. Velero Backup annotation is used when Backup.status was empty +// (e.g. CRD without underlyingResources in schema). +func (r *RestoreJobReconciler) resolveUnderlyingResourcesForRestore(ctx context.Context, backup *backupsv1alpha1.Backup, veleroBackupName string) *runtime.RawExtension { + if backup.Status.UnderlyingResources != nil && len(backup.Status.UnderlyingResources.Raw) > 0 { + return backup.Status.UnderlyingResources + } + vb := &velerov1.Backup{} + if err := r.Get(ctx, client.ObjectKey{Namespace: veleroNamespace, Name: veleroBackupName}, vb); err != nil { + return backup.Status.UnderlyingResources + } + if urJSON, ok := vb.Annotations[underlyingResourcesAnnotation]; ok && urJSON != "" { + return &runtime.RawExtension{Raw: []byte(urJSON)} + } + return backup.Status.UnderlyingResources +} + +// GVRs used during pre-restore preparation. +var ( + helmReleaseGVR = schema.GroupVersionResource{Group: "helm.toolkit.fluxcd.io", Version: "v2", Resource: "helmreleases"} + virtualMachineGVR = schema.GroupVersionResource{Group: "kubevirt.io", Version: "v1", Resource: "virtualmachines"} + vmiGVR = schema.GroupVersionResource{Group: "kubevirt.io", Version: "v1", Resource: "virtualmachineinstances"} + dataVolumeGVR = schema.GroupVersionResource{Group: "cdi.kubevirt.io", Version: "v1beta1", Resource: "datavolumes"} +) + +// helmReleaseNameForApp returns the HelmRelease name for the given application +// kind and name. Returns empty string for unsupported kinds. +func helmReleaseNameForApp(appKind, appName string) string { + switch appKind { + case vmInstanceKind: + return vmNamePrefix + appName + case vmDiskAppKind: + return vmDiskNamePrefix + appName + default: + return "" + } +} + +// targetHelmReleaseExists returns true when a HelmRelease with the given name +// already exists in namespace. Returns false for unsupported application kinds +// (those where helmReleaseNameForApp returns ""). +func (r *RestoreJobReconciler) targetHelmReleaseExists(ctx context.Context, appKind, hrName, namespace string) (bool, error) { + if hrName == "" { + return false, nil + } + _, err := r.Resource(helmReleaseGVR).Namespace(namespace).Get(ctx, hrName, metav1.GetOptions{}) + if err != nil { + if errors.IsNotFound(err) { + return false, nil + } + return false, err + } + return true, nil +} + +// shortHash returns the first 4 hex characters of sha256(input). +func shortHash(input string) string { + h := sha256.Sum256([]byte(input)) + return hex.EncodeToString(h[:])[:4] +} + +// prepareForRestore performs graceful pre-restore cleanup: +// 1. Suspends HelmReleases that belong to the backup scope. +// 2. Halts the VirtualMachine (sets spec.runStrategy=Halted). +// 3. Waits for the VMI to disappear (graceful shutdown complete). +// 4. Deletes DataVolumes so CDI doesn't recreate PVCs after rename. +// 5. Renames existing PVCs to -orig- so Velero can create fresh +// ones via Data Movement. +// +// Failures in individual steps are non-fatal: missing resources are expected +// (e.g. restore requested when app was already deleted). Each action emits +// a Kubernetes Event on the RestoreJob for observability. +// +// postRestoreRename renames VMInstance HelmRelease after Velero Restore completes. +// Velero resource modifiers cannot change metadata.name, so this step creates +// a new HelmRelease with the target name and deletes the old one. +// Flux will reconcile the renamed HelmRelease and recreate downstream resources +// (VM, VMI) with the new name. +func (r *RestoreJobReconciler) postRestoreRename(ctx context.Context, restoreJob *backupsv1alpha1.RestoreJob, backup *backupsv1alpha1.Backup, target restoreTarget) error { + logger := getLogger(ctx) + sourceAppName := backup.Spec.ApplicationRef.Name + sourceHRName := vmNamePrefix + sourceAppName + targetHRName := vmNamePrefix + target.AppName + + logger.Debug("post-restore rename", "from", sourceHRName, "to", targetHRName, "namespace", target.Namespace) + + // Get the restored HelmRelease with the original name + hrClient := r.Resource(helmReleaseGVR).Namespace(target.Namespace) + oldHR, err := hrClient.Get(ctx, sourceHRName, metav1.GetOptions{}) + if err != nil { + if errors.IsNotFound(err) { + logger.Debug("source HelmRelease not found, skipping rename", "name", sourceHRName) + return nil + } + return fmt.Errorf("failed to get HelmRelease %s: %w", sourceHRName, err) + } + + // Create new HelmRelease with the target name + newHR := oldHR.DeepCopy() + newHR.SetName(targetHRName) + newHR.SetResourceVersion("") + newHR.SetUID("") + newHR.SetCreationTimestamp(metav1.Time{}) + newHR.SetManagedFields(nil) + newHR.SetGeneration(0) + + // Update labels + labels := newHR.GetLabels() + if labels == nil { + labels = map[string]string{} + } + labels[appNameLabel] = target.AppName + labels["app.kubernetes.io/instance"] = targetHRName + labels["helm.toolkit.fluxcd.io/name"] = targetHRName + newHR.SetLabels(labels) + + // Remove Velero restore annotations/labels that tie it to the old restore + annotations := newHR.GetAnnotations() + delete(annotations, "velero.io/restore-name") + newHR.SetAnnotations(annotations) + + // Clear status so Flux reconciles fresh + unstructured.RemoveNestedField(newHR.Object, "status") + + if _, err := hrClient.Create(ctx, newHR, metav1.CreateOptions{}); err != nil { + if errors.IsAlreadyExists(err) { + logger.Debug("target HelmRelease already exists, skipping create", "name", targetHRName) + } else { + return fmt.Errorf("failed to create renamed HelmRelease %s: %w", targetHRName, err) + } + } else { + r.Recorder.Event(restoreJob, corev1.EventTypeNormal, "PostRestoreRename", + fmt.Sprintf("Created renamed HelmRelease %s (from %s)", targetHRName, sourceHRName)) + } + + // Delete the old HelmRelease + if err := hrClient.Delete(ctx, sourceHRName, metav1.DeleteOptions{}); err != nil && !errors.IsNotFound(err) { + return fmt.Errorf("failed to delete old HelmRelease %s: %w", sourceHRName, err) + } + r.Recorder.Event(restoreJob, corev1.EventTypeNormal, "PostRestoreRename", + fmt.Sprintf("Deleted old HelmRelease %s", sourceHRName)) + + logger.Debug("post-restore rename complete", "from", sourceHRName, "to", targetHRName) + return nil +} + +// Returns true when preparation is complete and the Velero Restore can be created. +// Returns false (with a requeue) when still waiting for VM shutdown. +func (r *RestoreJobReconciler) prepareForRestore(ctx context.Context, restoreJob *backupsv1alpha1.RestoreJob, backup *backupsv1alpha1.Backup, ur *runtime.RawExtension, target restoreTarget, opts RestoreOptions) (ready bool, result ctrl.Result, err error) { + // For restore-to-copy, skip all source-app preparation. + // The source application remains untouched; we're restoring a copy into another namespace. + if target.IsCopy { + r.Recorder.Event(restoreJob, corev1.EventTypeNormal, "PrepareForRestore", + "Restore to copy: skipping source application preparation") + return true, ctrl.Result{}, nil + } + + ns := restoreJob.Namespace + appName := backup.Spec.ApplicationRef.Name + appKind := backup.Spec.ApplicationRef.Kind + origSuffix := "-orig-" + shortHash(restoreJob.Name) + + // --- Step 1: Suspend HelmReleases --- + vmRes := getVMInstanceResources(ur) + hrNames := []string{} + if appKind == vmInstanceKind { + hrNames = append(hrNames, vmNamePrefix+appName) + } + if vmRes != nil { + for _, dv := range vmRes.DataVolumes { + hrNames = append(hrNames, dv.DataVolumeName) + } + } + for _, hrName := range hrNames { + if err := r.suspendHelmRelease(ctx, ns, hrName); err != nil { + r.Recorder.Event(restoreJob, corev1.EventTypeWarning, "PrepareForRestore", + fmt.Sprintf("Failed to suspend HelmRelease %s: %v", hrName, err)) + } else { + r.Recorder.Event(restoreJob, corev1.EventTypeNormal, "PrepareForRestore", + fmt.Sprintf("Suspended HelmRelease %s", hrName)) + } + } + + // --- Step 2: Halt VM and wait for shutdown --- + if appKind == vmInstanceKind { + vmName := vmNamePrefix + appName + halted, err := r.haltVirtualMachine(ctx, ns, vmName) + if err != nil { + r.Recorder.Event(restoreJob, corev1.EventTypeWarning, "PrepareForRestore", + fmt.Sprintf("Failed to halt VM %s: %v", vmName, err)) + // Non-fatal: proceed even if halting fails (VM might not exist) + } else if !halted { + r.Recorder.Event(restoreJob, corev1.EventTypeNormal, "PrepareForRestore", + fmt.Sprintf("Waiting for VM %s to shut down", vmName)) + return false, ctrl.Result{RequeueAfter: defaultRestoreRequeueAfter}, nil + } else { + r.Recorder.Event(restoreJob, corev1.EventTypeNormal, "PrepareForRestore", + fmt.Sprintf("VM %s is halted", vmName)) + } + } + + // --- Step 3: Rename PVCs to -orig- --- + // Must happen BEFORE deleting DVs: the PVC has an ownerReference to the DV, + // so deleting the DV first would cascade-delete the PVC via garbage collection. + // Only when keepOriginalPVC is true (default for in-place restore). + if opts.GetKeepOriginalPVC() && vmRes != nil { + for _, dv := range vmRes.DataVolumes { + if err := r.renamePVC(ctx, restoreJob, ns, dv.DataVolumeName, dv.DataVolumeName+origSuffix); err != nil { + r.Recorder.Event(restoreJob, corev1.EventTypeWarning, "PrepareForRestore", + fmt.Sprintf("Failed to keep old PVC %s: %v", dv.DataVolumeName, err)) + } + } + } + + // --- Step 4: Delete DataVolumes so CDI doesn't recreate PVCs --- + if vmRes != nil { + for _, dv := range vmRes.DataVolumes { + if err := r.deleteDataVolume(ctx, ns, dv.DataVolumeName); err != nil { + r.Recorder.Event(restoreJob, corev1.EventTypeWarning, "PrepareForRestore", + fmt.Sprintf("Failed to delete DataVolume %s: %v", dv.DataVolumeName, err)) + } else { + r.Recorder.Event(restoreJob, corev1.EventTypeNormal, "PrepareForRestore", + fmt.Sprintf("Deleted DataVolume %s", dv.DataVolumeName)) + } + } + } + + r.Recorder.Event(restoreJob, corev1.EventTypeNormal, "PrepareForRestore", "Pre-restore preparation complete") + return true, ctrl.Result{}, nil +} + +// suspendHelmRelease sets spec.suspend=true on a HelmRelease. +func (r *RestoreJobReconciler) suspendHelmRelease(ctx context.Context, ns, name string) error { + hr, err := r.Resource(helmReleaseGVR).Namespace(ns).Get(ctx, name, metav1.GetOptions{}) + if err != nil { + if errors.IsNotFound(err) { + return nil + } + return err + } + suspended, _, _ := unstructured.NestedBool(hr.Object, "spec", "suspend") + if suspended { + return nil + } + if err := unstructured.SetNestedField(hr.Object, true, "spec", "suspend"); err != nil { + return err + } + if _, err := r.Resource(helmReleaseGVR).Namespace(ns).Update(ctx, hr, metav1.UpdateOptions{}); err != nil { + return err + } + return nil +} + +// haltVirtualMachine sets runStrategy=Halted and returns true when the VMI is gone. +func (r *RestoreJobReconciler) haltVirtualMachine(ctx context.Context, ns, vmName string) (bool, error) { + vm, err := r.Resource(virtualMachineGVR).Namespace(ns).Get(ctx, vmName, metav1.GetOptions{}) + if err != nil { + if errors.IsNotFound(err) { + return true, nil + } + return false, err + } + + currentStrategy, _, _ := unstructured.NestedString(vm.Object, "spec", "runStrategy") + if currentStrategy != "Halted" { + if err := unstructured.SetNestedField(vm.Object, "Halted", "spec", "runStrategy"); err != nil { + return false, err + } + if _, err := r.Resource(virtualMachineGVR).Namespace(ns).Update(ctx, vm, metav1.UpdateOptions{}); err != nil { + return false, err + } + } + + // VMI gone = shutdown complete + _, err = r.Resource(vmiGVR).Namespace(ns).Get(ctx, vmName, metav1.GetOptions{}) + if err != nil { + if errors.IsNotFound(err) { + return true, nil + } + return false, err + } + return false, nil +} + +// deleteDataVolume deletes a DataVolume so CDI doesn't recreate the PVC after rename. +// Uses Orphan propagation to avoid cascade-deleting the PVC that the DV owns via +// ownerReference. Without this, keepOriginalPVC=false would silently destroy the +// original PVC through garbage collection instead of leaving it for Velero to overwrite. +func (r *RestoreJobReconciler) deleteDataVolume(ctx context.Context, ns, name string) error { + orphan := metav1.DeletePropagationOrphan + err := r.Resource(dataVolumeGVR).Namespace(ns).Delete(ctx, name, metav1.DeleteOptions{ + PropagationPolicy: &orphan, + }) + if err != nil && !errors.IsNotFound(err) { + return err + } + return nil +} + +// renamePVC preserves an existing PVC by rebinding it under a new name. +// The original PVC is deleted and a new one pointing to the same PV is created. +// Missing resources are silently skipped (non-fatal). +func (r *RestoreJobReconciler) renamePVC(ctx context.Context, restoreJob *backupsv1alpha1.RestoreJob, ns, oldName, newName string) error { + logger := getLogger(ctx) + + // Check if already renamed + existingNew := &corev1.PersistentVolumeClaim{} + if err := r.Get(ctx, client.ObjectKey{Namespace: ns, Name: newName}, existingNew); err == nil { + return nil + } + + // Get the original PVC + oldPVC := &corev1.PersistentVolumeClaim{} + if err := r.Get(ctx, client.ObjectKey{Namespace: ns, Name: oldName}, oldPVC); err != nil { + if errors.IsNotFound(err) { + return nil // nothing to rename + } + return err + } + + pvName := oldPVC.Spec.VolumeName + if pvName == "" { + logger.Debug("PVC not bound, deleting", "name", oldName) + return r.Delete(ctx, oldPVC) + } + + // Patch PV reclaim policy to Retain so it survives PVC deletion + pv := &corev1.PersistentVolume{} + if err := r.Get(ctx, client.ObjectKey{Name: pvName}, pv); err != nil { + return fmt.Errorf("failed to get PV %s: %w", pvName, err) + } + if pv.Spec.PersistentVolumeReclaimPolicy != corev1.PersistentVolumeReclaimRetain { + pv.Spec.PersistentVolumeReclaimPolicy = corev1.PersistentVolumeReclaimRetain + if err := r.Update(ctx, pv); err != nil { + return fmt.Errorf("failed to set Retain policy on PV %s: %w", pvName, err) + } + } + + // Create the new -orig PVC first (unbound, just the object) + newPVC := &corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: newName, + Namespace: ns, + }, + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: oldPVC.Spec.AccessModes, + Resources: oldPVC.Spec.Resources, + StorageClassName: oldPVC.Spec.StorageClassName, + VolumeMode: oldPVC.Spec.VolumeMode, + VolumeName: pvName, + }, + } + if err := r.Create(ctx, newPVC); err != nil && !errors.IsAlreadyExists(err) { + return fmt.Errorf("failed to create -orig PVC %s: %w", newName, err) + } + // Re-read to get UID for the claimRef + if err := r.Get(ctx, client.ObjectKey{Namespace: ns, Name: newName}, newPVC); err != nil { + return fmt.Errorf("failed to get -orig PVC %s: %w", newName, err) + } + + // Delete the original PVC + if err := r.Delete(ctx, oldPVC); err != nil && !errors.IsNotFound(err) { + return fmt.Errorf("failed to delete PVC %s: %w", oldName, err) + } + + // Point the PV's claimRef directly to the new -orig PVC. + // This is atomic — no window where the PV is Available for other PVCs to grab. + if err := r.Get(ctx, client.ObjectKey{Name: pvName}, pv); err != nil { + return fmt.Errorf("failed to re-fetch PV %s: %w", pvName, err) + } + pv.Spec.ClaimRef = &corev1.ObjectReference{ + APIVersion: "v1", + Kind: "PersistentVolumeClaim", + Namespace: ns, + Name: newName, + UID: newPVC.UID, + } + if err := r.Update(ctx, pv); err != nil { + return fmt.Errorf("failed to rebind PV %s to %s: %w", pvName, newName, err) + } + + r.Recorder.Event(restoreJob, corev1.EventTypeNormal, "PrepareForRestore", + fmt.Sprintf("Keep old PVC %s as %s (PV: %s)", oldName, newName, pvName)) + return nil +} + +// createVeleroRestore creates a Velero Restore resource. +func (r *RestoreJobReconciler) createVeleroRestore(ctx context.Context, restoreJob *backupsv1alpha1.RestoreJob, backup *backupsv1alpha1.Backup, strategy *strategyv1alpha1.Velero, veleroBackupName string, ur *runtime.RawExtension, target restoreTarget, opts RestoreOptions) error { + logger := getLogger(ctx) + logger.Debug("createVeleroRestore called", "strategy", strategy.Name, "veleroBackupName", veleroBackupName, "targetNS", target.Namespace, "isCopy", target.IsCopy) + + // For restore template context, always use the source (backup) namespace and app name. + // The strategy template uses includedNamespaces and orLabelSelectors to select + // resources from the backup tarball, which are stored under the source namespace + // and labeled with the source app name. + // Velero's namespaceMapping handles redirecting to the target namespace; + // resource modifiers handle renaming when the target app name differs. + templateContext := map[string]interface{}{ + "Application": map[string]interface{}{ + "metadata": map[string]interface{}{ + "name": backup.Spec.ApplicationRef.Name, + "namespace": backup.Namespace, + }, + "kind": backup.Spec.ApplicationRef.Kind, + }, + // TODO: Parameters are not currently stored on Backup, so they're unavailable during restore. + // This is a design limitation that should be addressed by persisting Parameters on the Backup object. + "Parameters": map[string]string{}, + } + + // Template the restore spec from the strategy, or use defaults if not specified + var veleroRestoreSpec velerov1.RestoreSpec + if strategy.Spec.Template.RestoreSpec != nil { + templatedSpec, err := template.Template(strategy.Spec.Template.RestoreSpec, templateContext) + if err != nil { + return fmt.Errorf("failed to template Velero Restore spec: %w", err) + } + veleroRestoreSpec = *templatedSpec + } + + // Set the backupName in the spec (required by Velero) + veleroRestoreSpec.BackupName = veleroBackupName + + // For restore-to-copy, set Velero namespaceMapping to redirect resources + // from the source namespace to the target namespace. + if target.IsCopy { + if veleroRestoreSpec.NamespaceMapping == nil { + veleroRestoreSpec.NamespaceMapping = make(map[string]string) + } + veleroRestoreSpec.NamespaceMapping[backup.Namespace] = target.Namespace + logger.Debug("set namespaceMapping on Velero Restore", "from", backup.Namespace, "to", target.Namespace) + } + + // Match backup: add OR selectors for each underlying VMDisk so restore applies the same + // scope as the intended backup (see createVeleroBackup). + if vmRes := getVMInstanceResources(ur); vmRes != nil { + for _, dv := range vmRes.DataVolumes { + veleroRestoreSpec.OrLabelSelectors = append(veleroRestoreSpec.OrLabelSelectors, &metav1.LabelSelector{ + MatchLabels: map[string]string{ + appKindLabel: vmDiskAppKind, + appNameLabel: dv.ApplicationName, + }, + }) + } + if len(vmRes.DataVolumes) > 0 { + logger.Debug("added VMDisk label selectors to Velero restore", "count", len(vmRes.DataVolumes)) + } + } + + // Create resourceModifiers ConfigMap + resourceModifierCM, err := r.createResourceModifiersConfigMap(ctx, restoreJob, backup, ur, target, opts) + if err != nil { + return fmt.Errorf("failed to create resourceModifiers ConfigMap: %w", err) + } + if resourceModifierCM != nil { + veleroRestoreSpec.ResourceModifier = &corev1.TypedLocalObjectReference{ + APIGroup: stringPtr(""), + Kind: "ConfigMap", + Name: resourceModifierCM.Name, + } + logger.Debug("set resourceModifier on Velero Restore", "configMap", resourceModifierCM.Name) + } + + generateName := fmt.Sprintf("%s.%s-", restoreJob.Namespace, restoreJob.Name) + veleroRestore := &velerov1.Restore{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: generateName, + Namespace: veleroNamespace, + Labels: map[string]string{ + backupsv1alpha1.OwningJobNameLabel: restoreJob.Name, + backupsv1alpha1.OwningJobNamespaceLabel: restoreJob.Namespace, + }, + }, + Spec: veleroRestoreSpec, + } + if err := r.Create(ctx, veleroRestore); err != nil { + logger.Error(err, "failed to create Velero Restore", "generateName", generateName) + r.Recorder.Event(restoreJob, corev1.EventTypeWarning, "VeleroRestoreCreationFailed", + fmt.Sprintf("Failed to create Velero Restore %s/%s: %v", veleroNamespace, generateName, err)) + return err + } + + logger.Debug("created Velero Restore", "name", veleroRestore.Name, "namespace", veleroRestore.Namespace) + r.Recorder.Event(restoreJob, corev1.EventTypeNormal, "VeleroRestoreCreated", + fmt.Sprintf("Created Velero Restore %s/%s", veleroNamespace, veleroRestore.Name)) + return nil +} + +// dataUploadListGVK is the API version shipped with Velero data mover CRDs (see velero datauploads CRD). +var dataUploadListGVK = schema.GroupVersionKind{Group: "velero.io", Version: "v2alpha1", Kind: "DataUploadList"} + +// formatVeleroBackupFailureMessageForBackupJob builds a BackupJob status message from Velero Backup +// status plus failed DataUpload resources (CSI data mover), similar to `velero backup describe`. +func formatVeleroBackupFailureMessageForBackupJob(ctx context.Context, c client.Client, veleroBackup *velerov1.Backup) string { + var b strings.Builder + fmt.Fprintf(&b, "Velero Backup failed with phase %s", veleroBackup.Status.Phase) + if fr := strings.TrimSpace(veleroBackup.Status.FailureReason); fr != "" { + fmt.Fprintf(&b, ": %s", fr) + } + if len(veleroBackup.Status.ValidationErrors) > 0 { + fmt.Fprintf(&b, "; validation: %v", veleroBackup.Status.ValidationErrors) + } + if h := veleroBackup.Status.HookStatus; h != nil && h.HooksFailed > 0 { + fmt.Fprintf(&b, "; hooks failed %d/%d", h.HooksFailed, h.HooksAttempted) + } + if veleroBackup.Status.BackupItemOperationsFailed > 0 { + fmt.Fprintf(&b, "; async item operations failed %d (completed %d, attempted %d)", + veleroBackup.Status.BackupItemOperationsFailed, + veleroBackup.Status.BackupItemOperationsCompleted, + veleroBackup.Status.BackupItemOperationsAttempted) + } + b.WriteString(appendFailedDataUploadMessages(ctx, c, veleroBackup.Name)) + return b.String() +} + +func appendFailedDataUploadMessages(ctx context.Context, c client.Client, veleroBackupName string) string { + ul := unstructured.UnstructuredList{} + ul.SetGroupVersionKind(dataUploadListGVK) + if err := c.List(ctx, &ul, client.InNamespace(veleroNamespace)); err != nil { + return "" + } + prefix := veleroBackupName + "-" + var b strings.Builder + for _, item := range ul.Items { + if !strings.HasPrefix(item.GetName(), prefix) { + continue + } + phase, _, _ := unstructured.NestedString(item.Object, "status", "phase") + if phase != "Failed" { + continue + } + msg, _, _ := unstructured.NestedString(item.Object, "status", "message") + if strings.TrimSpace(msg) == "" { + msg = "(empty status.message)" + } + srcPVC, _, _ := unstructured.NestedString(item.Object, "spec", "sourcePVC") + if srcPVC != "" { + fmt.Fprintf(&b, "; DataUpload %s failed for PVC %s: %s", item.GetName(), srcPVC, msg) + } else { + fmt.Fprintf(&b, "; DataUpload %s failed: %s", item.GetName(), msg) + } + } + return b.String() +} diff --git a/internal/backupcontroller/velerostrategy_controller_test.go b/internal/backupcontroller/velerostrategy_controller_test.go new file mode 100644 index 00000000..7b085dbf --- /dev/null +++ b/internal/backupcontroller/velerostrategy_controller_test.go @@ -0,0 +1,1213 @@ +package backupcontroller + +import ( + "context" + "encoding/json" + "testing" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + dynamicfake "k8s.io/client-go/dynamic/fake" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client" + clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake" + + strategyv1alpha1 "github.com/cozystack/cozystack/api/backups/strategy/v1alpha1" + backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1" + velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" +) + +// mockRESTMapper implements meta.RESTMapper for testing +type mockRESTMapper struct { + mapping *meta.RESTMapping +} + +func (m *mockRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) { + return m.mapping, nil +} + +func (m *mockRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) { + return []*meta.RESTMapping{m.mapping}, nil +} + +func (m *mockRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) { + return m.mapping.GroupVersionKind, nil +} + +func (m *mockRESTMapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) { + return []schema.GroupVersionKind{m.mapping.GroupVersionKind}, nil +} + +func (m *mockRESTMapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) { + return m.mapping.Resource, nil +} + +func (m *mockRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) { + return []schema.GroupVersionResource{m.mapping.Resource}, nil +} + +func (m *mockRESTMapper) ResourceSingularizer(resource string) (singular string, err error) { + return resource, nil +} + +func TestCreateVeleroBackup_TemplateContext(t *testing.T) { + // Setup scheme + testScheme := runtime.NewScheme() + _ = scheme.AddToScheme(testScheme) + _ = backupsv1alpha1.AddToScheme(testScheme) + _ = strategyv1alpha1.AddToScheme(testScheme) + _ = velerov1.AddToScheme(testScheme) + + // Create test application (VirtualMachine-like object) + testApp := &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-vm", + Namespace: "default", + Labels: map[string]string{ + "apps.cozystack.io/application.Kind": "VirtualMachine", + }, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "test-container", + Image: "test-image:latest", + }, + }, + }, + } + + // Create dynamic client with the test application + dynamicClient := dynamicfake.NewSimpleDynamicClient(testScheme, testApp) + + // Create REST mapping + mapping := &meta.RESTMapping{ + Resource: schema.GroupVersionResource{ + Group: "", + Version: "v1", + Resource: "pods", + }, + GroupVersionKind: schema.GroupVersionKind{ + Group: "", + Version: "v1", + Kind: "Pod", + }, + Scope: meta.RESTScopeNamespace, + } + + // Create BackupJob + backupJob := &backupsv1alpha1.BackupJob{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-backup-job", + Namespace: "default", + }, + Spec: backupsv1alpha1.BackupJobSpec{ + ApplicationRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr(""), + Kind: "Pod", + Name: "test-vm", + }, + BackupClassName: "velero", + }, + } + + // Create Velero strategy with template that uses Application and Parameters + veleroStrategy := &strategyv1alpha1.Velero{ + ObjectMeta: metav1.ObjectMeta{ + Name: "velero-strategy", + }, + Spec: strategyv1alpha1.VeleroSpec{ + Template: strategyv1alpha1.VeleroTemplate{ + Spec: velerov1.BackupSpec{ + // Use template variables to verify context is passed correctly + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "{{ .Application.metadata.name }}", + }, + }, + // Use Parameters in template + StorageLocation: "{{ .Parameters.backupStorageLocationName }}", + }, + }, + }, + } + + // Create ResolvedBackupConfig with parameters + resolved := &ResolvedBackupConfig{ + StrategyRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("strategy.backups.cozystack.io"), + Kind: "Velero", + Name: "velero-strategy", + }, + Parameters: map[string]string{ + "backupStorageLocationName": "default-storage", + }, + } + + // Create fake client for controller + fakeClient := clientfake.NewClientBuilder(). + WithScheme(testScheme). + WithObjects(backupJob, veleroStrategy). + Build() + + // Create reconciler with fake event recorder + reconciler := &BackupJobReconciler{ + Client: fakeClient, + Interface: dynamicClient, + RESTMapper: &mockRESTMapper{mapping: mapping}, + Scheme: testScheme, + Recorder: record.NewFakeRecorder(10), + } + + // Create context with logger + ctx := context.Background() + + // Call createVeleroBackup + err := reconciler.createVeleroBackup(ctx, backupJob, veleroStrategy, resolved) + if err != nil { + t.Fatalf("createVeleroBackup() error = %v", err) + } + + // Verify that the template was executed correctly by checking the created Velero Backup + // The template should have replaced {{ .Application.metadata.name }} with "test-vm" + // and {{ .Parameters.backupStorageLocationName }} with "default-storage" + + // Get the created Velero Backup + veleroBackups := &velerov1.BackupList{} + err = fakeClient.List(ctx, veleroBackups, client.InNamespace(veleroNamespace)) + if err != nil { + t.Fatalf("Failed to list Velero Backups: %v", err) + } + + if len(veleroBackups.Items) == 0 { + t.Fatal("Expected Velero Backup to be created, but none found") + } + + veleroBackup := veleroBackups.Items[0] + + // Verify template context was used correctly: + // 1. Application.metadata.name should be replaced with "test-vm" + if veleroBackup.Spec.LabelSelector == nil { + t.Fatal("Expected LabelSelector to be set by template") + } + if appLabel, ok := veleroBackup.Spec.LabelSelector.MatchLabels["app"]; ok { + if appLabel != "test-vm" { + t.Errorf("Template context Application.metadata.name not applied correctly. Expected 'test-vm', got '%s'", appLabel) + } + } else { + t.Error("Template context Application.metadata.name not found in label selector") + } + + // 2. Parameters.backupStorageLocationName should be replaced with "default-storage" + if veleroBackup.Spec.StorageLocation != "default-storage" { + t.Errorf("Template context Parameters.backupStorageLocationName not applied correctly. Expected 'default-storage', got '%s'", veleroBackup.Spec.StorageLocation) + } +} + +func TestResolveRestoreTarget_NoTargetNamespace_InPlace(t *testing.T) { + restoreJob := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{ + Name: "restore-test", + Namespace: "tenant-root", + }, + Spec: backupsv1alpha1.RestoreJobSpec{ + BackupRef: corev1.LocalObjectReference{Name: "my-backup"}, + TargetApplicationRef: &corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: "VMInstance", + Name: "test-vm", + }, + }, + } + + backup := &backupsv1alpha1.Backup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-backup", + Namespace: "tenant-root", + }, + Spec: backupsv1alpha1.BackupSpec{ + ApplicationRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: "VMInstance", + Name: "test-vm", + }, + }, + } + + // No targetNamespace in options → in-place restore + opts := RestoreOptions{} + target := resolveRestoreTarget(restoreJob, backup, opts) + + if target.IsCopy { + t.Error("expected IsCopy=false when targetNamespace is omitted, got true") + } + if target.Namespace != "tenant-root" { + t.Errorf("expected namespace 'tenant-root', got '%s'", target.Namespace) + } + if target.AppName != "test-vm" { + t.Errorf("expected appName 'test-vm', got '%s'", target.AppName) + } + if target.AppKind != "VMInstance" { + t.Errorf("expected appKind 'VMInstance', got '%s'", target.AppKind) + } +} + +func TestResolveRestoreTarget_SameTargetNamespace_InPlace(t *testing.T) { + restoreJob := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{ + Name: "restore-test", + Namespace: "tenant-root", + }, + Spec: backupsv1alpha1.RestoreJobSpec{ + BackupRef: corev1.LocalObjectReference{Name: "my-backup"}, + }, + } + + backup := &backupsv1alpha1.Backup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-backup", + Namespace: "tenant-root", + }, + Spec: backupsv1alpha1.BackupSpec{ + ApplicationRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: "VMInstance", + Name: "test-vm", + }, + }, + } + + // targetNamespace equals backup namespace → still in-place + opts := RestoreOptions{ + CommonRestoreOptions: CommonRestoreOptions{ + TargetNamespace: "tenant-root", + }, + } + target := resolveRestoreTarget(restoreJob, backup, opts) + + if target.IsCopy { + t.Error("expected IsCopy=false when targetNamespace equals backup namespace, got true") + } + if target.Namespace != "tenant-root" { + t.Errorf("expected namespace 'tenant-root', got '%s'", target.Namespace) + } +} + +func TestResolveRestoreTarget_DifferentTargetNamespace_Copy(t *testing.T) { + restoreJob := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{ + Name: "restore-test", + Namespace: "tenant-root", + }, + Spec: backupsv1alpha1.RestoreJobSpec{ + BackupRef: corev1.LocalObjectReference{Name: "my-backup"}, + }, + } + + backup := &backupsv1alpha1.Backup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-backup", + Namespace: "tenant-root", + }, + Spec: backupsv1alpha1.BackupSpec{ + ApplicationRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: "VMInstance", + Name: "test-vm", + }, + }, + } + + opts := RestoreOptions{ + CommonRestoreOptions: CommonRestoreOptions{ + TargetNamespace: "tenant-copy", + }, + } + target := resolveRestoreTarget(restoreJob, backup, opts) + + if !target.IsCopy { + t.Error("expected IsCopy=true when targetNamespace differs from backup namespace, got false") + } + if target.Namespace != "tenant-copy" { + t.Errorf("expected namespace 'tenant-copy', got '%s'", target.Namespace) + } +} + +// newTestRestoreJobReconcilerWithDynamic builds a RestoreJobReconciler with +// both static and dynamic fake clients. Use dynamicObjects to pre-populate +// unstructured resources (e.g. HelmReleases). +func newTestRestoreJobReconcilerWithDynamic(t *testing.T, dynamicObjects []runtime.Object, objects ...client.Object) *RestoreJobReconciler { + t.Helper() + testScheme := runtime.NewScheme() + _ = scheme.AddToScheme(testScheme) + _ = backupsv1alpha1.AddToScheme(testScheme) + _ = velerov1.AddToScheme(testScheme) + + fakeClient := clientfake.NewClientBuilder(). + WithScheme(testScheme). + WithObjects(objects...). + Build() + + dynamicClient := dynamicfake.NewSimpleDynamicClient(testScheme, dynamicObjects...) + + mapping := &meta.RESTMapping{ + Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}, + GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}, + Scope: meta.RESTScopeNamespace, + } + + return &RestoreJobReconciler{ + Client: fakeClient, + Interface: dynamicClient, + RESTMapper: &mockRESTMapper{mapping: mapping}, + Scheme: testScheme, + Recorder: record.NewFakeRecorder(100), + } +} + +// newTestRestoreJobReconciler builds a RestoreJobReconciler with fake clients for testing. +func newTestRestoreJobReconciler(t *testing.T, objects ...client.Object) *RestoreJobReconciler { + t.Helper() + testScheme := runtime.NewScheme() + _ = scheme.AddToScheme(testScheme) + _ = backupsv1alpha1.AddToScheme(testScheme) + _ = velerov1.AddToScheme(testScheme) + + fakeClient := clientfake.NewClientBuilder(). + WithScheme(testScheme). + WithObjects(objects...). + Build() + + dynamicClient := dynamicfake.NewSimpleDynamicClient(testScheme) + + mapping := &meta.RESTMapping{ + Resource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}, + GroupVersionKind: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}, + Scope: meta.RESTScopeNamespace, + } + + return &RestoreJobReconciler{ + Client: fakeClient, + Interface: dynamicClient, + RESTMapper: &mockRESTMapper{mapping: mapping}, + Scheme: testScheme, + Recorder: record.NewFakeRecorder(100), + } +} + +func TestPrepareForRestore_KeepOriginalPVCFalse_SkipsRename(t *testing.T) { + ns := "tenant-root" + + // Create a PVC that would be renamed if keepOriginalPVC were true + pvc := &corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "vm-disk-ubuntu-source", + Namespace: ns, + }, + Spec: corev1.PersistentVolumeClaimSpec{}, + } + + restoreJob := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{ + Name: "restore-test", + Namespace: ns, + }, + Spec: backupsv1alpha1.RestoreJobSpec{ + BackupRef: corev1.LocalObjectReference{Name: "my-backup"}, + }, + } + + backup := &backupsv1alpha1.Backup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-backup", + Namespace: ns, + }, + Spec: backupsv1alpha1.BackupSpec{ + ApplicationRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: "VMInstance", + Name: "test-vm", + }, + }, + } + + // underlyingResources with a DataVolume referencing the PVC + urData := vmInstanceResources{ + DataVolumes: []backupsv1alpha1.DataVolumeResource{ + {DataVolumeName: "vm-disk-ubuntu-source", ApplicationName: "ubuntu-source"}, + }, + } + urRaw, _ := json.Marshal(urData) + ur := &runtime.RawExtension{Raw: urRaw} + + target := restoreTarget{ + Namespace: ns, + AppName: "test-vm", + AppKind: "VMInstance", + IsCopy: false, + } + + // keepOriginalPVC = false → PVCs should NOT be renamed + opts := RestoreOptions{ + KeepOriginalPVC: boolPtr(false), + } + + reconciler := newTestRestoreJobReconciler(t, pvc, restoreJob, backup) + + ctx := context.Background() + ready, _, err := reconciler.prepareForRestore(ctx, restoreJob, backup, ur, target, opts) + if err != nil { + t.Fatalf("prepareForRestore() error = %v", err) + } + if !ready { + t.Fatal("expected ready=true, got false") + } + + // Verify the original PVC still exists with its original name (not renamed) + origPVC := &corev1.PersistentVolumeClaim{} + err = reconciler.Get(ctx, client.ObjectKey{Namespace: ns, Name: "vm-disk-ubuntu-source"}, origPVC) + if err != nil { + t.Errorf("original PVC should still exist with original name when keepOriginalPVC=false, got error: %v", err) + } + + // Verify no -orig PVC was created + origSuffix := "-orig-" + shortHash(restoreJob.Name) + renamedPVC := &corev1.PersistentVolumeClaim{} + err = reconciler.Get(ctx, client.ObjectKey{Namespace: ns, Name: "vm-disk-ubuntu-source" + origSuffix}, renamedPVC) + if err == nil { + t.Error("PVC should NOT have been renamed when keepOriginalPVC=false, but found renamed PVC") + } +} + +func TestResolveRestoreTarget_VMDisk_CommonRestoreOptions(t *testing.T) { + tests := []struct { + name string + targetNS string + wantIsCopy bool + wantNamespace string + }{ + { + name: "VMDisk in-place restore when targetNamespace is omitted", + targetNS: "", + wantIsCopy: false, + wantNamespace: "tenant-root", + }, + { + name: "VMDisk cross-namespace restore when targetNamespace differs", + targetNS: "tenant-copy", + wantIsCopy: true, + wantNamespace: "tenant-copy", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + restoreJob := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{ + Name: "restore-vmdisk", + Namespace: "tenant-root", + }, + Spec: backupsv1alpha1.RestoreJobSpec{ + BackupRef: corev1.LocalObjectReference{Name: "disk-backup"}, + TargetApplicationRef: &corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: "VMDisk", + Name: "ubuntu-source", + }, + }, + } + + backup := &backupsv1alpha1.Backup{ + ObjectMeta: metav1.ObjectMeta{ + Name: "disk-backup", + Namespace: "tenant-root", + }, + Spec: backupsv1alpha1.BackupSpec{ + ApplicationRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: "VMDisk", + Name: "ubuntu-source", + }, + }, + } + + // VMDisk uses only CommonRestoreOptions (no VMI-specific fields) + opts := RestoreOptions{ + CommonRestoreOptions: CommonRestoreOptions{ + TargetNamespace: tt.targetNS, + }, + } + + target := resolveRestoreTarget(restoreJob, backup, opts) + + if target.IsCopy != tt.wantIsCopy { + t.Errorf("IsCopy = %v, want %v", target.IsCopy, tt.wantIsCopy) + } + if target.Namespace != tt.wantNamespace { + t.Errorf("Namespace = %q, want %q", target.Namespace, tt.wantNamespace) + } + if target.AppKind != "VMDisk" { + t.Errorf("AppKind = %q, want 'VMDisk'", target.AppKind) + } + if target.AppName != "ubuntu-source" { + t.Errorf("AppName = %q, want 'ubuntu-source'", target.AppName) + } + }) + } +} + +func TestParseRestoreOptions_VMDiskOnlyCommonFields(t *testing.T) { + // Simulate a VMDisk restore where only CommonRestoreOptions fields are set + raw, _ := json.Marshal(map[string]interface{}{ + "targetNamespace": "tenant-copy", + "failIfTargetExists": true, + }) + ext := &runtime.RawExtension{Raw: raw} + + opts, err := parseRestoreOptions(ext) + if err != nil { + t.Fatalf("parseRestoreOptions() error = %v", err) + } + + if opts.TargetNamespace != "tenant-copy" { + t.Errorf("TargetNamespace = %q, want 'tenant-copy'", opts.TargetNamespace) + } + if !opts.GetFailIfTargetExists() { + t.Error("GetFailIfTargetExists() = false, want true") + } + // VMI-specific fields should be nil (not set by VMDisk options) + if opts.KeepOriginalPVC != nil { + t.Errorf("KeepOriginalPVC should be nil for VMDisk options, got %v", *opts.KeepOriginalPVC) + } + if opts.KeepOriginalIpAndMac != nil { + t.Errorf("KeepOriginalIpAndMac should be nil for VMDisk options, got %v", *opts.KeepOriginalIpAndMac) + } +} + +func TestRestoreOptions_Defaults(t *testing.T) { + t.Run("nil options default all bools to true", func(t *testing.T) { + opts, err := parseRestoreOptions(nil) + if err != nil { + t.Fatalf("parseRestoreOptions(nil) error = %v", err) + } + + if opts.TargetNamespace != "" { + t.Errorf("TargetNamespace default should be empty, got %q", opts.TargetNamespace) + } + if !opts.GetFailIfTargetExists() { + t.Error("GetFailIfTargetExists() should default to true") + } + if !opts.GetKeepOriginalPVC() { + t.Error("GetKeepOriginalPVC() should default to true") + } + if !opts.GetKeepOriginalIpAndMac() { + t.Error("GetKeepOriginalIpAndMac() should default to true") + } + }) + + t.Run("empty JSON defaults all bools to true", func(t *testing.T) { + raw, _ := json.Marshal(map[string]interface{}{}) + opts, err := parseRestoreOptions(&runtime.RawExtension{Raw: raw}) + if err != nil { + t.Fatalf("parseRestoreOptions({}) error = %v", err) + } + + if !opts.GetFailIfTargetExists() { + t.Error("GetFailIfTargetExists() should default to true") + } + if !opts.GetKeepOriginalPVC() { + t.Error("GetKeepOriginalPVC() should default to true") + } + if !opts.GetKeepOriginalIpAndMac() { + t.Error("GetKeepOriginalIpAndMac() should default to true") + } + }) + + t.Run("explicit false overrides defaults", func(t *testing.T) { + raw, _ := json.Marshal(map[string]interface{}{ + "failIfTargetExists": false, + "keepOriginalPVC": false, + "keepOriginalIpAndMac": false, + }) + opts, err := parseRestoreOptions(&runtime.RawExtension{Raw: raw}) + if err != nil { + t.Fatalf("parseRestoreOptions() error = %v", err) + } + + if opts.GetFailIfTargetExists() { + t.Error("GetFailIfTargetExists() should be false when explicitly set") + } + if opts.GetKeepOriginalPVC() { + t.Error("GetKeepOriginalPVC() should be false when explicitly set") + } + if opts.GetKeepOriginalIpAndMac() { + t.Error("GetKeepOriginalIpAndMac() should be false when explicitly set") + } + }) +} + +func TestResolveRestoreTarget_IsRenamed(t *testing.T) { + backup := &backupsv1alpha1.Backup{ + ObjectMeta: metav1.ObjectMeta{Name: "bk", Namespace: "tenant-root"}, + Spec: backupsv1alpha1.BackupSpec{ + ApplicationRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: "VMInstance", + Name: "test-alpine", + }, + }, + } + + t.Run("same name is not renamed", func(t *testing.T) { + rj := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{Name: "rj", Namespace: "tenant-root"}, + Spec: backupsv1alpha1.RestoreJobSpec{ + BackupRef: corev1.LocalObjectReference{Name: "bk"}, + TargetApplicationRef: &corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: "VMInstance", + Name: "test-alpine", + }, + }, + } + target := resolveRestoreTarget(rj, backup, RestoreOptions{ + CommonRestoreOptions: CommonRestoreOptions{TargetNamespace: "tenant-foo"}, + }) + if target.IsRenamed { + t.Error("IsRenamed should be false when names match") + } + }) + + t.Run("different name is renamed", func(t *testing.T) { + rj := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{Name: "rj", Namespace: "tenant-root"}, + Spec: backupsv1alpha1.RestoreJobSpec{ + BackupRef: corev1.LocalObjectReference{Name: "bk"}, + TargetApplicationRef: &corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: "VMInstance", + Name: "test-new", + }, + }, + } + target := resolveRestoreTarget(rj, backup, RestoreOptions{ + CommonRestoreOptions: CommonRestoreOptions{TargetNamespace: "tenant-foo"}, + }) + if !target.IsRenamed { + t.Error("IsRenamed should be true when names differ") + } + if target.AppName != "test-new" { + t.Errorf("AppName = %q, want 'test-new'", target.AppName) + } + if !target.IsCopy { + t.Error("IsCopy should be true") + } + }) + + t.Run("no targetApplicationRef is not renamed", func(t *testing.T) { + rj := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{Name: "rj", Namespace: "tenant-root"}, + Spec: backupsv1alpha1.RestoreJobSpec{ + BackupRef: corev1.LocalObjectReference{Name: "bk"}, + }, + } + target := resolveRestoreTarget(rj, backup, RestoreOptions{ + CommonRestoreOptions: CommonRestoreOptions{TargetNamespace: "tenant-foo"}, + }) + if target.IsRenamed { + t.Error("IsRenamed should be false when targetApplicationRef is nil") + } + if target.AppName != "test-alpine" { + t.Errorf("AppName = %q, want 'test-alpine'", target.AppName) + } + }) +} + +// makeUnstructuredHelmRelease creates an unstructured HelmRelease for dynamic client tests. +func makeUnstructuredHelmRelease(name, namespace string, labels map[string]string) *unstructured.Unstructured { + hr := &unstructured.Unstructured{} + hr.SetAPIVersion("helm.toolkit.fluxcd.io/v2") + hr.SetKind("HelmRelease") + hr.SetName(name) + hr.SetNamespace(namespace) + hr.SetLabels(labels) + return hr +} + +func TestPostRestoreRename_RenamesHelmRelease(t *testing.T) { + ns := "tenant-foo" + sourceHR := makeUnstructuredHelmRelease("vm-instance-test-alpine", ns, map[string]string{ + appNameLabel: "test-alpine", + "app.kubernetes.io/instance": "vm-instance-test-alpine", + "helm.toolkit.fluxcd.io/name": "vm-instance-test-alpine", + }) + + restoreJob := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{Name: "rj-rename", Namespace: "tenant-root"}, + Spec: backupsv1alpha1.RestoreJobSpec{ + BackupRef: corev1.LocalObjectReference{Name: "bk"}, + }, + } + backup := &backupsv1alpha1.Backup{ + ObjectMeta: metav1.ObjectMeta{Name: "bk", Namespace: "tenant-root"}, + Spec: backupsv1alpha1.BackupSpec{ + ApplicationRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: "VMInstance", + Name: "test-alpine", + }, + }, + } + target := restoreTarget{ + Namespace: ns, + AppName: "test-new", + AppKind: "VMInstance", + IsCopy: true, + IsRenamed: true, + } + + reconciler := newTestRestoreJobReconcilerWithDynamic(t, []runtime.Object{sourceHR}, restoreJob, backup) + ctx := context.Background() + + err := reconciler.postRestoreRename(ctx, restoreJob, backup, target) + if err != nil { + t.Fatalf("postRestoreRename() error = %v", err) + } + + hrClient := reconciler.Resource(helmReleaseGVR).Namespace(ns) + + // New HelmRelease should exist with target name + newHR, err := hrClient.Get(ctx, "vm-instance-test-new", metav1.GetOptions{}) + if err != nil { + t.Fatalf("new HelmRelease vm-instance-test-new not found: %v", err) + } + + // Check labels were updated + labels := newHR.GetLabels() + if labels[appNameLabel] != "test-new" { + t.Errorf("label %s = %q, want 'test-new'", appNameLabel, labels[appNameLabel]) + } + if labels["app.kubernetes.io/instance"] != "vm-instance-test-new" { + t.Errorf("label app.kubernetes.io/instance = %q, want 'vm-instance-test-new'", labels["app.kubernetes.io/instance"]) + } + if labels["helm.toolkit.fluxcd.io/name"] != "vm-instance-test-new" { + t.Errorf("label helm.toolkit.fluxcd.io/name = %q, want 'vm-instance-test-new'", labels["helm.toolkit.fluxcd.io/name"]) + } + + // Old HelmRelease should be deleted + _, err = hrClient.Get(ctx, "vm-instance-test-alpine", metav1.GetOptions{}) + if err == nil { + t.Error("old HelmRelease vm-instance-test-alpine should have been deleted") + } +} + +func TestPostRestoreRename_SkipsWhenSourceNotFound(t *testing.T) { + restoreJob := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{Name: "rj-rename", Namespace: "tenant-root"}, + Spec: backupsv1alpha1.RestoreJobSpec{ + BackupRef: corev1.LocalObjectReference{Name: "bk"}, + }, + } + backup := &backupsv1alpha1.Backup{ + ObjectMeta: metav1.ObjectMeta{Name: "bk", Namespace: "tenant-root"}, + Spec: backupsv1alpha1.BackupSpec{ + ApplicationRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: "VMInstance", + Name: "test-alpine", + }, + }, + } + target := restoreTarget{ + Namespace: "tenant-foo", + AppName: "test-new", + AppKind: "VMInstance", + IsCopy: true, + IsRenamed: true, + } + + // No HelmRelease in dynamic client — should skip gracefully + reconciler := newTestRestoreJobReconcilerWithDynamic(t, nil, restoreJob, backup) + ctx := context.Background() + + err := reconciler.postRestoreRename(ctx, restoreJob, backup, target) + if err != nil { + t.Fatalf("postRestoreRename() should skip gracefully when source HR not found, got error: %v", err) + } +} + +func TestPostRestoreRename_IdempotentWhenTargetExists(t *testing.T) { + ns := "tenant-foo" + sourceHR := makeUnstructuredHelmRelease("vm-instance-test-alpine", ns, map[string]string{ + appNameLabel: "test-alpine", + }) + // Target already exists (e.g. from a previous reconcile) + targetHR := makeUnstructuredHelmRelease("vm-instance-test-new", ns, map[string]string{ + appNameLabel: "test-new", + }) + + restoreJob := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{Name: "rj-rename", Namespace: "tenant-root"}, + Spec: backupsv1alpha1.RestoreJobSpec{ + BackupRef: corev1.LocalObjectReference{Name: "bk"}, + }, + } + backup := &backupsv1alpha1.Backup{ + ObjectMeta: metav1.ObjectMeta{Name: "bk", Namespace: "tenant-root"}, + Spec: backupsv1alpha1.BackupSpec{ + ApplicationRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: "VMInstance", + Name: "test-alpine", + }, + }, + } + target := restoreTarget{ + Namespace: ns, + AppName: "test-new", + AppKind: "VMInstance", + IsCopy: true, + IsRenamed: true, + } + + reconciler := newTestRestoreJobReconcilerWithDynamic(t, []runtime.Object{sourceHR, targetHR}, restoreJob, backup) + ctx := context.Background() + + err := reconciler.postRestoreRename(ctx, restoreJob, backup, target) + if err != nil { + t.Fatalf("postRestoreRename() should be idempotent, got error: %v", err) + } + + hrClient := reconciler.Resource(helmReleaseGVR).Namespace(ns) + + // Target should still exist + _, err = hrClient.Get(ctx, "vm-instance-test-new", metav1.GetOptions{}) + if err != nil { + t.Fatalf("target HelmRelease should exist: %v", err) + } + + // Source should be deleted + _, err = hrClient.Get(ctx, "vm-instance-test-alpine", metav1.GetOptions{}) + if err == nil { + t.Error("source HelmRelease should have been deleted") + } +} + +// --- failIfTargetExists enforcement tests --- + +func TestTargetHelmReleaseExists_ReturnsTrueWhenPresent(t *testing.T) { + ns := "tenant-copy" + hr := makeUnstructuredHelmRelease("vm-instance-test", ns, nil) + + restoreJob := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{Name: "rj", Namespace: "tenant-root"}, + } + backup := &backupsv1alpha1.Backup{ObjectMeta: metav1.ObjectMeta{Name: "bk", Namespace: "tenant-root"}} + + reconciler := newTestRestoreJobReconcilerWithDynamic(t, []runtime.Object{hr}, restoreJob, backup) + ctx := context.Background() + + exists, err := reconciler.targetHelmReleaseExists(ctx, vmInstanceKind, "vm-instance-test", ns) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !exists { + t.Error("expected exists=true when HelmRelease is present") + } +} + +func TestTargetHelmReleaseExists_ReturnsFalseWhenAbsent(t *testing.T) { + ns := "tenant-copy" + restoreJob := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{Name: "rj", Namespace: "tenant-root"}, + } + backup := &backupsv1alpha1.Backup{ObjectMeta: metav1.ObjectMeta{Name: "bk", Namespace: "tenant-root"}} + + reconciler := newTestRestoreJobReconcilerWithDynamic(t, nil, restoreJob, backup) + ctx := context.Background() + + exists, err := reconciler.targetHelmReleaseExists(ctx, vmInstanceKind, "vm-instance-test", ns) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if exists { + t.Error("expected exists=false when HelmRelease is absent") + } +} + +func TestTargetHelmReleaseExists_UnsupportedKindViaHelper(t *testing.T) { + ns := "tenant-copy" + // Even though a HR exists, unsupported kinds produce an empty hrName + // from helmReleaseNameForApp, which makes targetHelmReleaseExists return false. + hr := makeUnstructuredHelmRelease("vm-instance-test", ns, nil) + + restoreJob := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{Name: "rj", Namespace: "tenant-root"}, + } + backup := &backupsv1alpha1.Backup{ObjectMeta: metav1.ObjectMeta{Name: "bk", Namespace: "tenant-root"}} + + reconciler := newTestRestoreJobReconcilerWithDynamic(t, []runtime.Object{hr}, restoreJob, backup) + ctx := context.Background() + + // Unsupported kinds get empty hrName from the helper + hrName := helmReleaseNameForApp("MariaDB", "mydb") + exists, err := reconciler.targetHelmReleaseExists(ctx, "MariaDB", hrName, ns) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if exists { + t.Error("expected exists=false for unsupported kind (empty hrName)") + } +} + +// --- createResourceModifiersConfigMap tests --- + +func makeTestBackup(ns, appName, appKind string) *backupsv1alpha1.Backup { + return &backupsv1alpha1.Backup{ + ObjectMeta: metav1.ObjectMeta{Name: "bk", Namespace: ns}, + Spec: backupsv1alpha1.BackupSpec{ + ApplicationRef: corev1.TypedLocalObjectReference{ + APIGroup: stringPtr("apps.cozystack.io"), + Kind: appKind, + Name: appName, + }, + }, + } +} + +func makeTestRestoreJob(ns, name string) *backupsv1alpha1.RestoreJob { + return &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: ns}, + Spec: backupsv1alpha1.RestoreJobSpec{ + BackupRef: corev1.LocalObjectReference{Name: "bk"}, + }, + } +} + +func makeVMInstanceUR(ip, mac string, dvs []backupsv1alpha1.DataVolumeResource) *runtime.RawExtension { + data := vmInstanceResources{IP: ip, MAC: mac, DataVolumes: dvs} + raw, _ := json.Marshal(data) + return &runtime.RawExtension{Raw: raw} +} + +func TestCreateResourceModifiersConfigMap_InPlace_WithOVN(t *testing.T) { + ns := "tenant-root" + restoreJob := makeTestRestoreJob(ns, "rj-inplace") + backup := makeTestBackup(ns, "test-vm", "VMInstance") + + ur := makeVMInstanceUR("10.0.0.5", "aa:bb:cc:dd:ee:ff", nil) + target := restoreTarget{Namespace: ns, AppName: "test-vm", AppKind: "VMInstance", IsCopy: false} + opts := RestoreOptions{} // defaults: keepOriginalIpAndMac=true + + reconciler := newTestRestoreJobReconciler(t, restoreJob, backup) + ctx := context.Background() + + cm, err := reconciler.createResourceModifiersConfigMap(ctx, restoreJob, backup, ur, target, opts) + if err != nil { + t.Fatalf("createResourceModifiersConfigMap() error = %v", err) + } + if cm == nil { + t.Fatal("expected non-nil ConfigMap") + } + + rulesYAML, ok := cm.Data["resource-modifier-rules.yaml"] + if !ok { + t.Fatal("ConfigMap missing resource-modifier-rules.yaml key") + } + + // Should contain PVC adoption annotation + if !containsString(rulesYAML, cdiAllowClaimAdoption) { + t.Error("expected PVC adoption annotation in rules") + } + // Should contain OVN IP annotation (keepOriginalIpAndMac defaults to true) + if !containsString(rulesYAML, ovnIPAnnotation) { + t.Error("expected OVN IP annotation in rules for in-place restore with IP") + } + // Should NOT contain selector removal (in-place, not copy) + if containsString(rulesYAML, "/spec/selector") { + t.Error("selector removal rule should not be present for in-place restore") + } +} + +func TestCreateResourceModifiersConfigMap_Copy_NoOVN(t *testing.T) { + sourceNS := "tenant-root" + targetNS := "tenant-copy" + restoreJob := makeTestRestoreJob(sourceNS, "rj-copy") + backup := makeTestBackup(sourceNS, "test-vm", "VMInstance") + + // Copy restore: keepOriginalIpAndMac=false, no OVN annotations on copy + opts := RestoreOptions{ + KeepOriginalIpAndMac: boolPtr(false), + } + ur := makeVMInstanceUR("10.0.0.5", "aa:bb:cc:dd:ee:ff", nil) + target := restoreTarget{Namespace: targetNS, AppName: "test-vm", AppKind: "VMInstance", IsCopy: true} + + reconciler := newTestRestoreJobReconciler(t, restoreJob, backup) + ctx := context.Background() + + cm, err := reconciler.createResourceModifiersConfigMap(ctx, restoreJob, backup, ur, target, opts) + if err != nil { + t.Fatalf("createResourceModifiersConfigMap() error = %v", err) + } + + rulesYAML := cm.Data["resource-modifier-rules.yaml"] + + // Should contain PVC adoption annotation + if !containsString(rulesYAML, cdiAllowClaimAdoption) { + t.Error("expected PVC adoption annotation in rules") + } + // Should contain merge patch nulling out selector and volumeName (copy restore) + if !containsString(rulesYAML, "selector: null") { + t.Error("expected selector: null merge patch for copy restore") + } + if !containsString(rulesYAML, "volumeName: null") { + t.Error("expected volumeName: null merge patch for copy restore") + } + // Should NOT contain OVN annotations (keepOriginalIpAndMac=false) + if containsString(rulesYAML, ovnIPAnnotation) { + t.Error("OVN IP annotation should not be present when keepOriginalIpAndMac=false") + } +} + +func TestCreateResourceModifiersConfigMap_AlreadyExists_IsIdempotent(t *testing.T) { + ns := "tenant-root" + restoreJob := makeTestRestoreJob(ns, "rj-idem") + backup := makeTestBackup(ns, "test-vm", "VMInstance") + + target := restoreTarget{Namespace: ns, AppName: "test-vm", AppKind: "VMInstance", IsCopy: false} + opts := RestoreOptions{} + ur := makeVMInstanceUR("", "", nil) + + reconciler := newTestRestoreJobReconciler(t, restoreJob, backup) + ctx := context.Background() + + // First call creates the ConfigMap. + cm1, err := reconciler.createResourceModifiersConfigMap(ctx, restoreJob, backup, ur, target, opts) + if err != nil { + t.Fatalf("first call error = %v", err) + } + + // Second call must not error (AlreadyExists → update path). + cm2, err := reconciler.createResourceModifiersConfigMap(ctx, restoreJob, backup, ur, target, opts) + if err != nil { + t.Fatalf("second call error = %v", err) + } + if cm1.Name != cm2.Name { + t.Errorf("ConfigMap name changed: %q → %q", cm1.Name, cm2.Name) + } +} + +// --- helmReleaseNameForApp tests --- + +func TestHelmReleaseNameForApp(t *testing.T) { + tests := []struct { + kind, name, want string + }{ + {vmInstanceKind, "test-alpine", "vm-instance-test-alpine"}, + {vmDiskAppKind, "ubuntu-source", "vm-disk-ubuntu-source"}, + {"MariaDB", "mydb", ""}, + } + for _, tt := range tests { + t.Run(tt.kind+"/"+tt.name, func(t *testing.T) { + got := helmReleaseNameForApp(tt.kind, tt.name) + if got != tt.want { + t.Errorf("helmReleaseNameForApp(%q, %q) = %q, want %q", tt.kind, tt.name, got, tt.want) + } + }) + } +} + +func TestTargetHelmReleaseExists_VMDisk(t *testing.T) { + ns := "tenant-copy" + hr := makeUnstructuredHelmRelease("vm-disk-ubuntu-source", ns, nil) + + restoreJob := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{Name: "rj", Namespace: "tenant-root"}, + } + backup := &backupsv1alpha1.Backup{ObjectMeta: metav1.ObjectMeta{Name: "bk", Namespace: "tenant-root"}} + + reconciler := newTestRestoreJobReconcilerWithDynamic(t, []runtime.Object{hr}, restoreJob, backup) + ctx := context.Background() + + hrName := helmReleaseNameForApp(vmDiskAppKind, "ubuntu-source") + exists, err := reconciler.targetHelmReleaseExists(ctx, vmDiskAppKind, hrName, ns) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !exists { + t.Error("expected exists=true for VMDisk HelmRelease") + } +} + +func TestTargetHelmReleaseExists_UnsupportedKind_ReturnsFalse(t *testing.T) { + restoreJob := &backupsv1alpha1.RestoreJob{ + ObjectMeta: metav1.ObjectMeta{Name: "rj", Namespace: "tenant-root"}, + } + backup := &backupsv1alpha1.Backup{ObjectMeta: metav1.ObjectMeta{Name: "bk", Namespace: "tenant-root"}} + + reconciler := newTestRestoreJobReconcilerWithDynamic(t, nil, restoreJob, backup) + ctx := context.Background() + + // Unsupported kinds produce empty hrName which returns false + hrName := helmReleaseNameForApp("MariaDB", "mydb") + exists, err := reconciler.targetHelmReleaseExists(ctx, "MariaDB", hrName, "tenant-copy") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if exists { + t.Error("expected exists=false for unsupported kind") + } +} + +// --- ResourceModifier merge patch test for copy restore --- + +func TestCreateResourceModifiersConfigMap_Copy_UsesMergePatchForPVC(t *testing.T) { + sourceNS := "tenant-root" + targetNS := "tenant-copy" + restoreJob := makeTestRestoreJob(sourceNS, "rj-copy-merge") + backup := makeTestBackup(sourceNS, "test-vm", "VMInstance") + + opts := RestoreOptions{KeepOriginalIpAndMac: boolPtr(false)} + ur := makeVMInstanceUR("", "", nil) + target := restoreTarget{Namespace: targetNS, AppName: "test-vm", AppKind: "VMInstance", IsCopy: true} + + reconciler := newTestRestoreJobReconciler(t, restoreJob, backup) + ctx := context.Background() + + cm, err := reconciler.createResourceModifiersConfigMap(ctx, restoreJob, backup, ur, target, opts) + if err != nil { + t.Fatalf("createResourceModifiersConfigMap() error = %v", err) + } + + rulesYAML := cm.Data["resource-modifier-rules.yaml"] + + // Should use merge patch (patchData with null), NOT JSON patch (operation: remove) + if containsString(rulesYAML, "operation: remove") { + t.Error("should use merge patch instead of JSON Patch remove for PVC fields") + } + // The merge patch should null out selector and volumeName + if !containsString(rulesYAML, "selector: null") { + t.Error("expected selector: null in merge patch") + } + if !containsString(rulesYAML, "volumeName: null") { + t.Error("expected volumeName: null in merge patch") + } +} + +// containsString reports whether substr appears in s. +func containsString(s, substr string) bool { + if len(substr) == 0 || len(s) < len(substr) { + return false + } + for i := 0; i <= len(s)-len(substr); i++ { + if s[i:i+len(substr)] == substr { + return true + } + } + return false +} diff --git a/internal/controller/applicationdefinition_controller.go b/internal/controller/applicationdefinition_controller.go new file mode 100644 index 00000000..6ce25249 --- /dev/null +++ b/internal/controller/applicationdefinition_controller.go @@ -0,0 +1,177 @@ +package controller + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "slices" + "sync" + "time" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +type ApplicationDefinitionReconciler struct { + client.Client + Scheme *runtime.Scheme + + Debounce time.Duration + + mu sync.Mutex + lastEvent time.Time + lastHandled time.Time +} + +func (r *ApplicationDefinitionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + // Only handle debounced restart logic + // HelmRelease reconciliation is handled by ApplicationDefinitionHelmReconciler + return r.debouncedRestart(ctx) +} + +func (r *ApplicationDefinitionReconciler) SetupWithManager(mgr ctrl.Manager) error { + if r.Debounce == 0 { + r.Debounce = 5 * time.Second + } + + return ctrl.NewControllerManagedBy(mgr). + Named("applicationdefinition-controller"). + Watches( + &cozyv1alpha1.ApplicationDefinition{}, + handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request { + r.mu.Lock() + r.lastEvent = time.Now() + r.mu.Unlock() + return []reconcile.Request{{ + NamespacedName: types.NamespacedName{ + Namespace: "cozy-system", + Name: "cozystack-api", + }, + }} + }), + ). + Complete(r) +} + +type appDefHashView struct { + Name string `json:"name"` + Spec cozyv1alpha1.ApplicationDefinitionSpec `json:"spec"` +} + +func (r *ApplicationDefinitionReconciler) computeConfigHash(ctx context.Context) (string, error) { + list := &cozyv1alpha1.ApplicationDefinitionList{} + if err := r.List(ctx, list); err != nil { + return "", err + } + + slices.SortFunc(list.Items, sortAppDefs) + + views := make([]appDefHashView, 0, len(list.Items)) + for i := range list.Items { + views = append(views, appDefHashView{ + Name: list.Items[i].Name, + Spec: list.Items[i].Spec, + }) + } + b, err := json.Marshal(views) + if err != nil { + return "", err + } + sum := sha256.Sum256(b) + return hex.EncodeToString(sum[:]), nil +} + +func (r *ApplicationDefinitionReconciler) debouncedRestart(ctx context.Context) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + r.mu.Lock() + le := r.lastEvent + lh := r.lastHandled + debounce := r.Debounce + r.mu.Unlock() + + if debounce <= 0 { + debounce = 5 * time.Second + } + if le.IsZero() { + return ctrl.Result{}, nil + } + if d := time.Since(le); d < debounce { + return ctrl.Result{RequeueAfter: debounce - d}, nil + } + if !lh.Before(le) { + return ctrl.Result{}, nil + } + + newHash, err := r.computeConfigHash(ctx) + if err != nil { + return ctrl.Result{}, err + } + + tpl, obj, patch, err := r.getWorkload(ctx, types.NamespacedName{Namespace: "cozy-system", Name: "cozystack-api"}) + if err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + oldHash := tpl.Annotations["cozystack.io/config-hash"] + + if oldHash == newHash && oldHash != "" { + r.mu.Lock() + r.lastHandled = le + r.mu.Unlock() + logger.Info("No changes in ApplicationDefinition config; skipping restart", "hash", newHash) + return ctrl.Result{}, nil + } + + tpl.Annotations["cozystack.io/config-hash"] = newHash + + if err := r.Patch(ctx, obj, patch); err != nil { + return ctrl.Result{}, err + } + + r.mu.Lock() + r.lastHandled = le + r.mu.Unlock() + + logger.Info("Updated cozystack-api podTemplate config-hash; rollout triggered", + "old", oldHash, "new", newHash) + return ctrl.Result{}, nil +} + +func (r *ApplicationDefinitionReconciler) getWorkload( + ctx context.Context, + key types.NamespacedName, +) (tpl *corev1.PodTemplateSpec, obj client.Object, patch client.Patch, err error) { + dep := &appsv1.Deployment{} + if err := r.Get(ctx, key, dep); err != nil { + return nil, nil, nil, err + } + obj = dep + tpl = &dep.Spec.Template + patch = client.MergeFrom(dep.DeepCopy()) + if tpl.Annotations == nil { + tpl.Annotations = make(map[string]string) + } + return tpl, obj, patch, nil +} + +func sortAppDefs(a, b cozyv1alpha1.ApplicationDefinition) int { + if a.Name == b.Name { + return 0 + } + if a.Name < b.Name { + return -1 + } + return 1 +} diff --git a/internal/controller/applicationdefinition_helmreconciler.go b/internal/controller/applicationdefinition_helmreconciler.go new file mode 100644 index 00000000..5f4f63bd --- /dev/null +++ b/internal/controller/applicationdefinition_helmreconciler.go @@ -0,0 +1,188 @@ +package controller + +import ( + "context" + "fmt" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + helmv2 "github.com/fluxcd/helm-controller/api/v2" + + "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" +) + +// +kubebuilder:rbac:groups=cozystack.io,resources=applicationdefinitions,verbs=get;list;watch +// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;update;patch + +// ApplicationDefinitionHelmReconciler reconciles ApplicationDefinitions +// and updates related HelmReleases when an ApplicationDefinition changes. +// This controller does NOT watch HelmReleases to avoid mutual reconciliation storms +// with Flux's helm-controller. +type ApplicationDefinitionHelmReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +func (r *ApplicationDefinitionHelmReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + // Get the ApplicationDefinition that triggered this reconciliation + appDef := &cozyv1alpha1.ApplicationDefinition{} + if err := r.Get(ctx, req.NamespacedName, appDef); err != nil { + logger.Error(err, "failed to get ApplicationDefinition", "name", req.Name) + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + // Update HelmReleases related to this specific ApplicationDefinition + if err := r.updateHelmReleasesForAppDef(ctx, appDef); err != nil { + logger.Error(err, "failed to update HelmReleases for ApplicationDefinition", "appDef", appDef.Name) + return ctrl.Result{}, err + } + + return ctrl.Result{}, nil +} + +func (r *ApplicationDefinitionHelmReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + Named("applicationdefinition-helm-reconciler"). + For(&cozyv1alpha1.ApplicationDefinition{}). + Complete(r) +} + +// updateHelmReleasesForAppDef updates all HelmReleases that match the application labels from ApplicationDefinition +func (r *ApplicationDefinitionHelmReconciler) updateHelmReleasesForAppDef(ctx context.Context, appDef *cozyv1alpha1.ApplicationDefinition) error { + logger := log.FromContext(ctx) + + // Use application labels to find HelmReleases + // Labels: apps.cozystack.io/application.kind and apps.cozystack.io/application.group + applicationKind := appDef.Spec.Application.Kind + + // Validate that applicationKind is non-empty + if applicationKind == "" { + logger.V(4).Info("Skipping HelmRelease update: Application.Kind is empty", "appDef", appDef.Name) + return nil + } + + applicationGroup := "apps.cozystack.io" // All applications use this group + + // Build label selector for HelmReleases + // Only reconcile HelmReleases with apps.cozystack.io/application.* labels + labelSelector := client.MatchingLabels{ + "apps.cozystack.io/application.kind": applicationKind, + "apps.cozystack.io/application.group": applicationGroup, + } + + // List all HelmReleases with matching labels + hrList := &helmv2.HelmReleaseList{} + if err := r.List(ctx, hrList, labelSelector); err != nil { + logger.Error(err, "failed to list HelmReleases", "kind", applicationKind, "group", applicationGroup) + return err + } + + logger.V(4).Info("Found HelmReleases to update", "appDef", appDef.Name, "kind", applicationKind, "count", len(hrList.Items)) + + // Update each HelmRelease + for i := range hrList.Items { + hr := &hrList.Items[i] + if err := r.updateHelmReleaseChart(ctx, hr, appDef); err != nil { + logger.Error(err, "failed to update HelmRelease", "name", hr.Name, "namespace", hr.Namespace) + continue + } + } + + return nil +} + +// expectedValuesFrom returns the expected valuesFrom configuration for HelmReleases +func expectedValuesFrom() []helmv2.ValuesReference { + return []helmv2.ValuesReference{ + { + Kind: "Secret", + Name: "cozystack-values", + }, + } +} + +// valuesFromEqual compares two ValuesReference slices +func valuesFromEqual(a, b []helmv2.ValuesReference) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if a[i].Kind != b[i].Kind || + a[i].Name != b[i].Name || + a[i].ValuesKey != b[i].ValuesKey || + a[i].TargetPath != b[i].TargetPath || + a[i].Optional != b[i].Optional { + return false + } + } + return true +} + +// updateHelmReleaseChart updates the chart and valuesFrom in HelmRelease based on ApplicationDefinition +func (r *ApplicationDefinitionHelmReconciler) updateHelmReleaseChart(ctx context.Context, hr *helmv2.HelmRelease, appDef *cozyv1alpha1.ApplicationDefinition) error { + logger := log.FromContext(ctx) + hrCopy := hr.DeepCopy() + updated := false + + // Validate ChartRef configuration exists + if appDef.Spec.Release.ChartRef == nil || + appDef.Spec.Release.ChartRef.Kind == "" || + appDef.Spec.Release.ChartRef.Name == "" || + appDef.Spec.Release.ChartRef.Namespace == "" { + logger.Error(fmt.Errorf("invalid ChartRef in ApplicationDefinition"), "Skipping HelmRelease chartRef update: ChartRef is nil or incomplete", + "appDef", appDef.Name) + return nil + } + + // Use ChartRef directly from ApplicationDefinition + expectedChartRef := appDef.Spec.Release.ChartRef + + // Check if chartRef needs to be updated + if hrCopy.Spec.ChartRef == nil { + hrCopy.Spec.ChartRef = expectedChartRef + // Clear the old chart field when switching to chartRef + hrCopy.Spec.Chart = nil + updated = true + } else if hrCopy.Spec.ChartRef.Kind != expectedChartRef.Kind || + hrCopy.Spec.ChartRef.Name != expectedChartRef.Name || + hrCopy.Spec.ChartRef.Namespace != expectedChartRef.Namespace { + hrCopy.Spec.ChartRef = expectedChartRef + updated = true + } + + // Check and update valuesFrom configuration + expected := expectedValuesFrom() + if !valuesFromEqual(hrCopy.Spec.ValuesFrom, expected) { + logger.V(4).Info("Updating HelmRelease valuesFrom", "name", hr.Name, "namespace", hr.Namespace) + hrCopy.Spec.ValuesFrom = expected + updated = true + } + + // Check and update labels from ApplicationDefinition + if len(appDef.Spec.Release.Labels) > 0 { + if hrCopy.Labels == nil { + hrCopy.Labels = make(map[string]string) + } + for key, value := range appDef.Spec.Release.Labels { + if hrCopy.Labels[key] != value { + logger.V(4).Info("Updating HelmRelease label", "name", hr.Name, "namespace", hr.Namespace, "label", key, "value", value) + hrCopy.Labels[key] = value + updated = true + } + } + } + + if updated { + logger.V(4).Info("Updating HelmRelease", "name", hr.Name, "namespace", hr.Namespace) + if err := r.Update(ctx, hrCopy); err != nil { + return fmt.Errorf("failed to update HelmRelease: %w", err) + } + } + + return nil +} diff --git a/internal/controller/dashboard/README.md b/internal/controller/dashboard/README.md new file mode 100644 index 00000000..2efe9f45 --- /dev/null +++ b/internal/controller/dashboard/README.md @@ -0,0 +1,355 @@ +# Dashboard Resource Integration Guide + +This guide explains how to add a new Kubernetes resource to the Cozystack dashboard. The dashboard provides a unified interface for viewing and managing Kubernetes resources through custom table views, detail pages, and sidebar navigation. + +## Overview + +Adding a new resource to the dashboard requires three main components: + +1. **CustomColumnsOverride**: Defines how the resource appears in list/table views +2. **Factory**: Defines the detail page layout for individual resource instances +3. **Sidebar Entry**: Adds navigation to the resource in the sidebar menu + +## Prerequisites + +- The resource must have a Kubernetes CustomResourceDefinition (CRD) or be a built-in Kubernetes resource +- Know the resource's API group, version, kind, and plural name +- Understand the resource's spec structure to display relevant fields + +## Step-by-Step Guide + +### Step 1: Add CustomColumnsOverride + +The CustomColumnsOverride defines the columns shown in the resource list table and how clicking on a row navigates to the detail page. + +**Location**: `internal/controller/dashboard/static_refactored.go` in `CreateAllCustomColumnsOverrides()` + +**Example**: +```go +// Stock namespace backups cozystack io v1alpha1 plans +createCustomColumnsOverride("stock-namespace-/backups.cozystack.io/v1alpha1/plans", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "Plan", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/plan-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createApplicationRefColumn("Application"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), +}), +``` + +**Key Components**: +- **ID Format**: `stock-namespace-/{group}/{version}/{plural}` +- **Name Column**: Use `createCustomColumnWithJsonPath()` with: + - Badge value: Resource kind in PascalCase (e.g., "Plan", "Service") + - Link href: `/openapi-ui/{2}/{namespace}/factory/{resource-details}/{name}` +- **Additional Columns**: Use helper functions like: + - `createStringColumn()`: Simple string values + - `createTimestampColumn()`: Timestamp fields + - `createReadyColumn()`: Ready status from conditions + - Custom helpers for complex fields + +**Helper Functions Available**: +- `createCustomColumnWithJsonPath(name, jsonPath, badgeValue, badgeColor, linkHref)`: Column with badge and link +- `createStringColumn(name, jsonPath)`: Simple string column +- `createTimestampColumn(name, jsonPath)`: Timestamp with formatting +- `createReadyColumn()`: Ready status column +- `createBoolColumn(name, jsonPath)`: Boolean column +- `createArrayColumn(name, jsonPath)`: Array column + +### Step 2: Add Factory (Detail Page) + +The Factory defines the detail page layout when viewing an individual resource instance. + +**Location**: `internal/controller/dashboard/static_refactored.go` in `CreateAllFactories()` + +**Using Unified Factory Approach** (Recommended): +```go +// Resource details factory using unified approach +resourceConfig := UnifiedResourceConfig{ + Name: "resource-details", // Must match the href in CustomColumnsOverride + ResourceType: "factory", + Kind: "ResourceKind", // PascalCase + Plural: "resources", // lowercase plural + Title: "resource", // lowercase singular +} +resourceTabs := []any{ + map[string]any{ + "key": "details", + "label": "Details", + "children": []any{ + contentCard("details-card", map[string]any{ + "marginBottom": "24px", + }, []any{ + antdText("details-title", true, "Resource details", map[string]any{ + "fontSize": 20, + "marginBottom": "12px", + }), + spacer("details-spacer", 16), + antdRow("details-grid", []any{48, 12}, []any{ + antdCol("col-left", 12, []any{ + antdFlexVertical("col-left-stack", 24, []any{ + // Metadata fields: Name, Namespace, Created, etc. + }), + }), + antdCol("col-right", 12, []any{ + antdFlexVertical("col-right-stack", 24, []any{ + // Spec fields + }), + }), + }), + }), + }, + }, +} +resourceSpec := createUnifiedFactory(resourceConfig, resourceTabs, []any{"/api/clusters/{2}/k8s/apis/{group}/{version}/namespaces/{3}/{plural}/{6}"}) + +// Add to return list +return []*dashboardv1alpha1.Factory{ + // ... other factories + createFactory("resource-details", resourceSpec), +} +``` + +**Key Components**: +- **Factory Key**: Must match the href path segment (e.g., `plan-details` matches `/factory/plan-details/...`) +- **API Endpoint**: `/api/clusters/{2}/k8s/apis/{group}/{version}/namespaces/{3}/{plural}/{6}` + - `{2}`: Cluster name + - `{3}`: Namespace + - `{6}`: Resource name +- **Sidebar Tags**: Automatically set to `["{lowercase-kind}-sidebar"]` by `createUnifiedFactory()` +- **Tabs**: Define the detail page content (Details, YAML, etc.) + +**UI Helper Functions**: +- `contentCard(id, style, children)`: Container card +- `antdText(id, strong, text, style)`: Text element +- `antdFlexVertical(id, gap, children)`: Vertical flex container +- `antdRow(id, gutter, children)`: Row layout +- `antdCol(id, span, children)`: Column layout +- `parsedText(id, text, style)`: Text with JSON path parsing +- `parsedTextWithFormatter(id, text, formatter)`: Formatted text (e.g., timestamp) +- `spacer(id, space)`: Spacing element + +**Displaying Fields**: +```go +antdFlexVertical("field-block", 4, []any{ + antdText("field-label", true, "Field Label", nil), + parsedText("field-value", "{reqsJsonPath[0]['.spec.fieldName']['-']}", nil), +}), +``` + +### Step 3: Add Sidebar Entry + +The sidebar entry adds navigation to the resource in the sidebar menu. + +**Location**: `internal/controller/dashboard/sidebar.go` in `ensureSidebar()` + +**3a. Add to keysAndTags** (around line 110-116): +```go +// Add sidebar for {group} {kind} resource +keysAndTags["{plural}"] = []any{"{lowercase-kind}-sidebar"} +``` + +**3b. Add Sidebar Section** (if creating a new section, around line 169): +```go +// Add hardcoded {SectionName} section +menuItems = append(menuItems, map[string]any{ + "key": "{section-key}", + "label": "{SectionName}", + "children": []any{ + map[string]any{ + "key": "{plural}", + "label": "{ResourceLabel}", + "link": "/openapi-ui/{cluster}/{namespace}/api-table/{group}/{version}/{plural}", + }, + }, +}), +``` + +**3c. Add Sidebar ID to targetIDs** (around line 220): +```go +"stock-project-factory-{lowercase-kind}-details", +``` + +**3d. Update Category Ordering** (if adding a new section): +- Update the comment around line 29 to include the new section +- Update `orderCategoryLabels()` function if needed +- Add skip condition in the category loop (around line 149) + +**Important Notes**: +- The sidebar tag (`{lowercase-kind}-sidebar`) must match what the Factory uses +- The link format: `/openapi-ui/{cluster}/{namespace}/api-table/{group}/{version}/{plural}` +- All sidebars share the same `keysAndTags` and `menuItems`, so changes affect all sidebar instances + +### Step 4: Verify Integration + +1. **Check Factory-Sidebar Connection**: + - Factory uses `sidebarTags: ["{lowercase-kind}-sidebar"]` + - Sidebar has `keysAndTags["{plural}"] = []any{"{lowercase-kind}-sidebar"}` + - Sidebar ID `stock-project-factory-{lowercase-kind}-details` exists in `targetIDs` + +2. **Check Navigation Flow**: + - Sidebar link → List table (CustomColumnsOverride) + - List table Name column → Detail page (Factory) + - All paths use consistent naming + +3. **Test**: + - Verify the resource appears in the sidebar + - Verify the list table displays correctly + - Verify clicking a resource navigates to the detail page + - Verify the detail page displays all relevant fields + +## Common Patterns + +### Displaying Object References + +For fields that reference other resources (e.g., `applicationRef`, `storageRef`): + +```go +// In CustomColumnsOverride +createApplicationRefColumn("Application"), // Uses helper function + +// In Factory details tab +parsedText("application-ref-value", + "{reqsJsonPath[0]['.spec.applicationRef.kind']['-']}.{reqsJsonPath[0]['.spec.applicationRef.apiGroup']['-']}/{reqsJsonPath[0]['.spec.applicationRef.name']['-']}", + nil), +``` + +### Displaying Timestamps + +```go +antdFlexVertical("created-block", 4, []any{ + antdText("time-label", true, "Created", nil), + antdFlex("time-block", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "time-icon", + "text": "🌐", + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "formatter": "timestamp", + "id": "time-value", + "text": "{reqsJsonPath[0]['.metadata.creationTimestamp']['-']}", + }, + }, + }), +}), +``` + +### Displaying Namespace with Link + +```go +antdFlexVertical("meta-namespace-block", 8, []any{ + antdText("meta-namespace-label", true, "Namespace", nil), + antdFlex("header-row", 6, []any{ + // Badge component + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "header-badge", + "text": "NS", + "title": "namespace", + "style": map[string]any{ + "backgroundColor": "#a25792ff", + // ... badge styles + }, + }, + }, + // Link component + map[string]any{ + "type": "antdLink", + "data": map[string]any{ + "id": "namespace-link", + "text": "{reqsJsonPath[0]['.metadata.namespace']['-']}", + "href": "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace", + }, + }, + }), +}), +``` + +## File Reference + +- **CustomColumnsOverride**: `internal/controller/dashboard/static_refactored.go` → `CreateAllCustomColumnsOverrides()` +- **Factory**: `internal/controller/dashboard/static_refactored.go` → `CreateAllFactories()` +- **Sidebar**: `internal/controller/dashboard/sidebar.go` → `ensureSidebar()` +- **Helper Functions**: `internal/controller/dashboard/static_helpers.go` +- **UI Helpers**: `internal/controller/dashboard/ui_helpers.go` +- **Unified Helpers**: `internal/controller/dashboard/unified_helpers.go` + +## AI Agent Prompt Template + +Use this template when asking an AI agent to add a new resource to the dashboard: + +``` +Please add support for the {ResourceKind} resource ({group}/{version}/{plural}) to the Cozystack dashboard. + +Resource Details: +- API Group: {group} +- Version: {version} +- Kind: {ResourceKind} +- Plural: {plural} +- Namespaced: {true/false} + +Requirements: +1. Add a CustomColumnsOverride in CreateAllCustomColumnsOverrides() with: + - ID: stock-namespace-/{group}/{version}/{plural} + - Name column with {ResourceKind} badge linking to /factory/{lowercase-kind}-details/{name} + - Additional columns: {list relevant columns} + +2. Add a Factory in CreateAllFactories() with: + - Key: {lowercase-kind}-details + - API endpoint: /api/clusters/{2}/k8s/apis/{group}/{version}/namespaces/{3}/{plural}/{6} + - Details tab showing all spec fields: + {list spec fields to display} + - Use createUnifiedFactory() approach + +3. Add sidebar entry in ensureSidebar(): + - Add keysAndTags entry: keysAndTags["{plural}"] = []any{"{lowercase-kind}-sidebar"} + - Add sidebar section: {specify section name or "add to existing section"} + - Add to targetIDs: "stock-project-factory-{lowercase-kind}-details" + +4. Ensure Factory sidebarTags matches the keysAndTags entry + +Please follow the existing patterns in the codebase, particularly the Plan resource implementation as a reference. +``` + +## Example: Plan Resource + +The Plan resource (`backups.cozystack.io/v1alpha1/plans`) serves as a complete reference implementation: + +- **CustomColumnsOverride**: [Diff](https://github.com/cozystack/cozystack/compare/1f0b5ff9ac0d9d8896af46f8a19501c8b728671d..88da2d1f642b6cf03873d368dfdc675de23f1513#diff-8309b1db3362715b3d94a8b0beae7e95d3ccaf248d4f8702aaa12fba398da895R374-R380) in `static_refactored.go` +- **Factory**: [Diff](https://github.com/cozystack/cozystack/compare/1f0b5ff9ac0d9d8896af46f8a19501c8b728671d..88da2d1f642b6cf03873d368dfdc675de23f1513#diff-8309b1db3362715b3d94a8b0beae7e95d3ccaf248d4f8702aaa12fba398da895R1443-R1558) in `static_refactored.go` +- **Sidebar**: [Diff](https://github.com/cozystack/cozystack/compare/1f0b5ff9ac0d9d8896af46f8a19501c8b728671d..88da2d1f642b6cf03873d368dfdc675de23f1513#diff-be79027f7179e457a8f10e225bb921a197ffa390eb8f916d8d21379fadd54a56) in `sidebar.go` +- **Helper Function**: `createApplicationRefColumn()` in `static_helpers.go` ([diff](https://github.com/cozystack/cozystack/compare/1f0b5ff9ac0d9d8896af46f8a19501c8b728671d..88da2d1f642b6cf03873d368dfdc675de23f1513#diff-f17bcccc089cac3a8e965b13b9ab26e678d45bfc9a58d842399f218703e06a08R1026-R1046)) + +Review [this implementation](https://github.com/cozystack/cozystack/compare/1f0b5ff9ac0d9d8896af46f8a19501c8b728671d..88da2d1f642b6cf03873d368dfdc675de23f1513) for a complete working example. + +## Troubleshooting + +### Resource doesn't appear in sidebar +- Check that `keysAndTags["{plural}"]` is set correctly +- Verify the sidebar section is added to `menuItems` +- Ensure the sidebar ID is in `targetIDs` + +### Clicking resource doesn't navigate to detail page +- Verify the CustomColumnsOverride href matches the Factory key +- Check that the Factory key is exactly `{lowercase-kind}-details` +- Ensure the Factory is added to the return list in `CreateAllFactories()` + +### Detail page shows wrong sidebar +- Verify Factory `sidebarTags` matches `keysAndTags["{plural}"]` +- Check that the sidebar ID `stock-project-factory-{lowercase-kind}-details` exists +- Ensure all sidebars are updated (they share the same `keysAndTags`) + +### Fields not displaying correctly +- Verify JSON paths are correct (use `.spec.fieldName` format) +- Check that `reqsJsonPath[0]` index is used for single resource views +- Ensure field names match the actual resource spec structure + +## Additional Resources + +- Kubernetes API Conventions: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md +- Dashboard API Types: `api/dashboard/v1alpha1/` +- Resource Types: `api/backups/v1alpha1/` (example) + diff --git a/internal/controller/dashboard/breadcrumb.go b/internal/controller/dashboard/breadcrumb.go new file mode 100644 index 00000000..6d65f2db --- /dev/null +++ b/internal/controller/dashboard/breadcrumb.go @@ -0,0 +1,80 @@ +package dashboard + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +// ensureBreadcrumb creates or updates a Breadcrumb resource for the given CRD +func (m *Manager) ensureBreadcrumb(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error { + group, version, kind := pickGVK(crd) + + lowerKind := strings.ToLower(kind) + detailID := fmt.Sprintf("stock-project-factory-%s-details", lowerKind) + + obj := &dashv1alpha1.Breadcrumb{} + obj.SetName(detailID) + + plural := pickPlural(kind, crd) + + // Prefer dashboard.Plural for UI label if provided + labelPlural := titleFromKindPlural(kind, plural) + if crd != nil && crd.Spec.Dashboard != nil && crd.Spec.Dashboard.Plural != "" { + labelPlural = crd.Spec.Dashboard.Plural + } + + key := plural // e.g., "virtualmachines" + label := labelPlural + link := fmt.Sprintf("/openapi-ui/{cluster}/{namespace}/api-table/%s/%s/%s", strings.ToLower(group), strings.ToLower(version), plural) + // If this is a module, change the first breadcrumb item to "Tenant Modules" + if crd.Spec.Dashboard != nil && crd.Spec.Dashboard.Module { + key = "tenantmodules" + label = "Tenant Modules" + link = "/openapi-ui/{cluster}/{namespace}/api-table/core.cozystack.io/v1alpha1/tenantmodules" + } + + items := []any{ + map[string]any{ + "key": key, + "label": label, + "link": link, + }, + map[string]any{ + "key": strings.ToLower(kind), // "etcd" + "label": "{6}", // literal, as in your example + }, + } + + spec := map[string]any{ + "id": detailID, + "breadcrumbItems": items, + } + + _, err := controllerutil.CreateOrUpdate(ctx, m.Client, obj, func() error { + if err := controllerutil.SetOwnerReference(crd, obj, m.Scheme); err != nil { + return err + } + // Add dashboard labels to dynamic resources + m.addDashboardLabels(obj, crd, ResourceTypeDynamic) + b, err := json.Marshal(spec) + if err != nil { + return err + } + + // Only update spec if it's different to avoid unnecessary updates + newSpec := dashv1alpha1.ArbitrarySpec{JSON: apiextv1.JSON{Raw: b}} + if !compareArbitrarySpecs(obj.Spec, newSpec) { + obj.Spec = newSpec + } + return nil + }) + return err +} diff --git a/internal/controller/dashboard/customcolumns.go b/internal/controller/dashboard/customcolumns.go new file mode 100644 index 00000000..19a5a16a --- /dev/null +++ b/internal/controller/dashboard/customcolumns.go @@ -0,0 +1,147 @@ +package dashboard + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +// ensureCustomColumnsOverride creates or updates a CustomColumnsOverride that +// renders a header row with a colored badge and resource name link, plus a few +// useful columns (Ready, Created, Version). +// +// Naming convention mirrors your example: +// +// metadata.name: stock-namespace-.. +// spec.id: stock-namespace-/// +func (m *Manager) ensureCustomColumnsOverride(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) (controllerutil.OperationResult, error) { + g, v, kind := pickGVK(crd) + plural := pickPlural(kind, crd) + // Details page segment uses lowercase kind, mirroring your example + detailsSegment := strings.ToLower(kind) + "-details" + + name := fmt.Sprintf("stock-namespace-%s.%s.%s", g, v, plural) + id := fmt.Sprintf("stock-namespace-/%s/%s/%s", g, v, plural) + + obj := &dashv1alpha1.CustomColumnsOverride{} + obj.SetName(name) + + href := fmt.Sprintf("/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/%s/{reqsJsonPath[0]['.metadata.name']['-']}", detailsSegment) + + desired := map[string]any{ + "spec": map[string]any{ + "id": id, + "additionalPrinterColumns": []any{ + map[string]any{ + "name": "Name", + "type": "factory", + "jsonPath": ".metadata.name", + "customProps": map[string]any{ + "disableEventBubbling": true, + "items": []any{ + map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "header-row", + "align": "center", + "gap": 6, + }, + "children": []any{ + map[string]any{ + "type": "ResourceBadge", + "data": map[string]any{ + "id": "header-badge", + "value": kind, + // abbreviation auto-generated by ResourceBadge from value + }, + }, + map[string]any{ + "type": "antdLink", + "data": map[string]any{ + "id": "name-link", + "text": "{reqsJsonPath[0]['.metadata.name']['-']}", + "href": href, + }, + }, + }, + }, + }, + }, + }, + map[string]any{ + "name": "Ready", + "type": "Boolean", + "jsonPath": `.status.conditions[?(@.type=="Ready")].status`, + }, + map[string]any{ + "name": "Created", + "type": "factory", + "jsonPath": ".metadata.creationTimestamp", + "customProps": map[string]any{ + "disableEventBubbling": true, + "items": []any{ + map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "time-block", + "align": "center", + "gap": 6, + }, + "children": []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "time-icon", + "text": "🌐", + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "id": "time-value", + "text": "{reqsJsonPath[0]['.metadata.creationTimestamp']['-']}", + "formatter": "timestamp", + }, + }, + }, + }, + }, + }, + }, + map[string]any{ + "name": "Version", + "type": "string", + "jsonPath": ".status.version", + }, + }, + }, + } + + _, err := controllerutil.CreateOrUpdate(ctx, m.Client, obj, func() error { + if err := controllerutil.SetOwnerReference(crd, obj, m.Scheme); err != nil { + return err + } + // Add dashboard labels to dynamic resources + m.addDashboardLabels(obj, crd, ResourceTypeDynamic) + b, err := json.Marshal(desired["spec"]) + if err != nil { + return err + } + + // Only update spec if it's different to avoid unnecessary updates + newSpec := dashv1alpha1.ArbitrarySpec{JSON: apiextv1.JSON{Raw: b}} + if !compareArbitrarySpecs(obj.Spec, newSpec) { + obj.Spec = newSpec + } + return nil + }) + // Return OperationResultCreated/Updated is not available here with unstructured; we can mimic Updated when no error. + return controllerutil.OperationResultNone, err +} diff --git a/internal/controller/dashboard/customformsoverride.go b/internal/controller/dashboard/customformsoverride.go new file mode 100644 index 00000000..0a20ae71 --- /dev/null +++ b/internal/controller/dashboard/customformsoverride.go @@ -0,0 +1,463 @@ +package dashboard + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +// ensureCustomFormsOverride creates or updates a CustomFormsOverride resource for the given CRD +func (m *Manager) ensureCustomFormsOverride(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error { + g, v, kind := pickGVK(crd) + plural := pickPlural(kind, crd) + + name := fmt.Sprintf("%s.%s.%s", g, v, plural) + customizationID := fmt.Sprintf("default-/%s/%s/%s", g, v, plural) + + obj := &dashv1alpha1.CustomFormsOverride{} + obj.SetName(name) + + // Replicates your Helm includes (system metadata + api + status). + hidden := []any{} + hidden = append(hidden, hiddenMetadataSystem()...) + hidden = append(hidden, hiddenMetadataAPI()...) + hidden = append(hidden, hiddenStatus()...) + + // If Name is set, hide metadata + if crd.Spec.Dashboard != nil && strings.TrimSpace(crd.Spec.Dashboard.Name) != "" { + hidden = append([]interface{}{ + []any{"metadata"}, + }, hidden...) + } + + var sort []any + if crd.Spec.Dashboard != nil && len(crd.Spec.Dashboard.KeysOrder) > 0 { + sort = make([]any, len(crd.Spec.Dashboard.KeysOrder)) + for i, v := range crd.Spec.Dashboard.KeysOrder { + sort[i] = v + } + } + + // Parse OpenAPI schema once for reuse + l := log.FromContext(ctx) + openAPIProps := parseOpenAPIProperties(crd.Spec.Application.OpenAPISchema) + + // Build schema with multilineString for string fields without enum + schema, err := buildMultilineStringSchema(crd.Spec.Application.OpenAPISchema) + if err != nil { + // If schema parsing fails, log the error and use an empty schema + l.Error(err, "failed to build multiline string schema, using empty schema", "crd", crd.Name) + schema = map[string]any{} + } + + // Override specific fields with API-backed dropdowns (listInput type) + applyListInputOverrides(schema, kind, openAPIProps) + + // Hide deprecated fields from the UI + hidden = append(hidden, hiddenDeprecatedFields(kind)...) + + spec := map[string]any{ + "customizationId": customizationID, + "hidden": hidden, + "sort": sort, + "schema": schema, + "strategy": "merge", + } + + _, err = controllerutil.CreateOrUpdate(ctx, m.Client, obj, func() error { + if err := controllerutil.SetOwnerReference(crd, obj, m.Scheme); err != nil { + return err + } + // Add dashboard labels to dynamic resources + m.addDashboardLabels(obj, crd, ResourceTypeDynamic) + b, err := json.Marshal(spec) + if err != nil { + return err + } + + // Only update spec if it's different to avoid unnecessary updates + newSpec := dashv1alpha1.ArbitrarySpec{JSON: apiextv1.JSON{Raw: b}} + if !compareArbitrarySpecs(obj.Spec, newSpec) { + obj.Spec = newSpec + } + return nil + }) + return err +} + +// ensureCFOMapping updates the CFOMapping resource to include a mapping for the given CRD +func (m *Manager) ensureCFOMapping(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error { + g, v, kind := pickGVK(crd) + plural := pickPlural(kind, crd) + + resourcePath := fmt.Sprintf("/%s/%s/%s", g, v, plural) + customizationID := fmt.Sprintf("default-%s", resourcePath) + + obj := &dashv1alpha1.CFOMapping{} + obj.SetName("cfomapping") + + _, err := controllerutil.CreateOrUpdate(ctx, m.Client, obj, func() error { + // Parse existing mappings + mappings := make(map[string]string) + if obj.Spec.JSON.Raw != nil { + var spec map[string]any + if err := json.Unmarshal(obj.Spec.JSON.Raw, &spec); err == nil { + if m, ok := spec["mappings"].(map[string]any); ok { + for k, val := range m { + if s, ok := val.(string); ok { + mappings[k] = s + } + } + } + } + } + + // Add/update the mapping for this CRD + mappings[resourcePath] = customizationID + + specData := map[string]any{ + "mappings": mappings, + } + b, err := json.Marshal(specData) + if err != nil { + return err + } + + newSpec := dashv1alpha1.ArbitrarySpec{JSON: apiextv1.JSON{Raw: b}} + if !compareArbitrarySpecs(obj.Spec, newSpec) { + obj.Spec = newSpec + } + return nil + }) + return err +} + +// buildMultilineStringSchema parses OpenAPI schema and creates schema with multilineString +// for all string fields inside spec that don't have enum. +// It handles two structures: +// - properties.spec.properties (most resources) +// - properties.properties (VMDisk and similar resources without spec wrapper) +func buildMultilineStringSchema(openAPISchema string) (map[string]any, error) { + if openAPISchema == "" { + return map[string]any{}, nil + } + + var root map[string]any + if err := json.Unmarshal([]byte(openAPISchema), &root); err != nil { + return nil, fmt.Errorf("cannot parse openAPISchema: %w", err) + } + + props, _ := root["properties"].(map[string]any) + if props == nil { + return map[string]any{}, nil + } + + schema := map[string]any{ + "properties": map[string]any{}, + } + + var specProps map[string]any + var hasSpec bool + + // First try to find properties under spec + if specProp, ok := props["spec"].(map[string]any); ok { + specProps, hasSpec = specProp["properties"].(map[string]any) + } + + // If no spec wrapper, use top-level properties directly (VMDisk pattern) + if !hasSpec { + specProps = props + // Still wrap in spec for consistency with applyListInputOverrides + schemaProps := schema["properties"].(map[string]any) + specSchema := map[string]any{ + "properties": map[string]any{}, + } + schemaProps["spec"] = specSchema + processSpecProperties(specProps, specSchema["properties"].(map[string]any)) + return schema, nil + } + + // Create spec.properties structure in schema + schemaProps := schema["properties"].(map[string]any) + specSchema := map[string]any{ + "properties": map[string]any{}, + } + schemaProps["spec"] = specSchema + + // Process spec properties recursively + processSpecProperties(specProps, specSchema["properties"].(map[string]any)) + + return schema, nil +} + +// applyListInputOverrides injects listInput type overrides into the schema +// for fields that should be rendered as API-backed dropdowns in the dashboard. +// openAPIProps are the parsed top-level properties from the OpenAPI schema. +func applyListInputOverrides(schema map[string]any, kind string, openAPIProps map[string]any) { + switch kind { + case "VMInstance": + specProps := ensureSchemaPath(schema, "spec") + field := map[string]any{ + "type": "listInput", + "customProps": map[string]any{ + "valueUri": "/api/clusters/{cluster}/k8s/apis/instancetype.kubevirt.io/v1beta1/virtualmachineclusterinstancetypes", + "keysToValue": []any{"metadata", "name"}, + "keysToLabel": []any{"metadata", "name"}, + "allowEmpty": true, + }, + } + if prop, _ := openAPIProps["instanceType"].(map[string]any); prop != nil { + if def := prop["default"]; def != nil { + field["default"] = def + } + } + specProps["instanceType"] = field + + // Override disks[].name to be an API-backed dropdown listing VMDisk resources + disksItemProps := ensureArrayItemProps(specProps, "disks") + disksItemProps["name"] = map[string]any{ + "type": "listInput", + "customProps": map[string]any{ + "valueUri": "/api/clusters/{cluster}/k8s/apis/apps.cozystack.io/v1alpha1/namespaces/{namespace}/vmdisks", + "keysToValue": []any{"metadata", "name"}, + "keysToLabel": []any{"metadata", "name"}, + }, + } + + // Override networks[].name to be an API-backed dropdown listing NetworkAttachmentDefinitions + networksItemProps := ensureArrayItemProps(specProps, "networks") + networksItemProps["name"] = map[string]any{ + "type": "listInput", + "customProps": map[string]any{ + "valueUri": "/api/clusters/{cluster}/k8s/apis/k8s.cni.cncf.io/v1/namespaces/{namespace}/network-attachment-definitions", + "keysToValue": []any{"metadata", "name"}, + "keysToLabel": []any{"metadata", "name"}, + }, + } + + case "ClickHouse", "Harbor", "HTTPCache", "Kubernetes", "MariaDB", "MongoDB", + "NATS", "OpenBAO", "Postgres", "Qdrant", "RabbitMQ", "Redis": + specProps := ensureSchemaPath(schema, "spec") + specProps["storageClass"] = storageClassListInput() + + case "VMDisk": + specProps := ensureSchemaPath(schema, "spec") + specProps["storageClass"] = storageClassListInput() + + // Override source.image.name to be an API-backed dropdown listing default images + if sourceObj, ok := specProps["source"].(map[string]any); ok { + if imgProps, ok := sourceObj["properties"].(map[string]any); ok { + if imgName, ok := imgProps["image"].(map[string]any); ok { + if imgNameProps, ok := imgName["properties"].(map[string]any); ok { + imgNameProps["name"] = map[string]any{ + "type": "listInput", + "customProps": map[string]any{ + "valueUri": "/api/clusters/{cluster}/k8s/apis/cdi.kubevirt.io/v1beta1/namespaces/cozy-public/datavolumes", + "keysToValue": []any{"metadata", "annotations", "vm-default-images.cozystack.io/name"}, + "keysToLabel": []any{"metadata", "annotations", "vm-default-images.cozystack.io/description"}, + }, + } + } + } + // Override source.disk.name to be an API-backed dropdown listing VMDisk resources + if diskName, ok := imgProps["disk"].(map[string]any); ok { + if diskNameProps, ok := diskName["properties"].(map[string]any); ok { + diskNameProps["name"] = map[string]any{ + "type": "listInput", + "customProps": map[string]any{ + "valueUri": "/api/clusters/{cluster}/k8s/apis/apps.cozystack.io/v1alpha1/namespaces/{namespace}/vmdisks", + "keysToValue": []any{"metadata", "name"}, + "keysToLabel": []any{"metadata", "name"}, + }, + } + } + } + } + } + + case "FoundationDB": + storageProps := ensureSchemaPath(schema, "spec", "storage") + storageProps["storageClass"] = storageClassListInput() + + case "Kafka": + kafkaProps := ensureSchemaPath(schema, "spec", "kafka") + kafkaProps["storageClass"] = storageClassListInput() + zkProps := ensureSchemaPath(schema, "spec", "zookeeper") + zkProps["storageClass"] = storageClassListInput() + + case "Tenant": + specProps := ensureSchemaPath(schema, "spec") + specProps["schedulingClass"] = schedulingClassListInput() + } +} + +// hiddenDeprecatedFields returns hidden paths for deprecated fields that should not +// appear in the dashboard UI for the given kind. +func hiddenDeprecatedFields(kind string) []any { + switch kind { + case "VMInstance": + return []any{ + []any{"spec", "subnets"}, + } + } + return nil +} + +// storageClassListInput returns a listInput field config for a storageClass dropdown +// backed by the cluster's available StorageClasses. +func storageClassListInput() map[string]any { + return map[string]any{ + "type": "listInput", + "customProps": map[string]any{ + "valueUri": "/api/clusters/{cluster}/k8s/apis/storage.k8s.io/v1/storageclasses", + "keysToValue": []any{"metadata", "name"}, + "keysToLabel": []any{"metadata", "name"}, + }, + } +} + +// schedulingClassListInput returns a listInput field config for a schedulingClass dropdown +// backed by the cluster's available SchedulingClass CRs. +func schedulingClassListInput() map[string]any { + return map[string]any{ + "type": "listInput", + "customProps": map[string]any{ + "valueUri": "/api/clusters/{cluster}/k8s/apis/cozystack.io/v1alpha1/schedulingclasses", + "keysToValue": []any{"metadata", "name"}, + "keysToLabel": []any{"metadata", "name"}, + "allowEmpty": true, + }, + } +} + +// ensureArrayItemProps ensures that parentProps[fieldName].items.properties exists +// and returns the items properties map. Used for overriding fields inside array items. +func ensureArrayItemProps(parentProps map[string]any, fieldName string) map[string]any { + field, ok := parentProps[fieldName].(map[string]any) + if !ok { + field = map[string]any{} + parentProps[fieldName] = field + } + items, ok := field["items"].(map[string]any) + if !ok { + items = map[string]any{} + field["items"] = items + } + props, ok := items["properties"].(map[string]any) + if !ok { + props = map[string]any{} + items["properties"] = props + } + return props +} + +// parseOpenAPIProperties parses the top-level properties from an OpenAPI schema JSON string. +func parseOpenAPIProperties(openAPISchema string) map[string]any { + if openAPISchema == "" { + return nil + } + var root map[string]any + if err := json.Unmarshal([]byte(openAPISchema), &root); err != nil { + return nil + } + props, _ := root["properties"].(map[string]any) + return props +} + +// ensureSchemaPath ensures the nested properties structure exists in a schema +// and returns the innermost properties map. +// e.g. ensureSchemaPath(schema, "spec") returns schema["properties"]["spec"]["properties"] +func ensureSchemaPath(schema map[string]any, segments ...string) map[string]any { + current := schema + for _, seg := range segments { + props, ok := current["properties"].(map[string]any) + if !ok { + props = map[string]any{} + current["properties"] = props + } + child, ok := props[seg].(map[string]any) + if !ok { + child = map[string]any{} + props[seg] = child + } + current = child + } + props, ok := current["properties"].(map[string]any) + if !ok { + props = map[string]any{} + current["properties"] = props + } + return props +} + +// processSpecProperties recursively processes spec properties and adds multilineString type +// for string fields without enum +func processSpecProperties(props map[string]any, schemaProps map[string]any) { + for pname, raw := range props { + sub, ok := raw.(map[string]any) + if !ok { + continue + } + + typ, _ := sub["type"].(string) + + switch typ { + case "string": + // Check if this string field has enum + if !hasEnum(sub) { + // Add multilineString type for this field + if schemaProps[pname] == nil { + schemaProps[pname] = map[string]any{} + } + fieldSchema := schemaProps[pname].(map[string]any) + fieldSchema["type"] = "multilineString" + } + case "object": + // Recursively process nested objects + if childProps, ok := sub["properties"].(map[string]any); ok { + fieldSchema, ok := schemaProps[pname].(map[string]any) + if !ok { + fieldSchema = map[string]any{} + schemaProps[pname] = fieldSchema + } + nestedSchemaProps, ok := fieldSchema["properties"].(map[string]any) + if !ok { + nestedSchemaProps = map[string]any{} + fieldSchema["properties"] = nestedSchemaProps + } + processSpecProperties(childProps, nestedSchemaProps) + } + case "array": + // Check if array items are objects with properties + if items, ok := sub["items"].(map[string]any); ok { + if itemProps, ok := items["properties"].(map[string]any); ok { + // Create array item schema + fieldSchema, ok := schemaProps[pname].(map[string]any) + if !ok { + fieldSchema = map[string]any{} + schemaProps[pname] = fieldSchema + } + itemSchema, ok := fieldSchema["items"].(map[string]any) + if !ok { + itemSchema = map[string]any{} + fieldSchema["items"] = itemSchema + } + itemSchemaProps, ok := itemSchema["properties"].(map[string]any) + if !ok { + itemSchemaProps = map[string]any{} + itemSchema["properties"] = itemSchemaProps + } + processSpecProperties(itemProps, itemSchemaProps) + } + } + } + } +} diff --git a/internal/controller/dashboard/customformsoverride_test.go b/internal/controller/dashboard/customformsoverride_test.go new file mode 100644 index 00000000..6a83d62e --- /dev/null +++ b/internal/controller/dashboard/customformsoverride_test.go @@ -0,0 +1,621 @@ +package dashboard + +import ( + "encoding/json" + "testing" +) + +func TestBuildMultilineStringSchema(t *testing.T) { + // Test OpenAPI schema with various field types + openAPISchema := `{ + "properties": { + "spec": { + "type": "object", + "properties": { + "simpleString": { + "type": "string", + "description": "A simple string field" + }, + "stringWithEnum": { + "type": "string", + "enum": ["option1", "option2"], + "description": "String with enum should be skipped" + }, + "numberField": { + "type": "number", + "description": "Number field should be skipped" + }, + "nestedObject": { + "type": "object", + "properties": { + "nestedString": { + "type": "string", + "description": "Nested string should get multilineString" + }, + "nestedStringWithEnum": { + "type": "string", + "enum": ["a", "b"], + "description": "Nested string with enum should be skipped" + } + } + }, + "arrayOfObjects": { + "type": "array", + "items": { + "type": "object", + "properties": { + "itemString": { + "type": "string", + "description": "String in array item" + } + } + } + } + } + } + } + }` + + schema, err := buildMultilineStringSchema(openAPISchema) + if err != nil { + t.Fatalf("buildMultilineStringSchema failed: %v", err) + } + + // Marshal to JSON for easier inspection + schemaJSON, err := json.MarshalIndent(schema, "", " ") + if err != nil { + t.Fatalf("Failed to marshal schema: %v", err) + } + + t.Logf("Generated schema:\n%s", schemaJSON) + + // Verify that simpleString has multilineString type + props, ok := schema["properties"].(map[string]any) + if !ok { + t.Fatal("schema.properties is not a map") + } + + // Check spec property exists + spec, ok := props["spec"].(map[string]any) + if !ok { + t.Fatal("spec not found in properties") + } + + specProps, ok := spec["properties"].(map[string]any) + if !ok { + t.Fatal("spec.properties is not a map") + } + + // Check simpleString + simpleString, ok := specProps["simpleString"].(map[string]any) + if !ok { + t.Fatal("simpleString not found in spec.properties") + } + if simpleString["type"] != "multilineString" { + t.Errorf("simpleString should have type multilineString, got %v", simpleString["type"]) + } + + // Check stringWithEnum should not be present (or should not have multilineString) + if stringWithEnum, ok := specProps["stringWithEnum"].(map[string]any); ok { + if stringWithEnum["type"] == "multilineString" { + t.Error("stringWithEnum should not have multilineString type") + } + } + + // Check numberField should not be present + if numberField, ok := specProps["numberField"].(map[string]any); ok { + if numberField["type"] != nil { + t.Error("numberField should not have any type override") + } + } + + // Check nested object + nestedObject, ok := specProps["nestedObject"].(map[string]any) + if !ok { + t.Fatal("nestedObject not found in spec.properties") + } + nestedProps, ok := nestedObject["properties"].(map[string]any) + if !ok { + t.Fatal("nestedObject.properties is not a map") + } + + // Check nestedString + nestedString, ok := nestedProps["nestedString"].(map[string]any) + if !ok { + t.Fatal("nestedString not found in nestedObject.properties") + } + if nestedString["type"] != "multilineString" { + t.Errorf("nestedString should have type multilineString, got %v", nestedString["type"]) + } + + // Check array of objects + arrayOfObjects, ok := specProps["arrayOfObjects"].(map[string]any) + if !ok { + t.Fatal("arrayOfObjects not found in spec.properties") + } + items, ok := arrayOfObjects["items"].(map[string]any) + if !ok { + t.Fatal("arrayOfObjects.items is not a map") + } + itemProps, ok := items["properties"].(map[string]any) + if !ok { + t.Fatal("arrayOfObjects.items.properties is not a map") + } + itemString, ok := itemProps["itemString"].(map[string]any) + if !ok { + t.Fatal("itemString not found in arrayOfObjects.items.properties") + } + if itemString["type"] != "multilineString" { + t.Errorf("itemString should have type multilineString, got %v", itemString["type"]) + } +} + +func TestBuildMultilineStringSchemaEmpty(t *testing.T) { + schema, err := buildMultilineStringSchema("") + if err != nil { + t.Fatalf("buildMultilineStringSchema failed on empty string: %v", err) + } + if len(schema) != 0 { + t.Errorf("Expected empty schema for empty input, got %v", schema) + } +} + +func TestBuildMultilineStringSchemaInvalidJSON(t *testing.T) { + schema, err := buildMultilineStringSchema("{invalid json") + if err == nil { + t.Error("Expected error for invalid JSON") + } + if schema != nil { + t.Errorf("Expected nil schema for invalid JSON, got %v", schema) + } +} + +func TestApplyListInputOverrides_VMInstance(t *testing.T) { + openAPIProps := map[string]any{ + "instanceType": map[string]any{"type": "string", "default": "u1.medium"}, + } + + schema := map[string]any{} + applyListInputOverrides(schema, "VMInstance", openAPIProps) + + specProps := schema["properties"].(map[string]any)["spec"].(map[string]any)["properties"].(map[string]any) + instanceType, ok := specProps["instanceType"].(map[string]any) + if !ok { + t.Fatal("instanceType not found in schema.properties.spec.properties") + } + + if instanceType["type"] != "listInput" { + t.Errorf("expected type listInput, got %v", instanceType["type"]) + } + + if instanceType["default"] != "u1.medium" { + t.Errorf("expected default u1.medium, got %v", instanceType["default"]) + } + + customProps, ok := instanceType["customProps"].(map[string]any) + if !ok { + t.Fatal("customProps not found") + } + + expectedURI := "/api/clusters/{cluster}/k8s/apis/instancetype.kubevirt.io/v1beta1/virtualmachineclusterinstancetypes" + if customProps["valueUri"] != expectedURI { + t.Errorf("expected valueUri %s, got %v", expectedURI, customProps["valueUri"]) + } + + if customProps["allowEmpty"] != true { + t.Errorf("expected allowEmpty true, got %v", customProps["allowEmpty"]) + } + + // Check disks[].name is a listInput + disks, ok := specProps["disks"].(map[string]any) + if !ok { + t.Fatal("disks not found in schema.properties.spec.properties") + } + items, ok := disks["items"].(map[string]any) + if !ok { + t.Fatal("disks.items not found") + } + itemProps, ok := items["properties"].(map[string]any) + if !ok { + t.Fatal("disks.items.properties not found") + } + diskName, ok := itemProps["name"].(map[string]any) + if !ok { + t.Fatal("disks.items.properties.name not found") + } + if diskName["type"] != "listInput" { + t.Errorf("expected disks name type listInput, got %v", diskName["type"]) + } + diskCustomProps, ok := diskName["customProps"].(map[string]any) + if !ok { + t.Fatal("disks name customProps not found") + } + expectedDiskURI := "/api/clusters/{cluster}/k8s/apis/apps.cozystack.io/v1alpha1/namespaces/{namespace}/vmdisks" + if diskCustomProps["valueUri"] != expectedDiskURI { + t.Errorf("expected disks valueUri %s, got %v", expectedDiskURI, diskCustomProps["valueUri"]) + } + + // Check networks[].name is a listInput + networks, ok := specProps["networks"].(map[string]any) + if !ok { + t.Fatal("networks not found in schema.properties.spec.properties") + } + netItems, ok := networks["items"].(map[string]any) + if !ok { + t.Fatal("networks.items not found") + } + netItemProps, ok := netItems["properties"].(map[string]any) + if !ok { + t.Fatal("networks.items.properties not found") + } + netName, ok := netItemProps["name"].(map[string]any) + if !ok { + t.Fatal("networks.items.properties.name not found") + } + if netName["type"] != "listInput" { + t.Errorf("expected networks name type listInput, got %v", netName["type"]) + } + netCustomProps, ok := netName["customProps"].(map[string]any) + if !ok { + t.Fatal("networks name customProps not found") + } + expectedNetURI := "/api/clusters/{cluster}/k8s/apis/k8s.cni.cncf.io/v1/namespaces/{namespace}/network-attachment-definitions" + if netCustomProps["valueUri"] != expectedNetURI { + t.Errorf("expected networks valueUri %s, got %v", expectedNetURI, netCustomProps["valueUri"]) + } +} + +func TestHiddenDeprecatedFields_VMInstance(t *testing.T) { + hidden := hiddenDeprecatedFields("VMInstance") + if len(hidden) != 1 { + t.Fatalf("expected 1 hidden path, got %d", len(hidden)) + } + path, ok := hidden[0].([]any) + if !ok { + t.Fatal("hidden path is not []any") + } + if len(path) != 2 || path[0] != "spec" || path[1] != "subnets" { + t.Errorf("expected [spec subnets], got %v", path) + } +} + +func TestHiddenDeprecatedFields_UnknownKind(t *testing.T) { + hidden := hiddenDeprecatedFields("SomeOtherKind") + if hidden != nil { + t.Errorf("expected nil for unknown kind, got %v", hidden) + } +} + +func TestApplyListInputOverrides_StorageClassSimple(t *testing.T) { + for _, kind := range []string{ + "ClickHouse", "Harbor", "HTTPCache", "Kubernetes", "MariaDB", "MongoDB", + "NATS", "OpenBAO", "Postgres", "Qdrant", "RabbitMQ", "Redis", "VMDisk", + } { + t.Run(kind, func(t *testing.T) { + schema := map[string]any{} + applyListInputOverrides(schema, kind, map[string]any{}) + + specProps := schema["properties"].(map[string]any)["spec"].(map[string]any)["properties"].(map[string]any) + sc, ok := specProps["storageClass"].(map[string]any) + if !ok { + t.Fatalf("storageClass not found in spec.properties for kind %s", kind) + } + assertStorageClassListInput(t, sc) + }) + } +} + +func TestApplyListInputOverrides_StorageClassFoundationDB(t *testing.T) { + schema := map[string]any{} + applyListInputOverrides(schema, "FoundationDB", map[string]any{}) + + storageProps := schema["properties"].(map[string]any)["spec"].(map[string]any)["properties"].(map[string]any)["storage"].(map[string]any)["properties"].(map[string]any) + sc, ok := storageProps["storageClass"].(map[string]any) + if !ok { + t.Fatal("storageClass not found in spec.storage.properties") + } + assertStorageClassListInput(t, sc) +} + +func TestApplyListInputOverrides_VMDisk_SourceFields(t *testing.T) { + openAPISchema := `{ + "properties":{ + "optical":{"type":"boolean"}, + "source":{ + "type":"object", + "properties":{ + "image":{ + "type":"object", + "properties":{ + "name":{"type":"string"} + } + }, + "disk":{ + "type":"object", + "properties":{ + "name":{"type":"string"} + } + } + } + }, + "storage":{"type":"string"}, + "storageClass":{"type":"string"} + } + }` + + schema, err := buildMultilineStringSchema(openAPISchema) + if err != nil { + t.Fatalf("buildMultilineStringSchema failed: %v", err) + } + + applyListInputOverrides(schema, "VMDisk", map[string]any{}) + + specProps := schema["properties"].(map[string]any)["spec"].(map[string]any)["properties"].(map[string]any) + + // Check storageClass + sc, ok := specProps["storageClass"].(map[string]any) + if !ok { + t.Fatal("storageClass not found in spec.properties") + } + assertStorageClassListInput(t, sc) + + // Check source.image.name listInput + // Structure: specProps["source"]["properties"]["image"]["properties"]["name"] + sourceObj, ok := specProps["source"].(map[string]any) + if !ok { + t.Fatal("source not found in spec.properties") + } + sourceObjProps, ok := sourceObj["properties"].(map[string]any) + if !ok { + t.Fatal("source.properties not found") + } + imageObj, ok := sourceObjProps["image"].(map[string]any) + if !ok { + t.Fatal("image not found in source.properties") + } + imageObjProps, ok := imageObj["properties"].(map[string]any) + if !ok { + t.Fatal("image.properties not found") + } + imgName, ok := imageObjProps["name"].(map[string]any) + if !ok { + t.Fatal("name not found in image.properties") + } + if imgName["type"] != "listInput" { + t.Errorf("expected type listInput, got %v", imgName["type"]) + } + imgNameCustomProps, ok := imgName["customProps"].(map[string]any) + if !ok { + t.Fatal("name.customProps not found") + } + expectedImageURI := "/api/clusters/{cluster}/k8s/apis/cdi.kubevirt.io/v1beta1/namespaces/cozy-public/datavolumes" + if imgNameCustomProps["valueUri"] != expectedImageURI { + t.Errorf("expected valueUri %s, got %v", expectedImageURI, imgNameCustomProps["valueUri"]) + } + + // Check source.disk.name listInput + diskObj, ok := sourceObjProps["disk"].(map[string]any) + if !ok { + t.Fatal("disk not found in source.properties") + } + diskObjProps, ok := diskObj["properties"].(map[string]any) + if !ok { + t.Fatal("disk.properties not found") + } + diskName, ok := diskObjProps["name"].(map[string]any) + if !ok { + t.Fatal("name not found in disk.properties") + } + if diskName["type"] != "listInput" { + t.Errorf("expected type listInput, got %v", diskName["type"]) + } + diskNameCustomProps, ok := diskName["customProps"].(map[string]any) + if !ok { + t.Fatal("disk name.customProps not found") + } + expectedDiskURI := "/api/clusters/{cluster}/k8s/apis/apps.cozystack.io/v1alpha1/namespaces/{namespace}/vmdisks" + if diskNameCustomProps["valueUri"] != expectedDiskURI { + t.Errorf("expected valueUri %s, got %v", expectedDiskURI, diskNameCustomProps["valueUri"]) + } +} + +func TestApplyListInputOverrides_StorageClassKafka(t *testing.T) { + schema := map[string]any{} + applyListInputOverrides(schema, "Kafka", map[string]any{}) + + specProps := schema["properties"].(map[string]any)["spec"].(map[string]any)["properties"].(map[string]any) + + kafkaSC, ok := specProps["kafka"].(map[string]any)["properties"].(map[string]any)["storageClass"].(map[string]any) + if !ok { + t.Fatal("storageClass not found in spec.kafka.properties") + } + assertStorageClassListInput(t, kafkaSC) + + zkSC, ok := specProps["zookeeper"].(map[string]any)["properties"].(map[string]any)["storageClass"].(map[string]any) + if !ok { + t.Fatal("storageClass not found in spec.zookeeper.properties") + } + assertStorageClassListInput(t, zkSC) +} + +// assertStorageClassListInput verifies that a field is a correctly configured storageClass listInput. +func assertStorageClassListInput(t *testing.T, field map[string]any) { + t.Helper() + if field["type"] != "listInput" { + t.Errorf("expected type listInput, got %v", field["type"]) + } + customProps, ok := field["customProps"].(map[string]any) + if !ok { + t.Fatal("customProps not found") + } + expectedURI := "/api/clusters/{cluster}/k8s/apis/storage.k8s.io/v1/storageclasses" + if customProps["valueUri"] != expectedURI { + t.Errorf("expected valueUri %s, got %v", expectedURI, customProps["valueUri"]) + } +} + +func TestApplyListInputOverrides_UnknownKind(t *testing.T) { + schema := map[string]any{} + applyListInputOverrides(schema, "SomeOtherKind", map[string]any{}) + + if len(schema) != 0 { + t.Errorf("expected empty schema for unknown kind, got %v", schema) + } +} + +func TestApplyListInputOverrides_NoDefault(t *testing.T) { + openAPIProps := map[string]any{ + "instanceType": map[string]any{"type": "string"}, + } + + schema := map[string]any{} + applyListInputOverrides(schema, "VMInstance", openAPIProps) + + specProps := schema["properties"].(map[string]any)["spec"].(map[string]any)["properties"].(map[string]any) + instanceType := specProps["instanceType"].(map[string]any) + + if _, exists := instanceType["default"]; exists { + t.Errorf("expected no default key, got %v", instanceType["default"]) + } +} + +func TestApplyListInputOverrides_MergesWithExistingSchema(t *testing.T) { + openAPIProps := map[string]any{ + "instanceType": map[string]any{"type": "string", "default": "u1.medium"}, + } + + // Simulate schema that already has spec.properties from buildMultilineStringSchema + schema := map[string]any{ + "properties": map[string]any{ + "spec": map[string]any{ + "properties": map[string]any{ + "otherField": map[string]any{"type": "multilineString"}, + }, + }, + }, + } + applyListInputOverrides(schema, "VMInstance", openAPIProps) + + specProps := schema["properties"].(map[string]any)["spec"].(map[string]any)["properties"].(map[string]any) + + // instanceType should be added + if _, ok := specProps["instanceType"].(map[string]any); !ok { + t.Fatal("instanceType not found after override") + } + + // otherField should be preserved + otherField, ok := specProps["otherField"].(map[string]any) + if !ok { + t.Fatal("otherField was lost after override") + } + if otherField["type"] != "multilineString" { + t.Errorf("otherField type changed, got %v", otherField["type"]) + } +} + +func TestParseOpenAPIProperties(t *testing.T) { + t.Run("extracts properties", func(t *testing.T) { + props := parseOpenAPIProperties(`{"type":"object","properties":{"instanceType":{"type":"string","default":"u1.medium"}}}`) + field, _ := props["instanceType"].(map[string]any) + if field["default"] != "u1.medium" { + t.Errorf("expected default u1.medium, got %v", field["default"]) + } + }) + + t.Run("empty string", func(t *testing.T) { + if props := parseOpenAPIProperties(""); props != nil { + t.Errorf("expected nil, got %v", props) + } + }) + + t.Run("invalid JSON", func(t *testing.T) { + if props := parseOpenAPIProperties("{bad"); props != nil { + t.Errorf("expected nil, got %v", props) + } + }) + + t.Run("no properties key", func(t *testing.T) { + if props := parseOpenAPIProperties(`{"type":"object"}`); props != nil { + t.Errorf("expected nil, got %v", props) + } + }) +} + +func TestEnsureSchemaPath(t *testing.T) { + t.Run("creates path from empty schema", func(t *testing.T) { + schema := map[string]any{} + props := ensureSchemaPath(schema, "spec") + + props["field"] = "value" + + // Verify structure: schema.properties.spec.properties.field + got := schema["properties"].(map[string]any)["spec"].(map[string]any)["properties"].(map[string]any)["field"] + if got != "value" { + t.Errorf("expected value, got %v", got) + } + }) + + t.Run("preserves existing nested properties", func(t *testing.T) { + schema := map[string]any{ + "properties": map[string]any{ + "spec": map[string]any{ + "properties": map[string]any{ + "existing": "keep", + }, + }, + }, + } + props := ensureSchemaPath(schema, "spec") + + if props["existing"] != "keep" { + t.Errorf("existing property lost, got %v", props["existing"]) + } + }) + + t.Run("multi-level path", func(t *testing.T) { + schema := map[string]any{} + props := ensureSchemaPath(schema, "spec", "nested") + + props["deep"] = true + + got := schema["properties"].(map[string]any)["spec"].(map[string]any)["properties"].(map[string]any)["nested"].(map[string]any)["properties"].(map[string]any)["deep"] + if got != true { + t.Errorf("expected true, got %v", got) + } + }) +} + +func TestEnsureArrayItemProps(t *testing.T) { + t.Run("creates from empty parent", func(t *testing.T) { + parent := map[string]any{} + props := ensureArrayItemProps(parent, "disks") + + props["name"] = map[string]any{"type": "listInput"} + + got := parent["disks"].(map[string]any)["items"].(map[string]any)["properties"].(map[string]any)["name"].(map[string]any)["type"] + if got != "listInput" { + t.Errorf("expected listInput, got %v", got) + } + }) + + t.Run("preserves existing item properties", func(t *testing.T) { + parent := map[string]any{ + "disks": map[string]any{ + "items": map[string]any{ + "properties": map[string]any{ + "bus": map[string]any{"type": "string"}, + }, + }, + }, + } + props := ensureArrayItemProps(parent, "disks") + props["name"] = map[string]any{"type": "listInput"} + + if props["bus"].(map[string]any)["type"] != "string" { + t.Error("existing bus property was lost") + } + if props["name"].(map[string]any)["type"] != "listInput" { + t.Error("name property was not added") + } + }) +} diff --git a/internal/controller/dashboard/customformsprefill.go b/internal/controller/dashboard/customformsprefill.go new file mode 100644 index 00000000..35d22ff1 --- /dev/null +++ b/internal/controller/dashboard/customformsprefill.go @@ -0,0 +1,81 @@ +package dashboard + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// ensureCustomFormsPrefill creates or updates a CustomFormsPrefill resource for the given CRD +func (m *Manager) ensureCustomFormsPrefill(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) (reconcile.Result, error) { + logger := log.FromContext(ctx) + + app := crd.Spec.Application + group, version, kind := pickGVK(crd) + plural := pickPlural(kind, crd) + + name := fmt.Sprintf("%s.%s.%s", group, version, plural) + customizationID := fmt.Sprintf("default-/%s/%s/%s", group, version, plural) + + values, err := buildPrefillValues(app.OpenAPISchema) + if err != nil { + return reconcile.Result{}, err + } + + // Always prefill metadata.name (empty string if not specified in CRD) + var nameValue string + if crd.Spec.Dashboard != nil { + nameValue = strings.TrimSpace(crd.Spec.Dashboard.Name) + } + values = append([]interface{}{ + map[string]interface{}{ + "path": toIfaceSlice([]string{"metadata", "name"}), + "value": nameValue, + }, + }, values...) + + cfp := &dashv1alpha1.CustomFormsPrefill{} + cfp.Name = name // cluster-scoped + + specMap := map[string]any{ + "customizationId": customizationID, + "values": values, + } + // Use json.Marshal with sorted keys to ensure consistent output + specBytes, err := json.Marshal(specMap) + if err != nil { + return reconcile.Result{}, err + } + + _, err = controllerutil.CreateOrUpdate(ctx, m.Client, cfp, func() error { + if err := controllerutil.SetOwnerReference(crd, cfp, m.Scheme); err != nil { + return err + } + // Add dashboard labels to dynamic resources + m.addDashboardLabels(cfp, crd, ResourceTypeDynamic) + + // Only update spec if it's different to avoid unnecessary updates + newSpec := dashv1alpha1.ArbitrarySpec{ + JSON: apiextv1.JSON{Raw: specBytes}, + } + if !compareArbitrarySpecs(cfp.Spec, newSpec) { + cfp.Spec = newSpec + } + return nil + }) + if err != nil { + return reconcile.Result{}, err + } + + logger.Info("Applied CustomFormsPrefill", "name", cfp.Name) + return reconcile.Result{}, nil +} diff --git a/internal/controller/dashboard/factory.go b/internal/controller/dashboard/factory.go new file mode 100644 index 00000000..fe0cadfd --- /dev/null +++ b/internal/controller/dashboard/factory.go @@ -0,0 +1,627 @@ +package dashboard + +import ( + "context" + "encoding/json" + "fmt" + "sort" + "strings" + + dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +// ensureFactory creates or updates a Factory resource for the given CRD +func (m *Manager) ensureFactory(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error { + g, v, kind := pickGVK(crd) + plural := pickPlural(kind, crd) + + lowerKind := strings.ToLower(kind) + factoryName := fmt.Sprintf("%s-details", lowerKind) + resourceFetch := fmt.Sprintf("/api/clusters/{2}/k8s/apis/%s/%s/namespaces/{3}/%s/{6}", g, v, plural) + + flags := factoryFeatureFlags(crd) + + var keysOrder [][]string + if crd.Spec.Dashboard != nil { + keysOrder = crd.Spec.Dashboard.KeysOrder + } + tabs := []any{ + detailsTab(kind, resourceFetch, crd.Spec.Application.OpenAPISchema, keysOrder), + } + if flags.Workloads { + tabs = append(tabs, workloadsTab(kind)) + } + if flags.Ingresses { + tabs = append(tabs, ingressesTab(kind)) + } + if flags.Services { + tabs = append(tabs, servicesTab(kind)) + } + if flags.Secrets { + tabs = append(tabs, secretsTab(kind)) + } + if prefix, ok := vncTabPrefix(kind); ok { + tabs = append(tabs, vncTab(prefix)) + } + tabs = append(tabs, eventsTab(kind)) + tabs = append(tabs, yamlTab(g, v, plural)) + + // Use unified factory creation + config := UnifiedResourceConfig{ + Name: factoryName, + ResourceType: "factory", + Kind: kind, + Plural: plural, + Title: strings.ToLower(plural), + } + + spec := createUnifiedFactory(config, tabs, []any{resourceFetch}) + + obj := &dashv1alpha1.Factory{} + obj.SetName(factoryName) + + _, err := controllerutil.CreateOrUpdate(ctx, m.Client, obj, func() error { + if err := controllerutil.SetOwnerReference(crd, obj, m.Scheme); err != nil { + return err + } + // Add dashboard labels to dynamic resources + m.addDashboardLabels(obj, crd, ResourceTypeDynamic) + b, err := json.Marshal(spec) + if err != nil { + return err + } + + // Only update spec if it's different to avoid unnecessary updates + newSpec := dashv1alpha1.ArbitrarySpec{JSON: apiextv1.JSON{Raw: b}} + if !compareArbitrarySpecs(obj.Spec, newSpec) { + obj.Spec = newSpec + } + return nil + }) + return err +} + +// ---------------- Tabs builders ---------------- + +func detailsTab(kind, endpoint, schemaJSON string, keysOrder [][]string) map[string]any { + paramsBlocks := buildOpenAPIParamsBlocks(schemaJSON, keysOrder) + paramsList := map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "params-list", + "vertical": true, + "gap": float64(24), + }, + "children": paramsBlocks, + } + + leftColStack := []any{ + antdText("details-title", true, kind, map[string]any{ + "fontSize": float64(20), + "marginBottom": float64(12), + }), + antdFlexVertical("meta-name-block", 4, []any{ + antdText("meta-name-label", true, "Name", nil), + parsedText("meta-name-value", "{reqsJsonPath[0]['.metadata.name']['-']}", nil), + }), + antdFlexVertical("meta-namespace-block", 8, []any{ + antdText("meta-namespace-label", true, "Namespace", nil), + map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "namespace-row", + "align": "center", + "gap": float64(6), + }, + "children": []any{ + createUnifiedBadgeFromKind("ns-badge", "Namespace"), + antdLink("namespace-link", + "{reqsJsonPath[0]['.metadata.namespace']['-']}", + "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace", + ), + }, + }, + }), + antdFlexVertical("meta-created-block", 4, []any{ + antdText("time-label", true, "Created", nil), + antdFlex("time-block", 6, []any{ + antdText("time-icon", false, "🌐", nil), + parsedTextWithFormatter("time-value", "{reqsJsonPath[0]['.metadata.creationTimestamp']['-']}", "timestamp"), + }), + }), + antdFlexVertical("meta-version-block", 4, []any{ + antdText("version-label", true, "Version", nil), + parsedText("version-value", "{reqsJsonPath[0]['.status.version']['-']}", nil), + }), + antdFlexVertical("meta-released-block", 4, []any{ + antdText("released-label", true, "Released", nil), + parsedText("released-value", "{reqsJsonPath[0]['.status.conditions[?(@.type==\"Released\")].status']['-']}", nil), + }), + antdFlexVertical("meta-ready-block", 4, []any{ + antdText("ready-label", true, "Ready", nil), + parsedText("ready-value", "{reqsJsonPath[0]['.status.conditions[?(@.type==\"Ready\")].status']['-']}", nil), + }), + } + + rightColStack := []any{ + antdText("params-title", true, "Parameters", map[string]any{ + "fontSize": float64(20), + "marginBottom": float64(12), + }), + paramsList, + } + if kind == "VirtualPrivateCloud" { + rightColStack = append(rightColStack, + antdFlexVertical("vpc-subnets-block", 4, []any{ + antdText("vpc-subnets-label", true, "Subnets", nil), + map[string]any{ + "type": "EnrichedTable", + "data": map[string]any{ + "id": "vpc-subnets-table", + "baseprefix": "/openapi-ui", + "cluster": "{2}", + "customizationId": "virtualprivatecloud-subnets", + "fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/configmaps", + "fieldSelector": map[string]any{ + "metadata.name": "virtualprivatecloud-{6}-subnets", + }, + "pathToItems": []any{"items"}, + }, + }, + }), + ) + } + if kind == "Tenant" { + leftColStack = append(leftColStack, antdFlexVertical("tenant-external-ip-count", 4, []any{ + antdText("tenant-external-ip-count-label", true, "External IPs count", nil), + parsedText("tenant-external-ip-count-value", `{reqsJsonPath[0]['.status.externalIPsCount']['0']}`, nil), + })) + rightColStack = append(rightColStack, + antdFlexVertical("resource-quotas-block", 4, []any{ + antdText("resource-quotas-label", true, "Resource Quotas", map[string]any{ + "fontSize": float64(20), + "marginBottom": float64(12), + }), + map[string]any{ + "type": "EnrichedTable", + "data": map[string]any{ + "id": "resource-quotas-table", + "baseprefix": "/openapi-ui", + "cluster": "{2}", + "customizationId": "factory-resource-quotas", + "fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{reqsJsonPath[0]['.status.namespace']}/resourcequotas", + "pathToItems": []any{`items`}, + }, + }, + }), + ) + } + + return map[string]any{ + "key": "details", + "label": "Details", + "children": []any{ + contentCard("details-card", map[string]any{"marginBottom": float64(24)}, []any{ + map[string]any{ + "type": "antdRow", + "data": map[string]any{ + "id": "details-grid", + "gutter": []any{float64(48), float64(12)}, + }, + "children": []any{ + map[string]any{ + "type": "antdCol", + "data": map[string]any{"id": "col-left", "span": float64(12)}, + "children": []any{ + map[string]any{ + "type": "antdFlex", + "data": map[string]any{"id": "col-left-stack", "vertical": true, "gap": float64(24)}, + "children": leftColStack, + }, + }, + }, + map[string]any{ + "type": "antdCol", + "data": map[string]any{"id": "col-right", "span": float64(12)}, + "children": []any{ + map[string]any{ + "type": "antdFlex", + "data": map[string]any{"id": "col-right-stack", "vertical": true, "gap": float64(24)}, + "children": rightColStack, + }, + }, + }, + }, + }, + spacer("conditions-top-spacer", float64(16)), + antdText("conditions-title", true, "Conditions", map[string]any{"fontSize": float64(20)}), + spacer("conditions-spacer", float64(8)), + map[string]any{ + "type": "EnrichedTable", + "data": map[string]any{ + "id": "conditions-table", + "fetchUrl": endpoint, + "cluster": "{2}", + "customizationId": "factory-status-conditions", + "baseprefix": "/openapi-ui", + "withoutControls": true, + "pathToItems": []any{"status", "conditions"}, + }, + }, + }), + }, + } +} + +func workloadsTab(kind string) map[string]any { + return map[string]any{ + "key": "workloads", + "label": "Workloads", + "children": []any{ + map[string]any{ + "type": "EnrichedTable", + "data": map[string]any{ + "id": "workloads-table", + "fetchUrl": "/api/clusters/{2}/k8s/apis/cozystack.io/v1alpha1/namespaces/{3}/workloadmonitors", + "cluster": "{2}", + "baseprefix": "/openapi-ui", + "customizationId": "factory-details-v1alpha1.cozystack.io.workloadmonitors", + "pathToItems": []any{"items"}, + "labelSelector": map[string]any{ + "apps.cozystack.io/application.group": "apps.cozystack.io", + "apps.cozystack.io/application.kind": kind, + "apps.cozystack.io/application.name": "{reqs[0]['metadata','name']}", + }, + }, + }, + }, + } +} + +func servicesTab(kind string) map[string]any { + return map[string]any{ + "key": "services", + "label": "Services", + "children": []any{ + map[string]any{ + "type": "EnrichedTable", + "data": map[string]any{ + "id": "services-table", + "fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/services", + "cluster": "{2}", + "baseprefix": "/openapi-ui", + "customizationId": "factory-details-v1.services", + "pathToItems": []any{"items"}, + "labelSelector": map[string]any{ + "apps.cozystack.io/application.group": "apps.cozystack.io", + "apps.cozystack.io/application.kind": kind, + "apps.cozystack.io/application.name": "{reqs[0]['metadata','name']}", + "internal.cozystack.io/tenantresource": "true", + }, + }, + }, + }, + } +} + +func ingressesTab(kind string) map[string]any { + return map[string]any{ + "key": "ingresses", + "label": "Ingresses", + "children": []any{ + map[string]any{ + "type": "EnrichedTable", + "data": map[string]any{ + "id": "ingresses-table", + "fetchUrl": "/api/clusters/{2}/k8s/apis/networking.k8s.io/v1/namespaces/{3}/ingresses", + "cluster": "{2}", + "baseprefix": "/openapi-ui", + "customizationId": "factory-details-networking.k8s.io.v1.ingresses", + "pathToItems": []any{"items"}, + "labelSelector": map[string]any{ + "apps.cozystack.io/application.group": "apps.cozystack.io", + "apps.cozystack.io/application.kind": kind, + "apps.cozystack.io/application.name": "{reqs[0]['metadata','name']}", + "internal.cozystack.io/tenantresource": "true", + }, + }, + }, + }, + } +} + +func secretsTab(kind string) map[string]any { + return map[string]any{ + "key": "secrets", + "label": "Secrets", + "children": []any{ + map[string]any{ + "type": "EnrichedTable", + "data": map[string]any{ + "id": "secrets-table", + "fetchUrl": "/api/clusters/{2}/k8s/apis/core.cozystack.io/v1alpha1/namespaces/{3}/tenantsecrets", + "cluster": "{2}", + "baseprefix": "/openapi-ui", + "customizationId": "factory-details-v1alpha1.core.cozystack.io.tenantsecrets", + "pathToItems": []any{"items"}, + "labelSelector": map[string]any{ + "apps.cozystack.io/application.group": "apps.cozystack.io", + "apps.cozystack.io/application.kind": kind, + "apps.cozystack.io/application.name": "{reqs[0]['metadata','name']}", + }, + }, + }, + }, + } +} + +// eventsTab shows Kubernetes Events scoped to the application's namespace. +// Events are namespace-scoped because Kubernetes Events don't carry application +// labels and cannot be filtered by label selector. In Cozystack's multi-tenancy +// model, each tenant namespace maps to a single application scope, so namespace +// filtering provides the correct event scope. +// For Tenant applications, events are fetched from status.namespace (the tenant's +// own namespace) instead of the parent namespace where the Tenant object lives. +func eventsTab(kind string) map[string]any { + nsPlaceholder := "{3}" + if kind == "Tenant" { + nsPlaceholder = "{reqsJsonPath[0]['.status.namespace']}" + } + return map[string]any{ + "key": "events", + "label": "Events", + "children": []any{ + map[string]any{ + "type": "EnrichedTable", + "data": map[string]any{ + "id": "events-table", + "fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/" + nsPlaceholder + "/events", + "cluster": "{2}", + "baseprefix": "/openapi-ui", + "customizationId": "factory-details-events", + "pathToItems": []any{"items"}, + }, + }, + }, + } +} + +func yamlTab(group, version, plural string) map[string]any { + return map[string]any{ + "key": "yaml", + "label": "YAML", + "children": []any{ + map[string]any{ + "type": "YamlEditorSingleton", + "data": map[string]any{ + "id": "yaml-editor", + "cluster": "{2}", + "isNameSpaced": true, + "type": "apis", + "apiGroup": group, + "apiVersion": version, + "plural": plural, + "prefillValuesRequestIndex": float64(0), + "readOnly": true, + "substractHeight": float64(400), + }, + }, + }, + } +} + +func vncTabPrefix(kind string) (string, bool) { + switch kind { + case "VirtualMachine": + return "virtual-machine", true + case "VMInstance": + return "vm-instance", true + default: + return "", false + } +} + +func vncTab(prefix string) map[string]any { + return map[string]any{ + "key": "vnc", + "label": "VNC", + "children": []any{ + map[string]any{ + "type": "VMVNC", + "data": map[string]any{ + "id": "vm-vnc", + "cluster": "{2}", + "namespace": "{reqsJsonPath[0]['.metadata.namespace']['-']}", + "substractHeight": float64(400), + "vmName": fmt.Sprintf("%s-{reqsJsonPath[0]['.metadata.name']['-']}", prefix), + }, + }, + }, + } +} + +// ---------------- OpenAPI → Right column ---------------- + +func buildOpenAPIParamsBlocks(schemaJSON string, keysOrder [][]string) []any { + var blocks []any + fields := collectOpenAPILeafFields(schemaJSON, 2, 20) + + // Sort fields according to keysOrder if provided + if len(keysOrder) > 0 { + fields = sortFieldsByKeysOrder(fields, keysOrder) + } + + for idx, f := range fields { + id := fmt.Sprintf("param-%d", idx) + blocks = append(blocks, + antdFlexVertical(id, 4, []any{ + antdText(id+"-label", true, f.Label, nil), + parsedText(id+"-value", fmt.Sprintf("{reqsJsonPath[0]['.spec.%s']['-']}", f.JSONPathSpec), nil), + }), + ) + } + if len(fields) == 0 { + blocks = append(blocks, + antdText("params-empty", false, "No scalar parameters detected in schema (see YAML tab for full spec).", map[string]any{"opacity": float64(0.7)}), + ) + } + return blocks +} + +// sortFieldsByKeysOrder sorts fields according to the provided keysOrder +func sortFieldsByKeysOrder(fields []fieldInfo, keysOrder [][]string) []fieldInfo { + // Create a map for quick lookup of field positions + orderMap := make(map[string]int) + for i, path := range keysOrder { + // Convert path to dot notation (e.g., ["spec", "systemDisk", "image"] -> "systemDisk.image") + if len(path) > 1 && path[0] == "spec" { + dotPath := strings.Join(path[1:], ".") + orderMap[dotPath] = i + } + } + + // Sort fields based on their position in keysOrder + sort.Slice(fields, func(i, j int) bool { + posI, existsI := orderMap[fields[i].JSONPathSpec] + posJ, existsJ := orderMap[fields[j].JSONPathSpec] + + // If both exist in orderMap, sort by position + if existsI && existsJ { + return posI < posJ + } + // If only one exists, prioritize the one that exists + if existsI { + return true + } + if existsJ { + return false + } + // If neither exists, maintain original order (stable sort) + return i < j + }) + + return fields +} + +func collectOpenAPILeafFields(schemaJSON string, maxDepth, maxFields int) []fieldInfo { + type node = map[string]any + + if strings.TrimSpace(schemaJSON) == "" { + return nil + } + + var root any + if err := json.Unmarshal([]byte(schemaJSON), &root); err != nil { + // invalid JSON — skip + return nil + } + + props := map[string]any{} + if m, ok := root.(node); ok { + if p, ok := m["properties"].(node); ok { + props = p + } + } + if len(props) == 0 { + return nil + } + + var out []fieldInfo + var visit func(prefix []string, n node, depth int) + + addField := func(path []string, schema node) { + // Skip excluded paths (backup/bootstrap/password) + if shouldExcludeParamPath(path) { + return + } + // build label "Foo Bar / Baz" + label := humanizePath(path) + desc := getString(schema, "description") + out = append(out, fieldInfo{ + JSONPathSpec: strings.Join(path, "."), + Label: label, + Description: desc, + }) + } + + visit = func(prefix []string, n node, depth int) { + if len(out) >= maxFields { + return + } + // Scalar? + if isScalarType(n) || isIntOrString(n) || hasEnum(n) { + addField(prefix, n) + return + } + // Object with properties + if props, ok := n["properties"].(node); ok { + if depth >= maxDepth { + // too deep — stop + return + } + // deterministic ordering + keys := make([]string, 0, len(props)) + for k := range props { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + child, _ := props[k].(node) + visit(append(prefix, k), child, depth+1) + if len(out) >= maxFields { + return + } + } + return + } + // Arrays: try to render item if it's scalar and depth limit allows + if n["type"] == "array" { + if items, ok := n["items"].(node); ok && (isScalarType(items) || isIntOrString(items) || hasEnum(items)) { + addField(prefix, items) + } + return + } + // Otherwise skip (unknown/complex) + } + + // top-level: iterate properties + keys := make([]string, 0, len(props)) + for k := range props { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + if child, ok := props[k].(node); ok { + visit([]string{k}, child, 1) + if len(out) >= maxFields { + break + } + } + } + return out +} + +// ---------------- Feature flags ---------------- + +type factoryFlags struct { + Workloads bool + Ingresses bool + Services bool + Secrets bool +} + +// factoryFeatureFlags determines which tabs to show based on whether the +// ApplicationDefinition has non-empty Include resource selectors. +// Workloads tab is always shown. +func factoryFeatureFlags(crd *cozyv1alpha1.ApplicationDefinition) factoryFlags { + return factoryFlags{ + Workloads: true, + Ingresses: len(crd.Spec.Ingresses.Include) > 0, + Services: len(crd.Spec.Services.Include) > 0, + Secrets: len(crd.Spec.Secrets.Include) > 0, + } +} diff --git a/internal/controller/dashboard/factory_test.go b/internal/controller/dashboard/factory_test.go new file mode 100644 index 00000000..b3742564 --- /dev/null +++ b/internal/controller/dashboard/factory_test.go @@ -0,0 +1,60 @@ +package dashboard + +import ( + "testing" +) + +func TestEventsTab_Structure(t *testing.T) { + tab := eventsTab("PostgreSQL") + + if tab["key"] != "events" { + t.Errorf("expected key=events, got %v", tab["key"]) + } + if tab["label"] != "Events" { + t.Errorf("expected label=Events, got %v", tab["label"]) + } + + children, ok := tab["children"].([]any) + if !ok || len(children) != 1 { + t.Fatal("expected exactly 1 child in events tab") + } + + table, ok := children[0].(map[string]any) + if !ok { + t.Fatal("child is not a map") + } + if table["type"] != "EnrichedTable" { + t.Errorf("expected type=EnrichedTable, got %v", table["type"]) + } + + data, ok := table["data"].(map[string]any) + if !ok { + t.Fatal("table data is not a map") + } + if data["id"] != "events-table" { + t.Errorf("expected id=events-table, got %v", data["id"]) + } + if data["fetchUrl"] != "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/events" { + t.Errorf("unexpected fetchUrl for non-Tenant: %v", data["fetchUrl"]) + } + if data["customizationId"] != "factory-details-events" { + t.Errorf("expected customizationId=factory-details-events, got %v", data["customizationId"]) + } + + pathToItems, ok := data["pathToItems"].([]any) + if !ok || len(pathToItems) != 1 || pathToItems[0] != "items" { + t.Errorf("expected pathToItems=[items], got %v", data["pathToItems"]) + } +} + +func TestEventsTab_TenantUsesStatusNamespace(t *testing.T) { + tab := eventsTab("Tenant") + children := tab["children"].([]any) + table := children[0].(map[string]any) + data := table["data"].(map[string]any) + + expectedURL := "/api/clusters/{2}/k8s/api/v1/namespaces/{reqsJsonPath[0]['.status.namespace']}/events" + if data["fetchUrl"] != expectedURL { + t.Errorf("expected Tenant fetchUrl to use status.namespace, got %v", data["fetchUrl"]) + } +} diff --git a/internal/controller/dashboard/helpers.go b/internal/controller/dashboard/helpers.go new file mode 100644 index 00000000..2a35bbff --- /dev/null +++ b/internal/controller/dashboard/helpers.go @@ -0,0 +1,442 @@ +package dashboard + +import ( + "encoding/json" + "fmt" + "reflect" + "sort" + "strings" + + dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" +) + +// ---------------- Types used by OpenAPI parsing ---------------- + +type fieldInfo struct { + JSONPathSpec string // dotted path under .spec (e.g., "systemDisk.image") + Label string // "System Disk / Image" or "systemDisk.image" + Description string +} + +// ---------------- Public entry: ensure Factory ------------------ + +// pickGVK tries to read group/version/kind from the CRD. We prefer the "application" section, +// falling back to other likely fields if your schema differs. +func pickGVK(crd *cozyv1alpha1.ApplicationDefinition) (group, version, kind string) { + // Best guess based on your examples: + if crd.Spec.Application.Kind != "" { + kind = crd.Spec.Application.Kind + } + + // For applications, always use apps.cozystack.io group, not the CRD's own group + group = "apps.cozystack.io" + version = "v1alpha1" + + // Reasonable fallbacks if any are empty: + if kind == "" { + kind = "Resource" + } + return +} + +// pickPlural prefers a field on the CRD if you have it; otherwise do a simple lowercase + "s". +func pickPlural(kind string, crd *cozyv1alpha1.ApplicationDefinition) string { + // If you have crd.Spec.Application.Plural, prefer it. Example: + if crd.Spec.Application.Plural != "" { + return crd.Spec.Application.Plural + } + // naive pluralization + k := strings.ToLower(kind) + if strings.HasSuffix(k, "s") { + return k + } + return k + "s" +} + +// ----------------------- Helpers (OpenAPI → values) ----------------------- + +// defaultOrZero returns the schema default if present; otherwise a reasonable zero value. +func defaultOrZero(sub map[string]interface{}) interface{} { + if v, ok := sub["default"]; ok { + return v + } + typ, _ := sub["type"].(string) + switch typ { + case "string": + return "" + case "boolean": + return false + case "array": + return []interface{}{} + case "integer", "number": + return 0 + case "object": + return map[string]interface{}{} + default: + return nil + } +} + +// toIfaceSlice converts []string -> []interface{}. +func toIfaceSlice(ss []string) []interface{} { + out := make([]interface{}, len(ss)) + for i, s := range ss { + out[i] = s + } + return out +} + +// buildPrefillValues converts an OpenAPI schema (JSON string) into a []interface{} "values" list +// suitable for CustomFormsPrefill.spec.values. +// Rules: +// - For top-level primitive/array fields: emit an entry, using default if present, otherwise zero. +// - For top-level objects: recursively process nested objects and emit entries for all default values +// found at any nesting level. +func buildPrefillValues(openAPISchema string) ([]interface{}, error) { + var root map[string]interface{} + if err := json.Unmarshal([]byte(openAPISchema), &root); err != nil { + return nil, fmt.Errorf("cannot parse openAPISchema: %w", err) + } + props, _ := root["properties"].(map[string]interface{}) + if props == nil { + return []interface{}{}, nil + } + + var values []interface{} + processSchemaProperties(props, []string{"spec"}, &values, true) + return values, nil +} + +// processSchemaProperties recursively processes OpenAPI schema properties and extracts default values +func processSchemaProperties(props map[string]interface{}, path []string, values *[]interface{}, topLevel bool) { + for pname, raw := range props { + sub, _ := raw.(map[string]interface{}) + if sub == nil { + continue + } + + typ, _ := sub["type"].(string) + currentPath := append(path, pname) + + switch typ { + case "object": + // Check if this object has a default value + if objDefault, ok := sub["default"].(map[string]interface{}); ok { + // Process the default object recursively + processDefaultObject(objDefault, currentPath, values) + } + + // Also process child properties for their individual defaults + if childProps, ok := sub["properties"].(map[string]interface{}); ok { + processSchemaProperties(childProps, currentPath, values, false) + } + default: + // For primitive types, use default if present, otherwise zero value + val := defaultOrZero(sub) + // Only emit zero-value entries when at top level + if val != nil || topLevel { + entry := map[string]interface{}{ + "path": toIfaceSlice(currentPath), + "value": val, + } + *values = append(*values, entry) + } + } + } +} + +// processDefaultObject recursively processes a default object and creates entries for all nested values +func processDefaultObject(obj map[string]interface{}, path []string, values *[]interface{}) { + for key, value := range obj { + currentPath := append(path, key) + + // If the value is a map, process it recursively + if nestedObj, ok := value.(map[string]interface{}); ok { + processDefaultObject(nestedObj, currentPath, values) + } else { + // For primitive values, create an entry + entry := map[string]interface{}{ + "path": toIfaceSlice(currentPath), + "value": value, + } + *values = append(*values, entry) + } + } +} + +// normalizeJSON makes maps/slices JSON-safe for k8s Unstructured: +// - converts all int/int32/... to float64 +// - leaves strings, bools, nil as-is +func normalizeJSON(v any) any { + switch t := v.(type) { + case map[string]any: + out := make(map[string]any, len(t)) + for k, val := range t { + out[k] = normalizeJSON(val) + } + return out + case []any: + out := make([]any, len(t)) + for i := range t { + out[i] = normalizeJSON(t[i]) + } + return out + case int: + return float64(t) + case int8: + return float64(t) + case int16: + return float64(t) + case int32: + return float64(t) + case int64: + return float64(t) + case uint, uint8, uint16, uint32, uint64: + return float64(reflect.ValueOf(t).Convert(reflect.TypeOf(uint64(0))).Uint()) + case float32: + return float64(t) + default: + return v + } +} + +// --- helpers for schema inspection --- + +func isScalarType(n map[string]any) bool { + switch getString(n, "type") { + case "string", "integer", "number", "boolean": + return true + default: + return false + } +} + +func isIntOrString(n map[string]any) bool { + // Kubernetes extension: x-kubernetes-int-or-string: true + if v, ok := n["x-kubernetes-int-or-string"]; ok { + if b, ok := v.(bool); ok && b { + return true + } + } + // anyOf: integer|string + if anyOf, ok := n["anyOf"].([]any); ok { + hasInt := false + hasStr := false + for _, it := range anyOf { + if m, ok := it.(map[string]any); ok { + switch getString(m, "type") { + case "integer": + hasInt = true + case "string": + hasStr = true + } + } + } + return hasInt && hasStr + } + return false +} + +func hasEnum(n map[string]any) bool { + _, ok := n["enum"] + return ok +} + +func getString(n map[string]any, key string) string { + if v, ok := n[key]; ok { + if s, ok := v.(string); ok { + return s + } + } + return "" +} + +// shouldExcludeParamPath returns true if any part of the path contains +// backup / bootstrap / password (case-insensitive) +func shouldExcludeParamPath(parts []string) bool { + for _, p := range parts { + lp := strings.ToLower(p) + if strings.Contains(lp, "backup") || strings.Contains(lp, "bootstrap") || strings.Contains(lp, "password") || strings.Contains(lp, "cloudinit") { + return true + } + } + return false +} + +func humanizePath(parts []string) string { + // "systemDisk.image" -> "System Disk / Image" + return strings.Join(parts, " / ") +} + +// titleFromKindPlural returns a presentable plural label, e.g.: +// kind="VirtualMachine", plural="virtualmachines" => "VirtualMachines" +func titleFromKindPlural(kind, plural string) string { + return kind + "s" +} + +// The hidden lists below mirror the Helm templates you shared. +// Each entry is a path as nested string array, e.g. ["metadata","creationTimestamp"]. + +func hiddenMetadataSystem() []any { + return []any{ + []any{"metadata", "annotations"}, + []any{"metadata", "labels"}, + []any{"metadata", "namespace"}, + []any{"metadata", "creationTimestamp"}, + []any{"metadata", "deletionGracePeriodSeconds"}, + []any{"metadata", "deletionTimestamp"}, + []any{"metadata", "finalizers"}, + []any{"metadata", "generateName"}, + []any{"metadata", "generation"}, + []any{"metadata", "managedFields"}, + []any{"metadata", "ownerReferences"}, + []any{"metadata", "resourceVersion"}, + []any{"metadata", "selfLink"}, + []any{"metadata", "uid"}, + } +} + +func hiddenMetadataAPI() []any { + return []any{ + []any{"kind"}, + []any{"apiVersion"}, + []any{"appVersion"}, + } +} + +func hiddenStatus() []any { + return []any{ + []any{"status"}, + } +} + +// compareArbitrarySpecs compares two ArbitrarySpec objects by comparing their JSON content +func compareArbitrarySpecs(spec1, spec2 dashv1alpha1.ArbitrarySpec) bool { + // If both are empty, they're equal + if len(spec1.JSON.Raw) == 0 && len(spec2.JSON.Raw) == 0 { + return true + } + + // If one is empty and the other is not, they're different + if len(spec1.JSON.Raw) == 0 || len(spec2.JSON.Raw) == 0 { + return false + } + + // Parse and normalize both specs + norm1, err := normalizeJSONForComparison(spec1.JSON.Raw) + if err != nil { + return false + } + norm2, err := normalizeJSONForComparison(spec2.JSON.Raw) + if err != nil { + return false + } + + // Compare normalized JSON + equal := string(norm1) == string(norm2) + + return equal +} + +// normalizeJSONForComparison normalizes JSON by sorting arrays and objects +func normalizeJSONForComparison(data []byte) ([]byte, error) { + var obj interface{} + if err := json.Unmarshal(data, &obj); err != nil { + return nil, err + } + + // Recursively normalize the object + normalized := normalizeObject(obj) + + // Re-marshal to get normalized JSON + return json.Marshal(normalized) +} + +// normalizeObject recursively normalizes objects and arrays +func normalizeObject(obj interface{}) interface{} { + switch v := obj.(type) { + case map[string]interface{}: + // For maps, we don't need to sort keys as json.Marshal handles that + result := make(map[string]interface{}) + for k, val := range v { + result[k] = normalizeObject(val) + } + return result + case []interface{}: + // For arrays, we need to sort them if they contain objects with comparable fields + if len(v) == 0 { + return v + } + + // Check if this is an array of objects that can be sorted + if canSortArray(v) { + // Sort the array + sorted := make([]interface{}, len(v)) + copy(sorted, v) + sortArray(sorted) + return sorted + } + + // If we can't sort, just normalize each element + result := make([]interface{}, len(v)) + for i, val := range v { + result[i] = normalizeObject(val) + } + return result + default: + return v + } +} + +// canSortArray checks if an array can be sorted (contains objects with comparable fields) +func canSortArray(arr []interface{}) bool { + if len(arr) == 0 { + return false + } + + // Check if all elements are objects + for _, item := range arr { + if _, ok := item.(map[string]interface{}); !ok { + return false + } + } + + // Check if objects have comparable fields (like "path" for CustomFormsPrefill values) + firstObj, ok := arr[0].(map[string]interface{}) + if !ok { + return false + } + + // Look for "path" field which is used in CustomFormsPrefill values + if _, hasPath := firstObj["path"]; hasPath { + return true + } + + return false +} + +// sortArray sorts an array of objects by their "path" field +func sortArray(arr []interface{}) { + sort.Slice(arr, func(i, j int) bool { + objI, okI := arr[i].(map[string]interface{}) + objJ, okJ := arr[j].(map[string]interface{}) + + if !okI || !okJ { + return false + } + + pathI, hasPathI := objI["path"] + pathJ, hasPathJ := objJ["path"] + + if !hasPathI || !hasPathJ { + return false + } + + // Convert paths to strings for comparison + pathIStr := fmt.Sprintf("%v", pathI) + pathJStr := fmt.Sprintf("%v", pathJ) + + return pathIStr < pathJStr + }) +} diff --git a/internal/controller/dashboard/manager.go b/internal/controller/dashboard/manager.go new file mode 100644 index 00000000..42c641ad --- /dev/null +++ b/internal/controller/dashboard/manager.go @@ -0,0 +1,475 @@ +package dashboard + +import ( + "context" + "fmt" + "strings" + + dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + managerpkg "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +const ( + // Label keys for dashboard resource management + LabelManagedBy = "dashboard.cozystack.io/managed-by" + LabelResourceType = "dashboard.cozystack.io/resource-type" + LabelCRDName = "dashboard.cozystack.io/crd-name" + LabelCRDGroup = "dashboard.cozystack.io/crd-group" + LabelCRDVersion = "dashboard.cozystack.io/crd-version" + LabelCRDKind = "dashboard.cozystack.io/crd-kind" + LabelCRDPlural = "dashboard.cozystack.io/crd-plural" + + // Label values + ManagedByValue = "cozystack-dashboard-controller" + ResourceTypeStatic = "static" + ResourceTypeDynamic = "dynamic" +) + +// AddToScheme exposes dashboard types registration for controller setup. +func AddToScheme(s *runtime.Scheme) error { + return dashv1alpha1.AddToScheme(s) +} + +// Manager owns logic for creating/updating dashboard resources derived from CRDs. +// It’s easy to extend: add new ensure* methods and wire them into EnsureForAppDef. +type Manager struct { + client.Client + Scheme *runtime.Scheme +} + +// NewManager constructs a dashboard Manager. +func NewManager(c client.Client, scheme *runtime.Scheme) *Manager { + m := &Manager{Client: c, Scheme: scheme} + return m +} + +func (m *Manager) SetupWithManager(mgr ctrl.Manager) error { + if err := ctrl.NewControllerManagedBy(mgr). + Named("dashboard-reconciler"). + For(&cozyv1alpha1.ApplicationDefinition{}). + Complete(m); err != nil { + return err + } + + return mgr.Add(managerpkg.RunnableFunc(func(ctx context.Context) error { + if !mgr.GetCache().WaitForCacheSync(ctx) { + return fmt.Errorf("dashboard static resources cache sync failed") + } + return m.ensureStaticResources(ctx) + })) +} + +func (m *Manager) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + l := log.FromContext(ctx) + + crd := &cozyv1alpha1.ApplicationDefinition{} + + err := m.Get(ctx, types.NamespacedName{Name: req.Name}, crd) + if err != nil { + if apierrors.IsNotFound(err) { + if err := m.CleanupOrphanedResources(ctx); err != nil { + l.Error(err, "Failed to cleanup orphaned dashboard resources") + } + return ctrl.Result{}, nil // no point in requeuing here + } + return ctrl.Result{}, err + } + + return m.EnsureForAppDef(ctx, crd) +} + +// EnsureForAppDef is the single entry-point used by the controller. +// Add more ensure* calls here as you implement support for other resources: +// +// - ensureBreadcrumb (implemented) +// - ensureCustomColumnsOverride (implemented) +// - ensureCustomFormsOverride (implemented) +// - ensureCustomFormsPrefill (implemented) +// - ensureFactory +// - ensureMarketplacePanel (implemented) +// - ensureSidebar (implemented) +// - ensureTableUriMapping (implemented) +func (m *Manager) EnsureForAppDef(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) (reconcile.Result, error) { + // Early return if crd.Spec.Dashboard is nil to prevent oscillation + if crd.Spec.Dashboard == nil { + return reconcile.Result{}, nil + } + + // MarketplacePanel + if res, err := m.ensureMarketplacePanel(ctx, crd); err != nil || res.Requeue || res.RequeueAfter > 0 { + return res, err + } + + // CustomFormsPrefill + if res, err := m.ensureCustomFormsPrefill(ctx, crd); err != nil || res.Requeue || res.RequeueAfter > 0 { + return res, err + } + + // CustomColumnsOverride + if _, err := m.ensureCustomColumnsOverride(ctx, crd); err != nil { + return reconcile.Result{}, err + } + + if err := m.ensureTableUriMapping(ctx, crd); err != nil { + return reconcile.Result{}, err + } + + if err := m.ensureBreadcrumb(ctx, crd); err != nil { + return reconcile.Result{}, err + } + + if err := m.ensureCustomFormsOverride(ctx, crd); err != nil { + return reconcile.Result{}, err + } + + if err := m.ensureCFOMapping(ctx, crd); err != nil { + return reconcile.Result{}, err + } + + if err := m.ensureSidebar(ctx, crd); err != nil { + return reconcile.Result{}, err + } + + if err := m.ensureFactory(ctx, crd); err != nil { + return reconcile.Result{}, err + } + + if err := m.ensureNavigation(ctx, crd); err != nil { + return reconcile.Result{}, err + } + return reconcile.Result{}, nil +} + +// InitializeStaticResources creates all static dashboard resources once during controller startup +func (m *Manager) InitializeStaticResources(ctx context.Context) error { + return m.ensureStaticResources(ctx) +} + +// addDashboardLabels adds standard dashboard management labels to a resource +func (m *Manager) addDashboardLabels(obj client.Object, crd *cozyv1alpha1.ApplicationDefinition, resourceType string) { + labels := obj.GetLabels() + if labels == nil { + labels = make(map[string]string) + } + + labels[LabelManagedBy] = ManagedByValue + labels[LabelResourceType] = resourceType + + if crd != nil { + g, v, kind := pickGVK(crd) + plural := pickPlural(kind, crd) + + labels[LabelCRDName] = crd.Name + labels[LabelCRDGroup] = g + labels[LabelCRDVersion] = v + labels[LabelCRDKind] = kind + labels[LabelCRDPlural] = plural + } + + obj.SetLabels(labels) +} + +// getDashboardResourceSelector returns a label selector for dashboard-managed resources +func (m *Manager) getDashboardResourceSelector() client.MatchingLabels { + return client.MatchingLabels{ + LabelManagedBy: ManagedByValue, + } +} + +// getDynamicResourceSelector returns a label selector for dynamic dashboard resources +func (m *Manager) getDynamicResourceSelector() client.MatchingLabels { + return client.MatchingLabels{ + LabelManagedBy: ManagedByValue, + LabelResourceType: ResourceTypeDynamic, + } +} + +// getStaticResourceSelector returns a label selector for static dashboard resources +func (m *Manager) getStaticResourceSelector() client.MatchingLabels { + return client.MatchingLabels{ + LabelManagedBy: ManagedByValue, + LabelResourceType: ResourceTypeStatic, + } +} + +// CleanupOrphanedResources removes dashboard resources that are no longer needed +// This should be called after cache warming to ensure all current resources are known +func (m *Manager) CleanupOrphanedResources(ctx context.Context) error { + var crdList cozyv1alpha1.ApplicationDefinitionList + if err := m.List(ctx, &crdList, &client.ListOptions{}); err != nil { + return err + } + allCRDs := crdList.Items + + // Build a set of expected resource names for each type + expectedResources := m.buildExpectedResourceSet(allCRDs) + + // Clean up each resource type + resourceTypes := []client.Object{ + &dashv1alpha1.CustomColumnsOverride{}, + &dashv1alpha1.CustomFormsOverride{}, + &dashv1alpha1.CustomFormsPrefill{}, + &dashv1alpha1.MarketplacePanel{}, + &dashv1alpha1.Sidebar{}, + &dashv1alpha1.TableUriMapping{}, + &dashv1alpha1.Breadcrumb{}, + &dashv1alpha1.Factory{}, + } + + for _, resourceType := range resourceTypes { + if err := m.cleanupResourceType(ctx, resourceType, expectedResources); err != nil { + return err + } + } + + return nil +} + +// buildExpectedResourceSet creates a map of expected resource names by type +func (m *Manager) buildExpectedResourceSet(crds []cozyv1alpha1.ApplicationDefinition) map[string]map[string]bool { + expected := make(map[string]map[string]bool) + + // Initialize maps for each resource type + resourceTypes := []string{ + "CustomColumnsOverride", + "CustomFormsOverride", + "CustomFormsPrefill", + "MarketplacePanel", + "Sidebar", + "TableUriMapping", + "Breadcrumb", + "Factory", + } + + for _, rt := range resourceTypes { + expected[rt] = make(map[string]bool) + } + + // Add static resources (these should always exist) + staticResources := CreateAllStaticResources() + for _, resource := range staticResources { + resourceType := resource.GetObjectKind().GroupVersionKind().Kind + if expected[resourceType] != nil { + expected[resourceType][resource.GetName()] = true + } + } + + // Add dynamic resources based on current CRDs + for _, crd := range crds { + if crd.Spec.Dashboard == nil { + continue + } + + // Note: We include ALL resources with dashboard config, regardless of module flag + // because ensureFactory and ensureBreadcrumb create resources for all CRDs with dashboard config + + g, v, kind := pickGVK(&crd) + plural := pickPlural(kind, &crd) + + // CustomColumnsOverride - created for ALL CRDs with dashboard config + name := fmt.Sprintf("stock-namespace-%s.%s.%s", g, v, plural) + expected["CustomColumnsOverride"][name] = true + + // CustomFormsOverride - created for ALL CRDs with dashboard config + name = fmt.Sprintf("%s.%s.%s", g, v, plural) + expected["CustomFormsOverride"][name] = true + + // CustomFormsPrefill - created for ALL CRDs with dashboard config + expected["CustomFormsPrefill"][name] = true + + // MarketplacePanel - only created for non-module CRDs + if !crd.Spec.Dashboard.Module { + expected["MarketplacePanel"][crd.Name] = true + } + + // Sidebar resources - created for ALL CRDs with dashboard config + lowerKind := strings.ToLower(kind) + detailsID := fmt.Sprintf("stock-project-factory-%s-details", lowerKind) + expected["Sidebar"][detailsID] = true + + // Add other stock sidebars that are created for each CRD + stockSidebars := []string{ + "stock-project-factory-marketplace", + "stock-project-factory-workloadmonitor-details", + "stock-project-api-form", + "stock-project-api-table", + "stock-project-builtin-form", + "stock-project-builtin-table", + "stock-project-crd-form", + "stock-project-crd-table", + "stock-instance-api-form", + "stock-instance-api-table", + "stock-instance-builtin-form", + "stock-instance-builtin-table", + } + for _, sidebarID := range stockSidebars { + expected["Sidebar"][sidebarID] = true + } + + // TableUriMapping - created for ALL CRDs with dashboard config + name = fmt.Sprintf("stock-namespace-%s.%s.%s", g, v, plural) + expected["TableUriMapping"][name] = true + + // Breadcrumb - created for ALL CRDs with dashboard config + detailID := fmt.Sprintf("stock-project-factory-%s-details", lowerKind) + expected["Breadcrumb"][detailID] = true + + // Factory - created for ALL CRDs with dashboard config + factoryName := fmt.Sprintf("%s-details", lowerKind) + expected["Factory"][factoryName] = true + } + + return expected +} + +// cleanupResourceType removes orphaned resources of a specific type +func (m *Manager) cleanupResourceType(ctx context.Context, resourceType client.Object, expectedResources map[string]map[string]bool) error { + var ( + list client.ObjectList + resourceKind string + ) + switch resourceType.(type) { + case *dashv1alpha1.CustomColumnsOverride: + list = &dashv1alpha1.CustomColumnsOverrideList{} + resourceKind = "CustomColumnsOverride" + case *dashv1alpha1.CustomFormsOverride: + list = &dashv1alpha1.CustomFormsOverrideList{} + resourceKind = "CustomFormsOverride" + case *dashv1alpha1.CustomFormsPrefill: + list = &dashv1alpha1.CustomFormsPrefillList{} + resourceKind = "CustomFormsPrefill" + case *dashv1alpha1.MarketplacePanel: + list = &dashv1alpha1.MarketplacePanelList{} + resourceKind = "MarketplacePanel" + case *dashv1alpha1.Sidebar: + list = &dashv1alpha1.SidebarList{} + resourceKind = "Sidebar" + case *dashv1alpha1.TableUriMapping: + list = &dashv1alpha1.TableUriMappingList{} + resourceKind = "TableUriMapping" + case *dashv1alpha1.Breadcrumb: + list = &dashv1alpha1.BreadcrumbList{} + resourceKind = "Breadcrumb" + case *dashv1alpha1.Factory: + list = &dashv1alpha1.FactoryList{} + resourceKind = "Factory" + default: + return nil // Unknown type + } + + expected := expectedResources[resourceKind] + if expected == nil { + return nil // No expected resources for this type + } + + // List with dashboard labels + if err := m.List(ctx, list, m.getDashboardResourceSelector()); err != nil { + return err + } + + // Delete resources that are not in the expected set + switch l := list.(type) { + case *dashv1alpha1.CustomColumnsOverrideList: + for _, item := range l.Items { + if !expected[item.Name] { + if err := m.Delete(ctx, &item); err != nil { + if !apierrors.IsNotFound(err) { + return err + } + // Resource already deleted, continue + } + } + } + case *dashv1alpha1.CustomFormsOverrideList: + for _, item := range l.Items { + if !expected[item.Name] { + if err := m.Delete(ctx, &item); err != nil { + if !apierrors.IsNotFound(err) { + return err + } + // Resource already deleted, continue + } + } + } + case *dashv1alpha1.CustomFormsPrefillList: + for _, item := range l.Items { + if !expected[item.Name] { + if err := m.Delete(ctx, &item); err != nil { + if !apierrors.IsNotFound(err) { + return err + } + // Resource already deleted, continue + } + } + } + case *dashv1alpha1.MarketplacePanelList: + for _, item := range l.Items { + if !expected[item.Name] { + if err := m.Delete(ctx, &item); err != nil { + if !apierrors.IsNotFound(err) { + return err + } + // Resource already deleted, continue + } + } + } + case *dashv1alpha1.SidebarList: + for _, item := range l.Items { + if !expected[item.Name] { + if err := m.Delete(ctx, &item); err != nil { + if !apierrors.IsNotFound(err) { + return err + } + // Resource already deleted, continue + } + } + } + case *dashv1alpha1.TableUriMappingList: + for _, item := range l.Items { + if !expected[item.Name] { + if err := m.Delete(ctx, &item); err != nil { + if !apierrors.IsNotFound(err) { + return err + } + // Resource already deleted, continue + } + } + } + case *dashv1alpha1.BreadcrumbList: + for _, item := range l.Items { + if !expected[item.Name] { + logger := log.FromContext(ctx) + logger.Info("Deleting orphaned Breadcrumb resource", "name", item.Name) + if err := m.Delete(ctx, &item); err != nil { + if !apierrors.IsNotFound(err) { + return err + } + } + } + } + case *dashv1alpha1.FactoryList: + for _, item := range l.Items { + if !expected[item.Name] { + logger := log.FromContext(ctx) + logger.Info("Deleting orphaned Factory resource", "name", item.Name) + if err := m.Delete(ctx, &item); err != nil { + if !apierrors.IsNotFound(err) { + return err + } + } + } + } + } + + return nil +} diff --git a/internal/controller/dashboard/marketplacepanel.go b/internal/controller/dashboard/marketplacepanel.go new file mode 100644 index 00000000..14684afc --- /dev/null +++ b/internal/controller/dashboard/marketplacepanel.go @@ -0,0 +1,126 @@ +package dashboard + +import ( + "context" + "encoding/json" + + dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// ensureMarketplacePanel creates or updates a MarketplacePanel resource for the given CRD +func (m *Manager) ensureMarketplacePanel(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) (reconcile.Result, error) { + logger := log.FromContext(ctx) + + mp := &dashv1alpha1.MarketplacePanel{} + mp.Name = crd.Name // cluster-scoped resource, name mirrors CRD name + + // If dashboard is not set, delete the panel if it exists. + if crd.Spec.Dashboard == nil { + err := m.Get(ctx, client.ObjectKey{Name: mp.Name}, mp) + if apierrors.IsNotFound(err) { + return reconcile.Result{}, nil + } + if err != nil { + return reconcile.Result{}, err + } + if err := m.Delete(ctx, mp); err != nil && !apierrors.IsNotFound(err) { + return reconcile.Result{}, err + } + logger.Info("Deleted MarketplacePanel because dashboard is not set", "name", mp.Name) + return reconcile.Result{}, nil + } + + // Skip module and tenant resources (they don't need MarketplacePanel) + if crd.Spec.Dashboard.Module || crd.Spec.Application.Kind == "Tenant" { + err := m.Get(ctx, client.ObjectKey{Name: mp.Name}, mp) + if apierrors.IsNotFound(err) { + return reconcile.Result{}, nil + } + if err != nil { + return reconcile.Result{}, err + } + if err := m.Delete(ctx, mp); err != nil && !apierrors.IsNotFound(err) { + return reconcile.Result{}, err + } + logger.Info("Deleted MarketplacePanel because resource is a module", "name", mp.Name) + return reconcile.Result{}, nil + } + + // Build desired spec from CRD fields + d := crd.Spec.Dashboard + app := crd.Spec.Application + + displayName := d.Singular + if displayName == "" { + displayName = app.Kind + } + + tags := make([]any, len(d.Tags)) + for i, t := range d.Tags { + tags[i] = t + } + + _, err := controllerutil.CreateOrUpdate(ctx, m.Client, mp, func() error { + if err := controllerutil.SetOwnerReference(crd, mp, m.Scheme); err != nil { + return err + } + // Add dashboard labels to dynamic resources + m.addDashboardLabels(mp, crd, ResourceTypeDynamic) + + // Preserve user-set disabled/hidden values from existing resource + disabled := false + hidden := false + if mp.Spec.Raw != nil { + var existing map[string]any + if err := json.Unmarshal(mp.Spec.Raw, &existing); err == nil { + if v, ok := existing["disabled"].(bool); ok { + disabled = v + } + if v, ok := existing["hidden"].(bool); ok { + hidden = v + } + } + } + + specMap := map[string]any{ + "description": d.Description, + "name": displayName, + "type": "nonCrd", + "apiGroup": "apps.cozystack.io", + "apiVersion": "v1alpha1", + "plural": app.Plural, // e.g., "buckets" + "disabled": disabled, + "hidden": hidden, + "tags": tags, + "icon": d.Icon, + } + + specBytes, err := json.Marshal(specMap) + if err != nil { + return err + } + + // Only update spec if it's different to avoid unnecessary updates + newSpec := dashv1alpha1.ArbitrarySpec{ + JSON: apiextv1.JSON{Raw: specBytes}, + } + if !compareArbitrarySpecs(mp.Spec, newSpec) { + mp.Spec = newSpec + } + return nil + }) + if err != nil { + return reconcile.Result{}, err + } + + logger.Info("Applied MarketplacePanel", "name", mp.Name) + return reconcile.Result{}, nil +} diff --git a/internal/controller/dashboard/navigation.go b/internal/controller/dashboard/navigation.go new file mode 100644 index 00000000..5e4bad2e --- /dev/null +++ b/internal/controller/dashboard/navigation.go @@ -0,0 +1,69 @@ +package dashboard + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +// ensureNavigation updates the Navigation resource to include a baseFactoriesMapping entry for the given CRD +func (m *Manager) ensureNavigation(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error { + g, v, kind := pickGVK(crd) + plural := pickPlural(kind, crd) + + lowerKind := strings.ToLower(kind) + factoryKey := fmt.Sprintf("%s-details", lowerKind) + + // All CRD resources are namespaced API resources + mappingKey := fmt.Sprintf("base-factory-namespaced-api-%s-%s-%s", g, v, plural) + + obj := &dashv1alpha1.Navigation{} + obj.SetName("navigation") + + _, err := controllerutil.CreateOrUpdate(ctx, m.Client, obj, func() error { + // Parse existing spec + spec := make(map[string]any) + if obj.Spec.JSON.Raw != nil { + if err := json.Unmarshal(obj.Spec.JSON.Raw, &spec); err != nil { + spec = make(map[string]any) + } + } + + // Get or create baseFactoriesMapping + var mappings map[string]string + if existing, ok := spec["baseFactoriesMapping"].(map[string]any); ok { + mappings = make(map[string]string, len(existing)) + for k, val := range existing { + if s, ok := val.(string); ok { + mappings[k] = s + } + } + } else { + mappings = make(map[string]string) + } + + // Add/update the mapping for this CRD + mappings[mappingKey] = factoryKey + + spec["baseFactoriesMapping"] = mappings + + b, err := json.Marshal(spec) + if err != nil { + return err + } + + newSpec := dashv1alpha1.ArbitrarySpec{JSON: apiextv1.JSON{Raw: b}} + if !compareArbitrarySpecs(obj.Spec, newSpec) { + obj.Spec = newSpec + } + return nil + }) + return err +} diff --git a/internal/controller/dashboard/sidebar.go b/internal/controller/dashboard/sidebar.go new file mode 100644 index 00000000..69c933fb --- /dev/null +++ b/internal/controller/dashboard/sidebar.go @@ -0,0 +1,444 @@ +package dashboard + +import ( + "context" + "encoding/json" + "fmt" + "sort" + "strings" + + dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +// ensureSidebar creates/updates multiple Sidebar resources that share the same menu: +// - The "details" sidebar tied to the current kind (stock-project-factory--details) +// - The stock-project sidebars: api-form, api-table, builtin-form, builtin-table, crd-form, crd-table +// +// Menu rules: +// - The first section is "Marketplace" with two hardcoded entries: +// - Marketplace (/openapi-ui/{cluster}/{namespace}/factory/marketplace) +// - Tenant Info (/openapi-ui/{cluster}/{namespace}/factory/info-details/info) +// - All other sections are built from CRDs where spec.dashboard != nil. +// - Categories are ordered strictly as: +// Marketplace, IaaS, PaaS, NaaS, , Resources, Backups, Administration +// - Items within each category: sort by Weight (desc), then Label (A→Z). +func (m *Manager) ensureSidebar(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error { + // Build the full menu once. + + // 1) Fetch all CRDs + var all []cozyv1alpha1.ApplicationDefinition + var crdList cozyv1alpha1.ApplicationDefinitionList + if err := m.List(ctx, &crdList, &client.ListOptions{}); err != nil { + return err + } + all = crdList.Items + + // 1b) Fetch all MarketplacePanels to determine which resources are hidden + hiddenResources := map[string]bool{} + var mpList dashv1alpha1.MarketplacePanelList + if err := m.List(ctx, &mpList, &client.ListOptions{}); err == nil { + for i := range mpList.Items { + mp := &mpList.Items[i] + if mp.Spec.Raw != nil { + var spec map[string]any + if err := json.Unmarshal(mp.Spec.Raw, &spec); err == nil { + if hidden, ok := spec["hidden"].(bool); ok && hidden { + hiddenResources[mp.Name] = true + } + } + } + } + } + + // 2) Build category -> []item map (only for CRDs with spec.dashboard != nil) + type item struct { + Key string + Label string + Link string + Weight int + } + categories := map[string][]item{} // category label -> children + keysAndTags := map[string]any{} // plural -> []string{ "-sidebar" } + + // Collect sidebar names for module resources + var moduleSidebars []any + + for i := range all { + def := &all[i] + + // Include ONLY when spec.dashboard != nil + if def.Spec.Dashboard == nil { + continue + } + + g, v, kind := pickGVK(def) + plural := pickPlural(kind, def) + lowerKind := strings.ToLower(kind) + + // Skip resources hidden via MarketplacePanel + if hiddenResources[def.Name] { + continue + } + + // Check if this resource is a module + if def.Spec.Dashboard.Module { + // Special case: info should have its own keysAndTags, not be in modules + if lowerKind == "info" { + keysAndTags[plural] = []any{fmt.Sprintf("%s-sidebar", lowerKind)} + } else { + // Add to modules sidebar list + moduleSidebars = append(moduleSidebars, fmt.Sprintf("%s-sidebar", lowerKind)) + } + } else { + // Add to keysAndTags for non-module resources + keysAndTags[plural] = []any{fmt.Sprintf("%s-sidebar", lowerKind)} + } + + // Only add to menu categories if not a module + if !def.Spec.Dashboard.Module { + cat := safeCategory(def) // falls back to "Resources" if empty + + // Label: prefer dashboard.Plural if provided + label := titleFromKindPlural(kind, plural) + if def.Spec.Dashboard.Plural != "" { + label = def.Spec.Dashboard.Plural + } + + // Weight (default 0) + weight := def.Spec.Dashboard.Weight + + link := fmt.Sprintf("/openapi-ui/{cluster}/{namespace}/api-table/%s/%s/%s", g, v, plural) + + categories[cat] = append(categories[cat], item{ + Key: plural, + Label: label, + Link: link, + Weight: weight, + }) + } + } + + // Add modules to keysAndTags if we have any module sidebars + if len(moduleSidebars) > 0 { + keysAndTags["modules"] = moduleSidebars + } + + // Add sidebars for built-in Kubernetes resources + keysAndTags["services"] = []any{"service-sidebar"} + keysAndTags["secrets"] = []any{"secret-sidebar"} + keysAndTags["ingresses"] = []any{"ingress-sidebar"} + // Add sidebar for v1/services type loadbalancer + keysAndTags["loadbalancer-services"] = []any{"external-ips-sidebar"} + + // Add sidebar for backups.cozystack.io Plan resource + keysAndTags["plans"] = []any{"plan-sidebar"} + + // Add sidebar for backups.cozystack.io BackupJob resource + keysAndTags["backupjobs"] = []any{"backupjob-sidebar"} + + // Add sidebar for backups.cozystack.io Backup resource + keysAndTags["backups"] = []any{"backup-sidebar"} + + // Add sidebar for backups.cozystack.io RestoreJob resource + keysAndTags["restorejobs"] = []any{"restorejob-sidebar"} + + // 3) Sort items within each category by Weight (desc), then Label (A→Z) + for cat := range categories { + sort.Slice(categories[cat], func(i, j int) bool { + if categories[cat][i].Weight != categories[cat][j].Weight { + return categories[cat][i].Weight < categories[cat][j].Weight // lower weight first + } + return strings.ToLower(categories[cat][i].Label) < strings.ToLower(categories[cat][j].Label) + }) + } + + // 4) Order categories strictly: + // Marketplace (hardcoded), IaaS, PaaS, NaaS, , Resources, Backups (hardcoded), Administration (hardcoded) + orderedCats := orderCategoryLabels(categories) + + // 5) Build menuItems (hardcode "Marketplace"; then dynamic categories; then hardcode "Backups" and "Administration") + menuItems := []any{ + map[string]any{ + "key": "marketplace", + "label": "Marketplace", + "children": []any{ + map[string]any{ + "key": "marketplace", + "label": "Marketplace", + "link": "/openapi-ui/{cluster}/{namespace}/factory/marketplace", + }, + }, + }, + } + + for _, cat := range orderedCats { + // Skip "Marketplace", "Backups", and "Administration" here since they're hardcoded + if strings.EqualFold(cat, "Marketplace") || strings.EqualFold(cat, "Backups") || strings.EqualFold(cat, "Administration") { + continue + } + children := []any{} + for _, it := range categories[cat] { + children = append(children, map[string]any{ + "key": it.Key, + "label": it.Label, + "link": it.Link, + }) + } + if len(children) > 0 { + menuItems = append(menuItems, map[string]any{ + "key": slugify(cat), + "label": cat, + "children": children, + }) + } + } + + // Add hardcoded Backups section + menuItems = append(menuItems, map[string]any{ + "key": "backups-category", + "label": "Backups", + "children": []any{ + map[string]any{ + "key": "plans", + "label": "Plans", + "link": "/openapi-ui/{cluster}/{namespace}/api-table/backups.cozystack.io/v1alpha1/plans", + }, + map[string]any{ + "key": "backupjobs", + "label": "BackupJobs", + "link": "/openapi-ui/{cluster}/{namespace}/api-table/backups.cozystack.io/v1alpha1/backupjobs", + }, + map[string]any{ + "key": "backups", + "label": "Backups", + "link": "/openapi-ui/{cluster}/{namespace}/api-table/backups.cozystack.io/v1alpha1/backups", + }, + map[string]any{ + "key": "restorejobs", + "label": "RestoreJobs", + "link": "/openapi-ui/{cluster}/{namespace}/api-table/backups.cozystack.io/v1alpha1/restorejobs", + }, + }, + }) + + // Add hardcoded Administration section + menuItems = append(menuItems, map[string]any{ + "key": "administration", + "label": "Administration", + "children": []any{ + map[string]any{ + "key": "info", + "label": "Info", + "link": "/openapi-ui/{cluster}/{namespace}/factory/info-details/info", + }, + map[string]any{ + "key": "modules", + "label": "Modules", + "link": "/openapi-ui/{cluster}/{namespace}/api-table/core.cozystack.io/v1alpha1/tenantmodules", + }, + map[string]any{ + "key": "loadbalancer-services", + "label": "External IPs", + "link": "/openapi-ui/{cluster}/{namespace}/factory/external-ips", + }, + map[string]any{ + "key": "tenants", + "label": "Tenants", + "link": "/openapi-ui/{cluster}/{namespace}/api-table/apps.cozystack.io/v1alpha1/tenants", + }, + }, + }) + + // 6) Prepare the list of Sidebar IDs to upsert with the SAME content + // Create sidebars for ALL CRDs with dashboard config + targetIDs := []string{ + // stock-project sidebars (namespace-level, full menu) + "stock-project-factory-marketplace", + "stock-project-factory-workloadmonitor-details", + "stock-project-factory-kube-service-details", + "stock-project-factory-kube-secret-details", + "stock-project-factory-kube-ingress-details", + "stock-project-factory-plan-details", + "stock-project-factory-backupjob-details", + "stock-project-factory-backup-details", + "stock-project-factory-restorejob-details", + "stock-project-factory-external-ips", + "stock-project-api-form", + "stock-project-api-table", + "stock-project-builtin-form", + "stock-project-builtin-table", + "stock-project-crd-form", + "stock-project-crd-table", + // stock-instance sidebars (namespace-level pages after namespace is selected) + "stock-instance-api-form", + "stock-instance-api-table", + "stock-instance-builtin-form", + "stock-instance-builtin-table", + } + + // Add details sidebars for all CRDs with dashboard config, and collect + // the set of IDs that are genuinely CRD-backed (dynamic). The hardcoded + // `-details` IDs above (e.g. kube-* and backup/backupjob/plan/restorejob) + // are not tied to an ApplicationDefinition and must be treated as static + // so they receive consistent labels via upsertMultipleSidebars(). + dynamicDetailsIDs := map[string]bool{} + for i := range all { + def := &all[i] + if def.Spec.Dashboard == nil { + continue + } + _, _, kind := pickGVK(def) + lowerKind := strings.ToLower(kind) + detailsID := fmt.Sprintf("stock-project-factory-%s-details", lowerKind) + targetIDs = append(targetIDs, detailsID) + dynamicDetailsIDs[detailsID] = true + } + + // 7) Upsert all target sidebars with identical menuItems and keysAndTags + return m.upsertMultipleSidebars(ctx, crd, targetIDs, dynamicDetailsIDs, keysAndTags, menuItems) +} + +// upsertMultipleSidebars creates/updates several Sidebar resources with the same menu spec. +// dynamicDetailsIDs identifies `stock-project-factory--details` sidebars that are +// backed by an ApplicationDefinition and should therefore be owned by that CRD. +// Any other ID is treated as a static sidebar (managed-by labels, no owner ref). +func (m *Manager) upsertMultipleSidebars( + ctx context.Context, + crd *cozyv1alpha1.ApplicationDefinition, + ids []string, + dynamicDetailsIDs map[string]bool, + keysAndTags map[string]any, + menuItems []any, +) error { + for _, id := range ids { + spec := map[string]any{ + "id": id, + "keysAndTags": keysAndTags, + "menuItems": menuItems, + } + + obj := &dashv1alpha1.Sidebar{} + obj.SetName(id) + + if _, err := controllerutil.CreateOrUpdate(ctx, m.Client, obj, func() error { + // Only set owner reference for dynamic sidebars (stock-project-factory-{kind}-details) + // that are actually backed by an ApplicationDefinition. Static sidebars — including + // hardcoded details sidebars for built-in/backup resources — must fall through to the + // static-label branch so they're managed consistently. + if strings.HasPrefix(id, "stock-project-factory-") && strings.HasSuffix(id, "-details") && dynamicDetailsIDs[id] { + // This is a dynamic sidebar, set owner reference only if it matches the current CRD + _, _, kind := pickGVK(crd) + lowerKind := strings.ToLower(kind) + expectedID := fmt.Sprintf("stock-project-factory-%s-details", lowerKind) + if id == expectedID { + if err := controllerutil.SetOwnerReference(crd, obj, m.Scheme); err != nil { + return err + } + // Add dashboard labels to dynamic resources + m.addDashboardLabels(obj, crd, ResourceTypeDynamic) + } else { + // This is a different CRD's sidebar, don't modify owner references or labels + // Just update the spec + } + } else { + // This is a static sidebar, don't set owner references + // Add static labels + labels := obj.GetLabels() + if labels == nil { + labels = make(map[string]string) + } + labels[LabelManagedBy] = ManagedByValue + labels[LabelResourceType] = ResourceTypeStatic + obj.SetLabels(labels) + } + + b, err := json.Marshal(spec) + if err != nil { + return err + } + + // Only update spec if it's different to avoid unnecessary updates + newSpec := dashv1alpha1.ArbitrarySpec{JSON: apiextv1.JSON{Raw: b}} + if !compareArbitrarySpecs(obj.Spec, newSpec) { + obj.Spec = newSpec + } + return nil + }); err != nil { + return err + } + } + return nil +} + +// orderCategoryLabels returns category labels ordered strictly as: +// +// Marketplace, IaaS, PaaS, NaaS, , Resources, Administration. +// +// It only returns labels that exist in `cats` (except "Marketplace" which is hardcoded by caller). +func orderCategoryLabels[T any](cats map[string][]T) []string { + if len(cats) == 0 { + return []string{"Marketplace", "IaaS", "PaaS", "NaaS", "Resources", "Administration"} + } + + head := []string{"Marketplace", "IaaS", "PaaS", "NaaS"} + tail := []string{"Resources", "Administration"} + + present := make(map[string]struct{}, len(cats)) + for k := range cats { + present[k] = struct{}{} + } + + var result []string + + // Add head anchors (keep "Marketplace" in the order signature for the caller) + for _, h := range head { + result = append(result, h) + delete(present, h) + } + + // Collect "others": exclude tail + var others []string + for k := range present { + if k == "Resources" || k == "Administration" { + continue + } + others = append(others, k) + } + sort.Slice(others, func(i, j int) bool { return strings.ToLower(others[i]) < strings.ToLower(others[j]) }) + + // Append others, then tail (always in fixed order) + result = append(result, others...) + result = append(result, tail...) + + return result +} + +// safeCategory returns spec.dashboard.category or "Resources" if not set. +func safeCategory(def *cozyv1alpha1.ApplicationDefinition) string { + if def == nil || def.Spec.Dashboard == nil { + return "Resources" + } + if def.Spec.Dashboard.Category != "" { + return def.Spec.Dashboard.Category + } + return "Resources" +} + +// slugify converts a category label to a key-friendly identifier. +// "User Management" -> "usermanagement", "PaaS" -> "paas". +func slugify(s string) string { + s = strings.TrimSpace(strings.ToLower(s)) + out := make([]byte, 0, len(s)) + for i := 0; i < len(s); i++ { + c := s[i] + if (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') { + out = append(out, c) + } + } + return string(out) +} diff --git a/internal/controller/dashboard/static_helpers.go b/internal/controller/dashboard/static_helpers.go new file mode 100644 index 00000000..db37e05b --- /dev/null +++ b/internal/controller/dashboard/static_helpers.go @@ -0,0 +1,1161 @@ +package dashboard + +import ( + "encoding/json" + "strings" + + dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1" + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ---------------- Static resource helpers ---------------- + +// createBreadcrumb creates a Breadcrumb resource with the given name and breadcrumb items +func createBreadcrumb(name string, breadcrumbItems []map[string]any) *dashv1alpha1.Breadcrumb { + // Generate spec.id from name + specID := generateSpecID(name) + + data := map[string]any{ + "breadcrumbItems": breadcrumbItems, + "id": specID, + } + jsonData, _ := json.Marshal(data) + + return &dashv1alpha1.Breadcrumb{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "dashboard.cozystack.io/v1alpha1", + Kind: "Breadcrumb", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: "", + }, + Spec: dashv1alpha1.ArbitrarySpec{ + JSON: v1.JSON{ + Raw: jsonData, + }, + }, + } +} + +// createCustomColumnsOverride creates a CustomColumnsOverride resource +func createCustomColumnsOverride(id string, additionalPrinterColumns []any) *dashv1alpha1.CustomColumnsOverride { + // Generate metadata.name from spec.id + name := generateMetadataName(id) + + data := map[string]any{ + "additionalPrinterColumns": additionalPrinterColumns, + } + + // Add ID field for resources that should have it + shouldHaveID := true + if name == "stock-cluster-.v1.nodes" || + name == "stock-cluster-.v1.pods" || + name == "stock-namespace-.v1.pods" || + name == "factory-node-details-v1.pods" || + name == "factory-v1.pods" { + shouldHaveID = false + } + + // ID will be set later for specific resources, so don't set it here for pod/node resources + if shouldHaveID && !strings.Contains(name, "pods") && !strings.Contains(name, "nodes") { + data["id"] = id + } + + // Add additional fields for specific resources + if name == "factory-details-v1.services" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Name", + "value": float64(64), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "ClusterIP", + "value": "-", + }, + map[string]any{ + "key": "LoadbalancerIP", + "value": "-", + }, + } + } + + if name == "cluster-v1.configmaps" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Name", + "value": float64(64), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "Namespace", + "value": "-", + }, + } + } + + if name == "stock-cluster-v1.configmaps" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Name", + "value": float64(64), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "Namespace", + "value": "-", + }, + } + } + + if name == "stock-namespace-v1.configmaps" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Name", + "value": float64(64), + }, + } + } + + if name == "factory-details-v1alpha1.core.cozystack.io.tenantsecrets" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Name", + "value": float64(64), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "Namespace", + "value": "-", + }, + } + } + + if name == "factory-details-v1alpha1.cozystack.io.workloads" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Name", + "value": float64(64), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "Name", + "value": "-", + }, + map[string]any{ + "key": "Kind", + "value": "-", + }, + map[string]any{ + "key": "Type", + "value": "-", + }, + map[string]any{ + "key": "CPU", + "value": "-", + }, + map[string]any{ + "key": "Memory", + "value": "-", + }, + map[string]any{ + "key": "Operational", + "value": "-", + }, + } + } + + if name == "factory-kube-ingress-details-rules" { + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "Service", + "value": "-", + }, + map[string]any{ + "key": "Port", + "value": "-", + }, + map[string]any{ + "key": "Path", + "value": "-", + }, + } + } + + if name == "container-spec-containers-list" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Image", + "value": float64(64), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "Name", + "value": "-", + }, + map[string]any{ + "key": "Image", + "value": "-", + }, + map[string]any{ + "key": "Resources limits", + "value": "-", + }, + map[string]any{ + "key": "Resources requests", + "value": "-", + }, + map[string]any{ + "key": "Ports", + "value": "-", + }, + } + } + + if name == "container-spec-init-containers-list" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Image", + "value": float64(64), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "Name", + "value": "-", + }, + map[string]any{ + "key": "Image", + "value": "-", + }, + map[string]any{ + "key": "Resources limits", + "value": "-", + }, + map[string]any{ + "key": "Resources requests", + "value": "-", + }, + } + } + + if name == "container-status-containers-list" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Name", + "value": float64(63), + }, + map[string]any{ + "key": "Image", + "value": float64(63), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "TerminatedReason", + "value": "-", + }, + map[string]any{ + "key": "WaitingReason", + "value": "-", + }, + } + } + + if name == "container-status-init-containers-list" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Name", + "value": float64(63), + }, + map[string]any{ + "key": "Image", + "value": float64(63), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "TerminatedReason", + "value": "-", + }, + map[string]any{ + "key": "WaitingReason", + "value": "-", + }, + } + } + + if name == "factory-details-networking.k8s.io.v1.ingresses" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Name", + "value": float64(64), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "Hosts", + "value": "-", + }, + map[string]any{ + "key": "Address", + "value": "-", + }, + map[string]any{ + "key": "Port", + "value": "-", + }, + } + } + + if name == "stock-namespace-networking.k8s.io.v1.ingresses" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Name", + "value": float64(64), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "Hosts", + "value": "-", + }, + map[string]any{ + "key": "Address", + "value": "-", + }, + map[string]any{ + "key": "Port", + "value": "-", + }, + } + } + + if name == "factory-node-images" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "ImageID", + "value": float64(128), + }, + map[string]any{ + "key": "Size", + "value": float64(63), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "Message", + "value": "-", + }, + } + } + + if name == "factory-status-conditions" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Message", + "value": float64(63), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "Reason", + "value": "-", + }, + map[string]any{ + "key": "Message", + "value": "-", + }, + } + } + + if name == "stock-cluster-v1.secrets" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Name", + "value": float64(64), + }, + } + } + + if name == "stock-namespace-networking.k8s.io.v1.ingresses" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Name", + "value": float64(64), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "Hosts", + "value": "-", + }, + map[string]any{ + "key": "Address", + "value": "-", + }, + map[string]any{ + "key": "Port", + "value": "-", + }, + } + } + + if name == "stock-namespace-v1.configmaps" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Name", + "value": float64(64), + }, + } + } + + if name == "stock-namespace-v1.secrets" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Name", + "value": float64(64), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "Namespace", + "value": "-", + }, + } + } + + if name == "stock-namespace-v1.services" { + data["additionalPrinterColumnsTrimLengths"] = []any{ + map[string]any{ + "key": "Name", + "value": float64(64), + }, + } + data["additionalPrinterColumnsUndefinedValues"] = []any{ + map[string]any{ + "key": "ClusterIP", + "value": "-", + }, + map[string]any{ + "key": "LoadbalancerIP", + "value": "-", + }, + } + } + + jsonData, _ := json.Marshal(data) + + return &dashv1alpha1.CustomColumnsOverride{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "dashboard.cozystack.io/v1alpha1", + Kind: "CustomColumnsOverride", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: "", + }, + Spec: dashv1alpha1.ArbitrarySpec{ + JSON: v1.JSON{ + Raw: jsonData, + }, + }, + } +} + +// createFactory creates a Factory resource +func createFactory(name string, spec map[string]any) *dashv1alpha1.Factory { + jsonData, _ := json.Marshal(spec) + + return &dashv1alpha1.Factory{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "dashboard.cozystack.io/v1alpha1", + Kind: "Factory", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: "", + }, + Spec: dashv1alpha1.ArbitrarySpec{ + JSON: v1.JSON{ + Raw: jsonData, + }, + }, + } +} + +// createTableUriMapping creates a TableUriMapping resource +func createTableUriMapping(name string, spec map[string]any) *dashv1alpha1.TableUriMapping { + jsonData, _ := json.Marshal(spec) + + return &dashv1alpha1.TableUriMapping{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "dashboard.cozystack.io/v1alpha1", + Kind: "TableUriMapping", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: "", + }, + Spec: dashv1alpha1.ArbitrarySpec{ + JSON: v1.JSON{ + Raw: jsonData, + }, + }, + } +} + +// ---------------- Breadcrumb item helpers ---------------- + +// createBreadcrumbItem creates a breadcrumb item with key, label, and optional link +func createBreadcrumbItem(key, label string, link ...string) map[string]any { + item := map[string]any{ + "key": key, + "label": label, + } + if len(link) > 0 && link[0] != "" { + item["link"] = link[0] + } + return item +} + +// ---------------- Custom column helpers ---------------- + +// createCustomColumn creates a custom column with factory type and badge +func createCustomColumn(name, kind, plural, href string) map[string]any { + link := antdLink("name-link", "{reqsJsonPath[0]['.metadata.name']['-']}", href) + + return map[string]any{ + "name": name, + "type": "factory", + "customProps": map[string]any{ + "disableEventBubbling": true, + "items": []any{ + map[string]any{ + "children": []any{ + map[string]any{ + "type": "ResourceBadge", + "data": map[string]any{ + "id": "header-badge", + "value": kind, + // abbreviation auto-generated by ResourceBadge from value + }, + }, + link, + }, + "type": "antdFlex", + "data": map[string]any{ + "align": "center", + "gap": float64(6), + }, + }, + }, + }, + } +} + +// createCustomColumnWithBadge creates a custom column with a specific badge +// badgeValue should be the kind in PascalCase (e.g., "Service", "Pod") +// abbreviation is auto-generated by ResourceBadge from badgeValue +func createCustomColumnWithBadge(name, badgeValue, href string) map[string]any { + link := antdLink("name-link", "{reqsJsonPath[0]['.metadata.name']['-']}", href) + + badgeData := map[string]any{ + "id": "header-badge", + "value": badgeValue, + } + + return map[string]any{ + "name": name, + "type": "factory", + "customProps": map[string]any{ + "disableEventBubbling": true, + "items": []any{ + map[string]any{ + "children": []any{ + map[string]any{ + "type": "ResourceBadge", + "data": badgeData, + }, + link, + }, + "type": "antdFlex", + "data": map[string]any{ + "align": "center", + "gap": float64(6), + }, + }, + }, + }, + } +} + +// createCustomColumnWithSpecificColor creates a custom column with a specific kind and optional color +// badgeValue should be the kind in PascalCase (e.g., "Service", "Pod") +func createCustomColumnWithSpecificColor(name, kind, color, href string) map[string]any { + link := antdLink("name-link", "{reqsJsonPath[0]['.metadata.name']['-']}", href) + + badgeData := map[string]any{ + "id": "header-badge", + "value": kind, + } + // Add custom color if specified + if color != "" { + badgeData["style"] = map[string]any{ + "backgroundColor": color, + } + } + + return map[string]any{ + "name": name, + "type": "factory", + "jsonPath": ".metadata.name", + "customProps": map[string]any{ + "disableEventBubbling": true, + "items": []any{ + map[string]any{ + "children": []any{ + map[string]any{ + "type": "ResourceBadge", + "data": badgeData, + }, + link, + }, + "type": "antdFlex", + "data": map[string]any{ + "align": "center", + "gap": float64(6), + "id": "header-row", + }, + }, + }, + }, + } +} + +// createStringColumn creates a simple string column +func createStringColumn(name, jsonPath string) map[string]any { + return map[string]any{ + "name": name, + "type": "string", + "jsonPath": jsonPath, + } +} + +// createTimestampColumn creates a timestamp column with custom formatting. +// Extra jsonPaths act as ordered fallbacks: the first non-null path wins, +// and `-` is used only when every path is null. Depth is capped at two +// because the template parser's non-greedy matcher cannot track more than +// one level of alternating quotes in a nested reqsJsonPath fallback. +func createTimestampColumn(name string, jsonPaths ...string) map[string]any { + if len(jsonPaths) == 0 { + panic("createTimestampColumn requires at least one jsonPath") + } + if len(jsonPaths) > 2 { + panic("createTimestampColumn supports at most two jsonPaths (primary + one fallback)") + } + + var text string + switch len(jsonPaths) { + case 1: + text = "{reqsJsonPath[0]['" + jsonPaths[0] + "']['-']}" + case 2: + text = "{reqsJsonPath[0]['" + jsonPaths[0] + "'][\"{reqsJsonPath[0]['" + jsonPaths[1] + "']['-']}\"]}" + } + + return map[string]any{ + "name": name, + "type": "factory", + "jsonPath": jsonPaths[0], + "customProps": map[string]any{ + "disableEventBubbling": true, + "items": []any{ + map[string]any{ + "children": []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "time-icon", + "text": "🌐", + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "formatter": "timestamp", + "id": "time-value", + "text": text, + }, + }, + }, + "type": "antdFlex", + "data": map[string]any{ + "align": "center", + "gap": float64(6), + "id": "time-block", + }, + }, + }, + }, + } +} + +// ---------------- Factory helpers ---------------- + +// createFactoryHeader creates a header for factory resources +func createFactoryHeader(kind, plural string) map[string]any { + lowerKind := strings.ToLower(kind) + badge := createUnifiedBadgeFromKind("badge-"+lowerKind, kind) + nameText := parsedText(lowerKind+"-name", "{reqsJsonPath[0]['.metadata.name']['-']}", map[string]any{ + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": float64(20), + "lineHeight": "24px", + }) + + return antdFlex("header-row", float64(6), []any{ + badge, + nameText, + }) +} + +// getTabsId returns the appropriate tabs ID for a given key +func getTabsId(key string) string { + // Special cases + if key == "workloadmonitor-details" { + return "workloadmonitor-tabs" + } + if key == "kube-secret-details" { + return "secret-tabs" + } + if key == "kube-service-details" { + return "service-tabs" + } + return strings.ToLower(key) + "-tabs" +} + +// createFactorySpec creates a factory spec with header and tabs +func createFactorySpec(key string, sidebarTags []any, urlsToFetch []any, header map[string]any, tabs []any) map[string]any { + return map[string]any{ + "key": key, + "sidebarTags": sidebarTags, + "withScrollableMainContentCard": true, + "urlsToFetch": urlsToFetch, + "data": []any{ + header, + map[string]any{ + "type": "antdTabs", + "data": map[string]any{ + "id": getTabsId(key), + "defaultActiveKey": "details", + "items": tabs, + }, + }, + }, + } +} + +// createCustomColumnWithJsonPath creates a column with a custom badge and link using jsonPath +// badgeValue should be the kind in PascalCase (e.g., "Service", "VirtualMachine") +// abbreviation is auto-generated by ResourceBadge from badgeValue +func createCustomColumnWithJsonPath(name, jsonPath, badgeValue, badgeColor, linkHref string) map[string]any { + // Determine link ID based on jsonPath + linkId := "name-link" + if jsonPath == ".metadata.namespace" { + linkId = "namespace-link" + } + + badgeData := map[string]any{ + "id": "header-badge", + "value": badgeValue, + } + // Add custom color if specified + if badgeColor != "" { + badgeData["style"] = map[string]any{ + "backgroundColor": badgeColor, + } + } + + return map[string]any{ + "name": name, + "type": "factory", + "jsonPath": jsonPath, + "customProps": map[string]any{ + "disableEventBubbling": true, + "items": []any{ + map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "header-row", + "align": "center", + "gap": 6, + }, + "children": []any{ + map[string]any{ + "type": "ResourceBadge", + "data": badgeData, + }, + map[string]any{ + "type": "antdLink", + "data": map[string]any{ + "id": linkId, + "text": "{reqsJsonPath[0]['" + jsonPath + "']['-']}", + "href": linkHref, + }, + }, + }, + }, + }, + }, + } +} + +// createCustomColumnWithoutJsonPath creates a column with a custom badge and link without jsonPath +// badgeValue should be the kind in PascalCase (e.g., "Node", "Pod") +// abbreviation is auto-generated by ResourceBadge from badgeValue +func createCustomColumnWithoutJsonPath(name, badgeValue, badgeColor, linkHref string) map[string]any { + badgeData := map[string]any{ + "id": "header-badge", + "value": badgeValue, + } + // Add custom color if specified + if badgeColor != "" { + badgeData["style"] = map[string]any{ + "backgroundColor": badgeColor, + } + } + + return map[string]any{ + "name": name, + "type": "factory", + "customProps": map[string]any{ + "disableEventBubbling": true, + "items": []any{ + map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "header-row", + "align": "center", + "gap": 6, + }, + "children": []any{ + map[string]any{ + "type": "ResourceBadge", + "data": badgeData, + }, + map[string]any{ + "type": "antdLink", + "data": map[string]any{ + "id": "name-link", + "text": "{reqsJsonPath[0]['.spec.nodeName']['-']}", + "href": linkHref, + }, + }, + }, + }, + }, + }, + } +} + +// createStatusColumn creates a status column with StatusText component +func createStatusColumn(name, statusId string) map[string]any { + var statusData map[string]any + + if statusId == "pod-status" { + statusData = map[string]any{ + "id": statusId, + "criteriaError": "equals", + "criteriaSuccess": "notEquals", + "errorText": "Error", + "fallbackText": "Progressing", + "strategySuccess": "every", + "strategyError": "every", + "successText": "{reqsJsonPath[0]['.status.phase']['-']}", + "valueToCompareError": []any{ + "Failed", + "Unknown", + "Evicted", + "NodeLost", + "UnexpectedAdmissionError", + "SchedulerError", + "FailedScheduling", + "CrashLoopBackOff", + "ImagePullBackOff", + "ErrImagePull", + "ErrImageNeverPull", + "InvalidImageName", + "ImageInspectError", + "CreateContainerConfigError", + "CreateContainerError", + "RunContainerError", + "StartError", + "PostStartHookError", + "ContainerCannotRun", + "OOMKilled", + "Error", + "DeadlineExceeded", + "CreatePodSandboxError", + }, + "valueToCompareSuccess": []any{ + "Preempted", + "Shutdown", + "NodeShutdown", + "DisruptionTarget", + "Unschedulable", + "SchedulingGated", + "ContainersNotReady", + "ContainersNotInitialized", + "BackOff", + "PreStopHookError", + "KillError", + "ContainerStatusUnknown", + }, + "values": []any{ + "{reqsJsonPath[0]['.status.initContainerStatuses[*].state.waiting.reason']['-']}", + "{reqsJsonPath[0]['.status.initContainerStatuses[*].state.terminated.reason']['-']}", + "{reqsJsonPath[0]['.status.initContainerStatuses[*].lastState.terminated.reason']['-']}", + "{reqsJsonPath[0]['.status.containerStatuses[*].state.waiting.reason']['-']}", + "{reqsJsonPath[0]['.status.containerStatuses[*].state.terminated.reason']['-']}", + "{reqsJsonPath[0]['.status.containerStatuses[*].lastState.terminated.reason']['-']}", + "{reqsJsonPath[0]['.status.phase']['-']}", + "{reqsJsonPath[0]['.status.reason']['-']}", + "{reqsJsonPath[0]['.status.conditions[*].reason']['-']}", + }, + } + } else if statusId == "node-status" { + statusData = map[string]any{ + "id": statusId, + "criteriaError": "equals", + "criteriaSuccess": "equals", + "errorText": "Unavailable", + "fallbackText": "Progressing", + "strategySuccess": "every", + "strategyError": "every", + "successText": "Available", + "valueToCompareError": []any{ + "KernelDeadlock", + "ReadonlyFilesystem", + "NetworkUnavailable", + "MemoryPressure", + "DiskPressure", + "PIDPressure", + }, + "valueToCompareSuccess": "KubeletReady", + "values": []any{ + "{reqsJsonPath[0]['.status.conditions[?(@.status=='True')].reason']['-']}", + }, + } + } else { + // Default status data for other status types + statusData = map[string]any{ + "id": statusId, + } + } + + return map[string]any{ + "name": name, + "type": "factory", + "customProps": map[string]any{ + "disableEventBubbling": true, + "items": []any{ + map[string]any{ + "type": "StatusText", + "data": statusData, + }, + }, + }, + } +} + +// createSimpleStatusColumn creates a simple status column with basic StatusText component +func createSimpleStatusColumn(name, statusId string) map[string]any { + return map[string]any{ + "name": name, + "type": "factory", + "customProps": map[string]any{ + "disableEventBubbling": true, + "items": []any{ + map[string]any{ + "type": "StatusText", + "data": map[string]any{ + "id": statusId, + }, + }, + }, + }, + } +} + +// createSecretBase64Column creates a column with SecretBase64Plain component +func createSecretBase64Column(name, jsonPath string) map[string]any { + return map[string]any{ + "name": name, + "type": "factory", + "customProps": map[string]any{ + "disableEventBubbling": true, + "items": []any{ + map[string]any{ + "type": "SecretBase64Plain", + "data": map[string]any{ + "id": "example-secretbase64", + "plainTextValue": "hello", + "base64Value": "{reqsJsonPath[0]['" + jsonPath + "']['']}", + }, + }, + }, + }, + } +} + +// createArrayColumn creates a column with array type +func createArrayColumn(name, jsonPath string) map[string]any { + return map[string]any{ + "name": name, + "type": "array", + "jsonPath": jsonPath, + } +} + +// createBoolColumn creates a column with boolean type +func createBoolColumn(name, jsonPath string) map[string]any { + return map[string]any{ + "name": name, + "type": "bool", + "jsonPath": jsonPath, + } +} + +// createReadyColumn creates a Ready column with Boolean type and condition check +func createReadyColumn() map[string]any { + return map[string]any{ + "name": "Ready", + "type": "Boolean", + "jsonPath": `.status.conditions[?(@.type=="Ready")].status`, + } +} + +// createApplicationRefColumn creates a column that displays +// applicationRef in the format "Kind.apiGroup/name" +func createApplicationRefColumn(name string) map[string]any { + return map[string]any{ + "name": name, + "type": "factory", + "customProps": map[string]any{ + "disableEventBubbling": true, + "items": []any{ + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "id": "application-ref-text", + "text": "{reqsJsonPath[0]['.spec.applicationRef.kind']['-']}.{reqsJsonPath[0]['.spec.applicationRef.apiGroup']['-']}/{reqsJsonPath[0]['.spec.applicationRef.name']['-']}", + }, + }, + }, + }, + } +} + +// createConverterBytesColumn creates a column with ConverterBytes component +func createConverterBytesColumn(name, jsonPath string) map[string]any { + return map[string]any{ + "name": name, + "type": "factory", + "jsonPath": jsonPath, + "customProps": map[string]any{ + "disableEventBubbling": true, + "items": []any{ + map[string]any{ + "type": "ConverterBytes", + "data": map[string]any{ + "id": "example-converter-bytes", + "bytesValue": "{reqsJsonPath[0]['" + jsonPath + "']['-']}", + "format": true, + "precision": float64(1), + }, + }, + }, + }, + } +} + +// createFlatMapColumn creates a flatMap column that expands a map into separate rows +func createFlatMapColumn(name, jsonPath string) map[string]any { + return map[string]any{ + "name": name, + "type": "flatMap", + "jsonPath": jsonPath, + } +} + +// ---------------- Factory UI helper functions ---------------- + +// labelsEditor creates a Labels editor component +func labelsEditor(id, endpoint string, reqIndex int) map[string]any { + return map[string]any{ + "type": "Labels", + "data": map[string]any{ + "id": id, + "endpoint": endpoint, + "reqIndex": reqIndex, + "jsonPathToLabels": ".metadata.labels", + "pathToValue": "/metadata/labels", + "modalTitle": "Edit labels", + "modalDescriptionText": "", + "inputLabel": "", + "notificationSuccessMessage": "Updated successfully", + "notificationSuccessMessageDescription": "Labels have been updated", + "editModalWidth": 650, + "maxEditTagTextLength": 35, + "paddingContainerEnd": "24px", + "containerStyle": map[string]any{"marginTop": -30}, + "selectProps": map[string]any{"maxTagTextLength": 35}, + }, + } +} + +// annotationsEditor creates an Annotations editor component +func annotationsEditor(id, endpoint string, reqIndex int) map[string]any { + return map[string]any{ + "type": "Annotations", + "data": map[string]any{ + "id": id, + "endpoint": endpoint, + "reqIndex": reqIndex, + "jsonPathToObj": ".metadata.annotations", + "pathToValue": "/metadata/annotations", + "modalTitle": "Edit annotations", + "modalDescriptionText": "", + "inputLabel": "", + "notificationSuccessMessage": "Updated successfully", + "notificationSuccessMessageDescription": "Annotations have been updated", + "editModalWidth": "800px", + "errorText": "0 Annotations", + "text": "~counter~ Annotations", + "cols": []any{11, 11, 2}, + }, + } +} + +// yamlEditor creates a YamlEditorSingleton component +func yamlEditor(id, cluster string, isNameSpaced bool, typeName string, prefillValuesRequestIndex int) map[string]any { + return map[string]any{ + "type": "YamlEditorSingleton", + "data": map[string]any{ + "id": id, + "cluster": cluster, + "isNameSpaced": isNameSpaced, + "type": "builtin", + "plural": typeName, + "prefillValuesRequestIndex": prefillValuesRequestIndex, + "substractHeight": float64(400), + }, + } +} diff --git a/internal/controller/dashboard/static_processor.go b/internal/controller/dashboard/static_processor.go new file mode 100644 index 00000000..d4b270f4 --- /dev/null +++ b/internal/controller/dashboard/static_processor.go @@ -0,0 +1,61 @@ +package dashboard + +import ( + "context" + + dashv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +// ensureStaticResources ensures all static dashboard resources are created +func (m *Manager) ensureStaticResources(ctx context.Context) error { + // Use refactored resources from static_refactored.go + // This replaces the old static variables with dynamic creation using helper functions + staticResources := CreateAllStaticResources() + + // Create or update each static resource + for _, resource := range staticResources { + if err := m.ensureStaticResource(ctx, resource); err != nil { + return err + } + } + + return nil +} + +// ensureStaticResource creates or updates a single static resource +func (m *Manager) ensureStaticResource(ctx context.Context, obj client.Object) error { + // Create a copy to avoid modifying the original + resource := obj.DeepCopyObject().(client.Object) + + // Add dashboard labels to static resources + m.addDashboardLabels(resource, nil, ResourceTypeStatic) + + _, err := controllerutil.CreateOrUpdate(ctx, m.Client, resource, func() error { + // For static resources, we don't need to set owner references + // as they are meant to be persistent across CRD changes + // Copy Spec from the original object to the live object + switch o := obj.(type) { + case *dashv1alpha1.CustomColumnsOverride: + resource.(*dashv1alpha1.CustomColumnsOverride).Spec = o.Spec + case *dashv1alpha1.Breadcrumb: + resource.(*dashv1alpha1.Breadcrumb).Spec = o.Spec + case *dashv1alpha1.CustomFormsOverride: + resource.(*dashv1alpha1.CustomFormsOverride).Spec = o.Spec + case *dashv1alpha1.Factory: + resource.(*dashv1alpha1.Factory).Spec = o.Spec + case *dashv1alpha1.Navigation: + resource.(*dashv1alpha1.Navigation).Spec = o.Spec + case *dashv1alpha1.TableUriMapping: + resource.(*dashv1alpha1.TableUriMapping).Spec = o.Spec + case *dashv1alpha1.CFOMapping: + resource.(*dashv1alpha1.CFOMapping).Spec = o.Spec + } + // Ensure labels are always set + m.addDashboardLabels(resource, nil, ResourceTypeStatic) + return nil + }) + + return err +} diff --git a/internal/controller/dashboard/static_refactored.go b/internal/controller/dashboard/static_refactored.go new file mode 100644 index 00000000..9f28c0fb --- /dev/null +++ b/internal/controller/dashboard/static_refactored.go @@ -0,0 +1,2725 @@ +package dashboard + +import ( + "encoding/json" + "strings" + + dashboardv1alpha1 "github.com/cozystack/cozystack/api/dashboard/v1alpha1" + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// ---------------- Complete refactored static resources ---------------- + +// CreateAllBreadcrumbs creates all breadcrumb resources using helper functions +func CreateAllBreadcrumbs() []*dashboardv1alpha1.Breadcrumb { + return []*dashboardv1alpha1.Breadcrumb{ + // Stock project factory configmap details + createBreadcrumb("stock-project-factory-configmap-details", []map[string]any{ + createBreadcrumbItem("configmaps", "v1/configmaps", "/openapi-ui/{cluster}/{namespace}/builtin-table/configmaps"), + createBreadcrumbItem("configmap", "{6}"), + }), + + // Stock cluster factory namespace details + createBreadcrumb("stock-cluster-factory-namespace-details", []map[string]any{ + createBreadcrumbItem("namespaces", "v1/namespaces", "/openapi-ui/{cluster}/builtin-table/namespaces"), + createBreadcrumbItem("namespace", "{5}"), + }), + + // Stock cluster factory node details + createBreadcrumb("stock-cluster-factory-node-details", []map[string]any{ + createBreadcrumbItem("node", "v1/nodes", "/openapi-ui/{cluster}/builtin-table/nodes"), + createBreadcrumbItem("node", "{5}"), + }), + + // Stock project factory pod details + createBreadcrumb("stock-project-factory-pod-details", []map[string]any{ + createBreadcrumbItem("pods", "v1/pods", "/openapi-ui/{cluster}/{namespace}/builtin-table/pods"), + createBreadcrumbItem("pod", "{6}"), + }), + + // Stock project factory secret details + createBreadcrumb("stock-project-factory-kube-secret-details", []map[string]any{ + createBreadcrumbItem("secrets", "v1/secrets", "/openapi-ui/{cluster}/{namespace}/builtin-table/secrets"), + createBreadcrumbItem("secret", "{6}"), + }), + + // Stock project factory service details + createBreadcrumb("stock-project-factory-kube-service-details", []map[string]any{ + createBreadcrumbItem("services", "v1/services", "/openapi-ui/{cluster}/{namespace}/builtin-table/services"), + createBreadcrumbItem("service", "{6}"), + }), + + // Stock project factory ingress details + createBreadcrumb("stock-project-factory-kube-ingress-details", []map[string]any{ + createBreadcrumbItem("ingresses", "networking.k8s.io/v1/ingresses", "/openapi-ui/{cluster}/{namespace}/builtin-table/ingresses"), + createBreadcrumbItem("ingress", "{6}"), + }), + + // Stock cluster api table + createBreadcrumb("stock-cluster-api-table", []map[string]any{ + createBreadcrumbItem("api", "{apiGroup}/{apiVersion}/{plural}"), + }), + + // Stock cluster api form + createBreadcrumb("stock-cluster-api-form", []map[string]any{ + createBreadcrumbItem("create-api-res-namespaced-table", "{apiGroup}/{apiVersion}/{plural}", "/openapi-ui/{cluster}/api-table/{apiGroup}/{apiVersion}/{plural}"), + createBreadcrumbItem("create-api-res-namespaced-typename", "Create"), + }), + + // Stock cluster api form edit + createBreadcrumb("stock-cluster-api-form-edit", []map[string]any{ + createBreadcrumbItem("create-api-res-namespaced-table", "{apiGroup}/{apiVersion}/{plural}", "/openapi-ui/{cluster}/api-table/{apiGroup}/{apiVersion}/{plural}"), + createBreadcrumbItem("create-api-res-namespaced-typename", "Update"), + }), + + // Stock cluster builtin table + createBreadcrumb("stock-cluster-builtin-table", []map[string]any{ + createBreadcrumbItem("api", "v1/{plural}"), + }), + + // Stock cluster builtin form + createBreadcrumb("stock-cluster-builtin-form", []map[string]any{ + createBreadcrumbItem("create-api-res-namespaced-table", "v1/{plural}", "/openapi-ui/{cluster}/builtin-table/{plural}"), + createBreadcrumbItem("create-api-res-namespaced-typename", "Create"), + }), + + // Stock cluster builtin form edit + createBreadcrumb("stock-cluster-builtin-form-edit", []map[string]any{ + createBreadcrumbItem("create-api-res-namespaced-table", "v1/{plural}", "/openapi-ui/{cluster}/builtin-table/{plural}"), + createBreadcrumbItem("create-api-res-namespaced-typename", "Update"), + }), + + // Stock project api table + createBreadcrumb("stock-project-api-table", []map[string]any{ + createBreadcrumbItem("api", "{apiGroup}/{apiVersion}/{plural}"), + }), + + // Stock project api form + createBreadcrumb("stock-project-api-form", []map[string]any{ + createBreadcrumbItem("create-api-res-namespaced-table", "{apiGroup}/{apiVersion}/{plural}", "/openapi-ui/{cluster}/{namespace}/api-table/{apiGroup}/{apiVersion}/{plural}"), + createBreadcrumbItem("create-api-res-namespaced-typename", "Create"), + }), + + // Stock project api form edit + createBreadcrumb("stock-project-api-form-edit", []map[string]any{ + createBreadcrumbItem("create-api-res-namespaced-table", "{apiGroup}/{apiVersion}/{plural}", "/openapi-ui/{cluster}/{namespace}/api-table/{apiGroup}/{apiVersion}/{plural}"), + createBreadcrumbItem("create-api-res-namespaced-typename", "Update"), + }), + + // Stock project builtin table + createBreadcrumb("stock-project-builtin-table", []map[string]any{ + createBreadcrumbItem("api", "v1/{plural}"), + }), + + // Stock project builtin form + createBreadcrumb("stock-project-builtin-form", []map[string]any{ + createBreadcrumbItem("create-api-res-namespaced-table", "v1/{plural}", "/openapi-ui/{cluster}/{namespace}/builtin-table/{plural}"), + createBreadcrumbItem("create-api-res-namespaced-typename", "Create"), + }), + + // Stock project builtin form edit + createBreadcrumb("stock-project-builtin-form-edit", []map[string]any{ + createBreadcrumbItem("create-api-res-namespaced-table", "v1/{plural}", "/openapi-ui/{cluster}/{namespace}/builtin-table/{plural}"), + createBreadcrumbItem("create-api-res-namespaced-typename", "Update"), + }), + } +} + +// CreateAllCustomColumnsOverrides creates all custom column override resources using helper functions +func CreateAllCustomColumnsOverrides() []*dashboardv1alpha1.CustomColumnsOverride { + return []*dashboardv1alpha1.CustomColumnsOverride{ + // Factory details v1 services + createCustomColumnsOverride("factory-details-v1.services", []any{ + createCustomColumnWithSpecificColor("Name", "Service", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-service-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createStringColumn("ClusterIP", ".spec.clusterIP"), + createStringColumn("LoadbalancerIP", ".status.loadBalancer.ingress[0].ip"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + }), + + // Stock namespace v1 services + createCustomColumnsOverride("stock-namespace-/v1/services", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "Service", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-service-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createStringColumn("ClusterIP", ".spec.clusterIP"), + createStringColumn("LoadbalancerIP", ".status.loadBalancer.ingress[0].ip"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + }), + + // Stock namespace core cozystack io v1alpha1 tenantmodules + createCustomColumnsOverride("stock-namespace-/core.cozystack.io/v1alpha1/tenantmodules", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "Module", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/{reqsJsonPath[0]['.metadata.name']['-']}-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createReadyColumn(), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + createStringColumn("Version", ".status.version"), + }), + + // Factory service details endpointslice (Pod serving table) + createCustomColumnsOverride("factory-kube-service-details-endpointslice", []any{ + createStringColumn("Pod", ".targetRef.name"), + createArrayColumn("Addresses", ".addresses"), + createBoolColumn("Ready", ".conditions.ready"), + createStringColumn("Node", ".nodeName"), + }), + + // Factory service details port mapping + createCustomColumnsOverride("factory-kube-service-details-port-mapping", []any{ + createStringColumn("Name", ".name"), + createStringColumn("Port", ".port"), + createStringColumn("Protocol", ".protocol"), + createStringColumn("Pod port or name", ".targetPort"), + }), + + // Factory details v1alpha1 cozystack io workloadmonitors + createCustomColumnsOverride("factory-details-v1alpha1.cozystack.io.workloadmonitors", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "WorkloadMonitor", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/workloadmonitor-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createStringColumn("TYPE", ".spec.type"), + createStringColumn("VERSION", ".spec.version"), + createStringColumn("REPLICAS", ".spec.replicas"), + createStringColumn("MINREPLICAS", ".spec.minReplicas"), + createStringColumn("AVAILABLE", ".status.availableReplicas"), + createStringColumn("OBSERVED", ".status.observedReplicas"), + }), + + // Factory details v1alpha1 core cozystack io tenantsecrets + createCustomColumnsOverride("factory-details-v1alpha1.core.cozystack.io.tenantsecrets", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "Secret", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-secret-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createFlatMapColumn("Data", ".data"), + createStringColumn("Key", "_flatMapData_Key"), + createSecretBase64Column("Value", "._flatMapData_Value"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + }), + + // Virtual private cloud subnets + createCustomColumnsOverride("virtualprivatecloud-subnets", []any{ + createFlatMapColumn("Data", ".data"), + createStringColumn("Subnet Parameters", "_flatMapData_Key"), + createStringColumn("Values", "_flatMapData_Value"), + }), + + // Factory resource quotas + createCustomColumnsOverride("factory-resource-quotas", []any{ + createFlatMapColumn("Data", ".spec.hard"), + createStringColumn("Resource", "_flatMapData_Key"), + createStringColumn("Hard", "_flatMapData_Value"), + createStringColumn("Used", ".status.used[_flatMapData_Key]"), + }), + + // Factory ingress details rules + createCustomColumnsOverride("factory-kube-ingress-details-rules", []any{ + createStringColumn("Host", ".host"), + createCustomColumnWithJsonPath("Service", ".http.paths[0].backend.service.name", "Service", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-service-details/{reqsJsonPath[0]['.http.paths[0].backend.service.name']['-']}"), + createStringColumn("Port", ".http.paths[0].backend.service.port.number"), + createStringColumn("Path", ".http.paths[0].path"), + }), + + // Factory node images + createCustomColumnsOverride("factory-node-images", []any{ + createStringColumn("ImageID", ".names[0]"), + createConverterBytesColumn("Size", ".sizeBytes"), + }), + + // Factory pod details volume list + createCustomColumnsOverride("factory-pod-details-volume-list", []any{ + createStringColumn("Name", ".name"), + }), + + // Factory details events. Event Time falls back to `.firstTimestamp` + // because core/v1 Events (Helm, controller-runtime) populate only the + // legacy timestamps while events.k8s.io/v1 Events populate only + // `.eventTime`; taking the first non-null of the two covers both. + createCustomColumnsOverride("factory-details-events", []any{ + createTimestampColumn("Last Seen", ".lastTimestamp", ".eventTime"), + createTimestampColumn("Event Time", ".eventTime", ".firstTimestamp"), + createStringColumn("Type", ".type"), + createStringColumn("Reason", ".reason"), + createStringColumn("Object", ".involvedObject.kind"), + createStringColumn("Name", ".involvedObject.name"), + createStringColumn("Message", ".message"), + }), + + // Factory status conditions + createCustomColumnsOverride("factory-status-conditions", []any{ + createStringColumn("Type", ".type"), + createBoolColumn("Status", ".status"), + createTimestampColumn("Updated", ".lastTransitionTime"), + createStringColumn("Reason", ".reason"), + createStringColumn("Message", ".message"), + }), + + // Container status init containers list + createCustomColumnsOverride("container-status-init-containers-list", []any{ + createStringColumn("Name", ".name"), + createStringColumn("Image", ".imageID"), + createBoolColumn("Started", ".started"), + createBoolColumn("Ready", ".ready"), + createStringColumn("RestartCount", ".restartCount"), + createStringColumn("WaitingReason", ".state.waiting.reason"), + createStringColumn("TerminatedReason", ".state.terminated.reason"), + }), + + // Container status containers list + createCustomColumnsOverride("container-status-containers-list", []any{ + createStringColumn("Name", ".name"), + createStringColumn("Image", ".imageID"), + createBoolColumn("Started", ".started"), + createBoolColumn("Ready", ".ready"), + createStringColumn("RestartCount", ".restartCount"), + createStringColumn("WaitingReason", ".state.waiting.reason"), + createStringColumn("TerminatedReason", ".state.terminated.reason"), + }), + + // Container spec init containers list + createCustomColumnsOverride("container-spec-init-containers-list", []any{ + createStringColumn("Name", ".name"), + createStringColumn("Image", ".image"), + createArrayColumn("Resources requests", ".resources.requests"), + createArrayColumn("Resources limits", ".resources.limits"), + }), + + // Container spec containers list + createCustomColumnsOverride("container-spec-containers-list", []any{ + createStringColumn("Name", ".name"), + createStringColumn("Image", ".image"), + createArrayColumn("Resources requests", ".resources.requests"), + createArrayColumn("Resources limits", ".resources.limits"), + createArrayColumn("Ports", ".ports[*].containerPort"), + }), + + // Factory details networking k8s io v1 ingresses + createCustomColumnsOverride("factory-details-networking.k8s.io.v1.ingresses", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "Ingress", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-ingress-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createStringColumn("Hosts", ".spec.rules[*].host"), + createStringColumn("Address", ".status.loadBalancer.ingress[0].ip"), + createStringColumn("Port", ".spec.defaultBackend.service.port.number"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + }), + + // Stock namespace networking k8s io v1 ingresses + createCustomColumnsOverride("stock-namespace-/networking.k8s.io/v1/ingresses", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "Ingress", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-ingress-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createStringColumn("Hosts", ".spec.rules[*].host"), + createStringColumn("Address", ".status.loadBalancer.ingress[0].ip"), + createStringColumn("Port", ".spec.defaultBackend.service.port.number"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + }), + + // Stock cluster v1 configmaps + createCustomColumnsOverride("stock-cluster-/v1/configmaps", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "ConfigMap", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/configmap-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Namespace", ".metadata.namespace", "Namespace", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + }), + + // Stock namespace v1 configmaps + createCustomColumnsOverride("stock-namespace-/v1/configmaps", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "ConfigMap", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/configmap-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + }), + + // Cluster v1 configmaps + createCustomColumnsOverride("cluster-/v1/configmaps", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "ConfigMap", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/configmap-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Namespace", ".metadata.namespace", "Namespace", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + }), + + // Stock cluster v1 nodes + createCustomColumnsOverride("stock-cluster-/v1/nodes", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "Node", "", "/openapi-ui/{2}/factory/node-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createSimpleStatusColumn("Status", "node-status"), + }), + + // Factory node details v1 pods + createCustomColumnsOverride("factory-node-details-v1.pods", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "Pod", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/pod-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Namespace", ".metadata.namespace", "Namespace", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace"), + createStringColumn("Restart Policy", ".spec.restartPolicy"), + createStringColumn("Pod IP", ".status.podIP"), + createStringColumn("QOS", ".status.qosClass"), + createSimpleStatusColumn("Status", "pod-status"), + }), + + // Factory v1 pods + createCustomColumnsOverride("factory-v1.pods", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "Pod", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/pod-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithoutJsonPath("Node", "Node", "", "/openapi-ui/{2}/factory/node-details/{reqsJsonPath[0]['.spec.nodeName']['-']}"), + createStringColumn("Restart Policy", ".spec.restartPolicy"), + createStringColumn("Pod IP", ".status.podIP"), + createStringColumn("QOS", ".status.qosClass"), + createSimpleStatusColumn("Status", "pod-status"), + }), + + // Stock cluster v1 pods + createCustomColumnsOverride("stock-cluster-/v1/pods", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "Pod", "#009596", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/pod-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Namespace", ".metadata.namespace", "Namespace", "#a25792ff", "/openapi-ui/{2}/factory/tenantnamespace/{reqsJsonPath[0]['.metadata.namespace']['-']}"), + createCustomColumnWithJsonPath("Node", ".spec.nodeName", "Node", "#8476d1", "/openapi-ui/{2}/factory/node-details/{reqsJsonPath[0]['.spec.nodeName']['-']}"), + createStringColumn("Restart Policy", ".spec.restartPolicy"), + createStringColumn("Pod IP", ".status.podIP"), + createStringColumn("QOS", ".status.qosClass"), + createSimpleStatusColumn("Status", "pod-status"), + }), + + // Stock namespace v1 pods + createCustomColumnsOverride("stock-namespace-/v1/pods", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "Pod", "#009596", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/pod-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithoutJsonPath("Node", "Node", "#8476d1", "/openapi-ui/{2}/factory/node-details/{reqsJsonPath[0]['.spec.nodeName']['-']}"), + createStringColumn("Restart Policy", ".spec.restartPolicy"), + createStringColumn("Pod IP", ".status.podIP"), + createStringColumn("QOS", ".status.qosClass"), + createSimpleStatusColumn("Status", "pod-status"), + }), + + // Stock cluster v1 secrets + createCustomColumnsOverride("stock-cluster-/v1/secrets", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "Secret", "#c46100", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-secret-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createCustomColumnWithJsonPath("Namespace", ".metadata.namespace", "Namespace", "#a25792ff", "/openapi-ui/{2}/factory/tenantnamespace/{reqsJsonPath[0]['.metadata.namespace']['-']}"), + createStringColumn("Type", ".type"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + }), + + // Stock namespace v1 secrets + createCustomColumnsOverride("stock-namespace-/v1/secrets", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "Secret", "#c46100", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/kube-secret-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createStringColumn("Type", ".type"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + }), + + // Factory details v1alpha1 cozystack io workloads + createCustomColumnsOverride("factory-details-v1alpha1.cozystack.io.workloads", []any{ + createStringColumn("Name", ".metadata.name"), + createStringColumn("Kind", ".status.kind"), + createStringColumn("Type", ".status.type"), + createStringColumn("CPU", ".status.resources.cpu"), + createStringColumn("Memory", ".status.resources.memory"), + createStringColumn("Operational", ".status.operational"), + }), + + // Stock cluster core cozystack io v1alpha1 tenantnamespaces + createCustomColumnsOverride("stock-cluster-/core.cozystack.io/v1alpha1/tenantnamespaces", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "TenantNamespace", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.name']['-']}/factory/marketplace"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + }), + + // Stock namespace backups cozystack io v1alpha1 plans + createCustomColumnsOverride("stock-namespace-/backups.cozystack.io/v1alpha1/plans", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "Plan", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/plan-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createApplicationRefColumn("Application"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + }), + + // Stock namespace backups cozystack io v1alpha1 backupjobs + createCustomColumnsOverride("stock-namespace-/backups.cozystack.io/v1alpha1/backupjobs", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "BackupJob", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/backupjob-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createStringColumn("Phase", ".status.phase"), + createApplicationRefColumn("Application"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + }), + + // Stock namespace backups cozystack io v1alpha1 backups + createCustomColumnsOverride("stock-namespace-/backups.cozystack.io/v1alpha1/backups", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "Backup", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/backup-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createStringColumn("Phase", ".status.phase"), + createApplicationRefColumn("Application"), + createTimestampColumn("Taken At", ".spec.takenAt"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + }), + + // Stock namespace backups cozystack io v1alpha1 restorejobs + createCustomColumnsOverride("stock-namespace-/backups.cozystack.io/v1alpha1/restorejobs", []any{ + createCustomColumnWithJsonPath("Name", ".metadata.name", "RestoreJob", "", "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/restorejob-details/{reqsJsonPath[0]['.metadata.name']['-']}"), + createStringColumn("Phase", ".status.phase"), + createStringColumn("Backup", ".spec.backupRef.name"), + createTimestampColumn("Created", ".metadata.creationTimestamp"), + }), + } +} + +// CreateAllCustomFormsOverrides creates all custom forms override resources using helper functions +func CreateAllCustomFormsOverrides() []*dashboardv1alpha1.CustomFormsOverride { + return []*dashboardv1alpha1.CustomFormsOverride{ + // Default networking k8s io v1 ingresses + createCustomFormsOverride("default-/networking.k8s.io/v1/ingresses", map[string]any{ + "formItems": []any{ + createFormItem("metadata.name", "Name", "text"), + createFormItem("metadata.namespace", "Namespace", "text"), + createFormItem("spec.rules", "Rules", "array"), + }, + }), + + // Default storage k8s io v1 storageclasses + createCustomFormsOverride("default-/storage.k8s.io/v1/storageclasses", map[string]any{ + "formItems": []any{ + createFormItem("metadata.name", "Name", "text"), + createFormItem("provisioner", "Provisioner", "text"), + createFormItem("reclaimPolicy", "Reclaim Policy", "select"), + }, + }), + + // Default v1 configmaps + createCustomFormsOverride("default-/v1/configmaps", map[string]any{ + "formItems": []any{ + createFormItem("metadata.name", "Name", "text"), + createFormItem("metadata.namespace", "Namespace", "text"), + createFormItem("data", "Data", "object"), + }, + }), + + // Default v1 namespaces + createCustomFormsOverride("default-/v1/namespaces", map[string]any{ + "formItems": []any{ + createFormItem("metadata.name", "Name", "text"), + createFormItem("metadata.labels", "Labels", "object"), + }, + }), + + // Default v1 nodes + createCustomFormsOverride("default-/v1/nodes", map[string]any{ + "formItems": []any{ + createFormItem("metadata.name", "Name", "text"), + createFormItem("spec.podCIDR", "Pod CIDR", "text"), + }, + }), + + // Default v1 persistentvolumeclaims + createCustomFormsOverride("default-/v1/persistentvolumeclaims", map[string]any{ + "formItems": []any{ + createFormItem("metadata.name", "Name", "text"), + createFormItem("metadata.namespace", "Namespace", "text"), + createFormItem("spec.accessModes", "Access Modes", "array"), + }, + }), + + // Default v1 persistentvolumes + createCustomFormsOverride("default-/v1/persistentvolumes", map[string]any{ + "formItems": []any{ + createFormItem("metadata.name", "Name", "text"), + createFormItem("spec.capacity", "Capacity", "object"), + }, + }), + + // Default v1 pods + createCustomFormsOverride("default-/v1/pods", map[string]any{ + "formItems": []any{ + createFormItem("metadata.name", "Name", "text"), + createFormItem("metadata.namespace", "Namespace", "text"), + createFormItem("spec.containers", "Containers", "array"), + }, + }), + + // Default v1 secrets + createCustomFormsOverride("default-/v1/secrets", map[string]any{ + "formItems": []any{ + createFormItem("metadata.name", "Name", "text"), + createFormItem("metadata.namespace", "Namespace", "text"), + createFormItem("type", "Type", "text"), + }, + }), + + // Default v1 services + createCustomFormsOverride("default-/v1/services", map[string]any{ + "formItems": []any{ + createFormItem("metadata.name", "Name", "text"), + createFormItem("metadata.namespace", "Namespace", "text"), + createFormItem("spec.ports", "Ports", "array"), + }, + }), + + // Plans form override - backups.cozystack.io/v1alpha1 + createCustomFormsOverride("default-/backups.cozystack.io/v1alpha1/plans", map[string]any{ + "formItems": []any{ + createFormItem("metadata.name", "Name", "text"), + createFormItem("metadata.namespace", "Namespace", "text"), + createFormItem("spec.applicationRef.kind", "Application Kind", "text"), + createFormItem("spec.applicationRef.name", "Application Name", "text"), + createFormItem("spec.schedule.type", "Schedule Type", "text"), + createFormItem("spec.schedule.cron", "Schedule Cron", "text"), + }, + "schema": createSchema(map[string]any{ + "backupClassName": listInputScemaItemBackupClass(), + }), + }), + + // BackupJobs form override - backups.cozystack.io/v1alpha1 + createCustomFormsOverride("default-/backups.cozystack.io/v1alpha1/backupjobs", map[string]any{ + "formItems": []any{ + createFormItem("metadata.name", "Name", "text"), + createFormItem("metadata.namespace", "Namespace", "text"), + createFormItem("spec.planRef.name", "Plan Name (optional)", "text"), + createFormItem("spec.applicationRef.apiGroup", "Application API Group", "text"), + createFormItem("spec.applicationRef.kind", "Application Kind", "text"), + createFormItem("spec.applicationRef.name", "Application Name", "text"), + }, + "schema": createSchema(map[string]any{ + "backupClassName": listInputScemaItemBackupClass(), + }), + }), + + // RestoreJobs form override - backups.cozystack.io/v1alpha1 + createCustomFormsOverride("default-/backups.cozystack.io/v1alpha1/restorejobs", map[string]any{ + "formItems": []any{ + createFormItem("metadata.name", "Name", "text"), + createFormItem("metadata.namespace", "Namespace", "text"), + createFormItem("spec.backupRef.name", "Backup", "text"), + // Target application: leave empty to restore into the same application + // as referenced by the selected Backup. Fill all three to restore into + // a different application (e.g. rename, or restore into a new target). + createFormItem("spec.targetApplicationRef.apiGroup", "Target Application API Group (optional, used to restore into a different application)", "text"), + createFormItem("spec.targetApplicationRef.kind", "Target Application Kind (optional, used to restore into a different application)", "text"), + createFormItem("spec.targetApplicationRef.name", "Target Application Name (optional, used to restore into a different application)", "text"), + // Driver-specific options (key-value editor). Refer to the backup driver + // documentation for supported keys. + createFormItem("spec.options", "Options (driver-specific key/value pairs)", "object"), + }, + "schema": createSchema(map[string]any{ + "backupRef": map[string]any{ + "properties": map[string]any{ + "name": listInputSchemaItemBackup(), + }, + }, + }), + }), + } +} + +// CreateAllFactories creates all factory resources using helper functions +func CreateAllFactories() []*dashboardv1alpha1.Factory { + // Marketplace factory + marketplaceSpec := map[string]any{ + "key": "marketplace", + "sidebarTags": []any{ + "marketplace-sidebar", + }, + "urlsToFetch": []any{}, + "withScrollableMainContentCard": true, + "data": []any{ + contentCardWithTitle(31, "Marketplace", map[string]any{ + "flexGrow": 1, + }, []any{ + map[string]any{ + "data": map[string]any{ + "baseApiVersion": "v1alpha1", + "baseprefix": "openapi-ui", + "cluster": "{2}", + "id": 311, + "marketplaceKind": "MarketplacePanel", + "marketplacePlural": "marketplacepanels", + "namespace": "{3}", + "baseApiGroup": "dashboard.cozystack.io", + }, + "type": "MarketplaceCard", + }, + }), + }, + } + + // Namespace details factory using unified approach + namespaceConfig := UnifiedResourceConfig{ + Name: "namespace-details", + ResourceType: "factory", + Kind: "Namespace", + Plural: "namespaces", + Title: "namespace", + } + namespaceSpec := createUnifiedFactory(namespaceConfig, nil, []any{"/api/clusters/{2}/k8s/api/v1/namespaces/{5}"}) + + // Node details factory + nodeHeader := createNodeHeader() + // Create node spec with tabs containing items + nodeTabs := []any{ + map[string]any{ + "key": "details", + "label": "Details", + "children": []any{ + map[string]any{ + "type": "ContentCard", + "data": map[string]any{ + "id": "details-card", + "style": map[string]any{ + "marginBottom": "24px", + }, + }, + "children": []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "details-title", + "text": "Node details", + "strong": true, + "style": map[string]any{ + "fontSize": float64(20), + "marginBottom": "12px", + }, + }, + }, + }, + }, + }, + }, + } + nodeSpec := map[string]any{ + "key": "node-details", + "sidebarTags": []any{"node-sidebar"}, + "withScrollableMainContentCard": true, + "urlsToFetch": []any{"/api/clusters/{2}/k8s/api/v1/nodes/{5}"}, + "data": []any{ + nodeHeader, + map[string]any{ + "type": "antdTabs", + "data": map[string]any{ + "id": "tabs-root", + "defaultActiveKey": "details", + "items": nodeTabs, + }, + }, + }, + } + + // Pod details factory + podHeader := createPodHeader() + // Create pod spec with empty tabs (items: nil) + podSpec := map[string]any{ + "key": "pod-details", + "sidebarTags": []any{"pods-sidebar"}, + "withScrollableMainContentCard": true, + "urlsToFetch": []any{"/api/clusters/{2}/k8s/api/v1/namespaces/{3}/pods/{6}"}, + "data": []any{ + podHeader, + map[string]any{ + "type": "antdTabs", + "data": map[string]any{ + "id": "tabs-root", + "defaultActiveKey": "details", + "items": nil, + }, + }, + }, + } + + // Secret details factory + secretHeader := map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "header-row", + "align": "center", + "gap": float64(6), + "style": map[string]any{ + "marginBottom": "24px", + }, + }, + "children": []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "badge-secret", + "text": "S", + "title": "secret", + "style": map[string]any{ + "backgroundColor": "#c46100", + "borderRadius": "20px", + "color": "#fff", + "display": "inline-block", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": "20px", + "fontWeight": 400, + "lineHeight": "24px", + "minWidth": 24, + "padding": "0 9px", + "textAlign": "center", + "whiteSpace": "nowrap", + }, + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "id": "header-secret-name", + "text": "{reqsJsonPath[0]['.metadata.name']['-']}", + "style": map[string]any{ + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": "20px", + "lineHeight": "24px", + }, + }, + }, + }, + } + secretTabs := []any{ + map[string]any{ + "key": "details", + "label": "Details", + "children": []any{ + contentCard("details-card", map[string]any{ + "marginBottom": "24px", + }, []any{ + antdText("details-title", true, "Secret details", map[string]any{ + "fontSize": 20, + "marginBottom": "12px", + }), + spacer("details-spacer", 16), + antdRow("details-grid", []any{48, 12}, []any{ + antdCol("col-left", 12, []any{ + antdFlexVertical("col-left-stack", 24, []any{ + antdFlexVertical("meta-name-block", 4, []any{ + antdText("meta-name-label", true, "Name", nil), + parsedText("meta-name-value", "{reqsJsonPath[0]['.metadata.name']['-']}", nil), + }), + antdFlexVertical("meta-namespace-block", 8, []any{ + antdText("meta-name-label", true, "Namespace", nil), + antdFlex("header-row", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "header-badge", + "text": "NS", + "title": "namespace", + "style": map[string]any{ + "backgroundColor": "#a25792ff", + "borderRadius": "20px", + "color": "#fff", + "display": "inline-block", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": "15px", + "fontWeight": 400, + "lineHeight": "24px", + "minWidth": 24, + "padding": "0 9px", + "textAlign": "center", + "whiteSpace": "nowrap", + }, + }, + }, + map[string]any{ + "type": "antdLink", + "data": map[string]any{ + "id": "namespace-link", + "text": "{reqsJsonPath[0]['.metadata.namespace']['-']}", + "href": "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace", + }, + }, + }), + }), + antdFlexVertical("meta-labels-block", 8, []any{ + antdText("labels-title", true, "Labels", map[string]any{ + "fontSize": 14, + }), + map[string]any{ + "type": "Labels", + "data": map[string]any{ + "id": "labels-editor", + "endpoint": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/secrets/{6}", + "jsonPathToLabels": ".metadata.labels", + "pathToValue": "/metadata/labels", + "reqIndex": 0, + "modalTitle": "Edit labels", + "modalDescriptionText": "", + "inputLabel": "", + "notificationSuccessMessage": "Updated successfully", + "notificationSuccessMessageDescription": "Labels have been updated", + "editModalWidth": 650, + "maxEditTagTextLength": 35, + "paddingContainerEnd": "24px", + "containerStyle": map[string]any{ + "marginTop": "-30px", + }, + "selectProps": map[string]any{ + "maxTagTextLength": 35, + }, + }, + }, + }), + antdFlexVertical("ds-annotations", 4, []any{ + antdText("annotations", true, "Annotations", nil), + map[string]any{ + "type": "Annotations", + "data": map[string]any{ + "id": "annotations", + "endpoint": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/secrets/{6}", + "jsonPathToObj": ".metadata.annotations", + "pathToValue": "/metadata/annotations", + "reqIndex": 0, + "modalTitle": "Edit annotations", + "modalDescriptionText": "", + "inputLabel": "", + "notificationSuccessMessage": "Updated successfully", + "notificationSuccessMessageDescription": "Annotations have been updated", + "editModalWidth": "800px", + "errorText": "0 Annotations", + "text": "~counter~ Annotations", + "cols": []any{11, 11, 2}, + }, + }, + }), + antdFlexVertical("meta-created-block", 4, []any{ + antdText("time-label", true, "Created", nil), + antdFlex("time-block", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "time-icon", + "text": "🌐", + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "formatter": "timestamp", + "id": "time-value", + "text": "{reqsJsonPath[0]['.metadata.creationTimestamp']['-']}", + }, + }, + }), + }), + }), + }), + antdCol("col-right", 12, []any{ + antdFlexVertical("col-right-stack", 24, []any{ + antdFlexVertical("secret-type-block", 4, []any{ + antdText("secret-type-label", true, "Type", nil), + parsedText("secret-type-value", "{reqsJsonPath[0]['.type']['-']}", nil), + }), + antdFlexVertical("secret-sa-block", 4, []any{ + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "id": "serviceaccount-title", + "text": "ServiceAccount", + "strong": true, + "style": map[string]any{ + "fontWeight": "bold", + }, + }, + }, + map[string]any{ + "type": "antdLink", + "data": map[string]any{ + "id": "serviceaccount-link", + "text": "{reqsJsonPath[0]['.metadata.annotations[\"kubernetes.io/service-account.name\"]']['-']}", + "href": "/openapi-ui/{2}/{3}/factory/serviceaccount-details/{reqsJsonPath[0]['.metadata.annotations[\"kubernetes.io/service-account.name\"]']['-']}", + }, + }, + }), + }), + }), + }), + }), + }, + }, + map[string]any{ + "key": "yaml", + "label": "YAML", + "children": []any{ + map[string]any{ + "type": "YamlEditorSingleton", + "data": map[string]any{ + "id": "yaml-editor", + "cluster": "{2}", + "isNameSpaced": true, + "prefillValuesRequestIndex": 0, + "substractHeight": float64(400), + "type": "builtin", + "plural": "secrets", + "readOnly": true, + }, + }, + }, + }, + } + secretSpec := createFactorySpec("kube-secret-details", []any{"secret-sidebar"}, []any{"/api/clusters/{2}/k8s/api/v1/namespaces/{3}/secrets/{6}"}, secretHeader, secretTabs) + + // Service details factory + serviceHeader := map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "header-row", + "align": "center", + "gap": float64(6), + "style": map[string]any{ + "marginBottom": "24px", + }, + }, + "children": []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "badge-service", + "text": "S", + "title": "services", + "style": map[string]any{ + "backgroundColor": "#6ca100", + "borderRadius": "20px", + "color": "#fff", + "display": "inline-block", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": "20px", + "fontWeight": 400, + "lineHeight": "24px", + "minWidth": 24, + "padding": "0 9px", + "textAlign": "center", + "whiteSpace": "nowrap", + }, + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "id": "service-name", + "text": "{reqsJsonPath[0]['.metadata.name']['-']}", + "style": map[string]any{ + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": "20px", + "lineHeight": "24px", + }, + }, + }, + }, + } + serviceTabs := []any{ + map[string]any{ + "key": "details", + "label": "Details", + "children": []any{ + contentCard("details-card", map[string]any{ + "marginBottom": "24px", + }, []any{ + antdText("details-title", true, "Service details", map[string]any{ + "fontSize": 20, + "marginBottom": "12px", + }), + spacer("details-spacer", 16), + antdRow("details-grid", []any{48, 12}, []any{ + antdCol("col-left", 12, []any{ + antdFlexVertical("col-left-stack", 24, []any{ + antdFlexVertical("meta-name-block", 4, []any{ + antdText("meta-name-label", true, "Name", nil), + parsedText("meta-name-value", "{reqsJsonPath[0]['.metadata.name']['-']}", nil), + }), + antdFlexVertical("meta-namespace-block", 8, []any{ + antdText("meta-name-label", true, "Namespace", nil), + antdFlex("header-row", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "header-badge", + "text": "NS", + "title": "namespace", + "style": map[string]any{ + "backgroundColor": "#a25792ff", + "borderRadius": "20px", + "color": "#fff", + "display": "inline-block", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": "15px", + "fontWeight": 400, + "lineHeight": "24px", + "minWidth": 24, + "padding": "0 9px", + "textAlign": "center", + "whiteSpace": "nowrap", + }, + }, + }, + map[string]any{ + "type": "antdLink", + "data": map[string]any{ + "id": "namespace-link", + "text": "{reqsJsonPath[0]['.metadata.namespace']['-']}", + "href": "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace", + }, + }, + }), + }), + antdFlexVertical("meta-labels-block", 8, []any{ + antdText("labels-title", true, "Labels", map[string]any{ + "fontSize": 14, + }), + map[string]any{ + "type": "Labels", + "data": map[string]any{ + "id": "labels-editor", + "endpoint": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/services/{6}", + "jsonPathToLabels": ".metadata.labels", + "pathToValue": "/metadata/labels", + "reqIndex": 0, + "modalTitle": "Edit labels", + "modalDescriptionText": "", + "inputLabel": "", + "notificationSuccessMessage": "Updated successfully", + "notificationSuccessMessageDescription": "Labels have been updated", + "editModalWidth": 650, + "maxEditTagTextLength": 35, + "paddingContainerEnd": "24px", + "containerStyle": map[string]any{ + "marginTop": "-30px", + }, + "selectProps": map[string]any{ + "maxTagTextLength": 35, + }, + }, + }, + }), + antdFlexVertical("meta-pod-selector-block", 4, []any{ + antdText("pod-selector", true, "Pod selector", map[string]any{ + "fontSize": 14, + }), + map[string]any{ + "type": "LabelsToSearchParams", + "data": map[string]any{ + "id": "pod-to-search-params", + "jsonPathToLabels": ".spec.selector", + "linkPrefix": "/openapi-ui/{2}/search", + "reqIndex": 0, + "errorText": "-", + }, + }, + }), + antdFlexVertical("ds-annotations", 4, []any{ + antdText("annotations", true, "Annotations", nil), + map[string]any{ + "type": "Annotations", + "data": map[string]any{ + "id": "annotations", + "endpoint": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/services/{6}", + "jsonPathToObj": ".metadata.annotations", + "pathToValue": "/metadata/annotations", + "reqIndex": 0, + "modalTitle": "Edit annotations", + "modalDescriptionText": "", + "inputLabel": "", + "notificationSuccessMessage": "Updated successfully", + "notificationSuccessMessageDescription": "Annotations have been updated", + "editModalWidth": "800px", + "errorText": "0 Annotations", + "text": "~counter~ Annotations", + "cols": []any{11, 11, 2}, + }, + }, + }), + antdFlexVertical("meta-session-affinity-block", 4, []any{ + antdText("meta-session-affinity-label", true, "Session affinity", nil), + parsedText("meta-session-affinity-value", "{reqsJsonPath[0]['.spec.sessionAffinity']['Not configured']}", nil), + }), + antdFlexVertical("meta-created-block", 4, []any{ + antdText("time-label", true, "Created", nil), + antdFlex("time-block", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "time-icon", + "text": "🌐", + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "formatter": "timestamp", + "id": "time-value", + "text": "{reqsJsonPath[0]['.metadata.creationTimestamp']['-']}", + }, + }, + }), + }), + }), + }), + antdCol("col-right", 12, []any{ + antdFlexVertical("col-right-stack", 24, []any{ + antdText("routing-title", true, "Service routing", map[string]any{ + "fontSize": 20, + "marginBottom": "12px", + }), + spacer("routing-spacer", 16), + antdFlexVertical("service-hostname-block", 4, []any{ + antdText("service-hostname-label", true, "Hostname", nil), + parsedText("service-hostname-value", "{reqsJsonPath[0]['.metadata.name']['-']}.{reqsJsonPath[0]['.metadata.namespace']['-']}.svc.cluster.local", nil), + }), + antdFlexVertical("service-ip-block", 12, []any{ + antdFlexVertical("clusterip-block", 4, []any{ + antdText("clusterip-label", true, "ClusterIP address", nil), + parsedText("clusterip-value", "{reqsJsonPath[0]['.spec.clusterIP']['-']}", nil), + }), + antdFlexVertical("loadbalancerip-block", 4, []any{ + antdText("loadbalancerip-label", true, "LoadBalancerIP address", nil), + parsedText("loadbalancerip-value", "{reqsJsonPath[0]['.status.loadBalancer.ingress[0].ip']['Not Configured']}", nil), + }), + }), + antdFlexVertical("service-port-mapping-block", 4, []any{ + antdText("service-port-mapping-label", true, "Service port mapping", nil), + map[string]any{ + "type": "EnrichedTable", + "data": map[string]any{ + "id": "service-port-mapping-table", + "baseprefix": "/openapi-ui", + "cluster": "{2}", + "customizationId": "factory-kube-service-details-port-mapping", + "fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/services/{6}", + "pathToItems": ".spec.ports", + "withoutControls": true, + }, + }, + }), + map[string]any{ + "type": "VisibilityContainer", + "data": map[string]any{ + "id": "service-pod-serving-vis", + "value": "{reqsJsonPath[0]['.spec.selector']['-']}", + "style": map[string]any{ + "margin": 0, + "padding": 0, + }, + }, + "children": []any{ + antdFlexVertical("service-pod-serving-block", 4, []any{ + antdText("service-pod-serving-label", true, "Pod serving", nil), + map[string]any{ + "type": "EnrichedTable", + "data": map[string]any{ + "id": "service-pod-serving-table", + "baseprefix": "/openapi-ui", + "cluster": "{2}", + "customizationId": "factory-kube-service-details-endpointslice", + "fetchUrl": "/api/clusters/{2}/k8s/apis/discovery.k8s.io/v1/namespaces/{3}/endpointslices", + "labelSelector": map[string]any{ + "kubernetes.io/service-name": "{reqsJsonPath[0]['.metadata.name']['-']}", + }, + "pathToItems": ".items[*].endpoints", + "withoutControls": true, + }, + }, + }), + }, + }, + }), + }), + }), + }), + }, + }, + map[string]any{ + "key": "yaml", + "label": "YAML", + "children": []any{ + map[string]any{ + "type": "YamlEditorSingleton", + "data": map[string]any{ + "id": "yaml-editor", + "cluster": "{2}", + "isNameSpaced": true, + "prefillValuesRequestIndex": 0, + "substractHeight": float64(400), + "type": "builtin", + "plural": "services", + }, + }, + }, + }, + map[string]any{ + "key": "pods", + "label": "Pods", + "children": []any{ + map[string]any{ + "type": "VisibilityContainer", + "data": map[string]any{ + "id": "service-pod-serving-vis", + "value": "{reqsJsonPath[0]['.spec.selector']['-']}", + "style": map[string]any{ + "margin": 0, + "padding": 0, + }, + }, + "children": []any{ + map[string]any{ + "type": "EnrichedTable", + "data": map[string]any{ + "id": "pods-table", + "baseprefix": "/openapi-ui", + "cluster": "{2}", + "customizationId": "factory-node-details-/v1/pods", + "fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/pods", + "labelSelectorFull": map[string]any{ + "pathToLabels": ".spec.selector", + "reqIndex": 0, + }, + "pathToItems": ".items", + "withoutControls": false, + }, + }, + }, + }, + }, + }, + } + serviceSpec := createFactorySpec("kube-service-details", []any{"service-sidebar"}, []any{"/api/clusters/{2}/k8s/api/v1/namespaces/{3}/services/{6}"}, serviceHeader, serviceTabs) + + // Ingress details factory + ingressHeader := map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "header-row", + "align": "center", + "gap": 6, + "style": map[string]any{ + "marginBottom": float64(24), + }, + }, + "children": []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "badge-ingress", + "text": "I", + "title": "ingresses", + "style": map[string]any{ + "backgroundColor": "#2e7dff", + "borderRadius": "20px", + "color": "#fff", + "display": "inline-block", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": float64(20), + "fontWeight": float64(400), + "lineHeight": "24px", + "minWidth": float64(24), + "padding": "0 9px", + "textAlign": "center", + "whiteSpace": "nowrap", + }, + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "id": "ingress-name", + "text": "{reqsJsonPath[0]['.metadata.name']['-']}", + "style": map[string]any{ + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": float64(20), + "lineHeight": "24px", + }, + }, + }, + }, + } + + ingressTabs := []any{ + map[string]any{ + "key": "details", + "label": "Details", + "children": []any{ + contentCard("details-card", map[string]any{ + "marginBottom": float64(24), + }, []any{ + antdRow("details-grid", []any{48, 12}, []any{ + antdCol("col-left", 12, []any{ + antdFlexVertical("col-left-stack", 24, []any{ + antdFlexVertical("meta-name-block", 4, []any{ + antdText("meta-name-label", true, "Name", nil), + parsedText("meta-name-value", "{reqsJsonPath[0]['.metadata.name']['-']}", nil), + }), + antdFlexVertical("meta-namespace-block", 8, []any{ + antdText("meta-namespace-label", true, "Namespace", nil), + map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "namespace-row", + "align": "center", + "gap": 6, + }, + "children": []any{ + createUnifiedBadgeFromKind("ns-badge", "Namespace"), + antdLink("namespace-link", + "{reqsJsonPath[0]['.metadata.namespace']['-']}", + "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace", + ), + }, + }, + }), + antdFlexVertical("meta-created-block", 4, []any{ + antdText("time-label", true, "Created", nil), + antdFlex("time-block", 6, []any{ + antdText("time-icon", false, "🌐", nil), + parsedTextWithFormatter("time-value", "{reqsJsonPath[0]['.metadata.creationTimestamp']['-']}", "timestamp"), + }), + }), + }), + }), + antdCol("col-right", 12, []any{ + antdFlexVertical("col-right-stack", 24, []any{ + antdFlexVertical("status-ingress-ip", 4, []any{ + antdText("status-ingress-ip-label", true, "LoadBalancer IP", nil), + parsedText("status-ingress-ip-value", "{reqsJsonPath[0]['.status.loadBalancer.ingress[0].ip']['-']}", nil), + }), + antdFlexVertical("status-ingress-hostname", 4, []any{ + antdText("status-ingress-hostname-label", true, "LoadBalancer Hostname", nil), + parsedText("status-ingress-hostname-value", "{reqsJsonPath[0]['.status.loadBalancer.ingress[0].hostname']['-']}", nil), + }), + }), + }), + }), + spacer("rules-title-spacer", float64(16)), + antdText("rules-title", true, "Rules", map[string]any{ + "fontSize": float64(20), + }), + spacer("rules-spacer", float64(8)), + map[string]any{ + "type": "EnrichedTable", + "data": map[string]any{ + "id": "rules-table", + "fetchUrl": "/api/clusters/{2}/k8s/apis/networking.k8s.io/v1/namespaces/{3}/ingresses/{6}", + "cluster": "{2}", + "customizationId": "factory-kube-ingress-details-rules", + "baseprefix": "/openapi-ui", + "withoutControls": true, + "pathToItems": []any{"spec", "rules"}, + }, + }, + }), + }, + }, + map[string]any{ + "key": "yaml", + "label": "YAML", + "children": []any{ + map[string]any{ + "type": "YamlEditorSingleton", + "data": map[string]any{ + "id": "yaml-editor", + "cluster": "{2}", + "isNameSpaced": true, + "type": "apis", + "apiGroup": "networking.k8s.io", + "apiVersion": "v1", + "plural": "ingresses", + "prefillValuesRequestIndex": float64(0), + "substractHeight": float64(400), + }, + }, + }, + }, + } + ingressSpec := createFactorySpec("kube-ingress-details", []any{"ingress-sidebar"}, []any{"/api/clusters/{2}/k8s/apis/networking.k8s.io/v1/namespaces/{3}/ingresses/{6}"}, ingressHeader, ingressTabs) + + // Workloadmonitor details factory + workloadmonitorHeader := createWorkloadmonitorHeader() + workloadmonitorTabs := []any{ + map[string]any{ + "key": "details", + "label": "Details", + "children": []any{ + contentCard("details-card", map[string]any{ + "marginBottom": float64(24), + }, []any{ + antdRow("details-grid", []any{48, 12}, []any{ + antdCol("col-left", 12, []any{ + antdFlexVertical("col-left-stack", 24, []any{ + antdFlexVertical("meta-name-block", 4, []any{ + antdText("meta-name-label", true, "Name", nil), + parsedText("meta-name-value", "{reqsJsonPath[0]['.metadata.name']['-']}", nil), + }), + antdFlexVertical("meta-namespace-block", 8, []any{ + antdText("meta-namespace-label", true, "Namespace", nil), + antdFlex("namespace-row", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "ns-badge", + "text": "NS", + "style": map[string]any{ + "backgroundColor": "#a25792ff", + "borderRadius": "20px", + "color": "#fff", + "display": "inline-block", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": 15, + "fontWeight": 400, + "lineHeight": "24px", + "minWidth": 24, + "padding": "0 9px", + "textAlign": "center", + "whiteSpace": "nowrap", + }, + }, + }, + map[string]any{ + "type": "antdLink", + "data": map[string]any{ + "id": "namespace-link", + "text": "{reqsJsonPath[0]['.metadata.namespace']['-']}", + "href": "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace", + }, + }, + }), + }), + antdFlexVertical("meta-created-block", 4, []any{ + antdText("time-label", true, "Created", nil), + antdFlex("time-block", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "time-icon", + "text": "🌐", + }, + }, + parsedTextWithFormatter("time-value", "{reqsJsonPath[0]['.metadata.creationTimestamp']['-']}", "timestamp"), + }), + }), + antdFlexVertical("meta-kind-block", 4, []any{ + antdText("kind-label", true, "Kind", nil), + parsedText("kind-value", "{reqsJsonPath[0]['.spec.kind']['-']}", nil), + }), + antdFlexVertical("meta-type-block", 4, []any{ + antdText("type-label", true, "Type", nil), + parsedText("type-value", "{reqsJsonPath[0]['.spec.type']['-']}", nil), + }), + }), + }), + antdCol("col-right", 12, []any{ + antdFlexVertical("col-right-stack", 24, []any{ + antdText("params-title", true, "Parameters", map[string]any{ + "fontSize": float64(20), + "marginBottom": float64(12), + }), + antdFlexVertical("params-list", 24, []any{ + antdFlexVertical("param-version", 4, []any{ + antdText("param-version-label", true, "Version", nil), + parsedText("param-version-value", "{reqsJsonPath[0]['.spec.version']['-']}", nil), + }), + antdFlexVertical("param-replicas", 4, []any{ + antdText("param-replicas-label", true, "Replicas", nil), + parsedText("param-replicas-value", "{reqsJsonPath[0]['.spec.replicas']['-']}", nil), + }), + antdFlexVertical("param-minreplicas", 4, []any{ + antdText("param-minreplicas-label", true, "MinReplicas", nil), + parsedText("param-minreplicas-value", "{reqsJsonPath[0]['.spec.minReplicas']['-']}", nil), + }), + antdFlexVertical("param-available", 4, []any{ + antdText("param-available-label", true, "AvailableReplicas", nil), + parsedText("param-available-value", "{reqsJsonPath[0]['.status.availableReplicas']['-']}", nil), + }), + antdFlexVertical("param-observed", 4, []any{ + antdText("param-observed-label", true, "ObservedReplicas", nil), + parsedText("param-observed-value", "{reqsJsonPath[0]['.status.observedReplicas']['-']}", nil), + }), + antdFlexVertical("param-operational", 4, []any{ + antdText("param-operational-label", true, "Operational", nil), + parsedText("param-operational-value", "{reqsJsonPath[0]['.status.operational']['-']}", nil), + }), + }), + }), + }), + }), + }), + }, + }, + map[string]any{ + "key": "workloads", + "label": "Workloads", + "children": []any{ + map[string]any{ + "type": "EnrichedTable", + "data": map[string]any{ + "id": "workloads-table", + "baseprefix": "/openapi-ui", + "cluster": "{2}", + "customizationId": "factory-details-v1alpha1.cozystack.io.workloads", + "fetchUrl": "/api/clusters/{2}/k8s/apis/cozystack.io/v1alpha1/namespaces/{3}/workloads", + "labelSelector": map[string]any{ + "workloads.cozystack.io/monitor": "{reqs[0]['metadata','name']}", + }, + "pathToItems": []any{"items"}, + }, + }, + }, + }, + map[string]any{ + "key": "yaml", + "label": "YAML", + "children": []any{ + map[string]any{ + "type": "YamlEditorSingleton", + "data": map[string]any{ + "id": "yaml-editor", + "cluster": "{2}", + "isNameSpaced": true, + "prefillValuesRequestIndex": 0, + "substractHeight": float64(400), + "type": "apis", + "apiGroup": "cozystack.io", + "apiVersion": "v1alpha1", + "plural": "workloadmonitors", + }, + }, + }, + }, + } + workloadmonitorSpec := createFactorySpec("workloadmonitor-details", []any{"workloadmonitor-sidebar"}, []any{"/api/clusters/{2}/k8s/apis/cozystack.io/v1alpha1/namespaces/{3}/workloadmonitors/{6}"}, workloadmonitorHeader, workloadmonitorTabs) + + // Plan details factory using unified approach + planConfig := UnifiedResourceConfig{ + Name: "plan-details", + ResourceType: "factory", + Kind: "Plan", + Plural: "plans", + Title: "plan", + } + planTabs := []any{ + map[string]any{ + "key": "details", + "label": "Details", + "children": []any{ + contentCard("details-card", map[string]any{ + "marginBottom": "24px", + }, []any{ + antdText("details-title", true, "Plan details", map[string]any{ + "fontSize": 20, + "marginBottom": "12px", + }), + spacer("details-spacer", 16), + antdRow("details-grid", []any{48, 12}, []any{ + antdCol("col-left", 12, []any{ + antdFlexVertical("col-left-stack", 24, []any{ + antdFlexVertical("meta-name-block", 4, []any{ + antdText("meta-name-label", true, "Name", nil), + parsedText("meta-name-value", "{reqsJsonPath[0]['.metadata.name']['-']}", nil), + }), + antdFlexVertical("meta-namespace-block", 8, []any{ + antdText("meta-namespace-label", true, "Namespace", nil), + antdFlex("header-row", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "header-badge", + "text": "NS", + "title": "namespace", + "style": map[string]any{ + "backgroundColor": "#a25792ff", + "borderRadius": "20px", + "color": "#fff", + "display": "inline-block", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": "15px", + "fontWeight": 400, + "lineHeight": "24px", + "minWidth": 24, + "padding": "0 9px", + "textAlign": "center", + "whiteSpace": "nowrap", + }, + }, + }, + map[string]any{ + "type": "antdLink", + "data": map[string]any{ + "id": "namespace-link", + "text": "{reqsJsonPath[0]['.metadata.namespace']['-']}", + "href": "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace", + }, + }, + }), + }), + antdFlexVertical("meta-created-block", 4, []any{ + antdText("time-label", true, "Created", nil), + antdFlex("time-block", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "time-icon", + "text": "🌐", + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "formatter": "timestamp", + "id": "time-value", + "text": "{reqsJsonPath[0]['.metadata.creationTimestamp']['-']}", + }, + }, + }), + }), + }), + }), + antdCol("col-right", 12, []any{ + antdFlexVertical("col-right-stack", 24, []any{ + antdFlexVertical("spec-application-ref-block", 4, []any{ + antdText("application-ref-label", true, "Application", nil), + parsedText("application-ref-value", "{reqsJsonPath[0]['.spec.applicationRef.kind']['-']}.{reqsJsonPath[0]['.spec.applicationRef.apiGroup']['-']}/{reqsJsonPath[0]['.spec.applicationRef.name']['-']}", nil), + }), + antdFlexVertical("spec-backup-class-name-block", 4, []any{ + antdText("backup-class-name-label", true, "Backup Class", nil), + parsedText("backup-class-name-value", "{reqsJsonPath[0]['.spec.backupClassName']['-']}", nil), + }), + antdFlexVertical("spec-schedule-type-block", 4, []any{ + antdText("schedule-type-label", true, "Schedule Type", nil), + parsedText("schedule-type-value", "{reqsJsonPath[0]['.spec.schedule.type']['-']}", nil), + }), + antdFlexVertical("spec-schedule-cron-block", 4, []any{ + antdText("schedule-cron-label", true, "Schedule Cron", nil), + parsedText("schedule-cron-value", "{reqsJsonPath[0]['.spec.schedule.cron']['-']}", nil), + }), + }), + }), + }), + }), + }, + }, + } + planSpec := createUnifiedFactory(planConfig, planTabs, []any{"/api/clusters/{2}/k8s/apis/backups.cozystack.io/v1alpha1/namespaces/{3}/plans/{6}"}) + + // BackupJob details factory using unified approach + backupJobConfig := UnifiedResourceConfig{ + Name: "backupjob-details", + ResourceType: "factory", + Kind: "BackupJob", + Plural: "backupjobs", + Title: "backupjob", + } + backupJobTabs := []any{ + map[string]any{ + "key": "details", + "label": "Details", + "children": []any{ + contentCard("details-card", map[string]any{ + "marginBottom": "24px", + }, []any{ + antdText("details-title", true, "BackupJob details", map[string]any{ + "fontSize": 20, + "marginBottom": "12px", + }), + spacer("details-spacer", 16), + antdRow("details-grid", []any{48, 12}, []any{ + antdCol("col-left", 12, []any{ + antdFlexVertical("col-left-stack", 24, []any{ + antdFlexVertical("meta-name-block", 4, []any{ + antdText("meta-name-label", true, "Name", nil), + parsedText("meta-name-value", "{reqsJsonPath[0]['.metadata.name']['-']}", nil), + }), + antdFlexVertical("meta-namespace-block", 8, []any{ + antdText("meta-namespace-label", true, "Namespace", nil), + antdFlex("header-row", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "header-badge", + "text": "NS", + "title": "namespace", + "style": map[string]any{ + "backgroundColor": "#a25792ff", + "borderRadius": "20px", + "color": "#fff", + "display": "inline-block", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": "15px", + "fontWeight": 400, + "lineHeight": "24px", + "minWidth": 24, + "padding": "0 9px", + "textAlign": "center", + "whiteSpace": "nowrap", + }, + }, + }, + map[string]any{ + "type": "antdLink", + "data": map[string]any{ + "id": "namespace-link", + "text": "{reqsJsonPath[0]['.metadata.namespace']['-']}", + "href": "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace", + }, + }, + }), + }), + antdFlexVertical("meta-created-block", 4, []any{ + antdText("time-label", true, "Created", nil), + antdFlex("time-block", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "time-icon", + "text": "🌐", + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "formatter": "timestamp", + "id": "time-value", + "text": "{reqsJsonPath[0]['.metadata.creationTimestamp']['-']}", + }, + }, + }), + }), + }), + }), + antdCol("col-right", 12, []any{ + antdFlexVertical("col-right-stack", 24, []any{ + antdFlexVertical("status-phase-block", 4, []any{ + antdText("phase-label", true, "Phase", nil), + parsedText("phase-value", "{reqsJsonPath[0]['.status.phase']['-']}", nil), + }), + antdFlexVertical("spec-plan-ref-block", 4, []any{ + antdText("plan-ref-label", true, "Plan Ref", nil), + parsedText("plan-ref-value", "{reqsJsonPath[0]['.spec.planRef.name']['-']}", nil), + }), + antdFlexVertical("spec-application-ref-block", 4, []any{ + antdText("application-ref-label", true, "Application", nil), + parsedText("application-ref-value", "{reqsJsonPath[0]['.spec.applicationRef.kind']['-']}.{reqsJsonPath[0]['.spec.applicationRef.apiGroup']['-']}/{reqsJsonPath[0]['.spec.applicationRef.name']['-']}", nil), + }), + antdFlexVertical("spec-backup-class-name-block", 4, []any{ + antdText("backup-class-name-label", true, "Backup Class", nil), + parsedText("backup-class-name-value", "{reqsJsonPath[0]['.spec.backupClassName']['-']}", nil), + }), + antdFlexVertical("status-backup-ref-block", 4, []any{ + antdText("backup-ref-label", true, "Backup Ref", nil), + parsedText("backup-ref-value", "{reqsJsonPath[0]['.status.backupRef.name']['-']}", nil), + }), + antdFlexVertical("status-started-at-block", 4, []any{ + antdText("started-at-label", true, "Started At", nil), + antdFlex("time-block", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "time-icon", + "text": "🌐", + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "formatter": "timestamp", + "id": "time-value", + "text": "{reqsJsonPath[0]['.status.startedAt']['-']}", + }, + }, + }), + }), + antdFlexVertical("status-completed-at-block", 4, []any{ + antdText("completed-at-label", true, "Completed At", nil), + antdFlex("time-block", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "time-icon", + "text": "🌐", + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "formatter": "timestamp", + "id": "time-value", + "text": "{reqsJsonPath[0]['.status.completedAt']['-']}", + }, + }, + }), + }), + antdFlexVertical("status-message-block", 4, []any{ + antdText("message-label", true, "Message", nil), + parsedText("message-value", "{reqsJsonPath[0]['.status.message']['-']}", nil), + }), + }), + }), + }), + }), + }, + }, + } + backupJobSpec := createUnifiedFactory(backupJobConfig, backupJobTabs, []any{"/api/clusters/{2}/k8s/apis/backups.cozystack.io/v1alpha1/namespaces/{3}/backupjobs/{6}"}) + + // Backup details factory using unified approach + backupConfig := UnifiedResourceConfig{ + Name: "backup-details", + ResourceType: "factory", + Kind: "Backup", + Plural: "backups", + Title: "backup", + } + backupTabs := []any{ + map[string]any{ + "key": "details", + "label": "Details", + "children": []any{ + contentCard("details-card", map[string]any{ + "marginBottom": "24px", + }, []any{ + antdText("details-title", true, "Backup details", map[string]any{ + "fontSize": 20, + "marginBottom": "12px", + }), + spacer("details-spacer", 16), + antdRow("details-grid", []any{48, 12}, []any{ + antdCol("col-left", 12, []any{ + antdFlexVertical("col-left-stack", 24, []any{ + antdFlexVertical("meta-name-block", 4, []any{ + antdText("meta-name-label", true, "Name", nil), + parsedText("meta-name-value", "{reqsJsonPath[0]['.metadata.name']['-']}", nil), + }), + antdFlexVertical("meta-namespace-block", 8, []any{ + antdText("meta-namespace-label", true, "Namespace", nil), + antdFlex("header-row", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "header-badge", + "text": "NS", + "title": "namespace", + "style": map[string]any{ + "backgroundColor": "#a25792ff", + "borderRadius": "20px", + "color": "#fff", + "display": "inline-block", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": "15px", + "fontWeight": 400, + "lineHeight": "24px", + "minWidth": 24, + "padding": "0 9px", + "textAlign": "center", + "whiteSpace": "nowrap", + }, + }, + }, + map[string]any{ + "type": "antdLink", + "data": map[string]any{ + "id": "namespace-link", + "text": "{reqsJsonPath[0]['.metadata.namespace']['-']}", + "href": "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace", + }, + }, + }), + }), + antdFlexVertical("meta-created-block", 4, []any{ + antdText("time-label", true, "Created", nil), + antdFlex("time-block", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "time-icon", + "text": "🌐", + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "formatter": "timestamp", + "id": "time-value", + "text": "{reqsJsonPath[0]['.metadata.creationTimestamp']['-']}", + }, + }, + }), + }), + }), + }), + antdCol("col-right", 12, []any{ + antdFlexVertical("col-right-stack", 24, []any{ + antdFlexVertical("status-phase-block", 4, []any{ + antdText("phase-label", true, "Phase", nil), + parsedText("phase-value", "{reqsJsonPath[0]['.status.phase']['-']}", nil), + }), + antdFlexVertical("spec-taken-at-block", 4, []any{ + antdText("taken-at-label", true, "Taken At", nil), + antdFlex("time-block", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "time-icon", + "text": "🌐", + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "formatter": "timestamp", + "id": "time-value", + "text": "{reqsJsonPath[0]['.spec.takenAt']['-']}", + }, + }, + }), + }), + antdFlexVertical("spec-plan-ref-block", 4, []any{ + antdText("plan-ref-label", true, "Plan Ref", nil), + parsedText("plan-ref-value", "{reqsJsonPath[0]['.spec.planRef.name']['-']}", nil), + }), + antdFlexVertical("spec-application-ref-block", 4, []any{ + antdText("application-ref-label", true, "Application", nil), + parsedText("application-ref-value", "{reqsJsonPath[0]['.spec.applicationRef.kind']['-']}.{reqsJsonPath[0]['.spec.applicationRef.apiGroup']['-']}/{reqsJsonPath[0]['.spec.applicationRef.name']['-']}", nil), + }), + antdFlexVertical("spec-backup-class-name-block", 4, []any{ + antdText("backup-class-name-label", true, "Backup Class", nil), + parsedText("backup-class-name-value", "{reqsJsonPath[0]['.spec.backupClassName']['-']}", nil), + }), + antdFlexVertical("status-artifact-uri-block", 4, []any{ + antdText("artifact-uri-label", true, "Artifact URI", nil), + parsedText("artifact-uri-value", "{reqsJsonPath[0]['.status.artifact.uri']['-']}", nil), + }), + antdFlexVertical("status-artifact-size-block", 4, []any{ + antdText("artifact-size-label", true, "Artifact Size", nil), + parsedText("artifact-size-value", "{reqsJsonPath[0]['.status.artifact.sizeBytes']['-']}", nil), + }), + antdFlexVertical("status-artifact-checksum-block", 4, []any{ + antdText("artifact-checksum-label", true, "Artifact Checksum", nil), + parsedText("artifact-checksum-value", "{reqsJsonPath[0]['.status.artifact.checksum']['-']}", nil), + }), + }), + }), + }), + }), + }, + }, + } + backupSpec := createUnifiedFactory(backupConfig, backupTabs, []any{"/api/clusters/{2}/k8s/apis/backups.cozystack.io/v1alpha1/namespaces/{3}/backups/{6}"}) + + // RestoreJob details factory using unified approach + restoreJobConfig := UnifiedResourceConfig{ + Name: "restorejob-details", + ResourceType: "factory", + Kind: "RestoreJob", + Plural: "restorejobs", + Title: "restorejob", + } + restoreJobTabs := []any{ + map[string]any{ + "key": "details", + "label": "Details", + "children": []any{ + contentCard("details-card", map[string]any{ + "marginBottom": "24px", + }, []any{ + antdText("details-title", true, "RestoreJob details", map[string]any{ + "fontSize": 20, + "marginBottom": "12px", + }), + spacer("details-spacer", 16), + antdRow("details-grid", []any{48, 12}, []any{ + antdCol("col-left", 12, []any{ + antdFlexVertical("col-left-stack", 24, []any{ + antdFlexVertical("meta-name-block", 4, []any{ + antdText("meta-name-label", true, "Name", nil), + parsedText("meta-name-value", "{reqsJsonPath[0]['.metadata.name']['-']}", nil), + }), + antdFlexVertical("meta-namespace-block", 8, []any{ + antdText("meta-namespace-label", true, "Namespace", nil), + antdFlex("header-row", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "header-badge", + "text": "NS", + "title": "namespace", + "style": map[string]any{ + "backgroundColor": "#a25792ff", + "borderRadius": "20px", + "color": "#fff", + "display": "inline-block", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": "15px", + "fontWeight": 400, + "lineHeight": "24px", + "minWidth": 24, + "padding": "0 9px", + "textAlign": "center", + "whiteSpace": "nowrap", + }, + }, + }, + map[string]any{ + "type": "antdLink", + "data": map[string]any{ + "id": "namespace-link", + "text": "{reqsJsonPath[0]['.metadata.namespace']['-']}", + "href": "/openapi-ui/{2}/{reqsJsonPath[0]['.metadata.namespace']['-']}/factory/marketplace", + }, + }, + }), + }), + antdFlexVertical("meta-created-block", 4, []any{ + antdText("created-time-label", true, "Created", nil), + antdFlex("created-time-block", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "created-time-icon", + "text": "🌐", + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "formatter": "timestamp", + "id": "created-time-value", + "text": "{reqsJsonPath[0]['.metadata.creationTimestamp']['-']}", + }, + }, + }), + }), + }), + }), + antdCol("col-right", 12, []any{ + antdFlexVertical("col-right-stack", 24, []any{ + antdFlexVertical("status-phase-block", 4, []any{ + antdText("phase-label", true, "Phase", nil), + parsedText("phase-value", "{reqsJsonPath[0]['.status.phase']['-']}", nil), + }), + antdFlexVertical("spec-backup-ref-block", 4, []any{ + antdText("backup-ref-label", true, "Backup Ref", nil), + parsedText("backup-ref-value", "{reqsJsonPath[0]['.spec.backupRef.name']['-']}", nil), + }), + antdFlexVertical("spec-target-application-ref-block", 4, []any{ + antdText("target-application-ref-label", true, "Target Application", nil), + // targetApplicationRef is optional — when absent, the restore targets + // the same application as the selected Backup. Show a single friendly + // fallback in that case instead of rendering "-.-/-". + parsedText("target-application-ref-value", "{reqsJsonPath[0]['.spec.targetApplicationRef.name']['Same as backup']}", nil), + }), + antdFlexVertical("spec-options-target-namespace-block", 4, []any{ + antdText("options-target-namespace-label", true, "Target Namespace", nil), + parsedText("options-target-namespace-value", "{reqsJsonPath[0]['.spec.options.targetNamespace']['-']}", nil), + }), + antdFlexVertical("spec-options-fail-if-target-exists-block", 4, []any{ + antdText("options-fail-if-target-exists-label", true, "Fail If Target Exists", nil), + parsedText("options-fail-if-target-exists-value", "{reqsJsonPath[0]['.spec.options.failIfTargetExists']['-']}", nil), + }), + antdFlexVertical("spec-options-keep-original-pvc-block", 4, []any{ + antdText("options-keep-original-pvc-label", true, "Keep Original PVC", nil), + parsedText("options-keep-original-pvc-value", "{reqsJsonPath[0]['.spec.options.keepOriginalPVC']['-']}", nil), + }), + antdFlexVertical("spec-options-keep-original-ip-mac-block", 4, []any{ + antdText("options-keep-original-ip-mac-label", true, "Keep Original IP/MAC", nil), + parsedText("options-keep-original-ip-mac-value", "{reqsJsonPath[0]['.spec.options.keepOriginalIpAndMac']['-']}", nil), + }), + antdFlexVertical("status-started-at-block", 4, []any{ + antdText("started-at-label", true, "Started At", nil), + antdFlex("started-at-time-block", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "started-at-time-icon", + "text": "🌐", + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "formatter": "timestamp", + "id": "started-at-time-value", + "text": "{reqsJsonPath[0]['.status.startedAt']['-']}", + }, + }, + }), + }), + antdFlexVertical("status-completed-at-block", 4, []any{ + antdText("completed-at-label", true, "Completed At", nil), + antdFlex("completed-at-time-block", 6, []any{ + map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "completed-at-time-icon", + "text": "🌐", + }, + }, + map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "formatter": "timestamp", + "id": "completed-at-time-value", + "text": "{reqsJsonPath[0]['.status.completedAt']['-']}", + }, + }, + }), + }), + antdFlexVertical("status-message-block", 4, []any{ + antdText("message-label", true, "Message", nil), + parsedText("message-value", "{reqsJsonPath[0]['.status.message']['-']}", nil), + }), + }), + }), + }), + }), + }, + }, + } + restoreJobSpec := createUnifiedFactory(restoreJobConfig, restoreJobTabs, []any{"/api/clusters/{2}/k8s/apis/backups.cozystack.io/v1alpha1/namespaces/{3}/restorejobs/{6}"}) + + // External IPs factory (filtered services) + externalIPsTabs := []any{ + map[string]any{ + "key": "services", + "label": "Services", + "children": []any{ + map[string]any{ + "type": "EnrichedTable", + "data": map[string]any{ + "id": "external-ips-table", + "fetchUrl": "/api/clusters/{2}/k8s/api/v1/namespaces/{3}/services", + "cluster": "{2}", + "baseprefix": "/openapi-ui", + "customizationId": "factory-details-v1.services", + "pathToItems": ".items", + "fieldSelector": map[string]any{ + "spec.type": "LoadBalancer", + }, + }, + }, + }, + }, + } + externalIPsSpec := map[string]any{ + "key": "external-ips", + "sidebarTags": []any{"external-ips-sidebar"}, + "withScrollableMainContentCard": true, + "urlsToFetch": []any{}, + "data": []any{ + map[string]any{ + "type": "antdTabs", + "data": map[string]any{ + "id": "tabs-root", + "defaultActiveKey": "services", + "items": externalIPsTabs, + }, + }, + }, + } + + return []*dashboardv1alpha1.Factory{ + createFactory("marketplace", marketplaceSpec), + createFactory("namespace-details", namespaceSpec), + createFactory("node-details", nodeSpec), + createFactory("pod-details", podSpec), + createFactory("kube-secret-details", secretSpec), + createFactory("kube-service-details", serviceSpec), + createFactory("kube-ingress-details", ingressSpec), + createFactory("workloadmonitor-details", workloadmonitorSpec), + createFactory("plan-details", planSpec), + createFactory("backupjob-details", backupJobSpec), + createFactory("backup-details", backupSpec), + createFactory("restorejob-details", restoreJobSpec), + createFactory("external-ips", externalIPsSpec), + } +} + +// CreateAllNavigations creates all navigation resources using helper functions +func CreateAllNavigations() []*dashboardv1alpha1.Navigation { + // Build baseFactoriesMapping for static (built-in) factories + baseFactoriesMapping := map[string]string{ + // Cluster-scoped builtin resources + "base-factory-clusterscoped-builtin-v1-namespaces": "namespace-details", + "base-factory-clusterscoped-builtin-v1-nodes": "node-details", + // Namespaced builtin resources + "base-factory-namespaced-builtin-v1-pods": "pod-details", + "base-factory-namespaced-builtin-v1-secrets": "kube-secret-details", + "base-factory-namespaced-builtin-v1-services": "kube-service-details", + // Namespaced API resources + "base-factory-namespaced-api-networking.k8s.io-v1-ingresses": "kube-ingress-details", + "base-factory-namespaced-api-cozystack.io-v1alpha1-workloadmonitors": "workloadmonitor-details", + // Backup resources (not ApplicationDefinitions, so ensureNavigation doesn't cover them) + "base-factory-namespaced-api-backups.cozystack.io-v1alpha1-plans": "plan-details", + "base-factory-namespaced-api-backups.cozystack.io-v1alpha1-backupjobs": "backupjob-details", + "base-factory-namespaced-api-backups.cozystack.io-v1alpha1-backups": "backup-details", + "base-factory-namespaced-api-backups.cozystack.io-v1alpha1-restorejobs": "restorejob-details", + } + + return []*dashboardv1alpha1.Navigation{ + createNavigation("navigation", map[string]any{ + "namespaces": map[string]any{ + "change": "/openapi-ui/{selectedCluster}/{value}/factory/marketplace", + "clear": "/openapi-ui/{selectedCluster}/api-table/core.cozystack.io/v1alpha1/tenantnamespaces", + }, + "baseFactoriesMapping": baseFactoriesMapping, + }), + } +} + +// CreateAllTableUriMappings creates all table URI mapping resources using helper functions +func CreateAllTableUriMappings() []*dashboardv1alpha1.TableUriMapping { + // links are now handled through CustomFormsPrefills + return []*dashboardv1alpha1.TableUriMapping{} +} + +// ---------------- Additional helper functions for missing resource types ---------------- + +// createCustomFormsOverride creates a CustomFormsOverride resource +func createCustomFormsOverride(customizationId string, spec map[string]any) *dashboardv1alpha1.CustomFormsOverride { + // Generate name from customizationId + name := customizationId + if strings.Contains(customizationId, "default-/") { + // For default-/ resources, replace "default-/" with "default-" and slashes with dots + name = strings.ReplaceAll(customizationId, "default-/", "default-") + name = strings.ReplaceAll(name, "/", ".") + } + + // Create hidden fields list + hidden := []any{ + []any{"metadata", "creationTimestamp"}, + } + + // Add namespace to hidden for specific resources in the correct order + if strings.Contains(name, "namespaces") || strings.Contains(name, "nodes") { + hidden = append(hidden, []any{"metadata", "namespace"}) + } + + // Add remaining hidden fields + hidden = append(hidden, []any{ + []any{"metadata", "deletionGracePeriodSeconds"}, + []any{"metadata", "deletionTimestamp"}, + []any{"metadata", "finalizers"}, + []any{"metadata", "generateName"}, + []any{"metadata", "generation"}, + []any{"metadata", "managedFields"}, + []any{"metadata", "ownerReferences"}, + []any{"metadata", "resourceVersion"}, + []any{"metadata", "selfLink"}, + []any{"metadata", "uid"}, + []any{"kind"}, + []any{"apiVersion"}, + []any{"status"}, + }...) + + // Create new spec with all required fields including formItems from the original spec + newSpec := map[string]any{ + "customizationId": customizationId, + "hidden": hidden, + "schema": map[string]any{}, + "strategy": "merge", + } + + // Merge into newSpec caller-provided fields without: customizationId, hidden, strategy + for key, value := range spec { + if key != "customizationId" && key != "hidden" && key != "strategy" { + newSpec[key] = value + } + } + + jsonData, _ := json.Marshal(newSpec) + + return &dashboardv1alpha1.CustomFormsOverride{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "dashboard.cozystack.io/v1alpha1", + Kind: "CustomFormsOverride", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: "", + }, + Spec: dashboardv1alpha1.ArbitrarySpec{ + JSON: v1.JSON{ + Raw: jsonData, + }, + }, + } +} + +// createNavigation creates a Navigation resource +func createNavigation(name string, spec map[string]any) *dashboardv1alpha1.Navigation { + jsonData, _ := json.Marshal(spec) + + return &dashboardv1alpha1.Navigation{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "dashboard.cozystack.io/v1alpha1", + Kind: "Navigation", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: "", + }, + Spec: dashboardv1alpha1.ArbitrarySpec{ + JSON: v1.JSON{ + Raw: jsonData, + }, + }, + } +} + +func listInputScemaItemBackupClass() map[string]any { + return map[string]any{ + "type": "listInput", + "customProps": map[string]any{ + "valueUri": "/api/clusters/{cluster}/k8s/apis/backups.cozystack.io/v1alpha1/backupclasses", + "keysToValue": []any{"metadata", "name"}, + "keysToLabel": []any{"metadata", "name"}, + }, + } +} + +// listInputSchemaItemBackup returns a listInput schema overlay for selecting a Backup +// from the current namespace (used by RestoreJob form for spec.backupRef.name). +func listInputSchemaItemBackup() map[string]any { + return map[string]any{ + "type": "listInput", + "customProps": map[string]any{ + "valueUri": "/api/clusters/{cluster}/k8s/apis/backups.cozystack.io/v1alpha1/namespaces/{namespace}/backups", + "keysToValue": []any{"metadata", "name"}, + "keysToLabel": []any{"metadata", "name"}, + }, + } +} + +// backupClassSchema returns the schema for spec.backupClassName as listInput (BackupJob/Plan). +func createSchema(customProps map[string]any) map[string]any { + return map[string]any{ + "properties": map[string]any{ + "spec": map[string]any{ + "properties": customProps, + }, + }, + } +} + +// createFormItem creates a form item for CustomFormsOverride +func createFormItem(path, label, fieldType string) map[string]any { + return map[string]any{ + "path": path, + "label": label, + "type": fieldType, + } +} + +// createFormItemWithAPI creates a form item with API endpoint for resource-based selects +func createFormItemWithAPI(path, label, fieldType string, apiConfig map[string]any) map[string]any { + item := map[string]any{ + "path": path, + "label": label, + "type": fieldType, + } + // Merge API configuration into the form item + for key, value := range apiConfig { + item[key] = value + } + return item +} + +// ---------------- Workloadmonitor specific functions ---------------- + +// createNamespaceHeader creates a header specifically for namespace with correct colors and text +func createNamespaceHeader() map[string]any { + badge := map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "header-badge", + "text": "NS", + "title": "Namespace", + "style": map[string]any{ + "backgroundColor": "#a25792ff", + "borderRadius": "20px", + "color": "#fff", + "display": "inline-block", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": "20px", + "fontWeight": float64(400), + "lineHeight": "24px", + "minWidth": float64(24), + "padding": "0 9px", + "textAlign": "center", + "whiteSpace": "nowrap", + }, + }, + } + + nameText := parsedText("header-name", "{reqsJsonPath[0]['.metadata.name']['-']}", map[string]any{ + "fontSize": "20px", + "lineHeight": "24px", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + }) + + return map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "header-row", + "align": "center", + "gap": float64(6), + "style": map[string]any{ + "marginBottom": "24px", + }, + }, + "children": []any{ + badge, + nameText, + }, + } +} + +// createNodeHeader creates a header specifically for node with correct colors and text +func createNodeHeader() map[string]any { + badge := map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "header-badge", + "text": "N", + "title": "nodes", + "style": map[string]any{ + "backgroundColor": "#8476d1", + "borderRadius": "20px", + "color": "#fff", + "display": "inline-block", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": "20px", + "fontWeight": float64(400), + "lineHeight": "24px", + "minWidth": float64(24), + "padding": "0 9px", + "textAlign": "center", + "whiteSpace": "nowrap", + }, + }, + } + + nameText := parsedText("header-name", "{reqsJsonPath[0]['.metadata.name']['-']}", map[string]any{ + "fontSize": "20px", + "lineHeight": "24px", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + }) + + statusBlock := map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "status-header-block", + "vertical": true, + "gap": float64(4), + }, + "children": []any{ + map[string]any{ + "type": "StatusText", + "data": map[string]any{ + "id": "node-status", + "values": []any{ + "{reqsJsonPath[0]['.status.conditions[?(@.status=='True')].reason']['-']}", + }, + "criteriaSuccess": "equals", + "strategySuccess": "every", + "valueToCompareSuccess": "KubeletReady", + "criteriaError": "equals", + "strategyError": "every", + "valueToCompareError": []any{ + "KernelDeadlock", + "ReadonlyFilesystem", + "NetworkUnavailable", + "MemoryPressure", + "DiskPressure", + "PIDPressure", + }, + "successText": "Available", + "errorText": "Unavailable", + "fallbackText": "Progressing", + }, + }, + }, + } + + return map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "header-row", + "align": "center", + "gap": float64(6), + "style": map[string]any{ + "marginBottom": "24px", + }, + }, + "children": []any{ + badge, + nameText, + statusBlock, + }, + } +} + +// createPodHeader creates a header specifically for pod with correct colors and text +func createPodHeader() map[string]any { + badge := map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "header-badge", + "text": "P", + "title": "Pods", + "style": map[string]any{ + "backgroundColor": "#009596", + "borderRadius": "20px", + "color": "#fff", + "display": "inline-block", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": "20px", + "fontWeight": float64(400), + "lineHeight": "24px", + "minWidth": float64(24), + "padding": "0 9px", + "textAlign": "center", + "whiteSpace": "nowrap", + }, + }, + } + + nameText := parsedText("header-pod-name", "{reqsJsonPath[0]['.metadata.name']['-']}", map[string]any{ + "fontSize": "20px", + "lineHeight": "24px", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + }) + + statusBlock := map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "status-header-block", + "vertical": true, + "gap": float64(4), + }, + "children": []any{ + map[string]any{ + "type": "StatusText", + "data": map[string]any{ + "id": "pod-status", + }, + }, + }, + } + + return map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "header-row", + "align": "center", + "gap": float64(6), + "style": map[string]any{ + "marginBottom": "24px", + }, + }, + "children": []any{ + badge, + nameText, + statusBlock, + }, + } +} + +// createWorkloadmonitorHeader creates a header specifically for workloadmonitor with correct colors and text +func createWorkloadmonitorHeader() map[string]any { + badge := map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": "badge-workloadmonitor", + "text": "W", + "title": "workloadmonitors", + "style": map[string]any{ + "backgroundColor": "#c46100", + "borderRadius": "20px", + "color": "#fff", + "display": "inline-block", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": float64(20), + "fontWeight": float64(400), + "lineHeight": "24px", + "minWidth": float64(24), + "padding": "0 9px", + "textAlign": "center", + "whiteSpace": "nowrap", + }, + }, + } + + nameText := parsedText("workloadmonitor-name", "{reqsJsonPath[0]['.metadata.name']['-']}", map[string]any{ + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": float64(20), + "lineHeight": "24px", + }) + + return map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": "header-row", + "align": "center", + "gap": float64(6), + "style": map[string]any{ + "marginBottom": float64(24), + }, + }, + "children": []any{ + badge, + nameText, + }, + } +} + +// CreateStaticCFOMapping creates the CFOMapping resource with mappings from static CustomFormsOverrides +func CreateStaticCFOMapping() *dashboardv1alpha1.CFOMapping { + // Build mappings from static CustomFormsOverrides + customFormsOverrides := CreateAllCustomFormsOverrides() + mappings := make(map[string]string, len(customFormsOverrides)) + for _, cfo := range customFormsOverrides { + var spec map[string]any + if err := json.Unmarshal(cfo.Spec.JSON.Raw, &spec); err != nil { + continue + } + customizationID, ok := spec["customizationId"].(string) + if !ok { + continue + } + // Extract the resource path from customizationId (remove "default-" prefix) + resourcePath := strings.TrimPrefix(customizationID, "default-") + mappings[resourcePath] = customizationID + } + + return createCFOMapping("cfomapping", mappings) +} + +// createCFOMapping creates a CFOMapping resource +func createCFOMapping(name string, mappings map[string]string) *dashboardv1alpha1.CFOMapping { + spec := map[string]any{ + "mappings": mappings, + } + jsonData, _ := json.Marshal(spec) + + return &dashboardv1alpha1.CFOMapping{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "dashboard.cozystack.io/v1alpha1", + Kind: "CFOMapping", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: dashboardv1alpha1.ArbitrarySpec{ + JSON: v1.JSON{ + Raw: jsonData, + }, + }, + } +} + +// ---------------- Complete resource creation function ---------------- + +// CreateAllStaticResources creates all static dashboard resources using helper functions +func CreateAllStaticResources() []client.Object { + var resources []client.Object + + // Add all breadcrumbs + for _, breadcrumb := range CreateAllBreadcrumbs() { + resources = append(resources, breadcrumb) + } + + // Add all custom column overrides + for _, customColumns := range CreateAllCustomColumnsOverrides() { + resources = append(resources, customColumns) + } + + // Add all custom forms overrides + for _, customForms := range CreateAllCustomFormsOverrides() { + resources = append(resources, customForms) + } + + // Add all factories + for _, factory := range CreateAllFactories() { + resources = append(resources, factory) + } + + // Add all navigations + for _, navigation := range CreateAllNavigations() { + resources = append(resources, navigation) + } + + // Add all table URI mappings + for _, tableUriMapping := range CreateAllTableUriMappings() { + resources = append(resources, tableUriMapping) + } + + // Add CFOMapping + resources = append(resources, CreateStaticCFOMapping()) + + return resources +} diff --git a/internal/controller/dashboard/tableurimapping.go b/internal/controller/dashboard/tableurimapping.go new file mode 100644 index 00000000..e9a4849c --- /dev/null +++ b/internal/controller/dashboard/tableurimapping.go @@ -0,0 +1,13 @@ +package dashboard + +import ( + "context" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" +) + +// ensureTableUriMapping creates or updates a TableUriMapping resource for the given CRD +func (m *Manager) ensureTableUriMapping(ctx context.Context, crd *cozyv1alpha1.ApplicationDefinition) error { + // Links are fully managed by the CustomColumnsOverride. + return nil +} diff --git a/internal/controller/dashboard/ui_helpers.go b/internal/controller/dashboard/ui_helpers.go new file mode 100644 index 00000000..6c7e3000 --- /dev/null +++ b/internal/controller/dashboard/ui_helpers.go @@ -0,0 +1,223 @@ +package dashboard + +// ---------------- UI helpers (use float64 for numeric fields) ---------------- + +func contentCard(id string, style map[string]any, children []any) map[string]any { + return contentCardWithTitle(id, "", style, children) +} + +func contentCardWithTitle(id any, title string, style map[string]any, children []any) map[string]any { + data := map[string]any{ + "id": id, + "style": style, + } + if title != "" { + data["title"] = title + } + return map[string]any{ + "type": "ContentCard", + "data": data, + "children": children, + } +} + +func antdText(id string, strong bool, text string, style map[string]any) map[string]any { + // Auto-generate ID if not provided + if id == "" { + id = generateTextID("auto", "antd") + } + + data := map[string]any{ + "id": id, + "text": text, + "strong": strong, + } + if style != nil { + data["style"] = style + } + return map[string]any{"type": "antdText", "data": data} +} + +func parsedText(id, text string, style map[string]any) map[string]any { + // Auto-generate ID if not provided + if id == "" { + id = generateTextID("auto", "parsed") + } + + data := map[string]any{ + "id": id, + "text": text, + } + if style != nil { + data["style"] = style + } + return map[string]any{"type": "parsedText", "data": data} +} + +func parsedTextWithFormatter(id, text, formatter string) map[string]any { + // Auto-generate ID if not provided + if id == "" { + id = generateTextID("auto", "formatted") + } + + return map[string]any{ + "type": "parsedText", + "data": map[string]any{ + "id": id, + "text": text, + "formatter": formatter, + }, + } +} + +func spacer(id string, space float64) map[string]any { + // Auto-generate ID if not provided + if id == "" { + id = generateContainerID("auto", "spacer") + } + + return map[string]any{ + "type": "Spacer", + "data": map[string]any{ + "id": id, + "$space": space, + }, + } +} + +func antdFlex(id string, gap float64, children []any) map[string]any { + // Auto-generate ID if not provided + if id == "" { + id = generateContainerID("auto", "flex") + } + + return map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": id, + "align": "center", + "gap": gap, + }, + "children": children, + } +} + +func antdFlexSpaceBetween(id string, children []any) map[string]any { + if id == "" { + id = generateContainerID("auto", "flex") + } + + return map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": id, + "align": "center", + "justify": "space-between", + }, + "children": children, + } +} + +func antdFlexVertical(id string, gap float64, children []any) map[string]any { + // Auto-generate ID if not provided + if id == "" { + id = generateContainerID("auto", "flex-vertical") + } + + return map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": id, + "vertical": true, + "gap": gap, + }, + "children": children, + } +} + +func antdRow(id string, gutter []any, children []any) map[string]any { + // Auto-generate ID if not provided + if id == "" { + id = generateContainerID("auto", "row") + } + + return map[string]any{ + "type": "antdRow", + "data": map[string]any{ + "id": id, + "gutter": gutter, + }, + "children": children, + } +} + +func antdCol(id string, span float64, children []any) map[string]any { + return map[string]any{ + "type": "antdCol", + "data": map[string]any{ + "id": id, + "span": span, + }, + "children": children, + } +} + +func antdColWithStyle(id string, style map[string]any, children []any) map[string]any { + return map[string]any{ + "type": "antdCol", + "data": map[string]any{ + "id": id, + "style": style, + }, + "children": children, + } +} + +func antdLink(id, text, href string) map[string]any { + return map[string]any{ + "type": "antdLink", + "data": map[string]any{ + "id": id, + "text": text, + "href": href, + }, + } +} + +// ---------------- Badge helpers ---------------- + +// createBadge creates a badge element with the given text, color, and title +func createBadge(id, text, color, title string) map[string]any { + return map[string]any{ + "type": "antdText", + "data": map[string]any{ + "id": id, + "text": text, + "title": title, + "style": map[string]any{ + "whiteSpace": "nowrap", + "backgroundColor": color, + "fontWeight": 400, + "lineHeight": "24px", + "minWidth": 24, + "textAlign": "center", + "borderRadius": "20px", + "color": "#fff", + "display": "inline-block", + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": "15px", + "padding": "0 9px", + }, + }, + } +} + +// createBadgeFromKind creates a badge using the existing badge generation functions +func createBadgeFromKind(id, kind, title string) map[string]any { + return createUnifiedBadgeFromKind(id, kind) +} + +// createHeaderBadge creates a badge specifically for headers with consistent styling +func createHeaderBadge(id, kind, plural string) map[string]any { + return createUnifiedBadgeFromKind(id, kind) +} diff --git a/internal/controller/dashboard/unified_helpers.go b/internal/controller/dashboard/unified_helpers.go new file mode 100644 index 00000000..d5edf207 --- /dev/null +++ b/internal/controller/dashboard/unified_helpers.go @@ -0,0 +1,342 @@ +package dashboard + +import ( + "crypto/sha1" + "fmt" + "strings" +) + +// ---------------- Unified ID generation helpers ---------------- + +// generateID creates a unique ID based on the provided components +func generateID(components ...string) string { + if len(components) == 0 { + return "" + } + + // Join components with hyphens and convert to lowercase + id := strings.ToLower(strings.Join(components, "-")) + + // Remove any special characters that might cause issues + id = strings.ReplaceAll(id, ".", "-") + id = strings.ReplaceAll(id, "/", "-") + id = strings.ReplaceAll(id, " ", "-") + + // Remove multiple consecutive hyphens + for strings.Contains(id, "--") { + id = strings.ReplaceAll(id, "--", "-") + } + + // Remove leading/trailing hyphens + id = strings.Trim(id, "-") + + return id +} + +// generateSpecID creates a spec.id from metadata.name and other components +func generateSpecID(metadataName string, components ...string) string { + allComponents := append([]string{metadataName}, components...) + return generateID(allComponents...) +} + +// generateMetadataName creates metadata.name from spec.id +func generateMetadataName(specID string) string { + // Convert ID format to metadata.name format + // Replace / with . for metadata.name + name := strings.ReplaceAll(specID, "/", ".") + + // Clean up the name to be RFC 1123 compliant + // Remove any leading/trailing dots and ensure it starts/ends with alphanumeric + name = strings.Trim(name, ".") + + // Replace multiple consecutive dots with single dot + for strings.Contains(name, "..") { + name = strings.ReplaceAll(name, "..", ".") + } + + // Replace any remaining problematic patterns + // Handle cases like "stock-namespace-.v1" -> "stock-namespace-v1" + name = strings.ReplaceAll(name, "-.", "-") + name = strings.ReplaceAll(name, ".-", "-") + + // Ensure it starts with alphanumeric character + if len(name) > 0 && !isAlphanumeric(name[0]) { + name = "a" + name + } + + // Ensure it ends with alphanumeric character + if len(name) > 0 && !isAlphanumeric(name[len(name)-1]) { + name = name + "a" + } + + return name +} + +// isAlphanumeric checks if a character is alphanumeric +func isAlphanumeric(c byte) bool { + return (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') +} + +// ---------------- Unified badge generation helpers ---------------- + +// BadgeConfig holds configuration for badge generation +type BadgeConfig struct { + Kind string // Resource kind in PascalCase (e.g., "VirtualMachine") - used for value and auto-generation + Text string // Optional abbreviation override (if empty, ResourceBadge auto-generates from Kind) + Color string // Optional custom backgroundColor override +} + +// createUnifiedBadge creates a badge using the unified BadgeConfig with ResourceBadge component +func createUnifiedBadge(id string, config BadgeConfig) map[string]any { + data := map[string]any{ + "id": id, + "value": config.Kind, + } + + // Add abbreviation override if specified (otherwise ResourceBadge auto-generates from Kind) + if config.Text != "" { + data["abbreviation"] = config.Text + } + + // Add custom color if specified + if config.Color != "" { + data["style"] = map[string]any{ + "backgroundColor": config.Color, + } + } + + return map[string]any{ + "type": "ResourceBadge", + "data": data, + } +} + +// createUnifiedBadgeFromKind creates a badge from kind with ResourceBadge component +// Abbreviation is auto-generated by ResourceBadge from kind, but can be customized if needed +func createUnifiedBadgeFromKind(id, kind string) map[string]any { + return map[string]any{ + "type": "ResourceBadge", + "data": map[string]any{ + "id": id, + "value": kind, + // abbreviation is optional - ResourceBadge auto-generates from value + }, + } +} + +// ---------------- Resource creation helpers with unified approach ---------------- + +// ResourceConfig holds configuration for resource creation +type ResourceConfig struct { + SpecID string + MetadataName string + Kind string + Title string + BadgeConfig BadgeConfig +} + +// createResourceConfig creates a ResourceConfig from components +func createResourceConfig(components []string, kind, title string) ResourceConfig { + // Generate spec.id from components + specID := generateID(components...) + + // Generate metadata.name from spec.id + metadataName := generateMetadataName(specID) + + // Generate badge config + badgeConfig := BadgeConfig{ + Kind: kind, + } + + return ResourceConfig{ + SpecID: specID, + MetadataName: metadataName, + Kind: kind, + Title: title, + BadgeConfig: badgeConfig, + } +} + +// ---------------- Enhanced color generation ---------------- + +// ---------------- Automatic ID generation for UI elements ---------------- + +// generateElementID creates an ID for UI elements based on context and type +func generateElementID(elementType, context string, components ...string) string { + allComponents := append([]string{elementType, context}, components...) + return generateID(allComponents...) +} + +// generateBadgeID creates an ID for badge elements +func generateBadgeID(context string, kind string) string { + return generateElementID("badge", context, kind) +} + +// generateLinkID creates an ID for link elements +func generateLinkID(context string, linkType string) string { + return generateElementID("link", context, linkType) +} + +// generateTextID creates an ID for text elements +func generateTextID(context string, textType string) string { + return generateElementID("text", context, textType) +} + +// generateContainerID creates an ID for container elements +func generateContainerID(context string, containerType string) string { + return generateElementID("container", context, containerType) +} + +// generateTableID creates an ID for table elements +func generateTableID(context string, tableType string) string { + return generateElementID("table", context, tableType) +} + +// ---------------- Enhanced resource creation with automatic IDs ---------------- + +// createResourceWithAutoID creates a resource with automatically generated IDs +func createResourceWithAutoID(resourceType, name string, spec map[string]any) map[string]any { + // Generate spec.id from name + specID := generateSpecID(name) + + // Add the spec.id to the spec + spec["id"] = specID + + return spec +} + +// ---------------- Unified resource creation helpers ---------------- + +// UnifiedResourceConfig holds configuration for unified resource creation +type UnifiedResourceConfig struct { + Name string + ResourceType string + Kind string + Plural string + Title string + Color string + BadgeText string +} + +// createUnifiedFactory creates a factory using unified approach +func createUnifiedFactory(config UnifiedResourceConfig, tabs []any, urlsToFetch []any) map[string]any { + // Generate spec.id from name + specID := generateSpecID(config.Name) + + // Create header with unified badge + badgeConfig := BadgeConfig{ + Kind: config.Kind, + Text: config.BadgeText, + Color: config.Color, + } + + badge := createUnifiedBadge(generateBadgeID("header", config.Kind), badgeConfig) + nameText := parsedText(generateTextID("header", "name"), "{reqsJsonPath[0]['.metadata.name']['-']}", map[string]any{ + "fontFamily": "RedHatDisplay, Overpass, overpass, helvetica, arial, sans-serif", + "fontSize": float64(20), + "lineHeight": "24px", + }) + + header := antdFlexSpaceBetween(generateContainerID("header", "row"), []any{ + antdFlex(generateContainerID("header", "title-text"), float64(6), []any{ + badge, + nameText, + }), + antdLink(generateLinkID("header", "edit"), + "Edit", + fmt.Sprintf("/openapi-ui/{2}/{3}/forms/apis/{reqsJsonPath[0]['.apiVersion']['-']}/%s/{reqsJsonPath[0]['.metadata.name']['-']}", + config.Plural), + ), + }) + + // Add marginBottom style to header + if headerData, ok := header["data"].(map[string]any); ok { + if headerData["style"] == nil { + headerData["style"] = map[string]any{} + } + if style, ok := headerData["style"].(map[string]any); ok { + style["marginBottom"] = float64(24) + } + } + + return map[string]any{ + "key": config.Name, + "id": specID, + "sidebarTags": []any{fmt.Sprintf("%s-sidebar", strings.ToLower(config.Kind))}, + "withScrollableMainContentCard": true, + "urlsToFetch": urlsToFetch, + "data": []any{ + header, + map[string]any{ + "type": "antdTabs", + "data": map[string]any{ + "id": generateContainerID("tabs", strings.ToLower(config.Kind)), + "defaultActiveKey": "details", + "items": tabs, + }, + }, + }, + } +} + +// createUnifiedCustomColumn creates a custom column using unified approach +func createUnifiedCustomColumn(name, jsonPath, kind, title, href string) map[string]any { + badgeConfig := BadgeConfig{ + Kind: kind, + } + badge := createUnifiedBadge(generateBadgeID("column", kind), badgeConfig) + + linkID := generateLinkID("column", "name") + if jsonPath == ".metadata.namespace" { + linkID = generateLinkID("column", "namespace") + } + + link := antdLink(linkID, "{reqsJsonPath[0]['"+jsonPath+"']['-']}", href) + + return map[string]any{ + "name": name, + "type": "factory", + "jsonPath": jsonPath, + "customProps": map[string]any{ + "disableEventBubbling": true, + "items": []any{ + map[string]any{ + "type": "antdFlex", + "data": map[string]any{ + "id": generateContainerID("column", "header"), + "align": "center", + "gap": float64(6), + }, + "children": []any{badge, link}, + }, + }, + }, + } +} + +// ---------------- Utility functions ---------------- + +// hashString creates a short hash from a string for ID generation +func hashString(s string) string { + hash := sha1.Sum([]byte(s)) + return fmt.Sprintf("%x", hash[:4]) +} + +// sanitizeForID removes characters that shouldn't be in IDs +func sanitizeForID(s string) string { + // Replace problematic characters + s = strings.ReplaceAll(s, ".", "-") + s = strings.ReplaceAll(s, "/", "-") + s = strings.ReplaceAll(s, " ", "-") + s = strings.ReplaceAll(s, "_", "-") + + // Remove multiple consecutive hyphens + for strings.Contains(s, "--") { + s = strings.ReplaceAll(s, "--", "-") + } + + // Remove leading/trailing hyphens + s = strings.Trim(s, "-") + + return strings.ToLower(s) +} diff --git a/internal/controller/fluxplunger/flux_plunger.go b/internal/controller/fluxplunger/flux_plunger.go new file mode 100644 index 00000000..44886a2c --- /dev/null +++ b/internal/controller/fluxplunger/flux_plunger.go @@ -0,0 +1,333 @@ +package fluxplunger + +import ( + "context" + "fmt" + "sort" + "strconv" + "strings" + + helmv2 "github.com/fluxcd/helm-controller/api/v2" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" +) + +const ( + annotationLastProcessedVersion = "flux-plunger.cozystack.io/last-processed-version" + errorMessageNoDeployedReleases = "has no deployed releases" + fieldManager = "flux-client-side-apply" +) + +// FluxPlunger watches HelmRelease resources and fixes "has no deployed releases" errors +type FluxPlunger struct { + client.Client +} + +// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;update;patch +// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;delete + +// Reconcile handles HelmRelease resources with "has no deployed releases" error +func (r *FluxPlunger) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + // Get the HelmRelease + hr := &helmv2.HelmRelease{} + if err := r.Get(ctx, req.NamespacedName, hr); err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + // Check if HelmRelease is suspended + if hr.Spec.Suspend { + logger.Info("HelmRelease is suspended, checking if we need to unsuspend") + + // Get the list of Helm release secrets + secrets, err := r.listHelmReleaseSecrets(ctx, hr.Namespace, hr.Name) + if err != nil { + logger.Error(err, "Failed to list Helm release secrets") + return ctrl.Result{}, err + } + + // If no secrets, treat latest version as 0 + latestVersion := 0 + if len(secrets) > 0 { + latestSecret := getLatestSecret(secrets) + latestVersion = extractVersionNumber(latestSecret.Name) + } else { + logger.Info("No Helm release secrets found while suspended, treating as version 0") + } + + // Check if version is previous to just processed (latestVersion+1 == processedVersion) + // This is the ONLY condition when we unsuspend + shouldUnsuspend := false + if hr.Annotations != nil { + if processedVersionStr, exists := hr.Annotations[annotationLastProcessedVersion]; exists { + processedVersion, err := strconv.Atoi(processedVersionStr) + if err == nil && latestVersion+1 == processedVersion { + shouldUnsuspend = true + } + } + } + + if shouldUnsuspend { + // Unsuspend the HelmRelease + logger.Info("Secret was already deleted in previous run, removing suspend", "latest", latestVersion, "processed", latestVersion+1) + if err := r.unsuspendHelmRelease(ctx, hr); err != nil { + logger.Info("Could not unsuspend HelmRelease, will retry on next reconcile", "error", err.Error()) + return ctrl.Result{}, nil + } + return ctrl.Result{}, nil + } + + // If not previous to processed, skip all actions + logger.Info("HelmRelease is suspended by external process, skipping", "latest", latestVersion) + return ctrl.Result{}, nil + } + + // Check if HelmRelease has the specific error + if !hasNoDeployedReleasesError(hr) { + logger.V(1).Info("HelmRelease does not have 'has no deployed releases' error, skipping") + return ctrl.Result{}, nil + } + + logger.Info("Detected HelmRelease with 'has no deployed releases' error") + + // Get the list of Helm release secrets + secrets, err := r.listHelmReleaseSecrets(ctx, hr.Namespace, hr.Name) + if err != nil { + logger.Error(err, "Failed to list Helm release secrets") + return ctrl.Result{}, err + } + + if len(secrets) == 0 { + logger.Info("No Helm release secrets found, skipping") + return ctrl.Result{}, nil + } + + // Find the latest version + latestSecret := getLatestSecret(secrets) + latestVersion := extractVersionNumber(latestSecret.Name) + + logger.Info("Found latest Helm release version", "version", latestVersion, "secret", latestSecret.Name) + + // Check if we just processed the next version (current + 1 == processed) + if hr.Annotations != nil { + if processedVersionStr, exists := hr.Annotations[annotationLastProcessedVersion]; exists { + processedVersion, err := strconv.Atoi(processedVersionStr) + if err == nil { + if latestVersion+1 == processedVersion { + logger.Info("Already processed, secret was deleted previously", "latest", latestVersion, "processed", processedVersion) + return ctrl.Result{}, nil + } + } else { + // Failed to parse annotation, treat as if annotation doesn't exist + logger.Info("Failed to parse annotation, will process", "annotation", processedVersionStr, "error", err) + } + } + } + + // Suspend the HelmRelease + logger.Info("Suspending HelmRelease") + if err := r.suspendHelmRelease(ctx, hr); err != nil { + // Optimistic lock conflicts are normal - FluxCD also updates HelmRelease + // Don't return error, just log and let controller-runtime requeue on next update + logger.Info("Could not suspend HelmRelease, will retry on next reconcile", "error", err.Error()) + return ctrl.Result{}, nil + } + + // Delete the latest secret + logger.Info("Deleting latest Helm release secret", "secret", latestSecret.Name) + if err := r.Delete(ctx, &latestSecret); err != nil { + logger.Error(err, "Failed to delete Helm release secret") + return ctrl.Result{}, err + } + + // Update annotation with processed version + logger.Info("Updating annotation with processed version", "version", latestVersion) + if err := r.updateProcessedVersionAnnotation(ctx, hr, latestVersion); err != nil { + logger.Info("Could not update annotation, will retry on next reconcile", "error", err.Error()) + return ctrl.Result{}, nil + } + + // Unsuspend the HelmRelease + logger.Info("Unsuspending HelmRelease") + if err := r.unsuspendHelmRelease(ctx, hr); err != nil { + logger.Info("Could not unsuspend HelmRelease, will retry on next reconcile", "error", err.Error()) + return ctrl.Result{}, nil + } + + logger.Info("Successfully processed HelmRelease", "version", latestVersion) + return ctrl.Result{}, nil +} + +// hasNoDeployedReleasesError checks if the HelmRelease has the specific error +func hasNoDeployedReleasesError(hr *helmv2.HelmRelease) bool { + for _, condition := range hr.Status.Conditions { + if condition.Type == "Ready" && condition.Status == metav1.ConditionFalse { + if strings.Contains(condition.Message, errorMessageNoDeployedReleases) { + return true + } + } + } + return false +} + +// listHelmReleaseSecrets lists all Helm release secrets for a specific release +func (r *FluxPlunger) listHelmReleaseSecrets(ctx context.Context, namespace, releaseName string) ([]corev1.Secret, error) { + secretList := &corev1.SecretList{} + listOpts := []client.ListOption{ + client.InNamespace(namespace), + client.MatchingLabels{ + "name": releaseName, + "owner": "helm", + }, + } + + if err := r.List(ctx, secretList, listOpts...); err != nil { + return nil, fmt.Errorf("failed to list secrets: %w", err) + } + + // Filter only helm.sh/release.v1 secrets + filtered := []corev1.Secret{} + for _, secret := range secretList.Items { + if secret.Type == "helm.sh/release.v1" { + filtered = append(filtered, secret) + } + } + + return filtered, nil +} + +// getLatestSecret returns the secret with the highest version number +func getLatestSecret(secrets []corev1.Secret) corev1.Secret { + if len(secrets) == 1 { + return secrets[0] + } + + sort.Slice(secrets, func(i, j int) bool { + vi := extractVersionNumber(secrets[i].Name) + vj := extractVersionNumber(secrets[j].Name) + return vi > vj + }) + + return secrets[0] +} + +// extractVersionFromSecretName extracts version string from secret name +// e.g., "sh.helm.release.v1.cozystack-resource-definitions.v10" -> "v10" +func extractVersionFromSecretName(secretName string) string { + parts := strings.Split(secretName, ".") + if len(parts) > 0 { + return parts[len(parts)-1] + } + return "" +} + +// extractVersionNumber extracts numeric version from secret name +// e.g., "sh.helm.release.v1.cozystack-resource-definitions.v10" -> 10 +func extractVersionNumber(secretName string) int { + version := extractVersionFromSecretName(secretName) + // Remove 'v' prefix if present + version = strings.TrimPrefix(version, "v") + num, err := strconv.Atoi(version) + if err != nil { + return 0 + } + return num +} + +// suspendHelmRelease sets suspend to true on the HelmRelease +func (r *FluxPlunger) suspendHelmRelease(ctx context.Context, hr *helmv2.HelmRelease) error { + // Re-fetch the HelmRelease to get the latest state + key := types.NamespacedName{Namespace: hr.Namespace, Name: hr.Name} + latestHR := &helmv2.HelmRelease{} + if err := r.Get(ctx, key, latestHR); err != nil { + return fmt.Errorf("failed to get latest HelmRelease: %w", err) + } + + // If already suspended, nothing to do + if latestHR.Spec.Suspend { + return nil + } + + patch := client.MergeFromWithOptions(latestHR.DeepCopy(), client.MergeFromWithOptimisticLock{}) + latestHR.Spec.Suspend = true + + return r.Patch(ctx, latestHR, patch, client.FieldOwner(fieldManager)) +} + +// unsuspendHelmRelease sets suspend to false on the HelmRelease +func (r *FluxPlunger) unsuspendHelmRelease(ctx context.Context, hr *helmv2.HelmRelease) error { + // Re-fetch the HelmRelease to get the latest state + key := types.NamespacedName{Namespace: hr.Namespace, Name: hr.Name} + latestHR := &helmv2.HelmRelease{} + if err := r.Get(ctx, key, latestHR); err != nil { + return fmt.Errorf("failed to get latest HelmRelease: %w", err) + } + + // If already unsuspended, nothing to do + if !latestHR.Spec.Suspend { + return nil + } + + patch := client.MergeFromWithOptions(latestHR.DeepCopy(), client.MergeFromWithOptimisticLock{}) + latestHR.Spec.Suspend = false + + return r.Patch(ctx, latestHR, patch, client.FieldOwner(fieldManager)) +} + +// updateProcessedVersionAnnotation updates the annotation with the processed version +func (r *FluxPlunger) updateProcessedVersionAnnotation(ctx context.Context, hr *helmv2.HelmRelease, version int) error { + // Re-fetch the HelmRelease to get the latest state + key := types.NamespacedName{Namespace: hr.Namespace, Name: hr.Name} + latestHR := &helmv2.HelmRelease{} + if err := r.Get(ctx, key, latestHR); err != nil { + return fmt.Errorf("failed to get latest HelmRelease: %w", err) + } + + patch := client.MergeFromWithOptions(latestHR.DeepCopy(), client.MergeFromWithOptimisticLock{}) + + if latestHR.Annotations == nil { + latestHR.Annotations = make(map[string]string) + } + latestHR.Annotations[annotationLastProcessedVersion] = strconv.Itoa(version) + + return r.Patch(ctx, latestHR, patch, client.FieldOwner(fieldManager)) +} + +// SetupWithManager sets up the controller with the Manager +func (r *FluxPlunger) SetupWithManager(mgr ctrl.Manager) error { + // Watch HelmReleases that either: + // 1. Have the specific error, OR + // 2. Are suspended with our annotation (to handle crash recovery) + pred := predicate.NewPredicateFuncs(func(obj client.Object) bool { + hr, ok := obj.(*helmv2.HelmRelease) + if !ok { + return false + } + + // Always process if has error + if hasNoDeployedReleasesError(hr) { + return true + } + + // Also process suspended HelmReleases with our annotation (crash recovery) + if hr.Spec.Suspend && hr.Annotations != nil { + if _, exists := hr.Annotations[annotationLastProcessedVersion]; exists { + return true + } + } + + return false + }) + + return ctrl.NewControllerManagedBy(mgr). + Named("fluxplunger"). + For(&helmv2.HelmRelease{}). + WithEventFilter(pred). + Complete(r) +} diff --git a/internal/controller/kubeovnplunger/kubeovn_plunger.go b/internal/controller/kubeovnplunger/kubeovn_plunger.go new file mode 100644 index 00000000..5d4b3d1d --- /dev/null +++ b/internal/controller/kubeovnplunger/kubeovn_plunger.go @@ -0,0 +1,280 @@ +package kubeovnplunger + +import ( + "bytes" + "context" + "fmt" + "io" + "strings" + "time" + + "github.com/cozystack/cozystack/internal/sse" + "github.com/cozystack/cozystack/pkg/ovnstatus" + "github.com/prometheus/client_golang/prometheus" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/remotecommand" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" +) + +var ( + srv *sse.Server +) + +const ( + rescanInterval = 1 * time.Minute +) + +// KubeOVNPlunger watches the ovn-central cluster members +type KubeOVNPlunger struct { + client.Client + Scheme *runtime.Scheme + ClientSet kubernetes.Interface + REST *rest.Config + Registry prometheus.Registerer + metrics metrics + lastLeader map[string]string + seenCIDs map[string]map[string]struct{} +} + +// Reconcile runs the checks on the ovn-central members to see if their views of the cluster are consistent +func (r *KubeOVNPlunger) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + l := log.FromContext(ctx) + + deploy := &appsv1.Deployment{} + if err := r.Get(ctx, req.NamespacedName, deploy); err != nil { + return ctrl.Result{}, err + } + + iphints := map[string]string{} + for _, env := range deploy.Spec.Template.Spec.Containers[0].Env { + if env.Name != "NODE_IPS" { + continue + } + for _, ip := range strings.Split(env.Value, ",") { + iphints[ip] = "" + } + break + } + if len(iphints) == 0 { + l.Info("WARNING: running without IP hints, some error conditions cannot be detected") + } + pods := &corev1.PodList{} + + if err := r.List(ctx, pods, client.InNamespace(req.Namespace), client.MatchingLabels(map[string]string{"app": req.Name})); err != nil { + return ctrl.Result{}, fmt.Errorf("list ovn-central pods: %w", err) + } + + nbmv := make([]ovnstatus.MemberView, 0, len(pods.Items)) + sbmv := make([]ovnstatus.MemberView, 0, len(pods.Items)) + nbSnaps := make([]ovnstatus.HealthSnapshot, 0, len(pods.Items)) + sbSnaps := make([]ovnstatus.HealthSnapshot, 0, len(pods.Items)) + // TODO: get real iphints + for i := range pods.Items { + o := ovnstatus.OVNClient{} + o.ApplyDefaults() + o.Runner = func(ctx context.Context, bin string, args ...string) (string, error) { + cmd := append([]string{bin}, args...) + eo := ExecOptions{ + Namespace: req.Namespace, + Pod: pods.Items[i].Name, + Container: pods.Items[i].Spec.Containers[0].Name, + Command: cmd, + } + res, err := r.ExecPod(ctx, eo) + if err != nil { + return "", err + } + return res.Stdout, nil + } + nb, sb, err1, err2 := o.HealthBoth(ctx) + if err1 != nil || err2 != nil { + l.Error(fmt.Errorf("health check failed: nb=%w, sb=%w", err1, err2), "pod", pods.Items[i].Name) + continue + } + nbSnaps = append(nbSnaps, nb) + sbSnaps = append(sbSnaps, sb) + nbmv = append(nbmv, ovnstatus.BuildMemberView(nb)) + sbmv = append(sbmv, ovnstatus.BuildMemberView(sb)) + } + r.recordAndPruneCIDs("nb", cidFromSnaps(nbSnaps)) + r.recordAndPruneCIDs("sb", cidFromSnaps(sbSnaps)) + nbmv = ovnstatus.NormalizeViews(nbmv) + sbmv = ovnstatus.NormalizeViews(sbmv) + nbecv := ovnstatus.AnalyzeConsensusWithIPHints(nbmv, &ovnstatus.Hints{ExpectedIPs: iphints}) + sbecv := ovnstatus.AnalyzeConsensusWithIPHints(sbmv, &ovnstatus.Hints{ExpectedIPs: iphints}) + expected := len(iphints) + r.WriteClusterMetrics("nb", nbSnaps, nbecv, expected) + r.WriteClusterMetrics("sb", sbSnaps, sbecv, expected) + r.WriteMemberMetrics("nb", nbSnaps, nbmv, nbecv) + r.WriteMemberMetrics("sb", sbSnaps, sbmv, sbecv) + srv.Publish(nbecv.PrettyString() + sbecv.PrettyString()) + return ctrl.Result{}, nil +} + +// SetupWithManager attaches a generic ticker to trigger a reconcile every seconds +func (r *KubeOVNPlunger) SetupWithManager(mgr ctrl.Manager, kubeOVNNamespace, appName string) error { + r.REST = rest.CopyConfig(mgr.GetConfig()) + cs, err := kubernetes.NewForConfig(r.REST) + if err != nil { + return fmt.Errorf("build clientset: %w", err) + } + r.ClientSet = cs + ch := make(chan event.GenericEvent, 10) + mapFunc := func(context.Context, client.Object) []reconcile.Request { + return []reconcile.Request{{ + NamespacedName: types.NamespacedName{Namespace: kubeOVNNamespace, Name: appName}, + }} + } + mapper := handler.EnqueueRequestsFromMapFunc(mapFunc) + srv = sse.New(sse.Options{ + Addr: ":18080", + AllowCORS: true, + }) + r.initMetrics() + r.lastLeader = make(map[string]string) + r.seenCIDs = map[string]map[string]struct{}{"nb": {}, "sb": {}} + if err := ctrl.NewControllerManagedBy(mgr). + Named("kubeovnplunger"). + WatchesRawSource(source.Channel(ch, mapper)). + Complete(r); err != nil { + return err + } + _ = mgr.Add(manager.RunnableFunc(func(ctx context.Context) error { + go srv.ListenAndServe() + <-ctx.Done() + _ = srv.Shutdown(context.Background()) + return nil + })) + return mgr.Add(manager.RunnableFunc(func(ctx context.Context) error { + ticker := time.NewTicker(rescanInterval) + defer ticker.Stop() + for { + select { + case <-ctx.Done(): + return nil + case <-ticker.C: + ch <- event.GenericEvent{ + Object: &metav1.PartialObjectMetadata{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: kubeOVNNamespace, + Name: appName, + }, + }, + } + } + } + })) +} + +type ExecOptions struct { + Namespace string + Pod string + Container string + Command []string // e.g. []string{"sh", "-c", "echo hi"} + Stdin io.Reader // optional + TTY bool // if true, stderr is merged into stdout + Timeout time.Duration // optional overall timeout +} + +type ExecResult struct { + Stdout string + Stderr string + ExitCode *int // nil if not determinable +} + +// ExecPod runs a command in a pod and returns stdout/stderr/exit code. +func (r *KubeOVNPlunger) ExecPod(ctx context.Context, opts ExecOptions) (*ExecResult, error) { + if opts.Namespace == "" || opts.Pod == "" || opts.Container == "" { + return nil, fmt.Errorf("namespace, pod, and container are required") + } + + req := r.ClientSet.CoreV1().RESTClient(). + Post(). + Resource("pods"). + Namespace(opts.Namespace). + Name(opts.Pod). + SubResource("exec"). + VersionedParams(&corev1.PodExecOptions{ + Container: opts.Container, + Command: opts.Command, + Stdin: opts.Stdin != nil, + Stdout: true, + Stderr: !opts.TTY, + TTY: opts.TTY, + }, scheme.ParameterCodec) + + exec, err := remotecommand.NewSPDYExecutor(r.REST, "POST", req.URL()) + if err != nil { + return nil, fmt.Errorf("spdy executor: %w", err) + } + + var stdout, stderr bytes.Buffer + streamCtx := ctx + if opts.Timeout > 0 { + var cancel context.CancelFunc + streamCtx, cancel = context.WithTimeout(ctx, opts.Timeout) + defer cancel() + } + + streamErr := exec.StreamWithContext(streamCtx, remotecommand.StreamOptions{ + Stdin: opts.Stdin, + Stdout: &stdout, + Stderr: &stderr, + Tty: opts.TTY, + }) + + res := &ExecResult{Stdout: stdout.String(), Stderr: stderr.String()} + if streamErr != nil { + // Try to surface exit code instead of treating all failures as transport errors + type exitCoder interface{ ExitStatus() int } + if ec, ok := streamErr.(exitCoder); ok { + code := ec.ExitStatus() + res.ExitCode = &code + return res, nil + } + return res, fmt.Errorf("exec stream: %w", streamErr) + } + zero := 0 + res.ExitCode = &zero + return res, nil +} + +func (r *KubeOVNPlunger) recordAndPruneCIDs(db, currentCID string) { + + // Mark current as seen + if r.seenCIDs[db] == nil { + r.seenCIDs[db] = map[string]struct{}{} + } + if currentCID != "" { + r.seenCIDs[db][currentCID] = struct{}{} + } + + // Build a set of "still active" CIDs this cycle (could be none if you failed to collect) + active := map[string]struct{}{} + if currentCID != "" { + active[currentCID] = struct{}{} + } + + // Any seen CID that isn't active now is stale -> delete all its series + for cid := range r.seenCIDs[db] { + if _, ok := active[cid]; ok { + continue + } + r.deleteAllFor(db, cid) + delete(r.seenCIDs[db], cid) + } +} diff --git a/internal/controller/kubeovnplunger/kubeovn_plunger_test.go b/internal/controller/kubeovnplunger/kubeovn_plunger_test.go new file mode 100644 index 00000000..d548c9d4 --- /dev/null +++ b/internal/controller/kubeovnplunger/kubeovn_plunger_test.go @@ -0,0 +1,34 @@ +package kubeovnplunger + +import ( + "context" + "testing" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/config" +) + +var testPlunger *KubeOVNPlunger + +func init() { + scheme := runtime.NewScheme() + cfg := config.GetConfigOrDie() + c, _ := client.New(cfg, client.Options{}) + cs, _ := kubernetes.NewForConfig(cfg) + testPlunger = &KubeOVNPlunger{ + Client: c, + Scheme: scheme, + ClientSet: cs, + REST: cfg, + } +} + +func TestPlungerGetsStatuses(t *testing.T) { + _, err := testPlunger.Reconcile(context.Background(), ctrl.Request{}) + if err != nil { + t.Errorf("error should be nil but it's %s", err) + } +} diff --git a/internal/controller/kubeovnplunger/metrics.go b/internal/controller/kubeovnplunger/metrics.go new file mode 100644 index 00000000..0bdd5970 --- /dev/null +++ b/internal/controller/kubeovnplunger/metrics.go @@ -0,0 +1,423 @@ +package kubeovnplunger + +import ( + "time" + + "github.com/cozystack/cozystack/pkg/ovnstatus" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" +) + +type metrics struct { + // --- Core cluster health (per DB/cid) --- + clusterQuorum *prometheus.GaugeVec // 1/0 + allAgree *prometheus.GaugeVec // 1/0 + membersExpected *prometheus.GaugeVec + membersObserved *prometheus.GaugeVec + ipsExpected *prometheus.GaugeVec + ipsObserved *prometheus.GaugeVec + excessMembers *prometheus.GaugeVec + missingMembers *prometheus.GaugeVec + unexpectedIPsCount *prometheus.GaugeVec + missingExpectedIPsCount *prometheus.GaugeVec + ipConflictsCount *prometheus.GaugeVec + sidAddrDisagreements *prometheus.GaugeVec + + // --- Consensus summary (per DB/cid) --- + consensusMajoritySize *prometheus.GaugeVec + consensusMinoritySize *prometheus.GaugeVec + consensusDiffsTotal *prometheus.GaugeVec + + // --- Detail exports (sparse, keyed by IP/SID) --- + unexpectedIPGauge *prometheus.GaugeVec // {db,cid,ip} -> 1 + missingExpectedIPGauge *prometheus.GaugeVec // {db,cid,ip} -> 1 + ipConflictGauge *prometheus.GaugeVec // {db,cid,ip} -> count(sids) + suspectStaleGauge *prometheus.GaugeVec // {db,cid,sid} -> 1 + + // --- Per-member liveness/freshness (per DB/cid/sid[/ip]) --- + memberConnected *prometheus.GaugeVec // {db,cid,sid,ip} + memberLeader *prometheus.GaugeVec // {db,cid,sid} + memberLastMsgMs *prometheus.GaugeVec // {db,cid,sid} + memberIndex *prometheus.GaugeVec // {db,cid,sid} + memberIndexGap *prometheus.GaugeVec // {db,cid,sid} + memberReporter *prometheus.GaugeVec // {db,cid,sid} + memberMissingReporter *prometheus.GaugeVec // {db,cid,sid} + + // --- Ops/housekeeping --- + leaderTransitionsTotal *prometheus.CounterVec // {db,cid} + collectErrorsTotal *prometheus.CounterVec // {db,cid} + publishEventsTotal *prometheus.CounterVec // {db,cid} + snapshotTimestampSec *prometheus.GaugeVec // {db,cid} +} + +func (r *KubeOVNPlunger) initMetrics() { + p := promauto.With(r.Registry) + + ns := "ovn" + + // --- Core cluster health --- + r.metrics.clusterQuorum = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "cluster", Name: "quorum", + Help: "1 if cluster has quorum, else 0", + }, []string{"db", "cid"}) + + r.metrics.allAgree = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "cluster", Name: "all_agree", + Help: "1 if all members report identical membership", + }, []string{"db", "cid"}) + + r.metrics.membersExpected = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "cluster", Name: "members_expected", + Help: "Expected cluster size (replicas)", + }, []string{"db", "cid"}) + + r.metrics.membersObserved = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "cluster", Name: "members_observed", + Help: "Observed members (distinct SIDs across views)", + }, []string{"db", "cid"}) + + r.metrics.ipsExpected = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "cluster", Name: "ips_expected", + Help: "Expected distinct member IPs (from k8s hints)", + }, []string{"db", "cid"}) + + r.metrics.ipsObserved = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "cluster", Name: "ips_observed", + Help: "Observed distinct member IPs (from OVN views)", + }, []string{"db", "cid"}) + + r.metrics.excessMembers = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "cluster", Name: "excess_members", + Help: "Members over expected (>=0)", + }, []string{"db", "cid"}) + + r.metrics.missingMembers = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "cluster", Name: "missing_members", + Help: "Members short of expected (>=0)", + }, []string{"db", "cid"}) + + r.metrics.unexpectedIPsCount = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "cluster", Name: "unexpected_ips", + Help: "Count of IPs in OVN not present in k8s expected set", + }, []string{"db", "cid"}) + + r.metrics.missingExpectedIPsCount = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "cluster", Name: "missing_expected_ips", + Help: "Count of expected IPs not found in OVN", + }, []string{"db", "cid"}) + + r.metrics.ipConflictsCount = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "cluster", Name: "ip_conflicts", + Help: "Number of IPs claimed by multiple SIDs", + }, []string{"db", "cid"}) + + r.metrics.sidAddrDisagreements = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "cluster", Name: "sid_address_disagreements", + Help: "Number of SIDs seen with >1 distinct addresses", + }, []string{"db", "cid"}) + + // --- Consensus summary --- + r.metrics.consensusMajoritySize = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "consensus", Name: "majority_size", + Help: "Majority group size (0 if none)", + }, []string{"db", "cid"}) + + r.metrics.consensusMinoritySize = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "consensus", Name: "minority_size", + Help: "Minority group size", + }, []string{"db", "cid"}) + + r.metrics.consensusDiffsTotal = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "consensus", Name: "diffs_total", + Help: "Total per-reporter differences vs truth (missing + extra + mismatches)", + }, []string{"db", "cid"}) + + // --- Detail exports (sparse) --- + r.metrics.unexpectedIPGauge = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "consensus", Name: "unexpected_ip", + Help: "Unexpected IP present in OVN; value fixed at 1", + }, []string{"db", "cid", "ip"}) + + r.metrics.missingExpectedIPGauge = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "consensus", Name: "missing_expected_ip", + Help: "Expected IP missing from OVN; value fixed at 1", + }, []string{"db", "cid", "ip"}) + + r.metrics.ipConflictGauge = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "consensus", Name: "ip_conflict", + Help: "Number of SIDs claiming the same IP for this key", + }, []string{"db", "cid", "ip"}) + + r.metrics.suspectStaleGauge = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "consensus", Name: "suspect_stale", + Help: "Suspected stale SID candidate for kick; value fixed at 1 (emit only when remediation is warranted)", + }, []string{"db", "cid", "sid"}) + + // --- Per-member liveness/freshness --- + r.metrics.memberConnected = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "member", Name: "connected", + Help: "1 if local server reports connected/quorum, else 0", + }, []string{"db", "cid", "sid", "ip"}) + + r.metrics.memberLeader = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "member", Name: "leader", + Help: "1 if this member is leader, else 0", + }, []string{"db", "cid", "sid"}) + + r.metrics.memberLastMsgMs = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "member", Name: "last_msg_ms", + Help: "Follower->leader 'last msg' age in ms (legacy heuristic). NaN/omit if unknown", + }, []string{"db", "cid", "sid"}) + + r.metrics.memberIndex = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "member", Name: "index", + Help: "Local Raft log index", + }, []string{"db", "cid", "sid"}) + + r.metrics.memberIndexGap = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "member", Name: "index_gap", + Help: "Leader index minus local index (>=0)", + }, []string{"db", "cid", "sid"}) + + r.metrics.memberReporter = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "member", Name: "reporter", + Help: "1 if a self-view from this SID was collected in the scrape cycle", + }, []string{"db", "cid", "sid"}) + + r.metrics.memberMissingReporter = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "member", Name: "missing_reporter", + Help: "1 if SID appears in union but produced no self-view", + }, []string{"db", "cid", "sid"}) + + // --- Ops/housekeeping --- + r.metrics.leaderTransitionsTotal = p.NewCounterVec(prometheus.CounterOpts{ + Namespace: ns, Subsystem: "ops", Name: "leader_transitions_total", + Help: "Count of observed leader SID changes", + }, []string{"db", "cid"}) + + r.metrics.collectErrorsTotal = p.NewCounterVec(prometheus.CounterOpts{ + Namespace: ns, Subsystem: "ops", Name: "collect_errors_total", + Help: "Count of errors during health collection/analysis", + }, []string{"db", "cid"}) + + r.metrics.publishEventsTotal = p.NewCounterVec(prometheus.CounterOpts{ + Namespace: ns, Subsystem: "ops", Name: "publish_events_total", + Help: "Count of SSE publish events (optional)", + }, []string{"db", "cid"}) + + r.metrics.snapshotTimestampSec = p.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: ns, Subsystem: "ops", Name: "snapshot_timestamp_seconds", + Help: "Unix timestamp of the last successful consensus snapshot", + }, []string{"db", "cid"}) +} + +func (r *KubeOVNPlunger) WriteClusterMetrics(db string, snaps []ovnstatus.HealthSnapshot, ecv ovnstatus.ExtendedConsensusResult, expectedReplicas int) { + cid := cidFromSnaps(snaps) + + // Core cluster health + r.metrics.clusterQuorum.WithLabelValues(db, cid).Set(b2f(ecv.HasMajority)) + r.metrics.allAgree.WithLabelValues(db, cid).Set(b2f(ecv.AllAgree)) + r.metrics.membersExpected.WithLabelValues(db, cid).Set(float64(expectedReplicas)) + r.metrics.membersObserved.WithLabelValues(db, cid).Set(float64(ecv.MembersCount)) + r.metrics.ipsExpected.WithLabelValues(db, cid).Set(float64(len(ecv.ConsensusResult.TruthView.Members))) // optional; or len(hints.ExpectedIPs) + r.metrics.ipsObserved.WithLabelValues(db, cid).Set(float64(ecv.DistinctIPCount)) + r.metrics.excessMembers.WithLabelValues(db, cid).Set(float64(ecv.ExpectedExcess)) + r.metrics.missingMembers.WithLabelValues(db, cid).Set(float64(ecv.ExpectedShortfall)) + r.metrics.unexpectedIPsCount.WithLabelValues(db, cid).Set(float64(len(ecv.UnexpectedIPs))) + r.metrics.missingExpectedIPsCount.WithLabelValues(db, cid).Set(float64(len(ecv.MissingExpectedIPs))) + r.metrics.ipConflictsCount.WithLabelValues(db, cid).Set(float64(len(ecv.IPConflicts))) + + // Count SIDs with >1 distinct addresses + disagree := 0 + for _, n := range ecv.SIDAddressDisagreements { + if n > 1 { + disagree++ + } + } + r.metrics.sidAddrDisagreements.WithLabelValues(db, cid).Set(float64(disagree)) + + // Consensus summary + r.metrics.consensusMajoritySize.WithLabelValues(db, cid).Set(float64(len(ecv.MajorityMembers))) + r.metrics.consensusMinoritySize.WithLabelValues(db, cid).Set(float64(len(ecv.MinorityMembers))) + + // Sum diffs across reporters (missing + extra + mismatches) + totalDiffs := 0 + for _, d := range ecv.Diffs { + totalDiffs += len(d.MissingSIDs) + len(d.ExtraSIDs) + len(d.AddressMismatches) + } + r.metrics.consensusDiffsTotal.WithLabelValues(db, cid).Set(float64(totalDiffs)) + + // Sparse per-key exports (reset then re-emit for this {db,cid}) + r.metrics.unexpectedIPGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + for _, ip := range ecv.UnexpectedIPs { + r.metrics.unexpectedIPGauge.WithLabelValues(db, cid, ip).Set(1) + } + + r.metrics.missingExpectedIPGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + for _, ip := range ecv.MissingExpectedIPs { + r.metrics.missingExpectedIPGauge.WithLabelValues(db, cid, ip).Set(1) + } + + r.metrics.ipConflictGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + for ip, sids := range ecv.IPConflicts { + r.metrics.ipConflictGauge.WithLabelValues(db, cid, ip).Set(float64(len(sids))) + } + + // Only emit suspects when remediation is warranted (e.g., TooManyMembers / unexpected IPs / conflicts) + r.metrics.suspectStaleGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + if ecv.TooManyMembers || len(ecv.UnexpectedIPs) > 0 || len(ecv.IPConflicts) > 0 { + for _, sid := range ecv.SuspectStaleSIDs { + r.metrics.suspectStaleGauge.WithLabelValues(db, cid, sid).Set(1) + } + } + + // Snapshot timestamp + r.metrics.snapshotTimestampSec.WithLabelValues(db, cid).Set(float64(time.Now().Unix())) +} + +func (r *KubeOVNPlunger) WriteMemberMetrics(db string, snaps []ovnstatus.HealthSnapshot, views []ovnstatus.MemberView, ecv ovnstatus.ExtendedConsensusResult) { + cid := cidFromSnaps(snaps) + + // Figure out current leader SID (prefer local view from any leader snapshot) + curLeader := "" + for _, s := range snaps { + if s.Local.Leader { + curLeader = s.Local.SID + break + } + } + // Leader transitions + key := db + "|" + cid + if prev, ok := r.lastLeader[key]; ok && prev != "" && curLeader != "" && prev != curLeader { + r.metrics.leaderTransitionsTotal.WithLabelValues(db, cid).Inc() + } + if curLeader != "" { + r.lastLeader[key] = curLeader + } + + // Build quick maps for reporter set & IP per SID (best-effort) + reporter := map[string]struct{}{} + for _, v := range views { + if v.FromSID != "" { + reporter[v.FromSID] = struct{}{} + } + } + sidToIP := map[string]string{} + for _, v := range views { + for sid, addr := range v.Members { + if sidToIP[sid] == "" && addr != "" { + sidToIP[sid] = ovnstatus.AddrToIP(addr) // expose addrToIP or wrap here + } + } + } + + // Reset member vectors for this {db,cid} (avoid stale series) + r.metrics.memberConnected.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.memberLeader.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.memberLastMsgMs.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.memberIndex.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.memberIndexGap.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.memberReporter.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.memberMissingReporter.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + + // Leader index (to compute gaps) + lIdx := leaderIndex(snaps, curLeader) + + // Emit one series per snapshot (self view) + for _, s := range snaps { + sid := s.Local.SID + ip := sidToIP[sid] + if ip == "" { + ip = "unknown" + } + + r.metrics.memberConnected.WithLabelValues(db, cid, sid, ip).Set(b2f(s.Local.Connected)) + r.metrics.memberLeader.WithLabelValues(db, cid, sid).Set(b2f(s.Local.Leader)) + r.metrics.memberIndex.WithLabelValues(db, cid, sid).Set(float64(s.Local.Index)) + + if lIdx != nil && s.Local.Index >= 0 { + gap := *lIdx - s.Local.Index + if gap < 0 { + gap = 0 + } + r.metrics.memberIndexGap.WithLabelValues(db, cid, sid).Set(float64(gap)) + } + + // Reporter presence + _, isReporter := reporter[sid] + r.metrics.memberReporter.WithLabelValues(db, cid, sid).Set(b2f(isReporter)) + } + + // “Missing reporter” SIDs = union − reporters (from ecv) + reporterSet := map[string]struct{}{} + for sid := range reporter { + reporterSet[sid] = struct{}{} + } + unionSet := map[string]struct{}{} + for _, sid := range ecv.UnionMembers { + unionSet[sid] = struct{}{} + } + for sid := range unionSet { + if _, ok := reporterSet[sid]; !ok { + r.metrics.memberMissingReporter.WithLabelValues(db, cid, sid).Set(1) + } + } + + // Legacy follower freshness (if you kept LastMsgMs in servers parsing) + // We only know LastMsgMs from the Full.Servers in each snapshot; pick the freshest per SID. + lastMsg := map[string]int64{} + for _, s := range snaps { + for _, srv := range s.Full.Servers { + if srv.LastMsgMs != nil { + cur, ok := lastMsg[srv.SID] + if !ok || *srv.LastMsgMs < cur { + lastMsg[srv.SID] = *srv.LastMsgMs + } + } + } + } + for sid, ms := range lastMsg { + r.metrics.memberLastMsgMs.WithLabelValues(db, cid, sid).Set(float64(ms)) + } +} + +func (r *KubeOVNPlunger) deleteAllFor(db, cid string) { + // Cluster-level vecs (db,cid) + r.metrics.clusterQuorum.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.allAgree.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.membersExpected.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.membersObserved.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.ipsExpected.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.ipsObserved.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.excessMembers.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.missingMembers.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.unexpectedIPsCount.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.missingExpectedIPsCount.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.ipConflictsCount.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.sidAddrDisagreements.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + + r.metrics.consensusMajoritySize.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.consensusMinoritySize.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.consensusDiffsTotal.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + + // Sparse detail vecs (db,cid,*) + r.metrics.unexpectedIPGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.missingExpectedIPGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.ipConflictGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.suspectStaleGauge.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + + // Per-member vecs (db,cid,*) + r.metrics.memberConnected.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.memberLeader.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.memberLastMsgMs.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.memberIndex.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.memberIndexGap.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.memberReporter.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.memberMissingReporter.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + + // Ops vecs (db,cid) + r.metrics.leaderTransitionsTotal.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.collectErrorsTotal.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.publishEventsTotal.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) + r.metrics.snapshotTimestampSec.DeletePartialMatch(prometheus.Labels{"db": db, "cid": cid}) +} diff --git a/internal/controller/kubeovnplunger/util.go b/internal/controller/kubeovnplunger/util.go new file mode 100644 index 00000000..9d2d1090 --- /dev/null +++ b/internal/controller/kubeovnplunger/util.go @@ -0,0 +1,31 @@ +package kubeovnplunger + +import "github.com/cozystack/cozystack/pkg/ovnstatus" + +func b2f(b bool) float64 { + if b { + return 1 + } + return 0 +} + +// Pull a cluster UUID (cid) from any snapshots’ Local.CID (falls back to "") +func cidFromSnaps(snaps []ovnstatus.HealthSnapshot) string { + for _, s := range snaps { + if s.Local.CID != "" { + return s.Local.CID + } + } + return "" +} + +// Map SID -> last local index to compute gaps (optional) +func leaderIndex(snaps []ovnstatus.HealthSnapshot, leaderSID string) (idx *int64) { + for _, s := range snaps { + if s.Local.SID == leaderSID && s.Local.Index > 0 { + v := s.Local.Index + return &v + } + } + return nil +} diff --git a/internal/controller/system_helm_reconciler.go b/internal/controller/system_helm_reconciler.go deleted file mode 100644 index 83117c42..00000000 --- a/internal/controller/system_helm_reconciler.go +++ /dev/null @@ -1,139 +0,0 @@ -package controller - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "fmt" - "sort" - "time" - - helmv2 "github.com/fluxcd/helm-controller/api/v2" - corev1 "k8s.io/api/core/v1" - kerrors "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/event" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/predicate" -) - -type CozystackConfigReconciler struct { - client.Client - Scheme *runtime.Scheme -} - -var configMapNames = []string{"cozystack", "cozystack-branding", "cozystack-scheduling"} - -const configMapNamespace = "cozy-system" -const digestAnnotation = "cozystack.io/cozy-config-digest" -const forceReconcileKey = "reconcile.fluxcd.io/forceAt" -const requestedAt = "reconcile.fluxcd.io/requestedAt" - -func (r *CozystackConfigReconciler) Reconcile(ctx context.Context, _ ctrl.Request) (ctrl.Result, error) { - log := log.FromContext(ctx) - - digest, err := r.computeDigest(ctx) - if err != nil { - log.Error(err, "failed to compute config digest") - return ctrl.Result{}, nil - } - - var helmList helmv2.HelmReleaseList - if err := r.List(ctx, &helmList); err != nil { - return ctrl.Result{}, fmt.Errorf("failed to list HelmReleases: %w", err) - } - - now := time.Now().Format(time.RFC3339Nano) - updated := 0 - - for _, hr := range helmList.Items { - isSystemApp := hr.Labels["cozystack.io/system-app"] == "true" - isTenantRoot := hr.Namespace == "tenant-root" && hr.Name == "tenant-root" - if !isSystemApp && !isTenantRoot { - continue - } - - if hr.Annotations == nil { - hr.Annotations = map[string]string{} - } - - if hr.Annotations[digestAnnotation] == digest { - continue - } - - patch := client.MergeFrom(hr.DeepCopy()) - hr.Annotations[digestAnnotation] = digest - hr.Annotations[forceReconcileKey] = now - hr.Annotations[requestedAt] = now - - if err := r.Patch(ctx, &hr, patch); err != nil { - log.Error(err, "failed to patch HelmRelease", "name", hr.Name, "namespace", hr.Namespace) - continue - } - updated++ - log.Info("patched HelmRelease with new config digest", "name", hr.Name, "namespace", hr.Namespace) - } - - log.Info("finished reconciliation", "updatedHelmReleases", updated) - return ctrl.Result{}, nil -} - -func (r *CozystackConfigReconciler) computeDigest(ctx context.Context) (string, error) { - hash := sha256.New() - - for _, name := range configMapNames { - var cm corev1.ConfigMap - err := r.Get(ctx, client.ObjectKey{Namespace: configMapNamespace, Name: name}, &cm) - if err != nil { - if kerrors.IsNotFound(err) { - continue // ignore missing - } - return "", err - } - - // Sort keys for consistent hashing - var keys []string - for k := range cm.Data { - keys = append(keys, k) - } - sort.Strings(keys) - - for _, k := range keys { - v := cm.Data[k] - fmt.Fprintf(hash, "%s:%s=%s\n", name, k, v) - } - } - - return hex.EncodeToString(hash.Sum(nil)), nil -} - -func (r *CozystackConfigReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - WithEventFilter(predicate.Funcs{ - UpdateFunc: func(e event.UpdateEvent) bool { - cm, ok := e.ObjectNew.(*corev1.ConfigMap) - return ok && cm.Namespace == configMapNamespace && contains(configMapNames, cm.Name) - }, - CreateFunc: func(e event.CreateEvent) bool { - cm, ok := e.Object.(*corev1.ConfigMap) - return ok && cm.Namespace == configMapNamespace && contains(configMapNames, cm.Name) - }, - DeleteFunc: func(e event.DeleteEvent) bool { - cm, ok := e.Object.(*corev1.ConfigMap) - return ok && cm.Namespace == configMapNamespace && contains(configMapNames, cm.Name) - }, - }). - For(&corev1.ConfigMap{}). - Complete(r) -} - -func contains(slice []string, val string) bool { - for _, s := range slice { - if s == val { - return true - } - } - return false -} diff --git a/internal/controller/tenant_helm_reconciler.go b/internal/controller/tenant_helm_reconciler.go deleted file mode 100644 index 402ff5ba..00000000 --- a/internal/controller/tenant_helm_reconciler.go +++ /dev/null @@ -1,158 +0,0 @@ -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 3624e0e1..d0d9e743 100644 --- a/internal/controller/workload_controller.go +++ b/internal/controller/workload_controller.go @@ -3,11 +3,11 @@ package controller import ( "context" "strings" + "time" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" @@ -15,63 +15,50 @@ import ( cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" ) +const ( + deletionRequeueDelay = 30 * time.Second +) + // WorkloadMonitorReconciler reconciles a WorkloadMonitor object type WorkloadReconciler struct { client.Client Scheme *runtime.Scheme } +// workload_controller.go func (r *WorkloadReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - logger := log.FromContext(ctx) + log := log.FromContext(ctx) + w := &cozyv1alpha1.Workload{} - err := r.Get(ctx, req.NamespacedName, w) - if err != nil { + if err := r.Get(ctx, req.NamespacedName, w); err != nil { if apierrors.IsNotFound(err) { return ctrl.Result{}, nil } - logger.Error(err, "Unable to fetch Workload") return ctrl.Result{}, err } - // it's being deleted, nothing to handle - if w.DeletionTimestamp != nil { - return ctrl.Result{}, nil + // If my monitor is gone, delete me. + monName, has := w.Labels["workloads.cozystack.io/monitor"] + if !has { + return ctrl.Result{}, client.IgnoreNotFound(r.Delete(ctx, w)) } - - t := getMonitoredObject(w) - - if t == nil { - err = r.Delete(ctx, w) - if err != nil { - logger.Error(err, "failed to delete workload") - } + monitor := &cozyv1alpha1.WorkloadMonitor{} + if err := r.Get(ctx, client.ObjectKey{Namespace: w.Namespace, Name: monName}, monitor); apierrors.IsNotFound(err) { + // Monitor is gone → delete the Workload. Ignore NotFound here, too. + return ctrl.Result{}, client.IgnoreNotFound(r.Delete(ctx, w)) + } else if err != nil { + // Some other error fetching the monitor + log.Error(err, "failed to get WorkloadMonitor", "monitor", monName) return ctrl.Result{}, err } - err = r.Get(ctx, types.NamespacedName{Name: t.GetName(), Namespace: t.GetNamespace()}, t) - - // found object, nothing to do - if err == nil { - return ctrl.Result{}, nil - } - - // error getting object but not 404 -- requeue - if !apierrors.IsNotFound(err) { - logger.Error(err, "failed to get dependent object", "kind", t.GetObjectKind(), "dependent-object-name", t.GetName()) - return ctrl.Result{}, err - } - - err = r.Delete(ctx, w) - if err != nil { - logger.Error(err, "failed to delete workload") - } - return ctrl.Result{}, err + return ctrl.Result{}, nil } // SetupWithManager registers our controller with the Manager and sets up watches. func (r *WorkloadReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - // Watch WorkloadMonitor objects + // Watch Workload objects For(&cozyv1alpha1.Workload{}). Complete(r) } diff --git a/internal/controller/workload_controller_test.go b/internal/controller/workload_controller_test.go index 816c135e..194a20d3 100644 --- a/internal/controller/workload_controller_test.go +++ b/internal/controller/workload_controller_test.go @@ -1,10 +1,17 @@ package controller import ( + "context" "testing" cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" ) func TestUnprefixedMonitoredObjectReturnsNil(t *testing.T) { @@ -24,3 +31,83 @@ func TestPodMonitoredObject(t *testing.T) { t.Errorf(`getMonitoredObject(&Workload{Name: "%s"}) == %v, want &Pod{Name: "mypod"}`, w.Name, obj) } } + +func TestWorkloadReconciler_DeletesOnMissingMonitor(t *testing.T) { + scheme := runtime.NewScheme() + _ = cozyv1alpha1.AddToScheme(scheme) + _ = corev1.AddToScheme(scheme) + + // Workload with a non-existent monitor + w := &cozyv1alpha1.Workload{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod-foo", + Namespace: "default", + Labels: map[string]string{ + "workloads.cozystack.io/monitor": "missing-monitor", + }, + }, + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(w). + Build() + reconciler := &WorkloadReconciler{Client: fakeClient} + req := reconcile.Request{NamespacedName: types.NamespacedName{Name: "pod-foo", Namespace: "default"}} + + if _, err := reconciler.Reconcile(context.TODO(), req); err != nil { + t.Fatalf("Reconcile returned error: %v", err) + } + + // Expect workload to be deleted + err := fakeClient.Get(context.TODO(), req.NamespacedName, &cozyv1alpha1.Workload{}) + if !apierrors.IsNotFound(err) { + t.Errorf("expected workload to be deleted, got: %v", err) + } +} + +func TestWorkloadReconciler_KeepsWhenAllExist(t *testing.T) { + scheme := runtime.NewScheme() + _ = cozyv1alpha1.AddToScheme(scheme) + _ = corev1.AddToScheme(scheme) + + // Create a monitor and its backing Pod + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon", + Namespace: "default", + }, + } + pod := &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + }, + } + w := &cozyv1alpha1.Workload{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod-foo", + Namespace: "default", + Labels: map[string]string{ + "workloads.cozystack.io/monitor": "mon", + }, + }, + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(monitor, pod, w). + Build() + reconciler := &WorkloadReconciler{Client: fakeClient} + req := reconcile.Request{NamespacedName: types.NamespacedName{Name: "pod-foo", Namespace: "default"}} + + if _, err := reconciler.Reconcile(context.TODO(), req); err != nil { + t.Fatalf("Reconcile returned error: %v", err) + } + + // Expect workload to remain + err := fakeClient.Get(context.TODO(), req.NamespacedName, &cozyv1alpha1.Workload{}) + if err != nil { + t.Errorf("expected workload to persist, got error: %v", err) + } +} diff --git a/internal/controller/workloadmonitor_controller.go b/internal/controller/workloadmonitor_controller.go index 4408800e..35906a87 100644 --- a/internal/controller/workloadmonitor_controller.go +++ b/internal/controller/workloadmonitor_controller.go @@ -4,11 +4,18 @@ import ( "context" "encoding/json" "fmt" + "io" + "net/http" + "net/url" "sort" + "strconv" + "strings" + "time" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" "k8s.io/utils/pointer" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -21,8 +28,29 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + cosiv1alpha1 "sigs.k8s.io/container-object-storage-interface-api/apis/objectstorage/v1alpha1" ) +const ( + // namespaceMonitoringLabel is the namespace label that indicates which tenant + // namespace hosts the monitoring stack (VictoriaMetrics/Prometheus). + namespaceMonitoringLabel = "namespace.cozystack.io/monitoring" + workloadLabelPrefix = "workloads.cozystack.io/" + // workloadMonitorLabel is reserved: it names the WorkloadMonitor that owns + // the Workload and is always set by the reconciler, so it is never copied + // from monitor labels. + workloadMonitorLabel = workloadLabelPrefix + "monitor" + // vmSelectService is the well-known service name for VictoriaMetrics vmselect + // within a monitoring namespace. Port 8481, path /select/0/prometheus. + vmSelectService = "vmselect-shortterm" + vmSelectPort = "8481" + vmSelectPath = "/select/0/prometheus" +) + +// prometheusHTTPClient is a dedicated HTTP client for Prometheus queries, +// avoiding the shared http.DefaultClient global. +var prometheusHTTPClient = &http.Client{Timeout: 10 * time.Second} + // WorkloadMonitorReconciler reconciles a WorkloadMonitor object type WorkloadMonitorReconciler struct { client.Client @@ -35,6 +63,13 @@ type WorkloadMonitorReconciler struct { // +kubebuilder:rbac:groups=cozystack.io,resources=workloads/status,verbs=get;update;patch // +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch // +kubebuilder:rbac:groups=core,resources=persistentvolumeclaims,verbs=get;list;watch +// +kubebuilder:rbac:groups=core,resources=namespaces,verbs=get +// +kubebuilder:rbac:groups=objectstorage.k8s.io,resources=bucketclaims,verbs=get;list;watch + +// isBucketClaimReady checks if the BucketClaim has been provisioned. +func (r *WorkloadMonitorReconciler) isBucketClaimReady(bc *cosiv1alpha1.BucketClaim) bool { + return bc.Status.BucketReady +} // isServiceReady checks if the service has an external IP bound func (r *WorkloadMonitorReconciler) isServiceReady(svc *corev1.Service) bool { @@ -100,6 +135,190 @@ func updateOwnerReferences(obj metav1.Object, monitor client.Object) { obj.SetOwnerReferences(owners) } +// resolvePrometheusURL returns the Prometheus-compatible API base URL for the given namespace. +// It reads the namespace.cozystack.io/monitoring label to find the monitoring namespace, +// then constructs the vmselect URL. Returns empty string if monitoring is not configured. +func (r *WorkloadMonitorReconciler) resolvePrometheusURL(ctx context.Context, namespace string) string { + logger := log.FromContext(ctx) + ns := &corev1.Namespace{} + if err := r.Get(ctx, types.NamespacedName{Name: namespace}, ns); err != nil { + logger.V(1).Info("Failed to read namespace for monitoring resolution", "namespace", namespace, "error", err) + return "" + } + monitoringNS := ns.Labels[namespaceMonitoringLabel] + if monitoringNS == "" { + return "" + } + return fmt.Sprintf("http://%s.%s.svc:%s%s", vmSelectService, monitoringNS, vmSelectPort, vmSelectPath) +} + +// bucketMetrics holds size metrics for a single bucket, keyed by metric name. +type bucketMetrics struct { + LogicalSize int64 + PhysicalSize int64 + HasLogical bool + HasPhysical bool +} + +// queryAllBucketMetrics fetches SeaweedFS bucket size metrics for the given +// bucket names in a single Prometheus query and returns them keyed by bucket +// name. The query is scoped to only the requested buckets to avoid fetching +// metrics for buckets belonging to other WorkloadMonitors. +func (r *WorkloadMonitorReconciler) queryAllBucketMetrics(ctx context.Context, prometheusBaseURL string, bucketNames []string) map[string]*bucketMetrics { + result := make(map[string]*bucketMetrics) + if prometheusBaseURL == "" || len(bucketNames) == 0 { + return result + } + logger := log.FromContext(ctx) + + query := fmt.Sprintf(`{__name__=~"SeaweedFS_s3_bucket_(size|physical_size)_bytes",bucket=~"%s"}`, strings.Join(bucketNames, "|")) + u, err := url.Parse(strings.TrimRight(prometheusBaseURL, "/") + "/api/v1/query") + if err != nil { + logger.Error(err, "Failed to parse Prometheus URL") + return result + } + u.RawQuery = url.Values{"query": {query}}.Encode() + + httpCtx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + req, err := http.NewRequestWithContext(httpCtx, http.MethodGet, u.String(), nil) + if err != nil { + logger.Error(err, "Failed to create Prometheus request") + return result + } + + resp, err := prometheusHTTPClient.Do(req) + if err != nil { + logger.V(1).Info("Failed to query Prometheus for bucket metrics", "error", err) + return result + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + logger.V(1).Info("Prometheus returned non-OK status for bucket metrics", "status", resp.StatusCode) + return result + } + + body, err := io.ReadAll(io.LimitReader(resp.Body, 4<<20)) + if err != nil { + logger.Error(err, "Failed to read Prometheus response") + return result + } + + var promResp struct { + Status string `json:"status"` + Data struct { + Result []struct { + Metric map[string]string `json:"metric"` + Value [2]json.RawMessage `json:"value"` + } `json:"result"` + } `json:"data"` + } + if err := json.Unmarshal(body, &promResp); err != nil { + logger.Error(err, "Failed to parse Prometheus response") + return result + } + if promResp.Status != "success" { + return result + } + + for _, r := range promResp.Data.Result { + bucket := r.Metric["bucket"] + metricName := r.Metric["__name__"] + if bucket == "" || metricName == "" { + continue + } + + var valueStr string + if err := json.Unmarshal(r.Value[1], &valueStr); err != nil { + continue + } + val, err := strconv.ParseFloat(valueStr, 64) + if err != nil { + continue + } + + bm, ok := result[bucket] + if !ok { + bm = &bucketMetrics{} + result[bucket] = bm + } + + switch metricName { + case "SeaweedFS_s3_bucket_size_bytes": + bm.LogicalSize = int64(val) + bm.HasLogical = true + case "SeaweedFS_s3_bucket_physical_size_bytes": + bm.PhysicalSize = int64(val) + bm.HasPhysical = true + } + } + + return result +} + +// reconcileBucketClaimForMonitor creates or updates a Workload object for the given BucketClaim and WorkloadMonitor. +func (r *WorkloadMonitorReconciler) reconcileBucketClaimForMonitor( + ctx context.Context, + monitor *cozyv1alpha1.WorkloadMonitor, + bc cosiv1alpha1.BucketClaim, + allMetrics map[string]*bucketMetrics, +) error { + logger := log.FromContext(ctx) + workload := &cozyv1alpha1.Workload{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("bucket-%s", bc.Name), + Namespace: bc.Namespace, + Labels: make(map[string]string, len(bc.Labels)), + }, + } + + resources := make(map[string]resource.Quantity) + + // Look up pre-fetched bucket metrics by the SeaweedFS bucket name. + // bc.Status.BucketName is the COSI Bucket name, which the COSI driver + // uses directly as the SeaweedFS bucket name. + if bm, ok := allMetrics[bc.Status.BucketName]; ok { + if bm.HasLogical { + resources["s3-storage-bytes"] = *resource.NewQuantity(bm.LogicalSize, resource.BinarySI) + } + if bm.HasPhysical { + resources["s3-physical-storage-bytes"] = *resource.NewQuantity(bm.PhysicalSize, resource.BinarySI) + } + } + + monitorLabels := r.getMonitorLabels(monitor) + _, err := ctrl.CreateOrUpdate(ctx, r.Client, workload, func() error { + updateOwnerReferences(workload.GetObjectMeta(), &bc) + + if workload.Labels == nil { + workload.Labels = make(map[string]string) + } + // Apply monitor-level labels first so source-object labels can override on conflict + for k, v := range monitorLabels { + workload.Labels[k] = v + } + for k, v := range bc.Labels { + workload.Labels[k] = v + } + workload.Labels[workloadMonitorLabel] = monitor.Name + + workload.Status.Kind = monitor.Spec.Kind + workload.Status.Type = monitor.Spec.Type + workload.Status.Resources = resources + workload.Status.Operational = r.isBucketClaimReady(&bc) + + return nil + }) + if err != nil { + logger.Error(err, "Failed to CreateOrUpdate Workload", "workload", workload.Name) + return err + } + + return nil +} + // reconcileServiceForMonitor creates or updates a Workload object for the given Service and WorkloadMonitor. func (r *WorkloadMonitorReconciler) reconcileServiceForMonitor( ctx context.Context, @@ -111,6 +330,7 @@ func (r *WorkloadMonitorReconciler) reconcileServiceForMonitor( ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("svc-%s", svc.Name), Namespace: svc.Namespace, + Labels: make(map[string]string, len(svc.Labels)), }, } @@ -135,11 +355,22 @@ func (r *WorkloadMonitorReconciler) reconcileServiceForMonitor( resourceLabel = fmt.Sprintf("%s.ipaddresspool.metallb.io/requests.ipaddresses", resourceLabel) resources[resourceLabel] = quantity + monitorLabels := r.getMonitorLabels(monitor) _, err := ctrl.CreateOrUpdate(ctx, r.Client, workload, func() error { // Update owner references with the new monitor - updateOwnerReferences(workload.GetObjectMeta(), monitor) + updateOwnerReferences(workload.GetObjectMeta(), &svc) - workload.Labels = svc.Labels + // Apply monitor-level labels first so source-object labels can override on conflict + if workload.Labels == nil { + workload.Labels = make(map[string]string) + } + for k, v := range monitorLabels { + workload.Labels[k] = v + } + for k, v := range svc.Labels { + workload.Labels[k] = v + } + workload.Labels[workloadMonitorLabel] = monitor.Name // Fill Workload status fields: workload.Status.Kind = monitor.Spec.Kind @@ -168,6 +399,7 @@ func (r *WorkloadMonitorReconciler) reconcilePVCForMonitor( ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("pvc-%s", pvc.Name), Namespace: pvc.Namespace, + Labels: make(map[string]string, len(pvc.Labels)), }, } @@ -182,11 +414,22 @@ func (r *WorkloadMonitorReconciler) reconcilePVCForMonitor( resources[resourceLabel] = resourceQuantity } + monitorLabels := r.getMonitorLabels(monitor) _, err := ctrl.CreateOrUpdate(ctx, r.Client, workload, func() error { // Update owner references with the new monitor - updateOwnerReferences(workload.GetObjectMeta(), monitor) + updateOwnerReferences(workload.GetObjectMeta(), &pvc) - workload.Labels = pvc.Labels + // Apply monitor-level labels first so source-object labels can override on conflict + if workload.Labels == nil { + workload.Labels = make(map[string]string) + } + for k, v := range monitorLabels { + workload.Labels[k] = v + } + for k, v := range pvc.Labels { + workload.Labels[k] = v + } + workload.Labels[workloadMonitorLabel] = monitor.Name // Fill Workload status fields: workload.Status.Kind = monitor.Spec.Kind @@ -248,19 +491,27 @@ func (r *WorkloadMonitorReconciler) reconcilePodForMonitor( ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("pod-%s", pod.Name), Namespace: pod.Namespace, - Labels: map[string]string{}, + Labels: make(map[string]string, len(pod.Labels)), }, } metaLabels := r.getWorkloadMetadata(&pod) + monitorLabels := r.getMonitorLabels(monitor) _, err := ctrl.CreateOrUpdate(ctx, r.Client, workload, func() error { // Update owner references with the new monitor - updateOwnerReferences(workload.GetObjectMeta(), monitor) + updateOwnerReferences(workload.GetObjectMeta(), &pod) - // Copy labels from the Pod if needed + // Apply monitor-level labels first so source-object labels can override on conflict + if workload.Labels == nil { + workload.Labels = make(map[string]string) + } + for k, v := range monitorLabels { + workload.Labels[k] = v + } for k, v := range pod.Labels { workload.Labels[k] = v } + workload.Labels[workloadMonitorLabel] = monitor.Name // Add workload meta to labels for k, v := range metaLabels { @@ -366,23 +617,67 @@ func (r *WorkloadMonitorReconciler) Reconcile(ctx context.Context, req ctrl.Requ } } + bucketClaimList := &cosiv1alpha1.BucketClaimList{} + if err := r.List( + ctx, + bucketClaimList, + client.InNamespace(monitor.Namespace), + client.MatchingLabels(monitor.Spec.Selector), + ); err != nil { + logger.Error(err, "Unable to list BucketClaims for WorkloadMonitor", "monitor", monitor.Name) + return ctrl.Result{}, err + } + + if len(bucketClaimList.Items) > 0 { + bucketPromURL := r.resolvePrometheusURL(ctx, monitor.Namespace) + var bucketNames []string + for _, bc := range bucketClaimList.Items { + if bc.Status.BucketName != "" { + bucketNames = append(bucketNames, bc.Status.BucketName) + } + } + allBucketMetrics := r.queryAllBucketMetrics(ctx, bucketPromURL, bucketNames) + for _, bc := range bucketClaimList.Items { + if err := r.reconcileBucketClaimForMonitor(ctx, monitor, bc, allBucketMetrics); err != nil { + logger.Error(err, "Failed to reconcile Workload for BucketClaim", "BucketClaim", bc.Name) + continue + } + } + } + // Update WorkloadMonitor status based on observed pods monitor.Status.ObservedReplicas = observedReplicas monitor.Status.AvailableReplicas = availableReplicas - // Default to operational = true, but check MinReplicas if set - monitor.Status.Operational = pointer.Bool(true) - if monitor.Spec.MinReplicas != nil && availableReplicas < *monitor.Spec.MinReplicas { - monitor.Status.Operational = pointer.Bool(false) - } - // Update the WorkloadMonitor status in the cluster - if err := r.Status().Update(ctx, monitor); err != nil { - logger.Error(err, "Unable to update WorkloadMonitor status", "monitor", monitor.Name) + err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { + fresh := &cozyv1alpha1.WorkloadMonitor{} + if err := r.Get(ctx, req.NamespacedName, fresh); err != nil { + return err + } + fresh.Status.ObservedReplicas = observedReplicas + fresh.Status.AvailableReplicas = availableReplicas + + // Default to operational = true, but check MinReplicas if set. + // Use fresh.Spec to avoid making decisions based on a stale cached copy + // when the spec was updated between the initial read and this retry. + fresh.Status.Operational = pointer.Bool(true) + if fresh.Spec.MinReplicas != nil && availableReplicas < *fresh.Spec.MinReplicas { + fresh.Status.Operational = pointer.Bool(false) + } + return r.Status().Update(ctx, fresh) + }) + if err != nil { + logger.Error(err, "unable to update WorkloadMonitor status after retries") return ctrl.Result{}, err } - // Return without requeue if we want purely event-driven reconciliations + // Requeue periodically if there are BucketClaims to keep sizes up to date. + // Bucket sizes come from Prometheus metrics that update every 60s. + if len(bucketClaimList.Items) > 0 { + return ctrl.Result{RequeueAfter: 60 * time.Second}, nil + } + return ctrl.Result{}, nil } @@ -401,6 +696,11 @@ func (r *WorkloadMonitorReconciler) SetupWithManager(mgr ctrl.Manager) error { &corev1.PersistentVolumeClaim{}, handler.EnqueueRequestsFromMapFunc(mapObjectToMonitor(&corev1.PersistentVolumeClaim{}, r.Client)), ). + // Watch BucketClaims for S3 bucket billing + Watches( + &cosiv1alpha1.BucketClaim{}, + handler.EnqueueRequestsFromMapFunc(mapObjectToMonitor(&cosiv1alpha1.BucketClaim{}, r.Client)), + ). // Watch for changes to Workload objects we create (owned by WorkloadMonitor) Owns(&cozyv1alpha1.Workload{}). Complete(r) @@ -449,5 +749,26 @@ func (r *WorkloadMonitorReconciler) getWorkloadMetadata(obj client.Object) map[s if instanceType, ok := annotations["kubevirt.io/cluster-instancetype-name"]; ok { labels["workloads.cozystack.io/kubevirt-vmi-instance-type"] = instanceType } + if instanceProfile, ok := annotations["kubevirt.io/cluster-instanceprofile-name"]; ok { + labels["workloads.cozystack.io/kubevirt-vmi-instance-profile"] = instanceProfile + } + return labels +} + +// getMonitorLabels extracts workloads.cozystack.io/* labels from a WorkloadMonitor +// so they can be propagated onto Workload objects created for pods, PVCs, services, +// or bucket claims. The monitor label "workloads.cozystack.io/monitor" is reserved +// and set separately per Workload, so it is excluded here. +func (r *WorkloadMonitorReconciler) getMonitorLabels(monitor *cozyv1alpha1.WorkloadMonitor) map[string]string { + labels := make(map[string]string) + for k, v := range monitor.GetLabels() { + if !strings.HasPrefix(k, workloadLabelPrefix) { + continue + } + if k == workloadMonitorLabel { + continue + } + labels[k] = v + } return labels } diff --git a/internal/controller/workloadmonitor_controller_test.go b/internal/controller/workloadmonitor_controller_test.go new file mode 100644 index 00000000..355b0379 --- /dev/null +++ b/internal/controller/workloadmonitor_controller_test.go @@ -0,0 +1,846 @@ +package controller + +import ( + "context" + "fmt" + "net/http" + "net/http/httptest" + "strings" + "testing" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + cosiv1alpha1 "sigs.k8s.io/container-object-storage-interface-api/apis/objectstorage/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +func TestReconcile_OperationalStatusPersisted(t *testing.T) { + scheme := runtime.NewScheme() + _ = cozyv1alpha1.AddToScheme(scheme) + _ = corev1.AddToScheme(scheme) + _ = cosiv1alpha1.AddToScheme(scheme) + + minReplicas := int32(2) + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-monitor", + Namespace: "default", + }, + Spec: cozyv1alpha1.WorkloadMonitorSpec{ + Selector: map[string]string{"app": "test"}, + MinReplicas: &minReplicas, + }, + } + + // Create one pod that is ready — availableReplicas=1 < minReplicas=2, so Operational should be false + pod := &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pod-1", + Namespace: "default", + Labels: map[string]string{"app": "test"}, + }, + Status: corev1.PodStatus{ + Conditions: []corev1.PodCondition{ + {Type: corev1.PodReady, Status: corev1.ConditionTrue}, + }, + }, + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(monitor, pod). + WithStatusSubresource(monitor). + Build() + + reconciler := &WorkloadMonitorReconciler{Client: fakeClient, Scheme: scheme} + req := reconcile.Request{NamespacedName: types.NamespacedName{Name: "test-monitor", Namespace: "default"}} + + _, err := reconciler.Reconcile(context.TODO(), req) + if err != nil { + t.Fatalf("Reconcile returned error: %v", err) + } + + // Fetch the monitor back from fake client and check Operational is persisted + updated := &cozyv1alpha1.WorkloadMonitor{} + if err := fakeClient.Get(context.TODO(), req.NamespacedName, updated); err != nil { + t.Fatalf("Failed to get updated WorkloadMonitor: %v", err) + } + + if updated.Status.Operational == nil { + t.Fatal("Expected Operational to be set, got nil") + } + if *updated.Status.Operational { + t.Error("Expected Operational=false (1 available < 2 minReplicas), got true") + } + if updated.Status.ObservedReplicas != 1 { + t.Errorf("Expected ObservedReplicas=1, got %d", updated.Status.ObservedReplicas) + } + if updated.Status.AvailableReplicas != 1 { + t.Errorf("Expected AvailableReplicas=1, got %d", updated.Status.AvailableReplicas) + } +} + +func TestReconcile_OperationalTrue_WhenEnoughReplicas(t *testing.T) { + scheme := runtime.NewScheme() + _ = cozyv1alpha1.AddToScheme(scheme) + _ = corev1.AddToScheme(scheme) + _ = cosiv1alpha1.AddToScheme(scheme) + + minReplicas := int32(1) + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-monitor", + Namespace: "default", + }, + Spec: cozyv1alpha1.WorkloadMonitorSpec{ + Selector: map[string]string{"app": "test"}, + MinReplicas: &minReplicas, + }, + } + + pod := &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pod-1", + Namespace: "default", + Labels: map[string]string{"app": "test"}, + }, + Status: corev1.PodStatus{ + Conditions: []corev1.PodCondition{ + {Type: corev1.PodReady, Status: corev1.ConditionTrue}, + }, + }, + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(monitor, pod). + WithStatusSubresource(monitor). + Build() + + reconciler := &WorkloadMonitorReconciler{Client: fakeClient, Scheme: scheme} + req := reconcile.Request{NamespacedName: types.NamespacedName{Name: "test-monitor", Namespace: "default"}} + + _, err := reconciler.Reconcile(context.TODO(), req) + if err != nil { + t.Fatalf("Reconcile returned error: %v", err) + } + + updated := &cozyv1alpha1.WorkloadMonitor{} + if err := fakeClient.Get(context.TODO(), req.NamespacedName, updated); err != nil { + t.Fatalf("Failed to get updated WorkloadMonitor: %v", err) + } + + if updated.Status.Operational == nil { + t.Fatal("Expected Operational to be set, got nil") + } + if !*updated.Status.Operational { + t.Error("Expected Operational=true (1 available >= 1 minReplicas), got false") + } +} + +func TestGetMonitorLabels(t *testing.T) { + tests := []struct { + name string + labels map[string]string + expected map[string]string + }{ + { + name: "nil labels", + labels: nil, + expected: map[string]string{}, + }, + { + name: "only workloads.cozystack.io/* labels are propagated", + labels: map[string]string{ + "workloads.cozystack.io/resource-preset": "medium", + "app.kubernetes.io/name": "postgres", + "custom.example.com/team": "platform", + }, + expected: map[string]string{ + "workloads.cozystack.io/resource-preset": "medium", + }, + }, + { + name: "monitor label is reserved and excluded", + labels: map[string]string{ + "workloads.cozystack.io/resource-preset": "small", + "workloads.cozystack.io/monitor": "should-be-dropped", + }, + expected: map[string]string{ + "workloads.cozystack.io/resource-preset": "small", + }, + }, + { + name: "multiple workloads.cozystack.io labels propagate", + labels: map[string]string{ + "workloads.cozystack.io/resource-preset": "large", + "workloads.cozystack.io/tier": "db", + }, + expected: map[string]string{ + "workloads.cozystack.io/resource-preset": "large", + "workloads.cozystack.io/tier": "db", + }, + }, + { + name: "no matching labels returns empty map", + labels: map[string]string{ + "app.kubernetes.io/name": "postgres", + }, + expected: map[string]string{}, + }, + } + + r := &WorkloadMonitorReconciler{} + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{Labels: tc.labels}, + } + got := r.getMonitorLabels(monitor) + if len(got) != len(tc.expected) { + t.Fatalf("expected %d labels, got %d (%v)", len(tc.expected), len(got), got) + } + for k, v := range tc.expected { + if gv, ok := got[k]; !ok || gv != v { + t.Errorf("expected label %q=%q, got %q", k, v, gv) + } + } + }) + } +} + +func TestReconcile_MonitorLabelsPropagatedToPodWorkload(t *testing.T) { + scheme := runtime.NewScheme() + _ = cozyv1alpha1.AddToScheme(scheme) + _ = corev1.AddToScheme(scheme) + + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-monitor", + Namespace: "default", + Labels: map[string]string{ + "workloads.cozystack.io/resource-preset": "medium", + "app.kubernetes.io/name": "ignored-not-propagated", + }, + }, + Spec: cozyv1alpha1.WorkloadMonitorSpec{ + Selector: map[string]string{"app": "test"}, + Kind: "postgres", + Type: "postgres", + }, + } + + pod := &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pod-1", + Namespace: "default", + Labels: map[string]string{ + "app": "test", + "app.kubernetes.io/name": "pod-wins-on-conflict", + }, + }, + Status: corev1.PodStatus{ + Conditions: []corev1.PodCondition{ + {Type: corev1.PodReady, Status: corev1.ConditionTrue}, + }, + }, + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(monitor, pod). + WithStatusSubresource(monitor). + Build() + + reconciler := &WorkloadMonitorReconciler{Client: fakeClient, Scheme: scheme} + req := reconcile.Request{NamespacedName: types.NamespacedName{Name: "test-monitor", Namespace: "default"}} + if _, err := reconciler.Reconcile(context.TODO(), req); err != nil { + t.Fatalf("Reconcile returned error: %v", err) + } + + workload := &cozyv1alpha1.Workload{} + if err := fakeClient.Get(context.TODO(), types.NamespacedName{Name: "pod-test-pod-1", Namespace: "default"}, workload); err != nil { + t.Fatalf("Failed to get Workload: %v", err) + } + + if got := workload.Labels["workloads.cozystack.io/resource-preset"]; got != "medium" { + t.Errorf("expected monitor label propagated, got %q", got) + } + // Non-workloads.cozystack.io monitor labels must not be copied + if _, ok := workload.Labels["app.kubernetes.io/name"]; !ok { + t.Error("expected pod label to be present on Workload") + } + // Source-object label takes precedence on conflict + if got := workload.Labels["app.kubernetes.io/name"]; got != "pod-wins-on-conflict" { + t.Errorf("expected pod label to win on conflict, got %q", got) + } + // Reserved monitor label is always set from the monitor name + if got := workload.Labels["workloads.cozystack.io/monitor"]; got != "test-monitor" { + t.Errorf("expected monitor-name label, got %q", got) + } +} + +func TestReconcile_BackwardCompat_NoMonitorLabels(t *testing.T) { + scheme := runtime.NewScheme() + _ = cozyv1alpha1.AddToScheme(scheme) + _ = corev1.AddToScheme(scheme) + + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-monitor", + Namespace: "default", + }, + Spec: cozyv1alpha1.WorkloadMonitorSpec{ + Selector: map[string]string{"app": "test"}, + }, + } + + pod := &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pod-1", + Namespace: "default", + Labels: map[string]string{"app": "test"}, + }, + Status: corev1.PodStatus{ + Conditions: []corev1.PodCondition{ + {Type: corev1.PodReady, Status: corev1.ConditionTrue}, + }, + }, + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(monitor, pod). + WithStatusSubresource(monitor). + Build() + + reconciler := &WorkloadMonitorReconciler{Client: fakeClient, Scheme: scheme} + req := reconcile.Request{NamespacedName: types.NamespacedName{Name: "test-monitor", Namespace: "default"}} + if _, err := reconciler.Reconcile(context.TODO(), req); err != nil { + t.Fatalf("Reconcile returned error: %v", err) + } + + workload := &cozyv1alpha1.Workload{} + if err := fakeClient.Get(context.TODO(), types.NamespacedName{Name: "pod-test-pod-1", Namespace: "default"}, workload); err != nil { + t.Fatalf("Failed to get Workload: %v", err) + } + for k := range workload.Labels { + if strings.HasPrefix(k, "workloads.cozystack.io/") && k != "workloads.cozystack.io/monitor" { + t.Errorf("unexpected workload label present: %q", k) + } + } +} + +func TestReconcile_OperationalTrue_WhenNoMinReplicas(t *testing.T) { + scheme := runtime.NewScheme() + _ = cozyv1alpha1.AddToScheme(scheme) + _ = corev1.AddToScheme(scheme) + _ = cosiv1alpha1.AddToScheme(scheme) + + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-monitor", + Namespace: "default", + }, + Spec: cozyv1alpha1.WorkloadMonitorSpec{ + Selector: map[string]string{"app": "test"}, + // No MinReplicas — should default to operational=true + }, + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(monitor). + WithStatusSubresource(monitor). + Build() + + reconciler := &WorkloadMonitorReconciler{Client: fakeClient, Scheme: scheme} + req := reconcile.Request{NamespacedName: types.NamespacedName{Name: "test-monitor", Namespace: "default"}} + + _, err := reconciler.Reconcile(context.TODO(), req) + if err != nil { + t.Fatalf("Reconcile returned error: %v", err) + } + + updated := &cozyv1alpha1.WorkloadMonitor{} + if err := fakeClient.Get(context.TODO(), req.NamespacedName, updated); err != nil { + t.Fatalf("Failed to get updated WorkloadMonitor: %v", err) + } + + if updated.Status.Operational == nil { + t.Fatal("Expected Operational to be set, got nil") + } + if !*updated.Status.Operational { + t.Error("Expected Operational=true (no MinReplicas constraint), got false") + } +} + +func newTestScheme() *runtime.Scheme { + s := runtime.NewScheme() + _ = cozyv1alpha1.AddToScheme(s) + _ = corev1.AddToScheme(s) + _ = cosiv1alpha1.AddToScheme(s) + return s +} + +func TestReconcileBucketClaimCreatesWorkload(t *testing.T) { + s := newTestScheme() + + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-bucket", + Namespace: "tenant-demo", + }, + Spec: cozyv1alpha1.WorkloadMonitorSpec{ + Kind: "bucket", + Type: "s3", + Selector: map[string]string{ + "app.kubernetes.io/instance": "my-bucket", + }, + }, + } + + bc := &cosiv1alpha1.BucketClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-bucket", + Namespace: "tenant-demo", + Labels: map[string]string{ + "app.kubernetes.io/instance": "my-bucket", + }, + }, + Spec: cosiv1alpha1.BucketClaimSpec{ + BucketClassName: "seaweedfs", + Protocols: []cosiv1alpha1.Protocol{cosiv1alpha1.ProtocolS3}, + }, + Status: cosiv1alpha1.BucketClaimStatus{ + BucketReady: true, + BucketName: "cosi-abc123", + }, + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(s). + WithObjects(monitor, bc). + WithStatusSubresource(monitor). + Build() + + reconciler := &WorkloadMonitorReconciler{Client: fakeClient, Scheme: s} + req := reconcile.Request{NamespacedName: types.NamespacedName{ + Name: "my-bucket", + Namespace: "tenant-demo", + }} + + _, err := reconciler.Reconcile(context.TODO(), req) + if err != nil { + t.Fatalf("Reconcile returned error: %v", err) + } + + workload := &cozyv1alpha1.Workload{} + err = fakeClient.Get(context.TODO(), types.NamespacedName{ + Name: "bucket-my-bucket", + Namespace: "tenant-demo", + }, workload) + if err != nil { + t.Fatalf("expected Workload to be created, got error: %v", err) + } + + if workload.Status.Kind != "bucket" { + t.Errorf("expected Kind=bucket, got %q", workload.Status.Kind) + } + if workload.Status.Type != "s3" { + t.Errorf("expected Type=s3, got %q", workload.Status.Type) + } + if !workload.Status.Operational { + t.Error("expected Operational=true for ready BucketClaim") + } +} + +func TestReconcileBucketClaimNotReady(t *testing.T) { + s := newTestScheme() + + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-bucket", + Namespace: "tenant-demo", + }, + Spec: cozyv1alpha1.WorkloadMonitorSpec{ + Kind: "bucket", + Type: "s3", + Selector: map[string]string{ + "app.kubernetes.io/instance": "my-bucket", + }, + }, + } + + bc := &cosiv1alpha1.BucketClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-bucket", + Namespace: "tenant-demo", + Labels: map[string]string{ + "app.kubernetes.io/instance": "my-bucket", + }, + }, + Spec: cosiv1alpha1.BucketClaimSpec{ + BucketClassName: "seaweedfs", + Protocols: []cosiv1alpha1.Protocol{cosiv1alpha1.ProtocolS3}, + }, + Status: cosiv1alpha1.BucketClaimStatus{ + BucketReady: false, + }, + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(s). + WithObjects(monitor, bc). + WithStatusSubresource(monitor). + Build() + + reconciler := &WorkloadMonitorReconciler{Client: fakeClient, Scheme: s} + req := reconcile.Request{NamespacedName: types.NamespacedName{ + Name: "my-bucket", + Namespace: "tenant-demo", + }} + + _, err := reconciler.Reconcile(context.TODO(), req) + if err != nil { + t.Fatalf("Reconcile returned error: %v", err) + } + + workload := &cozyv1alpha1.Workload{} + err = fakeClient.Get(context.TODO(), types.NamespacedName{ + Name: "bucket-my-bucket", + Namespace: "tenant-demo", + }, workload) + if err != nil { + t.Fatalf("expected Workload to be created, got error: %v", err) + } + + if workload.Status.Operational { + t.Error("expected Operational=false for not-ready BucketClaim") + } +} + +func TestReconcile_MonitorLabelsPropagatedToBucketClaimWorkload(t *testing.T) { + s := newTestScheme() + + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-bucket", + Namespace: "tenant-demo", + Labels: map[string]string{ + "workloads.cozystack.io/resource-preset": "medium", + "app.kubernetes.io/name": "ignored-not-propagated", + }, + }, + Spec: cozyv1alpha1.WorkloadMonitorSpec{ + Kind: "bucket", + Type: "s3", + Selector: map[string]string{ + "app.kubernetes.io/instance": "my-bucket", + }, + }, + } + + bc := &cosiv1alpha1.BucketClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-bucket", + Namespace: "tenant-demo", + Labels: map[string]string{ + "app.kubernetes.io/instance": "my-bucket", + "app.kubernetes.io/name": "bucket-wins-on-conflict", + }, + }, + Spec: cosiv1alpha1.BucketClaimSpec{ + BucketClassName: "seaweedfs", + Protocols: []cosiv1alpha1.Protocol{cosiv1alpha1.ProtocolS3}, + }, + Status: cosiv1alpha1.BucketClaimStatus{ + BucketReady: true, + BucketName: "cosi-abc123", + }, + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(s). + WithObjects(monitor, bc). + WithStatusSubresource(monitor). + Build() + + reconciler := &WorkloadMonitorReconciler{Client: fakeClient, Scheme: s} + req := reconcile.Request{NamespacedName: types.NamespacedName{ + Name: "my-bucket", + Namespace: "tenant-demo", + }} + if _, err := reconciler.Reconcile(context.TODO(), req); err != nil { + t.Fatalf("Reconcile returned error: %v", err) + } + + workload := &cozyv1alpha1.Workload{} + if err := fakeClient.Get(context.TODO(), types.NamespacedName{ + Name: "bucket-my-bucket", + Namespace: "tenant-demo", + }, workload); err != nil { + t.Fatalf("Failed to get Workload: %v", err) + } + + if got := workload.Labels["workloads.cozystack.io/resource-preset"]; got != "medium" { + t.Errorf("expected monitor label propagated, got %q", got) + } + // Source-object label takes precedence on conflict + if got := workload.Labels["app.kubernetes.io/name"]; got != "bucket-wins-on-conflict" { + t.Errorf("expected bucket claim label to win on conflict, got %q", got) + } + // Reserved monitor label is always set from the monitor name + if got := workload.Labels["workloads.cozystack.io/monitor"]; got != "my-bucket" { + t.Errorf("expected monitor-name label, got %q", got) + } +} + +func TestReconcileNoBucketClaimSkips(t *testing.T) { + s := newTestScheme() + + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-postgres", + Namespace: "tenant-demo", + }, + Spec: cozyv1alpha1.WorkloadMonitorSpec{ + Kind: "postgres", + Type: "postgres", + Selector: map[string]string{ + "app.kubernetes.io/instance": "my-postgres", + }, + }, + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(s). + WithObjects(monitor). + WithStatusSubresource(monitor). + Build() + + reconciler := &WorkloadMonitorReconciler{Client: fakeClient, Scheme: s} + req := reconcile.Request{NamespacedName: types.NamespacedName{ + Name: "my-postgres", + Namespace: "tenant-demo", + }} + + _, err := reconciler.Reconcile(context.TODO(), req) + if err != nil { + t.Fatalf("Reconcile returned error: %v", err) + } + + workloadList := &cozyv1alpha1.WorkloadList{} + err = fakeClient.List(context.TODO(), workloadList) + if err != nil { + t.Fatalf("List returned error: %v", err) + } + + for _, w := range workloadList.Items { + if w.Status.Kind == "bucket" { + t.Error("expected no bucket workloads to be created for postgres monitor") + } + } +} + +func TestQueryAllBucketMetrics(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, `{"status":"success","data":{"resultType":"vector","result":[ + {"metric":{"__name__":"SeaweedFS_s3_bucket_size_bytes","bucket":"bucket-aaa"},"value":[1713000000,"10485864"]}, + {"metric":{"__name__":"SeaweedFS_s3_bucket_physical_size_bytes","bucket":"bucket-aaa"},"value":[1713000000,"20971728"]}, + {"metric":{"__name__":"SeaweedFS_s3_bucket_size_bytes","bucket":"bucket-bbb"},"value":[1713000000,"0"]} + ]}}`) + })) + defer srv.Close() + + reconciler := &WorkloadMonitorReconciler{} + metrics := reconciler.queryAllBucketMetrics(context.TODO(), srv.URL, []string{"bucket-aaa", "bucket-bbb"}) + + bm, ok := metrics["bucket-aaa"] + if !ok { + t.Fatal("expected bucket-aaa in metrics") + } + if !bm.HasLogical || bm.LogicalSize != 10485864 { + t.Errorf("expected logical=10485864, got %d", bm.LogicalSize) + } + if !bm.HasPhysical || bm.PhysicalSize != 20971728 { + t.Errorf("expected physical=20971728, got %d", bm.PhysicalSize) + } + + bm2, ok := metrics["bucket-bbb"] + if !ok { + t.Fatal("expected bucket-bbb in metrics") + } + if !bm2.HasLogical || bm2.LogicalSize != 0 { + t.Errorf("expected logical=0 for empty bucket, got %d", bm2.LogicalSize) + } + if bm2.HasPhysical { + t.Error("expected no physical size for bucket-bbb") + } +} + +func TestQueryAllBucketMetricsEmpty(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, `{"status":"success","data":{"resultType":"vector","result":[]}}`) + })) + defer srv.Close() + + reconciler := &WorkloadMonitorReconciler{} + metrics := reconciler.queryAllBucketMetrics(context.TODO(), srv.URL, []string{"bucket-aaa", "bucket-bbb"}) + if len(metrics) != 0 { + t.Errorf("expected empty metrics, got %d", len(metrics)) + } +} + +func TestQueryAllBucketMetricsServerError(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + })) + defer srv.Close() + + reconciler := &WorkloadMonitorReconciler{} + metrics := reconciler.queryAllBucketMetrics(context.TODO(), srv.URL, []string{"bucket-aaa", "bucket-bbb"}) + if len(metrics) != 0 { + t.Errorf("expected empty metrics on error, got %d", len(metrics)) + } +} + +func TestQueryAllBucketMetricsNoURL(t *testing.T) { + reconciler := &WorkloadMonitorReconciler{} + metrics := reconciler.queryAllBucketMetrics(context.TODO(), "", nil) + if len(metrics) != 0 { + t.Errorf("expected empty metrics when URL is empty, got %d", len(metrics)) + } +} + +func TestResolvePrometheusURL(t *testing.T) { + s := newTestScheme() + + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tenant-demo", + Labels: map[string]string{ + "namespace.cozystack.io/monitoring": "tenant-root", + }, + }, + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(s). + WithObjects(ns). + Build() + + reconciler := &WorkloadMonitorReconciler{Client: fakeClient, Scheme: s} + url := reconciler.resolvePrometheusURL(context.TODO(), "tenant-demo") + + expected := "http://vmselect-shortterm.tenant-root.svc:8481/select/0/prometheus" + if url != expected { + t.Errorf("expected %q, got %q", expected, url) + } +} + +func TestResolvePrometheusURLNoLabel(t *testing.T) { + s := newTestScheme() + + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tenant-demo", + }, + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(s). + WithObjects(ns). + Build() + + reconciler := &WorkloadMonitorReconciler{Client: fakeClient, Scheme: s} + url := reconciler.resolvePrometheusURL(context.TODO(), "tenant-demo") + + if url != "" { + t.Errorf("expected empty URL when no monitoring label, got %q", url) + } +} + +func TestReconcileBucketClaimRequeuesWhenBucketsExist(t *testing.T) { + s := newTestScheme() + + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tenant-demo", + }, + } + + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-bucket", + Namespace: "tenant-demo", + }, + Spec: cozyv1alpha1.WorkloadMonitorSpec{ + Kind: "bucket", + Type: "s3", + Selector: map[string]string{ + "app.kubernetes.io/instance": "my-bucket", + }, + }, + } + + bc := &cosiv1alpha1.BucketClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-bucket", + Namespace: "tenant-demo", + Labels: map[string]string{ + "app.kubernetes.io/instance": "my-bucket", + }, + }, + Spec: cosiv1alpha1.BucketClaimSpec{ + BucketClassName: "seaweedfs", + Protocols: []cosiv1alpha1.Protocol{cosiv1alpha1.ProtocolS3}, + }, + Status: cosiv1alpha1.BucketClaimStatus{ + BucketReady: true, + BucketName: "cosi-abc123", + }, + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(s). + WithObjects(ns, monitor, bc). + WithStatusSubresource(monitor). + Build() + + reconciler := &WorkloadMonitorReconciler{Client: fakeClient, Scheme: s} + req := reconcile.Request{NamespacedName: types.NamespacedName{ + Name: "my-bucket", + Namespace: "tenant-demo", + }} + + result, err := reconciler.Reconcile(context.TODO(), req) + if err != nil { + t.Fatalf("Reconcile returned error: %v", err) + } + + if result.RequeueAfter == 0 { + t.Error("expected RequeueAfter > 0 when buckets exist") + } + + workload := &cozyv1alpha1.Workload{} + err = fakeClient.Get(context.TODO(), types.NamespacedName{ + Name: "bucket-my-bucket", + Namespace: "tenant-demo", + }, workload) + if err != nil { + t.Fatalf("expected Workload to be created, got error: %v", err) + } + + // Without monitoring label on namespace, no size metrics should be set + if _, ok := workload.Status.Resources["s3-storage-bytes"]; ok { + t.Error("expected no s3-storage-bytes when monitoring is not configured") + } + if len(workload.Status.Resources) != 0 { + t.Errorf("expected empty resources without monitoring, got %v", workload.Status.Resources) + } +} diff --git a/internal/cozyvaluesreplicator/cozyvaluesreplicator.go b/internal/cozyvaluesreplicator/cozyvaluesreplicator.go new file mode 100644 index 00000000..5f6215a7 --- /dev/null +++ b/internal/cozyvaluesreplicator/cozyvaluesreplicator.go @@ -0,0 +1,272 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cozyvaluesreplicator + +import ( + "context" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// SecretReplicatorReconciler replicates a source secret to namespaces matching a label selector. +type SecretReplicatorReconciler struct { + client.Client + Scheme *runtime.Scheme + + // Source of truth: + SourceNamespace string + SecretName string + + // Namespaces to replicate into: + // (e.g. labels.SelectorFromSet(labels.Set{"tenant":"true"}), or metav1.LabelSelectorAsSelector(...)) + TargetNamespaceSelector labels.Selector +} + +func (r *SecretReplicatorReconciler) SetupWithManager(mgr ctrl.Manager) error { + // 1) Primary watch for requirement (b): + // Reconcile any Secret named r.SecretName in any namespace (includes source too). + // This keeps Secrets in cache and causes "copy changed -> reconcile it" to happen. + secretNameOnly := predicate.NewPredicateFuncs(func(obj client.Object) bool { + return obj.GetName() == r.SecretName + }) + + // 2) Secondary watch for requirement (c): + // When the *source* Secret changes, fan-out reconcile requests to every matching namespace. + onlySourceSecret := predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { return isSourceSecret(e.Object, r) }, + UpdateFunc: func(e event.UpdateEvent) bool { return isSourceSecret(e.ObjectNew, r) }, + DeleteFunc: func(e event.DeleteEvent) bool { return isSourceSecret(e.Object, r) }, + GenericFunc: func(e event.GenericEvent) bool { + return isSourceSecret(e.Object, r) + }, + } + + // Fan-out mapper for source Secret events -> one request per matching target namespace. + fanOutOnSourceSecret := handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, _ client.Object) []reconcile.Request { + // List namespaces *from the cache* (because we also watch Namespaces below). + var nsList corev1.NamespaceList + if err := r.List(ctx, &nsList); err != nil { + // If list fails, best-effort: return nothing; reconcile will be retried by next event. + return nil + } + + reqs := make([]reconcile.Request, 0, len(nsList.Items)) + for i := range nsList.Items { + ns := &nsList.Items[i] + if ns.Name == r.SourceNamespace { + continue + } + if r.TargetNamespaceSelector != nil && !r.TargetNamespaceSelector.Matches(labels.Set(ns.Labels)) { + continue + } + reqs = append(reqs, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: ns.Name, + Name: r.SecretName, + }, + }) + } + return reqs + }) + + // 3) Namespace watch for requirement (a): + // When a namespace is created/updated to match selector, enqueue reconcile for the Secret copy in that namespace. + enqueueOnNamespaceMatch := handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request { + ns, ok := obj.(*corev1.Namespace) + if !ok { + return nil + } + if ns.Name == r.SourceNamespace { + return nil + } + if r.TargetNamespaceSelector != nil && !r.TargetNamespaceSelector.Matches(labels.Set(ns.Labels)) { + return nil + } + return []reconcile.Request{{ + NamespacedName: types.NamespacedName{ + Namespace: ns.Name, + Name: r.SecretName, + }, + }} + }) + + // Only trigger from namespace events where the label match may be (or become) true. + // (You can keep this simple; it's fine if it fires on any update—your Reconcile should be idempotent.) + namespaceMayMatter := predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + ns, ok := e.Object.(*corev1.Namespace) + return ok && (r.TargetNamespaceSelector == nil || r.TargetNamespaceSelector.Matches(labels.Set(ns.Labels))) + }, + UpdateFunc: func(e event.UpdateEvent) bool { + oldNS, okOld := e.ObjectOld.(*corev1.Namespace) + newNS, okNew := e.ObjectNew.(*corev1.Namespace) + if !okOld || !okNew { + return false + } + // Fire if it matches now OR matched before (covers transitions both ways; reconcile can decide what to do). + oldMatch := r.TargetNamespaceSelector == nil || r.TargetNamespaceSelector.Matches(labels.Set(oldNS.Labels)) + newMatch := r.TargetNamespaceSelector == nil || r.TargetNamespaceSelector.Matches(labels.Set(newNS.Labels)) + return oldMatch || newMatch + }, + DeleteFunc: func(event.DeleteEvent) bool { return false }, // nothing to do on namespace delete + GenericFunc: func(event.GenericEvent) bool { return false }, + } + + return ctrl.NewControllerManagedBy(mgr). + // (b) Watch all Secrets with the chosen name; this also ensures Secret objects are cached. + For(&corev1.Secret{}, builder.WithPredicates(secretNameOnly)). + + // (c) Add a second watch on Secret, but only for the source secret, and fan-out to all namespaces. + Watches( + &corev1.Secret{}, + fanOutOnSourceSecret, + builder.WithPredicates(onlySourceSecret), + ). + + // (a) Watch Namespaces so they're cached and so "namespace appears / starts matching" enqueues reconcile. + Watches( + &corev1.Namespace{}, + enqueueOnNamespaceMatch, + builder.WithPredicates(namespaceMayMatter), + ). + Complete(r) +} + +func isSourceSecret(obj client.Object, r *SecretReplicatorReconciler) bool { + if obj == nil { + return false + } + return obj.GetNamespace() == r.SourceNamespace && obj.GetName() == r.SecretName +} + +func (r *SecretReplicatorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + // Ignore requests that don't match our secret name or are for the source namespace + if req.Name != r.SecretName || req.Namespace == r.SourceNamespace { + return ctrl.Result{}, nil + } + + // Verify the target namespace still exists and matches the selector + targetNamespace := &corev1.Namespace{} + if err := r.Get(ctx, types.NamespacedName{Name: req.Namespace}, targetNamespace); err != nil { + if apierrors.IsNotFound(err) { + // Namespace doesn't exist, nothing to do + return ctrl.Result{}, nil + } + logger.Error(err, "Failed to get target namespace", "namespace", req.Namespace) + return ctrl.Result{}, err + } + + // Check if namespace still matches the selector + if r.TargetNamespaceSelector != nil && !r.TargetNamespaceSelector.Matches(labels.Set(targetNamespace.Labels)) { + // Namespace no longer matches selector, delete the replicated secret if it exists + replicatedSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: req.Namespace, + Name: req.Name, + }, + } + if err := r.Delete(ctx, replicatedSecret); err != nil && !apierrors.IsNotFound(err) { + logger.Error(err, "Failed to delete replicated secret from non-matching namespace", + "namespace", req.Namespace, "secret", req.Name) + return ctrl.Result{}, err + } + return ctrl.Result{}, nil + } + + // Get the source secret + originalSecret := &corev1.Secret{} + if err := r.Get(ctx, types.NamespacedName{Namespace: r.SourceNamespace, Name: r.SecretName}, originalSecret); err != nil { + if apierrors.IsNotFound(err) { + // Source secret doesn't exist, delete the replicated secret if it exists + replicatedSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: req.Namespace, + Name: req.Name, + }, + } + if err := r.Delete(ctx, replicatedSecret); err != nil && !apierrors.IsNotFound(err) { + logger.Error(err, "Failed to delete replicated secret after source secret deletion", + "namespace", req.Namespace, "secret", req.Name) + return ctrl.Result{}, err + } + return ctrl.Result{}, nil + } + logger.Error(err, "Failed to get source secret", + "namespace", r.SourceNamespace, "secret", r.SecretName) + return ctrl.Result{}, err + } + + // Create or update the replicated secret + replicatedSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: req.Namespace, + Name: req.Name, + }, + } + + _, err := controllerutil.CreateOrUpdate(ctx, r.Client, replicatedSecret, func() error { + // Copy the secret data and type from the source + replicatedSecret.Data = make(map[string][]byte) + for k, v := range originalSecret.Data { + replicatedSecret.Data[k] = v + } + replicatedSecret.Type = originalSecret.Type + + // Copy labels and annotations from source (if any) + if originalSecret.Labels != nil { + if replicatedSecret.Labels == nil { + replicatedSecret.Labels = make(map[string]string) + } + for k, v := range originalSecret.Labels { + replicatedSecret.Labels[k] = v + } + } + if originalSecret.Annotations != nil { + if replicatedSecret.Annotations == nil { + replicatedSecret.Annotations = make(map[string]string) + } + for k, v := range originalSecret.Annotations { + replicatedSecret.Annotations[k] = v + } + } + + return nil + }) + if err != nil { + logger.Error(err, "Failed to create or update replicated secret", + "namespace", req.Namespace, "secret", req.Name) + return ctrl.Result{}, err + } + + return ctrl.Result{}, nil +} diff --git a/internal/crdinstall/install.go b/internal/crdinstall/install.go new file mode 100644 index 00000000..5143f2e6 --- /dev/null +++ b/internal/crdinstall/install.go @@ -0,0 +1,112 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package crdinstall + +import ( + "context" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/cozystack/cozystack/internal/manifestutil" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +// Install applies Cozystack CRDs using embedded manifests. +// It extracts the manifests and applies them to the cluster using server-side apply, +// then waits for all CRDs to have the Established condition. +func Install(ctx context.Context, k8sClient client.Client, writeEmbeddedManifests func(string) error) error { + logger := log.FromContext(ctx) + + tmpDir, err := os.MkdirTemp("", "crd-install-*") + if err != nil { + return fmt.Errorf("failed to create temp directory: %w", err) + } + defer os.RemoveAll(tmpDir) + + manifestsDir := filepath.Join(tmpDir, "manifests") + if err := os.MkdirAll(manifestsDir, 0755); err != nil { + return fmt.Errorf("failed to create manifests directory: %w", err) + } + + if err := writeEmbeddedManifests(manifestsDir); err != nil { + return fmt.Errorf("failed to extract embedded manifests: %w", err) + } + + entries, err := os.ReadDir(manifestsDir) + if err != nil { + return fmt.Errorf("failed to read manifests directory: %w", err) + } + + var manifestFiles []string + for _, entry := range entries { + if strings.HasSuffix(entry.Name(), ".yaml") { + manifestFiles = append(manifestFiles, filepath.Join(manifestsDir, entry.Name())) + } + } + + if len(manifestFiles) == 0 { + return fmt.Errorf("no YAML manifest files found in directory") + } + + var objects []*unstructured.Unstructured + for _, manifestPath := range manifestFiles { + objs, err := manifestutil.ParseManifestFile(manifestPath) + if err != nil { + return fmt.Errorf("failed to parse manifests from %s: %w", manifestPath, err) + } + objects = append(objects, objs...) + } + + if len(objects) == 0 { + return fmt.Errorf("no objects found in manifests") + } + + // Validate all objects are CRDs — reject anything else to prevent + // accidental force-apply of arbitrary resources. + for _, obj := range objects { + if obj.GetAPIVersion() != "apiextensions.k8s.io/v1" || obj.GetKind() != "CustomResourceDefinition" { + return fmt.Errorf("unexpected object %s %s/%s in CRD manifests, only apiextensions.k8s.io/v1 CustomResourceDefinition is allowed", + obj.GetAPIVersion(), obj.GetKind(), obj.GetName()) + } + } + + logger.Info("Applying Cozystack CRDs", "count", len(objects)) + for _, obj := range objects { + patchOptions := &client.PatchOptions{ + FieldManager: "cozystack-operator", + Force: func() *bool { b := true; return &b }(), + } + + if err := k8sClient.Patch(ctx, obj, client.Apply, patchOptions); err != nil { + return fmt.Errorf("failed to apply CRD %s: %w", obj.GetName(), err) + } + logger.Info("Applied CRD", "name", obj.GetName()) + } + + crdNames := manifestutil.CollectCRDNames(objects) + if err := manifestutil.WaitForCRDsEstablished(ctx, k8sClient, crdNames); err != nil { + return fmt.Errorf("CRDs not established after apply: %w", err) + } + + logger.Info("CRD installation completed successfully") + return nil +} diff --git a/internal/crdinstall/install_test.go b/internal/crdinstall/install_test.go new file mode 100644 index 00000000..870a146c --- /dev/null +++ b/internal/crdinstall/install_test.go @@ -0,0 +1,302 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package crdinstall + +import ( + "context" + "fmt" + "os" + "path/filepath" + "strings" + "testing" + "time" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/client/interceptor" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" +) + +func TestWriteEmbeddedManifests(t *testing.T) { + tmpDir := t.TempDir() + + if err := WriteEmbeddedManifests(tmpDir); err != nil { + t.Fatalf("WriteEmbeddedManifests() error = %v", err) + } + + entries, err := os.ReadDir(tmpDir) + if err != nil { + t.Fatalf("failed to read output dir: %v", err) + } + + var yamlFiles []string + for _, e := range entries { + if strings.HasSuffix(e.Name(), ".yaml") { + yamlFiles = append(yamlFiles, e.Name()) + } + } + + if len(yamlFiles) == 0 { + t.Error("WriteEmbeddedManifests() produced no YAML files") + } + + expectedFiles := []string{ + "cozystack.io_packages.yaml", + "cozystack.io_packagesources.yaml", + } + for _, expected := range expectedFiles { + found := false + for _, actual := range yamlFiles { + if actual == expected { + found = true + break + } + } + if !found { + t.Errorf("expected file %q not found in output, got %v", expected, yamlFiles) + } + } + + // Verify files are non-empty + for _, f := range yamlFiles { + data, err := os.ReadFile(filepath.Join(tmpDir, f)) + if err != nil { + t.Errorf("failed to read %s: %v", f, err) + continue + } + if len(data) == 0 { + t.Errorf("file %s is empty", f) + } + } +} + +func TestWriteEmbeddedManifests_filePermissions(t *testing.T) { + tmpDir := t.TempDir() + + if err := WriteEmbeddedManifests(tmpDir); err != nil { + t.Fatalf("WriteEmbeddedManifests() error = %v", err) + } + + entries, err := os.ReadDir(tmpDir) + if err != nil { + t.Fatalf("failed to read output dir: %v", err) + } + + for _, e := range entries { + if !strings.HasSuffix(e.Name(), ".yaml") { + continue + } + info, err := e.Info() + if err != nil { + t.Errorf("failed to get info for %s: %v", e.Name(), err) + continue + } + perm := info.Mode().Perm() + if perm&0o077 != 0 { + t.Errorf("file %s has overly permissive mode %o, expected no group/other access", e.Name(), perm) + } + } +} + +// newCRDManifestWriter returns a function that writes test CRD YAML files. +func newCRDManifestWriter(crds ...string) func(string) error { + return func(dir string) error { + for i, crd := range crds { + filename := filepath.Join(dir, fmt.Sprintf("crd%d.yaml", i+1)) + if err := os.WriteFile(filename, []byte(crd), 0600); err != nil { + return err + } + } + return nil + } +} + +var testCRD1 = `apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: packages.cozystack.io +spec: + group: cozystack.io + names: + kind: Package + plural: packages + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object +` + +var testCRD2 = `apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: packagesources.cozystack.io +spec: + group: cozystack.io + names: + kind: PackageSource + plural: packagesources + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object +` + +// establishedInterceptor simulates CRDs becoming Established in the API server. +func establishedInterceptor() interceptor.Funcs { + return interceptor.Funcs{ + Get: func(ctx context.Context, c client.WithWatch, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + if err := c.Get(ctx, key, obj, opts...); err != nil { + return err + } + u, ok := obj.(*unstructured.Unstructured) + if !ok { + return nil + } + if u.GetKind() == "CustomResourceDefinition" { + _ = unstructured.SetNestedSlice(u.Object, []interface{}{ + map[string]interface{}{ + "type": "Established", + "status": "True", + }, + }, "status", "conditions") + } + return nil + }, + } +} + +func TestInstall_appliesAllCRDs(t *testing.T) { + log.SetLogger(zap.New(zap.UseDevMode(true))) + + scheme := runtime.NewScheme() + if err := apiextensionsv1.AddToScheme(scheme); err != nil { + t.Fatalf("failed to add apiextensions to scheme: %v", err) + } + + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithInterceptorFuncs(establishedInterceptor()). + Build() + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + ctx = log.IntoContext(ctx, log.FromContext(context.Background())) + + err := Install(ctx, fakeClient, newCRDManifestWriter(testCRD1, testCRD2)) + if err != nil { + t.Fatalf("Install() error = %v", err) + } +} + +func TestInstall_noManifests(t *testing.T) { + log.SetLogger(zap.New(zap.UseDevMode(true))) + + scheme := runtime.NewScheme() + fakeClient := fake.NewClientBuilder().WithScheme(scheme).Build() + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + ctx = log.IntoContext(ctx, log.FromContext(context.Background())) + + err := Install(ctx, fakeClient, func(string) error { return nil }) + if err == nil { + t.Error("Install() expected error for empty manifests, got nil") + } + if !strings.Contains(err.Error(), "no YAML manifest files found") { + t.Errorf("Install() error = %v, want error containing 'no YAML manifest files found'", err) + } +} + +func TestInstall_writeManifestsFails(t *testing.T) { + log.SetLogger(zap.New(zap.UseDevMode(true))) + + scheme := runtime.NewScheme() + fakeClient := fake.NewClientBuilder().WithScheme(scheme).Build() + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + ctx = log.IntoContext(ctx, log.FromContext(context.Background())) + + err := Install(ctx, fakeClient, func(string) error { return os.ErrPermission }) + if err == nil { + t.Error("Install() expected error when writeManifests fails, got nil") + } +} + +func TestInstall_rejectsNonCRDObjects(t *testing.T) { + log.SetLogger(zap.New(zap.UseDevMode(true))) + + scheme := runtime.NewScheme() + if err := apiextensionsv1.AddToScheme(scheme); err != nil { + t.Fatalf("failed to add apiextensions to scheme: %v", err) + } + + fakeClient := fake.NewClientBuilder().WithScheme(scheme).Build() + + nonCRD := `apiVersion: v1 +kind: Namespace +metadata: + name: should-not-be-applied +` + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + ctx = log.IntoContext(ctx, log.FromContext(context.Background())) + + err := Install(ctx, fakeClient, newCRDManifestWriter(nonCRD)) + if err == nil { + t.Fatal("Install() expected error for non-CRD object, got nil") + } + if !strings.Contains(err.Error(), "unexpected object") { + t.Errorf("Install() error = %v, want error containing 'unexpected object'", err) + } +} + +func TestInstall_crdNotEstablished(t *testing.T) { + log.SetLogger(zap.New(zap.UseDevMode(true))) + + scheme := runtime.NewScheme() + if err := apiextensionsv1.AddToScheme(scheme); err != nil { + t.Fatalf("failed to add apiextensions to scheme: %v", err) + } + + // No interceptor: CRDs will never get Established condition + fakeClient := fake.NewClientBuilder().WithScheme(scheme).Build() + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + ctx = log.IntoContext(ctx, log.FromContext(context.Background())) + + err := Install(ctx, fakeClient, newCRDManifestWriter(testCRD1)) + if err == nil { + t.Fatal("Install() expected error when CRDs never become established, got nil") + } + if !strings.Contains(err.Error(), "CRDs not established") { + t.Errorf("Install() error = %v, want error containing 'CRDs not established'", err) + } +} diff --git a/internal/crdinstall/manifests.embed.go b/internal/crdinstall/manifests.embed.go new file mode 100644 index 00000000..7464e54e --- /dev/null +++ b/internal/crdinstall/manifests.embed.go @@ -0,0 +1,51 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package crdinstall + +import ( + "embed" + "fmt" + "io/fs" + "os" + "path" + "path/filepath" +) + +//go:embed manifests/*.yaml +var embeddedCRDManifests embed.FS + +// WriteEmbeddedManifests extracts embedded CRD manifests to a directory. +func WriteEmbeddedManifests(dir string) error { + manifests, err := fs.ReadDir(embeddedCRDManifests, "manifests") + if err != nil { + return fmt.Errorf("failed to read embedded manifests: %w", err) + } + + for _, manifest := range manifests { + data, err := fs.ReadFile(embeddedCRDManifests, path.Join("manifests", manifest.Name())) + if err != nil { + return fmt.Errorf("failed to read file %s: %w", manifest.Name(), err) + } + + outputPath := filepath.Join(dir, manifest.Name()) + if err := os.WriteFile(outputPath, data, 0600); err != nil { + return fmt.Errorf("failed to write file %s: %w", outputPath, err) + } + } + + return nil +} diff --git a/internal/crdinstall/manifests/.gitattributes b/internal/crdinstall/manifests/.gitattributes new file mode 100644 index 00000000..f581feca --- /dev/null +++ b/internal/crdinstall/manifests/.gitattributes @@ -0,0 +1 @@ +*.yaml linguist-generated diff --git a/internal/crdinstall/manifests/cozystack.io_packages.yaml b/internal/crdinstall/manifests/cozystack.io_packages.yaml new file mode 100644 index 00000000..cb7e2763 --- /dev/null +++ b/internal/crdinstall/manifests/cozystack.io_packages.yaml @@ -0,0 +1,171 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: packages.cozystack.io +spec: + group: cozystack.io + names: + kind: Package + listKind: PackageList + plural: packages + shortNames: + - pkg + - pkgs + singular: package + scope: Cluster + versions: + - additionalPrinterColumns: + - description: Selected variant + jsonPath: .spec.variant + name: Variant + type: string + - description: Ready status + jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - description: Ready message + jsonPath: .status.conditions[?(@.type=='Ready')].message + name: Status + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Package is the Schema for the packages API + 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: PackageSpec defines the desired state of Package + properties: + components: + additionalProperties: + description: PackageComponent defines overrides for a specific component + properties: + enabled: + description: |- + Enabled indicates whether this component should be installed + If false, the component will be disabled even if it's defined in the PackageSource + type: boolean + values: + description: |- + Values contains Helm chart values as a JSON object + These values will be merged with the default values from the PackageSource + x-kubernetes-preserve-unknown-fields: true + type: object + description: |- + Components is a map of release name to component overrides + Allows overriding values and enabling/disabling specific components from the PackageSource + type: object + ignoreDependencies: + description: |- + IgnoreDependencies is a list of package source dependencies to ignore + Dependencies listed here will not be installed even if they are specified in the PackageSource + items: + type: string + type: array + variant: + description: |- + Variant is the name of the variant to use from the PackageSource + If not specified, defaults to "default" + type: string + type: object + status: + description: PackageStatus defines the observed state of Package + properties: + conditions: + description: Conditions represents the latest available observations + of a Package's state + 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 + type: array + dependencies: + additionalProperties: + description: DependencyStatus represents the readiness status of + a dependency + properties: + ready: + description: Ready indicates whether the dependency is ready + type: boolean + required: + - ready + type: object + description: |- + Dependencies tracks the readiness status of each dependency + Key is the dependency package name, value indicates if the dependency is ready + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/internal/crdinstall/manifests/cozystack.io_packagesources.yaml b/internal/crdinstall/manifests/cozystack.io_packagesources.yaml new file mode 100644 index 00000000..1d0037df --- /dev/null +++ b/internal/crdinstall/manifests/cozystack.io_packagesources.yaml @@ -0,0 +1,263 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: packagesources.cozystack.io +spec: + group: cozystack.io + names: + kind: PackageSource + listKind: PackageSourceList + plural: packagesources + shortNames: + - pks + singular: packagesource + scope: Cluster + versions: + - additionalPrinterColumns: + - description: Package variants (comma-separated) + jsonPath: .status.variants + name: Variants + type: string + - description: Ready status + jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - description: Ready message + jsonPath: .status.conditions[?(@.type=='Ready')].message + name: Status + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: PackageSource is the Schema for the packagesources API + 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: PackageSourceSpec defines the desired state of PackageSource + properties: + sourceRef: + description: SourceRef is the source reference for the package source + charts + properties: + kind: + description: Kind of the source reference + enum: + - GitRepository + - OCIRepository + type: string + name: + description: Name of the source reference + type: string + namespace: + description: Namespace of the source reference + type: string + path: + description: |- + Path is the base path where packages are located in the source. + For GitRepository, defaults to "packages" if not specified. + For OCIRepository, defaults to empty string (root) if not specified. + type: string + required: + - kind + - name + - namespace + type: object + variants: + description: |- + Variants is a list of package source variants + Each variant defines components, applications, dependencies, and libraries for a specific configuration + items: + description: Variant defines a single variant configuration + properties: + components: + description: Components is a list of Helm releases to be installed + as part of this variant + items: + description: Component defines a single Helm release component + within a package source + properties: + install: + description: Install defines installation parameters for + this component + properties: + dependsOn: + description: DependsOn is a list of component names + that must be installed before this component + items: + type: string + type: array + namespace: + description: Namespace is the Kubernetes namespace + where the release will be installed + type: string + privileged: + description: Privileged indicates whether this release + requires privileged access + type: boolean + releaseName: + description: |- + ReleaseName is the name of the HelmRelease resource that will be created + If not specified, defaults to the component Name field + type: string + upgradeCRDs: + description: |- + UpgradeCRDs controls how CRDs from the chart's crds/ directory are + handled on HelmRelease upgrades. Maps to HelmRelease.Spec.Upgrade.CRDs. + Empty string (default) preserves the helm-controller default (Skip). + Use "CreateReplace" for operators that evolve their CRD set between + versions. Warning: CreateReplace overwrites CRDs and may cause data + loss if upstream drops fields from a CRD with live objects. + enum: + - Skip + - Create + - CreateReplace + type: string + type: object + libraries: + description: |- + Libraries is a list of library names that this component depends on + These libraries must be defined at the variant level + items: + type: string + type: array + name: + description: Name is the unique identifier for this component + within the package source + type: string + path: + description: Path is the path to the Helm chart directory + type: string + valuesFiles: + description: ValuesFiles is a list of values file names + to use + items: + type: string + type: array + required: + - name + - path + type: object + type: array + dependsOn: + description: |- + DependsOn is a list of package source dependencies + For example: "cozystack.networking" + items: + type: string + type: array + libraries: + description: Libraries is a list of Helm library charts used + by components in this variant + items: + description: Library defines a Helm library chart + properties: + name: + description: Name is the optional name for library placed + in charts + type: string + path: + description: Path is the path to the library chart directory + type: string + required: + - path + type: object + type: array + name: + description: Name is the unique identifier for this variant + type: string + required: + - name + type: object + type: array + type: object + status: + description: PackageSourceStatus defines the observed state of PackageSource + properties: + conditions: + description: Conditions represents the latest available observations + of a PackageSource's state + 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 + type: array + variants: + description: |- + Variants is a comma-separated list of package variant names + This field is populated by the controller based on spec.variants keys + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/internal/fluxinstall/install.go b/internal/fluxinstall/install.go new file mode 100644 index 00000000..4ae6f4cb --- /dev/null +++ b/internal/fluxinstall/install.go @@ -0,0 +1,337 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fluxinstall + +import ( + "context" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/cozystack/cozystack/internal/manifestutil" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +// Install installs Flux components using embedded manifests. +// It extracts the manifests and applies them to the cluster. +// The namespace is automatically determined from the Namespace object in the manifests. +func Install(ctx context.Context, k8sClient client.Client, writeEmbeddedManifests func(string) error) error { + logger := log.FromContext(ctx) + + // Create temporary directory for manifests + tmpDir, err := os.MkdirTemp("", "flux-install-*") + if err != nil { + return fmt.Errorf("failed to create temp directory: %w", err) + } + defer os.RemoveAll(tmpDir) + + // Extract embedded manifests (generated by cozypkg) + manifestsDir := filepath.Join(tmpDir, "manifests") + if err := os.MkdirAll(manifestsDir, 0755); err != nil { + return fmt.Errorf("failed to create manifests directory: %w", err) + } + + if err := writeEmbeddedManifests(manifestsDir); err != nil { + return fmt.Errorf("failed to extract embedded manifests: %w", err) + } + + // Find all YAML manifest files + entries, err := os.ReadDir(manifestsDir) + if err != nil { + return fmt.Errorf("failed to read manifests directory: %w", err) + } + + var manifestFiles []string + for _, entry := range entries { + if strings.HasSuffix(entry.Name(), ".yaml") { + manifestFiles = append(manifestFiles, filepath.Join(manifestsDir, entry.Name())) + } + } + + if len(manifestFiles) == 0 { + return fmt.Errorf("no YAML manifest files found in directory") + } + + // Parse all manifest files + var objects []*unstructured.Unstructured + for _, manifestPath := range manifestFiles { + objs, err := manifestutil.ParseManifestFile(manifestPath) + if err != nil { + return fmt.Errorf("failed to parse manifests from %s: %w", manifestPath, err) + } + objects = append(objects, objs...) + } + + if len(objects) == 0 { + return fmt.Errorf("no objects found in manifests") + } + + // Inject KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT if set in operator environment + if err := injectKubernetesServiceEnv(objects); err != nil { + logger.Info("Failed to inject KUBERNETES_SERVICE_* env vars, continuing anyway", "error", err) + } + + // Extract namespace from Namespace object in manifests + namespace, err := extractNamespace(objects) + if err != nil { + return fmt.Errorf("failed to extract namespace from manifests: %w", err) + } + + logger.Info("Installing Flux components", "namespace", namespace) + + // Apply manifests using server-side apply + logger.Info("Applying Flux manifests", "count", len(objects), "files", len(manifestFiles), "namespace", namespace) + if err := applyManifests(ctx, k8sClient, objects); err != nil { + return fmt.Errorf("failed to apply manifests: %w", err) + } + + logger.Info("Flux installation completed successfully") + return nil +} + +// applyManifests applies Kubernetes objects using server-side apply. +func applyManifests(ctx context.Context, k8sClient client.Client, objects []*unstructured.Unstructured) error { + logger := log.FromContext(ctx) + + // Separate CRDs and namespaces from other resources + var stageOne []*unstructured.Unstructured // CRDs and Namespaces + var stageTwo []*unstructured.Unstructured // Everything else + + for _, obj := range objects { + if isClusterDefinition(obj) { + stageOne = append(stageOne, obj) + } else { + stageTwo = append(stageTwo, obj) + } + } + + // Apply stage one (CRDs and Namespaces) first + if len(stageOne) > 0 { + logger.Info("Applying cluster definitions", "count", len(stageOne)) + if err := applyObjects(ctx, k8sClient, stageOne); err != nil { + return fmt.Errorf("failed to apply cluster definitions: %w", err) + } + + // Wait for CRDs to be established before applying dependent resources + crdNames := manifestutil.CollectCRDNames(stageOne) + if err := manifestutil.WaitForCRDsEstablished(ctx, k8sClient, crdNames); err != nil { + return fmt.Errorf("CRDs not established after apply: %w", err) + } + } + + // Apply stage two (everything else) + if len(stageTwo) > 0 { + logger.Info("Applying resources", "count", len(stageTwo)) + if err := applyObjects(ctx, k8sClient, stageTwo); err != nil { + return fmt.Errorf("failed to apply resources: %w", err) + } + } + + return nil +} + +// applyObjects applies a list of objects using server-side apply. +func applyObjects(ctx context.Context, k8sClient client.Client, objects []*unstructured.Unstructured) error { + for _, obj := range objects { + // Use server-side apply with force ownership and field manager + // FieldManager is required for apply patch operations + patchOptions := &client.PatchOptions{ + FieldManager: "cozystack-operator", + Force: func() *bool { b := true; return &b }(), + } + + if err := k8sClient.Patch(ctx, obj, client.Apply, patchOptions); err != nil { + return fmt.Errorf("failed to apply object %s/%s: %w", obj.GetKind(), obj.GetName(), err) + } + } + return nil +} + +// extractNamespace extracts the namespace name from the Namespace object in the manifests. +func extractNamespace(objects []*unstructured.Unstructured) (string, error) { + for _, obj := range objects { + if obj.GetKind() == "Namespace" { + namespace := obj.GetName() + if namespace == "" { + return "", fmt.Errorf("Namespace object has no name") + } + return namespace, nil + } + } + return "", fmt.Errorf("no Namespace object found in manifests") +} + +// isClusterDefinition checks if an object is a CRD or Namespace. +func isClusterDefinition(obj *unstructured.Unstructured) bool { + kind := obj.GetKind() + return kind == "CustomResourceDefinition" || kind == "Namespace" +} + +// injectKubernetesServiceEnv injects KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT +// environment variables into all containers of Deployment, StatefulSet, and DaemonSet objects +// if these variables are set in the operator's environment. +// Errors are logged but do not stop processing of other objects. +func injectKubernetesServiceEnv(objects []*unstructured.Unstructured) error { + kubernetesHost := os.Getenv("KUBERNETES_SERVICE_HOST") + kubernetesPort := os.Getenv("KUBERNETES_SERVICE_PORT") + + // If neither variable is set, nothing to do + if kubernetesHost == "" && kubernetesPort == "" { + return nil + } + + var firstErr error + for _, obj := range objects { + kind := obj.GetKind() + if kind != "Deployment" && kind != "StatefulSet" && kind != "DaemonSet" { + continue + } + + // Navigate to spec.template.spec + spec, found, err := unstructured.NestedMap(obj.Object, "spec", "template", "spec") + if !found { + continue + } + + // Skip pods that don't use hostNetwork - they should use normal Kubernetes DNS + hostNetwork, _, _ := unstructured.NestedBool(spec, "hostNetwork") + if !hostNetwork { + continue + } + if err != nil { + if firstErr == nil { + firstErr = fmt.Errorf("failed to get spec for %s/%s: %w", kind, obj.GetName(), err) + } + continue + } + + // Update containers + containers, found, err := unstructured.NestedSlice(spec, "containers") + if err != nil { + if firstErr == nil { + firstErr = fmt.Errorf("failed to get containers for %s/%s: %w", kind, obj.GetName(), err) + } + continue + } + if found { + containers = updateContainersEnv(containers, kubernetesHost, kubernetesPort) + if err := unstructured.SetNestedSlice(spec, containers, "containers"); err != nil { + if firstErr == nil { + firstErr = fmt.Errorf("failed to set containers for %s/%s: %w", kind, obj.GetName(), err) + } + continue + } + } + + // Update initContainers + initContainers, found, err := unstructured.NestedSlice(spec, "initContainers") + if err != nil { + if firstErr == nil { + firstErr = fmt.Errorf("failed to get initContainers for %s/%s: %w", kind, obj.GetName(), err) + } + continue + } + if found { + initContainers = updateContainersEnv(initContainers, kubernetesHost, kubernetesPort) + if err := unstructured.SetNestedSlice(spec, initContainers, "initContainers"); err != nil { + if firstErr == nil { + firstErr = fmt.Errorf("failed to set initContainers for %s/%s: %w", kind, obj.GetName(), err) + } + continue + } + } + + // Update spec in the object + if err := unstructured.SetNestedMap(obj.Object, spec, "spec", "template", "spec"); err != nil { + if firstErr == nil { + firstErr = fmt.Errorf("failed to update spec for %s/%s: %w", kind, obj.GetName(), err) + } + continue + } + } + + return firstErr +} + +// updateContainersEnv updates environment variables for a slice of containers. +func updateContainersEnv(containers []interface{}, kubernetesHost, kubernetesPort string) []interface{} { + for i, container := range containers { + containerMap, ok := container.(map[string]interface{}) + if !ok { + continue + } + + env, found, err := unstructured.NestedSlice(containerMap, "env") + if err != nil { + continue + } + + if !found { + env = []interface{}{} + } + + // Update or add KUBERNETES_SERVICE_HOST + if kubernetesHost != "" { + env = setEnvVar(env, "KUBERNETES_SERVICE_HOST", kubernetesHost) + } + + // Update or add KUBERNETES_SERVICE_PORT + if kubernetesPort != "" { + env = setEnvVar(env, "KUBERNETES_SERVICE_PORT", kubernetesPort) + } + + // Update the container's env + if err := unstructured.SetNestedSlice(containerMap, env, "env"); err != nil { + continue + } + + // Update the container in the slice + containers[i] = containerMap + } + + return containers +} + +// setEnvVar updates or adds an environment variable in the env slice. +func setEnvVar(env []interface{}, name, value string) []interface{} { + // Check if variable already exists + for i, envVar := range env { + envVarMap, ok := envVar.(map[string]interface{}) + if !ok { + continue + } + + if envVarMap["name"] == name { + // Update existing variable + envVarMap["value"] = value + env[i] = envVarMap + return env + } + } + + // Add new variable + env = append(env, map[string]interface{}{ + "name": name, + "value": value, + }) + + return env +} diff --git a/internal/fluxinstall/manifests.embed.go b/internal/fluxinstall/manifests.embed.go new file mode 100644 index 00000000..6ff48d2d --- /dev/null +++ b/internal/fluxinstall/manifests.embed.go @@ -0,0 +1,52 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fluxinstall + +import ( + "embed" + "fmt" + "io/fs" + "os" + "path" + "path/filepath" +) + +//go:embed manifests/*.yaml +var embeddedFluxManifests embed.FS + +// WriteEmbeddedManifests extracts embedded Flux manifests to a temporary directory. +func WriteEmbeddedManifests(dir string) error { + manifests, err := fs.ReadDir(embeddedFluxManifests, "manifests") + if err != nil { + return fmt.Errorf("failed to read embedded manifests: %w", err) + } + + for _, manifest := range manifests { + data, err := fs.ReadFile(embeddedFluxManifests, path.Join("manifests", manifest.Name())) + if err != nil { + return fmt.Errorf("failed to read file %s: %w", manifest.Name(), err) + } + + outputPath := filepath.Join(dir, manifest.Name()) + if err := os.WriteFile(outputPath, data, 0600); err != nil { + return fmt.Errorf("failed to write file %s: %w", outputPath, err) + } + } + + return nil +} + diff --git a/internal/fluxinstall/manifests/fluxcd-service.yaml b/internal/fluxinstall/manifests/fluxcd-service.yaml new file mode 100644 index 00000000..87feaec4 --- /dev/null +++ b/internal/fluxinstall/manifests/fluxcd-service.yaml @@ -0,0 +1,18 @@ +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + name: flux + namespace: cozy-fluxcd +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: http-sc + selector: + app.kubernetes.io/name: flux + type: ClusterIP diff --git a/internal/fluxinstall/manifests/fluxcd-tenants.yaml b/internal/fluxinstall/manifests/fluxcd-tenants.yaml new file mode 100644 index 00000000..077cf34c --- /dev/null +++ b/internal/fluxinstall/manifests/fluxcd-tenants.yaml @@ -0,0 +1,102 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: flux-tenants + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + sharding.fluxcd.io/role: shard + name: flux-tenants + namespace: cozy-fluxcd +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: flux-tenants + strategy: + type: Recreate + template: + metadata: + annotations: + cluster-autoscaler.kubernetes.io/safe-to-evict: "true" + prometheus.io/scrape: "true" + labels: + app.kubernetes.io/name: flux-tenants + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/os + operator: In + values: + - linux + containers: + - args: + - --watch-all-namespaces + - --log-level=info + - --log-encoding=json + - --enable-leader-election=false + - --metrics-addr=:9795 + - --health-addr=:9796 + - --watch-label-selector=sharding.fluxcd.io/key=tenants + - --concurrent=5 + - --requeue-dependency=30s + - --feature-gates=ExternalArtifact=true + env: + - name: RUNTIME_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + resource: limits.memory + - name: TUF_ROOT + value: /tmp/.sigstore + image: "ghcr.io/fluxcd/helm-controller:v1.4.3" + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /healthz + port: healthz + name: helm-controller + ports: + - containerPort: 9795 + name: http-prom + protocol: TCP + - containerPort: 9796 + name: healthz + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: healthz + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + volumeMounts: + - mountPath: /tmp + name: tmp + priorityClassName: system-cluster-critical + securityContext: + fsGroup: 1337 + serviceAccountName: flux + terminationGracePeriodSeconds: 60 + volumes: + - emptyDir: {} + name: tmp diff --git a/internal/fluxinstall/manifests/fluxcd.yaml b/internal/fluxinstall/manifests/fluxcd.yaml new file mode 100644 index 00000000..803f52bb --- /dev/null +++ b/internal/fluxinstall/manifests/fluxcd.yaml @@ -0,0 +1,11953 @@ +--- +# Instance: flux +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: alerts.notification.toolkit.fluxcd.io +spec: + group: notification.toolkit.fluxcd.io + names: + kind: Alert + listKind: AlertList + plural: alerts + singular: alert + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 Alert is deprecated, upgrade to v1beta3 + name: v1beta2 + schema: + openAPIV3Schema: + description: Alert is the Schema for the alerts API + 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: AlertSpec defines an alerting rule for events involving a list of objects. + properties: + eventMetadata: + additionalProperties: + type: string + description: |- + EventMetadata is an optional field for adding metadata to events dispatched by the + controller. This can be used for enhancing the context of the event. If a field + would override one already present on the original event as generated by the emitter, + then the override doesn't happen, i.e. the original value is preserved, and an info + log is printed. + type: object + eventSeverity: + default: info + description: |- + EventSeverity specifies how to filter events based on severity. + If set to 'info' no events will be filtered. + enum: + - info + - error + type: string + eventSources: + description: |- + EventSources specifies how to filter events based + on the involved object kind, name and namespace. + items: + description: |- + CrossNamespaceObjectReference contains enough information to let you locate the + typed referenced object at cluster level + properties: + apiVersion: + description: API version of the referent + type: string + kind: + description: Kind of the referent + enum: + - Bucket + - GitRepository + - Kustomization + - HelmRelease + - HelmChart + - HelmRepository + - ImageRepository + - ImagePolicy + - ImageUpdateAutomation + - OCIRepository + type: string + 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. + MatchLabels requires the name to be set to `*`. + type: object + name: + description: |- + Name of the referent + If multiple resources are targeted `*` may be set. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace of the referent + maxLength: 253 + minLength: 1 + type: string + required: + - kind + - name + type: object + type: array + exclusionList: + description: |- + ExclusionList specifies a list of Golang regular expressions + to be used for excluding messages. + items: + type: string + type: array + inclusionList: + description: |- + InclusionList specifies a list of Golang regular expressions + to be used for including messages. + items: + type: string + type: array + providerRef: + description: ProviderRef specifies which Provider this Alert should use. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + summary: + description: Summary holds a short description of the impact and affected cluster. + maxLength: 255 + type: string + suspend: + description: |- + Suspend tells the controller to suspend subsequent + events handling for this Alert. + type: boolean + required: + - eventSources + - providerRef + type: object + status: + default: + observedGeneration: -1 + description: AlertStatus defines the observed state of the Alert. + properties: + conditions: + description: Conditions holds the conditions for the Alert. + 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 + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta3 + schema: + openAPIV3Schema: + description: Alert is the Schema for the alerts API + 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: AlertSpec defines an alerting rule for events involving a list of objects. + properties: + eventMetadata: + additionalProperties: + type: string + description: |- + EventMetadata is an optional field for adding metadata to events dispatched by the + controller. This can be used for enhancing the context of the event. If a field + would override one already present on the original event as generated by the emitter, + then the override doesn't happen, i.e. the original value is preserved, and an info + log is printed. + type: object + eventSeverity: + default: info + description: |- + EventSeverity specifies how to filter events based on severity. + If set to 'info' no events will be filtered. + enum: + - info + - error + type: string + eventSources: + description: |- + EventSources specifies how to filter events based + on the involved object kind, name and namespace. + items: + description: |- + CrossNamespaceObjectReference contains enough information to let you locate the + typed referenced object at cluster level + properties: + apiVersion: + description: API version of the referent + type: string + kind: + description: Kind of the referent + enum: + - Bucket + - GitRepository + - Kustomization + - HelmRelease + - HelmChart + - HelmRepository + - ImageRepository + - ImagePolicy + - ImageUpdateAutomation + - OCIRepository + type: string + 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. + MatchLabels requires the name to be set to `*`. + type: object + name: + description: |- + Name of the referent + If multiple resources are targeted `*` may be set. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace of the referent + maxLength: 253 + minLength: 1 + type: string + required: + - kind + - name + type: object + type: array + exclusionList: + description: |- + ExclusionList specifies a list of Golang regular expressions + to be used for excluding messages. + items: + type: string + type: array + inclusionList: + description: |- + InclusionList specifies a list of Golang regular expressions + to be used for including messages. + items: + type: string + type: array + providerRef: + description: ProviderRef specifies which Provider this Alert should use. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + summary: + description: |- + Summary holds a short description of the impact and affected cluster. + Deprecated: Use EventMetadata instead. + maxLength: 255 + type: string + suspend: + description: |- + Suspend tells the controller to suspend subsequent + events handling for this Alert. + type: boolean + required: + - eventSources + - providerRef + type: object + type: object + served: true + storage: true + subresources: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: artifactgenerators.source.extensions.fluxcd.io +spec: + group: source.extensions.fluxcd.io + names: + kind: ArtifactGenerator + listKind: ArtifactGeneratorList + plural: artifactgenerators + shortNames: + - ag + singular: artifactgenerator + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: ArtifactGenerator is the Schema for the artifactgenerators API. + 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: ArtifactGeneratorSpec defines the desired state of ArtifactGenerator. + properties: + artifacts: + description: OutputArtifacts is a list of output artifacts to be generated. + items: + description: |- + OutputArtifact defines the desired state of an ExternalArtifact + generated by the ArtifactGenerator. + properties: + copy: + description: |- + Copy defines a list of copy operations to perform from the sources to the generated artifact. + The copy operations are performed in the order they are listed with existing files + being overwritten by later copy operations. + items: + properties: + exclude: + description: |- + Exclude specifies a list of glob patterns to exclude + files and dirs matched by the 'From' field. + items: + type: string + maxItems: 100 + type: array + from: + description: |- + From specifies the source (by alias) and the glob pattern to match files. + The format is "@/". + maxLength: 1024 + pattern: ^@([a-z0-9]([a-z0-9_-]*[a-z0-9])?)/(.*)$ + type: string + strategy: + description: |- + Strategy specifies the copy strategy to use. + 'Overwrite' will overwrite existing files in the destination. + 'Merge' is for merging YAML files using Helm values merge strategy. + If not specified, defaults to 'Overwrite'. + enum: + - Overwrite + - Merge + type: string + to: + description: |- + To specifies the destination path within the artifact. + The format is "@artifact/path", the alias "artifact" + refers to the root path of the generated artifact. + maxLength: 1024 + pattern: ^@(artifact)/(.*)$ + type: string + required: + - from + - to + type: object + minItems: 1 + type: array + name: + description: Name is the name of the generated artifact. + maxLength: 253 + pattern: ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$ + type: string + originRevision: + description: |- + OriginRevision is used to set the 'org.opencontainers.image.revision' + annotation on the generated artifact metadata. + If specified, it must point to an existing source alias in the format "@". + If the referenced source has an origin revision (e.g. a Git commit SHA), + it will be used to set the annotation on the generated artifact. + If the referenced source does not have an origin revision, the field is ignored. + maxLength: 64 + pattern: ^@([a-z0-9]([a-z0-9_-]*[a-z0-9])?)$ + type: string + revision: + description: |- + Revision is the revision of the generated artifact. + If specified, it must point to an existing source alias in the format "@". + If not specified, the revision is automatically set to the digest of the artifact content. + maxLength: 64 + pattern: ^@([a-z0-9]([a-z0-9_-]*[a-z0-9])?)$ + type: string + required: + - copy + - name + type: object + maxItems: 1000 + minItems: 1 + type: array + sources: + description: |- + Sources is a list of references to the Flux source-controller + resources that will be used to generate the artifact. + items: + description: SourceReference contains the reference to a Flux source-controller resource. + properties: + alias: + description: |- + Alias of the source within the ArtifactGenerator context. + The alias must be unique per ArtifactGenerator, and must consist + of lower case alphanumeric characters, underscores, and hyphens. + It must start and end with an alphanumeric character. + maxLength: 63 + pattern: ^[a-z0-9]([a-z0-9_-]*[a-z0-9])?$ + type: string + kind: + description: Kind of the source. + enum: + - Bucket + - GitRepository + - OCIRepository + type: string + name: + description: Name of the source. + maxLength: 253 + pattern: ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$ + type: string + namespace: + description: |- + Namespace of the source. + If not provided, defaults to the same namespace as the ArtifactGenerator. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - alias + - kind + - name + type: object + maxItems: 1000 + minItems: 1 + type: array + required: + - artifacts + - sources + type: object + status: + description: ArtifactGeneratorStatus defines the observed state of ArtifactGenerator. + properties: + conditions: + description: Conditions holds the conditions for the ArtifactGenerator. + 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 + type: array + inventory: + description: Inventory contains the list of generated ExternalArtifact references. + items: + description: |- + ExternalArtifactReference contains the reference to a + generated ExternalArtifact along with its digest. + properties: + digest: + description: Digest of the referent artifact. + type: string + filename: + description: Filename is the name of the artifact file. + type: string + name: + description: Name of the referent artifact. + type: string + namespace: + description: Namespace of the referent artifact. + type: string + required: + - digest + - filename + - name + - namespace + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedSourcesDigest: + description: |- + ObservedSourcesDigest is a hash representing the current state of + all the sources referenced by the ArtifactGenerator. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: buckets.source.toolkit.fluxcd.io +spec: + group: source.toolkit.fluxcd.io + names: + kind: Bucket + listKind: BucketList + plural: buckets + singular: bucket + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.endpoint + name: Endpoint + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + description: Bucket is the Schema for the buckets API. + 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: |- + BucketSpec specifies the required configuration to produce an Artifact for + an object storage bucket. + properties: + bucketName: + description: BucketName is the name of the object storage bucket. + type: string + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + bucket. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + This field is only supported for the `generic` provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + endpoint: + description: Endpoint is the object storage address the BucketName is located at. + type: string + ignore: + description: |- + Ignore overrides the set of excluded patterns in the .sourceignore format + (which is the same as .gitignore). If not provided, a default will be used, + consult the documentation for your version to find out what those are. + type: string + insecure: + description: Insecure allows connecting to a non-TLS HTTP Endpoint. + type: boolean + interval: + description: |- + Interval at which the Bucket Endpoint is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + prefix: + description: Prefix to use for server-side filtering of files in the Bucket. + type: string + provider: + default: generic + description: |- + Provider of the object storage bucket. + Defaults to 'generic', which expects an S3 (API) compatible object + storage. + enum: + - generic + - aws + - gcp + - azure + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the Bucket server. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + region: + description: Region of the Endpoint where the BucketName is located in. + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials + for the Bucket. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + the bucket. This field is only supported for the 'gcp' and 'aws' providers. + For more information about workload identity: + https://fluxcd.io/flux/components/source/buckets/#workload-identity + type: string + sts: + description: |- + STS specifies the required configuration to use a Security Token + Service for fetching temporary credentials to authenticate in a + Bucket provider. + + This field is only supported for the `aws` and `generic` providers. + properties: + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + STS endpoint. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + This field is only supported for the `ldap` provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + endpoint: + description: |- + Endpoint is the HTTP/S endpoint of the Security Token Service from + where temporary credentials will be fetched. + pattern: ^(http|https)://.*$ + type: string + provider: + description: Provider of the Security Token Service. + enum: + - aws + - ldap + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials + for the STS endpoint. This Secret must contain the fields `username` + and `password` and is supported only for the `ldap` provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - endpoint + - provider + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + Bucket. + type: boolean + timeout: + default: 60s + description: Timeout for fetch operations, defaults to 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + required: + - bucketName + - endpoint + - interval + type: object + x-kubernetes-validations: + - message: STS configuration is only supported for the 'aws' and 'generic' Bucket providers + rule: self.provider == 'aws' || self.provider == 'generic' || !has(self.sts) + - message: '''aws'' is the only supported STS provider for the ''aws'' Bucket provider' + rule: self.provider != 'aws' || !has(self.sts) || self.sts.provider == 'aws' + - message: '''ldap'' is the only supported STS provider for the ''generic'' Bucket provider' + rule: self.provider != 'generic' || !has(self.sts) || self.sts.provider == 'ldap' + - message: spec.sts.secretRef is not required for the 'aws' STS provider + rule: '!has(self.sts) || self.sts.provider != ''aws'' || !has(self.sts.secretRef)' + - message: spec.sts.certSecretRef is not required for the 'aws' STS provider + rule: '!has(self.sts) || self.sts.provider != ''aws'' || !has(self.sts.certSecretRef)' + - message: ServiceAccountName is not supported for the 'generic' Bucket provider + rule: self.provider != 'generic' || !has(self.serviceAccountName) + - message: cannot set both .spec.secretRef and .spec.serviceAccountName + rule: '!has(self.secretRef) || !has(self.serviceAccountName)' + status: + default: + observedGeneration: -1 + description: BucketStatus records the observed state of a Bucket. + properties: + artifact: + description: Artifact represents the last successful Bucket reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the Bucket. + 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 + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation of the Bucket object. + format: int64 + type: integer + observedIgnore: + description: |- + ObservedIgnore is the observed exclusion patterns used for constructing + the source artifact. + type: string + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + BucketStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.endpoint + name: Endpoint + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 Bucket is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: Bucket is the Schema for the buckets API. + 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: |- + BucketSpec specifies the required configuration to produce an Artifact for + an object storage bucket. + properties: + accessFrom: + description: |- + AccessFrom specifies an Access Control List for allowing cross-namespace + references to this object. + NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + 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 + type: array + required: + - namespaceSelectors + type: object + bucketName: + description: BucketName is the name of the object storage bucket. + type: string + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + bucket. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + This field is only supported for the `generic` provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + endpoint: + description: Endpoint is the object storage address the BucketName is located at. + type: string + ignore: + description: |- + Ignore overrides the set of excluded patterns in the .sourceignore format + (which is the same as .gitignore). If not provided, a default will be used, + consult the documentation for your version to find out what those are. + type: string + insecure: + description: Insecure allows connecting to a non-TLS HTTP Endpoint. + type: boolean + interval: + description: |- + Interval at which the Bucket Endpoint is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + prefix: + description: Prefix to use for server-side filtering of files in the Bucket. + type: string + provider: + default: generic + description: |- + Provider of the object storage bucket. + Defaults to 'generic', which expects an S3 (API) compatible object + storage. + enum: + - generic + - aws + - gcp + - azure + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the Bucket server. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + region: + description: Region of the Endpoint where the BucketName is located in. + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials + for the Bucket. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + sts: + description: |- + STS specifies the required configuration to use a Security Token + Service for fetching temporary credentials to authenticate in a + Bucket provider. + + This field is only supported for the `aws` and `generic` providers. + properties: + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + STS endpoint. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + This field is only supported for the `ldap` provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + endpoint: + description: |- + Endpoint is the HTTP/S endpoint of the Security Token Service from + where temporary credentials will be fetched. + pattern: ^(http|https)://.*$ + type: string + provider: + description: Provider of the Security Token Service. + enum: + - aws + - ldap + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials + for the STS endpoint. This Secret must contain the fields `username` + and `password` and is supported only for the `ldap` provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - endpoint + - provider + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + Bucket. + type: boolean + timeout: + default: 60s + description: Timeout for fetch operations, defaults to 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + required: + - bucketName + - endpoint + - interval + type: object + x-kubernetes-validations: + - message: STS configuration is only supported for the 'aws' and 'generic' Bucket providers + rule: self.provider == 'aws' || self.provider == 'generic' || !has(self.sts) + - message: '''aws'' is the only supported STS provider for the ''aws'' Bucket provider' + rule: self.provider != 'aws' || !has(self.sts) || self.sts.provider == 'aws' + - message: '''ldap'' is the only supported STS provider for the ''generic'' Bucket provider' + rule: self.provider != 'generic' || !has(self.sts) || self.sts.provider == 'ldap' + - message: spec.sts.secretRef is not required for the 'aws' STS provider + rule: '!has(self.sts) || self.sts.provider != ''aws'' || !has(self.sts.secretRef)' + - message: spec.sts.certSecretRef is not required for the 'aws' STS provider + rule: '!has(self.sts) || self.sts.provider != ''aws'' || !has(self.sts.certSecretRef)' + status: + default: + observedGeneration: -1 + description: BucketStatus records the observed state of a Bucket. + properties: + artifact: + description: Artifact represents the last successful Bucket reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the Bucket. + 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 + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation of the Bucket object. + format: int64 + type: integer + observedIgnore: + description: |- + ObservedIgnore is the observed exclusion patterns used for constructing + the source artifact. + type: string + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + BucketStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: externalartifacts.source.toolkit.fluxcd.io +spec: + group: source.toolkit.fluxcd.io + names: + kind: ExternalArtifact + listKind: ExternalArtifactList + plural: externalartifacts + singular: externalartifact + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .spec.sourceRef.name + name: Source + type: string + name: v1 + schema: + openAPIV3Schema: + description: ExternalArtifact is the Schema for the external artifacts API + 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: ExternalArtifactSpec defines the desired state of ExternalArtifact + properties: + sourceRef: + description: |- + SourceRef points to the Kubernetes custom resource for + which the artifact is generated. + properties: + apiVersion: + description: API version of the referent, if not specified the Kubernetes preferred version will be used. + type: string + kind: + description: Kind of the referent. + type: string + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it acts as LocalObjectReference. + type: string + required: + - kind + - name + type: object + type: object + status: + description: ExternalArtifactStatus defines the observed state of ExternalArtifact + properties: + artifact: + description: Artifact represents the output of an ExternalArtifact reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the ExternalArtifact. + 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 + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: gitrepositories.source.toolkit.fluxcd.io +spec: + group: source.toolkit.fluxcd.io + names: + kind: GitRepository + listKind: GitRepositoryList + plural: gitrepositories + shortNames: + - gitrepo + singular: gitrepository + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.url + name: URL + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + description: GitRepository is the Schema for the gitrepositories API. + 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: |- + GitRepositorySpec specifies the required configuration to produce an + Artifact for a Git repository. + properties: + ignore: + description: |- + Ignore overrides the set of excluded patterns in the .sourceignore format + (which is the same as .gitignore). If not provided, a default will be used, + consult the documentation for your version to find out what those are. + type: string + include: + description: |- + Include specifies a list of GitRepository resources which Artifacts + should be included in the Artifact produced for this GitRepository. + items: + description: |- + GitRepositoryInclude specifies a local reference to a GitRepository which + Artifact (sub-)contents must be included, and where they should be placed. + properties: + fromPath: + description: |- + FromPath specifies the path to copy contents from, defaults to the root + of the Artifact. + type: string + repository: + description: |- + GitRepositoryRef specifies the GitRepository which Artifact contents + must be included. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + toPath: + description: |- + ToPath specifies the path to copy contents to, defaults to the name of + the GitRepositoryRef. + type: string + required: + - repository + type: object + type: array + interval: + description: |- + Interval at which the GitRepository URL is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + provider: + description: |- + Provider used for authentication, can be 'azure', 'github', 'generic'. + When not specified, defaults to 'generic'. + enum: + - generic + - azure + - github + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the Git server. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + recurseSubmodules: + description: |- + RecurseSubmodules enables the initialization of all submodules within + the GitRepository as cloned from the URL, using their default settings. + type: boolean + ref: + description: |- + Reference specifies the Git reference to resolve and monitor for + changes, defaults to the 'master' branch. + properties: + branch: + description: Branch to check out, defaults to 'master' if no other field is defined. + type: string + commit: + description: |- + Commit SHA to check out, takes precedence over all reference fields. + + This can be combined with Branch to shallow clone the branch, in which + the commit is expected to exist. + type: string + name: + description: |- + Name of the reference to check out; takes precedence over Branch, Tag and SemVer. + + It must be a valid Git reference: https://git-scm.com/docs/git-check-ref-format#_description + Examples: "refs/heads/main", "refs/tags/v0.1.0", "refs/pull/420/head", "refs/merge-requests/1/head" + type: string + semver: + description: SemVer tag expression to check out, takes precedence over Tag. + type: string + tag: + description: Tag to check out, takes precedence over Branch. + type: string + type: object + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials for + the GitRepository. + For HTTPS repositories the Secret must contain 'username' and 'password' + fields for basic auth or 'bearerToken' field for token auth. + For SSH repositories the Secret must contain 'identity' + and 'known_hosts' fields. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to + authenticate to the GitRepository. This field is only supported for 'azure' provider. + type: string + sparseCheckout: + description: |- + SparseCheckout specifies a list of directories to checkout when cloning + the repository. If specified, only these directories are included in the + Artifact produced for this GitRepository. + items: + type: string + type: array + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + GitRepository. + type: boolean + timeout: + default: 60s + description: Timeout for Git operations like cloning, defaults to 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + url: + description: URL specifies the Git repository URL, it can be an HTTP/S or SSH address. + pattern: ^(http|https|ssh)://.*$ + type: string + verify: + description: |- + Verification specifies the configuration to verify the Git commit + signature(s). + properties: + mode: + default: HEAD + description: |- + Mode specifies which Git object(s) should be verified. + + The variants "head" and "HEAD" both imply the same thing, i.e. verify + the commit that the HEAD of the Git repository points to. The variant + "head" solely exists to ensure backwards compatibility. + enum: + - head + - HEAD + - Tag + - TagAndHEAD + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing the public keys of trusted Git + authors. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - secretRef + type: object + required: + - interval + - url + type: object + x-kubernetes-validations: + - message: serviceAccountName can only be set when provider is 'azure' + rule: '!has(self.serviceAccountName) || (has(self.provider) && self.provider == ''azure'')' + status: + default: + observedGeneration: -1 + description: GitRepositoryStatus records the observed state of a Git repository. + properties: + artifact: + description: Artifact represents the last successful GitRepository reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the GitRepository. + 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 + type: array + includedArtifacts: + description: |- + IncludedArtifacts contains a list of the last successfully included + Artifacts as instructed by GitRepositorySpec.Include. + items: + description: Artifact represents the output of a Source reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: |- + ObservedGeneration is the last observed generation of the GitRepository + object. + format: int64 + type: integer + observedIgnore: + description: |- + ObservedIgnore is the observed exclusion patterns used for constructing + the source artifact. + type: string + observedInclude: + description: |- + ObservedInclude is the observed list of GitRepository resources used to + produce the current Artifact. + items: + description: |- + GitRepositoryInclude specifies a local reference to a GitRepository which + Artifact (sub-)contents must be included, and where they should be placed. + properties: + fromPath: + description: |- + FromPath specifies the path to copy contents from, defaults to the root + of the Artifact. + type: string + repository: + description: |- + GitRepositoryRef specifies the GitRepository which Artifact contents + must be included. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + toPath: + description: |- + ToPath specifies the path to copy contents to, defaults to the name of + the GitRepositoryRef. + type: string + required: + - repository + type: object + type: array + observedRecurseSubmodules: + description: |- + ObservedRecurseSubmodules is the observed resource submodules + configuration used to produce the current Artifact. + type: boolean + observedSparseCheckout: + description: |- + ObservedSparseCheckout is the observed list of directories used to + produce the current Artifact. + items: + type: string + type: array + sourceVerificationMode: + description: |- + SourceVerificationMode is the last used verification mode indicating + which Git object(s) have been verified. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.url + name: URL + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 GitRepository is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: GitRepository is the Schema for the gitrepositories API. + 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: |- + GitRepositorySpec specifies the required configuration to produce an + Artifact for a Git repository. + properties: + accessFrom: + description: |- + AccessFrom specifies an Access Control List for allowing cross-namespace + references to this object. + NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + 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 + type: array + required: + - namespaceSelectors + type: object + gitImplementation: + default: go-git + description: |- + GitImplementation specifies which Git client library implementation to + use. Defaults to 'go-git', valid values are ('go-git', 'libgit2'). + Deprecated: gitImplementation is deprecated now that 'go-git' is the + only supported implementation. + enum: + - go-git + - libgit2 + type: string + ignore: + description: |- + Ignore overrides the set of excluded patterns in the .sourceignore format + (which is the same as .gitignore). If not provided, a default will be used, + consult the documentation for your version to find out what those are. + type: string + include: + description: |- + Include specifies a list of GitRepository resources which Artifacts + should be included in the Artifact produced for this GitRepository. + items: + description: |- + GitRepositoryInclude specifies a local reference to a GitRepository which + Artifact (sub-)contents must be included, and where they should be placed. + properties: + fromPath: + description: |- + FromPath specifies the path to copy contents from, defaults to the root + of the Artifact. + type: string + repository: + description: |- + GitRepositoryRef specifies the GitRepository which Artifact contents + must be included. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + toPath: + description: |- + ToPath specifies the path to copy contents to, defaults to the name of + the GitRepositoryRef. + type: string + required: + - repository + type: object + type: array + interval: + description: Interval at which to check the GitRepository for updates. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + recurseSubmodules: + description: |- + RecurseSubmodules enables the initialization of all submodules within + the GitRepository as cloned from the URL, using their default settings. + type: boolean + ref: + description: |- + Reference specifies the Git reference to resolve and monitor for + changes, defaults to the 'master' branch. + properties: + branch: + description: Branch to check out, defaults to 'master' if no other field is defined. + type: string + commit: + description: |- + Commit SHA to check out, takes precedence over all reference fields. + + This can be combined with Branch to shallow clone the branch, in which + the commit is expected to exist. + type: string + name: + description: |- + Name of the reference to check out; takes precedence over Branch, Tag and SemVer. + + It must be a valid Git reference: https://git-scm.com/docs/git-check-ref-format#_description + Examples: "refs/heads/main", "refs/tags/v0.1.0", "refs/pull/420/head", "refs/merge-requests/1/head" + type: string + semver: + description: SemVer tag expression to check out, takes precedence over Tag. + type: string + tag: + description: Tag to check out, takes precedence over Branch. + type: string + type: object + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials for + the GitRepository. + For HTTPS repositories the Secret must contain 'username' and 'password' + fields for basic auth or 'bearerToken' field for token auth. + For SSH repositories the Secret must contain 'identity' + and 'known_hosts' fields. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + GitRepository. + type: boolean + timeout: + default: 60s + description: Timeout for Git operations like cloning, defaults to 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + url: + description: URL specifies the Git repository URL, it can be an HTTP/S or SSH address. + pattern: ^(http|https|ssh)://.*$ + type: string + verify: + description: |- + Verification specifies the configuration to verify the Git commit + signature(s). + properties: + mode: + description: Mode specifies what Git object should be verified, currently ('head'). + enum: + - head + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing the public keys of trusted Git + authors. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - mode + - secretRef + type: object + required: + - interval + - url + type: object + status: + default: + observedGeneration: -1 + description: GitRepositoryStatus records the observed state of a Git repository. + properties: + artifact: + description: Artifact represents the last successful GitRepository reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the GitRepository. + 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 + type: array + contentConfigChecksum: + description: |- + ContentConfigChecksum is a checksum of all the configurations related to + the content of the source artifact: + - .spec.ignore + - .spec.recurseSubmodules + - .spec.included and the checksum of the included artifacts + observed in .status.observedGeneration version of the object. This can + be used to determine if the content of the included repository has + changed. + It has the format of `:`, for example: `sha256:`. + + Deprecated: Replaced with explicit fields for observed artifact content + config in the status. + type: string + includedArtifacts: + description: |- + IncludedArtifacts contains a list of the last successfully included + Artifacts as instructed by GitRepositorySpec.Include. + items: + description: Artifact represents the output of a Source reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: |- + ObservedGeneration is the last observed generation of the GitRepository + object. + format: int64 + type: integer + observedIgnore: + description: |- + ObservedIgnore is the observed exclusion patterns used for constructing + the source artifact. + type: string + observedInclude: + description: |- + ObservedInclude is the observed list of GitRepository resources used to + to produce the current Artifact. + items: + description: |- + GitRepositoryInclude specifies a local reference to a GitRepository which + Artifact (sub-)contents must be included, and where they should be placed. + properties: + fromPath: + description: |- + FromPath specifies the path to copy contents from, defaults to the root + of the Artifact. + type: string + repository: + description: |- + GitRepositoryRef specifies the GitRepository which Artifact contents + must be included. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + toPath: + description: |- + ToPath specifies the path to copy contents to, defaults to the name of + the GitRepositoryRef. + type: string + required: + - repository + type: object + type: array + observedRecurseSubmodules: + description: |- + ObservedRecurseSubmodules is the observed resource submodules + configuration used to produce the current Artifact. + type: boolean + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + GitRepositoryStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: helmcharts.source.toolkit.fluxcd.io +spec: + group: source.toolkit.fluxcd.io + names: + kind: HelmChart + listKind: HelmChartList + plural: helmcharts + shortNames: + - hc + singular: helmchart + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.chart + name: Chart + type: string + - jsonPath: .spec.version + name: Version + type: string + - jsonPath: .spec.sourceRef.kind + name: Source Kind + type: string + - jsonPath: .spec.sourceRef.name + name: Source Name + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + description: HelmChart is the Schema for the helmcharts API. + 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: HelmChartSpec specifies the desired state of a Helm chart. + properties: + chart: + description: |- + Chart is the name or path the Helm chart is available at in the + SourceRef. + type: string + ignoreMissingValuesFiles: + description: |- + IgnoreMissingValuesFiles controls whether to silently ignore missing values + files rather than failing. + type: boolean + interval: + description: |- + Interval at which the HelmChart SourceRef is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + reconcileStrategy: + default: ChartVersion + description: |- + ReconcileStrategy determines what enables the creation of a new artifact. + Valid values are ('ChartVersion', 'Revision'). + See the documentation of the values for an explanation on their behavior. + Defaults to ChartVersion when omitted. + enum: + - ChartVersion + - Revision + type: string + sourceRef: + description: SourceRef is the reference to the Source the chart is available at. + properties: + apiVersion: + description: APIVersion of the referent. + type: string + kind: + description: |- + Kind of the referent, valid values are ('HelmRepository', 'GitRepository', + 'Bucket'). + enum: + - HelmRepository + - GitRepository + - Bucket + type: string + name: + description: Name of the referent. + type: string + required: + - kind + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + source. + type: boolean + valuesFiles: + description: |- + ValuesFiles is an alternative list of values files to use as the chart + values (values.yaml is not included by default), expected to be a + relative path in the SourceRef. + Values files are merged in the order of this list with the last file + overriding the first. Ignored when omitted. + items: + type: string + type: array + verify: + description: |- + Verify contains the secret name containing the trusted public keys + used to verify the signature and specifies which provider to use to check + whether OCI image is authentic. + This field is only supported when using HelmRepository source with spec.type 'oci'. + Chart dependencies, which are not bundled in the umbrella chart artifact, are not verified. + properties: + matchOIDCIdentity: + description: |- + MatchOIDCIdentity specifies the identity matching criteria to use + while verifying an OCI artifact which was signed using Cosign keyless + signing. The artifact's identity is deemed to be verified if any of the + specified matchers match against the identity. + items: + description: |- + OIDCIdentityMatch specifies options for verifying the certificate identity, + i.e. the issuer and the subject of the certificate. + properties: + issuer: + description: |- + Issuer specifies the regex pattern to match against to verify + the OIDC issuer in the Fulcio certificate. The pattern must be a + valid Go regular expression. + type: string + subject: + description: |- + Subject specifies the regex pattern to match against to verify + the identity subject in the Fulcio certificate. The pattern must + be a valid Go regular expression. + type: string + required: + - issuer + - subject + type: object + type: array + provider: + default: cosign + description: Provider specifies the technology used to sign the OCI Artifact. + enum: + - cosign + - notation + type: string + secretRef: + description: |- + SecretRef specifies the Kubernetes Secret containing the + trusted public keys. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + version: + default: '*' + description: |- + Version is the chart version semver expression, ignored for charts from + GitRepository and Bucket sources. Defaults to latest when omitted. + type: string + required: + - chart + - interval + - sourceRef + type: object + status: + default: + observedGeneration: -1 + description: HelmChartStatus records the observed state of the HelmChart. + properties: + artifact: + description: Artifact represents the output of the last successful reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the HelmChart. + 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 + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedChartName: + description: |- + ObservedChartName is the last observed chart name as specified by the + resolved chart reference. + type: string + observedGeneration: + description: |- + ObservedGeneration is the last observed generation of the HelmChart + object. + format: int64 + type: integer + observedSourceArtifactRevision: + description: |- + ObservedSourceArtifactRevision is the last observed Artifact.Revision + of the HelmChartSpec.SourceRef. + type: string + observedValuesFiles: + description: |- + ObservedValuesFiles are the observed value files of the last successful + reconciliation. + It matches the chart in the last successfully reconciled artifact. + items: + type: string + type: array + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + BucketStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.chart + name: Chart + type: string + - jsonPath: .spec.version + name: Version + type: string + - jsonPath: .spec.sourceRef.kind + name: Source Kind + type: string + - jsonPath: .spec.sourceRef.name + name: Source Name + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 HelmChart is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: HelmChart is the Schema for the helmcharts API. + 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: HelmChartSpec specifies the desired state of a Helm chart. + properties: + accessFrom: + description: |- + AccessFrom specifies an Access Control List for allowing cross-namespace + references to this object. + NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + 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 + type: array + required: + - namespaceSelectors + type: object + chart: + description: |- + Chart is the name or path the Helm chart is available at in the + SourceRef. + type: string + ignoreMissingValuesFiles: + description: |- + IgnoreMissingValuesFiles controls whether to silently ignore missing values + files rather than failing. + type: boolean + interval: + description: |- + Interval at which the HelmChart SourceRef is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + reconcileStrategy: + default: ChartVersion + description: |- + ReconcileStrategy determines what enables the creation of a new artifact. + Valid values are ('ChartVersion', 'Revision'). + See the documentation of the values for an explanation on their behavior. + Defaults to ChartVersion when omitted. + enum: + - ChartVersion + - Revision + type: string + sourceRef: + description: SourceRef is the reference to the Source the chart is available at. + properties: + apiVersion: + description: APIVersion of the referent. + type: string + kind: + description: |- + Kind of the referent, valid values are ('HelmRepository', 'GitRepository', + 'Bucket'). + enum: + - HelmRepository + - GitRepository + - Bucket + type: string + name: + description: Name of the referent. + type: string + required: + - kind + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + source. + type: boolean + valuesFile: + description: |- + ValuesFile is an alternative values file to use as the default chart + values, expected to be a relative path in the SourceRef. Deprecated in + favor of ValuesFiles, for backwards compatibility the file specified here + is merged before the ValuesFiles items. Ignored when omitted. + type: string + valuesFiles: + description: |- + ValuesFiles is an alternative list of values files to use as the chart + values (values.yaml is not included by default), expected to be a + relative path in the SourceRef. + Values files are merged in the order of this list with the last file + overriding the first. Ignored when omitted. + items: + type: string + type: array + verify: + description: |- + Verify contains the secret name containing the trusted public keys + used to verify the signature and specifies which provider to use to check + whether OCI image is authentic. + This field is only supported when using HelmRepository source with spec.type 'oci'. + Chart dependencies, which are not bundled in the umbrella chart artifact, are not verified. + properties: + matchOIDCIdentity: + description: |- + MatchOIDCIdentity specifies the identity matching criteria to use + while verifying an OCI artifact which was signed using Cosign keyless + signing. The artifact's identity is deemed to be verified if any of the + specified matchers match against the identity. + items: + description: |- + OIDCIdentityMatch specifies options for verifying the certificate identity, + i.e. the issuer and the subject of the certificate. + properties: + issuer: + description: |- + Issuer specifies the regex pattern to match against to verify + the OIDC issuer in the Fulcio certificate. The pattern must be a + valid Go regular expression. + type: string + subject: + description: |- + Subject specifies the regex pattern to match against to verify + the identity subject in the Fulcio certificate. The pattern must + be a valid Go regular expression. + type: string + required: + - issuer + - subject + type: object + type: array + provider: + default: cosign + description: Provider specifies the technology used to sign the OCI Artifact. + enum: + - cosign + - notation + type: string + secretRef: + description: |- + SecretRef specifies the Kubernetes Secret containing the + trusted public keys. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + version: + default: '*' + description: |- + Version is the chart version semver expression, ignored for charts from + GitRepository and Bucket sources. Defaults to latest when omitted. + type: string + required: + - chart + - interval + - sourceRef + type: object + status: + default: + observedGeneration: -1 + description: HelmChartStatus records the observed state of the HelmChart. + properties: + artifact: + description: Artifact represents the output of the last successful reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the HelmChart. + 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 + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedChartName: + description: |- + ObservedChartName is the last observed chart name as specified by the + resolved chart reference. + type: string + observedGeneration: + description: |- + ObservedGeneration is the last observed generation of the HelmChart + object. + format: int64 + type: integer + observedSourceArtifactRevision: + description: |- + ObservedSourceArtifactRevision is the last observed Artifact.Revision + of the HelmChartSpec.SourceRef. + type: string + observedValuesFiles: + description: |- + ObservedValuesFiles are the observed value files of the last successful + reconciliation. + It matches the chart in the last successfully reconciled artifact. + items: + type: string + type: array + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + BucketStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: helmreleases.helm.toolkit.fluxcd.io +spec: + group: helm.toolkit.fluxcd.io + names: + kind: HelmRelease + listKind: HelmReleaseList + plural: helmreleases + shortNames: + - hr + singular: helmrelease + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v2 + schema: + openAPIV3Schema: + description: HelmRelease is the Schema for the helmreleases API + 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: HelmReleaseSpec defines the desired state of a Helm release. + properties: + chart: + description: |- + Chart defines the template of the v1.HelmChart that should be created + for this HelmRelease. + properties: + metadata: + description: ObjectMeta holds the template for metadata like labels and annotations. + properties: + annotations: + additionalProperties: + type: string + description: |- + Annotations is an unstructured key value map stored with a resource that may be + set by external tools to store and retrieve arbitrary metadata. They are not + queryable and should be preserved when modifying objects. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + type: object + labels: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to organize and categorize + (scope and select) objects. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + type: object + type: object + spec: + description: Spec holds the template for the v1.HelmChartSpec for this HelmRelease. + properties: + chart: + description: The name or path the Helm chart is available at in the SourceRef. + maxLength: 2048 + minLength: 1 + type: string + ignoreMissingValuesFiles: + description: IgnoreMissingValuesFiles controls whether to silently ignore missing values files rather than failing. + type: boolean + interval: + description: |- + Interval at which to check the v1.Source for updates. Defaults to + 'HelmReleaseSpec.Interval'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + reconcileStrategy: + default: ChartVersion + description: |- + Determines what enables the creation of a new artifact. Valid values are + ('ChartVersion', 'Revision'). + See the documentation of the values for an explanation on their behavior. + Defaults to ChartVersion when omitted. + enum: + - ChartVersion + - Revision + type: string + sourceRef: + description: The name and namespace of the v1.Source the chart is available at. + properties: + apiVersion: + description: APIVersion of the referent. + type: string + kind: + description: Kind of the referent. + enum: + - HelmRepository + - GitRepository + - Bucket + type: string + name: + description: Name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace of the referent. + maxLength: 63 + minLength: 1 + type: string + required: + - kind + - name + type: object + valuesFiles: + description: |- + Alternative list of values files to use as the chart values (values.yaml + is not included by default), expected to be a relative path in the SourceRef. + Values files are merged in the order of this list with the last file overriding + the first. Ignored when omitted. + items: + type: string + type: array + verify: + description: |- + Verify contains the secret name containing the trusted public keys + used to verify the signature and specifies which provider to use to check + whether OCI image is authentic. + This field is only supported for OCI sources. + Chart dependencies, which are not bundled in the umbrella chart artifact, + are not verified. + properties: + provider: + default: cosign + description: Provider specifies the technology used to sign the OCI Helm chart. + enum: + - cosign + - notation + type: string + secretRef: + description: |- + SecretRef specifies the Kubernetes Secret containing the + trusted public keys. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + version: + default: '*' + description: |- + Version semver expression, ignored for charts from v1.GitRepository and + v1beta2.Bucket sources. Defaults to latest when omitted. + type: string + required: + - chart + - sourceRef + type: object + required: + - spec + type: object + chartRef: + description: |- + ChartRef holds a reference to a source controller resource containing the + Helm chart artifact. + properties: + apiVersion: + description: APIVersion of the referent. + type: string + kind: + description: Kind of the referent. + enum: + - OCIRepository + - HelmChart + - ExternalArtifact + type: string + name: + description: Name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace of the referent, defaults to the namespace of the Kubernetes + resource object that contains the reference. + maxLength: 63 + minLength: 1 + type: string + required: + - kind + - name + type: object + commonMetadata: + description: |- + CommonMetadata specifies the common labels and annotations that are + applied to all resources. Any existing label or annotation will be + overridden if its key matches a common one. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to the object's metadata. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to the object's metadata. + type: object + type: object + dependsOn: + description: |- + DependsOn may contain a DependencyReference slice with + references to HelmRelease resources that must be ready before this HelmRelease + can be reconciled. + items: + description: DependencyReference defines a HelmRelease dependency on another HelmRelease resource. + properties: + name: + description: Name of the referent. + type: string + namespace: + description: |- + Namespace of the referent, defaults to the namespace of the HelmRelease + resource object that contains the reference. + type: string + readyExpr: + description: |- + ReadyExpr is a CEL expression that can be used to assess the readiness + of a dependency. When specified, the built-in readiness check + is replaced by the logic defined in the CEL expression. + To make the CEL expression additive to the built-in readiness check, + the feature gate `AdditiveCELDependencyCheck` must be set to `true`. + type: string + required: + - name + type: object + type: array + driftDetection: + description: |- + DriftDetection holds the configuration for detecting and handling + differences between the manifest in the Helm storage and the resources + currently existing in the cluster. + properties: + ignore: + description: |- + Ignore contains a list of rules for specifying which changes to ignore + during diffing. + items: + description: |- + IgnoreRule defines a rule to selectively disregard specific changes during + the drift detection process. + properties: + paths: + description: |- + Paths is a list of JSON Pointer (RFC 6901) paths to be excluded from + consideration in a Kubernetes object. + items: + type: string + type: array + target: + description: |- + Target is a selector for specifying Kubernetes objects to which this + rule applies. + If Target is not set, the Paths will be ignored for all Kubernetes + objects within the manifest of the Helm release. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - paths + type: object + type: array + mode: + description: |- + Mode defines how differences should be handled between the Helm manifest + and the manifest currently applied to the cluster. + If not explicitly set, it defaults to DiffModeDisabled. + enum: + - enabled + - warn + - disabled + type: string + type: object + install: + description: Install holds the configuration for Helm install actions for this HelmRelease. + properties: + crds: + description: |- + CRDs upgrade CRDs from the Helm Chart's crds directory according + to the CRD upgrade policy provided here. Valid values are `Skip`, + `Create` or `CreateReplace`. Default is `Create` and if omitted + CRDs are installed but not updated. + + Skip: do neither install nor replace (update) any CRDs. + + Create: new CRDs are created, existing CRDs are neither updated nor deleted. + + CreateReplace: new CRDs are created, existing CRDs are updated (replaced) + but not deleted. + + By default, CRDs are applied (installed) during Helm install action. + With this option users can opt in to CRD replace existing CRDs on Helm + install actions, which is not (yet) natively supported by Helm. + https://helm.sh/docs/chart_best_practices/custom_resource_definitions. + enum: + - Skip + - Create + - CreateReplace + type: string + createNamespace: + description: |- + CreateNamespace tells the Helm install action to create the + HelmReleaseSpec.TargetNamespace if it does not exist yet. + On uninstall, the namespace will not be garbage collected. + type: boolean + disableHooks: + description: DisableHooks prevents hooks from running during the Helm install action. + type: boolean + disableOpenAPIValidation: + description: |- + DisableOpenAPIValidation prevents the Helm install action from validating + rendered templates against the Kubernetes OpenAPI Schema. + type: boolean + disableSchemaValidation: + description: |- + DisableSchemaValidation prevents the Helm install action from validating + the values against the JSON Schema. + type: boolean + disableTakeOwnership: + description: |- + DisableTakeOwnership disables taking ownership of existing resources + during the Helm install action. Defaults to false. + type: boolean + disableWait: + description: |- + DisableWait disables the waiting for resources to be ready after a Helm + install has been performed. + type: boolean + disableWaitForJobs: + description: |- + DisableWaitForJobs disables waiting for jobs to complete after a Helm + install has been performed. + type: boolean + remediation: + description: |- + Remediation holds the remediation configuration for when the Helm install + action for the HelmRelease fails. The default is to not perform any action. + properties: + ignoreTestFailures: + description: |- + IgnoreTestFailures tells the controller to skip remediation when the Helm + tests are run after an install action but fail. Defaults to + 'Test.IgnoreFailures'. + type: boolean + remediateLastFailure: + description: |- + RemediateLastFailure tells the controller to remediate the last failure, when + no retries remain. Defaults to 'false'. + type: boolean + retries: + description: |- + Retries is the number of retries that should be attempted on failures before + bailing. Remediation, using an uninstall, is performed between each attempt. + Defaults to '0', a negative integer equals to unlimited retries. + type: integer + type: object + replace: + description: |- + Replace tells the Helm install action to re-use the 'ReleaseName', but only + if that name is a deleted release which remains in the history. + type: boolean + skipCRDs: + description: |- + SkipCRDs tells the Helm install action to not install any CRDs. By default, + CRDs are installed if not already present. + + Deprecated use CRD policy (`crds`) attribute with value `Skip` instead. + type: boolean + strategy: + description: |- + Strategy defines the install strategy to use for this HelmRelease. + Defaults to 'RemediateOnFailure'. + properties: + name: + description: Name of the install strategy. + enum: + - RemediateOnFailure + - RetryOnFailure + type: string + retryInterval: + description: |- + RetryInterval is the interval at which to retry a failed install. + Can be used only when Name is set to RetryOnFailure. + Defaults to '5m'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + required: + - name + type: object + x-kubernetes-validations: + - message: .retryInterval cannot be set when .name is 'RemediateOnFailure' + rule: '!has(self.retryInterval) || self.name != ''RemediateOnFailure''' + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm install action. Defaults to + 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + interval: + description: Interval at which to reconcile the Helm release. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + kubeConfig: + description: |- + KubeConfig for reconciling the HelmRelease on a remote cluster. + When used in combination with HelmReleaseSpec.ServiceAccountName, + forces the controller to act on behalf of that Service Account at the + target cluster. + If the --default-service-account flag is set, its value will be used as + a controller level fallback for when HelmReleaseSpec.ServiceAccountName + is empty. + properties: + configMapRef: + description: |- + ConfigMapRef holds an optional name of a ConfigMap that contains + the following keys: + + - `provider`: the provider to use. One of `aws`, `azure`, `gcp`, or + `generic`. Required. + - `cluster`: the fully qualified resource name of the Kubernetes + cluster in the cloud provider API. Not used by the `generic` + provider. Required when one of `address` or `ca.crt` is not set. + - `address`: the address of the Kubernetes API server. Required + for `generic`. For the other providers, if not specified, the + first address in the cluster resource will be used, and if + specified, it must match one of the addresses in the cluster + resource. + If audiences is not set, will be used as the audience for the + `generic` provider. + - `ca.crt`: the optional PEM-encoded CA certificate for the + Kubernetes API server. If not set, the controller will use the + CA certificate from the cluster resource. + - `audiences`: the optional audiences as a list of + line-break-separated strings for the Kubernetes ServiceAccount + token. Defaults to the `address` for the `generic` provider, or + to specific values for the other providers depending on the + provider. + - `serviceAccountName`: the optional name of the Kubernetes + ServiceAccount in the same namespace that should be used + for authentication. If not specified, the controller + ServiceAccount will be used. + + Mutually exclusive with SecretRef. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + secretRef: + description: |- + SecretRef holds an optional name of a secret that contains a key with + the kubeconfig file as the value. If no key is set, the key will default + to 'value'. Mutually exclusive with ConfigMapRef. + It is recommended that the kubeconfig is self-contained, and the secret + is regularly updated if credentials such as a cloud-access-token expire. + Cloud specific `cmd-path` auth helpers will not function without adding + binaries and credentials to the Pod that is responsible for reconciling + Kubernetes resources. Supported only for the generic provider. + properties: + key: + description: Key in the Secret, when not specified an implementation-specific default key is used. + type: string + name: + description: Name of the Secret. + type: string + required: + - name + type: object + type: object + x-kubernetes-validations: + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: has(self.configMapRef) || has(self.secretRef) + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: '!has(self.configMapRef) || !has(self.secretRef)' + maxHistory: + description: |- + MaxHistory is the number of revisions saved by Helm for this HelmRelease. + Use '0' for an unlimited number of revisions; defaults to '5'. + type: integer + persistentClient: + description: |- + PersistentClient tells the controller to use a persistent Kubernetes + client for this release. When enabled, the client will be reused for the + duration of the reconciliation, instead of being created and destroyed + for each (step of a) Helm action. + + This can improve performance, but may cause issues with some Helm charts + that for example do create Custom Resource Definitions during installation + outside Helm's CRD lifecycle hooks, which are then not observed to be + available by e.g. post-install hooks. + + If not set, it defaults to true. + type: boolean + postRenderers: + description: |- + PostRenderers holds an array of Helm PostRenderers, which will be applied in order + of their definition. + items: + description: PostRenderer contains a Helm PostRenderer specification. + properties: + kustomize: + description: Kustomization to apply as PostRenderer. + properties: + images: + description: |- + Images is a list of (image name, new name, new tag or digest) + for changing image names, tags or digests. This can also be achieved with a + patch, but this operator is simpler to specify. + items: + description: Image contains an image name, a new name, a new tag or digest, which will replace the original name and tag. + properties: + digest: + description: |- + Digest is the value used to replace the original image tag. + If digest is present NewTag value is ignored. + type: string + name: + description: Name is a tag-less image name. + type: string + newName: + description: NewName is the value used to replace the original name. + type: string + newTag: + description: NewTag is the value used to replace the original tag. + type: string + required: + - name + type: object + type: array + patches: + description: |- + Strategic merge and JSON patches, defined as inline YAML objects, + capable of targeting objects based on kind, label and annotation selectors. + items: + description: |- + Patch contains an inline StrategicMerge or JSON6902 patch, and the target the patch should + be applied to. + properties: + patch: + description: |- + Patch contains an inline StrategicMerge patch or an inline JSON6902 patch with + an array of operation objects. + type: string + target: + description: Target points to the resources that the patch document should be applied to. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - patch + type: object + type: array + type: object + type: object + type: array + releaseName: + description: |- + ReleaseName used for the Helm release. Defaults to a composition of + '[TargetNamespace-]Name'. + maxLength: 53 + minLength: 1 + type: string + rollback: + description: Rollback holds the configuration for Helm rollback actions for this HelmRelease. + properties: + cleanupOnFail: + description: |- + CleanupOnFail allows deletion of new resources created during the Helm + rollback action when it fails. + type: boolean + disableHooks: + description: DisableHooks prevents hooks from running during the Helm rollback action. + type: boolean + disableWait: + description: |- + DisableWait disables the waiting for resources to be ready after a Helm + rollback has been performed. + type: boolean + disableWaitForJobs: + description: |- + DisableWaitForJobs disables waiting for jobs to complete after a Helm + rollback has been performed. + type: boolean + force: + description: Force forces resource updates through a replacement strategy. + type: boolean + recreate: + description: Recreate performs pod restarts for the resource if applicable. + type: boolean + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm rollback action. Defaults to + 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + serviceAccountName: + description: |- + The name of the Kubernetes service account to impersonate + when reconciling this HelmRelease. + maxLength: 253 + minLength: 1 + type: string + storageNamespace: + description: |- + StorageNamespace used for the Helm storage. + Defaults to the namespace of the HelmRelease. + maxLength: 63 + minLength: 1 + type: string + suspend: + description: |- + Suspend tells the controller to suspend reconciliation for this HelmRelease, + it does not apply to already started reconciliations. Defaults to false. + type: boolean + targetNamespace: + description: |- + TargetNamespace to target when performing operations for the HelmRelease. + Defaults to the namespace of the HelmRelease. + maxLength: 63 + minLength: 1 + type: string + test: + description: Test holds the configuration for Helm test actions for this HelmRelease. + properties: + enable: + description: |- + Enable enables Helm test actions for this HelmRelease after an Helm install + or upgrade action has been performed. + type: boolean + filters: + description: Filters is a list of tests to run or exclude from running. + items: + description: Filter holds the configuration for individual Helm test filters. + properties: + exclude: + description: Exclude specifies whether the named test should be excluded. + type: boolean + name: + description: Name is the name of the test. + maxLength: 253 + minLength: 1 + type: string + required: + - name + type: object + type: array + ignoreFailures: + description: |- + IgnoreFailures tells the controller to skip remediation when the Helm tests + are run but fail. Can be overwritten for tests run after install or upgrade + actions in 'Install.IgnoreTestFailures' and 'Upgrade.IgnoreTestFailures'. + type: boolean + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation during + the performance of a Helm test action. Defaults to 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like Jobs + for hooks) during the performance of a Helm action. Defaults to '5m0s'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + uninstall: + description: Uninstall holds the configuration for Helm uninstall actions for this HelmRelease. + properties: + deletionPropagation: + default: background + description: |- + DeletionPropagation specifies the deletion propagation policy when + a Helm uninstall is performed. + enum: + - background + - foreground + - orphan + type: string + disableHooks: + description: DisableHooks prevents hooks from running during the Helm rollback action. + type: boolean + disableWait: + description: |- + DisableWait disables waiting for all the resources to be deleted after + a Helm uninstall is performed. + type: boolean + keepHistory: + description: |- + KeepHistory tells Helm to remove all associated resources and mark the + release as deleted, but retain the release history. + type: boolean + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm uninstall action. Defaults + to 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + upgrade: + description: Upgrade holds the configuration for Helm upgrade actions for this HelmRelease. + properties: + cleanupOnFail: + description: |- + CleanupOnFail allows deletion of new resources created during the Helm + upgrade action when it fails. + type: boolean + crds: + description: |- + CRDs upgrade CRDs from the Helm Chart's crds directory according + to the CRD upgrade policy provided here. Valid values are `Skip`, + `Create` or `CreateReplace`. Default is `Skip` and if omitted + CRDs are neither installed nor upgraded. + + Skip: do neither install nor replace (update) any CRDs. + + Create: new CRDs are created, existing CRDs are neither updated nor deleted. + + CreateReplace: new CRDs are created, existing CRDs are updated (replaced) + but not deleted. + + By default, CRDs are not applied during Helm upgrade action. With this + option users can opt-in to CRD upgrade, which is not (yet) natively supported by Helm. + https://helm.sh/docs/chart_best_practices/custom_resource_definitions. + enum: + - Skip + - Create + - CreateReplace + type: string + disableHooks: + description: DisableHooks prevents hooks from running during the Helm upgrade action. + type: boolean + disableOpenAPIValidation: + description: |- + DisableOpenAPIValidation prevents the Helm upgrade action from validating + rendered templates against the Kubernetes OpenAPI Schema. + type: boolean + disableSchemaValidation: + description: |- + DisableSchemaValidation prevents the Helm upgrade action from validating + the values against the JSON Schema. + type: boolean + disableTakeOwnership: + description: |- + DisableTakeOwnership disables taking ownership of existing resources + during the Helm upgrade action. Defaults to false. + type: boolean + disableWait: + description: |- + DisableWait disables the waiting for resources to be ready after a Helm + upgrade has been performed. + type: boolean + disableWaitForJobs: + description: |- + DisableWaitForJobs disables waiting for jobs to complete after a Helm + upgrade has been performed. + type: boolean + force: + description: Force forces resource updates through a replacement strategy. + type: boolean + preserveValues: + description: |- + PreserveValues will make Helm reuse the last release's values and merge in + overrides from 'Values'. Setting this flag makes the HelmRelease + non-declarative. + type: boolean + remediation: + description: |- + Remediation holds the remediation configuration for when the Helm upgrade + action for the HelmRelease fails. The default is to not perform any action. + properties: + ignoreTestFailures: + description: |- + IgnoreTestFailures tells the controller to skip remediation when the Helm + tests are run after an upgrade action but fail. + Defaults to 'Test.IgnoreFailures'. + type: boolean + remediateLastFailure: + description: |- + RemediateLastFailure tells the controller to remediate the last failure, when + no retries remain. Defaults to 'false' unless 'Retries' is greater than 0. + type: boolean + retries: + description: |- + Retries is the number of retries that should be attempted on failures before + bailing. Remediation, using 'Strategy', is performed between each attempt. + Defaults to '0', a negative integer equals to unlimited retries. + type: integer + strategy: + description: Strategy to use for failure remediation. Defaults to 'rollback'. + enum: + - rollback + - uninstall + type: string + type: object + strategy: + description: |- + Strategy defines the upgrade strategy to use for this HelmRelease. + Defaults to 'RemediateOnFailure'. + properties: + name: + description: Name of the upgrade strategy. + enum: + - RemediateOnFailure + - RetryOnFailure + type: string + retryInterval: + description: |- + RetryInterval is the interval at which to retry a failed upgrade. + Can be used only when Name is set to RetryOnFailure. + Defaults to '5m'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + required: + - name + type: object + x-kubernetes-validations: + - message: .retryInterval can only be set when .name is 'RetryOnFailure' + rule: '!has(self.retryInterval) || self.name == ''RetryOnFailure''' + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm upgrade action. Defaults to + 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + values: + description: Values holds the values for this Helm release. + x-kubernetes-preserve-unknown-fields: true + valuesFrom: + description: |- + ValuesFrom holds references to resources containing Helm values for this HelmRelease, + and information about how they should be merged. + items: + description: |- + ValuesReference contains a reference to a resource containing Helm values, + and optionally the key they can be found at. + properties: + kind: + description: Kind of the values referent, valid values are ('Secret', 'ConfigMap'). + enum: + - Secret + - ConfigMap + type: string + name: + description: |- + Name of the values referent. Should reside in the same namespace as the + referring resource. + maxLength: 253 + minLength: 1 + type: string + optional: + description: |- + Optional marks this ValuesReference as optional. When set, a not found error + for the values reference is ignored, but any ValuesKey, TargetPath or + transient error will still result in a reconciliation failure. + type: boolean + targetPath: + description: |- + TargetPath is the YAML dot notation path the value should be merged at. When + set, the ValuesKey is expected to be a single flat value. Defaults to 'None', + which results in the values getting merged at the root. + maxLength: 250 + pattern: ^([a-zA-Z0-9_\-.\\\/]|\[[0-9]{1,5}\])+$ + type: string + valuesKey: + description: |- + ValuesKey is the data key where the values.yaml or a specific value can be + found at. Defaults to 'values.yaml'. + maxLength: 253 + pattern: ^[\-._a-zA-Z0-9]+$ + type: string + required: + - kind + - name + type: object + type: array + required: + - interval + type: object + x-kubernetes-validations: + - message: either chart or chartRef must be set + rule: (has(self.chart) && !has(self.chartRef)) || (!has(self.chart) && has(self.chartRef)) + status: + default: + observedGeneration: -1 + description: HelmReleaseStatus defines the observed state of a HelmRelease. + properties: + conditions: + description: Conditions holds the conditions for the HelmRelease. + 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 + type: array + failures: + description: |- + Failures is the reconciliation failure count against the latest desired + state. It is reset after a successful reconciliation. + format: int64 + type: integer + helmChart: + description: |- + HelmChart is the namespaced name of the HelmChart resource created by + the controller for the HelmRelease. + type: string + history: + description: |- + History holds the history of Helm releases performed for this HelmRelease + up to the last successfully completed release. + items: + description: |- + Snapshot captures a point-in-time copy of the status information for a Helm release, + as managed by the controller. + properties: + apiVersion: + description: |- + APIVersion is the API version of the Snapshot. + Provisional: when the calculation method of the Digest field is changed, + this field will be used to distinguish between the old and new methods. + type: string + appVersion: + description: AppVersion is the chart app version of the release object in storage. + type: string + chartName: + description: ChartName is the chart name of the release object in storage. + type: string + chartVersion: + description: |- + ChartVersion is the chart version of the release object in + storage. + type: string + configDigest: + description: |- + ConfigDigest is the checksum of the config (better known as + "values") of the release object in storage. + It has the format of `:`. + type: string + deleted: + description: Deleted is when the release was deleted. + format: date-time + type: string + digest: + description: |- + Digest is the checksum of the release object in storage. + It has the format of `:`. + type: string + firstDeployed: + description: FirstDeployed is when the release was first deployed. + format: date-time + type: string + lastDeployed: + description: LastDeployed is when the release was last deployed. + format: date-time + type: string + name: + description: Name is the name of the release. + type: string + namespace: + description: Namespace is the namespace the release is deployed to. + type: string + ociDigest: + description: OCIDigest is the digest of the OCI artifact associated with the release. + type: string + status: + description: Status is the current state of the release. + type: string + testHooks: + additionalProperties: + description: |- + TestHookStatus holds the status information for a test hook as observed + to be run by the controller. + properties: + lastCompleted: + description: LastCompleted is the time the test hook last completed. + format: date-time + type: string + lastStarted: + description: LastStarted is the time the test hook was last started. + format: date-time + type: string + phase: + description: Phase the test hook was observed to be in. + type: string + type: object + description: |- + TestHooks is the list of test hooks for the release as observed to be + run by the controller. + type: object + version: + description: Version is the version of the release object in storage. + type: integer + required: + - chartName + - chartVersion + - configDigest + - digest + - firstDeployed + - lastDeployed + - name + - namespace + - status + - version + type: object + type: array + installFailures: + description: |- + InstallFailures is the install failure count against the latest desired + state. It is reset after a successful reconciliation. + format: int64 + type: integer + lastAttemptedConfigDigest: + description: |- + LastAttemptedConfigDigest is the digest for the config (better known as + "values") of the last reconciliation attempt. + type: string + lastAttemptedGeneration: + description: |- + LastAttemptedGeneration is the last generation the controller attempted + to reconcile. + format: int64 + type: integer + lastAttemptedReleaseAction: + description: |- + LastAttemptedReleaseAction is the last release action performed for this + HelmRelease. It is used to determine the active retry or remediation + strategy. + enum: + - install + - upgrade + type: string + lastAttemptedReleaseActionDuration: + description: |- + LastAttemptedReleaseActionDuration is the duration of the last + release action performed for this HelmRelease. + type: string + lastAttemptedRevision: + description: |- + LastAttemptedRevision is the Source revision of the last reconciliation + attempt. For OCIRepository sources, the 12 first characters of the digest are + appended to the chart version e.g. "1.2.3+1234567890ab". + type: string + lastAttemptedRevisionDigest: + description: |- + LastAttemptedRevisionDigest is the digest of the last reconciliation attempt. + This is only set for OCIRepository sources. + type: string + lastAttemptedValuesChecksum: + description: |- + LastAttemptedValuesChecksum is the SHA1 checksum for the values of the last + reconciliation attempt. + + Deprecated: Use LastAttemptedConfigDigest instead. + type: string + lastHandledForceAt: + description: |- + LastHandledForceAt holds the value of the most recent + force request value, so a change of the annotation value + can be detected. + type: string + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + lastHandledResetAt: + description: |- + LastHandledResetAt holds the value of the most recent reset request + value, so a change of the annotation value can be detected. + type: string + lastReleaseRevision: + description: |- + LastReleaseRevision is the revision of the last successful Helm release. + + Deprecated: Use History instead. + type: integer + observedCommonMetadataDigest: + description: |- + ObservedCommonMetadataDigest is the digest for the common metadata of + the last successful reconciliation attempt. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + observedPostRenderersDigest: + description: |- + ObservedPostRenderersDigest is the digest for the post-renderers of + the last successful reconciliation attempt. + type: string + storageNamespace: + description: |- + StorageNamespace is the namespace of the Helm release storage for the + current release. + maxLength: 63 + minLength: 1 + type: string + upgradeFailures: + description: |- + UpgradeFailures is the upgrade failure count against the latest desired + state. It is reset after a successful reconciliation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v2beta2 HelmRelease is deprecated, upgrade to v2 + name: v2beta2 + schema: + openAPIV3Schema: + description: HelmRelease is the Schema for the helmreleases API + 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: HelmReleaseSpec defines the desired state of a Helm release. + properties: + chart: + description: |- + Chart defines the template of the v1beta2.HelmChart that should be created + for this HelmRelease. + properties: + metadata: + description: ObjectMeta holds the template for metadata like labels and annotations. + properties: + annotations: + additionalProperties: + type: string + description: |- + Annotations is an unstructured key value map stored with a resource that may be + set by external tools to store and retrieve arbitrary metadata. They are not + queryable and should be preserved when modifying objects. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + type: object + labels: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to organize and categorize + (scope and select) objects. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + type: object + type: object + spec: + description: Spec holds the template for the v1beta2.HelmChartSpec for this HelmRelease. + properties: + chart: + description: The name or path the Helm chart is available at in the SourceRef. + maxLength: 2048 + minLength: 1 + type: string + ignoreMissingValuesFiles: + description: IgnoreMissingValuesFiles controls whether to silently ignore missing values files rather than failing. + type: boolean + interval: + description: |- + Interval at which to check the v1.Source for updates. Defaults to + 'HelmReleaseSpec.Interval'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + reconcileStrategy: + default: ChartVersion + description: |- + Determines what enables the creation of a new artifact. Valid values are + ('ChartVersion', 'Revision'). + See the documentation of the values for an explanation on their behavior. + Defaults to ChartVersion when omitted. + enum: + - ChartVersion + - Revision + type: string + sourceRef: + description: The name and namespace of the v1.Source the chart is available at. + properties: + apiVersion: + description: APIVersion of the referent. + type: string + kind: + description: Kind of the referent. + enum: + - HelmRepository + - GitRepository + - Bucket + type: string + name: + description: Name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace of the referent. + maxLength: 63 + minLength: 1 + type: string + required: + - kind + - name + type: object + valuesFile: + description: |- + Alternative values file to use as the default chart values, expected to + be a relative path in the SourceRef. Deprecated in favor of ValuesFiles, + for backwards compatibility the file defined here is merged before the + ValuesFiles items. Ignored when omitted. + type: string + valuesFiles: + description: |- + Alternative list of values files to use as the chart values (values.yaml + is not included by default), expected to be a relative path in the SourceRef. + Values files are merged in the order of this list with the last file overriding + the first. Ignored when omitted. + items: + type: string + type: array + verify: + description: |- + Verify contains the secret name containing the trusted public keys + used to verify the signature and specifies which provider to use to check + whether OCI image is authentic. + This field is only supported for OCI sources. + Chart dependencies, which are not bundled in the umbrella chart artifact, + are not verified. + properties: + provider: + default: cosign + description: Provider specifies the technology used to sign the OCI Helm chart. + enum: + - cosign + - notation + type: string + secretRef: + description: |- + SecretRef specifies the Kubernetes Secret containing the + trusted public keys. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + version: + default: '*' + description: |- + Version semver expression, ignored for charts from v1beta2.GitRepository and + v1beta2.Bucket sources. Defaults to latest when omitted. + type: string + required: + - chart + - sourceRef + type: object + required: + - spec + type: object + chartRef: + description: |- + ChartRef holds a reference to a source controller resource containing the + Helm chart artifact. + + Note: this field is provisional to the v2 API, and not actively used + by v2beta2 HelmReleases. + properties: + apiVersion: + description: APIVersion of the referent. + type: string + kind: + description: Kind of the referent. + enum: + - OCIRepository + - HelmChart + type: string + name: + description: Name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace of the referent, defaults to the namespace of the Kubernetes + resource object that contains the reference. + maxLength: 63 + minLength: 1 + type: string + required: + - kind + - name + type: object + dependsOn: + description: |- + DependsOn may contain a meta.NamespacedObjectReference slice with + references to HelmRelease resources that must be ready before this HelmRelease + can be reconciled. + items: + description: |- + NamespacedObjectReference contains enough information to locate the referenced Kubernetes resource object in any + namespace. + properties: + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it acts as LocalObjectReference. + type: string + required: + - name + type: object + type: array + driftDetection: + description: |- + DriftDetection holds the configuration for detecting and handling + differences between the manifest in the Helm storage and the resources + currently existing in the cluster. + properties: + ignore: + description: |- + Ignore contains a list of rules for specifying which changes to ignore + during diffing. + items: + description: |- + IgnoreRule defines a rule to selectively disregard specific changes during + the drift detection process. + properties: + paths: + description: |- + Paths is a list of JSON Pointer (RFC 6901) paths to be excluded from + consideration in a Kubernetes object. + items: + type: string + type: array + target: + description: |- + Target is a selector for specifying Kubernetes objects to which this + rule applies. + If Target is not set, the Paths will be ignored for all Kubernetes + objects within the manifest of the Helm release. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - paths + type: object + type: array + mode: + description: |- + Mode defines how differences should be handled between the Helm manifest + and the manifest currently applied to the cluster. + If not explicitly set, it defaults to DiffModeDisabled. + enum: + - enabled + - warn + - disabled + type: string + type: object + install: + description: Install holds the configuration for Helm install actions for this HelmRelease. + properties: + crds: + description: |- + CRDs upgrade CRDs from the Helm Chart's crds directory according + to the CRD upgrade policy provided here. Valid values are `Skip`, + `Create` or `CreateReplace`. Default is `Create` and if omitted + CRDs are installed but not updated. + + Skip: do neither install nor replace (update) any CRDs. + + Create: new CRDs are created, existing CRDs are neither updated nor deleted. + + CreateReplace: new CRDs are created, existing CRDs are updated (replaced) + but not deleted. + + By default, CRDs are applied (installed) during Helm install action. + With this option users can opt in to CRD replace existing CRDs on Helm + install actions, which is not (yet) natively supported by Helm. + https://helm.sh/docs/chart_best_practices/custom_resource_definitions. + enum: + - Skip + - Create + - CreateReplace + type: string + createNamespace: + description: |- + CreateNamespace tells the Helm install action to create the + HelmReleaseSpec.TargetNamespace if it does not exist yet. + On uninstall, the namespace will not be garbage collected. + type: boolean + disableHooks: + description: DisableHooks prevents hooks from running during the Helm install action. + type: boolean + disableOpenAPIValidation: + description: |- + DisableOpenAPIValidation prevents the Helm install action from validating + rendered templates against the Kubernetes OpenAPI Schema. + type: boolean + disableWait: + description: |- + DisableWait disables the waiting for resources to be ready after a Helm + install has been performed. + type: boolean + disableWaitForJobs: + description: |- + DisableWaitForJobs disables waiting for jobs to complete after a Helm + install has been performed. + type: boolean + remediation: + description: |- + Remediation holds the remediation configuration for when the Helm install + action for the HelmRelease fails. The default is to not perform any action. + properties: + ignoreTestFailures: + description: |- + IgnoreTestFailures tells the controller to skip remediation when the Helm + tests are run after an install action but fail. Defaults to + 'Test.IgnoreFailures'. + type: boolean + remediateLastFailure: + description: |- + RemediateLastFailure tells the controller to remediate the last failure, when + no retries remain. Defaults to 'false'. + type: boolean + retries: + description: |- + Retries is the number of retries that should be attempted on failures before + bailing. Remediation, using an uninstall, is performed between each attempt. + Defaults to '0', a negative integer equals to unlimited retries. + type: integer + type: object + replace: + description: |- + Replace tells the Helm install action to re-use the 'ReleaseName', but only + if that name is a deleted release which remains in the history. + type: boolean + skipCRDs: + description: |- + SkipCRDs tells the Helm install action to not install any CRDs. By default, + CRDs are installed if not already present. + + Deprecated use CRD policy (`crds`) attribute with value `Skip` instead. + type: boolean + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm install action. Defaults to + 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + interval: + description: Interval at which to reconcile the Helm release. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + kubeConfig: + description: |- + KubeConfig for reconciling the HelmRelease on a remote cluster. + When used in combination with HelmReleaseSpec.ServiceAccountName, + forces the controller to act on behalf of that Service Account at the + target cluster. + If the --default-service-account flag is set, its value will be used as + a controller level fallback for when HelmReleaseSpec.ServiceAccountName + is empty. + properties: + configMapRef: + description: |- + ConfigMapRef holds an optional name of a ConfigMap that contains + the following keys: + + - `provider`: the provider to use. One of `aws`, `azure`, `gcp`, or + `generic`. Required. + - `cluster`: the fully qualified resource name of the Kubernetes + cluster in the cloud provider API. Not used by the `generic` + provider. Required when one of `address` or `ca.crt` is not set. + - `address`: the address of the Kubernetes API server. Required + for `generic`. For the other providers, if not specified, the + first address in the cluster resource will be used, and if + specified, it must match one of the addresses in the cluster + resource. + If audiences is not set, will be used as the audience for the + `generic` provider. + - `ca.crt`: the optional PEM-encoded CA certificate for the + Kubernetes API server. If not set, the controller will use the + CA certificate from the cluster resource. + - `audiences`: the optional audiences as a list of + line-break-separated strings for the Kubernetes ServiceAccount + token. Defaults to the `address` for the `generic` provider, or + to specific values for the other providers depending on the + provider. + - `serviceAccountName`: the optional name of the Kubernetes + ServiceAccount in the same namespace that should be used + for authentication. If not specified, the controller + ServiceAccount will be used. + + Mutually exclusive with SecretRef. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + secretRef: + description: |- + SecretRef holds an optional name of a secret that contains a key with + the kubeconfig file as the value. If no key is set, the key will default + to 'value'. Mutually exclusive with ConfigMapRef. + It is recommended that the kubeconfig is self-contained, and the secret + is regularly updated if credentials such as a cloud-access-token expire. + Cloud specific `cmd-path` auth helpers will not function without adding + binaries and credentials to the Pod that is responsible for reconciling + Kubernetes resources. Supported only for the generic provider. + properties: + key: + description: Key in the Secret, when not specified an implementation-specific default key is used. + type: string + name: + description: Name of the Secret. + type: string + required: + - name + type: object + type: object + x-kubernetes-validations: + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: has(self.configMapRef) || has(self.secretRef) + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: '!has(self.configMapRef) || !has(self.secretRef)' + maxHistory: + description: |- + MaxHistory is the number of revisions saved by Helm for this HelmRelease. + Use '0' for an unlimited number of revisions; defaults to '5'. + type: integer + persistentClient: + description: |- + PersistentClient tells the controller to use a persistent Kubernetes + client for this release. When enabled, the client will be reused for the + duration of the reconciliation, instead of being created and destroyed + for each (step of a) Helm action. + + This can improve performance, but may cause issues with some Helm charts + that for example do create Custom Resource Definitions during installation + outside Helm's CRD lifecycle hooks, which are then not observed to be + available by e.g. post-install hooks. + + If not set, it defaults to true. + type: boolean + postRenderers: + description: |- + PostRenderers holds an array of Helm PostRenderers, which will be applied in order + of their definition. + items: + description: PostRenderer contains a Helm PostRenderer specification. + properties: + kustomize: + description: Kustomization to apply as PostRenderer. + properties: + images: + description: |- + Images is a list of (image name, new name, new tag or digest) + for changing image names, tags or digests. This can also be achieved with a + patch, but this operator is simpler to specify. + items: + description: Image contains an image name, a new name, a new tag or digest, which will replace the original name and tag. + properties: + digest: + description: |- + Digest is the value used to replace the original image tag. + If digest is present NewTag value is ignored. + type: string + name: + description: Name is a tag-less image name. + type: string + newName: + description: NewName is the value used to replace the original name. + type: string + newTag: + description: NewTag is the value used to replace the original tag. + type: string + required: + - name + type: object + type: array + patches: + description: |- + Strategic merge and JSON patches, defined as inline YAML objects, + capable of targeting objects based on kind, label and annotation selectors. + items: + description: |- + Patch contains an inline StrategicMerge or JSON6902 patch, and the target the patch should + be applied to. + properties: + patch: + description: |- + Patch contains an inline StrategicMerge patch or an inline JSON6902 patch with + an array of operation objects. + type: string + target: + description: Target points to the resources that the patch document should be applied to. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - patch + type: object + type: array + patchesJson6902: + description: |- + JSON 6902 patches, defined as inline YAML objects. + + Deprecated: use Patches instead. + items: + description: JSON6902Patch contains a JSON6902 patch and the target the patch should be applied to. + properties: + patch: + description: Patch contains the JSON6902 patch document with an array of operation objects. + items: + description: |- + JSON6902 is a JSON6902 operation object. + https://datatracker.ietf.org/doc/html/rfc6902#section-4 + properties: + from: + description: |- + From contains a JSON-pointer value that references a location within the target document where the operation is + performed. The meaning of the value depends on the value of Op, and is NOT taken into account by all operations. + type: string + op: + description: |- + Op indicates the operation to perform. Its value MUST be one of "add", "remove", "replace", "move", "copy", or + "test". + https://datatracker.ietf.org/doc/html/rfc6902#section-4 + enum: + - test + - remove + - add + - replace + - move + - copy + type: string + path: + description: |- + Path contains the JSON-pointer value that references a location within the target document where the operation + is performed. The meaning of the value depends on the value of Op. + type: string + value: + description: |- + Value contains a valid JSON structure. The meaning of the value depends on the value of Op, and is NOT taken into + account by all operations. + x-kubernetes-preserve-unknown-fields: true + required: + - op + - path + type: object + type: array + target: + description: Target points to the resources that the patch document should be applied to. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - patch + - target + type: object + type: array + patchesStrategicMerge: + description: |- + Strategic merge patches, defined as inline YAML objects. + + Deprecated: use Patches instead. + items: + x-kubernetes-preserve-unknown-fields: true + type: array + type: object + type: object + type: array + releaseName: + description: |- + ReleaseName used for the Helm release. Defaults to a composition of + '[TargetNamespace-]Name'. + maxLength: 53 + minLength: 1 + type: string + rollback: + description: Rollback holds the configuration for Helm rollback actions for this HelmRelease. + properties: + cleanupOnFail: + description: |- + CleanupOnFail allows deletion of new resources created during the Helm + rollback action when it fails. + type: boolean + disableHooks: + description: DisableHooks prevents hooks from running during the Helm rollback action. + type: boolean + disableWait: + description: |- + DisableWait disables the waiting for resources to be ready after a Helm + rollback has been performed. + type: boolean + disableWaitForJobs: + description: |- + DisableWaitForJobs disables waiting for jobs to complete after a Helm + rollback has been performed. + type: boolean + force: + description: Force forces resource updates through a replacement strategy. + type: boolean + recreate: + description: Recreate performs pod restarts for the resource if applicable. + type: boolean + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm rollback action. Defaults to + 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + serviceAccountName: + description: |- + The name of the Kubernetes service account to impersonate + when reconciling this HelmRelease. + maxLength: 253 + minLength: 1 + type: string + storageNamespace: + description: |- + StorageNamespace used for the Helm storage. + Defaults to the namespace of the HelmRelease. + maxLength: 63 + minLength: 1 + type: string + suspend: + description: |- + Suspend tells the controller to suspend reconciliation for this HelmRelease, + it does not apply to already started reconciliations. Defaults to false. + type: boolean + targetNamespace: + description: |- + TargetNamespace to target when performing operations for the HelmRelease. + Defaults to the namespace of the HelmRelease. + maxLength: 63 + minLength: 1 + type: string + test: + description: Test holds the configuration for Helm test actions for this HelmRelease. + properties: + enable: + description: |- + Enable enables Helm test actions for this HelmRelease after an Helm install + or upgrade action has been performed. + type: boolean + filters: + description: Filters is a list of tests to run or exclude from running. + items: + description: Filter holds the configuration for individual Helm test filters. + properties: + exclude: + description: Exclude specifies whether the named test should be excluded. + type: boolean + name: + description: Name is the name of the test. + maxLength: 253 + minLength: 1 + type: string + required: + - name + type: object + type: array + ignoreFailures: + description: |- + IgnoreFailures tells the controller to skip remediation when the Helm tests + are run but fail. Can be overwritten for tests run after install or upgrade + actions in 'Install.IgnoreTestFailures' and 'Upgrade.IgnoreTestFailures'. + type: boolean + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation during + the performance of a Helm test action. Defaults to 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like Jobs + for hooks) during the performance of a Helm action. Defaults to '5m0s'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + uninstall: + description: Uninstall holds the configuration for Helm uninstall actions for this HelmRelease. + properties: + deletionPropagation: + default: background + description: |- + DeletionPropagation specifies the deletion propagation policy when + a Helm uninstall is performed. + enum: + - background + - foreground + - orphan + type: string + disableHooks: + description: DisableHooks prevents hooks from running during the Helm rollback action. + type: boolean + disableWait: + description: |- + DisableWait disables waiting for all the resources to be deleted after + a Helm uninstall is performed. + type: boolean + keepHistory: + description: |- + KeepHistory tells Helm to remove all associated resources and mark the + release as deleted, but retain the release history. + type: boolean + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm uninstall action. Defaults + to 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + upgrade: + description: Upgrade holds the configuration for Helm upgrade actions for this HelmRelease. + properties: + cleanupOnFail: + description: |- + CleanupOnFail allows deletion of new resources created during the Helm + upgrade action when it fails. + type: boolean + crds: + description: |- + CRDs upgrade CRDs from the Helm Chart's crds directory according + to the CRD upgrade policy provided here. Valid values are `Skip`, + `Create` or `CreateReplace`. Default is `Skip` and if omitted + CRDs are neither installed nor upgraded. + + Skip: do neither install nor replace (update) any CRDs. + + Create: new CRDs are created, existing CRDs are neither updated nor deleted. + + CreateReplace: new CRDs are created, existing CRDs are updated (replaced) + but not deleted. + + By default, CRDs are not applied during Helm upgrade action. With this + option users can opt-in to CRD upgrade, which is not (yet) natively supported by Helm. + https://helm.sh/docs/chart_best_practices/custom_resource_definitions. + enum: + - Skip + - Create + - CreateReplace + type: string + disableHooks: + description: DisableHooks prevents hooks from running during the Helm upgrade action. + type: boolean + disableOpenAPIValidation: + description: |- + DisableOpenAPIValidation prevents the Helm upgrade action from validating + rendered templates against the Kubernetes OpenAPI Schema. + type: boolean + disableWait: + description: |- + DisableWait disables the waiting for resources to be ready after a Helm + upgrade has been performed. + type: boolean + disableWaitForJobs: + description: |- + DisableWaitForJobs disables waiting for jobs to complete after a Helm + upgrade has been performed. + type: boolean + force: + description: Force forces resource updates through a replacement strategy. + type: boolean + preserveValues: + description: |- + PreserveValues will make Helm reuse the last release's values and merge in + overrides from 'Values'. Setting this flag makes the HelmRelease + non-declarative. + type: boolean + remediation: + description: |- + Remediation holds the remediation configuration for when the Helm upgrade + action for the HelmRelease fails. The default is to not perform any action. + properties: + ignoreTestFailures: + description: |- + IgnoreTestFailures tells the controller to skip remediation when the Helm + tests are run after an upgrade action but fail. + Defaults to 'Test.IgnoreFailures'. + type: boolean + remediateLastFailure: + description: |- + RemediateLastFailure tells the controller to remediate the last failure, when + no retries remain. Defaults to 'false' unless 'Retries' is greater than 0. + type: boolean + retries: + description: |- + Retries is the number of retries that should be attempted on failures before + bailing. Remediation, using 'Strategy', is performed between each attempt. + Defaults to '0', a negative integer equals to unlimited retries. + type: integer + strategy: + description: Strategy to use for failure remediation. Defaults to 'rollback'. + enum: + - rollback + - uninstall + type: string + type: object + timeout: + description: |- + Timeout is the time to wait for any individual Kubernetes operation (like + Jobs for hooks) during the performance of a Helm upgrade action. Defaults to + 'HelmReleaseSpec.Timeout'. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + type: object + values: + description: Values holds the values for this Helm release. + x-kubernetes-preserve-unknown-fields: true + valuesFrom: + description: |- + ValuesFrom holds references to resources containing Helm values for this HelmRelease, + and information about how they should be merged. + items: + description: |- + ValuesReference contains a reference to a resource containing Helm values, + and optionally the key they can be found at. + properties: + kind: + description: Kind of the values referent, valid values are ('Secret', 'ConfigMap'). + enum: + - Secret + - ConfigMap + type: string + name: + description: |- + Name of the values referent. Should reside in the same namespace as the + referring resource. + maxLength: 253 + minLength: 1 + type: string + optional: + description: |- + Optional marks this ValuesReference as optional. When set, a not found error + for the values reference is ignored, but any ValuesKey, TargetPath or + transient error will still result in a reconciliation failure. + type: boolean + targetPath: + description: |- + TargetPath is the YAML dot notation path the value should be merged at. When + set, the ValuesKey is expected to be a single flat value. Defaults to 'None', + which results in the values getting merged at the root. + maxLength: 250 + pattern: ^([a-zA-Z0-9_\-.\\\/]|\[[0-9]{1,5}\])+$ + type: string + valuesKey: + description: |- + ValuesKey is the data key where the values.yaml or a specific value can be + found at. Defaults to 'values.yaml'. + maxLength: 253 + pattern: ^[\-._a-zA-Z0-9]+$ + type: string + required: + - kind + - name + type: object + type: array + required: + - interval + type: object + x-kubernetes-validations: + - message: either chart or chartRef must be set + rule: (has(self.chart) && !has(self.chartRef)) || (!has(self.chart) && has(self.chartRef)) + status: + default: + observedGeneration: -1 + description: HelmReleaseStatus defines the observed state of a HelmRelease. + properties: + conditions: + description: Conditions holds the conditions for the HelmRelease. + 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 + type: array + failures: + description: |- + Failures is the reconciliation failure count against the latest desired + state. It is reset after a successful reconciliation. + format: int64 + type: integer + helmChart: + description: |- + HelmChart is the namespaced name of the HelmChart resource created by + the controller for the HelmRelease. + type: string + history: + description: |- + History holds the history of Helm releases performed for this HelmRelease + up to the last successfully completed release. + items: + description: |- + Snapshot captures a point-in-time copy of the status information for a Helm release, + as managed by the controller. + properties: + apiVersion: + description: |- + APIVersion is the API version of the Snapshot. + Provisional: when the calculation method of the Digest field is changed, + this field will be used to distinguish between the old and new methods. + type: string + appVersion: + description: AppVersion is the chart app version of the release object in storage. + type: string + chartName: + description: ChartName is the chart name of the release object in storage. + type: string + chartVersion: + description: |- + ChartVersion is the chart version of the release object in + storage. + type: string + configDigest: + description: |- + ConfigDigest is the checksum of the config (better known as + "values") of the release object in storage. + It has the format of `:`. + type: string + deleted: + description: Deleted is when the release was deleted. + format: date-time + type: string + digest: + description: |- + Digest is the checksum of the release object in storage. + It has the format of `:`. + type: string + firstDeployed: + description: FirstDeployed is when the release was first deployed. + format: date-time + type: string + lastDeployed: + description: LastDeployed is when the release was last deployed. + format: date-time + type: string + name: + description: Name is the name of the release. + type: string + namespace: + description: Namespace is the namespace the release is deployed to. + type: string + ociDigest: + description: OCIDigest is the digest of the OCI artifact associated with the release. + type: string + status: + description: Status is the current state of the release. + type: string + testHooks: + additionalProperties: + description: |- + TestHookStatus holds the status information for a test hook as observed + to be run by the controller. + properties: + lastCompleted: + description: LastCompleted is the time the test hook last completed. + format: date-time + type: string + lastStarted: + description: LastStarted is the time the test hook was last started. + format: date-time + type: string + phase: + description: Phase the test hook was observed to be in. + type: string + type: object + description: |- + TestHooks is the list of test hooks for the release as observed to be + run by the controller. + type: object + version: + description: Version is the version of the release object in storage. + type: integer + required: + - chartName + - chartVersion + - configDigest + - digest + - firstDeployed + - lastDeployed + - name + - namespace + - status + - version + type: object + type: array + installFailures: + description: |- + InstallFailures is the install failure count against the latest desired + state. It is reset after a successful reconciliation. + format: int64 + type: integer + lastAppliedRevision: + description: |- + LastAppliedRevision is the revision of the last successfully applied + source. + + Deprecated: the revision can now be found in the History. + type: string + lastAttemptedConfigDigest: + description: |- + LastAttemptedConfigDigest is the digest for the config (better known as + "values") of the last reconciliation attempt. + type: string + lastAttemptedGeneration: + description: |- + LastAttemptedGeneration is the last generation the controller attempted + to reconcile. + format: int64 + type: integer + lastAttemptedReleaseAction: + description: |- + LastAttemptedReleaseAction is the last release action performed for this + HelmRelease. It is used to determine the active remediation strategy. + enum: + - install + - upgrade + type: string + lastAttemptedRevision: + description: |- + LastAttemptedRevision is the Source revision of the last reconciliation + attempt. For OCIRepository sources, the 12 first characters of the digest are + appended to the chart version e.g. "1.2.3+1234567890ab". + type: string + lastAttemptedRevisionDigest: + description: |- + LastAttemptedRevisionDigest is the digest of the last reconciliation attempt. + This is only set for OCIRepository sources. + type: string + lastAttemptedValuesChecksum: + description: |- + LastAttemptedValuesChecksum is the SHA1 checksum for the values of the last + reconciliation attempt. + + Deprecated: Use LastAttemptedConfigDigest instead. + type: string + lastHandledForceAt: + description: |- + LastHandledForceAt holds the value of the most recent force request + value, so a change of the annotation value can be detected. + type: string + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + lastHandledResetAt: + description: |- + LastHandledResetAt holds the value of the most recent reset request + value, so a change of the annotation value can be detected. + type: string + lastReleaseRevision: + description: |- + LastReleaseRevision is the revision of the last successful Helm release. + + Deprecated: Use History instead. + type: integer + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + observedPostRenderersDigest: + description: |- + ObservedPostRenderersDigest is the digest for the post-renderers of + the last successful reconciliation attempt. + type: string + storageNamespace: + description: |- + StorageNamespace is the namespace of the Helm release storage for the + current release. + maxLength: 63 + minLength: 1 + type: string + upgradeFailures: + description: |- + UpgradeFailures is the upgrade failure count against the latest desired + state. It is reset after a successful reconciliation. + format: int64 + type: integer + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: helmrepositories.source.toolkit.fluxcd.io +spec: + group: source.toolkit.fluxcd.io + names: + kind: HelmRepository + listKind: HelmRepositoryList + plural: helmrepositories + shortNames: + - helmrepo + singular: helmrepository + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.url + name: URL + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + description: HelmRepository is the Schema for the helmrepositories API. + 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: |- + HelmRepositorySpec specifies the required configuration to produce an + Artifact for a Helm repository index YAML. + properties: + accessFrom: + description: |- + AccessFrom specifies an Access Control List for allowing cross-namespace + references to this object. + NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + 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 + type: array + required: + - namespaceSelectors + type: object + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + registry. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + It takes precedence over the values specified in the Secret referred + to by `.spec.secretRef`. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + insecure: + description: |- + Insecure allows connecting to a non-TLS HTTP container registry. + This field is only taken into account if the .spec.type field is set to 'oci'. + type: boolean + interval: + description: |- + Interval at which the HelmRepository URL is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + passCredentials: + description: |- + PassCredentials allows the credentials from the SecretRef to be passed + on to a host that does not match the host as defined in URL. + This may be required if the host of the advertised chart URLs in the + index differ from the defined URL. + Enabling this should be done with caution, as it can potentially result + in credentials getting stolen in a MITM-attack. + type: boolean + provider: + default: generic + description: |- + Provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + This field is optional, and only taken into account if the .spec.type field is set to 'oci'. + When not specified, defaults to 'generic'. + enum: + - generic + - aws + - azure + - gcp + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials + for the HelmRepository. + For HTTP/S basic auth the secret must contain 'username' and 'password' + fields. + Support for TLS auth using the 'certFile' and 'keyFile', and/or 'caFile' + keys is deprecated. Please use `.spec.certSecretRef` instead. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + HelmRepository. + type: boolean + timeout: + description: |- + Timeout is used for the index fetch operation for an HTTPS helm repository, + and for remote OCI Repository operations like pulling for an OCI helm + chart by the associated HelmChart. + Its default value is 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + type: + description: |- + Type of the HelmRepository. + When this field is set to "oci", the URL field value must be prefixed with "oci://". + enum: + - default + - oci + type: string + url: + description: |- + URL of the Helm repository, a valid URL contains at least a protocol and + host. + pattern: ^(http|https|oci)://.*$ + type: string + required: + - url + type: object + status: + default: + observedGeneration: -1 + description: HelmRepositoryStatus records the observed state of the HelmRepository. + properties: + artifact: + description: Artifact represents the last successful HelmRepository reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the HelmRepository. + 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 + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: |- + ObservedGeneration is the last observed generation of the HelmRepository + object. + format: int64 + type: integer + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + HelmRepositoryStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.url + name: URL + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 HelmRepository is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: HelmRepository is the Schema for the helmrepositories API. + 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: |- + HelmRepositorySpec specifies the required configuration to produce an + Artifact for a Helm repository index YAML. + properties: + accessFrom: + description: |- + AccessFrom specifies an Access Control List for allowing cross-namespace + references to this object. + NOTE: Not implemented, provisional as of https://github.com/fluxcd/flux2/pull/2092 + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + 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 + type: array + required: + - namespaceSelectors + type: object + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + registry. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + It takes precedence over the values specified in the Secret referred + to by `.spec.secretRef`. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + insecure: + description: |- + Insecure allows connecting to a non-TLS HTTP container registry. + This field is only taken into account if the .spec.type field is set to 'oci'. + type: boolean + interval: + description: |- + Interval at which the HelmRepository URL is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + passCredentials: + description: |- + PassCredentials allows the credentials from the SecretRef to be passed + on to a host that does not match the host as defined in URL. + This may be required if the host of the advertised chart URLs in the + index differ from the defined URL. + Enabling this should be done with caution, as it can potentially result + in credentials getting stolen in a MITM-attack. + type: boolean + provider: + default: generic + description: |- + Provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + This field is optional, and only taken into account if the .spec.type field is set to 'oci'. + When not specified, defaults to 'generic'. + enum: + - generic + - aws + - azure + - gcp + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing authentication credentials + for the HelmRepository. + For HTTP/S basic auth the secret must contain 'username' and 'password' + fields. + Support for TLS auth using the 'certFile' and 'keyFile', and/or 'caFile' + keys is deprecated. Please use `.spec.certSecretRef` instead. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend the reconciliation of this + HelmRepository. + type: boolean + timeout: + description: |- + Timeout is used for the index fetch operation for an HTTPS helm repository, + and for remote OCI Repository operations like pulling for an OCI helm + chart by the associated HelmChart. + Its default value is 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + type: + description: |- + Type of the HelmRepository. + When this field is set to "oci", the URL field value must be prefixed with "oci://". + enum: + - default + - oci + type: string + url: + description: |- + URL of the Helm repository, a valid URL contains at least a protocol and + host. + pattern: ^(http|https|oci)://.*$ + type: string + required: + - url + type: object + status: + default: + observedGeneration: -1 + description: HelmRepositoryStatus records the observed state of the HelmRepository. + properties: + artifact: + description: Artifact represents the last successful HelmRepository reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the HelmRepository. + 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 + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: |- + ObservedGeneration is the last observed generation of the HelmRepository + object. + format: int64 + type: integer + url: + description: |- + URL is the dynamic fetch link for the latest Artifact. + It is provided on a "best effort" basis, and using the precise + HelmRepositoryStatus.Artifact data is recommended. + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: imagepolicies.image.toolkit.fluxcd.io +spec: + group: image.toolkit.fluxcd.io + names: + kind: ImagePolicy + listKind: ImagePolicyList + plural: imagepolicies + shortNames: + - imgpol + - imagepol + singular: imagepolicy + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.latestRef.name + name: Image + type: string + - jsonPath: .status.latestRef.tag + name: Tag + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: ImagePolicy is the Schema for the imagepolicies API + 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: |- + ImagePolicySpec defines the parameters for calculating the + ImagePolicy. + properties: + digestReflectionPolicy: + default: Never + description: |- + DigestReflectionPolicy governs the setting of the `.status.latestRef.digest` field. + + Never: The digest field will always be set to the empty string. + + IfNotPresent: The digest field will be set to the digest of the elected + latest image if the field is empty and the image did not change. + + Always: The digest field will always be set to the digest of the elected + latest image. + + Default: Never. + enum: + - Always + - IfNotPresent + - Never + type: string + filterTags: + description: |- + FilterTags enables filtering for only a subset of tags based on a set of + rules. If no rules are provided, all the tags from the repository will be + ordered and compared. + properties: + extract: + description: |- + Extract allows a capture group to be extracted from the specified regular + expression pattern, useful before tag evaluation. + type: string + pattern: + description: |- + Pattern specifies a regular expression pattern used to filter for image + tags. + type: string + type: object + imageRepositoryRef: + description: |- + ImageRepositoryRef points at the object specifying the image + being scanned + properties: + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it acts as LocalObjectReference. + type: string + required: + - name + type: object + interval: + description: |- + Interval is the length of time to wait between + refreshing the digest of the latest tag when the + reflection policy is set to "Always". + + Defaults to 10m. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + policy: + description: |- + Policy gives the particulars of the policy to be followed in + selecting the most recent image + properties: + alphabetical: + description: Alphabetical set of rules to use for alphabetical ordering of the tags. + properties: + order: + default: asc + description: |- + Order specifies the sorting order of the tags. Given the letters of the + alphabet as tags, ascending order would select Z, and descending order + would select A. + enum: + - asc + - desc + type: string + type: object + numerical: + description: Numerical set of rules to use for numerical ordering of the tags. + properties: + order: + default: asc + description: |- + Order specifies the sorting order of the tags. Given the integer values + from 0 to 9 as tags, ascending order would select 9, and descending order + would select 0. + enum: + - asc + - desc + type: string + type: object + semver: + description: |- + SemVer gives a semantic version range to check against the tags + available. + properties: + range: + description: |- + Range gives a semver range for the image tag; the highest + version within the range that's a tag yields the latest image. + type: string + required: + - range + type: object + type: object + suspend: + description: |- + This flag tells the controller to suspend subsequent policy reconciliations. + It does not apply to already started reconciliations. Defaults to false. + type: boolean + required: + - imageRepositoryRef + - policy + type: object + x-kubernetes-validations: + - message: spec.interval is only accepted when spec.digestReflectionPolicy is set to 'Always' + rule: '!has(self.interval) || (has(self.digestReflectionPolicy) && self.digestReflectionPolicy == ''Always'')' + - message: spec.interval must be set when spec.digestReflectionPolicy is set to 'Always' + rule: has(self.interval) || !has(self.digestReflectionPolicy) || self.digestReflectionPolicy != 'Always' + status: + default: + observedGeneration: -1 + description: ImagePolicyStatus defines the observed state of ImagePolicy + properties: + conditions: + 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 + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + latestRef: + description: |- + LatestRef gives the first in the list of images scanned by + the image repository, when filtered and ordered according + to the policy. + properties: + digest: + description: Digest is the image's digest. + type: string + name: + description: Name is the bare image's name. + type: string + tag: + description: Tag is the image's tag. + type: string + required: + - name + - tag + type: object + observedGeneration: + format: int64 + type: integer + observedPreviousRef: + description: |- + ObservedPreviousRef is the observed previous LatestRef. It is used + to keep track of the previous and current images. + properties: + digest: + description: Digest is the image's digest. + type: string + name: + description: Name is the bare image's name. + type: string + tag: + description: Tag is the image's tag. + type: string + required: + - name + - tag + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.latestRef.name + name: Image + type: string + - jsonPath: .status.latestRef.tag + name: Tag + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: v1beta2 ImagePolicy is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: ImagePolicy is the Schema for the imagepolicies API + 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: |- + ImagePolicySpec defines the parameters for calculating the + ImagePolicy. + properties: + digestReflectionPolicy: + default: Never + description: |- + DigestReflectionPolicy governs the setting of the `.status.latestRef.digest` field. + + Never: The digest field will always be set to the empty string. + + IfNotPresent: The digest field will be set to the digest of the elected + latest image if the field is empty and the image did not change. + + Always: The digest field will always be set to the digest of the elected + latest image. + + Default: Never. + enum: + - Always + - IfNotPresent + - Never + type: string + filterTags: + description: |- + FilterTags enables filtering for only a subset of tags based on a set of + rules. If no rules are provided, all the tags from the repository will be + ordered and compared. + properties: + extract: + description: |- + Extract allows a capture group to be extracted from the specified regular + expression pattern, useful before tag evaluation. + type: string + pattern: + description: |- + Pattern specifies a regular expression pattern used to filter for image + tags. + type: string + type: object + imageRepositoryRef: + description: |- + ImageRepositoryRef points at the object specifying the image + being scanned + properties: + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it acts as LocalObjectReference. + type: string + required: + - name + type: object + interval: + description: |- + Interval is the length of time to wait between + refreshing the digest of the latest tag when the + reflection policy is set to "Always". + + Defaults to 10m. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + policy: + description: |- + Policy gives the particulars of the policy to be followed in + selecting the most recent image + properties: + alphabetical: + description: Alphabetical set of rules to use for alphabetical ordering of the tags. + properties: + order: + default: asc + description: |- + Order specifies the sorting order of the tags. Given the letters of the + alphabet as tags, ascending order would select Z, and descending order + would select A. + enum: + - asc + - desc + type: string + type: object + numerical: + description: Numerical set of rules to use for numerical ordering of the tags. + properties: + order: + default: asc + description: |- + Order specifies the sorting order of the tags. Given the integer values + from 0 to 9 as tags, ascending order would select 9, and descending order + would select 0. + enum: + - asc + - desc + type: string + type: object + semver: + description: |- + SemVer gives a semantic version range to check against the tags + available. + properties: + range: + description: |- + Range gives a semver range for the image tag; the highest + version within the range that's a tag yields the latest image. + type: string + required: + - range + type: object + type: object + suspend: + description: |- + This flag tells the controller to suspend subsequent policy reconciliations. + It does not apply to already started reconciliations. Defaults to false. + type: boolean + required: + - imageRepositoryRef + - policy + type: object + x-kubernetes-validations: + - message: spec.interval is only accepted when spec.digestReflectionPolicy is set to 'Always' + rule: '!has(self.interval) || (has(self.digestReflectionPolicy) && self.digestReflectionPolicy == ''Always'')' + - message: spec.interval must be set when spec.digestReflectionPolicy is set to 'Always' + rule: has(self.interval) || !has(self.digestReflectionPolicy) || self.digestReflectionPolicy != 'Always' + status: + default: + observedGeneration: -1 + description: ImagePolicyStatus defines the observed state of ImagePolicy + properties: + conditions: + 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 + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + latestRef: + description: |- + LatestRef gives the first in the list of images scanned by + the image repository, when filtered and ordered according + to the policy. + properties: + digest: + description: Digest is the image's digest. + type: string + name: + description: Name is the bare image's name. + type: string + tag: + description: Tag is the image's tag. + type: string + required: + - name + - tag + type: object + observedGeneration: + format: int64 + type: integer + observedPreviousRef: + description: |- + ObservedPreviousRef is the observed previous LatestRef. It is used + to keep track of the previous and current images. + properties: + digest: + description: Digest is the image's digest. + type: string + name: + description: Name is the bare image's name. + type: string + tag: + description: Tag is the image's tag. + type: string + required: + - name + - tag + type: object + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: imagerepositories.image.toolkit.fluxcd.io +spec: + group: image.toolkit.fluxcd.io + names: + kind: ImageRepository + listKind: ImageRepositoryList + plural: imagerepositories + shortNames: + - imgrepo + - imagerepo + singular: imagerepository + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.image + name: Image + type: string + - jsonPath: .status.lastScanResult.tagCount + name: Tags + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .status.lastScanResult.scanTime + name: Last scan + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: ImageRepository is the Schema for the imagerepositories API + 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: |- + ImageRepositorySpec defines the parameters for scanning an image + repository, e.g., `fluxcd/flux`. + properties: + accessFrom: + description: |- + AccessFrom defines an ACL for allowing cross-namespace references + to the ImageRepository object based on the caller's namespace labels. + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + 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 + type: array + required: + - namespaceSelectors + type: object + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + registry. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + Note: Support for the `caFile`, `certFile` and `keyFile` keys has + been deprecated. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + exclusionList: + default: + - ^.*\.sig$ + description: |- + ExclusionList is a list of regex strings used to exclude certain tags + from being stored in the database. + items: + type: string + maxItems: 25 + type: array + image: + description: Image is the name of the image repository + type: string + insecure: + description: Insecure allows connecting to a non-TLS HTTP container registry. + type: boolean + interval: + description: |- + Interval is the length of time to wait between + scans of the image repository. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + provider: + default: generic + description: |- + The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + When not specified, defaults to 'generic'. + enum: + - generic + - aws + - azure + - gcp + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the container registry. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + secretRef: + description: |- + SecretRef can be given the name of a secret containing + credentials to use for the image registry. The secret should be + created with `kubectl create secret docker-registry`, or the + equivalent. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + the image pull if the service account has attached pull secrets. + maxLength: 253 + type: string + suspend: + description: |- + This flag tells the controller to suspend subsequent image scans. + It does not apply to already started scans. Defaults to false. + type: boolean + timeout: + description: |- + Timeout for image scanning. + Defaults to 'Interval' duration. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + required: + - image + - interval + type: object + status: + default: + observedGeneration: -1 + description: ImageRepositoryStatus defines the observed state of ImageRepository + properties: + canonicalImageName: + description: |- + CanonicalName is the name of the image repository with all the + implied bits made explicit; e.g., `docker.io/library/alpine` + rather than `alpine`. + type: string + conditions: + 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 + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + lastScanResult: + description: LastScanResult contains the number of fetched tags. + properties: + latestTags: + description: |- + LatestTags is a small sample of the tags found in the last scan. + It's the first 10 tags when sorting all the tags in descending + alphabetical order. + items: + type: string + type: array + revision: + description: Revision is a stable hash of the scanned tags. + type: string + scanTime: + description: ScanTime is the time when the last scan was performed. + format: date-time + type: string + tagCount: + description: TagCount is the number of tags found in the last scan. + type: integer + required: + - tagCount + type: object + observedExclusionList: + description: |- + ObservedExclusionList is a list of observed exclusion list. It reflects + the exclusion rules used for the observed scan result in + spec.lastScanResult. + items: + type: string + type: array + observedGeneration: + description: ObservedGeneration is the last reconciled generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.image + name: Image + type: string + - jsonPath: .status.lastScanResult.tagCount + name: Tags + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .status.lastScanResult.scanTime + name: Last scan + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: v1beta2 ImageRepository is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: ImageRepository is the Schema for the imagerepositories API + 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: |- + ImageRepositorySpec defines the parameters for scanning an image + repository, e.g., `fluxcd/flux`. + properties: + accessFrom: + description: |- + AccessFrom defines an ACL for allowing cross-namespace references + to the ImageRepository object based on the caller's namespace labels. + properties: + namespaceSelectors: + description: |- + NamespaceSelectors is the list of namespace selectors to which this ACL applies. + Items in this list are evaluated using a logical OR operation. + items: + description: |- + NamespaceSelector selects the namespaces to which this ACL applies. + An empty map of MatchLabels matches all namespaces in a cluster. + properties: + 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 + type: array + required: + - namespaceSelectors + type: object + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + registry. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + Note: Support for the `caFile`, `certFile` and `keyFile` keys has + been deprecated. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + exclusionList: + default: + - ^.*\.sig$ + description: |- + ExclusionList is a list of regex strings used to exclude certain tags + from being stored in the database. + items: + type: string + maxItems: 25 + type: array + image: + description: Image is the name of the image repository + type: string + insecure: + description: Insecure allows connecting to a non-TLS HTTP container registry. + type: boolean + interval: + description: |- + Interval is the length of time to wait between + scans of the image repository. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + provider: + default: generic + description: |- + The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + When not specified, defaults to 'generic'. + enum: + - generic + - aws + - azure + - gcp + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the container registry. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + secretRef: + description: |- + SecretRef can be given the name of a secret containing + credentials to use for the image registry. The secret should be + created with `kubectl create secret docker-registry`, or the + equivalent. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + the image pull if the service account has attached pull secrets. + maxLength: 253 + type: string + suspend: + description: |- + This flag tells the controller to suspend subsequent image scans. + It does not apply to already started scans. Defaults to false. + type: boolean + timeout: + description: |- + Timeout for image scanning. + Defaults to 'Interval' duration. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + required: + - image + - interval + type: object + status: + default: + observedGeneration: -1 + description: ImageRepositoryStatus defines the observed state of ImageRepository + properties: + canonicalImageName: + description: |- + CanonicalName is the name of the image repository with all the + implied bits made explicit; e.g., `docker.io/library/alpine` + rather than `alpine`. + type: string + conditions: + 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 + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + lastScanResult: + description: LastScanResult contains the number of fetched tags. + properties: + latestTags: + description: |- + LatestTags is a small sample of the tags found in the last scan. + It's the first 10 tags when sorting all the tags in descending + alphabetical order. + items: + type: string + type: array + revision: + description: Revision is a stable hash of the scanned tags. + type: string + scanTime: + description: ScanTime is the time when the last scan was performed. + format: date-time + type: string + tagCount: + description: TagCount is the number of tags found in the last scan. + type: integer + required: + - tagCount + type: object + observedExclusionList: + description: |- + ObservedExclusionList is a list of observed exclusion list. It reflects + the exclusion rules used for the observed scan result in + spec.lastScanResult. + items: + type: string + type: array + observedGeneration: + description: ObservedGeneration is the last reconciled generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: imageupdateautomations.image.toolkit.fluxcd.io +spec: + group: image.toolkit.fluxcd.io + names: + kind: ImageUpdateAutomation + listKind: ImageUpdateAutomationList + plural: imageupdateautomations + shortNames: + - iua + - imgupd + - imgauto + singular: imageupdateautomation + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .status.lastAutomationRunTime + name: Last run + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: ImageUpdateAutomation is the Schema for the imageupdateautomations API + 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: ImageUpdateAutomationSpec defines the desired state of ImageUpdateAutomation + properties: + git: + description: |- + GitSpec contains all the git-specific definitions. This is + technically optional, but in practice mandatory until there are + other kinds of source allowed. + properties: + checkout: + description: |- + Checkout gives the parameters for cloning the git repository, + ready to make changes. If not present, the `spec.ref` field from the + referenced `GitRepository` or its default will be used. + properties: + ref: + description: |- + Reference gives a branch, tag or commit to clone from the Git + repository. + properties: + branch: + description: Branch to check out, defaults to 'master' if no other field is defined. + type: string + commit: + description: |- + Commit SHA to check out, takes precedence over all reference fields. + + This can be combined with Branch to shallow clone the branch, in which + the commit is expected to exist. + type: string + name: + description: |- + Name of the reference to check out; takes precedence over Branch, Tag and SemVer. + + It must be a valid Git reference: https://git-scm.com/docs/git-check-ref-format#_description + Examples: "refs/heads/main", "refs/tags/v0.1.0", "refs/pull/420/head", "refs/merge-requests/1/head" + type: string + semver: + description: SemVer tag expression to check out, takes precedence over Tag. + type: string + tag: + description: Tag to check out, takes precedence over Branch. + type: string + type: object + required: + - ref + type: object + commit: + description: Commit specifies how to commit to the git repository. + properties: + author: + description: |- + Author gives the email and optionally the name to use as the + author of commits. + properties: + email: + description: Email gives the email to provide when making a commit. + type: string + name: + description: Name gives the name to provide when making a commit. + type: string + required: + - email + type: object + messageTemplate: + description: |- + MessageTemplate provides a template for the commit message, + into which will be interpolated the details of the change made. + Note: The `Updated` template field has been removed. Use `Changed` instead. + type: string + messageTemplateValues: + additionalProperties: + type: string + description: |- + MessageTemplateValues provides additional values to be available to the + templating rendering. + type: object + signingKey: + description: SigningKey provides the option to sign commits with a GPG key + properties: + secretRef: + description: |- + SecretRef holds the name to a secret that contains a 'git.asc' key + corresponding to the ASCII Armored file containing the GPG signing + keypair as the value. It must be in the same namespace as the + ImageUpdateAutomation. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - secretRef + type: object + required: + - author + type: object + push: + description: |- + Push specifies how and where to push commits made by the + automation. If missing, commits are pushed (back) to + `.spec.checkout.branch` or its default. + properties: + branch: + description: |- + Branch specifies that commits should be pushed to the branch + named. The branch is created using `.spec.checkout.branch` as the + starting point, if it doesn't already exist. + type: string + options: + additionalProperties: + type: string + description: |- + Options specifies the push options that are sent to the Git + server when performing a push operation. For details, see: + https://git-scm.com/docs/git-push#Documentation/git-push.txt---push-optionltoptiongt + type: object + refspec: + description: |- + Refspec specifies the Git Refspec to use for a push operation. + If both Branch and Refspec are provided, then the commit is pushed + to the branch and also using the specified refspec. + For more details about Git Refspecs, see: + https://git-scm.com/book/en/v2/Git-Internals-The-Refspec + type: string + type: object + required: + - commit + type: object + interval: + description: |- + Interval gives an lower bound for how often the automation + run should be attempted. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + policySelector: + description: |- + PolicySelector allows to filter applied policies based on labels. + By default includes all policies in namespace. + 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 + sourceRef: + description: |- + SourceRef refers to the resource giving access details + to a git repository. + properties: + apiVersion: + description: API version of the referent. + type: string + kind: + default: GitRepository + description: Kind of the referent. + enum: + - GitRepository + type: string + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, defaults to the namespace of the Kubernetes resource object that contains the reference. + type: string + required: + - kind + - name + type: object + suspend: + description: |- + Suspend tells the controller to not run this automation, until + it is unset (or set to false). Defaults to false. + type: boolean + update: + default: + strategy: Setters + description: |- + Update gives the specification for how to update the files in + the repository. This can be left empty, to use the default + value. + properties: + path: + description: |- + Path to the directory containing the manifests to be updated. + Defaults to 'None', which translates to the root path + of the GitRepositoryRef. + type: string + strategy: + default: Setters + description: Strategy names the strategy to be used. + enum: + - Setters + type: string + type: object + required: + - interval + - sourceRef + type: object + status: + default: + observedGeneration: -1 + description: ImageUpdateAutomationStatus defines the observed state of ImageUpdateAutomation + properties: + conditions: + 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 + type: array + lastAutomationRunTime: + description: |- + LastAutomationRunTime records the last time the controller ran + this automation through to completion (even if no updates were + made). + format: date-time + type: string + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + lastPushCommit: + description: |- + LastPushCommit records the SHA1 of the last commit made by the + controller, for this automation object + type: string + lastPushTime: + description: LastPushTime records the time of the last pushed change. + format: date-time + type: string + observedGeneration: + format: int64 + type: integer + observedPolicies: + additionalProperties: + description: ImageRef represents an image reference. + properties: + digest: + description: Digest is the image's digest. + type: string + name: + description: Name is the bare image's name. + type: string + tag: + description: Tag is the image's tag. + type: string + required: + - name + - tag + type: object + description: |- + ObservedPolicies is the list of observed ImagePolicies that were + considered by the ImageUpdateAutomation update process. + type: object + observedSourceRevision: + description: |- + ObservedPolicies []ObservedPolicy `json:"observedPolicies,omitempty"` + ObservedSourceRevision is the last observed source revision. This can be + used to determine if the source has been updated since last observation. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .status.lastAutomationRunTime + name: Last run + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: v1beta2 ImageUpdateAutomation is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: ImageUpdateAutomation is the Schema for the imageupdateautomations API + 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: ImageUpdateAutomationSpec defines the desired state of ImageUpdateAutomation + properties: + git: + description: |- + GitSpec contains all the git-specific definitions. This is + technically optional, but in practice mandatory until there are + other kinds of source allowed. + properties: + checkout: + description: |- + Checkout gives the parameters for cloning the git repository, + ready to make changes. If not present, the `spec.ref` field from the + referenced `GitRepository` or its default will be used. + properties: + ref: + description: |- + Reference gives a branch, tag or commit to clone from the Git + repository. + properties: + branch: + description: Branch to check out, defaults to 'master' if no other field is defined. + type: string + commit: + description: |- + Commit SHA to check out, takes precedence over all reference fields. + + This can be combined with Branch to shallow clone the branch, in which + the commit is expected to exist. + type: string + name: + description: |- + Name of the reference to check out; takes precedence over Branch, Tag and SemVer. + + It must be a valid Git reference: https://git-scm.com/docs/git-check-ref-format#_description + Examples: "refs/heads/main", "refs/tags/v0.1.0", "refs/pull/420/head", "refs/merge-requests/1/head" + type: string + semver: + description: SemVer tag expression to check out, takes precedence over Tag. + type: string + tag: + description: Tag to check out, takes precedence over Branch. + type: string + type: object + required: + - ref + type: object + commit: + description: Commit specifies how to commit to the git repository. + properties: + author: + description: |- + Author gives the email and optionally the name to use as the + author of commits. + properties: + email: + description: Email gives the email to provide when making a commit. + type: string + name: + description: Name gives the name to provide when making a commit. + type: string + required: + - email + type: object + messageTemplate: + description: |- + MessageTemplate provides a template for the commit message, + into which will be interpolated the details of the change made. + Note: The `Updated` template field has been removed. Use `Changed` instead. + type: string + messageTemplateValues: + additionalProperties: + type: string + description: |- + MessageTemplateValues provides additional values to be available to the + templating rendering. + type: object + signingKey: + description: SigningKey provides the option to sign commits with a GPG key + properties: + secretRef: + description: |- + SecretRef holds the name to a secret that contains a 'git.asc' key + corresponding to the ASCII Armored file containing the GPG signing + keypair as the value. It must be in the same namespace as the + ImageUpdateAutomation. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - secretRef + type: object + required: + - author + type: object + push: + description: |- + Push specifies how and where to push commits made by the + automation. If missing, commits are pushed (back) to + `.spec.checkout.branch` or its default. + properties: + branch: + description: |- + Branch specifies that commits should be pushed to the branch + named. The branch is created using `.spec.checkout.branch` as the + starting point, if it doesn't already exist. + type: string + options: + additionalProperties: + type: string + description: |- + Options specifies the push options that are sent to the Git + server when performing a push operation. For details, see: + https://git-scm.com/docs/git-push#Documentation/git-push.txt---push-optionltoptiongt + type: object + refspec: + description: |- + Refspec specifies the Git Refspec to use for a push operation. + If both Branch and Refspec are provided, then the commit is pushed + to the branch and also using the specified refspec. + For more details about Git Refspecs, see: + https://git-scm.com/book/en/v2/Git-Internals-The-Refspec + type: string + type: object + required: + - commit + type: object + interval: + description: |- + Interval gives an lower bound for how often the automation + run should be attempted. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + policySelector: + description: |- + PolicySelector allows to filter applied policies based on labels. + By default includes all policies in namespace. + 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 + sourceRef: + description: |- + SourceRef refers to the resource giving access details + to a git repository. + properties: + apiVersion: + description: API version of the referent. + type: string + kind: + default: GitRepository + description: Kind of the referent. + enum: + - GitRepository + type: string + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, defaults to the namespace of the Kubernetes resource object that contains the reference. + type: string + required: + - kind + - name + type: object + suspend: + description: |- + Suspend tells the controller to not run this automation, until + it is unset (or set to false). Defaults to false. + type: boolean + update: + default: + strategy: Setters + description: |- + Update gives the specification for how to update the files in + the repository. This can be left empty, to use the default + value. + properties: + path: + description: |- + Path to the directory containing the manifests to be updated. + Defaults to 'None', which translates to the root path + of the GitRepositoryRef. + type: string + strategy: + default: Setters + description: Strategy names the strategy to be used. + enum: + - Setters + type: string + type: object + required: + - interval + - sourceRef + type: object + status: + default: + observedGeneration: -1 + description: ImageUpdateAutomationStatus defines the observed state of ImageUpdateAutomation + properties: + conditions: + 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 + type: array + lastAutomationRunTime: + description: |- + LastAutomationRunTime records the last time the controller ran + this automation through to completion (even if no updates were + made). + format: date-time + type: string + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + lastPushCommit: + description: |- + LastPushCommit records the SHA1 of the last commit made by the + controller, for this automation object + type: string + lastPushTime: + description: LastPushTime records the time of the last pushed change. + format: date-time + type: string + observedGeneration: + format: int64 + type: integer + observedPolicies: + additionalProperties: + description: ImageRef represents an image reference. + properties: + digest: + description: Digest is the image's digest. + type: string + name: + description: Name is the bare image's name. + type: string + tag: + description: Tag is the image's tag. + type: string + required: + - name + - tag + type: object + description: |- + ObservedPolicies is the list of observed ImagePolicies that were + considered by the ImageUpdateAutomation update process. + type: object + observedSourceRevision: + description: |- + ObservedPolicies []ObservedPolicy `json:"observedPolicies,omitempty"` + ObservedSourceRevision is the last observed source revision. This can be + used to determine if the source has been updated since last observation. + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: kustomizations.kustomize.toolkit.fluxcd.io +spec: + group: kustomize.toolkit.fluxcd.io + names: + kind: Kustomization + listKind: KustomizationList + plural: kustomizations + shortNames: + - ks + singular: kustomization + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + description: Kustomization is the Schema for the kustomizations API. + 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: |- + KustomizationSpec defines the configuration to calculate the desired state + from a Source using Kustomize. + properties: + commonMetadata: + description: |- + CommonMetadata specifies the common labels and annotations that are + applied to all resources. Any existing label or annotation will be + overridden if its key matches a common one. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to the object's metadata. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to the object's metadata. + type: object + type: object + components: + description: Components specifies relative paths to kustomize Components. + items: + type: string + type: array + decryption: + description: Decrypt Kubernetes secrets before applying them on the cluster. + properties: + provider: + description: Provider is the name of the decryption engine. + enum: + - sops + type: string + secretRef: + description: |- + The secret name containing the private OpenPGP keys used for decryption. + A static credential for a cloud provider defined inside the Secret + takes priority to secret-less authentication with the ServiceAccountName + field. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the service account used to + authenticate with KMS services from cloud providers. If a + static credential for a given cloud provider is defined + inside the Secret referenced by SecretRef, that static + credential takes priority. + type: string + required: + - provider + type: object + deletionPolicy: + description: |- + DeletionPolicy can be used to control garbage collection when this + Kustomization is deleted. Valid values are ('MirrorPrune', 'Delete', + 'WaitForTermination', 'Orphan'). 'MirrorPrune' mirrors the Prune field + (orphan if false, delete if true). Defaults to 'MirrorPrune'. + enum: + - MirrorPrune + - Delete + - WaitForTermination + - Orphan + type: string + dependsOn: + description: |- + DependsOn may contain a DependencyReference slice + with references to Kustomization resources that must be ready before this + Kustomization can be reconciled. + items: + description: DependencyReference defines a Kustomization dependency on another Kustomization resource. + properties: + name: + description: Name of the referent. + type: string + namespace: + description: |- + Namespace of the referent, defaults to the namespace of the Kustomization + resource object that contains the reference. + type: string + readyExpr: + description: |- + ReadyExpr is a CEL expression that can be used to assess the readiness + of a dependency. When specified, the built-in readiness check + is replaced by the logic defined in the CEL expression. + To make the CEL expression additive to the built-in readiness check, + the feature gate `AdditiveCELDependencyCheck` must be set to `true`. + type: string + required: + - name + type: object + type: array + force: + default: false + description: |- + Force instructs the controller to recreate resources + when patching fails due to an immutable field change. + type: boolean + healthCheckExprs: + description: |- + HealthCheckExprs is a list of healthcheck expressions for evaluating the + health of custom resources using Common Expression Language (CEL). + The expressions are evaluated only when Wait or HealthChecks are specified. + items: + description: CustomHealthCheck defines the health check for custom resources. + properties: + apiVersion: + description: APIVersion of the custom resource under evaluation. + type: string + current: + description: |- + Current is the CEL expression that determines if the status + of the custom resource has reached the desired state. + type: string + failed: + description: |- + Failed is the CEL expression that determines if the status + of the custom resource has failed to reach the desired state. + type: string + inProgress: + description: |- + InProgress is the CEL expression that determines if the status + of the custom resource has not yet reached the desired state. + type: string + kind: + description: Kind of the custom resource under evaluation. + type: string + required: + - apiVersion + - current + - kind + type: object + type: array + healthChecks: + description: A list of resources to be included in the health assessment. + items: + description: |- + NamespacedObjectKindReference contains enough information to locate the typed referenced Kubernetes resource object + in any namespace. + properties: + apiVersion: + description: API version of the referent, if not specified the Kubernetes preferred version will be used. + type: string + kind: + description: Kind of the referent. + type: string + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it acts as LocalObjectReference. + type: string + required: + - kind + - name + type: object + type: array + ignoreMissingComponents: + description: |- + IgnoreMissingComponents instructs the controller to ignore Components paths + not found in source by removing them from the generated kustomization.yaml + before running kustomize build. + type: boolean + images: + description: |- + Images is a list of (image name, new name, new tag or digest) + for changing image names, tags or digests. This can also be achieved with a + patch, but this operator is simpler to specify. + items: + description: Image contains an image name, a new name, a new tag or digest, which will replace the original name and tag. + properties: + digest: + description: |- + Digest is the value used to replace the original image tag. + If digest is present NewTag value is ignored. + type: string + name: + description: Name is a tag-less image name. + type: string + newName: + description: NewName is the value used to replace the original name. + type: string + newTag: + description: NewTag is the value used to replace the original tag. + type: string + required: + - name + type: object + type: array + interval: + description: |- + The interval at which to reconcile the Kustomization. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + kubeConfig: + description: |- + The KubeConfig for reconciling the Kustomization on a remote cluster. + When used in combination with KustomizationSpec.ServiceAccountName, + forces the controller to act on behalf of that Service Account at the + target cluster. + If the --default-service-account flag is set, its value will be used as + a controller level fallback for when KustomizationSpec.ServiceAccountName + is empty. + properties: + configMapRef: + description: |- + ConfigMapRef holds an optional name of a ConfigMap that contains + the following keys: + + - `provider`: the provider to use. One of `aws`, `azure`, `gcp`, or + `generic`. Required. + - `cluster`: the fully qualified resource name of the Kubernetes + cluster in the cloud provider API. Not used by the `generic` + provider. Required when one of `address` or `ca.crt` is not set. + - `address`: the address of the Kubernetes API server. Required + for `generic`. For the other providers, if not specified, the + first address in the cluster resource will be used, and if + specified, it must match one of the addresses in the cluster + resource. + If audiences is not set, will be used as the audience for the + `generic` provider. + - `ca.crt`: the optional PEM-encoded CA certificate for the + Kubernetes API server. If not set, the controller will use the + CA certificate from the cluster resource. + - `audiences`: the optional audiences as a list of + line-break-separated strings for the Kubernetes ServiceAccount + token. Defaults to the `address` for the `generic` provider, or + to specific values for the other providers depending on the + provider. + - `serviceAccountName`: the optional name of the Kubernetes + ServiceAccount in the same namespace that should be used + for authentication. If not specified, the controller + ServiceAccount will be used. + + Mutually exclusive with SecretRef. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + secretRef: + description: |- + SecretRef holds an optional name of a secret that contains a key with + the kubeconfig file as the value. If no key is set, the key will default + to 'value'. Mutually exclusive with ConfigMapRef. + It is recommended that the kubeconfig is self-contained, and the secret + is regularly updated if credentials such as a cloud-access-token expire. + Cloud specific `cmd-path` auth helpers will not function without adding + binaries and credentials to the Pod that is responsible for reconciling + Kubernetes resources. Supported only for the generic provider. + properties: + key: + description: Key in the Secret, when not specified an implementation-specific default key is used. + type: string + name: + description: Name of the Secret. + type: string + required: + - name + type: object + type: object + x-kubernetes-validations: + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: has(self.configMapRef) || has(self.secretRef) + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: '!has(self.configMapRef) || !has(self.secretRef)' + namePrefix: + description: NamePrefix will prefix the names of all managed resources. + maxLength: 200 + minLength: 1 + type: string + nameSuffix: + description: NameSuffix will suffix the names of all managed resources. + maxLength: 200 + minLength: 1 + type: string + patches: + description: |- + Strategic merge and JSON patches, defined as inline YAML objects, + capable of targeting objects based on kind, label and annotation selectors. + items: + description: |- + Patch contains an inline StrategicMerge or JSON6902 patch, and the target the patch should + be applied to. + properties: + patch: + description: |- + Patch contains an inline StrategicMerge patch or an inline JSON6902 patch with + an array of operation objects. + type: string + target: + description: Target points to the resources that the patch document should be applied to. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - patch + type: object + type: array + path: + description: |- + Path to the directory containing the kustomization.yaml file, or the + set of plain YAMLs a kustomization.yaml should be generated for. + Defaults to 'None', which translates to the root path of the SourceRef. + type: string + postBuild: + description: |- + PostBuild describes which actions to perform on the YAML manifest + generated by building the kustomize overlay. + properties: + substitute: + additionalProperties: + type: string + description: |- + Substitute holds a map of key/value pairs. + The variables defined in your YAML manifests that match any of the keys + defined in the map will be substituted with the set value. + Includes support for bash string replacement functions + e.g. ${var:=default}, ${var:position} and ${var/substring/replacement}. + type: object + substituteFrom: + description: |- + SubstituteFrom holds references to ConfigMaps and Secrets containing + the variables and their values to be substituted in the YAML manifests. + The ConfigMap and the Secret data keys represent the var names, and they + must match the vars declared in the manifests for the substitution to + happen. + items: + description: |- + SubstituteReference contains a reference to a resource containing + the variables name and value. + properties: + kind: + description: Kind of the values referent, valid values are ('Secret', 'ConfigMap'). + enum: + - Secret + - ConfigMap + type: string + name: + description: |- + Name of the values referent. Should reside in the same namespace as the + referring resource. + maxLength: 253 + minLength: 1 + type: string + optional: + default: false + description: |- + Optional indicates whether the referenced resource must exist, or whether to + tolerate its absence. If true and the referenced resource is absent, proceed + as if the resource was present but empty, without any variables defined. + type: boolean + required: + - kind + - name + type: object + type: array + type: object + prune: + description: Prune enables garbage collection. + type: boolean + retryInterval: + description: |- + The interval at which to retry a previously failed reconciliation. + When not specified, the controller uses the KustomizationSpec.Interval + value to retry failures. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + serviceAccountName: + description: |- + The name of the Kubernetes service account to impersonate + when reconciling this Kustomization. + type: string + sourceRef: + description: Reference of the source where the kustomization file is. + properties: + apiVersion: + description: API version of the referent. + type: string + kind: + description: Kind of the referent. + enum: + - OCIRepository + - GitRepository + - Bucket + - ExternalArtifact + type: string + name: + description: Name of the referent. + type: string + namespace: + description: |- + Namespace of the referent, defaults to the namespace of the Kubernetes + resource object that contains the reference. + type: string + required: + - kind + - name + type: object + suspend: + description: |- + This flag tells the controller to suspend subsequent kustomize executions, + it does not apply to already started executions. Defaults to false. + type: boolean + targetNamespace: + description: |- + TargetNamespace sets or overrides the namespace in the + kustomization.yaml file. + maxLength: 63 + minLength: 1 + type: string + timeout: + description: |- + Timeout for validation, apply and health checking operations. + Defaults to 'Interval' duration. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + wait: + description: |- + Wait instructs the controller to check the health of all the reconciled + resources. When enabled, the HealthChecks are ignored. Defaults to false. + type: boolean + required: + - interval + - prune + - sourceRef + type: object + status: + default: + observedGeneration: -1 + description: KustomizationStatus defines the observed state of a kustomization. + properties: + conditions: + 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 + type: array + history: + description: |- + History contains a set of snapshots of the last reconciliation attempts + tracking the revision, the state and the duration of each attempt. + items: + description: |- + Snapshot represents a point-in-time record of a group of resources reconciliation, + including timing information, status, and a unique digest identifier. + properties: + digest: + description: Digest is the checksum in the format `:` of the resources in this snapshot. + type: string + firstReconciled: + description: FirstReconciled is the time when this revision was first reconciled to the cluster. + format: date-time + type: string + lastReconciled: + description: LastReconciled is the time when this revision was last reconciled to the cluster. + format: date-time + type: string + lastReconciledDuration: + description: LastReconciledDuration is time it took to reconcile the resources in this revision. + type: string + lastReconciledStatus: + description: LastReconciledStatus is the status of the last reconciliation. + type: string + metadata: + additionalProperties: + type: string + description: Metadata contains additional information about the snapshot. + type: object + totalReconciliations: + description: TotalReconciliations is the total number of reconciliations that have occurred for this snapshot. + format: int64 + type: integer + required: + - digest + - firstReconciled + - lastReconciled + - lastReconciledDuration + - lastReconciledStatus + - totalReconciliations + type: object + type: array + inventory: + description: |- + Inventory contains the list of Kubernetes resource object references that + have been successfully applied. + properties: + entries: + description: Entries of Kubernetes resource object references. + items: + description: ResourceRef contains the information necessary to locate a resource within a cluster. + properties: + id: + description: |- + ID is the string representation of the Kubernetes resource object's metadata, + in the format '___'. + type: string + v: + description: Version is the API version of the Kubernetes resource object's kind. + type: string + required: + - id + - v + type: object + type: array + required: + - entries + type: object + lastAppliedOriginRevision: + description: |- + The last successfully applied origin revision. + Equals the origin revision of the applied Artifact from the referenced Source. + Usually present on the Metadata of the applied Artifact and depends on the + Source type, e.g. for OCI it's the value associated with the key + "org.opencontainers.image.revision". + type: string + lastAppliedRevision: + description: |- + The last successfully applied revision. + Equals the Revision of the applied Artifact from the referenced Source. + type: string + lastAttemptedRevision: + description: LastAttemptedRevision is the revision of the last reconciliation attempt. + type: string + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last reconciled generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 Kustomization is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: Kustomization is the Schema for the kustomizations API. + 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: KustomizationSpec defines the configuration to calculate the desired state from a Source using Kustomize. + properties: + commonMetadata: + description: |- + CommonMetadata specifies the common labels and annotations that are applied to all resources. + Any existing label or annotation will be overridden if its key matches a common one. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to the object's metadata. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to the object's metadata. + type: object + type: object + components: + description: Components specifies relative paths to specifications of other Components. + items: + type: string + type: array + decryption: + description: Decrypt Kubernetes secrets before applying them on the cluster. + properties: + provider: + description: Provider is the name of the decryption engine. + enum: + - sops + type: string + secretRef: + description: The secret name containing the private OpenPGP keys used for decryption. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + dependsOn: + description: |- + DependsOn may contain a meta.NamespacedObjectReference slice + with references to Kustomization resources that must be ready before this + Kustomization can be reconciled. + items: + description: |- + NamespacedObjectReference contains enough information to locate the referenced Kubernetes resource object in any + namespace. + properties: + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it acts as LocalObjectReference. + type: string + required: + - name + type: object + type: array + force: + default: false + description: |- + Force instructs the controller to recreate resources + when patching fails due to an immutable field change. + type: boolean + healthChecks: + description: A list of resources to be included in the health assessment. + items: + description: |- + NamespacedObjectKindReference contains enough information to locate the typed referenced Kubernetes resource object + in any namespace. + properties: + apiVersion: + description: API version of the referent, if not specified the Kubernetes preferred version will be used. + type: string + kind: + description: Kind of the referent. + type: string + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it acts as LocalObjectReference. + type: string + required: + - kind + - name + type: object + type: array + images: + description: |- + Images is a list of (image name, new name, new tag or digest) + for changing image names, tags or digests. This can also be achieved with a + patch, but this operator is simpler to specify. + items: + description: Image contains an image name, a new name, a new tag or digest, which will replace the original name and tag. + properties: + digest: + description: |- + Digest is the value used to replace the original image tag. + If digest is present NewTag value is ignored. + type: string + name: + description: Name is a tag-less image name. + type: string + newName: + description: NewName is the value used to replace the original name. + type: string + newTag: + description: NewTag is the value used to replace the original tag. + type: string + required: + - name + type: object + type: array + interval: + description: The interval at which to reconcile the Kustomization. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + kubeConfig: + description: |- + The KubeConfig for reconciling the Kustomization on a remote cluster. + When used in combination with KustomizationSpec.ServiceAccountName, + forces the controller to act on behalf of that Service Account at the + target cluster. + If the --default-service-account flag is set, its value will be used as + a controller level fallback for when KustomizationSpec.ServiceAccountName + is empty. + properties: + configMapRef: + description: |- + ConfigMapRef holds an optional name of a ConfigMap that contains + the following keys: + + - `provider`: the provider to use. One of `aws`, `azure`, `gcp`, or + `generic`. Required. + - `cluster`: the fully qualified resource name of the Kubernetes + cluster in the cloud provider API. Not used by the `generic` + provider. Required when one of `address` or `ca.crt` is not set. + - `address`: the address of the Kubernetes API server. Required + for `generic`. For the other providers, if not specified, the + first address in the cluster resource will be used, and if + specified, it must match one of the addresses in the cluster + resource. + If audiences is not set, will be used as the audience for the + `generic` provider. + - `ca.crt`: the optional PEM-encoded CA certificate for the + Kubernetes API server. If not set, the controller will use the + CA certificate from the cluster resource. + - `audiences`: the optional audiences as a list of + line-break-separated strings for the Kubernetes ServiceAccount + token. Defaults to the `address` for the `generic` provider, or + to specific values for the other providers depending on the + provider. + - `serviceAccountName`: the optional name of the Kubernetes + ServiceAccount in the same namespace that should be used + for authentication. If not specified, the controller + ServiceAccount will be used. + + Mutually exclusive with SecretRef. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + secretRef: + description: |- + SecretRef holds an optional name of a secret that contains a key with + the kubeconfig file as the value. If no key is set, the key will default + to 'value'. Mutually exclusive with ConfigMapRef. + It is recommended that the kubeconfig is self-contained, and the secret + is regularly updated if credentials such as a cloud-access-token expire. + Cloud specific `cmd-path` auth helpers will not function without adding + binaries and credentials to the Pod that is responsible for reconciling + Kubernetes resources. Supported only for the generic provider. + properties: + key: + description: Key in the Secret, when not specified an implementation-specific default key is used. + type: string + name: + description: Name of the Secret. + type: string + required: + - name + type: object + type: object + x-kubernetes-validations: + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: has(self.configMapRef) || has(self.secretRef) + - message: exactly one of spec.kubeConfig.configMapRef or spec.kubeConfig.secretRef must be specified + rule: '!has(self.configMapRef) || !has(self.secretRef)' + patches: + description: |- + Strategic merge and JSON patches, defined as inline YAML objects, + capable of targeting objects based on kind, label and annotation selectors. + items: + description: |- + Patch contains an inline StrategicMerge or JSON6902 patch, and the target the patch should + be applied to. + properties: + patch: + description: |- + Patch contains an inline StrategicMerge patch or an inline JSON6902 patch with + an array of operation objects. + type: string + target: + description: Target points to the resources that the patch document should be applied to. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - patch + type: object + type: array + patchesJson6902: + description: |- + JSON 6902 patches, defined as inline YAML objects. + Deprecated: Use Patches instead. + items: + description: JSON6902Patch contains a JSON6902 patch and the target the patch should be applied to. + properties: + patch: + description: Patch contains the JSON6902 patch document with an array of operation objects. + items: + description: |- + JSON6902 is a JSON6902 operation object. + https://datatracker.ietf.org/doc/html/rfc6902#section-4 + properties: + from: + description: |- + From contains a JSON-pointer value that references a location within the target document where the operation is + performed. The meaning of the value depends on the value of Op, and is NOT taken into account by all operations. + type: string + op: + description: |- + Op indicates the operation to perform. Its value MUST be one of "add", "remove", "replace", "move", "copy", or + "test". + https://datatracker.ietf.org/doc/html/rfc6902#section-4 + enum: + - test + - remove + - add + - replace + - move + - copy + type: string + path: + description: |- + Path contains the JSON-pointer value that references a location within the target document where the operation + is performed. The meaning of the value depends on the value of Op. + type: string + value: + description: |- + Value contains a valid JSON structure. The meaning of the value depends on the value of Op, and is NOT taken into + account by all operations. + x-kubernetes-preserve-unknown-fields: true + required: + - op + - path + type: object + type: array + target: + description: Target points to the resources that the patch document should be applied to. + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource annotations. + type: string + group: + description: |- + Group is the API group to select resources from. + Together with Version and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + kind: + description: |- + Kind of the API Group to select resources from. + Together with Group and Version it is capable of unambiguously + identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches with the resource labels. + type: string + name: + description: Name to match resources with. + type: string + namespace: + description: Namespace to select resources from. + type: string + version: + description: |- + Version of the API Group to select resources from. + Together with Group and Kind it is capable of unambiguously identifying and/or selecting resources. + https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/api-group.md + type: string + type: object + required: + - patch + - target + type: object + type: array + patchesStrategicMerge: + description: |- + Strategic merge patches, defined as inline YAML objects. + Deprecated: Use Patches instead. + items: + x-kubernetes-preserve-unknown-fields: true + type: array + path: + description: |- + Path to the directory containing the kustomization.yaml file, or the + set of plain YAMLs a kustomization.yaml should be generated for. + Defaults to 'None', which translates to the root path of the SourceRef. + type: string + postBuild: + description: |- + PostBuild describes which actions to perform on the YAML manifest + generated by building the kustomize overlay. + properties: + substitute: + additionalProperties: + type: string + description: |- + Substitute holds a map of key/value pairs. + The variables defined in your YAML manifests + that match any of the keys defined in the map + will be substituted with the set value. + Includes support for bash string replacement functions + e.g. ${var:=default}, ${var:position} and ${var/substring/replacement}. + type: object + substituteFrom: + description: |- + SubstituteFrom holds references to ConfigMaps and Secrets containing + the variables and their values to be substituted in the YAML manifests. + The ConfigMap and the Secret data keys represent the var names and they + must match the vars declared in the manifests for the substitution to happen. + items: + description: |- + SubstituteReference contains a reference to a resource containing + the variables name and value. + properties: + kind: + description: Kind of the values referent, valid values are ('Secret', 'ConfigMap'). + enum: + - Secret + - ConfigMap + type: string + name: + description: |- + Name of the values referent. Should reside in the same namespace as the + referring resource. + maxLength: 253 + minLength: 1 + type: string + optional: + default: false + description: |- + Optional indicates whether the referenced resource must exist, or whether to + tolerate its absence. If true and the referenced resource is absent, proceed + as if the resource was present but empty, without any variables defined. + type: boolean + required: + - kind + - name + type: object + type: array + type: object + prune: + description: Prune enables garbage collection. + type: boolean + retryInterval: + description: |- + The interval at which to retry a previously failed reconciliation. + When not specified, the controller uses the KustomizationSpec.Interval + value to retry failures. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + serviceAccountName: + description: |- + The name of the Kubernetes service account to impersonate + when reconciling this Kustomization. + type: string + sourceRef: + description: Reference of the source where the kustomization file is. + properties: + apiVersion: + description: API version of the referent. + type: string + kind: + description: Kind of the referent. + enum: + - OCIRepository + - GitRepository + - Bucket + type: string + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, defaults to the namespace of the Kubernetes resource object that contains the reference. + type: string + required: + - kind + - name + type: object + suspend: + description: |- + This flag tells the controller to suspend subsequent kustomize executions, + it does not apply to already started executions. Defaults to false. + type: boolean + targetNamespace: + description: |- + TargetNamespace sets or overrides the namespace in the + kustomization.yaml file. + maxLength: 63 + minLength: 1 + type: string + timeout: + description: |- + Timeout for validation, apply and health checking operations. + Defaults to 'Interval' duration. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + validation: + description: 'Deprecated: Not used in v1beta2.' + enum: + - none + - client + - server + type: string + wait: + description: |- + Wait instructs the controller to check the health of all the reconciled resources. + When enabled, the HealthChecks are ignored. Defaults to false. + type: boolean + required: + - interval + - prune + - sourceRef + type: object + status: + default: + observedGeneration: -1 + description: KustomizationStatus defines the observed state of a kustomization. + properties: + conditions: + 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 + type: array + inventory: + description: Inventory contains the list of Kubernetes resource object references that have been successfully applied. + properties: + entries: + description: Entries of Kubernetes resource object references. + items: + description: ResourceRef contains the information necessary to locate a resource within a cluster. + properties: + id: + description: |- + ID is the string representation of the Kubernetes resource object's metadata, + in the format '___'. + type: string + v: + description: Version is the API version of the Kubernetes resource object's kind. + type: string + required: + - id + - v + type: object + type: array + required: + - entries + type: object + lastAppliedRevision: + description: |- + The last successfully applied revision. + Equals the Revision of the applied Artifact from the referenced Source. + type: string + lastAttemptedRevision: + description: LastAttemptedRevision is the revision of the last reconciliation attempt. + type: string + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last reconciled generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: ocirepositories.source.toolkit.fluxcd.io +spec: + group: source.toolkit.fluxcd.io + names: + kind: OCIRepository + listKind: OCIRepositoryList + plural: ocirepositories + shortNames: + - ocirepo + singular: ocirepository + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.url + name: URL + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: OCIRepository is the Schema for the ocirepositories API + 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: OCIRepositorySpec defines the desired state of OCIRepository + properties: + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + registry. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + ignore: + description: |- + Ignore overrides the set of excluded patterns in the .sourceignore format + (which is the same as .gitignore). If not provided, a default will be used, + consult the documentation for your version to find out what those are. + type: string + insecure: + description: Insecure allows connecting to a non-TLS HTTP container registry. + type: boolean + interval: + description: |- + Interval at which the OCIRepository URL is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + layerSelector: + description: |- + LayerSelector specifies which layer should be extracted from the OCI artifact. + When not specified, the first layer found in the artifact is selected. + properties: + mediaType: + description: |- + MediaType specifies the OCI media type of the layer + which should be extracted from the OCI Artifact. The + first layer matching this type is selected. + type: string + operation: + description: |- + Operation specifies how the selected layer should be processed. + By default, the layer compressed content is extracted to storage. + When the operation is set to 'copy', the layer compressed content + is persisted to storage as it is. + enum: + - extract + - copy + type: string + type: object + provider: + default: generic + description: |- + The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + When not specified, defaults to 'generic'. + enum: + - generic + - aws + - azure + - gcp + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the container registry. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + ref: + description: |- + The OCI reference to pull and monitor for changes, + defaults to the latest tag. + properties: + digest: + description: |- + Digest is the image digest to pull, takes precedence over SemVer. + The value should be in the format 'sha256:'. + type: string + semver: + description: |- + SemVer is the range of tags to pull selecting the latest within + the range, takes precedence over Tag. + type: string + semverFilter: + description: SemverFilter is a regex pattern to filter the tags within the SemVer range. + type: string + tag: + description: Tag is the image tag to pull, defaults to latest. + type: string + type: object + secretRef: + description: |- + SecretRef contains the secret name containing the registry login + credentials to resolve image metadata. + The secret must be of type kubernetes.io/dockerconfigjson. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + the image pull if the service account has attached pull secrets. For more information: + https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + type: string + suspend: + description: This flag tells the controller to suspend the reconciliation of this source. + type: boolean + timeout: + default: 60s + description: The timeout for remote OCI Repository operations like pulling, defaults to 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + url: + description: |- + URL is a reference to an OCI artifact repository hosted + on a remote container registry. + pattern: ^oci://.*$ + type: string + verify: + description: |- + Verify contains the secret name containing the trusted public keys + used to verify the signature and specifies which provider to use to check + whether OCI image is authentic. + properties: + matchOIDCIdentity: + description: |- + MatchOIDCIdentity specifies the identity matching criteria to use + while verifying an OCI artifact which was signed using Cosign keyless + signing. The artifact's identity is deemed to be verified if any of the + specified matchers match against the identity. + items: + description: |- + OIDCIdentityMatch specifies options for verifying the certificate identity, + i.e. the issuer and the subject of the certificate. + properties: + issuer: + description: |- + Issuer specifies the regex pattern to match against to verify + the OIDC issuer in the Fulcio certificate. The pattern must be a + valid Go regular expression. + type: string + subject: + description: |- + Subject specifies the regex pattern to match against to verify + the identity subject in the Fulcio certificate. The pattern must + be a valid Go regular expression. + type: string + required: + - issuer + - subject + type: object + type: array + provider: + default: cosign + description: Provider specifies the technology used to sign the OCI Artifact. + enum: + - cosign + - notation + type: string + secretRef: + description: |- + SecretRef specifies the Kubernetes Secret containing the + trusted public keys. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + required: + - interval + - url + type: object + status: + default: + observedGeneration: -1 + description: OCIRepositoryStatus defines the observed state of OCIRepository + properties: + artifact: + description: Artifact represents the output of the last successful OCI Repository sync. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the OCIRepository. + 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 + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + observedIgnore: + description: |- + ObservedIgnore is the observed exclusion patterns used for constructing + the source artifact. + type: string + observedLayerSelector: + description: |- + ObservedLayerSelector is the observed layer selector used for constructing + the source artifact. + properties: + mediaType: + description: |- + MediaType specifies the OCI media type of the layer + which should be extracted from the OCI Artifact. The + first layer matching this type is selected. + type: string + operation: + description: |- + Operation specifies how the selected layer should be processed. + By default, the layer compressed content is extracted to storage. + When the operation is set to 'copy', the layer compressed content + is persisted to storage as it is. + enum: + - extract + - copy + type: string + type: object + url: + description: URL is the download link for the artifact output of the last OCI Repository sync. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.url + name: URL + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: v1beta2 OCIRepository is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: OCIRepository is the Schema for the ocirepositories API + 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: OCIRepositorySpec defines the desired state of OCIRepository + properties: + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + registry. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + + Note: Support for the `caFile`, `certFile` and `keyFile` keys have + been deprecated. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + ignore: + description: |- + Ignore overrides the set of excluded patterns in the .sourceignore format + (which is the same as .gitignore). If not provided, a default will be used, + consult the documentation for your version to find out what those are. + type: string + insecure: + description: Insecure allows connecting to a non-TLS HTTP container registry. + type: boolean + interval: + description: |- + Interval at which the OCIRepository URL is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + layerSelector: + description: |- + LayerSelector specifies which layer should be extracted from the OCI artifact. + When not specified, the first layer found in the artifact is selected. + properties: + mediaType: + description: |- + MediaType specifies the OCI media type of the layer + which should be extracted from the OCI Artifact. The + first layer matching this type is selected. + type: string + operation: + description: |- + Operation specifies how the selected layer should be processed. + By default, the layer compressed content is extracted to storage. + When the operation is set to 'copy', the layer compressed content + is persisted to storage as it is. + enum: + - extract + - copy + type: string + type: object + provider: + default: generic + description: |- + The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + When not specified, defaults to 'generic'. + enum: + - generic + - aws + - azure + - gcp + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the container registry. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + ref: + description: |- + The OCI reference to pull and monitor for changes, + defaults to the latest tag. + properties: + digest: + description: |- + Digest is the image digest to pull, takes precedence over SemVer. + The value should be in the format 'sha256:'. + type: string + semver: + description: |- + SemVer is the range of tags to pull selecting the latest within + the range, takes precedence over Tag. + type: string + semverFilter: + description: SemverFilter is a regex pattern to filter the tags within the SemVer range. + type: string + tag: + description: Tag is the image tag to pull, defaults to latest. + type: string + type: object + secretRef: + description: |- + SecretRef contains the secret name containing the registry login + credentials to resolve image metadata. + The secret must be of type kubernetes.io/dockerconfigjson. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + the image pull if the service account has attached pull secrets. For more information: + https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + type: string + suspend: + description: This flag tells the controller to suspend the reconciliation of this source. + type: boolean + timeout: + default: 60s + description: The timeout for remote OCI Repository operations like pulling, defaults to 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + url: + description: |- + URL is a reference to an OCI artifact repository hosted + on a remote container registry. + pattern: ^oci://.*$ + type: string + verify: + description: |- + Verify contains the secret name containing the trusted public keys + used to verify the signature and specifies which provider to use to check + whether OCI image is authentic. + properties: + matchOIDCIdentity: + description: |- + MatchOIDCIdentity specifies the identity matching criteria to use + while verifying an OCI artifact which was signed using Cosign keyless + signing. The artifact's identity is deemed to be verified if any of the + specified matchers match against the identity. + items: + description: |- + OIDCIdentityMatch specifies options for verifying the certificate identity, + i.e. the issuer and the subject of the certificate. + properties: + issuer: + description: |- + Issuer specifies the regex pattern to match against to verify + the OIDC issuer in the Fulcio certificate. The pattern must be a + valid Go regular expression. + type: string + subject: + description: |- + Subject specifies the regex pattern to match against to verify + the identity subject in the Fulcio certificate. The pattern must + be a valid Go regular expression. + type: string + required: + - issuer + - subject + type: object + type: array + provider: + default: cosign + description: Provider specifies the technology used to sign the OCI Artifact. + enum: + - cosign + - notation + type: string + secretRef: + description: |- + SecretRef specifies the Kubernetes Secret containing the + trusted public keys. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + required: + - interval + - url + type: object + status: + default: + observedGeneration: -1 + description: OCIRepositoryStatus defines the observed state of OCIRepository + properties: + artifact: + description: Artifact represents the output of the last successful OCI Repository sync. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the OCIRepository. + 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 + type: array + contentConfigChecksum: + description: |- + ContentConfigChecksum is a checksum of all the configurations related to + the content of the source artifact: + - .spec.ignore + - .spec.layerSelector + observed in .status.observedGeneration version of the object. This can + be used to determine if the content configuration has changed and the + artifact needs to be rebuilt. + It has the format of `:`, for example: `sha256:`. + + Deprecated: Replaced with explicit fields for observed artifact content + config in the status. + type: string + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + observedIgnore: + description: |- + ObservedIgnore is the observed exclusion patterns used for constructing + the source artifact. + type: string + observedLayerSelector: + description: |- + ObservedLayerSelector is the observed layer selector used for constructing + the source artifact. + properties: + mediaType: + description: |- + MediaType specifies the OCI media type of the layer + which should be extracted from the OCI Artifact. The + first layer matching this type is selected. + type: string + operation: + description: |- + Operation specifies how the selected layer should be processed. + By default, the layer compressed content is extracted to storage. + When the operation is set to 'copy', the layer compressed content + is persisted to storage as it is. + enum: + - extract + - copy + type: string + type: object + url: + description: URL is the download link for the artifact output of the last OCI Repository sync. + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: providers.notification.toolkit.fluxcd.io +spec: + group: notification.toolkit.fluxcd.io + names: + kind: Provider + listKind: ProviderList + plural: providers + singular: provider + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 Provider is deprecated, upgrade to v1beta3 + name: v1beta2 + schema: + openAPIV3Schema: + description: Provider is the Schema for the providers API. + 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: ProviderSpec defines the desired state of the Provider. + properties: + address: + description: |- + Address specifies the endpoint, in a generic sense, to where alerts are sent. + What kind of endpoint depends on the specific Provider type being used. + For the generic Provider, for example, this is an HTTP/S address. + For other Provider types this could be a project ID or a namespace. + maxLength: 2048 + type: string + certSecretRef: + description: |- + CertSecretRef specifies the Secret containing + a PEM-encoded CA certificate (in the `ca.crt` key). + + Note: Support for the `caFile` key has + been deprecated. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + channel: + description: Channel specifies the destination channel where events should be posted. + maxLength: 2048 + type: string + interval: + description: Interval at which to reconcile the Provider with its Secret references. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + proxy: + description: Proxy the HTTP/S address of the proxy server. + maxLength: 2048 + pattern: ^(http|https)://.*$ + type: string + secretRef: + description: |- + SecretRef specifies the Secret containing the authentication + credentials for this Provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend subsequent + events handling for this Provider. + type: boolean + timeout: + description: Timeout for sending alerts to the Provider. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + type: + description: Type specifies which Provider implementation to use. + enum: + - slack + - discord + - msteams + - rocket + - generic + - generic-hmac + - github + - gitlab + - gitea + - bitbucketserver + - bitbucket + - azuredevops + - googlechat + - googlepubsub + - webex + - sentry + - azureeventhub + - telegram + - lark + - matrix + - opsgenie + - alertmanager + - grafana + - githubdispatch + - pagerduty + - datadog + type: string + username: + description: Username specifies the name under which events are posted. + maxLength: 2048 + type: string + required: + - type + type: object + status: + default: + observedGeneration: -1 + description: ProviderStatus defines the observed state of the Provider. + properties: + conditions: + description: Conditions holds the conditions for the Provider. + 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 + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last reconciled generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta3 + schema: + openAPIV3Schema: + description: Provider is the Schema for the providers API + 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: ProviderSpec defines the desired state of the Provider. + properties: + address: + description: |- + Address specifies the endpoint, in a generic sense, to where alerts are sent. + What kind of endpoint depends on the specific Provider type being used. + For the generic Provider, for example, this is an HTTP/S address. + For other Provider types this could be a project ID or a namespace. + maxLength: 2048 + type: string + certSecretRef: + description: |- + CertSecretRef specifies the Secret containing TLS certificates + for secure communication. + + Supported configurations: + - CA-only: Server authentication (provide ca.crt only) + - mTLS: Mutual authentication (provide ca.crt + tls.crt + tls.key) + - Client-only: Client authentication with system CA (provide tls.crt + tls.key only) + + Legacy keys "caFile", "certFile", "keyFile" are supported but deprecated. Use "ca.crt", "tls.crt", "tls.key" instead. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + channel: + description: Channel specifies the destination channel where events should be posted. + maxLength: 2048 + type: string + commitStatusExpr: + description: |- + CommitStatusExpr is a CEL expression that evaluates to a string value + that can be used to generate a custom commit status message for use + with eligible Provider types (github, gitlab, gitea, bitbucketserver, + bitbucket, azuredevops). Supported variables are: event, provider, + and alert. + type: string + interval: + description: |- + Interval at which to reconcile the Provider with its Secret references. + Deprecated and not used in v1beta3. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + proxy: + description: |- + Proxy the HTTP/S address of the proxy server. + Deprecated: Use ProxySecretRef instead. Will be removed in v1. + maxLength: 2048 + pattern: ^(http|https)://.*$ + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + for this Provider. The Secret should contain an 'address' key with the + HTTP/S address of the proxy server. Optional 'username' and 'password' + keys can be provided for proxy authentication. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + secretRef: + description: |- + SecretRef specifies the Secret containing the authentication + credentials for this Provider. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to + authenticate with cloud provider services through workload identity. + This enables multi-tenant authentication without storing static credentials. + + Supported provider types: azureeventhub, azuredevops, googlepubsub + + When specified, the controller will: + 1. Create an OIDC token for the specified ServiceAccount + 2. Exchange it for cloud provider credentials via STS + 3. Use the obtained credentials for API authentication + + When unspecified, controller-level authentication is used (single-tenant). + + An error is thrown if static credentials are also defined in SecretRef. + This field requires the ObjectLevelWorkloadIdentity feature gate to be enabled. + type: string + suspend: + description: |- + Suspend tells the controller to suspend subsequent + events handling for this Provider. + type: boolean + timeout: + description: Timeout for sending alerts to the Provider. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + type: + description: Type specifies which Provider implementation to use. + enum: + - slack + - discord + - msteams + - rocket + - generic + - generic-hmac + - github + - gitlab + - gitea + - bitbucketserver + - bitbucket + - azuredevops + - googlechat + - googlepubsub + - webex + - sentry + - azureeventhub + - telegram + - lark + - matrix + - opsgenie + - alertmanager + - grafana + - githubdispatch + - pagerduty + - datadog + - nats + - zulip + - otel + type: string + username: + description: Username specifies the name under which events are posted. + maxLength: 2048 + type: string + required: + - type + type: object + x-kubernetes-validations: + - message: spec.commitStatusExpr is only supported for the 'github', 'gitlab', 'gitea', 'bitbucketserver', 'bitbucket', 'azuredevops' provider types + rule: self.type == 'github' || self.type == 'gitlab' || self.type == 'gitea' || self.type == 'bitbucketserver' || self.type == 'bitbucket' || self.type == 'azuredevops' || !has(self.commitStatusExpr) + type: object + served: true + storage: true + subresources: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: receivers.notification.toolkit.fluxcd.io +spec: + group: notification.toolkit.fluxcd.io + names: + kind: Receiver + listKind: ReceiverList + plural: receivers + singular: receiver + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + description: Receiver is the Schema for the receivers API. + 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: ReceiverSpec defines the desired state of the Receiver. + properties: + events: + description: |- + Events specifies the list of event types to handle, + e.g. 'push' for GitHub or 'Push Hook' for GitLab. + items: + type: string + type: array + interval: + default: 10m + description: Interval at which to reconcile the Receiver with its Secret references. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + resourceFilter: + description: |- + ResourceFilter is a CEL expression expected to return a boolean that is + evaluated for each resource referenced in the Resources field when a + webhook is received. If the expression returns false then the controller + will not request a reconciliation for the resource. + When the expression is specified the controller will parse it and mark + the object as terminally failed if the expression is invalid or does not + return a boolean. + type: string + resources: + description: A list of resources to be notified about changes. + items: + description: |- + CrossNamespaceObjectReference contains enough information to let you locate the + typed referenced object at cluster level + properties: + apiVersion: + description: API version of the referent + type: string + kind: + description: Kind of the referent + enum: + - Bucket + - GitRepository + - Kustomization + - HelmRelease + - HelmChart + - HelmRepository + - ImageRepository + - ImagePolicy + - ImageUpdateAutomation + - OCIRepository + type: string + 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. + MatchLabels requires the name to be set to `*`. + type: object + name: + description: |- + Name of the referent + If multiple resources are targeted `*` may be set. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace of the referent + maxLength: 253 + minLength: 1 + type: string + required: + - kind + - name + type: object + type: array + secretRef: + description: |- + SecretRef specifies the Secret containing the token used + to validate the payload authenticity. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend subsequent + events handling for this receiver. + type: boolean + type: + description: |- + Type of webhook sender, used to determine + the validation procedure and payload deserialization. + enum: + - generic + - generic-hmac + - github + - gitlab + - bitbucket + - harbor + - dockerhub + - quay + - gcr + - nexus + - acr + - cdevents + type: string + required: + - resources + - secretRef + - type + type: object + status: + default: + observedGeneration: -1 + description: ReceiverStatus defines the observed state of the Receiver. + properties: + conditions: + description: Conditions holds the conditions for the Receiver. + 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 + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation of the Receiver object. + format: int64 + type: integer + webhookPath: + description: |- + WebhookPath is the generated incoming webhook address in the format + of '/hook/sha256sum(token+name+namespace)'. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + deprecated: true + deprecationWarning: v1beta2 Receiver is deprecated, upgrade to v1 + name: v1beta2 + schema: + openAPIV3Schema: + description: Receiver is the Schema for the receivers API. + 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: ReceiverSpec defines the desired state of the Receiver. + properties: + events: + description: |- + Events specifies the list of event types to handle, + e.g. 'push' for GitHub or 'Push Hook' for GitLab. + items: + type: string + type: array + interval: + description: Interval at which to reconcile the Receiver with its Secret references. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + resources: + description: A list of resources to be notified about changes. + items: + description: |- + CrossNamespaceObjectReference contains enough information to let you locate the + typed referenced object at cluster level + properties: + apiVersion: + description: API version of the referent + type: string + kind: + description: Kind of the referent + enum: + - Bucket + - GitRepository + - Kustomization + - HelmRelease + - HelmChart + - HelmRepository + - ImageRepository + - ImagePolicy + - ImageUpdateAutomation + - OCIRepository + type: string + 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. + MatchLabels requires the name to be set to `*`. + type: object + name: + description: |- + Name of the referent + If multiple resources are targeted `*` may be set. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace of the referent + maxLength: 253 + minLength: 1 + type: string + required: + - kind + - name + type: object + type: array + secretRef: + description: |- + SecretRef specifies the Secret containing the token used + to validate the payload authenticity. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + suspend: + description: |- + Suspend tells the controller to suspend subsequent + events handling for this receiver. + type: boolean + type: + description: |- + Type of webhook sender, used to determine + the validation procedure and payload deserialization. + enum: + - generic + - generic-hmac + - github + - gitlab + - bitbucket + - harbor + - dockerhub + - quay + - gcr + - nexus + - acr + type: string + required: + - resources + - secretRef + - type + type: object + status: + default: + observedGeneration: -1 + description: ReceiverStatus defines the observed state of the Receiver. + properties: + conditions: + description: Conditions holds the conditions for the Receiver. + 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 + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation of the Receiver object. + format: int64 + type: integer + url: + description: |- + URL is the generated incoming webhook address in the format + of '/hook/sha256sum(token+name+namespace)'. + Deprecated: Replaced by WebhookPath. + type: string + webhookPath: + description: |- + WebhookPath is the generated incoming webhook address in the format + of '/hook/sha256sum(token+name+namespace)'. + type: string + type: object + type: object + served: true + storage: false + subresources: + status: {} +--- +apiVersion: v1 +kind: Namespace +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + pod-security.kubernetes.io/enforce: privileged + name: cozy-fluxcd +--- +apiVersion: v1 +kind: ResourceQuota +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: flux + namespace: cozy-fluxcd +spec: + hard: + pods: "1000" + scopeSelector: + matchExpressions: + - operator: In + scopeName: PriorityClass + values: + - system-node-critical + - system-cluster-critical +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: flux + namespace: cozy-fluxcd +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" + rbac.authorization.k8s.io/aggregate-to-view: "true" + name: flux-view +rules: + - apiGroups: + - notification.toolkit.fluxcd.io + - source.toolkit.fluxcd.io + - helm.toolkit.fluxcd.io + - image.toolkit.fluxcd.io + - kustomize.toolkit.fluxcd.io + - source.extensions.fluxcd.io + resources: + - '*' + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: flux +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + name: flux + namespace: cozy-fluxcd +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + app.kubernetes.io/role: cluster-admin + labels: + app.kubernetes.io/name: flux + app.kubernetes.io/part-of: flux + app.kubernetes.io/version: v2.7.3 + name: flux + namespace: cozy-fluxcd +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: flux + strategy: + type: Recreate + template: + metadata: + annotations: + cluster-autoscaler.kubernetes.io/safe-to-evict: "true" + prometheus.io/scrape: "true" + labels: + app.kubernetes.io/name: flux + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/os + operator: In + values: + - linux + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - flux + topologyKey: kubernetes.io/hostname + containers: + - args: + - --watch-all-namespaces + - --log-level=info + - --log-encoding=json + - --enable-leader-election=false + - --metrics-addr=:9791 + - --health-addr=:9792 + - --storage-addr=:9790 + - --storage-path=/data + - --storage-adv-addr=flux.$(RUNTIME_NAMESPACE).svc + - --concurrent=5 + - --requeue-dependency=30s + - --watch-label-selector=!sharding.fluxcd.io/key + - --helm-cache-max-size=10 + - --helm-cache-ttl=60m + - --helm-cache-purge-interval=5m + - --events-addr=http://localhost:9690 + env: + - name: SOURCE_CONTROLLER_LOCALHOST + value: localhost:9790 + - name: SOURCE_WATCHER_LOCALHOST + value: localhost:9691 + - name: RUNTIME_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + resource: limits.memory + - name: TUF_ROOT + value: /tmp/.sigstore + - name: NO_PROXY + value: .svc + image: ghcr.io/fluxcd/source-controller:v1.7.3 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /healthz + port: healthz-sc + name: source-controller + ports: + - containerPort: 9790 + name: http-sc + protocol: TCP + - containerPort: 9791 + name: http-prom-sc + protocol: TCP + - containerPort: 9792 + name: healthz-sc + protocol: TCP + readinessProbe: + httpGet: + path: / + port: http-sc + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + volumeMounts: + - mountPath: /data + name: data + - mountPath: /tmp + name: tmp + - args: + - --watch-all-namespaces + - --log-level=info + - --log-encoding=json + - --enable-leader-election=false + - --metrics-addr=:9793 + - --health-addr=:9794 + - --watch-label-selector=!sharding.fluxcd.io/key + - --concurrent=5 + - --requeue-dependency=30s + - --events-addr=http://localhost:9690 + - --feature-gates=ExternalArtifact=true + env: + - name: SOURCE_CONTROLLER_LOCALHOST + value: localhost:9790 + - name: SOURCE_WATCHER_LOCALHOST + value: localhost:9691 + - name: RUNTIME_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + resource: limits.memory + - name: TUF_ROOT + value: /tmp/.sigstore + - name: NO_PROXY + value: .svc + image: ghcr.io/fluxcd/kustomize-controller:v1.7.2 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /healthz + port: healthz-kc + name: kustomize-controller + ports: + - containerPort: 9793 + name: http-prom-kc + protocol: TCP + - containerPort: 9794 + name: healthz-kc + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: healthz-kc + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + volumeMounts: + - mountPath: /tmp + name: tmp + - args: + - --watch-all-namespaces + - --log-level=info + - --log-encoding=json + - --enable-leader-election=false + - --metrics-addr=:9795 + - --health-addr=:9796 + - --watch-label-selector=!sharding.fluxcd.io/key + - --concurrent=5 + - --requeue-dependency=30s + - --events-addr=http://localhost:9690 + - --feature-gates=ExternalArtifact=true + env: + - name: SOURCE_CONTROLLER_LOCALHOST + value: localhost:9790 + - name: SOURCE_WATCHER_LOCALHOST + value: localhost:9691 + - name: RUNTIME_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + resource: limits.memory + - name: TUF_ROOT + value: /tmp/.sigstore + - name: NO_PROXY + value: .svc + image: ghcr.io/fluxcd/helm-controller:v1.4.3 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /healthz + port: healthz-hc + name: helm-controller + ports: + - containerPort: 9795 + name: http-prom-hc + protocol: TCP + - containerPort: 9796 + name: healthz-hc + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: healthz-hc + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + volumeMounts: + - mountPath: /tmp + name: tmp + - args: + - --watch-all-namespaces + - --log-level=info + - --log-encoding=json + - --enable-leader-election=false + - --receiverAddr=:9797 + - --metrics-addr=:9798 + - --health-addr=:9799 + - --events-addr=:9690 + env: + - name: SOURCE_CONTROLLER_LOCALHOST + value: localhost:9790 + - name: SOURCE_WATCHER_LOCALHOST + value: localhost:9691 + - name: RUNTIME_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + resource: limits.memory + - name: TUF_ROOT + value: /tmp/.sigstore + - name: NO_PROXY + value: .svc + image: ghcr.io/fluxcd/notification-controller:v1.7.4 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /healthz + port: healthz-nc + name: notification-controller + ports: + - containerPort: 9690 + name: http-nc + protocol: TCP + - containerPort: 9797 + name: http-webhook-nc + protocol: TCP + - containerPort: 9798 + name: http-prom-nc + protocol: TCP + - containerPort: 9799 + name: healthz-nc + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: healthz-nc + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + volumeMounts: + - mountPath: /tmp + name: tmp + - args: + - --watch-all-namespaces + - --log-level=info + - --log-encoding=json + - --enable-leader-election=false + - --metrics-addr=:9692 + - --health-addr=:9693 + - --storage-addr=:9691 + - --storage-path=/data + - --storage-adv-addr=flux.$(RUNTIME_NAMESPACE).svc + - --events-addr=http://localhost:9690 + env: + - name: SOURCE_CONTROLLER_LOCALHOST + value: localhost:9790 + - name: SOURCE_WATCHER_LOCALHOST + value: localhost:9691 + - name: RUNTIME_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + resource: limits.memory + - name: TUF_ROOT + value: /tmp/.sigstore + - name: NO_PROXY + value: .svc + image: ghcr.io/fluxcd/source-watcher:v2.0.2 + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /healthz + port: healthz-sw + name: source-watcher + ports: + - containerPort: 9691 + name: http-sw + protocol: TCP + - containerPort: 9692 + name: http-prom-sw + protocol: TCP + - containerPort: 9693 + name: healthz-sw + protocol: TCP + readinessProbe: + httpGet: + path: / + port: http-sw + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + volumeMounts: + - mountPath: /data + name: data + - mountPath: /tmp + name: tmp + hostNetwork: true + priorityClassName: system-cluster-critical + securityContext: + fsGroup: 1337 + serviceAccountName: flux + terminationGracePeriodSeconds: 120 + tolerations: + - key: node.kubernetes.io/not-ready + operator: Exists + - key: node.kubernetes.io/unreachable + operator: Exists + - key: node.cilium.io/agent-not-ready + operator: Exists + - key: node.cloudprovider.kubernetes.io/uninitialized + operator: Exists + volumes: + - emptyDir: {} + name: data + - emptyDir: {} + name: tmp diff --git a/internal/lineagecontrollerwebhook/config.go b/internal/lineagecontrollerwebhook/config.go new file mode 100644 index 00000000..ce4b6898 --- /dev/null +++ b/internal/lineagecontrollerwebhook/config.go @@ -0,0 +1,73 @@ +package lineagecontrollerwebhook + +import ( + "fmt" + "strings" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + helmv2 "github.com/fluxcd/helm-controller/api/v2" +) + +type appRef struct { + group string + kind string +} + +type runtimeConfig struct { + appCRDMap map[appRef]*cozyv1alpha1.ApplicationDefinition +} + +func (l *LineageControllerWebhook) initConfig() { + l.initOnce.Do(func() { + if l.config.Load() == nil { + l.config.Store(&runtimeConfig{ + appCRDMap: make(map[appRef]*cozyv1alpha1.ApplicationDefinition), + }) + } + }) +} + +// getApplicationLabel safely extracts an application label from HelmRelease +func getApplicationLabel(hr *helmv2.HelmRelease, key string) (string, error) { + if hr.Labels == nil { + return "", fmt.Errorf("cannot map helm release %s/%s to dynamic app: labels are nil", hr.Namespace, hr.Name) + } + val, ok := hr.Labels[key] + if !ok { + return "", fmt.Errorf("cannot map helm release %s/%s to dynamic app: missing %s label", hr.Namespace, hr.Name, key) + } + return val, nil +} + +func (l *LineageControllerWebhook) Map(hr *helmv2.HelmRelease) (string, string, string, error) { + // Extract application metadata from labels + appKind, err := getApplicationLabel(hr, "apps.cozystack.io/application.kind") + if err != nil { + return "", "", "", err + } + + appGroup, err := getApplicationLabel(hr, "apps.cozystack.io/application.group") + if err != nil { + return "", "", "", err + } + + appName, err := getApplicationLabel(hr, "apps.cozystack.io/application.name") + if err != nil { + return "", "", "", err + } + + // Construct API version from group + apiVersion := fmt.Sprintf("%s/v1alpha1", appGroup) + + // Extract prefix from HelmRelease name by removing the application name + // HelmRelease name format: + prefix := strings.TrimSuffix(hr.Name, appName) + + // Validate the derived prefix + // This ensures correctness when appName appears multiple times in hr.Name + if prefix+appName != hr.Name { + return "", "", "", fmt.Errorf("cannot derive prefix from helm release %s/%s: name does not end with application name %s", hr.Namespace, hr.Name, appName) + } + + return apiVersion, appKind, prefix, nil +} diff --git a/internal/lineagecontrollerwebhook/controller.go b/internal/lineagecontrollerwebhook/controller.go new file mode 100644 index 00000000..42bdb396 --- /dev/null +++ b/internal/lineagecontrollerwebhook/controller.go @@ -0,0 +1,44 @@ +package lineagecontrollerwebhook + +import ( + "context" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +// +kubebuilder:rbac:groups=cozystack.io,resources=applicationdefinitions,verbs=list;watch;get + +func (c *LineageControllerWebhook) SetupWithManagerAsController(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&cozyv1alpha1.ApplicationDefinition{}). + Complete(c) +} + +func (c *LineageControllerWebhook) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + l := log.FromContext(ctx) + crds := &cozyv1alpha1.ApplicationDefinitionList{} + if err := c.List(ctx, crds); err != nil { + l.Error(err, "failed reading ApplicationDefinitions") + return ctrl.Result{}, err + } + cfg := &runtimeConfig{ + appCRDMap: make(map[appRef]*cozyv1alpha1.ApplicationDefinition), + } + for _, crd := range crds.Items { + appRef := appRef{ + "apps.cozystack.io", + crd.Spec.Application.Kind, + } + + newRef := crd + if _, exists := cfg.appCRDMap[appRef]; exists { + l.Info("duplicate app mapping detected; ignoring subsequent entry", "key", appRef) + } else { + cfg.appCRDMap[appRef] = &newRef + } + } + c.config.Store(cfg) + return ctrl.Result{}, nil +} diff --git a/internal/lineagecontrollerwebhook/matcher.go b/internal/lineagecontrollerwebhook/matcher.go new file mode 100644 index 00000000..6e7bd318 --- /dev/null +++ b/internal/lineagecontrollerwebhook/matcher.go @@ -0,0 +1,73 @@ +package lineagecontrollerwebhook + +import ( + "bytes" + "context" + "text/template" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +// matchName checks if the provided name matches any of the resource names in the array. +// Each entry in resourceNames is treated as a Go template that gets rendered using the passed context. +// A nil resourceNames array matches any string. +func matchName(ctx context.Context, name string, templateContext map[string]string, resourceNames []string) bool { + if resourceNames == nil { + return true + } + + logger := log.FromContext(ctx) + for _, templateStr := range resourceNames { + tmpl, err := template.New("resourceName").Parse(templateStr) + if err != nil { + logger.Error(err, "failed to parse resource name template", "template", templateStr) + continue + } + + var buf bytes.Buffer + err = tmpl.Execute(&buf, templateContext) + if err != nil { + logger.Error(err, "failed to execute resource name template", "template", templateStr, "context", templateContext) + continue + } + + if buf.String() == name { + return true + } + } + + return false +} + +func matchResourceToSelector(ctx context.Context, name string, templateContext, l map[string]string, s *cozyv1alpha1.ApplicationDefinitionResourceSelector) bool { + sel, err := metav1.LabelSelectorAsSelector(&s.LabelSelector) + if err != nil { + log.FromContext(ctx).Error(err, "failed to convert label selector to selector") + return false + } + labelMatches := sel.Matches(labels.Set(l)) + nameMatches := matchName(ctx, name, templateContext, s.ResourceNames) + return labelMatches && nameMatches +} + +func matchResourceToSelectorArray(ctx context.Context, name string, templateContext, l map[string]string, ss []*cozyv1alpha1.ApplicationDefinitionResourceSelector) bool { + for _, s := range ss { + if matchResourceToSelector(ctx, name, templateContext, l, s) { + return true + } + } + return false +} + +func matchResourceToExcludeInclude(ctx context.Context, name string, templateContext, l map[string]string, resources *cozyv1alpha1.ApplicationDefinitionResources) bool { + if resources == nil { + return false + } + if matchResourceToSelectorArray(ctx, name, templateContext, l, resources.Exclude) { + return false + } + return matchResourceToSelectorArray(ctx, name, templateContext, l, resources.Include) +} diff --git a/internal/lineagecontrollerwebhook/types.go b/internal/lineagecontrollerwebhook/types.go new file mode 100644 index 00000000..f423ae95 --- /dev/null +++ b/internal/lineagecontrollerwebhook/types.go @@ -0,0 +1,23 @@ +package lineagecontrollerwebhook + +import ( + "sync" + "sync/atomic" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/dynamic" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" +) + +// +kubebuilder:webhook:path=/mutate-lineage,mutating=true,failurePolicy=Fail,sideEffects=None,groups="",resources=pods,secrets,services,persistentvolumeclaims,verbs=create;update,versions=v1,name=mlineage.cozystack.io,admissionReviewVersions={v1} +type LineageControllerWebhook struct { + client.Client + Scheme *runtime.Scheme + decoder admission.Decoder + dynClient dynamic.Interface + mapper meta.RESTMapper + config atomic.Value + initOnce sync.Once +} diff --git a/internal/lineagecontrollerwebhook/webhook.go b/internal/lineagecontrollerwebhook/webhook.go new file mode 100644 index 00000000..cf871fb0 --- /dev/null +++ b/internal/lineagecontrollerwebhook/webhook.go @@ -0,0 +1,286 @@ +package lineagecontrollerwebhook + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "strings" + + "github.com/cozystack/cozystack/pkg/lineage" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + schedulerapi "github.com/cozystack/cozystack-scheduler/pkg/apis/v1alpha1" +) + +var ( + NoAncestors = errors.New("no managed apps found in lineage") + AncestryAmbiguous = errors.New("object ancestry is ambiguous") +) + +const ( + ManagedObjectKey = "internal.cozystack.io/managed-by-cozystack" + ManagerGroupKey = "apps.cozystack.io/application.group" + ManagerKindKey = "apps.cozystack.io/application.kind" + ManagerNameKey = "apps.cozystack.io/application.name" +) + +// getResourceSelectors returns the appropriate ApplicationDefinitionResources for a given GroupKind +func (h *LineageControllerWebhook) getResourceSelectors(gk schema.GroupKind, crd *cozyv1alpha1.ApplicationDefinition) *cozyv1alpha1.ApplicationDefinitionResources { + switch { + case gk.Group == "" && gk.Kind == "Secret": + return &crd.Spec.Secrets + case gk.Group == "" && gk.Kind == "Service": + return &crd.Spec.Services + case gk.Group == "networking.k8s.io" && gk.Kind == "Ingress": + return &crd.Spec.Ingresses + default: + return nil + } +} + +// SetupWithManager registers the handler with the webhook server. +func (h *LineageControllerWebhook) SetupWithManagerAsWebhook(mgr ctrl.Manager) error { + cfg := rest.CopyConfig(mgr.GetConfig()) + + var err error + h.dynClient, err = dynamic.NewForConfig(cfg) + if err != nil { + return err + } + + httpClient, err := rest.HTTPClientFor(cfg) + if err != nil { + return err + } + + h.mapper, err = apiutil.NewDynamicRESTMapper(cfg, httpClient) + if err != nil { + return err + } + + h.initConfig() + // Register HTTP path -> handler. + mgr.GetWebhookServer().Register("/mutate-lineage", &admission.Webhook{Handler: h}) + + return nil +} + +// InjectDecoder lets controller-runtime give us a decoder for AdmissionReview requests. +func (h *LineageControllerWebhook) InjectDecoder(d admission.Decoder) error { + h.decoder = d + return nil +} + +// Handle is called for each AdmissionReview that matches the webhook config. +func (h *LineageControllerWebhook) Handle(ctx context.Context, req admission.Request) admission.Response { + logger := log.FromContext(ctx).WithValues( + "gvk", req.Kind.String(), + "namespace", req.Namespace, + "name", req.Name, + "operation", req.Operation, + ) + warn := make(admission.Warnings, 0) + + obj := &unstructured.Unstructured{} + if err := h.decodeUnstructured(req, obj); err != nil { + return admission.Errored(400, fmt.Errorf("decode object: %w", err)) + } + + owner, err := h.getOwner(ctx, obj) + switch { + case err != nil && errors.Is(err, AncestryAmbiguous): + warn = append(warn, "object ancestry ambiguous, using first ancestor found") + case err != nil && errors.Is(err, NoAncestors): + // not a problem, mark object as unmanaged + case err != nil: + logger.Error(err, "error computing lineage labels") + return admission.Errored(500, fmt.Errorf("error computing lineage labels: %w", err)) + } + labels, err := h.computeLabels(ctx, obj, owner) + if err != nil { + logger.Error(err, "error computing lineage labels") + return admission.Errored(500, fmt.Errorf("error computing lineage labels: %w", err)) + } + + h.applyLabels(obj, labels) + + if err := h.applySchedulingClass(ctx, obj, owner, req.Namespace); err != nil { + logger.Error(err, "error applying scheduling class") + return admission.Errored(500, fmt.Errorf("error applying scheduling class: %w", err)) + } + + mutated, err := json.Marshal(obj) + if err != nil { + return admission.Errored(500, fmt.Errorf("marshal mutated pod: %w", err)) + } + logger.V(1).Info("mutated pod", "namespace", obj.GetNamespace(), "name", obj.GetName()) + return admission.PatchResponseFromRaw(req.Object.Raw, mutated).WithWarnings(warn...) +} + +func (h *LineageControllerWebhook) getOwner(ctx context.Context, o *unstructured.Unstructured) (*unstructured.Unstructured, error) { + owners := lineage.WalkOwnershipGraph(ctx, h.dynClient, h.mapper, h, o) + if len(owners) == 0 { + return nil, NoAncestors + } + obj, err := owners[0].GetUnstructured(ctx, h.dynClient, h.mapper) + if err != nil { + return nil, err + } + if len(owners) > 1 { + err = AncestryAmbiguous + } + return obj, err +} + +func (h *LineageControllerWebhook) computeLabels(ctx context.Context, obj *unstructured.Unstructured, owner *unstructured.Unstructured) (map[string]string, error) { + if owner == nil { + return nil, nil + } + gv, err := schema.ParseGroupVersion(owner.GetAPIVersion()) + if err != nil { + // should never happen, we got an APIVersion right from the API + return nil, fmt.Errorf("could not parse APIVersion %s to a group and version: %w", owner.GetAPIVersion(), err) + } + labels := map[string]string{ + // truncate apigroup to first 63 chars + ManagedObjectKey: "true", + ManagerGroupKey: func(s string) string { + if len(s) < 63 { + return s + } + s = s[:63] + for b := s[62]; !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9')); s = s[:len(s)-1] { + b = s[len(s)-1] + } + return s + }(gv.Group), + ManagerKindKey: owner.GetKind(), + ManagerNameKey: owner.GetName(), + } + templateLabels := map[string]string{ + "kind": strings.ToLower(owner.GetKind()), + "name": owner.GetName(), + "namespace": obj.GetNamespace(), + } + cfg := h.config.Load().(*runtimeConfig) + crd := cfg.appCRDMap[appRef{gv.Group, owner.GetKind()}] + resourceSelectors := h.getResourceSelectors(obj.GroupVersionKind().GroupKind(), crd) + + labels[corev1alpha1.TenantResourceLabelKey] = func(b bool) string { + if b { + return corev1alpha1.TenantResourceLabelValue + } + return "false" + }(matchResourceToExcludeInclude(ctx, obj.GetName(), templateLabels, obj.GetLabels(), resourceSelectors)) + return labels, nil +} + +func (h *LineageControllerWebhook) applyLabels(o *unstructured.Unstructured, labels map[string]string) { + existing := o.GetLabels() + if existing == nil { + existing = make(map[string]string) + } + for k, v := range labels { + existing[k] = v + } + o.SetLabels(existing) +} + +// applySchedulingClass injects schedulerName and scheduling-class annotation +// into Pods whose namespace carries the scheduler.cozystack.io/scheduling-class label. +// If the referenced SchedulingClass CR does not exist (e.g. the scheduler +// package is not installed), the injection is silently skipped so that pods +// are not left Pending. +func (h *LineageControllerWebhook) applySchedulingClass(ctx context.Context, obj, owner *unstructured.Unstructured, namespace string) error { + if obj.GetKind() != "Pod" { + return nil + } + + // Determine scheduling class: owner Application field takes priority, + // then fall back to namespace label. + var schedulingClass string + if owner != nil { + var app appsv1alpha1.Application + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(owner.Object, &app); err == nil { + schedulingClass = app.SchedulingClass() + } + } + if schedulingClass == "" { + ns := &corev1.Namespace{} + if err := h.Get(ctx, client.ObjectKey{Name: namespace}, ns); err != nil { + return fmt.Errorf("getting namespace %s: %w", namespace, err) + } + schedulingClass = ns.Labels[schedulerapi.SchedulingClassLabel] + } + + if schedulingClass == "" { + return nil + } + + // Verify that the referenced SchedulingClass CR exists. + // If the CRD is not installed or the CR is missing, skip injection + // so that pods are not stuck Pending on a non-existent scheduler. + _, err := h.dynClient.Resource(schedulingClassGVR).Get(ctx, schedulingClass, metav1.GetOptions{}) + if err != nil { + logger := log.FromContext(ctx) + logger.Info("SchedulingClass not found, skipping scheduler injection", + "schedulingClass", schedulingClass, "namespace", namespace) + return nil + } + + if err := unstructured.SetNestedField(obj.Object, schedulerapi.SchedulerName, "spec", "schedulerName"); err != nil { + return fmt.Errorf("setting schedulerName: %w", err) + } + + annotations := obj.GetAnnotations() + if annotations == nil { + annotations = make(map[string]string) + } + annotations[schedulerapi.SchedulingClassAnnotation] = schedulingClass + obj.SetAnnotations(annotations) + + return nil +} + +var schedulingClassGVR = schema.GroupVersionResource{ + Group: schedulerapi.Group, + Version: schedulerapi.Version, + Resource: schedulerapi.Resource, +} + +func (h *LineageControllerWebhook) decodeUnstructured(req admission.Request, out *unstructured.Unstructured) error { + if h.decoder != nil { + if err := h.decoder.Decode(req, out); err == nil { + return nil + } + if req.Kind.Group != "" || req.Kind.Kind != "" || req.Kind.Version != "" { + out.SetGroupVersionKind(schema.GroupVersionKind{ + Group: req.Kind.Group, + Version: req.Kind.Version, + Kind: req.Kind.Kind, + }) + if err := h.decoder.Decode(req, out); err == nil { + return nil + } + } + } + if len(req.Object.Raw) == 0 { + return errors.New("empty admission object") + } + return json.Unmarshal(req.Object.Raw, &out.Object) +} diff --git a/internal/manifestutil/crd.go b/internal/manifestutil/crd.go new file mode 100644 index 00000000..08468d1b --- /dev/null +++ b/internal/manifestutil/crd.go @@ -0,0 +1,118 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package manifestutil + +import ( + "context" + "fmt" + "time" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +var crdGVK = schema.GroupVersionKind{ + Group: "apiextensions.k8s.io", + Version: "v1", + Kind: "CustomResourceDefinition", +} + +// WaitForCRDsEstablished polls the API server until all named CRDs have the +// Established condition set to True, or the context is cancelled. +func WaitForCRDsEstablished(ctx context.Context, k8sClient client.Client, crdNames []string) error { + if len(crdNames) == 0 { + return nil + } + + logger := log.FromContext(ctx) + ticker := time.NewTicker(500 * time.Millisecond) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return fmt.Errorf("context cancelled while waiting for CRDs to be established: %w", ctx.Err()) + default: + } + + allEstablished := true + var pendingCRD string + for _, name := range crdNames { + crd := &unstructured.Unstructured{} + crd.SetGroupVersionKind(crdGVK) + if err := k8sClient.Get(ctx, types.NamespacedName{Name: name}, crd); err != nil { + allEstablished = false + pendingCRD = name + break + } + + conditions, found, err := unstructured.NestedSlice(crd.Object, "status", "conditions") + if err != nil || !found { + allEstablished = false + pendingCRD = name + break + } + + established := false + for _, c := range conditions { + cond, ok := c.(map[string]interface{}) + if !ok { + continue + } + if cond["type"] == "Established" && cond["status"] == "True" { + established = true + break + } + } + if !established { + allEstablished = false + pendingCRD = name + break + } + } + + if allEstablished { + logger.Info("All CRDs established", "count", len(crdNames)) + return nil + } + + logger.V(1).Info("Waiting for CRD to be established", "crd", pendingCRD) + + select { + case <-ctx.Done(): + return fmt.Errorf("context cancelled while waiting for CRD %q to be established: %w", pendingCRD, ctx.Err()) + case <-ticker.C: + } + } +} + +// CollectCRDNames returns the names of all CustomResourceDefinition objects +// from the given list of unstructured objects. Only objects with +// apiVersion "apiextensions.k8s.io/v1" and kind "CustomResourceDefinition" +// are matched. +func CollectCRDNames(objects []*unstructured.Unstructured) []string { + var names []string + for _, obj := range objects { + if obj.GetAPIVersion() == "apiextensions.k8s.io/v1" && obj.GetKind() == "CustomResourceDefinition" { + names = append(names, obj.GetName()) + } + } + return names +} diff --git a/internal/manifestutil/crd_test.go b/internal/manifestutil/crd_test.go new file mode 100644 index 00000000..5d046353 --- /dev/null +++ b/internal/manifestutil/crd_test.go @@ -0,0 +1,202 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package manifestutil + +import ( + "context" + "strings" + "testing" + "time" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/client/interceptor" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" +) + +func TestCollectCRDNames(t *testing.T) { + objects := []*unstructured.Unstructured{ + {Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "Namespace", + "metadata": map[string]interface{}{"name": "test-ns"}, + }}, + {Object: map[string]interface{}{ + "apiVersion": "apiextensions.k8s.io/v1", + "kind": "CustomResourceDefinition", + "metadata": map[string]interface{}{"name": "packages.cozystack.io"}, + }}, + {Object: map[string]interface{}{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": map[string]interface{}{"name": "test-deploy"}, + }}, + {Object: map[string]interface{}{ + "apiVersion": "apiextensions.k8s.io/v1", + "kind": "CustomResourceDefinition", + "metadata": map[string]interface{}{"name": "packagesources.cozystack.io"}, + }}, + } + + names := CollectCRDNames(objects) + if len(names) != 2 { + t.Fatalf("CollectCRDNames() returned %d names, want 2", len(names)) + } + if names[0] != "packages.cozystack.io" { + t.Errorf("names[0] = %q, want %q", names[0], "packages.cozystack.io") + } + if names[1] != "packagesources.cozystack.io" { + t.Errorf("names[1] = %q, want %q", names[1], "packagesources.cozystack.io") + } +} + +func TestCollectCRDNames_ignoresWrongAPIVersion(t *testing.T) { + objects := []*unstructured.Unstructured{ + {Object: map[string]interface{}{ + "apiVersion": "apiextensions.k8s.io/v1", + "kind": "CustomResourceDefinition", + "metadata": map[string]interface{}{"name": "real.crd.io"}, + }}, + {Object: map[string]interface{}{ + "apiVersion": "apiextensions.k8s.io/v1beta1", + "kind": "CustomResourceDefinition", + "metadata": map[string]interface{}{"name": "legacy.crd.io"}, + }}, + } + + names := CollectCRDNames(objects) + if len(names) != 1 { + t.Fatalf("CollectCRDNames() returned %d names, want 1", len(names)) + } + if names[0] != "real.crd.io" { + t.Errorf("names[0] = %q, want %q", names[0], "real.crd.io") + } +} + +func TestCollectCRDNames_noCRDs(t *testing.T) { + objects := []*unstructured.Unstructured{ + {Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "Namespace", + "metadata": map[string]interface{}{"name": "test"}, + }}, + } + + names := CollectCRDNames(objects) + if len(names) != 0 { + t.Errorf("CollectCRDNames() returned %d names, want 0", len(names)) + } +} + +func TestWaitForCRDsEstablished_success(t *testing.T) { + log.SetLogger(zap.New(zap.UseDevMode(true))) + + scheme := runtime.NewScheme() + if err := apiextensionsv1.AddToScheme(scheme); err != nil { + t.Fatalf("failed to add apiextensions to scheme: %v", err) + } + + // Create a CRD object in the fake client + crd := &unstructured.Unstructured{Object: map[string]interface{}{ + "apiVersion": "apiextensions.k8s.io/v1", + "kind": "CustomResourceDefinition", + "metadata": map[string]interface{}{"name": "packages.cozystack.io"}, + }} + + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(crd). + WithInterceptorFuncs(interceptor.Funcs{ + Get: func(ctx context.Context, c client.WithWatch, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error { + if err := c.Get(ctx, key, obj, opts...); err != nil { + return err + } + u, ok := obj.(*unstructured.Unstructured) + if !ok { + return nil + } + if u.GetKind() == "CustomResourceDefinition" { + _ = unstructured.SetNestedSlice(u.Object, []interface{}{ + map[string]interface{}{ + "type": "Established", + "status": "True", + }, + }, "status", "conditions") + } + return nil + }, + }). + Build() + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + ctx = log.IntoContext(ctx, log.FromContext(context.Background())) + + err := WaitForCRDsEstablished(ctx, fakeClient, []string{"packages.cozystack.io"}) + if err != nil { + t.Fatalf("WaitForCRDsEstablished() error = %v", err) + } +} + +func TestWaitForCRDsEstablished_timeout(t *testing.T) { + log.SetLogger(zap.New(zap.UseDevMode(true))) + + scheme := runtime.NewScheme() + if err := apiextensionsv1.AddToScheme(scheme); err != nil { + t.Fatalf("failed to add apiextensions to scheme: %v", err) + } + + // CRD exists but never gets Established condition + crd := &unstructured.Unstructured{Object: map[string]interface{}{ + "apiVersion": "apiextensions.k8s.io/v1", + "kind": "CustomResourceDefinition", + "metadata": map[string]interface{}{"name": "packages.cozystack.io"}, + }} + + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(crd). + Build() + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + ctx = log.IntoContext(ctx, log.FromContext(context.Background())) + + err := WaitForCRDsEstablished(ctx, fakeClient, []string{"packages.cozystack.io"}) + if err == nil { + t.Fatal("WaitForCRDsEstablished() expected error on timeout, got nil") + } + if !strings.Contains(err.Error(), "packages.cozystack.io") { + t.Errorf("error should mention stuck CRD name, got: %v", err) + } +} + +func TestWaitForCRDsEstablished_empty(t *testing.T) { + scheme := runtime.NewScheme() + fakeClient := fake.NewClientBuilder().WithScheme(scheme).Build() + + ctx := context.Background() + err := WaitForCRDsEstablished(ctx, fakeClient, nil) + if err != nil { + t.Fatalf("WaitForCRDsEstablished() with empty names should return nil, got: %v", err) + } +} + diff --git a/internal/manifestutil/parse.go b/internal/manifestutil/parse.go new file mode 100644 index 00000000..009e4a96 --- /dev/null +++ b/internal/manifestutil/parse.go @@ -0,0 +1,76 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package manifestutil + +import ( + "bufio" + "bytes" + "fmt" + "io" + "os" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + k8syaml "k8s.io/apimachinery/pkg/util/yaml" +) + +// ParseManifestFile reads a YAML file and parses it into unstructured objects. +func ParseManifestFile(manifestPath string) ([]*unstructured.Unstructured, error) { + data, err := os.ReadFile(manifestPath) + if err != nil { + return nil, fmt.Errorf("failed to read manifest file: %w", err) + } + + return ReadYAMLObjects(bytes.NewReader(data)) +} + +// ReadYAMLObjects parses multi-document YAML from a reader into unstructured objects. +// Empty documents and documents without a kind are skipped. +func ReadYAMLObjects(reader io.Reader) ([]*unstructured.Unstructured, error) { + var objects []*unstructured.Unstructured + yamlReader := k8syaml.NewYAMLReader(bufio.NewReader(reader)) + + for { + doc, err := yamlReader.Read() + if err != nil { + if err == io.EOF { + break + } + return nil, fmt.Errorf("failed to read YAML document: %w", err) + } + + if len(bytes.TrimSpace(doc)) == 0 { + continue + } + + obj := &unstructured.Unstructured{} + decoder := k8syaml.NewYAMLOrJSONDecoder(bytes.NewReader(doc), len(doc)) + if err := decoder.Decode(obj); err != nil { + if err == io.EOF { + continue + } + return nil, fmt.Errorf("failed to decode YAML document: %w", err) + } + + if obj.GetKind() == "" { + continue + } + + objects = append(objects, obj) + } + + return objects, nil +} diff --git a/internal/manifestutil/parse_test.go b/internal/manifestutil/parse_test.go new file mode 100644 index 00000000..860405c7 --- /dev/null +++ b/internal/manifestutil/parse_test.go @@ -0,0 +1,161 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package manifestutil + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +func TestReadYAMLObjects(t *testing.T) { + tests := []struct { + name string + input string + wantCount int + wantErr bool + }{ + { + name: "single document", + input: `apiVersion: v1 +kind: ConfigMap +metadata: + name: test +`, + wantCount: 1, + }, + { + name: "multiple documents", + input: `apiVersion: v1 +kind: ConfigMap +metadata: + name: test1 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: test2 +`, + wantCount: 2, + }, + { + name: "empty input", + input: "", + wantCount: 0, + }, + { + name: "decoder rejects document without kind", + input: `apiVersion: v1 +metadata: + name: test +`, + wantErr: true, + }, + { + name: "whitespace-only document between separators is skipped", + input: `apiVersion: v1 +kind: ConfigMap +metadata: + name: test1 +--- + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: test2 +`, + wantCount: 2, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + objects, err := ReadYAMLObjects(strings.NewReader(tt.input)) + if (err != nil) != tt.wantErr { + t.Errorf("ReadYAMLObjects() error = %v, wantErr %v", err, tt.wantErr) + return + } + if len(objects) != tt.wantCount { + t.Errorf("ReadYAMLObjects() returned %d objects, want %d", len(objects), tt.wantCount) + } + }) + } +} + +func TestReadYAMLObjects_preservesFields(t *testing.T) { + input := `apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: packages.cozystack.io +spec: + group: cozystack.io +` + objects, err := ReadYAMLObjects(strings.NewReader(input)) + if err != nil { + t.Fatalf("ReadYAMLObjects() error = %v", err) + } + if len(objects) != 1 { + t.Fatalf("expected 1 object, got %d", len(objects)) + } + + obj := objects[0] + if obj.GetKind() != "CustomResourceDefinition" { + t.Errorf("kind = %q, want %q", obj.GetKind(), "CustomResourceDefinition") + } + if obj.GetName() != "packages.cozystack.io" { + t.Errorf("name = %q, want %q", obj.GetName(), "packages.cozystack.io") + } + if obj.GetAPIVersion() != "apiextensions.k8s.io/v1" { + t.Errorf("apiVersion = %q, want %q", obj.GetAPIVersion(), "apiextensions.k8s.io/v1") + } +} + +func TestParseManifestFile(t *testing.T) { + tmpDir := t.TempDir() + manifestPath := filepath.Join(tmpDir, "test.yaml") + + content := `apiVersion: v1 +kind: ConfigMap +metadata: + name: cm1 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cm2 +` + if err := os.WriteFile(manifestPath, []byte(content), 0600); err != nil { + t.Fatalf("failed to write test manifest: %v", err) + } + + objects, err := ParseManifestFile(manifestPath) + if err != nil { + t.Fatalf("ParseManifestFile() error = %v", err) + } + if len(objects) != 2 { + t.Errorf("ParseManifestFile() returned %d objects, want 2", len(objects)) + } +} + +func TestParseManifestFile_notFound(t *testing.T) { + _, err := ParseManifestFile("/nonexistent/path/test.yaml") + if err == nil { + t.Error("ParseManifestFile() expected error for nonexistent file, got nil") + } +} diff --git a/internal/operator/package_reconciler.go b/internal/operator/package_reconciler.go new file mode 100644 index 00000000..0e724e49 --- /dev/null +++ b/internal/operator/package_reconciler.go @@ -0,0 +1,1016 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package operator + +import ( + "context" + "fmt" + "strings" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + helmv2 "github.com/fluxcd/helm-controller/api/v2" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +const ( + // AnnotationSkipCozystackValues disables injection of cozystack-values secret into HelmRelease + // This annotation should be placed on PackageSource + AnnotationSkipCozystackValues = "operator.cozystack.io/skip-cozystack-values" + // SecretCozystackValues is the name of the secret containing cluster and namespace configuration + SecretCozystackValues = "cozystack-values" +) + +// parseCRDPolicy maps ComponentInstall.UpgradeCRDs to a helmv2.CRDsPolicy. +// Empty / nil preserves the helm-controller default (Skip on upgrade); +// the CRD enum marker restricts the string to Skip/Create/CreateReplace. +func parseCRDPolicy(install *cozyv1alpha1.ComponentInstall) helmv2.CRDsPolicy { + if install == nil || install.UpgradeCRDs == "" { + return "" + } + return helmv2.CRDsPolicy(install.UpgradeCRDs) +} + +// PackageReconciler reconciles Package resources +type PackageReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +// +kubebuilder:rbac:groups=cozystack.io,resources=packages,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=cozystack.io,resources=packages/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=cozystack.io,resources=packagesources,verbs=get;list;watch +// +kubebuilder:rbac:groups=helm.toolkit.fluxcd.io,resources=helmreleases,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=core,resources=namespaces,verbs=get;list;watch;create;update;patch + +// Reconcile is part of the main kubernetes reconciliation loop +func (r *PackageReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + pkg := &cozyv1alpha1.Package{} + if err := r.Get(ctx, req.NamespacedName, pkg); err != nil { + if apierrors.IsNotFound(err) { + // Resource not found, return (ownerReference will handle cleanup) + return ctrl.Result{}, nil + } + return ctrl.Result{}, err + } + + // Get PackageSource with the same name + packageSource := &cozyv1alpha1.PackageSource{} + if err := r.Get(ctx, types.NamespacedName{Name: pkg.Name}, packageSource); err != nil { + if apierrors.IsNotFound(err) { + meta.SetStatusCondition(&pkg.Status.Conditions, metav1.Condition{ + Type: "Ready", + Status: metav1.ConditionFalse, + Reason: "PackageSourceNotFound", + Message: fmt.Sprintf("PackageSource %s not found", pkg.Name), + }) + if err := r.Status().Update(ctx, pkg); err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, nil + } + return ctrl.Result{}, err + } + + // Determine variant (default to "default" if not specified) + variantName := pkg.Spec.Variant + if variantName == "" { + variantName = "default" + } + + // Find the variant in PackageSource + var variant *cozyv1alpha1.Variant + for i := range packageSource.Spec.Variants { + if packageSource.Spec.Variants[i].Name == variantName { + variant = &packageSource.Spec.Variants[i] + break + } + } + + if variant == nil { + meta.SetStatusCondition(&pkg.Status.Conditions, metav1.Condition{ + Type: "Ready", + Status: metav1.ConditionFalse, + Reason: "VariantNotFound", + Message: fmt.Sprintf("Variant %s not found in PackageSource %s", variantName, pkg.Name), + }) + if err := r.Status().Update(ctx, pkg); err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, nil + } + + // Reconcile namespaces from components + if err := r.reconcileNamespaces(ctx, pkg, variant); err != nil { + logger.Error(err, "failed to reconcile namespaces") + return ctrl.Result{}, err + } + + // Update dependencies status + if err := r.updateDependenciesStatus(ctx, pkg, variant); err != nil { + logger.Error(err, "failed to update dependencies status") + // Don't return error, continue with reconciliation + } + + // Validate variant dependencies before creating HelmReleases + // Check if all dependencies are ready based on status + if !r.areDependenciesReady(pkg, variant) { + logger.Info("variant dependencies not ready, skipping HelmRelease creation", "package", pkg.Name) + meta.SetStatusCondition(&pkg.Status.Conditions, metav1.Condition{ + Type: "Ready", + Status: metav1.ConditionFalse, + Reason: "DependenciesNotReady", + Message: "One or more dependencies are not ready", + }) + if err := r.Status().Update(ctx, pkg); err != nil { + return ctrl.Result{}, err + } + // Return success to avoid requeue, but don't create HelmReleases + return ctrl.Result{}, nil + } + + // Create HelmReleases for components with Install section + helmReleaseCount := 0 + for _, component := range variant.Components { + // Skip components without Install section + if component.Install == nil { + continue + } + + // Check if component is disabled via Package spec + if pkgComponent, ok := pkg.Spec.Components[component.Name]; ok { + if pkgComponent.Enabled != nil && !*pkgComponent.Enabled { + logger.V(1).Info("skipping disabled component", "package", pkg.Name, "component", component.Name) + continue + } + } + + // Build artifact name: -- (with dots replaced by dashes) + artifactName := fmt.Sprintf("%s-%s-%s", + strings.ReplaceAll(packageSource.Name, ".", "-"), + strings.ReplaceAll(variantName, ".", "-"), + strings.ReplaceAll(component.Name, ".", "-")) + + // Namespace must be set + namespace := component.Install.Namespace + if namespace == "" { + logger.Error(fmt.Errorf("component %s has empty namespace in Install section", component.Name), "namespace validation failed") + meta.SetStatusCondition(&pkg.Status.Conditions, metav1.Condition{ + Type: "Ready", + Status: metav1.ConditionFalse, + Reason: "InvalidConfiguration", + Message: fmt.Sprintf("Component %s has empty namespace in Install section", component.Name), + }) + if err := r.Status().Update(ctx, pkg); err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, fmt.Errorf("component %s has empty namespace in Install section", component.Name) + } + + // Determine release name (from Install or use component name) + releaseName := component.Install.ReleaseName + if releaseName == "" { + releaseName = component.Name + } + + // Build labels + labels := make(map[string]string) + labels["cozystack.io/package"] = pkg.Name + if component.Install.Privileged { + labels["cozystack.io/privileged"] = "true" + } + + // Create HelmRelease + hr := &helmv2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: releaseName, + Namespace: namespace, + Labels: labels, + }, + Spec: helmv2.HelmReleaseSpec{ + Interval: metav1.Duration{Duration: 5 * 60 * 1000000000}, // 5m + ChartRef: &helmv2.CrossNamespaceSourceReference{ + Kind: "ExternalArtifact", + Name: artifactName, + Namespace: "cozy-system", + }, + Install: &helmv2.Install{ + Timeout: &metav1.Duration{Duration: 10 * 60 * 1000000000}, // 10m + Remediation: &helmv2.InstallRemediation{ + Retries: -1, + }, + }, + Upgrade: &helmv2.Upgrade{ + Timeout: &metav1.Duration{Duration: 10 * 60 * 1000000000}, // 10m + Remediation: &helmv2.UpgradeRemediation{ + Retries: -1, + }, + CRDs: parseCRDPolicy(component.Install), + }, + }, + } + + // Add valuesFrom for cozystack-values secret unless disabled by annotation on PackageSource + if packageSource.GetAnnotations()[AnnotationSkipCozystackValues] != "true" { + hr.Spec.ValuesFrom = []helmv2.ValuesReference{ + { + Kind: "Secret", + Name: SecretCozystackValues, + }, + } + } + + // Set ownerReference + gvk, err := apiutil.GVKForObject(pkg, r.Scheme) + if err != nil { + logger.Error(err, "failed to get GVK for Package") + meta.SetStatusCondition(&pkg.Status.Conditions, metav1.Condition{ + Type: "Ready", + Status: metav1.ConditionFalse, + Reason: "InternalError", + Message: fmt.Sprintf("Failed to get GVK for Package: %v", err), + }) + if err := r.Status().Update(ctx, pkg); err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, fmt.Errorf("failed to get GVK for Package: %w", err) + } + hr.OwnerReferences = []metav1.OwnerReference{ + { + APIVersion: gvk.GroupVersion().String(), + Kind: gvk.Kind, + Name: pkg.Name, + UID: pkg.UID, + Controller: func() *bool { b := true; return &b }(), + }, + } + + // Merge values from Package spec if provided + if pkgComponent, ok := pkg.Spec.Components[component.Name]; ok && pkgComponent.Values != nil { + hr.Spec.Values = pkgComponent.Values + } + + // Build DependsOn from component Install and variant DependsOn + dependsOn, err := r.buildDependsOn(ctx, pkg, packageSource, variant, &component) + if err != nil { + logger.Error(err, "failed to build DependsOn", "component", component.Name) + meta.SetStatusCondition(&pkg.Status.Conditions, metav1.Condition{ + Type: "Ready", + Status: metav1.ConditionFalse, + Reason: "DependsOnFailed", + Message: fmt.Sprintf("Failed to build DependsOn for component %s: %v", component.Name, err), + }) + if err := r.Status().Update(ctx, pkg); err != nil { + return ctrl.Result{}, err + } + // Return nil to stop reconciliation, error is recorded in status + return ctrl.Result{}, nil + } + if len(dependsOn) > 0 { + hr.Spec.DependsOn = dependsOn + } + + // Set valuesFiles annotation + if len(component.ValuesFiles) > 0 { + if hr.Annotations == nil { + hr.Annotations = make(map[string]string) + } + hr.Annotations["cozyhr.cozystack.io/values-files"] = strings.Join(component.ValuesFiles, ",") + } + + if err := r.createOrUpdateHelmRelease(ctx, hr); err != nil { + logger.Error(err, "failed to reconcile HelmRelease", "name", releaseName, "namespace", namespace) + meta.SetStatusCondition(&pkg.Status.Conditions, metav1.Condition{ + Type: "Ready", + Status: metav1.ConditionFalse, + Reason: "HelmReleaseFailed", + Message: fmt.Sprintf("Failed to create HelmRelease %s: %v", releaseName, err), + }) + if err := r.Status().Update(ctx, pkg); err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{}, err + } + + helmReleaseCount++ + logger.Info("reconciled HelmRelease", "package", pkg.Name, "component", component.Name, "releaseName", releaseName, "namespace", namespace) + } + + // Cleanup orphaned HelmReleases + if err := r.cleanupOrphanedHelmReleases(ctx, pkg, variant); err != nil { + logger.Error(err, "failed to cleanup orphaned HelmReleases") + // Don't return error, continue with status update + } + + // Update status with success message + message := fmt.Sprintf("reconciliation succeeded, generated %d helmrelease(s)", helmReleaseCount) + meta.SetStatusCondition(&pkg.Status.Conditions, metav1.Condition{ + Type: "Ready", + Status: metav1.ConditionTrue, + Reason: "ReconciliationSucceeded", + Message: message, + }) + + if err := r.Status().Update(ctx, pkg); err != nil { + return ctrl.Result{}, err + } + + logger.Info("reconciled Package", "name", pkg.Name, "helmReleaseCount", helmReleaseCount) + + // Update dependencies status for Packages that depend on this Package + // This ensures they get re-enqueued when their dependency becomes ready + if err := r.updateDependentPackagesDependencies(ctx, pkg.Name); err != nil { + logger.V(1).Error(err, "failed to update dependent packages dependencies", "package", pkg.Name) + // Don't return error, this is best-effort + } + + // Dependent Packages will be automatically enqueued by the watch handler + // when this Package's status is updated (see SetupWithManager watch handler) + + return ctrl.Result{}, nil +} + +// createOrUpdateHelmRelease creates or updates a HelmRelease +func (r *PackageReconciler) createOrUpdateHelmRelease(ctx context.Context, hr *helmv2.HelmRelease) error { + existing := &helmv2.HelmRelease{} + key := types.NamespacedName{ + Name: hr.Name, + Namespace: hr.Namespace, + } + + err := r.Get(ctx, key, existing) + if apierrors.IsNotFound(err) { + return r.Create(ctx, hr) + } else if err != nil { + return err + } + + // Preserve resource version + hr.SetResourceVersion(existing.GetResourceVersion()) + + // Merge labels + labels := hr.GetLabels() + if labels == nil { + labels = make(map[string]string) + } + for k, v := range existing.GetLabels() { + if _, ok := labels[k]; !ok { + labels[k] = v + } + } + hr.SetLabels(labels) + + // Merge annotations + annotations := hr.GetAnnotations() + if annotations == nil { + annotations = make(map[string]string) + } + for k, v := range existing.GetAnnotations() { + if _, ok := annotations[k]; !ok { + annotations[k] = v + } + } + hr.SetAnnotations(annotations) + + hr.Spec.Suspend = existing.Spec.Suspend + // Update Spec + existing.Spec = hr.Spec + existing.SetLabels(hr.GetLabels()) + existing.SetAnnotations(hr.GetAnnotations()) + existing.SetOwnerReferences(hr.GetOwnerReferences()) + + return r.Update(ctx, existing) +} + +// getVariantForPackage retrieves the Variant for a given Package +// Returns the Variant and an error if not found +// If c is nil, uses the reconciler's client +func (r *PackageReconciler) getVariantForPackage(ctx context.Context, pkg *cozyv1alpha1.Package, c client.Client) (*cozyv1alpha1.Variant, error) { + // Use provided client or fall back to reconciler's client + cl := c + if cl == nil { + cl = r.Client + } + + // Determine variant name (default to "default" if not specified) + variantName := pkg.Spec.Variant + if variantName == "" { + variantName = "default" + } + + // Get the PackageSource + packageSource := &cozyv1alpha1.PackageSource{} + if err := cl.Get(ctx, types.NamespacedName{Name: pkg.Name}, packageSource); err != nil { + if apierrors.IsNotFound(err) { + return nil, fmt.Errorf("PackageSource %s not found", pkg.Name) + } + return nil, fmt.Errorf("failed to get PackageSource %s: %w", pkg.Name, err) + } + + // Find the variant in PackageSource + var variant *cozyv1alpha1.Variant + for i := range packageSource.Spec.Variants { + if packageSource.Spec.Variants[i].Name == variantName { + variant = &packageSource.Spec.Variants[i] + break + } + } + + if variant == nil { + return nil, fmt.Errorf("variant %s not found in PackageSource %s", variantName, pkg.Name) + } + + return variant, nil +} + +// buildDependsOn builds DependsOn list for a component +// Includes: +// 1. Dependencies from component.Install.DependsOn (with namespace from referenced component) +// 2. Dependencies from variant.DependsOn (all components with Install from referenced Package) +func (r *PackageReconciler) buildDependsOn(ctx context.Context, pkg *cozyv1alpha1.Package, packageSource *cozyv1alpha1.PackageSource, variant *cozyv1alpha1.Variant, component *cozyv1alpha1.Component) ([]helmv2.DependencyReference, error) { + logger := log.FromContext(ctx) + dependsOn := []helmv2.DependencyReference{} + + // Build map of component names to their release names and namespaces in current variant + componentMap := make(map[string]struct { + releaseName string + namespace string + }) + for _, comp := range variant.Components { + if comp.Install == nil { + continue + } + compNamespace := comp.Install.Namespace + if compNamespace == "" { + return nil, fmt.Errorf("component %s has empty namespace in Install section", comp.Name) + } + compReleaseName := comp.Install.ReleaseName + if compReleaseName == "" { + compReleaseName = comp.Name + } + componentMap[comp.Name] = struct { + releaseName string + namespace string + }{ + releaseName: compReleaseName, + namespace: compNamespace, + } + } + + // Add dependencies from component.Install.DependsOn + if len(component.Install.DependsOn) > 0 { + for _, depName := range component.Install.DependsOn { + depComp, ok := componentMap[depName] + if !ok { + return nil, fmt.Errorf("component %s not found in variant for dependency %s", depName, component.Name) + } + dependsOn = append(dependsOn, helmv2.DependencyReference{ + Name: depComp.releaseName, + Namespace: depComp.namespace, + }) + logger.V(1).Info("added component dependency", "component", component.Name, "dependsOn", depName, "releaseName", depComp.releaseName, "namespace", depComp.namespace) + } + } + + // Add dependencies from variant.DependsOn + if len(variant.DependsOn) > 0 { + for _, depPackageName := range variant.DependsOn { + // Check if dependency is in IgnoreDependencies + ignore := false + for _, ignoreDep := range pkg.Spec.IgnoreDependencies { + if ignoreDep == depPackageName { + ignore = true + break + } + } + if ignore { + logger.V(1).Info("ignoring dependency", "package", pkg.Name, "dependency", depPackageName) + continue + } + + // Get the Package + depPackage := &cozyv1alpha1.Package{} + if err := r.Get(ctx, types.NamespacedName{Name: depPackageName}, depPackage); err != nil { + if apierrors.IsNotFound(err) { + return nil, fmt.Errorf("dependent Package %s not found", depPackageName) + } + return nil, fmt.Errorf("failed to get dependent Package %s: %w", depPackageName, err) + } + + // Get the variant from dependent Package + depVariant, err := r.getVariantForPackage(ctx, depPackage, nil) + if err != nil { + return nil, fmt.Errorf("failed to get variant for dependent Package %s: %w", depPackageName, err) + } + + // Add all components with Install from dependent variant + for _, depComp := range depVariant.Components { + if depComp.Install == nil { + continue + } + + // Check if component is disabled in dependent Package + if depPkgComponent, ok := depPackage.Spec.Components[depComp.Name]; ok { + if depPkgComponent.Enabled != nil && !*depPkgComponent.Enabled { + continue + } + } + + depCompNamespace := depComp.Install.Namespace + if depCompNamespace == "" { + return nil, fmt.Errorf("component %s in dependent Package %s has empty namespace in Install section", depComp.Name, depPackageName) + } + depCompReleaseName := depComp.Install.ReleaseName + if depCompReleaseName == "" { + depCompReleaseName = depComp.Name + } + + dependsOn = append(dependsOn, helmv2.DependencyReference{ + Name: depCompReleaseName, + Namespace: depCompNamespace, + }) + logger.V(1).Info("added variant dependency", "package", pkg.Name, "dependency", depPackageName, "component", depComp.Name, "releaseName", depCompReleaseName, "namespace", depCompNamespace) + } + } + } + + return dependsOn, nil +} + +// updateDependenciesStatus updates the dependencies status in Package status +// It checks the readiness of each dependency and updates pkg.Status.Dependencies +// Old dependency keys that are no longer in the dependency list are removed +func (r *PackageReconciler) updateDependenciesStatus(ctx context.Context, pkg *cozyv1alpha1.Package, variant *cozyv1alpha1.Variant) error { + logger := log.FromContext(ctx) + + // Initialize dependencies map if nil + if pkg.Status.Dependencies == nil { + pkg.Status.Dependencies = make(map[string]cozyv1alpha1.DependencyStatus) + } + + // Build set of current dependencies (excluding ignored ones) + currentDeps := make(map[string]bool) + if len(variant.DependsOn) > 0 { + for _, depPackageName := range variant.DependsOn { + // Check if dependency is in IgnoreDependencies + ignore := false + for _, ignoreDep := range pkg.Spec.IgnoreDependencies { + if ignoreDep == depPackageName { + ignore = true + break + } + } + if ignore { + logger.V(1).Info("ignoring dependency", "package", pkg.Name, "dependency", depPackageName) + continue + } + currentDeps[depPackageName] = true + } + } + + // Remove old dependencies that are no longer in the list + for depName := range pkg.Status.Dependencies { + if !currentDeps[depName] { + delete(pkg.Status.Dependencies, depName) + logger.V(1).Info("removed old dependency from status", "package", pkg.Name, "dependency", depName) + } + } + + // Update status for each current dependency + for depPackageName := range currentDeps { + // Get the Package + depPackage := &cozyv1alpha1.Package{} + if err := r.Get(ctx, types.NamespacedName{Name: depPackageName}, depPackage); err != nil { + if apierrors.IsNotFound(err) { + // Dependency not found, mark as not ready + pkg.Status.Dependencies[depPackageName] = cozyv1alpha1.DependencyStatus{ + Ready: false, + } + logger.V(1).Info("dependency not found, marking as not ready", "package", pkg.Name, "dependency", depPackageName) + continue + } + // Error getting dependency, keep existing status or mark as not ready + if _, exists := pkg.Status.Dependencies[depPackageName]; !exists { + pkg.Status.Dependencies[depPackageName] = cozyv1alpha1.DependencyStatus{ + Ready: false, + } + } + logger.V(1).Error(err, "failed to get dependency, keeping existing status", "package", pkg.Name, "dependency", depPackageName) + continue + } + + // Check Ready condition + readyCondition := meta.FindStatusCondition(depPackage.Status.Conditions, "Ready") + isReady := readyCondition != nil && readyCondition.Status == metav1.ConditionTrue + + // Update dependency status + pkg.Status.Dependencies[depPackageName] = cozyv1alpha1.DependencyStatus{ + Ready: isReady, + } + logger.V(1).Info("updated dependency status", "package", pkg.Name, "dependency", depPackageName, "ready", isReady) + } + + return nil +} + +// areDependenciesReady checks if all dependencies are ready based on status +func (r *PackageReconciler) areDependenciesReady(pkg *cozyv1alpha1.Package, variant *cozyv1alpha1.Variant) bool { + if len(variant.DependsOn) == 0 { + return true + } + + for _, depPackageName := range variant.DependsOn { + // Check if dependency is in IgnoreDependencies + ignore := false + for _, ignoreDep := range pkg.Spec.IgnoreDependencies { + if ignoreDep == depPackageName { + ignore = true + break + } + } + if ignore { + continue + } + + // Check dependency status + depStatus, exists := pkg.Status.Dependencies[depPackageName] + if !exists || !depStatus.Ready { + return false + } + } + + return true +} + +// updateDependentPackagesDependencies updates dependencies status for all Packages that depend on the given Package +// This ensures dependent packages get re-enqueued when their dependency status changes +func (r *PackageReconciler) updateDependentPackagesDependencies(ctx context.Context, packageName string) error { + logger := log.FromContext(ctx) + + // Get all Packages + packageList := &cozyv1alpha1.PackageList{} + if err := r.List(ctx, packageList); err != nil { + return fmt.Errorf("failed to list Packages: %w", err) + } + + // Get the updated Package to check its readiness + updatedPkg := &cozyv1alpha1.Package{} + if err := r.Get(ctx, types.NamespacedName{Name: packageName}, updatedPkg); err != nil { + if apierrors.IsNotFound(err) { + return nil // Package not found, nothing to update + } + return fmt.Errorf("failed to get Package %s: %w", packageName, err) + } + + // Check Ready condition of the updated Package + readyCondition := meta.FindStatusCondition(updatedPkg.Status.Conditions, "Ready") + isReady := readyCondition != nil && readyCondition.Status == metav1.ConditionTrue + + // For each Package, check if it depends on the given Package + for _, pkg := range packageList.Items { + // Skip the Package itself + if pkg.Name == packageName { + continue + } + + // Get variant + variant, err := r.getVariantForPackage(ctx, &pkg, nil) + if err != nil { + // Continue if PackageSource or variant not found (best-effort operation) + logger.V(1).Info("skipping package, failed to get variant", "package", pkg.Name, "error", err) + continue + } + + // Check if this Package depends on the given Package + dependsOn := false + for _, dep := range variant.DependsOn { + // Check if dependency is in IgnoreDependencies + ignore := false + for _, ignoreDep := range pkg.Spec.IgnoreDependencies { + if ignoreDep == dep { + ignore = true + break + } + } + if ignore { + continue + } + + if dep == packageName { + dependsOn = true + break + } + } + + if dependsOn { + // Update the dependency status in this Package + if pkg.Status.Dependencies == nil { + pkg.Status.Dependencies = make(map[string]cozyv1alpha1.DependencyStatus) + } + pkg.Status.Dependencies[packageName] = cozyv1alpha1.DependencyStatus{ + Ready: isReady, + } + if err := r.Status().Update(ctx, &pkg); err != nil { + logger.V(1).Error(err, "failed to update dependency status for dependent Package", "package", pkg.Name, "dependency", packageName) + continue + } + logger.V(1).Info("updated dependency status for dependent Package", "package", pkg.Name, "dependency", packageName, "ready", isReady) + } + } + + return nil +} + +// reconcileNamespaces creates or updates namespaces based on components in the variant. +// For each namespace, it checks ALL Packages sharing that namespace to determine whether +// the namespace should be privileged — it is privileged if ANY Package has a privileged +// component installed in it. +func (r *PackageReconciler) reconcileNamespaces(ctx context.Context, pkg *cozyv1alpha1.Package, variant *cozyv1alpha1.Variant) error { + logger := log.FromContext(ctx) + + // Collect namespaces from this Package's components + targetNamespaces := make(map[string]struct{}) + for _, component := range variant.Components { + if component.Install == nil { + continue + } + if pkgComponent, ok := pkg.Spec.Components[component.Name]; ok { + if pkgComponent.Enabled != nil && !*pkgComponent.Enabled { + continue + } + } + namespace := component.Install.Namespace + if namespace == "" { + return fmt.Errorf("component %s has empty namespace in Install section", component.Name) + } + targetNamespaces[namespace] = struct{}{} + } + + // Determine which namespaces should be privileged by checking ALL Packages + privileged, err := r.resolvePrivilegedNamespaces(ctx, targetNamespaces) + if err != nil { + return fmt.Errorf("failed to resolve privileged namespaces: %w", err) + } + + // Create or update all namespaces + for nsName := range targetNamespaces { + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: nsName, + Labels: make(map[string]string), + Annotations: map[string]string{ + "helm.sh/resource-policy": "keep", + }, + }, + } + + if !strings.HasPrefix(nsName, "tenant-") { + namespace.Labels["cozystack.io/system"] = "true" + } + + if privileged[nsName] { + namespace.Labels["pod-security.kubernetes.io/enforce"] = "privileged" + } + + if err := r.createOrUpdateNamespace(ctx, namespace); err != nil { + logger.Error(err, "failed to reconcile namespace", "name", nsName, "privileged", privileged[nsName]) + return fmt.Errorf("failed to reconcile namespace %s: %w", nsName, err) + } + logger.Info("reconciled namespace", "name", nsName, "privileged", privileged[nsName]) + } + + return nil +} + +// resolvePrivilegedNamespaces checks all PackageSources and their corresponding Packages +// to determine which of the given namespaces require the privileged PodSecurity level. +// A namespace is privileged if ANY active Package has a component with privileged: true in it. +func (r *PackageReconciler) resolvePrivilegedNamespaces(ctx context.Context, namespaces map[string]struct{}) (map[string]bool, error) { + result := make(map[string]bool) + + packageSources := &cozyv1alpha1.PackageSourceList{} + if err := r.List(ctx, packageSources); err != nil { + return nil, fmt.Errorf("failed to list PackageSources: %w", err) + } + + for i := range packageSources.Items { + ps := &packageSources.Items[i] + + // Check if a Package exists for this PackageSource + pkg := &cozyv1alpha1.Package{} + if err := r.Get(ctx, types.NamespacedName{Name: ps.Name}, pkg); err != nil { + if apierrors.IsNotFound(err) { + continue + } + return nil, fmt.Errorf("failed to get Package %s: %w", ps.Name, err) + } + + // Resolve active variant + variantName := pkg.Spec.Variant + if variantName == "" { + variantName = "default" + } + + var variant *cozyv1alpha1.Variant + for j := range ps.Spec.Variants { + if ps.Spec.Variants[j].Name == variantName { + variant = &ps.Spec.Variants[j] + break + } + } + if variant == nil { + continue + } + + for _, component := range variant.Components { + if component.Install == nil { + continue + } + if pkgComponent, ok := pkg.Spec.Components[component.Name]; ok { + if pkgComponent.Enabled != nil && !*pkgComponent.Enabled { + continue + } + } + if _, relevant := namespaces[component.Install.Namespace]; !relevant { + continue + } + if component.Install.Privileged { + result[component.Install.Namespace] = true + } + } + } + + return result, nil +} + +// createOrUpdateNamespace creates or updates a namespace using server-side apply. +func (r *PackageReconciler) createOrUpdateNamespace(ctx context.Context, namespace *corev1.Namespace) error { + namespace.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("Namespace")) + return r.Patch(ctx, namespace, client.Apply, client.FieldOwner("cozystack-package-controller"), client.ForceOwnership) +} + +// cleanupOrphanedHelmReleases removes HelmReleases that are no longer needed +func (r *PackageReconciler) cleanupOrphanedHelmReleases(ctx context.Context, pkg *cozyv1alpha1.Package, variant *cozyv1alpha1.Variant) error { + logger := log.FromContext(ctx) + + // Build map of desired HelmRelease names (from components with Install) + desiredReleases := make(map[types.NamespacedName]bool) + for _, component := range variant.Components { + if component.Install == nil { + continue + } + + // Check if component is disabled via Package spec + if pkgComponent, ok := pkg.Spec.Components[component.Name]; ok { + if pkgComponent.Enabled != nil && !*pkgComponent.Enabled { + continue + } + } + + namespace := component.Install.Namespace + if namespace == "" { + // Skip components with empty namespace (they shouldn't exist anyway) + continue + } + + releaseName := component.Install.ReleaseName + if releaseName == "" { + releaseName = component.Name + } + + desiredReleases[types.NamespacedName{ + Name: releaseName, + Namespace: namespace, + }] = true + } + + // Find all HelmReleases owned by this Package + hrList := &helmv2.HelmReleaseList{} + if err := r.List(ctx, hrList, client.MatchingLabels{ + "cozystack.io/package": pkg.Name, + }); err != nil { + return err + } + + // Delete HelmReleases that are not in desired list + for _, hr := range hrList.Items { + key := types.NamespacedName{ + Name: hr.Name, + Namespace: hr.Namespace, + } + if !desiredReleases[key] { + logger.Info("deleting orphaned HelmRelease", "name", hr.Name, "namespace", hr.Namespace, "package", pkg.Name) + if err := r.Delete(ctx, &hr); err != nil && !apierrors.IsNotFound(err) { + logger.Error(err, "failed to delete orphaned HelmRelease", "name", hr.Name, "namespace", hr.Namespace) + } + } + } + + return nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *PackageReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + Named("cozystack-package"). + For(&cozyv1alpha1.Package{}). + Owns(&helmv2.HelmRelease{}). + Watches( + &cozyv1alpha1.PackageSource{}, + handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request { + ps, ok := obj.(*cozyv1alpha1.PackageSource) + if !ok { + return nil + } + // Find Package with the same name as PackageSource + // PackageSource and Package share the same name + pkg := &cozyv1alpha1.Package{} + if err := mgr.GetClient().Get(ctx, types.NamespacedName{Name: ps.Name}, pkg); err != nil { + // Package not found, that's ok - it might not exist yet + return nil + } + // Trigger reconcile for the corresponding Package + return []reconcile.Request{{ + NamespacedName: types.NamespacedName{ + Name: pkg.Name, + }, + }} + }), + ). + Watches( + &cozyv1alpha1.Package{}, + handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, obj client.Object) []reconcile.Request { + updatedPkg, ok := obj.(*cozyv1alpha1.Package) + if !ok { + return nil + } + // Find all Packages that depend on this Package + packageList := &cozyv1alpha1.PackageList{} + if err := mgr.GetClient().List(ctx, packageList); err != nil { + return nil + } + var requests []reconcile.Request + for _, pkg := range packageList.Items { + if pkg.Name == updatedPkg.Name { + continue // Skip the Package itself + } + // Get variant to check dependencies + variant, err := r.getVariantForPackage(ctx, &pkg, mgr.GetClient()) + if err != nil { + // Continue if PackageSource or variant not found + continue + } + // Check if this variant depends on updatedPkg + for _, dep := range variant.DependsOn { + // Check if dependency is in IgnoreDependencies + ignore := false + for _, ignoreDep := range pkg.Spec.IgnoreDependencies { + if ignoreDep == dep { + ignore = true + break + } + } + if ignore { + continue + } + if dep == updatedPkg.Name { + requests = append(requests, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: pkg.Name, + }, + }) + break + } + } + } + return requests + }), + ). + Complete(r) +} diff --git a/internal/operator/package_reconciler_test.go b/internal/operator/package_reconciler_test.go new file mode 100644 index 00000000..f0ee2c19 --- /dev/null +++ b/internal/operator/package_reconciler_test.go @@ -0,0 +1,138 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package operator + +import ( + "encoding/json" + "os" + "path/filepath" + "testing" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + helmv2 "github.com/fluxcd/helm-controller/api/v2" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "sigs.k8s.io/yaml" +) + +func TestParseCRDPolicy(t *testing.T) { + tests := []struct { + name string + install *cozyv1alpha1.ComponentInstall + want helmv2.CRDsPolicy + }{ + { + name: "nil install leaves flux default", + install: nil, + want: "", + }, + { + name: "empty upgradeCRDs leaves flux default", + install: &cozyv1alpha1.ComponentInstall{}, + want: "", + }, + { + name: "Skip is passed through", + install: &cozyv1alpha1.ComponentInstall{UpgradeCRDs: "Skip"}, + want: helmv2.Skip, + }, + { + name: "Create is passed through", + install: &cozyv1alpha1.ComponentInstall{UpgradeCRDs: "Create"}, + want: helmv2.Create, + }, + { + name: "CreateReplace is passed through", + install: &cozyv1alpha1.ComponentInstall{UpgradeCRDs: "CreateReplace"}, + want: helmv2.CreateReplace, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got := parseCRDPolicy(tc.install) + if got != tc.want { + t.Errorf("parseCRDPolicy() = %q, want %q", got, tc.want) + } + }) + } +} + +// TestPackageSourceCRDHasUpgradeCRDsEnum guards the generated CRD schema: the +// invalid-value case from the spec is enforced at the API server via a +// kubebuilder enum marker, not in the reconciler. If someone drops the marker +// and forgets to regenerate, this test catches it. +func TestPackageSourceCRDHasUpgradeCRDsEnum(t *testing.T) { + path := filepath.Join("..", "crdinstall", "manifests", "cozystack.io_packagesources.yaml") + data, err := os.ReadFile(path) + if err != nil { + t.Fatalf("read %s: %v", path, err) + } + + var crd apiextensionsv1.CustomResourceDefinition + if err := yaml.Unmarshal(data, &crd); err != nil { + t.Fatalf("unmarshal CRD: %v", err) + } + + var field *apiextensionsv1.JSONSchemaProps + for i := range crd.Spec.Versions { + v := &crd.Spec.Versions[i] + if v.Schema == nil || v.Schema.OpenAPIV3Schema == nil { + continue + } + spec, ok := v.Schema.OpenAPIV3Schema.Properties["spec"] + if !ok { + continue + } + variants, ok := spec.Properties["variants"] + if !ok || variants.Items == nil || variants.Items.Schema == nil { + continue + } + components, ok := variants.Items.Schema.Properties["components"] + if !ok || components.Items == nil || components.Items.Schema == nil { + continue + } + install, ok := components.Items.Schema.Properties["install"] + if !ok { + continue + } + f, ok := install.Properties["upgradeCRDs"] + if !ok { + continue + } + field = &f + break + } + + if field == nil { + t.Fatal("upgradeCRDs field not found in PackageSource CRD schema") + } + + got := map[string]bool{} + for _, e := range field.Enum { + var s string + if err := json.Unmarshal(e.Raw, &s); err != nil { + t.Fatalf("unmarshal enum value %q: %v", e.Raw, err) + } + got[s] = true + } + + for _, want := range []string{"Skip", "Create", "CreateReplace"} { + if !got[want] { + t.Errorf("enum value %q missing from upgradeCRDs; got %v", want, got) + } + } +} diff --git a/internal/operator/packagesource_reconciler.go b/internal/operator/packagesource_reconciler.go new file mode 100644 index 00000000..e79370bd --- /dev/null +++ b/internal/operator/packagesource_reconciler.go @@ -0,0 +1,413 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package operator + +import ( + "context" + "fmt" + "strings" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + sourcewatcherv1beta1 "github.com/fluxcd/source-watcher/api/v2/v1beta1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +// PackageSourceReconciler reconciles PackageSource resources +type PackageSourceReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +// +kubebuilder:rbac:groups=cozystack.io,resources=packagesources,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=cozystack.io,resources=packagesources/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=source.extensions.fluxcd.io,resources=artifactgenerators,verbs=get;list;watch;create;update;patch;delete + +// Reconcile is part of the main kubernetes reconciliation loop +func (r *PackageSourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + packageSource := &cozyv1alpha1.PackageSource{} + if err := r.Get(ctx, req.NamespacedName, packageSource); err != nil { + if apierrors.IsNotFound(err) { + // Resource not found, return (ownerReference will handle cleanup) + return ctrl.Result{}, nil + } + return ctrl.Result{}, err + } + + // Generate ArtifactGenerator for package source + if err := r.reconcileArtifactGenerators(ctx, packageSource); err != nil { + logger.Error(err, "failed to reconcile ArtifactGenerator") + return ctrl.Result{}, err + } + + // Update PackageSource status (variants and conditions from ArtifactGenerator) + if err := r.updateStatus(ctx, packageSource); err != nil { + logger.Error(err, "failed to update status") + // Don't return error, status update is not critical + } + + return ctrl.Result{}, nil +} + +// reconcileArtifactGenerators generates a single ArtifactGenerator for the package source +// Creates one ArtifactGenerator per package source with all OutputArtifacts from components +func (r *PackageSourceReconciler) reconcileArtifactGenerators(ctx context.Context, packageSource *cozyv1alpha1.PackageSource) error { + logger := log.FromContext(ctx) + + // Check if SourceRef is set + if packageSource.Spec.SourceRef == nil { + logger.Info("skipping ArtifactGenerator creation, SourceRef not set", "packageSource", packageSource.Name) + return nil + } + + // Namespace is always cozy-system + namespace := "cozy-system" + // ArtifactGenerator name is the package source name + agName := packageSource.Name + + // Collect all OutputArtifacts + outputArtifacts := []sourcewatcherv1beta1.OutputArtifact{} + + // Process all variants and their components + for _, variant := range packageSource.Spec.Variants { + // Build library map for this variant + // Map key is the library name (from lib.Name or extracted from path) + // This allows components in this variant to reference libraries by name + // Libraries are scoped per variant to avoid conflicts between variants + libraryMap := make(map[string]cozyv1alpha1.Library) + for _, lib := range variant.Libraries { + libName := lib.Name + if libName == "" { + // If library name is not set, extract from path + libName = r.getPackageNameFromPath(lib.Path) + } + if libName != "" { + // Store library with the resolved name + libraryMap[libName] = lib + } + } + + for _, component := range variant.Components { + // Skip components without path + if component.Path == "" { + logger.V(1).Info("skipping component without path", "packageSource", packageSource.Name, "variant", variant.Name, "component", component.Name) + continue + } + + logger.V(1).Info("processing component", "packageSource", packageSource.Name, "variant", variant.Name, "component", component.Name, "path", component.Path) + + // Extract component name from path (last component) + componentPathName := r.getPackageNameFromPath(component.Path) + if componentPathName == "" { + logger.Info("skipping component with invalid path", "packageSource", packageSource.Name, "variant", variant.Name, "component", component.Name, "path", component.Path) + continue + } + + // Get basePath with default values + basePath := r.getBasePath(packageSource) + + // Build copy operations + copyOps := []sourcewatcherv1beta1.CopyOperation{ + { + From: r.buildSourcePath(packageSource.Spec.SourceRef.Name, basePath, component.Path), + To: fmt.Sprintf("@artifact/%s/", componentPathName), + }, + } + + // Add libraries if specified + for _, libName := range component.Libraries { + if lib, ok := libraryMap[libName]; ok { + copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ + From: r.buildSourcePath(packageSource.Spec.SourceRef.Name, basePath, lib.Path), + To: fmt.Sprintf("@artifact/%s/charts/%s/", componentPathName, libName), + }) + } + } + + // Add valuesFiles if specified + for i, valuesFile := range component.ValuesFiles { + strategy := "Merge" + if i == 0 { + strategy = "Overwrite" + } + copyOps = append(copyOps, sourcewatcherv1beta1.CopyOperation{ + From: r.buildSourceFilePath(packageSource.Spec.SourceRef.Name, basePath, fmt.Sprintf("%s/%s", component.Path, valuesFile)), + To: fmt.Sprintf("@artifact/%s/values.yaml", componentPathName), + Strategy: strategy, + }) + } + + // Artifact name: -- + // Replace dots with dashes to comply with Kubernetes naming requirements + artifactName := fmt.Sprintf("%s-%s-%s", + strings.ReplaceAll(packageSource.Name, ".", "-"), + strings.ReplaceAll(variant.Name, ".", "-"), + strings.ReplaceAll(component.Name, ".", "-")) + + outputArtifacts = append(outputArtifacts, sourcewatcherv1beta1.OutputArtifact{ + Name: artifactName, + Copy: copyOps, + }) + + logger.Info("added OutputArtifact for component", "packageSource", packageSource.Name, "variant", variant.Name, "component", component.Name, "artifactName", artifactName) + } + } + + // If there are no OutputArtifacts, return (ownerReference will handle cleanup if needed) + if len(outputArtifacts) == 0 { + logger.Info("no OutputArtifacts to generate, skipping ArtifactGenerator creation", "packageSource", packageSource.Name) + return nil + } + + // Build labels + labels := make(map[string]string) + labels["cozystack.io/packagesource"] = packageSource.Name + + // Create single ArtifactGenerator for the package source + ag := &sourcewatcherv1beta1.ArtifactGenerator{ + ObjectMeta: metav1.ObjectMeta{ + Name: agName, + Namespace: namespace, + Labels: labels, + }, + Spec: sourcewatcherv1beta1.ArtifactGeneratorSpec{ + Sources: []sourcewatcherv1beta1.SourceReference{ + { + Alias: packageSource.Spec.SourceRef.Name, + Kind: packageSource.Spec.SourceRef.Kind, + Name: packageSource.Spec.SourceRef.Name, + Namespace: packageSource.Spec.SourceRef.Namespace, + }, + }, + OutputArtifacts: outputArtifacts, + }, + } + + // Set ownerReference + gvk, err := apiutil.GVKForObject(packageSource, r.Scheme) + if err != nil { + return fmt.Errorf("failed to get GVK for PackageSource: %w", err) + } + ag.OwnerReferences = []metav1.OwnerReference{ + { + APIVersion: gvk.GroupVersion().String(), + Kind: gvk.Kind, + Name: packageSource.Name, + UID: packageSource.UID, + Controller: func() *bool { b := true; return &b }(), + }, + } + + logger.Info("creating ArtifactGenerator for package source", "packageSource", packageSource.Name, "agName", agName, "namespace", namespace, "outputArtifactCount", len(outputArtifacts)) + + if err := r.createOrUpdate(ctx, ag); err != nil { + return fmt.Errorf("failed to reconcile ArtifactGenerator %s: %w", agName, err) + } + + logger.Info("reconciled ArtifactGenerator for package source", "name", agName, "namespace", namespace, "outputArtifactCount", len(outputArtifacts)) + + return nil +} + +// Helper functions +func (r *PackageSourceReconciler) getPackageNameFromPath(path string) string { + parts := strings.Split(path, "/") + if len(parts) > 0 { + return parts[len(parts)-1] + } + return "" +} + +// getBasePath returns the basePath with default values based on source kind +func (r *PackageSourceReconciler) getBasePath(packageSource *cozyv1alpha1.PackageSource) string { + // If path is explicitly set in SourceRef, use it (but normalize "/" to empty) + if packageSource.Spec.SourceRef.Path != "" { + path := strings.Trim(packageSource.Spec.SourceRef.Path, "/") + // If path is "/" or empty after trim, return empty string + if path == "" { + return "" + } + return path + } + // Default values based on kind + if packageSource.Spec.SourceRef.Kind == "OCIRepository" { + return "" // Root for OCI + } + // Default for GitRepository + return "packages" +} + +// buildSourcePath builds the full source path using basePath with glob pattern +func (r *PackageSourceReconciler) buildSourcePath(sourceName, basePath, path string) string { + // Remove leading/trailing slashes and combine + parts := []string{} + if basePath != "" { + trimmed := strings.Trim(basePath, "/") + if trimmed != "" { + parts = append(parts, trimmed) + } + } + if path != "" { + trimmed := strings.Trim(path, "/") + if trimmed != "" { + parts = append(parts, trimmed) + } + } + + fullPath := strings.Join(parts, "/") + if fullPath == "" { + return fmt.Sprintf("@%s/**", sourceName) + } + return fmt.Sprintf("@%s/%s/**", sourceName, fullPath) +} + +// buildSourceFilePath builds the full source path for a specific file (without glob pattern) +func (r *PackageSourceReconciler) buildSourceFilePath(sourceName, basePath, path string) string { + // Remove leading/trailing slashes and combine + parts := []string{} + if basePath != "" { + trimmed := strings.Trim(basePath, "/") + if trimmed != "" { + parts = append(parts, trimmed) + } + } + if path != "" { + trimmed := strings.Trim(path, "/") + if trimmed != "" { + parts = append(parts, trimmed) + } + } + + fullPath := strings.Join(parts, "/") + if fullPath == "" { + return fmt.Sprintf("@%s", sourceName) + } + return fmt.Sprintf("@%s/%s", sourceName, fullPath) +} + +// createOrUpdate creates or updates a resource using server-side apply +func (r *PackageSourceReconciler) createOrUpdate(ctx context.Context, obj client.Object) error { + // Ensure TypeMeta is set for server-side apply + // Use type assertion to set GVK if the object supports it + if runtimeObj, ok := obj.(runtime.Object); ok { + gvk, err := apiutil.GVKForObject(obj, r.Scheme) + if err != nil { + return fmt.Errorf("failed to get GVK for object: %w", err) + } + runtimeObj.GetObjectKind().SetGroupVersionKind(gvk) + } + + // Use server-side apply with field manager + // This is atomic and avoids race conditions from Get/Create/Update pattern + // Labels, annotations, and spec will be merged automatically by the server + // Each field is treated separately, so existing ones are preserved + return r.Patch(ctx, obj, client.Apply, client.FieldOwner("cozystack-packagesource-controller")) +} + +// updateStatus updates PackageSource status (variants and conditions from ArtifactGenerator) +func (r *PackageSourceReconciler) updateStatus(ctx context.Context, packageSource *cozyv1alpha1.PackageSource) error { + logger := log.FromContext(ctx) + + // Update variants in status from spec + variantNames := make([]string, 0, len(packageSource.Spec.Variants)) + for _, variant := range packageSource.Spec.Variants { + variantNames = append(variantNames, variant.Name) + } + packageSource.Status.Variants = strings.Join(variantNames, ",") + + // Check if SourceRef is set + if packageSource.Spec.SourceRef == nil { + // Set status to unknown if SourceRef is not set + meta.SetStatusCondition(&packageSource.Status.Conditions, metav1.Condition{ + Type: "Ready", + Status: metav1.ConditionUnknown, + Reason: "SourceRefNotSet", + Message: "SourceRef is not configured", + }) + return r.Status().Update(ctx, packageSource) + } + + // Get ArtifactGenerator + ag := &sourcewatcherv1beta1.ArtifactGenerator{} + agKey := types.NamespacedName{ + Name: packageSource.Name, + Namespace: "cozy-system", + } + + if err := r.Get(ctx, agKey, ag); err != nil { + if apierrors.IsNotFound(err) { + // ArtifactGenerator not found, set status to unknown + meta.SetStatusCondition(&packageSource.Status.Conditions, metav1.Condition{ + Type: "Ready", + Status: metav1.ConditionUnknown, + Reason: "ArtifactGeneratorNotFound", + Message: "ArtifactGenerator not found", + }) + return r.Status().Update(ctx, packageSource) + } + return fmt.Errorf("failed to get ArtifactGenerator: %w", err) + } + + // Find Ready condition in ArtifactGenerator + readyCondition := meta.FindStatusCondition(ag.Status.Conditions, "Ready") + if readyCondition == nil { + // No Ready condition in ArtifactGenerator, set status to unknown + meta.SetStatusCondition(&packageSource.Status.Conditions, metav1.Condition{ + Type: "Ready", + Status: metav1.ConditionUnknown, + Reason: "ArtifactGeneratorNotReady", + Message: "ArtifactGenerator Ready condition not found", + }) + return r.Status().Update(ctx, packageSource) + } + + // Copy Ready condition from ArtifactGenerator to PackageSource + meta.SetStatusCondition(&packageSource.Status.Conditions, metav1.Condition{ + Type: "Ready", + Status: readyCondition.Status, + Reason: readyCondition.Reason, + Message: readyCondition.Message, + ObservedGeneration: packageSource.Generation, + LastTransitionTime: readyCondition.LastTransitionTime, + }) + + logger.V(1).Info("updated PackageSource status from ArtifactGenerator", + "packageSource", packageSource.Name, + "status", readyCondition.Status, + "reason", readyCondition.Reason) + + return r.Status().Update(ctx, packageSource) +} + +// SetupWithManager sets up the controller with the Manager. +func (r *PackageSourceReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + Named("cozystack-packagesource"). + For(&cozyv1alpha1.PackageSource{}). + Owns(&sourcewatcherv1beta1.ArtifactGenerator{}). + Complete(r) +} + diff --git a/internal/shared/crdmem/memory.go b/internal/shared/crdmem/memory.go new file mode 100644 index 00000000..f0446627 --- /dev/null +++ b/internal/shared/crdmem/memory.go @@ -0,0 +1,99 @@ +package crdmem + +import ( + "context" + "sync" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type Memory struct { + mu sync.RWMutex + data map[string]cozyv1alpha1.ApplicationDefinition + primed bool + primeOnce sync.Once +} + +func New() *Memory { + return &Memory{data: make(map[string]cozyv1alpha1.ApplicationDefinition)} +} + +var ( + global *Memory + globalOnce sync.Once +) + +func Global() *Memory { + globalOnce.Do(func() { global = New() }) + return global +} + +func (m *Memory) Upsert(obj *cozyv1alpha1.ApplicationDefinition) { + if obj == nil { + return + } + m.mu.Lock() + m.data[obj.Name] = *obj.DeepCopy() + m.mu.Unlock() +} + +func (m *Memory) Delete(name string) { + m.mu.Lock() + delete(m.data, name) + m.mu.Unlock() +} + +func (m *Memory) Snapshot() []cozyv1alpha1.ApplicationDefinition { + m.mu.RLock() + defer m.mu.RUnlock() + out := make([]cozyv1alpha1.ApplicationDefinition, 0, len(m.data)) + for _, v := range m.data { + out = append(out, v) + } + return out +} + +func (m *Memory) IsPrimed() bool { + m.mu.RLock() + defer m.mu.RUnlock() + return m.primed +} + +type runnable func(context.Context) error + +func (r runnable) Start(ctx context.Context) error { return r(ctx) } + +func (m *Memory) EnsurePrimingWithManager(mgr ctrl.Manager) error { + var errOut error + m.primeOnce.Do(func() { + errOut = mgr.Add(runnable(func(ctx context.Context) error { + if ok := mgr.GetCache().WaitForCacheSync(ctx); !ok { + return nil + } + var list cozyv1alpha1.ApplicationDefinitionList + if err := mgr.GetClient().List(ctx, &list); err == nil { + for i := range list.Items { + m.Upsert(&list.Items[i]) + } + m.mu.Lock() + m.primed = true + m.mu.Unlock() + } + return nil + })) + }) + return errOut +} + +func (m *Memory) ListFromCacheOrAPI(ctx context.Context, c client.Client) ([]cozyv1alpha1.ApplicationDefinition, error) { + if m.IsPrimed() { + return m.Snapshot(), nil + } + var list cozyv1alpha1.ApplicationDefinitionList + if err := c.List(ctx, &list); err != nil { + return nil, err + } + return list.Items, nil +} diff --git a/internal/sse/server.go b/internal/sse/server.go new file mode 100644 index 00000000..60d983f5 --- /dev/null +++ b/internal/sse/server.go @@ -0,0 +1,293 @@ +// Package sse provides a tiny Server-Sent Events server with pluggable routes. +// No external deps; safe for quick demos and small dashboards. +package sse + +import ( + "context" + "fmt" + "html/template" + "log" + "net/http" + "strings" + "sync" + "time" +) + +// Options configures the SSE server. +type Options struct { + // Addr is the listening address, e.g. ":8080" or "127.0.0.1:0". + Addr string + + // IndexPath is the path serving a minimal live HTML page ("" to disable). + // e.g. "/" or "/status" + IndexPath string + + // StreamPath is the SSE endpoint path, e.g. "/stream". + StreamPath string + + // Title for the index page (cosmetic). + Title string + + // AllowCORS, if true, sets Access-Control-Allow-Origin: * for /stream. + AllowCORS bool + + // ClientBuf is the per-client buffered message queue size. + // If 0, defaults to 16. When full, new messages are dropped for that client. + ClientBuf int + + // Heartbeat sends a comment line every interval to keep connections alive. + // If 0, defaults to 25s. + Heartbeat time.Duration + + // Logger (optional). If nil, log.Printf is used. + Logger *log.Logger +} + +// Server is a simple SSE broadcaster. +type Server struct { + opts Options + mux *http.ServeMux + http *http.Server + + clientsMu sync.RWMutex + clients map[*client]struct{} + + // latest holds the most recent payload (sent to new clients on connect). + latestMu sync.RWMutex + latest string +} + +type client struct { + ch chan string + closeCh chan struct{} + flusher http.Flusher + w http.ResponseWriter + req *http.Request + logf func(string, ...any) + heartbeat time.Duration +} + +func New(opts Options) *Server { + if opts.ClientBuf <= 0 { + opts.ClientBuf = 16 + } + if opts.Heartbeat <= 0 { + opts.Heartbeat = 25 * time.Second + } + if opts.Addr == "" { + opts.Addr = ":8080" + } + if opts.StreamPath == "" { + opts.StreamPath = "/stream" + } + if opts.IndexPath == "" { + opts.IndexPath = "/" + } + s := &Server{ + opts: opts, + mux: http.NewServeMux(), + clients: make(map[*client]struct{}), + } + s.routes() + s.http = &http.Server{ + Addr: opts.Addr, + Handler: s.mux, + ReadHeaderTimeout: 10 * time.Second, + } + return s +} + +func (s *Server) routes() { + if s.opts.IndexPath != "" { + s.mux.HandleFunc(s.opts.IndexPath, s.handleIndex) + } + s.mux.HandleFunc(s.opts.StreamPath, s.handleStream) +} + +func (s *Server) logf(format string, args ...any) { + if s.opts.Logger != nil { + s.opts.Logger.Printf(format, args...) + } else { + log.Printf(format, args...) + } +} + +// ListenAndServe starts the HTTP server (blocking). +func (s *Server) ListenAndServe() error { + s.logf("sse: listening on http://%s (index=%s, stream=%s)", s.http.Addr, s.opts.IndexPath, s.opts.StreamPath) + return s.http.ListenAndServe() +} + +// Shutdown gracefully stops the server. +func (s *Server) Shutdown(ctx context.Context) error { + s.clientsMu.Lock() + for c := range s.clients { + close(c.closeCh) + } + s.clientsMu.Unlock() + return s.http.Shutdown(ctx) +} + +// Publish broadcasts a new payload to all clients and stores it as latest. +func (s *Server) Publish(payload string) { + // Store latest + s.latestMu.Lock() + s.latest = payload + s.latestMu.Unlock() + + // Broadcast + s.clientsMu.RLock() + defer s.clientsMu.RUnlock() + for c := range s.clients { + select { + case c.ch <- payload: + default: + // Drop if client is slow (buffer full) + if s.opts.Logger != nil { + s.opts.Logger.Printf("sse: dropping message to slow client %p", c) + } + } + } +} + +func (s *Server) handleIndex(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + page := indexTemplate(s.opts.Title, s.opts.StreamPath) + _, _ = w.Write([]byte(page)) +} + +func (s *Server) handleStream(w http.ResponseWriter, r *http.Request) { + // Required SSE headers + if s.opts.AllowCORS { + w.Header().Set("Access-Control-Allow-Origin", "*") + } + w.Header().Set("Content-Type", "text/event-stream") + w.Header().Set("Cache-Control", "no-cache") + w.Header().Set("Connection", "keep-alive") + + flusher, ok := w.(http.Flusher) + if !ok { + http.Error(w, "streaming unsupported", http.StatusInternalServerError) + return + } + + c := &client{ + ch: make(chan string, s.opts.ClientBuf), + closeCh: make(chan struct{}), + flusher: flusher, + w: w, + req: r, + logf: s.logf, + heartbeat: s.opts.Heartbeat, + } + + // Register client + s.clientsMu.Lock() + s.clients[c] = struct{}{} + s.clientsMu.Unlock() + + // Initial comment to open the stream for some proxies + fmt.Fprintf(w, ": connected %s\n\n", time.Now().Format(time.RFC3339)) + flusher.Flush() + + // Send latest if any + s.latestMu.RLock() + latest := s.latest + s.latestMu.RUnlock() + if latest != "" { + writeSSE(w, latest) + flusher.Flush() + } + + // Start pump + go c.pump() + + // Block until client disconnects + <-r.Context().Done() + + // Unregister client + close(c.closeCh) + s.clientsMu.Lock() + delete(s.clients, c) + s.clientsMu.Unlock() +} + +func (c *client) pump() { + t := time.NewTicker(c.heartbeat) + defer t.Stop() + for { + select { + case <-c.closeCh: + return + case msg := <-c.ch: + writeSSE(c.w, msg) + c.flusher.Flush() + case <-t.C: + // heartbeat comment (keeps connections alive through proxies) + fmt.Fprint(c.w, ": hb\n\n") + c.flusher.Flush() + } + } +} + +func writeSSE(w http.ResponseWriter, msg string) { + // Split on lines; each needs its own "data:" field per the SSE spec + lines := strings.Split(strings.TrimRight(msg, "\n"), "\n") + for _, ln := range lines { + fmt.Fprintf(w, "data: %s\n", ln) + } + fmt.Fprint(w, "\n") +} + +// Minimal index page with live updates +func indexTemplate(title, streamPath string) string { + if title == "" { + title = "SSE Stream" + } + if streamPath == "" { + streamPath = "/stream" + } + const tpl = ` + + + +{{.Title}} + + + +

{{.Title}}

+
Connecting…
+

+
+
+`
+	page, _ := template.New("idx").Parse(tpl)
+	var b strings.Builder
+	_ = page.Execute(&b, map[string]any{
+		"Title":  title,
+		"Stream": streamPath,
+	})
+	return b.String()
+}
diff --git a/internal/telemetry/collector.go b/internal/telemetry/collector.go
index 04d05d3a..f4bb8dd8 100644
--- a/internal/telemetry/collector.go
+++ b/internal/telemetry/collector.go
@@ -9,35 +9,34 @@ import (
 	"time"
 
 	corev1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/api/resource"
 	"k8s.io/apimachinery/pkg/types"
-	"k8s.io/client-go/discovery"
 	"k8s.io/client-go/rest"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/log"
 
+	helmv2 "github.com/fluxcd/helm-controller/api/v2"
+
 	cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
 )
 
-// Collector handles telemetry data collection and sending
+const (
+	// ApplicationKindLabel is the label used to identify application kind on HelmReleases
+	ApplicationKindLabel = "apps.cozystack.io/application.kind"
+)
+
+// Collector handles telemetry data collection for cozystack-controller
 type Collector struct {
-	client          client.Client
-	discoveryClient discovery.DiscoveryInterface
-	config          *Config
-	ticker          *time.Ticker
-	stopCh          chan struct{}
+	client client.Client
+	config *Config
+	ticker *time.Ticker
+	stopCh chan struct{}
 }
 
-// NewCollector creates a new telemetry collector
-func NewCollector(client client.Client, config *Config, kubeConfig *rest.Config) (*Collector, error) {
-	discoveryClient, err := discovery.NewDiscoveryClientForConfig(kubeConfig)
-	if err != nil {
-		return nil, fmt.Errorf("failed to create discovery client: %w", err)
-	}
+// NewCollector creates a new telemetry collector for cozystack-controller
+func NewCollector(c client.Client, config *Config, _ *rest.Config) (*Collector, error) {
 	return &Collector{
-		client:          client,
-		discoveryClient: discoveryClient,
-		config:          config,
+		client: c,
+		config: config,
 	}, nil
 }
 
@@ -67,46 +66,9 @@ func (c *Collector) Start(ctx context.Context) error {
 
 // NeedLeaderElection implements manager.LeaderElectionRunnable
 func (c *Collector) NeedLeaderElection() bool {
-	// Only run telemetry collector on the leader
 	return true
 }
 
-// Stop halts telemetry collection
-func (c *Collector) Stop() {
-	close(c.stopCh)
-}
-
-// getSizeGroup returns the exponential size group for PVC
-func getSizeGroup(size resource.Quantity) string {
-	gb := size.Value() / (1024 * 1024 * 1024)
-	switch {
-	case gb <= 1:
-		return "1Gi"
-	case gb <= 5:
-		return "5Gi"
-	case gb <= 10:
-		return "10Gi"
-	case gb <= 25:
-		return "25Gi"
-	case gb <= 50:
-		return "50Gi"
-	case gb <= 100:
-		return "100Gi"
-	case gb <= 250:
-		return "250Gi"
-	case gb <= 500:
-		return "500Gi"
-	case gb <= 1024:
-		return "1Ti"
-	case gb <= 2048:
-		return "2Ti"
-	case gb <= 5120:
-		return "5Ti"
-	default:
-		return "10Ti"
-	}
-}
-
 // collect gathers and sends telemetry data
 func (c *Collector) collect(ctx context.Context) {
 	logger := log.FromContext(ctx).V(1)
@@ -120,151 +82,54 @@ func (c *Collector) collect(ctx context.Context) {
 
 	clusterID := string(kubeSystemNS.UID)
 
-	var cozystackCM corev1.ConfigMap
-	if err := c.client.Get(ctx, types.NamespacedName{Namespace: "cozy-system", Name: "cozystack"}, &cozystackCM); err != nil {
-		logger.Info(fmt.Sprintf("Failed to get cozystack configmap in cozy-system namespace: %v", err))
+	// Get all ApplicationDefinitions to know which kinds exist
+	var appDefList cozyv1alpha1.ApplicationDefinitionList
+	if err := c.client.List(ctx, &appDefList); err != nil {
+		logger.Info(fmt.Sprintf("Failed to list ApplicationDefinitions: %v", err))
 		return
 	}
 
-	oidcEnabled := cozystackCM.Data["oidc-enabled"]
-	bundle := cozystackCM.Data["bundle-name"]
-	bundleEnable := cozystackCM.Data["bundle-enable"]
-	bundleDisable := cozystackCM.Data["bundle-disable"]
+	// Build a map of all known application kinds (initialized with 0)
+	appKindCounts := make(map[string]int)
+	for _, appDef := range appDefList.Items {
+		kind := appDef.Spec.Application.Kind
+		if kind != "" {
+			appKindCounts[kind] = 0
+		}
+	}
 
-	// Get Kubernetes version from nodes
-	var nodeList corev1.NodeList
-	if err := c.client.List(ctx, &nodeList); err != nil {
-		logger.Info(fmt.Sprintf("Failed to list nodes: %v", err))
+	// Get all HelmReleases with apps.cozystack.io/application.kind label in one request
+	var hrList helmv2.HelmReleaseList
+	if err := c.client.List(ctx, &hrList, client.HasLabels{ApplicationKindLabel}); err != nil {
+		logger.Info(fmt.Sprintf("Failed to list HelmReleases: %v", err))
 		return
 	}
 
+	// Count HelmReleases by application kind
+	for _, hr := range hrList.Items {
+		kind := hr.Labels[ApplicationKindLabel]
+		if kind != "" {
+			appKindCounts[kind]++
+		}
+	}
+
 	// Create metrics buffer
 	var metrics strings.Builder
 
-	// Add Cozystack info metric
-	if len(nodeList.Items) > 0 {
-		k8sVersion, _ := c.discoveryClient.ServerVersion()
+	// Write application count metrics
+	for kind, count := range appKindCounts {
 		metrics.WriteString(fmt.Sprintf(
-			"cozy_cluster_info{cozystack_version=\"%s\",kubernetes_version=\"%s\",oidc_enabled=\"%s\",bundle_name=\"%s\",bunde_enable=\"%s\",bunde_disable=\"%s\"} 1\n",
-			c.config.CozystackVersion,
-			k8sVersion,
-			oidcEnabled,
-			bundle,
-			bundleEnable,
-			bundleDisable,
-		))
-	}
-
-	// Collect node metrics
-	nodeOSCount := make(map[string]int)
-	for _, node := range nodeList.Items {
-		key := fmt.Sprintf("%s (%s)", node.Status.NodeInfo.OperatingSystem, node.Status.NodeInfo.OSImage)
-		nodeOSCount[key] = nodeOSCount[key] + 1
-	}
-
-	for osKey, count := range nodeOSCount {
-		metrics.WriteString(fmt.Sprintf(
-			"cozy_nodes_count{os=\"%s\",kernel=\"%s\"} %d\n",
-			osKey,
-			nodeList.Items[0].Status.NodeInfo.KernelVersion,
+			"cozy_application_count{kind=\"%s\"} %d\n",
+			kind,
 			count,
 		))
 	}
 
-	// Collect LoadBalancer services metrics
-	var serviceList corev1.ServiceList
-	if err := c.client.List(ctx, &serviceList); err != nil {
-		logger.Info(fmt.Sprintf("Failed to list Services: %v", err))
-	} else {
-		lbCount := 0
-		for _, svc := range serviceList.Items {
-			if svc.Spec.Type == corev1.ServiceTypeLoadBalancer {
-				lbCount++
-			}
+	// Send metrics only if there's something to send
+	if metrics.Len() > 0 {
+		if err := c.sendMetrics(clusterID, metrics.String()); err != nil {
+			logger.Info(fmt.Sprintf("Failed to send metrics: %v", err))
 		}
-		metrics.WriteString(fmt.Sprintf("cozy_loadbalancers_count %d\n", lbCount))
-	}
-
-	// Count tenant namespaces
-	var nsList corev1.NamespaceList
-	if err := c.client.List(ctx, &nsList); err != nil {
-		logger.Info(fmt.Sprintf("Failed to list Namespaces: %v", err))
-	} else {
-		tenantCount := 0
-		for _, ns := range nsList.Items {
-			if strings.HasPrefix(ns.Name, "tenant-") {
-				tenantCount++
-			}
-		}
-		metrics.WriteString(fmt.Sprintf("cozy_tenants_count %d\n", tenantCount))
-	}
-
-	// Collect PV metrics grouped by driver and size
-	var pvList corev1.PersistentVolumeList
-	if err := c.client.List(ctx, &pvList); err != nil {
-		logger.Info(fmt.Sprintf("Failed to list PVs: %v", err))
-	} else {
-		// Map to store counts by size and driver
-		pvMetrics := make(map[string]map[string]int)
-
-		for _, pv := range pvList.Items {
-			if capacity, ok := pv.Spec.Capacity[corev1.ResourceStorage]; ok {
-				sizeGroup := getSizeGroup(capacity)
-
-				// Get the CSI driver name
-				driver := "unknown"
-				if pv.Spec.CSI != nil {
-					driver = pv.Spec.CSI.Driver
-				} else if pv.Spec.HostPath != nil {
-					driver = "hostpath"
-				} else if pv.Spec.NFS != nil {
-					driver = "nfs"
-				}
-
-				// Initialize nested map if needed
-				if _, exists := pvMetrics[sizeGroup]; !exists {
-					pvMetrics[sizeGroup] = make(map[string]int)
-				}
-
-				// Increment count for this size/driver combination
-				pvMetrics[sizeGroup][driver]++
-			}
-		}
-
-		// Write metrics
-		for size, drivers := range pvMetrics {
-			for driver, count := range drivers {
-				metrics.WriteString(fmt.Sprintf(
-					"cozy_pvs_count{driver=\"%s\",size=\"%s\"} %d\n",
-					driver,
-					size,
-					count,
-				))
-			}
-		}
-	}
-
-	// Collect workload metrics
-	var monitorList cozyv1alpha1.WorkloadMonitorList
-	if err := c.client.List(ctx, &monitorList); err != nil {
-		logger.Info(fmt.Sprintf("Failed to list WorkloadMonitors: %v", err))
-		return
-	}
-
-	for _, monitor := range monitorList.Items {
-		metrics.WriteString(fmt.Sprintf(
-			"cozy_workloads_count{uid=\"%s\",kind=\"%s\",type=\"%s\",version=\"%s\"} %d\n",
-			monitor.UID,
-			monitor.Spec.Kind,
-			monitor.Spec.Type,
-			monitor.Spec.Version,
-			monitor.Status.ObservedReplicas,
-		))
-	}
-
-	// Send metrics
-	if err := c.sendMetrics(clusterID, metrics.String()); err != nil {
-		logger.Info(fmt.Sprintf("Failed to send metrics: %v", err))
 	}
 }
 
diff --git a/internal/telemetry/config.go b/internal/telemetry/config.go
index b4c9b4d1..d2d3dcc0 100644
--- a/internal/telemetry/config.go
+++ b/internal/telemetry/config.go
@@ -12,16 +12,13 @@ type Config struct {
 	Endpoint string
 	// Interval between telemetry data collection
 	Interval time.Duration
-	// CozystackVersion represents the current version of Cozystack
-	CozystackVersion string
 }
 
 // DefaultConfig returns default telemetry configuration
 func DefaultConfig() *Config {
 	return &Config{
-		Disabled:         false,
-		Endpoint:         "https://telemetry.cozystack.io",
-		Interval:         15 * time.Minute,
-		CozystackVersion: "unknown",
+		Disabled: false,
+		Endpoint: "https://telemetry.cozystack.io",
+		Interval: 15 * time.Minute,
 	}
 }
diff --git a/internal/telemetry/operator_collector.go b/internal/telemetry/operator_collector.go
new file mode 100644
index 00000000..8b4ec302
--- /dev/null
+++ b/internal/telemetry/operator_collector.go
@@ -0,0 +1,282 @@
+package telemetry
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"net/http"
+	"strings"
+	"time"
+
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/api/resource"
+	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/client-go/discovery"
+	"k8s.io/client-go/rest"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/log"
+
+	cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1"
+	"github.com/cozystack/cozystack/pkg/version"
+)
+
+// OperatorCollector handles telemetry data collection for cozystack-operator
+type OperatorCollector struct {
+	reader          client.Reader
+	discoveryClient discovery.DiscoveryInterface
+	config          *Config
+	ticker          *time.Ticker
+	stopCh          chan struct{}
+}
+
+// NewOperatorCollector creates a new telemetry collector for cozystack-operator
+func NewOperatorCollector(r client.Reader, config *Config, kubeConfig *rest.Config) (*OperatorCollector, error) {
+	discoveryClient, err := discovery.NewDiscoveryClientForConfig(kubeConfig)
+	if err != nil {
+		return nil, fmt.Errorf("failed to create discovery client: %w", err)
+	}
+	return &OperatorCollector{
+		reader:          r,
+		discoveryClient: discoveryClient,
+		config:          config,
+	}, nil
+}
+
+// Start implements manager.Runnable
+func (c *OperatorCollector) Start(ctx context.Context) error {
+	if c.config.Disabled {
+		return nil
+	}
+
+	c.ticker = time.NewTicker(c.config.Interval)
+	c.stopCh = make(chan struct{})
+
+	// Initial collection
+	c.collect(ctx)
+
+	for {
+		select {
+		case <-ctx.Done():
+			c.ticker.Stop()
+			close(c.stopCh)
+			return nil
+		case <-c.ticker.C:
+			c.collect(ctx)
+		}
+	}
+}
+
+// NeedLeaderElection implements manager.LeaderElectionRunnable
+func (c *OperatorCollector) NeedLeaderElection() bool {
+	return true
+}
+
+// getSizeGroup returns the exponential size group for PVC
+func getSizeGroup(size resource.Quantity) string {
+	gb := size.Value() / (1024 * 1024 * 1024)
+	switch {
+	case gb <= 1:
+		return "1Gi"
+	case gb <= 5:
+		return "5Gi"
+	case gb <= 10:
+		return "10Gi"
+	case gb <= 25:
+		return "25Gi"
+	case gb <= 50:
+		return "50Gi"
+	case gb <= 100:
+		return "100Gi"
+	case gb <= 250:
+		return "250Gi"
+	case gb <= 500:
+		return "500Gi"
+	case gb <= 1024:
+		return "1Ti"
+	case gb <= 2048:
+		return "2Ti"
+	case gb <= 5120:
+		return "5Ti"
+	default:
+		return "10Ti"
+	}
+}
+
+// collect gathers and sends telemetry data
+func (c *OperatorCollector) collect(ctx context.Context) {
+	logger := log.FromContext(ctx).V(1)
+
+	// Get cluster ID from kube-system namespace
+	var kubeSystemNS corev1.Namespace
+	if err := c.reader.Get(ctx, types.NamespacedName{Name: "kube-system"}, &kubeSystemNS); err != nil {
+		logger.Info(fmt.Sprintf("Failed to get kube-system namespace: %v", err))
+		return
+	}
+
+	clusterID := string(kubeSystemNS.UID)
+
+	// Get Kubernetes version
+	k8sVersion, err := c.discoveryClient.ServerVersion()
+	if err != nil {
+		logger.Info(fmt.Sprintf("Failed to get Kubernetes version: %v", err))
+		return
+	}
+
+	// Get nodes
+	var nodeList corev1.NodeList
+	if err := c.reader.List(ctx, &nodeList); err != nil {
+		logger.Info(fmt.Sprintf("Failed to list nodes: %v", err))
+		return
+	}
+
+	// Create metrics buffer
+	var metrics strings.Builder
+
+	// Add cluster info metric
+	metrics.WriteString(fmt.Sprintf(
+		"cozy_cluster_info{cozystack_version=\"%s\",kubernetes_version=\"%s\"} 1\n",
+		version.Version,
+		k8sVersion.GitVersion,
+	))
+
+	// Collect node metrics grouped by OS and kernel
+	nodeOSCount := make(map[string]map[string]int) // os -> kernel -> count
+	for _, node := range nodeList.Items {
+		osKey := fmt.Sprintf("%s (%s)", node.Status.NodeInfo.OperatingSystem, node.Status.NodeInfo.OSImage)
+		kernelKey := node.Status.NodeInfo.KernelVersion
+
+		if _, exists := nodeOSCount[osKey]; !exists {
+			nodeOSCount[osKey] = make(map[string]int)
+		}
+		nodeOSCount[osKey][kernelKey]++
+	}
+
+	for osKey, kernels := range nodeOSCount {
+		for kernel, count := range kernels {
+			metrics.WriteString(fmt.Sprintf(
+				"cozy_nodes_count{os=\"%s\",kernel=\"%s\"} %d\n",
+				osKey,
+				kernel,
+				count,
+			))
+		}
+	}
+
+	// Collect cluster capacity metrics (cpu, memory, gpu)
+	capacityTotals := make(map[string]int64)
+	for _, node := range nodeList.Items {
+		for resourceName, quantity := range node.Status.Capacity {
+			name := string(resourceName)
+			if name == "cpu" || name == "memory" || strings.HasPrefix(name, "nvidia.com/") {
+				capacityTotals[name] += quantity.Value()
+			}
+		}
+	}
+
+	for resourceName, total := range capacityTotals {
+		metrics.WriteString(fmt.Sprintf(
+			"cozy_cluster_capacity{resource=\"%s\"} %d\n",
+			resourceName,
+			total,
+		))
+	}
+
+	// Collect LoadBalancer services metrics
+	var serviceList corev1.ServiceList
+	if err := c.reader.List(ctx, &serviceList); err != nil {
+		logger.Info(fmt.Sprintf("Failed to list Services: %v", err))
+	} else {
+		lbCount := 0
+		for _, svc := range serviceList.Items {
+			if svc.Spec.Type == corev1.ServiceTypeLoadBalancer {
+				lbCount++
+			}
+		}
+		metrics.WriteString(fmt.Sprintf("cozy_loadbalancers_count %d\n", lbCount))
+	}
+
+	// Collect PV metrics grouped by driver and size
+	var pvList corev1.PersistentVolumeList
+	if err := c.reader.List(ctx, &pvList); err != nil {
+		logger.Info(fmt.Sprintf("Failed to list PVs: %v", err))
+	} else {
+		pvMetrics := make(map[string]map[string]int) // size -> driver -> count
+
+		for _, pv := range pvList.Items {
+			if capacity, ok := pv.Spec.Capacity[corev1.ResourceStorage]; ok {
+				sizeGroup := getSizeGroup(capacity)
+
+				driver := "unknown"
+				if pv.Spec.CSI != nil {
+					driver = pv.Spec.CSI.Driver
+				} else if pv.Spec.HostPath != nil {
+					driver = "hostpath"
+				} else if pv.Spec.NFS != nil {
+					driver = "nfs"
+				}
+
+				if _, exists := pvMetrics[sizeGroup]; !exists {
+					pvMetrics[sizeGroup] = make(map[string]int)
+				}
+				pvMetrics[sizeGroup][driver]++
+			}
+		}
+
+		for size, drivers := range pvMetrics {
+			for driver, count := range drivers {
+				metrics.WriteString(fmt.Sprintf(
+					"cozy_pvs_count{driver=\"%s\",size=\"%s\"} %d\n",
+					driver,
+					size,
+					count,
+				))
+			}
+		}
+	}
+
+	// Collect installed packages
+	var packageList cozyv1alpha1.PackageList
+	if err := c.reader.List(ctx, &packageList); err != nil {
+		logger.Info(fmt.Sprintf("Failed to list Packages: %v", err))
+	} else {
+		for _, pkg := range packageList.Items {
+			variant := pkg.Spec.Variant
+			if variant == "" {
+				variant = "default"
+			}
+			metrics.WriteString(fmt.Sprintf(
+				"cozy_package_info{name=\"%s\",variant=\"%s\"} 1\n",
+				pkg.Name,
+				variant,
+			))
+		}
+	}
+
+	// Send metrics
+	if err := c.sendMetrics(clusterID, metrics.String()); err != nil {
+		logger.Info(fmt.Sprintf("Failed to send metrics: %v", err))
+	}
+}
+
+// sendMetrics sends collected metrics to the configured endpoint
+func (c *OperatorCollector) sendMetrics(clusterID, metrics string) error {
+	req, err := http.NewRequest("POST", c.config.Endpoint, bytes.NewBufferString(metrics))
+	if err != nil {
+		return fmt.Errorf("failed to create request: %w", err)
+	}
+
+	req.Header.Set("Content-Type", "text/plain")
+	req.Header.Set("X-Cluster-ID", clusterID)
+
+	resp, err := http.DefaultClient.Do(req)
+	if err != nil {
+		return fmt.Errorf("failed to send request: %w", err)
+	}
+	defer resp.Body.Close()
+
+	if resp.StatusCode != http.StatusOK {
+		return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
+	}
+
+	return nil
+}
diff --git a/internal/template/template.go b/internal/template/template.go
new file mode 100644
index 00000000..c206bb3d
--- /dev/null
+++ b/internal/template/template.go
@@ -0,0 +1,68 @@
+package template
+
+import (
+	"bytes"
+	"encoding/json"
+	tmpl "text/template"
+)
+
+func Template[T any](obj *T, templateContext map[string]any) (*T, error) {
+	b, err := json.Marshal(obj)
+	if err != nil {
+		return nil, err
+	}
+	var unstructured any
+	err = json.Unmarshal(b, &unstructured)
+	if err != nil {
+		return nil, err
+	}
+	templateFunc := func(in string) string {
+		out, err := template(in, templateContext)
+		if err != nil {
+			return in
+		}
+		return out
+	}
+	unstructured = mapAtStrings(unstructured, templateFunc)
+	b, err = json.Marshal(unstructured)
+	if err != nil {
+		return nil, err
+	}
+	var out T
+	err = json.Unmarshal(b, &out)
+	if err != nil {
+		return nil, err
+	}
+	return &out, nil
+}
+
+func mapAtStrings(v any, f func(string) string) any {
+	switch x := v.(type) {
+	case map[string]any:
+		for k, val := range x {
+			x[k] = mapAtStrings(val, f)
+		}
+		return x
+	case []any:
+		for i, val := range x {
+			x[i] = mapAtStrings(val, f)
+		}
+		return x
+	case string:
+		return f(x)
+	default:
+		return v
+	}
+}
+
+func template(in string, templateContext map[string]any) (string, error) {
+	tpl, err := tmpl.New("this").Parse(in)
+	if err != nil {
+		return "", err
+	}
+	var buf bytes.Buffer
+	if err := tpl.Execute(&buf, templateContext); err != nil {
+		return "", err
+	}
+	return buf.String(), nil
+}
diff --git a/internal/template/template_test.go b/internal/template/template_test.go
new file mode 100644
index 00000000..94ea2210
--- /dev/null
+++ b/internal/template/template_test.go
@@ -0,0 +1,68 @@
+package template
+
+import (
+	"encoding/json"
+	"testing"
+
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func TestTemplate_PodTemplateSpec(t *testing.T) {
+	original := corev1.PodTemplateSpec{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "my-pod",
+			Labels: map[string]string{
+				"app": "demo",
+			},
+			Annotations: map[string]string{
+				"note": "hello",
+			},
+		},
+		Spec: corev1.PodSpec{
+			Containers: []corev1.Container{
+				{
+					Name:  "{{ .Release.Name }}",
+					Image: "nginx:1.21",
+					Args:  []string{"--flag={{ .Values.value }}"},
+					Env: []corev1.EnvVar{
+						{
+							Name:  "FOO",
+							Value: "{{ .Release.Namespace }}",
+						},
+					},
+				},
+			},
+		},
+	}
+	templateContext := map[string]any{
+		"Release": map[string]any{
+			"Name":      "foo",
+			"Namespace": "notdefault",
+		},
+		"Values": map[string]any{
+			"value": 3,
+		},
+	}
+	reference := *original.DeepCopy()
+	reference.Spec.Containers[0].Name = "foo"
+	reference.Spec.Containers[0].Args[0] = "--flag=3"
+	reference.Spec.Containers[0].Env[0].Value = "notdefault"
+	got, err := Template(&original, templateContext)
+	if err != nil {
+		t.Fatalf("Template returned error: %v", err)
+	}
+	b1, err := json.Marshal(reference)
+	t.Logf("reference:\n%s", string(b1))
+	if err != nil {
+		t.Fatalf("failed to marshal reference value: %v", err)
+	}
+	b2, err := json.Marshal(got)
+	t.Logf("got:\n%s", string(b2))
+	if err != nil {
+		t.Fatalf("failed to marshal transformed value: %v", err)
+	}
+	if string(b1) != string(b2) {
+		t.Fatalf("transformed value not equal to reference value, expected: %s, got: %s", string(b1), string(b2))
+	}
+}
diff --git a/packages/apps/Makefile b/packages/apps/Makefile
index 8751a048..50502f2b 100644
--- a/packages/apps/Makefile
+++ b/packages/apps/Makefile
@@ -1,14 +1,12 @@
-OUT=../_out/repos/apps
-TMP := $(shell mktemp -d)
+OUT=../../_out/repos/apps
+CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}')
+
+include ../../hack/common-envs.mk
 
 repo:
-	cd .. && ../hack/package_chart.sh apps $(OUT) $(TMP) library
+	rm -rf "$(OUT)"
+	helm package -d "$(OUT)" $(CHARTS) --version $(COZYSTACK_VERSION)
+	helm repo index "$(OUT)"
 
-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
-
-gen-versions-map: fix-chartnames
-	../../hack/gen_versions_map.sh
-
-check-version-map: gen-versions-map
-	git diff --exit-code -- versions_map
+fix-charts:
+	find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}' | while read i; do sed -i -e "s/^name: .*/name: $$i/" -e "s/^version: .*/version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process/g" "$$i/Chart.yaml"; done
diff --git a/packages/apps/README.md b/packages/apps/README.md
index b2cb30cf..8ee4c3ed 100644
--- a/packages/apps/README.md
+++ b/packages/apps/README.md
@@ -4,6 +4,5 @@
 cd packages/core/installer
 make image-cozystack REGISTRY=YOUR_CUSTOM_REGISTRY
 make apply
-kubectl delete pod dashboard-redis-master-0 -n cozy-dashboard
 kubectl delete po -l app=source-controller -n cozy-fluxcd
 ```
diff --git a/packages/apps/bucket/Chart.yaml b/packages/apps/bucket/Chart.yaml
index c0c0c0d0..f1c03d81 100644
--- a/packages/apps/bucket/Chart.yaml
+++ b/packages/apps/bucket/Chart.yaml
@@ -2,24 +2,6 @@ apiVersion: v2
 name: bucket
 description: S3 compatible storage
 icon: /logos/bucket.svg
-
-# 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: 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.2.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.
+version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process
 appVersion: "0.2.0"
diff --git a/packages/apps/bucket/Makefile b/packages/apps/bucket/Makefile
index 264adfcf..1e35bd53 100644
--- a/packages/apps/bucket/Makefile
+++ b/packages/apps/bucket/Makefile
@@ -1,4 +1,5 @@
-include ../../../scripts/package.mk
+include ../../../hack/package.mk
 
 generate:
-	readme-generator -v values.yaml -s values.schema.json -r README.md
+	cozyvalues-gen -m 'bucket' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/bucket/types.go
+	../../../hack/update-crd.sh
diff --git a/packages/apps/bucket/README.md b/packages/apps/bucket/README.md
index 89749b1d..982225ce 100644
--- a/packages/apps/bucket/README.md
+++ b/packages/apps/bucket/README.md
@@ -1,3 +1,13 @@
 # S3 bucket
 
 ## Parameters
+
+### Parameters
+
+| Name                   | Description                                                                | Type                | Value   |
+| ---------------------- | -------------------------------------------------------------------------- | ------------------- | ------- |
+| `locking`              | Provisions bucket from the `-lock` BucketClass (with object lock enabled). | `bool`              | `false` |
+| `storagePool`          | Selects a specific BucketClass by storage pool name.                       | `string`            | `""`    |
+| `users`                | Users configuration map.                                                   | `map[string]object` | `{}`    |
+| `users[name].readonly` | Whether the user has read-only access.                                     | `bool`              | `false` |
+
diff --git a/packages/apps/bucket/templates/bucketclaim.yaml b/packages/apps/bucket/templates/bucketclaim.yaml
index cebf95b4..0639916f 100644
--- a/packages/apps/bucket/templates/bucketclaim.yaml
+++ b/packages/apps/bucket/templates/bucketclaim.yaml
@@ -1,20 +1,24 @@
-{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }}
-{{- $seaweedfs := index $myNS.metadata.annotations "namespace.cozystack.io/seaweedfs" }}
+{{- $seaweedfs := .Values._namespace.seaweedfs }}
+{{- $pool := .Values.storagePool }}
 apiVersion: objectstorage.k8s.io/v1alpha1
 kind: BucketClaim
 metadata:
   name: {{ .Release.Name }}
+  labels:
+    app.kubernetes.io/instance: {{ .Release.Name }}
 spec:
-  bucketClassName: {{ $seaweedfs }}
+  bucketClassName: {{ $seaweedfs }}{{- if $pool }}-{{ $pool }}{{- end }}{{- if .Values.locking }}-lock{{- end }}
   protocols:
     - s3
+{{- range $name, $user := .Values.users }}
 ---
 apiVersion: objectstorage.k8s.io/v1alpha1
 kind: BucketAccess
 metadata:
-  name: {{ .Release.Name }}
+  name: {{ $.Release.Name }}-{{ $name }}
 spec:
-  bucketAccessClassName: {{ $seaweedfs }}
-  bucketClaimName: {{ .Release.Name }}
-  credentialsSecretName: {{ .Release.Name }}
+  bucketAccessClassName: {{ $seaweedfs }}{{- if $pool }}-{{ $pool }}{{- end }}{{- if $user.readonly }}-readonly{{- end }}
+  bucketClaimName: {{ $.Release.Name }}
+  credentialsSecretName: {{ $.Release.Name }}-{{ $name }}
   protocol: s3
+{{- end }}
diff --git a/packages/apps/bucket/templates/dashboard-resourcemap.yaml b/packages/apps/bucket/templates/dashboard-resourcemap.yaml
index 5edc8b7a..82a51e16 100644
--- a/packages/apps/bucket/templates/dashboard-resourcemap.yaml
+++ b/packages/apps/bucket/templates/dashboard-resourcemap.yaml
@@ -8,8 +8,9 @@ rules:
   resources:
   - secrets
   resourceNames:
-  - {{ .Release.Name }}
-  - {{ .Release.Name }}-credentials
+  {{- range $name, $user := .Values.users }}
+  - {{ $.Release.Name }}-{{ $name }}-credentials
+  {{- end }}
   verbs: ["get", "list", "watch"]
 - apiGroups:
   - networking.k8s.io
diff --git a/packages/apps/bucket/templates/helmrelease.yaml b/packages/apps/bucket/templates/helmrelease.yaml
index d51e3b36..d3290512 100644
--- a/packages/apps/bucket/templates/helmrelease.yaml
+++ b/packages/apps/bucket/templates/helmrelease.yaml
@@ -2,17 +2,25 @@ apiVersion: helm.toolkit.fluxcd.io/v2
 kind: HelmRelease
 metadata:
   name: {{ .Release.Name }}-system
+  labels:
+    sharding.fluxcd.io/key: tenants
 spec:
-  chart:
-    spec:
-      chart: cozy-bucket
-      reconcileStrategy: Revision
-      sourceRef:
-        kind: HelmRepository
-        name: cozystack-system
-        namespace: cozy-system
-      version: '>= 0.0.0-0'
-  interval: 1m0s
-  timeout: 5m0s
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-bucket-application-default-bucket-system
+    namespace: cozy-system
+  interval: 5m
+  timeout: 10m
+  install:
+    remediation:
+      retries: -1
+  upgrade:
+    force: true
+    remediation:
+      retries: -1
+  valuesFrom:
+  - kind: Secret
+    name: cozystack-values
   values:
     bucketName: {{ .Release.Name }}
+    users: {{ .Values.users | toJson }}
diff --git a/packages/apps/mysql/templates/workloadmonitor.yaml b/packages/apps/bucket/templates/workloadmonitor.yaml
similarity index 71%
rename from packages/apps/mysql/templates/workloadmonitor.yaml
rename to packages/apps/bucket/templates/workloadmonitor.yaml
index 9fc6d144..a23f3147 100644
--- a/packages/apps/mysql/templates/workloadmonitor.yaml
+++ b/packages/apps/bucket/templates/workloadmonitor.yaml
@@ -4,10 +4,10 @@ kind: WorkloadMonitor
 metadata:
   name: {{ $.Release.Name }}
 spec:
-  replicas: {{ .Values.replicas }}
-  minReplicas: 1
-  kind: mysql
-  type: mysql
+  replicas: 0
+  minReplicas: 0
+  kind: bucket
+  type: s3
   selector:
     app.kubernetes.io/instance: {{ $.Release.Name }}
   version: {{ $.Chart.Version }}
diff --git a/packages/apps/bucket/values.schema.json b/packages/apps/bucket/values.schema.json
index decc79aa..d302842c 100644
--- a/packages/apps/bucket/values.schema.json
+++ b/packages/apps/bucket/values.schema.json
@@ -1,5 +1,30 @@
 {
-    "title": "Chart Values",
-    "type": "object",
-    "properties": {}
-}
\ No newline at end of file
+  "title": "Chart Values",
+  "type": "object",
+  "properties": {
+    "locking": {
+      "description": "Provisions bucket from the `-lock` BucketClass (with object lock enabled).",
+      "type": "boolean",
+      "default": false
+    },
+    "storagePool": {
+      "description": "Selects a specific BucketClass by storage pool name.",
+      "type": "string",
+      "default": ""
+    },
+    "users": {
+      "description": "Users configuration map.",
+      "type": "object",
+      "default": {},
+      "additionalProperties": {
+        "type": "object",
+        "properties": {
+          "readonly": {
+            "description": "Whether the user has read-only access.",
+            "type": "boolean"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/packages/apps/bucket/values.yaml b/packages/apps/bucket/values.yaml
index 0967ef42..df284df7 100644
--- a/packages/apps/bucket/values.yaml
+++ b/packages/apps/bucket/values.yaml
@@ -1 +1,11 @@
-{}
+## @param {bool} locking=false - Provisions bucket from the `-lock` BucketClass (with object lock enabled).
+locking: false
+
+## @param {string} [storagePool] - Selects a specific BucketClass by storage pool name.
+storagePool: ""
+
+## @typedef {struct} User - Bucket user configuration.
+## @field {bool} [readonly] - Whether the user has read-only access.
+
+## @param {map[string]User} users - Users configuration map.
+users: {}
diff --git a/packages/apps/clickhouse/Chart.yaml b/packages/apps/clickhouse/Chart.yaml
index 9692c075..0ff41400 100644
--- a/packages/apps/clickhouse/Chart.yaml
+++ b/packages/apps/clickhouse/Chart.yaml
@@ -2,24 +2,6 @@ apiVersion: v2
 name: clickhouse
 description: Managed ClickHouse service
 icon: /logos/clickhouse.svg
-
-# 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: 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.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
-# follow Semantic Versioning. They should reflect the version the application is using.
-# It is recommended to use it with quotes.
+version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process
 appVersion: "24.9.2"
diff --git a/packages/apps/clickhouse/Makefile b/packages/apps/clickhouse/Makefile
index 8ee89141..2d671d1d 100644
--- a/packages/apps/clickhouse/Makefile
+++ b/packages/apps/clickhouse/Makefile
@@ -1,24 +1,19 @@
 CLICKHOUSE_BACKUP_TAG = $(shell awk '$$0 ~ /^version:/ {print $$2}' Chart.yaml)
 
-include ../../../scripts/common-envs.mk
-include ../../../scripts/package.mk
+include ../../../hack/common-envs.mk
+include ../../../hack/package.mk
 
 generate:
-	readme-generator -v values.yaml -s values.schema.json -r README.md
-	yq -i -o json --indent 4 '.properties.resourcesPreset.enum = ["none", "nano", "micro", "small", "medium", "large", "xlarge", "2xlarge"]' values.schema.json
+	cozyvalues-gen -m 'clickhouse' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/clickhouse/types.go
+	../../../hack/update-crd.sh
 
 image:
 	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 \
 		--metadata-file images/clickhouse-backup.json \
-		--push=$(PUSH) \
-		--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \
-		--load=$(LOAD)
+		$(BUILDX_ARGS)
 	echo "$(REGISTRY)/clickhouse-backup:$(call settag,$(CLICKHOUSE_BACKUP_TAG))@$$(yq e '."containerimage.digest"' images/clickhouse-backup.json -o json -r)" \
 		> images/clickhouse-backup.tag
 	rm -f images/clickhouse-backup.json
diff --git a/packages/apps/clickhouse/README.md b/packages/apps/clickhouse/README.md
index c4ab62ba..3b7d4b6e 100644
--- a/packages/apps/clickhouse/README.md
+++ b/packages/apps/clickhouse/README.md
@@ -23,35 +23,54 @@ For more details, read [Restic: Effective Backup from Stdin](https://blog.aenix.
 
 ### Common parameters
 
-| Name             | Description                                              | Value  |
-| ---------------- | -------------------------------------------------------- | ------ |
-| `size`           | Size of Persistent Volume for data                       | `10Gi` |
-| `logStorageSize` | Size of Persistent Volume for logs                       | `2Gi`  |
-| `shards`         | Number of Clickhouse shards                              | `1`    |
-| `replicas`       | Number of Clickhouse replicas                            | `2`    |
-| `storageClass`   | StorageClass used to store the data                      | `""`   |
-| `logTTL`         | TTL (expiration time) for query_log and query_thread_log | `15`   |
+| Name               | Description                                                                                                                          | Type       | Value   |
+| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | ---------- | ------- |
+| `replicas`         | Number of ClickHouse replicas.                                                                                                       | `int`      | `2`     |
+| `shards`           | Number of ClickHouse shards.                                                                                                         | `int`      | `1`     |
+| `resources`        | Explicit CPU and memory configuration for each ClickHouse replica. When omitted, the preset defined in `resourcesPreset` is applied. | `object`   | `{}`    |
+| `resources.cpu`    | CPU available to each replica.                                                                                                       | `quantity` | `""`    |
+| `resources.memory` | Memory (RAM) available to each replica.                                                                                              | `quantity` | `""`    |
+| `resourcesPreset`  | Default sizing preset used when `resources` is omitted.                                                                              | `string`   | `small` |
+| `size`             | Persistent Volume Claim size available for application data.                                                                         | `quantity` | `10Gi`  |
+| `storageClass`     | StorageClass used to store the data.                                                                                                 | `string`   | `""`    |
 
-### Configuration parameters
 
-| Name    | Description         | Value |
-| ------- | ------------------- | ----- |
-| `users` | Users configuration | `{}`  |
+### Application-specific parameters
+
+| Name                   | Description                                                   | Type                | Value   |
+| ---------------------- | ------------------------------------------------------------- | ------------------- | ------- |
+| `logStorageSize`       | Size of Persistent Volume for logs.                           | `quantity`          | `2Gi`   |
+| `logTTL`               | TTL (expiration time) for `query_log` and `query_thread_log`. | `int`               | `15`    |
+| `users`                | Users configuration map.                                      | `map[string]object` | `{}`    |
+| `users[name].password` | Password for the user.                                        | `string`            | `""`    |
+| `users[name].readonly` | User is readonly (default: false).                            | `bool`              | `false` |
+
 
 ### Backup parameters
 
-| Name                     | Description                                                                                                                             | Value                                                  |
-| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
-| `backup.enabled`         | Enable periodic backups                                                                                                                 | `false`                                                |
-| `backup.s3Region`        | AWS S3 region where backups are stored                                                                                                  | `us-east-1`                                            |
-| `backup.s3Bucket`        | S3 bucket used for storing backups                                                                                                      | `s3.example.org/clickhouse-backups`                    |
-| `backup.schedule`        | Cron schedule for automated backups                                                                                                     | `0 2 * * *`                                            |
-| `backup.cleanupStrategy` | Retention strategy for cleaning up old backups                                                                                          | `--keep-last=3 --keep-daily=3 --keep-within-weekly=1m` |
-| `backup.s3AccessKey`     | Access key for S3, used for authentication                                                                                              | `oobaiRus9pah8PhohL1ThaeTa4UVa7gu`                     |
-| `backup.s3SecretKey`     | Secret key for S3, used for authentication                                                                                              | `ju3eum4dekeich9ahM1te8waeGai0oog`                     |
-| `backup.resticPassword`  | Password for Restic backup encryption                                                                                                   | `ChaXoveekoh6eigh4siesheeda2quai0`                     |
-| `resources`              | Explicit CPU and memory configuration for each ClickHouse replica. When left empty, the preset defined in `resourcesPreset` is applied. | `{}`                                                   |
-| `resourcesPreset`        | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.       | `small`                                                |
+| Name                     | Description                                     | Type     | Value                                                  |
+| ------------------------ | ----------------------------------------------- | -------- | ------------------------------------------------------ |
+| `backup`                 | Backup configuration.                           | `object` | `{}`                                                   |
+| `backup.enabled`         | Enable regular backups (default: false).        | `bool`   | `false`                                                |
+| `backup.s3Region`        | AWS S3 region where backups are stored.         | `string` | `us-east-1`                                            |
+| `backup.s3Bucket`        | S3 bucket used for storing backups.             | `string` | `s3.example.org/clickhouse-backups`                    |
+| `backup.schedule`        | Cron schedule for automated backups.            | `string` | `0 2 * * *`                                            |
+| `backup.cleanupStrategy` | Retention strategy for cleaning up old backups. | `string` | `--keep-last=3 --keep-daily=3 --keep-within-weekly=1m` |
+| `backup.s3AccessKey`     | Access key for S3 authentication.               | `string` | ``                                    |
+| `backup.s3SecretKey`     | Secret key for S3 authentication.               | `string` | ``                                    |
+| `backup.resticPassword`  | Password for Restic backup encryption.          | `string` | ``                                           |
+
+
+### ClickHouse Keeper parameters
+
+| Name                               | Description                                                  | Type       | Value   |
+| ---------------------------------- | ------------------------------------------------------------ | ---------- | ------- |
+| `clickhouseKeeper`                 | ClickHouse Keeper configuration.                             | `object`   | `{}`    |
+| `clickhouseKeeper.enabled`         | Deploy ClickHouse Keeper for cluster coordination.           | `bool`     | `true`  |
+| `clickhouseKeeper.size`            | Persistent Volume Claim size available for application data. | `quantity` | `1Gi`   |
+| `clickhouseKeeper.resourcesPreset` | Default sizing preset.                                       | `string`   | `micro` |
+| `clickhouseKeeper.replicas`        | Number of Keeper replicas.                                   | `int`      | `3`     |
+
 
 ## Parameter examples and reference
 
diff --git a/packages/apps/clickhouse/images/clickhouse-backup.tag b/packages/apps/clickhouse/images/clickhouse-backup.tag
index 1cb4644f..1633ce80 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.11.0@sha256:3faf7a4cebf390b9053763107482de175aa0fdb88c1e77424fd81100b1c3a205
+ghcr.io/cozystack/cozystack/clickhouse-backup:0.0.0@sha256:3faf7a4cebf390b9053763107482de175aa0fdb88c1e77424fd81100b1c3a205
diff --git a/packages/apps/clickhouse/templates/chkeeper.yaml b/packages/apps/clickhouse/templates/chkeeper.yaml
new file mode 100644
index 00000000..42d88af4
--- /dev/null
+++ b/packages/apps/clickhouse/templates/chkeeper.yaml
@@ -0,0 +1,95 @@
+{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }}
+
+{{- if .Values.clickhouseKeeper.enabled }}
+apiVersion: "clickhouse-keeper.altinity.com/v1"
+kind: "ClickHouseKeeperInstallation"
+metadata:
+  name: "{{ .Release.Name }}-keeper"
+  annotations:
+    prometheus.io/port: "7000"
+    prometheus.io/scrape: "true"
+spec:
+  namespaceDomainPattern: "%s.svc.{{ $clusterDomain }}"
+  configuration:
+    clusters:
+      - name: "cluster1"
+        layout:
+          replicasCount: {{ .Values.clickhouseKeeper.replicas }}
+    settings:
+      logger/level: "trace"
+      logger/console: "true"
+      listen_host: "0.0.0.0"
+      keeper_server/four_letter_word_white_list: "*"
+      keeper_server/coordination_settings/raft_logs_level: "information"
+      prometheus/endpoint: "/metrics"
+      prometheus/port: "7000"
+      prometheus/metrics: "true"
+      prometheus/events: "true"
+      prometheus/asynchronous_metrics: "true"
+      prometheus/status_info: "false"
+
+  defaults:
+    templates:
+      # Templates are specified as default for all clusters
+      podTemplate: default
+      dataVolumeClaimTemplate: default
+
+  templates:
+    podTemplates:
+      - name: default
+        metadata:
+          labels:
+            app: "{{ .Release.Name }}-keeper"
+          annotations:
+            prometheus.io/port: "7000"
+            prometheus.io/scrape: "true"
+        spec:
+          affinity:
+            podAntiAffinity:
+              requiredDuringSchedulingIgnoredDuringExecution:
+                - labelSelector:
+                    matchExpressions:
+                      - key: "app"
+                        operator: In
+                        values:
+                          - "{{ .Release.Name }}-keeper"
+                  topologyKey: "kubernetes.io/hostname"
+          containers:
+            - name: clickhouse-keeper
+              imagePullPolicy: IfNotPresent
+              image: clickhouse/clickhouse-keeper:24.9.2.42
+              resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.clickhouseKeeper.resourcesPreset .Values.resources $) | nindent 20 }}  
+          securityContext:
+            fsGroup: 101
+
+    volumeClaimTemplates:
+      - name: default
+        spec:
+          accessModes:
+            - ReadWriteOnce
+          resources:
+            requests:
+              storage: "{{ .Values.clickhouseKeeper.size }}"
+---
+apiVersion: operator.victoriametrics.com/v1beta1
+kind: VMPodScrape
+metadata:
+  name: {{ .Release.Name }}-keeper
+  namespace: {{ .Release.Namespace }}
+spec:
+  selector:
+    matchLabels:
+      app: {{ .Release.Name }}-keeper
+  namespaceSelector:
+    matchNames:
+      - {{ .Release.Namespace }}
+  podMetricsEndpoints:
+    - port: metrics
+      path: /metrics
+      interval: 30s
+      scheme: http
+      relabelConfigs:
+        - action: replace
+          sourceLabels: [__meta_kubernetes_pod_node_name]
+          targetLabel: instance
+{{- end }}
diff --git a/packages/apps/clickhouse/templates/clickhouse.yaml b/packages/apps/clickhouse/templates/clickhouse.yaml
index 1acc7003..b645260b 100644
--- a/packages/apps/clickhouse/templates/clickhouse.yaml
+++ b/packages/apps/clickhouse/templates/clickhouse.yaml
@@ -1,5 +1,4 @@
-{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }}
-{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }}
+{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }}
 {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }}
 {{- $passwords := dict }}
 {{- $users := .Values.users }}
@@ -91,6 +90,18 @@ spec:
         layout:
           shardsCount: {{ .Values.shards }}
           replicasCount: {{ .Values.replicas }}
+    {{- if .Values.clickhouseKeeper.enabled }}
+    zookeeper:
+      nodes:
+        {{- $replicas := int .Values.clickhouseKeeper.replicas }}
+        {{- $release := .Release.Name }}
+        {{- $namespace := .Release.Namespace }}
+        {{- $clusterDomain := .Values.clusterDomain }}
+        {{- range $i := until $replicas }}
+        - host: "chk-{{ $release }}-keeper-cluster1-0-{{ $i }}.{{ $namespace }}.svc.{{ $clusterDomain }}"
+          port: 2181
+        {{- end }}
+    {{- end }}
   templates:
     volumeClaimTemplates:
       - name: data-volume-template
diff --git a/packages/apps/clickhouse/templates/dashboard-resourcemap.yaml b/packages/apps/clickhouse/templates/dashboard-resourcemap.yaml
index c0a7d9fb..042f6de6 100644
--- a/packages/apps/clickhouse/templates/dashboard-resourcemap.yaml
+++ b/packages/apps/clickhouse/templates/dashboard-resourcemap.yaml
@@ -23,6 +23,9 @@ rules:
   - workloadmonitors
   resourceNames:
   - {{ .Release.Name }}
+  {{- if .Values.clickhouseKeeper.enabled }}
+  - {{ .Release.Name }}-keeper
+  {{- end }}
   verbs: ["get", "list", "watch"]
 ---
 kind: RoleBinding
diff --git a/packages/apps/clickhouse/templates/workloadmonitor.yaml b/packages/apps/clickhouse/templates/workloadmonitor.yaml
index f87db7bf..62c951c2 100644
--- a/packages/apps/clickhouse/templates/workloadmonitor.yaml
+++ b/packages/apps/clickhouse/templates/workloadmonitor.yaml
@@ -3,6 +3,8 @@ apiVersion: cozystack.io/v1alpha1
 kind: WorkloadMonitor
 metadata:
   name: {{ $.Release.Name }}
+  labels:
+    workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }}
 spec:
   replicas: {{ .Values.replicas }}
   minReplicas: 1
@@ -11,3 +13,20 @@ spec:
   selector:
     app.kubernetes.io/instance: {{ $.Release.Name }}
   version: {{ $.Chart.Version }}
+{{- if .Values.clickhouseKeeper.enabled }}
+---
+apiVersion: cozystack.io/v1alpha1
+kind: WorkloadMonitor
+metadata:
+  name: {{ $.Release.Name }}-keeper
+  labels:
+    workloads.cozystack.io/resource-preset: {{ .Values.clickhouseKeeper.resourcesPreset | quote }}
+spec:
+  replicas: {{ .Values.clickhouseKeeper.replicas }}
+  minReplicas: 1
+  kind: clickhouse
+  type: clickhouse
+  selector:
+    app: {{ $.Release.Name }}-keeper
+  version: {{ $.Chart.Version }}
+{{- end }}
diff --git a/packages/apps/clickhouse/values.schema.json b/packages/apps/clickhouse/values.schema.json
index ddc88b97..e4e1df7d 100644
--- a/packages/apps/clickhouse/values.schema.json
+++ b/packages/apps/clickhouse/values.schema.json
@@ -1,101 +1,221 @@
 {
-    "title": "Chart Values",
-    "type": "object",
-    "properties": {
-        "size": {
-            "type": "string",
-            "description": "Size of Persistent Volume for data",
-            "default": "10Gi"
+  "title": "Chart Values",
+  "type": "object",
+  "properties": {
+    "replicas": {
+      "description": "Number of ClickHouse replicas.",
+      "type": "integer",
+      "default": 2
+    },
+    "shards": {
+      "description": "Number of ClickHouse shards.",
+      "type": "integer",
+      "default": 1
+    },
+    "resources": {
+      "description": "Explicit CPU and memory configuration for each ClickHouse replica. When omitted, the preset defined in `resourcesPreset` is applied.",
+      "type": "object",
+      "default": {},
+      "properties": {
+        "cpu": {
+          "description": "CPU available to each replica.",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
         },
-        "logStorageSize": {
-            "type": "string",
-            "description": "Size of Persistent Volume for logs",
-            "default": "2Gi"
+        "memory": {
+          "description": "Memory (RAM) available to each replica.",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
+        }
+      }
+    },
+    "resourcesPreset": {
+      "description": "Default sizing preset used when `resources` is omitted.",
+      "type": "string",
+      "default": "small",
+      "enum": [
+        "nano",
+        "micro",
+        "small",
+        "medium",
+        "large",
+        "xlarge",
+        "2xlarge"
+      ]
+    },
+    "size": {
+      "description": "Persistent Volume Claim size available for application data.",
+      "default": "10Gi",
+      "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+      "anyOf": [
+        {
+          "type": "integer"
         },
-        "shards": {
-            "type": "number",
-            "description": "Number of Clickhouse shards",
-            "default": 1
+        {
+          "type": "string"
+        }
+      ],
+      "x-kubernetes-int-or-string": true
+    },
+    "storageClass": {
+      "description": "StorageClass used to store the data.",
+      "type": "string",
+      "default": ""
+    },
+    "logStorageSize": {
+      "description": "Size of Persistent Volume for logs.",
+      "default": "2Gi",
+      "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+      "anyOf": [
+        {
+          "type": "integer"
+        },
+        {
+          "type": "string"
+        }
+      ],
+      "x-kubernetes-int-or-string": true
+    },
+    "logTTL": {
+      "description": "TTL (expiration time) for `query_log` and `query_thread_log`.",
+      "type": "integer",
+      "default": 15
+    },
+    "users": {
+      "description": "Users configuration map.",
+      "type": "object",
+      "default": {},
+      "additionalProperties": {
+        "type": "object",
+        "properties": {
+          "password": {
+            "description": "Password for the user.",
+            "type": "string"
+          },
+          "readonly": {
+            "description": "User is readonly (default: false).",
+            "type": "boolean"
+          }
+        }
+      }
+    },
+    "backup": {
+      "description": "Backup configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "cleanupStrategy",
+        "enabled",
+        "resticPassword",
+        "s3AccessKey",
+        "s3Bucket",
+        "s3Region",
+        "s3SecretKey",
+        "schedule"
+      ],
+      "properties": {
+        "cleanupStrategy": {
+          "description": "Retention strategy for cleaning up old backups.",
+          "type": "string",
+          "default": "--keep-last=3 --keep-daily=3 --keep-within-weekly=1m"
+        },
+        "enabled": {
+          "description": "Enable regular backups (default: false).",
+          "type": "boolean",
+          "default": false
+        },
+        "resticPassword": {
+          "description": "Password for Restic backup encryption.",
+          "type": "string",
+          "default": "\u003cpassword\u003e"
+        },
+        "s3AccessKey": {
+          "description": "Access key for S3 authentication.",
+          "type": "string",
+          "default": "\u003cyour-access-key\u003e"
+        },
+        "s3Bucket": {
+          "description": "S3 bucket used for storing backups.",
+          "type": "string",
+          "default": "s3.example.org/clickhouse-backups"
+        },
+        "s3Region": {
+          "description": "AWS S3 region where backups are stored.",
+          "type": "string",
+          "default": "us-east-1"
+        },
+        "s3SecretKey": {
+          "description": "Secret key for S3 authentication.",
+          "type": "string",
+          "default": "\u003cyour-secret-key\u003e"
+        },
+        "schedule": {
+          "description": "Cron schedule for automated backups.",
+          "type": "string",
+          "default": "0 2 * * *"
+        }
+      }
+    },
+    "clickhouseKeeper": {
+      "description": "ClickHouse Keeper configuration.",
+      "type": "object",
+      "default": {},
+      "properties": {
+        "enabled": {
+          "description": "Deploy ClickHouse Keeper for cluster coordination.",
+          "type": "boolean",
+          "default": true
         },
         "replicas": {
-            "type": "number",
-            "description": "Number of Clickhouse replicas",
-            "default": 2
-        },
-        "storageClass": {
-            "type": "string",
-            "description": "StorageClass used to store the data",
-            "default": ""
-        },
-        "logTTL": {
-            "type": "number",
-            "description": "TTL (expiration time) for query_log and query_thread_log",
-            "default": 15
-        },
-        "backup": {
-            "type": "object",
-            "properties": {
-                "enabled": {
-                    "type": "boolean",
-                    "description": "Enable periodic backups",
-                    "default": false
-                },
-                "s3Region": {
-                    "type": "string",
-                    "description": "AWS S3 region where backups are stored",
-                    "default": "us-east-1"
-                },
-                "s3Bucket": {
-                    "type": "string",
-                    "description": "S3 bucket used for storing backups",
-                    "default": "s3.example.org/clickhouse-backups"
-                },
-                "schedule": {
-                    "type": "string",
-                    "description": "Cron schedule for automated backups",
-                    "default": "0 2 * * *"
-                },
-                "cleanupStrategy": {
-                    "type": "string",
-                    "description": "Retention strategy for cleaning up old backups",
-                    "default": "--keep-last=3 --keep-daily=3 --keep-within-weekly=1m"
-                },
-                "s3AccessKey": {
-                    "type": "string",
-                    "description": "Access key for S3, used for authentication",
-                    "default": "oobaiRus9pah8PhohL1ThaeTa4UVa7gu"
-                },
-                "s3SecretKey": {
-                    "type": "string",
-                    "description": "Secret key for S3, used for authentication",
-                    "default": "ju3eum4dekeich9ahM1te8waeGai0oog"
-                },
-                "resticPassword": {
-                    "type": "string",
-                    "description": "Password for Restic backup encryption",
-                    "default": "ChaXoveekoh6eigh4siesheeda2quai0"
-                }
-            }
-        },
-        "resources": {
-            "type": "object",
-            "description": "Explicit CPU and memory configuration for each ClickHouse replica. When left empty, the preset defined in `resourcesPreset` is applied.",
-            "default": {}
+          "description": "Number of Keeper replicas.",
+          "type": "integer",
+          "default": 3
         },
         "resourcesPreset": {
-            "type": "string",
-            "description": "Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.",
-            "default": "small",
-            "enum": [
-                "none",
-                "nano",
-                "micro",
-                "small",
-                "medium",
-                "large",
-                "xlarge",
-                "2xlarge"
-            ]
+          "description": "Default sizing preset.",
+          "type": "string",
+          "default": "micro",
+          "enum": [
+            "nano",
+            "micro",
+            "small",
+            "medium",
+            "large",
+            "xlarge",
+            "2xlarge"
+          ]
+        },
+        "size": {
+          "description": "Persistent Volume Claim size available for application data.",
+          "default": "1Gi",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
         }
+      }
     }
+  }
 }
diff --git a/packages/apps/clickhouse/values.yaml b/packages/apps/clickhouse/values.yaml
index 2ddfbbb2..61ae0b88 100644
--- a/packages/apps/clickhouse/values.yaml
+++ b/packages/apps/clickhouse/values.yaml
@@ -1,22 +1,54 @@
-## @section Common parameters
-
-## @param size Size of Persistent Volume for data
-## @param logStorageSize Size of Persistent Volume for logs
-## @param shards Number of Clickhouse shards
-## @param replicas Number of Clickhouse replicas
-## @param storageClass StorageClass used to store the data
-## @param logTTL TTL (expiration time) for query_log and query_thread_log
 ##
-size: 10Gi
-logStorageSize: 2Gi
-shards: 1
+## @section Common parameters
+##
+
+## @typedef {struct} Resources - Explicit CPU and memory configuration for each ClickHouse replica.
+## @field {quantity} [cpu] - CPU available to each replica.
+## @field {quantity} [memory] - Memory (RAM) available to each replica.
+
+## @enum {string} ResourcesPreset - Default sizing preset.
+## @value nano
+## @value micro
+## @value small
+## @value medium
+## @value large
+## @value xlarge
+## @value 2xlarge
+
+## @param {int} replicas - Number of ClickHouse replicas.
 replicas: 2
+
+## @param {int} shards - Number of ClickHouse shards.
+shards: 1
+
+## @param {Resources} [resources] - Explicit CPU and memory configuration for each ClickHouse replica. When omitted, the preset defined in `resourcesPreset` is applied.
+resources: {}
+
+## @param {ResourcesPreset} resourcesPreset="small" - Default sizing preset used when `resources` is omitted.
+resourcesPreset: "small"
+
+## @param {quantity} size - Persistent Volume Claim size available for application data.
+size: 10Gi
+
+## @param {string} storageClass - StorageClass used to store the data.
 storageClass: ""
+
+##
+## @section Application-specific parameters
+##
+
+## @param {quantity} logStorageSize - Size of Persistent Volume for logs.
+logStorageSize: 2Gi
+
+## @param {int} logTTL - TTL (expiration time) for `query_log` and `query_thread_log`.
 logTTL: 15
 
-## @section Configuration parameters
+## @typedef {struct} User - User configuration.
+## @field {string} [password] - Password for the user.
+## @field {bool} [readonly] - User is readonly (default: false).
 
-## @param users [object] Users configuration
+## @param {map[string]User} users - Users configuration map.
+users: {}
 ## Example:
 ## users:
 ##   user1:
@@ -25,33 +57,45 @@ logTTL: 15
 ##     readonly: true
 ##     password: hackme
 ##
-users: {}
 
+##
 ## @section Backup parameters
+##
 
-## @param backup.enabled Enable periodic backups
-## @param backup.s3Region AWS S3 region where backups are stored
-## @param backup.s3Bucket S3 bucket used for storing backups
-## @param backup.schedule Cron schedule for automated backups
-## @param backup.cleanupStrategy Retention strategy for cleaning up old backups
-## @param backup.s3AccessKey Access key for S3, used for authentication
-## @param backup.s3SecretKey Secret key for S3, used for authentication
-## @param backup.resticPassword Password for Restic backup encryption
+## @typedef {struct} Backup - Backup configuration.
+## @field {bool} enabled - Enable regular backups (default: false).
+## @field {string} s3Region - AWS S3 region where backups are stored.
+## @field {string} s3Bucket - S3 bucket used for storing backups.
+## @field {string} schedule - Cron schedule for automated backups.
+## @field {string} cleanupStrategy - Retention strategy for cleaning up old backups.
+## @field {string} s3AccessKey - Access key for S3 authentication.
+## @field {string} s3SecretKey - Secret key for S3 authentication.
+## @field {string} resticPassword - Password for Restic backup encryption.
+
+## @param {Backup} backup - Backup configuration.
 backup:
   enabled: false
   s3Region: us-east-1
-  s3Bucket: s3.example.org/clickhouse-backups
+  s3Bucket: "s3.example.org/clickhouse-backups"
   schedule: "0 2 * * *"
   cleanupStrategy: "--keep-last=3 --keep-daily=3 --keep-within-weekly=1m"
-  s3AccessKey: oobaiRus9pah8PhohL1ThaeTa4UVa7gu
-  s3SecretKey: ju3eum4dekeich9ahM1te8waeGai0oog
-  resticPassword: ChaXoveekoh6eigh4siesheeda2quai0
+  s3AccessKey: ""
+  s3SecretKey: ""
+  resticPassword: ""
 
-## @param resources Explicit CPU and memory configuration for each ClickHouse replica. When left empty, the preset defined in `resourcesPreset` is applied.
-resources: {}
- # resources:
- #   cpu: 4000m
- #   memory: 4Gi
+##
+## @section ClickHouse Keeper parameters
+##
 
-## @param resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.
-resourcesPreset: "small"
+## @typedef {struct} ClickHouseKeeper - ClickHouse Keeper configuration.
+## @field {bool} [enabled] - Deploy ClickHouse Keeper for cluster coordination.
+## @field {quantity} [size] - Persistent Volume Claim size available for application data.
+## @field {ResourcesPreset} [resourcesPreset] - Default sizing preset.
+## @field {int} [replicas] - Number of Keeper replicas.
+
+## @param {ClickHouseKeeper} clickhouseKeeper - ClickHouse Keeper configuration.
+clickhouseKeeper:
+  enabled: true
+  size: 1Gi
+  resourcesPreset: micro
+  replicas: 3
diff --git a/packages/apps/ferretdb/Makefile b/packages/apps/ferretdb/Makefile
deleted file mode 100644
index e4057cb4..00000000
--- a/packages/apps/ferretdb/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-include ../../../scripts/package.mk
-
-generate:
-	readme-generator -v values.yaml -s values.schema.json -r README.md
-	yq -i -o json --indent 4 '.properties.resourcesPreset.enum = ["none", "nano", "micro", "small", "medium", "large", "xlarge", "2xlarge"]' values.schema.json
diff --git a/packages/apps/ferretdb/README.md b/packages/apps/ferretdb/README.md
deleted file mode 100644
index bdd2fd39..00000000
--- a/packages/apps/ferretdb/README.md
+++ /dev/null
@@ -1,67 +0,0 @@
-# Managed FerretDB Service
-
-FerretDB is an open source MongoDB alternative.
-It translates MongoDB wire protocol queries to SQL and can be used as a direct replacement for MongoDB 5.0+.
-Internally, FerretDB service is backed by Postgres.
-
-## Parameters
-
-### Common parameters
-
-| Name                     | Description                                                                                                                 | Value   |
-| ------------------------ | --------------------------------------------------------------------------------------------------------------------------- | ------- |
-| `external`               | Enable external access from outside the cluster                                                                             | `false` |
-| `size`                   | Persistent Volume size                                                                                                      | `10Gi`  |
-| `replicas`               | Number of replicas                                                                                                          | `2`     |
-| `storageClass`           | StorageClass used to store the data                                                                                         | `""`    |
-| `quorum.minSyncReplicas` | Minimum number of synchronous replicas that must acknowledge a transaction before it is considered committed                | `0`     |
-| `quorum.maxSyncReplicas` | Maximum number of synchronous replicas that can acknowledge a transaction (must be lower than the total number of replicas) | `0`     |
-
-### Configuration parameters
-
-| Name    | Description         | Value |
-| ------- | ------------------- | ----- |
-| `users` | Users configuration | `{}`  |
-
-### Backup parameters
-
-| Name                     | Description                                                                                                                           | Value                                                  |
-| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
-| `backup.enabled`         | Enable periodic backups                                                                                                               | `false`                                                |
-| `backup.s3Region`        | The AWS S3 region where backups are stored                                                                                            | `us-east-1`                                            |
-| `backup.s3Bucket`        | The S3 bucket used for storing backups                                                                                                | `s3.example.org/postgres-backups`                      |
-| `backup.schedule`        | Cron schedule for automated backups                                                                                                   | `0 2 * * *`                                            |
-| `backup.cleanupStrategy` | The strategy for cleaning up old backups                                                                                              | `--keep-last=3 --keep-daily=3 --keep-within-weekly=1m` |
-| `backup.s3AccessKey`     | The access key for S3, used for authentication                                                                                        | `oobaiRus9pah8PhohL1ThaeTa4UVa7gu`                     |
-| `backup.s3SecretKey`     | The secret key for S3, used for authentication                                                                                        | `ju3eum4dekeich9ahM1te8waeGai0oog`                     |
-| `backup.resticPassword`  | The password for Restic backup encryption                                                                                             | `ChaXoveekoh6eigh4siesheeda2quai0`                     |
-| `resources`              | Explicit CPU and memory configuration for each FerretDB replica. When left empty, the preset defined in `resourcesPreset` is applied. | `{}`                                                   |
-| `resourcesPreset`        | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.     | `nano`                                                 |
-
-
-
-## Parameter examples and reference
-
-### resources and resourcesPreset
-
-`resources` sets explicit CPU and memory configurations for each replica.
-When left empty, the preset defined in `resourcesPreset` is applied.
-
-```yaml
-resources:
-  cpu: 4000m
-  memory: 4Gi
-```
-
-`resourcesPreset` sets named CPU and memory configurations for each replica.
-This setting is ignored if the corresponding `resources` value is set.
-
-| Preset name | CPU    | memory  |
-|-------------|--------|---------|
-| `nano`      | `250m` | `128Mi` |
-| `micro`     | `500m` | `256Mi` |
-| `small`     | `1`    | `512Mi` |
-| `medium`    | `1`    | `1Gi`   |
-| `large`     | `2`    | `2Gi`   |
-| `xlarge`    | `4`    | `4Gi`   |
-| `2xlarge`   | `8`    | `8Gi`   |
diff --git a/packages/apps/ferretdb/images/postgres-backup.tag b/packages/apps/ferretdb/images/postgres-backup.tag
deleted file mode 100644
index c06767fd..00000000
--- a/packages/apps/ferretdb/images/postgres-backup.tag
+++ /dev/null
@@ -1 +0,0 @@
-ghcr.io/cozystack/cozystack/postgres-backup:0.14.0@sha256:10179ed56457460d95cd5708db2a00130901255fa30c4dd76c65d2ef5622b61f
diff --git a/packages/apps/ferretdb/logos/ferretdb.svg b/packages/apps/ferretdb/logos/ferretdb.svg
deleted file mode 100644
index 7d5c8b40..00000000
--- a/packages/apps/ferretdb/logos/ferretdb.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/apps/ferretdb/templates/backup-cronjob.yaml b/packages/apps/ferretdb/templates/backup-cronjob.yaml
deleted file mode 100644
index ae3b148a..00000000
--- a/packages/apps/ferretdb/templates/backup-cronjob.yaml
+++ /dev/null
@@ -1,99 +0,0 @@
-{{- if .Values.backup.enabled }}
-{{ $image := .Files.Get "images/backup.json" | fromJson }}
-
-apiVersion: batch/v1
-kind: CronJob
-metadata:
-  name: {{ .Release.Name }}-backup
-spec:
-  schedule: "{{ .Values.backup.schedule }}"
-  concurrencyPolicy: Forbid
-  successfulJobsHistoryLimit: 3
-  failedJobsHistoryLimit: 3
-  jobTemplate:
-    spec:
-      backoffLimit: 2
-      template:
-        spec:
-          restartPolicy: OnFailure
-      template:
-        metadata:
-          annotations:
-            checksum/config: {{ include (print $.Template.BasePath "/backup-script.yaml") . | sha256sum }}
-            checksum/secret: {{ include (print $.Template.BasePath "/backup-secret.yaml") . | sha256sum }}
-        spec:
-          restartPolicy: Never
-          containers:
-          - name: pgdump
-            image: "{{ $.Files.Get "images/postgres-backup.tag" | trim }}"
-            command:
-            - /bin/sh
-            - /scripts/backup.sh
-            env:
-            - name: REPO_PREFIX
-              value: {{ required "s3Bucket is not specified!" .Values.backup.s3Bucket | quote }}
-            - name: CLEANUP_STRATEGY
-              value: {{ required "cleanupStrategy is not specified!" .Values.backup.cleanupStrategy | quote }}
-            - name: PGUSER
-              valueFrom:
-                secretKeyRef:
-                  name: {{ .Release.Name }}-postgres-superuser
-                  key: username
-            - name: PGPASSWORD
-              valueFrom:
-                secretKeyRef:
-                  name: {{ .Release.Name }}-postgres-superuser
-                  key: password
-            - name: PGHOST
-              value: {{ .Release.Name }}-postgres-rw
-            - name: PGPORT
-              value: "5432"
-            - name: PGDATABASE
-              value: postgres
-            - name: AWS_ACCESS_KEY_ID
-              valueFrom:
-                secretKeyRef:
-                  name: {{ .Release.Name }}-backup
-                  key: s3AccessKey
-            - name: AWS_SECRET_ACCESS_KEY
-              valueFrom:
-                secretKeyRef:
-                  name: {{ .Release.Name }}-backup
-                  key: s3SecretKey
-            - name: AWS_DEFAULT_REGION
-              value: {{ .Values.backup.s3Region }}
-            - name: RESTIC_PASSWORD
-              valueFrom:
-                secretKeyRef:
-                  name: {{ .Release.Name }}-backup
-                  key: resticPassword
-            volumeMounts:
-            - mountPath: /scripts
-              name: scripts
-            - mountPath: /tmp
-              name: tmp
-            - mountPath: /.cache
-              name: cache
-            securityContext:
-              allowPrivilegeEscalation: false
-              capabilities:
-                drop:
-                - ALL
-              privileged: false
-              readOnlyRootFilesystem: true
-              runAsNonRoot: true
-          volumes:
-          - name: scripts
-            secret:
-              secretName: {{ .Release.Name }}-backup-script
-          - name: tmp
-            emptyDir: {}
-          - name: cache
-            emptyDir: {}
-          securityContext:
-            runAsNonRoot: true
-            runAsUser: 9000
-            runAsGroup: 9000
-            seccompProfile:
-              type: RuntimeDefault
-{{- end }}
diff --git a/packages/apps/ferretdb/templates/backup-script.yaml b/packages/apps/ferretdb/templates/backup-script.yaml
deleted file mode 100644
index 362bdc01..00000000
--- a/packages/apps/ferretdb/templates/backup-script.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-{{- if .Values.backup.enabled }}
----
-apiVersion: v1
-kind: Secret
-metadata:
-  name: {{ .Release.Name }}-backup-script
-stringData:
-  backup.sh: |
-    #!/bin/sh
-    set -e
-    set -o pipefail
-
-    JOB_ID="job-$(uuidgen|cut -f1 -d-)"
-    DB_LIST=$(psql -Atq -c 'SELECT datname FROM pg_catalog.pg_database;' | grep -v '^\(postgres\|app\|template.*\)$')
-    echo DB_LIST=$(echo "$DB_LIST" | shuf) # shuffle list
-    echo "Job ID: $JOB_ID"
-    echo "Target repo: $REPO_PREFIX"
-    echo "Cleanup strategy: $CLEANUP_STRATEGY"
-    echo "Start backup for:"
-    echo "$DB_LIST"
-    echo
-    echo "Backup started at `date +%Y-%m-%d\ %H:%M:%S`"
-    for db in $DB_LIST; do
-      (
-        set -x
-        restic -r "s3:${REPO_PREFIX}/$db" cat config >/dev/null 2>&1 || \
-          restic -r "s3:${REPO_PREFIX}/$db" init --repository-version 2
-        restic -r "s3:${REPO_PREFIX}/$db" unlock --remove-all >/dev/null 2>&1 || true # no locks, k8s takes care of it
-        pg_dump -Z0 -Ft -d "$db" | \
-          restic -r "s3:${REPO_PREFIX}/$db" backup --tag "$JOB_ID" --stdin --stdin-filename dump.tar
-        restic -r "s3:${REPO_PREFIX}/$db" tag --tag "$JOB_ID" --set "completed"
-      )
-    done
-    echo "Backup finished at `date +%Y-%m-%d\ %H:%M:%S`"
-
-    echo
-    echo "Run cleanup:"
-    echo
-
-    echo "Cleanup started at `date +%Y-%m-%d\ %H:%M:%S`"
-    for db in $DB_LIST; do
-      (
-        set -x
-        restic forget -r "s3:${REPO_PREFIX}/$db" --group-by=tags --keep-tag "completed" # keep completed snapshots only
-        restic forget -r "s3:${REPO_PREFIX}/$db" --group-by=tags $CLEANUP_STRATEGY
-        restic prune -r "s3:${REPO_PREFIX}/$db"
-      )
-    done
-    echo "Cleanup finished at `date +%Y-%m-%d\ %H:%M:%S`"
-{{- end }}
diff --git a/packages/apps/ferretdb/templates/external-svc.yaml b/packages/apps/ferretdb/templates/external-svc.yaml
deleted file mode 100644
index 31d54695..00000000
--- a/packages/apps/ferretdb/templates/external-svc.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-apiVersion: v1
-kind: Service
-metadata:
-  name: {{ .Release.Name }}
-  labels:
-    app.kubernetes.io/instance: {{ .Release.Name }}
-spec:
-  type: {{ ternary "LoadBalancer" "ClusterIP" .Values.external }}
-  {{- if .Values.external }}
-  externalTrafficPolicy: Local
-  allocateLoadBalancerNodePorts: false
-  {{- end }}
-  ports:
-  - name: ferretdb
-    port: 27017
-  selector:
-    app: {{ .Release.Name }}
diff --git a/packages/apps/ferretdb/templates/ferretdb.yaml b/packages/apps/ferretdb/templates/ferretdb.yaml
deleted file mode 100644
index 7fbba009..00000000
--- a/packages/apps/ferretdb/templates/ferretdb.yaml
+++ /dev/null
@@ -1,27 +0,0 @@
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: {{ .Release.Name }}
-spec:
-  replicas: {{ .Values.replicas }}
-  selector:
-    matchLabels:
-      app: {{ .Release.Name }}
-  template:
-    metadata:
-      labels:
-        app: {{ .Release.Name }}
-        app.kubernetes.io/instance: {{ .Release.Name }}
-    spec:
-      containers:
-      - name: ferretdb
-        image: ghcr.io/ferretdb/ferretdb:1.24.0
-        ports:
-        - containerPort: 27017
-        env:
-          - name: FERRETDB_POSTGRESQL_URL
-            valueFrom:
-              secretKeyRef:
-                name: {{ .Release.Name }}-postgres-app
-                key: uri
diff --git a/packages/apps/ferretdb/templates/init-job.yaml b/packages/apps/ferretdb/templates/init-job.yaml
deleted file mode 100644
index b7b03133..00000000
--- a/packages/apps/ferretdb/templates/init-job.yaml
+++ /dev/null
@@ -1,66 +0,0 @@
-apiVersion: batch/v1
-kind: Job
-metadata:
-  name: {{ .Release.Name }}-init-job
-  annotations:
-    "helm.sh/hook": post-install,post-upgrade
-    "helm.sh/hook-weight": "-5"
-    "helm.sh/hook-delete-policy": before-hook-creation
-spec:
-  template:
-    metadata:
-      name: {{ .Release.Name }}-init-job
-      annotations:
-        checksum/config: {{ include (print $.Template.BasePath "/init-script.yaml") . | sha256sum }}
-    spec:
-      restartPolicy: Never
-      containers:
-      - name: postgres
-        image: ghcr.io/cloudnative-pg/postgresql:15.3
-        command:
-        - bash
-        - /scripts/init.sh
-        env:
-        - name: PGUSER
-          valueFrom:
-            secretKeyRef:
-              name: {{ .Release.Name }}-postgres-superuser
-              key: username
-        - name: PGPASSWORD
-          valueFrom:
-            secretKeyRef:
-              name: {{ .Release.Name }}-postgres-superuser
-              key: password
-        - name: PGHOST
-          value: {{ .Release.Name }}-postgres-rw
-        - name: PGPORT
-          value: "5432"
-        - name: PGDATABASE
-          value: postgres
-        securityContext:
-          allowPrivilegeEscalation: false
-          capabilities:
-            drop:
-            - ALL
-          privileged: false
-          readOnlyRootFilesystem: true
-          runAsNonRoot: true
-        volumeMounts:
-        - mountPath: /etc/secret
-          name: secret
-        - mountPath: /scripts
-          name: scripts
-      securityContext:
-        fsGroup: 26
-        runAsGroup: 26
-        runAsNonRoot: true
-        runAsUser: 26
-        seccompProfile:
-          type: RuntimeDefault
-      volumes:
-      - name: secret
-        secret:
-          secretName: {{ .Release.Name }}-postgres-superuser
-      - name: scripts
-        secret:
-          secretName: {{ .Release.Name }}-init-script
diff --git a/packages/apps/ferretdb/templates/init-script.yaml b/packages/apps/ferretdb/templates/init-script.yaml
deleted file mode 100644
index 35723ede..00000000
--- a/packages/apps/ferretdb/templates/init-script.yaml
+++ /dev/null
@@ -1,131 +0,0 @@
-{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }}
-{{- $passwords := dict }}
-
-{{- with (index $existingSecret "data") }}
-  {{- range $k, $v := . }}
-    {{- $_ := set $passwords $k (b64dec $v) }}
-  {{- end }}
-{{- end }}
-
-{{- range $user, $u := .Values.users }}
-  {{- if $u.password }}
-    {{- $_ := set $passwords $user $u.password }}
-  {{- else if not (index $passwords $user) }}
-    {{- $_ := set $passwords $user (randAlphaNum 16) }}
-  {{- end }}
-{{- end }}
-
-{{- if .Values.users }}
-apiVersion: v1
-kind: Secret
-metadata:
-  name: {{ .Release.Name }}-credentials
-stringData:
-  {{- range $user, $u := .Values.users }}
-  {{ quote $user }}: {{ quote (index $passwords $user) }}
-  {{- end }}
-{{- end }}
----
-apiVersion: v1
-kind: Secret
-metadata:
-  name: {{ .Release.Name }}-init-script
-stringData:
-  init.sh: |
-    #!/bin/bash
-    set -e
-
-    until pg_isready ; do sleep 5; done
-
-    echo "== create users"
-    {{- if .Values.users }}
-    psql -v ON_ERROR_STOP=1 <<\EOT
-    {{- range $user, $u := .Values.users }}
-    SELECT 'CREATE ROLE {{ $user }} LOGIN INHERIT;'
-    WHERE NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = '{{ $user }}')\gexec
-    ALTER ROLE {{ $user }} WITH PASSWORD '{{ index $passwords $user }}' LOGIN INHERIT {{ ternary "REPLICATION" "NOREPLICATION" (default false $u.replication) }};
-    COMMENT ON ROLE {{ $user }} IS 'user managed by helm';
-    {{- end }}
-    EOT
-    {{- end }}
-
-    echo "== delete users"
-    MANAGED_USERS=$(echo '\du+' | psql | awk -F'|' '$4 == " user managed by helm" {print $1}' | awk NF=NF RS= OFS=' ')
-    DEFINED_USERS="{{ join " " (keys .Values.users) }}"
-    DELETE_USERS=$(for user in $MANAGED_USERS; do case " $DEFINED_USERS " in *" $user "*) :;; *) echo $user;; esac; done)
-
-    echo "users to delete: $DELETE_USERS"
-    for user in $DELETE_USERS; do
-    # https://stackoverflow.com/a/51257346/2931267
-    psql -v ON_ERROR_STOP=1 --echo-all <
+
+  
+  
+  
+  
+  
+    
+      
+      
+    
+  
+  
+    
+		
+
+		
+
+		
+
+	
+    
+    
+    
+  
+
diff --git a/packages/apps/foundationdb/templates/_resources.tpl b/packages/apps/foundationdb/templates/_resources.tpl
new file mode 100644
index 00000000..c1b4915e
--- /dev/null
+++ b/packages/apps/foundationdb/templates/_resources.tpl
@@ -0,0 +1,47 @@
+{{/*
+Common resource definitions
+*/}}
+{{- define "foundationdb.resources" -}}
+{{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resources.preset .Values.resources $) }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "foundationdb.labels" -}}
+helm.sh/chart: {{ include "foundationdb.chart" . }}
+{{ include "foundationdb.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "foundationdb.selectorLabels" -}}
+app.kubernetes.io/name: foundationdb
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Chart name and version
+*/}}
+{{- define "foundationdb.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Calculate minReplicas for WorkloadMonitor based on redundancyMode
+*/}}
+{{- define "foundationdb.minReplicas" -}}
+{{- $replicas := .Values.cluster.processCounts.storage -}}
+{{- if or (eq .Values.cluster.redundancyMode "triple") (eq .Values.cluster.redundancyMode "three_data_hall") (eq .Values.cluster.redundancyMode "three_datacenter") (eq .Values.cluster.redundancyMode "three_datacenter_fallback") (eq .Values.cluster.redundancyMode "three_data_hall_fallback") }}
+{{- print (max 1 (sub $replicas 2)) -}}
+{{- else if eq .Values.cluster.redundancyMode "double" }}
+{{- print (max 1 (sub $replicas 1)) -}}
+{{- else }}
+{{- print $replicas -}}
+{{- end -}}
+{{- end -}}
\ No newline at end of file
diff --git a/packages/apps/foundationdb/templates/backup.yaml b/packages/apps/foundationdb/templates/backup.yaml
new file mode 100644
index 00000000..129a7b2c
--- /dev/null
+++ b/packages/apps/foundationdb/templates/backup.yaml
@@ -0,0 +1,65 @@
+{{- if .Values.backup.enabled }}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ .Release.Name }}-s3-creds
+  labels:
+    app.kubernetes.io/name: foundationdb
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+type: Opaque
+data:
+  AWS_ACCESS_KEY_ID: {{ .Values.backup.s3.credentials.accessKeyId | b64enc }}
+  AWS_SECRET_ACCESS_KEY: {{ .Values.backup.s3.credentials.secretAccessKey | b64enc }}
+
+---
+apiVersion: apps.foundationdb.org/v1beta2
+kind: FoundationDBBackup
+metadata:
+  name: {{ .Release.Name }}-backup
+  labels:
+    app.kubernetes.io/name: foundationdb
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+spec:
+  clusterName: {{ .Release.Name }}
+  
+  backupState: Running
+  
+  backupDeploymentSpec:
+    podTemplateSpec:
+      spec:
+        containers:
+          - name: foundationdb
+            resources:
+              limits:
+                cpu: 100m
+                memory: 128Mi
+              requests:
+                cpu: 100m
+                memory: 128Mi
+            securityContext:
+              runAsUser: 0
+  
+  customParameters:
+    - backup_agent_snapshot_mode=0
+  
+  snapshotPeriodSeconds: 3600
+  
+  blobStoreConfiguration:
+    accountName: {{ .Values.backup.s3.bucket }}
+    bucket: {{ .Values.backup.s3.bucket }}
+    {{- if .Values.backup.s3.endpoint }}
+    endpoint: {{ .Values.backup.s3.endpoint }}
+    {{- end }}
+    credentials:
+      AWS_ACCESS_KEY_ID:
+        secretKeyRef:
+          name: {{ .Release.Name }}-s3-creds
+          key: AWS_ACCESS_KEY_ID
+      AWS_SECRET_ACCESS_KEY:
+        secretKeyRef:
+          name: {{ .Release.Name }}-s3-creds
+          key: AWS_SECRET_ACCESS_KEY
+{{- end }}
\ No newline at end of file
diff --git a/packages/apps/foundationdb/templates/cluster.yaml b/packages/apps/foundationdb/templates/cluster.yaml
new file mode 100644
index 00000000..be804233
--- /dev/null
+++ b/packages/apps/foundationdb/templates/cluster.yaml
@@ -0,0 +1,97 @@
+{{- $clusterDomain := index .Values._cluster "cluster-domain" | default "cozy.local" }}
+---
+apiVersion: apps.foundationdb.org/v1beta2
+kind: FoundationDBCluster
+metadata:
+  name: {{ .Release.Name }}
+  labels:
+    app.kubernetes.io/name: foundationdb
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+spec:
+  version: {{ .Values.cluster.version | quote }}
+
+  databaseConfiguration:
+    redundancy_mode: {{ .Values.cluster.redundancyMode }}
+    storage_engine: {{ .Values.cluster.storageEngine }}
+
+  processCounts:
+    {{- toYaml .Values.cluster.processCounts | nindent 4 }}
+  
+  automationOptions:
+    replacements:
+      enabled: {{ .Values.automaticReplacements }}
+    faultDomain:
+      key: {{ .Values.cluster.faultDomain.key }}
+      {{- if .Values.cluster.faultDomain.valueFrom }}
+      valueFrom: {{ .Values.cluster.faultDomain.valueFrom }}
+      {{- end }}
+    imageType: {{ .Values.imageType }}
+    labels:
+      filterOnOwnerReference: false
+      matchLabels:
+        foundationdb.org/fdb-cluster-name: {{ .Release.Name }}
+      processClassLabels:
+        - foundationdb.org/fdb-process-class
+      processGroupIDLabels:
+        - foundationdb.org/fdb-process-group-id
+    minimumUptimeSecondsForBounce: 60
+  
+  processes:
+    general:
+      {{- if .Values.customParameters }}
+      customParameters:
+        {{- range .Values.customParameters }}
+        - {{ . }}
+        {{- end }}
+      {{- end }}
+      podTemplate:
+        metadata:
+          labels:
+            policy.cozystack.io/allow-to-apiserver: "true"
+        spec:
+          serviceAccountName: {{ .Release.Name }}-foundationdb
+          securityContext:
+            fsGroup: {{ .Values.securityContext.runAsGroup }}
+          containers:
+            - name: foundationdb
+              resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 16 }}
+              securityContext:
+                {{- toYaml .Values.securityContext | nindent 16 }}
+            - name: foundationdb-kubernetes-sidecar
+              resources:
+                limits:
+                  cpu: 100m
+                  memory: 128Mi
+                requests:
+                  cpu: 100m
+                  memory: 128Mi
+              securityContext:
+                {{- toYaml .Values.securityContext | nindent 16 }}
+          initContainers:
+            - name: foundationdb-kubernetes-init
+              resources:
+                limits:
+                  cpu: 100m
+                  memory: 128Mi
+                requests:
+                  cpu: 100m
+                  memory: 128Mi
+              securityContext:
+                {{- toYaml .Values.securityContext | nindent 16 }}
+      volumeClaimTemplate:
+        spec:
+          {{- if .Values.storage.storageClass }}
+          storageClassName: {{ .Values.storage.storageClass }}
+          {{- end }}
+          resources:
+            requests:
+              storage: {{ .Values.storage.size }}
+  
+  routing:
+    dnsDomain: {{ $clusterDomain }}
+    defineDNSLocalityFields: true
+  
+  sidecarContainer:
+    enableLivenessProbe: true
+    enableReadinessProbe: true
\ No newline at end of file
diff --git a/packages/apps/foundationdb/templates/dashboard-resourcemap.yaml b/packages/apps/foundationdb/templates/dashboard-resourcemap.yaml
new file mode 100644
index 00000000..ea378769
--- /dev/null
+++ b/packages/apps/foundationdb/templates/dashboard-resourcemap.yaml
@@ -0,0 +1,22 @@
+{{- if .Values.monitoring.enabled }}
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ .Release.Name }}-resourcemap
+  labels:
+    app.kubernetes.io/name: foundationdb
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    app.cozystack.io/type: dashboard-resourcemap
+data:
+  resources: |
+    - apiVersion: apps.foundationdb.org/v1beta2
+      kind: FoundationDBCluster
+      name: {{ .Release.Name }}
+    {{- if .Values.backup.enabled }}
+    - apiVersion: apps.foundationdb.org/v1beta2
+      kind: FoundationDBBackup
+      name: {{ .Release.Name }}-backup
+    {{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/packages/apps/foundationdb/templates/role.yaml b/packages/apps/foundationdb/templates/role.yaml
new file mode 100644
index 00000000..a391a084
--- /dev/null
+++ b/packages/apps/foundationdb/templates/role.yaml
@@ -0,0 +1,22 @@
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: {{ .Release.Name }}-foundationdb
+  labels:
+    app.kubernetes.io/name: foundationdb
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - pods
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - update
+  - patch
+  - delete
\ No newline at end of file
diff --git a/packages/apps/foundationdb/templates/rolebinding.yaml b/packages/apps/foundationdb/templates/rolebinding.yaml
new file mode 100644
index 00000000..45b3e123
--- /dev/null
+++ b/packages/apps/foundationdb/templates/rolebinding.yaml
@@ -0,0 +1,17 @@
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: {{ .Release.Name }}-foundationdb
+  labels:
+    app.kubernetes.io/name: foundationdb
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: {{ .Release.Name }}-foundationdb
+subjects:
+- kind: ServiceAccount
+  name: {{ .Release.Name }}-foundationdb
+  namespace: {{ .Release.Namespace }}
\ No newline at end of file
diff --git a/packages/apps/foundationdb/templates/serviceaccount.yaml b/packages/apps/foundationdb/templates/serviceaccount.yaml
new file mode 100644
index 00000000..b53143de
--- /dev/null
+++ b/packages/apps/foundationdb/templates/serviceaccount.yaml
@@ -0,0 +1,9 @@
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ .Release.Name }}-foundationdb
+  labels:
+    app.kubernetes.io/name: foundationdb
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
\ No newline at end of file
diff --git a/packages/apps/foundationdb/templates/workloadmonitor.yaml b/packages/apps/foundationdb/templates/workloadmonitor.yaml
new file mode 100644
index 00000000..2e2a3d19
--- /dev/null
+++ b/packages/apps/foundationdb/templates/workloadmonitor.yaml
@@ -0,0 +1,21 @@
+{{- if .Values.monitoring.enabled }}
+---
+apiVersion: cozystack.io/v1alpha1
+kind: WorkloadMonitor
+metadata:
+  name: {{ .Release.Name }}
+  labels:
+    app.kubernetes.io/name: foundationdb
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }}
+spec:
+  replicas: {{ .Values.cluster.processCounts.storage }}
+  minReplicas: {{ include "foundationdb.minReplicas" . }}
+  kind: foundationdb
+  type: foundationdb
+  selector:
+    foundationdb.org/fdb-cluster-name: {{ .Release.Name }}
+    foundationdb.org/fdb-process-class: storage
+  version: {{ .Chart.Version }}
+{{- end }}
\ No newline at end of file
diff --git a/packages/apps/foundationdb/values.schema.json b/packages/apps/foundationdb/values.schema.json
new file mode 100644
index 00000000..1fc77d59
--- /dev/null
+++ b/packages/apps/foundationdb/values.schema.json
@@ -0,0 +1,287 @@
+{
+  "title": "Chart Values",
+  "type": "object",
+  "properties": {
+    "cluster": {
+      "description": "Cluster configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "faultDomain",
+        "processCounts",
+        "redundancyMode",
+        "storageEngine",
+        "version"
+      ],
+      "properties": {
+        "faultDomain": {
+          "description": "Fault domain configuration.",
+          "type": "object",
+          "default": {},
+          "required": [
+            "key",
+            "valueFrom"
+          ],
+          "properties": {
+            "key": {
+              "description": "Fault domain key.",
+              "type": "string",
+              "default": "kubernetes.io/hostname"
+            },
+            "valueFrom": {
+              "description": "Fault domain value source.",
+              "type": "string",
+              "default": "spec.nodeName"
+            }
+          }
+        },
+        "processCounts": {
+          "description": "Process counts for different roles.",
+          "type": "object",
+          "default": {},
+          "required": [
+            "cluster_controller",
+            "stateless",
+            "storage"
+          ],
+          "properties": {
+            "cluster_controller": {
+              "description": "Number of cluster controller processes.",
+              "type": "integer",
+              "default": 1
+            },
+            "stateless": {
+              "description": "Number of stateless processes (-1 for automatic).",
+              "type": "integer",
+              "default": -1
+            },
+            "storage": {
+              "description": "Number of storage processes (determines cluster size).",
+              "type": "integer",
+              "default": 3
+            }
+          }
+        },
+        "redundancyMode": {
+          "description": "Database redundancy mode (single, double, triple, three_datacenter, three_datacenter_fallback).",
+          "type": "string",
+          "default": "double"
+        },
+        "storageEngine": {
+          "description": "Storage engine (ssd-2, ssd-redwood-v1, ssd-rocksdb-v1, memory).",
+          "type": "string",
+          "default": "ssd-2"
+        },
+        "version": {
+          "description": "Version of FoundationDB to use.",
+          "type": "string",
+          "default": "7.3.63"
+        }
+      }
+    },
+    "storage": {
+      "description": "Storage configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "size",
+        "storageClass"
+      ],
+      "properties": {
+        "size": {
+          "description": "Size of persistent volumes for each instance.",
+          "default": "16Gi",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
+        },
+        "storageClass": {
+          "description": "Storage class (if not set, uses cluster default).",
+          "type": "string",
+          "default": ""
+        }
+      }
+    },
+    "resources": {
+      "description": "Explicit CPU and memory configuration for each FoundationDB instance. When omitted, the preset defined in `resourcesPreset` is applied.",
+      "type": "object",
+      "default": {},
+      "properties": {
+        "cpu": {
+          "description": "CPU available to each instance.",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
+        },
+        "memory": {
+          "description": "Memory (RAM) available to each instance.",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
+        }
+      }
+    },
+    "resourcesPreset": {
+      "description": "Default sizing preset used when `resources` is omitted.",
+      "type": "string",
+      "default": "medium",
+      "enum": [
+        "small",
+        "medium",
+        "large",
+        "xlarge",
+        "2xlarge"
+      ]
+    },
+    "backup": {
+      "description": "Backup configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "enabled",
+        "retentionPolicy",
+        "s3"
+      ],
+      "properties": {
+        "enabled": {
+          "description": "Enable backups.",
+          "type": "boolean",
+          "default": false
+        },
+        "retentionPolicy": {
+          "description": "Retention policy for backups.",
+          "type": "string",
+          "default": "7d"
+        },
+        "s3": {
+          "description": "S3 configuration for backups.",
+          "type": "object",
+          "default": {},
+          "required": [
+            "bucket",
+            "credentials",
+            "endpoint",
+            "region"
+          ],
+          "properties": {
+            "bucket": {
+              "description": "S3 bucket name.",
+              "type": "string",
+              "default": ""
+            },
+            "credentials": {
+              "description": "S3 credentials.",
+              "type": "object",
+              "default": {},
+              "required": [
+                "accessKeyId",
+                "secretAccessKey"
+              ],
+              "properties": {
+                "accessKeyId": {
+                  "description": "S3 access key ID.",
+                  "type": "string",
+                  "default": ""
+                },
+                "secretAccessKey": {
+                  "description": "S3 secret access key.",
+                  "type": "string",
+                  "default": ""
+                }
+              }
+            },
+            "endpoint": {
+              "description": "S3 endpoint URL.",
+              "type": "string",
+              "default": ""
+            },
+            "region": {
+              "description": "S3 region.",
+              "type": "string",
+              "default": "us-east-1"
+            }
+          }
+        }
+      }
+    },
+    "monitoring": {
+      "description": "Monitoring configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "enabled"
+      ],
+      "properties": {
+        "enabled": {
+          "description": "Enable WorkloadMonitor integration.",
+          "type": "boolean",
+          "default": true
+        }
+      }
+    },
+    "customParameters": {
+      "description": "Custom parameters to pass to FoundationDB.",
+      "type": "array",
+      "default": [],
+      "items": {
+        "type": "string"
+      }
+    },
+    "imageType": {
+      "description": "Container image deployment type.",
+      "type": "string",
+      "default": "unified",
+      "enum": [
+        "unified",
+        "split"
+      ]
+    },
+    "securityContext": {
+      "description": "Security context for containers.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "runAsGroup",
+        "runAsUser"
+      ],
+      "properties": {
+        "runAsGroup": {
+          "description": "Group ID to run the container.",
+          "type": "integer",
+          "default": 4059
+        },
+        "runAsUser": {
+          "description": "User ID to run the container.",
+          "type": "integer",
+          "default": 4059
+        }
+      }
+    },
+    "automaticReplacements": {
+      "description": "Enable automatic pod replacements.",
+      "type": "boolean",
+      "default": true
+    }
+  }
+}
diff --git a/packages/apps/foundationdb/values.yaml b/packages/apps/foundationdb/values.yaml
new file mode 100644
index 00000000..e908288a
--- /dev/null
+++ b/packages/apps/foundationdb/values.yaml
@@ -0,0 +1,120 @@
+##
+## @section Common parameters
+##
+
+## @typedef {struct} ClusterProcessCounts - Process counts for different roles.
+## @field {int} stateless - Number of stateless processes (-1 for automatic).
+## @field {int} storage - Number of storage processes (determines cluster size).
+## @field {int} cluster_controller - Number of cluster controller processes.
+
+## @typedef {struct} ClusterFaultDomain - Fault domain configuration.
+## @field {string} key - Fault domain key.
+## @field {string} valueFrom - Fault domain value source.
+
+## @typedef {struct} Cluster - Cluster configuration.
+## @field {ClusterProcessCounts} processCounts - Process counts for different roles.
+## @field {string} version - Version of FoundationDB to use.
+## @field {string} redundancyMode - Database redundancy mode (single, double, triple, three_datacenter, three_datacenter_fallback).
+## @field {string} storageEngine - Storage engine (ssd-2, ssd-redwood-v1, ssd-rocksdb-v1, memory).
+## @field {ClusterFaultDomain} faultDomain - Fault domain configuration.
+
+## @param {Cluster} cluster - Cluster configuration.
+cluster:
+  processCounts:
+    stateless: -1
+    storage: 3
+    cluster_controller: 1
+
+  version: "7.3.63"
+  redundancyMode: "double"
+  storageEngine: "ssd-2"
+
+  faultDomain:
+    key: "kubernetes.io/hostname"
+    valueFrom: "spec.nodeName"
+
+## @typedef {struct} Storage - Storage configuration.
+## @field {quantity} size - Size of persistent volumes for each instance.
+## @field {string} storageClass - Storage class (if not set, uses cluster default).
+
+## @param {Storage} storage - Storage configuration.
+storage:
+  size: "16Gi"
+  storageClass: ""
+
+## @typedef {struct} Resources - Explicit CPU and memory configuration for each FoundationDB instance.
+## @field {quantity} [cpu] - CPU available to each instance.
+## @field {quantity} [memory] - Memory (RAM) available to each instance.
+
+## @enum {string} ResourcesPreset - Default sizing preset.
+## @value small
+## @value medium
+## @value large
+## @value xlarge
+## @value 2xlarge
+
+## @param {Resources} [resources] - Explicit CPU and memory configuration for each FoundationDB instance. When omitted, the preset defined in `resourcesPreset` is applied.
+resources: {}
+
+## @param {ResourcesPreset} resourcesPreset="medium" - Default sizing preset used when `resources` is omitted.
+resourcesPreset: "medium"
+
+## @typedef {struct} BackupS3Credentials - S3 credentials.
+## @field {string} accessKeyId - S3 access key ID.
+## @field {string} secretAccessKey - S3 secret access key.
+
+## @typedef {struct} BackupS3 - S3 configuration for backups.
+## @field {string} bucket - S3 bucket name.
+## @field {string} endpoint - S3 endpoint URL.
+## @field {string} region - S3 region.
+## @field {BackupS3Credentials} credentials - S3 credentials.
+
+## @typedef {struct} Backup - Backup configuration.
+## @field {bool} enabled - Enable backups.
+## @field {BackupS3} s3 - S3 configuration for backups.
+## @field {string} retentionPolicy - Retention policy for backups.
+
+## @param {Backup} backup - Backup configuration.
+backup:
+  enabled: false
+  s3:
+    bucket: ""
+    endpoint: ""
+    region: "us-east-1"
+    credentials:
+      accessKeyId: ""
+      secretAccessKey: ""
+  retentionPolicy: "7d"
+
+## @typedef {struct} Monitoring - Monitoring configuration.
+## @field {bool} enabled - Enable WorkloadMonitor integration.
+
+## @param {Monitoring} monitoring - Monitoring configuration.
+monitoring:
+  enabled: true
+
+##
+## @section FoundationDB configuration
+##
+
+## @param {[]string} customParameters - Custom parameters to pass to FoundationDB.
+customParameters: []
+
+## @enum {string} ImageType - Container image deployment type.
+## @value unified
+## @value split
+
+## @param {ImageType} imageType="unified" - Container image deployment type.
+imageType: "unified"
+
+## @typedef {struct} SecurityContext - Security context for containers.
+## @field {int} runAsUser - User ID to run the container.
+## @field {int} runAsGroup - Group ID to run the container.
+
+## @param {SecurityContext} securityContext - Security context for containers.
+securityContext:
+  runAsUser: 4059
+  runAsGroup: 4059
+
+## @param {bool} automaticReplacements - Enable automatic pod replacements.
+automaticReplacements: true
diff --git a/packages/apps/harbor/Chart.yaml b/packages/apps/harbor/Chart.yaml
new file mode 100644
index 00000000..8b6f59da
--- /dev/null
+++ b/packages/apps/harbor/Chart.yaml
@@ -0,0 +1,7 @@
+apiVersion: v2
+name: harbor
+description: Managed Harbor container registry
+icon: /logos/harbor.svg
+type: application
+version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process
+appVersion: "2.14.2"
diff --git a/packages/apps/harbor/Makefile b/packages/apps/harbor/Makefile
new file mode 100644
index 00000000..43c25998
--- /dev/null
+++ b/packages/apps/harbor/Makefile
@@ -0,0 +1,7 @@
+NAME=harbor
+
+include ../../../hack/package.mk
+
+generate:
+	cozyvalues-gen -m 'harbor' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/harbor/types.go
+	../../../hack/update-crd.sh
diff --git a/packages/apps/harbor/README.md b/packages/apps/harbor/README.md
new file mode 100644
index 00000000..7789d9fe
--- /dev/null
+++ b/packages/apps/harbor/README.md
@@ -0,0 +1,47 @@
+# Managed Harbor Container Registry
+
+Harbor is an open-source trusted cloud-native registry project that stores, signs, and scans content.
+
+## Parameters
+
+### Common parameters
+
+| Name           | Description                                                                                  | Type     | Value |
+| -------------- | -------------------------------------------------------------------------------------------- | -------- | ----- |
+| `host`         | Hostname for external access to Harbor (defaults to 'harbor' subdomain for the tenant host). | `string` | `""`  |
+| `storageClass` | StorageClass used to store the data.                                                         | `string` | `""`  |
+
+
+### Component configuration
+
+| Name                          | Description                                                                                              | Type       | Value   |
+| ----------------------------- | -------------------------------------------------------------------------------------------------------- | ---------- | ------- |
+| `core`                        | Core API server configuration.                                                                           | `object`   | `{}`    |
+| `core.resources`              | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object`   | `{}`    |
+| `core.resources.cpu`          | Number of CPU cores allocated.                                                                           | `quantity` | `""`    |
+| `core.resources.memory`       | Amount of memory allocated.                                                                              | `quantity` | `""`    |
+| `core.resourcesPreset`        | Default sizing preset used when `resources` is omitted.                                                  | `string`   | `small` |
+| `registry`                    | Container image registry configuration.                                                                  | `object`   | `{}`    |
+| `registry.resources`          | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object`   | `{}`    |
+| `registry.resources.cpu`      | Number of CPU cores allocated.                                                                           | `quantity` | `""`    |
+| `registry.resources.memory`   | Amount of memory allocated.                                                                              | `quantity` | `""`    |
+| `registry.resourcesPreset`    | Default sizing preset used when `resources` is omitted.                                                  | `string`   | `small` |
+| `jobservice`                  | Background job service configuration.                                                                    | `object`   | `{}`    |
+| `jobservice.resources`        | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object`   | `{}`    |
+| `jobservice.resources.cpu`    | Number of CPU cores allocated.                                                                           | `quantity` | `""`    |
+| `jobservice.resources.memory` | Amount of memory allocated.                                                                              | `quantity` | `""`    |
+| `jobservice.resourcesPreset`  | Default sizing preset used when `resources` is omitted.                                                  | `string`   | `nano`  |
+| `trivy`                       | Trivy vulnerability scanner configuration.                                                               | `object`   | `{}`    |
+| `trivy.enabled`               | Enable or disable the vulnerability scanner.                                                             | `bool`     | `true`  |
+| `trivy.size`                  | Persistent Volume size for vulnerability database cache.                                                 | `quantity` | `5Gi`   |
+| `trivy.resources`             | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object`   | `{}`    |
+| `trivy.resources.cpu`         | Number of CPU cores allocated.                                                                           | `quantity` | `""`    |
+| `trivy.resources.memory`      | Amount of memory allocated.                                                                              | `quantity` | `""`    |
+| `trivy.resourcesPreset`       | Default sizing preset used when `resources` is omitted.                                                  | `string`   | `nano`  |
+| `database`                    | PostgreSQL database configuration.                                                                       | `object`   | `{}`    |
+| `database.size`               | Persistent Volume size for database storage.                                                             | `quantity` | `5Gi`   |
+| `database.replicas`           | Number of database instances.                                                                            | `int`      | `2`     |
+| `redis`                       | Redis cache configuration.                                                                               | `object`   | `{}`    |
+| `redis.size`                  | Persistent Volume size for cache storage.                                                                | `quantity` | `1Gi`   |
+| `redis.replicas`              | Number of Redis replicas.                                                                                | `int`      | `2`     |
+
diff --git a/packages/apps/mysql/charts/cozy-lib b/packages/apps/harbor/charts/cozy-lib
similarity index 100%
rename from packages/apps/mysql/charts/cozy-lib
rename to packages/apps/harbor/charts/cozy-lib
diff --git a/packages/apps/harbor/logos/harbor.svg b/packages/apps/harbor/logos/harbor.svg
new file mode 100644
index 00000000..682254c3
--- /dev/null
+++ b/packages/apps/harbor/logos/harbor.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/apps/harbor/templates/bucket.yaml b/packages/apps/harbor/templates/bucket.yaml
new file mode 100644
index 00000000..a9e60988
--- /dev/null
+++ b/packages/apps/harbor/templates/bucket.yaml
@@ -0,0 +1,19 @@
+{{- $seaweedfs := .Values._namespace.seaweedfs }}
+apiVersion: objectstorage.k8s.io/v1alpha1
+kind: BucketClaim
+metadata:
+  name: {{ .Release.Name }}-registry
+spec:
+  bucketClassName: {{ $seaweedfs }}
+  protocols:
+    - s3
+---
+apiVersion: objectstorage.k8s.io/v1alpha1
+kind: BucketAccess
+metadata:
+  name: {{ .Release.Name }}-registry
+spec:
+  bucketAccessClassName: {{ $seaweedfs }}
+  bucketClaimName: {{ .Release.Name }}-registry
+  credentialsSecretName: {{ .Release.Name }}-registry-bucket
+  protocol: s3
diff --git a/packages/apps/harbor/templates/dashboard-resourcemap.yaml b/packages/apps/harbor/templates/dashboard-resourcemap.yaml
new file mode 100644
index 00000000..f8d91a61
--- /dev/null
+++ b/packages/apps/harbor/templates/dashboard-resourcemap.yaml
@@ -0,0 +1,46 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: {{ .Release.Name }}-dashboard-resources
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - services
+  resourceNames:
+  - {{ .Release.Name }}
+  verbs: ["get", "list", "watch"]
+- apiGroups:
+  - ""
+  resources:
+  - secrets
+  resourceNames:
+  - {{ .Release.Name }}-credentials
+  verbs: ["get", "list", "watch"]
+- apiGroups:
+  - networking.k8s.io
+  resources:
+  - ingresses
+  resourceNames:
+  - {{ .Release.Name }}-ingress
+  verbs: ["get", "list", "watch"]
+- apiGroups:
+  - cozystack.io
+  resources:
+  - workloadmonitors
+  resourceNames:
+  - {{ .Release.Name }}-core
+  - {{ .Release.Name }}-registry
+  - {{ .Release.Name }}-portal
+  verbs: ["get", "list", "watch"]
+---
+kind: RoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: {{ .Release.Name }}-dashboard-resources
+subjects:
+{{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "super-admin" .Release.Namespace) }}
+roleRef:
+  kind: Role
+  name: {{ .Release.Name }}-dashboard-resources
+  apiGroup: rbac.authorization.k8s.io
diff --git a/packages/apps/harbor/templates/harbor.yaml b/packages/apps/harbor/templates/harbor.yaml
new file mode 100644
index 00000000..bf780967
--- /dev/null
+++ b/packages/apps/harbor/templates/harbor.yaml
@@ -0,0 +1,205 @@
+{{- $host := .Values._namespace.host }}
+{{- $harborHost := .Values.host | default (printf "%s.%s" .Release.Name $host) }}
+
+{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }}
+{{- $adminPassword := randAlphaNum 16 }}
+{{- $redisPassword := randAlphaNum 32 }}
+{{- if $existingSecret }}
+  {{- $adminPassword = index $existingSecret.data "admin-password" | b64dec }}
+  {{- if hasKey $existingSecret.data "redis-password" }}
+    {{- $redisPassword = index $existingSecret.data "redis-password" | b64dec }}
+  {{- end }}
+{{- end }}
+
+{{- $existingCoreSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-core" .Release.Name) }}
+{{- $tokenKey := "" }}
+{{- $tokenCert := "" }}
+{{- if $existingCoreSecret }}
+  {{- if hasKey $existingCoreSecret.data "tls.key" }}
+    {{- $tokenKey = index $existingCoreSecret.data "tls.key" | b64dec }}
+  {{- end }}
+  {{- if hasKey $existingCoreSecret.data "tls.crt" }}
+    {{- $tokenCert = index $existingCoreSecret.data "tls.crt" | b64dec }}
+  {{- end }}
+{{- end }}
+
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ .Release.Name }}-credentials
+stringData:
+  admin-password: {{ $adminPassword | quote }}
+  redis-password: {{ $redisPassword | quote }}
+  url: https://{{ $harborHost }}
+
+---
+
+apiVersion: helm.toolkit.fluxcd.io/v2
+kind: HelmRelease
+metadata:
+  name: {{ .Release.Name }}-system
+  labels:
+    sharding.fluxcd.io/key: tenants
+spec:
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-harbor-application-default-harbor-system
+    namespace: cozy-system
+  interval: 5m
+  timeout: 15m
+  install:
+    remediation:
+      retries: -1
+  upgrade:
+    force: true
+    remediation:
+      retries: -1
+  valuesFrom:
+  - kind: Secret
+    name: cozystack-values
+  - kind: Secret
+    name: {{ .Release.Name }}-credentials
+    valuesKey: redis-password
+    targetPath: redis.password
+  - kind: Secret
+    name: {{ .Release.Name }}-credentials
+    valuesKey: redis-password
+    targetPath: harbor.redis.external.password
+  values:
+    bucket:
+      secretName: {{ .Release.Name }}-registry-bucket
+    db:
+      replicas: {{ .Values.database.replicas }}
+      size: {{ .Values.database.size }}
+      {{- with .Values.storageClass }}
+      storageClass: {{ . }}
+      {{- end }}
+    redis:
+      replicas: {{ .Values.redis.replicas }}
+      size: {{ .Values.redis.size }}
+      {{- with .Values.storageClass }}
+      storageClass: {{ . }}
+      {{- end }}
+    harbor:
+      fullnameOverride: {{ .Release.Name }}
+      harborAdminPassword: {{ $adminPassword | quote }}
+      externalURL: https://{{ $harborHost }}
+      expose:
+        type: clusterIP
+        clusterIP:
+          name: {{ .Release.Name }}
+        tls:
+          enabled: false
+      persistence:
+        enabled: true
+        resourcePolicy: "keep"
+        imageChartStorage:
+          type: s3
+          s3:
+            existingSecret: {{ .Release.Name }}-registry-s3
+            region: us-east-1
+            bucket: {{ .Release.Name }}-registry
+            secure: false
+            v4auth: true
+        {{- if .Values.trivy.enabled }}
+        persistentVolumeClaim:
+          trivy:
+            size: {{ .Values.trivy.size }}
+            {{- with .Values.storageClass }}
+            storageClass: {{ . }}
+            {{- end }}
+        {{- end }}
+      portal:
+        resources: {{- include "cozy-lib.resources.defaultingSanitize" (list "nano" (dict) $) | nindent 10 }}
+      core:
+        {{- if and $tokenKey $tokenCert }}
+        tokenKey: {{ $tokenKey | quote }}
+        tokenCert: {{ $tokenCert | quote }}
+        {{- end }}
+        resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.core.resourcesPreset .Values.core.resources $) | nindent 10 }}
+      registry:
+        registry:
+          resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.registry.resourcesPreset .Values.registry.resources $) | nindent 12 }}
+        controller:
+          resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.registry.resourcesPreset .Values.registry.resources $) | nindent 12 }}
+      jobservice:
+        resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.jobservice.resourcesPreset .Values.jobservice.resources $) | nindent 10 }}
+      trivy:
+        enabled: {{ .Values.trivy.enabled }}
+        {{- if .Values.trivy.enabled }}
+        resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.trivy.resourcesPreset .Values.trivy.resources $) | nindent 10 }}
+        {{- end }}
+      database:
+        type: external
+        external:
+          host: "{{ .Release.Name }}-db-rw"
+          port: "5432"
+          username: app
+          coreDatabase: app
+          sslmode: require
+          existingSecret: "{{ .Release.Name }}-db-app"
+      redis:
+        type: external
+        external:
+          addr: "rfs-{{ .Release.Name }}-redis:26379"
+          sentinelMasterSet: "mymaster"
+          coreDatabaseIndex: "0"
+          jobserviceDatabaseIndex: "1"
+          registryDatabaseIndex: "2"
+          trivyAdapterIndex: "5"
+      metrics:
+        enabled: true
+        serviceMonitor:
+          enabled: true
+
+---
+
+apiVersion: cozystack.io/v1alpha1
+kind: WorkloadMonitor
+metadata:
+  name: {{ $.Release.Name }}-core
+  labels:
+    workloads.cozystack.io/resource-preset: {{ .Values.core.resourcesPreset | quote }}
+spec:
+  replicas: 1
+  minReplicas: 1
+  kind: harbor
+  type: core
+  selector:
+    release: {{ $.Release.Name }}-system
+    component: core
+  version: {{ $.Chart.Version }}
+
+---
+
+apiVersion: cozystack.io/v1alpha1
+kind: WorkloadMonitor
+metadata:
+  name: {{ $.Release.Name }}-registry
+  labels:
+    workloads.cozystack.io/resource-preset: {{ .Values.registry.resourcesPreset | quote }}
+spec:
+  replicas: 1
+  minReplicas: 1
+  kind: harbor
+  type: registry
+  selector:
+    release: {{ $.Release.Name }}-system
+    component: registry
+  version: {{ $.Chart.Version }}
+
+---
+
+apiVersion: cozystack.io/v1alpha1
+kind: WorkloadMonitor
+metadata:
+  name: {{ $.Release.Name }}-portal
+spec:
+  replicas: 1
+  minReplicas: 1
+  kind: harbor
+  type: portal
+  selector:
+    release: {{ $.Release.Name }}-system
+    component: portal
+  version: {{ $.Chart.Version }}
diff --git a/packages/apps/harbor/templates/ingress.yaml b/packages/apps/harbor/templates/ingress.yaml
new file mode 100644
index 00000000..70933f5f
--- /dev/null
+++ b/packages/apps/harbor/templates/ingress.yaml
@@ -0,0 +1,37 @@
+{{- $ingress := .Values._namespace.ingress }}
+{{- $host := .Values._namespace.host }}
+{{- $harborHost := .Values.host | default (printf "%s.%s" .Release.Name $host) }}
+{{- $solver := (index .Values._cluster "solver") | default "http01" }}
+{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }}
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: {{ .Release.Name }}-ingress
+  annotations:
+    nginx.ingress.kubernetes.io/proxy-body-size: "0"
+    nginx.ingress.kubernetes.io/proxy-read-timeout: "900"
+    nginx.ingress.kubernetes.io/proxy-send-timeout: "900"
+    nginx.ingress.kubernetes.io/ssl-redirect: "true"
+    nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
+    {{- if eq $solver "http01" }}
+    acme.cert-manager.io/http01-ingress-ingressclassname: {{ $ingress }}
+    {{- end }}
+    cert-manager.io/cluster-issuer: {{ $clusterIssuer }}
+spec:
+  ingressClassName: {{ $ingress }}
+  tls:
+    - hosts:
+        - {{ $harborHost | quote }}
+      secretName: {{ .Release.Name }}-ingress-tls
+  rules:
+    - host: {{ $harborHost | quote }}
+      http:
+        paths:
+          - path: /
+            pathType: Prefix
+            backend:
+              service:
+                name: {{ .Release.Name }}
+                port:
+                  number: 80
diff --git a/packages/apps/harbor/values.schema.json b/packages/apps/harbor/values.schema.json
new file mode 100644
index 00000000..23860ca3
--- /dev/null
+++ b/packages/apps/harbor/values.schema.json
@@ -0,0 +1,315 @@
+{
+  "title": "Chart Values",
+  "type": "object",
+  "properties": {
+    "host": {
+      "description": "Hostname for external access to Harbor (defaults to 'harbor' subdomain for the tenant host).",
+      "type": "string",
+      "default": ""
+    },
+    "storageClass": {
+      "description": "StorageClass used to store the data.",
+      "type": "string",
+      "default": ""
+    },
+    "core": {
+      "description": "Core API server configuration.",
+      "type": "object",
+      "default": {},
+      "properties": {
+        "resources": {
+          "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.",
+          "type": "object",
+          "default": {},
+          "properties": {
+            "cpu": {
+              "description": "Number of CPU cores allocated.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            },
+            "memory": {
+              "description": "Amount of memory allocated.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            }
+          }
+        },
+        "resourcesPreset": {
+          "description": "Default sizing preset used when `resources` is omitted.",
+          "type": "string",
+          "default": "small",
+          "enum": [
+            "nano",
+            "micro",
+            "small",
+            "medium",
+            "large",
+            "xlarge",
+            "2xlarge"
+          ]
+        }
+      }
+    },
+    "registry": {
+      "description": "Container image registry configuration.",
+      "type": "object",
+      "default": {},
+      "properties": {
+        "resources": {
+          "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.",
+          "type": "object",
+          "default": {},
+          "properties": {
+            "cpu": {
+              "description": "Number of CPU cores allocated.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            },
+            "memory": {
+              "description": "Amount of memory allocated.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            }
+          }
+        },
+        "resourcesPreset": {
+          "description": "Default sizing preset used when `resources` is omitted.",
+          "type": "string",
+          "default": "small",
+          "enum": [
+            "nano",
+            "micro",
+            "small",
+            "medium",
+            "large",
+            "xlarge",
+            "2xlarge"
+          ]
+        }
+      }
+    },
+    "jobservice": {
+      "description": "Background job service configuration.",
+      "type": "object",
+      "default": {},
+      "properties": {
+        "resources": {
+          "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.",
+          "type": "object",
+          "default": {},
+          "properties": {
+            "cpu": {
+              "description": "Number of CPU cores allocated.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            },
+            "memory": {
+              "description": "Amount of memory allocated.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            }
+          }
+        },
+        "resourcesPreset": {
+          "description": "Default sizing preset used when `resources` is omitted.",
+          "type": "string",
+          "default": "nano",
+          "enum": [
+            "nano",
+            "micro",
+            "small",
+            "medium",
+            "large",
+            "xlarge",
+            "2xlarge"
+          ]
+        }
+      }
+    },
+    "trivy": {
+      "description": "Trivy vulnerability scanner configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "enabled",
+        "size"
+      ],
+      "properties": {
+        "enabled": {
+          "description": "Enable or disable the vulnerability scanner.",
+          "type": "boolean",
+          "default": true
+        },
+        "resources": {
+          "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.",
+          "type": "object",
+          "default": {},
+          "properties": {
+            "cpu": {
+              "description": "Number of CPU cores allocated.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            },
+            "memory": {
+              "description": "Amount of memory allocated.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            }
+          }
+        },
+        "resourcesPreset": {
+          "description": "Default sizing preset used when `resources` is omitted.",
+          "type": "string",
+          "default": "nano",
+          "enum": [
+            "nano",
+            "micro",
+            "small",
+            "medium",
+            "large",
+            "xlarge",
+            "2xlarge"
+          ]
+        },
+        "size": {
+          "description": "Persistent Volume size for vulnerability database cache.",
+          "default": "5Gi",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
+        }
+      }
+    },
+    "database": {
+      "description": "PostgreSQL database configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "replicas",
+        "size"
+      ],
+      "properties": {
+        "replicas": {
+          "description": "Number of database instances.",
+          "type": "integer",
+          "default": 2
+        },
+        "size": {
+          "description": "Persistent Volume size for database storage.",
+          "default": "5Gi",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
+        }
+      }
+    },
+    "redis": {
+      "description": "Redis cache configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "replicas",
+        "size"
+      ],
+      "properties": {
+        "replicas": {
+          "description": "Number of Redis replicas.",
+          "type": "integer",
+          "default": 2
+        },
+        "size": {
+          "description": "Persistent Volume size for cache storage.",
+          "default": "1Gi",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
+        }
+      }
+    }
+  }
+}
diff --git a/packages/apps/harbor/values.yaml b/packages/apps/harbor/values.yaml
new file mode 100644
index 00000000..de44eaff
--- /dev/null
+++ b/packages/apps/harbor/values.yaml
@@ -0,0 +1,84 @@
+##
+## @section Common parameters
+##
+
+## @param {string} [host] - Hostname for external access to Harbor (defaults to 'harbor' subdomain for the tenant host).
+host: ""
+
+## @param {string} storageClass - StorageClass used to store the data.
+storageClass: ""
+
+##
+## @section Component configuration
+##
+
+## @typedef {struct} Resources - Resource configuration.
+## @field {quantity} [cpu] - Number of CPU cores allocated.
+## @field {quantity} [memory] - Amount of memory allocated.
+
+## @enum {string} ResourcesPreset - Default sizing preset.
+## @value nano
+## @value micro
+## @value small
+## @value medium
+## @value large
+## @value xlarge
+## @value 2xlarge
+
+## @typedef {struct} Core - Core API server configuration.
+## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.
+## @field {ResourcesPreset} [resourcesPreset] - Default sizing preset used when `resources` is omitted.
+
+## @param {Core} core - Core API server configuration.
+core:
+  resources: {}
+  resourcesPreset: "small"
+
+## @typedef {struct} Registry - Container image registry configuration.
+## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.
+## @field {ResourcesPreset} [resourcesPreset] - Default sizing preset used when `resources` is omitted.
+
+## @param {Registry} registry - Container image registry configuration.
+registry:
+  resources: {}
+  resourcesPreset: "small"
+
+## @typedef {struct} Jobservice - Background job service configuration.
+## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.
+## @field {ResourcesPreset} [resourcesPreset] - Default sizing preset used when `resources` is omitted.
+
+## @param {Jobservice} jobservice - Background job service configuration.
+jobservice:
+  resources: {}
+  resourcesPreset: "nano"
+
+## @typedef {struct} Trivy - Trivy vulnerability scanner configuration.
+## @field {bool} enabled - Enable or disable the vulnerability scanner.
+## @field {quantity} size - Persistent Volume size for vulnerability database cache.
+## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.
+## @field {ResourcesPreset} [resourcesPreset] - Default sizing preset used when `resources` is omitted.
+
+## @param {Trivy} trivy - Trivy vulnerability scanner configuration.
+trivy:
+  enabled: true
+  size: 5Gi
+  resources: {}
+  resourcesPreset: "nano"
+
+## @typedef {struct} Database - PostgreSQL database configuration (provisioned via CloudNativePG).
+## @field {quantity} size - Persistent Volume size for database storage.
+## @field {int} replicas - Number of database instances.
+
+## @param {Database} database - PostgreSQL database configuration.
+database:
+  size: 5Gi
+  replicas: 2
+
+## @typedef {struct} Redis - Redis cache configuration (provisioned via redis-operator).
+## @field {quantity} size - Persistent Volume size for cache storage.
+## @field {int} replicas - Number of Redis replicas.
+
+## @param {Redis} redis - Redis cache configuration.
+redis:
+  size: 1Gi
+  replicas: 2
diff --git a/packages/apps/http-cache/Chart.yaml b/packages/apps/http-cache/Chart.yaml
index 8d788564..bbd4f3a2 100644
--- a/packages/apps/http-cache/Chart.yaml
+++ b/packages/apps/http-cache/Chart.yaml
@@ -2,24 +2,6 @@ apiVersion: v2
 name: http-cache
 description: Layer7 load balancer and caching service
 icon: /logos/nginx.svg
-
-# 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: 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
-
-# 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.
+version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process
 appVersion: "1.25.3"
diff --git a/packages/apps/http-cache/Makefile b/packages/apps/http-cache/Makefile
index a118e386..899f0288 100644
--- a/packages/apps/http-cache/Makefile
+++ b/packages/apps/http-cache/Makefile
@@ -1,30 +1,24 @@
 NGINX_CACHE_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml)
 
-include ../../../scripts/common-envs.mk
-include ../../../scripts/package.mk
+include ../../../hack/common-envs.mk
+include ../../../hack/package.mk
 
 image: image-nginx
 
 image-nginx:
 	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 \
 		--metadata-file images/nginx-cache.json \
-		--push=$(PUSH) \
-		--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \
-		--load=$(LOAD)
+		$(BUILDX_ARGS)
 	echo "$(REGISTRY)/nginx-cache:$(call settag,$(NGINX_CACHE_TAG))@$$(yq e '."containerimage.digest"' images/nginx-cache.json -o json -r)" \
 		> images/nginx-cache.tag
 	rm -f images/nginx-cache.json
 
 generate:
-	readme-generator -v values.yaml -s values.schema.json -r README.md
-	yq -i -o json --indent 4 '.properties.haproxy.properties.resourcesPreset.enum = ["none", "nano", "micro", "small", "medium", "large", "xlarge", "2xlarge"]' values.schema.json
-	yq -i -o json --indent 4 '.properties.nginx.properties.resourcesPreset.enum = ["none", "nano", "micro", "small", "medium", "large", "xlarge", "2xlarge"]' values.schema.json
+	cozyvalues-gen -m 'httpcache' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/httpcache/types.go
+	../../../hack/update-crd.sh
 
 update:
 	tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/chrislim2888/IP2Location-C-Library | awk -F'[/^]' 'END{print $$3}') && \
diff --git a/packages/apps/http-cache/README.md b/packages/apps/http-cache/README.md
index 0a3cb0af..c227d153 100644
--- a/packages/apps/http-cache/README.md
+++ b/packages/apps/http-cache/README.md
@@ -60,23 +60,43 @@ The deployment architecture is illustrated in the diagram below:
 
 ### Common parameters
 
-| Name                      | Description                                                                                                                          | Value   |
-| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ------- |
-| `external`                | Enable external access from outside the cluster                                                                                      | `false` |
-| `size`                    | Persistent Volume size                                                                                                               | `10Gi`  |
-| `storageClass`            | StorageClass used to store the data                                                                                                  | `""`    |
-| `haproxy.replicas`        | Number of HAProxy replicas                                                                                                           | `2`     |
-| `nginx.replicas`          | Number of Nginx replicas                                                                                                             | `2`     |
-| `haproxy.resources`       | Explicit CPU and memory configuration for each HAProxy replica. When left empty, the preset defined in `resourcesPreset` is applied. | `{}`    |
-| `haproxy.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.    | `nano`  |
-| `nginx.resources`         | Explicit CPU and memory configuration for each nginx replica. When left empty, the preset defined in `resourcesPreset` is applied.   | `{}`    |
-| `nginx.resourcesPreset`   | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.    | `nano`  |
+| Name           | Description                                                  | Type       | Value   |
+| -------------- | ------------------------------------------------------------ | ---------- | ------- |
+| `size`         | Persistent Volume Claim size available for application data. | `quantity` | `10Gi`  |
+| `storageClass` | StorageClass used to store the data.                         | `string`   | `""`    |
+| `external`     | Enable external access from outside the cluster.             | `bool`     | `false` |
 
-### Configuration parameters
 
-| Name        | Description             | Value |
-| ----------- | ----------------------- | ----- |
-| `endpoints` | Endpoints configuration | `[]`  |
+### Application-specific parameters
+
+| Name        | Description                                      | Type       | Value |
+| ----------- | ------------------------------------------------ | ---------- | ----- |
+| `endpoints` | Endpoints configuration, as a list of . | `[]string` | `[]`  |
+
+
+### HAProxy parameters
+
+| Name                       | Description                                                                                              | Type       | Value  |
+| -------------------------- | -------------------------------------------------------------------------------------------------------- | ---------- | ------ |
+| `haproxy`                  | HAProxy configuration.                                                                                   | `object`   | `{}`   |
+| `haproxy.replicas`         | Number of HAProxy replicas.                                                                              | `int`      | `2`    |
+| `haproxy.resources`        | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object`   | `{}`   |
+| `haproxy.resources.cpu`    | CPU available to each replica.                                                                           | `quantity` | `""`   |
+| `haproxy.resources.memory` | Memory (RAM) available to each replica.                                                                  | `quantity` | `""`   |
+| `haproxy.resourcesPreset`  | Default sizing preset used when `resources` is omitted.                                                  | `string`   | `nano` |
+
+
+### Nginx parameters
+
+| Name                     | Description                                                                                              | Type       | Value  |
+| ------------------------ | -------------------------------------------------------------------------------------------------------- | ---------- | ------ |
+| `nginx`                  | Nginx configuration.                                                                                     | `object`   | `{}`   |
+| `nginx.replicas`         | Number of Nginx replicas.                                                                                | `int`      | `2`    |
+| `nginx.resources`        | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object`   | `{}`   |
+| `nginx.resources.cpu`    | CPU available to each replica.                                                                           | `quantity` | `""`   |
+| `nginx.resources.memory` | Memory (RAM) available to each replica.                                                                  | `quantity` | `""`   |
+| `nginx.resourcesPreset`  | Default sizing preset used when `resources` is omitted.                                                  | `string`   | `nano` |
+
 
 ## Parameter examples and reference
 
diff --git a/packages/apps/http-cache/images/nginx-cache.tag b/packages/apps/http-cache/images/nginx-cache.tag
index 3d6da77c..b08a374e 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.6.0@sha256:b7633717cd7449c0042ae92d8ca9b36e4d69566561f5c7d44e21058e7d05c6d5
+ghcr.io/cozystack/cozystack/nginx-cache:0.0.0@sha256:d397781152ab9123b11b8191d92eba7a0d2faa376aa2c15ddeb67842a9b59bab
diff --git a/packages/apps/http-cache/templates/haproxy/service.yaml b/packages/apps/http-cache/templates/haproxy/service.yaml
index 39659212..9286a8b5 100644
--- a/packages/apps/http-cache/templates/haproxy/service.yaml
+++ b/packages/apps/http-cache/templates/haproxy/service.yaml
@@ -10,7 +10,9 @@ spec:
   type: {{ ternary "LoadBalancer" "ClusterIP" .Values.external }}
   {{- if .Values.external }}
   externalTrafficPolicy: Local
+    {{- if (include "cozy-lib.network.disableLoadBalancerNodePorts" $ | fromYaml) }}
   allocateLoadBalancerNodePorts: false
+    {{- end }}
   {{- end }}
   selector:
     app: {{ .Release.Name }}-haproxy
diff --git a/packages/apps/http-cache/templates/workloadmonitor.yaml b/packages/apps/http-cache/templates/workloadmonitor.yaml
index 150d8bbe..a38a395a 100644
--- a/packages/apps/http-cache/templates/workloadmonitor.yaml
+++ b/packages/apps/http-cache/templates/workloadmonitor.yaml
@@ -3,6 +3,8 @@ apiVersion: cozystack.io/v1alpha1
 kind: WorkloadMonitor
 metadata:
   name: {{ $.Release.Name }}-haproxy
+  labels:
+    workloads.cozystack.io/resource-preset: {{ .Values.haproxy.resourcesPreset | quote }}
 spec:
   replicas: {{ .Values.haproxy.replicas }}
   minReplicas: 1
@@ -16,6 +18,8 @@ apiVersion: cozystack.io/v1alpha1
 kind: WorkloadMonitor
 metadata:
   name: {{ $.Release.Name }}-nginx
+  labels:
+    workloads.cozystack.io/resource-preset: {{ .Values.nginx.resourcesPreset | quote }}
 spec:
   replicas: {{ .Values.nginx.replicas }}
   minReplicas: 1
diff --git a/packages/apps/http-cache/values.schema.json b/packages/apps/http-cache/values.schema.json
index c624c8b5..14609cc3 100644
--- a/packages/apps/http-cache/values.schema.json
+++ b/packages/apps/http-cache/values.schema.json
@@ -1,87 +1,164 @@
 {
-    "title": "Chart Values",
-    "type": "object",
-    "properties": {
-        "external": {
-            "type": "boolean",
-            "description": "Enable external access from outside the cluster",
-            "default": false
+  "title": "Chart Values",
+  "type": "object",
+  "properties": {
+    "size": {
+      "description": "Persistent Volume Claim size available for application data.",
+      "default": "10Gi",
+      "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+      "anyOf": [
+        {
+          "type": "integer"
         },
-        "size": {
-            "type": "string",
-            "description": "Persistent Volume size",
-            "default": "10Gi"
-        },
-        "storageClass": {
-            "type": "string",
-            "description": "StorageClass used to store the data",
-            "default": ""
-        },
-        "haproxy": {
-            "type": "object",
-            "properties": {
-                "replicas": {
-                    "type": "number",
-                    "description": "Number of HAProxy replicas",
-                    "default": 2
-                },
-                "resources": {
-                    "type": "object",
-                    "description": "Explicit CPU and memory configuration for each HAProxy replica. When left empty, the preset defined in `resourcesPreset` is applied.",
-                    "default": {}
-                },
-                "resourcesPreset": {
-                    "type": "string",
-                    "description": "Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.",
-                    "default": "nano",
-                    "enum": [
-                        "none",
-                        "nano",
-                        "micro",
-                        "small",
-                        "medium",
-                        "large",
-                        "xlarge",
-                        "2xlarge"
-                    ]
-                }
-            }
-        },
-        "nginx": {
-            "type": "object",
-            "properties": {
-                "replicas": {
-                    "type": "number",
-                    "description": "Number of Nginx replicas",
-                    "default": 2
-                },
-                "resources": {
-                    "type": "object",
-                    "description": "Explicit CPU and memory configuration for each nginx replica. When left empty, the preset defined in `resourcesPreset` is applied.",
-                    "default": {}
-                },
-                "resourcesPreset": {
-                    "type": "string",
-                    "description": "Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.",
-                    "default": "nano",
-                    "enum": [
-                        "none",
-                        "nano",
-                        "micro",
-                        "small",
-                        "medium",
-                        "large",
-                        "xlarge",
-                        "2xlarge"
-                    ]
-                }
-            }
-        },
-        "endpoints": {
-            "type": "array",
-            "description": "Endpoints configuration",
-            "default": [],
-            "items": {}
+        {
+          "type": "string"
         }
+      ],
+      "x-kubernetes-int-or-string": true
+    },
+    "storageClass": {
+      "description": "StorageClass used to store the data.",
+      "type": "string",
+      "default": ""
+    },
+    "external": {
+      "description": "Enable external access from outside the cluster.",
+      "type": "boolean",
+      "default": false
+    },
+    "endpoints": {
+      "description": "Endpoints configuration, as a list of \u003cip:port\u003e.",
+      "type": "array",
+      "default": [],
+      "items": {
+        "type": "string"
+      }
+    },
+    "haproxy": {
+      "description": "HAProxy configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "replicas",
+        "resourcesPreset"
+      ],
+      "properties": {
+        "replicas": {
+          "description": "Number of HAProxy replicas.",
+          "type": "integer",
+          "default": 2
+        },
+        "resources": {
+          "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.",
+          "type": "object",
+          "default": {},
+          "properties": {
+            "cpu": {
+              "description": "CPU available to each replica.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            },
+            "memory": {
+              "description": "Memory (RAM) available to each replica.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            }
+          }
+        },
+        "resourcesPreset": {
+          "description": "Default sizing preset used when `resources` is omitted.",
+          "type": "string",
+          "default": "nano",
+          "enum": [
+            "nano",
+            "micro",
+            "small",
+            "medium",
+            "large",
+            "xlarge",
+            "2xlarge"
+          ]
+        }
+      }
+    },
+    "nginx": {
+      "description": "Nginx configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "replicas",
+        "resourcesPreset"
+      ],
+      "properties": {
+        "replicas": {
+          "description": "Number of Nginx replicas.",
+          "type": "integer",
+          "default": 2
+        },
+        "resources": {
+          "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.",
+          "type": "object",
+          "default": {},
+          "properties": {
+            "cpu": {
+              "description": "CPU available to each replica.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            },
+            "memory": {
+              "description": "Memory (RAM) available to each replica.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            }
+          }
+        },
+        "resourcesPreset": {
+          "description": "Default sizing preset used when `resources` is omitted.",
+          "type": "string",
+          "default": "nano",
+          "enum": [
+            "nano",
+            "micro",
+            "small",
+            "medium",
+            "large",
+            "xlarge",
+            "2xlarge"
+          ]
+        }
+      }
     }
+  }
 }
diff --git a/packages/apps/http-cache/values.yaml b/packages/apps/http-cache/values.yaml
index d6d05b06..d243bf9c 100644
--- a/packages/apps/http-cache/values.yaml
+++ b/packages/apps/http-cache/values.yaml
@@ -1,39 +1,22 @@
-
-## @section Common parameters
-
-## @param external Enable external access from outside the cluster
-## @param size Persistent Volume size
-## @param storageClass StorageClass used to store the data
-## @param haproxy.replicas Number of HAProxy replicas
-## @param nginx.replicas Number of Nginx replicas
 ##
-external: false
+## @section Common parameters
+##
+
+## @param {quantity} size - Persistent Volume Claim size available for application data.
 size: 10Gi
+
+## @param {string} storageClass - StorageClass used to store the data.
 storageClass: ""
-haproxy:
-  replicas: 2
-  ## @param haproxy.resources Explicit CPU and memory configuration for each HAProxy replica. When left empty, the preset defined in `resourcesPreset` is applied.
-  resources: {}
-  # resources:
-  #   cpu: 4000m
-  #   memory: 4Gi
 
-  ## @param haproxy.resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.
-  resourcesPreset: "nano"
-nginx:
-  replicas: 2
-  ## @param nginx.resources Explicit CPU and memory configuration for each nginx replica. When left empty, the preset defined in `resourcesPreset` is applied.
-  resources: {}
-  # resources:
-  #   cpu: 4000m
-  #   memory: 4Gi
+## @param {bool} external - Enable external access from outside the cluster.
+external: false
 
-  ## @param nginx.resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.
-  resourcesPreset: "nano"
+##
+## @section Application-specific parameters
+##
 
-## @section Configuration parameters
-
-## @param endpoints Endpoints configuration
+## @param {[]string} endpoints - Endpoints configuration, as a list of .
+endpoints: []
 ## Example:
 ## endpoints:
 ##   - 10.100.3.1:80
@@ -42,5 +25,46 @@ nginx:
 ##   - 10.100.3.12:80
 ##   - 10.100.3.3:80
 ##   - 10.100.3.13:80
+
 ##
-endpoints: []
+## @section HAProxy parameters
+##
+
+## @typedef {struct} Resources - Explicit CPU and memory configuration for each replica.
+## @field {quantity} [cpu] - CPU available to each replica.
+## @field {quantity} [memory] - Memory (RAM) available to each replica.
+
+## @enum {string} ResourcesPreset - Default sizing preset.
+## @value nano
+## @value micro
+## @value small
+## @value medium
+## @value large
+## @value xlarge
+## @value 2xlarge
+
+## @typedef {struct} HAProxy - HAProxy configuration.
+## @field {int} replicas - Number of HAProxy replicas.
+## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.
+## @field {ResourcesPreset} resourcesPreset - Default sizing preset used when `resources` is omitted.
+
+## @param {HAProxy} haproxy - HAProxy configuration.
+haproxy:
+  replicas: 2
+  resources: {}
+  resourcesPreset: "nano"
+
+##
+## @section Nginx parameters
+##
+
+## @typedef {struct} Nginx - Nginx configuration.
+## @field {int} replicas - Number of Nginx replicas.
+## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.
+## @field {ResourcesPreset} resourcesPreset - Default sizing preset used when `resources` is omitted.
+
+## @param {Nginx} nginx - Nginx configuration.
+nginx:
+  replicas: 2
+  resources: {}
+  resourcesPreset: "nano"
diff --git a/packages/apps/kafka/Chart.yaml b/packages/apps/kafka/Chart.yaml
index f609f238..6136729b 100644
--- a/packages/apps/kafka/Chart.yaml
+++ b/packages/apps/kafka/Chart.yaml
@@ -2,24 +2,6 @@ apiVersion: v2
 name: kafka
 description: Managed Kafka service
 icon: /logos/kafka.svg
-
-# 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: 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.8.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.
+version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process
 appVersion: "3.7.0"
diff --git a/packages/apps/kafka/Makefile b/packages/apps/kafka/Makefile
index e3d2547e..c1084e86 100644
--- a/packages/apps/kafka/Makefile
+++ b/packages/apps/kafka/Makefile
@@ -1,6 +1,6 @@
-include ../../../scripts/package.mk
+include ../../../hack/package.mk
+PRESET_ENUM := ["nano","micro","small","medium","large","xlarge","2xlarge"]
 
 generate:
-	readme-generator -v values.yaml -s values.schema.json -r README.md
-	yq -i -o json --indent 4 '.properties.kafka.properties.resourcesPreset.enum = ["none", "nano", "micro", "small", "medium", "large", "xlarge", "2xlarge"]' values.schema.json
-	yq -i -o json --indent 4 '.properties.zookeeper.properties.resourcesPreset.enum = ["none", "nano", "micro", "small", "medium", "large", "xlarge", "2xlarge"]' values.schema.json
+	cozyvalues-gen -m 'kafka' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/kafka/types.go
+	../../../hack/update-crd.sh
diff --git a/packages/apps/kafka/README.md b/packages/apps/kafka/README.md
index 15eca05f..35251d6f 100644
--- a/packages/apps/kafka/README.md
+++ b/packages/apps/kafka/README.md
@@ -4,25 +4,49 @@
 
 ### Common parameters
 
-| Name                        | Description                                                                                                                            | Value   |
-| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------- |
-| `external`                  | Enable external access from outside the cluster                                                                                        | `false` |
-| `kafka.size`                | Persistent Volume size for Kafka                                                                                                       | `10Gi`  |
-| `kafka.replicas`            | Number of Kafka replicas                                                                                                               | `3`     |
-| `kafka.storageClass`        | StorageClass used to store the Kafka data                                                                                              | `""`    |
-| `zookeeper.size`            | Persistent Volume size for ZooKeeper                                                                                                   | `5Gi`   |
-| `zookeeper.replicas`        | Number of ZooKeeper replicas                                                                                                           | `3`     |
-| `zookeeper.storageClass`    | StorageClass used to store the ZooKeeper data                                                                                          | `""`    |
-| `kafka.resources`           | Explicit CPU and memory configuration for each Kafka replica. When left empty, the preset defined in `resourcesPreset` is applied.     | `{}`    |
-| `kafka.resourcesPreset`     | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.      | `small` |
-| `zookeeper.resources`       | Explicit CPU and memory configuration for each Zookeeper replica. When left empty, the preset defined in `resourcesPreset` is applied. | `{}`    |
-| `zookeeper.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.      | `small` |
+| Name       | Description                                      | Type   | Value   |
+| ---------- | ------------------------------------------------ | ------ | ------- |
+| `external` | Enable external access from outside the cluster. | `bool` | `false` |
 
-### Configuration parameters
 
-| Name     | Description          | Value |
-| -------- | -------------------- | ----- |
-| `topics` | Topics configuration | `[]`  |
+### Application-specific parameters
+
+| Name                   | Description           | Type       | Value |
+| ---------------------- | --------------------- | ---------- | ----- |
+| `topics`               | Topics configuration. | `[]object` | `[]`  |
+| `topics[i].name`       | Topic name.           | `string`   | `""`  |
+| `topics[i].partitions` | Number of partitions. | `int`      | `0`   |
+| `topics[i].replicas`   | Number of replicas.   | `int`      | `0`   |
+| `topics[i].config`     | Topic configuration.  | `object`   | `{}`  |
+
+
+### Kafka configuration
+
+| Name                     | Description                                                                                              | Type       | Value   |
+| ------------------------ | -------------------------------------------------------------------------------------------------------- | ---------- | ------- |
+| `kafka`                  | Kafka configuration.                                                                                     | `object`   | `{}`    |
+| `kafka.replicas`         | Number of Kafka replicas.                                                                                | `int`      | `3`     |
+| `kafka.resources`        | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object`   | `{}`    |
+| `kafka.resources.cpu`    | CPU available to each replica.                                                                           | `quantity` | `""`    |
+| `kafka.resources.memory` | Memory (RAM) available to each replica.                                                                  | `quantity` | `""`    |
+| `kafka.resourcesPreset`  | Default sizing preset used when `resources` is omitted.                                                  | `string`   | `small` |
+| `kafka.size`             | Persistent Volume size for Kafka.                                                                        | `quantity` | `10Gi`  |
+| `kafka.storageClass`     | StorageClass used to store the Kafka data.                                                               | `string`   | `""`    |
+
+
+### ZooKeeper configuration
+
+| Name                         | Description                                                                                              | Type       | Value   |
+| ---------------------------- | -------------------------------------------------------------------------------------------------------- | ---------- | ------- |
+| `zookeeper`                  | ZooKeeper configuration.                                                                                 | `object`   | `{}`    |
+| `zookeeper.replicas`         | Number of ZooKeeper replicas.                                                                            | `int`      | `3`     |
+| `zookeeper.resources`        | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object`   | `{}`    |
+| `zookeeper.resources.cpu`    | CPU available to each replica.                                                                           | `quantity` | `""`    |
+| `zookeeper.resources.memory` | Memory (RAM) available to each replica.                                                                  | `quantity` | `""`    |
+| `zookeeper.resourcesPreset`  | Default sizing preset used when `resources` is omitted.                                                  | `string`   | `small` |
+| `zookeeper.size`             | Persistent Volume size for ZooKeeper.                                                                    | `quantity` | `5Gi`   |
+| `zookeeper.storageClass`     | StorageClass used to store the ZooKeeper data.                                                           | `string`   | `""`    |
+
 
 ## Parameter examples and reference
 
diff --git a/packages/apps/kafka/templates/workloadmonitor.yaml b/packages/apps/kafka/templates/workloadmonitor.yaml
index 4b161b04..c31eb425 100644
--- a/packages/apps/kafka/templates/workloadmonitor.yaml
+++ b/packages/apps/kafka/templates/workloadmonitor.yaml
@@ -3,6 +3,8 @@ apiVersion: cozystack.io/v1alpha1
 kind: WorkloadMonitor
 metadata:
   name: {{ $.Release.Name }}
+  labels:
+    workloads.cozystack.io/resource-preset: {{ .Values.kafka.resourcesPreset | quote }}
 spec:
   replicas: {{ .Values.replicas }}
   minReplicas: 1
@@ -19,6 +21,8 @@ apiVersion: cozystack.io/v1alpha1
 kind: WorkloadMonitor
 metadata:
   name: {{ $.Release.Name }}-zookeeper
+  labels:
+    workloads.cozystack.io/resource-preset: {{ .Values.zookeeper.resourcesPreset | quote }}
 spec:
   replicas: {{ .Values.replicas }}
   minReplicas: 1
diff --git a/packages/apps/kafka/values.schema.json b/packages/apps/kafka/values.schema.json
index 64fe7cf7..e3b6db12 100644
--- a/packages/apps/kafka/values.schema.json
+++ b/packages/apps/kafka/values.schema.json
@@ -1,97 +1,212 @@
 {
-    "title": "Chart Values",
-    "type": "object",
-    "properties": {
-        "external": {
-            "type": "boolean",
-            "description": "Enable external access from outside the cluster",
-            "default": false
-        },
-        "kafka": {
+  "title": "Chart Values",
+  "type": "object",
+  "properties": {
+    "external": {
+      "description": "Enable external access from outside the cluster.",
+      "type": "boolean",
+      "default": false
+    },
+    "topics": {
+      "description": "Topics configuration.",
+      "type": "array",
+      "default": [],
+      "items": {
+        "type": "object",
+        "required": [
+          "config",
+          "name",
+          "partitions",
+          "replicas"
+        ],
+        "properties": {
+          "config": {
+            "description": "Topic configuration.",
             "type": "object",
-            "properties": {
-                "size": {
-                    "type": "string",
-                    "description": "Persistent Volume size for Kafka",
-                    "default": "10Gi"
-                },
-                "replicas": {
-                    "type": "number",
-                    "description": "Number of Kafka replicas",
-                    "default": 3
-                },
-                "storageClass": {
-                    "type": "string",
-                    "description": "StorageClass used to store the Kafka data",
-                    "default": ""
-                },
-                "resources": {
-                    "type": "object",
-                    "description": "Explicit CPU and memory configuration for each Kafka replica. When left empty, the preset defined in `resourcesPreset` is applied.",
-                    "default": {}
-                },
-                "resourcesPreset": {
-                    "type": "string",
-                    "description": "Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.",
-                    "default": "small",
-                    "enum": [
-                        "none",
-                        "nano",
-                        "micro",
-                        "small",
-                        "medium",
-                        "large",
-                        "xlarge",
-                        "2xlarge"
-                    ]
-                }
-            }
-        },
-        "zookeeper": {
-            "type": "object",
-            "properties": {
-                "size": {
-                    "type": "string",
-                    "description": "Persistent Volume size for ZooKeeper",
-                    "default": "5Gi"
-                },
-                "replicas": {
-                    "type": "number",
-                    "description": "Number of ZooKeeper replicas",
-                    "default": 3
-                },
-                "storageClass": {
-                    "type": "string",
-                    "description": "StorageClass used to store the ZooKeeper data",
-                    "default": ""
-                },
-                "resources": {
-                    "type": "object",
-                    "description": "Explicit CPU and memory configuration for each Zookeeper replica. When left empty, the preset defined in `resourcesPreset` is applied.",
-                    "default": {}
-                },
-                "resourcesPreset": {
-                    "type": "string",
-                    "description": "Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.",
-                    "default": "small",
-                    "enum": [
-                        "none",
-                        "nano",
-                        "micro",
-                        "small",
-                        "medium",
-                        "large",
-                        "xlarge",
-                        "2xlarge"
-                    ]
-                }
-            }
-        },
-        "topics": {
-            "type": "array",
-            "description": "Topics configuration",
-            "default": [],
-            "items": {}
+            "x-kubernetes-preserve-unknown-fields": true
+          },
+          "name": {
+            "description": "Topic name.",
+            "type": "string"
+          },
+          "partitions": {
+            "description": "Number of partitions.",
+            "type": "integer"
+          },
+          "replicas": {
+            "description": "Number of replicas.",
+            "type": "integer"
+          }
         }
+      }
+    },
+    "kafka": {
+      "description": "Kafka configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "replicas",
+        "resourcesPreset",
+        "size",
+        "storageClass"
+      ],
+      "properties": {
+        "replicas": {
+          "description": "Number of Kafka replicas.",
+          "type": "integer",
+          "default": 3
+        },
+        "resources": {
+          "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.",
+          "type": "object",
+          "default": {},
+          "properties": {
+            "cpu": {
+              "description": "CPU available to each replica.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            },
+            "memory": {
+              "description": "Memory (RAM) available to each replica.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            }
+          }
+        },
+        "resourcesPreset": {
+          "description": "Default sizing preset used when `resources` is omitted.",
+          "type": "string",
+          "default": "small",
+          "enum": [
+            "nano",
+            "micro",
+            "small",
+            "medium",
+            "large",
+            "xlarge",
+            "2xlarge"
+          ]
+        },
+        "size": {
+          "description": "Persistent Volume size for Kafka.",
+          "default": "10Gi",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
+        },
+        "storageClass": {
+          "description": "StorageClass used to store the Kafka data.",
+          "type": "string",
+          "default": ""
+        }
+      }
+    },
+    "zookeeper": {
+      "description": "ZooKeeper configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "replicas",
+        "resourcesPreset",
+        "size",
+        "storageClass"
+      ],
+      "properties": {
+        "replicas": {
+          "description": "Number of ZooKeeper replicas.",
+          "type": "integer",
+          "default": 3
+        },
+        "resources": {
+          "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.",
+          "type": "object",
+          "default": {},
+          "properties": {
+            "cpu": {
+              "description": "CPU available to each replica.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            },
+            "memory": {
+              "description": "Memory (RAM) available to each replica.",
+              "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+              "anyOf": [
+                {
+                  "type": "integer"
+                },
+                {
+                  "type": "string"
+                }
+              ],
+              "x-kubernetes-int-or-string": true
+            }
+          }
+        },
+        "resourcesPreset": {
+          "description": "Default sizing preset used when `resources` is omitted.",
+          "type": "string",
+          "default": "small",
+          "enum": [
+            "nano",
+            "micro",
+            "small",
+            "medium",
+            "large",
+            "xlarge",
+            "2xlarge"
+          ]
+        },
+        "size": {
+          "description": "Persistent Volume size for ZooKeeper.",
+          "default": "5Gi",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
+        },
+        "storageClass": {
+          "description": "StorageClass used to store the ZooKeeper data.",
+          "type": "string",
+          "default": ""
+        }
+      }
     }
+  }
 }
diff --git a/packages/apps/kafka/values.yaml b/packages/apps/kafka/values.yaml
index e8204655..9c232262 100644
--- a/packages/apps/kafka/values.yaml
+++ b/packages/apps/kafka/values.yaml
@@ -1,42 +1,22 @@
-
-## @section Common parameters
-
-## @param external Enable external access from outside the cluster
-## @param kafka.size Persistent Volume size for Kafka
-## @param kafka.replicas Number of Kafka replicas
-## @param kafka.storageClass StorageClass used to store the Kafka data
-## @param zookeeper.size Persistent Volume size for ZooKeeper
-## @param zookeeper.replicas Number of ZooKeeper replicas
-## @param zookeeper.storageClass StorageClass used to store the ZooKeeper data
 ##
+## @section Common parameters
+##
+
+## @param {bool} external - Enable external access from outside the cluster.
 external: false
-kafka:
-  size: 10Gi
-  replicas: 3
-  storageClass: ""
-  ## @param kafka.resources Explicit CPU and memory configuration for each Kafka replica. When left empty, the preset defined in `resourcesPreset` is applied.
-  resources: {}
-  # resources:
-  #   cpu: 4000m
-  #   memory: 4Gi
-  ## @param kafka.resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.
-  resourcesPreset: "small"
 
-zookeeper:
-  size: 5Gi
-  replicas: 3
-  storageClass: ""
-  ## @param zookeeper.resources Explicit CPU and memory configuration for each Zookeeper replica. When left empty, the preset defined in `resourcesPreset` is applied.
-  resources: {}
-  # resources:
-  #   cpu: 4000m
-  #   memory: 4Gi
-  ## @param zookeeper.resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.
-  resourcesPreset: "small"
+##
+## @section Application-specific parameters
+##
 
-## @section Configuration parameters
+## @typedef {struct} Topic - Topic configuration.
+## @field {string} name - Topic name.
+## @field {int} partitions - Number of partitions.
+## @field {int} replicas - Number of replicas.
+## @field {object} config - Topic configuration.
 
-## @param topics Topics configuration
+## @param {[]Topic} topics - Topics configuration.
+topics: []
 ## Example:
 ## topics:
 ##   - name: Results
@@ -52,5 +32,54 @@ zookeeper:
 ##       min.insync.replicas: 2
 ##     partitions: 1
 ##     replicas: 3
+
 ##
-topics: []
+## @section Kafka configuration
+##
+
+## @typedef {struct} Resources - Explicit CPU and memory configuration for each replica.
+## @field {quantity} [cpu] - CPU available to each replica.
+## @field {quantity} [memory] - Memory (RAM) available to each replica.
+
+## @enum {string} ResourcesPreset - Default sizing preset.
+## @value nano
+## @value micro
+## @value small
+## @value medium
+## @value large
+## @value xlarge
+## @value 2xlarge
+
+## @typedef {struct} Kafka - Kafka configuration.
+## @field {int} replicas - Number of Kafka replicas.
+## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.
+## @field {ResourcesPreset} resourcesPreset - Default sizing preset used when `resources` is omitted.
+## @field {quantity} size - Persistent Volume size for Kafka.
+## @field {string} storageClass - StorageClass used to store the Kafka data.
+
+## @param {Kafka} kafka - Kafka configuration.
+kafka:
+  replicas: 3
+  resources: {}
+  resourcesPreset: "small"
+  size: 10Gi
+  storageClass: ""
+
+##
+## @section ZooKeeper configuration
+##
+
+## @typedef {struct} ZooKeeper - ZooKeeper configuration.
+## @field {int} replicas - Number of ZooKeeper replicas.
+## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.
+## @field {ResourcesPreset} resourcesPreset - Default sizing preset used when `resources` is omitted.
+## @field {quantity} size - Persistent Volume size for ZooKeeper.
+## @field {string} storageClass - StorageClass used to store the ZooKeeper data.
+
+## @param {ZooKeeper} zookeeper - ZooKeeper configuration.
+zookeeper:
+  replicas: 3
+  resources: {}
+  resourcesPreset: "small"
+  size: 5Gi
+  storageClass: ""
diff --git a/packages/apps/kubernetes/.helmignore b/packages/apps/kubernetes/.helmignore
index 1ea0ae84..cdada667 100644
--- a/packages/apps/kubernetes/.helmignore
+++ b/packages/apps/kubernetes/.helmignore
@@ -1,3 +1,5 @@
 .helmignore
 /logos
 /Makefile
+/hack
+/images/*/*
diff --git a/packages/apps/kubernetes/Chart.yaml b/packages/apps/kubernetes/Chart.yaml
index c3259ba3..5fc52ff3 100644
--- a/packages/apps/kubernetes/Chart.yaml
+++ b/packages/apps/kubernetes/Chart.yaml
@@ -2,24 +2,6 @@ apiVersion: v2
 name: kubernetes
 description: Managed Kubernetes service
 icon: /logos/kubernetes.svg
-
-# 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: 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.25.2
-
-# 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.32.4
+version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process
+appVersion: 1.32.6
diff --git a/packages/apps/kubernetes/Makefile b/packages/apps/kubernetes/Makefile
index 82ca4e8b..4fea42ef 100644
--- a/packages/apps/kubernetes/Makefile
+++ b/packages/apps/kubernetes/Makefile
@@ -1,67 +1,57 @@
-KUBERNETES_VERSION = v1.32
+KUBERNETES_VERSIONS = $(shell awk -F'"' '{print $$2}' files/versions.yaml)
 KUBERNETES_PKG_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml)
 
-include ../../../scripts/common-envs.mk
-include ../../../scripts/package.mk
+include ../../../hack/common-envs.mk
+include ../../../hack/package.mk
+
+test:
+	helm unittest .
 
 generate:
-	readme-generator -v values.yaml -s values.schema.json -r README.md
-	yq -o json -i '.properties.addons.properties.ingressNginx.properties.exposeMethod.enum = ["Proxied","LoadBalancer"]' values.schema.json
-	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
+	cozyvalues-gen -m 'kubernetes' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/kubernetes/types.go
+	../../../hack/update-crd.sh
+
+update:
+	hack/update-versions.sh
+	make generate
 
 image: image-ubuntu-container-disk image-kubevirt-cloud-provider image-kubevirt-csi-driver image-cluster-autoscaler
 
 image-ubuntu-container-disk:
-	docker buildx build images/ubuntu-container-disk \
-		--provenance false \
-		--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,$(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
+	$(foreach ver,$(KUBERNETES_VERSIONS), \
+		docker buildx build images/ubuntu-container-disk \
+			--build-arg KUBERNETES_VERSION=$(ver) \
+			--tag $(REGISTRY)/ubuntu-container-disk:$(call settag,$(ver)) \
+			--tag $(REGISTRY)/ubuntu-container-disk:$(call settag,$(ver)-$(TAG)) \
+			--cache-from type=registry,ref=$(REGISTRY)/ubuntu-container-disk:$(call settag,$(ver)) \
+			--cache-to type=inline \
+			--metadata-file images/ubuntu-container-disk-$(ver).json \
+			$(BUILDX_ARGS) && \
+		echo "$(REGISTRY)/ubuntu-container-disk:$(call settag,$(ver))@$$(yq e '."containerimage.digest"' images/ubuntu-container-disk-$(ver).json -o json -r)" \
+			> images/ubuntu-container-disk-$(ver).tag && \
+		rm -f images/ubuntu-container-disk-$(ver).json; \
+	)
 
 image-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 \
 		--cache-to type=inline \
 		--metadata-file images/kubevirt-cloud-provider.json \
-		--push=$(PUSH) \
-		--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \
-		--load=$(LOAD)
+		$(BUILDX_ARGS)
 	echo "$(REGISTRY)/kubevirt-cloud-provider:$(call settag,$(KUBERNETES_PKG_TAG))@$$(yq e '."containerimage.digest"' images/kubevirt-cloud-provider.json -o json -r)" \
 		> images/kubevirt-cloud-provider.tag
 	rm -f images/kubevirt-cloud-provider.json
 
 image-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 \
 		--cache-to type=inline \
 		--metadata-file images/kubevirt-csi-driver.json \
-		--push=$(PUSH) \
-		--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \
-		--load=$(LOAD)
+		$(BUILDX_ARGS)
 	echo "$(REGISTRY)/kubevirt-csi-driver:$(call settag,$(KUBERNETES_PKG_TAG))@$$(yq e '."containerimage.digest"' images/kubevirt-csi-driver.json -o json -r)" \
 		> images/kubevirt-csi-driver.tag
 	IMAGE=$$(cat images/kubevirt-csi-driver.tag) \
@@ -71,17 +61,13 @@ image-kubevirt-csi-driver:
 
 image-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 \
 		--cache-to type=inline \
 		--metadata-file images/cluster-autoscaler.json \
-		--push=$(PUSH) \
-		--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \
-		--load=$(LOAD)
+		$(BUILDX_ARGS)
 	echo "$(REGISTRY)/cluster-autoscaler:$(call settag,$(KUBERNETES_PKG_TAG))@$$(yq e '."containerimage.digest"' images/cluster-autoscaler.json -o json -r)" \
 		> images/cluster-autoscaler.tag
 	rm -f images/cluster-autoscaler.json
+
diff --git a/packages/apps/kubernetes/README.md b/packages/apps/kubernetes/README.md
index 7a936b83..bed1117a 100644
--- a/packages/apps/kubernetes/README.md
+++ b/packages/apps/kubernetes/README.md
@@ -11,6 +11,9 @@ Tenant clusters are fully separated from the management cluster and are intended
 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.
 
+Kubernetes version in tenant clusters is independent of Kubernetes in the management cluster.
+Users can select the latest patch versions from 1.28 to 1.33.
+
 ## Why Use a Managed Kubernetes Cluster?
 
 Kubernetes has emerged as the industry standard, providing a unified and accessible API, primarily utilizing YAML for configuration.
@@ -81,47 +84,97 @@ See the reference for components utilized in this service:
 
 ### Common Parameters
 
-| Name                    | Description                                                                                                       | Value        |
-| ----------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------ |
-| `host`                  | Hostname used to access the Kubernetes cluster externally. Defaults to `.` when empty. | `""`         |
-| `controlPlane.replicas` | Number of replicas for Kubernetes control-plane components.                                                       | `2`          |
-| `storageClass`          | StorageClass used to store user data.                                                                             | `replicated` |
-| `nodeGroups`            | nodeGroups configuration                                                                                          | `{}`         |
+| Name           | Description                          | Type     | Value        |
+| -------------- | ------------------------------------ | -------- | ------------ |
+| `storageClass` | StorageClass used to store the data. | `string` | `replicated` |
+
+
+### Application-specific Parameters
+
+| Name                                | Description                                                                                    | Type                | Value       |
+| ----------------------------------- | ---------------------------------------------------------------------------------------------- | ------------------- | ----------- |
+| `nodeGroups`                        | Worker nodes configuration map.                                                                | `map[string]object` | `{...}`     |
+| `nodeGroups[name].minReplicas`      | Minimum number of replicas.                                                                    | `int`               | `0`         |
+| `nodeGroups[name].maxReplicas`      | Maximum number of replicas.                                                                    | `int`               | `10`        |
+| `nodeGroups[name].instanceType`     | Virtual machine instance type.                                                                 | `string`            | `u1.medium` |
+| `nodeGroups[name].ephemeralStorage` | Ephemeral storage size.                                                                        | `quantity`          | `20Gi`      |
+| `nodeGroups[name].roles`            | List of node roles.                                                                            | `[]string`          | `[]`        |
+| `nodeGroups[name].resources`        | CPU and memory resources for each worker node.                                                 | `object`            | `{}`        |
+| `nodeGroups[name].resources.cpu`    | CPU available.                                                                                 | `quantity`          | `""`        |
+| `nodeGroups[name].resources.memory` | Memory (RAM) available.                                                                        | `quantity`          | `""`        |
+| `nodeGroups[name].gpus`             | List of GPUs to attach (NVIDIA driver requires at least 4 GiB RAM).                            | `[]object`          | `[]`        |
+| `nodeGroups[name].gpus[i].name`     | Name of GPU, such as "nvidia.com/AD102GL_L40S".                                                | `string`            | `""`        |
+| `version`                           | Kubernetes major.minor version to deploy                                                       | `string`            | `v1.35`     |
+| `host`                              | External hostname for Kubernetes cluster. Defaults to `.` if empty. | `string`            | `""`        |
+
 
 ### 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.exposeMethod`            | Method to expose the Ingress-NGINX controller. (allowed values: Proxied, LoadBalancer)                                                                                            | `Proxied` |
-| `addons.ingressNginx.hosts`                   | List of domain names that the parent cluster should route to this tenant cluster. Taken into account only when `exposeMethod` is set to `Proxied`.                                | `[]`      |
-| `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                                                                                                                                                         | `{}`      |
-| `addons.velero.enabled`                       | Enable velero for backup and restore k8s cluster.                                                                                                                                 | `false`   |
-| `addons.velero.valuesOverride`                | Custom values to override                                                                                                                                                         | `{}`      |
+| Name                                          | Description                                                                 | Type       | Value     |
+| --------------------------------------------- | --------------------------------------------------------------------------- | ---------- | --------- |
+| `addons`                                      | Cluster addons configuration.                                               | `object`   | `{}`      |
+| `addons.certManager`                          | Cert-manager addon.                                                         | `object`   | `{}`      |
+| `addons.certManager.enabled`                  | Enable cert-manager.                                                        | `bool`     | `false`   |
+| `addons.certManager.valuesOverride`           | Custom Helm values overrides.                                               | `object`   | `{}`      |
+| `addons.cilium`                               | Cilium CNI plugin.                                                          | `object`   | `{}`      |
+| `addons.cilium.valuesOverride`                | Custom Helm values overrides.                                               | `object`   | `{}`      |
+| `addons.gatewayAPI`                           | Gateway API addon.                                                          | `object`   | `{}`      |
+| `addons.gatewayAPI.enabled`                   | Enable Gateway API.                                                         | `bool`     | `false`   |
+| `addons.ingressNginx`                         | Ingress-NGINX controller.                                                   | `object`   | `{}`      |
+| `addons.ingressNginx.enabled`                 | Enable the controller (requires nodes labeled `ingress-nginx`).             | `bool`     | `false`   |
+| `addons.ingressNginx.exposeMethod`            | Method to expose the controller. Allowed values: `Proxied`, `LoadBalancer`. | `string`   | `Proxied` |
+| `addons.ingressNginx.hosts`                   | Domains routed to this tenant cluster when `exposeMethod` is `Proxied`.     | `[]string` | `[]`      |
+| `addons.ingressNginx.valuesOverride`          | Custom Helm values overrides.                                               | `object`   | `{}`      |
+| `addons.gpuOperator`                          | NVIDIA GPU Operator.                                                        | `object`   | `{}`      |
+| `addons.gpuOperator.enabled`                  | Enable GPU Operator.                                                        | `bool`     | `false`   |
+| `addons.gpuOperator.valuesOverride`           | Custom Helm values overrides.                                               | `object`   | `{}`      |
+| `addons.hami`                                 | HAMi GPU virtualization middleware.                                         | `object`   | `{}`      |
+| `addons.hami.enabled`                         | Enable HAMi (requires GPU Operator).                                        | `bool`     | `false`   |
+| `addons.hami.valuesOverride`                  | Custom Helm values overrides.                                               | `object`   | `{}`      |
+| `addons.fluxcd`                               | FluxCD GitOps operator.                                                     | `object`   | `{}`      |
+| `addons.fluxcd.enabled`                       | Enable FluxCD.                                                              | `bool`     | `false`   |
+| `addons.fluxcd.valuesOverride`                | Custom Helm values overrides.                                               | `object`   | `{}`      |
+| `addons.monitoringAgents`                     | Monitoring agents.                                                          | `object`   | `{}`      |
+| `addons.monitoringAgents.enabled`             | Enable monitoring agents.                                                   | `bool`     | `false`   |
+| `addons.monitoringAgents.valuesOverride`      | Custom Helm values overrides.                                               | `object`   | `{}`      |
+| `addons.verticalPodAutoscaler`                | Vertical Pod Autoscaler.                                                    | `object`   | `{}`      |
+| `addons.verticalPodAutoscaler.valuesOverride` | Custom Helm values overrides.                                               | `object`   | `{}`      |
+| `addons.velero`                               | Velero backup/restore addon.                                                | `object`   | `{}`      |
+| `addons.velero.enabled`                       | Enable Velero.                                                              | `bool`     | `false`   |
+| `addons.velero.valuesOverride`                | Custom Helm values overrides.                                               | `object`   | `{}`      |
+| `addons.coredns`                              | CoreDNS addon.                                                              | `object`   | `{}`      |
+| `addons.coredns.valuesOverride`               | Custom Helm values overrides.                                               | `object`   | `{}`      |
+
 
 ### Kubernetes Control Plane Configuration
 
-| Name                                               | Description                                                                                                                            | Value    |
-| -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -------- |
-| `controlPlane.apiServer.resources`                 | Explicit CPU and memory configuration for the API Server. When left empty, the preset defined in `resourcesPreset` is applied.         | `{}`     |
-| `controlPlane.apiServer.resourcesPreset`           | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.      | `medium` |
-| `controlPlane.controllerManager.resources`         | Explicit CPU and memory configuration for the Controller Manager. When left empty, the preset defined in `resourcesPreset` is applied. | `{}`     |
-| `controlPlane.controllerManager.resourcesPreset`   | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.      | `micro`  |
-| `controlPlane.scheduler.resources`                 | Explicit CPU and memory configuration for the Scheduler. When left empty, the preset defined in `resourcesPreset` is applied.          | `{}`     |
-| `controlPlane.scheduler.resourcesPreset`           | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.      | `micro`  |
-| `controlPlane.konnectivity.server.resources`       | Explicit CPU and memory configuration for Konnectivity. When left empty, the preset defined in `resourcesPreset` is applied.           | `{}`     |
-| `controlPlane.konnectivity.server.resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.      | `micro`  |
+| Name                                                | Description                                                                                   | Type       | Value   |
+| --------------------------------------------------- | --------------------------------------------------------------------------------------------- | ---------- | ------- |
+| `controlPlane`                                      | Kubernetes control-plane configuration.                                                       | `object`   | `{}`    |
+| `controlPlane.replicas`                             | Number of control-plane replicas.                                                             | `int`      | `2`     |
+| `controlPlane.apiServer`                            | API Server configuration.                                                                     | `object`   | `{}`    |
+| `controlPlane.apiServer.resources`                  | CPU and memory resources for API Server.                                                      | `object`   | `{}`    |
+| `controlPlane.apiServer.resources.cpu`              | CPU available.                                                                                | `quantity` | `""`    |
+| `controlPlane.apiServer.resources.memory`           | Memory (RAM) available.                                                                       | `quantity` | `""`    |
+| `controlPlane.apiServer.resourcesPreset`            | Preset if `resources` omitted.                                                                | `string`   | `large` |
+| `controlPlane.controllerManager`                    | Controller Manager configuration.                                                             | `object`   | `{}`    |
+| `controlPlane.controllerManager.resources`          | CPU and memory resources for Controller Manager.                                              | `object`   | `{}`    |
+| `controlPlane.controllerManager.resources.cpu`      | CPU available.                                                                                | `quantity` | `""`    |
+| `controlPlane.controllerManager.resources.memory`   | Memory (RAM) available.                                                                       | `quantity` | `""`    |
+| `controlPlane.controllerManager.resourcesPreset`    | Preset if `resources` omitted.                                                                | `string`   | `micro` |
+| `controlPlane.scheduler`                            | Scheduler configuration.                                                                      | `object`   | `{}`    |
+| `controlPlane.scheduler.resources`                  | CPU and memory resources for Scheduler.                                                       | `object`   | `{}`    |
+| `controlPlane.scheduler.resources.cpu`              | CPU available.                                                                                | `quantity` | `""`    |
+| `controlPlane.scheduler.resources.memory`           | Memory (RAM) available.                                                                       | `quantity` | `""`    |
+| `controlPlane.scheduler.resourcesPreset`            | Preset if `resources` omitted.                                                                | `string`   | `micro` |
+| `controlPlane.konnectivity`                         | Konnectivity configuration.                                                                   | `object`   | `{}`    |
+| `controlPlane.konnectivity.server`                  | Konnectivity Server configuration.                                                            | `object`   | `{}`    |
+| `controlPlane.konnectivity.server.resources`        | CPU and memory resources for Konnectivity.                                                    | `object`   | `{}`    |
+| `controlPlane.konnectivity.server.resources.cpu`    | CPU available.                                                                                | `quantity` | `""`    |
+| `controlPlane.konnectivity.server.resources.memory` | Memory (RAM) available.                                                                       | `quantity` | `""`    |
+| `controlPlane.konnectivity.server.resourcesPreset`  | Preset if `resources` omitted.                                                                | `string`   | `micro` |
+| `images`                                            | Optional image overrides for air-gapped or rate-limited registries.                           | `object`   | `{}`    |
+| `images.waitForKubeconfig`                          | Image used by the wait-for-kubeconfig init container. Empty falls back to images/busybox.tag. | `string`   | `""`    |
 
 
 ## Parameter examples and reference
diff --git a/packages/apps/kubernetes/files/konnectivity-versions.yaml b/packages/apps/kubernetes/files/konnectivity-versions.yaml
new file mode 100644
index 00000000..09ef4fa7
--- /dev/null
+++ b/packages/apps/kubernetes/files/konnectivity-versions.yaml
@@ -0,0 +1,4 @@
+# Konnectivity proxy version overrides per Kubernetes minor version.
+# When empty or absent, Kamaji auto-derives v0.{minor}.0 from the Kubernetes version.
+# Add entries here only when the auto-derived image tag does not exist in the registry.
+"v1.35": "v0.34.0"
diff --git a/packages/apps/kubernetes/files/versions.yaml b/packages/apps/kubernetes/files/versions.yaml
new file mode 100644
index 00000000..58942b97
--- /dev/null
+++ b/packages/apps/kubernetes/files/versions.yaml
@@ -0,0 +1,6 @@
+"v1.35": "v1.35.1"
+"v1.34": "v1.34.4"
+"v1.33": "v1.33.8"
+"v1.32": "v1.32.12"
+"v1.31": "v1.31.14"
+"v1.30": "v1.30.14"
diff --git a/packages/apps/kubernetes/hack/update-versions.sh b/packages/apps/kubernetes/hack/update-versions.sh
new file mode 100755
index 00000000..85c962c5
--- /dev/null
+++ b/packages/apps/kubernetes/hack/update-versions.sh
@@ -0,0 +1,260 @@
+#!/usr/bin/env bash
+
+set -o errexit
+set -o nounset
+set -o pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+KUBERNETES_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
+VALUES_FILE="${KUBERNETES_DIR}/values.yaml"
+VERSIONS_FILE="${KUBERNETES_DIR}/files/versions.yaml"
+MAKEFILE="${KUBERNETES_DIR}/Makefile"
+KAMAJI_DOCKERFILE="${KUBERNETES_DIR}/../../system/kamaji/images/kamaji/Dockerfile"
+
+# Check if skopeo is installed
+if ! command -v skopeo &> /dev/null; then
+    echo "Error: skopeo is not installed. Please install skopeo and try again." >&2
+    exit 1
+fi
+
+# Check if jq is installed
+if ! command -v jq &> /dev/null; then
+    echo "Error: jq is not installed. Please install jq and try again." >&2
+    exit 1
+fi
+
+# Get kamaji version from Dockerfile
+echo "Reading kamaji version from Dockerfile..."
+if [ ! -f "$KAMAJI_DOCKERFILE" ]; then
+    echo "Error: Kamaji Dockerfile not found at $KAMAJI_DOCKERFILE" >&2
+    exit 1
+fi
+
+KAMAJI_VERSION=$(grep "^ARG VERSION=" "$KAMAJI_DOCKERFILE" | cut -d= -f2 | tr -d '"')
+if [ -z "$KAMAJI_VERSION" ]; then
+    echo "Error: Could not extract kamaji version from Dockerfile" >&2
+    exit 1
+fi
+
+echo "Kamaji version: $KAMAJI_VERSION"
+
+# Get Kubernetes version from kamaji repository
+echo "Fetching Kubernetes version from kamaji repository..."
+KUBERNETES_VERSION_FROM_KAMAJI=$(curl -sSL "https://raw.githubusercontent.com/clastix/kamaji/${KAMAJI_VERSION}/internal/upgrade/kubeadm_version.go" | grep "KubeadmVersion" | sed -E 's/.*KubeadmVersion = "([^"]+)".*/\1/')
+
+if [ -z "$KUBERNETES_VERSION_FROM_KAMAJI" ]; then
+    echo "Error: Could not fetch Kubernetes version from kamaji repository" >&2
+    exit 1
+fi
+
+echo "Kubernetes version from kamaji: $KUBERNETES_VERSION_FROM_KAMAJI"
+
+# Extract major.minor version (e.g., "1.33" from "v1.33.0")
+KUBERNETES_MAJOR_MINOR=$(echo "$KUBERNETES_VERSION_FROM_KAMAJI" | sed -E 's/v([0-9]+)\.([0-9]+)\.[0-9]+/\1.\2/')
+KUBERNETES_MAJOR=$(echo "$KUBERNETES_MAJOR_MINOR" | cut -d. -f1)
+KUBERNETES_MINOR=$(echo "$KUBERNETES_MAJOR_MINOR" | cut -d. -f2)
+
+echo "Kubernetes major.minor: $KUBERNETES_MAJOR_MINOR"
+
+# Get available image tags
+echo "Fetching available image tags from registry..."
+AVAILABLE_TAGS=$(skopeo list-tags docker://registry.k8s.io/kube-apiserver | jq -r '.Tags[] | select(test("^v[0-9]+\\.[0-9]+\\.[0-9]+$"))' | sort -V)
+
+if [ -z "$AVAILABLE_TAGS" ]; then
+    echo "Error: Could not fetch available image tags" >&2
+    exit 1
+fi
+
+# Filter out versions higher than KUBERNETES_VERSION_FROM_KAMAJI
+echo "Filtering versions above ${KUBERNETES_VERSION_FROM_KAMAJI}..."
+FILTERED_TAGS=$(echo "$AVAILABLE_TAGS" | while read tag; do
+    if [ -n "$tag" ]; then
+        # Compare tag with KUBERNETES_VERSION_FROM_KAMAJI using version sort
+        # Include tag if it's less than or equal to KUBERNETES_VERSION_FROM_KAMAJI
+        if [ "$(printf '%s\n%s\n' "$tag" "$KUBERNETES_VERSION_FROM_KAMAJI" | sort -V | head -1)" = "$tag" ] || [ "$tag" = "$KUBERNETES_VERSION_FROM_KAMAJI" ]; then
+            echo "$tag"
+        fi
+    fi
+done)
+
+if [ -z "$FILTERED_TAGS" ]; then
+    echo "Error: No versions found after filtering" >&2
+    exit 1
+fi
+
+AVAILABLE_TAGS="$FILTERED_TAGS"
+echo "Filtered to $(echo "$AVAILABLE_TAGS" | wc -l | tr -d ' ') versions"
+
+# Find the latest patch version for the supported major.minor version
+echo "Finding latest patch version for ${KUBERNETES_MAJOR_MINOR}..."
+SUPPORTED_PATCH_TAGS=$(echo "$AVAILABLE_TAGS" | grep "^v${KUBERNETES_MAJOR}\\.${KUBERNETES_MINOR}\\.")
+if [ -z "$SUPPORTED_PATCH_TAGS" ]; then
+    echo "Error: Could not find any patch versions for ${KUBERNETES_MAJOR_MINOR}" >&2
+    exit 1
+fi
+KUBERNETES_VERSION=$(echo "$SUPPORTED_PATCH_TAGS" | tail -n1)
+echo "Using latest patch version: $KUBERNETES_VERSION"
+
+# Build versions map: major.minor -> latest patch version
+# First, collect all unique major.minor versions from available tags
+echo "Collecting all available major.minor versions..."
+ALL_MAJOR_MINOR_VERSIONS=$(echo "$AVAILABLE_TAGS" | sed -E 's/v([0-9]+)\.([0-9]+)\.[0-9]+/v\1.\2/' | sort -V -u)
+
+# Find the position of the supported version in the sorted list
+SUPPORTED_MAJOR_MINOR="v${KUBERNETES_MAJOR}.${KUBERNETES_MINOR}"
+echo "Looking for supported version: $SUPPORTED_MAJOR_MINOR"
+
+# Get all versions that are <= supported version
+# Create a temporary file for filtering
+TEMP_VERSIONS=$(mktemp)
+
+echo "$ALL_MAJOR_MINOR_VERSIONS" | while read version; do
+    # Compare versions using sort -V (version sort)
+    # If version <= supported, include it
+    if [ "$(printf '%s\n%s\n' "$version" "$SUPPORTED_MAJOR_MINOR" | sort -V | head -1)" = "$version" ] || [ "$version" = "$SUPPORTED_MAJOR_MINOR" ]; then
+        echo "$version"
+    fi
+done > "$TEMP_VERSIONS"
+
+# Get the supported version and 5 previous versions (total 6 versions)
+# First, find the position of supported version
+SUPPORTED_POS=$(grep -n "^${SUPPORTED_MAJOR_MINOR}$" "$TEMP_VERSIONS" | cut -d: -f1)
+
+if [ -z "$SUPPORTED_POS" ]; then
+    echo "Error: Supported version $SUPPORTED_MAJOR_MINOR not found in available versions" >&2
+    exit 1
+fi
+
+# Calculate start position (5 versions before supported, or from beginning if less than 5 available)
+TOTAL_LINES=$(wc -l < "$TEMP_VERSIONS" | tr -d ' ')
+START_POS=$((SUPPORTED_POS - 5))
+if [ $START_POS -lt 1 ]; then
+    START_POS=1
+fi
+
+# Extract versions from START_POS to SUPPORTED_POS (inclusive)
+CANDIDATE_VERSIONS=$(sed -n "${START_POS},${SUPPORTED_POS}p" "$TEMP_VERSIONS")
+
+if [ -z "$CANDIDATE_VERSIONS" ]; then
+    echo "Error: Could not find supported version $SUPPORTED_MAJOR_MINOR in available versions" >&2
+    exit 1
+fi
+
+declare -A VERSION_MAP
+VERSIONS=()
+
+# Process each candidate version
+for major_minor_key in $CANDIDATE_VERSIONS; do
+    # Extract major and minor for matching
+    major=$(echo "$major_minor_key" | sed -E 's/v([0-9]+)\.([0-9]+)/\1/')
+    minor=$(echo "$major_minor_key" | sed -E 's/v([0-9]+)\.([0-9]+)/\2/')
+    
+    # Find all tags that match this major.minor version
+    matching_tags=$(echo "$AVAILABLE_TAGS" | grep "^v${major}\\.${minor}\\.")
+    
+    if [ -n "$matching_tags" ]; then
+        # Get the latest patch version for this major.minor version
+        latest_tag=$(echo "$matching_tags" | tail -n1)
+        
+        VERSION_MAP["${major_minor_key}"]="${latest_tag}"
+        VERSIONS+=("${major_minor_key}")
+        echo "Found version: ${major_minor_key} -> ${latest_tag}"
+    fi
+done
+
+if [ ${#VERSIONS[@]} -eq 0 ]; then
+    echo "Error: No matching versions found" >&2
+    exit 1
+fi
+
+# Sort versions in descending order (newest first)
+IFS=$'\n' VERSIONS=($(printf '%s\n' "${VERSIONS[@]}" | sort -V -r))
+unset IFS
+
+echo "Versions to add: ${VERSIONS[*]}"
+
+# Create/update versions.yaml file
+echo "Updating $VERSIONS_FILE..."
+{
+    for ver in "${VERSIONS[@]}"; do
+        echo "\"${ver}\": \"${VERSION_MAP[$ver]}\""
+    done
+} > "$VERSIONS_FILE"
+
+echo "Successfully updated $VERSIONS_FILE"
+
+# Update values.yaml - enum with major.minor versions only
+TEMP_FILE=$(mktemp)
+trap "rm -f $TEMP_FILE $TEMP_VERSIONS" EXIT
+
+# Build new version section
+NEW_VERSION_SECTION="## @enum {string} Version"
+for ver in "${VERSIONS[@]}"; do
+    NEW_VERSION_SECTION="${NEW_VERSION_SECTION}
+## @value $ver"
+done
+NEW_VERSION_SECTION="${NEW_VERSION_SECTION}
+
+## @param {Version} version - Kubernetes major.minor version to deploy
+version: \"${VERSIONS[0]}\""
+
+# Check if version section already exists
+if grep -q "^## @enum {string} Version" "$VALUES_FILE"; then
+    # Version section exists, update it using awk
+    echo "Updating existing version section in $VALUES_FILE..."
+    
+    # Use awk to replace the section from "## @enum {string} Version" to "version: " (inclusive)
+    # Delete the old section and insert the new one
+    awk -v new_section="$NEW_VERSION_SECTION" '
+        /^## @enum {string} Version/ {
+            in_section = 1
+            print new_section
+            next
+        }
+        in_section && /^version: / {
+            in_section = 0
+            next
+        }
+        in_section {
+            next
+        }
+        { print }
+    ' "$VALUES_FILE" > "$TEMP_FILE.tmp"
+    mv "$TEMP_FILE.tmp" "$VALUES_FILE"
+else
+    # Version section doesn't exist, insert it before Application-specific parameters section
+    echo "Inserting new version section in $VALUES_FILE..."
+    
+    # Use awk to insert before "## @section Application-specific parameters"
+    awk -v new_section="$NEW_VERSION_SECTION" '
+        /^## @section Application-specific parameters/ {
+            print new_section
+            print ""
+        }
+        { print }
+    ' "$VALUES_FILE" > "$TEMP_FILE.tmp"
+    mv "$TEMP_FILE.tmp" "$VALUES_FILE"
+fi
+
+echo "Successfully updated $VALUES_FILE with versions: ${VERSIONS[*]}"
+
+# Update KUBERNETES_VERSION in Makefile
+# Extract major.minor from KUBERNETES_VERSION (e.g., "v1.33" from "v1.33.4")
+KUBERNETES_MAJOR_MINOR_FOR_MAKEFILE=$(echo "$KUBERNETES_VERSION" | sed -E 's/v([0-9]+)\.([0-9]+)\.[0-9]+/v\1.\2/')
+
+if grep -q "^KUBERNETES_VERSION" "$MAKEFILE"; then
+    # Update existing KUBERNETES_VERSION line using awk
+    echo "Updating KUBERNETES_VERSION in $MAKEFILE..."
+    awk -v new_version="${KUBERNETES_MAJOR_MINOR_FOR_MAKEFILE}" '
+        /^KUBERNETES_VERSION = / {
+            print "KUBERNETES_VERSION = " new_version
+            next
+        }
+        { print }
+    ' "$MAKEFILE" > "$TEMP_FILE.tmp"
+    mv "$TEMP_FILE.tmp" "$MAKEFILE"
+    echo "Successfully updated KUBERNETES_VERSION in $MAKEFILE to ${KUBERNETES_MAJOR_MINOR_FOR_MAKEFILE}"
+else
+    echo "Warning: KUBERNETES_VERSION not found in $MAKEFILE" >&2
+fi
+
diff --git a/packages/apps/kubernetes/images/busybox.tag b/packages/apps/kubernetes/images/busybox.tag
new file mode 100644
index 00000000..39de220a
--- /dev/null
+++ b/packages/apps/kubernetes/images/busybox.tag
@@ -0,0 +1 @@
+docker.io/library/busybox:1.37.0@sha256:1487d0af5f52b4ba31c7e465126ee2123fe3f2305d638e7827681e7cf6c83d5e
diff --git a/packages/apps/kubernetes/images/cluster-autoscaler.tag b/packages/apps/kubernetes/images/cluster-autoscaler.tag
index b7ea5c23..d9fd9a52 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.25.2@sha256:3a8170433e1632e5cc2b6d9db34d0605e8e6c63c158282c38450415e700e932e
+ghcr.io/cozystack/cozystack/cluster-autoscaler:0.0.0@sha256:e9d0aa7e651b03a6713b380101a61832818a91b5f989da9754f58693898c4056
diff --git a/packages/apps/kubernetes/images/kubevirt-cloud-provider.tag b/packages/apps/kubernetes/images/kubevirt-cloud-provider.tag
index 4dd82136..ca661f3a 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.25.2@sha256:e522960064290747a67502d4e8927c591bdb290bad1f0bae88a02758ebfd380f
+ghcr.io/cozystack/cozystack/kubevirt-cloud-provider:0.0.0@sha256:dee69d15fa8616aa6a1e5a67fc76370e7698a7f58b25e30650eb39c9fb826de8
diff --git a/packages/apps/kubernetes/images/kubevirt-cloud-provider/Dockerfile b/packages/apps/kubernetes/images/kubevirt-cloud-provider/Dockerfile
index 563251d8..58a4d039 100644
--- a/packages/apps/kubernetes/images/kubevirt-cloud-provider/Dockerfile
+++ b/packages/apps/kubernetes/images/kubevirt-cloud-provider/Dockerfile
@@ -21,6 +21,6 @@ RUN go mod vendor
 
 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
+FROM scratch
 COPY --from=builder /go/src/kubevirt.io/cloud-provider-kubevirt/bin/kubevirt-cloud-controller-manager /bin/kubevirt-cloud-controller-manager
 ENTRYPOINT [ "/bin/kubevirt-cloud-controller-manager" ]
diff --git a/packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/354.diff b/packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/379.diff
similarity index 63%
rename from packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/354.diff
rename to packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/379.diff
index 3410ea93..ad1ec9c5 100644
--- a/packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/354.diff
+++ b/packages/apps/kubernetes/images/kubevirt-cloud-provider/patches/379.diff
@@ -1,5 +1,5 @@
 diff --git a/pkg/controller/kubevirteps/kubevirteps_controller.go b/pkg/controller/kubevirteps/kubevirteps_controller.go
-index 53388eb8e..28644236f 100644
+index 53388eb8e..873060251 100644
 --- a/pkg/controller/kubevirteps/kubevirteps_controller.go
 +++ b/pkg/controller/kubevirteps/kubevirteps_controller.go
 @@ -12,7 +12,6 @@ import (
@@ -10,12 +10,17 @@ index 53388eb8e..28644236f 100644
  	"k8s.io/apimachinery/pkg/runtime"
  	"k8s.io/apimachinery/pkg/runtime/schema"
  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
-@@ -669,35 +668,50 @@ func (c *Controller) getDesiredEndpoints(service *v1.Service, tenantSlices []*di
+@@ -666,38 +665,62 @@ func (c *Controller) getDesiredEndpoints(service *v1.Service, tenantSlices []*di
+ 		// for extracting the nodes it does not matter what type of address we are dealing with
+ 		// all nodes with an endpoint for a corresponding slice will be selected.
+ 		nodeSet := sets.Set[string]{}
++		hasEndpointsWithoutNodeName := false
  		for _, slice := range tenantSlices {
  			for _, endpoint := range slice.Endpoints {
  				// find all unique nodes that correspond to an endpoint in a tenant slice
 +				if endpoint.NodeName == nil {
 +					klog.Warningf("Skipping endpoint without NodeName in slice %s/%s", slice.Namespace, slice.Name)
++					hasEndpointsWithoutNodeName = true
 +					continue
 +				}
  				nodeSet.Insert(*endpoint.NodeName)
@@ -23,6 +28,13 @@ index 53388eb8e..28644236f 100644
  		}
  
 -		klog.Infof("Desired nodes for service %s in namespace %s: %v", service.Name, service.Namespace, sets.List(nodeSet))
++		// Fallback: if no endpoints with NodeName were found, but there are endpoints without NodeName,
++		// distribute traffic to all VMIs (similar to ExternalTrafficPolicy=Cluster behavior)
++		if nodeSet.Len() == 0 && hasEndpointsWithoutNodeName {
++			klog.Infof("No endpoints with NodeName found for service %s/%s, falling back to all VMIs", service.Namespace, service.Name)
++			return c.getAllVMIEndpoints()
++		}
++
 +		klog.Infof("Desired nodes for service %s/%s: %v", service.Namespace, service.Name, sets.List(nodeSet))
  
  		for _, node := range sets.List(nodeSet) {
@@ -68,7 +80,7 @@ index 53388eb8e..28644236f 100644
  					desiredEndpoints = append(desiredEndpoints, &discovery.Endpoint{
  						Addresses: []string{i.IP},
  						Conditions: discovery.EndpointConditions{
-@@ -705,9 +719,9 @@ func (c *Controller) getDesiredEndpoints(service *v1.Service, tenantSlices []*di
+@@ -705,9 +728,9 @@ func (c *Controller) getDesiredEndpoints(service *v1.Service, tenantSlices []*di
  							Serving:     &serving,
  							Terminating: &terminating,
  						},
@@ -80,6 +92,71 @@ index 53388eb8e..28644236f 100644
  				}
  			}
  		}
+@@ -716,6 +739,64 @@ func (c *Controller) getDesiredEndpoints(service *v1.Service, tenantSlices []*di
+ 	return desiredEndpoints
+ }
+ 
++// getAllVMIEndpoints returns endpoints for all VMIs in the infra namespace.
++// This is used as a fallback when tenant endpoints don't have NodeName specified,
++// similar to ExternalTrafficPolicy=Cluster behavior where traffic is distributed to all nodes.
++func (c *Controller) getAllVMIEndpoints() []*discovery.Endpoint {
++	var endpoints []*discovery.Endpoint
++
++	// List all VMIs in the infra namespace
++	vmiList, err := c.infraDynamic.
++		Resource(kubevirtv1.VirtualMachineInstanceGroupVersionKind.GroupVersion().WithResource("virtualmachineinstances")).
++		Namespace(c.infraNamespace).
++		List(context.TODO(), metav1.ListOptions{})
++	if err != nil {
++		klog.Errorf("Failed to list VMIs in namespace %q: %v", c.infraNamespace, err)
++		return endpoints
++	}
++
++	for _, obj := range vmiList.Items {
++		vmi := &kubevirtv1.VirtualMachineInstance{}
++		err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, vmi)
++		if err != nil {
++			klog.Errorf("Failed to convert Unstructured to VirtualMachineInstance: %v", err)
++			continue
++		}
++
++		if vmi.Status.NodeName == "" {
++			klog.Warningf("Skipping VMI %s/%s: NodeName is empty", vmi.Namespace, vmi.Name)
++			continue
++		}
++		nodeNamePtr := &vmi.Status.NodeName
++
++		ready := vmi.Status.Phase == kubevirtv1.Running
++		serving := vmi.Status.Phase == kubevirtv1.Running
++		terminating := vmi.Status.Phase == kubevirtv1.Failed || vmi.Status.Phase == kubevirtv1.Succeeded
++
++		for _, i := range vmi.Status.Interfaces {
++			if i.Name == "default" {
++				if i.IP == "" {
++					klog.Warningf("VMI %s/%s interface %q has no IP, skipping", vmi.Namespace, vmi.Name, i.Name)
++					continue
++				}
++				endpoints = append(endpoints, &discovery.Endpoint{
++					Addresses: []string{i.IP},
++					Conditions: discovery.EndpointConditions{
++						Ready:       &ready,
++						Serving:     &serving,
++						Terminating: &terminating,
++					},
++					NodeName: nodeNamePtr,
++				})
++				break
++			}
++		}
++	}
++
++	klog.Infof("Fallback: created %d endpoints from all VMIs in namespace %s", len(endpoints), c.infraNamespace)
++	return endpoints
++}
++
+ func (c *Controller) ensureEndpointSliceLabels(slice *discovery.EndpointSlice, svc *v1.Service) (map[string]string, bool) {
+ 	labels := make(map[string]string)
+ 	labelsChanged := false
 diff --git a/pkg/controller/kubevirteps/kubevirteps_controller_test.go b/pkg/controller/kubevirteps/kubevirteps_controller_test.go
 index 1c97035b4..d205d0bed 100644
 --- a/pkg/controller/kubevirteps/kubevirteps_controller_test.go
diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver.tag b/packages/apps/kubernetes/images/kubevirt-csi-driver.tag
index 2f7b9b2d..00aa2caa 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.25.2@sha256:761e7235ff9cb7f6f223f00954943e6a5af32ed6624ee592a8610122f96febb0
+ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:72154a97054e16cdf3dea6129d962b8d7e86b55cf9386095e8ac2ce7c8b69172
diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver/Dockerfile b/packages/apps/kubernetes/images/kubevirt-csi-driver/Dockerfile
index 5ae5817f..b156d08e 100644
--- a/packages/apps/kubernetes/images/kubevirt-csi-driver/Dockerfile
+++ b/packages/apps/kubernetes/images/kubevirt-csi-driver/Dockerfile
@@ -1,31 +1,23 @@
-# Source: https://github.com/kubevirt/csi-driver/blob/main/Dockerfile
 ARG builder_image=docker.io/library/golang:1.22.5
 FROM ${builder_image} AS builder
-RUN git clone https://github.com/kubevirt/csi-driver /src/kubevirt-csi-driver \
- && cd /src/kubevirt-csi-driver \
- && git checkout a8d6605bc9997bcfda3fb9f1f82ba6445b4984cc
 
 ARG TARGETOS
 ARG TARGETARCH
-ENV GOOS=$TARGETOS
-ENV GOARCH=$TARGETARCH
 
-WORKDIR /src/kubevirt-csi-driver
+WORKDIR /src
 
-RUN make build
+COPY go.mod go.sum ./
+RUN go mod download
+
+COPY *.go ./
+RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build \
+    -ldflags "-X kubevirt.io/csi-driver/pkg/service.VendorVersion=0.2.0" \
+    -o kubevirt-csi-driver .
 
 FROM quay.io/centos/centos:stream9
-ARG git_url=https://github.com/kubevirt/csi-driver.git
 
-LABEL maintainers="The KubeVirt Project " \
-      description="KubeVirt CSI Driver" \
-      multi.GIT_URL=${git_url}
+RUN dnf install -y e2fsprogs xfsprogs nfs-utils && dnf clean all
+
+COPY --from=builder /src/kubevirt-csi-driver .
 
 ENTRYPOINT ["./kubevirt-csi-driver"]
-
-RUN dnf install -y e2fsprogs xfsprogs && dnf clean all
-
-ARG git_sha=NONE
-LABEL multi.GIT_SHA=${git_sha}
-
-COPY --from=builder /src/kubevirt-csi-driver/kubevirt-csi-driver .
diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver/controller.go b/packages/apps/kubernetes/images/kubevirt-csi-driver/controller.go
new file mode 100644
index 00000000..edddec09
--- /dev/null
+++ b/packages/apps/kubernetes/images/kubevirt-csi-driver/controller.go
@@ -0,0 +1,577 @@
+package main
+
+import (
+	"context"
+	"fmt"
+	"net/url"
+	"time"
+
+	csi "github.com/container-storage-interface/spec/lib/go/csi"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/api/errors"
+	"k8s.io/apimachinery/pkg/api/resource"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apimachinery/pkg/util/wait"
+	"k8s.io/client-go/dynamic"
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/tools/cache"
+	"k8s.io/client-go/util/retry"
+	"k8s.io/klog/v2"
+	cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
+
+	kubevirtclient "kubevirt.io/csi-driver/pkg/kubevirt"
+	"kubevirt.io/csi-driver/pkg/service"
+	"kubevirt.io/csi-driver/pkg/util"
+)
+
+const (
+	nfsVolumeKey    = "nfsVolume"
+	nfsExportKey    = "nfsExport"
+	busParameter    = "bus"
+	serialParameter = "serial"
+)
+
+var ciliumNetworkPolicyGVR = schema.GroupVersionResource{
+	Group:    "cilium.io",
+	Version:  "v2",
+	Resource: "ciliumnetworkpolicies",
+}
+
+var _ csi.ControllerServer = &WrappedControllerService{}
+
+// WrappedControllerService embeds the upstream ControllerService and adds RWX Filesystem (NFS) support.
+type WrappedControllerService struct {
+	*service.ControllerService
+	infraClient             kubernetes.Interface
+	dynamicClient           dynamic.Interface
+	virtClient              kubevirtclient.Client
+	infraNamespace          string
+	infraClusterLabels      map[string]string
+	storageClassEnforcement util.StorageClassEnforcement
+}
+
+// isRWXFilesystem checks if the volume capabilities request RWX access with filesystem mode.
+func isRWXFilesystem(caps []*csi.VolumeCapability) bool {
+	hasRWX := false
+	hasMount := false
+	for _, cap := range caps {
+		if cap == nil {
+			continue
+		}
+		if cap.GetMount() != nil {
+			hasMount = true
+		}
+		if am := cap.GetAccessMode(); am != nil && am.Mode == csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER {
+			hasRWX = true
+		}
+	}
+	return hasRWX && hasMount
+}
+
+// CreateVolume intercepts RWX Filesystem requests and creates a DataVolume in the infra
+// cluster with AccessMode=RWX and VolumeMode=Filesystem. Upstream rejects RWX+Filesystem,
+// so we handle DataVolume creation ourselves. Using DataVolume (not bare PVC) preserves
+// compatibility with upstream snapshot and clone operations.
+// For all other requests, delegates to upstream.
+func (w *WrappedControllerService) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) {
+	if req == nil {
+		return nil, status.Error(codes.InvalidArgument, "missing request")
+	}
+	if !isRWXFilesystem(req.GetVolumeCapabilities()) {
+		return w.ControllerService.CreateVolume(ctx, req)
+	}
+
+	if len(req.GetName()) == 0 {
+		return nil, status.Error(codes.InvalidArgument, "name missing in request")
+	}
+
+	// Storage class enforcement
+	storageClassName := req.Parameters[kubevirtclient.InfraStorageClassNameParameter]
+	if !w.storageClassEnforcement.AllowAll {
+		if storageClassName == "" {
+			if !w.storageClassEnforcement.AllowDefault {
+				return nil, status.Error(codes.InvalidArgument, "infraStorageclass is not in the allowed list")
+			}
+		} else if !util.Contains(w.storageClassEnforcement.AllowList, storageClassName) {
+			return nil, status.Error(codes.InvalidArgument, "infraStorageclass is not in the allowed list")
+		}
+	}
+
+	storageSize := req.GetCapacityRange().GetRequiredBytes()
+	dvName := req.Name
+
+	// Determine DataVolume source (blank, snapshot, or clone)
+	source, err := w.determineDvSource(ctx, req)
+	if err != nil {
+		return nil, err
+	}
+
+	// Handle CSI clone: CDI doesn't allow cloning PVCs in use by a pod,
+	// so use DataSourceRef instead (same approach as upstream)
+	sourcePVCName := ""
+	if source.PVC != nil {
+		sourcePVCName = source.PVC.Name
+		source = nil
+	}
+
+	volumeMode := corev1.PersistentVolumeFilesystem
+	dv := &cdiv1.DataVolume{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "DataVolume",
+			APIVersion: cdiv1.SchemeGroupVersion.String(),
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      dvName,
+			Namespace: w.infraNamespace,
+			Labels:    w.infraClusterLabels,
+			Annotations: map[string]string{
+				"cdi.kubevirt.io/storage.deleteAfterCompletion":    "false",
+				"cdi.kubevirt.io/storage.bind.immediate.requested": "true",
+			},
+		},
+		Spec: cdiv1.DataVolumeSpec{
+			Storage: &cdiv1.StorageSpec{
+				AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteMany},
+				VolumeMode:  &volumeMode,
+				Resources: corev1.ResourceRequirements{
+					Requests: corev1.ResourceList{
+						corev1.ResourceStorage: *resource.NewScaledQuantity(storageSize, 0),
+					},
+				},
+			},
+			Source: source,
+		},
+	}
+
+	if sourcePVCName != "" {
+		dv.Spec.Storage.DataSourceRef = &corev1.TypedObjectReference{
+			Kind: "PersistentVolumeClaim",
+			Name: sourcePVCName,
+		}
+	}
+
+	if storageClassName != "" {
+		dv.Spec.Storage.StorageClassName = &storageClassName
+	}
+
+	// Idempotency: check if DataVolume already exists
+	if existingDv, err := w.virtClient.GetDataVolume(ctx, w.infraNamespace, dvName); errors.IsNotFound(err) {
+		klog.Infof("Creating NFS DataVolume %s/%s", w.infraNamespace, dvName)
+		dv, err = w.virtClient.CreateDataVolume(ctx, w.infraNamespace, dv)
+		if err != nil {
+			klog.Errorf("Failed creating NFS DataVolume %s: %v", dvName, err)
+			return nil, err
+		}
+	} else if err != nil {
+		return nil, err
+	} else {
+		if existingDv != nil && existingDv.Spec.Storage != nil {
+			existingRequest := existingDv.Spec.Storage.Resources.Requests[corev1.ResourceStorage]
+			newRequest := dv.Spec.Storage.Resources.Requests[corev1.ResourceStorage]
+			if newRequest.Cmp(existingRequest) != 0 {
+				return nil, status.Error(codes.AlreadyExists, "requested storage size does not match existing size")
+			}
+			dv = existingDv
+		}
+	}
+
+	serial := string(dv.GetUID())
+
+	return &csi.CreateVolumeResponse{
+		Volume: &csi.Volume{
+			CapacityBytes: storageSize,
+			VolumeId:      dvName,
+			VolumeContext: map[string]string{
+				busParameter:    "scsi",
+				serialParameter: serial,
+				nfsVolumeKey:    "true",
+			},
+			ContentSource: req.GetVolumeContentSource(),
+		},
+	}, nil
+}
+
+// determineDvSource determines the DataVolume source from the CSI request content source.
+// Mirrors upstream logic for blank, snapshot, and clone sources.
+func (w *WrappedControllerService) determineDvSource(ctx context.Context, req *csi.CreateVolumeRequest) (*cdiv1.DataVolumeSource, error) {
+	res := &cdiv1.DataVolumeSource{}
+	if req.GetVolumeContentSource() != nil {
+		source := req.GetVolumeContentSource()
+		switch source.Type.(type) {
+		case *csi.VolumeContentSource_Snapshot:
+			snapshot, err := w.virtClient.GetVolumeSnapshot(ctx, w.infraNamespace, source.GetSnapshot().GetSnapshotId())
+			if errors.IsNotFound(err) {
+				return nil, status.Errorf(codes.NotFound, "source snapshot %s not found", source.GetSnapshot().GetSnapshotId())
+			} else if err != nil {
+				return nil, err
+			}
+			if snapshot != nil {
+				res.Snapshot = &cdiv1.DataVolumeSourceSnapshot{
+					Name:      snapshot.Name,
+					Namespace: w.infraNamespace,
+				}
+			}
+		case *csi.VolumeContentSource_Volume:
+			volume, err := w.virtClient.GetDataVolume(ctx, w.infraNamespace, source.GetVolume().GetVolumeId())
+			if errors.IsNotFound(err) {
+				return nil, status.Errorf(codes.NotFound, "source volume %s not found", source.GetVolume().GetVolumeId())
+			} else if err != nil {
+				return nil, err
+			}
+			if volume != nil {
+				res.PVC = &cdiv1.DataVolumeSourcePVC{
+					Name:      volume.Name,
+					Namespace: w.infraNamespace,
+				}
+			}
+		default:
+			return nil, status.Error(codes.InvalidArgument, "unknown content type")
+		}
+	} else {
+		res.Blank = &cdiv1.DataVolumeBlankImage{}
+	}
+	return res, nil
+}
+
+// ControllerPublishVolume for NFS volumes: annotates infra PVC for WFFC binding,
+// waits for PVC bound, extracts NFS export from PV, and creates CiliumNetworkPolicy.
+// For RWO volumes, delegates to upstream (hotplug SCSI).
+func (w *WrappedControllerService) ControllerPublishVolume(ctx context.Context, req *csi.ControllerPublishVolumeRequest) (*csi.ControllerPublishVolumeResponse, error) {
+	if req.GetVolumeContext()[nfsVolumeKey] != "true" {
+		return w.ControllerService.ControllerPublishVolume(ctx, req)
+	}
+
+	if len(req.GetVolumeId()) == 0 {
+		return nil, status.Error(codes.InvalidArgument, "volume id missing in request")
+	}
+	if len(req.GetNodeId()) == 0 {
+		return nil, status.Error(codes.InvalidArgument, "node id missing in request")
+	}
+
+	dvName := req.GetVolumeId()
+	vmNamespace, vmName, err := cache.SplitMetaNamespaceKey(req.GetNodeId())
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to parse node ID %q: %v", req.GetNodeId(), err)
+	}
+
+	klog.V(3).Infof("Publishing NFS volume %s to node %s/%s", dvName, vmNamespace, vmName)
+
+	// Get VMI for CiliumNetworkPolicy ownerReference
+	vmi, err := w.virtClient.GetVirtualMachine(ctx, vmNamespace, vmName)
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to get VMI %s/%s: %v", vmNamespace, vmName, err)
+	}
+
+	// Wait for PVC to be bound (CDI handles immediate binding via annotation)
+	klog.V(3).Infof("Waiting for PVC %s to be bound", dvName)
+	if err := wait.PollUntilContextTimeout(ctx, time.Second, 2*time.Minute, true, func(ctx context.Context) (bool, error) {
+		p, err := w.infraClient.CoreV1().PersistentVolumeClaims(w.infraNamespace).Get(ctx, dvName, metav1.GetOptions{})
+		if err != nil {
+			return false, err
+		}
+		return p.Status.Phase == corev1.ClaimBound, nil
+	}); err != nil {
+		return nil, status.Errorf(codes.Internal, "timed out waiting for PVC %s to be bound: %v", dvName, err)
+	}
+
+	// Read PV to get NFS export
+	pvc, err := w.infraClient.CoreV1().PersistentVolumeClaims(w.infraNamespace).Get(ctx, dvName, metav1.GetOptions{})
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to re-read PVC %s: %v", dvName, err)
+	}
+	pv, err := w.infraClient.CoreV1().PersistentVolumes().Get(ctx, pvc.Spec.VolumeName, metav1.GetOptions{})
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to get PV %s: %v", pvc.Spec.VolumeName, err)
+	}
+	nfsExport, err := getNFSExport(pv)
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to extract NFS export from PV %s: %v", pv.Name, err)
+	}
+	klog.V(3).Infof("NFS export for volume %s: %s", dvName, nfsExport)
+
+	// Parse NFS URL for CiliumNetworkPolicy port
+	_, port, _, err := parseNFSExport(nfsExport)
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to parse NFS export URL: %v", err)
+	}
+
+	// Create or update CiliumNetworkPolicy allowing egress to NFS server
+	cnpName := fmt.Sprintf("csi-nfs-%s", dvName)
+	vmiOwnerRef := map[string]interface{}{
+		"apiVersion": "kubevirt.io/v1",
+		"kind":       "VirtualMachineInstance",
+		"name":       vmName,
+		"uid":        string(vmi.UID),
+	}
+	cnp := &unstructured.Unstructured{
+		Object: map[string]interface{}{
+			"apiVersion": "cilium.io/v2",
+			"kind":       "CiliumNetworkPolicy",
+			"metadata": map[string]interface{}{
+				"name":            cnpName,
+				"namespace":       vmNamespace,
+				"ownerReferences": []interface{}{vmiOwnerRef},
+			},
+			"spec": map[string]interface{}{
+				"endpointSelector": buildEndpointSelector([]string{vmName}),
+				"egress": []interface{}{
+					map[string]interface{}{
+						"toEndpoints": []interface{}{
+							map[string]interface{}{
+								"matchLabels": map[string]interface{}{
+									"k8s:app.kubernetes.io/component": "linstor-csi-nfs-server",
+									"k8s:io.kubernetes.pod.namespace": "cozy-linstor",
+								},
+							},
+						},
+						"toPorts": []interface{}{
+							map[string]interface{}{
+								"ports": []interface{}{
+									map[string]interface{}{
+										"port":     port,
+										"protocol": "TCP",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	if _, err := w.dynamicClient.Resource(ciliumNetworkPolicyGVR).Namespace(vmNamespace).Create(ctx, cnp, metav1.CreateOptions{}); err != nil {
+		if !errors.IsAlreadyExists(err) {
+			return nil, status.Errorf(codes.Internal, "failed to create CiliumNetworkPolicy %s: %v", cnpName, err)
+		}
+		// CNP exists — add ownerReference for this VMI
+		if err := w.addCNPOwnerReference(ctx, vmNamespace, cnpName, vmiOwnerRef); err != nil {
+			return nil, err
+		}
+	}
+
+	klog.V(3).Infof("Successfully published NFS volume %s", dvName)
+	return &csi.ControllerPublishVolumeResponse{
+		PublishContext: map[string]string{
+			nfsExportKey: nfsExport,
+		},
+	}, nil
+}
+
+// ControllerUnpublishVolume for NFS volumes: deletes CiliumNetworkPolicy.
+// For RWO volumes, delegates to upstream (hotplug removal).
+func (w *WrappedControllerService) ControllerUnpublishVolume(ctx context.Context, req *csi.ControllerUnpublishVolumeRequest) (*csi.ControllerUnpublishVolumeResponse, error) {
+	dvName := req.GetVolumeId()
+
+	// Determine if NFS by checking infra PVC access modes
+	pvc, err := w.infraClient.CoreV1().PersistentVolumeClaims(w.infraNamespace).Get(ctx, dvName, metav1.GetOptions{})
+	if err != nil {
+		if errors.IsNotFound(err) {
+			return &csi.ControllerUnpublishVolumeResponse{}, nil
+		}
+		return nil, err
+	}
+
+	if !hasRWXAccessMode(pvc) {
+		return w.ControllerService.ControllerUnpublishVolume(ctx, req)
+	}
+
+	// NFS volume: remove VMI ownerReference from CiliumNetworkPolicy
+	vmNamespace, vmName, err := cache.SplitMetaNamespaceKey(req.GetNodeId())
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to parse node ID %q: %v", req.GetNodeId(), err)
+	}
+
+	cnpName := fmt.Sprintf("csi-nfs-%s", dvName)
+	klog.V(3).Infof("Removing VMI %s ownerReference from CiliumNetworkPolicy %s/%s", vmName, vmNamespace, cnpName)
+	if err := w.removeCNPOwnerReference(ctx, vmNamespace, cnpName, vmName); err != nil {
+		return nil, err
+	}
+
+	klog.V(3).Infof("Successfully unpublished NFS volume %s", dvName)
+	return &csi.ControllerUnpublishVolumeResponse{}, nil
+}
+
+// ControllerExpandVolume delegates to upstream for the actual DataVolume/PVC resize.
+// For NFS volumes, LINSTOR handles NFS server resize automatically, so no node expansion is needed.
+func (w *WrappedControllerService) ControllerExpandVolume(ctx context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error) {
+	resp, err := w.ControllerService.ControllerExpandVolume(ctx, req)
+	if err != nil {
+		return nil, err
+	}
+
+	// For NFS volumes, no node-side expansion is needed
+	pvc, err := w.infraClient.CoreV1().PersistentVolumeClaims(w.infraNamespace).Get(ctx, req.GetVolumeId(), metav1.GetOptions{})
+	if err != nil {
+		klog.Warningf("Failed to check PVC access mode for %s/%s: %v", w.infraNamespace, req.GetVolumeId(), err)
+	} else if hasRWXAccessMode(pvc) {
+		resp.NodeExpansionRequired = false
+	}
+
+	return resp, nil
+}
+
+// addCNPOwnerReference adds a VMI ownerReference to an existing CiliumNetworkPolicy.
+func (w *WrappedControllerService) addCNPOwnerReference(ctx context.Context, namespace, cnpName string, ownerRef map[string]interface{}) error {
+	return retry.RetryOnConflict(retry.DefaultRetry, func() error {
+		existing, err := w.dynamicClient.Resource(ciliumNetworkPolicyGVR).Namespace(namespace).Get(ctx, cnpName, metav1.GetOptions{})
+		if err != nil {
+			return status.Errorf(codes.Internal, "failed to get CiliumNetworkPolicy %s: %v", cnpName, err)
+		}
+
+		ownerRefs, _, _ := unstructured.NestedSlice(existing.Object, "metadata", "ownerReferences")
+		uid, _, _ := unstructured.NestedString(ownerRef, "uid")
+		for _, ref := range ownerRefs {
+			if refMap, ok := ref.(map[string]interface{}); ok {
+				if refMap["uid"] == uid {
+					return nil // already present
+				}
+			}
+		}
+
+		ownerRefs = append(ownerRefs, ownerRef)
+		if err := unstructured.SetNestedSlice(existing.Object, ownerRefs, "metadata", "ownerReferences"); err != nil {
+			return status.Errorf(codes.Internal, "failed to set ownerReferences: %v", err)
+		}
+
+		// Rebuild endpointSelector to include all VMs
+		selector := buildEndpointSelector(vmNamesFromOwnerRefs(ownerRefs))
+		if err := unstructured.SetNestedField(existing.Object, selector, "spec", "endpointSelector"); err != nil {
+			return status.Errorf(codes.Internal, "failed to set endpointSelector: %v", err)
+		}
+
+		if _, err := w.dynamicClient.Resource(ciliumNetworkPolicyGVR).Namespace(namespace).Update(ctx, existing, metav1.UpdateOptions{}); err != nil {
+			return err
+		}
+		klog.V(3).Infof("Added ownerReference to CiliumNetworkPolicy %s", cnpName)
+		return nil
+	})
+}
+
+// removeCNPOwnerReference removes a VMI ownerReference from a CiliumNetworkPolicy.
+// Deletes the CNP if no ownerReferences remain.
+func (w *WrappedControllerService) removeCNPOwnerReference(ctx context.Context, namespace, cnpName, vmName string) error {
+	return retry.RetryOnConflict(retry.DefaultRetry, func() error {
+		existing, err := w.dynamicClient.Resource(ciliumNetworkPolicyGVR).Namespace(namespace).Get(ctx, cnpName, metav1.GetOptions{})
+		if err != nil {
+			if errors.IsNotFound(err) {
+				return nil
+			}
+			return status.Errorf(codes.Internal, "failed to get CiliumNetworkPolicy %s: %v", cnpName, err)
+		}
+
+		ownerRefs, _, _ := unstructured.NestedSlice(existing.Object, "metadata", "ownerReferences")
+		var remaining []interface{}
+		for _, ref := range ownerRefs {
+			if refMap, ok := ref.(map[string]interface{}); ok {
+				if refMap["name"] == vmName {
+					continue
+				}
+			}
+			remaining = append(remaining, ref)
+		}
+
+		if len(remaining) == 0 {
+			// Last owner — delete CNP
+			if err := w.dynamicClient.Resource(ciliumNetworkPolicyGVR).Namespace(namespace).Delete(ctx, cnpName, metav1.DeleteOptions{}); err != nil {
+				if !errors.IsNotFound(err) {
+					return status.Errorf(codes.Internal, "failed to delete CiliumNetworkPolicy %s: %v", cnpName, err)
+				}
+			}
+			klog.V(3).Infof("Deleted CiliumNetworkPolicy %s (no more owners)", cnpName)
+			return nil
+		}
+
+		if err := unstructured.SetNestedSlice(existing.Object, remaining, "metadata", "ownerReferences"); err != nil {
+			return status.Errorf(codes.Internal, "failed to set ownerReferences: %v", err)
+		}
+
+		// Rebuild endpointSelector from remaining VMs
+		selector := buildEndpointSelector(vmNamesFromOwnerRefs(remaining))
+		if err := unstructured.SetNestedField(existing.Object, selector, "spec", "endpointSelector"); err != nil {
+			return status.Errorf(codes.Internal, "failed to set endpointSelector: %v", err)
+		}
+
+		if _, err := w.dynamicClient.Resource(ciliumNetworkPolicyGVR).Namespace(namespace).Update(ctx, existing, metav1.UpdateOptions{}); err != nil {
+			return err
+		}
+		klog.V(3).Infof("Removed VMI %s ownerReference from CiliumNetworkPolicy %s", vmName, cnpName)
+		return nil
+	})
+}
+
+// buildEndpointSelector returns an endpointSelector using matchExpressions
+// so that multiple VMs can be listed in a single selector.
+func buildEndpointSelector(vmNames []string) map[string]interface{} {
+	values := make([]interface{}, len(vmNames))
+	for i, name := range vmNames {
+		values[i] = name
+	}
+	return map[string]interface{}{
+		"matchExpressions": []interface{}{
+			map[string]interface{}{
+				"key":      "kubevirt.io/vm",
+				"operator": "In",
+				"values":   values,
+			},
+		},
+	}
+}
+
+// vmNamesFromOwnerRefs extracts VM names from ownerReferences.
+func vmNamesFromOwnerRefs(ownerRefs []interface{}) []string {
+	var names []string
+	for _, ref := range ownerRefs {
+		if refMap, ok := ref.(map[string]interface{}); ok {
+			if name, ok := refMap["name"].(string); ok {
+				names = append(names, name)
+			}
+		}
+	}
+	return names
+}
+
+func hasRWXAccessMode(pvc *corev1.PersistentVolumeClaim) bool {
+	for _, mode := range pvc.Spec.AccessModes {
+		if mode == corev1.ReadWriteMany {
+			return true
+		}
+	}
+	return false
+}
+
+// getNFSExport extracts the NFS export URL from a PersistentVolume.
+// Supports both native NFS PVs and CSI PVs with nfs-export volume attribute.
+func getNFSExport(pv *corev1.PersistentVolume) (string, error) {
+	if pv.Spec.NFS != nil {
+		return fmt.Sprintf("nfs://%s:2049%s", pv.Spec.NFS.Server, pv.Spec.NFS.Path), nil
+	}
+	if pv.Spec.CSI != nil && pv.Spec.CSI.VolumeAttributes != nil {
+		if export, ok := pv.Spec.CSI.VolumeAttributes["linstor.csi.linbit.com/nfs-export"]; ok {
+			return export, nil
+		}
+	}
+	return "", fmt.Errorf("no NFS export info found in PV %s", pv.Name)
+}
+
+// parseNFSExport parses an NFS URL of the form nfs://host:port/path.
+func parseNFSExport(nfsURL string) (host, port, path string, err error) {
+	u, err := url.Parse(nfsURL)
+	if err != nil {
+		return "", "", "", fmt.Errorf("failed to parse NFS URL %q: %w", nfsURL, err)
+	}
+	host = u.Hostname()
+	port = u.Port()
+	if port == "" {
+		port = "2049"
+	}
+	path = u.Path
+	if path == "" {
+		path = "/"
+	}
+	return host, port, path, nil
+}
diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver/go.mod b/packages/apps/kubernetes/images/kubevirt-csi-driver/go.mod
new file mode 100644
index 00000000..96a96107
--- /dev/null
+++ b/packages/apps/kubernetes/images/kubevirt-csi-driver/go.mod
@@ -0,0 +1,101 @@
+module cozystack.io/kubevirt-csi-driver
+
+go 1.22.0
+
+toolchain go1.22.5
+
+require (
+	github.com/container-storage-interface/spec v1.10.0
+	google.golang.org/grpc v1.65.0
+	gopkg.in/yaml.v2 v2.4.0
+	k8s.io/api v0.31.4
+	k8s.io/apimachinery v0.31.4
+	k8s.io/client-go v12.0.0+incompatible
+	k8s.io/klog/v2 v2.130.1
+	k8s.io/mount-utils v0.33.1
+	kubevirt.io/containerized-data-importer-api v1.59.0
+	kubevirt.io/csi-driver v0.0.0-20250702202414-a8d6605bc999
+)
+
+require (
+	github.com/coreos/go-systemd/v22 v22.5.0 // indirect
+	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+	github.com/emicklei/go-restful/v3 v3.11.0 // indirect
+	github.com/fxamacker/cbor/v2 v2.7.0 // indirect
+	github.com/go-logr/logr v1.4.2 // indirect
+	github.com/go-openapi/jsonpointer v0.19.6 // indirect
+	github.com/go-openapi/jsonreference v0.20.2 // indirect
+	github.com/go-openapi/swag v0.22.4 // indirect
+	github.com/godbus/dbus/v5 v5.1.0 // indirect
+	github.com/gogo/protobuf v1.3.2 // indirect
+	github.com/golang/mock v1.6.0 // indirect
+	github.com/golang/protobuf v1.5.4 // indirect
+	github.com/google/gnostic-models v0.6.8 // indirect
+	github.com/google/go-cmp v0.6.0 // indirect
+	github.com/google/gofuzz v1.2.0 // indirect
+	github.com/google/uuid v1.6.0 // indirect
+	github.com/imdario/mergo v0.3.15 // indirect
+	github.com/josharian/intern v1.0.0 // indirect
+	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/kubernetes-csi/csi-lib-utils v0.18.1 // indirect
+	github.com/kubernetes-csi/external-snapshotter/client/v6 v6.3.0 // indirect
+	github.com/mailru/easyjson v0.7.7 // indirect
+	github.com/moby/sys/mountinfo v0.7.1 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+	github.com/opencontainers/runc v1.1.13 // indirect
+	github.com/opencontainers/runtime-spec v1.0.3-0.20220909204839-494a5a6aca78 // indirect
+	github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183 // indirect
+	github.com/openshift/custom-resource-status v1.1.2 // indirect
+	github.com/sirupsen/logrus v1.9.3 // indirect
+	github.com/spf13/pflag v1.0.5 // indirect
+	github.com/x448/float16 v0.8.4 // indirect
+	golang.org/x/net v0.33.0 // indirect
+	golang.org/x/oauth2 v0.21.0 // indirect
+	golang.org/x/sys v0.28.0 // indirect
+	golang.org/x/term v0.27.0 // indirect
+	golang.org/x/text v0.21.0 // indirect
+	golang.org/x/time v0.3.0 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
+	google.golang.org/protobuf v1.34.2 // indirect
+	gopkg.in/inf.v0 v0.9.1 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+	k8s.io/apiextensions-apiserver v0.26.4 // indirect
+	k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
+	k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
+	kubevirt.io/api v1.2.2 // indirect
+	kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 // indirect
+	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
+	sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
+	sigs.k8s.io/yaml v1.4.0 // indirect
+)
+
+replace (
+	k8s.io/api => k8s.io/api v0.31.4
+	k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.31.4
+	k8s.io/apimachinery => k8s.io/apimachinery v0.31.4
+	k8s.io/apiserver => k8s.io/apiserver v0.31.4
+	k8s.io/cli-runtime => k8s.io/cli-runtime v0.31.4
+	k8s.io/client-go => k8s.io/client-go v0.31.4
+	k8s.io/cloud-provider => k8s.io/cloud-provider v0.31.4
+	k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.31.4
+	k8s.io/code-generator => k8s.io/code-generator v0.31.4
+	k8s.io/component-base => k8s.io/component-base v0.31.4
+	k8s.io/component-helpers => k8s.io/component-helpers v0.31.4
+	k8s.io/controller-manager => k8s.io/controller-manager v0.31.4
+	k8s.io/cri-api => k8s.io/cri-api v0.31.4
+	k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.31.4
+	k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.31.4
+	k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.31.4
+	k8s.io/kube-proxy => k8s.io/kube-proxy v0.31.4
+	k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.31.4
+	k8s.io/kubectl => k8s.io/kubectl v0.31.4
+	k8s.io/kubelet => k8s.io/kubelet v0.31.4
+	k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.31.4
+	k8s.io/metrics => k8s.io/metrics v0.31.4
+	k8s.io/mount-utils => k8s.io/mount-utils v0.31.4
+	k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.31.4
+	k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.31.4
+	kubevirt.io/csi-driver => github.com/kubevirt/csi-driver v0.0.0-20250702202414-a8d6605bc999
+)
diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver/go.sum b/packages/apps/kubernetes/images/kubevirt-csi-driver/go.sum
new file mode 100644
index 00000000..a0c4ac81
--- /dev/null
+++ b/packages/apps/kubernetes/images/kubevirt-csi-driver/go.sum
@@ -0,0 +1,543 @@
+github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
+github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
+github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs=
+github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
+github.com/container-storage-interface/spec v1.10.0 h1:YkzWPV39x+ZMTa6Ax2czJLLwpryrQ+dPesB34mrRMXA=
+github.com/container-storage-interface/spec v1.10.0/go.mod h1:DtUvaQszPml1YJfIK7c00mlv6/g4wNMLanLgiUbKFRI=
+github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
+github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/emicklei/go-restful v2.15.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
+github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
+github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
+github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
+github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
+github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
+github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
+github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
+github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
+github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
+github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
+github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
+github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
+github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
+github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
+github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
+github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
+github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
+github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
+github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
+github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
+github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
+github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
+github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
+github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kubernetes-csi/csi-lib-utils v0.18.1 h1:vpg1kbQ6lFVCz7mY71zcqVE7W0GAQXXBoFfHvbW3gdw=
+github.com/kubernetes-csi/csi-lib-utils v0.18.1/go.mod h1:PIcn27zmbY0KBue4JDdZVfDF56tjcS3jKroZPi+pMoY=
+github.com/kubernetes-csi/external-snapshotter/client/v6 v6.3.0 h1:qS4r4ljINLWKJ9m9Ge3Q3sGZ/eIoDVDT2RhAdQFHb1k=
+github.com/kubernetes-csi/external-snapshotter/client/v6 v6.3.0/go.mod h1:oGXx2XTEzs9ikW2V6IC1dD8trgjRsS/Mvc2JRiC618Y=
+github.com/kubevirt/csi-driver v0.0.0-20250702202414-a8d6605bc999 h1:nq11swNPIRarVZm/YTOWh9rbuEqivgpA1c4RUEFSL90=
+github.com/kubevirt/csi-driver v0.0.0-20250702202414-a8d6605bc999/go.mod h1:Pzl14YlqPpoK/ZdS79tUSuHbC2L/NPqOIjFTN5kTmUg=
+github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
+github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
+github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g=
+github.com/moby/sys/mountinfo v0.7.1/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
+github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
+github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
+github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
+github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0=
+github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
+github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw=
+github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
+github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc=
+github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk=
+github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo=
+github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
+github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
+github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
+github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
+github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
+github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
+github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
+github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
+github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
+github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
+github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
+github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
+github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc=
+github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM=
+github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
+github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
+github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
+github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw=
+github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw=
+github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ=
+github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
+github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
+github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ=
+github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
+github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
+github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY=
+github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
+github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
+github.com/opencontainers/runc v1.1.13 h1:98S2srgG9vw0zWcDpFMn5TRrh8kLxa/5OFUstuUhmRs=
+github.com/opencontainers/runc v1.1.13/go.mod h1:R016aXacfp/gwQBYw2FDGa9m+n6atbLWrYY8hNMT/sA=
+github.com/opencontainers/runtime-spec v1.0.3-0.20220909204839-494a5a6aca78 h1:R5M2qXZiK/mWPMT4VldCOiSL9HIAMuxQZWdG0CSM5+4=
+github.com/opencontainers/runtime-spec v1.0.3-0.20220909204839-494a5a6aca78/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183 h1:t/CahSnpqY46sQR01SoS+Jt0jtjgmhgE6lFmRnO4q70=
+github.com/openshift/api v0.0.0-20230503133300-8bbcb7ca7183/go.mod h1:4VWG+W22wrB4HfBL88P40DxLEpSOaiBVxUnfalfJo9k=
+github.com/openshift/custom-resource-status v1.1.2 h1:C3DL44LEbvlbItfd8mT5jWrqPfHnSOQoQf/sypqA6A4=
+github.com/openshift/custom-resource-status v1.1.2/go.mod h1:DB/Mf2oTeiAmVVX1gN+NEqweonAPY0TKUwADizj8+ZA=
+github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
+github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
+github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
+github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
+golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
+golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
+golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
+golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
+golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
+golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
+golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU=
+golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
+golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
+golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
+golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
+golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
+golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
+golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
+golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808/go.mod h1:KG1lNk5ZFNssSZLrpVb4sMXKMpGwGXOxSG3rnu2gZQQ=
+golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
+golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
+golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
+golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
+golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
+golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
+golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
+golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
+golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
+golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
+golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
+golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
+golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
+golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
+golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
+golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
+golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
+golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
+golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
+golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
+golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
+golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
+golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
+golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
+google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
+gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+k8s.io/api v0.31.4 h1:I2QNzitPVsPeLQvexMEsj945QumYraqv9m74isPDKhM=
+k8s.io/api v0.31.4/go.mod h1:d+7vgXLvmcdT1BCo79VEgJxHHryww3V5np2OYTr6jdw=
+k8s.io/apiextensions-apiserver v0.31.4 h1:FxbqzSvy92Ca9DIs5jqot883G0Ln/PGXfm/07t39LS0=
+k8s.io/apiextensions-apiserver v0.31.4/go.mod h1:hIW9YU8UsqZqIWGG99/gsdIU0Ar45Qd3A12QOe/rvpg=
+k8s.io/apimachinery v0.31.4 h1:8xjE2C4CzhYVm9DGf60yohpNUh5AEBnPxCryPBECmlM=
+k8s.io/apimachinery v0.31.4/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
+k8s.io/client-go v0.31.4 h1:t4QEXt4jgHIkKKlx06+W3+1JOwAFU/2OPiOo7H92eRQ=
+k8s.io/client-go v0.31.4/go.mod h1:kvuMro4sFYIa8sulL5Gi5GFqUPvfH2O/dXuKstbaaeg=
+k8s.io/code-generator v0.31.4/go.mod h1:yMDt13Kn7m4MMZ4LxB1KBzdZjEyxzdT4b4qXq+lnI90=
+k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
+k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
+k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8=
+k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
+k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
+k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
+k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
+k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
+k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
+k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
+k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
+k8s.io/mount-utils v0.31.4 h1:9aWJ5BpJvs6fdIo36wWIuCC6ZMNllUT0JSFsVNJloFI=
+k8s.io/mount-utils v0.31.4/go.mod h1:HV/VYBUGqYUj4vt82YltzpWvgv8FPg0G9ItyInT3NPU=
+k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+kubevirt.io/api v1.2.2 h1:PeA937vsZawmKAsiiDQZJ/BbGH4OhEWsIzWrCNfmYXk=
+kubevirt.io/api v1.2.2/go.mod h1:SbeR9ma4EwnaOZEUkh/lNz0kzYm5LPpEDE30vKXC5Zg=
+kubevirt.io/containerized-data-importer-api v1.59.0 h1:GdDt9BlR0qHejpMaPfASbsG8JWDmBf1s7xZBj5W9qn0=
+kubevirt.io/containerized-data-importer-api v1.59.0/go.mod h1:4yOGtCE7HvgKp7wftZZ3TBvDJ0x9d6N6KaRjRYcUFpE=
+kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90 h1:QMrd0nKP0BGbnxTqakhDZAUhGKxPiPiN5gSDqKUmGGc=
+kubevirt.io/controller-lifecycle-operator-sdk/api v0.0.0-20220329064328-f3cc58c6ed90/go.mod h1:018lASpFYBsYN6XwmA2TIrPCx6e0gviTd/ZNtSitKgc=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
+sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
+sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
+sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
+sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
+sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver/main.go b/packages/apps/kubernetes/images/kubevirt-csi-driver/main.go
new file mode 100644
index 00000000..396cee42
--- /dev/null
+++ b/packages/apps/kubernetes/images/kubevirt-csi-driver/main.go
@@ -0,0 +1,219 @@
+package main
+
+import (
+	"context"
+	"flag"
+	"fmt"
+	"os"
+	"strings"
+
+	csi "github.com/container-storage-interface/spec/lib/go/csi"
+	"gopkg.in/yaml.v2"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/client-go/dynamic"
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/rest"
+	"k8s.io/client-go/tools/clientcmd"
+	klog "k8s.io/klog/v2"
+	mount "k8s.io/mount-utils"
+
+	snapcli "kubevirt.io/csi-driver/pkg/generated/external-snapshotter/client-go/clientset/versioned"
+	"kubevirt.io/csi-driver/pkg/kubevirt"
+	"kubevirt.io/csi-driver/pkg/service"
+	"kubevirt.io/csi-driver/pkg/util"
+)
+
+var (
+	endpoint               = flag.String("endpoint", "unix:/csi/csi.sock", "CSI endpoint")
+	nodeName               = flag.String("node-name", "", "The node name - the node this pods runs on")
+	infraClusterNamespace  = flag.String("infra-cluster-namespace", "", "The infra-cluster namespace")
+	infraClusterKubeconfig = flag.String("infra-cluster-kubeconfig", "", "the infra-cluster kubeconfig file. If not set, defaults to in cluster config.")
+	infraClusterLabels     = flag.String("infra-cluster-labels", "", "The infra-cluster labels to use when creating resources in infra cluster. 'name=value' fields separated by a comma")
+	volumePrefix           = flag.String("volume-prefix", "pvc", "The prefix expected for persistent volumes")
+
+	infraStorageClassEnforcement = os.Getenv("INFRA_STORAGE_CLASS_ENFORCEMENT")
+
+	tenantClusterKubeconfig = flag.String("tenant-cluster-kubeconfig", "", "the tenant cluster kubeconfig file. If not set, defaults to in cluster config.")
+
+	runNodeService       = flag.Bool("run-node-service", true, "Specifies rather or not to run the node service, the default is true")
+	runControllerService = flag.Bool("run-controller-service", true, "Specifies rather or not to run the controller service, the default is true")
+)
+
+func init() {
+	klog.InitFlags(nil)
+}
+
+func main() {
+	flag.Parse()
+	handle()
+	os.Exit(0)
+}
+
+func handle() {
+	var tenantRestConfig *rest.Config
+	var infraRestConfig *rest.Config
+	var identityClientset *kubernetes.Clientset
+
+	if service.VendorVersion == "" {
+		klog.Fatal("VendorVersion must be set at compile time")
+	}
+	klog.V(2).Infof("Driver vendor %v %v", service.VendorName, service.VendorVersion)
+
+	if (infraClusterLabels == nil || *infraClusterLabels == "") && *runControllerService {
+		klog.Fatal("infra-cluster-labels must be set")
+	}
+	if volumePrefix == nil || *volumePrefix == "" {
+		klog.Fatal("volume-prefix must be set")
+	}
+
+	inClusterConfig, err := rest.InClusterConfig()
+	if err != nil {
+		klog.Fatalf("Failed to build in cluster config: %v", err)
+	}
+
+	if *tenantClusterKubeconfig != "" {
+		tenantRestConfig, err = clientcmd.BuildConfigFromFlags("", *tenantClusterKubeconfig)
+		if err != nil {
+			klog.Fatalf("failed to build tenant cluster config: %v", err)
+		}
+	} else {
+		tenantRestConfig = inClusterConfig
+	}
+
+	if *infraClusterKubeconfig != "" {
+		infraRestConfig, err = clientcmd.BuildConfigFromFlags("", *infraClusterKubeconfig)
+		if err != nil {
+			klog.Fatalf("failed to build infra cluster config: %v", err)
+		}
+	} else {
+		infraRestConfig = inClusterConfig
+	}
+
+	tenantClientSet, err := kubernetes.NewForConfig(tenantRestConfig)
+	if err != nil {
+		klog.Fatalf("Failed to build tenant client set: %v", err)
+	}
+	tenantSnapshotClientSet, err := snapcli.NewForConfig(tenantRestConfig)
+	if err != nil {
+		klog.Fatalf("Failed to build tenant snapshot client set: %v", err)
+	}
+
+	infraClusterLabelsMap := parseLabels()
+	klog.V(5).Infof("Storage class enforcement string: \n%s", infraStorageClassEnforcement)
+	storageClassEnforcement := configureStorageClassEnforcement(infraStorageClassEnforcement)
+
+	virtClient, err := kubevirt.NewClient(infraRestConfig, infraClusterLabelsMap, tenantClientSet, tenantSnapshotClientSet, storageClassEnforcement, *volumePrefix)
+	if err != nil {
+		klog.Fatal(err)
+	}
+
+	var nodeID string
+	if *nodeName != "" {
+		node, err := tenantClientSet.CoreV1().Nodes().Get(context.TODO(), *nodeName, v1.GetOptions{})
+		if err != nil {
+			klog.Fatal(fmt.Errorf("failed to find node by name %v: %v", *nodeName, err))
+		}
+		if node.Spec.ProviderID == "" {
+			klog.Fatal("provider name missing from node, something's not right")
+		}
+		vmName := strings.TrimPrefix(node.Spec.ProviderID, `kubevirt://`)
+		vmNamespace, ok := node.Annotations["cluster.x-k8s.io/cluster-namespace"]
+		if !ok {
+			klog.Fatal("cannot infer infra vm namespace")
+		}
+		nodeID = fmt.Sprintf("%s/%s", vmNamespace, vmName)
+		klog.Infof("Node name: %v, Node ID: %s", *nodeName, nodeID)
+	}
+
+	identityClientset = tenantClientSet
+	if *runControllerService {
+		identityClientset, err = kubernetes.NewForConfig(infraRestConfig)
+		if err != nil {
+			klog.Fatalf("Failed to build infra client set: %v", err)
+		}
+	}
+
+	// Create upstream driver (provides Identity, Controller, Node services)
+	upstreamDriver := service.NewKubevirtCSIDriver(virtClient,
+		identityClientset,
+		*infraClusterNamespace,
+		infraClusterLabelsMap,
+		storageClassEnforcement,
+		nodeID,
+		*runNodeService,
+		*runControllerService)
+
+	// Wrap controller and node services with NFS/RWX support
+	var cs csi.ControllerServer
+	if *runControllerService {
+		infraKubernetesClient, err := kubernetes.NewForConfig(infraRestConfig)
+		if err != nil {
+			klog.Fatalf("Failed to build infra kubernetes client: %v", err)
+		}
+		infraDynamicClient, err := dynamic.NewForConfig(infraRestConfig)
+		if err != nil {
+			klog.Fatalf("Failed to build infra dynamic client: %v", err)
+		}
+		cs = &WrappedControllerService{
+			ControllerService:       upstreamDriver.ControllerService,
+			infraClient:             infraKubernetesClient,
+			dynamicClient:           infraDynamicClient,
+			virtClient:              virtClient,
+			infraNamespace:          *infraClusterNamespace,
+			infraClusterLabels:      infraClusterLabelsMap,
+			storageClassEnforcement: storageClassEnforcement,
+		}
+	}
+
+	var ns csi.NodeServer
+	if *runNodeService {
+		ns = &WrappedNodeService{
+			NodeService: upstreamDriver.NodeService,
+			mounter:     mount.New(""),
+		}
+	}
+
+	// Run gRPC server with upstream Identity + wrapped Controller/Node
+	s := service.NewNonBlockingGRPCServer()
+	s.Start(*endpoint, upstreamDriver.IdentityService, cs, ns)
+	s.Wait()
+}
+
+func configureStorageClassEnforcement(infraStorageClassEnforcement string) util.StorageClassEnforcement {
+	var storageClassEnforcement util.StorageClassEnforcement
+
+	if infraStorageClassEnforcement == "" {
+		storageClassEnforcement = util.StorageClassEnforcement{
+			AllowAll:     true,
+			AllowDefault: true,
+		}
+	} else {
+		err := yaml.Unmarshal([]byte(infraStorageClassEnforcement), &storageClassEnforcement)
+		if err != nil {
+			klog.Fatalf("Failed to parse infra-storage-class-enforcement %v", err)
+		}
+	}
+	return storageClassEnforcement
+}
+
+func parseLabels() map[string]string {
+	infraClusterLabelsMap := map[string]string{}
+
+	if *infraClusterLabels == "" {
+		return infraClusterLabelsMap
+	}
+
+	labelStrings := strings.Split(*infraClusterLabels, ",")
+
+	for _, label := range labelStrings {
+		labelPair := strings.SplitN(label, "=", 2)
+
+		if len(labelPair) != 2 {
+			klog.Fatal("Bad labels format. Should be 'key=value,key=value,...'")
+		}
+
+		infraClusterLabelsMap[labelPair[0]] = labelPair[1]
+	}
+
+	return infraClusterLabelsMap
+}
diff --git a/packages/apps/kubernetes/images/kubevirt-csi-driver/node.go b/packages/apps/kubernetes/images/kubevirt-csi-driver/node.go
new file mode 100644
index 00000000..a367f27f
--- /dev/null
+++ b/packages/apps/kubernetes/images/kubevirt-csi-driver/node.go
@@ -0,0 +1,161 @@
+package main
+
+import (
+	"context"
+	"fmt"
+	"os"
+	"path/filepath"
+
+	csi "github.com/container-storage-interface/spec/lib/go/csi"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+	"k8s.io/klog/v2"
+	mount "k8s.io/mount-utils"
+
+	"kubevirt.io/csi-driver/pkg/service"
+)
+
+var _ csi.NodeServer = &WrappedNodeService{}
+
+// WrappedNodeService embeds the upstream NodeService and adds NFS mount support.
+type WrappedNodeService struct {
+	*service.NodeService
+	mounter mount.Interface
+}
+
+// NodeStageVolume for NFS volumes is a no-op (NFS doesn't need staging).
+// For RWO volumes, delegates to upstream (lsblk + mkfs).
+func (w *WrappedNodeService) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) {
+	if req.GetPublishContext()[nfsExportKey] != "" {
+		klog.V(3).Infof("NFS volume %s: skipping stage", req.GetVolumeId())
+		return &csi.NodeStageVolumeResponse{}, nil
+	}
+	return w.NodeService.NodeStageVolume(ctx, req)
+}
+
+// NodePublishVolume for NFS volumes: mounts the /data subdir of the NFS export
+// at the target path, hiding internal artifacts (disk.img, lost+found).
+// For RWO volumes, delegates to upstream (mount block device).
+func (w *WrappedNodeService) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) {
+	nfsExport := req.GetPublishContext()[nfsExportKey]
+	if nfsExport == "" {
+		return w.NodeService.NodePublishVolume(ctx, req)
+	}
+
+	klog.V(3).Infof("Publishing NFS volume %s at %s", req.GetVolumeId(), req.GetTargetPath())
+
+	host, port, path, err := parseNFSExport(nfsExport)
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to parse NFS export: %v", err)
+	}
+
+	targetPath := req.GetTargetPath()
+
+	// Check if already mounted
+	notMnt, err := w.mounter.IsLikelyNotMountPoint(targetPath)
+	if err != nil {
+		if !os.IsNotExist(err) {
+			return nil, status.Errorf(codes.Internal, "failed to check mount point %s: %v", targetPath, err)
+		}
+		if err := os.MkdirAll(targetPath, 0750); err != nil {
+			return nil, status.Errorf(codes.Internal, "failed to create target path %s: %v", targetPath, err)
+		}
+		notMnt = true
+	}
+	if !notMnt {
+		klog.V(3).Infof("NFS volume %s already mounted at %s", req.GetVolumeId(), targetPath)
+		return &csi.NodePublishVolumeResponse{}, nil
+	}
+
+	mountOptions := []string{
+		"nfsvers=4.2",
+		fmt.Sprintf("port=%s", port),
+	}
+	if req.GetReadonly() {
+		mountOptions = append(mountOptions, "ro")
+	}
+
+	// Temp-mount the NFS root to ensure /data subdir exists and migrate any
+	// user files that were written before this fix (backward compatibility).
+	tmpMount, err := os.MkdirTemp("", fmt.Sprintf("nfs-init-%s-", req.GetVolumeId()))
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to create temp mount dir: %v", err)
+	}
+	defer os.Remove(tmpMount)
+
+	rootSource := fmt.Sprintf("%s:%s", host, path)
+	rootOpts := []string{"nfsvers=4.2", fmt.Sprintf("port=%s", port)}
+	if err := w.mounter.Mount(rootSource, tmpMount, "nfs", rootOpts); err != nil {
+		return nil, status.Errorf(codes.Internal, "NFS temp mount failed: %v", err)
+	}
+	defer func() {
+		if err := w.mounter.Unmount(tmpMount); err != nil {
+			klog.Warningf("Failed to unmount temp dir %s: %v", tmpMount, err)
+		}
+	}()
+
+	dataDir := filepath.Join(tmpMount, "data")
+	if err := os.MkdirAll(dataDir, 0777); err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to create /data subdir: %v", err)
+	}
+
+	// Auto-migrate: move user files from root into /data (skip internal artifacts).
+	// Fail the publish if migration cannot complete to avoid hiding user data.
+	entries, err := os.ReadDir(tmpMount)
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "failed to read NFS root for migration (volume %s): %v", req.GetVolumeId(), err)
+	}
+	for _, entry := range entries {
+		name := entry.Name()
+		if name == "data" || name == "disk.img" || name == "lost+found" {
+			continue
+		}
+		src := filepath.Join(tmpMount, name)
+		dst := filepath.Join(dataDir, name)
+		if _, err := os.Stat(dst); err == nil {
+			continue // already exists in /data, skip
+		}
+		klog.Infof("Migrating %s to /data/%s for volume %s", name, name, req.GetVolumeId())
+		if err := os.Rename(src, dst); err != nil {
+			if os.IsNotExist(err) {
+				continue // benign: concurrent publish already moved it
+			}
+			return nil, status.Errorf(codes.Internal, "failed to migrate %s for volume %s: %v", name, req.GetVolumeId(), err)
+		}
+	}
+
+	// Mount only the /data subdir at the pod's target path.
+	dataSource := fmt.Sprintf("%s:%s/data", host, path)
+	klog.V(3).Infof("Mounting NFS %s at %s with options %v", dataSource, targetPath, mountOptions)
+	if err := w.mounter.Mount(dataSource, targetPath, "nfs", mountOptions); err != nil {
+		return nil, status.Errorf(codes.Internal, "NFS mount of %s at %s failed: %v", dataSource, targetPath, err)
+	}
+
+	return &csi.NodePublishVolumeResponse{}, nil
+}
+
+// NodeExpandVolume for NFS volumes is a no-op (LINSTOR handles NFS resize automatically).
+// This should not normally be called for NFS since ControllerExpandVolume returns
+// NodeExpansionRequired=false, but we handle it gracefully as a safety net.
+func (w *WrappedNodeService) NodeExpandVolume(ctx context.Context, req *csi.NodeExpandVolumeRequest) (*csi.NodeExpandVolumeResponse, error) {
+	if isNFSMount(req.GetVolumePath(), w.mounter) {
+		klog.V(3).Infof("NFS volume %s: skipping node expansion", req.GetVolumeId())
+		return &csi.NodeExpandVolumeResponse{}, nil
+	}
+	return w.NodeService.NodeExpandVolume(ctx, req)
+}
+
+// isNFSMount checks if the given path is an NFS mount point.
+func isNFSMount(path string, m mount.Interface) bool {
+	mountPoints, err := m.List()
+	if err != nil {
+		klog.Warningf("Failed to list mount points: %v", err)
+		return false
+	}
+	for _, mp := range mountPoints {
+		if mp.Path == path && (mp.Type == "nfs" || mp.Type == "nfs4") {
+			return true
+		}
+	}
+	return false
+}
diff --git a/packages/apps/kubernetes/images/ubuntu-container-disk.tag b/packages/apps/kubernetes/images/ubuntu-container-disk-v1.30.tag
similarity index 50%
rename from packages/apps/kubernetes/images/ubuntu-container-disk.tag
rename to packages/apps/kubernetes/images/ubuntu-container-disk-v1.30.tag
index 50416e0a..f49fffe6 100644
--- a/packages/apps/kubernetes/images/ubuntu-container-disk.tag
+++ b/packages/apps/kubernetes/images/ubuntu-container-disk-v1.30.tag
@@ -1 +1 @@
-ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.32@sha256:e53f2394c7aa76ad10818ffb945e40006cd77406999e47e036d41b8b0bf094cc
+ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.30@sha256:f460ed1fd5a721aed423e6c3b8be0105d7f693cd86ad992d9c15fd4b27e58cec
diff --git a/packages/apps/kubernetes/images/ubuntu-container-disk-v1.31.tag b/packages/apps/kubernetes/images/ubuntu-container-disk-v1.31.tag
new file mode 100644
index 00000000..b5bdc79a
--- /dev/null
+++ b/packages/apps/kubernetes/images/ubuntu-container-disk-v1.31.tag
@@ -0,0 +1 @@
+ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.31@sha256:aaa2dfa8ee53ae26295f44d2491330f51412457bbe4aa6ba256297cc0bd8a0da
diff --git a/packages/apps/kubernetes/images/ubuntu-container-disk-v1.32.tag b/packages/apps/kubernetes/images/ubuntu-container-disk-v1.32.tag
new file mode 100644
index 00000000..ca285644
--- /dev/null
+++ b/packages/apps/kubernetes/images/ubuntu-container-disk-v1.32.tag
@@ -0,0 +1 @@
+ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.32@sha256:7acb4728ef6b9c0ff3344bf486bb00f2a083f2098452344a362242235013db01
diff --git a/packages/apps/kubernetes/images/ubuntu-container-disk-v1.33.tag b/packages/apps/kubernetes/images/ubuntu-container-disk-v1.33.tag
new file mode 100644
index 00000000..bb58690a
--- /dev/null
+++ b/packages/apps/kubernetes/images/ubuntu-container-disk-v1.33.tag
@@ -0,0 +1 @@
+ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.33@sha256:a2024339ab9edb980a96b43ad2744b7aa31afaef0983ddbc6a546068b4cfa87a
diff --git a/packages/apps/kubernetes/images/ubuntu-container-disk-v1.34.tag b/packages/apps/kubernetes/images/ubuntu-container-disk-v1.34.tag
new file mode 100644
index 00000000..36eed7a7
--- /dev/null
+++ b/packages/apps/kubernetes/images/ubuntu-container-disk-v1.34.tag
@@ -0,0 +1 @@
+ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.34@sha256:97bcf946a5687889c6a421d14e5adece11f0978151b2165dc87b28f77f7607db
diff --git a/packages/apps/kubernetes/images/ubuntu-container-disk-v1.35.tag b/packages/apps/kubernetes/images/ubuntu-container-disk-v1.35.tag
new file mode 100644
index 00000000..faae83d2
--- /dev/null
+++ b/packages/apps/kubernetes/images/ubuntu-container-disk-v1.35.tag
@@ -0,0 +1 @@
+ghcr.io/cozystack/cozystack/ubuntu-container-disk:v1.35@sha256:364c6d454891f1eb1a598fddb69cf328a14dbc451a8ac65812b038a7756da60a
diff --git a/packages/apps/kubernetes/templates/_helpers.tpl b/packages/apps/kubernetes/templates/_helpers.tpl
index 36c06b64..40a8ae7a 100644
--- a/packages/apps/kubernetes/templates/_helpers.tpl
+++ b/packages/apps/kubernetes/templates/_helpers.tpl
@@ -49,3 +49,52 @@ Selector labels
 app.kubernetes.io/name: {{ include "kubernetes.name" . }}
 app.kubernetes.io/instance: {{ .Release.Name }}
 {{- end }}
+
+{{/*
+wait-for-kubeconfig init container shared by the control-plane-side
+Deployments (cluster-autoscaler, kccm, kcsi-controller) that mount the
+*-admin-kubeconfig Secret provisioned asynchronously by Kamaji. The
+Secret volume is declared optional so kubelet does not FailedMount while
+Kamaji is still bootstrapping; this container polls the mounted path and
+exits only when super-admin.svc appears, which happens after kubelet's
+optional-Secret refresh cycle.
+
+The 10m deadline stays strictly below the 15m HelmRelease
+Install.Timeout set by cozystack-api for the Kubernetes kind (via the
+release.cozystack.io/helm-install-timeout annotation) so the
+CrashLoopBackOff surfaces before flux remediation fires and uninstalls
+the Cluster CR.
+
+The default image lives in images/busybox.tag and points directly at
+docker.io by digest (not mirrored to ghcr.io like the other .tag files
+here): the payload is a one-shot sh loop and the digest pin makes the
+pull immutable. Operators in air-gapped or rate-limited environments
+can override it via .Values.images.waitForKubeconfig (any registry
+reference kubelet can pull). When the value is empty the chart falls
+back to the bundled digest pin, preserving the prior default.
+
+Call site owns the surrounding volumes block; the kubeconfig volume
+must exist on the pod and mount at /etc/kubernetes/kubeconfig.
+*/}}
+{{- define "kubernetes.waitForAdminKubeconfig" -}}
+- name: wait-for-kubeconfig
+  image: "{{ default (.Files.Get "images/busybox.tag" | trim) .Values.images.waitForKubeconfig }}"
+  command:
+  - sh
+  - -c
+  - |
+    set -eu
+    deadline=$(( $(date +%s) + 600 ))
+    until [ -s /etc/kubernetes/kubeconfig/super-admin.svc ]; do
+      if [ "$(date +%s)" -ge "$deadline" ]; then
+        echo "admin kubeconfig was not provisioned within 10m; exiting so the pod goes CrashLoopBackOff and surfaces in dashboards" >&2
+        exit 1
+      fi
+      echo "waiting for admin kubeconfig (provisioned by Kamaji, visible after kubelet Secret refresh)..."
+      sleep 5
+    done
+  volumeMounts:
+  - name: kubeconfig
+    mountPath: /etc/kubernetes/kubeconfig
+    readOnly: true
+{{- end }}
diff --git a/packages/apps/kubernetes/templates/_versions.tpl b/packages/apps/kubernetes/templates/_versions.tpl
new file mode 100644
index 00000000..403caff1
--- /dev/null
+++ b/packages/apps/kubernetes/templates/_versions.tpl
@@ -0,0 +1,14 @@
+{{- define "kubernetes.versionMap" }}
+{{- $versionMap := .Files.Get "files/versions.yaml" | fromYaml }}
+{{- if not (hasKey $versionMap .Values.version) }}
+    {{- printf `Kubernetes version %s is not supported, allowed versions are %s` $.Values.version (keys $versionMap) | fail }}
+{{- end }}
+{{- index $versionMap .Values.version }}
+{{- end }}
+
+{{- define "kubernetes.konnectivityVersion" }}
+{{- $konnVersionMap := .Files.Get "files/konnectivity-versions.yaml" | fromYaml }}
+{{- if hasKey $konnVersionMap .Values.version }}
+{{- index $konnVersionMap .Values.version }}
+{{- end }}
+{{- end }}
diff --git a/packages/apps/kubernetes/templates/cloud-config.yaml b/packages/apps/kubernetes/templates/cloud-config.yaml
index b1399b11..a4b7f2c9 100644
--- a/packages/apps/kubernetes/templates/cloud-config.yaml
+++ b/packages/apps/kubernetes/templates/cloud-config.yaml
@@ -10,3 +10,8 @@ data:
       enableEPSController: true
       selectorless: true
     namespace: {{ .Release.Namespace }}
+    infraLabels:
+      apps.cozystack.io/application.group: apps.cozystack.io
+      apps.cozystack.io/application.kind: Kubernetes
+      apps.cozystack.io/application.name: {{ .Release.Name | trimPrefix "kubernetes-" }}
+      internal.cozystack.io/tenantresource: "true"
diff --git a/packages/apps/kubernetes/templates/cluster-autoscaler/deployment.yaml b/packages/apps/kubernetes/templates/cluster-autoscaler/deployment.yaml
index a00e0155..298d86db 100644
--- a/packages/apps/kubernetes/templates/cluster-autoscaler/deployment.yaml
+++ b/packages/apps/kubernetes/templates/cluster-autoscaler/deployment.yaml
@@ -1,3 +1,14 @@
+{{- /*
+  Gate the control-plane-side workloads on the parent tenant having an etcd
+  DataStore. Without it no KamajiControlPlane is ever created, Kamaji never
+  provisions -admin-kubeconfig, and rendering these Deployments would cause
+  the wait-for-kubeconfig init to CrashLoopBackOff indefinitely, consuming
+  the parent HelmRelease install timeout and triggering the very uninstall
+  remediation cycle this chart is supposed to avoid. Rendering them only
+  when $etcd is set keeps the HelmRelease Ready while flux retries on its
+  interval and picks up the DataStore as soon as the Tenant chart finishes.
+*/}}
+{{- if .Values._namespace.etcd }}
 ---
 apiVersion: apps/v1
 kind: Deployment
@@ -23,6 +34,8 @@ spec:
         - key: node-role.kubernetes.io/control-plane
           operator: Exists
           effect: "NoSchedule"
+      initContainers:
+      {{- include "kubernetes.waitForAdminKubeconfig" $ | nindent 6 }}
       containers:
       - image: "{{ $.Files.Get "images/cluster-autoscaler.tag" | trim }}"
         name: cluster-autoscaler
@@ -56,6 +69,7 @@ spec:
         name: cloud-config
       - secret:
           secretName: {{ .Release.Name }}-admin-kubeconfig
+          optional: true
         name: kubeconfig
       serviceAccountName: {{ .Release.Name }}-cluster-autoscaler
       terminationGracePeriodSeconds: 10
@@ -105,3 +119,4 @@ rules:
     - list
     - update
     - watch
+{{- end }}
diff --git a/packages/apps/kubernetes/templates/cluster.yaml b/packages/apps/kubernetes/templates/cluster.yaml
index 7f3144a1..e1494e64 100644
--- a/packages/apps/kubernetes/templates/cluster.yaml
+++ b/packages/apps/kubernetes/templates/cluster.yaml
@@ -1,7 +1,17 @@
-{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }}
-{{- $etcd := index $myNS.metadata.annotations "namespace.cozystack.io/etcd" }}
-{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }}
-{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }}
+{{- $etcd := .Values._namespace.etcd }}
+{{- /*
+  When $etcd is empty, the parent Tenant application has not populated
+  _namespace.etcd in cozystack-values yet - either the operator forgot to
+  set etcd: true on an ancestor Tenant, or the Tenant HelmRelease is still
+  reconciling. Either way, rendering a KamajiControlPlane with an empty
+  dataStoreName would be rejected by Kamaji's admission webhook and the
+  HelmRelease would fail to install, triggering remediation. Instead, emit
+  a single ConfigMap as a user-visible status beacon and skip the rest so
+  flux marks the HelmRelease Ready and retries its 5m reconcile loop until
+  the Tenant chart catches up.
+*/}}
+{{- $ingress := .Values._namespace.ingress }}
+{{- $host := .Values._namespace.host }}
 {{- $kubevirtmachinetemplateNames := list }}
 {{- define "kubevirtmachinetemplate" -}}
 spec:
@@ -31,9 +41,8 @@ spec:
             {{- end }}
             cluster.x-k8s.io/deployment-name: {{ $.Release.Name }}-{{ .groupName }}
         spec:
-          {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }}
-          {{- if $configMap }}
-          {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }}
+          {{- if .Values._cluster.scheduling }}
+          {{- $rawConstraints := get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }}
           {{- if $rawConstraints }}
           {{- $rawConstraints | fromYaml | toYaml | nindent 10 }}
             labelSelector:
@@ -72,11 +81,13 @@ spec:
             memory:
               guest: {{ .group.resources.memory }}
             {{- end }}
+            resources:
+              {{- include "cozy-lib.resources.sanitize" (list (dict "ephemeral-storage" .group.ephemeralStorage) $) | nindent 14 }}
           evictionStrategy: External
           volumes:
           - name: system
             containerDisk:
-              image: "{{ $.Files.Get "images/ubuntu-container-disk.tag" | trim }}"
+              image: "{{ $.Files.Get (printf "images/ubuntu-container-disk-%s.tag" $.Values.version) | trim }}"
           - name: ephemeral
             emptyDisk:
               capacity: {{ .group.ephemeralStorage | default "20Gi" }}
@@ -84,6 +95,26 @@ spec:
           - name: default
             pod: {}
 {{- end }}
+{{- if not $etcd }}
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ .Release.Name }}-awaiting-etcd
+  namespace: {{ .Release.Namespace }}
+  labels:
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    app.kubernetes.io/name: kubernetes
+    app.kubernetes.io/instance: {{ .Release.Name }}
+data:
+  status: "awaiting-etcd"
+  message: |
+    No DataStore is available for this tenant Kubernetes cluster. The parent
+    Tenant application has not populated _namespace.etcd. Set spec.etcd: true
+    on an ancestor Tenant (usually tenant-root) and wait for its HelmRelease
+    to reconcile - this HelmRelease will pick up the DataStore on its next
+    5m reconcile loop and provision the cluster.
+{{- else }}
 ---
 apiVersion: cluster.x-k8s.io/v1beta1
 kind: Cluster
@@ -127,12 +158,17 @@ spec:
     resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.controlPlane.scheduler.resourcesPreset .Values.controlPlane.scheduler.resources $) | nindent 6 }}
   dataStoreName: "{{ $etcd }}"
   addons:
-    coreDNS:
-      dnsServiceIPs:
-      - 10.95.0.10
     konnectivity:
+      {{- $konnVersion := include "kubernetes.konnectivityVersion" $ | trim }}
+      {{- if $konnVersion }}
+      agent:
+        version: {{ $konnVersion }}
+      {{- end }}
       server:
         port: 8132
+        {{- if $konnVersion }}
+        version: {{ $konnVersion }}
+        {{- end }}
         resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.controlPlane.konnectivity.server.resourcesPreset .Values.controlPlane.konnectivity.server.resources $) | nindent 10 }}
   kubelet:
     cgroupfs: systemd
@@ -150,8 +186,8 @@ spec:
     podAdditionalMetadata:
       labels:
         policy.cozystack.io/allow-to-etcd: "true"
-  replicas: 2
-  version: {{ $.Chart.AppVersion }}
+  replicas: {{ .Values.controlPlane.replicas }}
+  version: {{ include "kubernetes.versionMap" $ }}
 ---
 apiVersion: cozystack.io/v1alpha1
 kind: WorkloadMonitor
@@ -185,6 +221,33 @@ metadata:
 spec:
   template:
     spec:
+      files:
+      - path: /usr/bin/update-k8s.sh
+        owner: root:root
+        permissions: "0755"
+        content: |
+          #!/usr/bin/env bash
+          set -euo pipefail
+
+          # Expected to be passed in via preKubeadmCommands
+          : "${KUBELET_VERSION:?KUBELET_VERSION must be set, e.g. v1.31.0}"
+
+          ARCH="$(uname -m)"
+          case "${ARCH}" in
+            x86_64) ARCH=amd64 ;;
+            aarch64) ARCH=arm64 ;;
+          esac
+
+          # Use your internal mirror here for real-world use.
+          BASE_URL="https://dl.k8s.io/release/${KUBELET_VERSION}/bin/linux/${ARCH}"
+
+          echo "Installing kubelet and kubeadm  ${KUBELET_VERSION} for ${ARCH}..."
+          curl -fsSL "${BASE_URL}/kubelet" -o /root/kubelet
+          curl -fsSL "${BASE_URL}/kubeadm" -o /root/kubeadm
+          chmod 0755 /root/kubelet
+          chmod 0755 /root/kubeadm
+          if /root/kubelet --version ; then mv /root/kubelet /usr/bin/kubelet ; fi
+          if /root/kubeadm version ; then mv /root/kubeadm /usr/bin/kubeadm ; fi
       diskSetup:
         filesystems:
         - device: /dev/vdb
@@ -208,6 +271,7 @@ spec:
         {{- end }}
       {{- end }}
       preKubeadmCommands:
+      - KUBELET_VERSION={{ include "kubernetes.versionMap" $}} /usr/bin/update-k8s.sh || true
       - sed -i 's|root:x:|root::|' /etc/passwd
       - systemctl stop containerd.service
       - mkdir -p /ephemeral/kubelet /ephemeral/containerd
@@ -218,6 +282,9 @@ spec:
       joinConfiguration:
         nodeRegistration:
           kubeletExtraArgs: {}
+          # Ignore this for 1.31
+          ignorePreflightErrors:
+          - FileExisting-conntrack
         discovery:
           bootstrapToken:
             apiServerEndpoint: {{ $.Release.Name }}.{{ $.Release.Namespace }}.svc:6443
@@ -269,6 +336,16 @@ metadata:
     {{- end }}
 spec:
   clusterName: {{ $.Release.Name }}
+  replicas: 2
+  strategy:
+    rollingUpdate:
+      maxSurge: {{ $group.maxReplicas }}
+      maxUnavailable: 1
+    type: RollingUpdate
+  selector:
+    matchLabels:
+      cluster.x-k8s.io/cluster-name: {{ $.Release.Name }}
+      cluster.x-k8s.io/deployment-name: {{ $.Release.Name }}-{{ $groupName }}
   template:
     metadata:
       labels:
@@ -290,7 +367,7 @@ spec:
         kind: KubevirtMachineTemplate
         name: {{ $.Release.Name }}-{{ $groupName }}-{{ $kubevirtmachinetemplateHash }}
         namespace: {{ $.Release.Namespace }}
-      version: v{{ $.Chart.AppVersion }}
+      version: {{ include "kubernetes.versionMap" $}}
 ---
 apiVersion: cluster.x-k8s.io/v1beta1
 kind: MachineHealthCheck
@@ -299,6 +376,7 @@ metadata:
   namespace: {{ $.Release.Namespace }}
 spec:
   clusterName: {{ $.Release.Name }}
+  maxUnhealthy: 0
   nodeStartupTimeout: 10m
   selector:
     matchLabels:
@@ -357,3 +435,4 @@ metadata:
 spec:
   {{- .spec | toYaml | nindent 2 }}
 {{- end }}
+{{- end }}
diff --git a/packages/apps/kubernetes/templates/csi/deploy.yaml b/packages/apps/kubernetes/templates/csi/deploy.yaml
index 27a37454..de62104c 100644
--- a/packages/apps/kubernetes/templates/csi/deploy.yaml
+++ b/packages/apps/kubernetes/templates/csi/deploy.yaml
@@ -1,3 +1,4 @@
+{{- if .Values._namespace.etcd }}
 kind: Deployment
 apiVersion: apps/v1
 metadata:
@@ -24,6 +25,8 @@ spec:
         - key: node-role.kubernetes.io/control-plane
           operator: Exists
           effect: "NoSchedule"
+      initContainers:
+      {{- include "kubernetes.waitForAdminKubeconfig" $ | nindent 6 }}
       containers:
         - name: csi-driver
           imagePullPolicy: Always
@@ -32,6 +35,7 @@ spec:
             - "--endpoint=$(CSI_ENDPOINT)"
             - "--infra-cluster-namespace=$(INFRACLUSTER_NAMESPACE)"
             - "--infra-cluster-labels=$(INFRACLUSTER_LABELS)"
+            - "--run-node-service=false"
             - "--v=5"
           ports:
             - name: healthz
@@ -69,6 +73,11 @@ spec:
             requests:
               cpu: 125m
               memory: 128Mi
+          securityContext:
+            capabilities:
+              drop:
+              - ALL
+            readOnlyRootFilesystem: true
         - name: csi-provisioner
           image: quay.io/openshift/origin-csi-external-provisioner:latest
           resources:
@@ -78,6 +87,11 @@ spec:
             requests:
               cpu: 125m
               memory: 128Mi
+          securityContext:
+            capabilities:
+              drop:
+              - ALL
+            readOnlyRootFilesystem: true
           args:
             - "--csi-address=$(ADDRESS)"
             - "--default-fstype=ext4"
@@ -118,6 +132,11 @@ spec:
             requests:
               cpu: 125m
               memory: 128Mi
+          securityContext:
+            capabilities:
+              drop:
+              - ALL
+            readOnlyRootFilesystem: true
         - name: csi-liveness-probe
           image: quay.io/openshift/origin-csi-livenessprobe:latest
           args:
@@ -134,9 +153,90 @@ spec:
             requests:
               cpu: 125m
               memory: 128Mi
+          securityContext:
+            capabilities:
+              drop:
+              - ALL
+            readOnlyRootFilesystem: true
+        - name: csi-snapshotter
+          args:
+          - --timeout=1m
+          - --csi-address=$(ADDRESS)
+          - --worker-threads=10
+          - --kubeconfig=/etc/kubernetes/kubeconfig/super-admin.svc
+          env:
+          - name: ADDRESS
+            value: /csi/csi.sock
+          image: registry.k8s.io/sig-storage/csi-snapshotter:v8.3.0
+          imagePullPolicy: IfNotPresent
+          resources:
+            limits:
+              cpu: 512m
+              memory: 512Mi
+            requests:
+              cpu: 125m
+              memory: 128Mi
+          securityContext:
+            capabilities:
+              drop:
+              - ALL
+            readOnlyRootFilesystem: true
+          volumeMounts:
+          - mountPath: /csi
+            name: socket-dir
+          - mountPath: /etc/kubernetes/kubeconfig
+            name: kubeconfig
+            readOnly: true
+        - name: snapshot-controller
+          image: registry.k8s.io/sig-storage/snapshot-controller:v8.3.0
+          args:
+            - --worker-threads=10
+            - --kubeconfig=/etc/kubernetes/kubeconfig/super-admin.svc
+          imagePullPolicy: IfNotPresent
+          resources:
+            limits:
+              cpu: 512m
+              memory: 512Mi
+            requests:
+              cpu: 125m
+              memory: 128Mi
+          securityContext:
+            capabilities:
+              drop:
+              - ALL
+            readOnlyRootFilesystem: true
+          volumeMounts:
+          - mountPath: /etc/kubernetes/kubeconfig
+            name: kubeconfig
+            readOnly: true
+        - name: csi-resizer
+          image: registry.k8s.io/sig-storage/csi-resizer:v1.13.1
+          args:
+            - "-csi-address=/csi/csi.sock"
+            - "-kubeconfig=/etc/kubernetes/kubeconfig/super-admin.svc"
+            - "-v=5"
+            - "-timeout=3m"
+            - '-handle-volume-inuse-error=false'
+          volumeMounts:
+            - mountPath: /csi
+              name: socket-dir
+            - mountPath: /etc/kubernetes/kubeconfig
+              name: kubeconfig
+              readOnly: true
+          resources:
+            requests:
+              cpu: 10m
+              memory: 20Mi
+          securityContext:
+            capabilities:
+              drop:
+              - ALL
+            readOnlyRootFilesystem: true
       volumes:
         - name: socket-dir
           emptyDir: {}
         - secret:
             secretName: {{ .Release.Name }}-admin-kubeconfig
+            optional: true
           name: kubeconfig
+{{- end }}
diff --git a/packages/apps/kubernetes/templates/csi/infra-cluster-service-account.yaml b/packages/apps/kubernetes/templates/csi/infra-cluster-service-account.yaml
index bbd6ff09..fb11ab25 100644
--- a/packages/apps/kubernetes/templates/csi/infra-cluster-service-account.yaml
+++ b/packages/apps/kubernetes/templates/csi/infra-cluster-service-account.yaml
@@ -24,6 +24,9 @@ rules:
 - apiGroups: [""]
   resources: ["persistentvolumeclaims"]
   verbs: ["get", "patch"]
+- apiGroups: ["cilium.io"]
+  resources: ["ciliumnetworkpolicies"]
+  verbs: ["get", "create", "update", "delete"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: RoleBinding
@@ -36,3 +39,25 @@ roleRef:
 subjects:
 - kind: ServiceAccount
   name: {{ .Release.Name }}-kcsi
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: {{ .Release.Name }}-kcsi
+rules:
+- apiGroups: [""]
+  resources: ["persistentvolumes"]
+  verbs: ["get"]
+---
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: {{ .Release.Name }}-kcsi-binding
+roleRef:
+  kind: ClusterRole
+  name: {{ .Release.Name }}-kcsi
+  apiGroup: rbac.authorization.k8s.io
+subjects:
+- kind: ServiceAccount
+  name: {{ .Release.Name }}-kcsi
+  namespace: {{ .Release.Namespace }}
diff --git a/packages/apps/kubernetes/templates/delete.yaml b/packages/apps/kubernetes/templates/delete.yaml
new file mode 100644
index 00000000..702ba542
--- /dev/null
+++ b/packages/apps/kubernetes/templates/delete.yaml
@@ -0,0 +1,149 @@
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  annotations:
+    "helm.sh/hook": pre-delete
+    "helm.sh/hook-weight": "10"
+    "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation
+  name: {{ .Release.Name }}-pre-cleanup
+spec:
+  template:
+    metadata:
+      labels:
+        policy.cozystack.io/allow-to-apiserver: "true"
+    spec:
+      serviceAccountName: {{ .Release.Name }}-cleanup
+      restartPolicy: Never
+      tolerations:
+        - key: CriticalAddonsOnly
+          operator: Exists
+        - key: node-role.kubernetes.io/control-plane
+          operator: Exists
+          effect: "NoSchedule"
+      containers:
+        - name: kubectl
+          image: docker.io/clastix/kubectl:v1.32
+          command:
+            - /bin/sh
+            - -c
+            - |
+              set -e
+              echo "Step 1: Suspending all HelmReleases with label cozystack.io/target-cluster-name={{ .Release.Name }}"
+              for hr in $(kubectl -n {{ .Release.Namespace }} get helmreleases.helm.toolkit.fluxcd.io -l "cozystack.io/target-cluster-name={{ .Release.Name }}" -o name 2>/dev/null || true); do
+                if [ -n "$hr" ]; then           
+                  echo "  Suspending $hr"
+                  kubectl -n {{ .Release.Namespace }} patch "$hr" \
+                    -p '{"spec": {"suspend": true}}' \
+                    --type=merge --field-manager=flux-client-side-apply
+                fi
+              done
+
+              echo "Step 2: Deleting HelmReleases with label cozystack.io/target-cluster-name={{ .Release.Name }}"
+              kubectl -n {{ .Release.Namespace }} delete helmreleases.helm.toolkit.fluxcd.io \
+                -l "cozystack.io/target-cluster-name={{ .Release.Name }}" \
+                --ignore-not-found=true --wait=true
+
+              echo "Step 3: Deleting KamajiControlPlane {{ .Release.Name }}"
+              kubectl -n {{ .Release.Namespace }} delete kamajicontrolplanes.controlplane.cluster.x-k8s.io {{ .Release.Name }} \
+                --ignore-not-found=true
+
+              echo "Step 4: Deleting TenantControlPlane {{ .Release.Name }}"
+              kubectl -n {{ .Release.Namespace }} delete tenantcontrolplanes.kamaji.clastix.io {{ .Release.Name }} \
+                --ignore-not-found=true
+
+              echo "Step 5: Cleaning up DataVolumes"
+              kubectl -n {{ .Release.Namespace }} delete datavolumes \
+                -l "cluster.x-k8s.io/cluster-name={{ .Release.Name }}" \
+                --ignore-not-found=true
+
+              echo "Step 6: Cleaning up LoadBalancer Services"
+              kubectl -n {{ .Release.Namespace }} delete services \
+                -l "cluster.x-k8s.io/cluster-name={{ .Release.Name }}" \
+                --field-selector spec.type=LoadBalancer \
+                --ignore-not-found=true
+
+              echo "Cleanup completed successfully"
+
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ .Release.Name }}-cleanup
+  annotations:
+    helm.sh/hook: pre-delete
+    helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation,hook-failed
+    helm.sh/hook-weight: "0"
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  annotations:
+    "helm.sh/hook": pre-delete
+    "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed
+    "helm.sh/hook-weight": "5"
+  name: {{ .Release.Name }}-cleanup
+rules:
+  - apiGroups:
+      - "helm.toolkit.fluxcd.io"
+    resources:
+      - helmreleases
+    verbs:
+      - get
+      - list
+      - watch
+      - patch
+      - delete
+  - apiGroups:
+      - "controlplane.cluster.x-k8s.io"
+    resources:
+      - kamajicontrolplanes
+    verbs:
+      - get
+      - list
+      - watch
+      - delete
+  - apiGroups:
+      - "kamaji.clastix.io"
+    resources:
+      - tenantcontrolplanes
+    verbs:
+      - get
+      - list
+      - watch
+      - delete
+  - apiGroups:
+      - "cdi.kubevirt.io"
+    resources:
+      - datavolumes
+    verbs:
+      - get
+      - list
+      - watch
+      - delete
+  - apiGroups:
+      - ""
+    resources:
+      - services
+    verbs:
+      - get
+      - list
+      - watch
+      - delete
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  annotations:
+    "helm.sh/hook": pre-delete
+    "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed
+    "helm.sh/hook-weight": "5"
+  name: {{ .Release.Name }}-cleanup
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: {{ .Release.Name }}-cleanup
+subjects:
+  - kind: ServiceAccount
+    name: {{ .Release.Name }}-cleanup
+    namespace: {{ .Release.Namespace }}
diff --git a/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml
index 7dc3eed1..fd9dac7e 100644
--- a/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml
+++ b/packages/apps/kubernetes/templates/helmreleases/cert-manager-crds.yaml
@@ -1,4 +1,4 @@
-{{- if .Values.addons.certManager.enabled }}
+{{- if and .Values.addons.certManager.enabled .Values._namespace.etcd }}
 apiVersion: helm.toolkit.fluxcd.io/v2
 kind: HelmRelease
 metadata:
@@ -6,29 +6,27 @@ metadata:
   labels:
     cozystack.io/repository: system
     cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
 spec:
-  interval: 5m
   releaseName: cert-manager-crds
-  chart:
-    spec:
-      chart: cozy-cert-manager-crds
-      reconcileStrategy: Revision
-      sourceRef:
-        kind: HelmRepository
-        name: cozystack-system
-        namespace: cozy-system
-      version: '>= 0.0.0-0'
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-cert-manager-crds
+    namespace: cozy-system
   kubeConfig:
     secretRef:
       name: {{ .Release.Name }}-admin-kubeconfig
       key: super-admin.svc
   targetNamespace: cozy-cert-manager-crds
   storageNamespace: cozy-cert-manager-crds
+  interval: 5m
+  timeout: 10m
   install:
     createNamespace: true
     remediation:
       retries: -1
   upgrade:
+    force: true
     remediation:
       retries: -1
   {{- if .Values.addons.certManager.valuesOverride }}
@@ -43,8 +41,6 @@ spec:
   - name: {{ .Release.Name }}
     namespace: {{ .Release.Namespace }}
   {{- end }}
-  - name: {{ .Release.Name }}-cilium
-    namespace: {{ .Release.Namespace }}
 {{- if .Values.addons.certManager.valuesOverride }}
 ---
 apiVersion: v1
diff --git a/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml b/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml
index 3a6e4939..700b666e 100644
--- a/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml
+++ b/packages/apps/kubernetes/templates/helmreleases/cert-manager.yaml
@@ -1,4 +1,14 @@
-{{- if .Values.addons.certManager.enabled }}
+{{- define "cozystack.defaultCertManagerValues" -}}
+{{- if $.Values.addons.gatewayAPI.enabled }}
+cert-manager:
+  config:
+    apiVersion: controller.config.cert-manager.io/v1alpha1
+    kind: ControllerConfiguration
+    enableGatewayAPI: true
+{{- end }}
+{{- end }}
+
+{{- if and .Values.addons.certManager.enabled .Values._namespace.etcd }}
 apiVersion: helm.toolkit.fluxcd.io/v2
 kind: HelmRelease
 metadata:
@@ -6,36 +16,31 @@ metadata:
   labels:
     cozystack.io/repository: system
     cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
 spec:
-  interval: 5m
   releaseName: cert-manager
-  chart:
-    spec:
-      chart: cozy-cert-manager
-      reconcileStrategy: Revision
-      sourceRef:
-        kind: HelmRepository
-        name: cozystack-system
-        namespace: cozy-system
-      version: '>= 0.0.0-0'
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-cert-manager
+    namespace: cozy-system
   kubeConfig:
     secretRef:
       name: {{ .Release.Name }}-admin-kubeconfig
       key: super-admin.svc
   targetNamespace: cozy-cert-manager
   storageNamespace: cozy-cert-manager
+  interval: 5m
+  timeout: 10m
   install:
     createNamespace: true
     remediation:
       retries: -1
   upgrade:
+    force: true
     remediation:
       retries: -1
-  {{- with .Values.addons.certManager.valuesOverride }}
   values:
-    {{- toYaml . | nindent 4 }}
-  {{- end }}
-
+    {{- toYaml (deepCopy .Values.addons.certManager.valuesOverride | mergeOverwrite (fromYaml (include "cozystack.defaultCertManagerValues" .))) | 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/cilium.yaml b/packages/apps/kubernetes/templates/helmreleases/cilium.yaml
index 7e8c7480..d8c90cbf 100644
--- a/packages/apps/kubernetes/templates/helmreleases/cilium.yaml
+++ b/packages/apps/kubernetes/templates/helmreleases/cilium.yaml
@@ -3,6 +3,7 @@ cilium:
   k8sServiceHost: {{ .Release.Name }}.{{ .Release.Namespace }}.svc
   k8sServicePort: 6443
   routingMode: tunnel
+  MTU: 1350
   enableIPv4Masquerade: true
   ipv4NativeRoutingCIDR: ""
   {{- if $.Values.addons.gatewayAPI.enabled }}
@@ -13,6 +14,7 @@ cilium:
   {{- end }}
 {{- end }}
 
+{{- if .Values._namespace.etcd }}
 apiVersion: helm.toolkit.fluxcd.io/v2
 kind: HelmRelease
 metadata:
@@ -20,29 +22,27 @@ metadata:
   labels:
     cozystack.io/repository: system
     cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
 spec:
-  interval: 5m
   releaseName: cilium
-  chart:
-    spec:
-      chart: cozy-cilium
-      reconcileStrategy: Revision
-      sourceRef:
-        kind: HelmRepository
-        name: cozystack-system
-        namespace: cozy-system
-      version: '>= 0.0.0-0'
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-cilium
+    namespace: cozy-system
   kubeConfig:
     secretRef:
       name: {{ .Release.Name }}-admin-kubeconfig
       key: super-admin.svc
   targetNamespace: cozy-cilium
   storageNamespace: cozy-cilium
+  interval: 5m
+  timeout: 10m
   install:
     createNamespace: true
     remediation:
       retries: -1
   upgrade:
+    force: true
     remediation:
       retries: -1
   values:
@@ -56,3 +56,4 @@ spec:
   - name: {{ .Release.Name }}-gateway-api-crds
     namespace: {{ .Release.Namespace }}
   {{- end }}
+{{- end }}
diff --git a/packages/apps/kubernetes/templates/helmreleases/coredns.yaml b/packages/apps/kubernetes/templates/helmreleases/coredns.yaml
new file mode 100644
index 00000000..0711a51d
--- /dev/null
+++ b/packages/apps/kubernetes/templates/helmreleases/coredns.yaml
@@ -0,0 +1,46 @@
+{{- define "cozystack.defaultCoreDNSValues" -}}
+coredns:
+  service:
+    clusterIP: "10.95.0.10"
+{{- end }}
+
+{{- if .Values._namespace.etcd }}
+apiVersion: helm.toolkit.fluxcd.io/v2
+kind: HelmRelease
+metadata:
+  name: {{ .Release.Name }}-coredns
+  labels:
+    cozystack.io/repository: system
+    cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
+spec:
+  releaseName: coredns
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-coredns
+    namespace: cozy-system
+  kubeConfig:
+    secretRef:
+      name: {{ .Release.Name }}-admin-kubeconfig
+      key: super-admin.svc
+  targetNamespace: kube-system
+  storageNamespace: kube-system
+  interval: 5m
+  timeout: 10m
+  install:
+    remediation:
+      retries: -1
+  upgrade:
+    force: true
+    remediation:
+      retries: -1
+  values:
+    {{- toYaml (deepCopy .Values.addons.coredns.valuesOverride | mergeOverwrite (fromYaml (include "cozystack.defaultCoreDNSValues" .))) | nindent 4 }}
+  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/csi.yaml b/packages/apps/kubernetes/templates/helmreleases/csi.yaml
index 8bbb1b9d..109d78e1 100644
--- a/packages/apps/kubernetes/templates/helmreleases/csi.yaml
+++ b/packages/apps/kubernetes/templates/helmreleases/csi.yaml
@@ -1,3 +1,4 @@
+{{- if .Values._namespace.etcd }}
 apiVersion: helm.toolkit.fluxcd.io/v2
 kind: HelmRelease
 metadata:
@@ -5,18 +6,14 @@ metadata:
   labels:
     cozystack.io/repository: system
     cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
 spec:
   interval: 5m
   releaseName: csi
-  chart:
-    spec:
-      chart: cozy-kubevirt-csi-node
-      reconcileStrategy: Revision
-      sourceRef:
-        kind: HelmRepository
-        name: cozystack-system
-        namespace: cozy-system
-      version: '>= 0.0.0-0'
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-kubevirt-csi-node
+    namespace: cozy-system
   kubeConfig:
     secretRef:
       name: {{ .Release.Name }}-admin-kubeconfig
@@ -35,7 +32,12 @@ spec:
     storageClass: "{{ . }}"
   {{- end }}
   dependsOn:
+  - name: {{ .Release.Name }}-vsnap-crd
+    namespace: {{ .Release.Namespace }}
+  - name: {{ .Release.Name }}-cilium
+    namespace: {{ .Release.Namespace }}
   {{- 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/delete.yaml b/packages/apps/kubernetes/templates/helmreleases/delete.yaml
deleted file mode 100644
index 2afcc48d..00000000
--- a/packages/apps/kubernetes/templates/helmreleases/delete.yaml
+++ /dev/null
@@ -1,101 +0,0 @@
----
-apiVersion: batch/v1
-kind: Job
-metadata:
-  annotations:
-    "helm.sh/hook": pre-delete
-    "helm.sh/hook-weight": "10"
-    "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed
-  name: {{ .Release.Name }}-flux-teardown
-spec:
-  template:
-    spec:
-      serviceAccountName: {{ .Release.Name }}-flux-teardown
-      restartPolicy: Never
-      tolerations:
-        - key: CriticalAddonsOnly
-          operator: Exists
-        - key: node-role.kubernetes.io/control-plane
-          operator: Exists
-          effect: "NoSchedule"
-      containers:
-        - name: kubectl
-          image: docker.io/clastix/kubectl:v1.32
-          command:
-            - /bin/sh
-            - -c
-            - |
-                kubectl
-                --namespace={{ .Release.Namespace }}
-                patch
-                helmrelease
-                {{ .Release.Name }}-cilium
-                {{ .Release.Name }}-gateway-api-crds
-                {{ .Release.Name }}-csi
-                {{ .Release.Name }}-cert-manager
-                {{ .Release.Name }}-cert-manager-crds
-                {{ .Release.Name }}-vertical-pod-autoscaler
-                {{ .Release.Name }}-vertical-pod-autoscaler-crds
-                {{ .Release.Name }}-ingress-nginx
-                {{ .Release.Name }}-fluxcd-operator
-                {{ .Release.Name }}-fluxcd
-                {{ .Release.Name }}-gpu-operator
-                {{ .Release.Name }}-velero
-                -p '{"spec": {"suspend": true}}'
-                --type=merge --field-manager=flux-client-side-apply || true
----
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  name: {{ .Release.Name }}-flux-teardown
-  annotations:
-    helm.sh/hook: pre-delete
-    helm.sh/hook-delete-policy: before-hook-creation,hook-failed
-    helm.sh/hook-weight: "0"
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: Role
-metadata:
-  annotations:
-    "helm.sh/hook": pre-install,post-install,pre-delete
-    "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed
-    "helm.sh/hook-weight": "5"
-  name: {{ .Release.Name }}-flux-teardown
-rules:
-  - apiGroups:
-      - "helm.toolkit.fluxcd.io"
-    resources:
-      - helmreleases
-    verbs:
-      - get
-      - patch
-    resourceNames:
-      - {{ .Release.Name }}-cilium
-      - {{ .Release.Name }}-csi
-      - {{ .Release.Name }}-cert-manager
-      - {{ .Release.Name }}-cert-manager-crds
-      - {{ .Release.Name }}-vertical-pod-autoscaler
-      - {{ .Release.Name }}-vertical-pod-autoscaler-crds
-      - {{ .Release.Name }}-ingress-nginx
-      - {{ .Release.Name }}-fluxcd-operator
-      - {{ .Release.Name }}-fluxcd
-      - {{ .Release.Name }}-gpu-operator
-      - {{ .Release.Name }}-velero
-
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: RoleBinding
-metadata:
-  annotations:
-    helm.sh/hook: pre-delete
-    helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation,hook-failed
-    helm.sh/hook-weight: "5"
-  name: {{ .Release.Name }}-flux-teardown
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: Role
-  name: {{ .Release.Name }}-flux-teardown
-subjects:
-  - kind: ServiceAccount
-    name: {{ .Release.Name }}-flux-teardown
-    namespace: {{ .Release.Namespace }}
diff --git a/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml b/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml
index 944ce8cf..25fff01c 100644
--- a/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml
+++ b/packages/apps/kubernetes/templates/helmreleases/fluxcd.yaml
@@ -1,4 +1,4 @@
-{{- if .Values.addons.fluxcd.enabled }}
+{{- if and .Values.addons.fluxcd.enabled .Values._namespace.etcd }}
 apiVersion: helm.toolkit.fluxcd.io/v2
 kind: HelmRelease
 metadata:
@@ -6,29 +6,27 @@ metadata:
   labels:
     cozystack.io/repository: system
     cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
 spec:
-  interval: 5m
   releaseName: fluxcd-operator
-  chart:
-    spec:
-      chart: cozy-fluxcd-operator
-      reconcileStrategy: Revision
-      sourceRef:
-        kind: HelmRepository
-        name: cozystack-system
-        namespace: cozy-system
-      version: '>= 0.0.0-0'
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-fluxcd-operator
+    namespace: cozy-system
   kubeConfig:
     secretRef:
       name: {{ .Release.Name }}-admin-kubeconfig
       key: super-admin.svc
   targetNamespace: cozy-fluxcd
   storageNamespace: cozy-fluxcd
+  interval: 5m
+  timeout: 10m
   install:
     createNamespace: true
     remediation:
       retries: -1
   upgrade:
+    force: true
     remediation:
       retries: -1
   values:
@@ -51,18 +49,14 @@ metadata:
   labels:
     cozystack.io/repository: system
     cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
 spec:
   interval: 5m
   releaseName: fluxcd
-  chart:
-    spec:
-      chart: cozy-fluxcd
-      reconcileStrategy: Revision
-      sourceRef:
-        kind: HelmRepository
-        name: cozystack-system
-        namespace: cozy-system
-      version: '>= 0.0.0-0'
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-fluxcd
+    namespace: cozy-system
   kubeConfig:
     secretRef:
       name: {{ .Release.Name }}-kubeconfig
diff --git a/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml
index 230bcdee..b4172ed1 100644
--- a/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml
+++ b/packages/apps/kubernetes/templates/helmreleases/gateway-api-crds.yaml
@@ -1,4 +1,4 @@
-{{- if $.Values.addons.gatewayAPI.enabled }}
+{{- if and $.Values.addons.gatewayAPI.enabled $.Values._namespace.etcd }}
 apiVersion: helm.toolkit.fluxcd.io/v2
 kind: HelmRelease
 metadata:
@@ -6,29 +6,26 @@ metadata:
   labels:
     cozystack.io/repository: system
     cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
 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
-      version: '>= 0.0.0-0'
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-gateway-api-crds
+    namespace: cozy-system
   kubeConfig:
     secretRef:
       name: {{ .Release.Name }}-admin-kubeconfig
       key: super-admin.svc
   targetNamespace: kube-system
   storageNamespace: kube-system
+  interval: 5m
+  timeout: 10m
   install:
-    createNamespace: false
     remediation:
       retries: -1
   upgrade:
+    force: true
     remediation:
       retries: -1
   dependsOn:
diff --git a/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml b/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml
index 861c3657..655dc868 100644
--- a/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml
+++ b/packages/apps/kubernetes/templates/helmreleases/gpu-operator.yaml
@@ -1,4 +1,12 @@
-{{- if .Values.addons.gpuOperator.enabled }}
+{{- define "cozystack.defaultGpuOperatorValues" -}}
+{{- if .Values.addons.hami.enabled }}
+gpu-operator:
+  devicePlugin:
+    enabled: false
+{{- end }}
+{{- end }}
+
+{{- if and .Values.addons.gpuOperator.enabled .Values._namespace.etcd }}
 apiVersion: helm.toolkit.fluxcd.io/v2
 kind: HelmRelease
 metadata:
@@ -6,34 +14,35 @@ metadata:
   labels:
     cozystack.io/repository: system
     cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
 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'
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-gpu-operator
+    namespace: cozy-system
   kubeConfig:
     secretRef:
       name: {{ .Release.Name }}-admin-kubeconfig
       key: super-admin.svc
   targetNamespace: cozy-gpu-operator
   storageNamespace: cozy-gpu-operator
+  interval: 5m
+  timeout: 10m
   install:
     createNamespace: true
     remediation:
       retries: -1
   upgrade:
+    force: true
     remediation:
       retries: -1
-  {{- with .Values.addons.gpuOperator.valuesOverride }}
+  {{- $defaults := fromYaml (include "cozystack.defaultGpuOperatorValues" .) }}
+  {{- $overrides := deepCopy (default (dict) .Values.addons.gpuOperator.valuesOverride) }}
+  {{- $merged := mergeOverwrite (default (dict) $defaults) $overrides }}
+  {{- if $merged }}
   values:
-    {{- toYaml . | nindent 4 }}
+    {{- toYaml $merged | nindent 4 }}
   {{- end }}
 
   dependsOn:
diff --git a/packages/apps/kubernetes/templates/helmreleases/hami.yaml b/packages/apps/kubernetes/templates/helmreleases/hami.yaml
new file mode 100644
index 00000000..f1538c7c
--- /dev/null
+++ b/packages/apps/kubernetes/templates/helmreleases/hami.yaml
@@ -0,0 +1,49 @@
+{{- if and .Values.addons.hami.enabled .Values._namespace.etcd }}
+{{- if not .Values.addons.gpuOperator.enabled }}
+{{- fail "addons.hami requires addons.gpuOperator to be enabled" }}
+{{- end }}
+apiVersion: helm.toolkit.fluxcd.io/v2
+kind: HelmRelease
+metadata:
+  name: {{ .Release.Name }}-hami
+  labels:
+    cozystack.io/repository: system
+    cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
+spec:
+  releaseName: hami
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-hami
+    namespace: cozy-system
+  kubeConfig:
+    secretRef:
+      name: {{ .Release.Name }}-admin-kubeconfig
+      key: super-admin.svc
+  targetNamespace: cozy-hami
+  storageNamespace: cozy-hami
+  interval: 5m
+  timeout: 10m
+  install:
+    createNamespace: true
+    remediation:
+      retries: -1
+  upgrade:
+    force: true
+    remediation:
+      retries: -1
+  {{- with .Values.addons.hami.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 }}
+  - name: {{ .Release.Name }}-gpu-operator
+    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 5d4a586d..6e2183d3 100644
--- a/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml
+++ b/packages/apps/kubernetes/templates/helmreleases/ingress-nginx.yaml
@@ -4,9 +4,12 @@ ingress-nginx:
   controller:
     kind: DaemonSet
     {{- if eq .Values.addons.ingressNginx.exposeMethod "Proxied" }}
-    hostNetwork: true
     service:
-      enabled: false
+      enabled: true
+      type: NodePort
+      nodePorts:
+        http: 30000
+        https: 30001
     {{- end }}
     {{- if not .Values.addons.certManager.enabled }}
     admissionWebhooks:
@@ -17,7 +20,7 @@ ingress-nginx:
     node-role.kubernetes.io/ingress-nginx: ""
 {{- end }}
 
-{{- if .Values.addons.ingressNginx.enabled }}
+{{- if and .Values.addons.ingressNginx.enabled .Values._namespace.etcd }}
 apiVersion: helm.toolkit.fluxcd.io/v2
 kind: HelmRelease
 metadata:
@@ -25,29 +28,27 @@ metadata:
   labels:
     cozystack.io/repository: system
     cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
 spec:
-  interval: 5m
   releaseName: ingress-nginx
-  chart:
-    spec:
-      chart: cozy-ingress-nginx
-      reconcileStrategy: Revision
-      sourceRef:
-        kind: HelmRepository
-        name: cozystack-system
-        namespace: cozy-system
-      version: '>= 0.0.0-0'
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-ingress-nginx
+    namespace: cozy-system
   kubeConfig:
     secretRef:
       name: {{ .Release.Name }}-admin-kubeconfig
       key: super-admin.svc
   targetNamespace: cozy-ingress-nginx
   storageNamespace: cozy-ingress-nginx
+  interval: 5m
+  timeout: 10m
   install:
     createNamespace: true
     remediation:
       retries: -1
   upgrade:
+    force: true
     remediation:
       retries: -1
   values:
diff --git a/packages/apps/kubernetes/templates/helmreleases/metrics-server.yaml b/packages/apps/kubernetes/templates/helmreleases/metrics-server.yaml
new file mode 100644
index 00000000..3e6f9660
--- /dev/null
+++ b/packages/apps/kubernetes/templates/helmreleases/metrics-server.yaml
@@ -0,0 +1,40 @@
+{{- if .Values._namespace.etcd }}
+apiVersion: helm.toolkit.fluxcd.io/v2
+kind: HelmRelease
+metadata:
+  name: {{ .Release.Name }}-metrics-server
+  labels:
+    cozystack.io/repository: system
+    cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
+spec:
+  releaseName: metrics-server
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-metrics-server
+    namespace: cozy-system
+  kubeConfig:
+    secretRef:
+      name: {{ .Release.Name }}-admin-kubeconfig
+      key: super-admin.svc
+  targetNamespace: cozy-monitoring
+  storageNamespace: cozy-monitoring
+  interval: 5m
+  timeout: 10m
+  install:
+    createNamespace: true
+    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 }}
+  - name: {{ .Release.Name }}-cilium
+    namespace: {{ .Release.Namespace }}
+  - name: {{ .Release.Name }}-prometheus-operator-crds
+    namespace: {{ .Release.Namespace }}
+{{- end }}
diff --git a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml
index 94f3c28a..a811f7dd 100644
--- a/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml
+++ b/packages/apps/kubernetes/templates/helmreleases/monitoring-agents.yaml
@@ -1,6 +1,6 @@
-{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }}
-{{- $targetTenant := index $myNS.metadata.annotations "namespace.cozystack.io/monitoring" }}
-{{- if .Values.addons.monitoringAgents.enabled }}
+{{- $targetTenant := .Values._namespace.monitoring }}
+{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }}
+{{- if and .Values.addons.monitoringAgents.enabled .Values._namespace.etcd }}
 apiVersion: helm.toolkit.fluxcd.io/v2
 kind: HelmRelease
 metadata:
@@ -8,30 +8,27 @@ metadata:
   labels:
     cozystack.io/repository: system
     cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
 spec:
-  interval: 5m
   releaseName: cozy-monitoring-agents
-  chart:
-    spec:
-      chart: cozy-monitoring-agents
-      reconcileStrategy: Revision
-      sourceRef:
-        kind: HelmRepository
-        name: cozystack-system
-        namespace: cozy-system
-      version: '>= 0.0.0-0'
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-monitoring-agents
+    namespace: cozy-system
   kubeConfig:
     secretRef:
       name: {{ .Release.Name }}-admin-kubeconfig
       key: super-admin.svc
   targetNamespace: cozy-monitoring
   storageNamespace: cozy-monitoring
+  interval: 5m
+  timeout: 10m
   install:
     createNamespace: true
-    timeout: "300s"
     remediation:
       retries: -1
   upgrade:
+    force: true
     remediation:
       retries: -1
   dependsOn:
@@ -43,13 +40,17 @@ spec:
     namespace: {{ .Release.Namespace }}
   - name: {{ .Release.Name }}-vertical-pod-autoscaler-crds
     namespace: {{ .Release.Namespace }}
+  - name: {{ .Release.Name }}-prometheus-operator-crds
+    namespace: {{ .Release.Namespace }}
+  - name: {{ .Release.Name }}-metrics-server
+    namespace: {{ .Release.Namespace }}
   values:
     vmagent:
       externalLabels:
         cluster: {{ .Release.Name }}
         tenant: {{ .Release.Namespace }}
       remoteWrite:
-        url: http://vminsert-shortterm.{{ $targetTenant }}.svc:8480/insert/0/prometheus
+        url: http://vminsert-shortterm.{{ $targetTenant }}.svc.{{ $clusterDomain }}:8480/insert/0/prometheus
     fluent-bit:
       readinessProbe:
         httpGet:
@@ -72,8 +73,8 @@ spec:
           [OUTPUT]
               Name http
               Match kube.*
-              Host vlogs-generic.{{ $targetTenant }}.svc
-              port 9428
+              Host vlinsert-generic.{{ $targetTenant }}.svc.{{ $clusterDomain }}
+              port 9481
               compress gzip
               uri /insert/jsonline?_stream_fields=stream,kubernetes_pod_name,kubernetes_container_name,kubernetes_namespace_name&_msg_field=log&_time_field=date
               format json_lines
diff --git a/packages/apps/kubernetes/templates/helmreleases/prometheus-operator-crds.yaml b/packages/apps/kubernetes/templates/helmreleases/prometheus-operator-crds.yaml
new file mode 100644
index 00000000..3038a058
--- /dev/null
+++ b/packages/apps/kubernetes/templates/helmreleases/prometheus-operator-crds.yaml
@@ -0,0 +1,35 @@
+{{- if .Values._namespace.etcd }}
+apiVersion: helm.toolkit.fluxcd.io/v2
+kind: HelmRelease
+metadata:
+  name: {{ .Release.Name }}-prometheus-operator-crds
+  labels:
+    cozystack.io/repository: system
+    cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
+spec:
+  releaseName: prometheus-operator-crds
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-prometheus-operator-crds
+    namespace: cozy-system
+  kubeConfig:
+    secretRef:
+      name: {{ .Release.Name }}-admin-kubeconfig
+      key: super-admin.svc
+  targetNamespace: cozy-victoria-metrics-operator
+  storageNamespace: cozy-victoria-metrics-operator
+  interval: 5m
+  install:
+    createNamespace: true
+    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/velero.yaml b/packages/apps/kubernetes/templates/helmreleases/velero.yaml
index 52310767..781b9c49 100644
--- a/packages/apps/kubernetes/templates/helmreleases/velero.yaml
+++ b/packages/apps/kubernetes/templates/helmreleases/velero.yaml
@@ -1,4 +1,4 @@
-{{- if .Values.addons.velero.enabled }}
+{{- if and .Values.addons.velero.enabled .Values._namespace.etcd }}
 apiVersion: helm.toolkit.fluxcd.io/v2
 kind: HelmRelease
 metadata:
@@ -6,29 +6,27 @@ metadata:
   labels:
     cozystack.io/repository: system
     cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
 spec:
-  interval: 5m
   releaseName: velero
-  chart:
-    spec:
-      chart: cozy-velero
-      reconcileStrategy: Revision
-      sourceRef:
-        kind: HelmRepository
-        name: cozystack-system
-        namespace: cozy-system
-      version: '>= 0.0.0-0'
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-velero
+    namespace: cozy-system
   kubeConfig:
     secretRef:
       name: {{ .Release.Name }}-admin-kubeconfig
       key: super-admin.svc
   targetNamespace: cozy-velero
   storageNamespace: cozy-velero
+  interval: 5m
+  timeout: 10m
   install:
     createNamespace: true
     remediation:
       retries: -1
   upgrade:
+    force: true
     remediation:
       retries: -1
   {{- with .Values.addons.velero.valuesOverride }}
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 336c198b..55a5faac 100644
--- a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml
+++ b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler-crds.yaml
@@ -1,4 +1,4 @@
-{{- if .Values.addons.monitoringAgents.enabled }}
+{{- if and .Values.addons.monitoringAgents.enabled .Values._namespace.etcd }}
 apiVersion: helm.toolkit.fluxcd.io/v2
 kind: HelmRelease
 metadata:
@@ -6,18 +6,14 @@ metadata:
   labels:
     cozystack.io/repository: system
     cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
 spec:
   interval: 5m
   releaseName: vertical-pod-autoscaler-crds
-  chart:
-    spec:
-      chart: cozy-vertical-pod-autoscaler-crds
-      reconcileStrategy: Revision
-      sourceRef:
-        kind: HelmRepository
-        name: cozystack-system
-        namespace: cozy-system
-      version: '>= 0.0.0-0'
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-vertical-pod-autoscaler-crds
+    namespace: cozy-system
   kubeConfig:
     secretRef:
       name: {{ .Release.Name }}-admin-kubeconfig
@@ -37,6 +33,4 @@ spec:
   - name: {{ .Release.Name }}
     namespace: {{ .Release.Namespace }}
   {{- end }}
-  - name: {{ .Release.Name }}-cilium
-    namespace: {{ .Release.Namespace }}
 {{- end }}
diff --git a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml
index 0d86b24e..74fb5a39 100644
--- a/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml
+++ b/packages/apps/kubernetes/templates/helmreleases/vertical-pod-autoscaler.yaml
@@ -1,8 +1,7 @@
 {{- define "cozystack.defaultVPAValues" -}}
-{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }}
-{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }}
-{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }}
-{{- $targetTenant := index $myNS.metadata.annotations "namespace.cozystack.io/monitoring" }}
+{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }}
+{{- $targetTenant := .Values._namespace.monitoring }}
+vpaForVPA: false
 vertical-pod-autoscaler:
   recommender:
     extraArgs:
@@ -25,7 +24,7 @@ vertical-pod-autoscaler:
         memory: 1600Mi
 {{- end }}
 
-{{- if .Values.addons.monitoringAgents.enabled }}
+{{- if and .Values.addons.monitoringAgents.enabled .Values._namespace.etcd }}
 apiVersion: helm.toolkit.fluxcd.io/v2
 kind: HelmRelease
 metadata:
@@ -33,29 +32,27 @@ metadata:
   labels:
     cozystack.io/repository: system
     cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
 spec:
-  interval: 5m
   releaseName: vertical-pod-autoscaler
-  chart:
-    spec:
-      chart: cozy-vertical-pod-autoscaler
-      reconcileStrategy: Revision
-      sourceRef:
-        kind: HelmRepository
-        name: cozystack-system
-        namespace: cozy-system
-      version: '>= 0.0.0-0'
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-vertical-pod-autoscaler
+    namespace: cozy-system
   kubeConfig:
     secretRef:
       name: {{ .Release.Name }}-admin-kubeconfig
       key: super-admin.svc
   targetNamespace: cozy-vertical-pod-autoscaler
   storageNamespace: cozy-vertical-pod-autoscaler
+  interval: 5m
+  timeout: 10m
   install:
     createNamespace: true
     remediation:
       retries: -1
   upgrade:
+    force: true
     remediation:
       retries: -1
   values:
diff --git a/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml b/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml
index 91445c45..7302f8f5 100644
--- a/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml
+++ b/packages/apps/kubernetes/templates/helmreleases/victoria-metrics-operator.yaml
@@ -1,4 +1,4 @@
-{{- if .Values.addons.monitoringAgents.enabled }}
+{{- if and .Values.addons.monitoringAgents.enabled .Values._namespace.etcd }}
 apiVersion: helm.toolkit.fluxcd.io/v2
 kind: HelmRelease
 metadata:
@@ -6,29 +6,27 @@ metadata:
   labels:
     cozystack.io/repository: system
     cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
 spec:
-  interval: 5m
   releaseName: cozy-victoria-metrics-operator
-  chart:
-    spec:
-      chart: cozy-victoria-metrics-operator
-      reconcileStrategy: Revision
-      sourceRef:
-        kind: HelmRepository
-        name: cozystack-system
-        namespace: cozy-system
-      version: '>= 0.0.0-0'
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-victoria-metrics-operator
+    namespace: cozy-system
   kubeConfig:
     secretRef:
       name: {{ .Release.Name }}-admin-kubeconfig
       key: super-admin.svc
   targetNamespace: cozy-victoria-metrics-operator
   storageNamespace: cozy-victoria-metrics-operator
+  interval: 5m
+  timeout: 10m
   install:
     createNamespace: true
     remediation:
       retries: -1
   upgrade:
+    force: true
     remediation:
       retries: -1
   dependsOn:
diff --git a/packages/apps/kubernetes/templates/helmreleases/volumesnapshot-crd.yaml b/packages/apps/kubernetes/templates/helmreleases/volumesnapshot-crd.yaml
new file mode 100644
index 00000000..d50fd93c
--- /dev/null
+++ b/packages/apps/kubernetes/templates/helmreleases/volumesnapshot-crd.yaml
@@ -0,0 +1,37 @@
+{{- if .Values._namespace.etcd }}
+apiVersion: helm.toolkit.fluxcd.io/v2
+kind: HelmRelease
+metadata:
+  name: {{ .Release.Name }}-vsnap-crd
+  labels:
+    cozystack.io/repository: system
+    cozystack.io/target-cluster-name: {{ .Release.Name }}
+    sharding.fluxcd.io/key: tenants
+spec:
+  releaseName: vsnap-crd
+  chartRef:
+    kind: ExternalArtifact
+    name: cozystack-kubernetes-application-kubevirt-kubernetes-volumesnapshot-crd
+    namespace: cozy-system
+  kubeConfig:
+    secretRef:
+      name: {{ .Release.Name }}-admin-kubeconfig
+      key: super-admin.svc
+  targetNamespace: cozy-vsnap-crd
+  storageNamespace: cozy-vsnap-crd
+  interval: 5m
+  timeout: 10m
+  install:
+    createNamespace: true
+    remediation:
+      retries: -1
+  upgrade:
+    force: true
+    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/ingress.yaml b/packages/apps/kubernetes/templates/ingress.yaml
index 8dd244cb..4adb7458 100644
--- a/packages/apps/kubernetes/templates/ingress.yaml
+++ b/packages/apps/kubernetes/templates/ingress.yaml
@@ -1,5 +1,4 @@
-{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }}
-{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }}
+{{- $ingress := .Values._namespace.ingress }}
 {{- if and (eq .Values.addons.ingressNginx.exposeMethod "Proxied") .Values.addons.ingressNginx.hosts }}
 ---
 apiVersion: networking.k8s.io/v1
@@ -15,6 +14,11 @@ metadata:
       }
     nginx.ingress.kubernetes.io/ssl-passthrough: "true"
     nginx.ingress.kubernetes.io/ssl-redirect: "false"
+  labels:
+    apps.cozystack.io/application.group: apps.cozystack.io
+    apps.cozystack.io/application.kind: Kubernetes
+    apps.cozystack.io/application.name: {{ .Release.Name | trimPrefix "kubernetes-" }}
+    internal.cozystack.io/tenantresource: "true"
 spec:
   ingressClassName: "{{ $ingress }}"
   rules:
@@ -42,16 +46,21 @@ apiVersion: v1
 kind: Service
 metadata:
   name: {{ .Release.Name }}-ingress-nginx
+  labels:
+    apps.cozystack.io/application.group: apps.cozystack.io
+    apps.cozystack.io/application.kind: Kubernetes
+    apps.cozystack.io/application.name: {{ .Release.Name | trimPrefix "kubernetes-" }}
+    internal.cozystack.io/tenantresource: "true"
 spec:
   ports:
   - appProtocol: http
     name: http
     port: 80
-    targetPort: 80
+    targetPort: 30000
   - appProtocol: https
     name: https
     port: 443
-    targetPort: 443
+    targetPort: 30001
   selector:
     cluster.x-k8s.io/cluster-name: {{ .Release.Name }}
     node-role.kubernetes.io/ingress-nginx: ""
diff --git a/packages/apps/kubernetes/templates/kccm/manager.yaml b/packages/apps/kubernetes/templates/kccm/manager.yaml
index 81426d4e..bd9e2798 100644
--- a/packages/apps/kubernetes/templates/kccm/manager.yaml
+++ b/packages/apps/kubernetes/templates/kccm/manager.yaml
@@ -1,3 +1,4 @@
+{{- if .Values._namespace.etcd }}
 apiVersion: apps/v1
 kind: Deployment
 metadata:
@@ -22,6 +23,8 @@ spec:
         - key: node-role.kubernetes.io/control-plane
           operator: Exists
           effect: "NoSchedule"
+      initContainers:
+      {{- include "kubernetes.waitForAdminKubeconfig" $ | nindent 6 }}
       containers:
       - name: kubevirt-cloud-controller-manager
         args:
@@ -55,5 +58,7 @@ spec:
         name: cloud-config
       - secret:
           secretName: {{ .Release.Name }}-admin-kubeconfig
+          optional: true
         name: kubeconfig
       serviceAccountName: {{ .Release.Name }}-kccm
+{{- end }}
diff --git a/packages/apps/kubernetes/tests/admin_kubeconfig_wait_test.yaml b/packages/apps/kubernetes/tests/admin_kubeconfig_wait_test.yaml
new file mode 100644
index 00000000..507e00af
--- /dev/null
+++ b/packages/apps/kubernetes/tests/admin_kubeconfig_wait_test.yaml
@@ -0,0 +1,155 @@
+suite: admin-kubeconfig wait guards
+
+release:
+  name: test
+  namespace: tenant-root
+
+values:
+  - values-ci.yaml
+
+tests:
+  - it: cluster-autoscaler mounts admin-kubeconfig as optional
+    template: templates/cluster-autoscaler/deployment.yaml
+    documentSelector:
+      path: kind
+      value: Deployment
+    asserts:
+      - equal:
+          path: spec.template.spec.volumes[?(@.name=="kubeconfig")].secret.secretName
+          value: test-admin-kubeconfig
+      - equal:
+          path: spec.template.spec.volumes[?(@.name=="kubeconfig")].secret.optional
+          value: true
+
+  - it: cluster-autoscaler waits for admin-kubeconfig via initContainer
+    template: templates/cluster-autoscaler/deployment.yaml
+    documentSelector:
+      path: kind
+      value: Deployment
+    asserts:
+      - equal:
+          path: spec.template.spec.initContainers[0].name
+          value: wait-for-kubeconfig
+      - contains:
+          path: spec.template.spec.initContainers[0].volumeMounts
+          content:
+            name: kubeconfig
+            mountPath: /etc/kubernetes/kubeconfig
+            readOnly: true
+
+  - it: kccm mounts admin-kubeconfig as optional
+    template: templates/kccm/manager.yaml
+    documentSelector:
+      path: kind
+      value: Deployment
+    asserts:
+      - equal:
+          path: spec.template.spec.volumes[?(@.name=="kubeconfig")].secret.secretName
+          value: test-admin-kubeconfig
+      - equal:
+          path: spec.template.spec.volumes[?(@.name=="kubeconfig")].secret.optional
+          value: true
+
+  - it: kccm waits for admin-kubeconfig via initContainer
+    template: templates/kccm/manager.yaml
+    documentSelector:
+      path: kind
+      value: Deployment
+    asserts:
+      - equal:
+          path: spec.template.spec.initContainers[0].name
+          value: wait-for-kubeconfig
+      - contains:
+          path: spec.template.spec.initContainers[0].volumeMounts
+          content:
+            name: kubeconfig
+            mountPath: /etc/kubernetes/kubeconfig
+            readOnly: true
+
+  - it: csi controller mounts admin-kubeconfig as optional
+    template: templates/csi/deploy.yaml
+    documentSelector:
+      path: kind
+      value: Deployment
+    asserts:
+      - equal:
+          path: spec.template.spec.volumes[?(@.name=="kubeconfig")].secret.secretName
+          value: test-admin-kubeconfig
+      - equal:
+          path: spec.template.spec.volumes[?(@.name=="kubeconfig")].secret.optional
+          value: true
+
+  - it: csi controller waits for admin-kubeconfig via initContainer
+    template: templates/csi/deploy.yaml
+    documentSelector:
+      path: kind
+      value: Deployment
+    asserts:
+      - equal:
+          path: spec.template.spec.initContainers[0].name
+          value: wait-for-kubeconfig
+      - contains:
+          path: spec.template.spec.initContainers[0].volumeMounts
+          content:
+            name: kubeconfig
+            mountPath: /etc/kubernetes/kubeconfig
+            readOnly: true
+
+  - it: wait-for-kubeconfig defaults to bundled busybox digest pin
+    template: templates/cluster-autoscaler/deployment.yaml
+    documentSelector:
+      path: kind
+      value: Deployment
+    asserts:
+      - matchRegex:
+          path: spec.template.spec.initContainers[0].image
+          pattern: '^docker\.io/library/busybox:[^@]+@sha256:[0-9a-f]{64}$'
+
+  - it: wait-for-kubeconfig honours images.waitForKubeconfig override
+    template: templates/cluster-autoscaler/deployment.yaml
+    documentSelector:
+      path: kind
+      value: Deployment
+    set:
+      images:
+        waitForKubeconfig: "registry.example.test/library/busybox:1.37.0@sha256:0000000000000000000000000000000000000000000000000000000000000000"
+    asserts:
+      - equal:
+          path: spec.template.spec.initContainers[0].image
+          value: "registry.example.test/library/busybox:1.37.0@sha256:0000000000000000000000000000000000000000000000000000000000000000"
+
+  - it: cluster.yaml renders and wires dataStoreName when tenant has etcd
+    template: templates/cluster.yaml
+    documentSelector:
+      path: kind
+      value: KamajiControlPlane
+    asserts:
+      - equal:
+          path: spec.dataStoreName
+          value: tenant-root
+
+  - it: cluster.yaml skips Cluster resources when tenant has no etcd DataStore
+    # Must NOT fail rendering - the parent Tenant chart populates
+    # _namespace.etcd asynchronously, so rendering failures here would cause
+    # flux install remediation on every cold bootstrap. Instead, emit only a
+    # ConfigMap status beacon so the HelmRelease reports Ready while flux
+    # retries on its interval until the DataStore appears.
+    template: templates/cluster.yaml
+    set:
+      _namespace:
+        etcd: ""
+        monitoring: ""
+        ingress: ""
+        seaweedfs: ""
+        host: ""
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: ConfigMap
+      - equal:
+          path: metadata.name
+          value: test-awaiting-etcd
+      - equal:
+          path: data.status
+          value: awaiting-etcd
diff --git a/packages/apps/kubernetes/tests/gpu_operator_hami_test.yaml b/packages/apps/kubernetes/tests/gpu_operator_hami_test.yaml
new file mode 100644
index 00000000..44528470
--- /dev/null
+++ b/packages/apps/kubernetes/tests/gpu_operator_hami_test.yaml
@@ -0,0 +1,99 @@
+suite: GPU Operator HelmRelease HAMi integration tests
+templates:
+  - templates/helmreleases/gpu-operator.yaml
+values:
+  - values-ci.yaml
+tests:
+  - it: should disable devicePlugin when hami is enabled
+    set:
+      addons:
+        gpuOperator:
+          enabled: true
+          valuesOverride: {}
+        hami:
+          enabled: true
+          valuesOverride: {}
+    asserts:
+      - equal:
+          path: spec.values.gpu-operator.devicePlugin.enabled
+          value: false
+
+  - it: should not have values when hami is disabled and no overrides
+    set:
+      addons:
+        gpuOperator:
+          enabled: true
+          valuesOverride: {}
+        hami:
+          enabled: false
+          valuesOverride: {}
+    asserts:
+      - notExists:
+          path: spec.values
+
+  - it: should apply hami defaults when valuesOverride key is omitted
+    set:
+      addons:
+        gpuOperator:
+          enabled: true
+        hami:
+          enabled: true
+    asserts:
+      - equal:
+          path: spec.values.gpu-operator.devicePlugin.enabled
+          value: false
+
+  - it: should allow user overrides to merge with hami defaults
+    set:
+      addons:
+        gpuOperator:
+          enabled: true
+          valuesOverride:
+            gpu-operator:
+              driver:
+                enabled: false
+        hami:
+          enabled: true
+          valuesOverride: {}
+    asserts:
+      - equal:
+          path: spec.values.gpu-operator.devicePlugin.enabled
+          value: false
+      - equal:
+          path: spec.values.gpu-operator.driver.enabled
+          value: false
+
+  - it: should let user explicitly override devicePlugin.enabled to true with hami enabled
+    set:
+      addons:
+        gpuOperator:
+          enabled: true
+          valuesOverride:
+            gpu-operator:
+              devicePlugin:
+                enabled: true
+              driver:
+                enabled: false
+        hami:
+          enabled: true
+          valuesOverride: {}
+    asserts:
+      - equal:
+          path: spec.values.gpu-operator.devicePlugin.enabled
+          value: true
+      - equal:
+          path: spec.values.gpu-operator.driver.enabled
+          value: false
+
+  - it: should not render when gpuOperator is disabled
+    set:
+      addons:
+        gpuOperator:
+          enabled: false
+          valuesOverride: {}
+        hami:
+          enabled: false
+          valuesOverride: {}
+    asserts:
+      - hasDocuments:
+          count: 0
diff --git a/packages/apps/kubernetes/tests/hami_test.yaml b/packages/apps/kubernetes/tests/hami_test.yaml
new file mode 100644
index 00000000..27f7c75b
--- /dev/null
+++ b/packages/apps/kubernetes/tests/hami_test.yaml
@@ -0,0 +1,153 @@
+suite: HAMi HelmRelease tests
+templates:
+  - templates/helmreleases/hami.yaml
+values:
+  - values-ci.yaml
+tests:
+  - it: should not render when hami is disabled
+    set:
+      addons:
+        hami:
+          enabled: false
+          valuesOverride: {}
+        gpuOperator:
+          enabled: true
+          valuesOverride: {}
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: should render HelmRelease when hami is enabled
+    set:
+      addons:
+        hami:
+          enabled: true
+          valuesOverride: {}
+        gpuOperator:
+          enabled: true
+          valuesOverride: {}
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: HelmRelease
+
+  - it: should fail when gpuOperator is not enabled
+    set:
+      addons:
+        hami:
+          enabled: true
+          valuesOverride: {}
+        gpuOperator:
+          enabled: false
+          valuesOverride: {}
+    asserts:
+      - failedTemplate:
+          errorMessage: "addons.hami requires addons.gpuOperator to be enabled"
+
+  - it: should have correct metadata labels
+    set:
+      addons:
+        hami:
+          enabled: true
+          valuesOverride: {}
+        gpuOperator:
+          enabled: true
+          valuesOverride: {}
+    asserts:
+      - equal:
+          path: metadata.labels["cozystack.io/repository"]
+          value: system
+      - equal:
+          path: metadata.labels["sharding.fluxcd.io/key"]
+          value: tenants
+
+  - it: should use ExternalArtifact chartRef
+    set:
+      addons:
+        hami:
+          enabled: true
+          valuesOverride: {}
+        gpuOperator:
+          enabled: true
+          valuesOverride: {}
+    asserts:
+      - equal:
+          path: spec.chartRef.kind
+          value: ExternalArtifact
+      - equal:
+          path: spec.chartRef.namespace
+          value: cozy-system
+
+  - it: should target cozy-hami namespace
+    set:
+      addons:
+        hami:
+          enabled: true
+          valuesOverride: {}
+        gpuOperator:
+          enabled: true
+          valuesOverride: {}
+    asserts:
+      - equal:
+          path: spec.targetNamespace
+          value: cozy-hami
+      - equal:
+          path: spec.storageNamespace
+          value: cozy-hami
+
+  - it: should depend on gpu-operator and cilium
+    release:
+      name: test
+      namespace: test-ns
+    set:
+      addons:
+        hami:
+          enabled: true
+          valuesOverride: {}
+        gpuOperator:
+          enabled: true
+          valuesOverride: {}
+    asserts:
+      - contains:
+          path: spec.dependsOn
+          content:
+            name: test-cilium
+            namespace: test-ns
+      - contains:
+          path: spec.dependsOn
+          content:
+            name: test-gpu-operator
+            namespace: test-ns
+
+  - it: should not render spec.values when valuesOverride is empty
+    set:
+      addons:
+        hami:
+          enabled: true
+          valuesOverride: {}
+        gpuOperator:
+          enabled: true
+          valuesOverride: {}
+    asserts:
+      - hasDocuments:
+          count: 1
+      - notExists:
+          path: spec.values
+
+  - it: should pass through valuesOverride
+    set:
+      addons:
+        hami:
+          enabled: true
+          valuesOverride:
+            hami:
+              devicePlugin:
+                deviceSplitCount: 5
+        gpuOperator:
+          enabled: true
+          valuesOverride: {}
+    asserts:
+      - equal:
+          path: spec.values.hami.devicePlugin.deviceSplitCount
+          value: 5
diff --git a/packages/apps/kubernetes/tests/values-ci-no-etcd.yaml b/packages/apps/kubernetes/tests/values-ci-no-etcd.yaml
new file mode 100644
index 00000000..c7c8196f
--- /dev/null
+++ b/packages/apps/kubernetes/tests/values-ci-no-etcd.yaml
@@ -0,0 +1,9 @@
+_namespace:
+  etcd: ""
+  monitoring: ""
+  ingress: ""
+  seaweedfs: ""
+  host: ""
+_cluster:
+  cluster-domain: cozy.local
+nodeGroups: null
diff --git a/packages/apps/kubernetes/tests/values-ci.yaml b/packages/apps/kubernetes/tests/values-ci.yaml
new file mode 100644
index 00000000..13365e8c
--- /dev/null
+++ b/packages/apps/kubernetes/tests/values-ci.yaml
@@ -0,0 +1,9 @@
+_namespace:
+  etcd: tenant-root
+  monitoring: ""
+  ingress: ""
+  seaweedfs: ""
+  host: ""
+_cluster:
+  cluster-domain: cozy.local
+nodeGroups: null
diff --git a/packages/apps/kubernetes/values.schema.json b/packages/apps/kubernetes/values.schema.json
index 9792d03a..a43deaec 100644
--- a/packages/apps/kubernetes/values.schema.json
+++ b/packages/apps/kubernetes/values.schema.json
@@ -2,33 +2,456 @@
   "title": "Chart Values",
   "type": "object",
   "properties": {
-    "host": {
+    "storageClass": {
+      "description": "StorageClass used to store the data.",
+      "type": "string",
+      "default": "replicated"
+    },
+    "nodeGroups": {
+      "description": "Worker nodes configuration map.",
+      "type": "object",
+      "default": {
+        "md0": {
+          "ephemeralStorage": "20Gi",
+          "gpus": [],
+          "instanceType": "u1.medium",
+          "maxReplicas": 10,
+          "minReplicas": 0,
+          "resources": {},
+          "roles": [
+            "ingress-nginx"
+          ]
+        }
+      },
+      "additionalProperties": {
+        "type": "object",
+        "required": [
+          "ephemeralStorage",
+          "instanceType",
+          "maxReplicas",
+          "minReplicas",
+          "resources"
+        ],
+        "properties": {
+          "ephemeralStorage": {
+            "description": "Ephemeral storage size.",
+            "default": "20Gi",
+            "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+            "anyOf": [
+              {
+                "type": "integer"
+              },
+              {
+                "type": "string"
+              }
+            ],
+            "x-kubernetes-int-or-string": true
+          },
+          "gpus": {
+            "description": "List of GPUs to attach (NVIDIA driver requires at least 4 GiB RAM).",
+            "type": "array",
+            "items": {
+              "type": "object",
+              "required": [
+                "name"
+              ],
+              "properties": {
+                "name": {
+                  "description": "Name of GPU, such as \"nvidia.com/AD102GL_L40S\".",
+                  "type": "string"
+                }
+              }
+            }
+          },
+          "instanceType": {
+            "description": "Virtual machine instance type.",
+            "type": "string",
+            "default": "u1.medium"
+          },
+          "maxReplicas": {
+            "description": "Maximum number of replicas.",
+            "type": "integer",
+            "default": 10
+          },
+          "minReplicas": {
+            "description": "Minimum number of replicas.",
+            "type": "integer",
+            "default": 0
+          },
+          "resources": {
+            "description": "CPU and memory resources for each worker node.",
+            "type": "object",
+            "properties": {
+              "cpu": {
+                "description": "CPU available.",
+                "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+                "anyOf": [
+                  {
+                    "type": "integer"
+                  },
+                  {
+                    "type": "string"
+                  }
+                ],
+                "x-kubernetes-int-or-string": true
+              },
+              "memory": {
+                "description": "Memory (RAM) available.",
+                "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+                "anyOf": [
+                  {
+                    "type": "integer"
+                  },
+                  {
+                    "type": "string"
+                  }
+                ],
+                "x-kubernetes-int-or-string": true
+              }
+            }
+          },
+          "roles": {
+            "description": "List of node roles.",
+            "type": "array",
+            "items": {
+              "type": "string"
+            }
+          }
+        }
+      }
+    },
+    "version": {
+      "description": "Kubernetes major.minor version to deploy",
+      "type": "string",
+      "default": "v1.35",
+      "enum": [
+        "v1.35",
+        "v1.34",
+        "v1.33",
+        "v1.32",
+        "v1.31",
+        "v1.30"
+      ]
+    },
+    "host": {
+      "description": "External hostname for Kubernetes cluster. Defaults to `\u003ccluster-name\u003e.\u003ctenant-host\u003e` if empty.",
       "type": "string",
-      "description": "Hostname used to access the Kubernetes cluster externally. Defaults to `.` when empty.",
       "default": ""
     },
-    "controlPlane": {
+    "addons": {
+      "description": "Cluster addons configuration.",
       "type": "object",
+      "default": {},
+      "required": [
+        "certManager",
+        "cilium",
+        "coredns",
+        "fluxcd",
+        "gatewayAPI",
+        "gpuOperator",
+        "hami",
+        "ingressNginx",
+        "monitoringAgents",
+        "velero",
+        "verticalPodAutoscaler"
+      ],
       "properties": {
-        "replicas": {
-          "type": "number",
-          "description": "Number of replicas for Kubernetes control-plane components.",
-          "default": 2
-        },
-        "apiServer": {
+        "certManager": {
+          "description": "Cert-manager addon.",
           "type": "object",
+          "default": {},
+          "required": [
+            "enabled",
+            "valuesOverride"
+          ],
+          "properties": {
+            "enabled": {
+              "description": "Enable cert-manager.",
+              "type": "boolean",
+              "default": false
+            },
+            "valuesOverride": {
+              "description": "Custom Helm values overrides.",
+              "type": "object",
+              "default": {},
+              "x-kubernetes-preserve-unknown-fields": true
+            }
+          }
+        },
+        "cilium": {
+          "description": "Cilium CNI plugin.",
+          "type": "object",
+          "default": {},
+          "required": [
+            "valuesOverride"
+          ],
+          "properties": {
+            "valuesOverride": {
+              "description": "Custom Helm values overrides.",
+              "type": "object",
+              "default": {},
+              "x-kubernetes-preserve-unknown-fields": true
+            }
+          }
+        },
+        "coredns": {
+          "description": "CoreDNS addon.",
+          "type": "object",
+          "default": {},
+          "required": [
+            "valuesOverride"
+          ],
+          "properties": {
+            "valuesOverride": {
+              "description": "Custom Helm values overrides.",
+              "type": "object",
+              "default": {},
+              "x-kubernetes-preserve-unknown-fields": true
+            }
+          }
+        },
+        "fluxcd": {
+          "description": "FluxCD GitOps operator.",
+          "type": "object",
+          "default": {},
+          "required": [
+            "enabled",
+            "valuesOverride"
+          ],
+          "properties": {
+            "enabled": {
+              "description": "Enable FluxCD.",
+              "type": "boolean",
+              "default": false
+            },
+            "valuesOverride": {
+              "description": "Custom Helm values overrides.",
+              "type": "object",
+              "default": {},
+              "x-kubernetes-preserve-unknown-fields": true
+            }
+          }
+        },
+        "gatewayAPI": {
+          "description": "Gateway API addon.",
+          "type": "object",
+          "default": {},
+          "required": [
+            "enabled"
+          ],
+          "properties": {
+            "enabled": {
+              "description": "Enable Gateway API.",
+              "type": "boolean",
+              "default": false
+            }
+          }
+        },
+        "gpuOperator": {
+          "description": "NVIDIA GPU Operator.",
+          "type": "object",
+          "default": {},
+          "required": [
+            "enabled",
+            "valuesOverride"
+          ],
+          "properties": {
+            "enabled": {
+              "description": "Enable GPU Operator.",
+              "type": "boolean",
+              "default": false
+            },
+            "valuesOverride": {
+              "description": "Custom Helm values overrides.",
+              "type": "object",
+              "default": {},
+              "x-kubernetes-preserve-unknown-fields": true
+            }
+          }
+        },
+        "hami": {
+          "description": "HAMi GPU virtualization middleware.",
+          "type": "object",
+          "default": {},
+          "required": [
+            "enabled",
+            "valuesOverride"
+          ],
+          "properties": {
+            "enabled": {
+              "description": "Enable HAMi (requires GPU Operator).",
+              "type": "boolean",
+              "default": false
+            },
+            "valuesOverride": {
+              "description": "Custom Helm values overrides.",
+              "type": "object",
+              "default": {},
+              "x-kubernetes-preserve-unknown-fields": true
+            }
+          }
+        },
+        "ingressNginx": {
+          "description": "Ingress-NGINX controller.",
+          "type": "object",
+          "default": {},
+          "required": [
+            "enabled",
+            "exposeMethod",
+            "valuesOverride"
+          ],
+          "properties": {
+            "enabled": {
+              "description": "Enable the controller (requires nodes labeled `ingress-nginx`).",
+              "type": "boolean",
+              "default": false
+            },
+            "exposeMethod": {
+              "description": "Method to expose the controller. Allowed values: `Proxied`, `LoadBalancer`.",
+              "type": "string",
+              "default": "Proxied",
+              "enum": [
+                "Proxied",
+                "LoadBalancer"
+              ]
+            },
+            "hosts": {
+              "description": "Domains routed to this tenant cluster when `exposeMethod` is `Proxied`.",
+              "type": "array",
+              "default": [],
+              "items": {
+                "type": "string"
+              }
+            },
+            "valuesOverride": {
+              "description": "Custom Helm values overrides.",
+              "type": "object",
+              "default": {},
+              "x-kubernetes-preserve-unknown-fields": true
+            }
+          }
+        },
+        "monitoringAgents": {
+          "description": "Monitoring agents.",
+          "type": "object",
+          "default": {},
+          "required": [
+            "enabled",
+            "valuesOverride"
+          ],
+          "properties": {
+            "enabled": {
+              "description": "Enable monitoring agents.",
+              "type": "boolean",
+              "default": false
+            },
+            "valuesOverride": {
+              "description": "Custom Helm values overrides.",
+              "type": "object",
+              "default": {},
+              "x-kubernetes-preserve-unknown-fields": true
+            }
+          }
+        },
+        "velero": {
+          "description": "Velero backup/restore addon.",
+          "type": "object",
+          "default": {},
+          "required": [
+            "enabled",
+            "valuesOverride"
+          ],
+          "properties": {
+            "enabled": {
+              "description": "Enable Velero.",
+              "type": "boolean",
+              "default": false
+            },
+            "valuesOverride": {
+              "description": "Custom Helm values overrides.",
+              "type": "object",
+              "default": {},
+              "x-kubernetes-preserve-unknown-fields": true
+            }
+          }
+        },
+        "verticalPodAutoscaler": {
+          "description": "Vertical Pod Autoscaler.",
+          "type": "object",
+          "default": {},
+          "required": [
+            "valuesOverride"
+          ],
+          "properties": {
+            "valuesOverride": {
+              "description": "Custom Helm values overrides.",
+              "type": "object",
+              "default": {},
+              "x-kubernetes-preserve-unknown-fields": true
+            }
+          }
+        }
+      }
+    },
+    "controlPlane": {
+      "description": "Kubernetes control-plane configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "apiServer",
+        "controllerManager",
+        "konnectivity",
+        "replicas",
+        "scheduler"
+      ],
+      "properties": {
+        "apiServer": {
+          "description": "API Server configuration.",
+          "type": "object",
+          "default": {},
+          "required": [
+            "resources",
+            "resourcesPreset"
+          ],
           "properties": {
             "resources": {
+              "description": "CPU and memory resources for API Server.",
               "type": "object",
-              "description": "Explicit CPU and memory configuration for the API Server. When left empty, the preset defined in `resourcesPreset` is applied.",
-              "default": {}
+              "default": {},
+              "properties": {
+                "cpu": {
+                  "description": "CPU available.",
+                  "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+                  "anyOf": [
+                    {
+                      "type": "integer"
+                    },
+                    {
+                      "type": "string"
+                    }
+                  ],
+                  "x-kubernetes-int-or-string": true
+                },
+                "memory": {
+                  "description": "Memory (RAM) available.",
+                  "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+                  "anyOf": [
+                    {
+                      "type": "integer"
+                    },
+                    {
+                      "type": "string"
+                    }
+                  ],
+                  "x-kubernetes-int-or-string": true
+                }
+              }
             },
             "resourcesPreset": {
+              "description": "Preset if `resources` omitted.",
               "type": "string",
-              "description": "Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.",
-              "default": "medium",
+              "default": "large",
               "enum": [
-                "none",
                 "nano",
                 "micro",
                 "small",
@@ -41,44 +464,52 @@
           }
         },
         "controllerManager": {
+          "description": "Controller Manager configuration.",
           "type": "object",
+          "default": {},
+          "required": [
+            "resources",
+            "resourcesPreset"
+          ],
           "properties": {
             "resources": {
+              "description": "CPU and memory resources for Controller Manager.",
               "type": "object",
-              "description": "Explicit CPU and memory configuration for the Controller Manager. When left empty, the preset defined in `resourcesPreset` is applied.",
-              "default": {}
+              "default": {},
+              "properties": {
+                "cpu": {
+                  "description": "CPU available.",
+                  "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+                  "anyOf": [
+                    {
+                      "type": "integer"
+                    },
+                    {
+                      "type": "string"
+                    }
+                  ],
+                  "x-kubernetes-int-or-string": true
+                },
+                "memory": {
+                  "description": "Memory (RAM) available.",
+                  "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+                  "anyOf": [
+                    {
+                      "type": "integer"
+                    },
+                    {
+                      "type": "string"
+                    }
+                  ],
+                  "x-kubernetes-int-or-string": true
+                }
+              }
             },
             "resourcesPreset": {
+              "description": "Preset if `resources` omitted.",
               "type": "string",
-              "description": "Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.",
               "default": "micro",
               "enum": [
-                "none",
-                "nano",
-                "micro",
-                "small",
-                "medium",
-                "large",
-                "xlarge",
-                "2xlarge"
-              ]
-            }
-          }
-        },
-        "scheduler": {
-          "type": "object",
-          "properties": {
-            "resources": {
-              "type": "object",
-              "description": "Explicit CPU and memory configuration for the Scheduler. When left empty, the preset defined in `resourcesPreset` is applied.",
-              "default": {}
-            },
-            "resourcesPreset": {
-              "type": "string",
-              "description": "Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.",
-              "default": "micro",
-              "enum": [
-                "none",
                 "nano",
                 "micro",
                 "small",
@@ -91,22 +522,60 @@
           }
         },
         "konnectivity": {
+          "description": "Konnectivity configuration.",
           "type": "object",
+          "default": {},
+          "required": [
+            "server"
+          ],
           "properties": {
             "server": {
+              "description": "Konnectivity Server configuration.",
               "type": "object",
+              "default": {},
+              "required": [
+                "resources",
+                "resourcesPreset"
+              ],
               "properties": {
                 "resources": {
+                  "description": "CPU and memory resources for Konnectivity.",
                   "type": "object",
-                  "description": "Explicit CPU and memory configuration for Konnectivity. When left empty, the preset defined in `resourcesPreset` is applied.",
-                  "default": {}
+                  "default": {},
+                  "properties": {
+                    "cpu": {
+                      "description": "CPU available.",
+                      "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+                      "anyOf": [
+                        {
+                          "type": "integer"
+                        },
+                        {
+                          "type": "string"
+                        }
+                      ],
+                      "x-kubernetes-int-or-string": true
+                    },
+                    "memory": {
+                      "description": "Memory (RAM) available.",
+                      "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+                      "anyOf": [
+                        {
+                          "type": "integer"
+                        },
+                        {
+                          "type": "string"
+                        }
+                      ],
+                      "x-kubernetes-int-or-string": true
+                    }
+                  }
                 },
                 "resourcesPreset": {
+                  "description": "Preset if `resources` omitted.",
                   "type": "string",
-                  "description": "Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.",
                   "default": "micro",
                   "enum": [
-                    "none",
                     "nano",
                     "micro",
                     "small",
@@ -119,151 +588,81 @@
               }
             }
           }
+        },
+        "replicas": {
+          "description": "Number of control-plane replicas.",
+          "type": "integer",
+          "default": 2
+        },
+        "scheduler": {
+          "description": "Scheduler configuration.",
+          "type": "object",
+          "default": {},
+          "required": [
+            "resources",
+            "resourcesPreset"
+          ],
+          "properties": {
+            "resources": {
+              "description": "CPU and memory resources for Scheduler.",
+              "type": "object",
+              "default": {},
+              "properties": {
+                "cpu": {
+                  "description": "CPU available.",
+                  "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+                  "anyOf": [
+                    {
+                      "type": "integer"
+                    },
+                    {
+                      "type": "string"
+                    }
+                  ],
+                  "x-kubernetes-int-or-string": true
+                },
+                "memory": {
+                  "description": "Memory (RAM) available.",
+                  "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+                  "anyOf": [
+                    {
+                      "type": "integer"
+                    },
+                    {
+                      "type": "string"
+                    }
+                  ],
+                  "x-kubernetes-int-or-string": true
+                }
+              }
+            },
+            "resourcesPreset": {
+              "description": "Preset if `resources` omitted.",
+              "type": "string",
+              "default": "micro",
+              "enum": [
+                "nano",
+                "micro",
+                "small",
+                "medium",
+                "large",
+                "xlarge",
+                "2xlarge"
+              ]
+            }
+          }
         }
       }
     },
-    "storageClass": {
-      "type": "string",
-      "description": "StorageClass used to store user data.",
-      "default": "replicated"
-    },
-    "addons": {
+    "images": {
+      "description": "Optional image overrides for air-gapped or rate-limited registries.",
       "type": "object",
+      "default": {},
       "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": {}
-            },
-            "exposeMethod": {
-              "type": "string",
-              "description": "Method to expose the Ingress-NGINX controller. (allowed values: Proxied, LoadBalancer)",
-              "default": "Proxied",
-              "enum": [
-                "Proxied",
-                "LoadBalancer"
-              ]
-            },
-            "hosts": {
-              "type": "array",
-              "description": "List of domain names that the parent cluster should route to this tenant cluster. Taken into account only when `exposeMethod` is set to `Proxied`.",
-              "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": {}
-            }
-          }
-        },
-        "velero": {
-          "type": "object",
-          "properties": {
-            "enabled": {
-              "type": "boolean",
-              "description": "Enable velero for backup and restore k8s cluster.",
-              "default": false
-            },
-            "valuesOverride": {
-              "type": "object",
-              "description": "Custom values to override",
-              "default": {}
-            }
-          }
+        "waitForKubeconfig": {
+          "description": "Image used by the wait-for-kubeconfig init container. Empty falls back to images/busybox.tag.",
+          "type": "string",
+          "default": ""
         }
       }
     }
diff --git a/packages/apps/kubernetes/values.yaml b/packages/apps/kubernetes/values.yaml
index 68e7c244..d609476c 100644
--- a/packages/apps/kubernetes/values.yaml
+++ b/packages/apps/kubernetes/values.yaml
@@ -1,14 +1,40 @@
-## @section Common Parameters
-
-## @param host Hostname used to access the Kubernetes cluster externally. Defaults to `.` when empty.
-## @param controlPlane.replicas Number of replicas for Kubernetes control-plane components.
-## @param storageClass StorageClass used to store user data.
 ##
-host: ""
+## @section Common Parameters
+##
+
+## @param {string} storageClass - StorageClass used to store the data.
 storageClass: replicated
 
-## @param nodeGroups [object] nodeGroups configuration
 ##
+## @section Application-specific Parameters
+##
+
+## @enum {string} ResourcesPreset - Default sizing preset.
+## @value nano
+## @value micro
+## @value small
+## @value medium
+## @value large
+## @value xlarge
+## @value 2xlarge
+
+## @typedef {struct} Resources - Explicit CPU and memory configuration for a node or component.
+## @field {quantity} [cpu] - CPU available.
+## @field {quantity} [memory] - Memory (RAM) available.
+
+## @typedef {struct} GPU - GPU configuration.
+## @field {string} name - Name of GPU, such as "nvidia.com/AD102GL_L40S".
+
+## @typedef {struct} NodeGroup - Worker node group configuration.
+## @field {int} minReplicas=0 - Minimum number of replicas.
+## @field {int} maxReplicas=10 - Maximum number of replicas.
+## @field {string} instanceType="u1.medium" - Virtual machine instance type.
+## @field {quantity} ephemeralStorage="20Gi" - Ephemeral storage size.
+## @field {[]string} roles - List of node roles.
+## @field {Resources} resources - CPU and memory resources for each worker node.
+## @field {[]GPU} gpus - List of GPUs to attach (NVIDIA driver requires at least 4 GiB RAM).
+
+## @param {map[string]NodeGroup} nodeGroups - Worker nodes configuration map.
 nodeGroups:
   md0:
     minReplicas: 0
@@ -17,135 +43,172 @@ nodeGroups:
     ephemeralStorage: 20Gi
     roles:
     - ingress-nginx
-
-    resources:
-      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
+    resources: {}
     gpus: []
 
+##
+## @enum {string} Version
+## @value v1.35
+## @value v1.34
+## @value v1.33
+## @value v1.32
+## @value v1.31
+## @value v1.30
 
+## @param {Version} version - Kubernetes major.minor version to deploy
+version: "v1.35"
+
+
+## @param {string} host - External hostname for Kubernetes cluster. Defaults to `.` if empty.
+host: ""
+
+##
 ## @section Cluster Addons
 ##
+
+## @typedef {struct} CertManagerAddon - cert-manager addon.
+## @field {bool} enabled - Enable cert-manager.
+## @field {object} valuesOverride - Custom Helm values overrides.
+
+## @typedef {struct} CiliumAddon - Cilium CNI plugin.
+## @field {object} valuesOverride - Custom Helm values overrides.
+
+## @typedef {struct} GatewayAPIAddon - Gateway API addon.
+## @field {bool} enabled - Enable Gateway API.
+
+## @enum {string} IngressNginxExposeMethod - Method to expose the controller
+## @value Proxied
+## @value LoadBalancer
+
+## @typedef {struct} IngressNginxAddon - Ingress-NGINX controller.
+## @field {bool} enabled - Enable the controller (requires nodes labeled `ingress-nginx`).
+## @field {IngressNginxExposeMethod} exposeMethod - Method to expose the controller. Allowed values: `Proxied`, `LoadBalancer`.
+## @field {[]string} hosts - Domains routed to this tenant cluster when `exposeMethod` is `Proxied`.
+## @field {object} valuesOverride - Custom Helm values overrides.
+
+## @typedef {struct} GPUOperatorAddon - NVIDIA GPU Operator.
+## @field {bool} enabled - Enable GPU Operator.
+## @field {object} valuesOverride - Custom Helm values overrides.
+
+## @typedef {struct} FluxCDAddon - FluxCD GitOps operator.
+## @field {bool} enabled - Enable FluxCD.
+## @field {object} valuesOverride - Custom Helm values overrides.
+
+## @typedef {struct} HAMiAddon - HAMi GPU virtualization middleware.
+## @field {bool} enabled - Enable HAMi (requires GPU Operator).
+## @field {object} valuesOverride - Custom Helm values overrides.
+
+## @typedef {struct} MonitoringAgentsAddon - Monitoring agents (Fluent Bit, VMAgents).
+## @field {bool} enabled - Enable monitoring agents.
+## @field {object} valuesOverride - Custom Helm values overrides.
+
+## @typedef {struct} VerticalPodAutoscalerAddon - Vertical Pod Autoscaler.
+## @field {object} valuesOverride - Custom Helm values overrides.
+
+## @typedef {struct} VeleroAddon - Velero backup and recovery addon.
+## @field {bool} enabled - Enable Velero.
+## @field {object} valuesOverride - Custom Helm values overrides.
+
+## @typedef {struct} CoreDNSAddon - CoreDNS addon.
+## @field {object} valuesOverride - Custom Helm values overrides.
+
+## @typedef {struct} Addons - Cluster addons configuration.
+## @field {CertManagerAddon} certManager - Cert-manager addon.
+## @field {CiliumAddon} cilium - Cilium CNI plugin.
+## @field {GatewayAPIAddon} gatewayAPI - Gateway API addon.
+## @field {IngressNginxAddon} ingressNginx - Ingress-NGINX controller.
+## @field {GPUOperatorAddon} gpuOperator - NVIDIA GPU Operator.
+## @field {HAMiAddon} hami - HAMi GPU virtualization middleware.
+## @field {FluxCDAddon} fluxcd - FluxCD GitOps operator.
+## @field {MonitoringAgentsAddon} monitoringAgents - Monitoring agents.
+## @field {VerticalPodAutoscalerAddon} verticalPodAutoscaler - Vertical Pod Autoscaler.
+## @field {VeleroAddon} velero - Velero backup/restore addon.
+## @field {CoreDNSAddon} coredns - CoreDNS addon.
+
+## @param {Addons} addons - Cluster addons configuration.
 addons:
-
-  ## Cert-manager: automatically creates and manages SSL/TLS certificate
-  ##
   certManager:
-    ## @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 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.exposeMethod Method to expose the Ingress-NGINX controller. (allowed values: Proxied, LoadBalancer)
-    ## @param addons.ingressNginx.hosts List of domain names that the parent cluster should route to this tenant cluster. Taken into account only when `exposeMethod` is set to `Proxied`.
-    ## e.g:
-    ## hosts:
-    ## - example.org
-    ## - foo.example.net
-    ##
     exposeMethod: Proxied
     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
-  ##
+  hami:
+    enabled: false
+    valuesOverride: {}
   fluxcd:
-    ## @param addons.fluxcd.enabled Enable FluxCD
-    ## @param addons.fluxcd.valuesOverride Custom values to override
-    ##
     enabled: false
     valuesOverride: {}
-
-  ## MonitoringAgents
-  ##
   monitoringAgents:
-    ## @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
     valuesOverride: {}
-
-  ## VerticalPodAutoscaler
-  ##
   verticalPodAutoscaler:
-    ## @param addons.verticalPodAutoscaler.valuesOverride Custom values to override
-    ##
     valuesOverride: {}
-
-  ## Velero
-  ##
   velero:
-    ## @param addons.velero.enabled Enable velero for backup and restore k8s cluster.
-    ## @param addons.velero.valuesOverride Custom values to override
-    ##
     enabled: false
     valuesOverride: {}
+  coredns:
+    valuesOverride: {}
 
+##
 ## @section Kubernetes Control Plane Configuration
 ##
 
+## @typedef {struct} APIServer - API Server configuration.
+## @field {Resources} resources - CPU and memory resources for API Server.
+## @field {ResourcesPreset} resourcesPreset="large" - Preset if `resources` omitted.
+
+## @typedef {struct} ControllerManager - Controller Manager configuration.
+## @field {Resources} resources - CPU and memory resources for Controller Manager.
+## @field {ResourcesPreset} resourcesPreset="micro" - Preset if `resources` omitted.
+
+## @typedef {struct} Scheduler - Scheduler configuration.
+## @field {Resources} resources - CPU and memory resources for Scheduler.
+## @field {ResourcesPreset} resourcesPreset="micro" - Preset if `resources` omitted.
+
+## @typedef {struct} KonnectivityServer - Konnectivity Server configuration.
+## @field {Resources} resources - CPU and memory resources for Konnectivity.
+## @field {ResourcesPreset} resourcesPreset="micro" - Preset if `resources` omitted.
+
+## @typedef {struct} Konnectivity - Konnectivity configuration.
+## @field {KonnectivityServer} server - Konnectivity Server configuration.
+
+## @typedef {struct} ControlPlane - Kubernetes control plane configuration.
+## @field {int} replicas=2 - Number of control-plane replicas.
+## @field {APIServer} apiServer - API Server configuration.
+## @field {ControllerManager} controllerManager - Controller Manager configuration.
+## @field {Scheduler} scheduler - Scheduler configuration.
+## @field {Konnectivity} konnectivity - Konnectivity configuration.
+
+## @param {ControlPlane} controlPlane - Kubernetes control-plane configuration.
 controlPlane:
   replicas: 2
-
   apiServer:
-    ## @param controlPlane.apiServer.resources Explicit CPU and memory configuration for the API Server. When left empty, the preset defined in `resourcesPreset` is applied.
-    ## @param controlPlane.apiServer.resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.
-    ## e.g:
-    ## resources:
-    ##   cpu: 4000m
-    ##   memory: 4Gi
-    ##
-    resourcesPreset: "medium"
     resources: {}
-
+    resourcesPreset: "large"
   controllerManager:
-    ## @param controlPlane.controllerManager.resources Explicit CPU and memory configuration for the Controller Manager. When left empty, the preset defined in `resourcesPreset` is applied.
-    ## @param controlPlane.controllerManager.resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.
-    resourcesPreset: "micro"
     resources: {}
-
+    resourcesPreset: "micro"
   scheduler:
-    ## @param controlPlane.scheduler.resources Explicit CPU and memory configuration for the Scheduler. When left empty, the preset defined in `resourcesPreset` is applied.
-    ## @param controlPlane.scheduler.resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.
-    resourcesPreset: "micro"
     resources: {}
-
+    resourcesPreset: "micro"
   konnectivity:
     server:
-      ## @param controlPlane.konnectivity.server.resources Explicit CPU and memory configuration for Konnectivity. When left empty, the preset defined in `resourcesPreset` is applied.
-      ## @param controlPlane.konnectivity.server.resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.
-      resourcesPreset: "micro"
       resources: {}
+      resourcesPreset: "micro"
+
+## @typedef {struct} Images - Optional image overrides for chart-internal helpers.
+## @field {string} [waitForKubeconfig] - Image used by the wait-for-kubeconfig init container. Empty falls back to images/busybox.tag.
+
+## @param {Images} images - Optional image overrides for air-gapped or rate-limited registries.
+images:
+  waitForKubeconfig: ""
diff --git a/packages/apps/virtual-machine/.helmignore b/packages/apps/mariadb/.helmignore
similarity index 82%
rename from packages/apps/virtual-machine/.helmignore
rename to packages/apps/mariadb/.helmignore
index 1ea0ae84..3de7d4a5 100644
--- a/packages/apps/virtual-machine/.helmignore
+++ b/packages/apps/mariadb/.helmignore
@@ -1,3 +1,4 @@
 .helmignore
 /logos
 /Makefile
+/hack
diff --git a/packages/apps/mariadb/Chart.yaml b/packages/apps/mariadb/Chart.yaml
new file mode 100644
index 00000000..6acc5082
--- /dev/null
+++ b/packages/apps/mariadb/Chart.yaml
@@ -0,0 +1,7 @@
+apiVersion: v2
+name: mariadb
+description: Managed MariaDB service
+icon: /logos/mariadb.svg
+type: application
+version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process
+appVersion: "11.0.2"
diff --git a/packages/apps/mysql/Makefile b/packages/apps/mariadb/Makefile
similarity index 53%
rename from packages/apps/mysql/Makefile
rename to packages/apps/mariadb/Makefile
index c458e263..9833f302 100644
--- a/packages/apps/mysql/Makefile
+++ b/packages/apps/mariadb/Makefile
@@ -1,24 +1,23 @@
 MARIADB_BACKUP_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml)
 
-include ../../../scripts/common-envs.mk
-include ../../../scripts/package.mk
+include ../../../hack/common-envs.mk
+include ../../../hack/package.mk
 
 generate:
-	readme-generator -v values.yaml -s values.schema.json -r README.md
-	yq -i -o json --indent 4 '.properties.resourcesPreset.enum = ["none", "nano", "micro", "small", "medium", "large", "xlarge", "2xlarge"]' values.schema.json
+	cozyvalues-gen -m 'mariadb' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/mariadb/types.go
+	../../../hack/update-crd.sh
+
+update:
+	hack/update-versions.sh
+	make generate
 
 image:
 	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 \
 		--metadata-file images/mariadb-backup.json \
-		--push=$(PUSH) \
-		--label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \
-		--load=$(LOAD)
+		$(BUILDX_ARGS)
 	echo "$(REGISTRY)/mariadb-backup:$(call settag,$(MARIADB_BACKUP_TAG))@$$(yq e '."containerimage.digest"' images/mariadb-backup.json -o json -r)" \
 		> images/mariadb-backup.tag
 	rm -f images/mariadb-backup.json
diff --git a/packages/apps/mariadb/README.md b/packages/apps/mariadb/README.md
new file mode 100644
index 00000000..9d97dc5f
--- /dev/null
+++ b/packages/apps/mariadb/README.md
@@ -0,0 +1,162 @@
+## Managed MariaDB Service
+
+The Managed MariaDB Service offers a powerful and widely used relational database solution.
+This service allows you to create and manage a replicated MariaDB cluster seamlessly.
+
+## Deployment Details
+
+This managed service is controlled by mariadb-operator, ensuring efficient management and seamless operation.
+
+- Docs: https://mariadb.com/kb/en/documentation/
+- GitHub: https://github.com/mariadb-operator/mariadb-operator
+
+## HowTos
+
+### How to switch master/slave replica
+
+```bash
+kubectl edit mariadb 
+```
+update:
+
+```bash
+spec:
+  replication:
+    primary:
+      podIndex: 1
+```
+
+check status:
+
+```bash
+NAME        READY   STATUS    PRIMARY POD   AGE
+  True    Running   app-db1-1     41d
+```
+
+### How to restore backup:
+
+find snapshot:
+```bash
+restic -r s3:s3.example.org/mariadb-backups/database_name snapshots
+```
+
+
+restore:
+```bash
+restic -r s3:s3.example.org/mariadb-backups/database_name restore latest --target /tmp/
+```
+
+more details:
+- https://blog.aenix.io/restic-effective-backup-from-stdin-4bc1e8f083c1
+
+### Known issues
+
+- **Replication can't be finished with various errors**
+- **Replication can't be finished in case if `binlog` purged**
+
+  Until `mariadbbackup` is not used to bootstrap a node by mariadb-operator (this feature is not implemented yet), follow these manual steps to fix it:
+  https://github.com/mariadb-operator/mariadb-operator/issues/141#issuecomment-1804760231
+
+- **Corrupted indices**
+  Sometimes some indices can be corrupted on master replica, you can recover them from slave:
+
+  ```bash
+  mysqldump -h  -P 3306 -u -p --column-statistics=0   ~/tmp/fix-table.sql
+  mysql -h  -P 3306 -u -p  < ~/tmp/fix-table.sql
+  ```
+
+## Parameters
+
+### Common parameters
+
+| Name               | Description                                                                                                                       | Type       | Value   |
+| ------------------ | --------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------- |
+| `replicas`         | Number of MariaDB replicas.                                                                                                       | `int`      | `2`     |
+| `resources`        | Explicit CPU and memory configuration for each MariaDB replica. When omitted, the preset defined in `resourcesPreset` is applied. | `object`   | `{}`    |
+| `resources.cpu`    | CPU available to each replica.                                                                                                    | `quantity` | `""`    |
+| `resources.memory` | Memory (RAM) available to each replica.                                                                                           | `quantity` | `""`    |
+| `resourcesPreset`  | Default sizing preset used when `resources` is omitted.                                                                           | `string`   | `nano`  |
+| `size`             | Persistent Volume Claim size available for application data.                                                                      | `quantity` | `10Gi`  |
+| `storageClass`     | StorageClass used to store the data.                                                                                              | `string`   | `""`    |
+| `external`         | Enable external access from outside the cluster.                                                                                  | `bool`     | `false` |
+| `version`          | MariaDB major.minor version to deploy                                                                                             | `string`   | `v11.8` |
+
+
+### Application-specific parameters
+
+| Name                             | Description                              | Type                | Value |
+| -------------------------------- | ---------------------------------------- | ------------------- | ----- |
+| `users`                          | Users configuration map.                 | `map[string]object` | `{}`  |
+| `users[name].password`           | Password for the user.                   | `string`            | `""`  |
+| `users[name].maxUserConnections` | Maximum number of connections.           | `int`               | `0`   |
+| `databases`                      | Databases configuration map.             | `map[string]object` | `{}`  |
+| `databases[name].roles`          | Roles assigned to users.                 | `object`            | `{}`  |
+| `databases[name].roles.admin`    | List of users with admin privileges.     | `[]string`          | `[]`  |
+| `databases[name].roles.readonly` | List of users with read-only privileges. | `[]string`          | `[]`  |
+
+
+### Backup parameters
+
+| Name                     | Description                                     | Type     | Value                                                  |
+| ------------------------ | ----------------------------------------------- | -------- | ------------------------------------------------------ |
+| `backup`                 | Backup configuration.                           | `object` | `{}`                                                   |
+| `backup.enabled`         | Enable regular backups (default: false).        | `bool`   | `false`                                                |
+| `backup.s3Region`        | AWS S3 region where backups are stored.         | `string` | `us-east-1`                                            |
+| `backup.s3Bucket`        | S3 bucket used for storing backups.             | `string` | `s3.example.org/mariadb-backups`                       |
+| `backup.schedule`        | Cron schedule for automated backups.            | `string` | `0 2 * * *`                                            |
+| `backup.cleanupStrategy` | Retention strategy for cleaning up old backups. | `string` | `--keep-last=3 --keep-daily=3 --keep-within-weekly=1m` |
+| `backup.s3AccessKey`     | Access key for S3 authentication.               | `string` | ``                                    |
+| `backup.s3SecretKey`     | Secret key for S3 authentication.               | `string` | ``                                    |
+| `backup.resticPassword`  | Password for Restic backup encryption.          | `string` | ``                                           |
+
+
+## Parameter examples and reference
+
+### resources and resourcesPreset
+
+`resources` sets explicit CPU and memory configurations for each replica.
+When left empty, the preset defined in `resourcesPreset` is applied.
+
+```yaml
+resources:
+  cpu: 4000m
+  memory: 4Gi
+```
+
+`resourcesPreset` sets named CPU and memory configurations for each replica.
+This setting is ignored if the corresponding `resources` value is set.
+
+| Preset name | CPU    | memory  |
+|-------------|--------|---------|
+| `nano`      | `250m` | `128Mi` |
+| `micro`     | `500m` | `256Mi` |
+| `small`     | `1`    | `512Mi` |
+| `medium`    | `1`    | `1Gi`   |
+| `large`     | `2`    | `2Gi`   |
+| `xlarge`    | `4`    | `4Gi`   |
+| `2xlarge`   | `8`    | `8Gi`   |
+
+### users
+
+```yaml
+users:
+  user1:
+    maxUserConnections: 1000
+    password: hackme
+  user2:
+    maxUserConnections: 1000
+    password: hackme
+```
+
+
+### databases
+
+```yaml
+databases:
+  myapp1:
+    roles:
+      admin:
+      - user1
+      readonly:
+      - user2
+```
diff --git a/packages/apps/virtual-machine/charts/cozy-lib b/packages/apps/mariadb/charts/cozy-lib
similarity index 100%
rename from packages/apps/virtual-machine/charts/cozy-lib
rename to packages/apps/mariadb/charts/cozy-lib
diff --git a/packages/apps/mariadb/files/versions.yaml b/packages/apps/mariadb/files/versions.yaml
new file mode 100644
index 00000000..59c8814c
--- /dev/null
+++ b/packages/apps/mariadb/files/versions.yaml
@@ -0,0 +1,4 @@
+"v11.8": "11.8.5"
+"v11.4": "11.4.9"
+"v10.11": "10.11.15"
+"v10.6": "10.6.24"
diff --git a/packages/apps/mariadb/hack/update-versions.sh b/packages/apps/mariadb/hack/update-versions.sh
new file mode 100755
index 00000000..775c0327
--- /dev/null
+++ b/packages/apps/mariadb/hack/update-versions.sh
@@ -0,0 +1,151 @@
+#!/usr/bin/env bash
+
+set -o errexit
+set -o nounset
+set -o pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+MARIADB_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
+VALUES_FILE="${MARIADB_DIR}/values.yaml"
+VERSIONS_FILE="${MARIADB_DIR}/files/versions.yaml"
+MARIADB_API_URL="https://downloads.mariadb.org/rest-api/mariadb/"
+
+# Check if jq is installed
+if ! command -v jq &> /dev/null; then
+    echo "Error: jq is not installed. Please install jq and try again." >&2
+    exit 1
+fi
+
+# Get LTS versions from MariaDB REST API
+echo "Fetching LTS versions from MariaDB REST API..."
+LTS_VERSIONS_JSON=$(curl -sSL "${MARIADB_API_URL}")
+
+if [ -z "$LTS_VERSIONS_JSON" ]; then
+    echo "Error: Could not fetch versions from MariaDB REST API" >&2
+    exit 1
+fi
+
+# Extract LTS stable major versions
+LTS_MAJOR_VERSIONS=$(echo "$LTS_VERSIONS_JSON" | jq -r '.major_releases[] | select(.release_support_type == "Long Term Support") | select(.release_status == "Stable") | .release_id' | sort -V -r)
+
+if [ -z "$LTS_MAJOR_VERSIONS" ]; then
+    echo "Error: Could not find any LTS stable versions" >&2
+    exit 1
+fi
+
+echo "Found LTS major versions: $(echo "$LTS_MAJOR_VERSIONS" | tr '\n' ' ')"
+
+# Build versions map: major version -> latest patch version
+declare -A VERSION_MAP
+MAJOR_VERSIONS=()
+
+for major_version in $LTS_MAJOR_VERSIONS; do
+    echo "Fetching patch versions for ${major_version}..."
+    
+    # Get patch versions for this major version
+    PATCH_VERSIONS_JSON=$(curl -sSL "${MARIADB_API_URL}${major_version}")
+    
+    if [ -z "$PATCH_VERSIONS_JSON" ]; then
+        echo "Warning: Could not fetch patch versions for ${major_version}, skipping..." >&2
+        continue
+    fi
+    
+    # Extract all stable patch version IDs (format: MAJOR.MINOR.PATCH)
+    # Filter only Stable releases
+    PATCH_VERSIONS=$(echo "$PATCH_VERSIONS_JSON" | jq -r --arg major "$major_version" '.releases | to_entries[] | select(.key | startswith($major + ".")) | select(.value.release_status == "Stable") | .key' | sort -V)
+    
+    # If no stable releases found, try to get any releases (for backwards compatibility)
+    if [ -z "$PATCH_VERSIONS" ]; then
+        PATCH_VERSIONS=$(echo "$PATCH_VERSIONS_JSON" | jq -r '.releases | keys[]' | grep -E "^${major_version}\." | sort -V)
+    fi
+    
+    if [ -z "$PATCH_VERSIONS" ]; then
+        echo "Warning: Could not find any patch versions for ${major_version}, skipping..." >&2
+        continue
+    fi
+    
+    # Get the latest patch version
+    LATEST_PATCH=$(echo "$PATCH_VERSIONS" | tail -n1)
+    
+    # major_version already has format MAJOR.MINOR (e.g., "11.8")
+    VERSION_MAP["v${major_version}"]="${LATEST_PATCH}"
+    MAJOR_VERSIONS+=("v${major_version}")
+    echo "Found version: v${major_version} -> ${LATEST_PATCH}"
+done
+
+if [ ${#MAJOR_VERSIONS[@]} -eq 0 ]; then
+    echo "Error: No matching versions found" >&2
+    exit 1
+fi
+
+# Sort major versions in descending order (newest first)
+IFS=$'\n' MAJOR_VERSIONS=($(printf '%s\n' "${MAJOR_VERSIONS[@]}" | sort -V -r))
+unset IFS
+
+echo "Major versions to add: ${MAJOR_VERSIONS[*]}"
+
+# Create/update versions.yaml file
+echo "Updating $VERSIONS_FILE..."
+{
+    for major_ver in "${MAJOR_VERSIONS[@]}"; do
+        echo "\"${major_ver}\": \"${VERSION_MAP[$major_ver]}\""
+    done
+} > "$VERSIONS_FILE"
+
+echo "Successfully updated $VERSIONS_FILE"
+
+# Update values.yaml - enum with major.minor versions only
+TEMP_FILE=$(mktemp)
+trap "rm -f $TEMP_FILE" EXIT
+
+# Build new version section
+NEW_VERSION_SECTION="## @enum {string} Version"
+for major_ver in "${MAJOR_VERSIONS[@]}"; do
+    NEW_VERSION_SECTION="${NEW_VERSION_SECTION}
+## @value $major_ver"
+done
+NEW_VERSION_SECTION="${NEW_VERSION_SECTION}
+
+## @param {Version} version - MariaDB major.minor version to deploy
+version: ${MAJOR_VERSIONS[0]}"
+
+# Check if version section already exists
+if grep -q "^## @enum {string} Version" "$VALUES_FILE"; then
+    # Version section exists, update it using awk
+    echo "Updating existing version section in $VALUES_FILE..."
+    
+    # Use awk to replace the section from "## @enum {string} Version" to "version: " (inclusive)
+    # Delete the old section and insert the new one
+    awk -v new_section="$NEW_VERSION_SECTION" '
+        /^## @enum {string} Version/ {
+            in_section = 1
+            print new_section
+            next
+        }
+        in_section && /^version: / {
+            in_section = 0
+            next
+        }
+        in_section {
+            next
+        }
+        { print }
+    ' "$VALUES_FILE" > "$TEMP_FILE.tmp"
+    mv "$TEMP_FILE.tmp" "$VALUES_FILE"
+else
+    # Version section doesn't exist, insert it before Application-specific parameters section
+    echo "Inserting new version section in $VALUES_FILE..."
+    
+    # Use awk to insert before "## @section Application-specific parameters"
+    awk -v new_section="$NEW_VERSION_SECTION" '
+        /^## @section Application-specific parameters/ {
+            print new_section
+            print ""
+        }
+        { print }
+    ' "$VALUES_FILE" > "$TEMP_FILE.tmp"
+    mv "$TEMP_FILE.tmp" "$VALUES_FILE"
+fi
+
+echo "Successfully updated $VALUES_FILE with major.minor versions: ${MAJOR_VERSIONS[*]}"
+
diff --git a/packages/apps/mariadb/images/mariadb-backup.tag b/packages/apps/mariadb/images/mariadb-backup.tag
new file mode 100644
index 00000000..6c830892
--- /dev/null
+++ b/packages/apps/mariadb/images/mariadb-backup.tag
@@ -0,0 +1 @@
+ghcr.io/cozystack/cozystack/mariadb-backup:0.0.0@sha256:3841eb171416711977dea0cf8cd45d32344caac9727af760c37d5e1dd41ee4bb
diff --git a/packages/apps/mysql/images/mariadb-backup/Dockerfile b/packages/apps/mariadb/images/mariadb-backup/Dockerfile
similarity index 100%
rename from packages/apps/mysql/images/mariadb-backup/Dockerfile
rename to packages/apps/mariadb/images/mariadb-backup/Dockerfile
diff --git a/packages/apps/mysql/logos/mariadb.svg b/packages/apps/mariadb/logos/mariadb.svg
similarity index 100%
rename from packages/apps/mysql/logos/mariadb.svg
rename to packages/apps/mariadb/logos/mariadb.svg
diff --git a/packages/apps/ferretdb/templates/.gitkeep b/packages/apps/mariadb/templates/.gitkeep
similarity index 100%
rename from packages/apps/ferretdb/templates/.gitkeep
rename to packages/apps/mariadb/templates/.gitkeep
diff --git a/packages/apps/ferretdb/templates/_resources.tpl b/packages/apps/mariadb/templates/_resources.tpl
similarity index 100%
rename from packages/apps/ferretdb/templates/_resources.tpl
rename to packages/apps/mariadb/templates/_resources.tpl
diff --git a/packages/apps/mariadb/templates/_versions.tpl b/packages/apps/mariadb/templates/_versions.tpl
new file mode 100644
index 00000000..a896ea5f
--- /dev/null
+++ b/packages/apps/mariadb/templates/_versions.tpl
@@ -0,0 +1,8 @@
+{{- define "mariadb.versionMap" }}
+{{- $versionMap := .Files.Get "files/versions.yaml" | fromYaml }}
+{{- if not (hasKey $versionMap .Values.version) }}
+    {{- printf `MariaDB version %s is not supported, allowed versions are %s` $.Values.version (keys $versionMap) | fail }}
+{{- end }}
+{{- index $versionMap .Values.version }}
+{{- end }}
+
diff --git a/packages/apps/mysql/templates/backup-cronjob.yaml b/packages/apps/mariadb/templates/backup-cronjob.yaml
similarity index 96%
rename from packages/apps/mysql/templates/backup-cronjob.yaml
rename to packages/apps/mariadb/templates/backup-cronjob.yaml
index 97b52208..ddb237cd 100644
--- a/packages/apps/mysql/templates/backup-cronjob.yaml
+++ b/packages/apps/mariadb/templates/backup-cronjob.yaml
@@ -13,9 +13,6 @@ spec:
   jobTemplate:
     spec:
       backoffLimit: 2
-      template:
-        spec:
-          restartPolicy: OnFailure
       template:
         metadata:
           annotations:
@@ -44,7 +41,7 @@ spec:
                   name: {{ .Release.Name }}
                   key: root-password
             - name: MYSQL_HOST
-              value: {{ .Release.Name }}-secondary
+              value: "{{ .Release.Name }}-{{ if eq (int .Values.replicas) 1 }}primary{{ else }}secondary{{ end }}"
             - name: AWS_ACCESS_KEY_ID
               valueFrom:
                 secretKeyRef:
diff --git a/packages/apps/mysql/templates/backup-script.yaml b/packages/apps/mariadb/templates/backup-script.yaml
similarity index 100%
rename from packages/apps/mysql/templates/backup-script.yaml
rename to packages/apps/mariadb/templates/backup-script.yaml
diff --git a/packages/apps/ferretdb/templates/backup-secret.yaml b/packages/apps/mariadb/templates/backup-secret.yaml
similarity index 100%
rename from packages/apps/ferretdb/templates/backup-secret.yaml
rename to packages/apps/mariadb/templates/backup-secret.yaml
diff --git a/packages/apps/mysql/templates/config.yaml b/packages/apps/mariadb/templates/config.yaml
similarity index 100%
rename from packages/apps/mysql/templates/config.yaml
rename to packages/apps/mariadb/templates/config.yaml
diff --git a/packages/apps/mysql/templates/dashboard-resourcemap.yaml b/packages/apps/mariadb/templates/dashboard-resourcemap.yaml
similarity index 100%
rename from packages/apps/mysql/templates/dashboard-resourcemap.yaml
rename to packages/apps/mariadb/templates/dashboard-resourcemap.yaml
diff --git a/packages/apps/mysql/templates/db.yaml b/packages/apps/mariadb/templates/db.yaml
similarity index 100%
rename from packages/apps/mysql/templates/db.yaml
rename to packages/apps/mariadb/templates/db.yaml
diff --git a/packages/apps/mariadb/templates/hooks/cleanup-pvc.yaml b/packages/apps/mariadb/templates/hooks/cleanup-pvc.yaml
new file mode 100644
index 00000000..e3fd5c32
--- /dev/null
+++ b/packages/apps/mariadb/templates/hooks/cleanup-pvc.yaml
@@ -0,0 +1,74 @@
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ .Release.Name }}-cleanup
+  labels:
+    app.kubernetes.io/instance: {{ .Release.Name }}
+  annotations:
+    "helm.sh/hook": post-delete
+    "helm.sh/hook-weight": "10"
+    "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
+spec:
+  template:
+    metadata:
+      labels:
+        app.kubernetes.io/instance: {{ .Release.Name }}
+        policy.cozystack.io/allow-to-apiserver: "true"
+    spec:
+      serviceAccountName: {{ .Release.Name }}-cleanup
+      restartPolicy: Never
+      containers:
+        - name: cleanup
+          image: docker.io/clastix/kubectl:v1.32
+          command:
+            - /bin/sh
+            - -c
+            - |
+              echo "Deleting orphaned PVCs for {{ .Release.Name }}..."
+              kubectl delete pvc -n {{ .Release.Namespace }} -l app.kubernetes.io/instance={{ .Release.Name }} || true
+              echo "PVC cleanup complete."
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ .Release.Name }}-cleanup
+  labels:
+    app.kubernetes.io/instance: {{ .Release.Name }}
+  annotations:
+    "helm.sh/hook": post-delete
+    helm.sh/hook-weight: "0"
+    "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: {{ .Release.Name }}-cleanup
+  labels:
+    app.kubernetes.io/instance: {{ .Release.Name }}
+  annotations:
+    "helm.sh/hook": post-delete
+    "helm.sh/hook-weight": "5"
+    "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
+rules:
+  - apiGroups: [""]
+    resources: ["persistentvolumeclaims"]
+    verbs: ["get", "list", "delete"]
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: {{ .Release.Name }}-cleanup
+  labels:
+    app.kubernetes.io/instance: {{ .Release.Name }}
+  annotations:
+    "helm.sh/hook": post-delete
+    helm.sh/hook-weight: "5"
+    "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: {{ .Release.Name }}-cleanup
+subjects:
+  - kind: ServiceAccount
+    name: {{ .Release.Name }}-cleanup
diff --git a/packages/apps/mysql/templates/mariadb.yaml b/packages/apps/mariadb/templates/mariadb.yaml
similarity index 87%
rename from packages/apps/mysql/templates/mariadb.yaml
rename to packages/apps/mariadb/templates/mariadb.yaml
index 3ba3748b..d3d5e636 100644
--- a/packages/apps/mysql/templates/mariadb.yaml
+++ b/packages/apps/mariadb/templates/mariadb.yaml
@@ -8,7 +8,7 @@ spec:
     name: {{ .Release.Name }}-credentials
     key: root
 
-  image: "mariadb:11.0.2"
+  image: "mariadb:{{ include "mariadb.versionMap" $ }}"
 
   port: 3306
 
@@ -29,13 +29,15 @@ spec:
             - {{ .Release.Name }}
         topologyKey: "kubernetes.io/hostname"
 
-  {{- if gt (int .Values.replicas) 1 }}
   replication:
     enabled: true
     #primary:
     #  podIndex: 0
     #  automaticFailover: true
-  {{- end }}
+
+  podMetadata:
+    labels:
+      "policy.cozystack.io/allow-to-apiserver": "true"
 
   metrics:
     enabled: true
@@ -61,9 +63,6 @@ spec:
     metadata:
       labels:
         app.kubernetes.io/instance: {{ $.Release.Name }}
-    {{- if and .Values.external (eq (int .Values.replicas) 1) }}
-    type: LoadBalancer
-    {{- end }}
   storage:
     size: {{ .Values.size }}
     resizeInUseVolumes: true
@@ -72,7 +71,7 @@ spec:
     storageClassName: {{ . }}
     {{- end }}
 
-  {{- if and .Values.external (gt (int .Values.replicas) 1) }}
+  {{- if .Values.external }}
   primaryService:
     type: LoadBalancer
   {{- end }}
diff --git a/packages/apps/mysql/templates/regsecret.yaml b/packages/apps/mariadb/templates/regsecret.yaml
similarity index 100%
rename from packages/apps/mysql/templates/regsecret.yaml
rename to packages/apps/mariadb/templates/regsecret.yaml
diff --git a/packages/apps/mysql/templates/secret.yaml b/packages/apps/mariadb/templates/secret.yaml
similarity index 100%
rename from packages/apps/mysql/templates/secret.yaml
rename to packages/apps/mariadb/templates/secret.yaml
diff --git a/packages/apps/mysql/templates/user.yaml b/packages/apps/mariadb/templates/user.yaml
similarity index 100%
rename from packages/apps/mysql/templates/user.yaml
rename to packages/apps/mariadb/templates/user.yaml
diff --git a/packages/apps/ferretdb/templates/workloadmonitor.yaml b/packages/apps/mariadb/templates/workloadmonitor.yaml
similarity index 67%
rename from packages/apps/ferretdb/templates/workloadmonitor.yaml
rename to packages/apps/mariadb/templates/workloadmonitor.yaml
index a1b364d0..36cb59f0 100644
--- a/packages/apps/ferretdb/templates/workloadmonitor.yaml
+++ b/packages/apps/mariadb/templates/workloadmonitor.yaml
@@ -3,11 +3,13 @@ apiVersion: cozystack.io/v1alpha1
 kind: WorkloadMonitor
 metadata:
   name: {{ $.Release.Name }}
+  labels:
+    workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }}
 spec:
   replicas: {{ .Values.replicas }}
   minReplicas: 1
-  kind: ferretdb
-  type: ferretdb
+  kind: mariadb
+  type: mariadb
   selector:
     app.kubernetes.io/instance: {{ $.Release.Name }}
   version: {{ $.Chart.Version }}
diff --git a/packages/apps/mariadb/values.schema.json b/packages/apps/mariadb/values.schema.json
new file mode 100644
index 00000000..49df40f0
--- /dev/null
+++ b/packages/apps/mariadb/values.schema.json
@@ -0,0 +1,202 @@
+{
+  "title": "Chart Values",
+  "type": "object",
+  "properties": {
+    "replicas": {
+      "description": "Number of MariaDB replicas.",
+      "type": "integer",
+      "default": 2
+    },
+    "resources": {
+      "description": "Explicit CPU and memory configuration for each MariaDB replica. When omitted, the preset defined in `resourcesPreset` is applied.",
+      "type": "object",
+      "default": {},
+      "properties": {
+        "cpu": {
+          "description": "CPU available to each replica.",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
+        },
+        "memory": {
+          "description": "Memory (RAM) available to each replica.",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
+        }
+      }
+    },
+    "resourcesPreset": {
+      "description": "Default sizing preset used when `resources` is omitted.",
+      "type": "string",
+      "default": "nano",
+      "enum": [
+        "nano",
+        "micro",
+        "small",
+        "medium",
+        "large",
+        "xlarge",
+        "2xlarge"
+      ]
+    },
+    "size": {
+      "description": "Persistent Volume Claim size available for application data.",
+      "default": "10Gi",
+      "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+      "anyOf": [
+        {
+          "type": "integer"
+        },
+        {
+          "type": "string"
+        }
+      ],
+      "x-kubernetes-int-or-string": true
+    },
+    "storageClass": {
+      "description": "StorageClass used to store the data.",
+      "type": "string",
+      "default": ""
+    },
+    "external": {
+      "description": "Enable external access from outside the cluster.",
+      "type": "boolean",
+      "default": false
+    },
+    "version": {
+      "description": "MariaDB major.minor version to deploy",
+      "type": "string",
+      "default": "v11.8",
+      "enum": [
+        "v11.8",
+        "v11.4",
+        "v10.11",
+        "v10.6"
+      ]
+    },
+    "users": {
+      "description": "Users configuration map.",
+      "type": "object",
+      "default": {},
+      "additionalProperties": {
+        "type": "object",
+        "required": [
+          "maxUserConnections",
+          "password"
+        ],
+        "properties": {
+          "maxUserConnections": {
+            "description": "Maximum number of connections.",
+            "type": "integer"
+          },
+          "password": {
+            "description": "Password for the user.",
+            "type": "string"
+          }
+        }
+      }
+    },
+    "databases": {
+      "description": "Databases configuration map.",
+      "type": "object",
+      "default": {},
+      "additionalProperties": {
+        "type": "object",
+        "properties": {
+          "roles": {
+            "description": "Roles assigned to users.",
+            "type": "object",
+            "properties": {
+              "admin": {
+                "description": "List of users with admin privileges.",
+                "type": "array",
+                "items": {
+                  "type": "string"
+                }
+              },
+              "readonly": {
+                "description": "List of users with read-only privileges.",
+                "type": "array",
+                "items": {
+                  "type": "string"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "backup": {
+      "description": "Backup configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "cleanupStrategy",
+        "enabled",
+        "resticPassword",
+        "s3AccessKey",
+        "s3Bucket",
+        "s3Region",
+        "s3SecretKey",
+        "schedule"
+      ],
+      "properties": {
+        "cleanupStrategy": {
+          "description": "Retention strategy for cleaning up old backups.",
+          "type": "string",
+          "default": "--keep-last=3 --keep-daily=3 --keep-within-weekly=1m"
+        },
+        "enabled": {
+          "description": "Enable regular backups (default: false).",
+          "type": "boolean",
+          "default": false
+        },
+        "resticPassword": {
+          "description": "Password for Restic backup encryption.",
+          "type": "string",
+          "default": "\u003cpassword\u003e"
+        },
+        "s3AccessKey": {
+          "description": "Access key for S3 authentication.",
+          "type": "string",
+          "default": "\u003cyour-access-key\u003e"
+        },
+        "s3Bucket": {
+          "description": "S3 bucket used for storing backups.",
+          "type": "string",
+          "default": "s3.example.org/mariadb-backups"
+        },
+        "s3Region": {
+          "description": "AWS S3 region where backups are stored.",
+          "type": "string",
+          "default": "us-east-1"
+        },
+        "s3SecretKey": {
+          "description": "Secret key for S3 authentication.",
+          "type": "string",
+          "default": "\u003cyour-secret-key\u003e"
+        },
+        "schedule": {
+          "description": "Cron schedule for automated backups.",
+          "type": "string",
+          "default": "0 2 * * *"
+        }
+      }
+    }
+  }
+}
diff --git a/packages/apps/mariadb/values.yaml b/packages/apps/mariadb/values.yaml
new file mode 100644
index 00000000..6d629a83
--- /dev/null
+++ b/packages/apps/mariadb/values.yaml
@@ -0,0 +1,106 @@
+##
+## @section Common parameters
+##
+
+## @typedef {struct} Resources - Explicit CPU and memory configuration for each MariaDB replica.
+## @field {quantity} [cpu] - CPU available to each replica.
+## @field {quantity} [memory] - Memory (RAM) available to each replica.
+
+## @enum {string} ResourcesPreset - Default sizing preset.
+## @value nano
+## @value micro
+## @value small
+## @value medium
+## @value large
+## @value xlarge
+## @value 2xlarge
+
+## @param {int} replicas - Number of MariaDB replicas.
+replicas: 2
+
+## @param {Resources} [resources] - Explicit CPU and memory configuration for each MariaDB replica. When omitted, the preset defined in `resourcesPreset` is applied.
+resources: {}
+
+## @param {ResourcesPreset} resourcesPreset="nano" - Default sizing preset used when `resources` is omitted.
+resourcesPreset: "nano"
+
+## @param {quantity} size - Persistent Volume Claim size available for application data.
+size: 10Gi
+
+## @param {string} storageClass - StorageClass used to store the data.
+storageClass: ""
+
+## @param {bool} external - Enable external access from outside the cluster.
+external: false
+
+##
+## @enum {string} Version
+## @value v11.8
+## @value v11.4
+## @value v10.11
+## @value v10.6
+
+## @param {Version} version - MariaDB major.minor version to deploy
+version: v11.8
+
+##
+## @section Application-specific parameters
+##
+
+## @typedef {struct} User - User configuration.
+## @field {string} password - Password for the user.
+## @field {int} maxUserConnections - Maximum number of connections.
+
+## @param {map[string]User} users - Users configuration map.
+users: {}
+## Example:
+## users:
+##   user1:
+##     maxUserConnections: 1000
+##     password: hackme
+##   user2:
+##     maxUserConnections: 1000
+##     password: hackme
+
+## @typedef {struct} DatabaseRoles - Role assignments for a database.
+## @field {[]string} [admin] - List of users with admin privileges.
+## @field {[]string} [readonly] - List of users with read-only privileges.
+
+## @typedef {struct} Database - Database configuration.
+## @field {DatabaseRoles} [roles] - Roles assigned to users.
+
+## @param {map[string]Database} databases - Databases configuration map.
+databases: {}
+## Example:
+## databases:
+##   myapp1:
+##     roles:
+##       admin:
+##       - user1
+##       readonly:
+##       - user2
+
+##
+## @section Backup parameters
+##
+
+## @typedef {struct} Backup - Backup configuration.
+## @field {bool} enabled - Enable regular backups (default: false).
+## @field {string} s3Region - AWS S3 region where backups are stored.
+## @field {string} s3Bucket - S3 bucket used for storing backups.
+## @field {string} schedule - Cron schedule for automated backups.
+## @field {string} cleanupStrategy - Retention strategy for cleaning up old backups.
+## @field {string} s3AccessKey - Access key for S3 authentication.
+## @field {string} s3SecretKey - Secret key for S3 authentication.
+## @field {string} resticPassword - Password for Restic backup encryption.
+
+## @param {Backup} backup - Backup configuration.
+backup:
+  enabled: false
+  s3Region: us-east-1
+  s3Bucket: "s3.example.org/mariadb-backups"
+  schedule: "0 2 * * *"
+  cleanupStrategy: "--keep-last=3 --keep-daily=3 --keep-within-weekly=1m"
+  s3AccessKey: ""
+  s3SecretKey: ""
+  resticPassword: ""
diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/.helmignore b/packages/apps/mongodb/.helmignore
similarity index 100%
rename from packages/system/kamaji-etcd/charts/kamaji-etcd/.helmignore
rename to packages/apps/mongodb/.helmignore
diff --git a/packages/apps/mongodb/Chart.yaml b/packages/apps/mongodb/Chart.yaml
new file mode 100644
index 00000000..ffa97e9c
--- /dev/null
+++ b/packages/apps/mongodb/Chart.yaml
@@ -0,0 +1,7 @@
+apiVersion: v2
+name: mongodb
+description: Managed MongoDB service
+icon: /logos/mongodb.svg
+type: application
+version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process
+appVersion: "8.0"
diff --git a/packages/apps/mongodb/Makefile b/packages/apps/mongodb/Makefile
new file mode 100644
index 00000000..37f30ccc
--- /dev/null
+++ b/packages/apps/mongodb/Makefile
@@ -0,0 +1,11 @@
+include ../../../hack/package.mk
+
+.PHONY: generate update
+
+generate:
+	cozyvalues-gen -m 'mongodb' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/mongodb/types.go
+	../../../hack/update-crd.sh
+
+update:
+	hack/update-versions.sh
+	make generate
diff --git a/packages/apps/mongodb/README.md b/packages/apps/mongodb/README.md
new file mode 100644
index 00000000..82127c59
--- /dev/null
+++ b/packages/apps/mongodb/README.md
@@ -0,0 +1,110 @@
+# Managed MongoDB Service
+
+MongoDB is a popular document-oriented NoSQL database known for its flexibility and scalability.
+The Managed MongoDB Service provides a self-healing replicated cluster managed by the Percona Operator for MongoDB.
+
+## Deployment Details
+
+This managed service is controlled by the Percona Operator for MongoDB, ensuring efficient management and seamless operation.
+
+- Docs: 
+- Github: 
+
+## Deployment Modes
+
+### Replica Set Mode (default)
+
+By default, MongoDB deploys as a replica set with the specified number of replicas.
+This mode is suitable for most use cases requiring high availability.
+
+### Sharded Cluster Mode
+
+Enable `sharding: true` for horizontal scaling across multiple shards.
+Each shard is a replica set, and mongos routers handle query routing.
+
+## Notes
+
+### External Access
+
+When `external: true` is enabled:
+- **Replica Set mode**: Traffic is load-balanced across all replica set members. This works well for read operations, but write operations require connecting to the primary. MongoDB drivers handle primary discovery automatically using the replica set connection string.
+- **Sharded mode**: Traffic is routed through mongos routers, which handle both reads and writes correctly.
+
+### Credentials
+
+On first install, the credentials secret will be empty until the Percona operator initializes the cluster.
+Run `helm upgrade` after MongoDB is ready to populate the credentials secret with the actual password.
+
+## Parameters
+
+### Common parameters
+
+| Name               | Description                                                                                                                       | Type       | Value   |
+| ------------------ | --------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------- |
+| `replicas`         | Number of MongoDB replicas in replica set.                                                                                        | `int`      | `3`     |
+| `resources`        | Explicit CPU and memory configuration for each MongoDB replica. When omitted, the preset defined in `resourcesPreset` is applied. | `object`   | `{}`    |
+| `resources.cpu`    | CPU available to each replica.                                                                                                    | `quantity` | `""`    |
+| `resources.memory` | Memory (RAM) available to each replica.                                                                                           | `quantity` | `""`    |
+| `resourcesPreset`  | Default sizing preset used when `resources` is omitted.                                                                           | `string`   | `small` |
+| `size`             | Persistent Volume Claim size available for application data.                                                                      | `quantity` | `10Gi`  |
+| `storageClass`     | StorageClass used to store the data.                                                                                              | `string`   | `""`    |
+| `external`         | Enable external access from outside the cluster.                                                                                  | `bool`     | `false` |
+| `version`          | MongoDB major version to deploy.                                                                                                  | `string`   | `v8`    |
+
+
+### Sharding configuration
+
+| Name                                | Description                                                        | Type       | Value   |
+| ----------------------------------- | ------------------------------------------------------------------ | ---------- | ------- |
+| `sharding`                          | Enable sharded cluster mode. When disabled, deploys a replica set. | `bool`     | `false` |
+| `shardingConfig`                    | Configuration for sharded cluster mode.                            | `object`   | `{}`    |
+| `shardingConfig.configServers`      | Number of config server replicas.                                  | `int`      | `3`     |
+| `shardingConfig.configServerSize`   | PVC size for config servers.                                       | `quantity` | `3Gi`   |
+| `shardingConfig.mongos`             | Number of mongos router replicas.                                  | `int`      | `2`     |
+| `shardingConfig.shards`             | List of shard configurations.                                      | `[]object` | `[...]` |
+| `shardingConfig.shards[i].name`     | Shard name.                                                        | `string`   | `""`    |
+| `shardingConfig.shards[i].replicas` | Number of replicas in this shard.                                  | `int`      | `0`     |
+| `shardingConfig.shards[i].size`     | PVC size for this shard.                                           | `quantity` | `""`    |
+
+
+### Users configuration
+
+| Name                   | Description                                        | Type                | Value |
+| ---------------------- | -------------------------------------------------- | ------------------- | ----- |
+| `users`                | Users configuration map.                           | `map[string]object` | `{}`  |
+| `users[name].password` | Password for the user (auto-generated if omitted). | `string`            | `""`  |
+
+
+### Databases configuration
+
+| Name                             | Description                                                | Type                | Value |
+| -------------------------------- | ---------------------------------------------------------- | ------------------- | ----- |
+| `databases`                      | Databases configuration map.                               | `map[string]object` | `{}`  |
+| `databases[name].roles`          | Roles assigned to users.                                   | `object`            | `{}`  |
+| `databases[name].roles.admin`    | List of users with admin privileges (readWrite + dbAdmin). | `[]string`          | `[]`  |
+| `databases[name].roles.readonly` | List of users with read-only privileges.                   | `[]string`          | `[]`  |
+
+
+### Backup parameters
+
+| Name                     | Description                                            | Type     | Value                               |
+| ------------------------ | ------------------------------------------------------ | -------- | ----------------------------------- |
+| `backup`                 | Backup configuration.                                  | `object` | `{}`                                |
+| `backup.enabled`         | Enable regular backups.                                | `bool`   | `false`                             |
+| `backup.schedule`        | Cron schedule for automated backups.                   | `string` | `0 2 * * *`                         |
+| `backup.retentionPolicy` | Retention policy (e.g. "30d").                         | `string` | `30d`                               |
+| `backup.destinationPath` | Destination path for backups (e.g. s3://bucket/path/). | `string` | `s3://bucket/path/to/folder/`       |
+| `backup.endpointURL`     | S3 endpoint URL for uploads.                           | `string` | `http://minio-gateway-service:9000` |
+| `backup.s3AccessKey`     | Access key for S3 authentication.                      | `string` | `""`                                |
+| `backup.s3SecretKey`     | Secret key for S3 authentication.                      | `string` | `""`                                |
+
+
+### Bootstrap (recovery) parameters
+
+| Name                     | Description                                               | Type     | Value   |
+| ------------------------ | --------------------------------------------------------- | -------- | ------- |
+| `bootstrap`              | Bootstrap configuration.                                  | `object` | `{}`    |
+| `bootstrap.enabled`      | Whether to restore from a backup.                         | `bool`   | `false` |
+| `bootstrap.recoveryTime` | Timestamp for point-in-time recovery; empty means latest. | `string` | `""`    |
+| `bootstrap.backupName`   | Name of backup to restore from.                           | `string` | `""`    |
+
diff --git a/packages/apps/mongodb/charts/cozy-lib b/packages/apps/mongodb/charts/cozy-lib
new file mode 120000
index 00000000..e1813509
--- /dev/null
+++ b/packages/apps/mongodb/charts/cozy-lib
@@ -0,0 +1 @@
+../../../library/cozy-lib
\ No newline at end of file
diff --git a/packages/apps/mongodb/files/versions.yaml b/packages/apps/mongodb/files/versions.yaml
new file mode 100644
index 00000000..ee1333c5
--- /dev/null
+++ b/packages/apps/mongodb/files/versions.yaml
@@ -0,0 +1,5 @@
+# MongoDB version mapping (major version -> Percona image tag)
+# Auto-generated by hack/update-versions.sh - do not edit manually
+"v8": "8.0.17-6"
+"v7": "7.0.28-15"
+"v6": "6.0.25-20"
diff --git a/packages/apps/mongodb/hack/update-versions.sh b/packages/apps/mongodb/hack/update-versions.sh
new file mode 100755
index 00000000..832eaf76
--- /dev/null
+++ b/packages/apps/mongodb/hack/update-versions.sh
@@ -0,0 +1,125 @@
+#!/usr/bin/env bash
+
+set -o errexit
+set -o nounset
+set -o pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+MONGODB_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
+VALUES_FILE="${MONGODB_DIR}/values.yaml"
+VERSIONS_FILE="${MONGODB_DIR}/files/versions.yaml"
+
+# Supported major versions (newest first)
+SUPPORTED_MAJOR_VERSIONS="8 7 6"
+
+echo "Supported major versions: $SUPPORTED_MAJOR_VERSIONS"
+
+# Check if skopeo is installed
+if ! command -v skopeo &> /dev/null; then
+    echo "Error: skopeo is not installed. Please install skopeo and try again." >&2
+    exit 1
+fi
+
+# Check if jq is installed
+if ! command -v jq &> /dev/null; then
+    echo "Error: jq is not installed. Please install jq and try again." >&2
+    exit 1
+fi
+
+# Get available image tags from Percona registry
+echo "Fetching available image tags from registry..."
+AVAILABLE_TAGS=$(skopeo list-tags docker://percona/percona-server-mongodb | jq -r '.Tags[]' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+-[0-9]+$' | sort -V)
+
+if [ -z "$AVAILABLE_TAGS" ]; then
+    echo "Error: Could not fetch available image tags" >&2
+    exit 1
+fi
+
+# Build versions map: major version -> latest tag
+declare -A VERSION_MAP
+MAJOR_VERSIONS=()
+
+for major_version in $SUPPORTED_MAJOR_VERSIONS; do
+    # Find all tags that match this major version
+    matching_tags=$(echo "$AVAILABLE_TAGS" | grep "^${major_version}\\.")
+
+    if [ -n "$matching_tags" ]; then
+        # Get the latest tag for this major version
+        latest_tag=$(echo "$matching_tags" | tail -n1)
+        VERSION_MAP["v${major_version}"]="${latest_tag}"
+        MAJOR_VERSIONS+=("v${major_version}")
+        echo "Found version: v${major_version} -> ${latest_tag}"
+    fi
+done
+
+if [ ${#MAJOR_VERSIONS[@]} -eq 0 ]; then
+    echo "Error: No matching versions found" >&2
+    exit 1
+fi
+
+echo "Major versions to add: ${MAJOR_VERSIONS[*]}"
+
+# Create/update versions.yaml file
+echo "Updating $VERSIONS_FILE..."
+{
+    echo "# MongoDB version mapping (major version -> Percona image tag)"
+    echo "# Auto-generated by hack/update-versions.sh - do not edit manually"
+    for major_ver in "${MAJOR_VERSIONS[@]}"; do
+        echo "\"${major_ver}\": \"${VERSION_MAP[$major_ver]}\""
+    done
+} > "$VERSIONS_FILE"
+
+echo "Successfully updated $VERSIONS_FILE"
+
+# Update values.yaml - enum with major versions only
+TEMP_FILE=$(mktemp)
+trap 'rm -f "$TEMP_FILE" "${TEMP_FILE}.tmp"' EXIT
+
+# Build new version section
+NEW_VERSION_SECTION="## @enum {string} Version"
+for major_ver in "${MAJOR_VERSIONS[@]}"; do
+    NEW_VERSION_SECTION="${NEW_VERSION_SECTION}
+## @value $major_ver"
+done
+NEW_VERSION_SECTION="${NEW_VERSION_SECTION}
+
+## @param {Version} version - MongoDB major version to deploy.
+version: ${MAJOR_VERSIONS[0]}"
+
+# Check if version section already exists
+if grep -q "^## @enum {string} Version" "$VALUES_FILE"; then
+    # Version section exists, update it using awk
+    echo "Updating existing version section in $VALUES_FILE..."
+
+    # Use awk to replace the section from "## @enum {string} Version" to "version: " (inclusive)
+    awk -v new_section="$NEW_VERSION_SECTION" '
+        /^## @enum {string} Version/ {
+            in_section = 1
+            print new_section
+            next
+        }
+        in_section && /^version: / {
+            in_section = 0
+            next
+        }
+        in_section {
+            next
+        }
+        { print }
+    ' "$VALUES_FILE" > "$TEMP_FILE.tmp"
+    mv "$TEMP_FILE.tmp" "$VALUES_FILE"
+else
+    # Version section doesn't exist, insert it before Sharding section
+    echo "Inserting new version section in $VALUES_FILE..."
+
+    awk -v new_section="$NEW_VERSION_SECTION" '
+        /^## @section Sharding configuration/ {
+            print new_section
+            print ""
+        }
+        { print }
+    ' "$VALUES_FILE" > "$TEMP_FILE.tmp"
+    mv "$TEMP_FILE.tmp" "$VALUES_FILE"
+fi
+
+echo "Successfully updated $VALUES_FILE with major versions: ${MAJOR_VERSIONS[*]}"
diff --git a/packages/apps/mongodb/logos/mongodb.svg b/packages/apps/mongodb/logos/mongodb.svg
new file mode 100644
index 00000000..86bb6d40
--- /dev/null
+++ b/packages/apps/mongodb/logos/mongodb.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/apps/mysql/templates/.gitkeep b/packages/apps/mongodb/templates/.gitkeep
similarity index 100%
rename from packages/apps/mysql/templates/.gitkeep
rename to packages/apps/mongodb/templates/.gitkeep
diff --git a/packages/apps/mongodb/templates/_versions.tpl b/packages/apps/mongodb/templates/_versions.tpl
new file mode 100644
index 00000000..6afc6457
--- /dev/null
+++ b/packages/apps/mongodb/templates/_versions.tpl
@@ -0,0 +1,12 @@
+{{/*
+MongoDB version mapping
+*/}}
+{{- define "mongodb.versionMap" -}}
+{{- $versions := .Files.Get "files/versions.yaml" | fromYaml -}}
+{{- $version := .Values.version -}}
+{{- if hasKey $versions $version -}}
+{{- index $versions $version -}}
+{{- else -}}
+{{- fail (printf "Unsupported MongoDB version: %s. Supported versions: %s" $version (keys $versions | sortAlpha | join ", ")) -}}
+{{- end -}}
+{{- end -}}
diff --git a/packages/apps/mongodb/templates/backup-secret.yaml b/packages/apps/mongodb/templates/backup-secret.yaml
new file mode 100644
index 00000000..f7b2ba01
--- /dev/null
+++ b/packages/apps/mongodb/templates/backup-secret.yaml
@@ -0,0 +1,11 @@
+{{- if or .Values.backup.enabled .Values.bootstrap.enabled }}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ .Release.Name }}-s3-creds
+type: Opaque
+stringData:
+  AWS_ACCESS_KEY_ID: {{ required "backup.s3AccessKey is required when backup or bootstrap is enabled" .Values.backup.s3AccessKey | quote }}
+  AWS_SECRET_ACCESS_KEY: {{ required "backup.s3SecretKey is required when backup or bootstrap is enabled" .Values.backup.s3SecretKey | quote }}
+{{- end }}
diff --git a/packages/apps/mongodb/templates/credentials.yaml b/packages/apps/mongodb/templates/credentials.yaml
new file mode 100644
index 00000000..561f7672
--- /dev/null
+++ b/packages/apps/mongodb/templates/credentials.yaml
@@ -0,0 +1,34 @@
+{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }}
+{{- $operatorSecret := lookup "v1" "Secret" .Release.Namespace (printf "internal-%s-users" .Release.Name) }}
+{{- $password := "" }}
+{{- if and $operatorSecret (hasKey $operatorSecret.data "MONGODB_DATABASE_ADMIN_PASSWORD") }}
+{{- $password = index $operatorSecret.data "MONGODB_DATABASE_ADMIN_PASSWORD" | b64dec }}
+{{- end }}
+---
+# Dashboard credentials - lookup from operator-created secret
+# Operator creates secret named "internal--users" with system user passwords
+# Note: On first install, password/uri will be empty until operator creates the secret.
+# Run 'helm upgrade' after MongoDB is ready to populate credentials.
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ .Release.Name }}-credentials
+type: Opaque
+stringData:
+  username: databaseAdmin
+  password: {{ $password | quote }}
+  {{- if .Values.sharding }}
+  host: {{ .Release.Name }}-mongos.{{ .Release.Namespace }}.svc.{{ $clusterDomain }}
+  {{- else }}
+  host: {{ .Release.Name }}-rs0.{{ .Release.Namespace }}.svc.{{ $clusterDomain }}
+  {{- end }}
+  port: "27017"
+  {{- if $password }}
+  {{- if .Values.sharding }}
+  uri: mongodb://databaseAdmin:{{ $password | urlquery }}@{{ .Release.Name }}-mongos.{{ .Release.Namespace }}.svc.{{ $clusterDomain }}:27017/admin
+  {{- else }}
+  uri: mongodb://databaseAdmin:{{ $password | urlquery }}@{{ .Release.Name }}-rs0.{{ .Release.Namespace }}.svc.{{ $clusterDomain }}:27017/admin?replicaSet=rs0
+  {{- end }}
+  {{- else }}
+  uri: ""
+  {{- end }}
diff --git a/packages/apps/ferretdb/templates/dashboard-resourcemap.yaml b/packages/apps/mongodb/templates/dashboard-resourcemap.yaml
similarity index 89%
rename from packages/apps/ferretdb/templates/dashboard-resourcemap.yaml
rename to packages/apps/mongodb/templates/dashboard-resourcemap.yaml
index af40a6fa..33a6a4ef 100644
--- a/packages/apps/ferretdb/templates/dashboard-resourcemap.yaml
+++ b/packages/apps/mongodb/templates/dashboard-resourcemap.yaml
@@ -8,7 +8,9 @@ rules:
   resources:
   - services
   resourceNames:
-  - {{ .Release.Name }}
+  - {{ .Release.Name }}-rs0
+  - {{ .Release.Name }}-mongos
+  - {{ .Release.Name }}-external
   verbs: ["get", "list", "watch"]
 - apiGroups:
   - ""
diff --git a/packages/apps/mongodb/templates/external-svc.yaml b/packages/apps/mongodb/templates/external-svc.yaml
new file mode 100644
index 00000000..22324514
--- /dev/null
+++ b/packages/apps/mongodb/templates/external-svc.yaml
@@ -0,0 +1,24 @@
+{{- if .Values.external }}
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Release.Name }}-external
+spec:
+  type: LoadBalancer
+  externalTrafficPolicy: Local
+  {{- if (include "cozy-lib.network.disableLoadBalancerNodePorts" $ | fromYaml) }}
+  allocateLoadBalancerNodePorts: false
+  {{- end }}
+  ports:
+  - name: mongodb
+    port: 27017
+  selector:
+    app.kubernetes.io/name: percona-server-mongodb
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    {{- if .Values.sharding }}
+    app.kubernetes.io/component: mongos
+    {{- else }}
+    app.kubernetes.io/component: mongod
+    app.kubernetes.io/replset: rs0
+    {{- end }}
+{{- end }}
diff --git a/packages/apps/mongodb/templates/mongodb.yaml b/packages/apps/mongodb/templates/mongodb.yaml
new file mode 100644
index 00000000..9273e506
--- /dev/null
+++ b/packages/apps/mongodb/templates/mongodb.yaml
@@ -0,0 +1,191 @@
+{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }}
+---
+apiVersion: psmdb.percona.com/v1
+kind: PerconaServerMongoDB
+metadata:
+  name: {{ .Release.Name }}
+spec:
+  crVersion: 1.21.1
+  clusterServiceDNSSuffix: svc.{{ $clusterDomain }}
+  pause: false
+  unmanaged: false
+  image: percona/percona-server-mongodb:{{ include "mongodb.versionMap" $ }}
+  imagePullPolicy: IfNotPresent
+
+  {{- if lt (int .Values.replicas) 3 }}
+  unsafeFlags:
+    replsetSize: true
+  {{- end }}
+
+  updateStrategy: SmartUpdate
+  upgradeOptions:
+    apply: disabled
+
+  pmm:
+    enabled: false
+    image: percona/pmm-client:2.44.1
+    serverHost: ""
+
+  sharding:
+    enabled: {{ .Values.sharding | default false }}
+    balancer:
+      enabled: true
+    {{- if .Values.sharding }}
+    configsvrReplSet:
+      size: {{ .Values.shardingConfig.configServers }}
+      resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 8 }}
+      volumeSpec:
+        persistentVolumeClaim:
+          {{- with .Values.storageClass }}
+          storageClassName: {{ . }}
+          {{- end }}
+          accessModes:
+            - ReadWriteOnce
+          resources:
+            requests:
+              storage: {{ .Values.shardingConfig.configServerSize }}
+      affinity:
+        antiAffinityTopologyKey: kubernetes.io/hostname
+      podDisruptionBudget:
+        maxUnavailable: 1
+    mongos:
+      size: {{ .Values.shardingConfig.mongos }}
+      resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 8 }}
+      affinity:
+        antiAffinityTopologyKey: kubernetes.io/hostname
+      podDisruptionBudget:
+        maxUnavailable: 1
+      expose:
+        exposeType: ClusterIP
+    {{- end }}
+
+  replsets:
+    {{- if .Values.sharding }}
+    {{- range .Values.shardingConfig.shards }}
+    - name: {{ .name }}
+      size: {{ .replicas }}
+      resources: {{- include "cozy-lib.resources.defaultingSanitize" (list $.Values.resourcesPreset $.Values.resources $) | nindent 8 }}
+      volumeSpec:
+        persistentVolumeClaim:
+          {{- with $.Values.storageClass }}
+          storageClassName: {{ . }}
+          {{- end }}
+          accessModes:
+            - ReadWriteOnce
+          resources:
+            requests:
+              storage: {{ .size }}
+      affinity:
+        antiAffinityTopologyKey: kubernetes.io/hostname
+      podDisruptionBudget:
+        maxUnavailable: 1
+    {{- end }}
+    {{- else }}
+    - name: rs0
+      size: {{ .Values.replicas }}
+      resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 8 }}
+      volumeSpec:
+        persistentVolumeClaim:
+          {{- with .Values.storageClass }}
+          storageClassName: {{ . }}
+          {{- end }}
+          accessModes:
+            - ReadWriteOnce
+          resources:
+            requests:
+              storage: {{ .Values.size }}
+      affinity:
+        antiAffinityTopologyKey: kubernetes.io/hostname
+      podDisruptionBudget:
+        maxUnavailable: 1
+      expose:
+        enabled: false
+    {{- end }}
+
+  {{- if .Values.users }}
+  {{- /* Build a map of username -> list of roles from databases config */}}
+  {{- $userRoles := dict }}
+  {{- range $dbname, $db := .Values.databases }}
+    {{- range $user := $db.roles.admin }}
+      {{- $roles := index $userRoles $user | default list }}
+      {{- $roles = append $roles (dict "name" "readWrite" "db" $dbname) }}
+      {{- $roles = append $roles (dict "name" "dbAdmin" "db" $dbname) }}
+      {{- $_ := set $userRoles $user $roles }}
+    {{- end }}
+    {{- range $user := $db.roles.readonly }}
+      {{- $roles := index $userRoles $user | default list }}
+      {{- $roles = append $roles (dict "name" "read" "db" $dbname) }}
+      {{- $_ := set $userRoles $user $roles }}
+    {{- end }}
+  {{- end }}
+  users:
+    {{- range $username, $user := .Values.users }}
+    {{- $roles := index $userRoles $username }}
+    {{- if not $roles }}
+    {{- fail (printf "user '%s' is not assigned to any database role in databases.*.roles" $username) }}
+    {{- end }}
+    - name: {{ $username }}
+      db: admin
+      passwordSecretRef:
+        name: {{ $.Release.Name }}-user-{{ $username }}
+        key: password
+      roles:
+        {{- range $roles }}
+        - name: {{ .name }}
+          db: {{ .db }}
+        {{- end }}
+    {{- end }}
+  {{- end }}
+
+  backup:
+    enabled: {{ .Values.backup.enabled | default false }}
+    image: percona/percona-backup-mongodb:2.11.0
+    {{- if .Values.backup.enabled }}
+    storages:
+      s3-storage:
+        type: s3
+        s3:
+          bucket: {{ .Values.backup.destinationPath | trimPrefix "s3://" | regexFind "^[^/]+" }}
+          prefix: {{ .Values.backup.destinationPath | trimPrefix "s3://" | splitList "/" | rest | join "/" }}
+          endpointUrl: {{ .Values.backup.endpointURL }}
+          credentialsSecret: {{ .Release.Name }}-s3-creds
+          insecureSkipTLSVerify: false
+          forcePathStyle: true
+    tasks:
+      - name: daily-backup
+        enabled: true
+        schedule: {{ .Values.backup.schedule | quote }}
+        keep: {{ .Values.backup.retentionPolicy | trimSuffix "d" | int }}
+        storageName: s3-storage
+        type: logical
+        compressionType: gzip
+    pitr:
+      enabled: true
+    {{- end }}
+---
+# WorkloadMonitor tracks data-bearing mongod pods only (not config servers or mongos routers)
+# The selector filters by component=mongod, so we only count shard replicas
+apiVersion: cozystack.io/v1alpha1
+kind: WorkloadMonitor
+metadata:
+  name: {{ .Release.Name }}
+  labels:
+    workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }}
+spec:
+  {{- if .Values.sharding }}
+  {{- $totalReplicas := 0 }}
+  {{- range .Values.shardingConfig.shards }}
+  {{- $totalReplicas = add $totalReplicas .replicas }}
+  {{- end }}
+  replicas: {{ $totalReplicas }}
+  {{- else }}
+  replicas: {{ .Values.replicas }}
+  {{- end }}
+  minReplicas: 1
+  kind: mongodb
+  type: mongodb
+  selector:
+    app.kubernetes.io/name: percona-server-mongodb
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/component: mongod
+  version: {{ .Chart.Version }}
diff --git a/packages/apps/mongodb/templates/restore.yaml b/packages/apps/mongodb/templates/restore.yaml
new file mode 100644
index 00000000..56e2150b
--- /dev/null
+++ b/packages/apps/mongodb/templates/restore.yaml
@@ -0,0 +1,37 @@
+{{- if .Values.bootstrap.enabled }}
+{{- if not .Values.bootstrap.backupName }}
+{{- fail "bootstrap.backupName is required when bootstrap.enabled is true" }}
+{{- end }}
+{{- if not .Values.backup.destinationPath }}
+{{- fail "backup.destinationPath is required when bootstrap.enabled is true" }}
+{{- end }}
+{{- if not .Values.backup.endpointURL }}
+{{- fail "backup.endpointURL is required when bootstrap.enabled is true" }}
+{{- end }}
+{{- if not .Values.backup.s3AccessKey }}
+{{- fail "backup.s3AccessKey is required when bootstrap.enabled is true" }}
+{{- end }}
+{{- if not .Values.backup.s3SecretKey }}
+{{- fail "backup.s3SecretKey is required when bootstrap.enabled is true" }}
+{{- end }}
+---
+apiVersion: psmdb.percona.com/v1
+kind: PerconaServerMongoDBRestore
+metadata:
+  name: {{ .Release.Name }}-restore
+spec:
+  clusterName: {{ .Release.Name }}
+  {{- if .Values.bootstrap.recoveryTime }}
+  pitr:
+    type: date
+    date: {{ .Values.bootstrap.recoveryTime | quote }}
+  {{- end }}
+  backupSource:
+    type: logical
+    destination: {{ .Values.backup.destinationPath | trimSuffix "/" }}/{{ .Values.bootstrap.backupName }}
+    s3:
+      credentialsSecret: {{ .Release.Name }}-s3-creds
+      endpointUrl: {{ .Values.backup.endpointURL }}
+      insecureSkipTLSVerify: false
+      forcePathStyle: true
+{{- end }}
diff --git a/packages/apps/mongodb/templates/user-secrets.yaml b/packages/apps/mongodb/templates/user-secrets.yaml
new file mode 100644
index 00000000..8212e95f
--- /dev/null
+++ b/packages/apps/mongodb/templates/user-secrets.yaml
@@ -0,0 +1,17 @@
+{{- range $username, $user := .Values.users }}
+{{- $existingSecret := lookup "v1" "Secret" $.Release.Namespace (printf "%s-user-%s" $.Release.Name $username) }}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ $.Release.Name }}-user-{{ $username }}
+type: Opaque
+stringData:
+  {{- if $user.password }}
+  password: {{ $user.password | quote }}
+  {{- else if and $existingSecret (hasKey $existingSecret.data "password") }}
+  password: {{ index $existingSecret.data "password" | b64dec | quote }}
+  {{- else }}
+  password: {{ randAlphaNum 16 | quote }}
+  {{- end }}
+{{- end }}
diff --git a/packages/apps/mongodb/tests/backup-secret_test.yaml b/packages/apps/mongodb/tests/backup-secret_test.yaml
new file mode 100644
index 00000000..f3eca410
--- /dev/null
+++ b/packages/apps/mongodb/tests/backup-secret_test.yaml
@@ -0,0 +1,112 @@
+suite: backup secret tests
+
+templates:
+  - templates/backup-secret.yaml
+
+tests:
+  # Not rendered when both backup and bootstrap disabled
+  - it: does not render when backup and bootstrap disabled
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      backup:
+        enabled: false
+      bootstrap:
+        enabled: false
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  # Rendered when backup enabled
+  - it: renders when backup enabled
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      backup:
+        enabled: true
+        s3AccessKey: "AKIAIOSFODNN7EXAMPLE"
+        s3SecretKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: Secret
+
+  # Rendered when bootstrap enabled (for restore)
+  - it: renders when bootstrap enabled
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      backup:
+        enabled: false
+        s3AccessKey: "AKIAIOSFODNN7EXAMPLE"
+        s3SecretKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
+      bootstrap:
+        enabled: true
+    asserts:
+      - hasDocuments:
+          count: 1
+
+  # Secret name
+  - it: uses correct secret name
+    release:
+      name: mydb
+      namespace: tenant-test
+    set:
+      backup:
+        enabled: true
+        s3AccessKey: "accesskey"
+        s3SecretKey: "secretkey"
+    asserts:
+      - equal:
+          path: metadata.name
+          value: mydb-s3-creds
+
+  # Contains AWS credentials
+  - it: contains AWS credentials
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      backup:
+        enabled: true
+        s3AccessKey: "MYACCESSKEY"
+        s3SecretKey: "MYSECRETKEY"
+    asserts:
+      - equal:
+          path: stringData.AWS_ACCESS_KEY_ID
+          value: "MYACCESSKEY"
+      - equal:
+          path: stringData.AWS_SECRET_ACCESS_KEY
+          value: "MYSECRETKEY"
+
+  # Fails without s3AccessKey
+  - it: fails when s3AccessKey missing
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      backup:
+        enabled: true
+        s3AccessKey: ""
+        s3SecretKey: "secretkey"
+    asserts:
+      - failedTemplate:
+          errorMessage: "backup.s3AccessKey is required when backup or bootstrap is enabled"
+
+  # Fails without s3SecretKey
+  - it: fails when s3SecretKey missing
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      backup:
+        enabled: true
+        s3AccessKey: "accesskey"
+        s3SecretKey: ""
+    asserts:
+      - failedTemplate:
+          errorMessage: "backup.s3SecretKey is required when backup or bootstrap is enabled"
diff --git a/packages/apps/mongodb/tests/credentials_test.yaml b/packages/apps/mongodb/tests/credentials_test.yaml
new file mode 100644
index 00000000..b06924ef
--- /dev/null
+++ b/packages/apps/mongodb/tests/credentials_test.yaml
@@ -0,0 +1,132 @@
+suite: credentials tests
+
+templates:
+  - templates/credentials.yaml
+
+tests:
+  # Basic rendering
+  - it: always renders a Secret
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: Secret
+      - equal:
+          path: metadata.name
+          value: test-mongodb-credentials
+      - equal:
+          path: type
+          value: Opaque
+
+  # Username is always databaseAdmin
+  - it: sets username to databaseAdmin
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+    asserts:
+      - equal:
+          path: stringData.username
+          value: databaseAdmin
+
+  # Port is always 27017
+  - it: sets port to 27017
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+    asserts:
+      - equal:
+          path: stringData.port
+          value: "27017"
+
+  # Host for replica set mode
+  - it: uses rs0 service for replica set mode
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      sharding: false
+    asserts:
+      - equal:
+          path: stringData.host
+          value: test-mongodb-rs0.tenant-test.svc.cozy.local
+
+  # Host for sharded mode
+  - it: uses mongos service for sharded mode
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      sharding: true
+    asserts:
+      - equal:
+          path: stringData.host
+          value: test-mongodb-mongos.tenant-test.svc.cozy.local
+
+  # Custom cluster domain
+  - it: uses custom cluster domain
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: custom.domain
+      sharding: false
+    asserts:
+      - equal:
+          path: stringData.host
+          value: test-mongodb-rs0.tenant-test.svc.custom.domain
+
+  # Default cluster domain when not set
+  - it: defaults to cozy.local when cluster domain not set
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster: {}
+      sharding: false
+    asserts:
+      - equal:
+          path: stringData.host
+          value: test-mongodb-rs0.tenant-test.svc.cozy.local
+
+  # Password empty without operator secret (lookup returns nil in tests)
+  - it: has empty password on first install
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+    asserts:
+      - equal:
+          path: stringData.password
+          value: ""
+
+  # URI empty without password
+  - it: has empty uri when password not available
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+    asserts:
+      - equal:
+          path: stringData.uri
+          value: ""
diff --git a/packages/apps/mongodb/tests/dashboard-resourcemap_test.yaml b/packages/apps/mongodb/tests/dashboard-resourcemap_test.yaml
new file mode 100644
index 00000000..8cc1a0a7
--- /dev/null
+++ b/packages/apps/mongodb/tests/dashboard-resourcemap_test.yaml
@@ -0,0 +1,106 @@
+suite: dashboard resourcemap tests
+
+templates:
+  - templates/dashboard-resourcemap.yaml
+
+tests:
+  # Always renders Role and RoleBinding
+  - it: renders Role and RoleBinding
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    asserts:
+      - hasDocuments:
+          count: 2
+      - isKind:
+          of: Role
+        documentIndex: 0
+      - isKind:
+          of: RoleBinding
+        documentIndex: 1
+
+  # Role naming
+  - it: uses correct Role name
+    release:
+      name: mydb
+      namespace: tenant-test
+    asserts:
+      - equal:
+          path: metadata.name
+          value: mydb-dashboard-resources
+        documentIndex: 0
+
+  # RoleBinding naming
+  - it: uses correct RoleBinding name
+    release:
+      name: mydb
+      namespace: tenant-test
+    asserts:
+      - equal:
+          path: metadata.name
+          value: mydb-dashboard-resources
+        documentIndex: 1
+
+  # Role grants access to services
+  - it: grants access to MongoDB services
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    asserts:
+      - contains:
+          path: rules[0].resourceNames
+          content: test-mongodb-rs0
+        documentIndex: 0
+      - contains:
+          path: rules[0].resourceNames
+          content: test-mongodb-mongos
+        documentIndex: 0
+      - contains:
+          path: rules[0].resourceNames
+          content: test-mongodb-external
+        documentIndex: 0
+
+  # Role grants access to credentials secret
+  - it: grants access to credentials secret
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    asserts:
+      - contains:
+          path: rules[1].resourceNames
+          content: test-mongodb-credentials
+        documentIndex: 0
+
+  # Role grants access to workloadmonitor
+  - it: grants access to WorkloadMonitor
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    asserts:
+      - contains:
+          path: rules[2].resourceNames
+          content: test-mongodb
+        documentIndex: 0
+      - equal:
+          path: rules[2].apiGroups[0]
+          value: cozystack.io
+        documentIndex: 0
+
+  # RoleBinding references correct Role
+  - it: RoleBinding references correct Role
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    asserts:
+      - equal:
+          path: roleRef.kind
+          value: Role
+        documentIndex: 1
+      - equal:
+          path: roleRef.name
+          value: test-mongodb-dashboard-resources
+        documentIndex: 1
+      - equal:
+          path: roleRef.apiGroup
+          value: rbac.authorization.k8s.io
+        documentIndex: 1
diff --git a/packages/apps/mongodb/tests/external-svc_test.yaml b/packages/apps/mongodb/tests/external-svc_test.yaml
new file mode 100644
index 00000000..ed3bf597
--- /dev/null
+++ b/packages/apps/mongodb/tests/external-svc_test.yaml
@@ -0,0 +1,154 @@
+suite: external service tests
+
+templates:
+  - templates/external-svc.yaml
+
+tests:
+  ###################
+  # Rendering       #
+  ###################
+
+  - it: does not render when external is false
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      external: false
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: renders LoadBalancer service when external is true
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      external: true
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: Service
+
+  ###################
+  # Service config  #
+  ###################
+
+  - it: uses correct service name
+    release:
+      name: mydb
+      namespace: tenant-test
+    set:
+      external: true
+    asserts:
+      - equal:
+          path: metadata.name
+          value: mydb-external
+
+  - it: sets LoadBalancer type
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      external: true
+    asserts:
+      - equal:
+          path: spec.type
+          value: LoadBalancer
+
+  - it: sets externalTrafficPolicy to Local
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      external: true
+    asserts:
+      - equal:
+          path: spec.externalTrafficPolicy
+          value: Local
+
+  - it: exposes MongoDB port 27017
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      external: true
+    asserts:
+      - equal:
+          path: spec.ports[0].name
+          value: mongodb
+      - equal:
+          path: spec.ports[0].port
+          value: 27017
+
+  ###########################
+  # Common selector labels  #
+  ###########################
+
+  - it: sets app.kubernetes.io/name selector
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      external: true
+    asserts:
+      - equal:
+          path: spec.selector["app.kubernetes.io/name"]
+          value: percona-server-mongodb
+
+  - it: sets app.kubernetes.io/instance selector
+    release:
+      name: mydb
+      namespace: tenant-test
+    set:
+      external: true
+    asserts:
+      - equal:
+          path: spec.selector["app.kubernetes.io/instance"]
+          value: mydb
+
+  ###########################
+  # Replica set mode        #
+  ###########################
+
+  - it: selects mongod for replica set mode
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      external: true
+      sharding: false
+    asserts:
+      - equal:
+          path: spec.selector["app.kubernetes.io/component"]
+          value: mongod
+      - equal:
+          path: spec.selector["app.kubernetes.io/replset"]
+          value: rs0
+
+  ###########################
+  # Sharded mode            #
+  ###########################
+
+  - it: selects mongos for sharded mode
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      external: true
+      sharding: true
+    asserts:
+      - equal:
+          path: spec.selector["app.kubernetes.io/component"]
+          value: mongos
+
+  - it: does not set replset selector for sharded mode
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      external: true
+      sharding: true
+    asserts:
+      - notExists:
+          path: spec.selector["app.kubernetes.io/replset"]
diff --git a/packages/apps/mongodb/tests/mongodb_test.yaml b/packages/apps/mongodb/tests/mongodb_test.yaml
new file mode 100644
index 00000000..4154ca25
--- /dev/null
+++ b/packages/apps/mongodb/tests/mongodb_test.yaml
@@ -0,0 +1,731 @@
+suite: mongodb CR tests
+
+templates:
+  - templates/mongodb.yaml
+
+tests:
+  ###################
+  # Basic rendering #
+  ###################
+
+  - it: renders PerconaServerMongoDB and WorkloadMonitor
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+    asserts:
+      - hasDocuments:
+          count: 2
+      - isKind:
+          of: PerconaServerMongoDB
+        documentIndex: 0
+      - isKind:
+          of: WorkloadMonitor
+        documentIndex: 1
+
+  - it: sets correct CR name
+    release:
+      name: my-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+    asserts:
+      - equal:
+          path: metadata.name
+          value: my-mongodb
+        documentIndex: 0
+
+  ##################
+  # CR Version     #
+  ##################
+
+  - it: sets crVersion to 1.21.1
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+    asserts:
+      - equal:
+          path: spec.crVersion
+          value: "1.21.1"
+        documentIndex: 0
+
+  #####################
+  # Cluster DNS       #
+  #####################
+
+  - it: sets clusterServiceDNSSuffix from cluster config
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: custom.local
+    asserts:
+      - equal:
+          path: spec.clusterServiceDNSSuffix
+          value: svc.custom.local
+        documentIndex: 0
+
+  - it: defaults clusterServiceDNSSuffix to cozy.local
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster: {}
+    asserts:
+      - equal:
+          path: spec.clusterServiceDNSSuffix
+          value: svc.cozy.local
+        documentIndex: 0
+
+  ##################
+  # Unsafe flags   #
+  ##################
+
+  - it: enables unsafeFlags when replicas is 1
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      replicas: 1
+    asserts:
+      - equal:
+          path: spec.unsafeFlags.replsetSize
+          value: true
+        documentIndex: 0
+
+  - it: enables unsafeFlags when replicas is 2
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      replicas: 2
+    asserts:
+      - equal:
+          path: spec.unsafeFlags.replsetSize
+          value: true
+        documentIndex: 0
+
+  - it: does not set unsafeFlags when replicas is 3
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      replicas: 3
+    asserts:
+      - notExists:
+          path: spec.unsafeFlags
+        documentIndex: 0
+
+  - it: does not set unsafeFlags when replicas is 5
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      replicas: 5
+    asserts:
+      - notExists:
+          path: spec.unsafeFlags
+        documentIndex: 0
+
+  ###########################
+  # Replica Set Mode        #
+  ###########################
+
+  - it: configures replica set rs0 in non-sharded mode
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      sharding: false
+      replicas: 3
+    asserts:
+      - equal:
+          path: spec.sharding.enabled
+          value: false
+        documentIndex: 0
+      - equal:
+          path: spec.replsets[0].name
+          value: rs0
+        documentIndex: 0
+      - equal:
+          path: spec.replsets[0].size
+          value: 3
+        documentIndex: 0
+
+  - it: sets storage size for replica set
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      sharding: false
+      size: 20Gi
+    asserts:
+      - equal:
+          path: spec.replsets[0].volumeSpec.persistentVolumeClaim.resources.requests.storage
+          value: 20Gi
+        documentIndex: 0
+
+  - it: sets storageClass when provided
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      sharding: false
+      storageClass: fast-ssd
+    asserts:
+      - equal:
+          path: spec.replsets[0].volumeSpec.persistentVolumeClaim.storageClassName
+          value: fast-ssd
+        documentIndex: 0
+
+  - it: does not set storageClass when empty
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      sharding: false
+      storageClass: ""
+    asserts:
+      - notExists:
+          path: spec.replsets[0].volumeSpec.persistentVolumeClaim.storageClassName
+        documentIndex: 0
+
+  ###########################
+  # Sharded Cluster Mode    #
+  ###########################
+
+  - it: enables sharding when configured
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      sharding: true
+      shardingConfig:
+        configServers: 3
+        configServerSize: 3Gi
+        mongos: 2
+        shards:
+          - name: rs0
+            replicas: 3
+            size: 10Gi
+    asserts:
+      - equal:
+          path: spec.sharding.enabled
+          value: true
+        documentIndex: 0
+      - equal:
+          path: spec.sharding.balancer.enabled
+          value: true
+        documentIndex: 0
+
+  - it: configures config servers
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      sharding: true
+      shardingConfig:
+        configServers: 5
+        configServerSize: 5Gi
+        mongos: 2
+        shards:
+          - name: rs0
+            replicas: 3
+            size: 10Gi
+    asserts:
+      - equal:
+          path: spec.sharding.configsvrReplSet.size
+          value: 5
+        documentIndex: 0
+      - equal:
+          path: spec.sharding.configsvrReplSet.volumeSpec.persistentVolumeClaim.resources.requests.storage
+          value: 5Gi
+        documentIndex: 0
+
+  - it: configures mongos routers
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      sharding: true
+      shardingConfig:
+        configServers: 3
+        configServerSize: 3Gi
+        mongos: 4
+        shards:
+          - name: rs0
+            replicas: 3
+            size: 10Gi
+    asserts:
+      - equal:
+          path: spec.sharding.mongos.size
+          value: 4
+        documentIndex: 0
+      - equal:
+          path: spec.sharding.mongos.expose.exposeType
+          value: ClusterIP
+        documentIndex: 0
+
+  - it: configures multiple shards
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      sharding: true
+      shardingConfig:
+        configServers: 3
+        configServerSize: 3Gi
+        mongos: 2
+        shards:
+          - name: shard1
+            replicas: 3
+            size: 50Gi
+          - name: shard2
+            replicas: 5
+            size: 100Gi
+    asserts:
+      - equal:
+          path: spec.replsets[0].name
+          value: shard1
+        documentIndex: 0
+      - equal:
+          path: spec.replsets[0].size
+          value: 3
+        documentIndex: 0
+      - equal:
+          path: spec.replsets[0].volumeSpec.persistentVolumeClaim.resources.requests.storage
+          value: 50Gi
+        documentIndex: 0
+      - equal:
+          path: spec.replsets[1].name
+          value: shard2
+        documentIndex: 0
+      - equal:
+          path: spec.replsets[1].size
+          value: 5
+        documentIndex: 0
+      - equal:
+          path: spec.replsets[1].volumeSpec.persistentVolumeClaim.resources.requests.storage
+          value: 100Gi
+        documentIndex: 0
+
+  ###########################
+  # Users configuration     #
+  ###########################
+
+  - it: does not include users section when no users defined
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      users: {}
+      databases: {}
+    asserts:
+      - notExists:
+          path: spec.users
+        documentIndex: 0
+
+  - it: configures users with admin role
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      users:
+        appuser: {}
+      databases:
+        appdb:
+          roles:
+            admin:
+              - appuser
+    asserts:
+      - exists:
+          path: spec.users
+        documentIndex: 0
+      - equal:
+          path: spec.users[0].name
+          value: appuser
+        documentIndex: 0
+      - equal:
+          path: spec.users[0].db
+          value: admin
+        documentIndex: 0
+      - equal:
+          path: spec.users[0].passwordSecretRef.name
+          value: test-mongodb-user-appuser
+        documentIndex: 0
+      - equal:
+          path: spec.users[0].passwordSecretRef.key
+          value: password
+        documentIndex: 0
+
+  - it: assigns readWrite and dbAdmin roles for admin users
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      users:
+        appuser: {}
+      databases:
+        mydb:
+          roles:
+            admin:
+              - appuser
+    asserts:
+      - equal:
+          path: spec.users[0].roles[0].name
+          value: readWrite
+        documentIndex: 0
+      - equal:
+          path: spec.users[0].roles[0].db
+          value: mydb
+        documentIndex: 0
+      - equal:
+          path: spec.users[0].roles[1].name
+          value: dbAdmin
+        documentIndex: 0
+      - equal:
+          path: spec.users[0].roles[1].db
+          value: mydb
+        documentIndex: 0
+
+  - it: assigns read role for readonly users
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      users:
+        reader: {}
+      databases:
+        mydb:
+          roles:
+            readonly:
+              - reader
+    asserts:
+      - equal:
+          path: spec.users[0].roles[0].name
+          value: read
+        documentIndex: 0
+      - equal:
+          path: spec.users[0].roles[0].db
+          value: mydb
+        documentIndex: 0
+
+  - it: fails when user is not assigned to any database role
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      users:
+        myuser: {}
+      databases: {}
+    asserts:
+      - failedTemplate:
+          errorMessage: "user 'myuser' is not assigned to any database role in databases.*.roles"
+
+  ###########################
+  # Backup configuration    #
+  ###########################
+
+  - it: disables backup when not enabled
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      backup:
+        enabled: false
+    asserts:
+      - equal:
+          path: spec.backup.enabled
+          value: false
+        documentIndex: 0
+      - notExists:
+          path: spec.backup.storages
+        documentIndex: 0
+
+  - it: configures backup when enabled
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      backup:
+        enabled: true
+        schedule: "0 3 * * *"
+        retentionPolicy: 14d
+        destinationPath: "s3://mybucket/backups/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.backup.enabled
+          value: true
+        documentIndex: 0
+      - equal:
+          path: spec.backup.storages.s3-storage.type
+          value: s3
+        documentIndex: 0
+
+  - it: parses bucket from destinationPath
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      backup:
+        enabled: true
+        destinationPath: "s3://my-backup-bucket/mongodb/prod/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.backup.storages.s3-storage.s3.bucket
+          value: my-backup-bucket
+        documentIndex: 0
+
+  - it: parses prefix from destinationPath
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      backup:
+        enabled: true
+        destinationPath: "s3://bucket/path/to/backups/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.backup.storages.s3-storage.s3.prefix
+          value: path/to/backups/
+        documentIndex: 0
+
+  - it: sets backup retention from retentionPolicy
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      backup:
+        enabled: true
+        retentionPolicy: 30d
+        destinationPath: "s3://bucket/path/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.backup.tasks[0].keep
+          value: 30
+        documentIndex: 0
+
+  - it: sets backup schedule
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      backup:
+        enabled: true
+        schedule: "0 4 * * *"
+        retentionPolicy: 7d
+        destinationPath: "s3://bucket/path/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.backup.tasks[0].schedule
+          value: "0 4 * * *"
+        documentIndex: 0
+
+  - it: enables PITR when backup enabled
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      backup:
+        enabled: true
+        destinationPath: "s3://bucket/path/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.backup.pitr.enabled
+          value: true
+        documentIndex: 0
+
+  - it: references s3-creds secret for backup
+    release:
+      name: mydb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      backup:
+        enabled: true
+        destinationPath: "s3://bucket/path/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.backup.storages.s3-storage.s3.credentialsSecret
+          value: mydb-s3-creds
+        documentIndex: 0
+
+  ###########################
+  # WorkloadMonitor         #
+  ###########################
+
+  - it: creates WorkloadMonitor with correct metadata
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+    asserts:
+      - equal:
+          path: metadata.name
+          value: test-mongodb
+        documentIndex: 1
+      - equal:
+          path: spec.kind
+          value: mongodb
+        documentIndex: 1
+      - equal:
+          path: spec.type
+          value: mongodb
+        documentIndex: 1
+
+  - it: sets replicas from values in non-sharded mode
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      sharding: false
+      replicas: 5
+    asserts:
+      - equal:
+          path: spec.replicas
+          value: 5
+        documentIndex: 1
+
+  - it: calculates total replicas in sharded mode
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+      sharding: true
+      shardingConfig:
+        configServers: 3
+        configServerSize: 3Gi
+        mongos: 2
+        shards:
+          - name: rs0
+            replicas: 3
+            size: 10Gi
+          - name: rs1
+            replicas: 5
+            size: 10Gi
+          - name: rs2
+            replicas: 2
+            size: 10Gi
+    asserts:
+      - equal:
+          path: spec.replicas
+          value: 10
+        documentIndex: 1
+
+  - it: sets minReplicas to 1
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+    asserts:
+      - equal:
+          path: spec.minReplicas
+          value: 1
+        documentIndex: 1
+
+  - it: sets correct selector labels
+    release:
+      name: mydb
+      namespace: tenant-test
+    set:
+      _cluster:
+        cluster-domain: cozy.local
+    asserts:
+      - equal:
+          path: spec.selector["app.kubernetes.io/name"]
+          value: percona-server-mongodb
+        documentIndex: 1
+      - equal:
+          path: spec.selector["app.kubernetes.io/instance"]
+          value: mydb
+        documentIndex: 1
+      - equal:
+          path: spec.selector["app.kubernetes.io/component"]
+          value: mongod
+        documentIndex: 1
+
diff --git a/packages/apps/mongodb/tests/restore_test.yaml b/packages/apps/mongodb/tests/restore_test.yaml
new file mode 100644
index 00000000..e591587b
--- /dev/null
+++ b/packages/apps/mongodb/tests/restore_test.yaml
@@ -0,0 +1,349 @@
+suite: restore tests
+
+templates:
+  - templates/restore.yaml
+
+tests:
+  #####################
+  # Rendering         #
+  #####################
+
+  - it: does not render when bootstrap is disabled
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: false
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: renders PerconaServerMongoDBRestore CR when enabled
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "my-backup-2025-01-07"
+      backup:
+        destinationPath: "s3://bucket/backups/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: PerconaServerMongoDBRestore
+
+  #####################
+  # Validation        #
+  #####################
+
+  - it: fails when backupName is missing
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: ""
+      backup:
+        destinationPath: "s3://bucket/path/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - failedTemplate:
+          errorMessage: "bootstrap.backupName is required when bootstrap.enabled is true"
+
+  - it: fails when destinationPath is missing
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "my-backup"
+      backup:
+        destinationPath: ""
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - failedTemplate:
+          errorMessage: "backup.destinationPath is required when bootstrap.enabled is true"
+
+  - it: fails when endpointURL is missing
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "my-backup"
+      backup:
+        destinationPath: "s3://bucket/path/"
+        endpointURL: ""
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - failedTemplate:
+          errorMessage: "backup.endpointURL is required when bootstrap.enabled is true"
+
+  #####################
+  # CR metadata       #
+  #####################
+
+  - it: uses correct restore CR name
+    release:
+      name: mydb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "backup-2025"
+      backup:
+        destinationPath: "s3://bucket/backups/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: metadata.name
+          value: mydb-restore
+
+  - it: references correct cluster name
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "backup-2025"
+      backup:
+        destinationPath: "s3://bucket/backups/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.clusterName
+          value: test-mongodb
+
+  #####################
+  # Backup source     #
+  #####################
+
+  - it: sets backupSource type to logical
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "backup-2025"
+      backup:
+        destinationPath: "s3://bucket/backups/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.backupSource.type
+          value: logical
+
+  - it: constructs destination from destinationPath and backupName
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "daily-backup-2025-01-07"
+      backup:
+        destinationPath: "s3://mybucket/mongodb/prod/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.backupSource.destination
+          value: s3://mybucket/mongodb/prod/daily-backup-2025-01-07
+
+  - it: trims trailing slash from destinationPath
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "backup"
+      backup:
+        destinationPath: "s3://bucket/path/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.backupSource.destination
+          value: s3://bucket/path/backup
+
+  #####################
+  # S3 configuration  #
+  #####################
+
+  - it: references s3-creds secret
+    release:
+      name: mydb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "backup"
+      backup:
+        destinationPath: "s3://bucket/path/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.backupSource.s3.credentialsSecret
+          value: mydb-s3-creds
+
+  - it: sets S3 endpoint URL
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "backup"
+      backup:
+        destinationPath: "s3://bucket/path/"
+        endpointURL: "https://s3.amazonaws.com"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.backupSource.s3.endpointUrl
+          value: "https://s3.amazonaws.com"
+
+  - it: disables insecureSkipTLSVerify
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "backup"
+      backup:
+        destinationPath: "s3://bucket/path/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.backupSource.s3.insecureSkipTLSVerify
+          value: false
+
+  - it: enables forcePathStyle
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "backup"
+      backup:
+        destinationPath: "s3://bucket/path/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.backupSource.s3.forcePathStyle
+          value: true
+
+  #####################
+  # PITR              #
+  #####################
+
+  - it: does not set pitr when recoveryTime not specified
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "backup"
+      backup:
+        destinationPath: "s3://bucket/path/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - notExists:
+          path: spec.pitr
+
+  - it: configures PITR when recoveryTime is set
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "my-backup"
+        recoveryTime: "2025-01-07 14:30:00"
+      backup:
+        destinationPath: "s3://bucket/backups/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: "secret"
+    asserts:
+      - equal:
+          path: spec.pitr.type
+          value: date
+      - equal:
+          path: spec.pitr.date
+          value: "2025-01-07 14:30:00"
+
+  #####################
+  # S3 credentials    #
+  #####################
+
+  - it: fails when s3AccessKey is missing
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "backup"
+      backup:
+        destinationPath: "s3://bucket/path/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: ""
+        s3SecretKey: "secret"
+    asserts:
+      - failedTemplate:
+          errorMessage: "backup.s3AccessKey is required when bootstrap.enabled is true"
+
+  - it: fails when s3SecretKey is missing
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      bootstrap:
+        enabled: true
+        backupName: "backup"
+      backup:
+        destinationPath: "s3://bucket/path/"
+        endpointURL: "http://minio:9000"
+        s3AccessKey: "access"
+        s3SecretKey: ""
+    asserts:
+      - failedTemplate:
+          errorMessage: "backup.s3SecretKey is required when bootstrap.enabled is true"
diff --git a/packages/apps/mongodb/tests/user-secrets_test.yaml b/packages/apps/mongodb/tests/user-secrets_test.yaml
new file mode 100644
index 00000000..6d9fb388
--- /dev/null
+++ b/packages/apps/mongodb/tests/user-secrets_test.yaml
@@ -0,0 +1,78 @@
+suite: user secrets tests
+
+templates:
+  - templates/user-secrets.yaml
+
+tests:
+  # No users configured
+  - it: does not render when no users defined
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      users: {}
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  # Single user
+  - it: creates secret for single user
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      users:
+        myuser: {}
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: Secret
+      - equal:
+          path: metadata.name
+          value: test-mongodb-user-myuser
+      - equal:
+          path: type
+          value: Opaque
+      - exists:
+          path: stringData.password
+
+  # Multiple users
+  - it: creates separate secrets for multiple users
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      users:
+        user1: {}
+        user2: {}
+    asserts:
+      - hasDocuments:
+          count: 2
+
+  # User with explicit password
+  - it: uses explicit password when provided
+    release:
+      name: test-mongodb
+      namespace: tenant-test
+    set:
+      users:
+        myuser:
+          password: "mysecretpassword"
+    asserts:
+      - equal:
+          path: stringData.password
+          value: "mysecretpassword"
+
+  # Secret naming convention
+  - it: follows naming convention release-user-username
+    release:
+      name: prod-db
+      namespace: tenant-prod
+    set:
+      users:
+        admin: {}
+    asserts:
+      - equal:
+          path: metadata.name
+          value: prod-db-user-admin
diff --git a/packages/apps/mongodb/values.schema.json b/packages/apps/mongodb/values.schema.json
new file mode 100644
index 00000000..2d077cfc
--- /dev/null
+++ b/packages/apps/mongodb/values.schema.json
@@ -0,0 +1,290 @@
+{
+  "title": "Chart Values",
+  "type": "object",
+  "properties": {
+    "replicas": {
+      "description": "Number of MongoDB replicas in replica set.",
+      "type": "integer",
+      "default": 3
+    },
+    "resources": {
+      "description": "Explicit CPU and memory configuration for each MongoDB replica. When omitted, the preset defined in `resourcesPreset` is applied.",
+      "type": "object",
+      "default": {},
+      "properties": {
+        "cpu": {
+          "description": "CPU available to each replica.",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
+        },
+        "memory": {
+          "description": "Memory (RAM) available to each replica.",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
+        }
+      }
+    },
+    "resourcesPreset": {
+      "description": "Default sizing preset used when `resources` is omitted.",
+      "type": "string",
+      "default": "small",
+      "enum": [
+        "nano",
+        "micro",
+        "small",
+        "medium",
+        "large",
+        "xlarge",
+        "2xlarge"
+      ]
+    },
+    "size": {
+      "description": "Persistent Volume Claim size available for application data.",
+      "default": "10Gi",
+      "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+      "anyOf": [
+        {
+          "type": "integer"
+        },
+        {
+          "type": "string"
+        }
+      ],
+      "x-kubernetes-int-or-string": true
+    },
+    "storageClass": {
+      "description": "StorageClass used to store the data.",
+      "type": "string",
+      "default": ""
+    },
+    "external": {
+      "description": "Enable external access from outside the cluster.",
+      "type": "boolean",
+      "default": false
+    },
+    "version": {
+      "description": "MongoDB major version to deploy.",
+      "type": "string",
+      "default": "v8",
+      "enum": [
+        "v8",
+        "v7",
+        "v6"
+      ]
+    },
+    "sharding": {
+      "description": "Enable sharded cluster mode. When disabled, deploys a replica set.",
+      "type": "boolean",
+      "default": false
+    },
+    "shardingConfig": {
+      "description": "Configuration for sharded cluster mode.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "configServerSize",
+        "configServers",
+        "mongos"
+      ],
+      "properties": {
+        "configServerSize": {
+          "description": "PVC size for config servers.",
+          "default": "3Gi",
+          "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ],
+          "x-kubernetes-int-or-string": true
+        },
+        "configServers": {
+          "description": "Number of config server replicas.",
+          "type": "integer",
+          "default": 3
+        },
+        "mongos": {
+          "description": "Number of mongos router replicas.",
+          "type": "integer",
+          "default": 2
+        },
+        "shards": {
+          "description": "List of shard configurations.",
+          "type": "array",
+          "default": [
+            {
+              "name": "rs0",
+              "replicas": 3,
+              "size": "10Gi"
+            }
+          ],
+          "items": {
+            "type": "object",
+            "required": [
+              "name",
+              "replicas",
+              "size"
+            ],
+            "properties": {
+              "name": {
+                "description": "Shard name.",
+                "type": "string"
+              },
+              "replicas": {
+                "description": "Number of replicas in this shard.",
+                "type": "integer"
+              },
+              "size": {
+                "description": "PVC size for this shard.",
+                "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
+                "anyOf": [
+                  {
+                    "type": "integer"
+                  },
+                  {
+                    "type": "string"
+                  }
+                ],
+                "x-kubernetes-int-or-string": true
+              }
+            }
+          }
+        }
+      }
+    },
+    "users": {
+      "description": "Users configuration map.",
+      "type": "object",
+      "default": {},
+      "additionalProperties": {
+        "type": "object",
+        "properties": {
+          "password": {
+            "description": "Password for the user (auto-generated if omitted).",
+            "type": "string"
+          }
+        }
+      }
+    },
+    "databases": {
+      "description": "Databases configuration map.",
+      "type": "object",
+      "default": {},
+      "additionalProperties": {
+        "type": "object",
+        "properties": {
+          "roles": {
+            "description": "Roles assigned to users.",
+            "type": "object",
+            "properties": {
+              "admin": {
+                "description": "List of users with admin privileges (readWrite + dbAdmin).",
+                "type": "array",
+                "items": {
+                  "type": "string"
+                }
+              },
+              "readonly": {
+                "description": "List of users with read-only privileges.",
+                "type": "array",
+                "items": {
+                  "type": "string"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "backup": {
+      "description": "Backup configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "enabled"
+      ],
+      "properties": {
+        "destinationPath": {
+          "description": "Destination path for backups (e.g. s3://bucket/path/).",
+          "type": "string",
+          "default": "s3://bucket/path/to/folder/"
+        },
+        "enabled": {
+          "description": "Enable regular backups.",
+          "type": "boolean",
+          "default": false
+        },
+        "endpointURL": {
+          "description": "S3 endpoint URL for uploads.",
+          "type": "string",
+          "default": "http://minio-gateway-service:9000"
+        },
+        "retentionPolicy": {
+          "description": "Retention policy (e.g. \"30d\").",
+          "type": "string",
+          "default": "30d"
+        },
+        "s3AccessKey": {
+          "description": "Access key for S3 authentication.",
+          "type": "string",
+          "default": ""
+        },
+        "s3SecretKey": {
+          "description": "Secret key for S3 authentication.",
+          "type": "string",
+          "default": ""
+        },
+        "schedule": {
+          "description": "Cron schedule for automated backups.",
+          "type": "string",
+          "default": "0 2 * * *"
+        }
+      }
+    },
+    "bootstrap": {
+      "description": "Bootstrap configuration.",
+      "type": "object",
+      "default": {},
+      "required": [
+        "backupName",
+        "enabled"
+      ],
+      "properties": {
+        "backupName": {
+          "description": "Name of backup to restore from.",
+          "type": "string",
+          "default": ""
+        },
+        "enabled": {
+          "description": "Whether to restore from a backup.",
+          "type": "boolean",
+          "default": false
+        },
+        "recoveryTime": {
+          "description": "Timestamp for point-in-time recovery; empty means latest.",
+          "type": "string",
+          "default": ""
+        }
+      }
+    }
+  }
+}
diff --git a/packages/apps/mongodb/values.yaml b/packages/apps/mongodb/values.yaml
new file mode 100644
index 00000000..df8fbe37
--- /dev/null
+++ b/packages/apps/mongodb/values.yaml
@@ -0,0 +1,146 @@
+##
+## @section Common parameters
+##
+
+## @typedef {struct} Resources - Explicit CPU and memory configuration for each MongoDB replica.
+## @field {quantity} [cpu] - CPU available to each replica.
+## @field {quantity} [memory] - Memory (RAM) available to each replica.
+
+## @enum {string} ResourcesPreset - Default sizing preset.
+## @value nano
+## @value micro
+## @value small
+## @value medium
+## @value large
+## @value xlarge
+## @value 2xlarge
+
+## @param {int} replicas - Number of MongoDB replicas in replica set.
+replicas: 3
+
+## @param {Resources} [resources] - Explicit CPU and memory configuration for each MongoDB replica. When omitted, the preset defined in `resourcesPreset` is applied.
+resources: {}
+
+## @param {ResourcesPreset} resourcesPreset="small" - Default sizing preset used when `resources` is omitted.
+resourcesPreset: "small"
+
+## @param {quantity} size - Persistent Volume Claim size available for application data.
+size: 10Gi
+
+## @param {string} storageClass - StorageClass used to store the data.
+storageClass: ""
+
+## @param {bool} external - Enable external access from outside the cluster.
+external: false
+
+##
+## @enum {string} Version
+## @value v8
+## @value v7
+## @value v6
+
+## @param {Version} version - MongoDB major version to deploy.
+version: v8
+
+##
+## @section Sharding configuration
+##
+
+## @param {bool} sharding - Enable sharded cluster mode. When disabled, deploys a replica set.
+sharding: false
+
+## @typedef {struct} ShardingConfig - Sharded cluster configuration.
+## @field {int} configServers - Number of config server replicas.
+## @field {quantity} configServerSize - PVC size for config servers.
+## @field {int} mongos - Number of mongos router replicas.
+## @field {[]Shard} shards - List of shard configurations.
+
+## @typedef {struct} Shard - Individual shard configuration.
+## @field {string} name - Shard name.
+## @field {int} replicas - Number of replicas in this shard.
+## @field {quantity} size - PVC size for this shard.
+
+## @param {ShardingConfig} shardingConfig - Configuration for sharded cluster mode.
+shardingConfig:
+  configServers: 3
+  configServerSize: 3Gi
+  mongos: 2
+  shards:
+    - name: rs0
+      replicas: 3
+      size: 10Gi
+
+##
+## @section Users configuration
+##
+
+## @typedef {struct} User - User configuration.
+## @field {string} [password] - Password for the user (auto-generated if omitted).
+
+## @param {map[string]User} users - Users configuration map.
+users: {}
+## Example:
+## users:
+##   user1:
+##     password: strongpassword
+##   user2: {}
+
+##
+## @section Databases configuration
+##
+
+## @typedef {struct} DatabaseRoles - Role assignments for a database.
+## @field {[]string} [admin] - List of users with admin privileges (readWrite + dbAdmin).
+## @field {[]string} [readonly] - List of users with read-only privileges.
+
+## @typedef {struct} Database - Database configuration.
+## @field {DatabaseRoles} [roles] - Roles assigned to users.
+
+## @param {map[string]Database} databases - Databases configuration map.
+databases: {}
+## Example:
+## databases:
+##   myapp:
+##     roles:
+##       admin:
+##       - user1
+##       readonly:
+##       - user2
+
+##
+## @section Backup parameters
+##
+
+## @typedef {struct} Backup - Backup configuration.
+## @field {bool} enabled - Enable regular backups.
+## @field {string} [schedule] - Cron schedule for automated backups.
+## @field {string} [retentionPolicy] - Retention policy (e.g. "30d").
+## @field {string} [destinationPath] - Destination path for backups (e.g. s3://bucket/path/).
+## @field {string} [endpointURL] - S3 endpoint URL for uploads.
+## @field {string} [s3AccessKey] - Access key for S3 authentication.
+## @field {string} [s3SecretKey] - Secret key for S3 authentication.
+
+## @param {Backup} backup - Backup configuration.
+backup:
+  enabled: false
+  schedule: "0 2 * * *"
+  retentionPolicy: 30d
+  destinationPath: "s3://bucket/path/to/folder/"
+  endpointURL: "http://minio-gateway-service:9000"
+  s3AccessKey: ""
+  s3SecretKey: ""
+
+##
+## @section Bootstrap (recovery) parameters
+##
+
+## @typedef {struct} Bootstrap - Bootstrap configuration for restoring a database cluster from a backup.
+## @field {bool} enabled - Whether to restore from a backup.
+## @field {string} [recoveryTime] - Timestamp for point-in-time recovery; empty means latest.
+## @field {string} backupName - Name of backup to restore from.
+
+## @param {Bootstrap} bootstrap - Bootstrap configuration.
+bootstrap:
+  enabled: false
+  recoveryTime: ""
+  backupName: ""
diff --git a/packages/apps/mysql/README.md b/packages/apps/mysql/README.md
deleted file mode 100644
index 53c9b218..00000000
--- a/packages/apps/mysql/README.md
+++ /dev/null
@@ -1,149 +0,0 @@
-## Managed MariaDB Service
-
-The Managed MariaDB Service offers a powerful and widely used relational database solution.
-This service allows you to create and manage a replicated MariaDB cluster seamlessly.
-
-## Deployment Details
-
-This managed service is controlled by mariadb-operator, ensuring efficient management and seamless operation.
-
-- Docs: https://mariadb.com/kb/en/documentation/
-- GitHub: https://github.com/mariadb-operator/mariadb-operator
-
-## HowTos
-
-### How to switch master/slave replica
-
-```
-kubectl edit mariadb 
-```
-update:
-
-```
-spec:
-  replication:
-    primary:
-      podIndex: 1
-```
-
-check status:
-
-```
-NAME        READY   STATUS    PRIMARY POD   AGE
-  True    Running   app-db1-1     41d
-```
-
-### How to restore backup:
-
-find snapshot:
-```
-restic -r s3:s3.example.org/mariadb-backups/database_name snapshots
-```
-
-
-restore:
-```
-restic -r s3:s3.example.org/mariadb-backups/database_name restore latest --target /tmp/
-```
-
-more details:
-- https://blog.aenix.io/restic-effective-backup-from-stdin-4bc1e8f083c1
-
-### Known issues
-
-- **Replication can't not be finished with various errors**
-- **Replication can't be finised in case if binlog purged**
-  Until mariadbbackup is not used to bootstrap a node by mariadb-operator (this feature is not inmplemented yet), follow these manual steps to fix it:
-  https://github.com/mariadb-operator/mariadb-operator/issues/141#issuecomment-1804760231
-
-- **Corrupted indicies**
-  Sometimes some indecies can be corrupted on master replica, you can recover them from slave:
-
-  ```
-  mysqldump -h  -P 3306 -u -p --column-statistics=0  
~/tmp/fix-table.sql - mysql -h -P 3306 -u -p < ~/tmp/fix-table.sql - ``` - -## Parameters - -### Common parameters - -| Name | Description | Value | -| -------------- | ----------------------------------------------- | ------- | -| `external` | Enable external access from outside the cluster | `false` | -| `size` | Persistent Volume size | `10Gi` | -| `replicas` | Number of MariaDB replicas | `2` | -| `storageClass` | StorageClass used to store the data | `""` | - -### Configuration parameters - -| Name | Description | Value | -| ----------- | ----------------------- | ----- | -| `users` | Users configuration | `{}` | -| `databases` | Databases configuration | `{}` | - -### Backup parameters - -| Name | Description | Value | -| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------ | -| `backup.enabled` | Enable periodic backups | `false` | -| `backup.s3Region` | The AWS S3 region where backups are stored | `us-east-1` | -| `backup.s3Bucket` | The S3 bucket used for storing backups | `s3.example.org/postgres-backups` | -| `backup.schedule` | Cron schedule for automated backups | `0 2 * * *` | -| `backup.cleanupStrategy` | The strategy for cleaning up old backups | `--keep-last=3 --keep-daily=3 --keep-within-weekly=1m` | -| `backup.s3AccessKey` | The access key for S3, used for authentication | `oobaiRus9pah8PhohL1ThaeTa4UVa7gu` | -| `backup.s3SecretKey` | The secret key for S3, used for authentication | `ju3eum4dekeich9ahM1te8waeGai0oog` | -| `backup.resticPassword` | The password for Restic backup encryption | `ChaXoveekoh6eigh4siesheeda2quai0` | -| `resources` | Explicit CPU and memory configuration for each MariaDB replica. When left empty, the preset defined in `resourcesPreset` is applied. | `{}` | -| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge. | `nano` | - -## Parameter examples and reference - -### resources and resourcesPreset - -`resources` sets explicit CPU and memory configurations for each replica. -When left empty, the preset defined in `resourcesPreset` is applied. - -```yaml -resources: - cpu: 4000m - memory: 4Gi -``` - -`resourcesPreset` sets named CPU and memory configurations for each replica. -This setting is ignored if the corresponding `resources` value is set. - -| Preset name | CPU | memory | -|-------------|--------|---------| -| `nano` | `250m` | `128Mi` | -| `micro` | `500m` | `256Mi` | -| `small` | `1` | `512Mi` | -| `medium` | `1` | `1Gi` | -| `large` | `2` | `2Gi` | -| `xlarge` | `4` | `4Gi` | -| `2xlarge` | `8` | `8Gi` | - -### users - -```yaml -users: - user1: - maxUserConnections: 1000 - password: hackme - user2: - maxUserConnections: 1000 - password: hackme -``` - - -### databases - -```yaml -databases: - myapp1: - roles: - admin: - - user1 - readonly: - - user2 -``` diff --git a/packages/apps/mysql/images/mariadb-backup.tag b/packages/apps/mysql/images/mariadb-backup.tag deleted file mode 100644 index 400814a1..00000000 --- a/packages/apps/mysql/images/mariadb-backup.tag +++ /dev/null @@ -1 +0,0 @@ -ghcr.io/cozystack/cozystack/mariadb-backup:0.9.0@sha256:cfd1c37d8ad24e10681d82d6e6ce8a641b4602c1b0ffa8516ae15b4958bb12d4 diff --git a/packages/apps/mysql/templates/backup-secret.yaml b/packages/apps/mysql/templates/backup-secret.yaml deleted file mode 100644 index be221e2f..00000000 --- a/packages/apps/mysql/templates/backup-secret.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{- if .Values.backup.enabled }} ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ .Release.Name }}-backup -stringData: - s3AccessKey: {{ required "s3AccessKey is not specified!" .Values.backup.s3AccessKey }} - s3SecretKey: {{ required "s3SecretKey is not specified!" .Values.backup.s3SecretKey }} - resticPassword: {{ required "resticPassword is not specified!" .Values.backup.resticPassword }} -{{- end }} diff --git a/packages/apps/mysql/values.schema.json b/packages/apps/mysql/values.schema.json deleted file mode 100644 index a183f764..00000000 --- a/packages/apps/mysql/values.schema.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "title": "Chart Values", - "type": "object", - "properties": { - "external": { - "type": "boolean", - "description": "Enable external access from outside the cluster", - "default": false - }, - "size": { - "type": "string", - "description": "Persistent Volume size", - "default": "10Gi" - }, - "replicas": { - "type": "number", - "description": "Number of MariaDB replicas", - "default": 2 - }, - "storageClass": { - "type": "string", - "description": "StorageClass used to store the data", - "default": "" - }, - "backup": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable periodic backups", - "default": false - }, - "s3Region": { - "type": "string", - "description": "The AWS S3 region where backups are stored", - "default": "us-east-1" - }, - "s3Bucket": { - "type": "string", - "description": "The S3 bucket used for storing backups", - "default": "s3.example.org/postgres-backups" - }, - "schedule": { - "type": "string", - "description": "Cron schedule for automated backups", - "default": "0 2 * * *" - }, - "cleanupStrategy": { - "type": "string", - "description": "The strategy for cleaning up old backups", - "default": "--keep-last=3 --keep-daily=3 --keep-within-weekly=1m" - }, - "s3AccessKey": { - "type": "string", - "description": "The access key for S3, used for authentication", - "default": "oobaiRus9pah8PhohL1ThaeTa4UVa7gu" - }, - "s3SecretKey": { - "type": "string", - "description": "The secret key for S3, used for authentication", - "default": "ju3eum4dekeich9ahM1te8waeGai0oog" - }, - "resticPassword": { - "type": "string", - "description": "The password for Restic backup encryption", - "default": "ChaXoveekoh6eigh4siesheeda2quai0" - } - } - }, - "resources": { - "type": "object", - "description": "Explicit CPU and memory configuration for each MariaDB replica. When left empty, the preset defined in `resourcesPreset` is applied.", - "default": {} - }, - "resourcesPreset": { - "type": "string", - "description": "Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.", - "default": "nano", - "enum": [ - "none", - "nano", - "micro", - "small", - "medium", - "large", - "xlarge", - "2xlarge" - ] - } - } -} diff --git a/packages/apps/mysql/values.yaml b/packages/apps/mysql/values.yaml deleted file mode 100644 index 1e74e340..00000000 --- a/packages/apps/mysql/values.yaml +++ /dev/null @@ -1,65 +0,0 @@ -## @section Common parameters - -## @param external Enable external access from outside the cluster -## @param size Persistent Volume size -## @param replicas Number of MariaDB replicas -## @param storageClass StorageClass used to store the data -## -external: false -size: 10Gi -replicas: 2 -storageClass: "" - -## @section Configuration parameters - -## @param users [object] Users configuration -## Example: -## users: -## user1: -## maxUserConnections: 1000 -## password: hackme -## user2: -## maxUserConnections: 1000 -## password: hackme -## -users: {} - -## @param databases [object] Databases configuration -## Example: -## databases: -## myapp1: -## roles: -## admin: -## - user1 -## readonly: -## - user2 -databases: {} - -## @section Backup parameters - -## @param backup.enabled Enable periodic backups -## @param backup.s3Region The AWS S3 region where backups are stored -## @param backup.s3Bucket The S3 bucket used for storing backups -## @param backup.schedule Cron schedule for automated backups -## @param backup.cleanupStrategy The strategy for cleaning up old backups -## @param backup.s3AccessKey The access key for S3, used for authentication -## @param backup.s3SecretKey The secret key for S3, used for authentication -## @param backup.resticPassword The password for Restic backup encryption -backup: - enabled: false - s3Region: us-east-1 - s3Bucket: s3.example.org/postgres-backups - schedule: "0 2 * * *" - cleanupStrategy: "--keep-last=3 --keep-daily=3 --keep-within-weekly=1m" - s3AccessKey: oobaiRus9pah8PhohL1ThaeTa4UVa7gu - s3SecretKey: ju3eum4dekeich9ahM1te8waeGai0oog - resticPassword: ChaXoveekoh6eigh4siesheeda2quai0 - -## @param resources Explicit CPU and memory configuration for each MariaDB replica. When left empty, the preset defined in `resourcesPreset` is applied. -resources: {} - # resources: - # cpu: 4000m - # memory: 4Gi - -## @param resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge. -resourcesPreset: "nano" diff --git a/packages/apps/nats/Chart.yaml b/packages/apps/nats/Chart.yaml index 882bf345..419b6183 100644 --- a/packages/apps/nats/Chart.yaml +++ b/packages/apps/nats/Chart.yaml @@ -2,24 +2,6 @@ apiVersion: v2 name: nats description: Managed NATS service icon: /logos/nats.svg - -# 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: 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.8.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. +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process appVersion: "1.4.1" diff --git a/packages/apps/nats/Makefile b/packages/apps/nats/Makefile index e4057cb4..29f6f9bc 100644 --- a/packages/apps/nats/Makefile +++ b/packages/apps/nats/Makefile @@ -1,5 +1,5 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: - readme-generator -v values.yaml -s values.schema.json -r README.md - yq -i -o json --indent 4 '.properties.resourcesPreset.enum = ["none", "nano", "micro", "small", "medium", "large", "xlarge", "2xlarge"]' values.schema.json + cozyvalues-gen -m 'nats' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/nats/types.go + ../../../hack/update-crd.sh diff --git a/packages/apps/nats/README.md b/packages/apps/nats/README.md index 01c2d835..7220c52c 100644 --- a/packages/apps/nats/README.md +++ b/packages/apps/nats/README.md @@ -7,18 +7,30 @@ It provides a data layer for cloud native applications, IoT messaging, and micro ### Common parameters -| Name | Description | Value | -| ------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------- | -| `external` | Enable external access from outside the cluster | `false` | -| `replicas` | Persistent Volume size for NATS | `2` | -| `storageClass` | StorageClass used to store the data | `""` | -| `users` | Users configuration | `{}` | -| `jetstream.size` | Jetstream persistent storage size | `10Gi` | -| `jetstream.enabled` | Enable or disable Jetstream | `true` | -| `config.merge` | Additional configuration to merge into NATS config | `{}` | -| `config.resolver` | Additional configuration to merge into NATS config | `{}` | -| `resources` | Explicit CPU and memory configuration for each NATS replica. When left empty, the preset defined in `resourcesPreset` is applied. | `{}` | -| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge. | `nano` | +| Name | Description | Type | Value | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------ | ---------- | ------- | +| `replicas` | Number of replicas. | `int` | `2` | +| `resources` | Explicit CPU and memory configuration for each NATS replica. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `resources.cpu` | CPU available to each replica. | `quantity` | `""` | +| `resources.memory` | Memory (RAM) available to each replica. | `quantity` | `""` | +| `resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `nano` | +| `storageClass` | StorageClass used to store the data. | `string` | `""` | +| `external` | Enable external access from outside the cluster. | `bool` | `false` | + + +### Application-specific parameters + +| Name | Description | Type | Value | +| ---------------------- | ------------------------------------------------------------- | ------------------- | ------ | +| `users` | Users configuration map. | `map[string]object` | `{}` | +| `users[name].password` | Password for the user. | `string` | `""` | +| `jetstream` | Jetstream configuration. | `object` | `{}` | +| `jetstream.enabled` | Enable or disable Jetstream for persistent messaging in NATS. | `bool` | `true` | +| `jetstream.size` | Jetstream persistent storage size. | `quantity` | `10Gi` | +| `config` | NATS configuration. | `object` | `{}` | +| `config.merge` | Additional configuration to merge into NATS config. | `*object` | `{}` | +| `config.resolver` | Additional resolver configuration to merge into NATS config. | `*object` | `{}` | + ## Parameter examples and reference diff --git a/packages/apps/nats/templates/nats.yaml b/packages/apps/nats/templates/nats.yaml index 75956b56..e5f5cf5d 100644 --- a/packages/apps/nats/templates/nats.yaml +++ b/packages/apps/nats/templates/nats.yaml @@ -1,6 +1,13 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }} +{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-credentials" .Release.Name) }} {{- $passwords := dict }} + +{{- with (dig "data" (dict) $existingSecret) }} + {{- range $k, $v := . }} + {{- $_ := set $passwords $k (b64dec $v) }} + {{- end }} +{{- end }} + {{- range $user, $u := .Values.users }} {{- if $u.password }} {{- $_ := set $passwords $user $u.password }} @@ -26,35 +33,35 @@ apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: {{ .Release.Name }}-system + labels: + sharding.fluxcd.io/key: tenants spec: - chart: - spec: - chart: cozy-nats - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' - interval: 1m0s - timeout: 5m0s + chartRef: + kind: ExternalArtifact + name: cozystack-nats-application-default-nats-system + namespace: cozy-system + interval: 5m + timeout: 10m + install: + remediation: + retries: -1 + upgrade: + force: true + remediation: + retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values values: nats: - podTemplate: + container: merge: - spec: - containers: - - name: nats - image: nats:2.10.17-alpine - resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 22 }} + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 12 }} fullnameOverride: {{ .Release.Name }} config: - cluster: - routeURLs: - k8sClusterDomain: {{ $clusterDomain }} - {{- if or (gt (len $passwords) 0) (gt (len .Values.config.merge) 0) }} + {{- if or $passwords .Values.config.merge }} merge: - {{- if gt (len $passwords) 0 }} + {{- if $passwords }} accounts: A: users: @@ -63,16 +70,18 @@ spec: password: "{{ $password }}" {{- end }} {{- end }} - {{- if and .Values.config (hasKey .Values.config "merge") }} - {{ toYaml .Values.config.merge | nindent 12 }} + {{- with .Values.config.merge }} + {{- toYaml . | nindent 10 }} {{- end }} {{- end }} - {{- if and .Values.config (hasKey .Values.config "resolver") }} + {{- with .Values.config.resolver }} resolver: - {{ toYaml .Values.config.resolver | nindent 12 }} + {{- toYaml . | nindent 10 }} {{- end }} cluster: enabled: true + routeURLs: + k8sClusterDomain: {{ $clusterDomain }} replicas: {{ .Values.replicas }} monitor: enabled: true @@ -86,10 +95,6 @@ spec: {{- with .Values.storageClass }} storageClassName: {{ . }} {{- end }} - promExporter: - enabled: true - podMonitor: - enabled: true {{- if .Values.external }} service: merge: diff --git a/packages/apps/nats/templates/workloadmonitor.yaml b/packages/apps/nats/templates/workloadmonitor.yaml index 43d64a46..cb20b4a6 100644 --- a/packages/apps/nats/templates/workloadmonitor.yaml +++ b/packages/apps/nats/templates/workloadmonitor.yaml @@ -3,6 +3,8 @@ apiVersion: cozystack.io/v1alpha1 kind: WorkloadMonitor metadata: name: {{ $.Release.Name }} + labels: + workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }} spec: replicas: {{ .Values.replicas }} minReplicas: 1 diff --git a/packages/apps/nats/values.schema.json b/packages/apps/nats/values.schema.json index 5d67d1c8..605c8752 100644 --- a/packages/apps/nats/values.schema.json +++ b/packages/apps/nats/values.schema.json @@ -1,71 +1,131 @@ { - "title": "Chart Values", - "type": "object", - "properties": { - "external": { - "type": "boolean", - "description": "Enable external access from outside the cluster", - "default": false - }, - "replicas": { - "type": "number", - "description": "Persistent Volume size for NATS", - "default": 2 - }, - "storageClass": { - "type": "string", - "description": "StorageClass used to store the data", - "default": "" - }, - "jetstream": { - "type": "object", - "properties": { - "size": { - "type": "string", - "description": "Jetstream persistent storage size", - "default": "10Gi" - }, - "enabled": { - "type": "boolean", - "description": "Enable or disable Jetstream", - "default": true - } + "title": "Chart Values", + "type": "object", + "properties": { + "replicas": { + "description": "Number of replicas.", + "type": "integer", + "default": 2 + }, + "resources": { + "description": "Explicit CPU and memory configuration for each NATS replica. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "CPU available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" } + ], + "x-kubernetes-int-or-string": true }, - "config": { - "type": "object", - "properties": { - "merge": { - "type": "object", - "description": "Additional configuration to merge into NATS config", - "default": {} - }, - "resolver": { - "type": "object", - "description": "Additional configuration to merge into NATS config", - "default": {} - } + "memory": { + "description": "Memory (RAM) available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" } - }, - "resources": { - "type": "object", - "description": "Explicit CPU and memory configuration for each NATS replica. When left empty, the preset defined in `resourcesPreset` is applied.", - "default": {} - }, - "resourcesPreset": { - "type": "string", - "description": "Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.", - "default": "nano", - "enum": [ - "none", - "nano", - "micro", - "small", - "medium", - "large", - "xlarge", - "2xlarge" - ] + ], + "x-kubernetes-int-or-string": true } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted.", + "type": "string", + "default": "nano", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + }, + "storageClass": { + "description": "StorageClass used to store the data.", + "type": "string", + "default": "" + }, + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + }, + "users": { + "description": "Users configuration map.", + "type": "object", + "default": {}, + "additionalProperties": { + "type": "object", + "properties": { + "password": { + "description": "Password for the user.", + "type": "string" + } + } + } + }, + "jetstream": { + "description": "Jetstream configuration.", + "type": "object", + "default": {}, + "required": [ + "enabled", + "size" + ], + "properties": { + "enabled": { + "description": "Enable or disable Jetstream for persistent messaging in NATS.", + "type": "boolean", + "default": true + }, + "size": { + "description": "Jetstream persistent storage size.", + "default": "10Gi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "config": { + "description": "NATS configuration.", + "type": "object", + "default": {}, + "properties": { + "merge": { + "description": "Additional configuration to merge into NATS config.", + "type": "object", + "default": {}, + "x-kubernetes-preserve-unknown-fields": true + }, + "resolver": { + "description": "Additional resolver configuration to merge into NATS config.", + "type": "object", + "default": {}, + "x-kubernetes-preserve-unknown-fields": true + } + } } + } } diff --git a/packages/apps/nats/values.yaml b/packages/apps/nats/values.yaml index 41b5021f..31d97713 100644 --- a/packages/apps/nats/values.yaml +++ b/packages/apps/nats/values.yaml @@ -1,72 +1,64 @@ - -## @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 +## @section Common parameters +## + +## @typedef {struct} Resources - Explicit CPU and memory configuration for each NATS replica. +## @field {quantity} [cpu] - CPU available to each replica. +## @field {quantity} [memory] - Memory (RAM) available to each replica. + +## @enum {string} ResourcesPreset - Default sizing preset. +## @value nano +## @value micro +## @value small +## @value medium +## @value large +## @value xlarge +## @value 2xlarge + +## @param {int} replicas - Number of replicas. replicas: 2 + +## @param {Resources} [resources] - Explicit CPU and memory configuration for each NATS replica. When omitted, the preset defined in `resourcesPreset` is applied. +resources: {} + +## @param {ResourcesPreset} resourcesPreset="nano" - Default sizing preset used when `resources` is omitted. +resourcesPreset: "nano" + +## @param {string} storageClass - StorageClass used to store the data. storageClass: "" -## @param users [object] Users configuration + +## @param {bool} external - Enable external access from outside the cluster. +external: false + +## +## @section Application-specific parameters +## + +## @typedef {struct} User - User configuration. +## @field {string} [password] - Password for the user. + +## @param {map[string]User} users - Users configuration map. +users: {} ## Example: ## users: ## user1: ## password: strongpassword ## user2: {} -users: {} +## @typedef {struct} Jetstream - Jetstream configuration. +## @field {bool} enabled=true - Enable or disable Jetstream for persistent messaging in NATS. +## @field {quantity} size - Jetstream persistent storage size. + +## @param {Jetstream} jetstream - Jetstream configuration. jetstream: - ## @param jetstream.size Jetstream persistent storage size - ## Specifies the size of the persistent storage for Jetstream (message store). - ## Default: 10Gi + enabled: true size: 10Gi - ## @param jetstream.enabled Enable or disable Jetstream - ## Set to true to enable Jetstream for persistent messaging in NATS. - ## Default: true - enabled: true +## @typedef {struct} Config - NATS configuration. +## @field {*object} [merge] - Additional configuration to merge into NATS config. +## @field {*object} [resolver] - Additional resolver configuration to merge into NATS config. +## @param {Config} config - NATS configuration. config: - ## @param config.merge Additional configuration to merge into NATS config - ## Allows you to customize NATS server settings by merging additional configurations. - ## For example, you can add extra parameters, configure authentication, or set custom settings. - ## Default: {} - ## example: - ## - ## merge: - ## $include: ./my-config.conf - ## zzz$include: ./my-config-last.conf - ## server_name: nats - ## authorization: - ## token: << $TOKEN >> - ## jetstream: - ## max_memory_store: << 1GB >> - ## - ## will yield the config: - ## { - ## include ./my-config.conf; - ## "authorization": { - ## "token": $TOKEN - ## }, - ## "jetstream": { - ## "max_memory_store": 1GB - ## }, - ## "server_name": "nats", - ## include ./my-config-last.conf; - ## } merge: {} - ## @param config.resolver Additional configuration to merge into NATS config - ## Allows you to customize NATS server settings by merging resolver configurations. - ## Default: {} - ## Example see: https://github.com/nats-io/k8s/blob/main/helm/charts/nats/values.yaml#L247 resolver: {} - -## @param resources Explicit CPU and memory configuration for each NATS replica. When left empty, the preset defined in `resourcesPreset` is applied. -resources: {} - # resources: - # cpu: 4000m - # memory: 4Gi - -## @param resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge. -resourcesPreset: "nano" diff --git a/packages/apps/ferretdb/.helmignore b/packages/apps/openbao/.helmignore similarity index 100% rename from packages/apps/ferretdb/.helmignore rename to packages/apps/openbao/.helmignore diff --git a/packages/apps/openbao/Chart.yaml b/packages/apps/openbao/Chart.yaml new file mode 100644 index 00000000..f33fc756 --- /dev/null +++ b/packages/apps/openbao/Chart.yaml @@ -0,0 +1,7 @@ +apiVersion: v2 +name: openbao +description: Managed OpenBAO secrets management service +icon: /logos/openbao.svg +type: application +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process +appVersion: "2.5.0" diff --git a/packages/apps/openbao/Makefile b/packages/apps/openbao/Makefile new file mode 100644 index 00000000..b9530139 --- /dev/null +++ b/packages/apps/openbao/Makefile @@ -0,0 +1,5 @@ +include ../../../hack/package.mk + +generate: + cozyvalues-gen -m 'openbao' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/openbao/types.go + ../../../hack/update-crd.sh diff --git a/packages/apps/openbao/README.md b/packages/apps/openbao/README.md new file mode 100644 index 00000000..c53c9d28 --- /dev/null +++ b/packages/apps/openbao/README.md @@ -0,0 +1,27 @@ +# Managed OpenBAO Service + +OpenBAO is an open-source secrets management solution forked from HashiCorp Vault. +It provides identity-based secrets and encryption management for cloud infrastructure. + +## Parameters + +### Common parameters + +| Name | Description | Type | Value | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------- | +| `replicas` | Number of OpenBAO replicas. HA with Raft is automatically enabled when replicas > 1. Switching between standalone (file storage) and HA (Raft storage) modes requires data migration. | `int` | `1` | +| `resources` | Explicit CPU and memory configuration for each OpenBAO replica. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `resources.cpu` | CPU available to each replica. | `quantity` | `""` | +| `resources.memory` | Memory (RAM) available to each replica. | `quantity` | `""` | +| `resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `small` | +| `size` | Persistent Volume Claim size for data storage. | `quantity` | `10Gi` | +| `storageClass` | StorageClass used to store the data. | `string` | `""` | +| `external` | Enable external access from outside the cluster. | `bool` | `false` | + + +### Application-specific parameters + +| Name | Description | Type | Value | +| ---- | -------------------------- | ------ | ------ | +| `ui` | Enable the OpenBAO web UI. | `bool` | `true` | + diff --git a/packages/apps/openbao/charts/cozy-lib b/packages/apps/openbao/charts/cozy-lib new file mode 120000 index 00000000..e1813509 --- /dev/null +++ b/packages/apps/openbao/charts/cozy-lib @@ -0,0 +1 @@ +../../../library/cozy-lib \ No newline at end of file diff --git a/packages/apps/openbao/logos/openbao.svg b/packages/apps/openbao/logos/openbao.svg new file mode 100644 index 00000000..5ce73b79 --- /dev/null +++ b/packages/apps/openbao/logos/openbao.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/apps/mysql/templates/_resources.tpl b/packages/apps/openbao/templates/_resources.tpl similarity index 91% rename from packages/apps/mysql/templates/_resources.tpl rename to packages/apps/openbao/templates/_resources.tpl index 6539c99a..7aeb976e 100644 --- a/packages/apps/mysql/templates/_resources.tpl +++ b/packages/apps/openbao/templates/_resources.tpl @@ -11,32 +11,32 @@ These presets are for basic testing and not meant to be used in production {{ include "resources.preset" (dict "type" "nano") -}} */}} {{- define "resources.preset" -}} -{{- $presets := dict - "nano" (dict +{{- $presets := dict + "nano" (dict "requests" (dict "cpu" "100m" "memory" "128Mi" "ephemeral-storage" "50Mi") "limits" (dict "memory" "128Mi" "ephemeral-storage" "2Gi") ) - "micro" (dict + "micro" (dict "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") "limits" (dict "memory" "256Mi" "ephemeral-storage" "2Gi") ) - "small" (dict + "small" (dict "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") "limits" (dict "memory" "512Mi" "ephemeral-storage" "2Gi") ) - "medium" (dict + "medium" (dict "requests" (dict "cpu" "500m" "memory" "1Gi" "ephemeral-storage" "50Mi") "limits" (dict "memory" "1Gi" "ephemeral-storage" "2Gi") ) - "large" (dict + "large" (dict "requests" (dict "cpu" "1" "memory" "2Gi" "ephemeral-storage" "50Mi") "limits" (dict "memory" "2Gi" "ephemeral-storage" "2Gi") ) - "xlarge" (dict + "xlarge" (dict "requests" (dict "cpu" "2" "memory" "4Gi" "ephemeral-storage" "50Mi") "limits" (dict "memory" "4Gi" "ephemeral-storage" "2Gi") ) - "2xlarge" (dict + "2xlarge" (dict "requests" (dict "cpu" "4" "memory" "8Gi" "ephemeral-storage" "50Mi") "limits" (dict "memory" "8Gi" "ephemeral-storage" "2Gi") ) diff --git a/packages/apps/virtual-machine/templates/dashboard-resourcemap.yaml b/packages/apps/openbao/templates/dashboard-resourcemap.yaml similarity index 67% rename from packages/apps/virtual-machine/templates/dashboard-resourcemap.yaml rename to packages/apps/openbao/templates/dashboard-resourcemap.yaml index 4beac5dc..452a07db 100644 --- a/packages/apps/virtual-machine/templates/dashboard-resourcemap.yaml +++ b/packages/apps/openbao/templates/dashboard-resourcemap.yaml @@ -8,7 +8,8 @@ rules: resources: - services resourceNames: - - {{ include "virtual-machine.fullname" . }} + - {{ .Release.Name }} + - {{ .Release.Name }}-internal verbs: ["get", "list", "watch"] - apiGroups: - cozystack.io @@ -28,16 +29,3 @@ roleRef: kind: Role name: {{ .Release.Name }}-dashboard-resources apiGroup: rbac.authorization.k8s.io ---- -apiVersion: cozystack.io/v1alpha1 -kind: WorkloadMonitor -metadata: - name: {{ $.Release.Name }} -spec: - replicas: 1 - minReplicas: 1 - kind: virtual-machine - type: virtual-machine - selector: - app.kubernetes.io/instance: {{ .Release.Name }} - version: {{ $.Chart.Version }} diff --git a/packages/apps/openbao/templates/openbao.yaml b/packages/apps/openbao/templates/openbao.yaml new file mode 100644 index 00000000..daa6f9c4 --- /dev/null +++ b/packages/apps/openbao/templates/openbao.yaml @@ -0,0 +1,99 @@ +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: {{ .Release.Name }}-system + labels: + sharding.fluxcd.io/key: tenants +spec: + chartRef: + kind: ExternalArtifact + name: cozystack-openbao-application-default-openbao-system + namespace: cozy-system + interval: 5m + timeout: 10m + install: + remediation: + retries: -1 + upgrade: + force: true + remediation: + retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values + values: + openbao: + fullnameOverride: {{ .Release.Name }} + global: + tlsDisable: true + server: + podManagementPolicy: Parallel + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 10 }} + dataStorage: + enabled: true + size: {{ .Values.size }} + {{- with .Values.storageClass }} + storageClass: {{ . }} + {{- end }} + {{- if gt (int .Values.replicas) 1 }} + standalone: + enabled: false + ha: + enabled: true + replicas: {{ .Values.replicas }} + raft: + enabled: true + setNodeId: true + config: | + ui = {{ .Values.ui }} + + listener "tcp" { + address = "[::]:8200" + cluster_address = "[::]:8201" + tls_disable = true + } + + storage "raft" { + path = "/openbao/data" + {{- range $i := until (int $.Values.replicas) }} + retry_join { + leader_api_addr = "http://{{ $.Release.Name }}-{{ $i }}.{{ $.Release.Name }}-internal:8200" + } + {{- end }} + } + + service_registration "kubernetes" {} + {{- else }} + standalone: + enabled: true + config: | + ui = {{ .Values.ui }} + + listener "tcp" { + address = "[::]:8200" + cluster_address = "[::]:8201" + tls_disable = true + } + + storage "file" { + path = "/openbao/data" + } + # Note: service_registration "kubernetes" {} is intentionally omitted + # in standalone mode — it requires an HA-capable storage backend and + # causes a fatal error with storage "file". + ha: + enabled: false + {{- end }} + {{- if .Values.external }} + service: + type: LoadBalancer + {{- end }} + ui: + enabled: {{ .Values.ui }} + {{- if .Values.external }} + serviceType: LoadBalancer + {{- end }} + injector: + enabled: false + csi: + enabled: false diff --git a/packages/apps/openbao/templates/workloadmonitor.yaml b/packages/apps/openbao/templates/workloadmonitor.yaml new file mode 100644 index 00000000..56f9ec8e --- /dev/null +++ b/packages/apps/openbao/templates/workloadmonitor.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: {{ $.Release.Name }} + labels: + workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }} +spec: + replicas: {{ .Values.replicas }} + minReplicas: 1 + kind: openbao + type: openbao + selector: + app.kubernetes.io/instance: {{ $.Release.Name }}-system + version: {{ $.Chart.Version }} diff --git a/packages/apps/openbao/values.schema.json b/packages/apps/openbao/values.schema.json new file mode 100644 index 00000000..9b32ddd6 --- /dev/null +++ b/packages/apps/openbao/values.schema.json @@ -0,0 +1,87 @@ +{ + "title": "Chart Values", + "type": "object", + "properties": { + "replicas": { + "description": "Number of OpenBAO replicas. HA with Raft is automatically enabled when replicas \u003e 1. Switching between standalone (file storage) and HA (Raft storage) modes requires data migration.", + "type": "integer", + "default": 1 + }, + "resources": { + "description": "Explicit CPU and memory configuration for each OpenBAO replica. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "CPU available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Memory (RAM) available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted.", + "type": "string", + "default": "small", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + }, + "size": { + "description": "Persistent Volume Claim size for data storage.", + "default": "10Gi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "storageClass": { + "description": "StorageClass used to store the data.", + "type": "string", + "default": "" + }, + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + }, + "ui": { + "description": "Enable the OpenBAO web UI.", + "type": "boolean", + "default": true + } + } +} diff --git a/packages/apps/openbao/values.yaml b/packages/apps/openbao/values.yaml new file mode 100644 index 00000000..fc8b75cc --- /dev/null +++ b/packages/apps/openbao/values.yaml @@ -0,0 +1,41 @@ +## +## @section Common parameters +## + +## @typedef {struct} Resources - Explicit CPU and memory configuration for each OpenBAO replica. +## @field {quantity} [cpu] - CPU available to each replica. +## @field {quantity} [memory] - Memory (RAM) available to each replica. + +## @enum {string} ResourcesPreset - Default sizing preset. +## @value nano +## @value micro +## @value small +## @value medium +## @value large +## @value xlarge +## @value 2xlarge + +## @param {int} replicas - Number of OpenBAO replicas. HA with Raft is automatically enabled when replicas > 1. Switching between standalone (file storage) and HA (Raft storage) modes requires data migration. +replicas: 1 + +## @param {Resources} [resources] - Explicit CPU and memory configuration for each OpenBAO replica. When omitted, the preset defined in `resourcesPreset` is applied. +resources: {} + +## @param {ResourcesPreset} resourcesPreset="small" - Default sizing preset used when `resources` is omitted. +resourcesPreset: "small" + +## @param {quantity} size - Persistent Volume Claim size for data storage. +size: 10Gi + +## @param {string} storageClass - StorageClass used to store the data. +storageClass: "" + +## @param {bool} external - Enable external access from outside the cluster. +external: false + +## +## @section Application-specific parameters +## + +## @param {bool} ui - Enable the OpenBAO web UI. +ui: true diff --git a/packages/system/monitoring-agents/charts/metrics-server/.helmignore b/packages/apps/opensearch/.helmignore similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/.helmignore rename to packages/apps/opensearch/.helmignore diff --git a/packages/apps/opensearch/Chart.yaml b/packages/apps/opensearch/Chart.yaml new file mode 100644 index 00000000..8abefadf --- /dev/null +++ b/packages/apps/opensearch/Chart.yaml @@ -0,0 +1,7 @@ +apiVersion: v2 +name: opensearch +description: Managed OpenSearch service +icon: /logos/opensearch.svg +type: application +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process +appVersion: "2.11.1" diff --git a/packages/apps/opensearch/Makefile b/packages/apps/opensearch/Makefile new file mode 100644 index 00000000..1781661f --- /dev/null +++ b/packages/apps/opensearch/Makefile @@ -0,0 +1,11 @@ +include ../../../hack/package.mk + +.PHONY: generate update + +generate: + cozyvalues-gen -m 'opensearch' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/opensearch/types.go + ../../../hack/update-crd.sh + +update: + hack/update-versions.sh + $(MAKE) generate diff --git a/packages/apps/opensearch/README.md b/packages/apps/opensearch/README.md new file mode 100644 index 00000000..d968c665 --- /dev/null +++ b/packages/apps/opensearch/README.md @@ -0,0 +1,60 @@ +# Managed OpenSearch Service + +## Parameters + +### Common parameters + +| Name | Description | Type | Value | +| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------- | +| `replicas` | Number of OpenSearch nodes in the cluster. | `int` | `3` | +| `resources` | Explicit CPU and memory configuration for each OpenSearch node. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `resources.cpu` | CPU available to each node. | `quantity` | `""` | +| `resources.memory` | Memory (RAM) available to each node. | `quantity` | `""` | +| `resourcesPreset` | Default sizing preset used when `resources` is omitted. OpenSearch requires minimum 2Gi memory. | `string` | `large` | +| `size` | Persistent Volume Claim size available for application data. | `quantity` | `10Gi` | +| `storageClass` | StorageClass used to store the data. | `string` | `""` | +| `external` | Enable external access from outside the cluster. | `bool` | `false` | +| `topologySpreadPolicy` | How strictly to enforce pod distribution across nodes and zones. | `string` | `soft` | +| `version` | OpenSearch major version to deploy. | `string` | `v2` | + + +### Image configuration + +| Name | Description | Type | Value | +| ------------------- | -------------------------------------- | -------- | ----- | +| `images` | Container images used by the operator. | `object` | `{}` | +| `images.opensearch` | OpenSearch image. | `string` | `""` | + + +### Node roles configuration + +| Name | Description | Type | Value | +| ------------------ | ----------------------------- | -------- | ------- | +| `nodeRoles` | Node roles configuration. | `object` | `{}` | +| `nodeRoles.master` | Enable cluster_manager role. | `bool` | `true` | +| `nodeRoles.data` | Enable data role. | `bool` | `true` | +| `nodeRoles.ingest` | Enable ingest role. | `bool` | `true` | +| `nodeRoles.ml` | Enable machine learning role. | `bool` | `false` | + + +### Users configuration + +| Name | Description | Type | Value | +| ---------------------- | -------------------------------------------------- | ------------------- | ----- | +| `users` | Custom OpenSearch users configuration map. | `map[string]object` | `{}` | +| `users[name].password` | Password for the user (auto-generated if omitted). | `string` | `""` | +| `users[name].roles` | List of OpenSearch roles. | `[]string` | `[]` | + + +### OpenSearch Dashboards configuration + +| Name | Description | Type | Value | +| ----------------------------- | ----------------------------------------------------- | ---------- | -------- | +| `dashboards` | OpenSearch Dashboards configuration. | `object` | `{}` | +| `dashboards.enabled` | Enable OpenSearch Dashboards deployment. | `bool` | `false` | +| `dashboards.replicas` | Number of Dashboards replicas. | `int` | `1` | +| `dashboards.resources` | Explicit CPU and memory configuration for Dashboards. | `object` | `{}` | +| `dashboards.resources.cpu` | CPU available to each node. | `quantity` | `""` | +| `dashboards.resources.memory` | Memory (RAM) available to each node. | `quantity` | `""` | +| `dashboards.resourcesPreset` | Default sizing preset for Dashboards. | `string` | `medium` | + diff --git a/packages/apps/opensearch/charts/cozy-lib b/packages/apps/opensearch/charts/cozy-lib new file mode 120000 index 00000000..e1813509 --- /dev/null +++ b/packages/apps/opensearch/charts/cozy-lib @@ -0,0 +1 @@ +../../../library/cozy-lib \ No newline at end of file diff --git a/packages/apps/opensearch/files/versions.yaml b/packages/apps/opensearch/files/versions.yaml new file mode 100644 index 00000000..be39fc80 --- /dev/null +++ b/packages/apps/opensearch/files/versions.yaml @@ -0,0 +1,5 @@ +# OpenSearch version mapping (major version -> image tag) +# Auto-generated by hack/update-versions.sh - do not edit manually +v3: "3.0.0" +v2: "2.11.1" +v1: "1.3.20" diff --git a/packages/apps/opensearch/hack/update-versions.sh b/packages/apps/opensearch/hack/update-versions.sh new file mode 100755 index 00000000..b2c4c946 --- /dev/null +++ b/packages/apps/opensearch/hack/update-versions.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OPENSEARCH_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +VERSIONS_FILE="${OPENSEARCH_DIR}/files/versions.yaml" + +# Supported major versions (newest first) +SUPPORTED_MAJOR_VERSIONS="3 2 1" + +echo "Supported major versions: $SUPPORTED_MAJOR_VERSIONS" + +# Check if skopeo is installed +if ! command -v skopeo &> /dev/null; then + echo "Error: skopeo is not installed. Please install skopeo and try again." >&2 + exit 1 +fi + +# Check if jq is installed +if ! command -v jq &> /dev/null; then + echo "Error: jq is not installed. Please install jq and try again." >&2 + exit 1 +fi + +# Get available image tags from Docker Hub +IMAGE="docker.io/opensearchproject/opensearch" +echo "Fetching available image tags from registry..." +TAGS=$(skopeo list-tags "docker://${IMAGE}" | jq -r '.Tags[]') + +echo "# OpenSearch version mapping (major version -> image tag)" > "${VERSIONS_FILE}" +echo "# Auto-generated by hack/update-versions.sh - do not edit manually" >> "${VERSIONS_FILE}" + +for MAJOR in $SUPPORTED_MAJOR_VERSIONS; do + # Find the latest stable release for this major version + LATEST=$(echo "$TAGS" \ + | grep -E "^${MAJOR}\.[0-9]+\.[0-9]+$" \ + | sort -t. -k1,1n -k2,2n -k3,3n \ + | tail -1) + + if [ -n "$LATEST" ]; then + echo "v${MAJOR}: latest tag is ${LATEST}" + echo "v${MAJOR}: \"${LATEST}\"" >> "${VERSIONS_FILE}" + else + echo "WARNING: No stable release found for major version ${MAJOR}" >&2 + fi +done + +echo "" +echo "Updated ${VERSIONS_FILE}:" +cat "${VERSIONS_FILE}" diff --git a/packages/apps/opensearch/logos/opensearch.svg b/packages/apps/opensearch/logos/opensearch.svg new file mode 100644 index 00000000..345fdd0a --- /dev/null +++ b/packages/apps/opensearch/logos/opensearch.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/apps/opensearch/templates/.gitkeep b/packages/apps/opensearch/templates/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/packages/apps/opensearch/templates/_versions.tpl b/packages/apps/opensearch/templates/_versions.tpl new file mode 100644 index 00000000..4eae4163 --- /dev/null +++ b/packages/apps/opensearch/templates/_versions.tpl @@ -0,0 +1,13 @@ +{{/* +Version mapping helper +Loads version mapping from files/versions.yaml and returns the full version for a given major version +*/}} +{{- define "opensearch.versionMap" -}} +{{- $versions := .Files.Get "files/versions.yaml" | fromYaml -}} +{{- $version := .Values.version | default "v2" -}} +{{- if hasKey $versions $version -}} +{{- index $versions $version -}} +{{- else -}} +{{- fail (printf "Invalid version '%s'. Available versions: %s" $version (keys $versions | join ", ")) -}} +{{- end -}} +{{- end -}} diff --git a/packages/apps/opensearch/templates/dashboard-resourcemap.yaml b/packages/apps/opensearch/templates/dashboard-resourcemap.yaml new file mode 100644 index 00000000..91dbf8cb --- /dev/null +++ b/packages/apps/opensearch/templates/dashboard-resourcemap.yaml @@ -0,0 +1,42 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ .Release.Name }}-dashboard-resources +rules: +- apiGroups: + - "" + resources: + - services + resourceNames: + - {{ .Release.Name }} + - {{ .Release.Name }}-external + {{- if .Values.dashboards.enabled }} + - {{ .Release.Name }}-dashboards + - {{ .Release.Name }}-dashboards-external + {{- end }} + verbs: ["get", "list", "watch"] +- apiGroups: + - "" + resources: + - secrets + resourceNames: + - {{ .Release.Name }}-credentials + verbs: ["get", "list", "watch"] +- apiGroups: + - cozystack.io + resources: + - workloadmonitors + resourceNames: + - {{ .Release.Name }} + verbs: ["get", "list", "watch"] +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Release.Name }}-dashboard-resources +subjects: +{{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "use" .Release.Namespace) }} +roleRef: + kind: Role + name: {{ .Release.Name }}-dashboard-resources + apiGroup: rbac.authorization.k8s.io diff --git a/packages/apps/opensearch/templates/external-svc.yaml b/packages/apps/opensearch/templates/external-svc.yaml new file mode 100644 index 00000000..f28626ab --- /dev/null +++ b/packages/apps/opensearch/templates/external-svc.yaml @@ -0,0 +1,39 @@ +{{- if .Values.external }} +{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-external + annotations: + external-dns.alpha.kubernetes.io/hostname: {{ .Release.Name }}.{{ .Release.Namespace }}.{{ $clusterDomain }} +spec: + type: LoadBalancer + selector: + opster.io/opensearch-cluster: {{ .Release.Name }} + opster.io/opensearch-nodepool: nodes + ports: + - name: https + port: 9200 + targetPort: 9200 + protocol: TCP +{{- if .Values.dashboards.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-dashboards-external + annotations: + external-dns.alpha.kubernetes.io/hostname: {{ .Release.Name }}-dashboards.{{ .Release.Namespace }}.{{ $clusterDomain }} +spec: + type: LoadBalancer + selector: + opster.io/opensearch-cluster: {{ .Release.Name }} + app.kubernetes.io/component: dashboards + ports: + - name: https + port: 5601 + targetPort: 5601 + protocol: TCP +{{- end }} +{{- end }} diff --git a/packages/apps/opensearch/templates/opensearch.yaml b/packages/apps/opensearch/templates/opensearch.yaml new file mode 100644 index 00000000..836a3d4b --- /dev/null +++ b/packages/apps/opensearch/templates/opensearch.yaml @@ -0,0 +1,105 @@ +{{- $topologyMode := .Values.topologySpreadPolicy | default "soft" }} +{{- $whenUnsatisfiable := "ScheduleAnyway" }} +{{- if eq $topologyMode "hard" }} +{{- $whenUnsatisfiable = "DoNotSchedule" }} +{{- end }} +--- +apiVersion: opensearch.opster.io/v1 +kind: OpenSearchCluster +metadata: + name: {{ .Release.Name }} +spec: + general: + serviceName: {{ .Release.Name }} + version: {{ include "opensearch.versionMap" $ }} + httpPort: 9200 + setVMMaxMapCount: true + drainDataNodes: true + {{- if gt (len .Values.images.opensearch) 0 }} + image: {{ .Values.images.opensearch }} + {{- end }} + bootstrap: + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 6 }} + security: + tls: + transport: + generate: true + perNode: true + http: + generate: true + config: + securityConfigSecret: + name: {{ .Release.Name }}-security-config + adminCredentialsSecret: + name: {{ .Release.Name }}-admin-credentials + {{- if .Values.dashboards.enabled }} + dashboards: + enable: true + version: {{ include "opensearch.versionMap" $ }} + replicas: {{ .Values.dashboards.replicas | default 1 }} + tls: + enable: true + generate: true + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list (.Values.dashboards.resourcesPreset | default "medium") .Values.dashboards.resources $) | nindent 6 }} + {{- end }} + nodePools: + - component: nodes + replicas: {{ .Values.replicas }} + diskSize: {{ .Values.size }} + persistence: + pvc: + accessModes: + - ReadWriteOnce + {{- if .Values.storageClass }} + storageClass: {{ .Values.storageClass }} + {{- else if eq (int .Values.replicas) 1 }} + storageClass: replicated + {{- else }} + storageClass: local + {{- end }} + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 8 }} + {{- if not (or .Values.nodeRoles.master .Values.nodeRoles.data .Values.nodeRoles.ingest .Values.nodeRoles.ml) }} + {{- fail "At least one node role must be enabled (master, data, ingest, or ml)" }} + {{- end }} + roles: + {{- if .Values.nodeRoles.master }} + - cluster_manager + {{- end }} + {{- if .Values.nodeRoles.data }} + - data + {{- end }} + {{- if .Values.nodeRoles.ingest }} + - ingest + {{- end }} + {{- if .Values.nodeRoles.ml }} + - ml + {{- end }} + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: {{ $whenUnsatisfiable }} + labelSelector: + matchLabels: + opster.io/opensearch-cluster: {{ .Release.Name }} + - maxSkew: 1 + topologyKey: topology.kubernetes.io/zone + whenUnsatisfiable: {{ $whenUnsatisfiable }} + labelSelector: + matchLabels: + opster.io/opensearch-cluster: {{ .Release.Name }} +--- +# WorkloadMonitor tracks OpenSearch pods +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: {{ .Release.Name }} + labels: + workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }} +spec: + replicas: {{ .Values.replicas }} + minReplicas: 1 + kind: opensearch + type: opensearch + selector: + opster.io/opensearch-cluster: {{ .Release.Name }} + version: {{ .Chart.Version }} diff --git a/packages/apps/opensearch/templates/security.yaml b/packages/apps/opensearch/templates/security.yaml new file mode 100644 index 00000000..d10d353a --- /dev/null +++ b/packages/apps/opensearch/templates/security.yaml @@ -0,0 +1,120 @@ +{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }} +{{- $existingAdminCreds := lookup "v1" "Secret" .Release.Namespace (printf "%s-admin-credentials" .Release.Name) }} +{{- $existingSecurityConfig := lookup "v1" "Secret" .Release.Namespace (printf "%s-security-config" .Release.Name) }} +{{- $password := randAlphaNum 32 }} +{{- if and $existingAdminCreds (hasKey $existingAdminCreds.data "password") }} +{{- $password = index $existingAdminCreds.data "password" | b64dec }} +{{- end }} +--- +# Admin credentials for the OpenSearch operator (referenced by adminCredentialsSecret) +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Release.Name }}-admin-credentials + labels: + app.kubernetes.io/name: opensearch + app.kubernetes.io/instance: {{ .Release.Name }} +type: Opaque +stringData: + username: admin + password: {{ $password | quote }} +--- +# Security plugin configuration (referenced by securityConfigSecret) +# On upgrades, the existing secret is preserved to avoid bcrypt hash regeneration +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Release.Name }}-security-config + labels: + app.kubernetes.io/name: opensearch + app.kubernetes.io/instance: {{ .Release.Name }} +type: Opaque +{{- if and $existingSecurityConfig (hasKey $existingSecurityConfig.data "internal_users.yml") }} +data: + {{- range $key, $val := $existingSecurityConfig.data }} + {{ $key }}: {{ $val }} + {{- end }} +{{- else }} +stringData: + config.yml: | + --- + _meta: + type: "config" + config_version: 2 + config: + dynamic: + http: + anonymous_auth_enabled: false + authc: + basic_internal_auth_domain: + description: "Authenticate via HTTP Basic against internal users database" + http_enabled: true + transport_enabled: true + order: 0 + http_authenticator: + type: basic + challenge: true + authentication_backend: + type: internal + + internal_users.yml: | + --- + _meta: + type: "internalusers" + config_version: 2 + admin: + hash: {{ htpasswd "admin" $password | trimPrefix "admin:" | quote }} + reserved: true + backend_roles: + - "admin" + description: "Admin user" + + roles.yml: | + --- + _meta: + type: "roles" + config_version: 2 + + roles_mapping.yml: | + --- + _meta: + type: "rolesmapping" + config_version: 2 + all_access: + reserved: false + backend_roles: + - "admin" + + action_groups.yml: | + --- + _meta: + type: "actiongroups" + config_version: 2 + + tenants.yml: | + --- + _meta: + type: "tenants" + config_version: 2 +{{- end }} +--- +# User-facing credentials with connection URI +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Release.Name }}-credentials + labels: + app.kubernetes.io/name: opensearch + app.kubernetes.io/instance: {{ .Release.Name }} +type: Opaque +stringData: + username: admin + password: {{ $password | quote }} + host: {{ .Release.Name }}.{{ .Release.Namespace }}.svc.{{ $clusterDomain }} + port: "9200" + uri: https://admin:{{ $password | urlquery }}@{{ .Release.Name }}.{{ .Release.Namespace }}.svc.{{ $clusterDomain }}:9200 + {{- if .Values.dashboards.enabled }} + dashboards-host: {{ .Release.Name }}-dashboards.{{ .Release.Namespace }}.svc.{{ $clusterDomain }} + dashboards-port: "5601" + dashboards-uri: https://admin:{{ $password | urlquery }}@{{ .Release.Name }}-dashboards.{{ .Release.Namespace }}.svc.{{ $clusterDomain }}:5601 + {{- end }} diff --git a/packages/apps/opensearch/templates/users.yaml b/packages/apps/opensearch/templates/users.yaml new file mode 100644 index 00000000..1d326206 --- /dev/null +++ b/packages/apps/opensearch/templates/users.yaml @@ -0,0 +1,21 @@ +{{- range $username, $user := .Values.users }} +{{- $existingSecret := lookup "v1" "Secret" $.Release.Namespace (printf "%s-user-%s" $.Release.Name $username) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ $.Release.Name }}-user-{{ $username }} + labels: + opensearch.opster.io/credentials: "true" +type: kubernetes.io/basic-auth +stringData: + username: {{ $username | quote }} + {{- if $user.password }} + password: {{ $user.password | quote }} + {{- else if and $existingSecret (hasKey $existingSecret.data "password") }} + password: {{ index $existingSecret.data "password" | b64dec | quote }} + {{- else }} + password: {{ randAlphaNum 16 | quote }} + {{- end }} + roles: {{ $user.roles | default (list "readall") | join "," | quote }} +{{- end }} diff --git a/packages/apps/opensearch/tests/opensearch_test.yaml b/packages/apps/opensearch/tests/opensearch_test.yaml new file mode 100644 index 00000000..2959ec18 --- /dev/null +++ b/packages/apps/opensearch/tests/opensearch_test.yaml @@ -0,0 +1,532 @@ +suite: opensearch CR tests + +templates: + - templates/opensearch.yaml + +tests: + ################### + # Basic rendering # + ################### + + - it: renders OpenSearchCluster and WorkloadMonitor + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - hasDocuments: + count: 2 + - isKind: + of: OpenSearchCluster + documentIndex: 0 + - isKind: + of: WorkloadMonitor + documentIndex: 1 + + - it: sets correct CR name + release: + name: my-opensearch + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: metadata.name + value: my-opensearch + documentIndex: 0 + + ################## + # Version # + ################## + + - it: defaults to version 2.11.1 + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: spec.general.version + value: "2.11.1" + documentIndex: 0 + + - it: sets version 3.0.0 when v3 selected + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + version: v3 + asserts: + - equal: + path: spec.general.version + value: "3.0.0" + documentIndex: 0 + + - it: sets version 1.3.20 when v1 selected + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + version: v1 + asserts: + - equal: + path: spec.general.version + value: "1.3.20" + documentIndex: 0 + + ##################### + # General # + ##################### + + - it: sets drainDataNodes to true + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: spec.general.drainDataNodes + value: true + documentIndex: 0 + + - it: sets httpPort to 9200 + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: spec.general.httpPort + value: 9200 + documentIndex: 0 + + ##################### + # Security # + ##################### + + - it: always includes security section with TLS + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: spec.security.tls.transport.generate + value: true + documentIndex: 0 + - equal: + path: spec.security.tls.transport.perNode + value: true + documentIndex: 0 + - equal: + path: spec.security.tls.http.generate + value: true + documentIndex: 0 + + - it: references security config secret + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: spec.security.config.securityConfigSecret.name + value: test-os-security-config + documentIndex: 0 + + - it: references admin credentials secret + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: spec.security.config.adminCredentialsSecret.name + value: test-os-admin-credentials + documentIndex: 0 + + - it: does not disable security plugin + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - notExists: + path: spec.general.additionalConfig + documentIndex: 0 + + ##################### + # Node Pools # + ##################### + + - it: sets default replica count to 3 + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: spec.nodePools[0].replicas + value: 3 + documentIndex: 0 + + - it: sets replica count from values + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + replicas: 5 + asserts: + - equal: + path: spec.nodePools[0].replicas + value: 5 + documentIndex: 0 + + ##################### + # Node Roles # + ##################### + + - it: enables default node roles + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - contains: + path: spec.nodePools[0].roles + content: cluster_manager + documentIndex: 0 + - contains: + path: spec.nodePools[0].roles + content: data + documentIndex: 0 + - contains: + path: spec.nodePools[0].roles + content: ingest + documentIndex: 0 + + - it: disables master role when configured + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + nodeRoles: + master: false + data: true + ingest: true + ml: false + asserts: + - notContains: + path: spec.nodePools[0].roles + content: cluster_manager + documentIndex: 0 + + - it: fails when all node roles are disabled + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + nodeRoles: + master: false + data: false + ingest: false + ml: false + asserts: + - failedTemplate: + errorMessage: "At least one node role must be enabled (master, data, ingest, or ml)" + + - it: enables ml role when configured + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + nodeRoles: + master: true + data: true + ingest: true + ml: true + asserts: + - contains: + path: spec.nodePools[0].roles + content: ml + documentIndex: 0 + + ########################### + # Topology Spread Policy # + ########################### + + - it: uses soft topology spread by default (ScheduleAnyway) + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: spec.nodePools[0].topologySpreadConstraints[0].whenUnsatisfiable + value: ScheduleAnyway + documentIndex: 0 + - equal: + path: spec.nodePools[0].topologySpreadConstraints[1].whenUnsatisfiable + value: ScheduleAnyway + documentIndex: 0 + + - it: uses hard topology spread when configured (DoNotSchedule) + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + topologySpreadPolicy: hard + asserts: + - equal: + path: spec.nodePools[0].topologySpreadConstraints[0].whenUnsatisfiable + value: DoNotSchedule + documentIndex: 0 + - equal: + path: spec.nodePools[0].topologySpreadConstraints[1].whenUnsatisfiable + value: DoNotSchedule + documentIndex: 0 + + - it: sets correct topology keys + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: spec.nodePools[0].topologySpreadConstraints[0].topologyKey + value: kubernetes.io/hostname + documentIndex: 0 + - equal: + path: spec.nodePools[0].topologySpreadConstraints[1].topologyKey + value: topology.kubernetes.io/zone + documentIndex: 0 + + ##################### + # Storage # + ##################### + + - it: sets accessModes to ReadWriteOnce + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - contains: + path: spec.nodePools[0].persistence.pvc.accessModes + content: ReadWriteOnce + documentIndex: 0 + + - it: sets storage size from values + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + size: 50Gi + asserts: + - equal: + path: spec.nodePools[0].diskSize + value: 50Gi + documentIndex: 0 + + - it: uses local storageClass when replicas > 1 and no storageClass + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + storageClass: "" + replicas: 3 + asserts: + - equal: + path: spec.nodePools[0].persistence.pvc.storageClass + value: local + documentIndex: 0 + + - it: uses replicated storageClass when single replica and no storageClass + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + storageClass: "" + replicas: 1 + asserts: + - equal: + path: spec.nodePools[0].persistence.pvc.storageClass + value: replicated + documentIndex: 0 + + - it: uses custom storageClass when provided + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + storageClass: fast-ssd + asserts: + - equal: + path: spec.nodePools[0].persistence.pvc.storageClass + value: fast-ssd + documentIndex: 0 + + ##################### + # Dashboards # + ##################### + + - it: does not render dashboards when disabled + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + dashboards: + enabled: false + replicas: 1 + resourcesPreset: "medium" + resources: {} + asserts: + - notExists: + path: spec.dashboards + documentIndex: 0 + + - it: renders dashboards when enabled + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + dashboards: + enabled: true + replicas: 1 + resourcesPreset: "medium" + resources: {} + asserts: + - equal: + path: spec.dashboards.enable + value: true + documentIndex: 0 + - equal: + path: spec.dashboards.replicas + value: 1 + documentIndex: 0 + - equal: + path: spec.dashboards.tls.enable + value: true + documentIndex: 0 + - equal: + path: spec.dashboards.tls.generate + value: true + documentIndex: 0 + + ########################### + # WorkloadMonitor # + ########################### + + - it: creates WorkloadMonitor with correct metadata + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: metadata.name + value: test-os + documentIndex: 1 + - equal: + path: spec.kind + value: opensearch + documentIndex: 1 + - equal: + path: spec.type + value: opensearch + documentIndex: 1 + + - it: sets replicas in WorkloadMonitor + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + replicas: 5 + asserts: + - equal: + path: spec.replicas + value: 5 + documentIndex: 1 + + - it: sets minReplicas to 1 + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: spec.minReplicas + value: 1 + documentIndex: 1 + + - it: sets correct selector labels + release: + name: mydb + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: spec.selector["opster.io/opensearch-cluster"] + value: mydb + documentIndex: 1 diff --git a/packages/apps/opensearch/tests/security_test.yaml b/packages/apps/opensearch/tests/security_test.yaml new file mode 100644 index 00000000..cd8740d9 --- /dev/null +++ b/packages/apps/opensearch/tests/security_test.yaml @@ -0,0 +1,207 @@ +suite: security secrets tests + +templates: + - templates/security.yaml + +tests: + ################### + # Basic rendering # + ################### + + - it: renders three secrets (admin-credentials, security-config, credentials) + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - hasDocuments: + count: 3 + + ########################### + # Admin credentials # + ########################### + + - it: sets admin-credentials secret name + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: metadata.name + value: test-os-admin-credentials + documentIndex: 0 + + - it: sets admin username + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: stringData.username + value: admin + documentIndex: 0 + + - it: generates a 32-char alphanumeric password + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - matchRegex: + path: stringData.password + pattern: "^[a-zA-Z0-9]{32}$" + documentIndex: 0 + + ########################### + # Security config # + ########################### + + - it: sets security-config secret name + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: metadata.name + value: test-os-security-config + documentIndex: 1 + + - it: includes config.yml with basic auth + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - exists: + path: stringData["config.yml"] + documentIndex: 1 + + - it: includes internal_users.yml with bcrypt hash + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - matchRegex: + path: stringData["internal_users.yml"] + pattern: "hash:.*\\$2a\\$" + documentIndex: 1 + + - it: includes roles_mapping.yml + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - exists: + path: stringData["roles_mapping.yml"] + documentIndex: 1 + + ########################### + # User-facing credentials # + ########################### + + - it: sets credentials secret name + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: metadata.name + value: test-os-credentials + documentIndex: 2 + + - it: sets correct host and port + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: stringData.host + value: test-os.tenant-test.svc.cozy.local + documentIndex: 2 + - equal: + path: stringData.port + value: "9200" + documentIndex: 2 + + - it: sets https URI with credentials + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + asserts: + - matchRegex: + path: stringData.uri + pattern: "^https://admin:[a-zA-Z0-9]{32}@test-os\\.tenant-test\\.svc\\.cozy\\.local:9200$" + documentIndex: 2 + + - it: does not include dashboards fields when dashboards disabled + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + dashboards: + enabled: false + replicas: 1 + resourcesPreset: "medium" + resources: {} + asserts: + - notExists: + path: stringData.dashboards-host + documentIndex: 2 + + - it: includes dashboards fields when dashboards enabled + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + dashboards: + enabled: true + replicas: 1 + resourcesPreset: "medium" + resources: {} + asserts: + - equal: + path: stringData.dashboards-host + value: test-os-dashboards.tenant-test.svc.cozy.local + documentIndex: 2 + - equal: + path: stringData.dashboards-port + value: "5601" + documentIndex: 2 + - matchRegex: + path: stringData.dashboards-uri + pattern: "^https://admin:[a-zA-Z0-9]{32}@test-os-dashboards\\.tenant-test\\.svc\\.cozy\\.local:5601$" + documentIndex: 2 diff --git a/packages/apps/opensearch/tests/users_test.yaml b/packages/apps/opensearch/tests/users_test.yaml new file mode 100644 index 00000000..f6b4990e --- /dev/null +++ b/packages/apps/opensearch/tests/users_test.yaml @@ -0,0 +1,176 @@ +suite: users secrets tests + +templates: + - templates/users.yaml + +tests: + ################### + # Basic rendering # + ################### + + - it: does not render secrets when no users defined + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + users: {} + asserts: + - hasDocuments: + count: 0 + + - it: renders one secret per user + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + users: + user1: + roles: + - readall + user2: + roles: + - all_access + asserts: + - hasDocuments: + count: 2 + + ##################### + # Secret metadata # + ##################### + + - it: sets correct secret name + release: + name: my-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + users: + myuser: + roles: + - readall + asserts: + - equal: + path: metadata.name + value: my-os-user-myuser + + - it: sets opensearch credentials label + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + users: + myuser: + roles: + - readall + asserts: + - equal: + path: metadata.labels["opensearch.opster.io/credentials"] + value: "true" + + - it: uses basic-auth secret type + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + users: + myuser: + roles: + - readall + asserts: + - equal: + path: type + value: kubernetes.io/basic-auth + + ##################### + # Secret data # + ##################### + + - it: sets username in secret + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + users: + testuser: + roles: + - readall + asserts: + - equal: + path: stringData.username + value: testuser + + - it: uses provided password + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + users: + myuser: + password: mysecretpassword + roles: + - readall + asserts: + - equal: + path: stringData.password + value: mysecretpassword + + - it: generates password when not provided + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + users: + myuser: + roles: + - readall + asserts: + - matchRegex: + path: stringData.password + pattern: "^[a-zA-Z0-9]{16}$" + + - it: sets roles as comma-separated string + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + users: + myuser: + roles: + - readall + - reporting_user + - monitoring_user + asserts: + - equal: + path: stringData.roles + value: "readall,reporting_user,monitoring_user" + + - it: defaults to readall role when no roles specified + release: + name: test-os + namespace: tenant-test + set: + _cluster: + cluster-domain: cozy.local + users: + myuser: {} + asserts: + - equal: + path: stringData.roles + value: "readall" diff --git a/packages/apps/opensearch/values.schema.json b/packages/apps/opensearch/values.schema.json new file mode 100644 index 00000000..04b530ba --- /dev/null +++ b/packages/apps/opensearch/values.schema.json @@ -0,0 +1,239 @@ +{ + "title": "Chart Values", + "type": "object", + "properties": { + "replicas": { + "description": "Number of OpenSearch nodes in the cluster.", + "type": "integer", + "default": 3 + }, + "resources": { + "description": "Explicit CPU and memory configuration for each OpenSearch node. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "CPU available to each node.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Memory (RAM) available to each node.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted. OpenSearch requires minimum 2Gi memory.", + "type": "string", + "default": "large", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + }, + "size": { + "description": "Persistent Volume Claim size available for application data.", + "default": "10Gi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "storageClass": { + "description": "StorageClass used to store the data.", + "type": "string", + "default": "" + }, + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + }, + "topologySpreadPolicy": { + "description": "How strictly to enforce pod distribution across nodes and zones.", + "type": "string", + "default": "soft", + "enum": [ + "soft", + "hard" + ] + }, + "version": { + "description": "OpenSearch major version to deploy.", + "type": "string", + "default": "v2", + "enum": [ + "v3", + "v2", + "v1" + ] + }, + "images": { + "description": "Container images used by the operator.", + "type": "object", + "default": {}, + "required": [ + "opensearch" + ], + "properties": { + "opensearch": { + "description": "OpenSearch image.", + "type": "string", + "default": "" + } + } + }, + "nodeRoles": { + "description": "Node roles configuration.", + "type": "object", + "default": {}, + "required": [ + "data", + "ingest", + "master", + "ml" + ], + "properties": { + "data": { + "description": "Enable data role.", + "type": "boolean", + "default": true + }, + "ingest": { + "description": "Enable ingest role.", + "type": "boolean", + "default": true + }, + "master": { + "description": "Enable cluster_manager role.", + "type": "boolean", + "default": true + }, + "ml": { + "description": "Enable machine learning role.", + "type": "boolean", + "default": false + } + } + }, + "users": { + "description": "Custom OpenSearch users configuration map.", + "type": "object", + "default": {}, + "additionalProperties": { + "type": "object", + "properties": { + "password": { + "description": "Password for the user (auto-generated if omitted).", + "type": "string" + }, + "roles": { + "description": "List of OpenSearch roles.", + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "dashboards": { + "description": "OpenSearch Dashboards configuration.", + "type": "object", + "default": {}, + "required": [ + "enabled", + "replicas", + "resourcesPreset" + ], + "properties": { + "enabled": { + "description": "Enable OpenSearch Dashboards deployment.", + "type": "boolean", + "default": false + }, + "replicas": { + "description": "Number of Dashboards replicas.", + "type": "integer", + "default": 1 + }, + "resources": { + "description": "Explicit CPU and memory configuration for Dashboards.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "CPU available to each node.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Memory (RAM) available to each node.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "resourcesPreset": { + "description": "Default sizing preset for Dashboards.", + "type": "string", + "default": "medium", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + } + } + } + } +} diff --git a/packages/apps/opensearch/values.yaml b/packages/apps/opensearch/values.yaml new file mode 100644 index 00000000..8de805e3 --- /dev/null +++ b/packages/apps/opensearch/values.yaml @@ -0,0 +1,111 @@ +## +## @section Common parameters +## + +## @typedef {struct} Resources - Explicit CPU and memory configuration for each OpenSearch node. +## @field {quantity} [cpu] - CPU available to each node. +## @field {quantity} [memory] - Memory (RAM) available to each node. + +## @enum {string} ResourcesPreset - Default sizing preset. +## @value nano +## @value micro +## @value small +## @value medium +## @value large +## @value xlarge +## @value 2xlarge + +## @param {int} replicas - Number of OpenSearch nodes in the cluster. +replicas: 3 + +## @param {Resources} [resources] - Explicit CPU and memory configuration for each OpenSearch node. When omitted, the preset defined in `resourcesPreset` is applied. +resources: {} + +## @param {ResourcesPreset} resourcesPreset="large" - Default sizing preset used when `resources` is omitted. OpenSearch requires minimum 2Gi memory. +resourcesPreset: "large" + +## @param {quantity} size - Persistent Volume Claim size available for application data. +size: 10Gi + +## @param {string} storageClass - StorageClass used to store the data. +storageClass: "" + +## @param {bool} external - Enable external access from outside the cluster. +external: false + +## @enum {string} TopologySpreadPolicy - Pod distribution policy across nodes/zones. +## @value soft - Best-effort distribution (ScheduleAnyway) - pods may be scheduled on same node if needed +## @value hard - Strict distribution (DoNotSchedule) - pods will not schedule if spread cannot be achieved + +## @param {TopologySpreadPolicy} topologySpreadPolicy="soft" - How strictly to enforce pod distribution across nodes and zones. +topologySpreadPolicy: "soft" + +## +## @enum {string} Version +## @value v3 +## @value v2 +## @value v1 + +## @param {Version} version - OpenSearch major version to deploy. +version: v2 + +## +## @section Image configuration +## + +## @typedef {struct} Images - Container image configuration. +## @field {string} opensearch - OpenSearch image. + +## @param {Images} images - Container images used by the operator. +images: + opensearch: "" + +## +## @section Node roles configuration +## + +## @typedef {struct} NodeRoles - OpenSearch node roles. +## @field {bool} master - Enable cluster_manager role. +## @field {bool} data - Enable data role. +## @field {bool} ingest - Enable ingest role. +## @field {bool} ml - Enable machine learning role. + +## @param {NodeRoles} nodeRoles - Node roles configuration. +nodeRoles: + master: true + data: true + ingest: true + ml: false + +## +## @section Users configuration +## + +## @typedef {struct} User - User configuration. +## @field {string} [password] - Password for the user (auto-generated if omitted). +## @field {[]string} roles - List of OpenSearch roles. + +## @param {map[string]User} users - Custom OpenSearch users configuration map. +users: {} +## Example: +## users: +## myuser: +## roles: +## - all_access + +## +## @section OpenSearch Dashboards configuration +## + +## @typedef {struct} Dashboards - OpenSearch Dashboards deployment configuration. +## @field {bool} enabled - Enable OpenSearch Dashboards deployment. +## @field {int} replicas - Number of Dashboards replicas. +## @field {Resources} [resources] - Explicit CPU and memory configuration for Dashboards. +## @field {ResourcesPreset} resourcesPreset - Default sizing preset for Dashboards. + +## @param {Dashboards} dashboards - OpenSearch Dashboards configuration. +dashboards: + enabled: false + replicas: 1 + resources: {} + resourcesPreset: "medium" diff --git a/packages/apps/postgres/.helmignore b/packages/apps/postgres/.helmignore index 1ea0ae84..3de7d4a5 100644 --- a/packages/apps/postgres/.helmignore +++ b/packages/apps/postgres/.helmignore @@ -1,3 +1,4 @@ .helmignore /logos /Makefile +/hack diff --git a/packages/apps/postgres/Chart.yaml b/packages/apps/postgres/Chart.yaml index 4ae93148..9c1cd00b 100644 --- a/packages/apps/postgres/Chart.yaml +++ b/packages/apps/postgres/Chart.yaml @@ -2,24 +2,6 @@ apiVersion: v2 name: postgres description: Managed PostgreSQL service icon: /logos/postgres.svg - -# 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: 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.17.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. +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process appVersion: "16.2" diff --git a/packages/apps/postgres/Makefile b/packages/apps/postgres/Makefile index e4057cb4..dff0b9c6 100644 --- a/packages/apps/postgres/Makefile +++ b/packages/apps/postgres/Makefile @@ -1,5 +1,9 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: - readme-generator -v values.yaml -s values.schema.json -r README.md - yq -i -o json --indent 4 '.properties.resourcesPreset.enum = ["none", "nano", "micro", "small", "medium", "large", "xlarge", "2xlarge"]' values.schema.json + cozyvalues-gen -m 'postgresql' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/postgresql/types.go + ../../../hack/update-crd.sh + +update: + hack/update-versions.sh + make generate diff --git a/packages/apps/postgres/README.md b/packages/apps/postgres/README.md index de808210..4cda7284 100644 --- a/packages/apps/postgres/README.md +++ b/packages/apps/postgres/README.md @@ -66,44 +66,80 @@ See: ### Common parameters -| Name | Description | Value | -| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------- | -| `external` | Enable external access from outside the cluster | `false` | -| `size` | Persistent Volume size | `10Gi` | -| `replicas` | Number of Postgres replicas | `2` | -| `storageClass` | StorageClass used to store the data | `""` | -| `postgresql.parameters.max_connections` | Determines the maximum number of concurrent connections to the database server. The default is typically 100 connections | `100` | -| `quorum.minSyncReplicas` | Minimum number of synchronous replicas that must acknowledge a transaction before it is considered committed. | `0` | -| `quorum.maxSyncReplicas` | Maximum number of synchronous replicas that can acknowledge a transaction (must be lower than the number of instances). | `0` | +| Name | Description | Type | Value | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | ---------- | ------- | +| `replicas` | Number of Postgres replicas. | `int` | `2` | +| `resources` | Explicit CPU and memory configuration for each PostgreSQL replica. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `resources.cpu` | CPU available to each replica. | `quantity` | `""` | +| `resources.memory` | Memory (RAM) available to each replica. | `quantity` | `""` | +| `resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `micro` | +| `size` | Persistent Volume Claim size available for application data. | `quantity` | `10Gi` | +| `storageClass` | StorageClass used to store the data. | `string` | `""` | +| `external` | Enable external access from outside the cluster. | `bool` | `false` | +| `version` | PostgreSQL major version to deploy | `string` | `v18` | -### Configuration parameters -| Name | Description | Value | -| ----------- | ----------------------- | ----- | -| `users` | Users configuration | `{}` | -| `databases` | Databases configuration | `{}` | +### Application-specific parameters + +| Name | Description | Type | Value | +| --------------------------------------- | ---------------------------------------------------------------- | -------- | ----- | +| `postgresql` | PostgreSQL server configuration. | `object` | `{}` | +| `postgresql.parameters` | PostgreSQL server parameters. | `object` | `{}` | +| `postgresql.parameters.max_connections` | Maximum number of concurrent connections to the database server. | `int` | `100` | + + +### Quorum-based synchronous replication + +| Name | Description | Type | Value | +| ------------------------ | ---------------------------------------------------------------------------------- | -------- | ----- | +| `quorum` | Quorum configuration for synchronous replication. | `object` | `{}` | +| `quorum.minSyncReplicas` | Minimum number of synchronous replicas required for commit. | `int` | `0` | +| `quorum.maxSyncReplicas` | Maximum number of synchronous replicas allowed (must be less than total replicas). | `int` | `0` | + + +### Users configuration + +| Name | Description | Type | Value | +| ------------------------- | -------------------------------------------- | ------------------- | ------- | +| `users` | Users configuration map. | `map[string]object` | `{}` | +| `users[name].password` | Password for the user. | `string` | `""` | +| `users[name].replication` | Whether the user has replication privileges. | `bool` | `false` | + + +### Databases configuration + +| Name | Description | Type | Value | +| -------------------------------- | ---------------------------------------- | ------------------- | ----- | +| `databases` | Databases configuration map. | `map[string]object` | `{}` | +| `databases[name].roles` | Roles assigned to users. | `object` | `{}` | +| `databases[name].roles.admin` | List of users with admin privileges. | `[]string` | `[]` | +| `databases[name].roles.readonly` | List of users with read-only privileges. | `[]string` | `[]` | +| `databases[name].extensions` | List of enabled PostgreSQL extensions. | `[]string` | `[]` | + ### Backup parameters -| Name | Description | Value | -| ------------------------ | ---------------------------------------------------------- | ----------------------------------- | -| `backup.enabled` | Enable regular backups | `false` | -| `backup.schedule` | Cron schedule for automated backups | `0 2 * * * *` | -| `backup.retentionPolicy` | Retention policy | `30d` | -| `backup.destinationPath` | Path to store the backup (i.e. s3://bucket/path/to/folder) | `s3://bucket/path/to/folder/` | -| `backup.endpointURL` | S3 Endpoint used to upload data to the cloud | `http://minio-gateway-service:9000` | -| `backup.s3AccessKey` | Access key for S3, used for authentication | `oobaiRus9pah8PhohL1ThaeTa4UVa7gu` | -| `backup.s3SecretKey` | Secret key for S3, used for authentication | `ju3eum4dekeich9ahM1te8waeGai0oog` | +| Name | Description | Type | Value | +| ------------------------ | ------------------------------------------------------ | -------- | ----------------------------------- | +| `backup` | Backup configuration. | `object` | `{}` | +| `backup.enabled` | Enable regular backups. | `bool` | `false` | +| `backup.schedule` | Cron schedule for automated backups. | `string` | `0 2 * * * *` | +| `backup.retentionPolicy` | Retention policy (e.g. "30d"). | `string` | `30d` | +| `backup.destinationPath` | Destination path for backups (e.g. s3://bucket/path/). | `string` | `s3://bucket/path/to/folder/` | +| `backup.endpointURL` | S3 endpoint URL for uploads. | `string` | `http://minio-gateway-service:9000` | +| `backup.s3AccessKey` | Access key for S3 authentication. | `string` | `` | +| `backup.s3SecretKey` | Secret key for S3 authentication. | `string` | `` | -### Bootstrap parameters -| Name | Description | Value | -| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- | ------- | -| `bootstrap.enabled` | Restore database cluster from a backup | `false` | -| `bootstrap.recoveryTime` | Timestamp (PITR) up to which recovery will proceed, expressed in RFC 3339 format. If left empty, will restore latest | `""` | -| `bootstrap.oldName` | Name of database cluster before deleting | `""` | -| `resources` | Explicit CPU and memory configuration for each PostgreSQL replica. When left empty, the preset defined in `resourcesPreset` is applied. | `{}` | -| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge. | `micro` | +### Bootstrap (recovery) parameters + +| Name | Description | Type | Value | +| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- | +| `bootstrap` | Bootstrap configuration. | `object` | `{}` | +| `bootstrap.enabled` | Whether to restore from a backup. | `bool` | `false` | +| `bootstrap.recoveryTime` | Timestamp (RFC3339) for point-in-time recovery; empty means latest. | `string` | `""` | +| `bootstrap.oldName` | Previous cluster name before deletion. | `string` | `""` | +| `bootstrap.serverName` | Barman server name (S3 path prefix) used by the original cluster when writing backups. Set this only when the original cluster had an explicit barmanObjectStore.serverName that differed from its Kubernetes resource name. | `string` | `""` | ## Parameter examples and reference diff --git a/packages/apps/postgres/files/versions.yaml b/packages/apps/postgres/files/versions.yaml new file mode 100644 index 00000000..e4fe13ea --- /dev/null +++ b/packages/apps/postgres/files/versions.yaml @@ -0,0 +1,6 @@ +"v18": "v18.1" +"v17": "v17.7" +"v16": "v16.11" +"v15": "v15.15" +"v14": "v14.20" +"v13": "v13.22" diff --git a/packages/apps/postgres/hack/update-versions.sh b/packages/apps/postgres/hack/update-versions.sh new file mode 100755 index 00000000..c92b3895 --- /dev/null +++ b/packages/apps/postgres/hack/update-versions.sh @@ -0,0 +1,138 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +POSTGRES_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +VALUES_FILE="${POSTGRES_DIR}/values.yaml" +VERSIONS_FILE="${POSTGRES_DIR}/files/versions.yaml" + +# Get supported major versions from GitHub README +echo "Fetching supported major versions from GitHub..." +SUPPORTED_MAJOR_VERSIONS=$(curl -sSL 'https://raw.githubusercontent.com/cloudnative-pg/postgres-containers/refs/heads/main/README.md' | sed -n '/# CNPG PostgreSQL Container Images/,/#/p' | awk -F' +| +' '$4 ~ /[0-9]+\-[0-9]+\-[0-9]+/ && $6 ~ /[0-9]+\-[0-9]+\-[0-9]+/ {print $2}' | sort -u | xargs) + +if [ -z "$SUPPORTED_MAJOR_VERSIONS" ]; then + echo "Error: Could not fetch supported major versions" >&2 + exit 1 +fi + +echo "Supported major versions: $SUPPORTED_MAJOR_VERSIONS" + +# Check if skopeo is installed +if ! command -v skopeo &> /dev/null; then + echo "Error: skopeo is not installed. Please install skopeo and try again." >&2 + exit 1 +fi + +# Check if jq is installed +if ! command -v jq &> /dev/null; then + echo "Error: jq is not installed. Please install jq and try again." >&2 + exit 1 +fi + +# Get available image tags +echo "Fetching available image tags from registry..." +AVAILABLE_TAGS=$(skopeo list-tags docker://ghcr.io/cloudnative-pg/postgresql | jq -r '.Tags[] | select(test("^[0-9]+\\.[0-9]+$"))' | sort -V) + +if [ -z "$AVAILABLE_TAGS" ]; then + echo "Error: Could not fetch available image tags" >&2 + exit 1 +fi + +# Build versions map: major version -> latest minor version +declare -A VERSION_MAP +MAJOR_VERSIONS=() + +for major_version in $SUPPORTED_MAJOR_VERSIONS; do + # Extract major version number (e.g., "18" from "18.1") + major_num=$(echo "$major_version" | cut -d. -f1) + + # Find all tags that match this major version + matching_tags=$(echo "$AVAILABLE_TAGS" | grep "^${major_num}\\.") + + if [ -n "$matching_tags" ]; then + # Get the latest minor version for this major version + latest_tag=$(echo "$matching_tags" | tail -n1) + VERSION_MAP["v${major_num}"]="v${latest_tag}" + MAJOR_VERSIONS+=("v${major_num}") + echo "Found version: v${major_num} -> v${latest_tag}" + fi +done + +if [ ${#MAJOR_VERSIONS[@]} -eq 0 ]; then + echo "Error: No matching versions found" >&2 + exit 1 +fi + +# Sort major versions in descending order (newest first) +IFS=$'\n' MAJOR_VERSIONS=($(printf '%s\n' "${MAJOR_VERSIONS[@]}" | sort -V -r)) +unset IFS + +echo "Major versions to add: ${MAJOR_VERSIONS[*]}" + +# Create/update versions.yaml file +echo "Updating $VERSIONS_FILE..." +{ + for major_ver in "${MAJOR_VERSIONS[@]}"; do + echo "\"${major_ver}\": \"${VERSION_MAP[$major_ver]}\"" + done +} > "$VERSIONS_FILE" + +echo "Successfully updated $VERSIONS_FILE" + +# Update values.yaml - enum with major versions only +TEMP_FILE=$(mktemp) +trap "rm -f $TEMP_FILE" EXIT + +# Build new version section +NEW_VERSION_SECTION="## @enum {string} Version" +for major_ver in "${MAJOR_VERSIONS[@]}"; do + NEW_VERSION_SECTION="${NEW_VERSION_SECTION} +## @value $major_ver" +done +NEW_VERSION_SECTION="${NEW_VERSION_SECTION} + +## @param {Version} version - PostgreSQL major version to deploy +version: ${MAJOR_VERSIONS[0]}" + +# Check if version section already exists +if grep -q "^## @enum {string} Version" "$VALUES_FILE"; then + # Version section exists, update it using awk + echo "Updating existing version section in $VALUES_FILE..." + + # Use awk to replace the section from "## @enum {string} Version" to "version: " (inclusive) + # Delete the old section and insert the new one + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @enum {string} Version/ { + in_section = 1 + print new_section + next + } + in_section && /^version: / { + in_section = 0 + next + } + in_section { + next + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +else + # Version section doesn't exist, insert it before Application-specific parameters section + echo "Inserting new version section in $VALUES_FILE..." + + # Use awk to insert before "## @section Application-specific parameters" + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @section Application-specific parameters/ { + print new_section + print "" + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +fi + +echo "Successfully updated $VALUES_FILE with major versions: ${MAJOR_VERSIONS[*]}" diff --git a/packages/apps/postgres/templates/_versions.tpl b/packages/apps/postgres/templates/_versions.tpl new file mode 100644 index 00000000..ca0ff2a2 --- /dev/null +++ b/packages/apps/postgres/templates/_versions.tpl @@ -0,0 +1,8 @@ +{{- define "postgres.versionMap" }} +{{- $versionMap := .Files.Get "files/versions.yaml" | fromYaml }} +{{- if not (hasKey $versionMap .Values.version) }} + {{- printf `PostgreSQL version %s is not supported, allowed versions are %s` $.Values.version (keys $versionMap) | fail }} +{{- end }} +{{- index $versionMap .Values.version }} +{{- end }} + diff --git a/packages/apps/postgres/templates/dashboard-resourcemap.yaml b/packages/apps/postgres/templates/dashboard-resourcemap.yaml index e248e0f9..d979289f 100644 --- a/packages/apps/postgres/templates/dashboard-resourcemap.yaml +++ b/packages/apps/postgres/templates/dashboard-resourcemap.yaml @@ -11,6 +11,7 @@ rules: - {{ .Release.Name }}-r - {{ .Release.Name }}-ro - {{ .Release.Name }}-rw + - {{ .Release.Name }}-external-write verbs: ["get", "list", "watch"] - apiGroups: - "" diff --git a/packages/apps/postgres/templates/db.yaml b/packages/apps/postgres/templates/db.yaml index 516077bd..2cdaec1d 100644 --- a/packages/apps/postgres/templates/db.yaml +++ b/packages/apps/postgres/templates/db.yaml @@ -32,6 +32,9 @@ spec: - name: {{ .Values.bootstrap.oldName }} barmanObjectStore: destinationPath: {{ .Values.backup.destinationPath }} + {{- if .Values.bootstrap.serverName }} + serverName: {{ .Values.bootstrap.serverName }} + {{- end }} endpointURL: {{ .Values.backup.endpointURL }} s3Credentials: accessKeyId: @@ -44,10 +47,10 @@ spec: resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 4 }} + imageName: ghcr.io/cloudnative-pg/postgresql:{{ include "postgres.versionMap" $ | trimPrefix "v" }} enableSuperuserAccess: true - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- if $configMap }} - {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }} + {{- if .Values._cluster.scheduling }} + {{- $rawConstraints := get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }} {{- if $rawConstraints }} {{- $rawConstraints | fromYaml | toYaml | nindent 2 }} labelSelector: @@ -78,12 +81,14 @@ spec: labels: policy.cozystack.io/allow-to-apiserver: "true" app.kubernetes.io/name: postgres.apps.cozystack.io - app.kubernets.io/instance: {{ $.Release.Name }} + app.kubernetes.io/instance: {{ $.Release.Name }} --- apiVersion: cozystack.io/v1alpha1 kind: WorkloadMonitor metadata: name: {{ $.Release.Name }} + labels: + workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }} spec: replicas: {{ .Values.replicas }} minReplicas: 1 @@ -91,5 +96,5 @@ spec: type: postgres selector: app.kubernetes.io/name: postgres.apps.cozystack.io - app.kubernets.io/instance: {{ $.Release.Name }} + app.kubernetes.io/instance: {{ $.Release.Name }} version: {{ $.Chart.Version }} diff --git a/packages/apps/postgres/templates/external-svc.yaml b/packages/apps/postgres/templates/external-svc.yaml index 2f4e8b91..a243dccd 100644 --- a/packages/apps/postgres/templates/external-svc.yaml +++ b/packages/apps/postgres/templates/external-svc.yaml @@ -7,7 +7,9 @@ spec: type: {{ ternary "LoadBalancer" "ClusterIP" .Values.external }} {{- if .Values.external }} externalTrafficPolicy: Local + {{- if (include "cozy-lib.network.disableLoadBalancerNodePorts" $ | fromYaml) }} allocateLoadBalancerNodePorts: false + {{- end }} {{- end }} ports: - name: postgres diff --git a/packages/apps/postgres/templates/init-job.yaml b/packages/apps/postgres/templates/init-job.yaml index f6c42dbd..323bfcaf 100644 --- a/packages/apps/postgres/templates/init-job.yaml +++ b/packages/apps/postgres/templates/init-job.yaml @@ -16,7 +16,7 @@ spec: restartPolicy: Never containers: - name: postgres - image: ghcr.io/cloudnative-pg/postgresql:15.3 + image: ghcr.io/cloudnative-pg/postgresql:{{ include "postgres.versionMap" $ | trimPrefix "v" }} command: - bash - /scripts/init.sh diff --git a/packages/apps/postgres/templates/init-script.yaml b/packages/apps/postgres/templates/init-script.yaml index 80f7c4c7..500d54d4 100644 --- a/packages/apps/postgres/templates/init-script.yaml +++ b/packages/apps/postgres/templates/init-script.yaml @@ -66,6 +66,38 @@ stringData: EOT done + echo "== delete databases" + MANAGED_DBS=$(psql -v ON_ERROR_STOP=1 -t -A -c "SELECT datname FROM pg_database d JOIN pg_shdescription s ON d.oid = s.objoid WHERE s.description = 'database managed by helm'") + DEFINED_DBS="{{ join " " (keys .Values.databases) }}" + DELETE_DBS=$(for db in $MANAGED_DBS; do case " $DEFINED_DBS " in *" $db "*) :;; *) echo $db;; esac; done) + + echo "databases to delete: $DELETE_DBS" + for db in $DELETE_DBS; do + psql -v ON_ERROR_STOP=1 --echo-all -c "DROP DATABASE IF EXISTS \"$db\" WITH (FORCE);" + done + + echo "== delete orphaned managed roles" + MANAGED_ROLES=$(psql -v ON_ERROR_STOP=1 -t -A -c "SELECT rolname FROM pg_roles r JOIN pg_shdescription s ON r.oid = s.objoid WHERE s.description = 'role managed by helm'") + DEFINED_ROLES="{{ range $database, $d := .Values.databases }}{{ $database }}_admin {{ $database }}_readonly {{ end }}" + DELETE_ROLES=$(for role in $MANAGED_ROLES; do case " $DEFINED_ROLES " in *" $role "*) :;; *) echo $role;; esac; done) + + echo "roles to delete: $DELETE_ROLES" + for role in $DELETE_ROLES; do + psql -v ON_ERROR_STOP=1 --echo-all <" + s3SecretKey: "" -## @section Bootstrap parameters - -## @param bootstrap.enabled Restore database cluster from a backup -## @param bootstrap.recoveryTime Timestamp (PITR) up to which recovery will proceed, expressed in RFC 3339 format. If left empty, will restore latest -## @param bootstrap.oldName Name of database cluster before deleting ## +## @section Bootstrap (recovery) parameters +## + +## @typedef {struct} Bootstrap - Bootstrap configuration for restoring a database cluster from a backup. +## @field {bool} enabled - Whether to restore from a backup. +## @field {string} [recoveryTime] - Timestamp (RFC3339) for point-in-time recovery; empty means latest. +## @field {string} oldName - Previous cluster name before deletion. +## @field {string} [serverName] - Barman server name (S3 path prefix) used by the original cluster when writing backups. Set this only when the original cluster had an explicit barmanObjectStore.serverName that differed from its Kubernetes resource name. + +## @param {Bootstrap} bootstrap - Bootstrap configuration. bootstrap: enabled: false # example: 2020-11-26 15:22:00.00000+00 recoveryTime: "" oldName: "" - -## @param resources Explicit CPU and memory configuration for each PostgreSQL replica. When left empty, the preset defined in `resourcesPreset` is applied. -resources: {} - # resources: - # cpu: 4000m - # memory: 4Gi - -## @param resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge. -resourcesPreset: "micro" + serverName: "" diff --git a/packages/extra/monitoring/.helmignore b/packages/apps/qdrant/.helmignore similarity index 82% rename from packages/extra/monitoring/.helmignore rename to packages/apps/qdrant/.helmignore index 1ea0ae84..3de7d4a5 100644 --- a/packages/extra/monitoring/.helmignore +++ b/packages/apps/qdrant/.helmignore @@ -1,3 +1,4 @@ .helmignore /logos /Makefile +/hack diff --git a/packages/apps/qdrant/Chart.yaml b/packages/apps/qdrant/Chart.yaml new file mode 100644 index 00000000..5c2699ac --- /dev/null +++ b/packages/apps/qdrant/Chart.yaml @@ -0,0 +1,11 @@ +apiVersion: v2 +name: qdrant +description: Managed Qdrant vector database service +icon: /logos/qdrant.svg +type: application +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process +appVersion: "v1.16.3" +dependencies: + - name: cozy-lib + version: "*" + repository: "file://charts/cozy-lib" diff --git a/packages/apps/qdrant/Makefile b/packages/apps/qdrant/Makefile new file mode 100644 index 00000000..2110125f --- /dev/null +++ b/packages/apps/qdrant/Makefile @@ -0,0 +1,5 @@ +include ../../../hack/package.mk + +generate: + cozyvalues-gen -m 'qdrant' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/qdrant/types.go + ../../../hack/update-crd.sh diff --git a/packages/apps/qdrant/README.md b/packages/apps/qdrant/README.md new file mode 100644 index 00000000..5b5f35a9 --- /dev/null +++ b/packages/apps/qdrant/README.md @@ -0,0 +1,52 @@ +# Managed Qdrant Service + +Qdrant is a high-performance vector database and similarity search engine designed for AI and machine learning applications. It provides efficient storage and retrieval of high-dimensional vectors with advanced filtering capabilities, making it ideal for recommendation systems, semantic search, and RAG (Retrieval-Augmented Generation) applications. + +## Deployment Details + +Service deploys Qdrant as a StatefulSet with automatic cluster mode when multiple replicas are configured. + +- Docs: https://qdrant.tech/documentation/ +- GitHub: https://github.com/qdrant/qdrant + +## Parameters + +### Common parameters + +| Name | Description | Type | Value | +| ------------------ | -------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------- | +| `replicas` | Number of Qdrant replicas. Cluster mode is automatically enabled when replicas > 1. | `int` | `1` | +| `resources` | Explicit CPU and memory configuration for each Qdrant replica. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `resources.cpu` | CPU available to each replica. | `quantity` | `""` | +| `resources.memory` | Memory (RAM) available to each replica. | `quantity` | `""` | +| `resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `small` | +| `size` | Persistent Volume Claim size available for vector data storage. | `quantity` | `10Gi` | +| `storageClass` | StorageClass used to store the data. | `string` | `""` | +| `external` | Enable external access from outside the cluster. | `bool` | `false` | + + +## Parameter examples and reference + +### resources and resourcesPreset + +`resources` sets explicit CPU and memory configurations for each replica. +When left empty, the preset defined in `resourcesPreset` is applied. + +```yaml +resources: + cpu: 4000m + memory: 4Gi +``` + +`resourcesPreset` sets named CPU and memory configurations for each replica. +This setting is ignored if the corresponding `resources` value is set. + +| Preset name | CPU | memory | +|-------------|--------|---------| +| `nano` | `250m` | `128Mi` | +| `micro` | `500m` | `256Mi` | +| `small` | `1` | `512Mi` | +| `medium` | `1` | `1Gi` | +| `large` | `2` | `2Gi` | +| `xlarge` | `4` | `4Gi` | +| `2xlarge` | `8` | `8Gi` | diff --git a/packages/apps/qdrant/charts/cozy-lib b/packages/apps/qdrant/charts/cozy-lib new file mode 120000 index 00000000..e1813509 --- /dev/null +++ b/packages/apps/qdrant/charts/cozy-lib @@ -0,0 +1 @@ +../../../library/cozy-lib \ No newline at end of file diff --git a/packages/apps/qdrant/logos/qdrant.svg b/packages/apps/qdrant/logos/qdrant.svg new file mode 100644 index 00000000..3c940b5e --- /dev/null +++ b/packages/apps/qdrant/logos/qdrant.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/packages/apps/qdrant/templates/dashboard-resourcemap.yaml b/packages/apps/qdrant/templates/dashboard-resourcemap.yaml new file mode 100644 index 00000000..0986951f --- /dev/null +++ b/packages/apps/qdrant/templates/dashboard-resourcemap.yaml @@ -0,0 +1,53 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ .Release.Name }}-dashboard-resources +rules: +- apiGroups: + - "" + resources: + - services + resourceNames: + - {{ .Release.Name }} + - {{ .Release.Name }}-headless + verbs: ["get", "list", "watch"] +- apiGroups: + - "" + resources: + - secrets + resourceNames: + - {{ .Release.Name }}-apikey + verbs: ["get", "list", "watch"] +- apiGroups: + - cozystack.io + resources: + - workloadmonitors + resourceNames: + - {{ .Release.Name }} + verbs: ["get", "list", "watch"] +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Release.Name }}-dashboard-resources +subjects: +{{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "use" .Release.Namespace) }} +roleRef: + kind: Role + name: {{ .Release.Name }}-dashboard-resources + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: {{ .Release.Name }} + labels: + workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }} +spec: + minReplicas: 1 + replicas: {{ .Values.replicas }} + kind: qdrant + type: qdrant + selector: + app.kubernetes.io/instance: {{ .Release.Name }}-system + version: {{ .Chart.Version }} diff --git a/packages/apps/qdrant/templates/qdrant.yaml b/packages/apps/qdrant/templates/qdrant.yaml new file mode 100644 index 00000000..888bd05e --- /dev/null +++ b/packages/apps/qdrant/templates/qdrant.yaml @@ -0,0 +1,43 @@ +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: {{ .Release.Name }}-system + labels: + sharding.fluxcd.io/key: tenants +spec: + chartRef: + kind: ExternalArtifact + name: cozystack-qdrant-application-default-qdrant-system + namespace: cozy-system + interval: 5m + timeout: 10m + install: + remediation: + retries: -1 + upgrade: + force: true + remediation: + retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values + values: + qdrant: + fullnameOverride: {{ .Release.Name }} + replicaCount: {{ .Values.replicas }} + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 8 }} + apiKey: true + livenessProbe: + enabled: true + persistence: + size: {{ .Values.size }} + {{- with .Values.storageClass }} + storageClassName: {{ . }} + {{- end }} + metrics: + serviceMonitor: + enabled: true + {{- if .Values.external }} + service: + type: LoadBalancer + {{- end }} diff --git a/packages/apps/qdrant/values.schema.json b/packages/apps/qdrant/values.schema.json new file mode 100644 index 00000000..90af7c3d --- /dev/null +++ b/packages/apps/qdrant/values.schema.json @@ -0,0 +1,82 @@ +{ + "title": "Chart Values", + "type": "object", + "properties": { + "replicas": { + "description": "Number of Qdrant replicas. Cluster mode is automatically enabled when replicas \u003e 1.", + "type": "integer", + "default": 1 + }, + "resources": { + "description": "Explicit CPU and memory configuration for each Qdrant replica. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "CPU available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Memory (RAM) available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted.", + "type": "string", + "default": "small", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + }, + "size": { + "description": "Persistent Volume Claim size available for vector data storage.", + "default": "10Gi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "storageClass": { + "description": "StorageClass used to store the data.", + "type": "string", + "default": "" + }, + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + } + } +} diff --git a/packages/apps/qdrant/values.yaml b/packages/apps/qdrant/values.yaml new file mode 100644 index 00000000..7abd25ff --- /dev/null +++ b/packages/apps/qdrant/values.yaml @@ -0,0 +1,34 @@ +## +## @section Common parameters +## + +## @typedef {struct} Resources - Explicit CPU and memory configuration for each Qdrant replica. +## @field {quantity} [cpu] - CPU available to each replica. +## @field {quantity} [memory] - Memory (RAM) available to each replica. + +## @enum {string} ResourcesPreset - Default sizing preset. +## @value nano +## @value micro +## @value small +## @value medium +## @value large +## @value xlarge +## @value 2xlarge + +## @param {int} replicas - Number of Qdrant replicas. Cluster mode is automatically enabled when replicas > 1. +replicas: 1 + +## @param {Resources} [resources] - Explicit CPU and memory configuration for each Qdrant replica. When omitted, the preset defined in `resourcesPreset` is applied. +resources: {} + +## @param {ResourcesPreset} resourcesPreset="small" - Default sizing preset used when `resources` is omitted. +resourcesPreset: "small" + +## @param {quantity} size - Persistent Volume Claim size available for vector data storage. +size: 10Gi + +## @param {string} storageClass - StorageClass used to store the data. +storageClass: "" + +## @param {bool} external - Enable external access from outside the cluster. +external: false diff --git a/packages/apps/rabbitmq/Chart.yaml b/packages/apps/rabbitmq/Chart.yaml index 41c0ea20..e764e7dd 100644 --- a/packages/apps/rabbitmq/Chart.yaml +++ b/packages/apps/rabbitmq/Chart.yaml @@ -2,24 +2,6 @@ apiVersion: v2 name: rabbitmq description: Managed RabbitMQ service icon: /logos/rabbitmq.svg - -# 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: 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.8.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: "3.13.2" +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process +appVersion: "4.2.4" diff --git a/packages/apps/rabbitmq/Makefile b/packages/apps/rabbitmq/Makefile index e4057cb4..9b045b66 100644 --- a/packages/apps/rabbitmq/Makefile +++ b/packages/apps/rabbitmq/Makefile @@ -1,5 +1,9 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: - readme-generator -v values.yaml -s values.schema.json -r README.md - yq -i -o json --indent 4 '.properties.resourcesPreset.enum = ["none", "nano", "micro", "small", "medium", "large", "xlarge", "2xlarge"]' values.schema.json + cozyvalues-gen -m 'rabbitmq' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/rabbitmq/types.go + ../../../hack/update-crd.sh + +update: + hack/update-versions.sh + make generate diff --git a/packages/apps/rabbitmq/README.md b/packages/apps/rabbitmq/README.md index cd65fb61..b1f01f21 100644 --- a/packages/apps/rabbitmq/README.md +++ b/packages/apps/rabbitmq/README.md @@ -13,21 +13,30 @@ The service utilizes official RabbitMQ operator. This ensures the reliability an ### Common parameters -| Name | Description | Value | -| -------------- | ----------------------------------------------- | ------- | -| `external` | Enable external access from outside the cluster | `false` | -| `size` | Persistent Volume size | `10Gi` | -| `replicas` | Number of RabbitMQ replicas | `3` | -| `storageClass` | StorageClass used to store the data | `""` | +| Name | Description | Type | Value | +| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------- | +| `replicas` | Number of RabbitMQ replicas. | `int` | `3` | +| `resources` | Explicit CPU and memory configuration for each RabbitMQ replica. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `resources.cpu` | CPU available to each replica. | `quantity` | `""` | +| `resources.memory` | Memory (RAM) available to each replica. | `quantity` | `""` | +| `resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `nano` | +| `size` | Persistent Volume Claim size available for application data. | `quantity` | `10Gi` | +| `storageClass` | StorageClass used to store the data. | `string` | `""` | +| `external` | Enable external access from outside the cluster. | `bool` | `false` | +| `version` | RabbitMQ major.minor version to deploy | `string` | `v4.2` | -### Configuration parameters -| Name | Description | Value | -| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------ | -| `users` | Users configuration | `{}` | -| `vhosts` | Virtual Hosts configuration | `{}` | -| `resources` | Explicit CPU and memory configuration for each RabbitMQ replica. When left empty, the preset defined in `resourcesPreset` is applied. | `{}` | -| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge. | `nano` | +### Application-specific parameters + +| Name | Description | Type | Value | +| ----------------------------- | -------------------------------- | ------------------- | ----- | +| `users` | Users configuration map. | `map[string]object` | `{}` | +| `users[name].password` | Password for the user. | `string` | `""` | +| `vhosts` | Virtual hosts configuration map. | `map[string]object` | `{}` | +| `vhosts[name].roles` | Virtual host roles list. | `object` | `{}` | +| `vhosts[name].roles.admin` | List of admin users. | `[]string` | `[]` | +| `vhosts[name].roles.readonly` | List of readonly users. | `[]string` | `[]` | + ## Parameter examples and reference diff --git a/packages/apps/rabbitmq/files/versions.yaml b/packages/apps/rabbitmq/files/versions.yaml new file mode 100644 index 00000000..0cf87dd0 --- /dev/null +++ b/packages/apps/rabbitmq/files/versions.yaml @@ -0,0 +1,4 @@ +"v4.2": "4.2.4" +"v4.1": "4.1.8" +"v4.0": "4.0.9" +"v3.13": "3.13.7" diff --git a/packages/apps/rabbitmq/hack/update-versions.sh b/packages/apps/rabbitmq/hack/update-versions.sh new file mode 100755 index 00000000..7dec5a84 --- /dev/null +++ b/packages/apps/rabbitmq/hack/update-versions.sh @@ -0,0 +1,129 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +RABBITMQ_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +VALUES_FILE="${RABBITMQ_DIR}/values.yaml" +VERSIONS_FILE="${RABBITMQ_DIR}/files/versions.yaml" +GITHUB_API_URL="https://api.github.com/repos/rabbitmq/rabbitmq-server/releases" + +# Check if jq is installed +if ! command -v jq &> /dev/null; then + echo "Error: jq is not installed. Please install jq and try again." >&2 + exit 1 +fi + +# Fetch releases from GitHub API +echo "Fetching releases from GitHub API..." +RELEASES_JSON=$(curl -sSL "${GITHUB_API_URL}?per_page=100") + +if [ -z "$RELEASES_JSON" ]; then + echo "Error: Could not fetch releases from GitHub API" >&2 + exit 1 +fi + +# Extract stable release tags (format: v3.13.7, v4.0.3, etc.) +# Filter out pre-releases and draft releases +RELEASE_TAGS=$(echo "$RELEASES_JSON" | jq -r '.[] | select(.prerelease == false) | select(.draft == false) | .tag_name' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V) + +if [ -z "$RELEASE_TAGS" ]; then + echo "Error: Could not find any stable release tags" >&2 + exit 1 +fi + +echo "Found release tags: $(echo "$RELEASE_TAGS" | tr '\n' ' ')" + +# Supported major.minor versions (newest first) +# We support the last few minor releases of each active major +SUPPORTED_MAJORS=("4.2" "4.1" "4.0" "3.13") + +# Build versions map: major.minor -> latest patch version +declare -A VERSION_MAP +MAJOR_VERSIONS=() + +for major_minor in "${SUPPORTED_MAJORS[@]}"; do + # Find the latest patch version for this major.minor + MATCHING=$(echo "$RELEASE_TAGS" | grep -E "^v${major_minor//./\\.}\.[0-9]+$" | tail -n1) + + if [ -n "$MATCHING" ]; then + # Strip the 'v' prefix for the value (Docker tag format is e.g. 3.13.7) + TAG_VERSION="${MATCHING#v}" + VERSION_MAP["v${major_minor}"]="${TAG_VERSION}" + MAJOR_VERSIONS+=("v${major_minor}") + echo "Found version: v${major_minor} -> ${TAG_VERSION}" + else + echo "Warning: No stable releases found for ${major_minor}, skipping..." >&2 + fi +done + +if [ ${#MAJOR_VERSIONS[@]} -eq 0 ]; then + echo "Error: No matching versions found" >&2 + exit 1 +fi + +echo "Major versions to add: ${MAJOR_VERSIONS[*]}" + +# Create/update versions.yaml file +echo "Updating $VERSIONS_FILE..." +{ + for major_ver in "${MAJOR_VERSIONS[@]}"; do + echo "\"${major_ver}\": \"${VERSION_MAP[$major_ver]}\"" + done +} > "$VERSIONS_FILE" + +echo "Successfully updated $VERSIONS_FILE" + +# Update values.yaml - enum with major.minor versions only +TEMP_FILE=$(mktemp) +trap "rm -f $TEMP_FILE" EXIT + +# Build new version section +NEW_VERSION_SECTION="## @enum {string} Version" +for major_ver in "${MAJOR_VERSIONS[@]}"; do + NEW_VERSION_SECTION="${NEW_VERSION_SECTION} +## @value $major_ver" +done +NEW_VERSION_SECTION="${NEW_VERSION_SECTION} + +## @param {Version} version - RabbitMQ major.minor version to deploy +version: ${MAJOR_VERSIONS[0]}" + +# Check if version section already exists +if grep -q "^## @enum {string} Version" "$VALUES_FILE"; then + # Version section exists, update it using awk + echo "Updating existing version section in $VALUES_FILE..." + + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @enum {string} Version/ { + in_section = 1 + print new_section + next + } + in_section && /^version: / { + in_section = 0 + next + } + in_section { + next + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +else + # Version section doesn't exist, insert it before Application-specific parameters section + echo "Inserting new version section in $VALUES_FILE..." + + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @section Application-specific parameters/ { + print new_section + print "" + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +fi + +echo "Successfully updated $VALUES_FILE with major.minor versions: ${MAJOR_VERSIONS[*]}" diff --git a/packages/apps/rabbitmq/templates/_versions.tpl b/packages/apps/rabbitmq/templates/_versions.tpl new file mode 100644 index 00000000..76955b33 --- /dev/null +++ b/packages/apps/rabbitmq/templates/_versions.tpl @@ -0,0 +1,8 @@ +{{- define "rabbitmq.versionMap" }} +{{- $versionMap := .Files.Get "files/versions.yaml" | fromYaml }} +{{- if not (hasKey $versionMap .Values.version) }} + {{- printf `RabbitMQ version %s is not supported, allowed versions are %s` $.Values.version (keys $versionMap) | fail }} +{{- end }} +{{- index $versionMap .Values.version }} +{{- end }} + diff --git a/packages/apps/rabbitmq/templates/rabbitmq.yaml b/packages/apps/rabbitmq/templates/rabbitmq.yaml index 7708a3af..bbf2efbe 100644 --- a/packages/apps/rabbitmq/templates/rabbitmq.yaml +++ b/packages/apps/rabbitmq/templates/rabbitmq.yaml @@ -7,6 +7,7 @@ metadata: app.kubernetes.io/managed-by: {{ .Release.Service }} spec: replicas: {{ .Values.replicas }} + image: 'rabbitmq:{{ include "rabbitmq.versionMap" $ }}-management' {{- if .Values.external }} service: type: LoadBalancer @@ -58,6 +59,8 @@ apiVersion: v1 kind: Secret metadata: name: {{ $.Release.Name }}-{{ kebabcase $user }}-credentials + labels: + apps.cozystack.io/user-secret: "true" type: Opaque stringData: username: {{ $user }} diff --git a/packages/apps/rabbitmq/templates/workloadmonitor.yaml b/packages/apps/rabbitmq/templates/workloadmonitor.yaml index 0f7462c7..66941153 100644 --- a/packages/apps/rabbitmq/templates/workloadmonitor.yaml +++ b/packages/apps/rabbitmq/templates/workloadmonitor.yaml @@ -3,6 +3,8 @@ apiVersion: cozystack.io/v1alpha1 kind: WorkloadMonitor metadata: name: {{ $.Release.Name }} + labels: + workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }} spec: replicas: {{ .Values.replicas }} minReplicas: 1 diff --git a/packages/apps/rabbitmq/values.schema.json b/packages/apps/rabbitmq/values.schema.json index 2e40482d..43eaa206 100644 --- a/packages/apps/rabbitmq/values.schema.json +++ b/packages/apps/rabbitmq/values.schema.json @@ -1,51 +1,140 @@ { - "title": "Chart Values", - "type": "object", - "properties": { - "external": { - "type": "boolean", - "description": "Enable external access from outside the cluster", - "default": false + "title": "Chart Values", + "type": "object", + "properties": { + "replicas": { + "description": "Number of RabbitMQ replicas.", + "type": "integer", + "default": 3 + }, + "resources": { + "description": "Explicit CPU and memory configuration for each RabbitMQ replica. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "CPU available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true }, - "size": { - "type": "string", - "description": "Persistent Volume size", - "default": "10Gi" - }, - "replicas": { - "type": "number", - "description": "Number of RabbitMQ replicas", - "default": 3 - }, - "storageClass": { - "type": "string", - "description": "StorageClass used to store the data", - "default": "" - }, - "vhosts": { - "type": "object", - "description": "Virtual Hosts configuration", - "default": {} - }, - "resources": { - "type": "object", - "description": "Explicit CPU and memory configuration for each RabbitMQ replica. When left empty, the preset defined in `resourcesPreset` is applied.", - "default": {} - }, - "resourcesPreset": { - "type": "string", - "description": "Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.", - "default": "nano", - "enum": [ - "none", - "nano", - "micro", - "small", - "medium", - "large", - "xlarge", - "2xlarge" - ] + "memory": { + "description": "Memory (RAM) available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted.", + "type": "string", + "default": "nano", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + }, + "size": { + "description": "Persistent Volume Claim size available for application data.", + "default": "10Gi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "storageClass": { + "description": "StorageClass used to store the data.", + "type": "string", + "default": "" + }, + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + }, + "version": { + "description": "RabbitMQ major.minor version to deploy", + "type": "string", + "default": "v4.2", + "enum": [ + "v4.2", + "v4.1", + "v4.0", + "v3.13" + ] + }, + "users": { + "description": "Users configuration map.", + "type": "object", + "default": {}, + "additionalProperties": { + "type": "object", + "properties": { + "password": { + "description": "Password for the user.", + "type": "string" + } + } + } + }, + "vhosts": { + "description": "Virtual hosts configuration map.", + "type": "object", + "default": {}, + "additionalProperties": { + "type": "object", + "required": [ + "roles" + ], + "properties": { + "roles": { + "description": "Virtual host roles list.", + "type": "object", + "properties": { + "admin": { + "description": "List of admin users.", + "type": "array", + "items": { + "type": "string" + } + }, + "readonly": { + "description": "List of readonly users.", + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } } + } } diff --git a/packages/apps/rabbitmq/values.yaml b/packages/apps/rabbitmq/values.yaml index c6df1725..08b6f5e6 100644 --- a/packages/apps/rabbitmq/values.yaml +++ b/packages/apps/rabbitmq/values.yaml @@ -1,18 +1,56 @@ -## @section Common parameters - -## @param external Enable external access from outside the cluster -## @param size Persistent Volume size -## @param replicas Number of RabbitMQ replicas -## @param storageClass StorageClass used to store the data ## -external: false -size: 10Gi +## @section Common parameters +## + +## @typedef {struct} Resources - Explicit CPU and memory configuration for each RabbitMQ replica. +## @field {quantity} [cpu] - CPU available to each replica. +## @field {quantity} [memory] - Memory (RAM) available to each replica. + +## @enum {string} ResourcesPreset - Default sizing preset. +## @value nano +## @value micro +## @value small +## @value medium +## @value large +## @value xlarge +## @value 2xlarge + +## @param {int} replicas - Number of RabbitMQ replicas. replicas: 3 + +## @param {Resources} [resources] - Explicit CPU and memory configuration for each RabbitMQ replica. When omitted, the preset defined in `resourcesPreset` is applied. +resources: {} + +## @param {ResourcesPreset} resourcesPreset="nano" - Default sizing preset used when `resources` is omitted. +resourcesPreset: "nano" + +## @param {quantity} size - Persistent Volume Claim size available for application data. +size: 10Gi + +## @param {string} storageClass - StorageClass used to store the data. storageClass: "" -## @section Configuration parameters +## @param {bool} external - Enable external access from outside the cluster. +external: false -## @param users [object] Users configuration +## +## @enum {string} Version +## @value v4.2 +## @value v4.1 +## @value v4.0 +## @value v3.13 + +## @param {Version} version - RabbitMQ major.minor version to deploy +version: v4.2 + +## @section Application-specific parameters +## + +## @typedef {struct} User - User configuration. +## @field {string} [password] - Password for the user. + +## @param {map[string]User} users - Users configuration map. +users: {} ## Example: ## users: ## user1: @@ -21,10 +59,16 @@ storageClass: "" ## password: hackme ## user3: ## password: testtest -## -users: {} -## @param vhosts Virtual Hosts configuration +## @typedef {struct} Roles - Virtual host roles. +## @field {[]string} [admin] - List of admin users. +## @field {[]string} [readonly] - List of readonly users. + +## @typedef {struct} Vhost - Virtual host configuration. +## @field {Roles} roles - Virtual host roles list. + +## @param {map[string]Vhost} vhosts - Virtual hosts configuration map. +vhosts: {} ## Example: ## vhosts: ## myapp: @@ -38,13 +82,3 @@ users: {} ## roles: ## admin: ## - user3 -vhosts: {} - -## @param resources Explicit CPU and memory configuration for each RabbitMQ replica. When left empty, the preset defined in `resourcesPreset` is applied. -resources: {} - # resources: - # cpu: 4000m - # memory: 4Gi - -## @param resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge. -resourcesPreset: "nano" diff --git a/packages/apps/redis/.helmignore b/packages/apps/redis/.helmignore index 1ea0ae84..3de7d4a5 100644 --- a/packages/apps/redis/.helmignore +++ b/packages/apps/redis/.helmignore @@ -1,3 +1,4 @@ .helmignore /logos /Makefile +/hack diff --git a/packages/apps/redis/Chart.yaml b/packages/apps/redis/Chart.yaml index 94294f91..8e237b25 100644 --- a/packages/apps/redis/Chart.yaml +++ b/packages/apps/redis/Chart.yaml @@ -2,24 +2,6 @@ apiVersion: v2 name: redis description: Managed Redis service icon: /logos/redis.svg - -# 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: 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 - -# 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. +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process appVersion: "6.2.6" diff --git a/packages/apps/redis/Makefile b/packages/apps/redis/Makefile index e4057cb4..939b75ee 100644 --- a/packages/apps/redis/Makefile +++ b/packages/apps/redis/Makefile @@ -1,5 +1,9 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: - readme-generator -v values.yaml -s values.schema.json -r README.md - yq -i -o json --indent 4 '.properties.resourcesPreset.enum = ["none", "nano", "micro", "small", "medium", "large", "xlarge", "2xlarge"]' values.schema.json + cozyvalues-gen -m 'redis' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/redis/types.go + ../../../hack/update-crd.sh + +update: + hack/update-versions.sh + make generate diff --git a/packages/apps/redis/README.md b/packages/apps/redis/README.md index f7a13513..7f82d229 100644 --- a/packages/apps/redis/README.md +++ b/packages/apps/redis/README.md @@ -13,15 +13,25 @@ Service utilizes the Spotahome Redis Operator for efficient management and orche ### Common parameters -| Name | Description | Value | -| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------- | -| `external` | Enable external access from outside the cluster | `false` | -| `size` | Persistent Volume size | `1Gi` | -| `replicas` | Number of Redis replicas | `2` | -| `storageClass` | StorageClass used to store the data | `""` | -| `authEnabled` | Enable password generation | `true` | -| `resources` | Explicit CPU and memory configuration for each Redis replica. When left empty, the preset defined in `resourcesPreset` is applied. | `{}` | -| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge. | `nano` | +| Name | Description | Type | Value | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------- | +| `replicas` | Number of Redis replicas. | `int` | `2` | +| `resources` | Explicit CPU and memory configuration for each Redis replica. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `resources.cpu` | CPU available to each replica. | `quantity` | `""` | +| `resources.memory` | Memory (RAM) available to each replica. | `quantity` | `""` | +| `resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `nano` | +| `size` | Persistent Volume Claim size available for application data. | `quantity` | `1Gi` | +| `storageClass` | StorageClass used to store the data. | `string` | `""` | +| `external` | Enable external access from outside the cluster. | `bool` | `false` | +| `version` | Redis major version to deploy | `string` | `v8` | + + +### Application-specific parameters + +| Name | Description | Type | Value | +| ------------- | --------------------------- | ------ | ------ | +| `authEnabled` | Enable password generation. | `bool` | `true` | + ## Parameter examples and reference diff --git a/packages/apps/redis/files/versions.yaml b/packages/apps/redis/files/versions.yaml new file mode 100644 index 00000000..be1e42d6 --- /dev/null +++ b/packages/apps/redis/files/versions.yaml @@ -0,0 +1,2 @@ +"v8": "8.4.0" +"v7": "7.4.7" diff --git a/packages/apps/redis/hack/update-versions.sh b/packages/apps/redis/hack/update-versions.sh new file mode 100755 index 00000000..daad973e --- /dev/null +++ b/packages/apps/redis/hack/update-versions.sh @@ -0,0 +1,161 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REDIS_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +VALUES_FILE="${REDIS_DIR}/values.yaml" +VERSIONS_FILE="${REDIS_DIR}/files/versions.yaml" +REDIS_IMAGE="docker://docker.io/redis" + +# Check if skopeo is installed +if ! command -v skopeo &> /dev/null; then + echo "Error: skopeo is not installed. Please install skopeo and try again." >&2 + exit 1 +fi + +# Check if jq is installed +if ! command -v jq &> /dev/null; then + echo "Error: jq is not installed. Please install jq and try again." >&2 + exit 1 +fi + +# Get available image tags +echo "Fetching available image tags from registry..." +AVAILABLE_TAGS=$(skopeo list-tags "${REDIS_IMAGE}" | jq -r '.Tags[] | select(test("^[0-9]+\\.[0-9]+\\.[0-9]+$"))' | sort -V) + +if [ -z "$AVAILABLE_TAGS" ]; then + echo "Error: Could not fetch available image tags" >&2 + exit 1 +fi + +# Get all unique major versions and find Latest and Previous +echo "Finding Latest and Previous major versions..." +ALL_MAJOR_VERSIONS=$(echo "$AVAILABLE_TAGS" | cut -d. -f1 | sort -u -n -r) +MAJOR_VERSIONS_ARRAY=($ALL_MAJOR_VERSIONS) + +if [ ${#MAJOR_VERSIONS_ARRAY[@]} -lt 1 ]; then + echo "Error: Could not find any major versions" >&2 + exit 1 +fi + +# Get Latest and Previous major versions +LATEST_MAJOR=${MAJOR_VERSIONS_ARRAY[0]} +PREVIOUS_MAJOR="" + +if [ ${#MAJOR_VERSIONS_ARRAY[@]} -ge 2 ]; then + PREVIOUS_MAJOR=${MAJOR_VERSIONS_ARRAY[1]} +fi + +if [ -z "$PREVIOUS_MAJOR" ]; then + echo "Warning: Only one major version found (${LATEST_MAJOR}), using it as both Latest and Previous" + PREVIOUS_MAJOR=$LATEST_MAJOR +fi + +echo "Latest major version: ${LATEST_MAJOR}" +echo "Previous major version: ${PREVIOUS_MAJOR}" + +# Build versions map: major version -> latest patch version +declare -A VERSION_MAP +MAJOR_VERSIONS=() +PROCESSED_MAJORS=() + +for major_version in "$LATEST_MAJOR" "$PREVIOUS_MAJOR"; do + # Skip if we already processed this major version + if [[ " ${PROCESSED_MAJORS[@]} " =~ " ${major_version} " ]]; then + continue + fi + PROCESSED_MAJORS+=("${major_version}") + + # Find all tags that match this major version + matching_tags=$(echo "$AVAILABLE_TAGS" | grep "^${major_version}\\.") + + if [ -n "$matching_tags" ]; then + # Get the latest patch version for this major version + latest_tag=$(echo "$matching_tags" | tail -n1) + VERSION_MAP["v${major_version}"]="${latest_tag}" + MAJOR_VERSIONS+=("v${major_version}") + echo "Found version: v${major_version} -> ${latest_tag}" + else + echo "Warning: Could not find any patch versions for ${major_version}, skipping..." >&2 + fi +done + +if [ ${#MAJOR_VERSIONS[@]} -eq 0 ]; then + echo "Error: No matching versions found" >&2 + exit 1 +fi + +# Sort major versions in descending order (newest first) +IFS=$'\n' MAJOR_VERSIONS=($(printf '%s\n' "${MAJOR_VERSIONS[@]}" | sort -V -r)) +unset IFS + +echo "Major versions to add: ${MAJOR_VERSIONS[*]}" + +# Create/update versions.yaml file +echo "Updating $VERSIONS_FILE..." +{ + for major_ver in "${MAJOR_VERSIONS[@]}"; do + echo "\"${major_ver}\": \"${VERSION_MAP[$major_ver]}\"" + done +} > "$VERSIONS_FILE" + +echo "Successfully updated $VERSIONS_FILE" + +# Update values.yaml - enum with major versions only +TEMP_FILE=$(mktemp) +trap "rm -f $TEMP_FILE" EXIT + +# Build new version section +NEW_VERSION_SECTION="## @enum {string} Version" +for major_ver in "${MAJOR_VERSIONS[@]}"; do + NEW_VERSION_SECTION="${NEW_VERSION_SECTION} +## @value $major_ver" +done +NEW_VERSION_SECTION="${NEW_VERSION_SECTION} + +## @param {Version} version - Redis major version to deploy +version: ${MAJOR_VERSIONS[0]}" + +# Check if version section already exists +if grep -q "^## @enum {string} Version" "$VALUES_FILE"; then + # Version section exists, update it using awk + echo "Updating existing version section in $VALUES_FILE..." + + # Use awk to replace the section from "## @enum {string} Version" to "version: " (inclusive) + # Delete the old section and insert the new one + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @enum {string} Version/ { + in_section = 1 + print new_section + next + } + in_section && /^version: / { + in_section = 0 + next + } + in_section { + next + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +else + # Version section doesn't exist, insert it before Application-specific parameters section + echo "Inserting new version section in $VALUES_FILE..." + + # Use awk to insert before "## @section Application-specific parameters" + awk -v new_section="$NEW_VERSION_SECTION" ' + /^## @section Application-specific parameters/ { + print new_section + print "" + } + { print } + ' "$VALUES_FILE" > "$TEMP_FILE.tmp" + mv "$TEMP_FILE.tmp" "$VALUES_FILE" +fi + +echo "Successfully updated $VALUES_FILE with major versions: ${MAJOR_VERSIONS[*]}" + diff --git a/packages/apps/redis/templates/_versions.tpl b/packages/apps/redis/templates/_versions.tpl new file mode 100644 index 00000000..758e3800 --- /dev/null +++ b/packages/apps/redis/templates/_versions.tpl @@ -0,0 +1,8 @@ +{{- define "redis.versionMap" }} +{{- $versionMap := .Files.Get "files/versions.yaml" | fromYaml }} +{{- if not (hasKey $versionMap .Values.version) }} + {{- printf `Redis version %s is not supported, allowed versions are %s` $.Values.version (keys $versionMap) | fail }} +{{- end }} +{{- index $versionMap .Values.version }} +{{- end }} + diff --git a/packages/apps/redis/templates/redisfailover.yaml b/packages/apps/redis/templates/redisfailover.yaml index f6d1ae05..160e030d 100644 --- a/packages/apps/redis/templates/redisfailover.yaml +++ b/packages/apps/redis/templates/redisfailover.yaml @@ -27,6 +27,7 @@ spec: replicas: 3 resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 6 }} redis: + image: "redis:{{ include "redis.versionMap" $ }}" resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 6 }} replicas: {{ .Values.replicas }} {{- with .Values.size }} @@ -74,6 +75,8 @@ kind: WorkloadMonitor metadata: name: {{ $.Release.Name }}-redis namespace: {{ $.Release.Namespace }} + labels: + workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }} spec: minReplicas: 1 replicas: {{ .Values.replicas }} @@ -89,6 +92,8 @@ kind: WorkloadMonitor metadata: name: {{ $.Release.Name }}-sentinel namespace: {{ $.Release.Namespace }} + labels: + workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }} spec: minReplicas: 2 replicas: 3 diff --git a/packages/apps/redis/templates/service.yaml b/packages/apps/redis/templates/service.yaml index 05729a4a..81a73761 100644 --- a/packages/apps/redis/templates/service.yaml +++ b/packages/apps/redis/templates/service.yaml @@ -11,7 +11,9 @@ spec: type: {{ ternary "LoadBalancer" "ClusterIP" .Values.external }} {{- if .Values.external }} externalTrafficPolicy: Local + {{- if (include "cozy-lib.network.disableLoadBalancerNodePorts" $ | fromYaml) }} allocateLoadBalancerNodePorts: false + {{- end }} {{- end }} selector: app.kubernetes.io/component: redis diff --git a/packages/apps/redis/values.schema.json b/packages/apps/redis/values.schema.json index 17e05c1a..a93d92ac 100644 --- a/packages/apps/redis/values.schema.json +++ b/packages/apps/redis/values.schema.json @@ -1,51 +1,96 @@ { - "title": "Chart Values", - "type": "object", - "properties": { - "external": { - "type": "boolean", - "description": "Enable external access from outside the cluster", - "default": false + "title": "Chart Values", + "type": "object", + "properties": { + "replicas": { + "description": "Number of Redis replicas.", + "type": "integer", + "default": 2 + }, + "resources": { + "description": "Explicit CPU and memory configuration for each Redis replica. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "CPU available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true }, - "size": { - "type": "string", - "description": "Persistent Volume size", - "default": "1Gi" - }, - "replicas": { - "type": "number", - "description": "Number of Redis replicas", - "default": 2 - }, - "storageClass": { - "type": "string", - "description": "StorageClass used to store the data", - "default": "" - }, - "authEnabled": { - "type": "boolean", - "description": "Enable password generation", - "default": true - }, - "resources": { - "type": "object", - "description": "Explicit CPU and memory configuration for each Redis replica. When left empty, the preset defined in `resourcesPreset` is applied.", - "default": {} - }, - "resourcesPreset": { - "type": "string", - "description": "Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.", - "default": "nano", - "enum": [ - "none", - "nano", - "micro", - "small", - "medium", - "large", - "xlarge", - "2xlarge" - ] + "memory": { + "description": "Memory (RAM) available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted.", + "type": "string", + "default": "nano", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + }, + "size": { + "description": "Persistent Volume Claim size available for application data.", + "default": "1Gi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "storageClass": { + "description": "StorageClass used to store the data.", + "type": "string", + "default": "" + }, + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + }, + "version": { + "description": "Redis major version to deploy", + "type": "string", + "default": "v8", + "enum": [ + "v8", + "v7" + ] + }, + "authEnabled": { + "description": "Enable password generation.", + "type": "boolean", + "default": true } + } } diff --git a/packages/apps/redis/values.yaml b/packages/apps/redis/values.yaml index 439e2029..efe80d07 100644 --- a/packages/apps/redis/values.yaml +++ b/packages/apps/redis/values.yaml @@ -1,22 +1,48 @@ -## @section Common parameters - -## @param external Enable external access from outside the cluster -## @param size Persistent Volume size -## @param replicas Number of Redis replicas -## @param storageClass StorageClass used to store the data -## @param authEnabled Enable password generation ## -external: false -size: 1Gi -replicas: 2 -storageClass: "" -authEnabled: true +## @section Common parameters +## -## @param resources Explicit CPU and memory configuration for each Redis replica. When left empty, the preset defined in `resourcesPreset` is applied. +## @typedef {struct} Resources - Explicit CPU and memory configuration for each Redis replica. +## @field {quantity} [cpu] - CPU available to each replica. +## @field {quantity} [memory] - Memory (RAM) available to each replica. + +## @enum {string} ResourcesPreset - Default sizing preset. +## @value nano +## @value micro +## @value small +## @value medium +## @value large +## @value xlarge +## @value 2xlarge + +## @param {int} replicas - Number of Redis replicas. +replicas: 2 + +## @param {Resources} [resources] - Explicit CPU and memory configuration for each Redis replica. When omitted, the preset defined in `resourcesPreset` is applied. resources: {} - # resources: - # cpu: 4000m - # memory: 4Gi - -## @param resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge. + +## @param {ResourcesPreset} resourcesPreset="nano" - Default sizing preset used when `resources` is omitted. resourcesPreset: "nano" + +## @param {quantity} size - Persistent Volume Claim size available for application data. +size: 1Gi + +## @param {string} storageClass - StorageClass used to store the data. +storageClass: "" + +## @param {bool} external - Enable external access from outside the cluster. +external: false + +## @enum {string} Version +## @value v8 +## @value v7 + +## @param {Version} version - Redis major version to deploy +version: v8 + +## +## @section Application-specific parameters +## + +## @param {bool} authEnabled - Enable password generation. +authEnabled: true diff --git a/packages/apps/tcp-balancer/Chart.yaml b/packages/apps/tcp-balancer/Chart.yaml index 5d2c65cf..a65c69e7 100644 --- a/packages/apps/tcp-balancer/Chart.yaml +++ b/packages/apps/tcp-balancer/Chart.yaml @@ -2,24 +2,6 @@ apiVersion: v2 name: tcp-balancer description: Layer4 load balancer service icon: /logos/haproxy.svg - -# 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: 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 - -# 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. +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process appVersion: "2.9.7" diff --git a/packages/apps/tcp-balancer/Makefile b/packages/apps/tcp-balancer/Makefile index 6c4fa835..e3bf78fe 100644 --- a/packages/apps/tcp-balancer/Makefile +++ b/packages/apps/tcp-balancer/Makefile @@ -1,7 +1,5 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: - readme-generator -v values.yaml -s values.schema.json -r README.md - yq -i -o json --indent 2 '.properties.httpAndHttps.properties.mode.enum = ["tcp","tcp-with-proxy"]' values.schema.json - yq -i -o json --indent 2 '.properties.resourcesPreset.enum = ["none", "nano", "micro", "small", "medium", "large", "xlarge", "2xlarge"]' values.schema.json - rm -f values.schema.json.tmp + cozyvalues-gen -m 'tcpbalancer' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/tcpbalancer/types.go + ../../../hack/update-crd.sh diff --git a/packages/apps/tcp-balancer/README.md b/packages/apps/tcp-balancer/README.md index 94dfd72e..c25990aa 100644 --- a/packages/apps/tcp-balancer/README.md +++ b/packages/apps/tcp-balancer/README.md @@ -12,23 +12,29 @@ Managed TCP Load Balancer Service efficiently utilizes HAProxy for load balancin ### Common parameters -| Name | Description | Value | -| ---------- | ----------------------------------------------- | ------- | -| `external` | Enable external access from outside the cluster | `false` | -| `replicas` | Number of HAProxy replicas | `2` | +| Name | Description | Type | Value | +| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------- | +| `replicas` | Number of HAProxy replicas. | `int` | `2` | +| `resources` | Explicit CPU and memory configuration for each TCP Balancer replica. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `resources.cpu` | CPU available to each replica. | `quantity` | `""` | +| `resources.memory` | Memory (RAM) available to each replica. | `quantity` | `""` | +| `resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `nano` | +| `external` | Enable external access from outside the cluster. | `bool` | `false` | -### Configuration parameters -| Name | Description | Value | -| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------- | -| `httpAndHttps.mode` | Mode for balancer. Allowed values: `tcp` and `tcp-with-proxy` | `tcp` | -| `httpAndHttps.targetPorts.http` | HTTP port number. | `80` | -| `httpAndHttps.targetPorts.https` | HTTPS port number. | `443` | -| `httpAndHttps.endpoints` | Endpoint addresses list | `[]` | -| `whitelistHTTP` | Secure HTTP by enabling client networks whitelisting | `false` | -| `whitelist` | List of client networks | `[]` | -| `resources` | Explicit CPU and memory configuration for each TCP Balancer replica. When left empty, the preset defined in `resourcesPreset` is applied. | `{}` | -| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge. | `nano` | +### Application-specific parameters + +| Name | Description | Type | Value | +| -------------------------------- | ------------------------------------------------------------- | ---------- | ------- | +| `httpAndHttps` | HTTP and HTTPS configuration. | `object` | `{}` | +| `httpAndHttps.mode` | Mode for balancer. | `string` | `tcp` | +| `httpAndHttps.targetPorts` | Target ports configuration. | `object` | `{}` | +| `httpAndHttps.targetPorts.http` | HTTP port number. | `int` | `80` | +| `httpAndHttps.targetPorts.https` | HTTPS port number. | `int` | `443` | +| `httpAndHttps.endpoints` | Endpoint addresses list. | `[]string` | `[]` | +| `whitelistHTTP` | Secure HTTP by whitelisting client networks (default: false). | `bool` | `false` | +| `whitelist` | List of allowed client networks. | `[]string` | `[]` | + ## Parameter examples and reference diff --git a/packages/apps/tcp-balancer/templates/service.yaml b/packages/apps/tcp-balancer/templates/service.yaml index 030b8e7e..8384cc85 100644 --- a/packages/apps/tcp-balancer/templates/service.yaml +++ b/packages/apps/tcp-balancer/templates/service.yaml @@ -10,7 +10,9 @@ spec: type: {{ ternary "LoadBalancer" "ClusterIP" .Values.external }} {{- if .Values.external }} externalTrafficPolicy: Local + {{- if (include "cozy-lib.network.disableLoadBalancerNodePorts" $ | fromYaml) }} allocateLoadBalancerNodePorts: false + {{- end }} {{- end }} selector: app: {{ .Release.Name }}-haproxy diff --git a/packages/apps/tcp-balancer/templates/workloadmonitor.yaml b/packages/apps/tcp-balancer/templates/workloadmonitor.yaml index 41dce2ab..3478826b 100644 --- a/packages/apps/tcp-balancer/templates/workloadmonitor.yaml +++ b/packages/apps/tcp-balancer/templates/workloadmonitor.yaml @@ -3,6 +3,8 @@ apiVersion: cozystack.io/v1alpha1 kind: WorkloadMonitor metadata: name: {{ $.Release.Name }} + labels: + workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }} spec: replicas: {{ .Values.replicas }} minReplicas: 1 diff --git a/packages/apps/tcp-balancer/values.schema.json b/packages/apps/tcp-balancer/values.schema.json index 908a72c5..20d04d80 100644 --- a/packages/apps/tcp-balancer/values.schema.json +++ b/packages/apps/tcp-balancer/values.schema.json @@ -2,73 +2,49 @@ "title": "Chart Values", "type": "object", "properties": { - "external": { - "type": "boolean", - "description": "Enable external access from outside the cluster", - "default": false - }, "replicas": { - "type": "number", - "description": "Number of HAProxy replicas", + "description": "Number of HAProxy replicas.", + "type": "integer", "default": 2 }, - "httpAndHttps": { + "resources": { + "description": "Explicit CPU and memory configuration for each TCP Balancer replica. When omitted, the preset defined in `resourcesPreset` is applied.", "type": "object", + "default": {}, "properties": { - "mode": { - "type": "string", - "description": "Mode for balancer. Allowed values: `tcp` and `tcp-with-proxy`", - "default": "tcp", - "enum": [ - "tcp", - "tcp-with-proxy" - ] - }, - "targetPorts": { - "type": "object", - "properties": { - "http": { - "type": "number", - "description": "HTTP port number.", - "default": 80 + "cpu": { + "description": "CPU available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" }, - "https": { - "type": "number", - "description": "HTTPS port number.", - "default": 443 + { + "type": "string" } - } + ], + "x-kubernetes-int-or-string": true }, - "endpoints": { - "type": "array", - "description": "Endpoint addresses list", - "default": [], - "items": {} + "memory": { + "description": "Memory (RAM) available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true } } }, - "whitelistHTTP": { - "type": "boolean", - "description": "Secure HTTP by enabling client networks whitelisting", - "default": false - }, - "whitelist": { - "type": "array", - "description": "List of client networks", - "default": [], - "items": {} - }, - "resources": { - "type": "object", - "description": "Explicit CPU and memory configuration for each TCP Balancer replica. When left empty, the preset defined in `resourcesPreset` is applied.", - "default": {} - }, "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted.", "type": "string", - "description": "Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.", "default": "nano", "enum": [ - "none", "nano", "micro", "small", @@ -77,6 +53,73 @@ "xlarge", "2xlarge" ] + }, + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + }, + "httpAndHttps": { + "description": "HTTP and HTTPS configuration.", + "type": "object", + "default": {}, + "required": [ + "mode", + "targetPorts" + ], + "properties": { + "endpoints": { + "description": "Endpoint addresses list.", + "type": "array", + "default": [], + "items": { + "type": "string" + } + }, + "mode": { + "description": "Mode for balancer.", + "type": "string", + "default": "tcp", + "enum": [ + "tcp", + "tcp-with-proxy" + ] + }, + "targetPorts": { + "description": "Target ports configuration.", + "type": "object", + "default": {}, + "required": [ + "http", + "https" + ], + "properties": { + "http": { + "description": "HTTP port number.", + "type": "integer", + "default": 80 + }, + "https": { + "description": "HTTPS port number.", + "type": "integer", + "default": 443 + } + } + } + } + }, + "whitelistHTTP": { + "description": "Secure HTTP by whitelisting client networks (default: false).", + "type": "boolean", + "default": false + }, + "whitelist": { + "description": "List of allowed client networks.", + "type": "array", + "default": [], + "items": { + "type": "string" + } } } } diff --git a/packages/apps/tcp-balancer/values.yaml b/packages/apps/tcp-balancer/values.yaml index 17ede5ce..9451ff8a 100644 --- a/packages/apps/tcp-balancer/values.yaml +++ b/packages/apps/tcp-balancer/values.yaml @@ -1,31 +1,50 @@ -## @section Common parameters - -## @param external Enable external access from outside the cluster -## @param replicas Number of HAProxy replicas ## -external: false +## @section Common parameters +## + +## @typedef {struct} Resources - Explicit CPU and memory configuration for each TCP Balancer replica. +## @field {quantity} [cpu] - CPU available to each replica. +## @field {quantity} [memory] - Memory (RAM) available to each replica. + +## @enum {string} ResourcesPreset - Default sizing preset. +## @value nano +## @value micro +## @value small +## @value medium +## @value large +## @value xlarge +## @value 2xlarge + +## @param {int} replicas - Number of HAProxy replicas. replicas: 2 -## @section Configuration parameters +## @param {Resources} [resources] - Explicit CPU and memory configuration for each TCP Balancer replica. When omitted, the preset defined in `resourcesPreset` is applied. +resources: {} -## @param httpAndHttps.mode Mode for balancer. Allowed values: `tcp` and `tcp-with-proxy` -## @param httpAndHttps.targetPorts.http HTTP port number. -## @param httpAndHttps.targetPorts.https HTTPS port number. -## @param httpAndHttps.endpoints Endpoint addresses list -## Example: -## httpAndHttps: -## mode: tcp -## targetPorts: -## http: 80 -## https: 443 -## endpoints: -## - 10.100.3.1 -## - 10.100.3.11 -## - 10.100.3.2 -## - 10.100.3.12 -## - 10.100.3.3 -## - 10.100.3.13 +## @param {ResourcesPreset} resourcesPreset="nano" - Default sizing preset used when `resources` is omitted. +resourcesPreset: "nano" +## @param {bool} external - Enable external access from outside the cluster. +external: false + +## +## @section Application-specific parameters +## + +## @enum {string} Mode - Mode for balancer. +## @value tcp +## @value tcp-with-proxy + +## @typedef {struct} TargetPorts - Target ports configuration. +## @field {int} http - HTTP port number. +## @field {int} https - HTTPS port number. + +## @typedef {struct} HttpAndHttps - HTTP and HTTPS configuration. +## @field {Mode} mode - Mode for balancer. +## @field {TargetPorts} targetPorts - Target ports configuration. +## @field {[]string} endpoints - Endpoint addresses list. + +## @param {HttpAndHttps} httpAndHttps - HTTP and HTTPS configuration. httpAndHttps: mode: tcp targetPorts: @@ -33,22 +52,14 @@ httpAndHttps: https: 443 endpoints: [] -## @param whitelistHTTP Secure HTTP by enabling client networks whitelisting -## @param whitelist List of client networks +## @param {bool} whitelistHTTP - Secure HTTP by whitelisting client networks (default: false). +whitelistHTTP: false ## Example: ## whitelistHTTP: true ## whitelist: ## - "1.2.3.4" ## - "10.100.0.0/16" ## -whitelistHTTP: false + +## @param {[]string} whitelist - List of allowed client networks. whitelist: [] - -## @param resources Explicit CPU and memory configuration for each TCP Balancer replica. When left empty, the preset defined in `resourcesPreset` is applied. -resources: {} -# resources: -# cpu: 4000m -# memory: 4Gi - -## @param resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge. -resourcesPreset: "nano" diff --git a/packages/apps/tenant/Chart.yaml b/packages/apps/tenant/Chart.yaml index b11ee15c..47635918 100644 --- a/packages/apps/tenant/Chart.yaml +++ b/packages/apps/tenant/Chart.yaml @@ -2,6 +2,5 @@ apiVersion: v2 name: tenant description: Separated tenant namespace icon: /logos/tenant.svg - type: application -version: 1.11.0 +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/apps/tenant/Makefile b/packages/apps/tenant/Makefile index 264adfcf..2f51d836 100644 --- a/packages/apps/tenant/Makefile +++ b/packages/apps/tenant/Makefile @@ -1,4 +1,8 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: - readme-generator -v values.yaml -s values.schema.json -r README.md + cozyvalues-gen -m 'tenant' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/tenant/types.go + ../../../hack/update-crd.sh + +test: + helm unittest . diff --git a/packages/apps/tenant/README.md b/packages/apps/tenant/README.md index cc26c830..96cf5c6e 100644 --- a/packages/apps/tenant/README.md +++ b/packages/apps/tenant/README.md @@ -6,15 +6,20 @@ Tenants can be created recursively and are subject to the following rules: ### Tenant naming -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. +Tenant names must be alphanumeric: + +- Lowercase letters (`a-z`) and digits (`0-9`) only +- Must start with a lowercase letter +- Dashes (`-`) are **not allowed**, unlike with other services +- Maximum length depends on the cluster configuration (Helm release prefix and root domain) + +This restriction exists to keep consistent naming in tenants, nested tenants, and services deployed in them. +A tenant cannot be named `foo-bar` because parsing internal resource names like `tenant-foo-bar` would be ambiguous. For example: - 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 @@ -69,12 +74,44 @@ tenant-u1 ### Common parameters -| Name | Description | Value | -| ---------------- | --------------------------------------------------------------------------------------------------------------------------- | ------- | -| `host` | The hostname used to access tenant services (defaults to using the tenant name as a subdomain for it's parent tenant host). | `""` | -| `etcd` | Deploy own Etcd cluster | `false` | -| `monitoring` | Deploy own Monitoring Stack | `false` | -| `ingress` | Deploy own Ingress Controller | `false` | -| `seaweedfs` | Deploy own SeaweedFS | `false` | -| `isolated` | Enforce tenant namespace with network policies | `true` | -| `resourceQuotas` | Define resource quotas for the tenant | `{}` | +| Name | Description | Type | Value | +| ----------------- | -------------------------------------------------------------------------------------------------------------------------- | --------------------- | ------- | +| `host` | The hostname used to access tenant services (defaults to using the tenant name as a subdomain for its parent tenant host). | `string` | `""` | +| `etcd` | Deploy own Etcd cluster. | `bool` | `false` | +| `monitoring` | Deploy own Monitoring Stack. | `bool` | `false` | +| `ingress` | Deploy own Ingress Controller. | `bool` | `false` | +| `seaweedfs` | Deploy own SeaweedFS. | `bool` | `false` | +| `schedulingClass` | The name of a SchedulingClass CR to apply scheduling constraints for this tenant's workloads. | `string` | `""` | +| `resourceQuotas` | Define resource quotas for the tenant. | `map[string]quantity` | `{}` | + + +## Configuration + +### Resource Quotas + +The `resourceQuotas` parameter allows you to limit resources available to the tenant. Supported keys include: + +**Compute resources** (converted to `requests.X` and `limits.X`): +- `cpu` - Total CPU cores (e.g., `"4"` or `"500m"`) +- `memory` - Total memory (e.g., `"4Gi"` or `"512Mi"`) +- `ephemeral-storage` - Ephemeral storage limit (e.g., `"10Gi"`) +- `storage` - Total persistent storage (e.g., `"100Gi"`) + +**Object count quotas** (passed as-is): +- `pods` - Maximum number of pods +- `services` - Maximum number of services +- `services.loadbalancers` - Maximum number of LoadBalancer services +- `services.nodeports` - Maximum number of NodePort services +- `configmaps` - Maximum number of ConfigMaps +- `secrets` - Maximum number of Secrets +- `persistentvolumeclaims` - Maximum number of PVCs + +**Example:** +```yaml +resourceQuotas: + cpu: 4 + memory: 4Gi + storage: 10Gi + services.loadbalancers: "3" + pods: "50" +``` diff --git a/packages/apps/tenant/templates/cilium-lb-pool.yaml b/packages/apps/tenant/templates/cilium-lb-pool.yaml new file mode 100644 index 00000000..63dbcaca --- /dev/null +++ b/packages/apps/tenant/templates/cilium-lb-pool.yaml @@ -0,0 +1,28 @@ +{{- $exposeMode := (index .Values._cluster "expose-mode") | default "externalIPs" }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} +{{- $exposeIPs := (index .Values._cluster "expose-external-ips") | default "" | nospace }} +{{- $ipsList := list }} +{{- range splitList "," $exposeIPs }} + {{- $ip := . | trim }} + {{- if $ip }} + {{- $ipsList = append $ipsList $ip }} + {{- end }} +{{- end }} +{{- $isPublishingIngressLB := and + (eq $exposeMode "loadBalancer") + (eq $exposeIngress .Release.Namespace) + .Values.ingress }} +{{- if and $isPublishingIngressLB $ipsList }} +apiVersion: cilium.io/v2 +kind: CiliumLoadBalancerIPPool +metadata: + name: {{ trimPrefix "tenant-" .Release.Namespace }}-exposure +spec: + blocks: + {{- range $ipsList }} + - cidr: {{ . }}{{ if not (contains "/" .) }}/{{ if contains ":" . }}128{{ else }}32{{ end }}{{ end }} + {{- end }} + serviceSelector: + matchLabels: + "io.kubernetes.service.namespace": {{ .Release.Namespace | quote }} +{{- end }} diff --git a/packages/apps/tenant/templates/cleanup-job.yaml b/packages/apps/tenant/templates/cleanup-job.yaml new file mode 100644 index 00000000..0f13daa4 --- /dev/null +++ b/packages/apps/tenant/templates/cleanup-job.yaml @@ -0,0 +1,85 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "tenant.name" . }}-cleanup + namespace: cozy-system + annotations: + helm.sh/hook: pre-delete + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "-5" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "tenant.name" . }}-cleanup + namespace: {{ include "tenant.name" . }} + annotations: + helm.sh/hook: pre-delete + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "-5" +rules: +- apiGroups: ["helm.toolkit.fluxcd.io"] + resources: ["helmreleases"] + verbs: ["get", "list", "delete"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "tenant.name" . }}-cleanup + namespace: {{ include "tenant.name" . }} + annotations: + helm.sh/hook: pre-delete + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "-5" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "tenant.name" . }}-cleanup +subjects: +- kind: ServiceAccount + name: {{ include "tenant.name" . }}-cleanup + namespace: cozy-system +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "tenant.name" . }}-cleanup + namespace: cozy-system + annotations: + helm.sh/hook: pre-delete + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "0" +spec: + ttlSecondsAfterFinished: 300 + template: + metadata: + name: {{ include "tenant.name" . }}-cleanup + labels: + policy.cozystack.io/allow-to-apiserver: "true" + spec: + serviceAccountName: {{ include "tenant.name" . }}-cleanup + restartPolicy: OnFailure + containers: + - name: cleanup + image: bitnami/kubectl:latest + command: + - /bin/bash + - -c + - | + set -e + NAMESPACE="{{ include "tenant.name" . }}" + + echo "Cleaning up HelmReleases in namespace: $NAMESPACE" + + echo "Deleting Applications" + kubectl delete helmreleases.helm.toolkit.fluxcd.io -n "$NAMESPACE" \ + -l 'apps.cozystack.io/application.kind,internal.cozystack.io/tenantmodule!=true' \ + --ignore-not-found=true --wait=true + + echo "Deleting Tenant Modules" + kubectl delete helmreleases.helm.toolkit.fluxcd.io -n "$NAMESPACE" \ + -l 'apps.cozystack.io/application.kind,internal.cozystack.io/tenantmodule=true' \ + --ignore-not-found=true --wait=true + + echo "Cleanup completed successfully" diff --git a/packages/apps/tenant/templates/etcd.yaml b/packages/apps/tenant/templates/etcd.yaml index 17b66683..9a122da2 100644 --- a/packages/apps/tenant/templates/etcd.yaml +++ b/packages/apps/tenant/templates/etcd.yaml @@ -4,22 +4,29 @@ kind: HelmRelease metadata: name: etcd namespace: {{ include "tenant.name" . }} - annotations: - helm.sh/resource-policy: keep labels: - cozystack.io/ui: "true" + sharding.fluxcd.io/key: tenants + internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} + apps.cozystack.io/application.kind: Etcd + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: etcd spec: - chart: - spec: - chart: etcd - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - version: "*" - interval: 1m0s - timeout: 5m0s + chartRef: + kind: ExternalArtifact + name: cozystack-etcd-application-default-etcd + namespace: cozy-system + interval: 5m + timeout: 30m + install: + remediation: + retries: -1 + upgrade: + force: true + remediation: + retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values {{- end }} diff --git a/packages/apps/tenant/templates/info.yaml b/packages/apps/tenant/templates/info.yaml index 08e32329..520028c1 100644 --- a/packages/apps/tenant/templates/info.yaml +++ b/packages/apps/tenant/templates/info.yaml @@ -1,27 +1,30 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} -{{- if $oidcEnabled }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: info namespace: {{ include "tenant.name" . }} - annotations: - helm.sh/resource-policy: keep labels: - cozystack.io/ui: "true" + sharding.fluxcd.io/key: tenants + internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} + apps.cozystack.io/application.kind: Info + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: info spec: - chart: - spec: - chart: info - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - version: "*" - interval: 1m0s - timeout: 5m0s -{{- end }} + chartRef: + kind: ExternalArtifact + name: cozystack-info-application-default-info + namespace: cozy-system + interval: 5m + timeout: 10m + install: + remediation: + retries: -1 + upgrade: + force: true + remediation: + retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values diff --git a/packages/apps/tenant/templates/ingress.yaml b/packages/apps/tenant/templates/ingress.yaml index b93ae0fa..1899a4da 100644 --- a/packages/apps/tenant/templates/ingress.yaml +++ b/packages/apps/tenant/templates/ingress.yaml @@ -4,23 +4,29 @@ kind: HelmRelease metadata: name: ingress namespace: {{ include "tenant.name" . }} - annotations: - helm.sh/resource-policy: keep labels: - cozystack.io/ui: "true" + sharding.fluxcd.io/key: tenants + internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} + apps.cozystack.io/application.kind: Ingress + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: ingress spec: - chart: - spec: - chart: ingress - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - version: "*" - interval: 1m0s - timeout: 5m0s - values: {} + chartRef: + kind: ExternalArtifact + name: cozystack-ingress-application-default-ingress + namespace: cozy-system + interval: 5m + timeout: 10m + install: + remediation: + retries: -1 + upgrade: + force: true + remediation: + retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values {{- end }} diff --git a/packages/apps/tenant/templates/keycloakgroups.yaml b/packages/apps/tenant/templates/keycloakgroups.yaml index cd759eab..9e25e60d 100644 --- a/packages/apps/tenant/templates/keycloakgroups.yaml +++ b/packages/apps/tenant/templates/keycloakgroups.yaml @@ -1,6 +1,6 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} -{{- if $oidcEnabled }} +{{- $oidcEnabled := index .Values._cluster "oidc-enabled" }} +{{- if eq $oidcEnabled "true" }} +{{- if .Capabilities.APIVersions.Has "v1.edp.epam.com/v1" }} apiVersion: v1.edp.epam.com/v1 kind: KeycloakRealmGroup metadata: @@ -51,3 +51,4 @@ spec: name: keycloakrealm-cozy kind: ClusterKeycloakRealm {{- end }} +{{- end }} diff --git a/packages/apps/tenant/templates/monitoring.yaml b/packages/apps/tenant/templates/monitoring.yaml index e62cb507..4d77faa6 100644 --- a/packages/apps/tenant/templates/monitoring.yaml +++ b/packages/apps/tenant/templates/monitoring.yaml @@ -4,46 +4,29 @@ kind: HelmRelease metadata: name: monitoring namespace: {{ include "tenant.name" . }} - annotations: - helm.sh/resource-policy: keep labels: - cozystack.io/ui: "true" + sharding.fluxcd.io/key: tenants + internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} + apps.cozystack.io/application.kind: Monitoring + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: monitoring spec: - chart: - spec: - chart: monitoring - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - version: "*" - interval: 1m0s - timeout: 5m0s - values: - metricsStorages: - - name: shortterm - retentionPeriod: "3d" - deduplicationInterval: "15s" - storage: 10Gi - vminsert: - resources: {} - vmselect: - resources: {} - vmstorage: - resources: {} - - name: longterm - retentionPeriod: "14d" - deduplicationInterval: "5m" - storage: 10Gi - vminsert: - resources: {} - vmselect: - resources: {} - vmstorage: - resources: {} - oncall: - enabled: false + chartRef: + kind: ExternalArtifact + name: cozystack-monitoring-application-default-monitoring + namespace: cozy-system + interval: 5m + timeout: 10m + install: + remediation: + retries: -1 + upgrade: + force: true + remediation: + retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values {{- end }} diff --git a/packages/apps/tenant/templates/namespace.yaml b/packages/apps/tenant/templates/namespace.yaml index d97ebf42..dfb83730 100644 --- a/packages/apps/tenant/templates/namespace.yaml +++ b/packages/apps/tenant/templates/namespace.yaml @@ -1,46 +1,72 @@ -{{- define "cozystack.namespace-anotations" }} -{{- $context := index . 0 }} -{{- $existingNS := index . 1 }} -{{- range $x := list "etcd" "monitoring" "ingress" "seaweedfs" }} -{{- if (index $context.Values $x) }} -namespace.cozystack.io/{{ $x }}: "{{ include "tenant.name" $context }}" -{{- else }} -namespace.cozystack.io/{{ $x }}: "{{ index $existingNS.metadata.annotations (printf "namespace.cozystack.io/%s" $x) | required (printf "namespace %s has no namespace.cozystack.io/%s annotation" $context.Release.Namespace $x) }}" -{{- end }} -{{- end }} -{{- end }} - +{{/* Lookup for namespace uid (needed for ownerReferences) */}} {{- $existingNS := lookup "v1" "Namespace" "" .Release.Namespace }} {{- if not $existingNS }} {{- fail (printf "error lookup existing namespace: %s" .Release.Namespace) }} {{- end }} {{- if ne (include "tenant.name" .) "tenant-root" }} +{{/* Compute namespace values once for use in both Secret and labels */}} +{{- $tenantName := include "tenant.name" . }} +{{- $parentNamespace := .Values._namespace | default dict }} +{{- $parentHost := $parentNamespace.host | default "" }} + +{{/* Compute host */}} +{{- $computedHost := "" }} +{{- if .Values.host }} +{{- $computedHost = .Values.host }} +{{- else if $parentHost }} +{{- $computedHost = printf "%s.%s" (splitList "-" $tenantName | last) $parentHost }} +{{- end }} + +{{/* Compute service references */}} +{{- $etcd := $parentNamespace.etcd | default "" }} +{{- if .Values.etcd }} +{{- $etcd = $tenantName }} +{{- end }} + +{{- $ingress := $parentNamespace.ingress | default "" }} +{{- if .Values.ingress }} +{{- $ingress = $tenantName }} +{{- end }} + +{{- $monitoring := $parentNamespace.monitoring | default "" }} +{{- if .Values.monitoring }} +{{- $monitoring = $tenantName }} +{{- end }} + +{{- $seaweedfs := $parentNamespace.seaweedfs | default "" }} +{{- if .Values.seaweedfs }} +{{- $seaweedfs = $tenantName }} +{{- end }} + +{{/* SchedulingClass: inherited from parent, can be set if parent has none */}} +{{- $schedulingClass := $parentNamespace.schedulingClass | default "" }} +{{- if and (not $schedulingClass) .Values.schedulingClass }} +{{- $schedulingClass = .Values.schedulingClass }} +{{- end }} --- apiVersion: v1 kind: Namespace metadata: - name: {{ include "tenant.name" . }} + name: {{ $tenantName }} {{- if hasPrefix "tenant-" .Release.Namespace }} - annotations: - {{- if .Values.host }} - namespace.cozystack.io/host: "{{ .Values.host }}" - {{- else }} - {{ $parentHost := index $existingNS.metadata.annotations "namespace.cozystack.io/host" | required (printf "namespace %s has no namespace.cozystack.io/host annotation" .Release.Namespace) }} - namespace.cozystack.io/host: "{{ splitList "-" (include "tenant.name" .) | last }}.{{ $parentHost }}" - {{- end }} - {{- include "cozystack.namespace-anotations" (list . $existingNS) | nindent 4 }} labels: - tenant.cozystack.io/{{ include "tenant.name" $ }}: "" - {{- if hasPrefix "tenant-" .Release.Namespace }} + tenant.cozystack.io/{{ $tenantName }}: "" {{- $parts := splitList "-" .Release.Namespace }} {{- range $i, $v := $parts }} {{- if ne $i 0 }} tenant.cozystack.io/{{ join "-" (slice $parts 0 (add $i 1)) }}: "" {{- end }} {{- end }} + {{/* Labels for network policies */}} + namespace.cozystack.io/etcd: {{ $etcd | quote }} + namespace.cozystack.io/ingress: {{ $ingress | quote }} + namespace.cozystack.io/monitoring: {{ $monitoring | quote }} + namespace.cozystack.io/seaweedfs: {{ $seaweedfs | quote }} + namespace.cozystack.io/host: {{ $computedHost | quote }} + {{- with $schedulingClass }} + scheduler.cozystack.io/scheduling-class: {{ . | quote }} {{- end }} - {{- include "cozystack.namespace-anotations" (list $ $existingNS) | nindent 4 }} alpha.kubevirt.io/auto-memory-limits-ratio: "1.0" ownerReferences: - apiVersion: v1 @@ -50,4 +76,26 @@ metadata: name: {{ .Release.Namespace }} uid: {{ $existingNS.metadata.uid }} {{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: cozystack-values + namespace: {{ $tenantName }} + labels: + reconcile.fluxcd.io/watch: Enabled +type: Opaque +stringData: + values.yaml: | + _cluster: + {{- .Values._cluster | toYaml | nindent 6 }} + _namespace: + etcd: {{ $etcd | quote }} + ingress: {{ $ingress | quote }} + monitoring: {{ $monitoring | quote }} + seaweedfs: {{ $seaweedfs | quote }} + host: {{ $computedHost | quote }} + {{- with $schedulingClass }} + schedulingClass: {{ . | quote }} + {{- end }} {{- end }} diff --git a/packages/apps/tenant/templates/networkpolicy.yaml b/packages/apps/tenant/templates/networkpolicy.yaml index 6d80f996..4bd3ba02 100644 --- a/packages/apps/tenant/templates/networkpolicy.yaml +++ b/packages/apps/tenant/templates/networkpolicy.yaml @@ -1,4 +1,3 @@ -{{- if .Values.isolated }} --- apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy @@ -48,6 +47,33 @@ spec: {{- range $i, $v := $parts }} {{- if ne $i 0 }} - matchLabels: + "k8s:app.kubernetes.io/name": "vminsert" + "k8s:io.kubernetes.pod.namespace": {{ join "-" (slice $parts 0 (add $i 1)) }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if ne (include "tenant.name" .) "tenant-root" }} + - toEndpoints: + {{- if hasPrefix "tenant-" .Release.Namespace }} + {{- $parts := splitList "-" .Release.Namespace }} + {{- range $i, $v := $parts }} + {{- if ne $i 0 }} + - matchLabels: + "k8s:app.kubernetes.io/instance": "etcd" + "k8s:io.kubernetes.pod.namespace": {{ join "-" (slice $parts 0 (add $i 1)) }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if ne (include "tenant.name" .) "tenant-root" }} + - toEndpoints: + {{- if hasPrefix "tenant-" .Release.Namespace }} + {{- $parts := splitList "-" .Release.Namespace }} + {{- range $i, $v := $parts }} + {{- if ne $i 0 }} + - matchLabels: + cozystack.io/service: ingress "k8s:io.kubernetes.pod.namespace": {{ join "-" (slice $parts 0 (add $i 1)) }} {{- end }} {{- end }} @@ -160,6 +186,23 @@ spec: --- apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy +metadata: + # Allow the tenant's ingress-nginx to reach both the linstor-gui + # gatekeeper pods (for /oauth2/* and app traffic) AND the transient + # ACME http-01 solver pods that cert-manager spins up in the same + # namespace during certificate issuance/renewal. Matching the whole + # namespace mirrors allow-to-dashboard / allow-to-keycloak. + name: allow-to-linstor-gui + namespace: {{ include "tenant.name" . }} +spec: + endpointSelector: {} + egress: + - toEndpoints: + - matchLabels: + "k8s:io.kubernetes.pod.namespace": cozy-linstor +--- +apiVersion: cilium.io/v2 +kind: CiliumNetworkPolicy metadata: name: allow-to-keycloak namespace: {{ include "tenant.name" . }} @@ -181,6 +224,27 @@ spec: - toEndpoints: - matchLabels: "k8s:io.kubernetes.pod.namespace": cozy-kubevirt-cdi +{{- if .Values.monitoring }} +--- +apiVersion: cilium.io/v2 +kind: CiliumClusterwideNetworkPolicy +metadata: + name: {{ include "tenant.name" . }}-egress-virt-handler +spec: + endpointSelector: + matchLabels: + "k8s:io.kubernetes.pod.namespace": "{{ include "tenant.name" . }}" + "k8s:app.kubernetes.io/name": "vmagent" + egress: + - toEndpoints: + - matchLabels: + "k8s:kubevirt.io": "virt-handler" + "k8s:io.kubernetes.pod.namespace": "cozy-kubevirt" + toPorts: + - ports: + - port: "8443" + protocol: TCP +{{- end }} --- apiVersion: cilium.io/v2 kind: CiliumNetworkPolicy @@ -193,4 +257,3 @@ spec: - toEndpoints: - matchLabels: cozystack.io/service: ingress -{{- end }} diff --git a/packages/apps/tenant/templates/quota.yaml b/packages/apps/tenant/templates/quota.yaml index 43941f56..6962d7c3 100644 --- a/packages/apps/tenant/templates/quota.yaml +++ b/packages/apps/tenant/templates/quota.yaml @@ -7,4 +7,21 @@ metadata: spec: hard: {{- include "cozy-lib.resources.flatten" (list .Values.resourceQuotas $) | nindent 6 }} +--- +apiVersion: v1 +kind: LimitRange +metadata: + name: tenant-range-limits + namespace: {{ include "tenant.name" . }} +spec: + limits: + - default: + cpu: "250m" + memory: "128Mi" + ephemeral-storage: "2Gi" + defaultRequest: + cpu: "25m" + memory: "128Mi" + ephemeral-storage: "50Mi" + type: Container {{- end }} diff --git a/packages/apps/tenant/templates/seaweedfs.yaml b/packages/apps/tenant/templates/seaweedfs.yaml index 5741d930..e0002ec9 100644 --- a/packages/apps/tenant/templates/seaweedfs.yaml +++ b/packages/apps/tenant/templates/seaweedfs.yaml @@ -4,22 +4,29 @@ kind: HelmRelease metadata: name: seaweedfs namespace: {{ include "tenant.name" . }} - annotations: - helm.sh/resource-policy: keep labels: - cozystack.io/ui: "true" + sharding.fluxcd.io/key: tenants + internal.cozystack.io/tenantmodule: "true" app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: {{ .Release.Service }} + apps.cozystack.io/application.kind: SeaweedFS + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: seaweedfs spec: - chart: - spec: - chart: seaweedfs - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - version: "*" - interval: 1m0s - timeout: 5m0s + chartRef: + kind: ExternalArtifact + name: cozystack-seaweedfs-application-default-seaweedfs + namespace: cozy-system + interval: 5m + timeout: 10m + install: + remediation: + retries: -1 + upgrade: + force: true + remediation: + retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values {{- end }} diff --git a/packages/apps/tenant/templates/tenant.yaml b/packages/apps/tenant/templates/tenant.yaml index b1724376..79eba4ca 100644 --- a/packages/apps/tenant/templates/tenant.yaml +++ b/packages/apps/tenant/templates/tenant.yaml @@ -5,45 +5,10 @@ metadata: name: {{ include "tenant.name" . }} namespace: {{ include "tenant.name" . }} --- -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "tenant.name" . }} - namespace: {{ include "tenant.name" . }} - annotations: - kubernetes.io/service-account.name: {{ include "tenant.name" . }} -type: kubernetes.io/service-account-token ---- -# == default role == ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: {{ include "tenant.name" . }} - namespace: {{ include "tenant.name" . }} -rules: -- apiGroups: [""] - resources: ["pods", "services", "persistentvolumes", "endpoints", "events", "resourcequotas"] - verbs: ["get", "list", "watch"] -- apiGroups: ["networking.k8s.io"] - resources: ["ingresses"] - verbs: ["get", "list", "watch"] -- apiGroups: ["rbac.authorization.k8s.io"] - resources: ["roles"] - verbs: ["get"] -- apiGroups: ["apps.cozystack.io"] - resources: ['*'] - verbs: ['*'] -- apiGroups: - - cozystack.io - resources: - - workloadmonitors - verbs: ["get", "list", "watch"] ---- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: {{ include "tenant.name" . }} + name: cozy:tenant namespace: {{ include "tenant.name" . }} subjects: {{- if ne .Release.Namespace "tenant-root" }} @@ -65,319 +30,67 @@ subjects: name: {{ include "tenant.name" . }} namespace: {{ include "tenant.name" . }} roleRef: - kind: Role - name: {{ include "tenant.name" . }} + kind: ClusterRole + name: cozy:tenant apiGroup: rbac.authorization.k8s.io --- -# == view role == ---- -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ include "tenant.name" . }}-view - namespace: {{ include "tenant.name" . }} -rules: - - apiGroups: - - rbac.authorization.k8s.io - resources: - - roles - verbs: - - get - - apiGroups: - - apps.cozystack.io - resources: - - "*" - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - pods - - services - - persistentvolumes - - endpoints - - events - - resourcequotas - verbs: - - get - - list - - watch - - apiGroups: - - networking.k8s.io - resources: - - ingresses - verbs: - - get - - list - - watch - - apiGroups: - - cozystack.io - resources: - - workloadmonitors - verbs: ["get", "list", "watch"] ---- +# == view role binding == kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: {{ include "tenant.name" . }}-view + name: cozy:tenant:view namespace: {{ include "tenant.name" . }} subjects: -{{ include "cozy-lib.rbac.subjectsForTenant" (list "view" (include "tenant.name" .)) | nindent 2 }} +{{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "view" (include "tenant.name" .)) | nindent 2 }} roleRef: - kind: Role - name: {{ include "tenant.name" . }}-view + kind: ClusterRole + name: cozy:tenant:view apiGroup: rbac.authorization.k8s.io - ---- -# == use role == ---- -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ include "tenant.name" . }}-use - namespace: {{ include "tenant.name" . }} -rules: - - apiGroups: [rbac.authorization.k8s.io] - resources: - - roles - verbs: - - get - - apiGroups: ["apps.cozystack.io"] - resources: - - "*" - verbs: - - get - - list - - watch - - apiGroups: [""] - resources: - - pods - - services - - persistentvolumes - - endpoints - - events - - resourcequotas - verbs: - - get - - list - - watch - - apiGroups: ["networking.k8s.io"] - resources: - - ingresses - verbs: - - get - - list - - watch - - apiGroups: ["subresources.kubevirt.io"] - resources: - - virtualmachineinstances/console - - virtualmachineinstances/vnc - verbs: - - get - - list - - apiGroups: ["subresources.kubevirt.io"] - resources: - - virtualmachineinstances/portforward - verbs: - - get - - update - - apiGroups: - - cozystack.io - resources: - - workloadmonitors - verbs: ["get", "list", "watch"] --- +# == use role binding == kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: {{ include "tenant.name" . }}-use + name: cozy:tenant:use namespace: {{ include "tenant.name" . }} subjects: -{{ include "cozy-lib.rbac.subjectsForTenant" (list "use" (include "tenant.name" .)) | nindent 2 }} +{{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "use" (include "tenant.name" .)) | nindent 2 }} roleRef: - kind: Role - name: {{ include "tenant.name" . }}-use + kind: ClusterRole + name: cozy:tenant:use apiGroup: rbac.authorization.k8s.io --- -# == admin role == ---- -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ include "tenant.name" . }}-admin - namespace: {{ include "tenant.name" . }} -rules: - - apiGroups: [rbac.authorization.k8s.io] - resources: - - roles - verbs: - - get - - apiGroups: [""] - resources: - - pods - - services - - persistentvolumes - - endpoints - - events - - resourcequotas - verbs: - - get - - list - - watch - - delete - - apiGroups: ["kubevirt.io"] - resources: - - virtualmachines - verbs: - - get - - list - - apiGroups: ["subresources.kubevirt.io"] - resources: - - virtualmachineinstances/console - - virtualmachineinstances/vnc - verbs: - - get - - list - - apiGroups: ["subresources.kubevirt.io"] - resources: - - virtualmachineinstances/portforward - verbs: - - get - - update - - apiGroups: ["apps.cozystack.io"] - resources: - - buckets - - clickhouses - - ferretdb - - foos - - httpcaches - - kafkas - - kuberneteses - - mysqls - - natses - - postgreses - - rabbitmqs - - redises - - seaweedfses - - tcpbalancers - - virtualmachines - - vmdisks - - vminstances - - infos - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - cozystack.io - resources: - - workloadmonitors - verbs: ["get", "list", "watch"] ---- +# == admin role binding == kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: {{ include "tenant.name" . }}-admin + name: cozy:tenant:admin namespace: {{ include "tenant.name" . }} subjects: -{{ include "cozy-lib.rbac.subjectsForTenant" (list "admin" (include "tenant.name" .)) | nindent 2 }} +{{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "admin" (include "tenant.name" .)) | nindent 2 }} roleRef: - kind: Role - name: {{ include "tenant.name" . }}-admin + kind: ClusterRole + name: cozy:tenant:admin apiGroup: rbac.authorization.k8s.io --- -# == super admin role == ---- -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: {{ include "tenant.name" . }}-super-admin - namespace: {{ include "tenant.name" . }} -rules: - - apiGroups: [rbac.authorization.k8s.io] - resources: - - roles - verbs: - - get - - apiGroups: [""] - resources: - - pods - - services - - persistentvolumes - - endpoints - - events - - resourcequotas - verbs: - - get - - list - - watch - - delete - - apiGroups: ["kubevirt.io"] - resources: - - virtualmachines - verbs: - - '*' - - apiGroups: ["subresources.kubevirt.io"] - resources: - - virtualmachineinstances/console - - virtualmachineinstances/vnc - verbs: - - get - - list - - apiGroups: ["subresources.kubevirt.io"] - resources: - - virtualmachineinstances/portforward - verbs: - - get - - update - - apiGroups: ["apps.cozystack.io"] - resources: - - '*' - verbs: - - '*' - - apiGroups: - - cozystack.io - resources: - - workloadmonitors - verbs: ["get", "list", "watch"] ---- +# == super admin role binding == kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: - name: {{ include "tenant.name" . }}-super-admin + name: cozy:tenant:super-admin namespace: {{ include "tenant.name" . }} subjects: -{{ include "cozy-lib.rbac.subjectsForTenant" (list "super-admin" (include "tenant.name" .) ) | nindent 2 }} +{{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "super-admin" (include "tenant.name" .) ) | nindent 2 }} roleRef: - kind: Role - name: {{ include "tenant.name" . }}-super-admin + kind: ClusterRole + name: cozy:tenant:super-admin apiGroup: rbac.authorization.k8s.io --- -# == dashboard role == ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: {{ include "tenant.name" . }} - namespace: cozy-public -rules: -- apiGroups: ["source.toolkit.fluxcd.io"] - resources: ["helmrepositories"] - verbs: ["get", "list"] -- apiGroups: ["source.toolkit.fluxcd.io"] - resources: ["helmcharts"] - verbs: ["get", "list"] ---- +# == dashboard role binding == apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: {{ include "tenant.name" . }} + name: cozy:{{ include "tenant.name" . }}:dashboard namespace: cozy-public subjects: - kind: Group @@ -397,5 +110,5 @@ subjects: namespace: {{ include "tenant.name" . }} roleRef: kind: Role - name: {{ include "tenant.name" . }} + name: cozy:tenant:dashboard apiGroup: rbac.authorization.k8s.io diff --git a/packages/apps/tenant/tests/exposure_test.yaml b/packages/apps/tenant/tests/exposure_test.yaml new file mode 100644 index 00000000..e86fab5b --- /dev/null +++ b/packages/apps/tenant/tests/exposure_test.yaml @@ -0,0 +1,141 @@ +suite: tenant CiliumLoadBalancerIPPool rendering for publishing.exposure=loadBalancer +templates: + - templates/cilium-lb-pool.yaml + +release: + name: tenant-root + namespace: tenant-root + +tests: + - it: default exposure (externalIPs) renders no pool + set: + ingress: true + _cluster: + expose-ingress: tenant-root + expose-external-ips: "192.0.2.10,192.0.2.11" + asserts: + - hasDocuments: + count: 0 + + - it: loadBalancer mode in publishing tenant with ingress=true renders v2 pool with namespace-only selector + set: + ingress: true + _cluster: + expose-ingress: tenant-root + expose-external-ips: "192.0.2.10,192.0.2.11" + expose-mode: loadBalancer + asserts: + - hasDocuments: + count: 1 + - equal: + path: apiVersion + value: cilium.io/v2 + - equal: + path: kind + value: CiliumLoadBalancerIPPool + - equal: + path: metadata.name + value: root-exposure + - equal: + path: spec.blocks + value: + - cidr: 192.0.2.10/32 + - cidr: 192.0.2.11/32 + - equal: + path: spec.serviceSelector.matchLabels["io.kubernetes.service.namespace"] + value: tenant-root + - notExists: + path: spec.serviceSelector.matchLabels["app.kubernetes.io/name"] + + - it: loadBalancer mode with IPv6 emits /128 CIDR + set: + ingress: true + _cluster: + expose-ingress: tenant-root + expose-external-ips: "2001:db8::1" + expose-mode: loadBalancer + asserts: + - equal: + path: spec.blocks + value: + - cidr: 2001:db8::1/128 + + - it: loadBalancer mode with mixed IPv4 and IPv6 emits correct CIDR per family + set: + ingress: true + _cluster: + expose-ingress: tenant-root + expose-external-ips: "192.0.2.10,2001:db8::1" + expose-mode: loadBalancer + asserts: + - equal: + path: spec.blocks + value: + - cidr: 192.0.2.10/32 + - cidr: 2001:db8::1/128 + + - it: loadBalancer mode accepts pre-CIDR input without double-suffixing + set: + ingress: true + _cluster: + expose-ingress: tenant-root + expose-external-ips: "192.0.2.10/32,2001:db8::1/128" + expose-mode: loadBalancer + asserts: + - equal: + path: spec.blocks + value: + - cidr: 192.0.2.10/32 + - cidr: 2001:db8::1/128 + + - it: loadBalancer mode filters out empty entries from externalIPs (trailing, leading, repeated commas) + set: + ingress: true + _cluster: + expose-ingress: tenant-root + expose-external-ips: "192.0.2.10,,192.0.2.11," + expose-mode: loadBalancer + asserts: + - hasDocuments: + count: 1 + - equal: + path: spec.blocks + value: + - cidr: 192.0.2.10/32 + - cidr: 192.0.2.11/32 + + - it: loadBalancer mode with ingress=false in publishing tenant renders no pool + set: + ingress: false + _cluster: + expose-ingress: tenant-root + expose-external-ips: "192.0.2.10" + expose-mode: loadBalancer + asserts: + - hasDocuments: + count: 0 + + - it: loadBalancer mode in a non-publishing tenant renders no pool + set: + ingress: true + _cluster: + expose-ingress: tenant-root + expose-external-ips: "192.0.2.10" + expose-mode: loadBalancer + release: + name: tenant-u1 + namespace: tenant-u1 + asserts: + - hasDocuments: + count: 0 + + - it: loadBalancer mode in publishing tenant with empty externalIPs renders no pool + set: + ingress: true + _cluster: + expose-ingress: tenant-root + expose-external-ips: "" + expose-mode: loadBalancer + asserts: + - hasDocuments: + count: 0 diff --git a/packages/apps/tenant/values.schema.json b/packages/apps/tenant/values.schema.json index 8ffe458f..28d9ac1e 100644 --- a/packages/apps/tenant/values.schema.json +++ b/packages/apps/tenant/values.schema.json @@ -1,41 +1,53 @@ { - "title": "Chart Values", - "type": "object", - "properties": { - "host": { - "type": "string", - "description": "The hostname used to access tenant services (defaults to using the tenant name as a subdomain for it's parent tenant host).", - "default": "" - }, - "etcd": { - "type": "boolean", - "description": "Deploy own Etcd cluster", - "default": false - }, - "monitoring": { - "type": "boolean", - "description": "Deploy own Monitoring Stack", - "default": false - }, - "ingress": { - "type": "boolean", - "description": "Deploy own Ingress Controller", - "default": false - }, - "seaweedfs": { - "type": "boolean", - "description": "Deploy own SeaweedFS", - "default": false - }, - "isolated": { - "type": "boolean", - "description": "Enforce tenant namespace with network policies", - "default": true - }, - "resourceQuotas": { - "type": "object", - "description": "Define resource quotas for the tenant", - "default": {} - } + "title": "Chart Values", + "type": "object", + "properties": { + "host": { + "description": "The hostname used to access tenant services (defaults to using the tenant name as a subdomain for its parent tenant host).", + "type": "string", + "default": "" + }, + "etcd": { + "description": "Deploy own Etcd cluster.", + "type": "boolean", + "default": false + }, + "monitoring": { + "description": "Deploy own Monitoring Stack.", + "type": "boolean", + "default": false + }, + "ingress": { + "description": "Deploy own Ingress Controller.", + "type": "boolean", + "default": false + }, + "seaweedfs": { + "description": "Deploy own SeaweedFS.", + "type": "boolean", + "default": false + }, + "schedulingClass": { + "description": "The name of a SchedulingClass CR to apply scheduling constraints for this tenant's workloads.", + "type": "string", + "default": "" + }, + "resourceQuotas": { + "description": "Define resource quotas for the tenant.", + "type": "object", + "default": {}, + "additionalProperties": { + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } } -} \ No newline at end of file + } +} diff --git a/packages/apps/tenant/values.yaml b/packages/apps/tenant/values.yaml index 7c64b278..f9f8a999 100644 --- a/packages/apps/tenant/values.yaml +++ b/packages/apps/tenant/values.yaml @@ -1,21 +1,24 @@ +## ## @section Common parameters +## -## @param host The hostname used to access tenant services (defaults to using the tenant name as a subdomain for it's parent tenant host). -## @param etcd Deploy own Etcd cluster -## @param monitoring Deploy own Monitoring Stack -## @param ingress Deploy own Ingress Controller -## @param seaweedfs Deploy own SeaweedFS -## @param isolated Enforce tenant namespace with network policies -## @param resourceQuotas Define resource quotas for the tenant +## @param {string} [host] - The hostname used to access tenant services (defaults to using the tenant name as a subdomain for its parent tenant host). host: "" + +## @param {bool} etcd - Deploy own Etcd cluster. etcd: false + +## @param {bool} monitoring - Deploy own Monitoring Stack. monitoring: false + +## @param {bool} ingress - Deploy own Ingress Controller. ingress: false + +## @param {bool} seaweedfs - Deploy own SeaweedFS. seaweedfs: false -isolated: true + +## @param {string} [schedulingClass] - The name of a SchedulingClass CR to apply scheduling constraints for this tenant's workloads. +schedulingClass: "" + +## @param {map[string]quantity} resourceQuotas - Define resource quotas for the tenant. resourceQuotas: {} -# resourceQuotas: -# cpu: "1" -# memory: "1Gi" -# nvidia.com/gpu: 4 -# storage: 100Gi diff --git a/packages/apps/versions_map b/packages/apps/versions_map deleted file mode 100644 index cefbae21..00000000 --- a/packages/apps/versions_map +++ /dev/null @@ -1,189 +0,0 @@ -bucket 0.1.0 632224a3 -bucket 0.2.0 HEAD -clickhouse 0.1.0 f7eaab0a -clickhouse 0.2.0 53f2365e -clickhouse 0.2.1 dfbc210b -clickhouse 0.3.0 6c5cf5bf -clickhouse 0.4.0 b40e1b09 -clickhouse 0.5.0 0f312d5c -clickhouse 0.6.0 1ec10165 -clickhouse 0.6.1 c62a83a7 -clickhouse 0.6.2 8267072d -clickhouse 0.7.0 93bdf411 -clickhouse 0.9.0 6130f43d -clickhouse 0.9.2 632224a3 -clickhouse 0.10.0 6358fd7a -clickhouse 0.10.1 4369b031 -clickhouse 0.11.0 HEAD -ferretdb 0.1.0 e9716091 -ferretdb 0.1.1 91b0499a -ferretdb 0.2.0 6c5cf5bf -ferretdb 0.3.0 b8e33d19 -ferretdb 0.4.0 b40e1b09 -ferretdb 0.4.1 1ec10165 -ferretdb 0.4.2 8267072d -ferretdb 0.5.0 93bdf411 -ferretdb 0.6.0 6130f43d -ferretdb 0.6.1 632224a3 -ferretdb 0.7.0 62cb694d -ferretdb 0.7.1 4369b031 -ferretdb 0.8.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 93bdf411 -http-cache 0.5.0 6130f43d -http-cache 0.5.1 62cb694d -http-cache 0.5.2 4369b031 -http-cache 0.6.0 HEAD -kafka 0.1.0 f7eaab0a -kafka 0.2.0 c0685f43 -kafka 0.2.1 dfbc210b -kafka 0.2.2 e9716091 -kafka 0.2.3 91b0499a -kafka 0.3.0 6c5cf5bf -kafka 0.3.1 c62a83a7 -kafka 0.3.2 93c46161 -kafka 0.3.3 8267072d -kafka 0.4.0 85ec09b8 -kafka 0.5.0 93bdf411 -kafka 0.6.0 6130f43d -kafka 0.6.1 632224a3 -kafka 0.7.0 6358fd7a -kafka 0.7.1 4369b031 -kafka 0.8.0 HEAD -kubernetes 0.24.0 62cb694d -kubernetes 0.25.0 70f82667 -kubernetes 0.25.1 acd4663a -kubernetes 0.25.2 HEAD -mysql 0.1.0 263e47be -mysql 0.2.0 c24a103f -mysql 0.3.0 53f2365e -mysql 0.4.0 6c5cf5bf -mysql 0.5.0 b40e1b09 -mysql 0.5.1 0f312d5c -mysql 0.5.2 1ec10165 -mysql 0.5.3 8267072d -mysql 0.6.0 93bdf411 -mysql 0.7.0 6130f43d -mysql 0.7.1 632224a3 -mysql 0.8.0 62cb694d -mysql 0.8.1 4369b031 -mysql 0.9.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 93bdf411 -nats 0.6.0 6130f43d -nats 0.6.1 632224a3 -nats 0.7.0 62cb694d -nats 0.7.1 4369b031 -nats 0.8.0 HEAD -postgres 0.1.0 263e47be -postgres 0.2.0 53f2365e -postgres 0.2.1 d7cfa53c -postgres 0.3.0 dfbc210b -postgres 0.4.0 e9716091 -postgres 0.4.1 91b0499a -postgres 0.5.0 6c5cf5bf -postgres 0.6.0 b40e1b09 -postgres 0.6.2 0f312d5c -postgres 0.7.0 4b90bf5a -postgres 0.7.1 1ec10165 -postgres 0.8.0 4e68e65c -postgres 0.9.0 8267072d -postgres 0.10.0 721c12a7 -postgres 0.10.1 93bdf411 -postgres 0.11.0 f9f8bb2f -postgres 0.12.0 6130f43d -postgres 0.12.1 632224a3 -postgres 0.14.0 62cb694d -postgres 0.15.1 4369b031 -postgres 0.16.0 70f82667 -postgres 0.17.0 acd4663a -postgres 0.17.1 HEAD -rabbitmq 0.1.0 263e47be -rabbitmq 0.2.0 53f2365e -rabbitmq 0.3.0 6c5cf5bf -rabbitmq 0.4.0 b40e1b09 -rabbitmq 0.4.1 1128d0cb -rabbitmq 0.4.2 4b90bf5a -rabbitmq 0.4.3 1ec10165 -rabbitmq 0.4.4 8267072d -rabbitmq 0.5.0 93bdf411 -rabbitmq 0.6.0 632224a3 -rabbitmq 0.7.0 62cb694d -rabbitmq 0.7.1 4369b031 -rabbitmq 0.8.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 93bdf411 -redis 0.7.0 6130f43d -redis 0.7.1 632224a3 -redis 0.8.0 62cb694d -redis 0.8.1 4369b031 -redis 0.9.0 HEAD -tcp-balancer 0.1.0 263e47be -tcp-balancer 0.2.0 53f2365e -tcp-balancer 0.3.0 93bdf411 -tcp-balancer 0.4.0 6130f43d -tcp-balancer 0.4.1 62cb694d -tcp-balancer 0.4.2 4369b031 -tcp-balancer 0.5.0 HEAD -tenant 1.10.0 4369b031 -tenant 1.11.0 HEAD -virtual-machine 0.1.4 f2015d65 -virtual-machine 0.1.5 263e47be -virtual-machine 0.2.0 c0685f43 -virtual-machine 0.3.0 6c5cf5bf -virtual-machine 0.4.0 b8e33d19 -virtual-machine 0.5.0 1ec10165 -virtual-machine 0.6.0 4e68e65c -virtual-machine 0.7.0 e23286a3 -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 721c12a7 -virtual-machine 0.9.1 93bdf411 -virtual-machine 0.10.0 6130f43d -virtual-machine 0.10.2 632224a3 -virtual-machine 0.11.0 4369b031 -virtual-machine 0.12.0 70f82667 -virtual-machine 0.12.1 HEAD -vm-disk 0.1.0 d971f2ff -vm-disk 0.1.1 6130f43d -vm-disk 0.1.2 632224a3 -vm-disk 0.2.0 4369b031 -vm-disk 0.3.0 HEAD -vm-instance 0.1.0 1ec10165 -vm-instance 0.2.0 84f3ccc0 -vm-instance 0.3.0 4e68e65c -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 721c12a7 -vm-instance 0.7.0 6130f43d -vm-instance 0.7.2 632224a3 -vm-instance 0.8.0 4369b031 -vm-instance 0.9.0 70f82667 -vm-instance 0.10.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 93bdf411 -vpn 0.5.0 6130f43d -vpn 0.5.1 632224a3 -vpn 0.6.1 62cb694d -vpn 0.6.2 4369b031 -vpn 0.7.0 HEAD diff --git a/packages/apps/virtual-machine/Makefile b/packages/apps/virtual-machine/Makefile deleted file mode 100644 index 5d31cacf..00000000 --- a/packages/apps/virtual-machine/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include ../../../scripts/package.mk - -generate: - readme-generator -v values.yaml -s values.schema.json -r README.md - yq -o json -i '.properties.gpus.items.type = "object" | .properties.gpus.default = []' values.schema.json - INSTANCE_TYPES=$$(yq e '.metadata.name' -o=json -r ../../system/kubevirt-instancetypes/templates/instancetypes.yaml | yq 'split(" ") | . + [""]' -o json) \ - && yq -i -o json ".properties.instanceType.optional=true | .properties.instanceType.enum = $${INSTANCE_TYPES}" values.schema.json - 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.systemDisk.properties.image.enum = ["ubuntu", "cirros", "alpine", "fedora", "talos"]' 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 deleted file mode 100644 index a1a89bdc..00000000 --- a/packages/apps/virtual-machine/README.md +++ /dev/null @@ -1,271 +0,0 @@ -# Virtual Machine (simple) - -A Virtual Machine (VM) simulates computer hardware, enabling various operating systems and applications to run in an isolated environment. - -## Deployment Details - -The virtual machine is managed and hosted through KubeVirt, allowing you to harness the benefits of virtualization within your Kubernetes ecosystem. - -- Docs: [KubeVirt User Guide](https://kubevirt.io/user-guide/) -- GitHub: [KubeVirt Repository](https://github.com/kubevirt/kubevirt) - -## Accessing virtual machine - -You can access the virtual machine using the virtctl tool: -- [KubeVirt User Guide - Virtctl Client Tool](https://kubevirt.io/user-guide/user_workloads/virtctl_client_tool/) - -To access the serial console: - -``` -virtctl console -``` - -To access the VM using VNC: - -``` -virtctl vnc -``` - -To SSH into the VM: - -``` -virtctl ssh @ -``` - -## Parameters - -### Common parameters - -| 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` | `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` | -| `instanceProfile` | Virtual Machine preferences profile | `ubuntu` | -| `systemDisk.image` | The base image for the virtual machine. Allowed values: `ubuntu`, `cirros`, `alpine`, `fedora` and `talos` | `ubuntu` | -| `systemDisk.storage` | The size of the disk allocated for the virtual machine | `5Gi` | -| `systemDisk.storageClass` | StorageClass used to store the data | `replicated` | -| `gpus` | List of GPUs to attach | `[]` | -| `resources.cpu` | The number of CPU cores allocated to the virtual machine | `""` | -| `resources.memory` | The amount of memory allocated to the virtual machine | `""` | -| `resources.sockets` | The number of CPU sockets allocated to the virtual machine (used to define vCPU topology) | `""` | -| `sshKeys` | List of SSH public keys for authentication. Can be a single key or a list of keys. | `[]` | -| `cloudInit` | cloud-init user data config. See cloud-init documentation for more details. | `""` | -| `cloudInitSeed` | A seed string to generate an SMBIOS UUID for the VM. | `""` | - -## U Series - -The U Series is quite neutral and provides resources for -general purpose applications. - -*U* is the abbreviation for "Universal", hinting at the universal -attitude towards workloads. - -VMs of instance types will share physical CPU cores on a -time-slice basis with other VMs. - -### U Series Characteristics - -Specific characteristics of this series are: -- *Burstable CPU performance* - The workload has a baseline compute - performance but is permitted to burst beyond this baseline, if - excess compute resources are available. -- *vCPU-To-Memory Ratio (1:4)* - A vCPU-to-Memory ratio of 1:4, for less - noise per node. - -## O Series - -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 - -Specific characteristics of this series are: -- *Burstable CPU performance* - The workload has a baseline compute - performance but is permitted to burst beyond this baseline, if - excess compute resources are available. -- *Overcommitted Memory* - Memory is over-committed in order to achieve - a higher workload density. -- *vCPU-To-Memory Ratio (1:4)* - A vCPU-to-Memory ratio of 1:4, for less - noise per node. - -## CX Series - -The CX Series provides exclusive compute resources for compute -intensive applications. - -*CX* is the abbreviation of "Compute Exclusive". - -The exclusive resources are given to the compute threads of the -VM. In order to ensure this, some additional cores (depending -on the number of disks and NICs) will be requested to offload -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 - -Specific characteristics of this series are: -- *Hugepages* - Hugepages are used in order to improve memory - performance. -- *Dedicated CPU* - Physical cores are exclusively assigned to every - vCPU in order to provide fixed and high compute guarantees to the - workload. -- *Isolated emulator threads* - Hypervisor emulator threads are isolated - from the vCPUs in order to reduce emaulation related impact on the - workload. -- *vNUMA* - Physical NUMA topology is reflected in the guest in order to - optimize guest sided cache utilization. -- *vCPU-To-Memory Ratio (1:2)* - A vCPU-to-Memory ratio of 1:2. - -## M Series - -The M Series provides resources for memory intensive -applications. - -*M* is the abbreviation of "Memory". - -### M Series Characteristics - -Specific characteristics of this series are: -- *Hugepages* - Hugepages are used in order to improve memory - performance. -- *Burstable CPU performance* - The workload has a baseline compute - performance but is permitted to burst beyond this baseline, if - excess compute resources are available. -- *vCPU-To-Memory Ratio (1:8)* - A vCPU-to-Memory ratio of 1:8, for much - less noise per node. - -## RT Series - -The RT Series provides resources for realtime applications, like Oslat. - -*RT* is the abbreviation for "realtime". - -This series of instance types requires nodes capable of running -realtime applications. - -### RT Series Characteristics - -Specific characteristics of this series are: -- *Hugepages* - Hugepages are used in order to improve memory - performance. -- *Dedicated CPU* - Physical cores are exclusively assigned to every - vCPU in order to provide fixed and high compute guarantees to the - workload. -- *Isolated emulator threads* - Hypervisor emulator threads are isolated - from the vCPUs in order to reduce emaulation related impact on the - workload. -- *vCPU-To-Memory Ratio (1:4)* - A vCPU-to-Memory ratio of 1:4 starting from - the medium size. - -## Development - -To get started with customizing or creating your own instancetypes and preferences -see [DEVELOPMENT.md](./DEVELOPMENT.md). - -## 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 - -The following preference resources are provided by Cozystack: - -Name | Guest OS ------|--------- -alpine | Alpine -centos.7 | CentOS 7 -centos.7.desktop | CentOS 7 -centos.stream10 | CentOS Stream 10 -centos.stream10.desktop | CentOS Stream 10 -centos.stream8 | CentOS Stream 8 -centos.stream8.desktop | CentOS Stream 8 -centos.stream8.dpdk | CentOS Stream 8 -centos.stream9 | CentOS Stream 9 -centos.stream9.desktop | CentOS Stream 9 -centos.stream9.dpdk | CentOS Stream 9 -cirros | Cirros -fedora | Fedora (amd64) -fedora.arm64 | Fedora (arm64) -opensuse.leap | OpenSUSE Leap -opensuse.tumbleweed | OpenSUSE Tumbleweed -rhel.10 | Red Hat Enterprise Linux 10 Beta (amd64) -rhel.10.arm64 | Red Hat Enterprise Linux 10 Beta (arm64) -rhel.7 | Red Hat Enterprise Linux 7 -rhel.7.desktop | Red Hat Enterprise Linux 7 -rhel.8 | Red Hat Enterprise Linux 8 -rhel.8.desktop | Red Hat Enterprise Linux 8 -rhel.8.dpdk | Red Hat Enterprise Linux 8 -rhel.9 | Red Hat Enterprise Linux 9 (amd64) -rhel.9.arm64 | Red Hat Enterprise Linux 9 (arm64) -rhel.9.desktop | Red Hat Enterprise Linux 9 Desktop (amd64) -rhel.9.dpdk | Red Hat Enterprise Linux 9 DPDK (amd64) -rhel.9.realtime | Red Hat Enterprise Linux 9 Realtime (amd64) -sles | SUSE Linux Enterprise Server -ubuntu | Ubuntu -windows.10 | Microsoft Windows 10 -windows.10.virtio | Microsoft Windows 10 (virtio) -windows.11 | Microsoft Windows 11 -windows.11.virtio | Microsoft Windows 11 (virtio) -windows.2k16 | Microsoft Windows Server 2016 -windows.2k16.virtio | Microsoft Windows Server 2016 (virtio) -windows.2k19 | Microsoft Windows Server 2019 -windows.2k19.virtio | Microsoft Windows Server 2019 (virtio) -windows.2k22 | Microsoft Windows Server 2022 -windows.2k22.virtio | Microsoft Windows Server 2022 (virtio) -windows.2k25 | Microsoft Windows Server 2025 -windows.2k25.virtio | Microsoft Windows Server 2025 (virtio) diff --git a/packages/apps/virtual-machine/hack/update-instance-types.sh b/packages/apps/virtual-machine/hack/update-instance-types.sh deleted file mode 100755 index 1a248525..00000000 --- a/packages/apps/virtual-machine/hack/update-instance-types.sh +++ /dev/null @@ -1 +0,0 @@ -#!/bin/sh diff --git a/packages/apps/virtual-machine/logos/vm.svg b/packages/apps/virtual-machine/logos/vm.svg deleted file mode 100644 index 9c3e34d9..00000000 --- a/packages/apps/virtual-machine/logos/vm.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/apps/virtual-machine/templates/_helpers.tpl b/packages/apps/virtual-machine/templates/_helpers.tpl deleted file mode 100644 index f3ade695..00000000 --- a/packages/apps/virtual-machine/templates/_helpers.tpl +++ /dev/null @@ -1,71 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "virtual-machine.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "virtual-machine.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "virtual-machine.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "virtual-machine.labels" -}} -helm.sh/chart: {{ include "virtual-machine.chart" . }} -{{ include "virtual-machine.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "virtual-machine.selectorLabels" -}} -app.kubernetes.io/name: {{ include "virtual-machine.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Generate a stable UUID for cloud-init re-initialization upon upgrade. -*/}} -{{- define "virtual-machine.stableUuid" -}} -{{- $source := printf "%s-%s-%s" .Release.Namespace (include "virtual-machine.fullname" .) .Values.cloudInitSeed }} -{{- $hash := sha256sum $source }} -{{- $uuid := printf "%s-%s-4%s-9%s-%s" (substr 0 8 $hash) (substr 8 12 $hash) (substr 13 16 $hash) (substr 17 20 $hash) (substr 20 32 $hash) }} -{{- if eq .Values.cloudInitSeed "" }} - {{- /* Try to save previous uuid to not trigger full cloud-init again if user decided to remove the seed. */}} - {{- $vmResource := lookup "kubevirt.io/v1" "VirtualMachine" .Release.Namespace (include "virtual-machine.fullname" .) -}} - {{- if $vmResource }} - {{- $existingUuid := $vmResource | dig "spec" "template" "spec" "domain" "firmware" "uuid" "" }} - {{- if $existingUuid }} - {{- $uuid = $existingUuid }} - {{- end }} - {{- end }} -{{- end }} -{{- $uuid }} -{{- end }} diff --git a/packages/apps/virtual-machine/templates/secret.yaml b/packages/apps/virtual-machine/templates/secret.yaml deleted file mode 100644 index 73cd92bf..00000000 --- a/packages/apps/virtual-machine/templates/secret.yaml +++ /dev/null @@ -1,33 +0,0 @@ -{{- if .Values.sshKeys }} ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "virtual-machine.fullname" $ }}-ssh-keys -stringData: - {{- range $k, $v := .Values.sshKeys }} - key{{ $k }}: {{ quote $v }} - {{- end }} -{{- end }} -{{- if or .Values.cloudInit .Values.sshKeys }} ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "virtual-machine.fullname" . }}-cloud-init -stringData: - userdata: | - {{- if .Values.cloudInit }} - {{- .Values.cloudInit | nindent 4 }} - {{- else if and (.Values.sshKeys) (not .Values.cloudInit) }} - {{- /* - We usually provide ssh keys in cloud-init metadata, because userdata it not typed and can be used for any purpose. - However, if user provides ssh keys but not cloud-init, we still need to provide a minimal cloud-init config to avoid errors. - */}} - #cloud-config - ssh_authorized_keys: - {{- range .Values.sshKeys }} - - {{ quote . }} - {{- end }} - {{- end }} -{{- end }} diff --git a/packages/apps/virtual-machine/templates/service.yaml b/packages/apps/virtual-machine/templates/service.yaml deleted file mode 100644 index 77df7058..00000000 --- a/packages/apps/virtual-machine/templates/service.yaml +++ /dev/null @@ -1,29 +0,0 @@ -{{- if .Values.external }} ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ include "virtual-machine.fullname" . }} - labels: - {{- include "virtual-machine.labels" . | nindent 4 }} - {{- if eq .Values.externalMethod "WholeIP" }} - annotations: - networking.cozystack.io/wholeIP: "true" - {{- end }} -spec: - type: {{ ternary "LoadBalancer" "ClusterIP" .Values.external }} - externalTrafficPolicy: Local - allocateLoadBalancerNodePorts: false - selector: - {{- include "virtual-machine.selectorLabels" . | nindent 4 }} - ports: - {{- if and (eq .Values.externalMethod "WholeIP") (not .Values.externalPorts) }} - - port: 65535 - {{- else }} - {{- range .Values.externalPorts }} - - name: port-{{ . }} - port: {{ . }} - targetPort: {{ . }} - {{- end }} - {{- end }} -{{- end }} diff --git a/packages/apps/virtual-machine/templates/vm-update-hook.yaml b/packages/apps/virtual-machine/templates/vm-update-hook.yaml deleted file mode 100644 index df85a760..00000000 --- a/packages/apps/virtual-machine/templates/vm-update-hook.yaml +++ /dev/null @@ -1,119 +0,0 @@ -{{- $vmName := include "virtual-machine.fullname" . -}} -{{- $namespace := .Release.Namespace -}} - -{{- $existingVM := lookup "kubevirt.io/v1" "VirtualMachine" $namespace $vmName -}} -{{- $existingPVC := lookup "v1" "PersistentVolumeClaim" $namespace $vmName -}} - -{{- $instanceType := .Values.instanceType | default "" -}} -{{- $instanceProfile := .Values.instanceProfile | default "" -}} -{{- $desiredStorage := .Values.systemDisk.storage | default "" -}} - -{{- $needUpdateType := false -}} -{{- $needUpdateProfile := false -}} -{{- $needResizePVC := false -}} - -{{- if and $existingVM $instanceType -}} - {{- if not (eq $existingVM.spec.instancetype.name $instanceType) -}} - {{- $needUpdateType = true -}} - {{- end -}} -{{- end -}} - -{{- if and $existingVM $instanceProfile -}} - {{- if not (eq $existingVM.spec.preference.name $instanceProfile) -}} - {{- $needUpdateProfile = true -}} - {{- end -}} -{{- end -}} - -{{- if and $existingPVC $desiredStorage -}} - {{- $currentStorage := $existingPVC.spec.resources.requests.storage | toString -}} - {{- if not (eq $currentStorage $desiredStorage) -}} - {{- $needResizePVC = true -}} - {{- end -}} -{{- end -}} - -{{- if or $needUpdateType $needUpdateProfile $needResizePVC }} -apiVersion: batch/v1 -kind: Job -metadata: - name: "{{ $.Release.Name }}-update-hook" - annotations: - helm.sh/hook: pre-install,pre-upgrade - helm.sh/hook-weight: "0" - helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation -spec: - template: - metadata: - labels: - app: "{{ $.Release.Name }}-update-hook" - policy.cozystack.io/allow-to-apiserver: "true" - spec: - serviceAccountName: {{ $.Release.Name }}-update-hook - restartPolicy: Never - containers: - - name: update-resources - image: bitnami/kubectl:latest - command: ["sh", "-exc"] - args: - - | - {{- if $needUpdateType }} - echo "Patching VirtualMachine for instancetype update..." - kubectl patch virtualmachine {{ $vmName }} -n {{ $namespace }} \ - --type merge \ - -p '{"spec":{"instancetype":{"name": "{{ $instanceType }}", "revisionName": null}}}' - {{- end }} - - {{- if $needUpdateProfile }} - echo "Patching VirtualMachine for preference update..." - kubectl patch virtualmachine {{ $vmName }} -n {{ $namespace }} \ - --type merge \ - -p '{"spec":{"preference":{"name": "{{ $instanceProfile }}", "revisionName": null}}}' - {{- end }} - - {{- if $needResizePVC }} - echo "Patching PVC for storage resize..." - kubectl patch pvc {{ $vmName }} -n {{ $namespace }} \ - --type merge \ - -p '{"spec":{"resources":{"requests":{"storage":"{{ $desiredStorage }}"}}}}' - {{- end }} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ $.Release.Name }}-update-hook - annotations: - helm.sh/hook: pre-install,pre-upgrade - helm.sh/hook-weight: "-5" - helm.sh/hook-delete-policy: before-hook-creation ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: {{ $.Release.Name }}-update-hook - annotations: - helm.sh/hook: pre-install,pre-upgrade - helm.sh/hook-weight: "-5" - helm.sh/hook-delete-policy: before-hook-creation -rules: - - apiGroups: ["kubevirt.io"] - resources: ["virtualmachines"] - verbs: ["patch", "get", "list", "watch"] - - apiGroups: [""] - resources: ["persistentvolumeclaims"] - verbs: ["patch", "get", "list", "watch"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: {{ $.Release.Name }}-update-hook - annotations: - helm.sh/hook: pre-install,pre-upgrade - helm.sh/hook-weight: "-5" - helm.sh/hook-delete-policy: before-hook-creation -subjects: - - kind: ServiceAccount - name: {{ $.Release.Name }}-update-hook -roleRef: - kind: Role - name: {{ $.Release.Name }}-update-hook - apiGroup: rbac.authorization.k8s.io -{{- end }} diff --git a/packages/apps/virtual-machine/templates/vm.yaml b/packages/apps/virtual-machine/templates/vm.yaml deleted file mode 100644 index 744ec220..00000000 --- a/packages/apps/virtual-machine/templates/vm.yaml +++ /dev/null @@ -1,134 +0,0 @@ -{{- if and .Values.instanceType (not (lookup "instancetype.kubevirt.io/v1beta1" "VirtualMachineClusterInstancetype" "" .Values.instanceType)) }} -{{- fail (printf "Specified instancetype not exists in cluster: %s" .Values.instanceType) }} -{{- end }} -{{- if and .Values.instanceProfile (not (lookup "instancetype.kubevirt.io/v1beta1" "VirtualMachineClusterPreference" "" .Values.instanceProfile)) }} -{{- fail (printf "Specified profile not exists in cluster: %s" .Values.instanceProfile) }} -{{- end }} - -apiVersion: kubevirt.io/v1 -kind: VirtualMachine -metadata: - name: {{ include "virtual-machine.fullname" . }} - labels: - {{- include "virtual-machine.labels" . | nindent 4 }} -spec: - running: {{ .Values.running | default "true" }} - - {{- with .Values.instanceType }} - instancetype: - kind: VirtualMachineClusterInstancetype - name: {{ . }} - {{- end }} - {{- with .Values.instanceProfile }} - preference: - kind: VirtualMachineClusterPreference - name: {{ . }} - {{- end }} - - dataVolumeTemplates: - - metadata: - name: {{ include "virtual-machine.fullname" . }} - labels: - app.kubernetes.io/instance: {{ .Release.Name }} - spec: - storage: - resources: - requests: - storage: {{ .Values.systemDisk.storage | quote }} - {{- with .Values.systemDisk.storageClass }} - storageClassName: {{ . }} - {{- end }} - source: - {{- $dv := lookup "cdi.kubevirt.io/v1beta1" "DataVolume" "cozy-public" (printf "vm-image-%s" .Values.systemDisk.image) }} - {{- if $dv }} - pvc: - name: vm-image-{{ .Values.systemDisk.image }} - namespace: cozy-public - {{- else }} - http: - {{- if eq .Values.systemDisk.image "cirros" }} - url: https://download.cirros-cloud.net/0.6.2/cirros-0.6.2-x86_64-disk.img - {{- else if eq .Values.systemDisk.image "ubuntu" }} - url: https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img - {{- else if eq .Values.systemDisk.image "fedora" }} - url: https://download.fedoraproject.org/pub/fedora/linux/releases/40/Cloud/x86_64/images/Fedora-Cloud-Base-Generic.x86_64-40-1.14.qcow2 - {{- else if eq .Values.systemDisk.image "alpine" }} - url: https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/cloud/nocloud_alpine-3.20.2-x86_64-bios-tiny-r0.qcow2 - {{- else if eq .Values.systemDisk.image "talos" }} - url: https://github.com/siderolabs/talos/releases/download/v1.7.6/nocloud-amd64.raw.xz - {{- end }} - {{- end }} - - template: - metadata: - annotations: - kubevirt.io/allow-pod-bridge-network-live-migration: "true" - labels: - {{- include "virtual-machine.labels" . | nindent 8 }} - spec: - domain: - {{- if and .Values.resources .Values.resources.cpu .Values.resources.sockets }} - cpu: - cores: {{ .Values.resources.cpu }} - sockets: {{ .Values.resources.sockets }} - {{- end }} - {{- if and .Values.resources .Values.resources.memory }} - resources: - requests: - memory: {{ .Values.resources.memory | quote }} - {{- end }} - firmware: - uuid: {{ include "virtual-machine.stableUuid" . }} - devices: - {{- if .Values.gpus }} - gpus: - {{- range $i, $gpu := .Values.gpus }} - - name: gpu{{ add $i 1 }} - deviceName: {{ $gpu.name }} - {{- end }} - {{- end }} - - disks: - - disk: - bus: scsi - name: systemdisk - {{- if or .Values.cloudInit .Values.sshKeys }} - - disk: - bus: virtio - name: cloudinitdisk - {{- end }} - - interfaces: - - name: default - bridge: {} - - machine: - type: "" - - {{- if .Values.sshKeys }} - accessCredentials: - - sshPublicKey: - source: - secret: - secretName: {{ include "virtual-machine.fullname" $ }}-ssh-keys - propagationMethod: - # keys will be injected into metadata part of cloud-init disk - noCloud: {} - {{- end }} - - terminationGracePeriodSeconds: 30 - - volumes: - - name: systemdisk - dataVolume: - name: {{ include "virtual-machine.fullname" . }} - {{- if or .Values.cloudInit .Values.sshKeys }} - - name: cloudinitdisk - cloudInitNoCloud: - secretRef: - name: {{ include "virtual-machine.fullname" . }}-cloud-init - {{- end }} - - networks: - - name: default - pod: {} diff --git a/packages/apps/virtual-machine/values.schema.json b/packages/apps/virtual-machine/values.schema.json deleted file mode 100644 index 55127ca1..00000000 --- a/packages/apps/virtual-machine/values.schema.json +++ /dev/null @@ -1,214 +0,0 @@ -{ - "title": "Chart Values", - "type": "object", - "properties": { - "external": { - "type": "boolean", - "description": "Enable external access from outside the cluster", - "default": false - }, - "externalMethod": { - "type": "string", - "description": "specify method to passthrough the traffic to the virtual machine. Allowed values: `WholeIP` and `PortList`", - "default": "PortList", - "enum": [ - "PortList", - "WholeIP" - ] - }, - "externalPorts": { - "type": "array", - "description": "Specify ports to forward from outside the cluster", - "default": "[]", - "items": { - "type": "integer" - } - }, - "running": { - "type": "boolean", - "description": "Determines if the virtual machine should be running", - "default": true - }, - "instanceType": { - "type": "string", - "description": "Virtual Machine instance type", - "default": "u1.medium", - "optional": true, - "enum": [ - "cx1.2xlarge", - "cx1.4xlarge", - "cx1.8xlarge", - "cx1.large", - "cx1.medium", - "cx1.xlarge", - "gn1.2xlarge", - "gn1.4xlarge", - "gn1.8xlarge", - "gn1.xlarge", - "m1.2xlarge", - "m1.4xlarge", - "m1.8xlarge", - "m1.large", - "m1.xlarge", - "n1.2xlarge", - "n1.4xlarge", - "n1.8xlarge", - "n1.large", - "n1.medium", - "n1.xlarge", - "o1.2xlarge", - "o1.4xlarge", - "o1.8xlarge", - "o1.large", - "o1.medium", - "o1.micro", - "o1.nano", - "o1.small", - "o1.xlarge", - "rt1.2xlarge", - "rt1.4xlarge", - "rt1.8xlarge", - "rt1.large", - "rt1.medium", - "rt1.micro", - "rt1.small", - "rt1.xlarge", - "u1.2xlarge", - "u1.2xmedium", - "u1.4xlarge", - "u1.8xlarge", - "u1.large", - "u1.medium", - "u1.micro", - "u1.nano", - "u1.small", - "u1.xlarge", - "" - ] - }, - "instanceProfile": { - "type": "string", - "description": "Virtual Machine preferences profile", - "default": "ubuntu", - "optional": true, - "enum": [ - "alpine", - "centos.7", - "centos.7.desktop", - "centos.stream10", - "centos.stream10.desktop", - "centos.stream8", - "centos.stream8.desktop", - "centos.stream8.dpdk", - "centos.stream9", - "centos.stream9.desktop", - "centos.stream9.dpdk", - "cirros", - "fedora", - "fedora.arm64", - "opensuse.leap", - "opensuse.tumbleweed", - "rhel.10", - "rhel.10.arm64", - "rhel.7", - "rhel.7.desktop", - "rhel.8", - "rhel.8.desktop", - "rhel.8.dpdk", - "rhel.9", - "rhel.9.arm64", - "rhel.9.desktop", - "rhel.9.dpdk", - "rhel.9.realtime", - "sles", - "ubuntu", - "windows.10", - "windows.10.virtio", - "windows.11", - "windows.11.virtio", - "windows.2k16", - "windows.2k16.virtio", - "windows.2k19", - "windows.2k19.virtio", - "windows.2k22", - "windows.2k22.virtio", - "windows.2k25", - "windows.2k25.virtio", - "" - ] - }, - "systemDisk": { - "type": "object", - "properties": { - "image": { - "type": "string", - "description": "The base image for the virtual machine. Allowed values: `ubuntu`, `cirros`, `alpine`, `fedora` and `talos`", - "default": "ubuntu", - "enum": [ - "ubuntu", - "cirros", - "alpine", - "fedora", - "talos" - ] - }, - "storage": { - "type": "string", - "description": "The size of the disk allocated for the virtual machine", - "default": "5Gi" - }, - "storageClass": { - "type": "string", - "description": "StorageClass used to store the data", - "default": "replicated" - } - } - }, - "gpus": { - "type": "array", - "description": "List of GPUs to attach", - "default": [], - "items": { - "type": "object" - } - }, - "resources": { - "type": "object", - "properties": { - "cpu": { - "type": "string", - "description": "The number of CPU cores allocated to the virtual machine", - "default": "" - }, - "memory": { - "type": "string", - "description": "The amount of memory allocated to the virtual machine", - "default": "" - }, - "sockets": { - "type": "string", - "description": "The number of CPU sockets allocated to the virtual machine (used to define vCPU topology)", - "default": "" - } - } - }, - "sshKeys": { - "type": "array", - "description": "List of SSH public keys for authentication. Can be a single key or a list of keys.", - "default": "[]", - "items": { - "type": "string" - } - }, - "cloudInit": { - "type": "string", - "description": "cloud-init user data config. See cloud-init documentation for more details.", - "default": "" - }, - "cloudInitSeed": { - "type": "string", - "description": "A seed string to generate an SMBIOS UUID for the VM.", - "default": "" - } - } -} diff --git a/packages/apps/virtual-machine/values.yaml b/packages/apps/virtual-machine/values.yaml deleted file mode 100644 index 116e8ab3..00000000 --- a/packages/apps/virtual-machine/values.yaml +++ /dev/null @@ -1,69 +0,0 @@ -## @section Common parameters - -## @param external Enable external access from outside the cluster -## @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: PortList -externalPorts: -- 22 - -## @param running Determines if the virtual machine should be running -running: true - -## @param instanceType Virtual Machine instance type -## @param instanceProfile Virtual Machine preferences profile -## -instanceType: "u1.medium" -instanceProfile: ubuntu - -## @param systemDisk.image The base image for the virtual machine. Allowed values: `ubuntu`, `cirros`, `alpine`, `fedora` and `talos` -## @param systemDisk.storage The size of the disk allocated for the virtual machine -## @param systemDisk.storageClass StorageClass used to store the data -## -systemDisk: - image: ubuntu - storage: 5Gi - storageClass: replicated - -## @param gpus [array] List of GPUs to attach -## Example: -## gpus: -## - name: nvidia.com/GA102GL_A10 -gpus: [] - -## @param resources.cpu The number of CPU cores allocated to the virtual machine -## @param resources.memory The amount of memory allocated to the virtual machine -## @param resources.sockets The number of CPU sockets allocated to the virtual machine (used to define vCPU topology) -resources: - cpu: "" - memory: "" - sockets: "" - -## @param sshKeys [array] List of SSH public keys for authentication. Can be a single key or a list of keys. -## Example: -## sshKeys: -## - ssh-rsa ... -## - ssh-ed25519 ... -## -sshKeys: [] - -## @param cloudInit cloud-init user data config. See cloud-init documentation for more details. -## - https://cloudinit.readthedocs.io/en/latest/explanation/format.html -## - https://cloudinit.readthedocs.io/en/latest/reference/examples.html -## Example: -## cloudInit: | -## #cloud-config -## password: ubuntu -## chpasswd: { expire: False } -## -cloudInit: "" - -## @param cloudInitSeed A seed string to generate an SMBIOS UUID for the VM. -cloudInitSeed: "" -## Change it to any new value to force a full cloud-init reconfiguration. Change it when you want to apply -## to an existing VM settings that are usually written only once, like new SSH keys or new network configuration. -## An empty value does nothing (and the existing UUID is not reverted). Please note that changing this value -## does not trigger a VM restart. You must perform the restart separately. -## Example: -## cloudInitSeed: "upd1" diff --git a/packages/apps/vm-disk/Chart.yaml b/packages/apps/vm-disk/Chart.yaml index 051adb30..fcdd9352 100644 --- a/packages/apps/vm-disk/Chart.yaml +++ b/packages/apps/vm-disk/Chart.yaml @@ -2,24 +2,6 @@ apiVersion: v2 name: vm-disk description: Virtual Machine disk icon: /logos/disk.svg - -# 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: 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 - -# 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.3.0 +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process +appVersion: 0.4.0 diff --git a/packages/apps/vm-disk/Makefile b/packages/apps/vm-disk/Makefile index 264adfcf..80b1075a 100644 --- a/packages/apps/vm-disk/Makefile +++ b/packages/apps/vm-disk/Makefile @@ -1,4 +1,5 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: - readme-generator -v values.yaml -s values.schema.json -r README.md + cozyvalues-gen -m 'vmdisk' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/vmdisk/types.go + ../../../hack/update-crd.sh diff --git a/packages/apps/vm-disk/README.md b/packages/apps/vm-disk/README.md index c6258006..3727d0f5 100644 --- a/packages/apps/vm-disk/README.md +++ b/packages/apps/vm-disk/README.md @@ -6,9 +6,17 @@ A Virtual Machine Disk ### Common parameters -| Name | Description | Value | -| -------------- | ------------------------------------------------------ | ------------ | -| `source` | The source image location used to create a disk | `{}` | -| `optical` | Defines is disk should be considered as optical | `false` | -| `storage` | The size of the disk allocated for the virtual machine | `5Gi` | -| `storageClass` | StorageClass used to store the data | `replicated` | +| Name | Description | Type | Value | +| ------------------- | ------------------------------------------------------- | ---------- | ------------ | +| `source` | The source image location used to create a disk. | `object` | `{}` | +| `source.image` | Use image by name from default collection. | `*object` | `null` | +| `source.image.name` | Name of the image to use. | `string` | `""` | +| `source.upload` | Upload local image. | `*object` | `null` | +| `source.http` | Download image from an HTTP source. | `*object` | `null` | +| `source.http.url` | URL to download the image. | `string` | `""` | +| `source.disk` | Clone an existing vm-disk. | `*object` | `null` | +| `source.disk.name` | Name of the vm-disk to clone. | `string` | `""` | +| `optical` | Defines if disk should be considered optical. | `bool` | `false` | +| `storage` | The size of the disk allocated for the virtual machine. | `quantity` | `5Gi` | +| `storageClass` | StorageClass used to store the data. | `string` | `replicated` | + diff --git a/packages/apps/vm-disk/logos/disk.svg b/packages/apps/vm-disk/logos/disk.svg index 175f5b92..b43b15f5 100644 --- a/packages/apps/vm-disk/logos/disk.svg +++ b/packages/apps/vm-disk/logos/disk.svg @@ -1,14 +1,25 @@ - - - + + + + + + + + - - - - - + + + + + + + + + + + + - diff --git a/packages/apps/vm-disk/templates/dv.yaml b/packages/apps/vm-disk/templates/dv.yaml index 3d68e639..521a82b8 100644 --- a/packages/apps/vm-disk/templates/dv.yaml +++ b/packages/apps/vm-disk/templates/dv.yaml @@ -21,15 +21,18 @@ spec: {{- end }} source: {{- if hasKey .Values.source "image" }} - {{- $dv := lookup "cdi.kubevirt.io/v1beta1" "DataVolume" "cozy-public" (printf "vm-image-%s" .Values.source.image.name) }} pvc: - name: vm-image-{{ required "A valid .Values.source.image.name entry required!" .Values.source.image.name }} + name: vm-default-images-{{ required "A valid .Values.source.image.name entry required!" .Values.source.image.name }} namespace: cozy-public {{- else if hasKey .Values.source "http" }} http: url: {{ required "A valid .Values.source.http.url entry required!" .Values.source.http.url }} {{- else if hasKey .Values.source "upload" }} upload: {} + {{- else if hasKey .Values.source "disk" }} + pvc: + name: vm-disk-{{ required "A valid .Values.source.disk.name entry required!" .Values.source.disk.name }} + namespace: {{ $.Release.Namespace }} {{- end }} {{- else }} source: diff --git a/packages/apps/vm-disk/templates/pvc-resize-hook.yaml b/packages/apps/vm-disk/templates/pvc-resize-hook.yaml index 83737452..2454c599 100644 --- a/packages/apps/vm-disk/templates/pvc-resize-hook.yaml +++ b/packages/apps/vm-disk/templates/pvc-resize-hook.yaml @@ -1,5 +1,17 @@ {{- $existingPVC := lookup "v1" "PersistentVolumeClaim" .Release.Namespace .Release.Name }} -{{- if and $existingPVC (ne ($existingPVC.spec.resources.requests.storage | toString) .Values.storage) -}} +{{- $shouldResize := false -}} +{{- if and $existingPVC .Values.storage -}} + {{- $currentStorage := $existingPVC.spec.resources.requests.storage | toString -}} + {{- if ne $currentStorage .Values.storage -}} + {{- $oldSize := (include "cozy-lib.resources.toFloat" $currentStorage) | float64 -}} + {{- $newSize := (include "cozy-lib.resources.toFloat" .Values.storage) | float64 -}} + {{- if gt $newSize $oldSize -}} + {{- $shouldResize = true -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- if $shouldResize -}} apiVersion: batch/v1 kind: Job metadata: @@ -19,10 +31,11 @@ spec: backoffLimit: 1 containers: - name: resize - image: bitnami/kubectl + image: docker.io/alpine/k8s:1.33.4 command: ["sh", "-xec"] args: - | + echo "Resizing PVC to {{ .Values.storage }}..." kubectl patch pvc {{ .Release.Name }} -p '{"spec":{"resources":{"requests":{"storage":"{{ .Values.storage }}"}}}}' --- apiVersion: v1 diff --git a/packages/apps/vm-disk/values.schema.json b/packages/apps/vm-disk/values.schema.json index 8bc577a4..d61fc359 100644 --- a/packages/apps/vm-disk/values.schema.json +++ b/packages/apps/vm-disk/values.schema.json @@ -1,26 +1,80 @@ { - "title": "Chart Values", - "type": "object", - "properties": { - "source": { - "type": "object", - "description": "The source image location used to create a disk", - "default": {} + "title": "Chart Values", + "type": "object", + "properties": { + "source": { + "description": "The source image location used to create a disk.", + "type": "object", + "default": {}, + "properties": { + "disk": { + "description": "Clone an existing vm-disk.", + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "description": "Name of the vm-disk to clone.", + "type": "string" + } + } }, - "optical": { - "type": "boolean", - "description": "Defines is disk should be considered as optical", - "default": false + "http": { + "description": "Download image from an HTTP source.", + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "description": "URL to download the image.", + "type": "string" + } + } }, - "storage": { - "type": "string", - "description": "The size of the disk allocated for the virtual machine", - "default": "5Gi" + "image": { + "description": "Use image by name from default collection.", + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "description": "Name of the image to use.", + "type": "string" + } + } }, - "storageClass": { - "type": "string", - "description": "StorageClass used to store the data", - "default": "replicated" + "upload": { + "description": "Upload local image.", + "type": "object" } + } + }, + "optical": { + "description": "Defines if disk should be considered optical.", + "type": "boolean", + "default": false + }, + "storage": { + "description": "The size of the disk allocated for the virtual machine.", + "default": "5Gi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "storageClass": { + "description": "StorageClass used to store the data.", + "type": "string", + "default": "replicated" } -} \ No newline at end of file + } +} diff --git a/packages/apps/vm-disk/values.yaml b/packages/apps/vm-disk/values.yaml index fc34a140..b9a20d68 100644 --- a/packages/apps/vm-disk/values.yaml +++ b/packages/apps/vm-disk/values.yaml @@ -1,33 +1,32 @@ +## ## @section Common parameters +## -## @param source The source image location used to create a disk -## Example using golden image: -## source: -## image: -## name: ubuntu -## -## Example upload local image: -## source: -## upload: {} -## -## Example download image from http source: -## source: -## http: -## url: "https://download.cirros-cloud.net/0.6.2/cirros-0.6.2-x86_64-disk.img" -## -## Well known public images: -## ubuntu: https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img -## fedora: https://download.fedoraproject.org/pub/fedora/linux/releases/40/Cloud/x86_64/images/Fedora-Cloud-Base-Generic.x86_64-40-1.14.qcow2 -## cirros: https://download.cirros-cloud.net/0.6.2/cirros-0.6.2-x86_64-disk.img -## alpine: https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/cloud/nocloud_alpine-3.20.2-x86_64-bios-tiny-r0.qcow2 -## talos: https://github.com/siderolabs/talos/releases/download/v1.7.6/nocloud-amd64.raw.xz +## @typedef {struct} SourceImage - Use image by name. +## @field {string} name - Name of the image to use. +## @typedef {struct} SourceUpload - Upload local image. + +## @typedef {struct} SourceHTTP - Download image from an HTTP source. +## @field {string} url - URL to download the image. + +## @typedef {struct} SourceDisk - Clone an existing vm-disk. +## @field {string} name - Name of the vm-disk to clone. + +## @typedef {struct} Source - The source image location used to create a disk. +## @field {*SourceImage} [image] - Use image by name from default collection. +## @field {*SourceUpload} [upload] - Upload local image. +## @field {*SourceHTTP} [http] - Download image from an HTTP source. +## @field {*SourceDisk} [disk] - Clone an existing vm-disk. + +## @param {Source} source - The source image location used to create a disk. source: {} -## @param optical Defines is disk should be considered as optical +## @param {bool} optical - Defines if disk should be considered optical. optical: false -## @param storage The size of the disk allocated for the virtual machine -## @param storageClass StorageClass used to store the data +## @param {quantity} storage - The size of the disk allocated for the virtual machine. storage: 5Gi + +## @param {string} storageClass - StorageClass used to store the data. storageClass: replicated diff --git a/packages/apps/vm-instance/Chart.yaml b/packages/apps/vm-instance/Chart.yaml index 1509211a..0764bed6 100644 --- a/packages/apps/vm-instance/Chart.yaml +++ b/packages/apps/vm-instance/Chart.yaml @@ -1,26 +1,7 @@ apiVersion: v2 -#name: Virtual Machine name: vm-instance description: Virtual machine instance icon: /logos/vmi.svg - -# 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: 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 - -# 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.10.0 +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process +appVersion: 0.12.0 diff --git a/packages/apps/vm-instance/Makefile b/packages/apps/vm-instance/Makefile index 3a9a0fd8..92798e4f 100644 --- a/packages/apps/vm-instance/Makefile +++ b/packages/apps/vm-instance/Makefile @@ -1,12 +1,9 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: - readme-generator -v values.yaml -s values.schema.json -r README.md - yq -o json -i '.properties.disks.items.type = "object" | .properties.disks.default = []' values.schema.json - yq -o json -i '.properties.gpus.items.type = "object" | .properties.gpus.default = []' values.schema.json - INSTANCE_TYPES=$$(yq e '.metadata.name' -o=json -r ../../system/kubevirt-instancetypes/templates/instancetypes.yaml | yq 'split(" ") | . + [""]' -o json) \ - && yq -i -o json ".properties.instanceType.optional=true | .properties.instanceType.enum = $${INSTANCE_TYPES}" values.schema.json + cozyvalues-gen -m 'vminstance' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/vminstance/types.go + #INSTANCE_TYPES=$$(yq e '.metadata.name' -o=json -r ../../system/kubevirt-instancetypes/templates/instancetypes.yaml | yq 'split(" ") | . + [""]' -o json) \ + # && yq -i -o json ".properties.instanceType.enum = $${INSTANCE_TYPES}" values.schema.json 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 = ["PortList", "WholeIP"]' values.schema.json + && yq -i -o json ".properties.instanceProfile.enum = $${PREFERENCES}" values.schema.json + ../../../hack/update-crd.sh diff --git a/packages/apps/vm-instance/README.md b/packages/apps/vm-instance/README.md index 6971ad54..9d6a52b2 100644 --- a/packages/apps/vm-instance/README.md +++ b/packages/apps/vm-instance/README.md @@ -36,22 +36,33 @@ virtctl ssh @ ### Common parameters -| 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` | `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` | -| `instanceProfile` | Virtual Machine preferences profile | `ubuntu` | -| `disks` | List of disks to attach | `[]` | -| `gpus` | List of GPUs to attach | `[]` | -| `resources.cpu` | The number of CPU cores allocated to the virtual machine | `""` | -| `resources.memory` | The amount of memory allocated to the virtual machine | `""` | -| `resources.sockets` | The number of CPU sockets allocated to the virtual machine (used to define vCPU topology) | `""` | -| `sshKeys` | List of SSH public keys for authentication. Can be a single key or a list of keys. | `[]` | -| `cloudInit` | cloud-init user data config. See cloud-init documentation for more details. | `""` | -| `cloudInitSeed` | A seed string to generate an SMBIOS UUID for the VM. | `""` | +| Name | Description | Type | Value | +| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ----------- | +| `external` | Enable external access from outside the cluster. | `bool` | `false` | +| `externalMethod` | Method to pass through traffic to the VM. | `string` | `PortList` | +| `externalPorts` | Ports to forward from outside the cluster. | `[]int` | `[22]` | +| `externalAllowICMP` | Whether to accept ICMP traffic to the VM in PortList mode (preserves ping and PMTU discovery). No effect in WholeIP mode. Default true so ping behaves as users expect even when port filtering is in effect. | `bool` | `true` | +| `runStrategy` | Requested running state of the VirtualMachineInstance | `string` | `Always` | +| `instanceType` | Virtual Machine instance type. | `string` | `u1.medium` | +| `instanceProfile` | Virtual Machine preferences profile. | `string` | `ubuntu` | +| `disks` | List of disks to attach. | `[]object` | `[]` | +| `disks[i].name` | Disk name. | `string` | `""` | +| `disks[i].bus` | Disk bus type (e.g. "sata"). | `string` | `""` | +| `networks` | Networks to attach the VM to. | `[]object` | `[]` | +| `networks[i].name` | Network attachment name. | `string` | `""` | +| `subnets` | Deprecated: use networks instead. | `[]object` | `[]` | +| `subnets[i].name` | Network attachment name. | `string` | `""` | +| `gpus` | List of GPUs to attach (NVIDIA driver requires at least 4 GiB RAM). | `[]object` | `[]` | +| `gpus[i].name` | The name of the GPU resource to attach. | `string` | `""` | +| `cpuModel` | Model specifies the CPU model inside the VMI. List of available models https://github.com/libvirt/libvirt/tree/master/src/cpu_map | `string` | `""` | +| `resources` | Resource configuration for the virtual machine. | `object` | `{}` | +| `resources.cpu` | Number of CPU cores allocated. | `quantity` | `""` | +| `resources.memory` | Amount of memory allocated. | `quantity` | `""` | +| `resources.sockets` | Number of CPU sockets (vCPU topology). | `quantity` | `""` | +| `sshKeys` | List of SSH public keys for authentication. | `[]string` | `[]` | +| `cloudInit` | Cloud-init user data. | `string` | `""` | +| `cloudInitSeed` | Seed string to generate SMBIOS UUID for the VM. | `string` | `""` | + ## U Series diff --git a/packages/apps/vm-instance/templates/_helpers.tpl b/packages/apps/vm-instance/templates/_helpers.tpl index f3ade695..ddea90fe 100644 --- a/packages/apps/vm-instance/templates/_helpers.tpl +++ b/packages/apps/vm-instance/templates/_helpers.tpl @@ -69,3 +69,58 @@ Generate a stable UUID for cloud-init re-initialization upon upgrade. {{- end }} {{- $uuid }} {{- end }} + +{{/* +Domain resources (cpu, memory) as a JSON object. +Used in vm.yaml for rendering and in the update hook for merge patches. +*/}} +{{- define "virtual-machine.domainResources" -}} +{{- $result := dict -}} +{{- if or .Values.cpuModel (and .Values.resources .Values.resources.cpu .Values.resources.sockets) -}} + {{- $cpu := dict -}} + {{- if and .Values.resources .Values.resources.cpu .Values.resources.sockets -}} + {{- $_ := set $cpu "cores" (.Values.resources.cpu | int64) -}} + {{- $_ := set $cpu "sockets" (.Values.resources.sockets | int64) -}} + {{- end -}} + {{- if .Values.cpuModel -}} + {{- $_ := set $cpu "model" .Values.cpuModel -}} + {{- end -}} + {{- $_ := set $result "cpu" $cpu -}} +{{- end -}} +{{- if and .Values.resources .Values.resources.memory -}} + {{- $_ := set $result "resources" (dict "requests" (dict "memory" .Values.resources.memory)) -}} +{{- end -}} +{{- $result | toJson -}} +{{- end -}} + +{{/* +Node Affinity for Windows VMs +*/}} +{{- define "virtual-machine.nodeAffinity" -}} +{{- if .Values._cluster.scheduling -}} +{{- $dedicatedNodesForWindowsVMs := get .Values._cluster.scheduling "dedicatedNodesForWindowsVMs" -}} +{{- if eq $dedicatedNodesForWindowsVMs "true" -}} +{{- $isWindows := hasPrefix "windows" (toString .Values.instanceProfile) -}} +affinity: + nodeAffinity: + {{- if $isWindows }} + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: scheduling.cozystack.io/vm-windows + operator: In + values: + - "true" + {{- else }} + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + preference: + matchExpressions: + - key: scheduling.cozystack.io/vm-windows + operator: NotIn + values: + - "true" + {{- end }} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/packages/apps/vm-instance/templates/service.yaml b/packages/apps/vm-instance/templates/service.yaml index 77df7058..cfeffa81 100644 --- a/packages/apps/vm-instance/templates/service.yaml +++ b/packages/apps/vm-instance/templates/service.yaml @@ -1,22 +1,33 @@ -{{- if .Values.external }} --- apiVersion: v1 kind: Service metadata: name: {{ include "virtual-machine.fullname" . }} labels: + apps.cozystack.io/user-service: "true" {{- include "virtual-machine.labels" . | nindent 4 }} - {{- if eq .Values.externalMethod "WholeIP" }} +{{- if .Values.external }} + service.kubernetes.io/service-proxy-name: "cozy-proxy" annotations: - networking.cozystack.io/wholeIP: "true" - {{- end }} + networking.cozystack.io/wholeIP: {{ ternary "true" "false" (eq .Values.externalMethod "WholeIP") | quote }} + {{- if eq .Values.externalMethod "PortList" }} + networking.cozystack.io/allowICMP: {{ ternary "true" "false" (ne .Values.externalAllowICMP false) | quote }} + {{- end }} +{{- end }} spec: type: {{ ternary "LoadBalancer" "ClusterIP" .Values.external }} +{{- if .Values.external }} externalTrafficPolicy: Local + {{- if ((include "cozy-lib.network.disableLoadBalancerNodePorts" $) | fromYaml) }} allocateLoadBalancerNodePorts: false + {{- end }} +{{- else }} + clusterIP: None +{{- end }} selector: {{- include "virtual-machine.selectorLabels" . | nindent 4 }} ports: +{{- if .Values.external }} {{- if and (eq .Values.externalMethod "WholeIP") (not .Values.externalPorts) }} - port: 65535 {{- else }} @@ -26,4 +37,6 @@ spec: targetPort: {{ . }} {{- end }} {{- end }} +{{- else }} + - port: 65535 {{- end }} diff --git a/packages/apps/vm-instance/templates/vm-update-hook.yaml b/packages/apps/vm-instance/templates/vm-update-hook.yaml index c9d6496c..995dafff 100644 --- a/packages/apps/vm-instance/templates/vm-update-hook.yaml +++ b/packages/apps/vm-instance/templates/vm-update-hook.yaml @@ -2,26 +2,43 @@ {{- $namespace := .Release.Namespace -}} {{- $existingVM := lookup "kubevirt.io/v1" "VirtualMachine" $namespace $vmName -}} +{{- $existingService := lookup "v1" "Service" $namespace $vmName -}} {{- $instanceType := .Values.instanceType | default "" -}} {{- $instanceProfile := .Values.instanceProfile | default "" -}} +{{- $desiredServiceType := ternary "LoadBalancer" "ClusterIP" .Values.external -}} {{- $needUpdateType := false -}} {{- $needUpdateProfile := false -}} +{{- $needRecreateService := false -}} +{{- $needRemoveInstanceType := false -}} +{{- $needRemoveCustomResources := false -}} -{{- if and $existingVM $instanceType -}} +{{- $existingHasInstanceType := and $existingVM $existingVM.spec.instancetype -}} +{{- if and $existingHasInstanceType (not $instanceType) -}} + {{- $needRemoveInstanceType = true -}} +{{- else if and $existingHasInstanceType $instanceType -}} {{- if not (eq $existingVM.spec.instancetype.name $instanceType) -}} {{- $needUpdateType = true -}} {{- end -}} +{{- else if and $existingVM (not $existingHasInstanceType) $instanceType -}} + {{- $needRemoveCustomResources = true -}} {{- end -}} -{{- if and $existingVM $instanceProfile -}} +{{- if and $existingVM $existingVM.spec.preference $instanceProfile -}} {{- if not (eq $existingVM.spec.preference.name $instanceProfile) -}} {{- $needUpdateProfile = true -}} {{- end -}} {{- end -}} -{{- if or $needUpdateType $needUpdateProfile }} +{{- if $existingService -}} + {{- $currentServiceType := $existingService.spec.type -}} + {{- if ne $currentServiceType $desiredServiceType -}} + {{- $needRecreateService = true -}} + {{- end -}} +{{- end -}} + +{{- if or $needUpdateType $needUpdateProfile $needRecreateService $needRemoveInstanceType $needRemoveCustomResources }} apiVersion: batch/v1 kind: Job metadata: @@ -41,23 +58,49 @@ spec: restartPolicy: Never containers: - name: update-resources - image: bitnami/kubectl:latest + image: docker.io/alpine/k8s:1.33.4 + resources: + requests: + memory: "16Mi" + cpu: "10m" + limits: + memory: "128Mi" + cpu: "100m" command: ["sh", "-exc"] args: - | {{- if $needUpdateType }} echo "Patching VirtualMachine for instancetype update..." - kubectl patch virtualmachine {{ $vmName }} -n {{ $namespace }} \ + kubectl patch virtualmachines.kubevirt.io {{ $vmName }} -n {{ $namespace }} \ --type merge \ -p '{"spec":{"instancetype":{"name": "{{ $instanceType }}", "revisionName": null}}}' {{- end }} - + {{- if $needUpdateProfile }} echo "Patching VirtualMachine for preference update..." - kubectl patch virtualmachine {{ $vmName }} -n {{ $namespace }} \ + kubectl patch virtualmachines.kubevirt.io {{ $vmName }} -n {{ $namespace }} \ --type merge \ -p '{"spec":{"preference":{"name": "{{ $instanceProfile }}", "revisionName": null}}}' {{- end }} + + {{- if $needRemoveInstanceType }} + echo "Removing instancetype from VM (switching to custom resources)..." + kubectl patch virtualmachines.kubevirt.io {{ $vmName }} -n {{ $namespace }} \ + --type merge \ + -p '{"spec":{"instancetype":null{{- if not $instanceProfile }},"preference":null{{- end }},"template":{"spec":{"domain":{{ include "virtual-machine.domainResources" . }}}}}}' + {{- end }} + + {{- if $needRemoveCustomResources }} + echo "Removing custom CPU/memory from domain (switching to instancetype)..." + kubectl patch virtualmachines.kubevirt.io {{ $vmName }} -n {{ $namespace }} \ + --type merge \ + -p '{"spec":{"instancetype":{"name":"{{ $instanceType }}","revisionName":null},"template":{"spec":{"domain":{"cpu":null,"resources":null}}}}}' + {{- end }} + + {{- if $needRecreateService }} + echo "Removing Service..." + kubectl delete service --cascade=orphan -n {{ $namespace }} {{ $vmName }} + {{- end }} --- apiVersion: v1 kind: ServiceAccount @@ -80,6 +123,10 @@ rules: - apiGroups: ["kubevirt.io"] resources: ["virtualmachines"] verbs: ["patch", "get", "list", "watch"] + - apiGroups: [""] + resources: ["services"] + resourceNames: ["{{ $vmName }}"] + verbs: ["delete"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding diff --git a/packages/apps/vm-instance/templates/vm.yaml b/packages/apps/vm-instance/templates/vm.yaml index 1674337f..55f278c1 100644 --- a/packages/apps/vm-instance/templates/vm.yaml +++ b/packages/apps/vm-instance/templates/vm.yaml @@ -4,6 +4,10 @@ {{- if and .Values.instanceProfile (not (lookup "instancetype.kubevirt.io/v1beta1" "VirtualMachineClusterPreference" "" .Values.instanceProfile)) }} {{- fail (printf "Specified instanceProfile does not exist in the cluster: %s" .Values.instanceProfile) }} {{- end }} +{{- if and (not .Values.instanceType) (not (and .Values.resources .Values.resources.cpu .Values.resources.sockets .Values.resources.memory)) }} +{{- fail "Either instanceType or resources (cpu, sockets, memory) must be specified" }} +{{- end }} +{{- $networks := .Values.networks | default .Values.subnets }} apiVersion: kubevirt.io/v1 kind: VirtualMachine @@ -12,7 +16,11 @@ metadata: labels: {{- include "virtual-machine.labels" . | nindent 4 }} spec: - running: {{ .Values.running }} + {{- if hasKey .Values "runStrategy" }} + runStrategy: {{ .Values.runStrategy }} + {{- else }} + runStrategy: {{ ternary "Always" "Halted" (.Values.running | default true) }} + {{- end }} {{- with .Values.instanceType }} instancetype: kind: VirtualMachineClusterInstancetype @@ -27,19 +35,22 @@ spec: metadata: annotations: kubevirt.io/allow-pod-bridge-network-live-migration: "true" + {{- $ovnIPName := printf "%s.%s" (include "virtual-machine.fullname" .) .Release.Namespace }} + {{- $ovnIP := lookup "kubeovn.io/v1" "IP" "" $ovnIPName }} + {{- if $ovnIP }} + ovn.kubernetes.io/mac_address: {{ $ovnIP.spec.macAddress | quote }} + ovn.kubernetes.io/ip_address: {{ $ovnIP.spec.ipAddress | quote }} + {{- end }} labels: {{- include "virtual-machine.labels" . | nindent 8 }} spec: domain: - {{- if and .Values.resources .Values.resources.cpu .Values.resources.sockets }} - cpu: - cores: {{ .Values.resources.cpu }} - sockets: {{ .Values.resources.sockets }} + {{- $domainRes := include "virtual-machine.domainResources" . | fromJson -}} + {{- with $domainRes.cpu }} + cpu: {{- . | toYaml | nindent 10 }} {{- end }} - {{- if and .Values.resources .Values.resources.memory }} - resources: - requests: - memory: {{ .Values.resources.memory | quote }} + {{- with $domainRes.resources }} + resources: {{- . | toYaml | nindent 10 }} {{- end }} firmware: uuid: {{ include "virtual-machine.stableUuid" . }} @@ -76,6 +87,10 @@ spec: interfaces: - name: default bridge: {} + {{- range $i, $net := $networks }} + - name: {{ $net.name }} + bridge: {} + {{- end }} machine: type: "" {{- with .Values.sshKeys }} @@ -89,6 +104,9 @@ spec: noCloud: {} {{- end }} terminationGracePeriodSeconds: 30 + + {{- include "virtual-machine.nodeAffinity" . | nindent 6 }} + volumes: {{- range .Values.disks }} - name: disk-{{ .name }} @@ -104,3 +122,8 @@ spec: networks: - name: default pod: {} + {{- range $i, $net := $networks }} + - name: {{ $net.name }} + multus: + networkName: {{ $.Release.Namespace }}/{{ $net.name }} + {{- end }} diff --git a/packages/apps/vm-instance/values.schema.json b/packages/apps/vm-instance/values.schema.json index 4711c633..01bd30a9 100644 --- a/packages/apps/vm-instance/values.schema.json +++ b/packages/apps/vm-instance/values.schema.json @@ -3,13 +3,13 @@ "type": "object", "properties": { "external": { + "description": "Enable external access from outside the cluster.", "type": "boolean", - "description": "Enable external access from outside the cluster", "default": false }, "externalMethod": { + "description": "Method to pass through traffic to the VM.", "type": "string", - "description": "specify method to passthrough the traffic to the virtual machine. Allowed values: `WholeIP` and `PortList`", "default": "PortList", "enum": [ "PortList", @@ -17,80 +17,41 @@ ] }, "externalPorts": { + "description": "Ports to forward from outside the cluster.", "type": "array", - "description": "Specify ports to forward from outside the cluster", - "default": "[]", + "default": [ + 22 + ], "items": { "type": "integer" } }, - "running": { + "externalAllowICMP": { + "description": "Whether to accept ICMP traffic to the VM in PortList mode (preserves ping and PMTU discovery). No effect in WholeIP mode. Default true so ping behaves as users expect even when port filtering is in effect.", "type": "boolean", - "description": "Determines if the virtual machine should be running", "default": true }, - "instanceType": { + "runStrategy": { + "description": "Requested running state of the VirtualMachineInstance", "type": "string", - "description": "Virtual Machine instance type", - "default": "u1.medium", - "optional": true, + "default": "Always", "enum": [ - "cx1.2xlarge", - "cx1.4xlarge", - "cx1.8xlarge", - "cx1.large", - "cx1.medium", - "cx1.xlarge", - "gn1.2xlarge", - "gn1.4xlarge", - "gn1.8xlarge", - "gn1.xlarge", - "m1.2xlarge", - "m1.4xlarge", - "m1.8xlarge", - "m1.large", - "m1.xlarge", - "n1.2xlarge", - "n1.4xlarge", - "n1.8xlarge", - "n1.large", - "n1.medium", - "n1.xlarge", - "o1.2xlarge", - "o1.4xlarge", - "o1.8xlarge", - "o1.large", - "o1.medium", - "o1.micro", - "o1.nano", - "o1.small", - "o1.xlarge", - "rt1.2xlarge", - "rt1.4xlarge", - "rt1.8xlarge", - "rt1.large", - "rt1.medium", - "rt1.micro", - "rt1.small", - "rt1.xlarge", - "u1.2xlarge", - "u1.2xmedium", - "u1.4xlarge", - "u1.8xlarge", - "u1.large", - "u1.medium", - "u1.micro", - "u1.nano", - "u1.small", - "u1.xlarge", - "" + "Always", + "Halted", + "Manual", + "RerunOnFailure", + "Once" ] }, - "instanceProfile": { + "instanceType": { + "description": "Virtual Machine instance type.", + "type": "string", + "default": "u1.medium" + }, + "instanceProfile": { + "description": "Virtual Machine preferences profile.", "type": "string", - "description": "Virtual Machine preferences profile", "default": "ubuntu", - "optional": true, "enum": [ "alpine", "centos.7", @@ -138,57 +99,138 @@ ] }, "disks": { + "description": "List of disks to attach.", "type": "array", - "description": "List of disks to attach", "default": [], "items": { - "type": "object" + "type": "object", + "required": [ + "name" + ], + "properties": { + "bus": { + "description": "Disk bus type (e.g. \"sata\").", + "type": "string" + }, + "name": { + "description": "Disk name.", + "type": "string" + } + } + } + }, + "networks": { + "description": "Networks to attach the VM to.", + "type": "array", + "default": [], + "items": { + "type": "object", + "properties": { + "name": { + "description": "Network attachment name.", + "type": "string" + } + } + } + }, + "subnets": { + "description": "Deprecated: use networks instead.", + "type": "array", + "default": [], + "items": { + "type": "object", + "properties": { + "name": { + "description": "Network attachment name.", + "type": "string" + } + } } }, "gpus": { + "description": "List of GPUs to attach (NVIDIA driver requires at least 4 GiB RAM).", "type": "array", - "description": "List of GPUs to attach", "default": [], "items": { - "type": "object" + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "description": "The name of the GPU resource to attach.", + "type": "string" + } + } } }, + "cpuModel": { + "description": "Model specifies the CPU model inside the VMI. List of available models https://github.com/libvirt/libvirt/tree/master/src/cpu_map", + "type": "string", + "default": "" + }, "resources": { + "description": "Resource configuration for the virtual machine.", "type": "object", + "default": {}, "properties": { "cpu": { - "type": "string", - "description": "The number of CPU cores allocated to the virtual machine", - "default": "" + "description": "Number of CPU cores allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true }, "memory": { - "type": "string", - "description": "The amount of memory allocated to the virtual machine", - "default": "" + "description": "Amount of memory allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true }, "sockets": { - "type": "string", - "description": "The number of CPU sockets allocated to the virtual machine (used to define vCPU topology)", - "default": "" + "description": "Number of CPU sockets (vCPU topology).", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true } } }, "sshKeys": { + "description": "List of SSH public keys for authentication.", "type": "array", - "description": "List of SSH public keys for authentication. Can be a single key or a list of keys.", - "default": "[]", + "default": [], "items": { "type": "string" } }, "cloudInit": { + "description": "Cloud-init user data.", "type": "string", - "description": "cloud-init user data config. See cloud-init documentation for more details.", "default": "" }, "cloudInitSeed": { + "description": "Seed string to generate SMBIOS UUID for the VM.", "type": "string", - "description": "A seed string to generate an SMBIOS UUID for the VM.", "default": "" } } diff --git a/packages/apps/vm-instance/values.yaml b/packages/apps/vm-instance/values.yaml index 30c3e4ea..92e399c2 100644 --- a/packages/apps/vm-instance/values.yaml +++ b/packages/apps/vm-instance/values.yaml @@ -1,68 +1,103 @@ +## ## @section Common parameters +## -## @param external Enable external access from outside the cluster -## @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 +## @enum {string} ExternalMethod - Method to pass through traffic to the VM. +## @value PortList - Forward selected ports only. +## @value WholeIP - Forward all traffic for the IP. + +## @typedef {struct} Disk - Disk configuration. +## @field {string} name - Disk name. +## @field {string} [bus] - Disk bus type (e.g. "sata"). + +## @typedef {struct} Network - Network to attach the VM to. +## @field {string} [name] - Network attachment name. + +## @typedef {struct} GPU - GPU device configuration. +## @field {string} name - The name of the GPU resource to attach. + +## @typedef {struct} Resources - Resource configuration for the virtual machine. +## @field {quantity} [cpu] - Number of CPU cores allocated. +## @field {quantity} [memory] - Amount of memory allocated. +## @field {quantity} [sockets] - Number of CPU sockets (vCPU topology). + +## @param {bool} external - Enable external access from outside the cluster. external: false + +## @param {ExternalMethod} externalMethod - Method to pass through traffic to the VM. externalMethod: PortList + +## @param {[]int} externalPorts - Ports to forward from outside the cluster. externalPorts: - 22 -## @param running Determines if the virtual machine should be running -running: true +## @param {bool} externalAllowICMP - Whether to accept ICMP traffic to the VM in PortList mode (preserves ping and PMTU discovery). No effect in WholeIP mode. Default true so ping behaves as users expect even when port filtering is in effect. +externalAllowICMP: true -## @param instanceType Virtual Machine instance type -## @param instanceProfile Virtual Machine preferences profile -## +## @enum {string} RunStrategy - Requested running state of the VirtualMachineInstance +## @value Always - VMI should always be running +## @value Halted - VMI should never be running +## @value Manual - VMI can be started/stopped using API endpoints +## @value RerunOnFailure - VMI will initially be running and restarted if a failure occurs, but will not be restarted upon successful completion +## @value Once - VMI will run once and not be restarted upon completion regardless if the completion is of phase Failure or Success + +## @param {RunStrategy} runStrategy - Requested running state of the VirtualMachineInstance +runStrategy: Always + +## @param {string} instanceType - Virtual Machine instance type. instanceType: "u1.medium" + +## @param {string} instanceProfile - Virtual Machine preferences profile. instanceProfile: ubuntu -## @param disks [array] List of disks to attach +## @param {[]Disk} disks - List of disks to attach. +disks: [] ## Example: ## disks: ## - name: example-system ## - name: example-data ## bus: sata -disks: [] -## @param gpus [array] List of GPUs to attach +## @param {[]Network} networks - Networks to attach the VM to. +networks: [] +## Example: +## networks: +## - name: subnet-84dbec17 +## - name: subnet-aa8896b5 + +## @param {[]Network} subnets - Deprecated: use networks instead. +subnets: [] + +## @param {[]GPU} gpus - List of GPUs to attach (NVIDIA driver requires at least 4 GiB RAM). +gpus: [] ## Example: ## gpus: ## - name: nvidia.com/GA102GL_A10 -gpus: [] -## @param resources.cpu The number of CPU cores allocated to the virtual machine -## @param resources.memory The amount of memory allocated to the virtual machine -## @param resources.sockets The number of CPU sockets allocated to the virtual machine (used to define vCPU topology) -resources: - cpu: "" - memory: "" - sockets: "" +## @param {string} cpuModel - Model specifies the CPU model inside the VMI. List of available models https://github.com/libvirt/libvirt/tree/master/src/cpu_map +cpuModel: "" -## @param sshKeys [array] List of SSH public keys for authentication. Can be a single key or a list of keys. +## @param {Resources} [resources] - Resource configuration for the virtual machine. +resources: {} + +## @param {[]string} sshKeys - List of SSH public keys for authentication. +sshKeys: [] ## Example: ## sshKeys: ## - ssh-rsa ... ## - ssh-ed25519 ... ## -sshKeys: [] -## @param cloudInit cloud-init user data config. See cloud-init documentation for more details. -## - https://cloudinit.readthedocs.io/en/latest/explanation/format.html -## - https://cloudinit.readthedocs.io/en/latest/reference/examples.html +## @param {string} cloudInit - Cloud-init user data. +cloudInit: "" ## Example: ## cloudInit: | ## #cloud-config ## password: ubuntu ## chpasswd: { expire: False } ## -cloudInit: "" -## @param cloudInitSeed A seed string to generate an SMBIOS UUID for the VM. +## @param {string} cloudInitSeed - Seed string to generate SMBIOS UUID for the VM. cloudInitSeed: "" -## Change it to any new value to force a full cloud-init reconfiguration. Change it when you want to apply -## to an existing VM settings that are usually written only once, like new SSH keys or new network configuration. -## An empty value does nothing (and the existing UUID is not reverted). Please note that changing this value -## does not trigger a VM restart. You must perform the restart separately. ## Example: ## cloudInitSeed: "upd1" diff --git a/packages/apps/vpc/Chart.yaml b/packages/apps/vpc/Chart.yaml new file mode 100644 index 00000000..d317ed21 --- /dev/null +++ b/packages/apps/vpc/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: virtualprivatecloud +description: Isolated networks +icon: logos/vpc.svg +type: application +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/apps/vpc/Makefile b/packages/apps/vpc/Makefile new file mode 100644 index 00000000..2f0c193f --- /dev/null +++ b/packages/apps/vpc/Makefile @@ -0,0 +1,8 @@ +include ../../../hack/package.mk + +generate: + cozyvalues-gen -m 'vpc' -v values.yaml -s values.schema.json -g ../../../api/apps/v1alpha1/vpc/types.go + ../../../hack/update-crd.sh + +update: + echo diff --git a/packages/apps/vpc/README.md b/packages/apps/vpc/README.md new file mode 100644 index 00000000..890f12d8 --- /dev/null +++ b/packages/apps/vpc/README.md @@ -0,0 +1,50 @@ +# VPC + +VPC offers a subset of dedicated subnets with networking services related to it. +As the service evolves, it will provide more ways to isolate your workloads. + +## Service details + +To function, the service requires kube-ovn and multus CNI to be present, so by default it will only work on `paas-full` bundle. +Kube-ovn provides VPC and Subnet resources and performs isolation and networking maintenance such as DHCP. Under the hood it uses ovn virtual routers and virtual switches. +Multus enables a multi-nic capability, so a pod or a VM could have two or more network interfaces. + +Currently every workload will have a connection to a default management network which will also have a default gateway, and the majority of traffic will go through it. +VPC subnets are for now an additional dedicated networking spaces. + +## Deployment notes + +VPC name must be unique within a tenant. +Subnet name and ip address range must be unique within a VPC. +Subnet ip address space must not overlap with the default management network ip address range, subsets of 172.16.0.0/12 are recommended. +Currently there are no fail-safe checks, however they are planned for the future. + +Different VPCs may have subnets with overlapping ip address ranges. + +A VM or a pod may be connected to multiple secondary Subnets at once. Each secondary connection will be represented as an additional network interface. + +## Parameters + +### Common parameters + +| Name | Description | Type | Value | +| -------------------- | -------------------------------- | ------------------- | ------- | +| `subnets` | Subnets of a VPC | `map[string]object` | `{...}` | +| `subnets[name].cidr` | Subnet CIDR, e.g. 192.168.0.0/24 | `cidr` | `{}` | + + +## Examples +```yaml +apiVersion: apps.cozystack.io/v1alpha1 +kind: VirtualPrivateCloud +metadata: + name: vpc00 +spec: + subnets: + sub00: + cidr: 172.16.0.0/24 + sub01: + cidr: 172.16.1.0/24 + sub02: + cidr: 172.16.2.0/24 +``` diff --git a/packages/apps/vpc/charts/cozy-lib b/packages/apps/vpc/charts/cozy-lib new file mode 120000 index 00000000..e1813509 --- /dev/null +++ b/packages/apps/vpc/charts/cozy-lib @@ -0,0 +1 @@ +../../../library/cozy-lib \ No newline at end of file diff --git a/packages/apps/vpc/logos/vpc.svg b/packages/apps/vpc/logos/vpc.svg new file mode 100644 index 00000000..555bb12e --- /dev/null +++ b/packages/apps/vpc/logos/vpc.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/apps/vpc/templates/vpc.yaml b/packages/apps/vpc/templates/vpc.yaml new file mode 100644 index 00000000..784c181b --- /dev/null +++ b/packages/apps/vpc/templates/vpc.yaml @@ -0,0 +1,126 @@ +## Release.Namespace == tenant name +## Release.Name == vpc name + +{{ $vpcId := print "vpc-" (print .Release.Namespace "/" .Release.Name | sha256sum | trunc 6) }} + +--- +apiVersion: kubeovn.io/v1 +kind: Vpc +metadata: + name: {{ $vpcId }} + labels: + cozystack.io/vpcName: {{ .Release.Name }} + cozystack.io/tenantName: {{ .Release.Namespace }} +spec: + enableExternal: false + namespaces: + - {{ .Release.Namespace }} +{{- if .Values.peers }} + vpcPeerings: +{{- range .Values.peers }} +{{- $remoteRelease := printf "virtualprivatecloud-%s" .vpcName }} +{{- $remoteVpcId := printf "vpc-%s" (printf "%s/%s" .tenantNamespace $remoteRelease | sha256sum | trunc 6) }} +{{- $sorted := list $vpcId $remoteVpcId | sortAlpha }} +{{- $pairKey := join "/" $sorted }} +{{- $pairHash := sha256sum $pairKey }} +{{- $byte0 := int (include "cozy-lib.strings.hexToInt" (substr 0 2 $pairHash)) }} +{{- $byte1 := int (include "cozy-lib.strings.hexToInt" (substr 2 4 $pairHash)) }} +{{- $oct3 := int (add (mod $byte0 254) 1) }} +{{- $base4 := int (mul (mod $byte1 64) 4) }} +{{- if eq $vpcId (index $sorted 0) }} + - remoteVpc: {{ $remoteVpcId }} + localConnectIP: {{ printf "169.254.%d.%d" $oct3 (int (add $base4 1)) }} +{{- else }} + - remoteVpc: {{ $remoteVpcId }} + localConnectIP: {{ printf "169.254.%d.%d" $oct3 (int (add $base4 2)) }} +{{- end }} +{{- end }} +{{- end }} +{{- if .Values.routes }} + staticRoutes: +{{- range .Values.routes }} + - cidr: {{ .cidr | quote }} + nextHopIP: {{ .nextHopIP | quote }} +{{- end }} +{{- end }} + +{{- range .Values.subnets }} +{{- $subnetId := print "subnet-" (print $.Release.Namespace "/" $vpcId "/" .name | sha256sum | trunc 8) }} +--- +apiVersion: k8s.cni.cncf.io/v1 +kind: NetworkAttachmentDefinition +metadata: + name: {{ $subnetId }} + namespace: {{ $.Release.Namespace }} + labels: + cozystack.io/subnetName: {{ .name }} + cozystack.io/vpcId: {{ $vpcId }} + cozystack.io/vpcName: {{ $.Release.Name }} + cozystack.io/tenantName: {{ $.Release.Namespace }} +spec: + config: '{ + "cniVersion": "0.3.0", + "type": "kube-ovn", + "server_socket": "/run/openvswitch/kube-ovn-daemon.sock", + "provider": "{{ $subnetId }}.{{ $.Release.Namespace }}.ovn" + }' +--- +apiVersion: kubeovn.io/v1 +kind: Subnet +metadata: + name: {{ $subnetId }} + labels: + cozystack.io/subnetName: {{ .name }} + cozystack.io/vpcId: {{ $vpcId }} + cozystack.io/vpcName: {{ $.Release.Name }} + cozystack.io/tenantName: {{ $.Release.Namespace }} +spec: + vpc: {{ $vpcId }} + cidrBlock: {{ .cidr }} + provider: "{{ $subnetId }}.{{ $.Release.Namespace }}.ovn" + protocol: IPv4 + enableLb: false + private: true +{{- end }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ $.Release.Name }}-subnets + labels: + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.kind: VirtualPrivateCloud + apps.cozystack.io/application.name: {{ trimPrefix "virtualprivatecloud-" .Release.Name }} + cozystack.io/vpcId: {{ $vpcId }} + cozystack.io/tenantName: {{ $.Release.Namespace }} +data: + {{- range .Values.subnets }} + {{ .name }}.ID: {{ print "subnet-" (print $.Release.Namespace "/" $vpcId "/" .name | sha256sum | trunc 8) }} + {{ .name }}.CIDR: {{ .cidr }} + {{- end }} + {{- range .Values.peers }} + {{- $remoteRelease := printf "virtualprivatecloud-%s" .vpcName }} + {{- $remoteVpcId := printf "vpc-%s" (printf "%s/%s" .tenantNamespace $remoteRelease | sha256sum | trunc 6) }} + peer.{{ .tenantNamespace }}.{{ .vpcName }}.vpcId: {{ $remoteVpcId | quote }} + peer.{{ .tenantNamespace }}.{{ .vpcName }}.tenantNamespace: {{ .tenantNamespace | quote }} + {{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: "{{ .Release.Name }}-subnets" +subjects: {{- include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "view" .Release.Namespace ) | nindent 2 }} +roleRef: + kind: Role + name: "{{ .Release.Name }}-subnets" + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: "{{ .Release.Name }}-subnets" +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get","list","watch"] + resourceNames: ["{{ .Release.Name }}-subnets"] diff --git a/packages/apps/vpc/values.schema.json b/packages/apps/vpc/values.schema.json new file mode 100644 index 00000000..b25b46ed --- /dev/null +++ b/packages/apps/vpc/values.schema.json @@ -0,0 +1,71 @@ +{ + "title": "Chart Values", + "type": "object", + "properties": { + "subnets": { + "description": "Subnets of a VPC", + "type": "array", + "default": [], + "items": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "cidr": { + "description": "IP address range", + "type": "string" + }, + "name": { + "description": "Subnet name", + "type": "string" + } + } + } + }, + "peers": { + "description": "VPC peering connections (bidirectional declaration required)", + "type": "array", + "default": [], + "items": { + "type": "object", + "required": [ + "tenantNamespace", + "vpcName" + ], + "properties": { + "tenantNamespace": { + "description": "Namespace of the remote tenant", + "type": "string" + }, + "vpcName": { + "description": "Logical name of the remote VPC (without \"virtualprivatecloud-\" prefix)", + "type": "string" + } + } + } + }, + "routes": { + "description": "Static routes for the VPC", + "type": "array", + "default": [], + "items": { + "type": "object", + "required": [ + "cidr", + "nextHopIP" + ], + "properties": { + "cidr": { + "description": "Destination CIDR", + "type": "string" + }, + "nextHopIP": { + "description": "Next hop IP address", + "type": "string" + } + } + } + } + } +} diff --git a/packages/apps/vpc/values.yaml b/packages/apps/vpc/values.yaml new file mode 100644 index 00000000..8bd27589 --- /dev/null +++ b/packages/apps/vpc/values.yaml @@ -0,0 +1,38 @@ +## +## @section Common parameters +## + +## @typedef {struct} Subnet - Subnet of a VPC +## @field {string} name - Subnet name +## @field {string} [cidr] - IP address range + +## @param {[]Subnet} subnets - Subnets of a VPC +subnets: [] +## Example: +## subnets: +## - name: mysubnet0 +## cidr: "172.16.0.0/24" +## - name: mysubnet1 +## cidr: "172.16.1.0/24" + +## @typedef {struct} Peer - VPC peering target +## @field {string} vpcName - Logical name of the remote VPC (without "virtualprivatecloud-" prefix) +## @field {string} tenantNamespace - Namespace of the remote tenant + +## @param {[]Peer} peers - VPC peering connections (bidirectional declaration required) +peers: [] +## Example: +## peers: +## - vpcName: "other-vpc" +## tenantNamespace: "tenant-other" + +## @typedef {struct} Route - Static route entry +## @field {string} cidr - Destination CIDR +## @field {string} nextHopIP - Next hop IP address + +## @param {[]Route} routes - Static routes for the VPC +routes: [] +## Example: +## routes: +## - cidr: "172.16.1.0/24" +## nextHopIP: "10.0.0.1" diff --git a/packages/apps/vpn/Chart.yaml b/packages/apps/vpn/Chart.yaml index 2ee979e4..097794c0 100644 --- a/packages/apps/vpn/Chart.yaml +++ b/packages/apps/vpn/Chart.yaml @@ -2,24 +2,6 @@ apiVersion: v2 name: vpn description: Managed VPN service icon: /logos/outline.svg - -# 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: 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 - -# 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. +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process appVersion: "1.8.1" diff --git a/packages/apps/vpn/Makefile b/packages/apps/vpn/Makefile index e4057cb4..d0b8412f 100644 --- a/packages/apps/vpn/Makefile +++ b/packages/apps/vpn/Makefile @@ -1,5 +1,5 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: - readme-generator -v values.yaml -s values.schema.json -r README.md - yq -i -o json --indent 4 '.properties.resourcesPreset.enum = ["none", "nano", "micro", "small", "medium", "large", "xlarge", "2xlarge"]' values.schema.json + cozyvalues-gen -m 'vpn' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/vpn/types.go + ../../../hack/update-crd.sh diff --git a/packages/apps/vpn/README.md b/packages/apps/vpn/README.md index 562db3de..b8bd7209 100644 --- a/packages/apps/vpn/README.md +++ b/packages/apps/vpn/README.md @@ -19,20 +19,25 @@ Furthermore, Shadowbox is compatible with standard Shadowsocks clients, providin ### Common parameters -| Name | Description | Value | -| ---------- | ----------------------------------------------- | ------- | -| `external` | Enable external access from outside the cluster | `false` | -| `replicas` | Number of VPN server replicas | `2` | +| Name | Description | Type | Value | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | ---------- | ------- | +| `replicas` | Number of VPN server replicas. | `int` | `2` | +| `resources` | Explicit CPU and memory configuration for each VPN server replica. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `resources.cpu` | CPU available to each replica. | `quantity` | `""` | +| `resources.memory` | Memory (RAM) available to each replica. | `quantity` | `""` | +| `resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `nano` | +| `external` | Enable external access from outside the cluster. | `bool` | `false` | -### Configuration parameters -| Name | Description | Value | -| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------ | -| `host` | Host used to substitute into generated URLs | `""` | -| `users` | Users configuration | `{}` | -| `externalIPs` | List of externalIPs for service. Optional. If not specified will use LoadBalancer service by default. | `[]` | -| `resources` | Explicit CPU and memory configuration for each VPN server replica. When left empty, the preset defined in `resourcesPreset` is applied. | `{}` | -| `resourcesPreset` | Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge. | `nano` | +### Application-specific parameters + +| Name | Description | Type | Value | +| ---------------------- | ------------------------------------------------------------------------------------------------------ | ------------------- | ----- | +| `host` | Host used to substitute into generated URLs. | `string` | `""` | +| `users` | Users configuration map. | `map[string]object` | `{}` | +| `users[name].password` | Password for the user (autogenerated if not provided). | `string` | `""` | +| `externalIPs` | List of externalIPs for service. Optional. If not specified, will use LoadBalancer service by default. | `[]string` | `[]` | + ## Parameter examples and reference diff --git a/packages/apps/vpn/templates/secret.yaml b/packages/apps/vpn/templates/secret.yaml index 79960096..3ef4ac4b 100644 --- a/packages/apps/vpn/templates/secret.yaml +++ b/packages/apps/vpn/templates/secret.yaml @@ -1,5 +1,4 @@ -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $host := .Values._namespace.host }} {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (printf "%s-vpn" .Release.Name) }} {{- $accessKeys := list }} {{- $passwords := dict }} diff --git a/packages/apps/vpn/templates/tls.yaml b/packages/apps/vpn/templates/tls.yaml index cc3fd9b6..fd1f0e22 100644 --- a/packages/apps/vpn/templates/tls.yaml +++ b/packages/apps/vpn/templates/tls.yaml @@ -14,7 +14,7 @@ data: tls.key: {{ index $existingSecret.data "tls.key" }} {{- else }} {{- with genSignedCert $cn nil nil 3650 $ca }} - cacert: {{ b64enc $ca.Cert }} + ca.crt: {{ b64enc $ca.Cert }} tls.crt: {{ b64enc .Cert }} tls.key: {{ b64enc .Key }} {{- end }} diff --git a/packages/apps/vpn/templates/workloadmonitor.yaml b/packages/apps/vpn/templates/workloadmonitor.yaml index a75f7940..7fc1ec7a 100644 --- a/packages/apps/vpn/templates/workloadmonitor.yaml +++ b/packages/apps/vpn/templates/workloadmonitor.yaml @@ -2,6 +2,8 @@ apiVersion: cozystack.io/v1alpha1 kind: WorkloadMonitor metadata: name: {{ $.Release.Name }} + labels: + workloads.cozystack.io/resource-preset: {{ .Values.resourcesPreset | quote }} spec: replicas: {{ .Values.replicas }} minReplicas: 1 diff --git a/packages/apps/vpn/values.schema.json b/packages/apps/vpn/values.schema.json index 13921381..abfd7b52 100644 --- a/packages/apps/vpn/values.schema.json +++ b/packages/apps/vpn/values.schema.json @@ -1,49 +1,90 @@ { - "title": "Chart Values", - "type": "object", - "properties": { - "external": { - "type": "boolean", - "description": "Enable external access from outside the cluster", - "default": false - }, - "replicas": { - "type": "number", - "description": "Number of VPN server replicas", - "default": 2 - }, - "host": { - "type": "string", - "description": "Host used to substitute into generated URLs", - "default": "" - }, - "externalIPs": { - "type": "array", - "description": "List of externalIPs for service. Optional. If not specified will use LoadBalancer service by default.", - "default": "[]", - "items": { - "type": "string" + "title": "Chart Values", + "type": "object", + "properties": { + "replicas": { + "description": "Number of VPN server replicas.", + "type": "integer", + "default": 2 + }, + "resources": { + "description": "Explicit CPU and memory configuration for each VPN server replica. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "CPU available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" } + ], + "x-kubernetes-int-or-string": true }, - "resources": { - "type": "object", - "description": "Explicit CPU and memory configuration for each VPN server replica. When left empty, the preset defined in `resourcesPreset` is applied.", - "default": {} - }, - "resourcesPreset": { - "type": "string", - "description": "Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge.", - "default": "nano", - "enum": [ - "none", - "nano", - "micro", - "small", - "medium", - "large", - "xlarge", - "2xlarge" - ] + "memory": { + "description": "Memory (RAM) available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted.", + "type": "string", + "default": "nano", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + }, + "external": { + "description": "Enable external access from outside the cluster.", + "type": "boolean", + "default": false + }, + "host": { + "description": "Host used to substitute into generated URLs.", + "type": "string", + "default": "" + }, + "users": { + "description": "Users configuration map.", + "type": "object", + "default": {}, + "additionalProperties": { + "type": "object", + "properties": { + "password": { + "description": "Password for the user (autogenerated if not provided).", + "type": "string" + } + } + } + }, + "externalIPs": { + "description": "List of externalIPs for service. Optional. If not specified, will use LoadBalancer service by default.", + "type": "array", + "default": [], + "items": { + "type": "string" + } } + } } diff --git a/packages/apps/vpn/values.yaml b/packages/apps/vpn/values.yaml index 9af5f6f2..5923e273 100644 --- a/packages/apps/vpn/values.yaml +++ b/packages/apps/vpn/values.yaml @@ -1,39 +1,49 @@ -## @section Common parameters - -## @param external Enable external access from outside the cluster -## @param replicas Number of VPN server replicas ## -external: false +## @section Common parameters +## + +## @typedef {struct} Resources - Explicit CPU and memory configuration for each VPN server replica. +## @field {quantity} [cpu] - CPU available to each replica. +## @field {quantity} [memory] - Memory (RAM) available to each replica. + +## @enum {string} ResourcesPreset - Default sizing preset. +## @value nano +## @value micro +## @value small +## @value medium +## @value large +## @value xlarge +## @value 2xlarge + +## @param {int} replicas - Number of VPN server replicas. replicas: 2 -## @section Configuration parameters +## @param {Resources} [resources] - Explicit CPU and memory configuration for each VPN server replica. When omitted, the preset defined in `resourcesPreset` is applied. +resources: {} -## @param host Host used to substitute into generated URLs +## @param {ResourcesPreset} resourcesPreset="nano" - Default sizing preset used when `resources` is omitted. +resourcesPreset: "nano" + +## @param {bool} external - Enable external access from outside the cluster. +external: false + +## +## @section Application-specific parameters +## + +## @param {string} host - Host used to substitute into generated URLs. host: "" -## @param users [object] Users configuration +## @typedef {struct} User - User configuration. +## @field {string} [password] - Password for the user (autogenerated if not provided). + +## @param {map[string]User} users - Users configuration map. +users: {} ## Example: ## users: ## user1: ## password: hackme ## user2: {} # autogenerated password -users: {} -## @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" -## +## @param {[]string} externalIPs - List of externalIPs for service. Optional. If not specified, will use LoadBalancer service by default. externalIPs: [] - -## @param resources Explicit CPU and memory configuration for each VPN server replica. When left empty, the preset defined in `resourcesPreset` is applied. -resources: {} -# resources: -# cpu: 4000m -# memory: 4Gi - -## @param resourcesPreset Default sizing preset used when `resources` is omitted. Allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge. -resourcesPreset: "nano" diff --git a/packages/system/kamaji-etcd/Chart.yaml b/packages/core/flux-aio/Chart.yaml similarity index 83% rename from packages/system/kamaji-etcd/Chart.yaml rename to packages/core/flux-aio/Chart.yaml index 068ef0d0..2e625a16 100644 --- a/packages/system/kamaji-etcd/Chart.yaml +++ b/packages/core/flux-aio/Chart.yaml @@ -1,3 +1,3 @@ apiVersion: v2 -name: cozy-kamaji-etcd +name: cozy-fluxcd version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/core/flux-aio/Makefile b/packages/core/flux-aio/Makefile new file mode 100644 index 00000000..c5eb27f9 --- /dev/null +++ b/packages/core/flux-aio/Makefile @@ -0,0 +1,24 @@ +NAME=flux-aio +NAMESPACE=cozy-$(NAME) + +include ../../../hack/common-envs.mk + +show: + cozyhr show -n $(NAMESPACE) $(NAME) --plain + +apply: + cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- --server-side --force-conflicts + +diff: + cozyhr show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f- + +MANIFESTS_DIR=../../../internal/fluxinstall/manifests + +update: + timoni bundle build -f flux-aio.cue > $(MANIFESTS_DIR)/fluxcd.yaml + yq eval '(select(.kind == "Namespace") | .metadata.labels."pod-security.kubernetes.io/enforce") = "privileged"' -i $(MANIFESTS_DIR)/fluxcd.yaml + sed -i $(MANIFESTS_DIR)/fluxcd.yaml \ + -e '/timoni/d' \ + -e 's|\.cluster\.local\.,||g' -e 's|\.cluster\.local\,||g' -e 's|\.cluster\.local\.||g' \ + -e 's|--storage-adv-addr=source-watcher.$$(RUNTIME_NAMESPACE).svc|--storage-adv-addr=flux.$$(RUNTIME_NAMESPACE).svc|' + yq eval '.spec.template.spec.containers[0].image = "'"$$(yq eval 'select(.kind == "Deployment" and .metadata.name == "flux") | .spec.template.spec.containers[] | select(.name == "helm-controller").image' $(MANIFESTS_DIR)/fluxcd.yaml)"'"' -i $(MANIFESTS_DIR)/fluxcd-tenants.yaml diff --git a/packages/core/flux-aio/flux-aio.cue b/packages/core/flux-aio/flux-aio.cue new file mode 100644 index 00000000..e47d20aa --- /dev/null +++ b/packages/core/flux-aio/flux-aio.cue @@ -0,0 +1,29 @@ +bundle: { + apiVersion: "v1alpha1" + name: "flux-aio" + instances: { + "flux": { + module: { + url: "oci://ghcr.io/stefanprodan/modules/flux-aio" + version: "latest" + } + namespace: "cozy-fluxcd" + values: { + securityProfile: "privileged" + tolerations: [{ + operator: "Exists" + key: "node.kubernetes.io/not-ready" + }, { + operator: "Exists" + key: "node.kubernetes.io/unreachable" + }, { + operator: "Exists" + key: "node.cilium.io/agent-not-ready" + }, { + operator: "Exists" + key: "node.cloudprovider.kubernetes.io/uninitialized" + }] + } + } + } +} diff --git a/packages/core/flux-aio/manifests b/packages/core/flux-aio/manifests new file mode 120000 index 00000000..f9bb5aad --- /dev/null +++ b/packages/core/flux-aio/manifests @@ -0,0 +1 @@ +../../../internal/fluxinstall/manifests \ No newline at end of file diff --git a/packages/core/installer/.helmignore b/packages/core/installer/.helmignore new file mode 100644 index 00000000..6901ff3d --- /dev/null +++ b/packages/core/installer/.helmignore @@ -0,0 +1,9 @@ +# VCS and IDE +.git +.gitignore + +# Build artifacts +Makefile +images/ +example/ +*.tgz diff --git a/packages/core/installer/Makefile b/packages/core/installer/Makefile index 6a694e03..a661bed4 100644 --- a/packages/core/installer/Makefile +++ b/packages/core/installer/Makefile @@ -1,67 +1,52 @@ NAME=installer NAMESPACE=cozy-system -TALOS_VERSION=$(shell awk '/^version:/ {print $$2}' images/talos/profiles/installer.yaml) - -include ../../../scripts/common-envs.mk +include ../../../hack/common-envs.mk pre-checks: ../../../hack/pre-checks.sh show: - cozypkg show -n $(NAMESPACE) $(NAME) --plain + cozyhr show --namespace $(NAMESPACE) $(NAME) --plain apply: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- + cozyhr show --namespace $(NAMESPACE) $(NAME) --plain | kubectl apply -f - diff: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f - + cozyhr show --namespace $(NAMESPACE) $(NAME) --plain | kubectl diff -f - -update: - hack/gen-profiles.sh +image: pre-checks image-operator image-packages chart -image: pre-checks image-matchbox image-cozystack image-talos - -image-cozystack: - docker buildx build -f images/cozystack/Dockerfile ../../.. \ - --provenance false \ - --tag $(REGISTRY)/installer:$(call settag,$(TAG)) \ - --cache-from type=registry,ref=$(REGISTRY)/installer:latest \ - --platform linux/amd64 \ +image-operator: + docker buildx build -f images/cozystack-operator/Dockerfile ../../.. \ + --tag $(REGISTRY)/cozystack-operator:$(call settag,$(TAG)) \ + --build-arg VERSION=$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/cozystack-operator:latest \ --cache-to type=inline \ - --metadata-file images/installer.json \ - --push=$(PUSH) \ - --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ - --load=$(LOAD) - IMAGE="$(REGISTRY)/installer:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/installer.json -o json -r)" \ - yq -i '.cozystack.image = strenv(IMAGE)' values.yaml - rm -f images/installer.json + --metadata-file images/cozystack-operator.json \ + $(BUILDX_ARGS) + IMAGE="$(REGISTRY)/cozystack-operator:$(call settag,$(TAG))@$$(yq -e '.["containerimage.digest"]' images/cozystack-operator.json -o json -r)" \ + yq -i '.cozystackOperator.image = strenv(IMAGE)' values.yaml + rm -f images/cozystack-operator.json -image-talos: - test -f ../../../_out/assets/installer-amd64.tar || make talos-installer - skopeo copy docker-archive:../../../_out/assets/installer-amd64.tar docker://$(REGISTRY)/talos:$(call settag,$(TALOS_VERSION)) +image-packages: + mkdir -p ../../../_out/assets images + echo $$(git rev-parse HEAD; git diff HEAD; git ls-files --others --exclude-standard) | shasum -a 256 > ../platform/.build-revision + flux push artifact \ + oci://$(REGISTRY)/cozystack-packages:$(call settag,$(TAG)) \ + --path=../../../packages \ + --source=https://github.com/cozystack/cozystack \ + --revision="$$(git describe --tags):$$(git rev-parse HEAD)" \ + 2>&1 | tee images/cozystack-packages.log + export REPO="oci://$(REGISTRY)/cozystack-packages" \ + export DIGEST=$$(awk -F @ '/artifact successfully pushed/ {print $$2}' images/cozystack-packages.log) && \ + rm -f images/cozystack-packages.log && \ + test -n "$$DIGEST" && \ + yq -i '.cozystackOperator.platformSourceUrl = strenv(REPO)' values.yaml && \ + yq -i '.cozystackOperator.platformSourceRef = "digest=" + strenv(DIGEST)' values.yaml -image-matchbox: - test -f ../../../_out/assets/kernel-amd64 || make talos-kernel - test -f ../../../_out/assets/initramfs-metal-amd64.xz || make talos-initramfs - docker buildx build -f images/matchbox/Dockerfile ../../.. \ - --provenance false \ - --tag $(REGISTRY)/matchbox:$(call settag,$(TAG)) \ - --tag $(REGISTRY)/matchbox:$(call settag,$(TALOS_VERSION)-$(TAG)) \ - --cache-from type=registry,ref=$(REGISTRY)/matchbox:latest \ - --cache-to type=inline \ - --metadata-file images/matchbox.json \ - --push=$(PUSH) \ - --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ - --load=$(LOAD) - echo "$(REGISTRY)/matchbox:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/matchbox.json -o json -r)" \ - > ../../extra/bootbox/images/matchbox.tag - rm -f images/matchbox.json - -assets: talos-iso talos-nocloud talos-metal talos-kernel talos-initramfs - -talos-initramfs talos-kernel talos-installer talos-iso talos-nocloud talos-metal: - mkdir -p ../../../_out/assets - cat images/talos/profiles/$(subst talos-,,$@).yaml | \ - docker run --rm -i -v /dev:/dev --privileged "ghcr.io/siderolabs/imager:$(TALOS_VERSION)" --tar-to-stdout - | \ - tar -C ../../../_out/assets -xzf- +chart: + set -e; \ + PKG=$$(helm package . --version $(COZYSTACK_VERSION) | awk '{print $$NF}'); \ + trap 'rm -f "$$PKG"' EXIT; \ + if [ "$(PUSH)" = "1" ]; then helm push "$$PKG" oci://$(REGISTRY); fi diff --git a/packages/core/installer/example/platform.yaml b/packages/core/installer/example/platform.yaml new file mode 100644 index 00000000..6ec544aa --- /dev/null +++ b/packages/core/installer/example/platform.yaml @@ -0,0 +1,20 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: Package +metadata: + name: cozystack.cozystack-platform +spec: + variant: isp-full + components: + platform: + values: + publishing: + host: "dev5.infra.aenix.org" + apiServerEndpoint: "https://api.dev5.infra.aenix.org" + externalIPs: + - 10.4.0.94 + - 10.4.0.179 + - 10.4.0.26 + authentication: + oidc: + enabled: true diff --git a/packages/core/installer/images/cozystack-operator/Dockerfile b/packages/core/installer/images/cozystack-operator/Dockerfile new file mode 100644 index 00000000..4268b2ba --- /dev/null +++ b/packages/core/installer/images/cozystack-operator/Dockerfile @@ -0,0 +1,24 @@ +FROM golang:1.25-alpine as builder + +ARG TARGETOS +ARG TARGETARCH +ARG VERSION=dev + +RUN apk add --no-cache make git + +COPY . /src/ +WORKDIR /src + +RUN go mod download + +# Build cozystack-operator +RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \ + -ldflags="-w -s -X github.com/cozystack/cozystack/pkg/version.Version=${VERSION}" \ + -o /cozystack-operator \ + ./cmd/cozystack-operator + +FROM alpine:3.22 + +COPY --from=builder /cozystack-operator /usr/bin/cozystack-operator + +ENTRYPOINT ["/usr/bin/cozystack-operator"] diff --git a/packages/core/installer/images/cozystack-operator/Dockerfile.dockerignore b/packages/core/installer/images/cozystack-operator/Dockerfile.dockerignore new file mode 100644 index 00000000..6803982e --- /dev/null +++ b/packages/core/installer/images/cozystack-operator/Dockerfile.dockerignore @@ -0,0 +1,12 @@ +# Exclude everything except src directory +* +!src/** +!api/** +!cmd/** +!hack/** +!internal/** +!packages/** +!pkg/** +!scripts/** +!go.mod +!go.sum diff --git a/packages/core/installer/images/cozystack/Dockerfile b/packages/core/installer/images/cozystack/Dockerfile deleted file mode 100644 index f41d5c89..00000000 --- a/packages/core/installer/images/cozystack/Dockerfile +++ /dev/null @@ -1,49 +0,0 @@ -FROM golang:1.24-alpine as k8s-await-election-builder - -ARG K8S_AWAIT_ELECTION_GITREPO=https://github.com/LINBIT/k8s-await-election -ARG K8S_AWAIT_ELECTION_VERSION=0.4.1 - -# TARGETARCH is a docker special variable: https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope -ARG TARGETARCH - -RUN apk add --no-cache git make -RUN git clone ${K8S_AWAIT_ELECTION_GITREPO} /usr/local/go/k8s-await-election/ \ - && cd /usr/local/go/k8s-await-election \ - && git reset --hard v${K8S_AWAIT_ELECTION_VERSION} \ - && make \ - && mv ./out/k8s-await-election-${TARGETARCH} /k8s-await-election - -FROM golang:1.24-alpine as builder - -ARG TARGETOS -ARG TARGETARCH - -RUN apk add --no-cache make git -RUN apk add helm --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community - -COPY . /src/ -WORKDIR /src - -RUN go mod download - -RUN go build -o /cozystack-assets-server -ldflags '-extldflags "-static" -w -s' ./cmd/cozystack-assets-server - -RUN make repos - -FROM alpine:3.22 - -RUN wget -O- https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/install.sh | sh -s -- -v 1.1.0 - -RUN apk add --no-cache make kubectl coreutils - -COPY --from=builder /src/scripts /cozystack/scripts -COPY --from=builder /src/packages/core /cozystack/packages/core -COPY --from=builder /src/packages/system /cozystack/packages/system -COPY --from=builder /src/_out/repos /cozystack/assets/repos -COPY --from=builder /src/_out/logos /cozystack/assets/logos -COPY --from=builder /cozystack-assets-server /usr/bin/cozystack-assets-server -COPY --from=k8s-await-election-builder /k8s-await-election /usr/bin/k8s-await-election -COPY --from=builder /src/dashboards /cozystack/assets/dashboards - -WORKDIR /cozystack -ENTRYPOINT ["/usr/bin/k8s-await-election", "/cozystack/scripts/installer.sh" ] diff --git a/packages/core/installer/images/cozystack/Dockerfile.dockerignore b/packages/core/installer/images/cozystack/Dockerfile.dockerignore deleted file mode 100644 index c1d18d8a..00000000 --- a/packages/core/installer/images/cozystack/Dockerfile.dockerignore +++ /dev/null @@ -1 +0,0 @@ -_out diff --git a/packages/core/installer/images/talos/profiles/initramfs.yaml b/packages/core/installer/images/talos/profiles/initramfs.yaml deleted file mode 100644 index fea9fe1d..00000000 --- a/packages/core/installer/images/talos/profiles/initramfs.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# this file generated by hack/gen-profiles.sh -# do not edit it -arch: amd64 -platform: metal -secureboot: false -version: v1.10.3 -input: - kernel: - path: /usr/install/amd64/vmlinuz - initramfs: - path: /usr/install/amd64/initramfs.xz - baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.10.3" - systemExtensions: - - imageRef: ghcr.io/siderolabs/amd-ucode:20250509 - - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250509 - - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250509 - - imageRef: ghcr.io/siderolabs/intel-ucode:20250211 - - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250509 - - imageRef: ghcr.io/siderolabs/drbd:9.2.13-v1.10.3 - - imageRef: ghcr.io/siderolabs/zfs:2.3.2-v1.10.3 -output: - kind: initramfs - imageOptions: {} - outFormat: raw diff --git a/packages/core/installer/images/talos/profiles/installer.yaml b/packages/core/installer/images/talos/profiles/installer.yaml deleted file mode 100644 index 524cf448..00000000 --- a/packages/core/installer/images/talos/profiles/installer.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# this file generated by hack/gen-profiles.sh -# do not edit it -arch: amd64 -platform: metal -secureboot: false -version: v1.10.3 -input: - kernel: - path: /usr/install/amd64/vmlinuz - initramfs: - path: /usr/install/amd64/initramfs.xz - baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.10.3" - systemExtensions: - - imageRef: ghcr.io/siderolabs/amd-ucode:20250509 - - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250509 - - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250509 - - imageRef: ghcr.io/siderolabs/intel-ucode:20250211 - - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250509 - - imageRef: ghcr.io/siderolabs/drbd:9.2.13-v1.10.3 - - imageRef: ghcr.io/siderolabs/zfs:2.3.2-v1.10.3 -output: - kind: installer - imageOptions: {} - outFormat: raw diff --git a/packages/core/installer/images/talos/profiles/iso.yaml b/packages/core/installer/images/talos/profiles/iso.yaml deleted file mode 100644 index 087509a8..00000000 --- a/packages/core/installer/images/talos/profiles/iso.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# this file generated by hack/gen-profiles.sh -# do not edit it -arch: amd64 -platform: metal -secureboot: false -version: v1.10.3 -input: - kernel: - path: /usr/install/amd64/vmlinuz - initramfs: - path: /usr/install/amd64/initramfs.xz - baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.10.3" - systemExtensions: - - imageRef: ghcr.io/siderolabs/amd-ucode:20250509 - - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250509 - - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250509 - - imageRef: ghcr.io/siderolabs/intel-ucode:20250211 - - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250509 - - imageRef: ghcr.io/siderolabs/drbd:9.2.13-v1.10.3 - - imageRef: ghcr.io/siderolabs/zfs:2.3.2-v1.10.3 -output: - kind: iso - imageOptions: {} - outFormat: raw diff --git a/packages/core/installer/images/talos/profiles/kernel.yaml b/packages/core/installer/images/talos/profiles/kernel.yaml deleted file mode 100644 index 2acf9d20..00000000 --- a/packages/core/installer/images/talos/profiles/kernel.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# this file generated by hack/gen-profiles.sh -# do not edit it -arch: amd64 -platform: metal -secureboot: false -version: v1.10.3 -input: - kernel: - path: /usr/install/amd64/vmlinuz - initramfs: - path: /usr/install/amd64/initramfs.xz - baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.10.3" - systemExtensions: - - imageRef: ghcr.io/siderolabs/amd-ucode:20250509 - - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250509 - - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250509 - - imageRef: ghcr.io/siderolabs/intel-ucode:20250211 - - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250509 - - imageRef: ghcr.io/siderolabs/drbd:9.2.13-v1.10.3 - - imageRef: ghcr.io/siderolabs/zfs:2.3.2-v1.10.3 -output: - kind: kernel - imageOptions: {} - outFormat: raw diff --git a/packages/core/installer/images/talos/profiles/metal.yaml b/packages/core/installer/images/talos/profiles/metal.yaml deleted file mode 100644 index cb5c9894..00000000 --- a/packages/core/installer/images/talos/profiles/metal.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# this file generated by hack/gen-profiles.sh -# do not edit it -arch: amd64 -platform: metal -secureboot: false -version: v1.10.3 -input: - kernel: - path: /usr/install/amd64/vmlinuz - initramfs: - path: /usr/install/amd64/initramfs.xz - baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.10.3" - systemExtensions: - - imageRef: ghcr.io/siderolabs/amd-ucode:20250509 - - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250509 - - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250509 - - imageRef: ghcr.io/siderolabs/intel-ucode:20250211 - - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250509 - - imageRef: ghcr.io/siderolabs/drbd:9.2.13-v1.10.3 - - imageRef: ghcr.io/siderolabs/zfs:2.3.2-v1.10.3 -output: - kind: image - imageOptions: { diskSize: 1306525696, diskFormat: raw } - outFormat: .xz diff --git a/packages/core/installer/images/talos/profiles/nocloud.yaml b/packages/core/installer/images/talos/profiles/nocloud.yaml deleted file mode 100644 index 87ba635e..00000000 --- a/packages/core/installer/images/talos/profiles/nocloud.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# this file generated by hack/gen-profiles.sh -# do not edit it -arch: amd64 -platform: nocloud -secureboot: false -version: v1.10.3 -input: - kernel: - path: /usr/install/amd64/vmlinuz - initramfs: - path: /usr/install/amd64/initramfs.xz - baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.10.3" - systemExtensions: - - imageRef: ghcr.io/siderolabs/amd-ucode:20250509 - - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20250509 - - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20250509 - - imageRef: ghcr.io/siderolabs/intel-ucode:20250211 - - imageRef: ghcr.io/siderolabs/qlogic-firmware:20250509 - - imageRef: ghcr.io/siderolabs/drbd:9.2.13-v1.10.3 - - imageRef: ghcr.io/siderolabs/zfs:2.3.2-v1.10.3 -output: - kind: image - imageOptions: { diskSize: 1306525696, diskFormat: raw } - outFormat: .xz diff --git a/packages/core/installer/templates/cozystack-operator.yaml b/packages/core/installer/templates/cozystack-operator.yaml new file mode 100644 index 00000000..aded0995 --- /dev/null +++ b/packages/core/installer/templates/cozystack-operator.yaml @@ -0,0 +1,103 @@ +{{- $validVariants := list "talos" "generic" "hosted" -}} +{{- if not (has .Values.cozystackOperator.variant $validVariants) -}} +{{- fail (printf "Invalid cozystackOperator.variant %q: must be one of talos, generic, hosted" .Values.cozystackOperator.variant) -}} +{{- end -}} +--- +apiVersion: v1 +kind: Namespace +metadata: + name: cozy-system + labels: + cozystack.io/system: "true" + pod-security.kubernetes.io/enforce: privileged + annotations: + helm.sh/resource-policy: keep +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: cozystack + namespace: cozy-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cozystack +subjects: +- kind: ServiceAccount + name: cozystack + namespace: cozy-system +roleRef: + kind: ClusterRole + name: cluster-admin + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cozystack-operator + namespace: cozy-system +spec: + replicas: 1 + selector: + matchLabels: + app: cozystack-operator + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 0 + maxUnavailable: 1 + template: + metadata: + labels: + app: cozystack-operator + spec: + serviceAccountName: cozystack + containers: + - name: cozystack-operator + image: "{{ .Values.cozystackOperator.image }}" + args: + - --leader-elect=true + - --install-flux=true + # The operator applies embedded CRDs via server-side apply on every + # startup, ensuring they stay up to date. + # To fully remove CRDs, delete them manually after helm uninstall. + - --install-crds=true + - --metrics-bind-address=0 + - --health-probe-bind-address=0 + {{- if .Values.cozystackOperator.disableTelemetry }} + - --disable-telemetry + {{- end }} + - --platform-source-name=cozystack-platform + - --platform-source-url={{ .Values.cozystackOperator.platformSourceUrl }} + {{- if .Values.cozystackOperator.platformSourceRef }} + - --platform-source-ref={{ .Values.cozystackOperator.platformSourceRef }} + {{- end }} + {{- if eq .Values.cozystackOperator.variant "talos" }} + env: + # Talos KubePrism endpoint + - name: KUBERNETES_SERVICE_HOST + value: "localhost" + - name: KUBERNETES_SERVICE_PORT + value: "7445" + {{- else if eq .Values.cozystackOperator.variant "generic" }} + env: + # Generic Kubernetes: API server endpoint + - name: KUBERNETES_SERVICE_HOST + value: {{ required "cozystack.apiServerHost is required in generic mode" .Values.cozystack.apiServerHost | quote }} + - name: KUBERNETES_SERVICE_PORT + value: {{ .Values.cozystack.apiServerPort | quote }} + {{- else if eq .Values.cozystackOperator.variant "hosted" }} + # Hosted: use in-cluster service account, no env override needed + env: [] + {{- end }} + hostNetwork: true + tolerations: + - key: "node.kubernetes.io/not-ready" + operator: "Exists" + - key: "node.kubernetes.io/unreachable" + operator: "Exists" + - key: "node.cilium.io/agent-not-ready" + operator: "Exists" + - key: "node.cloudprovider.kubernetes.io/uninitialized" + operator: "Exists" diff --git a/packages/core/installer/templates/cozystack.yaml b/packages/core/installer/templates/cozystack.yaml deleted file mode 100644 index 10ebdc1f..00000000 --- a/packages/core/installer/templates/cozystack.yaml +++ /dev/null @@ -1,100 +0,0 @@ ---- -apiVersion: v1 -kind: Namespace -metadata: - name: cozy-system - labels: - cozystack.io/system: "true" - pod-security.kubernetes.io/enforce: privileged ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: cozystack - namespace: cozy-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: cozystack -subjects: -- kind: ServiceAccount - name: cozystack - namespace: cozy-system -roleRef: - kind: ClusterRole - name: cluster-admin - apiGroup: rbac.authorization.k8s.io ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: cozystack - namespace: cozy-system -spec: - replicas: 1 - selector: - matchLabels: - app: cozystack - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 0 - maxUnavailable: 1 - template: - metadata: - labels: - app: cozystack - spec: - hostNetwork: true - serviceAccountName: cozystack - containers: - - name: cozystack - image: "{{ .Values.cozystack.image }}" - env: - - name: KUBERNETES_SERVICE_HOST - value: localhost - - name: KUBERNETES_SERVICE_PORT - value: "7445" - - name: K8S_AWAIT_ELECTION_ENABLED - value: "1" - - name: K8S_AWAIT_ELECTION_NAME - value: cozystack - - name: K8S_AWAIT_ELECTION_LOCK_NAME - value: cozystack - - name: K8S_AWAIT_ELECTION_LOCK_NAMESPACE - value: cozy-system - - name: K8S_AWAIT_ELECTION_IDENTITY - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: assets - image: "{{ .Values.cozystack.image }}" - command: - - /usr/bin/cozystack-assets-server - - "-dir=/cozystack/assets" - - "-address=:8123" - ports: - - name: http - containerPort: 8123 - tolerations: - - key: "node.kubernetes.io/not-ready" - operator: "Exists" - effect: "NoSchedule" - - key: "node.cilium.io/agent-not-ready" - operator: "Exists" - effect: "NoSchedule" ---- -apiVersion: v1 -kind: Service -metadata: - name: cozystack - namespace: cozy-system -spec: - ports: - - name: http - port: 80 - targetPort: 8123 - selector: - app: cozystack - type: ClusterIP diff --git a/packages/core/installer/values.yaml b/packages/core/installer/values.yaml index 39d2f70d..eef691ea 100644 --- a/packages/core/installer/values.yaml +++ b/packages/core/installer/values.yaml @@ -1,2 +1,15 @@ +cozystackOperator: + # Deployment variant: talos, generic, hosted + variant: talos + image: ghcr.io/cozystack/cozystack/cozystack-operator:v1.3.0@sha256:62574f12486bb40c901cf5ed484cca264405ce5810196d86555cbb27cce1ba48 + platformSourceUrl: 'oci://ghcr.io/cozystack/cozystack/cozystack-packages' + platformSourceRef: 'digest=sha256:a0b9ef938446b3132d3d22ad2262beb1027c48c9037b6c2346fdc2f19acd3036' +# Generic variant configuration (only used when cozystackOperator.variant=generic) cozystack: - image: ghcr.io/cozystack/cozystack/installer:v0.33.2@sha256:9d96e8b0398c4847783ea8b866d37a5a7de01fc6b7522764f8b3901cd6709018 + # Kubernetes API server host (IP only, no protocol/port) + # Must be the INTERNAL IP of the control-plane node + # (the IP visible on the node's network interface, not a public/NAT IP) + # Used by the operator and networking components (cilium, kube-ovn) + apiServerHost: "" + # Kubernetes API server port + apiServerPort: "6443" diff --git a/packages/core/platform/Makefile b/packages/core/platform/Makefile index ab0e17bf..15ed7b36 100644 --- a/packages/core/platform/Makefile +++ b/packages/core/platform/Makefile @@ -1,20 +1,28 @@ -NAME=platform +NAME=cozystack-platform NAMESPACE=cozy-system +include ../../../hack/common-envs.mk + show: - cozypkg show -n $(NAMESPACE) $(NAME) --plain + cozyhr show --namespace $(NAMESPACE) $(NAME) apply: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- - kubectl delete helmreleases.helm.toolkit.fluxcd.io -l cozystack.io/marked-for-deletion=true -A + cozyhr apply --namespace $(NAMESPACE) $(NAME) reconcile: apply -namespaces-show: - cozypkg show -n $(NAMESPACE) $(NAME) --plain -s templates/namespaces.yaml - -namespaces-apply: - cozypkg show -n $(NAMESPACE) $(NAME) --plain -s templates/namespaces.yaml | kubectl apply -f- - diff: - cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f- + cozyhr diff --namespace $(NAMESPACE) $(NAME) + +image: image-migrations + +image-migrations: + docker buildx build images/migrations \ + --tag $(REGISTRY)/platform-migrations:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/platform-migrations:latest \ + --cache-to type=inline \ + --metadata-file images/migrations.json \ + $(BUILDX_ARGS) + IMAGE="$(REGISTRY)/platform-migrations:$(call settag,$(TAG))@$$(yq -e -o json -r '.["containerimage.digest"]' images/migrations.json)" \ + yq --inplace '.migrations.image = strenv(IMAGE)' values.yaml + rm -f images/migrations.json diff --git a/packages/core/platform/bundles/distro-full.yaml b/packages/core/platform/bundles/distro-full.yaml deleted file mode 100644 index 3b1bd482..00000000 --- a/packages/core/platform/bundles/distro-full.yaml +++ /dev/null @@ -1,260 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} - -releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: cozy-fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: cozy-fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator,cilium] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - -- name: cilium - releaseName: cilium - chart: cozy-cilium - namespace: cozy-cilium - privileged: true - dependsOn: [] - valuesFiles: - - values.yaml - - values-talos.yaml - values: - cilium: - enableIPv4Masquerade: true - enableIdentityMark: true - ipv4NativeRoutingCIDR: "{{ index $cozyConfig.data "ipv4-pod-cidr" }}" - autoDirectNodeRoutes: true - routingMode: native - -- name: cilium-networkpolicy - releaseName: cilium-networkpolicy - chart: cozy-cilium-networkpolicy - namespace: cozy-cilium - privileged: true - dependsOn: [cilium] - -- name: cozy-proxy - releaseName: cozystack - chart: cozy-cozy-proxy - namespace: cozy-system - optional: true - dependsOn: [cilium] - -- name: cert-manager-crds - releaseName: cert-manager-crds - chart: cozy-cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [cilium] - -- name: cozystack-controller - releaseName: cozystack-controller - chart: cozy-cozystack-controller - namespace: cozy-system - dependsOn: [cilium] - {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} - values: - cozystackController: - disableTelemetry: true - {{- end }} - -- name: cert-manager - releaseName: cert-manager - chart: cozy-cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - -- name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cozy-cert-manager-issuers - namespace: cozy-cert-manager - optional: true - dependsOn: [cilium,cert-manager] - -- name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: cozy-victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - optional: true - dependsOn: [cilium,cert-manager] - -- name: monitoring-agents - releaseName: monitoring-agents - chart: cozy-monitoring-agents - namespace: cozy-monitoring - privileged: true - optional: true - dependsOn: [cilium,victoria-metrics-operator] - values: - scrapeRules: - etcd: - enabled: true - -- name: metallb - releaseName: metallb - chart: cozy-metallb - namespace: cozy-metallb - privileged: true - dependsOn: [cilium] - -- name: etcd-operator - releaseName: etcd-operator - chart: cozy-etcd-operator - namespace: cozy-etcd-operator - optional: true - dependsOn: [cilium,cert-manager] - -- name: grafana-operator - releaseName: grafana-operator - chart: cozy-grafana-operator - namespace: cozy-grafana-operator - optional: true - dependsOn: [cilium] - -- name: mariadb-operator - releaseName: mariadb-operator - chart: cozy-mariadb-operator - namespace: cozy-mariadb-operator - optional: true - dependsOn: [cilium,cert-manager,victoria-metrics-operator] - values: - mariadb-operator: - clusterName: {{ $clusterDomain }} - -- name: postgres-operator - releaseName: postgres-operator - chart: cozy-postgres-operator - namespace: cozy-postgres-operator - optional: true - dependsOn: [cilium,cert-manager,victoria-metrics-operator] - -- name: kafka-operator - releaseName: kafka-operator - chart: cozy-kafka-operator - namespace: cozy-kafka-operator - optional: true - dependsOn: [cilium,victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: {{ $clusterDomain }} - -- name: clickhouse-operator - releaseName: clickhouse-operator - chart: cozy-clickhouse-operator - namespace: cozy-clickhouse-operator - optional: true - dependsOn: [cilium,victoria-metrics-operator] - -- name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: cozy-rabbitmq-operator - namespace: cozy-rabbitmq-operator - optional: true - dependsOn: [cilium] - -- name: redis-operator - releaseName: redis-operator - chart: cozy-redis-operator - namespace: cozy-redis-operator - optional: true - dependsOn: [cilium] - -- name: piraeus-operator - releaseName: piraeus-operator - chart: cozy-piraeus-operator - namespace: cozy-linstor - dependsOn: [cilium,cert-manager] - -- name: snapshot-controller - releaseName: snapshot-controller - chart: cozy-snapshot-controller - namespace: cozy-snapshot-controller - dependsOn: [cilium] - -- name: objectstorage-controller - releaseName: objectstorage-controller - chart: cozy-objectstorage-controller - namespace: cozy-objectstorage-controller - optional: true - dependsOn: [cilium] - -- name: linstor - releaseName: linstor - chart: cozy-linstor - namespace: cozy-linstor - privileged: true - dependsOn: [piraeus-operator,cilium,cert-manager,snapshot-controller] - -- name: nfs-driver - releaseName: nfs-driver - chart: cozy-nfs-driver - namespace: cozy-nfs-driver - privileged: true - dependsOn: [cilium] - optional: true - -- name: telepresence - releaseName: traffic-manager - chart: cozy-telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [] - -- name: external-dns - releaseName: external-dns - chart: cozy-external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [cilium] - -- name: external-secrets-operator - releaseName: external-secrets-operator - chart: cozy-external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [cilium] - -- name: keycloak - releaseName: keycloak - chart: cozy-keycloak - namespace: cozy-keycloak - optional: true - dependsOn: [postgres-operator] - -- name: keycloak-operator - releaseName: keycloak-operator - chart: cozy-keycloak-operator - namespace: cozy-keycloak - optional: true - dependsOn: [keycloak] - -- name: bootbox - releaseName: bootbox - chart: cozy-bootbox - namespace: cozy-bootbox - privileged: true - optional: true - dependsOn: [cilium] - -- name: reloader - releaseName: reloader - chart: cozy-reloader - namespace: cozy-reloader - -- name: velero - releaseName: velero - chart: cozy-velero - namespace: cozy-velero - privileged: true - optional: true - dependsOn: [cilium] diff --git a/packages/core/platform/bundles/distro-hosted.yaml b/packages/core/platform/bundles/distro-hosted.yaml deleted file mode 100644 index 39a5fbd7..00000000 --- a/packages/core/platform/bundles/distro-hosted.yaml +++ /dev/null @@ -1,173 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} - -releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: cozy-fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: cozy-fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - -- name: cert-manager-crds - releaseName: cert-manager-crds - chart: cozy-cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [] - -- name: cozystack-controller - releaseName: cozystack-controller - chart: cozy-cozystack-controller - namespace: cozy-system - {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} - values: - cozystackController: - disableTelemetry: true - {{- end }} - -- name: cert-manager - releaseName: cert-manager - chart: cozy-cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - -- name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cozy-cert-manager-issuers - namespace: cozy-cert-manager - optional: true - dependsOn: [cert-manager] - -- name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: cozy-victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - optional: true - dependsOn: [cert-manager] - -- name: monitoring-agents - releaseName: monitoring-agents - chart: cozy-monitoring-agents - namespace: cozy-monitoring - privileged: true - optional: true - dependsOn: [victoria-metrics-operator] - values: - scrapeRules: - etcd: - enabled: true - -- name: etcd-operator - releaseName: etcd-operator - chart: cozy-etcd-operator - namespace: cozy-etcd-operator - optional: true - dependsOn: [cert-manager] - -- name: grafana-operator - releaseName: grafana-operator - chart: cozy-grafana-operator - namespace: cozy-grafana-operator - optional: true - dependsOn: [] - -- name: mariadb-operator - releaseName: mariadb-operator - chart: cozy-mariadb-operator - namespace: cozy-mariadb-operator - optional: true - dependsOn: [victoria-metrics-operator] - values: - mariadb-operator: - clusterName: {{ $clusterDomain }} - -- name: postgres-operator - releaseName: postgres-operator - chart: cozy-postgres-operator - namespace: cozy-postgres-operator - optional: true - dependsOn: [victoria-metrics-operator] - -- name: kafka-operator - releaseName: kafka-operator - chart: cozy-kafka-operator - namespace: cozy-kafka-operator - optional: true - dependsOn: [victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: {{ $clusterDomain }} - -- name: clickhouse-operator - releaseName: clickhouse-operator - chart: cozy-clickhouse-operator - namespace: cozy-clickhouse-operator - optional: true - dependsOn: [victoria-metrics-operator] - -- name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: cozy-rabbitmq-operator - namespace: cozy-rabbitmq-operator - optional: true - dependsOn: [] - -- name: redis-operator - releaseName: redis-operator - chart: cozy-redis-operator - namespace: cozy-redis-operator - optional: true - dependsOn: [] - -- name: telepresence - releaseName: traffic-manager - chart: cozy-telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [] - -- name: external-dns - releaseName: external-dns - chart: cozy-external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [] - -- name: external-secrets-operator - releaseName: external-secrets-operator - chart: cozy-external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [] - -- name: keycloak - releaseName: keycloak - chart: cozy-keycloak - namespace: cozy-keycloak - optional: true - dependsOn: [postgres-operator] - -- name: keycloak-operator - releaseName: keycloak-operator - chart: cozy-keycloak-operator - namespace: cozy-keycloak - optional: true - dependsOn: [keycloak] - -- name: velero - releaseName: velero - chart: cozy-velero - namespace: cozy-velero - privileged: true - optional: true diff --git a/packages/core/platform/bundles/paas-full.yaml b/packages/core/platform/bundles/paas-full.yaml deleted file mode 100644 index 5f244228..00000000 --- a/packages/core/platform/bundles/paas-full.yaml +++ /dev/null @@ -1,417 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} -{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- if not $host }} -{{- fail "ERROR need root-host in cozystack ConfigMap" }} -{{- end }} -{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} -{{- if not $apiServerEndpoint }} -{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} -{{- end }} - -releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: cozy-fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: cozy-fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator,cilium,kubeovn] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - -- name: cilium - releaseName: cilium - chart: cozy-cilium - namespace: cozy-cilium - privileged: true - dependsOn: [] - valuesFiles: - - values.yaml - - values-talos.yaml - - values-kubeovn.yaml - -- name: cilium-networkpolicy - releaseName: cilium-networkpolicy - chart: cozy-cilium-networkpolicy - namespace: cozy-cilium - privileged: true - dependsOn: [cilium] - -- name: kubeovn - releaseName: kubeovn - chart: cozy-kubeovn - namespace: cozy-kubeovn - privileged: true - dependsOn: [cilium] - values: - cozystack: - nodesHash: {{ include "cozystack.master-node-ips" . | sha256sum }} - kube-ovn: - ipv4: - POD_CIDR: "{{ index $cozyConfig.data "ipv4-pod-cidr" }}" - POD_GATEWAY: "{{ index $cozyConfig.data "ipv4-pod-gateway" }}" - SVC_CIDR: "{{ index $cozyConfig.data "ipv4-svc-cidr" }}" - JOIN_CIDR: "{{ index $cozyConfig.data "ipv4-join-cidr" }}" - -- name: kubeovn-webhook - releaseName: kubeovn-webhook - chart: cozy-kubeovn-webhook - namespace: cozy-kubeovn - privileged: true - dependsOn: [cilium,kubeovn,cert-manager] - -- name: cozy-proxy - releaseName: cozystack - chart: cozy-cozy-proxy - namespace: cozy-system - dependsOn: [cilium,kubeovn] - -- name: cert-manager-crds - releaseName: cert-manager-crds - chart: cozy-cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [cilium, kubeovn] - -- name: cozystack-api - releaseName: cozystack-api - chart: cozy-cozystack-api - namespace: cozy-system - dependsOn: [cilium,kubeovn] - -- name: cozystack-controller - releaseName: cozystack-controller - chart: cozy-cozystack-controller - namespace: cozy-system - dependsOn: [cilium,kubeovn] - {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} - values: - cozystackController: - disableTelemetry: true - {{- end }} - -- name: cert-manager - releaseName: cert-manager - chart: cozy-cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - -- name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cozy-cert-manager-issuers - namespace: cozy-cert-manager - dependsOn: [cilium,kubeovn,cert-manager] - -- name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: cozy-victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - dependsOn: [cilium,kubeovn,cert-manager] - -- name: monitoring-agents - releaseName: monitoring-agents - chart: cozy-monitoring-agents - namespace: cozy-monitoring - privileged: true - dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] - values: - scrapeRules: - etcd: - enabled: true - -- name: kubevirt-operator - releaseName: kubevirt-operator - chart: cozy-kubevirt-operator - namespace: cozy-kubevirt - dependsOn: [cilium,kubeovn,victoria-metrics-operator] - -- name: kubevirt - releaseName: kubevirt - chart: cozy-kubevirt - 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 - chart: cozy-kubevirt-instancetypes - namespace: cozy-kubevirt - dependsOn: [cilium,kubeovn,kubevirt-operator,kubevirt] - -- name: kubevirt-cdi-operator - releaseName: kubevirt-cdi-operator - chart: cozy-kubevirt-cdi-operator - namespace: cozy-kubevirt-cdi - dependsOn: [cilium,kubeovn] - -- name: kubevirt-cdi - releaseName: kubevirt-cdi - chart: cozy-kubevirt-cdi - namespace: cozy-kubevirt-cdi - dependsOn: [cilium,kubeovn,kubevirt-cdi-operator] - -- name: gpu-operator - releaseName: gpu-operator - chart: cozy-gpu-operator - namespace: cozy-gpu-operator - privileged: true - optional: true - dependsOn: [cilium,kubeovn] - valuesFiles: - - values.yaml - - values-talos.yaml - -- name: metallb - releaseName: metallb - chart: cozy-metallb - namespace: cozy-metallb - privileged: true - dependsOn: [cilium,kubeovn] - -- name: etcd-operator - releaseName: etcd-operator - chart: cozy-etcd-operator - namespace: cozy-etcd-operator - dependsOn: [cilium,kubeovn,cert-manager] - -- name: grafana-operator - releaseName: grafana-operator - chart: cozy-grafana-operator - namespace: cozy-grafana-operator - dependsOn: [cilium,kubeovn] - -- name: mariadb-operator - releaseName: mariadb-operator - chart: cozy-mariadb-operator - namespace: cozy-mariadb-operator - dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] - values: - mariadb-operator: - clusterName: {{ $clusterDomain }} - -- name: postgres-operator - releaseName: postgres-operator - chart: cozy-postgres-operator - namespace: cozy-postgres-operator - dependsOn: [cilium,kubeovn,cert-manager] - -- name: kafka-operator - releaseName: kafka-operator - chart: cozy-kafka-operator - namespace: cozy-kafka-operator - dependsOn: [cilium,kubeovn,victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: {{ $clusterDomain }} - -- name: clickhouse-operator - releaseName: clickhouse-operator - chart: cozy-clickhouse-operator - namespace: cozy-clickhouse-operator - dependsOn: [cilium,kubeovn,victoria-metrics-operator] - -- name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: cozy-rabbitmq-operator - namespace: cozy-rabbitmq-operator - dependsOn: [cilium,kubeovn] - -- name: redis-operator - releaseName: redis-operator - chart: cozy-redis-operator - namespace: cozy-redis-operator - dependsOn: [cilium,kubeovn] - -- name: piraeus-operator - releaseName: piraeus-operator - chart: cozy-piraeus-operator - namespace: cozy-linstor - dependsOn: [cilium,kubeovn,cert-manager,victoria-metrics-operator] - -- name: linstor - releaseName: linstor - chart: cozy-linstor - namespace: cozy-linstor - privileged: true - dependsOn: [piraeus-operator,cilium,kubeovn,cert-manager,snapshot-controller] - -- name: nfs-driver - releaseName: nfs-driver - chart: cozy-nfs-driver - namespace: cozy-nfs-driver - privileged: true - dependsOn: [cilium,kubeovn] - optional: true - -- name: snapshot-controller - releaseName: snapshot-controller - chart: cozy-snapshot-controller - namespace: cozy-snapshot-controller - dependsOn: [cilium,kubeovn,cert-manager-issuers] - -- name: objectstorage-controller - releaseName: objectstorage-controller - chart: cozy-objectstorage-controller - namespace: cozy-objectstorage-controller - dependsOn: [cilium,kubeovn] - -- name: telepresence - releaseName: traffic-manager - chart: cozy-telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [cilium,kubeovn] - -- name: dashboard - releaseName: dashboard - chart: cozy-dashboard - namespace: cozy-dashboard - values: - {{- $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" }} - - keycloak-configure - {{- end }} - -- name: kamaji - releaseName: kamaji - chart: cozy-kamaji - namespace: cozy-kamaji - dependsOn: [cilium,kubeovn,cert-manager] - -- name: capi-operator - releaseName: capi-operator - chart: cozy-capi-operator - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,cert-manager] - -- name: capi-providers-bootstrap - releaseName: capi-providers-bootstrap - chart: cozy-capi-providers-bootstrap - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - -- name: capi-providers-core - releaseName: capi-providers-core - chart: cozy-capi-providers-core - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - -- name: capi-providers-cpprovider - releaseName: capi-providers-cpprovider - chart: cozy-capi-providers-cpprovider - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - -- name: capi-providers-infraprovider - releaseName: capi-providers-infraprovider - chart: cozy-capi-providers-infraprovider - namespace: cozy-cluster-api - privileged: true - dependsOn: [cilium,kubeovn,capi-operator] - -- name: external-dns - releaseName: external-dns - chart: cozy-external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [cilium,kubeovn] - -- name: external-secrets-operator - releaseName: external-secrets-operator - chart: cozy-external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [cilium,kubeovn] - -- name: bootbox - releaseName: bootbox - chart: cozy-bootbox - namespace: cozy-bootbox - privileged: true - optional: true - dependsOn: [cilium,kubeovn] - -{{- if $oidcEnabled }} -- name: keycloak - releaseName: keycloak - chart: cozy-keycloak - namespace: cozy-keycloak - dependsOn: [postgres-operator] - -- name: keycloak-operator - releaseName: keycloak-operator - chart: cozy-keycloak-operator - namespace: cozy-keycloak - dependsOn: [keycloak] - -- name: keycloak-configure - releaseName: keycloak-configure - chart: cozy-keycloak-configure - namespace: cozy-keycloak - dependsOn: [keycloak-operator] - values: - cozystack: - configHash: {{ $cozyConfig | toJson | sha256sum }} -{{- end }} - -- name: goldpinger - releaseName: goldpinger - chart: cozy-goldpinger - namespace: cozy-goldpinger - privileged: true - dependsOn: [monitoring-agents] - -- name: vertical-pod-autoscaler - releaseName: vertical-pod-autoscaler - chart: cozy-vertical-pod-autoscaler - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [monitoring-agents] - values: - vertical-pod-autoscaler: - recommender: - extraArgs: - prometheus-address: http://vmselect-shortterm.tenant-root.svc.{{ $clusterDomain }}:8481/select/0/prometheus/ - -- name: vertical-pod-autoscaler-crds - releaseName: vertical-pod-autoscaler-crds - chart: cozy-vertical-pod-autoscaler-crds - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [cilium, kubeovn] - -- name: reloader - releaseName: reloader - chart: cozy-reloader - namespace: cozy-reloader - -- name: velero - releaseName: velero - chart: cozy-velero - namespace: cozy-velero - privileged: true - optional: true - dependsOn: [monitoring-agents] diff --git a/packages/core/platform/bundles/paas-hosted.yaml b/packages/core/platform/bundles/paas-hosted.yaml deleted file mode 100644 index 77d53efe..00000000 --- a/packages/core/platform/bundles/paas-hosted.yaml +++ /dev/null @@ -1,240 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} -{{- $oidcEnabled := index $cozyConfig.data "oidc-enabled" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- if not $host }} -{{- fail "ERROR need root-host in cozystack ConfigMap" }} -{{- end }} -{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} -{{- if not $apiServerEndpoint }} -{{- fail "ERROR need api-server-endpoint in cozystack ConfigMap" }} -{{- end }} - -releases: -- name: fluxcd-operator - releaseName: fluxcd-operator - chart: cozy-fluxcd-operator - namespace: cozy-fluxcd - privileged: true - dependsOn: [] - -- name: fluxcd - releaseName: fluxcd - chart: cozy-fluxcd - namespace: cozy-fluxcd - dependsOn: [fluxcd-operator] - values: - flux-instance: - instance: - cluster: - domain: {{ $clusterDomain }} - -- name: cert-manager-crds - releaseName: cert-manager-crds - chart: cozy-cert-manager-crds - namespace: cozy-cert-manager - dependsOn: [] - -- name: cozystack-api - releaseName: cozystack-api - chart: cozy-cozystack-api - namespace: cozy-system - dependsOn: [] - -- name: cozystack-controller - releaseName: cozystack-controller - chart: cozy-cozystack-controller - namespace: cozy-system - dependsOn: [] - {{- if eq (index $cozyConfig.data "telemetry-enabled") "false" }} - values: - cozystackController: - disableTelemetry: true - {{- end }} - -- name: cert-manager - releaseName: cert-manager - chart: cozy-cert-manager - namespace: cozy-cert-manager - dependsOn: [cert-manager-crds] - -- name: cert-manager-issuers - releaseName: cert-manager-issuers - chart: cozy-cert-manager-issuers - namespace: cozy-cert-manager - dependsOn: [cert-manager] - -- name: victoria-metrics-operator - releaseName: victoria-metrics-operator - chart: cozy-victoria-metrics-operator - namespace: cozy-victoria-metrics-operator - dependsOn: [cert-manager] - -- name: monitoring-agents - releaseName: monitoring-agents - chart: cozy-monitoring-agents - namespace: cozy-monitoring - privileged: true - dependsOn: [victoria-metrics-operator, vertical-pod-autoscaler-crds] - values: - scrapeRules: - etcd: - enabled: true - -- name: etcd-operator - releaseName: etcd-operator - chart: cozy-etcd-operator - namespace: cozy-etcd-operator - dependsOn: [cert-manager] - -- name: grafana-operator - releaseName: grafana-operator - chart: cozy-grafana-operator - namespace: cozy-grafana-operator - dependsOn: [] - -- name: mariadb-operator - releaseName: mariadb-operator - chart: cozy-mariadb-operator - namespace: cozy-mariadb-operator - dependsOn: [cert-manager,victoria-metrics-operator] - values: - mariadb-operator: - clusterName: {{ $clusterDomain }} - -- name: postgres-operator - releaseName: postgres-operator - chart: cozy-postgres-operator - namespace: cozy-postgres-operator - dependsOn: [cert-manager,victoria-metrics-operator] - -- name: kafka-operator - releaseName: kafka-operator - chart: cozy-kafka-operator - namespace: cozy-kafka-operator - dependsOn: [victoria-metrics-operator] - values: - strimzi-kafka-operator: - kubernetesServiceDnsDomain: {{ $clusterDomain }} - -- name: clickhouse-operator - releaseName: clickhouse-operator - chart: cozy-clickhouse-operator - namespace: cozy-clickhouse-operator - dependsOn: [victoria-metrics-operator] - -- name: rabbitmq-operator - releaseName: rabbitmq-operator - chart: cozy-rabbitmq-operator - namespace: cozy-rabbitmq-operator - dependsOn: [] - -- name: redis-operator - releaseName: redis-operator - chart: cozy-redis-operator - namespace: cozy-redis-operator - dependsOn: [] - -- name: piraeus-operator - releaseName: piraeus-operator - chart: cozy-piraeus-operator - namespace: cozy-linstor - dependsOn: [cert-manager] - -- name: objectstorage-controller - releaseName: objectstorage-controller - chart: cozy-objectstorage-controller - namespace: cozy-objectstorage-controller - dependsOn: [] - -- name: telepresence - releaseName: traffic-manager - chart: cozy-telepresence - namespace: cozy-telepresence - optional: true - dependsOn: [] - -- name: external-dns - releaseName: external-dns - chart: cozy-external-dns - namespace: cozy-external-dns - optional: true - dependsOn: [] - -- name: external-secrets-operator - releaseName: external-secrets-operator - chart: cozy-external-secrets-operator - namespace: cozy-external-secrets-operator - optional: true - dependsOn: [] - -- name: dashboard - releaseName: dashboard - chart: cozy-dashboard - namespace: cozy-dashboard - values: - {{- $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 }} - dependsOn: [] - {{- end }} - -{{- if $oidcEnabled }} -- name: keycloak - releaseName: keycloak - chart: cozy-keycloak - namespace: cozy-keycloak - dependsOn: [postgres-operator] - -- name: keycloak-operator - releaseName: keycloak-operator - chart: cozy-keycloak-operator - namespace: cozy-keycloak - dependsOn: [keycloak] - -- name: keycloak-configure - releaseName: keycloak-configure - chart: cozy-keycloak-configure - namespace: cozy-keycloak - dependsOn: [keycloak-operator] - values: - cozystack: - configHash: {{ $cozyConfig | toJson | sha256sum }} -{{- end }} - -- name: goldpinger - releaseName: goldpinger - chart: cozy-goldpinger - namespace: cozy-goldpinger - privileged: true - dependsOn: [monitoring-agents] - -- name: vertical-pod-autoscaler - releaseName: vertical-pod-autoscaler - chart: cozy-vertical-pod-autoscaler - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [monitoring-agents] - values: - vertical-pod-autoscaler: - recommender: - extraArgs: - prometheus-address: http://vmselect-shortterm.tenant-root.svc.{{ $clusterDomain }}:8481/select/0/prometheus/ - -- name: vertical-pod-autoscaler-crds - releaseName: vertical-pod-autoscaler-crds - chart: cozy-vertical-pod-autoscaler-crds - namespace: cozy-vertical-pod-autoscaler - privileged: true - dependsOn: [] - -- name: velero - releaseName: velero - chart: cozy-velero - namespace: cozy-velero - privileged: true - optional: true - dependsOn: [monitoring-agents] diff --git a/packages/core/platform/images/migrations/Dockerfile b/packages/core/platform/images/migrations/Dockerfile new file mode 100644 index 00000000..b35808d5 --- /dev/null +++ b/packages/core/platform/images/migrations/Dockerfile @@ -0,0 +1,12 @@ +FROM alpine:3.22 + +RUN wget -O- https://github.com/cozystack/cozyhr/raw/refs/heads/main/hack/install.sh | sh -s -- -v 1.6.1 + +RUN apk add --no-cache kubectl helm coreutils git jq ca-certificates bash curl + +COPY migrations /migrations +COPY run-migrations.sh /usr/bin/run-migrations.sh + +WORKDIR /migrations + +ENTRYPOINT ["/usr/bin/run-migrations.sh"] diff --git a/scripts/migrations/1 b/packages/core/platform/images/migrations/migrations/1 similarity index 100% rename from scripts/migrations/1 rename to packages/core/platform/images/migrations/migrations/1 diff --git a/scripts/migrations/10 b/packages/core/platform/images/migrations/migrations/10 old mode 100644 new mode 100755 similarity index 100% rename from scripts/migrations/10 rename to packages/core/platform/images/migrations/migrations/10 diff --git a/scripts/migrations/11 b/packages/core/platform/images/migrations/migrations/11 similarity index 100% rename from scripts/migrations/11 rename to packages/core/platform/images/migrations/migrations/11 diff --git a/scripts/migrations/12 b/packages/core/platform/images/migrations/migrations/12 similarity index 100% rename from scripts/migrations/12 rename to packages/core/platform/images/migrations/migrations/12 diff --git a/scripts/migrations/13 b/packages/core/platform/images/migrations/migrations/13 similarity index 100% rename from scripts/migrations/13 rename to packages/core/platform/images/migrations/migrations/13 diff --git a/scripts/migrations/14 b/packages/core/platform/images/migrations/migrations/14 similarity index 100% rename from scripts/migrations/14 rename to packages/core/platform/images/migrations/migrations/14 diff --git a/scripts/migrations/15 b/packages/core/platform/images/migrations/migrations/15 old mode 100644 new mode 100755 similarity index 97% rename from scripts/migrations/15 rename to packages/core/platform/images/migrations/migrations/15 index e0d78cfb..fe5c69a9 --- a/scripts/migrations/15 +++ b/packages/core/platform/images/migrations/migrations/15 @@ -21,7 +21,7 @@ kubectl get kuberneteses.apps.cozystack.io -A --no-headers --output=custom-colum done if kubectl get helmrelease kamaji -n cozy-kamaji; then - cozypkg reconcile kamaji -n cozy-kamaji --force + cozyhr reconcile kamaji -n cozy-kamaji --force fi # Write version to cozystack-version config diff --git a/scripts/migrations/16 b/packages/core/platform/images/migrations/migrations/16 similarity index 100% rename from scripts/migrations/16 rename to packages/core/platform/images/migrations/migrations/16 diff --git a/packages/core/platform/images/migrations/migrations/17 b/packages/core/platform/images/migrations/migrations/17 new file mode 100755 index 00000000..9749c0e2 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/17 @@ -0,0 +1,10 @@ +#!/bin/sh +# Migration 17 --> 18 + +# Upgrade kubernetes.apps to new chart version +kubectl get kuberneteses.apps.cozystack.io -A --no-headers --output=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name' | while read NAMESPACE NAME; do + kubectl patch kuberneteses.apps.cozystack.io -n "$NAMESPACE" "$NAME" --type merge -p '{"appVersion":"0.26.1"}' +done + +# Write version to cozystack-version config +kubectl create configmap -n cozy-system cozystack-version --from-literal=version=18 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/18 b/packages/core/platform/images/migrations/migrations/18 new file mode 100755 index 00000000..4a166fab --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/18 @@ -0,0 +1,18 @@ +#!/bin/sh +# Migration 18 --> 19 + +# Upgrade tenants.apps to new chart version +kubectl get tenants.apps.cozystack.io -A --no-headers --output=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name' | while read NAMESPACE NAME; do + kubectl patch tenants.apps.cozystack.io -n "$NAMESPACE" "$NAME" --type merge -p '{"appVersion":"1.13.0"}' +done + +# Upgrade virtualmachines.apps to new chart version +kubectl get virtualmachines.apps.cozystack.io -A --no-headers --output=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name' | while read NAMESPACE NAME; do + kubectl patch virtualmachines.apps.cozystack.io -n "$NAMESPACE" "$NAME" --type merge -p '{"appVersion":"0.14.0"}' +done +kubectl get vminstances.apps.cozystack.io -A --no-headers --output=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name' | while read NAMESPACE NAME; do + kubectl patch vminstances.apps.cozystack.io -n "$NAMESPACE" "$NAME" --type merge -p '{"appVersion":"0.12.0"}' +done + +# Write version to cozystack-version config +kubectl create configmap -n cozy-system cozystack-version --from-literal=version=19 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/19 b/packages/core/platform/images/migrations/migrations/19 new file mode 100755 index 00000000..446e10ad --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/19 @@ -0,0 +1,53 @@ +#!/bin/sh +# Migration 19 --> 20 + +set -euo pipefail + +kubectl get helmreleases.helm.toolkit.fluxcd.io -A \ + --field-selector=metadata.name=seaweedfs -o json | jq -r ' + .items[] as $o + | ($o.metadata.namespace // "") as $ns + | $o.metadata.name as $name + | $o.spec as $s + | $o.spec.values as $v + + | ( + ($s.chart.spec.version? // "") != "0.7.0" + or ($v.size? != null) + or ($v.storageClass? != null) + or ($v.replicas? != null) + or ($v.zones? != null) + ) as $needsChange + | select($needsChange) + + # JSON Patch + | [ + (if $s.chart.spec.version? then + {op:"replace", path:"/spec/chart/spec/version", value:"0.7.0"} + else + {op:"add", path:"/spec/chart/spec/version", value:"0.7.0"} + end), + + (if ($v|type) != "object" then {op:"add", path:"/spec/values", value:{}} else empty end), + + (if ($v.volume?|type) != "object" then {op:"add", path:"/spec/values/volume", value:{}} else empty end), + + (if $v.size? then {op:"add", path:"/spec/values/volume/size", value:$v.size} else empty end), + (if $v.storageClass? then {op:"add", path:"/spec/values/volume/storageClass", value:$v.storageClass} else empty end), + (if $v.replicas? then {op:"add", path:"/spec/values/volume/replicas", value:$v.replicas} else empty end), + (if $v.zones? then {op:"add", path:"/spec/values/volume/zones", value:$v.zones} else empty end), + + (if $v.size? then {op:"remove", path:"/spec/values/size"} else empty end), + (if $v.storageClass? then {op:"remove", path:"/spec/values/storageClass"} else empty end), + (if $v.replicas? then {op:"remove", path:"/spec/values/replicas"} else empty end), + (if $v.zones? then {op:"remove", path:"/spec/values/zones"} else empty end) + ] as $patch + + | "kubectl " + + (if $ns != "" then "-n \($ns) " else "" end) + + "patch helmreleases.helm.toolkit.fluxcd.io \($name) --type=json -p '\''\($patch|tojson)'\''" +' | sh -ex + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=20 --dry-run=client -o yaml | kubectl apply -f- diff --git a/scripts/migrations/2 b/packages/core/platform/images/migrations/migrations/2 similarity index 100% rename from scripts/migrations/2 rename to packages/core/platform/images/migrations/migrations/2 diff --git a/packages/core/platform/images/migrations/migrations/20 b/packages/core/platform/images/migrations/migrations/20 new file mode 100755 index 00000000..0c885338 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/20 @@ -0,0 +1,67 @@ +#!/bin/sh +# Migration 20 --> 21 + +set -euo pipefail + +kubectl -n cozy-system delete helmrelease cozystack-api \ + || kubectl -n cozy-system delete deployment cozystack-api --ignore-not-found # fallback to help migration progress if it failed first time +while [ $( kubectl -n cozy-system get po -l app=cozystack-api --no-headers | wc -l ) != 0 ] ; +do + echo "Waiting for Cozystack API pods to be deleted"; + sleep 1 +done + +kubectl -n cozy-system delete helmrelease cozystack-controller \ + || kubectl -n cozy-system delete deployment cozystack-controller --ignore-not-found # same fallback +kubectl delete customresourcedefinitions.apiextensions.k8s.io cozystackresourcedefinitions.cozystack.io --ignore-not-found +while [ $( kubectl -n cozy-system get po -l app=cozystack-controller --no-headers | wc -l ) != 0 ] ; +do + echo "Waiting for Cozystack controller pods to be deleted"; + sleep 1 +done + +kubectl delete helmrelease -n cozy-dashboard dashboard --ignore-not-found +sleep 5 +cozyhr -n cozy-system -C packages/system/cozystack-resource-definition-crd apply cozystack-resource-definition-crd --plain +cozyhr -n cozy-system -C packages/system/cozystack-resource-definitions apply cozystack-resource-definitions --plain +cozyhr -n cozy-system -C packages/system/cozystack-api apply cozystack-api --plain +if kubectl get ds cozystack-api -n cozy-system >/dev/null 2>&1; then + echo "Waiting for cozystack-api daemonset" + kubectl rollout status ds/cozystack-api -n cozy-system --timeout=5m || exit 1 +else + echo "Waiting for cozystack-api deployment" + kubectl rollout status deploy/cozystack-api -n cozy-system --timeout=5m || exit 1 +fi + +cozyhr -n cozy-system -C ./packages/system/cozystack-controller apply cozystack-controller --take-ownership +echo "Waiting for cozystack-controller" +kubectl rollout status deploy/cozystack-controller -n cozy-system --timeout=5m || exit 1 + +cozyhr -n cozy-system -C ./packages/system/lineage-controller-webhook/ apply lineage-controller-webhook --take-ownership +echo "Waiting for lineage-webhook" +kubectl rollout status ds/lineage-controller-webhook -n cozy-system --timeout=5m || exit 1 + +sleep 5 +echo "Running lineage-webhook test" +kubectl delete ns cozy-lineage-webhook-test --ignore-not-found && kubectl create ns cozy-lineage-webhook-test +cleanup_test_ns() { + kubectl delete ns cozy-lineage-webhook-test --ignore-not-found +} +trap cleanup_test_ns ERR +timeout 60 sh -c 'until kubectl -n cozy-lineage-webhook-test create service clusterip lineage-webhook-test --clusterip="None" --dry-run=server; do sleep 1; done' +cleanup_test_ns + +timestamp=$(date --rfc-3339=ns || date) +kubectl get namespace -o custom-columns=NAME:.metadata.name --no-headers | + grep '^tenant-' | + while read namespace ; do + (set -x; \ + kubectl annotate \ + pods,services,pvc,secrets,ingresses.networking.k8s.io,workloadmonitors.cozystack.io \ + -n "$namespace" --all \ + migration.cozystack.io="$timestamp" --overwrite || true) + done + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=21 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/21 b/packages/core/platform/images/migrations/migrations/21 new file mode 100755 index 00000000..bd5fda5f --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/21 @@ -0,0 +1,30 @@ +#!/bin/sh +# Migration 21 --> 22 + +set -euo pipefail + +# Disable pruning on Flux CRDs +for crd in $(kubectl get crd -o name | grep 'fluxcd.io$'); do + kubectl annotate $crd fluxcd.controlplane.io/prune=disabled +done + +# Remove flux instance +if kubectl get fluxinstance flux -n cozy-fluxcd >/dev/null 2>&1; then + kubectl annotate fluxinstance flux -n cozy-fluxcd fluxcd.controlplane.io/reconcile=disabled + kubectl delete fluxinstance flux -n cozy-fluxcd +fi +kubectl delete deploy -n cozy-fluxcd -l app.kubernetes.io/part-of=flux --ignore-not-found +kubectl delete hr -n cozy-fluxcd fluxcd --ignore-not-found --wait=false + +# Remove fluxcd-operator +kubectl delete hr -n cozy-fluxcd fluxcd-operator --ignore-not-found --wait=false +kubectl delete deploy -n cozy-fluxcd flux-operator --ignore-not-found + +# Remove labels from CRDs +for crd in $(kubectl get crd -o name | grep 'fluxcd\.io$'); do + kubectl label $crd fluxcd.controlplane.io/name- fluxcd.controlplane.io/namespace- +done + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=22 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/22 b/packages/core/platform/images/migrations/migrations/22 new file mode 100755 index 00000000..2dc8f281 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/22 @@ -0,0 +1,184 @@ +#!/bin/sh +# Migration 22 --> 23 + +set -euo pipefail + +# Migrate Victoria Metrics Operator CRDs to prometheus-operator-crds Helm release +for crd in $(kubectl get crd -o name | grep 'coreos\.com$'); do + kubectl annotate $crd meta.helm.sh/release-namespace=cozy-victoria-metrics-operator meta.helm.sh/release-name=prometheus-operator-crds --overwrite + kubectl label $crd app.kubernetes.io/managed-by=Helm helm.toolkit.fluxcd.io/namespace=cozy-victoria-metrics-operator helm.toolkit.fluxcd.io/name=prometheus-operator-crds --overwrite +done +kubectl delete secret -n cozy-victoria-metrics-operator -l name=victoria-metrics-operator,owner=helm --ignore-not-found + +# Remove CozyStack Resource Definitions HR +kubectl delete hr -n cozy-system cozystack-resource-definitions --ignore-not-found --wait=false +kubectl delete cozystackresourcedefinitions.cozystack.io --all --ignore-not-found --wait=false + +echo "Migrating HelmReleases: adding application labels for tenant-* namespaces" + +# Function to determine application type from HelmRelease name +determine_app_type() { + local name="$1" + local app_kind="" + local app_name="" + + # Try to match by prefix (longest match first) + case "$name" in + virtual-machine-*) + app_kind="VirtualMachine" + app_name="${name#virtual-machine-}" + ;; + vm-instance-*) + app_kind="VMInstance" + app_name="${name#vm-instance-}" + ;; + vm-disk-*) + app_kind="VMDisk" + app_name="${name#vm-disk-}" + ;; + virtualprivatecloud-*) + app_kind="VirtualPrivateCloud" + app_name="${name#virtualprivatecloud-}" + ;; + http-cache-*) + app_kind="HTTPCache" + app_name="${name#http-cache-}" + ;; + tcp-balancer-*) + app_kind="TCPBalancer" + app_name="${name#tcp-balancer-}" + ;; + clickhouse-*) + app_kind="ClickHouse" + app_name="${name#clickhouse-}" + ;; + foundationdb-*) + app_kind="FoundationDB" + app_name="${name#foundationdb-}" + ;; + ferretdb-*) + app_kind="FerretDB" + app_name="${name#ferretdb-}" + ;; + rabbitmq-*) + app_kind="RabbitMQ" + app_name="${name#rabbitmq-}" + ;; + kubernetes-*) + app_kind="Kubernetes" + app_name="${name#kubernetes-}" + ;; + bucket-*) + app_kind="Bucket" + app_name="${name#bucket-}" + ;; + kafka-*) + app_kind="Kafka" + app_name="${name#kafka-}" + ;; + mysql-*) + app_kind="MySQL" + app_name="${name#mysql-}" + ;; + nats-*) + app_kind="NATS" + app_name="${name#nats-}" + ;; + postgres-*) + app_kind="PostgreSQL" + app_name="${name#postgres-}" + ;; + redis-*) + app_kind="Redis" + app_name="${name#redis-}" + ;; + tenant-*) + app_kind="Tenant" + app_name="${name#tenant-}" + ;; + vpn-*) + app_kind="VPN" + app_name="${name#vpn-}" + ;; + bootbox) + app_kind="BootBox" + app_name="bootbox" + ;; + etcd) + app_kind="Etcd" + app_name="etcd" + ;; + info) + app_kind="Info" + app_name="info" + ;; + ingress|ingress-*) + app_kind="Ingress" + if [ "$name" = "ingress" ]; then + app_name="ingress" + else + app_name="${name#ingress-}" + fi + ;; + monitoring) + app_kind="Monitoring" + app_name="monitoring" + ;; + seaweedfs) + app_kind="SeaweedFS" + app_name="seaweedfs" + ;; + *) + # Unknown type + return 1 + ;; + esac + + echo "$app_kind|$app_name" + return 0 +} + +# Process all HelmReleases in tenant-* namespaces with cozystack.io/ui=true label +kubectl get helmreleases --all-namespaces -l cozystack.io/ui=true -o json | \ + jq -r '.items[] | select(.metadata.namespace | startswith("tenant-")) | "\(.metadata.namespace)|\(.metadata.name)"' | \ + while IFS='|' read -r namespace name; do + echo "Processing HelmRelease $namespace/$name" + + # Determine application type + app_type=$(determine_app_type "$name") + status=$? + if [ $status -ne 0 ] || [ -z "$app_type" ]; then + echo "Warning: Could not determine application type for $namespace/$name, skipping" + continue + fi + + app_kind=$(echo "$app_type" | cut -d'|' -f1) + app_name=$(echo "$app_type" | cut -d'|' -f2) + app_group="apps.cozystack.io" + + # Build labels string + labels="apps.cozystack.io/application.kind=$app_kind" + labels="$labels apps.cozystack.io/application.group=$app_group" + labels="$labels apps.cozystack.io/application.name=$app_name" + + # Apply labels using kubectl label --overwrite + kubectl label helmrelease -n "$namespace" "$name" --overwrite $labels + echo "Added application labels to $namespace/$name: $labels" + done + +echo "Migrating PostgreSQL HelmReleases: adding default version v17" + +# Patch all PostgreSQL HelmReleases to add spec.values.version: v17 +kubectl get helmreleases --all-namespaces -l apps.cozystack.io/application.kind=PostgreSQL -o json | \ + jq -r '.items[] | select(.spec.values.version == null) | "\(.metadata.namespace)|\(.metadata.name)"' | \ + while IFS='|' read -r namespace name; do + echo "Patching PostgreSQL HelmRelease $namespace/$name to add version v17" + kubectl patch helmrelease -n "$namespace" "$name" --type=merge -p '{"spec":{"values":{"version":"v17"}}}' + done + +echo "Migration completed" + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=23 --dry-run=client -o yaml | kubectl apply -f- + diff --git a/packages/core/platform/images/migrations/migrations/23 b/packages/core/platform/images/migrations/migrations/23 new file mode 100755 index 00000000..7cb9c85e --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/23 @@ -0,0 +1,18 @@ +#!/bin/sh +# Migration 23 --> 24 + +set -euo pipefail + +# Remove old cozystack-resource-definition-crd HelmRelease (renamed to application-definition-crd) +kubectl delete hr -n cozy-system cozystack-resource-definition-crd --ignore-not-found + +kubectl delete secrets -n cozy-system $( + kubectl get secrets -n cozy-system \ + -l owner=helm \ + -o jsonpath='{range .items[*]}{.metadata.labels.name}{" "}{.metadata.name}{"\n"}{end}' \ + | awk '$1 ~ /-rd$/ {print $2}' +) --ignore-not-found + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=24 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/24 b/packages/core/platform/images/migrations/migrations/24 new file mode 100755 index 00000000..cb34b041 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/24 @@ -0,0 +1,73 @@ +#!/bin/sh +# Migration 24 --> 25 +# Migrate MongoDB users configuration to new databases format + +set -euo pipefail + +echo "Migrating MongoDB HelmReleases: converting users to databases format" + +# Process all MongoDB HelmReleases +kubectl get helmreleases --all-namespaces -o json | \ + jq -r '.items[] | select(.metadata.name | startswith("mongodb-")) | "\(.metadata.namespace)|\(.metadata.name)"' | \ + while IFS='|' read -r namespace name; do + echo "Processing MongoDB HelmRelease $namespace/$name" + + # Get current spec.values + values=$(kubectl get helmrelease -n "$namespace" "$name" -o jsonpath='{.spec.values}') + + # Check if users exist and have old format (with db and roles fields) + has_old_format=$(echo "$values" | jq -r '.users // {} | to_entries[] | select(.value.db != null or .value.roles != null) | .key' | head -1) + + if [ -z "$has_old_format" ]; then + echo "Skipping $namespace/$name: no users with old format found" + continue + fi + + echo "Converting users configuration for $namespace/$name" + + # Build new configuration using jq + new_values=$(echo "$values" | jq ' + # Extract users and build new format + .users as $old_users | + + # Build databases from user roles + ($old_users // {} | to_entries | reduce .[] as $user ( + {}; + ($user.value.roles // []) as $roles | + reduce $roles[] as $role ( + .; + # Determine role type: readWrite/dbAdmin -> admin, read -> readonly + if ($role.name == "readWrite" or $role.name == "dbAdmin") then + .[$role.db].roles.admin = ((.[$role.db].roles.admin // []) + [$user.key] | unique) + elif ($role.name == "read") then + .[$role.db].roles.readonly = ((.[$role.db].roles.readonly // []) + [$user.key] | unique) + else + . + end + ) + )) as $databases | + + # Build new users (only keep password if present) + ($old_users // {} | to_entries | reduce .[] as $user ( + {}; + if $user.value.password then + .[$user.key] = {password: $user.value.password} + else + .[$user.key] = {} + end + )) as $new_users | + + # Update values + . + {users: $new_users} + (if ($databases | length) > 0 then {databases: $databases} else {} end) + ') + + # Patch the HelmRelease + kubectl patch helmrelease -n "$namespace" "$name" --type=merge -p "{\"spec\":{\"values\":$new_values}}" + echo "Successfully migrated $namespace/$name" + done + +echo "MongoDB migration completed" + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=25 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/25 b/packages/core/platform/images/migrations/migrations/25 new file mode 100755 index 00000000..655cce23 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/25 @@ -0,0 +1,23 @@ +#!/bin/sh +# Migration 25 --> 26 +# Remove legacy installer components during upgrade to v1.0 + +set -euo pipefail + +echo "Removing legacy installer components..." + +# Delete old cozystack installer deployment +kubectl delete deploy cozystack -n cozy-system --ignore-not-found + +# Delete old cozystack-assets statefulset +kubectl delete sts cozystack-assets -n cozy-system --ignore-not-found + +# Delete old bootbox HelmReleases (will be recreated by new platform chart if enabled) +kubectl delete hr bootbox -n cozy-system --ignore-not-found +kubectl delete hr bootbox-rd -n cozy-system --ignore-not-found + +echo "Legacy cleanup completed" + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=26 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/26 b/packages/core/platform/images/migrations/migrations/26 new file mode 100755 index 00000000..96fb9851 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/26 @@ -0,0 +1,172 @@ +#!/bin/sh +# Migration 26 --> 27 +# Migrate monitoring resources from extra/monitoring to system/monitoring +# This migration re-labels resources so they become owned by monitoring-system HelmRelease +# and deletes old helm release secrets so that helm does not diff old vs new chart manifests. + +set -euo pipefail + +echo "Starting monitoring migration to monitoring-system" + +# Function to relabel resources of a given type in a namespace +relabel_resources() { + local ns="$1" + local resource_type="$2" + + # Get resources with monitoring release annotation + local resources + resources=$(kubectl get "$resource_type" -n "$ns" -o json 2>/dev/null | \ + jq -r '.items[] | select(.metadata.annotations["meta.helm.sh/release-name"] == "monitoring") | .metadata.name' 2>/dev/null || true) + + for resource_name in $resources; do + # Skip dashboard-resourcemap resources (they stay with parent monitoring release) + if echo "$resource_name" | grep -q "dashboard-resources"; then + echo " Skipping $resource_type/$resource_name (stays with parent release)" + continue + fi + + echo " Relabeling $resource_type/$resource_name" + + # Update annotations and labels + kubectl annotate "$resource_type" -n "$ns" "$resource_name" \ + meta.helm.sh/release-name=monitoring-system --overwrite 2>/dev/null || true + + kubectl label "$resource_type" -n "$ns" "$resource_name" \ + helm.toolkit.fluxcd.io/name=monitoring-system --overwrite 2>/dev/null || true + done +} + +# Delete all helm release secrets for a given release name in a namespace. +# Uses both label selector and name-pattern matching to ensure complete cleanup. +delete_helm_secrets() { + local ns="$1" + local release="$2" + + # Primary: delete by label selector + kubectl delete secrets -n "$ns" -l "name=${release},owner=helm" --ignore-not-found + + # Fallback: find and delete by name pattern (in case labels were modified) + local remaining + remaining=$(kubectl get secrets -n "$ns" -o name | { grep "^secret/sh\.helm\.release\.v1\.${release}\." || true; }) + if [ -n "$remaining" ]; then + echo " Found secrets not matched by label selector, deleting by name..." + echo "$remaining" | while IFS= read -r secret; do + echo " Deleting $secret" + kubectl delete -n "$ns" "$secret" --ignore-not-found + done + fi + + # Verify all secrets are gone + remaining=$(kubectl get secrets -n "$ns" -o name | { grep "^secret/sh\.helm\.release\.v1\.${release}\." || true; }) + if [ -n "$remaining" ]; then + echo " ERROR: Failed to delete helm release secrets:" + echo "$remaining" + return 1 + fi +} + +# Find all tenant namespaces with monitoring HelmRelease +echo "Finding tenant namespaces with monitoring HelmRelease..." +NAMESPACES=$(kubectl get hr --all-namespaces -l cozystack.io/ui=true --field-selector=metadata.name=monitoring \ + -o jsonpath='{range .items[*]}{.metadata.namespace}{"\n"}{end}' | sort -u) + +if [ -z "$NAMESPACES" ]; then + echo "No monitoring HelmReleases found in tenant namespaces, skipping migration" + kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=27 --dry-run=client -o yaml | kubectl apply -f- + exit 0 +fi + +echo "Found namespaces with monitoring:" +echo "$NAMESPACES" + +# Process each namespace +for ns in $NAMESPACES; do + echo "" + echo "=========================================" + echo "Processing namespace: $ns" + echo "=========================================" + + # Check if monitoring HelmRelease exists + if ! kubectl get hr -n "$ns" monitoring >/dev/null 2>&1; then + echo "No monitoring HelmRelease in $ns, skipping" + continue + fi + + # Step 1: Suspend the HelmRelease + echo "" + echo "Step 1: Suspending HelmRelease monitoring..." + kubectl patch hr -n "$ns" monitoring --type=merge -p '{"spec":{"suspend":true}}' + + # Wait a moment for reconciliation to stop + sleep 2 + + # Step 2: Delete helm secrets for the monitoring release + echo "" + echo "Step 2: Deleting helm secrets for monitoring release..." + delete_helm_secrets "$ns" "monitoring" + + # Step 3: Relabel resources to be owned by monitoring-system + echo "" + echo "Step 3: Relabeling resources to monitoring-system..." + + # Core resources + echo "Processing core resources..." + relabel_resources "$ns" "secrets" + relabel_resources "$ns" "configmaps" + relabel_resources "$ns" "services" + + # Apps resources + echo "Processing apps resources..." + relabel_resources "$ns" "deployments.apps" + + # Networking resources + echo "Processing networking resources..." + relabel_resources "$ns" "ingresses.networking.k8s.io" + + # PostgreSQL operator resources + echo "Processing PostgreSQL resources..." + relabel_resources "$ns" "clusters.postgresql.cnpg.io" + + # Grafana operator resources + echo "Processing Grafana resources..." + relabel_resources "$ns" "grafanas.grafana.integreatly.org" + relabel_resources "$ns" "grafanadashboards.grafana.integreatly.org" + relabel_resources "$ns" "grafanadatasources.grafana.integreatly.org" + + # VictoriaMetrics operator resources + echo "Processing VictoriaMetrics resources..." + relabel_resources "$ns" "vmagents.operator.victoriametrics.com" + relabel_resources "$ns" "vmalerts.operator.victoriametrics.com" + relabel_resources "$ns" "vmalertmanagers.operator.victoriametrics.com" + relabel_resources "$ns" "vmclusters.operator.victoriametrics.com" + relabel_resources "$ns" "vmservicescrapes.operator.victoriametrics.com" + relabel_resources "$ns" "vlogs.operator.victoriametrics.com" + + # VPA resources + echo "Processing VPA resources..." + relabel_resources "$ns" "verticalpodautoscalers.autoscaling.k8s.io" + + # Cozystack resources + echo "Processing Cozystack resources..." + relabel_resources "$ns" "workloadmonitors.cozystack.io" + + # Step 4: Delete the suspended HelmRelease + # Helm secrets are already gone, so flux finalizer will find no release to uninstall + # and will simply remove the finalizer without deleting any resources. + echo "" + echo "Step 4: Deleting suspended HelmRelease monitoring..." + kubectl delete hr -n "$ns" monitoring --ignore-not-found + + echo "" + echo "Completed migration for namespace: $ns" +done + +echo "" +echo "=========================================" +echo "Monitoring migration completed successfully" +echo "=========================================" + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=27 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/27 b/packages/core/platform/images/migrations/migrations/27 new file mode 100755 index 00000000..5708ebbb --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/27 @@ -0,0 +1,29 @@ +#!/bin/sh +# Migration 27 --> 28 + +set -euo pipefail + +# Migrate Piraeus CRDs to piraeus-operator-crds Helm release +for crd in linstorclusters.piraeus.io linstornodeconnections.piraeus.io linstorsatelliteconfigurations.piraeus.io linstorsatellites.piraeus.io; do + if kubectl get crd "$crd" >/dev/null 2>&1; then + echo " Relabeling CRD $crd" + kubectl annotate crd "$crd" meta.helm.sh/release-namespace=cozy-linstor meta.helm.sh/release-name=piraeus-operator-crds --overwrite + kubectl label crd "$crd" app.kubernetes.io/managed-by=Helm helm.toolkit.fluxcd.io/namespace=cozy-linstor helm.toolkit.fluxcd.io/name=piraeus-operator-crds --overwrite + else + echo " CRD $crd not found, skipping" + fi +done + +# Delete old piraeus-operator helm secrets (by label and by name pattern) +kubectl delete secret -n cozy-linstor -l name=piraeus-operator,owner=helm --ignore-not-found +remaining=$(kubectl get secrets -n cozy-linstor -o name 2>/dev/null | { grep "^secret/sh\.helm\.release\.v1\.piraeus-operator\." || true; }) +if [ -n "$remaining" ]; then + echo " Deleting remaining piraeus-operator helm secrets by name..." + echo "$remaining" | while IFS= read -r secret; do + kubectl delete -n cozy-linstor "$secret" --ignore-not-found + done +fi + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=28 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/28 b/packages/core/platform/images/migrations/migrations/28 new file mode 100755 index 00000000..5174c9b0 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/28 @@ -0,0 +1,629 @@ +#!/bin/bash +# Migration 28 --> 29 +# Rename all mysql-prefixed resources to mariadb- across the cluster. +# Discovers all MySQL HelmReleases by label, migrates each instance. +# Idempotent: safe to re-run. + +set -euo pipefail + +OLD_PREFIX="mysql" +NEW_PREFIX="mariadb" +MARIADB_OPERATOR_NS="cozy-mariadb-operator" +MARIADB_WEBHOOK_NAME="mariadb-operator-webhook" +PROTECTION_WEBHOOK_NAME="protection-webhook" +PROTECTION_WEBHOOK_NS="protection-webhook" +declare -A OPERATOR_REPLICAS=() +declare -A ORIGINAL_PV_POLICIES=() + +# ============================================================ +# Helper functions +# ============================================================ + +resource_exists() { + local ns="$1" type="$2" name="$3" + kubectl -n "$ns" get "$type" "$name" --no-headers 2>/dev/null | grep -q . +} + +delete_resource() { + local ns="$1" type="$2" name="$3" + if resource_exists "$ns" "$type" "$name"; then + echo " [DELETE] ${type}/${name}" + kubectl -n "$ns" delete "$type" "$name" --wait=false + else + echo " [SKIP] ${type}/${name} already gone" + fi +} + +clone_resource() { + local ns="$1" type="$2" old_name="$3" new_name="$4" old_instance="$5" new_instance="$6" + + if resource_exists "$ns" "$type" "$new_name"; then + echo " [SKIP] ${type}/${new_name} already exists" + return 0 + fi + if ! resource_exists "$ns" "$type" "$old_name"; then + echo " [SKIP] ${type}/${old_name} not found" + return 0 + fi + + echo " [CREATE] ${type}/${new_name} from ${old_name}" + kubectl -n "$ns" get "$type" "$old_name" -o json | \ + jq --arg new_name "$new_name" --arg old "$old_instance" --arg new "$new_instance" ' + .metadata.name = $new_name | + del(.metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp, + .metadata.generation, .metadata.managedFields, .metadata.selfLink, + .metadata.ownerReferences) | + del(.status) | + .metadata.labels = ((.metadata.labels // {}) | with_entries( + if (.value | type) == "string" then .value |= gsub($old; $new) else . end)) | + .metadata.annotations = ((.metadata.annotations // {}) | with_entries( + select(.key != "kubectl.kubernetes.io/last-applied-configuration") | + if (.value | type) == "string" then .value |= gsub($old; $new) else . end)) + ' | kubectl -n "$ns" apply -f - +} + +patch_webhook_policy() { + local name="$1" policy="$2" + echo " [PATCH] Set failurePolicy=${policy} on ValidatingWebhookConfiguration/${name}" + kubectl get validatingwebhookconfiguration "$name" -o json | \ + jq --arg p "$policy" '.webhooks[].failurePolicy = $p' | \ + kubectl apply -f - +} + +# ============================================================ +# STEP 1: Discover all MySQL instances +# ============================================================ +echo "=== Discovering MySQL HelmReleases ===" +INSTANCES=() +while IFS=/ read -r ns name; do + [ -z "$ns" ] && continue + instance="${name#${OLD_PREFIX}-}" + INSTANCES+=("${ns}/${instance}") + echo " Found: ${ns}/${name} (instance=${instance})" +done < <(kubectl get hr -A -l "apps.cozystack.io/application.kind=MySQL" \ + -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}' 2>/dev/null) + +if [ ${#INSTANCES[@]} -eq 0 ]; then + echo " No MySQL HelmReleases found. Nothing to migrate." + + # Recover operator if a prior run left it scaled down + for deploy in mariadb-operator mariadb-operator-cert-controller mariadb-operator-webhook; do + current=$(kubectl -n "$MARIADB_OPERATOR_NS" get deploy "$deploy" \ + -o jsonpath='{.spec.replicas}' 2>/dev/null || echo "1") + if [ "$current" = "0" ]; then + echo " [RECOVER] Scaling ${deploy} -> 1" + kubectl -n "$MARIADB_OPERATOR_NS" scale deploy "$deploy" --replicas=1 + fi + done + + # Restore webhook if left at Ignore + current_policy=$(kubectl get validatingwebhookconfiguration "$MARIADB_WEBHOOK_NAME" \ + -o jsonpath='{.webhooks[0].failurePolicy}' 2>/dev/null || echo "unknown") + if [ "$current_policy" = "Ignore" ]; then + patch_webhook_policy "$MARIADB_WEBHOOK_NAME" "Fail" + fi + + # Unsuspend any new HelmReleases left suspended from a prior partial run + while IFS=/ read -r ns name; do + [ -z "$ns" ] && continue + suspended=$(kubectl -n "$ns" get hr "$name" -o jsonpath='{.spec.suspend}' 2>/dev/null || echo "false") + if [ "$suspended" = "true" ]; then + echo " [UNSUSPEND] ${ns}/hr/${name}" + kubectl -n "$ns" patch hr "$name" --type=merge -p '{"spec":{"suspend":false}}' + fi + done < <(kubectl get hr -A -l "apps.cozystack.io/application.kind=MariaDB" \ + -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}' 2>/dev/null) + + kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=29 --dry-run=client -o yaml | kubectl apply -f- + exit 0 +fi +echo " Total: ${#INSTANCES[@]} instance(s)" + +# ============================================================ +# STEP 2: Scale down mariadb-operator and disable its webhook +# ============================================================ +echo "" +echo "--- Step 2: Scale down mariadb-operator ---" +for deploy in mariadb-operator mariadb-operator-cert-controller mariadb-operator-webhook; do + current=$(kubectl -n "$MARIADB_OPERATOR_NS" get deploy "$deploy" -o jsonpath='{.spec.replicas}' 2>/dev/null || echo "0") + OPERATOR_REPLICAS["$deploy"]="$current" + if [ "$current" != "0" ]; then + echo " [SCALE] ${deploy} -> 0 (was ${current})" + kubectl -n "$MARIADB_OPERATOR_NS" scale deploy "$deploy" --replicas=0 + else + echo " [SKIP] ${deploy} already scaled to 0" + fi +done + +echo " Waiting for operator pods to terminate..." +kubectl -n "$MARIADB_OPERATOR_NS" wait --for=delete pod \ + -l app.kubernetes.io/instance=mariadb-operator --timeout=60s 2>/dev/null || true + +current_policy=$(kubectl get validatingwebhookconfiguration "$MARIADB_WEBHOOK_NAME" \ + -o jsonpath='{.webhooks[0].failurePolicy}' 2>/dev/null || echo "unknown") +if [ "$current_policy" = "Fail" ]; then + patch_webhook_policy "$MARIADB_WEBHOOK_NAME" "Ignore" +else + echo " [SKIP] Webhook ${MARIADB_WEBHOOK_NAME} already failurePolicy=${current_policy}" +fi + +# ============================================================ +# STEP 3: Migrate each instance +# ============================================================ +ALL_PV_NAMES=() +ALL_PROTECTED_RESOURCES=() + +for entry in "${INSTANCES[@]}"; do + NAMESPACE="${entry%%/*}" + INSTANCE="${entry#*/}" + OLD_NAME="${OLD_PREFIX}-${INSTANCE}" + NEW_NAME="${NEW_PREFIX}-${INSTANCE}" + + echo "" + echo "======================================================================" + echo "=== Migrating: ${OLD_NAME} -> ${NEW_NAME} in ${NAMESPACE}" + echo "======================================================================" + + # --- 3a: Suspend old HelmRelease --- + echo " --- Suspend HelmRelease ---" + if resource_exists "$NAMESPACE" "hr" "$OLD_NAME"; then + suspended=$(kubectl -n "$NAMESPACE" get hr "$OLD_NAME" -o jsonpath='{.spec.suspend}' 2>/dev/null || echo "false") + if [ "$suspended" != "true" ]; then + echo " [SUSPEND] hr/${OLD_NAME}" + kubectl -n "$NAMESPACE" patch hr "$OLD_NAME" --type=merge -p '{"spec":{"suspend":true}}' + else + echo " [SKIP] hr/${OLD_NAME} already suspended" + fi + else + echo " [SKIP] hr/${OLD_NAME} not found" + fi + + # --- 3b: Switch PV reclaim policy to Retain --- + echo " --- Switch PV reclaim to Retain ---" + PV_NAMES=() + replicas=$(kubectl -n "$NAMESPACE" get mariadb.k8s.mariadb.com "$OLD_NAME" \ + -o jsonpath='{.spec.replicas}' 2>/dev/null || true) + if [ -z "$replicas" ]; then + # Fallback: count existing PVCs matching the old or new name pattern + replicas=$(kubectl -n "$NAMESPACE" get pvc --no-headers -o name 2>/dev/null \ + | grep -cE "storage-${OLD_NAME}-[0-9]+$|storage-${NEW_NAME}-[0-9]+$" || echo "0") + echo " [INFO] MariaDB CR not found, derived replicas=${replicas} from existing PVCs" + fi + for i in $(seq 0 $((replicas - 1))); do + pvc_name="storage-${OLD_NAME}-${i}" + if resource_exists "$NAMESPACE" "pvc" "$pvc_name"; then + pv_name=$(kubectl -n "$NAMESPACE" get pvc "$pvc_name" -o jsonpath='{.spec.volumeName}') + PV_NAMES+=("$pv_name") + ALL_PV_NAMES+=("$pv_name") + current_policy=$(kubectl get pv "$pv_name" -o jsonpath='{.spec.persistentVolumeReclaimPolicy}') + if [ "$current_policy" != "Retain" ]; then + echo " [PATCH] PV ${pv_name}: ${current_policy} -> Retain" + ORIGINAL_PV_POLICIES["$pv_name"]="$current_policy" + kubectl patch pv "$pv_name" -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}' + else + echo " [SKIP] PV ${pv_name} already Retain" + fi + else + new_pvc_name="storage-${NEW_NAME}-${i}" + if resource_exists "$NAMESPACE" "pvc" "$new_pvc_name"; then + pv_name=$(kubectl -n "$NAMESPACE" get pvc "$new_pvc_name" -o jsonpath='{.spec.volumeName}') + PV_NAMES+=("$pv_name") + ALL_PV_NAMES+=("$pv_name") + echo " [SKIP] New PVC ${new_pvc_name} already exists, PV=${pv_name}" + else + echo " [WARN] Neither old nor new PVC found for index ${i}" + PV_NAMES+=("") + fi + fi + done + + # --- 3c: Delete old StatefulSet and Deployment --- + echo " --- Delete old StatefulSet/Deployment ---" + if resource_exists "$NAMESPACE" "statefulset" "$OLD_NAME"; then + echo " [DELETE] statefulset/${OLD_NAME} (cascade=orphan)" + kubectl -n "$NAMESPACE" delete statefulset "$OLD_NAME" --cascade=orphan + else + echo " [SKIP] statefulset/${OLD_NAME} already gone" + fi + if resource_exists "$NAMESPACE" "deployment" "${OLD_NAME}-metrics"; then + echo " [DELETE] deployment/${OLD_NAME}-metrics" + kubectl -n "$NAMESPACE" delete deployment "${OLD_NAME}-metrics" + else + echo " [SKIP] deployment/${OLD_NAME}-metrics already gone" + fi + + # --- 3d: Delete old pods --- + echo " --- Delete old pods ---" + for i in $(seq 0 $((replicas - 1))); do + pod_name="${OLD_NAME}-${i}" + if resource_exists "$NAMESPACE" "pod" "$pod_name"; then + echo " [DELETE] pod/${pod_name}" + kubectl -n "$NAMESPACE" delete pod "$pod_name" --grace-period=30 + else + echo " [SKIP] pod/${pod_name} already gone" + fi + done + for pod in $(kubectl -n "$NAMESPACE" get pods \ + -l app.kubernetes.io/name=mysqld-exporter,app.kubernetes.io/instance="${OLD_NAME}" \ + -o name 2>/dev/null); do + echo " [DELETE] ${pod}" + kubectl -n "$NAMESPACE" delete "$pod" --grace-period=30 + done + + # --- 3e: Migrate PVCs --- + echo " --- Migrate PVCs ---" + for i in $(seq 0 $((replicas - 1))); do + old_pvc="storage-${OLD_NAME}-${i}" + new_pvc="storage-${NEW_NAME}-${i}" + pv_name="${PV_NAMES[$i]:-}" + + if [ -z "$pv_name" ]; then + echo " [WARN] No PV found for index ${i}, skipping" + continue + fi + + if resource_exists "$NAMESPACE" "pvc" "$new_pvc"; then + new_phase=$(kubectl -n "$NAMESPACE" get pvc "$new_pvc" \ + -o jsonpath='{.status.phase}' 2>/dev/null || echo "unknown") + if [ "$new_phase" = "Bound" ]; then + echo " [SKIP] PVC ${new_pvc} already Bound" + continue + fi + fi + + if resource_exists "$NAMESPACE" "pvc" "$old_pvc"; then + storage_size=$(kubectl -n "$NAMESPACE" get pvc "$old_pvc" \ + -o jsonpath='{.spec.resources.requests.storage}') + storage_class=$(kubectl -n "$NAMESPACE" get pvc "$old_pvc" \ + -o jsonpath='{.spec.storageClassName}') + old_labels=$(kubectl -n "$NAMESPACE" get pvc "$old_pvc" -o json | \ + jq --arg old "$OLD_NAME" --arg new "$NEW_NAME" \ + '(.metadata.labels // {}) | with_entries( + if (.value | type) == "string" and .value == $old then .value = $new else . end)') + + if ! resource_exists "$NAMESPACE" "pvc" "$new_pvc"; then + echo " [CREATE] PVC ${new_pvc} -> PV ${pv_name}" + cat < ${new_pvc}" + kubectl patch pv "$pv_name" --type=merge -p "{ + \"spec\":{\"claimRef\":{\"apiVersion\":\"v1\",\"kind\":\"PersistentVolumeClaim\", + \"name\":\"${new_pvc}\",\"namespace\":\"${NAMESPACE}\",\"uid\":\"${new_pvc_uid}\"}} + }" + + echo " Waiting for PVC ${new_pvc} to bind..." + kubectl -n "$NAMESPACE" wait pvc "$new_pvc" \ + --for=jsonpath='{.status.phase}'=Bound --timeout=60s + echo " [OK] PVC ${new_pvc} is Bound" + fi + done + + # --- 3f: Clone Services --- + echo " --- Clone Services ---" + for suffix in "" "-internal" "-primary" "-secondary" "-metrics"; do + old_svc="${OLD_NAME}${suffix}" + new_svc="${NEW_NAME}${suffix}" + if resource_exists "$NAMESPACE" "svc" "$old_svc"; then + if resource_exists "$NAMESPACE" "svc" "$new_svc"; then + echo " [SKIP] svc/${new_svc} already exists" + else + echo " [CREATE] svc/${new_svc} from ${old_svc}" + kubectl -n "$NAMESPACE" get svc "$old_svc" -o json | \ + jq --arg new_svc "$new_svc" --arg old "$OLD_NAME" --arg new "$NEW_NAME" ' + .metadata.name = $new_svc | + del(.metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp, + .metadata.generation, .metadata.managedFields, .metadata.selfLink, + .metadata.ownerReferences) | + del(.status) | + del(.spec.clusterIP, .spec.clusterIPs) | + .metadata.labels = ((.metadata.labels // {}) | with_entries( + if (.value | type) == "string" then .value |= gsub($old; $new) else . end)) | + .metadata.annotations = ((.metadata.annotations // {}) | with_entries( + select(.key != "kubectl.kubernetes.io/last-applied-configuration") | + if (.value | type) == "string" then .value |= gsub($old; $new) else . end)) | + .spec.selector = ((.spec.selector // {}) | with_entries( + if (.value | type) == "string" then .value |= gsub($old; $new) else . end)) + ' | kubectl -n "$NAMESPACE" apply -f - + fi + fi + done + + # --- 3g: Clone Secrets --- + echo " --- Clone Secrets ---" + for secret in $(kubectl -n "$NAMESPACE" get secret -o name 2>/dev/null \ + | { grep "secret/${OLD_NAME}" || true; } | { grep -v "sh.helm.release" || true; }); do + old_secret_name="${secret#secret/}" + new_secret_name="${NEW_NAME}${old_secret_name#${OLD_NAME}}" + clone_resource "$NAMESPACE" "secret" "$old_secret_name" "$new_secret_name" "$OLD_NAME" "$NEW_NAME" + done + + # --- 3h: Clone ConfigMaps --- + echo " --- Clone ConfigMaps ---" + for cm in $(kubectl -n "$NAMESPACE" get configmap -o name 2>/dev/null \ + | { grep "configmap/${OLD_NAME}" || true; }); do + old_cm_name="${cm#configmap/}" + new_cm_name="${NEW_NAME}${old_cm_name#${OLD_NAME}}" + clone_resource "$NAMESPACE" "configmap" "$old_cm_name" "$new_cm_name" "$OLD_NAME" "$NEW_NAME" + done + + # --- 3i: Clone MariaDB CR --- + echo " --- Clone MariaDB CR ---" + if resource_exists "$NAMESPACE" "mariadb.k8s.mariadb.com" "$OLD_NAME"; then + if resource_exists "$NAMESPACE" "mariadb.k8s.mariadb.com" "$NEW_NAME"; then + echo " [SKIP] mariadb.k8s.mariadb.com/${NEW_NAME} already exists" + else + echo " [CREATE] mariadb.k8s.mariadb.com/${NEW_NAME}" + kubectl -n "$NAMESPACE" get mariadb.k8s.mariadb.com "$OLD_NAME" -o json | \ + jq --arg old "$OLD_NAME" --arg new "$NEW_NAME" ' + .metadata.name = $new | + del(.metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp, + .metadata.generation, .metadata.managedFields, .metadata.selfLink, + .metadata.finalizers, .metadata.ownerReferences) | + del(.status) | + .metadata.labels = ((.metadata.labels // {}) | with_entries( + if (.value | type) == "string" then .value |= gsub($old; $new) else . end)) | + .metadata.annotations = ((.metadata.annotations // {}) | with_entries( + select(.key != "kubectl.kubernetes.io/last-applied-configuration") | + if (.value | type) == "string" then .value |= gsub($old; $new) else . end)) | + .spec = (.spec | tostring | gsub($old; $new) | fromjson) + ' | kubectl -n "$NAMESPACE" apply -f - + fi + fi + + # --- 3j: Clone Users, Databases, Grants --- + echo " --- Clone Users, Databases, Grants ---" + for kind in "user.k8s.mariadb.com" "database.k8s.mariadb.com" "grant.k8s.mariadb.com"; do + for resource in $(kubectl -n "$NAMESPACE" get "$kind" -o name 2>/dev/null | grep "${OLD_NAME}"); do + old_res_name="${resource##*/}" + new_res_name="${NEW_NAME}${old_res_name#${OLD_NAME}}" + if resource_exists "$NAMESPACE" "$kind" "$new_res_name"; then + echo " [SKIP] ${kind}/${new_res_name} already exists" + else + echo " [CREATE] ${kind}/${new_res_name}" + kubectl -n "$NAMESPACE" get "$kind" "$old_res_name" -o json | \ + jq --arg old "$OLD_NAME" --arg new "$NEW_NAME" --arg new_name "$new_res_name" ' + .metadata.name = $new_name | + del(.metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp, + .metadata.generation, .metadata.managedFields, .metadata.selfLink, + .metadata.finalizers, .metadata.ownerReferences) | + del(.status) | + .metadata.labels = ((.metadata.labels // {}) | with_entries( + if (.value | type) == "string" then .value |= gsub($old; $new) else . end)) | + .metadata.annotations = ((.metadata.annotations // {}) | with_entries( + select(.key != "kubectl.kubernetes.io/last-applied-configuration") | + if (.value | type) == "string" then .value |= gsub($old; $new) else . end)) | + .spec = (.spec | tostring | gsub($old; $new) | fromjson) + ' | kubectl -n "$NAMESPACE" apply -f - + fi + done + done + + # --- 3k: Clone WorkloadMonitor --- + echo " --- Clone WorkloadMonitor ---" + clone_resource "$NAMESPACE" "workloadmonitor.cozystack.io" "$OLD_NAME" "$NEW_NAME" "$OLD_NAME" "$NEW_NAME" + + # --- 3l: Create new HelmRelease (suspended) --- + echo " --- Create new HelmRelease (suspended) ---" + if resource_exists "$NAMESPACE" "hr" "$NEW_NAME"; then + echo " [SKIP] hr/${NEW_NAME} already exists" + elif resource_exists "$NAMESPACE" "hr" "$OLD_NAME"; then + echo " [CREATE] hr/${NEW_NAME} from ${OLD_NAME} (suspended)" + kubectl -n "$NAMESPACE" get hr "$OLD_NAME" -o json | \ + jq --arg old "$OLD_NAME" --arg new "$NEW_NAME" \ + --arg old_prefix "$OLD_PREFIX" --arg new_prefix "$NEW_PREFIX" ' + .metadata.name = $new | + del(.metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp, + .metadata.generation, .metadata.managedFields, .metadata.selfLink, + .metadata.finalizers, .metadata.ownerReferences) | + del(.status) | + .metadata.labels = ((.metadata.labels // {}) | with_entries( + if (.value | type) == "string" then .value |= gsub($old; $new) else . end) | + if .["apps.cozystack.io/application.kind"] == "MySQL" + then .["apps.cozystack.io/application.kind"] = "MariaDB" + else . end) | + .metadata.annotations = ((.metadata.annotations // {}) | with_entries( + select(.key != "kubectl.kubernetes.io/last-applied-configuration") | + if (.value | type) == "string" then .value |= gsub($old; $new) else . end)) | + (if .spec.chart.spec.chart == $old_prefix + then .spec.chart.spec.chart = $new_prefix else . end) | + .spec.suspend = true + ' | kubectl -n "$NAMESPACE" apply -f - + else + echo " [WARN] hr/${OLD_NAME} not found, cannot clone" + fi + + # --- 3m: Delete old unprotected resources --- + echo " --- Delete old resources ---" + for kind in "grant.k8s.mariadb.com" "database.k8s.mariadb.com" "user.k8s.mariadb.com"; do + for resource in $(kubectl -n "$NAMESPACE" get "$kind" -o name 2>/dev/null | grep "${OLD_NAME}"); do + old_res_name="${resource##*/}" + kubectl -n "$NAMESPACE" patch "$kind" "$old_res_name" --type=json \ + -p='[{"op":"remove","path":"/metadata/finalizers"}]' 2>/dev/null || true + echo " [DELETE] ${kind}/${old_res_name}" + kubectl -n "$NAMESPACE" delete "$kind" "$old_res_name" --wait=false 2>/dev/null || true + done + done + + if resource_exists "$NAMESPACE" "mariadb.k8s.mariadb.com" "$OLD_NAME"; then + kubectl -n "$NAMESPACE" patch mariadb.k8s.mariadb.com "$OLD_NAME" --type=json \ + -p='[{"op":"remove","path":"/metadata/finalizers"}]' 2>/dev/null || true + delete_resource "$NAMESPACE" "mariadb.k8s.mariadb.com" "$OLD_NAME" + fi + + for secret in $(kubectl -n "$NAMESPACE" get secret -o name 2>/dev/null \ + | { grep "secret/${OLD_NAME}" || true; } | { grep -v "sh.helm.release" || true; }); do + old_secret_name="${secret#secret/}" + delete_resource "$NAMESPACE" "secret" "$old_secret_name" + done + + for cm in $(kubectl -n "$NAMESPACE" get configmap -o name 2>/dev/null \ + | { grep "configmap/${OLD_NAME}" || true; }); do + old_cm_name="${cm#configmap/}" + delete_resource "$NAMESPACE" "configmap" "$old_cm_name" + done + + delete_resource "$NAMESPACE" "workloadmonitor.cozystack.io" "$OLD_NAME" + + if resource_exists "$NAMESPACE" "hr" "$OLD_NAME"; then + kubectl -n "$NAMESPACE" patch hr "$OLD_NAME" --type=json \ + -p='[{"op":"remove","path":"/metadata/finalizers"}]' 2>/dev/null || true + delete_resource "$NAMESPACE" "hr" "$OLD_NAME" + fi + + echo " [DELETE] secrets with label owner=helm,name=${OLD_NAME}" + kubectl -n "$NAMESPACE" delete secret -l "owner=helm,name=${OLD_NAME}" 2>/dev/null || true + + # Collect protected resources for batch deletion + for suffix in "" "-internal" "-primary" "-secondary" "-metrics"; do + svc_name="${OLD_NAME}${suffix}" + if resource_exists "$NAMESPACE" "svc" "$svc_name"; then + ALL_PROTECTED_RESOURCES+=("${NAMESPACE}:svc/${svc_name}") + fi + done + for i in $(seq 0 $((replicas - 1))); do + old_pvc="storage-${OLD_NAME}-${i}" + if resource_exists "$NAMESPACE" "pvc" "$old_pvc"; then + ALL_PROTECTED_RESOURCES+=("${NAMESPACE}:pvc/${old_pvc}") + fi + done +done + +# ============================================================ +# STEP 4: Delete protected resources (PVCs, Services) +# ============================================================ +echo "" +echo "--- Step 4: Delete protected resources ---" + +if [ ${#ALL_PROTECTED_RESOURCES[@]} -gt 0 ]; then + echo " --- Temporarily disabling protection-webhook ---" + + WEBHOOK_REPLICAS=$(kubectl -n "$PROTECTION_WEBHOOK_NS" get deploy "$PROTECTION_WEBHOOK_NAME" \ + -o jsonpath='{.spec.replicas}' 2>/dev/null || echo "1") + + echo " [SCALE] ${PROTECTION_WEBHOOK_NAME} -> 0 (was ${WEBHOOK_REPLICAS})" + kubectl -n "$PROTECTION_WEBHOOK_NS" scale deploy "$PROTECTION_WEBHOOK_NAME" --replicas=0 + + patch_webhook_policy "$PROTECTION_WEBHOOK_NAME" "Ignore" + + echo " Waiting for webhook pods to terminate..." + kubectl -n "$PROTECTION_WEBHOOK_NS" wait --for=delete pod \ + -l app.kubernetes.io/name=protection-webhook --timeout=60s 2>/dev/null || true + sleep 3 + + for entry in "${ALL_PROTECTED_RESOURCES[@]}"; do + ns="${entry%%:*}" + res="${entry#*:}" + echo " [DELETE] ${ns}/${res}" + kubectl -n "$ns" delete "$res" --wait=false 2>/dev/null || true + done + + patch_webhook_policy "$PROTECTION_WEBHOOK_NAME" "Fail" + + echo " [SCALE] ${PROTECTION_WEBHOOK_NAME} -> ${WEBHOOK_REPLICAS}" + kubectl -n "$PROTECTION_WEBHOOK_NS" scale deploy "$PROTECTION_WEBHOOK_NAME" \ + --replicas="$WEBHOOK_REPLICAS" + echo " --- protection-webhook restored ---" +else + echo " [SKIP] No protected resources to delete" +fi + +# ============================================================ +# STEP 5: Restore PV reclaim policies +# ============================================================ +echo "" +echo "--- Step 5: Restore PV reclaim policies ---" +for pv_name in "${ALL_PV_NAMES[@]}"; do + if [ -n "$pv_name" ]; then + original="${ORIGINAL_PV_POLICIES[$pv_name]:-}" + if [ -n "$original" ]; then + echo " [PATCH] PV ${pv_name}: Retain -> ${original}" + kubectl patch pv "$pv_name" -p "{\"spec\":{\"persistentVolumeReclaimPolicy\":\"${original}\"}}" + else + echo " [SKIP] PV ${pv_name} was already Retain, leaving as-is" + fi + fi +done + +# ============================================================ +# STEP 6: Restore mariadb-operator +# ============================================================ +echo "" +echo "--- Step 6: Restore mariadb-operator ---" + +current_policy=$(kubectl get validatingwebhookconfiguration "$MARIADB_WEBHOOK_NAME" \ + -o jsonpath='{.webhooks[0].failurePolicy}' 2>/dev/null || echo "unknown") +if [ "$current_policy" = "Ignore" ]; then + patch_webhook_policy "$MARIADB_WEBHOOK_NAME" "Fail" +else + echo " [SKIP] Webhook ${MARIADB_WEBHOOK_NAME} already failurePolicy=${current_policy}" +fi + +for deploy in mariadb-operator mariadb-operator-cert-controller mariadb-operator-webhook; do + current=$(kubectl -n "$MARIADB_OPERATOR_NS" get deploy "$deploy" \ + -o jsonpath='{.spec.replicas}' 2>/dev/null || echo "1") + if [ "$current" = "0" ]; then + target="${OPERATOR_REPLICAS[$deploy]:-1}" + echo " [SCALE] ${deploy} -> ${target}" + kubectl -n "$MARIADB_OPERATOR_NS" scale deploy "$deploy" --replicas="$target" + else + echo " [SKIP] ${deploy} already running (replicas=${current})" + fi +done + +# ============================================================ +# STEP 7: Unsuspend all new HelmReleases +# ============================================================ +echo "" +echo "--- Step 7: Unsuspend new HelmReleases ---" +for entry in "${INSTANCES[@]}"; do + ns="${entry%%/*}" + instance="${entry#*/}" + new_name="${NEW_PREFIX}-${instance}" + if resource_exists "$ns" "hr" "$new_name"; then + suspended=$(kubectl -n "$ns" get hr "$new_name" \ + -o jsonpath='{.spec.suspend}' 2>/dev/null || echo "false") + if [ "$suspended" = "true" ]; then + echo " [UNSUSPEND] ${ns}/hr/${new_name}" + kubectl -n "$ns" patch hr "$new_name" --type=merge -p '{"spec":{"suspend":false}}' + else + echo " [SKIP] ${ns}/hr/${new_name} already not suspended" + fi + fi +done + +echo "" +echo "=== Migration complete (${#INSTANCES[@]} instance(s)) ===" + +# ============================================================ +# STEP 8: Clean up orphaned mysql-rd system HelmRelease +# ============================================================ +echo "" +echo "--- Step 8: Clean up orphaned mysql-rd HelmRelease ---" +if kubectl -n cozy-system get hr mysql-rd --no-headers 2>/dev/null | grep -q .; then + echo " [DELETE] hr/mysql-rd" + kubectl -n cozy-system delete hr mysql-rd --wait=false +else + echo " [SKIP] hr/mysql-rd already gone" +fi +kubectl -n cozy-system delete secret -l "owner=helm,name=mysql-rd" --ignore-not-found + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=29 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/29 b/packages/core/platform/images/migrations/migrations/29 new file mode 100755 index 00000000..b72c2a93 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/29 @@ -0,0 +1,733 @@ +#!/bin/bash +# Migration 29 --> 30 +# Convert virtual-machine HelmReleases to vm-disk + vm-instance. +# Discovers all VirtualMachine HelmReleases by label, migrates each instance. +# Idempotent: safe to re-run. + +set -euo pipefail + +OLD_PREFIX="virtual-machine" +NEW_DISK_PREFIX="vm-disk" +NEW_INSTANCE_PREFIX="vm-instance" +CDI_APISERVER_NS="cozy-kubevirt-cdi" +CDI_APISERVER_DEPLOY="cdi-apiserver" +CDI_VALIDATING_WEBHOOKS="cdi-api-datavolume-validate cdi-api-dataimportcron-validate cdi-api-populator-validate cdi-api-validate" +CDI_MUTATING_WEBHOOKS="cdi-api-datavolume-mutate" + +# ============================================================ +# Helper functions +# ============================================================ + +resource_exists() { + local ns="$1" type="$2" name="$3" + kubectl -n "$ns" get "$type" "$name" --no-headers 2>/dev/null | grep -q . +} + +delete_resource() { + local ns="$1" type="$2" name="$3" + if resource_exists "$ns" "$type" "$name"; then + echo " [DELETE] ${type}/${name}" + kubectl -n "$ns" delete "$type" "$name" --wait=false + else + echo " [SKIP] ${type}/${name} already gone" + fi +} + +clone_resource() { + local ns="$1" type="$2" old_name="$3" new_name="$4" old_instance="$5" new_instance="$6" + + if resource_exists "$ns" "$type" "$new_name"; then + echo " [SKIP] ${type}/${new_name} already exists" + return 0 + fi + if ! resource_exists "$ns" "$type" "$old_name"; then + echo " [SKIP] ${type}/${old_name} not found" + return 0 + fi + + echo " [CREATE] ${type}/${new_name} from ${old_name}" + kubectl -n "$ns" get "$type" "$old_name" -o json | \ + jq --arg new_name "$new_name" --arg old "$old_instance" --arg new "$new_instance" ' + .metadata.name = $new_name | + del(.metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp, + .metadata.generation, .metadata.managedFields, .metadata.selfLink, + .metadata.ownerReferences) | + del(.status) | + .metadata.labels = ((.metadata.labels // {}) | with_entries( + if (.value | type) == "string" then .value |= gsub($old; $new) else . end)) | + .metadata.annotations = ((.metadata.annotations // {}) | with_entries( + select(.key != "kubectl.kubernetes.io/last-applied-configuration") | + if (.value | type) == "string" then .value |= gsub($old; $new) else . end)) + ' | kubectl -n "$ns" apply -f - +} + +# ============================================================ +# STEP 1: Discover all VirtualMachine instances +# ============================================================ +echo "=== Discovering VirtualMachine HelmReleases ===" +INSTANCES=() +while IFS=/ read -r ns name; do + [ -z "$ns" ] && continue + instance="${name#${OLD_PREFIX}-}" + INSTANCES+=("${ns}/${instance}") + echo " Found: ${ns}/${name} (instance=${instance})" +done < <(kubectl get hr -A -l "apps.cozystack.io/application.kind=VirtualMachine" \ + -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}' 2>/dev/null) + +if [ ${#INSTANCES[@]} -eq 0 ]; then + echo " No VirtualMachine HelmReleases found. Nothing to migrate." + kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=30 --dry-run=client -o yaml | kubectl apply -f- + exit 0 +fi +echo " Total: ${#INSTANCES[@]} instance(s)" + +# ============================================================ +# STEP 2: Migrate each instance +# ============================================================ +ALL_PV_NAMES=() + +for entry in "${INSTANCES[@]}"; do + NAMESPACE="${entry%%/*}" + INSTANCE="${entry#*/}" + OLD_NAME="${OLD_PREFIX}-${INSTANCE}" + NEW_DISK_NAME="${NEW_DISK_PREFIX}-${INSTANCE}" + NEW_INSTANCE_NAME="${NEW_INSTANCE_PREFIX}-${INSTANCE}" + + echo "" + echo "======================================================================" + echo "=== Migrating: ${OLD_NAME} -> ${NEW_DISK_NAME} + ${NEW_INSTANCE_NAME} in ${NAMESPACE}" + echo "======================================================================" + + # --- 2a: Suspend old HelmRelease --- + echo " --- Suspend HelmRelease ---" + if resource_exists "$NAMESPACE" "hr" "$OLD_NAME"; then + suspended=$(kubectl -n "$NAMESPACE" get hr "$OLD_NAME" -o jsonpath='{.spec.suspend}' 2>/dev/null || echo "false") + if [ "$suspended" != "true" ]; then + echo " [SUSPEND] hr/${OLD_NAME}" + kubectl -n "$NAMESPACE" patch hr "$OLD_NAME" --type=merge -p '{"spec":{"suspend":true}}' + else + echo " [SKIP] hr/${OLD_NAME} already suspended" + fi + else + echo " [SKIP] hr/${OLD_NAME} not found" + fi + + # --- 2b: Extract values from HelmRelease --- + echo " --- Extract values ---" + VALUES_SECRET="" + VALUES_KEY="values.yaml" + if resource_exists "$NAMESPACE" "hr" "$OLD_NAME"; then + VALUES_SECRET=$(kubectl -n "$NAMESPACE" get hr "$OLD_NAME" -o json | \ + jq -r '.spec.valuesFrom // [] | map(select(.kind == "Secret" and (.name | test("cozystack-values") | not))) | .[0].name // ""') + if [ -n "$VALUES_SECRET" ]; then + VALUES_KEY=$(kubectl -n "$NAMESPACE" get hr "$OLD_NAME" -o json | \ + jq -r '.spec.valuesFrom // [] | map(select(.kind == "Secret" and (.name | test("cozystack-values") | not))) | .[0].valuesKey // "values.yaml"') + fi + fi + + # Extract values from secret + EXTERNAL="false" + EXTERNAL_METHOD="PortList" + EXTERNAL_PORTS='[22]' + INSTANCE_TYPE="u1.medium" + INSTANCE_PROFILE="ubuntu" + RUN_STRATEGY="Always" + SYSTEM_DISK_IMAGE="ubuntu" + SYSTEM_DISK_STORAGE="5Gi" + SYSTEM_DISK_STORAGE_CLASS="replicated" + SSH_KEYS="[]" + CLOUD_INIT="" + CLOUD_INIT_SEED="" + SUBNETS="[]" + GPUS="[]" + CPU_MODEL="" + RESOURCES="{}" + + if [ -n "$VALUES_SECRET" ] && resource_exists "$NAMESPACE" "secret" "$VALUES_SECRET"; then + echo " Reading values from secret: ${VALUES_SECRET}" + VALUES_YAML=$(kubectl -n "$NAMESPACE" get secret "$VALUES_SECRET" -o jsonpath="{.data.${VALUES_KEY}}" 2>/dev/null | base64 -d 2>/dev/null || true) + if [ -z "$VALUES_YAML" ]; then + VALUES_YAML=$(kubectl -n "$NAMESPACE" get secret "$VALUES_SECRET" -o jsonpath="{.stringData.${VALUES_KEY}}" 2>/dev/null || true) + fi + if [ -n "$VALUES_YAML" ]; then + EXTERNAL=$(echo "$VALUES_YAML" | yq -r '.external // false') + EXTERNAL_METHOD=$(echo "$VALUES_YAML" | yq -r '.externalMethod // "PortList"') + EXTERNAL_PORTS=$(echo "$VALUES_YAML" | yq -c '.externalPorts // [22]') + INSTANCE_TYPE=$(echo "$VALUES_YAML" | yq -r '.instanceType // "u1.medium"') + INSTANCE_PROFILE=$(echo "$VALUES_YAML" | yq -r '.instanceProfile // "ubuntu"') + RUN_STRATEGY=$(echo "$VALUES_YAML" | yq -r '.runStrategy // (if .running == false then "Halted" else "Always" end)') + SYSTEM_DISK_IMAGE=$(echo "$VALUES_YAML" | yq -r '.systemDisk.image // "ubuntu"') + SYSTEM_DISK_STORAGE=$(echo "$VALUES_YAML" | yq -r '.systemDisk.storage // "5Gi"') + SYSTEM_DISK_STORAGE_CLASS=$(echo "$VALUES_YAML" | yq -r '.systemDisk.storageClass // "replicated"') + SSH_KEYS=$(echo "$VALUES_YAML" | yq -c '.sshKeys // []') + CLOUD_INIT=$(echo "$VALUES_YAML" | yq -r '.cloudInit // ""') + CLOUD_INIT_SEED=$(echo "$VALUES_YAML" | yq -r '.cloudInitSeed // ""') + SUBNETS=$(echo "$VALUES_YAML" | yq -c '.subnets // []') + GPUS=$(echo "$VALUES_YAML" | yq -c '.gpus // []') + CPU_MODEL=$(echo "$VALUES_YAML" | yq -r '.cpuModel // ""') + RESOURCES=$(echo "$VALUES_YAML" | yq -c '.resources // {}') + fi + fi + + echo " external=${EXTERNAL}, instanceType=${INSTANCE_TYPE}, image=${SYSTEM_DISK_IMAGE}" + + # --- 2c: Save kube-ovn IP --- + echo " --- Save kube-ovn IP ---" + OVN_IP="" + OVN_MAC="" + OVN_SUBNET="ovn-default" + OVN_IP_NAME="${OLD_NAME}.${NAMESPACE}" + if kubectl get ip.kubeovn.io "$OVN_IP_NAME" --no-headers 2>/dev/null | grep -q .; then + OVN_IP=$(kubectl get ip.kubeovn.io "$OVN_IP_NAME" -o jsonpath='{.spec.ipAddress}') + OVN_MAC=$(kubectl get ip.kubeovn.io "$OVN_IP_NAME" -o jsonpath='{.spec.macAddress}') + OVN_SUBNET=$(kubectl get ip.kubeovn.io "$OVN_IP_NAME" -o jsonpath='{.spec.subnet}') + echo " kube-ovn IP: ${OVN_IP}, MAC: ${OVN_MAC}, subnet: ${OVN_SUBNET}" + else + echo " [SKIP] No kube-ovn IP resource found" + fi + + # --- 2d: Save LoadBalancer IP (if external=true) --- + echo " --- Save LoadBalancer IP ---" + LB_IP="" + if [ "$EXTERNAL" = "true" ] && resource_exists "$NAMESPACE" "svc" "$OLD_NAME"; then + LB_IP=$(kubectl -n "$NAMESPACE" get svc "$OLD_NAME" -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null || true) + if [ -n "$LB_IP" ]; then + echo " LoadBalancer IP: ${LB_IP}" + else + echo " [WARN] external=true but no LoadBalancer IP assigned" + fi + else + echo " [SKIP] Not external or no service" + fi + + # --- 2e: Switch PV reclaim policy to Retain --- + echo " --- Switch PV reclaim to Retain ---" + PV_NAME="" + if resource_exists "$NAMESPACE" "pvc" "$OLD_NAME"; then + PV_NAME=$(kubectl -n "$NAMESPACE" get pvc "$OLD_NAME" -o jsonpath='{.spec.volumeName}') + if [ -n "$PV_NAME" ]; then + ALL_PV_NAMES+=("$PV_NAME") + current_policy=$(kubectl get pv "$PV_NAME" -o jsonpath='{.spec.persistentVolumeReclaimPolicy}') + if [ "$current_policy" != "Retain" ]; then + echo " [PATCH] PV ${PV_NAME}: ${current_policy} -> Retain" + kubectl patch pv "$PV_NAME" -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}' + else + echo " [SKIP] PV ${PV_NAME} already Retain" + fi + fi + elif resource_exists "$NAMESPACE" "pvc" "$NEW_DISK_NAME"; then + PV_NAME=$(kubectl -n "$NAMESPACE" get pvc "$NEW_DISK_NAME" -o jsonpath='{.spec.volumeName}') + ALL_PV_NAMES+=("$PV_NAME") + echo " [SKIP] New PVC ${NEW_DISK_NAME} already exists, PV=${PV_NAME}" + else + echo " [WARN] No PVC found for ${OLD_NAME} or ${NEW_DISK_NAME}" + fi + + # --- 2f: Stop and delete the VirtualMachine --- + echo " --- Stop VirtualMachine ---" + if resource_exists "$NAMESPACE" "vm" "$OLD_NAME"; then + echo " [PATCH] Stop VM ${OLD_NAME}" + kubectl -n "$NAMESPACE" patch vm "$OLD_NAME" --type merge -p '{"spec":{"runStrategy":"Halted"}}' 2>/dev/null || \ + kubectl -n "$NAMESPACE" patch vm "$OLD_NAME" --type merge -p '{"spec":{"running":false}}' 2>/dev/null || true + + echo " Waiting for VMI to terminate..." + kubectl -n "$NAMESPACE" wait --for=delete vmi "$OLD_NAME" --timeout=120s 2>/dev/null || true + fi + + # --- 2g: Delete VirtualMachine CR (cascades to DataVolume and PVC) --- + echo " --- Delete VirtualMachine CR ---" + if resource_exists "$NAMESPACE" "vm" "$OLD_NAME"; then + echo " [DELETE] vm/${OLD_NAME}" + kubectl -n "$NAMESPACE" delete vm "$OLD_NAME" --wait=true --timeout=60s 2>/dev/null || true + fi + + echo " Waiting for old PVC to be deleted..." + for i in $(seq 1 30); do + if ! resource_exists "$NAMESPACE" "pvc" "$OLD_NAME"; then + echo " [OK] PVC ${OLD_NAME} deleted" + break + fi + sleep 2 + done + + # If PVC still exists (orphaned), delete it manually + if resource_exists "$NAMESPACE" "pvc" "$OLD_NAME"; then + echo " [DELETE] Orphaned pvc/${OLD_NAME}" + kubectl -n "$NAMESPACE" delete pvc "$OLD_NAME" --wait=false 2>/dev/null || true + fi + + # Delete orphaned DataVolume if still present + if resource_exists "$NAMESPACE" "dv" "$OLD_NAME"; then + echo " [DELETE] Orphaned dv/${OLD_NAME}" + kubectl -n "$NAMESPACE" delete dv "$OLD_NAME" --wait=false 2>/dev/null || true + fi + + # --- 2h: Create new PVC for vm-disk --- + echo " --- Create new PVC for vm-disk ---" + if [ -n "$PV_NAME" ]; then + if resource_exists "$NAMESPACE" "pvc" "$NEW_DISK_NAME"; then + new_phase=$(kubectl -n "$NAMESPACE" get pvc "$NEW_DISK_NAME" \ + -o jsonpath='{.status.phase}' 2>/dev/null || echo "unknown") + if [ "$new_phase" = "Bound" ]; then + echo " [SKIP] PVC ${NEW_DISK_NAME} already Bound" + fi + else + PV_VOLUME_MODE=$(kubectl get pv "$PV_NAME" -o jsonpath='{.spec.volumeMode}' 2>/dev/null || echo "Filesystem") + echo " [CREATE] PVC ${NEW_DISK_NAME} -> PV ${PV_NAME} (volumeMode=${PV_VOLUME_MODE})" + cat < ${NEW_DISK_NAME}" + kubectl patch pv "$PV_NAME" --type=merge -p "{ + \"spec\":{\"claimRef\":{\"apiVersion\":\"v1\",\"kind\":\"PersistentVolumeClaim\", + \"name\":\"${NEW_DISK_NAME}\",\"namespace\":\"${NAMESPACE}\",\"uid\":\"${new_pvc_uid}\"}} + }" + + echo " Waiting for PVC ${NEW_DISK_NAME} to bind..." + kubectl -n "$NAMESPACE" wait pvc "$NEW_DISK_NAME" \ + --for=jsonpath='{.status.phase}'=Bound --timeout=60s + echo " [OK] PVC ${NEW_DISK_NAME} is Bound" + fi + fi + + # --- 2i: Clone Secrets --- + echo " --- Clone Secrets ---" + kubectl -n "$NAMESPACE" get secret -o name 2>/dev/null \ + | { grep "secret/${OLD_NAME}" || true; } | { grep -v "sh.helm.release" || true; } | { grep -v "values" || true; } \ + | while IFS= read -r secret; do + old_secret_name="${secret#secret/}" + suffix="${old_secret_name#${OLD_NAME}}" + new_secret_name="${NEW_INSTANCE_NAME}${suffix}" + clone_resource "$NAMESPACE" "secret" "$old_secret_name" "$new_secret_name" "$OLD_NAME" "$NEW_INSTANCE_NAME" + done + + # --- 2j: Clone WorkloadMonitor --- + echo " --- Clone WorkloadMonitor ---" + clone_resource "$NAMESPACE" "workloadmonitor.cozystack.io" "$OLD_NAME" "$NEW_INSTANCE_NAME" "$OLD_NAME" "$NEW_INSTANCE_NAME" + + # --- 2k: Migrate kube-ovn IP --- + echo " --- Migrate kube-ovn IP ---" + NEW_OVN_IP_NAME="${NEW_INSTANCE_NAME}.${NAMESPACE}" + if [ -n "$OVN_IP" ]; then + if kubectl get ip.kubeovn.io "$NEW_OVN_IP_NAME" --no-headers 2>/dev/null | grep -q .; then + echo " [SKIP] ip.kubeovn.io/${NEW_OVN_IP_NAME} already exists" + else + echo " [CREATE] ip.kubeovn.io/${NEW_OVN_IP_NAME}" + cat </dev/null | grep -q .; then + echo " [DELETE] ip.kubeovn.io/${OVN_IP_NAME}" + kubectl delete ip.kubeovn.io "$OVN_IP_NAME" 2>/dev/null || true + fi + fi + + # --- 2l: Create vm-disk values secret --- + echo " --- Create vm-disk values secret ---" + DISK_VALUES_SECRET="${NEW_DISK_NAME}-values" + if ! resource_exists "$NAMESPACE" "secret" "$DISK_VALUES_SECRET"; then + echo " [CREATE] secret/${DISK_VALUES_SECRET}" + cat </dev/null \ + | { grep "secret/${OLD_NAME}" || true; } | { grep -v "sh.helm.release" || true; } | { grep -v "values" || true; } \ + | while IFS= read -r secret; do + old_secret_name="${secret#secret/}" + delete_resource "$NAMESPACE" "secret" "$old_secret_name" + done + + delete_resource "$NAMESPACE" "workloadmonitor.cozystack.io" "$OLD_NAME" + + if resource_exists "$NAMESPACE" "hr" "$OLD_NAME"; then + kubectl -n "$NAMESPACE" patch hr "$OLD_NAME" --type=json \ + -p='[{"op":"remove","path":"/metadata/finalizers"}]' 2>/dev/null || true + delete_resource "$NAMESPACE" "hr" "$OLD_NAME" + fi + + echo " [DELETE] secrets with label owner=helm,name=${OLD_NAME}" + kubectl -n "$NAMESPACE" delete secret -l "owner=helm,name=${OLD_NAME}" 2>/dev/null || true + + # Delete old values secret + if [ -n "$VALUES_SECRET" ]; then + delete_resource "$NAMESPACE" "secret" "$VALUES_SECRET" + fi + + # Delete old service (if exists) + if resource_exists "$NAMESPACE" "svc" "$OLD_NAME"; then + delete_resource "$NAMESPACE" "svc" "$OLD_NAME" + fi +done + +# ============================================================ +# STEP 3: Restore PV reclaim policies +# ============================================================ +echo "" +echo "--- Step 3: Restore PV reclaim policies ---" +for pv_name in "${ALL_PV_NAMES[@]}"; do + if [ -n "$pv_name" ]; then + current_policy=$(kubectl get pv "$pv_name" \ + -o jsonpath='{.spec.persistentVolumeReclaimPolicy}' 2>/dev/null || echo "unknown") + if [ "$current_policy" = "Retain" ]; then + echo " [PATCH] PV ${pv_name}: Retain -> Delete" + kubectl patch pv "$pv_name" -p '{"spec":{"persistentVolumeReclaimPolicy":"Delete"}}' + else + echo " [SKIP] PV ${pv_name} already ${current_policy}" + fi + fi +done + +# ============================================================ +# STEP 4: Temporarily disable CDI datavolume webhooks +# ============================================================ +# CDI's datavolume-validate webhook rejects DataVolume creation when a PVC +# with the same name already exists. We must disable it so that vm-disk +# HelmReleases can reconcile and adopt the pre-created PVCs. +# We scale down both cdi-operator (which recreates webhook configs) and +# cdi-apiserver (which serves the webhooks), then delete webhook configs. +# Both are restored after vm-disk HRs reconcile. +echo "" +echo "--- Step 4: Temporarily disable CDI webhooks ---" + +CDI_OPERATOR_REPLICAS=$(kubectl -n "$CDI_APISERVER_NS" get deploy cdi-operator \ + -o jsonpath='{.spec.replicas}' 2>/dev/null || echo "1") +CDI_APISERVER_REPLICAS=$(kubectl -n "$CDI_APISERVER_NS" get deploy "$CDI_APISERVER_DEPLOY" \ + -o jsonpath='{.spec.replicas}' 2>/dev/null || echo "1") + +echo " [SCALE] cdi-operator -> 0 (was ${CDI_OPERATOR_REPLICAS})" +kubectl -n "$CDI_APISERVER_NS" scale deploy cdi-operator --replicas=0 +echo " [SCALE] ${CDI_APISERVER_DEPLOY} -> 0 (was ${CDI_APISERVER_REPLICAS})" +kubectl -n "$CDI_APISERVER_NS" scale deploy "$CDI_APISERVER_DEPLOY" --replicas=0 + +echo " Waiting for cdi pods to terminate..." +kubectl -n "$CDI_APISERVER_NS" wait --for=delete pod \ + -l cdi.kubevirt.io=cdi-apiserver --timeout=60s 2>/dev/null || true +kubectl -n "$CDI_APISERVER_NS" wait --for=delete pod \ + -l name=cdi-operator --timeout=60s 2>/dev/null || true + +for wh in $CDI_VALIDATING_WEBHOOKS; do + if kubectl get validatingwebhookconfiguration "$wh" >/dev/null 2>&1; then + echo " [DELETE] validatingwebhookconfiguration/${wh}" + kubectl delete validatingwebhookconfiguration "$wh" 2>/dev/null || true + fi +done +for wh in $CDI_MUTATING_WEBHOOKS; do + if kubectl get mutatingwebhookconfiguration "$wh" >/dev/null 2>&1; then + echo " [DELETE] mutatingwebhookconfiguration/${wh}" + kubectl delete mutatingwebhookconfiguration "$wh" 2>/dev/null || true + fi +done +sleep 2 + +# ============================================================ +# STEP 5: Unsuspend vm-disk HelmReleases first +# ============================================================ +echo "" +echo "--- Step 5: Unsuspend vm-disk HelmReleases ---" +for entry in "${INSTANCES[@]}"; do + ns="${entry%%/*}" + instance="${entry#*/}" + disk_name="${NEW_DISK_PREFIX}-${instance}" + if resource_exists "$ns" "hr" "$disk_name"; then + suspended=$(kubectl -n "$ns" get hr "$disk_name" \ + -o jsonpath='{.spec.suspend}' 2>/dev/null || echo "false") + if [ "$suspended" = "true" ]; then + echo " [UNSUSPEND] ${ns}/hr/${disk_name}" + kubectl -n "$ns" patch hr "$disk_name" --type=merge -p '{"spec":{"suspend":false}}' + else + echo " [SKIP] ${ns}/hr/${disk_name} already not suspended" + fi + # Force immediate reconciliation + echo " [TRIGGER] Reconcile ${ns}/hr/${disk_name}" + kubectl -n "$ns" annotate hr "$disk_name" --overwrite \ + "reconcile.fluxcd.io/requestedAt=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" 2>/dev/null || true + fi +done + +# Wait for disk HelmReleases to become ready +echo " Waiting for vm-disk HelmReleases to reconcile..." +for entry in "${INSTANCES[@]}"; do + ns="${entry%%/*}" + instance="${entry#*/}" + disk_name="${NEW_DISK_PREFIX}-${instance}" + for i in $(seq 1 60); do + ready=$(kubectl -n "$ns" get hr "$disk_name" -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null || true) + if [ "$ready" = "True" ]; then + echo " [OK] ${ns}/hr/${disk_name} is Ready" + break + fi + if [ "$i" = "60" ]; then + echo " [WARN] ${ns}/hr/${disk_name} did not become Ready within timeout" + fi + sleep 5 + done +done + +# ============================================================ +# STEP 6: Restore CDI webhooks +# ============================================================ +# Scale cdi-operator and cdi-apiserver back up. +# cdi-apiserver will recreate webhook configurations automatically on start. +echo "" +echo "--- Step 6: Restore CDI webhooks ---" + +echo " [SCALE] cdi-operator -> ${CDI_OPERATOR_REPLICAS}" +kubectl -n "$CDI_APISERVER_NS" scale deploy cdi-operator \ + --replicas="$CDI_OPERATOR_REPLICAS" +echo " [SCALE] ${CDI_APISERVER_DEPLOY} -> ${CDI_APISERVER_REPLICAS}" +kubectl -n "$CDI_APISERVER_NS" scale deploy "$CDI_APISERVER_DEPLOY" \ + --replicas="$CDI_APISERVER_REPLICAS" + +echo " Waiting for CDI to be ready..." +kubectl -n "$CDI_APISERVER_NS" rollout status deploy cdi-operator --timeout=120s 2>/dev/null || true +kubectl -n "$CDI_APISERVER_NS" rollout status deploy "$CDI_APISERVER_DEPLOY" --timeout=120s 2>/dev/null || true +echo " --- CDI webhooks restored ---" + +# ============================================================ +# STEP 7: Unsuspend vm-instance HelmReleases +# ============================================================ +echo "" +echo "--- Step 7: Unsuspend vm-instance HelmReleases ---" +for entry in "${INSTANCES[@]}"; do + ns="${entry%%/*}" + instance="${entry#*/}" + instance_name="${NEW_INSTANCE_PREFIX}-${instance}" + if resource_exists "$ns" "hr" "$instance_name"; then + suspended=$(kubectl -n "$ns" get hr "$instance_name" \ + -o jsonpath='{.spec.suspend}' 2>/dev/null || echo "false") + if [ "$suspended" = "true" ]; then + echo " [UNSUSPEND] ${ns}/hr/${instance_name}" + kubectl -n "$ns" patch hr "$instance_name" --type=merge -p '{"spec":{"suspend":false}}' + else + echo " [SKIP] ${ns}/hr/${instance_name} already not suspended" + fi + fi +done + +echo "" +echo "=== Migration complete (${#INSTANCES[@]} instance(s)) ===" + +# ============================================================ +# STEP 8: Clean up orphaned virtual-machine-rd system HelmRelease +# ============================================================ +echo "" +echo "--- Step 8: Clean up orphaned virtual-machine-rd HelmRelease ---" +if kubectl -n cozy-system get hr virtual-machine-rd --no-headers 2>/dev/null | grep -q .; then + echo " [DELETE] hr/virtual-machine-rd" + kubectl -n cozy-system delete hr virtual-machine-rd --wait=false +else + echo " [SKIP] hr/virtual-machine-rd already gone" +fi +kubectl -n cozy-system delete secret -l "owner=helm,name=virtual-machine-rd" --ignore-not-found + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=30 --dry-run=client -o yaml | kubectl apply -f- diff --git a/scripts/migrations/3 b/packages/core/platform/images/migrations/migrations/3 similarity index 100% rename from scripts/migrations/3 rename to packages/core/platform/images/migrations/migrations/3 diff --git a/packages/core/platform/images/migrations/migrations/30 b/packages/core/platform/images/migrations/migrations/30 new file mode 100755 index 00000000..64b89305 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/30 @@ -0,0 +1,116 @@ +#!/bin/bash +# Migration 30 --> 31 +# Convert VPC subnets from map format to array format in HelmRelease values. +# Map format: subnets: {name: {cidr: x}} +# Array format: subnets: [{name: name, cidr: x}] +# Idempotent: skips if subnets is already an array or empty/null. + +set -euo pipefail + +# ============================================================ +# STEP 1: Discover all VirtualPrivateCloud HelmReleases +# ============================================================ +echo "=== Discovering VirtualPrivateCloud HelmReleases ===" +INSTANCES=() +while IFS=/ read -r ns name; do + [ -z "$ns" ] && continue + INSTANCES+=("${ns}/${name}") + echo " Found: ${ns}/${name}" +done < <(kubectl get hr -A -l "apps.cozystack.io/application.kind=VirtualPrivateCloud" \ + -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}' 2>/dev/null) + +if [ ${#INSTANCES[@]} -eq 0 ]; then + echo " No VirtualPrivateCloud HelmReleases found. Nothing to migrate." + kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=31 --dry-run=client -o yaml | kubectl apply -f- + exit 0 +fi +echo " Total: ${#INSTANCES[@]} instance(s)" + +# ============================================================ +# STEP 2: Migrate each instance +# ============================================================ +for entry in "${INSTANCES[@]}"; do + NAMESPACE="${entry%%/*}" + HR_NAME="${entry#*/}" + + echo "" + echo "======================================================================" + echo "=== Processing: ${HR_NAME} in ${NAMESPACE}" + echo "======================================================================" + + # --- Find values Secret --- + VALUES_SECRET=$(kubectl -n "$NAMESPACE" get hr "$HR_NAME" -o json | \ + jq -r '.spec.valuesFrom // [] | map(select(.kind == "Secret" and (.name | test("cozystack-values") | not))) | .[0].name // ""') + VALUES_KEY=$(kubectl -n "$NAMESPACE" get hr "$HR_NAME" -o json | \ + jq -r '.spec.valuesFrom // [] | map(select(.kind == "Secret" and (.name | test("cozystack-values") | not))) | .[0].valuesKey // "values.yaml"') + + if [ -z "$VALUES_SECRET" ]; then + echo " [SKIP] No values Secret found for hr/${HR_NAME}" + continue + fi + + if ! kubectl -n "$NAMESPACE" get secret "$VALUES_SECRET" --no-headers 2>/dev/null | grep -q .; then + echo " [SKIP] Secret ${VALUES_SECRET} not found" + continue + fi + + echo " Reading values from secret: ${VALUES_SECRET} (key: ${VALUES_KEY})" + + # --- Decode current values --- + VALUES_YAML=$(kubectl -n "$NAMESPACE" get secret "$VALUES_SECRET" \ + -o jsonpath="{.data.${VALUES_KEY}}" 2>/dev/null | base64 -d 2>/dev/null || true) + if [ -z "$VALUES_YAML" ]; then + VALUES_YAML=$(kubectl -n "$NAMESPACE" get secret "$VALUES_SECRET" \ + -o jsonpath="{.stringData.${VALUES_KEY}}" 2>/dev/null || true) + fi + + if [ -z "$VALUES_YAML" ]; then + echo " [SKIP] Could not read values from secret" + continue + fi + + # --- Check subnets type --- + SUBNETS_TYPE=$(echo "$VALUES_YAML" | yq -r '.subnets | type') + + case "$SUBNETS_TYPE" in + "!!map"|"object") + echo " [CONVERT] subnets is a map, converting to array" + ;; + "!!seq"|"array") + echo " [SKIP] subnets is already an array" + continue + ;; + "!!null"|"null") + echo " [SKIP] subnets is null/empty" + continue + ;; + *) + echo " [SKIP] subnets has unexpected type: ${SUBNETS_TYPE}" + continue + ;; + esac + + # --- Convert map to array --- + # {name: {cidr: x}} -> [{name: name, cidr: x}] + NEW_VALUES=$(echo "$VALUES_YAML" | yq ' + .subnets = ([.subnets | to_entries[] | {"name": .key} + .value]) + ') + + # --- Patch the Secret --- + NEW_VALUES_B64=$(echo "$NEW_VALUES" | base64) + echo " [PATCH] Updating secret/${VALUES_SECRET}" + kubectl -n "$NAMESPACE" get secret "$VALUES_SECRET" -o json | \ + jq --arg key "$VALUES_KEY" --arg val "$NEW_VALUES_B64" \ + '.data[$key] = $val' | \ + kubectl apply -f - + + echo " [OK] Converted subnets for ${HR_NAME}" +done + +echo "" +echo "=== Migration complete (${#INSTANCES[@]} instance(s)) ===" + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=31 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/31 b/packages/core/platform/images/migrations/migrations/31 new file mode 100755 index 00000000..2a261d9b --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/31 @@ -0,0 +1,45 @@ +#!/bin/sh +# Migration 31 --> 32 +# Adopt tenant-root resources into cozystack-basics Helm release. +# +# In v0.41.x tenant-root Namespace and HelmRelease were applied via +# kubectl apply (no Helm tracking). In v1.0 they are managed by the +# cozystack-basics Helm release. Without Helm ownership annotations +# the install of cozystack-basics fails because the resources already +# exist. This migration adds the required annotations and labels so +# Helm can adopt them. + +set -euo pipefail + +RELEASE_NAME="cozystack-basics" +RELEASE_NS="cozy-system" + +# Adopt Namespace tenant-root +if kubectl get namespace tenant-root >/dev/null 2>&1; then + echo "Adopting Namespace tenant-root into $RELEASE_NAME" + kubectl annotate namespace tenant-root \ + meta.helm.sh/release-name="$RELEASE_NAME" \ + meta.helm.sh/release-namespace="$RELEASE_NS" \ + --overwrite + kubectl label namespace tenant-root \ + app.kubernetes.io/managed-by=Helm \ + --overwrite +fi + +# Adopt HelmRelease tenant-root +if kubectl get helmrelease -n tenant-root tenant-root >/dev/null 2>&1; then + echo "Adopting HelmRelease tenant-root into $RELEASE_NAME" + kubectl annotate helmrelease -n tenant-root tenant-root \ + meta.helm.sh/release-name="$RELEASE_NAME" \ + meta.helm.sh/release-namespace="$RELEASE_NS" \ + helm.sh/resource-policy=keep \ + --overwrite + kubectl label helmrelease -n tenant-root tenant-root \ + app.kubernetes.io/managed-by=Helm \ + sharding.fluxcd.io/key=tenants \ + --overwrite +fi + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=32 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/32 b/packages/core/platform/images/migrations/migrations/32 new file mode 100755 index 00000000..c93a9312 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/32 @@ -0,0 +1,92 @@ +#!/bin/sh +# Migration 32 --> 33 +# Convert publishing.certificates.issuerType to solver + issuerName in +# the cozystack-platform Package resource. +# +# Old field (pre-refactor schema): +# publishing.certificates.issuerType: "http01" | "cloudflare" +# New fields: +# publishing.certificates.solver: "http01" | "dns01" +# publishing.certificates.issuerName: "letsencrypt-prod" (or custom) +# +# Conversion table: +# cloudflare -> solver: dns01, issuerName: letsencrypt-prod +# http01 -> solver: http01, issuerName: letsencrypt-prod +# -> issuerName: (solver left at chart default) +# -> no-op + +set -euo pipefail + +PACKAGE_NAME="cozystack.cozystack-platform" + +# Check if Package exists +if ! kubectl get package "$PACKAGE_NAME" >/dev/null 2>&1; then + echo "Package $PACKAGE_NAME not found, skipping migration" + kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=33 --dry-run=client -o yaml | kubectl apply -f - + exit 0 +fi + +# Read current issuerType value +ISSUER_TYPE=$(kubectl get package "$PACKAGE_NAME" -o json | \ + jq -r '.spec.components.platform.values.publishing.certificates.issuerType // ""') + +if [ -z "$ISSUER_TYPE" ]; then + echo "No issuerType found in Package $PACKAGE_NAME, nothing to migrate" + kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=33 --dry-run=client -o yaml | kubectl apply -f - + exit 0 +fi + +echo "Found issuerType: $ISSUER_TYPE" + +# Convert old issuerType to new solver/issuerName +SOLVER="" +ISSUER_NAME="" +case "$ISSUER_TYPE" in + cloudflare) + SOLVER="dns01" + ISSUER_NAME="letsencrypt-prod" + ;; + http01) + SOLVER="http01" + ISSUER_NAME="letsencrypt-prod" + ;; + *) + # Unrecognised value — treat as custom ClusterIssuer name, no solver override + ISSUER_NAME="$ISSUER_TYPE" + ;; +esac + +echo "Converting to: solver=${SOLVER:-}, issuerName=${ISSUER_NAME:-}" + +# Build the certificates patch: +# - null removes issuerType (JSON merge patch semantics) +# - solver and issuerName are included only when non-empty +CERTS_PATCH=$(jq -n --arg solver "$SOLVER" --arg issuerName "$ISSUER_NAME" ' + {"issuerType": null} + + (if $solver != "" then {"solver": $solver} else {} end) + + (if $issuerName != "" then {"issuerName": $issuerName} else {} end) +') + +PATCH_JSON=$(jq -n --argjson certs "$CERTS_PATCH" '{ + "spec": { + "components": { + "platform": { + "values": { + "publishing": { + "certificates": $certs + } + } + } + } + } +}') + +kubectl patch package "$PACKAGE_NAME" --type=merge --patch "$PATCH_JSON" + +echo "Migration complete: issuerType=$ISSUER_TYPE -> solver=${SOLVER:-} issuerName=${ISSUER_NAME:-}" + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=33 --dry-run=client -o yaml | kubectl apply -f - diff --git a/packages/core/platform/images/migrations/migrations/33 b/packages/core/platform/images/migrations/migrations/33 new file mode 100755 index 00000000..5da6788f --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/33 @@ -0,0 +1,30 @@ +#!/bin/sh +# Migration 33 --> 34 +# Clean up orphaned system -rd HelmReleases left after application renames. +# +# These HelmReleases reference ExternalArtifacts that no longer exist: +# ferretdb-rd -> replaced by mongodb-rd +# mysql-rd -> replaced by mariadb-rd (migration 28 handled user HRs only) +# virtual-machine-rd -> replaced by vm-disk-rd + vm-instance-rd (migration 29 handled user HRs only) +# +# Idempotent: safe to re-run. + +set -euo pipefail + +echo "=== Cleaning up orphaned -rd HelmReleases ===" + +for hr_name in ferretdb-rd mysql-rd virtual-machine-rd; do + if kubectl -n cozy-system get hr "$hr_name" --no-headers 2>/dev/null | grep -q .; then + echo " [DELETE] hr/${hr_name}" + kubectl -n cozy-system delete hr "$hr_name" --wait=false + else + echo " [SKIP] hr/${hr_name} already gone" + fi + kubectl -n cozy-system delete secret -l "owner=helm,name=${hr_name}" --ignore-not-found +done + +echo "=== Cleanup complete ===" + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=34 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/34 b/packages/core/platform/images/migrations/migrations/34 new file mode 100755 index 00000000..f031d590 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/34 @@ -0,0 +1,46 @@ +#!/bin/sh +# Migration 34 --> 35 +# Backfill spec.version on rabbitmq.apps.cozystack.io resources. +# +# Before this migration RabbitMQ had no user-selectable version; the +# operator always used its built-in default image (v3.x). A version field +# was added in this release. Without this migration every existing cluster +# would be upgraded to the new default (v4.2) on the next reconcile. +# +# Set spec.version to "v3.13" for any rabbitmq app resource that does not +# already have it set. + +set -euo pipefail + +DEFAULT_VERSION="v3.13" + +# Skip if the CRD does not exist (rabbitmq was never installed) +if ! kubectl api-resources --api-group=apps.cozystack.io -o name 2>/dev/null | grep -q '^rabbitmqs\.'; then + echo "CRD rabbitmqs.apps.cozystack.io not found, skipping migration" + kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=35 --dry-run=client -o yaml | kubectl apply -f- + exit 0 +fi + +RABBITMQS=$(kubectl get rabbitmqs.apps.cozystack.io -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}') +for resource in $RABBITMQS; do + NS="${resource%%/*}" + APP_NAME="${resource##*/}" + + # Skip if spec.version is already set + CURRENT_VER=$(kubectl get rabbitmqs.apps.cozystack.io -n "$NS" "$APP_NAME" \ + -o jsonpath='{.spec.version}') + if [ -n "$CURRENT_VER" ]; then + echo "SKIP $NS/$APP_NAME: spec.version already set to '$CURRENT_VER'" + continue + fi + + echo "Patching rabbitmq/$APP_NAME in $NS: setting version=$DEFAULT_VERSION" + + kubectl patch rabbitmqs.apps.cozystack.io -n "$NS" "$APP_NAME" --type=merge \ + --patch "{\"spec\":{\"version\":\"${DEFAULT_VERSION}\"}}" +done + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=35 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/35 b/packages/core/platform/images/migrations/migrations/35 new file mode 100755 index 00000000..a7471180 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/35 @@ -0,0 +1,21 @@ +#!/bin/sh +# Migration 35 --> 36 +# Add helm.sh/resource-policy=keep annotation to existing VLogs resources +# so they are preserved when the monitoring helm release upgrades to VLCluster. +# Users will need to manually verify the new cluster is working, then optionally +# migrate historical data and delete old VLogs resources. + +set -euo pipefail + +VLOGS=$(kubectl get vlogs.operator.victoriametrics.com --all-namespaces --output jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}' 2>/dev/null || true) +for resource in $VLOGS; do + NS="${resource%%/*}" + NAME="${resource##*/}" + echo "Adding keep annotation to VLogs/$NAME in $NS" + kubectl annotate vlogs.operator.victoriametrics.com --namespace "$NS" "$NAME" \ + helm.sh/resource-policy=keep \ + --overwrite +done + +kubectl create configmap --namespace cozy-system cozystack-version \ + --from-literal=version=36 --dry-run=client --output yaml | kubectl apply --filename - diff --git a/packages/core/platform/images/migrations/migrations/36 b/packages/core/platform/images/migrations/migrations/36 new file mode 100755 index 00000000..0f0a94dd --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/36 @@ -0,0 +1,22 @@ +#!/bin/sh +# Migration 36 --> 37 +# +# Copy spec.subnets to spec.networks in VMInstance resources. +# The old "subnets" field is kept intact because migrations run before +# the new CRD is applied; removing it now would lose data. + +set -e + +if ! kubectl get crd vminstances.apps.cozystack.io >/dev/null 2>&1; then + echo "VMInstance CRD not found, skipping migration" +else +kubectl get vminstances.apps.cozystack.io -A -o json | jq -r ' + .items[] + | select(.spec.subnets != null and (.spec.subnets | length) > 0) + | select(.spec.networks == null or (.spec.networks | length) == 0) + | "kubectl -n \(.metadata.namespace) patch vminstances.apps.cozystack.io \(.metadata.name) --type=json -p '\''[{\"op\":\"add\",\"path\":\"/spec/networks\",\"value\":\(.spec.subnets|tojson)}]'\''" +' | sh -ex +fi + +# Write version to cozystack-version config +kubectl create configmap -n cozy-system cozystack-version --from-literal=version=37 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/37 b/packages/core/platform/images/migrations/migrations/37 new file mode 100755 index 00000000..856da262 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/37 @@ -0,0 +1,78 @@ +#!/bin/bash +# Migration 37 --> 38 +# Pin PostgreSQL image to 17.7-standard-trixie for system databases. +# +# This migration updates the imageName for all CNPG clusters belonging to +# system components (keycloak-db, grafana-db, alerta-db, seaweedfs-db, and +# harbor's dynamically-named DB): +# - If imageName is not set: pins to 17.7-standard-trixie +# - If imageName has any PG 17 tag: forces 17.7-standard-trixie +# - If imageName has a bare version tag (e.g. :18.1): appends -standard-trixie +# +# NOTE: This migration ONLY updates system CNPG Cluster resources (clusters.postgresql.cnpg.io), +# NOT user-created Postgres applications. + +set -euo pipefail + +TARGET_IMAGE="ghcr.io/cloudnative-pg/postgresql:17.7-standard-trixie" + +# Static system database names +STATIC_DB_NAMES="keycloak-db grafana-db alerta-db seaweedfs-db" + +echo "=== Updating PostgreSQL images for system databases ===" +echo "Target image: $TARGET_IMAGE" + +# Fetch all CNPG clusters with their name, namespace, imageName, and Helm release annotation in one call +ALL_CLUSTERS=$(kubectl get clusters.postgresql.cnpg.io -A \ + -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.imageName}{"\t"}{.metadata.annotations.meta\.helm\.sh/release-name}{"\n"}{end}' 2>/dev/null || true) + +while IFS=$'\t' read -r NAMESPACE CLUSTER_NAME CURRENT_IMAGE HELM_RELEASE; do + [ -z "$NAMESPACE" ] && continue + + # Check if cluster name matches one of the static system databases + MATCH=false + for db_name in $STATIC_DB_NAMES; do + if [ "$CLUSTER_NAME" = "$db_name" ]; then + MATCH=true + break + fi + done + + # For harbor: match clusters ending with -db whose Helm release ends with -system + if [ "$MATCH" = false ] && [[ "$CLUSTER_NAME" == *-db ]] && [[ "$HELM_RELEASE" == *-system ]]; then + MATCH=true + fi + + if [ "$MATCH" = false ]; then + continue + fi + + PATCH_IMAGE="" + + if [ -z "$CURRENT_IMAGE" ]; then + # imageName not set — pin to target + PATCH_IMAGE="$TARGET_IMAGE" + echo "PATCH $NAMESPACE/$CLUSTER_NAME: imageName not set, setting to $PATCH_IMAGE" + elif [[ "$CURRENT_IMAGE" =~ :17\. ]]; then + # Any PG 17 image — force to the pinned 17.7-standard-trixie + PATCH_IMAGE="$TARGET_IMAGE" + echo "PATCH $NAMESPACE/$CLUSTER_NAME: PG 17 detected, $CURRENT_IMAGE -> $PATCH_IMAGE" + elif [[ "$CURRENT_IMAGE" =~ :[0-9]+\.[0-9]+$ ]]; then + # Bare version tag for other majors (e.g. :18.1) — append -standard-trixie suffix + PATCH_IMAGE="${CURRENT_IMAGE}-standard-trixie" + echo "PATCH $NAMESPACE/$CLUSTER_NAME: bare tag detected, $CURRENT_IMAGE -> $PATCH_IMAGE" + else + echo "SKIP $NAMESPACE/$CLUSTER_NAME: imageName already set to $CURRENT_IMAGE" + continue + fi + + kubectl patch clusters.postgresql.cnpg.io -n "$NAMESPACE" "$CLUSTER_NAME" \ + --type=merge \ + --patch "{\"spec\":{\"imageName\":\"${PATCH_IMAGE}\"}}" +done <<< "$ALL_CLUSTERS" + +echo "=== PostgreSQL image update completed ===" + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=38 --dry-run=client -o yaml | kubectl apply -f- diff --git a/packages/core/platform/images/migrations/migrations/38 b/packages/core/platform/images/migrations/migrations/38 new file mode 100755 index 00000000..59536cb1 --- /dev/null +++ b/packages/core/platform/images/migrations/migrations/38 @@ -0,0 +1,52 @@ +#!/bin/sh +# Migration 38 --> 39 +# Rename DataVolumes/PVCs in cozy-public from vm-image- to vm-default-images-. +# +# The vm-disk package previously looked up golden images with the prefix "vm-image-". +# The new vm-default-images package uses the prefix "vm-default-images-". +# This migration renames any existing DataVolumes so that live vm-disk resources +# continue to resolve their source PVC after upgrade. + +set -euo pipefail + +NAMESPACE="cozy-public" + +# Skip if CDI DataVolume CRD is not installed +if ! kubectl api-resources --api-group=cdi.kubevirt.io -o name 2>/dev/null | grep -q '^datavolumes\.'; then + echo "CDI DataVolume CRD not found, skipping rename" + kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=39 --dry-run=client -o yaml | kubectl apply -f- + exit 0 +fi + +# Find DataVolumes whose name starts with "vm-image-" +DVNAMES=$(kubectl get datavolumes.cdi.kubevirt.io -n "$NAMESPACE" \ + -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null \ + | grep '^vm-image-' || true) + +if [ -z "$DVNAMES" ]; then + echo "No vm-image-* DataVolumes found in $NAMESPACE, nothing to rename" +else + for DVNAME in $DVNAMES; do + NEWNAME="vm-default-images-${DVNAME#vm-image-}" + echo "Renaming DataVolume $DVNAME -> $NEWNAME in namespace $NAMESPACE" + + # Export existing DV spec, swap name, and apply as new object + kubectl get datavolumes.cdi.kubevirt.io -n "$NAMESPACE" "$DVNAME" -o json \ + | jq --arg new "$NEWNAME" ' + del(.metadata.resourceVersion, .metadata.uid, .metadata.creationTimestamp, + .metadata.generation, .metadata.selfLink, .metadata.managedFields, + .status) + | .metadata.name = $new + ' \ + | kubectl apply -f - + + # Delete the old DataVolume + kubectl delete datavolumes.cdi.kubevirt.io -n "$NAMESPACE" "$DVNAME" --ignore-not-found=true + echo "Renamed $DVNAME -> $NEWNAME" + done +fi + +# Stamp version +kubectl create configmap -n cozy-system cozystack-version \ + --from-literal=version=39 --dry-run=client -o yaml | kubectl apply -f- diff --git a/scripts/migrations/4 b/packages/core/platform/images/migrations/migrations/4 similarity index 100% rename from scripts/migrations/4 rename to packages/core/platform/images/migrations/migrations/4 diff --git a/scripts/migrations/5 b/packages/core/platform/images/migrations/migrations/5 similarity index 100% rename from scripts/migrations/5 rename to packages/core/platform/images/migrations/migrations/5 diff --git a/scripts/migrations/6 b/packages/core/platform/images/migrations/migrations/6 similarity index 100% rename from scripts/migrations/6 rename to packages/core/platform/images/migrations/migrations/6 diff --git a/scripts/migrations/7 b/packages/core/platform/images/migrations/migrations/7 similarity index 100% rename from scripts/migrations/7 rename to packages/core/platform/images/migrations/migrations/7 diff --git a/scripts/migrations/8 b/packages/core/platform/images/migrations/migrations/8 similarity index 100% rename from scripts/migrations/8 rename to packages/core/platform/images/migrations/migrations/8 diff --git a/scripts/migrations/9 b/packages/core/platform/images/migrations/migrations/9 similarity index 100% rename from scripts/migrations/9 rename to packages/core/platform/images/migrations/migrations/9 diff --git a/packages/core/platform/images/migrations/run-migrations.sh b/packages/core/platform/images/migrations/run-migrations.sh new file mode 100755 index 00000000..a8224ef7 --- /dev/null +++ b/packages/core/platform/images/migrations/run-migrations.sh @@ -0,0 +1,41 @@ +#!/bin/sh +set -euo pipefail + +NAMESPACE="${NAMESPACE:-cozy-system}" +CURRENT_VERSION="${CURRENT_VERSION:-0}" +TARGET_VERSION="${TARGET_VERSION:-0}" + +echo "Starting migrations from version $CURRENT_VERSION to $TARGET_VERSION" + +# Check if ConfigMap exists +if ! kubectl get configmap --namespace "$NAMESPACE" cozystack-version >/dev/null 2>&1; then + echo "ConfigMap cozystack-version does not exist, creating it with version $TARGET_VERSION" + kubectl create configmap --namespace "$NAMESPACE" cozystack-version \ + --from-literal=version="$TARGET_VERSION" \ + --dry-run=client --output yaml | kubectl apply --filename - + echo "ConfigMap created with version $TARGET_VERSION" + exit 0 +fi + +# If current version is already at target, nothing to do +if [ "$CURRENT_VERSION" -ge "$TARGET_VERSION" ]; then + echo "Current version $CURRENT_VERSION is already at or above target version $TARGET_VERSION" + exit 0 +fi + +# Run migrations sequentially from current version to target version +for i in $(seq $CURRENT_VERSION $((TARGET_VERSION - 1))); do + if [ -f "/migrations/$i" ]; then + echo "Running migration $i" + chmod +x /migrations/$i + /migrations/$i || { + echo "Migration $i failed" + exit 1 + } + echo "Migration $i completed successfully" + else + echo "Migration $i not found, skipping" + fi +done + +echo "All migrations completed successfully" diff --git a/packages/core/platform/sources/backup-controller.yaml b/packages/core/platform/sources/backup-controller.yaml new file mode 100644 index 00000000..f68e168b --- /dev/null +++ b/packages/core/platform/sources/backup-controller.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.backup-controller +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: backup-controller + path: system/backup-controller + install: + privileged: true + namespace: cozy-backup-controller + releaseName: backup-controller diff --git a/packages/core/platform/sources/backupstrategy-controller.yaml b/packages/core/platform/sources/backupstrategy-controller.yaml new file mode 100644 index 00000000..b86c5c0d --- /dev/null +++ b/packages/core/platform/sources/backupstrategy-controller.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.backupstrategy-controller +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: backupstrategy-controller + path: system/backupstrategy-controller + install: + privileged: true + namespace: cozy-backup-controller + releaseName: backupstrategy-controller diff --git a/packages/core/platform/sources/bootbox-application.yaml b/packages/core/platform/sources/bootbox-application.yaml new file mode 100644 index 00000000..ee640176 --- /dev/null +++ b/packages/core/platform/sources/bootbox-application.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.bootbox-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: bootbox + path: extra/bootbox + libraries: ["cozy-lib"] + - name: bootbox-rd + path: system/bootbox-rd + install: + namespace: cozy-system + releaseName: bootbox-rd diff --git a/packages/core/platform/sources/bootbox.yaml b/packages/core/platform/sources/bootbox.yaml new file mode 100644 index 00000000..a7ce246e --- /dev/null +++ b/packages/core/platform/sources/bootbox.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.bootbox +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.bootbox-application + components: + - name: bootbox + path: system/bootbox + install: + privileged: true + namespace: cozy-bootbox + releaseName: bootbox diff --git a/packages/core/platform/sources/bucket-application.yaml b/packages/core/platform/sources/bucket-application.yaml new file mode 100644 index 00000000..a50c116f --- /dev/null +++ b/packages/core/platform/sources/bucket-application.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.bucket-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.objectstorage-controller + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: bucket-system + path: system/bucket + - name: bucket + path: apps/bucket + libraries: ["cozy-lib"] + - name: bucket-rd + path: system/bucket-rd + install: + namespace: cozy-system + releaseName: bucket-rd diff --git a/packages/core/platform/sources/capi-operator.yaml b/packages/core/platform/sources/capi-operator.yaml new file mode 100644 index 00000000..a4536402 --- /dev/null +++ b/packages/core/platform/sources/capi-operator.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.capi-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: capi-operator + path: system/capi-operator + install: + privileged: true + namespace: cozy-cluster-api + releaseName: capi-operator diff --git a/packages/core/platform/sources/capi-provider-bootstrap-kubeadm.yaml b/packages/core/platform/sources/capi-provider-bootstrap-kubeadm.yaml new file mode 100644 index 00000000..90cea107 --- /dev/null +++ b/packages/core/platform/sources/capi-provider-bootstrap-kubeadm.yaml @@ -0,0 +1,34 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.capi-provider-bootstrap-kubeadm +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.capi-operator + components: + - name: capi-providers-bootstrap + path: system/capi-providers-bootstrap + install: + privileged: true + namespace: cozy-cluster-api + releaseName: capi-providers-bootstrap + - name: kubevirt + dependsOn: + - cozystack.networking + - cozystack.capi-operator + components: + - name: capi-providers-bootstrap + path: system/capi-providers-bootstrap + install: + privileged: true + namespace: cozy-cluster-api + releaseName: capi-providers-bootstrap diff --git a/packages/core/platform/sources/capi-provider-core.yaml b/packages/core/platform/sources/capi-provider-core.yaml new file mode 100644 index 00000000..91af6617 --- /dev/null +++ b/packages/core/platform/sources/capi-provider-core.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.capi-provider-core +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.capi-operator + components: + - name: capi-providers-core + path: system/capi-providers-core + install: + privileged: true + namespace: cozy-cluster-api + releaseName: capi-providers-core diff --git a/packages/core/platform/sources/capi-provider-cp-kamaji.yaml b/packages/core/platform/sources/capi-provider-cp-kamaji.yaml new file mode 100644 index 00000000..08c29b8f --- /dev/null +++ b/packages/core/platform/sources/capi-provider-cp-kamaji.yaml @@ -0,0 +1,36 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.capi-provider-cp-kamaji +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.capi-operator + - cozystack.kamaji + components: + - name: capi-providers-cpprovider + path: system/capi-providers-cpprovider + install: + privileged: true + namespace: cozy-cluster-api + releaseName: capi-providers-cpprovider + - name: kamaji + dependsOn: + - cozystack.networking + - cozystack.capi-operator + - cozystack.kamaji + components: + - name: capi-providers-cpprovider + path: system/capi-providers-cpprovider + install: + privileged: true + namespace: cozy-cluster-api + releaseName: capi-providers-cpprovider diff --git a/packages/core/platform/sources/capi-provider-infra-kubevirt.yaml b/packages/core/platform/sources/capi-provider-infra-kubevirt.yaml new file mode 100644 index 00000000..341e1920 --- /dev/null +++ b/packages/core/platform/sources/capi-provider-infra-kubevirt.yaml @@ -0,0 +1,36 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.capi-provider-infra-kubevirt +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.capi-operator + - cozystack.kubevirt + components: + - name: capi-providers-infraprovider + path: system/capi-providers-infraprovider + install: + privileged: true + namespace: cozy-cluster-api + releaseName: capi-providers-infraprovider + - name: kubevirt + dependsOn: + - cozystack.networking + - cozystack.capi-operator + - cozystack.kubevirt + components: + - name: capi-providers-infraprovider + path: system/capi-providers-infraprovider + install: + privileged: true + namespace: cozy-cluster-api + releaseName: capi-providers-infraprovider diff --git a/packages/core/platform/sources/cert-manager.yaml b/packages/core/platform/sources/cert-manager.yaml new file mode 100644 index 00000000..0907021e --- /dev/null +++ b/packages/core/platform/sources/cert-manager.yaml @@ -0,0 +1,35 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.cert-manager +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: cert-manager-crds + path: system/cert-manager-crds + install: + namespace: cozy-cert-manager + releaseName: cert-manager-crds + - name: cert-manager + path: system/cert-manager + install: + namespace: cozy-cert-manager + releaseName: cert-manager + dependsOn: + - cert-manager-crds + - name: cert-manager-issuers + path: system/cert-manager-issuers + install: + namespace: cozy-cert-manager + releaseName: cert-manager-issuers + dependsOn: + - cert-manager diff --git a/packages/core/platform/sources/clickhouse-application.yaml b/packages/core/platform/sources/clickhouse-application.yaml new file mode 100644 index 00000000..f22a003d --- /dev/null +++ b/packages/core/platform/sources/clickhouse-application.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.clickhouse-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.clickhouse-operator + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: clickhouse + path: apps/clickhouse + libraries: ["cozy-lib"] + - name: clickhouse-rd + path: system/clickhouse-rd + install: + namespace: cozy-system + releaseName: clickhouse-rd diff --git a/packages/core/platform/sources/clickhouse-operator.yaml b/packages/core/platform/sources/clickhouse-operator.yaml new file mode 100644 index 00000000..d98d1eb9 --- /dev/null +++ b/packages/core/platform/sources/clickhouse-operator.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.clickhouse-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.prometheus-operator-crds + components: + - name: clickhouse-operator + path: system/clickhouse-operator + install: + namespace: cozy-clickhouse-operator + releaseName: clickhouse-operator diff --git a/packages/core/platform/sources/cluster-autoscaler-azure.yaml b/packages/core/platform/sources/cluster-autoscaler-azure.yaml new file mode 100644 index 00000000..7709f3f7 --- /dev/null +++ b/packages/core/platform/sources/cluster-autoscaler-azure.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.cluster-autoscaler-azure +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: cluster-autoscaler-azure + path: system/cluster-autoscaler + valuesFiles: + - values.yaml + - values-azure.yaml + install: + namespace: cozy-cluster-autoscaler-azure + releaseName: cluster-autoscaler-azure diff --git a/packages/core/platform/sources/cluster-autoscaler-hetzner.yaml b/packages/core/platform/sources/cluster-autoscaler-hetzner.yaml new file mode 100644 index 00000000..bbb1a85b --- /dev/null +++ b/packages/core/platform/sources/cluster-autoscaler-hetzner.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.cluster-autoscaler-hetzner +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: cluster-autoscaler-hetzner + path: system/cluster-autoscaler + valuesFiles: + - values.yaml + - values-hetzner.yaml + install: + namespace: cozy-cluster-autoscaler-hetzner + releaseName: cluster-autoscaler-hetzner diff --git a/packages/core/platform/sources/clustersecret-operator.yaml b/packages/core/platform/sources/clustersecret-operator.yaml new file mode 100644 index 00000000..2dc800ab --- /dev/null +++ b/packages/core/platform/sources/clustersecret-operator.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.clustersecret-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: clustersecret-operator + path: system/clustersecret-operator + install: + namespace: cozy-clustersecret-operator + releaseName: clustersecret-operator diff --git a/packages/core/platform/sources/cozy-proxy.yaml b/packages/core/platform/sources/cozy-proxy.yaml new file mode 100644 index 00000000..041b968f --- /dev/null +++ b/packages/core/platform/sources/cozy-proxy.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.cozy-proxy +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: cozy-proxy + path: system/cozy-proxy + install: + namespace: cozy-system + releaseName: cozy-proxy diff --git a/packages/core/platform/sources/cozystack-basics.yaml b/packages/core/platform/sources/cozystack-basics.yaml new file mode 100644 index 00000000..a3fbbad1 --- /dev/null +++ b/packages/core/platform/sources/cozystack-basics.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.cozystack-basics +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.tenant-application + components: + - name: cozystack-basics + path: system/cozystack-basics + install: + namespace: cozy-system + releaseName: cozystack-basics diff --git a/packages/core/platform/sources/cozystack-engine.yaml b/packages/core/platform/sources/cozystack-engine.yaml new file mode 100644 index 00000000..596c81c4 --- /dev/null +++ b/packages/core/platform/sources/cozystack-engine.yaml @@ -0,0 +1,109 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.cozystack-engine +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: application-definition-crd + path: system/application-definition-crd + install: + namespace: cozy-system + releaseName: application-definition-crd + - name: cozystack-controller + path: system/cozystack-controller + install: + namespace: cozy-system + releaseName: cozystack-controller + dependsOn: + - application-definition-crd + - name: cozystack-api + path: system/cozystack-api + install: + namespace: cozy-system + releaseName: cozystack-api + dependsOn: + - cozystack-controller + - application-definition-crd + - name: lineage-controller-webhook + path: system/lineage-controller-webhook + install: + namespace: cozy-system + releaseName: lineage-controller-webhook + dependsOn: + - cozystack-controller + - application-definition-crd + - name: dashboard + path: system/dashboard + install: + namespace: cozy-dashboard + releaseName: dashboard + dependsOn: + - cozystack-api + - cozystack-controller + - application-definition-crd + - name: oidc + dependsOn: + - cozystack.networking + - cozystack.keycloak + - cozystack.keycloak-operator + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: application-definition-crd + path: system/application-definition-crd + install: + namespace: cozy-system + releaseName: application-definition-crd + - name: cozystack-controller + path: system/cozystack-controller + install: + namespace: cozy-system + releaseName: cozystack-controller + dependsOn: + - application-definition-crd + - name: cozystack-api + path: system/cozystack-api + install: + namespace: cozy-system + releaseName: cozystack-api + dependsOn: + - cozystack-controller + - application-definition-crd + - name: lineage-controller-webhook + path: system/lineage-controller-webhook + install: + namespace: cozy-system + releaseName: lineage-controller-webhook + dependsOn: + - cozystack-controller + - application-definition-crd + - name: dashboard + path: system/dashboard + install: + namespace: cozy-dashboard + releaseName: dashboard + dependsOn: + - cozystack-api + - cozystack-controller + - keycloak-configure + - application-definition-crd + - name: keycloak-configure + path: system/keycloak-configure + install: + namespace: cozy-keycloak + releaseName: keycloak-configure + dependsOn: [] diff --git a/packages/core/platform/sources/cozystack-scheduler.yaml b/packages/core/platform/sources/cozystack-scheduler.yaml new file mode 100644 index 00000000..52e85a4f --- /dev/null +++ b/packages/core/platform/sources/cozystack-scheduler.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.cozystack-scheduler +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + components: + - name: cozystack-scheduler + path: system/cozystack-scheduler + install: + namespace: kube-system + releaseName: cozystack-scheduler + - name: linstor + dependsOn: + - cozystack.linstor-scheduler + components: + - name: cozystack-scheduler + path: system/cozystack-scheduler + valuesFiles: + - values-linstor.yaml + install: + namespace: kube-system + releaseName: cozystack-scheduler diff --git a/packages/core/platform/sources/etcd-application.yaml b/packages/core/platform/sources/etcd-application.yaml new file mode 100644 index 00000000..1abcec12 --- /dev/null +++ b/packages/core/platform/sources/etcd-application.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.etcd-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: etcd + path: extra/etcd + libraries: ["cozy-lib"] + - name: etcd-rd + path: system/etcd-rd + install: + namespace: cozy-system + releaseName: etcd-rd diff --git a/packages/core/platform/sources/etcd-operator.yaml b/packages/core/platform/sources/etcd-operator.yaml new file mode 100644 index 00000000..5f42a4a0 --- /dev/null +++ b/packages/core/platform/sources/etcd-operator.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.etcd-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.cert-manager + - cozystack.vertical-pod-autoscaler + components: + - name: etcd-operator + path: system/etcd-operator + install: + namespace: cozy-etcd-operator + releaseName: etcd-operator diff --git a/packages/core/platform/sources/external-dns-application.yaml b/packages/core/platform/sources/external-dns-application.yaml new file mode 100644 index 00000000..0a37dc52 --- /dev/null +++ b/packages/core/platform/sources/external-dns-application.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.external-dns-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: external-dns-system + path: system/external-dns + - name: external-dns + path: extra/external-dns + libraries: ["cozy-lib"] + - name: external-dns-rd + path: system/external-dns-rd + install: + namespace: cozy-system + releaseName: external-dns-rd diff --git a/packages/core/platform/sources/external-dns.yaml b/packages/core/platform/sources/external-dns.yaml new file mode 100644 index 00000000..a3f6ca6e --- /dev/null +++ b/packages/core/platform/sources/external-dns.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.external-dns +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: external-dns + path: system/external-dns + install: + namespace: cozy-external-dns + releaseName: external-dns diff --git a/packages/core/platform/sources/external-secrets-operator.yaml b/packages/core/platform/sources/external-secrets-operator.yaml new file mode 100644 index 00000000..bc69dcce --- /dev/null +++ b/packages/core/platform/sources/external-secrets-operator.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.external-secrets-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: external-secrets-operator + path: system/external-secrets-operator + install: + namespace: cozy-external-secrets-operator + releaseName: external-secrets-operator diff --git a/packages/core/platform/sources/flux-plunger.yaml b/packages/core/platform/sources/flux-plunger.yaml new file mode 100644 index 00000000..bbee0b34 --- /dev/null +++ b/packages/core/platform/sources/flux-plunger.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.flux-plunger +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.cert-manager + - cozystack.cozystack-engine + components: + - name: flux-plunger + path: system/flux-plunger + install: + namespace: cozy-fluxcd + releaseName: flux-plunger diff --git a/packages/core/platform/sources/foundationdb-application.yaml b/packages/core/platform/sources/foundationdb-application.yaml new file mode 100644 index 00000000..4488b033 --- /dev/null +++ b/packages/core/platform/sources/foundationdb-application.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.foundationdb-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.foundationdb-operator + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: foundationdb + path: apps/foundationdb + libraries: ["cozy-lib"] + - name: foundationdb-rd + path: system/foundationdb-rd + install: + namespace: cozy-system + releaseName: foundationdb-rd diff --git a/packages/core/platform/sources/foundationdb-operator.yaml b/packages/core/platform/sources/foundationdb-operator.yaml new file mode 100644 index 00000000..0af881f6 --- /dev/null +++ b/packages/core/platform/sources/foundationdb-operator.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.foundationdb-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.cert-manager + components: + - name: foundationdb-operator + path: system/foundationdb-operator + install: + namespace: cozy-foundationdb-operator + releaseName: foundationdb-operator diff --git a/packages/core/platform/sources/goldpinger.yaml b/packages/core/platform/sources/goldpinger.yaml new file mode 100644 index 00000000..975ad138 --- /dev/null +++ b/packages/core/platform/sources/goldpinger.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.goldpinger +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.prometheus-operator-crds + components: + - name: goldpinger + path: system/goldpinger + install: + privileged: true + namespace: cozy-goldpinger + releaseName: goldpinger diff --git a/packages/core/platform/sources/gpu-operator.yaml b/packages/core/platform/sources/gpu-operator.yaml new file mode 100644 index 00000000..e41cc9b2 --- /dev/null +++ b/packages/core/platform/sources/gpu-operator.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.gpu-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: gpu-operator + path: system/gpu-operator + valuesFiles: + - values.yaml + - values-talos.yaml + install: + privileged: true + namespace: cozy-gpu-operator + releaseName: gpu-operator diff --git a/packages/core/platform/sources/grafana-operator.yaml b/packages/core/platform/sources/grafana-operator.yaml new file mode 100644 index 00000000..d46597b7 --- /dev/null +++ b/packages/core/platform/sources/grafana-operator.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.grafana-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: grafana-operator + path: system/grafana-operator + install: + namespace: cozy-grafana-operator + releaseName: grafana-operator diff --git a/packages/core/platform/sources/hami.yaml b/packages/core/platform/sources/hami.yaml new file mode 100644 index 00000000..0184e405 --- /dev/null +++ b/packages/core/platform/sources/hami.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.hami +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.gpu-operator + components: + - name: hami + path: system/hami + valuesFiles: + - values.yaml + install: + privileged: true + namespace: cozy-hami + releaseName: hami diff --git a/packages/core/platform/sources/harbor-application.yaml b/packages/core/platform/sources/harbor-application.yaml new file mode 100644 index 00000000..c2773bdd --- /dev/null +++ b/packages/core/platform/sources/harbor-application.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.harbor-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.postgres-operator + - cozystack.redis-operator + - cozystack.objectstorage-controller + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: harbor-system + path: system/harbor + - name: harbor + path: apps/harbor + libraries: ["cozy-lib"] + - name: harbor-rd + path: system/harbor-rd + install: + namespace: cozy-system + releaseName: harbor-rd diff --git a/packages/core/platform/sources/hetzner-robotlb.yaml b/packages/core/platform/sources/hetzner-robotlb.yaml new file mode 100644 index 00000000..8660890c --- /dev/null +++ b/packages/core/platform/sources/hetzner-robotlb.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.hetzner-robotlb +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: hetzner-robotlb + path: system/hetzner-robotlb + install: + namespace: cozy-hetzner-robotlb + releaseName: robotlb diff --git a/packages/core/platform/sources/http-cache-application.yaml b/packages/core/platform/sources/http-cache-application.yaml new file mode 100644 index 00000000..67537b4f --- /dev/null +++ b/packages/core/platform/sources/http-cache-application.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.http-cache-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: http-cache + path: apps/http-cache + libraries: [cozy-lib] + - name: http-cache-rd + path: system/http-cache-rd + install: + namespace: cozy-system + releaseName: http-cache-rd diff --git a/packages/core/platform/sources/info-application.yaml b/packages/core/platform/sources/info-application.yaml new file mode 100644 index 00000000..25b8b798 --- /dev/null +++ b/packages/core/platform/sources/info-application.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.info-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: info + path: extra/info + libraries: ["cozy-lib"] + - name: info-rd + path: system/info-rd + install: + namespace: cozy-system + releaseName: info-rd diff --git a/packages/core/platform/sources/ingress-application.yaml b/packages/core/platform/sources/ingress-application.yaml new file mode 100644 index 00000000..638c2f1c --- /dev/null +++ b/packages/core/platform/sources/ingress-application.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.ingress-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: ingress-system + path: system/ingress-nginx + - name: ingress + path: extra/ingress + libraries: ["cozy-lib"] + - name: ingress-rd + path: system/ingress-rd + install: + namespace: cozy-system + releaseName: ingress-rd diff --git a/packages/core/platform/sources/ingress-nginx.yaml b/packages/core/platform/sources/ingress-nginx.yaml new file mode 100644 index 00000000..b51e096f --- /dev/null +++ b/packages/core/platform/sources/ingress-nginx.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.ingress-nginx +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.prometheus-operator-crds + components: + - name: ingress-nginx + path: system/ingress-nginx + install: + namespace: cozy-ingress-nginx + releaseName: ingress-nginx diff --git a/packages/core/platform/sources/kafka-application.yaml b/packages/core/platform/sources/kafka-application.yaml new file mode 100644 index 00000000..4a5ca158 --- /dev/null +++ b/packages/core/platform/sources/kafka-application.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.kafka-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.kafka-operator + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: kafka + path: apps/kafka + libraries: ["cozy-lib"] + - name: kafka-rd + path: system/kafka-rd + install: + namespace: cozy-system + releaseName: kafka-rd diff --git a/packages/core/platform/sources/kafka-operator.yaml b/packages/core/platform/sources/kafka-operator.yaml new file mode 100644 index 00000000..83d7d502 --- /dev/null +++ b/packages/core/platform/sources/kafka-operator.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.kafka-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.prometheus-operator-crds + components: + - name: kafka-operator + path: system/kafka-operator + install: + namespace: cozy-kafka-operator + releaseName: kafka-operator diff --git a/packages/core/platform/sources/kamaji.yaml b/packages/core/platform/sources/kamaji.yaml new file mode 100644 index 00000000..915c5898 --- /dev/null +++ b/packages/core/platform/sources/kamaji.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.kamaji +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: kamaji + path: system/kamaji + install: + namespace: cozy-kamaji + releaseName: kamaji diff --git a/packages/core/platform/sources/keycloak-operator.yaml b/packages/core/platform/sources/keycloak-operator.yaml new file mode 100644 index 00000000..ce3a5f7e --- /dev/null +++ b/packages/core/platform/sources/keycloak-operator.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.keycloak-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.keycloak + components: + - name: keycloak-operator + path: system/keycloak-operator + install: + namespace: cozy-keycloak + releaseName: keycloak-operator diff --git a/packages/core/platform/sources/keycloak.yaml b/packages/core/platform/sources/keycloak.yaml new file mode 100644 index 00000000..545d70a5 --- /dev/null +++ b/packages/core/platform/sources/keycloak.yaml @@ -0,0 +1,26 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.keycloak +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.postgres-operator + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: keycloak + path: system/keycloak + libraries: ["cozy-lib"] + install: + namespace: cozy-keycloak + releaseName: keycloak diff --git a/packages/core/platform/sources/kubeovn-plunger.yaml b/packages/core/platform/sources/kubeovn-plunger.yaml new file mode 100644 index 00000000..bdd8f1c8 --- /dev/null +++ b/packages/core/platform/sources/kubeovn-plunger.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.kubeovn-plunger +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.cert-manager + - cozystack.networking + - cozystack.victoria-metrics-operator + components: + - name: kubeovn-plunger + path: system/kubeovn-plunger + install: + namespace: cozy-kubeovn + releaseName: kubeovn-plunger diff --git a/packages/core/platform/sources/kubeovn-webhook.yaml b/packages/core/platform/sources/kubeovn-webhook.yaml new file mode 100644 index 00000000..3125b692 --- /dev/null +++ b/packages/core/platform/sources/kubeovn-webhook.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.kubeovn-webhook +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.cert-manager + components: + - name: kubeovn-webhook + path: system/kubeovn-webhook + install: + privileged: true + namespace: cozy-kubeovn + releaseName: kubeovn-webhook diff --git a/packages/core/platform/sources/kubernetes-application.yaml b/packages/core/platform/sources/kubernetes-application.yaml new file mode 100644 index 00000000..088383ad --- /dev/null +++ b/packages/core/platform/sources/kubernetes-application.yaml @@ -0,0 +1,70 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.kubernetes-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: kubevirt + dependsOn: + - cozystack.networking + - cozystack.capi-operator + - cozystack.capi-provider-bootstrap-kubeadm + - cozystack.capi-provider-core + - cozystack.capi-provider-cp-kamaji + - cozystack.capi-provider-infra-kubevirt + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: kubernetes-ingress-nginx + path: system/ingress-nginx + - name: kubernetes-cert-manager-crds + path: system/cert-manager-crds + - name: kubernetes-volumesnapshot-crd + path: system/vsnap-crd + - name: kubernetes-velero + path: system/velero + - name: kubernetes-gateway-api-crds + path: system/gateway-api-crds + - name: kubernetes-victoria-metrics-operator + path: system/victoria-metrics-operator + - name: kubernetes-kubevirt-csi-node + path: system/kubevirt-csi-node + - name: kubernetes-vertical-pod-autoscaler-crds + path: system/vertical-pod-autoscaler-crds + - name: kubernetes-coredns + path: system/coredns + - name: kubernetes-cert-manager + path: system/cert-manager + - name: kubernetes-fluxcd-operator + path: system/fluxcd-operator + - name: kubernetes-fluxcd + path: system/fluxcd + - name: kubernetes-monitoring-agents + path: system/monitoring-agents + - name: kubernetes-cilium + path: system/cilium + - name: kubernetes-gpu-operator + path: system/gpu-operator + - name: kubernetes-hami + path: system/hami + - name: kubernetes-vertical-pod-autoscaler + path: system/vertical-pod-autoscaler + - name: kubernetes-prometheus-operator-crds + path: system/prometheus-operator-crds + - name: kubernetes-metrics-server + path: system/metrics-server + - name: kubernetes + path: apps/kubernetes + libraries: ["cozy-lib"] + - name: kubernetes-rd + path: system/kubernetes-rd + install: + namespace: cozy-system + releaseName: kubernetes-rd diff --git a/packages/core/platform/sources/kubevirt-cdi.yaml b/packages/core/platform/sources/kubevirt-cdi.yaml new file mode 100644 index 00000000..bd925c0d --- /dev/null +++ b/packages/core/platform/sources/kubevirt-cdi.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.kubevirt-cdi +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: kubevirt-cdi-operator + path: system/kubevirt-cdi-operator + install: + namespace: cozy-kubevirt-cdi + releaseName: kubevirt-cdi-operator + - name: kubevirt-cdi + path: system/kubevirt-cdi + install: + namespace: cozy-kubevirt-cdi + releaseName: kubevirt-cdi + dependsOn: + - kubevirt-cdi-operator diff --git a/packages/core/platform/sources/kubevirt.yaml b/packages/core/platform/sources/kubevirt.yaml new file mode 100644 index 00000000..d1bb7a13 --- /dev/null +++ b/packages/core/platform/sources/kubevirt.yaml @@ -0,0 +1,38 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.kubevirt +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.prometheus-operator-crds + components: + - name: kubevirt-operator + path: system/kubevirt-operator + install: + namespace: cozy-kubevirt + releaseName: kubevirt-operator + - name: kubevirt + path: system/kubevirt + install: + privileged: true + namespace: cozy-kubevirt + releaseName: kubevirt + dependsOn: + - kubevirt-operator + - name: kubevirt-instancetypes + path: system/kubevirt-instancetypes + install: + namespace: cozy-kubevirt + releaseName: kubevirt-instancetypes + dependsOn: + - kubevirt-operator + - kubevirt diff --git a/packages/core/platform/sources/linstor-gui.yaml b/packages/core/platform/sources/linstor-gui.yaml new file mode 100644 index 00000000..005e1fb7 --- /dev/null +++ b/packages/core/platform/sources/linstor-gui.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.linstor-gui +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.linstor + components: + - name: linstor-gui + path: system/linstor-gui + install: + namespace: cozy-linstor + releaseName: linstor-gui diff --git a/packages/core/platform/sources/linstor-scheduler.yaml b/packages/core/platform/sources/linstor-scheduler.yaml new file mode 100644 index 00000000..fad3eeb7 --- /dev/null +++ b/packages/core/platform/sources/linstor-scheduler.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.linstor-scheduler +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.linstor + - cozystack.cert-manager + components: + - name: linstor-scheduler + path: system/linstor-scheduler + install: + namespace: cozy-linstor + releaseName: linstor-scheduler diff --git a/packages/core/platform/sources/linstor.yaml b/packages/core/platform/sources/linstor.yaml new file mode 100644 index 00000000..6e2ec01a --- /dev/null +++ b/packages/core/platform/sources/linstor.yaml @@ -0,0 +1,41 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.linstor +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.cert-manager + - cozystack.victoria-metrics-operator + - cozystack.reloader + - cozystack.snapshot-controller + components: + - name: piraeus-operator-crds + path: system/piraeus-operator-crds + install: + privileged: true + namespace: cozy-linstor + releaseName: piraeus-operator-crds + - name: piraeus-operator + path: system/piraeus-operator + install: + namespace: cozy-linstor + releaseName: piraeus-operator + dependsOn: + - piraeus-operator-crds + - name: linstor + path: system/linstor + install: + privileged: true + namespace: cozy-linstor + releaseName: linstor + dependsOn: + - piraeus-operator diff --git a/packages/core/platform/sources/local-ccm.yaml b/packages/core/platform/sources/local-ccm.yaml new file mode 100644 index 00000000..5317abf8 --- /dev/null +++ b/packages/core/platform/sources/local-ccm.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.local-ccm +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: local-ccm + path: system/local-ccm + install: + privileged: true + namespace: cozy-local-ccm + releaseName: local-ccm diff --git a/packages/core/platform/sources/mariadb-application.yaml b/packages/core/platform/sources/mariadb-application.yaml new file mode 100644 index 00000000..34ff901b --- /dev/null +++ b/packages/core/platform/sources/mariadb-application.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.mariadb-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.mariadb-operator + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: mariadb + path: apps/mariadb + libraries: ["cozy-lib"] + - name: mariadb-rd + path: system/mariadb-rd + install: + namespace: cozy-system + releaseName: mariadb-rd diff --git a/packages/core/platform/sources/mariadb-operator.yaml b/packages/core/platform/sources/mariadb-operator.yaml new file mode 100644 index 00000000..7be1da14 --- /dev/null +++ b/packages/core/platform/sources/mariadb-operator.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.mariadb-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.prometheus-operator-crds + - cozystack.cert-manager + components: + - name: mariadb-operator + path: system/mariadb-operator + install: + namespace: cozy-mariadb-operator + releaseName: mariadb-operator diff --git a/packages/core/platform/sources/metallb.yaml b/packages/core/platform/sources/metallb.yaml new file mode 100644 index 00000000..e1a09886 --- /dev/null +++ b/packages/core/platform/sources/metallb.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.metallb +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: metallb + path: system/metallb + install: + privileged: true + namespace: cozy-metallb + releaseName: metallb diff --git a/packages/core/platform/sources/metrics-server.yaml b/packages/core/platform/sources/metrics-server.yaml new file mode 100644 index 00000000..607cd7f0 --- /dev/null +++ b/packages/core/platform/sources/metrics-server.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.metrics-server +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.prometheus-operator-crds + components: + - name: metrics-server + path: system/metrics-server + install: + namespace: cozy-monitoring + releaseName: metrics-server diff --git a/packages/core/platform/sources/mongodb-application.yaml b/packages/core/platform/sources/mongodb-application.yaml new file mode 100644 index 00000000..b6106fe1 --- /dev/null +++ b/packages/core/platform/sources/mongodb-application.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.mongodb-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: mongodb + path: apps/mongodb + libraries: ["cozy-lib"] + - name: mongodb-rd + path: system/mongodb-rd + install: + namespace: cozy-system + releaseName: mongodb-rd diff --git a/packages/core/platform/sources/mongodb-operator.yaml b/packages/core/platform/sources/mongodb-operator.yaml new file mode 100644 index 00000000..e3d6fe9e --- /dev/null +++ b/packages/core/platform/sources/mongodb-operator.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.mongodb-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.prometheus-operator-crds + - cozystack.cert-manager + components: + - name: mongodb-operator + path: system/mongodb-operator + install: + namespace: cozy-mongodb-operator + releaseName: mongodb-operator diff --git a/packages/core/platform/sources/monitoring-agents.yaml b/packages/core/platform/sources/monitoring-agents.yaml new file mode 100644 index 00000000..206699b6 --- /dev/null +++ b/packages/core/platform/sources/monitoring-agents.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.monitoring-agents +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.metrics-server + - cozystack.victoria-metrics-operator + - cozystack.vertical-pod-autoscaler + components: + - name: monitoring-agents + path: system/monitoring-agents + install: + releaseName: monitoring-agents + namespace: cozy-monitoring + privileged: true diff --git a/packages/core/platform/sources/monitoring-application.yaml b/packages/core/platform/sources/monitoring-application.yaml new file mode 100644 index 00000000..119aaa37 --- /dev/null +++ b/packages/core/platform/sources/monitoring-application.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.monitoring-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.postgres-operator + - cozystack.grafana-operator + - cozystack.victoria-metrics-operator + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: monitoring-system + path: system/monitoring + libraries: ["cozy-lib"] + - name: monitoring + path: extra/monitoring + libraries: ["cozy-lib"] + - name: monitoring-rd + path: system/monitoring-rd + install: + namespace: cozy-system + releaseName: monitoring-rd diff --git a/packages/core/platform/sources/monitoring.yaml b/packages/core/platform/sources/monitoring.yaml new file mode 100644 index 00000000..ea2007ec --- /dev/null +++ b/packages/core/platform/sources/monitoring.yaml @@ -0,0 +1,43 @@ + +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.monitoring + annotations: + operator.cozystack.io/skip-cozystack-values: "true" +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.vertical-pod-autoscaler + - cozystack.networking + - cozystack.postgres-operator + - cozystack.grafana-operator + - cozystack.victoria-metrics-operator + - cozystack.prometheus-operator-crds + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: monitoring + path: system/monitoring + libraries: ["cozy-lib"] + install: + privileged: true + namespace: cozy-monitoring + releaseName: monitoring + - name: vertical-pod-autoscaler + path: system/vertical-pod-autoscaler + - name: postgres-operator + path: system/postgres-operator + - name: grafana-operator + path: system/grafana-operator + - name: victoria-metrics-operator + path: system/victoria-metrics-operator + - name: prometheus-operator-crds + path: system/prometheus-operator-crds \ No newline at end of file diff --git a/packages/core/platform/sources/multus.yaml b/packages/core/platform/sources/multus.yaml new file mode 100644 index 00000000..88910e93 --- /dev/null +++ b/packages/core/platform/sources/multus.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.multus +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: multus + path: system/multus + install: + privileged: true + namespace: cozy-multus + releaseName: multus diff --git a/packages/core/platform/sources/nats-application.yaml b/packages/core/platform/sources/nats-application.yaml new file mode 100644 index 00000000..b09c5a30 --- /dev/null +++ b/packages/core/platform/sources/nats-application.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.nats-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: nats-system + path: system/nats + - name: nats + path: apps/nats + libraries: ["cozy-lib"] + - name: nats-rd + path: system/nats-rd + install: + namespace: cozy-system + releaseName: nats-rd diff --git a/packages/core/platform/sources/networking.yaml b/packages/core/platform/sources/networking.yaml new file mode 100644 index 00000000..bece76f8 --- /dev/null +++ b/packages/core/platform/sources/networking.yaml @@ -0,0 +1,143 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.networking +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: noop + components: [] + - name: cilium + dependsOn: [] + components: + - name: cilium + path: system/cilium + valuesFiles: + - values.yaml + - values-talos.yaml + install: + privileged: true + namespace: cozy-cilium + releaseName: cilium + dependsOn: [] + - name: cilium-networkpolicy + path: system/cilium-networkpolicy + install: + privileged: true + namespace: cozy-cilium + releaseName: cilium-networkpolicy + dependsOn: + - cilium + - name: cilium-kilo + dependsOn: [] + components: + - name: cilium + path: system/cilium + valuesFiles: + - values.yaml + - values-talos.yaml + - values-kilo.yaml + install: + privileged: true + namespace: cozy-cilium + releaseName: cilium + dependsOn: [] + - name: kilo + path: system/kilo + valuesFiles: + - values.yaml + - values-cilium.yaml + install: + privileged: true + namespace: cozy-kilo + releaseName: kilo + dependsOn: + - cilium + # Generic Cilium variant for non-Talos clusters (kubeadm, k3s, RKE2, etc.) + - name: cilium-generic + dependsOn: [] + components: + - name: cilium + path: system/cilium + valuesFiles: + - values.yaml + - values-apparmor.yaml + install: + privileged: true + namespace: cozy-cilium + releaseName: cilium + dependsOn: [] + - name: cilium-networkpolicy + path: system/cilium-networkpolicy + install: + privileged: true + namespace: cozy-cilium + releaseName: cilium-networkpolicy + dependsOn: + - cilium + - name: kubeovn-cilium + dependsOn: [] + components: + - name: cilium + path: system/cilium + valuesFiles: + - values.yaml + - values-talos.yaml + - values-kubeovn.yaml + install: + privileged: true + namespace: cozy-cilium + releaseName: cilium + dependsOn: [] + - name: cilium-networkpolicy + path: system/cilium-networkpolicy + install: + privileged: true + namespace: cozy-cilium + releaseName: cilium-networkpolicy + dependsOn: + - cilium + - name: kubeovn + path: system/kubeovn + install: + privileged: true + namespace: cozy-kubeovn + releaseName: kubeovn + dependsOn: + - cilium + # Generic KubeOVN+Cilium variant for non-Talos clusters (kubeadm, k3s, RKE2, etc.) + - name: kubeovn-cilium-generic + dependsOn: [] + components: + - name: cilium + path: system/cilium + valuesFiles: + - values.yaml + - values-apparmor.yaml + - values-kubeovn.yaml + install: + privileged: true + namespace: cozy-cilium + releaseName: cilium + dependsOn: [] + - name: cilium-networkpolicy + path: system/cilium-networkpolicy + install: + privileged: true + namespace: cozy-cilium + releaseName: cilium-networkpolicy + dependsOn: + - cilium + - name: kubeovn + path: system/kubeovn + install: + privileged: true + namespace: cozy-kubeovn + releaseName: kubeovn + dependsOn: + - cilium diff --git a/packages/core/platform/sources/nfs-driver.yaml b/packages/core/platform/sources/nfs-driver.yaml new file mode 100644 index 00000000..aa1effec --- /dev/null +++ b/packages/core/platform/sources/nfs-driver.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.nfs-driver +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: nfs-driver + path: system/nfs-driver + install: + privileged: true + namespace: cozy-nfs-driver + releaseName: nfs-driver diff --git a/packages/core/platform/sources/objectstorage-controller.yaml b/packages/core/platform/sources/objectstorage-controller.yaml new file mode 100644 index 00000000..cf89ee46 --- /dev/null +++ b/packages/core/platform/sources/objectstorage-controller.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.objectstorage-controller +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: objectstorage-controller + path: system/objectstorage-controller + install: + namespace: cozy-objectstorage-controller + releaseName: objectstorage-controller diff --git a/packages/core/platform/sources/openbao-application.yaml b/packages/core/platform/sources/openbao-application.yaml new file mode 100644 index 00000000..438148af --- /dev/null +++ b/packages/core/platform/sources/openbao-application.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.openbao-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: openbao-system + path: system/openbao + - name: openbao + path: apps/openbao + libraries: ["cozy-lib"] + - name: openbao-rd + path: system/openbao-rd + install: + namespace: cozy-system + releaseName: openbao-rd diff --git a/packages/core/platform/sources/opensearch-application.yaml b/packages/core/platform/sources/opensearch-application.yaml new file mode 100644 index 00000000..19358c21 --- /dev/null +++ b/packages/core/platform/sources/opensearch-application.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.opensearch-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.opensearch-operator + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: opensearch + path: apps/opensearch + libraries: ["cozy-lib"] + - name: opensearch-rd + path: system/opensearch-rd + install: + namespace: cozy-system + releaseName: opensearch-rd diff --git a/packages/core/platform/sources/opensearch-operator.yaml b/packages/core/platform/sources/opensearch-operator.yaml new file mode 100644 index 00000000..21dd7a43 --- /dev/null +++ b/packages/core/platform/sources/opensearch-operator.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.opensearch-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.prometheus-operator-crds + components: + - name: opensearch-operator + path: system/opensearch-operator + install: + namespace: cozy-opensearch-operator + releaseName: opensearch-operator diff --git a/packages/core/platform/sources/postgres-application.yaml b/packages/core/platform/sources/postgres-application.yaml new file mode 100644 index 00000000..5d7b220b --- /dev/null +++ b/packages/core/platform/sources/postgres-application.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.postgres-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.postgres-operator + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: postgres + path: apps/postgres + libraries: ["cozy-lib"] + - name: postgres-rd + path: system/postgres-rd + install: + namespace: cozy-system + releaseName: postgres-rd diff --git a/packages/core/platform/sources/postgres-operator.yaml b/packages/core/platform/sources/postgres-operator.yaml new file mode 100644 index 00000000..c72e5269 --- /dev/null +++ b/packages/core/platform/sources/postgres-operator.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.postgres-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.prometheus-operator-crds + - cozystack.cert-manager + components: + - name: postgres-operator + path: system/postgres-operator + install: + namespace: cozy-postgres-operator + releaseName: postgres-operator diff --git a/packages/core/platform/sources/prometheus-operator-crds.yaml b/packages/core/platform/sources/prometheus-operator-crds.yaml new file mode 100644 index 00000000..4ab9ad98 --- /dev/null +++ b/packages/core/platform/sources/prometheus-operator-crds.yaml @@ -0,0 +1,20 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.prometheus-operator-crds +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: [] + components: + - name: prometheus-operator-crds + path: system/prometheus-operator-crds + install: + namespace: cozy-victoria-metrics-operator + releaseName: prometheus-operator-crds diff --git a/packages/core/platform/sources/qdrant-application.yaml b/packages/core/platform/sources/qdrant-application.yaml new file mode 100644 index 00000000..6477cc37 --- /dev/null +++ b/packages/core/platform/sources/qdrant-application.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.qdrant-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: qdrant-system + path: system/qdrant + - name: qdrant + path: apps/qdrant + libraries: ["cozy-lib"] + - name: qdrant-rd + path: system/qdrant-rd + install: + namespace: cozy-system + releaseName: qdrant-rd diff --git a/packages/core/platform/sources/rabbitmq-application.yaml b/packages/core/platform/sources/rabbitmq-application.yaml new file mode 100644 index 00000000..7dc68b31 --- /dev/null +++ b/packages/core/platform/sources/rabbitmq-application.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.rabbitmq-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.rabbitmq-operator + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: rabbitmq + path: apps/rabbitmq + libraries: ["cozy-lib"] + - name: rabbitmq-rd + path: system/rabbitmq-rd + install: + namespace: cozy-system + releaseName: rabbitmq-rd diff --git a/packages/core/platform/sources/rabbitmq-operator.yaml b/packages/core/platform/sources/rabbitmq-operator.yaml new file mode 100644 index 00000000..843ceb47 --- /dev/null +++ b/packages/core/platform/sources/rabbitmq-operator.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.rabbitmq-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: rabbitmq-operator + path: system/rabbitmq-operator + install: + namespace: cozy-rabbitmq-operator + releaseName: rabbitmq-operator diff --git a/packages/core/platform/sources/redis-application.yaml b/packages/core/platform/sources/redis-application.yaml new file mode 100644 index 00000000..41a2a9dc --- /dev/null +++ b/packages/core/platform/sources/redis-application.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.redis-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.redis-operator + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: redis + path: apps/redis + libraries: ["cozy-lib"] + - name: redis-rd + path: system/redis-rd + install: + namespace: cozy-system + releaseName: redis-rd diff --git a/packages/core/platform/sources/redis-operator.yaml b/packages/core/platform/sources/redis-operator.yaml new file mode 100644 index 00000000..9abb3d26 --- /dev/null +++ b/packages/core/platform/sources/redis-operator.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.redis-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: redis-operator + path: system/redis-operator + install: + namespace: cozy-redis-operator + releaseName: redis-operator diff --git a/packages/core/platform/sources/reloader.yaml b/packages/core/platform/sources/reloader.yaml new file mode 100644 index 00000000..fb3f2e44 --- /dev/null +++ b/packages/core/platform/sources/reloader.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.reloader +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: reloader + path: system/reloader + install: + namespace: cozy-reloader + releaseName: reloader diff --git a/packages/core/platform/sources/seaweedfs-application.yaml b/packages/core/platform/sources/seaweedfs-application.yaml new file mode 100644 index 00000000..70de6662 --- /dev/null +++ b/packages/core/platform/sources/seaweedfs-application.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.seaweedfs-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: seaweedfs-system + path: system/seaweedfs + - name: seaweedfs + path: extra/seaweedfs + libraries: ["cozy-lib"] + - name: seaweedfs-rd + path: system/seaweedfs-rd + install: + namespace: cozy-system + releaseName: seaweedfs-rd diff --git a/packages/core/platform/sources/snapshot-controller.yaml b/packages/core/platform/sources/snapshot-controller.yaml new file mode 100644 index 00000000..3d4342a4 --- /dev/null +++ b/packages/core/platform/sources/snapshot-controller.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.snapshot-controller +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.cert-manager + components: + - name: snapshot-controller + path: system/snapshot-controller + install: + namespace: cozy-snapshot-controller + releaseName: snapshot-controller diff --git a/packages/core/platform/sources/tcp-balancer-application.yaml b/packages/core/platform/sources/tcp-balancer-application.yaml new file mode 100644 index 00000000..0ba031e7 --- /dev/null +++ b/packages/core/platform/sources/tcp-balancer-application.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.tcp-balancer-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: tcp-balancer + path: apps/tcp-balancer + libraries: ["cozy-lib"] + - name: tcp-balancer-rd + path: system/tcp-balancer-rd + install: + namespace: cozy-system + releaseName: tcp-balancer-rd diff --git a/packages/core/platform/sources/telepresence.yaml b/packages/core/platform/sources/telepresence.yaml new file mode 100644 index 00000000..ae52d918 --- /dev/null +++ b/packages/core/platform/sources/telepresence.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.telepresence +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: telepresence + path: system/telepresence + install: + namespace: cozy-telepresence + releaseName: traffic-manager diff --git a/packages/core/platform/sources/tenant-application.yaml b/packages/core/platform/sources/tenant-application.yaml new file mode 100644 index 00000000..d95cfd44 --- /dev/null +++ b/packages/core/platform/sources/tenant-application.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.tenant-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.ingress-application + - cozystack.seaweedfs-application + - cozystack.info-application + - cozystack.monitoring-application + - cozystack.etcd-application + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: tenant + path: apps/tenant + libraries: [cozy-lib] + - name: tenant-rd + path: system/tenant-rd + install: + namespace: cozy-system + releaseName: tenant-rd diff --git a/packages/core/platform/sources/velero.yaml b/packages/core/platform/sources/velero.yaml new file mode 100644 index 00000000..2374e847 --- /dev/null +++ b/packages/core/platform/sources/velero.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.velero +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.monitoring-agents + components: + - name: velero + path: system/velero + install: + privileged: true + namespace: cozy-velero + releaseName: velero diff --git a/packages/core/platform/sources/vertical-pod-autoscaler.yaml b/packages/core/platform/sources/vertical-pod-autoscaler.yaml new file mode 100644 index 00000000..a4d827cc --- /dev/null +++ b/packages/core/platform/sources/vertical-pod-autoscaler.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.vertical-pod-autoscaler +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + components: + - name: vertical-pod-autoscaler-crds + path: system/vertical-pod-autoscaler-crds + install: + privileged: true + namespace: cozy-vertical-pod-autoscaler + releaseName: vertical-pod-autoscaler-crds + - name: vpa-for-vpa + path: system/vertical-pod-autoscaler + - name: vertical-pod-autoscaler + path: system/vertical-pod-autoscaler + install: + privileged: true + namespace: cozy-vertical-pod-autoscaler + releaseName: vertical-pod-autoscaler + dependsOn: + - vertical-pod-autoscaler-crds diff --git a/packages/core/platform/sources/victoria-metrics-operator.yaml b/packages/core/platform/sources/victoria-metrics-operator.yaml new file mode 100644 index 00000000..a5b47683 --- /dev/null +++ b/packages/core/platform/sources/victoria-metrics-operator.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.victoria-metrics-operator +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.cert-manager + components: + - name: victoria-metrics-operator + path: system/victoria-metrics-operator + install: + namespace: cozy-victoria-metrics-operator + releaseName: victoria-metrics-operator diff --git a/packages/core/platform/sources/virtualprivatecloud-application.yaml b/packages/core/platform/sources/virtualprivatecloud-application.yaml new file mode 100644 index 00000000..b6a8519b --- /dev/null +++ b/packages/core/platform/sources/virtualprivatecloud-application.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.virtualprivatecloud-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: kubevirt + dependsOn: + - cozystack.networking + - cozystack.multus + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: virtualprivatecloud + path: apps/vpc + libraries: [cozy-lib] + - name: virtualprivatecloud-rd + path: system/virtualprivatecloud-rd + install: + namespace: cozy-system + releaseName: virtualprivatecloud-rd diff --git a/packages/core/platform/sources/vm-default-images.yaml b/packages/core/platform/sources/vm-default-images.yaml new file mode 100644 index 00000000..16cd6a94 --- /dev/null +++ b/packages/core/platform/sources/vm-default-images.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.vm-default-images +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + - cozystack.kubevirt-cdi + components: + - name: vm-default-images + path: system/vm-default-images + install: + namespace: cozy-system + releaseName: vm-default-images diff --git a/packages/core/platform/sources/vm-disk-application.yaml b/packages/core/platform/sources/vm-disk-application.yaml new file mode 100644 index 00000000..a4e98ca9 --- /dev/null +++ b/packages/core/platform/sources/vm-disk-application.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.vm-disk-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: kubevirt + dependsOn: + - cozystack.networking + - cozystack.kubevirt-cdi + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: vm-disk + path: apps/vm-disk + libraries: ["cozy-lib"] + - name: vm-disk-rd + path: system/vm-disk-rd + install: + namespace: cozy-system + releaseName: vm-disk-rd diff --git a/packages/core/platform/sources/vm-instance-application.yaml b/packages/core/platform/sources/vm-instance-application.yaml new file mode 100644 index 00000000..eaa0c76e --- /dev/null +++ b/packages/core/platform/sources/vm-instance-application.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.vm-instance-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: kubevirt + dependsOn: + - cozystack.networking + - cozystack.kubevirt + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: vm-instance + path: apps/vm-instance + libraries: ["cozy-lib"] + - name: vm-instance-rd + path: system/vm-instance-rd + install: + namespace: cozy-system + releaseName: vm-instance-rd diff --git a/packages/core/platform/sources/vpn-application.yaml b/packages/core/platform/sources/vpn-application.yaml new file mode 100644 index 00000000..0200108f --- /dev/null +++ b/packages/core/platform/sources/vpn-application.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: cozystack.io/v1alpha1 +kind: PackageSource +metadata: + name: cozystack.vpn-application +spec: + sourceRef: + kind: OCIRepository + name: cozystack-packages + namespace: cozy-system + path: / + variants: + - name: default + dependsOn: + - cozystack.networking + libraries: + - name: cozy-lib + path: library/cozy-lib + components: + - name: vpn + path: apps/vpn + libraries: ["cozy-lib"] + - name: vpn-rd + path: system/vpn-rd + install: + namespace: cozy-system + releaseName: vpn-rd diff --git a/packages/core/platform/templates/_helpers.tpl b/packages/core/platform/templates/_helpers.tpl index 73a4574c..4bc02429 100644 --- a/packages/core/platform/templates/_helpers.tpl +++ b/packages/core/platform/templates/_helpers.tpl @@ -1,78 +1,72 @@ -{{/* -Get IP-addresses of master nodes -*/}} -{{- define "cozystack.master-node-ips" -}} -{{- $nodes := lookup "v1" "Node" "" "" -}} -{{- $ips := list -}} -{{- range $node := $nodes.items -}} - {{- if eq (index $node.metadata.labels "node-role.kubernetes.io/control-plane") "" -}} - {{- range $address := $node.status.addresses -}} - {{- if eq $address.type "InternalIP" -}} - {{- $ips = append $ips $address.address -}} - {{- break -}} - {{- end -}} - {{- end -}} - {{- end -}} -{{- end -}} -{{ join "," $ips }} +{{- define "cozystack.platform.package" -}} +{{- $name := index . 0 -}} +{{- $variant := default "default" (index . 1) -}} +{{- $root := default $ (index . 2) -}} +{{- $components := dict -}} +{{- if gt (len .) 3 -}} +{{- $components = index . 3 -}} {{- end -}} +{{- $disabled := default (list) $root.Values.bundles.disabledPackages -}} +{{- if not (has $name $disabled) -}} +--- +apiVersion: cozystack.io/v1alpha1 +kind: Package +metadata: + name: {{ $name }} + annotations: + helm.sh/resource-policy: keep +spec: + variant: {{ $variant }} +{{- if $components }} + components: +{{ toYaml $components | indent 4 }} +{{- end }} +{{- end }} +{{ 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 }} +{{- define "cozystack.platform.package.default" -}} +{{- $name := index . 0 -}} +{{- $root := index . 1 -}} +{{- include "cozystack.platform.package" (list $name "default" $root) }} +{{ end }} + +{{- define "cozystack.platform.package.optional" -}} +{{- $name := index . 0 -}} +{{- $variant := default "default" (index . 1) -}} +{{- $root := default $ (index . 2) -}} +{{- $disabled := default (list) $root.Values.bundles.disabledPackages -}} +{{- $enabled := default (list) $root.Values.bundles.enabledPackages -}} +{{- if and (has $name $enabled) (not (has $name $disabled)) -}} +--- +apiVersion: cozystack.io/v1alpha1 +kind: Package +metadata: + name: {{ $name }} + annotations: + helm.sh/resource-policy: keep +spec: + variant: {{ $variant }} {{- 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%; - } - .header-version { - display: none; - } - .label.label-info-secondary { - display: none; - } +{{ end }} + +{{- define "cozystack.platform.package.optional.default" -}} +{{- $name := index . 0 -}} +{{- $root := index . 1 -}} +{{- include "cozystack.platform.package.optional" (list $name "default" $root) }} +{{ end }} + +{{/* +Common system packages shared between isp-full and isp-full-generic bundles. +Does NOT include: networking (variant differs), linstor (talos.enabled differs) +*/}} +{{- define "cozystack.platform.system.common-packages" -}} +{{- $root := . -}} +{{include "cozystack.platform.package.default" (list "cozystack.kubeovn-webhook" $root) }} +{{include "cozystack.platform.package.default" (list "cozystack.kubeovn-plunger" $root) }} +{{include "cozystack.platform.package.default" (list "cozystack.cozy-proxy" $root) }} +{{include "cozystack.platform.package.default" (list "cozystack.multus" $root) }} +{{include "cozystack.platform.package.default" (list "cozystack.metallb" $root) }} +{{include "cozystack.platform.package.default" (list "cozystack.reloader" $root) }} +{{include "cozystack.platform.package.default" (list "cozystack.linstor-scheduler" $root) }} +{{include "cozystack.platform.package.default" (list "cozystack.snapshot-controller" $root) }} {{- end }} diff --git a/packages/core/platform/templates/apps.yaml b/packages/core/platform/templates/apps.yaml index a24744b8..6e1ae25a 100644 --- a/packages/core/platform/templates/apps.yaml +++ b/packages/core/platform/templates/apps.yaml @@ -1,63 +1,49 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $bundleName := index $cozyConfig.data "bundle-name" }} +{{- $kubeRootCa := lookup "v1" "ConfigMap" "kube-system" "kube-root-ca.crt" }} +{{- $cozystackCm := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} +{{- $bundleName := .Values.bundles.system.variant }} {{- $bundle := tpl (.Files.Get (printf "bundles/%s.yaml" $bundleName)) . | fromYaml }} -{{- $host := "example.org" }} -{{- $host := "example.org" }} -{{- if $cozyConfig.data }} - {{- if hasKey $cozyConfig.data "root-host" }} - {{- $host = index $cozyConfig.data "root-host" }} - {{- end }} -{{- end }} -{{- $tenantRoot := dict }} -{{- if .Capabilities.APIVersions.Has "helm.toolkit.fluxcd.io/v2" }} -{{- $tenantRoot = lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" "tenant-root" "tenant-root" }} -{{- end }} -{{- if and $tenantRoot $tenantRoot.spec $tenantRoot.spec.values $tenantRoot.spec.values.host }} -{{- $host = $tenantRoot.spec.values.host }} -{{- else }} -{{- end }} +{{- /* Read root-host from ConfigMap if available, else use chart values */ -}} +{{- $rootHost := .Values.publishing.host -}} +{{- if and $cozystackCm $cozystackCm.data -}} +{{- $rootHost = default $rootHost (index $cozystackCm.data "root-host") -}} +{{- end -}} --- apiVersion: v1 -kind: Namespace +kind: Secret metadata: - annotations: - helm.sh/resource-policy: keep - namespace.cozystack.io/etcd: tenant-root - namespace.cozystack.io/monitoring: tenant-root - namespace.cozystack.io/ingress: tenant-root - namespace.cozystack.io/seaweedfs: tenant-root - namespace.cozystack.io/host: "{{ $host }}" - name: tenant-root ---- -apiVersion: helm.toolkit.fluxcd.io/v2 -kind: HelmRelease -metadata: - name: tenant-root - namespace: tenant-root + name: cozystack-values + namespace: cozy-system labels: - cozystack.io/ui: "true" -spec: - interval: 0s - releaseName: tenant-root - install: - remediation: - retries: -1 - upgrade: - remediation: - retries: -1 - chart: - spec: - chart: tenant - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - values: - host: "{{ $host }}" - dependsOn: - {{- range $x := $bundle.releases }} - {{- if has $x.name (list "cilium" "kubeovn") }} - - name: {{ $x.name }} - namespace: {{ $x.namespace }} - {{- end }} - {{- end }} + reconcile.fluxcd.io/watch: Enabled +type: Opaque +stringData: + values.yaml: | + _cluster: + root-host: {{ $rootHost | quote }} + bundle-name: {{ .Values.bundles.system.variant | quote }} + solver: {{ .Values.publishing.certificates.solver | quote }} + issuer-name: {{ .Values.publishing.certificates.issuerName | quote }} + oidc-enabled: {{ .Values.authentication.oidc.enabled | quote }} + oidc-insecure-skip-verify: {{ .Values.authentication.oidc.insecureSkipVerify | quote }} + extra-keycloak-redirect-uri-for-dashboard: {{ index .Values.authentication.oidc.keycloakExtraRedirectUri | quote }} + keycloak-internal-url: {{ .Values.authentication.oidc.keycloakInternalUrl | quote }} + expose-services: {{ .Values.publishing.exposedServices | join "," | quote }} + expose-ingress: {{ .Values.publishing.ingressName | quote }} + expose-external-ips: {{ .Values.publishing.externalIPs | join "," | quote }} + expose-mode: {{ .Values.publishing.exposure | default "externalIPs" | quote }} + cluster-domain: {{ .Values.networking.clusterDomain | quote }} + api-server-endpoint: {{ .Values.publishing.apiServerEndpoint | quote }} + {{- with .Values.branding }} + branding: + {{- . | toYaml | nindent 8 }} + {{- end }} + cpu-allocation-ratio: {{ .Values.resources.cpuAllocationRatio | quote }} + memory-allocation-ratio: {{ .Values.resources.memoryAllocationRatio | quote }} + ephemeral-storage-allocation-ratio: {{ .Values.resources.ephemeralStorageAllocationRatio | quote }} + {{- with .Values.scheduling }} + scheduling: + {{- . | toYaml | nindent 8 }} + {{- end }} + {{- with $kubeRootCa.data }} + kube-root-ca: {{ index . "ca.crt" | b64enc | quote }} + {{- end }} diff --git a/packages/core/platform/templates/bundles/iaas.yaml b/packages/core/platform/templates/bundles/iaas.yaml new file mode 100644 index 00000000..66ec98b2 --- /dev/null +++ b/packages/core/platform/templates/bundles/iaas.yaml @@ -0,0 +1,25 @@ +{{- if and .Values.bundles.iaas.enabled (not (or (eq .Values.bundles.system.variant "isp-full") (eq .Values.bundles.system.variant "isp-full-generic"))) }} +{{- fail "bundles.iaas.enabled can only be true when bundles.system.variant is 'isp-full' or 'isp-full-generic'" }} +{{- end }} +{{- if and .Values.bundles.iaas.enabled (or (eq .Values.bundles.system.variant "isp-full") (eq .Values.bundles.system.variant "isp-full-generic")) }} +{{- $kubevirtComponents := dict -}} +{{- if .Values.resources.cpuAllocationRatio -}} +{{- $_ := set $kubevirtComponents "kubevirt" (dict "values" (dict "cpuAllocationRatio" (.Values.resources.cpuAllocationRatio | int))) -}} +{{- end -}} +{{include "cozystack.platform.package" (list "cozystack.kubevirt" "default" $ $kubevirtComponents) }} +{{include "cozystack.platform.package.default" (list "cozystack.kubevirt-cdi" $) }} +{{include "cozystack.platform.package.optional.default" (list "cozystack.vm-default-images" $) }} +{{include "cozystack.platform.package.optional.default" (list "cozystack.gpu-operator" $) }} +{{include "cozystack.platform.package.optional.default" (list "cozystack.hami" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.kamaji" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.capi-operator" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.capi-provider-bootstrap-kubeadm" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.capi-provider-core" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.capi-provider-cp-kamaji" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.capi-provider-infra-kubevirt" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.bucket-application" $) }} +{{include "cozystack.platform.package" (list "cozystack.kubernetes-application" "kubevirt" $) }} +{{include "cozystack.platform.package" (list "cozystack.virtualprivatecloud-application" "kubevirt" $) }} +{{include "cozystack.platform.package" (list "cozystack.vm-disk-application" "kubevirt" $) }} +{{include "cozystack.platform.package" (list "cozystack.vm-instance-application" "kubevirt" $) }} +{{- end }} diff --git a/packages/core/platform/templates/bundles/naas.yaml b/packages/core/platform/templates/bundles/naas.yaml new file mode 100644 index 00000000..9682d447 --- /dev/null +++ b/packages/core/platform/templates/bundles/naas.yaml @@ -0,0 +1,8 @@ +{{- if and .Values.bundles.naas.enabled (not (or (eq .Values.bundles.system.variant "isp-full") (eq .Values.bundles.system.variant "isp-full-generic") (eq .Values.bundles.system.variant "isp-hosted"))) }} +{{- fail "bundles.naas.enabled can only be true when bundles.system.variant is 'isp-full', 'isp-full-generic', or 'isp-hosted'" }} +{{- end }} +{{- if and .Values.bundles.naas.enabled (or (eq .Values.bundles.system.variant "isp-full") (eq .Values.bundles.system.variant "isp-full-generic") (eq .Values.bundles.system.variant "isp-hosted")) }} +{{include "cozystack.platform.package.default" (list "cozystack.http-cache-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.tcp-balancer-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.vpn-application" $) }} +{{- end }} diff --git a/packages/core/platform/templates/bundles/paas.yaml b/packages/core/platform/templates/bundles/paas.yaml new file mode 100644 index 00000000..54854368 --- /dev/null +++ b/packages/core/platform/templates/bundles/paas.yaml @@ -0,0 +1,24 @@ +{{- if and .Values.bundles.paas.enabled (not (or (eq .Values.bundles.system.variant "isp-full") (eq .Values.bundles.system.variant "isp-full-generic") (eq .Values.bundles.system.variant "isp-hosted"))) }} +{{- fail "bundles.paas.enabled can only be true when bundles.system.variant is 'isp-full', 'isp-full-generic', or 'isp-hosted'" }} +{{- end }} +{{- if and .Values.bundles.paas.enabled (or (eq .Values.bundles.system.variant "isp-full") (eq .Values.bundles.system.variant "isp-full-generic") (eq .Values.bundles.system.variant "isp-hosted")) }} +{{include "cozystack.platform.package.default" (list "cozystack.mariadb-operator" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.kafka-operator" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.clickhouse-operator" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.foundationdb-operator" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.rabbitmq-operator" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.redis-operator" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.mongodb-operator" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.clickhouse-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.foundationdb-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.harbor-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.kafka-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.mariadb-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.mongodb-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.nats-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.openbao-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.postgres-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.qdrant-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.rabbitmq-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.redis-application" $) }} +{{- end }} diff --git a/packages/core/platform/templates/bundles/system.yaml b/packages/core/platform/templates/bundles/system.yaml new file mode 100644 index 00000000..6c587c82 --- /dev/null +++ b/packages/core/platform/templates/bundles/system.yaml @@ -0,0 +1,158 @@ +{{- if .Values.bundles.system.enabled }} + +# Networking +{{- if eq .Values.bundles.system.variant "isp-full" }} +{{- $networkingComponents := dict -}} +{{- if .Values.networking -}} +{{- $kubeovnIpv4 := dict + "POD_CIDR" .Values.networking.podCIDR + "POD_GATEWAY" .Values.networking.podGateway + "SVC_CIDR" .Values.networking.serviceCIDR + "JOIN_CIDR" .Values.networking.joinCIDR -}} +{{- $kubeovnDict := dict "ipv4" $kubeovnIpv4 -}} +{{- if .Values.networking.kubeovn.MASTER_NODES -}} +{{- $_ := set $kubeovnDict "MASTER_NODES" .Values.networking.kubeovn.MASTER_NODES -}} +{{- end -}} +{{- $kubeovnValues := dict "kube-ovn" $kubeovnDict -}} +{{- $_ := set $networkingComponents "kubeovn" (dict "values" $kubeovnValues) -}} +{{- /* For Talos (isp-full): use KubePrism endpoint and disable cgroup autoMount */ -}} +{{- $ciliumValues := dict "cilium" (dict + "k8sServiceHost" "localhost" + "k8sServicePort" "7445" + "cgroup" (dict "autoMount" (dict "enabled" false))) -}} +{{- $_ := set $networkingComponents "cilium" (dict "values" $ciliumValues) -}} +{{- end -}} +{{include "cozystack.platform.package" (list "cozystack.networking" "kubeovn-cilium" $ $networkingComponents) }} +{{include "cozystack.platform.system.common-packages" $ }} +{{include "cozystack.platform.package.default" (list "cozystack.linstor" $) }} +{{include "cozystack.platform.package" (list "cozystack.cozystack-scheduler" "linstor" $) }} +{{- end }} + +{{- if eq .Values.bundles.system.variant "isp-hosted" }} +{{include "cozystack.platform.package" (list "cozystack.networking" "noop" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.cozystack-scheduler" $) }} +{{- end }} + +{{- if eq .Values.bundles.system.variant "isp-full-generic" }} +{{- $networkingComponents := dict -}} +{{- if .Values.networking -}} +{{- /* Parse apiServerEndpoint URL for generic k8s (used by both Cilium and KubeOVN) */ -}} +{{- /* First try cozystack ConfigMap, then fall back to chart values */ -}} +{{- $cozystackCm := lookup "v1" "ConfigMap" "cozy-system" "cozystack" -}} +{{- $apiServerEndpoint := .Values.publishing.apiServerEndpoint -}} +{{- if and $cozystackCm $cozystackCm.data -}} +{{- $apiServerEndpoint = default $apiServerEndpoint (index $cozystackCm.data "api-server-endpoint") -}} +{{- end -}} +{{- $apiHost := "" -}} +{{- $apiPort := "6443" -}} +{{- if $apiServerEndpoint -}} +{{- $parsed := urlParse $apiServerEndpoint -}} +{{- $hostPort := splitList ":" $parsed.host -}} +{{- $apiHost = index $hostPort 0 -}} +{{- if gt (len $hostPort) 1 -}} +{{- $apiPort = index $hostPort 1 -}} +{{- else -}} +{{- $apiPort = "6443" -}} +{{- end -}} +{{- end -}} +{{- /* KubeOVN IPv4 configuration - read from ConfigMap or fall back to chart values */ -}} +{{- $podCIDR := .Values.networking.podCIDR -}} +{{- $podGateway := .Values.networking.podGateway -}} +{{- $svcCIDR := .Values.networking.serviceCIDR -}} +{{- $joinCIDR := .Values.networking.joinCIDR -}} +{{- if and $cozystackCm $cozystackCm.data -}} +{{- $podCIDR = default $podCIDR (index $cozystackCm.data "ipv4-pod-cidr") -}} +{{- $podGateway = default $podGateway (index $cozystackCm.data "ipv4-pod-gateway") -}} +{{- $svcCIDR = default $svcCIDR (index $cozystackCm.data "ipv4-svc-cidr") -}} +{{- $joinCIDR = default $joinCIDR (index $cozystackCm.data "ipv4-join-cidr") -}} +{{- end -}} +{{- $kubeovnIpv4 := dict + "POD_CIDR" $podCIDR + "POD_GATEWAY" $podGateway + "SVC_CIDR" $svcCIDR + "JOIN_CIDR" $joinCIDR -}} +{{- $kubeovnDict := dict "ipv4" $kubeovnIpv4 -}} +{{- /* Set MASTER_NODES: explicit value or empty (let kube-ovn discover nodes by label) */ -}} +{{- $masterNodes := .Values.networking.kubeovn.MASTER_NODES -}} +{{- if $masterNodes -}} +{{- $_ := set $kubeovnDict "MASTER_NODES" $masterNodes -}} +{{- end -}} +{{- /* For generic k8s (k3s), control-plane label has value "true" */ -}} +{{- $_ := set $kubeovnDict "MASTER_NODES_LABEL" "node-role.kubernetes.io/control-plane=true" -}} +{{- $kubeovnValues := dict "kube-ovn" $kubeovnDict -}} +{{- $_ := set $networkingComponents "kubeovn" (dict "values" $kubeovnValues) -}} +{{- /* Cilium configuration - for generic k8s, always enable cgroup autoMount */ -}} +{{- $ciliumValues := dict "cilium" (dict + "k8sServiceHost" $apiHost + "k8sServicePort" $apiPort + "cgroup" (dict "autoMount" (dict "enabled" true))) -}} +{{- $_ := set $networkingComponents "cilium" (dict "values" $ciliumValues) -}} +{{- end -}} +{{- /* Use kubeovn-cilium-generic variant (no values-talos.yaml) */ -}} +{{include "cozystack.platform.package" (list "cozystack.networking" "kubeovn-cilium-generic" $ $networkingComponents) }} +{{include "cozystack.platform.system.common-packages" $ }} +{{- /* Pass talos.enabled: false to linstor for generic Linux */ -}} +{{- $linstorComponents := dict "linstor" (dict "values" (dict "talos" (dict "enabled" false))) -}} +{{include "cozystack.platform.package" (list "cozystack.linstor" "default" $ $linstorComponents) }} +{{include "cozystack.platform.package" (list "cozystack.cozystack-scheduler" "linstor" $) }} +{{- end }} + +# Cozystack Engine +{{- $cozystackEngineComponents := dict -}} +{{- /* For generic k8s, DaemonSets with control-plane nodeSelector need value "true" */ -}} +{{- if eq .Values.bundles.system.variant "isp-full-generic" -}} +{{- $genericNodeSelector := dict "node-role.kubernetes.io/control-plane" "true" -}} +{{- /* cozystack-api DaemonSet */ -}} +{{- $apiValues := dict "cozystackAPI" (dict "nodeSelector" $genericNodeSelector) -}} +{{- $_ := set $cozystackEngineComponents "cozystack-api" (dict "values" $apiValues) -}} +{{- end -}} +{{- if .Values.authentication.oidc.enabled }} +{{include "cozystack.platform.package" (list "cozystack.cozystack-engine" "oidc" $ $cozystackEngineComponents) }} +{{include "cozystack.platform.package.default" (list "cozystack.keycloak" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.keycloak-operator" $) }} +{{- else }} +{{include "cozystack.platform.package" (list "cozystack.cozystack-engine" "default" $ $cozystackEngineComponents) }} +{{- end }} + +# Common Packages +{{include "cozystack.platform.package.default" (list "cozystack.cert-manager" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.flux-plunger" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.victoria-metrics-operator" $) }} +{{- $tenantComponents := dict -}} +{{- $tenantClusterValues := dict "_cluster" (dict "oidc-enabled" (ternary "true" "false" .Values.authentication.oidc.enabled)) -}} +{{- $_ := set $tenantComponents "tenant" (dict "values" $tenantClusterValues) }} +{{include "cozystack.platform.package" (list "cozystack.tenant-application" "default" $ $tenantComponents) }} +{{include "cozystack.platform.package.default" (list "cozystack.ingress-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.seaweedfs-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.info-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.monitoring-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.etcd-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.cozystack-basics" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.backupstrategy-controller" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.backup-controller" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.vertical-pod-autoscaler" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.metrics-server" $) }} +{{- $monitoringAgentsComponents := dict "monitoring-agents" (dict "values" (dict "global" (dict "target" "tenant-root"))) -}} +{{include "cozystack.platform.package" (list "cozystack.monitoring-agents" "default" $ $monitoringAgentsComponents) }} +{{include "cozystack.platform.package.default" (list "cozystack.goldpinger" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.prometheus-operator-crds" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.grafana-operator" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.etcd-operator" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.postgres-operator" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.objectstorage-controller" $) }} + +# Optional System Packages (controlled via bundles.enabledPackages) +{{include "cozystack.platform.package.optional.default" (list "cozystack.nfs-driver" $) }} +{{include "cozystack.platform.package.optional.default" (list "cozystack.telepresence" $) }} +{{include "cozystack.platform.package.optional.default" (list "cozystack.external-dns" $) }} +{{include "cozystack.platform.package.optional.default" (list "cozystack.external-dns-application" $) }} +{{include "cozystack.platform.package.optional.default" (list "cozystack.external-secrets-operator" $) }} +{{include "cozystack.platform.package.optional.default" (list "cozystack.velero" $) }} +{{include "cozystack.platform.package.optional.default" (list "cozystack.linstor-gui" $) }} +{{- if has "cozystack.bootbox" (default (list) .Values.bundles.enabledPackages) }} +{{include "cozystack.platform.package.default" (list "cozystack.bootbox-application" $) }} +{{include "cozystack.platform.package.default" (list "cozystack.bootbox" $) }} +{{- end }} +{{include "cozystack.platform.package.optional.default" (list "cozystack.hetzner-robotlb" $) }} + +{{- end }} diff --git a/packages/core/platform/templates/containerd-registry-secret.yaml b/packages/core/platform/templates/containerd-registry-secret.yaml new file mode 100644 index 00000000..6e9fb640 --- /dev/null +++ b/packages/core/platform/templates/containerd-registry-secret.yaml @@ -0,0 +1,35 @@ +{{- if .Values.registries.mirrors }} +apiVersion: v1 +kind: Secret +metadata: + name: patch-containerd + namespace: cozy-system +type: Opaque +stringData: +{{- range $registry, $mirror := .Values.registries.mirrors }} +{{- if $mirror.endpoints }} + {{ $registry }}.toml: | + server = "https://{{ $registry }}" +{{- range $endpoint := $mirror.endpoints }} + [host."{{ $endpoint }}"] + capabilities = ["pull", "resolve"] +{{- $endpointConfig := index $.Values.registries.config $endpoint }} +{{- if $endpointConfig }} +{{- if $endpointConfig.tls }} +{{- if $endpointConfig.tls.insecureSkipVerify }} + skip_verify = true +{{- end }} +{{- end }} +{{- if $endpointConfig.auth }} + [host."{{ $endpoint }}".auth] + username = "{{ $endpointConfig.auth.username }}" + password = "{{ $endpointConfig.auth.password }}" +{{- end }} +{{- else }} + skip_verify = true +{{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + diff --git a/packages/core/platform/templates/cozystack-version.yaml b/packages/core/platform/templates/cozystack-version.yaml new file mode 100644 index 00000000..09b845c2 --- /dev/null +++ b/packages/core/platform/templates/cozystack-version.yaml @@ -0,0 +1,13 @@ +{{- $configMap := lookup "v1" "ConfigMap" .Release.Namespace "cozystack-version" }} +{{- if not $configMap }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cozystack-version + namespace: {{ .Release.Namespace }} + annotations: + helm.sh/resource-policy: keep +data: + version: {{ .Values.migrations.targetVersion | quote }} +{{- end }} diff --git a/packages/core/platform/templates/helmreleases.yaml b/packages/core/platform/templates/helmreleases.yaml deleted file mode 100644 index 17b373be..00000000 --- a/packages/core/platform/templates/helmreleases.yaml +++ /dev/null @@ -1,85 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $bundleName := index $cozyConfig.data "bundle-name" }} -{{- $bundle := tpl (.Files.Get (printf "bundles/%s.yaml" $bundleName)) . | fromYaml }} -{{- $dependencyNamespaces := dict }} -{{- $disabledComponents := splitList "," ((index $cozyConfig.data "bundle-disable") | default "") }} -{{- $enabledComponents := splitList "," ((index $cozyConfig.data "bundle-enable") | default "") }} - -{{/* collect dependency namespaces from releases */}} -{{- range $x := $bundle.releases }} -{{- $_ := set $dependencyNamespaces $x.name $x.namespace }} -{{- end }} - -{{- range $x := $bundle.releases }} - -{{- $shouldInstall := true }} -{{- $shouldDelete := false }} -{{- if or (has $x.name $disabledComponents) (and ($x.optional) (not (has $x.name $enabledComponents))) }} -{{- $shouldInstall = false }} -{{- if $.Capabilities.APIVersions.Has "helm.toolkit.fluxcd.io/v2" }} -{{- if lookup "helm.toolkit.fluxcd.io/v2" "HelmRelease" $x.namespace $x.name }} -{{- $shouldDelete = true }} -{{- end }} -{{- end }} -{{- end }} - -{{- if or $shouldInstall $shouldDelete }} ---- -apiVersion: helm.toolkit.fluxcd.io/v2 -kind: HelmRelease -metadata: - name: {{ $x.name }} - namespace: {{ $x.namespace }} - labels: - cozystack.io/repository: system - cozystack.io/system-app: "true" - {{- if $shouldDelete }} - cozystack.io/marked-for-deletion: "true" - {{- end }} -spec: - interval: 5m - releaseName: {{ $x.releaseName | default $x.name }} - install: - crds: CreateReplace - remediation: - retries: -1 - upgrade: - crds: CreateReplace - remediation: - retries: -1 - chart: - spec: - chart: {{ $x.chart }} - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' - {{- with $x.valuesFiles }} - valuesFiles: - {{- toYaml $x.valuesFiles | nindent 6 }} - {{- end }} - {{- $values := dict }} - {{- with $x.values }} - {{- $values = merge . $values }} - {{- end }} - {{- with index $cozyConfig.data (printf "values-%s" $x.name) }} - {{- $values = merge (fromYaml .) $values }} - {{- end }} - {{- with $values }} - values: - {{- toYaml . | nindent 4}} - {{- end }} - - {{- with $x.dependsOn }} - dependsOn: - {{- range $dep := . }} - {{- if not (has $dep $disabledComponents) }} - - name: {{ $dep }} - namespace: {{ index $dependencyNamespaces $dep }} - {{- end }} - {{- end }} - {{- end }} -{{- end }} -{{- end }} diff --git a/packages/core/platform/templates/helmrepos.yaml b/packages/core/platform/templates/helmrepos.yaml deleted file mode 100644 index 69f77534..00000000 --- a/packages/core/platform/templates/helmrepos.yaml +++ /dev/null @@ -1,34 +0,0 @@ ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: HelmRepository -metadata: - name: cozystack-system - namespace: cozy-system - labels: - cozystack.io/repository: system -spec: - interval: 5m0s - url: http://cozystack.cozy-system.svc/repos/system ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: HelmRepository -metadata: - name: cozystack-apps - namespace: cozy-public - labels: - cozystack.io/ui: "true" - cozystack.io/repository: apps -spec: - interval: 5m0s - url: http://cozystack.cozy-system.svc/repos/apps ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: HelmRepository -metadata: - name: cozystack-extra - namespace: cozy-public - labels: - cozystack.io/repository: extra -spec: - interval: 5m0s - url: http://cozystack.cozy-system.svc/repos/extra diff --git a/packages/core/platform/templates/migration-hook.yaml b/packages/core/platform/templates/migration-hook.yaml new file mode 100644 index 00000000..67b09820 --- /dev/null +++ b/packages/core/platform/templates/migration-hook.yaml @@ -0,0 +1,69 @@ +{{- if .Values.migrations.enabled }} +{{- $shouldRunMigrationHook := false }} +{{- $currentVersion := 0 }} +{{- $targetVersion := .Values.migrations.targetVersion | int }} +{{- $configMap := lookup "v1" "ConfigMap" .Release.Namespace "cozystack-version" }} +{{- if $configMap }} + {{- $currentVersion = dig "data" "version" "0" $configMap | int }} + {{- if lt $currentVersion $targetVersion }} + {{- $shouldRunMigrationHook = true }} + {{- end }} +{{- end }} + +{{- if $shouldRunMigrationHook }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: cozystack-migration-hook + annotations: + helm.sh/hook: pre-upgrade,pre-install + helm.sh/hook-weight: "1" + helm.sh/hook-delete-policy: before-hook-creation +spec: + backoffLimit: 3 + template: + metadata: + labels: + policy.cozystack.io/allow-to-apiserver: "true" + spec: + serviceAccountName: cozystack-migration-hook + containers: + - name: migration + image: {{ .Values.migrations.image }} + env: + - name: NAMESPACE + value: {{ .Release.Namespace | quote }} + - name: CURRENT_VERSION + value: {{ $currentVersion | quote }} + - name: TARGET_VERSION + value: {{ $targetVersion | quote }} + restartPolicy: Never +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + annotations: + helm.sh/hook: pre-upgrade,pre-install + helm.sh/hook-weight: "1" + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation + name: cozystack-migration-hook +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + name: cozystack-migration-hook + namespace: {{ .Release.Namespace | quote }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: cozystack-migration-hook + annotations: + helm.sh/hook: pre-upgrade,pre-install + helm.sh/hook-weight: "1" + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation +{{- end }} +{{- end }} diff --git a/packages/core/platform/templates/namespaces.yaml b/packages/core/platform/templates/namespaces.yaml deleted file mode 100644 index 11d00553..00000000 --- a/packages/core/platform/templates/namespaces.yaml +++ /dev/null @@ -1,40 +0,0 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $bundleName := index $cozyConfig.data "bundle-name" }} -{{- $bundle := tpl (.Files.Get (printf "bundles/%s.yaml" $bundleName)) . | fromYaml }} -{{- $disabledComponents := splitList "," ((index $cozyConfig.data "bundle-disable") | default "") }} -{{- $enabledComponents := splitList "," ((index $cozyConfig.data "bundle-enable") | default "") }} -{{- $namespaces := dict }} - -{{/* collect namespaces from releases */}} -{{- range $x := $bundle.releases }} - {{- if not (hasKey $namespaces $x.namespace) }} - {{- if not (has $x.name $disabledComponents) }} - {{- if or (not $x.optional) (and ($x.optional) (has $x.name $enabledComponents)) }} - {{- $_ := set $namespaces $x.namespace false }} - {{- end }} - {{- end }} - {{- end }} - {{/* if at least one release requires a privileged namespace, then it should be privileged */}} - {{- if or $x.privileged (index $namespaces $x.namespace) }} - {{- $_ := set $namespaces $x.namespace true }} - {{- end }} -{{- end }} - -{{/* Add extra namespaces */}} -{{- $_ := set $namespaces "cozy-system" true }} -{{- $_ := set $namespaces "cozy-public" false }} - -{{- range $namespace, $privileged := $namespaces }} ---- -apiVersion: v1 -kind: Namespace -metadata: - annotations: - "helm.sh/resource-policy": keep - labels: - cozystack.io/system: "true" - {{- if $privileged }} - pod-security.kubernetes.io/enforce: privileged - {{- end }} - name: {{ $namespace }} -{{- end }} diff --git a/packages/core/platform/templates/repository.yaml b/packages/core/platform/templates/repository.yaml new file mode 100644 index 00000000..9bd9f5a1 --- /dev/null +++ b/packages/core/platform/templates/repository.yaml @@ -0,0 +1,17 @@ +{{- $sourceRef := .Values.sourceRef }} +{{- $apiVersion := "source.toolkit.fluxcd.io/v1" }} +{{- $kind := $sourceRef.kind }} +{{- $name := $sourceRef.name }} +{{- $namespace := $sourceRef.namespace }} +{{- $sourceRepo := lookup $apiVersion $kind $namespace $name }} +{{- if not $sourceRepo }} +{{- fail (printf "Source repository %s/%s of kind %s not found in namespace %s" $namespace $name $kind $namespace) }} +{{- end }} +--- +apiVersion: {{ $apiVersion }} +kind: {{ $kind }} +metadata: + name: cozystack-packages + namespace: cozy-system +spec: +{{- $sourceRepo.spec | toYaml | nindent 2 }} diff --git a/packages/core/platform/templates/scheduling.yaml b/packages/core/platform/templates/scheduling.yaml new file mode 100644 index 00000000..4486155a --- /dev/null +++ b/packages/core/platform/templates/scheduling.yaml @@ -0,0 +1,11 @@ +{{- if .Values.scheduling.globalAppTopologySpreadConstraints }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cozystack-scheduling + namespace: cozy-system +data: + globalAppTopologySpreadConstraints: | + {{- toYaml .Values.scheduling.globalAppTopologySpreadConstraints | nindent 4 }} +{{- end }} diff --git a/packages/core/platform/templates/sources.yaml b/packages/core/platform/templates/sources.yaml new file mode 100644 index 00000000..9d4eca37 --- /dev/null +++ b/packages/core/platform/templates/sources.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "sources/*.yaml" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/core/platform/values-isp-full-generic.yaml b/packages/core/platform/values-isp-full-generic.yaml new file mode 100644 index 00000000..4fd5ff59 --- /dev/null +++ b/packages/core/platform/values-isp-full-generic.yaml @@ -0,0 +1,15 @@ +migrations: + enabled: true +bundles: + system: + enabled: true + variant: "isp-full-generic" + iaas: + enabled: true + paas: + enabled: true + naas: + enabled: true + enabledPackages: + - cozystack.velero + - cozystack.backupstrategy-controller diff --git a/packages/core/platform/values-isp-full.yaml b/packages/core/platform/values-isp-full.yaml new file mode 100644 index 00000000..c79ff4ba --- /dev/null +++ b/packages/core/platform/values-isp-full.yaml @@ -0,0 +1,12 @@ +migrations: + enabled: true +bundles: + system: + enabled: true + variant: "isp-full" + iaas: + enabled: true + paas: + enabled: true + naas: + enabled: true diff --git a/packages/core/platform/values-isp-hosted.yaml b/packages/core/platform/values-isp-hosted.yaml new file mode 100644 index 00000000..c3af0deb --- /dev/null +++ b/packages/core/platform/values-isp-hosted.yaml @@ -0,0 +1,12 @@ +migrations: + enabled: true +bundles: + system: + enabled: false + variant: "isp-hosted" + iaas: + enabled: false + paas: + enabled: true + naas: + enabled: true diff --git a/packages/core/platform/values.yaml b/packages/core/platform/values.yaml new file mode 100644 index 00000000..605e23bc --- /dev/null +++ b/packages/core/platform/values.yaml @@ -0,0 +1,137 @@ +sourceRef: + kind: OCIRepository + name: cozystack-platform + namespace: cozy-system + path: / +migrations: + enabled: false + image: ghcr.io/cozystack/cozystack/platform-migrations:v1.3.0@sha256:555e4b76421361805a84bc9088b01b23a9c4a9430bd8ebd2db82ef9677d7008c + targetVersion: 39 +# Bundle deployment configuration +bundles: + system: + enabled: false + variant: "isp-full" # Options: "isp-full", "isp-full-generic", "isp-hosted", "distro-full" + iaas: + enabled: false + paas: + enabled: false + naas: + enabled: false + disabledPackages: [] + enabledPackages: [] +# Network configuration +networking: + clusterDomain: "cozy.local" + podCIDR: "10.244.0.0/16" + podGateway: "10.244.0.1" + serviceCIDR: "10.96.0.0/16" + joinCIDR: "100.64.0.0/16" + # KubeOVN master nodes override (optional) + # By default, KubeOVN helm chart uses `lookup` to find control-plane nodes + # by label `node-role.kubernetes.io/control-plane`. On fresh clusters or + # during initial deployment, lookup may return empty results. + # Set this to comma-separated list of master node IPs to override. + kubeovn: + MASTER_NODES: "" +# Service publishing and ingress configuration +publishing: + host: "example.org" + ingressName: tenant-root + exposedServices: + - api + - dashboard + - vm-exportproxy + - cdi-uploadproxy + apiServerEndpoint: "" # example: "https://api.example.org" + externalIPs: [] + # Exposure mode for the ingress-nginx Service. When "externalIPs" (current + # default) is selected, the Service is created as ClusterIP with + # Service.spec.externalIPs set from publishing.externalIPs. When + # "loadBalancer" is selected, the Service is type: LoadBalancer and a + # CiliumLoadBalancerIPPool makes those same addresses allocatable via LB IPAM. + # + # Service.spec.externalIPs is deprecated upstream in Kubernetes v1.36 + # (KEP-5707). The AllowServiceExternalIPs feature gate is expected to default + # to false around v1.40 and the implementation removed around v1.43 — switch + # to "loadBalancer" before upgrading past v1.40. + # + # Caveats for the "loadBalancer" mode: + # - publishing.externalIPs must contain at least one non-empty address, + # otherwise the chart render fails with an explicit error (a LoadBalancer + # Service without a pool would sit in forever). + # - The ingress-nginx Service is created with externalTrafficPolicy: Local + # to preserve the client source IP. Traffic arriving on a node that does + # not host an ingress-nginx pod is dropped, so the external IP must be + # routed to a node that runs the ingress pod (floating IP / keepalived / + # upstream router / podAntiAffinity). + # - Cilium does NOT announce the IP on its own unless L2 announcements or + # BGP are enabled in the Cilium values (disabled by default in Cozystack). + # This mode assumes the operator already routes the externalIPs to a + # cluster node; enabling announcements is out of scope for this setting. + # - Switching this value on a running cluster causes the ingress-nginx + # Service to be recreated (the HelmRelease has upgrade.force: true and + # the Service kind changes between ClusterIP and LoadBalancer). Expect a + # brief interruption of ingress traffic during the flip. + # + # Scope: this setting only controls the ingress-nginx Service. Other + # cozystack components that currently write Service.spec.externalIPs directly + # (e.g. the vpn app at packages/apps/vpn/templates/service.yaml) are NOT + # migrated by flipping this value and must be addressed separately before + # the AllowServiceExternalIPs feature gate flips to off in ~v1.40. + exposure: externalIPs # "externalIPs" or "loadBalancer" + certificates: + solver: http01 # "http01" or "dns01" + issuerName: letsencrypt-prod +# Authentication configuration +authentication: + oidc: + enabled: false + insecureSkipVerify: false + keycloakExtraRedirectUri: "" + # Internal URL to access KeyCloak realm for backend-to-backend requests (bypasses external DNS). + # When set, oauth2-proxy uses --skip-oidc-discovery and routes all backend calls (token, jwks, + # userinfo, logout) through this URL while keeping browser redirects on the external URL. + # Example: http://keycloak-http.cozy-keycloak.svc:8080/realms/cozy + keycloakInternalUrl: "" +# Pod scheduling configuration +scheduling: + globalAppTopologySpreadConstraints: "" +# UI branding configuration +branding: {} +# Container registry mirrors configuration +# +# Example: +# registries: +# mirrors: +# docker.io: +# endpoints: +# - http://10.0.0.1:8082 +# ghcr.io: +# endpoints: +# - http://10.0.0.1:8083 +# gcr.io: +# endpoints: +# - http://10.0.0.1:8084 +# registry.k8s.io: +# endpoints: +# - http://10.0.0.1:8085 +# quay.io: +# endpoints: +# - http://10.0.0.1:8086 +# cr.fluentbit.io: +# endpoints: +# - http://10.0.0.1:8087 +# docker-registry3.mariadb.com: +# endpoints: +# - http://10.0.0.1:8088 +# config: +# "10.0.0.1:8082": +# tls: +# insecureSkipVerify: true +registries: {} +# Resource allocation ratios +resources: + cpuAllocationRatio: 10 + memoryAllocationRatio: 1 + ephemeralStorageAllocationRatio: 40 diff --git a/packages/core/talos/Chart.yaml b/packages/core/talos/Chart.yaml new file mode 100644 index 00000000..0ba301dc --- /dev/null +++ b/packages/core/talos/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +name: cozy-talos +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process + diff --git a/packages/core/talos/Makefile b/packages/core/talos/Makefile new file mode 100644 index 00000000..e06793b9 --- /dev/null +++ b/packages/core/talos/Makefile @@ -0,0 +1,56 @@ +NAME=talos +NAMESPACE=cozy-system + +TALOS_VERSION=$(shell awk '/^version:/ {print $$2}' images/talos/profiles/installer.yaml) + +include ../../../hack/common-envs.mk + +update: + hack/gen-profiles.sh + +image: image-matchbox image-talos + +image-talos: + test -f ../../../_out/assets/installer-amd64.tar || make talos-installer + skopeo copy docker-archive:../../../_out/assets/installer-amd64.tar docker://$(REGISTRY)/talos:$(call settag,$(TALOS_VERSION)) + +image-matchbox: + test -f ../../../_out/assets/kernel-amd64 || make talos-kernel + test -f ../../../_out/assets/initramfs-metal-amd64.xz || make talos-initramfs + docker buildx build -f images/matchbox/Dockerfile ../../.. \ + --tag $(REGISTRY)/matchbox:$(call settag,$(TAG)) \ + --tag $(REGISTRY)/matchbox:$(call settag,$(TALOS_VERSION)-$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/matchbox:latest \ + --cache-to type=inline \ + --metadata-file images/matchbox.json \ + $(BUILDX_ARGS) + echo "$(REGISTRY)/matchbox:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/matchbox.json -o json -r)" \ + > ../../extra/bootbox/images/matchbox.tag + rm -f images/matchbox.json + +assets: talos-iso talos-nocloud talos-metal talos-kernel talos-initramfs + +talos-initramfs: + test -f ../../../_out/assets/initramfs-metal-amd64.xz || $(MAKE) build-talos-initramfs + +talos-kernel: + test -f ../../../_out/assets/kernel-amd64 || $(MAKE) build-talos-kernel + +talos-installer: + test -f ../../../_out/assets/installer-amd64.tar || $(MAKE) build-talos-installer + +talos-iso: + test -f ../../../_out/assets/metal-amd64.iso || $(MAKE) build-talos-iso + +talos-nocloud: + test -f ../../../_out/assets/nocloud-amd64.raw.xz || $(MAKE) build-talos-nocloud + +talos-metal: + test -f ../../../_out/assets/metal-amd64.raw.xz || $(MAKE) build-talos-metal + +build-talos-initramfs build-talos-kernel build-talos-installer build-talos-iso build-talos-nocloud build-talos-metal: + mkdir -p ../../../_out/assets + cat images/talos/profiles/$(subst build-talos-,,$@).yaml | \ + docker run --rm -i -v /dev:/dev --privileged "ghcr.io/siderolabs/imager:$(TALOS_VERSION)" --tar-to-stdout - | \ + tar -C ../../../_out/assets -xzf- + diff --git a/packages/core/installer/hack/gen-profiles.sh b/packages/core/talos/hack/gen-profiles.sh similarity index 63% rename from packages/core/installer/hack/gen-profiles.sh rename to packages/core/talos/hack/gen-profiles.sh index 5225ace6..bbe932d7 100755 --- a/packages/core/installer/hack/gen-profiles.sh +++ b/packages/core/talos/hack/gen-profiles.sh @@ -2,8 +2,9 @@ set -e set -u +TMPDIR=$(mktemp -d) PROFILES="initramfs kernel iso installer nocloud metal" -FIRMWARES="amd-ucode amdgpu-firmware bnx2-bnx2x i915-ucode intel-ice-firmware intel-ucode qlogic-firmware" +FIRMWARES="amd-ucode amdgpu bnx2-bnx2x i915 intel-ice-firmware intel-ucode qlogic-firmware" EXTENSIONS="drbd zfs" mkdir -p images/talos/profiles @@ -14,20 +15,22 @@ echo "$talos_version" export "TALOS_VERSION=$talos_version" +crane export ghcr.io/siderolabs/extensions:${TALOS_VERSION} | tar x -O image-digests > $TMPDIR/image-digests + for firmware in $FIRMWARES; do printf "fetching %s version: " "$firmware" - firmware_var=$(echo "$firmware" | tr '[:lower:]' '[:upper:]' | tr - _)_VERSION - version=$(skopeo list-tags docker://ghcr.io/siderolabs/$firmware | jq -r '.Tags[]|select(length == 8)|select(startswith("20"))' | sort -V | tail -n 1) - echo "$version" - export "$firmware_var=$version" + firmware_var=$(echo "$firmware" | tr '[:lower:]' '[:upper:]' | tr - _)_IMAGE + image=$(grep -F "/$firmware:" $TMPDIR/image-digests) + echo "$image" + export "$firmware_var=$image" done for extension in $EXTENSIONS; do printf "fetching %s version: " "$extension" - extension_var=$(echo "$extension" | tr '[:lower:]' '[:upper:]' | tr - _)_VERSION - version=$(skopeo --override-os linux --override-arch amd64 list-tags docker://ghcr.io/siderolabs/$extension | jq -r '.Tags[]' | grep "\-${talos_version}$" | sort -V | tail -n1) - echo "$version" - export "$extension_var=$version" + extension_var=$(echo "$extension" | tr '[:lower:]' '[:upper:]' | tr - _)_IMAGE + image=$(grep -F "/$extension:" $TMPDIR/image-digests) + echo "$image" + export "$extension_var=$image" done for profile in $PROFILES; do @@ -76,15 +79,17 @@ input: initramfs: path: /usr/install/amd64/initramfs.xz baseInstaller: - imageRef: "ghcr.io/siderolabs/installer:v1.10.3" + imageRef: "ghcr.io/siderolabs/installer:${TALOS_VERSION}" systemExtensions: - - imageRef: ghcr.io/siderolabs/amd-ucode:${AMD_UCODE_VERSION} - - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:${BNX2_BNX2X_VERSION} - - imageRef: ghcr.io/siderolabs/intel-ice-firmware:${INTEL_ICE_FIRMWARE_VERSION} - - imageRef: ghcr.io/siderolabs/intel-ucode:${INTEL_UCODE_VERSION} - - imageRef: ghcr.io/siderolabs/qlogic-firmware:${QLOGIC_FIRMWARE_VERSION} - - imageRef: ghcr.io/siderolabs/drbd:${DRBD_VERSION} - - imageRef: ghcr.io/siderolabs/zfs:${ZFS_VERSION} + - imageRef: ${AMD_UCODE_IMAGE} + - imageRef: ${AMDGPU_IMAGE} + - imageRef: ${BNX2_BNX2X_IMAGE} + - imageRef: ${INTEL_ICE_FIRMWARE_IMAGE} + - imageRef: ${I915_IMAGE} + - imageRef: ${INTEL_UCODE_IMAGE} + - imageRef: ${QLOGIC_FIRMWARE_IMAGE} + - imageRef: ${DRBD_IMAGE} + - imageRef: ${ZFS_IMAGE} output: kind: ${kind} imageOptions: ${image_options} diff --git a/packages/core/installer/hack/gen-versions.sh b/packages/core/talos/hack/gen-versions.sh similarity index 100% rename from packages/core/installer/hack/gen-versions.sh rename to packages/core/talos/hack/gen-versions.sh diff --git a/packages/core/installer/images/matchbox/Dockerfile b/packages/core/talos/images/matchbox/Dockerfile similarity index 53% rename from packages/core/installer/images/matchbox/Dockerfile rename to packages/core/talos/images/matchbox/Dockerfile index 1083ab26..fbb6f3bf 100644 --- a/packages/core/installer/images/matchbox/Dockerfile +++ b/packages/core/talos/images/matchbox/Dockerfile @@ -2,5 +2,5 @@ FROM quay.io/poseidon/matchbox:v0.10.0 COPY _out/assets/initramfs-metal-amd64.xz /var/lib/matchbox/assets/initramfs.xz COPY _out/assets/kernel-amd64 /var/lib/matchbox/assets/vmlinuz -COPY packages/core/installer/images/matchbox/groups /var/lib/matchbox/groups -COPY packages/core/installer/images/matchbox/profiles /var/lib/matchbox/profiles +COPY packages/core/talos/images/matchbox/groups /var/lib/matchbox/groups +COPY packages/core/talos/images/matchbox/profiles /var/lib/matchbox/profiles diff --git a/packages/core/installer/images/matchbox/groups/default.json b/packages/core/talos/images/matchbox/groups/default.json similarity index 100% rename from packages/core/installer/images/matchbox/groups/default.json rename to packages/core/talos/images/matchbox/groups/default.json diff --git a/packages/core/installer/images/matchbox/profiles/default.json b/packages/core/talos/images/matchbox/profiles/default.json similarity index 100% rename from packages/core/installer/images/matchbox/profiles/default.json rename to packages/core/talos/images/matchbox/profiles/default.json diff --git a/packages/core/talos/images/talos/profiles/initramfs.yaml b/packages/core/talos/images/talos/profiles/initramfs.yaml new file mode 100644 index 00000000..182fb3e8 --- /dev/null +++ b/packages/core/talos/images/talos/profiles/initramfs.yaml @@ -0,0 +1,27 @@ +# this file generated by hack/gen-profiles.sh +# do not edit it +arch: amd64 +platform: metal +secureboot: false +version: v1.12.6 +input: + kernel: + path: /usr/install/amd64/vmlinuz + initramfs: + path: /usr/install/amd64/initramfs.xz + baseInstaller: + imageRef: "ghcr.io/siderolabs/installer:v1.12.6" + systemExtensions: + - imageRef: ghcr.io/siderolabs/amd-ucode:20260309@sha256:716cd5350f77e7b10eebef88d8abdd0c32f2d929acd2bceac7ea33c0aac3b1a7 + - imageRef: ghcr.io/siderolabs/amdgpu:20260309-v1.12.6@sha256:64c7cbcde57a69742c76e3899385f5cd6af1238b0aba094962197fd4098838bd + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20260309@sha256:b17b87d9a20c806cf186e95ab351b771ffd622a35afcbd41eb07d4642680a231 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20260309@sha256:eee55c66cb23fe93380b83909af2cd4ede970205b861c0aa147404c88e8c7f65 + - imageRef: ghcr.io/siderolabs/i915:20260309-v1.12.6@sha256:6d150e23b2ca98ed34fca2b0510bc97e912f95839926bf6e02c55952e15387c2 + - imageRef: ghcr.io/siderolabs/intel-ucode:20260227@sha256:6112f6426a7081727545f7c33dcf2a89ff672494847b180380b4c58f3544a7b2 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20260309@sha256:b97cfde1e252412ba594a16302a3505f80aee1f105e2aa76b3bdf3b9dcc56cab + - imageRef: ghcr.io/siderolabs/drbd:9.2.16-v1.12.6@sha256:f524139c5be4626d7f2b6bd47745ce93648f3f1ab2b681fb00f8ab97ec2c19a3 + - imageRef: ghcr.io/siderolabs/zfs:2.4.1-v1.12.6@sha256:059d39f1d2d6dde263dbd8062207d0aa68805bb0748c087494791c7f985b87d1 +output: + kind: initramfs + imageOptions: {} + outFormat: raw diff --git a/packages/core/talos/images/talos/profiles/installer.yaml b/packages/core/talos/images/talos/profiles/installer.yaml new file mode 100644 index 00000000..c56c1d32 --- /dev/null +++ b/packages/core/talos/images/talos/profiles/installer.yaml @@ -0,0 +1,27 @@ +# this file generated by hack/gen-profiles.sh +# do not edit it +arch: amd64 +platform: metal +secureboot: false +version: v1.12.6 +input: + kernel: + path: /usr/install/amd64/vmlinuz + initramfs: + path: /usr/install/amd64/initramfs.xz + baseInstaller: + imageRef: "ghcr.io/siderolabs/installer:v1.12.6" + systemExtensions: + - imageRef: ghcr.io/siderolabs/amd-ucode:20260309@sha256:716cd5350f77e7b10eebef88d8abdd0c32f2d929acd2bceac7ea33c0aac3b1a7 + - imageRef: ghcr.io/siderolabs/amdgpu:20260309-v1.12.6@sha256:64c7cbcde57a69742c76e3899385f5cd6af1238b0aba094962197fd4098838bd + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20260309@sha256:b17b87d9a20c806cf186e95ab351b771ffd622a35afcbd41eb07d4642680a231 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20260309@sha256:eee55c66cb23fe93380b83909af2cd4ede970205b861c0aa147404c88e8c7f65 + - imageRef: ghcr.io/siderolabs/i915:20260309-v1.12.6@sha256:6d150e23b2ca98ed34fca2b0510bc97e912f95839926bf6e02c55952e15387c2 + - imageRef: ghcr.io/siderolabs/intel-ucode:20260227@sha256:6112f6426a7081727545f7c33dcf2a89ff672494847b180380b4c58f3544a7b2 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20260309@sha256:b97cfde1e252412ba594a16302a3505f80aee1f105e2aa76b3bdf3b9dcc56cab + - imageRef: ghcr.io/siderolabs/drbd:9.2.16-v1.12.6@sha256:f524139c5be4626d7f2b6bd47745ce93648f3f1ab2b681fb00f8ab97ec2c19a3 + - imageRef: ghcr.io/siderolabs/zfs:2.4.1-v1.12.6@sha256:059d39f1d2d6dde263dbd8062207d0aa68805bb0748c087494791c7f985b87d1 +output: + kind: installer + imageOptions: {} + outFormat: raw diff --git a/packages/core/talos/images/talos/profiles/iso.yaml b/packages/core/talos/images/talos/profiles/iso.yaml new file mode 100644 index 00000000..25fc336a --- /dev/null +++ b/packages/core/talos/images/talos/profiles/iso.yaml @@ -0,0 +1,27 @@ +# this file generated by hack/gen-profiles.sh +# do not edit it +arch: amd64 +platform: metal +secureboot: false +version: v1.12.6 +input: + kernel: + path: /usr/install/amd64/vmlinuz + initramfs: + path: /usr/install/amd64/initramfs.xz + baseInstaller: + imageRef: "ghcr.io/siderolabs/installer:v1.12.6" + systemExtensions: + - imageRef: ghcr.io/siderolabs/amd-ucode:20260309@sha256:716cd5350f77e7b10eebef88d8abdd0c32f2d929acd2bceac7ea33c0aac3b1a7 + - imageRef: ghcr.io/siderolabs/amdgpu:20260309-v1.12.6@sha256:64c7cbcde57a69742c76e3899385f5cd6af1238b0aba094962197fd4098838bd + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20260309@sha256:b17b87d9a20c806cf186e95ab351b771ffd622a35afcbd41eb07d4642680a231 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20260309@sha256:eee55c66cb23fe93380b83909af2cd4ede970205b861c0aa147404c88e8c7f65 + - imageRef: ghcr.io/siderolabs/i915:20260309-v1.12.6@sha256:6d150e23b2ca98ed34fca2b0510bc97e912f95839926bf6e02c55952e15387c2 + - imageRef: ghcr.io/siderolabs/intel-ucode:20260227@sha256:6112f6426a7081727545f7c33dcf2a89ff672494847b180380b4c58f3544a7b2 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20260309@sha256:b97cfde1e252412ba594a16302a3505f80aee1f105e2aa76b3bdf3b9dcc56cab + - imageRef: ghcr.io/siderolabs/drbd:9.2.16-v1.12.6@sha256:f524139c5be4626d7f2b6bd47745ce93648f3f1ab2b681fb00f8ab97ec2c19a3 + - imageRef: ghcr.io/siderolabs/zfs:2.4.1-v1.12.6@sha256:059d39f1d2d6dde263dbd8062207d0aa68805bb0748c087494791c7f985b87d1 +output: + kind: iso + imageOptions: {} + outFormat: raw diff --git a/packages/core/talos/images/talos/profiles/kernel.yaml b/packages/core/talos/images/talos/profiles/kernel.yaml new file mode 100644 index 00000000..d0153bf8 --- /dev/null +++ b/packages/core/talos/images/talos/profiles/kernel.yaml @@ -0,0 +1,27 @@ +# this file generated by hack/gen-profiles.sh +# do not edit it +arch: amd64 +platform: metal +secureboot: false +version: v1.12.6 +input: + kernel: + path: /usr/install/amd64/vmlinuz + initramfs: + path: /usr/install/amd64/initramfs.xz + baseInstaller: + imageRef: "ghcr.io/siderolabs/installer:v1.12.6" + systemExtensions: + - imageRef: ghcr.io/siderolabs/amd-ucode:20260309@sha256:716cd5350f77e7b10eebef88d8abdd0c32f2d929acd2bceac7ea33c0aac3b1a7 + - imageRef: ghcr.io/siderolabs/amdgpu:20260309-v1.12.6@sha256:64c7cbcde57a69742c76e3899385f5cd6af1238b0aba094962197fd4098838bd + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20260309@sha256:b17b87d9a20c806cf186e95ab351b771ffd622a35afcbd41eb07d4642680a231 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20260309@sha256:eee55c66cb23fe93380b83909af2cd4ede970205b861c0aa147404c88e8c7f65 + - imageRef: ghcr.io/siderolabs/i915:20260309-v1.12.6@sha256:6d150e23b2ca98ed34fca2b0510bc97e912f95839926bf6e02c55952e15387c2 + - imageRef: ghcr.io/siderolabs/intel-ucode:20260227@sha256:6112f6426a7081727545f7c33dcf2a89ff672494847b180380b4c58f3544a7b2 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20260309@sha256:b97cfde1e252412ba594a16302a3505f80aee1f105e2aa76b3bdf3b9dcc56cab + - imageRef: ghcr.io/siderolabs/drbd:9.2.16-v1.12.6@sha256:f524139c5be4626d7f2b6bd47745ce93648f3f1ab2b681fb00f8ab97ec2c19a3 + - imageRef: ghcr.io/siderolabs/zfs:2.4.1-v1.12.6@sha256:059d39f1d2d6dde263dbd8062207d0aa68805bb0748c087494791c7f985b87d1 +output: + kind: kernel + imageOptions: {} + outFormat: raw diff --git a/packages/core/talos/images/talos/profiles/metal.yaml b/packages/core/talos/images/talos/profiles/metal.yaml new file mode 100644 index 00000000..579cc333 --- /dev/null +++ b/packages/core/talos/images/talos/profiles/metal.yaml @@ -0,0 +1,27 @@ +# this file generated by hack/gen-profiles.sh +# do not edit it +arch: amd64 +platform: metal +secureboot: false +version: v1.12.6 +input: + kernel: + path: /usr/install/amd64/vmlinuz + initramfs: + path: /usr/install/amd64/initramfs.xz + baseInstaller: + imageRef: "ghcr.io/siderolabs/installer:v1.12.6" + systemExtensions: + - imageRef: ghcr.io/siderolabs/amd-ucode:20260309@sha256:716cd5350f77e7b10eebef88d8abdd0c32f2d929acd2bceac7ea33c0aac3b1a7 + - imageRef: ghcr.io/siderolabs/amdgpu:20260309-v1.12.6@sha256:64c7cbcde57a69742c76e3899385f5cd6af1238b0aba094962197fd4098838bd + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20260309@sha256:b17b87d9a20c806cf186e95ab351b771ffd622a35afcbd41eb07d4642680a231 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20260309@sha256:eee55c66cb23fe93380b83909af2cd4ede970205b861c0aa147404c88e8c7f65 + - imageRef: ghcr.io/siderolabs/i915:20260309-v1.12.6@sha256:6d150e23b2ca98ed34fca2b0510bc97e912f95839926bf6e02c55952e15387c2 + - imageRef: ghcr.io/siderolabs/intel-ucode:20260227@sha256:6112f6426a7081727545f7c33dcf2a89ff672494847b180380b4c58f3544a7b2 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20260309@sha256:b97cfde1e252412ba594a16302a3505f80aee1f105e2aa76b3bdf3b9dcc56cab + - imageRef: ghcr.io/siderolabs/drbd:9.2.16-v1.12.6@sha256:f524139c5be4626d7f2b6bd47745ce93648f3f1ab2b681fb00f8ab97ec2c19a3 + - imageRef: ghcr.io/siderolabs/zfs:2.4.1-v1.12.6@sha256:059d39f1d2d6dde263dbd8062207d0aa68805bb0748c087494791c7f985b87d1 +output: + kind: image + imageOptions: { diskSize: 1306525696, diskFormat: raw } + outFormat: .xz diff --git a/packages/core/talos/images/talos/profiles/nocloud.yaml b/packages/core/talos/images/talos/profiles/nocloud.yaml new file mode 100644 index 00000000..24ad7f3c --- /dev/null +++ b/packages/core/talos/images/talos/profiles/nocloud.yaml @@ -0,0 +1,27 @@ +# this file generated by hack/gen-profiles.sh +# do not edit it +arch: amd64 +platform: nocloud +secureboot: false +version: v1.12.6 +input: + kernel: + path: /usr/install/amd64/vmlinuz + initramfs: + path: /usr/install/amd64/initramfs.xz + baseInstaller: + imageRef: "ghcr.io/siderolabs/installer:v1.12.6" + systemExtensions: + - imageRef: ghcr.io/siderolabs/amd-ucode:20260309@sha256:716cd5350f77e7b10eebef88d8abdd0c32f2d929acd2bceac7ea33c0aac3b1a7 + - imageRef: ghcr.io/siderolabs/amdgpu:20260309-v1.12.6@sha256:64c7cbcde57a69742c76e3899385f5cd6af1238b0aba094962197fd4098838bd + - imageRef: ghcr.io/siderolabs/bnx2-bnx2x:20260309@sha256:b17b87d9a20c806cf186e95ab351b771ffd622a35afcbd41eb07d4642680a231 + - imageRef: ghcr.io/siderolabs/intel-ice-firmware:20260309@sha256:eee55c66cb23fe93380b83909af2cd4ede970205b861c0aa147404c88e8c7f65 + - imageRef: ghcr.io/siderolabs/i915:20260309-v1.12.6@sha256:6d150e23b2ca98ed34fca2b0510bc97e912f95839926bf6e02c55952e15387c2 + - imageRef: ghcr.io/siderolabs/intel-ucode:20260227@sha256:6112f6426a7081727545f7c33dcf2a89ff672494847b180380b4c58f3544a7b2 + - imageRef: ghcr.io/siderolabs/qlogic-firmware:20260309@sha256:b97cfde1e252412ba594a16302a3505f80aee1f105e2aa76b3bdf3b9dcc56cab + - imageRef: ghcr.io/siderolabs/drbd:9.2.16-v1.12.6@sha256:f524139c5be4626d7f2b6bd47745ce93648f3f1ab2b681fb00f8ab97ec2c19a3 + - imageRef: ghcr.io/siderolabs/zfs:2.4.1-v1.12.6@sha256:059d39f1d2d6dde263dbd8062207d0aa68805bb0748c087494791c7f985b87d1 +output: + kind: image + imageOptions: { diskSize: 1306525696, diskFormat: raw } + outFormat: .xz diff --git a/packages/core/talos/values.yaml b/packages/core/talos/values.yaml new file mode 100644 index 00000000..e69de29b diff --git a/packages/core/testing/Chart.yaml b/packages/core/testing/Chart.yaml old mode 100755 new mode 100644 diff --git a/packages/core/testing/Makefile b/packages/core/testing/Makefile old mode 100755 new mode 100644 index f597d5ce..ce21a8e1 --- a/packages/core/testing/Makefile +++ b/packages/core/testing/Makefile @@ -6,7 +6,7 @@ SANDBOX_NAME := cozy-e2e-sandbox-$(shell echo "$$(hostname):$$(pwd)" | sha256sum ROOT_DIR = $(dir $(abspath $(firstword $(MAKEFILE_LIST))/../../..)) -include ../../../scripts/common-envs.mk +include ../../../hack/common-envs.mk help: ## Show this help. @@ -16,36 +16,28 @@ image: image-e2e-sandbox image-e2e-sandbox: docker buildx build -f images/e2e-sandbox/Dockerfile images/e2e-sandbox \ - --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 \ --metadata-file images/e2e-sandbox.json \ - --push=$(PUSH) \ - --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ - --load=$(LOAD) + $(BUILDX_ARGS) IMAGE="$(REGISTRY)/e2e-sandbox:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/e2e-sandbox.json -o json -r)" \ yq -i '.e2e.image = strenv(IMAGE)' values.yaml rm -f images/e2e-sandbox.json -test: test-cluster test-apps ## Run the end-to-end tests in existing sandbox +test: test-openapi test-apps ## Run the end-to-end tests in existing sandbox copy-nocloud-image: docker cp ../../../_out/assets/nocloud-amd64.raw.xz "${SANDBOX_NAME}":/workspace/_out/assets/nocloud-amd64.raw.xz -copy-installer-manifest: - docker cp ../../../_out/assets/cozystack-installer.yaml "${SANDBOX_NAME}":/workspace/_out/assets/cozystack-installer.yaml - prepare-cluster: copy-nocloud-image docker exec "${SANDBOX_NAME}" sh -c 'cd /workspace && hack/cozytest.sh hack/e2e-prepare-cluster.bats' -install-cozystack: copy-installer-manifest +install-cozystack: docker exec "${SANDBOX_NAME}" sh -c 'cd /workspace && hack/cozytest.sh hack/e2e-install-cozystack.bats' -test-cluster: copy-nocloud-image copy-installer-manifest ## Run the end-to-end for creating a cluster - docker exec "${SANDBOX_NAME}" sh -c 'cd /workspace && hack/cozytest.sh hack/e2e-cluster.bats' +test-openapi: + docker exec "${SANDBOX_NAME}" sh -c 'cd /workspace && hack/cozytest.sh hack/e2e-test-openapi.bats' test-apps-%: docker exec "${SANDBOX_NAME}" sh -c 'cd /workspace && hack/cozytest.sh hack/e2e-apps/$*.bats' diff --git a/packages/core/testing/images/e2e-sandbox/Dockerfile b/packages/core/testing/images/e2e-sandbox/Dockerfile old mode 100755 new mode 100644 index d67dec13..2f94991f --- a/packages/core/testing/images/e2e-sandbox/Dockerfile +++ b/packages/core/testing/images/e2e-sandbox/Dockerfile @@ -3,13 +3,13 @@ FROM ubuntu:22.04 ARG KUBECTL_VERSION=1.33.2 ARG TALOSCTL_VERSION=1.10.4 ARG HELM_VERSION=3.18.3 -ARG COZYPKG_VERSION=1.1.0 +ARG COZYHR_VERSION=1.6.1 ARG TARGETOS ARG TARGETARCH RUN apt update -q -RUN apt install -yq --no-install-recommends psmisc genisoimage ca-certificates qemu-kvm qemu-utils iproute2 iptables wget xz-utils netcat curl jq make git +RUN apt install -yq --no-install-recommends psmisc genisoimage ca-certificates qemu-kvm qemu-utils iproute2 iptables wget xz-utils netcat curl jq make git bash-completion 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 \ @@ -18,7 +18,16 @@ RUN curl -sSL "https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm 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 -RUN curl -sSL "https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/install.sh" | sh -s -- -v "${COZYPKG_VERSION}" - +RUN curl -sSL "https://github.com/cozystack/cozyhr/raw/refs/heads/main/hack/install.sh" | sh -s -- -v "${COZYHR_VERSION}" +RUN curl https://dl.min.io/client/mc/release/${TARGETOS}-${TARGETARCH}/mc --create-dirs -o /usr/local/bin/mc \ +&& chmod +x /usr/local/bin/mc +RUN <<'EOF' +cat <<'EOT' >> /etc/bash.bashrc +. /etc/bash_completion +. <(kubectl completion bash) +alias k=kubectl +complete -F __start_kubectl k +EOT +EOF COPY entrypoint.sh /usr/local/bin/entrypoint.sh ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] diff --git a/packages/core/testing/values.yaml b/packages/core/testing/values.yaml old mode 100755 new mode 100644 index 9248aa45..9d4bdd10 --- 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.33.2@sha256:4af1266f9e055306deb6054be88230e864bfe420b8fa887ab675e6d2efb0f4fa + image: ghcr.io/cozystack/cozystack/e2e-sandbox:v1.3.0@sha256:0367a03b981df2a3ea13f411d4cb7869c2bf2c89c07d3d5c8971b9a28921ccef diff --git a/packages/extra/Makefile b/packages/extra/Makefile index e05e4985..dd3293a0 100644 --- a/packages/extra/Makefile +++ b/packages/extra/Makefile @@ -1,14 +1,12 @@ -OUT=../_out/repos/extra -TMP := $(shell mktemp -d) +OUT=../../_out/repos/extra +CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}') + +include ../../hack/common-envs.mk repo: - cd .. && ../hack/package_chart.sh extra $(OUT) $(TMP) library + rm -rf "$(OUT)" + helm package -d "$(OUT)" $(CHARTS) --version $(COZYSTACK_VERSION) + helm repo index "$(OUT)" -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 - -gen-versions-map: fix-chartnames - ../../hack/gen_versions_map.sh - -check-version-map: gen-versions-map - git diff --exit-code -- versions_map +fix-charts: + find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}' | while read i; do sed -i -e "s/^name: .*/name: $$i/" -e "s/^version: .*/version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process/g" "$$i/Chart.yaml"; done diff --git a/packages/extra/bootbox/Chart.yaml b/packages/extra/bootbox/Chart.yaml index 08e4b0cd..00b591c4 100644 --- a/packages/extra/bootbox/Chart.yaml +++ b/packages/extra/bootbox/Chart.yaml @@ -3,4 +3,4 @@ name: bootbox description: PXE hardware provisioning icon: /logos/bootbox.svg type: application -version: 0.2.0 +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/extra/bootbox/Makefile b/packages/extra/bootbox/Makefile index dec085a9..57fa0a77 100644 --- a/packages/extra/bootbox/Makefile +++ b/packages/extra/bootbox/Makefile @@ -1,11 +1,8 @@ NAME=bootbox NAMESPACE=tenant-root -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: - readme-generator -v values.yaml -s values.schema.json.tmp -r README.md - cat values.schema.json.tmp | \ - jq '.properties.machines.items.type = "object"' \ - > values.schema.json - rm -f values.schema.json.tmp + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md + ../../../hack/update-crd.sh diff --git a/packages/extra/bootbox/README.md b/packages/extra/bootbox/README.md index c3f25b32..70add719 100644 --- a/packages/extra/bootbox/README.md +++ b/packages/extra/bootbox/README.md @@ -4,8 +4,20 @@ ### Common parameters -| Name | Description | Value | -| --------------- | ----------------------------------------------------- | ------ | -| `whitelistHTTP` | Secure HTTP by enabling client networks whitelisting | `true` | -| `whitelist` | List of client networks | `[]` | -| `machines` | Configuration of physical machine instances | `[]` | +| Name | Description | Type | Value | +| ------------------------- | ----------------------------------------------------- | ---------- | ------- | +| `whitelistHTTP` | Secure HTTP by enabling client networks whitelisting. | `bool` | `true` | +| `whitelist` | List of client networks. | `[]string` | `[]` | +| `machines` | Configuration of physical machine instances. | `[]object` | `[]` | +| `machines[i].hostname` | Hostname. | `string` | `""` | +| `machines[i].arch` | Architecture. | `string` | `""` | +| `machines[i].ip` | IP address configuration. | `object` | `{}` | +| `machines[i].ip.address` | IP address. | `string` | `""` | +| `machines[i].ip.gateway` | IP gateway. | `string` | `""` | +| `machines[i].ip.netmask` | Netmask. | `string` | `""` | +| `machines[i].leaseTime` | Lease time. | `int` | `0` | +| `machines[i].mac` | MAC addresses. | `[]string` | `[]` | +| `machines[i].nameServers` | Name servers. | `[]string` | `[]` | +| `machines[i].timeServers` | Time servers. | `[]string` | `[]` | +| `machines[i].uefi` | UEFI. | `bool` | `false` | + diff --git a/packages/extra/bootbox/images/matchbox.tag b/packages/extra/bootbox/images/matchbox.tag index 807d1974..f51c7675 100644 --- a/packages/extra/bootbox/images/matchbox.tag +++ b/packages/extra/bootbox/images/matchbox.tag @@ -1 +1 @@ -ghcr.io/cozystack/cozystack/matchbox:v0.33.2@sha256:04e42e125127c0e696cfcb516821e72ce178caa8a92e4c06d3f65c3ef6b3ef1e +ghcr.io/cozystack/cozystack/matchbox:v1.3.0@sha256:85b8e04bf6f0690612dd63e80475df269f4a436d16680f8a40f2860cf16e2f74 diff --git a/packages/extra/bootbox/templates/matchbox/ingress.yaml b/packages/extra/bootbox/templates/matchbox/ingress.yaml index 31de7716..5eef3489 100644 --- a/packages/extra/bootbox/templates/matchbox/ingress.yaml +++ b/packages/extra/bootbox/templates/matchbox/ingress.yaml @@ -1,9 +1,7 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $solver := (index .Values._cluster "solver") | default "http01" }} +{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }} +{{- $ingress := .Values._namespace.ingress }} +{{- $host := .Values._namespace.host }} apiVersion: networking.k8s.io/v1 kind: Ingress metadata: @@ -11,10 +9,10 @@ metadata: labels: app: bootbox annotations: - {{- if ne $issuerType "cloudflare" }} - acme.cert-manager.io/http01-ingress-class: {{ $ingress }} + {{- if eq $solver "http01" }} + acme.cert-manager.io/http01-ingress-ingressclassname: {{ $ingress }} {{- end }} - cert-manager.io/cluster-issuer: letsencrypt-prod + cert-manager.io/cluster-issuer: {{ $clusterIssuer }} {{- if .Values.whitelistHTTP }} nginx.ingress.kubernetes.io/whitelist-source-range: "{{ join "," (.Values.whitelist | default "0.0.0.0/32") }}" {{- end }} diff --git a/packages/extra/bootbox/templates/matchbox/machines.yaml b/packages/extra/bootbox/templates/matchbox/machines.yaml index e2733b89..a52c4b40 100644 --- a/packages/extra/bootbox/templates/matchbox/machines.yaml +++ b/packages/extra/bootbox/templates/matchbox/machines.yaml @@ -1,9 +1,4 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $host := .Values._namespace.host }} {{ range $m := .Values.machines }} --- diff --git a/packages/extra/bootbox/values.schema.json b/packages/extra/bootbox/values.schema.json index e365ece4..8e243c12 100644 --- a/packages/extra/bootbox/values.schema.json +++ b/packages/extra/bootbox/values.schema.json @@ -3,22 +3,93 @@ "type": "object", "properties": { "whitelistHTTP": { + "description": "Secure HTTP by enabling client networks whitelisting.", "type": "boolean", - "description": "Secure HTTP by enabling client networks whitelisting", "default": true }, "whitelist": { + "description": "List of client networks.", "type": "array", - "description": "List of client networks", "default": [], - "items": {} + "items": { + "type": "string" + } }, "machines": { + "description": "Configuration of physical machine instances.", "type": "array", - "description": "Configuration of physical machine instances", - "default": "[]", + "default": [], "items": { - "type": "object" + "type": "object", + "required": [ + "arch", + "hostname", + "ip", + "leaseTime", + "uefi" + ], + "properties": { + "arch": { + "description": "Architecture.", + "type": "string" + }, + "hostname": { + "description": "Hostname.", + "type": "string" + }, + "ip": { + "description": "IP address configuration.", + "type": "object", + "required": [ + "address", + "gateway", + "netmask" + ], + "properties": { + "address": { + "description": "IP address.", + "type": "string" + }, + "gateway": { + "description": "IP gateway.", + "type": "string" + }, + "netmask": { + "description": "Netmask.", + "type": "string" + } + } + }, + "leaseTime": { + "description": "Lease time.", + "type": "integer" + }, + "mac": { + "description": "MAC addresses.", + "type": "array", + "items": { + "type": "string" + } + }, + "nameServers": { + "description": "Name servers.", + "type": "array", + "items": { + "type": "string" + } + }, + "timeServers": { + "description": "Time servers.", + "type": "array", + "items": { + "type": "string" + } + }, + "uefi": { + "description": "UEFI.", + "type": "boolean" + } + } } } } diff --git a/packages/extra/bootbox/values.yaml b/packages/extra/bootbox/values.yaml index f4d55572..ed447083 100644 --- a/packages/extra/bootbox/values.yaml +++ b/packages/extra/bootbox/values.yaml @@ -1,18 +1,35 @@ +## ## @section Common parameters +## -## @param whitelistHTTP Secure HTTP by enabling client networks whitelisting -## @param whitelist List of client networks +## @param {bool} whitelistHTTP - Secure HTTP by enabling client networks whitelisting. +whitelistHTTP: true ## Example: ## whitelistHTTP: true ## whitelist: ## - "1.2.3.4" ## - "10.8.0.0/16" -## -whitelistHTTP: true + +## @param {[]string} whitelist - List of client networks. whitelist: [] -## @param machines [array] Configuration of physical machine instances -## +## @typedef {struct} MachineConfig - IP address configuration. +## @field {string} address - IP address. +## @field {string} gateway - IP gateway. +## @field {string} netmask - Netmask. + +## @typedef {struct} Machine - Machine configuration. +## @field {string} hostname - Hostname. +## @field {string} arch - Architecture. +## @field {MachineConfig} ip - IP address configuration. +## @field {int} leaseTime - Lease time. +## @field {[]string} mac - MAC addresses. +## @field {[]string} nameServers - Name servers. +## @field {[]string} timeServers - Time servers. +## @field {bool} uefi - UEFI. + +## @param {[]Machine} machines - Configuration of physical machine instances. +machines: [] ## Example: ## machines: ## - hostname: machine1 @@ -26,5 +43,3 @@ whitelist: [] ## nameServers: [1.1.1.1,8.8.8.8] ## timeServers: [pool.ntp.org] ## uefi: true - -machines: [] diff --git a/packages/extra/etcd/Chart.yaml b/packages/extra/etcd/Chart.yaml index cdc44062..48900d42 100644 --- a/packages/extra/etcd/Chart.yaml +++ b/packages/extra/etcd/Chart.yaml @@ -3,4 +3,4 @@ name: etcd description: Storage for Kubernetes clusters icon: /logos/etcd.svg type: application -version: 2.9.0 +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/extra/etcd/Makefile b/packages/extra/etcd/Makefile index 1c503d6b..2b3ed61e 100644 --- a/packages/extra/etcd/Makefile +++ b/packages/extra/etcd/Makefile @@ -1,6 +1,10 @@ NAME=etcd -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: - readme-generator -v values.yaml -s values.schema.json -r README.md + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md + ../../../hack/update-crd.sh + +test: + helm unittest . diff --git a/packages/extra/etcd/README.md b/packages/extra/etcd/README.md index 96e3f1a9..daf9f114 100644 --- a/packages/extra/etcd/README.md +++ b/packages/extra/etcd/README.md @@ -4,8 +4,12 @@ ### Common parameters -| Name | Description | Value | -| -------------- | ----------------------------------- | ----- | -| `size` | Persistent Volume size | `4Gi` | -| `storageClass` | StorageClass used to store the data | `""` | -| `replicas` | Number of etcd replicas | `3` | +| Name | Description | Type | Value | +| ------------------ | ------------------------------------ | ---------- | ------- | +| `size` | Persistent Volume size. | `quantity` | `4Gi` | +| `storageClass` | StorageClass used to store the data. | `string` | `""` | +| `replicas` | Number of etcd replicas. | `int` | `3` | +| `resources` | Resource configuration for etcd. | `object` | `{}` | +| `resources.cpu` | Number of CPU cores allocated. | `quantity` | `1000m` | +| `resources.memory` | Amount of memory allocated. | `quantity` | `512Mi` | + diff --git a/packages/extra/etcd/templates/etcd-cluster.yaml b/packages/extra/etcd/templates/etcd-cluster.yaml index f3b5637f..a604b448 100644 --- a/packages/extra/etcd/templates/etcd-cluster.yaml +++ b/packages/extra/etcd/templates/etcd-cluster.yaml @@ -46,9 +46,28 @@ spec: - name: metrics containerPort: 2381 protocol: TCP + startupProbe: + failureThreshold: 300 + periodSeconds: 5 + livenessProbe: + failureThreshold: 10 + periodSeconds: 10 + readinessProbe: + failureThreshold: 3 + periodSeconds: 5 {{- with .Values.resources }} resources: {{- include "cozy-lib.resources.sanitize" (list . $) | nindent 10 }} {{- end }} + {{- $rawConstraints := "" }} + {{- if .Values._cluster.scheduling }} + {{- $rawConstraints = get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }} + {{- end }} + {{- if $rawConstraints }} + {{- $rawConstraints | fromYaml | toYaml | nindent 6 }} + labelSelector: + matchLabels: + app.kubernetes.io/instance: etcd + {{- else }} topologySpreadConstraints: - maxSkew: 1 topologyKey: "kubernetes.io/hostname" @@ -56,6 +75,7 @@ spec: labelSelector: matchLabels: app.kubernetes.io/instance: etcd + {{- end }} podDisruptionBudgetTemplate: {} --- apiVersion: cert-manager.io/v1 @@ -84,6 +104,7 @@ spec: - {{ .Release.Name }} secretName: etcd-peer-ca-tls privateKey: + rotationPolicy: Never algorithm: RSA size: 4096 issuerRef: @@ -110,6 +131,7 @@ spec: - {{ .Release.Name }} secretName: etcd-ca-tls privateKey: + rotationPolicy: Never algorithm: RSA size: 4096 issuerRef: diff --git a/packages/extra/etcd/templates/etcd-defrag.yaml b/packages/extra/etcd/templates/etcd-defrag.yaml index 21a8e514..0478129f 100644 --- a/packages/extra/etcd/templates/etcd-defrag.yaml +++ b/packages/extra/etcd/templates/etcd-defrag.yaml @@ -4,14 +4,26 @@ metadata: name: {{ .Release.Name }}-defrag spec: schedule: "0 * * * *" + concurrencyPolicy: Forbid + startingDeadlineSeconds: 300 successfulJobsHistoryLimit: 3 + failedJobsHistoryLimit: 1 jobTemplate: spec: + activeDeadlineSeconds: 1800 + backoffLimit: 2 template: spec: containers: - name: etcd-defrag image: ghcr.io/ahrtr/etcd-defrag:v0.13.0 + resources: + requests: + cpu: 200m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi args: - --endpoints={{ range $i, $e := until (int .Values.replicas) }}{{ if $i }},{{ end }}https://{{ $.Release.Name }}-{{ $i }}.{{ $.Release.Name }}-headless.{{ $.Release.Namespace }}.svc:2379{{ end }} - --cacert=/etc/etcd/pki/client/cert/ca.crt diff --git a/packages/extra/etcd/templates/hook/job.yaml b/packages/extra/etcd/templates/hook/job.yaml deleted file mode 100644 index 1a93e6f2..00000000 --- a/packages/extra/etcd/templates/hook/job.yaml +++ /dev/null @@ -1,39 +0,0 @@ -{{- $shouldUpdateCerts := true }} -{{- $configMap := lookup "v1" "ConfigMap" .Release.Namespace "etcd-deployed-version" }} -{{- if $configMap }} - {{- $deployedVersion := index $configMap "data" "version" }} - {{- if $deployedVersion | semverCompare ">= 2.6.1" }} - {{- $shouldUpdateCerts = false }} - {{- end }} -{{- end }} - -{{- if $shouldUpdateCerts }} ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: etcd-hook - annotations: - helm.sh/hook: post-upgrade - helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded -spec: - template: - metadata: - labels: - policy.cozystack.io/allow-to-apiserver: "true" - spec: - serviceAccountName: etcd-hook - containers: - - name: kubectl - image: bitnami/kubectl:latest - command: - - sh - args: - - -exc - - |- - kubectl --namespace={{ .Release.Namespace }} delete secrets etcd-ca-tls etcd-peer-ca-tls - sleep 10 - kubectl --namespace={{ .Release.Namespace }} delete secrets etcd-client-tls etcd-peer-tls etcd-server-tls - kubectl --namespace={{ .Release.Namespace }} delete pods --selector=app.kubernetes.io/instance=etcd,app.kubernetes.io/managed-by=etcd-operator,app.kubernetes.io/name=etcd,cozystack.io/service=etcd - restartPolicy: Never -{{- end }} diff --git a/packages/extra/etcd/templates/hook/role.yaml b/packages/extra/etcd/templates/hook/role.yaml deleted file mode 100644 index 327eeadb..00000000 --- a/packages/extra/etcd/templates/hook/role.yaml +++ /dev/null @@ -1,26 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - annotations: - helm.sh/hook: post-upgrade - helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded - name: etcd-hook -rules: -- apiGroups: - - "" - resources: - - secrets - - pods - verbs: - - get - - list - - watch - - delete -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch diff --git a/packages/extra/etcd/templates/hook/rolebinding.yaml b/packages/extra/etcd/templates/hook/rolebinding.yaml deleted file mode 100644 index 0ee0ffd1..00000000 --- a/packages/extra/etcd/templates/hook/rolebinding.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: etcd-hook - annotations: - helm.sh/hook: post-upgrade - helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: etcd-hook -subjects: - - kind: ServiceAccount - name: etcd-hook - namespace: {{ .Release.Namespace | quote }} diff --git a/packages/extra/etcd/templates/hook/serviceaccount.yaml b/packages/extra/etcd/templates/hook/serviceaccount.yaml deleted file mode 100644 index 552fb5fc..00000000 --- a/packages/extra/etcd/templates/hook/serviceaccount.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: etcd-hook - annotations: - helm.sh/hook: post-upgrade - helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded diff --git a/packages/extra/etcd/templates/version.yaml b/packages/extra/etcd/templates/version.yaml deleted file mode 100644 index cc9375bb..00000000 --- a/packages/extra/etcd/templates/version.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: etcd-deployed-version -data: - version: {{ .Chart.Version }} diff --git a/packages/extra/etcd/templates/vpa.yaml b/packages/extra/etcd/templates/vpa.yaml new file mode 100644 index 00000000..57055cbd --- /dev/null +++ b/packages/extra/etcd/templates/vpa.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: etcd +spec: + targetRef: + apiVersion: apps/v1 + kind: StatefulSet + name: etcd + updatePolicy: + updateMode: Auto + resourcePolicy: + containerPolicies: + - containerName: etcd + {{- with dict "cpu" "250m" "memory" "256Mi" }} + minAllowed: {{- get (include "cozy-lib.resources.sanitize" (list . $) | fromYaml) "requests" | toYaml | nindent 8 }} + {{- end }} + {{- with dict "cpu" "5000m" "memory" "8Gi" }} + maxAllowed: {{- get (include "cozy-lib.resources.sanitize" (list . $) | fromYaml) "requests" | toYaml | nindent 8 }} + {{- end }} diff --git a/packages/extra/etcd/tests/no-post-upgrade-hook_test.yaml b/packages/extra/etcd/tests/no-post-upgrade-hook_test.yaml new file mode 100644 index 00000000..0e4f5aa3 --- /dev/null +++ b/packages/extra/etcd/tests/no-post-upgrade-hook_test.yaml @@ -0,0 +1,34 @@ +suite: etcd chart does not ship a destructive post-upgrade cert-regeneration hook + +release: + name: etcd + namespace: tenant-root + +templates: + - templates/check-release-name.yaml + - templates/dashboard-resourcemap.yaml + - templates/datastore.yaml + - templates/etcd-defrag.yaml + - templates/hook/job.yaml + - templates/podscrape.yaml + - templates/prometheus-rules.yaml + - templates/version.yaml + +tests: + - it: renders no Job named etcd-hook + documentSelector: + path: metadata.name + value: etcd-hook + skipEmptyTemplates: true + asserts: + - hasDocuments: + count: 0 + + - it: renders no ConfigMap named etcd-deployed-version + documentSelector: + path: metadata.name + value: etcd-deployed-version + skipEmptyTemplates: true + asserts: + - hasDocuments: + count: 0 diff --git a/packages/extra/etcd/values.schema.json b/packages/extra/etcd/values.schema.json index 0582e97c..3c66664c 100644 --- a/packages/extra/etcd/values.schema.json +++ b/packages/extra/etcd/values.schema.json @@ -1,21 +1,65 @@ { - "title": "Chart Values", - "type": "object", - "properties": { - "size": { - "type": "string", - "description": "Persistent Volume size", - "default": "4Gi" + "title": "Chart Values", + "type": "object", + "properties": { + "size": { + "description": "Persistent Volume size.", + "default": "4Gi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" }, - "storageClass": { - "type": "string", - "description": "StorageClass used to store the data", - "default": "" - }, - "replicas": { - "type": "number", - "description": "Number of etcd replicas", - "default": 3 + { + "type": "string" } + ], + "x-kubernetes-int-or-string": true + }, + "storageClass": { + "description": "StorageClass used to store the data.", + "type": "string", + "default": "" + }, + "replicas": { + "description": "Number of etcd replicas.", + "type": "integer", + "default": 3 + }, + "resources": { + "description": "Resource configuration for etcd.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "Number of CPU cores allocated.", + "default": "1000m", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Amount of memory allocated.", + "default": "512Mi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } } + } } diff --git a/packages/extra/etcd/values.yaml b/packages/extra/etcd/values.yaml index d8b927fe..8dac251d 100644 --- a/packages/extra/etcd/values.yaml +++ b/packages/extra/etcd/values.yaml @@ -1,14 +1,21 @@ -## @section Common parameters - -## @param size Persistent Volume size -## @param storageClass StorageClass used to store the data -## @param replicas Number of etcd replicas ## +## @section Common parameters +## + +## @param {quantity} [size] - Persistent Volume size. size: 4Gi + +## @param {string} [storageClass] - StorageClass used to store the data. storageClass: "" + +## @param {int} [replicas] - Number of etcd replicas. replicas: 3 -## @param resources Resources +## @typedef {struct} Resources - Resource configuration for etcd. +## @field {quantity} [cpu] - Number of CPU cores allocated. +## @field {quantity} [memory] - Amount of memory allocated. + +## @param {Resources} [resources] - Resource configuration for etcd. resources: - cpu: 4 - memory: 1Gi + cpu: 1000m + memory: 512Mi diff --git a/packages/extra/external-dns/Chart.yaml b/packages/extra/external-dns/Chart.yaml new file mode 100644 index 00000000..d9788a41 --- /dev/null +++ b/packages/extra/external-dns/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: external-dns +description: External DNS for automatic DNS record management +icon: /logos/external-dns.svg +type: application +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/extra/external-dns/Makefile b/packages/extra/external-dns/Makefile new file mode 100644 index 00000000..8b8fbc2f --- /dev/null +++ b/packages/extra/external-dns/Makefile @@ -0,0 +1,7 @@ +NAME=external-dns + +include ../../../hack/package.mk + +generate: + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md + ../../../hack/update-crd.sh diff --git a/packages/extra/external-dns/README.md b/packages/extra/external-dns/README.md new file mode 100644 index 00000000..027182c1 --- /dev/null +++ b/packages/extra/external-dns/README.md @@ -0,0 +1,88 @@ +# External DNS + +## Parameters + +### Common parameters + +| Name | Description | Type | Value | +| ------------------ | ---------------------------------------------------------------------------------- | ---------- | ------------- | +| `provider` | DNS provider name. | `string` | `{}` | +| `domainFilters` | List of domains this external-dns instance can manage. | `[]string` | `[]` | +| `policy` | How DNS records are synchronized. | `string` | `upsert-only` | +| `extraArgs` | Extra arguments for external-dns. | `[]string` | `[]` | +| `gatewayAPI` | Enable Gateway API HTTPRoute as a source for DNS records. | `bool` | `false` | +| `annotationPrefix` | Custom annotation prefix for external-dns (useful for running multiple instances). | `string` | `""` | + + +### Cloudflare + +| Name | Description | Type | Value | +| ------------ | -------------------------------- | -------- | ----------------------------------------------------------- | +| `cloudflare` | Cloudflare provider credentials. | `object` | `{"apiEmail":"","apiKey":"","apiToken":"","proxied":false}` | + + +### AWS + +| Name | Description | Type | Value | +| ----- | --------------------------------- | -------- | ------------------------------------------------------------------- | +| `aws` | AWS Route53 provider credentials. | `object` | `{"accessKeyId":"","region":"","secretAccessKey":"","zoneType":""}` | + + +### Azure + +| Name | Description | Type | Value | +| ------- | ------------------------------- | -------- | ---------------------------------------------------------------------------------------------- | +| `azure` | Azure DNS provider credentials. | `object` | `{"aadClientId":"","aadClientSecret":"","resourceGroup":"","subscriptionId":"","tenantId":""}` | + + +### Google + +| Name | Description | Type | Value | +| -------- | -------------------------------------- | -------- | --------------------------------------- | +| `google` | Google Cloud DNS provider credentials. | `object` | `{"project":"","serviceAccountKey":""}` | + + +### DigitalOcean + +| Name | Description | Type | Value | +| -------------- | -------------------------------------- | -------- | -------------- | +| `digitalocean` | DigitalOcean DNS provider credentials. | `object` | `{"token":""}` | + + +### Linode + +| Name | Description | Type | Value | +| -------- | -------------------------------- | -------- | -------------- | +| `linode` | Linode DNS provider credentials. | `object` | `{"token":""}` | + + +### OVH + +| Name | Description | Type | Value | +| ----- | ----------------------------- | -------- | ----------------------------------------------------------------------------- | +| `ovh` | OVH DNS provider credentials. | `object` | `{"applicationKey":"","applicationSecret":"","consumerKey":"","endpoint":""}` | + + +### Exoscale + +| Name | Description | Type | Value | +| ---------- | ---------------------------------- | -------- | ------------------------------ | +| `exoscale` | Exoscale DNS provider credentials. | `object` | `{"apiKey":"","apiSecret":""}` | + + +### GoDaddy + +| Name | Description | Type | Value | +| --------- | --------------------------------- | -------- | ------------------------------ | +| `godaddy` | GoDaddy DNS provider credentials. | `object` | `{"apiKey":"","apiSecret":""}` | + + +### Resources + +| Name | Description | Type | Value | +| ------------------ | -------------------------------------------------------------------------------------------------------- | ---------- | ------ | +| `resources` | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `resources.cpu` | CPU available to each replica. | `quantity` | `""` | +| `resources.memory` | Memory (RAM) available to each replica. | `quantity` | `""` | +| `resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `nano` | + diff --git a/packages/extra/external-dns/charts/cozy-lib b/packages/extra/external-dns/charts/cozy-lib new file mode 120000 index 00000000..e1813509 --- /dev/null +++ b/packages/extra/external-dns/charts/cozy-lib @@ -0,0 +1 @@ +../../../library/cozy-lib \ No newline at end of file diff --git a/packages/extra/external-dns/config.json b/packages/extra/external-dns/config.json new file mode 100644 index 00000000..b2f956f3 --- /dev/null +++ b/packages/extra/external-dns/config.json @@ -0,0 +1,23 @@ +{ + "comments": { + "format": "##" + }, + "tags": { + "param": "@param", + "section": "@section", + "descriptionStart": "@descriptionStart", + "descriptionEnd": "@descriptionEnd", + "skip": "@skip", + "extra": "@extra" + }, + "modifiers": { + "array": "array", + "object": "object", + "string": "string", + "nullable": "nullable", + "default": "default" + }, + "regexp": { + "paramsSectionTitle": "Parameters" + } +} diff --git a/packages/extra/external-dns/logos/external-dns.svg b/packages/extra/external-dns/logos/external-dns.svg new file mode 100644 index 00000000..b22ad8c4 --- /dev/null +++ b/packages/extra/external-dns/logos/external-dns.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/packages/extra/external-dns/templates/dashboard-resourcemap.yaml b/packages/extra/external-dns/templates/dashboard-resourcemap.yaml new file mode 100644 index 00000000..edd96b74 --- /dev/null +++ b/packages/extra/external-dns/templates/dashboard-resourcemap.yaml @@ -0,0 +1,23 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ .Release.Name }}-dashboard-resources +rules: +- apiGroups: + - helm.toolkit.fluxcd.io + resources: + - helmreleases + resourceNames: + - {{ .Release.Name }} + verbs: ["get", "list", "watch"] +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Release.Name }}-dashboard-resources +subjects: +{{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "admin" .Release.Namespace) }} +roleRef: + kind: Role + name: {{ .Release.Name }}-dashboard-resources + apiGroup: rbac.authorization.k8s.io diff --git a/packages/extra/external-dns/templates/external-dns.yaml b/packages/extra/external-dns/templates/external-dns.yaml new file mode 100644 index 00000000..cdfb8901 --- /dev/null +++ b/packages/extra/external-dns/templates/external-dns.yaml @@ -0,0 +1,169 @@ +{{- if not .Values.provider }} +{{- fail "provider is required: set it to one of cloudflare, aws, azure, google, digitalocean, linode, ovh, exoscale, godaddy, inmemory" }} +{{- end }} +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: {{ .Release.Name }}-system + labels: + app.kubernetes.io/instance: {{ .Release.Name }}-system + app.kubernetes.io/managed-by: {{ .Release.Service }} +spec: + chartRef: + kind: ExternalArtifact + name: cozystack-external-dns-application-default-external-dns-system + namespace: cozy-system + interval: 5m + timeout: 10m + install: + remediation: + retries: -1 + upgrade: + force: true + remediation: + retries: -1 + values: + external-dns: + namespaced: true + txtOwnerId: {{ .Release.Namespace | quote }} + policy: {{ .Values.policy | quote }} + {{- if .Values.annotationPrefix }} + annotationPrefix: {{ .Values.annotationPrefix | quote }} + {{- end }} + provider: + name: {{ .Values.provider | quote }} + sources: + - ingress + - service + {{- if .Values.gatewayAPI }} + - gateway-httproute + {{- end }} + {{- with .Values.domainFilters }} + domainFilters: + {{- toYaml . | nindent 8 }} + {{- end }} + + {{- /* Provider-specific credentials and config */}} + + {{- if eq .Values.provider "cloudflare" }} + {{- if or .Values.cloudflare.apiToken (and .Values.cloudflare.apiKey .Values.cloudflare.apiEmail) }} + env: + {{- if .Values.cloudflare.apiToken }} + - name: CF_API_TOKEN + value: {{ .Values.cloudflare.apiToken | quote }} + {{- else }} + - name: CF_API_KEY + value: {{ .Values.cloudflare.apiKey | quote }} + - name: CF_API_EMAIL + value: {{ .Values.cloudflare.apiEmail | quote }} + {{- end }} + {{- end }} + {{- if .Values.cloudflare.proxied }} + cloudflare: + proxied: true + {{- end }} + {{- end }} + + {{- if eq .Values.provider "aws" }} + {{- if or .Values.aws.accessKeyId .Values.aws.secretAccessKey .Values.aws.region }} + env: + {{- if .Values.aws.accessKeyId }} + - name: AWS_ACCESS_KEY_ID + value: {{ .Values.aws.accessKeyId | quote }} + {{- end }} + {{- if .Values.aws.secretAccessKey }} + - name: AWS_SECRET_ACCESS_KEY + value: {{ .Values.aws.secretAccessKey | quote }} + {{- end }} + {{- if .Values.aws.region }} + - name: AWS_DEFAULT_REGION + value: {{ .Values.aws.region | quote }} + {{- end }} + {{- end }} + {{- if .Values.aws.zoneType }} + aws: + zoneType: {{ .Values.aws.zoneType | quote }} + {{- end }} + {{- end }} + + {{- if eq .Values.provider "azure" }} + {{- if or .Values.azure.tenantId .Values.azure.subscriptionId .Values.azure.resourceGroup .Values.azure.aadClientId .Values.azure.aadClientSecret }} + azure: + tenantId: {{ .Values.azure.tenantId | quote }} + subscriptionId: {{ .Values.azure.subscriptionId | quote }} + resourceGroup: {{ .Values.azure.resourceGroup | quote }} + aadClientId: {{ .Values.azure.aadClientId | quote }} + aadClientSecret: {{ .Values.azure.aadClientSecret | quote }} + {{- end }} + {{- end }} + + {{- if eq .Values.provider "digitalocean" }} + {{- if .Values.digitalocean.token }} + env: + - name: DO_TOKEN + value: {{ .Values.digitalocean.token | quote }} + {{- end }} + {{- end }} + + {{- if eq .Values.provider "google" }} + {{- if or .Values.google.project .Values.google.serviceAccountKey }} + google: + project: {{ .Values.google.project | quote }} + {{- if .Values.google.serviceAccountKey }} + serviceAccountKey: {{ .Values.google.serviceAccountKey | quote }} + {{- end }} + {{- end }} + {{- end }} + + {{- if eq .Values.provider "linode" }} + {{- if .Values.linode.token }} + env: + - name: LINODE_TOKEN + value: {{ .Values.linode.token | quote }} + {{- end }} + {{- end }} + + {{- if eq .Values.provider "ovh" }} + {{- if or .Values.ovh.endpoint .Values.ovh.applicationKey .Values.ovh.applicationSecret .Values.ovh.consumerKey }} + env: + - name: OVH_ENDPOINT + value: {{ .Values.ovh.endpoint | quote }} + - name: OVH_APPLICATION_KEY + value: {{ .Values.ovh.applicationKey | quote }} + - name: OVH_APPLICATION_SECRET + value: {{ .Values.ovh.applicationSecret | quote }} + - name: OVH_CONSUMER_KEY + value: {{ .Values.ovh.consumerKey | quote }} + {{- end }} + {{- end }} + + {{- if eq .Values.provider "exoscale" }} + {{- if or .Values.exoscale.apiKey .Values.exoscale.apiSecret }} + env: + - name: EXOSCALE_API_KEY + value: {{ .Values.exoscale.apiKey | quote }} + - name: EXOSCALE_API_SECRET + value: {{ .Values.exoscale.apiSecret | quote }} + {{- end }} + {{- end }} + + {{- /* extraArgs: merge user-supplied args with provider-specific args (godaddy) */}} + {{- $godaddyArgs := list }} + {{- if eq .Values.provider "godaddy" }} + {{- if .Values.godaddy.apiKey }} + {{- $godaddyArgs = append $godaddyArgs (printf "--godaddy-api-key=%s" .Values.godaddy.apiKey) }} + {{- end }} + {{- if .Values.godaddy.apiSecret }} + {{- $godaddyArgs = append $godaddyArgs (printf "--godaddy-api-secret=%s" .Values.godaddy.apiSecret) }} + {{- end }} + {{- end }} + {{- $allArgs := concat (.Values.extraArgs | default list) $godaddyArgs }} + {{- with $allArgs }} + extraArgs: + {{- toYaml . | nindent 8 }} + {{- end }} + + {{- with (include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $)) }} + resources: + {{- . | nindent 8 }} + {{- end }} diff --git a/packages/extra/external-dns/values.schema.json b/packages/extra/external-dns/values.schema.json new file mode 100644 index 00000000..08de0f8e --- /dev/null +++ b/packages/extra/external-dns/values.schema.json @@ -0,0 +1,193 @@ +{ + "title": "Chart Values", + "type": "object", + "properties": { + "provider": { + "description": "DNS provider name.", + "type": "string", + "enum": [ + "cloudflare", + "aws", + "azure", + "google", + "digitalocean", + "linode", + "ovh", + "exoscale", + "godaddy", + "inmemory" + ] + }, + "domainFilters": { + "description": "List of domains this external-dns instance can manage.", + "type": "array", + "default": [], + "items": { + "type": "string" + } + }, + "policy": { + "description": "How DNS records are synchronized.", + "type": "string", + "default": "upsert-only", + "enum": [ + "create-only", + "sync", + "upsert-only" + ] + }, + "extraArgs": { + "description": "Extra arguments for external-dns.", + "type": "array", + "default": [], + "items": { + "type": "string" + } + }, + "gatewayAPI": { + "description": "Enable Gateway API HTTPRoute as a source for DNS records.", + "type": "boolean", + "default": false + }, + "annotationPrefix": { + "description": "Custom annotation prefix for external-dns (useful for running multiple instances).", + "type": "string", + "default": "" + }, + "cloudflare": { + "description": "Cloudflare provider credentials.", + "type": "object", + "default": { + "apiEmail": "", + "apiKey": "", + "apiToken": "", + "proxied": false + }, + "x-kubernetes-preserve-unknown-fields": true + }, + "aws": { + "description": "AWS Route53 provider credentials.", + "type": "object", + "default": { + "accessKeyId": "", + "region": "", + "secretAccessKey": "", + "zoneType": "" + }, + "x-kubernetes-preserve-unknown-fields": true + }, + "azure": { + "description": "Azure DNS provider credentials.", + "type": "object", + "default": { + "aadClientId": "", + "aadClientSecret": "", + "resourceGroup": "", + "subscriptionId": "", + "tenantId": "" + }, + "x-kubernetes-preserve-unknown-fields": true + }, + "google": { + "description": "Google Cloud DNS provider credentials.", + "type": "object", + "default": { + "project": "", + "serviceAccountKey": "" + }, + "x-kubernetes-preserve-unknown-fields": true + }, + "digitalocean": { + "description": "DigitalOcean DNS provider credentials.", + "type": "object", + "default": { + "token": "" + }, + "x-kubernetes-preserve-unknown-fields": true + }, + "linode": { + "description": "Linode DNS provider credentials.", + "type": "object", + "default": { + "token": "" + }, + "x-kubernetes-preserve-unknown-fields": true + }, + "ovh": { + "description": "OVH DNS provider credentials.", + "type": "object", + "default": { + "applicationKey": "", + "applicationSecret": "", + "consumerKey": "", + "endpoint": "" + }, + "x-kubernetes-preserve-unknown-fields": true + }, + "exoscale": { + "description": "Exoscale DNS provider credentials.", + "type": "object", + "default": { + "apiKey": "", + "apiSecret": "" + }, + "x-kubernetes-preserve-unknown-fields": true + }, + "godaddy": { + "description": "GoDaddy DNS provider credentials.", + "type": "object", + "default": { + "apiKey": "", + "apiSecret": "" + }, + "x-kubernetes-preserve-unknown-fields": true + }, + "resources": { + "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "CPU available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Memory (RAM) available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted.", + "type": "string", + "default": "nano", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + } + } +} diff --git a/packages/extra/external-dns/values.yaml b/packages/extra/external-dns/values.yaml new file mode 100644 index 00000000..c40d2dff --- /dev/null +++ b/packages/extra/external-dns/values.yaml @@ -0,0 +1,149 @@ +## +## @section Common parameters +## + +## @enum {string} Provider - DNS provider. +## @value cloudflare +## @value aws +## @value azure +## @value google +## @value digitalocean +## @value linode +## @value ovh +## @value exoscale +## @value godaddy +## @value inmemory + +## @param {Provider} provider - DNS provider name. +# provider: + +## @param {[]string} domainFilters - List of domains this external-dns instance can manage. +domainFilters: [] + +## @enum {string} Policy - How DNS records are synchronized. +## @value create-only +## @value sync +## @value upsert-only + +## @param {Policy} policy="upsert-only" - How DNS records are synchronized. +policy: "upsert-only" + +## @param {[]string} extraArgs - Extra arguments for external-dns. +extraArgs: [] + +## @param {bool} gatewayAPI=false - Enable Gateway API HTTPRoute as a source for DNS records. +gatewayAPI: false + +## @param {string} [annotationPrefix] - Custom annotation prefix for external-dns (useful for running multiple instances). +annotationPrefix: "" + +## +## @section Cloudflare +## + +## @param {object} cloudflare - Cloudflare provider credentials. +cloudflare: + apiToken: "" + apiKey: "" + apiEmail: "" + proxied: false + +## +## @section AWS +## + +## @param {object} aws - AWS Route53 provider credentials. +aws: + accessKeyId: "" + secretAccessKey: "" + region: "" + zoneType: "" + +## +## @section Azure +## + +## @param {object} azure - Azure DNS provider credentials. +azure: + tenantId: "" + subscriptionId: "" + resourceGroup: "" + aadClientId: "" + aadClientSecret: "" + +## +## @section Google +## + +## @param {object} google - Google Cloud DNS provider credentials. +google: + project: "" + serviceAccountKey: "" + +## +## @section DigitalOcean +## + +## @param {object} digitalocean - DigitalOcean DNS provider credentials. +digitalocean: + token: "" + +## +## @section Linode +## + +## @param {object} linode - Linode DNS provider credentials. +linode: + token: "" + +## +## @section OVH +## + +## @param {object} ovh - OVH DNS provider credentials. +ovh: + endpoint: "" + applicationKey: "" + applicationSecret: "" + consumerKey: "" + +## +## @section Exoscale +## + +## @param {object} exoscale - Exoscale DNS provider credentials. +exoscale: + apiKey: "" + apiSecret: "" + +## +## @section GoDaddy +## + +## @param {object} godaddy - GoDaddy DNS provider credentials. +godaddy: + apiKey: "" + apiSecret: "" + +## +## @section Resources +## + +## @typedef {struct} Resources - Explicit CPU and memory configuration. +## @field {quantity} [cpu] - CPU available to each replica. +## @field {quantity} [memory] - Memory (RAM) available to each replica. + +## @enum {string} ResourcesPreset - Default sizing preset. +## @value nano +## @value micro +## @value small +## @value medium +## @value large +## @value xlarge +## @value 2xlarge + +## @param {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. +resources: {} + +## @param {ResourcesPreset} resourcesPreset="nano" - Default sizing preset used when `resources` is omitted. +resourcesPreset: "nano" diff --git a/packages/extra/info/Chart.yaml b/packages/extra/info/Chart.yaml index 6ba3ac46..ad222011 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.1.0 +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/extra/info/Makefile b/packages/extra/info/Makefile index 86ce0ede..02e04d53 100644 --- a/packages/extra/info/Makefile +++ b/packages/extra/info/Makefile @@ -1,3 +1,8 @@ NAME=etcd -include ../../../scripts/package.mk +include ../../../hack/package.mk + +generate: + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md + yq -o json -i '.properties = {}' values.schema.json + ../../../hack/update-crd.sh diff --git a/packages/extra/info/README.md b/packages/extra/info/README.md index e361cfe6..5a1cabe2 100644 --- a/packages/extra/info/README.md +++ b/packages/extra/info/README.md @@ -1,18 +1,3 @@ # Info -### Kubeconfig for tenant - -### Kubelogin - -For using kubeconfig need install kubelogin. - -```bash -# Homebrew (macOS and Linux) -brew install int128/kubelogin/kubelogin - -# Krew (macOS, Linux, Windows and ARM) -kubectl krew install oidc-login - -# Chocolatey (Windows) -choco install kubelogin -``` +## Parameters diff --git a/packages/extra/info/templates/dashboard-resourcemap.yaml b/packages/extra/info/templates/dashboard-resourcemap.yaml index 2fe68df1..aa8b7641 100644 --- a/packages/extra/info/templates/dashboard-resourcemap.yaml +++ b/packages/extra/info/templates/dashboard-resourcemap.yaml @@ -1,3 +1,4 @@ +{{- $oidcEnabled := index .Values._cluster "oidc-enabled" }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: @@ -8,7 +9,11 @@ rules: resources: - secrets resourceNames: + {{- if eq $oidcEnabled "true" }} - kubeconfig-{{ .Release.Namespace }} + {{- else }} + - {{ .Release.Namespace }} + {{- end }} verbs: ["get", "list", "watch"] --- kind: RoleBinding @@ -16,7 +21,13 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: {{ .Release.Name }}-dashboard-resources subjects: +{{- if eq $oidcEnabled "true" }} {{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "view" .Release.Namespace) }} +{{- else }} +- kind: ServiceAccount + name: tenant-{{ .Release.Namespace }} + namespace: tenant-{{ .Release.Namespace }} +{{- end }} roleRef: kind: Role name: {{ .Release.Name }}-dashboard-resources diff --git a/packages/extra/info/templates/kubeconfig.yaml b/packages/extra/info/templates/kubeconfig.yaml index d960a587..d2331654 100644 --- a/packages/extra/info/templates/kubeconfig.yaml +++ b/packages/extra/info/templates/kubeconfig.yaml @@ -1,23 +1,18 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- $k8sClientSecret := lookup "v1" "Secret" "cozy-keycloak" "k8s-client" }} - -{{- if $k8sClientSecret }} -{{- $apiServerEndpoint := index $cozyConfig.data "api-server-endpoint" }} -{{- $managementKubeconfigEndpoint := default "" (get $cozyConfig.data "management-kubeconfig-endpoint") }} -{{- if and $managementKubeconfigEndpoint (ne $managementKubeconfigEndpoint "") }} -{{- $apiServerEndpoint = $managementKubeconfigEndpoint }} -{{- end }} -{{- $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 }} +{{- $host := .Values._namespace.host | default (index .Values._cluster "root-host") }} +{{- $oidcEnabled := index .Values._cluster "oidc-enabled" }} +{{- if $oidcEnabled }} +{{- $apiServerEndpoint := index .Values._cluster "api-server-endpoint" }} +{{- $managementKubeconfigEndpoint := default "" (index .Values._cluster "management-kubeconfig-endpoint") }} +{{- if and $managementKubeconfigEndpoint (ne $managementKubeconfigEndpoint "") }} +{{- $apiServerEndpoint = $managementKubeconfigEndpoint }} +{{- end }} +{{- $k8sCa := index .Values._cluster "kube-root-ca" }} +{{- 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 @@ -48,7 +43,6 @@ stringData: - get-token - --oidc-issuer-url=https://keycloak.{{ $host }}/realms/cozy - --oidc-client-id=kubernetes - - --oidc-client-secret={{ $k8sClient }} - --skip-open-browser command: kubectl {{- end }} diff --git a/packages/extra/info/templates/serviceaccount.yaml b/packages/extra/info/templates/serviceaccount.yaml new file mode 100644 index 00000000..492f1b27 --- /dev/null +++ b/packages/extra/info/templates/serviceaccount.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Release.Namespace }} + annotations: + kubernetes.io/service-account.name: {{ .Release.Namespace }} +type: kubernetes.io/service-account-token diff --git a/packages/extra/info/values.schema.json b/packages/extra/info/values.schema.json index 0967ef42..167bc53e 100644 --- a/packages/extra/info/values.schema.json +++ b/packages/extra/info/values.schema.json @@ -1 +1,5 @@ -{} +{ + "title": "Chart Values", + "type": "object", + "properties": {} +} diff --git a/packages/extra/info/values.yaml b/packages/extra/info/values.yaml index e69de29b..0967ef42 100644 --- a/packages/extra/info/values.yaml +++ b/packages/extra/info/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/extra/ingress/Chart.yaml b/packages/extra/ingress/Chart.yaml index 289c931a..193d881d 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.7.0 +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/extra/ingress/Makefile b/packages/extra/ingress/Makefile index a1de94f4..65b53c03 100644 --- a/packages/extra/ingress/Makefile +++ b/packages/extra/ingress/Makefile @@ -1,6 +1,6 @@ NAME=ingress -include ../../../scripts/package.mk +include ../../../hack/package.mk update: get-cloudflare-ips @@ -8,4 +8,8 @@ get-cloudflare-ips: printf '{{- define "ingress.cloudflare-ips" -}}\n%s,%s\n{{- end }}\n' "$$(curl -s https://www.cloudflare.com/ips-v4/ | tr '\n' ,)" "$$(curl -s https://www.cloudflare.com/ips-v6/ | tr '\n' ,)" > templates/_cloudflare-ips.tpl generate: - readme-generator -v values.yaml -s values.schema.json -r README.md + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md + ../../../hack/update-crd.sh + +test: + helm unittest . diff --git a/packages/extra/ingress/README.md b/packages/extra/ingress/README.md index ab4ed3d9..c541d8e9 100644 --- a/packages/extra/ingress/README.md +++ b/packages/extra/ingress/README.md @@ -4,10 +4,27 @@ ### 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` | +| Name | Description | Type | Value | +| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------- | +| `replicas` | Number of ingress-nginx replicas. | `int` | `2` | +| `whitelist` | List of client networks. | `[]string` | `[]` | +| `cloudflareProxy` | Restoring original visitor IPs when Cloudflare proxied is enabled. | `bool` | `false` | +| `resources` | Explicit CPU and memory configuration for each ingress-nginx replica. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `resources.cpu` | CPU available to each replica. | `quantity` | `""` | +| `resources.memory` | Memory (RAM) available to each replica. | `quantity` | `""` | +| `resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `micro` | + + +## Exposure mode + +The ingress Service type is driven by the cluster-wide `publishing.exposure` value in the platform chart, not by any key in this package. Two modes exist: + +- `externalIPs` (default) has three rendered shapes: + - Release namespace matches `publishing.ingressName` AND `publishing.externalIPs` is non-empty → Service is `ClusterIP` with `Service.spec.externalIPs` set from that list and `externalTrafficPolicy: Cluster`. + - Release namespace matches `publishing.ingressName` but `publishing.externalIPs` is empty → Service falls back to `type: LoadBalancer` with `externalTrafficPolicy: Local`. + - Release namespace does not match `publishing.ingressName` (non-root tenants) → Service is `type: LoadBalancer` with `externalTrafficPolicy: Local`. + `Service.spec.externalIPs` is deprecated upstream in Kubernetes v1.36 (KEP-5707); plan migration before v1.40. +- `loadBalancer` — Service is `type: LoadBalancer` with `externalTrafficPolicy: Local`, and a `CiliumLoadBalancerIPPool` makes the addresses in `publishing.externalIPs` allocatable via Cilium LB IPAM. Requires `publishing.externalIPs` to contain at least one non-empty address (render fails otherwise) and assumes the addresses are already routed to a cluster node (floating IP / upstream router). See the inline comment on `publishing.exposure` in the platform chart for full caveats, including the note that switching the value on a running cluster causes the ingress Service to be recreated. + +This setting only migrates ingress-nginx away from `Service.spec.externalIPs`. Other cozystack components that use the same deprecated field (e.g. the `vpn` app) must be migrated separately before Kubernetes v1.40 flips the `AllowServiceExternalIPs` feature gate off. diff --git a/packages/extra/ingress/templates/nginx-ingress.yaml b/packages/extra/ingress/templates/nginx-ingress.yaml index 88d98b74..8e1f00fb 100644 --- a/packages/extra/ingress/templates/nginx-ingress.yaml +++ b/packages/extra/ingress/templates/nginx-ingress.yaml @@ -1,28 +1,49 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} -{{- $exposeExternalIPs := (index $cozyConfig.data "expose-external-ips") | default "" }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} +{{- $exposeExternalIPs := (index .Values._cluster "expose-external-ips") | default "" | nospace }} +{{- $exposeMode := (index .Values._cluster "expose-mode") | default "externalIPs" }} +{{- $exposeIPsList := list }} +{{- range splitList "," $exposeExternalIPs }} + {{- $ip := . | trim }} + {{- if $ip }} + {{- $exposeIPsList = append $exposeIPsList $ip }} + {{- end }} +{{- end }} +{{- if not (has $exposeMode (list "externalIPs" "loadBalancer")) }} +{{- fail (printf "unknown publishing.exposure mode %q: must be \"externalIPs\" or \"loadBalancer\"" $exposeMode) }} +{{- end }} +{{- if and (eq $exposeMode "loadBalancer") (eq $exposeIngress .Release.Namespace) (not $exposeIPsList) }} +{{- fail "publishing.exposure=loadBalancer requires publishing.externalIPs to contain at least one non-empty address: the CiliumLoadBalancerIPPool has nothing to advertise and the Service would stay in ." }} +{{- end }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: ingress-nginx-system + labels: + sharding.fluxcd.io/key: tenants spec: - chart: - spec: - chart: cozy-ingress-nginx - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' - interval: 1m0s - timeout: 5m0s + chartRef: + kind: ExternalArtifact + name: cozystack-ingress-application-default-ingress-system + namespace: cozy-system + interval: 5m + timeout: 10m + install: + remediation: + retries: -1 + upgrade: + force: true + remediation: + retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values values: ingress-nginx: fullnameOverride: {{ trimPrefix "tenant-" .Release.Namespace }}-ingress controller: replicaCount: {{ .Values.replicas }} ingressClass: {{ .Release.Namespace }} + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.resourcesPreset .Values.resources $) | nindent 10 }} ingressClassResource: name: {{ .Release.Namespace }} controllerValue: k8s.io/ingress-nginx-{{ .Release.Namespace }} @@ -34,21 +55,24 @@ spec: enabled: false {{- end }} service: - {{- if and (eq $exposeIngress .Release.Namespace) $exposeExternalIPs }} + {{- if and (eq $exposeIngress .Release.Namespace) (eq $exposeMode "loadBalancer") }} + type: LoadBalancer + externalTrafficPolicy: Local + {{- else if and (eq $exposeIngress .Release.Namespace) $exposeIPsList }} externalIPs: - {{- toYaml (splitList "," $exposeExternalIPs) | nindent 12 }} + {{- toYaml $exposeIPsList | nindent 12 }} type: ClusterIP externalTrafficPolicy: Cluster {{- else }} type: LoadBalancer externalTrafficPolicy: Local {{- end }} - {{- if or .Values.whitelist .Values.clouflareProxy }} + {{- if or .Values.whitelist .Values.cloudflareProxy }} config: {{- with .Values.whitelist }} whitelist-source-range: "{{ join "," . }}" {{- end }} - {{- if .Values.clouflareProxy }} + {{- if .Values.cloudflareProxy }} set_real_ip_from: "{{ include "ingress.cloudflare-ips" . }}" use-forwarded-headers: "true" server-snippet: "real_ip_header CF-Connecting-IP;" diff --git a/packages/extra/ingress/tests/exposure_test.yaml b/packages/extra/ingress/tests/exposure_test.yaml new file mode 100644 index 00000000..1c76b3da --- /dev/null +++ b/packages/extra/ingress/tests/exposure_test.yaml @@ -0,0 +1,165 @@ +suite: ingress exposure modes +templates: + - templates/nginx-ingress.yaml + +release: + name: ingress + namespace: tenant-root + +tests: + - it: default exposure (externalIPs) renders ClusterIP Service with spec.externalIPs + set: + _cluster: + expose-ingress: tenant-root + expose-external-ips: "192.0.2.10,192.0.2.11" + asserts: + - template: templates/nginx-ingress.yaml + equal: + path: spec.values.ingress-nginx.controller.service.type + value: ClusterIP + - template: templates/nginx-ingress.yaml + equal: + path: spec.values.ingress-nginx.controller.service.externalTrafficPolicy + value: Cluster + - template: templates/nginx-ingress.yaml + equal: + path: spec.values.ingress-nginx.controller.service.externalIPs + value: + - 192.0.2.10 + - 192.0.2.11 + - template: templates/nginx-ingress.yaml + notExists: + path: spec.values.ingress-nginx.controller.service.labels + + - it: legacy config without expose-mode falls back to externalIPs behavior + set: + _cluster: + expose-ingress: tenant-root + expose-external-ips: "192.0.2.10" + asserts: + - template: templates/nginx-ingress.yaml + equal: + path: spec.values.ingress-nginx.controller.service.type + value: ClusterIP + + - it: externalIPs mode in a namespace other than publishing.ingressName renders LoadBalancer fallback without externalIPs + set: + _cluster: + expose-ingress: tenant-root + expose-external-ips: "192.0.2.10" + release: + namespace: tenant-other + asserts: + - template: templates/nginx-ingress.yaml + equal: + path: spec.values.ingress-nginx.controller.service.type + value: LoadBalancer + - template: templates/nginx-ingress.yaml + equal: + path: spec.values.ingress-nginx.controller.service.externalTrafficPolicy + value: Local + - template: templates/nginx-ingress.yaml + notExists: + path: spec.values.ingress-nginx.controller.service.externalIPs + + - it: loadBalancer mode renders LoadBalancer Service without externalIPs on the Service + set: + _cluster: + expose-ingress: tenant-root + expose-external-ips: "192.0.2.10,192.0.2.11" + expose-mode: loadBalancer + asserts: + - template: templates/nginx-ingress.yaml + equal: + path: spec.values.ingress-nginx.controller.service.type + value: LoadBalancer + - template: templates/nginx-ingress.yaml + equal: + path: spec.values.ingress-nginx.controller.service.externalTrafficPolicy + value: Local + - template: templates/nginx-ingress.yaml + notExists: + path: spec.values.ingress-nginx.controller.service.labels + - template: templates/nginx-ingress.yaml + notExists: + path: spec.values.ingress-nginx.controller.service.externalIPs + + - it: loadBalancer mode without externalIPs fails chart render with explicit message + set: + _cluster: + expose-ingress: tenant-root + expose-external-ips: "" + expose-mode: loadBalancer + asserts: + - template: templates/nginx-ingress.yaml + failedTemplate: + errorMessage: "publishing.exposure=loadBalancer requires publishing.externalIPs to contain at least one non-empty address: the CiliumLoadBalancerIPPool has nothing to advertise and the Service would stay in ." + + - it: unknown exposure mode is rejected with a clear error (case-sensitive enum) + set: + _cluster: + expose-ingress: tenant-root + expose-external-ips: "192.0.2.10" + expose-mode: LoadBalancer + asserts: + - template: templates/nginx-ingress.yaml + failedTemplate: + errorMessage: "unknown publishing.exposure mode \"LoadBalancer\": must be \"externalIPs\" or \"loadBalancer\"" + + - it: another typo in exposure mode also fails + set: + _cluster: + expose-ingress: tenant-root + expose-external-ips: "192.0.2.10" + expose-mode: loadbalancer + asserts: + - template: templates/nginx-ingress.yaml + failedTemplate: + errorMessage: "unknown publishing.exposure mode \"loadbalancer\": must be \"externalIPs\" or \"loadBalancer\"" + + - it: loadBalancer mode in a namespace other than publishing.ingressName falls back to LoadBalancer Service without pool + set: + _cluster: + expose-ingress: tenant-root + expose-external-ips: "192.0.2.10" + expose-mode: loadBalancer + release: + namespace: tenant-other + asserts: + - template: templates/nginx-ingress.yaml + equal: + path: spec.values.ingress-nginx.controller.service.type + value: LoadBalancer + - template: templates/nginx-ingress.yaml + equal: + path: spec.values.ingress-nginx.controller.service.externalTrafficPolicy + value: Local + - template: templates/nginx-ingress.yaml + notExists: + path: spec.values.ingress-nginx.controller.service.labels + - template: templates/nginx-ingress.yaml + notExists: + path: spec.values.ingress-nginx.controller.service.externalIPs + + - it: loadBalancer mode with only-empty externalIPs fails chart render (comma-only input) + set: + _cluster: + expose-ingress: tenant-root + expose-external-ips: ",," + expose-mode: loadBalancer + asserts: + - template: templates/nginx-ingress.yaml + failedTemplate: + errorMessage: "publishing.exposure=loadBalancer requires publishing.externalIPs to contain at least one non-empty address: the CiliumLoadBalancerIPPool has nothing to advertise and the Service would stay in ." + + - it: externalIPs mode also filters out empty entries (trailing comma) + set: + _cluster: + expose-ingress: tenant-root + expose-external-ips: "192.0.2.10," + asserts: + - template: templates/nginx-ingress.yaml + equal: + path: spec.values.ingress-nginx.controller.service.externalIPs + value: + - 192.0.2.10 diff --git a/packages/extra/ingress/values.schema.json b/packages/extra/ingress/values.schema.json index c956bac3..7a53a197 100644 --- a/packages/extra/ingress/values.schema.json +++ b/packages/extra/ingress/values.schema.json @@ -1,30 +1,71 @@ { - "title": "Chart Values", - "type": "object", - "properties": { - "replicas": { - "type": "number", - "description": "Number of ingress-nginx replicas", - "default": 2 - }, - "externalIPs": { - "type": "array", - "description": "List of externalIPs for service.", - "default": "[]", - "items": { - "type": "string" + "title": "Chart Values", + "type": "object", + "properties": { + "replicas": { + "description": "Number of ingress-nginx replicas.", + "type": "integer", + "default": 2 + }, + "whitelist": { + "description": "List of client networks.", + "type": "array", + "default": [], + "items": { + "type": "string" + } + }, + "cloudflareProxy": { + "description": "Restoring original visitor IPs when Cloudflare proxied is enabled.", + "type": "boolean", + "default": false + }, + "resources": { + "description": "Explicit CPU and memory configuration for each ingress-nginx replica. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "CPU available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" } + ], + "x-kubernetes-int-or-string": true }, - "whitelist": { - "type": "array", - "description": "List of client networks", - "default": [], - "items": {} - }, - "clouflareProxy": { - "type": "boolean", - "description": "Restoring original visitor IPs when Cloudflare proxied is enabled", - "default": false + "memory": { + "description": "Memory (RAM) available to each replica.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted.", + "type": "string", + "default": "micro", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] } -} \ No newline at end of file + } +} diff --git a/packages/extra/ingress/values.yaml b/packages/extra/ingress/values.yaml index a5cee834..e1529a4e 100644 --- a/packages/extra/ingress/values.yaml +++ b/packages/extra/ingress/values.yaml @@ -1,15 +1,39 @@ -## @section Common parameters - -## @param replicas Number of ingress-nginx replicas ## +## @section Common parameters +## + +## @param {int} replicas - Number of ingress-nginx replicas. replicas: 2 -## @param whitelist List of client networks +## @param {[]string} whitelist - List of client networks. +whitelist: [] ## Example: ## whitelist: ## - "1.2.3.4" ## - "10.100.0.0/16" -whitelist: [] -## @param clouflareProxy Restoring original visitor IPs when Cloudflare proxied is enabled -clouflareProxy: false +## @param {bool} cloudflareProxy - Restoring original visitor IPs when Cloudflare proxied is enabled. +cloudflareProxy: false + +## @typedef {struct} Resources - Explicit CPU and memory configuration for each ingress-nginx replica. +## @field {quantity} [cpu] - CPU available to each replica. +## @field {quantity} [memory] - Memory (RAM) available to each replica. + +## @enum {string} ResourcesPreset - Default sizing preset. +## @value nano +## @value micro +## @value small +## @value medium +## @value large +## @value xlarge +## @value 2xlarge + +## @param {Resources} [resources] - Explicit CPU and memory configuration for each ingress-nginx replica. When omitted, the preset defined in `resourcesPreset` is applied. +resources: {} +## Example: +## resources: +## cpu: 4000m +## memory: 4Gi + +## @param {ResourcesPreset} resourcesPreset="micro" - Default sizing preset used when `resources` is omitted. +resourcesPreset: "micro" diff --git a/packages/extra/monitoring/Chart.yaml b/packages/extra/monitoring/Chart.yaml index ffc79ede..2db12ec5 100644 --- a/packages/extra/monitoring/Chart.yaml +++ b/packages/extra/monitoring/Chart.yaml @@ -3,4 +3,4 @@ name: monitoring description: Monitoring and observability stack icon: /logos/monitoring.svg type: application -version: 1.12.0 +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/extra/monitoring/Makefile b/packages/extra/monitoring/Makefile index e2b8d330..1ae213b6 100644 --- a/packages/extra/monitoring/Makefile +++ b/packages/extra/monitoring/Makefile @@ -2,28 +2,20 @@ GRAFANA_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml) NAME=monitoring -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk generate: - readme-generator -v values.yaml -s values.schema.json.tmp -r README.md - cat values.schema.json.tmp | \ - jq '.properties.metricsStorages.items.type = "object" | .properties.logsStorages.items.type = "object"' \ - > values.schema.json - rm -f values.schema.json.tmp + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md + ../../../hack/update-crd.sh image: 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 \ --metadata-file images/grafana.json \ - --push=$(PUSH) \ - --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ - --load=$(LOAD) + $(BUILDX_ARGS) echo "$(REGISTRY)/grafana:$(call settag,$(GRAFANA_TAG))@$$(yq e '."containerimage.digest"' images/grafana.json -o json -r)" \ > images/grafana.tag rm -f images/grafana.json diff --git a/packages/extra/monitoring/README.md b/packages/extra/monitoring/README.md index 1f9dd556..ed7df4f6 100644 --- a/packages/extra/monitoring/README.md +++ b/packages/extra/monitoring/README.md @@ -4,14 +4,100 @@ ### Common parameters -| Name | Description | Value | -| ----------------------------------------- | --------------------------------------------------------------------------------------------------------- | ------ | -| `host` | The hostname used to access the grafana externally (defaults to 'grafana' subdomain for the tenant host). | `""` | -| `metricsStorages` | Configuration of metrics storage instances | `[]` | -| `logsStorages` | Configuration of logs storage instances | `[]` | -| `alerta.storage` | Persistent Volume size for alerta database | `10Gi` | -| `alerta.storageClassName` | StorageClass used to store the data | `""` | -| `alerta.alerts.telegram.token` | telegram token for your bot | `""` | -| `alerta.alerts.telegram.chatID` | specify multiple ID's separated by comma. Get yours in https://t.me/chatid_echo_bot | `""` | -| `alerta.alerts.telegram.disabledSeverity` | list of severity without alerts, separated comma like: "informational,warning" | `""` | -| `grafana.db.size` | Persistent Volume size for grafana database | `10Gi` | +| Name | Description | Type | Value | +| ------ | ----------------------------------------------------------------------------------------------------- | -------- | ----- | +| `host` | The hostname used to access Grafana externally (defaults to 'grafana' subdomain for the tenant host). | `string` | `""` | + + +### Metrics storage configuration + +| Name | Description | Type | Value | +| ------------------------------------------------ | ------------------------------------------- | ---------- | ------- | +| `metricsStorages` | Configuration of metrics storage instances. | `[]object` | `[...]` | +| `metricsStorages[i].name` | Name of the storage instance. | `string` | `""` | +| `metricsStorages[i].retentionPeriod` | Retention period for metrics. | `string` | `""` | +| `metricsStorages[i].deduplicationInterval` | Deduplication interval for metrics. | `string` | `""` | +| `metricsStorages[i].storage` | Persistent volume size. | `string` | `10Gi` | +| `metricsStorages[i].storageClassName` | StorageClass used for the data. | `string` | `""` | +| `metricsStorages[i].vminsert` | Configuration for vminsert. | `object` | `{}` | +| `metricsStorages[i].vminsert.minAllowed` | Minimum guaranteed resources. | `object` | `{}` | +| `metricsStorages[i].vminsert.minAllowed.cpu` | CPU request. | `quantity` | `""` | +| `metricsStorages[i].vminsert.minAllowed.memory` | Memory request. | `quantity` | `""` | +| `metricsStorages[i].vminsert.maxAllowed` | Maximum allowed resources. | `object` | `{}` | +| `metricsStorages[i].vminsert.maxAllowed.cpu` | CPU limit. | `quantity` | `""` | +| `metricsStorages[i].vminsert.maxAllowed.memory` | Memory limit. | `quantity` | `""` | +| `metricsStorages[i].vmselect` | Configuration for vmselect. | `object` | `{}` | +| `metricsStorages[i].vmselect.minAllowed` | Minimum guaranteed resources. | `object` | `{}` | +| `metricsStorages[i].vmselect.minAllowed.cpu` | CPU request. | `quantity` | `""` | +| `metricsStorages[i].vmselect.minAllowed.memory` | Memory request. | `quantity` | `""` | +| `metricsStorages[i].vmselect.maxAllowed` | Maximum allowed resources. | `object` | `{}` | +| `metricsStorages[i].vmselect.maxAllowed.cpu` | CPU limit. | `quantity` | `""` | +| `metricsStorages[i].vmselect.maxAllowed.memory` | Memory limit. | `quantity` | `""` | +| `metricsStorages[i].vmstorage` | Configuration for vmstorage. | `object` | `{}` | +| `metricsStorages[i].vmstorage.minAllowed` | Minimum guaranteed resources. | `object` | `{}` | +| `metricsStorages[i].vmstorage.minAllowed.cpu` | CPU request. | `quantity` | `""` | +| `metricsStorages[i].vmstorage.minAllowed.memory` | Memory request. | `quantity` | `""` | +| `metricsStorages[i].vmstorage.maxAllowed` | Maximum allowed resources. | `object` | `{}` | +| `metricsStorages[i].vmstorage.maxAllowed.cpu` | CPU limit. | `quantity` | `""` | +| `metricsStorages[i].vmstorage.maxAllowed.memory` | Memory limit. | `quantity` | `""` | + + +### Logs storage configuration + +| Name | Description | Type | Value | +| ---------------------------------- | ---------------------------------------- | ---------- | ------------ | +| `logsStorages` | Configuration of logs storage instances. | `[]object` | `[...]` | +| `logsStorages[i].name` | Name of the storage instance. | `string` | `""` | +| `logsStorages[i].retentionPeriod` | Retention period for logs. | `string` | `1` | +| `logsStorages[i].storage` | Persistent volume size. | `string` | `10Gi` | +| `logsStorages[i].storageClassName` | StorageClass used to store the data. | `string` | `replicated` | + + +### Alerta configuration + +| Name | Description | Type | Value | +| ----------------------------------------- | --------------------------------------------------------------------- | ---------- | ------- | +| `alerta` | Configuration for the Alerta service. | `object` | `{}` | +| `alerta.storage` | Persistent volume size for the database. | `string` | `10Gi` | +| `alerta.storageClassName` | StorageClass used for the database. | `string` | `""` | +| `alerta.resources` | Resource configuration. | `object` | `{}` | +| `alerta.resources.requests` | Resource requests. | `object` | `{}` | +| `alerta.resources.requests.cpu` | CPU request. | `quantity` | `100m` | +| `alerta.resources.requests.memory` | Memory request. | `quantity` | `256Mi` | +| `alerta.resources.limits` | Resource limits. | `object` | `{}` | +| `alerta.resources.limits.cpu` | CPU limit. | `quantity` | `1` | +| `alerta.resources.limits.memory` | Memory limit. | `quantity` | `1Gi` | +| `alerta.alerts` | Alert routing configuration. | `object` | `{}` | +| `alerta.alerts.telegram` | Configuration for Telegram alerts. | `object` | `{}` | +| `alerta.alerts.telegram.token` | Telegram bot token. | `string` | `""` | +| `alerta.alerts.telegram.chatID` | Telegram chat ID(s), separated by commas. | `string` | `""` | +| `alerta.alerts.telegram.disabledSeverity` | List of severities without alerts (e.g. ["informational","warning"]). | `[]string` | `[]` | +| `alerta.alerts.slack` | Configuration for Slack alerts. | `object` | `{}` | +| `alerta.alerts.slack.url` | Configuration uri for Slack alerts. | `string` | `""` | +| `alerta.alerts.slack.disabledSeverity` | List of severities without alerts (e.g. ["informational","warning"]). | `[]string` | `[]` | + + +### Grafana configuration + +| Name | Description | Type | Value | +| ----------------------------------- | ---------------------------------------- | ---------- | ------- | +| `grafana` | Configuration for Grafana. | `object` | `{}` | +| `grafana.db` | Database configuration. | `object` | `{}` | +| `grafana.db.size` | Persistent volume size for the database. | `string` | `10Gi` | +| `grafana.resources` | Resource configuration. | `object` | `{}` | +| `grafana.resources.requests` | Resource requests. | `object` | `{}` | +| `grafana.resources.requests.cpu` | CPU request. | `quantity` | `100m` | +| `grafana.resources.requests.memory` | Memory request. | `quantity` | `256Mi` | +| `grafana.resources.limits` | Resource limits. | `object` | `{}` | +| `grafana.resources.limits.cpu` | CPU limit. | `quantity` | `1` | +| `grafana.resources.limits.memory` | Memory limit. | `quantity` | `1Gi` | + + +### Vmagent configuration + +| Name | Description | Type | Value | +| ------------------------ | ---------------------------------------- | -------- | ----- | +| `vmagent` | Configuration for VictoriaMetrics Agent. | `object` | `{}` | +| `vmagent.externalLabels` | External labels applied to all metrics. | `object` | `{}` | +| `vmagent.remoteWrite` | Remote write configuration. | `object` | `{}` | + diff --git a/packages/extra/monitoring/images/grafana.tag b/packages/extra/monitoring/images/grafana.tag deleted file mode 100644 index 5bc2f99a..00000000 --- a/packages/extra/monitoring/images/grafana.tag +++ /dev/null @@ -1 +0,0 @@ -ghcr.io/cozystack/cozystack/grafana:1.12.0@sha256:c63978e1ed0304e8518b31ddee56c4e8115541b997d8efbe1c0a74da57140399 diff --git a/packages/extra/monitoring/templates/dashboard-resourcemap.yaml b/packages/extra/monitoring/templates/dashboard-resourcemap.yaml index 894a11d4..5a5a3def 100644 --- a/packages/extra/monitoring/templates/dashboard-resourcemap.yaml +++ b/packages/extra/monitoring/templates/dashboard-resourcemap.yaml @@ -42,7 +42,9 @@ rules: - {{ .name }}-vminsert {{- end }} {{- range .Values.logsStorages }} - - {{ $.Release.Name }}-vlogs-{{ .name }} + - {{ .name }}-vlstorage + - {{ .name }}-vlselect + - {{ .name }}-vlinsert {{- end }} {{- range .Values.metricsStorages }} - vmalert-{{ .name }} diff --git a/packages/extra/monitoring/templates/dashboards.yaml b/packages/extra/monitoring/templates/dashboards.yaml deleted file mode 100644 index 3facf66c..00000000 --- a/packages/extra/monitoring/templates/dashboards.yaml +++ /dev/null @@ -1,16 +0,0 @@ -{{- range (split "\n" (.Files.Get "dashboards.list")) }} -{{- $parts := split "/" . }} -{{- if eq (len $parts) 2 }} ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaDashboard -metadata: - name: {{ $parts._0 }}-{{ $parts._1 }} -spec: - folder: {{ $parts._0 }} - instanceSelector: - matchLabels: - dashboards: grafana - url: http://cozystack.cozy-system.svc/dashboards/{{ . }}.json -{{- end }} -{{- end }} diff --git a/packages/extra/monitoring/templates/grafana/db.yaml b/packages/extra/monitoring/templates/grafana/db.yaml deleted file mode 100644 index f1781cff..00000000 --- a/packages/extra/monitoring/templates/grafana/db.yaml +++ /dev/null @@ -1,44 +0,0 @@ -apiVersion: postgresql.cnpg.io/v1 -kind: Cluster -metadata: - name: grafana-db -spec: - instances: 2 - storage: - size: {{ .Values.grafana.db.size }} - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- if $configMap }} - {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }} - {{- if $rawConstraints }} - {{- $rawConstraints | fromYaml | toYaml | nindent 2 }} - labelSelector: - matchLabels: - cnpg.io/cluster: grafana-db - {{- end }} - {{- end }} - monitoring: - enablePodMonitor: true - resources: - limits: - cpu: "1" - memory: 2048Mi - requests: - cpu: 100m - memory: 512Mi - inheritedMetadata: - labels: - policy.cozystack.io/allow-to-apiserver: "true" ---- -apiVersion: cozystack.io/v1alpha1 -kind: WorkloadMonitor -metadata: - name: grafana-db -spec: - replicas: 2 - minReplicas: 1 - kind: monitoring - type: postgres - selector: - cnpg.io/cluster: grafana-db - cnpg.io/podRole: instance - version: {{ $.Chart.Version }} diff --git a/packages/extra/monitoring/templates/helmrelease.yaml b/packages/extra/monitoring/templates/helmrelease.yaml new file mode 100644 index 00000000..0c3c2377 --- /dev/null +++ b/packages/extra/monitoring/templates/helmrelease.yaml @@ -0,0 +1,24 @@ +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: {{ .Release.Name }}-system + labels: + sharding.fluxcd.io/key: tenants +spec: + chartRef: + kind: ExternalArtifact + name: cozystack-monitoring-application-default-monitoring-system + namespace: cozy-system + interval: 5m + timeout: 10m + install: + remediation: + retries: -1 + upgrade: + force: true + remediation: + retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values + values: {{- .Values | toYaml | nindent 4 }} diff --git a/packages/extra/monitoring/templates/vlogs/vlogs.yaml b/packages/extra/monitoring/templates/vlogs/vlogs.yaml deleted file mode 100644 index 08d8d82b..00000000 --- a/packages/extra/monitoring/templates/vlogs/vlogs.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{- range .Values.logsStorages }} -apiVersion: operator.victoriametrics.com/v1beta1 -kind: VLogs -metadata: - name: {{ .name }} -spec: - image: - tag: v1.17.0-victorialogs - storage: - resources: - requests: - storage: {{ .storage }} - storageClassName: {{ .storageClassName }} - accessModes: [ReadWriteOnce] - retentionPeriod: "{{ .retentionPeriod }}" - removePvcAfterDelete: true ---- -apiVersion: cozystack.io/v1alpha1 -kind: WorkloadMonitor -metadata: - name: vlogs-{{ .name }} -spec: - replicas: 1 - minReplicas: 1 - kind: monitoring - type: vlogs - selector: - app.kubernetes.io/component: monitoring - app.kubernetes.io/instance: {{ .name }} - app.kubernetes.io/name: vlogs - version: {{ $.Chart.Version }} -{{- end }} diff --git a/packages/extra/monitoring/templates/workloadmonitors.yaml b/packages/extra/monitoring/templates/workloadmonitors.yaml new file mode 100644 index 00000000..5d803351 --- /dev/null +++ b/packages/extra/monitoring/templates/workloadmonitors.yaml @@ -0,0 +1,180 @@ +{{- range .Values.metricsStorages }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: {{ .name }}-vmstorage +spec: + replicas: 2 + minReplicas: 1 + kind: monitoring + type: vmstorage + selector: + app.kubernetes.io/component: monitoring + app.kubernetes.io/instance: {{ .name }} + app.kubernetes.io/name: vmstorage + version: {{ $.Chart.Version }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: {{ .name }}-vmselect +spec: + replicas: 2 + minReplicas: 1 + kind: monitoring + type: vmselect + selector: + app.kubernetes.io/component: monitoring + app.kubernetes.io/instance: {{ .name }} + app.kubernetes.io/name: vmselect + version: {{ $.Chart.Version }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: {{ .name }}-vminsert +spec: + replicas: 2 + minReplicas: 1 + kind: monitoring + type: vminsert + selector: + app.kubernetes.io/component: monitoring + app.kubernetes.io/instance: {{ .name }} + app.kubernetes.io/name: vminsert + version: {{ $.Chart.Version }} +{{- end }} +{{- range .Values.metricsStorages }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: vmalert-{{ .name }} +spec: + replicas: 1 + minReplicas: 1 + kind: monitoring + type: vmalert + selector: + app.kubernetes.io/instance: vmalert-{{ .name }} + app.kubernetes.io/name: vmalert + version: {{ $.Chart.Version }} +{{- break }} +{{- end }} +{{- range .Values.logsStorages }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: {{ .name }}-vlstorage +spec: + replicas: 2 + minReplicas: 1 + kind: monitoring + type: vlstorage + selector: + app.kubernetes.io/component: monitoring + app.kubernetes.io/instance: {{ .name }} + app.kubernetes.io/name: vlstorage + version: {{ $.Chart.Version }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: {{ .name }}-vlselect +spec: + replicas: 2 + minReplicas: 1 + kind: monitoring + type: vlselect + selector: + app.kubernetes.io/component: monitoring + app.kubernetes.io/instance: {{ .name }} + app.kubernetes.io/name: vlselect + version: {{ $.Chart.Version }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: {{ .name }}-vlinsert +spec: + replicas: 2 + minReplicas: 1 + kind: monitoring + type: vlinsert + selector: + app.kubernetes.io/component: monitoring + app.kubernetes.io/instance: {{ .name }} + app.kubernetes.io/name: vlinsert + version: {{ $.Chart.Version }} +{{- end }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: grafana +spec: + replicas: 2 + minReplicas: 1 + kind: monitoring + type: grafana + selector: + app: grafana + version: {{ $.Chart.Version }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: grafana-db +spec: + replicas: 2 + minReplicas: 1 + kind: monitoring + type: postgres + selector: + cnpg.io/cluster: grafana-db + cnpg.io/podRole: instance + version: {{ $.Chart.Version }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: alerta-db +spec: + replicas: 2 + minReplicas: 1 + kind: monitoring + type: postgres + selector: + cnpg.io/cluster: alerta-db + cnpg.io/podRole: instance + version: {{ $.Chart.Version }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: alerta +spec: + replicas: 1 + minReplicas: 1 + kind: monitoring + type: alerta + selector: + app: alerta + release: alerta + version: {{ $.Chart.Version }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: alertmanager +spec: + replicas: 3 + minReplicas: 2 + kind: monitoring + type: alertmanager + selector: + app.kubernetes.io/instance: alertmanager + app.kubernetes.io/name: vmalertmanager + version: {{ $.Chart.Version }} diff --git a/packages/extra/monitoring/values.schema.json b/packages/extra/monitoring/values.schema.json index 4adf1de6..4bc6906e 100644 --- a/packages/extra/monitoring/values.schema.json +++ b/packages/extra/monitoring/values.schema.json @@ -3,59 +3,277 @@ "type": "object", "properties": { "host": { + "description": "The hostname used to access Grafana externally (defaults to 'grafana' subdomain for the tenant host).", "type": "string", - "description": "The hostname used to access the grafana externally (defaults to 'grafana' subdomain for the tenant host).", "default": "" }, "metricsStorages": { + "description": "Configuration of metrics storage instances.", "type": "array", - "description": "Configuration of metrics storage instances", - "default": "[]", - "items": { - "type": "object" - } - }, - "logsStorages": { - "type": "array", - "description": "Configuration of logs storage instances", - "default": "[]", - "items": { - "type": "object" - } - }, - "alerta": { - "type": "object", - "properties": { - "storage": { - "type": "string", - "description": "Persistent Volume size for alerta database", - "default": "10Gi" + "default": [ + { + "deduplicationInterval": "15s", + "name": "shortterm", + "retentionPeriod": "3d", + "storage": "10Gi", + "storageClassName": "" }, - "storageClassName": { - "type": "string", - "description": "StorageClass used to store the data", - "default": "" - }, - "alerts": { - "type": "object", - "properties": { - "telegram": { - "type": "object", - "properties": { - "token": { - "type": "string", - "description": "telegram token for your bot", - "default": "" - }, - "chatID": { - "type": "string", - "description": "specify multiple ID's separated by comma. Get yours in https://t.me/chatid_echo_bot", - "default": "" - }, - "disabledSeverity": { - "type": "string", - "description": "list of severity without alerts, separated comma like: \"informational,warning\"", - "default": "" + { + "deduplicationInterval": "5m", + "name": "longterm", + "retentionPeriod": "14d", + "storage": "10Gi", + "storageClassName": "" + } + ], + "items": { + "type": "object", + "required": [ + "deduplicationInterval", + "name", + "retentionPeriod", + "storage" + ], + "properties": { + "deduplicationInterval": { + "description": "Deduplication interval for metrics.", + "type": "string" + }, + "name": { + "description": "Name of the storage instance.", + "type": "string" + }, + "retentionPeriod": { + "description": "Retention period for metrics.", + "type": "string" + }, + "storage": { + "description": "Persistent volume size.", + "type": "string", + "default": "10Gi" + }, + "storageClassName": { + "description": "StorageClass used for the data.", + "type": "string" + }, + "vminsert": { + "description": "Configuration for vminsert.", + "type": "object", + "properties": { + "maxAllowed": { + "description": "Maximum allowed resources.", + "type": "object", + "properties": { + "cpu": { + "description": "CPU limit.", + "default": 1, + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Memory limit.", + "default": "1Gi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "minAllowed": { + "description": "Minimum guaranteed resources.", + "type": "object", + "properties": { + "cpu": { + "description": "CPU request.", + "default": "100m", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Memory request.", + "default": "256Mi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + } + } + }, + "vmselect": { + "description": "Configuration for vmselect.", + "type": "object", + "properties": { + "maxAllowed": { + "description": "Maximum allowed resources.", + "type": "object", + "properties": { + "cpu": { + "description": "CPU limit.", + "default": 1, + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Memory limit.", + "default": "1Gi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "minAllowed": { + "description": "Minimum guaranteed resources.", + "type": "object", + "properties": { + "cpu": { + "description": "CPU request.", + "default": "100m", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Memory request.", + "default": "256Mi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + } + } + }, + "vmstorage": { + "description": "Configuration for vmstorage.", + "type": "object", + "properties": { + "maxAllowed": { + "description": "Maximum allowed resources.", + "type": "object", + "properties": { + "cpu": { + "description": "CPU limit.", + "default": 1, + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Memory limit.", + "default": "1Gi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "minAllowed": { + "description": "Minimum guaranteed resources.", + "type": "object", + "properties": { + "cpu": { + "description": "CPU request.", + "default": "100m", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Memory request.", + "default": "256Mi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } } } } @@ -63,18 +281,318 @@ } } }, - "grafana": { + "logsStorages": { + "description": "Configuration of logs storage instances.", + "type": "array", + "default": [ + { + "name": "generic", + "retentionPeriod": "1", + "storage": "10Gi", + "storageClassName": "replicated" + } + ], + "items": { + "type": "object", + "required": [ + "name", + "retentionPeriod", + "storage", + "storageClassName" + ], + "properties": { + "name": { + "description": "Name of the storage instance.", + "type": "string" + }, + "retentionPeriod": { + "description": "Retention period for logs.", + "type": "string", + "default": "1" + }, + "storage": { + "description": "Persistent volume size.", + "type": "string", + "default": "10Gi" + }, + "storageClassName": { + "description": "StorageClass used to store the data.", + "type": "string", + "default": "replicated" + } + } + } + }, + "alerta": { + "description": "Configuration for the Alerta service.", "type": "object", + "default": {}, + "properties": { + "alerts": { + "description": "Alert routing configuration.", + "type": "object", + "default": {}, + "properties": { + "slack": { + "description": "Configuration for Slack alerts.", + "type": "object", + "default": {}, + "required": [ + "url" + ], + "properties": { + "disabledSeverity": { + "description": "List of severities without alerts (e.g. [\"informational\",\"warning\"]).", + "type": "array", + "default": [], + "items": { + "type": "string" + } + }, + "url": { + "description": "Configuration uri for Slack alerts.", + "type": "string", + "default": "" + } + } + }, + "telegram": { + "description": "Configuration for Telegram alerts.", + "type": "object", + "default": {}, + "required": [ + "chatID", + "token" + ], + "properties": { + "chatID": { + "description": "Telegram chat ID(s), separated by commas.", + "type": "string", + "default": "" + }, + "disabledSeverity": { + "description": "List of severities without alerts (e.g. [\"informational\",\"warning\"]).", + "type": "array", + "default": [], + "items": { + "type": "string" + } + }, + "token": { + "description": "Telegram bot token.", + "type": "string", + "default": "" + } + } + } + } + }, + "resources": { + "description": "Resource configuration.", + "type": "object", + "default": {}, + "properties": { + "limits": { + "description": "Resource limits.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "CPU limit.", + "default": 1, + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Memory limit.", + "default": "1Gi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "requests": { + "description": "Resource requests.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "CPU request.", + "default": "100m", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Memory request.", + "default": "256Mi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + } + } + }, + "storage": { + "description": "Persistent volume size for the database.", + "type": "string", + "default": "10Gi" + }, + "storageClassName": { + "description": "StorageClass used for the database.", + "type": "string", + "default": "" + } + } + }, + "grafana": { + "description": "Configuration for Grafana.", + "type": "object", + "default": {}, "properties": { "db": { + "description": "Database configuration.", "type": "object", + "default": {}, "properties": { "size": { + "description": "Persistent volume size for the database.", "type": "string", - "description": "Persistent Volume size for grafana database", "default": "10Gi" } } + }, + "resources": { + "description": "Resource configuration.", + "type": "object", + "default": {}, + "properties": { + "limits": { + "description": "Resource limits.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "CPU limit.", + "default": 1, + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Memory limit.", + "default": "1Gi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "requests": { + "description": "Resource requests.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "CPU request.", + "default": "100m", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Memory request.", + "default": "256Mi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + } + } + } + } + }, + "vmagent": { + "description": "Configuration for VictoriaMetrics Agent.", + "type": "object", + "default": {}, + "properties": { + "externalLabels": { + "description": "External labels applied to all metrics.", + "type": "object", + "default": { + "cluster": "cozystack" + } + }, + "remoteWrite": { + "description": "Remote write configuration.", + "type": "object", + "default": { + "urls": [ + "http://vminsert-shortterm:8480/insert/0/prometheus", + "http://vminsert-longterm:8480/insert/0/prometheus" + ] + } } } } diff --git a/packages/extra/monitoring/values.yaml b/packages/extra/monitoring/values.yaml index c359df3a..c521f389 100644 --- a/packages/extra/monitoring/values.yaml +++ b/packages/extra/monitoring/values.yaml @@ -1,10 +1,41 @@ ## @section Common parameters +## -## @param host The hostname used to access the grafana externally (defaults to 'grafana' subdomain for the tenant host). +## @param {string} host - The hostname used to access Grafana externally (defaults to 'grafana' subdomain for the tenant host). host: "" -## @param metricsStorages [array] Configuration of metrics storage instances ## +## @section Metrics storage configuration +## + +## @typedef {struct} Request - Minimum guaranteed resources. +## @field {quantity} [cpu] - CPU request. +## @field {quantity} [memory] - Memory request. + +## @typedef {struct} Limit - Maximum allowed resources. +## @field {quantity} [cpu] - CPU limit. +## @field {quantity} [memory] - Memory limit. + +## @typedef {struct} VMComponent - VictoriaMetrics component configuration. +## @field {Request} [minAllowed] - Minimum guaranteed resources. +## @field {Limit} [maxAllowed] - Maximum allowed resources. + +## @typedef {struct} Resources - Combined resource configuration. +## @field {Request} [requests] - Resource requests. +## @field {Limit} [limits] - Resource limits. + +## @typedef {struct} MetricsStorage - Configuration of metrics storage instance. +## @field {string} name - Name of the storage instance. +## @field {string} retentionPeriod - Retention period for metrics. +## @field {string} deduplicationInterval - Deduplication interval for metrics. +## @field {string} storage="10Gi" - Persistent volume size. +## @field {string} [storageClassName] - StorageClass used for the data. +## @field {VMComponent} [vminsert] - Configuration for vminsert. +## @field {VMComponent} [vmselect] - Configuration for vmselect. +## @field {VMComponent} [vmstorage] - Configuration for vmstorage. + +## @param {[]MetricsStorage} metricsStorages - Configuration of metrics storage instances. +metricsStorages: ## Example: ## metricsStorages: ## - name: shortterm @@ -33,8 +64,6 @@ host: "" ## maxAllowed: ## cpu: 4000m ## memory: 8Gi -## -metricsStorages: - name: shortterm retentionPeriod: "3d" deduplicationInterval: "15s" @@ -46,18 +75,47 @@ metricsStorages: storage: 10Gi storageClassName: "" -## @param logsStorages [array] Configuration of logs storage instances ## +## @section Logs storage configuration +## + +## @typedef {struct} LogsStorage - Configuration of logs storage instance. +## @field {string} name - Name of the storage instance. +## @field {string} retentionPeriod="1" - Retention period for logs. +## @field {string} storage="10Gi" - Persistent volume size. +## @field {string} storageClassName="replicated" - StorageClass used to store the data. + +## @param {[]LogsStorage} logsStorages - Configuration of logs storage instances. logsStorages: - name: generic retentionPeriod: "1" storage: 10Gi storageClassName: replicated -## Configuration for Alerta -## @param alerta.storage Persistent Volume size for alerta database -## @param alerta.storageClassName StorageClass used to store the data ## +## @section Alerta configuration +## + +## @typedef {struct} TelegramAlerts - Telegram alert configuration. +## @field {string} token - Telegram bot token. +## @field {string} chatID - Telegram chat ID(s), separated by commas. +## @field {[]string} [disabledSeverity] - List of severities without alerts (e.g. ["informational","warning"]). + +## @typedef {struct} SlackAlerts - Slack alert configuration. +## @field {string} url - Configuration uri for Slack alerts. +## @field {[]string} [disabledSeverity] - List of severities without alerts (e.g. ["informational","warning"]). + +## @typedef {struct} Alerts - Alert routing configuration. +## @field {TelegramAlerts} [telegram] - Configuration for Telegram alerts. +## @field {SlackAlerts} [slack] - Configuration for Slack alerts. + +## @typedef {struct} Alerta - Configuration for the Alerta service. +## @field {string} [storage] - Persistent volume size for the database. +## @field {string} [storageClassName] - StorageClass used for the database. +## @field {Resources} [resources] - Resource configuration. +## @field {Alerts} [alerts] - Alert routing configuration. + +## @param {Alerta} alerta - Configuration for the Alerta service. alerta: storage: 10Gi storageClassName: "" @@ -69,22 +127,25 @@ alerta: cpu: 100m memory: 256Mi alerts: - ## @param alerta.alerts.telegram.token telegram token for your bot - ## @param alerta.alerts.telegram.chatID specify multiple ID's separated by comma. Get yours in https://t.me/chatid_echo_bot - ## @param alerta.alerts.telegram.disabledSeverity list of severity without alerts, separated comma like: "informational,warning" - ## example: - ## telegram: - ## token: "7262461387:AAGtwq16iwuVtWtzoN6TUEMpF00fpC9Xz34" - ## chatID: "-4520856007" - ## disabledSeverity: "informational,warning" - ## telegram: token: "" chatID: "" - disabledSeverity: "" + disabledSeverity: [] + slack: + url: "" + disabledSeverity: [] +## +## @section Grafana configuration +## -## Configuration for Grafana -## @param grafana.db.size Persistent Volume size for grafana database +## @typedef {struct} GrafanaDB - Grafana database configuration. +## @field {string} [size] - Persistent volume size for the database. + +## @typedef {struct} Grafana - Grafana service configuration. +## @field {GrafanaDB} [db] - Database configuration. +## @field {Resources} [resources] - Resource configuration. + +## @param {Grafana} grafana - Configuration for Grafana. grafana: db: size: 10Gi @@ -95,3 +156,29 @@ grafana: requests: cpu: 100m memory: 256Mi +## +## @section Vmagent configuration +## + +## @typedef {struct} VmagentRemoteWrite - Remote write configuration. +## @typedef {stringSlice} VmagentRemoteWriteURLs - List of remoteWrite endpoint URLs. + +## @typedef {struct} VmagentExternalLabels - External labels for metrics. +## @field {string} [] - Label value for the given key. + +## @typedef {struct} Vmagent - VictoriaMetrics Agent configuration. +## @field {VmagentExternalLabels} [externalLabels] - External labels applied to all metrics. +## @field {VmagentRemoteWrite} [remoteWrite] - Remote write configuration. + +## @param {Vmagent} vmagent - Configuration for VictoriaMetrics Agent. +vmagent: + externalLabels: + cluster: cozystack + remoteWrite: + urls: + - http://vminsert-shortterm:8480/insert/0/prometheus + - http://vminsert-longterm:8480/insert/0/prometheus + ## inlineScrapeConfig: | + ## - job_name: "custom" + ## static_configs: + ## - targets: ["my-service:9090"] diff --git a/packages/extra/seaweedfs/Chart.yaml b/packages/extra/seaweedfs/Chart.yaml index 233b0c8b..03754568 100644 --- a/packages/extra/seaweedfs/Chart.yaml +++ b/packages/extra/seaweedfs/Chart.yaml @@ -2,24 +2,6 @@ apiVersion: v2 name: seaweedfs description: Seaweedfs icon: /logos/seaweedfs.svg - -# 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: 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 - -# 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. +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process appVersion: "3.71" diff --git a/packages/extra/seaweedfs/Makefile b/packages/extra/seaweedfs/Makefile index bc02a298..eaa1b906 100644 --- a/packages/extra/seaweedfs/Makefile +++ b/packages/extra/seaweedfs/Makefile @@ -1,6 +1,7 @@ NAME=seaweedfs -include ../../../scripts/package.mk +include ../../../hack/package.mk generate: - readme-generator -v values.yaml -s values.schema.json -r README.md + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md + ../../../hack/update-crd.sh diff --git a/packages/extra/seaweedfs/README.md b/packages/extra/seaweedfs/README.md index 557c1e00..62bb9bf2 100644 --- a/packages/extra/seaweedfs/README.md +++ b/packages/extra/seaweedfs/README.md @@ -1,13 +1,80 @@ -# Managed NATS Service +# Managed SeaweedFS Service ## Parameters ### Common parameters -| Name | Description | Value | -| -------------- | --------------------------------------------------------------------------------------------------------- | ------ | -| `host` | The hostname used to access the grafana externally (defaults to 'grafana' subdomain for the tenant host). | `""` | -| `replicas` | Persistent Volume size for NATS | `2` | -| `size` | Persistent Volume size | `10Gi` | -| `storageClass` | StorageClass used to store the data | `""` | +| Name | Description | Type | Value | +| ------------------- | -------------------------------------------------------------------------------------------------- | -------- | -------- | +| `host` | The hostname used to access SeaweedFS externally (defaults to 's3' subdomain for the tenant host). | `string` | `""` | +| `topology` | The topology of the SeaweedFS cluster. | `string` | `Simple` | +| `replicationFactor` | Replication factor: number of replicas for each volume in the SeaweedFS cluster. | `int` | `2` | + + +### SeaweedFS Components Configuration + +| Name | Description | Type | Value | +| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------- | ------- | +| `db` | Database configuration. | `object` | `{}` | +| `db.replicas` | Number of database replicas. | `int` | `2` | +| `db.size` | Persistent Volume size. | `quantity` | `10Gi` | +| `db.storageClass` | StorageClass used to store the data. | `string` | `""` | +| `db.resources` | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `db.resources.cpu` | Number of CPU cores allocated. | `quantity` | `""` | +| `db.resources.memory` | Amount of memory allocated. | `quantity` | `""` | +| `db.resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `small` | +| `master` | Master service configuration. | `object` | `{}` | +| `master.replicas` | Number of master replicas. | `int` | `3` | +| `master.resources` | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `master.resources.cpu` | Number of CPU cores allocated. | `quantity` | `""` | +| `master.resources.memory` | Amount of memory allocated. | `quantity` | `""` | +| `master.resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `small` | +| `filer` | Filer service configuration. | `object` | `{}` | +| `filer.replicas` | Number of filer replicas. | `int` | `2` | +| `filer.resources` | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `filer.resources.cpu` | Number of CPU cores allocated. | `quantity` | `""` | +| `filer.resources.memory` | Amount of memory allocated. | `quantity` | `""` | +| `filer.resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `small` | +| `filer.grpcHost` | The hostname used to expose or access the filer service externally. | `string` | `""` | +| `filer.grpcPort` | The port used to access the filer service externally. | `int` | `443` | +| `filer.whitelist` | A list of IP addresses or CIDR ranges that are allowed to access the filer service. | `[]string` | `[]` | +| `volume` | Volume service configuration. | `object` | `{}` | +| `volume.replicas` | Number of volume replicas. | `int` | `2` | +| `volume.size` | Persistent Volume size. | `quantity` | `10Gi` | +| `volume.storageClass` | StorageClass used to store the data. | `string` | `""` | +| `volume.diskType` | SeaweedFS disk type tag for the default volume servers (e.g., "hdd", "ssd"). | `string` | `""` | +| `volume.resources` | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `volume.resources.cpu` | Number of CPU cores allocated. | `quantity` | `""` | +| `volume.resources.memory` | Amount of memory allocated. | `quantity` | `""` | +| `volume.resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `small` | +| `volume.zones` | A map of zones for MultiZone topology. Each zone can have its own number of replicas and size. | `map[string]object` | `{}` | +| `volume.zones[name].replicas` | Number of replicas in the zone. | `int` | `0` | +| `volume.zones[name].size` | Zone storage size. | `quantity` | `""` | +| `volume.zones[name].dataCenter` | SeaweedFS data center name for this zone. Defaults to the zone name. | `string` | `""` | +| `volume.zones[name].nodeSelector` | YAML nodeSelector for this zone (default: topology.kubernetes.io/zone: ). | `string` | `""` | +| `volume.zones[name].storageClass` | StorageClass used to store zone data. Defaults to volume.storageClass. | `string` | `""` | +| `volume.zones[name].pools` | A map of storage pools for this zone. Each pool creates a separate Volume StatefulSet per zone. | `map[string]object` | `{}` | +| `volume.zones[name].pools[name].diskType` | SeaweedFS disk type tag (e.g., "ssd", "hdd", "nvme"). | `string` | `""` | +| `volume.zones[name].pools[name].replicas` | Number of volume replicas. Defaults to volume.replicas (Simple) or zone.replicas/volume.replicas (MultiZone). | `int` | `0` | +| `volume.zones[name].pools[name].size` | Persistent Volume size. Defaults to volume.size (Simple) or zone.size/volume.size (MultiZone). | `quantity` | `""` | +| `volume.zones[name].pools[name].storageClass` | Kubernetes StorageClass for the pool. Defaults to volume.storageClass. | `string` | `""` | +| `volume.zones[name].pools[name].resources` | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `volume.zones[name].pools[name].resources.cpu` | Number of CPU cores allocated. | `quantity` | `""` | +| `volume.zones[name].pools[name].resources.memory` | Amount of memory allocated. | `quantity` | `""` | +| `volume.zones[name].pools[name].resourcesPreset` | Default sizing preset used when `resources` is omitted. Defaults to volume.resourcesPreset. | `string` | `{}` | +| `volume.pools` | A map of storage pools. Each pool creates a separate Volume StatefulSet with its own disk type. | `map[string]object` | `{}` | +| `volume.pools[name].diskType` | SeaweedFS disk type tag (e.g., "ssd", "hdd", "nvme"). | `string` | `""` | +| `volume.pools[name].replicas` | Number of volume replicas. Defaults to volume.replicas (Simple) or zone.replicas/volume.replicas (MultiZone). | `int` | `0` | +| `volume.pools[name].size` | Persistent Volume size. Defaults to volume.size (Simple) or zone.size/volume.size (MultiZone). | `quantity` | `""` | +| `volume.pools[name].storageClass` | Kubernetes StorageClass for the pool. Defaults to volume.storageClass. | `string` | `""` | +| `volume.pools[name].resources` | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `volume.pools[name].resources.cpu` | Number of CPU cores allocated. | `quantity` | `""` | +| `volume.pools[name].resources.memory` | Amount of memory allocated. | `quantity` | `""` | +| `volume.pools[name].resourcesPreset` | Default sizing preset used when `resources` is omitted. Defaults to volume.resourcesPreset. | `string` | `{}` | +| `s3` | S3 service configuration. | `object` | `{}` | +| `s3.replicas` | Number of S3 replicas. | `int` | `2` | +| `s3.resources` | Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. | `object` | `{}` | +| `s3.resources.cpu` | Number of CPU cores allocated. | `quantity` | `""` | +| `s3.resources.memory` | Amount of memory allocated. | `quantity` | `""` | +| `s3.resourcesPreset` | Default sizing preset used when `resources` is omitted. | `string` | `small` | diff --git a/packages/extra/seaweedfs/images/objectstorage-sidecar.tag b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag new file mode 100644 index 00000000..9b413da5 --- /dev/null +++ b/packages/extra/seaweedfs/images/objectstorage-sidecar.tag @@ -0,0 +1 @@ +ghcr.io/cozystack/cozystack/objectstorage-sidecar:v1.3.0@sha256:5bcccbdb13979a16cee535eb5fbcdf0d87973689010a10b7b25e55c5be3edaa6 diff --git a/packages/extra/seaweedfs/images/seaweedfs-cosi-driver.tag b/packages/extra/seaweedfs/images/seaweedfs-cosi-driver.tag new file mode 100644 index 00000000..52494779 --- /dev/null +++ b/packages/extra/seaweedfs/images/seaweedfs-cosi-driver.tag @@ -0,0 +1 @@ +ghcr.io/seaweedfs/seaweedfs-cosi-driver:v0.3.0 diff --git a/packages/extra/seaweedfs/templates/client/cosi-bucket-class.yaml b/packages/extra/seaweedfs/templates/client/cosi-bucket-class.yaml new file mode 100644 index 00000000..ce049b31 --- /dev/null +++ b/packages/extra/seaweedfs/templates/client/cosi-bucket-class.yaml @@ -0,0 +1,38 @@ +{{- if eq .Values.topology "Client" }} +--- +kind: BucketClass +apiVersion: objectstorage.k8s.io/v1alpha1 +metadata: + name: {{ .Release.Namespace }} +driverName: {{ .Release.Namespace }}.seaweedfs.objectstorage.k8s.io +deletionPolicy: Delete +--- +kind: BucketClass +apiVersion: objectstorage.k8s.io/v1alpha1 +metadata: + name: {{ .Release.Namespace }}-lock +driverName: {{ .Release.Namespace }}.seaweedfs.objectstorage.k8s.io +deletionPolicy: Retain +parameters: + objectLockEnabled: "true" + objectLockRetentionMode: "COMPLIANCE" + objectLockRetentionDays: "365" +--- +kind: BucketAccessClass +apiVersion: objectstorage.k8s.io/v1alpha1 +metadata: + name: {{ .Release.Namespace }} +driverName: {{ .Release.Namespace }}.seaweedfs.objectstorage.k8s.io +authenticationType: KEY +parameters: + accessPolicy: readwrite +--- +kind: BucketAccessClass +apiVersion: objectstorage.k8s.io/v1alpha1 +metadata: + name: {{ .Release.Namespace }}-readonly +driverName: {{ .Release.Namespace }}.seaweedfs.objectstorage.k8s.io +authenticationType: KEY +parameters: + accessPolicy: readonly +{{- end }} diff --git a/packages/extra/seaweedfs/templates/client/cosi-cluster-role.yaml b/packages/extra/seaweedfs/templates/client/cosi-cluster-role.yaml new file mode 100644 index 00000000..4ee30f30 --- /dev/null +++ b/packages/extra/seaweedfs/templates/client/cosi-cluster-role.yaml @@ -0,0 +1,61 @@ +{{- if eq .Values.topology "Client" }} +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Release.Namespace }}-objectstorage-provisioner +rules: +- apiGroups: ["objectstorage.k8s.io"] + resources: + - "buckets" + - "bucketaccesses" + - "bucketclaims" + - "bucketclasses" + - "bucketclasses/status" + - "bucketaccessclasses" + - "buckets/status" + - "bucketaccesses/status" + - "bucketclaims/status" + - "bucketaccessclasses/status" + verbs: + - "get" + - "list" + - "watch" + - "update" + - "create" + - "delete" +- apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: + - "get" + - "watch" + - "list" + - "delete" + - "update" + - "create" +- apiGroups: [""] + resources: + - "secrets" + - "events" + verbs: + - "get" + - "list" + - "watch" + - "update" + - "create" + - "delete" + - "patch" +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Release.Namespace }}-objectstorage-provisioner +subjects: + - kind: ServiceAccount + name: {{ .Release.Name }}-objectstorage-provisioner + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ .Release.Namespace }}-objectstorage-provisioner + apiGroup: rbac.authorization.k8s.io +{{- end }} diff --git a/packages/extra/seaweedfs/templates/client/cosi-deployment.yaml b/packages/extra/seaweedfs/templates/client/cosi-deployment.yaml new file mode 100644 index 00000000..f73a61bf --- /dev/null +++ b/packages/extra/seaweedfs/templates/client/cosi-deployment.yaml @@ -0,0 +1,86 @@ +{{- if eq .Values.topology "Client" }} +{{- $host := .Values._namespace.host }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $.Release.Name }}-objectstorage-provisioner + namespace: {{ $.Release.Namespace }} + labels: + app.kubernetes.io/component: objectstorage-provisioner + app.kubernetes.io/instance: seaweedfs + app.kubernetes.io/name: {{ $.Release.Name }} +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/component: objectstorage-provisioner + app.kubernetes.io/instance: seaweedfs + app.kubernetes.io/name: {{ $.Release.Name }} + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + creationTimestamp: null + labels: + policy.cozystack.io/allow-to-apiserver: "true" + app.kubernetes.io/component: objectstorage-provisioner + app.kubernetes.io/instance: seaweedfs + app.kubernetes.io/name: {{ $.Release.Name }} + spec: + containers: + - name: seaweedfs-cosi-driver + image: "{{ $.Files.Get "images/seaweedfs-cosi-driver.tag" | trim }}" + imagePullPolicy: IfNotPresent + env: + - name: DRIVERNAME + value: {{ .Release.Namespace }}.seaweedfs.objectstorage.k8s.io + - name: ENDPOINT + value: https://{{ .Values.host | default (printf "s3.%s" $host) }} + - name: SEAWEEDFS_FILER + value: "{{ .Values.filer.grpcHost }}:{{ .Values.filer.grpcPort }}" + - name: WEED_GRPC_CLIENT_KEY + value: /usr/local/share/ca-certificates/client/tls.key + - name: WEED_GRPC_CLIENT_CERT + value: /usr/local/share/ca-certificates/client/tls.crt + - name: WEED_GRPC_CA + value: /usr/local/share/ca-certificates/client/ca.crt + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 100m + memory: 128Mi + volumeMounts: + - mountPath: /var/lib/cosi + name: socket + - mountPath: /usr/local/share/ca-certificates/client/ + name: client-cert + readOnly: true + - name: seaweedfs-cosi-sidecar + image: "{{ $.Files.Get "images/objectstorage-sidecar.tag" | trim }}" + imagePullPolicy: IfNotPresent + args: + - --v=5 + env: + - name: POD_NAMESPACE + value: {{ .Release.Namespace }} + volumeMounts: + - mountPath: /var/lib/cosi + name: socket + enableServiceLinks: false + restartPolicy: Always + terminationGracePeriodSeconds: 10 + serviceAccountName: {{ .Release.Name }}-objectstorage-provisioner + volumes: + - name: socket + emptyDir: {} + - name: client-cert + secret: + defaultMode: 420 + secretName: seaweedfs-client-cert +{{- end }} diff --git a/packages/extra/seaweedfs/templates/client/cosi-service-account.yaml b/packages/extra/seaweedfs/templates/client/cosi-service-account.yaml new file mode 100644 index 00000000..20407dee --- /dev/null +++ b/packages/extra/seaweedfs/templates/client/cosi-service-account.yaml @@ -0,0 +1,8 @@ +{{- if eq .Values.topology "Client" }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Release.Name }}-objectstorage-provisioner + namespace: {{ .Release.Namespace }} +automountServiceAccountToken: true +{{- end }} diff --git a/packages/extra/seaweedfs/templates/cm.yaml b/packages/extra/seaweedfs/templates/cm.yaml new file mode 100644 index 00000000..1aec9a1b --- /dev/null +++ b/packages/extra/seaweedfs/templates/cm.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ .Release.Name }}-deployed-topology" +data: + topology: {{ quote .Values.topology }} diff --git a/packages/extra/seaweedfs/templates/dashboard-resourcemap.yaml b/packages/extra/seaweedfs/templates/dashboard-resourcemap.yaml index 02c9b2aa..dfd408da 100644 --- a/packages/extra/seaweedfs/templates/dashboard-resourcemap.yaml +++ b/packages/extra/seaweedfs/templates/dashboard-resourcemap.yaml @@ -3,6 +3,7 @@ kind: Role metadata: name: {{ .Release.Name }}-dashboard-resources rules: +{{- if not (eq .Values.topology "Client") }} - apiGroups: - "" resources: @@ -24,16 +25,31 @@ rules: resourceNames: - {{ $.Release.Name }}-master - {{ $.Release.Name }}-filer - - {{ $.Release.Name }}-volume - {{ $.Release.Name }}-db + - {{ $.Release.Name }}-s3 + {{- if eq .Values.topology "Simple" }} + - {{ $.Release.Name }}-volume + {{- range $poolName, $pool := .Values.volume.pools }} + - {{ $.Release.Name }}-volume-{{ $poolName }} + {{- end }} + {{- else if eq .Values.topology "MultiZone" }} + {{- range $zoneName, $zone := .Values.volume.zones }} + - {{ $.Release.Name }}-volume-{{ $zoneName }} + {{- range $poolName, $pool := (dig "pools" dict $zone) }} + - {{ $.Release.Name }}-volume-{{ $zoneName }}-{{ $poolName }} + {{- end }} + {{- end }} + {{- end }} verbs: ["get", "list", "watch"] +{{- end }} + --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: {{ .Release.Name }}-dashboard-resources subjects: -{{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "admin" .Release.Namespace) }} +{{ include "cozy-lib.rbac.subjectsForTenantAndAccessLevel" (list "super-admin" .Release.Namespace) }} roleRef: kind: Role name: {{ .Release.Name }}-dashboard-resources diff --git a/packages/extra/seaweedfs/templates/ingress.yaml b/packages/extra/seaweedfs/templates/ingress.yaml new file mode 100644 index 00000000..cf4e837e --- /dev/null +++ b/packages/extra/seaweedfs/templates/ingress.yaml @@ -0,0 +1,40 @@ +{{- $ingress := .Values._namespace.ingress }} +{{- $host := .Values._namespace.host }} +{{- if and (not (eq .Values.topology "Client")) (.Values.filer.grpcHost) }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + nginx.ingress.kubernetes.io/backend-protocol: GRPCS + nginx.ingress.kubernetes.io/ssl-passthrough: "true" + nginx.ingress.kubernetes.io/whitelist-source-range: "{{ join "," (.Values.filer.whitelist | default "0.0.0.0/32") }}" + name: seaweedfs-filer-external +spec: + ingressClassName: tenant-root + rules: + - host: {{ .Values.filer.grpcHost | default (printf "filer.%s" $host) }} + http: + paths: + - backend: + service: + name: {{ $.Release.Name }}-filer-external + port: + number: 18888 + path: / + pathType: ImplementationSpecific +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ $.Release.Name }}-filer-external +spec: + ports: + - name: swfs-filer-grpc + port: 18888 + protocol: TCP + targetPort: 18888 + selector: + app.kubernetes.io/component: filer + app.kubernetes.io/name: {{ $.Release.Name }} +{{- end }} diff --git a/packages/extra/seaweedfs/templates/seaweedfs.yaml b/packages/extra/seaweedfs/templates/seaweedfs.yaml index a2fcb30c..2f5720ca 100644 --- a/packages/extra/seaweedfs/templates/seaweedfs.yaml +++ b/packages/extra/seaweedfs/templates/seaweedfs.yaml @@ -1,64 +1,240 @@ -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- /* Preflight checks for Helm template */ -}} +{{- if not (has .Values.topology (list "Simple" "MultiZone" "Client")) }} +{{- fail "Invalid value for .Values.topology. Must be one of 'Simple', 'MultiZone' or 'Client'." }} +{{- end }} +{{- if and (eq .Values.topology "Client") (not .Values.filer.grpcHost) }} +{{- fail "When topology is 'Client', .Values.filer.grpcHost must be set to a valid remote filer GRPC service endpoint." }} +{{- end }} +{{- if lt (int .Values.replicationFactor) 1 }} +{{- fail "Invalid value for .Values.replicationFactor. Must be at least 1." }} +{{- end }} +{{- if eq .Values.topology "MultiZone" }} +{{- if (eq (len .Values.volume.zones) 0) }} +{{- fail "Zones must be defined for MultiZone topology." }} +{{- end }} +{{- if and (hasKey .Values.volume "zones") (gt (int .Values.replicationFactor) (len .Values.volume.zones)) }} +{{- fail "replicationFactor must be less than or equal to the number of zones defined in .Values.volume.zones." }} +{{- end }} +{{- end }} +{{- if and (eq .Values.topology "Client") (gt (len .Values.volume.pools) 0) }} +{{- fail "volume.pools is not supported with Client topology." }} +{{- end }} +{{- if and (eq .Values.topology "MultiZone") (gt (len .Values.volume.pools) 0) }} +{{- fail "volume.pools is not supported with MultiZone topology. Use volume.zones[name].pools instead." }} +{{- end }} +{{- if and .Values.volume.diskType (not (regexMatch "^[a-z0-9]+$" .Values.volume.diskType)) }} +{{- fail (printf "volume.diskType must be lowercase alphanumeric (got: %s)." .Values.volume.diskType) }} +{{- end }} + +{{- /* Collect and validate all pools from volume.pools and zones[].pools */ -}} +{{- $allPools := dict }} +{{- range $poolName, $pool := .Values.volume.pools }} +{{- if not (regexMatch "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$" $poolName) }} +{{- fail (printf "volume.pools key '%s' must be a valid DNS label (lowercase alphanumeric and hyphens, no dots)." $poolName) }} +{{- end }} +{{- if or (hasSuffix "-lock" $poolName) (hasSuffix "-readonly" $poolName) }} +{{- fail (printf "volume.pools key '%s' must not end with '-lock' or '-readonly' (reserved suffixes for COSI resources)." $poolName) }} +{{- end }} +{{- if not $pool.diskType }} +{{- fail (printf "volume.pools.%s.diskType is required." $poolName) }} +{{- end }} +{{- if not (regexMatch "^[a-z0-9]+$" $pool.diskType) }} +{{- fail (printf "volume.pools.%s.diskType must be lowercase alphanumeric (got: %s)." $poolName $pool.diskType) }} +{{- end }} +{{- if and $.Values.volume.diskType (eq $pool.diskType $.Values.volume.diskType) }} +{{- fail (printf "volume.pools.%s.diskType '%s' must differ from volume.diskType." $poolName $pool.diskType) }} +{{- end }} +{{- $_ := set $allPools $poolName $pool.diskType }} +{{- end }} +{{- if eq .Values.topology "MultiZone" }} +{{- range $zoneName, $zone := .Values.volume.zones }} +{{- range $poolName, $pool := (dig "pools" dict $zone) }} +{{- if not (regexMatch "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$" $poolName) }} +{{- fail (printf "volume.zones.%s.pools key '%s' must be a valid DNS label." $zoneName $poolName) }} +{{- end }} +{{- if or (hasSuffix "-lock" $poolName) (hasSuffix "-readonly" $poolName) }} +{{- fail (printf "volume.zones.%s.pools key '%s' must not end with '-lock' or '-readonly' (reserved suffixes for COSI resources)." $zoneName $poolName) }} +{{- end }} +{{- if not $pool.diskType }} +{{- fail (printf "volume.zones.%s.pools.%s.diskType is required." $zoneName $poolName) }} +{{- end }} +{{- if not (regexMatch "^[a-z0-9]+$" $pool.diskType) }} +{{- fail (printf "volume.zones.%s.pools.%s.diskType must be lowercase alphanumeric (got: %s)." $zoneName $poolName $pool.diskType) }} +{{- end }} +{{- if and $.Values.volume.diskType (eq $pool.diskType $.Values.volume.diskType) }} +{{- fail (printf "volume.zones.%s.pools.%s.diskType '%s' must differ from volume.diskType." $zoneName $poolName $pool.diskType) }} +{{- end }} +{{- if and (hasKey $allPools $poolName) (ne (get $allPools $poolName) $pool.diskType) }} +{{- fail (printf "Pool '%s' has inconsistent diskType across zones (expected '%s', got '%s' in zone '%s')." $poolName (get $allPools $poolName) $pool.diskType $zoneName) }} +{{- end }} +{{- $_ := set $allPools $poolName $pool.diskType }} +{{- $composedName := printf "%s-%s" $zoneName $poolName }} +{{- if hasKey $.Values.volume.zones $composedName }} +{{- fail (printf "Composed volume name '%s' (from zone '%s' and pool '%s') collides with an existing zone name." $composedName $zoneName $poolName) }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{- $detectedTopology := "Unknown" }} +{{- $configMap := lookup "v1" "ConfigMap" .Release.Namespace (printf "%s-deployed-topology" .Release.Name) }} +{{- if $configMap }} +{{- $detectedTopology = dig "data" "topology" "Unknown" $configMap }} +{{- else }} +{{- if lookup "v1" "PersistentVolumeClaim" .Release.Namespace (printf "data1-%s-volume-0" .Release.Name) }} +{{- $detectedTopology = "Simple" }} +{{- else if lookup "apps/v1" "StatefulSet" .Release.Namespace (printf "%s-master" .Release.Name) }} +{{- $detectedTopology = "MultiZone" }} +{{- end }} +{{- end }} + +{{- if not (has $detectedTopology (list .Values.topology "Unknown")) }} +{{- fail (printf "Not allowed to switch between topologies after the first deployment: %s" $detectedTopology) }} +{{- end }} + +{{- if not (eq .Values.topology "Client") }} +{{- $ingress := .Values._namespace.ingress }} +{{- $host := .Values._namespace.host }} +{{- $solver := (index .Values._cluster "solver") | default "http01" }} +{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: {{ .Release.Name }}-system + labels: + sharding.fluxcd.io/key: tenants spec: - chart: - spec: - chart: cozy-seaweedfs - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-system - namespace: cozy-system - version: '>= 0.0.0-0' - interval: 1m0s - timeout: 5m0s + chartRef: + kind: ExternalArtifact + name: cozystack-seaweedfs-application-default-seaweedfs-system + namespace: cozy-system + interval: 5m + timeout: 10m + install: + remediation: + retries: -1 + upgrade: + force: true + remediation: + retries: -1 + valuesFrom: + - kind: Secret + name: cozystack-values values: global: serviceAccountName: "{{ .Release.Namespace }}-seaweedfs" + db: + replicas: {{ .Values.db.replicas }} + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.db.resourcesPreset .Values.db.resources $) | nindent 8 }} + size: {{ .Values.db.size }} + {{- with .Values.db.storageClass }} + storageClass: {{ . }} + {{- end }} seaweedfs: master: - resources: - requests: - cpu: "100m" - memory: "128Mi" - limits: - cpu: "500m" - memory: "512Mi" + {{ if eq .Values.topology "Simple" }} + defaultReplicaPlacement: "00{{ sub .Values.replicationFactor 1 }}" + {{- else if eq .Values.topology "MultiZone" }} + defaultReplicaPlacement: "{{ sub .Values.replicationFactor 1 }}00" + {{- end }} + replicas: {{ .Values.master.replicas }} + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.master.resourcesPreset .Values.master.resources $) | nindent 10 }} volume: - replicas: {{ .Values.replicas }} - resources: - requests: - cpu: "100m" - memory: "128Mi" - limits: - cpu: "500m" - memory: "512Mi" - # TODO: workaround for non-working online resize - podAnnotations: - volume-size: "{{ .Values.size }}" + {{ if eq .Values.topology "MultiZone" }} + enabled: false + {{- end }} + replicas: {{ .Values.volume.replicas }} + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.volume.resourcesPreset .Values.volume.resources $) | nindent 10 }} dataDirs: - name: data1 type: "persistentVolumeClaim" - size: "{{ .Values.size }}" - {{- with .Values.storageClass }} + size: "{{ .Values.volume.size }}" + {{- with .Values.volume.storageClass }} storageClass: {{ . }} {{- end }} maxVolumes: 0 + {{- if .Values.volume.diskType }} + extraArgs: + - "-disk={{ .Values.volume.diskType }}" + {{- end }} + {{- if or (and (eq .Values.topology "Simple") (gt (len .Values.volume.pools) 0)) (eq .Values.topology "MultiZone") }} + volumes: + {{- if eq .Values.topology "Simple" }} + {{- range $poolName, $pool := .Values.volume.pools }} + {{ $poolName }}: + replicas: {{ ternary $pool.replicas $.Values.volume.replicas (hasKey $pool "replicas") }} + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list ($pool.resourcesPreset | default $.Values.volume.resourcesPreset) (default dict $pool.resources) $) | nindent 12 }} + dataDirs: + - name: data1 + type: "persistentVolumeClaim" + size: "{{ $pool.size | default $.Values.volume.size }}" + {{- with ($pool.storageClass | default $.Values.volume.storageClass) }} + storageClass: "{{ . }}" + {{- end }} + maxVolumes: 0 + extraArgs: + - "-disk={{ $pool.diskType }}" + {{- end }} + {{- else if eq .Values.topology "MultiZone" }} + {{- range $zoneName, $zone := .Values.volume.zones }} + {{ $zoneName }}: + replicas: {{ ternary $zone.replicas $.Values.volume.replicas (hasKey $zone "replicas") }} + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list $.Values.volume.resourcesPreset $.Values.volume.resources $) | nindent 12 }} + dataDirs: + - name: data1 + type: "persistentVolumeClaim" + size: "{{ $zone.size | default $.Values.volume.size }}" + {{- with ($zone.storageClass | default $.Values.volume.storageClass) }} + storageClass: "{{ . }}" + {{- end }} + maxVolumes: 0 + nodeSelector: | + {{- with $zone.nodeSelector }} +{{ . | indent 12 }} + {{- else }} + topology.kubernetes.io/zone: {{ $zoneName }} + {{- end }} + dataCenter: {{ $zone.dataCenter | default $zoneName }} + {{- if $.Values.volume.diskType }} + extraArgs: + - "-disk={{ $.Values.volume.diskType }}" + {{- end }} + {{- end }} + {{- range $zoneName, $zone := .Values.volume.zones }} + {{- range $poolName, $pool := (dig "pools" dict $zone) }} + {{ $zoneName }}-{{ $poolName }}: + replicas: {{ ternary $pool.replicas (ternary $zone.replicas $.Values.volume.replicas (hasKey $zone "replicas")) (hasKey $pool "replicas") }} + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list ($pool.resourcesPreset | default $.Values.volume.resourcesPreset) (default dict $pool.resources) $) | nindent 12 }} + dataDirs: + - name: data1 + type: "persistentVolumeClaim" + size: "{{ $pool.size | default $zone.size | default $.Values.volume.size }}" + {{- with ($pool.storageClass | default $zone.storageClass | default $.Values.volume.storageClass) }} + storageClass: "{{ . }}" + {{- end }} + maxVolumes: 0 + nodeSelector: | + {{- with $zone.nodeSelector }} +{{ . | indent 12 }} + {{- else }} + topology.kubernetes.io/zone: {{ $zoneName }} + {{- end }} + dataCenter: {{ $zone.dataCenter | default $zoneName }} + extraArgs: + - "-disk={{ $pool.diskType }}" + {{- end }} + {{- end }} + {{- end }} + {{- end }} filer: + {{ if eq .Values.topology "Simple" }} + defaultReplicaPlacement: "00{{ sub .Values.replicationFactor 1 }}" + {{- else if eq .Values.topology "MultiZone" }} + defaultReplicaPlacement: "{{ sub .Values.replicationFactor 1 }}00" + {{- end }} s3: domainName: {{ .Values.host | default (printf "s3.%s" $host) }} - resources: - requests: - cpu: "100m" - memory: "128Mi" - limits: - cpu: "500m" - memory: "512Mi" + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.filer.resourcesPreset .Values.filer.resources $) | nindent 10 }} s3: ingress: className: {{ $ingress }} @@ -66,12 +242,15 @@ spec: annotations: nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" - acme.cert-manager.io/http01-ingress-class: {{ $ingress }} - cert-manager.io/cluster-issuer: letsencrypt-prod + {{- if eq $solver "http01" }} + acme.cert-manager.io/http01-ingress-ingressclassname: {{ $ingress }} + {{- end }} + cert-manager.io/cluster-issuer: {{ $clusterIssuer }} tls: - hosts: - {{ .Values.host | default (printf "s3.%s" $host) }} secretName: {{ .Release.Name }}-s3-ingress-tls + resources: {{- include "cozy-lib.resources.defaultingSanitize" (list .Values.s3.resourcesPreset .Values.s3.resources $) | nindent 10 }} cosi: driverName: "{{ .Release.Namespace }}.seaweedfs.objectstorage.k8s.io" bucketClassName: "{{ .Release.Namespace }}" @@ -88,8 +267,8 @@ kind: WorkloadMonitor metadata: name: {{ $.Release.Name }}-master spec: - replicas: 3 - minReplicas: 2 + replicas: {{ .Values.master.replicas }} + minReplicas: {{ div .Values.master.replicas 2 | add1 }} kind: seaweedfs type: master selector: @@ -102,7 +281,7 @@ kind: WorkloadMonitor metadata: name: {{ $.Release.Name }}-filer spec: - replicas: 2 + replicas: {{ .Values.filer.replicas }} minReplicas: 1 kind: seaweedfs type: filer @@ -110,27 +289,79 @@ spec: app.kubernetes.io/component: filer app.kubernetes.io/name: seaweedfs version: {{ $.Chart.Version }} + +{{ if eq .Values.topology "Simple" }} --- apiVersion: cozystack.io/v1alpha1 kind: WorkloadMonitor metadata: name: {{ $.Release.Name }}-volume spec: - replicas: {{ .Values.replicas }} - minReplicas: {{ div .Values.replicas 2 | add1 }} + replicas: {{ .Values.volume.replicas }} + minReplicas: 1 kind: seaweedfs type: volume selector: app.kubernetes.io/component: volume app.kubernetes.io/name: seaweedfs version: {{ $.Chart.Version }} +{{- range $poolName, $pool := .Values.volume.pools }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: {{ $.Release.Name }}-volume-{{ $poolName }} +spec: + replicas: {{ ternary $pool.replicas $.Values.volume.replicas (hasKey $pool "replicas") }} + minReplicas: 1 + kind: seaweedfs + type: volume + selector: + app.kubernetes.io/component: volume-{{ $poolName }} + app.kubernetes.io/name: seaweedfs + version: {{ $.Chart.Version }} +{{- end }} +{{- else if eq .Values.topology "MultiZone" }} +{{- range $zoneName, $zoneSpec := .Values.volume.zones }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: {{ $.Release.Name }}-volume-{{ $zoneName }} +spec: + replicas: {{ ternary $zoneSpec.replicas $.Values.volume.replicas (hasKey $zoneSpec "replicas") }} + minReplicas: 1 + kind: seaweedfs + type: volume + selector: + app.kubernetes.io/component: volume-{{ $zoneName }} + app.kubernetes.io/name: seaweedfs + version: {{ $.Chart.Version }} +{{- range $poolName, $pool := (dig "pools" dict $zoneSpec) }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: {{ $.Release.Name }}-volume-{{ $zoneName }}-{{ $poolName }} +spec: + replicas: {{ ternary $pool.replicas (ternary $zoneSpec.replicas $.Values.volume.replicas (hasKey $zoneSpec "replicas")) (hasKey $pool "replicas") }} + minReplicas: 1 + kind: seaweedfs + type: volume + selector: + app.kubernetes.io/component: volume-{{ $zoneName }}-{{ $poolName }} + app.kubernetes.io/name: seaweedfs + version: {{ $.Chart.Version }} +{{- end }} +{{- end }} +{{- end }} --- apiVersion: cozystack.io/v1alpha1 kind: WorkloadMonitor metadata: name: {{ $.Release.Name }}-db spec: - replicas: 2 + replicas: {{ .Values.db.replicas }} minReplicas: 1 kind: seaweedfs type: postgres @@ -138,3 +369,18 @@ spec: cnpg.io/cluster: seaweedfs-db cnpg.io/podRole: instance version: {{ $.Chart.Version }} +--- +apiVersion: cozystack.io/v1alpha1 +kind: WorkloadMonitor +metadata: + name: {{ $.Release.Name }}-s3 +spec: + replicas: {{ .Values.s3.replicas }} + minReplicas: 1 + kind: seaweedfs + type: s3 + selector: + app.kubernetes.io/component: s3 + app.kubernetes.io/name: seaweedfs + version: {{ $.Chart.Version }} +{{- end }} diff --git a/packages/extra/seaweedfs/templates/storage-pool-bucket-classes.yaml b/packages/extra/seaweedfs/templates/storage-pool-bucket-classes.yaml new file mode 100644 index 00000000..bf58340a --- /dev/null +++ b/packages/extra/seaweedfs/templates/storage-pool-bucket-classes.yaml @@ -0,0 +1,55 @@ +{{- if ne .Values.topology "Client" }} +{{- /* Collect unique pools from volume.pools and zones[].pools */ -}} +{{- $uniquePools := dict }} +{{- range $poolName, $pool := .Values.volume.pools }} +{{- $_ := set $uniquePools $poolName $pool.diskType }} +{{- end }} +{{- if eq .Values.topology "MultiZone" }} +{{- range $zoneName, $zone := .Values.volume.zones }} +{{- range $poolName, $pool := (dig "pools" dict $zone) }} +{{- $_ := set $uniquePools $poolName $pool.diskType }} +{{- end }} +{{- end }} +{{- end }} +{{- range $poolName, $diskType := $uniquePools }} +--- +kind: BucketClass +apiVersion: objectstorage.k8s.io/v1alpha1 +metadata: + name: {{ $.Release.Namespace }}-{{ $poolName }} +driverName: {{ $.Release.Namespace }}.seaweedfs.objectstorage.k8s.io +deletionPolicy: Delete +parameters: + disk: {{ $diskType }} +--- +kind: BucketClass +apiVersion: objectstorage.k8s.io/v1alpha1 +metadata: + name: {{ $.Release.Namespace }}-{{ $poolName }}-lock +driverName: {{ $.Release.Namespace }}.seaweedfs.objectstorage.k8s.io +deletionPolicy: Retain +parameters: + disk: {{ $diskType }} + objectLockEnabled: "true" + objectLockRetentionMode: "COMPLIANCE" + objectLockRetentionDays: "365" +--- +kind: BucketAccessClass +apiVersion: objectstorage.k8s.io/v1alpha1 +metadata: + name: {{ $.Release.Namespace }}-{{ $poolName }} +driverName: {{ $.Release.Namespace }}.seaweedfs.objectstorage.k8s.io +authenticationType: KEY +parameters: + accessPolicy: readwrite +--- +kind: BucketAccessClass +apiVersion: objectstorage.k8s.io/v1alpha1 +metadata: + name: {{ $.Release.Namespace }}-{{ $poolName }}-readonly +driverName: {{ $.Release.Namespace }}.seaweedfs.objectstorage.k8s.io +authenticationType: KEY +parameters: + accessPolicy: readonly +{{- end }} +{{- end }} diff --git a/packages/extra/seaweedfs/templates/vpa.yaml b/packages/extra/seaweedfs/templates/vpa.yaml deleted file mode 100644 index a0c6d6a7..00000000 --- a/packages/extra/seaweedfs/templates/vpa.yaml +++ /dev/null @@ -1,66 +0,0 @@ -apiVersion: autoscaling.k8s.io/v1 -kind: VerticalPodAutoscaler -metadata: - name: {{ .Release.Name }}-filer -spec: - targetRef: - apiVersion: apps/v1 - kind: StatefulSet - name: {{ .Release.Name }}-filer - updatePolicy: - updateMode: Auto - resourcePolicy: - containerPolicies: - - containerName: seaweedfs - minAllowed: - cpu: 25m - memory: 64Mi - maxAllowed: - cpu: "1" - memory: 2048Mi - ---- - -apiVersion: autoscaling.k8s.io/v1 -kind: VerticalPodAutoscaler -metadata: - name: {{ .Release.Name }}-master -spec: - targetRef: - apiVersion: apps/v1 - kind: StatefulSet - name: {{ .Release.Name }}-master - updatePolicy: - updateMode: Auto - resourcePolicy: - containerPolicies: - - containerName: seaweedfs - minAllowed: - cpu: 25m - memory: 64Mi - maxAllowed: - cpu: "1" - memory: 2048Mi - ---- - -apiVersion: autoscaling.k8s.io/v1 -kind: VerticalPodAutoscaler -metadata: - name: {{ .Release.Name }}-volume -spec: - targetRef: - apiVersion: apps/v1 - kind: StatefulSet - name: {{ .Release.Name }}-volume - updatePolicy: - updateMode: Auto - resourcePolicy: - containerPolicies: - - containerName: seaweedfs - minAllowed: - cpu: 25m - memory: 64Mi - maxAllowed: - cpu: "1" - memory: 2048Mi diff --git a/packages/extra/seaweedfs/values.schema.json b/packages/extra/seaweedfs/values.schema.json index c7daa251..9b48043d 100644 --- a/packages/extra/seaweedfs/values.schema.json +++ b/packages/extra/seaweedfs/values.schema.json @@ -1,26 +1,586 @@ { - "title": "Chart Values", - "type": "object", - "properties": { - "host": { - "type": "string", - "description": "The hostname used to access the grafana externally (defaults to 'grafana' subdomain for the tenant host).", - "default": "" - }, + "title": "Chart Values", + "type": "object", + "properties": { + "host": { + "description": "The hostname used to access SeaweedFS externally (defaults to 's3' subdomain for the tenant host).", + "type": "string", + "default": "" + }, + "topology": { + "description": "The topology of the SeaweedFS cluster.", + "type": "string", + "default": "Simple", + "enum": [ + "Simple", + "MultiZone", + "Client" + ] + }, + "replicationFactor": { + "description": "Replication factor: number of replicas for each volume in the SeaweedFS cluster.", + "type": "integer", + "default": 2 + }, + "db": { + "description": "Database configuration.", + "type": "object", + "default": {}, + "properties": { "replicas": { - "type": "number", - "description": "Persistent Volume size for NATS", - "default": 2 + "description": "Number of database replicas.", + "type": "integer", + "default": 2 + }, + "resources": { + "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "Number of CPU cores allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Amount of memory allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted.", + "type": "string", + "default": "small", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] }, "size": { - "type": "string", - "description": "Persistent Volume size", - "default": "10Gi" + "description": "Persistent Volume size.", + "default": "10Gi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true }, "storageClass": { - "type": "string", - "description": "StorageClass used to store the data", - "default": "" + "description": "StorageClass used to store the data.", + "type": "string", + "default": "" } + } + }, + "master": { + "description": "Master service configuration.", + "type": "object", + "default": {}, + "properties": { + "replicas": { + "description": "Number of master replicas.", + "type": "integer", + "default": 3 + }, + "resources": { + "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "Number of CPU cores allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Amount of memory allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted.", + "type": "string", + "default": "small", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + } + } + }, + "filer": { + "description": "Filer service configuration.", + "type": "object", + "default": {}, + "properties": { + "grpcHost": { + "description": "The hostname used to expose or access the filer service externally.", + "type": "string", + "default": "" + }, + "grpcPort": { + "description": "The port used to access the filer service externally.", + "type": "integer", + "default": 443 + }, + "replicas": { + "description": "Number of filer replicas.", + "type": "integer", + "default": 2 + }, + "resources": { + "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "Number of CPU cores allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Amount of memory allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted.", + "type": "string", + "default": "small", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + }, + "whitelist": { + "description": "A list of IP addresses or CIDR ranges that are allowed to access the filer service.", + "type": "array", + "default": [], + "items": { + "type": "string" + } + } + } + }, + "volume": { + "description": "Volume service configuration.", + "type": "object", + "default": {}, + "properties": { + "diskType": { + "description": "SeaweedFS disk type tag for the default volume servers (e.g., \"hdd\", \"ssd\").", + "type": "string", + "default": "" + }, + "pools": { + "description": "A map of storage pools. Each pool creates a separate Volume StatefulSet with its own disk type.", + "type": "object", + "default": {}, + "additionalProperties": { + "type": "object", + "required": [ + "diskType" + ], + "properties": { + "diskType": { + "description": "SeaweedFS disk type tag (e.g., \"ssd\", \"hdd\", \"nvme\").", + "type": "string" + }, + "replicas": { + "description": "Number of volume replicas. Defaults to volume.replicas (Simple) or zone.replicas/volume.replicas (MultiZone).", + "type": "integer" + }, + "resources": { + "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "properties": { + "cpu": { + "description": "Number of CPU cores allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Amount of memory allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted. Defaults to volume.resourcesPreset.", + "type": "string", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + }, + "size": { + "description": "Persistent Volume size. Defaults to volume.size (Simple) or zone.size/volume.size (MultiZone).", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "storageClass": { + "description": "Kubernetes StorageClass for the pool. Defaults to volume.storageClass.", + "type": "string" + } + } + } + }, + "replicas": { + "description": "Number of volume replicas.", + "type": "integer", + "default": 2 + }, + "resources": { + "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "Number of CPU cores allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Amount of memory allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted.", + "type": "string", + "default": "small", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + }, + "size": { + "description": "Persistent Volume size.", + "default": "10Gi", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "storageClass": { + "description": "StorageClass used to store the data.", + "type": "string", + "default": "" + }, + "zones": { + "description": "A map of zones for MultiZone topology. Each zone can have its own number of replicas and size.", + "type": "object", + "default": {}, + "additionalProperties": { + "type": "object", + "properties": { + "dataCenter": { + "description": "SeaweedFS data center name for this zone. Defaults to the zone name.", + "type": "string" + }, + "nodeSelector": { + "description": "YAML nodeSelector for this zone (default: topology.kubernetes.io/zone: \u003czoneName\u003e).", + "type": "string" + }, + "pools": { + "description": "A map of storage pools for this zone. Each pool creates a separate Volume StatefulSet per zone.", + "type": "object", + "additionalProperties": { + "type": "object", + "required": [ + "diskType" + ], + "properties": { + "diskType": { + "description": "SeaweedFS disk type tag (e.g., \"ssd\", \"hdd\", \"nvme\").", + "type": "string" + }, + "replicas": { + "description": "Number of volume replicas. Defaults to volume.replicas (Simple) or zone.replicas/volume.replicas (MultiZone).", + "type": "integer" + }, + "resources": { + "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "properties": { + "cpu": { + "description": "Number of CPU cores allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Amount of memory allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted. Defaults to volume.resourcesPreset.", + "type": "string", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + }, + "size": { + "description": "Persistent Volume size. Defaults to volume.size (Simple) or zone.size/volume.size (MultiZone).", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "storageClass": { + "description": "Kubernetes StorageClass for the pool. Defaults to volume.storageClass.", + "type": "string" + } + } + } + }, + "replicas": { + "description": "Number of replicas in the zone.", + "type": "integer" + }, + "size": { + "description": "Zone storage size.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "storageClass": { + "description": "StorageClass used to store zone data. Defaults to volume.storageClass.", + "type": "string" + } + } + } + } + } + }, + "s3": { + "description": "S3 service configuration.", + "type": "object", + "default": {}, + "properties": { + "replicas": { + "description": "Number of S3 replicas.", + "type": "integer", + "default": 2 + }, + "resources": { + "description": "Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.", + "type": "object", + "default": {}, + "properties": { + "cpu": { + "description": "Number of CPU cores allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + }, + "memory": { + "description": "Amount of memory allocated.", + "pattern": "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "x-kubernetes-int-or-string": true + } + } + }, + "resourcesPreset": { + "description": "Default sizing preset used when `resources` is omitted.", + "type": "string", + "default": "small", + "enum": [ + "nano", + "micro", + "small", + "medium", + "large", + "xlarge", + "2xlarge" + ] + } + } } -} \ No newline at end of file + } +} diff --git a/packages/extra/seaweedfs/values.yaml b/packages/extra/seaweedfs/values.yaml index 5921ac55..9965d5d0 100644 --- a/packages/extra/seaweedfs/values.yaml +++ b/packages/extra/seaweedfs/values.yaml @@ -1,12 +1,132 @@ +## ## @section Common parameters +## -## @param host The hostname used to access the grafana externally (defaults to 'grafana' subdomain for the tenant host). +## @param {string} [host] - The hostname used to access SeaweedFS externally (defaults to 's3' subdomain for the tenant host). host: "" -## @param replicas Persistent Volume size for NATS -## @param size Persistent Volume size -## @param storageClass StorageClass used to store the data +## @enum {string} Topology - The topology of the SeaweedFS cluster. +## @value Simple +## @value MultiZone +## @value Client + +## @param {Topology} topology="Simple" - The topology of the SeaweedFS cluster. +topology: Simple + +## @param {int} replicationFactor - Replication factor: number of replicas for each volume in the SeaweedFS cluster. +replicationFactor: 2 + ## -replicas: 2 -size: 10Gi -storageClass: "" +## @section SeaweedFS Components Configuration +## + +## @typedef {struct} Resources - Resource configuration. +## @field {quantity} [cpu] - Number of CPU cores allocated. +## @field {quantity} [memory] - Amount of memory allocated. + +## @enum {string} ResourcesPreset - Default sizing preset. +## @value nano +## @value micro +## @value small +## @value medium +## @value large +## @value xlarge +## @value 2xlarge + +## @typedef {struct} DB - Database configuration. +## @field {int} [replicas] - Number of database replicas. +## @field {quantity} [size] - Persistent Volume size. +## @field {string} [storageClass] - StorageClass used to store the data. +## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. +## @field {ResourcesPreset} [resourcesPreset] - Default sizing preset used when `resources` is omitted. + +## @param {DB} db - Database configuration. +db: + replicas: 2 + size: "10Gi" + storageClass: "" + resources: {} + resourcesPreset: "small" + +## @typedef {struct} Master - Master service configuration. +## @field {int} [replicas] - Number of master replicas. +## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. +## @field {ResourcesPreset} [resourcesPreset] - Default sizing preset used when `resources` is omitted. + +## @param {Master} [master] - Master service configuration. +master: + replicas: 3 + resources: {} + resourcesPreset: "small" + +## @typedef {struct} Filer - Filer service configuration. +## @field {int} [replicas] - Number of filer replicas. +## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. +## @field {ResourcesPreset} [resourcesPreset] - Default sizing preset used when `resources` is omitted. +## @field {string} [grpcHost] - The hostname used to expose or access the filer service externally. +## @field {int} [grpcPort] - The port used to access the filer service externally. +## @field {[]string} [whitelist] - A list of IP addresses or CIDR ranges that are allowed to access the filer service. + +## @param {Filer} [filer] - Filer service configuration. +filer: + replicas: 2 + resources: {} + resourcesPreset: "small" + grpcHost: "" + grpcPort: 443 + whitelist: [] + +## @typedef {struct} StoragePool - Storage pool configuration for separating buckets by disk type. +## @field {string} diskType - SeaweedFS disk type tag (e.g., "ssd", "hdd", "nvme"). +## @field {int} [replicas] - Number of volume replicas. Defaults to volume.replicas (Simple) or zone.replicas/volume.replicas (MultiZone). +## @field {quantity} [size] - Persistent Volume size. Defaults to volume.size (Simple) or zone.size/volume.size (MultiZone). +## @field {string} [storageClass] - Kubernetes StorageClass for the pool. Defaults to volume.storageClass. +## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. +## @field {ResourcesPreset} [resourcesPreset] - Default sizing preset used when `resources` is omitted. Defaults to volume.resourcesPreset. + +## @typedef {struct} Zone - Zone configuration. +## @field {int} [replicas] - Number of replicas in the zone. +## @field {quantity} [size] - Zone storage size. +## @field {string} [dataCenter] - SeaweedFS data center name for this zone. Defaults to the zone name. +## @field {string} [nodeSelector] - YAML nodeSelector for this zone (default: topology.kubernetes.io/zone: ). +## @field {string} [storageClass] - StorageClass used to store zone data. Defaults to volume.storageClass. +## @field {map[string]StoragePool} [pools] - A map of storage pools for this zone. Each pool creates a separate Volume StatefulSet per zone. +## NOTE: Zone-level resources/resourcesPreset are inherited from volume.* settings. Pools within a zone can define their own resources. + +## @typedef {struct} Volume - Volume service configuration. +## @field {int} [replicas] - Number of volume replicas. +## @field {quantity} [size] - Persistent Volume size. +## @field {string} [storageClass] - StorageClass used to store the data. +## @field {string} [diskType] - SeaweedFS disk type tag for the default volume servers (e.g., "hdd", "ssd"). +## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. +## @field {ResourcesPreset} [resourcesPreset] - Default sizing preset used when `resources` is omitted. +## @field {map[string]Zone} [zones] - A map of zones for MultiZone topology. Each zone can have its own number of replicas and size. +## @field {map[string]StoragePool} [pools] - A map of storage pools. Each pool creates a separate Volume StatefulSet with its own disk type. + +## @param {Volume} [volume] - Volume service configuration. +volume: + replicas: 2 + size: 10Gi + storageClass: "" + diskType: "" + resources: {} + resourcesPreset: "small" + zones: {} + pools: {} + #pools: + # fast: + # diskType: ssd + # replicas: 2 + # size: 50Gi + # storageClass: "local-nvme" + +## @typedef {struct} S3 - S3 service configuration. +## @field {int} [replicas] - Number of S3 replicas. +## @field {Resources} [resources] - Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied. +## @field {ResourcesPreset} [resourcesPreset] - Default sizing preset used when `resources` is omitted. + +## @param {S3} [s3] - S3 service configuration. +s3: + replicas: 2 + resources: {} + resourcesPreset: "small" diff --git a/packages/extra/versions_map b/packages/extra/versions_map deleted file mode 100644 index cb9683bb..00000000 --- a/packages/extra/versions_map +++ /dev/null @@ -1,57 +0,0 @@ -bootbox 0.1.0 45a7416c -bootbox 0.1.1 632224a3 -bootbox 0.2.0 HEAD -etcd 1.0.0 ca79f725 -etcd 2.0.0 c0685f43 -etcd 2.0.1 007d414f -etcd 2.1.0 25221fdc -etcd 2.2.0 71514249 -etcd 2.3.0 fde4bcfa -etcd 2.4.0 af48519d -etcd 2.5.0 24fa7222 -etcd 2.6.0 8c460528 -etcd 2.6.1 45a7416c -etcd 2.7.0 632224a3 -etcd 2.8.0 4369b031 -etcd 2.9.0 HEAD -info 1.0.0 93bdf411 -info 1.0.1 632224a3 -info 1.1.0 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 93bdf411 -ingress 1.6.0 632224a3 -ingress 1.7.0 HEAD -monitoring 1.0.0 d7cfa53c -monitoring 1.1.0 25221fdc -monitoring 1.2.0 f81be075 -monitoring 1.2.1 71514249 -monitoring 1.3.0 6c5cf5bf -monitoring 1.4.0 0f312d5c -monitoring 1.5.0 b8949304 -monitoring 1.5.1 c62a83a7 -monitoring 1.5.2 e44bece1 -monitoring 1.5.3 fde4bcfa -monitoring 1.5.4 d4634797 -monitoring 1.6.0 cb7b8158 -monitoring 1.6.1 4e68e65c -monitoring 1.7.0 2a976afe -monitoring 1.8.0 8c460528 -monitoring 1.8.1 8267072d -monitoring 1.9.0 45a7416c -monitoring 1.9.1 fd240701 -monitoring 1.9.2 f9f8bb2f -monitoring 1.10.0 632224a3 -monitoring 1.10.1 8c86905b -monitoring 1.11.0 4369b031 -monitoring 1.12.0 HEAD -seaweedfs 0.1.0 71514249 -seaweedfs 0.2.0 5fb9cfe3 -seaweedfs 0.2.1 fde4bcfa -seaweedfs 0.3.0 45a7416c -seaweedfs 0.4.0 632224a3 -seaweedfs 0.4.1 8c86905b -seaweedfs 0.5.0 HEAD diff --git a/packages/library/Makefile b/packages/library/Makefile index 42651d03..620dcf10 100644 --- a/packages/library/Makefile +++ b/packages/library/Makefile @@ -1,8 +1,12 @@ -OUT=../_out/repos/library -TMP := $(shell mktemp -d) +OUT=../../_out/repos/library +CHARTS := $(shell find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}') + +include ../../hack/common-envs.mk repo: - cd .. && ../hack/package_chart.sh library $(OUT) $(TMP) + rm -rf "$(OUT)" + helm package -d "$(OUT)" $(CHARTS) --version $(COZYSTACK_VERSION) + helm repo index "$(OUT)" -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 +fix-charts: + find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}' | while read i; do sed -i -e "s/^name: .*/name: $$i/" -e "s/^version: .*/version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process/g" "$$i/Chart.yaml"; done diff --git a/packages/library/cozy-lib/Chart.yaml b/packages/library/cozy-lib/Chart.yaml index 6aa01a14..0cda13e5 100644 --- a/packages/library/cozy-lib/Chart.yaml +++ b/packages/library/cozy-lib/Chart.yaml @@ -1,18 +1,5 @@ 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.3.0 +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/library/cozy-lib/Makefile b/packages/library/cozy-lib/Makefile index fa0142de..925f90c1 100644 --- a/packages/library/cozy-lib/Makefile +++ b/packages/library/cozy-lib/Makefile @@ -1,6 +1,8 @@ -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk generate: - readme-generator -v values.yaml -s values.schema.json -r README.md + cozyvalues-gen -v values.yaml -s values.schema.json -r README.md +test: + $(MAKE) -C ../../tests/cozy-lib-tests/ test diff --git a/packages/library/cozy-lib/templates/_cozyconfig.tpl b/packages/library/cozy-lib/templates/_cozyconfig.tpl index 559f7415..648b2617 100644 --- a/packages/library/cozy-lib/templates/_cozyconfig.tpl +++ b/packages/library/cozy-lib/templates/_cozyconfig.tpl @@ -1,7 +1,130 @@ +{{/* +Cluster-wide configuration helpers. +These helpers read from .Values._cluster which is populated via valuesFrom from Secret cozystack-values. +*/}} + +{{/* +Get the root host for the cluster. +Usage: {{ include "cozy-lib.root-host" . }} +*/}} +{{- define "cozy-lib.root-host" -}} +{{- (index .Values._cluster "root-host") | default "" }} +{{- end }} + +{{/* +Get the bundle name for the cluster. +Usage: {{ include "cozy-lib.bundle-name" . }} +*/}} +{{- define "cozy-lib.bundle-name" -}} +{{- (index .Values._cluster "bundle-name") | default "" }} +{{- end }} + +{{/* +Get the images registry. +Usage: {{ include "cozy-lib.images-registry" . }} +*/}} +{{- define "cozy-lib.images-registry" -}} +{{- (index .Values._cluster "images-registry") | default "" }} +{{- end }} + +{{/* +Get the ipv4 cluster CIDR. +Usage: {{ include "cozy-lib.ipv4-cluster-cidr" . }} +*/}} +{{- define "cozy-lib.ipv4-cluster-cidr" -}} +{{- (index .Values._cluster "ipv4-cluster-cidr") | default "" }} +{{- end }} + +{{/* +Get the ipv4 service CIDR. +Usage: {{ include "cozy-lib.ipv4-service-cidr" . }} +*/}} +{{- define "cozy-lib.ipv4-service-cidr" -}} +{{- (index .Values._cluster "ipv4-service-cidr") | default "" }} +{{- end }} + +{{/* +Get the ipv4 join CIDR. +Usage: {{ include "cozy-lib.ipv4-join-cidr" . }} +*/}} +{{- define "cozy-lib.ipv4-join-cidr" -}} +{{- (index .Values._cluster "ipv4-join-cidr") | default "" }} +{{- end }} + +{{/* +Get scheduling configuration. +Usage: {{ include "cozy-lib.scheduling" . }} +Returns: YAML string of scheduling configuration +*/}} +{{- define "cozy-lib.scheduling" -}} +{{- if .Values._cluster.scheduling }} +{{- .Values._cluster.scheduling | toYaml }} +{{- end }} +{{- end }} + +{{/* +Get branding configuration. +Usage: {{ include "cozy-lib.branding" . }} +Returns: YAML string of branding configuration +*/}} +{{- define "cozy-lib.branding" -}} +{{- if .Values._cluster.branding }} +{{- .Values._cluster.branding | toYaml }} +{{- end }} +{{- end }} + +{{/* +Namespace-specific configuration helpers. +These helpers read from .Values._namespace which is populated via valuesFrom from Secret cozystack-values. +*/}} + +{{/* +Get the host for this namespace. +Usage: {{ include "cozy-lib.ns-host" . }} +*/}} +{{- define "cozy-lib.ns-host" -}} +{{- .Values._namespace.host | default "" }} +{{- end }} + +{{/* +Get the etcd namespace reference. +Usage: {{ include "cozy-lib.ns-etcd" . }} +*/}} +{{- define "cozy-lib.ns-etcd" -}} +{{- .Values._namespace.etcd | default "" }} +{{- end }} + +{{/* +Get the ingress namespace reference. +Usage: {{ include "cozy-lib.ns-ingress" . }} +*/}} +{{- define "cozy-lib.ns-ingress" -}} +{{- .Values._namespace.ingress | default "" }} +{{- end }} + +{{/* +Get the monitoring namespace reference. +Usage: {{ include "cozy-lib.ns-monitoring" . }} +*/}} +{{- define "cozy-lib.ns-monitoring" -}} +{{- .Values._namespace.monitoring | default "" }} +{{- end }} + +{{/* +Get the seaweedfs namespace reference. +Usage: {{ include "cozy-lib.ns-seaweedfs" . }} +*/}} +{{- define "cozy-lib.ns-seaweedfs" -}} +{{- .Values._namespace.seaweedfs | default "" }} +{{- end }} + +{{/* +Legacy helper - kept for backward compatibility during migration. +Loads config into context. Deprecated: use direct .Values._cluster access instead. +*/}} {{- define "cozy-lib.loadCozyConfig" }} {{- include "cozy-lib.checkInput" . }} {{- if not (hasKey (index . 1) "cozyConfig") }} -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $_ := set (index . 1) "cozyConfig" $cozyConfig }} +{{- $_ := set (index . 1) "cozyConfig" (dict "data" ((index . 1).Values._cluster | default dict)) }} {{- end }} {{- end }} diff --git a/packages/library/cozy-lib/templates/_network.tpl b/packages/library/cozy-lib/templates/_network.tpl new file mode 100644 index 00000000..4908f7d5 --- /dev/null +++ b/packages/library/cozy-lib/templates/_network.tpl @@ -0,0 +1,23 @@ +{{- define "cozy-lib.network.defaultDisableLoadBalancerNodePorts" }} +{{/* Default behavior prior to introduction */}} +{{- `true` }} +{{- end }} + +{{/* +Invoke as {{ include "cozy-lib.network.disableLoadBalancerNodePorts" $ }}. +Detects whether the current load balancer class requires nodeports to function +correctly. Currently just checks if Hetzner's RobotLB is enabled, which does +require nodeports, and so, returns `false`. Otherwise assumes that metallb is +in use and returns `true`. +*/}} + +{{- define "cozy-lib.network.disableLoadBalancerNodePorts" }} +{{- include "cozy-lib.loadCozyConfig" (list "" .) }} +{{- $cozyConfig := index . "cozyConfig" }} +{{- if not $cozyConfig }} +{{- include "cozy-lib.network.defaultDisableLoadBalancerNodePorts" . }} +{{- else }} +{{- $enabledComponents := splitList "," ((index $cozyConfig.data "bundle-enable") | default "") }} +{{- not (has "robotlb" $enabledComponents) }} +{{- end }} +{{- end }} diff --git a/packages/library/cozy-lib/templates/_resources.tpl b/packages/library/cozy-lib/templates/_resources.tpl index ee0fb732..cb055ea1 100644 --- a/packages/library/cozy-lib/templates/_resources.tpl +++ b/packages/library/cozy-lib/templates/_resources.tpl @@ -154,7 +154,7 @@ {{- $resources := index . 1 }} {{- $global := index . 2 }} {{- $presetMap := include "cozy-lib.resources.unsanitizedPreset" $preset | fromYaml }} -{{- $mergedMap := deepCopy $resources | mergeOverwrite $presetMap }} +{{- $mergedMap := deepCopy (default (dict) $resources) | mergeOverwrite $presetMap }} {{- include "cozy-lib.resources.sanitize" (list $mergedMap $global) }} {{- end }} @@ -172,3 +172,48 @@ {{- $xmsMi := min (div $memoryLimitInt 4194304) (div $memoryRequestInt 1048576) }} {{- printf `-Xms%dm -Xmx%dm` $xmsMi $xmxMi }} {{- end }} + +{{- define "cozy-lib.resources.flatten" -}} +{{- $out := dict -}} +{{- $res := include "cozy-lib.resources.sanitize" . | fromYaml -}} +{{- range $section, $values := $res }} +{{- range $k, $v := $values }} +{{- with include "cozy-lib.resources.flattenResource" (list $section $k) }} +{{- $_ := set $out . $v }} +{{- end }} +{{- end }} +{{- end }} +{{- $out | toYaml }} +{{- end }} + +{{/* + This is a helper function that takes an argument like `list "limits" "services.loadbalancers"` + or `list "limits" "storage"` or `list "requests" "cpu"` and returns "services.loadbalancers", + "", and "requests.cpu", respectively, thus transforming them to an acceptable format for k8s + ResourceQuotas objects. +*/}} +{{- define "cozy-lib.resources.flattenResource" }} +{{- $rawQuotaKeys := list + "pods" + "services" + "services.loadbalancers" + "services.nodeports" + "services.clusterip" + "configmaps" + "secrets" + "persistentvolumeclaims" + "replicationcontrollers" + "resourcequotas" +-}} +{{- $section := index . 0 }} +{{- $type := index . 1 }} +{{- $out := "" }} +{{- if and (eq $section "limits") (eq $type "storage") }} +{{- $out = "" }} +{{- else if and (eq $section "limits") (has $type $rawQuotaKeys) }} +{{- $out = $type }} +{{- else if not (has $type $rawQuotaKeys) }} +{{- $out = printf "%s.%s" $section $type }} +{{- end }} +{{- $out -}} +{{- end }} diff --git a/packages/library/cozy-lib/templates/_strings.tpl b/packages/library/cozy-lib/templates/_strings.tpl new file mode 100644 index 00000000..0ba8153f --- /dev/null +++ b/packages/library/cozy-lib/templates/_strings.tpl @@ -0,0 +1,3 @@ +{{- define "cozy-lib.strings.hexToInt" }} +{{- printf "num: 0x%s" . | fromYaml | dig "num" 0 }} +{{- end }} diff --git a/packages/system/Makefile b/packages/system/Makefile index 2031c3a0..9173d353 100644 --- a/packages/system/Makefile +++ b/packages/system/Makefile @@ -1,12 +1,14 @@ OUT=../../_out/repos/system +CHARTS := $(shell grep -F 'version: 0.0.0' */Chart.yaml | cut -f1 -d/) +VERSIONED_CHARTS := $(shell grep '^version:' */Chart.yaml | grep -Fv '0.0.0' | cut -f1 -d/) -include ../../scripts/common-envs.mk +include ../../hack/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 $(COZYSTACK_VERSION) + helm package -d "$(OUT)" $(CHARTS) --version $(COZYSTACK_VERSION) + helm package -d "$(OUT)" $(VERSIONED_CHARTS) cd "$(OUT)" && helm repo index . -fix-chartnames: - find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}' | while read i; do sed -i "s/^name: .*/name: cozy-$$i/" "$$i/Chart.yaml"; done +fix-charts: + find . -maxdepth 2 -name Chart.yaml | awk -F/ '{print $$2}' | while read i; do sed -i -e "s/^name: .*/name: cozy-$$i/" -e "s/^version: .*/version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process/g" "$$i/Chart.yaml"; done diff --git a/packages/system/application-definition-crd/Chart.yaml b/packages/system/application-definition-crd/Chart.yaml new file mode 100644 index 00000000..f272bf43 --- /dev/null +++ b/packages/system/application-definition-crd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: application-definition-crd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/application-definition-crd/Makefile b/packages/system/application-definition-crd/Makefile new file mode 100644 index 00000000..adb378af --- /dev/null +++ b/packages/system/application-definition-crd/Makefile @@ -0,0 +1,4 @@ +export NAME=application-definition-crd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/application-definition-crd/definition/cozystack.io_applicationdefinitions.yaml b/packages/system/application-definition-crd/definition/cozystack.io_applicationdefinitions.yaml new file mode 100644 index 00000000..44d33865 --- /dev/null +++ b/packages/system/application-definition-crd/definition/cozystack.io_applicationdefinitions.yaml @@ -0,0 +1,638 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: applicationdefinitions.cozystack.io +spec: + group: cozystack.io + names: + kind: ApplicationDefinition + listKind: ApplicationDefinitionList + plural: applicationdefinitions + singular: applicationdefinition + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ApplicationDefinition is the Schema for the applicationdefinitions + API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + application: + description: Application configuration + properties: + kind: + description: Kind of the application, used for UI and API + type: string + openAPISchema: + description: OpenAPI schema for the application, used for API + validation + type: string + plural: + description: Plural name of the application, used for UI and API + type: string + singular: + description: Singular name of the application, used for UI and + API + type: string + required: + - kind + - openAPISchema + - plural + - singular + type: object + dashboard: + description: Dashboard configuration for this resource + properties: + category: + description: Category used to group resources in the UI (e.g., + "Storage", "Networking") + type: string + description: + description: Short description shown in catalogs or headers (e.g., + "S3 compatible storage") + type: string + icon: + description: Icon encoded as a string (e.g., inline SVG, base64, + or data URI) + type: string + keysOrder: + description: Order of keys in the YAML view + items: + items: + type: string + type: array + type: array + module: + description: Whether this resource is a module (tenant module) + type: boolean + name: + description: Hard-coded name used in the UI (e.g., "bucket") + type: string + plural: + description: Plural human-readable name (e.g., "Buckets") + type: string + singular: + description: Human-readable name shown in the UI (e.g., "Bucket") + type: string + singularResource: + description: Whether this resource is singular (not a collection) + in the UI + type: boolean + tabs: + description: Which tabs to show for this resource + items: + description: DashboardTab enumerates allowed UI tabs. + enum: + - workloads + - ingresses + - services + - secrets + - yaml + type: string + type: array + tags: + description: Free-form tags for search and filtering + items: + type: string + type: array + weight: + description: Order weight for sorting resources in the UI (lower + first) + type: integer + required: + - category + - plural + - singular + type: object + ingresses: + description: Ingress selectors + properties: + exclude: + description: |- + Exclude contains an array of resource selectors that target resources. + If a resource matches the selector in any of the elements in the array, it is + hidden from the user, regardless of the matches in the include array. + items: + description: "ApplicationDefinitionResourceSelector extends + metav1.LabelSelector with resourceNames support.\nA resource + matches this selector only if it satisfies ALL criteria:\n- + Label selector conditions (matchExpressions and matchLabels)\n- + AND has a name that matches one of the names in resourceNames + (if specified)\n\nThe resourceNames field supports Go templates + with the following variables available:\n- {{ .name }}: The + name of the managing application (from apps.cozystack.io/application.name)\n- + {{ .kind }}: The lowercased kind of the managing application + (from apps.cozystack.io/application.kind)\n- {{ .namespace + }}: The namespace of the resource being processed\n\nExample + YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t + \ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t + \ goodlabel: goodvalue\n\t resourceNames:\n\t - + \"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t + \ - \"specificname\"" + 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 + resourceNames: + description: |- + ResourceNames is a list of resource names to match + If specified, the resource must have one of these exact names to match the selector + items: + type: string + type: array + type: object + x-kubernetes-map-type: atomic + type: array + include: + description: |- + Include contains an array of resource selectors that target resources. + If a resource matches the selector in any of the elements in the array, and + matches none of the selectors in the exclude array that resource is marked + as a tenant resource and is visible to users. + items: + description: "ApplicationDefinitionResourceSelector extends + metav1.LabelSelector with resourceNames support.\nA resource + matches this selector only if it satisfies ALL criteria:\n- + Label selector conditions (matchExpressions and matchLabels)\n- + AND has a name that matches one of the names in resourceNames + (if specified)\n\nThe resourceNames field supports Go templates + with the following variables available:\n- {{ .name }}: The + name of the managing application (from apps.cozystack.io/application.name)\n- + {{ .kind }}: The lowercased kind of the managing application + (from apps.cozystack.io/application.kind)\n- {{ .namespace + }}: The namespace of the resource being processed\n\nExample + YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t + \ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t + \ goodlabel: goodvalue\n\t resourceNames:\n\t - + \"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t + \ - \"specificname\"" + 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 + resourceNames: + description: |- + ResourceNames is a list of resource names to match + If specified, the resource must have one of these exact names to match the selector + items: + type: string + type: array + type: object + x-kubernetes-map-type: atomic + type: array + type: object + release: + description: Release configuration + properties: + chartRef: + description: Reference to the chart source + properties: + apiVersion: + description: APIVersion of the referent. + type: string + kind: + description: Kind of the referent. + enum: + - OCIRepository + - HelmChart + - ExternalArtifact + type: string + name: + description: Name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace of the referent, defaults to the namespace of the Kubernetes + resource object that contains the reference. + maxLength: 63 + minLength: 1 + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + description: Labels for the release + type: object + prefix: + description: Prefix for the release name + type: string + required: + - chartRef + - prefix + type: object + secrets: + description: Secret selectors + properties: + exclude: + description: |- + Exclude contains an array of resource selectors that target resources. + If a resource matches the selector in any of the elements in the array, it is + hidden from the user, regardless of the matches in the include array. + items: + description: "ApplicationDefinitionResourceSelector extends + metav1.LabelSelector with resourceNames support.\nA resource + matches this selector only if it satisfies ALL criteria:\n- + Label selector conditions (matchExpressions and matchLabels)\n- + AND has a name that matches one of the names in resourceNames + (if specified)\n\nThe resourceNames field supports Go templates + with the following variables available:\n- {{ .name }}: The + name of the managing application (from apps.cozystack.io/application.name)\n- + {{ .kind }}: The lowercased kind of the managing application + (from apps.cozystack.io/application.kind)\n- {{ .namespace + }}: The namespace of the resource being processed\n\nExample + YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t + \ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t + \ goodlabel: goodvalue\n\t resourceNames:\n\t - + \"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t + \ - \"specificname\"" + 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 + resourceNames: + description: |- + ResourceNames is a list of resource names to match + If specified, the resource must have one of these exact names to match the selector + items: + type: string + type: array + type: object + x-kubernetes-map-type: atomic + type: array + include: + description: |- + Include contains an array of resource selectors that target resources. + If a resource matches the selector in any of the elements in the array, and + matches none of the selectors in the exclude array that resource is marked + as a tenant resource and is visible to users. + items: + description: "ApplicationDefinitionResourceSelector extends + metav1.LabelSelector with resourceNames support.\nA resource + matches this selector only if it satisfies ALL criteria:\n- + Label selector conditions (matchExpressions and matchLabels)\n- + AND has a name that matches one of the names in resourceNames + (if specified)\n\nThe resourceNames field supports Go templates + with the following variables available:\n- {{ .name }}: The + name of the managing application (from apps.cozystack.io/application.name)\n- + {{ .kind }}: The lowercased kind of the managing application + (from apps.cozystack.io/application.kind)\n- {{ .namespace + }}: The namespace of the resource being processed\n\nExample + YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t + \ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t + \ goodlabel: goodvalue\n\t resourceNames:\n\t - + \"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t + \ - \"specificname\"" + 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 + resourceNames: + description: |- + ResourceNames is a list of resource names to match + If specified, the resource must have one of these exact names to match the selector + items: + type: string + type: array + type: object + x-kubernetes-map-type: atomic + type: array + type: object + services: + description: Service selectors + properties: + exclude: + description: |- + Exclude contains an array of resource selectors that target resources. + If a resource matches the selector in any of the elements in the array, it is + hidden from the user, regardless of the matches in the include array. + items: + description: "ApplicationDefinitionResourceSelector extends + metav1.LabelSelector with resourceNames support.\nA resource + matches this selector only if it satisfies ALL criteria:\n- + Label selector conditions (matchExpressions and matchLabels)\n- + AND has a name that matches one of the names in resourceNames + (if specified)\n\nThe resourceNames field supports Go templates + with the following variables available:\n- {{ .name }}: The + name of the managing application (from apps.cozystack.io/application.name)\n- + {{ .kind }}: The lowercased kind of the managing application + (from apps.cozystack.io/application.kind)\n- {{ .namespace + }}: The namespace of the resource being processed\n\nExample + YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t + \ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t + \ goodlabel: goodvalue\n\t resourceNames:\n\t - + \"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t + \ - \"specificname\"" + 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 + resourceNames: + description: |- + ResourceNames is a list of resource names to match + If specified, the resource must have one of these exact names to match the selector + items: + type: string + type: array + type: object + x-kubernetes-map-type: atomic + type: array + include: + description: |- + Include contains an array of resource selectors that target resources. + If a resource matches the selector in any of the elements in the array, and + matches none of the selectors in the exclude array that resource is marked + as a tenant resource and is visible to users. + items: + description: "ApplicationDefinitionResourceSelector extends + metav1.LabelSelector with resourceNames support.\nA resource + matches this selector only if it satisfies ALL criteria:\n- + Label selector conditions (matchExpressions and matchLabels)\n- + AND has a name that matches one of the names in resourceNames + (if specified)\n\nThe resourceNames field supports Go templates + with the following variables available:\n- {{ .name }}: The + name of the managing application (from apps.cozystack.io/application.name)\n- + {{ .kind }}: The lowercased kind of the managing application + (from apps.cozystack.io/application.kind)\n- {{ .namespace + }}: The namespace of the resource being processed\n\nExample + YAML:\n\n\tsecrets:\n\t include:\n\t - matchExpressions:\n\t + \ - key: badlabel\n\t operator: DoesNotExist\n\t matchLabels:\n\t + \ goodlabel: goodvalue\n\t resourceNames:\n\t - + \"{{ .name }}-secret\"\n\t - \"{{ .kind }}-{{ .name }}-tls\"\n\t + \ - \"specificname\"" + 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 + resourceNames: + description: |- + ResourceNames is a list of resource names to match + If specified, the resource must have one of these exact names to match the selector + items: + type: string + type: array + type: object + x-kubernetes-map-type: atomic + type: array + type: object + required: + - application + - release + type: object + type: object + served: true + storage: true diff --git a/packages/system/application-definition-crd/templates/crd.yaml b/packages/system/application-definition-crd/templates/crd.yaml new file mode 100644 index 00000000..3c94f229 --- /dev/null +++ b/packages/system/application-definition-crd/templates/crd.yaml @@ -0,0 +1,2 @@ +--- +{{ .Files.Get "definition/cozystack.io_applicationdefinitions.yaml" }} diff --git a/packages/system/application-definition-crd/values.yaml b/packages/system/application-definition-crd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/application-definition-crd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/backup-controller/Chart.yaml b/packages/system/backup-controller/Chart.yaml new file mode 100644 index 00000000..fd135712 --- /dev/null +++ b/packages/system/backup-controller/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-backup-controller +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/backup-controller/Makefile b/packages/system/backup-controller/Makefile new file mode 100644 index 00000000..472a99ba --- /dev/null +++ b/packages/system/backup-controller/Makefile @@ -0,0 +1,18 @@ +NAME=backup-controller +NAMESPACE=cozy-backup-controller + +include ../../../hack/common-envs.mk +include ../../../hack/package.mk + +image: image-backup-controller + +image-backup-controller: + docker buildx build -f images/backup-controller/Dockerfile ../../.. \ + --tag $(REGISTRY)/backup-controller:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/backup-controller:latest \ + --cache-to type=inline \ + --metadata-file images/backup-controller.json \ + $(BUILDX_ARGS) + IMAGE="$(REGISTRY)/backup-controller:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/backup-controller.json -o json -r)" \ + yq -i '.backupController.image = strenv(IMAGE)' values.yaml + rm -f images/backup-controller.json diff --git a/packages/system/backup-controller/definitions/.gitattributes b/packages/system/backup-controller/definitions/.gitattributes new file mode 100644 index 00000000..6de56dcb --- /dev/null +++ b/packages/system/backup-controller/definitions/.gitattributes @@ -0,0 +1,2 @@ +* linguist-generated +.gitattributes -linguist-generated diff --git a/packages/system/backup-controller/definitions/backups.cozystack.io_backupclasses.yaml b/packages/system/backup-controller/definitions/backups.cozystack.io_backupclasses.yaml new file mode 100644 index 00000000..4af8cf7d --- /dev/null +++ b/packages/system/backup-controller/definitions/backups.cozystack.io_backupclasses.yaml @@ -0,0 +1,171 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: backupclasses.backups.cozystack.io +spec: + group: backups.cozystack.io + names: + kind: BackupClass + listKind: BackupClassList + plural: backupclasses + singular: backupclass + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + BackupClass defines a class of backup configurations that can be referenced + by BackupJob and Plan resources. It encapsulates strategy and storage configuration + per application type. + 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: BackupClassSpec defines the desired state of a BackupClass. + properties: + strategies: + description: Strategies is a list of backup strategies, each matching + a specific application type. + items: + description: BackupClassStrategy defines a backup strategy for a + specific application type. + properties: + application: + description: Application specifies which application types this + strategy applies to. + properties: + apiGroup: + description: |- + APIGroup is the API group of the application. + If not specified, defaults to "apps.cozystack.io". + type: string + kind: + description: Kind is the kind of the application (e.g., + VirtualMachine, MariaDB). + type: string + required: + - kind + type: object + parameters: + additionalProperties: + type: string + description: |- + Parameters holds strategy-specific and storage-specific parameters. + Common parameters include: + - backupStorageLocationName: Name of Velero BackupStorageLocation + type: object + strategyRef: + description: StrategyRef references the driver-specific BackupStrategy + (e.g., Velero). + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + required: + - application + - strategyRef + type: object + type: array + required: + - strategies + type: object + status: + description: BackupClassStatus defines the observed state of a BackupClass. + properties: + conditions: + description: Conditions represents the latest available observations + of a BackupClass's state. + 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 + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/backup-controller/definitions/backups.cozystack.io_backupjobs.yaml b/packages/system/backup-controller/definitions/backups.cozystack.io_backupjobs.yaml new file mode 100644 index 00000000..7a0ed6f5 --- /dev/null +++ b/packages/system/backup-controller/definitions/backups.cozystack.io_backupjobs.yaml @@ -0,0 +1,208 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: backupjobs.backups.cozystack.io +spec: + group: backups.cozystack.io + names: + kind: BackupJob + listKind: BackupJobList + plural: backupjobs + singular: backupjob + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.phase + name: Phase + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + BackupJob represents a single execution of a backup. + It is typically created by a Plan controller when a schedule fires. + 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: BackupJobSpec describes the execution of a single backup + operation. + properties: + applicationRef: + description: |- + ApplicationRef holds a reference to the managed application whose state + is being backed up. + If apiGroup is not specified, it defaults to "apps.cozystack.io". + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + backupClassName: + description: |- + BackupClassName references a BackupClass that contains strategy and storage configuration. + The BackupClass will be resolved to determine the appropriate strategy and storage + based on the ApplicationRef. + This field is immutable once the BackupJob is created. + minLength: 1 + type: string + x-kubernetes-validations: + - message: backupClassName is immutable + rule: self == oldSelf + planRef: + description: |- + PlanRef refers to the Plan that requested this backup run. + For ad-hoc/manual backups, this can be omitted. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + required: + - applicationRef + - backupClassName + type: object + status: + description: BackupJobStatus represents the observed state of a BackupJob. + properties: + backupRef: + description: BackupRef refers to the Backup object created by this + run, if any. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + completedAt: + description: |- + CompletedAt is the time at which the backup run completed (successfully + or otherwise). + format: date-time + type: string + conditions: + description: Conditions represents the latest available observations + of a BackupJob's state. + 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 + type: array + message: + description: |- + Message is a human-readable message indicating details about why the + backup run is in its current phase, if any. + type: string + phase: + description: |- + Phase is a high-level summary of the run's state. + Typical values: Pending, Running, Succeeded, Failed. + type: string + startedAt: + description: StartedAt is the time at which the backup run started. + format: date-time + type: string + type: object + type: object + selectableFields: + - jsonPath: .spec.applicationRef.apiGroup + - jsonPath: .spec.applicationRef.kind + - jsonPath: .spec.applicationRef.name + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/backup-controller/definitions/backups.cozystack.io_backups.yaml b/packages/system/backup-controller/definitions/backups.cozystack.io_backups.yaml new file mode 100644 index 00000000..d48df533 --- /dev/null +++ b/packages/system/backup-controller/definitions/backups.cozystack.io_backups.yaml @@ -0,0 +1,223 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: backups.backups.cozystack.io +spec: + group: backups.cozystack.io + names: + kind: Backup + listKind: BackupList + plural: backups + singular: backup + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Backup represents a single backup artifact for a given application. + 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: BackupSpec describes an immutable backup artifact produced + by a BackupJob. + properties: + applicationRef: + description: ApplicationRef refers to the application that was backed + up. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + driverMetadata: + additionalProperties: + type: string + description: |- + DriverMetadata holds driver-specific, opaque metadata associated with + this backup (for example snapshot IDs, schema versions, etc.). + This data is not interpreted by the core backup controllers. + type: object + planRef: + description: |- + PlanRef refers to the Plan that produced this backup, if any. + For manually triggered backups, this can be omitted. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + strategyRef: + description: |- + StrategyRef refers to the driver-specific BackupStrategy that was used + to create this backup. This allows the driver to later perform restores. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + takenAt: + description: |- + TakenAt is the time at which the backup was taken (as reported by the + driver). It may differ slightly from metadata.creationTimestamp. + format: date-time + type: string + required: + - applicationRef + - strategyRef + - takenAt + type: object + status: + description: BackupStatus represents the observed state of a Backup. + properties: + artifact: + description: Artifact describes the stored backup object, if available. + properties: + checksum: + description: |- + Checksum is the checksum of the artifact, if computed. + For example: "sha256:". + type: string + sizeBytes: + description: SizeBytes is the size of the artifact in bytes, if + known. + format: int64 + type: integer + uri: + description: |- + URI is a driver-/storage-specific URI pointing to the backup artifact. + For example: s3://bucket/prefix/file.tar.gz + type: string + required: + - uri + type: object + conditions: + description: Conditions represents the latest available observations + of a Backup's state. + 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 + type: array + phase: + description: |- + Phase is a simple, high-level summary of the backup's state. + Typical values are: Pending, Ready, Failed. + type: string + underlyingResources: + description: |- + UnderlyingResources holds application-specific resource metadata discovered + during backup (e.g., VM disks, network configuration). The payload is a + self-typed JSON object carrying an inlined TypeMeta (kind/apiVersion) so + the consuming controller can dispatch on the application kind. + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + selectableFields: + - jsonPath: .spec.applicationRef.apiGroup + - jsonPath: .spec.applicationRef.kind + - jsonPath: .spec.applicationRef.name + served: true + storage: true diff --git a/packages/system/backup-controller/definitions/backups.cozystack.io_plans.yaml b/packages/system/backup-controller/definitions/backups.cozystack.io_plans.yaml new file mode 100644 index 00000000..94c09334 --- /dev/null +++ b/packages/system/backup-controller/definitions/backups.cozystack.io_plans.yaml @@ -0,0 +1,162 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: plans.backups.cozystack.io +spec: + group: backups.cozystack.io + names: + kind: Plan + listKind: PlanList + plural: plans + singular: plan + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + Plan describes the schedule, method and storage location for the + backup of a given target application. + 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: |- + PlanSpec references the storage, the strategy, the application to be + backed up and specifies the timetable on which the backups will run. + properties: + applicationRef: + description: |- + ApplicationRef holds a reference to the managed application, + whose state and configuration must be backed up. + If apiGroup is not specified, it defaults to "apps.cozystack.io". + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + backupClassName: + description: |- + BackupClassName references a BackupClass that contains strategy and storage configuration. + The BackupClass will be resolved to determine the appropriate strategy and storage + based on the ApplicationRef. + type: string + schedule: + description: Schedule specifies when backup copies are created. + properties: + cron: + description: |- + Cron contains the cron spec for scheduling backups. Must be + specified if the schedule type is `cron`. Since only `cron` is + supported, omitting this field is not allowed. + type: string + type: + description: |- + Type is the type of schedule specification. Supported values are + [`cron`]. If omitted, defaults to `cron`. + type: string + type: object + required: + - applicationRef + - backupClassName + - schedule + type: object + status: + properties: + conditions: + 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 + type: array + type: object + type: object + selectableFields: + - jsonPath: .spec.applicationRef.apiGroup + - jsonPath: .spec.applicationRef.kind + - jsonPath: .spec.applicationRef.name + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/backup-controller/definitions/backups.cozystack.io_restorejobs.yaml b/packages/system/backup-controller/definitions/backups.cozystack.io_restorejobs.yaml new file mode 100644 index 00000000..b9465994 --- /dev/null +++ b/packages/system/backup-controller/definitions/backups.cozystack.io_restorejobs.yaml @@ -0,0 +1,180 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: restorejobs.backups.cozystack.io +spec: + group: backups.cozystack.io + names: + kind: RestoreJob + listKind: RestoreJobList + plural: restorejobs + singular: restorejob + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.phase + name: Phase + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: RestoreJob represents a single execution of a restore from a + Backup. + 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: RestoreJobSpec describes the execution of a single restore + operation. + properties: + backupRef: + description: BackupRef refers to the Backup that should be restored. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + options: + description: |- + Options is a driver-specific blob of restore options, typed based on + targetApplicationRef and the current controller implementation. + type: object + x-kubernetes-preserve-unknown-fields: true + targetApplicationRef: + description: |- + TargetApplicationRef refers to the application into which the backup + should be restored. If omitted, the driver SHOULD restore into the same + application as referenced by backup.spec.applicationRef. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + required: + - backupRef + type: object + status: + description: RestoreJobStatus represents the observed state of a RestoreJob. + properties: + completedAt: + description: |- + CompletedAt is the time at which the restore run completed (successfully + or otherwise). + format: date-time + type: string + conditions: + description: Conditions represents the latest available observations + of a RestoreJob's state. + 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 + type: array + message: + description: |- + Message is a human-readable message indicating details about why the + restore run is in its current phase, if any. + type: string + phase: + description: |- + Phase is a high-level summary of the run's state. + Typical values: Pending, Running, Succeeded, Failed. + type: string + startedAt: + description: StartedAt is the time at which the restore run started. + format: date-time + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/backup-controller/images/backup-controller/Dockerfile b/packages/system/backup-controller/images/backup-controller/Dockerfile new file mode 100644 index 00000000..a48bc4f9 --- /dev/null +++ b/packages/system/backup-controller/images/backup-controller/Dockerfile @@ -0,0 +1,23 @@ +FROM golang:1.25-alpine AS builder + +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /workspace + +COPY go.mod go.sum ./ +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go mod download + +COPY api api/ +COPY pkg pkg/ +COPY cmd cmd/ +COPY internal internal/ + +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -ldflags="-extldflags=-static" -o /backup-controller cmd/backup-controller/main.go + +FROM scratch + +COPY --from=builder /backup-controller /backup-controller +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt + +ENTRYPOINT ["/backup-controller"] diff --git a/packages/system/backup-controller/templates/crds.yaml b/packages/system/backup-controller/templates/crds.yaml new file mode 100644 index 00000000..32b438c1 --- /dev/null +++ b/packages/system/backup-controller/templates/crds.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "definitions/*.yaml" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/backup-controller/templates/deployment.yaml b/packages/system/backup-controller/templates/deployment.yaml new file mode 100644 index 00000000..f23f3f81 --- /dev/null +++ b/packages/system/backup-controller/templates/deployment.yaml @@ -0,0 +1,57 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: backup-controller + labels: + app: backup-controller +spec: + replicas: {{ .Values.backupController.replicas }} + selector: + matchLabels: + app: backup-controller + template: + metadata: + labels: + app: backup-controller + spec: + tolerations: + - key: "node-role.kubernetes.io/control-plane" + operator: "Exists" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/master" + operator: "Exists" + effect: "NoSchedule" + serviceAccountName: backup-controller + containers: + - name: backup-controller + image: "{{ .Values.backupController.image }}" + args: + - --leader-elect + {{- if .Values.backupController.metrics.enable }} + - --metrics-bind-address={{ .Values.backupController.metrics.bindAddress }} + {{- end }} + {{- if .Values.backupController.debug }} + - --zap-log-level=debug + {{- else }} + - --zap-log-level=info + {{- end }} + ports: + - name: metrics + containerPort: {{ splitList ":" .Values.backupController.metrics.bindAddress | mustLast }} + - name: health + containerPort: 8081 + readinessProbe: + httpGet: + path: /readyz + port: health + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /healthz + port: health + initialDelaySeconds: 15 + periodSeconds: 20 + {{- with .Values.backupController.resources }} + resources: {{- . | toYaml | nindent 10 }} + {{- end }} diff --git a/packages/system/backup-controller/templates/rbac-bind.yaml b/packages/system/backup-controller/templates/rbac-bind.yaml new file mode 100644 index 00000000..cbe9b5b8 --- /dev/null +++ b/packages/system/backup-controller/templates/rbac-bind.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: backups.cozystack.io:core-controller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: backups.cozystack.io:core-controller +subjects: +- kind: ServiceAccount + name: backup-controller + namespace: {{ .Release.Namespace }} diff --git a/packages/system/backup-controller/templates/rbac.yaml b/packages/system/backup-controller/templates/rbac.yaml new file mode 100644 index 00000000..da2460c0 --- /dev/null +++ b/packages/system/backup-controller/templates/rbac.yaml @@ -0,0 +1,23 @@ +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: backups.cozystack.io:core-controller +rules: +# Plan: reconcile schedule and update status +- apiGroups: ["backups.cozystack.io"] + resources: ["plans"] + verbs: ["get", "list", "watch"] +- apiGroups: ["backups.cozystack.io"] + resources: ["plans/status"] + verbs: ["get", "update", "patch"] +# BackupJob: create when schedule fires (status is updated by backupstrategy-controller) +- apiGroups: ["backups.cozystack.io"] + resources: ["backupjobs"] + verbs: ["create", "get", "list", "watch"] +# Leader election (--leader-elect) +- apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "list", "watch", "create", "update", "patch"] +- apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] diff --git a/packages/system/backup-controller/templates/sa.yaml b/packages/system/backup-controller/templates/sa.yaml new file mode 100644 index 00000000..4a180dd2 --- /dev/null +++ b/packages/system/backup-controller/templates/sa.yaml @@ -0,0 +1,4 @@ +kind: ServiceAccount +apiVersion: v1 +metadata: + name: backup-controller diff --git a/packages/system/backup-controller/templates/tenant-clusterroles.yaml b/packages/system/backup-controller/templates/tenant-clusterroles.yaml new file mode 100644 index 00000000..1e9eb775 --- /dev/null +++ b/packages/system/backup-controller/templates/tenant-clusterroles.yaml @@ -0,0 +1,44 @@ +--- +# == backup view cluster role == +# Aggregated into cozy-tenant-view (and consequently use, admin, super-admin) +# Provides read-only access to all backup resources +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cozy:backups:view + labels: + rbac.cozystack.io/aggregate-to-tenant-view: "true" +rules: +- apiGroups: ["backups.cozystack.io"] + resources: + - plans + - backupjobs + - restorejobs + - backups + - backupclasses + verbs: + - get + - list + - watch +--- +# == backup admin cluster role == +# Aggregated into cozy-tenant-admin (and consequently super-admin) +# Provides write access to plans, backupjobs, restorejobs +# Backups and backupclasses remain read-only (inherited from view) +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cozy:backups:admin + labels: + rbac.cozystack.io/aggregate-to-tenant-admin: "true" +rules: +- apiGroups: ["backups.cozystack.io"] + resources: + - plans + - backupjobs + - restorejobs + verbs: + - create + - update + - patch + - delete diff --git a/packages/system/backup-controller/values.yaml b/packages/system/backup-controller/values.yaml new file mode 100644 index 00000000..34e033ce --- /dev/null +++ b/packages/system/backup-controller/values.yaml @@ -0,0 +1,14 @@ +backupController: + image: "ghcr.io/cozystack/cozystack/backup-controller:v1.3.0@sha256:e1a083dc92f26dfef004f47c1cd20a6357174aad835004f58e751c494b76649a" + replicas: 2 + debug: false + metrics: + enabled: true + bindAddress: ":8443" + resources: + requests: + cpu: 10m + memory: 64Mi + limits: + cpu: 500m + memory: 128Mi diff --git a/packages/system/backupstrategy-controller/Chart.yaml b/packages/system/backupstrategy-controller/Chart.yaml new file mode 100644 index 00000000..bf556f3b --- /dev/null +++ b/packages/system/backupstrategy-controller/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-backupstrategy-controller +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/backupstrategy-controller/Makefile b/packages/system/backupstrategy-controller/Makefile new file mode 100644 index 00000000..e6f23ca7 --- /dev/null +++ b/packages/system/backupstrategy-controller/Makefile @@ -0,0 +1,18 @@ +NAME=backupstrategy-controller +NAMESPACE=cozy-backup-controller + +include ../../../hack/common-envs.mk +include ../../../hack/package.mk + +image: image-backupstrategy-controller + +image-backupstrategy-controller: + docker buildx build -f images/backupstrategy-controller/Dockerfile ../../.. \ + --tag $(REGISTRY)/backupstrategy-controller:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/backupstrategy-controller:latest \ + --cache-to type=inline \ + --metadata-file images/backupstrategy-controller.json \ + $(BUILDX_ARGS) + IMAGE="$(REGISTRY)/backupstrategy-controller:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/backupstrategy-controller.json -o json -r)" \ + yq -i '.backupStrategyController.image = strenv(IMAGE)' values.yaml + rm -f images/backupstrategy-controller.json diff --git a/packages/system/backupstrategy-controller/definitions/.gitattributes b/packages/system/backupstrategy-controller/definitions/.gitattributes new file mode 100644 index 00000000..f581feca --- /dev/null +++ b/packages/system/backupstrategy-controller/definitions/.gitattributes @@ -0,0 +1 @@ +*.yaml linguist-generated diff --git a/packages/system/backupstrategy-controller/definitions/strategy.backups.cozystack.io_jobs.yaml b/packages/system/backupstrategy-controller/definitions/strategy.backups.cozystack.io_jobs.yaml new file mode 100644 index 00000000..b4fea209 --- /dev/null +++ b/packages/system/backupstrategy-controller/definitions/strategy.backups.cozystack.io_jobs.yaml @@ -0,0 +1,8527 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: jobs.strategy.backups.cozystack.io +spec: + group: strategy.backups.cozystack.io + names: + kind: Job + listKind: JobList + plural: jobs + singular: job + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Job defines a backup strategy using a one-shot Job + 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: JobSpec specifies the desired behavior of a backup job. + properties: + template: + description: |- + Template holds a PodTemplateSpec with the right shape to + run a single pod to completion and create a tarball with + a given apps data. Helm-like Go templates are supported. + The values of the source application are available under + `.Values`. `.Release.Name` and `.Release.Namespace` are + also exported. + properties: + metadata: + description: |- + Standard object's metadata. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + type: object + spec: + description: |- + Specification of the desired behavior of the pod. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + activeDeadlineSeconds: + description: |- + Optional duration in seconds the pod may be active on the node relative to + StartTime before the system will actively try to mark it failed and kill associated containers. + Value must be a positive integer. + format: int64 + type: integer + affinity: + description: If specified, the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling rules + for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + automountServiceAccountToken: + description: AutomountServiceAccountToken indicates whether + a service account token should be automatically mounted. + type: boolean + containers: + description: |- + List of containers belonging to the pod. + Containers cannot currently be added or removed. + There must be at least one container in a Pod. + Cannot be updated. + items: + description: A single application container that you want + to run within a pod. + properties: + args: + description: |- + Arguments to the entrypoint. + The container image's CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + description: |- + Entrypoint array. Not executed within a shell. + The container image's ENTRYPOINT is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + description: |- + List of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: |- + Name of the environment variable. + May consist of any printable ASCII characters except '='. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + description: |- + FileKeyRef selects a key of the env file. + Requires the EnvFiles feature gate to be enabled. + properties: + key: + description: |- + The key within the env file. An invalid key will prevent the pod from starting. + The keys defined within a source may consist of any printable ASCII characters except '='. + During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. + type: string + optional: + default: false + description: |- + Specify whether the file or its key must be defined. If the file or key + does not exist, then the env var is not published. + If optional is set to true and the specified key does not exist, + the environment variable will not be set in the Pod's containers. + + If optional is set to false and the specified key does not exist, + an error will be returned during Pod creation. + type: boolean + path: + description: |- + The path within the volume from which to select the file. + Must be relative and may not contain the '..' path or start with '..'. + type: string + volumeName: + description: The name of the volume mount + containing the env file. + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in + the pod's namespace + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + description: |- + List of sources to populate environment variables in the container. + The keys defined within a source may consist of any printable ASCII characters except '='. + When a key exists in multiple + sources, the value associated with the last source will take precedence. + 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 or Secrets + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: |- + Optional text to prepend to the name of each environment variable. + May consist of any printable ASCII characters except '='. + type: string + secretRef: + description: The Secret to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + description: |- + Container image name. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + imagePullPolicy: + description: |- + Image pull policy. + One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + type: string + lifecycle: + description: |- + Actions that the management system should take in response to container lifecycle events. + Cannot be updated. + properties: + postStart: + description: |- + PostStart is called immediately after a container is created. If the handler fails, + the container is terminated and restarted according to its restart policy. + Other management of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies a command to execute + in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents a duration that + the container should sleep. + properties: + seconds: + description: Seconds is the number of seconds + to sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for backward compatibility. There is no validation of this field and + lifecycle hooks will fail at runtime when it is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: |- + PreStop is called immediately before a container is terminated due to an + API request or management event such as liveness/startup probe failure, + preemption, resource contention, etc. The handler is not called if the + container crashes or exits. The Pod's termination grace period countdown begins before the + PreStop hook is executed. Regardless of the outcome of the handler, the + container will eventually terminate within the Pod's termination grace + period (unless delayed by finalizers). Other management of the container blocks until the hook completes + or until the termination grace period is reached. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies a command to execute + in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents a duration that + the container should sleep. + properties: + seconds: + description: Seconds is the number of seconds + to sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for backward compatibility. There is no validation of this field and + lifecycle hooks will fail at runtime when it is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - 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: |- + Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies a command to execute + in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + name: + description: |- + Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: |- + List of ports to expose from the container. Not specifying a port here + DOES NOT prevent that port from being exposed. Any port which is + listening on the default "0.0.0.0" address inside a container will be + accessible from the network. + Modifying this array with strategic merge patch may corrupt the data. + For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port + in a single container. + properties: + containerPort: + description: |- + Number of port to expose on the pod's IP address. + This must be a valid port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: |- + Number of port to expose on the host. + If specified, this must be a valid port number, 0 < x < 65536. + If HostNetwork is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: |- + If specified, this must be an IANA_SVC_NAME and unique within the pod. Each + named port in a pod must have a unique name. Name for the port that can be + referred to by services. + type: string + protocol: + default: TCP + description: |- + Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: |- + Periodic probe of container service readiness. + Container will be removed from service endpoints if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies a command to execute + in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents resource + resize policy for the container. + properties: + resourceName: + description: |- + Name of the resource to which this resource resize policy applies. + Supported values: cpu, memory. + type: string + restartPolicy: + description: |- + Restart policy to apply when specified resource is resized. + If not specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: |- + Compute Resources required by this container. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry + in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + restartPolicy: + description: |- + RestartPolicy defines the restart behavior of individual containers in a pod. + This overrides the pod-level restart policy. When this field is not specified, + the restart behavior is defined by the Pod's restart policy and the container type. + Additionally, setting the RestartPolicy as "Always" for the init container will + have the following effect: + this init container will be continually restarted on + exit until all regular containers have terminated. Once all regular + containers have completed, all init containers with restartPolicy "Always" + will be shut down. This lifecycle differs from normal init containers and + is often referred to as a "sidecar" container. Although this init + container still starts in the init container sequence, it does not wait + for the container to complete before proceeding to the next init + container. Instead, the next init container starts immediately after this + init container is started, or after any startupProbe has successfully + completed. + type: string + restartPolicyRules: + description: |- + Represents a list of rules to be checked to determine if the + container should be restarted on exit. The rules are evaluated in + order. Once a rule matches a container exit condition, the remaining + rules are ignored. If no rule matches the container exit condition, + the Container-level restart policy determines the whether the container + is restarted or not. Constraints on the rules: + - At most 20 rules are allowed. + - Rules can have the same action. + - Identical rules are not forbidden in validations. + When rules are specified, container MUST set RestartPolicy explicitly + even it if matches the Pod's RestartPolicy. + items: + description: ContainerRestartRule describes how a + container exit is handled. + properties: + action: + description: |- + Specifies the action taken on a container exit if the requirements + are satisfied. The only possible value is "Restart" to restart the + container. + type: string + exitCodes: + description: Represents the exit codes to check + on container exits. + properties: + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. Possible values are: + - In: the requirement is satisfied if the container exit code is in the + set of specified values. + - NotIn: the requirement is satisfied if the container exit code is + not in the set of specified values. + type: string + values: + description: |- + Specifies the set of values to check for container exit codes. + At most 255 elements are allowed. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + description: |- + SecurityContext defines the security options the container should be run with. + If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + properties: + allowPrivilegeEscalation: + description: |- + AllowPrivilegeEscalation controls whether a process can gain more + privileges than its parent process. This bool directly controls if + the no_new_privs flag will be set on the container process. + AllowPrivilegeEscalation is true always when the container is: + 1) run as Privileged + 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows. + type: boolean + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by this container. If set, this profile + overrides the pod's appArmorProfile. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + capabilities: + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. + Note that this field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: |- + procMount denotes the type of proc mount to use for the containers. + The default value is Default which uses the container runtime defaults for + readonly paths and masked paths. + This requires the ProcMountType feature flag to be enabled. + Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: |- + Whether this container has a read-only root filesystem. + Default is false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that + applies to the container. + type: string + role: + description: Role is a SELinux role label that + applies to the container. + type: string + type: + description: Type is a SELinux type label that + applies to the container. + type: string + user: + description: User is a SELinux user label that + applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by this container. If seccomp options are + provided at both the pod & container level, the container options + override the pod options. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name + of the GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + startupProbe: + description: |- + StartupProbe indicates that the Pod has successfully initialized. + If specified, no other probes are executed until this completes successfully. + If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. + This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, + when it might take a long time to load data or warm a cache, than during steady-state operation. + This cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies a command to execute + in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + stdin: + description: |- + Whether this container should allocate a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will always result in EOF. + Default is false. + type: boolean + stdinOnce: + description: |- + Whether the container runtime should close the stdin channel after it has been opened by + a single attach. When stdin is true the stdin stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the + first client attaches to stdin, and then remains open and accepts data until the client disconnects, + at which time stdin is closed and remains closed until the container is restarted. If this + flag is false, a container processes that reads from stdin will never receive an EOF. + Default is false + type: boolean + terminationMessagePath: + description: |- + Optional: Path at which the file to which the container's termination message + will be written is mounted into the container's filesystem. + Message written is intended to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. The total message length across + all containers will be limited to 12kb. + Defaults to /dev/termination-log. + Cannot be updated. + type: string + terminationMessagePolicy: + description: |- + Indicate how the termination message should be populated. File will use the contents of + terminationMessagePath to populate the container status message on both success and failure. + FallbackToLogsOnError will use the last chunk of container log output if the termination + message file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, whichever is smaller. + Defaults to File. + Cannot be updated. + type: string + tty: + description: |- + Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. + Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices + to be used by the container. + items: + description: volumeDevice describes a mapping of a + raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside of + the container that the device will be mapped + to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + description: |- + Pod volumes to mount into the container's filesystem. + Cannot be updated. + items: + description: VolumeMount describes a mounting of a + Volume within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. + When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified + (which defaults to None). + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + recursiveReadOnly: + description: |- + RecursiveReadOnly specifies whether read-only mounts should be handled + recursively. + + If ReadOnly is false, this field has no meaning and must be unspecified. + + If ReadOnly is true, and this field is set to Disabled, the mount is not made + recursively read-only. If this field is set to IfPossible, the mount is made + recursively read-only, if it is supported by the container runtime. If this + field is set to Enabled, the mount is made recursively read-only if it is + supported by the container runtime, otherwise the pod will not be started and + an error will be generated to indicate the reason. + + If this field is set to IfPossible or Enabled, MountPropagation must be set to + None (or be unspecified, which defaults to None). + + If this field is not specified, it is treated as an equivalent of Disabled. + type: string + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + description: |- + Container's working directory. + If not specified, the container runtime's default will be used, which + might be configured in the container image. + Cannot be updated. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + dnsConfig: + description: |- + Specifies the DNS parameters of a pod. + Parameters specified here will be merged to the generated DNS + configuration based on DNSPolicy. + properties: + nameservers: + description: |- + A list of DNS name server IP addresses. + This will be appended to the base nameservers generated from DNSPolicy. + Duplicated nameservers will be removed. + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + description: |- + A list of DNS resolver options. + This will be merged with the base options generated from DNSPolicy. + Duplicated entries will be removed. Resolution options given in Options + will override those that appear in the base DNSPolicy. + items: + description: PodDNSConfigOption defines DNS resolver + options of a pod. + properties: + name: + description: |- + Name is this DNS resolver option's name. + Required. + type: string + value: + description: Value is this DNS resolver option's + value. + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + description: |- + A list of DNS search domains for host-name lookup. + This will be appended to the base search paths generated from DNSPolicy. + Duplicated search paths will be removed. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + dnsPolicy: + description: |- + Set DNS policy for the pod. + Defaults to "ClusterFirst". + Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. + DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. + To have DNS options set along with hostNetwork, you have to specify DNS policy + explicitly to 'ClusterFirstWithHostNet'. + type: string + enableServiceLinks: + description: |- + EnableServiceLinks indicates whether information about services should be injected into pod's + environment variables, matching the syntax of Docker links. + Optional: Defaults to true. + type: boolean + ephemeralContainers: + description: |- + List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing + pod to perform user-initiated actions such as debugging. This list cannot be specified when + creating a pod, and it cannot be modified by updating the pod spec. In order to add an + ephemeral container to an existing pod, use the pod's ephemeralcontainers subresource. + items: + description: |- + An EphemeralContainer is a temporary container that you may add to an existing Pod for + user-initiated activities such as debugging. Ephemeral containers have no resource or + scheduling guarantees, and they will not be restarted when they exit or when a Pod is + removed or restarted. The kubelet may evict a Pod if an ephemeral container causes the + Pod to exceed its resource allocation. + + To add an ephemeral container, use the ephemeralcontainers subresource of an existing + Pod. Ephemeral containers may not be removed or restarted. + properties: + args: + description: |- + Arguments to the entrypoint. + The image's CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + description: |- + Entrypoint array. Not executed within a shell. + The image's ENTRYPOINT is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + description: |- + List of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: |- + Name of the environment variable. + May consist of any printable ASCII characters except '='. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + description: |- + FileKeyRef selects a key of the env file. + Requires the EnvFiles feature gate to be enabled. + properties: + key: + description: |- + The key within the env file. An invalid key will prevent the pod from starting. + The keys defined within a source may consist of any printable ASCII characters except '='. + During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. + type: string + optional: + default: false + description: |- + Specify whether the file or its key must be defined. If the file or key + does not exist, then the env var is not published. + If optional is set to true and the specified key does not exist, + the environment variable will not be set in the Pod's containers. + + If optional is set to false and the specified key does not exist, + an error will be returned during Pod creation. + type: boolean + path: + description: |- + The path within the volume from which to select the file. + Must be relative and may not contain the '..' path or start with '..'. + type: string + volumeName: + description: The name of the volume mount + containing the env file. + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in + the pod's namespace + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + description: |- + List of sources to populate environment variables in the container. + The keys defined within a source may consist of any printable ASCII characters except '='. + When a key exists in multiple + sources, the value associated with the last source will take precedence. + 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 or Secrets + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: |- + Optional text to prepend to the name of each environment variable. + May consist of any printable ASCII characters except '='. + type: string + secretRef: + description: The Secret to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + description: |- + Container image name. + More info: https://kubernetes.io/docs/concepts/containers/images + type: string + imagePullPolicy: + description: |- + Image pull policy. + One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + type: string + lifecycle: + description: Lifecycle is not allowed for ephemeral + containers. + properties: + postStart: + description: |- + PostStart is called immediately after a container is created. If the handler fails, + the container is terminated and restarted according to its restart policy. + Other management of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies a command to execute + in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents a duration that + the container should sleep. + properties: + seconds: + description: Seconds is the number of seconds + to sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for backward compatibility. There is no validation of this field and + lifecycle hooks will fail at runtime when it is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: |- + PreStop is called immediately before a container is terminated due to an + API request or management event such as liveness/startup probe failure, + preemption, resource contention, etc. The handler is not called if the + container crashes or exits. The Pod's termination grace period countdown begins before the + PreStop hook is executed. Regardless of the outcome of the handler, the + container will eventually terminate within the Pod's termination grace + period (unless delayed by finalizers). Other management of the container blocks until the hook completes + or until the termination grace period is reached. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies a command to execute + in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents a duration that + the container should sleep. + properties: + seconds: + description: Seconds is the number of seconds + to sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for backward compatibility. There is no validation of this field and + lifecycle hooks will fail at runtime when it is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - 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: Probes are not allowed for ephemeral containers. + properties: + exec: + description: Exec specifies a command to execute + in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + name: + description: |- + Name of the ephemeral container specified as a DNS_LABEL. + This name must be unique among all containers, init containers and ephemeral containers. + type: string + ports: + description: Ports are not allowed for ephemeral containers. + items: + description: ContainerPort represents a network port + in a single container. + properties: + containerPort: + description: |- + Number of port to expose on the pod's IP address. + This must be a valid port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: |- + Number of port to expose on the host. + If specified, this must be a valid port number, 0 < x < 65536. + If HostNetwork is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: |- + If specified, this must be an IANA_SVC_NAME and unique within the pod. Each + named port in a pod must have a unique name. Name for the port that can be + referred to by services. + type: string + protocol: + default: TCP + description: |- + Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: Probes are not allowed for ephemeral containers. + properties: + exec: + description: Exec specifies a command to execute + in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents resource + resize policy for the container. + properties: + resourceName: + description: |- + Name of the resource to which this resource resize policy applies. + Supported values: cpu, memory. + type: string + restartPolicy: + description: |- + Restart policy to apply when specified resource is resized. + If not specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: |- + Resources are not allowed for ephemeral containers. Ephemeral containers use spare resources + already allocated to the pod. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry + in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + restartPolicy: + description: |- + Restart policy for the container to manage the restart behavior of each + container within a pod. + You cannot set this field on ephemeral containers. + type: string + restartPolicyRules: + description: |- + Represents a list of rules to be checked to determine if the + container should be restarted on exit. You cannot set this field on + ephemeral containers. + items: + description: ContainerRestartRule describes how a + container exit is handled. + properties: + action: + description: |- + Specifies the action taken on a container exit if the requirements + are satisfied. The only possible value is "Restart" to restart the + container. + type: string + exitCodes: + description: Represents the exit codes to check + on container exits. + properties: + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. Possible values are: + - In: the requirement is satisfied if the container exit code is in the + set of specified values. + - NotIn: the requirement is satisfied if the container exit code is + not in the set of specified values. + type: string + values: + description: |- + Specifies the set of values to check for container exit codes. + At most 255 elements are allowed. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + description: |- + Optional: SecurityContext defines the security options the ephemeral container should be run with. + If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. + properties: + allowPrivilegeEscalation: + description: |- + AllowPrivilegeEscalation controls whether a process can gain more + privileges than its parent process. This bool directly controls if + the no_new_privs flag will be set on the container process. + AllowPrivilegeEscalation is true always when the container is: + 1) run as Privileged + 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows. + type: boolean + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by this container. If set, this profile + overrides the pod's appArmorProfile. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + capabilities: + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. + Note that this field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: |- + procMount denotes the type of proc mount to use for the containers. + The default value is Default which uses the container runtime defaults for + readonly paths and masked paths. + This requires the ProcMountType feature flag to be enabled. + Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: |- + Whether this container has a read-only root filesystem. + Default is false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that + applies to the container. + type: string + role: + description: Role is a SELinux role label that + applies to the container. + type: string + type: + description: Type is a SELinux type label that + applies to the container. + type: string + user: + description: User is a SELinux user label that + applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by this container. If seccomp options are + provided at both the pod & container level, the container options + override the pod options. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name + of the GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + startupProbe: + description: Probes are not allowed for ephemeral containers. + properties: + exec: + description: Exec specifies a command to execute + in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + stdin: + description: |- + Whether this container should allocate a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will always result in EOF. + Default is false. + type: boolean + stdinOnce: + description: |- + Whether the container runtime should close the stdin channel after it has been opened by + a single attach. When stdin is true the stdin stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the + first client attaches to stdin, and then remains open and accepts data until the client disconnects, + at which time stdin is closed and remains closed until the container is restarted. If this + flag is false, a container processes that reads from stdin will never receive an EOF. + Default is false + type: boolean + targetContainerName: + description: |- + If set, the name of the container from PodSpec that this ephemeral container targets. + The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. + If not set then the ephemeral container uses the namespaces configured in the Pod spec. + + The container runtime must implement support for this feature. If the runtime does not + support namespace targeting then the result of setting this field is undefined. + type: string + terminationMessagePath: + description: |- + Optional: Path at which the file to which the container's termination message + will be written is mounted into the container's filesystem. + Message written is intended to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. The total message length across + all containers will be limited to 12kb. + Defaults to /dev/termination-log. + Cannot be updated. + type: string + terminationMessagePolicy: + description: |- + Indicate how the termination message should be populated. File will use the contents of + terminationMessagePath to populate the container status message on both success and failure. + FallbackToLogsOnError will use the last chunk of container log output if the termination + message file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, whichever is smaller. + Defaults to File. + Cannot be updated. + type: string + tty: + description: |- + Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. + Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices + to be used by the container. + items: + description: volumeDevice describes a mapping of a + raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside of + the container that the device will be mapped + to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + description: |- + Pod volumes to mount into the container's filesystem. Subpath mounts are not allowed for ephemeral containers. + Cannot be updated. + items: + description: VolumeMount describes a mounting of a + Volume within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. + When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified + (which defaults to None). + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + recursiveReadOnly: + description: |- + RecursiveReadOnly specifies whether read-only mounts should be handled + recursively. + + If ReadOnly is false, this field has no meaning and must be unspecified. + + If ReadOnly is true, and this field is set to Disabled, the mount is not made + recursively read-only. If this field is set to IfPossible, the mount is made + recursively read-only, if it is supported by the container runtime. If this + field is set to Enabled, the mount is made recursively read-only if it is + supported by the container runtime, otherwise the pod will not be started and + an error will be generated to indicate the reason. + + If this field is set to IfPossible or Enabled, MountPropagation must be set to + None (or be unspecified, which defaults to None). + + If this field is not specified, it is treated as an equivalent of Disabled. + type: string + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + description: |- + Container's working directory. + If not specified, the container runtime's default will be used, which + might be configured in the container image. + Cannot be updated. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + hostAliases: + description: |- + HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts + file if specified. + items: + description: |- + HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the + pod's hosts file. + properties: + hostnames: + description: Hostnames for the above IP address. + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + description: IP address of the host file entry. + type: string + required: + - ip + type: object + type: array + x-kubernetes-list-map-keys: + - ip + x-kubernetes-list-type: map + hostIPC: + description: |- + Use the host's ipc namespace. + Optional: Default to false. + type: boolean + hostNetwork: + description: |- + Host networking requested for this pod. Use the host's network namespace. + When using HostNetwork you should specify ports so the scheduler is aware. + When `hostNetwork` is true, specified `hostPort` fields in port definitions must match `containerPort`, + and unspecified `hostPort` fields in port definitions are defaulted to match `containerPort`. + Default to false. + type: boolean + hostPID: + description: |- + Use the host's pid namespace. + Optional: Default to false. + type: boolean + hostUsers: + description: |- + Use the host's user namespace. + Optional: Default to true. + If set to true or not present, the pod will be run in the host user namespace, useful + for when the pod needs a feature only available to the host user namespace, such as + loading a kernel module with CAP_SYS_MODULE. + When set to false, a new userns is created for the pod. Setting false is useful for + mitigating container breakout vulnerabilities even allowing users to run their + containers as root without actually having root privileges on the host. + This field is alpha-level and is only honored by servers that enable the UserNamespacesSupport feature. + type: boolean + hostname: + description: |- + Specifies the hostname of the Pod + If not specified, the pod's hostname will be set to a system-defined value. + type: string + hostnameOverride: + description: |- + HostnameOverride specifies an explicit override for the pod's hostname as perceived by the pod. + This field only specifies the pod's hostname and does not affect its DNS records. + When this field is set to a non-empty string: + - It takes precedence over the values set in `hostname` and `subdomain`. + - The Pod's hostname will be set to this value. + - `setHostnameAsFQDN` must be nil or set to false. + - `hostNetwork` must be set to false. + + This field must be a valid DNS subdomain as defined in RFC 1123 and contain at most 64 characters. + Requires the HostnameOverride feature gate to be enabled. + type: string + imagePullSecrets: + description: |- + ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. + If specified, these secrets will be passed to individual puller implementations for them to use. + More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + initContainers: + description: |- + List of initialization containers belonging to the pod. + Init containers are executed in order prior to containers being started. If any + init container fails, the pod is considered to have failed and is handled according + to its restartPolicy. The name for an init container or normal container must be + unique among all containers. + Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. + The resourceRequirements of an init container are taken into account during scheduling + by finding the highest request/limit for each resource type, and then using the max of + that value or the sum of the normal containers. Limits are applied to init containers + in a similar fashion. + Init containers cannot currently be added or removed. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ + items: + description: A single application container that you want + to run within a pod. + properties: + args: + description: |- + Arguments to the entrypoint. + The container image's CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + description: |- + Entrypoint array. Not executed within a shell. + The container image's ENTRYPOINT is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + description: |- + List of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable + present in a Container. + properties: + name: + description: |- + Name of the environment variable. + May consist of any printable ASCII characters except '='. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's + value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + description: |- + FileKeyRef selects a key of the env file. + Requires the EnvFiles feature gate to be enabled. + properties: + key: + description: |- + The key within the env file. An invalid key will prevent the pod from starting. + The keys defined within a source may consist of any printable ASCII characters except '='. + During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. + type: string + optional: + default: false + description: |- + Specify whether the file or its key must be defined. If the file or key + does not exist, then the env var is not published. + If optional is set to true and the specified key does not exist, + the environment variable will not be set in the Pod's containers. + + If optional is set to false and the specified key does not exist, + an error will be returned during Pod creation. + type: boolean + path: + description: |- + The path within the volume from which to select the file. + Must be relative and may not contain the '..' path or start with '..'. + type: string + volumeName: + description: The name of the volume mount + containing the env file. + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in + the pod's namespace + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + description: |- + List of sources to populate environment variables in the container. + The keys defined within a source may consist of any printable ASCII characters except '='. + When a key exists in multiple + sources, the value associated with the last source will take precedence. + 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 or Secrets + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: |- + Optional text to prepend to the name of each environment variable. + May consist of any printable ASCII characters except '='. + type: string + secretRef: + description: The Secret to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + description: |- + Container image name. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + imagePullPolicy: + description: |- + Image pull policy. + One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + type: string + lifecycle: + description: |- + Actions that the management system should take in response to container lifecycle events. + Cannot be updated. + properties: + postStart: + description: |- + PostStart is called immediately after a container is created. If the handler fails, + the container is terminated and restarted according to its restart policy. + Other management of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies a command to execute + in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents a duration that + the container should sleep. + properties: + seconds: + description: Seconds is the number of seconds + to sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for backward compatibility. There is no validation of this field and + lifecycle hooks will fail at runtime when it is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: |- + PreStop is called immediately before a container is terminated due to an + API request or management event such as liveness/startup probe failure, + preemption, resource contention, etc. The handler is not called if the + container crashes or exits. The Pod's termination grace period countdown begins before the + PreStop hook is executed. Regardless of the outcome of the handler, the + container will eventually terminate within the Pod's termination grace + period (unless delayed by finalizers). Other management of the container blocks until the hook completes + or until the termination grace period is reached. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies a command to execute + in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the + request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents a duration that + the container should sleep. + properties: + seconds: + description: Seconds is the number of seconds + to sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for backward compatibility. There is no validation of this field and + lifecycle hooks will fail at runtime when it is specified. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - 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: |- + Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies a command to execute + in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + name: + description: |- + Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: |- + List of ports to expose from the container. Not specifying a port here + DOES NOT prevent that port from being exposed. Any port which is + listening on the default "0.0.0.0" address inside a container will be + accessible from the network. + Modifying this array with strategic merge patch may corrupt the data. + For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port + in a single container. + properties: + containerPort: + description: |- + Number of port to expose on the pod's IP address. + This must be a valid port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: |- + Number of port to expose on the host. + If specified, this must be a valid port number, 0 < x < 65536. + If HostNetwork is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: |- + If specified, this must be an IANA_SVC_NAME and unique within the pod. Each + named port in a pod must have a unique name. Name for the port that can be + referred to by services. + type: string + protocol: + default: TCP + description: |- + Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: |- + Periodic probe of container service readiness. + Container will be removed from service endpoints if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies a command to execute + in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents resource + resize policy for the container. + properties: + resourceName: + description: |- + Name of the resource to which this resource resize policy applies. + Supported values: cpu, memory. + type: string + restartPolicy: + description: |- + Restart policy to apply when specified resource is resized. + If not specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: |- + Compute Resources required by this container. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry + in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + restartPolicy: + description: |- + RestartPolicy defines the restart behavior of individual containers in a pod. + This overrides the pod-level restart policy. When this field is not specified, + the restart behavior is defined by the Pod's restart policy and the container type. + Additionally, setting the RestartPolicy as "Always" for the init container will + have the following effect: + this init container will be continually restarted on + exit until all regular containers have terminated. Once all regular + containers have completed, all init containers with restartPolicy "Always" + will be shut down. This lifecycle differs from normal init containers and + is often referred to as a "sidecar" container. Although this init + container still starts in the init container sequence, it does not wait + for the container to complete before proceeding to the next init + container. Instead, the next init container starts immediately after this + init container is started, or after any startupProbe has successfully + completed. + type: string + restartPolicyRules: + description: |- + Represents a list of rules to be checked to determine if the + container should be restarted on exit. The rules are evaluated in + order. Once a rule matches a container exit condition, the remaining + rules are ignored. If no rule matches the container exit condition, + the Container-level restart policy determines the whether the container + is restarted or not. Constraints on the rules: + - At most 20 rules are allowed. + - Rules can have the same action. + - Identical rules are not forbidden in validations. + When rules are specified, container MUST set RestartPolicy explicitly + even it if matches the Pod's RestartPolicy. + items: + description: ContainerRestartRule describes how a + container exit is handled. + properties: + action: + description: |- + Specifies the action taken on a container exit if the requirements + are satisfied. The only possible value is "Restart" to restart the + container. + type: string + exitCodes: + description: Represents the exit codes to check + on container exits. + properties: + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. Possible values are: + - In: the requirement is satisfied if the container exit code is in the + set of specified values. + - NotIn: the requirement is satisfied if the container exit code is + not in the set of specified values. + type: string + values: + description: |- + Specifies the set of values to check for container exit codes. + At most 255 elements are allowed. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + description: |- + SecurityContext defines the security options the container should be run with. + If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + properties: + allowPrivilegeEscalation: + description: |- + AllowPrivilegeEscalation controls whether a process can gain more + privileges than its parent process. This bool directly controls if + the no_new_privs flag will be set on the container process. + AllowPrivilegeEscalation is true always when the container is: + 1) run as Privileged + 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows. + type: boolean + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by this container. If set, this profile + overrides the pod's appArmorProfile. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + capabilities: + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. + Note that this field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: |- + procMount denotes the type of proc mount to use for the containers. + The default value is Default which uses the container runtime defaults for + readonly paths and masked paths. + This requires the ProcMountType feature flag to be enabled. + Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: |- + Whether this container has a read-only root filesystem. + Default is false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that + applies to the container. + type: string + role: + description: Role is a SELinux role label that + applies to the container. + type: string + type: + description: Type is a SELinux type label that + applies to the container. + type: string + user: + description: User is a SELinux user label that + applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by this container. If seccomp options are + provided at both the pod & container level, the container options + override the pod options. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name + of the GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + startupProbe: + description: |- + StartupProbe indicates that the Pod has successfully initialized. + If specified, no other probes are executed until this completes successfully. + If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. + This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, + when it might take a long time to load data or warm a cache, than during steady-state operation. + This cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies a command to execute + in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom + header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to + a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + stdin: + description: |- + Whether this container should allocate a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will always result in EOF. + Default is false. + type: boolean + stdinOnce: + description: |- + Whether the container runtime should close the stdin channel after it has been opened by + a single attach. When stdin is true the stdin stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the + first client attaches to stdin, and then remains open and accepts data until the client disconnects, + at which time stdin is closed and remains closed until the container is restarted. If this + flag is false, a container processes that reads from stdin will never receive an EOF. + Default is false + type: boolean + terminationMessagePath: + description: |- + Optional: Path at which the file to which the container's termination message + will be written is mounted into the container's filesystem. + Message written is intended to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. The total message length across + all containers will be limited to 12kb. + Defaults to /dev/termination-log. + Cannot be updated. + type: string + terminationMessagePolicy: + description: |- + Indicate how the termination message should be populated. File will use the contents of + terminationMessagePath to populate the container status message on both success and failure. + FallbackToLogsOnError will use the last chunk of container log output if the termination + message file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, whichever is smaller. + Defaults to File. + Cannot be updated. + type: string + tty: + description: |- + Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. + Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices + to be used by the container. + items: + description: volumeDevice describes a mapping of a + raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside of + the container that the device will be mapped + to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + description: |- + Pod volumes to mount into the container's filesystem. + Cannot be updated. + items: + description: VolumeMount describes a mounting of a + Volume within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. + When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified + (which defaults to None). + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + recursiveReadOnly: + description: |- + RecursiveReadOnly specifies whether read-only mounts should be handled + recursively. + + If ReadOnly is false, this field has no meaning and must be unspecified. + + If ReadOnly is true, and this field is set to Disabled, the mount is not made + recursively read-only. If this field is set to IfPossible, the mount is made + recursively read-only, if it is supported by the container runtime. If this + field is set to Enabled, the mount is made recursively read-only if it is + supported by the container runtime, otherwise the pod will not be started and + an error will be generated to indicate the reason. + + If this field is set to IfPossible or Enabled, MountPropagation must be set to + None (or be unspecified, which defaults to None). + + If this field is not specified, it is treated as an equivalent of Disabled. + type: string + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + description: |- + Container's working directory. + If not specified, the container runtime's default will be used, which + might be configured in the container image. + Cannot be updated. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + nodeName: + description: |- + NodeName indicates in which node this pod is scheduled. + If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. + Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. + This field should not be used to express a desire for the pod to be scheduled on a specific node. + https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename + type: string + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector is a selector which must be true for the pod to fit on a node. + Selector which must match a node's labels for the pod to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + x-kubernetes-map-type: atomic + os: + description: |- + Specifies the OS of the containers in the pod. + Some pod and container fields are restricted if this is set. + + If the OS field is set to linux, the following fields must be unset: + -securityContext.windowsOptions + + If the OS field is set to windows, following fields must be unset: + - spec.hostPID + - spec.hostIPC + - spec.hostUsers + - spec.resources + - spec.securityContext.appArmorProfile + - spec.securityContext.seLinuxOptions + - spec.securityContext.seccompProfile + - spec.securityContext.fsGroup + - spec.securityContext.fsGroupChangePolicy + - spec.securityContext.sysctls + - spec.shareProcessNamespace + - spec.securityContext.runAsUser + - spec.securityContext.runAsGroup + - spec.securityContext.supplementalGroups + - spec.securityContext.supplementalGroupsPolicy + - spec.containers[*].securityContext.appArmorProfile + - spec.containers[*].securityContext.seLinuxOptions + - spec.containers[*].securityContext.seccompProfile + - spec.containers[*].securityContext.capabilities + - spec.containers[*].securityContext.readOnlyRootFilesystem + - spec.containers[*].securityContext.privileged + - spec.containers[*].securityContext.allowPrivilegeEscalation + - spec.containers[*].securityContext.procMount + - spec.containers[*].securityContext.runAsUser + - spec.containers[*].securityContext.runAsGroup + properties: + name: + description: |- + Name is the name of the operating system. The currently supported values are linux and windows. + Additional value may be defined in future and can be one of: + https://github.com/opencontainers/runtime-spec/blob/master/config.md#platform-specific-configuration + Clients should expect to handle additional values and treat unrecognized values in this field as os: null + type: string + required: + - name + type: object + overhead: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. + This field will be autopopulated at admission time by the RuntimeClass admission controller. If + the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. + The RuntimeClass admission controller will reject Pod create requests which have the overhead already + set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value + defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. + More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md + type: object + preemptionPolicy: + description: |- + PreemptionPolicy is the Policy for preempting pods with lower priority. + One of Never, PreemptLowerPriority. + Defaults to PreemptLowerPriority if unset. + type: string + priority: + description: |- + The priority value. Various system components use this field to find the + priority of the pod. When Priority Admission Controller is enabled, it + prevents users from setting this field. The admission controller populates + this field from PriorityClassName. + The higher the value, the higher the priority. + format: int32 + type: integer + priorityClassName: + description: |- + If specified, indicates the pod's priority. "system-node-critical" and + "system-cluster-critical" are two special keywords which indicate the + highest priorities with the former being the highest priority. Any other + name must be defined by creating a PriorityClass object with that name. + If not specified, the pod priority will be default or zero if there is no + default. + type: string + readinessGates: + description: |- + If specified, all readiness gates will be evaluated for pod readiness. + A pod is ready when all its containers are ready AND + all conditions specified in the readiness gates have status equal to "True" + More info: https://git.k8s.io/enhancements/keps/sig-network/580-pod-readiness-gates + items: + description: PodReadinessGate contains the reference to + a pod condition + properties: + conditionType: + description: ConditionType refers to a condition in + the pod's condition list with matching type. + type: string + required: + - conditionType + type: object + type: array + x-kubernetes-list-type: atomic + resourceClaims: + description: |- + ResourceClaims defines which ResourceClaims must be allocated + and reserved before the Pod is allowed to start. The resources + will be made available to those containers which consume them + by name. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. + items: + description: |- + PodResourceClaim references exactly one ResourceClaim, either directly + or by naming a ResourceClaimTemplate which is then turned into a ResourceClaim + for the pod. + + It adds a name to it that uniquely identifies the ResourceClaim inside the Pod. + Containers that need access to the ResourceClaim reference it with this name. + properties: + name: + description: |- + Name uniquely identifies this resource claim inside the pod. + This must be a DNS_LABEL. + type: string + resourceClaimName: + description: |- + ResourceClaimName is the name of a ResourceClaim object in the same + namespace as this pod. + + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string + resourceClaimTemplateName: + description: |- + ResourceClaimTemplateName is the name of a ResourceClaimTemplate + object in the same namespace as this pod. + + The template will be used to create a new ResourceClaim, which will + be bound to this pod. When this pod is deleted, the ResourceClaim + will also be deleted. The pod name and resource name, along with a + generated component, will be used to form a unique name for the + ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + + This field is immutable and no changes will be made to the + corresponding ResourceClaim by the control plane after creating the + ResourceClaim. + + Exactly one of ResourceClaimName and ResourceClaimTemplateName must + be set. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + resources: + description: |- + Resources is the total amount of CPU and Memory resources required by all + containers in the pod. It supports specifying Requests and Limits for + "cpu", "memory" and "hugepages-" resource names only. ResourceClaims are not supported. + + This field enables fine-grained control over resource allocation for the + entire pod, allowing resource sharing among containers in a pod. + + This is an alpha field and requires enabling the PodLevelResources feature + gate. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + restartPolicy: + description: |- + Restart policy for all containers within the pod. + One of Always, OnFailure, Never. In some contexts, only a subset of those values may be permitted. + Default to Always. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy + type: string + runtimeClassName: + description: |- + RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used + to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. + If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an + empty definition that uses the default runtime handler. + More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class + type: string + schedulerName: + description: |- + If specified, the pod will be dispatched by specified scheduler. + If not specified, the pod will be dispatched by default scheduler. + type: string + schedulingGates: + description: |- + SchedulingGates is an opaque list of values that if specified will block scheduling the pod. + If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the + scheduler will not attempt to schedule the pod. + + SchedulingGates can only be set at pod creation time, and be removed only afterwards. + items: + description: PodSchedulingGate is associated to a Pod to + guard its scheduling. + properties: + name: + description: |- + Name of the scheduling gate. + Each scheduling gate must have a unique name field. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + securityContext: + description: |- + SecurityContext holds pod-level security attributes and common container settings. + Optional: Defaults to empty. See type description for default values of each field. + properties: + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxChangePolicy: + description: |- + seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod. + It has no effect on nodes that do not support SELinux or to volumes does not support SELinux. + Valid values are "MountOption" and "Recursive". + + "Recursive" means relabeling of all files on all Pod volumes by the container runtime. + This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node. + + "MountOption" mounts all eligible Pod volumes with `-o context` mount option. + This requires all Pods that share the same volume to use the same SELinux label. + It is not possible to share the same volume among privileged and unprivileged Pods. + Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes + whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their + CSIDriver instance. Other volumes are always re-labelled recursively. + "MountOption" value is allowed only when SELinuxMount feature gate is enabled. + + If not specified and SELinuxMount feature gate is enabled, "MountOption" is used. + If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes + and "Recursive" for all other volumes. + + This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers. + + All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state. + Note that this field cannot be set when spec.os.name is windows. + type: string + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be + set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options within a container's SecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of + the GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + serviceAccount: + description: |- + DeprecatedServiceAccount is a deprecated alias for ServiceAccountName. + Deprecated: Use serviceAccountName instead. + type: string + serviceAccountName: + description: |- + ServiceAccountName is the name of the ServiceAccount to use to run this pod. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + type: string + setHostnameAsFQDN: + description: |- + If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default). + In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). + In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters to FQDN. + If a pod does not have FQDN, this has no effect. + Default to false. + type: boolean + shareProcessNamespace: + description: |- + Share a single process namespace between all of the containers in a pod. + When this is set containers will be able to view and signal processes from other containers + in the same pod, and the first process in each container will not be assigned PID 1. + HostPID and ShareProcessNamespace cannot both be set. + Optional: Default to false. + type: boolean + subdomain: + description: |- + If specified, the fully qualified Pod hostname will be "...svc.". + If not specified, the pod will not have a domainname at all. + type: string + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + If this value is nil, the default grace period will be used instead. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + Defaults to 30 seconds. + format: int64 + type: integer + tolerations: + description: If specified, the pod's tolerations. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + x-kubernetes-list-type: atomic + topologySpreadConstraints: + description: |- + TopologySpreadConstraints describes how a group of pods ought to spread across topology + domains. Scheduler will schedule pods in a way which abides by the constraints. + All topologySpreadConstraints are ANDed. + items: + description: TopologySpreadConstraint specifies how to spread + matching pods among the given topology. + properties: + labelSelector: + description: |- + LabelSelector is used to find matching pods. + Pods that match this label selector are counted to determine the number of pods + in their corresponding topology domain. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select the pods over which + spreading will be calculated. The keys are used to lookup values from the + incoming pod labels, those key-value labels are ANDed with labelSelector + to select the group of existing pods over which spreading will be calculated + for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + MatchLabelKeys cannot be set when LabelSelector isn't set. + Keys that don't exist in the incoming pod labels will + be ignored. A null or empty list means only match against labelSelector. + + This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + description: |- + MaxSkew describes the degree to which pods may be unevenly distributed. + When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference + between the number of matching pods in the target topology and the global minimum. + The global minimum is the minimum number of matching pods in an eligible domain + or zero if the number of eligible domains is less than MinDomains. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 2/2/1: + In this case, the global minimum is 1. + | zone1 | zone2 | zone3 | + | P P | P P | P | + - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; + scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) + violate MaxSkew(1). + - if MaxSkew is 2, incoming pod can be scheduled onto any zone. + When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence + to topologies that satisfy it. + It's a required field. Default value is 1 and 0 is not allowed. + format: int32 + type: integer + minDomains: + description: |- + MinDomains indicates a minimum number of eligible domains. + When the number of eligible domains with matching topology keys is less than minDomains, + Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. + And when the number of eligible domains with matching topology keys equals or greater than minDomains, + this value has no effect on scheduling. + As a result, when the number of eligible domains is less than minDomains, + scheduler won't schedule more than maxSkew Pods to those domains. + If value is nil, the constraint behaves as if MinDomains is equal to 1. + Valid values are integers greater than 0. + When value is not nil, WhenUnsatisfiable must be DoNotSchedule. + + For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same + labelSelector spread as 2/2/2: + | zone1 | zone2 | zone3 | + | P P | P P | P P | + The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. + In this situation, new pod with the same labelSelector cannot be scheduled, + because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, + it will violate MaxSkew. + format: int32 + type: integer + nodeAffinityPolicy: + description: |- + NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector + when calculating pod topology spread skew. Options are: + - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. + - 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. + type: string + nodeTaintsPolicy: + description: |- + NodeTaintsPolicy indicates how we will treat node taints when calculating + pod topology spread skew. Options are: + - Honor: nodes without taints, along with tainted nodes for which the incoming pod + has a toleration, are included. + - Ignore: node taints are ignored. All nodes are included. + + If this value is nil, the behavior is equivalent to the Ignore policy. + type: string + topologyKey: + description: |- + TopologyKey is the key of node labels. Nodes that have a label with this key + and identical values are considered to be in the same topology. + We consider each as a "bucket", and try to put balanced number + of pods into each bucket. + We define a domain as a particular instance of a topology. + Also, we define an eligible domain as a domain whose nodes meet the requirements of + nodeAffinityPolicy and nodeTaintsPolicy. + e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. + And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. + It's a required field. + type: string + whenUnsatisfiable: + description: |- + WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy + the spread constraint. + - DoNotSchedule (default) tells the scheduler not to schedule it. + - ScheduleAnyway tells the scheduler to schedule the pod in any location, + but giving higher precedence to topologies that would help reduce the + skew. + A constraint is considered "Unsatisfiable" for an incoming pod + if and only if every possible node assignment for that pod would violate + "MaxSkew" on some topology. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 3/1/1: + | zone1 | zone2 | zone3 | + | P P P | P | P | + If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled + to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies + MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler + won't make it *more* imbalanced. + It's a required field. + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + x-kubernetes-list-map-keys: + - topologyKey + - whenUnsatisfiable + x-kubernetes-list-type: map + volumes: + description: |- + List of volumes that can be mounted by containers belonging to the pod. + More info: https://kubernetes.io/docs/concepts/storage/volumes + items: + description: Volume represents a named volume in a pod that + may be accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: |- + awsElasticBlockStore represents an AWS Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + Deprecated: AWSElasticBlockStore is deprecated. All operations for the in-tree + awsElasticBlockStore type are redirected to the ebs.csi.aws.com CSI driver. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + properties: + fsType: + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + type: string + partition: + description: |- + partition is the partition in the volume that you want to mount. + If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition as "1". + Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + format: int32 + type: integer + readOnly: + description: |- + readOnly value true will force the readOnly setting in VolumeMounts. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + type: boolean + volumeID: + description: |- + volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + type: string + required: + - volumeID + type: object + azureDisk: + description: |- + azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. + Deprecated: AzureDisk is deprecated. All operations for the in-tree azureDisk type + are redirected to the disk.csi.azure.com CSI driver. + properties: + cachingMode: + description: 'cachingMode is the Host Caching mode: + None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data disk + in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in + the blob storage + type: string + fsType: + default: ext4 + description: |- + fsType is Filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: multiple + blob disks per storage account Dedicated: single + blob disk per storage account Managed: azure + managed data disk (only in managed availability + set). defaults to shared' + type: string + readOnly: + default: false + description: |- + readOnly Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: |- + azureFile represents an Azure File Service mount on the host and bind mount to the pod. + Deprecated: AzureFile is deprecated. All operations for the in-tree azureFile type + are redirected to the file.csi.azure.com CSI driver. + properties: + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret that + contains Azure Storage Account Name and Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: |- + cephFS represents a Ceph FS mount on the host that shares a pod's lifetime. + Deprecated: CephFS is deprecated and the in-tree cephfs type is no longer supported. + properties: + monitors: + description: |- + monitors is Required: Monitors is a collection of Ceph monitors + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + description: 'path is Optional: Used as the mounted + root, rather than the full Ceph tree, default + is /' + type: string + readOnly: + description: |- + readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + type: boolean + secretFile: + description: |- + secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + type: string + secretRef: + description: |- + secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: |- + user is optional: User is the rados user name, default is admin + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + type: string + required: + - monitors + type: object + cinder: + description: |- + cinder represents a cinder volume attached and mounted on kubelets host machine. + Deprecated: Cinder is deprecated. All operations for the in-tree cinder type + are redirected to the cinder.csi.openstack.org CSI driver. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + type: string + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + type: boolean + secretRef: + description: |- + secretRef is optional: points to a secret object containing parameters used to connect + to OpenStack. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: |- + volumeID used to identify the volume in cinder. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that should + populate this volume + properties: + defaultMode: + description: |- + defaultMode is optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents + ephemeral storage that is handled by certain external + CSI drivers. + properties: + driver: + description: |- + driver is the name of the CSI driver that handles this volume. + Consult with your admin for the correct name as registered in the cluster. + type: string + fsType: + description: |- + fsType to mount. Ex. "ext4", "xfs", "ntfs". + If not provided, the empty value is passed to the associated CSI driver + which will determine the default filesystem to apply. + type: string + nodePublishSecretRef: + description: |- + nodePublishSecretRef is a reference to the secret object containing + sensitive information to pass to the CSI driver to complete the CSI + NodePublishVolume and NodeUnpublishVolume calls. + This field is optional, and may be empty if no secret is required. If the + secret object contains more than one secret, all secret references are passed. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: |- + readOnly specifies a read-only configuration for the volume. + Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: |- + volumeAttributes stores driver-specific properties that are passed to the CSI + driver. Consult your driver's documentation for supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API about + the pod that should populate this volume + properties: + defaultMode: + description: |- + Optional: mode bits to use on created files by default. Must be a + Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: Items is a list of downward API volume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing the + pod field + properties: + fieldRef: + description: 'Required: Selects a field of + the pod: only annotations, labels, name, + namespace and uid are supported.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: |- + Optional: mode bits used to set permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. Must + not be absolute or contain the ''..'' path. + Must be utf-8 encoded. The first item of + the relative path must not start with ''..''' + type: string + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + description: |- + emptyDir represents a temporary directory that shares a pod's lifetime. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + properties: + medium: + description: |- + medium represents what type of storage medium should back this directory. + The default is "" which means to use the node's default medium. + Must be an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: |- + sizeLimit is the total amount of local storage required for this EmptyDir volume. + The size limit is also applicable for memory medium. + The maximum usage on memory medium EmptyDir would be the minimum value between + the SizeLimit specified here and the sum of memory limits of all containers in a pod. + The default is nil which means that the limit is undefined. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: |- + ephemeral represents a volume that is handled by a cluster storage driver. + The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, + and deleted when the pod is removed. + + Use this if: + a) the volume is only needed while the pod runs, + b) features of normal volumes like restoring from snapshot or capacity + tracking are needed, + c) the storage driver is specified through a storage class, and + d) the storage driver supports dynamic volume provisioning through + a PersistentVolumeClaim (see EphemeralVolumeSource for more + information on the connection between this volume type + and PersistentVolumeClaim). + + Use PersistentVolumeClaim or one of the vendor-specific + APIs for volumes that persist for longer than the lifecycle + of an individual pod. + + Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to + be used that way - see the documentation of the driver for + more information. + + A pod can use both types of ephemeral volumes and + persistent volumes at the same time. + properties: + volumeClaimTemplate: + description: |- + Will be used to create a stand-alone PVC to provision the volume. + The pod in which this EphemeralVolumeSource is embedded will be the + owner of the PVC, i.e. the PVC will be deleted together with the + pod. The name of the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` array + entry. Pod validation will reject the pod if the concatenated name + is not valid for a PVC (for example, too long). + + An existing PVC with that name that is not owned by the pod + will *not* be used for the pod to avoid using an unrelated + volume by mistake. Starting the pod is then blocked until + the unrelated PVC is removed. If such a pre-created PVC is + meant to be used by the pod, the PVC has to updated with an + owner reference to the pod once the pod exists. Normally + this should not be necessary, but it may be useful when + manually reconstructing a broken cluster. + + This field is read-only and no changes will be made by Kubernetes + to the PVC after it has been created. + + Required, must not be nil. + properties: + metadata: + description: |- + May contain labels and annotations that will be copied into the PVC + when creating it. No other fields are allowed and will be rejected during + validation. + type: object + spec: + description: |- + The specification for the PersistentVolumeClaim. The entire content is + copied unchanged into the PVC that gets created from this + template. The same fields as in a PersistentVolumeClaim + are also valid here. + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + 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 + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource + that is attached to a kubelet's host machine and then + exposed to the pod. + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + lun: + description: 'lun is Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: |- + readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target + worldwide names (WWNs)' + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + description: |- + wwids Optional: FC volume world wide identifiers (wwids) + Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + description: |- + flexVolume represents a generic volume resource that is + provisioned/attached using an exec based plugin. + Deprecated: FlexVolume is deprecated. Consider using a CSIDriver instead. + properties: + driver: + description: driver is the name of the driver to + use for this volume. + type: string + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field holds + extra command options if any.' + type: object + readOnly: + description: |- + readOnly is Optional: defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: |- + secretRef is Optional: secretRef is reference to the secret object containing + sensitive information to pass to the plugin scripts. This may be + empty if no secret object is specified. If the secret object + contains more than one secret, all secrets are passed to the plugin + scripts. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: |- + flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running. + Deprecated: Flocker is deprecated and the in-tree flocker type is no longer supported. + properties: + datasetName: + description: |- + datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker + should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. + This is unique identifier of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: |- + gcePersistentDisk represents a GCE Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + Deprecated: GCEPersistentDisk is deprecated. All operations for the in-tree + gcePersistentDisk type are redirected to the pd.csi.storage.gke.io CSI driver. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + properties: + fsType: + description: |- + fsType is filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + type: string + partition: + description: |- + partition is the partition in the volume that you want to mount. + If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition as "1". + Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + format: int32 + type: integer + pdName: + description: |- + pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + type: string + readOnly: + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + type: boolean + required: + - pdName + type: object + gitRepo: + description: |- + gitRepo represents a git repository at a particular revision. + Deprecated: GitRepo is deprecated. To provision a container with a git repo, mount an + EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir + into the Pod's container. + properties: + directory: + description: |- + directory is the target directory name. + Must not contain or start with '..'. If '.' is supplied, the volume directory will be the + git repository. Otherwise, if specified, the volume will contain the git repository in + the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the + specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: |- + glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. + Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported. + properties: + endpoints: + description: endpoints is the endpoint name that + details Glusterfs topology. + type: string + path: + description: |- + path is the Glusterfs volume path. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + type: string + readOnly: + description: |- + readOnly here will force the Glusterfs volume to be mounted with read-only permissions. + Defaults to false. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: |- + hostPath represents a pre-existing file or directory on the host + machine that is directly exposed to the container. This is generally + used for system agents or other privileged things that are allowed + to see the host machine. Most containers will NOT need this. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + properties: + path: + description: |- + path of the directory on the host. + If the path is a symlink, it will follow the link to the real path. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + type: string + type: + description: |- + type for HostPath Volume + Defaults to "" + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + type: string + required: + - path + type: object + image: + description: |- + image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. + The volume is resolved at pod startup depending on which PullPolicy value is provided: + + - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + + The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. + A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. + 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) before 1.33. + The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. + properties: + pullPolicy: + description: |- + Policy for pulling OCI objects. Possible values are: + Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + type: string + reference: + description: |- + Required: Image or artifact reference to be used. + Behaves in the same way as pod.spec.containers[*].image. + Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + type: object + iscsi: + description: |- + iscsi represents an ISCSI Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether support + iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support + iSCSI Session CHAP authentication + type: boolean + fsType: + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + type: string + initiatorName: + description: |- + initiatorName is the custom iSCSI Initiator Name. + If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface + : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified Name. + type: string + iscsiInterface: + default: default + description: |- + iscsiInterface is the interface Name that uses an iSCSI transport. + Defaults to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: |- + portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and 3260). + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for iSCSI + target and initiator authentication + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: |- + targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: |- + name of the volume. + Must be a DNS_LABEL and unique within the pod. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + nfs: + description: |- + nfs represents an NFS mount on the host that shares a pod's lifetime + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + properties: + path: + description: |- + path that is exported by the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + type: string + readOnly: + description: |- + readOnly here will force the NFS export to be mounted with read-only permissions. + Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + type: boolean + server: + description: |- + server is the hostname or IP address of the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: |- + persistentVolumeClaimVolumeSource represents a reference to a + PersistentVolumeClaim in the same namespace. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + properties: + claimName: + description: |- + claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + type: string + readOnly: + description: |- + readOnly Will force the ReadOnly setting in VolumeMounts. + Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: |- + photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine. + Deprecated: PhotonPersistentDisk is deprecated and the in-tree photonPersistentDisk type is no longer supported. + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon + Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: |- + portworxVolume represents a portworx volume attached and mounted on kubelets host machine. + Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type + are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate + is on. + properties: + fsType: + description: |- + fSType represents the filesystem type to mount + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx + volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources + secrets, configmaps, and downward API + properties: + defaultMode: + description: |- + defaultMode are the mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + sources: + description: |- + sources is the list of volume projections. Each entry in this list + handles one source. + items: + description: |- + Projection that may be projected along with other supported volume types. + Exactly one of these fields must be set. + properties: + clusterTrustBundle: + description: |- + ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field + of ClusterTrustBundle objects in an auto-updating file. + + Alpha, gated by the ClusterTrustBundleProjection feature gate. + + ClusterTrustBundle objects can either be selected by name, or by the + combination of signer name and a label selector. + + Kubelet performs aggressive normalization of the PEM contents written + into the pod filesystem. Esoteric PEM features such as inter-block + comments and block headers are stripped. Certificates are deduplicated. + The ordering of certificates within the file is arbitrary, and Kubelet + may change the order over time. + properties: + labelSelector: + description: |- + Select all ClusterTrustBundles that match this label selector. Only has + effect if signerName is set. Mutually-exclusive with name. If unset, + interpreted as "match nothing". If set but empty, interpreted as "match + everything". + 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 + name: + description: |- + Select a single ClusterTrustBundle by object name. Mutually-exclusive + with signerName and labelSelector. + type: string + optional: + description: |- + If true, don't block pod startup if the referenced ClusterTrustBundle(s) + aren't available. If using name, then the named ClusterTrustBundle is + allowed not to exist. If using signerName, then the combination of + signerName and labelSelector is allowed to match zero + ClusterTrustBundles. + type: boolean + path: + description: Relative path from the volume + root to write the bundle. + type: string + signerName: + description: |- + Select all ClusterTrustBundles that match this signer name. + Mutually-exclusive with name. The contents of all selected + ClusterTrustBundles will be unified and deduplicated. + type: string + required: + - path + type: object + configMap: + description: configMap information about the + configMap data to project + properties: + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a + path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: optional specify whether + the ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about + the downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects + a field of the pod: only annotations, + labels, name, namespace and uid + are supported.' + properties: + apiVersion: + description: Version of the + schema the FieldPath is written + in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field + to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: |- + Optional: mode bits used to set permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file + to be created. Must not be absolute + or contain the ''..'' path. Must + be utf-8 encoded. The first item + of the relative path must not + start with ''..''' + type: string + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. + properties: + containerName: + description: 'Container name: + required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + description: |- + Projects an auto-rotating credential bundle (private key and certificate + chain) that the pod can use either as a TLS client or server. + + Kubelet generates a private key and uses it to send a + PodCertificateRequest to the named signer. Once the signer approves the + request and issues a certificate chain, Kubelet writes the key and + certificate chain to the pod filesystem. The pod does not start until + certificates have been issued for each podCertificate projected volume + source in its spec. + + Kubelet will begin trying to rotate the certificate at the time indicated + by the signer using the PodCertificateRequest.Status.BeginRefreshAt + timestamp. + + Kubelet can write a single file, indicated by the credentialBundlePath + field, or separate files, indicated by the keyPath and + certificateChainPath fields. + + The credential bundle is a single file in PEM format. The first PEM + entry is the private key (in PKCS#8 format), and the remaining PEM + entries are the certificate chain issued by the signer (typically, + signers will return their certificate chain in leaf-to-root order). + + Prefer using the credential bundle format, since your application code + can read it atomically. If you use keyPath and certificateChainPath, + your application must make two separate file reads. If these coincide + with a certificate rotation, it is possible that the private key and leaf + certificate you read may not correspond to each other. Your application + will need to check for this condition, and re-read until they are + consistent. + + The named signer controls chooses the format of the certificate it + issues; consult the signer implementation's documentation to learn how to + use the certificates it issues. + properties: + certificateChainPath: + description: |- + Write the certificate chain at this path in the projected volume. + + Most applications should use credentialBundlePath. When using keyPath + and certificateChainPath, your application needs to check that the key + and leaf certificate are consistent, because it is possible to read the + files mid-rotation. + type: string + credentialBundlePath: + description: |- + Write the credential bundle at this path in the projected volume. + + The credential bundle is a single file that contains multiple PEM blocks. + The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private + key. + + The remaining blocks are CERTIFICATE blocks, containing the issued + certificate chain from the signer (leaf and any intermediates). + + Using credentialBundlePath lets your Pod's application code make a single + atomic read that retrieves a consistent key and certificate chain. If you + project them to separate files, your application code will need to + additionally check that the leaf certificate was issued to the key. + type: string + keyPath: + description: |- + Write the key at this path in the projected volume. + + Most applications should use credentialBundlePath. When using keyPath + and certificateChainPath, your application needs to check that the key + and leaf certificate are consistent, because it is possible to read the + files mid-rotation. + type: string + keyType: + description: |- + The type of keypair Kubelet will generate for the pod. + + Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384", + "ECDSAP521", and "ED25519". + type: string + maxExpirationSeconds: + description: |- + maxExpirationSeconds is the maximum lifetime permitted for the + certificate. + + Kubelet copies this value verbatim into the PodCertificateRequests it + generates for this projection. + + If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver + will reject values shorter than 3600 (1 hour). The maximum allowable + value is 7862400 (91 days). + + The signer implementation is then free to issue a certificate with any + lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600 + seconds (1 hour). This constraint is enforced by kube-apiserver. + `kubernetes.io` signers will never issue certificates with a lifetime + longer than 24 hours. + format: int32 + type: integer + signerName: + description: Kubelet's generated CSRs + will be addressed to this signer. + type: string + required: + - keyType + - signerName + type: object + secret: + description: secret information about the + secret data to project + properties: + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a + path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: optional field specify whether + the Secret or its key must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information + about the serviceAccountToken data to project + properties: + audience: + description: |- + audience is the intended audience of the token. A recipient of a token + must identify itself with an identifier specified in the audience of the + token, and otherwise should reject the token. The audience defaults to the + identifier of the apiserver. + type: string + expirationSeconds: + description: |- + expirationSeconds is the requested duration of validity of the service + account token. As the token approaches expiration, the kubelet volume + plugin will proactively rotate the service account token. The kubelet will + start trying to rotate the token if the token is older than 80 percent of + its time to live or if the token is older than 24 hours.Defaults to 1 hour + and must be at least 10 minutes. + format: int64 + type: integer + path: + description: |- + path is the path relative to the mount point of the file to project the + token into. + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + description: |- + quobyte represents a Quobyte mount on the host that shares a pod's lifetime. + Deprecated: Quobyte is deprecated and the in-tree quobyte type is no longer supported. + properties: + group: + description: |- + group to map volume access to + Default is no group + type: string + readOnly: + description: |- + readOnly here will force the Quobyte volume to be mounted with read-only permissions. + Defaults to false. + type: boolean + registry: + description: |- + registry represents a single or multiple Quobyte Registry services + specified as a string as host:port pair (multiple entries are separated with commas) + which acts as the central registry for volumes + type: string + tenant: + description: |- + tenant owning the given Quobyte volume in the Backend + Used with dynamically provisioned Quobyte volumes, value is set by the plugin + type: string + user: + description: |- + user to map volume access to + Defaults to serivceaccount user + type: string + volume: + description: volume is a string that references + an already created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: |- + rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. + Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported. + properties: + fsType: + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + type: string + image: + description: |- + image is the rados image name. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + keyring: + default: /etc/ceph/keyring + description: |- + keyring is the path to key ring for RBDUser. + Default is /etc/ceph/keyring. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + monitors: + description: |- + monitors is a collection of Ceph monitors. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + description: |- + pool is the rados pool name. + Default is rbd. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + readOnly: + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: boolean + secretRef: + description: |- + secretRef is name of the authentication secret for RBDUser. If provided + overrides keyring. + Default is nil. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + description: |- + user is the rados user name. + Default is admin. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + required: + - image + - monitors + type: object + scaleIO: + description: |- + scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. + Deprecated: ScaleIO is deprecated and the in-tree scaleIO type is no longer supported. + properties: + fsType: + default: xfs + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". + Default is "xfs". + type: string + gateway: + description: gateway is the host address of the + ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the + ScaleIO Protection Domain for the configured storage. + type: string + readOnly: + description: |- + readOnly Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: |- + secretRef references to the secret for ScaleIO user and other + sensitive information. If this is not provided, Login operation will fail. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable SSL + communication with Gateway, default false + type: boolean + storageMode: + default: ThinProvisioned + description: |- + storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. + Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage + Pool associated with the protection domain. + type: string + system: + description: system is the name of the storage system + as configured in ScaleIO. + type: string + volumeName: + description: |- + volumeName is the name of a volume already created in the ScaleIO system + that is associated with this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: |- + secret represents a secret that should populate this volume. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + properties: + defaultMode: + description: |- + defaultMode is Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values + for mode bits. Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: |- + items If unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + description: optional field specify whether the + Secret or its keys must be defined + type: boolean + secretName: + description: |- + secretName is the name of the secret in the pod's namespace to use. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + type: string + type: object + storageos: + description: |- + storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes. + Deprecated: StorageOS is deprecated and the in-tree storageos type is no longer supported. + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: |- + secretRef specifies the secret to use for obtaining the StorageOS API + credentials. If not specified, default values will be attempted. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: |- + volumeName is the human-readable name of the StorageOS volume. Volume + names are only unique within a namespace. + type: string + volumeNamespace: + description: |- + volumeNamespace specifies the scope of the volume within StorageOS. If no + namespace is specified then the Pod's namespace will be used. This allows the + Kubernetes name scoping to be mirrored within StorageOS for tighter integration. + Set VolumeName to any name to override the default behaviour. + Set to "default" if you are not using namespaces within StorageOS. + Namespaces that do not pre-exist within StorageOS will be created. + type: string + type: object + vsphereVolume: + description: |- + vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine. + Deprecated: VsphereVolume is deprecated. All operations for the in-tree vsphereVolume type + are redirected to the csi.vsphere.vmware.com CSI driver. + properties: + fsType: + description: |- + fsType is filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy + Based Management (SPBM) profile ID associated + with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage Policy + Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + required: + - containers + type: object + type: object + required: + - template + type: object + status: + properties: + conditions: + 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 + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/backupstrategy-controller/definitions/strategy.backups.cozystack.io_veleroes.yaml b/packages/system/backupstrategy-controller/definitions/strategy.backups.cozystack.io_veleroes.yaml new file mode 100644 index 00000000..34254aed --- /dev/null +++ b/packages/system/backupstrategy-controller/definitions/strategy.backups.cozystack.io_veleroes.yaml @@ -0,0 +1,1024 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: veleroes.strategy.backups.cozystack.io +spec: + group: strategy.backups.cozystack.io + names: + kind: Velero + listKind: VeleroList + plural: veleroes + singular: velero + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Velero defines a backup strategy using Velero as the driver. + 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: VeleroSpec specifies the desired strategy for backing up + with Velero. + properties: + template: + description: |- + VeleroTemplate describes the data a backup.velero.io should have when + templated from a Velero backup strategy. + properties: + restoreSpec: + description: RestoreSpec defines the specification for a Velero + restore. + properties: + backupName: + description: |- + BackupName is the unique name of the Velero backup to restore + from. + type: string + excludedNamespaces: + description: |- + ExcludedNamespaces contains a list of namespaces that are not + included in the restore. + items: + type: string + nullable: true + type: array + excludedResources: + description: |- + ExcludedResources is a slice of resource names that are not + included in the restore. + items: + type: string + nullable: true + type: array + existingResourcePolicy: + description: ExistingResourcePolicy specifies the restore + behavior for the Kubernetes resource to be restored + nullable: true + type: string + hooks: + description: Hooks represent custom behaviors that should + be executed during or post restore. + properties: + resources: + items: + description: |- + RestoreResourceHookSpec defines one or more RestoreResrouceHooks that should be executed based on + the rules defined for namespaces, resources, and label selector. + properties: + excludedNamespaces: + description: ExcludedNamespaces specifies the namespaces + to which this hook spec does not apply. + items: + type: string + nullable: true + type: array + excludedResources: + description: ExcludedResources specifies the resources + to which this hook spec does not apply. + items: + type: string + nullable: true + type: array + includedNamespaces: + description: |- + IncludedNamespaces specifies the namespaces to which this hook spec applies. If empty, it applies + to all namespaces. + items: + type: string + nullable: true + type: array + includedResources: + description: |- + IncludedResources specifies the resources to which this hook spec applies. If empty, it applies + to all resources. + items: + type: string + nullable: true + type: array + labelSelector: + description: LabelSelector, if specified, filters + the resources to which this hook spec applies. + nullable: true + 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 + name: + description: Name is the name of this hook. + type: string + postHooks: + description: PostHooks is a list of RestoreResourceHooks + to execute during and after restoring a resource. + items: + description: RestoreResourceHook defines a restore + hook for a resource. + properties: + exec: + description: Exec defines an exec restore + hook. + properties: + command: + description: Command is the command and + arguments to execute from within a container + after a pod has been restored. + items: + type: string + minItems: 1 + type: array + container: + description: |- + Container is the container in the pod where the command should be executed. If not specified, + the pod's first container is used. + type: string + execTimeout: + description: |- + ExecTimeout defines the maximum amount of time Velero should wait for the hook to complete before + considering the execution a failure. + type: string + onError: + description: OnError specifies how Velero + should behave if it encounters an error + executing this hook. + enum: + - Continue + - Fail + type: string + waitForReady: + description: WaitForReady ensures command + will be launched when container is Ready + instead of Running. + nullable: true + type: boolean + waitTimeout: + description: |- + WaitTimeout defines the maximum amount of time Velero should wait for the container to be Ready + before attempting to run the command. + type: string + required: + - command + type: object + init: + description: Init defines an init restore + hook. + properties: + initContainers: + description: InitContainers is list of + init containers to be added to a pod + during its restore. + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + x-kubernetes-preserve-unknown-fields: true + timeout: + description: Timeout defines the maximum + amount of time Velero should wait for + the initContainers to complete. + type: string + type: object + type: object + type: array + required: + - name + type: object + type: array + type: object + includeClusterResources: + description: |- + IncludeClusterResources specifies whether cluster-scoped resources + should be included for consideration in the restore. If null, defaults + to true. + nullable: true + type: boolean + includedNamespaces: + description: |- + IncludedNamespaces is a slice of namespace names to include objects + from. If empty, all namespaces are included. + items: + type: string + nullable: true + type: array + includedResources: + description: |- + IncludedResources is a slice of resource names to include + in the restore. If empty, all resources in the backup are included. + items: + type: string + nullable: true + type: array + itemOperationTimeout: + description: |- + ItemOperationTimeout specifies the time used to wait for RestoreItemAction operations + The default value is 4 hour. + type: string + labelSelector: + description: |- + LabelSelector is a metav1.LabelSelector to filter with + when restoring individual objects from the backup. If empty + or nil, all objects are included. Optional. + nullable: true + 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 + namespaceMapping: + additionalProperties: + type: string + description: |- + NamespaceMapping is a map of source namespace names + to target namespace names to restore into. Any source + namespaces not included in the map will be restored into + namespaces of the same name. + type: object + orLabelSelectors: + description: |- + OrLabelSelectors is list of metav1.LabelSelector to filter with + when restoring individual objects from the backup. If multiple provided + they will be joined by the OR operator. LabelSelector as well as + OrLabelSelectors cannot co-exist in restore request, only one of them + can be used + items: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + nullable: true + type: array + preserveNodePorts: + description: PreserveNodePorts specifies whether to restore + old nodePorts from backup. + nullable: true + type: boolean + resourceModifier: + description: ResourceModifier specifies the reference to JSON + resource patches that should be applied to resources before + restoration. + nullable: true + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + restorePVs: + description: |- + RestorePVs specifies whether to restore all included + PVs from snapshot + nullable: true + type: boolean + restoreStatus: + description: |- + RestoreStatus specifies which resources we should restore the status + field. If nil, no objects are included. Optional. + nullable: true + properties: + excludedResources: + description: ExcludedResources specifies the resources + to which will not restore the status. + items: + type: string + nullable: true + type: array + includedResources: + description: |- + IncludedResources specifies the resources to which will restore the status. + If empty, it applies to all resources. + items: + type: string + nullable: true + type: array + type: object + scheduleName: + description: |- + ScheduleName is the unique name of the Velero schedule to restore + from. If specified, and BackupName is empty, Velero will restore + from the most recent successful backup created from this schedule. + type: string + uploaderConfig: + description: UploaderConfig specifies the configuration for + the restore. + nullable: true + properties: + parallelFilesDownload: + description: ParallelFilesDownload is the concurrency + number setting for restore. + type: integer + writeSparseFiles: + description: WriteSparseFiles is a flag to indicate whether + write files sparsely or not. + nullable: true + type: boolean + type: object + type: object + spec: + description: BackupSpec defines the specification for a Velero + backup. + properties: + csiSnapshotTimeout: + description: |- + CSISnapshotTimeout specifies the time used to wait for CSI VolumeSnapshot status turns to + ReadyToUse during creation, before returning error as timeout. + The default value is 10 minute. + type: string + datamover: + description: |- + DataMover specifies the data mover to be used by the backup. + If DataMover is "" or "velero", the built-in data mover will be used. + type: string + defaultVolumesToFsBackup: + description: |- + DefaultVolumesToFsBackup specifies whether pod volume file system backup should be used + for all volumes by default. + nullable: true + type: boolean + defaultVolumesToRestic: + description: |- + DefaultVolumesToRestic specifies whether restic should be used to take a + backup of all pod volumes by default. + + Deprecated: this field is no longer used and will be removed entirely in future. Use DefaultVolumesToFsBackup instead. + nullable: true + type: boolean + excludedClusterScopedResources: + description: |- + ExcludedClusterScopedResources is a slice of cluster-scoped + resource type names to exclude from the backup. + If set to "*", all cluster-scoped resource types are excluded. + The default value is empty. + items: + type: string + nullable: true + type: array + excludedNamespaceScopedResources: + description: |- + ExcludedNamespaceScopedResources is a slice of namespace-scoped + resource type names to exclude from the backup. + If set to "*", all namespace-scoped resource types are excluded. + The default value is empty. + items: + type: string + nullable: true + type: array + excludedNamespaces: + description: |- + ExcludedNamespaces contains a list of namespaces that are not + included in the backup. + items: + type: string + nullable: true + type: array + excludedResources: + description: |- + ExcludedResources is a slice of resource names that are not + included in the backup. + items: + type: string + nullable: true + type: array + hooks: + description: Hooks represent custom behaviors that should + be executed at different phases of the backup. + properties: + resources: + description: Resources are hooks that should be executed + when backing up individual instances of a resource. + items: + description: |- + BackupResourceHookSpec defines one or more BackupResourceHooks that should be executed based on + the rules defined for namespaces, resources, and label selector. + properties: + excludedNamespaces: + description: ExcludedNamespaces specifies the namespaces + to which this hook spec does not apply. + items: + type: string + nullable: true + type: array + excludedResources: + description: ExcludedResources specifies the resources + to which this hook spec does not apply. + items: + type: string + nullable: true + type: array + includedNamespaces: + description: |- + IncludedNamespaces specifies the namespaces to which this hook spec applies. If empty, it applies + to all namespaces. + items: + type: string + nullable: true + type: array + includedResources: + description: |- + IncludedResources specifies the resources to which this hook spec applies. If empty, it applies + to all resources. + items: + type: string + nullable: true + type: array + labelSelector: + description: LabelSelector, if specified, filters + the resources to which this hook spec applies. + nullable: true + 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 + name: + description: Name is the name of this hook. + type: string + post: + description: |- + PostHooks is a list of BackupResourceHooks to execute after storing the item in the backup. + These are executed after all "additional items" from item actions are processed. + items: + description: BackupResourceHook defines a hook + for a resource. + properties: + exec: + description: Exec defines an exec hook. + properties: + command: + description: Command is the command and + arguments to execute. + items: + type: string + minItems: 1 + type: array + container: + description: |- + Container is the container in the pod where the command should be executed. If not specified, + the pod's first container is used. + type: string + onError: + description: OnError specifies how Velero + should behave if it encounters an error + executing this hook. + enum: + - Continue + - Fail + type: string + timeout: + description: |- + Timeout defines the maximum amount of time Velero should wait for the hook to complete before + considering the execution a failure. + type: string + required: + - command + type: object + required: + - exec + type: object + type: array + pre: + description: |- + PreHooks is a list of BackupResourceHooks to execute prior to storing the item in the backup. + These are executed before any "additional items" from item actions are processed. + items: + description: BackupResourceHook defines a hook + for a resource. + properties: + exec: + description: Exec defines an exec hook. + properties: + command: + description: Command is the command and + arguments to execute. + items: + type: string + minItems: 1 + type: array + container: + description: |- + Container is the container in the pod where the command should be executed. If not specified, + the pod's first container is used. + type: string + onError: + description: OnError specifies how Velero + should behave if it encounters an error + executing this hook. + enum: + - Continue + - Fail + type: string + timeout: + description: |- + Timeout defines the maximum amount of time Velero should wait for the hook to complete before + considering the execution a failure. + type: string + required: + - command + type: object + required: + - exec + type: object + type: array + required: + - name + type: object + nullable: true + type: array + type: object + includeClusterResources: + description: |- + IncludeClusterResources specifies whether cluster-scoped resources + should be included for consideration in the backup. + nullable: true + type: boolean + includedClusterScopedResources: + description: |- + IncludedClusterScopedResources is a slice of cluster-scoped + resource type names to include in the backup. + If set to "*", all cluster-scoped resource types are included. + The default value is empty, which means only related + cluster-scoped resources are included. + items: + type: string + nullable: true + type: array + includedNamespaceScopedResources: + description: |- + IncludedNamespaceScopedResources is a slice of namespace-scoped + resource type names to include in the backup. + The default value is "*". + items: + type: string + nullable: true + type: array + includedNamespaces: + description: |- + IncludedNamespaces is a slice of namespace names to include objects + from. If empty, all namespaces are included. + items: + type: string + nullable: true + type: array + includedResources: + description: |- + IncludedResources is a slice of resource names to include + in the backup. If empty, all resources are included. + items: + type: string + nullable: true + type: array + itemOperationTimeout: + description: |- + ItemOperationTimeout specifies the time used to wait for asynchronous BackupItemAction operations + The default value is 4 hour. + type: string + labelSelector: + description: |- + LabelSelector is a metav1.LabelSelector to filter with + when adding individual objects to the backup. If empty + or nil, all objects are included. Optional. + nullable: true + 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 + metadata: + properties: + labels: + additionalProperties: + type: string + type: object + type: object + orLabelSelectors: + description: |- + OrLabelSelectors is list of metav1.LabelSelector to filter with + when adding individual objects to the backup. If multiple provided + they will be joined by the OR operator. LabelSelector as well as + OrLabelSelectors cannot co-exist in backup request, only one of them + can be used. + items: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + nullable: true + type: array + orderedResources: + additionalProperties: + type: string + description: |- + OrderedResources specifies the backup order of resources of specific Kind. + The map key is the resource name and value is a list of object names separated by commas. + Each resource name has format "namespace/objectname". For cluster resources, simply use "objectname". + nullable: true + type: object + resourcePolicy: + description: ResourcePolicy specifies the referenced resource + policies that backup should follow + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + snapshotMoveData: + description: SnapshotMoveData specifies whether snapshot data + should be moved + nullable: true + type: boolean + snapshotVolumes: + description: |- + SnapshotVolumes specifies whether to take snapshots + of any PV's referenced in the set of objects included + in the Backup. + nullable: true + type: boolean + storageLocation: + description: StorageLocation is a string containing the name + of a BackupStorageLocation where the backup should be stored. + type: string + ttl: + description: |- + TTL is a time.Duration-parseable string describing how long + the Backup should be retained for. + type: string + uploaderConfig: + description: UploaderConfig specifies the configuration for + the uploader. + nullable: true + properties: + parallelFilesUpload: + description: ParallelFilesUpload is the number of files + parallel uploads to perform when using the uploader. + type: integer + type: object + volumeGroupSnapshotLabelKey: + description: VolumeGroupSnapshotLabelKey specifies the label + key to group PVCs under a VGS. + type: string + volumeSnapshotLocations: + description: VolumeSnapshotLocations is a list containing + names of VolumeSnapshotLocations associated with this backup. + items: + type: string + type: array + type: object + required: + - spec + type: object + required: + - template + type: object + status: + properties: + conditions: + 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 + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/backupstrategy-controller/images/backupstrategy-controller/Dockerfile b/packages/system/backupstrategy-controller/images/backupstrategy-controller/Dockerfile new file mode 100644 index 00000000..c4f60746 --- /dev/null +++ b/packages/system/backupstrategy-controller/images/backupstrategy-controller/Dockerfile @@ -0,0 +1,23 @@ +FROM golang:1.25-alpine AS builder + +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /workspace + +COPY go.mod go.sum ./ +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go mod download + +COPY api api/ +COPY pkg pkg/ +COPY cmd cmd/ +COPY internal internal/ + +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -ldflags="-extldflags=-static" -o /backupstrategy-controller cmd/backupstrategy-controller/main.go + +FROM scratch + +COPY --from=builder /backupstrategy-controller /backupstrategy-controller +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt + +ENTRYPOINT ["/backupstrategy-controller"] diff --git a/packages/system/backupstrategy-controller/templates/crds.yaml b/packages/system/backupstrategy-controller/templates/crds.yaml new file mode 100644 index 00000000..32b438c1 --- /dev/null +++ b/packages/system/backupstrategy-controller/templates/crds.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "definitions/*.yaml" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/backupstrategy-controller/templates/deployment.yaml b/packages/system/backupstrategy-controller/templates/deployment.yaml new file mode 100644 index 00000000..25874369 --- /dev/null +++ b/packages/system/backupstrategy-controller/templates/deployment.yaml @@ -0,0 +1,57 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: backupstrategy-controller + labels: + app: backupstrategy-controller +spec: + replicas: {{ .Values.backupStrategyController.replicas }} + selector: + matchLabels: + app: backupstrategy-controller + template: + metadata: + labels: + app: backupstrategy-controller + spec: + tolerations: + - key: "node-role.kubernetes.io/control-plane" + operator: "Exists" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/master" + operator: "Exists" + effect: "NoSchedule" + serviceAccountName: backupstrategy-controller + containers: + - name: backupstrategy-controller + image: "{{ .Values.backupStrategyController.image }}" + args: + - --leader-elect + {{- if .Values.backupStrategyController.metrics.enable }} + - --metrics-bind-address={{ .Values.backupStrategyController.metrics.bindAddress }} + {{- end }} + {{- if .Values.backupStrategyController.debug }} + - --zap-log-level=debug + {{- else }} + - --zap-log-level=info + {{- end }} + ports: + - name: metrics + containerPort: {{ splitList ":" .Values.backupStrategyController.metrics.bindAddress | mustLast }} + - name: health + containerPort: 8081 + readinessProbe: + httpGet: + path: /readyz + port: health + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /healthz + port: health + initialDelaySeconds: 15 + periodSeconds: 20 + {{- with .Values.backupStrategyController.resources }} + resources: {{- . | toYaml | nindent 10 }} + {{- end }} diff --git a/packages/system/backupstrategy-controller/templates/rbac-bind.yaml b/packages/system/backupstrategy-controller/templates/rbac-bind.yaml new file mode 100644 index 00000000..03578cc2 --- /dev/null +++ b/packages/system/backupstrategy-controller/templates/rbac-bind.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: backups.cozystack.io:strategy-controller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: backups.cozystack.io:strategy-controller +subjects: +- kind: ServiceAccount + name: backupstrategy-controller + namespace: {{ .Release.Namespace }} diff --git a/packages/system/backupstrategy-controller/templates/rbac.yaml b/packages/system/backupstrategy-controller/templates/rbac.yaml new file mode 100644 index 00000000..634ea88b --- /dev/null +++ b/packages/system/backupstrategy-controller/templates/rbac.yaml @@ -0,0 +1,82 @@ +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: backups.cozystack.io:strategy-controller +rules: +# Strategy types (Velero, Job) +- apiGroups: ["strategy.backups.cozystack.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] +# BackupClass: resolve strategy per application +- apiGroups: ["backups.cozystack.io"] + resources: ["backupclasses"] + verbs: ["get", "list", "watch"] +# BackupJob / RestoreJob: reconcile; update for RestoreJob finalizers +- apiGroups: ["backups.cozystack.io"] + resources: ["backupjobs", "restorejobs"] + verbs: ["get", "list", "watch", "update", "patch"] +- apiGroups: ["backups.cozystack.io"] + resources: ["backupjobs/status", "restorejobs/status"] + verbs: ["get", "update", "patch"] +# Backup: create after Velero job completes; update/patch for BackupReconciler finalizers +- apiGroups: ["backups.cozystack.io"] + resources: ["backups"] + verbs: ["create", "get", "list", "watch", "update", "patch"] +# Pods: BackupJob lists virt-launcher pods by label (manager cache uses cluster-scoped list/watch) +- apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch"] +# ConfigMaps: controller-runtime cache requires cluster-scoped list/watch; +# create/update/delete is scoped to cozy-velero via a Role shipped by the +# velero chart (packages/system/velero/templates/backupstrategy-controller-rbac.yaml) +# so it is only created when velero is installed. +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "list", "watch"] +# Application refs (e.g. VMInstance) for backup/restore scope +- apiGroups: ["apps.cozystack.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] +# KubeVirt: pre-restore halts VMs and checks VMI shutdown +- apiGroups: ["kubevirt.io"] + resources: ["virtualmachines"] + verbs: ["get", "update"] +- apiGroups: ["kubevirt.io"] + resources: ["virtualmachineinstances"] + verbs: ["get"] +# CDI DataVolumes: pre-restore deletes DVs so CDI doesn't recreate PVCs after rename +- apiGroups: ["cdi.kubevirt.io"] + resources: ["datavolumes"] + verbs: ["delete"] +# HelmReleases: pre-restore suspends HRs; post-restore rename creates new HR and deletes old +- apiGroups: ["helm.toolkit.fluxcd.io"] + resources: ["helmreleases"] + verbs: ["get", "create", "update", "delete"] +# PVCs and PVs: pre-restore renames PVCs (delete old, create new) and patches PV reclaim policy +- apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "watch", "create", "delete"] +- apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["get", "list", "watch", "update"] +# Velero Backup/Restore/DataUpload in cozy-velero namespace (DataUpload: enrich BackupJob failure messages) +- apiGroups: ["velero.io"] + resources: ["backups", "restores", "datauploads"] + verbs: ["create", "get", "list", "watch", "update", "patch", "delete", "deletecollection"] +# Velero DeleteBackupRequest: used by BackupReconciler to delete Velero backups with their storage data +- apiGroups: ["velero.io"] + resources: ["deletebackuprequests"] + verbs: ["create", "get", "list", "watch"] +# Namespaces: validate target namespace exists for cross-namespace restore +# controller-runtime cache requires list/watch for any resource accessed via r.Get() +- apiGroups: [""] + resources: ["namespaces"] + verbs: ["get", "list", "watch"] +# Events from Recorder.Event() calls +- apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] +# Leader election (--leader-elect) +- apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "list", "watch", "create", "update", "patch"] diff --git a/packages/system/backupstrategy-controller/templates/sa.yaml b/packages/system/backupstrategy-controller/templates/sa.yaml new file mode 100644 index 00000000..d55ba978 --- /dev/null +++ b/packages/system/backupstrategy-controller/templates/sa.yaml @@ -0,0 +1,4 @@ +kind: ServiceAccount +apiVersion: v1 +metadata: + name: backupstrategy-controller diff --git a/packages/system/backupstrategy-controller/values.yaml b/packages/system/backupstrategy-controller/values.yaml new file mode 100644 index 00000000..d6453124 --- /dev/null +++ b/packages/system/backupstrategy-controller/values.yaml @@ -0,0 +1,14 @@ +backupStrategyController: + image: "ghcr.io/cozystack/cozystack/backupstrategy-controller:v1.3.0@sha256:be0a9ec1f4307064b16388a24628aee46e06252738338add80b99ea1e04e62bf" + replicas: 2 + debug: false + metrics: + enabled: true + bindAddress: ":8443" + resources: + requests: + cpu: 10m + memory: 64Mi + limits: + cpu: 500m + memory: 128Mi diff --git a/packages/system/bootbox-rd/Chart.yaml b/packages/system/bootbox-rd/Chart.yaml new file mode 100644 index 00000000..0a35867d --- /dev/null +++ b/packages/system/bootbox-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: bootbox-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/bootbox-rd/Makefile b/packages/system/bootbox-rd/Makefile new file mode 100644 index 00000000..9d03ab2b --- /dev/null +++ b/packages/system/bootbox-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=bootbox-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/bootbox-rd/cozyrds/bootbox.yaml b/packages/system/bootbox-rd/cozyrds/bootbox.yaml new file mode 100644 index 00000000..667740e3 --- /dev/null +++ b/packages/system/bootbox-rd/cozyrds/bootbox.yaml @@ -0,0 +1,41 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: bootbox +spec: + application: + kind: BootBox + plural: bootboxes + singular: bootbox + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"whitelistHTTP":{"description":"Secure HTTP by enabling client networks whitelisting.","type":"boolean","default":true},"whitelist":{"description":"List of client networks.","type":"array","default":[],"items":{"type":"string"}},"machines":{"description":"Configuration of physical machine instances.","type":"array","default":[],"items":{"type":"object","required":["arch","hostname","ip","leaseTime","uefi"],"properties":{"arch":{"description":"Architecture.","type":"string"},"hostname":{"description":"Hostname.","type":"string"},"ip":{"description":"IP address configuration.","type":"object","required":["address","gateway","netmask"],"properties":{"address":{"description":"IP address.","type":"string"},"gateway":{"description":"IP gateway.","type":"string"},"netmask":{"description":"Netmask.","type":"string"}}},"leaseTime":{"description":"Lease time.","type":"integer"},"mac":{"description":"MAC addresses.","type":"array","items":{"type":"string"}},"nameServers":{"description":"Name servers.","type":"array","items":{"type":"string"}},"timeServers":{"description":"Time servers.","type":"array","items":{"type":"string"}},"uefi":{"description":"UEFI.","type":"boolean"}}}}}} + release: + prefix: "" + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-bootbox-application-default-bootbox + namespace: cozy-system + dashboard: + category: Administration + singular: BootBox + plural: BootBox + name: bootbox + description: PXE hardware provisioning + module: true + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl85NzlfNzkyKSIvPgo8cGF0aCBkPSJNNzEuNTY5OCA3Ni41MzM2QzcxLjIzNzQgNzYuNTMzNiA3MC45MDM2IDc2LjQ4NDcgNzAuNTgyOSA3Ni4zODkyTDM2LjIwNzkgNjYuMDc2N0MzNC4zODg1IDY1LjUzMTEgMzMuMzU2MiA2My42MTQ0IDMzLjkwMTcgNjEuNzk2NkMzNC40NDg5IDU5Ljk3NTUgMzYuMzY1NyA1OC45NDgzIDM4LjE4MTcgNTkuNDkwNEw3MS41Njk4IDY5LjUwNzZMMTA0Ljk1OCA1OS40OTA0QzEwNi43NzYgNTguOTYgMTA4LjY5MSA1OS45NzcyIDEwOS4yMzggNjEuNzk2NkMxMDkuNzgzIDYzLjYxNDQgMTA4Ljc1MSA2NS41MzExIDEwNi45MzIgNjYuMDc2N0w3Mi41NTY3IDc2LjM4OTJDNzIuMjM2IDc2LjQ4NDcgNzEuOTAyMiA3Ni41MzM2IDcxLjU2OTggNzYuNTMzNloiIGZpbGw9IiMyMzFGMjAiLz4KPHBhdGggZD0iTTc0Ljk3MyA1My4wMjE0Qzc0Ljc2NjggNTQuMzI3NiA3My44MDQzIDU1LjM5MzMgNzIuNTY2OCA1NS43NzE0TDM4LjE5MTggNjYuMDgzOUMzNy44NDggNjYuMTg3IDM3LjUzODcgNjYuMjIxNCAzNy4xOTQ5IDY2LjIyMTRDMzYuMzY5OSA2Ni4yMjE0IDM1LjU3OTMgNjUuOTEyIDM0LjkyNjIgNjUuMzYyTDIxLjE3NjIgNTMuMzMwOEMyMC4yNDggNTIuNTQwMSAxOS44MzU1IDUxLjI2ODMgMjAuMDc2MiA1MC4wNjUxQzIwLjMxNjggNDguODYyIDIxLjE3NjIgNDcuODY1MSAyMi4zNDQ5IDQ3LjQ4N0w1My4yODI0IDM3LjE3NDVDNTQuMzEzNyAzNi44MzA4IDU1LjQ0OCAzNy4wMDI2IDU2LjM0MTggMzcuNjIxNEw3My41MjkzIDQ5LjY1MjZDNzQuNjI5MyA1MC40MDg5IDc1LjE3OTMgNTEuNzE1MSA3NC45NzMgNTMuMDIxNFoiIGZpbGw9IiNGRkRDODMiLz4KPHBhdGggZD0iTTEyMS45NjQgNTMuMzMwOEwxMDguMjE0IDY1LjM2MkMxMDcuNTYgNjUuOTEyIDEwNi43NyA2Ni4yMjE0IDEwNS45NDUgNjYuMjIxNEMxMDUuNjAxIDY2LjIyMTQgMTA1LjI5MiA2Ni4xODcgMTA0Ljk0OCA2Ni4wODM5TDcwLjU3MyA1NS43NzE0QzY5LjMzNTUgNTUuMzkzMyA2OC4zNzMgNTQuMzI3NiA2OC4xNjY3IDUzLjAyMTRDNjcuOTYwNSA1MS43MTUxIDY4LjUxMDUgNTAuNDA4OSA2OS42MTA1IDQ5LjY1MjZMODYuNzk4IDM3LjYyMTRDODcuNjkxNyAzNy4wMDI2IDg4LjgyNjEgMzYuODMwOCA4OS44NTc0IDM3LjE3NDVMMTIwLjc5NSA0Ny40ODdDMTIxLjk2NCA0Ny44NjUxIDEyMi44MjMgNDguODYyIDEyMy4wNjQgNTAuMDY1MUMxMjMuMzA0IDUxLjI2ODMgMTIyLjg5MiA1Mi41NDAxIDEyMS45NjQgNTMuMzMwOFoiIGZpbGw9IiNGRkRDODMiLz4KPHBhdGggZD0iTTEwOS4zODIgNjMuNjQyNlYxMDcuNDcxQzEwOS4zODIgMTA4Ljg4IDEwOC41MjIgMTEwLjE1MiAxMDcuMjE2IDExMC42NjhMNzIuODQxMiAxMjQuNDE4QzcyLjQyODcgMTI0LjU4OSA3Mi4wMTYyIDEyNC42NTggNzEuNTY5MyAxMjQuNjU4QzcxLjEyMjUgMTI0LjY1OCA3MC43MSAxMjQuNTg5IDcwLjI5NzUgMTI0LjQxOEwzNS45MjI1IDExMC42NjhDMzQuNjE2MiAxMTAuMTUyIDMzLjc1NjggMTA4Ljg4IDMzLjc1NjggMTA3LjQ3MVY2My42NDI2QzMzLjc1NjggNjEuNzUyIDM1LjMwMzcgNjAuMjA1MSAzNy4xOTQzIDYwLjIwNTFIMTA1Ljk0NEMxMDcuODM1IDYwLjIwNTEgMTA5LjM4MiA2MS43NTIgMTA5LjM4MiA2My42NDI2WiIgZmlsbD0iI0VBQkQ0QyIvPgo8cGF0aCBkPSJNMTA3Ljk5OSA2MS40OTU4QzEwNy45OTkgNjIuOTgxMiAxMDcuMDM3IDY0LjI5NzkgMTA1LjY0MyA2NC43MzY4TDcyLjQ2MTMgNzQuODY1QzcyLjEyOTUgNzQuOTY2MiA3MS44MzA4IDc1IDcxLjQ5OSA3NUM3MS4xNjcyIDc1IDcwLjg2ODYgNzQuOTY2MiA3MC41MzY4IDc0Ljg2NUwzNy4zNTQ5IDY0LjczNjhDMzUuOTYxMyA2NC4yOTc5IDM0Ljk5OSA2Mi45ODEyIDM0Ljk5OSA2MS40OTU4QzM0Ljk5OSA2MC4wMTAzIDM1Ljk2MTMgNTguNjkzNyAzNy4zNTQ5IDU4LjI1NDhMNzAuNTM2OCA0OC4xMjY2QzcxLjE2NzIgNDcuOTU3OCA3MS44MzA4IDQ3Ljk1NzggNzIuNDYxMyA0OC4xMjY2TDEwNS42NDMgNTguMjU0OEMxMDcuMDM3IDU4LjY5MzcgMTA3Ljk5OSA2MC4wMTAzIDEwNy45OTkgNjEuNDk1OFoiIGZpbGw9IiM0QzM4MjUiLz4KPHBhdGggZD0iTTc0LjUxMTggNzdDNzUuMzUgNzcgNzYuMTc5NCA3Ni45NjI4IDc3IDc2LjkxMzNWMjEuMDg2N0M3Ni4xNzY1IDIxLjAzNDcgNzUuMzQ3MSAyMSA3NC41MDU5IDIxQzczLjY2NDcgMjEgNzIuODI5NCAyMS4wMzQ3IDcyIDIxLjA4NjdWNzYuOTEwOEM3Mi44MjY1IDc2Ljk2MjggNzMuNjU4OCA3Ni45OTc1IDc0LjUgNzdINzQuNTExOFoiIGZpbGw9InVybCgjcGFpbnQxX2xpbmVhcl85NzlfNzkyKSIvPgo8cGF0aCBkPSJNNDQuMDI4MiAzOC4xMTI5TDQzLjIwNzggMzcuMjk1OUM0Mi4wNzczIDM4LjkxMjEgNDEuMDc0NiA0MC42MTQgNDAuMjA4OCA0Mi4zODYxQzUwLjEwMDEgNTIuNDM1NCA1MS4xNDI0IDU3LjI4MzUgNTEuMTI4OSA1OC45MDc0QzUxLjA5MTkgNjMuMDI2IDQ2LjA1MjIgNjkuNDg0NSA0MC4xNDE2IDc1LjQ2NTdDNDAuOTk5NiA3Ny4yMzc1IDQxLjk5MzMgNzguOTQwNSA0My4xMTM3IDgwLjU1OTJDNDMuNDQ5OSA4MC4yMjMgNDMuNzY5MyA3OS45MTM3IDQ0LjA5NTQgNzkuNTg0MkM1Mi42MjUgNzAuOTk3NSA1Ni43OTQgNjQuMjQ5OCA1Ni44NDQ1IDU4Ljk0NzdDNTYuODk0OSA1My42NDU3IDUyLjcwMjQgNDYuODg3OSA0NC4wMjgyIDM4LjExMjlaIiBmaWxsPSJ1cmwoI3BhaW50Ml9saW5lYXJfOTc5Xzc5MikiLz4KPHBhdGggZD0iTTEwNC42OTUgNzkuNTk3NUwxMDUuNjc2IDgwLjU3MjVDMTA2Ljc5NSA3OC45NDkyIDEwNy43ODcgNzcuMjQxNyAxMDguNjQyIDc1LjQ2NTVDMTAyLjczNSA2OS40NzA5IDk3LjY5NDggNjIuOTk1NSA5Ny42NTQ1IDU4Ljg5MzdDOTcuNjE3NSA1NC44OTI4IDEwMi42MjcgNDguNDIwOCAxMDguNTY4IDQyLjM1OUMxMDcuNzAzIDQwLjU5MTcgMTA2LjcwMyAzOC44OTQ0IDEwNS41NzYgMzcuMjgyMkwxMDQuNzU1IDM4LjA5OTJDOTYuMDgxIDQ2Ljg1NzUgOTEuODg4NSA1My42NzkxIDkxLjkzODkgNTguOTQ0MkM5MS45ODk0IDY0LjIwOTIgOTYuMTU4MyA3MS4wMTA3IDEwNC42OTUgNzkuNTk3NVoiIGZpbGw9InVybCgjcGFpbnQzX2xpbmVhcl85NzlfNzkyKSIvPgo8cGF0aCBkPSJNODcuNDM5NiA1OC45MzQ0Qzg3LjQzOTYgNTEuNTM3OCA5MC43Mzc4IDM5LjIzOTMgOTUuODE3OSAyNy42MTY1Qzk0LjE5NzkgMjYuNTEzOSA5Mi40OTUgMjUuNTM4MiA5MC43MjQ0IDI0LjY5ODJDODUuMTYzNSAzNy4yMjg3IDgxLjcyMDcgNTAuNTU2MSA4MS43MjA3IDU4Ljk0NzhDODEuNzIwNyA2Ny4wNjczIDg1LjQ0OTMgODAuNTQyNSA5MS4xMTEgOTMuMTQwM0M5Mi44NDY4IDkyLjI4NTkgOTQuNTE0NyA5MS4zMDAyIDk2LjEwMDQgOTAuMTkxN0M5MC44NTg5IDc4LjQwMDkgODcuNDM5NiA2Ni4wNzU1IDg3LjQzOTYgNTguOTM0NFoiIGZpbGw9InVybCgjcGFpbnQ0X2xpbmVhcl85NzlfNzkyKSIvPgo8cGF0aCBkPSJNNjcuMDM4NCA1OC45MzUzQzY3LjAzODQgNTAuNDk5OCA2My40NTc4IDM3LjA5ODUgNTcuOTYwOCAyNC43MjI3QzU2LjIxNTggMjUuNTYxMyA1NC41Mzc3IDI2LjUzMjUgNTIuOTQxMiAyNy42Mjc1QzU4LjAzMTQgMzkuMjQzNSA2MS4zMjI4IDUxLjU0NTQgNjEuMzIyOCA1OC45MzUzQzYxLjMyMjggNjYuMDczIDU3LjkwMzYgNzguMzk1IDUyLjY2MjEgOTAuMTcyNEM1NC4yNDgyIDkxLjI4MDIgNTUuOTE2MSA5Mi4yNjU4IDU3LjY1MTQgOTMuMTIxQzYzLjMxOTkgODAuNTI2NiA2Ny4wMzg0IDY3LjA2MTQgNjcuMDM4NCA1OC45MzUzWiIgZmlsbD0idXJsKCNwYWludDVfbGluZWFyXzk3OV83OTIpIi8+CjxwYXRoIGQ9Ik03NC40MjI5IDc0Ljk4N0w2MC42NzI5IDk1LjYxMkM2MC4wMTk3IDk2LjYwODkgNTguOTU0MSA5Ny4xNTg5IDU3LjgxOTcgOTcuMTU4OUM1Ny40MDcyIDk3LjE1ODkgNTYuOTYwNCA5Ny4wOTAxIDU2LjU0NzkgOTYuOTE4M0wyMi4xNzI5IDgzLjE2ODNDMjEuMTQxNiA4Mi43NTU4IDIwLjM4NTQgODEuODk2NCAyMC4xMTA0IDgwLjg2NTFDMTkuODM1NCA3OS43OTk1IDIwLjA3NiA3OC42NjUxIDIwLjc2MzUgNzcuODQwMUwzNC41MTM1IDYwLjY1MjZDMzUuMzcyOSA1OS41NTI2IDMyLjczOTEgNTcuODQwNCAzNC4wNzk3IDU4LjIxODVMNzIuNTY2NiA2OS43OTY0QzczLjU5NzkgNzAuMTA1OCA3NC40MjI5IDcwLjg5NjQgNzQuODAxIDcxLjkyNzZDNzUuMTc5MSA3Mi45NTg5IDc1LjA0MTYgNzQuMDkzMyA3NC40MjI5IDc0Ljk4N1oiIGZpbGw9IiNGRkRDODMiLz4KPHBhdGggZD0iTTEyMy4wMjkgODAuNjI0MkMxMjIuNzU0IDgxLjY1NTUgMTIxLjk5OCA4Mi41NDkyIDEyMS4wMDEgODIuOTI3NEw4Ni42MjYxIDk2LjkxOEM4Ni4xNzkyIDk3LjA4OTkgODUuNzY2NyA5Ny4xNTg2IDg1LjMxOTkgOTcuMTU4NkM4NC4xODU1IDk3LjE1ODYgODMuMTE5OSA5Ni42MDg2IDgyLjQ2NjcgOTUuNjExN0w2OC43MTY3IDc0Ljk4NjdDNjguMDk4IDc0LjA5MyA2Ny45NjA1IDcyLjk1ODYgNjguMzM4NiA3MS45Mjc0QzY4LjcxNjcgNzAuODk2MSA2OS41NDE3IDcwLjEwNTUgNzAuNTczIDY5Ljc5NjFMMTA4LjQ2OSA1OC40MzMxQzEwOS44MSA1OC4wMjA2IDEwNy43MzIgNTkuNTUyNCAxMDguNjI2IDYwLjYxOEwxMjIuMzc2IDc3LjU5OTJDMTIzLjA2NCA3OC40MjQyIDEyMy4zMDQgNzkuNTU4NiAxMjMuMDI5IDgwLjYyNDJaIiBmaWxsPSIjRkZEQzgzIi8+CjxkZWZzPgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXJfOTc5Xzc5MiIgeDE9IjI0IiB5MT0iMy41IiB4Mj0iMTgxIiB5Mj0iMTQ3IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiM0ODAwMDAiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjQUUyMzAwIi8+CjwvbGluZWFyR3JhZGllbnQ+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQxX2xpbmVhcl85NzlfNzkyIiB4MT0iNzQuNSIgeTE9IjE3LjIzNjkiIHgyPSI3NC41IiB5Mj0iNzkuOTEzMyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjRkZEMjAwIi8+CjxzdG9wIG9mZnNldD0iMC4wNiIgc3RvcC1jb2xvcj0iI0ZGQjUwMCIvPgo8c3RvcCBvZmZzZXQ9IjAuMTQiIHN0b3AtY29sb3I9IiNGRjhDMDAiLz4KPHN0b3Agb2Zmc2V0PSIwLjIxIiBzdG9wLWNvbG9yPSIjRkY3MzAwIi8+CjxzdG9wIG9mZnNldD0iMC4yNiIgc3RvcC1jb2xvcj0iI0ZGNkEwMCIvPgo8c3RvcCBvZmZzZXQ9IjAuMzMiIHN0b3AtY29sb3I9IiNGQzRGMEUiLz4KPHN0b3Agb2Zmc2V0PSIwLjQzIiBzdG9wLWNvbG9yPSIjRjkyRjFFIi8+CjxzdG9wIG9mZnNldD0iMC41MSIgc3RvcC1jb2xvcj0iI0Y4MUIyNyIvPgo8c3RvcCBvZmZzZXQ9IjAuNTciIHN0b3AtY29sb3I9IiNGNzE0MkIiLz4KPHN0b3Agb2Zmc2V0PSIwLjY4IiBzdG9wLWNvbG9yPSIjREYxNjJFIi8+CjxzdG9wIG9mZnNldD0iMC43OSIgc3RvcC1jb2xvcj0iI0FGMUEzOCIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM0QjIxNEMiLz4KPC9saW5lYXJHcmFkaWVudD4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDJfbGluZWFyXzk3OV83OTIiIHgxPSI0OC40OTMiIHkxPSIxNS44OTI4IiB4Mj0iNDguNDkzIiB5Mj0iMTAwLjk1NCIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjRkZEMjAwIi8+CjxzdG9wIG9mZnNldD0iMC4wNiIgc3RvcC1jb2xvcj0iI0ZGQjUwMCIvPgo8c3RvcCBvZmZzZXQ9IjAuMTQiIHN0b3AtY29sb3I9IiNGRjhDMDAiLz4KPHN0b3Agb2Zmc2V0PSIwLjIxIiBzdG9wLWNvbG9yPSIjRkY3MzAwIi8+CjxzdG9wIG9mZnNldD0iMC4yNiIgc3RvcC1jb2xvcj0iI0ZGNkEwMCIvPgo8c3RvcCBvZmZzZXQ9IjAuMzMiIHN0b3AtY29sb3I9IiNGQzRGMEUiLz4KPHN0b3Agb2Zmc2V0PSIwLjQzIiBzdG9wLWNvbG9yPSIjRjkyRjFFIi8+CjxzdG9wIG9mZnNldD0iMC41MSIgc3RvcC1jb2xvcj0iI0Y4MUIyNyIvPgo8c3RvcCBvZmZzZXQ9IjAuNTciIHN0b3AtY29sb3I9IiNGNzE0MkIiLz4KPHN0b3Agb2Zmc2V0PSIwLjY4IiBzdG9wLWNvbG9yPSIjREYxNjJFIi8+CjxzdG9wIG9mZnNldD0iMC43OSIgc3RvcC1jb2xvcj0iI0FGMUEzOCIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM0QjIxNEMiLz4KPC9saW5lYXJHcmFkaWVudD4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDNfbGluZWFyXzk3OV83OTIiIHgxPSIxMDAuMjkiIHkxPSIxNS44OTI2IiB4Mj0iMTAwLjI5IiB5Mj0iMTAwLjk1MyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjRkZEMjAwIi8+CjxzdG9wIG9mZnNldD0iMC4wNiIgc3RvcC1jb2xvcj0iI0ZGQjUwMCIvPgo8c3RvcCBvZmZzZXQ9IjAuMTQiIHN0b3AtY29sb3I9IiNGRjhDMDAiLz4KPHN0b3Agb2Zmc2V0PSIwLjIxIiBzdG9wLWNvbG9yPSIjRkY3MzAwIi8+CjxzdG9wIG9mZnNldD0iMC4yNiIgc3RvcC1jb2xvcj0iI0ZGNkEwMCIvPgo8c3RvcCBvZmZzZXQ9IjAuMzMiIHN0b3AtY29sb3I9IiNGQzRGMEUiLz4KPHN0b3Agb2Zmc2V0PSIwLjQzIiBzdG9wLWNvbG9yPSIjRjkyRjFFIi8+CjxzdG9wIG9mZnNldD0iMC41MSIgc3RvcC1jb2xvcj0iI0Y4MUIyNyIvPgo8c3RvcCBvZmZzZXQ9IjAuNTciIHN0b3AtY29sb3I9IiNGNzE0MkIiLz4KPHN0b3Agb2Zmc2V0PSIwLjY4IiBzdG9wLWNvbG9yPSIjREYxNjJFIi8+CjxzdG9wIG9mZnNldD0iMC43OSIgc3RvcC1jb2xvcj0iI0FGMUEzOCIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM0QjIxNEMiLz4KPC9saW5lYXJHcmFkaWVudD4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDRfbGluZWFyXzk3OV83OTIiIHgxPSI4OC45MTIyIiB5MT0iMTUuODkyOSIgeDI9Ijg4LjkxMjIiIHkyPSIxMDAuOTU0IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkQyMDAiLz4KPHN0b3Agb2Zmc2V0PSIwLjA2IiBzdG9wLWNvbG9yPSIjRkZCNTAwIi8+CjxzdG9wIG9mZnNldD0iMC4xNCIgc3RvcC1jb2xvcj0iI0ZGOEMwMCIvPgo8c3RvcCBvZmZzZXQ9IjAuMjEiIHN0b3AtY29sb3I9IiNGRjczMDAiLz4KPHN0b3Agb2Zmc2V0PSIwLjI2IiBzdG9wLWNvbG9yPSIjRkY2QTAwIi8+CjxzdG9wIG9mZnNldD0iMC4zMyIgc3RvcC1jb2xvcj0iI0ZDNEYwRSIvPgo8c3RvcCBvZmZzZXQ9IjAuNDMiIHN0b3AtY29sb3I9IiNGOTJGMUUiLz4KPHN0b3Agb2Zmc2V0PSIwLjUxIiBzdG9wLWNvbG9yPSIjRjgxQjI3Ii8+CjxzdG9wIG9mZnNldD0iMC41NyIgc3RvcC1jb2xvcj0iI0Y3MTQyQiIvPgo8c3RvcCBvZmZzZXQ9IjAuNjgiIHN0b3AtY29sb3I9IiNERjE2MkUiLz4KPHN0b3Agb2Zmc2V0PSIwLjc5IiBzdG9wLWNvbG9yPSIjQUYxQTM4Ii8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzRCMjE0QyIvPgo8L2xpbmVhckdyYWRpZW50Pgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50NV9saW5lYXJfOTc5Xzc5MiIgeDE9IjU5Ljg1NyIgeTE9IjE1Ljg5MzgiIHgyPSI1OS44NTciIHkyPSIxMDAuOTU1IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkQyMDAiLz4KPHN0b3Agb2Zmc2V0PSIwLjA2IiBzdG9wLWNvbG9yPSIjRkZCNTAwIi8+CjxzdG9wIG9mZnNldD0iMC4xNCIgc3RvcC1jb2xvcj0iI0ZGOEMwMCIvPgo8c3RvcCBvZmZzZXQ9IjAuMjEiIHN0b3AtY29sb3I9IiNGRjczMDAiLz4KPHN0b3Agb2Zmc2V0PSIwLjI2IiBzdG9wLWNvbG9yPSIjRkY2QTAwIi8+CjxzdG9wIG9mZnNldD0iMC4zMyIgc3RvcC1jb2xvcj0iI0ZDNEYwRSIvPgo8c3RvcCBvZmZzZXQ9IjAuNDMiIHN0b3AtY29sb3I9IiNGOTJGMUUiLz4KPHN0b3Agb2Zmc2V0PSIwLjUxIiBzdG9wLWNvbG9yPSIjRjgxQjI3Ii8+CjxzdG9wIG9mZnNldD0iMC41NyIgc3RvcC1jb2xvcj0iI0Y3MTQyQiIvPgo8c3RvcCBvZmZzZXQ9IjAuNjgiIHN0b3AtY29sb3I9IiNERjE2MkUiLz4KPHN0b3Agb2Zmc2V0PSIwLjc5IiBzdG9wLWNvbG9yPSIjQUYxQTM4Ii8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzRCMjE0QyIvPgo8L2xpbmVhckdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPgo= + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "whitelistHTTP"], ["spec", "whitelist"], ["spec", "machines"]] + secrets: + exclude: [] + include: [] + services: + exclude: [] + include: + - resourceNames: + - bootbox + ingresses: + exclude: [] + include: + - resourceNames: + - bootbox diff --git a/packages/system/bootbox-rd/templates/cozyrd.yaml b/packages/system/bootbox-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/bootbox-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/bootbox-rd/values.yaml b/packages/system/bootbox-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/bootbox-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/bootbox/Makefile b/packages/system/bootbox/Makefile index ce4e1af0..2e666462 100644 --- a/packages/system/bootbox/Makefile +++ b/packages/system/bootbox/Makefile @@ -1,7 +1,7 @@ export NAME=bootbox export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/bootbox/templates/bootbox.yaml b/packages/system/bootbox/templates/bootbox.yaml index 7e7eb660..fb0c8fe5 100644 --- a/packages/system/bootbox/templates/bootbox.yaml +++ b/packages/system/bootbox/templates/bootbox.yaml @@ -4,18 +4,16 @@ metadata: annotations: helm.sh/resource-policy: keep labels: - cozystack.io/ui: "true" + sharding.fluxcd.io/key: tenants + apps.cozystack.io/application.kind: BootBox + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: bootbox name: bootbox namespace: tenant-root spec: - chart: - spec: - chart: bootbox - reconcileStrategy: Revision - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - version: '*' + chartRef: + kind: ExternalArtifact + name: cozystack-bootbox-application-default-bootbox + namespace: cozy-system interval: 1m0s timeout: 5m0s diff --git a/packages/system/bucket-rd/Chart.yaml b/packages/system/bucket-rd/Chart.yaml new file mode 100644 index 00000000..352a949c --- /dev/null +++ b/packages/system/bucket-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: bucket-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/bucket-rd/Makefile b/packages/system/bucket-rd/Makefile new file mode 100644 index 00000000..259617e8 --- /dev/null +++ b/packages/system/bucket-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=bucket-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/bucket-rd/cozyrds/bucket.yaml b/packages/system/bucket-rd/cozyrds/bucket.yaml new file mode 100644 index 00000000..7eab56b6 --- /dev/null +++ b/packages/system/bucket-rd/cozyrds/bucket.yaml @@ -0,0 +1,41 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: bucket +spec: + application: + kind: Bucket + plural: buckets + singular: bucket + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"locking":{"description":"Provisions bucket from the `-lock` BucketClass (with object lock enabled).","type":"boolean","default":false},"storagePool":{"description":"Selects a specific BucketClass by storage pool name.","type":"string","default":""},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"readonly":{"description":"Whether the user has read-only access.","type":"boolean"}}}}}} + release: + prefix: bucket- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-bucket-application-default-bucket + namespace: cozy-system + dashboard: + singular: Bucket + plural: Buckets + category: IaaS + weight: 80 + description: S3 compatible storage + tags: + - storage + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODNfMzA5MSkiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik03MiAzMC4xNjQxTDExNy45ODMgMzYuNzc4OVY0MC42NzM5QzExNy45ODMgNDYuNDY1MyA5Ny4zODYyIDUxLjEzMzIgNzEuOTgyNyA1MS4xMzMyQzQ2LjU3OTIgNTEuMTMzMiAyNiA0Ni40NjUzIDI2IDQwLjY3MzlWMzYuNDQzMUw3MiAzMC4xNjQxWk03MiA1OC4yNjc4QzkxLjIwODQgNTguMjY3OCAxMDcuNjU4IDU1LjU5ODYgMTE0LjU0NyA1MS44MDQ4TDExNi44MDMgNDguMTExTDExNy43MjMgNDQuNzUzVjQ4LjkxNzFMMTAyLjY3OSAxMTEuMDMzQzEwMi42NzkgMTE0Ljg5NSA4OC45NTMzIDExOCA3Mi4wMTcyIDExOEM1NS4wODEyIDExOCA0MS4zNzQzIDExNC44OTUgNDEuMzc0MyAxMTEuMDMzTDI2LjMzIDQ4LjkxNzFWNDQuODM2OUwyOS44MDA3IDUxLjkzODJDMzYuNzA2NSA1NS42NjUzIDUyLjk5OTcgNTguMjY3OCA3MiA1OC4yNjc4WiIgZmlsbD0iIzhDMzEyMyIvPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTcyLjAwMDMgMjZDOTcuNDAzOCAyNiAxMTggMzAuNjgzOSAxMTggMzYuNDQyQzExOCA0Mi4yIDk3LjM4NjYgNDYuODUwNyA3Mi4wMDAzIDQ2Ljg1MDdDNDYuNjE0MSA0Ni44NTA3IDI2LjAxNzYgNDIuMjM0NSAyNi4wMTc2IDM2LjQ0MkMyNi4wMTc2IDMwLjY0OTQgNDYuNTk2OCAyNiA3Mi4wMDAzIDI2Wk03Mi4wMDAzIDU0LjEwMzdDOTUuNjg1NyA1NC4xMDM3IDExNS4xNzIgNTAuMDU4IDExNy43MDYgNDQuODE5N0wxMDIuNjYyIDEwNi45MzdDMTAyLjY2MiAxMTAuNzk5IDg4LjkzNjQgMTEzLjkwNSA3Mi4wMDAzIDExMy45MDVDNTUuMDY0MyAxMTMuOTA1IDQxLjMzOSAxMTAuODE2IDQxLjMzOSAxMDYuOTU0TDI2LjI5NTkgNDQuODM3QzI4Ljg0NjYgNTAuMDU4IDQ4LjMzMzMgNTQuMTAzNyA3Mi4wMDAzIDU0LjEwMzdaIiBmaWxsPSIjRTA1MjQzIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNjEuMTcyNSA2MC4wMjkzSDgxLjA5MjhWNzkuMTY3Nkg2MS4xNzI1VjYwLjAyOTNaTTQ1LjMzMDEgOTUuMzY4OEM0NS4zMzAxIDkwLjE0MiA0OS43MTA0IDg1LjkzNDIgNTUuMTUxMSA4NS45MzQyQzYwLjU5MTcgODUuOTM0MiA2NC45NzIxIDkwLjE0MiA2NC45NzIxIDk1LjM2ODhDNjQuOTcyMSAxMDAuNTk2IDYwLjU5MTcgMTA0LjgwMyA1NS4xNTExIDEwNC44MDNDNDkuNzEwNCAxMDQuODAzIDQ1LjMzMDEgMTAwLjU5NiA0NS4zMzAxIDk1LjM2ODhaTTk2LjQ0ODcgMTA0LjM2OEg3Ni43NzIyTDg2LjYxMDUgODYuNzczN0w5Ni40NDg3IDEwNC4zNjhaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4M18zMDkxIiB4MT0iMCIgeTE9IjAiIHgyPSIxNTEiIHkyPSIxODAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0ZGRjBFRSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNFQzg4N0QiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "locking"], ["spec", "storagePool"], ["spec", "users"]] + secrets: + exclude: [] + include: + - resourceNames: + - bucket-{{ .name }}-credentials + - matchLabels: + apps.cozystack.io/user-secret: "true" + ingresses: + exclude: [] + include: + - resourceNames: + - bucket-{{ .name }}-ui diff --git a/packages/system/bucket-rd/templates/cozyrd.yaml b/packages/system/bucket-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/bucket-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/bucket-rd/values.yaml b/packages/system/bucket-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/bucket-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/bucket/Makefile b/packages/system/bucket/Makefile index 1f8d34b2..87944b28 100644 --- a/packages/system/bucket/Makefile +++ b/packages/system/bucket/Makefile @@ -2,8 +2,8 @@ S3MANAGER_TAG=v0.5.0 export NAME=s3manager-system -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: @echo Nothing to update @@ -12,16 +12,11 @@ image: image-s3manager image-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 \ --metadata-file images/s3manager.json \ - --push=$(PUSH) \ - --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ - --load=$(LOAD) + $(BUILDX_ARGS) echo "$(REGISTRY)/s3manager:$(call settag,$(S3MANAGER_TAG))@$$(yq e '."containerimage.digest"' images/s3manager.json -o json -r)" \ > images/s3manager.tag rm -f images/s3manager.json diff --git a/packages/system/bucket/images/s3manager.tag b/packages/system/bucket/images/s3manager.tag index 3243c172..889db0af 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:1ba30c6c3443e826006b4f6d1c6c251e74a4ffde6bd940f73aef1058a9d10751 +ghcr.io/cozystack/cozystack/s3manager:v0.5.0@sha256:fb65e734bbdbdaef2238769cc2ecfb54dbddaf1e0952ad438a9b3e26b9dbb4b5 diff --git a/packages/system/bucket/images/s3manager/Dockerfile b/packages/system/bucket/images/s3manager/Dockerfile index 179acead..e97adf07 100644 --- a/packages/system/bucket/images/s3manager/Dockerfile +++ b/packages/system/bucket/images/s3manager/Dockerfile @@ -9,6 +9,7 @@ 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 go mod tidy 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 diff --git a/packages/system/bucket/images/s3manager/cozystack.patch b/packages/system/bucket/images/s3manager/cozystack.patch index f631b144..2f569042 100644 --- a/packages/system/bucket/images/s3manager/cozystack.patch +++ b/packages/system/bucket/images/s3manager/cozystack.patch @@ -1,3 +1,235 @@ +diff --git a/go.mod b/go.mod +index b5d8540..6ede8e8 100644 +--- a/go.mod ++++ b/go.mod +@@ -1,10 +1,11 @@ + module github.com/cloudlena/s3manager + +-go 1.22.5 ++go 1.23 + + require ( + github.com/cloudlena/adapters v0.0.0-20240708203353-a39be02cc801 + github.com/gorilla/mux v1.8.1 ++ github.com/gorilla/sessions v1.4.0 + github.com/matryer/is v1.4.1 + github.com/minio/minio-go/v7 v7.0.74 + github.com/spf13/viper v1.19.0 +@@ -16,6 +17,7 @@ require ( + github.com/go-ini/ini v1.67.0 // indirect + github.com/goccy/go-json v0.10.3 // indirect + github.com/google/uuid v1.6.0 // indirect ++ github.com/gorilla/securecookie v1.1.2 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect +diff --git a/go.sum b/go.sum +index 1ea1b16..d7866ce 100644 +--- a/go.sum ++++ b/go.sum +@@ -16,10 +16,16 @@ github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= + github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= + github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= + github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= ++github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= ++github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= + github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= + github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= + github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= + github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= ++github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= ++github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= ++github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= ++github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= + github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= + github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= + github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +diff --git a/main.go b/main.go +index 2ffe8ab..723a1b8 100644 +--- a/main.go ++++ b/main.go +@@ -41,10 +41,12 @@ type configuration struct { + Timeout int32 + SseType string + SseKey string ++ LoginMode bool + } + + func parseConfiguration() configuration { + var accessKeyID, secretAccessKey, iamEndpoint string ++ var loginMode bool + + viper.AutomaticEnv() + +@@ -57,13 +59,10 @@ func parseConfiguration() configuration { + iamEndpoint = viper.GetString("IAM_ENDPOINT") + } else { + accessKeyID = viper.GetString("ACCESS_KEY_ID") +- if len(accessKeyID) == 0 { +- log.Fatal("please provide ACCESS_KEY_ID") +- } +- + secretAccessKey = viper.GetString("SECRET_ACCESS_KEY") +- if len(secretAccessKey) == 0 { +- log.Fatal("please provide SECRET_ACCESS_KEY") ++ if len(accessKeyID) == 0 || len(secretAccessKey) == 0 { ++ log.Println("ACCESS_KEY_ID or SECRET_ACCESS_KEY not set, starting in login mode") ++ loginMode = true + } + } + +@@ -115,6 +114,7 @@ func parseConfiguration() configuration { + Timeout: timeout, + SseType: sseType, + SseKey: sseKey, ++ LoginMode: loginMode, + } + } + +@@ -135,57 +135,96 @@ func main() { + log.Fatal(err) + } + +- // Set up S3 client +- opts := &minio.Options{ +- Secure: configuration.UseSSL, +- } +- if configuration.UseIam { +- opts.Creds = credentials.NewIAM(configuration.IamEndpoint) +- } else { +- var signatureType credentials.SignatureType +- +- switch configuration.SignatureType { +- case "V2": +- signatureType = credentials.SignatureV2 +- case "V4": +- signatureType = credentials.SignatureV4 +- case "V4Streaming": +- signatureType = credentials.SignatureV4Streaming +- case "Anonymous": +- signatureType = credentials.SignatureAnonymous +- default: +- log.Fatalf("Invalid SIGNATURE_TYPE: %s", configuration.SignatureType) ++ // Set up router ++ r := mux.NewRouter() ++ r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.FS(statics)))).Methods(http.MethodGet) ++ ++ if configuration.LoginMode { ++ // Login mode: no pre-configured S3 client, per-session credentials ++ sessionCfg := &s3manager.SessionConfig{ ++ Store: s3manager.NewSessionStore(), ++ Endpoint: configuration.Endpoint, ++ UseSSL: configuration.UseSSL, ++ SkipSSLVerify: configuration.SkipSSLVerification, ++ AllowDelete: configuration.AllowDelete, ++ ForceDownload: configuration.ForceDownload, ++ ListRecursive: configuration.ListRecursive, ++ SseInfo: sseType, ++ Templates: templates, + } + +- opts.Creds = credentials.NewStatic(configuration.AccessKeyID, configuration.SecretAccessKey, "", signatureType) +- } ++ // Public routes (no auth required) ++ r.Handle("/login", s3manager.HandleLoginView(templates)).Methods(http.MethodGet) ++ r.Handle("/login", s3manager.HandleLogin(sessionCfg)).Methods(http.MethodPost) ++ r.Handle("/logout", s3manager.HandleLogout(sessionCfg)).Methods(http.MethodPost) ++ ++ // Protected routes (auth required via middleware) ++ protected := mux.NewRouter() ++ protected.Handle("/", http.RedirectHandler("/buckets", http.StatusPermanentRedirect)).Methods(http.MethodGet) ++ protected.Handle("/buckets", s3manager.HandleBucketsViewDynamic(templates, configuration.AllowDelete)).Methods(http.MethodGet) ++ protected.PathPrefix("/buckets/").Handler(s3manager.HandleBucketViewDynamic(templates, configuration.AllowDelete, configuration.ListRecursive)).Methods(http.MethodGet) ++ protected.Handle("/api/buckets", s3manager.HandleCreateBucketDynamic()).Methods(http.MethodPost) ++ if configuration.AllowDelete { ++ protected.Handle("/api/buckets/{bucketName}", s3manager.HandleDeleteBucketDynamic()).Methods(http.MethodDelete) ++ } ++ protected.Handle("/api/buckets/{bucketName}/objects", s3manager.HandleCreateObjectDynamic(sseType)).Methods(http.MethodPost) ++ protected.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}/url", s3manager.HandleGenerateUrlDynamic()).Methods(http.MethodGet) ++ protected.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}", s3manager.HandleGetObjectDynamic(configuration.ForceDownload)).Methods(http.MethodGet) ++ if configuration.AllowDelete { ++ protected.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}", s3manager.HandleDeleteObjectDynamic()).Methods(http.MethodDelete) ++ } + +- if configuration.Region != "" { +- opts.Region = configuration.Region +- } +- if configuration.UseSSL && configuration.SkipSSLVerification { +- opts.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} //nolint:gosec +- } +- s3, err := minio.New(configuration.Endpoint, opts) +- if err != nil { +- log.Fatalln(fmt.Errorf("error creating s3 client: %w", err)) +- } ++ r.PathPrefix("/").Handler(s3manager.RequireAuth(sessionCfg, protected)) ++ } else { ++ // Pre-configured mode: existing behavior with static S3 client ++ opts := &minio.Options{ ++ Secure: configuration.UseSSL, ++ } ++ if configuration.UseIam { ++ opts.Creds = credentials.NewIAM(configuration.IamEndpoint) ++ } else { ++ var signatureType credentials.SignatureType ++ ++ switch configuration.SignatureType { ++ case "V2": ++ signatureType = credentials.SignatureV2 ++ case "V4": ++ signatureType = credentials.SignatureV4 ++ case "V4Streaming": ++ signatureType = credentials.SignatureV4Streaming ++ case "Anonymous": ++ signatureType = credentials.SignatureAnonymous ++ default: ++ log.Fatalf("Invalid SIGNATURE_TYPE: %s", configuration.SignatureType) ++ } ++ ++ opts.Creds = credentials.NewStatic(configuration.AccessKeyID, configuration.SecretAccessKey, "", signatureType) ++ } + +- // Set up router +- r := mux.NewRouter() +- r.Handle("/", http.RedirectHandler("/buckets", http.StatusPermanentRedirect)).Methods(http.MethodGet) +- r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.FS(statics)))).Methods(http.MethodGet) +- r.Handle("/buckets", s3manager.HandleBucketsView(s3, templates, configuration.AllowDelete)).Methods(http.MethodGet) +- r.PathPrefix("/buckets/").Handler(s3manager.HandleBucketView(s3, templates, configuration.AllowDelete, configuration.ListRecursive)).Methods(http.MethodGet) +- r.Handle("/api/buckets", s3manager.HandleCreateBucket(s3)).Methods(http.MethodPost) +- if configuration.AllowDelete { +- r.Handle("/api/buckets/{bucketName}", s3manager.HandleDeleteBucket(s3)).Methods(http.MethodDelete) +- } +- r.Handle("/api/buckets/{bucketName}/objects", s3manager.HandleCreateObject(s3, sseType)).Methods(http.MethodPost) +- r.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}/url", s3manager.HandleGenerateUrl(s3)).Methods(http.MethodGet) +- r.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}", s3manager.HandleGetObject(s3, configuration.ForceDownload)).Methods(http.MethodGet) +- if configuration.AllowDelete { +- r.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}", s3manager.HandleDeleteObject(s3)).Methods(http.MethodDelete) ++ if configuration.Region != "" { ++ opts.Region = configuration.Region ++ } ++ if configuration.UseSSL && configuration.SkipSSLVerification { ++ opts.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} //nolint:gosec ++ } ++ s3, err := minio.New(configuration.Endpoint, opts) ++ if err != nil { ++ log.Fatalln(fmt.Errorf("error creating s3 client: %w", err)) ++ } ++ ++ r.Handle("/", http.RedirectHandler("/buckets", http.StatusPermanentRedirect)).Methods(http.MethodGet) ++ r.Handle("/buckets", s3manager.HandleBucketsView(s3, templates, configuration.AllowDelete)).Methods(http.MethodGet) ++ r.PathPrefix("/buckets/").Handler(s3manager.HandleBucketView(s3, templates, configuration.AllowDelete, configuration.ListRecursive)).Methods(http.MethodGet) ++ r.Handle("/api/buckets", s3manager.HandleCreateBucket(s3)).Methods(http.MethodPost) ++ if configuration.AllowDelete { ++ r.Handle("/api/buckets/{bucketName}", s3manager.HandleDeleteBucket(s3)).Methods(http.MethodDelete) ++ } ++ r.Handle("/api/buckets/{bucketName}/objects", s3manager.HandleCreateObject(s3, sseType)).Methods(http.MethodPost) ++ r.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}/url", s3manager.HandleGenerateUrl(s3)).Methods(http.MethodGet) ++ r.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}", s3manager.HandleGetObject(s3, configuration.ForceDownload)).Methods(http.MethodGet) ++ if configuration.AllowDelete { ++ r.Handle("/api/buckets/{bucketName}/objects/{objectName:.*}", s3manager.HandleDeleteObject(s3)).Methods(http.MethodDelete) ++ } + } + + lr := logging.Handler(os.Stdout)(r) diff --git a/web/template/bucket.html.tmpl b/web/template/bucket.html.tmpl index e2f8d28..87add13 100644 --- a/web/template/bucket.html.tmpl @@ -24,3 +256,298 @@ index c7ea184..fb1dce7 100644 +diff --git a/internal/app/s3manager/auth.go b/internal/app/s3manager/auth.go +new file mode 100644 +index 0000000..58589e2 +--- /dev/null ++++ b/internal/app/s3manager/auth.go +@@ -0,0 +1,237 @@ ++package s3manager ++ ++import ( ++ "context" ++ "crypto/rand" ++ "crypto/tls" ++ "fmt" ++ "html/template" ++ "io/fs" ++ "log" ++ "net/http" ++ ++ "github.com/gorilla/sessions" ++ "github.com/minio/minio-go/v7" ++ "github.com/minio/minio-go/v7/pkg/credentials" ++) ++ ++type contextKey string ++ ++const s3ContextKey contextKey = "s3client" ++ ++// SessionConfig holds session store and S3 connection settings for login mode. ++type SessionConfig struct { ++ Store *sessions.CookieStore ++ Endpoint string ++ UseSSL bool ++ SkipSSLVerify bool ++ AllowDelete bool ++ ForceDownload bool ++ ListRecursive bool ++ SseInfo SSEType ++ Templates fs.FS ++} ++ ++// NewSessionStore creates a CookieStore with a random encryption key. ++func NewSessionStore() *sessions.CookieStore { ++ key := make([]byte, 32) ++ if _, err := rand.Read(key); err != nil { ++ log.Fatal("failed to generate session key:", err) ++ } ++ store := sessions.NewCookieStore(key) ++ store.Options = &sessions.Options{ ++ Path: "/", ++ MaxAge: 86400, ++ HttpOnly: true, ++ Secure: true, ++ SameSite: http.SameSiteLaxMode, ++ } ++ return store ++} ++ ++// NewS3Client creates a minio client from user-provided credentials. ++func NewS3Client(endpoint, accessKey, secretKey string, useSSL, skipSSLVerify bool) (*minio.Client, error) { ++ opts := &minio.Options{ ++ Creds: credentials.NewStaticV4(accessKey, secretKey, ""), ++ Secure: useSSL, ++ } ++ if useSSL && skipSSLVerify { ++ opts.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} //nolint:gosec ++ } ++ return minio.New(endpoint, opts) ++} ++ ++// S3FromContext retrieves the S3 client stored in request context. ++func S3FromContext(ctx context.Context) S3 { ++ if s3, ok := ctx.Value(s3ContextKey).(S3); ok { ++ return s3 ++ } ++ return nil ++} ++ ++func contextWithS3(ctx context.Context, s3 S3) context.Context { ++ return context.WithValue(ctx, s3ContextKey, s3) ++} ++ ++// RequireAuth is middleware that validates session credentials and injects ++// an S3 client into the request context. Redirects to /login if no session. ++func RequireAuth(cfg *SessionConfig, next http.Handler) http.Handler { ++ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ++ session, _ := cfg.Store.Get(r, "s3session") ++ accessKey, ok1 := session.Values["accessKey"].(string) ++ secretKey, ok2 := session.Values["secretKey"].(string) ++ if !ok1 || !ok2 || accessKey == "" || secretKey == "" { ++ http.Redirect(w, r, "/login", http.StatusFound) ++ return ++ } ++ ++ s3, err := NewS3Client(cfg.Endpoint, accessKey, secretKey, cfg.UseSSL, cfg.SkipSSLVerify) ++ if err != nil { ++ // Session has bad credentials — clear and redirect to login ++ session.Options.MaxAge = -1 ++ _ = session.Save(r, w) ++ http.Redirect(w, r, "/login", http.StatusFound) ++ return ++ } ++ ++ ctx := contextWithS3(r.Context(), s3) ++ next.ServeHTTP(w, r.WithContext(ctx)) ++ }) ++} ++ ++// HandleLoginView renders the login page. ++func HandleLoginView(templates fs.FS) http.HandlerFunc { ++ return func(w http.ResponseWriter, r *http.Request) { ++ errorMsg := r.URL.Query().Get("error") ++ ++ data := struct { ++ Error string ++ }{ ++ Error: errorMsg, ++ } ++ ++ t, err := template.ParseFS(templates, "layout.html.tmpl", "login.html.tmpl") ++ if err != nil { ++ handleHTTPError(w, fmt.Errorf("error parsing login template: %w", err)) ++ return ++ } ++ err = t.ExecuteTemplate(w, "layout", data) ++ if err != nil { ++ handleHTTPError(w, fmt.Errorf("error executing login template: %w", err)) ++ return ++ } ++ } ++} ++ ++// HandleLogin processes the login form POST. ++func HandleLogin(cfg *SessionConfig) http.HandlerFunc { ++ return func(w http.ResponseWriter, r *http.Request) { ++ accessKey := r.FormValue("accessKey") ++ secretKey := r.FormValue("secretKey") ++ ++ if accessKey == "" || secretKey == "" { ++ http.Redirect(w, r, "/login?error=credentials+required", http.StatusFound) ++ return ++ } ++ ++ // Validate credentials by attempting ListBuckets ++ s3, err := NewS3Client(cfg.Endpoint, accessKey, secretKey, cfg.UseSSL, cfg.SkipSSLVerify) ++ if err != nil { ++ http.Redirect(w, r, "/login?error=connection+failed", http.StatusFound) ++ return ++ } ++ _, err = s3.ListBuckets(r.Context()) ++ if err != nil { ++ http.Redirect(w, r, "/login?error=invalid+credentials", http.StatusFound) ++ return ++ } ++ ++ // Save credentials to session ++ session, _ := cfg.Store.Get(r, "s3session") ++ session.Values["accessKey"] = accessKey ++ session.Values["secretKey"] = secretKey ++ err = session.Save(r, w) ++ if err != nil { ++ handleHTTPError(w, fmt.Errorf("error saving session: %w", err)) ++ return ++ } ++ ++ http.Redirect(w, r, "/buckets", http.StatusFound) ++ } ++} ++ ++// HandleLogout destroys the session and redirects to login. ++func HandleLogout(cfg *SessionConfig) http.HandlerFunc { ++ return func(w http.ResponseWriter, r *http.Request) { ++ session, _ := cfg.Store.Get(r, "s3session") ++ session.Options.MaxAge = -1 ++ _ = session.Save(r, w) ++ http.Redirect(w, r, "/login", http.StatusFound) ++ } ++} ++ ++// Dynamic handler wrappers — extract S3 from context, delegate to original handlers. ++ ++// HandleBucketsViewDynamic wraps HandleBucketsView for login mode. ++func HandleBucketsViewDynamic(templates fs.FS, allowDelete bool) http.HandlerFunc { ++ return func(w http.ResponseWriter, r *http.Request) { ++ s3 := S3FromContext(r.Context()) ++ HandleBucketsView(s3, templates, allowDelete).ServeHTTP(w, r) ++ } ++} ++ ++// HandleBucketViewDynamic wraps HandleBucketView for login mode. ++func HandleBucketViewDynamic(templates fs.FS, allowDelete bool, listRecursive bool) http.HandlerFunc { ++ return func(w http.ResponseWriter, r *http.Request) { ++ s3 := S3FromContext(r.Context()) ++ HandleBucketView(s3, templates, allowDelete, listRecursive).ServeHTTP(w, r) ++ } ++} ++ ++// HandleCreateBucketDynamic wraps HandleCreateBucket for login mode. ++func HandleCreateBucketDynamic() http.HandlerFunc { ++ return func(w http.ResponseWriter, r *http.Request) { ++ s3 := S3FromContext(r.Context()) ++ HandleCreateBucket(s3).ServeHTTP(w, r) ++ } ++} ++ ++// HandleDeleteBucketDynamic wraps HandleDeleteBucket for login mode. ++func HandleDeleteBucketDynamic() http.HandlerFunc { ++ return func(w http.ResponseWriter, r *http.Request) { ++ s3 := S3FromContext(r.Context()) ++ HandleDeleteBucket(s3).ServeHTTP(w, r) ++ } ++} ++ ++// HandleCreateObjectDynamic wraps HandleCreateObject for login mode. ++func HandleCreateObjectDynamic(sseInfo SSEType) http.HandlerFunc { ++ return func(w http.ResponseWriter, r *http.Request) { ++ s3 := S3FromContext(r.Context()) ++ HandleCreateObject(s3, sseInfo).ServeHTTP(w, r) ++ } ++} ++ ++// HandleGenerateUrlDynamic wraps HandleGenerateUrl for login mode. ++func HandleGenerateUrlDynamic() http.HandlerFunc { ++ return func(w http.ResponseWriter, r *http.Request) { ++ s3 := S3FromContext(r.Context()) ++ HandleGenerateUrl(s3).ServeHTTP(w, r) ++ } ++} ++ ++// HandleGetObjectDynamic wraps HandleGetObject for login mode. ++func HandleGetObjectDynamic(forceDownload bool) http.HandlerFunc { ++ return func(w http.ResponseWriter, r *http.Request) { ++ s3 := S3FromContext(r.Context()) ++ HandleGetObject(s3, forceDownload).ServeHTTP(w, r) ++ } ++} ++ ++// HandleDeleteObjectDynamic wraps HandleDeleteObject for login mode. ++func HandleDeleteObjectDynamic() http.HandlerFunc { ++ return func(w http.ResponseWriter, r *http.Request) { ++ s3 := S3FromContext(r.Context()) ++ HandleDeleteObject(s3).ServeHTTP(w, r) ++ } ++} +diff --git a/web/template/login.html.tmpl b/web/template/login.html.tmpl +new file mode 100644 +index 0000000..f153018 +--- /dev/null ++++ b/web/template/login.html.tmpl +@@ -0,0 +1,46 @@ ++{{ define "content" }} ++ ++ ++ ++
++
++
++
++
++
++ Sign In ++

Enter your S3 credentials to access the bucket manager.

++
++ ++ {{ if .Error }} ++
++ error {{ .Error }} ++
++ {{ end }} ++ ++
++
++ vpn_key ++ ++ ++
++
++ lock ++ ++ ++
++
++ ++ ++
++
++
++
++
++
++{{ end }} diff --git a/packages/system/bucket/templates/deployment.yaml b/packages/system/bucket/templates/deployment.yaml index 7e115de0..5c13cb2d 100644 --- a/packages/system/bucket/templates/deployment.yaml +++ b/packages/system/bucket/templates/deployment.yaml @@ -1,3 +1,12 @@ +{{- $endpoint := printf "s3.%s" .Values._namespace.host }} +{{- range $name, $user := .Values.users }} + {{- $secretName := printf "%s-%s" $.Values.bucketName $name }} + {{- $existingSecret := lookup "v1" "Secret" $.Release.Namespace $secretName }} + {{- if $existingSecret }} + {{- $bucketInfo := fromJson (b64dec (index $existingSecret.data "BucketInfo")) }} + {{- $endpoint = trimPrefix "https://" (index $bucketInfo.spec.secretS3 "endpoint") }} + {{- end }} +{{- end }} apiVersion: apps/v1 kind: Deployment metadata: @@ -17,19 +26,6 @@ spec: image: "{{ $.Files.Get "images/s3manager.tag" | trim }}" env: - name: ENDPOINT - valueFrom: - secretKeyRef: - name: {{ .Values.bucketName }}-credentials - key: endpoint + value: {{ $endpoint | quote }} - name: SKIP_SSL_VERIFICATION value: "true" - - name: ACCESS_KEY_ID - valueFrom: - secretKeyRef: - name: {{ .Values.bucketName }}-credentials - key: accessKey - - name: SECRET_ACCESS_KEY - valueFrom: - secretKeyRef: - name: {{ .Values.bucketName }}-credentials - key: secretKey diff --git a/packages/system/bucket/templates/ingress.yaml b/packages/system/bucket/templates/ingress.yaml index d8d659c7..b7ffaf8b 100644 --- a/packages/system/bucket/templates/ingress.yaml +++ b/packages/system/bucket/templates/ingress.yaml @@ -1,24 +1,20 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} +{{- $host := .Values._namespace.host }} +{{- $ingress := .Values._namespace.ingress }} +{{- $solver := (index .Values._cluster "solver") | default "http01" }} +{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }} apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: {{ .Values.bucketName }}-ui annotations: - nginx.ingress.kubernetes.io/auth-type: "basic" - nginx.ingress.kubernetes.io/auth-secret: "{{ .Values.bucketName }}-ui-auth" - nginx.ingress.kubernetes.io/auth-realm: "Authentication Required" nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/proxy-read-timeout: "99999" nginx.ingress.kubernetes.io/proxy-send-timeout: "99999" - {{- if ne $issuerType "cloudflare" }} - acme.cert-manager.io/http01-ingress-class: {{ $ingress }} + {{- if eq $solver "http01" }} + acme.cert-manager.io/http01-ingress-ingressclassname: {{ $ingress }} {{- end }} - cert-manager.io/cluster-issuer: letsencrypt-prod + cert-manager.io/cluster-issuer: {{ $clusterIssuer }} spec: ingressClassName: {{ $ingress }} tls: diff --git a/packages/system/bucket/templates/secret.yaml b/packages/system/bucket/templates/secret.yaml index 9c5442ce..683a0972 100644 --- a/packages/system/bucket/templates/secret.yaml +++ b/packages/system/bucket/templates/secret.yaml @@ -1,22 +1,2 @@ -{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace .Values.bucketName }} -{{- $bucketInfo := fromJson (b64dec (index $existingSecret.data "BucketInfo")) }} -{{- $accessKeyID := index $bucketInfo.spec.secretS3 "accessKeyID" }} -{{- $accessSecretKey := index $bucketInfo.spec.secretS3 "accessSecretKey" }} -{{- $endpoint := index $bucketInfo.spec.secretS3 "endpoint" }} - -apiVersion: v1 -kind: Secret -metadata: - name: {{ .Values.bucketName }}-credentials -type: Opaque -stringData: - accessKey: {{ $accessKeyID | quote }} - secretKey: {{ $accessSecretKey | quote }} - endpoint: {{ trimPrefix "https://" $endpoint }} ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ .Values.bucketName }}-ui-auth -data: - auth: {{ htpasswd $accessKeyID $accessSecretKey | b64enc | quote }} +{{/* Secrets previously used for s3manager credential injection and nginx basic auth */}} +{{/* are no longer needed — s3manager now handles authentication via its own login page */}} diff --git a/packages/system/bucket/templates/user-credentials.yaml b/packages/system/bucket/templates/user-credentials.yaml new file mode 100644 index 00000000..7ccdd731 --- /dev/null +++ b/packages/system/bucket/templates/user-credentials.yaml @@ -0,0 +1,20 @@ +{{- range $name, $user := .Values.users }} +{{- $secretName := printf "%s-%s" $.Values.bucketName $name }} +{{- $existingSecret := lookup "v1" "Secret" $.Release.Namespace $secretName }} +{{- if $existingSecret }} +{{- $bucketInfo := fromJson (b64dec (index $existingSecret.data "BucketInfo")) }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ $secretName }}-credentials + labels: + apps.cozystack.io/user-secret: "true" +type: Opaque +stringData: + accessKey: {{ index $bucketInfo.spec.secretS3 "accessKeyID" | quote }} + secretKey: {{ index $bucketInfo.spec.secretS3 "accessSecretKey" | quote }} + endpoint: {{ trimPrefix "https://" (index $bucketInfo.spec.secretS3 "endpoint") }} + bucketName: {{ index $bucketInfo.spec "bucketName" | quote }} +{{- end }} +{{- end }} diff --git a/packages/system/bucket/values.yaml b/packages/system/bucket/values.yaml index e1499c6e..739c4977 100644 --- a/packages/system/bucket/values.yaml +++ b/packages/system/bucket/values.yaml @@ -1 +1,2 @@ bucketName: "cozystack" +users: {} diff --git a/packages/system/capi-operator/Makefile b/packages/system/capi-operator/Makefile index dc421cee..9349f549 100644 --- a/packages/system/capi-operator/Makefile +++ b/packages/system/capi-operator/Makefile @@ -5,7 +5,7 @@ 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 +include ../../../hack/package.mk update: clean capi-operator-update rm -rf charts/cluster-api-operator/charts/ diff --git a/packages/system/capi-providers-bootstrap/Makefile b/packages/system/capi-providers-bootstrap/Makefile index f588e439..54d8ca8b 100644 --- a/packages/system/capi-providers-bootstrap/Makefile +++ b/packages/system/capi-providers-bootstrap/Makefile @@ -1,4 +1,4 @@ export NAME=capi-providers-bootstrap export NAMESPACE=cozy-cluster-api -include ../../../scripts/package.mk +include ../../../hack/package.mk diff --git a/packages/system/capi-providers-core/Makefile b/packages/system/capi-providers-core/Makefile index a9bae779..f5f038c1 100644 --- a/packages/system/capi-providers-core/Makefile +++ b/packages/system/capi-providers-core/Makefile @@ -1,4 +1,4 @@ export NAME=capi-providers-core export NAMESPACE=cozy-cluster-api -include ../../../scripts/package.mk +include ../../../hack/package.mk diff --git a/packages/system/capi-providers-cpprovider/Makefile b/packages/system/capi-providers-cpprovider/Makefile index 06f0dd6d..caec8d96 100644 --- a/packages/system/capi-providers-cpprovider/Makefile +++ b/packages/system/capi-providers-cpprovider/Makefile @@ -1,4 +1,4 @@ export NAME=capi-providers-cpprovider export NAMESPACE=cozy-cluster-api -include ../../../scripts/package.mk +include ../../../hack/package.mk diff --git a/packages/system/capi-providers-cpprovider/files/components.gz b/packages/system/capi-providers-cpprovider/files/components.gz index 60ac302a..930a26af 100644 Binary files a/packages/system/capi-providers-cpprovider/files/components.gz and b/packages/system/capi-providers-cpprovider/files/components.gz differ diff --git a/packages/system/capi-providers-cpprovider/files/control-plane-components.yaml b/packages/system/capi-providers-cpprovider/files/control-plane-components.yaml index d30e7373..64fc7d6d 100644 --- a/packages/system/capi-providers-cpprovider/files/control-plane-components.yaml +++ b/packages/system/capi-providers-cpprovider/files/control-plane-components.yaml @@ -109,7 +109,7 @@ spec: agent: default: image: registry.k8s.io/kas-network-proxy/proxy-agent - version: v0.28.6 + mode: DaemonSet properties: extraArgs: description: |- @@ -120,10 +120,31 @@ spec: items: type: string type: array + hostNetwork: + default: false + description: |- + HostNetwork enables the konnectivity agent to use the Host network namespace. + By enabling this mode, the Agent doesn't need to wait for the CNI initialisation, + enabling a sort of out-of-band access to nodes for troubleshooting scenarios, + or when the agent needs direct access to the host network. + type: boolean image: default: registry.k8s.io/kas-network-proxy/proxy-agent description: AgentImage defines the container image for Konnectivity's agent. type: string + mode: + default: DaemonSet + description: 'Mode allows specifying the Agent deployment mode: Deployment, or DaemonSet (default).' + enum: + - DaemonSet + - Deployment + type: string + replicas: + description: |- + Replicas defines the number of replicas when Mode is Deployment. + Must be 0 if Mode is DaemonSet. + format: int32 + type: integer tolerations: default: - key: CriticalAddonsOnly @@ -169,15 +190,20 @@ spec: type: object type: array version: - default: v0.28.6 - description: Version for Konnectivity agent. + description: |- + Version for Konnectivity agent. + If left empty, Kamaji will automatically inflect the version from the deployed Tenant Control Plane. + + WARNING: for last cut-off releases, the container image could be not available. type: string type: object + x-kubernetes-validations: + - message: replicas must be 0 when mode is DaemonSet, and greater than 0 when mode is Deployment + rule: '!(self.mode == ''DaemonSet'' && has(self.replicas) && self.replicas != 0) && !(self.mode == ''Deployment'' && self.replicas == 0)' server: default: image: registry.k8s.io/kas-network-proxy/proxy-server port: 8132 - version: v0.28.6 properties: extraArgs: description: |- @@ -204,7 +230,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -256,8 +282,11 @@ spec: type: object type: object version: - default: v0.28.6 - description: Container image version of the Konnectivity server. + description: |- + Container image version of the Konnectivity server. + If left empty, Kamaji will automatically inflect the version from the deployed Tenant Control Plane. + + WARNING: for last cut-off releases, the container image could be not available. type: string required: - port @@ -410,7 +439,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -560,7 +589,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -620,6 +649,16 @@ spec: dataStoreSchema: description: DataStoreSchema allows to specify the name of the database (for relational DataStores) or the key prefix (for etcd) type: string + dataStoreUsername: + description: |- + DataStoreUsername allows to specify the username of the database (for relational DataStores). This + value is optional and immutable. Note that Kamaji currently doesn't ensure that DataStoreUsername values are unique. It's up + to the user to avoid clashes between different TenantControlPlanes. If not set upon creation, Kamaji will default the + DataStoreUsername by concatenating the namespace and name of the TenantControlPlane. + type: string + x-kubernetes-validations: + - message: changing the dataStoreUsername is not supported + rule: self == oldSelf deployment: description: Configure how the TenantControlPlane Deployment object should be configured. properties: @@ -903,7 +942,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 @@ -918,7 +956,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 @@ -1079,7 +1116,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 @@ -1094,7 +1130,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 @@ -1183,8 +1218,8 @@ spec: most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. items: description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) @@ -1248,7 +1283,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 @@ -1263,7 +1297,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 @@ -1424,7 +1457,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 @@ -1439,7 +1471,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 @@ -1587,7 +1618,9 @@ spec: description: EnvVar represents an environment variable present in a Container. properties: name: - description: Name of the environment variable. Must be a C_IDENTIFIER. + description: |- + Name of the environment variable. + May consist of any printable ASCII characters except '='. type: string value: description: |- @@ -1641,6 +1674,42 @@ spec: - fieldPath type: object x-kubernetes-map-type: atomic + fileKeyRef: + description: |- + FileKeyRef selects a key of the env file. + Requires the EnvFiles feature gate to be enabled. + properties: + key: + description: |- + The key within the env file. An invalid key will prevent the pod from starting. + The keys defined within a source may consist of any printable ASCII characters except '='. + During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. + type: string + optional: + default: false + description: |- + Specify whether the file or its key must be defined. If the file or key + does not exist, then the env var is not published. + If optional is set to true and the specified key does not exist, + the environment variable will not be set in the Pod's containers. + + If optional is set to false and the specified key does not exist, + an error will be returned during Pod creation. + type: boolean + path: + description: |- + The path within the volume from which to select the file. + Must be relative and may not contain the '..' path or start with '..'. + type: string + volumeName: + description: The name of the volume mount containing the env file. + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic resourceFieldRef: description: |- Selects a resource of the container: only resources limits and requests @@ -1696,13 +1765,13 @@ spec: envFrom: description: |- List of sources to populate environment variables in the container. - The keys defined within a source must be a C_IDENTIFIER. All invalid keys - will be reported as an event when the container is starting. When a key exists in multiple + The keys defined within a source may consist of any printable ASCII characters except '='. + When a key exists in multiple sources, the value associated with the last source will take precedence. 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 @@ -1722,7 +1791,9 @@ 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. + May consist of any printable ASCII characters except '='. type: string secretRef: description: The Secret to select from @@ -1971,6 +2042,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: |- @@ -2361,7 +2438,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -2415,10 +2492,10 @@ spec: restartPolicy: description: |- RestartPolicy defines the restart behavior of individual containers in a pod. - This field may only be set for init containers, and the only allowed value is "Always". - For non-init containers or when this field is not specified, + This overrides the pod-level restart policy. When this field is not specified, the restart behavior is defined by the Pod's restart policy and the container type. - Setting the RestartPolicy as "Always" for the init container will have the following effect: + Additionally, setting the RestartPolicy as "Always" for the init container will + have the following effect: this init container will be continually restarted on exit until all regular containers have terminated. Once all regular containers have completed, all init containers with restartPolicy "Always" @@ -2430,6 +2507,57 @@ spec: init container is started, or after any startupProbe has successfully completed. type: string + restartPolicyRules: + description: |- + Represents a list of rules to be checked to determine if the + container should be restarted on exit. The rules are evaluated in + order. Once a rule matches a container exit condition, the remaining + rules are ignored. If no rule matches the container exit condition, + the Container-level restart policy determines the whether the container + is restarted or not. Constraints on the rules: + - At most 20 rules are allowed. + - Rules can have the same action. + - Identical rules are not forbidden in validations. + When rules are specified, container MUST set RestartPolicy explicitly + even it if matches the Pod's RestartPolicy. + items: + description: ContainerRestartRule describes how a container exit is handled. + properties: + action: + description: |- + Specifies the action taken on a container exit if the requirements + are satisfied. The only possible value is "Restart" to restart the + container. + type: string + exitCodes: + description: Represents the exit codes to check on container exits. + properties: + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. Possible values are: + - In: the requirement is satisfied if the container exit code is in the + set of specified values. + - NotIn: the requirement is satisfied if the container exit code is + not in the set of specified values. + type: string + values: + description: |- + Specifies the set of values to check for container exit codes. + At most 255 elements are allowed. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic securityContext: description: |- SecurityContext defines the security options the container should be run with. @@ -2951,7 +3079,9 @@ spec: description: EnvVar represents an environment variable present in a Container. properties: name: - description: Name of the environment variable. Must be a C_IDENTIFIER. + description: |- + Name of the environment variable. + May consist of any printable ASCII characters except '='. type: string value: description: |- @@ -3005,6 +3135,42 @@ spec: - fieldPath type: object x-kubernetes-map-type: atomic + fileKeyRef: + description: |- + FileKeyRef selects a key of the env file. + Requires the EnvFiles feature gate to be enabled. + properties: + key: + description: |- + The key within the env file. An invalid key will prevent the pod from starting. + The keys defined within a source may consist of any printable ASCII characters except '='. + During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. + type: string + optional: + default: false + description: |- + Specify whether the file or its key must be defined. If the file or key + does not exist, then the env var is not published. + If optional is set to true and the specified key does not exist, + the environment variable will not be set in the Pod's containers. + + If optional is set to false and the specified key does not exist, + an error will be returned during Pod creation. + type: boolean + path: + description: |- + The path within the volume from which to select the file. + Must be relative and may not contain the '..' path or start with '..'. + type: string + volumeName: + description: The name of the volume mount containing the env file. + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic resourceFieldRef: description: |- Selects a resource of the container: only resources limits and requests @@ -3060,13 +3226,13 @@ spec: envFrom: description: |- List of sources to populate environment variables in the container. - The keys defined within a source must be a C_IDENTIFIER. All invalid keys - will be reported as an event when the container is starting. When a key exists in multiple + The keys defined within a source may consist of any printable ASCII characters except '='. + When a key exists in multiple sources, the value associated with the last source will take precedence. 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 @@ -3086,7 +3252,9 @@ 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. + May consist of any printable ASCII characters except '='. type: string secretRef: description: The Secret to select from @@ -3335,6 +3503,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: |- @@ -3725,7 +3899,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -3779,10 +3953,10 @@ spec: restartPolicy: description: |- RestartPolicy defines the restart behavior of individual containers in a pod. - This field may only be set for init containers, and the only allowed value is "Always". - For non-init containers or when this field is not specified, + This overrides the pod-level restart policy. When this field is not specified, the restart behavior is defined by the Pod's restart policy and the container type. - Setting the RestartPolicy as "Always" for the init container will have the following effect: + Additionally, setting the RestartPolicy as "Always" for the init container will + have the following effect: this init container will be continually restarted on exit until all regular containers have terminated. Once all regular containers have completed, all init containers with restartPolicy "Always" @@ -3794,6 +3968,57 @@ spec: init container is started, or after any startupProbe has successfully completed. type: string + restartPolicyRules: + description: |- + Represents a list of rules to be checked to determine if the + container should be restarted on exit. The rules are evaluated in + order. Once a rule matches a container exit condition, the remaining + rules are ignored. If no rule matches the container exit condition, + the Container-level restart policy determines the whether the container + is restarted or not. Constraints on the rules: + - At most 20 rules are allowed. + - Rules can have the same action. + - Identical rules are not forbidden in validations. + When rules are specified, container MUST set RestartPolicy explicitly + even it if matches the Pod's RestartPolicy. + items: + description: ContainerRestartRule describes how a container exit is handled. + properties: + action: + description: |- + Specifies the action taken on a container exit if the requirements + are satisfied. The only possible value is "Restart" to restart the + container. + type: string + exitCodes: + description: Represents the exit codes to check on container exits. + properties: + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. Possible values are: + - In: the requirement is satisfied if the container exit code is in the + set of specified values. + - NotIn: the requirement is satisfied if the container exit code is + not in the set of specified values. + type: string + values: + description: |- + Specifies the set of values to check for container exit codes. + At most 255 elements are allowed. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic securityContext: description: |- SecurityContext defines the security options the container should be run with. @@ -4915,15 +5140,13 @@ spec: volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. If specified, the CSI driver will create or update the volume with the attributes defined in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -5097,12 +5320,9 @@ spec: description: |- glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported. - More info: https://examples.k8s.io/volumes/glusterfs/README.md properties: endpoints: - description: |- - endpoints is the endpoint name that details Glusterfs topology. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + description: endpoints is the endpoint name that details Glusterfs topology. type: string path: description: |- @@ -5156,7 +5376,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: @@ -5181,7 +5401,7 @@ spec: description: |- iscsi represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. - More info: https://examples.k8s.io/volumes/iscsi/README.md + More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi properties: chapAuthDiscovery: description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication @@ -5571,6 +5791,110 @@ spec: type: array x-kubernetes-list-type: atomic type: object + podCertificate: + description: |- + Projects an auto-rotating credential bundle (private key and certificate + chain) that the pod can use either as a TLS client or server. + + Kubelet generates a private key and uses it to send a + PodCertificateRequest to the named signer. Once the signer approves the + request and issues a certificate chain, Kubelet writes the key and + certificate chain to the pod filesystem. The pod does not start until + certificates have been issued for each podCertificate projected volume + source in its spec. + + Kubelet will begin trying to rotate the certificate at the time indicated + by the signer using the PodCertificateRequest.Status.BeginRefreshAt + timestamp. + + Kubelet can write a single file, indicated by the credentialBundlePath + field, or separate files, indicated by the keyPath and + certificateChainPath fields. + + The credential bundle is a single file in PEM format. The first PEM + entry is the private key (in PKCS#8 format), and the remaining PEM + entries are the certificate chain issued by the signer (typically, + signers will return their certificate chain in leaf-to-root order). + + Prefer using the credential bundle format, since your application code + can read it atomically. If you use keyPath and certificateChainPath, + your application must make two separate file reads. If these coincide + with a certificate rotation, it is possible that the private key and leaf + certificate you read may not correspond to each other. Your application + will need to check for this condition, and re-read until they are + consistent. + + The named signer controls chooses the format of the certificate it + issues; consult the signer implementation's documentation to learn how to + use the certificates it issues. + properties: + certificateChainPath: + description: |- + Write the certificate chain at this path in the projected volume. + + Most applications should use credentialBundlePath. When using keyPath + and certificateChainPath, your application needs to check that the key + and leaf certificate are consistent, because it is possible to read the + files mid-rotation. + type: string + credentialBundlePath: + description: |- + Write the credential bundle at this path in the projected volume. + + The credential bundle is a single file that contains multiple PEM blocks. + The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private + key. + + The remaining blocks are CERTIFICATE blocks, containing the issued + certificate chain from the signer (leaf and any intermediates). + + Using credentialBundlePath lets your Pod's application code make a single + atomic read that retrieves a consistent key and certificate chain. If you + project them to separate files, your application code will need to + additionally check that the leaf certificate was issued to the key. + type: string + keyPath: + description: |- + Write the key at this path in the projected volume. + + Most applications should use credentialBundlePath. When using keyPath + and certificateChainPath, your application needs to check that the key + and leaf certificate are consistent, because it is possible to read the + files mid-rotation. + type: string + keyType: + description: |- + The type of keypair Kubelet will generate for the pod. + + Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384", + "ECDSAP521", and "ED25519". + type: string + maxExpirationSeconds: + description: |- + maxExpirationSeconds is the maximum lifetime permitted for the + certificate. + + Kubelet copies this value verbatim into the PodCertificateRequests it + generates for this projection. + + If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver + will reject values shorter than 3600 (1 hour). The maximum allowable + value is 7862400 (91 days). + + The signer implementation is then free to issue a certificate with any + lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600 + seconds (1 hour). This constraint is enforced by kube-apiserver. + `kubernetes.io` signers will never issue certificates with a lifetime + longer than 24 hours. + format: int32 + type: integer + signerName: + description: Kubelet's generated CSRs will be addressed to this signer. + type: string + required: + - keyType + - signerName + type: object secret: description: secret information about the secret data to project properties: @@ -5700,7 +6024,6 @@ spec: description: |- rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported. - More info: https://examples.k8s.io/volumes/rbd/README.md properties: fsType: description: |- @@ -6199,7 +6522,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: |- @@ -6210,7 +6532,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: |- @@ -6270,7 +6591,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -6326,14 +6647,14 @@ spec: default: cgroupfs: systemd preferredAddressTypes: - - Hostname - InternalIP - ExternalIP + - Hostname description: Configure the Kubelet options, such as the preferred address types, or the expected cgroupfs. properties: cgroupfs: description: |- - CGroupFS defines the cgroup driver for Kubelet + CGroupFS defines the cgroup driver for Kubelet https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/configure-cgroup-driver/ enum: - systemd @@ -6341,12 +6662,12 @@ spec: type: string preferredAddressTypes: default: - - Hostname - InternalIP - ExternalIP + - Hostname description: |- Ordered list of the preferred NodeAddressTypes to use for kubelet connections. - Default to Hostname, InternalIP, ExternalIP. + Default to InternalIP, ExternalIP, Hostname. items: enum: - Hostname @@ -6357,6 +6678,7 @@ spec: type: string minItems: 1 type: array + x-kubernetes-list-type: set type: object network: default: @@ -6557,7 +6879,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -6844,7 +7166,7 @@ spec: agent: default: image: registry.k8s.io/kas-network-proxy/proxy-agent - version: v0.28.6 + mode: DaemonSet properties: extraArgs: description: |- @@ -6855,10 +7177,31 @@ spec: items: type: string type: array + hostNetwork: + default: false + description: |- + HostNetwork enables the konnectivity agent to use the Host network namespace. + By enabling this mode, the Agent doesn't need to wait for the CNI initialisation, + enabling a sort of out-of-band access to nodes for troubleshooting scenarios, + or when the agent needs direct access to the host network. + type: boolean image: default: registry.k8s.io/kas-network-proxy/proxy-agent description: AgentImage defines the container image for Konnectivity's agent. type: string + mode: + default: DaemonSet + description: 'Mode allows specifying the Agent deployment mode: Deployment, or DaemonSet (default).' + enum: + - DaemonSet + - Deployment + type: string + replicas: + description: |- + Replicas defines the number of replicas when Mode is Deployment. + Must be 0 if Mode is DaemonSet. + format: int32 + type: integer tolerations: default: - key: CriticalAddonsOnly @@ -6904,15 +7247,20 @@ spec: type: object type: array version: - default: v0.28.6 - description: Version for Konnectivity agent. + description: |- + Version for Konnectivity agent. + If left empty, Kamaji will automatically inflect the version from the deployed Tenant Control Plane. + + WARNING: for last cut-off releases, the container image could be not available. type: string type: object + x-kubernetes-validations: + - message: replicas must be 0 when mode is DaemonSet, and greater than 0 when mode is Deployment + rule: '!(self.mode == ''DaemonSet'' && has(self.replicas) && self.replicas != 0) && !(self.mode == ''Deployment'' && self.replicas == 0)' server: default: image: registry.k8s.io/kas-network-proxy/proxy-server port: 8132 - version: v0.28.6 properties: extraArgs: description: |- @@ -6939,7 +7287,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -6991,8 +7339,11 @@ spec: type: object type: object version: - default: v0.28.6 - description: Container image version of the Konnectivity server. + description: |- + Container image version of the Konnectivity server. + If left empty, Kamaji will automatically inflect the version from the deployed Tenant Control Plane. + + WARNING: for last cut-off releases, the container image could be not available. type: string required: - port @@ -7145,7 +7496,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -7280,7 +7631,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -7340,6 +7691,16 @@ spec: dataStoreSchema: description: DataStoreSchema allows to specify the name of the database (for relational DataStores) or the key prefix (for etcd) type: string + dataStoreUsername: + description: |- + DataStoreUsername allows to specify the username of the database (for relational DataStores). This + value is optional and immutable. Note that Kamaji currently doesn't ensure that DataStoreUsername values are unique. It's up + to the user to avoid clashes between different TenantControlPlanes. If not set upon creation, Kamaji will default the + DataStoreUsername by concatenating the namespace and name of the TenantControlPlane. + type: string + x-kubernetes-validations: + - message: changing the dataStoreUsername is not supported + rule: self == oldSelf deployment: description: Configure how the TenantControlPlane Deployment object should be configured. properties: @@ -7623,7 +7984,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 @@ -7638,7 +7998,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 @@ -7799,7 +8158,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 @@ -7814,7 +8172,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 @@ -7903,8 +8260,8 @@ spec: most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. items: description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) @@ -7968,7 +8325,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 @@ -7983,7 +8339,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 @@ -8144,7 +8499,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 @@ -8159,7 +8513,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 @@ -8307,7 +8660,9 @@ spec: description: EnvVar represents an environment variable present in a Container. properties: name: - description: Name of the environment variable. Must be a C_IDENTIFIER. + description: |- + Name of the environment variable. + May consist of any printable ASCII characters except '='. type: string value: description: |- @@ -8361,6 +8716,42 @@ spec: - fieldPath type: object x-kubernetes-map-type: atomic + fileKeyRef: + description: |- + FileKeyRef selects a key of the env file. + Requires the EnvFiles feature gate to be enabled. + properties: + key: + description: |- + The key within the env file. An invalid key will prevent the pod from starting. + The keys defined within a source may consist of any printable ASCII characters except '='. + During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. + type: string + optional: + default: false + description: |- + Specify whether the file or its key must be defined. If the file or key + does not exist, then the env var is not published. + If optional is set to true and the specified key does not exist, + the environment variable will not be set in the Pod's containers. + + If optional is set to false and the specified key does not exist, + an error will be returned during Pod creation. + type: boolean + path: + description: |- + The path within the volume from which to select the file. + Must be relative and may not contain the '..' path or start with '..'. + type: string + volumeName: + description: The name of the volume mount containing the env file. + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic resourceFieldRef: description: |- Selects a resource of the container: only resources limits and requests @@ -8416,13 +8807,13 @@ spec: envFrom: description: |- List of sources to populate environment variables in the container. - The keys defined within a source must be a C_IDENTIFIER. All invalid keys - will be reported as an event when the container is starting. When a key exists in multiple + The keys defined within a source may consist of any printable ASCII characters except '='. + When a key exists in multiple sources, the value associated with the last source will take precedence. 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 @@ -8442,7 +8833,9 @@ 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. + May consist of any printable ASCII characters except '='. type: string secretRef: description: The Secret to select from @@ -8691,6 +9084,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: |- @@ -9081,7 +9480,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -9135,10 +9534,10 @@ spec: restartPolicy: description: |- RestartPolicy defines the restart behavior of individual containers in a pod. - This field may only be set for init containers, and the only allowed value is "Always". - For non-init containers or when this field is not specified, + This overrides the pod-level restart policy. When this field is not specified, the restart behavior is defined by the Pod's restart policy and the container type. - Setting the RestartPolicy as "Always" for the init container will have the following effect: + Additionally, setting the RestartPolicy as "Always" for the init container will + have the following effect: this init container will be continually restarted on exit until all regular containers have terminated. Once all regular containers have completed, all init containers with restartPolicy "Always" @@ -9150,6 +9549,57 @@ spec: init container is started, or after any startupProbe has successfully completed. type: string + restartPolicyRules: + description: |- + Represents a list of rules to be checked to determine if the + container should be restarted on exit. The rules are evaluated in + order. Once a rule matches a container exit condition, the remaining + rules are ignored. If no rule matches the container exit condition, + the Container-level restart policy determines the whether the container + is restarted or not. Constraints on the rules: + - At most 20 rules are allowed. + - Rules can have the same action. + - Identical rules are not forbidden in validations. + When rules are specified, container MUST set RestartPolicy explicitly + even it if matches the Pod's RestartPolicy. + items: + description: ContainerRestartRule describes how a container exit is handled. + properties: + action: + description: |- + Specifies the action taken on a container exit if the requirements + are satisfied. The only possible value is "Restart" to restart the + container. + type: string + exitCodes: + description: Represents the exit codes to check on container exits. + properties: + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. Possible values are: + - In: the requirement is satisfied if the container exit code is in the + set of specified values. + - NotIn: the requirement is satisfied if the container exit code is + not in the set of specified values. + type: string + values: + description: |- + Specifies the set of values to check for container exit codes. + At most 255 elements are allowed. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic securityContext: description: |- SecurityContext defines the security options the container should be run with. @@ -9671,7 +10121,9 @@ spec: description: EnvVar represents an environment variable present in a Container. properties: name: - description: Name of the environment variable. Must be a C_IDENTIFIER. + description: |- + Name of the environment variable. + May consist of any printable ASCII characters except '='. type: string value: description: |- @@ -9725,6 +10177,42 @@ spec: - fieldPath type: object x-kubernetes-map-type: atomic + fileKeyRef: + description: |- + FileKeyRef selects a key of the env file. + Requires the EnvFiles feature gate to be enabled. + properties: + key: + description: |- + The key within the env file. An invalid key will prevent the pod from starting. + The keys defined within a source may consist of any printable ASCII characters except '='. + During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. + type: string + optional: + default: false + description: |- + Specify whether the file or its key must be defined. If the file or key + does not exist, then the env var is not published. + If optional is set to true and the specified key does not exist, + the environment variable will not be set in the Pod's containers. + + If optional is set to false and the specified key does not exist, + an error will be returned during Pod creation. + type: boolean + path: + description: |- + The path within the volume from which to select the file. + Must be relative and may not contain the '..' path or start with '..'. + type: string + volumeName: + description: The name of the volume mount containing the env file. + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic resourceFieldRef: description: |- Selects a resource of the container: only resources limits and requests @@ -9780,13 +10268,13 @@ spec: envFrom: description: |- List of sources to populate environment variables in the container. - The keys defined within a source must be a C_IDENTIFIER. All invalid keys - will be reported as an event when the container is starting. When a key exists in multiple + The keys defined within a source may consist of any printable ASCII characters except '='. + When a key exists in multiple sources, the value associated with the last source will take precedence. 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 @@ -9806,7 +10294,9 @@ 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. + May consist of any printable ASCII characters except '='. type: string secretRef: description: The Secret to select from @@ -10055,6 +10545,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: |- @@ -10445,7 +10941,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -10499,10 +10995,10 @@ spec: restartPolicy: description: |- RestartPolicy defines the restart behavior of individual containers in a pod. - This field may only be set for init containers, and the only allowed value is "Always". - For non-init containers or when this field is not specified, + This overrides the pod-level restart policy. When this field is not specified, the restart behavior is defined by the Pod's restart policy and the container type. - Setting the RestartPolicy as "Always" for the init container will have the following effect: + Additionally, setting the RestartPolicy as "Always" for the init container will + have the following effect: this init container will be continually restarted on exit until all regular containers have terminated. Once all regular containers have completed, all init containers with restartPolicy "Always" @@ -10514,6 +11010,57 @@ spec: init container is started, or after any startupProbe has successfully completed. type: string + restartPolicyRules: + description: |- + Represents a list of rules to be checked to determine if the + container should be restarted on exit. The rules are evaluated in + order. Once a rule matches a container exit condition, the remaining + rules are ignored. If no rule matches the container exit condition, + the Container-level restart policy determines the whether the container + is restarted or not. Constraints on the rules: + - At most 20 rules are allowed. + - Rules can have the same action. + - Identical rules are not forbidden in validations. + When rules are specified, container MUST set RestartPolicy explicitly + even it if matches the Pod's RestartPolicy. + items: + description: ContainerRestartRule describes how a container exit is handled. + properties: + action: + description: |- + Specifies the action taken on a container exit if the requirements + are satisfied. The only possible value is "Restart" to restart the + container. + type: string + exitCodes: + description: Represents the exit codes to check on container exits. + properties: + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. Possible values are: + - In: the requirement is satisfied if the container exit code is in the + set of specified values. + - NotIn: the requirement is satisfied if the container exit code is + not in the set of specified values. + type: string + values: + description: |- + Specifies the set of values to check for container exit codes. + At most 255 elements are allowed. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic securityContext: description: |- SecurityContext defines the security options the container should be run with. @@ -11635,15 +12182,13 @@ spec: volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. If specified, the CSI driver will create or update the volume with the attributes defined in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -11817,12 +12362,9 @@ spec: description: |- glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported. - More info: https://examples.k8s.io/volumes/glusterfs/README.md properties: endpoints: - description: |- - endpoints is the endpoint name that details Glusterfs topology. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + description: endpoints is the endpoint name that details Glusterfs topology. type: string path: description: |- @@ -11876,7 +12418,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: @@ -11901,7 +12443,7 @@ spec: description: |- iscsi represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. - More info: https://examples.k8s.io/volumes/iscsi/README.md + More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi properties: chapAuthDiscovery: description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication @@ -12291,6 +12833,110 @@ spec: type: array x-kubernetes-list-type: atomic type: object + podCertificate: + description: |- + Projects an auto-rotating credential bundle (private key and certificate + chain) that the pod can use either as a TLS client or server. + + Kubelet generates a private key and uses it to send a + PodCertificateRequest to the named signer. Once the signer approves the + request and issues a certificate chain, Kubelet writes the key and + certificate chain to the pod filesystem. The pod does not start until + certificates have been issued for each podCertificate projected volume + source in its spec. + + Kubelet will begin trying to rotate the certificate at the time indicated + by the signer using the PodCertificateRequest.Status.BeginRefreshAt + timestamp. + + Kubelet can write a single file, indicated by the credentialBundlePath + field, or separate files, indicated by the keyPath and + certificateChainPath fields. + + The credential bundle is a single file in PEM format. The first PEM + entry is the private key (in PKCS#8 format), and the remaining PEM + entries are the certificate chain issued by the signer (typically, + signers will return their certificate chain in leaf-to-root order). + + Prefer using the credential bundle format, since your application code + can read it atomically. If you use keyPath and certificateChainPath, + your application must make two separate file reads. If these coincide + with a certificate rotation, it is possible that the private key and leaf + certificate you read may not correspond to each other. Your application + will need to check for this condition, and re-read until they are + consistent. + + The named signer controls chooses the format of the certificate it + issues; consult the signer implementation's documentation to learn how to + use the certificates it issues. + properties: + certificateChainPath: + description: |- + Write the certificate chain at this path in the projected volume. + + Most applications should use credentialBundlePath. When using keyPath + and certificateChainPath, your application needs to check that the key + and leaf certificate are consistent, because it is possible to read the + files mid-rotation. + type: string + credentialBundlePath: + description: |- + Write the credential bundle at this path in the projected volume. + + The credential bundle is a single file that contains multiple PEM blocks. + The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private + key. + + The remaining blocks are CERTIFICATE blocks, containing the issued + certificate chain from the signer (leaf and any intermediates). + + Using credentialBundlePath lets your Pod's application code make a single + atomic read that retrieves a consistent key and certificate chain. If you + project them to separate files, your application code will need to + additionally check that the leaf certificate was issued to the key. + type: string + keyPath: + description: |- + Write the key at this path in the projected volume. + + Most applications should use credentialBundlePath. When using keyPath + and certificateChainPath, your application needs to check that the key + and leaf certificate are consistent, because it is possible to read the + files mid-rotation. + type: string + keyType: + description: |- + The type of keypair Kubelet will generate for the pod. + + Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384", + "ECDSAP521", and "ED25519". + type: string + maxExpirationSeconds: + description: |- + maxExpirationSeconds is the maximum lifetime permitted for the + certificate. + + Kubelet copies this value verbatim into the PodCertificateRequests it + generates for this projection. + + If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver + will reject values shorter than 3600 (1 hour). The maximum allowable + value is 7862400 (91 days). + + The signer implementation is then free to issue a certificate with any + lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600 + seconds (1 hour). This constraint is enforced by kube-apiserver. + `kubernetes.io` signers will never issue certificates with a lifetime + longer than 24 hours. + format: int32 + type: integer + signerName: + description: Kubelet's generated CSRs will be addressed to this signer. + type: string + required: + - keyType + - signerName + type: object secret: description: secret information about the secret data to project properties: @@ -12420,7 +13066,6 @@ spec: description: |- rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported. - More info: https://examples.k8s.io/volumes/rbd/README.md properties: fsType: description: |- @@ -12919,7 +13564,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: |- @@ -12930,7 +13574,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: |- @@ -12990,7 +13633,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -13046,14 +13689,14 @@ spec: default: cgroupfs: systemd preferredAddressTypes: - - Hostname - InternalIP - ExternalIP + - Hostname description: Configure the Kubelet options, such as the preferred address types, or the expected cgroupfs. properties: cgroupfs: description: |- - CGroupFS defines the cgroup driver for Kubelet + CGroupFS defines the cgroup driver for Kubelet https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/configure-cgroup-driver/ enum: - systemd @@ -13061,12 +13704,12 @@ spec: type: string preferredAddressTypes: default: - - Hostname - InternalIP - ExternalIP + - Hostname description: |- Ordered list of the preferred NodeAddressTypes to use for kubelet connections. - Default to Hostname, InternalIP, ExternalIP. + Default to InternalIP, ExternalIP, Hostname. items: enum: - Hostname @@ -13077,6 +13720,7 @@ spec: type: string minItems: 1 type: array + x-kubernetes-list-type: set type: object network: default: @@ -13270,7 +13914,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -13516,6 +14160,8 @@ rules: - metal3clusters verbs: - get + - list + - watch - apiGroups: - kamaji.clastix.io resources: @@ -13626,14 +14272,14 @@ spec: - --dynamic-infrastructure-clusters=${CACPPK_INFRASTRUCTURE_CLUSTERS:= } command: - /manager - image: docker.io/clastix/cluster-api-control-plane-provider-kamaji:v0.15.0 + image: docker.io/clastix/cluster-api-control-plane-provider-kamaji:v0.16.0 livenessProbe: httpGet: path: /healthz port: 8081 initialDelaySeconds: 15 periodSeconds: 20 - name: manager + name: controller readinessProbe: httpGet: path: /readyz diff --git a/packages/system/capi-providers-cpprovider/files/metadata.yaml b/packages/system/capi-providers-cpprovider/files/metadata.yaml index b282734a..d22c9ab0 100644 --- a/packages/system/capi-providers-cpprovider/files/metadata.yaml +++ b/packages/system/capi-providers-cpprovider/files/metadata.yaml @@ -5,6 +5,9 @@ # update this file only when a new major or minor version is released apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3 releaseSeries: + - major: 0 + minor: 16 + contract: v1beta1 - major: 0 minor: 15 contract: v1beta1 diff --git a/packages/system/capi-providers-cpprovider/templates/configmaps.yaml b/packages/system/capi-providers-cpprovider/templates/configmaps.yaml index d69ab12b..736c06a5 100644 --- a/packages/system/capi-providers-cpprovider/templates/configmaps.yaml +++ b/packages/system/capi-providers-cpprovider/templates/configmaps.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: ConfigMap metadata: - name: v0.15.1-cp + name: v0.16.0-cp labels: cp-components: cozy annotations: diff --git a/packages/system/capi-providers-cpprovider/templates/providers.yaml b/packages/system/capi-providers-cpprovider/templates/providers.yaml index b173be14..125a82c7 100644 --- a/packages/system/capi-providers-cpprovider/templates/providers.yaml +++ b/packages/system/capi-providers-cpprovider/templates/providers.yaml @@ -4,7 +4,7 @@ metadata: name: kamaji spec: # https://github.com/clastix/cluster-api-control-plane-provider-kamaji - version: v0.15.1-cp + version: v0.16.0-cp fetchConfig: selector: matchLabels: diff --git a/packages/system/capi-providers-infraprovider/Makefile b/packages/system/capi-providers-infraprovider/Makefile index 8e4423f3..042a4f0e 100644 --- a/packages/system/capi-providers-infraprovider/Makefile +++ b/packages/system/capi-providers-infraprovider/Makefile @@ -1,4 +1,4 @@ export NAME=capi-providers-infraprovider export NAMESPACE=cozy-cluster-api -include ../../../scripts/package.mk +include ../../../hack/package.mk diff --git a/packages/system/cert-manager-crds/Makefile b/packages/system/cert-manager-crds/Makefile index 0d665914..7e7370ac 100644 --- a/packages/system/cert-manager-crds/Makefile +++ b/packages/system/cert-manager-crds/Makefile @@ -1,8 +1,5 @@ -include ../../../scripts/package.mk +export NAME=cert-manager-crds +export NAMESPACE=cozy-cert-manager + +include ../../../hack/package.mk -update: - rm -rf charts - helm repo add jetstack https://charts.jetstack.io - helm repo update jetstack - helm pull jetstack/cert-manager --untar --untardir charts - rm -f -- `find charts/cert-manager/templates -maxdepth 1 -mindepth 1 | grep -v 'crds.yaml\|_helpers.tpl'` diff --git a/packages/system/cert-manager-crds/charts/cert-manager/Chart.yaml b/packages/system/cert-manager-crds/charts/cert-manager/Chart.yaml deleted file mode 100644 index 300db669..00000000 --- a/packages/system/cert-manager-crds/charts/cert-manager/Chart.yaml +++ /dev/null @@ -1,26 +0,0 @@ -annotations: - artifacthub.io/category: security - artifacthub.io/license: Apache-2.0 - artifacthub.io/prerelease: "false" - artifacthub.io/signKey: | - fingerprint: 1020CF3C033D4F35BAE1C19E1226061C665DF13E - url: https://cert-manager.io/public-keys/cert-manager-keyring-2021-09-20-1020CF3C033D4F35BAE1C19E1226061C665DF13E.gpg -apiVersion: v2 -appVersion: v1.16.3 -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 -keywords: -- cert-manager -- kube-lego -- letsencrypt -- tls -kubeVersion: '>= 1.22.0-0' -maintainers: -- email: cert-manager-maintainers@googlegroups.com - name: cert-manager-maintainers - url: https://cert-manager.io -name: cert-manager -sources: -- https://github.com/cert-manager/cert-manager -version: v1.16.3 diff --git a/packages/system/cert-manager-crds/charts/cert-manager/README.md b/packages/system/cert-manager-crds/charts/cert-manager/README.md deleted file mode 100644 index 6fa25cc9..00000000 --- a/packages/system/cert-manager-crds/charts/cert-manager/README.md +++ /dev/null @@ -1,1994 +0,0 @@ -# cert-manager - -cert-manager is a Kubernetes addon to automate the management and issuance of -TLS certificates from various issuing sources. - -It will ensure certificates are valid and up to date periodically, and attempt -to renew certificates at an appropriate time before expiry. - -## Prerequisites - -- Kubernetes 1.22+ - -## Installing the Chart - -Full installation instructions, including details on how to configure extra -functionality in cert-manager can be found in the [installation docs](https://cert-manager.io/docs/installation/kubernetes/). - -Before installing the chart, you must first install the cert-manager CustomResourceDefinition resources. -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 -``` - -To install the chart with the release name `cert-manager`: - -```console -## Add the Jetstack Helm repository -$ 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 -``` - -In order to begin issuing certificates, you will need to set up a ClusterIssuer -or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer). - -More information on the different types of issuers and how to configure them -can be found in [our documentation](https://cert-manager.io/docs/configuration/). - -For information on how to configure cert-manager to automatically provision -Certificates for Ingress resources, take a look at the -[Securing Ingresses documentation](https://cert-manager.io/docs/usage/ingress/). - -> **Tip**: List all releases using `helm list` - -## Upgrading the Chart - -Special considerations may be required when upgrading the Helm chart, and these -are documented in our full [upgrading guide](https://cert-manager.io/docs/installation/upgrading/). - -**Please check here before performing upgrades!** - -## Uninstalling the Chart - -To uninstall/delete the `cert-manager` deployment: - -```console -$ helm delete cert-manager --namespace cert-manager -``` - -The command removes all the Kubernetes components associated with the chart and deletes the release. - -If you want to completely uninstall cert-manager from your cluster, you will also need to -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 -``` - -## Configuration - - -### Global - -#### **global.imagePullSecrets** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Reference to one or more secrets to be used when pulling images. For more information, see [Pull an Image from a Private Registry](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/). - -For example: - -```yaml -imagePullSecrets: - - name: "image-pull-secret" -``` -#### **global.commonLabels** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Labels to apply to all resources. -Please note that this does not add labels to the resources created dynamically by the controllers. For these resources, you have to add the labels in the template in the cert-manager custom resource: For example, podTemplate/ ingressTemplate in ACMEChallengeSolverHTTP01Ingress. For more information, see the [cert-manager documentation](https://cert-manager.io/docs/reference/api-docs/#acme.cert-manager.io/v1.ACMEChallengeSolverHTTP01Ingress). -For example, secretTemplate in CertificateSpec -For more information, see the [cert-manager documentation](https://cert-manager.io/docs/reference/api-docs/#cert-manager.io/v1.CertificateSpec). -#### **global.revisionHistoryLimit** ~ `number` - -The number of old ReplicaSets to retain to allow rollback (if not set, the default Kubernetes value is set to 10). - -#### **global.priorityClassName** ~ `string` -> Default value: -> ```yaml -> "" -> ``` - -The optional priority class to be used for the cert-manager pods. -#### **global.rbac.create** ~ `bool` -> Default value: -> ```yaml -> true -> ``` - -Create required ClusterRoles and ClusterRoleBindings for cert-manager. -#### **global.rbac.aggregateClusterRoles** ~ `bool` -> Default value: -> ```yaml -> true -> ``` - -Aggregate ClusterRoles to Kubernetes default user-facing roles. For more information, see [User-facing roles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) -#### **global.podSecurityPolicy.enabled** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -Create PodSecurityPolicy for cert-manager. - -Note that PodSecurityPolicy was deprecated in Kubernetes 1.21 and removed in Kubernetes 1.25. -#### **global.podSecurityPolicy.useAppArmor** ~ `bool` -> Default value: -> ```yaml -> true -> ``` - -Configure the PodSecurityPolicy to use AppArmor. -#### **global.logLevel** ~ `number` -> Default value: -> ```yaml -> 2 -> ``` - -Set the verbosity of cert-manager. A range of 0 - 6, with 6 being the most verbose. -#### **global.leaderElection.namespace** ~ `string` -> Default value: -> ```yaml -> kube-system -> ``` - -Override the namespace used for the leader election lease. -#### **global.leaderElection.leaseDuration** ~ `string` - -The duration that non-leader candidates will wait after observing a leadership renewal until attempting to acquire leadership of a led but unrenewed leader slot. This is effectively the maximum duration that a leader can be stopped before it is replaced by another candidate. - -#### **global.leaderElection.renewDeadline** ~ `string` - -The interval between attempts by the acting master to renew a leadership slot before it stops leading. This must be less than or equal to the lease duration. - -#### **global.leaderElection.retryPeriod** ~ `string` - -The duration the clients should wait between attempting acquisition and renewal of a leadership. - -#### **installCRDs** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -This option is equivalent to setting crds.enabled=true and crds.keep=true. Deprecated: use crds.enabled and crds.keep instead. -#### **crds.enabled** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -This option decides if the CRDs should be installed as part of the Helm installation. -#### **crds.keep** ~ `bool` -> Default value: -> ```yaml -> true -> ``` - -This option makes it so that the "helm.sh/resource-policy": keep annotation is added to the CRD. This will prevent Helm from uninstalling the CRD when the Helm release is uninstalled. WARNING: when the CRDs are removed, all cert-manager custom resources -(Certificates, Issuers, ...) will be removed too by the garbage collector. -### Controller - -#### **replicaCount** ~ `number` -> Default value: -> ```yaml -> 1 -> ``` - -The number of replicas of the cert-manager controller to run. - -The default is 1, but in production set this to 2 or 3 to provide high availability. - -If `replicas > 1`, consider setting `podDisruptionBudget.enabled=true`. - -Note that cert-manager uses leader election to ensure that there can only be a single instance active at a time. -#### **strategy** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Deployment update strategy for the cert-manager controller deployment. For more information, see the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy). - -For example: - -```yaml -strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 0 - maxUnavailable: 1 -``` -#### **podDisruptionBudget.enabled** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -Enable or disable the PodDisruptionBudget resource. - -This prevents downtime during voluntary disruptions such as during a Node upgrade. For example, the PodDisruptionBudget will block `kubectl drain` if it is used on the Node where the only remaining cert-manager -Pod is currently running. -#### **podDisruptionBudget.minAvailable** ~ `unknown` - -This configures the minimum available pods for disruptions. It can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%). -It cannot be used if `maxUnavailable` is set. - - -#### **podDisruptionBudget.maxUnavailable** ~ `unknown` - -This configures the maximum unavailable pods for disruptions. It can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%). it cannot be used if `minAvailable` is set. - - -#### **featureGates** ~ `string` -> Default value: -> ```yaml -> "" -> ``` - -A comma-separated list of feature gates that should be enabled on the controller pod. -#### **maxConcurrentChallenges** ~ `number` -> Default value: -> ```yaml -> 60 -> ``` - -The maximum number of challenges that can be scheduled as 'processing' at once. -#### **image.registry** ~ `string` - -The container registry to pull the manager image from. - -#### **image.repository** ~ `string` -> Default value: -> ```yaml -> quay.io/jetstack/cert-manager-controller -> ``` - -The container image for the cert-manager controller. - -#### **image.tag** ~ `string` - -Override the image tag to deploy by setting this variable. If no value is set, the chart's appVersion is used. - -#### **image.digest** ~ `string` - -Setting a digest will override any tag. - -#### **image.pullPolicy** ~ `string` -> Default value: -> ```yaml -> IfNotPresent -> ``` - -Kubernetes imagePullPolicy on Deployment. -#### **clusterResourceNamespace** ~ `string` -> Default value: -> ```yaml -> "" -> ``` - -Override the namespace used to store DNS provider credentials etc. for ClusterIssuer resources. By default, the same namespace as cert-manager is deployed within is used. This namespace will not be automatically created by the Helm chart. -#### **namespace** ~ `string` -> Default value: -> ```yaml -> "" -> ``` - -This namespace allows you to define where the services are installed into. If not set then they use the namespace of the release. This is helpful when installing cert manager as a chart dependency (sub chart). -#### **fullnameOverride** ~ `string` - -Override the "cert-manager.fullname" value. This value is used as part of most of the names of the resources created by this Helm chart. - -#### **nameOverride** ~ `string` - -Override the "cert-manager.name" value, which is used to annotate some of the resources that are created by this Chart (using "app.kubernetes.io/name"). NOTE: There are some inconsistencies in the Helm chart when it comes to these annotations (some resources use eg. "cainjector.name" which resolves to the value "cainjector"). - -#### **serviceAccount.create** ~ `bool` -> Default value: -> ```yaml -> true -> ``` - -Specifies whether a service account should be created. -#### **serviceAccount.name** ~ `string` - -The name of the service account to use. -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. - -#### **serviceAccount.labels** ~ `object` - -Optional additional labels to add to the controller's Service Account. - -#### **serviceAccount.automountServiceAccountToken** ~ `bool` -> Default value: -> ```yaml -> true -> ``` - -Automount API credentials for a Service Account. -#### **automountServiceAccountToken** ~ `bool` - -Automounting API credentials for a particular pod. - -#### **enableCertificateOwnerRef** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -When this flag is enabled, secrets will be automatically removed when the certificate resource is deleted. -#### **config** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -This property is used to configure options for the controller pod. This allows setting options that would usually be provided using flags. - -If `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. - -For example: - -```yaml -config: - apiVersion: controller.config.cert-manager.io/v1alpha1 - kind: ControllerConfiguration - logging: - verbosity: 2 - format: text - leaderElectionConfig: - namespace: kube-system - kubernetesAPIQPS: 9000 - kubernetesAPIBurst: 9000 - numberOfConcurrentWorkers: 200 - featureGates: - AdditionalCertificateOutputFormats: true - DisallowInsecureCSRUsageDefinition: true - ExperimentalCertificateSigningRequestControllers: true - ExperimentalGatewayAPISupport: true - LiteralCertificateSubject: true - SecretsFilteredCaching: true - ServerSideApply: true - StableCertificateRequestName: true - UseCertificateRequestBasicConstraints: true - ValidateCAA: true - # Configure the metrics server for TLS - # See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls - metricsTLSConfig: - dynamic: - secretNamespace: "cert-manager" - secretName: "cert-manager-metrics-ca" - dnsNames: - - cert-manager-metrics -``` -#### **dns01RecursiveNameservers** ~ `string` -> Default value: -> ```yaml -> "" -> ``` - -A comma-separated string with the host and port of the recursive nameservers cert-manager should query. -#### **dns01RecursiveNameserversOnly** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -Forces cert-manager to use only the recursive nameservers for verification. Enabling this option could cause the DNS01 self check to take longer owing to caching performed by the recursive nameservers. -#### **disableAutoApproval** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -Option to disable cert-manager's build-in auto-approver. The auto-approver approves all CertificateRequests that reference issuers matching the 'approveSignerNames' option. This 'disableAutoApproval' option is useful when you want to make all approval decisions using a different approver (like approver-policy - https://github.com/cert-manager/approver-policy). -#### **approveSignerNames** ~ `array` -> Default value: -> ```yaml -> - issuers.cert-manager.io/* -> - clusterissuers.cert-manager.io/* -> ``` - -List of signer names that cert-manager will approve by default. CertificateRequests referencing these signer names will be auto-approved by cert-manager. Defaults to just approving the cert-manager.io Issuer and ClusterIssuer issuers. When set to an empty array, ALL issuers will be auto-approved by cert-manager. To disable the auto-approval, because eg. you are using approver-policy, you can enable 'disableAutoApproval'. -ref: https://cert-manager.io/docs/concepts/certificaterequest/#approval - -#### **extraArgs** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Additional command line flags to pass to cert-manager controller binary. To see all available flags run `docker run quay.io/jetstack/cert-manager-controller: --help`. - -Use this flag to enable or disable arbitrary controllers. For example, to disable the CertificateRequests approver. - -For example: - -```yaml -extraArgs: - - --controllers=*,-certificaterequests-approver -``` -#### **extraEnv** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Additional environment variables to pass to cert-manager controller binary. -For example: - -```yaml -extraEnv: -- name: SOME_VAR - value: 'some value' -``` -#### **resources** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Resources to provide to the cert-manager controller pod. - -For example: - -```yaml -requests: - cpu: 10m - memory: 32Mi -``` - -For more information, see [Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). -#### **securityContext** ~ `object` -> Default value: -> ```yaml -> runAsNonRoot: true -> seccompProfile: -> type: RuntimeDefault -> ``` - -Pod Security Context. -For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). - -#### **containerSecurityContext** ~ `object` -> Default value: -> ```yaml -> allowPrivilegeEscalation: false -> capabilities: -> drop: -> - ALL -> readOnlyRootFilesystem: true -> ``` - -Container Security Context to be set on the controller component container. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). - -#### **volumes** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Additional volumes to add to the cert-manager controller pod. -#### **volumeMounts** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Additional volume mounts to add to the cert-manager controller container. -#### **deploymentAnnotations** ~ `object` - -Optional additional annotations to add to the controller Deployment. - -#### **podAnnotations** ~ `object` - -Optional additional annotations to add to the controller Pods. - -#### **podLabels** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Optional additional labels to add to the controller Pods. -#### **serviceAnnotations** ~ `object` - -Optional annotations to add to the controller Service. - -#### **serviceLabels** ~ `object` - -Optional additional labels to add to the controller Service. - -#### **serviceIPFamilyPolicy** ~ `string` - -Optionally set the IP family policy for the controller Service to configure dual-stack; see [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services). - -#### **serviceIPFamilies** ~ `array` - -Optionally set the IP families for the controller Service that should be supported, in the order in which they should be applied to ClusterIP. Can be IPv4 and/or IPv6. - -#### **podDnsPolicy** ~ `string` - -Pod DNS policy. -For more information, see [Pod's DNS Policy](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy). - -#### **podDnsConfig** ~ `object` - -Pod DNS configuration. The podDnsConfig field is optional and can work with any podDnsPolicy settings. However, when a Pod's dnsPolicy is set to "None", the dnsConfig field has to be specified. For more information, see [Pod's DNS Config](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config). - -#### **hostAliases** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Optional hostAliases for cert-manager-controller pods. May be useful when performing ACME DNS-01 self checks. -#### **nodeSelector** ~ `object` -> Default value: -> ```yaml -> kubernetes.io/os: linux -> ``` - -The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with matching labels. For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). - -This default ensures that Pods are only scheduled to Linux nodes. It prevents Pods being scheduled to Windows nodes in a mixed OS cluster. - -#### **ingressShim.defaultIssuerName** ~ `string` - -Optional default issuer to use for ingress resources. - -#### **ingressShim.defaultIssuerKind** ~ `string` - -Optional default issuer kind to use for ingress resources. - -#### **ingressShim.defaultIssuerGroup** ~ `string` - -Optional default issuer group to use for ingress resources. - -#### **http_proxy** ~ `string` - -Configures the HTTP_PROXY environment variable where a HTTP proxy is required. - -#### **https_proxy** ~ `string` - -Configures the HTTPS_PROXY environment variable where a HTTP proxy is required. - -#### **no_proxy** ~ `string` - -Configures the NO_PROXY environment variable where a HTTP proxy is required, but certain domains should be excluded. - -#### **affinity** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core). - -For example: - -```yaml -affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: foo.bar.com/role - operator: In - values: - - master -``` -#### **tolerations** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core). - -For example: - -```yaml -tolerations: -- key: foo.bar.com/role - operator: Equal - value: master - effect: NoSchedule -``` -#### **topologySpreadConstraints** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -A list of Kubernetes TopologySpreadConstraints, if required. For more information, see [Topology spread constraint v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#topologyspreadconstraint-v1-core - -For example: - -```yaml -topologySpreadConstraints: -- maxSkew: 2 - topologyKey: topology.kubernetes.io/zone - whenUnsatisfiable: ScheduleAnyway - labelSelector: - matchLabels: - app.kubernetes.io/instance: cert-manager - app.kubernetes.io/component: controller -``` -#### **livenessProbe** ~ `object` -> Default value: -> ```yaml -> enabled: true -> failureThreshold: 8 -> initialDelaySeconds: 10 -> periodSeconds: 10 -> successThreshold: 1 -> timeoutSeconds: 15 -> ``` - -LivenessProbe settings for the controller container of the controller Pod. - -This is enabled by default, in order to enable the clock-skew liveness probe that restarts the controller in case of a skew between the system clock and the monotonic clock. LivenessProbe durations and thresholds are based on those used for the Kubernetes controller-manager. For more information see the following on the -[Kubernetes GitHub repository](https://github.com/kubernetes/kubernetes/blob/806b30170c61a38fedd54cc9ede4cd6275a1ad3b/cmd/kubeadm/app/util/staticpod/utils.go#L241-L245) - -#### **enableServiceLinks** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -enableServiceLinks indicates whether information about services should be injected into the pod's environment variables, matching the syntax of Docker links. -### Prometheus - -#### **prometheus.enabled** ~ `bool` -> Default value: -> ```yaml -> true -> ``` - -Enable Prometheus monitoring for the cert-manager controller and webhook. If you use the Prometheus Operator, set prometheus.podmonitor.enabled or prometheus.servicemonitor.enabled, to create a PodMonitor or a -ServiceMonitor resource. -Otherwise, 'prometheus.io' annotations are added to the cert-manager and cert-manager-webhook Deployments. Note that you can not enable both PodMonitor and ServiceMonitor as they are mutually exclusive. Enabling both will result in an error. -#### **prometheus.servicemonitor.enabled** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -Create a ServiceMonitor to add cert-manager to Prometheus. -#### **prometheus.servicemonitor.namespace** ~ `string` - -The namespace that the service monitor should live in, defaults to the cert-manager namespace. - -#### **prometheus.servicemonitor.prometheusInstance** ~ `string` -> Default value: -> ```yaml -> default -> ``` - -Specifies the `prometheus` label on the created ServiceMonitor. This is used when different Prometheus instances have label selectors matching different ServiceMonitors. -#### **prometheus.servicemonitor.targetPort** ~ `number` -> Default value: -> ```yaml -> 9402 -> ``` - -The target port to set on the ServiceMonitor. This must match the port that the cert-manager controller is listening on for metrics. -#### **prometheus.servicemonitor.path** ~ `string` -> Default value: -> ```yaml -> /metrics -> ``` - -The path to scrape for metrics. -#### **prometheus.servicemonitor.interval** ~ `string` -> Default value: -> ```yaml -> 60s -> ``` - -The interval to scrape metrics. -#### **prometheus.servicemonitor.scrapeTimeout** ~ `string` -> Default value: -> ```yaml -> 30s -> ``` - -The timeout before a metrics scrape fails. -#### **prometheus.servicemonitor.labels** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Additional labels to add to the ServiceMonitor. -#### **prometheus.servicemonitor.annotations** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Additional annotations to add to the ServiceMonitor. -#### **prometheus.servicemonitor.honorLabels** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -Keep labels from scraped data, overriding server-side labels. -#### **prometheus.servicemonitor.endpointAdditionalProperties** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -EndpointAdditionalProperties allows setting additional properties on the endpoint such as relabelings, metricRelabelings etc. - -For example: - -```yaml -endpointAdditionalProperties: - relabelings: - - action: replace - sourceLabels: - - __meta_kubernetes_pod_node_name - targetLabel: instance -``` - - - -#### **prometheus.podmonitor.enabled** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -Create a PodMonitor to add cert-manager to Prometheus. -#### **prometheus.podmonitor.namespace** ~ `string` - -The namespace that the pod monitor should live in, defaults to the cert-manager namespace. - -#### **prometheus.podmonitor.prometheusInstance** ~ `string` -> Default value: -> ```yaml -> default -> ``` - -Specifies the `prometheus` label on the created PodMonitor. This is used when different Prometheus instances have label selectors matching different PodMonitors. -#### **prometheus.podmonitor.path** ~ `string` -> Default value: -> ```yaml -> /metrics -> ``` - -The path to scrape for metrics. -#### **prometheus.podmonitor.interval** ~ `string` -> Default value: -> ```yaml -> 60s -> ``` - -The interval to scrape metrics. -#### **prometheus.podmonitor.scrapeTimeout** ~ `string` -> Default value: -> ```yaml -> 30s -> ``` - -The timeout before a metrics scrape fails. -#### **prometheus.podmonitor.labels** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Additional labels to add to the PodMonitor. -#### **prometheus.podmonitor.annotations** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Additional annotations to add to the PodMonitor. -#### **prometheus.podmonitor.honorLabels** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -Keep labels from scraped data, overriding server-side labels. -#### **prometheus.podmonitor.endpointAdditionalProperties** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -EndpointAdditionalProperties allows setting additional properties on the endpoint such as relabelings, metricRelabelings etc. - -For example: - -```yaml -endpointAdditionalProperties: - relabelings: - - action: replace - sourceLabels: - - __meta_kubernetes_pod_node_name - targetLabel: instance - # Configure the PodMonitor for TLS connections - # See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls - scheme: https - tlsConfig: - serverName: cert-manager-metrics - ca: - secret: - name: cert-manager-metrics-ca - key: "tls.crt" -``` - - - -### Webhook - -#### **webhook.replicaCount** ~ `number` -> Default value: -> ```yaml -> 1 -> ``` - -Number of replicas of the cert-manager webhook to run. - -The default is 1, but in production set this to 2 or 3 to provide high availability. - -If `replicas > 1`, consider setting `webhook.podDisruptionBudget.enabled=true`. -#### **webhook.timeoutSeconds** ~ `number` -> Default value: -> ```yaml -> 30 -> ``` - -The number of seconds the API server should wait for the webhook to respond before treating the call as a failure. The value must be between 1 and 30 seconds. For more information, see -[Validating webhook configuration v1](https://kubernetes.io/docs/reference/kubernetes-api/extend-resources/validating-webhook-configuration-v1/). - -The default is set to the maximum value of 30 seconds as users sometimes report that the connection between the K8S API server and the cert-manager webhook server times out. If *this* timeout is reached, the error message will be "context deadline exceeded", which doesn't help the user diagnose what phase of the HTTPS connection timed out. For example, it could be during DNS resolution, TCP connection, TLS negotiation, HTTP negotiation, or slow HTTP response from the webhook server. By setting this timeout to its maximum value the underlying timeout error message has more chance of being returned to the end user. -#### **webhook.config** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -This is used to configure options for the webhook pod. This allows setting options that would usually be provided using flags. - -If `apiVersion` and `kind` are unspecified they default to the current latest version (currently `webhook.config.cert-manager.io/v1alpha1`). You can pin the version by specifying the `apiVersion` yourself. - -For example: - -```yaml -apiVersion: webhook.config.cert-manager.io/v1alpha1 -kind: WebhookConfiguration -# The port that the webhook listens on for requests. -# In GKE private clusters, by default Kubernetes apiservers are allowed to -# talk to the cluster nodes only on 443 and 10250. Configuring -# securePort: 10250 therefore will work out-of-the-box without needing to add firewall -# rules or requiring NET_BIND_SERVICE capabilities to bind port numbers < 1000. -# This should be uncommented and set as a default by the chart once -# the apiVersion of WebhookConfiguration graduates beyond v1alpha1. -securePort: 10250 -# Configure the metrics server for TLS -# See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls -metricsTLSConfig: - dynamic: - secretNamespace: "cert-manager" - secretName: "cert-manager-metrics-ca" - dnsNames: - - cert-manager-metrics -``` -#### **webhook.strategy** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -The update strategy for the cert-manager webhook deployment. For more information, see the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy) - -For example: - -```yaml -strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 0 - maxUnavailable: 1 -``` -#### **webhook.securityContext** ~ `object` -> Default value: -> ```yaml -> runAsNonRoot: true -> seccompProfile: -> type: RuntimeDefault -> ``` - -Pod Security Context to be set on the webhook component Pod. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). - -#### **webhook.containerSecurityContext** ~ `object` -> Default value: -> ```yaml -> allowPrivilegeEscalation: false -> capabilities: -> drop: -> - ALL -> readOnlyRootFilesystem: true -> ``` - -Container Security Context to be set on the webhook component container. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). - -#### **webhook.podDisruptionBudget.enabled** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -Enable or disable the PodDisruptionBudget resource. - -This prevents downtime during voluntary disruptions such as during a Node upgrade. For example, the PodDisruptionBudget will block `kubectl drain` if it is used on the Node where the only remaining cert-manager -Pod is currently running. -#### **webhook.podDisruptionBudget.minAvailable** ~ `unknown` - -This property configures the minimum available pods for disruptions. Can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%). -It cannot be used if `maxUnavailable` is set. - - -#### **webhook.podDisruptionBudget.maxUnavailable** ~ `unknown` - -This property configures the maximum unavailable pods for disruptions. Can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%). -It cannot be used if `minAvailable` is set. - - -#### **webhook.deploymentAnnotations** ~ `object` - -Optional additional annotations to add to the webhook Deployment. - -#### **webhook.podAnnotations** ~ `object` - -Optional additional annotations to add to the webhook Pods. - -#### **webhook.serviceAnnotations** ~ `object` - -Optional additional annotations to add to the webhook Service. - -#### **webhook.mutatingWebhookConfigurationAnnotations** ~ `object` - -Optional additional annotations to add to the webhook MutatingWebhookConfiguration. - -#### **webhook.validatingWebhookConfigurationAnnotations** ~ `object` - -Optional additional annotations to add to the webhook ValidatingWebhookConfiguration. - -#### **webhook.validatingWebhookConfiguration.namespaceSelector** ~ `object` -> Default value: -> ```yaml -> matchExpressions: -> - key: cert-manager.io/disable-validation -> operator: NotIn -> values: -> - "true" -> ``` - -Configure spec.namespaceSelector for validating webhooks. - -#### **webhook.mutatingWebhookConfiguration.namespaceSelector** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Configure spec.namespaceSelector for mutating webhooks. - -#### **webhook.extraArgs** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Additional command line flags to pass to cert-manager webhook binary. To see all available flags run `docker run quay.io/jetstack/cert-manager-webhook: --help`. -#### **webhook.extraEnv** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Additional environment variables to pass to cert-manager webhook binary. -For example: - -```yaml -extraEnv: -- name: SOME_VAR - value: 'some value' -``` -#### **webhook.featureGates** ~ `string` -> Default value: -> ```yaml -> "" -> ``` - -Comma separated list of feature gates that should be enabled on the webhook pod. -#### **webhook.resources** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Resources to provide to the cert-manager webhook pod. - -For example: - -```yaml -requests: - cpu: 10m - memory: 32Mi -``` - -For more information, see [Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). -#### **webhook.livenessProbe** ~ `object` -> Default value: -> ```yaml -> failureThreshold: 3 -> initialDelaySeconds: 60 -> periodSeconds: 10 -> successThreshold: 1 -> timeoutSeconds: 1 -> ``` - -Liveness probe values. -For more information, see [Container probes](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes). - -#### **webhook.readinessProbe** ~ `object` -> Default value: -> ```yaml -> failureThreshold: 3 -> initialDelaySeconds: 5 -> periodSeconds: 5 -> successThreshold: 1 -> timeoutSeconds: 1 -> ``` - -Readiness probe values. -For more information, see [Container probes](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes). - -#### **webhook.nodeSelector** ~ `object` -> Default value: -> ```yaml -> kubernetes.io/os: linux -> ``` - -The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with matching labels. For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). - -This default ensures that Pods are only scheduled to Linux nodes. It prevents Pods being scheduled to Windows nodes in a mixed OS cluster. - -#### **webhook.affinity** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core). - -For example: - -```yaml -affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: foo.bar.com/role - operator: In - values: - - master -``` -#### **webhook.tolerations** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core). - -For example: - -```yaml -tolerations: -- key: foo.bar.com/role - operator: Equal - value: master - effect: NoSchedule -``` -#### **webhook.topologySpreadConstraints** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -A list of Kubernetes TopologySpreadConstraints, if required. For more information, see [Topology spread constraint v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#topologyspreadconstraint-v1-core). - -For example: - -```yaml -topologySpreadConstraints: -- maxSkew: 2 - topologyKey: topology.kubernetes.io/zone - whenUnsatisfiable: ScheduleAnyway - labelSelector: - matchLabels: - app.kubernetes.io/instance: cert-manager - app.kubernetes.io/component: controller -``` -#### **webhook.podLabels** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Optional additional labels to add to the Webhook Pods. -#### **webhook.serviceLabels** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Optional additional labels to add to the Webhook Service. -#### **webhook.serviceIPFamilyPolicy** ~ `string` -> Default value: -> ```yaml -> "" -> ``` - -Optionally set the IP family policy for the controller Service to configure dual-stack; see [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services). -#### **webhook.serviceIPFamilies** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Optionally set the IP families for the controller Service that should be supported, in the order in which they should be applied to ClusterIP. Can be IPv4 and/or IPv6. -#### **webhook.image.registry** ~ `string` - -The container registry to pull the webhook image from. - -#### **webhook.image.repository** ~ `string` -> Default value: -> ```yaml -> quay.io/jetstack/cert-manager-webhook -> ``` - -The container image for the cert-manager webhook - -#### **webhook.image.tag** ~ `string` - -Override the image tag to deploy by setting this variable. If no value is set, the chart's appVersion will be used. - -#### **webhook.image.digest** ~ `string` - -Setting a digest will override any tag - -#### **webhook.image.pullPolicy** ~ `string` -> Default value: -> ```yaml -> IfNotPresent -> ``` - -Kubernetes imagePullPolicy on Deployment. -#### **webhook.serviceAccount.create** ~ `bool` -> Default value: -> ```yaml -> true -> ``` - -Specifies whether a service account should be created. -#### **webhook.serviceAccount.name** ~ `string` - -The name of the service account to use. -If not set and create is true, a name is generated using the fullname template. - -#### **webhook.serviceAccount.annotations** ~ `object` - -Optional additional annotations to add to the webhook's Service Account. - -#### **webhook.serviceAccount.labels** ~ `object` - -Optional additional labels to add to the webhook's Service Account. - -#### **webhook.serviceAccount.automountServiceAccountToken** ~ `bool` -> Default value: -> ```yaml -> true -> ``` - -Automount API credentials for a Service Account. -#### **webhook.automountServiceAccountToken** ~ `bool` - -Automounting API credentials for a particular pod. - -#### **webhook.securePort** ~ `number` -> Default value: -> ```yaml -> 10250 -> ``` - -The port that the webhook listens on for requests. In GKE private clusters, by default Kubernetes apiservers are allowed to talk to the cluster nodes only on 443 and 10250. Configuring securePort: 10250, therefore will work out-of-the-box without needing to add firewall rules or requiring NET_BIND_SERVICE capabilities to bind port numbers <1000. -#### **webhook.hostNetwork** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -Specifies if the webhook should be started in hostNetwork mode. - -Required for use in some managed kubernetes clusters (such as AWS EKS) with custom. CNI (such as calico), because control-plane managed by AWS cannot communicate with pods' IP CIDR and admission webhooks are not working - -Since the default port for the webhook conflicts with kubelet on the host network, `webhook.securePort` should be changed to an available port if running in hostNetwork mode. -#### **webhook.serviceType** ~ `string` -> Default value: -> ```yaml -> ClusterIP -> ``` - -Specifies how the service should be handled. Useful if you want to expose the webhook outside of the cluster. In some cases, the control plane cannot reach internal services. -#### **webhook.loadBalancerIP** ~ `string` - -Specify the load balancer IP for the created service. - -#### **webhook.url** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Overrides the mutating webhook and validating webhook so they reach the webhook service using the `url` field instead of a service. -#### **webhook.networkPolicy.enabled** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -Create network policies for the webhooks. -#### **webhook.networkPolicy.ingress** ~ `array` -> Default value: -> ```yaml -> - from: -> - ipBlock: -> cidr: 0.0.0.0/0 -> ``` - -Ingress rule for the webhook network policy. By default, it allows all inbound traffic. - -#### **webhook.networkPolicy.egress** ~ `array` -> Default value: -> ```yaml -> - ports: -> - port: 80 -> protocol: TCP -> - port: 443 -> protocol: TCP -> - port: 53 -> protocol: TCP -> - port: 53 -> protocol: UDP -> - port: 6443 -> protocol: TCP -> to: -> - ipBlock: -> cidr: 0.0.0.0/0 -> ``` - -Egress rule for the webhook network policy. By default, it allows all outbound traffic to ports 80 and 443, as well as DNS ports. - -#### **webhook.volumes** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Additional volumes to add to the cert-manager controller pod. -#### **webhook.volumeMounts** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Additional volume mounts to add to the cert-manager controller container. -#### **webhook.enableServiceLinks** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -enableServiceLinks indicates whether information about services should be injected into the pod's environment variables, matching the syntax of Docker links. -### CA Injector - -#### **cainjector.enabled** ~ `bool` -> Default value: -> ```yaml -> true -> ``` - -Create the CA Injector deployment -#### **cainjector.replicaCount** ~ `number` -> Default value: -> ```yaml -> 1 -> ``` - -The number of replicas of the cert-manager cainjector to run. - -The default is 1, but in production set this to 2 or 3 to provide high availability. - -If `replicas > 1`, consider setting `cainjector.podDisruptionBudget.enabled=true`. - -Note that cert-manager uses leader election to ensure that there can only be a single instance active at a time. -#### **cainjector.config** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -This is used to configure options for the cainjector pod. It allows setting options that are usually provided via flags. - -If `apiVersion` and `kind` are unspecified they default to the current latest version (currently `cainjector.config.cert-manager.io/v1alpha1`). You can pin the version by specifying the `apiVersion` yourself. - -For example: - -```yaml -apiVersion: cainjector.config.cert-manager.io/v1alpha1 -kind: CAInjectorConfiguration -logging: - verbosity: 2 - format: text -leaderElectionConfig: - namespace: kube-system -# Configure the metrics server for TLS -# See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls -metricsTLSConfig: - dynamic: - secretNamespace: "cert-manager" - secretName: "cert-manager-metrics-ca" - dnsNames: - - cert-manager-metrics -``` -#### **cainjector.strategy** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Deployment update strategy for the cert-manager cainjector deployment. For more information, see the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy). - -For example: - -```yaml -strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 0 - maxUnavailable: 1 -``` -#### **cainjector.securityContext** ~ `object` -> Default value: -> ```yaml -> runAsNonRoot: true -> seccompProfile: -> type: RuntimeDefault -> ``` - -Pod Security Context to be set on the cainjector component Pod. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). - -#### **cainjector.containerSecurityContext** ~ `object` -> Default value: -> ```yaml -> allowPrivilegeEscalation: false -> capabilities: -> drop: -> - ALL -> readOnlyRootFilesystem: true -> ``` - -Container Security Context to be set on the cainjector component container. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). - -#### **cainjector.podDisruptionBudget.enabled** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -Enable or disable the PodDisruptionBudget resource. - -This prevents downtime during voluntary disruptions such as during a Node upgrade. For example, the PodDisruptionBudget will block `kubectl drain` if it is used on the Node where the only remaining cert-manager -Pod is currently running. -#### **cainjector.podDisruptionBudget.minAvailable** ~ `unknown` - -`minAvailable` configures the minimum available pods for disruptions. It can either be set to -an integer (e.g. 1) or a percentage value (e.g. 25%). -Cannot be used if `maxUnavailable` is set. - - -#### **cainjector.podDisruptionBudget.maxUnavailable** ~ `unknown` - -`maxUnavailable` configures the maximum unavailable pods for disruptions. It can either be set to -an integer (e.g. 1) or a percentage value (e.g. 25%). -Cannot be used if `minAvailable` is set. - - -#### **cainjector.deploymentAnnotations** ~ `object` - -Optional additional annotations to add to the cainjector Deployment. - -#### **cainjector.podAnnotations** ~ `object` - -Optional additional annotations to add to the cainjector Pods. - -#### **cainjector.serviceAnnotations** ~ `object` - -Optional additional annotations to add to the cainjector metrics Service. - -#### **cainjector.extraArgs** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Additional command line flags to pass to cert-manager cainjector binary. To see all available flags run `docker run quay.io/jetstack/cert-manager-cainjector: --help`. -#### **cainjector.extraEnv** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Additional environment variables to pass to cert-manager cainjector binary. -For example: - -```yaml -extraEnv: -- name: SOME_VAR - value: 'some value' -``` -#### **cainjector.featureGates** ~ `string` -> Default value: -> ```yaml -> "" -> ``` - -Comma separated list of feature gates that should be enabled on the cainjector pod. -#### **cainjector.resources** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Resources to provide to the cert-manager cainjector pod. - -For example: - -```yaml -requests: - cpu: 10m - memory: 32Mi -``` - -For more information, see [Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). -#### **cainjector.nodeSelector** ~ `object` -> Default value: -> ```yaml -> kubernetes.io/os: linux -> ``` - -The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with matching labels. For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). - -This default ensures that Pods are only scheduled to Linux nodes. It prevents Pods being scheduled to Windows nodes in a mixed OS cluster. - -#### **cainjector.affinity** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core). - -For example: - -```yaml -affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: foo.bar.com/role - operator: In - values: - - master -``` -#### **cainjector.tolerations** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core). - -For example: - -```yaml -tolerations: -- key: foo.bar.com/role - operator: Equal - value: master - effect: NoSchedule -``` -#### **cainjector.topologySpreadConstraints** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -A list of Kubernetes TopologySpreadConstraints, if required. For more information, see [Topology spread constraint v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#topologyspreadconstraint-v1-core). - -For example: - -```yaml -topologySpreadConstraints: -- maxSkew: 2 - topologyKey: topology.kubernetes.io/zone - whenUnsatisfiable: ScheduleAnyway - labelSelector: - matchLabels: - app.kubernetes.io/instance: cert-manager - app.kubernetes.io/component: controller -``` -#### **cainjector.podLabels** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Optional additional labels to add to the CA Injector Pods. -#### **cainjector.serviceLabels** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Optional additional labels to add to the CA Injector metrics Service. -#### **cainjector.image.registry** ~ `string` - -The container registry to pull the cainjector image from. - -#### **cainjector.image.repository** ~ `string` -> Default value: -> ```yaml -> quay.io/jetstack/cert-manager-cainjector -> ``` - -The container image for the cert-manager cainjector - -#### **cainjector.image.tag** ~ `string` - -Override the image tag to deploy by setting this variable. If no value is set, the chart's appVersion will be used. - -#### **cainjector.image.digest** ~ `string` - -Setting a digest will override any tag. - -#### **cainjector.image.pullPolicy** ~ `string` -> Default value: -> ```yaml -> IfNotPresent -> ``` - -Kubernetes imagePullPolicy on Deployment. -#### **cainjector.serviceAccount.create** ~ `bool` -> Default value: -> ```yaml -> true -> ``` - -Specifies whether a service account should be created. -#### **cainjector.serviceAccount.name** ~ `string` - -The name of the service account to use. -If not set and create is true, a name is generated using the fullname template - -#### **cainjector.serviceAccount.annotations** ~ `object` - -Optional additional annotations to add to the cainjector's Service Account. - -#### **cainjector.serviceAccount.labels** ~ `object` - -Optional additional labels to add to the cainjector's Service Account. - -#### **cainjector.serviceAccount.automountServiceAccountToken** ~ `bool` -> Default value: -> ```yaml -> true -> ``` - -Automount API credentials for a Service Account. -#### **cainjector.automountServiceAccountToken** ~ `bool` - -Automounting API credentials for a particular pod. - -#### **cainjector.volumes** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Additional volumes to add to the cert-manager controller pod. -#### **cainjector.volumeMounts** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Additional volume mounts to add to the cert-manager controller container. -#### **cainjector.enableServiceLinks** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -enableServiceLinks indicates whether information about services should be injected into the pod's environment variables, matching the syntax of Docker links. -### ACME Solver - -#### **acmesolver.image.registry** ~ `string` - -The container registry to pull the acmesolver image from. - -#### **acmesolver.image.repository** ~ `string` -> Default value: -> ```yaml -> quay.io/jetstack/cert-manager-acmesolver -> ``` - -The container image for the cert-manager acmesolver. - -#### **acmesolver.image.tag** ~ `string` - -Override the image tag to deploy by setting this variable. If no value is set, the chart's appVersion is used. - -#### **acmesolver.image.digest** ~ `string` - -Setting a digest will override any tag. - -#### **acmesolver.image.pullPolicy** ~ `string` -> Default value: -> ```yaml -> IfNotPresent -> ``` - -Kubernetes imagePullPolicy on Deployment. -### Startup API Check - - -This startupapicheck is a Helm post-install hook that waits for the webhook endpoints to become available. The check is implemented using a Kubernetes Job - if you are injecting mesh sidecar proxies into cert-manager pods, ensure that they are not injected into this Job's pod. Otherwise, the installation may time out owing to the Job never being completed because the sidecar proxy does not exit. For more information, see [this note](https://github.com/cert-manager/cert-manager/pull/4414). -#### **startupapicheck.enabled** ~ `bool` -> Default value: -> ```yaml -> true -> ``` - -Enables the startup api check. -#### **startupapicheck.securityContext** ~ `object` -> Default value: -> ```yaml -> runAsNonRoot: true -> seccompProfile: -> type: RuntimeDefault -> ``` - -Pod Security Context to be set on the startupapicheck component Pod. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). - -#### **startupapicheck.containerSecurityContext** ~ `object` -> Default value: -> ```yaml -> allowPrivilegeEscalation: false -> capabilities: -> drop: -> - ALL -> readOnlyRootFilesystem: true -> ``` - -Container Security Context to be set on the controller component container. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). - -#### **startupapicheck.timeout** ~ `string` -> Default value: -> ```yaml -> 1m -> ``` - -Timeout for 'kubectl check api' command. -#### **startupapicheck.backoffLimit** ~ `number` -> Default value: -> ```yaml -> 4 -> ``` - -Job backoffLimit -#### **startupapicheck.jobAnnotations** ~ `object` -> Default value: -> ```yaml -> helm.sh/hook: post-install -> helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded -> helm.sh/hook-weight: "1" -> ``` - -Optional additional annotations to add to the startupapicheck Job. - -#### **startupapicheck.podAnnotations** ~ `object` - -Optional additional annotations to add to the startupapicheck Pods. - -#### **startupapicheck.extraArgs** ~ `array` -> Default value: -> ```yaml -> - -v -> ``` - -Additional command line flags to pass to startupapicheck binary. To see all available flags run `docker run quay.io/jetstack/cert-manager-startupapicheck: --help`. - -Verbose logging is enabled by default so that if startupapicheck fails, you can know what exactly caused the failure. Verbose logs include details of the webhook URL, IP address and TCP connect errors for example. - -#### **startupapicheck.extraEnv** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Additional environment variables to pass to cert-manager startupapicheck binary. -For example: - -```yaml -extraEnv: -- name: SOME_VAR - value: 'some value' -``` -#### **startupapicheck.resources** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Resources to provide to the cert-manager controller pod. - -For example: - -```yaml -requests: - cpu: 10m - memory: 32Mi -``` - -For more information, see [Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). -#### **startupapicheck.nodeSelector** ~ `object` -> Default value: -> ```yaml -> kubernetes.io/os: linux -> ``` - -The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with matching labels. For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). - -This default ensures that Pods are only scheduled to Linux nodes. It prevents Pods being scheduled to Windows nodes in a mixed OS cluster. - -#### **startupapicheck.affinity** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core). -For example: - -```yaml -affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: foo.bar.com/role - operator: In - values: - - master -``` -#### **startupapicheck.tolerations** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core). - -For example: - -```yaml -tolerations: -- key: foo.bar.com/role - operator: Equal - value: master - effect: NoSchedule -``` -#### **startupapicheck.podLabels** ~ `object` -> Default value: -> ```yaml -> {} -> ``` - -Optional additional labels to add to the startupapicheck Pods. -#### **startupapicheck.image.registry** ~ `string` - -The container registry to pull the startupapicheck image from. - -#### **startupapicheck.image.repository** ~ `string` -> Default value: -> ```yaml -> quay.io/jetstack/cert-manager-startupapicheck -> ``` - -The container image for the cert-manager startupapicheck. - -#### **startupapicheck.image.tag** ~ `string` - -Override the image tag to deploy by setting this variable. If no value is set, the chart's appVersion is used. - -#### **startupapicheck.image.digest** ~ `string` - -Setting a digest will override any tag. - -#### **startupapicheck.image.pullPolicy** ~ `string` -> Default value: -> ```yaml -> IfNotPresent -> ``` - -Kubernetes imagePullPolicy on Deployment. -#### **startupapicheck.rbac.annotations** ~ `object` -> Default value: -> ```yaml -> helm.sh/hook: post-install -> helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded -> helm.sh/hook-weight: "-5" -> ``` - -annotations for the startup API Check job RBAC and PSP resources. - -#### **startupapicheck.automountServiceAccountToken** ~ `bool` - -Automounting API credentials for a particular pod. - -#### **startupapicheck.serviceAccount.create** ~ `bool` -> Default value: -> ```yaml -> true -> ``` - -Specifies whether a service account should be created. -#### **startupapicheck.serviceAccount.name** ~ `string` - -The name of the service account to use. -If not set and create is true, a name is generated using the fullname template. - -#### **startupapicheck.serviceAccount.annotations** ~ `object` -> Default value: -> ```yaml -> helm.sh/hook: post-install -> helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded -> helm.sh/hook-weight: "-5" -> ``` - -Optional additional annotations to add to the Job's Service Account. - -#### **startupapicheck.serviceAccount.automountServiceAccountToken** ~ `bool` -> Default value: -> ```yaml -> true -> ``` - -Automount API credentials for a Service Account. - -#### **startupapicheck.serviceAccount.labels** ~ `object` - -Optional additional labels to add to the startupapicheck's Service Account. - -#### **startupapicheck.volumes** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Additional volumes to add to the cert-manager controller pod. -#### **startupapicheck.volumeMounts** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Additional volume mounts to add to the cert-manager controller container. -#### **startupapicheck.enableServiceLinks** ~ `bool` -> Default value: -> ```yaml -> false -> ``` - -enableServiceLinks indicates whether information about services should be injected into pod's environment variables, matching the syntax of Docker links. -#### **extraObjects** ~ `array` -> Default value: -> ```yaml -> [] -> ``` - -Create dynamic manifests via values. - -For example: - -```yaml -extraObjects: - - | - apiVersion: v1 - kind: ConfigMap - metadata: - name: '{{ template "cert-manager.fullname" . }}-extra-configmap' -``` - - -### Default Security Contexts - -The default pod-level and container-level security contexts, below, adhere to the [restricted](https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted) Pod Security Standards policies. - -Default pod-level securityContext: -```yaml -runAsNonRoot: true -seccompProfile: - type: RuntimeDefault -``` - -Default containerSecurityContext: -```yaml -allowPrivilegeEscalation: false -capabilities: - drop: - - ALL -``` - -### Assigning Values - -Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. - -Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, - -```console -$ helm install my-release -f values.yaml . -``` -> **Tip**: You can use the default [values.yaml](https://github.com/cert-manager/cert-manager/blob/master/deploy/charts/cert-manager/values.yaml) - -## Contributing - -This chart is maintained at [github.com/cert-manager/cert-manager](https://github.com/cert-manager/cert-manager/tree/master/deploy/charts/cert-manager). diff --git a/packages/system/cert-manager-crds/charts/cert-manager/templates/crds.yaml b/packages/system/cert-manager-crds/charts/cert-manager/templates/crds.yaml deleted file mode 100644 index 00930f9c..00000000 --- a/packages/system/cert-manager-crds/charts/cert-manager/templates/crds.yaml +++ /dev/null @@ -1,12013 +0,0 @@ -# {{- include "cert-manager.crd-check" . }} -# START crd {{- if or .Values.crds.enabled .Values.installCRDs }} -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: certificaterequests.cert-manager.io - # START annotations {{- if .Values.crds.keep }} - annotations: - helm.sh/resource-policy: keep - # END annotations {{- end }} - labels: - app: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/name: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/instance: '{{ .Release.Name }}' - # Generated labels {{- include "labels" . | nindent 4 }} -spec: - group: cert-manager.io - names: - kind: CertificateRequest - listKind: CertificateRequestList - plural: certificaterequests - shortNames: - - cr - - crs - singular: certificaterequest - categories: - - cert-manager - scope: Namespaced - versions: - - name: v1 - subresources: - status: {} - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Approved")].status - name: Approved - type: string - - jsonPath: .status.conditions[?(@.type=="Denied")].status - name: Denied - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .spec.issuerRef.name - name: Issuer - type: string - - jsonPath: .spec.username - name: Requester - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: |- - A CertificateRequest is used to request a signed certificate from one of the - configured issuers. - - All fields within the CertificateRequest's `spec` are immutable after creation. - A CertificateRequest will either succeed or fail, as denoted by its `Ready` status - condition and its `status.failureTime` field. - - A CertificateRequest is a one-shot resource, meaning it represents a single - point in time request for a certificate and cannot be re-used. - type: object - 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: |- - Specification of the desired state of the CertificateRequest resource. - https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - type: object - required: - - issuerRef - - request - properties: - duration: - description: |- - Requested 'duration' (i.e. lifetime) of the Certificate. Note that the - issuer may choose to ignore the requested duration, just like any other - requested attribute. - type: string - extra: - description: |- - Extra contains extra attributes of the user that created the CertificateRequest. - Populated by the cert-manager webhook on creation and immutable. - type: object - additionalProperties: - type: array - items: - type: string - groups: - description: |- - Groups contains group membership of the user that created the CertificateRequest. - Populated by the cert-manager webhook on creation and immutable. - type: array - items: - type: string - x-kubernetes-list-type: atomic - isCA: - description: |- - Requested basic constraints isCA value. Note that the issuer may choose - to ignore the requested isCA value, just like any other requested attribute. - - NOTE: If the CSR in the `Request` field has a BasicConstraints extension, - it must have the same isCA value as specified here. - - If true, this will automatically add the `cert sign` usage to the list - of requested `usages`. - type: boolean - issuerRef: - description: |- - Reference to the issuer responsible for issuing the certificate. - If the issuer is namespace-scoped, it must be in the same namespace - as the Certificate. If the issuer is cluster-scoped, it can be used - from any namespace. - - The `name` field of the reference must always be specified. - type: object - required: - - name - properties: - group: - description: Group of the resource being referred to. - type: string - kind: - description: Kind of the resource being referred to. - type: string - name: - description: Name of the resource being referred to. - type: string - request: - description: |- - The PEM-encoded X.509 certificate signing request to be submitted to the - issuer for signing. - - If the CSR has a BasicConstraints extension, its isCA attribute must - match the `isCA` value of this CertificateRequest. - If the CSR has a KeyUsage extension, its key usages must match the - key usages in the `usages` field of this CertificateRequest. - If the CSR has a ExtKeyUsage extension, its extended key usages - must match the extended key usages in the `usages` field of this - CertificateRequest. - type: string - format: byte - uid: - description: |- - UID contains the uid of the user that created the CertificateRequest. - Populated by the cert-manager webhook on creation and immutable. - type: string - usages: - description: |- - Requested key usages and extended key usages. - - NOTE: If the CSR in the `Request` field has uses the KeyUsage or - ExtKeyUsage extension, these extensions must have the same values - as specified here without any additional values. - - If unset, defaults to `digital signature` and `key encipherment`. - type: array - items: - description: |- - KeyUsage specifies valid usage contexts for keys. - See: - https://tools.ietf.org/html/rfc5280#section-4.2.1.3 - https://tools.ietf.org/html/rfc5280#section-4.2.1.12 - - Valid KeyUsage values are as follows: - "signing", - "digital signature", - "content commitment", - "key encipherment", - "key agreement", - "data encipherment", - "cert sign", - "crl sign", - "encipher only", - "decipher only", - "any", - "server auth", - "client auth", - "code signing", - "email protection", - "s/mime", - "ipsec end system", - "ipsec tunnel", - "ipsec user", - "timestamping", - "ocsp signing", - "microsoft sgc", - "netscape sgc" - type: string - enum: - - signing - - digital signature - - content commitment - - key encipherment - - key agreement - - data encipherment - - cert sign - - crl sign - - encipher only - - decipher only - - any - - server auth - - client auth - - code signing - - email protection - - s/mime - - ipsec end system - - ipsec tunnel - - ipsec user - - timestamping - - ocsp signing - - microsoft sgc - - netscape sgc - username: - description: |- - Username contains the name of the user that created the CertificateRequest. - Populated by the cert-manager webhook on creation and immutable. - type: string - status: - description: |- - Status of the CertificateRequest. - This is set and managed automatically. - Read-only. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - type: object - properties: - ca: - description: |- - The PEM encoded X.509 certificate of the signer, also known as the CA - (Certificate Authority). - This is set on a best-effort basis by different issuers. - If not set, the CA is assumed to be unknown/not available. - type: string - format: byte - certificate: - description: |- - The PEM encoded X.509 certificate resulting from the certificate - signing request. - If not set, the CertificateRequest has either not been completed or has - failed. More information on failure can be found by checking the - `conditions` field. - type: string - format: byte - conditions: - description: |- - List of status conditions to indicate the status of a CertificateRequest. - Known condition types are `Ready`, `InvalidRequest`, `Approved` and `Denied`. - type: array - items: - description: CertificateRequestCondition contains condition information for a CertificateRequest. - type: object - required: - - status - - type - properties: - lastTransitionTime: - description: |- - LastTransitionTime is the timestamp corresponding to the last status - change of this condition. - type: string - format: date-time - message: - description: |- - Message is a human readable description of the details of the last - transition, complementing reason. - type: string - reason: - description: |- - Reason is a brief machine readable explanation for the condition's last - transition. - type: string - status: - description: Status of the condition, one of (`True`, `False`, `Unknown`). - type: string - enum: - - "True" - - "False" - - Unknown - type: - description: |- - Type of the condition, known values are (`Ready`, `InvalidRequest`, - `Approved`, `Denied`). - type: string - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - failureTime: - description: |- - FailureTime stores the time that this CertificateRequest failed. This is - used to influence garbage collection and back-off. - type: string - format: date-time - served: true - storage: true - -# END crd {{- end }} - ---- -# START crd {{- if or .Values.crds.enabled .Values.installCRDs }} -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: certificates.cert-manager.io - # START annotations {{- if .Values.crds.keep }} - annotations: - helm.sh/resource-policy: keep - # END annotations {{- end }} - labels: - app: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/name: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/instance: '{{ .Release.Name }}' - # Generated labels {{- include "labels" . | nindent 4 }} -spec: - group: cert-manager.io - names: - kind: Certificate - listKind: CertificateList - plural: certificates - shortNames: - - cert - - certs - singular: certificate - categories: - - cert-manager - scope: Namespaced - versions: - - name: v1 - subresources: - status: {} - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .spec.secretName - name: Secret - type: string - - jsonPath: .spec.issuerRef.name - name: Issuer - priority: 1 - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: |- - A Certificate resource should be created to ensure an up to date and signed - X.509 certificate is stored in the Kubernetes Secret resource named in `spec.secretName`. - - The stored certificate will be renewed before it expires (as configured by `spec.renewBefore`). - type: object - 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: |- - Specification of the desired state of the Certificate resource. - https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - type: object - required: - - issuerRef - - secretName - properties: - additionalOutputFormats: - description: |- - Defines extra output formats of the private key and signed certificate chain - to be written to this Certificate's target Secret. - - This is a Beta Feature enabled by default. It can be disabled with the - `--feature-gates=AdditionalCertificateOutputFormats=false` option set on both - the controller and webhook components. - type: array - items: - description: |- - CertificateAdditionalOutputFormat defines an additional output format of a - Certificate resource. These contain supplementary data formats of the signed - certificate chain and paired private key. - type: object - required: - - type - properties: - type: - description: |- - Type is the name of the format type that should be written to the - Certificate's target Secret. - type: string - enum: - - DER - - CombinedPEM - commonName: - description: |- - Requested common name X509 certificate subject attribute. - More info: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6 - NOTE: TLS clients will ignore this value when any subject alternative name is - set (see https://tools.ietf.org/html/rfc6125#section-6.4.4). - - Should have a length of 64 characters or fewer to avoid generating invalid CSRs. - Cannot be set if the `literalSubject` field is set. - type: string - dnsNames: - description: Requested DNS subject alternative names. - type: array - items: - type: string - duration: - description: |- - Requested 'duration' (i.e. lifetime) of the Certificate. Note that the - issuer may choose to ignore the requested duration, just like any other - requested attribute. - - If unset, this defaults to 90 days. - Minimum accepted duration is 1 hour. - Value must be in units accepted by Go time.ParseDuration https://golang.org/pkg/time/#ParseDuration. - type: string - emailAddresses: - description: Requested email subject alternative names. - type: array - items: - type: string - encodeUsagesInRequest: - description: |- - Whether the KeyUsage and ExtKeyUsage extensions should be set in the encoded CSR. - - This option defaults to true, and should only be disabled if the target - issuer does not support CSRs with these X509 KeyUsage/ ExtKeyUsage extensions. - type: boolean - ipAddresses: - description: Requested IP address subject alternative names. - type: array - items: - type: string - isCA: - description: |- - Requested basic constraints isCA value. - The isCA value is used to set the `isCA` field on the created CertificateRequest - resources. Note that the issuer may choose to ignore the requested isCA value, just - like any other requested attribute. - - If true, this will automatically add the `cert sign` usage to the list - of requested `usages`. - type: boolean - issuerRef: - description: |- - Reference to the issuer responsible for issuing the certificate. - If the issuer is namespace-scoped, it must be in the same namespace - as the Certificate. If the issuer is cluster-scoped, it can be used - from any namespace. - - The `name` field of the reference must always be specified. - type: object - required: - - name - properties: - group: - description: Group of the resource being referred to. - type: string - kind: - description: Kind of the resource being referred to. - type: string - name: - description: Name of the resource being referred to. - type: string - keystores: - description: Additional keystore output formats to be stored in the Certificate's Secret. - type: object - properties: - jks: - description: |- - JKS configures options for storing a JKS keystore in the - `spec.secretName` Secret resource. - type: object - required: - - create - - passwordSecretRef - properties: - alias: - description: |- - Alias specifies the alias of the key in the keystore, required by the JKS format. - If not provided, the default alias `certificate` will be used. - type: string - create: - description: |- - 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`. - 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 - passwordSecretRef: - description: |- - PasswordSecretRef is a reference to a key in a Secret resource - containing the password used to encrypt the JKS keystore. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - pkcs12: - description: |- - PKCS12 configures options for storing a PKCS12 keystore in the - `spec.secretName` Secret resource. - 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`. - 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 - passwordSecretRef: - description: |- - PasswordSecretRef is a reference to a key in a Secret resource - containing the password used to encrypt the PKCS12 keystore. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - profile: - description: |- - Profile specifies the key and certificate encryption algorithms and the HMAC algorithm - used to create the PKCS12 keystore. Default value is `LegacyRC2` for backward compatibility. - - If provided, allowed values are: - `LegacyRC2`: Deprecated. Not supported by default in OpenSSL 3 or Java 20. - `LegacyDES`: Less secure algorithm. Use this option for maximal compatibility. - `Modern2023`: Secure algorithm. Use this option in case you have to always use secure algorithms - (eg. because of company policy). Please note that the security of the algorithm is not that important - in reality, because the unencrypted certificate and private key are also stored in the Secret. - type: string - enum: - - LegacyRC2 - - LegacyDES - - Modern2023 - literalSubject: - description: |- - Requested X.509 certificate subject, represented using the LDAP "String - Representation of a Distinguished Name" [1]. - Important: the LDAP string format also specifies the order of the attributes - in the subject, this is important when issuing certs for LDAP authentication. - Example: `CN=foo,DC=corp,DC=example,DC=com` - More info [1]: https://datatracker.ietf.org/doc/html/rfc4514 - More info: https://github.com/cert-manager/cert-manager/issues/3203 - More info: https://github.com/cert-manager/cert-manager/issues/4424 - - Cannot be set if the `subject` or `commonName` field is set. - type: string - nameConstraints: - description: |- - x.509 certificate NameConstraint extension which MUST NOT be used in a non-CA certificate. - More Info: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10 - - This is an Alpha Feature and is only enabled with the - `--feature-gates=NameConstraints=true` option set on both - the controller and webhook components. - type: object - properties: - critical: - description: if true then the name constraints are marked critical. - type: boolean - excluded: - description: |- - Excluded contains the constraints which must be disallowed. Any name matching a - restriction in the excluded field is invalid regardless - of information appearing in the permitted - type: object - properties: - dnsDomains: - description: DNSDomains is a list of DNS domains that are permitted or excluded. - type: array - items: - type: string - emailAddresses: - description: EmailAddresses is a list of Email Addresses that are permitted or excluded. - type: array - items: - type: string - ipRanges: - description: |- - IPRanges is a list of IP Ranges that are permitted or excluded. - This should be a valid CIDR notation. - type: array - items: - type: string - uriDomains: - description: URIDomains is a list of URI domains that are permitted or excluded. - type: array - items: - type: string - permitted: - description: Permitted contains the constraints in which the names must be located. - type: object - properties: - dnsDomains: - description: DNSDomains is a list of DNS domains that are permitted or excluded. - type: array - items: - type: string - emailAddresses: - description: EmailAddresses is a list of Email Addresses that are permitted or excluded. - type: array - items: - type: string - ipRanges: - description: |- - IPRanges is a list of IP Ranges that are permitted or excluded. - This should be a valid CIDR notation. - type: array - items: - type: string - uriDomains: - description: URIDomains is a list of URI domains that are permitted or excluded. - type: array - items: - type: string - otherNames: - description: |- - `otherNames` is an escape hatch for SAN that allows any type. We currently restrict the support to string like otherNames, cf RFC 5280 p 37 - Any UTF8 String valued otherName can be passed with by setting the keys oid: x.x.x.x and UTF8Value: somevalue for `otherName`. - Most commonly this would be UPN set with oid: 1.3.6.1.4.1.311.20.2.3 - You should ensure that any OID passed is valid for the UTF8String type as we do not explicitly validate this. - type: array - items: - type: object - properties: - oid: - description: |- - OID is the object identifier for the otherName SAN. - The object identifier must be expressed as a dotted string, for - example, "1.2.840.113556.1.4.221". - type: string - utf8Value: - description: |- - utf8Value is the string value of the otherName SAN. - The utf8Value accepts any valid UTF8 string to set as value for the otherName SAN. - type: string - privateKey: - description: |- - Private key options. These include the key algorithm and size, the used - encoding and the rotation policy. - type: object - properties: - algorithm: - description: |- - Algorithm is the private key algorithm of the corresponding private key - for this certificate. - - If provided, allowed values are either `RSA`, `ECDSA` or `Ed25519`. - If `algorithm` is specified and `size` is not provided, - key size of 2048 will be used for `RSA` key algorithm and - key size of 256 will be used for `ECDSA` key algorithm. - key size is ignored when using the `Ed25519` key algorithm. - type: string - enum: - - RSA - - ECDSA - - Ed25519 - encoding: - description: |- - The private key cryptography standards (PKCS) encoding for this - certificate's private key to be encoded in. - - If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 - and PKCS#8, respectively. - Defaults to `PKCS1` if not specified. - type: string - enum: - - PKCS1 - - PKCS8 - rotationPolicy: - description: |- - RotationPolicy controls how private keys should be regenerated when a - re-issuance is being processed. - - If set to `Never`, a private key will only be generated if one does not - already exist in the target `spec.secretName`. If one does exist but it - does not have the correct algorithm or size, a warning will be raised - to await user intervention. - If set to `Always`, a private key matching the specified requirements - will be generated whenever a re-issuance occurs. - Default is `Never` for backward compatibility. - type: string - enum: - - Never - - Always - size: - description: |- - Size is the key bit size of the corresponding private key for this certificate. - - If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, - and will default to `2048` if not specified. - If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, - and will default to `256` if not specified. - If `algorithm` is set to `Ed25519`, Size is ignored. - No other values are allowed. - type: integer - renewBefore: - description: |- - How long before the currently issued certificate's expiry cert-manager should - renew the certificate. For example, if a certificate is valid for 60 minutes, - and `renewBefore=10m`, cert-manager will begin to attempt to renew the certificate - 50 minutes after it was issued (i.e. when there are 10 minutes remaining until - the certificate is no longer valid). - - NOTE: The actual lifetime of the issued certificate is used to determine the - renewal time. If an issuer returns a certificate with a different lifetime than - the one requested, cert-manager will use the lifetime of the issued certificate. - - If unset, this defaults to 1/3 of the issued certificate's lifetime. - Minimum accepted value is 5 minutes. - Value must be in units accepted by Go time.ParseDuration https://golang.org/pkg/time/#ParseDuration. - Cannot be set if the `renewBeforePercentage` field is set. - type: string - renewBeforePercentage: - description: |- - `renewBeforePercentage` is like `renewBefore`, except it is a relative percentage - rather than an absolute duration. For example, if a certificate is valid for 60 - minutes, and `renewBeforePercentage=25`, cert-manager will begin to attempt to - renew the certificate 45 minutes after it was issued (i.e. when there are 15 - minutes (25%) remaining until the certificate is no longer valid). - - NOTE: The actual lifetime of the issued certificate is used to determine the - renewal time. If an issuer returns a certificate with a different lifetime than - the one requested, cert-manager will use the lifetime of the issued certificate. - - Value must be an integer in the range (0,100). The minimum effective - `renewBefore` derived from the `renewBeforePercentage` and `duration` fields is 5 - minutes. - Cannot be set if the `renewBefore` field is set. - type: integer - format: int32 - revisionHistoryLimit: - description: |- - The maximum number of CertificateRequest revisions that are maintained in - the Certificate's history. Each revision represents a single `CertificateRequest` - created by this Certificate, either when it was created, renewed, or Spec - was changed. Revisions will be removed by oldest first if the number of - revisions exceeds this number. - - If set, revisionHistoryLimit must be a value of `1` or greater. - If unset (`nil`), revisions will not be garbage collected. - Default value is `nil`. - type: integer - format: int32 - secretName: - description: |- - Name of the Secret resource that will be automatically created and - managed by this Certificate resource. It will be populated with a - private key and certificate, signed by the denoted issuer. The Secret - resource lives in the same namespace as the Certificate resource. - type: string - secretTemplate: - description: |- - Defines annotations and labels to be copied to the Certificate's Secret. - Labels and annotations on the Secret will be changed as they appear on the - SecretTemplate when added or removed. SecretTemplate annotations are added - in conjunction with, and cannot overwrite, the base set of annotations - cert-manager sets on the Certificate's Secret. - type: object - properties: - annotations: - description: Annotations is a key value map to be copied to the target Kubernetes Secret. - type: object - additionalProperties: - type: string - labels: - description: Labels is a key value map to be copied to the target Kubernetes Secret. - type: object - additionalProperties: - type: string - subject: - description: |- - Requested set of X509 certificate subject attributes. - More info: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6 - - The common name attribute is specified separately in the `commonName` field. - Cannot be set if the `literalSubject` field is set. - type: object - properties: - countries: - description: Countries to be used on the Certificate. - type: array - items: - type: string - localities: - description: Cities to be used on the Certificate. - type: array - items: - type: string - organizationalUnits: - description: Organizational Units to be used on the Certificate. - type: array - items: - type: string - organizations: - description: Organizations to be used on the Certificate. - type: array - items: - type: string - postalCodes: - description: Postal codes to be used on the Certificate. - type: array - items: - type: string - provinces: - description: State/Provinces to be used on the Certificate. - type: array - items: - type: string - serialNumber: - description: Serial number to be used on the Certificate. - type: string - streetAddresses: - description: Street addresses to be used on the Certificate. - type: array - items: - type: string - uris: - description: Requested URI subject alternative names. - type: array - items: - type: string - usages: - description: |- - Requested key usages and extended key usages. - These usages are used to set the `usages` field on the created CertificateRequest - resources. If `encodeUsagesInRequest` is unset or set to `true`, the usages - will additionally be encoded in the `request` field which contains the CSR blob. - - If unset, defaults to `digital signature` and `key encipherment`. - type: array - items: - description: |- - KeyUsage specifies valid usage contexts for keys. - See: - https://tools.ietf.org/html/rfc5280#section-4.2.1.3 - https://tools.ietf.org/html/rfc5280#section-4.2.1.12 - - Valid KeyUsage values are as follows: - "signing", - "digital signature", - "content commitment", - "key encipherment", - "key agreement", - "data encipherment", - "cert sign", - "crl sign", - "encipher only", - "decipher only", - "any", - "server auth", - "client auth", - "code signing", - "email protection", - "s/mime", - "ipsec end system", - "ipsec tunnel", - "ipsec user", - "timestamping", - "ocsp signing", - "microsoft sgc", - "netscape sgc" - type: string - enum: - - signing - - digital signature - - content commitment - - key encipherment - - key agreement - - data encipherment - - cert sign - - crl sign - - encipher only - - decipher only - - any - - server auth - - client auth - - code signing - - email protection - - s/mime - - ipsec end system - - ipsec tunnel - - ipsec user - - timestamping - - ocsp signing - - microsoft sgc - - netscape sgc - status: - description: |- - Status of the Certificate. - This is set and managed automatically. - Read-only. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - type: object - properties: - conditions: - description: |- - List of status conditions to indicate the status of certificates. - Known condition types are `Ready` and `Issuing`. - type: array - items: - description: CertificateCondition contains condition information for a Certificate. - type: object - required: - - status - - type - properties: - lastTransitionTime: - description: |- - LastTransitionTime is the timestamp corresponding to the last status - change of this condition. - type: string - format: date-time - message: - description: |- - Message is a human readable description of the details of the last - transition, complementing reason. - type: string - observedGeneration: - description: |- - If set, this represents the .metadata.generation that the condition was - set based upon. - For instance, if .metadata.generation is currently 12, but the - .status.condition[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the Certificate. - type: integer - format: int64 - reason: - description: |- - Reason is a brief machine readable explanation for the condition's last - transition. - type: string - status: - description: Status of the condition, one of (`True`, `False`, `Unknown`). - type: string - enum: - - "True" - - "False" - - Unknown - type: - description: Type of the condition, known values are (`Ready`, `Issuing`). - type: string - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - failedIssuanceAttempts: - description: |- - The number of continuous failed issuance attempts up till now. This - field gets removed (if set) on a successful issuance and gets set to - 1 if unset and an issuance has failed. If an issuance has failed, the - delay till the next issuance will be calculated using formula - time.Hour * 2 ^ (failedIssuanceAttempts - 1). - type: integer - lastFailureTime: - description: |- - LastFailureTime is set only if the latest issuance for this - Certificate failed and contains the time of the failure. If an - issuance has failed, the delay till the next issuance will be - calculated using formula time.Hour * 2 ^ (failedIssuanceAttempts - - 1). If the latest issuance has succeeded this field will be unset. - type: string - format: date-time - nextPrivateKeySecretName: - description: |- - The name of the Secret resource containing the private key to be used - for the next certificate iteration. - The keymanager controller will automatically set this field if the - `Issuing` condition is set to `True`. - It will automatically unset this field when the Issuing condition is - not set or False. - type: string - notAfter: - description: |- - The expiration time of the certificate stored in the secret named - by this resource in `spec.secretName`. - type: string - format: date-time - notBefore: - description: |- - The time after which the certificate stored in the secret named - by this resource in `spec.secretName` is valid. - type: string - format: date-time - renewalTime: - description: |- - RenewalTime is the time at which the certificate will be next - renewed. - If not set, no upcoming renewal is scheduled. - type: string - format: date-time - revision: - description: |- - The current 'revision' of the certificate as issued. - - When a CertificateRequest resource is created, it will have the - `cert-manager.io/certificate-revision` set to one greater than the - current value of this field. - - Upon issuance, this field will be set to the value of the annotation - on the CertificateRequest resource used to issue the certificate. - - Persisting the value on the CertificateRequest resource allows the - certificates controller to know whether a request is part of an old - issuance or if it is part of the ongoing revision's issuance by - checking if the revision value in the annotation is greater than this - field. - type: integer - served: true - storage: true - -# END crd {{- end }} - ---- -# START crd {{- if or .Values.crds.enabled .Values.installCRDs }} -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: challenges.acme.cert-manager.io - # START annotations {{- if .Values.crds.keep }} - annotations: - helm.sh/resource-policy: keep - # END annotations {{- end }} - labels: - app: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/name: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/instance: '{{ .Release.Name }}' - # Generated labels {{- include "labels" . | nindent 4 }} -spec: - group: acme.cert-manager.io - names: - kind: Challenge - listKind: ChallengeList - plural: challenges - singular: challenge - categories: - - cert-manager - - cert-manager-acme - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.state - name: State - type: string - - jsonPath: .spec.dnsName - name: Domain - type: string - - jsonPath: .status.reason - name: Reason - priority: 1 - type: string - - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1 - schema: - openAPIV3Schema: - description: Challenge is a type to represent a Challenge request with an ACME server - type: object - required: - - metadata - - spec - 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: - type: object - required: - - authorizationURL - - dnsName - - issuerRef - - key - - solver - - token - - type - - url - properties: - authorizationURL: - description: |- - The URL to the ACME Authorization resource that this - challenge is a part of. - type: string - dnsName: - description: |- - dnsName is the identifier that this challenge is for, e.g. example.com. - If the requested DNSName is a 'wildcard', this field MUST be set to the - non-wildcard domain, e.g. for `*.example.com`, it must be `example.com`. - type: string - issuerRef: - description: |- - References a properly configured ACME-type Issuer which should - be used to create this Challenge. - If the Issuer does not exist, processing will be retried. - If the Issuer is not an 'ACME' Issuer, an error will be returned and the - Challenge will be marked as failed. - type: object - required: - - name - properties: - group: - description: Group of the resource being referred to. - type: string - kind: - description: Kind of the resource being referred to. - type: string - name: - description: Name of the resource being referred to. - type: string - key: - description: |- - The ACME challenge key for this challenge - For HTTP01 challenges, this is the value that must be responded with to - complete the HTTP01 challenge in the format: - `.`. - For DNS01 challenges, this is the base64 encoded SHA256 sum of the - `.` - text that must be set as the TXT record content. - type: string - solver: - description: |- - Contains the domain solving configuration that should be used to - solve this challenge resource. - type: object - properties: - dns01: - description: |- - Configures cert-manager to attempt to complete authorizations by - performing the DNS01 challenge flow. - type: object - properties: - acmeDNS: - description: |- - Use the 'ACME DNS' (https://github.com/joohoi/acme-dns) API to manage - DNS01 challenge records. - type: object - required: - - accountSecretRef - - host - properties: - accountSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - host: - type: string - akamai: - description: Use the Akamai DNS zone management API to manage DNS01 challenge records. - type: object - required: - - accessTokenSecretRef - - clientSecretSecretRef - - clientTokenSecretRef - - serviceConsumerDomain - properties: - accessTokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientSecretSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientTokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - serviceConsumerDomain: - type: string - azureDNS: - description: Use the Microsoft Azure DNS API to manage DNS01 challenge records. - type: object - required: - - resourceGroupName - - subscriptionID - properties: - clientID: - description: |- - Auth: Azure Service Principal: - The ClientID of the Azure Service Principal used to authenticate with Azure DNS. - If set, ClientSecret and TenantID must also be set. - type: string - clientSecretSecretRef: - description: |- - Auth: Azure Service Principal: - A reference to a Secret containing the password associated with the Service Principal. - If set, ClientID and TenantID must also be set. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - environment: - description: name of the Azure environment (default AzurePublicCloud) - type: string - enum: - - AzurePublicCloud - - AzureChinaCloud - - AzureGermanCloud - - AzureUSGovernmentCloud - hostedZoneName: - description: name of the DNS zone that should be used - type: string - managedIdentity: - description: |- - Auth: Azure Workload Identity or Azure Managed Service Identity: - Settings to enable Azure Workload Identity or Azure Managed Service Identity - If set, ClientID, ClientSecret and TenantID must not be set. - type: object - properties: - clientID: - description: client ID of the managed identity, can not be used at the same time as resourceID - type: string - resourceID: - description: |- - 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 - resourceGroupName: - description: resource group the DNS zone is located in - type: string - subscriptionID: - description: ID of the Azure subscription - type: string - tenantID: - description: |- - Auth: Azure Service Principal: - The TenantID of the Azure Service Principal used to authenticate with Azure DNS. - If set, ClientID and ClientSecret must also be set. - type: string - cloudDNS: - description: Use the Google Cloud DNS API to manage DNS01 challenge records. - type: object - required: - - project - properties: - hostedZoneName: - description: |- - HostedZoneName is an optional field that tells cert-manager in which - Cloud DNS zone the challenge record has to be created. - If left empty cert-manager will automatically choose a zone. - type: string - project: - type: string - serviceAccountSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - cloudflare: - description: Use the Cloudflare API to manage DNS01 challenge records. - type: object - properties: - apiKeySecretRef: - description: |- - API key to use to authenticate with Cloudflare. - Note: using an API token to authenticate is now the recommended method - as it allows greater control of permissions. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - apiTokenSecretRef: - description: API token used to authenticate with Cloudflare. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - email: - description: Email of the account, only required when using API key based authentication. - type: string - cnameStrategy: - description: |- - CNAMEStrategy configures how the DNS01 provider should handle CNAME - records when found in DNS zones. - type: string - enum: - - None - - Follow - digitalocean: - description: Use the DigitalOcean DNS API to manage DNS01 challenge records. - type: object - required: - - tokenSecretRef - properties: - tokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - rfc2136: - description: |- - Use RFC2136 ("Dynamic Updates in the Domain Name System") (https://datatracker.ietf.org/doc/rfc2136/) - to manage DNS01 challenge records. - type: object - required: - - nameserver - properties: - nameserver: - description: |- - The IP address or hostname of an authoritative DNS server supporting - RFC2136 in the form host:port. If the host is an IPv6 address it must be - enclosed in square brackets (e.g [2001:db8::1]) ; port is optional. - This field is required. - type: string - tsigAlgorithm: - description: |- - The TSIG Algorithm configured in the DNS supporting RFC2136. Used only - when ``tsigSecretSecretRef`` and ``tsigKeyName`` are defined. - Supported values are (case-insensitive): ``HMACMD5`` (default), - ``HMACSHA1``, ``HMACSHA256`` or ``HMACSHA512``. - type: string - tsigKeyName: - description: |- - The TSIG Key name configured in the DNS. - If ``tsigSecretSecretRef`` is defined, this field is required. - type: string - tsigSecretSecretRef: - description: |- - The name of the secret containing the TSIG value. - If ``tsigKeyName`` is defined, this field is required. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - route53: - description: Use the AWS Route53 API to manage DNS01 challenge records. - type: object - properties: - accessKeyID: - description: |- - The AccessKeyID is used for authentication. - Cannot be set when SecretAccessKeyID is set. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: string - accessKeyIDSecretRef: - description: |- - The SecretAccessKey is used for authentication. If set, pull the AWS - access key ID from a key within a Kubernetes Secret. - Cannot be set when AccessKeyID is set. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - auth: - description: Auth configures how cert-manager authenticates. - type: object - required: - - kubernetes - properties: - kubernetes: - description: |- - Kubernetes authenticates with Route53 using AssumeRoleWithWebIdentity - by passing a bound ServiceAccount token. - type: object - required: - - serviceAccountRef - properties: - serviceAccountRef: - description: |- - A reference to a service account that will be used to request a bound - token (also known as "projected token"). To use this field, you must - configure an RBAC rule to let cert-manager request a token. - type: object - required: - - name - properties: - audiences: - description: |- - TokenAudiences is an optional list of audiences to include in the - token passed to AWS. The default token consisting of the issuer's namespace - and name is always included. - If unset the audience defaults to `sts.amazonaws.com`. - type: array - items: - type: string - name: - description: Name of the ServiceAccount used to request a token. - type: string - hostedZoneID: - description: If set, the provider will manage only this zone in Route53 and will not do a lookup using the route53:ListHostedZonesByName api call. - type: string - region: - description: |- - Override the AWS region. - - Route53 is a global service and does not have regional endpoints but the - region specified here (or via environment variables) is used as a hint to - help compute the correct AWS credential scope and partition when it - connects to Route53. See: - - [Amazon Route 53 endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/r53.html) - - [Global services](https://docs.aws.amazon.com/whitepapers/latest/aws-fault-isolation-boundaries/global-services.html) - - If you omit this region field, cert-manager will use the region from - AWS_REGION and AWS_DEFAULT_REGION environment variables, if they are set - in the cert-manager controller Pod. - - The `region` field is not needed if you use [IAM Roles for Service Accounts (IRSA)](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html). - Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: - [Amazon EKS Pod Identity Webhook](https://github.com/aws/amazon-eks-pod-identity-webhook). - In this case this `region` field value is ignored. - - The `region` field is not needed if you use [EKS Pod Identities](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html). - Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: - [Amazon EKS Pod Identity Agent](https://github.com/aws/eks-pod-identity-agent), - In this case this `region` field value is ignored. - type: string - role: - description: |- - Role is a Role ARN which the Route53 provider will assume using either the explicit credentials AccessKeyID/SecretAccessKey - or the inferred credentials from environment variables, shared credentials file or AWS Instance metadata - type: string - secretAccessKeySecretRef: - description: |- - The SecretAccessKey is used for authentication. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - webhook: - description: |- - Configure an external webhook based DNS01 challenge solver to manage - DNS01 challenge records. - type: object - required: - - groupName - - solverName - properties: - config: - description: |- - Additional configuration that should be passed to the webhook apiserver - when challenges are processed. - This can contain arbitrary JSON data. - Secret values should not be specified in this stanza. - If secret values are needed (e.g. credentials for a DNS service), you - should use a SecretKeySelector to reference a Secret resource. - For details on the schema of this field, consult the webhook provider - implementation's documentation. - x-kubernetes-preserve-unknown-fields: true - groupName: - description: |- - The API group name that should be used when POSTing ChallengePayload - resources to the webhook apiserver. - This should be the same as the GroupName specified in the webhook - provider implementation. - type: string - solverName: - description: |- - The name of the solver to use, as defined in the webhook provider - implementation. - This will typically be the name of the provider, e.g. 'cloudflare'. - type: string - http01: - description: |- - Configures cert-manager to attempt to complete authorizations by - performing the HTTP01 challenge flow. - It is not possible to obtain certificates for wildcard domain names - (e.g. `*.example.com`) using the HTTP01 challenge mechanism. - type: object - properties: - gatewayHTTPRoute: - description: |- - The Gateway API is a sig-network community API that models service networking - in Kubernetes (https://gateway-api.sigs.k8s.io/). The Gateway solver will - create HTTPRoutes with the specified labels in the same namespace as the challenge. - This solver is experimental, and fields / behaviour may change in the future. - type: object - properties: - labels: - description: |- - Custom labels that will be applied to HTTPRoutes created by cert-manager - while solving HTTP-01 challenges. - type: object - additionalProperties: - type: string - parentRefs: - description: |- - When solving an HTTP-01 challenge, cert-manager creates an HTTPRoute. - cert-manager needs to know which parentRefs should be used when creating - the HTTPRoute. Usually, the parentRef references a Gateway. See: - https://gateway-api.sigs.k8s.io/api-types/httproute/#attaching-to-gateways - type: array - 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. - type: object - required: - - name - properties: - group: - 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 - type: string - default: gateway.networking.k8s.io - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - kind: - 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. - type: string - default: Gateway - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - name: - description: |- - Name is the name of the referent. - - Support: Core - type: string - maxLength: 253 - minLength: 1 - 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 - type: string - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - 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 - type: integer - format: int32 - maximum: 65535 - minimum: 1 - 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 - type: string - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - podTemplate: - description: |- - Optional pod template used to configure the ACME challenge solver pods - used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the pod used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - spec: - description: |- - PodSpec defines overrides for the HTTP01 challenge solver pod. - Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. - All other fields will be ignored. - type: object - properties: - affinity: - description: If specified, the pod's scheduling constraints - type: object - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for the pod. - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - type: object - required: - - preference - - weight - properties: - preference: - description: A node selector term, associated with the corresponding weight. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - type: object - required: - - nodeSelectorTerms - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The terms are ORed. - type: array - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - imagePullSecrets: - description: If specified, the pod's imagePullSecrets - type: array - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - type: object - properties: - name: - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - default: "" - x-kubernetes-map-type: atomic - nodeSelector: - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. - More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - type: object - additionalProperties: - type: string - priorityClassName: - description: If specified, the pod's priorityClassName. - type: string - securityContext: - description: If specified, the pod's security context - type: object - properties: - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - type: object - properties: - level: - description: Level is SELinux level label that applies to the container. - type: string - role: - description: Role is a SELinux role label that applies to the container. - type: string - type: - description: Type is a SELinux type label that applies to the container. - type: string - user: - description: User is a SELinux user label that applies to the container. - type: string - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - type: object - required: - - type - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - type: integer - format: int64 - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - description: Sysctl defines a kernel parameter to be set - type: object - required: - - name - - value - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - serviceAccountName: - description: If specified, the pod's service account - type: string - tolerations: - description: If specified, the pod's tolerations. - type: array - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - type: object - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - type: integer - format: int64 - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - serviceType: - description: |- - Optional service type for Kubernetes solver service. Supported values - are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - ingress: - description: |- - The ingress based HTTP01 challenge solver will solve challenges by - creating or modifying Ingress resources in order to route requests for - '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are - provisioned by cert-manager for each Challenge to be completed. - type: object - properties: - class: - description: |- - This field configures the annotation `kubernetes.io/ingress.class` when - creating Ingress resources to solve ACME challenges that use this - challenge solver. Only one of `class`, `name` or `ingressClassName` may - be specified. - type: string - ingressClassName: - description: |- - This field configures the field `ingressClassName` on the created Ingress - resources used to solve ACME challenges that use this challenge solver. - This is the recommended way of configuring the ingress class. Only one of - `class`, `name` or `ingressClassName` may be specified. - type: string - ingressTemplate: - description: |- - Optional ingress template used to configure the ACME challenge solver - ingress used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the ingress used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - name: - description: |- - The name of the ingress resource that should have ACME challenge solving - routes inserted into it in order to solve HTTP01 challenges. - This is typically used in conjunction with ingress controllers like - ingress-gce, which maintains a 1:1 mapping between external IPs and - ingress resources. Only one of `class`, `name` or `ingressClassName` may - be specified. - type: string - podTemplate: - description: |- - Optional pod template used to configure the ACME challenge solver pods - used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the pod used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - spec: - description: |- - PodSpec defines overrides for the HTTP01 challenge solver pod. - Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. - All other fields will be ignored. - type: object - properties: - affinity: - description: If specified, the pod's scheduling constraints - type: object - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for the pod. - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - type: object - required: - - preference - - weight - properties: - preference: - description: A node selector term, associated with the corresponding weight. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - type: object - required: - - nodeSelectorTerms - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The terms are ORed. - type: array - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - imagePullSecrets: - description: If specified, the pod's imagePullSecrets - type: array - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - type: object - properties: - name: - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - default: "" - x-kubernetes-map-type: atomic - nodeSelector: - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. - More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - type: object - additionalProperties: - type: string - priorityClassName: - description: If specified, the pod's priorityClassName. - type: string - securityContext: - description: If specified, the pod's security context - type: object - properties: - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - type: object - properties: - level: - description: Level is SELinux level label that applies to the container. - type: string - role: - description: Role is a SELinux role label that applies to the container. - type: string - type: - description: Type is a SELinux type label that applies to the container. - type: string - user: - description: User is a SELinux user label that applies to the container. - type: string - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - type: object - required: - - type - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - type: integer - format: int64 - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - description: Sysctl defines a kernel parameter to be set - type: object - required: - - name - - value - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - serviceAccountName: - description: If specified, the pod's service account - type: string - tolerations: - description: If specified, the pod's tolerations. - type: array - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - type: object - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - type: integer - format: int64 - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - serviceType: - description: |- - Optional service type for Kubernetes solver service. Supported values - are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - selector: - description: |- - Selector selects a set of DNSNames on the Certificate resource that - should be solved using this challenge solver. - If not specified, the solver will be treated as the 'default' solver - with the lowest priority, i.e. if any other solver has a more specific - match, it will be used instead. - type: object - properties: - dnsNames: - description: |- - List of DNSNames that this solver will be used to solve. - If specified and a match is found, a dnsNames selector will take - precedence over a dnsZones selector. - If multiple solvers match with the same dnsNames value, the solver - with the most matching labels in matchLabels will be selected. - If neither has more matches, the solver defined earlier in the list - will be selected. - type: array - items: - type: string - dnsZones: - description: |- - List of DNSZones that this solver will be used to solve. - The most specific DNS zone match specified here will take precedence - over other DNS zone matches, so a solver specifying sys.example.com - will be selected over one specifying example.com for the domain - www.sys.example.com. - If multiple solvers match with the same dnsZones value, the solver - with the most matching labels in matchLabels will be selected. - If neither has more matches, the solver defined earlier in the list - will be selected. - type: array - items: - type: string - matchLabels: - description: |- - A label selector that is used to refine the set of certificate's that - this challenge solver will apply to. - type: object - additionalProperties: - type: string - token: - description: |- - The ACME challenge token for this challenge. - This is the raw value returned from the ACME server. - type: string - type: - description: |- - The type of ACME challenge this resource represents. - One of "HTTP-01" or "DNS-01". - type: string - enum: - - HTTP-01 - - DNS-01 - url: - description: |- - The URL of the ACME Challenge resource for this challenge. - This can be used to lookup details about the status of this challenge. - type: string - wildcard: - description: |- - wildcard will be true if this challenge is for a wildcard identifier, - for example '*.example.com'. - type: boolean - status: - type: object - properties: - presented: - description: |- - presented will be set to true if the challenge values for this challenge - are currently 'presented'. - This *does not* imply the self check is passing. Only that the values - have been 'submitted' for the appropriate challenge mechanism (i.e. the - DNS01 TXT record has been presented, or the HTTP01 configuration has been - configured). - type: boolean - processing: - description: |- - Used to denote whether this challenge should be processed or not. - This field will only be set to true by the 'scheduling' component. - It will only be set to false by the 'challenges' controller, after the - challenge has reached a final state or timed out. - If this field is set to false, the challenge controller will not take - any more action. - type: boolean - reason: - description: |- - Contains human readable information on why the Challenge is in the - current state. - type: string - state: - description: |- - Contains the current 'state' of the challenge. - If not set, the state of the challenge is unknown. - type: string - enum: - - valid - - ready - - pending - - processing - - invalid - - expired - - errored - served: true - storage: true - subresources: - status: {} - -# END crd {{- end }} - ---- -# START crd {{- if or .Values.crds.enabled .Values.installCRDs }} -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: clusterissuers.cert-manager.io - # START annotations {{- if .Values.crds.keep }} - annotations: - helm.sh/resource-policy: keep - # END annotations {{- end }} - labels: - app: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/name: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/instance: '{{ .Release.Name }}' - # Generated labels {{- include "labels" . | nindent 4 }} -spec: - group: cert-manager.io - names: - kind: ClusterIssuer - listKind: ClusterIssuerList - plural: clusterissuers - singular: clusterissuer - categories: - - cert-manager - scope: Cluster - versions: - - name: v1 - subresources: - status: {} - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: |- - A ClusterIssuer represents a certificate issuing authority which can be - referenced as part of `issuerRef` fields. - It is similar to an Issuer, however it is cluster-scoped and therefore can - be referenced by resources that exist in *any* namespace, not just the same - namespace as the referent. - type: object - required: - - spec - 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: Desired state of the ClusterIssuer resource. - type: object - properties: - acme: - description: |- - ACME configures this issuer to communicate with a RFC8555 (ACME) server - to obtain signed x509 certificates. - type: object - required: - - privateKeySecretRef - - server - properties: - caBundle: - description: |- - Base64-encoded bundle of PEM CAs which can be used to validate the certificate - chain presented by the ACME server. - Mutually exclusive with SkipTLSVerify; prefer using CABundle to prevent various - kinds of security vulnerabilities. - If CABundle and SkipTLSVerify are unset, the system certificate bundle inside - the container is used to validate the TLS connection. - type: string - format: byte - disableAccountKeyGeneration: - description: |- - Enables or disables generating a new ACME account key. - If true, the Issuer resource will *not* request a new account but will expect - the account key to be supplied via an existing secret. - If false, the cert-manager system will generate a new ACME account key - for the Issuer. - Defaults to false. - type: boolean - email: - description: |- - Email is the email address to be associated with the ACME account. - This field is optional, but it is strongly recommended to be set. - It will be used to contact you in case of issues with your account or - certificates, including expiry notification emails. - This field may be updated after the account is initially registered. - type: string - enableDurationFeature: - description: |- - Enables requesting a Not After date on certificates that matches the - duration of the certificate. This is not supported by all ACME servers - like Let's Encrypt. If set to true when the ACME server does not support - it, it will create an error on the Order. - Defaults to false. - type: boolean - externalAccountBinding: - description: |- - ExternalAccountBinding is a reference to a CA external account of the ACME - server. - If set, upon registration cert-manager will attempt to associate the given - external account credentials with the registered ACME account. - type: object - required: - - keyID - - keySecretRef - properties: - keyAlgorithm: - description: |- - Deprecated: keyAlgorithm field exists for historical compatibility - reasons and should not be used. The algorithm is now hardcoded to HS256 - in golang/x/crypto/acme. - type: string - enum: - - HS256 - - HS384 - - HS512 - keyID: - description: keyID is the ID of the CA key that the External Account is bound to. - type: string - keySecretRef: - description: |- - keySecretRef is a Secret Key Selector referencing a data item in a Kubernetes - Secret which holds the symmetric MAC key of the External Account Binding. - The `key` is the index string that is paired with the key data in the - Secret and should not be confused with the key data itself, or indeed with - the External Account Binding keyID above. - The secret key stored in the Secret **must** be un-padded, base64 URL - encoded data. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - preferredChain: - description: |- - PreferredChain is the chain to use if the ACME server outputs multiple. - PreferredChain is no guarantee that this one gets delivered by the ACME - endpoint. - For example, for Let's Encrypt's DST crosssign you would use: - "DST Root CA X3" or "ISRG Root X1" for the newer Let's Encrypt root CA. - This value picks the first certificate bundle in the combined set of - ACME default and alternative chains that has a root-most certificate with - this value as its issuer's commonname. - type: string - maxLength: 64 - privateKeySecretRef: - description: |- - PrivateKey is the name of a Kubernetes Secret resource that will be used to - store the automatically generated ACME account private key. - Optionally, a `key` may be specified to select a specific entry within - the named Secret resource. - If `key` is not specified, a default of `tls.key` will be used. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - server: - description: |- - Server is the URL used to access the ACME server's 'directory' endpoint. - For example, for Let's Encrypt's staging endpoint, you would use: - "https://acme-staging-v02.api.letsencrypt.org/directory". - Only ACME v2 endpoints (i.e. RFC 8555) are supported. - type: string - skipTLSVerify: - description: |- - INSECURE: Enables or disables validation of the ACME server TLS certificate. - If true, requests to the ACME server will not have the TLS certificate chain - validated. - Mutually exclusive with CABundle; prefer using CABundle to prevent various - kinds of security vulnerabilities. - Only enable this option in development environments. - If CABundle and SkipTLSVerify are unset, the system certificate bundle inside - the container is used to validate the TLS connection. - Defaults to false. - type: boolean - solvers: - description: |- - Solvers is a list of challenge solvers that will be used to solve - ACME challenges for the matching domains. - Solver configurations must be provided in order to obtain certificates - from an ACME server. - For more information, see: https://cert-manager.io/docs/configuration/acme/ - type: array - items: - description: |- - An ACMEChallengeSolver describes how to solve ACME challenges for the issuer it is part of. - A selector may be provided to use different solving strategies for different DNS names. - Only one of HTTP01 or DNS01 must be provided. - type: object - properties: - dns01: - description: |- - Configures cert-manager to attempt to complete authorizations by - performing the DNS01 challenge flow. - type: object - properties: - acmeDNS: - description: |- - Use the 'ACME DNS' (https://github.com/joohoi/acme-dns) API to manage - DNS01 challenge records. - type: object - required: - - accountSecretRef - - host - properties: - accountSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - host: - type: string - akamai: - description: Use the Akamai DNS zone management API to manage DNS01 challenge records. - type: object - required: - - accessTokenSecretRef - - clientSecretSecretRef - - clientTokenSecretRef - - serviceConsumerDomain - properties: - accessTokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientSecretSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientTokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - serviceConsumerDomain: - type: string - azureDNS: - description: Use the Microsoft Azure DNS API to manage DNS01 challenge records. - type: object - required: - - resourceGroupName - - subscriptionID - properties: - clientID: - description: |- - Auth: Azure Service Principal: - The ClientID of the Azure Service Principal used to authenticate with Azure DNS. - If set, ClientSecret and TenantID must also be set. - type: string - clientSecretSecretRef: - description: |- - Auth: Azure Service Principal: - A reference to a Secret containing the password associated with the Service Principal. - If set, ClientID and TenantID must also be set. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - environment: - description: name of the Azure environment (default AzurePublicCloud) - type: string - enum: - - AzurePublicCloud - - AzureChinaCloud - - AzureGermanCloud - - AzureUSGovernmentCloud - hostedZoneName: - description: name of the DNS zone that should be used - type: string - managedIdentity: - description: |- - Auth: Azure Workload Identity or Azure Managed Service Identity: - Settings to enable Azure Workload Identity or Azure Managed Service Identity - If set, ClientID, ClientSecret and TenantID must not be set. - type: object - properties: - clientID: - description: client ID of the managed identity, can not be used at the same time as resourceID - type: string - resourceID: - description: |- - 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 - resourceGroupName: - description: resource group the DNS zone is located in - type: string - subscriptionID: - description: ID of the Azure subscription - type: string - tenantID: - description: |- - Auth: Azure Service Principal: - The TenantID of the Azure Service Principal used to authenticate with Azure DNS. - If set, ClientID and ClientSecret must also be set. - type: string - cloudDNS: - description: Use the Google Cloud DNS API to manage DNS01 challenge records. - type: object - required: - - project - properties: - hostedZoneName: - description: |- - HostedZoneName is an optional field that tells cert-manager in which - Cloud DNS zone the challenge record has to be created. - If left empty cert-manager will automatically choose a zone. - type: string - project: - type: string - serviceAccountSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - cloudflare: - description: Use the Cloudflare API to manage DNS01 challenge records. - type: object - properties: - apiKeySecretRef: - description: |- - API key to use to authenticate with Cloudflare. - Note: using an API token to authenticate is now the recommended method - as it allows greater control of permissions. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - apiTokenSecretRef: - description: API token used to authenticate with Cloudflare. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - email: - description: Email of the account, only required when using API key based authentication. - type: string - cnameStrategy: - description: |- - CNAMEStrategy configures how the DNS01 provider should handle CNAME - records when found in DNS zones. - type: string - enum: - - None - - Follow - digitalocean: - description: Use the DigitalOcean DNS API to manage DNS01 challenge records. - type: object - required: - - tokenSecretRef - properties: - tokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - rfc2136: - description: |- - Use RFC2136 ("Dynamic Updates in the Domain Name System") (https://datatracker.ietf.org/doc/rfc2136/) - to manage DNS01 challenge records. - type: object - required: - - nameserver - properties: - nameserver: - description: |- - The IP address or hostname of an authoritative DNS server supporting - RFC2136 in the form host:port. If the host is an IPv6 address it must be - enclosed in square brackets (e.g [2001:db8::1]) ; port is optional. - This field is required. - type: string - tsigAlgorithm: - description: |- - The TSIG Algorithm configured in the DNS supporting RFC2136. Used only - when ``tsigSecretSecretRef`` and ``tsigKeyName`` are defined. - Supported values are (case-insensitive): ``HMACMD5`` (default), - ``HMACSHA1``, ``HMACSHA256`` or ``HMACSHA512``. - type: string - tsigKeyName: - description: |- - The TSIG Key name configured in the DNS. - If ``tsigSecretSecretRef`` is defined, this field is required. - type: string - tsigSecretSecretRef: - description: |- - The name of the secret containing the TSIG value. - If ``tsigKeyName`` is defined, this field is required. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - route53: - description: Use the AWS Route53 API to manage DNS01 challenge records. - type: object - properties: - accessKeyID: - description: |- - The AccessKeyID is used for authentication. - Cannot be set when SecretAccessKeyID is set. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: string - accessKeyIDSecretRef: - description: |- - The SecretAccessKey is used for authentication. If set, pull the AWS - access key ID from a key within a Kubernetes Secret. - Cannot be set when AccessKeyID is set. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - auth: - description: Auth configures how cert-manager authenticates. - type: object - required: - - kubernetes - properties: - kubernetes: - description: |- - Kubernetes authenticates with Route53 using AssumeRoleWithWebIdentity - by passing a bound ServiceAccount token. - type: object - required: - - serviceAccountRef - properties: - serviceAccountRef: - description: |- - A reference to a service account that will be used to request a bound - token (also known as "projected token"). To use this field, you must - configure an RBAC rule to let cert-manager request a token. - type: object - required: - - name - properties: - audiences: - description: |- - TokenAudiences is an optional list of audiences to include in the - token passed to AWS. The default token consisting of the issuer's namespace - and name is always included. - If unset the audience defaults to `sts.amazonaws.com`. - type: array - items: - type: string - name: - description: Name of the ServiceAccount used to request a token. - type: string - hostedZoneID: - description: If set, the provider will manage only this zone in Route53 and will not do a lookup using the route53:ListHostedZonesByName api call. - type: string - region: - description: |- - Override the AWS region. - - Route53 is a global service and does not have regional endpoints but the - region specified here (or via environment variables) is used as a hint to - help compute the correct AWS credential scope and partition when it - connects to Route53. See: - - [Amazon Route 53 endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/r53.html) - - [Global services](https://docs.aws.amazon.com/whitepapers/latest/aws-fault-isolation-boundaries/global-services.html) - - If you omit this region field, cert-manager will use the region from - AWS_REGION and AWS_DEFAULT_REGION environment variables, if they are set - in the cert-manager controller Pod. - - The `region` field is not needed if you use [IAM Roles for Service Accounts (IRSA)](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html). - Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: - [Amazon EKS Pod Identity Webhook](https://github.com/aws/amazon-eks-pod-identity-webhook). - In this case this `region` field value is ignored. - - The `region` field is not needed if you use [EKS Pod Identities](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html). - Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: - [Amazon EKS Pod Identity Agent](https://github.com/aws/eks-pod-identity-agent), - In this case this `region` field value is ignored. - type: string - role: - description: |- - Role is a Role ARN which the Route53 provider will assume using either the explicit credentials AccessKeyID/SecretAccessKey - or the inferred credentials from environment variables, shared credentials file or AWS Instance metadata - type: string - secretAccessKeySecretRef: - description: |- - The SecretAccessKey is used for authentication. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - webhook: - description: |- - Configure an external webhook based DNS01 challenge solver to manage - DNS01 challenge records. - type: object - required: - - groupName - - solverName - properties: - config: - description: |- - Additional configuration that should be passed to the webhook apiserver - when challenges are processed. - This can contain arbitrary JSON data. - Secret values should not be specified in this stanza. - If secret values are needed (e.g. credentials for a DNS service), you - should use a SecretKeySelector to reference a Secret resource. - For details on the schema of this field, consult the webhook provider - implementation's documentation. - x-kubernetes-preserve-unknown-fields: true - groupName: - description: |- - The API group name that should be used when POSTing ChallengePayload - resources to the webhook apiserver. - This should be the same as the GroupName specified in the webhook - provider implementation. - type: string - solverName: - description: |- - The name of the solver to use, as defined in the webhook provider - implementation. - This will typically be the name of the provider, e.g. 'cloudflare'. - type: string - http01: - description: |- - Configures cert-manager to attempt to complete authorizations by - performing the HTTP01 challenge flow. - It is not possible to obtain certificates for wildcard domain names - (e.g. `*.example.com`) using the HTTP01 challenge mechanism. - type: object - properties: - gatewayHTTPRoute: - description: |- - The Gateway API is a sig-network community API that models service networking - in Kubernetes (https://gateway-api.sigs.k8s.io/). The Gateway solver will - create HTTPRoutes with the specified labels in the same namespace as the challenge. - This solver is experimental, and fields / behaviour may change in the future. - type: object - properties: - labels: - description: |- - Custom labels that will be applied to HTTPRoutes created by cert-manager - while solving HTTP-01 challenges. - type: object - additionalProperties: - type: string - parentRefs: - description: |- - When solving an HTTP-01 challenge, cert-manager creates an HTTPRoute. - cert-manager needs to know which parentRefs should be used when creating - the HTTPRoute. Usually, the parentRef references a Gateway. See: - https://gateway-api.sigs.k8s.io/api-types/httproute/#attaching-to-gateways - type: array - 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. - type: object - required: - - name - properties: - group: - 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 - type: string - default: gateway.networking.k8s.io - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - kind: - 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. - type: string - default: Gateway - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - name: - description: |- - Name is the name of the referent. - - Support: Core - type: string - maxLength: 253 - minLength: 1 - 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 - type: string - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - 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 - type: integer - format: int32 - maximum: 65535 - minimum: 1 - 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 - type: string - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - podTemplate: - description: |- - Optional pod template used to configure the ACME challenge solver pods - used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the pod used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - spec: - description: |- - PodSpec defines overrides for the HTTP01 challenge solver pod. - Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. - All other fields will be ignored. - type: object - properties: - affinity: - description: If specified, the pod's scheduling constraints - type: object - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for the pod. - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - type: object - required: - - preference - - weight - properties: - preference: - description: A node selector term, associated with the corresponding weight. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - type: object - required: - - nodeSelectorTerms - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The terms are ORed. - type: array - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - imagePullSecrets: - description: If specified, the pod's imagePullSecrets - type: array - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - type: object - properties: - name: - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - default: "" - x-kubernetes-map-type: atomic - nodeSelector: - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. - More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - type: object - additionalProperties: - type: string - priorityClassName: - description: If specified, the pod's priorityClassName. - type: string - securityContext: - description: If specified, the pod's security context - type: object - properties: - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - type: object - properties: - level: - description: Level is SELinux level label that applies to the container. - type: string - role: - description: Role is a SELinux role label that applies to the container. - type: string - type: - description: Type is a SELinux type label that applies to the container. - type: string - user: - description: User is a SELinux user label that applies to the container. - type: string - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - type: object - required: - - type - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - type: integer - format: int64 - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - description: Sysctl defines a kernel parameter to be set - type: object - required: - - name - - value - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - serviceAccountName: - description: If specified, the pod's service account - type: string - tolerations: - description: If specified, the pod's tolerations. - type: array - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - type: object - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - type: integer - format: int64 - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - serviceType: - description: |- - Optional service type for Kubernetes solver service. Supported values - are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - ingress: - description: |- - The ingress based HTTP01 challenge solver will solve challenges by - creating or modifying Ingress resources in order to route requests for - '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are - provisioned by cert-manager for each Challenge to be completed. - type: object - properties: - class: - description: |- - This field configures the annotation `kubernetes.io/ingress.class` when - creating Ingress resources to solve ACME challenges that use this - challenge solver. Only one of `class`, `name` or `ingressClassName` may - be specified. - type: string - ingressClassName: - description: |- - This field configures the field `ingressClassName` on the created Ingress - resources used to solve ACME challenges that use this challenge solver. - This is the recommended way of configuring the ingress class. Only one of - `class`, `name` or `ingressClassName` may be specified. - type: string - ingressTemplate: - description: |- - Optional ingress template used to configure the ACME challenge solver - ingress used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the ingress used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - name: - description: |- - The name of the ingress resource that should have ACME challenge solving - routes inserted into it in order to solve HTTP01 challenges. - This is typically used in conjunction with ingress controllers like - ingress-gce, which maintains a 1:1 mapping between external IPs and - ingress resources. Only one of `class`, `name` or `ingressClassName` may - be specified. - type: string - podTemplate: - description: |- - Optional pod template used to configure the ACME challenge solver pods - used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the pod used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - spec: - description: |- - PodSpec defines overrides for the HTTP01 challenge solver pod. - Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. - All other fields will be ignored. - type: object - properties: - affinity: - description: If specified, the pod's scheduling constraints - type: object - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for the pod. - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - type: object - required: - - preference - - weight - properties: - preference: - description: A node selector term, associated with the corresponding weight. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - type: object - required: - - nodeSelectorTerms - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The terms are ORed. - type: array - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - imagePullSecrets: - description: If specified, the pod's imagePullSecrets - type: array - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - type: object - properties: - name: - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - default: "" - x-kubernetes-map-type: atomic - nodeSelector: - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. - More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - type: object - additionalProperties: - type: string - priorityClassName: - description: If specified, the pod's priorityClassName. - type: string - securityContext: - description: If specified, the pod's security context - type: object - properties: - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - type: object - properties: - level: - description: Level is SELinux level label that applies to the container. - type: string - role: - description: Role is a SELinux role label that applies to the container. - type: string - type: - description: Type is a SELinux type label that applies to the container. - type: string - user: - description: User is a SELinux user label that applies to the container. - type: string - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - type: object - required: - - type - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - type: integer - format: int64 - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - description: Sysctl defines a kernel parameter to be set - type: object - required: - - name - - value - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - serviceAccountName: - description: If specified, the pod's service account - type: string - tolerations: - description: If specified, the pod's tolerations. - type: array - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - type: object - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - type: integer - format: int64 - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - serviceType: - description: |- - Optional service type for Kubernetes solver service. Supported values - are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - selector: - description: |- - Selector selects a set of DNSNames on the Certificate resource that - should be solved using this challenge solver. - If not specified, the solver will be treated as the 'default' solver - with the lowest priority, i.e. if any other solver has a more specific - match, it will be used instead. - type: object - properties: - dnsNames: - description: |- - List of DNSNames that this solver will be used to solve. - If specified and a match is found, a dnsNames selector will take - precedence over a dnsZones selector. - If multiple solvers match with the same dnsNames value, the solver - with the most matching labels in matchLabels will be selected. - If neither has more matches, the solver defined earlier in the list - will be selected. - type: array - items: - type: string - dnsZones: - description: |- - List of DNSZones that this solver will be used to solve. - The most specific DNS zone match specified here will take precedence - over other DNS zone matches, so a solver specifying sys.example.com - will be selected over one specifying example.com for the domain - www.sys.example.com. - If multiple solvers match with the same dnsZones value, the solver - with the most matching labels in matchLabels will be selected. - If neither has more matches, the solver defined earlier in the list - will be selected. - type: array - items: - type: string - matchLabels: - description: |- - A label selector that is used to refine the set of certificate's that - this challenge solver will apply to. - type: object - additionalProperties: - type: string - ca: - description: |- - CA configures this issuer to sign certificates using a signing CA keypair - stored in a Secret resource. - This is used to build internal PKIs that are managed by cert-manager. - type: object - required: - - secretName - properties: - crlDistributionPoints: - description: |- - The CRL distribution points is an X.509 v3 certificate extension which identifies - the location of the CRL from which the revocation of this certificate can be checked. - If not set, certificates will be issued without distribution points set. - type: array - items: - type: string - issuingCertificateURLs: - description: |- - IssuingCertificateURLs is a list of URLs which this issuer should embed into certificates - it creates. See https://www.rfc-editor.org/rfc/rfc5280#section-4.2.2.1 for more details. - As an example, such a URL might be "http://ca.domain.com/ca.crt". - type: array - items: - type: string - ocspServers: - description: |- - The OCSP server list is an X.509 v3 extension that defines a list of - URLs of OCSP responders. The OCSP responders can be queried for the - revocation status of an issued certificate. If not set, the - certificate will be issued with no OCSP servers set. For example, an - OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org". - type: array - items: - type: string - secretName: - description: |- - SecretName is the name of the secret used to sign Certificates issued - by this Issuer. - type: string - selfSigned: - description: |- - SelfSigned configures this issuer to 'self sign' certificates using the - private key used to create the CertificateRequest object. - type: object - properties: - crlDistributionPoints: - description: |- - The CRL distribution points is an X.509 v3 certificate extension which identifies - the location of the CRL from which the revocation of this certificate can be checked. - If not set certificate will be issued without CDP. Values are strings. - type: array - items: - type: string - vault: - description: |- - Vault configures this issuer to sign certificates using a HashiCorp Vault - PKI backend. - type: object - required: - - auth - - path - - server - properties: - auth: - description: Auth configures how cert-manager authenticates with the Vault server. - type: object - properties: - appRole: - description: |- - AppRole authenticates with Vault using the App Role auth mechanism, - with the role and secret stored in a Kubernetes Secret resource. - type: object - required: - - path - - roleId - - secretRef - properties: - path: - description: |- - Path where the App Role authentication backend is mounted in Vault, e.g: - "approle" - type: string - roleId: - description: |- - RoleID configured in the App Role authentication backend when setting - up the authentication backend in Vault. - type: string - secretRef: - description: |- - Reference to a key in a Secret that contains the App Role secret used - to authenticate with Vault. - The `key` field must be specified and denotes which entry within the Secret - resource is used as the app role secret. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientCertificate: - description: |- - ClientCertificate authenticates with Vault by presenting a client - certificate during the request's TLS handshake. - Works only when using HTTPS protocol. - type: object - properties: - mountPath: - description: |- - The Vault mountPath here is the mount path to use when authenticating with - Vault. For example, setting a value to `/v1/auth/foo`, will use the path - `/v1/auth/foo/login` to authenticate with Vault. If unspecified, the - default value "/v1/auth/cert" will be used. - type: string - name: - description: |- - Name of the certificate role to authenticate against. - If not set, matching any certificate role, if available. - type: string - secretName: - description: |- - Reference to Kubernetes Secret of type "kubernetes.io/tls" (hence containing - tls.crt and tls.key) used to authenticate to Vault using TLS client - authentication. - type: string - kubernetes: - description: |- - Kubernetes authenticates with Vault by passing the ServiceAccount - token stored in the named Secret resource to the Vault server. - type: object - required: - - role - properties: - mountPath: - description: |- - The Vault mountPath here is the mount path to use when authenticating with - Vault. For example, setting a value to `/v1/auth/foo`, will use the path - `/v1/auth/foo/login` to authenticate with Vault. If unspecified, the - default value "/v1/auth/kubernetes" will be used. - type: string - role: - description: |- - A required field containing the Vault Role to assume. A Role binds a - Kubernetes ServiceAccount with a set of Vault policies. - type: string - secretRef: - description: |- - The required Secret field containing a Kubernetes ServiceAccount JWT used - for authenticating with Vault. Use of 'ambient credentials' is not - supported. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - serviceAccountRef: - description: |- - A reference to a service account that will be used to request a bound - token (also known as "projected token"). Compared to using "secretRef", - using this field means that you don't rely on statically bound tokens. To - use this field, you must configure an RBAC rule to let cert-manager - request a token. - type: object - required: - - name - properties: - audiences: - description: |- - TokenAudiences is an optional list of extra audiences to include in the token passed to Vault. The default token - consisting of the issuer's namespace and name is always included. - type: array - items: - type: string - name: - description: Name of the ServiceAccount used to request a token. - type: string - tokenSecretRef: - description: TokenSecretRef authenticates with Vault by presenting a token. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - caBundle: - description: |- - Base64-encoded bundle of PEM CAs which will be used to validate the certificate - chain presented by Vault. Only used if using HTTPS to connect to Vault and - ignored for HTTP connections. - Mutually exclusive with CABundleSecretRef. - If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in - the cert-manager controller container is used to validate the TLS connection. - type: string - format: byte - caBundleSecretRef: - description: |- - Reference to a Secret containing a bundle of PEM-encoded CAs to use when - verifying the certificate chain presented by Vault when using HTTPS. - Mutually exclusive with CABundle. - If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in - the cert-manager controller container is used to validate the TLS connection. - If no key for the Secret is specified, cert-manager will default to 'ca.crt'. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientCertSecretRef: - description: |- - Reference to a Secret containing a PEM-encoded Client Certificate to use when the - Vault server requires mTLS. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientKeySecretRef: - description: |- - Reference to a Secret containing a PEM-encoded Client Private Key to use when the - Vault server requires mTLS. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1" - More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces - type: string - path: - description: |- - Path is the mount path of the Vault PKI backend's `sign` endpoint, e.g: - "my_pki_mount/sign/my-role-name". - type: string - server: - description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' - type: string - venafi: - description: |- - Venafi configures this issuer to sign certificates using a Venafi TPP - or Venafi Cloud policy zone. - type: object - required: - - zone - properties: - cloud: - description: |- - Cloud specifies the Venafi cloud configuration settings. - Only one of TPP or Cloud may be specified. - type: object - required: - - apiTokenSecretRef - properties: - apiTokenSecretRef: - description: APITokenSecretRef is a secret key selector for the Venafi Cloud API token. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - url: - description: |- - URL is the base URL for Venafi Cloud. - Defaults to "https://api.venafi.cloud/v1". - type: string - tpp: - description: |- - TPP specifies Trust Protection Platform configuration settings. - Only one of TPP or Cloud may be specified. - type: object - required: - - credentialsRef - - url - properties: - caBundle: - description: |- - Base64-encoded bundle of PEM CAs which will be used to validate the certificate - chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP. - If undefined, the certificate bundle in the cert-manager controller container - is used to validate the chain. - type: string - format: byte - caBundleSecretRef: - description: |- - Reference to a Secret containing a base64-encoded bundle of PEM CAs - which will be used to validate the certificate chain presented by the TPP server. - Only used if using HTTPS; ignored for HTTP. Mutually exclusive with CABundle. - If neither CABundle nor CABundleSecretRef is defined, the certificate bundle in - the cert-manager controller container is used to validate the TLS connection. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - credentialsRef: - description: |- - CredentialsRef is a reference to a Secret containing the Venafi TPP API credentials. - The secret must contain the key 'access-token' for the Access Token Authentication, - or two keys, 'username' and 'password' for the API Keys Authentication. - type: object - required: - - name - properties: - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - url: - description: |- - URL is the base URL for the vedsdk endpoint of the Venafi TPP instance, - for example: "https://tpp.example.com/vedsdk". - type: string - zone: - description: |- - Zone is the Venafi Policy Zone to use for this issuer. - All requests made to the Venafi platform will be restricted by the named - zone policy. - This field is required. - type: string - status: - description: Status of the ClusterIssuer. This is set and managed automatically. - type: object - properties: - acme: - description: |- - ACME specific status options. - This field should only be set if the Issuer is configured to use an ACME - server to issue certificates. - type: object - properties: - lastPrivateKeyHash: - description: |- - LastPrivateKeyHash is a hash of the private key associated with the latest - registered ACME account, in order to track changes made to registered account - associated with the Issuer - type: string - lastRegisteredEmail: - description: |- - LastRegisteredEmail is the email associated with the latest registered - ACME account, in order to track changes made to registered account - associated with the Issuer - type: string - uri: - description: |- - URI is the unique account identifier, which can also be used to retrieve - account details from the CA - type: string - conditions: - description: |- - List of status conditions to indicate the status of a CertificateRequest. - Known condition types are `Ready`. - type: array - items: - description: IssuerCondition contains condition information for an Issuer. - type: object - required: - - status - - type - properties: - lastTransitionTime: - description: |- - LastTransitionTime is the timestamp corresponding to the last status - change of this condition. - type: string - format: date-time - message: - description: |- - Message is a human readable description of the details of the last - transition, complementing reason. - type: string - observedGeneration: - description: |- - If set, this represents the .metadata.generation that the condition was - set based upon. - For instance, if .metadata.generation is currently 12, but the - .status.condition[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the Issuer. - type: integer - format: int64 - reason: - description: |- - Reason is a brief machine readable explanation for the condition's last - transition. - type: string - status: - description: Status of the condition, one of (`True`, `False`, `Unknown`). - type: string - enum: - - "True" - - "False" - - Unknown - type: - description: Type of the condition, known values are (`Ready`). - type: string - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - served: true - storage: true - -# END crd {{- end }} - ---- -# START crd {{- if or .Values.crds.enabled .Values.installCRDs }} -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: issuers.cert-manager.io - # START annotations {{- if .Values.crds.keep }} - annotations: - helm.sh/resource-policy: keep - # END annotations {{- end }} - labels: - app: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/name: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/instance: '{{ .Release.Name }}' - app.kubernetes.io/component: "crds" - # Generated labels {{- include "labels" . | nindent 4 }} -spec: - group: cert-manager.io - names: - kind: Issuer - listKind: IssuerList - plural: issuers - singular: issuer - categories: - - cert-manager - scope: Namespaced - versions: - - name: v1 - subresources: - status: {} - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: |- - An Issuer represents a certificate issuing authority which can be - referenced as part of `issuerRef` fields. - It is scoped to a single namespace and can therefore only be referenced by - resources within the same namespace. - type: object - required: - - spec - 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: Desired state of the Issuer resource. - type: object - properties: - acme: - description: |- - ACME configures this issuer to communicate with a RFC8555 (ACME) server - to obtain signed x509 certificates. - type: object - required: - - privateKeySecretRef - - server - properties: - caBundle: - description: |- - Base64-encoded bundle of PEM CAs which can be used to validate the certificate - chain presented by the ACME server. - Mutually exclusive with SkipTLSVerify; prefer using CABundle to prevent various - kinds of security vulnerabilities. - If CABundle and SkipTLSVerify are unset, the system certificate bundle inside - the container is used to validate the TLS connection. - type: string - format: byte - disableAccountKeyGeneration: - description: |- - Enables or disables generating a new ACME account key. - If true, the Issuer resource will *not* request a new account but will expect - the account key to be supplied via an existing secret. - If false, the cert-manager system will generate a new ACME account key - for the Issuer. - Defaults to false. - type: boolean - email: - description: |- - Email is the email address to be associated with the ACME account. - This field is optional, but it is strongly recommended to be set. - It will be used to contact you in case of issues with your account or - certificates, including expiry notification emails. - This field may be updated after the account is initially registered. - type: string - enableDurationFeature: - description: |- - Enables requesting a Not After date on certificates that matches the - duration of the certificate. This is not supported by all ACME servers - like Let's Encrypt. If set to true when the ACME server does not support - it, it will create an error on the Order. - Defaults to false. - type: boolean - externalAccountBinding: - description: |- - ExternalAccountBinding is a reference to a CA external account of the ACME - server. - If set, upon registration cert-manager will attempt to associate the given - external account credentials with the registered ACME account. - type: object - required: - - keyID - - keySecretRef - properties: - keyAlgorithm: - description: |- - Deprecated: keyAlgorithm field exists for historical compatibility - reasons and should not be used. The algorithm is now hardcoded to HS256 - in golang/x/crypto/acme. - type: string - enum: - - HS256 - - HS384 - - HS512 - keyID: - description: keyID is the ID of the CA key that the External Account is bound to. - type: string - keySecretRef: - description: |- - keySecretRef is a Secret Key Selector referencing a data item in a Kubernetes - Secret which holds the symmetric MAC key of the External Account Binding. - The `key` is the index string that is paired with the key data in the - Secret and should not be confused with the key data itself, or indeed with - the External Account Binding keyID above. - The secret key stored in the Secret **must** be un-padded, base64 URL - encoded data. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - preferredChain: - description: |- - PreferredChain is the chain to use if the ACME server outputs multiple. - PreferredChain is no guarantee that this one gets delivered by the ACME - endpoint. - For example, for Let's Encrypt's DST crosssign you would use: - "DST Root CA X3" or "ISRG Root X1" for the newer Let's Encrypt root CA. - This value picks the first certificate bundle in the combined set of - ACME default and alternative chains that has a root-most certificate with - this value as its issuer's commonname. - type: string - maxLength: 64 - privateKeySecretRef: - description: |- - PrivateKey is the name of a Kubernetes Secret resource that will be used to - store the automatically generated ACME account private key. - Optionally, a `key` may be specified to select a specific entry within - the named Secret resource. - If `key` is not specified, a default of `tls.key` will be used. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - server: - description: |- - Server is the URL used to access the ACME server's 'directory' endpoint. - For example, for Let's Encrypt's staging endpoint, you would use: - "https://acme-staging-v02.api.letsencrypt.org/directory". - Only ACME v2 endpoints (i.e. RFC 8555) are supported. - type: string - skipTLSVerify: - description: |- - INSECURE: Enables or disables validation of the ACME server TLS certificate. - If true, requests to the ACME server will not have the TLS certificate chain - validated. - Mutually exclusive with CABundle; prefer using CABundle to prevent various - kinds of security vulnerabilities. - Only enable this option in development environments. - If CABundle and SkipTLSVerify are unset, the system certificate bundle inside - the container is used to validate the TLS connection. - Defaults to false. - type: boolean - solvers: - description: |- - Solvers is a list of challenge solvers that will be used to solve - ACME challenges for the matching domains. - Solver configurations must be provided in order to obtain certificates - from an ACME server. - For more information, see: https://cert-manager.io/docs/configuration/acme/ - type: array - items: - description: |- - An ACMEChallengeSolver describes how to solve ACME challenges for the issuer it is part of. - A selector may be provided to use different solving strategies for different DNS names. - Only one of HTTP01 or DNS01 must be provided. - type: object - properties: - dns01: - description: |- - Configures cert-manager to attempt to complete authorizations by - performing the DNS01 challenge flow. - type: object - properties: - acmeDNS: - description: |- - Use the 'ACME DNS' (https://github.com/joohoi/acme-dns) API to manage - DNS01 challenge records. - type: object - required: - - accountSecretRef - - host - properties: - accountSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - host: - type: string - akamai: - description: Use the Akamai DNS zone management API to manage DNS01 challenge records. - type: object - required: - - accessTokenSecretRef - - clientSecretSecretRef - - clientTokenSecretRef - - serviceConsumerDomain - properties: - accessTokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientSecretSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientTokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - serviceConsumerDomain: - type: string - azureDNS: - description: Use the Microsoft Azure DNS API to manage DNS01 challenge records. - type: object - required: - - resourceGroupName - - subscriptionID - properties: - clientID: - description: |- - Auth: Azure Service Principal: - The ClientID of the Azure Service Principal used to authenticate with Azure DNS. - If set, ClientSecret and TenantID must also be set. - type: string - clientSecretSecretRef: - description: |- - Auth: Azure Service Principal: - A reference to a Secret containing the password associated with the Service Principal. - If set, ClientID and TenantID must also be set. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - environment: - description: name of the Azure environment (default AzurePublicCloud) - type: string - enum: - - AzurePublicCloud - - AzureChinaCloud - - AzureGermanCloud - - AzureUSGovernmentCloud - hostedZoneName: - description: name of the DNS zone that should be used - type: string - managedIdentity: - description: |- - Auth: Azure Workload Identity or Azure Managed Service Identity: - Settings to enable Azure Workload Identity or Azure Managed Service Identity - If set, ClientID, ClientSecret and TenantID must not be set. - type: object - properties: - clientID: - description: client ID of the managed identity, can not be used at the same time as resourceID - type: string - resourceID: - description: |- - 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 - resourceGroupName: - description: resource group the DNS zone is located in - type: string - subscriptionID: - description: ID of the Azure subscription - type: string - tenantID: - description: |- - Auth: Azure Service Principal: - The TenantID of the Azure Service Principal used to authenticate with Azure DNS. - If set, ClientID and ClientSecret must also be set. - type: string - cloudDNS: - description: Use the Google Cloud DNS API to manage DNS01 challenge records. - type: object - required: - - project - properties: - hostedZoneName: - description: |- - HostedZoneName is an optional field that tells cert-manager in which - Cloud DNS zone the challenge record has to be created. - If left empty cert-manager will automatically choose a zone. - type: string - project: - type: string - serviceAccountSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - cloudflare: - description: Use the Cloudflare API to manage DNS01 challenge records. - type: object - properties: - apiKeySecretRef: - description: |- - API key to use to authenticate with Cloudflare. - Note: using an API token to authenticate is now the recommended method - as it allows greater control of permissions. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - apiTokenSecretRef: - description: API token used to authenticate with Cloudflare. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - email: - description: Email of the account, only required when using API key based authentication. - type: string - cnameStrategy: - description: |- - CNAMEStrategy configures how the DNS01 provider should handle CNAME - records when found in DNS zones. - type: string - enum: - - None - - Follow - digitalocean: - description: Use the DigitalOcean DNS API to manage DNS01 challenge records. - type: object - required: - - tokenSecretRef - properties: - tokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - rfc2136: - description: |- - Use RFC2136 ("Dynamic Updates in the Domain Name System") (https://datatracker.ietf.org/doc/rfc2136/) - to manage DNS01 challenge records. - type: object - required: - - nameserver - properties: - nameserver: - description: |- - The IP address or hostname of an authoritative DNS server supporting - RFC2136 in the form host:port. If the host is an IPv6 address it must be - enclosed in square brackets (e.g [2001:db8::1]) ; port is optional. - This field is required. - type: string - tsigAlgorithm: - description: |- - The TSIG Algorithm configured in the DNS supporting RFC2136. Used only - when ``tsigSecretSecretRef`` and ``tsigKeyName`` are defined. - Supported values are (case-insensitive): ``HMACMD5`` (default), - ``HMACSHA1``, ``HMACSHA256`` or ``HMACSHA512``. - type: string - tsigKeyName: - description: |- - The TSIG Key name configured in the DNS. - If ``tsigSecretSecretRef`` is defined, this field is required. - type: string - tsigSecretSecretRef: - description: |- - The name of the secret containing the TSIG value. - If ``tsigKeyName`` is defined, this field is required. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - route53: - description: Use the AWS Route53 API to manage DNS01 challenge records. - type: object - properties: - accessKeyID: - description: |- - The AccessKeyID is used for authentication. - Cannot be set when SecretAccessKeyID is set. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: string - accessKeyIDSecretRef: - description: |- - The SecretAccessKey is used for authentication. If set, pull the AWS - access key ID from a key within a Kubernetes Secret. - Cannot be set when AccessKeyID is set. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - auth: - description: Auth configures how cert-manager authenticates. - type: object - required: - - kubernetes - properties: - kubernetes: - description: |- - Kubernetes authenticates with Route53 using AssumeRoleWithWebIdentity - by passing a bound ServiceAccount token. - type: object - required: - - serviceAccountRef - properties: - serviceAccountRef: - description: |- - A reference to a service account that will be used to request a bound - token (also known as "projected token"). To use this field, you must - configure an RBAC rule to let cert-manager request a token. - type: object - required: - - name - properties: - audiences: - description: |- - TokenAudiences is an optional list of audiences to include in the - token passed to AWS. The default token consisting of the issuer's namespace - and name is always included. - If unset the audience defaults to `sts.amazonaws.com`. - type: array - items: - type: string - name: - description: Name of the ServiceAccount used to request a token. - type: string - hostedZoneID: - description: If set, the provider will manage only this zone in Route53 and will not do a lookup using the route53:ListHostedZonesByName api call. - type: string - region: - description: |- - Override the AWS region. - - Route53 is a global service and does not have regional endpoints but the - region specified here (or via environment variables) is used as a hint to - help compute the correct AWS credential scope and partition when it - connects to Route53. See: - - [Amazon Route 53 endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/r53.html) - - [Global services](https://docs.aws.amazon.com/whitepapers/latest/aws-fault-isolation-boundaries/global-services.html) - - If you omit this region field, cert-manager will use the region from - AWS_REGION and AWS_DEFAULT_REGION environment variables, if they are set - in the cert-manager controller Pod. - - The `region` field is not needed if you use [IAM Roles for Service Accounts (IRSA)](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html). - Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: - [Amazon EKS Pod Identity Webhook](https://github.com/aws/amazon-eks-pod-identity-webhook). - In this case this `region` field value is ignored. - - The `region` field is not needed if you use [EKS Pod Identities](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html). - Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: - [Amazon EKS Pod Identity Agent](https://github.com/aws/eks-pod-identity-agent), - In this case this `region` field value is ignored. - type: string - role: - description: |- - Role is a Role ARN which the Route53 provider will assume using either the explicit credentials AccessKeyID/SecretAccessKey - or the inferred credentials from environment variables, shared credentials file or AWS Instance metadata - type: string - secretAccessKeySecretRef: - description: |- - The SecretAccessKey is used for authentication. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - webhook: - description: |- - Configure an external webhook based DNS01 challenge solver to manage - DNS01 challenge records. - type: object - required: - - groupName - - solverName - properties: - config: - description: |- - Additional configuration that should be passed to the webhook apiserver - when challenges are processed. - This can contain arbitrary JSON data. - Secret values should not be specified in this stanza. - If secret values are needed (e.g. credentials for a DNS service), you - should use a SecretKeySelector to reference a Secret resource. - For details on the schema of this field, consult the webhook provider - implementation's documentation. - x-kubernetes-preserve-unknown-fields: true - groupName: - description: |- - The API group name that should be used when POSTing ChallengePayload - resources to the webhook apiserver. - This should be the same as the GroupName specified in the webhook - provider implementation. - type: string - solverName: - description: |- - The name of the solver to use, as defined in the webhook provider - implementation. - This will typically be the name of the provider, e.g. 'cloudflare'. - type: string - http01: - description: |- - Configures cert-manager to attempt to complete authorizations by - performing the HTTP01 challenge flow. - It is not possible to obtain certificates for wildcard domain names - (e.g. `*.example.com`) using the HTTP01 challenge mechanism. - type: object - properties: - gatewayHTTPRoute: - description: |- - The Gateway API is a sig-network community API that models service networking - in Kubernetes (https://gateway-api.sigs.k8s.io/). The Gateway solver will - create HTTPRoutes with the specified labels in the same namespace as the challenge. - This solver is experimental, and fields / behaviour may change in the future. - type: object - properties: - labels: - description: |- - Custom labels that will be applied to HTTPRoutes created by cert-manager - while solving HTTP-01 challenges. - type: object - additionalProperties: - type: string - parentRefs: - description: |- - When solving an HTTP-01 challenge, cert-manager creates an HTTPRoute. - cert-manager needs to know which parentRefs should be used when creating - the HTTPRoute. Usually, the parentRef references a Gateway. See: - https://gateway-api.sigs.k8s.io/api-types/httproute/#attaching-to-gateways - type: array - 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. - type: object - required: - - name - properties: - group: - 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 - type: string - default: gateway.networking.k8s.io - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - kind: - 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. - type: string - default: Gateway - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - name: - description: |- - Name is the name of the referent. - - Support: Core - type: string - maxLength: 253 - minLength: 1 - 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 - type: string - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - 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 - type: integer - format: int32 - maximum: 65535 - minimum: 1 - 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 - type: string - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - podTemplate: - description: |- - Optional pod template used to configure the ACME challenge solver pods - used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the pod used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - spec: - description: |- - PodSpec defines overrides for the HTTP01 challenge solver pod. - Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. - All other fields will be ignored. - type: object - properties: - affinity: - description: If specified, the pod's scheduling constraints - type: object - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for the pod. - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - type: object - required: - - preference - - weight - properties: - preference: - description: A node selector term, associated with the corresponding weight. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - type: object - required: - - nodeSelectorTerms - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The terms are ORed. - type: array - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - imagePullSecrets: - description: If specified, the pod's imagePullSecrets - type: array - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - type: object - properties: - name: - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - default: "" - x-kubernetes-map-type: atomic - nodeSelector: - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. - More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - type: object - additionalProperties: - type: string - priorityClassName: - description: If specified, the pod's priorityClassName. - type: string - securityContext: - description: If specified, the pod's security context - type: object - properties: - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - type: object - properties: - level: - description: Level is SELinux level label that applies to the container. - type: string - role: - description: Role is a SELinux role label that applies to the container. - type: string - type: - description: Type is a SELinux type label that applies to the container. - type: string - user: - description: User is a SELinux user label that applies to the container. - type: string - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - type: object - required: - - type - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - type: integer - format: int64 - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - description: Sysctl defines a kernel parameter to be set - type: object - required: - - name - - value - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - serviceAccountName: - description: If specified, the pod's service account - type: string - tolerations: - description: If specified, the pod's tolerations. - type: array - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - type: object - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - type: integer - format: int64 - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - serviceType: - description: |- - Optional service type for Kubernetes solver service. Supported values - are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - ingress: - description: |- - The ingress based HTTP01 challenge solver will solve challenges by - creating or modifying Ingress resources in order to route requests for - '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are - provisioned by cert-manager for each Challenge to be completed. - type: object - properties: - class: - description: |- - This field configures the annotation `kubernetes.io/ingress.class` when - creating Ingress resources to solve ACME challenges that use this - challenge solver. Only one of `class`, `name` or `ingressClassName` may - be specified. - type: string - ingressClassName: - description: |- - This field configures the field `ingressClassName` on the created Ingress - resources used to solve ACME challenges that use this challenge solver. - This is the recommended way of configuring the ingress class. Only one of - `class`, `name` or `ingressClassName` may be specified. - type: string - ingressTemplate: - description: |- - Optional ingress template used to configure the ACME challenge solver - ingress used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the ingress used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - name: - description: |- - The name of the ingress resource that should have ACME challenge solving - routes inserted into it in order to solve HTTP01 challenges. - This is typically used in conjunction with ingress controllers like - ingress-gce, which maintains a 1:1 mapping between external IPs and - ingress resources. Only one of `class`, `name` or `ingressClassName` may - be specified. - type: string - podTemplate: - description: |- - Optional pod template used to configure the ACME challenge solver pods - used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the pod used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - spec: - description: |- - PodSpec defines overrides for the HTTP01 challenge solver pod. - Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. - All other fields will be ignored. - type: object - properties: - affinity: - description: If specified, the pod's scheduling constraints - type: object - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for the pod. - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - type: object - required: - - preference - - weight - properties: - preference: - description: A node selector term, associated with the corresponding weight. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - type: object - required: - - nodeSelectorTerms - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The terms are ORed. - type: array - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - imagePullSecrets: - description: If specified, the pod's imagePullSecrets - type: array - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - type: object - properties: - name: - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - default: "" - x-kubernetes-map-type: atomic - nodeSelector: - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. - More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - type: object - additionalProperties: - type: string - priorityClassName: - description: If specified, the pod's priorityClassName. - type: string - securityContext: - description: If specified, the pod's security context - type: object - properties: - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - type: object - properties: - level: - description: Level is SELinux level label that applies to the container. - type: string - role: - description: Role is a SELinux role label that applies to the container. - type: string - type: - description: Type is a SELinux type label that applies to the container. - type: string - user: - description: User is a SELinux user label that applies to the container. - type: string - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - type: object - required: - - type - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - type: integer - format: int64 - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - description: Sysctl defines a kernel parameter to be set - type: object - required: - - name - - value - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - serviceAccountName: - description: If specified, the pod's service account - type: string - tolerations: - description: If specified, the pod's tolerations. - type: array - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - type: object - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - type: integer - format: int64 - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - serviceType: - description: |- - Optional service type for Kubernetes solver service. Supported values - are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - selector: - description: |- - Selector selects a set of DNSNames on the Certificate resource that - should be solved using this challenge solver. - If not specified, the solver will be treated as the 'default' solver - with the lowest priority, i.e. if any other solver has a more specific - match, it will be used instead. - type: object - properties: - dnsNames: - description: |- - List of DNSNames that this solver will be used to solve. - If specified and a match is found, a dnsNames selector will take - precedence over a dnsZones selector. - If multiple solvers match with the same dnsNames value, the solver - with the most matching labels in matchLabels will be selected. - If neither has more matches, the solver defined earlier in the list - will be selected. - type: array - items: - type: string - dnsZones: - description: |- - List of DNSZones that this solver will be used to solve. - The most specific DNS zone match specified here will take precedence - over other DNS zone matches, so a solver specifying sys.example.com - will be selected over one specifying example.com for the domain - www.sys.example.com. - If multiple solvers match with the same dnsZones value, the solver - with the most matching labels in matchLabels will be selected. - If neither has more matches, the solver defined earlier in the list - will be selected. - type: array - items: - type: string - matchLabels: - description: |- - A label selector that is used to refine the set of certificate's that - this challenge solver will apply to. - type: object - additionalProperties: - type: string - ca: - description: |- - CA configures this issuer to sign certificates using a signing CA keypair - stored in a Secret resource. - This is used to build internal PKIs that are managed by cert-manager. - type: object - required: - - secretName - properties: - crlDistributionPoints: - description: |- - The CRL distribution points is an X.509 v3 certificate extension which identifies - the location of the CRL from which the revocation of this certificate can be checked. - If not set, certificates will be issued without distribution points set. - type: array - items: - type: string - issuingCertificateURLs: - description: |- - IssuingCertificateURLs is a list of URLs which this issuer should embed into certificates - it creates. See https://www.rfc-editor.org/rfc/rfc5280#section-4.2.2.1 for more details. - As an example, such a URL might be "http://ca.domain.com/ca.crt". - type: array - items: - type: string - ocspServers: - description: |- - The OCSP server list is an X.509 v3 extension that defines a list of - URLs of OCSP responders. The OCSP responders can be queried for the - revocation status of an issued certificate. If not set, the - certificate will be issued with no OCSP servers set. For example, an - OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org". - type: array - items: - type: string - secretName: - description: |- - SecretName is the name of the secret used to sign Certificates issued - by this Issuer. - type: string - selfSigned: - description: |- - SelfSigned configures this issuer to 'self sign' certificates using the - private key used to create the CertificateRequest object. - type: object - properties: - crlDistributionPoints: - description: |- - The CRL distribution points is an X.509 v3 certificate extension which identifies - the location of the CRL from which the revocation of this certificate can be checked. - If not set certificate will be issued without CDP. Values are strings. - type: array - items: - type: string - vault: - description: |- - Vault configures this issuer to sign certificates using a HashiCorp Vault - PKI backend. - type: object - required: - - auth - - path - - server - properties: - auth: - description: Auth configures how cert-manager authenticates with the Vault server. - type: object - properties: - appRole: - description: |- - AppRole authenticates with Vault using the App Role auth mechanism, - with the role and secret stored in a Kubernetes Secret resource. - type: object - required: - - path - - roleId - - secretRef - properties: - path: - description: |- - Path where the App Role authentication backend is mounted in Vault, e.g: - "approle" - type: string - roleId: - description: |- - RoleID configured in the App Role authentication backend when setting - up the authentication backend in Vault. - type: string - secretRef: - description: |- - Reference to a key in a Secret that contains the App Role secret used - to authenticate with Vault. - The `key` field must be specified and denotes which entry within the Secret - resource is used as the app role secret. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientCertificate: - description: |- - ClientCertificate authenticates with Vault by presenting a client - certificate during the request's TLS handshake. - Works only when using HTTPS protocol. - type: object - properties: - mountPath: - description: |- - The Vault mountPath here is the mount path to use when authenticating with - Vault. For example, setting a value to `/v1/auth/foo`, will use the path - `/v1/auth/foo/login` to authenticate with Vault. If unspecified, the - default value "/v1/auth/cert" will be used. - type: string - name: - description: |- - Name of the certificate role to authenticate against. - If not set, matching any certificate role, if available. - type: string - secretName: - description: |- - Reference to Kubernetes Secret of type "kubernetes.io/tls" (hence containing - tls.crt and tls.key) used to authenticate to Vault using TLS client - authentication. - type: string - kubernetes: - description: |- - Kubernetes authenticates with Vault by passing the ServiceAccount - token stored in the named Secret resource to the Vault server. - type: object - required: - - role - properties: - mountPath: - description: |- - The Vault mountPath here is the mount path to use when authenticating with - Vault. For example, setting a value to `/v1/auth/foo`, will use the path - `/v1/auth/foo/login` to authenticate with Vault. If unspecified, the - default value "/v1/auth/kubernetes" will be used. - type: string - role: - description: |- - A required field containing the Vault Role to assume. A Role binds a - Kubernetes ServiceAccount with a set of Vault policies. - type: string - secretRef: - description: |- - The required Secret field containing a Kubernetes ServiceAccount JWT used - for authenticating with Vault. Use of 'ambient credentials' is not - supported. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - serviceAccountRef: - description: |- - A reference to a service account that will be used to request a bound - token (also known as "projected token"). Compared to using "secretRef", - using this field means that you don't rely on statically bound tokens. To - use this field, you must configure an RBAC rule to let cert-manager - request a token. - type: object - required: - - name - properties: - audiences: - description: |- - TokenAudiences is an optional list of extra audiences to include in the token passed to Vault. The default token - consisting of the issuer's namespace and name is always included. - type: array - items: - type: string - name: - description: Name of the ServiceAccount used to request a token. - type: string - tokenSecretRef: - description: TokenSecretRef authenticates with Vault by presenting a token. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - caBundle: - description: |- - Base64-encoded bundle of PEM CAs which will be used to validate the certificate - chain presented by Vault. Only used if using HTTPS to connect to Vault and - ignored for HTTP connections. - Mutually exclusive with CABundleSecretRef. - If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in - the cert-manager controller container is used to validate the TLS connection. - type: string - format: byte - caBundleSecretRef: - description: |- - Reference to a Secret containing a bundle of PEM-encoded CAs to use when - verifying the certificate chain presented by Vault when using HTTPS. - Mutually exclusive with CABundle. - If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in - the cert-manager controller container is used to validate the TLS connection. - If no key for the Secret is specified, cert-manager will default to 'ca.crt'. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientCertSecretRef: - description: |- - Reference to a Secret containing a PEM-encoded Client Certificate to use when the - Vault server requires mTLS. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientKeySecretRef: - description: |- - Reference to a Secret containing a PEM-encoded Client Private Key to use when the - Vault server requires mTLS. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1" - More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces - type: string - path: - description: |- - Path is the mount path of the Vault PKI backend's `sign` endpoint, e.g: - "my_pki_mount/sign/my-role-name". - type: string - server: - description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' - type: string - venafi: - description: |- - Venafi configures this issuer to sign certificates using a Venafi TPP - or Venafi Cloud policy zone. - type: object - required: - - zone - properties: - cloud: - description: |- - Cloud specifies the Venafi cloud configuration settings. - Only one of TPP or Cloud may be specified. - type: object - required: - - apiTokenSecretRef - properties: - apiTokenSecretRef: - description: APITokenSecretRef is a secret key selector for the Venafi Cloud API token. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - url: - description: |- - URL is the base URL for Venafi Cloud. - Defaults to "https://api.venafi.cloud/v1". - type: string - tpp: - description: |- - TPP specifies Trust Protection Platform configuration settings. - Only one of TPP or Cloud may be specified. - type: object - required: - - credentialsRef - - url - properties: - caBundle: - description: |- - Base64-encoded bundle of PEM CAs which will be used to validate the certificate - chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP. - If undefined, the certificate bundle in the cert-manager controller container - is used to validate the chain. - type: string - format: byte - caBundleSecretRef: - description: |- - Reference to a Secret containing a base64-encoded bundle of PEM CAs - which will be used to validate the certificate chain presented by the TPP server. - Only used if using HTTPS; ignored for HTTP. Mutually exclusive with CABundle. - If neither CABundle nor CABundleSecretRef is defined, the certificate bundle in - the cert-manager controller container is used to validate the TLS connection. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - credentialsRef: - description: |- - CredentialsRef is a reference to a Secret containing the Venafi TPP API credentials. - The secret must contain the key 'access-token' for the Access Token Authentication, - or two keys, 'username' and 'password' for the API Keys Authentication. - type: object - required: - - name - properties: - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - url: - description: |- - URL is the base URL for the vedsdk endpoint of the Venafi TPP instance, - for example: "https://tpp.example.com/vedsdk". - type: string - zone: - description: |- - Zone is the Venafi Policy Zone to use for this issuer. - All requests made to the Venafi platform will be restricted by the named - zone policy. - This field is required. - type: string - status: - description: Status of the Issuer. This is set and managed automatically. - type: object - properties: - acme: - description: |- - ACME specific status options. - This field should only be set if the Issuer is configured to use an ACME - server to issue certificates. - type: object - properties: - lastPrivateKeyHash: - description: |- - LastPrivateKeyHash is a hash of the private key associated with the latest - registered ACME account, in order to track changes made to registered account - associated with the Issuer - type: string - lastRegisteredEmail: - description: |- - LastRegisteredEmail is the email associated with the latest registered - ACME account, in order to track changes made to registered account - associated with the Issuer - type: string - uri: - description: |- - URI is the unique account identifier, which can also be used to retrieve - account details from the CA - type: string - conditions: - description: |- - List of status conditions to indicate the status of a CertificateRequest. - Known condition types are `Ready`. - type: array - items: - description: IssuerCondition contains condition information for an Issuer. - type: object - required: - - status - - type - properties: - lastTransitionTime: - description: |- - LastTransitionTime is the timestamp corresponding to the last status - change of this condition. - type: string - format: date-time - message: - description: |- - Message is a human readable description of the details of the last - transition, complementing reason. - type: string - observedGeneration: - description: |- - If set, this represents the .metadata.generation that the condition was - set based upon. - For instance, if .metadata.generation is currently 12, but the - .status.condition[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the Issuer. - type: integer - format: int64 - reason: - description: |- - Reason is a brief machine readable explanation for the condition's last - transition. - type: string - status: - description: Status of the condition, one of (`True`, `False`, `Unknown`). - type: string - enum: - - "True" - - "False" - - Unknown - type: - description: Type of the condition, known values are (`Ready`). - type: string - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - served: true - storage: true - -# END crd {{- end }} - ---- -# START crd {{- if or .Values.crds.enabled .Values.installCRDs }} -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: orders.acme.cert-manager.io - # START annotations {{- if .Values.crds.keep }} - annotations: - helm.sh/resource-policy: keep - # END annotations {{- end }} - labels: - app: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/name: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/instance: '{{ .Release.Name }}' - app.kubernetes.io/component: "crds" - # Generated labels {{- include "labels" . | nindent 4 }} -spec: - group: acme.cert-manager.io - names: - kind: Order - listKind: OrderList - plural: orders - singular: order - categories: - - cert-manager - - cert-manager-acme - scope: Namespaced - versions: - - name: v1 - subresources: - status: {} - additionalPrinterColumns: - - jsonPath: .status.state - name: State - type: string - - jsonPath: .spec.issuerRef.name - name: Issuer - priority: 1 - type: string - - jsonPath: .status.reason - name: Reason - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: Order is a type to represent an Order with an ACME server - type: object - required: - - metadata - - spec - 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: - type: object - required: - - issuerRef - - request - properties: - commonName: - description: |- - CommonName is the common name as specified on the DER encoded CSR. - If specified, this value must also be present in `dnsNames` or `ipAddresses`. - This field must match the corresponding field on the DER encoded CSR. - type: string - dnsNames: - description: |- - DNSNames is a list of DNS names that should be included as part of the Order - validation process. - This field must match the corresponding field on the DER encoded CSR. - type: array - items: - type: string - duration: - description: |- - Duration is the duration for the not after date for the requested certificate. - this is set on order creation as pe the ACME spec. - type: string - ipAddresses: - description: |- - IPAddresses is a list of IP addresses that should be included as part of the Order - validation process. - This field must match the corresponding field on the DER encoded CSR. - type: array - items: - type: string - issuerRef: - description: |- - IssuerRef references a properly configured ACME-type Issuer which should - be used to create this Order. - If the Issuer does not exist, processing will be retried. - If the Issuer is not an 'ACME' Issuer, an error will be returned and the - Order will be marked as failed. - type: object - required: - - name - properties: - group: - description: Group of the resource being referred to. - type: string - kind: - description: Kind of the resource being referred to. - type: string - name: - description: Name of the resource being referred to. - type: string - request: - description: |- - Certificate signing request bytes in DER encoding. - This will be used when finalizing the order. - This field must be set on the order. - type: string - format: byte - status: - type: object - properties: - authorizations: - description: |- - Authorizations contains data returned from the ACME server on what - authorizations must be completed in order to validate the DNS names - specified on the Order. - type: array - items: - description: |- - ACMEAuthorization contains data returned from the ACME server on an - authorization that must be completed in order validate a DNS name on an ACME - Order resource. - type: object - required: - - url - properties: - challenges: - description: |- - Challenges specifies the challenge types offered by the ACME server. - One of these challenge types will be selected when validating the DNS - name and an appropriate Challenge resource will be created to perform - the ACME challenge process. - type: array - items: - description: |- - Challenge specifies a challenge offered by the ACME server for an Order. - An appropriate Challenge resource can be created to perform the ACME - challenge process. - type: object - required: - - token - - type - - url - properties: - token: - description: |- - Token is the token that must be presented for this challenge. - This is used to compute the 'key' that must also be presented. - type: string - type: - description: |- - Type is the type of challenge being offered, e.g. 'http-01', 'dns-01', - 'tls-sni-01', etc. - This is the raw value retrieved from the ACME server. - Only 'http-01' and 'dns-01' are supported by cert-manager, other values - will be ignored. - type: string - url: - description: |- - URL is the URL of this challenge. It can be used to retrieve additional - metadata about the Challenge from the ACME server. - type: string - identifier: - description: Identifier is the DNS name to be validated as part of this authorization - type: string - initialState: - description: |- - InitialState is the initial state of the ACME authorization when first - fetched from the ACME server. - If an Authorization is already 'valid', the Order controller will not - create a Challenge resource for the authorization. This will occur when - working with an ACME server that enables 'authz reuse' (such as Let's - Encrypt's production endpoint). - If not set and 'identifier' is set, the state is assumed to be pending - and a Challenge will be created. - type: string - enum: - - valid - - ready - - pending - - processing - - invalid - - expired - - errored - url: - description: URL is the URL of the Authorization that must be completed - type: string - wildcard: - description: |- - Wildcard will be true if this authorization is for a wildcard DNS name. - If this is true, the identifier will be the *non-wildcard* version of - the DNS name. - For example, if '*.example.com' is the DNS name being validated, this - field will be 'true' and the 'identifier' field will be 'example.com'. - type: boolean - certificate: - description: |- - Certificate is a copy of the PEM encoded certificate for this Order. - This field will be populated after the order has been successfully - finalized with the ACME server, and the order has transitioned to the - 'valid' state. - type: string - format: byte - failureTime: - description: |- - FailureTime stores the time that this order failed. - This is used to influence garbage collection and back-off. - type: string - format: date-time - finalizeURL: - description: |- - FinalizeURL of the Order. - This is used to obtain certificates for this order once it has been completed. - type: string - reason: - description: |- - Reason optionally provides more information about a why the order is in - the current state. - type: string - state: - description: |- - State contains the current state of this Order resource. - States 'success' and 'expired' are 'final' - type: string - enum: - - valid - - ready - - pending - - processing - - invalid - - expired - - errored - url: - description: |- - URL of the Order. - This will initially be empty when the resource is first created. - The Order controller will populate this field when the Order is first processed. - This field will be immutable after it is initially set. - type: string - served: true - storage: true - -# END crd {{- end }} diff --git a/packages/system/cert-manager-crds/charts/cert-manager/values.schema.json b/packages/system/cert-manager-crds/charts/cert-manager/values.schema.json deleted file mode 100644 index d04da90c..00000000 --- a/packages/system/cert-manager-crds/charts/cert-manager/values.schema.json +++ /dev/null @@ -1,2135 +0,0 @@ -{ - "$defs": { - "helm-values": { - "additionalProperties": false, - "properties": { - "acmesolver": { - "$ref": "#/$defs/helm-values.acmesolver" - }, - "affinity": { - "$ref": "#/$defs/helm-values.affinity" - }, - "approveSignerNames": { - "$ref": "#/$defs/helm-values.approveSignerNames" - }, - "automountServiceAccountToken": { - "$ref": "#/$defs/helm-values.automountServiceAccountToken" - }, - "cainjector": { - "$ref": "#/$defs/helm-values.cainjector" - }, - "clusterResourceNamespace": { - "$ref": "#/$defs/helm-values.clusterResourceNamespace" - }, - "config": { - "$ref": "#/$defs/helm-values.config" - }, - "containerSecurityContext": { - "$ref": "#/$defs/helm-values.containerSecurityContext" - }, - "crds": { - "$ref": "#/$defs/helm-values.crds" - }, - "creator": { - "$ref": "#/$defs/helm-values.creator" - }, - "deploymentAnnotations": { - "$ref": "#/$defs/helm-values.deploymentAnnotations" - }, - "disableAutoApproval": { - "$ref": "#/$defs/helm-values.disableAutoApproval" - }, - "dns01RecursiveNameservers": { - "$ref": "#/$defs/helm-values.dns01RecursiveNameservers" - }, - "dns01RecursiveNameserversOnly": { - "$ref": "#/$defs/helm-values.dns01RecursiveNameserversOnly" - }, - "enableCertificateOwnerRef": { - "$ref": "#/$defs/helm-values.enableCertificateOwnerRef" - }, - "enableServiceLinks": { - "$ref": "#/$defs/helm-values.enableServiceLinks" - }, - "enabled": { - "$ref": "#/$defs/helm-values.enabled" - }, - "extraArgs": { - "$ref": "#/$defs/helm-values.extraArgs" - }, - "extraEnv": { - "$ref": "#/$defs/helm-values.extraEnv" - }, - "extraObjects": { - "$ref": "#/$defs/helm-values.extraObjects" - }, - "featureGates": { - "$ref": "#/$defs/helm-values.featureGates" - }, - "fullnameOverride": { - "$ref": "#/$defs/helm-values.fullnameOverride" - }, - "global": { - "$ref": "#/$defs/helm-values.global" - }, - "hostAliases": { - "$ref": "#/$defs/helm-values.hostAliases" - }, - "http_proxy": { - "$ref": "#/$defs/helm-values.http_proxy" - }, - "https_proxy": { - "$ref": "#/$defs/helm-values.https_proxy" - }, - "image": { - "$ref": "#/$defs/helm-values.image" - }, - "ingressShim": { - "$ref": "#/$defs/helm-values.ingressShim" - }, - "installCRDs": { - "$ref": "#/$defs/helm-values.installCRDs" - }, - "livenessProbe": { - "$ref": "#/$defs/helm-values.livenessProbe" - }, - "maxConcurrentChallenges": { - "$ref": "#/$defs/helm-values.maxConcurrentChallenges" - }, - "nameOverride": { - "$ref": "#/$defs/helm-values.nameOverride" - }, - "namespace": { - "$ref": "#/$defs/helm-values.namespace" - }, - "no_proxy": { - "$ref": "#/$defs/helm-values.no_proxy" - }, - "nodeSelector": { - "$ref": "#/$defs/helm-values.nodeSelector" - }, - "podAnnotations": { - "$ref": "#/$defs/helm-values.podAnnotations" - }, - "podDisruptionBudget": { - "$ref": "#/$defs/helm-values.podDisruptionBudget" - }, - "podDnsConfig": { - "$ref": "#/$defs/helm-values.podDnsConfig" - }, - "podDnsPolicy": { - "$ref": "#/$defs/helm-values.podDnsPolicy" - }, - "podLabels": { - "$ref": "#/$defs/helm-values.podLabels" - }, - "prometheus": { - "$ref": "#/$defs/helm-values.prometheus" - }, - "replicaCount": { - "$ref": "#/$defs/helm-values.replicaCount" - }, - "resources": { - "$ref": "#/$defs/helm-values.resources" - }, - "securityContext": { - "$ref": "#/$defs/helm-values.securityContext" - }, - "serviceAccount": { - "$ref": "#/$defs/helm-values.serviceAccount" - }, - "serviceAnnotations": { - "$ref": "#/$defs/helm-values.serviceAnnotations" - }, - "serviceIPFamilies": { - "$ref": "#/$defs/helm-values.serviceIPFamilies" - }, - "serviceIPFamilyPolicy": { - "$ref": "#/$defs/helm-values.serviceIPFamilyPolicy" - }, - "serviceLabels": { - "$ref": "#/$defs/helm-values.serviceLabels" - }, - "startupapicheck": { - "$ref": "#/$defs/helm-values.startupapicheck" - }, - "strategy": { - "$ref": "#/$defs/helm-values.strategy" - }, - "tolerations": { - "$ref": "#/$defs/helm-values.tolerations" - }, - "topologySpreadConstraints": { - "$ref": "#/$defs/helm-values.topologySpreadConstraints" - }, - "volumeMounts": { - "$ref": "#/$defs/helm-values.volumeMounts" - }, - "volumes": { - "$ref": "#/$defs/helm-values.volumes" - }, - "webhook": { - "$ref": "#/$defs/helm-values.webhook" - } - }, - "type": "object" - }, - "helm-values.acmesolver": { - "additionalProperties": false, - "properties": { - "image": { - "$ref": "#/$defs/helm-values.acmesolver.image" - } - }, - "type": "object" - }, - "helm-values.acmesolver.image": { - "additionalProperties": false, - "properties": { - "digest": { - "$ref": "#/$defs/helm-values.acmesolver.image.digest" - }, - "pullPolicy": { - "$ref": "#/$defs/helm-values.acmesolver.image.pullPolicy" - }, - "registry": { - "$ref": "#/$defs/helm-values.acmesolver.image.registry" - }, - "repository": { - "$ref": "#/$defs/helm-values.acmesolver.image.repository" - }, - "tag": { - "$ref": "#/$defs/helm-values.acmesolver.image.tag" - } - }, - "type": "object" - }, - "helm-values.acmesolver.image.digest": { - "description": "Setting a digest will override any tag.", - "type": "string" - }, - "helm-values.acmesolver.image.pullPolicy": { - "default": "IfNotPresent", - "description": "Kubernetes imagePullPolicy on Deployment.", - "type": "string" - }, - "helm-values.acmesolver.image.registry": { - "description": "The container registry to pull the acmesolver image from.", - "type": "string" - }, - "helm-values.acmesolver.image.repository": { - "default": "quay.io/jetstack/cert-manager-acmesolver", - "description": "The container image for the cert-manager acmesolver.", - "type": "string" - }, - "helm-values.acmesolver.image.tag": { - "description": "Override the image tag to deploy by setting this variable. If no value is set, the chart's appVersion is used.", - "type": "string" - }, - "helm-values.affinity": { - "default": {}, - "description": "A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core).\n\nFor example:\naffinity:\n nodeAffinity:\n requiredDuringSchedulingIgnoredDuringExecution:\n nodeSelectorTerms:\n - matchExpressions:\n - key: foo.bar.com/role\n operator: In\n values:\n - master", - "type": "object" - }, - "helm-values.approveSignerNames": { - "default": [ - "issuers.cert-manager.io/*", - "clusterissuers.cert-manager.io/*" - ], - "description": "List of signer names that cert-manager will approve by default. CertificateRequests referencing these signer names will be auto-approved by cert-manager. Defaults to just approving the cert-manager.io Issuer and ClusterIssuer issuers. When set to an empty array, ALL issuers will be auto-approved by cert-manager. To disable the auto-approval, because eg. you are using approver-policy, you can enable 'disableAutoApproval'.\nref: https://cert-manager.io/docs/concepts/certificaterequest/#approval", - "items": {}, - "type": "array" - }, - "helm-values.automountServiceAccountToken": { - "description": "Automounting API credentials for a particular pod.", - "type": "boolean" - }, - "helm-values.cainjector": { - "additionalProperties": false, - "properties": { - "affinity": { - "$ref": "#/$defs/helm-values.cainjector.affinity" - }, - "automountServiceAccountToken": { - "$ref": "#/$defs/helm-values.cainjector.automountServiceAccountToken" - }, - "config": { - "$ref": "#/$defs/helm-values.cainjector.config" - }, - "containerSecurityContext": { - "$ref": "#/$defs/helm-values.cainjector.containerSecurityContext" - }, - "deploymentAnnotations": { - "$ref": "#/$defs/helm-values.cainjector.deploymentAnnotations" - }, - "enableServiceLinks": { - "$ref": "#/$defs/helm-values.cainjector.enableServiceLinks" - }, - "enabled": { - "$ref": "#/$defs/helm-values.cainjector.enabled" - }, - "extraArgs": { - "$ref": "#/$defs/helm-values.cainjector.extraArgs" - }, - "extraEnv": { - "$ref": "#/$defs/helm-values.cainjector.extraEnv" - }, - "featureGates": { - "$ref": "#/$defs/helm-values.cainjector.featureGates" - }, - "image": { - "$ref": "#/$defs/helm-values.cainjector.image" - }, - "nodeSelector": { - "$ref": "#/$defs/helm-values.cainjector.nodeSelector" - }, - "podAnnotations": { - "$ref": "#/$defs/helm-values.cainjector.podAnnotations" - }, - "podDisruptionBudget": { - "$ref": "#/$defs/helm-values.cainjector.podDisruptionBudget" - }, - "podLabels": { - "$ref": "#/$defs/helm-values.cainjector.podLabels" - }, - "replicaCount": { - "$ref": "#/$defs/helm-values.cainjector.replicaCount" - }, - "resources": { - "$ref": "#/$defs/helm-values.cainjector.resources" - }, - "securityContext": { - "$ref": "#/$defs/helm-values.cainjector.securityContext" - }, - "serviceAccount": { - "$ref": "#/$defs/helm-values.cainjector.serviceAccount" - }, - "serviceAnnotations": { - "$ref": "#/$defs/helm-values.cainjector.serviceAnnotations" - }, - "serviceLabels": { - "$ref": "#/$defs/helm-values.cainjector.serviceLabels" - }, - "strategy": { - "$ref": "#/$defs/helm-values.cainjector.strategy" - }, - "tolerations": { - "$ref": "#/$defs/helm-values.cainjector.tolerations" - }, - "topologySpreadConstraints": { - "$ref": "#/$defs/helm-values.cainjector.topologySpreadConstraints" - }, - "volumeMounts": { - "$ref": "#/$defs/helm-values.cainjector.volumeMounts" - }, - "volumes": { - "$ref": "#/$defs/helm-values.cainjector.volumes" - } - }, - "type": "object" - }, - "helm-values.cainjector.affinity": { - "default": {}, - "description": "A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core).\n\nFor example:\naffinity:\n nodeAffinity:\n requiredDuringSchedulingIgnoredDuringExecution:\n nodeSelectorTerms:\n - matchExpressions:\n - key: foo.bar.com/role\n operator: In\n values:\n - master", - "type": "object" - }, - "helm-values.cainjector.automountServiceAccountToken": { - "description": "Automounting API credentials for a particular pod.", - "type": "boolean" - }, - "helm-values.cainjector.config": { - "default": {}, - "description": "This is used to configure options for the cainjector pod. It allows setting options that are usually provided via flags.\n\nIf `apiVersion` and `kind` are unspecified they default to the current latest version (currently `cainjector.config.cert-manager.io/v1alpha1`). You can pin the version by specifying the `apiVersion` yourself.\n\nFor example:\napiVersion: cainjector.config.cert-manager.io/v1alpha1\nkind: CAInjectorConfiguration\nlogging:\n verbosity: 2\n format: text\nleaderElectionConfig:\n namespace: kube-system\n# Configure the metrics server for TLS\n# See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls\nmetricsTLSConfig:\n dynamic:\n secretNamespace: \"cert-manager\"\n secretName: \"cert-manager-metrics-ca\"\n dnsNames:\n - cert-manager-metrics", - "type": "object" - }, - "helm-values.cainjector.containerSecurityContext": { - "default": { - "allowPrivilegeEscalation": false, - "capabilities": { - "drop": [ - "ALL" - ] - }, - "readOnlyRootFilesystem": true - }, - "description": "Container Security Context to be set on the cainjector component container. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/).", - "type": "object" - }, - "helm-values.cainjector.deploymentAnnotations": { - "description": "Optional additional annotations to add to the cainjector Deployment.", - "type": "object" - }, - "helm-values.cainjector.enableServiceLinks": { - "default": false, - "description": "enableServiceLinks indicates whether information about services should be injected into the pod's environment variables, matching the syntax of Docker links.", - "type": "boolean" - }, - "helm-values.cainjector.enabled": { - "default": true, - "description": "Create the CA Injector deployment", - "type": "boolean" - }, - "helm-values.cainjector.extraArgs": { - "default": [], - "description": "Additional command line flags to pass to cert-manager cainjector binary. To see all available flags run `docker run quay.io/jetstack/cert-manager-cainjector: --help`.", - "items": {}, - "type": "array" - }, - "helm-values.cainjector.extraEnv": { - "default": [], - "description": "Additional environment variables to pass to cert-manager cainjector binary.\nFor example:\nextraEnv:\n- name: SOME_VAR\n value: 'some value'", - "items": {}, - "type": "array" - }, - "helm-values.cainjector.featureGates": { - "default": "", - "description": "Comma separated list of feature gates that should be enabled on the cainjector pod.", - "type": "string" - }, - "helm-values.cainjector.image": { - "additionalProperties": false, - "properties": { - "digest": { - "$ref": "#/$defs/helm-values.cainjector.image.digest" - }, - "pullPolicy": { - "$ref": "#/$defs/helm-values.cainjector.image.pullPolicy" - }, - "registry": { - "$ref": "#/$defs/helm-values.cainjector.image.registry" - }, - "repository": { - "$ref": "#/$defs/helm-values.cainjector.image.repository" - }, - "tag": { - "$ref": "#/$defs/helm-values.cainjector.image.tag" - } - }, - "type": "object" - }, - "helm-values.cainjector.image.digest": { - "description": "Setting a digest will override any tag.", - "type": "string" - }, - "helm-values.cainjector.image.pullPolicy": { - "default": "IfNotPresent", - "description": "Kubernetes imagePullPolicy on Deployment.", - "type": "string" - }, - "helm-values.cainjector.image.registry": { - "description": "The container registry to pull the cainjector image from.", - "type": "string" - }, - "helm-values.cainjector.image.repository": { - "default": "quay.io/jetstack/cert-manager-cainjector", - "description": "The container image for the cert-manager cainjector", - "type": "string" - }, - "helm-values.cainjector.image.tag": { - "description": "Override the image tag to deploy by setting this variable. If no value is set, the chart's appVersion will be used.", - "type": "string" - }, - "helm-values.cainjector.nodeSelector": { - "default": { - "kubernetes.io/os": "linux" - }, - "description": "The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with matching labels. For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/).\n\nThis default ensures that Pods are only scheduled to Linux nodes. It prevents Pods being scheduled to Windows nodes in a mixed OS cluster.", - "type": "object" - }, - "helm-values.cainjector.podAnnotations": { - "description": "Optional additional annotations to add to the cainjector Pods.", - "type": "object" - }, - "helm-values.cainjector.podDisruptionBudget": { - "additionalProperties": false, - "properties": { - "enabled": { - "$ref": "#/$defs/helm-values.cainjector.podDisruptionBudget.enabled" - }, - "maxUnavailable": { - "$ref": "#/$defs/helm-values.cainjector.podDisruptionBudget.maxUnavailable" - }, - "minAvailable": { - "$ref": "#/$defs/helm-values.cainjector.podDisruptionBudget.minAvailable" - } - }, - "type": "object" - }, - "helm-values.cainjector.podDisruptionBudget.enabled": { - "default": false, - "description": "Enable or disable the PodDisruptionBudget resource.\n\nThis prevents downtime during voluntary disruptions such as during a Node upgrade. For example, the PodDisruptionBudget will block `kubectl drain` if it is used on the Node where the only remaining cert-manager\nPod is currently running.", - "type": "boolean" - }, - "helm-values.cainjector.podDisruptionBudget.maxUnavailable": { - "description": "`maxUnavailable` configures the maximum unavailable pods for disruptions. It can either be set to\nan integer (e.g. 1) or a percentage value (e.g. 25%).\nCannot be used if `minAvailable` is set." - }, - "helm-values.cainjector.podDisruptionBudget.minAvailable": { - "description": "`minAvailable` configures the minimum available pods for disruptions. It can either be set to\nan integer (e.g. 1) or a percentage value (e.g. 25%).\nCannot be used if `maxUnavailable` is set." - }, - "helm-values.cainjector.podLabels": { - "default": {}, - "description": "Optional additional labels to add to the CA Injector Pods.", - "type": "object" - }, - "helm-values.cainjector.replicaCount": { - "default": 1, - "description": "The number of replicas of the cert-manager cainjector to run.\n\nThe default is 1, but in production set this to 2 or 3 to provide high availability.\n\nIf `replicas > 1`, consider setting `cainjector.podDisruptionBudget.enabled=true`.\n\nNote that cert-manager uses leader election to ensure that there can only be a single instance active at a time.", - "type": "number" - }, - "helm-values.cainjector.resources": { - "default": {}, - "description": "Resources to provide to the cert-manager cainjector pod.\n\nFor example:\nrequests:\n cpu: 10m\n memory: 32Mi\nFor more information, see [Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/).", - "type": "object" - }, - "helm-values.cainjector.securityContext": { - "default": { - "runAsNonRoot": true, - "seccompProfile": { - "type": "RuntimeDefault" - } - }, - "description": "Pod Security Context to be set on the cainjector component Pod. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/).", - "type": "object" - }, - "helm-values.cainjector.serviceAccount": { - "additionalProperties": false, - "properties": { - "annotations": { - "$ref": "#/$defs/helm-values.cainjector.serviceAccount.annotations" - }, - "automountServiceAccountToken": { - "$ref": "#/$defs/helm-values.cainjector.serviceAccount.automountServiceAccountToken" - }, - "create": { - "$ref": "#/$defs/helm-values.cainjector.serviceAccount.create" - }, - "labels": { - "$ref": "#/$defs/helm-values.cainjector.serviceAccount.labels" - }, - "name": { - "$ref": "#/$defs/helm-values.cainjector.serviceAccount.name" - } - }, - "type": "object" - }, - "helm-values.cainjector.serviceAccount.annotations": { - "description": "Optional additional annotations to add to the cainjector's Service Account.", - "type": "object" - }, - "helm-values.cainjector.serviceAccount.automountServiceAccountToken": { - "default": true, - "description": "Automount API credentials for a Service Account.", - "type": "boolean" - }, - "helm-values.cainjector.serviceAccount.create": { - "default": true, - "description": "Specifies whether a service account should be created.", - "type": "boolean" - }, - "helm-values.cainjector.serviceAccount.labels": { - "description": "Optional additional labels to add to the cainjector's Service Account.", - "type": "object" - }, - "helm-values.cainjector.serviceAccount.name": { - "description": "The name of the service account to use.\nIf not set and create is true, a name is generated using the fullname template", - "type": "string" - }, - "helm-values.cainjector.serviceAnnotations": { - "description": "Optional additional annotations to add to the cainjector metrics Service.", - "type": "object" - }, - "helm-values.cainjector.serviceLabels": { - "default": {}, - "description": "Optional additional labels to add to the CA Injector metrics Service.", - "type": "object" - }, - "helm-values.cainjector.strategy": { - "default": {}, - "description": "Deployment update strategy for the cert-manager cainjector deployment. For more information, see the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy).\n\nFor example:\nstrategy:\n type: RollingUpdate\n rollingUpdate:\n maxSurge: 0\n maxUnavailable: 1", - "type": "object" - }, - "helm-values.cainjector.tolerations": { - "default": [], - "description": "A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core).\n\nFor example:\ntolerations:\n- key: foo.bar.com/role\n operator: Equal\n value: master\n effect: NoSchedule", - "items": {}, - "type": "array" - }, - "helm-values.cainjector.topologySpreadConstraints": { - "default": [], - "description": "A list of Kubernetes TopologySpreadConstraints, if required. For more information, see [Topology spread constraint v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#topologyspreadconstraint-v1-core).\n\nFor example:\ntopologySpreadConstraints:\n- maxSkew: 2\n topologyKey: topology.kubernetes.io/zone\n whenUnsatisfiable: ScheduleAnyway\n labelSelector:\n matchLabels:\n app.kubernetes.io/instance: cert-manager\n app.kubernetes.io/component: controller", - "items": {}, - "type": "array" - }, - "helm-values.cainjector.volumeMounts": { - "default": [], - "description": "Additional volume mounts to add to the cert-manager controller container.", - "items": {}, - "type": "array" - }, - "helm-values.cainjector.volumes": { - "default": [], - "description": "Additional volumes to add to the cert-manager controller pod.", - "items": {}, - "type": "array" - }, - "helm-values.clusterResourceNamespace": { - "default": "", - "description": "Override the namespace used to store DNS provider credentials etc. for ClusterIssuer resources. By default, the same namespace as cert-manager is deployed within is used. This namespace will not be automatically created by the Helm chart.", - "type": "string" - }, - "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", - "type": "object" - }, - "helm-values.containerSecurityContext": { - "default": { - "allowPrivilegeEscalation": false, - "capabilities": { - "drop": [ - "ALL" - ] - }, - "readOnlyRootFilesystem": true - }, - "description": "Container Security Context to be set on the controller component container. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/).", - "type": "object" - }, - "helm-values.crds": { - "additionalProperties": false, - "properties": { - "enabled": { - "$ref": "#/$defs/helm-values.crds.enabled" - }, - "keep": { - "$ref": "#/$defs/helm-values.crds.keep" - } - }, - "type": "object" - }, - "helm-values.crds.enabled": { - "default": false, - "description": "This option decides if the CRDs should be installed as part of the Helm installation.", - "type": "boolean" - }, - "helm-values.crds.keep": { - "default": true, - "description": "This option makes it so that the \"helm.sh/resource-policy\": keep annotation is added to the CRD. This will prevent Helm from uninstalling the CRD when the Helm release is uninstalled. WARNING: when the CRDs are removed, all cert-manager custom resources\n(Certificates, Issuers, ...) will be removed too by the garbage collector.", - "type": "boolean" - }, - "helm-values.creator": { - "default": "helm", - "description": "Field used by our release pipeline to produce the static manifests. The field defaults to \"helm\" but is set to \"static\" when we render the static YAML manifests.", - "type": "string" - }, - "helm-values.deploymentAnnotations": { - "description": "Optional additional annotations to add to the controller Deployment.", - "type": "object" - }, - "helm-values.disableAutoApproval": { - "default": false, - "description": "Option to disable cert-manager's build-in auto-approver. The auto-approver approves all CertificateRequests that reference issuers matching the 'approveSignerNames' option. This 'disableAutoApproval' option is useful when you want to make all approval decisions using a different approver (like approver-policy - https://github.com/cert-manager/approver-policy).", - "type": "boolean" - }, - "helm-values.dns01RecursiveNameservers": { - "default": "", - "description": "A comma-separated string with the host and port of the recursive nameservers cert-manager should query.", - "type": "string" - }, - "helm-values.dns01RecursiveNameserversOnly": { - "default": false, - "description": "Forces cert-manager to use only the recursive nameservers for verification. Enabling this option could cause the DNS01 self check to take longer owing to caching performed by the recursive nameservers.", - "type": "boolean" - }, - "helm-values.enableCertificateOwnerRef": { - "default": false, - "description": "When this flag is enabled, secrets will be automatically removed when the certificate resource is deleted.", - "type": "boolean" - }, - "helm-values.enableServiceLinks": { - "default": false, - "description": "enableServiceLinks indicates whether information about services should be injected into the pod's environment variables, matching the syntax of Docker links.", - "type": "boolean" - }, - "helm-values.enabled": { - "default": true, - "description": "Field that can be used as a condition when cert-manager is a dependency. This definition is only here as a placeholder such that it is included in the json schema. See https://helm.sh/docs/chart_best_practices/dependencies/#conditions-and-tags for more info.", - "type": "boolean" - }, - "helm-values.extraArgs": { - "default": [], - "description": "Additional command line flags to pass to cert-manager controller binary. To see all available flags run `docker run quay.io/jetstack/cert-manager-controller: --help`.\n\nUse this flag to enable or disable arbitrary controllers. For example, to disable the CertificateRequests approver.\n\nFor example:\nextraArgs:\n - --controllers=*,-certificaterequests-approver", - "items": {}, - "type": "array" - }, - "helm-values.extraEnv": { - "default": [], - "description": "Additional environment variables to pass to cert-manager controller binary.\nFor example:\nextraEnv:\n- name: SOME_VAR\n value: 'some value'", - "items": {}, - "type": "array" - }, - "helm-values.extraObjects": { - "default": [], - "description": "Create dynamic manifests via values.\n\nFor example:\nextraObjects:\n - |\n apiVersion: v1\n kind: ConfigMap\n metadata:\n name: '{{ template \"cert-manager.fullname\" . }}-extra-configmap'", - "items": {}, - "type": "array" - }, - "helm-values.featureGates": { - "default": "", - "description": "A comma-separated list of feature gates that should be enabled on the controller pod.", - "type": "string" - }, - "helm-values.fullnameOverride": { - "description": "Override the \"cert-manager.fullname\" value. This value is used as part of most of the names of the resources created by this Helm chart.", - "type": "string" - }, - "helm-values.global": { - "description": "Global values shared across all (sub)charts", - "properties": { - "commonLabels": { - "$ref": "#/$defs/helm-values.global.commonLabels" - }, - "imagePullSecrets": { - "$ref": "#/$defs/helm-values.global.imagePullSecrets" - }, - "leaderElection": { - "$ref": "#/$defs/helm-values.global.leaderElection" - }, - "logLevel": { - "$ref": "#/$defs/helm-values.global.logLevel" - }, - "podSecurityPolicy": { - "$ref": "#/$defs/helm-values.global.podSecurityPolicy" - }, - "priorityClassName": { - "$ref": "#/$defs/helm-values.global.priorityClassName" - }, - "rbac": { - "$ref": "#/$defs/helm-values.global.rbac" - }, - "revisionHistoryLimit": { - "$ref": "#/$defs/helm-values.global.revisionHistoryLimit" - } - }, - "type": "object" - }, - "helm-values.global.commonLabels": { - "default": {}, - "description": "Labels to apply to all resources.\nPlease note that this does not add labels to the resources created dynamically by the controllers. For these resources, you have to add the labels in the template in the cert-manager custom resource: For example, podTemplate/ ingressTemplate in ACMEChallengeSolverHTTP01Ingress. For more information, see the [cert-manager documentation](https://cert-manager.io/docs/reference/api-docs/#acme.cert-manager.io/v1.ACMEChallengeSolverHTTP01Ingress).\nFor example, secretTemplate in CertificateSpec\nFor more information, see the [cert-manager documentation](https://cert-manager.io/docs/reference/api-docs/#cert-manager.io/v1.CertificateSpec).", - "type": "object" - }, - "helm-values.global.imagePullSecrets": { - "default": [], - "description": "Reference to one or more secrets to be used when pulling images. For more information, see [Pull an Image from a Private Registry](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/).\n\nFor example:\nimagePullSecrets:\n - name: \"image-pull-secret\"", - "items": {}, - "type": "array" - }, - "helm-values.global.leaderElection": { - "properties": { - "leaseDuration": { - "$ref": "#/$defs/helm-values.global.leaderElection.leaseDuration" - }, - "namespace": { - "$ref": "#/$defs/helm-values.global.leaderElection.namespace" - }, - "renewDeadline": { - "$ref": "#/$defs/helm-values.global.leaderElection.renewDeadline" - }, - "retryPeriod": { - "$ref": "#/$defs/helm-values.global.leaderElection.retryPeriod" - } - }, - "type": "object" - }, - "helm-values.global.leaderElection.leaseDuration": { - "description": "The duration that non-leader candidates will wait after observing a leadership renewal until attempting to acquire leadership of a led but unrenewed leader slot. This is effectively the maximum duration that a leader can be stopped before it is replaced by another candidate.", - "type": "string" - }, - "helm-values.global.leaderElection.namespace": { - "default": "kube-system", - "description": "Override the namespace used for the leader election lease.", - "type": "string" - }, - "helm-values.global.leaderElection.renewDeadline": { - "description": "The interval between attempts by the acting master to renew a leadership slot before it stops leading. This must be less than or equal to the lease duration.", - "type": "string" - }, - "helm-values.global.leaderElection.retryPeriod": { - "description": "The duration the clients should wait between attempting acquisition and renewal of a leadership.", - "type": "string" - }, - "helm-values.global.logLevel": { - "default": 2, - "description": "Set the verbosity of cert-manager. A range of 0 - 6, with 6 being the most verbose.", - "type": "number" - }, - "helm-values.global.podSecurityPolicy": { - "properties": { - "enabled": { - "$ref": "#/$defs/helm-values.global.podSecurityPolicy.enabled" - }, - "useAppArmor": { - "$ref": "#/$defs/helm-values.global.podSecurityPolicy.useAppArmor" - } - }, - "type": "object" - }, - "helm-values.global.podSecurityPolicy.enabled": { - "default": false, - "description": "Create PodSecurityPolicy for cert-manager.\n\nNote that PodSecurityPolicy was deprecated in Kubernetes 1.21 and removed in Kubernetes 1.25.", - "type": "boolean" - }, - "helm-values.global.podSecurityPolicy.useAppArmor": { - "default": true, - "description": "Configure the PodSecurityPolicy to use AppArmor.", - "type": "boolean" - }, - "helm-values.global.priorityClassName": { - "default": "", - "description": "The optional priority class to be used for the cert-manager pods.", - "type": "string" - }, - "helm-values.global.rbac": { - "properties": { - "aggregateClusterRoles": { - "$ref": "#/$defs/helm-values.global.rbac.aggregateClusterRoles" - }, - "create": { - "$ref": "#/$defs/helm-values.global.rbac.create" - } - }, - "type": "object" - }, - "helm-values.global.rbac.aggregateClusterRoles": { - "default": true, - "description": "Aggregate ClusterRoles to Kubernetes default user-facing roles. For more information, see [User-facing roles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)", - "type": "boolean" - }, - "helm-values.global.rbac.create": { - "default": true, - "description": "Create required ClusterRoles and ClusterRoleBindings for cert-manager.", - "type": "boolean" - }, - "helm-values.global.revisionHistoryLimit": { - "description": "The number of old ReplicaSets to retain to allow rollback (if not set, the default Kubernetes value is set to 10).", - "type": "number" - }, - "helm-values.hostAliases": { - "default": [], - "description": "Optional hostAliases for cert-manager-controller pods. May be useful when performing ACME DNS-01 self checks.", - "items": {}, - "type": "array" - }, - "helm-values.http_proxy": { - "description": "Configures the HTTP_PROXY environment variable where a HTTP proxy is required.", - "type": "string" - }, - "helm-values.https_proxy": { - "description": "Configures the HTTPS_PROXY environment variable where a HTTP proxy is required.", - "type": "string" - }, - "helm-values.image": { - "additionalProperties": false, - "properties": { - "digest": { - "$ref": "#/$defs/helm-values.image.digest" - }, - "pullPolicy": { - "$ref": "#/$defs/helm-values.image.pullPolicy" - }, - "registry": { - "$ref": "#/$defs/helm-values.image.registry" - }, - "repository": { - "$ref": "#/$defs/helm-values.image.repository" - }, - "tag": { - "$ref": "#/$defs/helm-values.image.tag" - } - }, - "type": "object" - }, - "helm-values.image.digest": { - "description": "Setting a digest will override any tag.", - "type": "string" - }, - "helm-values.image.pullPolicy": { - "default": "IfNotPresent", - "description": "Kubernetes imagePullPolicy on Deployment.", - "type": "string" - }, - "helm-values.image.registry": { - "description": "The container registry to pull the manager image from.", - "type": "string" - }, - "helm-values.image.repository": { - "default": "quay.io/jetstack/cert-manager-controller", - "description": "The container image for the cert-manager controller.", - "type": "string" - }, - "helm-values.image.tag": { - "description": "Override the image tag to deploy by setting this variable. If no value is set, the chart's appVersion is used.", - "type": "string" - }, - "helm-values.ingressShim": { - "additionalProperties": false, - "properties": { - "defaultIssuerGroup": { - "$ref": "#/$defs/helm-values.ingressShim.defaultIssuerGroup" - }, - "defaultIssuerKind": { - "$ref": "#/$defs/helm-values.ingressShim.defaultIssuerKind" - }, - "defaultIssuerName": { - "$ref": "#/$defs/helm-values.ingressShim.defaultIssuerName" - } - }, - "type": "object" - }, - "helm-values.ingressShim.defaultIssuerGroup": { - "description": "Optional default issuer group to use for ingress resources.", - "type": "string" - }, - "helm-values.ingressShim.defaultIssuerKind": { - "description": "Optional default issuer kind to use for ingress resources.", - "type": "string" - }, - "helm-values.ingressShim.defaultIssuerName": { - "description": "Optional default issuer to use for ingress resources.", - "type": "string" - }, - "helm-values.installCRDs": { - "default": false, - "description": "This option is equivalent to setting crds.enabled=true and crds.keep=true. Deprecated: use crds.enabled and crds.keep instead.", - "type": "boolean" - }, - "helm-values.livenessProbe": { - "default": { - "enabled": true, - "failureThreshold": 8, - "initialDelaySeconds": 10, - "periodSeconds": 10, - "successThreshold": 1, - "timeoutSeconds": 15 - }, - "description": "LivenessProbe settings for the controller container of the controller Pod.\n\nThis is enabled by default, in order to enable the clock-skew liveness probe that restarts the controller in case of a skew between the system clock and the monotonic clock. LivenessProbe durations and thresholds are based on those used for the Kubernetes controller-manager. For more information see the following on the\n[Kubernetes GitHub repository](https://github.com/kubernetes/kubernetes/blob/806b30170c61a38fedd54cc9ede4cd6275a1ad3b/cmd/kubeadm/app/util/staticpod/utils.go#L241-L245)", - "type": "object" - }, - "helm-values.maxConcurrentChallenges": { - "default": 60, - "description": "The maximum number of challenges that can be scheduled as 'processing' at once.", - "type": "number" - }, - "helm-values.nameOverride": { - "description": "Override the \"cert-manager.name\" value, which is used to annotate some of the resources that are created by this Chart (using \"app.kubernetes.io/name\"). NOTE: There are some inconsistencies in the Helm chart when it comes to these annotations (some resources use eg. \"cainjector.name\" which resolves to the value \"cainjector\").", - "type": "string" - }, - "helm-values.namespace": { - "default": "", - "description": "This namespace allows you to define where the services are installed into. If not set then they use the namespace of the release. This is helpful when installing cert manager as a chart dependency (sub chart).", - "type": "string" - }, - "helm-values.no_proxy": { - "description": "Configures the NO_PROXY environment variable where a HTTP proxy is required, but certain domains should be excluded.", - "type": "string" - }, - "helm-values.nodeSelector": { - "default": { - "kubernetes.io/os": "linux" - }, - "description": "The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with matching labels. For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/).\n\nThis default ensures that Pods are only scheduled to Linux nodes. It prevents Pods being scheduled to Windows nodes in a mixed OS cluster.", - "type": "object" - }, - "helm-values.podAnnotations": { - "description": "Optional additional annotations to add to the controller Pods.", - "type": "object" - }, - "helm-values.podDisruptionBudget": { - "additionalProperties": false, - "properties": { - "enabled": { - "$ref": "#/$defs/helm-values.podDisruptionBudget.enabled" - }, - "maxUnavailable": { - "$ref": "#/$defs/helm-values.podDisruptionBudget.maxUnavailable" - }, - "minAvailable": { - "$ref": "#/$defs/helm-values.podDisruptionBudget.minAvailable" - } - }, - "type": "object" - }, - "helm-values.podDisruptionBudget.enabled": { - "default": false, - "description": "Enable or disable the PodDisruptionBudget resource.\n\nThis prevents downtime during voluntary disruptions such as during a Node upgrade. For example, the PodDisruptionBudget will block `kubectl drain` if it is used on the Node where the only remaining cert-manager\nPod is currently running.", - "type": "boolean" - }, - "helm-values.podDisruptionBudget.maxUnavailable": { - "description": "This configures the maximum unavailable pods for disruptions. It can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%). it cannot be used if `minAvailable` is set." - }, - "helm-values.podDisruptionBudget.minAvailable": { - "description": "This configures the minimum available pods for disruptions. It can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%).\nIt cannot be used if `maxUnavailable` is set." - }, - "helm-values.podDnsConfig": { - "description": "Pod DNS configuration. The podDnsConfig field is optional and can work with any podDnsPolicy settings. However, when a Pod's dnsPolicy is set to \"None\", the dnsConfig field has to be specified. For more information, see [Pod's DNS Config](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config).", - "type": "object" - }, - "helm-values.podDnsPolicy": { - "description": "Pod DNS policy.\nFor more information, see [Pod's DNS Policy](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy).", - "type": "string" - }, - "helm-values.podLabels": { - "default": {}, - "description": "Optional additional labels to add to the controller Pods.", - "type": "object" - }, - "helm-values.prometheus": { - "additionalProperties": false, - "properties": { - "enabled": { - "$ref": "#/$defs/helm-values.prometheus.enabled" - }, - "podmonitor": { - "$ref": "#/$defs/helm-values.prometheus.podmonitor" - }, - "servicemonitor": { - "$ref": "#/$defs/helm-values.prometheus.servicemonitor" - } - }, - "type": "object" - }, - "helm-values.prometheus.enabled": { - "default": true, - "description": "Enable Prometheus monitoring for the cert-manager controller and webhook. If you use the Prometheus Operator, set prometheus.podmonitor.enabled or prometheus.servicemonitor.enabled, to create a PodMonitor or a\nServiceMonitor resource.\nOtherwise, 'prometheus.io' annotations are added to the cert-manager and cert-manager-webhook Deployments. Note that you can not enable both PodMonitor and ServiceMonitor as they are mutually exclusive. Enabling both will result in an error.", - "type": "boolean" - }, - "helm-values.prometheus.podmonitor": { - "additionalProperties": false, - "properties": { - "annotations": { - "$ref": "#/$defs/helm-values.prometheus.podmonitor.annotations" - }, - "enabled": { - "$ref": "#/$defs/helm-values.prometheus.podmonitor.enabled" - }, - "endpointAdditionalProperties": { - "$ref": "#/$defs/helm-values.prometheus.podmonitor.endpointAdditionalProperties" - }, - "honorLabels": { - "$ref": "#/$defs/helm-values.prometheus.podmonitor.honorLabels" - }, - "interval": { - "$ref": "#/$defs/helm-values.prometheus.podmonitor.interval" - }, - "labels": { - "$ref": "#/$defs/helm-values.prometheus.podmonitor.labels" - }, - "namespace": { - "$ref": "#/$defs/helm-values.prometheus.podmonitor.namespace" - }, - "path": { - "$ref": "#/$defs/helm-values.prometheus.podmonitor.path" - }, - "prometheusInstance": { - "$ref": "#/$defs/helm-values.prometheus.podmonitor.prometheusInstance" - }, - "scrapeTimeout": { - "$ref": "#/$defs/helm-values.prometheus.podmonitor.scrapeTimeout" - } - }, - "type": "object" - }, - "helm-values.prometheus.podmonitor.annotations": { - "default": {}, - "description": "Additional annotations to add to the PodMonitor.", - "type": "object" - }, - "helm-values.prometheus.podmonitor.enabled": { - "default": false, - "description": "Create a PodMonitor to add cert-manager to Prometheus.", - "type": "boolean" - }, - "helm-values.prometheus.podmonitor.endpointAdditionalProperties": { - "default": {}, - "description": "EndpointAdditionalProperties allows setting additional properties on the endpoint such as relabelings, metricRelabelings etc.\n\nFor example:\nendpointAdditionalProperties:\n relabelings:\n - action: replace\n sourceLabels:\n - __meta_kubernetes_pod_node_name\n targetLabel: instance\n # Configure the PodMonitor for TLS connections\n # See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls\n scheme: https\n tlsConfig:\n serverName: cert-manager-metrics\n ca:\n secret:\n name: cert-manager-metrics-ca\n key: \"tls.crt\"", - "type": "object" - }, - "helm-values.prometheus.podmonitor.honorLabels": { - "default": false, - "description": "Keep labels from scraped data, overriding server-side labels.", - "type": "boolean" - }, - "helm-values.prometheus.podmonitor.interval": { - "default": "60s", - "description": "The interval to scrape metrics.", - "type": "string" - }, - "helm-values.prometheus.podmonitor.labels": { - "default": {}, - "description": "Additional labels to add to the PodMonitor.", - "type": "object" - }, - "helm-values.prometheus.podmonitor.namespace": { - "description": "The namespace that the pod monitor should live in, defaults to the cert-manager namespace.", - "type": "string" - }, - "helm-values.prometheus.podmonitor.path": { - "default": "/metrics", - "description": "The path to scrape for metrics.", - "type": "string" - }, - "helm-values.prometheus.podmonitor.prometheusInstance": { - "default": "default", - "description": "Specifies the `prometheus` label on the created PodMonitor. This is used when different Prometheus instances have label selectors matching different PodMonitors.", - "type": "string" - }, - "helm-values.prometheus.podmonitor.scrapeTimeout": { - "default": "30s", - "description": "The timeout before a metrics scrape fails.", - "type": "string" - }, - "helm-values.prometheus.servicemonitor": { - "additionalProperties": false, - "properties": { - "annotations": { - "$ref": "#/$defs/helm-values.prometheus.servicemonitor.annotations" - }, - "enabled": { - "$ref": "#/$defs/helm-values.prometheus.servicemonitor.enabled" - }, - "endpointAdditionalProperties": { - "$ref": "#/$defs/helm-values.prometheus.servicemonitor.endpointAdditionalProperties" - }, - "honorLabels": { - "$ref": "#/$defs/helm-values.prometheus.servicemonitor.honorLabels" - }, - "interval": { - "$ref": "#/$defs/helm-values.prometheus.servicemonitor.interval" - }, - "labels": { - "$ref": "#/$defs/helm-values.prometheus.servicemonitor.labels" - }, - "namespace": { - "$ref": "#/$defs/helm-values.prometheus.servicemonitor.namespace" - }, - "path": { - "$ref": "#/$defs/helm-values.prometheus.servicemonitor.path" - }, - "prometheusInstance": { - "$ref": "#/$defs/helm-values.prometheus.servicemonitor.prometheusInstance" - }, - "scrapeTimeout": { - "$ref": "#/$defs/helm-values.prometheus.servicemonitor.scrapeTimeout" - }, - "targetPort": { - "$ref": "#/$defs/helm-values.prometheus.servicemonitor.targetPort" - } - }, - "type": "object" - }, - "helm-values.prometheus.servicemonitor.annotations": { - "default": {}, - "description": "Additional annotations to add to the ServiceMonitor.", - "type": "object" - }, - "helm-values.prometheus.servicemonitor.enabled": { - "default": false, - "description": "Create a ServiceMonitor to add cert-manager to Prometheus.", - "type": "boolean" - }, - "helm-values.prometheus.servicemonitor.endpointAdditionalProperties": { - "default": {}, - "description": "EndpointAdditionalProperties allows setting additional properties on the endpoint such as relabelings, metricRelabelings etc.\n\nFor example:\nendpointAdditionalProperties:\n relabelings:\n - action: replace\n sourceLabels:\n - __meta_kubernetes_pod_node_name\n targetLabel: instance", - "type": "object" - }, - "helm-values.prometheus.servicemonitor.honorLabels": { - "default": false, - "description": "Keep labels from scraped data, overriding server-side labels.", - "type": "boolean" - }, - "helm-values.prometheus.servicemonitor.interval": { - "default": "60s", - "description": "The interval to scrape metrics.", - "type": "string" - }, - "helm-values.prometheus.servicemonitor.labels": { - "default": {}, - "description": "Additional labels to add to the ServiceMonitor.", - "type": "object" - }, - "helm-values.prometheus.servicemonitor.namespace": { - "description": "The namespace that the service monitor should live in, defaults to the cert-manager namespace.", - "type": "string" - }, - "helm-values.prometheus.servicemonitor.path": { - "default": "/metrics", - "description": "The path to scrape for metrics.", - "type": "string" - }, - "helm-values.prometheus.servicemonitor.prometheusInstance": { - "default": "default", - "description": "Specifies the `prometheus` label on the created ServiceMonitor. This is used when different Prometheus instances have label selectors matching different ServiceMonitors.", - "type": "string" - }, - "helm-values.prometheus.servicemonitor.scrapeTimeout": { - "default": "30s", - "description": "The timeout before a metrics scrape fails.", - "type": "string" - }, - "helm-values.prometheus.servicemonitor.targetPort": { - "default": 9402, - "description": "The target port to set on the ServiceMonitor. This must match the port that the cert-manager controller is listening on for metrics.", - "type": "number" - }, - "helm-values.replicaCount": { - "default": 1, - "description": "The number of replicas of the cert-manager controller to run.\n\nThe default is 1, but in production set this to 2 or 3 to provide high availability.\n\nIf `replicas > 1`, consider setting `podDisruptionBudget.enabled=true`.\n\nNote that cert-manager uses leader election to ensure that there can only be a single instance active at a time.", - "type": "number" - }, - "helm-values.resources": { - "default": {}, - "description": "Resources to provide to the cert-manager controller pod.\n\nFor example:\nrequests:\n cpu: 10m\n memory: 32Mi\nFor more information, see [Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/).", - "type": "object" - }, - "helm-values.securityContext": { - "default": { - "runAsNonRoot": true, - "seccompProfile": { - "type": "RuntimeDefault" - } - }, - "description": "Pod Security Context.\nFor more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/).", - "type": "object" - }, - "helm-values.serviceAccount": { - "additionalProperties": false, - "properties": { - "annotations": { - "$ref": "#/$defs/helm-values.serviceAccount.annotations" - }, - "automountServiceAccountToken": { - "$ref": "#/$defs/helm-values.serviceAccount.automountServiceAccountToken" - }, - "create": { - "$ref": "#/$defs/helm-values.serviceAccount.create" - }, - "labels": { - "$ref": "#/$defs/helm-values.serviceAccount.labels" - }, - "name": { - "$ref": "#/$defs/helm-values.serviceAccount.name" - } - }, - "type": "object" - }, - "helm-values.serviceAccount.annotations": { - "description": "Optional additional annotations to add to the controller's Service Account.", - "type": "object" - }, - "helm-values.serviceAccount.automountServiceAccountToken": { - "default": true, - "description": "Automount API credentials for a Service Account.", - "type": "boolean" - }, - "helm-values.serviceAccount.create": { - "default": true, - "description": "Specifies whether a service account should be created.", - "type": "boolean" - }, - "helm-values.serviceAccount.labels": { - "description": "Optional additional labels to add to the controller's Service Account.", - "type": "object" - }, - "helm-values.serviceAccount.name": { - "description": "The name of the service account to use.\nIf not set and create is true, a name is generated using the fullname template.", - "type": "string" - }, - "helm-values.serviceAnnotations": { - "description": "Optional annotations to add to the controller Service.", - "type": "object" - }, - "helm-values.serviceIPFamilies": { - "description": "Optionally set the IP families for the controller Service that should be supported, in the order in which they should be applied to ClusterIP. Can be IPv4 and/or IPv6.", - "items": {}, - "type": "array" - }, - "helm-values.serviceIPFamilyPolicy": { - "description": "Optionally set the IP family policy for the controller Service to configure dual-stack; see [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services).", - "type": "string" - }, - "helm-values.serviceLabels": { - "description": "Optional additional labels to add to the controller Service.", - "type": "object" - }, - "helm-values.startupapicheck": { - "additionalProperties": false, - "properties": { - "affinity": { - "$ref": "#/$defs/helm-values.startupapicheck.affinity" - }, - "automountServiceAccountToken": { - "$ref": "#/$defs/helm-values.startupapicheck.automountServiceAccountToken" - }, - "backoffLimit": { - "$ref": "#/$defs/helm-values.startupapicheck.backoffLimit" - }, - "containerSecurityContext": { - "$ref": "#/$defs/helm-values.startupapicheck.containerSecurityContext" - }, - "enableServiceLinks": { - "$ref": "#/$defs/helm-values.startupapicheck.enableServiceLinks" - }, - "enabled": { - "$ref": "#/$defs/helm-values.startupapicheck.enabled" - }, - "extraArgs": { - "$ref": "#/$defs/helm-values.startupapicheck.extraArgs" - }, - "extraEnv": { - "$ref": "#/$defs/helm-values.startupapicheck.extraEnv" - }, - "image": { - "$ref": "#/$defs/helm-values.startupapicheck.image" - }, - "jobAnnotations": { - "$ref": "#/$defs/helm-values.startupapicheck.jobAnnotations" - }, - "nodeSelector": { - "$ref": "#/$defs/helm-values.startupapicheck.nodeSelector" - }, - "podAnnotations": { - "$ref": "#/$defs/helm-values.startupapicheck.podAnnotations" - }, - "podLabels": { - "$ref": "#/$defs/helm-values.startupapicheck.podLabels" - }, - "rbac": { - "$ref": "#/$defs/helm-values.startupapicheck.rbac" - }, - "resources": { - "$ref": "#/$defs/helm-values.startupapicheck.resources" - }, - "securityContext": { - "$ref": "#/$defs/helm-values.startupapicheck.securityContext" - }, - "serviceAccount": { - "$ref": "#/$defs/helm-values.startupapicheck.serviceAccount" - }, - "timeout": { - "$ref": "#/$defs/helm-values.startupapicheck.timeout" - }, - "tolerations": { - "$ref": "#/$defs/helm-values.startupapicheck.tolerations" - }, - "volumeMounts": { - "$ref": "#/$defs/helm-values.startupapicheck.volumeMounts" - }, - "volumes": { - "$ref": "#/$defs/helm-values.startupapicheck.volumes" - } - }, - "type": "object" - }, - "helm-values.startupapicheck.affinity": { - "default": {}, - "description": "A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core).\nFor example:\naffinity:\n nodeAffinity:\n requiredDuringSchedulingIgnoredDuringExecution:\n nodeSelectorTerms:\n - matchExpressions:\n - key: foo.bar.com/role\n operator: In\n values:\n - master", - "type": "object" - }, - "helm-values.startupapicheck.automountServiceAccountToken": { - "description": "Automounting API credentials for a particular pod.", - "type": "boolean" - }, - "helm-values.startupapicheck.backoffLimit": { - "default": 4, - "description": "Job backoffLimit", - "type": "number" - }, - "helm-values.startupapicheck.containerSecurityContext": { - "default": { - "allowPrivilegeEscalation": false, - "capabilities": { - "drop": [ - "ALL" - ] - }, - "readOnlyRootFilesystem": true - }, - "description": "Container Security Context to be set on the controller component container. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/).", - "type": "object" - }, - "helm-values.startupapicheck.enableServiceLinks": { - "default": false, - "description": "enableServiceLinks indicates whether information about services should be injected into pod's environment variables, matching the syntax of Docker links.", - "type": "boolean" - }, - "helm-values.startupapicheck.enabled": { - "default": true, - "description": "Enables the startup api check.", - "type": "boolean" - }, - "helm-values.startupapicheck.extraArgs": { - "default": [ - "-v" - ], - "description": "Additional command line flags to pass to startupapicheck binary. To see all available flags run `docker run quay.io/jetstack/cert-manager-startupapicheck: --help`.\n\nVerbose logging is enabled by default so that if startupapicheck fails, you can know what exactly caused the failure. Verbose logs include details of the webhook URL, IP address and TCP connect errors for example.", - "items": {}, - "type": "array" - }, - "helm-values.startupapicheck.extraEnv": { - "default": [], - "description": "Additional environment variables to pass to cert-manager startupapicheck binary.\nFor example:\nextraEnv:\n- name: SOME_VAR\n value: 'some value'", - "items": {}, - "type": "array" - }, - "helm-values.startupapicheck.image": { - "additionalProperties": false, - "properties": { - "digest": { - "$ref": "#/$defs/helm-values.startupapicheck.image.digest" - }, - "pullPolicy": { - "$ref": "#/$defs/helm-values.startupapicheck.image.pullPolicy" - }, - "registry": { - "$ref": "#/$defs/helm-values.startupapicheck.image.registry" - }, - "repository": { - "$ref": "#/$defs/helm-values.startupapicheck.image.repository" - }, - "tag": { - "$ref": "#/$defs/helm-values.startupapicheck.image.tag" - } - }, - "type": "object" - }, - "helm-values.startupapicheck.image.digest": { - "description": "Setting a digest will override any tag.", - "type": "string" - }, - "helm-values.startupapicheck.image.pullPolicy": { - "default": "IfNotPresent", - "description": "Kubernetes imagePullPolicy on Deployment.", - "type": "string" - }, - "helm-values.startupapicheck.image.registry": { - "description": "The container registry to pull the startupapicheck image from.", - "type": "string" - }, - "helm-values.startupapicheck.image.repository": { - "default": "quay.io/jetstack/cert-manager-startupapicheck", - "description": "The container image for the cert-manager startupapicheck.", - "type": "string" - }, - "helm-values.startupapicheck.image.tag": { - "description": "Override the image tag to deploy by setting this variable. If no value is set, the chart's appVersion is used.", - "type": "string" - }, - "helm-values.startupapicheck.jobAnnotations": { - "default": { - "helm.sh/hook": "post-install", - "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded", - "helm.sh/hook-weight": "1" - }, - "description": "Optional additional annotations to add to the startupapicheck Job.", - "type": "object" - }, - "helm-values.startupapicheck.nodeSelector": { - "default": { - "kubernetes.io/os": "linux" - }, - "description": "The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with matching labels. For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/).\n\nThis default ensures that Pods are only scheduled to Linux nodes. It prevents Pods being scheduled to Windows nodes in a mixed OS cluster.", - "type": "object" - }, - "helm-values.startupapicheck.podAnnotations": { - "description": "Optional additional annotations to add to the startupapicheck Pods.", - "type": "object" - }, - "helm-values.startupapicheck.podLabels": { - "default": {}, - "description": "Optional additional labels to add to the startupapicheck Pods.", - "type": "object" - }, - "helm-values.startupapicheck.rbac": { - "additionalProperties": false, - "properties": { - "annotations": { - "$ref": "#/$defs/helm-values.startupapicheck.rbac.annotations" - } - }, - "type": "object" - }, - "helm-values.startupapicheck.rbac.annotations": { - "default": { - "helm.sh/hook": "post-install", - "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded", - "helm.sh/hook-weight": "-5" - }, - "description": "annotations for the startup API Check job RBAC and PSP resources.", - "type": "object" - }, - "helm-values.startupapicheck.resources": { - "default": {}, - "description": "Resources to provide to the cert-manager controller pod.\n\nFor example:\nrequests:\n cpu: 10m\n memory: 32Mi\nFor more information, see [Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/).", - "type": "object" - }, - "helm-values.startupapicheck.securityContext": { - "default": { - "runAsNonRoot": true, - "seccompProfile": { - "type": "RuntimeDefault" - } - }, - "description": "Pod Security Context to be set on the startupapicheck component Pod. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/).", - "type": "object" - }, - "helm-values.startupapicheck.serviceAccount": { - "additionalProperties": false, - "properties": { - "annotations": { - "$ref": "#/$defs/helm-values.startupapicheck.serviceAccount.annotations" - }, - "automountServiceAccountToken": { - "$ref": "#/$defs/helm-values.startupapicheck.serviceAccount.automountServiceAccountToken" - }, - "create": { - "$ref": "#/$defs/helm-values.startupapicheck.serviceAccount.create" - }, - "labels": { - "$ref": "#/$defs/helm-values.startupapicheck.serviceAccount.labels" - }, - "name": { - "$ref": "#/$defs/helm-values.startupapicheck.serviceAccount.name" - } - }, - "type": "object" - }, - "helm-values.startupapicheck.serviceAccount.annotations": { - "default": { - "helm.sh/hook": "post-install", - "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded", - "helm.sh/hook-weight": "-5" - }, - "description": "Optional additional annotations to add to the Job's Service Account.", - "type": "object" - }, - "helm-values.startupapicheck.serviceAccount.automountServiceAccountToken": { - "default": true, - "description": "Automount API credentials for a Service Account.", - "type": "boolean" - }, - "helm-values.startupapicheck.serviceAccount.create": { - "default": true, - "description": "Specifies whether a service account should be created.", - "type": "boolean" - }, - "helm-values.startupapicheck.serviceAccount.labels": { - "description": "Optional additional labels to add to the startupapicheck's Service Account.", - "type": "object" - }, - "helm-values.startupapicheck.serviceAccount.name": { - "description": "The name of the service account to use.\nIf not set and create is true, a name is generated using the fullname template.", - "type": "string" - }, - "helm-values.startupapicheck.timeout": { - "default": "1m", - "description": "Timeout for 'kubectl check api' command.", - "type": "string" - }, - "helm-values.startupapicheck.tolerations": { - "default": [], - "description": "A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core).\n\nFor example:\ntolerations:\n- key: foo.bar.com/role\n operator: Equal\n value: master\n effect: NoSchedule", - "items": {}, - "type": "array" - }, - "helm-values.startupapicheck.volumeMounts": { - "default": [], - "description": "Additional volume mounts to add to the cert-manager controller container.", - "items": {}, - "type": "array" - }, - "helm-values.startupapicheck.volumes": { - "default": [], - "description": "Additional volumes to add to the cert-manager controller pod.", - "items": {}, - "type": "array" - }, - "helm-values.strategy": { - "default": {}, - "description": "Deployment update strategy for the cert-manager controller deployment. For more information, see the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy).\n\nFor example:\nstrategy:\n type: RollingUpdate\n rollingUpdate:\n maxSurge: 0\n maxUnavailable: 1", - "type": "object" - }, - "helm-values.tolerations": { - "default": [], - "description": "A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core).\n\nFor example:\ntolerations:\n- key: foo.bar.com/role\n operator: Equal\n value: master\n effect: NoSchedule", - "items": {}, - "type": "array" - }, - "helm-values.topologySpreadConstraints": { - "default": [], - "description": "A list of Kubernetes TopologySpreadConstraints, if required. For more information, see [Topology spread constraint v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#topologyspreadconstraint-v1-core\n\nFor example:\ntopologySpreadConstraints:\n- maxSkew: 2\n topologyKey: topology.kubernetes.io/zone\n whenUnsatisfiable: ScheduleAnyway\n labelSelector:\n matchLabels:\n app.kubernetes.io/instance: cert-manager\n app.kubernetes.io/component: controller", - "items": {}, - "type": "array" - }, - "helm-values.volumeMounts": { - "default": [], - "description": "Additional volume mounts to add to the cert-manager controller container.", - "items": {}, - "type": "array" - }, - "helm-values.volumes": { - "default": [], - "description": "Additional volumes to add to the cert-manager controller pod.", - "items": {}, - "type": "array" - }, - "helm-values.webhook": { - "additionalProperties": false, - "properties": { - "affinity": { - "$ref": "#/$defs/helm-values.webhook.affinity" - }, - "automountServiceAccountToken": { - "$ref": "#/$defs/helm-values.webhook.automountServiceAccountToken" - }, - "config": { - "$ref": "#/$defs/helm-values.webhook.config" - }, - "containerSecurityContext": { - "$ref": "#/$defs/helm-values.webhook.containerSecurityContext" - }, - "deploymentAnnotations": { - "$ref": "#/$defs/helm-values.webhook.deploymentAnnotations" - }, - "enableServiceLinks": { - "$ref": "#/$defs/helm-values.webhook.enableServiceLinks" - }, - "extraArgs": { - "$ref": "#/$defs/helm-values.webhook.extraArgs" - }, - "extraEnv": { - "$ref": "#/$defs/helm-values.webhook.extraEnv" - }, - "featureGates": { - "$ref": "#/$defs/helm-values.webhook.featureGates" - }, - "hostNetwork": { - "$ref": "#/$defs/helm-values.webhook.hostNetwork" - }, - "image": { - "$ref": "#/$defs/helm-values.webhook.image" - }, - "livenessProbe": { - "$ref": "#/$defs/helm-values.webhook.livenessProbe" - }, - "loadBalancerIP": { - "$ref": "#/$defs/helm-values.webhook.loadBalancerIP" - }, - "mutatingWebhookConfiguration": { - "$ref": "#/$defs/helm-values.webhook.mutatingWebhookConfiguration" - }, - "mutatingWebhookConfigurationAnnotations": { - "$ref": "#/$defs/helm-values.webhook.mutatingWebhookConfigurationAnnotations" - }, - "networkPolicy": { - "$ref": "#/$defs/helm-values.webhook.networkPolicy" - }, - "nodeSelector": { - "$ref": "#/$defs/helm-values.webhook.nodeSelector" - }, - "podAnnotations": { - "$ref": "#/$defs/helm-values.webhook.podAnnotations" - }, - "podDisruptionBudget": { - "$ref": "#/$defs/helm-values.webhook.podDisruptionBudget" - }, - "podLabels": { - "$ref": "#/$defs/helm-values.webhook.podLabels" - }, - "readinessProbe": { - "$ref": "#/$defs/helm-values.webhook.readinessProbe" - }, - "replicaCount": { - "$ref": "#/$defs/helm-values.webhook.replicaCount" - }, - "resources": { - "$ref": "#/$defs/helm-values.webhook.resources" - }, - "securePort": { - "$ref": "#/$defs/helm-values.webhook.securePort" - }, - "securityContext": { - "$ref": "#/$defs/helm-values.webhook.securityContext" - }, - "serviceAccount": { - "$ref": "#/$defs/helm-values.webhook.serviceAccount" - }, - "serviceAnnotations": { - "$ref": "#/$defs/helm-values.webhook.serviceAnnotations" - }, - "serviceIPFamilies": { - "$ref": "#/$defs/helm-values.webhook.serviceIPFamilies" - }, - "serviceIPFamilyPolicy": { - "$ref": "#/$defs/helm-values.webhook.serviceIPFamilyPolicy" - }, - "serviceLabels": { - "$ref": "#/$defs/helm-values.webhook.serviceLabels" - }, - "serviceType": { - "$ref": "#/$defs/helm-values.webhook.serviceType" - }, - "strategy": { - "$ref": "#/$defs/helm-values.webhook.strategy" - }, - "timeoutSeconds": { - "$ref": "#/$defs/helm-values.webhook.timeoutSeconds" - }, - "tolerations": { - "$ref": "#/$defs/helm-values.webhook.tolerations" - }, - "topologySpreadConstraints": { - "$ref": "#/$defs/helm-values.webhook.topologySpreadConstraints" - }, - "url": { - "$ref": "#/$defs/helm-values.webhook.url" - }, - "validatingWebhookConfiguration": { - "$ref": "#/$defs/helm-values.webhook.validatingWebhookConfiguration" - }, - "validatingWebhookConfigurationAnnotations": { - "$ref": "#/$defs/helm-values.webhook.validatingWebhookConfigurationAnnotations" - }, - "volumeMounts": { - "$ref": "#/$defs/helm-values.webhook.volumeMounts" - }, - "volumes": { - "$ref": "#/$defs/helm-values.webhook.volumes" - } - }, - "type": "object" - }, - "helm-values.webhook.affinity": { - "default": {}, - "description": "A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core).\n\nFor example:\naffinity:\n nodeAffinity:\n requiredDuringSchedulingIgnoredDuringExecution:\n nodeSelectorTerms:\n - matchExpressions:\n - key: foo.bar.com/role\n operator: In\n values:\n - master", - "type": "object" - }, - "helm-values.webhook.automountServiceAccountToken": { - "description": "Automounting API credentials for a particular pod.", - "type": "boolean" - }, - "helm-values.webhook.config": { - "default": {}, - "description": "This is used to configure options for the webhook 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 `webhook.config.cert-manager.io/v1alpha1`). You can pin the version by specifying the `apiVersion` yourself.\n\nFor example:\napiVersion: webhook.config.cert-manager.io/v1alpha1\nkind: WebhookConfiguration\n# The port that the webhook listens on for requests.\n# In GKE private clusters, by default Kubernetes apiservers are allowed to\n# talk to the cluster nodes only on 443 and 10250. Configuring\n# securePort: 10250 therefore will work out-of-the-box without needing to add firewall\n# rules or requiring NET_BIND_SERVICE capabilities to bind port numbers < 1000.\n# This should be uncommented and set as a default by the chart once\n# the apiVersion of WebhookConfiguration graduates beyond v1alpha1.\nsecurePort: 10250\n# Configure the metrics server for TLS\n# See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls\nmetricsTLSConfig:\n dynamic:\n secretNamespace: \"cert-manager\"\n secretName: \"cert-manager-metrics-ca\"\n dnsNames:\n - cert-manager-metrics", - "type": "object" - }, - "helm-values.webhook.containerSecurityContext": { - "default": { - "allowPrivilegeEscalation": false, - "capabilities": { - "drop": [ - "ALL" - ] - }, - "readOnlyRootFilesystem": true - }, - "description": "Container Security Context to be set on the webhook component container. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/).", - "type": "object" - }, - "helm-values.webhook.deploymentAnnotations": { - "description": "Optional additional annotations to add to the webhook Deployment.", - "type": "object" - }, - "helm-values.webhook.enableServiceLinks": { - "default": false, - "description": "enableServiceLinks indicates whether information about services should be injected into the pod's environment variables, matching the syntax of Docker links.", - "type": "boolean" - }, - "helm-values.webhook.extraArgs": { - "default": [], - "description": "Additional command line flags to pass to cert-manager webhook binary. To see all available flags run `docker run quay.io/jetstack/cert-manager-webhook: --help`.", - "items": {}, - "type": "array" - }, - "helm-values.webhook.extraEnv": { - "default": [], - "description": "Additional environment variables to pass to cert-manager webhook binary.\nFor example:\nextraEnv:\n- name: SOME_VAR\n value: 'some value'", - "items": {}, - "type": "array" - }, - "helm-values.webhook.featureGates": { - "default": "", - "description": "Comma separated list of feature gates that should be enabled on the webhook pod.", - "type": "string" - }, - "helm-values.webhook.hostNetwork": { - "default": false, - "description": "Specifies if the webhook should be started in hostNetwork mode.\n\nRequired for use in some managed kubernetes clusters (such as AWS EKS) with custom. CNI (such as calico), because control-plane managed by AWS cannot communicate with pods' IP CIDR and admission webhooks are not working\n\nSince the default port for the webhook conflicts with kubelet on the host network, `webhook.securePort` should be changed to an available port if running in hostNetwork mode.", - "type": "boolean" - }, - "helm-values.webhook.image": { - "additionalProperties": false, - "properties": { - "digest": { - "$ref": "#/$defs/helm-values.webhook.image.digest" - }, - "pullPolicy": { - "$ref": "#/$defs/helm-values.webhook.image.pullPolicy" - }, - "registry": { - "$ref": "#/$defs/helm-values.webhook.image.registry" - }, - "repository": { - "$ref": "#/$defs/helm-values.webhook.image.repository" - }, - "tag": { - "$ref": "#/$defs/helm-values.webhook.image.tag" - } - }, - "type": "object" - }, - "helm-values.webhook.image.digest": { - "description": "Setting a digest will override any tag", - "type": "string" - }, - "helm-values.webhook.image.pullPolicy": { - "default": "IfNotPresent", - "description": "Kubernetes imagePullPolicy on Deployment.", - "type": "string" - }, - "helm-values.webhook.image.registry": { - "description": "The container registry to pull the webhook image from.", - "type": "string" - }, - "helm-values.webhook.image.repository": { - "default": "quay.io/jetstack/cert-manager-webhook", - "description": "The container image for the cert-manager webhook", - "type": "string" - }, - "helm-values.webhook.image.tag": { - "description": "Override the image tag to deploy by setting this variable. If no value is set, the chart's appVersion will be used.", - "type": "string" - }, - "helm-values.webhook.livenessProbe": { - "default": { - "failureThreshold": 3, - "initialDelaySeconds": 60, - "periodSeconds": 10, - "successThreshold": 1, - "timeoutSeconds": 1 - }, - "description": "Liveness probe values.\nFor more information, see [Container probes](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes).", - "type": "object" - }, - "helm-values.webhook.loadBalancerIP": { - "description": "Specify the load balancer IP for the created service.", - "type": "string" - }, - "helm-values.webhook.mutatingWebhookConfiguration": { - "additionalProperties": false, - "properties": { - "namespaceSelector": { - "$ref": "#/$defs/helm-values.webhook.mutatingWebhookConfiguration.namespaceSelector" - } - }, - "type": "object" - }, - "helm-values.webhook.mutatingWebhookConfiguration.namespaceSelector": { - "default": {}, - "description": "Configure spec.namespaceSelector for mutating webhooks.", - "type": "object" - }, - "helm-values.webhook.mutatingWebhookConfigurationAnnotations": { - "description": "Optional additional annotations to add to the webhook MutatingWebhookConfiguration.", - "type": "object" - }, - "helm-values.webhook.networkPolicy": { - "additionalProperties": false, - "properties": { - "egress": { - "$ref": "#/$defs/helm-values.webhook.networkPolicy.egress" - }, - "enabled": { - "$ref": "#/$defs/helm-values.webhook.networkPolicy.enabled" - }, - "ingress": { - "$ref": "#/$defs/helm-values.webhook.networkPolicy.ingress" - } - }, - "type": "object" - }, - "helm-values.webhook.networkPolicy.egress": { - "default": [ - { - "ports": [ - { - "port": 80, - "protocol": "TCP" - }, - { - "port": 443, - "protocol": "TCP" - }, - { - "port": 53, - "protocol": "TCP" - }, - { - "port": 53, - "protocol": "UDP" - }, - { - "port": 6443, - "protocol": "TCP" - } - ], - "to": [ - { - "ipBlock": { - "cidr": "0.0.0.0/0" - } - } - ] - } - ], - "description": "Egress rule for the webhook network policy. By default, it allows all outbound traffic to ports 80 and 443, as well as DNS ports.", - "items": {}, - "type": "array" - }, - "helm-values.webhook.networkPolicy.enabled": { - "default": false, - "description": "Create network policies for the webhooks.", - "type": "boolean" - }, - "helm-values.webhook.networkPolicy.ingress": { - "default": [ - { - "from": [ - { - "ipBlock": { - "cidr": "0.0.0.0/0" - } - } - ] - } - ], - "description": "Ingress rule for the webhook network policy. By default, it allows all inbound traffic.", - "items": {}, - "type": "array" - }, - "helm-values.webhook.nodeSelector": { - "default": { - "kubernetes.io/os": "linux" - }, - "description": "The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with matching labels. For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/).\n\nThis default ensures that Pods are only scheduled to Linux nodes. It prevents Pods being scheduled to Windows nodes in a mixed OS cluster.", - "type": "object" - }, - "helm-values.webhook.podAnnotations": { - "description": "Optional additional annotations to add to the webhook Pods.", - "type": "object" - }, - "helm-values.webhook.podDisruptionBudget": { - "additionalProperties": false, - "properties": { - "enabled": { - "$ref": "#/$defs/helm-values.webhook.podDisruptionBudget.enabled" - }, - "maxUnavailable": { - "$ref": "#/$defs/helm-values.webhook.podDisruptionBudget.maxUnavailable" - }, - "minAvailable": { - "$ref": "#/$defs/helm-values.webhook.podDisruptionBudget.minAvailable" - } - }, - "type": "object" - }, - "helm-values.webhook.podDisruptionBudget.enabled": { - "default": false, - "description": "Enable or disable the PodDisruptionBudget resource.\n\nThis prevents downtime during voluntary disruptions such as during a Node upgrade. For example, the PodDisruptionBudget will block `kubectl drain` if it is used on the Node where the only remaining cert-manager\nPod is currently running.", - "type": "boolean" - }, - "helm-values.webhook.podDisruptionBudget.maxUnavailable": { - "description": "This property configures the maximum unavailable pods for disruptions. Can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%).\nIt cannot be used if `minAvailable` is set." - }, - "helm-values.webhook.podDisruptionBudget.minAvailable": { - "description": "This property configures the minimum available pods for disruptions. Can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%).\nIt cannot be used if `maxUnavailable` is set." - }, - "helm-values.webhook.podLabels": { - "default": {}, - "description": "Optional additional labels to add to the Webhook Pods.", - "type": "object" - }, - "helm-values.webhook.readinessProbe": { - "default": { - "failureThreshold": 3, - "initialDelaySeconds": 5, - "periodSeconds": 5, - "successThreshold": 1, - "timeoutSeconds": 1 - }, - "description": "Readiness probe values.\nFor more information, see [Container probes](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes).", - "type": "object" - }, - "helm-values.webhook.replicaCount": { - "default": 1, - "description": "Number of replicas of the cert-manager webhook to run.\n\nThe default is 1, but in production set this to 2 or 3 to provide high availability.\n\nIf `replicas > 1`, consider setting `webhook.podDisruptionBudget.enabled=true`.", - "type": "number" - }, - "helm-values.webhook.resources": { - "default": {}, - "description": "Resources to provide to the cert-manager webhook pod.\n\nFor example:\nrequests:\n cpu: 10m\n memory: 32Mi\nFor more information, see [Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/).", - "type": "object" - }, - "helm-values.webhook.securePort": { - "default": 10250, - "description": "The port that the webhook listens on for requests. In GKE private clusters, by default Kubernetes apiservers are allowed to talk to the cluster nodes only on 443 and 10250. Configuring securePort: 10250, therefore will work out-of-the-box without needing to add firewall rules or requiring NET_BIND_SERVICE capabilities to bind port numbers <1000.", - "type": "number" - }, - "helm-values.webhook.securityContext": { - "default": { - "runAsNonRoot": true, - "seccompProfile": { - "type": "RuntimeDefault" - } - }, - "description": "Pod Security Context to be set on the webhook component Pod. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/).", - "type": "object" - }, - "helm-values.webhook.serviceAccount": { - "additionalProperties": false, - "properties": { - "annotations": { - "$ref": "#/$defs/helm-values.webhook.serviceAccount.annotations" - }, - "automountServiceAccountToken": { - "$ref": "#/$defs/helm-values.webhook.serviceAccount.automountServiceAccountToken" - }, - "create": { - "$ref": "#/$defs/helm-values.webhook.serviceAccount.create" - }, - "labels": { - "$ref": "#/$defs/helm-values.webhook.serviceAccount.labels" - }, - "name": { - "$ref": "#/$defs/helm-values.webhook.serviceAccount.name" - } - }, - "type": "object" - }, - "helm-values.webhook.serviceAccount.annotations": { - "description": "Optional additional annotations to add to the webhook's Service Account.", - "type": "object" - }, - "helm-values.webhook.serviceAccount.automountServiceAccountToken": { - "default": true, - "description": "Automount API credentials for a Service Account.", - "type": "boolean" - }, - "helm-values.webhook.serviceAccount.create": { - "default": true, - "description": "Specifies whether a service account should be created.", - "type": "boolean" - }, - "helm-values.webhook.serviceAccount.labels": { - "description": "Optional additional labels to add to the webhook's Service Account.", - "type": "object" - }, - "helm-values.webhook.serviceAccount.name": { - "description": "The name of the service account to use.\nIf not set and create is true, a name is generated using the fullname template.", - "type": "string" - }, - "helm-values.webhook.serviceAnnotations": { - "description": "Optional additional annotations to add to the webhook Service.", - "type": "object" - }, - "helm-values.webhook.serviceIPFamilies": { - "default": [], - "description": "Optionally set the IP families for the controller Service that should be supported, in the order in which they should be applied to ClusterIP. Can be IPv4 and/or IPv6.", - "items": {}, - "type": "array" - }, - "helm-values.webhook.serviceIPFamilyPolicy": { - "default": "", - "description": "Optionally set the IP family policy for the controller Service to configure dual-stack; see [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services).", - "type": "string" - }, - "helm-values.webhook.serviceLabels": { - "default": {}, - "description": "Optional additional labels to add to the Webhook Service.", - "type": "object" - }, - "helm-values.webhook.serviceType": { - "default": "ClusterIP", - "description": "Specifies how the service should be handled. Useful if you want to expose the webhook outside of the cluster. In some cases, the control plane cannot reach internal services.", - "type": "string" - }, - "helm-values.webhook.strategy": { - "default": {}, - "description": "The update strategy for the cert-manager webhook deployment. For more information, see the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy)\n\nFor example:\nstrategy:\n type: RollingUpdate\n rollingUpdate:\n maxSurge: 0\n maxUnavailable: 1", - "type": "object" - }, - "helm-values.webhook.timeoutSeconds": { - "default": 30, - "description": "The number of seconds the API server should wait for the webhook to respond before treating the call as a failure. The value must be between 1 and 30 seconds. For more information, see\n[Validating webhook configuration v1](https://kubernetes.io/docs/reference/kubernetes-api/extend-resources/validating-webhook-configuration-v1/).\n\nThe default is set to the maximum value of 30 seconds as users sometimes report that the connection between the K8S API server and the cert-manager webhook server times out. If *this* timeout is reached, the error message will be \"context deadline exceeded\", which doesn't help the user diagnose what phase of the HTTPS connection timed out. For example, it could be during DNS resolution, TCP connection, TLS negotiation, HTTP negotiation, or slow HTTP response from the webhook server. By setting this timeout to its maximum value the underlying timeout error message has more chance of being returned to the end user.", - "type": "number" - }, - "helm-values.webhook.tolerations": { - "default": [], - "description": "A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core).\n\nFor example:\ntolerations:\n- key: foo.bar.com/role\n operator: Equal\n value: master\n effect: NoSchedule", - "items": {}, - "type": "array" - }, - "helm-values.webhook.topologySpreadConstraints": { - "default": [], - "description": "A list of Kubernetes TopologySpreadConstraints, if required. For more information, see [Topology spread constraint v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#topologyspreadconstraint-v1-core).\n\nFor example:\ntopologySpreadConstraints:\n- maxSkew: 2\n topologyKey: topology.kubernetes.io/zone\n whenUnsatisfiable: ScheduleAnyway\n labelSelector:\n matchLabels:\n app.kubernetes.io/instance: cert-manager\n app.kubernetes.io/component: controller", - "items": {}, - "type": "array" - }, - "helm-values.webhook.url": { - "default": {}, - "description": "Overrides the mutating webhook and validating webhook so they reach the webhook service using the `url` field instead of a service.", - "type": "object" - }, - "helm-values.webhook.validatingWebhookConfiguration": { - "additionalProperties": false, - "properties": { - "namespaceSelector": { - "$ref": "#/$defs/helm-values.webhook.validatingWebhookConfiguration.namespaceSelector" - } - }, - "type": "object" - }, - "helm-values.webhook.validatingWebhookConfiguration.namespaceSelector": { - "default": { - "matchExpressions": [ - { - "key": "cert-manager.io/disable-validation", - "operator": "NotIn", - "values": [ - "true" - ] - } - ] - }, - "description": "Configure spec.namespaceSelector for validating webhooks.", - "type": "object" - }, - "helm-values.webhook.validatingWebhookConfigurationAnnotations": { - "description": "Optional additional annotations to add to the webhook ValidatingWebhookConfiguration.", - "type": "object" - }, - "helm-values.webhook.volumeMounts": { - "default": [], - "description": "Additional volume mounts to add to the cert-manager controller container.", - "items": {}, - "type": "array" - }, - "helm-values.webhook.volumes": { - "default": [], - "description": "Additional volumes to add to the cert-manager controller pod.", - "items": {}, - "type": "array" - } - }, - "$ref": "#/$defs/helm-values", - "$schema": "http://json-schema.org/draft-07/schema#" -} diff --git a/packages/system/cert-manager-crds/charts/cert-manager/values.yaml b/packages/system/cert-manager-crds/charts/cert-manager/values.yaml deleted file mode 100644 index 7a1c2953..00000000 --- a/packages/system/cert-manager-crds/charts/cert-manager/values.yaml +++ /dev/null @@ -1,1455 +0,0 @@ -# +docs:section=Global - -# Default values for cert-manager. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. -global: - # Reference to one or more secrets to be used when pulling images. - # For more information, see [Pull an Image from a Private Registry](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/). - # - # For example: - # imagePullSecrets: - # - name: "image-pull-secret" - imagePullSecrets: [] - - # Labels to apply to all resources. - # Please note that this does not add labels to the resources created dynamically by the controllers. - # For these resources, you have to add the labels in the template in the cert-manager custom resource: - # For example, podTemplate/ ingressTemplate in ACMEChallengeSolverHTTP01Ingress - # For more information, see the [cert-manager documentation](https://cert-manager.io/docs/reference/api-docs/#acme.cert-manager.io/v1.ACMEChallengeSolverHTTP01Ingress). - # For example, secretTemplate in CertificateSpec - # For more information, see the [cert-manager documentation](https://cert-manager.io/docs/reference/api-docs/#cert-manager.io/v1.CertificateSpec). - commonLabels: {} - - # The number of old ReplicaSets to retain to allow rollback (if not set, the default Kubernetes value is set to 10). - # +docs:property - # revisionHistoryLimit: 1 - - # The optional priority class to be used for the cert-manager pods. - priorityClassName: "" - - rbac: - # Create required ClusterRoles and ClusterRoleBindings for cert-manager. - create: true - # Aggregate ClusterRoles to Kubernetes default user-facing roles. For more information, see [User-facing roles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) - aggregateClusterRoles: true - - podSecurityPolicy: - # Create PodSecurityPolicy for cert-manager. - # - # Note that PodSecurityPolicy was deprecated in Kubernetes 1.21 and removed in Kubernetes 1.25. - enabled: false - # Configure the PodSecurityPolicy to use AppArmor. - useAppArmor: true - - # Set the verbosity of cert-manager. A range of 0 - 6, with 6 being the most verbose. - logLevel: 2 - - leaderElection: - # Override the namespace used for the leader election lease. - namespace: "kube-system" - - # The duration that non-leader candidates will wait after observing a - # leadership renewal until attempting to acquire leadership of a led but - # unrenewed leader slot. This is effectively the maximum duration that a - # leader can be stopped before it is replaced by another candidate. - # +docs:property - # leaseDuration: 60s - - # The interval between attempts by the acting master to renew a leadership - # slot before it stops leading. This must be less than or equal to the - # lease duration. - # +docs:property - # renewDeadline: 40s - - # The duration the clients should wait between attempting acquisition and - # renewal of a leadership. - # +docs:property - # retryPeriod: 15s - -# This option is equivalent to setting crds.enabled=true and crds.keep=true. -# Deprecated: use crds.enabled and crds.keep instead. -installCRDs: false - -crds: - # This option decides if the CRDs should be installed - # as part of the Helm installation. - enabled: false - - # This option makes it so that the "helm.sh/resource-policy": keep - # annotation is added to the CRD. This will prevent Helm from uninstalling - # the CRD when the Helm release is uninstalled. - # WARNING: when the CRDs are removed, all cert-manager custom resources - # (Certificates, Issuers, ...) will be removed too by the garbage collector. - keep: true - -# +docs:section=Controller - -# The number of replicas of the cert-manager controller to run. -# -# The default is 1, but in production set this to 2 or 3 to provide high -# availability. -# -# If `replicas > 1`, consider setting `podDisruptionBudget.enabled=true`. -# -# Note that cert-manager uses leader election to ensure that there can -# only be a single instance active at a time. -replicaCount: 1 - -# Deployment update strategy for the cert-manager controller deployment. -# For more information, see the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy). -# -# For example: -# strategy: -# type: RollingUpdate -# rollingUpdate: -# maxSurge: 0 -# maxUnavailable: 1 -strategy: {} - -podDisruptionBudget: - # Enable or disable the PodDisruptionBudget resource. - # - # This prevents downtime during voluntary disruptions such as during a Node upgrade. - # For example, the PodDisruptionBudget will block `kubectl drain` - # if it is used on the Node where the only remaining cert-manager - # Pod is currently running. - enabled: false - - # This configures the minimum available pods for disruptions. It can either be set to - # an integer (e.g. 1) or a percentage value (e.g. 25%). - # It cannot be used if `maxUnavailable` is set. - # +docs:property - # +docs:type=unknown - # minAvailable: 1 - - # This configures the maximum unavailable pods for disruptions. It can either be set to - # an integer (e.g. 1) or a percentage value (e.g. 25%). - # it cannot be used if `minAvailable` is set. - # +docs:property - # +docs:type=unknown - # maxUnavailable: 1 - -# A comma-separated list of feature gates that should be enabled on the -# controller pod. -featureGates: "" - -# The maximum number of challenges that can be scheduled as 'processing' at once. -maxConcurrentChallenges: 60 - -image: - # The container registry to pull the manager image from. - # +docs:property - # registry: quay.io - - # The container image for the cert-manager controller. - # +docs:property - repository: quay.io/jetstack/cert-manager-controller - - # Override the image tag to deploy by setting this variable. - # If no value is set, the chart's appVersion is used. - # +docs:property - # tag: vX.Y.Z - - # Setting a digest will override any tag. - # +docs:property - # digest: sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20 - - # Kubernetes imagePullPolicy on Deployment. - pullPolicy: IfNotPresent - -# Override the namespace used to store DNS provider credentials etc. for ClusterIssuer -# resources. By default, the same namespace as cert-manager is deployed within is -# used. This namespace will not be automatically created by the Helm chart. -clusterResourceNamespace: "" - -# This namespace allows you to define where the services are installed into. -# If not set then they use the namespace of the release. -# This is helpful when installing cert manager as a chart dependency (sub chart). -namespace: "" - -# Override the "cert-manager.fullname" value. This value is used as part of -# most of the names of the resources created by this Helm chart. -# +docs:property -# fullnameOverride: "my-cert-manager" - -# Override the "cert-manager.name" value, which is used to annotate some of -# the resources that are created by this Chart (using "app.kubernetes.io/name"). -# NOTE: There are some inconsistencies in the Helm chart when it comes to -# these annotations (some resources use eg. "cainjector.name" which resolves -# to the value "cainjector"). -# +docs:property -# nameOverride: "my-cert-manager" - -serviceAccount: - # Specifies whether a service account should be created. - create: true - - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template. - # +docs:property - # name: "" - - # Optional additional annotations to add to the controller's Service Account. - # +docs:property - # annotations: {} - - # Optional additional labels to add to the controller's Service Account. - # +docs:property - # labels: {} - - # Automount API credentials for a Service Account. - automountServiceAccountToken: true - -# Automounting API credentials for a particular pod. -# +docs:property -# automountServiceAccountToken: true - -# When this flag is enabled, secrets will be automatically removed when the certificate resource is deleted. -enableCertificateOwnerRef: false - -# This property is used to configure options for the controller pod. -# This allows setting options that would usually be provided using flags. -# -# If `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. -# -# For example: -# config: -# apiVersion: controller.config.cert-manager.io/v1alpha1 -# kind: ControllerConfiguration -# logging: -# verbosity: 2 -# format: text -# leaderElectionConfig: -# namespace: kube-system -# kubernetesAPIQPS: 9000 -# kubernetesAPIBurst: 9000 -# numberOfConcurrentWorkers: 200 -# featureGates: -# AdditionalCertificateOutputFormats: true -# DisallowInsecureCSRUsageDefinition: true -# ExperimentalCertificateSigningRequestControllers: true -# ExperimentalGatewayAPISupport: true -# LiteralCertificateSubject: true -# SecretsFilteredCaching: true -# ServerSideApply: true -# StableCertificateRequestName: true -# UseCertificateRequestBasicConstraints: true -# ValidateCAA: true -# # Configure the metrics server for TLS -# # See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls -# metricsTLSConfig: -# dynamic: -# secretNamespace: "cert-manager" -# secretName: "cert-manager-metrics-ca" -# dnsNames: -# - cert-manager-metrics -config: {} - -# Setting Nameservers for DNS01 Self Check. -# For more information, see the [cert-manager documentation](https://cert-manager.io/docs/configuration/acme/dns01/#setting-nameservers-for-dns01-self-check). - -# A comma-separated string with the host and port of the recursive nameservers cert-manager should query. -dns01RecursiveNameservers: "" - -# Forces cert-manager to use only the recursive nameservers for verification. -# Enabling this option could cause the DNS01 self check to take longer owing to caching performed by the recursive nameservers. -dns01RecursiveNameserversOnly: false - -# Option to disable cert-manager's build-in auto-approver. The auto-approver -# approves all CertificateRequests that reference issuers matching the 'approveSignerNames' -# option. This 'disableAutoApproval' option is useful when you want to make all approval decisions -# using a different approver (like approver-policy - https://github.com/cert-manager/approver-policy). -disableAutoApproval: false - -# List of signer names that cert-manager will approve by default. CertificateRequests -# referencing these signer names will be auto-approved by cert-manager. Defaults to just -# approving the cert-manager.io Issuer and ClusterIssuer issuers. When set to an empty -# array, ALL issuers will be auto-approved by cert-manager. To disable the auto-approval, -# because eg. you are using approver-policy, you can enable 'disableAutoApproval'. -# ref: https://cert-manager.io/docs/concepts/certificaterequest/#approval -# +docs:property -approveSignerNames: -- issuers.cert-manager.io/* -- clusterissuers.cert-manager.io/* - -# Additional command line flags to pass to cert-manager controller binary. -# To see all available flags run `docker run quay.io/jetstack/cert-manager-controller: --help`. -# -# Use this flag to enable or disable arbitrary controllers. For example, to disable the CertificateRequests approver. -# -# For example: -# extraArgs: -# - --controllers=*,-certificaterequests-approver -extraArgs: [] - -# Additional environment variables to pass to cert-manager controller binary. -# For example: -# extraEnv: -# - name: SOME_VAR -# value: 'some value' -extraEnv: [] - -# Resources to provide to the cert-manager controller pod. -# -# For example: -# requests: -# cpu: 10m -# memory: 32Mi -# -# For more information, see [Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). -resources: {} - -# Pod Security Context. -# For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). -# +docs:property -securityContext: - runAsNonRoot: true - seccompProfile: - type: RuntimeDefault - -# Container Security Context to be set on the controller component container. -# For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). -# +docs:property -containerSecurityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - readOnlyRootFilesystem: true - -# Additional volumes to add to the cert-manager controller pod. -volumes: [] - -# Additional volume mounts to add to the cert-manager controller container. -volumeMounts: [] - -# Optional additional annotations to add to the controller Deployment. -# +docs:property -# deploymentAnnotations: {} - -# Optional additional annotations to add to the controller Pods. -# +docs:property -# podAnnotations: {} - -# Optional additional labels to add to the controller Pods. -podLabels: {} - -# Optional annotations to add to the controller Service. -# +docs:property -# serviceAnnotations: {} - -# Optional additional labels to add to the controller Service. -# +docs:property -# serviceLabels: {} - -# Optionally set the IP family policy for the controller Service to configure dual-stack; see [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services). -# +docs:property -# serviceIPFamilyPolicy: "" - -# Optionally set the IP families for the controller Service that should be supported, in the order in which they should be applied to ClusterIP. Can be IPv4 and/or IPv6. -# +docs:property -# serviceIPFamilies: [] - -# Optional DNS settings. These are useful if you have a public and private DNS zone for -# the same domain on Route 53. The following is an example of ensuring -# cert-manager can access an ingress or DNS TXT records at all times. -# Note that this requires Kubernetes 1.10 or `CustomPodDNS` feature gate enabled for -# the cluster to work. - -# Pod DNS policy. -# For more information, see [Pod's DNS Policy](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy). -# +docs:property -# podDnsPolicy: "None" - -# Pod DNS configuration. The podDnsConfig field is optional and can work with any podDnsPolicy -# settings. However, when a Pod's dnsPolicy is set to "None", the dnsConfig field has to be specified. -# For more information, see [Pod's DNS Config](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config). -# +docs:property -# podDnsConfig: -# nameservers: -# - "1.1.1.1" -# - "8.8.8.8" - -# Optional hostAliases for cert-manager-controller pods. May be useful when performing ACME DNS-01 self checks. -hostAliases: [] -# - ip: 127.0.0.1 -# hostnames: -# - foo.local -# - bar.local -# - ip: 10.1.2.3 -# hostnames: -# - foo.remote -# - bar.remote - -# The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with -# matching labels. -# For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). -# -# This default ensures that Pods are only scheduled to Linux nodes. -# It prevents Pods being scheduled to Windows nodes in a mixed OS cluster. -# +docs:property -nodeSelector: - kubernetes.io/os: linux - -# +docs:ignore -ingressShim: {} - - # Optional default issuer to use for ingress resources. - # +docs:property=ingressShim.defaultIssuerName - # defaultIssuerName: "" - - # Optional default issuer kind to use for ingress resources. - # +docs:property=ingressShim.defaultIssuerKind - # defaultIssuerKind: "" - - # Optional default issuer group to use for ingress resources. - # +docs:property=ingressShim.defaultIssuerGroup - # defaultIssuerGroup: "" - -# Use these variables to configure the HTTP_PROXY environment variables. - -# Configures the HTTP_PROXY environment variable where a HTTP proxy is required. -# +docs:property -# http_proxy: "http://proxy:8080" - -# Configures the HTTPS_PROXY environment variable where a HTTP proxy is required. -# +docs:property -# https_proxy: "https://proxy:8080" - -# Configures the NO_PROXY environment variable where a HTTP proxy is required, -# but certain domains should be excluded. -# +docs:property -# no_proxy: 127.0.0.1,localhost - - -# A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core). -# -# For example: -# affinity: -# nodeAffinity: -# requiredDuringSchedulingIgnoredDuringExecution: -# nodeSelectorTerms: -# - matchExpressions: -# - key: foo.bar.com/role -# operator: In -# values: -# - master -affinity: {} - -# A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core). -# -# For example: -# tolerations: -# - key: foo.bar.com/role -# operator: Equal -# value: master -# effect: NoSchedule -tolerations: [] - -# A list of Kubernetes TopologySpreadConstraints, if required. For more information, see [Topology spread constraint v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#topologyspreadconstraint-v1-core -# -# For example: -# topologySpreadConstraints: -# - maxSkew: 2 -# topologyKey: topology.kubernetes.io/zone -# whenUnsatisfiable: ScheduleAnyway -# labelSelector: -# matchLabels: -# app.kubernetes.io/instance: cert-manager -# app.kubernetes.io/component: controller -topologySpreadConstraints: [] - -# LivenessProbe settings for the controller container of the controller Pod. -# -# This is enabled by default, in order to enable the clock-skew liveness probe that -# restarts the controller in case of a skew between the system clock and the monotonic clock. -# LivenessProbe durations and thresholds are based on those used for the Kubernetes -# controller-manager. For more information see the following on the -# [Kubernetes GitHub repository](https://github.com/kubernetes/kubernetes/blob/806b30170c61a38fedd54cc9ede4cd6275a1ad3b/cmd/kubeadm/app/util/staticpod/utils.go#L241-L245) -# +docs:property -livenessProbe: - enabled: true - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 15 - successThreshold: 1 - failureThreshold: 8 - -# enableServiceLinks indicates whether information about services should be -# injected into the pod's environment variables, matching the syntax of Docker -# links. -enableServiceLinks: false - -# +docs:section=Prometheus - -prometheus: - # Enable Prometheus monitoring for the cert-manager controller and webhook. - # If you use the Prometheus Operator, set prometheus.podmonitor.enabled or - # prometheus.servicemonitor.enabled, to create a PodMonitor or a - # ServiceMonitor resource. - # Otherwise, 'prometheus.io' annotations are added to the cert-manager and - # cert-manager-webhook Deployments. - # Note that you can not enable both PodMonitor and ServiceMonitor as they are - # mutually exclusive. Enabling both will result in an error. - enabled: true - - servicemonitor: - # Create a ServiceMonitor to add cert-manager to Prometheus. - enabled: false - - # The namespace that the service monitor should live in, defaults - # to the cert-manager namespace. - # +docs:property - # namespace: cert-manager - - # Specifies the `prometheus` label on the created ServiceMonitor. This is - # used when different Prometheus instances have label selectors matching - # different ServiceMonitors. - prometheusInstance: default - - # The target port to set on the ServiceMonitor. This must match the port that the - # cert-manager controller is listening on for metrics. - targetPort: 9402 - - # The path to scrape for metrics. - path: /metrics - - # The interval to scrape metrics. - interval: 60s - - # The timeout before a metrics scrape fails. - scrapeTimeout: 30s - - # Additional labels to add to the ServiceMonitor. - labels: {} - - # Additional annotations to add to the ServiceMonitor. - annotations: {} - - # Keep labels from scraped data, overriding server-side labels. - honorLabels: false - - # EndpointAdditionalProperties allows setting additional properties on the - # endpoint such as relabelings, metricRelabelings etc. - # - # For example: - # endpointAdditionalProperties: - # relabelings: - # - action: replace - # sourceLabels: - # - __meta_kubernetes_pod_node_name - # targetLabel: instance - # - # +docs:property - endpointAdditionalProperties: {} - - # Note that you can not enable both PodMonitor and ServiceMonitor as they are mutually exclusive. Enabling both will result in an error. - podmonitor: - # Create a PodMonitor to add cert-manager to Prometheus. - enabled: false - - # The namespace that the pod monitor should live in, defaults - # to the cert-manager namespace. - # +docs:property - # namespace: cert-manager - - # Specifies the `prometheus` label on the created PodMonitor. This is - # used when different Prometheus instances have label selectors matching - # different PodMonitors. - prometheusInstance: default - - # The path to scrape for metrics. - path: /metrics - - # The interval to scrape metrics. - interval: 60s - - # The timeout before a metrics scrape fails. - scrapeTimeout: 30s - - # Additional labels to add to the PodMonitor. - labels: {} - - # Additional annotations to add to the PodMonitor. - annotations: {} - - # Keep labels from scraped data, overriding server-side labels. - honorLabels: false - - # EndpointAdditionalProperties allows setting additional properties on the - # endpoint such as relabelings, metricRelabelings etc. - # - # For example: - # endpointAdditionalProperties: - # relabelings: - # - action: replace - # sourceLabels: - # - __meta_kubernetes_pod_node_name - # targetLabel: instance - # # Configure the PodMonitor for TLS connections - # # See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls - # scheme: https - # tlsConfig: - # serverName: cert-manager-metrics - # ca: - # secret: - # name: cert-manager-metrics-ca - # key: "tls.crt" - # - # +docs:property - endpointAdditionalProperties: {} - -# +docs:section=Webhook - -webhook: - # Number of replicas of the cert-manager webhook to run. - # - # The default is 1, but in production set this to 2 or 3 to provide high - # availability. - # - # If `replicas > 1`, consider setting `webhook.podDisruptionBudget.enabled=true`. - replicaCount: 1 - - # The number of seconds the API server should wait for the webhook to respond before treating the call as a failure. - # The value must be between 1 and 30 seconds. For more information, see - # [Validating webhook configuration v1](https://kubernetes.io/docs/reference/kubernetes-api/extend-resources/validating-webhook-configuration-v1/). - # - # The default is set to the maximum value of 30 seconds as - # users sometimes report that the connection between the K8S API server and - # the cert-manager webhook server times out. - # If *this* timeout is reached, the error message will be "context deadline exceeded", - # which doesn't help the user diagnose what phase of the HTTPS connection timed out. - # For example, it could be during DNS resolution, TCP connection, TLS - # negotiation, HTTP negotiation, or slow HTTP response from the webhook - # server. - # By setting this timeout to its maximum value the underlying timeout error - # message has more chance of being returned to the end user. - timeoutSeconds: 30 - - # This is used to configure options for the webhook pod. - # This allows setting options that would usually be provided using flags. - # - # If `apiVersion` and `kind` are unspecified they default to the current latest - # version (currently `webhook.config.cert-manager.io/v1alpha1`). You can pin - # the version by specifying the `apiVersion` yourself. - # - # For example: - # apiVersion: webhook.config.cert-manager.io/v1alpha1 - # kind: WebhookConfiguration - # # The port that the webhook listens on for requests. - # # In GKE private clusters, by default Kubernetes apiservers are allowed to - # # talk to the cluster nodes only on 443 and 10250. Configuring - # # securePort: 10250 therefore will work out-of-the-box without needing to add firewall - # # rules or requiring NET_BIND_SERVICE capabilities to bind port numbers < 1000. - # # This should be uncommented and set as a default by the chart once - # # the apiVersion of WebhookConfiguration graduates beyond v1alpha1. - # securePort: 10250 - # # Configure the metrics server for TLS - # # See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls - # metricsTLSConfig: - # dynamic: - # secretNamespace: "cert-manager" - # secretName: "cert-manager-metrics-ca" - # dnsNames: - # - cert-manager-metrics - config: {} - - # The update strategy for the cert-manager webhook deployment. - # For more information, see the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy) - # - # For example: - # strategy: - # type: RollingUpdate - # rollingUpdate: - # maxSurge: 0 - # maxUnavailable: 1 - strategy: {} - - # Pod Security Context to be set on the webhook component Pod. - # For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). - # +docs:property - securityContext: - runAsNonRoot: true - seccompProfile: - type: RuntimeDefault - - # Container Security Context to be set on the webhook component container. - # For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). - # +docs:property - containerSecurityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - readOnlyRootFilesystem: true - - podDisruptionBudget: - # Enable or disable the PodDisruptionBudget resource. - # - # This prevents downtime during voluntary disruptions such as during a Node upgrade. - # For example, the PodDisruptionBudget will block `kubectl drain` - # if it is used on the Node where the only remaining cert-manager - # Pod is currently running. - enabled: false - - # This property configures the minimum available pods for disruptions. Can either be set to - # an integer (e.g. 1) or a percentage value (e.g. 25%). - # It cannot be used if `maxUnavailable` is set. - # +docs:property - # +docs:type=unknown - # minAvailable: 1 - - # This property configures the maximum unavailable pods for disruptions. Can either be set to - # an integer (e.g. 1) or a percentage value (e.g. 25%). - # It cannot be used if `minAvailable` is set. - # +docs:property - # +docs:type=unknown - # maxUnavailable: 1 - - # Optional additional annotations to add to the webhook Deployment. - # +docs:property - # deploymentAnnotations: {} - - # Optional additional annotations to add to the webhook Pods. - # +docs:property - # podAnnotations: {} - - # Optional additional annotations to add to the webhook Service. - # +docs:property - # serviceAnnotations: {} - - # Optional additional annotations to add to the webhook MutatingWebhookConfiguration. - # +docs:property - # mutatingWebhookConfigurationAnnotations: {} - - # Optional additional annotations to add to the webhook ValidatingWebhookConfiguration. - # +docs:property - # validatingWebhookConfigurationAnnotations: {} - - validatingWebhookConfiguration: - # Configure spec.namespaceSelector for validating webhooks. - # +docs:property - namespaceSelector: - matchExpressions: - - key: "cert-manager.io/disable-validation" - operator: "NotIn" - values: - - "true" - - mutatingWebhookConfiguration: - # Configure spec.namespaceSelector for mutating webhooks. - # +docs:property - namespaceSelector: {} - # matchLabels: - # key: value - # matchExpressions: - # - key: kubernetes.io/metadata.name - # operator: NotIn - # values: - # - kube-system - - - # Additional command line flags to pass to cert-manager webhook binary. - # To see all available flags run `docker run quay.io/jetstack/cert-manager-webhook: --help`. - extraArgs: [] - # Path to a file containing a WebhookConfiguration object used to configure the webhook. - # - --config= - - # Additional environment variables to pass to cert-manager webhook binary. - # For example: - # extraEnv: - # - name: SOME_VAR - # value: 'some value' - extraEnv: [] - - # Comma separated list of feature gates that should be enabled on the - # webhook pod. - featureGates: "" - - # Resources to provide to the cert-manager webhook pod. - # - # For example: - # requests: - # cpu: 10m - # memory: 32Mi - # - # For more information, see [Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). - resources: {} - - # Liveness probe values. - # For more information, see [Container probes](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes). - # - # +docs:property - livenessProbe: - failureThreshold: 3 - initialDelaySeconds: 60 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 1 - - # Readiness probe values. - # For more information, see [Container probes](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes). - # - # +docs:property - readinessProbe: - failureThreshold: 3 - initialDelaySeconds: 5 - periodSeconds: 5 - successThreshold: 1 - timeoutSeconds: 1 - - # The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with - # matching labels. - # For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). - # - # This default ensures that Pods are only scheduled to Linux nodes. - # It prevents Pods being scheduled to Windows nodes in a mixed OS cluster. - # +docs:property - nodeSelector: - kubernetes.io/os: linux - - # A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core). - # - # For example: - # affinity: - # nodeAffinity: - # requiredDuringSchedulingIgnoredDuringExecution: - # nodeSelectorTerms: - # - matchExpressions: - # - key: foo.bar.com/role - # operator: In - # values: - # - master - affinity: {} - - # A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core). - # - # For example: - # tolerations: - # - key: foo.bar.com/role - # operator: Equal - # value: master - # effect: NoSchedule - tolerations: [] - - # A list of Kubernetes TopologySpreadConstraints, if required. For more information, see [Topology spread constraint v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#topologyspreadconstraint-v1-core). - # - # For example: - # topologySpreadConstraints: - # - maxSkew: 2 - # topologyKey: topology.kubernetes.io/zone - # whenUnsatisfiable: ScheduleAnyway - # labelSelector: - # matchLabels: - # app.kubernetes.io/instance: cert-manager - # app.kubernetes.io/component: controller - topologySpreadConstraints: [] - - # Optional additional labels to add to the Webhook Pods. - podLabels: {} - - # Optional additional labels to add to the Webhook Service. - serviceLabels: {} - - # Optionally set the IP family policy for the controller Service to configure dual-stack; see [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services). - serviceIPFamilyPolicy: "" - - # Optionally set the IP families for the controller Service that should be supported, in the order in which they should be applied to ClusterIP. Can be IPv4 and/or IPv6. - serviceIPFamilies: [] - - image: - # The container registry to pull the webhook image from. - # +docs:property - # registry: quay.io - - # The container image for the cert-manager webhook - # +docs:property - repository: quay.io/jetstack/cert-manager-webhook - - # Override the image tag to deploy by setting this variable. - # If no value is set, the chart's appVersion will be used. - # +docs:property - # tag: vX.Y.Z - - # Setting a digest will override any tag - # +docs:property - # digest: sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20 - - # Kubernetes imagePullPolicy on Deployment. - pullPolicy: IfNotPresent - - serviceAccount: - # Specifies whether a service account should be created. - create: true - - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template. - # +docs:property - # name: "" - - # Optional additional annotations to add to the webhook's Service Account. - # +docs:property - # annotations: {} - - # Optional additional labels to add to the webhook's Service Account. - # +docs:property - # labels: {} - - # Automount API credentials for a Service Account. - automountServiceAccountToken: true - - # Automounting API credentials for a particular pod. - # +docs:property - # automountServiceAccountToken: true - - # The port that the webhook listens on for requests. - # In GKE private clusters, by default Kubernetes apiservers are allowed to - # talk to the cluster nodes only on 443 and 10250. Configuring - # securePort: 10250, therefore will work out-of-the-box without needing to add firewall - # rules or requiring NET_BIND_SERVICE capabilities to bind port numbers <1000. - securePort: 10250 - - # Specifies if the webhook should be started in hostNetwork mode. - # - # Required for use in some managed kubernetes clusters (such as AWS EKS) with custom - # CNI (such as calico), because control-plane managed by AWS cannot communicate - # with pods' IP CIDR and admission webhooks are not working - # - # Since the default port for the webhook conflicts with kubelet on the host - # network, `webhook.securePort` should be changed to an available port if - # running in hostNetwork mode. - hostNetwork: false - - # Specifies how the service should be handled. Useful if you want to expose the - # webhook outside of the cluster. In some cases, the control plane cannot - # reach internal services. - serviceType: ClusterIP - - # Specify the load balancer IP for the created service. - # +docs:property - # loadBalancerIP: "10.10.10.10" - - # Overrides the mutating webhook and validating webhook so they reach the webhook - # service using the `url` field instead of a service. - url: {} - # host: - - # Enables default network policies for webhooks. - networkPolicy: - # Create network policies for the webhooks. - enabled: false - - # Ingress rule for the webhook network policy. By default, it allows all - # inbound traffic. - # +docs:property - ingress: - - from: - - ipBlock: - cidr: 0.0.0.0/0 - - # Egress rule for the webhook network policy. By default, it allows all - # outbound traffic to ports 80 and 443, as well as DNS ports. - # +docs:property - egress: - - ports: - - port: 80 - protocol: TCP - - port: 443 - protocol: TCP - - port: 53 - protocol: TCP - - port: 53 - protocol: UDP - # On OpenShift and OKD, the Kubernetes API server listens on. - # port 6443. - - port: 6443 - protocol: TCP - to: - - ipBlock: - cidr: 0.0.0.0/0 - - # Additional volumes to add to the cert-manager controller pod. - volumes: [] - - # Additional volume mounts to add to the cert-manager controller container. - volumeMounts: [] - - # enableServiceLinks indicates whether information about services should be - # injected into the pod's environment variables, matching the syntax of Docker - # links. - enableServiceLinks: false - -# +docs:section=CA Injector - -cainjector: - # Create the CA Injector deployment - enabled: true - - # The number of replicas of the cert-manager cainjector to run. - # - # The default is 1, but in production set this to 2 or 3 to provide high - # availability. - # - # If `replicas > 1`, consider setting `cainjector.podDisruptionBudget.enabled=true`. - # - # Note that cert-manager uses leader election to ensure that there can - # only be a single instance active at a time. - replicaCount: 1 - - # This is used to configure options for the cainjector pod. - # It allows setting options that are usually provided via flags. - # - # If `apiVersion` and `kind` are unspecified they default to the current latest - # version (currently `cainjector.config.cert-manager.io/v1alpha1`). You can pin - # the version by specifying the `apiVersion` yourself. - # - # For example: - # apiVersion: cainjector.config.cert-manager.io/v1alpha1 - # kind: CAInjectorConfiguration - # logging: - # verbosity: 2 - # format: text - # leaderElectionConfig: - # namespace: kube-system - # # Configure the metrics server for TLS - # # See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls - # metricsTLSConfig: - # dynamic: - # secretNamespace: "cert-manager" - # secretName: "cert-manager-metrics-ca" - # dnsNames: - # - cert-manager-metrics - config: {} - - # Deployment update strategy for the cert-manager cainjector deployment. - # For more information, see the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy). - # - # For example: - # strategy: - # type: RollingUpdate - # rollingUpdate: - # maxSurge: 0 - # maxUnavailable: 1 - strategy: {} - - # Pod Security Context to be set on the cainjector component Pod - # For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). - # +docs:property - securityContext: - runAsNonRoot: true - seccompProfile: - type: RuntimeDefault - - # Container Security Context to be set on the cainjector component container - # For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). - # +docs:property - containerSecurityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - readOnlyRootFilesystem: true - - podDisruptionBudget: - # Enable or disable the PodDisruptionBudget resource. - # - # This prevents downtime during voluntary disruptions such as during a Node upgrade. - # For example, the PodDisruptionBudget will block `kubectl drain` - # if it is used on the Node where the only remaining cert-manager - # Pod is currently running. - enabled: false - - # `minAvailable` configures the minimum available pods for disruptions. It can either be set to - # an integer (e.g. 1) or a percentage value (e.g. 25%). - # Cannot be used if `maxUnavailable` is set. - # +docs:property - # +docs:type=unknown - # minAvailable: 1 - - # `maxUnavailable` configures the maximum unavailable pods for disruptions. It can either be set to - # an integer (e.g. 1) or a percentage value (e.g. 25%). - # Cannot be used if `minAvailable` is set. - # +docs:property - # +docs:type=unknown - # maxUnavailable: 1 - - # Optional additional annotations to add to the cainjector Deployment. - # +docs:property - # deploymentAnnotations: {} - - # Optional additional annotations to add to the cainjector Pods. - # +docs:property - # podAnnotations: {} - - # Optional additional annotations to add to the cainjector metrics Service. - # +docs:property - # serviceAnnotations: {} - - # Additional command line flags to pass to cert-manager cainjector binary. - # To see all available flags run `docker run quay.io/jetstack/cert-manager-cainjector: --help`. - extraArgs: [] - # Enable profiling for cainjector. - # - --enable-profiling=true - - # Additional environment variables to pass to cert-manager cainjector binary. - # For example: - # extraEnv: - # - name: SOME_VAR - # value: 'some value' - extraEnv: [] - - # Comma separated list of feature gates that should be enabled on the - # cainjector pod. - featureGates: "" - - # Resources to provide to the cert-manager cainjector pod. - # - # For example: - # requests: - # cpu: 10m - # memory: 32Mi - # - # For more information, see [Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). - resources: {} - - - # The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with - # matching labels. - # For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). - # - # This default ensures that Pods are only scheduled to Linux nodes. - # It prevents Pods being scheduled to Windows nodes in a mixed OS cluster. - # +docs:property - nodeSelector: - kubernetes.io/os: linux - - # A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core). - # - # For example: - # affinity: - # nodeAffinity: - # requiredDuringSchedulingIgnoredDuringExecution: - # nodeSelectorTerms: - # - matchExpressions: - # - key: foo.bar.com/role - # operator: In - # values: - # - master - affinity: {} - - # A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core). - # - # For example: - # tolerations: - # - key: foo.bar.com/role - # operator: Equal - # value: master - # effect: NoSchedule - tolerations: [] - - # A list of Kubernetes TopologySpreadConstraints, if required. For more information, see [Topology spread constraint v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#topologyspreadconstraint-v1-core). - # - # For example: - # topologySpreadConstraints: - # - maxSkew: 2 - # topologyKey: topology.kubernetes.io/zone - # whenUnsatisfiable: ScheduleAnyway - # labelSelector: - # matchLabels: - # app.kubernetes.io/instance: cert-manager - # app.kubernetes.io/component: controller - topologySpreadConstraints: [] - - # Optional additional labels to add to the CA Injector Pods. - podLabels: {} - - # Optional additional labels to add to the CA Injector metrics Service. - serviceLabels: {} - - image: - # The container registry to pull the cainjector image from. - # +docs:property - # registry: quay.io - - # The container image for the cert-manager cainjector - # +docs:property - repository: quay.io/jetstack/cert-manager-cainjector - - # Override the image tag to deploy by setting this variable. - # If no value is set, the chart's appVersion will be used. - # +docs:property - # tag: vX.Y.Z - - # Setting a digest will override any tag. - # +docs:property - # digest: sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20 - - # Kubernetes imagePullPolicy on Deployment. - pullPolicy: IfNotPresent - - serviceAccount: - # Specifies whether a service account should be created. - create: true - - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - # +docs:property - # name: "" - - # Optional additional annotations to add to the cainjector's Service Account. - # +docs:property - # annotations: {} - - # Optional additional labels to add to the cainjector's Service Account. - # +docs:property - # labels: {} - - # Automount API credentials for a Service Account. - automountServiceAccountToken: true - - # Automounting API credentials for a particular pod. - # +docs:property - # automountServiceAccountToken: true - - # Additional volumes to add to the cert-manager controller pod. - volumes: [] - - # Additional volume mounts to add to the cert-manager controller container. - volumeMounts: [] - - # enableServiceLinks indicates whether information about services should be - # injected into the pod's environment variables, matching the syntax of Docker - # links. - enableServiceLinks: false - -# +docs:section=ACME Solver - -acmesolver: - image: - # The container registry to pull the acmesolver image from. - # +docs:property - # registry: quay.io - - # The container image for the cert-manager acmesolver. - # +docs:property - repository: quay.io/jetstack/cert-manager-acmesolver - - # Override the image tag to deploy by setting this variable. - # If no value is set, the chart's appVersion is used. - # +docs:property - # tag: vX.Y.Z - - # Setting a digest will override any tag. - # +docs:property - # digest: sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20 - - # Kubernetes imagePullPolicy on Deployment. - pullPolicy: IfNotPresent - -# +docs:section=Startup API Check -# This startupapicheck is a Helm post-install hook that waits for the webhook -# endpoints to become available. -# The check is implemented using a Kubernetes Job - if you are injecting mesh -# sidecar proxies into cert-manager pods, ensure that they -# are not injected into this Job's pod. Otherwise, the installation may time out -# owing to the Job never being completed because the sidecar proxy does not exit. -# For more information, see [this note](https://github.com/cert-manager/cert-manager/pull/4414). - -startupapicheck: - # Enables the startup api check. - enabled: true - - # Pod Security Context to be set on the startupapicheck component Pod. - # For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). - # +docs:property - securityContext: - runAsNonRoot: true - seccompProfile: - type: RuntimeDefault - - # Container Security Context to be set on the controller component container. - # For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). - # +docs:property - containerSecurityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - readOnlyRootFilesystem: true - - # Timeout for 'kubectl check api' command. - timeout: 1m - - # Job backoffLimit - backoffLimit: 4 - - # Optional additional annotations to add to the startupapicheck Job. - # +docs:property - jobAnnotations: - helm.sh/hook: post-install - helm.sh/hook-weight: "1" - helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded - - # Optional additional annotations to add to the startupapicheck Pods. - # +docs:property - # podAnnotations: {} - - # Additional command line flags to pass to startupapicheck binary. - # To see all available flags run `docker run quay.io/jetstack/cert-manager-startupapicheck: --help`. - # - # Verbose logging is enabled by default so that if startupapicheck fails, you - # can know what exactly caused the failure. Verbose logs include details of - # the webhook URL, IP address and TCP connect errors for example. - # +docs:property - extraArgs: - - -v - - # Additional environment variables to pass to cert-manager startupapicheck binary. - # For example: - # extraEnv: - # - name: SOME_VAR - # value: 'some value' - extraEnv: [] - - # Resources to provide to the cert-manager controller pod. - # - # For example: - # requests: - # cpu: 10m - # memory: 32Mi - # - # For more information, see [Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). - resources: {} - - - # The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with - # matching labels. - # For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). - # - # This default ensures that Pods are only scheduled to Linux nodes. - # It prevents Pods being scheduled to Windows nodes in a mixed OS cluster. - # +docs:property - nodeSelector: - kubernetes.io/os: linux - - # A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core). - # For example: - # affinity: - # nodeAffinity: - # requiredDuringSchedulingIgnoredDuringExecution: - # nodeSelectorTerms: - # - matchExpressions: - # - key: foo.bar.com/role - # operator: In - # values: - # - master - affinity: {} - - # A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core). - # - # For example: - # tolerations: - # - key: foo.bar.com/role - # operator: Equal - # value: master - # effect: NoSchedule - tolerations: [] - - # Optional additional labels to add to the startupapicheck Pods. - podLabels: {} - - image: - # The container registry to pull the startupapicheck image from. - # +docs:property - # registry: quay.io - - # The container image for the cert-manager startupapicheck. - # +docs:property - repository: quay.io/jetstack/cert-manager-startupapicheck - - # Override the image tag to deploy by setting this variable. - # If no value is set, the chart's appVersion is used. - # +docs:property - # tag: vX.Y.Z - - # Setting a digest will override any tag. - # +docs:property - # digest: sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20 - - # Kubernetes imagePullPolicy on Deployment. - pullPolicy: IfNotPresent - - rbac: - # annotations for the startup API Check job RBAC and PSP resources. - # +docs:property - annotations: - helm.sh/hook: post-install - helm.sh/hook-weight: "-5" - helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded - - # Automounting API credentials for a particular pod. - # +docs:property - # automountServiceAccountToken: true - - serviceAccount: - # Specifies whether a service account should be created. - create: true - - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template. - # +docs:property - # name: "" - - # Optional additional annotations to add to the Job's Service Account. - # +docs:property - annotations: - helm.sh/hook: post-install - helm.sh/hook-weight: "-5" - helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded - - # Automount API credentials for a Service Account. - # +docs:property - automountServiceAccountToken: true - - # Optional additional labels to add to the startupapicheck's Service Account. - # +docs:property - # labels: {} - - # Additional volumes to add to the cert-manager controller pod. - volumes: [] - - # Additional volume mounts to add to the cert-manager controller container. - volumeMounts: [] - - # enableServiceLinks indicates whether information about services should be - # injected into pod's environment variables, matching the syntax of Docker - # links. - enableServiceLinks: false - -# Create dynamic manifests via values. -# -# For example: -# extraObjects: -# - | -# apiVersion: v1 -# kind: ConfigMap -# metadata: -# name: '{{ template "cert-manager.fullname" . }}-extra-configmap' -extraObjects: [] - -# Field used by our release pipeline to produce the static manifests. -# The field defaults to "helm" but is set to "static" when we render -# the static YAML manifests. -# +docs:hidden -creator: "helm" - -# Field that can be used as a condition when cert-manager is a dependency. -# This definition is only here as a placeholder such that it is included in -# the json schema. -# See https://helm.sh/docs/chart_best_practices/dependencies/#conditions-and-tags -# for more info. -# +docs:hidden -enabled: true diff --git a/packages/system/cert-manager-crds/charts/cert-manager/templates/_helpers.tpl b/packages/system/cert-manager-crds/templates/_helpers.tpl similarity index 95% rename from packages/system/cert-manager-crds/charts/cert-manager/templates/_helpers.tpl rename to packages/system/cert-manager-crds/templates/_helpers.tpl index e15fa191..f85373f3 100644 --- a/packages/system/cert-manager-crds/charts/cert-manager/templates/_helpers.tpl +++ b/packages/system/cert-manager-crds/templates/_helpers.tpl @@ -187,6 +187,17 @@ See https://github.com/cert-manager/cert-manager/issues/6329 for a list of linke {{- end }} {{- end }} +{{/* +Labels for the CRD resources. +*/}} +{{- define "cert-manager.crd-labels" -}} +app: "{{ template "cert-manager.name" . }}" +app.kubernetes.io/name: "{{ template "cert-manager.name" . }}" +app.kubernetes.io/instance: "{{ .Release.Name }}" +app.kubernetes.io/component: "crds" +{{ include "labels" . }} +{{- end -}} + {{/* Check that the user has not set both .installCRDs and .crds.enabled or set .installCRDs and disabled .crds.keep. diff --git a/packages/system/cert-manager-crds/templates/crd-acme.cert-manager.io_challenges.yaml b/packages/system/cert-manager-crds/templates/crd-acme.cert-manager.io_challenges.yaml new file mode 100644 index 00000000..5bed0cd8 --- /dev/null +++ b/packages/system/cert-manager-crds/templates/crd-acme.cert-manager.io_challenges.yaml @@ -0,0 +1,3281 @@ +{{- if or .Values.crds.enabled .Values.installCRDs }} +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: "challenges.acme.cert-manager.io" + {{- if .Values.crds.keep }} + annotations: + helm.sh/resource-policy: keep + {{- end }} + labels: + {{- include "cert-manager.crd-labels" . | nindent 4 }} +spec: + group: acme.cert-manager.io + names: + categories: + - cert-manager + - cert-manager-acme + kind: Challenge + listKind: ChallengeList + plural: challenges + singular: challenge + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.state + name: State + type: string + - jsonPath: .spec.dnsName + name: Domain + type: string + - jsonPath: .status.reason + name: Reason + priority: 1 + type: string + - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: Challenge is a type to represent a Challenge request with an ACME server + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + authorizationURL: + description: |- + The URL to the ACME Authorization resource that this + challenge is a part of. + type: string + dnsName: + description: |- + dnsName is the identifier that this challenge is for, e.g., example.com. + If the requested DNSName is a 'wildcard', this field MUST be set to the + non-wildcard domain, e.g., for `*.example.com`, it must be `example.com`. + type: string + issuerRef: + description: |- + References a properly configured ACME-type Issuer which should + be used to create this Challenge. + If the Issuer does not exist, processing will be retried. + If the Issuer is not an 'ACME' Issuer, an error will be returned and the + Challenge will be marked as failed. + properties: + group: + description: |- + Group of the issuer being referred to. + Defaults to 'cert-manager.io'. + type: string + kind: + description: |- + Kind of the issuer being referred to. + Defaults to 'Issuer'. + type: string + name: + description: Name of the issuer being referred to. + type: string + required: + - name + type: object + key: + description: |- + The ACME challenge key for this challenge + For HTTP01 challenges, this is the value that must be responded with to + complete the HTTP01 challenge in the format: + `.`. + For DNS01 challenges, this is the base64 encoded SHA256 sum of the + `.` + text that must be set as the TXT record content. + type: string + solver: + description: |- + Contains the domain solving configuration that should be used to + solve this challenge resource. + properties: + dns01: + description: |- + Configures cert-manager to attempt to complete authorizations by + performing the DNS01 challenge flow. + properties: + acmeDNS: + description: |- + Use the 'ACME DNS' (https://github.com/joohoi/acme-dns) API to manage + DNS01 challenge records. + properties: + accountSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + host: + type: string + required: + - accountSecretRef + - host + type: object + akamai: + description: Use the Akamai DNS zone management API to manage DNS01 challenge records. + properties: + accessTokenSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + clientSecretSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + clientTokenSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + serviceConsumerDomain: + type: string + required: + - accessTokenSecretRef + - clientSecretSecretRef + - clientTokenSecretRef + - serviceConsumerDomain + type: object + azureDNS: + description: Use the Microsoft Azure DNS API to manage DNS01 challenge records. + properties: + clientID: + description: |- + Auth: Azure Service Principal: + The ClientID of the Azure Service Principal used to authenticate with Azure DNS. + If set, ClientSecret and TenantID must also be set. + type: string + clientSecretSecretRef: + description: |- + Auth: Azure Service Principal: + A reference to a Secret containing the password associated with the Service Principal. + If set, ClientID and TenantID must also be set. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + environment: + description: name of the Azure environment (default AzurePublicCloud) + enum: + - AzurePublicCloud + - AzureChinaCloud + - AzureGermanCloud + - AzureUSGovernmentCloud + type: string + hostedZoneName: + description: name of the DNS zone that should be used + type: string + managedIdentity: + description: |- + Auth: Azure Workload Identity or Azure Managed Service Identity: + Settings to enable Azure Workload Identity or Azure Managed Service Identity + If set, ClientID, ClientSecret and TenantID must not be set. + properties: + clientID: + description: client ID of the managed identity, cannot be used at the same time as resourceID + type: string + resourceID: + description: |- + resource ID of the managed identity, cannot 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, cannot be used at the same time as resourceID + type: string + type: object + resourceGroupName: + description: resource group the DNS zone is located in + type: string + subscriptionID: + description: ID of the Azure subscription + type: string + tenantID: + description: |- + Auth: Azure Service Principal: + The TenantID of the Azure Service Principal used to authenticate with Azure DNS. + If set, ClientID and ClientSecret must also be set. + type: string + required: + - resourceGroupName + - subscriptionID + type: object + cloudDNS: + description: Use the Google Cloud DNS API to manage DNS01 challenge records. + properties: + hostedZoneName: + description: |- + HostedZoneName is an optional field that tells cert-manager in which + Cloud DNS zone the challenge record has to be created. + If left empty cert-manager will automatically choose a zone. + type: string + project: + type: string + serviceAccountSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + required: + - project + type: object + cloudflare: + description: Use the Cloudflare API to manage DNS01 challenge records. + properties: + apiKeySecretRef: + description: |- + API key to use to authenticate with Cloudflare. + Note: using an API token to authenticate is now the recommended method + as it allows greater control of permissions. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + apiTokenSecretRef: + description: API token used to authenticate with Cloudflare. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + email: + description: Email of the account, only required when using API key based authentication. + type: string + type: object + cnameStrategy: + description: |- + CNAMEStrategy configures how the DNS01 provider should handle CNAME + records when found in DNS zones. + enum: + - None + - Follow + type: string + digitalocean: + description: Use the DigitalOcean DNS API to manage DNS01 challenge records. + properties: + tokenSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + required: + - tokenSecretRef + type: object + rfc2136: + description: |- + Use RFC2136 ("Dynamic Updates in the Domain Name System") (https://datatracker.ietf.org/doc/rfc2136/) + to manage DNS01 challenge records. + properties: + nameserver: + description: |- + The IP address or hostname of an authoritative DNS server supporting + RFC2136 in the form host:port. If the host is an IPv6 address it must be + enclosed in square brackets (e.g [2001:db8::1]) ; port is optional. + This field is required. + type: string + protocol: + description: Protocol to use for dynamic DNS update queries. Valid values are (case-sensitive) ``TCP`` and ``UDP``; ``UDP`` (default). + enum: + - TCP + - UDP + type: string + tsigAlgorithm: + description: |- + The TSIG Algorithm configured in the DNS supporting RFC2136. Used only + when ``tsigSecretSecretRef`` and ``tsigKeyName`` are defined. + Supported values are (case-insensitive): ``HMACMD5`` (default), + ``HMACSHA1``, ``HMACSHA256`` or ``HMACSHA512``. + type: string + tsigKeyName: + description: |- + The TSIG Key name configured in the DNS. + If ``tsigSecretSecretRef`` is defined, this field is required. + type: string + tsigSecretSecretRef: + description: |- + The name of the secret containing the TSIG value. + If ``tsigKeyName`` is defined, this field is required. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + required: + - nameserver + type: object + route53: + description: Use the AWS Route53 API to manage DNS01 challenge records. + properties: + accessKeyID: + description: |- + The AccessKeyID is used for authentication. + Cannot be set when SecretAccessKeyID is set. + If neither the Access Key nor Key ID are set, we fall-back to using env + vars, shared credentials file or AWS Instance metadata, + see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials + type: string + accessKeyIDSecretRef: + description: |- + The SecretAccessKey is used for authentication. If set, pull the AWS + access key ID from a key within a Kubernetes Secret. + Cannot be set when AccessKeyID is set. + If neither the Access Key nor Key ID are set, we fall-back to using env + vars, shared credentials file or AWS Instance metadata, + see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + auth: + description: Auth configures how cert-manager authenticates. + properties: + kubernetes: + description: |- + Kubernetes authenticates with Route53 using AssumeRoleWithWebIdentity + by passing a bound ServiceAccount token. + properties: + serviceAccountRef: + description: |- + A reference to a service account that will be used to request a bound + token (also known as "projected token"). To use this field, you must + configure an RBAC rule to let cert-manager request a token. + properties: + audiences: + description: |- + TokenAudiences is an optional list of audiences to include in the + token passed to AWS. The default token consisting of the issuer's namespace + and name is always included. + If unset the audience defaults to `sts.amazonaws.com`. + items: + type: string + type: array + x-kubernetes-list-type: atomic + name: + description: Name of the ServiceAccount used to request a token. + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + required: + - kubernetes + type: object + hostedZoneID: + description: If set, the provider will manage only this zone in Route53 and will not do a lookup using the route53:ListHostedZonesByName api call. + type: string + region: + description: |- + Override the AWS region. + + Route53 is a global service and does not have regional endpoints but the + region specified here (or via environment variables) is used as a hint to + help compute the correct AWS credential scope and partition when it + connects to Route53. See: + - [Amazon Route 53 endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/r53.html) + - [Global services](https://docs.aws.amazon.com/whitepapers/latest/aws-fault-isolation-boundaries/global-services.html) + + If you omit this region field, cert-manager will use the region from + AWS_REGION and AWS_DEFAULT_REGION environment variables, if they are set + in the cert-manager controller Pod. + + The `region` field is not needed if you use [IAM Roles for Service Accounts (IRSA)](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html). + Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: + [Amazon EKS Pod Identity Webhook](https://github.com/aws/amazon-eks-pod-identity-webhook). + In this case this `region` field value is ignored. + + The `region` field is not needed if you use [EKS Pod Identities](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html). + Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: + [Amazon EKS Pod Identity Agent](https://github.com/aws/eks-pod-identity-agent), + In this case this `region` field value is ignored. + type: string + role: + description: |- + Role is a Role ARN which the Route53 provider will assume using either the explicit credentials AccessKeyID/SecretAccessKey + or the inferred credentials from environment variables, shared credentials file or AWS Instance metadata + type: string + secretAccessKeySecretRef: + description: |- + The SecretAccessKey is used for authentication. + If neither the Access Key nor Key ID are set, we fall-back to using env + vars, shared credentials file or AWS Instance metadata, + see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + type: object + webhook: + description: |- + Configure an external webhook based DNS01 challenge solver to manage + DNS01 challenge records. + properties: + config: + description: |- + Additional configuration that should be passed to the webhook apiserver + when challenges are processed. + This can contain arbitrary JSON data. + Secret values should not be specified in this stanza. + If secret values are needed (e.g., credentials for a DNS service), you + should use a SecretKeySelector to reference a Secret resource. + For details on the schema of this field, consult the webhook provider + implementation's documentation. + x-kubernetes-preserve-unknown-fields: true + groupName: + description: |- + The API group name that should be used when POSTing ChallengePayload + resources to the webhook apiserver. + This should be the same as the GroupName specified in the webhook + provider implementation. + type: string + solverName: + description: |- + The name of the solver to use, as defined in the webhook provider + implementation. + This will typically be the name of the provider, e.g., 'cloudflare'. + type: string + required: + - groupName + - solverName + type: object + type: object + http01: + description: |- + Configures cert-manager to attempt to complete authorizations by + performing the HTTP01 challenge flow. + It is not possible to obtain certificates for wildcard domain names + (e.g., `*.example.com`) using the HTTP01 challenge mechanism. + properties: + gatewayHTTPRoute: + description: |- + The Gateway API is a sig-network community API that models service networking + in Kubernetes (https://gateway-api.sigs.k8s.io/). The Gateway solver will + create HTTPRoutes with the specified labels in the same namespace as the challenge. + This solver is experimental, and fields / behaviour may change in the future. + properties: + labels: + additionalProperties: + type: string + description: |- + Custom labels that will be applied to HTTPRoutes created by cert-manager + while solving HTTP-01 challenges. + type: object + parentRefs: + description: |- + When solving an HTTP-01 challenge, cert-manager creates an HTTPRoute. + cert-manager needs to know which parentRefs should be used when creating + the HTTPRoute. Usually, the parentRef references a Gateway. See: + https://gateway-api.sigs.k8s.io/api-types/httproute/#attaching-to-gateways + 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 + type: array + x-kubernetes-list-type: atomic + podTemplate: + description: |- + Optional pod template used to configure the ACME challenge solver pods + used for HTTP01 challenges. + properties: + metadata: + description: |- + ObjectMeta overrides for the pod used to solve HTTP01 challenges. + Only the 'labels' and 'annotations' fields may be set. + If labels or annotations overlap with in-built values, the values here + will override the in-built values. + properties: + annotations: + additionalProperties: + type: string + description: Annotations that should be added to the created ACME HTTP01 solver pods. + type: object + labels: + additionalProperties: + type: string + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + type: object + spec: + description: |- + PodSpec defines overrides for the HTTP01 challenge solver pod. + Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. + All other fields will be ignored. + properties: + affinity: + description: If specified, the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + imagePullSecrets: + description: If specified, the pod's imagePullSecrets + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector is a selector which must be true for the pod to fit on a node. + Selector which must match a node's labels for the pod to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + resources: + description: |- + If specified, the pod's resource requirements. + These values override the global resource configuration flags. + Note that when only specifying resource limits, ensure they are greater than or equal + to the corresponding global resource requests configured via controller flags + (--acme-http01-solver-resource-request-cpu, --acme-http01-solver-resource-request-memory). + Kubernetes will reject pod creation if limits are lower than requests, causing challenge failures. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to the global values configured via controller flags. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + securityContext: + description: If specified, the pod's security context + properties: + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in addition + to the container's primary GID, the fsGroup (if specified), and group memberships + defined in the container image for the uid of the container process. If unspecified, + no additional groups are added to any container. Note that group memberships + defined in the container image for the uid of the container process are still effective, + even if they are not included in this list. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + type: object + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + serviceType: + description: |- + Optional service type for Kubernetes solver service. Supported values + are NodePort or ClusterIP. If unset, defaults to NodePort. + type: string + type: object + ingress: + description: |- + The ingress based HTTP01 challenge solver will solve challenges by + creating or modifying Ingress resources in order to route requests for + '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are + provisioned by cert-manager for each Challenge to be completed. + properties: + class: + description: |- + This field configures the annotation `kubernetes.io/ingress.class` when + creating Ingress resources to solve ACME challenges that use this + challenge solver. Only one of `class`, `name` or `ingressClassName` may + be specified. + type: string + ingressClassName: + description: |- + This field configures the field `ingressClassName` on the created Ingress + resources used to solve ACME challenges that use this challenge solver. + This is the recommended way of configuring the ingress class. Only one of + `class`, `name` or `ingressClassName` may be specified. + type: string + ingressTemplate: + description: |- + Optional ingress template used to configure the ACME challenge solver + ingress used for HTTP01 challenges. + properties: + metadata: + description: |- + ObjectMeta overrides for the ingress used to solve HTTP01 challenges. + Only the 'labels' and 'annotations' fields may be set. + If labels or annotations overlap with in-built values, the values here + will override the in-built values. + properties: + annotations: + additionalProperties: + type: string + description: Annotations that should be added to the created ACME HTTP01 solver ingress. + type: object + labels: + additionalProperties: + type: string + description: Labels that should be added to the created ACME HTTP01 solver ingress. + type: object + type: object + type: object + name: + description: |- + The name of the ingress resource that should have ACME challenge solving + routes inserted into it in order to solve HTTP01 challenges. + This is typically used in conjunction with ingress controllers like + ingress-gce, which maintains a 1:1 mapping between external IPs and + ingress resources. Only one of `class`, `name` or `ingressClassName` may + be specified. + type: string + podTemplate: + description: |- + Optional pod template used to configure the ACME challenge solver pods + used for HTTP01 challenges. + properties: + metadata: + description: |- + ObjectMeta overrides for the pod used to solve HTTP01 challenges. + Only the 'labels' and 'annotations' fields may be set. + If labels or annotations overlap with in-built values, the values here + will override the in-built values. + properties: + annotations: + additionalProperties: + type: string + description: Annotations that should be added to the created ACME HTTP01 solver pods. + type: object + labels: + additionalProperties: + type: string + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + type: object + spec: + description: |- + PodSpec defines overrides for the HTTP01 challenge solver pod. + Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. + All other fields will be ignored. + properties: + affinity: + description: If specified, the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + imagePullSecrets: + description: If specified, the pod's imagePullSecrets + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector is a selector which must be true for the pod to fit on a node. + Selector which must match a node's labels for the pod to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + resources: + description: |- + If specified, the pod's resource requirements. + These values override the global resource configuration flags. + Note that when only specifying resource limits, ensure they are greater than or equal + to the corresponding global resource requests configured via controller flags + (--acme-http01-solver-resource-request-cpu, --acme-http01-solver-resource-request-memory). + Kubernetes will reject pod creation if limits are lower than requests, causing challenge failures. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to the global values configured via controller flags. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + securityContext: + description: If specified, the pod's security context + properties: + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in addition + to the container's primary GID, the fsGroup (if specified), and group memberships + defined in the container image for the uid of the container process. If unspecified, + no additional groups are added to any container. Note that group memberships + defined in the container image for the uid of the container process are still effective, + even if they are not included in this list. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + type: object + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + serviceType: + description: |- + Optional service type for Kubernetes solver service. Supported values + are NodePort or ClusterIP. If unset, defaults to NodePort. + type: string + type: object + type: object + selector: + description: |- + Selector selects a set of DNSNames on the Certificate resource that + should be solved using this challenge solver. + If not specified, the solver will be treated as the 'default' solver + with the lowest priority, i.e. if any other solver has a more specific + match, it will be used instead. + properties: + dnsNames: + description: |- + List of DNSNames that this solver will be used to solve. + If specified and a match is found, a dnsNames selector will take + precedence over a dnsZones selector. + If multiple solvers match with the same dnsNames value, the solver + with the most matching labels in matchLabels will be selected. + If neither has more matches, the solver defined earlier in the list + will be selected. + items: + type: string + type: array + x-kubernetes-list-type: atomic + dnsZones: + description: |- + List of DNSZones that this solver will be used to solve. + The most specific DNS zone match specified here will take precedence + over other DNS zone matches, so a solver specifying sys.example.com + will be selected over one specifying example.com for the domain + www.sys.example.com. + If multiple solvers match with the same dnsZones value, the solver + with the most matching labels in matchLabels will be selected. + If neither has more matches, the solver defined earlier in the list + will be selected. + items: + type: string + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + A label selector that is used to refine the set of certificate's that + this challenge solver will apply to. + type: object + type: object + type: object + token: + description: |- + The ACME challenge token for this challenge. + This is the raw value returned from the ACME server. + type: string + type: + description: |- + The type of ACME challenge this resource represents. + One of "HTTP-01" or "DNS-01". + enum: + - HTTP-01 + - DNS-01 + type: string + url: + description: |- + The URL of the ACME Challenge resource for this challenge. + This can be used to lookup details about the status of this challenge. + type: string + wildcard: + description: |- + wildcard will be true if this challenge is for a wildcard identifier, + for example '*.example.com'. + type: boolean + required: + - authorizationURL + - dnsName + - issuerRef + - key + - solver + - token + - type + - url + type: object + status: + properties: + presented: + description: |- + presented will be set to true if the challenge values for this challenge + are currently 'presented'. + This *does not* imply the self check is passing. Only that the values + have been 'submitted' for the appropriate challenge mechanism (i.e. the + DNS01 TXT record has been presented, or the HTTP01 configuration has been + configured). + type: boolean + processing: + description: |- + Used to denote whether this challenge should be processed or not. + This field will only be set to true by the 'scheduling' component. + It will only be set to false by the 'challenges' controller, after the + challenge has reached a final state or timed out. + If this field is set to false, the challenge controller will not take + any more action. + type: boolean + reason: + description: |- + Contains human readable information on why the Challenge is in the + current state. + type: string + state: + description: |- + Contains the current 'state' of the challenge. + If not set, the state of the challenge is unknown. + enum: + - valid + - ready + - pending + - processing + - invalid + - expired + - errored + type: string + type: object + required: + - metadata + - spec + type: object + served: true + storage: true + subresources: + status: {} +{{- end }} diff --git a/packages/system/cert-manager-crds/templates/crd-acme.cert-manager.io_orders.yaml b/packages/system/cert-manager-crds/templates/crd-acme.cert-manager.io_orders.yaml new file mode 100644 index 00000000..3242fc41 --- /dev/null +++ b/packages/system/cert-manager-crds/templates/crd-acme.cert-manager.io_orders.yaml @@ -0,0 +1,274 @@ +{{- if or .Values.crds.enabled .Values.installCRDs }} +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: "orders.acme.cert-manager.io" + {{- if .Values.crds.keep }} + annotations: + helm.sh/resource-policy: keep + {{- end }} + labels: + {{- include "cert-manager.crd-labels" . | nindent 4 }} +spec: + group: acme.cert-manager.io + names: + categories: + - cert-manager + - cert-manager-acme + kind: Order + listKind: OrderList + plural: orders + singular: order + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.state + name: State + type: string + - jsonPath: .spec.issuerRef.name + name: Issuer + priority: 1 + type: string + - jsonPath: .status.reason + name: Reason + priority: 1 + type: string + - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: Order is a type to represent an Order with an ACME server + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + commonName: + description: |- + CommonName is the common name as specified on the DER encoded CSR. + If specified, this value must also be present in `dnsNames` or `ipAddresses`. + This field must match the corresponding field on the DER encoded CSR. + type: string + dnsNames: + description: |- + DNSNames is a list of DNS names that should be included as part of the Order + validation process. + This field must match the corresponding field on the DER encoded CSR. + items: + type: string + type: array + x-kubernetes-list-type: atomic + duration: + description: |- + Duration is the duration for the not after date for the requested certificate. + this is set on order creation as pe the ACME spec. + type: string + ipAddresses: + description: |- + IPAddresses is a list of IP addresses that should be included as part of the Order + validation process. + This field must match the corresponding field on the DER encoded CSR. + items: + type: string + type: array + x-kubernetes-list-type: atomic + issuerRef: + description: |- + IssuerRef references a properly configured ACME-type Issuer which should + be used to create this Order. + If the Issuer does not exist, processing will be retried. + If the Issuer is not an 'ACME' Issuer, an error will be returned and the + Order will be marked as failed. + properties: + group: + description: |- + Group of the issuer being referred to. + Defaults to 'cert-manager.io'. + type: string + kind: + description: |- + Kind of the issuer being referred to. + Defaults to 'Issuer'. + type: string + name: + description: Name of the issuer being referred to. + type: string + required: + - name + type: object + profile: + description: |- + Profile allows requesting a certificate profile from the ACME server. + Supported profiles are listed by the server's ACME directory URL. + type: string + request: + description: |- + Certificate signing request bytes in DER encoding. + This will be used when finalizing the order. + This field must be set on the order. + format: byte + type: string + required: + - issuerRef + - request + type: object + status: + properties: + authorizations: + description: |- + Authorizations contains data returned from the ACME server on what + authorizations must be completed in order to validate the DNS names + specified on the Order. + items: + description: |- + ACMEAuthorization contains data returned from the ACME server on an + authorization that must be completed in order validate a DNS name on an ACME + Order resource. + properties: + challenges: + description: |- + Challenges specifies the challenge types offered by the ACME server. + One of these challenge types will be selected when validating the DNS + name and an appropriate Challenge resource will be created to perform + the ACME challenge process. + items: + description: |- + Challenge specifies a challenge offered by the ACME server for an Order. + An appropriate Challenge resource can be created to perform the ACME + challenge process. + properties: + token: + description: |- + Token is the token that must be presented for this challenge. + This is used to compute the 'key' that must also be presented. + type: string + type: + description: |- + Type is the type of challenge being offered, e.g., 'http-01', 'dns-01', + 'tls-sni-01', etc. + This is the raw value retrieved from the ACME server. + Only 'http-01' and 'dns-01' are supported by cert-manager, other values + will be ignored. + type: string + url: + description: |- + URL is the URL of this challenge. It can be used to retrieve additional + metadata about the Challenge from the ACME server. + type: string + required: + - token + - type + - url + type: object + type: array + x-kubernetes-list-type: atomic + identifier: + description: Identifier is the DNS name to be validated as part of this authorization + type: string + initialState: + description: |- + InitialState is the initial state of the ACME authorization when first + fetched from the ACME server. + If an Authorization is already 'valid', the Order controller will not + create a Challenge resource for the authorization. This will occur when + working with an ACME server that enables 'authz reuse' (such as Let's + Encrypt's production endpoint). + If not set and 'identifier' is set, the state is assumed to be pending + and a Challenge will be created. + enum: + - valid + - ready + - pending + - processing + - invalid + - expired + - errored + type: string + url: + description: URL is the URL of the Authorization that must be completed + type: string + wildcard: + description: |- + Wildcard will be true if this authorization is for a wildcard DNS name. + If this is true, the identifier will be the *non-wildcard* version of + the DNS name. + For example, if '*.example.com' is the DNS name being validated, this + field will be 'true' and the 'identifier' field will be 'example.com'. + type: boolean + required: + - url + type: object + type: array + x-kubernetes-list-type: atomic + certificate: + description: |- + Certificate is a copy of the PEM encoded certificate for this Order. + This field will be populated after the order has been successfully + finalized with the ACME server, and the order has transitioned to the + 'valid' state. + format: byte + type: string + failureTime: + description: |- + FailureTime stores the time that this order failed. + This is used to influence garbage collection and back-off. + format: date-time + type: string + finalizeURL: + description: |- + FinalizeURL of the Order. + This is used to obtain certificates for this order once it has been completed. + type: string + reason: + description: |- + Reason optionally provides more information about a why the order is in + the current state. + type: string + state: + description: |- + State contains the current state of this Order resource. + States 'success' and 'expired' are 'final' + enum: + - valid + - ready + - pending + - processing + - invalid + - expired + - errored + type: string + url: + description: |- + URL of the Order. + This will initially be empty when the resource is first created. + The Order controller will populate this field when the Order is first processed. + This field will be immutable after it is initially set. + type: string + type: object + required: + - metadata + - spec + type: object + served: true + storage: true + subresources: + status: {} +{{- end }} diff --git a/packages/system/cert-manager-crds/templates/crd-cert-manager.io_certificaterequests.yaml b/packages/system/cert-manager-crds/templates/crd-cert-manager.io_certificaterequests.yaml new file mode 100644 index 00000000..e25ad1d0 --- /dev/null +++ b/packages/system/cert-manager-crds/templates/crd-cert-manager.io_certificaterequests.yaml @@ -0,0 +1,319 @@ +{{- if or .Values.crds.enabled .Values.installCRDs }} +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: "certificaterequests.cert-manager.io" + {{- if .Values.crds.keep }} + annotations: + helm.sh/resource-policy: keep + {{- end }} + labels: + {{- include "cert-manager.crd-labels" . | nindent 4 }} +spec: + group: cert-manager.io + names: + categories: + - cert-manager + kind: CertificateRequest + listKind: CertificateRequestList + plural: certificaterequests + shortNames: + - cr + - crs + singular: certificaterequest + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type == "Approved")].status + name: Approved + type: string + - jsonPath: .status.conditions[?(@.type == "Denied")].status + name: Denied + type: string + - jsonPath: .status.conditions[?(@.type == "Ready")].status + name: Ready + type: string + - jsonPath: .spec.issuerRef.name + name: Issuer + type: string + - jsonPath: .spec.username + name: Requester + type: string + - jsonPath: .status.conditions[?(@.type == "Ready")].message + name: Status + priority: 1 + type: string + - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: |- + A CertificateRequest is used to request a signed certificate from one of the + configured issuers. + + All fields within the CertificateRequest's `spec` are immutable after creation. + A CertificateRequest will either succeed or fail, as denoted by its `Ready` status + condition and its `status.failureTime` field. + + A CertificateRequest is a one-shot resource, meaning it represents a single + point in time request for a certificate and cannot be re-used. + 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: |- + Specification of the desired state of the CertificateRequest resource. + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + duration: + description: |- + Requested 'duration' (i.e. lifetime) of the Certificate. Note that the + issuer may choose to ignore the requested duration, just like any other + requested attribute. + type: string + extra: + additionalProperties: + items: + type: string + type: array + description: |- + Extra contains extra attributes of the user that created the CertificateRequest. + Populated by the cert-manager webhook on creation and immutable. + type: object + groups: + description: |- + Groups contains group membership of the user that created the CertificateRequest. + Populated by the cert-manager webhook on creation and immutable. + items: + type: string + type: array + x-kubernetes-list-type: atomic + isCA: + description: |- + Requested basic constraints isCA value. Note that the issuer may choose + to ignore the requested isCA value, just like any other requested attribute. + + NOTE: If the CSR in the `Request` field has a BasicConstraints extension, + it must have the same isCA value as specified here. + + If true, this will automatically add the `cert sign` usage to the list + of requested `usages`. + type: boolean + issuerRef: + description: |- + Reference to the issuer responsible for issuing the certificate. + If the issuer is namespace-scoped, it must be in the same namespace + as the Certificate. If the issuer is cluster-scoped, it can be used + from any namespace. + + The `name` field of the reference must always be specified. + properties: + group: + description: |- + Group of the issuer being referred to. + Defaults to 'cert-manager.io'. + type: string + kind: + description: |- + Kind of the issuer being referred to. + Defaults to 'Issuer'. + type: string + name: + description: Name of the issuer being referred to. + type: string + required: + - name + type: object + request: + description: |- + The PEM-encoded X.509 certificate signing request to be submitted to the + issuer for signing. + + If the CSR has a BasicConstraints extension, its isCA attribute must + match the `isCA` value of this CertificateRequest. + If the CSR has a KeyUsage extension, its key usages must match the + key usages in the `usages` field of this CertificateRequest. + If the CSR has a ExtKeyUsage extension, its extended key usages + must match the extended key usages in the `usages` field of this + CertificateRequest. + format: byte + type: string + uid: + description: |- + UID contains the uid of the user that created the CertificateRequest. + Populated by the cert-manager webhook on creation and immutable. + type: string + usages: + description: |- + Requested key usages and extended key usages. + + NOTE: If the CSR in the `Request` field has uses the KeyUsage or + ExtKeyUsage extension, these extensions must have the same values + as specified here without any additional values. + + If unset, defaults to `digital signature` and `key encipherment`. + items: + description: |- + KeyUsage specifies valid usage contexts for keys. + See: + https://tools.ietf.org/html/rfc5280#section-4.2.1.3 + https://tools.ietf.org/html/rfc5280#section-4.2.1.12 + + Valid KeyUsage values are as follows: + "signing", + "digital signature", + "content commitment", + "key encipherment", + "key agreement", + "data encipherment", + "cert sign", + "crl sign", + "encipher only", + "decipher only", + "any", + "server auth", + "client auth", + "code signing", + "email protection", + "s/mime", + "ipsec end system", + "ipsec tunnel", + "ipsec user", + "timestamping", + "ocsp signing", + "microsoft sgc", + "netscape sgc" + enum: + - signing + - digital signature + - content commitment + - key encipherment + - key agreement + - data encipherment + - cert sign + - crl sign + - encipher only + - decipher only + - any + - server auth + - client auth + - code signing + - email protection + - s/mime + - ipsec end system + - ipsec tunnel + - ipsec user + - timestamping + - ocsp signing + - microsoft sgc + - netscape sgc + type: string + type: array + x-kubernetes-list-type: atomic + username: + description: |- + Username contains the name of the user that created the CertificateRequest. + Populated by the cert-manager webhook on creation and immutable. + type: string + required: + - issuerRef + - request + type: object + status: + description: |- + Status of the CertificateRequest. + This is set and managed automatically. + Read-only. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + ca: + description: |- + The PEM encoded X.509 certificate of the signer, also known as the CA + (Certificate Authority). + This is set on a best-effort basis by different issuers. + If not set, the CA is assumed to be unknown/not available. + format: byte + type: string + certificate: + description: |- + The PEM encoded X.509 certificate resulting from the certificate + signing request. + If not set, the CertificateRequest has either not been completed or has + failed. More information on failure can be found by checking the + `conditions` field. + format: byte + type: string + conditions: + description: |- + List of status conditions to indicate the status of a CertificateRequest. + Known condition types are `Ready`, `InvalidRequest`, `Approved` and `Denied`. + items: + description: CertificateRequestCondition contains condition information for a CertificateRequest. + properties: + lastTransitionTime: + description: |- + LastTransitionTime is the timestamp corresponding to the last status + change of this condition. + format: date-time + type: string + message: + description: |- + Message is a human readable description of the details of the last + transition, complementing reason. + type: string + reason: + description: |- + Reason is a brief machine readable explanation for the condition's last + transition. + type: string + status: + description: Status of the condition, one of (`True`, `False`, `Unknown`). + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + Type of the condition, known values are (`Ready`, `InvalidRequest`, + `Approved`, `Denied`). + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + failureTime: + description: |- + FailureTime stores the time that this CertificateRequest failed. This is + used to influence garbage collection and back-off. + format: date-time + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +{{- end }} diff --git a/packages/system/cert-manager-crds/templates/crd-cert-manager.io_certificates.yaml b/packages/system/cert-manager-crds/templates/crd-cert-manager.io_certificates.yaml new file mode 100644 index 00000000..6689de66 --- /dev/null +++ b/packages/system/cert-manager-crds/templates/crd-cert-manager.io_certificates.yaml @@ -0,0 +1,816 @@ +{{- if or .Values.crds.enabled .Values.installCRDs }} +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: "certificates.cert-manager.io" + {{- if .Values.crds.keep }} + annotations: + helm.sh/resource-policy: keep + {{- end }} + labels: + {{- include "cert-manager.crd-labels" . | nindent 4 }} +spec: + group: cert-manager.io + names: + categories: + - cert-manager + kind: Certificate + listKind: CertificateList + plural: certificates + shortNames: + - cert + - certs + singular: certificate + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type == "Ready")].status + name: Ready + type: string + - jsonPath: .spec.secretName + name: Secret + type: string + - jsonPath: .spec.issuerRef.name + name: Issuer + priority: 1 + type: string + - jsonPath: .status.conditions[?(@.type == "Ready")].message + name: Status + priority: 1 + type: string + - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: |- + A Certificate resource should be created to ensure an up to date and signed + X.509 certificate is stored in the Kubernetes Secret resource named in `spec.secretName`. + + The stored certificate will be renewed before it expires (as configured by `spec.renewBefore`). + 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: |- + Specification of the desired state of the Certificate resource. + https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + additionalOutputFormats: + description: |- + Defines extra output formats of the private key and signed certificate chain + to be written to this Certificate's target Secret. + items: + description: |- + CertificateAdditionalOutputFormat defines an additional output format of a + Certificate resource. These contain supplementary data formats of the signed + certificate chain and paired private key. + properties: + type: + description: |- + Type is the name of the format type that should be written to the + Certificate's target Secret. + enum: + - DER + - CombinedPEM + type: string + required: + - type + type: object + type: array + x-kubernetes-list-type: atomic + commonName: + description: |- + Requested common name X509 certificate subject attribute. + More info: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6 + NOTE: TLS clients will ignore this value when any subject alternative name is + set (see https://tools.ietf.org/html/rfc6125#section-6.4.4). + + Should have a length of 64 characters or fewer to avoid generating invalid CSRs. + Cannot be set if the `literalSubject` field is set. + type: string + dnsNames: + description: Requested DNS subject alternative names. + items: + type: string + type: array + x-kubernetes-list-type: atomic + duration: + description: |- + Requested 'duration' (i.e. lifetime) of the Certificate. Note that the + issuer may choose to ignore the requested duration, just like any other + requested attribute. + + If unset, this defaults to 90 days. + Minimum accepted duration is 1 hour. + Value must be in units accepted by Go time.ParseDuration https://golang.org/pkg/time/#ParseDuration. + type: string + emailAddresses: + description: Requested email subject alternative names. + items: + type: string + type: array + x-kubernetes-list-type: atomic + encodeUsagesInRequest: + description: |- + Whether the KeyUsage and ExtKeyUsage extensions should be set in the encoded CSR. + + This option defaults to true, and should only be disabled if the target + issuer does not support CSRs with these X509 KeyUsage/ ExtKeyUsage extensions. + type: boolean + ipAddresses: + description: Requested IP address subject alternative names. + items: + type: string + type: array + x-kubernetes-list-type: atomic + isCA: + description: |- + Requested basic constraints isCA value. + The isCA value is used to set the `isCA` field on the created CertificateRequest + resources. Note that the issuer may choose to ignore the requested isCA value, just + like any other requested attribute. + + If true, this will automatically add the `cert sign` usage to the list + of requested `usages`. + type: boolean + issuerRef: + description: |- + Reference to the issuer responsible for issuing the certificate. + If the issuer is namespace-scoped, it must be in the same namespace + as the Certificate. If the issuer is cluster-scoped, it can be used + from any namespace. + + The `name` field of the reference must always be specified. + properties: + group: + description: |- + Group of the issuer being referred to. + Defaults to 'cert-manager.io'. + type: string + kind: + description: |- + Kind of the issuer being referred to. + Defaults to 'Issuer'. + type: string + name: + description: Name of the issuer being referred to. + type: string + required: + - name + type: object + keystores: + description: Additional keystore output formats to be stored in the Certificate's Secret. + properties: + jks: + description: |- + JKS configures options for storing a JKS keystore in the + `spec.secretName` Secret resource. + properties: + alias: + description: |- + Alias specifies the alias of the key in the keystore, required by the JKS format. + If not provided, the default alias `certificate` will be used. + type: string + create: + description: |- + 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` 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 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. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + required: + - create + type: object + pkcs12: + description: |- + PKCS12 configures options for storing a PKCS12 keystore in the + `spec.secretName` Secret resource. + 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` 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 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. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + profile: + description: |- + Profile specifies the key and certificate encryption algorithms and the HMAC algorithm + used to create the PKCS12 keystore. Default value is `LegacyRC2` for backward compatibility. + + If provided, allowed values are: + `LegacyRC2`: Deprecated. Not supported by default in OpenSSL 3 or Java 20. + `LegacyDES`: Less secure algorithm. Use this option for maximal compatibility. + `Modern2023`: Secure algorithm. Use this option in case you have to always use secure algorithms + (e.g., because of company policy). Please note that the security of the algorithm is not that important + in reality, because the unencrypted certificate and private key are also stored in the Secret. + enum: + - LegacyRC2 + - LegacyDES + - Modern2023 + type: string + required: + - create + type: object + type: object + literalSubject: + description: |- + Requested X.509 certificate subject, represented using the LDAP "String + Representation of a Distinguished Name" [1]. + Important: the LDAP string format also specifies the order of the attributes + in the subject, this is important when issuing certs for LDAP authentication. + Example: `CN=foo,DC=corp,DC=example,DC=com` + More info [1]: https://datatracker.ietf.org/doc/html/rfc4514 + More info: https://github.com/cert-manager/cert-manager/issues/3203 + More info: https://github.com/cert-manager/cert-manager/issues/4424 + + Cannot be set if the `subject` or `commonName` field is set. + type: string + nameConstraints: + description: |- + x.509 certificate NameConstraint extension which MUST NOT be used in a non-CA certificate. + More Info: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10 + + This is an Alpha Feature and is only enabled with the + `--feature-gates=NameConstraints=true` option set on both + the controller and webhook components. + properties: + critical: + description: if true then the name constraints are marked critical. + type: boolean + excluded: + description: |- + Excluded contains the constraints which must be disallowed. Any name matching a + restriction in the excluded field is invalid regardless + of information appearing in the permitted + properties: + dnsDomains: + description: DNSDomains is a list of DNS domains that are permitted or excluded. + items: + type: string + type: array + x-kubernetes-list-type: atomic + emailAddresses: + description: EmailAddresses is a list of Email Addresses that are permitted or excluded. + items: + type: string + type: array + x-kubernetes-list-type: atomic + ipRanges: + description: |- + IPRanges is a list of IP Ranges that are permitted or excluded. + This should be a valid CIDR notation. + items: + type: string + type: array + x-kubernetes-list-type: atomic + uriDomains: + description: URIDomains is a list of URI domains that are permitted or excluded. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + permitted: + description: Permitted contains the constraints in which the names must be located. + properties: + dnsDomains: + description: DNSDomains is a list of DNS domains that are permitted or excluded. + items: + type: string + type: array + x-kubernetes-list-type: atomic + emailAddresses: + description: EmailAddresses is a list of Email Addresses that are permitted or excluded. + items: + type: string + type: array + x-kubernetes-list-type: atomic + ipRanges: + description: |- + IPRanges is a list of IP Ranges that are permitted or excluded. + This should be a valid CIDR notation. + items: + type: string + type: array + x-kubernetes-list-type: atomic + uriDomains: + description: URIDomains is a list of URI domains that are permitted or excluded. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + type: object + otherNames: + description: |- + `otherNames` is an escape hatch for SAN that allows any type. We currently restrict the support to string like otherNames, cf RFC 5280 p 37 + Any UTF8 String valued otherName can be passed with by setting the keys oid: x.x.x.x and UTF8Value: somevalue for `otherName`. + Most commonly this would be UPN set with oid: 1.3.6.1.4.1.311.20.2.3 + You should ensure that any OID passed is valid for the UTF8String type as we do not explicitly validate this. + items: + properties: + oid: + description: |- + OID is the object identifier for the otherName SAN. + The object identifier must be expressed as a dotted string, for + example, "1.2.840.113556.1.4.221". + type: string + utf8Value: + description: |- + utf8Value is the string value of the otherName SAN. + The utf8Value accepts any valid UTF8 string to set as value for the otherName SAN. + type: string + type: object + type: array + x-kubernetes-list-type: atomic + privateKey: + description: |- + Private key options. These include the key algorithm and size, the used + encoding and the rotation policy. + properties: + algorithm: + description: |- + Algorithm is the private key algorithm of the corresponding private key + for this certificate. + + If provided, allowed values are either `RSA`, `ECDSA` or `Ed25519`. + If `algorithm` is specified and `size` is not provided, + key size of 2048 will be used for `RSA` key algorithm and + key size of 256 will be used for `ECDSA` key algorithm. + key size is ignored when using the `Ed25519` key algorithm. + enum: + - RSA + - ECDSA + - Ed25519 + type: string + encoding: + description: |- + The private key cryptography standards (PKCS) encoding for this + certificate's private key to be encoded in. + + If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 + and PKCS#8, respectively. + Defaults to `PKCS1` if not specified. + enum: + - PKCS1 + - PKCS8 + type: string + rotationPolicy: + description: |- + RotationPolicy controls how private keys should be regenerated when a + re-issuance is being processed. + + If set to `Never`, a private key will only be generated if one does not + already exist in the target `spec.secretName`. If one does exist but it + does not have the correct algorithm or size, a warning will be raised + to await user intervention. + If set to `Always`, a private key matching the specified requirements + will be generated whenever a re-issuance occurs. + Default is `Always`. + The default was changed from `Never` to `Always` in cert-manager >=v1.18.0. + The new default can be disabled by setting the + `--feature-gates=DefaultPrivateKeyRotationPolicyAlways=false` option on + the controller component. + enum: + - Never + - Always + type: string + size: + description: |- + Size is the key bit size of the corresponding private key for this certificate. + + If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, + and will default to `2048` if not specified. + If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, + and will default to `256` if not specified. + If `algorithm` is set to `Ed25519`, Size is ignored. + No other values are allowed. + type: integer + type: object + renewBefore: + description: |- + How long before the currently issued certificate's expiry cert-manager should + renew the certificate. For example, if a certificate is valid for 60 minutes, + and `renewBefore=10m`, cert-manager will begin to attempt to renew the certificate + 50 minutes after it was issued (i.e. when there are 10 minutes remaining until + the certificate is no longer valid). + + NOTE: The actual lifetime of the issued certificate is used to determine the + renewal time. If an issuer returns a certificate with a different lifetime than + the one requested, cert-manager will use the lifetime of the issued certificate. + + If unset, this defaults to 1/3 of the issued certificate's lifetime. + Minimum accepted value is 5 minutes. + Value must be in units accepted by Go time.ParseDuration https://golang.org/pkg/time/#ParseDuration. + Cannot be set if the `renewBeforePercentage` field is set. + type: string + renewBeforePercentage: + description: |- + `renewBeforePercentage` is like `renewBefore`, except it is a relative percentage + rather than an absolute duration. For example, if a certificate is valid for 60 + minutes, and `renewBeforePercentage=25`, cert-manager will begin to attempt to + renew the certificate 45 minutes after it was issued (i.e. when there are 15 + minutes (25%) remaining until the certificate is no longer valid). + + NOTE: The actual lifetime of the issued certificate is used to determine the + renewal time. If an issuer returns a certificate with a different lifetime than + the one requested, cert-manager will use the lifetime of the issued certificate. + + Value must be an integer in the range (0,100). The minimum effective + `renewBefore` derived from the `renewBeforePercentage` and `duration` fields is 5 + minutes. + Cannot be set if the `renewBefore` field is set. + format: int32 + type: integer + revisionHistoryLimit: + description: |- + The maximum number of CertificateRequest revisions that are maintained in + the Certificate's history. Each revision represents a single `CertificateRequest` + created by this Certificate, either when it was created, renewed, or Spec + was changed. Revisions will be removed by oldest first if the number of + revisions exceeds this number. + + If set, revisionHistoryLimit must be a value of `1` or greater. + Default value is `1`. + format: int32 + type: integer + secretName: + description: |- + Name of the Secret resource that will be automatically created and + managed by this Certificate resource. It will be populated with a + private key and certificate, signed by the denoted issuer. The Secret + resource lives in the same namespace as the Certificate resource. + type: string + secretTemplate: + description: |- + Defines annotations and labels to be copied to the Certificate's Secret. + Labels and annotations on the Secret will be changed as they appear on the + SecretTemplate when added or removed. SecretTemplate annotations are added + in conjunction with, and cannot overwrite, the base set of annotations + cert-manager sets on the Certificate's Secret. + properties: + annotations: + additionalProperties: + type: string + description: Annotations is a key value map to be copied to the target Kubernetes Secret. + type: object + labels: + additionalProperties: + type: string + description: Labels is a key value map to be copied to the target Kubernetes Secret. + type: object + type: object + signatureAlgorithm: + description: |- + Signature algorithm to use. + Allowed values for RSA keys: SHA256WithRSA, SHA384WithRSA, SHA512WithRSA. + Allowed values for ECDSA keys: ECDSAWithSHA256, ECDSAWithSHA384, ECDSAWithSHA512. + Allowed values for Ed25519 keys: PureEd25519. + enum: + - SHA256WithRSA + - SHA384WithRSA + - SHA512WithRSA + - ECDSAWithSHA256 + - ECDSAWithSHA384 + - ECDSAWithSHA512 + - PureEd25519 + type: string + subject: + description: |- + Requested set of X509 certificate subject attributes. + More info: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6 + + The common name attribute is specified separately in the `commonName` field. + Cannot be set if the `literalSubject` field is set. + properties: + countries: + description: Countries to be used on the Certificate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + localities: + description: Cities to be used on the Certificate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + organizationalUnits: + description: Organizational Units to be used on the Certificate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + organizations: + description: Organizations to be used on the Certificate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + postalCodes: + description: Postal codes to be used on the Certificate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + provinces: + description: State/Provinces to be used on the Certificate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + serialNumber: + description: Serial number to be used on the Certificate. + type: string + streetAddresses: + description: Street addresses to be used on the Certificate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + uris: + description: Requested URI subject alternative names. + items: + type: string + type: array + x-kubernetes-list-type: atomic + usages: + description: |- + Requested key usages and extended key usages. + These usages are used to set the `usages` field on the created CertificateRequest + resources. If `encodeUsagesInRequest` is unset or set to `true`, the usages + will additionally be encoded in the `request` field which contains the CSR blob. + + If unset, defaults to `digital signature` and `key encipherment`. + items: + description: |- + KeyUsage specifies valid usage contexts for keys. + See: + https://tools.ietf.org/html/rfc5280#section-4.2.1.3 + https://tools.ietf.org/html/rfc5280#section-4.2.1.12 + + Valid KeyUsage values are as follows: + "signing", + "digital signature", + "content commitment", + "key encipherment", + "key agreement", + "data encipherment", + "cert sign", + "crl sign", + "encipher only", + "decipher only", + "any", + "server auth", + "client auth", + "code signing", + "email protection", + "s/mime", + "ipsec end system", + "ipsec tunnel", + "ipsec user", + "timestamping", + "ocsp signing", + "microsoft sgc", + "netscape sgc" + enum: + - signing + - digital signature + - content commitment + - key encipherment + - key agreement + - data encipherment + - cert sign + - crl sign + - encipher only + - decipher only + - any + - server auth + - client auth + - code signing + - email protection + - s/mime + - ipsec end system + - ipsec tunnel + - ipsec user + - timestamping + - ocsp signing + - microsoft sgc + - netscape sgc + type: string + type: array + x-kubernetes-list-type: atomic + required: + - issuerRef + - secretName + type: object + status: + description: |- + Status of the Certificate. + This is set and managed automatically. + Read-only. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + conditions: + description: |- + List of status conditions to indicate the status of certificates. + Known condition types are `Ready` and `Issuing`. + items: + description: CertificateCondition contains condition information for a Certificate. + properties: + lastTransitionTime: + description: |- + LastTransitionTime is the timestamp corresponding to the last status + change of this condition. + format: date-time + type: string + message: + description: |- + Message is a human readable description of the details of the last + transition, complementing reason. + type: string + observedGeneration: + description: |- + If set, this represents the .metadata.generation that the condition was + set based upon. + For instance, if .metadata.generation is currently 12, but the + .status.condition[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the Certificate. + format: int64 + type: integer + reason: + description: |- + Reason is a brief machine readable explanation for the condition's last + transition. + type: string + status: + description: Status of the condition, one of (`True`, `False`, `Unknown`). + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: Type of the condition, known values are (`Ready`, `Issuing`). + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + failedIssuanceAttempts: + description: |- + The number of continuous failed issuance attempts up till now. This + field gets removed (if set) on a successful issuance and gets set to + 1 if unset and an issuance has failed. If an issuance has failed, the + delay till the next issuance will be calculated using formula + time.Hour * 2 ^ (failedIssuanceAttempts - 1). + type: integer + lastFailureTime: + description: |- + LastFailureTime is set only if the latest issuance for this + Certificate failed and contains the time of the failure. If an + issuance has failed, the delay till the next issuance will be + calculated using formula time.Hour * 2 ^ (failedIssuanceAttempts - + 1). If the latest issuance has succeeded this field will be unset. + format: date-time + type: string + nextPrivateKeySecretName: + description: |- + The name of the Secret resource containing the private key to be used + for the next certificate iteration. + The keymanager controller will automatically set this field if the + `Issuing` condition is set to `True`. + It will automatically unset this field when the Issuing condition is + not set or False. + type: string + notAfter: + description: |- + The expiration time of the certificate stored in the secret named + by this resource in `spec.secretName`. + format: date-time + type: string + notBefore: + description: |- + The time after which the certificate stored in the secret named + by this resource in `spec.secretName` is valid. + format: date-time + type: string + renewalTime: + description: |- + RenewalTime is the time at which the certificate will be next + renewed. + If not set, no upcoming renewal is scheduled. + format: date-time + type: string + revision: + description: |- + The current 'revision' of the certificate as issued. + + When a CertificateRequest resource is created, it will have the + `cert-manager.io/certificate-revision` set to one greater than the + current value of this field. + + Upon issuance, this field will be set to the value of the annotation + on the CertificateRequest resource used to issue the certificate. + + Persisting the value on the CertificateRequest resource allows the + certificates controller to know whether a request is part of an old + issuance or if it is part of the ongoing revision's issuance by + checking if the revision value in the annotation is greater than this + field. + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} +{{- end }} diff --git a/packages/system/cert-manager-crds/templates/crd-cert-manager.io_clusterissuers.yaml b/packages/system/cert-manager-crds/templates/crd-cert-manager.io_clusterissuers.yaml new file mode 100644 index 00000000..790d4b5c --- /dev/null +++ b/packages/system/cert-manager-crds/templates/crd-cert-manager.io_clusterissuers.yaml @@ -0,0 +1,3815 @@ +{{- if or .Values.crds.enabled .Values.installCRDs }} +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: "clusterissuers.cert-manager.io" + {{- if .Values.crds.keep }} + annotations: + helm.sh/resource-policy: keep + {{- end }} + labels: + {{- include "cert-manager.crd-labels" . | nindent 4 }} +spec: + group: cert-manager.io + names: + categories: + - cert-manager + kind: ClusterIssuer + listKind: ClusterIssuerList + plural: clusterissuers + shortNames: + - ciss + singular: clusterissuer + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type == "Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type == "Ready")].message + name: Status + priority: 1 + type: string + - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: |- + A ClusterIssuer represents a certificate issuing authority which can be + referenced as part of `issuerRef` fields. + It is similar to an Issuer, however it is cluster-scoped and therefore can + be referenced by resources that exist in *any* namespace, not just the same + namespace as the referent. + 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: Desired state of the ClusterIssuer resource. + properties: + acme: + description: |- + ACME configures this issuer to communicate with a RFC8555 (ACME) server + to obtain signed x509 certificates. + properties: + caBundle: + description: |- + Base64-encoded bundle of PEM CAs which can be used to validate the certificate + chain presented by the ACME server. + Mutually exclusive with SkipTLSVerify; prefer using CABundle to prevent various + kinds of security vulnerabilities. + If CABundle and SkipTLSVerify are unset, the system certificate bundle inside + the container is used to validate the TLS connection. + format: byte + type: string + disableAccountKeyGeneration: + description: |- + Enables or disables generating a new ACME account key. + If true, the Issuer resource will *not* request a new account but will expect + the account key to be supplied via an existing secret. + If false, the cert-manager system will generate a new ACME account key + for the Issuer. + Defaults to false. + type: boolean + email: + description: |- + Email is the email address to be associated with the ACME account. + This field is optional, but it is strongly recommended to be set. + It will be used to contact you in case of issues with your account or + certificates, including expiry notification emails. + This field may be updated after the account is initially registered. + type: string + enableDurationFeature: + description: |- + Enables requesting a Not After date on certificates that matches the + duration of the certificate. This is not supported by all ACME servers + like Let's Encrypt. If set to true when the ACME server does not support + it, it will create an error on the Order. + Defaults to false. + type: boolean + externalAccountBinding: + description: |- + ExternalAccountBinding is a reference to a CA external account of the ACME + server. + If set, upon registration cert-manager will attempt to associate the given + external account credentials with the registered ACME account. + properties: + keyAlgorithm: + description: |- + Deprecated: keyAlgorithm field exists for historical compatibility + reasons and should not be used. The algorithm is now hardcoded to HS256 + in golang/x/crypto/acme. + enum: + - HS256 + - HS384 + - HS512 + type: string + keyID: + description: keyID is the ID of the CA key that the External Account is bound to. + type: string + keySecretRef: + description: |- + keySecretRef is a Secret Key Selector referencing a data item in a Kubernetes + Secret which holds the symmetric MAC key of the External Account Binding. + The `key` is the index string that is paired with the key data in the + Secret and should not be confused with the key data itself, or indeed with + the External Account Binding keyID above. + The secret key stored in the Secret **must** be un-padded, base64 URL + encoded data. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + required: + - keyID + - keySecretRef + type: object + preferredChain: + description: |- + PreferredChain is the chain to use if the ACME server outputs multiple. + PreferredChain is no guarantee that this one gets delivered by the ACME + endpoint. + For example, for Let's Encrypt's DST cross-sign you would use: + "DST Root CA X3" or "ISRG Root X1" for the newer Let's Encrypt root CA. + This value picks the first certificate bundle in the combined set of + ACME default and alternative chains that has a root-most certificate with + this value as its issuer's commonname. + maxLength: 64 + type: string + privateKeySecretRef: + description: |- + PrivateKey is the name of a Kubernetes Secret resource that will be used to + store the automatically generated ACME account private key. + Optionally, a `key` may be specified to select a specific entry within + the named Secret resource. + If `key` is not specified, a default of `tls.key` will be used. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + profile: + description: |- + Profile allows requesting a certificate profile from the ACME server. + Supported profiles are listed by the server's ACME directory URL. + type: string + server: + description: |- + Server is the URL used to access the ACME server's 'directory' endpoint. + For example, for Let's Encrypt's staging endpoint, you would use: + "https://acme-staging-v02.api.letsencrypt.org/directory". + Only ACME v2 endpoints (i.e. RFC 8555) are supported. + type: string + skipTLSVerify: + description: |- + INSECURE: Enables or disables validation of the ACME server TLS certificate. + If true, requests to the ACME server will not have the TLS certificate chain + validated. + Mutually exclusive with CABundle; prefer using CABundle to prevent various + kinds of security vulnerabilities. + Only enable this option in development environments. + If CABundle and SkipTLSVerify are unset, the system certificate bundle inside + the container is used to validate the TLS connection. + Defaults to false. + type: boolean + solvers: + description: |- + Solvers is a list of challenge solvers that will be used to solve + ACME challenges for the matching domains. + Solver configurations must be provided in order to obtain certificates + from an ACME server. + For more information, see: https://cert-manager.io/docs/configuration/acme/ + items: + description: |- + An ACMEChallengeSolver describes how to solve ACME challenges for the issuer it is part of. + A selector may be provided to use different solving strategies for different DNS names. + Only one of HTTP01 or DNS01 must be provided. + properties: + dns01: + description: |- + Configures cert-manager to attempt to complete authorizations by + performing the DNS01 challenge flow. + properties: + acmeDNS: + description: |- + Use the 'ACME DNS' (https://github.com/joohoi/acme-dns) API to manage + DNS01 challenge records. + properties: + accountSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + host: + type: string + required: + - accountSecretRef + - host + type: object + akamai: + description: Use the Akamai DNS zone management API to manage DNS01 challenge records. + properties: + accessTokenSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + clientSecretSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + clientTokenSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + serviceConsumerDomain: + type: string + required: + - accessTokenSecretRef + - clientSecretSecretRef + - clientTokenSecretRef + - serviceConsumerDomain + type: object + azureDNS: + description: Use the Microsoft Azure DNS API to manage DNS01 challenge records. + properties: + clientID: + description: |- + Auth: Azure Service Principal: + The ClientID of the Azure Service Principal used to authenticate with Azure DNS. + If set, ClientSecret and TenantID must also be set. + type: string + clientSecretSecretRef: + description: |- + Auth: Azure Service Principal: + A reference to a Secret containing the password associated with the Service Principal. + If set, ClientID and TenantID must also be set. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + environment: + description: name of the Azure environment (default AzurePublicCloud) + enum: + - AzurePublicCloud + - AzureChinaCloud + - AzureGermanCloud + - AzureUSGovernmentCloud + type: string + hostedZoneName: + description: name of the DNS zone that should be used + type: string + managedIdentity: + description: |- + Auth: Azure Workload Identity or Azure Managed Service Identity: + Settings to enable Azure Workload Identity or Azure Managed Service Identity + If set, ClientID, ClientSecret and TenantID must not be set. + properties: + clientID: + description: client ID of the managed identity, cannot be used at the same time as resourceID + type: string + resourceID: + description: |- + resource ID of the managed identity, cannot 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, cannot be used at the same time as resourceID + type: string + type: object + resourceGroupName: + description: resource group the DNS zone is located in + type: string + subscriptionID: + description: ID of the Azure subscription + type: string + tenantID: + description: |- + Auth: Azure Service Principal: + The TenantID of the Azure Service Principal used to authenticate with Azure DNS. + If set, ClientID and ClientSecret must also be set. + type: string + required: + - resourceGroupName + - subscriptionID + type: object + cloudDNS: + description: Use the Google Cloud DNS API to manage DNS01 challenge records. + properties: + hostedZoneName: + description: |- + HostedZoneName is an optional field that tells cert-manager in which + Cloud DNS zone the challenge record has to be created. + If left empty cert-manager will automatically choose a zone. + type: string + project: + type: string + serviceAccountSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + required: + - project + type: object + cloudflare: + description: Use the Cloudflare API to manage DNS01 challenge records. + properties: + apiKeySecretRef: + description: |- + API key to use to authenticate with Cloudflare. + Note: using an API token to authenticate is now the recommended method + as it allows greater control of permissions. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + apiTokenSecretRef: + description: API token used to authenticate with Cloudflare. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + email: + description: Email of the account, only required when using API key based authentication. + type: string + type: object + cnameStrategy: + description: |- + CNAMEStrategy configures how the DNS01 provider should handle CNAME + records when found in DNS zones. + enum: + - None + - Follow + type: string + digitalocean: + description: Use the DigitalOcean DNS API to manage DNS01 challenge records. + properties: + tokenSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + required: + - tokenSecretRef + type: object + rfc2136: + description: |- + Use RFC2136 ("Dynamic Updates in the Domain Name System") (https://datatracker.ietf.org/doc/rfc2136/) + to manage DNS01 challenge records. + properties: + nameserver: + description: |- + The IP address or hostname of an authoritative DNS server supporting + RFC2136 in the form host:port. If the host is an IPv6 address it must be + enclosed in square brackets (e.g [2001:db8::1]) ; port is optional. + This field is required. + type: string + protocol: + description: Protocol to use for dynamic DNS update queries. Valid values are (case-sensitive) ``TCP`` and ``UDP``; ``UDP`` (default). + enum: + - TCP + - UDP + type: string + tsigAlgorithm: + description: |- + The TSIG Algorithm configured in the DNS supporting RFC2136. Used only + when ``tsigSecretSecretRef`` and ``tsigKeyName`` are defined. + Supported values are (case-insensitive): ``HMACMD5`` (default), + ``HMACSHA1``, ``HMACSHA256`` or ``HMACSHA512``. + type: string + tsigKeyName: + description: |- + The TSIG Key name configured in the DNS. + If ``tsigSecretSecretRef`` is defined, this field is required. + type: string + tsigSecretSecretRef: + description: |- + The name of the secret containing the TSIG value. + If ``tsigKeyName`` is defined, this field is required. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + required: + - nameserver + type: object + route53: + description: Use the AWS Route53 API to manage DNS01 challenge records. + properties: + accessKeyID: + description: |- + The AccessKeyID is used for authentication. + Cannot be set when SecretAccessKeyID is set. + If neither the Access Key nor Key ID are set, we fall-back to using env + vars, shared credentials file or AWS Instance metadata, + see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials + type: string + accessKeyIDSecretRef: + description: |- + The SecretAccessKey is used for authentication. If set, pull the AWS + access key ID from a key within a Kubernetes Secret. + Cannot be set when AccessKeyID is set. + If neither the Access Key nor Key ID are set, we fall-back to using env + vars, shared credentials file or AWS Instance metadata, + see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + auth: + description: Auth configures how cert-manager authenticates. + properties: + kubernetes: + description: |- + Kubernetes authenticates with Route53 using AssumeRoleWithWebIdentity + by passing a bound ServiceAccount token. + properties: + serviceAccountRef: + description: |- + A reference to a service account that will be used to request a bound + token (also known as "projected token"). To use this field, you must + configure an RBAC rule to let cert-manager request a token. + properties: + audiences: + description: |- + TokenAudiences is an optional list of audiences to include in the + token passed to AWS. The default token consisting of the issuer's namespace + and name is always included. + If unset the audience defaults to `sts.amazonaws.com`. + items: + type: string + type: array + x-kubernetes-list-type: atomic + name: + description: Name of the ServiceAccount used to request a token. + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + required: + - kubernetes + type: object + hostedZoneID: + description: If set, the provider will manage only this zone in Route53 and will not do a lookup using the route53:ListHostedZonesByName api call. + type: string + region: + description: |- + Override the AWS region. + + Route53 is a global service and does not have regional endpoints but the + region specified here (or via environment variables) is used as a hint to + help compute the correct AWS credential scope and partition when it + connects to Route53. See: + - [Amazon Route 53 endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/r53.html) + - [Global services](https://docs.aws.amazon.com/whitepapers/latest/aws-fault-isolation-boundaries/global-services.html) + + If you omit this region field, cert-manager will use the region from + AWS_REGION and AWS_DEFAULT_REGION environment variables, if they are set + in the cert-manager controller Pod. + + The `region` field is not needed if you use [IAM Roles for Service Accounts (IRSA)](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html). + Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: + [Amazon EKS Pod Identity Webhook](https://github.com/aws/amazon-eks-pod-identity-webhook). + In this case this `region` field value is ignored. + + The `region` field is not needed if you use [EKS Pod Identities](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html). + Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: + [Amazon EKS Pod Identity Agent](https://github.com/aws/eks-pod-identity-agent), + In this case this `region` field value is ignored. + type: string + role: + description: |- + Role is a Role ARN which the Route53 provider will assume using either the explicit credentials AccessKeyID/SecretAccessKey + or the inferred credentials from environment variables, shared credentials file or AWS Instance metadata + type: string + secretAccessKeySecretRef: + description: |- + The SecretAccessKey is used for authentication. + If neither the Access Key nor Key ID are set, we fall-back to using env + vars, shared credentials file or AWS Instance metadata, + see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + type: object + webhook: + description: |- + Configure an external webhook based DNS01 challenge solver to manage + DNS01 challenge records. + properties: + config: + description: |- + Additional configuration that should be passed to the webhook apiserver + when challenges are processed. + This can contain arbitrary JSON data. + Secret values should not be specified in this stanza. + If secret values are needed (e.g., credentials for a DNS service), you + should use a SecretKeySelector to reference a Secret resource. + For details on the schema of this field, consult the webhook provider + implementation's documentation. + x-kubernetes-preserve-unknown-fields: true + groupName: + description: |- + The API group name that should be used when POSTing ChallengePayload + resources to the webhook apiserver. + This should be the same as the GroupName specified in the webhook + provider implementation. + type: string + solverName: + description: |- + The name of the solver to use, as defined in the webhook provider + implementation. + This will typically be the name of the provider, e.g., 'cloudflare'. + type: string + required: + - groupName + - solverName + type: object + type: object + http01: + description: |- + Configures cert-manager to attempt to complete authorizations by + performing the HTTP01 challenge flow. + It is not possible to obtain certificates for wildcard domain names + (e.g., `*.example.com`) using the HTTP01 challenge mechanism. + properties: + gatewayHTTPRoute: + description: |- + The Gateway API is a sig-network community API that models service networking + in Kubernetes (https://gateway-api.sigs.k8s.io/). The Gateway solver will + create HTTPRoutes with the specified labels in the same namespace as the challenge. + This solver is experimental, and fields / behaviour may change in the future. + properties: + labels: + additionalProperties: + type: string + description: |- + Custom labels that will be applied to HTTPRoutes created by cert-manager + while solving HTTP-01 challenges. + type: object + parentRefs: + description: |- + When solving an HTTP-01 challenge, cert-manager creates an HTTPRoute. + cert-manager needs to know which parentRefs should be used when creating + the HTTPRoute. Usually, the parentRef references a Gateway. See: + https://gateway-api.sigs.k8s.io/api-types/httproute/#attaching-to-gateways + 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 + type: array + x-kubernetes-list-type: atomic + podTemplate: + description: |- + Optional pod template used to configure the ACME challenge solver pods + used for HTTP01 challenges. + properties: + metadata: + description: |- + ObjectMeta overrides for the pod used to solve HTTP01 challenges. + Only the 'labels' and 'annotations' fields may be set. + If labels or annotations overlap with in-built values, the values here + will override the in-built values. + properties: + annotations: + additionalProperties: + type: string + description: Annotations that should be added to the created ACME HTTP01 solver pods. + type: object + labels: + additionalProperties: + type: string + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + type: object + spec: + description: |- + PodSpec defines overrides for the HTTP01 challenge solver pod. + Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. + All other fields will be ignored. + properties: + affinity: + description: If specified, the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + imagePullSecrets: + description: If specified, the pod's imagePullSecrets + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector is a selector which must be true for the pod to fit on a node. + Selector which must match a node's labels for the pod to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + resources: + description: |- + If specified, the pod's resource requirements. + These values override the global resource configuration flags. + Note that when only specifying resource limits, ensure they are greater than or equal + to the corresponding global resource requests configured via controller flags + (--acme-http01-solver-resource-request-cpu, --acme-http01-solver-resource-request-memory). + Kubernetes will reject pod creation if limits are lower than requests, causing challenge failures. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to the global values configured via controller flags. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + securityContext: + description: If specified, the pod's security context + properties: + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in addition + to the container's primary GID, the fsGroup (if specified), and group memberships + defined in the container image for the uid of the container process. If unspecified, + no additional groups are added to any container. Note that group memberships + defined in the container image for the uid of the container process are still effective, + even if they are not included in this list. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + type: object + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + serviceType: + description: |- + Optional service type for Kubernetes solver service. Supported values + are NodePort or ClusterIP. If unset, defaults to NodePort. + type: string + type: object + ingress: + description: |- + The ingress based HTTP01 challenge solver will solve challenges by + creating or modifying Ingress resources in order to route requests for + '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are + provisioned by cert-manager for each Challenge to be completed. + properties: + class: + description: |- + This field configures the annotation `kubernetes.io/ingress.class` when + creating Ingress resources to solve ACME challenges that use this + challenge solver. Only one of `class`, `name` or `ingressClassName` may + be specified. + type: string + ingressClassName: + description: |- + This field configures the field `ingressClassName` on the created Ingress + resources used to solve ACME challenges that use this challenge solver. + This is the recommended way of configuring the ingress class. Only one of + `class`, `name` or `ingressClassName` may be specified. + type: string + ingressTemplate: + description: |- + Optional ingress template used to configure the ACME challenge solver + ingress used for HTTP01 challenges. + properties: + metadata: + description: |- + ObjectMeta overrides for the ingress used to solve HTTP01 challenges. + Only the 'labels' and 'annotations' fields may be set. + If labels or annotations overlap with in-built values, the values here + will override the in-built values. + properties: + annotations: + additionalProperties: + type: string + description: Annotations that should be added to the created ACME HTTP01 solver ingress. + type: object + labels: + additionalProperties: + type: string + description: Labels that should be added to the created ACME HTTP01 solver ingress. + type: object + type: object + type: object + name: + description: |- + The name of the ingress resource that should have ACME challenge solving + routes inserted into it in order to solve HTTP01 challenges. + This is typically used in conjunction with ingress controllers like + ingress-gce, which maintains a 1:1 mapping between external IPs and + ingress resources. Only one of `class`, `name` or `ingressClassName` may + be specified. + type: string + podTemplate: + description: |- + Optional pod template used to configure the ACME challenge solver pods + used for HTTP01 challenges. + properties: + metadata: + description: |- + ObjectMeta overrides for the pod used to solve HTTP01 challenges. + Only the 'labels' and 'annotations' fields may be set. + If labels or annotations overlap with in-built values, the values here + will override the in-built values. + properties: + annotations: + additionalProperties: + type: string + description: Annotations that should be added to the created ACME HTTP01 solver pods. + type: object + labels: + additionalProperties: + type: string + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + type: object + spec: + description: |- + PodSpec defines overrides for the HTTP01 challenge solver pod. + Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. + All other fields will be ignored. + properties: + affinity: + description: If specified, the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + imagePullSecrets: + description: If specified, the pod's imagePullSecrets + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector is a selector which must be true for the pod to fit on a node. + Selector which must match a node's labels for the pod to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + resources: + description: |- + If specified, the pod's resource requirements. + These values override the global resource configuration flags. + Note that when only specifying resource limits, ensure they are greater than or equal + to the corresponding global resource requests configured via controller flags + (--acme-http01-solver-resource-request-cpu, --acme-http01-solver-resource-request-memory). + Kubernetes will reject pod creation if limits are lower than requests, causing challenge failures. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to the global values configured via controller flags. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + securityContext: + description: If specified, the pod's security context + properties: + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in addition + to the container's primary GID, the fsGroup (if specified), and group memberships + defined in the container image for the uid of the container process. If unspecified, + no additional groups are added to any container. Note that group memberships + defined in the container image for the uid of the container process are still effective, + even if they are not included in this list. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + type: object + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + serviceType: + description: |- + Optional service type for Kubernetes solver service. Supported values + are NodePort or ClusterIP. If unset, defaults to NodePort. + type: string + type: object + type: object + selector: + description: |- + Selector selects a set of DNSNames on the Certificate resource that + should be solved using this challenge solver. + If not specified, the solver will be treated as the 'default' solver + with the lowest priority, i.e. if any other solver has a more specific + match, it will be used instead. + properties: + dnsNames: + description: |- + List of DNSNames that this solver will be used to solve. + If specified and a match is found, a dnsNames selector will take + precedence over a dnsZones selector. + If multiple solvers match with the same dnsNames value, the solver + with the most matching labels in matchLabels will be selected. + If neither has more matches, the solver defined earlier in the list + will be selected. + items: + type: string + type: array + x-kubernetes-list-type: atomic + dnsZones: + description: |- + List of DNSZones that this solver will be used to solve. + The most specific DNS zone match specified here will take precedence + over other DNS zone matches, so a solver specifying sys.example.com + will be selected over one specifying example.com for the domain + www.sys.example.com. + If multiple solvers match with the same dnsZones value, the solver + with the most matching labels in matchLabels will be selected. + If neither has more matches, the solver defined earlier in the list + will be selected. + items: + type: string + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + A label selector that is used to refine the set of certificate's that + this challenge solver will apply to. + type: object + type: object + type: object + type: array + x-kubernetes-list-type: atomic + required: + - privateKeySecretRef + - server + type: object + ca: + description: |- + CA configures this issuer to sign certificates using a signing CA keypair + stored in a Secret resource. + This is used to build internal PKIs that are managed by cert-manager. + properties: + crlDistributionPoints: + description: |- + The CRL distribution points is an X.509 v3 certificate extension which identifies + the location of the CRL from which the revocation of this certificate can be checked. + If not set, certificates will be issued without distribution points set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + issuingCertificateURLs: + description: |- + IssuingCertificateURLs is a list of URLs which this issuer should embed into certificates + it creates. See https://www.rfc-editor.org/rfc/rfc5280#section-4.2.2.1 for more details. + As an example, such a URL might be "http://ca.domain.com/ca.crt". + items: + type: string + type: array + x-kubernetes-list-type: atomic + ocspServers: + description: |- + The OCSP server list is an X.509 v3 extension that defines a list of + URLs of OCSP responders. The OCSP responders can be queried for the + revocation status of an issued certificate. If not set, the + certificate will be issued with no OCSP servers set. For example, an + OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org". + items: + type: string + type: array + x-kubernetes-list-type: atomic + secretName: + description: |- + SecretName is the name of the secret used to sign Certificates issued + by this Issuer. + type: string + required: + - secretName + type: object + selfSigned: + description: |- + SelfSigned configures this issuer to 'self sign' certificates using the + private key used to create the CertificateRequest object. + properties: + crlDistributionPoints: + description: |- + The CRL distribution points is an X.509 v3 certificate extension which identifies + the location of the CRL from which the revocation of this certificate can be checked. + If not set certificate will be issued without CDP. Values are strings. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + vault: + description: |- + Vault configures this issuer to sign certificates using a HashiCorp Vault + PKI backend. + properties: + auth: + description: Auth configures how cert-manager authenticates with the Vault server. + properties: + appRole: + description: |- + AppRole authenticates with Vault using the App Role auth mechanism, + with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + description: |- + Path where the App Role authentication backend is mounted in Vault, e.g: + "approle" + type: string + roleId: + description: |- + RoleID configured in the App Role authentication backend when setting + up the authentication backend in Vault. + type: string + secretRef: + description: |- + Reference to a key in a Secret that contains the App Role secret used + to authenticate with Vault. + The `key` field must be specified and denotes which entry within the Secret + resource is used as the app role secret. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + required: + - path + - roleId + - secretRef + type: object + clientCertificate: + description: |- + ClientCertificate authenticates with Vault by presenting a client + certificate during the request's TLS handshake. + Works only when using HTTPS protocol. + properties: + mountPath: + description: |- + The Vault mountPath here is the mount path to use when authenticating with + Vault. For example, setting a value to `/v1/auth/foo`, will use the path + `/v1/auth/foo/login` to authenticate with Vault. If unspecified, the + default value "/v1/auth/cert" will be used. + type: string + name: + description: |- + Name of the certificate role to authenticate against. + If not set, matching any certificate role, if available. + type: string + secretName: + description: |- + Reference to Kubernetes Secret of type "kubernetes.io/tls" (hence containing + tls.crt and tls.key) used to authenticate to Vault using TLS client + authentication. + type: string + type: object + kubernetes: + description: |- + Kubernetes authenticates with Vault by passing the ServiceAccount + token stored in the named Secret resource to the Vault server. + properties: + mountPath: + description: |- + The Vault mountPath here is the mount path to use when authenticating with + Vault. For example, setting a value to `/v1/auth/foo`, will use the path + `/v1/auth/foo/login` to authenticate with Vault. If unspecified, the + default value "/v1/auth/kubernetes" will be used. + type: string + role: + description: |- + A required field containing the Vault Role to assume. A Role binds a + Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: |- + The required Secret field containing a Kubernetes ServiceAccount JWT used + for authenticating with Vault. Use of 'ambient credentials' is not + supported. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + serviceAccountRef: + description: |- + A reference to a service account that will be used to request a bound + token (also known as "projected token"). Compared to using "secretRef", + using this field means that you don't rely on statically bound tokens. To + use this field, you must configure an RBAC rule to let cert-manager + request a token. + properties: + audiences: + description: |- + TokenAudiences is an optional list of extra audiences to include in the token passed to Vault. The default token + consisting of the issuer's namespace and name is always included. + items: + type: string + type: array + x-kubernetes-list-type: atomic + name: + description: Name of the ServiceAccount used to request a token. + type: string + required: + - name + type: object + required: + - role + type: object + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + type: object + caBundle: + description: |- + Base64-encoded bundle of PEM CAs which will be used to validate the certificate + chain presented by Vault. Only used if using HTTPS to connect to Vault and + ignored for HTTP connections. + Mutually exclusive with CABundleSecretRef. + If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in + the cert-manager controller container is used to validate the TLS connection. + format: byte + type: string + caBundleSecretRef: + description: |- + Reference to a Secret containing a bundle of PEM-encoded CAs to use when + verifying the certificate chain presented by Vault when using HTTPS. + Mutually exclusive with CABundle. + If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in + the cert-manager controller container is used to validate the TLS connection. + If no key for the Secret is specified, cert-manager will default to 'ca.crt'. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + clientCertSecretRef: + description: |- + Reference to a Secret containing a PEM-encoded Client Certificate to use when the + Vault server requires mTLS. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + clientKeySecretRef: + description: |- + Reference to a Secret containing a PEM-encoded Client Private Key to use when the + Vault server requires mTLS. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + namespace: + description: |- + Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1" + More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces + type: string + path: + description: |- + Path is the mount path of the Vault PKI backend's `sign` endpoint, e.g: + "my_pki_mount/sign/my-role-name". + type: string + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + serverName: + description: |- + ServerName is used to verify the hostname on the returned certificates + by the Vault server. + type: string + required: + - auth + - path + - server + type: object + venafi: + description: |- + Venafi configures this issuer to sign certificates using a Venafi TPP + or Venafi Cloud policy zone. + properties: + cloud: + description: |- + Cloud specifies the Venafi cloud configuration settings. + Only one of TPP or Cloud may be specified. + properties: + apiTokenSecretRef: + description: APITokenSecretRef is a secret key selector for the Venafi Cloud API token. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + url: + description: |- + URL is the base URL for Venafi Cloud. + Defaults to "https://api.venafi.cloud/". + type: string + required: + - apiTokenSecretRef + type: object + tpp: + description: |- + TPP specifies Trust Protection Platform configuration settings. + Only one of TPP or Cloud may be specified. + properties: + caBundle: + description: |- + Base64-encoded bundle of PEM CAs which will be used to validate the certificate + chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP. + If undefined, the certificate bundle in the cert-manager controller container + is used to validate the chain. + format: byte + type: string + caBundleSecretRef: + description: |- + Reference to a Secret containing a base64-encoded bundle of PEM CAs + which will be used to validate the certificate chain presented by the TPP server. + Only used if using HTTPS; ignored for HTTP. Mutually exclusive with CABundle. + If neither CABundle nor CABundleSecretRef is defined, the certificate bundle in + the cert-manager controller container is used to validate the TLS connection. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + credentialsRef: + description: |- + CredentialsRef is a reference to a Secret containing the Venafi TPP API credentials. + The secret must contain the key 'access-token' for the Access Token Authentication, + or two keys, 'username' and 'password' for the API Keys Authentication. + properties: + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + url: + description: |- + URL is the base URL for the vedsdk endpoint of the Venafi TPP instance, + for example: "https://tpp.example.com/vedsdk". + type: string + required: + - credentialsRef + - url + type: object + zone: + description: |- + Zone is the Venafi Policy Zone to use for this issuer. + All requests made to the Venafi platform will be restricted by the named + zone policy. + This field is required. + type: string + required: + - zone + type: object + type: object + status: + description: Status of the ClusterIssuer. This is set and managed automatically. + properties: + acme: + description: |- + ACME specific status options. + This field should only be set if the Issuer is configured to use an ACME + server to issue certificates. + properties: + lastPrivateKeyHash: + description: |- + LastPrivateKeyHash is a hash of the private key associated with the latest + registered ACME account, in order to track changes made to registered account + associated with the Issuer + type: string + lastRegisteredEmail: + description: |- + LastRegisteredEmail is the email associated with the latest registered + ACME account, in order to track changes made to registered account + associated with the Issuer + type: string + uri: + description: |- + URI is the unique account identifier, which can also be used to retrieve + account details from the CA + type: string + type: object + conditions: + description: |- + List of status conditions to indicate the status of a CertificateRequest. + Known condition types are `Ready`. + items: + description: IssuerCondition contains condition information for an Issuer. + properties: + lastTransitionTime: + description: |- + LastTransitionTime is the timestamp corresponding to the last status + change of this condition. + format: date-time + type: string + message: + description: |- + Message is a human readable description of the details of the last + transition, complementing reason. + type: string + observedGeneration: + description: |- + If set, this represents the .metadata.generation that the condition was + set based upon. + For instance, if .metadata.generation is currently 12, but the + .status.condition[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the Issuer. + format: int64 + type: integer + reason: + description: |- + Reason is a brief machine readable explanation for the condition's last + transition. + type: string + status: + description: Status of the condition, one of (`True`, `False`, `Unknown`). + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: Type of the condition, known values are (`Ready`). + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +{{- end }} diff --git a/packages/system/cert-manager-crds/templates/crd-cert-manager.io_issuers.yaml b/packages/system/cert-manager-crds/templates/crd-cert-manager.io_issuers.yaml new file mode 100644 index 00000000..43277f84 --- /dev/null +++ b/packages/system/cert-manager-crds/templates/crd-cert-manager.io_issuers.yaml @@ -0,0 +1,3814 @@ +{{- if or .Values.crds.enabled .Values.installCRDs }} +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: "issuers.cert-manager.io" + {{- if .Values.crds.keep }} + annotations: + helm.sh/resource-policy: keep + {{- end }} + labels: + {{- include "cert-manager.crd-labels" . | nindent 4 }} +spec: + group: cert-manager.io + names: + categories: + - cert-manager + kind: Issuer + listKind: IssuerList + plural: issuers + shortNames: + - iss + singular: issuer + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type == "Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type == "Ready")].message + name: Status + priority: 1 + type: string + - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: |- + An Issuer represents a certificate issuing authority which can be + referenced as part of `issuerRef` fields. + It is scoped to a single namespace and can therefore only be referenced by + resources within the same namespace. + 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: Desired state of the Issuer resource. + properties: + acme: + description: |- + ACME configures this issuer to communicate with a RFC8555 (ACME) server + to obtain signed x509 certificates. + properties: + caBundle: + description: |- + Base64-encoded bundle of PEM CAs which can be used to validate the certificate + chain presented by the ACME server. + Mutually exclusive with SkipTLSVerify; prefer using CABundle to prevent various + kinds of security vulnerabilities. + If CABundle and SkipTLSVerify are unset, the system certificate bundle inside + the container is used to validate the TLS connection. + format: byte + type: string + disableAccountKeyGeneration: + description: |- + Enables or disables generating a new ACME account key. + If true, the Issuer resource will *not* request a new account but will expect + the account key to be supplied via an existing secret. + If false, the cert-manager system will generate a new ACME account key + for the Issuer. + Defaults to false. + type: boolean + email: + description: |- + Email is the email address to be associated with the ACME account. + This field is optional, but it is strongly recommended to be set. + It will be used to contact you in case of issues with your account or + certificates, including expiry notification emails. + This field may be updated after the account is initially registered. + type: string + enableDurationFeature: + description: |- + Enables requesting a Not After date on certificates that matches the + duration of the certificate. This is not supported by all ACME servers + like Let's Encrypt. If set to true when the ACME server does not support + it, it will create an error on the Order. + Defaults to false. + type: boolean + externalAccountBinding: + description: |- + ExternalAccountBinding is a reference to a CA external account of the ACME + server. + If set, upon registration cert-manager will attempt to associate the given + external account credentials with the registered ACME account. + properties: + keyAlgorithm: + description: |- + Deprecated: keyAlgorithm field exists for historical compatibility + reasons and should not be used. The algorithm is now hardcoded to HS256 + in golang/x/crypto/acme. + enum: + - HS256 + - HS384 + - HS512 + type: string + keyID: + description: keyID is the ID of the CA key that the External Account is bound to. + type: string + keySecretRef: + description: |- + keySecretRef is a Secret Key Selector referencing a data item in a Kubernetes + Secret which holds the symmetric MAC key of the External Account Binding. + The `key` is the index string that is paired with the key data in the + Secret and should not be confused with the key data itself, or indeed with + the External Account Binding keyID above. + The secret key stored in the Secret **must** be un-padded, base64 URL + encoded data. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + required: + - keyID + - keySecretRef + type: object + preferredChain: + description: |- + PreferredChain is the chain to use if the ACME server outputs multiple. + PreferredChain is no guarantee that this one gets delivered by the ACME + endpoint. + For example, for Let's Encrypt's DST cross-sign you would use: + "DST Root CA X3" or "ISRG Root X1" for the newer Let's Encrypt root CA. + This value picks the first certificate bundle in the combined set of + ACME default and alternative chains that has a root-most certificate with + this value as its issuer's commonname. + maxLength: 64 + type: string + privateKeySecretRef: + description: |- + PrivateKey is the name of a Kubernetes Secret resource that will be used to + store the automatically generated ACME account private key. + Optionally, a `key` may be specified to select a specific entry within + the named Secret resource. + If `key` is not specified, a default of `tls.key` will be used. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + profile: + description: |- + Profile allows requesting a certificate profile from the ACME server. + Supported profiles are listed by the server's ACME directory URL. + type: string + server: + description: |- + Server is the URL used to access the ACME server's 'directory' endpoint. + For example, for Let's Encrypt's staging endpoint, you would use: + "https://acme-staging-v02.api.letsencrypt.org/directory". + Only ACME v2 endpoints (i.e. RFC 8555) are supported. + type: string + skipTLSVerify: + description: |- + INSECURE: Enables or disables validation of the ACME server TLS certificate. + If true, requests to the ACME server will not have the TLS certificate chain + validated. + Mutually exclusive with CABundle; prefer using CABundle to prevent various + kinds of security vulnerabilities. + Only enable this option in development environments. + If CABundle and SkipTLSVerify are unset, the system certificate bundle inside + the container is used to validate the TLS connection. + Defaults to false. + type: boolean + solvers: + description: |- + Solvers is a list of challenge solvers that will be used to solve + ACME challenges for the matching domains. + Solver configurations must be provided in order to obtain certificates + from an ACME server. + For more information, see: https://cert-manager.io/docs/configuration/acme/ + items: + description: |- + An ACMEChallengeSolver describes how to solve ACME challenges for the issuer it is part of. + A selector may be provided to use different solving strategies for different DNS names. + Only one of HTTP01 or DNS01 must be provided. + properties: + dns01: + description: |- + Configures cert-manager to attempt to complete authorizations by + performing the DNS01 challenge flow. + properties: + acmeDNS: + description: |- + Use the 'ACME DNS' (https://github.com/joohoi/acme-dns) API to manage + DNS01 challenge records. + properties: + accountSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + host: + type: string + required: + - accountSecretRef + - host + type: object + akamai: + description: Use the Akamai DNS zone management API to manage DNS01 challenge records. + properties: + accessTokenSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + clientSecretSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + clientTokenSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + serviceConsumerDomain: + type: string + required: + - accessTokenSecretRef + - clientSecretSecretRef + - clientTokenSecretRef + - serviceConsumerDomain + type: object + azureDNS: + description: Use the Microsoft Azure DNS API to manage DNS01 challenge records. + properties: + clientID: + description: |- + Auth: Azure Service Principal: + The ClientID of the Azure Service Principal used to authenticate with Azure DNS. + If set, ClientSecret and TenantID must also be set. + type: string + clientSecretSecretRef: + description: |- + Auth: Azure Service Principal: + A reference to a Secret containing the password associated with the Service Principal. + If set, ClientID and TenantID must also be set. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + environment: + description: name of the Azure environment (default AzurePublicCloud) + enum: + - AzurePublicCloud + - AzureChinaCloud + - AzureGermanCloud + - AzureUSGovernmentCloud + type: string + hostedZoneName: + description: name of the DNS zone that should be used + type: string + managedIdentity: + description: |- + Auth: Azure Workload Identity or Azure Managed Service Identity: + Settings to enable Azure Workload Identity or Azure Managed Service Identity + If set, ClientID, ClientSecret and TenantID must not be set. + properties: + clientID: + description: client ID of the managed identity, cannot be used at the same time as resourceID + type: string + resourceID: + description: |- + resource ID of the managed identity, cannot 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, cannot be used at the same time as resourceID + type: string + type: object + resourceGroupName: + description: resource group the DNS zone is located in + type: string + subscriptionID: + description: ID of the Azure subscription + type: string + tenantID: + description: |- + Auth: Azure Service Principal: + The TenantID of the Azure Service Principal used to authenticate with Azure DNS. + If set, ClientID and ClientSecret must also be set. + type: string + required: + - resourceGroupName + - subscriptionID + type: object + cloudDNS: + description: Use the Google Cloud DNS API to manage DNS01 challenge records. + properties: + hostedZoneName: + description: |- + HostedZoneName is an optional field that tells cert-manager in which + Cloud DNS zone the challenge record has to be created. + If left empty cert-manager will automatically choose a zone. + type: string + project: + type: string + serviceAccountSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + required: + - project + type: object + cloudflare: + description: Use the Cloudflare API to manage DNS01 challenge records. + properties: + apiKeySecretRef: + description: |- + API key to use to authenticate with Cloudflare. + Note: using an API token to authenticate is now the recommended method + as it allows greater control of permissions. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + apiTokenSecretRef: + description: API token used to authenticate with Cloudflare. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + email: + description: Email of the account, only required when using API key based authentication. + type: string + type: object + cnameStrategy: + description: |- + CNAMEStrategy configures how the DNS01 provider should handle CNAME + records when found in DNS zones. + enum: + - None + - Follow + type: string + digitalocean: + description: Use the DigitalOcean DNS API to manage DNS01 challenge records. + properties: + tokenSecretRef: + description: |- + A reference to a specific 'key' within a Secret resource. + In some instances, `key` is a required field. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + required: + - tokenSecretRef + type: object + rfc2136: + description: |- + Use RFC2136 ("Dynamic Updates in the Domain Name System") (https://datatracker.ietf.org/doc/rfc2136/) + to manage DNS01 challenge records. + properties: + nameserver: + description: |- + The IP address or hostname of an authoritative DNS server supporting + RFC2136 in the form host:port. If the host is an IPv6 address it must be + enclosed in square brackets (e.g [2001:db8::1]) ; port is optional. + This field is required. + type: string + protocol: + description: Protocol to use for dynamic DNS update queries. Valid values are (case-sensitive) ``TCP`` and ``UDP``; ``UDP`` (default). + enum: + - TCP + - UDP + type: string + tsigAlgorithm: + description: |- + The TSIG Algorithm configured in the DNS supporting RFC2136. Used only + when ``tsigSecretSecretRef`` and ``tsigKeyName`` are defined. + Supported values are (case-insensitive): ``HMACMD5`` (default), + ``HMACSHA1``, ``HMACSHA256`` or ``HMACSHA512``. + type: string + tsigKeyName: + description: |- + The TSIG Key name configured in the DNS. + If ``tsigSecretSecretRef`` is defined, this field is required. + type: string + tsigSecretSecretRef: + description: |- + The name of the secret containing the TSIG value. + If ``tsigKeyName`` is defined, this field is required. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + required: + - nameserver + type: object + route53: + description: Use the AWS Route53 API to manage DNS01 challenge records. + properties: + accessKeyID: + description: |- + The AccessKeyID is used for authentication. + Cannot be set when SecretAccessKeyID is set. + If neither the Access Key nor Key ID are set, we fall-back to using env + vars, shared credentials file or AWS Instance metadata, + see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials + type: string + accessKeyIDSecretRef: + description: |- + The SecretAccessKey is used for authentication. If set, pull the AWS + access key ID from a key within a Kubernetes Secret. + Cannot be set when AccessKeyID is set. + If neither the Access Key nor Key ID are set, we fall-back to using env + vars, shared credentials file or AWS Instance metadata, + see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + auth: + description: Auth configures how cert-manager authenticates. + properties: + kubernetes: + description: |- + Kubernetes authenticates with Route53 using AssumeRoleWithWebIdentity + by passing a bound ServiceAccount token. + properties: + serviceAccountRef: + description: |- + A reference to a service account that will be used to request a bound + token (also known as "projected token"). To use this field, you must + configure an RBAC rule to let cert-manager request a token. + properties: + audiences: + description: |- + TokenAudiences is an optional list of audiences to include in the + token passed to AWS. The default token consisting of the issuer's namespace + and name is always included. + If unset the audience defaults to `sts.amazonaws.com`. + items: + type: string + type: array + x-kubernetes-list-type: atomic + name: + description: Name of the ServiceAccount used to request a token. + type: string + required: + - name + type: object + required: + - serviceAccountRef + type: object + required: + - kubernetes + type: object + hostedZoneID: + description: If set, the provider will manage only this zone in Route53 and will not do a lookup using the route53:ListHostedZonesByName api call. + type: string + region: + description: |- + Override the AWS region. + + Route53 is a global service and does not have regional endpoints but the + region specified here (or via environment variables) is used as a hint to + help compute the correct AWS credential scope and partition when it + connects to Route53. See: + - [Amazon Route 53 endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/r53.html) + - [Global services](https://docs.aws.amazon.com/whitepapers/latest/aws-fault-isolation-boundaries/global-services.html) + + If you omit this region field, cert-manager will use the region from + AWS_REGION and AWS_DEFAULT_REGION environment variables, if they are set + in the cert-manager controller Pod. + + The `region` field is not needed if you use [IAM Roles for Service Accounts (IRSA)](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html). + Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: + [Amazon EKS Pod Identity Webhook](https://github.com/aws/amazon-eks-pod-identity-webhook). + In this case this `region` field value is ignored. + + The `region` field is not needed if you use [EKS Pod Identities](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html). + Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: + [Amazon EKS Pod Identity Agent](https://github.com/aws/eks-pod-identity-agent), + In this case this `region` field value is ignored. + type: string + role: + description: |- + Role is a Role ARN which the Route53 provider will assume using either the explicit credentials AccessKeyID/SecretAccessKey + or the inferred credentials from environment variables, shared credentials file or AWS Instance metadata + type: string + secretAccessKeySecretRef: + description: |- + The SecretAccessKey is used for authentication. + If neither the Access Key nor Key ID are set, we fall-back to using env + vars, shared credentials file or AWS Instance metadata, + see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + type: object + webhook: + description: |- + Configure an external webhook based DNS01 challenge solver to manage + DNS01 challenge records. + properties: + config: + description: |- + Additional configuration that should be passed to the webhook apiserver + when challenges are processed. + This can contain arbitrary JSON data. + Secret values should not be specified in this stanza. + If secret values are needed (e.g., credentials for a DNS service), you + should use a SecretKeySelector to reference a Secret resource. + For details on the schema of this field, consult the webhook provider + implementation's documentation. + x-kubernetes-preserve-unknown-fields: true + groupName: + description: |- + The API group name that should be used when POSTing ChallengePayload + resources to the webhook apiserver. + This should be the same as the GroupName specified in the webhook + provider implementation. + type: string + solverName: + description: |- + The name of the solver to use, as defined in the webhook provider + implementation. + This will typically be the name of the provider, e.g., 'cloudflare'. + type: string + required: + - groupName + - solverName + type: object + type: object + http01: + description: |- + Configures cert-manager to attempt to complete authorizations by + performing the HTTP01 challenge flow. + It is not possible to obtain certificates for wildcard domain names + (e.g., `*.example.com`) using the HTTP01 challenge mechanism. + properties: + gatewayHTTPRoute: + description: |- + The Gateway API is a sig-network community API that models service networking + in Kubernetes (https://gateway-api.sigs.k8s.io/). The Gateway solver will + create HTTPRoutes with the specified labels in the same namespace as the challenge. + This solver is experimental, and fields / behaviour may change in the future. + properties: + labels: + additionalProperties: + type: string + description: |- + Custom labels that will be applied to HTTPRoutes created by cert-manager + while solving HTTP-01 challenges. + type: object + parentRefs: + description: |- + When solving an HTTP-01 challenge, cert-manager creates an HTTPRoute. + cert-manager needs to know which parentRefs should be used when creating + the HTTPRoute. Usually, the parentRef references a Gateway. See: + https://gateway-api.sigs.k8s.io/api-types/httproute/#attaching-to-gateways + 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 + type: array + x-kubernetes-list-type: atomic + podTemplate: + description: |- + Optional pod template used to configure the ACME challenge solver pods + used for HTTP01 challenges. + properties: + metadata: + description: |- + ObjectMeta overrides for the pod used to solve HTTP01 challenges. + Only the 'labels' and 'annotations' fields may be set. + If labels or annotations overlap with in-built values, the values here + will override the in-built values. + properties: + annotations: + additionalProperties: + type: string + description: Annotations that should be added to the created ACME HTTP01 solver pods. + type: object + labels: + additionalProperties: + type: string + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + type: object + spec: + description: |- + PodSpec defines overrides for the HTTP01 challenge solver pod. + Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. + All other fields will be ignored. + properties: + affinity: + description: If specified, the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + imagePullSecrets: + description: If specified, the pod's imagePullSecrets + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector is a selector which must be true for the pod to fit on a node. + Selector which must match a node's labels for the pod to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + resources: + description: |- + If specified, the pod's resource requirements. + These values override the global resource configuration flags. + Note that when only specifying resource limits, ensure they are greater than or equal + to the corresponding global resource requests configured via controller flags + (--acme-http01-solver-resource-request-cpu, --acme-http01-solver-resource-request-memory). + Kubernetes will reject pod creation if limits are lower than requests, causing challenge failures. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to the global values configured via controller flags. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + securityContext: + description: If specified, the pod's security context + properties: + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in addition + to the container's primary GID, the fsGroup (if specified), and group memberships + defined in the container image for the uid of the container process. If unspecified, + no additional groups are added to any container. Note that group memberships + defined in the container image for the uid of the container process are still effective, + even if they are not included in this list. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + type: object + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + serviceType: + description: |- + Optional service type for Kubernetes solver service. Supported values + are NodePort or ClusterIP. If unset, defaults to NodePort. + type: string + type: object + ingress: + description: |- + The ingress based HTTP01 challenge solver will solve challenges by + creating or modifying Ingress resources in order to route requests for + '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are + provisioned by cert-manager for each Challenge to be completed. + properties: + class: + description: |- + This field configures the annotation `kubernetes.io/ingress.class` when + creating Ingress resources to solve ACME challenges that use this + challenge solver. Only one of `class`, `name` or `ingressClassName` may + be specified. + type: string + ingressClassName: + description: |- + This field configures the field `ingressClassName` on the created Ingress + resources used to solve ACME challenges that use this challenge solver. + This is the recommended way of configuring the ingress class. Only one of + `class`, `name` or `ingressClassName` may be specified. + type: string + ingressTemplate: + description: |- + Optional ingress template used to configure the ACME challenge solver + ingress used for HTTP01 challenges. + properties: + metadata: + description: |- + ObjectMeta overrides for the ingress used to solve HTTP01 challenges. + Only the 'labels' and 'annotations' fields may be set. + If labels or annotations overlap with in-built values, the values here + will override the in-built values. + properties: + annotations: + additionalProperties: + type: string + description: Annotations that should be added to the created ACME HTTP01 solver ingress. + type: object + labels: + additionalProperties: + type: string + description: Labels that should be added to the created ACME HTTP01 solver ingress. + type: object + type: object + type: object + name: + description: |- + The name of the ingress resource that should have ACME challenge solving + routes inserted into it in order to solve HTTP01 challenges. + This is typically used in conjunction with ingress controllers like + ingress-gce, which maintains a 1:1 mapping between external IPs and + ingress resources. Only one of `class`, `name` or `ingressClassName` may + be specified. + type: string + podTemplate: + description: |- + Optional pod template used to configure the ACME challenge solver pods + used for HTTP01 challenges. + properties: + metadata: + description: |- + ObjectMeta overrides for the pod used to solve HTTP01 challenges. + Only the 'labels' and 'annotations' fields may be set. + If labels or annotations overlap with in-built values, the values here + will override the in-built values. + properties: + annotations: + additionalProperties: + type: string + description: Annotations that should be added to the created ACME HTTP01 solver pods. + type: object + labels: + additionalProperties: + type: string + description: Labels that should be added to the created ACME HTTP01 solver pods. + type: object + type: object + spec: + description: |- + PodSpec defines overrides for the HTTP01 challenge solver pod. + Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. + All other fields will be ignored. + properties: + affinity: + description: If specified, the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + imagePullSecrets: + description: If specified, the pod's imagePullSecrets + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector is a selector which must be true for the pod to fit on a node. + Selector which must match a node's labels for the pod to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + priorityClassName: + description: If specified, the pod's priorityClassName. + type: string + resources: + description: |- + If specified, the pod's resource requirements. + These values override the global resource configuration flags. + Note that when only specifying resource limits, ensure they are greater than or equal + to the corresponding global resource requests configured via controller flags + (--acme-http01-solver-resource-request-cpu, --acme-http01-solver-resource-request-memory). + Kubernetes will reject pod creation if limits are lower than requests, causing challenge failures. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to the global values configured via controller flags. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + securityContext: + description: If specified, the pod's security context + properties: + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in addition + to the container's primary GID, the fsGroup (if specified), and group memberships + defined in the container image for the uid of the container process. If unspecified, + no additional groups are added to any container. Note that group memberships + defined in the container image for the uid of the container process are still effective, + even if they are not included in this list. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + type: object + serviceAccountName: + description: If specified, the pod's service account + type: string + tolerations: + description: If specified, the pod's tolerations. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + serviceType: + description: |- + Optional service type for Kubernetes solver service. Supported values + are NodePort or ClusterIP. If unset, defaults to NodePort. + type: string + type: object + type: object + selector: + description: |- + Selector selects a set of DNSNames on the Certificate resource that + should be solved using this challenge solver. + If not specified, the solver will be treated as the 'default' solver + with the lowest priority, i.e. if any other solver has a more specific + match, it will be used instead. + properties: + dnsNames: + description: |- + List of DNSNames that this solver will be used to solve. + If specified and a match is found, a dnsNames selector will take + precedence over a dnsZones selector. + If multiple solvers match with the same dnsNames value, the solver + with the most matching labels in matchLabels will be selected. + If neither has more matches, the solver defined earlier in the list + will be selected. + items: + type: string + type: array + x-kubernetes-list-type: atomic + dnsZones: + description: |- + List of DNSZones that this solver will be used to solve. + The most specific DNS zone match specified here will take precedence + over other DNS zone matches, so a solver specifying sys.example.com + will be selected over one specifying example.com for the domain + www.sys.example.com. + If multiple solvers match with the same dnsZones value, the solver + with the most matching labels in matchLabels will be selected. + If neither has more matches, the solver defined earlier in the list + will be selected. + items: + type: string + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + description: |- + A label selector that is used to refine the set of certificate's that + this challenge solver will apply to. + type: object + type: object + type: object + type: array + x-kubernetes-list-type: atomic + required: + - privateKeySecretRef + - server + type: object + ca: + description: |- + CA configures this issuer to sign certificates using a signing CA keypair + stored in a Secret resource. + This is used to build internal PKIs that are managed by cert-manager. + properties: + crlDistributionPoints: + description: |- + The CRL distribution points is an X.509 v3 certificate extension which identifies + the location of the CRL from which the revocation of this certificate can be checked. + If not set, certificates will be issued without distribution points set. + items: + type: string + type: array + x-kubernetes-list-type: atomic + issuingCertificateURLs: + description: |- + IssuingCertificateURLs is a list of URLs which this issuer should embed into certificates + it creates. See https://www.rfc-editor.org/rfc/rfc5280#section-4.2.2.1 for more details. + As an example, such a URL might be "http://ca.domain.com/ca.crt". + items: + type: string + type: array + x-kubernetes-list-type: atomic + ocspServers: + description: |- + The OCSP server list is an X.509 v3 extension that defines a list of + URLs of OCSP responders. The OCSP responders can be queried for the + revocation status of an issued certificate. If not set, the + certificate will be issued with no OCSP servers set. For example, an + OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org". + items: + type: string + type: array + x-kubernetes-list-type: atomic + secretName: + description: |- + SecretName is the name of the secret used to sign Certificates issued + by this Issuer. + type: string + required: + - secretName + type: object + selfSigned: + description: |- + SelfSigned configures this issuer to 'self sign' certificates using the + private key used to create the CertificateRequest object. + properties: + crlDistributionPoints: + description: |- + The CRL distribution points is an X.509 v3 certificate extension which identifies + the location of the CRL from which the revocation of this certificate can be checked. + If not set certificate will be issued without CDP. Values are strings. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + vault: + description: |- + Vault configures this issuer to sign certificates using a HashiCorp Vault + PKI backend. + properties: + auth: + description: Auth configures how cert-manager authenticates with the Vault server. + properties: + appRole: + description: |- + AppRole authenticates with Vault using the App Role auth mechanism, + with the role and secret stored in a Kubernetes Secret resource. + properties: + path: + description: |- + Path where the App Role authentication backend is mounted in Vault, e.g: + "approle" + type: string + roleId: + description: |- + RoleID configured in the App Role authentication backend when setting + up the authentication backend in Vault. + type: string + secretRef: + description: |- + Reference to a key in a Secret that contains the App Role secret used + to authenticate with Vault. + The `key` field must be specified and denotes which entry within the Secret + resource is used as the app role secret. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + required: + - path + - roleId + - secretRef + type: object + clientCertificate: + description: |- + ClientCertificate authenticates with Vault by presenting a client + certificate during the request's TLS handshake. + Works only when using HTTPS protocol. + properties: + mountPath: + description: |- + The Vault mountPath here is the mount path to use when authenticating with + Vault. For example, setting a value to `/v1/auth/foo`, will use the path + `/v1/auth/foo/login` to authenticate with Vault. If unspecified, the + default value "/v1/auth/cert" will be used. + type: string + name: + description: |- + Name of the certificate role to authenticate against. + If not set, matching any certificate role, if available. + type: string + secretName: + description: |- + Reference to Kubernetes Secret of type "kubernetes.io/tls" (hence containing + tls.crt and tls.key) used to authenticate to Vault using TLS client + authentication. + type: string + type: object + kubernetes: + description: |- + Kubernetes authenticates with Vault by passing the ServiceAccount + token stored in the named Secret resource to the Vault server. + properties: + mountPath: + description: |- + The Vault mountPath here is the mount path to use when authenticating with + Vault. For example, setting a value to `/v1/auth/foo`, will use the path + `/v1/auth/foo/login` to authenticate with Vault. If unspecified, the + default value "/v1/auth/kubernetes" will be used. + type: string + role: + description: |- + A required field containing the Vault Role to assume. A Role binds a + Kubernetes ServiceAccount with a set of Vault policies. + type: string + secretRef: + description: |- + The required Secret field containing a Kubernetes ServiceAccount JWT used + for authenticating with Vault. Use of 'ambient credentials' is not + supported. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + serviceAccountRef: + description: |- + A reference to a service account that will be used to request a bound + token (also known as "projected token"). Compared to using "secretRef", + using this field means that you don't rely on statically bound tokens. To + use this field, you must configure an RBAC rule to let cert-manager + request a token. + properties: + audiences: + description: |- + TokenAudiences is an optional list of extra audiences to include in the token passed to Vault. The default token + consisting of the issuer's namespace and name is always included. + items: + type: string + type: array + x-kubernetes-list-type: atomic + name: + description: Name of the ServiceAccount used to request a token. + type: string + required: + - name + type: object + required: + - role + type: object + tokenSecretRef: + description: TokenSecretRef authenticates with Vault by presenting a token. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + type: object + caBundle: + description: |- + Base64-encoded bundle of PEM CAs which will be used to validate the certificate + chain presented by Vault. Only used if using HTTPS to connect to Vault and + ignored for HTTP connections. + Mutually exclusive with CABundleSecretRef. + If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in + the cert-manager controller container is used to validate the TLS connection. + format: byte + type: string + caBundleSecretRef: + description: |- + Reference to a Secret containing a bundle of PEM-encoded CAs to use when + verifying the certificate chain presented by Vault when using HTTPS. + Mutually exclusive with CABundle. + If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in + the cert-manager controller container is used to validate the TLS connection. + If no key for the Secret is specified, cert-manager will default to 'ca.crt'. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + clientCertSecretRef: + description: |- + Reference to a Secret containing a PEM-encoded Client Certificate to use when the + Vault server requires mTLS. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + clientKeySecretRef: + description: |- + Reference to a Secret containing a PEM-encoded Client Private Key to use when the + Vault server requires mTLS. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + namespace: + description: |- + Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1" + More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces + type: string + path: + description: |- + Path is the mount path of the Vault PKI backend's `sign` endpoint, e.g: + "my_pki_mount/sign/my-role-name". + type: string + server: + description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' + type: string + serverName: + description: |- + ServerName is used to verify the hostname on the returned certificates + by the Vault server. + type: string + required: + - auth + - path + - server + type: object + venafi: + description: |- + Venafi configures this issuer to sign certificates using a Venafi TPP + or Venafi Cloud policy zone. + properties: + cloud: + description: |- + Cloud specifies the Venafi cloud configuration settings. + Only one of TPP or Cloud may be specified. + properties: + apiTokenSecretRef: + description: APITokenSecretRef is a secret key selector for the Venafi Cloud API token. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + url: + description: |- + URL is the base URL for Venafi Cloud. + Defaults to "https://api.venafi.cloud/". + type: string + required: + - apiTokenSecretRef + type: object + tpp: + description: |- + TPP specifies Trust Protection Platform configuration settings. + Only one of TPP or Cloud may be specified. + properties: + caBundle: + description: |- + Base64-encoded bundle of PEM CAs which will be used to validate the certificate + chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP. + If undefined, the certificate bundle in the cert-manager controller container + is used to validate the chain. + format: byte + type: string + caBundleSecretRef: + description: |- + Reference to a Secret containing a base64-encoded bundle of PEM CAs + which will be used to validate the certificate chain presented by the TPP server. + Only used if using HTTPS; ignored for HTTP. Mutually exclusive with CABundle. + If neither CABundle nor CABundleSecretRef is defined, the certificate bundle in + the cert-manager controller container is used to validate the TLS connection. + properties: + key: + description: |- + The key of the entry in the Secret resource's `data` field to be used. + Some instances of this field may be defaulted, in others it may be + required. + type: string + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + credentialsRef: + description: |- + CredentialsRef is a reference to a Secret containing the Venafi TPP API credentials. + The secret must contain the key 'access-token' for the Access Token Authentication, + or two keys, 'username' and 'password' for the API Keys Authentication. + properties: + name: + description: |- + Name of the resource being referred to. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + required: + - name + type: object + url: + description: |- + URL is the base URL for the vedsdk endpoint of the Venafi TPP instance, + for example: "https://tpp.example.com/vedsdk". + type: string + required: + - credentialsRef + - url + type: object + zone: + description: |- + Zone is the Venafi Policy Zone to use for this issuer. + All requests made to the Venafi platform will be restricted by the named + zone policy. + This field is required. + type: string + required: + - zone + type: object + type: object + status: + description: Status of the Issuer. This is set and managed automatically. + properties: + acme: + description: |- + ACME specific status options. + This field should only be set if the Issuer is configured to use an ACME + server to issue certificates. + properties: + lastPrivateKeyHash: + description: |- + LastPrivateKeyHash is a hash of the private key associated with the latest + registered ACME account, in order to track changes made to registered account + associated with the Issuer + type: string + lastRegisteredEmail: + description: |- + LastRegisteredEmail is the email associated with the latest registered + ACME account, in order to track changes made to registered account + associated with the Issuer + type: string + uri: + description: |- + URI is the unique account identifier, which can also be used to retrieve + account details from the CA + type: string + type: object + conditions: + description: |- + List of status conditions to indicate the status of a CertificateRequest. + Known condition types are `Ready`. + items: + description: IssuerCondition contains condition information for an Issuer. + properties: + lastTransitionTime: + description: |- + LastTransitionTime is the timestamp corresponding to the last status + change of this condition. + format: date-time + type: string + message: + description: |- + Message is a human readable description of the details of the last + transition, complementing reason. + type: string + observedGeneration: + description: |- + If set, this represents the .metadata.generation that the condition was + set based upon. + For instance, if .metadata.generation is currently 12, but the + .status.condition[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the Issuer. + format: int64 + type: integer + reason: + description: |- + Reason is a brief machine readable explanation for the condition's last + transition. + type: string + status: + description: Status of the condition, one of (`True`, `False`, `Unknown`). + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: Type of the condition, known values are (`Ready`). + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +{{- end }} diff --git a/packages/system/cert-manager-crds/values.yaml b/packages/system/cert-manager-crds/values.yaml index 0b21fc93..15136853 100644 --- a/packages/system/cert-manager-crds/values.yaml +++ b/packages/system/cert-manager-crds/values.yaml @@ -1,2 +1,8 @@ -cert-manager: - installCRDs: true +global: + commonLabels: {} + +creator: helm + +crds: + enabled: true + keep: true diff --git a/packages/system/cert-manager-issuers/Makefile b/packages/system/cert-manager-issuers/Makefile index a7a6ce10..8808dbfd 100644 --- a/packages/system/cert-manager-issuers/Makefile +++ b/packages/system/cert-manager-issuers/Makefile @@ -1,4 +1,4 @@ export NAME=cert-manager-issuers export NAMESPACE=cozy-cert-manager -include ../../../scripts/package.mk +include ../../../hack/package.mk diff --git a/packages/system/cert-manager-issuers/templates/cluster-issuers.yaml b/packages/system/cert-manager-issuers/templates/cluster-issuers.yaml index 6a70eef0..3b582082 100644 --- a/packages/system/cert-manager-issuers/templates/cluster-issuers.yaml +++ b/packages/system/cert-manager-issuers/templates/cluster-issuers.yaml @@ -1,7 +1,7 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} +{{- $solver := (index .Values._cluster "solver") | default "http01" }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} -apiVersion: cert-manager.io/v1 +apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod @@ -11,16 +11,16 @@ spec: name: letsencrypt-prod server: https://acme-v02.api.letsencrypt.org/directory solvers: - - {{- if eq $issuerType "cloudflare" }} + - {{- if eq $solver "dns01" }} dns01: cloudflare: apiTokenSecretRef: name: cloudflare-api-token-secret key: api-token {{- else }} - http01: - ingress: - class: nginx + http01: + ingress: + ingressClassName: {{ $exposeIngress }} {{- end }} --- @@ -35,16 +35,16 @@ spec: name: letsencrypt-stage server: https://acme-staging-v02.api.letsencrypt.org/directory solvers: - - {{- if eq $issuerType "cloudflare" }} + - {{- if eq $solver "dns01" }} dns01: cloudflare: apiTokenSecretRef: name: cloudflare-api-token-secret key: api-token {{- else }} - http01: - ingress: - class: nginx + http01: + ingress: + ingressClassName: {{ $exposeIngress }} {{- end }} --- diff --git a/packages/system/cert-manager/Makefile b/packages/system/cert-manager/Makefile index d48ad5be..c3ff574b 100644 --- a/packages/system/cert-manager/Makefile +++ b/packages/system/cert-manager/Makefile @@ -1,10 +1,13 @@ export NAME=cert-manager export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts helm repo add jetstack https://charts.jetstack.io helm repo update jetstack helm pull jetstack/cert-manager --untar --untardir charts + rm -rf ../cert-manager-crds/templates/* + mv charts/cert-manager/templates/crd-*.yaml ../cert-manager-crds/templates/ + cp charts/cert-manager/templates/_helpers.tpl ../cert-manager-crds/templates/ diff --git a/packages/system/cert-manager/charts/cert-manager/Chart.yaml b/packages/system/cert-manager/charts/cert-manager/Chart.yaml index 2a49d00c..2756247d 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.17.2 +appVersion: v1.19.3 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.17.2 +version: v1.19.3 diff --git a/packages/system/cert-manager/charts/cert-manager/README.md b/packages/system/cert-manager/charts/cert-manager/README.md index 1d502429..456e740d 100644 --- a/packages/system/cert-manager/charts/cert-manager/README.md +++ b/packages/system/cert-manager/charts/cert-manager/README.md @@ -1,10 +1,10 @@ # cert-manager -cert-manager is a Kubernetes addon to automate the management and issuance of -TLS certificates from various issuing sources. +cert-manager creates TLS certificates for workloads in your Kubernetes or OpenShift cluster and renews the certificates before they expire. -It will ensure certificates are valid and up to date periodically, and attempt -to renew certificates at an appropriate time before expiry. +cert-manager can obtain certificates from a [variety of certificate authorities](https://cert-manager.io/docs/configuration/issuers/), including: +[Let's Encrypt](https://cert-manager.io/docs/configuration/acme/), [HashiCorp Vault](https://cert-manager.io/docs/configuration/vault/), +[Venafi](https://cert-manager.io/docs/configuration/venafi/) and [private PKI](https://cert-manager.io/docs/configuration/ca/). ## Prerequisites @@ -13,23 +13,21 @@ to renew certificates at an appropriate time before expiry. ## Installing the Chart Full installation instructions, including details on how to configure extra -functionality in cert-manager can be found in the [installation docs](https://cert-manager.io/docs/installation/kubernetes/). - -Before installing the chart, you must first install the cert-manager CustomResourceDefinition resources. -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.17.2/cert-manager.crds.yaml -``` +functionality in cert-manager can be found in the [installation docs](https://cert-manager.io/docs/installation/helm/). To install the chart with the release name `cert-manager`: ```console -## Add the Jetstack Helm repository -$ helm repo add jetstack https://charts.jetstack.io --force-update +# Add the Jetstack Helm repository +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.17.2 jetstack/cert-manager +# Install the cert-manager helm chart +helm install \ + cert-manager jetstack/cert-manager \ + --namespace cert-manager \ + --create-namespace \ + --version v1.19.3 \ + --set crds.enabled=true ``` In order to begin issuing certificates, you will need to set up a ClusterIssuer @@ -56,17 +54,25 @@ are documented in our full [upgrading guide](https://cert-manager.io/docs/instal To uninstall/delete the `cert-manager` deployment: ```console -$ helm delete cert-manager --namespace cert-manager +helm delete cert-manager --namespace cert-manager ``` The command removes all the Kubernetes components associated with the chart and deletes the release. If you want to completely uninstall cert-manager from your cluster, you will also need to -delete the previously installed CustomResourceDefinition resources: +delete the previously installed CustomResourceDefinition resources. -```console -$ kubectl delete -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.2/cert-manager.crds.yaml -``` +> ☢️ This will remove all `Issuer`,`ClusterIssuer`,`Certificate`,`CertificateRequest`,`Order` and `Challenge` resources from the cluster: +> +> ```console +> kubectl delete crd \ +> issuers.cert-manager.io \ +> clusterissuers.cert-manager.io \ +> certificates.cert-manager.io \ +> certificaterequests.cert-manager.io \ +> orders.acme.cert-manager.io \ +> challenges.acme.cert-manager.io +> ``` ## Configuration @@ -87,6 +93,18 @@ For example: imagePullSecrets: - name: "image-pull-secret" ``` +#### **global.nodeSelector** ~ `object` +> Default value: +> ```yaml +> {} +> ``` + +Global node selector + +The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with matching labels. For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). + +If a component-specific nodeSelector is also set, it will be merged and take precedence. + #### **global.commonLabels** ~ `object` > Default value: > ```yaml @@ -108,6 +126,18 @@ The number of old ReplicaSets to retain to allow rollback (if not set, the defau > ``` The optional priority class to be used for the cert-manager pods. +#### **global.hostUsers** ~ `bool` + +Set all pods to run in a user namespace without host access. Experimental: may be removed once the Kubernetes User Namespaces feature is GA. + +Requirements: + - Kubernetes ≥ 1.33, or + - Kubernetes 1.27–1.32 with UserNamespacesSupport feature gate enabled. + +Set to false to run pods in a user namespace without host access. + +See [limitations](https://kubernetes.io/docs/concepts/workloads/pods/user-namespaces/#limitations) for details. + #### **global.rbac.create** ~ `bool` > Default value: > ```yaml @@ -230,13 +260,13 @@ This prevents downtime during voluntary disruptions such as during a Node upgrad Pod is currently running. #### **podDisruptionBudget.minAvailable** ~ `unknown` -This configures the minimum available pods for disruptions. It can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%). +This configures the minimum available pods for disruptions. It can either be set to an integer (e.g., 1) or a percentage value (e.g., 25%). It cannot be used if `maxUnavailable` is set. #### **podDisruptionBudget.maxUnavailable** ~ `unknown` -This configures the maximum unavailable pods for disruptions. It can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%). it cannot be used if `minAvailable` is set. +This configures the maximum unavailable pods for disruptions. It can either be set to an integer (e.g., 1) or a percentage value (e.g., 25%). it cannot be used if `minAvailable` is set. #### **featureGates** ~ `string` @@ -300,7 +330,7 @@ Override the "cert-manager.fullname" value. This value is used as part of most o #### **nameOverride** ~ `string` -Override the "cert-manager.name" value, which is used to annotate some of the resources that are created by this Chart (using "app.kubernetes.io/name"). NOTE: There are some inconsistencies in the Helm chart when it comes to these annotations (some resources use eg. "cainjector.name" which resolves to the value "cainjector"). +Override the "cert-manager.name" value, which is used to annotate some of the resources that are created by this Chart (using "app.kubernetes.io/name"). NOTE: There are some inconsistencies in the Helm chart when it comes to these annotations (some resources use, e.g., "cainjector.name" which resolves to the value "cainjector"). #### **serviceAccount.create** ~ `bool` > Default value: @@ -371,10 +401,10 @@ config: kubernetesAPIBurst: 9000 numberOfConcurrentWorkers: 200 enableGatewayAPI: true - # Feature gates as of v1.17.0. Listed with their default values. + # Feature gates as of v1.18.1. Listed with their default values. # See https://cert-manager.io/docs/cli/controller/ featureGates: - AdditionalCertificateOutputFormats: true # BETA - default=true + AdditionalCertificateOutputFormats: true # GA - default=true AllAlpha: false # ALPHA - default=false AllBeta: false # BETA - default=false ExperimentalCertificateSigningRequestControllers: false # ALPHA - default=false @@ -386,8 +416,10 @@ config: ServerSideApply: false # ALPHA - default=false StableCertificateRequestName: true # BETA - default=true UseCertificateRequestBasicConstraints: false # ALPHA - default=false - UseDomainQualifiedFinalizer: true # BETA - default=false + UseDomainQualifiedFinalizer: true # GA - default=true ValidateCAA: false # ALPHA - default=false + DefaultPrivateKeyRotationPolicyAlways: true # BETA - default=true + ACMEHTTP01IngressPathTypeExact: true # BETA - default=true # Configure the metrics server for TLS # See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls metricsTLSConfig: @@ -425,7 +457,7 @@ Option to disable cert-manager's build-in auto-approver. The auto-approver appro > - clusterissuers.cert-manager.io/* > ``` -List of signer names that cert-manager will approve by default. CertificateRequests referencing these signer names will be auto-approved by cert-manager. Defaults to just approving the cert-manager.io Issuer and ClusterIssuer issuers. When set to an empty array, ALL issuers will be auto-approved by cert-manager. To disable the auto-approval, because eg. you are using approver-policy, you can enable 'disableAutoApproval'. +List of signer names that cert-manager will approve by default. CertificateRequests referencing these signer names will be auto-approved by cert-manager. Defaults to just approving the cert-manager.io Issuer and ClusterIssuer issuers. When set to an empty array, ALL issuers will be auto-approved by cert-manager. To disable the auto-approval, because, e.g., you are using approver-policy, you can enable 'disableAutoApproval'. ref: https://cert-manager.io/docs/concepts/certificaterequest/#approval #### **extraArgs** ~ `array` @@ -684,7 +716,7 @@ enableServiceLinks indicates whether information about services should be inject Enable Prometheus monitoring for the cert-manager controller and webhook. If you use the Prometheus Operator, set prometheus.podmonitor.enabled or prometheus.servicemonitor.enabled, to create a PodMonitor or a ServiceMonitor resource. -Otherwise, 'prometheus.io' annotations are added to the cert-manager and cert-manager-webhook Deployments. Note that you can not enable both PodMonitor and ServiceMonitor as they are mutually exclusive. Enabling both will result in an error. +Otherwise, 'prometheus.io' annotations are added to the cert-manager and cert-manager-webhook Deployments. Note that you cannot enable both PodMonitor and ServiceMonitor as they are mutually exclusive. Enabling both will result in an error. #### **prometheus.servicemonitor.enabled** ~ `bool` > Default value: > ```yaml @@ -703,13 +735,14 @@ The namespace that the service monitor should live in, defaults to the cert-mana > ``` Specifies the `prometheus` label on the created ServiceMonitor. This is used when different Prometheus instances have label selectors matching different ServiceMonitors. -#### **prometheus.servicemonitor.targetPort** ~ `number` +#### **prometheus.servicemonitor.targetPort** ~ `string,integer` > Default value: > ```yaml -> 9402 +> http-metrics > ``` The target port to set on the ServiceMonitor. This must match the port that the cert-manager controller is listening on for metrics. + #### **prometheus.servicemonitor.path** ~ `string` > Default value: > ```yaml @@ -969,13 +1002,13 @@ This prevents downtime during voluntary disruptions such as during a Node upgrad Pod is currently running. #### **webhook.podDisruptionBudget.minAvailable** ~ `unknown` -This property configures the minimum available pods for disruptions. Can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%). +This property configures the minimum available pods for disruptions. Can either be set to an integer (e.g., 1) or a percentage value (e.g., 25%). It cannot be used if `maxUnavailable` is set. #### **webhook.podDisruptionBudget.maxUnavailable** ~ `unknown` -This property configures the maximum unavailable pods for disruptions. Can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%). +This property configures the maximum unavailable pods for disruptions. Can either be set to an integer (e.g., 1) or a percentage value (e.g., 25%). It cannot be used if `minAvailable` is set. @@ -1293,6 +1326,8 @@ Create network policies for the webhooks. > - from: > - ipBlock: > cidr: 0.0.0.0/0 +> - ipBlock: +> cidr: ::/0 > ``` Ingress rule for the webhook network policy. By default, it allows all inbound traffic. @@ -1314,6 +1349,8 @@ Ingress rule for the webhook network policy. By default, it allows all inbound t > to: > - ipBlock: > cidr: 0.0.0.0/0 +> - ipBlock: +> cidr: ::/0 > ``` Egress rule for the webhook network policy. By default, it allows all outbound traffic to ports 80 and 443, as well as DNS ports. @@ -1442,14 +1479,14 @@ Pod is currently running. #### **cainjector.podDisruptionBudget.minAvailable** ~ `unknown` `minAvailable` configures the minimum available pods for disruptions. It can either be set to -an integer (e.g. 1) or a percentage value (e.g. 25%). +an integer (e.g., 1) or a percentage value (e.g., 25%). Cannot be used if `maxUnavailable` is set. #### **cainjector.podDisruptionBudget.maxUnavailable** ~ `unknown` `maxUnavailable` configures the maximum unavailable pods for disruptions. It can either be set to -an integer (e.g. 1) or a percentage value (e.g. 25%). +an integer (e.g., 1) or a percentage value (e.g., 25%). Cannot be used if `minAvailable` is set. diff --git a/packages/system/cert-manager/charts/cert-manager/templates/NOTES.txt b/packages/system/cert-manager/charts/cert-manager/templates/NOTES.txt index 341d1012..4d0b4b60 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/NOTES.txt +++ b/packages/system/cert-manager/charts/cert-manager/templates/NOTES.txt @@ -1,6 +1,12 @@ {{- if .Values.installCRDs }} ⚠️ WARNING: `installCRDs` is deprecated, use `crds.enabled` instead. + {{- end }} +⚠️ WARNING: New default private key rotation policy for Certificate resources. +The default private key rotation policy for Certificate resources was +changed to `Always` in cert-manager >= v1.18.0. +Learn more in the [1.18 release notes](https://cert-manager.io/docs/releases/release-notes/release-notes-1.18). + cert-manager {{ .Chart.AppVersion }} has been deployed successfully! In order to begin issuing certificates, you will need to set up a ClusterIssuer diff --git a/packages/system/cert-manager/charts/cert-manager/templates/_helpers.tpl b/packages/system/cert-manager/charts/cert-manager/templates/_helpers.tpl index e15fa191..f85373f3 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/_helpers.tpl +++ b/packages/system/cert-manager/charts/cert-manager/templates/_helpers.tpl @@ -187,6 +187,17 @@ See https://github.com/cert-manager/cert-manager/issues/6329 for a list of linke {{- end }} {{- end }} +{{/* +Labels for the CRD resources. +*/}} +{{- define "cert-manager.crd-labels" -}} +app: "{{ template "cert-manager.name" . }}" +app.kubernetes.io/name: "{{ template "cert-manager.name" . }}" +app.kubernetes.io/instance: "{{ .Release.Name }}" +app.kubernetes.io/component: "crds" +{{ include "labels" . }} +{{- end -}} + {{/* Check that the user has not set both .installCRDs and .crds.enabled or set .installCRDs and disabled .crds.keep. 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 dc14ab02..b5434caa 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 @@ -67,6 +67,9 @@ spec: {{- with .Values.global.priorityClassName }} priorityClassName: {{ . | quote }} {{- end }} + {{- if (hasKey .Values.global "hostUsers") }} + hostUsers: {{ .Values.global.hostUsers }} + {{- end }} {{- with .Values.cainjector.securityContext }} securityContext: {{- toYaml . | nindent 8 }} @@ -136,9 +139,13 @@ spec: {{- toYaml . | nindent 12 }} {{- end }} {{- end }} - {{- with .Values.cainjector.nodeSelector }} + {{- $nodeSelector := .Values.global.nodeSelector | default dict }} + {{- $nodeSelector = merge $nodeSelector (.Values.cainjector.nodeSelector | default dict) }} + {{- with $nodeSelector }} nodeSelector: - {{- toYaml . | nindent 8 }} + {{- range $key, $value := . }} + {{ $key }}: {{ $value | quote }} + {{- end }} {{- end }} {{- with .Values.cainjector.affinity }} affinity: diff --git a/packages/system/cert-manager/charts/cert-manager/templates/crds.yaml b/packages/system/cert-manager/charts/cert-manager/templates/crds.yaml deleted file mode 100644 index f5f8ec43..00000000 --- a/packages/system/cert-manager/charts/cert-manager/templates/crds.yaml +++ /dev/null @@ -1,12036 +0,0 @@ -# {{- include "cert-manager.crd-check" . }} -# START crd {{- if or .Values.crds.enabled .Values.installCRDs }} -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: certificaterequests.cert-manager.io - # START annotations {{- if .Values.crds.keep }} - annotations: - helm.sh/resource-policy: keep - # END annotations {{- end }} - labels: - app: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/name: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/instance: '{{ .Release.Name }}' - # Generated labels {{- include "labels" . | nindent 4 }} -spec: - group: cert-manager.io - names: - kind: CertificateRequest - listKind: CertificateRequestList - plural: certificaterequests - shortNames: - - cr - - crs - singular: certificaterequest - categories: - - cert-manager - scope: Namespaced - versions: - - name: v1 - subresources: - status: {} - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Approved")].status - name: Approved - type: string - - jsonPath: .status.conditions[?(@.type=="Denied")].status - name: Denied - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .spec.issuerRef.name - name: Issuer - type: string - - jsonPath: .spec.username - name: Requester - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: |- - A CertificateRequest is used to request a signed certificate from one of the - configured issuers. - - All fields within the CertificateRequest's `spec` are immutable after creation. - A CertificateRequest will either succeed or fail, as denoted by its `Ready` status - condition and its `status.failureTime` field. - - A CertificateRequest is a one-shot resource, meaning it represents a single - point in time request for a certificate and cannot be re-used. - type: object - 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: |- - Specification of the desired state of the CertificateRequest resource. - https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - type: object - required: - - issuerRef - - request - properties: - duration: - description: |- - Requested 'duration' (i.e. lifetime) of the Certificate. Note that the - issuer may choose to ignore the requested duration, just like any other - requested attribute. - type: string - extra: - description: |- - Extra contains extra attributes of the user that created the CertificateRequest. - Populated by the cert-manager webhook on creation and immutable. - type: object - additionalProperties: - type: array - items: - type: string - groups: - description: |- - Groups contains group membership of the user that created the CertificateRequest. - Populated by the cert-manager webhook on creation and immutable. - type: array - items: - type: string - x-kubernetes-list-type: atomic - isCA: - description: |- - Requested basic constraints isCA value. Note that the issuer may choose - to ignore the requested isCA value, just like any other requested attribute. - - NOTE: If the CSR in the `Request` field has a BasicConstraints extension, - it must have the same isCA value as specified here. - - If true, this will automatically add the `cert sign` usage to the list - of requested `usages`. - type: boolean - issuerRef: - description: |- - Reference to the issuer responsible for issuing the certificate. - If the issuer is namespace-scoped, it must be in the same namespace - as the Certificate. If the issuer is cluster-scoped, it can be used - from any namespace. - - The `name` field of the reference must always be specified. - type: object - required: - - name - properties: - group: - description: Group of the resource being referred to. - type: string - kind: - description: Kind of the resource being referred to. - type: string - name: - description: Name of the resource being referred to. - type: string - request: - description: |- - The PEM-encoded X.509 certificate signing request to be submitted to the - issuer for signing. - - If the CSR has a BasicConstraints extension, its isCA attribute must - match the `isCA` value of this CertificateRequest. - If the CSR has a KeyUsage extension, its key usages must match the - key usages in the `usages` field of this CertificateRequest. - If the CSR has a ExtKeyUsage extension, its extended key usages - must match the extended key usages in the `usages` field of this - CertificateRequest. - type: string - format: byte - uid: - description: |- - UID contains the uid of the user that created the CertificateRequest. - Populated by the cert-manager webhook on creation and immutable. - type: string - usages: - description: |- - Requested key usages and extended key usages. - - NOTE: If the CSR in the `Request` field has uses the KeyUsage or - ExtKeyUsage extension, these extensions must have the same values - as specified here without any additional values. - - If unset, defaults to `digital signature` and `key encipherment`. - type: array - items: - description: |- - KeyUsage specifies valid usage contexts for keys. - See: - https://tools.ietf.org/html/rfc5280#section-4.2.1.3 - https://tools.ietf.org/html/rfc5280#section-4.2.1.12 - - Valid KeyUsage values are as follows: - "signing", - "digital signature", - "content commitment", - "key encipherment", - "key agreement", - "data encipherment", - "cert sign", - "crl sign", - "encipher only", - "decipher only", - "any", - "server auth", - "client auth", - "code signing", - "email protection", - "s/mime", - "ipsec end system", - "ipsec tunnel", - "ipsec user", - "timestamping", - "ocsp signing", - "microsoft sgc", - "netscape sgc" - type: string - enum: - - signing - - digital signature - - content commitment - - key encipherment - - key agreement - - data encipherment - - cert sign - - crl sign - - encipher only - - decipher only - - any - - server auth - - client auth - - code signing - - email protection - - s/mime - - ipsec end system - - ipsec tunnel - - ipsec user - - timestamping - - ocsp signing - - microsoft sgc - - netscape sgc - username: - description: |- - Username contains the name of the user that created the CertificateRequest. - Populated by the cert-manager webhook on creation and immutable. - type: string - status: - description: |- - Status of the CertificateRequest. - This is set and managed automatically. - Read-only. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - type: object - properties: - ca: - description: |- - The PEM encoded X.509 certificate of the signer, also known as the CA - (Certificate Authority). - This is set on a best-effort basis by different issuers. - If not set, the CA is assumed to be unknown/not available. - type: string - format: byte - certificate: - description: |- - The PEM encoded X.509 certificate resulting from the certificate - signing request. - If not set, the CertificateRequest has either not been completed or has - failed. More information on failure can be found by checking the - `conditions` field. - type: string - format: byte - conditions: - description: |- - List of status conditions to indicate the status of a CertificateRequest. - Known condition types are `Ready`, `InvalidRequest`, `Approved` and `Denied`. - type: array - items: - description: CertificateRequestCondition contains condition information for a CertificateRequest. - type: object - required: - - status - - type - properties: - lastTransitionTime: - description: |- - LastTransitionTime is the timestamp corresponding to the last status - change of this condition. - type: string - format: date-time - message: - description: |- - Message is a human readable description of the details of the last - transition, complementing reason. - type: string - reason: - description: |- - Reason is a brief machine readable explanation for the condition's last - transition. - type: string - status: - description: Status of the condition, one of (`True`, `False`, `Unknown`). - type: string - enum: - - "True" - - "False" - - Unknown - type: - description: |- - Type of the condition, known values are (`Ready`, `InvalidRequest`, - `Approved`, `Denied`). - type: string - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - failureTime: - description: |- - FailureTime stores the time that this CertificateRequest failed. This is - used to influence garbage collection and back-off. - type: string - format: date-time - served: true - storage: true - -# END crd {{- end }} - ---- -# START crd {{- if or .Values.crds.enabled .Values.installCRDs }} -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: certificates.cert-manager.io - # START annotations {{- if .Values.crds.keep }} - annotations: - helm.sh/resource-policy: keep - # END annotations {{- end }} - labels: - app: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/name: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/instance: '{{ .Release.Name }}' - # Generated labels {{- include "labels" . | nindent 4 }} -spec: - group: cert-manager.io - names: - kind: Certificate - listKind: CertificateList - plural: certificates - shortNames: - - cert - - certs - singular: certificate - categories: - - cert-manager - scope: Namespaced - versions: - - name: v1 - subresources: - status: {} - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .spec.secretName - name: Secret - type: string - - jsonPath: .spec.issuerRef.name - name: Issuer - priority: 1 - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: |- - A Certificate resource should be created to ensure an up to date and signed - X.509 certificate is stored in the Kubernetes Secret resource named in `spec.secretName`. - - The stored certificate will be renewed before it expires (as configured by `spec.renewBefore`). - type: object - 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: |- - Specification of the desired state of the Certificate resource. - https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - type: object - required: - - issuerRef - - secretName - properties: - additionalOutputFormats: - description: |- - Defines extra output formats of the private key and signed certificate chain - to be written to this Certificate's target Secret. - - This is a Beta Feature enabled by default. It can be disabled with the - `--feature-gates=AdditionalCertificateOutputFormats=false` option set on both - the controller and webhook components. - type: array - items: - description: |- - CertificateAdditionalOutputFormat defines an additional output format of a - Certificate resource. These contain supplementary data formats of the signed - certificate chain and paired private key. - type: object - required: - - type - properties: - type: - description: |- - Type is the name of the format type that should be written to the - Certificate's target Secret. - type: string - enum: - - DER - - CombinedPEM - commonName: - description: |- - Requested common name X509 certificate subject attribute. - More info: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6 - NOTE: TLS clients will ignore this value when any subject alternative name is - set (see https://tools.ietf.org/html/rfc6125#section-6.4.4). - - Should have a length of 64 characters or fewer to avoid generating invalid CSRs. - Cannot be set if the `literalSubject` field is set. - type: string - dnsNames: - description: Requested DNS subject alternative names. - type: array - items: - type: string - duration: - description: |- - Requested 'duration' (i.e. lifetime) of the Certificate. Note that the - issuer may choose to ignore the requested duration, just like any other - requested attribute. - - If unset, this defaults to 90 days. - Minimum accepted duration is 1 hour. - Value must be in units accepted by Go time.ParseDuration https://golang.org/pkg/time/#ParseDuration. - type: string - emailAddresses: - description: Requested email subject alternative names. - type: array - items: - type: string - encodeUsagesInRequest: - description: |- - Whether the KeyUsage and ExtKeyUsage extensions should be set in the encoded CSR. - - This option defaults to true, and should only be disabled if the target - issuer does not support CSRs with these X509 KeyUsage/ ExtKeyUsage extensions. - type: boolean - ipAddresses: - description: Requested IP address subject alternative names. - type: array - items: - type: string - isCA: - description: |- - Requested basic constraints isCA value. - The isCA value is used to set the `isCA` field on the created CertificateRequest - resources. Note that the issuer may choose to ignore the requested isCA value, just - like any other requested attribute. - - If true, this will automatically add the `cert sign` usage to the list - of requested `usages`. - type: boolean - issuerRef: - description: |- - Reference to the issuer responsible for issuing the certificate. - If the issuer is namespace-scoped, it must be in the same namespace - as the Certificate. If the issuer is cluster-scoped, it can be used - from any namespace. - - The `name` field of the reference must always be specified. - type: object - required: - - name - properties: - group: - description: Group of the resource being referred to. - type: string - kind: - description: Kind of the resource being referred to. - type: string - name: - description: Name of the resource being referred to. - type: string - keystores: - description: Additional keystore output formats to be stored in the Certificate's Secret. - type: object - properties: - jks: - description: |- - JKS configures options for storing a JKS keystore in the - `spec.secretName` Secret resource. - type: object - required: - - create - properties: - alias: - description: |- - Alias specifies the alias of the key in the keystore, required by the JKS format. - If not provided, the default alias `certificate` will be used. - type: string - create: - description: |- - 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` 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 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 - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - pkcs12: - description: |- - PKCS12 configures options for storing a PKCS12 keystore in the - `spec.secretName` Secret resource. - type: object - required: - - create - 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` 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 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 - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - profile: - description: |- - Profile specifies the key and certificate encryption algorithms and the HMAC algorithm - used to create the PKCS12 keystore. Default value is `LegacyRC2` for backward compatibility. - - If provided, allowed values are: - `LegacyRC2`: Deprecated. Not supported by default in OpenSSL 3 or Java 20. - `LegacyDES`: Less secure algorithm. Use this option for maximal compatibility. - `Modern2023`: Secure algorithm. Use this option in case you have to always use secure algorithms - (eg. because of company policy). Please note that the security of the algorithm is not that important - in reality, because the unencrypted certificate and private key are also stored in the Secret. - type: string - enum: - - LegacyRC2 - - LegacyDES - - Modern2023 - literalSubject: - description: |- - Requested X.509 certificate subject, represented using the LDAP "String - Representation of a Distinguished Name" [1]. - Important: the LDAP string format also specifies the order of the attributes - in the subject, this is important when issuing certs for LDAP authentication. - Example: `CN=foo,DC=corp,DC=example,DC=com` - More info [1]: https://datatracker.ietf.org/doc/html/rfc4514 - More info: https://github.com/cert-manager/cert-manager/issues/3203 - More info: https://github.com/cert-manager/cert-manager/issues/4424 - - Cannot be set if the `subject` or `commonName` field is set. - type: string - nameConstraints: - description: |- - x.509 certificate NameConstraint extension which MUST NOT be used in a non-CA certificate. - More Info: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10 - - This is an Alpha Feature and is only enabled with the - `--feature-gates=NameConstraints=true` option set on both - the controller and webhook components. - type: object - properties: - critical: - description: if true then the name constraints are marked critical. - type: boolean - excluded: - description: |- - Excluded contains the constraints which must be disallowed. Any name matching a - restriction in the excluded field is invalid regardless - of information appearing in the permitted - type: object - properties: - dnsDomains: - description: DNSDomains is a list of DNS domains that are permitted or excluded. - type: array - items: - type: string - emailAddresses: - description: EmailAddresses is a list of Email Addresses that are permitted or excluded. - type: array - items: - type: string - ipRanges: - description: |- - IPRanges is a list of IP Ranges that are permitted or excluded. - This should be a valid CIDR notation. - type: array - items: - type: string - uriDomains: - description: URIDomains is a list of URI domains that are permitted or excluded. - type: array - items: - type: string - permitted: - description: Permitted contains the constraints in which the names must be located. - type: object - properties: - dnsDomains: - description: DNSDomains is a list of DNS domains that are permitted or excluded. - type: array - items: - type: string - emailAddresses: - description: EmailAddresses is a list of Email Addresses that are permitted or excluded. - type: array - items: - type: string - ipRanges: - description: |- - IPRanges is a list of IP Ranges that are permitted or excluded. - This should be a valid CIDR notation. - type: array - items: - type: string - uriDomains: - description: URIDomains is a list of URI domains that are permitted or excluded. - type: array - items: - type: string - otherNames: - description: |- - `otherNames` is an escape hatch for SAN that allows any type. We currently restrict the support to string like otherNames, cf RFC 5280 p 37 - Any UTF8 String valued otherName can be passed with by setting the keys oid: x.x.x.x and UTF8Value: somevalue for `otherName`. - Most commonly this would be UPN set with oid: 1.3.6.1.4.1.311.20.2.3 - You should ensure that any OID passed is valid for the UTF8String type as we do not explicitly validate this. - type: array - items: - type: object - properties: - oid: - description: |- - OID is the object identifier for the otherName SAN. - The object identifier must be expressed as a dotted string, for - example, "1.2.840.113556.1.4.221". - type: string - utf8Value: - description: |- - utf8Value is the string value of the otherName SAN. - The utf8Value accepts any valid UTF8 string to set as value for the otherName SAN. - type: string - privateKey: - description: |- - Private key options. These include the key algorithm and size, the used - encoding and the rotation policy. - type: object - properties: - algorithm: - description: |- - Algorithm is the private key algorithm of the corresponding private key - for this certificate. - - If provided, allowed values are either `RSA`, `ECDSA` or `Ed25519`. - If `algorithm` is specified and `size` is not provided, - key size of 2048 will be used for `RSA` key algorithm and - key size of 256 will be used for `ECDSA` key algorithm. - key size is ignored when using the `Ed25519` key algorithm. - type: string - enum: - - RSA - - ECDSA - - Ed25519 - encoding: - description: |- - The private key cryptography standards (PKCS) encoding for this - certificate's private key to be encoded in. - - If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 - and PKCS#8, respectively. - Defaults to `PKCS1` if not specified. - type: string - enum: - - PKCS1 - - PKCS8 - rotationPolicy: - description: |- - RotationPolicy controls how private keys should be regenerated when a - re-issuance is being processed. - - If set to `Never`, a private key will only be generated if one does not - already exist in the target `spec.secretName`. If one does exist but it - does not have the correct algorithm or size, a warning will be raised - to await user intervention. - If set to `Always`, a private key matching the specified requirements - will be generated whenever a re-issuance occurs. - Default is `Never` for backward compatibility. - type: string - enum: - - Never - - Always - size: - description: |- - Size is the key bit size of the corresponding private key for this certificate. - - If `algorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, - and will default to `2048` if not specified. - If `algorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, - and will default to `256` if not specified. - If `algorithm` is set to `Ed25519`, Size is ignored. - No other values are allowed. - type: integer - renewBefore: - description: |- - How long before the currently issued certificate's expiry cert-manager should - renew the certificate. For example, if a certificate is valid for 60 minutes, - and `renewBefore=10m`, cert-manager will begin to attempt to renew the certificate - 50 minutes after it was issued (i.e. when there are 10 minutes remaining until - the certificate is no longer valid). - - NOTE: The actual lifetime of the issued certificate is used to determine the - renewal time. If an issuer returns a certificate with a different lifetime than - the one requested, cert-manager will use the lifetime of the issued certificate. - - If unset, this defaults to 1/3 of the issued certificate's lifetime. - Minimum accepted value is 5 minutes. - Value must be in units accepted by Go time.ParseDuration https://golang.org/pkg/time/#ParseDuration. - Cannot be set if the `renewBeforePercentage` field is set. - type: string - renewBeforePercentage: - description: |- - `renewBeforePercentage` is like `renewBefore`, except it is a relative percentage - rather than an absolute duration. For example, if a certificate is valid for 60 - minutes, and `renewBeforePercentage=25`, cert-manager will begin to attempt to - renew the certificate 45 minutes after it was issued (i.e. when there are 15 - minutes (25%) remaining until the certificate is no longer valid). - - NOTE: The actual lifetime of the issued certificate is used to determine the - renewal time. If an issuer returns a certificate with a different lifetime than - the one requested, cert-manager will use the lifetime of the issued certificate. - - Value must be an integer in the range (0,100). The minimum effective - `renewBefore` derived from the `renewBeforePercentage` and `duration` fields is 5 - minutes. - Cannot be set if the `renewBefore` field is set. - type: integer - format: int32 - revisionHistoryLimit: - description: |- - The maximum number of CertificateRequest revisions that are maintained in - the Certificate's history. Each revision represents a single `CertificateRequest` - created by this Certificate, either when it was created, renewed, or Spec - was changed. Revisions will be removed by oldest first if the number of - revisions exceeds this number. - - If set, revisionHistoryLimit must be a value of `1` or greater. - If unset (`nil`), revisions will not be garbage collected. - Default value is `nil`. - type: integer - format: int32 - secretName: - description: |- - Name of the Secret resource that will be automatically created and - managed by this Certificate resource. It will be populated with a - private key and certificate, signed by the denoted issuer. The Secret - resource lives in the same namespace as the Certificate resource. - type: string - secretTemplate: - description: |- - Defines annotations and labels to be copied to the Certificate's Secret. - Labels and annotations on the Secret will be changed as they appear on the - SecretTemplate when added or removed. SecretTemplate annotations are added - in conjunction with, and cannot overwrite, the base set of annotations - cert-manager sets on the Certificate's Secret. - type: object - properties: - annotations: - description: Annotations is a key value map to be copied to the target Kubernetes Secret. - type: object - additionalProperties: - type: string - labels: - description: Labels is a key value map to be copied to the target Kubernetes Secret. - type: object - additionalProperties: - type: string - subject: - description: |- - Requested set of X509 certificate subject attributes. - More info: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6 - - The common name attribute is specified separately in the `commonName` field. - Cannot be set if the `literalSubject` field is set. - type: object - properties: - countries: - description: Countries to be used on the Certificate. - type: array - items: - type: string - localities: - description: Cities to be used on the Certificate. - type: array - items: - type: string - organizationalUnits: - description: Organizational Units to be used on the Certificate. - type: array - items: - type: string - organizations: - description: Organizations to be used on the Certificate. - type: array - items: - type: string - postalCodes: - description: Postal codes to be used on the Certificate. - type: array - items: - type: string - provinces: - description: State/Provinces to be used on the Certificate. - type: array - items: - type: string - serialNumber: - description: Serial number to be used on the Certificate. - type: string - streetAddresses: - description: Street addresses to be used on the Certificate. - type: array - items: - type: string - uris: - description: Requested URI subject alternative names. - type: array - items: - type: string - usages: - description: |- - Requested key usages and extended key usages. - These usages are used to set the `usages` field on the created CertificateRequest - resources. If `encodeUsagesInRequest` is unset or set to `true`, the usages - will additionally be encoded in the `request` field which contains the CSR blob. - - If unset, defaults to `digital signature` and `key encipherment`. - type: array - items: - description: |- - KeyUsage specifies valid usage contexts for keys. - See: - https://tools.ietf.org/html/rfc5280#section-4.2.1.3 - https://tools.ietf.org/html/rfc5280#section-4.2.1.12 - - Valid KeyUsage values are as follows: - "signing", - "digital signature", - "content commitment", - "key encipherment", - "key agreement", - "data encipherment", - "cert sign", - "crl sign", - "encipher only", - "decipher only", - "any", - "server auth", - "client auth", - "code signing", - "email protection", - "s/mime", - "ipsec end system", - "ipsec tunnel", - "ipsec user", - "timestamping", - "ocsp signing", - "microsoft sgc", - "netscape sgc" - type: string - enum: - - signing - - digital signature - - content commitment - - key encipherment - - key agreement - - data encipherment - - cert sign - - crl sign - - encipher only - - decipher only - - any - - server auth - - client auth - - code signing - - email protection - - s/mime - - ipsec end system - - ipsec tunnel - - ipsec user - - timestamping - - ocsp signing - - microsoft sgc - - netscape sgc - status: - description: |- - Status of the Certificate. - This is set and managed automatically. - Read-only. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - type: object - properties: - conditions: - description: |- - List of status conditions to indicate the status of certificates. - Known condition types are `Ready` and `Issuing`. - type: array - items: - description: CertificateCondition contains condition information for a Certificate. - type: object - required: - - status - - type - properties: - lastTransitionTime: - description: |- - LastTransitionTime is the timestamp corresponding to the last status - change of this condition. - type: string - format: date-time - message: - description: |- - Message is a human readable description of the details of the last - transition, complementing reason. - type: string - observedGeneration: - description: |- - If set, this represents the .metadata.generation that the condition was - set based upon. - For instance, if .metadata.generation is currently 12, but the - .status.condition[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the Certificate. - type: integer - format: int64 - reason: - description: |- - Reason is a brief machine readable explanation for the condition's last - transition. - type: string - status: - description: Status of the condition, one of (`True`, `False`, `Unknown`). - type: string - enum: - - "True" - - "False" - - Unknown - type: - description: Type of the condition, known values are (`Ready`, `Issuing`). - type: string - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - failedIssuanceAttempts: - description: |- - The number of continuous failed issuance attempts up till now. This - field gets removed (if set) on a successful issuance and gets set to - 1 if unset and an issuance has failed. If an issuance has failed, the - delay till the next issuance will be calculated using formula - time.Hour * 2 ^ (failedIssuanceAttempts - 1). - type: integer - lastFailureTime: - description: |- - LastFailureTime is set only if the latest issuance for this - Certificate failed and contains the time of the failure. If an - issuance has failed, the delay till the next issuance will be - calculated using formula time.Hour * 2 ^ (failedIssuanceAttempts - - 1). If the latest issuance has succeeded this field will be unset. - type: string - format: date-time - nextPrivateKeySecretName: - description: |- - The name of the Secret resource containing the private key to be used - for the next certificate iteration. - The keymanager controller will automatically set this field if the - `Issuing` condition is set to `True`. - It will automatically unset this field when the Issuing condition is - not set or False. - type: string - notAfter: - description: |- - The expiration time of the certificate stored in the secret named - by this resource in `spec.secretName`. - type: string - format: date-time - notBefore: - description: |- - The time after which the certificate stored in the secret named - by this resource in `spec.secretName` is valid. - type: string - format: date-time - renewalTime: - description: |- - RenewalTime is the time at which the certificate will be next - renewed. - If not set, no upcoming renewal is scheduled. - type: string - format: date-time - revision: - description: |- - The current 'revision' of the certificate as issued. - - When a CertificateRequest resource is created, it will have the - `cert-manager.io/certificate-revision` set to one greater than the - current value of this field. - - Upon issuance, this field will be set to the value of the annotation - on the CertificateRequest resource used to issue the certificate. - - Persisting the value on the CertificateRequest resource allows the - certificates controller to know whether a request is part of an old - issuance or if it is part of the ongoing revision's issuance by - checking if the revision value in the annotation is greater than this - field. - type: integer - served: true - storage: true - -# END crd {{- end }} - ---- -# START crd {{- if or .Values.crds.enabled .Values.installCRDs }} -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: challenges.acme.cert-manager.io - # START annotations {{- if .Values.crds.keep }} - annotations: - helm.sh/resource-policy: keep - # END annotations {{- end }} - labels: - app: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/name: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/instance: '{{ .Release.Name }}' - # Generated labels {{- include "labels" . | nindent 4 }} -spec: - group: acme.cert-manager.io - names: - kind: Challenge - listKind: ChallengeList - plural: challenges - singular: challenge - categories: - - cert-manager - - cert-manager-acme - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.state - name: State - type: string - - jsonPath: .spec.dnsName - name: Domain - type: string - - jsonPath: .status.reason - name: Reason - priority: 1 - type: string - - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1 - schema: - openAPIV3Schema: - description: Challenge is a type to represent a Challenge request with an ACME server - type: object - required: - - metadata - - spec - 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: - type: object - required: - - authorizationURL - - dnsName - - issuerRef - - key - - solver - - token - - type - - url - properties: - authorizationURL: - description: |- - The URL to the ACME Authorization resource that this - challenge is a part of. - type: string - dnsName: - description: |- - dnsName is the identifier that this challenge is for, e.g. example.com. - If the requested DNSName is a 'wildcard', this field MUST be set to the - non-wildcard domain, e.g. for `*.example.com`, it must be `example.com`. - type: string - issuerRef: - description: |- - References a properly configured ACME-type Issuer which should - be used to create this Challenge. - If the Issuer does not exist, processing will be retried. - If the Issuer is not an 'ACME' Issuer, an error will be returned and the - Challenge will be marked as failed. - type: object - required: - - name - properties: - group: - description: Group of the resource being referred to. - type: string - kind: - description: Kind of the resource being referred to. - type: string - name: - description: Name of the resource being referred to. - type: string - key: - description: |- - The ACME challenge key for this challenge - For HTTP01 challenges, this is the value that must be responded with to - complete the HTTP01 challenge in the format: - `.`. - For DNS01 challenges, this is the base64 encoded SHA256 sum of the - `.` - text that must be set as the TXT record content. - type: string - solver: - description: |- - Contains the domain solving configuration that should be used to - solve this challenge resource. - type: object - properties: - dns01: - description: |- - Configures cert-manager to attempt to complete authorizations by - performing the DNS01 challenge flow. - type: object - properties: - acmeDNS: - description: |- - Use the 'ACME DNS' (https://github.com/joohoi/acme-dns) API to manage - DNS01 challenge records. - type: object - required: - - accountSecretRef - - host - properties: - accountSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - host: - type: string - akamai: - description: Use the Akamai DNS zone management API to manage DNS01 challenge records. - type: object - required: - - accessTokenSecretRef - - clientSecretSecretRef - - clientTokenSecretRef - - serviceConsumerDomain - properties: - accessTokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientSecretSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientTokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - serviceConsumerDomain: - type: string - azureDNS: - description: Use the Microsoft Azure DNS API to manage DNS01 challenge records. - type: object - required: - - resourceGroupName - - subscriptionID - properties: - clientID: - description: |- - Auth: Azure Service Principal: - The ClientID of the Azure Service Principal used to authenticate with Azure DNS. - If set, ClientSecret and TenantID must also be set. - type: string - clientSecretSecretRef: - description: |- - Auth: Azure Service Principal: - A reference to a Secret containing the password associated with the Service Principal. - If set, ClientID and TenantID must also be set. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - environment: - description: name of the Azure environment (default AzurePublicCloud) - type: string - enum: - - AzurePublicCloud - - AzureChinaCloud - - AzureGermanCloud - - AzureUSGovernmentCloud - hostedZoneName: - description: name of the DNS zone that should be used - type: string - managedIdentity: - description: |- - Auth: Azure Workload Identity or Azure Managed Service Identity: - Settings to enable Azure Workload Identity or Azure Managed Service Identity - If set, ClientID, ClientSecret and TenantID must not be set. - type: object - properties: - clientID: - description: client ID of the managed identity, can not be used at the same time as resourceID - type: string - resourceID: - description: |- - 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 - subscriptionID: - description: ID of the Azure subscription - type: string - tenantID: - description: |- - Auth: Azure Service Principal: - The TenantID of the Azure Service Principal used to authenticate with Azure DNS. - If set, ClientID and ClientSecret must also be set. - type: string - cloudDNS: - description: Use the Google Cloud DNS API to manage DNS01 challenge records. - type: object - required: - - project - properties: - hostedZoneName: - description: |- - HostedZoneName is an optional field that tells cert-manager in which - Cloud DNS zone the challenge record has to be created. - If left empty cert-manager will automatically choose a zone. - type: string - project: - type: string - serviceAccountSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - cloudflare: - description: Use the Cloudflare API to manage DNS01 challenge records. - type: object - properties: - apiKeySecretRef: - description: |- - API key to use to authenticate with Cloudflare. - Note: using an API token to authenticate is now the recommended method - as it allows greater control of permissions. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - apiTokenSecretRef: - description: API token used to authenticate with Cloudflare. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - email: - description: Email of the account, only required when using API key based authentication. - type: string - cnameStrategy: - description: |- - CNAMEStrategy configures how the DNS01 provider should handle CNAME - records when found in DNS zones. - type: string - enum: - - None - - Follow - digitalocean: - description: Use the DigitalOcean DNS API to manage DNS01 challenge records. - type: object - required: - - tokenSecretRef - properties: - tokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - rfc2136: - description: |- - Use RFC2136 ("Dynamic Updates in the Domain Name System") (https://datatracker.ietf.org/doc/rfc2136/) - to manage DNS01 challenge records. - type: object - required: - - nameserver - properties: - nameserver: - description: |- - The IP address or hostname of an authoritative DNS server supporting - RFC2136 in the form host:port. If the host is an IPv6 address it must be - enclosed in square brackets (e.g [2001:db8::1]) ; port is optional. - This field is required. - type: string - tsigAlgorithm: - description: |- - The TSIG Algorithm configured in the DNS supporting RFC2136. Used only - when ``tsigSecretSecretRef`` and ``tsigKeyName`` are defined. - Supported values are (case-insensitive): ``HMACMD5`` (default), - ``HMACSHA1``, ``HMACSHA256`` or ``HMACSHA512``. - type: string - tsigKeyName: - description: |- - The TSIG Key name configured in the DNS. - If ``tsigSecretSecretRef`` is defined, this field is required. - type: string - tsigSecretSecretRef: - description: |- - The name of the secret containing the TSIG value. - If ``tsigKeyName`` is defined, this field is required. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - route53: - description: Use the AWS Route53 API to manage DNS01 challenge records. - type: object - properties: - accessKeyID: - description: |- - The AccessKeyID is used for authentication. - Cannot be set when SecretAccessKeyID is set. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: string - accessKeyIDSecretRef: - description: |- - The SecretAccessKey is used for authentication. If set, pull the AWS - access key ID from a key within a Kubernetes Secret. - Cannot be set when AccessKeyID is set. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - auth: - description: Auth configures how cert-manager authenticates. - type: object - required: - - kubernetes - properties: - kubernetes: - description: |- - Kubernetes authenticates with Route53 using AssumeRoleWithWebIdentity - by passing a bound ServiceAccount token. - type: object - required: - - serviceAccountRef - properties: - serviceAccountRef: - description: |- - A reference to a service account that will be used to request a bound - token (also known as "projected token"). To use this field, you must - configure an RBAC rule to let cert-manager request a token. - type: object - required: - - name - properties: - audiences: - description: |- - TokenAudiences is an optional list of audiences to include in the - token passed to AWS. The default token consisting of the issuer's namespace - and name is always included. - If unset the audience defaults to `sts.amazonaws.com`. - type: array - items: - type: string - name: - description: Name of the ServiceAccount used to request a token. - type: string - hostedZoneID: - description: If set, the provider will manage only this zone in Route53 and will not do a lookup using the route53:ListHostedZonesByName api call. - type: string - region: - description: |- - Override the AWS region. - - Route53 is a global service and does not have regional endpoints but the - region specified here (or via environment variables) is used as a hint to - help compute the correct AWS credential scope and partition when it - connects to Route53. See: - - [Amazon Route 53 endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/r53.html) - - [Global services](https://docs.aws.amazon.com/whitepapers/latest/aws-fault-isolation-boundaries/global-services.html) - - If you omit this region field, cert-manager will use the region from - AWS_REGION and AWS_DEFAULT_REGION environment variables, if they are set - in the cert-manager controller Pod. - - The `region` field is not needed if you use [IAM Roles for Service Accounts (IRSA)](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html). - Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: - [Amazon EKS Pod Identity Webhook](https://github.com/aws/amazon-eks-pod-identity-webhook). - In this case this `region` field value is ignored. - - The `region` field is not needed if you use [EKS Pod Identities](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html). - Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: - [Amazon EKS Pod Identity Agent](https://github.com/aws/eks-pod-identity-agent), - In this case this `region` field value is ignored. - type: string - role: - description: |- - Role is a Role ARN which the Route53 provider will assume using either the explicit credentials AccessKeyID/SecretAccessKey - or the inferred credentials from environment variables, shared credentials file or AWS Instance metadata - type: string - secretAccessKeySecretRef: - description: |- - The SecretAccessKey is used for authentication. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - webhook: - description: |- - Configure an external webhook based DNS01 challenge solver to manage - DNS01 challenge records. - type: object - required: - - groupName - - solverName - properties: - config: - description: |- - Additional configuration that should be passed to the webhook apiserver - when challenges are processed. - This can contain arbitrary JSON data. - Secret values should not be specified in this stanza. - If secret values are needed (e.g. credentials for a DNS service), you - should use a SecretKeySelector to reference a Secret resource. - For details on the schema of this field, consult the webhook provider - implementation's documentation. - x-kubernetes-preserve-unknown-fields: true - groupName: - description: |- - The API group name that should be used when POSTing ChallengePayload - resources to the webhook apiserver. - This should be the same as the GroupName specified in the webhook - provider implementation. - type: string - solverName: - description: |- - The name of the solver to use, as defined in the webhook provider - implementation. - This will typically be the name of the provider, e.g. 'cloudflare'. - type: string - http01: - description: |- - Configures cert-manager to attempt to complete authorizations by - performing the HTTP01 challenge flow. - It is not possible to obtain certificates for wildcard domain names - (e.g. `*.example.com`) using the HTTP01 challenge mechanism. - type: object - properties: - gatewayHTTPRoute: - description: |- - The Gateway API is a sig-network community API that models service networking - in Kubernetes (https://gateway-api.sigs.k8s.io/). The Gateway solver will - create HTTPRoutes with the specified labels in the same namespace as the challenge. - This solver is experimental, and fields / behaviour may change in the future. - type: object - properties: - labels: - description: |- - Custom labels that will be applied to HTTPRoutes created by cert-manager - while solving HTTP-01 challenges. - type: object - additionalProperties: - type: string - parentRefs: - description: |- - When solving an HTTP-01 challenge, cert-manager creates an HTTPRoute. - cert-manager needs to know which parentRefs should be used when creating - the HTTPRoute. Usually, the parentRef references a Gateway. See: - https://gateway-api.sigs.k8s.io/api-types/httproute/#attaching-to-gateways - type: array - 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. - type: object - required: - - name - properties: - group: - 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 - type: string - default: gateway.networking.k8s.io - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - kind: - 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. - type: string - default: Gateway - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - name: - description: |- - Name is the name of the referent. - - Support: Core - type: string - maxLength: 253 - minLength: 1 - 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 - type: string - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - 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 - type: integer - format: int32 - maximum: 65535 - minimum: 1 - 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 - type: string - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - podTemplate: - description: |- - Optional pod template used to configure the ACME challenge solver pods - used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the pod used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - spec: - description: |- - PodSpec defines overrides for the HTTP01 challenge solver pod. - Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. - All other fields will be ignored. - type: object - properties: - affinity: - description: If specified, the pod's scheduling constraints - type: object - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for the pod. - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - type: object - required: - - preference - - weight - properties: - preference: - description: A node selector term, associated with the corresponding weight. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - type: object - required: - - nodeSelectorTerms - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The terms are ORed. - type: array - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - imagePullSecrets: - description: If specified, the pod's imagePullSecrets - type: array - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - type: object - properties: - name: - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - default: "" - x-kubernetes-map-type: atomic - nodeSelector: - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. - More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - type: object - additionalProperties: - type: string - priorityClassName: - description: If specified, the pod's priorityClassName. - type: string - securityContext: - description: If specified, the pod's security context - type: object - properties: - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - type: object - properties: - level: - description: Level is SELinux level label that applies to the container. - type: string - role: - description: Role is a SELinux role label that applies to the container. - type: string - type: - description: Type is a SELinux type label that applies to the container. - type: string - user: - description: User is a SELinux user label that applies to the container. - type: string - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - type: object - required: - - type - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - type: integer - format: int64 - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - description: Sysctl defines a kernel parameter to be set - type: object - required: - - name - - value - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - serviceAccountName: - description: If specified, the pod's service account - type: string - tolerations: - description: If specified, the pod's tolerations. - type: array - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - type: object - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - type: integer - format: int64 - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - serviceType: - description: |- - Optional service type for Kubernetes solver service. Supported values - are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - ingress: - description: |- - The ingress based HTTP01 challenge solver will solve challenges by - creating or modifying Ingress resources in order to route requests for - '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are - provisioned by cert-manager for each Challenge to be completed. - type: object - properties: - class: - description: |- - This field configures the annotation `kubernetes.io/ingress.class` when - creating Ingress resources to solve ACME challenges that use this - challenge solver. Only one of `class`, `name` or `ingressClassName` may - be specified. - type: string - ingressClassName: - description: |- - This field configures the field `ingressClassName` on the created Ingress - resources used to solve ACME challenges that use this challenge solver. - This is the recommended way of configuring the ingress class. Only one of - `class`, `name` or `ingressClassName` may be specified. - type: string - ingressTemplate: - description: |- - Optional ingress template used to configure the ACME challenge solver - ingress used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the ingress used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - name: - description: |- - The name of the ingress resource that should have ACME challenge solving - routes inserted into it in order to solve HTTP01 challenges. - This is typically used in conjunction with ingress controllers like - ingress-gce, which maintains a 1:1 mapping between external IPs and - ingress resources. Only one of `class`, `name` or `ingressClassName` may - be specified. - type: string - podTemplate: - description: |- - Optional pod template used to configure the ACME challenge solver pods - used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the pod used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - spec: - description: |- - PodSpec defines overrides for the HTTP01 challenge solver pod. - Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. - All other fields will be ignored. - type: object - properties: - affinity: - description: If specified, the pod's scheduling constraints - type: object - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for the pod. - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - type: object - required: - - preference - - weight - properties: - preference: - description: A node selector term, associated with the corresponding weight. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - type: object - required: - - nodeSelectorTerms - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The terms are ORed. - type: array - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - imagePullSecrets: - description: If specified, the pod's imagePullSecrets - type: array - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - type: object - properties: - name: - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - default: "" - x-kubernetes-map-type: atomic - nodeSelector: - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. - More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - type: object - additionalProperties: - type: string - priorityClassName: - description: If specified, the pod's priorityClassName. - type: string - securityContext: - description: If specified, the pod's security context - type: object - properties: - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - type: object - properties: - level: - description: Level is SELinux level label that applies to the container. - type: string - role: - description: Role is a SELinux role label that applies to the container. - type: string - type: - description: Type is a SELinux type label that applies to the container. - type: string - user: - description: User is a SELinux user label that applies to the container. - type: string - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - type: object - required: - - type - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - type: integer - format: int64 - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - description: Sysctl defines a kernel parameter to be set - type: object - required: - - name - - value - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - serviceAccountName: - description: If specified, the pod's service account - type: string - tolerations: - description: If specified, the pod's tolerations. - type: array - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - type: object - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - type: integer - format: int64 - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - serviceType: - description: |- - Optional service type for Kubernetes solver service. Supported values - are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - selector: - description: |- - Selector selects a set of DNSNames on the Certificate resource that - should be solved using this challenge solver. - If not specified, the solver will be treated as the 'default' solver - with the lowest priority, i.e. if any other solver has a more specific - match, it will be used instead. - type: object - properties: - dnsNames: - description: |- - List of DNSNames that this solver will be used to solve. - If specified and a match is found, a dnsNames selector will take - precedence over a dnsZones selector. - If multiple solvers match with the same dnsNames value, the solver - with the most matching labels in matchLabels will be selected. - If neither has more matches, the solver defined earlier in the list - will be selected. - type: array - items: - type: string - dnsZones: - description: |- - List of DNSZones that this solver will be used to solve. - The most specific DNS zone match specified here will take precedence - over other DNS zone matches, so a solver specifying sys.example.com - will be selected over one specifying example.com for the domain - www.sys.example.com. - If multiple solvers match with the same dnsZones value, the solver - with the most matching labels in matchLabels will be selected. - If neither has more matches, the solver defined earlier in the list - will be selected. - type: array - items: - type: string - matchLabels: - description: |- - A label selector that is used to refine the set of certificate's that - this challenge solver will apply to. - type: object - additionalProperties: - type: string - token: - description: |- - The ACME challenge token for this challenge. - This is the raw value returned from the ACME server. - type: string - type: - description: |- - The type of ACME challenge this resource represents. - One of "HTTP-01" or "DNS-01". - type: string - enum: - - HTTP-01 - - DNS-01 - url: - description: |- - The URL of the ACME Challenge resource for this challenge. - This can be used to lookup details about the status of this challenge. - type: string - wildcard: - description: |- - wildcard will be true if this challenge is for a wildcard identifier, - for example '*.example.com'. - type: boolean - status: - type: object - properties: - presented: - description: |- - presented will be set to true if the challenge values for this challenge - are currently 'presented'. - This *does not* imply the self check is passing. Only that the values - have been 'submitted' for the appropriate challenge mechanism (i.e. the - DNS01 TXT record has been presented, or the HTTP01 configuration has been - configured). - type: boolean - processing: - description: |- - Used to denote whether this challenge should be processed or not. - This field will only be set to true by the 'scheduling' component. - It will only be set to false by the 'challenges' controller, after the - challenge has reached a final state or timed out. - If this field is set to false, the challenge controller will not take - any more action. - type: boolean - reason: - description: |- - Contains human readable information on why the Challenge is in the - current state. - type: string - state: - description: |- - Contains the current 'state' of the challenge. - If not set, the state of the challenge is unknown. - type: string - enum: - - valid - - ready - - pending - - processing - - invalid - - expired - - errored - served: true - storage: true - subresources: - status: {} - -# END crd {{- end }} - ---- -# START crd {{- if or .Values.crds.enabled .Values.installCRDs }} -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: clusterissuers.cert-manager.io - # START annotations {{- if .Values.crds.keep }} - annotations: - helm.sh/resource-policy: keep - # END annotations {{- end }} - labels: - app: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/name: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/instance: '{{ .Release.Name }}' - # Generated labels {{- include "labels" . | nindent 4 }} -spec: - group: cert-manager.io - names: - kind: ClusterIssuer - listKind: ClusterIssuerList - plural: clusterissuers - singular: clusterissuer - categories: - - cert-manager - scope: Cluster - versions: - - name: v1 - subresources: - status: {} - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: |- - A ClusterIssuer represents a certificate issuing authority which can be - referenced as part of `issuerRef` fields. - It is similar to an Issuer, however it is cluster-scoped and therefore can - be referenced by resources that exist in *any* namespace, not just the same - namespace as the referent. - type: object - required: - - spec - 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: Desired state of the ClusterIssuer resource. - type: object - properties: - acme: - description: |- - ACME configures this issuer to communicate with a RFC8555 (ACME) server - to obtain signed x509 certificates. - type: object - required: - - privateKeySecretRef - - server - properties: - caBundle: - description: |- - Base64-encoded bundle of PEM CAs which can be used to validate the certificate - chain presented by the ACME server. - Mutually exclusive with SkipTLSVerify; prefer using CABundle to prevent various - kinds of security vulnerabilities. - If CABundle and SkipTLSVerify are unset, the system certificate bundle inside - the container is used to validate the TLS connection. - type: string - format: byte - disableAccountKeyGeneration: - description: |- - Enables or disables generating a new ACME account key. - If true, the Issuer resource will *not* request a new account but will expect - the account key to be supplied via an existing secret. - If false, the cert-manager system will generate a new ACME account key - for the Issuer. - Defaults to false. - type: boolean - email: - description: |- - Email is the email address to be associated with the ACME account. - This field is optional, but it is strongly recommended to be set. - It will be used to contact you in case of issues with your account or - certificates, including expiry notification emails. - This field may be updated after the account is initially registered. - type: string - enableDurationFeature: - description: |- - Enables requesting a Not After date on certificates that matches the - duration of the certificate. This is not supported by all ACME servers - like Let's Encrypt. If set to true when the ACME server does not support - it, it will create an error on the Order. - Defaults to false. - type: boolean - externalAccountBinding: - description: |- - ExternalAccountBinding is a reference to a CA external account of the ACME - server. - If set, upon registration cert-manager will attempt to associate the given - external account credentials with the registered ACME account. - type: object - required: - - keyID - - keySecretRef - properties: - keyAlgorithm: - description: |- - Deprecated: keyAlgorithm field exists for historical compatibility - reasons and should not be used. The algorithm is now hardcoded to HS256 - in golang/x/crypto/acme. - type: string - enum: - - HS256 - - HS384 - - HS512 - keyID: - description: keyID is the ID of the CA key that the External Account is bound to. - type: string - keySecretRef: - description: |- - keySecretRef is a Secret Key Selector referencing a data item in a Kubernetes - Secret which holds the symmetric MAC key of the External Account Binding. - The `key` is the index string that is paired with the key data in the - Secret and should not be confused with the key data itself, or indeed with - the External Account Binding keyID above. - The secret key stored in the Secret **must** be un-padded, base64 URL - encoded data. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - preferredChain: - description: |- - PreferredChain is the chain to use if the ACME server outputs multiple. - PreferredChain is no guarantee that this one gets delivered by the ACME - endpoint. - For example, for Let's Encrypt's DST crosssign you would use: - "DST Root CA X3" or "ISRG Root X1" for the newer Let's Encrypt root CA. - This value picks the first certificate bundle in the combined set of - ACME default and alternative chains that has a root-most certificate with - this value as its issuer's commonname. - type: string - maxLength: 64 - privateKeySecretRef: - description: |- - PrivateKey is the name of a Kubernetes Secret resource that will be used to - store the automatically generated ACME account private key. - Optionally, a `key` may be specified to select a specific entry within - the named Secret resource. - If `key` is not specified, a default of `tls.key` will be used. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - server: - description: |- - Server is the URL used to access the ACME server's 'directory' endpoint. - For example, for Let's Encrypt's staging endpoint, you would use: - "https://acme-staging-v02.api.letsencrypt.org/directory". - Only ACME v2 endpoints (i.e. RFC 8555) are supported. - type: string - skipTLSVerify: - description: |- - INSECURE: Enables or disables validation of the ACME server TLS certificate. - If true, requests to the ACME server will not have the TLS certificate chain - validated. - Mutually exclusive with CABundle; prefer using CABundle to prevent various - kinds of security vulnerabilities. - Only enable this option in development environments. - If CABundle and SkipTLSVerify are unset, the system certificate bundle inside - the container is used to validate the TLS connection. - Defaults to false. - type: boolean - solvers: - description: |- - Solvers is a list of challenge solvers that will be used to solve - ACME challenges for the matching domains. - Solver configurations must be provided in order to obtain certificates - from an ACME server. - For more information, see: https://cert-manager.io/docs/configuration/acme/ - type: array - items: - description: |- - An ACMEChallengeSolver describes how to solve ACME challenges for the issuer it is part of. - A selector may be provided to use different solving strategies for different DNS names. - Only one of HTTP01 or DNS01 must be provided. - type: object - properties: - dns01: - description: |- - Configures cert-manager to attempt to complete authorizations by - performing the DNS01 challenge flow. - type: object - properties: - acmeDNS: - description: |- - Use the 'ACME DNS' (https://github.com/joohoi/acme-dns) API to manage - DNS01 challenge records. - type: object - required: - - accountSecretRef - - host - properties: - accountSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - host: - type: string - akamai: - description: Use the Akamai DNS zone management API to manage DNS01 challenge records. - type: object - required: - - accessTokenSecretRef - - clientSecretSecretRef - - clientTokenSecretRef - - serviceConsumerDomain - properties: - accessTokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientSecretSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientTokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - serviceConsumerDomain: - type: string - azureDNS: - description: Use the Microsoft Azure DNS API to manage DNS01 challenge records. - type: object - required: - - resourceGroupName - - subscriptionID - properties: - clientID: - description: |- - Auth: Azure Service Principal: - The ClientID of the Azure Service Principal used to authenticate with Azure DNS. - If set, ClientSecret and TenantID must also be set. - type: string - clientSecretSecretRef: - description: |- - Auth: Azure Service Principal: - A reference to a Secret containing the password associated with the Service Principal. - If set, ClientID and TenantID must also be set. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - environment: - description: name of the Azure environment (default AzurePublicCloud) - type: string - enum: - - AzurePublicCloud - - AzureChinaCloud - - AzureGermanCloud - - AzureUSGovernmentCloud - hostedZoneName: - description: name of the DNS zone that should be used - type: string - managedIdentity: - description: |- - Auth: Azure Workload Identity or Azure Managed Service Identity: - Settings to enable Azure Workload Identity or Azure Managed Service Identity - If set, ClientID, ClientSecret and TenantID must not be set. - type: object - properties: - clientID: - description: client ID of the managed identity, can not be used at the same time as resourceID - type: string - resourceID: - description: |- - 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 - subscriptionID: - description: ID of the Azure subscription - type: string - tenantID: - description: |- - Auth: Azure Service Principal: - The TenantID of the Azure Service Principal used to authenticate with Azure DNS. - If set, ClientID and ClientSecret must also be set. - type: string - cloudDNS: - description: Use the Google Cloud DNS API to manage DNS01 challenge records. - type: object - required: - - project - properties: - hostedZoneName: - description: |- - HostedZoneName is an optional field that tells cert-manager in which - Cloud DNS zone the challenge record has to be created. - If left empty cert-manager will automatically choose a zone. - type: string - project: - type: string - serviceAccountSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - cloudflare: - description: Use the Cloudflare API to manage DNS01 challenge records. - type: object - properties: - apiKeySecretRef: - description: |- - API key to use to authenticate with Cloudflare. - Note: using an API token to authenticate is now the recommended method - as it allows greater control of permissions. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - apiTokenSecretRef: - description: API token used to authenticate with Cloudflare. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - email: - description: Email of the account, only required when using API key based authentication. - type: string - cnameStrategy: - description: |- - CNAMEStrategy configures how the DNS01 provider should handle CNAME - records when found in DNS zones. - type: string - enum: - - None - - Follow - digitalocean: - description: Use the DigitalOcean DNS API to manage DNS01 challenge records. - type: object - required: - - tokenSecretRef - properties: - tokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - rfc2136: - description: |- - Use RFC2136 ("Dynamic Updates in the Domain Name System") (https://datatracker.ietf.org/doc/rfc2136/) - to manage DNS01 challenge records. - type: object - required: - - nameserver - properties: - nameserver: - description: |- - The IP address or hostname of an authoritative DNS server supporting - RFC2136 in the form host:port. If the host is an IPv6 address it must be - enclosed in square brackets (e.g [2001:db8::1]) ; port is optional. - This field is required. - type: string - tsigAlgorithm: - description: |- - The TSIG Algorithm configured in the DNS supporting RFC2136. Used only - when ``tsigSecretSecretRef`` and ``tsigKeyName`` are defined. - Supported values are (case-insensitive): ``HMACMD5`` (default), - ``HMACSHA1``, ``HMACSHA256`` or ``HMACSHA512``. - type: string - tsigKeyName: - description: |- - The TSIG Key name configured in the DNS. - If ``tsigSecretSecretRef`` is defined, this field is required. - type: string - tsigSecretSecretRef: - description: |- - The name of the secret containing the TSIG value. - If ``tsigKeyName`` is defined, this field is required. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - route53: - description: Use the AWS Route53 API to manage DNS01 challenge records. - type: object - properties: - accessKeyID: - description: |- - The AccessKeyID is used for authentication. - Cannot be set when SecretAccessKeyID is set. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: string - accessKeyIDSecretRef: - description: |- - The SecretAccessKey is used for authentication. If set, pull the AWS - access key ID from a key within a Kubernetes Secret. - Cannot be set when AccessKeyID is set. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - auth: - description: Auth configures how cert-manager authenticates. - type: object - required: - - kubernetes - properties: - kubernetes: - description: |- - Kubernetes authenticates with Route53 using AssumeRoleWithWebIdentity - by passing a bound ServiceAccount token. - type: object - required: - - serviceAccountRef - properties: - serviceAccountRef: - description: |- - A reference to a service account that will be used to request a bound - token (also known as "projected token"). To use this field, you must - configure an RBAC rule to let cert-manager request a token. - type: object - required: - - name - properties: - audiences: - description: |- - TokenAudiences is an optional list of audiences to include in the - token passed to AWS. The default token consisting of the issuer's namespace - and name is always included. - If unset the audience defaults to `sts.amazonaws.com`. - type: array - items: - type: string - name: - description: Name of the ServiceAccount used to request a token. - type: string - hostedZoneID: - description: If set, the provider will manage only this zone in Route53 and will not do a lookup using the route53:ListHostedZonesByName api call. - type: string - region: - description: |- - Override the AWS region. - - Route53 is a global service and does not have regional endpoints but the - region specified here (or via environment variables) is used as a hint to - help compute the correct AWS credential scope and partition when it - connects to Route53. See: - - [Amazon Route 53 endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/r53.html) - - [Global services](https://docs.aws.amazon.com/whitepapers/latest/aws-fault-isolation-boundaries/global-services.html) - - If you omit this region field, cert-manager will use the region from - AWS_REGION and AWS_DEFAULT_REGION environment variables, if they are set - in the cert-manager controller Pod. - - The `region` field is not needed if you use [IAM Roles for Service Accounts (IRSA)](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html). - Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: - [Amazon EKS Pod Identity Webhook](https://github.com/aws/amazon-eks-pod-identity-webhook). - In this case this `region` field value is ignored. - - The `region` field is not needed if you use [EKS Pod Identities](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html). - Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: - [Amazon EKS Pod Identity Agent](https://github.com/aws/eks-pod-identity-agent), - In this case this `region` field value is ignored. - type: string - role: - description: |- - Role is a Role ARN which the Route53 provider will assume using either the explicit credentials AccessKeyID/SecretAccessKey - or the inferred credentials from environment variables, shared credentials file or AWS Instance metadata - type: string - secretAccessKeySecretRef: - description: |- - The SecretAccessKey is used for authentication. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - webhook: - description: |- - Configure an external webhook based DNS01 challenge solver to manage - DNS01 challenge records. - type: object - required: - - groupName - - solverName - properties: - config: - description: |- - Additional configuration that should be passed to the webhook apiserver - when challenges are processed. - This can contain arbitrary JSON data. - Secret values should not be specified in this stanza. - If secret values are needed (e.g. credentials for a DNS service), you - should use a SecretKeySelector to reference a Secret resource. - For details on the schema of this field, consult the webhook provider - implementation's documentation. - x-kubernetes-preserve-unknown-fields: true - groupName: - description: |- - The API group name that should be used when POSTing ChallengePayload - resources to the webhook apiserver. - This should be the same as the GroupName specified in the webhook - provider implementation. - type: string - solverName: - description: |- - The name of the solver to use, as defined in the webhook provider - implementation. - This will typically be the name of the provider, e.g. 'cloudflare'. - type: string - http01: - description: |- - Configures cert-manager to attempt to complete authorizations by - performing the HTTP01 challenge flow. - It is not possible to obtain certificates for wildcard domain names - (e.g. `*.example.com`) using the HTTP01 challenge mechanism. - type: object - properties: - gatewayHTTPRoute: - description: |- - The Gateway API is a sig-network community API that models service networking - in Kubernetes (https://gateway-api.sigs.k8s.io/). The Gateway solver will - create HTTPRoutes with the specified labels in the same namespace as the challenge. - This solver is experimental, and fields / behaviour may change in the future. - type: object - properties: - labels: - description: |- - Custom labels that will be applied to HTTPRoutes created by cert-manager - while solving HTTP-01 challenges. - type: object - additionalProperties: - type: string - parentRefs: - description: |- - When solving an HTTP-01 challenge, cert-manager creates an HTTPRoute. - cert-manager needs to know which parentRefs should be used when creating - the HTTPRoute. Usually, the parentRef references a Gateway. See: - https://gateway-api.sigs.k8s.io/api-types/httproute/#attaching-to-gateways - type: array - 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. - type: object - required: - - name - properties: - group: - 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 - type: string - default: gateway.networking.k8s.io - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - kind: - 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. - type: string - default: Gateway - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - name: - description: |- - Name is the name of the referent. - - Support: Core - type: string - maxLength: 253 - minLength: 1 - 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 - type: string - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - 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 - type: integer - format: int32 - maximum: 65535 - minimum: 1 - 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 - type: string - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - podTemplate: - description: |- - Optional pod template used to configure the ACME challenge solver pods - used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the pod used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - spec: - description: |- - PodSpec defines overrides for the HTTP01 challenge solver pod. - Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. - All other fields will be ignored. - type: object - properties: - affinity: - description: If specified, the pod's scheduling constraints - type: object - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for the pod. - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - type: object - required: - - preference - - weight - properties: - preference: - description: A node selector term, associated with the corresponding weight. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - type: object - required: - - nodeSelectorTerms - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The terms are ORed. - type: array - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - imagePullSecrets: - description: If specified, the pod's imagePullSecrets - type: array - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - type: object - properties: - name: - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - default: "" - x-kubernetes-map-type: atomic - nodeSelector: - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. - More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - type: object - additionalProperties: - type: string - priorityClassName: - description: If specified, the pod's priorityClassName. - type: string - securityContext: - description: If specified, the pod's security context - type: object - properties: - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - type: object - properties: - level: - description: Level is SELinux level label that applies to the container. - type: string - role: - description: Role is a SELinux role label that applies to the container. - type: string - type: - description: Type is a SELinux type label that applies to the container. - type: string - user: - description: User is a SELinux user label that applies to the container. - type: string - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - type: object - required: - - type - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - type: integer - format: int64 - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - description: Sysctl defines a kernel parameter to be set - type: object - required: - - name - - value - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - serviceAccountName: - description: If specified, the pod's service account - type: string - tolerations: - description: If specified, the pod's tolerations. - type: array - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - type: object - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - type: integer - format: int64 - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - serviceType: - description: |- - Optional service type for Kubernetes solver service. Supported values - are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - ingress: - description: |- - The ingress based HTTP01 challenge solver will solve challenges by - creating or modifying Ingress resources in order to route requests for - '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are - provisioned by cert-manager for each Challenge to be completed. - type: object - properties: - class: - description: |- - This field configures the annotation `kubernetes.io/ingress.class` when - creating Ingress resources to solve ACME challenges that use this - challenge solver. Only one of `class`, `name` or `ingressClassName` may - be specified. - type: string - ingressClassName: - description: |- - This field configures the field `ingressClassName` on the created Ingress - resources used to solve ACME challenges that use this challenge solver. - This is the recommended way of configuring the ingress class. Only one of - `class`, `name` or `ingressClassName` may be specified. - type: string - ingressTemplate: - description: |- - Optional ingress template used to configure the ACME challenge solver - ingress used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the ingress used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - name: - description: |- - The name of the ingress resource that should have ACME challenge solving - routes inserted into it in order to solve HTTP01 challenges. - This is typically used in conjunction with ingress controllers like - ingress-gce, which maintains a 1:1 mapping between external IPs and - ingress resources. Only one of `class`, `name` or `ingressClassName` may - be specified. - type: string - podTemplate: - description: |- - Optional pod template used to configure the ACME challenge solver pods - used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the pod used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - spec: - description: |- - PodSpec defines overrides for the HTTP01 challenge solver pod. - Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. - All other fields will be ignored. - type: object - properties: - affinity: - description: If specified, the pod's scheduling constraints - type: object - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for the pod. - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - type: object - required: - - preference - - weight - properties: - preference: - description: A node selector term, associated with the corresponding weight. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - type: object - required: - - nodeSelectorTerms - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The terms are ORed. - type: array - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - imagePullSecrets: - description: If specified, the pod's imagePullSecrets - type: array - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - type: object - properties: - name: - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - default: "" - x-kubernetes-map-type: atomic - nodeSelector: - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. - More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - type: object - additionalProperties: - type: string - priorityClassName: - description: If specified, the pod's priorityClassName. - type: string - securityContext: - description: If specified, the pod's security context - type: object - properties: - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - type: object - properties: - level: - description: Level is SELinux level label that applies to the container. - type: string - role: - description: Role is a SELinux role label that applies to the container. - type: string - type: - description: Type is a SELinux type label that applies to the container. - type: string - user: - description: User is a SELinux user label that applies to the container. - type: string - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - type: object - required: - - type - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - type: integer - format: int64 - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - description: Sysctl defines a kernel parameter to be set - type: object - required: - - name - - value - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - serviceAccountName: - description: If specified, the pod's service account - type: string - tolerations: - description: If specified, the pod's tolerations. - type: array - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - type: object - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - type: integer - format: int64 - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - serviceType: - description: |- - Optional service type for Kubernetes solver service. Supported values - are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - selector: - description: |- - Selector selects a set of DNSNames on the Certificate resource that - should be solved using this challenge solver. - If not specified, the solver will be treated as the 'default' solver - with the lowest priority, i.e. if any other solver has a more specific - match, it will be used instead. - type: object - properties: - dnsNames: - description: |- - List of DNSNames that this solver will be used to solve. - If specified and a match is found, a dnsNames selector will take - precedence over a dnsZones selector. - If multiple solvers match with the same dnsNames value, the solver - with the most matching labels in matchLabels will be selected. - If neither has more matches, the solver defined earlier in the list - will be selected. - type: array - items: - type: string - dnsZones: - description: |- - List of DNSZones that this solver will be used to solve. - The most specific DNS zone match specified here will take precedence - over other DNS zone matches, so a solver specifying sys.example.com - will be selected over one specifying example.com for the domain - www.sys.example.com. - If multiple solvers match with the same dnsZones value, the solver - with the most matching labels in matchLabels will be selected. - If neither has more matches, the solver defined earlier in the list - will be selected. - type: array - items: - type: string - matchLabels: - description: |- - A label selector that is used to refine the set of certificate's that - this challenge solver will apply to. - type: object - additionalProperties: - type: string - ca: - description: |- - CA configures this issuer to sign certificates using a signing CA keypair - stored in a Secret resource. - This is used to build internal PKIs that are managed by cert-manager. - type: object - required: - - secretName - properties: - crlDistributionPoints: - description: |- - The CRL distribution points is an X.509 v3 certificate extension which identifies - the location of the CRL from which the revocation of this certificate can be checked. - If not set, certificates will be issued without distribution points set. - type: array - items: - type: string - issuingCertificateURLs: - description: |- - IssuingCertificateURLs is a list of URLs which this issuer should embed into certificates - it creates. See https://www.rfc-editor.org/rfc/rfc5280#section-4.2.2.1 for more details. - As an example, such a URL might be "http://ca.domain.com/ca.crt". - type: array - items: - type: string - ocspServers: - description: |- - The OCSP server list is an X.509 v3 extension that defines a list of - URLs of OCSP responders. The OCSP responders can be queried for the - revocation status of an issued certificate. If not set, the - certificate will be issued with no OCSP servers set. For example, an - OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org". - type: array - items: - type: string - secretName: - description: |- - SecretName is the name of the secret used to sign Certificates issued - by this Issuer. - type: string - selfSigned: - description: |- - SelfSigned configures this issuer to 'self sign' certificates using the - private key used to create the CertificateRequest object. - type: object - properties: - crlDistributionPoints: - description: |- - The CRL distribution points is an X.509 v3 certificate extension which identifies - the location of the CRL from which the revocation of this certificate can be checked. - If not set certificate will be issued without CDP. Values are strings. - type: array - items: - type: string - vault: - description: |- - Vault configures this issuer to sign certificates using a HashiCorp Vault - PKI backend. - type: object - required: - - auth - - path - - server - properties: - auth: - description: Auth configures how cert-manager authenticates with the Vault server. - type: object - properties: - appRole: - description: |- - AppRole authenticates with Vault using the App Role auth mechanism, - with the role and secret stored in a Kubernetes Secret resource. - type: object - required: - - path - - roleId - - secretRef - properties: - path: - description: |- - Path where the App Role authentication backend is mounted in Vault, e.g: - "approle" - type: string - roleId: - description: |- - RoleID configured in the App Role authentication backend when setting - up the authentication backend in Vault. - type: string - secretRef: - description: |- - Reference to a key in a Secret that contains the App Role secret used - to authenticate with Vault. - The `key` field must be specified and denotes which entry within the Secret - resource is used as the app role secret. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientCertificate: - description: |- - ClientCertificate authenticates with Vault by presenting a client - certificate during the request's TLS handshake. - Works only when using HTTPS protocol. - type: object - properties: - mountPath: - description: |- - The Vault mountPath here is the mount path to use when authenticating with - Vault. For example, setting a value to `/v1/auth/foo`, will use the path - `/v1/auth/foo/login` to authenticate with Vault. If unspecified, the - default value "/v1/auth/cert" will be used. - type: string - name: - description: |- - Name of the certificate role to authenticate against. - If not set, matching any certificate role, if available. - type: string - secretName: - description: |- - Reference to Kubernetes Secret of type "kubernetes.io/tls" (hence containing - tls.crt and tls.key) used to authenticate to Vault using TLS client - authentication. - type: string - kubernetes: - description: |- - Kubernetes authenticates with Vault by passing the ServiceAccount - token stored in the named Secret resource to the Vault server. - type: object - required: - - role - properties: - mountPath: - description: |- - The Vault mountPath here is the mount path to use when authenticating with - Vault. For example, setting a value to `/v1/auth/foo`, will use the path - `/v1/auth/foo/login` to authenticate with Vault. If unspecified, the - default value "/v1/auth/kubernetes" will be used. - type: string - role: - description: |- - A required field containing the Vault Role to assume. A Role binds a - Kubernetes ServiceAccount with a set of Vault policies. - type: string - secretRef: - description: |- - The required Secret field containing a Kubernetes ServiceAccount JWT used - for authenticating with Vault. Use of 'ambient credentials' is not - supported. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - serviceAccountRef: - description: |- - A reference to a service account that will be used to request a bound - token (also known as "projected token"). Compared to using "secretRef", - using this field means that you don't rely on statically bound tokens. To - use this field, you must configure an RBAC rule to let cert-manager - request a token. - type: object - required: - - name - properties: - audiences: - description: |- - TokenAudiences is an optional list of extra audiences to include in the token passed to Vault. The default token - consisting of the issuer's namespace and name is always included. - type: array - items: - type: string - name: - description: Name of the ServiceAccount used to request a token. - type: string - tokenSecretRef: - description: TokenSecretRef authenticates with Vault by presenting a token. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - caBundle: - description: |- - Base64-encoded bundle of PEM CAs which will be used to validate the certificate - chain presented by Vault. Only used if using HTTPS to connect to Vault and - ignored for HTTP connections. - Mutually exclusive with CABundleSecretRef. - If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in - the cert-manager controller container is used to validate the TLS connection. - type: string - format: byte - caBundleSecretRef: - description: |- - Reference to a Secret containing a bundle of PEM-encoded CAs to use when - verifying the certificate chain presented by Vault when using HTTPS. - Mutually exclusive with CABundle. - If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in - the cert-manager controller container is used to validate the TLS connection. - If no key for the Secret is specified, cert-manager will default to 'ca.crt'. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientCertSecretRef: - description: |- - Reference to a Secret containing a PEM-encoded Client Certificate to use when the - Vault server requires mTLS. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientKeySecretRef: - description: |- - Reference to a Secret containing a PEM-encoded Client Private Key to use when the - Vault server requires mTLS. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1" - More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces - type: string - path: - description: |- - Path is the mount path of the Vault PKI backend's `sign` endpoint, e.g: - "my_pki_mount/sign/my-role-name". - type: string - server: - description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' - type: string - venafi: - description: |- - Venafi configures this issuer to sign certificates using a Venafi TPP - or Venafi Cloud policy zone. - type: object - required: - - zone - properties: - cloud: - description: |- - Cloud specifies the Venafi cloud configuration settings. - Only one of TPP or Cloud may be specified. - type: object - required: - - apiTokenSecretRef - properties: - apiTokenSecretRef: - description: APITokenSecretRef is a secret key selector for the Venafi Cloud API token. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - url: - description: |- - URL is the base URL for Venafi Cloud. - Defaults to "https://api.venafi.cloud/v1". - type: string - tpp: - description: |- - TPP specifies Trust Protection Platform configuration settings. - Only one of TPP or Cloud may be specified. - type: object - required: - - credentialsRef - - url - properties: - caBundle: - description: |- - Base64-encoded bundle of PEM CAs which will be used to validate the certificate - chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP. - If undefined, the certificate bundle in the cert-manager controller container - is used to validate the chain. - type: string - format: byte - caBundleSecretRef: - description: |- - Reference to a Secret containing a base64-encoded bundle of PEM CAs - which will be used to validate the certificate chain presented by the TPP server. - Only used if using HTTPS; ignored for HTTP. Mutually exclusive with CABundle. - If neither CABundle nor CABundleSecretRef is defined, the certificate bundle in - the cert-manager controller container is used to validate the TLS connection. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - credentialsRef: - description: |- - CredentialsRef is a reference to a Secret containing the Venafi TPP API credentials. - The secret must contain the key 'access-token' for the Access Token Authentication, - or two keys, 'username' and 'password' for the API Keys Authentication. - type: object - required: - - name - properties: - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - url: - description: |- - URL is the base URL for the vedsdk endpoint of the Venafi TPP instance, - for example: "https://tpp.example.com/vedsdk". - type: string - zone: - description: |- - Zone is the Venafi Policy Zone to use for this issuer. - All requests made to the Venafi platform will be restricted by the named - zone policy. - This field is required. - type: string - status: - description: Status of the ClusterIssuer. This is set and managed automatically. - type: object - properties: - acme: - description: |- - ACME specific status options. - This field should only be set if the Issuer is configured to use an ACME - server to issue certificates. - type: object - properties: - lastPrivateKeyHash: - description: |- - LastPrivateKeyHash is a hash of the private key associated with the latest - registered ACME account, in order to track changes made to registered account - associated with the Issuer - type: string - lastRegisteredEmail: - description: |- - LastRegisteredEmail is the email associated with the latest registered - ACME account, in order to track changes made to registered account - associated with the Issuer - type: string - uri: - description: |- - URI is the unique account identifier, which can also be used to retrieve - account details from the CA - type: string - conditions: - description: |- - List of status conditions to indicate the status of a CertificateRequest. - Known condition types are `Ready`. - type: array - items: - description: IssuerCondition contains condition information for an Issuer. - type: object - required: - - status - - type - properties: - lastTransitionTime: - description: |- - LastTransitionTime is the timestamp corresponding to the last status - change of this condition. - type: string - format: date-time - message: - description: |- - Message is a human readable description of the details of the last - transition, complementing reason. - type: string - observedGeneration: - description: |- - If set, this represents the .metadata.generation that the condition was - set based upon. - For instance, if .metadata.generation is currently 12, but the - .status.condition[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the Issuer. - type: integer - format: int64 - reason: - description: |- - Reason is a brief machine readable explanation for the condition's last - transition. - type: string - status: - description: Status of the condition, one of (`True`, `False`, `Unknown`). - type: string - enum: - - "True" - - "False" - - Unknown - type: - description: Type of the condition, known values are (`Ready`). - type: string - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - served: true - storage: true - -# END crd {{- end }} - ---- -# START crd {{- if or .Values.crds.enabled .Values.installCRDs }} -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: issuers.cert-manager.io - # START annotations {{- if .Values.crds.keep }} - annotations: - helm.sh/resource-policy: keep - # END annotations {{- end }} - labels: - app: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/name: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/instance: '{{ .Release.Name }}' - app.kubernetes.io/component: "crds" - # Generated labels {{- include "labels" . | nindent 4 }} -spec: - group: cert-manager.io - names: - kind: Issuer - listKind: IssuerList - plural: issuers - singular: issuer - categories: - - cert-manager - scope: Namespaced - versions: - - name: v1 - subresources: - status: {} - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: |- - An Issuer represents a certificate issuing authority which can be - referenced as part of `issuerRef` fields. - It is scoped to a single namespace and can therefore only be referenced by - resources within the same namespace. - type: object - required: - - spec - 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: Desired state of the Issuer resource. - type: object - properties: - acme: - description: |- - ACME configures this issuer to communicate with a RFC8555 (ACME) server - to obtain signed x509 certificates. - type: object - required: - - privateKeySecretRef - - server - properties: - caBundle: - description: |- - Base64-encoded bundle of PEM CAs which can be used to validate the certificate - chain presented by the ACME server. - Mutually exclusive with SkipTLSVerify; prefer using CABundle to prevent various - kinds of security vulnerabilities. - If CABundle and SkipTLSVerify are unset, the system certificate bundle inside - the container is used to validate the TLS connection. - type: string - format: byte - disableAccountKeyGeneration: - description: |- - Enables or disables generating a new ACME account key. - If true, the Issuer resource will *not* request a new account but will expect - the account key to be supplied via an existing secret. - If false, the cert-manager system will generate a new ACME account key - for the Issuer. - Defaults to false. - type: boolean - email: - description: |- - Email is the email address to be associated with the ACME account. - This field is optional, but it is strongly recommended to be set. - It will be used to contact you in case of issues with your account or - certificates, including expiry notification emails. - This field may be updated after the account is initially registered. - type: string - enableDurationFeature: - description: |- - Enables requesting a Not After date on certificates that matches the - duration of the certificate. This is not supported by all ACME servers - like Let's Encrypt. If set to true when the ACME server does not support - it, it will create an error on the Order. - Defaults to false. - type: boolean - externalAccountBinding: - description: |- - ExternalAccountBinding is a reference to a CA external account of the ACME - server. - If set, upon registration cert-manager will attempt to associate the given - external account credentials with the registered ACME account. - type: object - required: - - keyID - - keySecretRef - properties: - keyAlgorithm: - description: |- - Deprecated: keyAlgorithm field exists for historical compatibility - reasons and should not be used. The algorithm is now hardcoded to HS256 - in golang/x/crypto/acme. - type: string - enum: - - HS256 - - HS384 - - HS512 - keyID: - description: keyID is the ID of the CA key that the External Account is bound to. - type: string - keySecretRef: - description: |- - keySecretRef is a Secret Key Selector referencing a data item in a Kubernetes - Secret which holds the symmetric MAC key of the External Account Binding. - The `key` is the index string that is paired with the key data in the - Secret and should not be confused with the key data itself, or indeed with - the External Account Binding keyID above. - The secret key stored in the Secret **must** be un-padded, base64 URL - encoded data. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - preferredChain: - description: |- - PreferredChain is the chain to use if the ACME server outputs multiple. - PreferredChain is no guarantee that this one gets delivered by the ACME - endpoint. - For example, for Let's Encrypt's DST crosssign you would use: - "DST Root CA X3" or "ISRG Root X1" for the newer Let's Encrypt root CA. - This value picks the first certificate bundle in the combined set of - ACME default and alternative chains that has a root-most certificate with - this value as its issuer's commonname. - type: string - maxLength: 64 - privateKeySecretRef: - description: |- - PrivateKey is the name of a Kubernetes Secret resource that will be used to - store the automatically generated ACME account private key. - Optionally, a `key` may be specified to select a specific entry within - the named Secret resource. - If `key` is not specified, a default of `tls.key` will be used. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - server: - description: |- - Server is the URL used to access the ACME server's 'directory' endpoint. - For example, for Let's Encrypt's staging endpoint, you would use: - "https://acme-staging-v02.api.letsencrypt.org/directory". - Only ACME v2 endpoints (i.e. RFC 8555) are supported. - type: string - skipTLSVerify: - description: |- - INSECURE: Enables or disables validation of the ACME server TLS certificate. - If true, requests to the ACME server will not have the TLS certificate chain - validated. - Mutually exclusive with CABundle; prefer using CABundle to prevent various - kinds of security vulnerabilities. - Only enable this option in development environments. - If CABundle and SkipTLSVerify are unset, the system certificate bundle inside - the container is used to validate the TLS connection. - Defaults to false. - type: boolean - solvers: - description: |- - Solvers is a list of challenge solvers that will be used to solve - ACME challenges for the matching domains. - Solver configurations must be provided in order to obtain certificates - from an ACME server. - For more information, see: https://cert-manager.io/docs/configuration/acme/ - type: array - items: - description: |- - An ACMEChallengeSolver describes how to solve ACME challenges for the issuer it is part of. - A selector may be provided to use different solving strategies for different DNS names. - Only one of HTTP01 or DNS01 must be provided. - type: object - properties: - dns01: - description: |- - Configures cert-manager to attempt to complete authorizations by - performing the DNS01 challenge flow. - type: object - properties: - acmeDNS: - description: |- - Use the 'ACME DNS' (https://github.com/joohoi/acme-dns) API to manage - DNS01 challenge records. - type: object - required: - - accountSecretRef - - host - properties: - accountSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - host: - type: string - akamai: - description: Use the Akamai DNS zone management API to manage DNS01 challenge records. - type: object - required: - - accessTokenSecretRef - - clientSecretSecretRef - - clientTokenSecretRef - - serviceConsumerDomain - properties: - accessTokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientSecretSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientTokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - serviceConsumerDomain: - type: string - azureDNS: - description: Use the Microsoft Azure DNS API to manage DNS01 challenge records. - type: object - required: - - resourceGroupName - - subscriptionID - properties: - clientID: - description: |- - Auth: Azure Service Principal: - The ClientID of the Azure Service Principal used to authenticate with Azure DNS. - If set, ClientSecret and TenantID must also be set. - type: string - clientSecretSecretRef: - description: |- - Auth: Azure Service Principal: - A reference to a Secret containing the password associated with the Service Principal. - If set, ClientID and TenantID must also be set. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - environment: - description: name of the Azure environment (default AzurePublicCloud) - type: string - enum: - - AzurePublicCloud - - AzureChinaCloud - - AzureGermanCloud - - AzureUSGovernmentCloud - hostedZoneName: - description: name of the DNS zone that should be used - type: string - managedIdentity: - description: |- - Auth: Azure Workload Identity or Azure Managed Service Identity: - Settings to enable Azure Workload Identity or Azure Managed Service Identity - If set, ClientID, ClientSecret and TenantID must not be set. - type: object - properties: - clientID: - description: client ID of the managed identity, can not be used at the same time as resourceID - type: string - resourceID: - description: |- - 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 - subscriptionID: - description: ID of the Azure subscription - type: string - tenantID: - description: |- - Auth: Azure Service Principal: - The TenantID of the Azure Service Principal used to authenticate with Azure DNS. - If set, ClientID and ClientSecret must also be set. - type: string - cloudDNS: - description: Use the Google Cloud DNS API to manage DNS01 challenge records. - type: object - required: - - project - properties: - hostedZoneName: - description: |- - HostedZoneName is an optional field that tells cert-manager in which - Cloud DNS zone the challenge record has to be created. - If left empty cert-manager will automatically choose a zone. - type: string - project: - type: string - serviceAccountSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - cloudflare: - description: Use the Cloudflare API to manage DNS01 challenge records. - type: object - properties: - apiKeySecretRef: - description: |- - API key to use to authenticate with Cloudflare. - Note: using an API token to authenticate is now the recommended method - as it allows greater control of permissions. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - apiTokenSecretRef: - description: API token used to authenticate with Cloudflare. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - email: - description: Email of the account, only required when using API key based authentication. - type: string - cnameStrategy: - description: |- - CNAMEStrategy configures how the DNS01 provider should handle CNAME - records when found in DNS zones. - type: string - enum: - - None - - Follow - digitalocean: - description: Use the DigitalOcean DNS API to manage DNS01 challenge records. - type: object - required: - - tokenSecretRef - properties: - tokenSecretRef: - description: |- - A reference to a specific 'key' within a Secret resource. - In some instances, `key` is a required field. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - rfc2136: - description: |- - Use RFC2136 ("Dynamic Updates in the Domain Name System") (https://datatracker.ietf.org/doc/rfc2136/) - to manage DNS01 challenge records. - type: object - required: - - nameserver - properties: - nameserver: - description: |- - The IP address or hostname of an authoritative DNS server supporting - RFC2136 in the form host:port. If the host is an IPv6 address it must be - enclosed in square brackets (e.g [2001:db8::1]) ; port is optional. - This field is required. - type: string - tsigAlgorithm: - description: |- - The TSIG Algorithm configured in the DNS supporting RFC2136. Used only - when ``tsigSecretSecretRef`` and ``tsigKeyName`` are defined. - Supported values are (case-insensitive): ``HMACMD5`` (default), - ``HMACSHA1``, ``HMACSHA256`` or ``HMACSHA512``. - type: string - tsigKeyName: - description: |- - The TSIG Key name configured in the DNS. - If ``tsigSecretSecretRef`` is defined, this field is required. - type: string - tsigSecretSecretRef: - description: |- - The name of the secret containing the TSIG value. - If ``tsigKeyName`` is defined, this field is required. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - route53: - description: Use the AWS Route53 API to manage DNS01 challenge records. - type: object - properties: - accessKeyID: - description: |- - The AccessKeyID is used for authentication. - Cannot be set when SecretAccessKeyID is set. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: string - accessKeyIDSecretRef: - description: |- - The SecretAccessKey is used for authentication. If set, pull the AWS - access key ID from a key within a Kubernetes Secret. - Cannot be set when AccessKeyID is set. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - auth: - description: Auth configures how cert-manager authenticates. - type: object - required: - - kubernetes - properties: - kubernetes: - description: |- - Kubernetes authenticates with Route53 using AssumeRoleWithWebIdentity - by passing a bound ServiceAccount token. - type: object - required: - - serviceAccountRef - properties: - serviceAccountRef: - description: |- - A reference to a service account that will be used to request a bound - token (also known as "projected token"). To use this field, you must - configure an RBAC rule to let cert-manager request a token. - type: object - required: - - name - properties: - audiences: - description: |- - TokenAudiences is an optional list of audiences to include in the - token passed to AWS. The default token consisting of the issuer's namespace - and name is always included. - If unset the audience defaults to `sts.amazonaws.com`. - type: array - items: - type: string - name: - description: Name of the ServiceAccount used to request a token. - type: string - hostedZoneID: - description: If set, the provider will manage only this zone in Route53 and will not do a lookup using the route53:ListHostedZonesByName api call. - type: string - region: - description: |- - Override the AWS region. - - Route53 is a global service and does not have regional endpoints but the - region specified here (or via environment variables) is used as a hint to - help compute the correct AWS credential scope and partition when it - connects to Route53. See: - - [Amazon Route 53 endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/r53.html) - - [Global services](https://docs.aws.amazon.com/whitepapers/latest/aws-fault-isolation-boundaries/global-services.html) - - If you omit this region field, cert-manager will use the region from - AWS_REGION and AWS_DEFAULT_REGION environment variables, if they are set - in the cert-manager controller Pod. - - The `region` field is not needed if you use [IAM Roles for Service Accounts (IRSA)](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html). - Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: - [Amazon EKS Pod Identity Webhook](https://github.com/aws/amazon-eks-pod-identity-webhook). - In this case this `region` field value is ignored. - - The `region` field is not needed if you use [EKS Pod Identities](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html). - Instead an AWS_REGION environment variable is added to the cert-manager controller Pod by: - [Amazon EKS Pod Identity Agent](https://github.com/aws/eks-pod-identity-agent), - In this case this `region` field value is ignored. - type: string - role: - description: |- - Role is a Role ARN which the Route53 provider will assume using either the explicit credentials AccessKeyID/SecretAccessKey - or the inferred credentials from environment variables, shared credentials file or AWS Instance metadata - type: string - secretAccessKeySecretRef: - description: |- - The SecretAccessKey is used for authentication. - If neither the Access Key nor Key ID are set, we fall-back to using env - vars, shared credentials file or AWS Instance metadata, - see: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - webhook: - description: |- - Configure an external webhook based DNS01 challenge solver to manage - DNS01 challenge records. - type: object - required: - - groupName - - solverName - properties: - config: - description: |- - Additional configuration that should be passed to the webhook apiserver - when challenges are processed. - This can contain arbitrary JSON data. - Secret values should not be specified in this stanza. - If secret values are needed (e.g. credentials for a DNS service), you - should use a SecretKeySelector to reference a Secret resource. - For details on the schema of this field, consult the webhook provider - implementation's documentation. - x-kubernetes-preserve-unknown-fields: true - groupName: - description: |- - The API group name that should be used when POSTing ChallengePayload - resources to the webhook apiserver. - This should be the same as the GroupName specified in the webhook - provider implementation. - type: string - solverName: - description: |- - The name of the solver to use, as defined in the webhook provider - implementation. - This will typically be the name of the provider, e.g. 'cloudflare'. - type: string - http01: - description: |- - Configures cert-manager to attempt to complete authorizations by - performing the HTTP01 challenge flow. - It is not possible to obtain certificates for wildcard domain names - (e.g. `*.example.com`) using the HTTP01 challenge mechanism. - type: object - properties: - gatewayHTTPRoute: - description: |- - The Gateway API is a sig-network community API that models service networking - in Kubernetes (https://gateway-api.sigs.k8s.io/). The Gateway solver will - create HTTPRoutes with the specified labels in the same namespace as the challenge. - This solver is experimental, and fields / behaviour may change in the future. - type: object - properties: - labels: - description: |- - Custom labels that will be applied to HTTPRoutes created by cert-manager - while solving HTTP-01 challenges. - type: object - additionalProperties: - type: string - parentRefs: - description: |- - When solving an HTTP-01 challenge, cert-manager creates an HTTPRoute. - cert-manager needs to know which parentRefs should be used when creating - the HTTPRoute. Usually, the parentRef references a Gateway. See: - https://gateway-api.sigs.k8s.io/api-types/httproute/#attaching-to-gateways - type: array - 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. - type: object - required: - - name - properties: - group: - 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 - type: string - default: gateway.networking.k8s.io - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - kind: - 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. - type: string - default: Gateway - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - name: - description: |- - Name is the name of the referent. - - Support: Core - type: string - maxLength: 253 - minLength: 1 - 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 - type: string - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - 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 - type: integer - format: int32 - maximum: 65535 - minimum: 1 - 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 - type: string - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - podTemplate: - description: |- - Optional pod template used to configure the ACME challenge solver pods - used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the pod used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - spec: - description: |- - PodSpec defines overrides for the HTTP01 challenge solver pod. - Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. - All other fields will be ignored. - type: object - properties: - affinity: - description: If specified, the pod's scheduling constraints - type: object - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for the pod. - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - type: object - required: - - preference - - weight - properties: - preference: - description: A node selector term, associated with the corresponding weight. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - type: object - required: - - nodeSelectorTerms - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The terms are ORed. - type: array - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - imagePullSecrets: - description: If specified, the pod's imagePullSecrets - type: array - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - type: object - properties: - name: - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - default: "" - x-kubernetes-map-type: atomic - nodeSelector: - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. - More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - type: object - additionalProperties: - type: string - priorityClassName: - description: If specified, the pod's priorityClassName. - type: string - securityContext: - description: If specified, the pod's security context - type: object - properties: - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - type: object - properties: - level: - description: Level is SELinux level label that applies to the container. - type: string - role: - description: Role is a SELinux role label that applies to the container. - type: string - type: - description: Type is a SELinux type label that applies to the container. - type: string - user: - description: User is a SELinux user label that applies to the container. - type: string - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - type: object - required: - - type - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - type: integer - format: int64 - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - description: Sysctl defines a kernel parameter to be set - type: object - required: - - name - - value - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - serviceAccountName: - description: If specified, the pod's service account - type: string - tolerations: - description: If specified, the pod's tolerations. - type: array - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - type: object - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - type: integer - format: int64 - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - serviceType: - description: |- - Optional service type for Kubernetes solver service. Supported values - are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - ingress: - description: |- - The ingress based HTTP01 challenge solver will solve challenges by - creating or modifying Ingress resources in order to route requests for - '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are - provisioned by cert-manager for each Challenge to be completed. - type: object - properties: - class: - description: |- - This field configures the annotation `kubernetes.io/ingress.class` when - creating Ingress resources to solve ACME challenges that use this - challenge solver. Only one of `class`, `name` or `ingressClassName` may - be specified. - type: string - ingressClassName: - description: |- - This field configures the field `ingressClassName` on the created Ingress - resources used to solve ACME challenges that use this challenge solver. - This is the recommended way of configuring the ingress class. Only one of - `class`, `name` or `ingressClassName` may be specified. - type: string - ingressTemplate: - description: |- - Optional ingress template used to configure the ACME challenge solver - ingress used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the ingress used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver ingress. - type: object - additionalProperties: - type: string - name: - description: |- - The name of the ingress resource that should have ACME challenge solving - routes inserted into it in order to solve HTTP01 challenges. - This is typically used in conjunction with ingress controllers like - ingress-gce, which maintains a 1:1 mapping between external IPs and - ingress resources. Only one of `class`, `name` or `ingressClassName` may - be specified. - type: string - podTemplate: - description: |- - Optional pod template used to configure the ACME challenge solver pods - used for HTTP01 challenges. - type: object - properties: - metadata: - description: |- - ObjectMeta overrides for the pod used to solve HTTP01 challenges. - Only the 'labels' and 'annotations' fields may be set. - If labels or annotations overlap with in-built values, the values here - will override the in-built values. - type: object - properties: - annotations: - description: Annotations that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - labels: - description: Labels that should be added to the created ACME HTTP01 solver pods. - type: object - additionalProperties: - type: string - spec: - description: |- - PodSpec defines overrides for the HTTP01 challenge solver pod. - Check ACMEChallengeSolverHTTP01IngressPodSpec to find out currently supported fields. - All other fields will be ignored. - type: object - properties: - affinity: - description: If specified, the pod's scheduling constraints - type: object - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for the pod. - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - type: object - required: - - preference - - weight - properties: - preference: - description: A node selector term, associated with the corresponding weight. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - type: object - required: - - nodeSelectorTerms - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. The terms are ORed. - type: array - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - type: object - properties: - matchExpressions: - description: A list of node selector requirements by node's labels. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchFields: - description: A list of node selector requirements by node's fields. - type: array - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - type: object - required: - - key - - operator - properties: - key: - description: The label key that the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - This array is replaced during a strategic merge patch. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - x-kubernetes-list-type: atomic - x-kubernetes-map-type: atomic - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). - type: object - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - type: array - items: - description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) - type: object - required: - - podAffinityTerm - - weight - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated with the corresponding weight. - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - type: integer - format: int32 - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - type: array - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - type: object - required: - - topologyKey - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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). - type: array - items: - type: string - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - type: object - properties: - matchExpressions: - description: matchExpressions is a list of label selector requirements. The requirements are ANDed. - type: array - items: - description: |- - A label selector requirement is a selector that contains values, a key, and an operator that - relates the key and values. - type: object - required: - - key - - operator - 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. - type: array - items: - type: string - x-kubernetes-list-type: atomic - x-kubernetes-list-type: atomic - matchLabels: - 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 - additionalProperties: - type: string - x-kubernetes-map-type: atomic - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - type: array - items: - type: string - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - x-kubernetes-list-type: atomic - imagePullSecrets: - description: If specified, the pod's imagePullSecrets - type: array - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - type: object - properties: - name: - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - default: "" - x-kubernetes-map-type: atomic - nodeSelector: - description: |- - NodeSelector is a selector which must be true for the pod to fit on a node. - Selector which must match a node's labels for the pod to be scheduled on that node. - More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - type: object - additionalProperties: - type: string - priorityClassName: - description: If specified, the pod's priorityClassName. - type: string - securityContext: - description: If specified, the pod's security context - type: object - properties: - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - type: integer - format: int64 - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - type: object - properties: - level: - description: Level is SELinux level label that applies to the container. - type: string - role: - description: Role is a SELinux role label that applies to the container. - type: string - type: - description: Type is a SELinux type label that applies to the container. - type: string - user: - description: User is a SELinux user label that applies to the container. - type: string - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - type: object - required: - - type - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - type: integer - format: int64 - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - type: array - items: - description: Sysctl defines a kernel parameter to be set - type: object - required: - - name - - value - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - serviceAccountName: - description: If specified, the pod's service account - type: string - tolerations: - description: If specified, the pod's tolerations. - type: array - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - type: object - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - type: integer - format: int64 - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - serviceType: - description: |- - Optional service type for Kubernetes solver service. Supported values - are NodePort or ClusterIP. If unset, defaults to NodePort. - type: string - selector: - description: |- - Selector selects a set of DNSNames on the Certificate resource that - should be solved using this challenge solver. - If not specified, the solver will be treated as the 'default' solver - with the lowest priority, i.e. if any other solver has a more specific - match, it will be used instead. - type: object - properties: - dnsNames: - description: |- - List of DNSNames that this solver will be used to solve. - If specified and a match is found, a dnsNames selector will take - precedence over a dnsZones selector. - If multiple solvers match with the same dnsNames value, the solver - with the most matching labels in matchLabels will be selected. - If neither has more matches, the solver defined earlier in the list - will be selected. - type: array - items: - type: string - dnsZones: - description: |- - List of DNSZones that this solver will be used to solve. - The most specific DNS zone match specified here will take precedence - over other DNS zone matches, so a solver specifying sys.example.com - will be selected over one specifying example.com for the domain - www.sys.example.com. - If multiple solvers match with the same dnsZones value, the solver - with the most matching labels in matchLabels will be selected. - If neither has more matches, the solver defined earlier in the list - will be selected. - type: array - items: - type: string - matchLabels: - description: |- - A label selector that is used to refine the set of certificate's that - this challenge solver will apply to. - type: object - additionalProperties: - type: string - ca: - description: |- - CA configures this issuer to sign certificates using a signing CA keypair - stored in a Secret resource. - This is used to build internal PKIs that are managed by cert-manager. - type: object - required: - - secretName - properties: - crlDistributionPoints: - description: |- - The CRL distribution points is an X.509 v3 certificate extension which identifies - the location of the CRL from which the revocation of this certificate can be checked. - If not set, certificates will be issued without distribution points set. - type: array - items: - type: string - issuingCertificateURLs: - description: |- - IssuingCertificateURLs is a list of URLs which this issuer should embed into certificates - it creates. See https://www.rfc-editor.org/rfc/rfc5280#section-4.2.2.1 for more details. - As an example, such a URL might be "http://ca.domain.com/ca.crt". - type: array - items: - type: string - ocspServers: - description: |- - The OCSP server list is an X.509 v3 extension that defines a list of - URLs of OCSP responders. The OCSP responders can be queried for the - revocation status of an issued certificate. If not set, the - certificate will be issued with no OCSP servers set. For example, an - OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org". - type: array - items: - type: string - secretName: - description: |- - SecretName is the name of the secret used to sign Certificates issued - by this Issuer. - type: string - selfSigned: - description: |- - SelfSigned configures this issuer to 'self sign' certificates using the - private key used to create the CertificateRequest object. - type: object - properties: - crlDistributionPoints: - description: |- - The CRL distribution points is an X.509 v3 certificate extension which identifies - the location of the CRL from which the revocation of this certificate can be checked. - If not set certificate will be issued without CDP. Values are strings. - type: array - items: - type: string - vault: - description: |- - Vault configures this issuer to sign certificates using a HashiCorp Vault - PKI backend. - type: object - required: - - auth - - path - - server - properties: - auth: - description: Auth configures how cert-manager authenticates with the Vault server. - type: object - properties: - appRole: - description: |- - AppRole authenticates with Vault using the App Role auth mechanism, - with the role and secret stored in a Kubernetes Secret resource. - type: object - required: - - path - - roleId - - secretRef - properties: - path: - description: |- - Path where the App Role authentication backend is mounted in Vault, e.g: - "approle" - type: string - roleId: - description: |- - RoleID configured in the App Role authentication backend when setting - up the authentication backend in Vault. - type: string - secretRef: - description: |- - Reference to a key in a Secret that contains the App Role secret used - to authenticate with Vault. - The `key` field must be specified and denotes which entry within the Secret - resource is used as the app role secret. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientCertificate: - description: |- - ClientCertificate authenticates with Vault by presenting a client - certificate during the request's TLS handshake. - Works only when using HTTPS protocol. - type: object - properties: - mountPath: - description: |- - The Vault mountPath here is the mount path to use when authenticating with - Vault. For example, setting a value to `/v1/auth/foo`, will use the path - `/v1/auth/foo/login` to authenticate with Vault. If unspecified, the - default value "/v1/auth/cert" will be used. - type: string - name: - description: |- - Name of the certificate role to authenticate against. - If not set, matching any certificate role, if available. - type: string - secretName: - description: |- - Reference to Kubernetes Secret of type "kubernetes.io/tls" (hence containing - tls.crt and tls.key) used to authenticate to Vault using TLS client - authentication. - type: string - kubernetes: - description: |- - Kubernetes authenticates with Vault by passing the ServiceAccount - token stored in the named Secret resource to the Vault server. - type: object - required: - - role - properties: - mountPath: - description: |- - The Vault mountPath here is the mount path to use when authenticating with - Vault. For example, setting a value to `/v1/auth/foo`, will use the path - `/v1/auth/foo/login` to authenticate with Vault. If unspecified, the - default value "/v1/auth/kubernetes" will be used. - type: string - role: - description: |- - A required field containing the Vault Role to assume. A Role binds a - Kubernetes ServiceAccount with a set of Vault policies. - type: string - secretRef: - description: |- - The required Secret field containing a Kubernetes ServiceAccount JWT used - for authenticating with Vault. Use of 'ambient credentials' is not - supported. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - serviceAccountRef: - description: |- - A reference to a service account that will be used to request a bound - token (also known as "projected token"). Compared to using "secretRef", - using this field means that you don't rely on statically bound tokens. To - use this field, you must configure an RBAC rule to let cert-manager - request a token. - type: object - required: - - name - properties: - audiences: - description: |- - TokenAudiences is an optional list of extra audiences to include in the token passed to Vault. The default token - consisting of the issuer's namespace and name is always included. - type: array - items: - type: string - name: - description: Name of the ServiceAccount used to request a token. - type: string - tokenSecretRef: - description: TokenSecretRef authenticates with Vault by presenting a token. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - caBundle: - description: |- - Base64-encoded bundle of PEM CAs which will be used to validate the certificate - chain presented by Vault. Only used if using HTTPS to connect to Vault and - ignored for HTTP connections. - Mutually exclusive with CABundleSecretRef. - If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in - the cert-manager controller container is used to validate the TLS connection. - type: string - format: byte - caBundleSecretRef: - description: |- - Reference to a Secret containing a bundle of PEM-encoded CAs to use when - verifying the certificate chain presented by Vault when using HTTPS. - Mutually exclusive with CABundle. - If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in - the cert-manager controller container is used to validate the TLS connection. - If no key for the Secret is specified, cert-manager will default to 'ca.crt'. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientCertSecretRef: - description: |- - Reference to a Secret containing a PEM-encoded Client Certificate to use when the - Vault server requires mTLS. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - clientKeySecretRef: - description: |- - Reference to a Secret containing a PEM-encoded Client Private Key to use when the - Vault server requires mTLS. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Name of the vault namespace. Namespaces is a set of features within Vault Enterprise that allows Vault environments to support Secure Multi-tenancy. e.g: "ns1" - More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces - type: string - path: - description: |- - Path is the mount path of the Vault PKI backend's `sign` endpoint, e.g: - "my_pki_mount/sign/my-role-name". - type: string - server: - description: 'Server is the connection address for the Vault server, e.g: "https://vault.example.com:8200".' - type: string - venafi: - description: |- - Venafi configures this issuer to sign certificates using a Venafi TPP - or Venafi Cloud policy zone. - type: object - required: - - zone - properties: - cloud: - description: |- - Cloud specifies the Venafi cloud configuration settings. - Only one of TPP or Cloud may be specified. - type: object - required: - - apiTokenSecretRef - properties: - apiTokenSecretRef: - description: APITokenSecretRef is a secret key selector for the Venafi Cloud API token. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - url: - description: |- - URL is the base URL for Venafi Cloud. - Defaults to "https://api.venafi.cloud/v1". - type: string - tpp: - description: |- - TPP specifies Trust Protection Platform configuration settings. - Only one of TPP or Cloud may be specified. - type: object - required: - - credentialsRef - - url - properties: - caBundle: - description: |- - Base64-encoded bundle of PEM CAs which will be used to validate the certificate - chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP. - If undefined, the certificate bundle in the cert-manager controller container - is used to validate the chain. - type: string - format: byte - caBundleSecretRef: - description: |- - Reference to a Secret containing a base64-encoded bundle of PEM CAs - which will be used to validate the certificate chain presented by the TPP server. - Only used if using HTTPS; ignored for HTTP. Mutually exclusive with CABundle. - If neither CABundle nor CABundleSecretRef is defined, the certificate bundle in - the cert-manager controller container is used to validate the TLS connection. - type: object - required: - - name - properties: - key: - description: |- - The key of the entry in the Secret resource's `data` field to be used. - Some instances of this field may be defaulted, in others it may be - required. - type: string - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - credentialsRef: - description: |- - CredentialsRef is a reference to a Secret containing the Venafi TPP API credentials. - The secret must contain the key 'access-token' for the Access Token Authentication, - or two keys, 'username' and 'password' for the API Keys Authentication. - type: object - required: - - name - properties: - name: - description: |- - Name of the resource being referred to. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - url: - description: |- - URL is the base URL for the vedsdk endpoint of the Venafi TPP instance, - for example: "https://tpp.example.com/vedsdk". - type: string - zone: - description: |- - Zone is the Venafi Policy Zone to use for this issuer. - All requests made to the Venafi platform will be restricted by the named - zone policy. - This field is required. - type: string - status: - description: Status of the Issuer. This is set and managed automatically. - type: object - properties: - acme: - description: |- - ACME specific status options. - This field should only be set if the Issuer is configured to use an ACME - server to issue certificates. - type: object - properties: - lastPrivateKeyHash: - description: |- - LastPrivateKeyHash is a hash of the private key associated with the latest - registered ACME account, in order to track changes made to registered account - associated with the Issuer - type: string - lastRegisteredEmail: - description: |- - LastRegisteredEmail is the email associated with the latest registered - ACME account, in order to track changes made to registered account - associated with the Issuer - type: string - uri: - description: |- - URI is the unique account identifier, which can also be used to retrieve - account details from the CA - type: string - conditions: - description: |- - List of status conditions to indicate the status of a CertificateRequest. - Known condition types are `Ready`. - type: array - items: - description: IssuerCondition contains condition information for an Issuer. - type: object - required: - - status - - type - properties: - lastTransitionTime: - description: |- - LastTransitionTime is the timestamp corresponding to the last status - change of this condition. - type: string - format: date-time - message: - description: |- - Message is a human readable description of the details of the last - transition, complementing reason. - type: string - observedGeneration: - description: |- - If set, this represents the .metadata.generation that the condition was - set based upon. - For instance, if .metadata.generation is currently 12, but the - .status.condition[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the Issuer. - type: integer - format: int64 - reason: - description: |- - Reason is a brief machine readable explanation for the condition's last - transition. - type: string - status: - description: Status of the condition, one of (`True`, `False`, `Unknown`). - type: string - enum: - - "True" - - "False" - - Unknown - type: - description: Type of the condition, known values are (`Ready`). - type: string - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - served: true - storage: true - -# END crd {{- end }} - ---- -# START crd {{- if or .Values.crds.enabled .Values.installCRDs }} -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: orders.acme.cert-manager.io - # START annotations {{- if .Values.crds.keep }} - annotations: - helm.sh/resource-policy: keep - # END annotations {{- end }} - labels: - app: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/name: '{{ template "cert-manager.name" . }}' - app.kubernetes.io/instance: '{{ .Release.Name }}' - app.kubernetes.io/component: "crds" - # Generated labels {{- include "labels" . | nindent 4 }} -spec: - group: acme.cert-manager.io - names: - kind: Order - listKind: OrderList - plural: orders - singular: order - categories: - - cert-manager - - cert-manager-acme - scope: Namespaced - versions: - - name: v1 - subresources: - status: {} - additionalPrinterColumns: - - jsonPath: .status.state - name: State - type: string - - jsonPath: .spec.issuerRef.name - name: Issuer - priority: 1 - type: string - - jsonPath: .status.reason - name: Reason - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - description: CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. - name: Age - type: date - schema: - openAPIV3Schema: - description: Order is a type to represent an Order with an ACME server - type: object - required: - - metadata - - spec - 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: - type: object - required: - - issuerRef - - request - properties: - commonName: - description: |- - CommonName is the common name as specified on the DER encoded CSR. - If specified, this value must also be present in `dnsNames` or `ipAddresses`. - This field must match the corresponding field on the DER encoded CSR. - type: string - dnsNames: - description: |- - DNSNames is a list of DNS names that should be included as part of the Order - validation process. - This field must match the corresponding field on the DER encoded CSR. - type: array - items: - type: string - duration: - description: |- - Duration is the duration for the not after date for the requested certificate. - this is set on order creation as pe the ACME spec. - type: string - ipAddresses: - description: |- - IPAddresses is a list of IP addresses that should be included as part of the Order - validation process. - This field must match the corresponding field on the DER encoded CSR. - type: array - items: - type: string - issuerRef: - description: |- - IssuerRef references a properly configured ACME-type Issuer which should - be used to create this Order. - If the Issuer does not exist, processing will be retried. - If the Issuer is not an 'ACME' Issuer, an error will be returned and the - Order will be marked as failed. - type: object - required: - - name - properties: - group: - description: Group of the resource being referred to. - type: string - kind: - description: Kind of the resource being referred to. - type: string - name: - description: Name of the resource being referred to. - type: string - request: - description: |- - Certificate signing request bytes in DER encoding. - This will be used when finalizing the order. - This field must be set on the order. - type: string - format: byte - status: - type: object - properties: - authorizations: - description: |- - Authorizations contains data returned from the ACME server on what - authorizations must be completed in order to validate the DNS names - specified on the Order. - type: array - items: - description: |- - ACMEAuthorization contains data returned from the ACME server on an - authorization that must be completed in order validate a DNS name on an ACME - Order resource. - type: object - required: - - url - properties: - challenges: - description: |- - Challenges specifies the challenge types offered by the ACME server. - One of these challenge types will be selected when validating the DNS - name and an appropriate Challenge resource will be created to perform - the ACME challenge process. - type: array - items: - description: |- - Challenge specifies a challenge offered by the ACME server for an Order. - An appropriate Challenge resource can be created to perform the ACME - challenge process. - type: object - required: - - token - - type - - url - properties: - token: - description: |- - Token is the token that must be presented for this challenge. - This is used to compute the 'key' that must also be presented. - type: string - type: - description: |- - Type is the type of challenge being offered, e.g. 'http-01', 'dns-01', - 'tls-sni-01', etc. - This is the raw value retrieved from the ACME server. - Only 'http-01' and 'dns-01' are supported by cert-manager, other values - will be ignored. - type: string - url: - description: |- - URL is the URL of this challenge. It can be used to retrieve additional - metadata about the Challenge from the ACME server. - type: string - identifier: - description: Identifier is the DNS name to be validated as part of this authorization - type: string - initialState: - description: |- - InitialState is the initial state of the ACME authorization when first - fetched from the ACME server. - If an Authorization is already 'valid', the Order controller will not - create a Challenge resource for the authorization. This will occur when - working with an ACME server that enables 'authz reuse' (such as Let's - Encrypt's production endpoint). - If not set and 'identifier' is set, the state is assumed to be pending - and a Challenge will be created. - type: string - enum: - - valid - - ready - - pending - - processing - - invalid - - expired - - errored - url: - description: URL is the URL of the Authorization that must be completed - type: string - wildcard: - description: |- - Wildcard will be true if this authorization is for a wildcard DNS name. - If this is true, the identifier will be the *non-wildcard* version of - the DNS name. - For example, if '*.example.com' is the DNS name being validated, this - field will be 'true' and the 'identifier' field will be 'example.com'. - type: boolean - certificate: - description: |- - Certificate is a copy of the PEM encoded certificate for this Order. - This field will be populated after the order has been successfully - finalized with the ACME server, and the order has transitioned to the - 'valid' state. - type: string - format: byte - failureTime: - description: |- - FailureTime stores the time that this order failed. - This is used to influence garbage collection and back-off. - type: string - format: date-time - finalizeURL: - description: |- - FinalizeURL of the Order. - This is used to obtain certificates for this order once it has been completed. - type: string - reason: - description: |- - Reason optionally provides more information about a why the order is in - the current state. - type: string - state: - description: |- - State contains the current state of this Order resource. - States 'success' and 'expired' are 'final' - type: string - enum: - - valid - - ready - - pending - - processing - - invalid - - expired - - errored - url: - description: |- - URL of the Order. - This will initially be empty when the resource is first created. - The Order controller will populate this field when the Order is first processed. - This field will be immutable after it is initially set. - type: string - served: true - storage: true - -# END crd {{- end }} 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 8a4a9734..453e8238 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/deployment.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/deployment.yaml @@ -66,6 +66,9 @@ spec: {{- with .Values.global.priorityClassName }} priorityClassName: {{ . | quote }} {{- end }} + {{- if (hasKey .Values.global "hostUsers") }} + hostUsers: {{ .Values.global.hostUsers }} + {{- end }} {{- with .Values.securityContext }} securityContext: {{- toYaml . | nindent 8 }} @@ -209,9 +212,13 @@ spec: failureThreshold: {{ .failureThreshold }} {{- end }} {{- end }} - {{- with .Values.nodeSelector }} + {{- $nodeSelector := .Values.global.nodeSelector | default dict }} + {{- $nodeSelector = merge $nodeSelector (.Values.nodeSelector | default dict) }} + {{- with $nodeSelector }} nodeSelector: - {{- toYaml . | nindent 8 }} + {{- range $key, $value := . }} + {{ $key }}: {{ $value | quote }} + {{- end }} {{- end }} {{- with .Values.affinity }} affinity: @@ -234,4 +241,4 @@ spec: {{- end }} {{- with .Values.hostAliases }} hostAliases: {{ toYaml . | nindent 8 }} - {{- end }} \ No newline at end of file + {{- end }} diff --git a/packages/system/cert-manager/charts/cert-manager/templates/rbac.yaml b/packages/system/cert-manager/charts/cert-manager/templates/rbac.yaml index baae425f..7acd5711 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/rbac.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/rbac.yaml @@ -49,7 +49,7 @@ subjects: apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: {{ template "cert-manager.serviceAccountName" . }}-tokenrequest + name: {{ template "cert-manager.fullname" . }}-tokenrequest namespace: {{ include "cert-manager.namespace" . }} labels: app: {{ include "cert-manager.name" . }} @@ -69,7 +69,7 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: {{ include "cert-manager.fullname" . }}-{{ template "cert-manager.serviceAccountName" . }}-tokenrequest + name: {{ include "cert-manager.fullname" . }}-tokenrequest namespace: {{ include "cert-manager.namespace" . }} labels: app: {{ include "cert-manager.name" . }} @@ -80,7 +80,7 @@ metadata: roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: {{ template "cert-manager.serviceAccountName" . }}-tokenrequest + name: {{ template "cert-manager.fullname" . }}-tokenrequest subjects: - kind: ServiceAccount name: {{ template "cert-manager.serviceAccountName" . }} @@ -256,8 +256,8 @@ rules: - apiGroups: ["networking.k8s.io"] resources: ["ingresses"] verbs: ["get", "list", "watch", "create", "delete", "update"] - - apiGroups: [ "gateway.networking.k8s.io" ] - resources: [ "httproutes" ] + - apiGroups: ["gateway.networking.k8s.io"] + resources: ["httproutes"] verbs: ["get", "list", "watch", "create", "delete", "update"] # We require the ability to specify a custom hostname when we are creating # new ingress resources. 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 698ddef8..fac93d0a 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/serviceaccount.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/serviceaccount.yaml @@ -12,7 +12,8 @@ metadata: {{- with .Values.serviceAccount.annotations }} annotations: {{- range $k, $v := . }} - {{- printf "%s: %s" (tpl $k $) (tpl $v $) | nindent 4 }} + {{- $value := $v | quote }} + {{- printf "%s: %s" (tpl $k $) (tpl $value $) | nindent 4 }} {{- end }} {{- end }} labels: diff --git a/packages/system/cert-manager/charts/cert-manager/templates/servicemonitor.yaml b/packages/system/cert-manager/charts/cert-manager/templates/servicemonitor.yaml index dd1beec8..a29f3c6a 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/servicemonitor.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/servicemonitor.yaml @@ -16,7 +16,9 @@ metadata: app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/component: "controller" {{- include "labels" . | nindent 4 }} + {{- if .Values.prometheus.servicemonitor.prometheusInstance }} prometheus: {{ .Values.prometheus.servicemonitor.prometheusInstance }} + {{- end }} {{- with .Values.prometheus.servicemonitor.labels }} {{- toYaml . | nindent 4 }} {{- end }} @@ -54,8 +56,12 @@ spec: endpoints: - targetPort: {{ .Values.prometheus.servicemonitor.targetPort }} path: {{ .Values.prometheus.servicemonitor.path }} + {{- if .Values.prometheus.servicemonitor.interval }} interval: {{ .Values.prometheus.servicemonitor.interval }} + {{- end }} + {{- if .Values.prometheus.servicemonitor.scrapeTimeout }} scrapeTimeout: {{ .Values.prometheus.servicemonitor.scrapeTimeout }} + {{- end }} honorLabels: {{ .Values.prometheus.servicemonitor.honorLabels }} {{- with .Values.prometheus.servicemonitor.endpointAdditionalProperties }} {{- toYaml . | nindent 4 }} diff --git a/packages/system/cert-manager/charts/cert-manager/templates/startupapicheck-job.yaml b/packages/system/cert-manager/charts/cert-manager/templates/startupapicheck-job.yaml index 183cff4e..f68d5409 100644 --- a/packages/system/cert-manager/charts/cert-manager/templates/startupapicheck-job.yaml +++ b/packages/system/cert-manager/charts/cert-manager/templates/startupapicheck-job.yaml @@ -41,6 +41,9 @@ spec: {{- with .Values.global.priorityClassName }} priorityClassName: {{ . | quote }} {{- end }} + {{- if (hasKey .Values.global "hostUsers") }} + hostUsers: {{ .Values.global.hostUsers }} + {{- end }} {{- with .Values.startupapicheck.securityContext }} securityContext: {{- toYaml . | nindent 8 }} @@ -76,9 +79,13 @@ spec: volumeMounts: {{- toYaml . | nindent 12 }} {{- end }} - {{- with .Values.startupapicheck.nodeSelector }} + {{- $nodeSelector := .Values.global.nodeSelector | default dict }} + {{- $nodeSelector = merge $nodeSelector (.Values.startupapicheck.nodeSelector | default dict) }} + {{- with $nodeSelector }} nodeSelector: - {{- toYaml . | nindent 8 }} + {{- range $key, $value := . }} + {{ $key }}: {{ $value | quote }} + {{- end }} {{- end }} {{- with .Values.startupapicheck.affinity }} affinity: 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 857cf353..d2b10ae8 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 @@ -66,6 +66,9 @@ spec: {{- with .Values.global.priorityClassName }} priorityClassName: {{ . | quote }} {{- end }} + {{- if (hasKey .Values.global "hostUsers") }} + hostUsers: {{ .Values.global.hostUsers }} + {{- end }} {{- with .Values.webhook.securityContext }} securityContext: {{- toYaml . | nindent 8 }} @@ -102,7 +105,7 @@ spec: - --dynamic-serving-dns-names={{ template "webhook.fullname" . }} - --dynamic-serving-dns-names={{ template "webhook.fullname" . }}.$(POD_NAMESPACE) - --dynamic-serving-dns-names={{ template "webhook.fullname" . }}.$(POD_NAMESPACE).svc - {{ if .Values.webhook.url.host }} + {{- if .Values.webhook.url.host }} - --dynamic-serving-dns-names={{ .Values.webhook.url.host }} {{- end }} {{- end }} @@ -137,11 +140,7 @@ spec: livenessProbe: httpGet: path: /livez - {{- if $config.healthzPort }} - port: {{ $config.healthzPort }} - {{- else }} - port: 6080 - {{- end }} + port: healthcheck scheme: HTTP initialDelaySeconds: {{ .Values.webhook.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.webhook.livenessProbe.periodSeconds }} @@ -151,11 +150,7 @@ spec: readinessProbe: httpGet: path: /healthz - {{- if $config.healthzPort }} - port: {{ $config.healthzPort }} - {{- else }} - port: 6080 - {{- end }} + port: healthcheck scheme: HTTP initialDelaySeconds: {{ .Values.webhook.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.webhook.readinessProbe.periodSeconds }} @@ -188,9 +183,13 @@ spec: {{- toYaml . | nindent 12 }} {{- end }} {{- end }} - {{- with .Values.webhook.nodeSelector }} + {{- $nodeSelector := .Values.global.nodeSelector | default dict }} + {{- $nodeSelector = merge $nodeSelector (.Values.webhook.nodeSelector | default dict) }} + {{- with $nodeSelector }} nodeSelector: - {{- toYaml . | nindent 8 }} + {{- range $key, $value := . }} + {{ $key }}: {{ $value | quote }} + {{- end }} {{- end }} {{- with .Values.webhook.affinity }} affinity: 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 36d1d0ca..7f90b6c3 100644 --- a/packages/system/cert-manager/charts/cert-manager/values.schema.json +++ b/packages/system/cert-manager/charts/cert-manager/values.schema.json @@ -236,7 +236,7 @@ "issuers.cert-manager.io/*", "clusterissuers.cert-manager.io/*" ], - "description": "List of signer names that cert-manager will approve by default. CertificateRequests referencing these signer names will be auto-approved by cert-manager. Defaults to just approving the cert-manager.io Issuer and ClusterIssuer issuers. When set to an empty array, ALL issuers will be auto-approved by cert-manager. To disable the auto-approval, because eg. you are using approver-policy, you can enable 'disableAutoApproval'.\nref: https://cert-manager.io/docs/concepts/certificaterequest/#approval", + "description": "List of signer names that cert-manager will approve by default. CertificateRequests referencing these signer names will be auto-approved by cert-manager. Defaults to just approving the cert-manager.io Issuer and ClusterIssuer issuers. When set to an empty array, ALL issuers will be auto-approved by cert-manager. To disable the auto-approval, because, e.g., you are using approver-policy, you can enable 'disableAutoApproval'.\nref: https://cert-manager.io/docs/concepts/certificaterequest/#approval", "items": {}, "type": "array" }, @@ -461,10 +461,10 @@ "type": "boolean" }, "helm-values.cainjector.podDisruptionBudget.maxUnavailable": { - "description": "`maxUnavailable` configures the maximum unavailable pods for disruptions. It can either be set to\nan integer (e.g. 1) or a percentage value (e.g. 25%).\nCannot be used if `minAvailable` is set." + "description": "`maxUnavailable` configures the maximum unavailable pods for disruptions. It can either be set to\nan integer (e.g., 1) or a percentage value (e.g., 25%).\nCannot be used if `minAvailable` is set." }, "helm-values.cainjector.podDisruptionBudget.minAvailable": { - "description": "`minAvailable` configures the minimum available pods for disruptions. It can either be set to\nan integer (e.g. 1) or a percentage value (e.g. 25%).\nCannot be used if `maxUnavailable` is set." + "description": "`minAvailable` configures the minimum available pods for disruptions. It can either be set to\nan integer (e.g., 1) or a percentage value (e.g., 25%).\nCannot be used if `maxUnavailable` is set." }, "helm-values.cainjector.podLabels": { "default": {}, @@ -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 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", + "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.18.1. Listed with their default values.\n # See https://cert-manager.io/docs/cli/controller/\n featureGates:\n AdditionalCertificateOutputFormats: true # GA - 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 # GA - default=true\n ValidateCAA: false # ALPHA - default=false\n DefaultPrivateKeyRotationPolicyAlways: true # BETA - default=true\n ACMEHTTP01IngressPathTypeExact: true # BETA - default=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", "type": "object" }, "helm-values.containerSecurityContext": { @@ -689,6 +689,9 @@ "commonLabels": { "$ref": "#/$defs/helm-values.global.commonLabels" }, + "hostUsers": { + "$ref": "#/$defs/helm-values.global.hostUsers" + }, "imagePullSecrets": { "$ref": "#/$defs/helm-values.global.imagePullSecrets" }, @@ -698,6 +701,9 @@ "logLevel": { "$ref": "#/$defs/helm-values.global.logLevel" }, + "nodeSelector": { + "$ref": "#/$defs/helm-values.global.nodeSelector" + }, "podSecurityPolicy": { "$ref": "#/$defs/helm-values.global.podSecurityPolicy" }, @@ -718,6 +724,10 @@ "description": "Labels to apply to all resources.\nPlease note that this does not add labels to the resources created dynamically by the controllers. For these resources, you have to add the labels in the template in the cert-manager custom resource: For example, podTemplate/ ingressTemplate in ACMEChallengeSolverHTTP01Ingress. For more information, see the [cert-manager documentation](https://cert-manager.io/docs/reference/api-docs/#acme.cert-manager.io/v1.ACMEChallengeSolverHTTP01Ingress).\nFor example, secretTemplate in CertificateSpec\nFor more information, see the [cert-manager documentation](https://cert-manager.io/docs/reference/api-docs/#cert-manager.io/v1.CertificateSpec).", "type": "object" }, + "helm-values.global.hostUsers": { + "description": "Set all pods to run in a user namespace without host access. Experimental: may be removed once the Kubernetes User Namespaces feature is GA.\n\nRequirements:\n - Kubernetes ≥ 1.33, or\n - Kubernetes 1.27–1.32 with UserNamespacesSupport feature gate enabled.\n\nSet to false to run pods in a user namespace without host access.\n\nSee [limitations](https://kubernetes.io/docs/concepts/workloads/pods/user-namespaces/#limitations) for details.", + "type": "boolean" + }, "helm-values.global.imagePullSecrets": { "default": [], "description": "Reference to one or more secrets to be used when pulling images. For more information, see [Pull an Image from a Private Registry](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/).\n\nFor example:\nimagePullSecrets:\n - name: \"image-pull-secret\"", @@ -763,6 +773,11 @@ "description": "Set the verbosity of cert-manager. A range of 0 - 6, with 6 being the most verbose.", "type": "number" }, + "helm-values.global.nodeSelector": { + "default": {}, + "description": "Global node selector\n\nThe nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with matching labels. For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/).\n\nIf a component-specific nodeSelector is also set, it will be merged and take precedence.", + "type": "object" + }, "helm-values.global.podSecurityPolicy": { "properties": { "enabled": { @@ -921,7 +936,7 @@ "type": "number" }, "helm-values.nameOverride": { - "description": "Override the \"cert-manager.name\" value, which is used to annotate some of the resources that are created by this Chart (using \"app.kubernetes.io/name\"). NOTE: There are some inconsistencies in the Helm chart when it comes to these annotations (some resources use eg. \"cainjector.name\" which resolves to the value \"cainjector\").", + "description": "Override the \"cert-manager.name\" value, which is used to annotate some of the resources that are created by this Chart (using \"app.kubernetes.io/name\"). NOTE: There are some inconsistencies in the Helm chart when it comes to these annotations (some resources use, e.g., \"cainjector.name\" which resolves to the value \"cainjector\").", "type": "string" }, "helm-values.namespace": { @@ -965,10 +980,10 @@ "type": "boolean" }, "helm-values.podDisruptionBudget.maxUnavailable": { - "description": "This configures the maximum unavailable pods for disruptions. It can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%). it cannot be used if `minAvailable` is set." + "description": "This configures the maximum unavailable pods for disruptions. It can either be set to an integer (e.g., 1) or a percentage value (e.g., 25%). it cannot be used if `minAvailable` is set." }, "helm-values.podDisruptionBudget.minAvailable": { - "description": "This configures the minimum available pods for disruptions. It can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%).\nIt cannot be used if `maxUnavailable` is set." + "description": "This configures the minimum available pods for disruptions. It can either be set to an integer (e.g., 1) or a percentage value (e.g., 25%).\nIt cannot be used if `maxUnavailable` is set." }, "helm-values.podDnsConfig": { "description": "Pod DNS configuration. The podDnsConfig field is optional and can work with any podDnsPolicy settings. However, when a Pod's dnsPolicy is set to \"None\", the dnsConfig field has to be specified. For more information, see [Pod's DNS Config](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config).", @@ -1000,7 +1015,7 @@ }, "helm-values.prometheus.enabled": { "default": true, - "description": "Enable Prometheus monitoring for the cert-manager controller and webhook. If you use the Prometheus Operator, set prometheus.podmonitor.enabled or prometheus.servicemonitor.enabled, to create a PodMonitor or a\nServiceMonitor resource.\nOtherwise, 'prometheus.io' annotations are added to the cert-manager and cert-manager-webhook Deployments. Note that you can not enable both PodMonitor and ServiceMonitor as they are mutually exclusive. Enabling both will result in an error.", + "description": "Enable Prometheus monitoring for the cert-manager controller and webhook. If you use the Prometheus Operator, set prometheus.podmonitor.enabled or prometheus.servicemonitor.enabled, to create a PodMonitor or a\nServiceMonitor resource.\nOtherwise, 'prometheus.io' annotations are added to the cert-manager and cert-manager-webhook Deployments. Note that you cannot enable both PodMonitor and ServiceMonitor as they are mutually exclusive. Enabling both will result in an error.", "type": "boolean" }, "helm-values.prometheus.podmonitor": { @@ -1177,9 +1192,8 @@ "type": "string" }, "helm-values.prometheus.servicemonitor.targetPort": { - "default": 9402, - "description": "The target port to set on the ServiceMonitor. This must match the port that the cert-manager controller is listening on for metrics.", - "type": "number" + "default": "http-metrics", + "description": "The target port to set on the ServiceMonitor. This must match the port that the cert-manager controller is listening on for metrics." }, "helm-values.replicaCount": { "default": 1, @@ -1887,6 +1901,11 @@ "ipBlock": { "cidr": "0.0.0.0/0" } + }, + { + "ipBlock": { + "cidr": "::/0" + } } ] } @@ -1908,6 +1927,11 @@ "ipBlock": { "cidr": "0.0.0.0/0" } + }, + { + "ipBlock": { + "cidr": "::/0" + } } ] } @@ -1948,10 +1972,10 @@ "type": "boolean" }, "helm-values.webhook.podDisruptionBudget.maxUnavailable": { - "description": "This property configures the maximum unavailable pods for disruptions. Can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%).\nIt cannot be used if `minAvailable` is set." + "description": "This property configures the maximum unavailable pods for disruptions. Can either be set to an integer (e.g., 1) or a percentage value (e.g., 25%).\nIt cannot be used if `minAvailable` is set." }, "helm-values.webhook.podDisruptionBudget.minAvailable": { - "description": "This property configures the minimum available pods for disruptions. Can either be set to an integer (e.g. 1) or a percentage value (e.g. 25%).\nIt cannot be used if `maxUnavailable` is set." + "description": "This property configures the minimum available pods for disruptions. Can either be set to an integer (e.g., 1) or a percentage value (e.g., 25%).\nIt cannot be used if `maxUnavailable` is set." }, "helm-values.webhook.podLabels": { "default": {}, diff --git a/packages/system/cert-manager/charts/cert-manager/values.yaml b/packages/system/cert-manager/charts/cert-manager/values.yaml index a8c94f8b..54257c79 100644 --- a/packages/system/cert-manager/charts/cert-manager/values.yaml +++ b/packages/system/cert-manager/charts/cert-manager/values.yaml @@ -12,6 +12,16 @@ global: # - name: "image-pull-secret" imagePullSecrets: [] + # Global node selector + # + # The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with + # matching labels. + # For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). + # + # If a component-specific nodeSelector is also set, it will be merged and take precedence. + # +docs:property + nodeSelector: {} + # Labels to apply to all resources. # Please note that this does not add labels to the resources created dynamically by the controllers. # For these resources, you have to add the labels in the template in the cert-manager custom resource: @@ -28,6 +38,19 @@ global: # The optional priority class to be used for the cert-manager pods. priorityClassName: "" + # Set all pods to run in a user namespace without host access. + # Experimental: may be removed once the Kubernetes User Namespaces feature is GA. + # + # Requirements: + # - Kubernetes ≥ 1.33, or + # - Kubernetes 1.27–1.32 with UserNamespacesSupport feature gate enabled. + # + # Set to false to run pods in a user namespace without host access. + # + # See [limitations](https://kubernetes.io/docs/concepts/workloads/pods/user-namespaces/#limitations) for details. + # +docs:property + # hostUsers: false + rbac: # Create required ClusterRoles and ClusterRoleBindings for cert-manager. create: true @@ -117,14 +140,14 @@ podDisruptionBudget: enabled: false # This configures the minimum available pods for disruptions. It can either be set to - # an integer (e.g. 1) or a percentage value (e.g. 25%). + # an integer (e.g., 1) or a percentage value (e.g., 25%). # It cannot be used if `maxUnavailable` is set. # +docs:property # +docs:type=unknown # minAvailable: 1 # This configures the maximum unavailable pods for disruptions. It can either be set to - # an integer (e.g. 1) or a percentage value (e.g. 25%). + # an integer (e.g., 1) or a percentage value (e.g., 25%). # it cannot be used if `minAvailable` is set. # +docs:property # +docs:type=unknown @@ -176,7 +199,7 @@ namespace: "" # Override the "cert-manager.name" value, which is used to annotate some of # the resources that are created by this Chart (using "app.kubernetes.io/name"). # NOTE: There are some inconsistencies in the Helm chart when it comes to -# these annotations (some resources use eg. "cainjector.name" which resolves +# these annotations (some resources use, e.g., "cainjector.name" which resolves # to the value "cainjector"). # +docs:property # nameOverride: "my-cert-manager" @@ -231,10 +254,10 @@ enableCertificateOwnerRef: false # kubernetesAPIBurst: 9000 # numberOfConcurrentWorkers: 200 # enableGatewayAPI: true -# # Feature gates as of v1.17.0. Listed with their default values. +# # Feature gates as of v1.18.1. Listed with their default values. # # See https://cert-manager.io/docs/cli/controller/ # featureGates: -# AdditionalCertificateOutputFormats: true # BETA - default=true +# AdditionalCertificateOutputFormats: true # GA - default=true # AllAlpha: false # ALPHA - default=false # AllBeta: false # BETA - default=false # ExperimentalCertificateSigningRequestControllers: false # ALPHA - default=false @@ -246,8 +269,10 @@ enableCertificateOwnerRef: false # ServerSideApply: false # ALPHA - default=false # StableCertificateRequestName: true # BETA - default=true # UseCertificateRequestBasicConstraints: false # ALPHA - default=false -# UseDomainQualifiedFinalizer: true # BETA - default=false +# UseDomainQualifiedFinalizer: true # GA - default=true # ValidateCAA: false # ALPHA - default=false +# DefaultPrivateKeyRotationPolicyAlways: true # BETA - default=true +# ACMEHTTP01IngressPathTypeExact: true # BETA - default=true # # Configure the metrics server for TLS # # See https://cert-manager.io/docs/devops-tips/prometheus-metrics/#tls # metricsTLSConfig: @@ -278,7 +303,7 @@ disableAutoApproval: false # referencing these signer names will be auto-approved by cert-manager. Defaults to just # approving the cert-manager.io Issuer and ClusterIssuer issuers. When set to an empty # array, ALL issuers will be auto-approved by cert-manager. To disable the auto-approval, -# because eg. you are using approver-policy, you can enable 'disableAutoApproval'. +# because, e.g., you are using approver-policy, you can enable 'disableAutoApproval'. # ref: https://cert-manager.io/docs/concepts/certificaterequest/#approval # +docs:property approveSignerNames: @@ -434,7 +459,6 @@ ingressShim: {} # +docs:property # no_proxy: 127.0.0.1,localhost - # A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core). # # For example: @@ -502,7 +526,7 @@ prometheus: # ServiceMonitor resource. # Otherwise, 'prometheus.io' annotations are added to the cert-manager and # cert-manager-webhook Deployments. - # Note that you can not enable both PodMonitor and ServiceMonitor as they are + # Note that you cannot enable both PodMonitor and ServiceMonitor as they are # mutually exclusive. Enabling both will result in an error. enabled: true @@ -522,7 +546,8 @@ prometheus: # The target port to set on the ServiceMonitor. This must match the port that the # cert-manager controller is listening on for metrics. - targetPort: 9402 + # +docs:type=string,integer + targetPort: http-metrics # The path to scrape for metrics. path: /metrics @@ -556,7 +581,7 @@ prometheus: # +docs:property endpointAdditionalProperties: {} - # Note that you can not enable both PodMonitor and ServiceMonitor as they are mutually exclusive. Enabling both will result in an error. + # Note that you cannot enable both PodMonitor and ServiceMonitor as they are mutually exclusive. Enabling both will result in an error. podmonitor: # Create a PodMonitor to add cert-manager to Prometheus. enabled: false @@ -706,14 +731,14 @@ webhook: enabled: false # This property configures the minimum available pods for disruptions. Can either be set to - # an integer (e.g. 1) or a percentage value (e.g. 25%). + # an integer (e.g., 1) or a percentage value (e.g., 25%). # It cannot be used if `maxUnavailable` is set. # +docs:property # +docs:type=unknown # minAvailable: 1 # This property configures the maximum unavailable pods for disruptions. Can either be set to - # an integer (e.g. 1) or a percentage value (e.g. 25%). + # an integer (e.g., 1) or a percentage value (e.g., 25%). # It cannot be used if `minAvailable` is set. # +docs:property # +docs:type=unknown @@ -959,6 +984,8 @@ webhook: - from: - ipBlock: cidr: 0.0.0.0/0 + - ipBlock: + cidr: "::/0" # Egress rule for the webhook network policy. By default, it allows all # outbound traffic to ports 80 and 443, as well as DNS ports. @@ -980,6 +1007,8 @@ webhook: to: - ipBlock: cidr: 0.0.0.0/0 + - ipBlock: + cidr: "::/0" # Additional volumes to add to the cert-manager controller pod. volumes: [] @@ -1073,14 +1102,14 @@ cainjector: enabled: false # `minAvailable` configures the minimum available pods for disruptions. It can either be set to - # an integer (e.g. 1) or a percentage value (e.g. 25%). + # an integer (e.g., 1) or a percentage value (e.g., 25%). # Cannot be used if `maxUnavailable` is set. # +docs:property # +docs:type=unknown # minAvailable: 1 # `maxUnavailable` configures the maximum unavailable pods for disruptions. It can either be set to - # an integer (e.g. 1) or a percentage value (e.g. 25%). + # an integer (e.g., 1) or a percentage value (e.g., 25%). # Cannot be used if `minAvailable` is set. # +docs:property # +docs:type=unknown diff --git a/packages/system/cert-manager/values.yaml b/packages/system/cert-manager/values.yaml index 5accf95f..e69de29b 100644 --- a/packages/system/cert-manager/values.yaml +++ b/packages/system/cert-manager/values.yaml @@ -1,2 +0,0 @@ -cert-manager: - installCRDs: false diff --git a/packages/system/cilium-networkpolicy/Makefile b/packages/system/cilium-networkpolicy/Makefile index c81b87e9..a24a54b5 100644 --- a/packages/system/cilium-networkpolicy/Makefile +++ b/packages/system/cilium-networkpolicy/Makefile @@ -1,5 +1,5 @@ export NAME=cilium-networkpolicy export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk diff --git a/packages/system/cilium/Makefile b/packages/system/cilium/Makefile index 72502d12..71b47a77 100644 --- a/packages/system/cilium/Makefile +++ b/packages/system/cilium/Makefile @@ -3,31 +3,35 @@ CILIUM_TAG=$(shell awk '$$1 == "version:" {print $$2}' charts/cilium/Chart.yaml) export NAME=cilium export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts helm repo add cilium https://helm.cilium.io/ helm repo update cilium - helm pull cilium/cilium --untar --untardir charts --version 1.17 - sed -i -e '/Used in iptables/d' -e '/SYS_MODULE/d' charts/cilium/values.yaml + helm pull cilium/cilium --untar --untardir charts --version 1.19 + $(SED_INPLACE) -e '/Used in iptables/d' -e '/SYS_MODULE/d' charts/cilium/values.yaml + # Drop the whole k8s<1.30 AppArmor annotations block from the cilium-agent + # DaemonSet. Cozystack manages these annotations through cilium.podAnnotations + # in values.yaml on every k8s version, so keeping the upstream block would + # produce duplicate mapping keys on k8s<1.30. + perl -i -0pe 's|\n \{\{- if not \.Values\.securityContext\.privileged \}\}\n \{\{- if semverCompare "<1\.30\.0".*?\n \{\{- end \}\}\n \{\{- end \}\}\n \{\{- end \}\}||s' \ + charts/cilium/templates/cilium-agent/daemonset.yaml + @! grep -q 'container\.apparmor\.security\.beta\.kubernetes\.io' \ + charts/cilium/templates/cilium-agent/daemonset.yaml || \ + { echo 'ERROR: perl patch did not remove the upstream AppArmor block from cilium-agent/daemonset.yaml (upstream template format may have changed)' >&2; exit 1; } version=$$(awk '$$1 == "version:" {print $$2}' charts/cilium/Chart.yaml) && \ - sed -i "s/ARG VERSION=.*/ARG VERSION=v$${version}/" images/cilium/Dockerfile + $(SED_INPLACE) "s/ARG VERSION=.*/ARG VERSION=v$${version}/" images/cilium/Dockerfile 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 \ --cache-to type=inline \ --metadata-file images/cilium.json \ - --push=$(PUSH) \ - --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ - --load=$(LOAD) + $(BUILDX_ARGS) REPOSITORY="$(REGISTRY)/cilium" \ yq -i '.cilium.image.repository = strenv(REPOSITORY)' values.yaml TAG=$(call settag,$(CILIUM_TAG)) \ diff --git a/packages/system/cilium/charts/cilium/Chart.yaml b/packages/system/cilium/charts/cilium/Chart.yaml index 7511b20c..5fe2baed 100644 --- a/packages/system/cilium/charts/cilium/Chart.yaml +++ b/packages/system/cilium/charts/cilium/Chart.yaml @@ -7,67 +7,61 @@ annotations: ciliumclusterwidenetworkpolicies.cilium.io\n displayName: Cilium Clusterwide Network Policy\n description: |\n Cilium Clusterwide Network Policies support configuring network traffic\n policiies across the entire cluster, including - applying node firewalls.\n- kind: CiliumExternalWorkload\n version: v2\n name: - ciliumexternalworkloads.cilium.io\n displayName: Cilium External Workload\n description: - |\n Cilium External Workload supports configuring the ability for external\n - \ non-Kubernetes workloads to join the cluster.\n- kind: CiliumLocalRedirectPolicy\n - \ version: v2\n name: ciliumlocalredirectpolicies.cilium.io\n displayName: Cilium - Local Redirect Policy\n description: |\n Cilium Local Redirect Policy allows - local redirects to be configured\n within a node to support use cases like - Node-Local DNS or KIAM.\n- kind: CiliumNode\n version: v2\n name: ciliumnodes.cilium.io\n - \ displayName: Cilium Node\n description: |\n Cilium Node represents a node - managed by Cilium. It contains a\n specification to control various node specific - configuration aspects\n and a status section to represent the status of the - node.\n- kind: CiliumIdentity\n version: v2\n name: ciliumidentities.cilium.io\n - \ displayName: Cilium Identity\n description: |\n Cilium Identity allows introspection - into security identities that\n Cilium allocates which identify sets of labels - that are assigned to\n individual endpoints in the cluster.\n- kind: CiliumEndpoint\n - \ version: v2\n name: ciliumendpoints.cilium.io\n displayName: Cilium Endpoint\n - \ description: |\n Cilium Endpoint represents the status of individual pods - or nodes in\n the cluster which are managed by Cilium, including enforcement - status,\n IP addressing and whether the networking is successfully operational.\n- - kind: CiliumEndpointSlice\n version: v2alpha1\n name: ciliumendpointslices.cilium.io\n - \ displayName: Cilium Endpoint Slice\n description: |\n Cilium Endpoint Slice - represents the status of groups of pods or nodes\n in the cluster which are - managed by Cilium, including enforcement status,\n IP addressing and whether - the networking is successfully operational.\n- kind: CiliumEgressGatewayPolicy\n - \ version: v2\n name: ciliumegressgatewaypolicies.cilium.io\n displayName: Cilium - Egress Gateway Policy\n description: |\n Cilium Egress Gateway Policy provides - control over the way that traffic\n leaves the cluster and which source addresses - to use for that traffic.\n- kind: CiliumClusterwideEnvoyConfig\n version: v2\n - \ name: ciliumclusterwideenvoyconfigs.cilium.io\n displayName: Cilium Clusterwide - Envoy Config\n description: |\n Cilium Clusterwide Envoy Config specifies - Envoy resources and K8s service mappings\n to be provisioned into Cilium host - proxy instances in cluster context.\n- kind: CiliumEnvoyConfig\n version: v2\n - \ name: ciliumenvoyconfigs.cilium.io\n displayName: Cilium Envoy Config\n description: - |\n Cilium Envoy Config specifies Envoy resources and K8s service mappings\n - \ to be provisioned into Cilium host proxy instances in namespace context.\n- - kind: CiliumNodeConfig\n version: v2\n name: ciliumnodeconfigs.cilium.io\n displayName: - Cilium Node Configuration\n description: |\n CiliumNodeConfig is a list of - configuration key-value pairs. It is applied to\n nodes indicated by a label - selector.\n- kind: CiliumBGPPeeringPolicy\n version: v2alpha1\n name: ciliumbgppeeringpolicies.cilium.io\n - \ displayName: Cilium BGP Peering Policy\n description: |\n Cilium BGP Peering - Policy instructs Cilium to create specific BGP peering\n configurations.\n- - kind: CiliumBGPClusterConfig\n version: v2alpha1\n name: ciliumbgpclusterconfigs.cilium.io\n - \ displayName: Cilium BGP Cluster Config\n description: |\n Cilium BGP Cluster - Config instructs Cilium operator to create specific BGP cluster\n configurations.\n- - kind: CiliumBGPPeerConfig\n version: v2alpha1\n name: ciliumbgppeerconfigs.cilium.io\n - \ displayName: Cilium BGP Peer Config\n description: |\n CiliumBGPPeerConfig - is a common set of BGP peer configurations. It can be referenced \n by multiple - peers from CiliumBGPClusterConfig.\n- kind: CiliumBGPAdvertisement\n version: - v2alpha1\n name: ciliumbgpadvertisements.cilium.io\n displayName: Cilium BGP - Advertisement\n description: |\n CiliumBGPAdvertisement is used to define - source of BGP advertisement as well as BGP attributes \n to be advertised with - those prefixes.\n- kind: CiliumBGPNodeConfig\n version: v2alpha1\n name: ciliumbgpnodeconfigs.cilium.io\n - \ displayName: Cilium BGP Node Config\n description: |\n CiliumBGPNodeConfig - is read only node specific BGP configuration. It is constructed by Cilium operator.\n - \ It will also contain node local BGP state information.\n- kind: CiliumBGPNodeConfigOverride\n - \ version: v2alpha1\n name: ciliumbgpnodeconfigoverrides.cilium.io\n displayName: - Cilium BGP Node Config Override\n description: |\n CiliumBGPNodeConfigOverride - can be used to override node specific BGP configuration.\n- kind: CiliumLoadBalancerIPPool\n - \ version: v2alpha1\n name: ciliumloadbalancerippools.cilium.io\n displayName: - Cilium Load Balancer IP Pool\n description: |\n Defining a Cilium Load Balancer - IP Pool instructs Cilium to assign IPs to LoadBalancer Services.\n- kind: CiliumCIDRGroup\n + applying node firewalls.\n- kind: CiliumLocalRedirectPolicy\n version: v2\n name: + ciliumlocalredirectpolicies.cilium.io\n displayName: Cilium Local Redirect Policy\n + \ description: |\n Cilium Local Redirect Policy allows local redirects to be + configured\n within a node to support use cases like Node-Local DNS.\n- kind: + CiliumNode\n version: v2\n name: ciliumnodes.cilium.io\n displayName: Cilium + Node\n description: |\n Cilium Node represents a node managed by Cilium. It + contains a\n specification to control various node specific configuration aspects\n + \ and a status section to represent the status of the node.\n- kind: CiliumIdentity\n + \ version: v2\n name: ciliumidentities.cilium.io\n displayName: Cilium Identity\n + \ description: |\n Cilium Identity allows introspection into security identities + that\n Cilium allocates which identify sets of labels that are assigned to\n + \ individual endpoints in the cluster.\n- kind: CiliumEndpoint\n version: v2\n + \ name: ciliumendpoints.cilium.io\n displayName: Cilium Endpoint\n description: + |\n Cilium Endpoint represents the status of individual pods or nodes in\n + \ the cluster which are managed by Cilium, including enforcement status,\n IP + addressing and whether the networking is successfully operational.\n- kind: CiliumEndpointSlice\n + \ version: v2alpha1\n name: ciliumendpointslices.cilium.io\n displayName: Cilium + Endpoint Slice\n description: |\n Cilium Endpoint Slice represents the status + of groups of pods or nodes\n in the cluster which are managed by Cilium, including + enforcement status,\n IP addressing and whether the networking is successfully + operational.\n- kind: CiliumEgressGatewayPolicy\n version: v2\n name: ciliumegressgatewaypolicies.cilium.io\n + \ displayName: Cilium Egress Gateway Policy\n description: |\n Cilium Egress + Gateway Policy provides control over the way that traffic\n leaves the cluster + and which source addresses to use for that traffic.\n- kind: CiliumClusterwideEnvoyConfig\n + \ version: v2\n name: ciliumclusterwideenvoyconfigs.cilium.io\n displayName: + Cilium Clusterwide Envoy Config\n description: |\n Cilium Clusterwide Envoy + Config specifies Envoy resources and K8s service mappings\n to be provisioned + into Cilium host proxy instances in cluster context.\n- kind: CiliumEnvoyConfig\n + \ version: v2\n name: ciliumenvoyconfigs.cilium.io\n displayName: Cilium Envoy + Config\n description: |\n Cilium Envoy Config specifies Envoy resources and + K8s service mappings\n to be provisioned into Cilium host proxy instances in + namespace context.\n- kind: CiliumNodeConfig\n version: v2\n name: ciliumnodeconfigs.cilium.io\n + \ displayName: Cilium Node Configuration\n description: |\n CiliumNodeConfig + is a list of configuration key-value pairs. It is applied to\n nodes indicated + by a label selector.\n- kind: CiliumBGPClusterConfig\n version: v2alpha1\n name: + ciliumbgpclusterconfigs.cilium.io\n displayName: Cilium BGP Cluster Config\n + \ description: |\n Cilium BGP Cluster Config instructs Cilium operator to create + specific BGP cluster\n configurations.\n- kind: CiliumBGPPeerConfig\n version: + v2alpha1\n name: ciliumbgppeerconfigs.cilium.io\n displayName: Cilium BGP Peer + Config\n description: |\n CiliumBGPPeerConfig is a common set of BGP peer + configurations. It can be referenced \n by multiple peers from CiliumBGPClusterConfig.\n- + kind: CiliumBGPAdvertisement\n version: v2alpha1\n name: ciliumbgpadvertisements.cilium.io\n + \ displayName: Cilium BGP Advertisement\n description: |\n CiliumBGPAdvertisement + is used to define source of BGP advertisement as well as BGP attributes \n to + be advertised with those prefixes.\n- kind: CiliumBGPNodeConfig\n version: v2alpha1\n + \ name: ciliumbgpnodeconfigs.cilium.io\n displayName: Cilium BGP Node Config\n + \ description: |\n CiliumBGPNodeConfig is read only node specific BGP configuration. + It is constructed by Cilium operator.\n It will also contain node local BGP + state information.\n- kind: CiliumBGPNodeConfigOverride\n version: v2alpha1\n + \ name: ciliumbgpnodeconfigoverrides.cilium.io\n displayName: Cilium BGP Node + Config Override\n description: |\n CiliumBGPNodeConfigOverride can be used + to override node specific BGP configuration.\n- kind: CiliumLoadBalancerIPPool\n + \ version: v2\n name: ciliumloadbalancerippools.cilium.io\n displayName: Cilium + Load Balancer IP Pool\n description: |\n Defining a Cilium Load Balancer IP + Pool instructs Cilium to assign IPs to LoadBalancer Services.\n- kind: CiliumCIDRGroup\n \ version: v2alpha1\n name: ciliumcidrgroups.cilium.io\n displayName: Cilium CIDR Group\n description: |\n CiliumCIDRGroup is a list of CIDRs that can be referenced as a single entity from CiliumNetworkPolicies.\n- kind: CiliumL2AnnouncementPolicy\n @@ -77,9 +71,12 @@ annotations: area network, by which nodes, and via which interfaces.\n- kind: CiliumPodIPPool\n \ version: v2alpha1\n name: ciliumpodippools.cilium.io\n displayName: Cilium Pod IP Pool\n description: |\n CiliumPodIPPool defines an IP pool that can - be used for pooled IPAM (i.e. the multi-pool IPAM mode).\n" + be used for pooled IPAM (i.e. the multi-pool IPAM mode).\n- kind: CiliumGatewayClassConfig\n + \ version: v2alpha1\n name: ciliumgatewayclassconfigs.cilium.io\n displayName: + Cilium Gateway Class Config\n description: |\n CiliumGatewayClassConfig defines + a configuration for Gateway API GatewayClass.\n" apiVersion: v2 -appVersion: 1.17.4 +appVersion: 1.19.3 description: eBPF-based Networking, Security, and Observability home: https://cilium.io/ icon: https://cdn.jsdelivr.net/gh/cilium/cilium@main/Documentation/images/logo-solo.svg @@ -95,4 +92,4 @@ kubeVersion: '>= 1.21.0-0' name: cilium sources: - https://github.com/cilium/cilium -version: 1.17.4 +version: 1.19.3 diff --git a/packages/system/cilium/charts/cilium/README.md b/packages/system/cilium/charts/cilium/README.md index b141e058..d7697c56 100644 --- a/packages/system/cilium/charts/cilium/README.md +++ b/packages/system/cilium/charts/cilium/README.md @@ -1,6 +1,6 @@ # cilium -![Version: 1.17.4](https://img.shields.io/badge/Version-1.17.4-informational?style=flat-square) ![AppVersion: 1.17.4](https://img.shields.io/badge/AppVersion-1.17.4-informational?style=flat-square) +![Version: 1.19.3](https://img.shields.io/badge/Version-1.19.3-informational?style=flat-square) ![AppVersion: 1.19.3](https://img.shields.io/badge/AppVersion-1.19.3-informational?style=flat-square) Cilium is open source software for providing and transparently securing network connectivity and loadbalancing between application workloads such as @@ -59,10 +59,14 @@ contributors across the globe, there is almost always someone available to help. | agentNotReadyTaintKey | string | `"node.cilium.io/agent-not-ready"` | Configure the key of the taint indicating that Cilium is not ready on the node. When set to a value starting with `ignore-taint.cluster-autoscaler.kubernetes.io/`, the Cluster Autoscaler will ignore the taint on its decisions, allowing the cluster to scale up. | | aksbyocni.enabled | bool | `false` | Enable AKS BYOCNI integration. Note that this is incompatible with AKS clusters not created in BYOCNI mode: use Azure integration (`azure.enabled`) instead. | | alibabacloud.enabled | bool | `false` | Enable AlibabaCloud ENI integration | +| alibabacloud.nodeSpec.securityGroupTags | list | `[]` | | +| alibabacloud.nodeSpec.securityGroups | list | `[]` | | +| alibabacloud.nodeSpec.vSwitchTags | list | `[]` | | +| alibabacloud.nodeSpec.vSwitches | list | `[]` | | | annotateK8sNode | bool | `false` | Annotate k8s node upon initialization with Cilium's metadata. | | annotations | object | `{}` | Annotations to be added to all top-level cilium-agent objects (resources under templates/cilium-agent) | | apiRateLimit | string | `nil` | The api-rate-limit option can be used to overwrite individual settings of the default configuration for rate limiting calls to the Cilium Agent API | -| authentication.enabled | bool | `true` | Enable authentication processing and garbage collection. Note that if disabled, policy enforcement will still block requests that require authentication. But the resulting authentication requests for these requests will not be processed, therefore the requests not be allowed. | +| authentication.enabled | bool | `false` | Enable authentication processing and garbage collection. Note that if disabled, policy enforcement will still block requests that require authentication. But the resulting authentication requests for these requests will not be processed, therefore the requests not be allowed. | | authentication.gcInterval | string | `"5m0s"` | Interval for garbage collection of auth map entries. | | authentication.mutual.connectTimeout | string | `"5s"` | Timeout for connecting to the remote node TCP socket | | authentication.mutual.port | int | `4250` | Port on the agent where mutual authentication handshakes between agents will be performed | @@ -85,7 +89,7 @@ contributors across the globe, there is almost always someone available to help. | authentication.mutual.spire.install.agent.tolerations | list | `[{"effect":"NoSchedule","key":"node.kubernetes.io/not-ready"},{"effect":"NoSchedule","key":"node-role.kubernetes.io/master"},{"effect":"NoSchedule","key":"node-role.kubernetes.io/control-plane"},{"effect":"NoSchedule","key":"node.cloudprovider.kubernetes.io/uninitialized","value":"true"},{"key":"CriticalAddonsOnly","operator":"Exists"}]` | SPIRE agent tolerations configuration By default it follows the same tolerations as the agent itself to allow the Cilium agent on this node to connect to SPIRE. ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | | authentication.mutual.spire.install.enabled | bool | `true` | Enable SPIRE installation. This will only take effect only if authentication.mutual.spire.enabled is true | | authentication.mutual.spire.install.existingNamespace | bool | `false` | SPIRE namespace already exists. Set to true if Helm should not create, manage, and import the SPIRE namespace. | -| authentication.mutual.spire.install.initImage | object | `{"digest":"sha256:37f7b378a29ceb4c551b1b5582e27747b855bbfaa73fa11914fe0df028dc581f","override":null,"pullPolicy":"IfNotPresent","repository":"docker.io/library/busybox","tag":"1.37.0","useDigest":true}` | init container image of SPIRE agent and server | +| authentication.mutual.spire.install.initImage | object | `{"digest":"sha256:1487d0af5f52b4ba31c7e465126ee2123fe3f2305d638e7827681e7cf6c83d5e","override":null,"pullPolicy":"IfNotPresent","repository":"docker.io/library/busybox","tag":"1.37.0","useDigest":true}` | init container image of SPIRE agent and server | | authentication.mutual.spire.install.namespace | string | `"cilium-spire"` | SPIRE namespace to install into | | authentication.mutual.spire.install.server.affinity | object | `{}` | SPIRE server affinity configuration | | authentication.mutual.spire.install.server.annotations | object | `{}` | SPIRE server annotations | @@ -114,28 +118,35 @@ contributors across the globe, there is almost always someone available to help. | authentication.rotatedIdentitiesQueueSize | int | `1024` | Buffer size of the channel Cilium uses to receive certificate expiration events from auth handlers. | | autoDirectNodeRoutes | bool | `false` | Enable installation of PodCIDR routes between worker nodes if worker nodes share a common L2 network segment. | | azure.enabled | bool | `false` | Enable Azure integration. Note that this is incompatible with AKS clusters created in BYOCNI mode: use AKS BYOCNI integration (`aksbyocni.enabled`) instead. | -| bandwidthManager | object | `{"bbr":false,"enabled":false}` | Enable bandwidth manager to optimize TCP and UDP workloads and allow for rate-limiting traffic from individual Pods with EDT (Earliest Departure Time) through the "kubernetes.io/egress-bandwidth" Pod annotation. | +| azure.nodeSpec.azureInterfaceName | string | `""` | | +| bandwidthManager | object | `{"bbr":false,"bbrHostNamespaceOnly":false,"enabled":false}` | Enable bandwidth manager to optimize TCP and UDP workloads and allow for rate-limiting traffic from individual Pods with EDT (Earliest Departure Time) through the "kubernetes.io/egress-bandwidth" Pod annotation. | | bandwidthManager.bbr | bool | `false` | Activate BBR TCP congestion control for Pods | +| bandwidthManager.bbrHostNamespaceOnly | bool | `false` | Activate BBR TCP congestion control for Pods in the host namespace only. | | bandwidthManager.enabled | bool | `false` | Enable bandwidth manager infrastructure (also prerequirement for BBR) | -| bgpControlPlane | object | `{"enabled":false,"secretsNamespace":{"create":false,"name":"kube-system"},"statusReport":{"enabled":true}}` | This feature set enables virtual BGP routers to be created via CiliumBGPPeeringPolicy CRDs. | +| bgpControlPlane | object | `{"enabled":false,"legacyOriginAttribute":{"enabled":false},"routerIDAllocation":{"ipPool":"","mode":"default"},"secretsNamespace":{"create":false,"name":"kube-system"},"statusReport":{"enabled":true}}` | This feature set enables virtual BGP routers to be created via BGP CRDs. | | bgpControlPlane.enabled | bool | `false` | Enables the BGP control plane. | +| bgpControlPlane.legacyOriginAttribute | object | `{"enabled":false}` | Legacy BGP ORIGIN attribute settings | +| bgpControlPlane.legacyOriginAttribute.enabled | bool | `false` | Enable/Disable advertising LoadBalancerIP routes with the legacy BGP ORIGIN attribute value INCOMPLETE (2) instead of the default IGP (0). Enable for compatibility with the legacy behavior of MetalLB integration. | +| bgpControlPlane.routerIDAllocation | object | `{"ipPool":"","mode":"default"}` | BGP router-id allocation mode | +| bgpControlPlane.routerIDAllocation.ipPool | string | `""` | IP pool to allocate the BGP router-id from when the mode is ip-pool. | +| bgpControlPlane.routerIDAllocation.mode | string | `"default"` | BGP router-id allocation mode. In default mode, the router-id is derived from the IPv4 address if it is available, or else it is determined by the lower 32 bits of the MAC address. | | bgpControlPlane.secretsNamespace | object | `{"create":false,"name":"kube-system"}` | SecretsNamespace is the namespace which BGP support will retrieve secrets from. | | bgpControlPlane.secretsNamespace.create | bool | `false` | Create secrets namespace for BGP secrets. | | bgpControlPlane.secretsNamespace.name | string | `"kube-system"` | The name of the secret namespace to which Cilium agents are given read access | -| bgpControlPlane.statusReport | object | `{"enabled":true}` | Status reporting settings (BGPv2 only) | -| bgpControlPlane.statusReport.enabled | bool | `true` | Enable/Disable BGPv2 status reporting It is recommended to enable status reporting in general, but if you have any issue such as high API server load, you can disable it by setting this to false. | +| bgpControlPlane.statusReport | object | `{"enabled":true}` | Status reporting settings | +| bgpControlPlane.statusReport.enabled | bool | `true` | Enable/Disable BGP status reporting It is recommended to enable status reporting in general, but if you have any issue such as high API server load, you can disable it by setting this to false. | | bpf.authMapMax | int | `524288` | Configure the maximum number of entries in auth map. | | bpf.autoMount.enabled | bool | `true` | Enable automatic mount of BPF filesystem When `autoMount` is enabled, the BPF filesystem is mounted at `bpf.root` path on the underlying host and inside the cilium agent pod. If users disable `autoMount`, it's expected that users have mounted bpffs filesystem at the specified `bpf.root` volume, and then the volume will be mounted inside the cilium agent pod at the same path. | | bpf.ctAccounting | bool | `false` | Enable CT accounting for packets and bytes | | bpf.ctAnyMax | int | `262144` | Configure the maximum number of entries for the non-TCP connection tracking table. | | bpf.ctTcpMax | int | `524288` | Configure the maximum number of entries in the TCP connection tracking table. | -| bpf.datapathMode | string | `veth` | Mode for Pod devices for the core datapath (veth, netkit, netkit-l2, lb-only) | +| bpf.datapathMode | string | `veth` | Mode for Pod devices for the core datapath (veth, netkit, netkit-l2). Note netkit is incompatible with TPROXY (`bpf.tproxy`). | | bpf.disableExternalIPMitigation | bool | `false` | Disable ExternalIP mitigation (CVE-2020-8554) | | bpf.distributedLRU | object | `{"enabled":false}` | Control to use a distributed per-CPU backend memory for the core BPF LRU maps which Cilium uses. This improves performance significantly, but it is also recommended to increase BPF map sizing along with that. | | bpf.distributedLRU.enabled | bool | `false` | Enable distributed LRU backend memory. For compatibility with existing installations it is off by default. | | bpf.enableTCX | bool | `true` | Attach endpoint programs using tcx instead of legacy tc hooks on supported kernels. | | bpf.events | object | `{"default":{"burstLimit":null,"rateLimit":null},"drop":{"enabled":true},"policyVerdict":{"enabled":true},"trace":{"enabled":true}}` | Control events generated by the Cilium datapath exposed to Cilium monitor and Hubble. Helm configuration for BPF events map rate limiting is experimental and might change in upcoming releases. | -| bpf.events.default | object | `{"burstLimit":null,"rateLimit":null}` | Default settings for all types of events except dbg and pcap. | +| bpf.events.default | object | `{"burstLimit":null,"rateLimit":null}` | Default settings for all types of events except dbg. | | bpf.events.default.burstLimit | int | `0` | Configure the maximum number of messages that can be written to BPF events map in 1 second. If burstLimit is greater than 0, non-zero value for rateLimit must also be provided lest the configuration is considered invalid. Setting both burstLimit and rateLimit to 0 disables BPF events rate limiting. | | bpf.events.default.rateLimit | int | `0` | Configure the limit of messages per second that can be written to BPF events map. The number of messages is averaged, meaning that if no messages were written to the map over 5 seconds, it's possible to write more events in the 6th second. If rateLimit is greater than 0, non-zero value for burstLimit must also be provided lest the configuration is considered invalid. Setting both burstLimit and rateLimit to 0 disables BPF events rate limiting. | | bpf.events.drop.enabled | bool | `true` | Enable drop events. | @@ -152,33 +163,39 @@ contributors across the globe, there is almost always someone available to help. | bpf.monitorAggregation | string | `"medium"` | Configure the level of aggregation for monitor notifications. Valid options are none, low, medium, maximum. | | bpf.monitorFlags | string | `"all"` | Configure which TCP flags trigger notifications when seen for the first time in a connection. | | bpf.monitorInterval | string | `"5s"` | Configure the typical time between monitor notifications for active connections. | +| bpf.monitorTraceIPOption | int | `0` | Configure the IP tracing option type. This option is used to specify the IP option type to use for tracing. The value must be an integer between 0 and 255. @schema type: [null, integer] minimum: 0 maximum: 255 @schema | | bpf.natMax | int | `524288` | Configure the maximum number of entries for the NAT table. | | bpf.neighMax | int | `524288` | Configure the maximum number of entries for the neighbor table. | | bpf.nodeMapMax | int | `nil` | Configures the maximum number of entries for the node table. | | bpf.policyMapMax | int | `16384` | Configure the maximum number of entries in endpoint policy map (per endpoint). @schema type: [null, integer] @schema | +| bpf.policyMapPressureMetricsThreshold | float64 | `0.1` | Configure threshold for emitting pressure metrics of policy maps. @schema type: [null, number] @schema | +| bpf.policyStatsMapMax | int | `65536` | Configure the maximum number of entries in global policy stats map. @schema type: [null, integer] @schema | | bpf.preallocateMaps | bool | `false` | Enables pre-allocation of eBPF map values. This increases memory usage but can reduce latency. | | bpf.root | string | `"/sys/fs/bpf"` | Configure the mount point for the BPF filesystem | -| bpf.tproxy | bool | `false` | Configure the eBPF-based TPROXY (beta) to reduce reliance on iptables rules for implementing Layer 7 policy. | +| bpf.tproxy | bool | `false` | Configure the eBPF-based TPROXY (beta) to reduce reliance on iptables rules for implementing Layer 7 policy. Note this is incompatible with netkit (`bpf.datapathMode=netkit`, `bpf.datapathMode=netkit-l2`). | | bpf.vlanBypass | list | `[]` | Configure explicitly allowed VLAN id's for bpf logic bypass. [0] will allow all VLAN id's without any filtering. | | bpfClockProbe | bool | `false` | Enable BPF clock source probing for more efficient tick retrieval. | -| certgen | object | `{"affinity":{},"annotations":{"cronJob":{},"job":{}},"extraVolumeMounts":[],"extraVolumes":[],"generateCA":true,"image":{"digest":"sha256:ab6b1928e9c5f424f6b0f51c68065b9fd85e2f8d3e5f21fbd1a3cb27e6fb9321","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/certgen","tag":"v0.2.1","useDigest":true},"nodeSelector":{},"podLabels":{},"priorityClassName":"","tolerations":[],"ttlSecondsAfterFinished":1800}` | Configure certificate generation for Hubble integration. If hubble.tls.auto.method=cronJob, these values are used for the Kubernetes CronJob which will be scheduled regularly to (re)generate any certificates not provided manually. | +| certgen | object | `{"affinity":{},"annotations":{"cronJob":{},"job":{}},"cronJob":{"failedJobsHistoryLimit":1,"successfulJobsHistoryLimit":3},"extraVolumeMounts":[],"extraVolumes":[],"generateCA":true,"image":{"digest":"sha256:f0c656830e856d26b24b0e144df1f8b327d3b46748d76a630514111fc365b697","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/certgen","tag":"v0.4.1","useDigest":true},"nodeSelector":{},"podLabels":{},"priorityClassName":"","resources":{},"tolerations":[],"ttlSecondsAfterFinished":null}` | Configure certificate generation for Hubble integration. If hubble.tls.auto.method=cronJob, these values are used for the Kubernetes CronJob which will be scheduled regularly to (re)generate any certificates not provided manually. | | certgen.affinity | object | `{}` | Affinity for certgen | | certgen.annotations | object | `{"cronJob":{},"job":{}}` | Annotations to be added to the hubble-certgen initial Job and CronJob | +| certgen.cronJob.failedJobsHistoryLimit | int | `1` | The number of failed finished jobs to keep | +| certgen.cronJob.successfulJobsHistoryLimit | int | `3` | The number of successful finished jobs to keep | | certgen.extraVolumeMounts | list | `[]` | Additional certgen volumeMounts. | | certgen.extraVolumes | list | `[]` | Additional certgen volumes. | | certgen.generateCA | bool | `true` | When set to true the certificate authority secret is created. | | certgen.nodeSelector | object | `{}` | Node selector for certgen ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector | | certgen.podLabels | object | `{}` | Labels to be added to hubble-certgen pods | | certgen.priorityClassName | string | `""` | Priority class for certgen ref: https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#priorityclass | +| certgen.resources | object | `{}` | Resource limits for certgen ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers | | certgen.tolerations | list | `[]` | Node tolerations for pod assignment on nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | -| certgen.ttlSecondsAfterFinished | int | `1800` | Seconds after which the completed job pod will be deleted | +| certgen.ttlSecondsAfterFinished | string | `nil` | Seconds after which the completed job pod will be deleted | | cgroup | object | `{"autoMount":{"enabled":true,"resources":{}},"hostRoot":"/run/cilium/cgroupv2"}` | Configure cgroup related configuration | | cgroup.autoMount.enabled | bool | `true` | Enable auto mount of cgroup2 filesystem. When `autoMount` is enabled, cgroup2 filesystem is mounted at `cgroup.hostRoot` path on the underlying host and inside the cilium agent pod. If users disable `autoMount`, it's expected that users have mounted cgroup2 filesystem at the specified `cgroup.hostRoot` volume, and then the volume will be mounted inside the cilium agent pod at the same path. | | cgroup.autoMount.resources | object | `{}` | Init Container Cgroup Automount resource limits & requests | | cgroup.hostRoot | string | `"/run/cilium/cgroupv2"` | Configure cgroup root where cgroup2 filesystem is mounted on the host (see also: `cgroup.autoMount`) | +| ciliumEndpointSlice | object | `{"enabled":false,"rateLimits":[{"burst":20,"limit":10,"nodes":0},{"burst":100,"limit":50,"nodes":100}]}` | CiliumEndpointSlice configuration options. | | ciliumEndpointSlice.enabled | bool | `false` | Enable Cilium EndpointSlice feature. | | ciliumEndpointSlice.rateLimits | list | `[{"burst":20,"limit":10,"nodes":0},{"burst":100,"limit":50,"nodes":100}]` | List of rate limit options to be used for the CiliumEndpointSlice controller. Each object in the list must have the following fields: nodes: Count of nodes at which to apply the rate limit. limit: The sustained request rate in requests per second. The maximum rate that can be configured is 50. burst: The burst request rate in requests per second. The maximum burst that can be configured is 100. | -| ciliumEndpointSlice.sliceMode | string | `"identity"` | The slicing mode to use for CiliumEndpointSlices. identity groups together CiliumEndpoints that share the same identity. fcfs groups together CiliumEndpoints in a first-come-first-serve basis, filling in the largest non-full slice first. | | cleanBpfState | bool | `false` | Clean all eBPF datapath state from the initContainer of the cilium-agent DaemonSet. WARNING: Use with care! | | cleanState | bool | `false` | Clean all local Cilium state from the initContainer of the cilium-agent DaemonSet. Implies cleanBpfState: true. WARNING: Use with care! | | cluster.id | int | `0` | Unique ID of the cluster. Must be unique across all connected clusters and in the range of 1 to 255. Only required for Cluster Mesh, may be 0 if Cluster Mesh is not used. | @@ -197,12 +214,13 @@ contributors across the globe, there is almost always someone available to help. | clustermesh.apiserver.extraVolumeMounts | list | `[]` | Additional clustermesh-apiserver volumeMounts. | | clustermesh.apiserver.extraVolumes | list | `[]` | Additional clustermesh-apiserver volumes. | | clustermesh.apiserver.healthPort | int | `9880` | TCP port for the clustermesh-apiserver health API. | -| clustermesh.apiserver.image | object | `{"digest":"sha256:0b72f3046cf36ff9b113d53cc61185e893edb5fe728a2c9e561c1083f806453d","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/clustermesh-apiserver","tag":"v1.17.4","useDigest":true}` | Clustermesh API server image. | -| clustermesh.apiserver.kvstoremesh.enabled | bool | `true` | Enable KVStoreMesh. KVStoreMesh caches the information retrieved from the remote clusters in the local etcd instance. | +| clustermesh.apiserver.image | object | `{"digest":"sha256:a8136a7615d6c6041d3aa6f2674d17beaec238170d669507ccc05328a778e2b7","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/clustermesh-apiserver","tag":"v1.19.3","useDigest":true}` | Clustermesh API server image. | +| clustermesh.apiserver.kvstoremesh.enabled | bool | `true` | Enable KVStoreMesh. KVStoreMesh caches the information retrieved from the remote clusters in the local etcd instance (deprecated - KVStoreMesh will always be enabled once the option is removed). | | clustermesh.apiserver.kvstoremesh.extraArgs | list | `[]` | Additional KVStoreMesh arguments. | | clustermesh.apiserver.kvstoremesh.extraEnv | list | `[]` | Additional KVStoreMesh environment variables. | | clustermesh.apiserver.kvstoremesh.extraVolumeMounts | list | `[]` | Additional KVStoreMesh volumeMounts. | | clustermesh.apiserver.kvstoremesh.healthPort | int | `9881` | TCP port for the KVStoreMesh health API. | +| clustermesh.apiserver.kvstoremesh.kvstoreMode | string | `"internal"` | Specify the KVStore mode when running KVStoreMesh Supported values: - "internal": remote cluster identities are cached in etcd that runs as a sidecar within ``clustermesh-apiserver`` pod. - "external": ``clustermesh-apiserver`` will sync remote cluster information to the etcd used as kvstore. This can't be enabled with crd identity allocation mode. | | clustermesh.apiserver.kvstoremesh.lifecycle | object | `{}` | lifecycle setting for the KVStoreMesh container | | clustermesh.apiserver.kvstoremesh.readinessProbe | object | `{}` | Configuration for the KVStoreMesh readiness probe. | | clustermesh.apiserver.kvstoremesh.resources | object | `{}` | Resource requests and limits for the KVStoreMesh container | @@ -220,18 +238,22 @@ contributors across the globe, there is almost always someone available to help. | clustermesh.apiserver.metrics.serviceMonitor.etcd.interval | string | `"10s"` | Interval for scrape metrics (etcd metrics) | | clustermesh.apiserver.metrics.serviceMonitor.etcd.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor clustermesh-apiserver (etcd metrics) | | clustermesh.apiserver.metrics.serviceMonitor.etcd.relabelings | string | `nil` | Relabeling configs for the ServiceMonitor clustermesh-apiserver (etcd metrics) | +| clustermesh.apiserver.metrics.serviceMonitor.etcd.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | | clustermesh.apiserver.metrics.serviceMonitor.interval | string | `"10s"` | Interval for scrape metrics (apiserver metrics) | | clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.interval | string | `"10s"` | Interval for scrape metrics (KVStoreMesh metrics) | | clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor clustermesh-apiserver (KVStoreMesh metrics) | | clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.relabelings | string | `nil` | Relabeling configs for the ServiceMonitor clustermesh-apiserver (KVStoreMesh metrics) | +| clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | | clustermesh.apiserver.metrics.serviceMonitor.labels | object | `{}` | Labels to add to ServiceMonitor clustermesh-apiserver | | clustermesh.apiserver.metrics.serviceMonitor.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor clustermesh-apiserver (apiserver metrics) | | clustermesh.apiserver.metrics.serviceMonitor.relabelings | string | `nil` | Relabeling configs for the ServiceMonitor clustermesh-apiserver (apiserver metrics) | +| clustermesh.apiserver.metrics.serviceMonitor.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | | clustermesh.apiserver.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for pod assignment ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector | | clustermesh.apiserver.podAnnotations | object | `{}` | Annotations to be added to clustermesh-apiserver pods | | clustermesh.apiserver.podDisruptionBudget.enabled | bool | `false` | enable PodDisruptionBudget ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ | | clustermesh.apiserver.podDisruptionBudget.maxUnavailable | int | `1` | Maximum number/percentage of pods that may be made unavailable | | clustermesh.apiserver.podDisruptionBudget.minAvailable | string | `nil` | Minimum number/percentage of pods that should remain scheduled. When it's set, maxUnavailable must be disabled by `maxUnavailable: null` | +| clustermesh.apiserver.podDisruptionBudget.unhealthyPodEvictionPolicy | string | `nil` | How are unhealthy, but running, pods counted for eviction | | clustermesh.apiserver.podLabels | object | `{}` | Labels to be added to clustermesh-apiserver pods | | clustermesh.apiserver.podSecurityContext | object | `{"fsGroup":65532,"runAsGroup":65532,"runAsNonRoot":true,"runAsUser":65532}` | Security context to be added to clustermesh-apiserver pods | | clustermesh.apiserver.priorityClassName | string | `""` | The priority class to use for clustermesh-apiserver | @@ -242,56 +264,90 @@ contributors across the globe, there is almost always someone available to help. | clustermesh.apiserver.service.annotations | object | `{}` | Annotations for the clustermesh-apiserver service. Example annotations to configure an internal load balancer on different cloud providers: * AKS: service.beta.kubernetes.io/azure-load-balancer-internal: "true" * EKS: service.beta.kubernetes.io/aws-load-balancer-scheme: "internal" * GKE: networking.gke.io/load-balancer-type: "Internal" | | clustermesh.apiserver.service.enableSessionAffinity | string | `"HAOnly"` | Defines when to enable session affinity. Each replica in a clustermesh-apiserver deployment runs its own discrete etcd cluster. Remote clients connect to one of the replicas through a shared Kubernetes Service. A client reconnecting to a different backend will require a full resync to ensure data integrity. Session affinity can reduce the likelihood of this happening, but may not be supported by all cloud providers. Possible values: - "HAOnly" (default) Only enable session affinity for deployments with more than 1 replica. - "Always" Always enable session affinity. - "Never" Never enable session affinity. Useful in environments where session affinity is not supported, but may lead to slightly degraded performance due to more frequent reconnections. | | clustermesh.apiserver.service.externalTrafficPolicy | string | `"Cluster"` | The externalTrafficPolicy of service used for apiserver access. | +| clustermesh.apiserver.service.externallyCreated | bool | `false` | Set externallyCreated to true to create the clustermesh-apiserver service outside this helm chart. For example after external load balancer controllers are created. | | clustermesh.apiserver.service.internalTrafficPolicy | string | `"Cluster"` | The internalTrafficPolicy of service used for apiserver access. | +| clustermesh.apiserver.service.labels | object | `{}` | Labels for the clustermesh-apiserver service. | | clustermesh.apiserver.service.loadBalancerClass | string | `nil` | Configure a loadBalancerClass. Allows to configure the loadBalancerClass on the clustermesh-apiserver LB service in case the Service type is set to LoadBalancer (requires Kubernetes 1.24+). | | clustermesh.apiserver.service.loadBalancerIP | string | `nil` | Configure a specific loadBalancerIP. Allows to configure a specific loadBalancerIP on the clustermesh-apiserver LB service in case the Service type is set to LoadBalancer. | | clustermesh.apiserver.service.loadBalancerSourceRanges | list | `[]` | Configure loadBalancerSourceRanges. Allows to configure the source IP ranges allowed to access the clustermesh-apiserver LB service in case the Service type is set to LoadBalancer. | -| clustermesh.apiserver.service.nodePort | int | `32379` | Optional port to use as the node port for apiserver access. WARNING: make sure to configure a different NodePort in each cluster if kube-proxy replacement is enabled, as Cilium is currently affected by a known bug (#24692) when NodePorts are handled by the KPR implementation. If a service with the same NodePort exists both in the local and the remote cluster, all traffic originating from inside the cluster and targeting the corresponding NodePort will be redirected to a local backend, regardless of whether the destination node belongs to the local or the remote cluster. | +| clustermesh.apiserver.service.nodePort | int | `32379` | Optional port to use as the node port for apiserver access. | | clustermesh.apiserver.service.type | string | `"NodePort"` | The type of service used for apiserver access. | | clustermesh.apiserver.terminationGracePeriodSeconds | int | `30` | terminationGracePeriodSeconds for the clustermesh-apiserver deployment | | clustermesh.apiserver.tls.admin | object | `{"cert":"","key":""}` | base64 encoded PEM values for the clustermesh-apiserver admin certificate and private key. Used if 'auto' is not enabled. | -| clustermesh.apiserver.tls.authMode | string | `"legacy"` | Configure the clustermesh authentication mode. Supported values: - legacy: All clusters access remote clustermesh instances with the same username (i.e., remote). The "remote" certificate must be generated with CN=remote if provided manually. - migration: Intermediate mode required to upgrade from legacy to cluster (and vice versa) with no disruption. Specifically, it enables the creation of the per-cluster usernames, while still using the common one for authentication. The "remote" certificate must be generated with CN=remote if provided manually (same as legacy). - cluster: Each cluster accesses remote etcd instances with a username depending on the local cluster name (i.e., remote-). The "remote" certificate must be generated with CN=remote- if provided manually. Cluster mode is meaningful only when the same CA is shared across all clusters part of the mesh. | +| clustermesh.apiserver.tls.admin.cert | string | `""` | Deprecated, as secrets will always need to be created externally if `auto` is disabled. | +| clustermesh.apiserver.tls.admin.key | string | `""` | Deprecated, as secrets will always need to be created externally if `auto` is disabled. | +| clustermesh.apiserver.tls.authMode | string | `"migration"` | Configure the clustermesh authentication mode. Supported values: - legacy: All clusters access remote clustermesh instances with the same username (i.e., remote). The "remote" certificate must be generated with CN=remote if provided manually. - migration: Intermediate mode required to upgrade from legacy to cluster (and vice versa) with no disruption. Specifically, it enables the creation of the per-cluster usernames, while still using the common one for authentication. The "remote" certificate must be generated with CN=remote if provided manually (same as legacy). - cluster: Each cluster accesses remote etcd instances with a username depending on the local cluster name (i.e., remote-). The "remote" certificate must be generated with CN=remote- if provided manually. Cluster mode is meaningful only when the same CA is shared across all clusters part of the mesh. | | clustermesh.apiserver.tls.auto | object | `{"certManagerIssuerRef":{},"certValidityDuration":1095,"enabled":true,"method":"helm"}` | Configure automatic TLS certificates generation. A Kubernetes CronJob is used the generate any certificates not provided by the user at installation time. | | clustermesh.apiserver.tls.auto.certManagerIssuerRef | object | `{}` | certmanager issuer used when clustermesh.apiserver.tls.auto.method=certmanager. | | clustermesh.apiserver.tls.auto.certValidityDuration | int | `1095` | Generated certificates validity duration in days. | -| clustermesh.apiserver.tls.auto.enabled | bool | `true` | When set to true, automatically generate a CA and certificates to enable mTLS between clustermesh-apiserver and external workload instances. If set to false, the certs to be provided by setting appropriate values below. | -| clustermesh.apiserver.tls.client | object | `{"cert":"","key":""}` | base64 encoded PEM values for the clustermesh-apiserver client certificate and private key. Used if 'auto' is not enabled. | -| clustermesh.apiserver.tls.enableSecrets | bool | `true` | Allow users to provide their own certificates Users may need to provide their certificates using a mechanism that requires they provide their own secrets. This setting does not apply to any of the auto-generated mechanisms below, it only restricts the creation of secrets via the `tls-provided` templates. | +| clustermesh.apiserver.tls.auto.enabled | bool | `true` | When set to true, automatically generate a CA and certificates to enable mTLS between clustermesh-apiserver and external workload instances. When set to false you need to pre-create the following secrets: - clustermesh-apiserver-server-cert - clustermesh-apiserver-admin-cert - clustermesh-apiserver-remote-cert - clustermesh-apiserver-local-cert The above secret should at least contains the keys `tls.crt` and `tls.key` and optionally `ca.crt` if a CA bundle is not configured. | +| clustermesh.apiserver.tls.enableSecrets | deprecated | `true` | Allow users to provide their own certificates Users may need to provide their certificates using a mechanism that requires they provide their own secrets. This setting does not apply to any of the auto-generated mechanisms below, it only restricts the creation of secrets via the `tls-provided` templates. This option is deprecated as secrets are expected to be created externally when 'auto' is not enabled. | | clustermesh.apiserver.tls.remote | object | `{"cert":"","key":""}` | base64 encoded PEM values for the clustermesh-apiserver remote cluster certificate and private key. Used if 'auto' is not enabled. | +| clustermesh.apiserver.tls.remote.cert | string | `""` | Deprecated, as secrets will always need to be created externally if `auto` is disabled. | +| clustermesh.apiserver.tls.remote.key | string | `""` | Deprecated, as secrets will always need to be created externally if `auto` is disabled. | | clustermesh.apiserver.tls.server | object | `{"cert":"","extraDnsNames":[],"extraIpAddresses":[],"key":""}` | base64 encoded PEM values for the clustermesh-apiserver server certificate and private key. Used if 'auto' is not enabled. | +| clustermesh.apiserver.tls.server.cert | string | `""` | Deprecated, as secrets will always need to be created externally if `auto` is disabled. | | clustermesh.apiserver.tls.server.extraDnsNames | list | `[]` | Extra DNS names added to certificate when it's auto generated | | clustermesh.apiserver.tls.server.extraIpAddresses | list | `[]` | Extra IP addresses added to certificate when it's auto generated | +| clustermesh.apiserver.tls.server.key | string | `""` | Deprecated, as secrets will always need to be created externally if `auto` is disabled. | | clustermesh.apiserver.tolerations | list | `[]` | Node tolerations for pod assignment on nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | | clustermesh.apiserver.topologySpreadConstraints | list | `[]` | Pod topology spread constraints for clustermesh-apiserver | | clustermesh.apiserver.updateStrategy | object | `{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0},"type":"RollingUpdate"}` | clustermesh-apiserver update strategy | +| clustermesh.cacheTTL | string | `"0s"` | The time to live for the cache of a remote cluster after connectivity is lost. If the connection is not re-established within this duration, the cached data is revoked to prevent stale state. If not specified or set to 0s, the cache is never revoked (default). | | clustermesh.config | object | `{"clusters":[],"domain":"mesh.cilium.io","enabled":false}` | Clustermesh explicit configuration. | -| clustermesh.config.clusters | list | `[]` | List of clusters to be peered in the mesh. | +| clustermesh.config.clusters | list | `[]` | Clusters to be peered in the mesh. @schema type: [object, array] @schema | | clustermesh.config.domain | string | `"mesh.cilium.io"` | Default dns domain for the Clustermesh API servers This is used in the case cluster addresses are not provided and IPs are used. | -| clustermesh.config.enabled | bool | `false` | Enable the Clustermesh explicit configuration. | +| clustermesh.config.enabled | bool | `false` | Enable the Clustermesh explicit configuration. If set to false, you need to provide the following resources yourself: - (Secret) cilium-clustermesh (used by cilium-agent/cilium-operator to connect to the local etcd instance if KVStoreMesh is enabled or the remote clusters if KVStoreMesh is disabled) - (Secret) cilium-kvstoremesh (used by KVStoreMesh to connect to the remote clusters) - (ConfigMap) clustermesh-remote-users (used to create one etcd user per remote cluster if clustermesh-apiserver is used and `clustermesh.apiserver.tls.authMode` is not set to `legacy`) | | clustermesh.enableEndpointSliceSynchronization | bool | `false` | Enable the synchronization of Kubernetes EndpointSlices corresponding to the remote endpoints of appropriately-annotated global services through ClusterMesh | -| clustermesh.enableMCSAPISupport | bool | `false` | Enable Multi-Cluster Services API support | +| clustermesh.enableMCSAPISupport | bool | `false` | Enable Multi-Cluster Services API support (deprecated; use clustermesh.mcsapi.enabled) | | clustermesh.maxConnectedClusters | int | `255` | The maximum number of clusters to support in a ClusterMesh. This value cannot be changed on running clusters, and all clusters in a ClusterMesh must be configured with the same value. Values > 255 will decrease the maximum allocatable cluster-local identities. Supported values are 255 and 511. | -| clustermesh.useAPIServer | bool | `false` | Deploy clustermesh-apiserver for clustermesh | +| clustermesh.mcsapi.corednsAutoConfigure.affinity | object | `{}` | Affinity for coredns-mcsapi-autoconfig | +| clustermesh.mcsapi.corednsAutoConfigure.annotations | object | `{}` | Annotations to be added to the coredns-mcsapi-autoconfig Job | +| clustermesh.mcsapi.corednsAutoConfigure.coredns.clusterDomain | string | `"cluster.local"` | The cluster domain for the cluster CoreDNS service | +| clustermesh.mcsapi.corednsAutoConfigure.coredns.clustersetDomain | string | `"clusterset.local"` | The clusterset domain for the cluster CoreDNS service | +| clustermesh.mcsapi.corednsAutoConfigure.coredns.configMapName | string | `"coredns"` | The ConfigMap name for the cluster CoreDNS service | +| clustermesh.mcsapi.corednsAutoConfigure.coredns.deploymentName | string | `"coredns"` | The Deployment for the cluster CoreDNS service | +| clustermesh.mcsapi.corednsAutoConfigure.coredns.namespace | string | `"kube-system"` | The namespace for the cluster CoreDNS service | +| clustermesh.mcsapi.corednsAutoConfigure.coredns.serviceAccountName | string | `"coredns"` | The Service Account name for the cluster CoreDNS service | +| clustermesh.mcsapi.corednsAutoConfigure.enabled | bool | `false` | Enable auto-configuration of CoreDNS for Multi-Cluster Services API. CoreDNS MUST be at least in version v1.12.2 to run this. | +| clustermesh.mcsapi.corednsAutoConfigure.extraArgs | list | `[]` | Additional arguments to `clustermesh-apiserver coredns-mcsapi-auto-configure`. | +| clustermesh.mcsapi.corednsAutoConfigure.extraVolumeMounts | list | `[]` | Additional coredns-mcsapi-autoconfig volumeMounts. | +| clustermesh.mcsapi.corednsAutoConfigure.extraVolumes | list | `[]` | Additional coredns-mcsapi-autoconfig volumes. | +| clustermesh.mcsapi.corednsAutoConfigure.nodeSelector | object | `{}` | Node selector for coredns-mcsapi-autoconfig ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector | +| clustermesh.mcsapi.corednsAutoConfigure.podLabels | object | `{}` | Labels to be added to coredns-mcsapi-autoconfig pods | +| clustermesh.mcsapi.corednsAutoConfigure.priorityClassName | string | `""` | Priority class for coredns-mcsapi-autoconfig ref: https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#priorityclass | +| clustermesh.mcsapi.corednsAutoConfigure.resources | object | `{}` | Resource limits for coredns-mcsapi-autoconfig ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers | +| clustermesh.mcsapi.corednsAutoConfigure.tolerations | list | `[]` | Node tolerations for pod assignment on nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | +| clustermesh.mcsapi.corednsAutoConfigure.ttlSecondsAfterFinished | int | `1800` | Seconds after which the completed job pod will be deleted | +| clustermesh.mcsapi.enabled | bool | `false` | Enable Multi-Cluster Services API support | +| clustermesh.mcsapi.installCRDs | bool | `true` | Enabled MCS-API CRDs auto-installation | +| clustermesh.policyDefaultLocalCluster | bool | `true` | Control whether policy rules assume by default the local cluster if not explicitly selected | +| clustermesh.useAPIServer | bool | `false` | Deploy clustermesh-apiserver for clustermesh. This option is typically used with ``clustermesh.config.enabled=true``. Refer to the ``clustermesh.config.enabled=true``documentation for more information. | | cni.binPath | string | `"/opt/cni/bin"` | Configure the path to the CNI binary directory on the host. | | cni.chainingMode | string | `nil` | Configure chaining on top of other CNI plugins. Possible values: - none - aws-cni - flannel - generic-veth - portmap | | cni.chainingTarget | string | `nil` | A CNI network name in to which the Cilium plugin should be added as a chained plugin. This will cause the agent to watch for a CNI network with this network name. When it is found, this will be used as the basis for Cilium's CNI configuration file. If this is set, it assumes a chaining mode of generic-veth. As a special case, a chaining mode of aws-cni implies a chainingTarget of aws-cni. | | cni.confFileMountPath | string | `"/tmp/cni-configuration"` | Configure the path to where to mount the ConfigMap inside the agent pod. | | cni.confPath | string | `"/etc/cni/net.d"` | Configure the path to the CNI configuration directory on the host. | -| cni.configMapKey | string | `"cni-config"` | Configure the key in the CNI ConfigMap to read the contents of the CNI configuration from. | +| cni.configMap | string | `""` | When defined, configMap will mount the provided value as ConfigMap and interpret the 'cni.configMapKey' value as CNI configuration file and write it when the agent starts up. | +| cni.configMapKey | string | `"cni-config"` | Configure the key in the CNI ConfigMap to read the contents of the CNI configuration from. For this to be effective, the 'cni.configMap' parameter must be specified too. Note that the 'cni.configMap' parameter is the name of the ConfigMap, while 'cni.configMapKey' is the name of the key in the ConfigMap data containing the actual configuration. | | cni.customConf | bool | `false` | Skip writing of the CNI configuration. This can be used if writing of the CNI configuration is performed by external automation. | | cni.enableRouteMTUForCNIChaining | bool | `false` | Enable route MTU for pod netns when CNI chaining is used | | cni.exclusive | bool | `true` | Make Cilium take ownership over the `/etc/cni/net.d` directory on the node, renaming all non-Cilium CNI configurations to `*.cilium_bak`. This ensures no Pods can be scheduled using other CNI plugins during Cilium agent downtime. | | cni.hostConfDirMountPath | string | `"/host/etc/cni/net.d"` | Configure the path to where the CNI configuration directory is mounted inside the agent pod. | | cni.install | bool | `true` | Install the CNI configuration and binary files into the filesystem. | +| cni.iptablesRemoveAWSRules | bool | `true` | Enable the removal of iptables rules created by the AWS CNI VPC plugin. | | cni.logFile | string | `"/var/run/cilium/cilium-cni.log"` | Configure the log file for CNI logging with retention policy of 7 days. Disable CNI file logging by setting this field to empty explicitly. | -| cni.resources | object | `{"requests":{"cpu":"100m","memory":"10Mi"}}` | Specifies the resources for the cni initContainer | +| cni.resources | object | `{"limits":{"cpu":1,"memory":"1Gi"},"requests":{"cpu":"100m","memory":"10Mi"}}` | Specifies the resources for the cni initContainer | | cni.uninstall | bool | `false` | Remove the CNI configuration and binary files on agent shutdown. Enable this if you're removing Cilium from the cluster. Disable this to prevent the CNI configuration file from being removed during agent upgrade, which can cause nodes to go unmanageable. | | commonLabels | object | `{}` | commonLabels allows users to add common labels for all Cilium resources. | +| configDriftDetection | object | `{"driftChecker":true,"enabled":true,"ignoredKeys":[]}` | Configuration for the ConfigMap drift detection feature. When enabled, the agent continuously watches the cilium-config ConfigMap and exposes a cilium_drift_checker_config_delta Prometheus metric reporting the number of keys that differ between the ConfigMap and the agent's active settings. A non-zero value indicates that the agent has not yet applied all current ConfigMap changes and needs to be restarted. | +| configDriftDetection.driftChecker | bool | `true` | Enable the drift checker which compares the DynamicConfig table against the agent's active settings and publishes the cilium_drift_checker_config_delta metric. | +| configDriftDetection.enabled | bool | `true` | Enable watching of the cilium-config ConfigMap and reflecting its contents into the agent's internal DynamicConfig table. | +| configDriftDetection.ignoredKeys | list | `[]` | List of config-map keys to ignore when computing the drift delta. | +| connectivityProbeFrequencyRatio | float64 | `0.5` | Ratio of the connectivity probe frequency vs resource usage, a float in [0, 1]. 0 will give more frequent probing, 1 will give less frequent probing. Probing frequency is dynamically adjusted based on the cluster size. | | conntrackGCInterval | string | `"0s"` | Configure how frequently garbage collection should occur for the datapath connection tracking table. | | conntrackGCMaxInterval | string | `""` | Configure the maximum frequency for the garbage collection of the connection tracking table. Only affects the automatic computation for the frequency and has no effect when 'conntrackGCInterval' is set. This can be set to more frequently clean up unused identities created from ToFQDN policies. | | crdWaitTimeout | string | `"5m"` | Configure timeout in which Cilium will exit if CRDs are not available | -| customCalls | object | `{"enabled":false}` | Tail call hooks for custom eBPF programs. | -| customCalls.enabled | bool | `false` | Enable tail call hooks for custom eBPF programs. | | daemon.allowedConfigOverrides | string | `nil` | allowedConfigOverrides is a list of config-map keys that can be overridden. That is to say, if this value is set, config sources (excepting the first one) can only override keys in this list. This takes precedence over blockedConfigOverrides. By default, all keys may be overridden. To disable overrides, set this to "none" or change the configSources variable. | | daemon.blockedConfigOverrides | string | `nil` | blockedConfigOverrides is a list of config-map keys that may not be overridden. In other words, if any of these keys appear in a configuration source excepting the first one, they will be ignored This is ignored if allowedConfigOverrides is set. By default, all keys may be overridden. | | daemon.configSources | string | `nil` | Configure a custom list of possible configuration override sources The default is "config-map:cilium-config,cilium-node-config". For supported values, see the help text for the build-config subcommand. Note that this value should be a comma-separated string. | @@ -299,8 +355,9 @@ contributors across the globe, there is almost always someone available to help. | daemon.runPath | string | `"/var/run/cilium"` | Configure where Cilium runtime state should be stored. | | dashboards | object | `{"annotations":{},"enabled":false,"label":"grafana_dashboard","labelValue":"1","namespace":null}` | Grafana dashboards for cilium-agent grafana can import dashboards based on the label and value ref: https://github.com/grafana/helm-charts/tree/main/charts/grafana#sidecar-for-dashboards | | debug.enabled | bool | `false` | Enable debug logging | -| debug.verbose | string | `nil` | Configure verbosity levels for debug logging This option is used to enable debug messages for operations related to such sub-system such as (e.g. kvstore, envoy, datapath or policy), and flow is for enabling debug messages emitted per request, message and connection. Multiple values can be set via a space-separated string (e.g. "datapath envoy"). Applicable values: - flow - kvstore - envoy - datapath - policy | -| defaultLBServiceIPAM | string | `"lbipam"` | defaultLBServiceIPAM indicates the default LoadBalancer Service IPAM when no LoadBalancer class is set. Applicable values: lbipam, nodeipam, none @schema type: [string] @schema | +| debug.metricsSamplingInterval | string | `"5m"` | Set the agent-internal metrics sampling frequency. This sets the frequency of the internal sampling of the agent metrics. These are available via the "cilium-dbg shell -- metrics -s" command and are part of the metrics HTML page included in the sysdump. @schema type: [null, string] @schema | +| debug.verbose | string | `nil` | Configure verbosity levels for debug logging This option is used to enable debug messages for operations related to such sub-system such as (e.g. kvstore, envoy, datapath, policy, or tagged), and flow is for enabling debug messages emitted per request, message and connection. Multiple values can be set via a space-separated string (e.g. "datapath envoy"). Applicable values: - flow - kvstore - envoy - datapath - policy - tagged | +| defaultLBServiceIPAM | string | `"lbipam"` | defaultLBServiceIPAM indicates the default LoadBalancer Service IPAM when no LoadBalancer class is set. Applicable values: lbipam, nodeipam, none | | directRoutingSkipUnreachable | bool | `false` | Enable skipping of PodCIDR routes between worker nodes if the worker nodes are in a different L2 network segment. | | disableEndpointCRD | bool | `false` | Disable the usage of CiliumEndpoint CRD. | | dnsPolicy | string | `""` | DNS policy for Cilium agent pods. Ref: https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy | @@ -310,24 +367,23 @@ contributors across the globe, there is almost always someone available to help. | dnsProxy.idleConnectionGracePeriod | string | `"0s"` | Time during which idle but previously active connections with expired DNS lookups are still considered alive. | | dnsProxy.maxDeferredConnectionDeletes | int | `10000` | Maximum number of IPs to retain for expired DNS lookups with still-active connections. | | dnsProxy.minTtl | int | `0` | The minimum time, in seconds, to use DNS data for toFQDNs policies. If the upstream DNS server returns a DNS record with a shorter TTL, Cilium overwrites the TTL with this value. Setting this value to zero means that Cilium will honor the TTLs returned by the upstream DNS server. | +| dnsProxy.preAllocateIdentities | bool | `true` | Pre-allocate ToFQDN identities. This reduces DNS proxy tail latency, at the potential cost of some unnecessary policymap entries. Disable this if you have a large (200+) number of unique ToFQDN selectors. | | dnsProxy.preCache | string | `""` | DNS cache data at this path is preloaded on agent startup. | | dnsProxy.proxyPort | int | `0` | Global port on which the in-agent DNS proxy should listen. Default 0 is a OS-assigned port. | | dnsProxy.proxyResponseMaxDelay | string | `"100ms"` | The maximum time the DNS proxy holds an allowed DNS response before sending it along. Responses are sent as soon as the datapath is updated with the new IP information. | | dnsProxy.socketLingerTimeout | int | `10` | Timeout (in seconds) when closing the connection between the DNS proxy and the upstream server. If set to 0, the connection is closed immediately (with TCP RST). If set to -1, the connection is closed asynchronously in the background. | | egressGateway.enabled | bool | `false` | Enables egress gateway to redirect and SNAT the traffic that leaves the cluster. | | egressGateway.reconciliationTriggerInterval | string | `"1s"` | Time between triggers of egress gateway state reconciliations | -| enableCiliumEndpointSlice | bool | `false` | Enable CiliumEndpointSlice feature (deprecated, please use `ciliumEndpointSlice.enabled` instead). | | enableCriticalPriorityClass | bool | `true` | Explicitly enable or disable priority class. .Capabilities.KubeVersion is unsettable in `helm template` calls, it depends on k8s libraries version that Helm was compiled against. This option allows to explicitly disable setting the priority class, which is useful for rendering charts for gke clusters in advance. | | enableIPv4BIGTCP | bool | `false` | Enables IPv4 BIG TCP support which increases maximum IPv4 GSO/GRO limits for nodes and pods | -| enableIPv4Masquerade | bool | `true` | Enables masquerading of IPv4 traffic leaving the node from endpoints. | +| enableIPv4Masquerade | bool | `true` unless ipam eni mode is active | Enables masquerading of IPv4 traffic leaving the node from endpoints. | | enableIPv6BIGTCP | bool | `false` | Enables IPv6 BIG TCP support which increases maximum IPv6 GSO/GRO limits for nodes and pods | | enableIPv6Masquerade | bool | `true` | Enables masquerading of IPv6 traffic leaving the node from endpoints. | | enableInternalTrafficPolicy | bool | `true` | Enable Internal Traffic Policy | -| enableK8sTerminatingEndpoint | bool | `true` | Configure whether to enable auto detect of terminating state for endpoints in order to support graceful termination. | | enableLBIPAM | bool | `true` | Enable LoadBalancer IP Address Management | | enableMasqueradeRouteSource | bool | `false` | Enables masquerading to the source of the route for traffic leaving the node from endpoints. | +| enableNoServiceEndpointsRoutable | bool | `true` | Enable routing to a service that has zero endpoints | | enableNonDefaultDenyPolicies | bool | `true` | Enable Non-Default-Deny policies | -| enableRuntimeDeviceDetection | bool | `true` | Enables experimental support for the detection of new and removed datapath devices. When devices change the eBPF datapath is reloaded and services updated. If "devices" is set then only those devices, or devices matching a wildcard will be considered. This option has been deprecated and is a no-op. | | enableXTSocketFallback | bool | `true` | Enables the fallback compatibility solution for when the xt_socket kernel module is missing and it is needed for the datapath L7 redirection to work properly. See documentation for details on when this can be disabled: https://docs.cilium.io/en/stable/operations/system_requirements/#linux-kernel. | | encryption.enabled | bool | `false` | Enable transparent network encryption. | | encryption.ipsec.encryptedOverlay | bool | `false` | Enable IPsec encrypted overlay | @@ -338,14 +394,39 @@ contributors across the globe, there is almost always someone available to help. | encryption.ipsec.mountPath | string | `"/etc/ipsec"` | Path to mount the secret inside the Cilium pod. | | encryption.ipsec.secretName | string | `"cilium-ipsec-keys"` | Name of the Kubernetes secret containing the encryption keys. | | encryption.nodeEncryption | bool | `false` | Enable encryption for pure node to node traffic. This option is only effective when encryption.type is set to "wireguard". | -| encryption.strictMode | object | `{"allowRemoteNodeIdentities":false,"cidr":"","enabled":false}` | Configure the WireGuard Pod2Pod strict mode. | -| encryption.strictMode.allowRemoteNodeIdentities | bool | `false` | Allow dynamic lookup of remote node identities. This is required when tunneling is used or direct routing is used and the node CIDR and pod CIDR overlap. | -| encryption.strictMode.cidr | string | `""` | CIDR for the WireGuard Pod2Pod strict mode. | -| encryption.strictMode.enabled | bool | `false` | Enable WireGuard Pod2Pod strict mode. | -| encryption.type | string | `"ipsec"` | Encryption method. Can be either ipsec or wireguard. | +| encryption.strictMode | object | `{"allowRemoteNodeIdentities":false,"cidr":"","egress":{"allowRemoteNodeIdentities":false,"cidr":"","enabled":false},"enabled":false,"ingress":{"enabled":false}}` | Configure the Encryption Pod2Pod strict mode. | +| encryption.strictMode.allowRemoteNodeIdentities | bool | `false` | Allow dynamic lookup of remote node identities. (deprecated: please use encryption.strictMode.egress.allowRemoteNodeIdentities) This is required when tunneling is used or direct routing is used and the node CIDR and pod CIDR overlap. | +| encryption.strictMode.cidr | string | `""` | CIDR for the Encryption Pod2Pod strict mode. (deprecated: please use encryption.strictMode.egress.cidr) | +| encryption.strictMode.egress.allowRemoteNodeIdentities | bool | `false` | Allow dynamic lookup of remote node identities. This is required when tunneling is used or direct routing is used and the node CIDR and pod CIDR overlap. | +| encryption.strictMode.egress.cidr | string | `""` | CIDR for the Encryption Pod2Pod strict egress mode. | +| encryption.strictMode.egress.enabled | bool | `false` | Enable strict egress encryption. | +| encryption.strictMode.enabled | bool | `false` | Enable Encryption Pod2Pod strict mode. (deprecated: please use encryption.strictMode.egress.enabled) | +| encryption.strictMode.ingress.enabled | bool | `false` | Enable strict ingress encryption. When enabled, all unencrypted overlay ingress traffic will be dropped. This option is only applicable when WireGuard and tunneling are enabled. | +| encryption.type | string | `"ipsec"` | Encryption method. Can be one of ipsec, wireguard or ztunnel. | | encryption.wireguard.persistentKeepalive | string | `"0s"` | Controls WireGuard PersistentKeepalive option. Set 0s to disable. | +| encryption.ztunnel | object | `{"affinity":{},"annotations":{},"caAddress":"https://localhost:15012","extraEnv":[],"extraVolumeMounts":[],"extraVolumes":[],"healthPort":15021,"image":{"digest":null,"override":null,"pullPolicy":"IfNotPresent","repository":"docker.io/istio/ztunnel","tag":"1.28.0-distroless","useDigest":false},"nodeSelector":{"kubernetes.io/os":"linux"},"podAnnotations":{},"podLabels":{},"priorityClassName":null,"readinessProbe":{"failureThreshold":3,"initialDelaySeconds":0,"periodSeconds":10},"resources":{"requests":{"cpu":"200m","memory":"512Mi"}},"secrets":{"bootstrapRootCert":null},"terminationGracePeriodSeconds":30,"tolerations":[{"effect":"NoSchedule","operator":"Exists"},{"key":"CriticalAddonsOnly","operator":"Exists"},{"effect":"NoExecute","operator":"Exists"}],"updateStrategy":{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0},"type":"RollingUpdate"}}` | ztunnel encryption configuration. ztunnel is Istio's purpose-built, per-node proxy for handling L4 traffic in ambient mesh mode. These settings only apply when encryption.type is set to "ztunnel". | +| encryption.ztunnel.affinity | object | `{}` | Affinity for ztunnel pods. | +| encryption.ztunnel.annotations | object | `{}` | Annotations to be added to all ztunnel resources. | +| encryption.ztunnel.caAddress | string | `"https://localhost:15012"` | CA server address for certificate requests. | +| encryption.ztunnel.extraEnv | list | `[]` | Additional ztunnel container environment variables. | +| encryption.ztunnel.extraVolumeMounts | list | `[]` | Additional ztunnel volumeMounts. | +| encryption.ztunnel.extraVolumes | list | `[]` | Additional ztunnel volumes. | +| encryption.ztunnel.healthPort | int | `15021` | TCP port for the health API. | +| encryption.ztunnel.image | object | `{"digest":null,"override":null,"pullPolicy":"IfNotPresent","repository":"docker.io/istio/ztunnel","tag":"1.28.0-distroless","useDigest":false}` | ztunnel container image. | +| encryption.ztunnel.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node selector for ztunnel pods. | +| encryption.ztunnel.podAnnotations | object | `{}` | Annotations to be added to ztunnel pods. | +| encryption.ztunnel.podLabels | object | `{}` | Labels to be added to ztunnel pods. | +| encryption.ztunnel.priorityClassName | string | `nil` | The priority class to use for ztunnel pods. | +| encryption.ztunnel.readinessProbe | object | `{"failureThreshold":3,"initialDelaySeconds":0,"periodSeconds":10}` | Readiness probe configuration. | +| encryption.ztunnel.resources | object | `{"requests":{"cpu":"200m","memory":"512Mi"}}` | ztunnel resource limits & requests. | +| encryption.ztunnel.secrets | object | `{"bootstrapRootCert":null}` | ztunnel secrets configuration. | +| encryption.ztunnel.secrets.bootstrapRootCert | string | `nil` | Base64-encoded bootstrap root certificate content. If not provided, the secret must be created manually before deploying. @schema type: [null, string] @schema | +| encryption.ztunnel.terminationGracePeriodSeconds | int | `30` | Configure termination grace period for ztunnel DaemonSet. | +| encryption.ztunnel.tolerations | list | `[{"effect":"NoSchedule","operator":"Exists"},{"key":"CriticalAddonsOnly","operator":"Exists"},{"effect":"NoExecute","operator":"Exists"}]` | Node tolerations for ztunnel scheduling. | +| encryption.ztunnel.updateStrategy | object | `{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0},"type":"RollingUpdate"}` | ztunnel update strategy. | | endpointHealthChecking.enabled | bool | `true` | Enable connectivity health checking between virtual endpoints. | | endpointLockdownOnMapOverflow | bool | `false` | Enable endpoint lockdown on policy map overflow. | +| endpointPolicyUpdateTimeoutDuration | string | `nil` | Max duration to wait for envoy to respond to configuration changes. Default "10s". | | endpointRoutes.enabled | bool | `false` | Enable use of per endpoint routes instead of routing via the cilium_host interface. | | eni.awsEnablePrefixDelegation | bool | `false` | Enable ENI prefix delegation | | eni.awsReleaseExcessIPs | bool | `false` | Release IPs not used from the ENI | @@ -356,13 +437,24 @@ contributors across the globe, there is almost always someone available to help. | eni.gcTags | object | `{"io.cilium/cilium-managed":"true,"io.cilium/cluster-name":""}` | Additional tags attached to ENIs created by Cilium. Dangling ENIs with this tag will be garbage collected | | eni.iamRole | string | `""` | If using IAM role for Service Accounts will not try to inject identity values from cilium-aws kubernetes secret. Adds annotation to service account if managed by Helm. See https://github.com/aws/amazon-eks-pod-identity-webhook | | eni.instanceTagsFilter | list | `[]` | Filter via AWS EC2 Instance tags (k=v) which will dictate which AWS EC2 Instances are going to be used to create new ENIs | +| eni.nodeSpec | object | `{"deleteOnTermination":null,"disablePrefixDelegation":false,"excludeInterfaceTags":[],"firstInterfaceIndex":null,"securityGroupTags":[],"securityGroups":[],"subnetIDs":[],"subnetTags":[],"usePrimaryAddress":false}` | NodeSpec configuration for the ENI | +| eni.nodeSpec.deleteOnTermination | string | `nil` | Delete ENI on termination @schema type: [null, boolean] @schema | +| eni.nodeSpec.disablePrefixDelegation | bool | `false` | Disable prefix delegation for IP allocation | +| eni.nodeSpec.excludeInterfaceTags | list | `[]` | Exclude interface tags to use for IP allocation | +| eni.nodeSpec.firstInterfaceIndex | string | `nil` | First interface index to use for IP allocation @schema type: [null, integer] @schema | +| eni.nodeSpec.securityGroupTags | list | `[]` | Security group tags to use for IP allocation | +| eni.nodeSpec.securityGroups | list | `[]` | Security groups to use for IP allocation | +| eni.nodeSpec.subnetIDs | list | `[]` | Subnet IDs to use for IP allocation | +| eni.nodeSpec.subnetTags | list | `[]` | Subnet tags to use for IP allocation | +| eni.nodeSpec.usePrimaryAddress | bool | `false` | Use primary address for IP allocation | | eni.subnetIDsFilter | list | `[]` | Filter via subnet IDs which will dictate which subnets are going to be used to create new ENIs Important note: This requires that each instance has an ENI with a matching subnet attached when Cilium is deployed. If you only want to control subnets for ENIs attached by Cilium, use the CNI configuration file settings (cni.customConf) instead. | | eni.subnetTagsFilter | list | `[]` | Filter via tags (k=v) which will dictate which subnets are going to be used to create new ENIs Important note: This requires that each instance has an ENI with a matching subnet attached when Cilium is deployed. If you only want to control subnets for ENIs attached by Cilium, use the CNI configuration file settings (cni.customConf) instead. | -| eni.updateEC2AdapterLimitViaAPI | bool | `true` | Update ENI Adapter limits from the EC2 API | | envoy.affinity | object | `{"nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"cilium.io/no-schedule","operator":"NotIn","values":["true"]}]}]}},"podAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":[{"labelSelector":{"matchLabels":{"k8s-app":"cilium"}},"topologyKey":"kubernetes.io/hostname"}]},"podAntiAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":[{"labelSelector":{"matchLabels":{"k8s-app":"cilium-envoy"}},"topologyKey":"kubernetes.io/hostname"}]}}` | Affinity for cilium-envoy. | | envoy.annotations | object | `{}` | Annotations to be added to all top-level cilium-envoy objects (resources under templates/cilium-envoy) | | envoy.baseID | int | `0` | Set Envoy'--base-id' to use when allocating shared memory regions. Only needs to be changed if multiple Envoy instances will run on the same node and may have conflicts. Supported values: 0 - 4294967295. Defaults to '0' | | envoy.bootstrapConfigMap | string | `nil` | ADVANCED OPTION: Bring your own custom Envoy bootstrap ConfigMap. Provide the name of a ConfigMap with a `bootstrap-config.json` key. When specified, Envoy will use this ConfigMap instead of the default provided by the chart. WARNING: Use of this setting has the potential to prevent cilium-envoy from starting up, and can cause unexpected behavior (e.g. due to syntax error or semantically incorrect configuration). Before submitting an issue, please ensure you have disabled this feature, as support cannot be provided for custom Envoy bootstrap configs. @schema type: [null, string] @schema | +| envoy.clusterMaxConnections | int | `1024` | Maximum number of connections on Envoy clusters | +| envoy.clusterMaxRequests | int | `1024` | Maximum number of requests on Envoy clusters | | envoy.connectTimeoutSeconds | int | `2` | Time in seconds after which a TCP connection attempt times out | | envoy.debug.admin.enabled | bool | `false` | Enable admin interface for cilium-envoy. This is useful for debugging and should not be enabled in production. | | envoy.debug.admin.port | int | `9901` | Port number (bound to loopback interface). kubectl port-forward can be used to access the admin interface. | @@ -376,9 +468,12 @@ contributors across the globe, there is almost always someone available to help. | envoy.extraVolumes | list | `[]` | Additional envoy volumes. | | envoy.healthPort | int | `9878` | TCP port for the health API. | | envoy.httpRetryCount | int | `3` | Maximum number of retries for each HTTP request | +| envoy.httpUpstreamLingerTimeout | string | `nil` | Time in seconds to block Envoy worker thread while an upstream HTTP connection is closing. If set to 0, the connection is closed immediately (with TCP RST). If set to -1, the connection is closed asynchronously in the background. | | envoy.idleTimeoutDurationSeconds | int | `60` | Set Envoy upstream HTTP idle connection timeout seconds. Does not apply to connections with pending requests. Default 60s | -| envoy.image | object | `{"digest":"sha256:a04218c6879007d60d96339a441c448565b6f86650358652da27582e0efbf182","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium-envoy","tag":"v1.32.6-1746661844-0f602c28cb2aa57b29078195049fb257d5b5246c","useDigest":true}` | Envoy container image. | +| envoy.image | object | `{"digest":"sha256:ba0ab8adac082d50d525fd2c5ba096c8facea3a471561b7c61c7a5b9c2e0de0d","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium-envoy","tag":"v1.36.6-1776000132-2437d2edeaf4d9b56ef279bd0d71127440c067aa","useDigest":true}` | Envoy container image. | +| envoy.initContainers | list | `[]` | Init containers added to the cilium Envoy DaemonSet. | | envoy.initialFetchTimeoutSeconds | int | `30` | Time in seconds after which the initial fetch on an xDS stream is considered timed out | +| envoy.livenessProbe.enabled | bool | `true` | Enable liveness probe for cilium-envoy | | envoy.livenessProbe.failureThreshold | int | `10` | failure threshold of liveness probe | | envoy.livenessProbe.periodSeconds | int | `30` | interval between checks of the liveness probe | | envoy.log.accessLogBufferSize | int | `4096` | Size of the Envoy access log buffer created within the agent in bytes. Tune this value up if you encounter "Envoy: Discarded truncated access log message" errors. Large request/response header sizes (e.g. 16KiB) will require a larger buffer size. | @@ -388,6 +483,7 @@ contributors across the globe, there is almost always someone available to help. | envoy.log.path | string | `""` | Path to a separate Envoy log file, if any. Defaults to /dev/stdout. | | envoy.maxConcurrentRetries | int | `128` | Maximum number of concurrent retries on Envoy clusters | | envoy.maxConnectionDurationSeconds | int | `0` | Set Envoy HTTP option max_connection_duration seconds. Default 0 (disable) | +| envoy.maxGlobalDownstreamConnections | int | `50000` | Maximum number of global downstream connections | | envoy.maxRequestsPerConnection | int | `0` | ProxyMaxRequestsPerConnection specifies the max_requests_per_connection setting for Envoy | | envoy.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node selector for cilium-envoy. | | envoy.podAnnotations | object | `{}` | Annotations to be added to envoy pods | @@ -396,7 +492,7 @@ contributors across the globe, there is almost always someone available to help. | envoy.podSecurityContext.appArmorProfile | object | `{"type":"Unconfined"}` | AppArmorProfile options for the `cilium-agent` and init containers | | envoy.policyRestoreTimeoutDuration | string | `nil` | Max duration to wait for endpoint policies to be restored on restart. Default "3m". | | envoy.priorityClassName | string | `nil` | The priority class to use for cilium-envoy. | -| envoy.prometheus | object | `{"enabled":true,"port":"9964","serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","labels":{},"metricRelabelings":null,"relabelings":[{"replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}]}}` | Configure Cilium Envoy Prometheus options. Note that some of these apply to either cilium-agent or cilium-envoy. | +| envoy.prometheus | object | `{"enabled":true,"port":"9964","serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","labels":{},"metricRelabelings":null,"relabelings":[{"action":"replace","replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}],"scrapeTimeout":null}}` | Configure Cilium Envoy Prometheus options. Note that some of these apply to either cilium-agent or cilium-envoy. | | envoy.prometheus.enabled | bool | `true` | Enable prometheus metrics for cilium-envoy | | envoy.prometheus.port | string | `"9964"` | Serve prometheus metrics for cilium-envoy on the configured port | | envoy.prometheus.serviceMonitor.annotations | object | `{}` | Annotations to add to ServiceMonitor cilium-envoy | @@ -404,7 +500,8 @@ contributors across the globe, there is almost always someone available to help. | envoy.prometheus.serviceMonitor.interval | string | `"10s"` | Interval for scrape metrics. | | envoy.prometheus.serviceMonitor.labels | object | `{}` | Labels to add to ServiceMonitor cilium-envoy | | envoy.prometheus.serviceMonitor.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor cilium-envoy or for cilium-agent with Envoy configured. | -| envoy.prometheus.serviceMonitor.relabelings | list | `[{"replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}]` | Relabeling configs for the ServiceMonitor cilium-envoy or for cilium-agent with Envoy configured. | +| envoy.prometheus.serviceMonitor.relabelings | list | `[{"action":"replace","replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}]` | Relabeling configs for the ServiceMonitor cilium-envoy or for cilium-agent with Envoy configured. | +| envoy.prometheus.serviceMonitor.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | | envoy.readinessProbe.failureThreshold | int | `3` | failure threshold of readiness probe | | envoy.readinessProbe.periodSeconds | int | `30` | interval between checks of the readiness probe | | envoy.resources | object | `{}` | Envoy resource limits & requests ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | @@ -413,11 +510,14 @@ contributors across the globe, there is almost always someone available to help. | envoy.securityContext.capabilities.keepCapNetBindService | bool | `false` | Keep capability `NET_BIND_SERVICE` for Envoy process. | | envoy.securityContext.privileged | bool | `false` | Run the pod with elevated privileges | | envoy.securityContext.seLinuxOptions | object | `{"level":"s0","type":"spc_t"}` | SELinux options for the `cilium-envoy` container | +| envoy.startupProbe.enabled | bool | `true` | Enable startup probe for cilium-envoy | | envoy.startupProbe.failureThreshold | int | `105` | failure threshold of startup probe. 105 x 2s translates to the old behaviour of the readiness probe (120s delay + 30 x 3s) | | envoy.startupProbe.periodSeconds | int | `2` | interval between checks of the startup probe | +| envoy.streamIdleTimeoutDurationSeconds | int | `300` | Set Envoy the amount of time that the connection manager will allow a stream to exist with no upstream or downstream activity. default 5 minutes | | envoy.terminationGracePeriodSeconds | int | `1` | Configure termination grace period for cilium-envoy DaemonSet. | | envoy.tolerations | list | `[{"operator":"Exists"}]` | Node tolerations for envoy scheduling to nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | | envoy.updateStrategy | object | `{"rollingUpdate":{"maxUnavailable":2},"type":"RollingUpdate"}` | cilium-envoy update strategy ref: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/#updating-a-daemonset | +| envoy.useOriginalSourceAddress | bool | `true` | For cases when CiliumEnvoyConfig is not used directly (Ingress, Gateway), configures Cilium BPF Metadata listener filter to use the original source address when extracting the metadata for a request. | | envoy.xffNumTrustedHopsL7PolicyEgress | int | `0` | Number of trusted hops regarding the x-forwarded-for and related HTTP headers for the egress L7 policy enforcement Envoy listeners. | | envoy.xffNumTrustedHopsL7PolicyIngress | int | `0` | Number of trusted hops regarding the x-forwarded-for and related HTTP headers for the ingress L7 policy enforcement Envoy listeners. | | envoyConfig.enabled | bool | `false` | Enable CiliumEnvoyConfig CRD CiliumEnvoyConfig CRD can also be implicitly enabled by other options. | @@ -428,9 +528,6 @@ contributors across the globe, there is almost always someone available to help. | etcd.enabled | bool | `false` | Enable etcd mode for the agent. | | etcd.endpoints | list | `["https://CHANGE-ME:2379"]` | List of etcd endpoints | | etcd.ssl | bool | `false` | Enable use of TLS/SSL for connectivity to etcd. | -| externalIPs.enabled | bool | `false` | Enable ExternalIPs service support. | -| externalWorkloads | object | `{"enabled":false}` | Configure external workloads support | -| externalWorkloads.enabled | bool | `false` | Enable support for external workloads, such as VMs (false by default). | | extraArgs | list | `[]` | Additional agent container arguments. | | extraConfig | object | `{}` | extraConfig allows you to specify additional configuration parameters to be included in the cilium-config configmap. | | extraContainers | list | `[]` | Additional containers added to the cilium DaemonSet. | @@ -457,26 +554,25 @@ contributors across the globe, there is almost always someone available to help. | healthCheckICMPFailureThreshold | int | `3` | Number of ICMP requests sent for each health check before marking a node or endpoint unreachable. | | healthChecking | bool | `true` | Enable connectivity health checking. | | healthPort | int | `9879` | TCP port for the agent health API. This is not the port for cilium-health. | -| highScaleIPcache | object | `{"enabled":false}` | EnableHighScaleIPcache enables the special ipcache mode for high scale clusters. The ipcache content will be reduced to the strict minimum and traffic will be encapsulated to carry security identities. | -| highScaleIPcache.enabled | bool | `false` | Enable the high scale mode for the ipcache. | | hostFirewall | object | `{"enabled":false}` | Configure the host firewall. | | hostFirewall.enabled | bool | `false` | Enables the enforcement of host policies in the eBPF datapath. | -| hostPort.enabled | bool | `false` | Enable hostPort service support. | | hubble.annotations | object | `{}` | Annotations to be added to all top-level hubble objects (resources under templates/hubble) | | hubble.dropEventEmitter | object | `{"enabled":false,"interval":"2m","reasons":["auth_required","policy_denied"]}` | Emit v1.Events related to pods on detection of packet drops. This feature is alpha, please provide feedback at https://github.com/cilium/cilium/issues/33975. | | hubble.dropEventEmitter.interval | string | `"2m"` | - Minimum time between emitting same events. | | hubble.dropEventEmitter.reasons | list | `["auth_required","policy_denied"]` | - Drop reasons to emit events for. ref: https://docs.cilium.io/en/stable/_api/v1/flow/README/#dropreason | | hubble.enabled | bool | `true` | Enable Hubble (true by default). | -| hubble.export | object | `{"dynamic":{"config":{"configMapName":"cilium-flowlog-config","content":[{"excludeFilters":[],"fieldMask":[],"filePath":"/var/run/cilium/hubble/events.log","includeFilters":[],"name":"all"}],"createConfigMap":true},"enabled":false},"fileMaxBackups":5,"fileMaxSizeMb":10,"static":{"allowList":[],"denyList":[],"enabled":false,"fieldMask":[],"filePath":"/var/run/cilium/hubble/events.log"}}` | Hubble flows export. | -| hubble.export.dynamic | object | `{"config":{"configMapName":"cilium-flowlog-config","content":[{"excludeFilters":[],"fieldMask":[],"filePath":"/var/run/cilium/hubble/events.log","includeFilters":[],"name":"all"}],"createConfigMap":true},"enabled":false}` | - Dynamic exporters configuration. Dynamic exporters may be reconfigured without a need of agent restarts. | +| hubble.export | object | `{"dynamic":{"config":{"configMapName":"cilium-flowlog-config","content":[{"aggregationInterval":"0s","excludeFilters":[],"fieldAggregate":[],"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log","includeFilters":[],"name":"all"}],"createConfigMap":true},"enabled":false},"static":{"aggregationInterval":"0s","allowList":[],"denyList":[],"enabled":false,"fieldAggregate":[],"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log"}}` | Hubble flows export. | +| hubble.export.dynamic | object | `{"config":{"configMapName":"cilium-flowlog-config","content":[{"aggregationInterval":"0s","excludeFilters":[],"fieldAggregate":[],"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log","includeFilters":[],"name":"all"}],"createConfigMap":true},"enabled":false}` | - Dynamic exporters configuration. Dynamic exporters may be reconfigured without a need of agent restarts. | | hubble.export.dynamic.config.configMapName | string | `"cilium-flowlog-config"` | -- Name of configmap with configuration that may be altered to reconfigure exporters within a running agents. | -| hubble.export.dynamic.config.content | list | `[{"excludeFilters":[],"fieldMask":[],"filePath":"/var/run/cilium/hubble/events.log","includeFilters":[],"name":"all"}]` | -- Exporters configuration in YAML format. | +| hubble.export.dynamic.config.content | list | `[{"aggregationInterval":"0s","excludeFilters":[],"fieldAggregate":[],"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log","includeFilters":[],"name":"all"}]` | -- Exporters configuration in YAML format. | | hubble.export.dynamic.config.createConfigMap | bool | `true` | -- True if helm installer should create config map. Switch to false if you want to self maintain the file content. | -| hubble.export.fileMaxBackups | int | `5` | - Defines max number of backup/rotated files. | -| hubble.export.fileMaxSizeMb | int | `10` | - Defines max file size of output file before it gets rotated. | -| hubble.export.static | object | `{"allowList":[],"denyList":[],"enabled":false,"fieldMask":[],"filePath":"/var/run/cilium/hubble/events.log"}` | - Static exporter configuration. Static exporter is bound to agent lifecycle. | +| hubble.export.static | object | `{"aggregationInterval":"0s","allowList":[],"denyList":[],"enabled":false,"fieldAggregate":[],"fieldMask":[],"fileCompress":false,"fileMaxBackups":5,"fileMaxSizeMb":10,"filePath":"/var/run/cilium/hubble/events.log"}` | - Static exporter configuration. Static exporter is bound to agent lifecycle. | +| hubble.export.static.aggregationInterval | string | `"0s"` | - Defines the interval at which to aggregate before exporting Hubble flows. Aggregation feature is only enabled when fieldAggregate is specified and aggregationInterval > 0s. | +| hubble.export.static.fileCompress | bool | `false` | - Enable compression of rotated files. | +| hubble.export.static.fileMaxBackups | int | `5` | - Defines max number of backup/rotated files. | +| hubble.export.static.fileMaxSizeMb | int | `10` | - Defines max file size of output file before it gets rotated. | | hubble.listenAddress | string | `":4244"` | An additional address for Hubble to listen to. Set this field ":4244" if you are enabling Hubble Relay, as it assumes that Hubble is listening on port 4244. | -| hubble.metrics | object | `{"dashboards":{"annotations":{},"enabled":false,"label":"grafana_dashboard","labelValue":"1","namespace":null},"dynamic":{"config":{"configMapName":"cilium-dynamic-metrics-config","content":[],"createConfigMap":true},"enabled":false},"enableOpenMetrics":false,"enabled":null,"port":9965,"serviceAnnotations":{},"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","jobLabel":"","labels":{},"metricRelabelings":null,"relabelings":[{"replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}],"tlsConfig":{}},"tls":{"enabled":false,"server":{"cert":"","existingSecret":"","extraDnsNames":[],"extraIpAddresses":[],"key":"","mtls":{"enabled":false,"key":"ca.crt","name":null,"useSecret":false}}}}` | Hubble metrics configuration. See https://docs.cilium.io/en/stable/observability/metrics/#hubble-metrics for more comprehensive documentation about Hubble metrics. | +| hubble.metrics | object | `{"dashboards":{"annotations":{},"enabled":false,"label":"grafana_dashboard","labelValue":"1","namespace":null},"dynamic":{"config":{"configMapName":"cilium-dynamic-metrics-config","content":[],"createConfigMap":true},"enabled":false},"enableOpenMetrics":false,"enabled":null,"port":9965,"serviceAnnotations":{},"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","jobLabel":"","labels":{},"metricRelabelings":null,"relabelings":[{"action":"replace","replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}],"scrapeTimeout":null,"tlsConfig":{}},"tls":{"enabled":false,"server":{"cert":"","existingSecret":"","extraDnsNames":[],"extraIpAddresses":[],"key":"","mtls":{"enabled":false,"key":"ca.crt","name":null,"useSecret":false}}}}` | Hubble metrics configuration. See https://docs.cilium.io/en/stable/observability/metrics/#hubble-metrics for more comprehensive documentation about Hubble metrics. | | hubble.metrics.dashboards | object | `{"annotations":{},"enabled":false,"label":"grafana_dashboard","labelValue":"1","namespace":null}` | Grafana dashboards for hubble grafana can import dashboards based on the label and value ref: https://github.com/grafana/helm-charts/tree/main/charts/grafana#sidecar-for-dashboards | | hubble.metrics.dynamic.config.configMapName | string | `"cilium-dynamic-metrics-config"` | -- Name of configmap with configuration that may be altered to reconfigure metric handlers within a running agent. | | hubble.metrics.dynamic.config.content | list | `[]` | -- Exporters configuration in YAML format. | @@ -491,7 +587,8 @@ contributors across the globe, there is almost always someone available to help. | hubble.metrics.serviceMonitor.jobLabel | string | `""` | jobLabel to add for ServiceMonitor hubble | | hubble.metrics.serviceMonitor.labels | object | `{}` | Labels to add to ServiceMonitor hubble | | hubble.metrics.serviceMonitor.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor hubble | -| hubble.metrics.serviceMonitor.relabelings | list | `[{"replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}]` | Relabeling configs for the ServiceMonitor hubble | +| hubble.metrics.serviceMonitor.relabelings | list | `[{"action":"replace","replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}]` | Relabeling configs for the ServiceMonitor hubble | +| hubble.metrics.serviceMonitor.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | | hubble.metrics.tls.server.cert | string | `""` | base64 encoded PEM values for the Hubble metrics server certificate (deprecated). Use existingSecret instead. | | hubble.metrics.tls.server.existingSecret | string | `""` | Name of the Secret containing the certificate and key for the Hubble metrics server. If specified, cert and key are ignored. | | hubble.metrics.tls.server.extraDnsNames | list | `[]` | Extra DNS names added to certificate when it's auto generated | @@ -500,6 +597,7 @@ contributors across the globe, there is almost always someone available to help. | hubble.metrics.tls.server.mtls | object | `{"enabled":false,"key":"ca.crt","name":null,"useSecret":false}` | Configure mTLS for the Hubble metrics server. | | hubble.metrics.tls.server.mtls.key | string | `"ca.crt"` | Entry of the ConfigMap containing the CA. | | hubble.metrics.tls.server.mtls.name | string | `nil` | Name of the ConfigMap containing the CA to validate client certificates against. If mTLS is enabled and this is unspecified, it will default to the same CA used for Hubble metrics server certificates. | +| hubble.networkPolicyCorrelation | object | `{"enabled":true}` | Enables network policy correlation of Hubble flows, i.e. populating `egress_allowed_by`, `ingress_denied_by` fields with policy information. | | hubble.peerService.clusterDomain | string | `"cluster.local"` | The cluster domain to use to query the Hubble Peer service. It should be the local cluster. | | hubble.peerService.targetPort | int | `4244` | Target Port for the Peer service, must match the hubble.listenAddress' port. | | hubble.preferIpv6 | bool | `false` | Whether Hubble should prefer to announce IPv6 or IPv4 addresses if both are available. | @@ -508,42 +606,48 @@ contributors across the globe, there is almost always someone available to help. | hubble.redact.http.headers.deny | list | `[]` | List of HTTP headers to deny: matching headers will be redacted. Note: `allow` and `deny` lists cannot be used both at the same time, only one can be present. Example: redact: enabled: true http: headers: deny: - Authorization - Proxy-Authorization You can specify the options from the helm CLI: --set hubble.redact.enabled="true" --set hubble.redact.http.headers.deny="Authorization,Proxy-Authorization" | | hubble.redact.http.urlQuery | bool | `false` | Enables redacting URL query (GET) parameters. Example: redact: enabled: true http: urlQuery: true You can specify the options from the helm CLI: --set hubble.redact.enabled="true" --set hubble.redact.http.urlQuery="true" | | hubble.redact.http.userInfo | bool | `true` | Enables redacting user info, e.g., password when basic auth is used. Example: redact: enabled: true http: userInfo: true You can specify the options from the helm CLI: --set hubble.redact.enabled="true" --set hubble.redact.http.userInfo="true" | -| hubble.redact.kafka.apiKey | bool | `true` | Enables redacting Kafka's API key. Example: redact: enabled: true kafka: apiKey: true You can specify the options from the helm CLI: --set hubble.redact.enabled="true" --set hubble.redact.kafka.apiKey="true" | +| hubble.redact.kafka.apiKey | bool | `true` | Enables redacting Kafka's API key (deprecated, will be removed in v1.19). Example: redact: enabled: true kafka: apiKey: true You can specify the options from the helm CLI: --set hubble.redact.enabled="true" --set hubble.redact.kafka.apiKey="true" | | hubble.relay.affinity | object | `{"podAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":[{"labelSelector":{"matchLabels":{"k8s-app":"cilium"}},"topologyKey":"kubernetes.io/hostname"}]}}` | Affinity for hubble-replay | | hubble.relay.annotations | object | `{}` | Annotations to be added to all top-level hubble-relay objects (resources under templates/hubble-relay) | -| hubble.relay.dialTimeout | string | `nil` | Dial timeout to connect to the local hubble instance to receive peer information (e.g. "30s"). This option has been deprecated and is a no-op. | | hubble.relay.enabled | bool | `false` | Enable Hubble Relay (requires hubble.enabled=true) | | hubble.relay.extraEnv | list | `[]` | Additional hubble-relay environment variables. | | hubble.relay.extraVolumeMounts | list | `[]` | Additional hubble-relay volumeMounts. | | hubble.relay.extraVolumes | list | `[]` | Additional hubble-relay volumes. | | hubble.relay.gops.enabled | bool | `true` | Enable gops for hubble-relay | | hubble.relay.gops.port | int | `9893` | Configure gops listen port for hubble-relay | -| hubble.relay.image | object | `{"digest":"sha256:c16de12a64b8b56de62b15c1652d036253b40cd7fa643d7e1a404dc71dc66441","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/hubble-relay","tag":"v1.17.4","useDigest":true}` | Hubble-relay container image. | +| hubble.relay.image | object | `{"digest":"sha256:5ee21d57b6ef2aa6db67e603a735fdceb162454b352b7335b651456e308f681b","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/hubble-relay","tag":"v1.19.3","useDigest":true}` | Hubble-relay container image. | | hubble.relay.listenHost | string | `""` | Host to listen to. Specify an empty string to bind to all the interfaces. | | hubble.relay.listenPort | string | `"4245"` | Port to listen to. | +| hubble.relay.logOptions | object | `{"format":null,"level":null}` | Logging configuration for hubble-relay. | +| hubble.relay.logOptions.format | string | text-ts | Log format for hubble-relay. Valid values are: text, text-ts, json, json-ts. | +| hubble.relay.logOptions.level | string | info | Log level for hubble-relay. Valid values are: debug, info, warn, error. | | hubble.relay.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for pod assignment ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector | | hubble.relay.podAnnotations | object | `{}` | Annotations to be added to hubble-relay pods | | hubble.relay.podDisruptionBudget.enabled | bool | `false` | enable PodDisruptionBudget ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ | | hubble.relay.podDisruptionBudget.maxUnavailable | int | `1` | Maximum number/percentage of pods that may be made unavailable | | hubble.relay.podDisruptionBudget.minAvailable | string | `nil` | Minimum number/percentage of pods that should remain scheduled. When it's set, maxUnavailable must be disabled by `maxUnavailable: null` | +| hubble.relay.podDisruptionBudget.unhealthyPodEvictionPolicy | string | `nil` | How are unhealthy, but running, pods counted for eviction | | hubble.relay.podLabels | object | `{}` | Labels to be added to hubble-relay pods | -| hubble.relay.podSecurityContext | object | `{"fsGroup":65532}` | hubble-relay pod security context | +| hubble.relay.podSecurityContext | object | `{"fsGroup":65532,"seccompProfile":{"type":"RuntimeDefault"}}` | hubble-relay pod security context | | hubble.relay.pprof.address | string | `"localhost"` | Configure pprof listen address for hubble-relay | +| hubble.relay.pprof.blockProfileRate | int | `0` | Enable goroutine blocking profiling for hubble-relay and set the rate of sampled events in nanoseconds (set to 1 to sample all events [warning: performance overhead]) | | hubble.relay.pprof.enabled | bool | `false` | Enable pprof for hubble-relay | +| hubble.relay.pprof.mutexProfileFraction | int | `0` | Enable mutex contention profiling for hubble-relay and set the fraction of sampled events (set to 1 to sample all events) | | hubble.relay.pprof.port | int | `6062` | Configure pprof listen port for hubble-relay | | hubble.relay.priorityClassName | string | `""` | The priority class to use for hubble-relay | -| hubble.relay.prometheus | object | `{"enabled":false,"port":9966,"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","labels":{},"metricRelabelings":null,"relabelings":null}}` | Enable prometheus metrics for hubble-relay on the configured port at /metrics | +| hubble.relay.prometheus | object | `{"enabled":false,"port":9966,"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","labels":{},"metricRelabelings":null,"relabelings":null,"scrapeTimeout":null}}` | Enable prometheus metrics for hubble-relay on the configured port at /metrics | | hubble.relay.prometheus.serviceMonitor.annotations | object | `{}` | Annotations to add to ServiceMonitor hubble-relay | | hubble.relay.prometheus.serviceMonitor.enabled | bool | `false` | Enable service monitors. This requires the prometheus CRDs to be available (see https://github.com/prometheus-operator/prometheus-operator/blob/main/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml) | | hubble.relay.prometheus.serviceMonitor.interval | string | `"10s"` | Interval for scrape metrics. | | hubble.relay.prometheus.serviceMonitor.labels | object | `{}` | Labels to add to ServiceMonitor hubble-relay | | hubble.relay.prometheus.serviceMonitor.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor hubble-relay | | hubble.relay.prometheus.serviceMonitor.relabelings | string | `nil` | Relabeling configs for the ServiceMonitor hubble-relay | +| hubble.relay.prometheus.serviceMonitor.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | | hubble.relay.replicas | int | `1` | Number of replicas run for the hubble-relay deployment. | | hubble.relay.resources | object | `{}` | Specifies the resources for the hubble-relay pods | | hubble.relay.retryTimeout | string | `nil` | Backoff duration to retry connecting to the local hubble instance in case of failure (e.g. "30s"). | | hubble.relay.rollOutPods | bool | `false` | Roll out Hubble Relay pods automatically when configmap is updated. | -| hubble.relay.securityContext | object | `{"capabilities":{"drop":["ALL"]},"runAsGroup":65532,"runAsNonRoot":true,"runAsUser":65532}` | hubble-relay container security context | +| hubble.relay.securityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"runAsGroup":65532,"runAsNonRoot":true,"runAsUser":65532,"seccompProfile":{"type":"RuntimeDefault"}}` | hubble-relay container security context | | hubble.relay.service | object | `{"nodePort":31234,"type":"ClusterIP"}` | hubble-relay service configuration. | | hubble.relay.service.nodePort | int | `31234` | - The port to use when the service type is set to NodePort. | | hubble.relay.service.type | string | `"ClusterIP"` | - The type of service used for Hubble Relay access, either ClusterIP, NodePort or LoadBalancer. | @@ -585,19 +689,19 @@ contributors across the globe, there is almost always someone available to help. | hubble.ui.backend.extraEnv | list | `[]` | Additional hubble-ui backend environment variables. | | hubble.ui.backend.extraVolumeMounts | list | `[]` | Additional hubble-ui backend volumeMounts. | | hubble.ui.backend.extraVolumes | list | `[]` | Additional hubble-ui backend volumes. | -| hubble.ui.backend.image | object | `{"digest":"sha256:a034b7e98e6ea796ed26df8f4e71f83fc16465a19d166eff67a03b822c0bfa15","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/hubble-ui-backend","tag":"v0.13.2","useDigest":true}` | Hubble-ui backend image. | +| hubble.ui.backend.image | object | `{"digest":"sha256:db1454e45dc39ca41fbf7cad31eec95d99e5b9949c39daaad0fa81ef29d56953","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/hubble-ui-backend","tag":"v0.13.3","useDigest":true}` | Hubble-ui backend image. | | hubble.ui.backend.livenessProbe.enabled | bool | `false` | Enable liveness probe for Hubble-ui backend (requires Hubble-ui 0.12+) | | hubble.ui.backend.readinessProbe.enabled | bool | `false` | Enable readiness probe for Hubble-ui backend (requires Hubble-ui 0.12+) | | hubble.ui.backend.resources | object | `{}` | Resource requests and limits for the 'backend' container of the 'hubble-ui' deployment. | -| hubble.ui.backend.securityContext | object | `{}` | Hubble-ui backend security context. | +| hubble.ui.backend.securityContext | object | `{"allowPrivilegeEscalation":false}` | Hubble-ui backend security context. | | hubble.ui.baseUrl | string | `"/"` | Defines base url prefix for all hubble-ui http requests. It needs to be changed in case if ingress for hubble-ui is configured under some sub-path. Trailing `/` is required for custom path, ex. `/service-map/` | | hubble.ui.enabled | bool | `false` | Whether to enable the Hubble UI. | | hubble.ui.frontend.extraEnv | list | `[]` | Additional hubble-ui frontend environment variables. | | hubble.ui.frontend.extraVolumeMounts | list | `[]` | Additional hubble-ui frontend volumeMounts. | | hubble.ui.frontend.extraVolumes | list | `[]` | Additional hubble-ui frontend volumes. | -| hubble.ui.frontend.image | object | `{"digest":"sha256:9e37c1296b802830834cc87342a9182ccbb71ffebb711971e849221bd9d59392","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/hubble-ui","tag":"v0.13.2","useDigest":true}` | Hubble-ui frontend image. | +| hubble.ui.frontend.image | object | `{"digest":"sha256:661d5de7050182d495c6497ff0b007a7a1e379648e60830dd68c4d78ae21761d","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/hubble-ui","tag":"v0.13.3","useDigest":true}` | Hubble-ui frontend image. | | hubble.ui.frontend.resources | object | `{}` | Resource requests and limits for the 'frontend' container of the 'hubble-ui' deployment. | -| hubble.ui.frontend.securityContext | object | `{}` | Hubble-ui frontend security context. | +| hubble.ui.frontend.securityContext | object | `{"allowPrivilegeEscalation":false}` | Hubble-ui frontend security context. | | hubble.ui.frontend.server.ipv6 | object | `{"enabled":true}` | Controls server listener for ipv6 | | hubble.ui.ingress | object | `{"annotations":{},"className":"","enabled":false,"hosts":["chart-example.local"],"labels":{},"tls":[]}` | hubble-ui ingress configuration. | | hubble.ui.labels | object | `{}` | Additional labels to be added to 'hubble-ui' deployment object | @@ -606,13 +710,15 @@ contributors across the globe, there is almost always someone available to help. | hubble.ui.podDisruptionBudget.enabled | bool | `false` | enable PodDisruptionBudget ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ | | hubble.ui.podDisruptionBudget.maxUnavailable | int | `1` | Maximum number/percentage of pods that may be made unavailable | | hubble.ui.podDisruptionBudget.minAvailable | string | `nil` | Minimum number/percentage of pods that should remain scheduled. When it's set, maxUnavailable must be disabled by `maxUnavailable: null` | +| hubble.ui.podDisruptionBudget.unhealthyPodEvictionPolicy | string | `nil` | How are unhealthy, but running, pods counted for eviction | | hubble.ui.podLabels | object | `{}` | Labels to be added to hubble-ui pods | | hubble.ui.priorityClassName | string | `""` | The priority class to use for hubble-ui | | hubble.ui.replicas | int | `1` | The number of replicas of Hubble UI to deploy. | | hubble.ui.rollOutPods | bool | `false` | Roll out Hubble-ui pods automatically when configmap is updated. | | hubble.ui.securityContext | object | `{"fsGroup":1001,"runAsGroup":1001,"runAsUser":1001}` | Security context to be added to Hubble UI pods | -| hubble.ui.service | object | `{"annotations":{},"nodePort":31235,"type":"ClusterIP"}` | hubble-ui service configuration. | +| hubble.ui.service | object | `{"annotations":{},"labels":{},"nodePort":31235,"type":"ClusterIP"}` | hubble-ui service configuration. | | hubble.ui.service.annotations | object | `{}` | Annotations to be added for the Hubble UI service | +| hubble.ui.service.labels | object | `{}` | Labels to be added for the Hubble UI service | | hubble.ui.service.nodePort | int | `31235` | - The port to use when the service type is set to NodePort. | | hubble.ui.service.type | string | `"ClusterIP"` | - The type of service used for Hubble UI access, either ClusterIP or NodePort. | | hubble.ui.standalone.enabled | bool | `false` | When true, it will allow installing the Hubble UI only, without checking dependencies. It is useful if a cluster already has cilium and Hubble relay installed and you just want Hubble UI to be deployed. When installed via helm, installing UI should be done via `helm upgrade` and when installed via the cilium cli, then `cilium hubble enable --ui` | @@ -620,12 +726,14 @@ contributors across the globe, there is almost always someone available to help. | hubble.ui.tls.client.cert | string | `""` | base64 encoded PEM values for the Hubble UI client certificate (deprecated). Use existingSecret instead. | | hubble.ui.tls.client.existingSecret | string | `""` | Name of the Secret containing the client certificate and key for Hubble UI If specified, cert and key are ignored. | | hubble.ui.tls.client.key | string | `""` | base64 encoded PEM values for the Hubble UI client key (deprecated). Use existingSecret instead. | +| hubble.ui.tmpVolume | object | `{}` | Configure temporary volume for hubble-ui | | hubble.ui.tolerations | list | `[]` | Node tolerations for pod assignment on nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | | hubble.ui.topologySpreadConstraints | list | `[]` | Pod topology spread constraints for hubble-ui | | hubble.ui.updateStrategy | object | `{"rollingUpdate":{"maxUnavailable":1},"type":"RollingUpdate"}` | hubble-ui update strategy. | | identityAllocationMode | string | `"crd"` | Method to use for identity allocation (`crd`, `kvstore` or `doublewrite-readkvstore` / `doublewrite-readcrd` for migrating between identity backends). | | identityChangeGracePeriod | string | `"5s"` | Time to wait before using new identity on endpoint identity change. | -| image | object | `{"digest":"sha256:24a73fe795351cf3279ac8e84918633000b52a9654ff73a6b0d7223bcff4a67a","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.17.4","useDigest":true}` | Agent container image. | +| identityManagementMode | string | `"agent"` | Control whether CiliumIdentities are created by the agent ("agent"), the operator ("operator") or both ("both"). "Both" should be used only to migrate between "agent" and "operator". Operator-managed identities is a beta feature. | +| image | object | `{"digest":"sha256:2e61680593cddca8b6c055f6d4c849d87a26a1c91c7e3b8b56c7fb76ab7b7b10","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.19.3","useDigest":true}` | Agent container image. | | imagePullSecrets | list | `[]` | Configure image pull secrets for pulling container images | | ingressController.default | bool | `false` | Set cilium ingress controller to be the default ingress controller This will let cilium ingress controller route entries without ingress class set | | ingressController.defaultSecretName | string | `nil` | Default secret name for ingresses without .spec.tls[].secretName set. | @@ -660,6 +768,11 @@ contributors across the globe, there is almost always someone available to help. | ipam.installUplinkRoutesForDelegatedIPAM | bool | `false` | Install ingress/egress routes through uplink on host for Pods when working with delegated IPAM plugin. | | ipam.mode | string | `"cluster-pool"` | Configure IP Address Management mode. ref: https://docs.cilium.io/en/stable/network/concepts/ipam/ | | ipam.multiPoolPreAllocation | string | `""` | Pre-allocation settings for IPAM in Multi-Pool mode | +| ipam.nodeSpec | object | `{"ipamMaxAllocate":null,"ipamMinAllocate":null,"ipamPreAllocate":null,"ipamStaticIPTags":[]}` | NodeSpec configuration for the IPAM | +| ipam.nodeSpec.ipamMaxAllocate | string | `nil` | IPAM max allocate @schema type: [null, integer] @schema | +| ipam.nodeSpec.ipamMinAllocate | string | `nil` | IPAM min allocate @schema type: [null, integer] @schema | +| ipam.nodeSpec.ipamPreAllocate | string | `nil` | IPAM pre allocate @schema type: [null, integer] @schema | +| ipam.nodeSpec.ipamStaticIPTags | list | `[]` | IPAM static IP tags (currently only works with AWS and Azure) | | ipam.operator.autoCreateCiliumPodIPPools | object | `{}` | IP pools to auto-create in multi-pool IPAM mode. | | ipam.operator.clusterPoolIPv4MaskSize | int | `24` | IPv4 CIDR mask size to delegate to individual nodes for IPAM. | | ipam.operator.clusterPoolIPv4PodCIDRList | list | `["10.0.0.0/8"]` | IPv4 CIDR list range to delegate to individual nodes for IPAM. | @@ -675,6 +788,10 @@ contributors across the globe, there is almost always someone available to help. | k8s | object | `{"requireIPv4PodCIDR":false,"requireIPv6PodCIDR":false}` | Configure Kubernetes specific configuration | | k8s.requireIPv4PodCIDR | bool | `false` | requireIPv4PodCIDR enables waiting for Kubernetes to provide the PodCIDR range via the Kubernetes node resource | | k8s.requireIPv6PodCIDR | bool | `false` | requireIPv6PodCIDR enables waiting for Kubernetes to provide the PodCIDR range via the Kubernetes node resource | +| k8sClientExponentialBackoff | object | `{"backoffBaseSeconds":1,"backoffMaxDurationSeconds":120,"enabled":true}` | Configure exponential backoff for client-go in Cilium agent. | +| k8sClientExponentialBackoff.backoffBaseSeconds | int | `1` | Configure base (in seconds) for exponential backoff. | +| k8sClientExponentialBackoff.backoffMaxDurationSeconds | int | `120` | Configure maximum duration (in seconds) for exponential backoff. | +| k8sClientExponentialBackoff.enabled | bool | `true` | Enable exponential backoff for client-go in Cilium agent. | | k8sClientRateLimit | object | `{"burst":null,"operator":{"burst":null,"qps":null},"qps":null}` | Configure the client side rate limit for the agent If the amount of requests to the Kubernetes API server exceeds the configured rate limit, the agent will start to throttle requests by delaying them until there is budget or the request times out. | | k8sClientRateLimit.burst | int | 20 | The burst request rate in requests per second. The rate limiter will allow short bursts with a higher rate. | | k8sClientRateLimit.operator | object | `{"burst":null,"qps":null}` | Configure the client side rate limit for the Cilium Operator | @@ -683,15 +800,18 @@ contributors across the globe, there is almost always someone available to help. | k8sClientRateLimit.qps | int | 10 | The sustained request rate in requests per second. | | k8sNetworkPolicy.enabled | bool | `true` | Enable support for K8s NetworkPolicy | | k8sServiceHost | string | `""` | Kubernetes service host - use "auto" for automatic lookup from the cluster-info ConfigMap | +| k8sServiceHostRef | object | `{"key":null,"name":null}` | Configure the Kubernetes service endpoint dynamically using a ConfigMap. Mutually exclusive with `k8sServiceHost`. | +| k8sServiceHostRef.key | string | `nil` | Key in the ConfigMap containing the Kubernetes service endpoint | +| k8sServiceHostRef.name | string | `nil` | name of the ConfigMap containing the Kubernetes service endpoint | | k8sServiceLookupConfigMapName | string | `""` | When `k8sServiceHost=auto`, allows to customize the configMap name. It defaults to `cluster-info`. | | k8sServiceLookupNamespace | string | `""` | When `k8sServiceHost=auto`, allows to customize the namespace that contains `k8sServiceLookupConfigMapName`. It defaults to `kube-public`. | | k8sServicePort | string | `""` | Kubernetes service port | | keepDeprecatedLabels | bool | `false` | Keep the deprecated selector labels when deploying Cilium DaemonSet. | | keepDeprecatedProbes | bool | `false` | Keep the deprecated probes when deploying Cilium DaemonSet | | kubeConfigPath | string | `"~/.kube/config"` | Kubernetes config path | +| kubeProxyReplacement | string | `"false"` | Configure the kube-proxy replacement in Cilium BPF datapath Valid options are "true" or "false". ref: https://docs.cilium.io/en/stable/network/kubernetes/kubeproxy-free/ @schema@ type: [string, boolean] @schema@ | | kubeProxyReplacementHealthzBindAddr | string | `""` | healthz server bind address for the kube-proxy replacement. To enable set the value to '0.0.0.0:10256' for all ipv4 addresses and this '[::]:10256' for all ipv6 addresses. By default it is disabled. | -| l2NeighDiscovery.enabled | bool | `true` | Enable L2 neighbor discovery in the agent | -| l2NeighDiscovery.refreshPeriod | string | `"30s"` | Override the agent's default neighbor resolution refresh period. | +| l2NeighDiscovery.enabled | bool | `false` | Enable L2 neighbor discovery in the agent | | l2announcements | object | `{"enabled":false}` | Configure L2 announcements | | l2announcements.enabled | bool | `false` | Enable L2 announcements | | l2podAnnouncements | object | `{"enabled":false,"interface":"eth0"}` | Configure L2 pod announcements | @@ -701,32 +821,33 @@ contributors across the globe, there is almost always someone available to help. | livenessProbe.failureThreshold | int | `10` | failure threshold of liveness probe | | livenessProbe.periodSeconds | int | `30` | interval between checks of the liveness probe | | livenessProbe.requireK8sConnectivity | bool | `false` | whether to require k8s connectivity as part of the check. | -| loadBalancer | object | `{"acceleration":"disabled","experimental":false,"l7":{"algorithm":"round_robin","backend":"disabled","ports":[]}}` | Configure service load balancing | +| loadBalancer | object | `{"acceleration":"disabled","l7":{"algorithm":"round_robin","backend":"disabled","ports":[]},"serviceTopology":false}` | Configure service load balancing | | loadBalancer.acceleration | string | `"disabled"` | acceleration is the option to accelerate service handling via XDP Applicable values can be: disabled (do not use XDP), native (XDP BPF program is run directly out of the networking driver's early receive path), or best-effort (use native mode XDP acceleration on devices that support it). | -| loadBalancer.experimental | bool | `false` | experimental enables support for the experimental load-balancing control-plane. | | loadBalancer.l7 | object | `{"algorithm":"round_robin","backend":"disabled","ports":[]}` | L7 LoadBalancer | | loadBalancer.l7.algorithm | string | `"round_robin"` | Default LB algorithm The default LB algorithm to be used for services, which can be overridden by the service annotation (e.g. service.cilium.io/lb-l7-algorithm) Applicable values: round_robin, least_request, random | | loadBalancer.l7.backend | string | `"disabled"` | Enable L7 service load balancing via envoy proxy. The request to a k8s service, which has specific annotation e.g. service.cilium.io/lb-l7, will be forwarded to the local backend proxy to be load balanced to the service endpoints. Please refer to docs for supported annotations for more configuration. Applicable values: - envoy: Enable L7 load balancing via envoy proxy. This will automatically set enable-envoy-config as well. - disabled: Disable L7 load balancing by way of service annotation. | | loadBalancer.l7.ports | list | `[]` | List of ports from service to be automatically redirected to above backend. Any service exposing one of these ports will be automatically redirected. Fine-grained control can be achieved by using the service annotation. | -| localRedirectPolicy | bool | `false` | Enable Local Redirect Policy. | +| loadBalancer.serviceTopology | bool | `false` | serviceTopology enables K8s Topology Aware Hints -based service endpoints filtering | +| localRedirectPolicies.addressMatcherCIDRs | string | `nil` | Limit the allowed addresses in Address Matcher rule of Local Redirect Policies to the given CIDRs. @schema@ type: [null, array] @schema@ | +| localRedirectPolicies.enabled | bool | `false` | Enable local redirect policies. | +| localRedirectPolicy | bool | `false` | Enable Local Redirect Policy (deprecated, please use 'localRedirectPolicies.enabled' instead) | | logSystemLoad | bool | `false` | Enables periodic logging of system load | | maglev | object | `{}` | Configure maglev consistent hashing | | monitor | object | `{"enabled":false}` | cilium-monitor sidecar. | | monitor.enabled | bool | `false` | Enable the cilium-monitor sidecar. | -| name | string | `"cilium"` | Agent container name. | -| namespaceOverride | string | `""` | namespaceOverride allows to override the destination namespace for Cilium resources. This property allows to use Cilium as part of an Umbrella Chart with different targets. | +| name | string | `"cilium"` | Agent daemonset name. | +| namespaceOverride | string | `""` | namespaceOverride allows to override the destination namespace for Cilium resources. | | nat.mapStatsEntries | int | `32` | Number of the top-k SNAT map connections to track in Cilium statedb. | | nat.mapStatsInterval | string | `"30s"` | Interval between how often SNAT map is counted for stats. | | nat46x64Gateway | object | `{"enabled":false}` | Configure standalone NAT46/NAT64 gateway | -| nat46x64Gateway.enabled | bool | `false` | Enable RFC8215-prefixed translation | +| nat46x64Gateway.enabled | bool | `false` | Enable RFC6052-prefixed translation | | nodeIPAM.enabled | bool | `false` | Configure Node IPAM ref: https://docs.cilium.io/en/stable/network/node-ipam/ | -| nodePort | object | `{"addresses":null,"autoProtectPortRange":true,"bindProtection":true,"enableHealthCheck":true,"enableHealthCheckLoadBalancerIP":false,"enabled":false}` | Configure N-S k8s service loadbalancing | +| nodePort | object | `{"addresses":null,"autoProtectPortRange":true,"bindProtection":true,"enableHealthCheck":true,"enableHealthCheckLoadBalancerIP":false}` | Configure N-S k8s service loadbalancing | | nodePort.addresses | string | `nil` | List of CIDRs for choosing which IP addresses assigned to native devices are used for NodePort load-balancing. By default this is empty and the first suitable, preferably private, IPv4 and IPv6 address assigned to each device is used. Example: addresses: ["192.168.1.0/24", "2001::/64"] | | nodePort.autoProtectPortRange | bool | `true` | Append NodePort range to ip_local_reserved_ports if clash with ephemeral ports is detected. | | nodePort.bindProtection | bool | `true` | Set to true to prevent applications binding to service ports. | | nodePort.enableHealthCheck | bool | `true` | Enable healthcheck nodePort server for NodePort services | | nodePort.enableHealthCheckLoadBalancerIP | bool | `false` | Enable access of the healthcheck nodePort on the LoadBalancerIP. Needs EnableHealthCheck to be enabled | -| nodePort.enabled | bool | `false` | Enable the Cilium NodePort service implementation. | | nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node selector for cilium-agent. | | nodeSelectorLabels | bool | `false` | Enable/Disable use of node label based identity | | nodeinit.affinity | object | `{}` | Affinity for cilium-nodeinit | @@ -736,7 +857,7 @@ contributors across the globe, there is almost always someone available to help. | nodeinit.extraEnv | list | `[]` | Additional nodeinit environment variables. | | nodeinit.extraVolumeMounts | list | `[]` | Additional nodeinit volumeMounts. | | nodeinit.extraVolumes | list | `[]` | Additional nodeinit volumes. | -| nodeinit.image | object | `{"digest":"sha256:8d7b41c4ca45860254b3c19e20210462ef89479bb6331d6760c4e609d651b29c","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/startup-script","tag":"c54c7edeab7fde4da68e59acd319ab24af242c3f","useDigest":true}` | node-init image. | +| nodeinit.image | object | `{"digest":"sha256:50b9cf9c280096b59b80d2fc8ee6638facef79ac18998a22f0cbc40d5d28c16f","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/startup-script","tag":"1763560095-8f36c34","useDigest":true}` | node-init image. | | nodeinit.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for nodeinit pod assignment ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector | | nodeinit.podAnnotations | object | `{}` | Annotations to be added to node-init pods. | | nodeinit.podLabels | object | `{}` | Labels to be added to node-init pods. | @@ -745,10 +866,11 @@ contributors across the globe, there is almost always someone available to help. | nodeinit.prestop | object | `{"postScript":"","preScript":""}` | prestop offers way to customize prestop nodeinit script (pre and post position) | | nodeinit.priorityClassName | string | `""` | The priority class to use for the nodeinit pod. | | nodeinit.resources | object | `{"requests":{"cpu":"100m","memory":"100Mi"}}` | nodeinit resource limits & requests ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | -| nodeinit.securityContext | object | `{"capabilities":{"add":["SYS_MODULE","NET_ADMIN","SYS_ADMIN","SYS_CHROOT","SYS_PTRACE"]},"privileged":false,"seLinuxOptions":{"level":"s0","type":"spc_t"}}` | Security context to be added to nodeinit pods. | +| nodeinit.securityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"add":["SYS_MODULE","NET_ADMIN","SYS_ADMIN","SYS_CHROOT","SYS_PTRACE"]},"privileged":false,"seLinuxOptions":{"level":"s0","type":"spc_t"}}` | Security context to be added to nodeinit pods. | | nodeinit.startup | object | `{"postScript":"","preScript":""}` | startup offers way to customize startup nodeinit script (pre and post position) | | nodeinit.tolerations | list | `[{"operator":"Exists"}]` | Node tolerations for nodeinit scheduling to nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | | nodeinit.updateStrategy | object | `{"type":"RollingUpdate"}` | node-init update strategy | +| nodeinit.waitForCloudInit | bool | `false` | wait for Cloud init to finish on the host and assume the node has cloud init installed | | operator.affinity | object | `{"podAntiAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":[{"labelSelector":{"matchLabels":{"io.cilium/app":"operator"}},"topologyKey":"kubernetes.io/hostname"}]}}` | Affinity for cilium-operator | | operator.annotations | object | `{}` | Annotations to be added to all top-level cilium-operator objects (resources under templates/cilium-operator) | | operator.dashboards | object | `{"annotations":{},"enabled":false,"label":"grafana_dashboard","labelValue":"1","namespace":null}` | Grafana dashboards for cilium-operator grafana can import dashboards based on the label and value ref: https://github.com/grafana/helm-charts/tree/main/charts/grafana#sidecar-for-dashboards | @@ -763,20 +885,23 @@ contributors across the globe, there is almost always someone available to help. | operator.hostNetwork | bool | `true` | HostNetwork setting | | operator.identityGCInterval | string | `"15m0s"` | Interval for identity garbage collection. | | operator.identityHeartbeatTimeout | string | `"30m0s"` | Timeout for identity heartbeats. | -| operator.image | object | `{"alibabacloudDigest":"sha256:eaa7b18b7cda65af1d454d54224d175fdb69a35199fa949ae7dfda2789c18dd6","awsDigest":"sha256:3c31583e57648470fbf6646ac67122ac5896ce5f979ab824d9a38cfc7eafc753","azureDigest":"sha256:d8d95049bfeab47cb1a3f995164e1ca2cdec8e6c7036c29799647999cdae07b1","genericDigest":"sha256:a3906412f477b09904f46aac1bed28eb522bef7899ed7dd81c15f78b7aa1b9b5","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/operator","suffix":"","tag":"v1.17.4","useDigest":true}` | cilium-operator image. | +| operator.image | object | `{"alibabacloudDigest":"sha256:176321a65123373ff8c7823b25183102cbad98375e8d6c80b96d68b6e8491103","awsDigest":"sha256:a53dcbfb77282bf2ddd3abbe60f6d49762e7c1389a36cb35b71d504644a56640","azureDigest":"sha256:699c1571a3df1a98882ee13610d47cffb7b34ee7e8d276096db798a5f6c7e4cb","genericDigest":"sha256:205b09b0ed6accbf9fe688d312a9f0fcfc6a316fc081c23fbffb472af5dd62cd","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/operator","suffix":"","tag":"v1.19.3","useDigest":true}` | cilium-operator image. | | operator.nodeGCInterval | string | `"5m0s"` | Interval for cilium node garbage collection. | | operator.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for cilium-operator pod assignment ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector | | operator.podAnnotations | object | `{}` | Annotations to be added to cilium-operator pods | | operator.podDisruptionBudget.enabled | bool | `false` | enable PodDisruptionBudget ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ | | operator.podDisruptionBudget.maxUnavailable | int | `1` | Maximum number/percentage of pods that may be made unavailable | | operator.podDisruptionBudget.minAvailable | string | `nil` | Minimum number/percentage of pods that should remain scheduled. When it's set, maxUnavailable must be disabled by `maxUnavailable: null` | +| operator.podDisruptionBudget.unhealthyPodEvictionPolicy | string | `nil` | How are unhealthy, but running, pods counted for eviction | | operator.podLabels | object | `{}` | Labels to be added to cilium-operator pods | -| operator.podSecurityContext | object | `{}` | Security context to be added to cilium-operator pods | +| operator.podSecurityContext | object | `{"seccompProfile":{"type":"RuntimeDefault"}}` | Security context to be added to cilium-operator pods | | operator.pprof.address | string | `"localhost"` | Configure pprof listen address for cilium-operator | +| operator.pprof.blockProfileRate | int | `0` | Enable goroutine blocking profiling for cilium-operator and set the rate of sampled events in nanoseconds (set to 1 to sample all events [warning: performance overhead]) | | operator.pprof.enabled | bool | `false` | Enable pprof for cilium-operator | +| operator.pprof.mutexProfileFraction | int | `0` | Enable mutex contention profiling for cilium-operator and set the fraction of sampled events (set to 1 to sample all events) | | operator.pprof.port | int | `6061` | Configure pprof listen port for cilium-operator | | operator.priorityClassName | string | `""` | The priority class to use for cilium-operator | -| operator.prometheus | object | `{"enabled":true,"metricsService":false,"port":9963,"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","jobLabel":"","labels":{},"metricRelabelings":null,"relabelings":null}}` | Enable prometheus metrics for cilium-operator on the configured port at /metrics | +| operator.prometheus | object | `{"enabled":true,"metricsService":false,"port":9963,"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","jobLabel":"","labels":{},"metricRelabelings":null,"relabelings":null,"scrapeTimeout":null},"tls":{"enabled":false,"server":{"existingSecret":"","mtls":{"enabled":false}}}}` | Enable prometheus metrics for cilium-operator on the configured port at /metrics | | operator.prometheus.serviceMonitor.annotations | object | `{}` | Annotations to add to ServiceMonitor cilium-operator | | operator.prometheus.serviceMonitor.enabled | bool | `false` | Enable service monitors. This requires the prometheus CRDs to be available (see https://github.com/prometheus-operator/prometheus-operator/blob/main/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml) | | operator.prometheus.serviceMonitor.interval | string | `"10s"` | Interval for scrape metrics. | @@ -784,55 +909,65 @@ contributors across the globe, there is almost always someone available to help. | operator.prometheus.serviceMonitor.labels | object | `{}` | Labels to add to ServiceMonitor cilium-operator | | operator.prometheus.serviceMonitor.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor cilium-operator | | operator.prometheus.serviceMonitor.relabelings | string | `nil` | Relabeling configs for the ServiceMonitor cilium-operator | +| operator.prometheus.serviceMonitor.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | +| operator.prometheus.tls | object | `{"enabled":false,"server":{"existingSecret":"","mtls":{"enabled":false}}}` | TLS configuration for Prometheus | +| operator.prometheus.tls.server.existingSecret | string | `""` | Name of the Secret containing the certificate, key and CA files for the Prometheus server. | | operator.removeNodeTaints | bool | `true` | Remove Cilium node taint from Kubernetes nodes that have a healthy Cilium pod running. | | operator.replicas | int | `2` | Number of replicas to run for the cilium-operator deployment | | operator.resources | object | `{}` | cilium-operator resource limits & requests ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | | operator.rollOutPods | bool | `false` | Roll out cilium-operator pods automatically when configmap is updated. | -| operator.securityContext | object | `{}` | Security context to be added to cilium-operator pods | +| operator.securityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]}}` | Security context to be added to cilium-operator pods | | operator.setNodeNetworkStatus | bool | `true` | Set Node condition NetworkUnavailable to 'false' with the reason 'CiliumIsUp' for nodes that have a healthy Cilium pod. | | operator.setNodeTaints | string | same as removeNodeTaints | Taint nodes where Cilium is scheduled but not running. This prevents pods from being scheduled to nodes where Cilium is not the default CNI provider. | | operator.skipCRDCreation | bool | `false` | Skip CRDs creation for cilium-operator | -| operator.tolerations | list | `[{"operator":"Exists"}]` | Node tolerations for cilium-operator scheduling to nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | +| operator.tolerations | list | `[{"key":"node-role.kubernetes.io/control-plane","operator":"Exists"},{"key":"node-role.kubernetes.io/master","operator":"Exists"},{"key":"node.kubernetes.io/not-ready","operator":"Exists"},{"key":"node.cloudprovider.kubernetes.io/uninitialized","operator":"Exists"}]` | Node tolerations for cilium-operator scheduling to nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ Toleration for agentNotReadyTaintKey taint is always added to cilium-operator pods. @schema type: [null, array] @schema | | operator.topologySpreadConstraints | list | `[]` | Pod topology spread constraints for cilium-operator | | operator.unmanagedPodWatcher.intervalSeconds | int | `15` | Interval, in seconds, to check if there are any pods that are not managed by Cilium. | | operator.unmanagedPodWatcher.restart | bool | `true` | Restart any pod that are not managed by Cilium. | +| operator.unmanagedPodWatcher.selector | string | `nil` | Selector for pods that should be restarted when not managed by Cilium. If not set, defaults to built-in selector "k8s-app=kube-dns". Set to empty string to select all pods. @schema type: [null, string] @schema | | operator.updateStrategy | object | `{"rollingUpdate":{"maxSurge":"25%","maxUnavailable":"50%"},"type":"RollingUpdate"}` | cilium-operator update strategy | | pmtuDiscovery.enabled | bool | `false` | Enable path MTU discovery to send ICMP fragmentation-needed replies to the client. | +| pmtuDiscovery.packetizationLayerPMTUDMode | string | `"blackhole"` | Enable kernel probing path MTU discovery for Pods which uses different message sizes to search for correct MTU value. Valid values are: always, blackhole, disabled and unset (or empty). If value is 'unset' or left empty then will not try to override setting. | | podAnnotations | object | `{}` | Annotations to be added to agent pods | | podLabels | object | `{}` | Labels to be added to agent pods | -| podSecurityContext | object | `{"appArmorProfile":{"type":"Unconfined"}}` | Security Context for cilium-agent pods. | +| podSecurityContext | object | `{"appArmorProfile":{"type":"Unconfined"},"seccompProfile":{"type":"Unconfined"}}` | Security Context for cilium-agent pods. | | podSecurityContext.appArmorProfile | object | `{"type":"Unconfined"}` | AppArmorProfile options for the `cilium-agent` and init containers | | policyCIDRMatchMode | string | `nil` | policyCIDRMatchMode is a list of entities that may be selected by CIDR selector. The possible value is "nodes". | +| policyDenyResponse | string | `"none"` | Configure what the response should be to pod egress traffic denied by network policy. Possible values: - none (default) - icmp | | policyEnforcementMode | string | `"default"` | The agent can be put into one of the three policy enforcement modes: default, always and never. ref: https://docs.cilium.io/en/stable/security/policy/intro/#policy-enforcement-modes | | pprof.address | string | `"localhost"` | Configure pprof listen address for cilium-agent | +| pprof.blockProfileRate | int | `0` | Enable goroutine blocking profiling for cilium-agent and set the rate of sampled events in nanoseconds (set to 1 to sample all events [warning: performance overhead]) | | pprof.enabled | bool | `false` | Enable pprof for cilium-agent | +| pprof.mutexProfileFraction | int | `0` | Enable mutex contention profiling for cilium-agent and set the fraction of sampled events (set to 1 to sample all events) | | pprof.port | int | `6060` | Configure pprof listen port for cilium-agent | | preflight.affinity | object | `{"podAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":[{"labelSelector":{"matchLabels":{"k8s-app":"cilium"}},"topologyKey":"kubernetes.io/hostname"}]}}` | Affinity for cilium-preflight | | preflight.annotations | object | `{}` | Annotations to be added to all top-level preflight objects (resources under templates/cilium-preflight) | | preflight.enabled | bool | `false` | Enable Cilium pre-flight resources (required for upgrade) | +| preflight.envoy.image | object | `{"digest":"sha256:ba0ab8adac082d50d525fd2c5ba096c8facea3a471561b7c61c7a5b9c2e0de0d","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium-envoy","tag":"v1.36.6-1776000132-2437d2edeaf4d9b56ef279bd0d71127440c067aa","useDigest":true}` | Envoy pre-flight image. | | preflight.extraEnv | list | `[]` | Additional preflight environment variables. | | preflight.extraVolumeMounts | list | `[]` | Additional preflight volumeMounts. | | preflight.extraVolumes | list | `[]` | Additional preflight volumes. | -| preflight.image | object | `{"digest":"sha256:24a73fe795351cf3279ac8e84918633000b52a9654ff73a6b0d7223bcff4a67a","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.17.4","useDigest":true}` | Cilium pre-flight image. | +| preflight.image | object | `{"digest":"sha256:2e61680593cddca8b6c055f6d4c849d87a26a1c91c7e3b8b56c7fb76ab7b7b10","override":null,"pullPolicy":"IfNotPresent","repository":"quay.io/cilium/cilium","tag":"v1.19.3","useDigest":true}` | Cilium pre-flight image. | | preflight.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for preflight pod assignment ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector | | preflight.podAnnotations | object | `{}` | Annotations to be added to preflight pods | | preflight.podDisruptionBudget.enabled | bool | `false` | enable PodDisruptionBudget ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ | | preflight.podDisruptionBudget.maxUnavailable | int | `1` | Maximum number/percentage of pods that may be made unavailable | | preflight.podDisruptionBudget.minAvailable | string | `nil` | Minimum number/percentage of pods that should remain scheduled. When it's set, maxUnavailable must be disabled by `maxUnavailable: null` | +| preflight.podDisruptionBudget.unhealthyPodEvictionPolicy | string | `nil` | How are unhealthy, but running, pods counted for eviction | | preflight.podLabels | object | `{}` | Labels to be added to the preflight pod. | | preflight.podSecurityContext | object | `{}` | Security context to be added to preflight pods. | | preflight.priorityClassName | string | `""` | The priority class to use for the preflight pod. | | preflight.readinessProbe.initialDelaySeconds | int | `5` | For how long kubelet should wait before performing the first probe | | preflight.readinessProbe.periodSeconds | int | `5` | interval between checks of the readiness probe | | preflight.resources | object | `{}` | preflight resource limits & requests ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | -| preflight.securityContext | object | `{}` | Security context to be added to preflight pods | +| preflight.securityContext | object | `{"allowPrivilegeEscalation":false}` | Security context to be added to preflight pods | | preflight.terminationGracePeriodSeconds | int | `1` | Configure termination grace period for preflight Deployment and DaemonSet. | | preflight.tofqdnsPreCache | string | `""` | Path to write the `--tofqdns-pre-cache` file to. | | preflight.tolerations | list | `[{"operator":"Exists"}]` | Node tolerations for preflight scheduling to nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | | preflight.updateStrategy | object | `{"type":"RollingUpdate"}` | preflight update strategy | | preflight.validateCNPs | bool | `true` | By default we should always validate the installed CNPs before upgrading Cilium. This will make sure the user will have the policies deployed in the cluster with the right schema. | | priorityClassName | string | `""` | The priority class to use for cilium-agent. | -| prometheus | object | `{"controllerGroupMetrics":["write-cni-file","sync-host-ips","sync-lb-maps-with-k8s-services"],"enabled":false,"metrics":null,"metricsService":false,"port":9962,"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","jobLabel":"","labels":{},"metricRelabelings":null,"relabelings":[{"replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}],"trustCRDsExist":false}}` | Configure prometheus metrics on the configured port at /metrics | +| prometheus | object | `{"controllerGroupMetrics":["write-cni-file","sync-host-ips","sync-lb-maps-with-k8s-services"],"enabled":false,"metrics":null,"metricsService":false,"port":9962,"serviceMonitor":{"annotations":{},"enabled":false,"interval":"10s","jobLabel":"","labels":{},"metricRelabelings":null,"relabelings":[{"action":"replace","replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}],"scrapeTimeout":null,"trustCRDsExist":false}}` | Configure prometheus metrics on the configured port at /metrics | | prometheus.controllerGroupMetrics | list | `["write-cni-file","sync-host-ips","sync-lb-maps-with-k8s-services"]` | - Enable controller group metrics for monitoring specific Cilium subsystems. The list is a list of controller group names. The special values of "all" and "none" are supported. The set of controller group names is not guaranteed to be stable between Cilium versions. | | prometheus.metrics | string | `nil` | Metrics that should be enabled or disabled from the default metric list. The list is expected to be separated by a space. (+metric_foo to enable metric_foo , -metric_bar to disable metric_bar). ref: https://docs.cilium.io/en/stable/observability/metrics/ | | prometheus.serviceMonitor.annotations | object | `{}` | Annotations to add to ServiceMonitor cilium-agent | @@ -841,7 +976,8 @@ contributors across the globe, there is almost always someone available to help. | prometheus.serviceMonitor.jobLabel | string | `""` | jobLabel to add for ServiceMonitor cilium-agent | | prometheus.serviceMonitor.labels | object | `{}` | Labels to add to ServiceMonitor cilium-agent | | prometheus.serviceMonitor.metricRelabelings | string | `nil` | Metrics relabeling configs for the ServiceMonitor cilium-agent | -| prometheus.serviceMonitor.relabelings | list | `[{"replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}]` | Relabeling configs for the ServiceMonitor cilium-agent | +| prometheus.serviceMonitor.relabelings | list | `[{"action":"replace","replacement":"${1}","sourceLabels":["__meta_kubernetes_pod_node_name"],"targetLabel":"node"}]` | Relabeling configs for the ServiceMonitor cilium-agent | +| prometheus.serviceMonitor.scrapeTimeout | string | `nil` | Timeout after which scrape is considered to be failed. | | prometheus.serviceMonitor.trustCRDsExist | bool | `false` | Set to `true` and helm will not check for monitoring.coreos.com/v1 CRDs before deploying | | rbac.create | bool | `true` | Enable creation of Resource-Based Access Control configuration. | | readinessProbe.failureThreshold | int | `3` | failure threshold of readiness probe | @@ -854,23 +990,38 @@ contributors across the globe, there is almost always someone available to help. | scheduling.mode | string | Defaults to apply a pod anti-affinity rule to the agent pod - `anti-affinity` | Mode specifies how Cilium daemonset pods should be scheduled to Nodes. `anti-affinity` mode applies a pod anti-affinity rule to the cilium daemonset. Pod anti-affinity may significantly impact scheduling throughput for large clusters. See: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity `kube-scheduler` mode forgoes the anti-affinity rule for full scheduling throughput. Kube-scheduler avoids host port conflict when scheduling pods. | | sctp | object | `{"enabled":false}` | SCTP Configuration Values | | sctp.enabled | bool | `false` | Enable SCTP support. NOTE: Currently, SCTP support does not support rewriting ports or multihoming. | +| secretsNamespaceAnnotations | object | `{}` | Annotations to be added to all cilium-secret namespaces (resources under templates/cilium-secrets-namespace) | +| secretsNamespaceLabels | object | `{}` | Labels to be added to all cilium-secret namespaces (resources under templates/cilium-secrets-namespace) | +| securityContext.allowPrivilegeEscalation | bool | `false` | disable privilege escalation | | securityContext.capabilities.applySysctlOverwrites | list | `["SYS_ADMIN","SYS_CHROOT","SYS_PTRACE"]` | capabilities for the `apply-sysctl-overwrites` init container | -| securityContext.capabilities.ciliumAgent | list | `["CHOWN","KILL","NET_ADMIN","NET_RAW","IPC_LOCK","SYS_MODULE","SYS_ADMIN","SYS_RESOURCE","DAC_OVERRIDE","FOWNER","SETGID","SETUID"]` | Capabilities for the `cilium-agent` container | +| securityContext.capabilities.ciliumAgent | list | `["CHOWN","KILL","NET_ADMIN","NET_RAW","IPC_LOCK","SYS_MODULE","SYS_ADMIN","SYS_RESOURCE","DAC_OVERRIDE","FOWNER","SETGID","SETUID","SYSLOG"]` | Capabilities for the `cilium-agent` container | | securityContext.capabilities.cleanCiliumState | list | `["NET_ADMIN","SYS_MODULE","SYS_ADMIN","SYS_RESOURCE"]` | Capabilities for the `clean-cilium-state` init container | | securityContext.capabilities.mountCgroup | list | `["SYS_ADMIN","SYS_CHROOT","SYS_PTRACE"]` | Capabilities for the `mount-cgroup` init container | | securityContext.privileged | bool | `false` | Run the pod with elevated privileges | | securityContext.seLinuxOptions | object | `{"level":"s0","type":"spc_t"}` | SELinux options for the `cilium-agent` and init containers | | serviceAccounts | object | Component's fully qualified name. | Define serviceAccount names for components. | | serviceAccounts.clustermeshcertgen | object | `{"annotations":{},"automount":true,"create":true,"name":"clustermesh-apiserver-generate-certs"}` | Clustermeshcertgen is used if clustermesh.apiserver.tls.auto.method=cronJob | +| serviceAccounts.corednsMCSAPI | object | `{"annotations":{},"automount":true,"create":true,"name":"cilium-coredns-mcsapi-autoconfig"}` | CorednsMCSAPI is used if clustermesh.mcsapi.corednsAutoConfigure.enabled=true | | serviceAccounts.hubblecertgen | object | `{"annotations":{},"automount":true,"create":true,"name":"hubble-generate-certs"}` | Hubblecertgen is used if hubble.tls.auto.method=cronJob | | serviceAccounts.nodeinit.enabled | bool | `false` | Enabled is temporary until https://github.com/cilium/cilium-cli/issues/1396 is implemented. Cilium CLI doesn't create the SAs for node-init, thus the workaround. Helm is not affected by this issue. Name and automount can be configured, if enabled is set to true. Otherwise, they are ignored. Enabled can be removed once the issue is fixed. Cilium-nodeinit DS must also be fixed. | +| serviceAccounts.ztunnel | object | `{"annotations":{},"automount":false,"create":true,"name":"ztunnel-cilium"}` | Ztunnel is used if encryption.type=ztunnel | | serviceNoBackendResponse | string | `"reject"` | Configure what the response should be to traffic for a service without backends. Possible values: - reject (default) - drop | | sleepAfterInit | bool | `false` | Do not run Cilium agent when running with clean mode. Useful to completely uninstall Cilium as it will stop Cilium from starting and create artifacts in the node. | | socketLB | object | `{"enabled":false}` | Configure socket LB | | socketLB.enabled | bool | `false` | Enable socket LB | -| startupProbe.failureThreshold | int | `105` | failure threshold of startup probe. 105 x 2s translates to the old behaviour of the readiness probe (120s delay + 30 x 3s) | +| standaloneDnsProxy | object | `{"annotations":{},"automountServiceAccountToken":false,"debug":false,"enabled":false,"image":{"digest":"","override":null,"pullPolicy":"IfNotPresent","repository":"","tag":"","useDigest":true},"nodeSelector":{"kubernetes.io/os":"linux"},"rollOutPods":false,"serverPort":10095,"tolerations":[],"updateStrategy":{"rollingUpdate":{"maxSurge":2,"maxUnavailable":0},"type":"RollingUpdate"}}` | Standalone DNS Proxy Configuration Note: The standalone DNS proxy uses the agent's dnsProxy.* configuration for DNS settings (proxyPort, enableDnsCompression) to ensure consistency. | +| standaloneDnsProxy.annotations | object | `{}` | Standalone DNS proxy annotations | +| standaloneDnsProxy.automountServiceAccountToken | bool | `false` | Standalone DNS proxy auto mount service account token | +| standaloneDnsProxy.debug | bool | `false` | Standalone DNS proxy debug mode | +| standaloneDnsProxy.enabled | bool | `false` | Enable standalone DNS proxy (alpha feature) | +| standaloneDnsProxy.image | object | `{"digest":"","override":null,"pullPolicy":"IfNotPresent","repository":"","tag":"","useDigest":true}` | Standalone DNS proxy image | +| standaloneDnsProxy.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Standalone DNS proxy Node Selector | +| standaloneDnsProxy.rollOutPods | bool | `false` | Roll out Standalone DNS proxy automatically when configmap is updated. | +| standaloneDnsProxy.serverPort | int | `10095` | Standalone DNS proxy server port | +| standaloneDnsProxy.tolerations | list | `[]` | Standalone DNS proxy tolerations | +| standaloneDnsProxy.updateStrategy | object | `{"rollingUpdate":{"maxSurge":2,"maxUnavailable":0},"type":"RollingUpdate"}` | Standalone DNS proxy update strategy | +| startupProbe.failureThreshold | int | `300` | failure threshold of startup probe. Allow Cilium to take up to 600s to start up (300 attempts with 2s between attempts). | | startupProbe.periodSeconds | int | `2` | interval between checks of the startup probe | -| svcSourceRangeCheck | bool | `true` | Enable check of service source ranges (currently, only for LoadBalancer). | | synchronizeK8sNodes | bool | `true` | Synchronize Kubernetes nodes to kvstore and perform CNP GC. | | sysctlfix | object | `{"enabled":true}` | Configure sysctl override described in #20072. | | sysctlfix.enabled | bool | `true` | Enable the sysctl override. When enabled, the init container will mount the /proc of the host so that the `sysctlfix` utility can execute. | @@ -892,10 +1043,12 @@ contributors across the globe, there is almost always someone available to help. | tls.secretsNamespace | object | `{"create":true,"name":"cilium-secrets"}` | Configures where secrets used in CiliumNetworkPolicies will be looked for | | tls.secretsNamespace.create | bool | `true` | Create secrets namespace for TLS Interception secrets. | | tls.secretsNamespace.name | string | `"cilium-secrets"` | Name of TLS Interception secret namespace. | +| tmpVolume | object | `{}` | Configure temporary volume for cilium-agent | | tolerations | list | `[{"operator":"Exists"}]` | Node tolerations for agent scheduling to nodes with taints ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ | | tunnelPort | int | Port 8472 for VXLAN, Port 6081 for Geneve | Configure VXLAN and Geneve tunnel port. | | tunnelProtocol | string | `"vxlan"` | Tunneling protocol to use in tunneling mode and for ad-hoc tunnels. Possible values: - "" - vxlan - geneve | | tunnelSourcePortRange | string | 0-0 to let the kernel driver decide the range | Configure VXLAN and Geneve tunnel source port range hint. | +| underlayProtocol | string | `"ipv4"` | IP family for the underlay. Possible values: - "ipv4" - "ipv6" | | updateStrategy | object | `{"rollingUpdate":{"maxUnavailable":2},"type":"RollingUpdate"}` | Cilium agent update strategy | | upgradeCompatibility | string | `nil` | upgradeCompatibility helps users upgrading to ensure that the configMap for Cilium will not change critical values to ensure continued operation This flag is not required for new installations. For example: '1.7', '1.8', '1.9' | | vtep.cidr | string | `""` | A space separated list of VTEP device CIDRs, for example "1.1.1.0/24 1.1.2.0/24" | diff --git a/packages/system/cilium/charts/cilium/files/cilium-agent/dashboards/cilium-dashboard.json b/packages/system/cilium/charts/cilium/files/cilium-agent/dashboards/cilium-dashboard.json index e6cf5c26..1f0a1080 100644 --- a/packages/system/cilium/charts/cilium/files/cilium-agent/dashboards/cilium-dashboard.json +++ b/packages/system/cilium/charts/cilium/files/cilium-agent/dashboards/cilium-dashboard.json @@ -39,6 +39,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -133,7 +134,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -169,6 +170,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -276,7 +278,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -317,7 +319,6 @@ }, { "collapsed": false, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -346,6 +347,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -498,7 +500,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -554,6 +556,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -633,7 +636,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -691,6 +694,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -770,7 +774,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -838,6 +842,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -917,7 +922,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -981,6 +986,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -1045,7 +1051,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -1063,7 +1069,6 @@ }, { "collapsed": false, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -1092,6 +1097,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -1198,7 +1204,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -1232,6 +1238,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -1338,7 +1345,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -1372,6 +1379,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -1478,7 +1486,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -1512,6 +1520,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -1618,7 +1627,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -1652,6 +1661,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -1758,7 +1768,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -1792,6 +1802,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -1898,7 +1909,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -1917,7 +1928,6 @@ }, { "collapsed": false, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -1930,7 +1940,10 @@ "type": "row" }, { - "datasource": null, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, "gridPos": { "h": 1, "w": 24, @@ -1947,13 +1960,7 @@ "content": "", "mode": "markdown" }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": null, - "refId": "A" - } - ], + "pluginVersion": "11.3.1", "title": "BPF", "type": "text" }, @@ -1974,6 +1981,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -2081,7 +2089,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -2117,6 +2125,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -2225,7 +2234,7 @@ "sort": "desc" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -2259,6 +2268,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -2366,7 +2376,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -2400,6 +2410,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -2466,7 +2477,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -2500,6 +2511,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -2584,7 +2596,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -2618,6 +2630,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -2702,7 +2715,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -2736,6 +2749,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -2840,7 +2854,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -2858,7 +2872,10 @@ "type": "timeseries" }, { - "datasource": null, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, "gridPos": { "h": 1, "w": 24, @@ -2875,13 +2892,7 @@ "content": "", "mode": "markdown" }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": null, - "refId": "A" - } - ], + "pluginVersion": "11.3.1", "title": "kvstore", "type": "text" }, @@ -2902,6 +2913,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -3010,7 +3022,7 @@ "sort": "desc" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -3044,6 +3056,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -3152,7 +3165,7 @@ "sort": "desc" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -3186,6 +3199,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -3293,7 +3307,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -3327,6 +3341,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -3434,7 +3449,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -3468,6 +3483,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -3572,7 +3588,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -3590,7 +3606,10 @@ "type": "timeseries" }, { - "datasource": null, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, "gridPos": { "h": 1, "w": 24, @@ -3607,13 +3626,7 @@ "content": "", "mode": "markdown" }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": null, - "refId": "A" - } - ], + "pluginVersion": "11.3.1", "title": "Cilium network information", "type": "text" }, @@ -3634,6 +3647,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -3697,7 +3711,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -3731,6 +3745,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -3794,7 +3809,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -3828,6 +3843,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -4175,7 +4191,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -4254,6 +4270,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -4601,7 +4618,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -4680,6 +4697,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -5027,7 +5045,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -5106,6 +5124,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -5453,7 +5472,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -5532,6 +5551,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", @@ -5631,7 +5651,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -5665,6 +5685,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -5759,7 +5780,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -5793,6 +5814,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -5856,7 +5878,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -5890,6 +5912,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -5953,7 +5976,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -5998,6 +6021,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -6061,7 +6085,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -6095,6 +6119,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -6265,7 +6290,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -6299,6 +6324,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -6362,7 +6388,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -6396,6 +6422,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -6518,7 +6545,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -6558,7 +6585,10 @@ "type": "timeseries" }, { - "datasource": null, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, "gridPos": { "h": 1, "w": 24, @@ -6575,13 +6605,7 @@ "content": "", "mode": "markdown" }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": null, - "refId": "A" - } - ], + "pluginVersion": "11.3.1", "title": "Policy", "type": "text" }, @@ -6602,6 +6626,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -6711,40 +6736,20 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "sum(rate(cilium_policy_l7_total{k8s_app=\"cilium\", pod=~\"$pod\", rule=\"denied\"}[1m]))", + "editorMode": "code", + "expr": "sum by(rule, proxy_type) (rate(cilium_policy_l7_total{k8s_app=\"cilium\", pod=~\"$pod\"}[1m]))", "format": "time_series", "intervalFactor": 1, - "legendFormat": "denied", + "legendFormat": "{{proxy_type}} - {{rule}}", + "range": true, "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "sum(rate(cilium_policy_l7_total{k8s_app=\"cilium\", pod=~\"$pod\", rule=\"forwarded\"}[1m]))", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "forwarded", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "sum(rate(cilium_policy_l7_total{k8s_app=\"cilium\", pod=~\"$pod\", rule=\"received\"}[1m]))", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "received", - "refId": "C" } ], "title": "L7 forwarded request", @@ -6755,6 +6760,7 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "description": "99th percentile of DNS proxy request processing latency, by span", "fieldConfig": { "defaults": { "color": { @@ -6767,8 +6773,9 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", - "fillOpacity": 10, + "fillOpacity": 34, "gradientMode": "none", "hideFrom": { "legend": false, @@ -6777,12 +6784,15 @@ }, "insertNulls": false, "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, - "showPoints": "never", + "showPoints": "auto", "spanNulls": false, "stacking": { "group": "A", @@ -6800,14 +6810,10 @@ { "color": "green", "value": null - }, - { - "color": "red", - "value": 80 } ] }, - "unit": "ops" + "unit": "s" }, "overrides": [] }, @@ -6817,213 +6823,7 @@ "x": 12, "y": 115 }, - "id": 37, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "sum(rate(cilium_drop_count_total{direction=\"INGRESS\", k8s_app=\"cilium\", pod=~\"$pod\"}[5m])) by (reason)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "{{reason}}", - "refId": "A" - } - ], - "title": "Cilium drops Ingress", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "bars", - "fillOpacity": 100, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "normal" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Max per node processingTime" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#e24d42", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Max per node upstreamTime" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#58140c", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "avg(cilium_policy_l7_total{pod=~\"cilium.*\", rule=\"parse_errors\"})" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#bf1b00", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "parse errors" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#bf1b00", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Max per node processingTime" - }, - "properties": [ - { - "id": "unit", - "value": "short" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Max per node upstreamTime" - }, - "properties": [ - { - "id": "unit", - "value": "short" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "avg(cilium_policy_l7_total{pod=~\"cilium.*\", rule=\"parse_errors\"})" - }, - "properties": [ - { - "id": "unit", - "value": "short" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "parse errors" - }, - "properties": [ - { - "id": "unit", - "value": "short" - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 12, - "x": 0, - "y": 120 - }, - "id": 94, + "id": 123, "options": { "legend": { "calcs": [ @@ -7038,33 +6838,23 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "avg(rate(cilium_proxy_upstream_reply_seconds_sum{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope) / sum(rate(cilium_proxy_upstream_reply_seconds_count{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope)", + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by(scope, le) (rate(cilium_proxy_upstream_reply_seconds_bucket{protocol_l7=\"dns\", k8s_app=\"cilium\", pod=~\"$pod\", scope!=\"totalTime\"}[5m]))) \n", "format": "time_series", - "interval": "", "intervalFactor": 1, "legendFormat": "{{scope}}", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "avg(cilium_policy_l7_total{k8s_app=\"cilium\", pod=~\"$pod\", rule=\"parse_errors\"}) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "parse errors", + "range": true, "refId": "B" } ], - "title": "Proxy response time (Avg)", + "title": "DNS proxy request latency", "type": "timeseries" }, { @@ -7084,6 +6874,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -7117,21 +6908,17 @@ { "color": "green", "value": null - }, - { - "color": "red", - "value": 80 } ] }, - "unit": "bps" + "unit": "pps" }, "overrides": [] }, "gridPos": { "h": 5, "w": 12, - "x": 12, + "x": 0, "y": 120 }, "id": 114, @@ -7147,21 +6934,22 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "sum(rate(cilium_drop_bytes_total{direction=\"INGRESS\", k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (reason) * 8", + "expr": "sum(rate(cilium_drop_count_total{k8s_app=\"cilium\", pod=~\"$pod\", reason=\"Policy denied\"}[1m])) by (direction)", "format": "time_series", "intervalFactor": 1, - "legendFormat": "{{reason}}", + "legendFormat": "{{direction}}", + "range": true, "refId": "A" } ], - "title": "Dropped Ingress Traffic", + "title": "Policy Denies: L3/L4", "type": "timeseries" }, { @@ -7181,6 +6969,103 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 120 + }, + "id": 37, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(cilium_policy_l7_total{rule=\"denied\", k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (proxy_type)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{reason}}", + "range": true, + "refId": "A" + } + ], + "title": "Policy Denies: L7", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "End-to-end duration to apply incremental identity updates to the policy control and data planes.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -7357,17 +7242,19 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "min(rate(cilium_triggers_policy_update_call_duration_seconds_sum{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope) / sum(rate(cilium_triggers_policy_update_call_duration_seconds_count{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope)", + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by(le) (rate(cilium_policy_incremental_update_duration_bucket{k8s_app=\"cilium\", pod=~\"$pod\"}[5m])))", "format": "time_series", "intervalFactor": 1, - "legendFormat": "min", + "legendFormat": "99%", + "range": true, "refId": "A" }, { @@ -7375,25 +7262,16 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "avg(rate(cilium_triggers_policy_update_call_duration_seconds_sum{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope) / sum(rate(cilium_triggers_policy_update_call_duration_seconds_count{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope)", + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum by(le) (rate(cilium_policy_incremental_update_duration_bucket{k8s_app=\"cilium\", pod=~\"$pod\"}[5m])))", "format": "time_series", "intervalFactor": 1, - "legendFormat": "avg", + "legendFormat": "50%", + "range": true, "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "max(rate(cilium_triggers_policy_update_call_duration_seconds_sum{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope) / sum(rate(cilium_triggers_policy_update_call_duration_seconds_count{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "max", - "refId": "C" } ], - "title": "Policy Trigger Duration", + "title": "Policy Identity Update Latency", "type": "timeseries" }, { @@ -7401,6 +7279,7 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "description": "The time taken for new or updated network policy to be applied to all affected endpoints", "fieldConfig": { "defaults": { "color": { @@ -7413,8 +7292,9 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, - "drawStyle": "bars", - "fillOpacity": 100, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 35, "gradientMode": "none", "hideFrom": { "legend": false, @@ -7432,7 +7312,7 @@ "spanNulls": false, "stacking": { "group": "A", - "mode": "normal" + "mode": "none" }, "thresholdsStyle": { "mode": "off" @@ -7455,530 +7335,6 @@ }, "unit": "s" }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Max per node processingTime" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#e24d42", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Max per node upstreamTime" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#58140c", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "parse errors" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#bf1b00", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "parse errors" - }, - "properties": [ - { - "id": "unit", - "value": "short" - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 12, - "x": 12, - "y": 125 - }, - "id": 66, - "options": { - "legend": { - "calcs": [ - "mean" - ], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "max(rate(cilium_proxy_upstream_reply_seconds_sum{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope) / sum(rate(cilium_proxy_upstream_reply_seconds_count{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Max {{scope}}", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "max(rate(cilium_policy_l7_total{k8s_app=\"cilium\", pod=~\"$pod\", rule=\"parse_errors\"}[1m])) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "parse errors", - "refId": "A" - } - ], - "title": "Proxy response time (Max)", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "bars", - "fillOpacity": 100, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "both" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#7eb26d", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "egress" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#e5ac0e", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "ingress" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#e0752d", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "none" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#bf1b00", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 0, - "y": 130 - }, - "id": 33, - "options": { - "legend": { - "calcs": [ - "lastNotNull" - ], - "displayMode": "list", - "placement": "right", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "sum(cilium_policy_endpoint_enforcement_status{k8s_app=\"cilium\", pod=~\"$pod\"}) by (enforcement)", - "format": "time_series", - "hide": false, - "instant": true, - "interval": "1s", - "intervalFactor": 1, - "legendFormat": "{{enforcement}}", - "refId": "B" - } - ], - "title": "Endpoints policy enforcement status", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 35, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "avg" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#b7dbab", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "max" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "rgba(89, 132, 76, 0.54)", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "min" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#2f575e", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "max" - }, - "properties": [ - { - "id": "custom.fillBelowTo", - "value": "min" - }, - { - "id": "custom.lineWidth", - "value": 0 - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "min" - }, - "properties": [ - { - "id": "custom.lineWidth", - "value": 0 - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 6, - "y": 130 - }, - "id": 100, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "min(cilium_proxy_redirects{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "min", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "avg(cilium_proxy_redirects{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "avg", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "max(cilium_proxy_redirects{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "max", - "refId": "C" - } - ], - "title": "Proxy Redirects", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 35, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "opm" - }, "overrides": [ { "matcher": { @@ -8116,7 +7472,7 @@ "h": 5, "w": 12, "x": 12, - "y": 130 + "y": 125 }, "id": 102, "options": { @@ -8131,17 +7487,19 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "min(rate(cilium_triggers_policy_update_total{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod) * 60", + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by(le) (rate(cilium_policy_implementation_delay_bucket{k8s_app=\"cilium\", pod=~\"$pod\"}[5m])))", "format": "time_series", "intervalFactor": 1, - "legendFormat": "min trigger", + "legendFormat": "99%", + "range": true, "refId": "A" }, { @@ -8149,36 +7507,16 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "expr": "avg(rate(cilium_triggers_policy_update_total{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod) * 60", + "editorMode": "code", + "expr": "histogram_quantile(0.5, sum by(le) (rate(cilium_policy_implementation_delay_bucket{k8s_app=\"cilium\", pod=~\"$pod\"}[5m]))) ", "format": "time_series", "intervalFactor": 1, - "legendFormat": "average trigger", + "legendFormat": "50%", + "range": true, "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "max(rate(cilium_triggers_policy_update_total{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod) * 60", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "max trigger", - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "max(rate(cilium_triggers_policy_update_folds{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod) * 60", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "folds", - "refId": "D" } ], - "title": "Policy Trigger Runs", + "title": "Policy Apply Latency", "type": "timeseries" }, { @@ -8198,6 +7536,540 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "bars", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "both" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#7eb26d", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "egress" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#e5ac0e", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ingress" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#e0752d", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "none" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#bf1b00", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 130 + }, + "id": 33, + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "11.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(cilium_policy_endpoint_enforcement_status{k8s_app=\"cilium\", pod=~\"$pod\"}) by (enforcement)", + "format": "time_series", + "hide": false, + "instant": true, + "interval": "1s", + "intervalFactor": 1, + "legendFormat": "{{enforcement}}", + "refId": "B" + } + ], + "title": "Endpoints policy enforcement status", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 35, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "avg" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#b7dbab", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "max" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "rgba(89, 132, 76, 0.54)", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "min" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#2f575e", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "max" + }, + "properties": [ + { + "id": "custom.fillBelowTo", + "value": "min" + }, + { + "id": "custom.lineWidth", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "min" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 130 + }, + "id": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "min(cilium_proxy_redirects{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "min", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "avg(cilium_proxy_redirects{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "avg", + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "max(cilium_proxy_redirects{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "max", + "refId": "C" + } + ], + "title": "Proxy Redirects", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Endpoint policy calculation time by stage. Shows the 99th-percentile.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 35, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "avg" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#f9d9f9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "max" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806eb7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "min" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#806eb7", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "max" + }, + "properties": [ + { + "id": "custom.fillBelowTo", + "value": "min" + }, + { + "id": "custom.lineWidth", + "value": 0 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "min" + }, + "properties": [ + { + "id": "custom.lineWidth", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 130 + }, + "id": 117, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "11.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum by(scope, le) (rate(cilium_endpoint_regeneration_time_stats_seconds_bucket{scope=~\"proxyConfiguration|endpointPolicyCalculation|selectorPolicyCalculation|proxyPolicyCalculation\",k8s_app=\"cilium\",status=\"success\",pod=~\"$pod\"}[5m])))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Policy Calculation Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 35, "gradientMode": "none", @@ -8337,7 +8209,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -8388,366 +8260,15 @@ "type": "timeseries" }, { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "bars", - "fillOpacity": 100, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "normal" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "ops" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "Max per node processingTime" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#e24d42", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "Max per node upstreamTime" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#58140c", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "parse errors" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#bf1b00", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "parse errors" - }, - "properties": [ - { - "id": "unit", - "value": "s" - }, - { - "id": "custom.axisPlacement", - "value": "hidden" - } - ] - } - ] + "defaults": {}, + "overrides": [] }, - "gridPos": { - "h": 5, - "w": 12, - "x": 12, - "y": 135 - }, - "id": 123, - "options": { - "legend": { - "calcs": [ - "mean" - ], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "avg(rate(cilium_proxy_upstream_reply_seconds_count{k8s_app=\"cilium\", pod=~\"$pod\"}[1m])) by (pod, scope)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "{{scope}}", - "refId": "B" - } - ], - "title": "DNS proxy requests", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 35, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "avg" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#f9d9f9", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "max" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#806eb7", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "min" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#806eb7", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "max" - }, - "properties": [ - { - "id": "custom.fillBelowTo", - "value": "min" - }, - { - "id": "custom.lineWidth", - "value": 0 - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "min" - }, - "properties": [ - { - "id": "custom.lineWidth", - "value": 0 - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 12, - "x": 12, - "y": 140 - }, - "id": 117, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "min(cilium_policy_max_revision{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "min", - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "avg(cilium_policy_max_revision{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "avg", - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "expr": "max(cilium_policy_max_revision{k8s_app=\"cilium\", pod=~\"$pod\"}) by (pod)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "max", - "refId": "C" - } - ], - "title": "Policy Revision", - "type": "timeseries" - }, - { - "datasource": null, "gridPos": { "h": 1, "w": 24, "x": 0, - "y": 145 + "y": 140 }, "id": 73, "options": { @@ -8759,13 +8280,7 @@ "content": "", "mode": "markdown" }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": null, - "refId": "A" - } - ], + "pluginVersion": "11.3.1", "title": "Endpoints", "type": "text" }, @@ -8786,6 +8301,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -8834,7 +8350,7 @@ "h": 9, "w": 12, "x": 0, - "y": 146 + "y": 141 }, "id": 55, "options": { @@ -8851,7 +8367,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -8885,6 +8401,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -8933,7 +8450,7 @@ "h": 9, "w": 12, "x": 12, - "y": 146 + "y": 141 }, "id": 115, "options": { @@ -8950,7 +8467,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -8984,6 +8501,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -9093,7 +8611,7 @@ "h": 5, "w": 12, "x": 0, - "y": 155 + "y": 150 }, "id": 49, "options": { @@ -9111,7 +8629,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -9146,6 +8664,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -9240,7 +8759,7 @@ "h": 5, "w": 12, "x": 12, - "y": 155 + "y": 150 }, "id": 51, "options": { @@ -9257,7 +8776,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -9275,12 +8794,15 @@ "type": "timeseries" }, { - "datasource": null, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, "gridPos": { "h": 1, "w": 24, "x": 0, - "y": 160 + "y": 155 }, "id": 74, "options": { @@ -9292,13 +8814,7 @@ "content": "", "mode": "markdown" }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": null, - "refId": "A" - } - ], + "pluginVersion": "11.3.1", "title": "Controllers", "type": "text" }, @@ -9319,6 +8835,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 30, "gradientMode": "none", @@ -9413,7 +8930,7 @@ "h": 5, "w": 12, "x": 0, - "y": 161 + "y": 156 }, "id": 70, "options": { @@ -9431,7 +8948,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -9476,6 +8993,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -9615,7 +9133,7 @@ "h": 5, "w": 12, "x": 12, - "y": 161 + "y": 156 }, "id": 68, "options": { @@ -9634,8 +9152,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", - "repeatDirection": "h", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -9653,12 +9170,15 @@ "type": "timeseries" }, { - "datasource": null, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, "gridPos": { "h": 1, "w": 24, "x": 0, - "y": 166 + "y": 161 }, "id": 60, "options": { @@ -9670,13 +9190,7 @@ "content": "", "mode": "markdown" }, - "pluginVersion": "10.4.3", - "targets": [ - { - "datasource": null, - "refId": "A" - } - ], + "pluginVersion": "11.3.1", "title": "Kubernetes integration", "type": "text" }, @@ -9697,6 +9211,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -9786,7 +9301,7 @@ "h": 7, "w": 12, "x": 0, - "y": 167 + "y": 162 }, "id": 163, "options": { @@ -9801,7 +9316,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -9835,6 +9350,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -9924,7 +9440,7 @@ "h": 7, "w": 12, "x": 12, - "y": 167 + "y": 162 }, "id": 165, "options": { @@ -9939,7 +9455,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -9973,6 +9489,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -10062,7 +9579,7 @@ "h": 8, "w": 12, "x": 0, - "y": 174 + "y": 169 }, "id": 168, "options": { @@ -10080,7 +9597,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -10114,6 +9631,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -10203,7 +9721,7 @@ "h": 8, "w": 12, "x": 12, - "y": 174 + "y": 169 }, "id": 166, "options": { @@ -10220,7 +9738,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -10254,6 +9772,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -10343,7 +9862,7 @@ "h": 6, "w": 12, "x": 0, - "y": 182 + "y": 177 }, "id": 172, "options": { @@ -10360,7 +9879,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -10394,6 +9913,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -10483,7 +10003,7 @@ "h": 6, "w": 12, "x": 12, - "y": 182 + "y": 177 }, "id": 174, "options": { @@ -10500,7 +10020,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -10534,6 +10054,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -10623,7 +10144,7 @@ "h": 8, "w": 12, "x": 0, - "y": 188 + "y": 183 }, "id": 175, "options": { @@ -10640,7 +10161,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -10674,6 +10195,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -10763,7 +10285,7 @@ "h": 8, "w": 12, "x": 12, - "y": 188 + "y": 183 }, "id": 173, "options": { @@ -10780,7 +10302,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -10814,6 +10336,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -10862,7 +10385,7 @@ "h": 7, "w": 12, "x": 0, - "y": 196 + "y": 191 }, "id": 108, "options": { @@ -10877,7 +10400,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -10911,6 +10434,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -11005,7 +10529,7 @@ "h": 7, "w": 12, "x": 12, - "y": 196 + "y": 191 }, "id": 119, "options": { @@ -11020,7 +10544,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -11054,6 +10578,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -11148,7 +10673,7 @@ "h": 7, "w": 12, "x": 0, - "y": 203 + "y": 198 }, "id": 109, "options": { @@ -11163,7 +10688,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -11197,6 +10722,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -11291,7 +10817,7 @@ "h": 7, "w": 12, "x": 12, - "y": 203 + "y": 198 }, "id": 122, "options": { @@ -11306,7 +10832,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -11340,6 +10866,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -11388,7 +10915,7 @@ "h": 7, "w": 12, "x": 0, - "y": 210 + "y": 205 }, "id": 118, "options": { @@ -11403,7 +10930,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -11437,6 +10964,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -11485,7 +11013,7 @@ "h": 7, "w": 12, "x": 12, - "y": 210 + "y": 205 }, "id": 120, "options": { @@ -11500,7 +11028,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -11534,6 +11062,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "bars", "fillOpacity": 100, "gradientMode": "none", @@ -11582,7 +11111,7 @@ "h": 7, "w": 12, "x": 0, - "y": 217 + "y": 212 }, "id": 121, "options": { @@ -11597,7 +11126,7 @@ "sort": "none" } }, - "pluginVersion": "10.4.3", + "pluginVersion": "11.3.1", "targets": [ { "datasource": { @@ -11615,30 +11144,26 @@ "type": "timeseries" } ], - "refresh": false, - "schemaVersion": 39, + "preload": false, + "refresh": "", + "schemaVersion": 40, "tags": [], "templating": { "list": [ { "current": {}, - "hide": 0, "includeAll": false, "label": "Prometheus", - "multi": false, "name": "DS_PROMETHEUS", "options": [], "query": "prometheus", - "queryValue": "", "refresh": 1, "regex": "", - "skipUrlSync": false, "type": "datasource" }, { "allValue": "cilium.*", "current": { - "selected": false, "text": "All", "value": "$__all" }, @@ -11647,20 +11172,14 @@ "uid": "${DS_PROMETHEUS}" }, "definition": "label_values(cilium_version, pod)", - "hide": 0, "includeAll": true, - "multi": false, "name": "pod", "options": [], "query": "label_values(cilium_version, pod)", "refresh": 2, "regex": "", - "skipUrlSync": false, "sort": 1, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false + "type": "query" } ] }, @@ -11679,17 +11198,6 @@ "1h", "2h", "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" ] }, "timezone": "utc", @@ -11697,4 +11205,4 @@ "uid": "vtuWtdumz", "version": 1, "weekStart": "" -} +} \ No newline at end of file diff --git a/packages/system/cilium/charts/cilium/files/cilium-envoy/configmap/bootstrap-config.yaml b/packages/system/cilium/charts/cilium/files/cilium-envoy/configmap/bootstrap-config.yaml index 3a26b3c2..90ebf4ac 100644 --- a/packages/system/cilium/charts/cilium/files/cilium-envoy/configmap/bootstrap-config.yaml +++ b/packages/system/cilium/charts/cilium/files/cilium-envoy/configmap/bootstrap-config.yaml @@ -54,7 +54,7 @@ staticResources: - addressPrefix: "::1" prefixLen: 128 {{- end }} - streamIdleTimeout: "0s" + streamIdleTimeout: "{{ .Values.envoy.streamIdleTimeoutDurationSeconds }}s" {{- end }} {{- if and .Values.envoy.debug.admin.enabled }} - name: "envoy-admin-listener" @@ -107,7 +107,7 @@ staticResources: - addressPrefix: "::1" prefixLen: 128 {{- end }} - streamIdleTimeout: "0s" + streamIdleTimeout: "{{ .Values.envoy.streamIdleTimeoutDurationSeconds }}s" {{- end }} - name: "envoy-health-listener" address: @@ -159,7 +159,7 @@ staticResources: - addressPrefix: "::1" prefixLen: 128 {{- end }} - streamIdleTimeout: "0s" + streamIdleTimeout: "{{ .Values.envoy.streamIdleTimeoutDurationSeconds }}s" clusters: - name: "ingress-cluster" type: "ORIGINAL_DST" @@ -167,6 +167,8 @@ staticResources: circuitBreakers: thresholds: - maxRetries: {{ .Values.envoy.maxConcurrentRetries }} + maxConnections: {{ .Values.envoy.clusterMaxConnections }} + maxRequests: {{ .Values.envoy.clusterMaxRequests }} lbPolicy: "CLUSTER_PROVIDED" typedExtensionProtocolOptions: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: @@ -183,6 +185,8 @@ staticResources: circuitBreakers: thresholds: - maxRetries: {{ .Values.envoy.maxConcurrentRetries }} + maxConnections: {{ .Values.envoy.clusterMaxConnections }} + maxRequests: {{ .Values.envoy.clusterMaxRequests }} lbPolicy: "CLUSTER_PROVIDED" typedExtensionProtocolOptions: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: @@ -204,6 +208,8 @@ staticResources: circuitBreakers: thresholds: - maxRetries: {{ .Values.envoy.maxConcurrentRetries }} + maxConnections: {{ .Values.envoy.clusterMaxConnections }} + maxRequests: {{ .Values.envoy.clusterMaxRequests }} lbPolicy: "CLUSTER_PROVIDED" typedExtensionProtocolOptions: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: @@ -220,6 +226,8 @@ staticResources: circuitBreakers: thresholds: - maxRetries: {{ .Values.envoy.maxConcurrentRetries }} + maxConnections: {{ .Values.envoy.clusterMaxConnections }} + maxRequests: {{ .Values.envoy.clusterMaxRequests }} lbPolicy: "CLUSTER_PROVIDED" typedExtensionProtocolOptions: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: @@ -292,7 +300,7 @@ overloadManager: - name: "envoy.resource_monitors.global_downstream_max_connections" typedConfig: "@type": "type.googleapis.com/envoy.extensions.resource_monitors.downstream_connections.v3.DownstreamConnectionsConfig" - max_active_downstream_connections: "50000" + max_active_downstream_connections: "{{ .Values.envoy.maxGlobalDownstreamConnections }}" applicationLogConfig: logFormat: {{- if .Values.envoy.log.format_json }} @@ -304,3 +312,4 @@ admin: address: pipe: path: "/var/run/cilium/envoy/sockets/admin.sock" + mode: 0660 diff --git a/packages/system/cilium/charts/cilium/files/nodeinit/startup.bash b/packages/system/cilium/charts/cilium/files/nodeinit/startup.bash index aa63cac8..68e6b50b 100644 --- a/packages/system/cilium/charts/cilium/files/nodeinit/startup.bash +++ b/packages/system/cilium/charts/cilium/files/nodeinit/startup.bash @@ -156,6 +156,14 @@ fi iptables -w -t nat -D POSTROUTING -m comment --comment "ip-masq: ensure nat POSTROUTING directs all non-LOCAL destination traffic to our custom IP-MASQ chain" -m addrtype ! --dst-type LOCAL -j IP-MASQ || true {{- end }} +{{- if .Values.nodeinit.waitForCloudInit }} +echo "Waiting for cloud-init..." +if command -v cloud-init >/dev/null 2>&1; then + cloud-init status --wait + echo "cloud-init completed!" +fi +{{- end }} + {{- if not (eq .Values.nodeinit.bootstrapFile "") }} mkdir -p {{ .Values.nodeinit.bootstrapFile | dir | quote }} date > {{ .Values.nodeinit.bootstrapFile | quote }} diff --git a/packages/system/cilium/charts/cilium/templates/NOTES.txt b/packages/system/cilium/charts/cilium/templates/NOTES.txt index f5405074..5d82f4d2 100644 --- a/packages/system/cilium/charts/cilium/templates/NOTES.txt +++ b/packages/system/cilium/charts/cilium/templates/NOTES.txt @@ -17,6 +17,13 @@ You have successfully installed {{ title .Chart.Name }}. {{- end }} +{{- $warnings := include "cilium.warnings" . }} +{{- if $warnings }} + +WARNINGS: +{{ $warnings }} +{{- end }} + Your release version is {{ .Chart.Version }}. For any further help, visit https://docs.cilium.io/en/v{{ (semver .Chart.Version).Major }}.{{ (semver .Chart.Version).Minor }}/gettinghelp diff --git a/packages/system/cilium/charts/cilium/templates/_extensions.tpl b/packages/system/cilium/charts/cilium/templates/_extensions.tpl index 5da57e2e..8c0e5c20 100644 --- a/packages/system/cilium/charts/cilium/templates/_extensions.tpl +++ b/packages/system/cilium/charts/cilium/templates/_extensions.tpl @@ -3,6 +3,42 @@ _extensions.tpl contains template blocks that are intended to allow packagers to modify or extend the default chart behaviors. */}} +{{/* +Allow packagers to add extra volumes to cilium-agent. +*/}} +{{- define "cilium-agent.volumes.extra" }} +{{- end }} + +{{- define "cilium-agent.volumeMounts.extra" }} +{{- end }} + +{{/* +Allow packagers to set dnsPolicy for cilium-agent. +*/}} +{{- define "cilium-agent.dnsPolicy" }} +{{- if .Values.dnsPolicy }} +dnsPolicy: {{ .Values.dnsPolicy }} +{{- end }} +{{- end }} + +{{/* +Allow packagers to add extra volumes to cilium-operator. +*/}} +{{- define "cilium-operator.volumes.extra" }} +{{- end }} + +{{- define "cilium-operator.volumeMounts.extra" }} +{{- end }} + +{{/* +Allow packagers to set securityContext for cilium-operator. +*/}} +{{- define "cilium.operator.securityContext" }} +{{- with .Values.operator.securityContext }} +{{ toYaml . }} +{{- end }} +{{- end }} + {{/* Intentionally empty to allow downstream chart packagers to add extra containers to hubble-relay without having to modify the deployment manifest @@ -54,3 +90,87 @@ Allow packagers to add extra configuration to certgen. */}} {{- define "certgen.config.extra" -}} {{- end }} + +{{/* +Allow packagers to add extra arguments to the clustermesh-apiserver apiserver container. +*/}} +{{- define "clustermesh.apiserver.args.extra" -}} +{{- end }} + +{{/* +Allow packagers to add extra arguments to the clustermesh-apiserver kvstoremesh container. +*/}} +{{- define "clustermesh.kvstoremesh.args.extra" -}} +{{- end }} + +{{/* +Allow packagers to add init containers to the cilium-envoy pods. +*/}} +{{- define "envoy.initContainers" -}} +{{- end }} + +{{/* +Allow packagers to add extra args to the cilium-envoy container. +*/}} +{{- define "envoy.args.extra" -}} +{{- end }} + +{{/* +Allow packagers to add extra env vars to the cilium-envoy container. +*/}} +{{- define "envoy.env.extra" -}} +{{- end }} + +{{/* +Allow packagers to add extra volume mounts to the cilium-envoy container. +*/}} +{{- define "envoy.volumeMounts.extra" -}} +{{- end }} + +{{/* +Allow packagers to add extra host path mounts to the cilium-envoy container. +*/}} +{{- define "envoy.hostPathMounts.extra" -}} +{{- end }} + + +{{/* +Allow packagers to define set of ports for cilium-envoy container. +The template needs to allow overriding ports spec not just adding. +*/}} +{{- define "envoy.ports" -}} + {{- if .Values.envoy.prometheus.enabled }} + ports: + - name: envoy-metrics + containerPort: {{ .Values.envoy.prometheus.port }} + hostPort: {{ .Values.envoy.prometheus.port }} + protocol: TCP + {{- if and .Values.envoy.debug.admin.enabled .Values.envoy.debug.admin.port }} + - name: envoy-admin + containerPort: {{ .Values.envoy.debug.admin.port }} + hostPort: {{ .Values.envoy.debug.admin.port }} + protocol: TCP + {{- end }} + {{- end }} +{{- end }} + +{{/* +Allow packagers to define update strategy for cilium-envoy pods. +*/}} +{{- define "envoy.updateStrategy" -}} +{{- with .Values.envoy.updateStrategy }} +updateStrategy: + {{- toYaml . | trim | nindent 2 }} + {{- end }} +{{- end }} + +{{/* +Allow packagers to define affinity for cilium-envoy pods. +*/}} +{{- define "envoy.affinity" -}} +{{- with .Values.envoy.affinity }} +affinity: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- end }} + diff --git a/packages/system/cilium/charts/cilium/templates/_helpers.tpl b/packages/system/cilium/charts/cilium/templates/_helpers.tpl index dc113ba0..e90aa482 100644 --- a/packages/system/cilium/charts/cilium/templates/_helpers.tpl +++ b/packages/system/cilium/charts/cilium/templates/_helpers.tpl @@ -131,12 +131,16 @@ To override the namespace and configMap when using `auto`: {{- define "k8sServiceHost" }} {{- $configmapName := default "cluster-info" .Values.k8sServiceLookupConfigMapName }} {{- $configmapNamespace := default "kube-public" .Values.k8sServiceLookupNamespace }} - {{- if and (eq .Values.k8sServiceHost "auto") (lookup "v1" "ConfigMap" $configmapNamespace $configmapName) }} + {{- if eq .Values.k8sServiceHost "auto" }} {{- $configmap := (lookup "v1" "ConfigMap" $configmapNamespace $configmapName) }} - {{- $kubeconfig := get $configmap.data "kubeconfig" }} - {{- $k8sServer := get ($kubeconfig | fromYaml) "clusters" | mustFirst | dig "cluster" "server" "" }} - {{- $uri := (split "https://" $k8sServer)._1 | trim }} - {{- (split ":" $uri)._0 | quote }} + {{- if $configmap }} + {{- $kubeconfig := get $configmap.data "kubeconfig" }} + {{- $k8sServer := get ($kubeconfig | fromYaml) "clusters" | mustFirst | dig "cluster" "server" "" }} + {{- $uri := (split "https://" $k8sServer)._1 | trim }} + {{- (split ":" $uri)._0 | quote }} + {{- else }} + {{- fail (printf "ConfigMap %s/%s not found, please create it or set k8sServiceHost to a valid value" $configmapNamespace $configmapName) }} + {{- end }} {{- else }} {{- .Values.k8sServiceHost | quote }} {{- end }} @@ -209,4 +213,11 @@ Return user specify tls.secretSync.enabled or default value based on the upgrade {{- false }} {{- end }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} + +{{/* +Determine if CRDs are used for identity allocation +*/}} +{{- define "identityAllocationCRD" }} + {{- list "crd" "doublewrite-readkvstore" "doublewrite-readcrd" | has .Values.identityAllocationMode }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-agent/clusterrole.yaml b/packages/system/cilium/charts/cilium/templates/cilium-agent/clusterrole.yaml index 6aef1b21..57b13447 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-agent/clusterrole.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-agent/clusterrole.yaml @@ -42,6 +42,9 @@ rules: - pods - endpoints - nodes +{{- if not $readSecretsOnlyFromSecretsNamespace }} + - secrets +{{- end }} verbs: - get - list @@ -87,19 +90,10 @@ rules: # until we figure out how to avoid "get" inside the preflight, and then # should be removed ideally. - get -{{- if not $readSecretsOnlyFromSecretsNamespace }} -- apiGroups: - - "" - resources: - - secrets - verbs: - - get -{{- end }} - apiGroups: - cilium.io resources: - ciliumloadbalancerippools - - ciliumbgppeeringpolicies - ciliumbgpnodeconfigs - ciliumbgpadvertisements - ciliumbgppeerconfigs diff --git a/packages/system/cilium/charts/cilium/templates/cilium-agent/daemonset.yaml b/packages/system/cilium/charts/cilium/templates/cilium-agent/daemonset.yaml index ddc6b905..fff1b384 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-agent/daemonset.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-agent/daemonset.yaml @@ -10,12 +10,13 @@ {{- $kubeProxyReplacement := (coalesce .Values.kubeProxyReplacement "false") -}} {{- $envoyDS := eq (include "envoyDaemonSetEnabled" .) "true" -}} +{{- $buildDaemonConfig := or (kindIs "invalid" .Values.daemon.configSources) (not (regexMatch "^config-map:[^,]+$" .Values.daemon.configSources)) -}} --- apiVersion: apps/v1 kind: DaemonSet metadata: - name: cilium + name: {{ .Values.name }} namespace: {{ include "cilium.namespace" . }} {{- with .Values.annotations }} annotations: @@ -56,22 +57,10 @@ spec: # ensure pods roll when configmap updates cilium.io/cilium-configmap-checksum: {{ include (print $.Template.BasePath "/cilium-configmap.yaml") . | sha256sum | quote }} {{- end }} - {{- if not .Values.securityContext.privileged }} - {{- if semverCompare "<1.30.0" (printf "%d.%d.0" (semver .Capabilities.KubeVersion.Version).Major (semver .Capabilities.KubeVersion.Version).Minor) }} - # Set app AppArmor's profile to "unconfined". The value of this annotation - # can be modified as long users know which profiles they have available - # in AppArmor. - container.apparmor.security.beta.kubernetes.io/cilium-agent: "unconfined" - container.apparmor.security.beta.kubernetes.io/clean-cilium-state: "unconfined" - {{- if .Values.cgroup.autoMount.enabled }} - container.apparmor.security.beta.kubernetes.io/mount-cgroup: "unconfined" - container.apparmor.security.beta.kubernetes.io/apply-sysctl-overwrites: "unconfined" - {{- end }} - {{- end }} - {{- end }} {{- with .Values.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} + kubectl.kubernetes.io/default-container: cilium-agent labels: k8s-app: cilium app.kubernetes.io/name: cilium-agent @@ -133,7 +122,7 @@ spec: httpGet: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} path: /healthz - port: {{ .Values.healthPort }} + port: health scheme: HTTP httpHeaders: - name: "brief" @@ -153,7 +142,7 @@ spec: httpGet: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} path: /healthz - port: {{ .Values.healthPort }} + port: health scheme: HTTP httpHeaders: - name: "brief" @@ -176,7 +165,7 @@ spec: httpGet: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} path: /healthz - port: {{ .Values.healthPort }} + port: health scheme: HTTP httpHeaders: - name: "brief" @@ -205,18 +194,33 @@ spec: resourceFieldRef: resource: limits.memory divisor: '1' + {{- if and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_HOST + valueFrom: + configMapKeyRef: + name: {{ .Values.k8sServiceHostRef.name }} + key: {{ .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_PORT + value: {{ include "k8sServicePort" . }} + {{- end }} {{- if .Values.k8sServiceHost }} - name: KUBERNETES_SERVICE_HOST value: {{ include "k8sServiceHost" . }} - name: KUBERNETES_SERVICE_PORT value: {{ include "k8sServicePort" . }} {{- end }} + {{- if .Values.k8sClientExponentialBackoff.enabled }} + - name: KUBE_CLIENT_BACKOFF_BASE + value: {{ .Values.k8sClientExponentialBackoff.backoffBaseSeconds | quote }} + - name: KUBE_CLIENT_BACKOFF_DURATION + value: {{ .Values.k8sClientExponentialBackoff.backoffMaxDurationSeconds | quote }} + {{- end }} {{- with .Values.extraEnv }} {{- toYaml . | trim | nindent 8 }} {{- end }} {{- if .Values.cni.install }} lifecycle: - {{- if ne .Values.cni.chainingMode "aws-cni" }} + {{- if and .Values.cni.iptablesRemoveAWSRules (ne .Values.cni.chainingMode "aws-cni") }} postStart: exec: command: @@ -234,12 +238,17 @@ spec: resources: {{- toYaml . | trim | nindent 10 }} {{- end }} - {{- if or .Values.prometheus.enabled (or .Values.hubble.metrics.enabled .Values.hubble.metrics.dynamic.enabled) }} ports: + - name: health + containerPort: {{ .Values.healthPort }} + hostPort: {{ .Values.healthPort }} + protocol: TCP + {{- if .Values.hubble.enabled }} - name: peer-service containerPort: {{ .Values.hubble.peerService.targetPort }} hostPort: {{ .Values.hubble.peerService.targetPort }} protocol: TCP + {{- end }} {{- if .Values.prometheus.enabled }} - name: prometheus containerPort: {{ .Values.prometheus.port }} @@ -251,7 +260,7 @@ spec: hostPort: {{ .Values.envoy.prometheus.port }} protocol: TCP {{- end }} - {{- if and .Values.envoy.debug.admin.port (not $envoyDS) }} + {{- if and .Values.envoy.debug.admin.enabled .Values.envoy.debug.admin.port (not $envoyDS) }} - name: envoy-admin containerPort: {{ .Values.envoy.debug.admin.port }} hostPort: {{ .Values.envoy.debug.admin.port }} @@ -264,7 +273,6 @@ spec: hostPort: {{ .Values.hubble.metrics.port }} protocol: TCP {{- end }} - {{- end }} securityContext: {{- if .Values.securityContext.privileged }} privileged: true @@ -303,7 +311,6 @@ spec: - mountPath: /host/proc/sys/kernel name: host-proc-sys-kernel {{- end}} - {{- if .Values.bpf.autoMount.enabled }} - name: bpf-maps mountPath: /sys/fs/bpf {{- if .Values.securityContext.privileged }} @@ -315,7 +322,6 @@ spec: # in Cilium. mountPropagation: HostToContainer {{- end}} - {{- end }} {{- if not (contains "/run/cilium/cgroupv2" .Values.cgroup.hostRoot) }} # Check for duplicate mounts before mounting - name: cilium-cgroup @@ -361,6 +367,10 @@ spec: - name: cilium-ipsec-secrets mountPath: {{ .Values.encryption.ipsec.mountPath }} {{- end }} + {{- if and .Values.encryption.enabled (eq .Values.encryption.type "ztunnel") }} + - name: cilium-ztunnel-secrets + mountPath: /etc/ztunnel + {{- end }} {{- if .Values.kubeConfigPath }} - name: kube-config mountPath: {{ .Values.kubeConfigPath }} @@ -376,8 +386,14 @@ spec: mountPath: /var/lib/cilium/tls/hubble readOnly: true {{- end }} + {{- if $buildDaemonConfig }} - name: tmp mountPath: /tmp + {{- else }} + - name: cilium-config-path + mountPath: /tmp/cilium/config-map + readOnly: true + {{- end }} {{- range .Values.extraHostPathMounts }} - name: {{ .name }} mountPath: {{ .mountPath }} @@ -399,6 +415,7 @@ spec: {{- with .Values.extraVolumeMounts }} {{- toYaml . | nindent 8 }} {{- end }} + {{- include "cilium-agent.volumeMounts.extra" . | nindent 8 }} {{- if .Values.monitor.enabled }} - name: cilium-monitor image: {{ include "cilium.image" .Values.image | quote }} @@ -432,9 +449,14 @@ spec: {{- toYaml .Values.extraContainers | nindent 6 }} {{- end }} initContainers: + {{- if $buildDaemonConfig }} - name: config image: {{ include "cilium.image" .Values.image | quote }} imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- with .Values.initResources }} + resources: + {{- toYaml . | trim | nindent 10 }} + {{- end }} command: - cilium-dbg - build-config @@ -450,6 +472,9 @@ spec: {{- if .Values.kubeConfigPath }} - "--k8s-kubeconfig-path={{ .Values.kubeConfigPath }}" {{- end }} + {{- if hasKey .Values.k8s "apiServerURLs" }} + - "--k8s-api-server-urls={{ .Values.k8s.apiServerURLs }}" + {{- end }} env: - name: K8S_NODE_NAME valueFrom: @@ -461,6 +486,15 @@ spec: fieldRef: apiVersion: v1 fieldPath: metadata.namespace + {{- if and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_HOST + valueFrom: + configMapKeyRef: + name: {{ .Values.k8sServiceHostRef.name }} + key: {{ .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_PORT + value: {{ include "k8sServicePort" . }} + {{- end }} {{- if .Values.k8sServiceHost }} - name: KUBERNETES_SERVICE_HOST value: {{ include "k8sServiceHost" . }} @@ -482,6 +516,17 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} terminationMessagePolicy: FallbackToLogsOnError + securityContext: + {{- if .Values.securityContext.privileged }} + privileged: true + {{- else }} + capabilities: + add: + - NET_ADMIN + drop: + - ALL + {{- end}} + {{- end }} {{- if .Values.cgroup.autoMount.enabled }} # Required to mount cgroup2 filesystem on the underlying Kubernetes node. # We use nsenter command with host's cgroup and mount namespaces enabled. @@ -493,12 +538,15 @@ spec: value: {{ .Values.cgroup.hostRoot }} - name: BIN_PATH value: {{ .Values.cni.binPath }} - {{- with .Values.cgroup.autoMount.resources }} + {{- if .Values.cgroup.autoMount.resources }} resources: - {{- toYaml . | trim | nindent 10 }} + {{- toYaml .Values.cgroup.autoMount.resources | trim | nindent 10 }} + {{- else if .Values.initResources }} + resources: + {{- toYaml .Values.initResources | trim | nindent 10 }} {{- end }} command: - - sh + - bash - -ec # The statically linked Go program binary is invoked to avoid any # dependency on utilities like sh and mount that can be missing on certain @@ -544,7 +592,7 @@ spec: - name: BIN_PATH value: {{ .Values.cni.binPath }} command: - - sh + - bash - -ec # The statically linked Go program binary is invoked to avoid any # dependency on utilities like sh that can be missing on certain @@ -598,12 +646,10 @@ spec: terminationMessagePolicy: FallbackToLogsOnError securityContext: privileged: true - {{- if and .Values.bpf.autoMount.enabled }} volumeMounts: - name: bpf-maps mountPath: /sys/fs/bpf mountPropagation: Bidirectional - {{- end }} {{- end }} {{- if and .Values.nodeinit.enabled .Values.nodeinit.bootstrapFile }} - name: wait-for-node-init @@ -614,7 +660,7 @@ spec: {{- toYaml . | trim | nindent 10 }} {{- end }} command: - - sh + - bash - -c - | until test -s {{ (print "/tmp/cilium-bootstrap.d/" (.Values.nodeinit.bootstrapFile | base)) | quote }}; do @@ -650,6 +696,15 @@ spec: name: cilium-config key: write-cni-conf-when-ready optional: true + {{- if and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_HOST + valueFrom: + configMapKeyRef: + name: {{ .Values.k8sServiceHostRef.name }} + key: {{ .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_PORT + value: {{ include "k8sServicePort" . }} + {{- end }} {{- if .Values.k8sServiceHost }} - name: KUBERNETES_SERVICE_HOST value: {{ include "k8sServiceHost" . }} @@ -677,10 +732,8 @@ spec: - ALL {{- end}} volumeMounts: - {{- if .Values.bpf.autoMount.enabled}} - name: bpf-maps mountPath: /sys/fs/bpf - {{- end }} # Required to mount cgroup filesystem from the host to cilium agent pod - name: cilium-cgroup mountPath: {{ .Values.cgroup.hostRoot }} @@ -768,9 +821,7 @@ spec: automountServiceAccountToken: {{ .Values.serviceAccounts.cilium.automount }} terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} hostNetwork: true - {{- if .Values.dnsPolicy }} - dnsPolicy: {{ .Values.dnsPolicy }} - {{- end }} + {{- include "cilium-agent.dnsPolicy" . | nindent 6 }} {{- if (eq .Values.scheduling.mode "anti-affinity") }} {{- with .Values.affinity }} affinity: @@ -787,7 +838,7 @@ spec: {{- end }} {{- if and .Values.clustermesh.config.enabled (not (and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled )) }} hostAliases: - {{- range $cluster := .Values.clustermesh.config.clusters }} + {{- range $_, $cluster := (include "clustermesh-clusters" . | fromJson) }} {{- range $ip := $cluster.ips }} - ip: {{ $ip }} hostnames: [ "{{ $cluster.name }}.{{ $.Values.clustermesh.config.domain }}" ] @@ -795,9 +846,20 @@ spec: {{- end }} {{- end }} volumes: - # For sharing configuration between the "config" initContainer and the agent + {{- if $buildDaemonConfig }} + # For sharing configuration between the "config" initContainer and the agent - name: tmp + {{- if .Values.tmpVolume }} + {{- toYaml .Values.tmpVolume | nindent 8 }} + {{- else }} emptyDir: {} + {{- end }} + {{- else }} + # To read the configuration from the config map + - name: cilium-config-path + configMap: + name: {{ trimPrefix "config-map:" .Values.daemon.configSources }} + {{- end }} # To keep state between restarts / upgrades - name: cilium-run hostPath: @@ -808,13 +870,11 @@ spec: hostPath: path: /var/run/netns type: DirectoryOrCreate - {{- if .Values.bpf.autoMount.enabled }} # To keep state between restarts / upgrades for bpf maps - name: bpf-maps hostPath: path: /sys/fs/bpf type: DirectoryOrCreate - {{- end }} {{- if or .Values.cgroup.autoMount.enabled .Values.sysctlfix.enabled }} # To mount cgroup2 filesystem on the host or apply sysctlfix - name: hostproc @@ -960,6 +1020,11 @@ spec: secret: secretName: {{ .Values.encryption.ipsec.secretName }} {{- end }} + {{- if and .Values.encryption.enabled (eq .Values.encryption.type "ztunnel") }} + - name: cilium-ztunnel-secrets + secret: + secretName: cilium-ztunnel-secrets + {{- end }} {{- if .Values.cni.configMap }} - name: cni-configuration configMap: @@ -1008,7 +1073,7 @@ spec: defaultMode: 0400 sources: - secret: - name: {{ .Values.hubble.tls.server.existingSecret | default "hubble-metrics-server-certs" }} + name: {{ .Values.hubble.metrics.tls.server.existingSecret | default "hubble-metrics-server-certs" }} optional: true items: - key: tls.crt @@ -1063,4 +1128,5 @@ spec: {{- with .Values.extraVolumes }} {{- toYaml . | nindent 6 }} {{- end }} + {{- include "cilium-agent.volumes.extra" . | nindent 6 }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-agent/role.yaml b/packages/system/cilium/charts/cilium/templates/cilium-agent/role.yaml index 0a2b43d1..df60d89b 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-agent/role.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-agent/role.yaml @@ -120,7 +120,7 @@ rules: - watch {{- end}} -{{- if and .Values.operator.enabled .Values.serviceAccounts.operator.create $readSecretsOnlyFromSecretsNamespace .Values.tls.secretsNamespace.name }} +{{- if and .Values.agent (not .Values.preflight.enabled) .Values.serviceAccounts.cilium.create $readSecretsOnlyFromSecretsNamespace .Values.tls.secretsNamespace.name }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role @@ -130,7 +130,7 @@ metadata: {{- with .Values.annotations }} annotations: {{- toYaml . | nindent 4 }} - {{- end }} + {{- end }} labels: app.kubernetes.io/part-of: cilium rules: diff --git a/packages/system/cilium/charts/cilium/templates/cilium-agent/rolebinding.yaml b/packages/system/cilium/charts/cilium/templates/cilium-agent/rolebinding.yaml index fc4f35ec..5caf2f15 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-agent/rolebinding.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-agent/rolebinding.yaml @@ -27,7 +27,7 @@ subjects: {{- end}} {{- if and .Values.agent (not .Values.preflight.enabled) .Values.serviceAccounts.cilium.create .Values.ingressController.enabled .Values.ingressController.secretsNamespace.name}} ---- +--- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: @@ -126,7 +126,7 @@ subjects: namespace: {{ include "cilium.namespace" . }} {{- end}} -{{- if and (not .Values.preflight.enabled) $readSecretsOnlyFromSecretsNamespace .Values.tls.secretsNamespace.name }} +{{- if and .Values.agent (not .Values.preflight.enabled) .Values.serviceAccounts.cilium.create $readSecretsOnlyFromSecretsNamespace .Values.tls.secretsNamespace.name }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding @@ -145,5 +145,5 @@ roleRef: subjects: - kind: ServiceAccount name: {{ .Values.serviceAccounts.cilium.name | quote }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cilium.namespace" . }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-agent/servicemonitor.yaml b/packages/system/cilium/charts/cilium/templates/cilium-agent/servicemonitor.yaml index 09d11a5d..10be4cce 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-agent/servicemonitor.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-agent/servicemonitor.yaml @@ -7,6 +7,7 @@ metadata: namespace: {{ .Values.prometheus.serviceMonitor.namespace | default (include "cilium.namespace" .) }} labels: app.kubernetes.io/part-of: cilium + app.kubernetes.io/name: cilium-agent {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} @@ -49,6 +50,9 @@ spec: {{- if and .Values.envoy.enabled .Values.envoy.prometheus.serviceMonitor.enabled }} - port: envoy-metrics interval: {{ .Values.envoy.prometheus.serviceMonitor.interval | quote }} + {{- if .Values.envoy.prometheus.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.envoy.prometheus.serviceMonitor.scrapeTimeout | quote }} + {{- end }} honorLabels: true path: /metrics {{- with .Values.envoy.prometheus.serviceMonitor.relabelings }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-ca-secret.yaml b/packages/system/cilium/charts/cilium/templates/cilium-ca-secret.yaml index f5a6674d..91569863 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-ca-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-ca-secret.yaml @@ -1,5 +1,5 @@ {{- if or - (and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm")) + (and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm")) (and (or .Values.agent .Values.hubble.relay.enabled .Values.hubble.ui.enabled) .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "helm")) (and .Values.tls.ca.key .Values.tls.ca.cert) -}} @@ -11,8 +11,13 @@ kind: Secret metadata: name: {{ .commonCASecretName }} namespace: {{ include "cilium.namespace" . }} - {{- with .Values.commonLabels }} labels: + {{- with .Values.commonLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + cilium.io/helm-template-non-idempotent: "true" + {{- with .Values.nonIdempotentAnnotations }} + annotations: {{- toYaml . | nindent 4 }} {{- end }} data: diff --git a/packages/system/cilium/charts/cilium/templates/cilium-configmap.yaml b/packages/system/cilium/charts/cilium/templates/cilium-configmap.yaml index 1b0a1645..5d76944d 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-configmap.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-configmap.yaml @@ -1,4 +1,4 @@ -{{- if and ( or (.Values.agent) (.Values.operator.enabled) .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) (not .Values.preflight.enabled) }} +{{- if and ( or (.Values.agent) (.Values.operator.enabled) .Values.clustermesh.useAPIServer) (not .Values.preflight.enabled) }} {{- /* Default values with backwards compatibility */ -}} {{- $defaultBpfMapDynamicSizeRatio := 0.0 -}} {{- $defaultBpfMasquerade := "false" -}} @@ -15,6 +15,7 @@ {{- $defaultK8sClientQPS := 5 -}} {{- $defaultK8sClientBurst := 10 -}} {{- $defaultDNSProxyEnableTransparentMode := "false" -}} +{{- $defaultEnableIPv4Masquerade := "true" -}} {{- $envoyDS := eq (include "envoyDaemonSetEnabled" .) "true" -}} {{- $readSecretsOnlyFromSecretsNamespace := eq (include "readSecretsOnlyFromSecretsNamespace" .) "true" -}} {{- $secretSyncEnabled := eq (include "secretSyncEnabled" .) "true" -}} @@ -32,12 +33,6 @@ {{- end }} {{- $defaultBpfCtTcpMax = 0 -}} {{- $defaultBpfCtAnyMax = 0 -}} - {{- $defaultKubeProxyReplacement = "probe" -}} -{{- end -}} - -{{- /* Default values when 1.9 was initially deployed */ -}} -{{- if semverCompare ">=1.9" (default "1.9" .Values.upgradeCompatibility) -}} - {{- $defaultKubeProxyReplacement = "probe" -}} {{- end -}} {{- /* Default values when 1.10 was initially deployed */ -}} @@ -51,7 +46,6 @@ {{- if .Values.azure.enabled }} {{- $azureUsePrimaryAddress = "false" -}} {{- end }} - {{- $defaultKubeProxyReplacement = "disabled" -}} {{- $defaultDNSProxyEnableTransparentMode = "true" -}} {{- end -}} @@ -61,7 +55,19 @@ {{- $defaultKubeProxyReplacement = "false" -}} {{- end -}} +{{- /* Default values when 1.18 was initially deployed */ -}} +{{- if semverCompare ">=1.18" (default "1.18" .Values.upgradeCompatibility) -}} + {{- /* defaultIPv4Masquerad in ENI mode for 1.18 needed to override earlier version defaults set above when upgradeCompatibility is not specified */ -}} + {{- if .Values.eni.enabled }} + {{- $defaultEnableIPv4Masquerade = "false" -}} + # Will also do this for ipv6 when ENI mode works with ipv6. + {{- end }} +{{- end -}} {{- $ipam := (coalesce .Values.ipam.mode $defaultIPAM) -}} +{{- if .Values.eni.enabled }} + {{- $ipam = "eni" -}} +{{- end }} + {{- $bpfCtTcpMax := (coalesce .Values.bpf.ctTcpMax $defaultBpfCtTcpMax) -}} {{- $bpfCtAnyMax := (coalesce .Values.bpf.ctAnyMax $defaultBpfCtAnyMax) -}} {{- $stringValueKPR := (toString .Values.kubeProxyReplacement) -}} @@ -177,6 +183,10 @@ data: debug-verbose: "{{ .Values.debug.verbose }}" {{- end }} +{{- if hasKey .Values.debug "metricsSamplingInterval" }} + metrics-sampling-interval: "{{ .Values.debug.metricsSamplingInterval }}" +{{- end }} + {{- if ne (int .Values.healthPort) 9879 }} # Set the TCP port for the agent health status API. This is not the port used # for cilium-health. @@ -245,6 +255,14 @@ data: operator-prometheus-serve-addr: ":{{ .Values.operator.prometheus.port }}" enable-metrics: "true" {{- end }} +{{- if and .Values.operator.prometheus.enabled .Values.operator.prometheus.tls.enabled }} + operator-prometheus-enable-tls: "true" + operator-prometheus-tls-cert-file: /var/lib/cilium/tls/prometheus/server.crt + operator-prometheus-tls-key-file: /var/lib/cilium/tls/prometheus/server.key + {{- if .Values.operator.prometheus.tls.server.mtls.enabled }} + operator-prometheus-tls-client-ca-files: /var/lib/cilium/tls/prometheus/client-ca.crt + {{- end }} +{{- end }} {{- if .Values.operator.skipCRDCreation }} skip-crd-creation: "true" @@ -378,7 +396,7 @@ data: bpf-events-default-burst-limit: {{ .Values.bpf.events.default.burstLimit | quote }} {{- end}} -{{- if .Values.bpf.mapDynamicSizeRatio }} +{{- if ne 0.0 ( .Values.bpf.mapDynamicSizeRatio | float64) }} # Specifies the ratio (0.0-1.0] of total system memory to use for dynamic # sizing of the TCP CT, non-TCP CT, NAT and policy BPF maps. bpf-map-dynamic-size-ratio: {{ .Values.bpf.mapDynamicSizeRatio | quote }} @@ -443,6 +461,17 @@ data: # policy map (per endpoint) bpf-policy-map-max: "{{ .Values.bpf.policyMapMax | int }}" {{- end }} +{{- if has (kindOf .Values.bpf.policyMapPressureMetricsThreshold) (list "int64" "float64") }} + bpf-policy-map-pressure-metrics-threshold: {{ .Values.bpf.policyMapPressureMetricsThreshold | quote }} +{{- end }} +{{- if .Values.endpointPolicyUpdateTimeoutDuration }} + endpoint-policy-update-timeout: {{ .Values.endpointPolicyUpdateTimeoutDuration | quote }} +{{- end }} +{{- if hasKey .Values.bpf "policyStatsMapMax" }} + # bpf-policy-stats-map-max specifies the maximum number of entries in global + # policy stats map + bpf-policy-stats-map-max: "{{ .Values.bpf.policyStatsMapMax | int }}" +{{- end }} {{- if hasKey .Values.bpf "lbMapMax" }} # bpf-lb-map-max specifies the maximum number of entries in bpf lb service, # backend and affinity maps. @@ -484,10 +513,10 @@ data: preallocate-bpf-maps: "{{ .Values.bpf.preallocateMaps }}" # Name of the cluster. Only relevant when building a mesh of clusters. - cluster-name: {{ .Values.cluster.name }} + cluster-name: {{ .Values.cluster.name | quote }} {{- if hasKey .Values.cluster "id" }} - # Unique ID of the cluster. Must be unique across all conneted clusters and + # Unique ID of the cluster. Must be unique across all connected clusters and # in the range of 1 and 255. Only relevant when building a mesh of clusters. cluster-id: "{{ .Values.cluster.id }}" {{- end }} @@ -508,20 +537,42 @@ data: {{- end }} {{- end }} - routing-mode: {{ .Values.routingMode | default (ternary "native" "tunnel" .Values.gke.enabled) | quote }} + routing-mode: {{ .Values.routingMode | default (ternary "native" "tunnel" (or .Values.eni.enabled .Values.gke.enabled)) | quote }} tunnel-protocol: {{ .Values.tunnelProtocol | default "vxlan" | quote }} +{{- if eq .Values.routingMode "native" }} + {{- if and .Values.ipv4.enabled .Values.enableIPv4Masquerade (not .Values.ipMasqAgent.enabled) }} + {{- if and (ne $ipam "eni") (ne $ipam "alibabacloud") }} + {{- if not .Values.ipv4NativeRoutingCIDR }} + {{- fail " ipv4NativeRoutingCIDR must be set when routingMode is native"}} + {{- end }} + {{- end }} + {{- end }} + {{- if and .Values.ipv6.enabled .Values.enableIPv6Masquerade (not .Values.ipMasqAgent.enabled) }} + {{- if not .Values.ipv6NativeRoutingCIDR }} + {{- fail "ipv6NativeRoutingCIDR must be set when routingMode is native" }} + {{- end }} + {{- end }} +{{- end }} + {{- if .Values.tunnelPort }} tunnel-port: {{ .Values.tunnelPort | quote }} {{- end }} {{- if .Values.tunnelSourcePortRange }} tunnel-source-port-range: {{ .Values.tunnelSourcePortRange | quote }} {{- end }} +{{- if .Values.underlayProtocol }} + underlay-protocol: {{ .Values.underlayProtocol | quote }} +{{- end }} {{- if .Values.serviceNoBackendResponse }} service-no-backend-response: "{{ .Values.serviceNoBackendResponse }}" {{- end}} +{{- if .Values.policyDenyResponse }} + policy-deny-response: "{{ .Values.policyDenyResponse }}" +{{- end}} + {{- if .Values.MTU }} mtu: {{ .Values.MTU | quote }} {{- end }} @@ -531,9 +582,6 @@ data: enable-endpoint-routes: "true" {{- end }} auto-create-cilium-node-resource: "true" -{{- if .Values.eni.updateEC2AdapterLimitViaAPI }} - update-ec2-adapter-limit-via-api: "true" -{{- end }} {{- if .Values.eni.awsReleaseExcessIPs }} aws-release-excess-ips: "true" {{- end }} @@ -542,6 +590,35 @@ data: {{- end }} ec2-api-endpoint: {{ .Values.eni.ec2APIEndpoint | quote }} eni-tags: {{ .Values.eni.eniTags | toRawJson | quote }} +{{- if .Values.eni.nodeSpec }} + {{- if ne .Values.eni.nodeSpec.firstInterfaceIndex nil }} + eni-first-interface-index: {{ .Values.eni.nodeSpec.firstInterfaceIndex | quote }} + {{- end }} + {{- if .Values.eni.nodeSpec.subnetIDs }} + eni-subnet-ids: {{ .Values.eni.nodeSpec.subnetIDs | join "," | quote }} + {{- end }} + {{- if .Values.eni.nodeSpec.subnetTags }} + eni-subnet-tags: {{ .Values.eni.nodeSpec.subnetTags | join "," | quote }} + {{- end }} + {{- if .Values.eni.nodeSpec.securityGroups }} + eni-security-groups: {{ .Values.eni.nodeSpec.securityGroups | join "," | quote }} + {{- end }} + {{- if .Values.eni.nodeSpec.securityGroupTags }} + eni-security-group-tags: {{ .Values.eni.nodeSpec.securityGroupTags | join "," | quote }} + {{- end }} + {{- if .Values.eni.nodeSpec.excludeInterfaceTags }} + eni-exclude-interface-tags: {{ .Values.eni.nodeSpec.excludeInterfaceTags | join "," | quote }} + {{- end }} + {{- if .Values.eni.nodeSpec.usePrimaryAddress }} + eni-use-primary-address: "true" + {{- end }} + {{- if .Values.eni.nodeSpec.disablePrefixDelegation }} + eni-disable-prefix-delegation: "true" + {{- end }} + {{- if ne .Values.eni.nodeSpec.deleteOnTermination nil }} + eni-delete-on-termination: {{ .Values.eni.nodeSpec.deleteOnTermination | quote }} + {{- end }} +{{- end }} {{- if .Values.eni.subnetIDsFilter }} subnet-ids-filter: {{ .Values.eni.subnetIDsFilter | join " " | quote }} {{- end }} @@ -567,17 +644,39 @@ data: {{- end }} azure-use-primary-address: {{ $azureUsePrimaryAddress | quote }} {{- end }} +{{- if .Values.azure.nodeSpec.azureInterfaceName }} + azure-interface-name: {{ .Values.azure.nodeSpec.azureInterfaceName | quote }} +{{- end }} {{- if .Values.alibabacloud.enabled }} enable-endpoint-routes: "true" auto-create-cilium-node-resource: "true" {{- end }} +{{- if .Values.alibabacloud.nodeSpec.vSwitches }} + alibabacloud-vswitches: {{ .Values.alibabacloud.nodeSpec.vSwitches | join "," | quote }} +{{- end }} +{{- if .Values.alibabacloud.nodeSpec.vSwitchTags }} + alibabacloud-vswitch-tags: {{ .Values.alibabacloud.nodeSpec.vSwitchTags | join "," | quote }} +{{- end }} +{{- if .Values.alibabacloud.nodeSpec.securityGroups }} + alibabacloud-security-groups: {{ .Values.alibabacloud.nodeSpec.securityGroups | join "," | quote }} +{{- end }} +{{- if .Values.alibabacloud.nodeSpec.securityGroupTags }} + alibabacloud-security-group-tags: {{ .Values.alibabacloud.nodeSpec.securityGroupTags | join "," | quote }} +{{- end }} {{- if hasKey .Values "l7Proxy" }} # Enables L7 proxy for L7 policy enforcement and visibility enable-l7-proxy: {{ .Values.l7Proxy | quote }} {{- end }} +{{- if hasKey .Values "standaloneDnsProxy" }} + {{- if .Values.standaloneDnsProxy.enabled }} + enable-standalone-dns-proxy: {{ .Values.standaloneDnsProxy.enabled | quote }} + standalone-dns-proxy-server-port: {{ .Values.standaloneDnsProxy.serverPort | quote }} + {{- end }} +{{- end }} + {{- if ne $cniChainingMode "none" }} # Enable chaining with another CNI plugin # @@ -602,7 +701,11 @@ data: {{- end }} {{- end }} - enable-ipv4-masquerade: {{ .Values.enableIPv4Masquerade | quote }} +{{- if (not (kindIs "invalid" .Values.enableIPv4Masquerade)) }} + enable-ipv4-masquerade: {{.Values.enableIPv4Masquerade | quote }} +{{- else }} + enable-ipv4-masquerade: {{ $defaultEnableIPv4Masquerade | quote }} +{{- end }} enable-ipv4-big-tcp: {{ .Values.enableIPv4BIGTCP | quote }} enable-ipv6-big-tcp: {{ .Values.enableIPv6BIGTCP | quote }} enable-ipv6-masquerade: {{ .Values.enableIPv6Masquerade | quote }} @@ -650,6 +753,8 @@ data: {{- if .Values.encryption.wireguard.persistentKeepalive }} wireguard-persistent-keepalive: {{ .Values.encryption.wireguard.persistentKeepalive | quote }} {{- end }} + {{- else if eq .Values.encryption.type "ztunnel" }} + enable-ztunnel: {{ .Values.encryption.enabled | quote }} {{- end }} {{- if .Values.encryption.nodeEncryption }} encrypt-node: {{ .Values.encryption.nodeEncryption | quote }} @@ -657,11 +762,20 @@ data: {{- end }} {{- if .Values.encryption.strictMode.enabled }} - enable-encryption-strict-mode: {{ .Values.encryption.strictMode.enabled | quote }} + # --- DEPRECATED: Please use encryption.strictMode.egress.enabled instead + enable-encryption-strict-mode-egress: {{ .Values.encryption.strictMode.enabled | quote }} + encryption-strict-egress-cidr: {{ .Values.encryption.strictMode.cidr | quote }} + encryption-strict-egress-allow-remote-node-identities: {{ .Values.encryption.strictMode.allowRemoteNodeIdentities | quote }} +{{- end }} - encryption-strict-mode-cidr: {{ .Values.encryption.strictMode.cidr | quote }} +{{- if .Values.encryption.strictMode.ingress.enabled }} + enable-encryption-strict-mode-ingress: {{ .Values.encryption.strictMode.ingress.enabled | quote }} +{{- end }} - encryption-strict-mode-allow-remote-node-identities: {{ .Values.encryption.strictMode.allowRemoteNodeIdentities | quote }} +{{- if .Values.encryption.strictMode.egress.enabled }} + enable-encryption-strict-mode-egress: {{ .Values.encryption.strictMode.egress.enabled | quote }} + encryption-strict-egress-cidr: {{ .Values.encryption.strictMode.egress.cidr | quote }} + encryption-strict-egress-allow-remote-node-identities: {{ .Values.encryption.strictMode.egress.allowRemoteNodeIdentities | quote }} {{- end }} enable-xt-socket-fallback: {{ .Values.enableXTSocketFallback | quote }} @@ -686,15 +800,16 @@ data: {{- if .Values.bandwidthManager.enabled }} enable-bandwidth-manager: {{ .Values.bandwidthManager.enabled | quote }} enable-bbr: {{ .Values.bandwidthManager.bbr | quote }} + enable-bbr-hostns-only: {{ .Values.bandwidthManager.bbrHostNamespaceOnly | quote }} {{- end }} {{- end }} -{{- if .Values.highScaleIPcache.enabled }} - enable-high-scale-ipcache: {{ .Values.highScaleIPcache.enabled | quote }} +{{ if or .Values.localRedirectPolicies.enabled .Values.localRedirectPolicy }} + enable-local-redirect-policy: "true" {{- end }} -{{- if hasKey .Values "localRedirectPolicy" }} - enable-local-redirect-policy: {{ .Values.localRedirectPolicy | quote }} +{{- if .Values.localRedirectPolicies.addressMatcherCIDRs }} + lrp-address-matcher-cidrs: {{ .Values.localRedirectPolicies.addressMatcherCIDRs | join "," | quote }} {{- end }} {{- if .Values.ipv4NativeRoutingCIDR }} @@ -725,20 +840,20 @@ data: devices: {{ join " " .Values.devices | quote }} {{- end }} -{{- if .Values.enableRuntimeDeviceDetection }} - enable-runtime-device-detection: "true" -{{- end }} - {{- if .Values.forceDeviceDetection }} force-device-detection: "true" {{- end }} kube-proxy-replacement: {{ $kubeProxyReplacement | quote }} -{{- if ne $kubeProxyReplacement "disabled" }} +{{- if eq $kubeProxyReplacement "true" }} kube-proxy-replacement-healthz-bind-address: {{ default "" .Values.kubeProxyReplacementHealthzBindAddr | quote}} {{- end }} +{{- if hasKey .Values "enableNoServiceEndpointsRoutable" }} + enable-no-service-endpoints-routable: {{ .Values.enableNoServiceEndpointsRoutable | quote }} +{{- end }} + {{- if $socketLB }} {{- if hasKey $socketLB "enabled" }} bpf-lb-sock: {{ $socketLB.enabled | quote }} @@ -754,20 +869,7 @@ data: {{- end }} {{- end }} -{{- if hasKey .Values "hostPort" }} -{{- if eq $kubeProxyReplacement "partial" }} - enable-host-port: {{ .Values.hostPort.enabled | quote }} -{{- end }} -{{- end }} -{{- if hasKey .Values "externalIPs" }} -{{- if eq $kubeProxyReplacement "partial" }} - enable-external-ips: {{ .Values.externalIPs.enabled | quote }} -{{- end }} -{{- end }} {{- if hasKey .Values "nodePort" }} -{{- if or (eq $kubeProxyReplacement "partial") (eq $kubeProxyReplacement "false") }} - enable-node-port: {{ .Values.nodePort.enabled | quote }} -{{- end }} {{- if hasKey .Values.nodePort "range" }} node-port-range: {{ get .Values.nodePort "range" | quote }} {{- end }} @@ -790,7 +892,7 @@ data: {{- end }} {{- if hasKey .Values "loadBalancer" }} {{- if .Values.loadBalancer.standalone }} - datapath-mode: lb-only + bpf-lb-only: {{ .Values.loadBalancer.standalone | quote }} {{- end }} {{- if hasKey .Values.loadBalancer "mode" }} bpf-lb-mode: {{ .Values.loadBalancer.mode | quote }} @@ -806,46 +908,40 @@ data: {{- end }} {{- if hasKey .Values.loadBalancer "serviceTopology" }} enable-service-topology: {{ .Values.loadBalancer.serviceTopology | quote }} -# {{- end }} - -{{- if hasKey .Values.loadBalancer "experimental" }} - enable-experimental-lb: {{ .Values.loadBalancer.experimental | quote }} {{- end }} -{{- if hasKey .Values.loadBalancer "protocolDifferentiation" }} - bpf-lb-proto-diff: {{ .Values.loadBalancer.protocolDifferentiation.enabled | quote }} {{- end }} -{{- end }} {{- if hasKey .Values.maglev "tableSize" }} bpf-lb-maglev-table-size: {{ .Values.maglev.tableSize | quote}} {{- end }} {{- if hasKey .Values.maglev "hashSeed" }} bpf-lb-maglev-hash-seed: {{ .Values.maglev.hashSeed | quote}} {{- end }} -{{- if .Values.sessionAffinity }} - enable-session-affinity: {{ .Values.sessionAffinity | quote }} -{{- end }} -{{- if .Values.svcSourceRangeCheck }} - enable-svc-source-range-check: {{ .Values.svcSourceRangeCheck | quote }} + +{{- if .Values.bpf.monitorTraceIPOption }} + ip-tracing-option-type: {{ .Values.bpf.monitorTraceIPOption | quote }} {{- end }} {{- if hasKey .Values "l2NeighDiscovery" }} {{- if hasKey .Values.l2NeighDiscovery "enabled" }} enable-l2-neigh-discovery: {{ .Values.l2NeighDiscovery.enabled | quote }} {{- end }} - arping-refresh-period: {{ include "validateDuration" .Values.l2NeighDiscovery.refreshPeriod | quote }} {{- end }} {{- if .Values.pprof.enabled }} pprof: {{ .Values.pprof.enabled | quote }} pprof-address: {{ .Values.pprof.address | quote }} pprof-port: {{ .Values.pprof.port | quote }} + pprof-mutex-profile-fraction: {{ .Values.pprof.mutexProfileFraction | quote }} + pprof-block-profile-rate: {{ .Values.pprof.blockProfileRate | quote }} {{- end }} {{- if .Values.operator.pprof.enabled }} operator-pprof: {{ .Values.operator.pprof.enabled | quote }} operator-pprof-address: {{ .Values.operator.pprof.address | quote }} operator-pprof-port: {{ .Values.operator.pprof.port | quote }} + operator-pprof-mutex-profile-fraction: {{ .Values.operator.pprof.mutexProfileFraction | quote }} + operator-pprof-block-profile-rate: {{ .Values.operator.pprof.blockProfileRate | quote }} {{- end }} {{- if .Values.logSystemLoad }} @@ -860,6 +956,9 @@ data: {{- if hasKey .Values.k8s "requireIPv6PodCIDR" }} k8s-require-ipv6-pod-cidr: {{ .Values.k8s.requireIPv6PodCIDR | quote }} {{- end }} +{{- if hasKey .Values.k8s "apiServerURLs" }} + k8s-api-server-urls: {{ .Values.k8s.apiServerURLs | quote }} +{{- end }} {{- if and .Values.endpointRoutes .Values.endpointRoutes.enabled }} enable-endpoint-routes: {{ .Values.endpointRoutes.enabled | quote }} {{- end }} @@ -919,6 +1018,12 @@ data: {{- end }} enable-node-selector-labels: {{ .Values.nodeSelectorLabels | quote }} +{{- if hasKey .Values "nodeLabels" }} + # To include or exclude matched resources from cilium node identity evaluation + # List of labels just like --labels flag (.Values.labels) + node-labels: {{ .Values.nodeLabels | quote }} +{{- end }} + {{- if hasKey .Values "synchronizeK8sNodes" }} synchronize-k8s-nodes: {{ .Values.synchronizeK8sNodes | quote }} {{- end }} @@ -944,6 +1049,10 @@ data: # Capacity of the buffer to store recent events. hubble-event-buffer-capacity: {{ .Values.hubble.eventBufferCapacity | quote }} {{- end }} +{{- if hasKey .Values.hubble "lostEventSendInterval" }} + # Interval to send lost events from Observer server. + hubble-lost-event-send-interval: {{ include "validateDuration" .Values.hubble.lostEventSendInterval | quote }} +{{- end }} {{- if or .Values.hubble.metrics.enabled .Values.hubble.metrics.dynamic.enabled}} # Address to expose Hubble metrics (e.g. ":7070"). Metrics server will be disabled if this # field is not set. @@ -971,6 +1080,9 @@ data: hubble-dynamic-metrics-config-path: /dynamic-metrics-config/dynamic-metrics.yaml {{- end }} +{{- if hasKey .Values.hubble.networkPolicyCorrelation "enabled" }} + hubble-network-policy-correlation-enabled: {{ .Values.hubble.networkPolicyCorrelation.enabled | quote }} +{{- end }} {{- if .Values.hubble.redact }} {{- if eq .Values.hubble.redact.enabled true }} # Enables hubble redact capabilities @@ -1002,11 +1114,16 @@ data: {{- end }} {{- end }} {{- if .Values.hubble.export }} - hubble-export-file-max-size-mb: {{ .Values.hubble.export.fileMaxSizeMb | quote }} - hubble-export-file-max-backups: {{ .Values.hubble.export.fileMaxBackups | quote }} +{{- /* hubble export configurations moved, use default to make upgrades seemless */ -}} +{{- /* TODO: remove default once v1.18 is released, remove warning in warnings.txt and add failure validation in validate.yaml */ -}} {{- if .Values.hubble.export.static.enabled }} + hubble-export-file-max-size-mb: {{ .Values.hubble.export.fileMaxSizeMb | default .Values.hubble.export.static.fileMaxSizeMb | quote }} + hubble-export-file-max-backups: {{ .Values.hubble.export.fileMaxBackups | default .Values.hubble.export.static.fileMaxBackups | quote }} + hubble-export-file-compress: {{ .Values.hubble.export.fileCompress | default .Values.hubble.export.static.fileCompress | quote }} + hubble-export-aggregation-interval: {{ include "validateDuration" .Values.hubble.export.aggregationInterval | default .Values.hubble.export.static.aggregationInterval | quote }} hubble-export-file-path: {{ .Values.hubble.export.static.filePath | quote }} hubble-export-fieldmask: {{ .Values.hubble.export.static.fieldMask | join " " | quote }} + hubble-export-fieldaggregate: {{ .Values.hubble.export.static.fieldAggregate | join " " | quote }} hubble-export-allowlist: {{ .Values.hubble.export.static.allowList | join " " | quote }} hubble-export-denylist: {{ .Values.hubble.export.static.denyList | join " " | quote }} {{- end }} @@ -1031,7 +1148,7 @@ data: hubble-drop-events-interval: {{ .Values.hubble.dropEventEmitter.interval | quote }} hubble-drop-events-reasons: {{ .Values.hubble.dropEventEmitter.reasons | join " " | quote }} {{- end }} -{{- if .Values.hubble.preferIpv6 }} +{{- if or (eq .Values.hubble.preferIpv6 true) (eq .Values.ipv4.enabled false) }} hubble-prefer-ipv6: "true" {{- end }} {{- if (not (kindIs "invalid" .Values.hubble.skipUnknownCGroupIDs)) }} @@ -1043,10 +1160,28 @@ data: disable-iptables-feeder-rules: {{ .Values.disableIptablesFeederRules | join " " | quote }} {{- end }} {{- if .Values.aksbyocni.enabled }} + {{- if or (not .Values.ipam.mode) (eq .Values.ipam.mode "cluster-pool") }} ipam: "cluster-pool" + {{- else if eq .Values.ipam.mode "multi-pool" }} + ipam: "multi-pool" + {{- end }} {{- else }} ipam: {{ $ipam | quote }} {{- end }} +{{- if .Values.ipam.nodeSpec }} + {{- if ne .Values.ipam.nodeSpec.ipamMinAllocate nil }} + ipam-min-allocate: {{ .Values.ipam.nodeSpec.ipamMinAllocate | quote }} + {{- end }} + {{- if ne .Values.ipam.nodeSpec.ipamPreAllocate nil }} + ipam-pre-allocate: {{ .Values.ipam.nodeSpec.ipamPreAllocate | quote }} + {{- end }} + {{- if ne .Values.ipam.nodeSpec.ipamMaxAllocate nil }} + ipam-max-allocate: {{ .Values.ipam.nodeSpec.ipamMaxAllocate | quote }} + {{- end }} + {{- if .Values.ipam.nodeSpec.ipamStaticIPTags }} + ipam-static-ip-tags: {{ .Values.ipam.nodeSpec.ipamStaticIPTags | join "," | quote }} + {{- end }} +{{- end }} {{- if .Values.ipam.multiPoolPreAllocation }} ipam-multi-pool-pre-allocation: {{ .Values.ipam.multiPoolPreAllocation | quote }} {{- end }} @@ -1057,18 +1192,10 @@ data: {{- if (eq $ipam "cluster-pool") }} {{- if .Values.ipv4.enabled }} - {{- if hasKey .Values.ipam.operator "clusterPoolIPv4PodCIDR" }} - {{- /* ipam.operator.clusterPoolIPv4PodCIDR removed in v1.14, remove this failsafe around v1.17 */ -}} - {{- fail "Value ipam.operator.clusterPoolIPv4PodCIDR removed, use ipam.operator.clusterPoolIPv4PodCIDRList instead" }} - {{- end }} cluster-pool-ipv4-cidr: {{ .Values.ipam.operator.clusterPoolIPv4PodCIDRList | join " " | quote }} cluster-pool-ipv4-mask-size: {{ .Values.ipam.operator.clusterPoolIPv4MaskSize | quote }} {{- end }} {{- if .Values.ipv6.enabled }} - {{- if hasKey .Values.ipam.operator "clusterPoolIPv6PodCIDR" }} - {{- /* ipam.operator.clusterPoolIPv6PodCIDR removed in v1.14, remove this failsafe around v1.17 */ -}} - {{- fail "Value ipam.operator.clusterPoolIPv6PodCIDR removed, use ipam.operator.clusterPoolIPv6PodCIDRList instead" }} - {{- end }} cluster-pool-ipv6-cidr: {{ .Values.ipam.operator.clusterPoolIPv6PodCIDRList | join " " | quote }} cluster-pool-ipv6-mask-size: {{ .Values.ipam.operator.clusterPoolIPv6MaskSize | quote }} {{- end }} @@ -1108,7 +1235,7 @@ data: {{- end }} {{- if .Values.egressGateway.enabled }} - enable-ipv4-egress-gateway: "true" + enable-egress-gateway: "true" {{- end }} {{- if hasKey .Values.egressGateway "reconciliationTriggerInterval" }} egress-gateway-reconciliation-trigger-interval: {{ .Values.egressGateway.reconciliationTriggerInterval | quote }} @@ -1137,20 +1264,11 @@ data: crd-wait-timeout: {{ include "validateDuration" .Values.crdWaitTimeout | quote }} {{- end }} -{{- if .Values.enableK8sEndpointSlice }} - enable-k8s-endpoint-slice: {{ .Values.enableK8sEndpointSlice | quote }} -{{- end }} - {{- if hasKey .Values.k8s "serviceProxyName" }} # Configure service proxy name for Cilium. k8s-service-proxy-name: {{ .Values.k8s.serviceProxyName | quote }} {{- end }} -{{- if and .Values.customCalls .Values.customCalls.enabled }} - # Enable tail call hooks for custom eBPF programs. - enable-custom-calls: {{ .Values.customCalls.enabled | quote }} -{{- end }} - {{- if .Values.l2announcements.enabled }} # Enable L2 announcements enable-l2-announcements: {{ .Values.l2announcements.enabled | quote }} @@ -1167,19 +1285,28 @@ data: {{- if .Values.l2podAnnouncements.enabled }} enable-l2-pod-announcements: {{ .Values.l2podAnnouncements.enabled | quote }} + {{- if .Values.l2podAnnouncements.interfacePattern }} + l2-pod-announcements-interface-pattern: {{ .Values.l2podAnnouncements.interfacePattern | quote }} + {{- else }} l2-pod-announcements-interface: {{ .Values.l2podAnnouncements.interface | quote }} + {{- end }} {{- end }} {{- if .Values.bgpControlPlane.enabled }} enable-bgp-control-plane: "true" bgp-secrets-namespace: {{ .Values.bgpControlPlane.secretsNamespace.name | quote }} enable-bgp-control-plane-status-report: {{ .Values.bgpControlPlane.statusReport.enabled | quote }} + bgp-router-id-allocation-mode: {{ .Values.bgpControlPlane.routerIDAllocation.mode | quote }} + bgp-router-id-allocation-ip-pool: {{ .Values.bgpControlPlane.routerIDAllocation.ipPool | quote }} + enable-bgp-legacy-origin-attribute: {{ .Values.bgpControlPlane.legacyOriginAttribute.enabled | quote }} {{- end }} {{- if .Values.pmtuDiscovery.enabled }} enable-pmtu-discovery: "true" {{- end }} + packetization-layer-pmtud-mode: {{ .Values.pmtuDiscovery.packetizationLayerPMTUDMode | quote }} + {{- if not .Values.securityContext.privileged }} procfs: "/host/proc" {{- end }} @@ -1201,19 +1328,14 @@ data: disable-external-ip-mitigation: {{ .Values.bpf.disableExternalIPMitigation | quote }} {{- end }} -{{- if or .Values.ciliumEndpointSlice.enabled .Values.enableCiliumEndpointSlice }} +{{- if .Values.ciliumEndpointSlice.enabled }} enable-cilium-endpoint-slice: "true" {{- if .Values.ciliumEndpointSlice.rateLimits }} ces-rate-limits: {{ .Values.ciliumEndpointSlice.rateLimits | toJson | quote }} {{- end }} - {{- if .Values.ciliumEndpointSlice.sliceMode }} - ces-slice-mode: {{ .Values.ciliumEndpointSlice.sliceMode | quote }} - {{- end }} {{- end }} -{{- if hasKey .Values "enableK8sTerminatingEndpoint" }} - enable-k8s-terminating-endpoint: {{ .Values.enableK8sTerminatingEndpoint | quote }} -{{- end }} + identity-management-mode: {{ .Values.identityManagementMode | quote }} {{- if hasKey .Values.sctp "enabled" }} enable-sctp: {{ .Values.sctp.enabled | quote }} @@ -1259,11 +1381,16 @@ data: {{- end }} {{- if .Values.operator.unmanagedPodWatcher.restart }} - unmanaged-pod-watcher-interval: {{ .Values.operator.unmanagedPodWatcher.intervalSeconds | quote }} + {{- $interval := .Values.operator.unmanagedPodWatcher.intervalSeconds }} + unmanaged-pod-watcher-interval: {{ printf "%ds" (int $interval) | quote }} {{- else }} unmanaged-pod-watcher-interval: "0" {{- end }} +{{- if ne .Values.operator.unmanagedPodWatcher.selector nil }} + pod-restart-selector: {{ .Values.operator.unmanagedPodWatcher.selector }} +{{- end }} + {{- if .Values.dnsProxy }} {{- if hasKey .Values.dnsProxy "enableTransparentMode" }} # explicit setting gets precedence @@ -1302,6 +1429,7 @@ data: {{- if .Values.dnsProxy.proxyResponseMaxDelay }} tofqdns-proxy-response-max-delay: {{ .Values.dnsProxy.proxyResponseMaxDelay | quote }} {{- end }} + tofqdns-preallocate-identities: {{ .Values.dnsProxy.preAllocateIdentities | quote }} {{- end }} {{- if hasKey .Values "agentNotReadyTaintKey" }} @@ -1332,15 +1460,24 @@ data: proxy-xff-num-trusted-hops-egress: {{ .Values.envoy.xffNumTrustedHopsL7PolicyEgress | quote }} proxy-connect-timeout: {{ .Values.envoy.connectTimeoutSeconds | quote }} proxy-initial-fetch-timeout: {{ .Values.envoy.initialFetchTimeoutSeconds | quote }} + proxy-max-active-downstream-connections: {{ .Values.envoy.maxGlobalDownstreamConnections | quote }} proxy-max-requests-per-connection: {{ .Values.envoy.maxRequestsPerConnection | quote }} proxy-max-connection-duration-seconds: {{ .Values.envoy.maxConnectionDurationSeconds | quote }} proxy-idle-timeout-seconds: {{ .Values.envoy.idleTimeoutDurationSeconds | quote }} proxy-max-concurrent-retries: {{ .Values.envoy.maxConcurrentRetries | quote }} + proxy-use-original-source-address: {{ .Values.envoy.useOriginalSourceAddress | quote }} + proxy-cluster-max-connections: {{ .Values.envoy.clusterMaxConnections | quote }} + proxy-cluster-max-requests: {{ .Values.envoy.clusterMaxRequests | quote }} http-retry-count: {{ .Values.envoy.httpRetryCount | quote }} + http-stream-idle-timeout: {{ .Values.envoy.streamIdleTimeoutDurationSeconds | quote }} external-envoy-proxy: {{ include "envoyDaemonSetEnabled" . | quote }} envoy-base-id: {{ .Values.envoy.baseID | quote }} +{{- if .Values.envoy.httpUpstreamLingerTimeout }} + envoy-http-upstream-linger-timeout: {{ .Values.envoy.httpUpstreamLingerTimeout | quote }} +{{- end }} + {{- if .Values.envoy.policyRestoreTimeoutDuration }} envoy-policy-restore-timeout: {{ .Values.envoy.policyRestoreTimeoutDuration | quote }} {{- end }} @@ -1359,12 +1496,14 @@ data: {{- if hasKey .Values.clustermesh "maxConnectedClusters" }} max-connected-clusters: {{ .Values.clustermesh.maxConnectedClusters | quote }} {{- end }} + clustermesh-cache-ttl: {{ .Values.clustermesh.cacheTTL | quote }} clustermesh-enable-endpoint-sync: {{ .Values.clustermesh.enableEndpointSliceSynchronization | quote }} - clustermesh-enable-mcs-api: {{ .Values.clustermesh.enableMCSAPISupport | quote }} + clustermesh-enable-mcs-api: {{ (or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport) | quote }} + clustermesh-mcs-api-install-crds: {{ .Values.clustermesh.mcsapi.installCRDs | quote }} + policy-default-local-cluster: {{ .Values.clustermesh.policyDefaultLocalCluster | quote }} nat-map-stats-entries: {{ .Values.nat.mapStatsEntries | quote }} nat-map-stats-interval: {{ .Values.nat.mapStatsInterval | quote }} - enable-internal-traffic-policy: {{ .Values.enableInternalTrafficPolicy | quote }} enable-lb-ipam: {{ .Values.enableLBIPAM | quote }} enable-non-default-deny-policies: {{ .Values.enableNonDefaultDenyPolicies | quote }} @@ -1372,6 +1511,18 @@ data: enable-source-ip-verification: {{ .Values.daemon.enableSourceIPVerification | quote }} {{- end }} +{{- if has (kindOf .Values.connectivityProbeFrequencyRatio) (list "int64" "float64") }} + connectivity-probe-frequency-ratio: {{ .Values.connectivityProbeFrequencyRatio | quote }} +{{- end }} + +{{- if hasKey .Values "configDriftDetection" }} + enable-dynamic-config: {{ .Values.configDriftDetection.enabled | quote }} + enable-drift-checker: {{ .Values.configDriftDetection.driftChecker | quote }} + {{- if .Values.configDriftDetection.ignoredKeys }} + ignore-flags-drift-checker: {{ join "," .Values.configDriftDetection.ignoredKeys | quote }} + {{- end }} +{{- end }} + # Extra config allows adding arbitrary properties to the cilium config. # By putting it at the end of the ConfigMap, it's also possible to override existing properties. {{- if .Values.extraConfig }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-envoy/configmap.yaml b/packages/system/cilium/charts/cilium/templates/cilium-envoy/configmap.yaml index b2639892..4511e7ad 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-envoy/configmap.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-envoy/configmap.yaml @@ -1,5 +1,5 @@ {{- $envoyDS := eq (include "envoyDaemonSetEnabled" .) "true" -}} -{{- if and $envoyDS (not .Values.preflight.enabled) }} +{{- if (and $envoyDS (not .Values.preflight.enabled)) }} --- apiVersion: v1 diff --git a/packages/system/cilium/charts/cilium/templates/cilium-envoy/daemonset.yaml b/packages/system/cilium/charts/cilium/templates/cilium-envoy/daemonset.yaml index 5649796a..2afc2e97 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-envoy/daemonset.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-envoy/daemonset.yaml @@ -22,10 +22,7 @@ spec: selector: matchLabels: k8s-app: cilium-envoy - {{- with .Values.envoy.updateStrategy }} - updateStrategy: - {{- toYaml . | trim | nindent 4 }} - {{- end }} + {{- include "envoy.updateStrategy" . | nindent 2 }} template: metadata: annotations: @@ -69,6 +66,7 @@ spec: securityContext: {{- toYaml . | nindent 8 }} {{- end }} + {{- include "envoy.initContainers" . | nindent 6 }} containers: - name: cilium-envoy image: {{ include "cilium.image" .Values.envoy.image | quote }} @@ -94,9 +92,11 @@ spec: {{- if .Values.envoy.log.path }} - '--log-path {{ .Values.envoy.log.path }}' {{- end }} + {{- include "envoy.args.extra" . | nindent 8 }} {{- with .Values.envoy.extraArgs }} {{- toYaml . | trim | nindent 8 }} {{- end }} + {{- if .Values.envoy.startupProbe.enabled }} startupProbe: httpGet: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} @@ -107,6 +107,8 @@ spec: periodSeconds: {{ .Values.envoy.startupProbe.periodSeconds }} successThreshold: 1 initialDelaySeconds: 5 + {{- end }} + {{- if .Values.envoy.livenessProbe.enabled }} livenessProbe: httpGet: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} @@ -117,6 +119,7 @@ spec: successThreshold: 1 failureThreshold: {{ .Values.envoy.livenessProbe.failureThreshold }} timeoutSeconds: 5 + {{- end }} readinessProbe: httpGet: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} @@ -138,12 +141,22 @@ spec: fieldRef: apiVersion: v1 fieldPath: metadata.namespace + {{- if and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_HOST + valueFrom: + configMapKeyRef: + name: {{ .Values.k8sServiceHostRef.name }} + key: {{ .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_PORT + value: {{ include "k8sServicePort" . }} + {{- end }} {{- if .Values.k8sServiceHost }} - name: KUBERNETES_SERVICE_HOST value: {{ include "k8sServiceHost" . }} - name: KUBERNETES_SERVICE_PORT value: {{ include "k8sServicePort" . }} {{- end }} + {{- include "envoy.env.extra" . | nindent 8 }} {{- with .Values.envoy.extraEnv }} {{- toYaml . | trim | nindent 8 }} {{- end }} @@ -151,19 +164,7 @@ spec: resources: {{- toYaml . | trim | nindent 10 }} {{- end }} - {{- if .Values.envoy.prometheus.enabled }} - ports: - - name: envoy-metrics - containerPort: {{ .Values.envoy.prometheus.port }} - hostPort: {{ .Values.envoy.prometheus.port }} - protocol: TCP - {{- if and .Values.envoy.debug.admin.enabled .Values.envoy.debug.admin.port }} - - name: envoy-admin - containerPort: {{ .Values.envoy.debug.admin.port }} - hostPort: {{ .Values.envoy.debug.admin.port }} - protocol: TCP - {{- end }} - {{- end }} + {{- include "envoy.ports" . }} securityContext: {{- if .Values.envoy.securityContext.privileged }} privileged: true @@ -196,6 +197,7 @@ spec: mountPath: /sys/fs/bpf mountPropagation: HostToContainer {{- end }} + {{- include "envoy.volumeMounts.extra" . | nindent 8 }} {{- range .Values.envoy.extraHostPathMounts }} - name: {{ .name }} mountPath: {{ .mountPath }} @@ -219,10 +221,7 @@ spec: {{- if .Values.envoy.dnsPolicy }} dnsPolicy: {{ .Values.envoy.dnsPolicy }} {{- end }} - {{- with .Values.envoy.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} + {{- include "envoy.affinity" . | nindent 6 }} {{- with .Values.envoy.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} @@ -256,6 +255,7 @@ spec: path: /sys/fs/bpf type: DirectoryOrCreate {{- end }} + {{- include "envoy.hostPathMounts.extra" . | nindent 4 }} {{- range .Values.envoy.extraHostPathMounts }} - name: {{ .name }} hostPath: diff --git a/packages/system/cilium/charts/cilium/templates/cilium-envoy/service.yaml b/packages/system/cilium/charts/cilium/templates/cilium-envoy/service.yaml index 6b982c28..8da47943 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-envoy/service.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-envoy/service.yaml @@ -32,5 +32,5 @@ spec: - name: envoy-metrics port: {{ .Values.envoy.prometheus.port }} protocol: TCP - targetPort: envoy-metrics + targetPort: {{ .Values.envoy.prometheus.port }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-envoy/servicemonitor.yaml b/packages/system/cilium/charts/cilium/templates/cilium-envoy/servicemonitor.yaml index a46aeeb8..6c2bce3c 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-envoy/servicemonitor.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-envoy/servicemonitor.yaml @@ -34,6 +34,9 @@ spec: endpoints: - port: envoy-metrics interval: {{ .Values.envoy.prometheus.serviceMonitor.interval | quote }} + {{- if .Values.envoy.prometheus.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.envoy.prometheus.serviceMonitor.scrapeTimeout | quote }} + {{- end }} honorLabels: true path: /metrics {{- with .Values.envoy.prometheus.serviceMonitor.relabelings }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-flowlog-configmap.yaml b/packages/system/cilium/charts/cilium/templates/cilium-flowlog-configmap.yaml index 7d86eb7f..84e12eae 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-flowlog-configmap.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-flowlog-configmap.yaml @@ -12,5 +12,18 @@ metadata: data: flowlogs.yaml: | flowLogs: -{{ .Values.hubble.export.dynamic.config.content | toYaml | indent 4 }} + {{- /* hubble export configurations moved, use default to make upgrades seemless */ -}} + {{- /* TODO: remove default once v1.18 is released, remove warning in warnings.txt and add failure validation in validate.yaml */ -}} + {{- range .Values.hubble.export.dynamic.config.content }} + {{- if hasKey $.Values.hubble.export "fileMaxSizeMb" }} + {{- $_ := set . "fileMaxSizeMb" (get $.Values.hubble.export "fileMaxSizeMb") -}} + {{- end }} + {{- if hasKey $.Values.hubble.export "fileMaxBackups" }} + {{- $_ := set . "fileMaxBackups" (get $.Values.hubble.export "fileMaxBackups") -}} + {{- end }} + {{- if hasKey $.Values.hubble.export "fileCompress" }} + {{- $_ := set . "fileCompress" (get $.Values.hubble.export "fileCompress") -}} + {{- end }} + {{- list . | toYaml | nindent 6 }} + {{- end }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-ingress-service.yaml b/packages/system/cilium/charts/cilium/templates/cilium-ingress-service.yaml index 8d806f21..f25afeee 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-ingress-service.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-ingress-service.yaml @@ -22,11 +22,15 @@ spec: - name: http port: 80 protocol: TCP + {{- if .Values.ingressController.service.insecureNodePort }} nodePort: {{ .Values.ingressController.service.insecureNodePort }} + {{- end }} - name: https port: 443 protocol: TCP + {{- if .Values.ingressController.service.secureNodePort }} nodePort: {{ .Values.ingressController.service.secureNodePort }} + {{- end }} {{- if .Values.ingressController.hostNetwork.enabled }} type: ClusterIP {{- else }} @@ -41,12 +45,12 @@ spec: {{- if .Values.ingressController.service.loadBalancerIP }} loadBalancerIP: {{ .Values.ingressController.service.loadBalancerIP }} {{- end }} - {{- if .Values.ingressController.service.externalTrafficPolicy }} + {{- if and .Values.ingressController.service.externalTrafficPolicy (not .Values.ingressController.hostNetwork.enabled) }} externalTrafficPolicy: {{ .Values.ingressController.service.externalTrafficPolicy }} {{- end }} --- -apiVersion: v1 -kind: Endpoints +apiVersion: discovery.k8s.io/v1 +kind: EndpointSlice metadata: name: {{ .Values.ingressController.service.name }} namespace: {{ include "cilium.namespace" . }} @@ -61,9 +65,10 @@ metadata: annotations: {{- toYaml .Values.ingressController.service.annotations | nindent 4 }} {{- end }} -subsets: +addressType: IPv4 +endpoints: - addresses: - - ip: "192.192.192.192" - ports: - - port: 9999 + - "192.192.192.192" +ports: +- port: 9999 {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-nodeinit/daemonset.yaml b/packages/system/cilium/charts/cilium/templates/cilium-nodeinit/daemonset.yaml index add6ae5a..4edbeada 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-nodeinit/daemonset.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-nodeinit/daemonset.yaml @@ -122,6 +122,8 @@ spec: {{- if .Values.serviceAccounts.nodeinit.enabled }} serviceAccountName: {{ .Values.serviceAccounts.nodeinit.name | quote }} automountServiceAccountToken: {{ .Values.serviceAccounts.nodeinit.automount }} + {{- else }} + automountServiceAccountToken: false {{- end }} {{- with .Values.nodeinit.extraVolumes }} volumes: diff --git a/packages/system/cilium/charts/cilium/templates/cilium-operator/clusterrole.yaml b/packages/system/cilium/charts/cilium/templates/cilium-operator/clusterrole.yaml index dba1ca8b..c147e2b5 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-operator/clusterrole.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-operator/clusterrole.yaml @@ -69,7 +69,7 @@ rules: resources: - endpointslices verbs: -{{- if .Values.clustermesh.enableEndpointSliceSynchronization }} +{{- if or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} - create - update - delete @@ -78,6 +78,17 @@ rules: - get - list - watch +{{- if .Values.clustermesh.enableEndpointSliceSynchronization }} +- apiGroups: + - "" + resources: + # The controller needs to be able to set a service's finalizers to be able to create an EndpointSlice + # resource that is owned by the service and sets blockOwnerDeletion=true in its ownerRef. + # This is required when the admission plugin OwnerReferencesPermissionEnforcement is activated. + - services/finalizers + verbs: + - update +{{- end }} - apiGroups: - "" resources: @@ -114,6 +125,20 @@ rules: - delete - patch {{- end }} +{{- if or .Values.ingressController.enabled .Values.gatewayAPI.enabled }} +- apiGroups: + - "discovery.k8s.io" + resources: + - endpointslices + verbs: + - get + - list + - watch + - create + - update + - delete + - patch +{{- end }} {{- if .Values.clustermesh.enableEndpointSliceSynchronization }} - apiGroups: - "" @@ -164,6 +189,9 @@ rules: verbs: # To synchronize garbage collection of such resources - update + {{- if (or (eq .Values.identityManagementMode "operator") (eq .Values.identityManagementMode "both")) }} + - create + {{- end }} - apiGroups: - cilium.io resources: @@ -224,7 +252,6 @@ rules: - update resourceNames: - ciliumloadbalancerippools.cilium.io - - ciliumbgppeeringpolicies.cilium.io - ciliumbgpclusterconfigs.cilium.io - ciliumbgppeerconfigs.cilium.io - ciliumbgpadvertisements.cilium.io @@ -236,7 +263,6 @@ rules: - ciliumendpoints.cilium.io - ciliumendpointslices.cilium.io - ciliumenvoyconfigs.cilium.io - - ciliumexternalworkloads.cilium.io - ciliumidentities.cilium.io - ciliumlocalredirectpolicies.cilium.io - ciliumnetworkpolicies.cilium.io @@ -245,12 +271,16 @@ rules: - ciliumcidrgroups.cilium.io - ciliuml2announcementpolicies.cilium.io - ciliumpodippools.cilium.io + - ciliumgatewayclassconfigs.cilium.io +{{- if and (or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport) .Values.clustermesh.mcsapi.installCRDs }} + - serviceimports.multicluster.x-k8s.io + - serviceexports.multicluster.x-k8s.io +{{- end }} - apiGroups: - cilium.io resources: - ciliumloadbalancerippools - ciliumpodippools - - ciliumbgppeeringpolicies - ciliumbgpclusterconfigs - ciliumbgpnodeconfigoverrides - ciliumbgppeerconfigs @@ -298,6 +328,10 @@ rules: - networking.k8s.io resources: - ingresses/status # To update ingress status with load balancer IP. + # The controller needs to be able to set ingress finalizers to be able to create a CiliumEnvoyConfig + # resource that is owned by the ingress, and set blockOwnerDeletion=true in its ownerRef. + # This is required when the admission plugin OwnerReferencesPermissionEnforcement is activated. + - ingresses/finalizers verbs: - update {{- end }} @@ -316,6 +350,12 @@ rules: - get - list - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - gatewayclasses + verbs: + - patch - apiGroups: - gateway.networking.k8s.io resources: @@ -327,8 +367,23 @@ rules: verbs: - update - patch +- apiGroups: + - cilium.io + resources: + - ciliumgatewayclassconfigs + verbs: + - get + - list + - watch +- apiGroups: + - cilium.io + resources: + - ciliumgatewayclassconfigs/status + verbs: + - update + - patch {{- end }} -{{- if or .Values.gatewayAPI.enabled .Values.clustermesh.enableMCSAPISupport }} +{{- if or .Values.gatewayAPI.enabled .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} - apiGroups: - multicluster.x-k8s.io resources: @@ -337,14 +392,14 @@ rules: - get - list - watch -{{- if .Values.clustermesh.enableMCSAPISupport }} +{{- if or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} - create - update - patch - delete {{- end }} {{- end }} -{{- if .Values.clustermesh.enableMCSAPISupport }} +{{- if or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} - apiGroups: - multicluster.x-k8s.io resources: @@ -352,6 +407,15 @@ rules: verbs: - update - patch +- apiGroups: + - multicluster.x-k8s.io + resources: + # The controller needs to be able to set serviceimport finalizers to be able to create a derived Service + # resource that is owned by the ServiceImport and sets blockOwnerDeletion=true in its ownerRef. + # This is required when the admission plugin OwnerReferencesPermissionEnforcement is activated. + - serviceimports/finalizers + verbs: + - update - apiGroups: - multicluster.x-k8s.io resources: @@ -377,4 +441,10 @@ rules: - patch - delete {{- end }} +- apiGroups: + - cilium.io + resources: + - ciliumendpointslices + verbs: + - deletecollection {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-operator/deployment.yaml b/packages/system/cilium/charts/cilium/templates/cilium-operator/deployment.yaml index e0fe3115..f4cddff8 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-operator/deployment.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-operator/deployment.yaml @@ -98,7 +98,7 @@ spec: fieldRef: apiVersion: v1 fieldPath: metadata.namespace - {{- if or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.enableMCSAPISupport }} + {{- if or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} - name: CILIUM_CLUSTERMESH_CONFIG value: /var/lib/cilium/clustermesh/ {{- end }} @@ -142,6 +142,15 @@ spec: key: ALIBABA_CLOUD_ACCESS_KEY_SECRET optional: true {{- end }} + {{- if and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_HOST + valueFrom: + configMapKeyRef: + name: {{ .Values.k8sServiceHostRef.name }} + key: {{ .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_PORT + value: {{ include "k8sServicePort" . }} + {{- end }} {{- if .Values.k8sServiceHost }} - name: KUBERNETES_SERVICE_HOST value: {{ include "k8sServiceHost" . }} @@ -161,6 +170,7 @@ spec: - name: AZURE_RESOURCE_GROUP value: {{ .Values.azure.resourceGroup }} {{- end }} + {{- if .Values.azure.clientID }} - name: AZURE_CLIENT_ID valueFrom: secretKeyRef: @@ -172,11 +182,15 @@ spec: name: cilium-azure key: AZURE_CLIENT_SECRET {{- end }} + {{- end }} {{- with .Values.operator.extraEnv }} {{- toYaml . | nindent 8 }} {{- end }} - {{- if .Values.operator.prometheus.enabled }} ports: + - name: health + containerPort: 9234 + hostPort: 9234 + {{- if .Values.operator.prometheus.enabled }} - name: prometheus containerPort: {{ .Values.operator.prometheus.port }} {{- if .Values.operator.hostNetwork }} @@ -190,7 +204,7 @@ spec: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} {{- end }} path: /healthz - port: 9234 + port: health scheme: HTTP initialDelaySeconds: 60 periodSeconds: 10 @@ -201,7 +215,7 @@ spec: host: {{ .Values.ipv4.enabled | ternary "127.0.0.1" "::1" | quote }} {{- end }} path: /healthz - port: 9234 + port: health scheme: HTTP initialDelaySeconds: 0 periodSeconds: 5 @@ -221,7 +235,7 @@ spec: readOnly: true {{- end }} {{- end }} - {{- if or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.enableMCSAPISupport }} + {{- if or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} - name: clustermesh-secrets mountPath: /var/lib/cilium/clustermesh readOnly: true @@ -236,6 +250,11 @@ spec: mountPath: {{ dir .Values.authentication.mutual.spire.agentSocketPath }} readOnly: true {{- end }} + {{- if and .Values.operator.prometheus.enabled .Values.operator.prometheus.tls.enabled }} + - name: prometheus-tls + mountPath: /var/lib/cilium/tls/prometheus + readOnly: true + {{- end }} {{- range .Values.operator.extraHostPathMounts }} - name: {{ .name }} mountPath: {{ .mountPath }} @@ -247,13 +266,15 @@ spec: {{- with .Values.operator.extraVolumeMounts }} {{- toYaml . | nindent 8 }} {{- end }} + {{- include "cilium-operator.volumeMounts.extra" . | nindent 8 }} {{- with .Values.operator.resources }} resources: {{- toYaml . | trim | nindent 10 }} {{- end }} - {{- with .Values.operator.securityContext }} + {{- $sc := include "cilium.operator.securityContext" . | trim }} + {{- if $sc }} securityContext: - {{- toYaml . | trim | nindent 10 }} + {{- $sc | nindent 10 }} {{- end }} terminationMessagePolicy: FallbackToLogsOnError hostNetwork: {{ .Values.operator.hostNetwork }} @@ -286,19 +307,25 @@ spec: nodeSelector: {{- toYaml . | trim | nindent 8 }} {{- end }} - {{- if and (or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.enableMCSAPISupport) .Values.clustermesh.config.enabled (not (and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled )) }} + {{- if and (or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport) .Values.clustermesh.config.enabled (not (and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled )) }} hostAliases: - {{- range $cluster := .Values.clustermesh.config.clusters }} + {{- range $_, $cluster := (include "clustermesh-clusters" . | fromJson) }} {{- range $ip := $cluster.ips }} - ip: {{ $ip }} hostnames: [ "{{ $cluster.name }}.{{ $.Values.clustermesh.config.domain }}" ] {{- end }} {{- end }} {{- end }} - {{- with .Values.operator.tolerations }} + {{- if or (.Values.operator.tolerations) (hasKey .Values "agentNotReadyTaintKey") }} tolerations: + {{- with .Values.operator.tolerations }} {{- toYaml . | trim | nindent 8 }} {{- end }} + {{- if hasKey .Values "agentNotReadyTaintKey" }} + - key: {{ .Values.agentNotReadyTaintKey }} + operator: Exists + {{ end}} + {{- end}} volumes: # To read the configuration from the config map - name: cilium-config-path @@ -347,7 +374,7 @@ spec: {{- with .Values.operator.extraVolumes }} {{- toYaml . | nindent 6 }} {{- end }} - {{- if or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.enableMCSAPISupport }} + {{- if or .Values.clustermesh.enableEndpointSliceSynchronization .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} # To read the clustermesh configuration - name: clustermesh-secrets projected: @@ -404,4 +431,25 @@ spec: path: local-etcd-client-ca.crt {{- end }} {{- end }} + {{- if and .Values.operator.prometheus.enabled .Values.operator.prometheus.tls.enabled }} + # To read the prometheus configuration + - name: prometheus-tls + projected: + # note: the leading zero means this number is in octal representation: do not remove it + defaultMode: 0400 + sources: + - secret: + name: {{ .Values.operator.prometheus.tls.server.existingSecret }} + optional: true + items: + - key: tls.crt + path: server.crt + - key: tls.key + path: server.key + {{- if .Values.operator.prometheus.tls.server.mtls.enabled }} + - key: ca.crt + path: client-ca.crt + {{- end }} + {{- end }} + {{- include "cilium-operator.volumes.extra" . | nindent 6 }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-operator/poddisruptionbudget.yaml b/packages/system/cilium/charts/cilium/templates/cilium-operator/poddisruptionbudget.yaml index 74d29b43..ee543e93 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-operator/poddisruptionbudget.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-operator/poddisruptionbudget.yaml @@ -24,6 +24,13 @@ spec: {{- with $component.minAvailable }} minAvailable: {{ . }} {{- end }} + {{- if (semverCompare ">= 1.27-0" .Capabilities.KubeVersion.Version) }} + {{- if hasKey $component "unhealthyPodEvictionPolicy" }} + {{- with $component.unhealthyPodEvictionPolicy }} + unhealthyPodEvictionPolicy: {{ . }} + {{- end }} + {{- end }} + {{- end }} selector: matchLabels: io.cilium/app: operator diff --git a/packages/system/cilium/charts/cilium/templates/cilium-operator/role.yaml b/packages/system/cilium/charts/cilium/templates/cilium-operator/role.yaml index 8f7acd9f..11515ced 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-operator/role.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-operator/role.yaml @@ -83,3 +83,35 @@ rules: - update - patch {{- end }} + +{{- if and .Values.operator.enabled .Values.serviceAccounts.operator.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: cilium-operator-ztunnel + namespace: {{ include "cilium.namespace" . }} + {{- with .Values.operator.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app.kubernetes.io/part-of: cilium + {{- with .Values.commonLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +rules: +# ZTunnel DaemonSet management permissions +# Note: These permissions must always be granted (not conditional on encryption.type) +# because the controller needs to clean up stale DaemonSets when ztunnel is disabled. +- apiGroups: + - apps + resources: + - daemonsets + verbs: + - create + - delete + - get + - list + - watch +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-operator/rolebinding.yaml b/packages/system/cilium/charts/cilium/templates/cilium-operator/rolebinding.yaml index c77e39e9..22ac17bc 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-operator/rolebinding.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-operator/rolebinding.yaml @@ -75,5 +75,31 @@ roleRef: subjects: - kind: ServiceAccount name: {{ .Values.serviceAccounts.operator.name | quote }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cilium.namespace" . }} +{{- end }} + +{{- if and .Values.operator.enabled .Values.serviceAccounts.operator.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: cilium-operator-ztunnel + namespace: {{ include "cilium.namespace" . }} + labels: + app.kubernetes.io/part-of: cilium + {{- with .Values.commonLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.operator.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: cilium-operator-ztunnel +subjects: +- kind: ServiceAccount + name: {{ .Values.serviceAccounts.operator.name | quote }} + namespace: {{ include "cilium.namespace" . }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-operator/secret.yaml b/packages/system/cilium/charts/cilium/templates/cilium-operator/secret.yaml index 4ac55d7a..6346e136 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-operator/secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-operator/secret.yaml @@ -1,5 +1,6 @@ {{- if .Values.operator.enabled }} {{- if .Values.azure.enabled }} +{{- if .Values.azure.clientID }} apiVersion: v1 kind: Secret metadata: @@ -19,3 +20,4 @@ data: AZURE_CLIENT_SECRET: {{ default "" .Values.azure.clientSecret | b64enc | quote }} {{- end }} {{- end }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-operator/servicemonitor.yaml b/packages/system/cilium/charts/cilium/templates/cilium-operator/servicemonitor.yaml index c73b49da..b0a91f43 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-operator/servicemonitor.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-operator/servicemonitor.yaml @@ -33,6 +33,9 @@ spec: endpoints: - port: metrics interval: {{ .Values.operator.prometheus.serviceMonitor.interval | quote }} + {{- if .Values.operator.prometheus.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.operator.prometheus.serviceMonitor.scrapeTimeout | quote }} + {{- end }} honorLabels: true path: /metrics {{- with .Values.operator.prometheus.serviceMonitor.relabelings }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrole.yaml b/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrole.yaml index 9a2c0615..fbf511cd 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrole.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrole.yaml @@ -42,6 +42,9 @@ rules: - pods - endpoints - nodes +{{- if $readSecretsOnlyFromSecretsNamespace }} + - secrets +{{- end }} verbs: - get - list @@ -87,19 +90,10 @@ rules: # until we figure out how to avoid "get" inside the preflight, and then # should be removed ideally. - get -{{- if $readSecretsOnlyFromSecretsNamespace }} -- apiGroups: - - "" - resources: - - secrets - verbs: - - get -{{- end }} - apiGroups: - cilium.io resources: - ciliumloadbalancerippools - - ciliumbgppeeringpolicies - ciliumbgpnodeconfigs - ciliumbgpadvertisements - ciliumbgppeerconfigs diff --git a/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrolebinding.yaml b/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrolebinding.yaml index 93827895..ec667ea0 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrolebinding.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-preflight/clusterrolebinding.yaml @@ -18,6 +18,6 @@ roleRef: name: cilium-pre-flight subjects: - kind: ServiceAccount - name: {{ .Values.serviceAccounts.preflight.name | quote }} + name: {{ .Values.serviceAccounts.preflight.name | quote }} namespace: {{ include "cilium.namespace" . }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-preflight/daemonset.yaml b/packages/system/cilium/charts/cilium/templates/cilium-preflight/daemonset.yaml index 0e793cfa..b5418fe5 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-preflight/daemonset.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-preflight/daemonset.yaml @@ -1,14 +1,16 @@ +{{- $envoyDS := eq (include "envoyDaemonSetEnabled" .) "true" -}} + {{- if .Values.preflight.enabled }} apiVersion: apps/v1 kind: DaemonSet metadata: name: cilium-pre-flight-check namespace: {{ include "cilium.namespace" . }} - {{- with .Values.preflight.annotations }} {{- with .Values.commonLabels }} labels: {{- toYaml . | nindent 4 }} {{- end }} + {{- with .Values.preflight.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} @@ -19,10 +21,11 @@ spec: kubernetes.io/cluster-service: "true" template: metadata: - {{- with .Values.preflight.podAnnotations }} annotations: + kubectl.kubernetes.io/default-container: cilium-pre-flight-check + {{- with .Values.preflight.podAnnotations }} {{- toYaml . | nindent 8 }} - {{- end }} + {{- end }} labels: app.kubernetes.io/part-of: cilium k8s-app: cilium-pre-flight-check @@ -84,7 +87,7 @@ spec: apiVersion: v1 fieldPath: spec.nodeName {{- with .Values.preflight.extraEnv }} - {{- toYaml . | trim | nindent 12 }} + {{- toYaml . | trim | nindent 10 }} {{- end }} volumeMounts: - name: cilium-run @@ -137,6 +140,15 @@ spec: initialDelaySeconds: 5 periodSeconds: 5 env: + {{- if and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_HOST + valueFrom: + configMapKeyRef: + name: {{ .Values.k8sServiceHostRef.name }} + key: {{ .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_PORT + value: {{ include "k8sServicePort" . }} + {{- end }} {{- if .Values.k8sServiceHost }} - name: KUBERNETES_SERVICE_HOST value: {{ include "k8sServiceHost" . }} @@ -172,6 +184,45 @@ spec: {{- end }} terminationMessagePolicy: FallbackToLogsOnError {{- end }} + {{- if $envoyDS }} + - name: cilium-pre-flight-envoy + image: {{ include "cilium.image" .Values.preflight.envoy.image | quote }} + imagePullPolicy: {{ .Values.preflight.image.pullPolicy }} + command: ["/bin/sh"] + args: + - -c + - "touch /tmp/ready; sleep 1h" + livenessProbe: + exec: + command: + - cat + - /tmp/ready + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - cat + - /tmp/ready + initialDelaySeconds: 5 + periodSeconds: 5 + volumeMounts: + - name: envoy-sockets + mountPath: /var/run/cilium/envoy/sockets + readOnly: false + - name: envoy-artifacts + mountPath: /var/run/cilium/envoy/artifacts + readOnly: true + {{- with .Values.preflight.resources }} + resources: + {{- toYaml . | trim | nindent 12 }} + {{- end }} + {{- with .Values.preflight.securityContext }} + securityContext: + {{- toYaml . | trim | nindent 14 }} + {{- end }} + terminationMessagePolicy: FallbackToLogsOnError + {{- end }} hostNetwork: true dnsPolicy: ClusterFirstWithHostNet restartPolicy: Always @@ -217,6 +268,16 @@ spec: optional: true {{- end }} {{- end }} + {{- if $envoyDS }} + - name: envoy-sockets + hostPath: + path: "{{ .Values.daemon.runPath }}/envoy/sockets" + type: DirectoryOrCreate + - name: envoy-artifacts + hostPath: + path: "{{ .Values.daemon.runPath }}/envoy/artifacts" + type: DirectoryOrCreate + {{- end }} {{- with .Values.preflight.extraVolumes }} {{- toYaml . | nindent 6 }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/cilium-preflight/deployment.yaml b/packages/system/cilium/charts/cilium/templates/cilium-preflight/deployment.yaml index 26c7f063..6218b460 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-preflight/deployment.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-preflight/deployment.yaml @@ -13,7 +13,7 @@ metadata: app.kubernetes.io/name: cilium-pre-flight-check {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} - {{- end }} + {{- end }} spec: selector: matchLabels: @@ -64,7 +64,16 @@ spec: {{- toYaml . | nindent 10 }} {{- end }} env: - {{- if .Values.k8sServiceHost }} + {{- if and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_HOST + valueFrom: + configMapKeyRef: + name: {{ .Values.k8sServiceHostRef.name }} + key: {{ .Values.k8sServiceHostRef.key }} + - name: KUBERNETES_SERVICE_PORT + value: {{ include "k8sServicePort" . }} + {{- end }} + {{- if .Values.k8sServiceHost }} - name: KUBERNETES_SERVICE_HOST value: {{ include "k8sServiceHost" . }} - name: KUBERNETES_SERVICE_PORT diff --git a/packages/system/cilium/charts/cilium/templates/cilium-preflight/poddisruptionbudget.yaml b/packages/system/cilium/charts/cilium/templates/cilium-preflight/poddisruptionbudget.yaml index be41a74c..576d9d35 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-preflight/poddisruptionbudget.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-preflight/poddisruptionbudget.yaml @@ -24,6 +24,13 @@ spec: {{- with $component.minAvailable }} minAvailable: {{ . }} {{- end }} + {{- if (semverCompare ">= 1.27-0" .Capabilities.KubeVersion.Version) }} + {{- if hasKey $component "unhealthyPodEvictionPolicy" }} + {{- with $component.unhealthyPodEvictionPolicy }} + unhealthyPodEvictionPolicy: {{ . }} + {{- end }} + {{- end }} + {{- end }} selector: matchLabels: k8s-app: cilium-pre-flight-check-deployment diff --git a/packages/system/cilium/charts/cilium/templates/cilium-secrets-namespace.yaml b/packages/system/cilium/charts/cilium/templates/cilium-secrets-namespace.yaml index 2a7726d8..600ccfeb 100644 --- a/packages/system/cilium/charts/cilium/templates/cilium-secrets-namespace.yaml +++ b/packages/system/cilium/charts/cilium/templates/cilium-secrets-namespace.yaml @@ -20,4 +20,11 @@ metadata: {{- with $.Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} + {{- with $.Values.secretsNamespaceLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + annotations: + {{- with $.Values.secretsNamespaceAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} {{- end}} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrole.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrole.yaml index e7ebda95..88288eb8 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrole.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrole.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.serviceAccounts.clustermeshApiserver.create .Values.rbac.create }} +{{- if and .Values.clustermesh.useAPIServer .Values.serviceAccounts.clustermeshApiserver.create .Values.rbac.create (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") (eq "true" (include "identityAllocationCRD" .)) }} apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: @@ -13,40 +13,13 @@ metadata: {{- toYaml . | nindent 4 }} {{- end }} rules: -{{- if .Values.externalWorkloads.enabled }} -- apiGroups: - - cilium.io - resources: - - ciliumnodes - - ciliumendpoints - - ciliumidentities - verbs: - - create -- apiGroups: - - cilium.io - resources: - - ciliumexternalworkloads/status - - ciliumnodes - - ciliumidentities - verbs: - - update -- apiGroups: - - cilium.io - resources: - - ciliumendpoints - - ciliumendpoints/status - verbs: - - patch -{{- end }} - apiGroups: - cilium.io resources: - ciliumidentities -{{- if .Values.externalWorkloads.enabled }} - - ciliumexternalworkloads -{{- end }} - ciliumendpoints - ciliumnodes + - ciliumendpointslices verbs: - get - list @@ -77,7 +50,7 @@ rules: - get - list - watch -{{- if .Values.clustermesh.enableMCSAPISupport }} +{{- if or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} - apiGroups: - multicluster.x-k8s.io resources: diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrolebinding.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrolebinding.yaml index ecd5fe31..efbcf138 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrolebinding.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/clusterrolebinding.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.serviceAccounts.clustermeshApiserver.create .Values.rbac.create }} +{{- if and .Values.clustermesh.useAPIServer .Values.serviceAccounts.clustermeshApiserver.create .Values.rbac.create (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") (eq "true" (include "identityAllocationCRD" .)) }} apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/deployment.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/deployment.yaml index 9450ea43..1146209a 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/deployment.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/deployment.yaml @@ -1,4 +1,4 @@ -{{- if (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) }} +{{- if .Values.clustermesh.useAPIServer }} {{- if not (list "legacy" "migration" "cluster" | has .Values.clustermesh.apiserver.tls.authMode) -}} {{- fail ".Values.clustermesh.apiserver.tls.authMode must be one of legacy, migration, cluster" -}} {{- end -}} @@ -23,9 +23,16 @@ spec: selector: matchLabels: k8s-app: clustermesh-apiserver - {{- with .Values.clustermesh.apiserver.updateStrategy }} + {{- if eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "external" }} + {{/* without proper locking in kvstoremesh we can't run multiple pods at once */}} strategy: + type: Recreate + {{- else }} + {{- with .Values.clustermesh.apiserver.updateStrategy }} + strategy: + # -- The priority class to use for clustermesh-apiserver {{- toYaml . | nindent 4 }} + {{- end }} {{- end }} template: metadata: @@ -33,6 +40,7 @@ spec: {{- with .Values.clustermesh.apiserver.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} + kubectl.kubernetes.io/default-container: apiserver labels: app.kubernetes.io/part-of: cilium app.kubernetes.io/name: clustermesh-apiserver @@ -52,6 +60,7 @@ spec: securityContext: {{- toYaml . | nindent 8 }} {{- end }} + {{- if eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal" }} initContainers: - name: etcd-init image: {{ include "cilium.image" .Values.clustermesh.apiserver.image | quote }} @@ -104,7 +113,9 @@ spec: resources: {{- toYaml . | nindent 10 }} {{- end }} + {{- end }} containers: + {{- if eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal" }} - name: etcd # The clustermesh-apiserver container image includes an etcd binary. image: {{ include "cilium.image" .Values.clustermesh.apiserver.image | quote }} @@ -118,23 +129,22 @@ spec: - --trusted-ca-file=/var/lib/etcd-secrets/ca.crt - --cert-file=/var/lib/etcd-secrets/tls.crt - --key-file=/var/lib/etcd-secrets/tls.key - # Surrounding the IPv4 address with brackets works in this case, since etcd - # uses net.SplitHostPort() internally and it accepts the that format. - - --listen-client-urls=https://127.0.0.1:2379,https://[$(HOSTNAME_IP)]:2379 - - --advertise-client-urls=https://[$(HOSTNAME_IP)]:2379 + - --listen-client-urls=https://0.0.0.0:2379 + # We advertise localhost as client URLs for convenience, even though + # technically not correct. However, it doesn't matter, as this is a + # single replica cluster, and clients directly connect to it via the + # address provided as part of their configuration. + - --advertise-client-urls=https://localhost:2379 - --initial-cluster-token=$(INITIAL_CLUSTER_TOKEN) - --auto-compaction-retention=1 + - --enable-grpc-gateway=false {{- if .Values.clustermesh.apiserver.metrics.etcd.enabled }} - - --listen-metrics-urls=http://[$(HOSTNAME_IP)]:{{ .Values.clustermesh.apiserver.metrics.etcd.port }} + - --listen-metrics-urls=http://0.0.0.0:{{ .Values.clustermesh.apiserver.metrics.etcd.port }} - --metrics={{ .Values.clustermesh.apiserver.metrics.etcd.mode }} {{- end }} env: - name: ETCDCTL_API value: "3" - - name: HOSTNAME_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - name: INITIAL_CLUSTER_TOKEN valueFrom: fieldRef: @@ -170,6 +180,8 @@ spec: lifecycle: {{- toYaml . | nindent 10 }} {{- end }} + {{- end }} + {{- if eq "true" (include "identityAllocationCRD" .) }} - name: apiserver image: {{ include "cilium.image" .Values.clustermesh.apiserver.image | quote }} imagePullPolicy: {{ .Values.clustermesh.apiserver.image.pullPolicy }} @@ -193,14 +205,17 @@ spec: - --cluster-users-enabled - --cluster-users-config-path=/var/lib/cilium/etcd-config/users.yaml {{- end }} - - --enable-external-workloads={{ .Values.externalWorkloads.enabled }} {{- if .Values.clustermesh.apiserver.metrics.enabled }} - --prometheus-serve-addr=:{{ .Values.clustermesh.apiserver.metrics.port }} - --controller-group-metrics=all {{- end }} - {{- if .Values.clustermesh.enableMCSAPISupport }} + {{- if or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport }} - --clustermesh-enable-mcs-api {{- end }} + {{- if .Values.ciliumEndpointSlice.enabled }} + - --enable-cilium-endpoint-slice + {{- end }} + {{- include "clustermesh.apiserver.args.extra" . | nindent 8 }} {{- with .Values.clustermesh.apiserver.extraArgs }} {{- toYaml . | trim | nindent 8 }} {{- end }} @@ -222,6 +237,9 @@ spec: name: cilium-config key: enable-k8s-endpoint-slice optional: true + {{- with .Values.clustermesh.apiserver.extraEnv }} + {{- toYaml . | trim | nindent 8 }} + {{- end }} readinessProbe: httpGet: path: /readyz @@ -229,9 +247,6 @@ spec: {{- with .Values.clustermesh.apiserver.readinessProbe }} {{- toYaml . | trim | nindent 10 }} {{- end }} - {{- with .Values.clustermesh.apiserver.extraEnv }} - {{- toYaml . | trim | nindent 8 }} - {{- end }} ports: - name: apiserv-health containerPort: {{ .Values.clustermesh.apiserver.healthPort }} @@ -266,6 +281,7 @@ spec: lifecycle: {{- toYaml . | nindent 10 }} {{- end }} + {{- end }} {{- if .Values.clustermesh.apiserver.kvstoremesh.enabled }} - name: kvstoremesh image: {{ include "cilium.image" .Values.clustermesh.apiserver.image | quote }} @@ -281,17 +297,22 @@ spec: - --cluster-id=$(CLUSTER_ID) - --kvstore-opt=etcd.config=/var/lib/cilium/etcd-config.yaml - --kvstore-opt=etcd.qps=100 + {{- if ne .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "external" }} - --kvstore-opt=etcd.bootstrapQps=10000 + {{- end }} - --kvstore-opt=etcd.maxInflight=10 - --clustermesh-config=/var/lib/cilium/clustermesh {{- if hasKey .Values.clustermesh "maxConnectedClusters" }} - --max-connected-clusters={{ .Values.clustermesh.maxConnectedClusters }} {{- end }} + - --clustermesh-cache-ttl={{ .Values.clustermesh.cacheTTL }} - --health-port={{ .Values.clustermesh.apiserver.kvstoremesh.healthPort }} {{- if .Values.clustermesh.apiserver.metrics.kvstoremesh.enabled }} - --prometheus-serve-addr=:{{ .Values.clustermesh.apiserver.metrics.kvstoremesh.port }} - --controller-group-metrics=all {{- end }} + - --enable-heartbeat={{ eq "true" (include "identityAllocationCRD" .) | ternary "false" "true" }} + {{- include "clustermesh.kvstoremesh.args.extra" . | nindent 8 }} {{- with .Values.clustermesh.apiserver.kvstoremesh.extraArgs }} {{- toYaml . | trim | nindent 8 }} {{- end }} @@ -330,12 +351,19 @@ spec: {{- toYaml . | nindent 10 }} {{- end }} volumeMounts: + {{- if (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") }} - name: etcd-admin-client mountPath: /var/lib/cilium/etcd-secrets readOnly: true + {{- end }} - name: kvstoremesh-secrets mountPath: /var/lib/cilium/clustermesh readOnly: true + {{- if eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "external"}} + - name: etcd-config + mountPath: /var/lib/cilium + readOnly: true + {{- end }} {{- with .Values.clustermesh.apiserver.kvstoremesh.extraVolumeMounts }} {{- toYaml . | nindent 8 }} {{- end }} @@ -350,6 +378,7 @@ spec: {{- end }} {{- end }} volumes: + {{- if (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") }} - name: etcd-server-secrets projected: # note: the leading zero means this number is in octal representation: do not remove it @@ -404,6 +433,7 @@ spec: - name: etcd-data-dir emptyDir: medium: {{ ternary "Memory" "" (eq .Values.clustermesh.apiserver.etcd.storageMedium "Memory") | quote }} + {{- end }} {{- if .Values.clustermesh.apiserver.kvstoremesh.enabled }} - name: kvstoremesh-secrets projected: @@ -425,8 +455,26 @@ spec: path: common-etcd-client.key - key: tls.crt path: common-etcd-client.crt + {{- if not .Values.tls.caBundle.enabled }} - key: ca.crt path: common-etcd-client-ca.crt + {{- else }} + - {{ .Values.tls.caBundle.useSecret | ternary "secret" "configMap" }}: + name: {{ .Values.tls.caBundle.name }} + optional: true + items: + - key: {{ .Values.tls.caBundle.key }} + path: common-etcd-client-ca.crt + {{- end }} + {{- if eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "external"}} + - configMap: + defaultMode: 0400 + items: + - key: etcd-config + path: etcd-config.yaml + name: cilium-config + name: etcd-config + {{- end }} {{- end }} {{- with .Values.clustermesh.apiserver.extraVolumes }} {{- toYaml . | nindent 6 }} @@ -461,7 +509,7 @@ spec: {{- end }} {{- if and .Values.clustermesh.config.enabled .Values.clustermesh.apiserver.kvstoremesh.enabled }} hostAliases: - {{- range $cluster := .Values.clustermesh.config.clusters }} + {{- range $_, $cluster := (include "clustermesh-clusters" . | fromJson) }} {{- range $ip := $cluster.ips }} - ip: {{ $ip }} hostnames: [ "{{ $cluster.name }}.{{ $.Values.clustermesh.config.domain }}" ] diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/metrics-service.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/metrics-service.yaml index 915b3165..587c9b13 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/metrics-service.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/metrics-service.yaml @@ -1,6 +1,6 @@ {{- $kvstoreMetricsEnabled := and .Values.clustermesh.apiserver.kvstoremesh.enabled .Values.clustermesh.apiserver.metrics.kvstoremesh.enabled -}} {{- if and - (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) + .Values.clustermesh.useAPIServer (or .Values.clustermesh.apiserver.metrics.enabled $kvstoreMetricsEnabled .Values.clustermesh.apiserver.metrics.etcd.enabled) }} apiVersion: v1 kind: Service @@ -24,11 +24,13 @@ spec: clusterIP: None type: ClusterIP ports: - {{- if .Values.clustermesh.apiserver.metrics.enabled }} + {{- if and (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") (eq "true" (include "identityAllocationCRD" .)) }} + {{- if .Values.clustermesh.apiserver.metrics.enabled }} - name: apiserv-metrics port: {{ .Values.clustermesh.apiserver.metrics.port }} protocol: TCP targetPort: apiserv-metrics + {{- end }} {{- end }} {{- if $kvstoreMetricsEnabled }} - name: kvmesh-metrics @@ -36,11 +38,13 @@ spec: protocol: TCP targetPort: kvmesh-metrics {{- end }} - {{- if .Values.clustermesh.apiserver.metrics.etcd.enabled }} + {{- if eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal" }} + {{- if .Values.clustermesh.apiserver.metrics.etcd.enabled }} - name: etcd-metrics port: {{ .Values.clustermesh.apiserver.metrics.etcd.port }} protocol: TCP targetPort: etcd-metrics + {{- end }} {{- end }} selector: k8s-app: clustermesh-apiserver diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/poddisruptionbudget.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/poddisruptionbudget.yaml index 491b075d..2ead8f29 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/poddisruptionbudget.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/poddisruptionbudget.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.podDisruptionBudget.enabled }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.podDisruptionBudget.enabled }} {{- $component := .Values.clustermesh.apiserver.podDisruptionBudget }} apiVersion: policy/v1 kind: PodDisruptionBudget @@ -24,6 +24,13 @@ spec: {{- with $component.minAvailable }} minAvailable: {{ . }} {{- end }} + {{- if (semverCompare ">= 1.27-0" .Capabilities.KubeVersion.Version) }} + {{- if hasKey $component "unhealthyPodEvictionPolicy" }} + {{- with $component.unhealthyPodEvictionPolicy }} + unhealthyPodEvictionPolicy: {{ . }} + {{- end }} + {{- end }} + {{- end }} selector: matchLabels: k8s-app: clustermesh-apiserver diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/service.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/service.yaml index fa7b193c..5e20234b 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/service.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/service.yaml @@ -1,4 +1,4 @@ -{{- if (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) }} +{{- if and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") (not .Values.clustermesh.apiserver.service.externallyCreated) }} apiVersion: v1 kind: Service metadata: @@ -11,7 +11,9 @@ metadata: {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} - + {{- with .Values.clustermesh.apiserver.service.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} {{- if or .Values.clustermesh.apiserver.service.annotations .Values.clustermesh.annotations }} annotations: {{- with .Values.clustermesh.annotations }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/serviceaccount.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/serviceaccount.yaml index 2df6aa87..a24369ef 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/serviceaccount.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/serviceaccount.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.serviceAccounts.clustermeshApiserver.create -}} +{{- if and .Values.clustermesh.useAPIServer .Values.serviceAccounts.clustermeshApiserver.create -}} apiVersion: v1 kind: ServiceAccount metadata: diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/servicemonitor.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/servicemonitor.yaml index 800d79f7..a9d4d5bc 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/servicemonitor.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/servicemonitor.yaml @@ -1,6 +1,6 @@ {{- $kvstoreMetricsEnabled := and .Values.clustermesh.apiserver.kvstoremesh.enabled .Values.clustermesh.apiserver.metrics.kvstoremesh.enabled -}} {{- if and - (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) + .Values.clustermesh.useAPIServer (or .Values.clustermesh.apiserver.metrics.enabled $kvstoreMetricsEnabled .Values.clustermesh.apiserver.metrics.etcd.enabled) .Values.clustermesh.apiserver.metrics.serviceMonitor.enabled }} --- @@ -11,6 +11,7 @@ metadata: namespace: {{ .Values.clustermesh.apiserver.metrics.serviceMonitor.namespace | default (include "cilium.namespace" .) }} labels: app.kubernetes.io/part-of: cilium + app.kubernetes.io/name: clustermesh-apiserver {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} @@ -35,9 +36,12 @@ spec: matchNames: - {{ include "cilium.namespace" . }} endpoints: - {{- if .Values.clustermesh.apiserver.metrics.enabled }} + {{- if and .Values.clustermesh.apiserver.metrics.enabled (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") (eq "true" (include "identityAllocationCRD" .)) }} - port: apiserv-metrics interval: {{ .Values.clustermesh.apiserver.metrics.serviceMonitor.interval | quote }} + {{- if .Values.clustermesh.apiserver.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.clustermesh.apiserver.metrics.serviceMonitor.scrapeTimeout | quote }} + {{- end }} honorLabels: true path: /metrics {{- with .Values.clustermesh.apiserver.metrics.serviceMonitor.relabelings }} @@ -52,6 +56,9 @@ spec: {{- if $kvstoreMetricsEnabled }} - port: kvmesh-metrics interval: {{ .Values.clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.interval | quote }} + {{- if .Values.clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.scrapeTimeout }} + scrapeTimeout: {{ .Values.clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.scrapeTimeout | quote }} + {{- end }} honorLabels: true path: /metrics {{- with .Values.clustermesh.apiserver.metrics.serviceMonitor.kvstoremesh.relabelings }} @@ -63,9 +70,12 @@ spec: {{- toYaml . | nindent 4 }} {{- end }} {{- end }} - {{- if .Values.clustermesh.apiserver.metrics.etcd.enabled }} + {{- if and .Values.clustermesh.apiserver.metrics.etcd.enabled (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") }} - port: etcd-metrics interval: {{ .Values.clustermesh.apiserver.metrics.serviceMonitor.etcd.interval | quote }} + {{- if .Values.clustermesh.apiserver.metrics.serviceMonitor.etcd.scrapeTimeout }} + scrapeTimeout: {{ .Values.clustermesh.apiserver.metrics.serviceMonitor.etcd.scrapeTimeout | quote }} + {{- end }} honorLabels: true path: /metrics {{- with .Values.clustermesh.apiserver.metrics.serviceMonitor.etcd.relabelings }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/admin-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/admin-secret.yaml index 974ebfa8..7a2713b6 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/admin-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/admin-secret.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} +{{- if and (and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal")) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} --- apiVersion: cert-manager.io/v1 kind: Certificate diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/client-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/client-secret.yaml deleted file mode 100644 index 0b33c852..00000000 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/client-secret.yaml +++ /dev/null @@ -1,22 +0,0 @@ -{{- if and .Values.externalWorkloads.enabled .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} ---- -apiVersion: cert-manager.io/v1 -kind: Certificate -metadata: - name: clustermesh-apiserver-client-cert - namespace: {{ include "cilium.namespace" . }} - {{- with .Values.commonLabels }} - labels: - {{- toYaml . | nindent 4 }} - {{- end }} - {{- with .Values.clustermesh.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - issuerRef: - {{- toYaml .Values.clustermesh.apiserver.tls.auto.certManagerIssuerRef | nindent 4 }} - secretName: clustermesh-apiserver-client-cert - commonName: externalworkload - duration: {{ printf "%dh0m0s" (mul .Values.clustermesh.apiserver.tls.auto.certValidityDuration 24) }} -{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/local-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/local-secret.yaml index d38e8195..376fd61b 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/local-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/local-secret.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} --- apiVersion: cert-manager.io/v1 kind: Certificate diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/remote-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/remote-secret.yaml index 47cb29ff..94ab4119 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/remote-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/remote-secret.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} +{{- if and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} --- apiVersion: cert-manager.io/v1 kind: Certificate diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/server-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/server-secret.yaml index 8e94d1fe..a8772ae2 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/server-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-certmanager/server-secret.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} +{{- if and (and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal")) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} --- apiVersion: cert-manager.io/v1 kind: Certificate diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/_job-spec.tpl b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/_job-spec.tpl index a12d3256..2fdccf47 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/_job-spec.tpl +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/_job-spec.tpl @@ -9,10 +9,22 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} spec: + securityContext: + seccompProfile: + type: RuntimeDefault containers: - name: certgen image: {{ include "cilium.image" .Values.certgen.image | quote }} imagePullPolicy: {{ .Values.certgen.image.pullPolicy }} + securityContext: + capabilities: + drop: + - ALL + allowPrivilegeEscalation: false + {{- with .Values.certgen.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} command: - "/usr/bin/cilium-certgen" args: @@ -76,21 +88,11 @@ spec: - client auth validity: {{ $certValidityStr }} {{- end }} - {{- if .Values.externalWorkloads.enabled }} - - name: clustermesh-apiserver-client-cert - namespace: {{ include "cilium.namespace" . }} - commonName: "externalworkload" - usage: - - signing - - key encipherment - - client auth - validity: {{ $certValidityStr }} - {{- end }} {{- with .Values.certgen.extraVolumeMounts }} volumeMounts: {{- toYaml . | nindent 10 }} {{- end }} - hostNetwork: true + hostNetwork: false {{- with .Values.certgen.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} @@ -102,7 +104,6 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} - serviceAccount: {{ .Values.serviceAccounts.clustermeshcertgen.name | quote }} serviceAccountName: {{ .Values.serviceAccounts.clustermeshcertgen.name | quote }} automountServiceAccountToken: {{ .Values.serviceAccounts.clustermeshcertgen.automount }} {{- with .Values.imagePullSecrets }} @@ -114,9 +115,11 @@ spec: volumes: {{- toYaml . | nindent 6 }} {{- end }} - affinity: {{- with .Values.certgen.affinity }} + affinity: {{- toYaml . | nindent 8 }} {{- end }} - ttlSecondsAfterFinished: {{ .Values.certgen.ttlSecondsAfterFinished }} + {{- with .Values.certgen.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ . }} + {{- end }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/cronjob.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/cronjob.yaml index 4dfc8076..4b88d92c 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/cronjob.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/cronjob.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.clustermesh.apiserver.tls.auto.schedule }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.clustermesh.apiserver.tls.auto.schedule }} apiVersion: batch/v1 kind: CronJob metadata: @@ -16,6 +16,8 @@ metadata: {{- end }} spec: schedule: {{ .Values.clustermesh.apiserver.tls.auto.schedule | quote }} + successfulJobsHistoryLimit: {{ .Values.certgen.cronJob.successfulJobsHistoryLimit }} + failedJobsHistoryLimit: {{ .Values.certgen.cronJob.failedJobsHistoryLimit }} concurrencyPolicy: Forbid jobTemplate: {{- include "clustermesh-apiserver-generate-certs.job.spec" . | nindent 4 }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/job.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/job.yaml index d27a3150..574aee13 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/job.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/job.yaml @@ -1,9 +1,18 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") }} +{{- if and (and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal")) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") }} +{{/* +Because Kubernetes job specs are immutable, Helm will fail patch this job if +the spec changes between releases. To avoid breaking the upgrade path, we +generate a name for the job here which is based on the checksum of the spec. +This will cause the name of the job to change if its content changes, +and in turn cause Helm to do delete the old job and replace it with a new one. +*/}} +{{- $jobSpec := include "clustermesh-apiserver-generate-certs.job.spec" . -}} +{{- $checkSum := $jobSpec | sha256sum | trunc 10 -}} --- apiVersion: batch/v1 kind: Job metadata: - name: clustermesh-apiserver-generate-certs + name: clustermesh-apiserver-generate-certs-{{$checkSum}} namespace: {{ include "cilium.namespace" . }} labels: k8s-app: clustermesh-apiserver-generate-certs @@ -11,13 +20,14 @@ metadata: {{- toYaml . | nindent 4 }} {{- end }} app.kubernetes.io/part-of: cilium + {{- if or .Values.certgen.annotations.job .Values.clustermesh.annotations }} annotations: - "helm.sh/hook": post-install,post-upgrade {{- with .Values.certgen.annotations.job }} - {{- toYaml . | nindent 4 }} + {{- toYaml . | nindent 4 }} {{- end }} {{- with .Values.clustermesh.annotations }} {{- toYaml . | nindent 4 }} {{- end }} -{{ include "clustermesh-apiserver-generate-certs.job.spec" . }} + {{- end }} +{{ $jobSpec }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/role.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/role.yaml index e8e8b0ae..1f6dc153 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/role.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/role.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.serviceAccounts.clustermeshcertgen.create }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.serviceAccounts.clustermeshcertgen.create }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: @@ -38,7 +38,6 @@ rules: - clustermesh-apiserver-admin-cert - clustermesh-apiserver-remote-cert - clustermesh-apiserver-local-cert - - clustermesh-apiserver-client-cert verbs: - update {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/rolebinding.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/rolebinding.yaml index 28f36797..6e5dd695 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/rolebinding.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/rolebinding.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.serviceAccounts.clustermeshcertgen.create }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.serviceAccounts.clustermeshcertgen.create }} apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/serviceaccount.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/serviceaccount.yaml index 1a8c3ea1..42066dd1 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/serviceaccount.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-cronjob/serviceaccount.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.serviceAccounts.clustermeshcertgen.create }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "cronJob") .Values.serviceAccounts.clustermeshcertgen.create }} apiVersion: v1 kind: ServiceAccount metadata: diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/admin-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/admin-secret.yaml index a35f7cdc..49325d14 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/admin-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/admin-secret.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} +{{- if and ( and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal")) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} {{- $_ := include "cilium.ca.setup" . -}} {{- $cn := include "clustermesh-apiserver-generate-certs.admin-common-name" . -}} {{- $cert := genSignedCert $cn nil nil (.Values.clustermesh.apiserver.tls.auto.certValidityDuration | int) .commonCA -}} @@ -8,12 +8,16 @@ kind: Secret metadata: name: clustermesh-apiserver-admin-cert namespace: {{ include "cilium.namespace" . }} - {{- with .Values.commonLabels }} labels: + {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} - {{- with .Values.clustermesh.annotations }} + cilium.io/helm-template-non-idempotent: "true" annotations: + {{- with .Values.clustermesh.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.nonIdempotentAnnotations }} {{- toYaml . | nindent 4 }} {{- end }} type: kubernetes.io/tls diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/client-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/client-secret.yaml deleted file mode 100644 index 220e9d3d..00000000 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/client-secret.yaml +++ /dev/null @@ -1,24 +0,0 @@ -{{- if and .Values.externalWorkloads.enabled .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} -{{- $_ := include "cilium.ca.setup" . -}} -{{- $cn := "externalworkload" }} -{{- $cert := genSignedCert $cn nil nil (.Values.clustermesh.apiserver.tls.auto.certValidityDuration | int) .commonCA -}} ---- -apiVersion: v1 -kind: Secret -metadata: - name: clustermesh-apiserver-client-cert - namespace: {{ include "cilium.namespace" . }} - {{- with .Values.commonLabels }} - labels: - {{- toYaml . | nindent 4 }} - {{- end }} - {{- with .Values.clustermesh.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -type: kubernetes.io/tls -data: - ca.crt: {{ .commonCA.Cert | b64enc }} - tls.crt: {{ $cert.Cert | b64enc }} - tls.key: {{ $cert.Key | b64enc }} -{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/local-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/local-secret.yaml index 4efc252d..3d34bd68 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/local-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/local-secret.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} {{- $_ := include "cilium.ca.setup" . -}} {{- $cn := include "clustermesh-apiserver-generate-certs.local-common-name" . -}} {{- $cert := genSignedCert $cn nil nil (.Values.clustermesh.apiserver.tls.auto.certValidityDuration | int) .commonCA -}} @@ -8,12 +8,16 @@ kind: Secret metadata: name: clustermesh-apiserver-local-cert namespace: {{ include "cilium.namespace" . }} - {{- with .Values.commonLabels }} labels: + {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} - {{- with .Values.clustermesh.annotations }} + cilium.io/helm-template-non-idempotent: "true" annotations: + {{- with .Values.clustermesh.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.nonIdempotentAnnotations }} {{- toYaml . | nindent 4 }} {{- end }} type: kubernetes.io/tls diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/remote-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/remote-secret.yaml index 04175f7a..11bfc51d 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/remote-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/remote-secret.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} +{{- if and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} {{- $_ := include "cilium.ca.setup" . -}} {{- $cn := include "clustermesh-apiserver-generate-certs.remote-common-name" . -}} {{- $cert := genSignedCert $cn nil nil (.Values.clustermesh.apiserver.tls.auto.certValidityDuration | int) .commonCA -}} @@ -8,12 +8,16 @@ kind: Secret metadata: name: clustermesh-apiserver-remote-cert namespace: {{ include "cilium.namespace" . }} - {{- with .Values.commonLabels }} labels: + {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} - {{- with .Values.clustermesh.annotations }} + cilium.io/helm-template-non-idempotent: "true" annotations: + {{- with .Values.clustermesh.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.nonIdempotentAnnotations }} {{- toYaml . | nindent 4 }} {{- end }} type: kubernetes.io/tls diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/server-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/server-secret.yaml index 53c895fa..0df9a20d 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/server-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-helm/server-secret.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} +{{- if and (and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal")) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "helm") }} {{- $_ := include "cilium.ca.setup" . -}} {{- $cn := "clustermesh-apiserver.cilium.io" }} {{- $ip := concat (list "127.0.0.1" "::1") .Values.clustermesh.apiserver.tls.server.extraIpAddresses }} @@ -10,12 +10,16 @@ kind: Secret metadata: name: clustermesh-apiserver-server-cert namespace: {{ include "cilium.namespace" . }} - {{- with .Values.commonLabels }} labels: + {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} - {{- with .Values.clustermesh.annotations }} + cilium.io/helm-template-non-idempotent: "true" annotations: + {{- with .Values.clustermesh.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.nonIdempotentAnnotations }} {{- toYaml . | nindent 4 }} {{- end }} type: kubernetes.io/tls diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/admin-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/admin-secret.yaml index 91955979..24a8f1c9 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/admin-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/admin-secret.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) (not .Values.clustermesh.apiserver.tls.auto.enabled) }} +{{- if and (and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal")) (not .Values.clustermesh.apiserver.tls.auto.enabled) }} {{- if .Values.clustermesh.apiserver.tls.enableSecrets }} apiVersion: v1 kind: Secret diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/client-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/client-secret.yaml deleted file mode 100644 index 92c977cc..00000000 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/client-secret.yaml +++ /dev/null @@ -1,22 +0,0 @@ -{{- if and .Values.externalWorkloads.enabled (not .Values.clustermesh.apiserver.tls.auto.enabled) }} -{{- if .Values.clustermesh.apiserver.tls.enableSecrets }} -apiVersion: v1 -kind: Secret -metadata: - name: clustermesh-apiserver-client-cert - namespace: {{ include "cilium.namespace" . }} - {{- with .Values.clustermesh.annotations }} - {{- with .Values.commonLabels }} - labels: - {{- toYaml . | nindent 4 }} - {{- end }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -type: kubernetes.io/tls -data: - ca.crt: {{ .Values.tls.ca.cert }} - tls.crt: {{ .Values.clustermesh.apiserver.tls.client.cert | required "missing clustermesh.apiserver.tls.client.cert" }} - tls.key: {{ .Values.clustermesh.apiserver.tls.client.key | required "missing clustermesh.apiserver.tls.client.key" }} -{{- end }} -{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/remote-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/remote-secret.yaml index 62173a1f..46a1b6c4 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/remote-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/remote-secret.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.clustermesh.useAPIServer (not .Values.clustermesh.apiserver.tls.auto.enabled) }} +{{- if and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") (not .Values.clustermesh.apiserver.tls.auto.enabled) }} {{- if .Values.clustermesh.apiserver.tls.enableSecrets }} apiVersion: v1 kind: Secret diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/server-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/server-secret.yaml index 231178ca..02b23986 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/server-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/tls-provided/server-secret.yaml @@ -1,4 +1,4 @@ -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) (not .Values.clustermesh.apiserver.tls.auto.enabled) }} +{{- if and (and .Values.clustermesh.useAPIServer (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal")) (not .Values.clustermesh.apiserver.tls.auto.enabled) }} {{- if .Values.clustermesh.apiserver.tls.enableSecrets }} apiVersion: v1 kind: Secret diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/users-configmap.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/users-configmap.yaml index 56572bb2..d742e4e7 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/users-configmap.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-apiserver/users-configmap.yaml @@ -1,5 +1,5 @@ {{- if and - (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) + (and .Values.clustermesh.useAPIServer .Values.clustermesh.config.enabled (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "internal") (eq "true" (include "identityAllocationCRD" .))) (ne .Values.clustermesh.apiserver.tls.authMode "legacy") }} --- @@ -21,7 +21,7 @@ metadata: data: users.yaml: | users: - {{- range .Values.clustermesh.config.clusters }} + {{- range (include "clustermesh-clusters" . | fromJson) }} - name: remote-{{ .name }} role: remote {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-config/_helpers.tpl b/packages/system/cilium/charts/cilium/templates/clustermesh-config/_helpers.tpl index 3529f066..abe9bdb8 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-config/_helpers.tpl +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-config/_helpers.tpl @@ -2,6 +2,8 @@ {{- $cluster := index . 0 -}} {{- $domain := index . 1 -}} {{- $override := index . 2 -}} +{{- $local_etcd := index . 3 -}} +{{- $etcd_config := index . 4 -}} {{- /* The parenthesis around $cluster.tls are required, since it can be null: https://stackoverflow.com/a/68807258 */}} {{- $prefix := ternary "common-" (printf "%s." $cluster.name) (or (empty ($cluster.tls).cert) (empty ($cluster.tls).key)) -}} {{- /* KVStoreMesh is enabled, and we are generating the secret used by Cilium agents. */}} @@ -12,15 +14,24 @@ {{- end -}} endpoints: -{{- if ne $override "" }} +{{- if $local_etcd }} +{{ $etcd_config.endpoints | toYaml }} +{{- else if ne $override "" }} - {{ $override }} {{- else if $cluster.ips }} - https://{{ $cluster.name }}.{{ $domain }}:{{ $cluster.port }} {{- else }} - https://{{ $cluster.address | required "missing clustermesh.apiserver.config.clusters.address" }}:{{ $cluster.port }} {{- end }} +{{- if $local_etcd }} + {{- if $etcd_config.ssl }} +trusted-ca-file: '/var/lib/etcd-secrets/etcd-client-ca.crt' +key-file: '/var/lib/etcd-secrets/etcd-client.key' +cert-file: '/var/lib/etcd-secrets/etcd-client.crt' + {{- end }} +{{- else }} {{- if or (ne $override "") (not (empty ($cluster.tls).caCert)) }} -{{- /* The custom CA configuration takes effect only if a custom certificate and key are also set, */}} +{{- /* The custom CA configuration takes effect only if a custom certificate and key are also set */}} {{- /* otherwise we may enter this branch, but the prefix is still set to common-. */}} {{- /* Additionally, when KVStoreMesh is enabled, and we are generating the secret for the agents, */}} {{- /* we want to always use the corresponding CA certificate, that is the one with local- prefix. */}} @@ -31,3 +42,27 @@ trusted-ca-file: /var/lib/cilium/clustermesh/common-etcd-client-ca.crt key-file: /var/lib/cilium/clustermesh/{{ $prefix }}etcd-client.key cert-file: /var/lib/cilium/clustermesh/{{ $prefix }}etcd-client.crt {{- end }} +{{- end }} + +{{- define "clustermesh-clusters" }} +{{- $clusters := dict }} +{{- if kindIs "map" .Values.clustermesh.config.clusters }} + {{- range $name, $cluster := deepCopy .Values.clustermesh.config.clusters }} + {{- if ne $cluster.enabled false }} + {{- $_ := unset $cluster "enabled" }} + {{- $_ = set $cluster "name" $name }} + {{- $_ = set $clusters $name $cluster }} + {{- end }} + {{- end }} +{{- else if kindIs "slice" .Values.clustermesh.config.clusters }} + {{- range $cluster := deepCopy .Values.clustermesh.config.clusters }} + {{- if ne $cluster.enabled false }} + {{- $_ := unset $cluster "enabled" }} + {{- $_ := set $clusters $cluster.name $cluster }} + {{- end }} + {{- end }} +{{- else }} + {{- fail (printf "unknown type %s for clustermesh.config.clusters" (kindOf .Values.clustermesh.config.clusters)) }} +{{- end }} +{{- toJson $clusters }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-config/clustermesh-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-config/clustermesh-secret.yaml index 7f4f14b2..d60d6f1c 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-config/clustermesh-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-config/clustermesh-secret.yaml @@ -17,8 +17,9 @@ metadata: data: {{- $kvstoremesh := and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.kvstoremesh.enabled }} {{- $override := ternary (printf "https://clustermesh-apiserver.%s.svc:2379" (include "cilium.namespace" .)) "" $kvstoremesh }} - {{- range .Values.clustermesh.config.clusters }} - {{ .name }}: {{ include "clustermesh-config-generate-etcd-cfg" (list . $.Values.clustermesh.config.domain $override) | b64enc }} + {{- $local_etcd := and $kvstoremesh (eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "external") }} + {{- range (include "clustermesh-clusters" . | fromJson) }} + {{ .name }}: {{ include "clustermesh-config-generate-etcd-cfg" (list . $.Values.clustermesh.config.domain $override $local_etcd $.Values.etcd ) | b64enc }} {{- /* The parenthesis around .tls are required, since it can be null: https://stackoverflow.com/a/68807258 */}} {{- if and (eq $override "") (.tls).cert (.tls).key }} {{- if .tls.caCert }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-config/kvstoremesh-secret.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-config/kvstoremesh-secret.yaml index e9b554ac..2828cfd2 100644 --- a/packages/system/cilium/charts/cilium/templates/clustermesh-config/kvstoremesh-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-config/kvstoremesh-secret.yaml @@ -15,8 +15,8 @@ metadata: {{- toYaml . | nindent 4 }} {{- end }} data: - {{- range .Values.clustermesh.config.clusters }} - {{ .name }}: {{ include "clustermesh-config-generate-etcd-cfg" (list . $.Values.clustermesh.config.domain "") | b64enc }} + {{- range (include "clustermesh-clusters" . | fromJson) }} + {{ .name }}: {{ include "clustermesh-config-generate-etcd-cfg" (list . $.Values.clustermesh.config.domain "" false $.Values.etcd ) | b64enc }} {{- /* The parenthesis around .tls are required, since it can be null: https://stackoverflow.com/a/68807258 */}} {{- if and (.tls).cert (.tls).key }} {{- if .tls.caCert }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/clusterrole.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/clusterrole.yaml new file mode 100644 index 00000000..08fcea1b --- /dev/null +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/clusterrole.yaml @@ -0,0 +1,29 @@ +{{- if and (or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport) .Values.clustermesh.mcsapi.corednsAutoConfigure.enabled }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: coredns-mcsapi + labels: + app.kubernetes.io/part-of: cilium + {{- with .Values.commonLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + annotations: + {{/* + We have to leave CoreDNS RBAC to be able to read MCS-API resources + as we would leave a broken CoreDNS installation otherwise + */}} + helm.sh/resource-policy: keep + {{- with .Values.clustermesh.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +rules: +- apiGroups: + - multicluster.x-k8s.io + resources: + - serviceimports + verbs: + - list + - watch +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/clusterrolebinding.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/clusterrolebinding.yaml new file mode 100644 index 00000000..7a1867f5 --- /dev/null +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/clusterrolebinding.yaml @@ -0,0 +1,28 @@ +{{- if and (or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport) .Values.clustermesh.mcsapi.corednsAutoConfigure.enabled }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: coredns-mcsapi + labels: + app.kubernetes.io/part-of: cilium + {{- with .Values.commonLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + annotations: + {{/* + We have to leave CoreDNS RBAC to be able to read MCS-API resources + as we would leave a broken CoreDNS installation otherwise + */}} + helm.sh/resource-policy: keep + {{- with .Values.clustermesh.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: coredns-mcsapi +subjects: +- kind: ServiceAccount + name: {{ .Values.clustermesh.mcsapi.corednsAutoConfigure.coredns.serviceAccountName | quote }} + namespace: {{ .Values.clustermesh.mcsapi.corednsAutoConfigure.coredns.namespace | quote }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-clusterrole.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-clusterrole.yaml new file mode 100644 index 00000000..ac339f9f --- /dev/null +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-clusterrole.yaml @@ -0,0 +1,22 @@ +{{- if and (or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport) .Values.clustermesh.mcsapi.corednsAutoConfigure.enabled }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: cilium-coredns-mcsapi-autoconfig + {{- with .Values.commonLabels }} + labels: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.clustermesh.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +rules: +# note: namespaces permission are needed to initialize and verify that the kubernetes client works. +- apiGroups: + - "" + resources: + - "namespaces" + verbs: + - "get" +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-clusterrolebinding.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-clusterrolebinding.yaml new file mode 100644 index 00000000..4b70ccf4 --- /dev/null +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-clusterrolebinding.yaml @@ -0,0 +1,22 @@ +{{- if and (or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport) .Values.clustermesh.mcsapi.corednsAutoConfigure.enabled }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: cilium-coredns-mcsapi-autoconfig + {{- with .Values.commonLabels }} + labels: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.clustermesh.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cilium-coredns-mcsapi-autoconfig +subjects: +- kind: ServiceAccount + name: {{ .Values.serviceAccounts.corednsMCSAPI.name | quote }} + namespace: {{ include "cilium.namespace" . }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-role.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-role.yaml new file mode 100644 index 00000000..52f42fae --- /dev/null +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-role.yaml @@ -0,0 +1,36 @@ +{{- if and (or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport) .Values.clustermesh.mcsapi.corednsAutoConfigure.enabled }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: cilium-coredns-mcsapi-autoconfig + namespace: {{ .Values.clustermesh.mcsapi.corednsAutoConfigure.coredns.namespace }} + {{- with .Values.commonLabels }} + labels: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.clustermesh.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +rules: +- apiGroups: + - "" + resources: + - "configmaps" + verbs: + - "update" + - "patch" + - "get" + resourceNames: + - "{{ .Values.clustermesh.mcsapi.corednsAutoConfigure.coredns.configMapName }}" +- apiGroups: + - "apps" + resources: + - "deployments" + verbs: + - "patch" + - "update" + - "get" + resourceNames: + - "{{ .Values.clustermesh.mcsapi.corednsAutoConfigure.coredns.deploymentName }}" +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-rolebinding.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-rolebinding.yaml new file mode 100644 index 00000000..f5caf1a1 --- /dev/null +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-rolebinding.yaml @@ -0,0 +1,23 @@ +{{- if and (or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport) .Values.clustermesh.mcsapi.corednsAutoConfigure.enabled }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: cilium-coredns-mcsapi-autoconfig + namespace: {{ .Values.clustermesh.mcsapi.corednsAutoConfigure.coredns.namespace }} + {{- with .Values.commonLabels }} + labels: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.clustermesh.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: cilium-coredns-mcsapi-autoconfig +subjects: +- kind: ServiceAccount + name: {{ .Values.serviceAccounts.corednsMCSAPI.name | quote }} + namespace: {{ include "cilium.namespace" . }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-serviceaccount.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-serviceaccount.yaml new file mode 100644 index 00000000..4e572a13 --- /dev/null +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job-serviceaccount.yaml @@ -0,0 +1,20 @@ +{{- if and (or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport) .Values.clustermesh.mcsapi.corednsAutoConfigure.enabled .Values.serviceAccounts.corednsMCSAPI.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.serviceAccounts.corednsMCSAPI.name | quote }} + namespace: {{ include "cilium.namespace" . }} + {{- with .Values.commonLabels }} + labels: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if or .Values.serviceAccounts.corednsMCSAPI.annotations .Values.clustermesh.annotations }} + annotations: + {{- with .Values.clustermesh.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.serviceAccounts.corednsMCSAPI.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job.yaml b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job.yaml new file mode 100644 index 00000000..9f9c3ccd --- /dev/null +++ b/packages/system/cilium/charts/cilium/templates/clustermesh-coredns-mcsapi/job.yaml @@ -0,0 +1,82 @@ +{{- if and (or .Values.clustermesh.mcsapi.enabled .Values.clustermesh.enableMCSAPISupport) .Values.clustermesh.mcsapi.corednsAutoConfigure.enabled }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: cilium-coredns-mcsapi-autoconfig + namespace: {{ include "cilium.namespace" . }} + labels: + k8s-app: cilium-coredns-mcsapi-autoconfig + {{- with .Values.commonLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + app.kubernetes.io/part-of: cilium + annotations: + "helm.sh/hook": post-install,post-upgrade + {{- with .Values.clustermesh.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.clustermesh.mcsapi.corednsAutoConfigure.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + template: + metadata: + labels: + k8s-app: cilium-coredns-mcsapi-autoconfig + {{- with .Values.clustermesh.mcsapi.corednsAutoConfigure.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + containers: + - name: autoconfig + image: {{ include "cilium.image" .Values.clustermesh.apiserver.image | quote }} + imagePullPolicy: {{ .Values.clustermesh.apiserver.image.pullPolicy }} + {{- with .Values.clustermesh.mcsapi.corednsAutoConfigure.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + command: + - /usr/bin/clustermesh-apiserver + args: + - mcsapi-coredns-cfg + - --coredns-deployment-name={{ .Values.clustermesh.mcsapi.corednsAutoConfigure.coredns.deploymentName }} + - --coredns-configmap-name={{ .Values.clustermesh.mcsapi.corednsAutoConfigure.coredns.configMapName }} + - --coredns-namespace={{ .Values.clustermesh.mcsapi.corednsAutoConfigure.coredns.namespace }} + - --coredns-cluster-domain={{ .Values.clustermesh.mcsapi.corednsAutoConfigure.coredns.clusterDomain }} + - --coredns-clusterset-domain={{ .Values.clustermesh.mcsapi.corednsAutoConfigure.coredns.clustersetDomain }} + {{- with .Values.clustermesh.mcsapi.corednsAutoConfigure.extraArgs }} + {{- toYaml . | trim | nindent 12 }} + {{- end }} + {{- with .Values.clustermesh.mcsapi.corednsAutoConfigure.extraVolumeMounts }} + volumeMounts: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- with .Values.clustermesh.mcsapi.corednsAutoConfigure.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.clustermesh.mcsapi.corednsAutoConfigure.priorityClassName }} + priorityClassName: {{ .Values.clustermesh.mcsapi.corednsAutoConfigure.priorityClassName }} + {{- end }} + {{- with .Values.clustermesh.mcsapi.corednsAutoConfigure.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ .Values.serviceAccounts.corednsMCSAPI.name | quote }} + automountServiceAccountToken: true + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: OnFailure + {{- with .Values.clustermesh.mcsapi.corednsAutoConfigure.extraVolumes }} + volumes: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.clustermesh.mcsapi.corednsAutoConfigure.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + ttlSecondsAfterFinished: {{ .Values.clustermesh.mcsapi.corednsAutoConfigure.ttlSecondsAfterFinished }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble-relay/configmap.yaml b/packages/system/cilium/charts/cilium/templates/hubble-relay/configmap.yaml index 26b6219a..9df77bae 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble-relay/configmap.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble-relay/configmap.yaml @@ -29,6 +29,8 @@ data: pprof: {{ .Values.hubble.relay.pprof.enabled | quote }} pprof-address: {{ .Values.hubble.relay.pprof.address | quote }} pprof-port: {{ .Values.hubble.relay.pprof.port | quote }} + pprof-mutex-profile-fraction: {{ .Values.hubble.relay.pprof.mutexProfileFraction | quote }} + pprof-block-profile-rate: {{ .Values.hubble.relay.pprof.blockProfileRate | quote }} {{- end }} {{- if .Values.hubble.relay.prometheus.enabled }} metrics-listen-address: ":{{ .Values.hubble.relay.prometheus.port }}" @@ -44,4 +46,10 @@ data: disable-client-tls: true {{- end }} {{- include "hubble-relay.config.tls" . | nindent 4 }} + {{- if .Values.hubble.relay.logOptions.format }} + log-format: {{ .Values.hubble.relay.logOptions.format }} + {{- end }} + {{- if .Values.hubble.relay.logOptions.level }} + log-level: {{ .Values.hubble.relay.logOptions.level }} + {{- end }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble-relay/poddisruptionbudget.yaml b/packages/system/cilium/charts/cilium/templates/hubble-relay/poddisruptionbudget.yaml index b44cecfa..5f28b83f 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble-relay/poddisruptionbudget.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble-relay/poddisruptionbudget.yaml @@ -24,6 +24,13 @@ spec: {{- with $component.minAvailable }} minAvailable: {{ . }} {{- end }} + {{- if (semverCompare ">= 1.27-0" .Capabilities.KubeVersion.Version) }} + {{- if hasKey $component "unhealthyPodEvictionPolicy" }} + {{- with $component.unhealthyPodEvictionPolicy }} + unhealthyPodEvictionPolicy: {{ . }} + {{- end }} + {{- end }} + {{- end }} selector: matchLabels: k8s-app: hubble-relay diff --git a/packages/system/cilium/charts/cilium/templates/hubble-relay/servicemonitor.yaml b/packages/system/cilium/charts/cilium/templates/hubble-relay/servicemonitor.yaml index b6b1733c..e4b62ce0 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble-relay/servicemonitor.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble-relay/servicemonitor.yaml @@ -5,6 +5,8 @@ metadata: name: hubble-relay namespace: {{ .Values.hubble.relay.prometheus.serviceMonitor.namespace | default (include "cilium.namespace" .) }} labels: + app.kubernetes.io/part-of: cilium + app.kubernetes.io/name: hubble-relay {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} @@ -31,6 +33,9 @@ spec: endpoints: - port: metrics interval: {{ .Values.hubble.relay.prometheus.serviceMonitor.interval | quote }} + {{- if .Values.hubble.relay.prometheus.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.hubble.relay.prometheus.serviceMonitor.scrapeTimeout | quote }} + {{- end }} path: /metrics {{- with .Values.hubble.relay.prometheus.serviceMonitor.relabelings }} relabelings: diff --git a/packages/system/cilium/charts/cilium/templates/hubble-ui/_nginx.tpl b/packages/system/cilium/charts/cilium/templates/hubble-ui/_nginx.tpl index 5d3d0a80..4d8f7b90 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble-ui/_nginx.tpl +++ b/packages/system/cilium/charts/cilium/templates/hubble-ui/_nginx.tpl @@ -31,10 +31,11 @@ server { sub_filter '' ''; {{- end }} location {{ .Values.hubble.ui.baseUrl }} { + if ($http_user_agent ~* "kube-probe") { access_log off; } {{- if not (eq .Values.hubble.ui.baseUrl "/") }} rewrite ^{{ (trimSuffix "/" .Values.hubble.ui.baseUrl) }}(/.*)$ $1 break; {{- end }} - # double `/index.html` is required here + # double `/index.html` is required here try_files $uri $uri/ /index.html /index.html; } diff --git a/packages/system/cilium/charts/cilium/templates/hubble-ui/clusterrole.yaml b/packages/system/cilium/charts/cilium/templates/hubble-ui/clusterrole.yaml index b8607bd9..ebb8cbd6 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble-ui/clusterrole.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble-ui/clusterrole.yaml @@ -14,14 +14,6 @@ metadata: {{- end }} rules: -- apiGroups: - - networking.k8s.io - resources: - - networkpolicies - verbs: - - get - - list - - watch - apiGroups: - "" resources: @@ -43,12 +35,4 @@ rules: - get - list - watch -- apiGroups: - - cilium.io - resources: - - "*" - verbs: - - get - - list - - watch {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble-ui/deployment.yaml b/packages/system/cilium/charts/cilium/templates/hubble-ui/deployment.yaml index c3b3dc5a..07a94dce 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble-ui/deployment.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble-ui/deployment.yaml @@ -74,11 +74,11 @@ spec: livenessProbe: httpGet: path: /healthz - port: 8081 + port: http readinessProbe: httpGet: path: / - port: 8081 + port: http {{- with .Values.hubble.ui.frontend.resources }} resources: {{- toYaml . | trim | nindent 10 }} @@ -184,8 +184,12 @@ spec: defaultMode: 420 name: hubble-ui-nginx name: hubble-ui-nginx-conf - - emptyDir: {} - name: tmp-dir + - name: tmp-dir + {{- if .Values.hubble.ui.tmpVolume }} + {{- toYaml .Values.hubble.ui.tmpVolume | nindent 8 }} + {{- else }} + emptyDir: {} + {{- end }} {{- if .Values.hubble.relay.tls.server.enabled }} - name: hubble-ui-client-certs {{- if .Values.hubble.ui.standalone.enabled }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble-ui/poddisruptionbudget.yaml b/packages/system/cilium/charts/cilium/templates/hubble-ui/poddisruptionbudget.yaml index 35402984..93e909fb 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble-ui/poddisruptionbudget.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble-ui/poddisruptionbudget.yaml @@ -24,6 +24,13 @@ spec: {{- with $component.minAvailable }} minAvailable: {{ . }} {{- end }} + {{- if (semverCompare ">= 1.27-0" .Capabilities.KubeVersion.Version) }} + {{- if hasKey $component "unhealthyPodEvictionPolicy" }} + {{- with $component.unhealthyPodEvictionPolicy }} + unhealthyPodEvictionPolicy: {{ . }} + {{- end }} + {{- end }} + {{- end }} selector: matchLabels: k8s-app: hubble-ui diff --git a/packages/system/cilium/charts/cilium/templates/hubble-ui/service.yaml b/packages/system/cilium/charts/cilium/templates/hubble-ui/service.yaml index 90b3b1b7..ade023fe 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble-ui/service.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble-ui/service.yaml @@ -21,6 +21,9 @@ metadata: {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} + {{- with .Values.hubble.ui.service.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} spec: type: {{ .Values.hubble.ui.service.type | quote }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble/servicemonitor.yaml b/packages/system/cilium/charts/cilium/templates/hubble/servicemonitor.yaml index 1f3717fa..909f05ed 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble/servicemonitor.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble/servicemonitor.yaml @@ -6,7 +6,7 @@ metadata: namespace: {{ .Values.prometheus.serviceMonitor.namespace | default (include "cilium.namespace" .) }} labels: app.kubernetes.io/part-of: cilium - + app.kubernetes.io/name: hubble {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} @@ -33,6 +33,9 @@ spec: endpoints: - port: hubble-metrics interval: {{ .Values.hubble.metrics.serviceMonitor.interval | quote }} + {{- if .Values.hubble.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.hubble.metrics.serviceMonitor.scrapeTimeout | quote }} + {{- end }} honorLabels: true path: /metrics {{- if .Values.hubble.metrics.tls.enabled }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble/tls-cronjob/_job-spec.tpl b/packages/system/cilium/charts/cilium/templates/hubble/tls-cronjob/_job-spec.tpl index 2b37bdc0..06fb3347 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble/tls-cronjob/_job-spec.tpl +++ b/packages/system/cilium/charts/cilium/templates/hubble/tls-cronjob/_job-spec.tpl @@ -21,6 +21,10 @@ spec: drop: - ALL allowPrivilegeEscalation: false + {{- with .Values.certgen.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} command: - "/usr/bin/cilium-certgen" # Because this is executed as a job, we pass the values as command @@ -133,7 +137,6 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} - serviceAccount: {{ .Values.serviceAccounts.hubblecertgen.name | quote }} serviceAccountName: {{ .Values.serviceAccounts.hubblecertgen.name | quote }} automountServiceAccountToken: {{ .Values.serviceAccounts.hubblecertgen.automount }} {{- with .Values.imagePullSecrets }} @@ -145,9 +148,11 @@ spec: volumes: {{- toYaml . | nindent 6 }} {{- end }} - affinity: {{- with .Values.certgen.affinity }} + affinity: {{- toYaml . | nindent 8 }} {{- end }} - ttlSecondsAfterFinished: {{ .Values.certgen.ttlSecondsAfterFinished }} + {{- with .Values.certgen.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ . }} + {{- end }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble/tls-cronjob/cronjob.yaml b/packages/system/cilium/charts/cilium/templates/hubble/tls-cronjob/cronjob.yaml index 697806c6..b49c00a6 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble/tls-cronjob/cronjob.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble/tls-cronjob/cronjob.yaml @@ -23,6 +23,8 @@ metadata: {{- end }} spec: schedule: {{ .Values.hubble.tls.auto.schedule | quote }} + successfulJobsHistoryLimit: {{ .Values.certgen.cronJob.successfulJobsHistoryLimit }} + failedJobsHistoryLimit: {{ .Values.certgen.cronJob.failedJobsHistoryLimit }} concurrencyPolicy: Forbid jobTemplate: {{- include "hubble-generate-certs.job.spec" . | nindent 4 }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble/tls-cronjob/job.yaml b/packages/system/cilium/charts/cilium/templates/hubble/tls-cronjob/job.yaml index 5e4e67ff..96371916 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble/tls-cronjob/job.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble/tls-cronjob/job.yaml @@ -1,9 +1,18 @@ {{- if and .Values.hubble.enabled .Values.hubble.tls.enabled .Values.hubble.tls.auto.enabled (eq .Values.hubble.tls.auto.method "cronJob") }} +{{/* +Because Kubernetes job specs are immutable, Helm will fail patch this job if +the spec changes between releases. To avoid breaking the upgrade path, we +generate a name for the job here which is based on the checksum of the spec. +This will cause the name of the job to change if its content changes, +and in turn cause Helm to do delete the old job and replace it with a new one. +*/}} +{{- $jobSpec := include "hubble-generate-certs.job.spec" . -}} +{{- $checkSum := $jobSpec | sha256sum | trunc 10 -}} --- apiVersion: batch/v1 kind: Job metadata: - name: hubble-generate-certs + name: hubble-generate-certs-{{$checkSum}} namespace: {{ include "cilium.namespace" . }} labels: k8s-app: hubble-generate-certs @@ -12,13 +21,14 @@ metadata: {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} + {{- if or .Values.certgen.annotations.job .Values.hubble.annotations }} annotations: - "helm.sh/hook": post-install,post-upgrade {{- with .Values.certgen.annotations.job }} - {{- toYaml . | nindent 4 }} + {{- toYaml . | nindent 4 }} {{- end }} {{- with .Values.hubble.annotations }} - {{- toYaml . | nindent 4 }} + {{- toYaml . | nindent 4 }} {{- end }} -{{ include "hubble-generate-certs.job.spec" . }} + {{- end }} +{{ $jobSpec }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/metrics-server-secret.yaml b/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/metrics-server-secret.yaml index 0cc13efa..d334b986 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/metrics-server-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/metrics-server-secret.yaml @@ -10,13 +10,17 @@ kind: Secret metadata: name: hubble-metrics-server-certs namespace: {{ include "cilium.namespace" . }} - {{- with .Values.commonLabels }} labels: + {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} + cilium.io/helm-template-non-idempotent: "true" - {{- with .Values.hubble.annotations }} annotations: + {{- with .Values.hubble.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.nonIdempotentAnnotations }} {{- toYaml . | nindent 4 }} {{- end }} type: kubernetes.io/tls diff --git a/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/relay-client-secret.yaml b/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/relay-client-secret.yaml index f6ba3279..6f001dc9 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/relay-client-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/relay-client-secret.yaml @@ -3,24 +3,36 @@ {{- $cn := "*.hubble-relay.cilium.io" }} {{- $dns := list $cn }} {{- $cert := genSignedCert $cn nil $dns (.Values.hubble.tls.auto.certValidityDuration | int) .commonCA -}} +{{- $tls_crt := ($cert.Cert | b64enc) }} +{{- $tls_key := ($cert.Key | b64enc) }} +{{- with lookup "v1" "Secret" (include "cilium.namespace" .) "hubble-relay-client-certs" }} + {{- if and (index .data "tls.crt") (index .data "tls.key") }} + {{- $tls_key = (index .data "tls.key") }} + {{- $tls_crt = (index .data "tls.crt") }} + {{- end }} +{{- end }} --- apiVersion: v1 kind: Secret metadata: name: hubble-relay-client-certs namespace: {{ include "cilium.namespace" . }} - {{- with .Values.commonLabels }} labels: + {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} + cilium.io/helm-template-non-idempotent: "true" - {{- with .Values.hubble.annotations }} annotations: + {{- with .Values.hubble.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.nonIdempotentAnnotations }} {{- toYaml . | nindent 4 }} {{- end }} type: kubernetes.io/tls data: ca.crt: {{ .commonCA.Cert | b64enc }} - tls.crt: {{ $cert.Cert | b64enc }} - tls.key: {{ $cert.Key | b64enc }} + tls.crt: {{ $tls_crt }} + tls.key: {{ $tls_key }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/relay-server-secret.yaml b/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/relay-server-secret.yaml index 986b3cac..229148a0 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/relay-server-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/relay-server-secret.yaml @@ -10,13 +10,17 @@ kind: Secret metadata: name: hubble-relay-server-certs namespace: {{ include "cilium.namespace" . }} - {{- with .Values.commonLabels }} labels: + {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} + cilium.io/helm-template-non-idempotent: "true" - {{- with .Values.hubble.annotations }} annotations: + {{- with .Values.hubble.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.nonIdempotentAnnotations }} {{- toYaml . | nindent 4 }} {{- end }} type: kubernetes.io/tls diff --git a/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/server-secret.yaml b/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/server-secret.yaml index a159240d..4d214a56 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/server-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/server-secret.yaml @@ -4,24 +4,36 @@ {{- $ip := .Values.hubble.tls.server.extraIpAddresses }} {{- $dns := prepend .Values.hubble.tls.server.extraDnsNames $cn }} {{- $cert := genSignedCert $cn $ip $dns (.Values.hubble.tls.auto.certValidityDuration | int) .commonCA -}} +{{- $tls_crt := ($cert.Cert | b64enc) }} +{{- $tls_key := ($cert.Key | b64enc) }} +{{- with lookup "v1" "Secret" (include "cilium.namespace" .) "hubble-server-certs" }} + {{- if and (index .data "tls.crt") (index .data "tls.key") }} + {{- $tls_key = (index .data "tls.key") }} + {{- $tls_crt = (index .data "tls.crt") }} + {{- end }} +{{- end }} --- apiVersion: v1 kind: Secret metadata: name: hubble-server-certs namespace: {{ include "cilium.namespace" . }} - {{- with .Values.commonLabels }} labels: + {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} + cilium.io/helm-template-non-idempotent: "true" - {{- with .Values.hubble.annotations }} annotations: + {{- with .Values.hubble.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.nonIdempotentAnnotations }} {{- toYaml . | nindent 4 }} {{- end }} type: kubernetes.io/tls data: ca.crt: {{ .commonCA.Cert | b64enc }} - tls.crt: {{ $cert.Cert | b64enc }} - tls.key: {{ $cert.Key | b64enc }} + tls.crt: {{ $tls_crt }} + tls.key: {{ $tls_key }} {{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/ui-client-certs.yaml b/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/ui-client-certs.yaml index e1f62ead..8c1b40aa 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/ui-client-certs.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble/tls-helm/ui-client-certs.yaml @@ -10,13 +10,17 @@ metadata: name: hubble-ui-client-certs namespace: {{ include "cilium.namespace" . }} - {{- with .Values.commonLabels }} labels: + {{- with .Values.commonLabels }} {{- toYaml . | nindent 4 }} {{- end }} + cilium.io/helm-template-non-idempotent: "true" - {{- with .Values.hubble.annotations }} annotations: + {{- with .Values.hubble.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.nonIdempotentAnnotations }} {{- toYaml . | nindent 4 }} {{- end }} type: kubernetes.io/tls diff --git a/packages/system/cilium/charts/cilium/templates/hubble/tls-provided/metrics-server-secret.yaml b/packages/system/cilium/charts/cilium/templates/hubble/tls-provided/metrics-server-secret.yaml index 8137aef3..64183918 100644 --- a/packages/system/cilium/charts/cilium/templates/hubble/tls-provided/metrics-server-secret.yaml +++ b/packages/system/cilium/charts/cilium/templates/hubble/tls-provided/metrics-server-secret.yaml @@ -4,7 +4,7 @@ kind: Secret metadata: name: hubble-metrics-server-certs namespace: {{ include "cilium.namespace" . }} - + {{- with .Values.commonLabels }} labels: {{- toYaml . | nindent 4 }} diff --git a/packages/system/cilium/charts/cilium/templates/spire/agent/daemonset.yaml b/packages/system/cilium/charts/cilium/templates/spire/agent/daemonset.yaml index cac60877..00bfee91 100644 --- a/packages/system/cilium/charts/cilium/templates/spire/agent/daemonset.yaml +++ b/packages/system/cilium/charts/cilium/templates/spire/agent/daemonset.yaml @@ -91,7 +91,7 @@ spec: {{- with .Values.authentication.mutual.spire.install.agent.resources }} resources: {{- toYaml . | trim | nindent 12 }} - {{- end }} + {{- end }} livenessProbe: httpGet: path: /live diff --git a/packages/system/cilium/charts/cilium/templates/spire/server/statefulset.yaml b/packages/system/cilium/charts/cilium/templates/spire/server/statefulset.yaml index 3b243fc8..23dda2c0 100644 --- a/packages/system/cilium/charts/cilium/templates/spire/server/statefulset.yaml +++ b/packages/system/cilium/charts/cilium/templates/spire/server/statefulset.yaml @@ -29,6 +29,8 @@ spec: serviceName: spire-server template: metadata: + annotations: + kubectl.kubernetes.io/default-container: spire-server labels: app: spire-server {{- with .Values.commonLabels }} @@ -75,7 +77,7 @@ spec: {{- with .Values.authentication.mutual.spire.install.server.resources }} resources: {{- toYaml . | trim | nindent 10 }} - {{- end }} + {{- end }} ports: - name: grpc containerPort: 8081 diff --git a/packages/system/cilium/charts/cilium/templates/standalone-dns-proxy/configmap.yaml b/packages/system/cilium/charts/cilium/templates/standalone-dns-proxy/configmap.yaml new file mode 100644 index 00000000..9d65c1a8 --- /dev/null +++ b/packages/system/cilium/charts/cilium/templates/standalone-dns-proxy/configmap.yaml @@ -0,0 +1,28 @@ +{{- if .Values.standaloneDnsProxy.enabled }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: standalone-dns-proxy-config + namespace: {{ include "cilium.namespace" . }} + {{- with .Values.commonLabels }} + labels: + {{- toYaml . | nindent 4 }} + {{- end }} + + {{- with .Values.standaloneDnsProxy.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +data: + # Use the same L7 proxy and DNS settings as the agent for consistency + enable-l7-proxy: {{ .Values.l7Proxy | quote }} + debug: {{ .Values.standaloneDnsProxy.debug | quote }} + enable-standalone-dns-proxy: {{ .Values.standaloneDnsProxy.enabled | quote }} + enable-ipv4: {{ .Values.ipv4.enabled | quote }} + enable-ipv6: {{ .Values.ipv6.enabled | quote }} + standalone-dns-proxy-server-port: {{ .Values.standaloneDnsProxy.serverPort | quote }} + # DNS proxy configuration inherited from agent settings + tofqdns-proxy-port: {{ .Values.dnsProxy.proxyPort | quote }} + tofqdns-enable-dns-compression: {{ .Values.dnsProxy.enableDnsCompression | quote }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/standalone-dns-proxy/daemonset.yaml b/packages/system/cilium/charts/cilium/templates/standalone-dns-proxy/daemonset.yaml new file mode 100644 index 00000000..7ea150a4 --- /dev/null +++ b/packages/system/cilium/charts/cilium/templates/standalone-dns-proxy/daemonset.yaml @@ -0,0 +1,80 @@ +{{- if .Values.standaloneDnsProxy.enabled }} +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: standalone-dns-proxy + namespace: {{ include "cilium.namespace" . }} + {{- with .Values.standaloneDnsProxy.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + k8s-app: standalone-dns-proxy + app.kubernetes.io/part-of: cilium + app.kubernetes.io/name: standalone-dns-proxy + name: standalone-dns-proxy + {{- with .Values.commonLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + minReadySeconds: 5 + {{- with .Values.standaloneDnsProxy.updateStrategy }} + updateStrategy: + {{- toYaml . | nindent 4 }} + {{- end }} + selector: + matchLabels: + k8s-app: standalone-dns-proxy + template: + metadata: + annotations: + {{- if .Values.standaloneDnsProxy.rollOutPods }} + # ensure pods roll when configmap updates + cilium.io/standalone-dns-proxy-configmap-checksum: {{ include (print $.Template.BasePath "/standalone-dns-proxy/configmap.yaml") . | sha256sum | quote }} + {{- end }} + container.apparmor.security.beta.kubernetes.io/standalone-dns-proxy: "unconfined" + labels: + k8s-app: standalone-dns-proxy + name: standalone-dns-proxy + app.kubernetes.io/name: standalone-dns-proxy + app.kubernetes.io/part-of: cilium + {{- with .Values.commonLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + hostNetwork: true + automountServiceAccountToken: {{ .Values.standaloneDnsProxy.automountServiceAccountToken }} + {{- with .Values.standaloneDnsProxy.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + tolerations: + - operator: Exists + {{- with .Values.standaloneDnsProxy.tolerations }} + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: standalone-dns-proxy + image: {{ include "cilium.image" .Values.standaloneDnsProxy.image | quote }} + args: + - --config-dir=/tmp/standalone-dns-proxy/config-map + imagePullPolicy: {{ .Values.standaloneDnsProxy.image.pullPolicy }} + volumeMounts: + - mountPath: /tmp/standalone-dns-proxy/config-map + name: standalone-dns-proxy-config-path + readOnly: true + - mountPath: /var/run/standalone-dns-proxy + name: runtime-dir + securityContext: + capabilities: + add: ["NET_ADMIN", "NET_RAW"] + drop: ["ALL"] + volumes: + - configMap: + defaultMode: 420 + name: standalone-dns-proxy-config + name: standalone-dns-proxy-config-path + - emptyDir: {} + name: runtime-dir +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/validate.yaml b/packages/system/cilium/charts/cilium/templates/validate.yaml index 37da6cd6..ac3164b6 100644 --- a/packages/system/cilium/charts/cilium/templates/validate.yaml +++ b/packages/system/cilium/charts/cilium/templates/validate.yaml @@ -1,5 +1,13 @@ {{/* validate deprecated options are not being used */}} +{{/* Options removed in v1.18 */}} +{{- if (dig "enableCiliumEndpointSlice" "" .Values.AsMap) }} + {{ fail "enableCiliumEndpointSlice was deprecated in v1.16 and has been removed in v1.18. For details please refer to https://docs.cilium.io/en/v1.18/operations/upgrade/#helm-options" }} +{{- end }} +{{- if (dig "ciliumEndpointSlice" "sliceMode" "" .Values.AsMap) }} + {{ fail "ciliumEndpointSlice.sliceMode has been removed in v1.18. For details please refer to https://docs.cilium.io/en/v1.18/operations/upgrade/#helm-options" }} +{{- end }} + {{/* Options deprecated in v1.15 and removed in v1.16 */}} {{- if or (dig "encryption" "keyFile" "" .Values.AsMap) @@ -42,6 +50,11 @@ {{ fail "enableCnpStatusUpdates was deprecated in v1.14 and has been removed in v1.15. For details please refer to https://docs.cilium.io/en/v1.15/operations/upgrade/#helm-options" }} {{- end }} +{{/* validate single k8sServiceHost strategy */}} +{{- if and (and .Values.k8sServiceHostRef.name .Values.k8sServiceHostRef.key) .Values.k8sServiceHost }} + {{- fail "Both k8sServiceHostRef and k8sServiceHost are set. Please set only one of them." }} +{{- end }} + {{/* validate hubble config */}} {{- if and .Values.hubble.ui.enabled (not .Values.hubble.ui.standalone.enabled) }} {{- if not .Values.hubble.relay.enabled }} @@ -78,7 +91,7 @@ {{ fail "Only one of .Values.hubble.redact.http.headers.allow, .Values.hubble.redact.http.headers.deny can be specified"}} {{- end }} -{{- if and (or .Values.externalWorkloads.enabled .Values.clustermesh.useAPIServer) .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} +{{- if and .Values.clustermesh.useAPIServer .Values.clustermesh.apiserver.tls.auto.enabled (eq .Values.clustermesh.apiserver.tls.auto.method "certmanager") }} {{- if not .Values.clustermesh.apiserver.tls.auto.certManagerIssuerRef }} {{ fail "ClusterMesh TLS certgen method=certmanager requires that user specifies .Values.clustermesh.apiserver.tls.auto.certManagerIssuerRef" }} {{- end }} @@ -129,7 +142,7 @@ {{- end }} {{/* validate Cilium operator */}} -{{- if or .Values.ciliumEndpointSlice.enabled .Values.enableCiliumEndpointSlice }} +{{- if .Values.ciliumEndpointSlice.enabled }} {{- if eq .Values.disableEndpointCRD true }} {{ fail "if Cilium Endpoint Slice is enabled (.Values.ciliumEndpointSlice.enabled=true), it requires .Values.disableEndpointCRD=false" }} {{- end }} @@ -156,29 +169,73 @@ {{- end }} {{/* validate clustermesh-apiserver */}} + +{{- if not (list "internal" "external" | has .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode) -}} +{{- fail ".Values.clustermesh.apiserver.kvstoremesh.kvstoreMode must have the value of external or internal" -}} +{{- end -}} + {{- if .Values.clustermesh.useAPIServer }} - {{- if and (ne .Values.identityAllocationMode "crd") (ne .Values.identityAllocationMode "doublewrite-readkvstore") (ne .Values.identityAllocationMode "doublewrite-readcrd") }} - {{ fail (printf "The clustermesh-apiserver cannot be enabled in combination with .Values.identityAllocationMode=%s. To establish a Cluster Mesh, directly configure the parameters to access the remote kvstore through .Values.clustermesh.config" .Values.identityAllocationMode ) }} - {{- end }} - {{- if .Values.disableEndpointCRD }} - {{ fail "The clustermesh-apiserver cannot be enabled in combination with .Values.disableEndpointCRD=true" }} + {{- if eq "true" (include "identityAllocationCRD" .) }} + {{/* CRDs are used */}} + {{- if and .Values.disableEndpointCRD }} + {{ fail "The clustermesh-apiserver cannot be enabled in combination with .Values.disableEndpointCRD=true" }} + {{- end }} + {{- else }} + {{/* kvstore is used */}} + {{- if not .Values.clustermesh.apiserver.kvstoremesh.enabled }} + {{ fail (printf "The kvstoremesh container cannot be disabled in combination with .Values.identityAllocationMode=%s. To establish a Cluster Mesh, directly configure the parameters to access the remote kvstores through .Values.clustermesh.config" .Values.identityAllocationMode ) }} + {{- end}} {{- end }} {{- end }} -{{- if .Values.externalWorkloads.enabled }} - {{- if and (ne .Values.identityAllocationMode "crd") (ne .Values.identityAllocationMode "doublewrite-readkvstore") (ne .Values.identityAllocationMode "doublewrite-readcrd") }} - {{ fail (printf "External workloads support cannot be enabled in combination with .Values.identityAllocationMode=%s" .Values.identityAllocationMode ) }} +{{- if eq .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode "external"}} + {{- if not .Values.clustermesh.useAPIServer }} + {{- fail "kvstoremesh.kvstoreMode=external can only be used with clustermesh.useAPIServer=true" }} {{- end }} - {{- if .Values.disableEndpointCRD }} - {{ fail "External workloads support cannot be enabled in combination with .Values.disableEndpointCRD=true" }} + {{- if not .Values.clustermesh.apiserver.kvstoremesh.enabled }} + {{- fail "kvstoremesh.kvstoreMode=external can only be used with kvstoremesh.enabled=true" }} + {{- end }} + {{- if ne (toString .Values.clustermesh.apiserver.replicas) "1" }} + {{- fail "Only single clustermesh-apiserver replica is allowed when kvstoreMode=external" }} + {{- end }} + {{- if and (ne .Values.identityAllocationMode "kvstore") (ne .Values.identityAllocationMode "doublewrite-readkvstore") (ne .Values.identityAllocationMode "doublewrite-readcrd") }} + {{- fail (printf "KVStoreMesh with %s etcd cannot be enabled in combination with .Values.identityAllocationMode=%s" .Values.clustermesh.apiserver.kvstoremesh.kvstoreMode .Values.identityAllocationMode) }} {{- end }} {{- end }} -{{/*validate ClusterMesh */}} +{{/* validate ClusterMesh */}} {{- if and (ne (int .Values.clustermesh.maxConnectedClusters) 255) (ne (int .Values.clustermesh.maxConnectedClusters) 511) }} {{- fail "max-connected-clusters must be set to 255 or 511" }} {{- end }} -{{/*validate Envoy baseID */}} +{{/* validate Envoy baseID */}} {{- if not (and (ge (int .Values.envoy.baseID) 0) (le (int .Values.envoy.baseID) 4294967295)) }} {{- fail "envoy.baseID must be an int. Supported values 0 - 4294967295" }} {{- end }} + +{{/* validate enableK8sClientExponentialBackoff and extraEnv to avoid duplicate env var keys */}} +{{- if .Values.k8sClientExponentialBackoff.enabled }} + {{- range .Values.extraEnv }} + {{- if or (eq .name "KUBE_CLIENT_BACKOFF_BASE") (eq .name "KUBE_CLIENT_BACKOFF_DURATION") }} + {{ fail "k8sClientExponentialBackoff cannot be enabled when extraEnv contains KUBE_CLIENT_BACKOFF_BASE or KUBE_CLIENT_BACKOFF_DURATION" }} + {{- end }} + {{- end }} +{{- end }} + +{{/* validate Standalone DNS Proxy */}} +{{- if .Values.standaloneDnsProxy.enabled }} + {{- if not .Values.dnsProxy.proxyPort }} + {{ fail "standaloneDnsProxy requires dnsProxy.proxyPort to be explicitly set (e.g., 10094)" }} + {{- end }} + {{- if eq (int .Values.dnsProxy.proxyPort) 0 }} + {{ fail "standaloneDnsProxy requires dnsProxy.proxyPort to be set to a non-zero value (e.g., 10094). The standalone DNS proxy uses the same DNS configuration as the agent." }} + {{- end }} +{{- end }} + +{{/* validate we don't run tproxy with netkit - see GH issue 39892 */}} +{{- if hasKey .Values "bpf" }} + {{- if and (hasKey .Values.bpf "tproxy") (hasKey .Values.bpf "datapathMode") }} + {{- if and (.Values.bpf.tproxy) (list "netkit" "netkit-l2" | has .Values.bpf.datapathMode) }} + {{ fail ".Values.bpf.tproxy cannot be enabled with .Values.bpf.datapathMode=netkit or .Values.bpf.datapathMode=netkit-l2" }} + {{- end }} + {{- end }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/warnings.txt b/packages/system/cilium/charts/cilium/templates/warnings.txt new file mode 100644 index 00000000..8cc823b3 --- /dev/null +++ b/packages/system/cilium/charts/cilium/templates/warnings.txt @@ -0,0 +1,13 @@ +{{- define "cilium.warnings" }} +{{- /* TODO: move this warning to a validation failure once v1.18 is released */ -}} +{{- if or + (hasKey .Values.hubble.export "fileMaxSizeMb") + (hasKey .Values.hubble.export "fileMaxBackups") + (hasKey .Values.hubble.export "fileCompress") +-}} +- We detected that one or more Hubble export options under 'hubble.export' are currently set + ('fileMaxSizeMb', 'fileMaxBackups', 'fileCompress'). Please note that these have moved to + their corresponding exporter type ('hubble.export.static', 'hubble.export.dynamic.config.content') + and will be removed in v1.19. +{{- end -}} +{{- end -}} diff --git a/packages/system/cilium/charts/cilium/templates/ztunnel/daemonset.yaml b/packages/system/cilium/charts/cilium/templates/ztunnel/daemonset.yaml new file mode 100644 index 00000000..f9363068 --- /dev/null +++ b/packages/system/cilium/charts/cilium/templates/ztunnel/daemonset.yaml @@ -0,0 +1,165 @@ +{{- if and .Values.encryption.enabled (eq .Values.encryption.type "ztunnel") }} +--- +kind: DaemonSet +apiVersion: apps/v1 +metadata: + name: ztunnel-cilium + namespace: {{ include "cilium.namespace" . }} + {{- with .Values.encryption.ztunnel.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app: ztunnel-cilium + app.kubernetes.io/part-of: cilium + app.kubernetes.io/name: ztunnel-cilium + {{- with .Values.commonLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + revisionHistoryLimit: 10 + selector: + matchLabels: + app: ztunnel-cilium + {{- with .Values.encryption.ztunnel.updateStrategy }} + updateStrategy: + {{- toYaml . | trim | nindent 4 }} + {{- end }} + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + {{- with .Values.encryption.ztunnel.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + app: ztunnel-cilium + app.kubernetes.io/part-of: cilium + app.kubernetes.io/name: ztunnel-cilium + {{- with .Values.commonLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.encryption.ztunnel.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + hostNetwork: true + dnsPolicy: ClusterFirst + containers: + - name: istio-proxy + image: {{ include "cilium.image" .Values.encryption.ztunnel.image | quote }} + imagePullPolicy: {{ .Values.encryption.ztunnel.image.pullPolicy }} + args: + - proxy + - ztunnel + env: + - name: XDS_ADDRESS + value: "https://localhost:15012" + - name: XDS_ROOT_CA + value: "/etc/ztunnel/bootstrap-root.crt" + - name: CA_ROOT_CA + value: "/etc/ztunnel/bootstrap-root.crt" + - name: CA_ADDRESS + value: {{ .Values.encryption.ztunnel.caAddress | quote }} + - name: ISTIO_META_DNS_CAPTURE + value: "false" + - name: INPOD_UDS + value: "/var/run/cilium/ztunnel.sock" + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: ISTIO_META_ENABLE_HBONE + value: "true" + {{- with .Values.encryption.ztunnel.extraEnv }} + {{- toYaml . | trim | nindent 12 }} + {{- end }} + readinessProbe: + httpGet: + path: /healthz/ready + port: {{ .Values.encryption.ztunnel.healthPort }} + host: "127.0.0.1" + scheme: HTTP + initialDelaySeconds: {{ .Values.encryption.ztunnel.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.encryption.ztunnel.readinessProbe.periodSeconds }} + failureThreshold: {{ .Values.encryption.ztunnel.readinessProbe.failureThreshold }} + successThreshold: 1 + timeoutSeconds: 1 + {{- with .Values.encryption.ztunnel.resources }} + resources: + {{- toYaml . | trim | nindent 12 }} + {{- end }} + securityContext: + allowPrivilegeEscalation: true + capabilities: + add: + - NET_ADMIN + - SYS_ADMIN + - NET_RAW + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsGroup: 1337 + runAsNonRoot: false + runAsUser: 0 + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /var/run/cilium + name: cilium-dir + readOnly: false + - mountPath: /etc/ztunnel + name: cilium-ztunnel-secrets + readOnly: true + {{- with .Values.encryption.ztunnel.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.encryption.ztunnel.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.encryption.ztunnel.nodeSelector }} + nodeSelector: + {{- toYaml . | trim | nindent 8 }} + {{- end }} + {{- with .Values.encryption.ztunnel.tolerations }} + tolerations: + {{- toYaml . | trim | nindent 8 }} + {{- end }} + priorityClassName: {{ include "cilium.priorityClass" (list $ .Values.encryption.ztunnel.priorityClassName "system-node-critical") }} + restartPolicy: Always + terminationGracePeriodSeconds: {{ .Values.encryption.ztunnel.terminationGracePeriodSeconds }} + {{- if .Values.serviceAccounts.ztunnel.create }} + serviceAccountName: {{ .Values.serviceAccounts.ztunnel.name | quote }} + automountServiceAccountToken: {{ .Values.serviceAccounts.ztunnel.automount }} + {{- else }} + automountServiceAccountToken: false + {{- end }} + volumes: + - name: cilium-dir + hostPath: + path: /var/run/cilium + type: DirectoryOrCreate + - name: cilium-ztunnel-secrets + secret: + secretName: cilium-ztunnel-secrets + defaultMode: 420 + items: + - key: bootstrap-root.crt + path: bootstrap-root.crt + mode: 420 + {{- with .Values.encryption.ztunnel.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/ztunnel/secret.yaml b/packages/system/cilium/charts/cilium/templates/ztunnel/secret.yaml new file mode 100644 index 00000000..520857dc --- /dev/null +++ b/packages/system/cilium/charts/cilium/templates/ztunnel/secret.yaml @@ -0,0 +1,23 @@ +{{- if and .Values.encryption.enabled (eq .Values.encryption.type "ztunnel") }} +{{- if .Values.encryption.ztunnel.secrets.bootstrapRootCert }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: cilium-ztunnel-secrets + namespace: {{ include "cilium.namespace" . }} + {{- with .Values.encryption.ztunnel.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app.kubernetes.io/part-of: cilium + app.kubernetes.io/name: ztunnel-cilium + {{- with .Values.commonLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +type: Opaque +data: + bootstrap-root.crt: {{ .Values.encryption.ztunnel.secrets.bootstrapRootCert | b64enc }} +{{- end }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/templates/ztunnel/serviceaccount.yaml b/packages/system/cilium/charts/cilium/templates/ztunnel/serviceaccount.yaml new file mode 100644 index 00000000..4ef9e2bc --- /dev/null +++ b/packages/system/cilium/charts/cilium/templates/ztunnel/serviceaccount.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.encryption.enabled (eq .Values.encryption.type "ztunnel") .Values.serviceAccounts.ztunnel.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.serviceAccounts.ztunnel.name | quote }} + namespace: {{ include "cilium.namespace" . }} + {{- with .Values.commonLabels }} + labels: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if or .Values.serviceAccounts.ztunnel.annotations .Values.encryption.ztunnel.annotations }} + annotations: + {{- with .Values.encryption.ztunnel.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.serviceAccounts.ztunnel.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/packages/system/cilium/charts/cilium/values.schema.json b/packages/system/cilium/charts/cilium/values.schema.json index bf5280ac..65c84af5 100644 --- a/packages/system/cilium/charts/cilium/values.schema.json +++ b/packages/system/cilium/charts/cilium/values.schema.json @@ -58,6 +58,27 @@ "properties": { "enabled": { "type": "boolean" + }, + "nodeSpec": { + "properties": { + "securityGroupTags": { + "items": {}, + "type": "array" + }, + "securityGroups": { + "items": {}, + "type": "array" + }, + "vSwitchTags": { + "items": {}, + "type": "array" + }, + "vSwitches": { + "items": {}, + "type": "array" + } + }, + "type": "object" } }, "type": "object" @@ -440,6 +461,14 @@ "properties": { "enabled": { "type": "boolean" + }, + "nodeSpec": { + "properties": { + "azureInterfaceName": { + "type": "string" + } + }, + "type": "object" } }, "type": "object" @@ -449,6 +478,9 @@ "bbr": { "type": "boolean" }, + "bbrHostNamespaceOnly": { + "type": "boolean" + }, "enabled": { "type": "boolean" } @@ -460,6 +492,25 @@ "enabled": { "type": "boolean" }, + "legacyOriginAttribute": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "routerIDAllocation": { + "properties": { + "ipPool": { + "type": "string" + }, + "mode": { + "type": "string" + } + }, + "type": "object" + }, "secretsNamespace": { "properties": { "create": { @@ -535,10 +586,16 @@ "default": { "properties": { "burstLimit": { - "type": "null" + "type": [ + "null", + "integer" + ] }, "rateLimit": { - "type": "null" + "type": [ + "null", + "integer" + ] } }, "type": "object" @@ -597,7 +654,8 @@ "mapDynamicSizeRatio": { "type": [ "null", - "number" + "number", + "string" ] }, "masquerade": { @@ -615,6 +673,14 @@ "monitorInterval": { "type": "string" }, + "monitorTraceIPOption": { + "minimum": 0, + "maximum": 255, + "type": [ + "null", + "integer" + ] + }, "natMax": { "type": [ "null", @@ -639,6 +705,18 @@ "integer" ] }, + "policyMapPressureMetricsThreshold": { + "type": [ + "null", + "number" + ] + }, + "policyStatsMapMax": { + "type": [ + "null", + "integer" + ] + }, "preallocateMaps": { "type": "boolean" }, @@ -679,6 +757,17 @@ }, "type": "object" }, + "cronJob": { + "properties": { + "failedJobsHistoryLimit": { + "type": "integer" + }, + "successfulJobsHistoryLimit": { + "type": "integer" + } + }, + "type": "object" + }, "extraVolumeMounts": { "items": {}, "type": "array" @@ -725,12 +814,18 @@ "priorityClassName": { "type": "string" }, + "resources": { + "type": "object" + }, "tolerations": { "items": {}, "type": "array" }, "ttlSecondsAfterFinished": { - "type": "integer" + "type": [ + "null", + "integer" + ] } }, "type": "object" @@ -791,12 +886,6 @@ ] }, "type": "array" - }, - "sliceMode": { - "enum": [ - "identity", - "fcfs" - ] } }, "type": "object" @@ -991,6 +1080,9 @@ "healthPort": { "type": "integer" }, + "kvstoreMode": { + "type": "string" + }, "lifecycle": { "type": "object" }, @@ -1086,6 +1178,12 @@ "null", "array" ] + }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -1109,6 +1207,12 @@ "null", "array" ] + }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -1127,6 +1231,12 @@ "null", "array" ] + }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -1163,6 +1273,12 @@ "integer", "string" ] + }, + "unhealthyPodEvictionPolicy": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -1240,12 +1356,18 @@ "Cluster" ] }, + "externallyCreated": { + "type": "boolean" + }, "internalTrafficPolicy": { "enum": [ "Local", "Cluster" ] }, + "labels": { + "type": "object" + }, "loadBalancerClass": { "type": [ "null", @@ -1307,17 +1429,6 @@ }, "type": "object" }, - "client": { - "properties": { - "cert": { - "type": "string" - }, - "key": { - "type": "string" - } - }, - "type": "object" - }, "enableSecrets": { "type": "boolean" }, @@ -1390,11 +1501,17 @@ }, "type": "object" }, + "cacheTTL": { + "type": "string" + }, "config": { "properties": { "clusters": { "items": {}, - "type": "array" + "type": [ + "object", + "array" + ] }, "domain": { "type": "string" @@ -1414,6 +1531,88 @@ "maxConnectedClusters": { "type": "integer" }, + "mcsapi": { + "properties": { + "corednsAutoConfigure": { + "properties": { + "affinity": { + "type": "object" + }, + "annotations": { + "type": "object" + }, + "coredns": { + "properties": { + "clusterDomain": { + "type": "string" + }, + "clustersetDomain": { + "type": "string" + }, + "configMapName": { + "type": "string" + }, + "deploymentName": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "serviceAccountName": { + "type": "string" + } + }, + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "extraArgs": { + "items": {}, + "type": "array" + }, + "extraVolumeMounts": { + "items": {}, + "type": "array" + }, + "extraVolumes": { + "items": {}, + "type": "array" + }, + "nodeSelector": { + "type": "object" + }, + "podLabels": { + "type": "object" + }, + "priorityClassName": { + "type": "string" + }, + "resources": { + "type": "object" + }, + "tolerations": { + "items": {}, + "type": "array" + }, + "ttlSecondsAfterFinished": { + "type": "integer" + } + }, + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "installCRDs": { + "type": "boolean" + } + }, + "type": "object" + }, + "policyDefaultLocalCluster": { + "type": "boolean" + }, "useAPIServer": { "type": "boolean" } @@ -1443,6 +1642,9 @@ "confPath": { "type": "string" }, + "configMap": { + "type": "string" + }, "configMapKey": { "type": "string" }, @@ -1461,15 +1663,35 @@ "install": { "type": "boolean" }, + "iptablesRemoveAWSRules": { + "type": "boolean" + }, "logFile": { "type": "string" }, "resources": { "properties": { + "limits": { + "properties": { + "cpu": { + "type": [ + "integer", + "string" + ] + }, + "memory": { + "type": "string" + } + }, + "type": "object" + }, "requests": { "properties": { "cpu": { - "type": "string" + "type": [ + "integer", + "string" + ] }, "memory": { "type": "string" @@ -1492,6 +1714,27 @@ "object" ] }, + "configDriftDetection": { + "properties": { + "driftChecker": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "ignoredKeys": { + "items": {}, + "type": "array" + } + }, + "type": "object" + }, + "connectivityProbeFrequencyRatio": { + "type": [ + "null", + "number" + ] + }, "conntrackGCInterval": { "type": "string" }, @@ -1501,14 +1744,6 @@ "crdWaitTimeout": { "type": "string" }, - "customCalls": { - "properties": { - "enabled": { - "type": "boolean" - } - }, - "type": "object" - }, "daemon": { "properties": { "allowedConfigOverrides": { @@ -1569,6 +1804,12 @@ "enabled": { "type": "boolean" }, + "metricsSamplingInterval": { + "type": [ + "null", + "string" + ] + }, "verbose": { "type": [ "null", @@ -1610,6 +1851,9 @@ "minTtl": { "type": "integer" }, + "preAllocateIdentities": { + "type": "boolean" + }, "preCache": { "type": "string" }, @@ -1636,9 +1880,6 @@ }, "type": "object" }, - "enableCiliumEndpointSlice": { - "type": "boolean" - }, "enableCriticalPriorityClass": { "type": "boolean" }, @@ -1646,7 +1887,10 @@ "type": "boolean" }, "enableIPv4Masquerade": { - "type": "boolean" + "type": [ + "null", + "boolean" + ] }, "enableIPv6BIGTCP": { "type": "boolean" @@ -1657,19 +1901,16 @@ "enableInternalTrafficPolicy": { "type": "boolean" }, - "enableK8sTerminatingEndpoint": { - "type": "boolean" - }, "enableLBIPAM": { "type": "boolean" }, "enableMasqueradeRouteSource": { "type": "boolean" }, - "enableNonDefaultDenyPolicies": { + "enableNoServiceEndpointsRoutable": { "type": "boolean" }, - "enableRuntimeDeviceDetection": { + "enableNonDefaultDenyPolicies": { "type": "boolean" }, "enableXTSocketFallback": { @@ -1717,8 +1958,30 @@ "cidr": { "type": "string" }, + "egress": { + "properties": { + "allowRemoteNodeIdentities": { + "type": "boolean" + }, + "cidr": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, "enabled": { "type": "boolean" + }, + "ingress": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" } }, "type": "object" @@ -1733,6 +1996,184 @@ } }, "type": "object" + }, + "ztunnel": { + "properties": { + "affinity": { + "type": "object" + }, + "annotations": { + "type": "object" + }, + "caAddress": { + "type": "string" + }, + "extraEnv": { + "items": {}, + "type": "array" + }, + "extraVolumeMounts": { + "items": {}, + "type": "array" + }, + "extraVolumes": { + "items": {}, + "type": "array" + }, + "healthPort": { + "type": "integer" + }, + "image": { + "properties": { + "digest": { + "type": [ + "null", + "string" + ] + }, + "override": { + "type": [ + "null", + "string" + ] + }, + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + }, + "useDigest": { + "type": "boolean" + } + }, + "type": "object" + }, + "nodeSelector": { + "properties": { + "kubernetes.io/os": { + "type": "string" + } + }, + "type": "object" + }, + "podAnnotations": { + "type": "object" + }, + "podLabels": { + "type": "object" + }, + "priorityClassName": { + "type": [ + "null", + "string" + ] + }, + "readinessProbe": { + "properties": { + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + } + }, + "type": "object" + }, + "resources": { + "properties": { + "requests": { + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "secrets": { + "properties": { + "bootstrapRootCert": { + "type": [ + "null", + "string" + ] + } + }, + "type": "object" + }, + "terminationGracePeriodSeconds": { + "type": "integer" + }, + "tolerations": { + "items": { + "anyOf": [ + { + "properties": { + "effect": { + "type": "string" + }, + "operator": { + "type": "string" + } + } + }, + { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + } + } + }, + { + "properties": { + "effect": { + "type": "string" + }, + "operator": { + "type": "string" + } + } + } + ] + }, + "type": "array" + }, + "updateStrategy": { + "properties": { + "rollingUpdate": { + "properties": { + "maxSurge": { + "type": "integer" + }, + "maxUnavailable": { + "type": "integer" + } + }, + "type": "object" + }, + "type": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" } }, "type": "object" @@ -1748,6 +2189,9 @@ "endpointLockdownOnMapOverflow": { "type": "boolean" }, + "endpointPolicyUpdateTimeoutDuration": { + "type": "null" + }, "endpointRoutes": { "properties": { "enabled": { @@ -1789,6 +2233,49 @@ "items": {}, "type": "array" }, + "nodeSpec": { + "properties": { + "deleteOnTermination": { + "type": [ + "null", + "boolean" + ] + }, + "disablePrefixDelegation": { + "type": "boolean" + }, + "excludeInterfaceTags": { + "items": {}, + "type": "array" + }, + "firstInterfaceIndex": { + "type": [ + "null", + "integer" + ] + }, + "securityGroupTags": { + "items": {}, + "type": "array" + }, + "securityGroups": { + "items": {}, + "type": "array" + }, + "subnetIDs": { + "items": {}, + "type": "array" + }, + "subnetTags": { + "items": {}, + "type": "array" + }, + "usePrimaryAddress": { + "type": "boolean" + } + }, + "type": "object" + }, "subnetIDsFilter": { "items": {}, "type": "array" @@ -1796,9 +2283,6 @@ "subnetTagsFilter": { "items": {}, "type": "array" - }, - "updateEC2AdapterLimitViaAPI": { - "type": "boolean" } }, "type": "object" @@ -1934,6 +2418,12 @@ "string" ] }, + "clusterMaxConnections": { + "type": "integer" + }, + "clusterMaxRequests": { + "type": "integer" + }, "connectTimeoutSeconds": { "type": "integer" }, @@ -1995,6 +2485,9 @@ "httpRetryCount": { "type": "integer" }, + "httpUpstreamLingerTimeout": { + "type": "null" + }, "idleTimeoutDurationSeconds": { "type": "integer" }, @@ -2024,11 +2517,18 @@ }, "type": "object" }, + "initContainers": { + "items": {}, + "type": "array" + }, "initialFetchTimeoutSeconds": { "type": "integer" }, "livenessProbe": { "properties": { + "enabled": { + "type": "boolean" + }, "failureThreshold": { "type": "integer" }, @@ -2088,6 +2588,9 @@ "maxConnectionDurationSeconds": { "type": "integer" }, + "maxGlobalDownstreamConnections": { + "type": "integer" + }, "maxRequestsPerConnection": { "type": "integer" }, @@ -2163,6 +2666,9 @@ "anyOf": [ { "properties": { + "action": { + "type": "string" + }, "replacement": { "type": "string" }, @@ -2184,6 +2690,12 @@ ] }, "type": "array" + }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -2250,6 +2762,9 @@ }, "startupProbe": { "properties": { + "enabled": { + "type": "boolean" + }, "failureThreshold": { "type": "integer" }, @@ -2259,6 +2774,9 @@ }, "type": "object" }, + "streamIdleTimeoutDurationSeconds": { + "type": "integer" + }, "terminationGracePeriodSeconds": { "type": "integer" }, @@ -2295,6 +2813,9 @@ }, "type": "object" }, + "useOriginalSourceAddress": { + "type": "boolean" + }, "xffNumTrustedHopsL7PolicyEgress": { "type": "integer" }, @@ -2347,22 +2868,6 @@ }, "type": "object" }, - "externalIPs": { - "properties": { - "enabled": { - "type": "boolean" - } - }, - "type": "object" - }, - "externalWorkloads": { - "properties": { - "enabled": { - "type": "boolean" - } - }, - "type": "object" - }, "extraArgs": { "items": {}, "type": "array" @@ -2478,14 +2983,6 @@ "healthPort": { "type": "integer" }, - "highScaleIPcache": { - "properties": { - "enabled": { - "type": "boolean" - } - }, - "type": "object" - }, "hostFirewall": { "properties": { "enabled": { @@ -2494,14 +2991,6 @@ }, "type": "object" }, - "hostPort": { - "properties": { - "enabled": { - "type": "boolean" - } - }, - "type": "object" - }, "hubble": { "properties": { "annotations": { @@ -2548,14 +3037,30 @@ "anyOf": [ { "properties": { + "aggregationInterval": { + "type": "string" + }, "excludeFilters": { "items": {}, "type": "array" }, + "fieldAggregate": { + "items": {}, + "type": "array" + }, "fieldMask": { "items": {}, "type": "array" }, + "fileCompress": { + "type": "boolean" + }, + "fileMaxBackups": { + "type": "integer" + }, + "fileMaxSizeMb": { + "type": "integer" + }, "filePath": { "type": "string" }, @@ -2584,14 +3089,11 @@ }, "type": "object" }, - "fileMaxBackups": { - "type": "integer" - }, - "fileMaxSizeMb": { - "type": "integer" - }, "static": { "properties": { + "aggregationInterval": { + "type": "string" + }, "allowList": { "items": {}, "type": "array" @@ -2603,10 +3105,23 @@ "enabled": { "type": "boolean" }, + "fieldAggregate": { + "items": {}, + "type": "array" + }, "fieldMask": { "items": {}, "type": "array" }, + "fileCompress": { + "type": "boolean" + }, + "fileMaxBackups": { + "type": "integer" + }, + "fileMaxSizeMb": { + "type": "integer" + }, "filePath": { "type": "string" } @@ -2710,6 +3225,9 @@ "anyOf": [ { "properties": { + "action": { + "type": "string" + }, "replacement": { "type": "string" }, @@ -2732,6 +3250,12 @@ }, "type": "array" }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] + }, "tlsConfig": { "type": "object" } @@ -2788,6 +3312,14 @@ }, "type": "object" }, + "networkPolicyCorrelation": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, "peerService": { "properties": { "clusterDomain": { @@ -2884,12 +3416,6 @@ "annotations": { "type": "object" }, - "dialTimeout": { - "type": [ - "null", - "string" - ] - }, "enabled": { "type": "boolean" }, @@ -2948,6 +3474,23 @@ "listenPort": { "type": "string" }, + "logOptions": { + "properties": { + "format": { + "type": [ + "null", + "string" + ] + }, + "level": { + "type": [ + "null", + "string" + ] + } + }, + "type": "object" + }, "nodeSelector": { "properties": { "kubernetes.io/os": { @@ -2977,6 +3520,12 @@ "integer", "string" ] + }, + "unhealthyPodEvictionPolicy": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -2988,6 +3537,14 @@ "properties": { "fsGroup": { "type": "integer" + }, + "seccompProfile": { + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" } }, "type": "object" @@ -2997,9 +3554,15 @@ "address": { "type": "string" }, + "blockProfileRate": { + "type": "integer" + }, "enabled": { "type": "boolean" }, + "mutexProfileFraction": { + "type": "integer" + }, "port": { "type": "integer" } @@ -3042,6 +3605,12 @@ "null", "array" ] + }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -3066,6 +3635,9 @@ }, "securityContext": { "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, "capabilities": { "properties": { "drop": { @@ -3089,6 +3661,14 @@ }, "runAsUser": { "type": "integer" + }, + "seccompProfile": { + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" } }, "type": "object" @@ -3326,6 +3906,11 @@ "type": "object" }, "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + } + }, "type": "object" } }, @@ -3381,6 +3966,11 @@ "type": "object" }, "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + } + }, "type": "object" }, "server": { @@ -3462,6 +4052,12 @@ "integer", "string" ] + }, + "unhealthyPodEvictionPolicy": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -3497,6 +4093,9 @@ "annotations": { "type": "object" }, + "labels": { + "type": "object" + }, "nodePort": { "type": "integer" }, @@ -3541,6 +4140,9 @@ }, "type": "object" }, + "tmpVolume": { + "type": "object" + }, "tolerations": { "items": {}, "type": "array" @@ -3580,6 +4182,13 @@ "identityChangeGracePeriod": { "type": "string" }, + "identityManagementMode": { + "enum": [ + "agent", + "operator", + "both" + ] + }, "image": { "properties": { "digest": { @@ -3775,6 +4384,33 @@ "multiPoolPreAllocation": { "type": "string" }, + "nodeSpec": { + "properties": { + "ipamMaxAllocate": { + "type": [ + "null", + "integer" + ] + }, + "ipamMinAllocate": { + "type": [ + "null", + "integer" + ] + }, + "ipamPreAllocate": { + "type": [ + "null", + "integer" + ] + }, + "ipamStaticIPTags": { + "items": {}, + "type": "array" + } + }, + "type": "object" + }, "operator": { "properties": { "autoCreateCiliumPodIPPools": { @@ -3866,6 +4502,20 @@ }, "type": "object" }, + "k8sClientExponentialBackoff": { + "properties": { + "backoffBaseSeconds": { + "type": "integer" + }, + "backoffMaxDurationSeconds": { + "type": "integer" + }, + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, "k8sClientRateLimit": { "properties": { "burst": { @@ -3911,6 +4561,23 @@ "k8sServiceHost": { "type": "string" }, + "k8sServiceHostRef": { + "properties": { + "key": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, "k8sServiceLookupConfigMapName": { "type": [ "null", @@ -3938,6 +4605,12 @@ "kubeConfigPath": { "type": "string" }, + "kubeProxyReplacement": { + "type": [ + "string", + "boolean" + ] + }, "kubeProxyReplacementHealthzBindAddr": { "type": "string" }, @@ -3945,9 +4618,6 @@ "properties": { "enabled": { "type": "boolean" - }, - "refreshPeriod": { - "type": "string" } }, "type": "object" @@ -3993,9 +4663,6 @@ "acceleration": { "type": "string" }, - "experimental": { - "type": "boolean" - }, "l7": { "properties": { "algorithm": { @@ -4010,6 +4677,23 @@ } }, "type": "object" + }, + "serviceTopology": { + "type": "boolean" + } + }, + "type": "object" + }, + "localRedirectPolicies": { + "properties": { + "addressMatcherCIDRs": { + "type": [ + "null", + "array" + ] + }, + "enabled": { + "type": "boolean" } }, "type": "object" @@ -4087,9 +4771,6 @@ }, "enableHealthCheckLoadBalancerIP": { "type": "boolean" - }, - "enabled": { - "type": "boolean" } }, "type": "object" @@ -4203,7 +4884,10 @@ "requests": { "properties": { "cpu": { - "type": "string" + "type": [ + "integer", + "string" + ] }, "memory": { "type": "string" @@ -4216,6 +4900,9 @@ }, "securityContext": { "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, "capabilities": { "properties": { "add": { @@ -4292,6 +4979,9 @@ } }, "type": "object" + }, + "waitForCloudInit": { + "type": "boolean" } }, "type": "object" @@ -4469,6 +5159,12 @@ "integer", "string" ] + }, + "unhealthyPodEvictionPolicy": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -4477,6 +5173,16 @@ "type": "object" }, "podSecurityContext": { + "properties": { + "seccompProfile": { + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" + } + }, "type": "object" }, "pprof": { @@ -4484,9 +5190,15 @@ "address": { "type": "string" }, + "blockProfileRate": { + "type": "integer" + }, "enabled": { "type": "boolean" }, + "mutexProfileFraction": { + "type": "integer" + }, "port": { "type": "integer" } @@ -4535,6 +5247,36 @@ "null", "array" ] + }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] + } + }, + "type": "object" + }, + "tls": { + "properties": { + "enabled": { + "type": "boolean" + }, + "server": { + "properties": { + "existingSecret": { + "type": "string" + }, + "mtls": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" } }, "type": "object" @@ -4555,6 +5297,26 @@ "type": "boolean" }, "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "drop": { + "items": { + "anyOf": [ + { + "type": "string" + } + ] + }, + "type": "array" + } + }, + "type": "object" + } + }, "type": "object" }, "setNodeNetworkStatus": { @@ -4574,6 +5336,39 @@ "anyOf": [ { "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + } + } + }, + { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + } + } + }, + { + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + } + } + }, + { + "properties": { + "key": { + "type": "string" + }, "operator": { "type": "string" } @@ -4581,7 +5376,10 @@ } ] }, - "type": "array" + "type": [ + "null", + "array" + ] }, "topologySpreadConstraints": { "items": {}, @@ -4594,6 +5392,12 @@ }, "restart": { "type": "boolean" + }, + "selector": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -4630,6 +5434,9 @@ "properties": { "enabled": { "type": "boolean" + }, + "packetizationLayerPMTUDMode": { + "type": "string" } }, "type": "object" @@ -4649,6 +5456,14 @@ } }, "type": "object" + }, + "seccompProfile": { + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" } }, "type": "object" @@ -4660,6 +5475,9 @@ "array" ] }, + "policyDenyResponse": { + "type": "string" + }, "policyEnforcementMode": { "type": "string" }, @@ -4668,9 +5486,15 @@ "address": { "type": "string" }, + "blockProfileRate": { + "type": "integer" + }, "enabled": { "type": "boolean" }, + "mutexProfileFraction": { + "type": "integer" + }, "port": { "type": "integer" } @@ -4722,6 +5546,37 @@ "enabled": { "type": "boolean" }, + "envoy": { + "properties": { + "image": { + "properties": { + "digest": { + "type": "string" + }, + "override": { + "type": [ + "null", + "string" + ] + }, + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + }, + "useDigest": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, "extraEnv": { "items": {}, "type": "array" @@ -4789,6 +5644,12 @@ "integer", "string" ] + }, + "unhealthyPodEvictionPolicy": { + "type": [ + "null", + "string" + ] } }, "type": "object" @@ -4817,6 +5678,11 @@ "type": "object" }, "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + } + }, "type": "object" }, "terminationGracePeriodSeconds": { @@ -4917,6 +5783,9 @@ "anyOf": [ { "properties": { + "action": { + "type": "string" + }, "replacement": { "type": "string" }, @@ -4939,6 +5808,12 @@ }, "type": "array" }, + "scrapeTimeout": { + "type": [ + "null", + "string" + ] + }, "trustCRDsExist": { "type": "boolean" } @@ -5029,8 +5904,17 @@ }, "type": "object" }, + "secretsNamespaceAnnotations": { + "type": "object" + }, + "secretsNamespaceLabels": { + "type": "object" + }, "securityContext": { "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, "capabilities": { "properties": { "applySysctlOverwrites": { @@ -5085,6 +5969,9 @@ { "type": "string" }, + { + "type": "string" + }, { "type": "string" } @@ -5200,6 +6087,23 @@ }, "type": "object" }, + "corednsMCSAPI": { + "properties": { + "annotations": { + "type": "object" + }, + "automount": { + "type": "boolean" + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, "envoy": { "properties": { "annotations": { @@ -5321,6 +6225,23 @@ } }, "type": "object" + }, + "ztunnel": { + "properties": { + "annotations": { + "type": "object" + }, + "automount": { + "type": "boolean" + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + }, + "type": "object" } }, "type": "object" @@ -5339,6 +6260,86 @@ }, "type": "object" }, + "standaloneDnsProxy": { + "properties": { + "annotations": { + "type": "object" + }, + "automountServiceAccountToken": { + "type": "boolean" + }, + "debug": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "image": { + "properties": { + "digest": { + "type": "string" + }, + "override": { + "type": [ + "null", + "string" + ] + }, + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + }, + "useDigest": { + "type": "boolean" + } + }, + "type": "object" + }, + "nodeSelector": { + "properties": { + "kubernetes.io/os": { + "type": "string" + } + }, + "type": "object" + }, + "rollOutPods": { + "type": "boolean" + }, + "serverPort": { + "type": "integer" + }, + "tolerations": { + "items": {}, + "type": "array" + }, + "updateStrategy": { + "properties": { + "rollingUpdate": { + "properties": { + "maxSurge": { + "type": "integer" + }, + "maxUnavailable": { + "type": "integer" + } + }, + "type": "object" + }, + "type": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, "startupProbe": { "properties": { "failureThreshold": { @@ -5350,9 +6351,6 @@ }, "type": "object" }, - "svcSourceRangeCheck": { - "type": "boolean" - }, "synchronizeK8sNodes": { "type": "boolean" }, @@ -5437,6 +6435,9 @@ }, "type": "object" }, + "tmpVolume": { + "type": "object" + }, "tolerations": { "items": { "anyOf": [ @@ -5460,6 +6461,9 @@ "tunnelSourcePortRange": { "type": "string" }, + "underlayProtocol": { + "type": "string" + }, "updateStrategy": { "properties": { "rollingUpdate": { diff --git a/packages/system/cilium/charts/cilium/values.yaml b/packages/system/cilium/charts/cilium/values.yaml index 28b8ec20..66f76982 100644 --- a/packages/system/cilium/charts/cilium/values.yaml +++ b/packages/system/cilium/charts/cilium/values.yaml @@ -6,7 +6,6 @@ # type: [null, string] # @schema # -- namespaceOverride allows to override the destination namespace for Cilium resources. -# This property allows to use Cilium as part of an Umbrella Chart with different targets. namespaceOverride: "" # @schema # type: [null, object] @@ -29,7 +28,7 @@ debug: # @schema # -- Configure verbosity levels for debug logging # This option is used to enable debug messages for operations related to such - # sub-system such as (e.g. kvstore, envoy, datapath or policy), and flow is + # sub-system such as (e.g. kvstore, envoy, datapath, policy, or tagged), and flow is # for enabling debug messages emitted per request, message and connection. # Multiple values can be set via a space-separated string (e.g. "datapath envoy"). # @@ -39,7 +38,16 @@ debug: # - envoy # - datapath # - policy + # - tagged verbose: ~ + # -- Set the agent-internal metrics sampling frequency. This sets the + # frequency of the internal sampling of the agent metrics. These are + # available via the "cilium-dbg shell -- metrics -s" command and are + # part of the metrics HTML page included in the sysdump. + # @schema + # type: [null, string] + # @schema + metricsSamplingInterval: "5m" rbac: # -- Enable creation of Resource-Based Access Control configuration. create: true @@ -52,6 +60,18 @@ iptablesRandomFully: false # -- (string) Kubernetes config path # @default -- `"~/.kube/config"` kubeConfigPath: "" +# -- Configure the Kubernetes service endpoint dynamically using a ConfigMap. Mutually exclusive with `k8sServiceHost`. +k8sServiceHostRef: + # @schema + # type: [string, null] + # @schema + # -- (string) name of the ConfigMap containing the Kubernetes service endpoint + name: + # @schema + # type: [string, null] + # @schema + # -- (string) Key in the ConfigMap containing the Kubernetes service endpoint + key: # -- (string) Kubernetes service host - use "auto" for automatic lookup from the cluster-info ConfigMap k8sServiceHost: "" # @schema @@ -103,6 +123,14 @@ k8sClientRateLimit: # The rate limiter will allow short bursts with a higher rate. # @default -- 200 burst: +# -- Configure exponential backoff for client-go in Cilium agent. +k8sClientExponentialBackoff: + # -- Enable exponential backoff for client-go in Cilium agent. + enabled: true + # -- Configure base (in seconds) for exponential backoff. + backoffBaseSeconds: 1 + # -- Configure maximum duration (in seconds) for exponential backoff. + backoffMaxDurationSeconds: 120 cluster: # -- Name of the cluster. Only required for Cluster Mesh and mutual authentication with SPIRE. # It must respect the following constraints: @@ -176,14 +204,42 @@ serviceAccounts: name: hubble-generate-certs automount: true annotations: {} + # -- CorednsMCSAPI is used if clustermesh.mcsapi.corednsAutoConfigure.enabled=true + corednsMCSAPI: + create: true + name: cilium-coredns-mcsapi-autoconfig + automount: true + annotations: {} + # -- Ztunnel is used if encryption.type=ztunnel + ztunnel: + create: true + name: ztunnel-cilium + automount: false + annotations: {} # -- Configure termination grace period for cilium-agent DaemonSet. terminationGracePeriodSeconds: 1 # -- Install the cilium agent resources. agent: true -# -- Agent container name. +# -- Agent daemonset name. name: cilium # -- Roll out cilium agent pods automatically when configmap is updated. rollOutCiliumPods: false +# -- Configuration for the ConfigMap drift detection feature. +# When enabled, the agent continuously watches the cilium-config ConfigMap +# and exposes a cilium_drift_checker_config_delta Prometheus metric reporting +# the number of keys that differ between the ConfigMap and the agent's active +# settings. A non-zero value indicates that the agent has not yet applied all +# current ConfigMap changes and needs to be restarted. +configDriftDetection: + # -- Enable watching of the cilium-config ConfigMap and reflecting its + # contents into the agent's internal DynamicConfig table. + enabled: true + # -- Enable the drift checker which compares the DynamicConfig table against + # the agent's active settings and publishes the + # cilium_drift_checker_config_delta metric. + driftChecker: true + # -- List of config-map keys to ignore when computing the drift delta. + ignoredKeys: [] # -- Agent container image. image: # @schema @@ -191,10 +247,10 @@ image: # @schema override: ~ repository: "quay.io/cilium/cilium" - tag: "v1.17.4" + tag: "v1.19.3" pullPolicy: "IfNotPresent" # cilium-digest - digest: "sha256:24a73fe795351cf3279ac8e84918633000b52a9654ff73a6b0d7223bcff4a67a" + digest: sha256:2e61680593cddca8b6c055f6d4c849d87a26a1c91c7e3b8b56c7fb76ab7b7b10 useDigest: true # -- Scheduling configurations for cilium pods scheduling: @@ -270,6 +326,8 @@ podSecurityContext: # -- AppArmorProfile options for the `cilium-agent` and init containers appArmorProfile: type: "Unconfined" + seccompProfile: + type: "Unconfined" # -- Annotations to be added to agent pods podAnnotations: {} # -- Labels to be added to agent pods @@ -289,6 +347,8 @@ initResources: {} securityContext: # -- User to run the pod with # runAsUser: 0 + # -- disable privilege escalation + allowPrivilegeEscalation: false # -- Run the pod with elevated privileges privileged: false # -- SELinux options for the `cilium-agent` and init containers @@ -331,6 +391,8 @@ securityContext: - SETGID # Allow to execute program that changes UID (e.g. required for package installation) - SETUID + # Allow to read dmesg and get kernel pointers when kptr_restrict=1 + - SYSLOG # -- Capabilities for the `mount-cgroup` init container mountCgroup: # Only used for 'mount' cgroup @@ -401,9 +463,16 @@ azure: # clientID: 00000000-0000-0000-0000-000000000000 # clientSecret: 00000000-0000-0000-0000-000000000000 # userAssignedIdentityID: 00000000-0000-0000-0000-000000000000 + nodeSpec: + azureInterfaceName: "" alibabacloud: # -- Enable AlibabaCloud ENI integration enabled: false + nodeSpec: + vSwitches: [] + vSwitchTags: [] + securityGroups: [] + securityGroupTags: [] # -- Enable bandwidth manager to optimize TCP and UDP workloads and allow # for rate-limiting traffic from individual Pods with EDT (Earliest Departure # Time) through the "kubernetes.io/egress-bandwidth" Pod annotation. @@ -412,15 +481,11 @@ bandwidthManager: enabled: false # -- Activate BBR TCP congestion control for Pods bbr: false + # -- Activate BBR TCP congestion control for Pods in the host namespace only. + bbrHostNamespaceOnly: false # -- Configure standalone NAT46/NAT64 gateway nat46x64Gateway: - # -- Enable RFC8215-prefixed translation - enabled: false -# -- EnableHighScaleIPcache enables the special ipcache mode for high scale -# clusters. The ipcache content will be reduced to the strict minimum and -# traffic will be encapsulated to carry security identities. -highScaleIPcache: - # -- Enable the high scale mode for the ipcache. + # -- Enable RFC6052-prefixed translation enabled: false # -- Configure L2 announcements l2announcements: @@ -438,8 +503,9 @@ l2podAnnouncements: enabled: false # -- Interface used for sending Gratuitous ARP pod announcements interface: "eth0" -# -- This feature set enables virtual BGP routers to be created via -# CiliumBGPPeeringPolicy CRDs. + # -- A regular expression matching interfaces used for sending Gratuitous ARP pod announcements + # interfacePattern: "" +# -- This feature set enables virtual BGP routers to be created via BGP CRDs. bgpControlPlane: # -- Enables the BGP control plane. enabled: false @@ -449,16 +515,33 @@ bgpControlPlane: create: false # -- The name of the secret namespace to which Cilium agents are given read access name: kube-system - # -- Status reporting settings (BGPv2 only) + # -- Status reporting settings statusReport: - # -- Enable/Disable BGPv2 status reporting + # -- Enable/Disable BGP status reporting # It is recommended to enable status reporting in general, but if you have any issue # such as high API server load, you can disable it by setting this to false. enabled: true + # -- BGP router-id allocation mode + routerIDAllocation: + # -- BGP router-id allocation mode. In default mode, the router-id is derived from the IPv4 address if it is available, or else it is determined by the lower 32 bits of the MAC address. + mode: "default" + # -- IP pool to allocate the BGP router-id from when the mode is ip-pool. + ipPool: "" + # -- Legacy BGP ORIGIN attribute settings + legacyOriginAttribute: + # -- Enable/Disable advertising LoadBalancerIP routes with the legacy + # BGP ORIGIN attribute value INCOMPLETE (2) instead of the default IGP (0). + # Enable for compatibility with the legacy behavior of MetalLB integration. + enabled: false pmtuDiscovery: # -- Enable path MTU discovery to send ICMP fragmentation-needed replies to # the client. enabled: false + # -- Enable kernel probing path MTU discovery for Pods which uses different message + # sizes to search for correct MTU value. + # Valid values are: always, blackhole, disabled and unset (or empty). If value + # is 'unset' or left empty then will not try to override setting. + packetizationLayerPMTUDMode: "blackhole" bpf: autoMount: # -- Enable automatic mount of BPF filesystem @@ -506,8 +589,11 @@ bpf: # Helm configuration for BPF events map rate limiting is experimental and might change # in upcoming releases. events: - # -- Default settings for all types of events except dbg and pcap. + # -- Default settings for all types of events except dbg. default: + # @schema + # type: [null, integer] + # @schema # -- (int) Configure the limit of messages per second that can be written to # BPF events map. The number of messages is averaged, meaning that if no messages # were written to the map over 5 seconds, it's possible to write more events @@ -516,6 +602,9 @@ bpf: # and rateLimit to 0 disables BPF events rate limiting. # @default -- `0` rateLimit: ~ + # @schema + # type: [null, integer] + # @schema # -- (int) Configure the maximum number of messages that can be written to BPF events # map in 1 second. If burstLimit is greater than 0, non-zero value for rateLimit must # also be provided lest the configuration is considered invalid. Setting both burstLimit @@ -560,9 +649,20 @@ bpf: # type: [null, integer] # @schema policyMapMax: 16384 + # -- (float64) Configure threshold for emitting pressure metrics of policy maps. # @schema # type: [null, number] # @schema + # @default -- `0.1` + policyMapPressureMetricsThreshold: ~ + # -- Configure the maximum number of entries in global policy stats map. + # @schema + # type: [null, integer] + # @schema + policyStatsMapMax: 65536 + # @schema + # type: [null, number, string] + # @schema # -- (float64) Configure auto-sizing for all BPF maps based on available memory. # ref: https://docs.cilium.io/en/stable/network/ebpf/maps/ # @default -- `0.0025` @@ -612,7 +712,8 @@ bpf: # type: [null, boolean] # @schema # -- (bool) Configure the eBPF-based TPROXY (beta) to reduce reliance on iptables rules - # for implementing Layer 7 policy. + # for implementing Layer 7 policy. Note this is incompatible with netkit (`bpf.datapathMode=netkit`, + # `bpf.datapathMode=netkit-l2`). # @default -- `false` tproxy: ~ # @schema @@ -622,6 +723,15 @@ bpf: # [0] will allow all VLAN id's without any filtering. # @default -- `[]` vlanBypass: ~ + # -- Configure the IP tracing option type. + # This option is used to specify the IP option type to use for tracing. + # The value must be an integer between 0 and 255. + # @schema + # type: [null, integer] + # minimum: 0 + # maximum: 255 + # @schema + monitorTraceIPOption: 0 # -- (bool) Disable ExternalIP mitigation (CVE-2020-8554) # @default -- `false` disableExternalIPMitigation: false @@ -629,7 +739,8 @@ bpf: # supported kernels. # @default -- `true` enableTCX: true - # -- (string) Mode for Pod devices for the core datapath (veth, netkit, netkit-l2, lb-only) + # -- (string) Mode for Pod devices for the core datapath (veth, netkit, netkit-l2). + # Note netkit is incompatible with TPROXY (`bpf.tproxy`). # @default -- `veth` datapathMode: veth # -- Enable BPF clock source probing for more efficient tick retrieval. @@ -699,12 +810,15 @@ cni: # readCniConf: /host/etc/cni/net.d/05-sample.conflist.input # -- When defined, configMap will mount the provided value as ConfigMap and - # interpret the cniConf variable as CNI configuration file and write it - # when the agent starts up - # configMap: cni-configuration - + # interpret the 'cni.configMapKey' value as CNI configuration file and write it + # when the agent starts up. + configMap: "" # -- Configure the key in the CNI ConfigMap to read the contents of - # the CNI configuration from. + # the CNI configuration from. For this to be effective, the 'cni.configMap' + # parameter must be specified too. + # Note that the 'cni.configMap' parameter is the name of the ConfigMap, while + # 'cni.configMapKey' is the name of the key in the ConfigMap data containing + # the actual configuration. configMapKey: cni-config # -- Configure the path to where to mount the ConfigMap inside the agent pod. confFileMountPath: /tmp/cni-configuration @@ -714,10 +828,29 @@ cni: # -- Specifies the resources for the cni initContainer resources: requests: + # @schema + # type: [integer, string] + # @schema cpu: 100m memory: 10Mi + limits: + # @schema + # type: [integer, string] + # @schema + cpu: 1 + memory: 1Gi # -- Enable route MTU for pod netns when CNI chaining is used enableRouteMTUForCNIChaining: false + # -- Enable the removal of iptables rules created by the AWS CNI VPC plugin. + iptablesRemoveAWSRules: true +# @schema +# type: [null, number] +# @schema +# -- (float64) Ratio of the connectivity probe frequency vs resource usage, a float in +# [0, 1]. 0 will give more frequent probing, 1 will give less frequent probing. Probing +# frequency is dynamically adjusted based on the cluster size. +# @default -- `0.5` +connectivityProbeFrequencyRatio: ~ # -- (string) Configure how frequently garbage collection should occur for the datapath # connection tracking table. # @default -- `"0s"` @@ -730,10 +863,6 @@ conntrackGCMaxInterval: "" # -- (string) Configure timeout in which Cilium will exit if CRDs are not available # @default -- `"5m"` crdWaitTimeout: "" -# -- Tail call hooks for custom eBPF programs. -customCalls: - # -- Enable tail call hooks for custom eBPF programs. - enabled: false daemon: # -- Configure where Cilium runtime state should be stored. runPath: "/var/run/cilium" @@ -776,6 +905,12 @@ daemon: # # By default, this functionality is enabled enableSourceIPVerification: true +# -- Configure temporary volume for cilium-agent +tmpVolume: {} +# emptyDir: +# sizeLimit: "100Mi" +# medium: "Memory" + # -- Specify which network interfaces can run the eBPF datapath. This means # that a packet sent from a pod to a destination outside the cluster will be # masqueraded (to an output device IPv4 address), if the output device runs the @@ -783,13 +918,6 @@ daemon: # a non-local route. This should be used only when autodetection is not suitable. # devices: "" -# -- Enables experimental support for the detection of new and removed datapath -# devices. When devices change the eBPF datapath is reloaded and services updated. -# If "devices" is set then only those devices, or devices matching a wildcard will -# be considered. -# -# This option has been deprecated and is a no-op. -enableRuntimeDeviceDetection: true # -- Forces the auto-detection of devices, even if specific devices are explicitly listed forceDeviceDetection: false # -- Chains to ignore when installing feeder rules. @@ -801,11 +929,7 @@ forceDeviceDetection: false # -- Enable setting identity mark for local traffic. # enableIdentityMark: true -# -- Enable Kubernetes EndpointSlice feature in Cilium if the cluster supports it. -# enableK8sEndpointSlice: true - -# -- Enable CiliumEndpointSlice feature (deprecated, please use `ciliumEndpointSlice.enabled` instead). -enableCiliumEndpointSlice: false +# -- CiliumEndpointSlice configuration options. ciliumEndpointSlice: # -- Enable Cilium EndpointSlice feature. enabled: false @@ -821,13 +945,13 @@ ciliumEndpointSlice: - nodes: 100 limit: 50 burst: 100 - # @schema - # enum: ["identity", "fcfs"] - # @schema - # -- The slicing mode to use for CiliumEndpointSlices. - # identity groups together CiliumEndpoints that share the same identity. - # fcfs groups together CiliumEndpoints in a first-come-first-serve basis, filling in the largest non-full slice first. - sliceMode: identity +# @schema +# enum: ["agent", "operator", "both"] +# @schema +# -- Control whether CiliumIdentities are created by the agent ("agent"), the operator ("operator") or both ("both"). +# "Both" should be used only to migrate between "agent" and "operator". +# Operator-managed identities is a beta feature. +identityManagementMode: "agent" envoyConfig: # -- Enable CiliumEnvoyConfig CRD # CiliumEnvoyConfig CRD can also be implicitly enabled by other options. @@ -984,20 +1108,33 @@ enableXTSocketFallback: true encryption: # -- Enable transparent network encryption. enabled: false - # -- Encryption method. Can be either ipsec or wireguard. + # -- Encryption method. Can be one of ipsec, wireguard or ztunnel. type: ipsec # -- Enable encryption for pure node to node traffic. # This option is only effective when encryption.type is set to "wireguard". nodeEncryption: false - # -- Configure the WireGuard Pod2Pod strict mode. + # -- Configure the Encryption Pod2Pod strict mode. strictMode: - # -- Enable WireGuard Pod2Pod strict mode. + # -- Enable Encryption Pod2Pod strict mode. (deprecated: please use encryption.strictMode.egress.enabled) enabled: false - # -- CIDR for the WireGuard Pod2Pod strict mode. + # -- CIDR for the Encryption Pod2Pod strict mode. (deprecated: please use encryption.strictMode.egress.cidr) cidr: "" - # -- Allow dynamic lookup of remote node identities. + # -- Allow dynamic lookup of remote node identities. (deprecated: please use encryption.strictMode.egress.allowRemoteNodeIdentities) # This is required when tunneling is used or direct routing is used and the node CIDR and pod CIDR overlap. allowRemoteNodeIdentities: false + egress: + # -- Enable strict egress encryption. + enabled: false + # -- CIDR for the Encryption Pod2Pod strict egress mode. + cidr: "" + # -- Allow dynamic lookup of remote node identities. + # This is required when tunneling is used or direct routing is used and the node CIDR and pod CIDR overlap. + allowRemoteNodeIdentities: false + ingress: + # -- Enable strict ingress encryption. + # When enabled, all unencrypted overlay ingress traffic will be dropped. + # This option is only applicable when WireGuard and tunneling are enabled. + enabled: false ipsec: # -- Name of the key file inside the Kubernetes secret configured via secretName. keyFile: keys @@ -1018,9 +1155,89 @@ encryption: wireguard: # -- Controls WireGuard PersistentKeepalive option. Set 0s to disable. persistentKeepalive: 0s + # -- ztunnel encryption configuration. + # ztunnel is Istio's purpose-built, per-node proxy for handling L4 traffic in ambient mesh mode. + # These settings only apply when encryption.type is set to "ztunnel". + ztunnel: + # -- ztunnel container image. + image: + # @schema + # type: [null, string] + # @schema + override: ~ + repository: "docker.io/istio/ztunnel" + tag: "1.28.0-distroless" + pullPolicy: "IfNotPresent" + # @schema + # type: [null, string] + # @schema + digest: ~ + useDigest: false + # -- CA server address for certificate requests. + caAddress: "https://localhost:15012" + # -- TCP port for the health API. + healthPort: 15021 + # -- ztunnel resource limits & requests. + resources: + requests: + cpu: 200m + memory: 512Mi + # -- ztunnel update strategy. + updateStrategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + # -- Configure termination grace period for ztunnel DaemonSet. + terminationGracePeriodSeconds: 30 + # -- Readiness probe configuration. + readinessProbe: + initialDelaySeconds: 0 + periodSeconds: 10 + failureThreshold: 3 + # -- Node selector for ztunnel pods. + nodeSelector: + kubernetes.io/os: linux + # -- Node tolerations for ztunnel scheduling. + tolerations: + - effect: NoSchedule + operator: Exists + - key: CriticalAddonsOnly + operator: Exists + - effect: NoExecute + operator: Exists + # -- Affinity for ztunnel pods. + affinity: {} + # @schema + # type: [null, string] + # @schema + # -- The priority class to use for ztunnel pods. + priorityClassName: ~ + # -- Annotations to be added to all ztunnel resources. + annotations: {} + # -- Annotations to be added to ztunnel pods. + podAnnotations: {} + # -- Labels to be added to ztunnel pods. + podLabels: {} + # -- Additional ztunnel container environment variables. + extraEnv: [] + # -- Additional ztunnel volumes. + extraVolumes: [] + # -- Additional ztunnel volumeMounts. + extraVolumeMounts: [] + # -- ztunnel secrets configuration. + secrets: + # -- Base64-encoded bootstrap root certificate content. + # If not provided, the secret must be created manually before deploying. + # @schema + # type: [null, string] + # @schema + bootstrapRootCert: ~ endpointHealthChecking: # -- Enable connectivity health checking between virtual endpoints. enabled: true +# -- Max duration to wait for envoy to respond to configuration changes. Default "10s". +endpointPolicyUpdateTimeoutDuration: null endpointRoutes: # @schema # type: [boolean, string] @@ -1036,8 +1253,6 @@ endpointLockdownOnMapOverflow: false eni: # -- Enable Elastic Network Interface (ENI) integration. enabled: false - # -- Update ENI Adapter limits from the EC2 API - updateEC2AdapterLimitViaAPI: true # -- Release IPs not used from the ENI awsReleaseExcessIPs: false # -- Enable ENI prefix delegation @@ -1071,9 +1286,32 @@ eni: # -- Filter via AWS EC2 Instance tags (k=v) which will dictate which AWS EC2 Instances # are going to be used to create new ENIs instanceTagsFilter: [] -externalIPs: - # -- Enable ExternalIPs service support. - enabled: false + # -- NodeSpec configuration for the ENI + nodeSpec: + # -- First interface index to use for IP allocation + # @schema + # type: [null, integer] + # @schema + firstInterfaceIndex: ~ + # -- Subnet IDs to use for IP allocation + subnetIDs: [] + # -- Subnet tags to use for IP allocation + subnetTags: [] + # -- Security groups to use for IP allocation + securityGroups: [] + # -- Security group tags to use for IP allocation + securityGroupTags: [] + # -- Exclude interface tags to use for IP allocation + excludeInterfaceTags: [] + # -- Use primary address for IP allocation + usePrimaryAddress: false + # -- Disable prefix delegation for IP allocation + disablePrefixDelegation: false + # -- Delete ENI on termination + # @schema + # type: [null, boolean] + # @schema + deleteOnTermination: ~ # fragmentTracking enables IPv4 fragment tracking support in the datapath. # fragmentTracking: true gke: @@ -1089,9 +1327,8 @@ healthCheckICMPFailureThreshold: 3 hostFirewall: # -- Enables the enforcement of host policies in the eBPF datapath. enabled: false -hostPort: - # -- Enable hostPort service support. - enabled: false +# -- Enable routing to a service that has zero endpoints +enableNoServiceEndpointsRoutable: true # -- Configure socket LB socketLB: # -- Enable socket LB @@ -1115,12 +1352,15 @@ certgen: # @schema override: ~ repository: "quay.io/cilium/certgen" - tag: "v0.2.1" - digest: "sha256:ab6b1928e9c5f424f6b0f51c68065b9fd85e2f8d3e5f21fbd1a3cb27e6fb9321" + tag: "v0.4.1" + digest: "sha256:f0c656830e856d26b24b0e144df1f8b327d3b46748d76a630514111fc365b697" useDigest: true pullPolicy: "IfNotPresent" + # @schema + # type: [null, integer] + # @schema # -- Seconds after which the completed job pod will be deleted - ttlSecondsAfterFinished: 1800 + ttlSecondsAfterFinished: null # -- Labels to be added to hubble-certgen pods podLabels: {} # -- Annotations to be added to the hubble-certgen initial Job and CronJob @@ -1136,12 +1376,20 @@ certgen: # -- Node tolerations for pod assignment on nodes with taints # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ tolerations: [] + # -- Resource limits for certgen + # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers + resources: {} # -- Additional certgen volumes. extraVolumes: [] # -- Additional certgen volumeMounts. extraVolumeMounts: [] # -- Affinity for certgen affinity: {} + cronJob: + # -- The number of successful finished jobs to keep + successfulJobsHistoryLimit: 3 + # -- The number of failed finished jobs to keep + failedJobsHistoryLimit: 1 hubble: # -- Enable Hubble (true by default). enabled: true @@ -1157,6 +1405,9 @@ hubble: # 2047, 4095, 8191, 16383, 32767, 65535 # eventBufferCapacity: "4095" + # -- The interval at which Hubble will send out lost events from the Observer server, if any. + # lostEventSendInterval: 1s + # -- Hubble metrics configuration. # See https://docs.cilium.io/en/stable/observability/metrics/#hubble-metrics # for more comprehensive documentation about Hubble metrics. @@ -1231,11 +1482,17 @@ hubble: jobLabel: "" # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Relabeling configs for the ServiceMonitor hubble relabelings: - sourceLabels: - __meta_kubernetes_pod_node_name targetLabel: node + action: replace replacement: ${1} # @schema # type: [null, array] @@ -1275,6 +1532,10 @@ hubble: # excludeFilters: [] # -- Unix domain socket path to listen to when Hubble is enabled. socketPath: /var/run/cilium/hubble.sock + # -- Enables network policy correlation of Hubble flows, i.e. populating `egress_allowed_by`, `ingress_denied_by` fields with policy information. + networkPolicyCorrelation: + # @default -- `true` + enabled: true # -- Enables redacting sensitive information present in Layer 7 flows. redact: enabled: false @@ -1336,7 +1597,7 @@ hubble: # --set hubble.redact.http.headers.deny="Authorization,Proxy-Authorization" deny: [] kafka: - # -- Enables redacting Kafka's API key. + # -- Enables redacting Kafka's API key (deprecated, will be removed in v1.19). # Example: # # redact: @@ -1440,9 +1701,9 @@ hubble: # @schema override: ~ repository: "quay.io/cilium/hubble-relay" - tag: "v1.17.4" + tag: "v1.19.3" # hubble-relay-digest - digest: "sha256:c16de12a64b8b56de62b15c1652d036253b40cd7fa643d7e1a404dc71dc66441" + digest: sha256:5ee21d57b6ef2aa6db67e603a735fdceb162454b352b7335b651456e308f681b useDigest: true pullPolicy: "IfNotPresent" # -- Specifies the resources for the hubble-relay pods @@ -1494,6 +1755,11 @@ hubble: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- The priority class to use for hubble-relay priorityClassName: "" # -- Configure termination grace period for hubble relay Deployment. @@ -1513,12 +1779,17 @@ hubble: # -- hubble-relay pod security context podSecurityContext: fsGroup: 65532 + seccompProfile: + type: RuntimeDefault # -- hubble-relay container security context securityContext: # readOnlyRootFilesystem: true + allowPrivilegeEscalation: false runAsNonRoot: true runAsUser: 65532 runAsGroup: 65532 + seccompProfile: + type: RuntimeDefault capabilities: drop: - ALL @@ -1579,13 +1850,6 @@ hubble: # @schema # type: [null, string] # @schema - # -- Dial timeout to connect to the local hubble instance to receive peer information (e.g. "30s"). - # - # This option has been deprecated and is a no-op. - dialTimeout: ~ - # @schema - # type: [null, string] - # @schema # -- Backoff duration to retry connecting to the local hubble instance in case of failure (e.g. "30s"). retryTimeout: ~ # @schema @@ -1620,6 +1884,11 @@ hubble: annotations: {} # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Specify the Kubernetes namespace where Prometheus expects to find # service monitors configured. # namespace: "" @@ -1645,6 +1914,24 @@ hubble: address: localhost # -- Configure pprof listen port for hubble-relay port: 6062 + # -- Enable mutex contention profiling for hubble-relay and set the fraction of sampled events (set to 1 to sample all events) + mutexProfileFraction: 0 + # -- Enable goroutine blocking profiling for hubble-relay and set the rate of sampled events in nanoseconds (set to 1 to sample all events [warning: performance overhead]) + blockProfileRate: 0 + # -- Logging configuration for hubble-relay. + logOptions: + # @schema + # type: [null, string] + # @schema + # -- Log format for hubble-relay. Valid values are: text, text-ts, json, json-ts. + # @default -- text-ts + format: ~ + # @schema + # type: [null, string] + # @schema + # -- Log level for hubble-relay. Valid values are: debug, info, warn, error. + # @default -- info + level: ~ ui: # -- Whether to enable the Hubble UI. enabled: false @@ -1691,12 +1978,13 @@ hubble: # @schema override: ~ repository: "quay.io/cilium/hubble-ui-backend" - tag: "v0.13.2" - digest: "sha256:a034b7e98e6ea796ed26df8f4e71f83fc16465a19d166eff67a03b822c0bfa15" + tag: "v0.13.3" + digest: "sha256:db1454e45dc39ca41fbf7cad31eec95d99e5b9949c39daaad0fa81ef29d56953" useDigest: true pullPolicy: "IfNotPresent" # -- Hubble-ui backend security context. - securityContext: {} + securityContext: + allowPrivilegeEscalation: false # -- Additional hubble-ui backend environment variables. extraEnv: [] # -- Additional hubble-ui backend volumes. @@ -1725,12 +2013,13 @@ hubble: # @schema override: ~ repository: "quay.io/cilium/hubble-ui" - tag: "v0.13.2" - digest: "sha256:9e37c1296b802830834cc87342a9182ccbb71ffebb711971e849221bd9d59392" + tag: "v0.13.3" + digest: "sha256:661d5de7050182d495c6497ff0b007a7a1e379648e60830dd68c4d78ae21761d" useDigest: true pullPolicy: "IfNotPresent" # -- Hubble-ui frontend security context. - securityContext: {} + securityContext: + allowPrivilegeEscalation: false # -- Additional hubble-ui frontend environment variables. extraEnv: [] # -- Additional hubble-ui frontend volumes. @@ -1775,6 +2064,11 @@ hubble: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- Affinity for hubble-ui affinity: {} # -- Pod topology spread constraints for hubble-ui @@ -1809,6 +2103,8 @@ hubble: service: # -- Annotations to be added for the Hubble UI service annotations: {} + # -- Labels to be added for the Hubble UI service + labels: {} # --- The type of service used for Hubble UI access, either ClusterIP or NodePort. type: ClusterIP # --- The port to use when the service type is set to NodePort. @@ -1831,12 +2127,13 @@ hubble: # - secretName: chart-example-tls # hosts: # - chart-example.local + # -- Configure temporary volume for hubble-ui + tmpVolume: {} + # emptyDir: + # # sizeLimit: "100Mi" + # # medium: "Memory" # -- Hubble flows export. export: - # --- Defines max file size of output file before it gets rotated. - fileMaxSizeMb: 10 - # --- Defines max number of backup/rotated files. - fileMaxBackups: 5 # --- Static exporter configuration. # Static exporter is bound to agent lifecycle. static: @@ -1847,11 +2144,25 @@ hubble: # - source # - destination # - verdict + fieldAggregate: [] + # - time + # - source + # - destination + # - verdict + # --- Defines the interval at which to aggregate before exporting Hubble flows. + # Aggregation feature is only enabled when fieldAggregate is specified and aggregationInterval > 0s. + aggregationInterval: "0s" allowList: [] # - '{"verdict":["DROPPED","ERROR"]}' denyList: [] # - '{"source_pod":["kube-system/"]}' # - '{"destination_pod":["kube-system/"]}' + # --- Defines max file size of output file before it gets rotated. + fileMaxSizeMb: 10 + # --- Defines max number of backup/rotated files. + fileMaxBackups: 5 + # --- Enable compression of rotated files. + fileCompress: false # --- Dynamic exporters configuration. # Dynamic exporters may be reconfigured without a need of agent restarts. dynamic: @@ -1866,9 +2177,14 @@ hubble: content: - name: all fieldMask: [] + fieldAggregate: [] + aggregationInterval: "0s" includeFilters: [] excludeFilters: [] filePath: "/var/run/cilium/hubble/events.log" + fileMaxSizeMb: 10 + fileMaxBackups: 5 + fileCompress: false # - name: "test002" # filePath: "/var/log/network/flow-log/pa/test002.log" # fieldMask: ["source.namespace", "source.pod_name", "destination.namespace", "destination.pod_name", "verdict"] @@ -1878,6 +2194,9 @@ hubble: # - type: 1 # - destination_pod: ["frontend/nginx-975996d4c-7hhgt"] # excludeFilters: [] + # fileMaxSizeMb: 1 + # fileMaxBackups: 10 + # fileCompress: true # end: "2023-10-09T23:59:59-07:00" # -- Emit v1.Events related to pods on detection of packet drops. # This feature is alpha, please provide feedback at https://github.com/cilium/cilium/issues/33975. @@ -1952,11 +2271,30 @@ ipam: # refill the bucket up to the burst size capacity. # @default -- `4.0` externalAPILimitQPS: ~ -# -- defaultLBServiceIPAM indicates the default LoadBalancer Service IPAM when -# no LoadBalancer class is set. Applicable values: lbipam, nodeipam, none + # -- NodeSpec configuration for the IPAM + nodeSpec: + # -- IPAM min allocate + # @schema + # type: [null, integer] + # @schema + ipamMinAllocate: ~ + # -- IPAM pre allocate + # @schema + # type: [null, integer] + # @schema + ipamPreAllocate: ~ + # -- IPAM max allocate + # @schema + # type: [null, integer] + # @schema + ipamMaxAllocate: ~ + # -- IPAM static IP tags (currently only works with AWS and Azure) + ipamStaticIPTags: [] # @schema # type: [string] # @schema +# -- defaultLBServiceIPAM indicates the default LoadBalancer Service IPAM when +# no LoadBalancer class is set. Applicable values: lbipam, nodeipam, none defaultLBServiceIPAM: lbipam nodeIPAM: # -- Configure Node IPAM @@ -1992,14 +2330,17 @@ k8s: # -- requireIPv6PodCIDR enables waiting for Kubernetes to provide the PodCIDR # range via the Kubernetes node resource requireIPv6PodCIDR: false + # -- A space separated list of Kubernetes API server URLs to use with the client. + # For example "https://192.168.0.1:6443 https://192.168.0.2:6443" + # apiServerURLs: "" # -- Keep the deprecated selector labels when deploying Cilium DaemonSet. keepDeprecatedLabels: false # -- Keep the deprecated probes when deploying Cilium DaemonSet keepDeprecatedProbes: false startupProbe: # -- failure threshold of startup probe. - # 105 x 2s translates to the old behaviour of the readiness probe (120s delay + 30 x 3s) - failureThreshold: 105 + # Allow Cilium to take up to 600s to start up (300 attempts with 2s between attempts). + failureThreshold: 300 # -- interval between checks of the startup probe periodSeconds: 2 livenessProbe: @@ -2017,8 +2358,10 @@ readinessProbe: # -- Configure the kube-proxy replacement in Cilium BPF datapath # Valid options are "true" or "false". # ref: https://docs.cilium.io/en/stable/network/kubernetes/kubeproxy-free/ -#kubeProxyReplacement: "false" - +# @schema@ +# type: [string, boolean] +# @schema@ +kubeProxyReplacement: "false" # -- healthz server bind address for the kube-proxy replacement. # To enable set the value to '0.0.0.0:10256' for all ipv4 # addresses and this '[::]:10256' for all ipv6 addresses. @@ -2026,13 +2369,20 @@ readinessProbe: kubeProxyReplacementHealthzBindAddr: "" l2NeighDiscovery: # -- Enable L2 neighbor discovery in the agent - enabled: true - # -- Override the agent's default neighbor resolution refresh period. - refreshPeriod: "30s" + enabled: false # -- Enable Layer 7 network policy. l7Proxy: true -# -- Enable Local Redirect Policy. +# -- Enable Local Redirect Policy (deprecated, please use 'localRedirectPolicies.enabled' instead) localRedirectPolicy: false +localRedirectPolicies: + # -- Enable local redirect policies. + enabled: false + # -- Limit the allowed addresses in Address Matcher rule of + # Local Redirect Policies to the given CIDRs. + # @schema@ + # type: [null, array] + # @schema@ + addressMatcherCIDRs: ~ # To include or exclude matched resources from cilium identity evaluation # labels: "" @@ -2051,8 +2401,12 @@ maglev: {} # -- hashSeed is the cluster-wide base64 encoded seed for the hashing # hashSeed: -# -- Enables masquerading of IPv4 traffic leaving the node from endpoints. -enableIPv4Masquerade: true +# @schema +# type: [null, boolean] +# @schema +# -- (bool) Enables masquerading of IPv4 traffic leaving the node from endpoints. +# @default -- `true` unless ipam eni mode is active +enableIPv4Masquerade: ~ # -- Enables masquerading of IPv6 traffic leaving the node from endpoints. enableIPv6Masquerade: true # -- Enables masquerading to the source of the route for traffic leaving the node from endpoints. @@ -2132,17 +2486,13 @@ loadBalancer: # path), or best-effort (use native mode XDP acceleration on devices # that support it). acceleration: disabled - # -- dsrDispatch configures whether IP option or IPIP encapsulation is - # used to pass a service IP and port to remote backend + # -- dsrDispatch configures whether IP option (opt), IPIP encapsulation (ipip), + # Geneve Class Option (geneve) used to pass a service IP and port to remote backend # dsrDispatch: opt # -- serviceTopology enables K8s Topology Aware Hints -based service # endpoints filtering - # serviceTopology: false - - # -- experimental enables support for the experimental load-balancing - # control-plane. - experimental: false + serviceTopology: false # -- L7 LoadBalancer l7: # -- Enable L7 service load balancing via envoy proxy. @@ -2165,8 +2515,6 @@ loadBalancer: algorithm: round_robin # -- Configure N-S k8s service loadbalancing nodePort: - # -- Enable the Cilium NodePort service implementation. - enabled: false # -- Port range to use for NodePort services. # range: "30000,32767" @@ -2210,6 +2558,10 @@ pprof: address: localhost # -- Configure pprof listen port for cilium-agent port: 6060 + # -- Enable mutex contention profiling for cilium-agent and set the fraction of sampled events (set to 1 to sample all events) + mutexProfileFraction: 0 + # -- Enable goroutine blocking profiling for cilium-agent and set the rate of sampled events in nanoseconds (set to 1 to sample all events [warning: performance overhead]) + blockProfileRate: 0 # -- Configure prometheus metrics on the configured port at /metrics prometheus: metricsService: false @@ -2227,6 +2579,11 @@ prometheus: jobLabel: "" # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Specify the Kubernetes namespace where Prometheus expects to find # service monitors configured. # namespace: "" @@ -2235,6 +2592,7 @@ prometheus: - sourceLabels: - __meta_kubernetes_pod_node_name targetLabel: node + action: replace replacement: ${1} # @schema # type: [null, array] @@ -2328,6 +2686,12 @@ envoy: initialFetchTimeoutSeconds: 30 # -- Maximum number of concurrent retries on Envoy clusters maxConcurrentRetries: 128 + # -- Maximum number of connections on Envoy clusters + clusterMaxConnections: 1024 + # -- Maximum number of requests on Envoy clusters + clusterMaxRequests: 1024 + # -- Maximum number of global downstream connections + maxGlobalDownstreamConnections: 50000 # -- Maximum number of retries for each HTTP request httpRetryCount: 3 # -- ProxyMaxRequestsPerConnection specifies the max_requests_per_connection setting for Envoy @@ -2337,15 +2701,23 @@ envoy: # -- Set Envoy upstream HTTP idle connection timeout seconds. # Does not apply to connections with pending requests. Default 60s idleTimeoutDurationSeconds: 60 + # -- Set Envoy the amount of time that the connection manager will allow a stream to exist with no upstream or downstream activity. + # default 5 minutes + streamIdleTimeoutDurationSeconds: 300 # -- Number of trusted hops regarding the x-forwarded-for and related HTTP headers for the ingress L7 policy enforcement Envoy listeners. xffNumTrustedHopsL7PolicyIngress: 0 # -- Number of trusted hops regarding the x-forwarded-for and related HTTP headers for the egress L7 policy enforcement Envoy listeners. xffNumTrustedHopsL7PolicyEgress: 0 + # -- For cases when CiliumEnvoyConfig is not used directly (Ingress, Gateway), configures Cilium BPF Metadata listener filter + # to use the original source address when extracting the metadata for a request. + useOriginalSourceAddress: true # @schema # type: [null, string] # @schema # -- Max duration to wait for endpoint policies to be restored on restart. Default "3m". policyRestoreTimeoutDuration: null + # -- Time in seconds to block Envoy worker thread while an upstream HTTP connection is closing. If set to 0, the connection is closed immediately (with TCP RST). If set to -1, the connection is closed asynchronously in the background. + httpUpstreamLingerTimeout: null # -- Envoy container image. image: # @schema @@ -2353,10 +2725,12 @@ envoy: # @schema override: ~ repository: "quay.io/cilium/cilium-envoy" - tag: "v1.32.6-1746661844-0f602c28cb2aa57b29078195049fb257d5b5246c" + tag: "v1.36.6-1776000132-2437d2edeaf4d9b56ef279bd0d71127440c067aa" pullPolicy: "IfNotPresent" - digest: "sha256:a04218c6879007d60d96339a441c448565b6f86650358652da27582e0efbf182" + digest: "sha256:ba0ab8adac082d50d525fd2c5ba096c8facea3a471561b7c61c7a5b9c2e0de0d" useDigest: true + # -- Init containers added to the cilium Envoy DaemonSet. + initContainers: [] # -- Additional containers added to the cilium Envoy DaemonSet. extraContainers: [] # -- Additional envoy container arguments. @@ -2422,12 +2796,16 @@ envoy: # memory: 512Mi startupProbe: + # -- Enable startup probe for cilium-envoy + enabled: true # -- failure threshold of startup probe. # 105 x 2s translates to the old behaviour of the readiness probe (120s delay + 30 x 3s) failureThreshold: 105 # -- interval between checks of the startup probe periodSeconds: 2 livenessProbe: + # -- Enable liveness probe for cilium-envoy + enabled: true # -- failure threshold of liveness probe failureThreshold: 10 # -- interval between checks of the liveness probe @@ -2540,6 +2918,11 @@ envoy: annotations: {} # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Specify the Kubernetes namespace where Prometheus expects to find # service monitors configured. # namespace: "" @@ -2549,6 +2932,7 @@ envoy: - sourceLabels: - __meta_kubernetes_pod_node_name targetLabel: node + action: replace replacement: ${1} # @schema # type: [null, array] @@ -2560,6 +2944,10 @@ envoy: port: "9964" # -- Enable/Disable use of node label based identity nodeSelectorLabels: false +# To include or exclude matched resources from cilium node identity evaluation +# List of labels just like --labels flag (.Values.labels) +# nodeLabels: "" + # -- Enable resource quotas for priority classes used in the cluster. resourceQuotas: enabled: false @@ -2573,14 +2961,15 @@ resourceQuotas: pods: "15" # Need to document default ################## -#sessionAffinity: false +# -- Annotations to be added to all cilium-secret namespaces (resources under templates/cilium-secrets-namespace) +secretsNamespaceAnnotations: {} +# -- Labels to be added to all cilium-secret namespaces (resources under templates/cilium-secrets-namespace) +secretsNamespaceLabels: {} # -- Do not run Cilium agent when running with clean mode. Useful to completely # uninstall Cilium as it will stop Cilium from starting and create artifacts # in the node. sleepAfterInit: false -# -- Enable check of service source ranges (currently, only for LoadBalancer). -svcSourceRangeCheck: true # -- Synchronize Kubernetes nodes to kvstore and perform CNP GC. synchronizeK8sNodes: true # -- Configure TLS configuration in the agent. @@ -2662,6 +3051,12 @@ tls: # - geneve # @default -- `"vxlan"` tunnelProtocol: "" +# -- IP family for the underlay. +# Possible values: +# - "ipv4" +# - "ipv6" +# @default -- `"ipv4"` +underlayProtocol: "" # -- Enable native-routing mode or tunneling mode. # Possible values: # - "" @@ -2680,6 +3075,11 @@ tunnelSourcePortRange: 0-0 # - reject (default) # - drop serviceNoBackendResponse: reject +# -- Configure what the response should be to pod egress traffic denied by network policy. +# Possible values: +# - none (default) +# - icmp +policyDenyResponse: none # -- Configure the underlying network MTU to overwrite auto-detected MTU. # This value doesn't change the host network interface MTU i.e. eth0 or ens0. # It changes the MTU for cilium_net@cilium_host, cilium_host@cilium_net, @@ -2710,15 +3110,15 @@ operator: # @schema override: ~ repository: "quay.io/cilium/operator" - tag: "v1.17.4" + tag: "v1.19.3" # operator-generic-digest - genericDigest: "sha256:a3906412f477b09904f46aac1bed28eb522bef7899ed7dd81c15f78b7aa1b9b5" + genericDigest: sha256:205b09b0ed6accbf9fe688d312a9f0fcfc6a316fc081c23fbffb472af5dd62cd # operator-azure-digest - azureDigest: "sha256:d8d95049bfeab47cb1a3f995164e1ca2cdec8e6c7036c29799647999cdae07b1" + azureDigest: sha256:699c1571a3df1a98882ee13610d47cffb7b34ee7e8d276096db798a5f6c7e4cb # operator-aws-digest - awsDigest: "sha256:3c31583e57648470fbf6646ac67122ac5896ce5f979ab824d9a38cfc7eafc753" + awsDigest: sha256:a53dcbfb77282bf2ddd3abbe60f6d49762e7c1389a36cb35b71d504644a56640 # operator-alibabacloud-digest - alibabacloudDigest: "sha256:eaa7b18b7cda65af1d454d54224d175fdb69a35199fa949ae7dfda2789c18dd6" + alibabacloudDigest: sha256:176321a65123373ff8c7823b25183102cbad98375e8d6c80b96d68b6e8491103 useDigest: true pullPolicy: "IfNotPresent" suffix: "" @@ -2761,12 +3161,19 @@ operator: kubernetes.io/os: linux # -- Node tolerations for cilium-operator scheduling to nodes with taints # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ + # Toleration for agentNotReadyTaintKey taint is always added to cilium-operator pods. + # @schema + # type: [null, array] + # @schema tolerations: - - operator: Exists - # - key: "key" - # operator: "Equal|Exists" - # value: "value" - # effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)" + - key: "node-role.kubernetes.io/control-plane" + operator: Exists + - key: "node-role.kubernetes.io/master" #deprecated + operator: Exists + - key: "node.kubernetes.io/not-ready" + operator: Exists + - key: "node.cloudprovider.kubernetes.io/uninitialized" + operator: Exists # -- Additional cilium-operator container arguments. extraArgs: [] # -- Additional cilium-operator environment variables. @@ -2789,7 +3196,9 @@ operator: # -- HostNetwork setting hostNetwork: true # -- Security context to be added to cilium-operator pods - podSecurityContext: {} + podSecurityContext: + seccompProfile: + type: RuntimeDefault # -- Annotations to be added to cilium-operator pods podAnnotations: {} # -- Labels to be added to cilium-operator pods @@ -2810,6 +3219,11 @@ operator: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- cilium-operator resource limits & requests # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: {} @@ -2821,7 +3235,11 @@ operator: # memory: 128Mi # -- Security context to be added to cilium-operator pods - securityContext: {} + securityContext: + capabilities: + drop: + - ALL + allowPrivilegeEscalation: false # runAsUser: 0 # -- Interval for endpoint garbage collection. @@ -2839,6 +3257,10 @@ operator: address: localhost # -- Configure pprof listen port for cilium-operator port: 6061 + # -- Enable mutex contention profiling for cilium-operator and set the fraction of sampled events (set to 1 to sample all events) + mutexProfileFraction: 0 + # -- Enable goroutine blocking profiling for cilium-operator and set the rate of sampled events in nanoseconds (set to 1 to sample all events [warning: performance overhead]) + blockProfileRate: 0 # -- Enable prometheus metrics for cilium-operator on the configured port at # /metrics prometheus: @@ -2858,6 +3280,11 @@ operator: # -- Interval for scrape metrics. interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor cilium-operator @@ -2867,6 +3294,17 @@ operator: # @schema # -- Metrics relabeling configs for the ServiceMonitor cilium-operator metricRelabelings: ~ + # -- TLS configuration for Prometheus + tls: + enabled: false + server: + # -- Name of the Secret containing the certificate, key and CA files for the Prometheus server. + existingSecret: "" + mtls: + # When set to true enforces mutual TLS between Operator Prometheus server and its clients. + # False allow non-mutual TLS connections. + # This option has no effect when TLS is disabled. + enabled: false # -- Grafana dashboards for cilium-operator # grafana can import dashboards based on the label and value # ref: https://github.com/grafana/helm-charts/tree/main/charts/grafana#sidecar-for-dashboards @@ -2900,6 +3338,12 @@ operator: # -- Interval, in seconds, to check if there are any pods that are not # managed by Cilium. intervalSeconds: 15 + # -- Selector for pods that should be restarted when not managed by Cilium. + # If not set, defaults to built-in selector "k8s-app=kube-dns". Set to empty string to select all pods. + # @schema + # type: [null, string] + # @schema + selector: ~ nodeinit: # -- Enable the node initialization DaemonSet enabled: false @@ -2910,8 +3354,8 @@ nodeinit: # @schema override: ~ repository: "quay.io/cilium/startup-script" - tag: "c54c7edeab7fde4da68e59acd319ab24af242c3f" - digest: "sha256:8d7b41c4ca45860254b3c19e20210462ef89479bb6331d6760c4e609d651b29c" + tag: "1763560095-8f36c34" + digest: "sha256:50b9cf9c280096b59b80d2fc8ee6638facef79ac18998a22f0cbc40d5d28c16f" useDigest: true pullPolicy: "IfNotPresent" # -- The priority class to use for the nodeinit pod. @@ -2954,10 +3398,14 @@ nodeinit: # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: requests: + # @schema + # type: [integer, string] + # @schema cpu: 100m memory: 100Mi # -- Security context to be added to nodeinit pods. securityContext: + allowPrivilegeEscalation: false privileged: false seLinuxOptions: level: 's0' @@ -2975,6 +3423,8 @@ nodeinit: # -- bootstrapFile is the location of the file where the bootstrap timestamp is # written by the node-init DaemonSet bootstrapFile: "/tmp/cilium-bootstrap.d/cilium-bootstrap-time" + # -- wait for Cloud init to finish on the host and assume the node has cloud init installed + waitForCloudInit: false # -- startup offers way to customize startup nodeinit script (pre and post position) startup: preScript: "" @@ -2993,11 +3443,23 @@ preflight: # @schema override: ~ repository: "quay.io/cilium/cilium" - tag: "v1.17.4" + tag: "v1.19.3" # cilium-digest - digest: "sha256:24a73fe795351cf3279ac8e84918633000b52a9654ff73a6b0d7223bcff4a67a" + digest: sha256:2e61680593cddca8b6c055f6d4c849d87a26a1c91c7e3b8b56c7fb76ab7b7b10 useDigest: true pullPolicy: "IfNotPresent" + envoy: + # -- Envoy pre-flight image. + image: + # @schema + # type: [null, string] + # @schema + override: ~ + repository: "quay.io/cilium/cilium-envoy" + tag: "v1.36.6-1776000132-2437d2edeaf4d9b56ef279bd0d71127440c067aa" + pullPolicy: "IfNotPresent" + digest: "sha256:ba0ab8adac082d50d525fd2c5ba096c8facea3a471561b7c61c7a5b9c2e0de0d" + useDigest: true # -- The priority class to use for the preflight pod. priorityClassName: "" # -- preflight update strategy @@ -3053,6 +3515,11 @@ preflight: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- preflight resource limits & requests # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: {} @@ -3069,7 +3536,8 @@ preflight: # -- interval between checks of the readiness probe periodSeconds: 5 # -- Security context to be added to preflight pods - securityContext: {} + securityContext: + allowPrivilegeEscalation: false # runAsUser: 0 # -- Path to write the `--tofqdns-pre-cache` file to. @@ -3090,7 +3558,9 @@ enableCriticalPriorityClass: true # on AArch64 as the images do not currently ship a version of Envoy. #disableEnvoyVersionCheck: false clustermesh: - # -- Deploy clustermesh-apiserver for clustermesh + # -- Deploy clustermesh-apiserver for clustermesh. This option is typically + # used with ``clustermesh.config.enabled=true``. Refer to the + # ``clustermesh.config.enabled=true``documentation for more information. useAPIServer: false # -- The maximum number of clusters to support in a ClusterMesh. This value # cannot be changed on running clusters, and all clusters in a ClusterMesh @@ -3098,42 +3568,132 @@ clustermesh: # maximum allocatable cluster-local identities. # Supported values are 255 and 511. maxConnectedClusters: 255 + # -- The time to live for the cache of a remote cluster after connectivity is + # lost. If the connection is not re-established within this duration, the + # cached data is revoked to prevent stale state. If not specified or set to + # 0s, the cache is never revoked (default). + cacheTTL: "0s" # -- Enable the synchronization of Kubernetes EndpointSlices corresponding to # the remote endpoints of appropriately-annotated global services through ClusterMesh enableEndpointSliceSynchronization: false - # -- Enable Multi-Cluster Services API support + # -- Enable Multi-Cluster Services API support (deprecated; use clustermesh.mcsapi.enabled) enableMCSAPISupport: false + # -- Control whether policy rules assume by default the local cluster if not explicitly selected + policyDefaultLocalCluster: true # -- Annotations to be added to all top-level clustermesh objects (resources under templates/clustermesh-apiserver and templates/clustermesh-config) annotations: {} # -- Clustermesh explicit configuration. config: # -- Enable the Clustermesh explicit configuration. + # If set to false, you need to provide the following resources yourself: + # - (Secret) cilium-clustermesh (used by cilium-agent/cilium-operator to connect to + # the local etcd instance if KVStoreMesh is enabled or the remote clusters + # if KVStoreMesh is disabled) + # - (Secret) cilium-kvstoremesh (used by KVStoreMesh to connect to the remote clusters) + # - (ConfigMap) clustermesh-remote-users (used to create one etcd user per remote cluster + # if clustermesh-apiserver is used and `clustermesh.apiserver.tls.authMode` is not + # set to `legacy`) enabled: false # -- Default dns domain for the Clustermesh API servers # This is used in the case cluster addresses are not provided # and IPs are used. domain: mesh.cilium.io - # -- List of clusters to be peered in the mesh. + # -- Clusters to be peered in the mesh. + # @schema + # type: [object, array] + # @schema clusters: [] + # You can use a dict of clusters (recommended): # clusters: - # # -- Name of the cluster + # # -- Name of the cluster + # cluster1: + # # -- Whether to enable this cluster in the mesh. Optional, defaults to true. + # enabled: true + # # -- Address of the cluster, use this if you created DNS records for + # # the cluster Clustermesh API server. + # address: cluster1.mesh.cilium.io + # # -- Port of the cluster Clustermesh API server. + # port: 2379 + # # -- IPs of the cluster Clustermesh API server, use multiple ones when + # # you have multiple IPs to access the Clustermesh API server. + # ips: + # - 172.18.255.201 + # # -- (deprecated) base64 encoded PEM values for the cluster client certificate, private key and certificate authority. + # # These fields can (and should) be omitted in case the CA is shared across clusters. In that case, the + # # "remote" private key and certificate available in the local cluster are automatically used instead. + # tls: + # cert: "" + # key: "" + # caCert: "" + # + # Or alternatively you can use a list of clusters: + # clusters: + # # -- Name of the cluster # - name: cluster1 - # # -- Address of the cluster, use this if you created DNS records for - # # the cluster Clustermesh API server. + # # -- Address of the cluster, use this if you created DNS records for + # # the cluster Clustermesh API server. # address: cluster1.mesh.cilium.io - # # -- Port of the cluster Clustermesh API server. + # # -- Port of the cluster Clustermesh API server. # port: 2379 - # # -- IPs of the cluster Clustermesh API server, use multiple ones when - # # you have multiple IPs to access the Clustermesh API server. + # # -- IPs of the cluster Clustermesh API server, use multiple ones when + # # you have multiple IPs to access the Clustermesh API server. # ips: # - 172.18.255.201 - # # -- base64 encoded PEM values for the cluster client certificate, private key and certificate authority. - # # These fields can (and should) be omitted in case the CA is shared across clusters. In that case, the - # # "remote" private key and certificate available in the local cluster are automatically used instead. + # # -- (deprecated) base64 encoded PEM values for the cluster client certificate, private key and certificate authority. + # # These fields can (and should) be omitted in case the CA is shared across clusters. In that case, the + # # "remote" private key and certificate available in the local cluster are automatically used instead. # tls: # cert: "" # key: "" # caCert: "" + mcsapi: + # -- Enable Multi-Cluster Services API support + enabled: false + # -- Enabled MCS-API CRDs auto-installation + installCRDs: true + corednsAutoConfigure: + # -- Enable auto-configuration of CoreDNS for Multi-Cluster Services API. + # CoreDNS MUST be at least in version v1.12.2 to run this. + enabled: false + coredns: + # -- The Deployment for the cluster CoreDNS service + deploymentName: coredns + # -- The Service Account name for the cluster CoreDNS service + serviceAccountName: coredns + # -- The ConfigMap name for the cluster CoreDNS service + configMapName: coredns + # -- The namespace for the cluster CoreDNS service + namespace: kube-system + # -- The cluster domain for the cluster CoreDNS service + clusterDomain: cluster.local + # -- The clusterset domain for the cluster CoreDNS service + clustersetDomain: clusterset.local + # -- Additional arguments to `clustermesh-apiserver coredns-mcsapi-auto-configure`. + extraArgs: [] + # -- Seconds after which the completed job pod will be deleted + ttlSecondsAfterFinished: 1800 + # -- Labels to be added to coredns-mcsapi-autoconfig pods + podLabels: {} + # -- Annotations to be added to the coredns-mcsapi-autoconfig Job + annotations: {} + # -- Node selector for coredns-mcsapi-autoconfig + # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector + nodeSelector: {} + # -- Priority class for coredns-mcsapi-autoconfig + # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#priorityclass + priorityClassName: "" + # -- Node tolerations for pod assignment on nodes with taints + # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ + tolerations: [] + # -- Resource limits for coredns-mcsapi-autoconfig + # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers + resources: {} + # -- Additional coredns-mcsapi-autoconfig volumes. + extraVolumes: [] + # -- Additional coredns-mcsapi-autoconfig volumeMounts. + extraVolumeMounts: [] + # -- Affinity for coredns-mcsapi-autoconfig + affinity: {} apiserver: # -- Clustermesh API server image. image: @@ -3142,9 +3702,9 @@ clustermesh: # @schema override: ~ repository: "quay.io/cilium/clustermesh-apiserver" - tag: "v1.17.4" + tag: "v1.19.3" # clustermesh-apiserver-digest - digest: "sha256:0b72f3046cf36ff9b113d53cc61185e893edb5fe728a2c9e561c1083f806453d" + digest: sha256:a8136a7615d6c6041d3aa6f2674d17beaec238170d669507ccc05328a778e2b7 useDigest: true pullPolicy: "IfNotPresent" # -- TCP port for the clustermesh-apiserver health API. @@ -3198,7 +3758,7 @@ clustermesh: storageMedium: Disk kvstoremesh: # -- Enable KVStoreMesh. KVStoreMesh caches the information retrieved - # from the remote clusters in the local etcd instance. + # from the remote clusters in the local etcd instance (deprecated - KVStoreMesh will always be enabled once the option is removed). enabled: true # -- TCP port for the KVStoreMesh health API. healthPort: 9881 @@ -3227,18 +3787,18 @@ clustermesh: - ALL # -- lifecycle setting for the KVStoreMesh container lifecycle: {} + # -- Specify the KVStore mode when running KVStoreMesh + # Supported values: + # - "internal": remote cluster identities are cached in etcd that runs as a sidecar within ``clustermesh-apiserver`` pod. + # - "external": ``clustermesh-apiserver`` will sync remote cluster information to the etcd used as kvstore. This can't be enabled with crd identity allocation mode. + kvstoreMode: "internal" service: + # -- (bool) Set externallyCreated to true to create the clustermesh-apiserver service outside this helm chart. + # For example after external load balancer controllers are created. + externallyCreated: false # -- The type of service used for apiserver access. type: NodePort # -- Optional port to use as the node port for apiserver access. - # - # WARNING: make sure to configure a different NodePort in each cluster if - # kube-proxy replacement is enabled, as Cilium is currently affected by a known - # bug (#24692) when NodePorts are handled by the KPR implementation. If a service - # with the same NodePort exists both in the local and the remote cluster, all - # traffic originating from inside the cluster and targeting the corresponding - # NodePort will be redirected to a local backend, regardless of whether the - # destination node belongs to the local or the remote cluster. nodePort: 32379 # -- Annotations for the clustermesh-apiserver service. # Example annotations to configure an internal load balancer on different cloud providers: @@ -3246,6 +3806,8 @@ clustermesh: # * EKS: service.beta.kubernetes.io/aws-load-balancer-scheme: "internal" # * GKE: networking.gke.io/load-balancer-type: "Internal" annotations: {} + # -- Labels for the clustermesh-apiserver service. + labels: {} # @schema # enum: [Local, Cluster] # @schema @@ -3338,6 +3900,11 @@ clustermesh: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- Resource requests and limits for the clustermesh-apiserver resources: {} # requests: @@ -3400,13 +3967,15 @@ clustermesh: # The "remote" certificate must be generated with CN=remote- # if provided manually. Cluster mode is meaningful only when the same # CA is shared across all clusters part of the mesh. - authMode: legacy - # -- Allow users to provide their own certificates + authMode: migration + # -- (deprecated) Allow users to provide their own certificates # Users may need to provide their certificates using # a mechanism that requires they provide their own secrets. # This setting does not apply to any of the auto-generated # mechanisms below, it only restricts the creation of secrets # via the `tls-provided` templates. + # This option is deprecated as secrets are expected to be created + # externally when 'auto' is not enabled. enableSecrets: true # -- Configure automatic TLS certificates generation. # A Kubernetes CronJob is used the generate any @@ -3415,7 +3984,14 @@ clustermesh: auto: # -- When set to true, automatically generate a CA and certificates to # enable mTLS between clustermesh-apiserver and external workload instances. - # If set to false, the certs to be provided by setting appropriate values below. + # + # When set to false you need to pre-create the following secrets: + # - clustermesh-apiserver-server-cert + # - clustermesh-apiserver-admin-cert + # - clustermesh-apiserver-remote-cert + # - clustermesh-apiserver-local-cert + # The above secret should at least contains the keys `tls.crt` and `tls.key` + # and optionally `ca.crt` if a CA bundle is not configured. enabled: true # Sets the method to auto-generate certificates. Supported values: # - helm: This method uses Helm to generate all certificates. @@ -3450,7 +4026,9 @@ clustermesh: # -- base64 encoded PEM values for the clustermesh-apiserver server certificate and private key. # Used if 'auto' is not enabled. server: + # -- Deprecated, as secrets will always need to be created externally if `auto` is disabled. cert: "" + # -- Deprecated, as secrets will always need to be created externally if `auto` is disabled. key: "" # -- Extra DNS names added to certificate when it's auto generated extraDnsNames: [] @@ -3459,17 +4037,16 @@ clustermesh: # -- base64 encoded PEM values for the clustermesh-apiserver admin certificate and private key. # Used if 'auto' is not enabled. admin: + # -- Deprecated, as secrets will always need to be created externally if `auto` is disabled. cert: "" - key: "" - # -- base64 encoded PEM values for the clustermesh-apiserver client certificate and private key. - # Used if 'auto' is not enabled. - client: - cert: "" + # -- Deprecated, as secrets will always need to be created externally if `auto` is disabled. key: "" # -- base64 encoded PEM values for the clustermesh-apiserver remote cluster certificate and private key. # Used if 'auto' is not enabled. remote: + # -- Deprecated, as secrets will always need to be created externally if `auto` is disabled. cert: "" + # -- Deprecated, as secrets will always need to be created externally if `auto` is disabled. key: "" # clustermesh-apiserver Prometheus metrics configuration metrics: @@ -3504,6 +4081,11 @@ clustermesh: # -- Interval for scrape metrics (apiserver metrics) interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor clustermesh-apiserver (apiserver metrics) @@ -3517,6 +4099,11 @@ clustermesh: # -- Interval for scrape metrics (KVStoreMesh metrics) interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor clustermesh-apiserver (KVStoreMesh metrics) @@ -3530,6 +4117,11 @@ clustermesh: # -- Interval for scrape metrics (etcd metrics) interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor clustermesh-apiserver (etcd metrics) @@ -3539,10 +4131,6 @@ clustermesh: # @schema # -- Metrics relabeling configs for the ServiceMonitor clustermesh-apiserver (etcd metrics) metricRelabelings: ~ -# -- Configure external workloads support -externalWorkloads: - # -- Enable support for external workloads, such as VMs (false by default). - enabled: false # -- Configure cgroup related configuration cgroup: autoMount: @@ -3567,9 +4155,6 @@ cgroup: sysctlfix: # -- Enable the sysctl override. When enabled, the init container will mount the /proc of the host so that the `sysctlfix` utility can execute. enabled: true -# -- Configure whether to enable auto detect of terminating state for endpoints -# in order to support graceful termination. -enableK8sTerminatingEndpoint: true # -- Configure whether to unload DNS policy rules on graceful shutdown # dnsPolicyUnloadOnShutdown: false @@ -3602,6 +4187,9 @@ dnsProxy: proxyResponseMaxDelay: 100ms # -- DNS proxy operation mode (true/false, or unset to use version dependent defaults) # enableTransparentMode: true + # -- Pre-allocate ToFQDN identities. This reduces DNS proxy tail latency, at the potential cost of some + # unnecessary policymap entries. Disable this if you have a large (200+) number of unique ToFQDN selectors. + preAllocateIdentities: true # -- SCTP Configuration Values sctp: # -- Enable SCTP support. NOTE: Currently, SCTP support does not support rewriting ports or multihoming. @@ -3613,7 +4201,7 @@ authentication: # -- Enable authentication processing and garbage collection. # Note that if disabled, policy enforcement will still block requests that require authentication. # But the resulting authentication requests for these requests will not be processed, therefore the requests not be allowed. - enabled: true + enabled: false # -- Buffer size of the channel Cilium uses to receive authentication events from the signal map. queueSize: 1024 # -- Buffer size of the channel Cilium uses to receive certificate expiration events from auth handlers. @@ -3651,7 +4239,7 @@ authentication: override: ~ repository: "docker.io/library/busybox" tag: "1.37.0" - digest: "sha256:37f7b378a29ceb4c551b1b5582e27747b855bbfaa73fa11914fe0df028dc581f" + digest: "sha256:1487d0af5f52b4ba31c7e465126ee2123fe3f2305d638e7827681e7cf6c83d5e" useDigest: true pullPolicy: "IfNotPresent" # SPIRE agent configuration @@ -3806,3 +4394,41 @@ authentication: enableInternalTrafficPolicy: true # -- Enable LoadBalancer IP Address Management enableLBIPAM: true +# -- Standalone DNS Proxy Configuration +# Note: The standalone DNS proxy uses the agent's dnsProxy.* configuration +# for DNS settings (proxyPort, enableDnsCompression) to ensure consistency. +standaloneDnsProxy: + # -- Enable standalone DNS proxy (alpha feature) + enabled: false + # -- Roll out Standalone DNS proxy automatically when configmap is updated. + rollOutPods: false + # -- Standalone DNS proxy annotations + annotations: {} + # -- Standalone DNS proxy debug mode + debug: false + # -- Standalone DNS proxy server port + serverPort: 10095 + # -- Standalone DNS proxy Node Selector + nodeSelector: + kubernetes.io/os: linux + # -- Standalone DNS proxy tolerations + tolerations: [] + # -- Standalone DNS proxy auto mount service account token + automountServiceAccountToken: false + # -- Standalone DNS proxy update strategy + updateStrategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 2 + maxUnavailable: 0 + # -- Standalone DNS proxy image + image: + # @schema + # type: [null, string] + # @schema + override: ~ + repository: "" + tag: "" + digest: "" + useDigest: true + pullPolicy: "IfNotPresent" diff --git a/packages/system/cilium/charts/cilium/values.yaml.tmpl b/packages/system/cilium/charts/cilium/values.yaml.tmpl index 9d6ce1d6..8039b40c 100644 --- a/packages/system/cilium/charts/cilium/values.yaml.tmpl +++ b/packages/system/cilium/charts/cilium/values.yaml.tmpl @@ -3,7 +3,6 @@ # type: [null, string] # @schema # -- namespaceOverride allows to override the destination namespace for Cilium resources. -# This property allows to use Cilium as part of an Umbrella Chart with different targets. namespaceOverride: "" # @schema # type: [null, object] @@ -27,7 +26,7 @@ debug: # @schema # -- Configure verbosity levels for debug logging # This option is used to enable debug messages for operations related to such - # sub-system such as (e.g. kvstore, envoy, datapath or policy), and flow is + # sub-system such as (e.g. kvstore, envoy, datapath, policy, or tagged), and flow is # for enabling debug messages emitted per request, message and connection. # Multiple values can be set via a space-separated string (e.g. "datapath envoy"). # @@ -37,7 +36,17 @@ debug: # - envoy # - datapath # - policy + # - tagged verbose: ~ + + # -- Set the agent-internal metrics sampling frequency. This sets the + # frequency of the internal sampling of the agent metrics. These are + # available via the "cilium-dbg shell -- metrics -s" command and are + # part of the metrics HTML page included in the sysdump. + # @schema + # type: [null, string] + # @schema + metricsSamplingInterval: "5m" rbac: # -- Enable creation of Resource-Based Access Control configuration. create: true @@ -52,6 +61,18 @@ iptablesRandomFully: false # -- (string) Kubernetes config path # @default -- `"~/.kube/config"` kubeConfigPath: "" +# -- Configure the Kubernetes service endpoint dynamically using a ConfigMap. Mutually exclusive with `k8sServiceHost`. +k8sServiceHostRef: + # @schema + # type: [string, null] + # @schema + # -- (string) name of the ConfigMap containing the Kubernetes service endpoint + name: + # @schema + # type: [string, null] + # @schema + # -- (string) Key in the ConfigMap containing the Kubernetes service endpoint + key: # -- (string) Kubernetes service host - use "auto" for automatic lookup from the cluster-info ConfigMap k8sServiceHost: "" # @schema @@ -104,6 +125,15 @@ k8sClientRateLimit: # @default -- 200 burst: +# -- Configure exponential backoff for client-go in Cilium agent. +k8sClientExponentialBackoff: + # -- Enable exponential backoff for client-go in Cilium agent. + enabled: true + # -- Configure base (in seconds) for exponential backoff. + backoffBaseSeconds: 1 + # -- Configure maximum duration (in seconds) for exponential backoff. + backoffMaxDurationSeconds: 120 + cluster: # -- Name of the cluster. Only required for Cluster Mesh and mutual authentication with SPIRE. # It must respect the following constraints: @@ -177,14 +207,42 @@ serviceAccounts: name: hubble-generate-certs automount: true annotations: {} + # -- CorednsMCSAPI is used if clustermesh.mcsapi.corednsAutoConfigure.enabled=true + corednsMCSAPI: + create: true + name: cilium-coredns-mcsapi-autoconfig + automount: true + annotations: {} + # -- Ztunnel is used if encryption.type=ztunnel + ztunnel: + create: true + name: ztunnel-cilium + automount: false + annotations: {} # -- Configure termination grace period for cilium-agent DaemonSet. terminationGracePeriodSeconds: 1 # -- Install the cilium agent resources. agent: true -# -- Agent container name. +# -- Agent daemonset name. name: cilium # -- Roll out cilium agent pods automatically when configmap is updated. rollOutCiliumPods: false +# -- Configuration for the ConfigMap drift detection feature. +# When enabled, the agent continuously watches the cilium-config ConfigMap +# and exposes a cilium_drift_checker_config_delta Prometheus metric reporting +# the number of keys that differ between the ConfigMap and the agent's active +# settings. A non-zero value indicates that the agent has not yet applied all +# current ConfigMap changes and needs to be restarted. +configDriftDetection: + # -- Enable watching of the cilium-config ConfigMap and reflecting its + # contents into the agent's internal DynamicConfig table. + enabled: true + # -- Enable the drift checker which compares the DynamicConfig table against + # the agent's active settings and publishes the + # cilium_drift_checker_config_delta metric. + driftChecker: true + # -- List of config-map keys to ignore when computing the drift delta. + ignoredKeys: [] # -- Agent container image. image: # @schema @@ -271,6 +329,8 @@ podSecurityContext: # -- AppArmorProfile options for the `cilium-agent` and init containers appArmorProfile: type: "Unconfined" + seccompProfile: + type: "Unconfined" # -- Annotations to be added to agent pods podAnnotations: {} # -- Labels to be added to agent pods @@ -290,6 +350,8 @@ initResources: {} securityContext: # -- User to run the pod with # runAsUser: 0 + # -- disable privilege escalation + allowPrivilegeEscalation: false # -- Run the pod with elevated privileges privileged: false # -- SELinux options for the `cilium-agent` and init containers @@ -334,6 +396,8 @@ securityContext: - SETGID # Allow to execute program that changes UID (e.g. required for package installation) - SETUID + # Allow to read dmesg and get kernel pointers when kptr_restrict=1 + - SYSLOG # -- Capabilities for the `mount-cgroup` init container mountCgroup: # Only used for 'mount' cgroup @@ -406,9 +470,16 @@ azure: # clientID: 00000000-0000-0000-0000-000000000000 # clientSecret: 00000000-0000-0000-0000-000000000000 # userAssignedIdentityID: 00000000-0000-0000-0000-000000000000 + nodeSpec: + azureInterfaceName: "" alibabacloud: # -- Enable AlibabaCloud ENI integration enabled: false + nodeSpec: + vSwitches: [] + vSwitchTags: [] + securityGroups: [] + securityGroupTags: [] # -- Enable bandwidth manager to optimize TCP and UDP workloads and allow # for rate-limiting traffic from individual Pods with EDT (Earliest Departure # Time) through the "kubernetes.io/egress-bandwidth" Pod annotation. @@ -417,15 +488,11 @@ bandwidthManager: enabled: false # -- Activate BBR TCP congestion control for Pods bbr: false + # -- Activate BBR TCP congestion control for Pods in the host namespace only. + bbrHostNamespaceOnly: false # -- Configure standalone NAT46/NAT64 gateway nat46x64Gateway: - # -- Enable RFC8215-prefixed translation - enabled: false -# -- EnableHighScaleIPcache enables the special ipcache mode for high scale -# clusters. The ipcache content will be reduced to the strict minimum and -# traffic will be encapsulated to carry security identities. -highScaleIPcache: - # -- Enable the high scale mode for the ipcache. + # -- Enable RFC6052-prefixed translation enabled: false # -- Configure L2 announcements l2announcements: @@ -443,8 +510,9 @@ l2podAnnouncements: enabled: false # -- Interface used for sending Gratuitous ARP pod announcements interface: "eth0" -# -- This feature set enables virtual BGP routers to be created via -# CiliumBGPPeeringPolicy CRDs. + # -- A regular expression matching interfaces used for sending Gratuitous ARP pod announcements + # interfacePattern: "" +# -- This feature set enables virtual BGP routers to be created via BGP CRDs. bgpControlPlane: # -- Enables the BGP control plane. enabled: false @@ -454,16 +522,33 @@ bgpControlPlane: create: false # -- The name of the secret namespace to which Cilium agents are given read access name: kube-system - # -- Status reporting settings (BGPv2 only) + # -- Status reporting settings statusReport: - # -- Enable/Disable BGPv2 status reporting + # -- Enable/Disable BGP status reporting # It is recommended to enable status reporting in general, but if you have any issue # such as high API server load, you can disable it by setting this to false. enabled: true + # -- BGP router-id allocation mode + routerIDAllocation: + # -- BGP router-id allocation mode. In default mode, the router-id is derived from the IPv4 address if it is available, or else it is determined by the lower 32 bits of the MAC address. + mode: "default" + # -- IP pool to allocate the BGP router-id from when the mode is ip-pool. + ipPool: "" + # -- Legacy BGP ORIGIN attribute settings + legacyOriginAttribute: + # -- Enable/Disable advertising LoadBalancerIP routes with the legacy + # BGP ORIGIN attribute value INCOMPLETE (2) instead of the default IGP (0). + # Enable for compatibility with the legacy behavior of MetalLB integration. + enabled: false pmtuDiscovery: # -- Enable path MTU discovery to send ICMP fragmentation-needed replies to # the client. enabled: false + # -- Enable kernel probing path MTU discovery for Pods which uses different message + # sizes to search for correct MTU value. + # Valid values are: always, blackhole, disabled and unset (or empty). If value + # is 'unset' or left empty then will not try to override setting. + packetizationLayerPMTUDMode: "blackhole" bpf: autoMount: # -- Enable automatic mount of BPF filesystem @@ -511,8 +596,11 @@ bpf: # Helm configuration for BPF events map rate limiting is experimental and might change # in upcoming releases. events: - # -- Default settings for all types of events except dbg and pcap. + # -- Default settings for all types of events except dbg. default: + # @schema + # type: [null, integer] + # @schema # -- (int) Configure the limit of messages per second that can be written to # BPF events map. The number of messages is averaged, meaning that if no messages # were written to the map over 5 seconds, it's possible to write more events @@ -521,6 +609,9 @@ bpf: # and rateLimit to 0 disables BPF events rate limiting. # @default -- `0` rateLimit: ~ + # @schema + # type: [null, integer] + # @schema # -- (int) Configure the maximum number of messages that can be written to BPF events # map in 1 second. If burstLimit is greater than 0, non-zero value for rateLimit must # also be provided lest the configuration is considered invalid. Setting both burstLimit @@ -565,9 +656,20 @@ bpf: # type: [null, integer] # @schema policyMapMax: 16384 + # -- (float64) Configure threshold for emitting pressure metrics of policy maps. # @schema # type: [null, number] # @schema + # @default -- `0.1` + policyMapPressureMetricsThreshold: ~ + # -- Configure the maximum number of entries in global policy stats map. + # @schema + # type: [null, integer] + # @schema + policyStatsMapMax: 65536 + # @schema + # type: [null, number, string] + # @schema # -- (float64) Configure auto-sizing for all BPF maps based on available memory. # ref: https://docs.cilium.io/en/stable/network/ebpf/maps/ # @default -- `0.0025` @@ -617,7 +719,8 @@ bpf: # type: [null, boolean] # @schema # -- (bool) Configure the eBPF-based TPROXY (beta) to reduce reliance on iptables rules - # for implementing Layer 7 policy. + # for implementing Layer 7 policy. Note this is incompatible with netkit (`bpf.datapathMode=netkit`, + # `bpf.datapathMode=netkit-l2`). # @default -- `false` tproxy: ~ # @schema @@ -627,6 +730,15 @@ bpf: # [0] will allow all VLAN id's without any filtering. # @default -- `[]` vlanBypass: ~ + # -- Configure the IP tracing option type. + # This option is used to specify the IP option type to use for tracing. + # The value must be an integer between 0 and 255. + # @schema + # type: [null, integer] + # minimum: 0 + # maximum: 255 + # @schema + monitorTraceIPOption: 0 # -- (bool) Disable ExternalIP mitigation (CVE-2020-8554) # @default -- `false` disableExternalIPMitigation: false @@ -634,7 +746,8 @@ bpf: # supported kernels. # @default -- `true` enableTCX: true - # -- (string) Mode for Pod devices for the core datapath (veth, netkit, netkit-l2, lb-only) + # -- (string) Mode for Pod devices for the core datapath (veth, netkit, netkit-l2). + # Note netkit is incompatible with TPROXY (`bpf.tproxy`). # @default -- `veth` datapathMode: veth # -- Enable BPF clock source probing for more efficient tick retrieval. @@ -704,12 +817,16 @@ cni: # readCniConf: /host/etc/cni/net.d/05-sample.conflist.input # -- When defined, configMap will mount the provided value as ConfigMap and - # interpret the cniConf variable as CNI configuration file and write it - # when the agent starts up - # configMap: cni-configuration + # interpret the 'cni.configMapKey' value as CNI configuration file and write it + # when the agent starts up. + configMap: "" # -- Configure the key in the CNI ConfigMap to read the contents of - # the CNI configuration from. + # the CNI configuration from. For this to be effective, the 'cni.configMap' + # parameter must be specified too. + # Note that the 'cni.configMap' parameter is the name of the ConfigMap, while + # 'cni.configMapKey' is the name of the key in the ConfigMap data containing + # the actual configuration. configMapKey: cni-config # -- Configure the path to where to mount the ConfigMap inside the agent pod. confFileMountPath: /tmp/cni-configuration @@ -719,10 +836,29 @@ cni: # -- Specifies the resources for the cni initContainer resources: requests: + # @schema + # type: [integer, string] + # @schema cpu: 100m memory: 10Mi + limits: + # @schema + # type: [integer, string] + # @schema + cpu: 1 + memory: 1Gi # -- Enable route MTU for pod netns when CNI chaining is used enableRouteMTUForCNIChaining: false + # -- Enable the removal of iptables rules created by the AWS CNI VPC plugin. + iptablesRemoveAWSRules: true +# @schema +# type: [null, number] +# @schema +# -- (float64) Ratio of the connectivity probe frequency vs resource usage, a float in +# [0, 1]. 0 will give more frequent probing, 1 will give less frequent probing. Probing +# frequency is dynamically adjusted based on the cluster size. +# @default -- `0.5` +connectivityProbeFrequencyRatio: ~ # -- (string) Configure how frequently garbage collection should occur for the datapath # connection tracking table. # @default -- `"0s"` @@ -735,10 +871,6 @@ conntrackGCMaxInterval: "" # -- (string) Configure timeout in which Cilium will exit if CRDs are not available # @default -- `"5m"` crdWaitTimeout: "" -# -- Tail call hooks for custom eBPF programs. -customCalls: - # -- Enable tail call hooks for custom eBPF programs. - enabled: false daemon: # -- Configure where Cilium runtime state should be stored. runPath: "/var/run/cilium" @@ -781,6 +913,13 @@ daemon: # # By default, this functionality is enabled enableSourceIPVerification: true + +# -- Configure temporary volume for cilium-agent +tmpVolume: {} + # emptyDir: + # sizeLimit: "100Mi" + # medium: "Memory" + # -- Specify which network interfaces can run the eBPF datapath. This means # that a packet sent from a pod to a destination outside the cluster will be # masqueraded (to an output device IPv4 address), if the output device runs the @@ -788,14 +927,6 @@ daemon: # a non-local route. This should be used only when autodetection is not suitable. # devices: "" -# -- Enables experimental support for the detection of new and removed datapath -# devices. When devices change the eBPF datapath is reloaded and services updated. -# If "devices" is set then only those devices, or devices matching a wildcard will -# be considered. -# -# This option has been deprecated and is a no-op. -enableRuntimeDeviceDetection: true - # -- Forces the auto-detection of devices, even if specific devices are explicitly listed forceDeviceDetection: false @@ -808,12 +939,7 @@ forceDeviceDetection: false # -- Enable setting identity mark for local traffic. # enableIdentityMark: true -# -- Enable Kubernetes EndpointSlice feature in Cilium if the cluster supports it. -# enableK8sEndpointSlice: true - -# -- Enable CiliumEndpointSlice feature (deprecated, please use `ciliumEndpointSlice.enabled` instead). -enableCiliumEndpointSlice: false - +# -- CiliumEndpointSlice configuration options. ciliumEndpointSlice: # -- Enable Cilium EndpointSlice feature. enabled: false @@ -830,13 +956,13 @@ ciliumEndpointSlice: limit: 50 burst: 100 - # @schema - # enum: ["identity", "fcfs"] - # @schema - # -- The slicing mode to use for CiliumEndpointSlices. - # identity groups together CiliumEndpoints that share the same identity. - # fcfs groups together CiliumEndpoints in a first-come-first-serve basis, filling in the largest non-full slice first. - sliceMode: identity +# @schema +# enum: ["agent", "operator", "both"] +# @schema +# -- Control whether CiliumIdentities are created by the agent ("agent"), the operator ("operator") or both ("both"). +# "Both" should be used only to migrate between "agent" and "operator". +# Operator-managed identities is a beta feature. +identityManagementMode: "agent" envoyConfig: # -- Enable CiliumEnvoyConfig CRD @@ -997,20 +1123,33 @@ enableXTSocketFallback: true encryption: # -- Enable transparent network encryption. enabled: false - # -- Encryption method. Can be either ipsec or wireguard. + # -- Encryption method. Can be one of ipsec, wireguard or ztunnel. type: ipsec # -- Enable encryption for pure node to node traffic. # This option is only effective when encryption.type is set to "wireguard". nodeEncryption: false - # -- Configure the WireGuard Pod2Pod strict mode. + # -- Configure the Encryption Pod2Pod strict mode. strictMode: - # -- Enable WireGuard Pod2Pod strict mode. + # -- Enable Encryption Pod2Pod strict mode. (deprecated: please use encryption.strictMode.egress.enabled) enabled: false - # -- CIDR for the WireGuard Pod2Pod strict mode. + # -- CIDR for the Encryption Pod2Pod strict mode. (deprecated: please use encryption.strictMode.egress.cidr) cidr: "" - # -- Allow dynamic lookup of remote node identities. + # -- Allow dynamic lookup of remote node identities. (deprecated: please use encryption.strictMode.egress.allowRemoteNodeIdentities) # This is required when tunneling is used or direct routing is used and the node CIDR and pod CIDR overlap. allowRemoteNodeIdentities: false + egress: + # -- Enable strict egress encryption. + enabled: false + # -- CIDR for the Encryption Pod2Pod strict egress mode. + cidr: "" + # -- Allow dynamic lookup of remote node identities. + # This is required when tunneling is used or direct routing is used and the node CIDR and pod CIDR overlap. + allowRemoteNodeIdentities: false + ingress: + # -- Enable strict ingress encryption. + # When enabled, all unencrypted overlay ingress traffic will be dropped. + # This option is only applicable when WireGuard and tunneling are enabled. + enabled: false ipsec: # -- Name of the key file inside the Kubernetes secret configured via secretName. keyFile: keys @@ -1031,9 +1170,89 @@ encryption: wireguard: # -- Controls WireGuard PersistentKeepalive option. Set 0s to disable. persistentKeepalive: 0s + # -- ztunnel encryption configuration. + # ztunnel is Istio's purpose-built, per-node proxy for handling L4 traffic in ambient mesh mode. + # These settings only apply when encryption.type is set to "ztunnel". + ztunnel: + # -- ztunnel container image. + image: + # @schema + # type: [null, string] + # @schema + override: ~ + repository: "docker.io/istio/ztunnel" + tag: "1.28.0-distroless" + pullPolicy: "IfNotPresent" + # @schema + # type: [null, string] + # @schema + digest: ~ + useDigest: false + # -- CA server address for certificate requests. + caAddress: "https://localhost:15012" + # -- TCP port for the health API. + healthPort: 15021 + # -- ztunnel resource limits & requests. + resources: + requests: + cpu: 200m + memory: 512Mi + # -- ztunnel update strategy. + updateStrategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + # -- Configure termination grace period for ztunnel DaemonSet. + terminationGracePeriodSeconds: 30 + # -- Readiness probe configuration. + readinessProbe: + initialDelaySeconds: 0 + periodSeconds: 10 + failureThreshold: 3 + # -- Node selector for ztunnel pods. + nodeSelector: + kubernetes.io/os: linux + # -- Node tolerations for ztunnel scheduling. + tolerations: + - effect: NoSchedule + operator: Exists + - key: CriticalAddonsOnly + operator: Exists + - effect: NoExecute + operator: Exists + # -- Affinity for ztunnel pods. + affinity: {} + # @schema + # type: [null, string] + # @schema + # -- The priority class to use for ztunnel pods. + priorityClassName: ~ + # -- Annotations to be added to all ztunnel resources. + annotations: {} + # -- Annotations to be added to ztunnel pods. + podAnnotations: {} + # -- Labels to be added to ztunnel pods. + podLabels: {} + # -- Additional ztunnel container environment variables. + extraEnv: [] + # -- Additional ztunnel volumes. + extraVolumes: [] + # -- Additional ztunnel volumeMounts. + extraVolumeMounts: [] + # -- ztunnel secrets configuration. + secrets: + # -- Base64-encoded bootstrap root certificate content. + # If not provided, the secret must be created manually before deploying. + # @schema + # type: [null, string] + # @schema + bootstrapRootCert: ~ endpointHealthChecking: # -- Enable connectivity health checking between virtual endpoints. enabled: true +# -- Max duration to wait for envoy to respond to configuration changes. Default "10s". +endpointPolicyUpdateTimeoutDuration: null endpointRoutes: # @schema # type: [boolean, string] @@ -1049,8 +1268,6 @@ endpointLockdownOnMapOverflow: false eni: # -- Enable Elastic Network Interface (ENI) integration. enabled: false - # -- Update ENI Adapter limits from the EC2 API - updateEC2AdapterLimitViaAPI: true # -- Release IPs not used from the ENI awsReleaseExcessIPs: false # -- Enable ENI prefix delegation @@ -1084,9 +1301,33 @@ eni: # -- Filter via AWS EC2 Instance tags (k=v) which will dictate which AWS EC2 Instances # are going to be used to create new ENIs instanceTagsFilter: [] -externalIPs: - # -- Enable ExternalIPs service support. - enabled: false + # -- NodeSpec configuration for the ENI + nodeSpec: + # -- First interface index to use for IP allocation + # @schema + # type: [null, integer] + # @schema + firstInterfaceIndex: ~ + # -- Subnet IDs to use for IP allocation + subnetIDs: [] + # -- Subnet tags to use for IP allocation + subnetTags: [] + # -- Security groups to use for IP allocation + securityGroups: [] + # -- Security group tags to use for IP allocation + securityGroupTags: [] + # -- Exclude interface tags to use for IP allocation + excludeInterfaceTags: [] + # -- Use primary address for IP allocation + usePrimaryAddress: false + # -- Disable prefix delegation for IP allocation + disablePrefixDelegation: false + # -- Delete ENI on termination + # @schema + # type: [null, boolean] + # @schema + deleteOnTermination: ~ + # fragmentTracking enables IPv4 fragment tracking support in the datapath. # fragmentTracking: true gke: @@ -1102,9 +1343,8 @@ healthCheckICMPFailureThreshold: 3 hostFirewall: # -- Enables the enforcement of host policies in the eBPF datapath. enabled: false -hostPort: - # -- Enable hostPort service support. - enabled: false +# -- Enable routing to a service that has zero endpoints +enableNoServiceEndpointsRoutable: true # -- Configure socket LB socketLB: # -- Enable socket LB @@ -1132,8 +1372,11 @@ certgen: digest: "${CERTGEN_DIGEST}" useDigest: true pullPolicy: "${PULL_POLICY}" + # @schema + # type: [null, integer] + # @schema # -- Seconds after which the completed job pod will be deleted - ttlSecondsAfterFinished: 1800 + ttlSecondsAfterFinished: null # -- Labels to be added to hubble-certgen pods podLabels: {} # -- Annotations to be added to the hubble-certgen initial Job and CronJob @@ -1149,12 +1392,20 @@ certgen: # -- Node tolerations for pod assignment on nodes with taints # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ tolerations: [] + # -- Resource limits for certgen + # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers + resources: {} # -- Additional certgen volumes. extraVolumes: [] # -- Additional certgen volumeMounts. extraVolumeMounts: [] # -- Affinity for certgen affinity: {} + cronJob: + # -- The number of successful finished jobs to keep + successfulJobsHistoryLimit: 3 + # -- The number of failed finished jobs to keep + failedJobsHistoryLimit: 1 hubble: # -- Enable Hubble (true by default). enabled: true @@ -1170,6 +1421,9 @@ hubble: # 2047, 4095, 8191, 16383, 32767, 65535 # eventBufferCapacity: "4095" + # -- The interval at which Hubble will send out lost events from the Observer server, if any. + # lostEventSendInterval: 1s + # -- Hubble metrics configuration. # See https://docs.cilium.io/en/stable/observability/metrics/#hubble-metrics # for more comprehensive documentation about Hubble metrics. @@ -1244,11 +1498,17 @@ hubble: jobLabel: "" # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Relabeling configs for the ServiceMonitor hubble relabelings: - sourceLabels: - __meta_kubernetes_pod_node_name targetLabel: node + action: replace replacement: ${1} # @schema # type: [null, array] @@ -1288,6 +1548,10 @@ hubble: # excludeFilters: [] # -- Unix domain socket path to listen to when Hubble is enabled. socketPath: /var/run/cilium/hubble.sock + # -- Enables network policy correlation of Hubble flows, i.e. populating `egress_allowed_by`, `ingress_denied_by` fields with policy information. + networkPolicyCorrelation: + # @default -- `true` + enabled: true # -- Enables redacting sensitive information present in Layer 7 flows. redact: enabled: false @@ -1349,7 +1613,7 @@ hubble: # --set hubble.redact.http.headers.deny="Authorization,Proxy-Authorization" deny: [] kafka: - # -- Enables redacting Kafka's API key. + # -- Enables redacting Kafka's API key (deprecated, will be removed in v1.19). # Example: # # redact: @@ -1507,6 +1771,11 @@ hubble: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- The priority class to use for hubble-relay priorityClassName: "" # -- Configure termination grace period for hubble relay Deployment. @@ -1526,12 +1795,17 @@ hubble: # -- hubble-relay pod security context podSecurityContext: fsGroup: 65532 + seccompProfile: + type: RuntimeDefault # -- hubble-relay container security context securityContext: # readOnlyRootFilesystem: true + allowPrivilegeEscalation: false runAsNonRoot: true runAsUser: 65532 runAsGroup: 65532 + seccompProfile: + type: RuntimeDefault capabilities: drop: - ALL @@ -1592,13 +1866,6 @@ hubble: # @schema # type: [null, string] # @schema - # -- Dial timeout to connect to the local hubble instance to receive peer information (e.g. "30s"). - # - # This option has been deprecated and is a no-op. - dialTimeout: ~ - # @schema - # type: [null, string] - # @schema # -- Backoff duration to retry connecting to the local hubble instance in case of failure (e.g. "30s"). retryTimeout: ~ # @schema @@ -1633,6 +1900,11 @@ hubble: annotations: {} # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Specify the Kubernetes namespace where Prometheus expects to find # service monitors configured. # namespace: "" @@ -1658,6 +1930,24 @@ hubble: address: localhost # -- Configure pprof listen port for hubble-relay port: 6062 + # -- Enable mutex contention profiling for hubble-relay and set the fraction of sampled events (set to 1 to sample all events) + mutexProfileFraction: 0 + # -- Enable goroutine blocking profiling for hubble-relay and set the rate of sampled events in nanoseconds (set to 1 to sample all events [warning: performance overhead]) + blockProfileRate: 0 + # -- Logging configuration for hubble-relay. + logOptions: + # @schema + # type: [null, string] + # @schema + # -- Log format for hubble-relay. Valid values are: text, text-ts, json, json-ts. + # @default -- text-ts + format: ~ + # @schema + # type: [null, string] + # @schema + # -- Log level for hubble-relay. Valid values are: debug, info, warn, error. + # @default -- info + level: ~ ui: # -- Whether to enable the Hubble UI. enabled: false @@ -1709,7 +1999,8 @@ hubble: useDigest: true pullPolicy: "${PULL_POLICY}" # -- Hubble-ui backend security context. - securityContext: {} + securityContext: + allowPrivilegeEscalation: false # -- Additional hubble-ui backend environment variables. extraEnv: [] # -- Additional hubble-ui backend volumes. @@ -1743,7 +2034,8 @@ hubble: useDigest: true pullPolicy: "${PULL_POLICY}" # -- Hubble-ui frontend security context. - securityContext: {} + securityContext: + allowPrivilegeEscalation: false # -- Additional hubble-ui frontend environment variables. extraEnv: [] # -- Additional hubble-ui frontend volumes. @@ -1788,6 +2080,11 @@ hubble: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- Affinity for hubble-ui affinity: {} # -- Pod topology spread constraints for hubble-ui @@ -1822,6 +2119,8 @@ hubble: service: # -- Annotations to be added for the Hubble UI service annotations: {} + # -- Labels to be added for the Hubble UI service + labels: {} # --- The type of service used for Hubble UI access, either ClusterIP or NodePort. type: ClusterIP # --- The port to use when the service type is set to NodePort. @@ -1844,12 +2143,15 @@ hubble: # - secretName: chart-example-tls # hosts: # - chart-example.local + + # -- Configure temporary volume for hubble-ui + tmpVolume: {} + # emptyDir: + # # sizeLimit: "100Mi" + # # medium: "Memory" + # -- Hubble flows export. export: - # --- Defines max file size of output file before it gets rotated. - fileMaxSizeMb: 10 - # --- Defines max number of backup/rotated files. - fileMaxBackups: 5 # --- Static exporter configuration. # Static exporter is bound to agent lifecycle. static: @@ -1860,11 +2162,25 @@ hubble: # - source # - destination # - verdict + fieldAggregate: [] + # - time + # - source + # - destination + # - verdict + # --- Defines the interval at which to aggregate before exporting Hubble flows. + # Aggregation feature is only enabled when fieldAggregate is specified and aggregationInterval > 0s. + aggregationInterval: "0s" allowList: [] # - '{"verdict":["DROPPED","ERROR"]}' denyList: [] # - '{"source_pod":["kube-system/"]}' # - '{"destination_pod":["kube-system/"]}' + # --- Defines max file size of output file before it gets rotated. + fileMaxSizeMb: 10 + # --- Defines max number of backup/rotated files. + fileMaxBackups: 5 + # --- Enable compression of rotated files. + fileCompress: false # --- Dynamic exporters configuration. # Dynamic exporters may be reconfigured without a need of agent restarts. dynamic: @@ -1879,9 +2195,14 @@ hubble: content: - name: all fieldMask: [] + fieldAggregate: [] + aggregationInterval: "0s" includeFilters: [] excludeFilters: [] filePath: "/var/run/cilium/hubble/events.log" + fileMaxSizeMb: 10 + fileMaxBackups: 5 + fileCompress: false # - name: "test002" # filePath: "/var/log/network/flow-log/pa/test002.log" # fieldMask: ["source.namespace", "source.pod_name", "destination.namespace", "destination.pod_name", "verdict"] @@ -1891,6 +2212,9 @@ hubble: # - type: 1 # - destination_pod: ["frontend/nginx-975996d4c-7hhgt"] # excludeFilters: [] + # fileMaxSizeMb: 1 + # fileMaxBackups: 10 + # fileCompress: true # end: "2023-10-09T23:59:59-07:00" # -- Emit v1.Events related to pods on detection of packet drops. @@ -1967,11 +2291,30 @@ ipam: # refill the bucket up to the burst size capacity. # @default -- `4.0` externalAPILimitQPS: ~ -# -- defaultLBServiceIPAM indicates the default LoadBalancer Service IPAM when -# no LoadBalancer class is set. Applicable values: lbipam, nodeipam, none + # -- NodeSpec configuration for the IPAM + nodeSpec: + # -- IPAM min allocate + # @schema + # type: [null, integer] + # @schema + ipamMinAllocate: ~ + # -- IPAM pre allocate + # @schema + # type: [null, integer] + # @schema + ipamPreAllocate: ~ + # -- IPAM max allocate + # @schema + # type: [null, integer] + # @schema + ipamMaxAllocate: ~ + # -- IPAM static IP tags (currently only works with AWS and Azure) + ipamStaticIPTags: [] # @schema # type: [string] # @schema +# -- defaultLBServiceIPAM indicates the default LoadBalancer Service IPAM when +# no LoadBalancer class is set. Applicable values: lbipam, nodeipam, none defaultLBServiceIPAM: lbipam nodeIPAM: # -- Configure Node IPAM @@ -2007,14 +2350,18 @@ k8s: # -- requireIPv6PodCIDR enables waiting for Kubernetes to provide the PodCIDR # range via the Kubernetes node resource requireIPv6PodCIDR: false + # -- A space separated list of Kubernetes API server URLs to use with the client. + # For example "https://192.168.0.1:6443 https://192.168.0.2:6443" + # apiServerURLs: "" + # -- Keep the deprecated selector labels when deploying Cilium DaemonSet. keepDeprecatedLabels: false # -- Keep the deprecated probes when deploying Cilium DaemonSet keepDeprecatedProbes: false startupProbe: # -- failure threshold of startup probe. - # 105 x 2s translates to the old behaviour of the readiness probe (120s delay + 30 x 3s) - failureThreshold: 105 + # Allow Cilium to take up to 600s to start up (300 attempts with 2s between attempts). + failureThreshold: 300 # -- interval between checks of the startup probe periodSeconds: 2 livenessProbe: @@ -2032,7 +2379,10 @@ readinessProbe: # -- Configure the kube-proxy replacement in Cilium BPF datapath # Valid options are "true" or "false". # ref: https://docs.cilium.io/en/stable/network/kubernetes/kubeproxy-free/ -#kubeProxyReplacement: "false" + # @schema@ + # type: [string, boolean] + # @schema@ +kubeProxyReplacement: "false" # -- healthz server bind address for the kube-proxy replacement. # To enable set the value to '0.0.0.0:10256' for all ipv4 @@ -2041,13 +2391,24 @@ readinessProbe: kubeProxyReplacementHealthzBindAddr: "" l2NeighDiscovery: # -- Enable L2 neighbor discovery in the agent - enabled: true - # -- Override the agent's default neighbor resolution refresh period. - refreshPeriod: "30s" + enabled: false # -- Enable Layer 7 network policy. l7Proxy: true -# -- Enable Local Redirect Policy. + +# -- Enable Local Redirect Policy (deprecated, please use 'localRedirectPolicies.enabled' instead) localRedirectPolicy: false + +localRedirectPolicies: + # -- Enable local redirect policies. + enabled: false + + # -- Limit the allowed addresses in Address Matcher rule of + # Local Redirect Policies to the given CIDRs. + # @schema@ + # type: [null, array] + # @schema@ + addressMatcherCIDRs: ~ + # To include or exclude matched resources from cilium identity evaluation # labels: "" @@ -2066,8 +2427,12 @@ maglev: {} # -- hashSeed is the cluster-wide base64 encoded seed for the hashing # hashSeed: -# -- Enables masquerading of IPv4 traffic leaving the node from endpoints. -enableIPv4Masquerade: true +# @schema +# type: [null, boolean] +# @schema +# -- (bool) Enables masquerading of IPv4 traffic leaving the node from endpoints. +# @default -- `true` unless ipam eni mode is active +enableIPv4Masquerade: ~ # -- Enables masquerading of IPv6 traffic leaving the node from endpoints. enableIPv6Masquerade: true # -- Enables masquerading to the source of the route for traffic leaving the node from endpoints. @@ -2149,17 +2514,13 @@ loadBalancer: # path), or best-effort (use native mode XDP acceleration on devices # that support it). acceleration: disabled - # -- dsrDispatch configures whether IP option or IPIP encapsulation is - # used to pass a service IP and port to remote backend + # -- dsrDispatch configures whether IP option (opt), IPIP encapsulation (ipip), + # Geneve Class Option (geneve) used to pass a service IP and port to remote backend # dsrDispatch: opt # -- serviceTopology enables K8s Topology Aware Hints -based service # endpoints filtering - # serviceTopology: false - - # -- experimental enables support for the experimental load-balancing - # control-plane. - experimental: false + serviceTopology: false # -- L7 LoadBalancer l7: @@ -2183,8 +2544,6 @@ loadBalancer: algorithm: round_robin # -- Configure N-S k8s service loadbalancing nodePort: - # -- Enable the Cilium NodePort service implementation. - enabled: false # -- Port range to use for NodePort services. # range: "30000,32767" @@ -2229,6 +2588,10 @@ pprof: address: localhost # -- Configure pprof listen port for cilium-agent port: 6060 + # -- Enable mutex contention profiling for cilium-agent and set the fraction of sampled events (set to 1 to sample all events) + mutexProfileFraction: 0 + # -- Enable goroutine blocking profiling for cilium-agent and set the rate of sampled events in nanoseconds (set to 1 to sample all events [warning: performance overhead]) + blockProfileRate: 0 # -- Configure prometheus metrics on the configured port at /metrics prometheus: metricsService: false @@ -2246,6 +2609,11 @@ prometheus: jobLabel: "" # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Specify the Kubernetes namespace where Prometheus expects to find # service monitors configured. # namespace: "" @@ -2254,6 +2622,7 @@ prometheus: - sourceLabels: - __meta_kubernetes_pod_node_name targetLabel: node + action: replace replacement: ${1} # @schema # type: [null, array] @@ -2347,6 +2716,12 @@ envoy: initialFetchTimeoutSeconds: 30 # -- Maximum number of concurrent retries on Envoy clusters maxConcurrentRetries: 128 + # -- Maximum number of connections on Envoy clusters + clusterMaxConnections: 1024 + # -- Maximum number of requests on Envoy clusters + clusterMaxRequests: 1024 + # -- Maximum number of global downstream connections + maxGlobalDownstreamConnections: 50000 # -- Maximum number of retries for each HTTP request httpRetryCount: 3 # -- ProxyMaxRequestsPerConnection specifies the max_requests_per_connection setting for Envoy @@ -2356,15 +2731,23 @@ envoy: # -- Set Envoy upstream HTTP idle connection timeout seconds. # Does not apply to connections with pending requests. Default 60s idleTimeoutDurationSeconds: 60 + # -- Set Envoy the amount of time that the connection manager will allow a stream to exist with no upstream or downstream activity. + # default 5 minutes + streamIdleTimeoutDurationSeconds: 300 # -- Number of trusted hops regarding the x-forwarded-for and related HTTP headers for the ingress L7 policy enforcement Envoy listeners. xffNumTrustedHopsL7PolicyIngress: 0 # -- Number of trusted hops regarding the x-forwarded-for and related HTTP headers for the egress L7 policy enforcement Envoy listeners. xffNumTrustedHopsL7PolicyEgress: 0 + # -- For cases when CiliumEnvoyConfig is not used directly (Ingress, Gateway), configures Cilium BPF Metadata listener filter + # to use the original source address when extracting the metadata for a request. + useOriginalSourceAddress: true # @schema # type: [null, string] # @schema # -- Max duration to wait for endpoint policies to be restored on restart. Default "3m". policyRestoreTimeoutDuration: null + # -- Time in seconds to block Envoy worker thread while an upstream HTTP connection is closing. If set to 0, the connection is closed immediately (with TCP RST). If set to -1, the connection is closed asynchronously in the background. + httpUpstreamLingerTimeout: null # -- Envoy container image. image: # @schema @@ -2376,6 +2759,8 @@ envoy: pullPolicy: "${PULL_POLICY}" digest: "${CILIUM_ENVOY_DIGEST}" useDigest: true + # -- Init containers added to the cilium Envoy DaemonSet. + initContainers: [] # -- Additional containers added to the cilium Envoy DaemonSet. extraContainers: [] # -- Additional envoy container arguments. @@ -2441,12 +2826,16 @@ envoy: # memory: 512Mi startupProbe: + # -- Enable startup probe for cilium-envoy + enabled: true # -- failure threshold of startup probe. # 105 x 2s translates to the old behaviour of the readiness probe (120s delay + 30 x 3s) failureThreshold: 105 # -- interval between checks of the startup probe periodSeconds: 2 livenessProbe: + # -- Enable liveness probe for cilium-envoy + enabled: true # -- failure threshold of liveness probe failureThreshold: 10 # -- interval between checks of the liveness probe @@ -2559,6 +2948,11 @@ envoy: annotations: {} # -- Interval for scrape metrics. interval: "10s" + # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ # -- Specify the Kubernetes namespace where Prometheus expects to find # service monitors configured. # namespace: "" @@ -2568,6 +2962,7 @@ envoy: - sourceLabels: - __meta_kubernetes_pod_node_name targetLabel: node + action: replace replacement: ${1} # @schema # type: [null, array] @@ -2581,6 +2976,10 @@ envoy: # -- Enable/Disable use of node label based identity nodeSelectorLabels: false +# To include or exclude matched resources from cilium node identity evaluation +# List of labels just like --labels flag (.Values.labels) +# nodeLabels: "" + # -- Enable resource quotas for priority classes used in the cluster. resourceQuotas: enabled: false @@ -2594,14 +2993,16 @@ resourceQuotas: pods: "15" # Need to document default ################## -#sessionAffinity: false + +# -- Annotations to be added to all cilium-secret namespaces (resources under templates/cilium-secrets-namespace) +secretsNamespaceAnnotations: {} +# -- Labels to be added to all cilium-secret namespaces (resources under templates/cilium-secrets-namespace) +secretsNamespaceLabels: {} # -- Do not run Cilium agent when running with clean mode. Useful to completely # uninstall Cilium as it will stop Cilium from starting and create artifacts # in the node. sleepAfterInit: false -# -- Enable check of service source ranges (currently, only for LoadBalancer). -svcSourceRangeCheck: true # -- Synchronize Kubernetes nodes to kvstore and perform CNP GC. synchronizeK8sNodes: true # -- Configure TLS configuration in the agent. @@ -2683,6 +3084,12 @@ tls: # - geneve # @default -- `"vxlan"` tunnelProtocol: "" +# -- IP family for the underlay. +# Possible values: +# - "ipv4" +# - "ipv6" +# @default -- `"ipv4"` +underlayProtocol: "" # -- Enable native-routing mode or tunneling mode. # Possible values: # - "" @@ -2701,6 +3108,11 @@ tunnelSourcePortRange: 0-0 # - reject (default) # - drop serviceNoBackendResponse: reject +# -- Configure what the response should be to pod egress traffic denied by network policy. +# Possible values: +# - none (default) +# - icmp +policyDenyResponse: none # -- Configure the underlying network MTU to overwrite auto-detected MTU. # This value doesn't change the host network interface MTU i.e. eth0 or ens0. # It changes the MTU for cilium_net@cilium_host, cilium_host@cilium_net, @@ -2782,12 +3194,19 @@ operator: kubernetes.io/os: linux # -- Node tolerations for cilium-operator scheduling to nodes with taints # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ + # Toleration for agentNotReadyTaintKey taint is always added to cilium-operator pods. + # @schema + # type: [null, array] + # @schema tolerations: - - operator: Exists - # - key: "key" - # operator: "Equal|Exists" - # value: "value" - # effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)" + - key: "node-role.kubernetes.io/control-plane" + operator: Exists + - key: "node-role.kubernetes.io/master" #deprecated + operator: Exists + - key: "node.kubernetes.io/not-ready" + operator: Exists + - key: "node.cloudprovider.kubernetes.io/uninitialized" + operator: Exists # -- Additional cilium-operator container arguments. extraArgs: [] # -- Additional cilium-operator environment variables. @@ -2810,7 +3229,9 @@ operator: # -- HostNetwork setting hostNetwork: true # -- Security context to be added to cilium-operator pods - podSecurityContext: {} + podSecurityContext: + seccompProfile: + type: RuntimeDefault # -- Annotations to be added to cilium-operator pods podAnnotations: {} # -- Labels to be added to cilium-operator pods @@ -2831,6 +3252,11 @@ operator: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- cilium-operator resource limits & requests # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: {} @@ -2842,7 +3268,11 @@ operator: # memory: 128Mi # -- Security context to be added to cilium-operator pods - securityContext: {} + securityContext: + capabilities: + drop: + - ALL + allowPrivilegeEscalation: false # runAsUser: 0 # -- Interval for endpoint garbage collection. @@ -2860,6 +3290,10 @@ operator: address: localhost # -- Configure pprof listen port for cilium-operator port: 6061 + # -- Enable mutex contention profiling for cilium-operator and set the fraction of sampled events (set to 1 to sample all events) + mutexProfileFraction: 0 + # -- Enable goroutine blocking profiling for cilium-operator and set the rate of sampled events in nanoseconds (set to 1 to sample all events [warning: performance overhead]) + blockProfileRate: 0 # -- Enable prometheus metrics for cilium-operator on the configured port at # /metrics prometheus: @@ -2879,6 +3313,11 @@ operator: # -- Interval for scrape metrics. interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor cilium-operator @@ -2888,6 +3327,17 @@ operator: # @schema # -- Metrics relabeling configs for the ServiceMonitor cilium-operator metricRelabelings: ~ + # -- TLS configuration for Prometheus + tls: + enabled: false + server: + # -- Name of the Secret containing the certificate, key and CA files for the Prometheus server. + existingSecret: "" + mtls: + # When set to true enforces mutual TLS between Operator Prometheus server and its clients. + # False allow non-mutual TLS connections. + # This option has no effect when TLS is disabled. + enabled: false # -- Grafana dashboards for cilium-operator # grafana can import dashboards based on the label and value # ref: https://github.com/grafana/helm-charts/tree/main/charts/grafana#sidecar-for-dashboards @@ -2921,6 +3371,12 @@ operator: # -- Interval, in seconds, to check if there are any pods that are not # managed by Cilium. intervalSeconds: 15 + # -- Selector for pods that should be restarted when not managed by Cilium. + # If not set, defaults to built-in selector "k8s-app=kube-dns". Set to empty string to select all pods. + # @schema + # type: [null, string] + # @schema + selector: ~ nodeinit: # -- Enable the node initialization DaemonSet enabled: false @@ -2975,10 +3431,14 @@ nodeinit: # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: requests: + # @schema + # type: [integer, string] + # @schema cpu: 100m memory: 100Mi # -- Security context to be added to nodeinit pods. securityContext: + allowPrivilegeEscalation: false privileged: false seLinuxOptions: level: 's0' @@ -2998,6 +3458,8 @@ nodeinit: # -- bootstrapFile is the location of the file where the bootstrap timestamp is # written by the node-init DaemonSet bootstrapFile: "/tmp/cilium-bootstrap.d/cilium-bootstrap-time" + # -- wait for Cloud init to finish on the host and assume the node has cloud init installed + waitForCloudInit: false # -- startup offers way to customize startup nodeinit script (pre and post position) startup: preScript: "" @@ -3021,6 +3483,18 @@ preflight: digest: ${CILIUM_DIGEST} useDigest: ${USE_DIGESTS} pullPolicy: "${PULL_POLICY}" + envoy: + # -- Envoy pre-flight image. + image: + # @schema + # type: [null, string] + # @schema + override: ~ + repository: "${CILIUM_ENVOY_REPO}" + tag: "${CILIUM_ENVOY_VERSION}" + pullPolicy: "${PULL_POLICY}" + digest: "${CILIUM_ENVOY_DIGEST}" + useDigest: true # -- The priority class to use for the preflight pod. priorityClassName: "" # -- preflight update strategy @@ -3076,6 +3550,11 @@ preflight: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- preflight resource limits & requests # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ resources: {} @@ -3092,7 +3571,8 @@ preflight: # -- interval between checks of the readiness probe periodSeconds: 5 # -- Security context to be added to preflight pods - securityContext: {} + securityContext: + allowPrivilegeEscalation: false # runAsUser: 0 # -- Path to write the `--tofqdns-pre-cache` file to. @@ -3113,7 +3593,9 @@ enableCriticalPriorityClass: true # on AArch64 as the images do not currently ship a version of Envoy. #disableEnvoyVersionCheck: false clustermesh: - # -- Deploy clustermesh-apiserver for clustermesh + # -- Deploy clustermesh-apiserver for clustermesh. This option is typically + # used with ``clustermesh.config.enabled=true``. Refer to the + # ``clustermesh.config.enabled=true``documentation for more information. useAPIServer: false # -- The maximum number of clusters to support in a ClusterMesh. This value # cannot be changed on running clusters, and all clusters in a ClusterMesh @@ -3121,43 +3603,133 @@ clustermesh: # maximum allocatable cluster-local identities. # Supported values are 255 and 511. maxConnectedClusters: 255 + # -- The time to live for the cache of a remote cluster after connectivity is + # lost. If the connection is not re-established within this duration, the + # cached data is revoked to prevent stale state. If not specified or set to + # 0s, the cache is never revoked (default). + cacheTTL: "0s" # -- Enable the synchronization of Kubernetes EndpointSlices corresponding to # the remote endpoints of appropriately-annotated global services through ClusterMesh enableEndpointSliceSynchronization: false - # -- Enable Multi-Cluster Services API support + # -- Enable Multi-Cluster Services API support (deprecated; use clustermesh.mcsapi.enabled) enableMCSAPISupport: false + # -- Control whether policy rules assume by default the local cluster if not explicitly selected + policyDefaultLocalCluster: true # -- Annotations to be added to all top-level clustermesh objects (resources under templates/clustermesh-apiserver and templates/clustermesh-config) annotations: {} # -- Clustermesh explicit configuration. config: # -- Enable the Clustermesh explicit configuration. + # If set to false, you need to provide the following resources yourself: + # - (Secret) cilium-clustermesh (used by cilium-agent/cilium-operator to connect to + # the local etcd instance if KVStoreMesh is enabled or the remote clusters + # if KVStoreMesh is disabled) + # - (Secret) cilium-kvstoremesh (used by KVStoreMesh to connect to the remote clusters) + # - (ConfigMap) clustermesh-remote-users (used to create one etcd user per remote cluster + # if clustermesh-apiserver is used and `clustermesh.apiserver.tls.authMode` is not + # set to `legacy`) enabled: false # -- Default dns domain for the Clustermesh API servers # This is used in the case cluster addresses are not provided # and IPs are used. domain: mesh.cilium.io - # -- List of clusters to be peered in the mesh. + # -- Clusters to be peered in the mesh. + # @schema + # type: [object, array] + # @schema clusters: [] + # You can use a dict of clusters (recommended): # clusters: - # # -- Name of the cluster + # # -- Name of the cluster + # cluster1: + # # -- Whether to enable this cluster in the mesh. Optional, defaults to true. + # enabled: true + # # -- Address of the cluster, use this if you created DNS records for + # # the cluster Clustermesh API server. + # address: cluster1.mesh.cilium.io + # # -- Port of the cluster Clustermesh API server. + # port: 2379 + # # -- IPs of the cluster Clustermesh API server, use multiple ones when + # # you have multiple IPs to access the Clustermesh API server. + # ips: + # - 172.18.255.201 + # # -- (deprecated) base64 encoded PEM values for the cluster client certificate, private key and certificate authority. + # # These fields can (and should) be omitted in case the CA is shared across clusters. In that case, the + # # "remote" private key and certificate available in the local cluster are automatically used instead. + # tls: + # cert: "" + # key: "" + # caCert: "" + # + # Or alternatively you can use a list of clusters: + # clusters: + # # -- Name of the cluster # - name: cluster1 - # # -- Address of the cluster, use this if you created DNS records for - # # the cluster Clustermesh API server. + # # -- Address of the cluster, use this if you created DNS records for + # # the cluster Clustermesh API server. # address: cluster1.mesh.cilium.io - # # -- Port of the cluster Clustermesh API server. + # # -- Port of the cluster Clustermesh API server. # port: 2379 - # # -- IPs of the cluster Clustermesh API server, use multiple ones when - # # you have multiple IPs to access the Clustermesh API server. + # # -- IPs of the cluster Clustermesh API server, use multiple ones when + # # you have multiple IPs to access the Clustermesh API server. # ips: # - 172.18.255.201 - # # -- base64 encoded PEM values for the cluster client certificate, private key and certificate authority. - # # These fields can (and should) be omitted in case the CA is shared across clusters. In that case, the - # # "remote" private key and certificate available in the local cluster are automatically used instead. + # # -- (deprecated) base64 encoded PEM values for the cluster client certificate, private key and certificate authority. + # # These fields can (and should) be omitted in case the CA is shared across clusters. In that case, the + # # "remote" private key and certificate available in the local cluster are automatically used instead. # tls: # cert: "" # key: "" # caCert: "" + mcsapi: + # -- Enable Multi-Cluster Services API support + enabled: false + # -- Enabled MCS-API CRDs auto-installation + installCRDs: true + corednsAutoConfigure: + # -- Enable auto-configuration of CoreDNS for Multi-Cluster Services API. + # CoreDNS MUST be at least in version v1.12.2 to run this. + enabled: false + coredns: + # -- The Deployment for the cluster CoreDNS service + deploymentName: coredns + # -- The Service Account name for the cluster CoreDNS service + serviceAccountName: coredns + # -- The ConfigMap name for the cluster CoreDNS service + configMapName: coredns + # -- The namespace for the cluster CoreDNS service + namespace: kube-system + # -- The cluster domain for the cluster CoreDNS service + clusterDomain: cluster.local + # -- The clusterset domain for the cluster CoreDNS service + clustersetDomain: clusterset.local + # -- Additional arguments to `clustermesh-apiserver coredns-mcsapi-auto-configure`. + extraArgs: [] + # -- Seconds after which the completed job pod will be deleted + ttlSecondsAfterFinished: 1800 + # -- Labels to be added to coredns-mcsapi-autoconfig pods + podLabels: {} + # -- Annotations to be added to the coredns-mcsapi-autoconfig Job + annotations: {} + # -- Node selector for coredns-mcsapi-autoconfig + # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector + nodeSelector: {} + # -- Priority class for coredns-mcsapi-autoconfig + # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#priorityclass + priorityClassName: "" + # -- Node tolerations for pod assignment on nodes with taints + # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ + tolerations: [] + # -- Resource limits for coredns-mcsapi-autoconfig + # ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers + resources: {} + # -- Additional coredns-mcsapi-autoconfig volumes. + extraVolumes: [] + # -- Additional coredns-mcsapi-autoconfig volumeMounts. + extraVolumeMounts: [] + # -- Affinity for coredns-mcsapi-autoconfig + affinity: {} apiserver: # -- Clustermesh API server image. image: @@ -3226,7 +3798,7 @@ clustermesh: kvstoremesh: # -- Enable KVStoreMesh. KVStoreMesh caches the information retrieved - # from the remote clusters in the local etcd instance. + # from the remote clusters in the local etcd instance (deprecated - KVStoreMesh will always be enabled once the option is removed). enabled: true # -- TCP port for the KVStoreMesh health API. @@ -3257,18 +3829,18 @@ clustermesh: - ALL # -- lifecycle setting for the KVStoreMesh container lifecycle: {} + # -- Specify the KVStore mode when running KVStoreMesh + # Supported values: + # - "internal": remote cluster identities are cached in etcd that runs as a sidecar within ``clustermesh-apiserver`` pod. + # - "external": ``clustermesh-apiserver`` will sync remote cluster information to the etcd used as kvstore. This can't be enabled with crd identity allocation mode. + kvstoreMode: "internal" service: + # -- (bool) Set externallyCreated to true to create the clustermesh-apiserver service outside this helm chart. + # For example after external load balancer controllers are created. + externallyCreated: false # -- The type of service used for apiserver access. type: NodePort # -- Optional port to use as the node port for apiserver access. - # - # WARNING: make sure to configure a different NodePort in each cluster if - # kube-proxy replacement is enabled, as Cilium is currently affected by a known - # bug (#24692) when NodePorts are handled by the KPR implementation. If a service - # with the same NodePort exists both in the local and the remote cluster, all - # traffic originating from inside the cluster and targeting the corresponding - # NodePort will be redirected to a local backend, regardless of whether the - # destination node belongs to the local or the remote cluster. nodePort: 32379 # -- Annotations for the clustermesh-apiserver service. # Example annotations to configure an internal load balancer on different cloud providers: @@ -3276,6 +3848,8 @@ clustermesh: # * EKS: service.beta.kubernetes.io/aws-load-balancer-scheme: "internal" # * GKE: networking.gke.io/load-balancer-type: "Internal" annotations: {} + # -- Labels for the clustermesh-apiserver service. + labels: {} # @schema # enum: [Local, Cluster] # @schema @@ -3368,6 +3942,11 @@ clustermesh: # @schema # -- Maximum number/percentage of pods that may be made unavailable maxUnavailable: 1 + # @schema + # type: [null, string] + # @schema + # -- How are unhealthy, but running, pods counted for eviction + unhealthyPodEvictionPolicy: null # -- Resource requests and limits for the clustermesh-apiserver resources: {} # requests: @@ -3430,13 +4009,15 @@ clustermesh: # The "remote" certificate must be generated with CN=remote- # if provided manually. Cluster mode is meaningful only when the same # CA is shared across all clusters part of the mesh. - authMode: legacy - # -- Allow users to provide their own certificates + authMode: migration + # -- (deprecated) Allow users to provide their own certificates # Users may need to provide their certificates using # a mechanism that requires they provide their own secrets. # This setting does not apply to any of the auto-generated # mechanisms below, it only restricts the creation of secrets # via the `tls-provided` templates. + # This option is deprecated as secrets are expected to be created + # externally when 'auto' is not enabled. enableSecrets: true # -- Configure automatic TLS certificates generation. # A Kubernetes CronJob is used the generate any @@ -3445,7 +4026,14 @@ clustermesh: auto: # -- When set to true, automatically generate a CA and certificates to # enable mTLS between clustermesh-apiserver and external workload instances. - # If set to false, the certs to be provided by setting appropriate values below. + # + # When set to false you need to pre-create the following secrets: + # - clustermesh-apiserver-server-cert + # - clustermesh-apiserver-admin-cert + # - clustermesh-apiserver-remote-cert + # - clustermesh-apiserver-local-cert + # The above secret should at least contains the keys `tls.crt` and `tls.key` + # and optionally `ca.crt` if a CA bundle is not configured. enabled: true # Sets the method to auto-generate certificates. Supported values: # - helm: This method uses Helm to generate all certificates. @@ -3477,10 +4065,13 @@ clustermesh: # name: ca-issuer # -- certmanager issuer used when clustermesh.apiserver.tls.auto.method=certmanager. certManagerIssuerRef: {} + # -- base64 encoded PEM values for the clustermesh-apiserver server certificate and private key. # Used if 'auto' is not enabled. server: + # -- Deprecated, as secrets will always need to be created externally if `auto` is disabled. cert: "" + # -- Deprecated, as secrets will always need to be created externally if `auto` is disabled. key: "" # -- Extra DNS names added to certificate when it's auto generated extraDnsNames: [] @@ -3489,17 +4080,16 @@ clustermesh: # -- base64 encoded PEM values for the clustermesh-apiserver admin certificate and private key. # Used if 'auto' is not enabled. admin: + # -- Deprecated, as secrets will always need to be created externally if `auto` is disabled. cert: "" - key: "" - # -- base64 encoded PEM values for the clustermesh-apiserver client certificate and private key. - # Used if 'auto' is not enabled. - client: - cert: "" + # -- Deprecated, as secrets will always need to be created externally if `auto` is disabled. key: "" # -- base64 encoded PEM values for the clustermesh-apiserver remote cluster certificate and private key. # Used if 'auto' is not enabled. remote: + # -- Deprecated, as secrets will always need to be created externally if `auto` is disabled. cert: "" + # -- Deprecated, as secrets will always need to be created externally if `auto` is disabled. key: "" # clustermesh-apiserver Prometheus metrics configuration metrics: @@ -3534,6 +4124,11 @@ clustermesh: # -- Interval for scrape metrics (apiserver metrics) interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor clustermesh-apiserver (apiserver metrics) @@ -3547,6 +4142,11 @@ clustermesh: # -- Interval for scrape metrics (KVStoreMesh metrics) interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor clustermesh-apiserver (KVStoreMesh metrics) @@ -3560,6 +4160,11 @@ clustermesh: # -- Interval for scrape metrics (etcd metrics) interval: "10s" # @schema + # type: [null, string] + # @schema + # -- Timeout after which scrape is considered to be failed. + scrapeTimeout: ~ + # @schema # type: [null, array] # @schema # -- Relabeling configs for the ServiceMonitor clustermesh-apiserver (etcd metrics) @@ -3569,10 +4174,6 @@ clustermesh: # @schema # -- Metrics relabeling configs for the ServiceMonitor clustermesh-apiserver (etcd metrics) metricRelabelings: ~ -# -- Configure external workloads support -externalWorkloads: - # -- Enable support for external workloads, such as VMs (false by default). - enabled: false # -- Configure cgroup related configuration cgroup: autoMount: @@ -3597,9 +4198,6 @@ cgroup: sysctlfix: # -- Enable the sysctl override. When enabled, the init container will mount the /proc of the host so that the `sysctlfix` utility can execute. enabled: true -# -- Configure whether to enable auto detect of terminating state for endpoints -# in order to support graceful termination. -enableK8sTerminatingEndpoint: true # -- Configure whether to unload DNS policy rules on graceful shutdown # dnsPolicyUnloadOnShutdown: false @@ -3632,6 +4230,9 @@ dnsProxy: proxyResponseMaxDelay: 100ms # -- DNS proxy operation mode (true/false, or unset to use version dependent defaults) # enableTransparentMode: true + # -- Pre-allocate ToFQDN identities. This reduces DNS proxy tail latency, at the potential cost of some + # unnecessary policymap entries. Disable this if you have a large (200+) number of unique ToFQDN selectors. + preAllocateIdentities: true # -- SCTP Configuration Values sctp: # -- Enable SCTP support. NOTE: Currently, SCTP support does not support rewriting ports or multihoming. @@ -3643,7 +4244,7 @@ authentication: # -- Enable authentication processing and garbage collection. # Note that if disabled, policy enforcement will still block requests that require authentication. # But the resulting authentication requests for these requests will not be processed, therefore the requests not be allowed. - enabled: true + enabled: false # -- Buffer size of the channel Cilium uses to receive authentication events from the signal map. queueSize: 1024 # -- Buffer size of the channel Cilium uses to receive certificate expiration events from auth handlers. @@ -3836,3 +4437,41 @@ authentication: enableInternalTrafficPolicy: true # -- Enable LoadBalancer IP Address Management enableLBIPAM: true +# -- Standalone DNS Proxy Configuration +# Note: The standalone DNS proxy uses the agent's dnsProxy.* configuration +# for DNS settings (proxyPort, enableDnsCompression) to ensure consistency. +standaloneDnsProxy: + # -- Enable standalone DNS proxy (alpha feature) + enabled: false + # -- Roll out Standalone DNS proxy automatically when configmap is updated. + rollOutPods: false + # -- Standalone DNS proxy annotations + annotations: {} + # -- Standalone DNS proxy debug mode + debug: false + # -- Standalone DNS proxy server port + serverPort: 10095 + # -- Standalone DNS proxy Node Selector + nodeSelector: + kubernetes.io/os: linux + # -- Standalone DNS proxy tolerations + tolerations: [] + # -- Standalone DNS proxy auto mount service account token + automountServiceAccountToken: false + # -- Standalone DNS proxy update strategy + updateStrategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 2 + maxUnavailable: 0 + # -- Standalone DNS proxy image + image: + # @schema + # type: [null, string] + # @schema + override: ~ + repository: "${STANDALONE_DNS_PROXY_REPO}" + tag: "${STANDALONE_DNS_PROXY_VERSION}" + digest: "${STANDALONE_DNS_PROXY_DIGEST}" + useDigest: ${USE_DIGESTS} + pullPolicy: "${PULL_POLICY}" diff --git a/packages/system/cilium/images/cilium/Dockerfile b/packages/system/cilium/images/cilium/Dockerfile index a8ea6535..32fc6fb8 100644 --- a/packages/system/cilium/images/cilium/Dockerfile +++ b/packages/system/cilium/images/cilium/Dockerfile @@ -1,2 +1,2 @@ -ARG VERSION=v1.17.4 +ARG VERSION=v1.19.3 FROM quay.io/cilium/cilium:${VERSION} diff --git a/packages/system/cilium/values-apparmor.yaml b/packages/system/cilium/values-apparmor.yaml new file mode 100644 index 00000000..0712836c --- /dev/null +++ b/packages/system/cilium/values-apparmor.yaml @@ -0,0 +1,20 @@ +cilium: + # Opt out of the cri-containerd.apparmor.d profile for containers that invoke + # nsenter to join the host cgroup/mount namespace. The kernel reports the + # denial as a blocked "ptrace" operation. Required on Ubuntu 22.04+ and + # other distros that load this AppArmor profile by default, where the + # denial otherwise puts cilium-agent into Init:CrashLoopBackOff. + # The deprecated annotations are used because k8s >= 1.30 pod-level + # appArmorProfile: Unconfined is not honoured by containerd CRI today + # (kubernetes/kubernetes#125069). + # Only applied on non-Talos cilium variants where cgroup.autoMount.enabled is + # true — on Talos mount-cgroup is not rendered and the kube-apiserver would + # reject an annotation referencing a non-existent container. + # mount-bpf-fs is intentionally excluded: it renders with its own + # securityContext.privileged=true, and the kernel does not apply AppArmor + # profiles to privileged containers. + podAnnotations: + container.apparmor.security.beta.kubernetes.io/cilium-agent: unconfined + container.apparmor.security.beta.kubernetes.io/clean-cilium-state: unconfined + container.apparmor.security.beta.kubernetes.io/mount-cgroup: unconfined + container.apparmor.security.beta.kubernetes.io/apply-sysctl-overwrites: unconfined diff --git a/packages/system/cilium/values-kilo.yaml b/packages/system/cilium/values-kilo.yaml new file mode 100644 index 00000000..c303ef0a --- /dev/null +++ b/packages/system/cilium/values-kilo.yaml @@ -0,0 +1,3 @@ +cilium: + hostFirewall: + enabled: false diff --git a/packages/system/cilium/values-kubeovn.yaml b/packages/system/cilium/values-kubeovn.yaml index 3a4e3abc..62c75b29 100644 --- a/packages/system/cilium/values-kubeovn.yaml +++ b/packages/system/cilium/values-kubeovn.yaml @@ -15,6 +15,5 @@ cilium: enableIPv4Masquerade: false enableIPv6Masquerade: false enableIdentityMark: false - enableRuntimeDeviceDetection: true forceDeviceDetection: true devices: "ovn0 genev_sys_6081" diff --git a/packages/system/cilium/values.yaml b/packages/system/cilium/values.yaml index abc36f51..9aba7cb9 100644 --- a/packages/system/cilium/values.yaml +++ b/packages/system/cilium/values.yaml @@ -10,11 +10,16 @@ cilium: enabled: true loadBalancer: algorithm: maglev + serviceTopology: true ipam: mode: "kubernetes" image: repository: ghcr.io/cozystack/cozystack/cilium - tag: 1.17.4 - digest: "sha256:91f628cbdc4652b4459af79c5a0501282cc0bc0a9fc11e3d8cb65e884f94e751" + tag: 1.19.3 + digest: "sha256:700f06f4803a838a8e830be5ace4650e3ad82bdefabfb2f4d110368d307a5efb" envoy: enabled: false + rollOutCiliumPods: true + operator: + rollOutPods: true + replicas: 1 diff --git a/packages/system/clickhouse-operator/Makefile b/packages/system/clickhouse-operator/Makefile index e821b664..289631d6 100644 --- a/packages/system/clickhouse-operator/Makefile +++ b/packages/system/clickhouse-operator/Makefile @@ -1,7 +1,7 @@ export NAME=clickhouse-operator export NAMESPACE=cozy-clickhouse-operator -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/Chart.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/Chart.yaml index be7fe0c1..f68e1701 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/Chart.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/Chart.yaml @@ -1,11 +1,12 @@ apiVersion: v2 -appVersion: 0.23.4 +appVersion: 0.25.2 description: 'Helm chart to deploy [altinity-clickhouse-operator](https://github.com/Altinity/clickhouse-operator). The ClickHouse Operator creates, configures and manages ClickHouse clusters running on Kubernetes. For upgrade please install CRDs separately: ```bash kubectl apply - -f https://github.com/Altinity/clickhouse-operator/raw/master/deploy/helm/crds/CustomResourceDefinition-clickhouseinstallations.clickhouse.altinity.com.yaml kubectl - apply -f https://github.com/Altinity/clickhouse-operator/raw/master/deploy/helm/crds/CustomResourceDefinition-clickhouseinstallationtemplates.clickhouse.altinity.com.yaml kubectl - apply -f https://github.com/Altinity/clickhouse-operator/raw/master/deploy/helm/crds/CustomResourceDefinition-clickhouseoperatorconfigurations.clickhouse.altinity.com.yaml + -f https://github.com/Altinity/clickhouse-operator/raw/master/deploy/helm/clickhouse-operator/crds/CustomResourceDefinition-clickhouseinstallations.clickhouse.altinity.com.yaml kubectl + apply -f https://github.com/Altinity/clickhouse-operator/raw/master/deploy/helm/clickhouse-operator/crds/CustomResourceDefinition-clickhouseinstallationtemplates.clickhouse.altinity.com.yaml kubectl + apply -f https://github.com/Altinity/clickhouse-operator/raw/master/deploy/helm/clickhouse-operator/crds/CustomResourceDefinition-clickhouseoperatorconfigurations.clickhouse.altinity.com.yaml kubectl + apply -f https://github.com/Altinity/clickhouse-operator/raw/master/deploy/helm/clickhouse-operator/crds/CustomResourceDefinition-clickhousekeeperinstallations.clickhouse-keeper.altinity.com.yaml ```' home: https://github.com/Altinity/clickhouse-operator icon: https://logosandtypes.com/wp-content/uploads/2020/12/altinity.svg @@ -14,4 +15,4 @@ maintainers: name: altinity name: altinity-clickhouse-operator type: application -version: 0.23.4 +version: 0.25.2 diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/README.md b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/README.md index d81cc7ca..e4a1ad68 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/README.md +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/README.md @@ -1,6 +1,6 @@ # altinity-clickhouse-operator -![Version: 0.23.4](https://img.shields.io/badge/Version-0.23.4-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.23.4](https://img.shields.io/badge/AppVersion-0.23.4-informational?style=flat-square) +![Version: 0.25.2](https://img.shields.io/badge/Version-0.25.2-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.25.2](https://img.shields.io/badge/AppVersion-0.25.2-informational?style=flat-square) Helm chart to deploy [altinity-clickhouse-operator](https://github.com/Altinity/clickhouse-operator). @@ -8,9 +8,10 @@ The ClickHouse Operator creates, configures and manages ClickHouse clusters runn For upgrade please install CRDs separately: ```bash - kubectl apply -f https://github.com/Altinity/clickhouse-operator/raw/master/deploy/helm/crds/CustomResourceDefinition-clickhouseinstallations.clickhouse.altinity.com.yaml - kubectl apply -f https://github.com/Altinity/clickhouse-operator/raw/master/deploy/helm/crds/CustomResourceDefinition-clickhouseinstallationtemplates.clickhouse.altinity.com.yaml - kubectl apply -f https://github.com/Altinity/clickhouse-operator/raw/master/deploy/helm/crds/CustomResourceDefinition-clickhouseoperatorconfigurations.clickhouse.altinity.com.yaml + kubectl apply -f https://github.com/Altinity/clickhouse-operator/raw/master/deploy/helm/clickhouse-operator/crds/CustomResourceDefinition-clickhouseinstallations.clickhouse.altinity.com.yaml + kubectl apply -f https://github.com/Altinity/clickhouse-operator/raw/master/deploy/helm/clickhouse-operator/crds/CustomResourceDefinition-clickhouseinstallationtemplates.clickhouse.altinity.com.yaml + kubectl apply -f https://github.com/Altinity/clickhouse-operator/raw/master/deploy/helm/clickhouse-operator/crds/CustomResourceDefinition-clickhouseoperatorconfigurations.clickhouse.altinity.com.yaml + kubectl apply -f https://github.com/Altinity/clickhouse-operator/raw/master/deploy/helm/clickhouse-operator/crds/CustomResourceDefinition-clickhousekeeperinstallations.clickhouse-keeper.altinity.com.yaml ``` **Homepage:** @@ -25,34 +26,38 @@ For upgrade please install CRDs separately: | Key | Type | Default | Description | |-----|------|---------|-------------| -| additionalResources | list | `[]` | list of additional resources to create (are processed via `tpl` function), useful for create ClickHouse clusters together with clickhouse-operator, look `kubectl explain chi` for details | -| affinity | object | `{}` | affinity for scheduler pod assignment, look `kubectl explain pod.spec.affinity` for details | -| configs | object | check the values.yaml file for the config content, auto-generated from latest operator release | clickhouse-operator configs | +| additionalResources | list | `[]` | list of additional resources to create (processed via `tpl` function), useful for create ClickHouse clusters together with clickhouse-operator. check `kubectl explain chi` for details | +| affinity | object | `{}` | affinity for scheduler pod assignment, check `kubectl explain pod.spec.affinity` for details | +| commonAnnotations | object | `{}` | set of annotations that will be applied to all the resources for the operator | +| commonLabels | object | `{}` | set of labels that will be applied to all the resources for the operator | +| configs | object | check the `values.yaml` file for the config content (auto-generated from latest operator release) | clickhouse operator configs | | dashboards.additionalLabels | object | `{"grafana_dashboard":""}` | labels to add to a secret with dashboards | | dashboards.annotations | object | `{}` | annotations to add to a secret with dashboards | -| dashboards.enabled | bool | `false` | provision grafana dashboards as secrets (can be synced by grafana dashboards sidecar https://github.com/grafana/helm-charts/blob/grafana-6.33.1/charts/grafana/values.yaml#L679 ) | +| dashboards.enabled | bool | `false` | provision grafana dashboards as configMaps (can be synced by grafana dashboards sidecar https://github.com/grafana/helm-charts/blob/grafana-8.3.4/charts/grafana/values.yaml#L778 ) | | dashboards.grafana_folder | string | `"clickhouse"` | | | fullnameOverride | string | `""` | full name of the chart. | -| imagePullSecrets | list | `[]` | image pull secret for private images in clickhouse-operator pod possible value format [{"name":"your-secret-name"}] look `kubectl explain pod.spec.imagePullSecrets` for details | +| imagePullSecrets | list | `[]` | image pull secret for private images in clickhouse-operator pod possible value format `[{"name":"your-secret-name"}]`, check `kubectl explain pod.spec.imagePullSecrets` for details | | metrics.containerSecurityContext | object | `{}` | | | metrics.enabled | bool | `true` | | -| metrics.env | list | `[]` | additional environment variables for the deployment of metrics-exporter containers possible format value [{"name": "SAMPLE", "value": "text"}] | +| metrics.env | list | `[]` | additional environment variables for the deployment of metrics-exporter containers possible format value `[{"name": "SAMPLE", "value": "text"}]` | | metrics.image.pullPolicy | string | `"IfNotPresent"` | image pull policy | | metrics.image.repository | string | `"altinity/metrics-exporter"` | image repository | | metrics.image.tag | string | `""` | image tag (chart's appVersion value will be used if not set) | | metrics.resources | object | `{}` | custom resource configuration | | nameOverride | string | `""` | override name of the chart | -| nodeSelector | object | `{}` | node for scheduler pod assignment, look `kubectl explain pod.spec.nodeSelector` for details | +| namespaceOverride | string | `""` | | +| nodeSelector | object | `{}` | node for scheduler pod assignment, check `kubectl explain pod.spec.nodeSelector` for details | | operator.containerSecurityContext | object | `{}` | | -| operator.env | list | `[]` | additional environment variables for the clickhouse-operator container in deployment possible format value [{"name": "SAMPLE", "value": "text"}] | +| operator.env | list | `[]` | additional environment variables for the clickhouse-operator container in deployment possible format value `[{"name": "SAMPLE", "value": "text"}]` | | operator.image.pullPolicy | string | `"IfNotPresent"` | image pull policy | | operator.image.repository | string | `"altinity/clickhouse-operator"` | image repository | | operator.image.tag | string | `""` | image tag (chart's appVersion value will be used if not set) | -| operator.resources | object | `{}` | custom resource configuration, look `kubectl explain pod.spec.containers.resources` for details | -| podAnnotations | object | `{"clickhouse-operator-metrics/port":"9999","clickhouse-operator-metrics/scrape":"true","prometheus.io/port":"8888","prometheus.io/scrape":"true"}` | annotations to add to the clickhouse-operator pod, look `kubectl explain pod.spec.annotations` for details | +| operator.resources | object | `{}` | custom resource configuration, check `kubectl explain pod.spec.containers.resources` for details | +| podAnnotations | object | check the `values.yaml` file | annotations to add to the clickhouse-operator pod, check `kubectl explain pod.spec.annotations` for details | | podLabels | object | `{}` | labels to add to the clickhouse-operator pod | | podSecurityContext | object | `{}` | | -| rbac.create | bool | `true` | specifies whether cluster roles and cluster role bindings should be created | +| rbac.create | bool | `true` | specifies whether rbac resources should be created | +| rbac.namespaceScoped | bool | `false` | specifies whether to create roles and rolebindings at the cluster level or namespace level | | secret.create | bool | `true` | create a secret with operator credentials | | secret.password | string | `"clickhouse_operator_password"` | operator credentials password | | secret.username | string | `"clickhouse_operator"` | operator credentials username | @@ -60,6 +65,15 @@ For upgrade please install CRDs separately: | serviceAccount.create | bool | `true` | specifies whether a service account should be created | | serviceAccount.name | string | `nil` | the name of the service account to use; if not set and create is true, a name is generated using the fullname template | | serviceMonitor.additionalLabels | object | `{}` | additional labels for service monitor | -| serviceMonitor.enabled | bool | `false` | ServiceMonitor Custom resource is created for a (prometheus-operator)[https://github.com/prometheus-operator/prometheus-operator] | -| tolerations | list | `[]` | tolerations for scheduler pod assignment, look `kubectl explain pod.spec.tolerations` for details | +| serviceMonitor.clickhouseMetrics.interval | string | `"30s"` | | +| serviceMonitor.clickhouseMetrics.metricRelabelings | list | `[]` | | +| serviceMonitor.clickhouseMetrics.relabelings | list | `[]` | | +| serviceMonitor.clickhouseMetrics.scrapeTimeout | string | `""` | | +| serviceMonitor.enabled | bool | `false` | ServiceMonitor Custom resource is created for a [prometheus-operator](https://github.com/prometheus-operator/prometheus-operator) In serviceMonitor will be created two endpoints clickhouse-metrics on port 8888 and operator-metrics # 9999. Ypu can specify interval, scrapeTimeout, relabelings, metricRelabelings for each endpoint below | +| serviceMonitor.operatorMetrics.interval | string | `"30s"` | | +| serviceMonitor.operatorMetrics.metricRelabelings | list | `[]` | | +| serviceMonitor.operatorMetrics.relabelings | list | `[]` | | +| serviceMonitor.operatorMetrics.scrapeTimeout | string | `""` | | +| tolerations | list | `[]` | tolerations for scheduler pod assignment, check `kubectl explain pod.spec.tolerations` for details | +| topologySpreadConstraints | list | `[]` | | diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/README.md.gotmpl b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/README.md.gotmpl new file mode 100644 index 00000000..8dff3784 --- /dev/null +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/README.md.gotmpl @@ -0,0 +1,17 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.badgesSection" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +{{ template "chart.maintainersSection" . }} + +{{ template "chart.sourcesSection" . }} + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSection" . }} + diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhouseinstallations.clickhouse.altinity.com.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhouseinstallations.clickhouse.altinity.com.yaml index f3eff275..84359a4b 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhouseinstallations.clickhouse.altinity.com.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhouseinstallations.clickhouse.altinity.com.yaml @@ -4,14 +4,14 @@ # SINGULAR=clickhouseinstallation # PLURAL=clickhouseinstallations # SHORT=chi -# OPERATOR_VERSION=0.23.4 +# OPERATOR_VERSION=0.25.2 # apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: clickhouseinstallations.clickhouse.altinity.com labels: - clickhouse.altinity.com/chop: 0.23.4 + clickhouse.altinity.com/chop: 0.25.2 spec: group: clickhouse.altinity.com scope: Namespaced @@ -51,13 +51,12 @@ spec: jsonPath: .status.taskID - name: status type: string - description: CHI status + description: Resource status jsonPath: .status.status - - name: hosts-unchanged + - name: hosts-completed type: integer - description: Unchanged hosts count - priority: 1 # show in wide view - jsonPath: .status.hostsUnchanged + description: Completed hosts count + jsonPath: .status.hostsCompleted - name: hosts-updated type: integer description: Updated hosts count @@ -68,20 +67,11 @@ spec: description: Added hosts count priority: 1 # show in wide view jsonPath: .status.hostsAdded - - name: hosts-completed - type: integer - description: Completed hosts count - jsonPath: .status.hostsCompleted - name: hosts-deleted type: integer description: Hosts deleted count priority: 1 # show in wide view jsonPath: .status.hostsDeleted - - name: hosts-delete - type: integer - description: Hosts to be deleted count - priority: 1 # show in wide view - jsonPath: .status.hostsDelete - name: endpoint type: string description: Client access endpoint @@ -92,39 +82,51 @@ spec: description: Age of the resource # Displayed in all priorities jsonPath: .metadata.creationTimestamp + - name: suspend + type: string + description: Suspend reconciliation + # Displayed in all priorities + jsonPath: .spec.suspend subresources: status: {} schema: openAPIV3Schema: - description: "define a set of Kubernetes resources (StatefulSet, PVC, Service, ConfigMap) which describe behavior one or more ClickHouse clusters" + description: "define a set of Kubernetes resources (StatefulSet, PVC, Service, ConfigMap) which describe behavior one or more clusters" type: object required: - spec 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' + 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' + 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 status: type: object - description: "Current ClickHouseInstallation manifest status, contains many fields like a normalized configuration, clickhouse-operator version, current action and all applied action list, current taskID and all applied taskIDs and other" + description: | + Status contains many fields like a normalized configuration, clickhouse-operator version, current action and all applied action list, current taskID and all applied taskIDs and other properties: chop-version: type: string - description: "ClickHouse operator version" + description: "Operator version" chop-commit: type: string - description: "ClickHouse operator git commit SHA" + description: "Operator git commit SHA" chop-date: type: string - description: "ClickHouse operator build date" + description: "Operator build date" chop-ip: type: string - description: "IP address of the operator's pod which managed this CHI" + description: "IP address of the operator's pod which managed this resource" clusters: type: integer minimum: 0 @@ -222,17 +224,23 @@ spec: endpoint: type: string description: "Endpoint" + endpoints: + type: array + description: "All endpoints" + nullable: true + items: + type: string generation: type: integer minimum: 0 description: "Generation" normalized: type: object - description: "Normalized CHI requested" + description: "Normalized resource requested" x-kubernetes-preserve-unknown-fields: true normalizedCompleted: type: object - description: "Normalized CHI completed" + description: "Normalized resource completed" x-kubernetes-preserve-unknown-fields: true hostsWithTablesCreated: type: array @@ -240,6 +248,12 @@ spec: nullable: true items: type: string + hostsWithReplicaCaughtUp: + type: array + description: "List of hosts with replica caught up" + nullable: true + items: + type: string usedTemplates: type: array description: "List of templates used to build this CHI" @@ -301,6 +315,13 @@ spec: enum: - "" - "RollingUpdate" + suspend: + !!merge <<: *TypeStringBool + description: | + Suspend reconciliation of resources managed by a ClickHouse Installation. + Works as the following: + - When `suspend` is `true` operator stops reconciling all resources. + - When `suspend` is `false` or not set, operator reconciles all resources. troubleshoot: !!merge <<: *TypeStringBool description: | @@ -412,6 +433,63 @@ spec: service: !!merge <<: *TypeObjectsCleanup description: "Behavior policy for failed Service, `Retain` by default" + runtime: + type: object + description: "runtime parameters for clickhouse-operator process which are used during reconcile cycle" + properties: + reconcileShardsThreadsNumber: + type: integer + minimum: 1 + maximum: 65535 + description: "How many goroutines will be used to reconcile shards of a cluster in parallel, 1 by default" + reconcileShardsMaxConcurrencyPercent: + type: integer + minimum: 0 + maximum: 100 + description: "The maximum percentage of cluster shards that may be reconciled in parallel, 50 percent by default." + macros: + type: object + description: "macros parameters" + properties: + sections: + type: object + description: "sections behaviour for macros" + properties: + users: + type: object + description: "sections behaviour for macros on users" + properties: + enabled: + !!merge <<: *TypeStringBool + description: "enabled or not" + profiles: + type: object + description: "sections behaviour for macros on profiles" + properties: + enabled: + !!merge <<: *TypeStringBool + description: "enabled or not" + quotas: + type: object + description: "sections behaviour for macros on quotas" + properties: + enabled: + !!merge <<: *TypeStringBool + description: "enabled or not" + settings: + type: object + description: "sections behaviour for macros on settings" + properties: + enabled: + !!merge <<: *TypeStringBool + description: "enabled or not" + files: + type: object + description: "sections behaviour for macros on files" + properties: + enabled: + !!merge <<: *TypeStringBool + description: "enabled or not" defaults: type: object description: | @@ -424,7 +502,7 @@ spec: description: | define should replicas be specified by FQDN in ``. In case of "no" will use short hostname and clickhouse-server will use kubernetes default suffixes for DNS lookup - "yes" by default + "no" by default distributedDDL: type: object description: | @@ -474,7 +552,13 @@ spec: description: "optional, template name from chi.spec.templates.volumeClaimTemplates, allows customization each `PVC` which will mount for clickhouse log directory in each `Pod` during render and reconcile every StatefulSet.spec resource described in `chi.spec.configuration.clusters`" serviceTemplate: type: string - description: "optional, template name from chi.spec.templates.serviceTemplates, allows customization for one `Service` resource which will created by `clickhouse-operator` which cover all clusters in whole `chi` resource" + description: "optional, template name from chi.spec.templates.serviceTemplates. used for customization of the `Service` resource, created by `clickhouse-operator` to cover all clusters in whole `chi` resource" + serviceTemplates: + type: array + description: "optional, template names from chi.spec.templates.serviceTemplates. used for customization of the `Service` resources, created by `clickhouse-operator` to cover all clusters in whole `chi` resource" + nullable: true + items: + type: string clusterServiceTemplate: type: string description: "optional, template name from chi.spec.templates.serviceTemplates, allows customization for each `Service` resource which will created by `clickhouse-operator` which cover each clickhouse cluster described in `chi.spec.configuration.clusters`" @@ -486,7 +570,7 @@ spec: description: "optional, template name from chi.spec.templates.serviceTemplates, allows customization for each `Service` resource which will created by `clickhouse-operator` which cover each replica inside each shard inside each clickhouse cluster described in `chi.spec.configuration.clusters`" volumeClaimTemplate: type: string - description: "DEPRECATED! VolumeClaimTemplate is deprecated in favor of DataVolumeClaimTemplate and LogVolumeClaimTemplate" + description: "optional, alias for dataVolumeClaimTemplate, template name from chi.spec.templates.volumeClaimTemplates, allows customization each `PVC` which will mount for clickhouse data directory in each `Pod` during render and reconcile every StatefulSet.spec resource described in `chi.spec.configuration.clusters`" configuration: type: object description: "allows configure multiple aspects and behavior for `clickhouse-server` instance and also allows describe multiple `clickhouse-server` clusters inside one `chi` resource" @@ -521,6 +605,9 @@ spec: secure: !!merge <<: *TypeStringBool description: "if a secure connection to Zookeeper is required" + availabilityZone: + type: string + description: "availability zone for Zookeeper node" session_timeout_ms: type: integer description: "session timeout during connect to Zookeeper" @@ -540,6 +627,20 @@ spec: you can configure password hashed, authorization restrictions, database level security row filters etc. More details: https://clickhouse.tech/docs/en/operations/settings/settings-users/ Your yaml code will convert to XML, see examples https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md#specconfigurationusers + + any key could contains `valueFrom` with `secretKeyRef` which allow pass password from kubernetes secrets + secret value will pass in `pod.spec.containers.evn`, and generate with from_env=XXX in XML in /etc/clickhouse-server/users.d/chop-generated-users.xml + it not allow automatically updates when updates `secret`, change spec.taskID for manually trigger reconcile cycle + + look into https://github.com/Altinity/clickhouse-operator/blob/master/docs/chi-examples/05-settings-01-overview.yaml for examples + + any key with prefix `k8s_secret_` shall has value with format namespace/secret/key or secret/key + in this case value from secret will write directly into XML tag during render *-usersd ConfigMap + + any key with prefix `k8s_secret_env` shall has value with format namespace/secret/key or secret/key + in this case value from secret will write into environment variable and write to XML tag via from_env=XXX + + look into https://github.com/Altinity/clickhouse-operator/blob/master/docs/chi-examples/05-settings-01-overview.yaml for examples # nullable: true x-kubernetes-preserve-unknown-fields: true profiles: @@ -566,6 +667,12 @@ spec: allows configure `clickhouse-server` settings inside ... tag in each `Pod` during generate `ConfigMap` which will mount in `/etc/clickhouse-server/config.d/` More details: https://clickhouse.tech/docs/en/operations/settings/settings/ Your yaml code will convert to XML, see examples https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md#specconfigurationsettings + + any key could contains `valueFrom` with `secretKeyRef` which allow pass password from kubernetes secrets + look into https://github.com/Altinity/clickhouse-operator/blob/master/docs/chi-examples/05-settings-01-overview.yaml for examples + + secret value will pass in `pod.spec.env`, and generate with from_env=XXX in XML in /etc/clickhouse-server/config.d/chop-generated-settings.xml + it not allow automatically updates when updates `secret`, change spec.taskID for manually trigger reconcile cycle # nullable: true x-kubernetes-preserve-unknown-fields: true files: &TypeFiles @@ -575,14 +682,20 @@ spec: every key in this object is the file name every value in this object is the file content you can use `!!binary |` and base64 for binary files, see details here https://yaml.org/type/binary.html - each key could contains prefix like USERS, COMMON, HOST or config.d, users.d, cond.d, wrong prefixes will ignored, subfolders also will ignored + each key could contains prefix like {common}, {users}, {hosts} or config.d, users.d, conf.d, wrong prefixes will be ignored, subfolders also will be ignored More details: https://github.com/Altinity/clickhouse-operator/blob/master/docs/chi-examples/05-settings-05-files-nested.yaml + + any key could contains `valueFrom` with `secretKeyRef` which allow pass values from kubernetes secrets + secrets will mounted into pod as separate volume in /etc/clickhouse-server/secrets.d/ + and will automatically update when update secret + it useful for pass SSL certificates from cert-manager or similar tool + look into https://github.com/Altinity/clickhouse-operator/blob/master/docs/chi-examples/05-settings-01-overview.yaml for examples # nullable: true x-kubernetes-preserve-unknown-fields: true clusters: type: array description: | - describes ClickHouse clusters layout and allows change settings on cluster-level, shard-level and replica-level + describes clusters layout and allows change settings on cluster-level, shard-level and replica-level every cluster is a set of StatefulSet, one StatefulSet contains only one Pod with `clickhouse-server` all Pods will rendered in part of ClickHouse configs, mounted from ConfigMap as `/etc/clickhouse-server/config.d/chop-generated-remote_servers.xml` Clusters will use for Distributed table engine, more details: https://clickhouse.tech/docs/en/engines/table-engines/special/distributed/ @@ -595,7 +708,7 @@ spec: properties: name: type: string - description: "cluster name, used to identify set of ClickHouse servers and wide used during generate names of related Kubernetes resources" + description: "cluster name, used to identify set of servers and wide used during generate names of related Kubernetes resources" minLength: 1 # See namePartClusterMaxLen const maxLength: 15 @@ -683,6 +796,32 @@ spec: required: - name - key + pdbMaxUnavailable: + type: integer + description: | + Pod eviction is allowed if at most "pdbMaxUnavailable" pods are unavailable after the eviction, + i.e. even in absence of the evicted pod. For example, one can prevent all voluntary evictions + by specifying 0. This is a mutually exclusive setting with "minAvailable". + minimum: 0 + maximum: 65535 + reconcile: + type: object + description: "allow tuning reconciling process" + properties: + runtime: + type: object + description: "runtime parameters for clickhouse-operator process which are used during reconcile cycle" + properties: + reconcileShardsThreadsNumber: + type: integer + minimum: 1 + maximum: 65535 + description: "How many goroutines will be used to reconcile shards of a cluster in parallel, 1 by default" + reconcileShardsMaxConcurrencyPercent: + type: integer + minimum: 0 + maximum: 100 + description: "The maximum percentage of cluster shards that may be reconciled in parallel, 50 percent by default." layout: type: object description: | @@ -690,18 +829,24 @@ spec: allows override settings on each shard and replica separatelly # nullable: true properties: - type: - type: string - description: "DEPRECATED - to be removed soon" shardsCount: type: integer - description: "how much shards for current ClickHouse cluster will run in Kubernetes, each shard contains shared-nothing part of data and contains set of replicas, cluster contains 1 shard by default" + description: | + how much shards for current ClickHouse cluster will run in Kubernetes, + each shard contains shared-nothing part of data and contains set of replicas, + cluster contains 1 shard by default" replicasCount: type: integer - description: "how much replicas in each shards for current ClickHouse cluster will run in Kubernetes, each replica is a separate `StatefulSet` which contains only one `Pod` with `clickhouse-server` instance, every shard contains 1 replica by default" + description: | + how much replicas in each shards for current cluster will run in Kubernetes, + each replica is a separate `StatefulSet` which contains only one `Pod` with `clickhouse-server` instance, + every shard contains 1 replica by default" shards: type: array - description: "optional, allows override top-level `chi.spec.configuration`, cluster-level `chi.spec.configuration.clusters` settings for each shard separately, use it only if you fully understand what you do" + description: | + optional, allows override top-level `chi.spec.configuration`, cluster-level + `chi.spec.configuration.clusters` settings for each shard separately, + use it only if you fully understand what you do" # nullable: true items: type: object @@ -1036,7 +1181,7 @@ spec: description: "template name, could use to link inside top-level `chi.spec.defaults.templates.podTemplate`, cluster-level `chi.spec.configuration.clusters.templates.podTemplate`, shard-level `chi.spec.configuration.clusters.layout.shards.temlates.podTemplate`, replica-level `chi.spec.configuration.clusters.layout.replicas.templates.podTemplate`" generateName: type: string - description: "allows define format for generated `Pod` name, look to https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md#spectemplatesservicetemplates for details about aviailable template variables" + description: "allows define format for generated `Pod` name, look to https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md#spectemplatesservicetemplates for details about available template variables" zone: type: object description: "allows define custom zone name and will separate ClickHouse `Pods` between nodes, shortcut for `chi.spec.templates.podTemplates.spec.affinity.podAntiAffinity`" @@ -1108,7 +1253,9 @@ spec: maximum: 65535 topologyKey: type: string - description: "use for inter-pod affinity look to `pod.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution.podAffinityTerm.topologyKey`, More info: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity" + description: | + use for inter-pod affinity look to `pod.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution.podAffinityTerm.topologyKey`, + more info: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity" metadata: type: object description: | @@ -1124,7 +1271,8 @@ spec: x-kubernetes-preserve-unknown-fields: true volumeClaimTemplates: type: array - description: "allows define template for rendering `PVC` kubernetes resource, which would use inside `Pod` for mount clickhouse `data`, clickhouse `logs` or something else" + description: | + allows define template for rendering `PVC` kubernetes resource, which would use inside `Pod` for mount clickhouse `data`, clickhouse `logs` or something else # nullable: true items: type: object @@ -1177,14 +1325,17 @@ spec: replica-level `chi.spec.configuration.clusters.layout.replicas.templates.replicaServiceTemplate` or `chi.spec.configuration.clusters.layout.shards.replicas.replicaServiceTemplate` generateName: type: string - description: "allows define format for generated `Service` name, look to https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md#spectemplatesservicetemplates for details about aviailable template variables" + description: | + allows define format for generated `Service` name, + look to https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md#spectemplatesservicetemplates + for details about available template variables" metadata: # TODO specify ObjectMeta type: object description: | allows pass standard object's metadata from template to Service Could be use for define specificly for Cloud Provider metadata which impact to behavior of service - More info: https://kubernetes.io/docs/concepts/services-networking/service/ + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata # nullable: true x-kubernetes-preserve-unknown-fields: true spec: @@ -1197,7 +1348,9 @@ spec: x-kubernetes-preserve-unknown-fields: true useTemplates: type: array - description: "list of `ClickHouseInstallationTemplate` (chit) resource names which will merge with current `Chi` manifest during render Kubernetes resources to create related ClickHouse clusters" + description: | + list of `ClickHouseInstallationTemplate` (chit) resource names which will merge with current `CHI` + manifest during render Kubernetes resources to create related ClickHouse clusters" # nullable: true items: type: object diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhouseinstallationtemplates.clickhouse.altinity.com.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhouseinstallationtemplates.clickhouse.altinity.com.yaml index d8ef8ba5..0d7dab1a 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhouseinstallationtemplates.clickhouse.altinity.com.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhouseinstallationtemplates.clickhouse.altinity.com.yaml @@ -4,14 +4,14 @@ # SINGULAR=clickhouseinstallationtemplate # PLURAL=clickhouseinstallationtemplates # SHORT=chit -# OPERATOR_VERSION=0.23.4 +# OPERATOR_VERSION=0.25.2 # apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: clickhouseinstallationtemplates.clickhouse.altinity.com labels: - clickhouse.altinity.com/chop: 0.23.4 + clickhouse.altinity.com/chop: 0.25.2 spec: group: clickhouse.altinity.com scope: Namespaced @@ -51,13 +51,12 @@ spec: jsonPath: .status.taskID - name: status type: string - description: CHI status + description: Resource status jsonPath: .status.status - - name: hosts-unchanged + - name: hosts-completed type: integer - description: Unchanged hosts count - priority: 1 # show in wide view - jsonPath: .status.hostsUnchanged + description: Completed hosts count + jsonPath: .status.hostsCompleted - name: hosts-updated type: integer description: Updated hosts count @@ -68,20 +67,11 @@ spec: description: Added hosts count priority: 1 # show in wide view jsonPath: .status.hostsAdded - - name: hosts-completed - type: integer - description: Completed hosts count - jsonPath: .status.hostsCompleted - name: hosts-deleted type: integer description: Hosts deleted count priority: 1 # show in wide view jsonPath: .status.hostsDeleted - - name: hosts-delete - type: integer - description: Hosts to be deleted count - priority: 1 # show in wide view - jsonPath: .status.hostsDelete - name: endpoint type: string description: Client access endpoint @@ -92,39 +82,51 @@ spec: description: Age of the resource # Displayed in all priorities jsonPath: .metadata.creationTimestamp + - name: suspend + type: string + description: Suspend reconciliation + # Displayed in all priorities + jsonPath: .spec.suspend subresources: status: {} schema: openAPIV3Schema: - description: "define a set of Kubernetes resources (StatefulSet, PVC, Service, ConfigMap) which describe behavior one or more ClickHouse clusters" + description: "define a set of Kubernetes resources (StatefulSet, PVC, Service, ConfigMap) which describe behavior one or more clusters" type: object required: - spec 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' + 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' + 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 status: type: object - description: "Current ClickHouseInstallation manifest status, contains many fields like a normalized configuration, clickhouse-operator version, current action and all applied action list, current taskID and all applied taskIDs and other" + description: | + Status contains many fields like a normalized configuration, clickhouse-operator version, current action and all applied action list, current taskID and all applied taskIDs and other properties: chop-version: type: string - description: "ClickHouse operator version" + description: "Operator version" chop-commit: type: string - description: "ClickHouse operator git commit SHA" + description: "Operator git commit SHA" chop-date: type: string - description: "ClickHouse operator build date" + description: "Operator build date" chop-ip: type: string - description: "IP address of the operator's pod which managed this CHI" + description: "IP address of the operator's pod which managed this resource" clusters: type: integer minimum: 0 @@ -222,17 +224,23 @@ spec: endpoint: type: string description: "Endpoint" + endpoints: + type: array + description: "All endpoints" + nullable: true + items: + type: string generation: type: integer minimum: 0 description: "Generation" normalized: type: object - description: "Normalized CHI requested" + description: "Normalized resource requested" x-kubernetes-preserve-unknown-fields: true normalizedCompleted: type: object - description: "Normalized CHI completed" + description: "Normalized resource completed" x-kubernetes-preserve-unknown-fields: true hostsWithTablesCreated: type: array @@ -240,6 +248,12 @@ spec: nullable: true items: type: string + hostsWithReplicaCaughtUp: + type: array + description: "List of hosts with replica caught up" + nullable: true + items: + type: string usedTemplates: type: array description: "List of templates used to build this CHI" @@ -301,6 +315,13 @@ spec: enum: - "" - "RollingUpdate" + suspend: + !!merge <<: *TypeStringBool + description: | + Suspend reconciliation of resources managed by a ClickHouse Installation. + Works as the following: + - When `suspend` is `true` operator stops reconciling all resources. + - When `suspend` is `false` or not set, operator reconciles all resources. troubleshoot: !!merge <<: *TypeStringBool description: | @@ -412,6 +433,63 @@ spec: service: !!merge <<: *TypeObjectsCleanup description: "Behavior policy for failed Service, `Retain` by default" + runtime: + type: object + description: "runtime parameters for clickhouse-operator process which are used during reconcile cycle" + properties: + reconcileShardsThreadsNumber: + type: integer + minimum: 1 + maximum: 65535 + description: "How many goroutines will be used to reconcile shards of a cluster in parallel, 1 by default" + reconcileShardsMaxConcurrencyPercent: + type: integer + minimum: 0 + maximum: 100 + description: "The maximum percentage of cluster shards that may be reconciled in parallel, 50 percent by default." + macros: + type: object + description: "macros parameters" + properties: + sections: + type: object + description: "sections behaviour for macros" + properties: + users: + type: object + description: "sections behaviour for macros on users" + properties: + enabled: + !!merge <<: *TypeStringBool + description: "enabled or not" + profiles: + type: object + description: "sections behaviour for macros on profiles" + properties: + enabled: + !!merge <<: *TypeStringBool + description: "enabled or not" + quotas: + type: object + description: "sections behaviour for macros on quotas" + properties: + enabled: + !!merge <<: *TypeStringBool + description: "enabled or not" + settings: + type: object + description: "sections behaviour for macros on settings" + properties: + enabled: + !!merge <<: *TypeStringBool + description: "enabled or not" + files: + type: object + description: "sections behaviour for macros on files" + properties: + enabled: + !!merge <<: *TypeStringBool + description: "enabled or not" defaults: type: object description: | @@ -424,7 +502,7 @@ spec: description: | define should replicas be specified by FQDN in ``. In case of "no" will use short hostname and clickhouse-server will use kubernetes default suffixes for DNS lookup - "yes" by default + "no" by default distributedDDL: type: object description: | @@ -474,7 +552,13 @@ spec: description: "optional, template name from chi.spec.templates.volumeClaimTemplates, allows customization each `PVC` which will mount for clickhouse log directory in each `Pod` during render and reconcile every StatefulSet.spec resource described in `chi.spec.configuration.clusters`" serviceTemplate: type: string - description: "optional, template name from chi.spec.templates.serviceTemplates, allows customization for one `Service` resource which will created by `clickhouse-operator` which cover all clusters in whole `chi` resource" + description: "optional, template name from chi.spec.templates.serviceTemplates. used for customization of the `Service` resource, created by `clickhouse-operator` to cover all clusters in whole `chi` resource" + serviceTemplates: + type: array + description: "optional, template names from chi.spec.templates.serviceTemplates. used for customization of the `Service` resources, created by `clickhouse-operator` to cover all clusters in whole `chi` resource" + nullable: true + items: + type: string clusterServiceTemplate: type: string description: "optional, template name from chi.spec.templates.serviceTemplates, allows customization for each `Service` resource which will created by `clickhouse-operator` which cover each clickhouse cluster described in `chi.spec.configuration.clusters`" @@ -486,7 +570,7 @@ spec: description: "optional, template name from chi.spec.templates.serviceTemplates, allows customization for each `Service` resource which will created by `clickhouse-operator` which cover each replica inside each shard inside each clickhouse cluster described in `chi.spec.configuration.clusters`" volumeClaimTemplate: type: string - description: "DEPRECATED! VolumeClaimTemplate is deprecated in favor of DataVolumeClaimTemplate and LogVolumeClaimTemplate" + description: "optional, alias for dataVolumeClaimTemplate, template name from chi.spec.templates.volumeClaimTemplates, allows customization each `PVC` which will mount for clickhouse data directory in each `Pod` during render and reconcile every StatefulSet.spec resource described in `chi.spec.configuration.clusters`" configuration: type: object description: "allows configure multiple aspects and behavior for `clickhouse-server` instance and also allows describe multiple `clickhouse-server` clusters inside one `chi` resource" @@ -521,6 +605,9 @@ spec: secure: !!merge <<: *TypeStringBool description: "if a secure connection to Zookeeper is required" + availabilityZone: + type: string + description: "availability zone for Zookeeper node" session_timeout_ms: type: integer description: "session timeout during connect to Zookeeper" @@ -540,6 +627,20 @@ spec: you can configure password hashed, authorization restrictions, database level security row filters etc. More details: https://clickhouse.tech/docs/en/operations/settings/settings-users/ Your yaml code will convert to XML, see examples https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md#specconfigurationusers + + any key could contains `valueFrom` with `secretKeyRef` which allow pass password from kubernetes secrets + secret value will pass in `pod.spec.containers.evn`, and generate with from_env=XXX in XML in /etc/clickhouse-server/users.d/chop-generated-users.xml + it not allow automatically updates when updates `secret`, change spec.taskID for manually trigger reconcile cycle + + look into https://github.com/Altinity/clickhouse-operator/blob/master/docs/chi-examples/05-settings-01-overview.yaml for examples + + any key with prefix `k8s_secret_` shall has value with format namespace/secret/key or secret/key + in this case value from secret will write directly into XML tag during render *-usersd ConfigMap + + any key with prefix `k8s_secret_env` shall has value with format namespace/secret/key or secret/key + in this case value from secret will write into environment variable and write to XML tag via from_env=XXX + + look into https://github.com/Altinity/clickhouse-operator/blob/master/docs/chi-examples/05-settings-01-overview.yaml for examples # nullable: true x-kubernetes-preserve-unknown-fields: true profiles: @@ -566,6 +667,12 @@ spec: allows configure `clickhouse-server` settings inside ... tag in each `Pod` during generate `ConfigMap` which will mount in `/etc/clickhouse-server/config.d/` More details: https://clickhouse.tech/docs/en/operations/settings/settings/ Your yaml code will convert to XML, see examples https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md#specconfigurationsettings + + any key could contains `valueFrom` with `secretKeyRef` which allow pass password from kubernetes secrets + look into https://github.com/Altinity/clickhouse-operator/blob/master/docs/chi-examples/05-settings-01-overview.yaml for examples + + secret value will pass in `pod.spec.env`, and generate with from_env=XXX in XML in /etc/clickhouse-server/config.d/chop-generated-settings.xml + it not allow automatically updates when updates `secret`, change spec.taskID for manually trigger reconcile cycle # nullable: true x-kubernetes-preserve-unknown-fields: true files: &TypeFiles @@ -575,14 +682,20 @@ spec: every key in this object is the file name every value in this object is the file content you can use `!!binary |` and base64 for binary files, see details here https://yaml.org/type/binary.html - each key could contains prefix like USERS, COMMON, HOST or config.d, users.d, cond.d, wrong prefixes will ignored, subfolders also will ignored + each key could contains prefix like {common}, {users}, {hosts} or config.d, users.d, conf.d, wrong prefixes will be ignored, subfolders also will be ignored More details: https://github.com/Altinity/clickhouse-operator/blob/master/docs/chi-examples/05-settings-05-files-nested.yaml + + any key could contains `valueFrom` with `secretKeyRef` which allow pass values from kubernetes secrets + secrets will mounted into pod as separate volume in /etc/clickhouse-server/secrets.d/ + and will automatically update when update secret + it useful for pass SSL certificates from cert-manager or similar tool + look into https://github.com/Altinity/clickhouse-operator/blob/master/docs/chi-examples/05-settings-01-overview.yaml for examples # nullable: true x-kubernetes-preserve-unknown-fields: true clusters: type: array description: | - describes ClickHouse clusters layout and allows change settings on cluster-level, shard-level and replica-level + describes clusters layout and allows change settings on cluster-level, shard-level and replica-level every cluster is a set of StatefulSet, one StatefulSet contains only one Pod with `clickhouse-server` all Pods will rendered in part of ClickHouse configs, mounted from ConfigMap as `/etc/clickhouse-server/config.d/chop-generated-remote_servers.xml` Clusters will use for Distributed table engine, more details: https://clickhouse.tech/docs/en/engines/table-engines/special/distributed/ @@ -595,7 +708,7 @@ spec: properties: name: type: string - description: "cluster name, used to identify set of ClickHouse servers and wide used during generate names of related Kubernetes resources" + description: "cluster name, used to identify set of servers and wide used during generate names of related Kubernetes resources" minLength: 1 # See namePartClusterMaxLen const maxLength: 15 @@ -683,6 +796,32 @@ spec: required: - name - key + pdbMaxUnavailable: + type: integer + description: | + Pod eviction is allowed if at most "pdbMaxUnavailable" pods are unavailable after the eviction, + i.e. even in absence of the evicted pod. For example, one can prevent all voluntary evictions + by specifying 0. This is a mutually exclusive setting with "minAvailable". + minimum: 0 + maximum: 65535 + reconcile: + type: object + description: "allow tuning reconciling process" + properties: + runtime: + type: object + description: "runtime parameters for clickhouse-operator process which are used during reconcile cycle" + properties: + reconcileShardsThreadsNumber: + type: integer + minimum: 1 + maximum: 65535 + description: "How many goroutines will be used to reconcile shards of a cluster in parallel, 1 by default" + reconcileShardsMaxConcurrencyPercent: + type: integer + minimum: 0 + maximum: 100 + description: "The maximum percentage of cluster shards that may be reconciled in parallel, 50 percent by default." layout: type: object description: | @@ -690,18 +829,24 @@ spec: allows override settings on each shard and replica separatelly # nullable: true properties: - type: - type: string - description: "DEPRECATED - to be removed soon" shardsCount: type: integer - description: "how much shards for current ClickHouse cluster will run in Kubernetes, each shard contains shared-nothing part of data and contains set of replicas, cluster contains 1 shard by default" + description: | + how much shards for current ClickHouse cluster will run in Kubernetes, + each shard contains shared-nothing part of data and contains set of replicas, + cluster contains 1 shard by default" replicasCount: type: integer - description: "how much replicas in each shards for current ClickHouse cluster will run in Kubernetes, each replica is a separate `StatefulSet` which contains only one `Pod` with `clickhouse-server` instance, every shard contains 1 replica by default" + description: | + how much replicas in each shards for current cluster will run in Kubernetes, + each replica is a separate `StatefulSet` which contains only one `Pod` with `clickhouse-server` instance, + every shard contains 1 replica by default" shards: type: array - description: "optional, allows override top-level `chi.spec.configuration`, cluster-level `chi.spec.configuration.clusters` settings for each shard separately, use it only if you fully understand what you do" + description: | + optional, allows override top-level `chi.spec.configuration`, cluster-level + `chi.spec.configuration.clusters` settings for each shard separately, + use it only if you fully understand what you do" # nullable: true items: type: object @@ -1036,7 +1181,7 @@ spec: description: "template name, could use to link inside top-level `chi.spec.defaults.templates.podTemplate`, cluster-level `chi.spec.configuration.clusters.templates.podTemplate`, shard-level `chi.spec.configuration.clusters.layout.shards.temlates.podTemplate`, replica-level `chi.spec.configuration.clusters.layout.replicas.templates.podTemplate`" generateName: type: string - description: "allows define format for generated `Pod` name, look to https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md#spectemplatesservicetemplates for details about aviailable template variables" + description: "allows define format for generated `Pod` name, look to https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md#spectemplatesservicetemplates for details about available template variables" zone: type: object description: "allows define custom zone name and will separate ClickHouse `Pods` between nodes, shortcut for `chi.spec.templates.podTemplates.spec.affinity.podAntiAffinity`" @@ -1108,7 +1253,9 @@ spec: maximum: 65535 topologyKey: type: string - description: "use for inter-pod affinity look to `pod.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution.podAffinityTerm.topologyKey`, More info: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity" + description: | + use for inter-pod affinity look to `pod.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution.podAffinityTerm.topologyKey`, + more info: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity" metadata: type: object description: | @@ -1124,7 +1271,8 @@ spec: x-kubernetes-preserve-unknown-fields: true volumeClaimTemplates: type: array - description: "allows define template for rendering `PVC` kubernetes resource, which would use inside `Pod` for mount clickhouse `data`, clickhouse `logs` or something else" + description: | + allows define template for rendering `PVC` kubernetes resource, which would use inside `Pod` for mount clickhouse `data`, clickhouse `logs` or something else # nullable: true items: type: object @@ -1177,14 +1325,17 @@ spec: replica-level `chi.spec.configuration.clusters.layout.replicas.templates.replicaServiceTemplate` or `chi.spec.configuration.clusters.layout.shards.replicas.replicaServiceTemplate` generateName: type: string - description: "allows define format for generated `Service` name, look to https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md#spectemplatesservicetemplates for details about aviailable template variables" + description: | + allows define format for generated `Service` name, + look to https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md#spectemplatesservicetemplates + for details about available template variables" metadata: # TODO specify ObjectMeta type: object description: | allows pass standard object's metadata from template to Service Could be use for define specificly for Cloud Provider metadata which impact to behavior of service - More info: https://kubernetes.io/docs/concepts/services-networking/service/ + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata # nullable: true x-kubernetes-preserve-unknown-fields: true spec: @@ -1197,7 +1348,9 @@ spec: x-kubernetes-preserve-unknown-fields: true useTemplates: type: array - description: "list of `ClickHouseInstallationTemplate` (chit) resource names which will merge with current `Chi` manifest during render Kubernetes resources to create related ClickHouse clusters" + description: | + list of `ClickHouseInstallationTemplate` (chit) resource names which will merge with current `CHI` + manifest during render Kubernetes resources to create related ClickHouse clusters" # nullable: true items: type: object diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhousekeeperinstallations.clickhouse-keeper.altinity.com.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhousekeeperinstallations.clickhouse-keeper.altinity.com.yaml index 07fdeca3..4581ff39 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhousekeeperinstallations.clickhouse-keeper.altinity.com.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhousekeeperinstallations.clickhouse-keeper.altinity.com.yaml @@ -1,13 +1,13 @@ # Template Parameters: # -# OPERATOR_VERSION=0.23.4 +# OPERATOR_VERSION=0.25.2 # apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: clickhousekeeperinstallations.clickhouse-keeper.altinity.com labels: - clickhouse-keeper.altinity.com/chop: 0.23.4 + clickhouse-keeper.altinity.com/chop: 0.25.2 spec: group: clickhouse-keeper.altinity.com scope: Namespaced @@ -22,123 +22,487 @@ spec: served: true storage: true additionalPrinterColumns: + - name: version + type: string + description: Operator version + priority: 1 # show in wide view + jsonPath: .status.chop-version + - name: clusters + type: integer + description: Clusters count + jsonPath: .status.clusters + - name: shards + type: integer + description: Shards count + priority: 1 # show in wide view + jsonPath: .status.shards + - name: hosts + type: integer + description: Hosts count + jsonPath: .status.hosts + - name: taskID + type: string + description: TaskID + priority: 1 # show in wide view + jsonPath: .status.taskID - name: status type: string - description: CHK status + description: Resource status jsonPath: .status.status - - name: replicas + - name: hosts-unchanged type: integer - description: Replica count + description: Unchanged hosts count priority: 1 # show in wide view - jsonPath: .status.replicas + jsonPath: .status.hostsUnchanged + - name: hosts-updated + type: integer + description: Updated hosts count + priority: 1 # show in wide view + jsonPath: .status.hostsUpdated + - name: hosts-added + type: integer + description: Added hosts count + priority: 1 # show in wide view + jsonPath: .status.hostsAdded + - name: hosts-completed + type: integer + description: Completed hosts count + jsonPath: .status.hostsCompleted + - name: hosts-deleted + type: integer + description: Hosts deleted count + priority: 1 # show in wide view + jsonPath: .status.hostsDeleted + - name: hosts-delete + type: integer + description: Hosts to be deleted count + priority: 1 # show in wide view + jsonPath: .status.hostsDelete + - name: endpoint + type: string + description: Client access endpoint + priority: 1 # show in wide view + jsonPath: .status.endpoint - name: age type: date description: Age of the resource # Displayed in all priorities jsonPath: .metadata.creationTimestamp + - name: suspend + type: string + description: Suspend reconciliation + # Displayed in all priorities + jsonPath: .spec.suspend subresources: status: {} schema: openAPIV3Schema: + description: "define a set of Kubernetes resources (StatefulSet, PVC, Service, ConfigMap) which describe behavior one or more clusters" type: object required: - spec - description: "define a set of Kubernetes resources (StatefulSet, PVC, Service, ConfigMap) which describe behavior one ClickHouse Keeper cluster" properties: apiVersion: - type: string 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 - kind: 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 status: type: object description: | - Current ClickHouseKeeperInstallation status, contains many fields like overall status, desired replicas and ready replica list with their endpoints + Status contains many fields like a normalized configuration, clickhouse-operator version, current action and all applied action list, current taskID and all applied taskIDs and other properties: chop-version: type: string - description: "ClickHouse operator version" + description: "Operator version" chop-commit: type: string - description: "ClickHouse operator git commit SHA" + description: "Operator git commit SHA" chop-date: type: string - description: "ClickHouse operator build date" + description: "Operator build date" chop-ip: type: string - description: "IP address of the operator's pod which managed this CHI" + description: "IP address of the operator's pod which managed this resource" + clusters: + type: integer + minimum: 0 + description: "Clusters count" + shards: + type: integer + minimum: 0 + description: "Shards count" + replicas: + type: integer + minimum: 0 + description: "Replicas count" + hosts: + type: integer + minimum: 0 + description: "Hosts count" status: type: string description: "Status" - replicas: - type: integer - format: int32 - description: Replicas is the number of number of desired replicas in the cluster - readyReplicas: + taskID: + type: string + description: "Current task id" + taskIDsStarted: type: array - description: ReadyReplicas is the array of endpoints of those ready replicas in the cluster + description: "Started task ids" + nullable: true items: - type: object - properties: - host: - type: string - description: dns name or ip address for Keeper node - port: - type: integer - minimum: 0 - maximum: 65535 - description: TCP port which used to connect to Keeper node - secure: - type: string - description: if a secure connection to Keeper is required + type: string + taskIDsCompleted: + type: array + description: "Completed task ids" + nullable: true + items: + type: string + action: + type: string + description: "Action" + actions: + type: array + description: "Actions" + nullable: true + items: + type: string + error: + type: string + description: "Last error" + errors: + type: array + description: "Errors" + nullable: true + items: + type: string + hostsUnchanged: + type: integer + minimum: 0 + description: "Unchanged Hosts count" + hostsUpdated: + type: integer + minimum: 0 + description: "Updated Hosts count" + hostsAdded: + type: integer + minimum: 0 + description: "Added Hosts count" + hostsCompleted: + type: integer + minimum: 0 + description: "Completed Hosts count" + hostsDeleted: + type: integer + minimum: 0 + description: "Deleted Hosts count" + hostsDelete: + type: integer + minimum: 0 + description: "About to delete Hosts count" + pods: + type: array + description: "Pods" + nullable: true + items: + type: string + pod-ips: + type: array + description: "Pod IPs" + nullable: true + items: + type: string + fqdns: + type: array + description: "Pods FQDNs" + nullable: true + items: + type: string + endpoint: + type: string + description: "Endpoint" + endpoints: + type: array + description: "All endpoints" + nullable: true + items: + type: string + generation: + type: integer + minimum: 0 + description: "Generation" normalized: type: object - description: "Normalized CHK requested" + description: "Normalized resource requested" x-kubernetes-preserve-unknown-fields: true normalizedCompleted: type: object - description: "Normalized CHK completed" + description: "Normalized resource completed" x-kubernetes-preserve-unknown-fields: true + hostsWithTablesCreated: + type: array + description: "List of hosts with tables created by the operator" + nullable: true + items: + type: string + hostsWithReplicaCaughtUp: + type: array + description: "List of hosts with replica caught up" + nullable: true + items: + type: string + usedTemplates: + type: array + description: "List of templates used to build this CHI" + nullable: true + x-kubernetes-preserve-unknown-fields: true + items: + type: object + x-kubernetes-preserve-unknown-fields: true spec: type: object - description: KeeperSpec defines the desired state of a Keeper cluster + # x-kubernetes-preserve-unknown-fields: true + description: | + Specification of the desired behavior of one or more ClickHouse clusters + More info: https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md properties: + taskID: + type: string + description: | + Allows to define custom taskID for CHI update and watch status of this update execution. + Displayed in all .status.taskID* fields. + By default (if not filled) every update of CHI manifest will generate random taskID + stop: &TypeStringBool + type: string + description: | + Allows to stop all ClickHouse clusters defined in a CHI. + Works as the following: + - When `stop` is `1` operator sets `Replicas: 0` in each StatefulSet. Thie leads to having all `Pods` and `Service` deleted. All PVCs are kept intact. + - When `stop` is `0` operator sets `Replicas: 1` and `Pod`s and `Service`s will created again and all retained PVCs will be attached to `Pod`s. + enum: + # List StringBoolXXX constants from model + - "" + - "0" + - "1" + - "False" + - "false" + - "True" + - "true" + - "No" + - "no" + - "Yes" + - "yes" + - "Off" + - "off" + - "On" + - "on" + - "Disable" + - "disable" + - "Enable" + - "enable" + - "Disabled" + - "disabled" + - "Enabled" + - "enabled" + suspend: + !!merge <<: *TypeStringBool + description: | + Suspend reconciliation of resources managed by a ClickHouse Keeper. + Works as the following: + - When `suspend` is `true` operator stops reconciling all resources. + - When `suspend` is `false` or not set, operator reconciles all resources. namespaceDomainPattern: type: string description: | Custom domain pattern which will be used for DNS names of `Service` or `Pod`. Typical use scenario - custom cluster domain in Kubernetes cluster Example: %s.svc.my.test - replicas: - type: integer - format: int32 + reconciling: + type: object + description: "Optional, allows tuning reconciling cycle for ClickhouseInstallation from clickhouse-operator side" + # nullable: true + properties: + policy: + type: string + description: | + DISCUSSED TO BE DEPRECATED + Syntax sugar + Overrides all three 'reconcile.host.wait.{exclude, queries, include}' values from the operator's config + Possible values: + - wait - should wait to exclude host, complete queries and include host back into the cluster + - nowait - should NOT wait to exclude host, complete queries and include host back into the cluster + enum: + - "" + - "wait" + - "nowait" + configMapPropagationTimeout: + type: integer + description: | + Timeout in seconds for `clickhouse-operator` to wait for modified `ConfigMap` to propagate into the `Pod` + More details: https://kubernetes.io/docs/concepts/configuration/configmap/#mounted-configmaps-are-updated-automatically + minimum: 0 + maximum: 3600 + cleanup: + type: object + description: "Optional, defines behavior for cleanup Kubernetes resources during reconcile cycle" + # nullable: true + properties: + unknownObjects: + type: object + description: | + Describes what clickhouse-operator should do with found Kubernetes resources which should be managed by clickhouse-operator, + but do not have `ownerReference` to any currently managed `ClickHouseInstallation` resource. + Default behavior is `Delete`" + # nullable: true + properties: + statefulSet: &TypeObjectsCleanup + type: string + description: "Behavior policy for unknown StatefulSet, `Delete` by default" + enum: + # List ObjectsCleanupXXX constants from model + - "" + - "Retain" + - "Delete" + pvc: + type: string + !!merge <<: *TypeObjectsCleanup + description: "Behavior policy for unknown PVC, `Delete` by default" + configMap: + !!merge <<: *TypeObjectsCleanup + description: "Behavior policy for unknown ConfigMap, `Delete` by default" + service: + !!merge <<: *TypeObjectsCleanup + description: "Behavior policy for unknown Service, `Delete` by default" + reconcileFailedObjects: + type: object + description: | + Describes what clickhouse-operator should do with Kubernetes resources which are failed during reconcile. + Default behavior is `Retain`" + # nullable: true + properties: + statefulSet: + !!merge <<: *TypeObjectsCleanup + description: "Behavior policy for failed StatefulSet, `Retain` by default" + pvc: + !!merge <<: *TypeObjectsCleanup + description: "Behavior policy for failed PVC, `Retain` by default" + configMap: + !!merge <<: *TypeObjectsCleanup + description: "Behavior policy for failed ConfigMap, `Retain` by default" + service: + !!merge <<: *TypeObjectsCleanup + description: "Behavior policy for failed Service, `Retain` by default" + defaults: + type: object description: | - Replicas is the expected size of the keeper cluster. - The valid range of size is from 1 to 7. - minimum: 1 - maximum: 7 + define default behavior for whole ClickHouseInstallation, some behavior can be re-define on cluster, shard and replica level + More info: https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md#specdefaults + # nullable: true + properties: + replicasUseFQDN: + !!merge <<: *TypeStringBool + description: | + define should replicas be specified by FQDN in ``. + In case of "no" will use short hostname and clickhouse-server will use kubernetes default suffixes for DNS lookup + "no" by default + distributedDDL: + type: object + description: | + allows change `` settings + More info: https://clickhouse.tech/docs/en/operations/server-configuration-parameters/settings/#server-settings-distributed_ddl + # nullable: true + properties: + profile: + type: string + description: "Settings from this profile will be used to execute DDL queries" + storageManagement: + type: object + description: default storage management options + properties: + provisioner: &TypePVCProvisioner + type: string + description: "defines `PVC` provisioner - be it StatefulSet or the Operator" + enum: + - "" + - "StatefulSet" + - "Operator" + reclaimPolicy: &TypePVCReclaimPolicy + type: string + description: | + defines behavior of `PVC` deletion. + `Delete` by default, if `Retain` specified then `PVC` will be kept when deleting StatefulSet + enum: + - "" + - "Retain" + - "Delete" + templates: &TypeTemplateNames + type: object + description: "optional, configuration of the templates names which will use for generate Kubernetes resources according to one or more ClickHouse clusters described in current ClickHouseInstallation (chi) resource" + # nullable: true + properties: + hostTemplate: + type: string + description: "optional, template name from chi.spec.templates.hostTemplates, which will apply to configure every `clickhouse-server` instance during render ConfigMap resources which will mount into `Pod`" + podTemplate: + type: string + description: "optional, template name from chi.spec.templates.podTemplates, allows customization each `Pod` resource during render and reconcile each StatefulSet.spec resource described in `chi.spec.configuration.clusters`" + dataVolumeClaimTemplate: + type: string + description: "optional, template name from chi.spec.templates.volumeClaimTemplates, allows customization each `PVC` which will mount for clickhouse data directory in each `Pod` during render and reconcile every StatefulSet.spec resource described in `chi.spec.configuration.clusters`" + logVolumeClaimTemplate: + type: string + description: "optional, template name from chi.spec.templates.volumeClaimTemplates, allows customization each `PVC` which will mount for clickhouse log directory in each `Pod` during render and reconcile every StatefulSet.spec resource described in `chi.spec.configuration.clusters`" + serviceTemplate: + type: string + description: "optional, template name from chi.spec.templates.serviceTemplates. used for customization of the `Service` resource, created by `clickhouse-operator` to cover all clusters in whole `chi` resource" + serviceTemplates: + type: array + description: "optional, template names from chi.spec.templates.serviceTemplates. used for customization of the `Service` resources, created by `clickhouse-operator` to cover all clusters in whole `chi` resource" + nullable: true + items: + type: string + clusterServiceTemplate: + type: string + description: "optional, template name from chi.spec.templates.serviceTemplates, allows customization for each `Service` resource which will created by `clickhouse-operator` which cover each clickhouse cluster described in `chi.spec.configuration.clusters`" + shardServiceTemplate: + type: string + description: "optional, template name from chi.spec.templates.serviceTemplates, allows customization for each `Service` resource which will created by `clickhouse-operator` which cover each shard inside clickhouse cluster described in `chi.spec.configuration.clusters`" + replicaServiceTemplate: + type: string + description: "optional, template name from chi.spec.templates.serviceTemplates, allows customization for each `Service` resource which will created by `clickhouse-operator` which cover each replica inside each shard inside each clickhouse cluster described in `chi.spec.configuration.clusters`" + volumeClaimTemplate: + type: string + description: "optional, alias for dataVolumeClaimTemplate, template name from chi.spec.templates.volumeClaimTemplates, allows customization each `PVC` which will mount for clickhouse data directory in each `Pod` during render and reconcile every StatefulSet.spec resource described in `chi.spec.configuration.clusters`" configuration: type: object description: "allows configure multiple aspects and behavior for `clickhouse-server` instance and also allows describe multiple `clickhouse-server` clusters inside one `chi` resource" # nullable: true properties: - settings: + settings: &TypeSettings type: object - description: "allows configure multiple aspects and behavior for `clickhouse-keeper` instance" + description: | + allows configure multiple aspects and behavior for `clickhouse-keeper` instance + # nullable: true + x-kubernetes-preserve-unknown-fields: true + files: &TypeFiles + type: object + description: | + allows define content of any setting + # nullable: true x-kubernetes-preserve-unknown-fields: true clusters: type: array description: | - describes ClickHouseKeeper clusters layout and allows change settings on cluster-level and replica-level + describes clusters layout and allows change settings on cluster-level and replica-level # nullable: true items: type: object @@ -147,25 +511,178 @@ spec: properties: name: type: string - description: "cluster name, used to identify set of ClickHouseKeeper servers and wide used during generate names of related Kubernetes resources" + description: "cluster name, used to identify set of servers and wide used during generate names of related Kubernetes resources" minLength: 1 # See namePartClusterMaxLen const maxLength: 15 pattern: "^[a-zA-Z0-9-]{0,15}$" + settings: + !!merge <<: *TypeSettings + description: | + optional, allows configure `clickhouse-server` settings inside ... tag in each `Pod` only in one cluster during generate `ConfigMap` which will mount in `/etc/clickhouse-server/config.d/` + override top-level `chi.spec.configuration.settings` + More details: https://clickhouse.tech/docs/en/operations/settings/settings/ + files: + !!merge <<: *TypeFiles + description: | + optional, allows define content of any setting file inside each `Pod` on current cluster during generate `ConfigMap` which will mount in `/etc/clickhouse-server/config.d/` or `/etc/clickhouse-server/conf.d/` or `/etc/clickhouse-server/users.d/` + override top-level `chi.spec.configuration.files` + templates: + !!merge <<: *TypeTemplateNames + description: | + optional, configuration of the templates names which will use for generate Kubernetes resources according to selected cluster + override top-level `chi.spec.configuration.templates` layout: type: object description: | - describe current cluster layout, how many replicas + describe current cluster layout, how much shards in cluster, how much replica in shard + allows override settings on each shard and replica separatelly # nullable: true properties: replicasCount: type: integer - description: "how many replicas in ClickHouseKeeper cluster" + description: | + how much replicas in each shards for current cluster will run in Kubernetes, + each replica is a separate `StatefulSet` which contains only one `Pod` with `clickhouse-server` instance, + every shard contains 1 replica by default" + replicas: + type: array + description: "optional, allows override top-level `chi.spec.configuration` and cluster-level `chi.spec.configuration.clusters` configuration for each replica and each shard relates to selected replica, use it only if you fully understand what you do" + # nullable: true + items: + type: object + properties: + name: + type: string + description: "optional, by default replica name is generated, but you can override it and setup custom name" + minLength: 1 + # See namePartShardMaxLen const + maxLength: 15 + pattern: "^[a-zA-Z0-9-]{0,15}$" + settings: + !!merge <<: *TypeSettings + description: | + optional, allows configure `clickhouse-server` settings inside ... tag in `Pod` only in one replica during generate `ConfigMap` which will mount in `/etc/clickhouse-server/conf.d/` + override top-level `chi.spec.configuration.settings`, cluster-level `chi.spec.configuration.clusters.settings` and will ignore if shard-level `chi.spec.configuration.clusters.layout.shards` present + More details: https://clickhouse.tech/docs/en/operations/settings/settings/ + files: + !!merge <<: *TypeFiles + description: | + optional, allows define content of any setting file inside each `Pod` only in one replica during generate `ConfigMap` which will mount in `/etc/clickhouse-server/config.d/` or `/etc/clickhouse-server/conf.d/` or `/etc/clickhouse-server/users.d/` + override top-level `chi.spec.configuration.files` and cluster-level `chi.spec.configuration.clusters.files`, will ignore if `chi.spec.configuration.clusters.layout.shards` presents + templates: + !!merge <<: *TypeTemplateNames + description: | + optional, configuration of the templates names which will use for generate Kubernetes resources according to selected replica + override top-level `chi.spec.configuration.templates`, cluster-level `chi.spec.configuration.clusters.templates` + shardsCount: + type: integer + description: "optional, count of shards related to current replica, you can override each shard behavior on low-level `chi.spec.configuration.clusters.layout.replicas.shards`" + minimum: 1 + shards: + type: array + description: "optional, list of shards related to current replica, will ignore if `chi.spec.configuration.clusters.layout.shards` presents" + # nullable: true + items: + # Host + type: object + properties: + name: + type: string + description: "optional, by default shard name is generated, but you can override it and setup custom name" + minLength: 1 + # See namePartReplicaMaxLen const + maxLength: 15 + pattern: "^[a-zA-Z0-9-]{0,15}$" + zkPort: + type: integer + minimum: 1 + maximum: 65535 + raftPort: + type: integer + minimum: 1 + maximum: 65535 + settings: + !!merge <<: *TypeSettings + description: | + optional, allows configure `clickhouse-server` settings inside ... tag in `Pod` only in one shard related to current replica during generate `ConfigMap` which will mount in `/etc/clickhouse-server/conf.d/` + override top-level `chi.spec.configuration.settings`, cluster-level `chi.spec.configuration.clusters.settings` and replica-level `chi.spec.configuration.clusters.layout.replicas.settings` + More details: https://clickhouse.tech/docs/en/operations/settings/settings/ + files: + !!merge <<: *TypeFiles + description: | + optional, allows define content of any setting file inside each `Pod` only in one shard related to current replica during generate `ConfigMap` which will mount in `/etc/clickhouse-server/config.d/` or `/etc/clickhouse-server/conf.d/` or `/etc/clickhouse-server/users.d/` + override top-level `chi.spec.configuration.files` and cluster-level `chi.spec.configuration.clusters.files`, will ignore if `chi.spec.configuration.clusters.layout.shards` presents + templates: + !!merge <<: *TypeTemplateNames + description: | + optional, configuration of the templates names which will use for generate Kubernetes resources according to selected replica + override top-level `chi.spec.configuration.templates`, cluster-level `chi.spec.configuration.clusters.templates`, replica-level `chi.spec.configuration.clusters.layout.replicas.templates` templates: type: object description: "allows define templates which will use for render Kubernetes resources like StatefulSet, ConfigMap, Service, PVC, by default, clickhouse-operator have own templates, but you can override it" # nullable: true properties: + hostTemplates: + type: array + description: "hostTemplate will use during apply to generate `clickhose-server` config files" + # nullable: true + items: + type: object + #required: + # - name + properties: + name: + description: "template name, could use to link inside top-level `chi.spec.defaults.templates.hostTemplate`, cluster-level `chi.spec.configuration.clusters.templates.hostTemplate`, shard-level `chi.spec.configuration.clusters.layout.shards.temlates.hostTemplate`, replica-level `chi.spec.configuration.clusters.layout.replicas.templates.hostTemplate`" + type: string + portDistribution: + type: array + description: "define how will distribute numeric values of named ports in `Pod.spec.containers.ports` and clickhouse-server configs" + # nullable: true + items: + type: object + #required: + # - type + properties: + type: + type: string + description: "type of distribution, when `Unspecified` (default value) then all listen ports on clickhouse-server configuration in all Pods will have the same value, when `ClusterScopeIndex` then ports will increment to offset from base value depends on shard and replica index inside cluster with combination of `chi.spec.templates.podTemlates.spec.HostNetwork` it allows setup ClickHouse cluster inside Kubernetes and provide access via external network bypass Kubernetes internal network" + enum: + # List PortDistributionXXX constants + - "" + - "Unspecified" + - "ClusterScopeIndex" + spec: + # Host + type: object + properties: + name: + type: string + description: "by default, hostname will generate, but this allows define custom name for each `clickhuse-server`" + minLength: 1 + # See namePartReplicaMaxLen const + maxLength: 15 + pattern: "^[a-zA-Z0-9-]{0,15}$" + zkPort: + type: integer + minimum: 1 + maximum: 65535 + raftPort: + type: integer + minimum: 1 + maximum: 65535 + settings: + !!merge <<: *TypeSettings + description: | + optional, allows configure `clickhouse-server` settings inside ... tag in each `Pod` where this template will apply during generate `ConfigMap` which will mount in `/etc/clickhouse-server/conf.d/` + More details: https://clickhouse.tech/docs/en/operations/settings/settings/ + files: + !!merge <<: *TypeFiles + description: | + optional, allows define content of any setting file inside each `Pod` where this template will apply during generate `ConfigMap` which will mount in `/etc/clickhouse-server/config.d/` or `/etc/clickhouse-server/conf.d/` or `/etc/clickhouse-server/users.d/` + templates: + !!merge <<: *TypeTemplateNames + description: "be careful, this part of CRD allows override template inside template, don't use it if you don't understand what you do" podTemplates: type: array description: | @@ -180,6 +697,83 @@ spec: name: type: string description: "template name, could use to link inside top-level `chi.spec.defaults.templates.podTemplate`, cluster-level `chi.spec.configuration.clusters.templates.podTemplate`, shard-level `chi.spec.configuration.clusters.layout.shards.temlates.podTemplate`, replica-level `chi.spec.configuration.clusters.layout.replicas.templates.podTemplate`" + generateName: + type: string + description: "allows define format for generated `Pod` name, look to https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md#spectemplatesservicetemplates for details about available template variables" + zone: + type: object + description: "allows define custom zone name and will separate ClickHouse `Pods` between nodes, shortcut for `chi.spec.templates.podTemplates.spec.affinity.podAntiAffinity`" + #required: + # - values + properties: + key: + type: string + description: "optional, if defined, allows select kubernetes nodes by label with `name` equal `key`" + values: + type: array + description: "optional, if defined, allows select kubernetes nodes by label with `value` in `values`" + # nullable: true + items: + type: string + distribution: + type: string + description: "DEPRECATED, shortcut for `chi.spec.templates.podTemplates.spec.affinity.podAntiAffinity`" + enum: + - "" + - "Unspecified" + - "OnePerHost" + podDistribution: + type: array + description: "define ClickHouse Pod distribution policy between Kubernetes Nodes inside Shard, Replica, Namespace, CHI, another ClickHouse cluster" + # nullable: true + items: + type: object + #required: + # - type + properties: + type: + type: string + description: "you can define multiple affinity policy types" + enum: + # List PodDistributionXXX constants + - "" + - "Unspecified" + - "ClickHouseAntiAffinity" + - "ShardAntiAffinity" + - "ReplicaAntiAffinity" + - "AnotherNamespaceAntiAffinity" + - "AnotherClickHouseInstallationAntiAffinity" + - "AnotherClusterAntiAffinity" + - "MaxNumberPerNode" + - "NamespaceAffinity" + - "ClickHouseInstallationAffinity" + - "ClusterAffinity" + - "ShardAffinity" + - "ReplicaAffinity" + - "PreviousTailAffinity" + - "CircularReplication" + scope: + type: string + description: "scope for apply each podDistribution" + enum: + # list PodDistributionScopeXXX constants + - "" + - "Unspecified" + - "Shard" + - "Replica" + - "Cluster" + - "ClickHouseInstallation" + - "Namespace" + number: + type: integer + description: "define, how much ClickHouse Pods could be inside selected scope with selected distribution type" + minimum: 0 + maximum: 65535 + topologyKey: + type: string + description: | + use for inter-pod affinity look to `pod.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution.podAffinityTerm.topologyKey`, + more info: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity" metadata: type: object description: | @@ -195,7 +789,8 @@ spec: x-kubernetes-preserve-unknown-fields: true volumeClaimTemplates: type: array - description: "allows define template for rendering `PVC` kubernetes resource, which would use inside `Pod` for mount clickhouse `data`, clickhouse `logs` or something else" + description: | + allows define template for rendering `PVC` kubernetes resource, which would use inside `Pod` for mount clickhouse `data`, clickhouse `logs` or something else # nullable: true items: type: object @@ -211,6 +806,8 @@ spec: cluster-level `chi.spec.configuration.clusters.templates.dataVolumeClaimTemplate` or `chi.spec.configuration.clusters.templates.logVolumeClaimTemplate`, shard-level `chi.spec.configuration.clusters.layout.shards.temlates.dataVolumeClaimTemplate` or `chi.spec.configuration.clusters.layout.shards.temlates.logVolumeClaimTemplate` replica-level `chi.spec.configuration.clusters.layout.replicas.templates.dataVolumeClaimTemplate` or `chi.spec.configuration.clusters.layout.replicas.templates.logVolumeClaimTemplate` + provisioner: *TypePVCProvisioner + reclaimPolicy: *TypePVCReclaimPolicy metadata: type: object description: | @@ -244,6 +841,12 @@ spec: cluster-level `chi.spec.configuration.clusters.templates.clusterServiceTemplate` shard-level `chi.spec.configuration.clusters.layout.shards.temlates.shardServiceTemplate` replica-level `chi.spec.configuration.clusters.layout.replicas.templates.replicaServiceTemplate` or `chi.spec.configuration.clusters.layout.shards.replicas.replicaServiceTemplate` + generateName: + type: string + description: | + allows define format for generated `Service` name, + look to https://github.com/Altinity/clickhouse-operator/blob/master/docs/custom_resource_explained.md#spectemplatesservicetemplates + for details about available template variables" metadata: # TODO specify ObjectMeta type: object diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhouseoperatorconfigurations.clickhouse.altinity.com.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhouseoperatorconfigurations.clickhouse.altinity.com.yaml index b53ef91d..9bfe368d 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhouseoperatorconfigurations.clickhouse.altinity.com.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/crds/CustomResourceDefinition-clickhouseoperatorconfigurations.clickhouse.altinity.com.yaml @@ -7,7 +7,7 @@ kind: CustomResourceDefinition metadata: name: clickhouseoperatorconfigurations.clickhouse.altinity.com labels: - clickhouse.altinity.com/chop: 0.23.4 + clickhouse.altinity.com/chop: 0.25.2 spec: group: clickhouse.altinity.com scope: Namespaced @@ -137,6 +137,7 @@ spec: items: type: object description: "setting: value pairs for configuration restart policy" + x-kubernetes-preserve-unknown-fields: true access: type: object description: "parameters which use for connect to clickhouse from clickhouse-operator deployment" @@ -181,6 +182,47 @@ spec: minimum: 1 maximum: 600 description: "Timout to perform SQL query from the operator to ClickHouse instances. In seconds." + addons: + type: object + description: "Configuration addons specifies additional settings" + properties: + rules: + type: array + description: "Array of set of rules per specified ClickHouse versions" + items: + type: object + properties: + version: + type: string + description: "ClickHouse version expression" + spec: + type: object + description: "spec" + properties: + configuration: + type: object + description: "allows configure multiple aspects and behavior for `clickhouse-server` instance and also allows describe multiple `clickhouse-server` clusters inside one `chi` resource" + properties: + users: + type: object + description: "see same section from CR spec" + x-kubernetes-preserve-unknown-fields: true + profiles: + type: object + description: "see same section from CR spec" + x-kubernetes-preserve-unknown-fields: true + quotas: + type: object + description: "see same section from CR spec" + x-kubernetes-preserve-unknown-fields: true + settings: + type: object + description: "see same section from CR spec" + x-kubernetes-preserve-unknown-fields: true + files: + type: object + description: "see same section from CR spec" + x-kubernetes-preserve-unknown-fields: true metrics: type: object description: "parameters which use for connect to fetch metrics from clickhouse by clickhouse-operator" @@ -323,6 +365,19 @@ spec: include: !!merge <<: *TypeStringBool description: "Whether the operator during reconcile procedure should wait for a ClickHouse host to be included into a ClickHouse cluster" + replicas: + type: object + description: "Whether the operator during reconcile procedure should wait for replicas to catch-up" + properties: + all: + !!merge <<: *TypeStringBool + description: "Whether the operator during reconcile procedure should wait for all replicas to catch-up" + new: + !!merge <<: *TypeStringBool + description: "Whether the operator during reconcile procedure should wait for new replicas to catch-up" + delay: + type: integer + description: "replication max absolute delay to consider replica is not delayed" annotation: type: object description: "defines which metadata.annotations items will include or exclude during render StatefulSet, Pod, PVC resources" @@ -373,6 +428,40 @@ spec: - "LabelClusterScopeCycleSize" - "LabelClusterScopeCycleIndex" - "LabelClusterScopeCycleOffset" + metrics: + type: object + description: "defines metrics exporter options" + properties: + labels: + type: object + description: "defines metric labels options" + properties: + exclude: + type: array + description: | + When adding labels to a metric exclude labels with names from the following list + items: + type: string + status: + type: object + description: "defines status options" + properties: + fields: + type: object + description: "defines status fields options" + properties: + action: + !!merge <<: *TypeStringBool + description: "Whether the operator should fill status field 'action'" + actions: + !!merge <<: *TypeStringBool + description: "Whether the operator should fill status field 'actions'" + error: + !!merge <<: *TypeStringBool + description: "Whether the operator should fill status field 'error'" + errors: + !!merge <<: *TypeStringBool + description: "Whether the operator should fill status field 'errors'" statefulSet: type: object description: "define StatefulSet-specific parameters" diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/files/Altinity_ClickHouse_Operator_dashboard.json b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/files/Altinity_ClickHouse_Operator_dashboard.json index 3d914458..0f3e34b8 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/files/Altinity_ClickHouse_Operator_dashboard.json +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/files/Altinity_ClickHouse_Operator_dashboard.json @@ -1,56 +1,23 @@ { - "__inputs": [ - { - "name": "DS_PROMETHEUS", - "label": "clickhouse-operator-prometheus", - "description": "", - "type": "datasource", - "pluginId": "prometheus", - "pluginName": "Prometheus" - } - ], - "__requires": [ - { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "7.5.15" - }, - { - "type": "panel", - "id": "grafana-piechart-panel", - "name": "Pie Chart", - "version": "1.6.2" - }, - { - "type": "panel", - "id": "graph", - "name": "Graph", - "version": "" - }, - { - "type": "datasource", - "id": "prometheus", - "name": "Prometheus", - "version": "1.0.0" - }, - { - "type": "panel", - "id": "singlestat", - "name": "Singlestat", - "version": "" - }, - { - "type": "panel", - "id": "table-old", - "name": "Table (old)", - "version": "" - } - ], "annotations": { "list": [ { - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "enable": true, "expr": "ALERTS{app=~\"clickhouse-operator|zookeeper\"}", "hide": false, @@ -64,40 +31,87 @@ "textFormat": "{{alertstate}}", "titleFormat": "{{alertname}}", "type": "tags" - }, - { - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" } ] }, "description": "Alitinity Clickhouse Operator metrics exported by Monitoring Agent", "editable": true, + "fiscalYearStartMonth": 0, "gnetId": 882, "graphTooltip": 1, - "id": null, - "iteration": 1662652674457, + "id": 82, "links": [], + "liveNow": false, "panels": [ { - "columns": [ - { - "text": "Current", - "value": "current" - } - ], - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "fieldConfig": { - "defaults": {}, - "overrides": [] + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "hidden", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 22, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "smooth", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "log": 2, + "type": "log" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 43, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(245, 54, 54, 0.9)", + "value": null + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Time" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "auto" + } + ] + } + ] }, - "filterNull": false, - "fontSize": "100%", "gridPos": { "h": 4, "w": 10, @@ -105,55 +119,40 @@ "y": 0 }, "id": 15, - "links": [], - "pageSize": null, - "scroll": true, - "showHeader": true, - "sort": { - "col": 2, - "desc": false - }, - "styles": [ - { - "align": "auto", - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "pattern": "Time", - "type": "date" + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - { - "align": "auto", - "colorMode": "value", - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "decimals": 1, - "pattern": "/.*/", - "thresholds": [ - "3600", - "86400" - ], - "type": "number", - "unit": "s" + "tooltip": { + "mode": "multi", + "sort": "none" } - ], + }, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "chi_clickhouse_metric_Uptime{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sort(avg by (hostname)(chi_clickhouse_metric_Uptime{chi=~\"$chi\",hostname=~\"$hostname\"})) OR on () vector(0)", + "interval": "", "intervalFactor": 2, "legendFormat": "{{hostname}}", "metric": "chi_clickhouse_metric_Uptime", + "range": true, "refId": "A", "step": 60 } ], - "title": "Uptime", - "transform": "timeseries_aggregations", - "type": "table-old" + "title": "Uptime (logarithmic)", + "transformations": [], + "type": "timeseries" }, { - "cacheTimeout": null, "colorBackground": false, "colorValue": true, "colors": [ @@ -161,12 +160,29 @@ "rgba(237, 129, 40, 0.89)", "rgba(245, 54, 54, 0.9)" ], - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "Clickhouse operator metrics-exporter fails when grab metrics from clickhouse-server\n\nPlease look pods status\n\nkubectl get pods --all-namespaces | grep clickhouse", "editable": true, "error": false, "fieldConfig": { - "defaults": {}, + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, "overrides": [] }, "format": "none", @@ -185,7 +201,6 @@ }, "id": 47, "interval": "", - "isNew": true, "links": [ { "targetBlank": true, @@ -206,7 +221,23 @@ ], "maxDataPoints": 100, "nullPointMode": "connected", - "nullText": null, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.3", "postfix": "", "postfixFontSize": "50%", "prefix": "", @@ -228,7 +259,10 @@ "tableColumn": "", "targets": [ { - "expr": "sum(chi_clickhouse_metric_fetch_errors{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\",fetch_type=\"system.metrics\"})", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(chi_clickhouse_metric_fetch_errors{chi=~\"$chi\",hostname=~\"$hostname\",fetch_type=\"system.metrics\"})", "intervalFactor": 2, "legendFormat": "", "refId": "A", @@ -236,10 +270,8 @@ } ], "thresholds": "1,1", - "timeFrom": null, - "timeShift": null, "title": "Failed Pods", - "type": "singlestat", + "type": "stat", "valueFontSize": "80%", "valueMaps": [ { @@ -251,70 +283,311 @@ "valueName": "current" }, { - "columns": [ - { - "text": "Current", - "value": "current" - } - ], - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "description": "For example, version 11.22.33 is translated to 11022033", "fieldConfig": { - "defaults": {}, - "overrides": [] + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "hidden", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 3, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [ + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "auto" + } + ] + } + ] }, - "filterNull": false, - "fontSize": "100%", "gridPos": { "h": 4, - "w": 11, + "w": 7, "x": 13, "y": 0 }, "hideTimeOverride": false, "id": 17, - "links": [], - "pageSize": null, - "scroll": false, - "showHeader": true, - "sort": { - "col": 3, - "desc": true - }, - "styles": [ - { - "align": "auto", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "decimals": 0, - "pattern": "/.*/", - "thresholds": [], - "type": "number", - "unit": "none" + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" } - ], + }, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "chi_clickhouse_metric_VersionInteger{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sort_desc(max by (hostname) (chi_clickhouse_metric_VersionInteger{chi=~\"$chi\",hostname=~\"$hostname\"}))", "intervalFactor": 2, "legendFormat": "{{hostname}}", "metric": "chi_clickhouse_metric_VersionInteger", + "range": true, "refId": "A", "step": 60 } ], - "timeFrom": null, - "timeShift": null, "title": "Version", - "transform": "timeseries_aggregations", - "type": "table-old" + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 20, + "y": 0 + }, + "id": 56, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "center", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "10.4.3", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "max(chi_clickhouse_metric_NumberOfTables{chi=~\"$chi\",hostname=~\"$hostname\"})", + "instant": false, + "legendFormat": "Tables", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "max(chi_clickhouse_metric_NumberOfDatabases{chi=~\"$chi\",hostname=~\"$hostname\"})", + "hide": false, + "instant": false, + "legendFormat": "Databases", + "range": true, + "refId": "B" + } + ], + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#265d1fd9", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Value" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "options": { + "pattern": "(\\d\\d)(?:00(\\d)|0(\\d\\d)|(\\d\\d\\d))0*(.*)", + "result": { + "index": 0, + "text": "$1.$2$3$4.$5" + } + }, + "type": "regex" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 4, + "w": 2, + "x": 22, + "y": 0 + }, + "hideTimeOverride": false, + "id": 62, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "center", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^Version$/", + "values": false + }, + "showPercentChange": false, + "text": {}, + "textMode": "value_and_name", + "wideLayout": true + }, + "pluginVersion": "10.4.3", + "targets": [ + { + "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "editorMode": "code", + "exemplar": true, + "expr": "max(chi_clickhouse_metric_VersionInteger{chi=~\"$chi\",hostname=~\"$hostname\"})", + "interval": "", + "intervalFactor": 2, + "legendFormat": "Version", + "metric": "chi_clickhouse_metric_VersionInteger", + "range": true, + "refId": "A", + "step": 60 + } + ], + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "chi-(.*)\\.svc\\.cluster\\.local", + "renamePattern": "$1" + } + }, + { + "id": "convertFieldType", + "options": { + "conversions": [ + { + "destinationType": "string", + "targetField": "Value" + } + ], + "fields": {} + } + } + ], + "type": "stat" }, { - "cacheTimeout": null, "colorBackground": false, "colorValue": true, "colors": [ @@ -322,12 +595,29 @@ "rgba(237, 129, 40, 0.89)", "rgba(245, 54, 54, 0.9)" ], - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "Check Zookeeper connection, Disk Free space and network interconnection between replicas ASAP", "editable": true, "error": false, "fieldConfig": { - "defaults": {}, + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, "overrides": [] }, "format": "none", @@ -345,8 +635,6 @@ "y": 2 }, "id": 6, - "interval": null, - "isNew": true, "links": [ { "targetBlank": true, @@ -372,7 +660,23 @@ ], "maxDataPoints": 100, "nullPointMode": "connected", - "nullText": null, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.3", "postfix": "", "postfixFontSize": "50%", "prefix": "", @@ -394,7 +698,10 @@ "tableColumn": "", "targets": [ { - "expr": "sum(chi_clickhouse_metric_ReadonlyReplica{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"})", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(chi_clickhouse_metric_ReadonlyReplica{chi=~\"$chi\",hostname=~\"$hostname\"})", "intervalFactor": 2, "legendFormat": "", "refId": "A", @@ -403,7 +710,7 @@ ], "thresholds": "1,1", "title": "ReadOnly replicas", - "type": "singlestat", + "type": "stat", "valueFontSize": "80%", "valueMaps": [ { @@ -415,41 +722,72 @@ "valueName": "current" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "Show DNS errors and distributed server-server connections failures", "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 7, "w": 8, "x": 0, "y": 4 }, - "hiddenSeries": false, "id": 21, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "hideZero": false, - "max": true, - "min": true, - "show": false, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, "links": [ { "targetBlank": true, @@ -462,22 +800,30 @@ "url": "https://github.com/ClickHouse/ClickHouse/search?q=DNSError" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": true, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "increase(chi_clickhouse_event_NetworkErrors{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_NetworkErrors{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "intervalFactor": 2, "legendFormat": "NetworkErrors {{hostname}}", "metric": "chi_clickhouse_event_NetworkErrors", @@ -485,7 +831,10 @@ "step": 120 }, { - "expr": "increase(chi_clickhouse_event_DistributedConnectionFailAtAll{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_DistributedConnectionFailAtAll{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "intervalFactor": 2, "legendFormat": "DistributedConnectionFailAtAll {{hostname}}", "metric": "chi_clickhouse_event_DistributedConnectionFailAtAll", @@ -493,7 +842,10 @@ "step": 120 }, { - "expr": "increase(chi_clickhouse_event_DistributedConnectionFailTry{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_DistributedConnectionFailTry{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "intervalFactor": 2, "legendFormat": "DistributedConnectionFailTry {{hostname}}", "metric": "chi_clickhouse_event_DistributedConnectionFailTry", @@ -501,7 +853,10 @@ "step": 120 }, { - "expr": "increase(chi_clickhouse_event_DNSError{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_DNSError{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "intervalFactor": 2, "legendFormat": "DNSErrors {{hostname}}", "metric": "chi_clickhouse_event_NetworkErrors", @@ -509,83 +864,76 @@ "step": 120 } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "DNS and Distributed Connection Errors", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "Show readonly and partial shutdown replicas, zookeeer exceptions, zookeeer sessions, zookeeper init requests", "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 7, "w": 8, "x": 8, "y": 4 }, - "hiddenSeries": false, "id": 19, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "hideZero": false, - "max": true, - "min": true, - "show": false, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, "links": [ { "targetBlank": true, @@ -603,22 +951,30 @@ "url": "https://www.slideshare.net/Altinity/introduction-to-the-mysteries-of-clickhouse-replication-by-robert-hodges-and-altinity-engineering-team" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": true, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "chi_clickhouse_metric_ReadonlyReplica{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_ReadonlyReplica{chi=~\"$chi\",hostname=~\"$hostname\"}", "hide": false, "intervalFactor": 2, "legendFormat": "ReadonlyReplica {{hostname}}", @@ -627,7 +983,10 @@ "step": 120 }, { - "expr": "increase(chi_clickhouse_event_ReplicaPartialShutdown{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_ReplicaPartialShutdown{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "intervalFactor": 2, "legendFormat": "ReplicaPartialShutdown {{hostname}}", "metric": "chi_clickhouse_event_ReplicaPartialShutdown", @@ -635,7 +994,10 @@ "step": 120 }, { - "expr": "increase(chi_clickhouse_event_ZooKeeperUserExceptions{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_ZooKeeperUserExceptions{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "hide": true, "intervalFactor": 2, "legendFormat": "ZooKeeperUserExceptions {{hostname}}", @@ -644,7 +1006,10 @@ "step": 120 }, { - "expr": "increase(chi_clickhouse_event_ZooKeeperInit{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_ZooKeeperInit{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "intervalFactor": 2, "legendFormat": "ZooKeeperInit {{hostname}}", "metric": "chi_clickhouse_event_ZooKeeperInit", @@ -652,7 +1017,10 @@ "step": 120 }, { - "expr": "increase(chi_clickhouse_metric_ZooKeeperSession{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_metric_ZooKeeperSession{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "intervalFactor": 2, "legendFormat": "ZooKeeperSession {{hostname}}", "metric": "chi_clickhouse_metric_ZooKeeperSession", @@ -660,7 +1028,10 @@ "step": 120 }, { - "expr": "increase(chi_clickhouse_event_ZooKeeperHardwareExceptions{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_ZooKeeperHardwareExceptions{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "intervalFactor": 2, "legendFormat": "ZooKeeperHardwareExceptions {{hostname}}", "metric": "chi_clickhouse_event_ZooKeeperUserExceptions", @@ -668,87 +1039,76 @@ "step": 120 } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Replication and ZooKeeper Exceptions", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "delayed query\nNumber of INSERT queries that are throttled due to high number of active data parts for partition in a *MergeTree table.\n\ndelayed blocks\nNumber of times the INSERT of a block to a *MergeTree table was throttled due to high number of active data parts for partition. \n\nrejected blocks\nNumber of times the INSERT of a block to a MergeTree table was rejected with 'Too many parts' exception due to high number of active data parts for partition.\n\n\nplease look\nparts_to_delay_insert\nparts_to_throw_insert\n\nin system.merge_tree_settings table", - "editable": true, - "error": false, "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, - "grid": {}, "gridPos": { "h": 7, "w": 8, "x": 16, "y": 4 }, - "hiddenSeries": false, "id": 5, - "isNew": true, - "legend": { - "avg": false, - "current": false, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 2, "links": [ { "targetBlank": true, @@ -761,134 +1121,293 @@ "url": "https://clickhouse.com/docs/en/operations/system-tables/merge_tree_settings" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "chi_clickhouse_metric_DelayedInserts{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_DelayedInserts{chi=~\"$chi\",hostname=~\"$hostname\"}", "intervalFactor": 2, "legendFormat": "delayed queries {{hostname}}", "refId": "A", "step": 10 }, { - "expr": "increase(chi_clickhouse_event_DelayedInserts{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_DelayedInserts{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "intervalFactor": 2, "legendFormat": "delayed blocks {{hostname}}", "refId": "B", "step": 10 }, { - "expr": "increase(chi_clickhouse_event_RejectedInserts{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_RejectedInserts{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "intervalFactor": 2, "legendFormat": "rejected blocks {{hostname}}", "refId": "C", "step": 10 }, { - "expr": "chi_clickhouse_metric_DistributedFilesToInsert{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_DistributedFilesToInsert{chi=~\"$chi\",hostname=~\"$hostname\"}", "legendFormat": "pending distributed files {{ hostname }}", "refId": "D" }, { - "expr": "chi_clickhouse_metric_BrokenDistributedFilesToInsert{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_BrokenDistributedFilesToInsert{chi=~\"$chi\",hostname=~\"$hostname\"}", "legendFormat": "broken distributed files {{ hostname }}", "refId": "E" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Delayed/Rejected/Pending Inserts", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "description": "Number of SELECT queries started to be interpreted and maybe executed. Does not include queries that are failed to parse, that are rejected due to AST size limits; rejected due to quota limits or limits on number of simultaneously running queries. May include internal queries initiated by ClickHouse itself. Does not count subqueries.", - "editable": true, - "error": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Number of executing queries", "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisWidth": 55, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 29, + "gradientMode": "hue", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepBefore", + "lineWidth": 0, + "pointSize": 2, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Overall" + }, + "properties": [ + { + "id": "custom.lineInterpolation", + "value": "smooth" + }, + { + "id": "custom.fillOpacity", + "value": 0 + }, + { + "id": "custom.lineStyle", + "value": { + "fill": "solid" + } + }, + { + "id": "custom.lineWidth", + "value": 1 + } + ] + } + ] }, - "fill": 1, - "fillGradient": 0, - "grid": {}, "gridPos": { "h": 7, "w": 8, "x": 0, "y": 11 }, - "hiddenSeries": false, - "id": 1, - "isNew": true, - "legend": { - "avg": true, - "current": true, - "hideEmpty": true, - "hideZero": true, - "max": false, - "min": false, - "show": false, - "total": false, - "values": true + "id": 63, + "links": [ + { + "targetBlank": true, + "title": "max_concurent_queries", + "url": "https://clickhouse.com/docs/en/operations/server-configuration-parameters/settings#max_concurrent_queries" + }, + { + "targetBlank": true, + "title": "max_execution_time", + "url": "https://clickhouse.com/docs/en/operations/settings/query-complexity#max-execution-time" + } + ], + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "sum" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": false, + "sortBy": "Max", + "sortDesc": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "lines": true, - "linewidth": 2, + "pluginVersion": "8.3.2", + "targets": [ + { + "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "editorMode": "code", + "exemplar": true, + "expr": "max by (hostname) (max_over_time(chi_clickhouse_metric_Query{chi=~\"$chi\",hostname=~\"$hostname\"}[$__interval])-1) OR on () vector(0) > 0", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{hostname}}", + "range": true, + "refId": "A", + "step": 10 + }, + { + "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "editorMode": "code", + "exemplar": true, + "expr": "sum(chi_clickhouse_metric_Query{chi=~\"$chi\",hostname=~\"$hostname\"}-1) OR on () vector(0)", + "hide": false, + "interval": "", + "intervalFactor": 5, + "legendFormat": "Overall", + "range": true, + "refId": "Overall", + "step": 10 + } + ], + "title": "Queries (running)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Number of executing select queries", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisWidth": 55, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 25, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 11 + }, + "id": 8, "links": [ { "targetBlank": true, @@ -901,271 +1420,105 @@ "url": "https://clickhouse.com/docs/en/operations/settings/query-complexity#max-execution-time" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": true, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "rate(chi_clickhouse_event_SelectQuery{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": true, + "expr": "sum(rate(chi_clickhouse_event_SelectQuery{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])) OR on () vector(0)", + "hide": false, "intervalFactor": 2, - "legendFormat": "select {{hostname}}", - "refId": "B", - "step": 10 - }, - { - "expr": "rate(chi_clickhouse_event_Query{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "hide": true, - "intervalFactor": 2, - "legendFormat": "total {{hostname}}", + "legendFormat": "Select", + "range": true, "refId": "A", "step": 10 } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Select Queries", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "", - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "title": "Select Queries (started per sec)", + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "description": "Show how much bytes read and decompress via compressed buffer on each server in cluster", - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] + "datasource": { + "uid": "${DS_PROMETHEUS}" }, - "fill": 1, - "fillGradient": 1, - "grid": {}, - "gridPos": { - "h": 7, - "w": 8, - "x": 8, - "y": 11 - }, - "hiddenSeries": false, - "id": 8, - "isNew": true, - "legend": { - "avg": false, - "current": false, - "hideEmpty": true, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 2, - "links": [ - { - "targetBlank": true, - "title": "I/O buffers architecture", - "url": "https://clickhouse.com/docs/en/development/architecture/#io" - } - ], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - { - "alias": "/^uncompressed.+/", - "color": "#73BF69" - }, - { - "alias": "/^(file descriptor|os).+/", - "color": "#F2495C" - }, - { - "alias": "/^compressed.+/", - "color": "#FADE2A" - } - ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "rate(chi_clickhouse_event_CompressedReadBufferBytes{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "hide": false, - "intervalFactor": 2, - "legendFormat": "uncompressed {{hostname}}", - "refId": "A", - "step": 10 - }, - { - "expr": "rate(chi_clickhouse_event_ReadCompressedBytes{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "hide": false, - "interval": "", - "intervalFactor": 2, - "legendFormat": "compressed {{hostname}}", - "refId": "C", - "step": 10 - }, - { - "expr": "rate(chi_clickhouse_event_ReadBufferFromFileDescriptorReadBytes{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "hide": false, - "interval": "", - "intervalFactor": 2, - "legendFormat": "file descriptor {{hostname}}", - "refId": "B", - "step": 10 - }, - { - "expr": "rate(chi_clickhouse_event_OSReadBytes{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "hide": false, - "interval": "", - "intervalFactor": 2, - "legendFormat": "os {{hostname}}", - "refId": "D", - "step": 10 - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Read Bytes", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "bytes", - "label": "", - "logBase": 10, - "max": null, - "min": "0", - "show": true - }, - { - "decimals": null, - "format": "short", - "label": "", - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, "description": "Total amount of memory (bytes) allocated in currently executing queries. \n\nNote that some memory allocations may not be accounted.", - "editable": true, - "error": false, "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, - "grid": {}, "gridPos": { "h": 7, "w": 8, "x": 16, "y": 11 }, - "hiddenSeries": false, "id": 13, - "isNew": true, - "legend": { - "avg": false, - "current": false, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 2, "links": [ { "targetBlank": true, @@ -1173,110 +1526,101 @@ "url": "https://clickhouse.com/docs/en/operations/settings/query-complexity#settings_max_memory_usage" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "chi_clickhouse_metric_MemoryTracking{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_MemoryTracking{chi=~\"$chi\",hostname=~\"$hostname\"}", "intervalFactor": 2, "legendFormat": "{{hostname}}", "refId": "A", "step": 10 } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Memory for Queries", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "description": "Number of INSERT queries to be interpreted and potentially executed. Does not include queries that failed to parse or were rejected due to AST size limits, quota limits or limits on the number of simultaneously running queries. May include internal queries initiated by ClickHouse itself. Does not count subqueries.", - "editable": true, - "error": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Number of running INSERT queries. Does not include queries that failed to parse or were rejected due to AST size limits, quota limits or limits on the number of simultaneously running queries. May include internal queries initiated by ClickHouse itself. Does not count subqueries.", "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, - "grid": {}, "gridPos": { "h": 7, "w": 8, "x": 0, "y": 18 }, - "hiddenSeries": false, "id": 30, - "isNew": true, - "legend": { - "avg": false, - "current": false, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 2, "links": [ { "targetBlank": true, @@ -1284,223 +1628,211 @@ "url": "https://clickhouse.com/docs/en/operations/settings/query-complexity#settings_max_memory_usage" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - {}, - {} - ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "rate(chi_clickhouse_event_InsertQuery{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "irate(chi_clickhouse_event_InsertQuery{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "legendFormat": "Insert queries {{hostname}}", + "range": true, "refId": "C" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Insert Queries", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "reqps", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "title": "Insert Queries (running)", + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "description": "## Tracks amount of inserted data.", - "editable": true, - "error": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Number of executing insert queries", "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "axisWidth": 55, + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 25, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, - "grid": {}, "gridPos": { "h": 7, "w": 8, "x": 8, "y": 18 }, - "hiddenSeries": false, - "id": 37, - "isNew": true, - "legend": { - "avg": false, - "current": false, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 2, + "id": 58, "links": [ { "targetBlank": true, - "title": "max_memory_usage", - "url": "https://clickhouse.com/docs/en/operations/settings/query-complexity#settings_max_memory_usage" - } - ], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - {}, - {} - ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "rate(chi_clickhouse_event_InsertedBytes{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "Insert bytes {{hostname}}", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Bytes Inserted", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true + "title": "max_concurent_queries", + "url": "https://clickhouse.com/docs/en/operations/server-configuration-parameters/settings#max_concurrent_queries" }, { - "format": "reqps", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false + "targetBlank": true, + "title": "max_execution_time", + "url": "https://clickhouse.com/docs/en/operations/settings/query-complexity#max-execution-time" } ], - "yaxis": { - "align": false, - "alignLevel": null - } + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.3", + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": true, + "expr": "sum(rate(chi_clickhouse_event_InsertQuery{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])) OR on () vector(0)", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Select", + "range": true, + "refId": "A", + "step": 10 + } + ], + "title": "Insert Queries (started per sec)", + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "## Tracks rows of inserted data.", - "editable": true, - "error": false, "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, - "grid": {}, "gridPos": { "h": 7, "w": 8, "x": 16, "y": 18 }, - "hiddenSeries": false, "id": 32, - "isNew": true, - "legend": { - "avg": false, - "current": false, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 2, "links": [ { "targetBlank": true, @@ -1508,112 +1840,174 @@ "url": "https://clickhouse.com/docs/en/operations/settings/query-complexity#settings_max_memory_usage" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - {}, - {} - ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "rate(chi_clickhouse_event_InsertedRows{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_InsertedRows{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "legendFormat": "Insert rows {{hostname}}", "refId": "A" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Rows Inserted", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "reqps", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "Show how intensive data exchange between replicas in parts", - "editable": true, - "error": false, "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^max.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFA6B0", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^check.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF9830", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^fetch.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B877D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^(data loss|fetch fail|check fail).+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^replicated merge.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#DEB6F2", + "mode": "fixed" + } + } + ] + } + ] }, - "fill": 1, - "fillGradient": 0, - "grid": {}, "gridPos": { "h": 7, "w": 8, "x": 0, "y": 25 }, - "hiddenSeries": false, "id": 3, - "isNew": true, - "legend": { - "alignAsTable": false, - "avg": true, - "current": true, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, "links": [ { "targetBlank": true, @@ -1621,49 +2015,29 @@ "url": "https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/replication" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - { - "$$hashKey": "object:227", - "alias": "/^max.+/", - "color": "#FFA6B0" + "legend": { + "calcs": [ + "mean", + "lastNotNull" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - { - "$$hashKey": "object:228", - "alias": "/^check.+/", - "color": "#FF9830" - }, - { - "$$hashKey": "object:229", - "alias": "/^fetch.+/", - "color": "#B877D9" - }, - { - "$$hashKey": "object:338", - "alias": "/^(data loss|fetch fail|check fail).+/", - "color": "#C4162A" - }, - { - "$$hashKey": "object:1252", - "alias": "/^replicated merge.+/", - "color": "#DEB6F2" + "tooltip": { + "mode": "multi", + "sort": "none" } - ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + }, + "pluginVersion": "10.4.3", "targets": [ { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "exemplar": true, - "expr": "rate(chi_clickhouse_event_ReplicatedDataLoss{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "expr": "irate(chi_clickhouse_event_ReplicatedDataLoss{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "interval": "", "intervalFactor": 2, "legendFormat": "data loss {{hostname}}", @@ -1671,8 +2045,11 @@ "step": 20 }, { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "exemplar": true, - "expr": "rate(chi_clickhouse_event_ReplicatedPartChecks{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "expr": "irate(chi_clickhouse_event_ReplicatedPartChecks{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "hide": false, "interval": "", "intervalFactor": 2, @@ -1681,8 +2058,11 @@ "step": 20 }, { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "exemplar": true, - "expr": "rate(chi_clickhouse_event_ReplicatedPartChecksFailed{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "expr": "irate(chi_clickhouse_event_ReplicatedPartChecksFailed{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "hide": false, "interval": "", "intervalFactor": 2, @@ -1691,8 +2071,11 @@ "step": 20 }, { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "exemplar": true, - "expr": "rate(chi_clickhouse_event_ReplicatedPartFetches{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "expr": "irate(chi_clickhouse_event_ReplicatedPartFetches{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "hide": false, "interval": "", "intervalFactor": 2, @@ -1701,8 +2084,11 @@ "step": 20 }, { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "exemplar": true, - "expr": "rate(chi_clickhouse_event_ReplicatedPartFailedFetches{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "expr": "irate(chi_clickhouse_event_ReplicatedPartFailedFetches{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "hide": false, "interval": "", "intervalFactor": 2, @@ -1711,8 +2097,11 @@ "step": 20 }, { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "exemplar": true, - "expr": "rate(chi_clickhouse_event_ReplicatedPartFetchesOfMerged{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "expr": "irate(chi_clickhouse_event_ReplicatedPartFetchesOfMerged{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "hide": false, "interval": "", "intervalFactor": 2, @@ -1721,8 +2110,11 @@ "step": 20 }, { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "exemplar": true, - "expr": "rate(chi_clickhouse_event_ReplicatedPartMerges{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "expr": "irate(chi_clickhouse_event_ReplicatedPartMerges{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "hide": false, "interval": "", "intervalFactor": 2, @@ -1731,98 +2123,122 @@ "step": 20 }, { - "expr": "chi_clickhouse_metric_ReplicasSumInsertsInQueue{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_ReplicasSumInsertsInQueue{chi=~\"$chi\",hostname=~\"$hostname\"}", "legendFormat": "inserts in queue {{hostname}}", "refId": "H" }, { - "expr": "chi_clickhouse_metric_ReplicasSumMergesInQueue{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_ReplicasSumMergesInQueue{chi=~\"$chi\",hostname=~\"$hostname\"}", "legendFormat": "merges in queue {{hostname}}", "refId": "I" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Replication Queue Jobs", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "", - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "Show seconds when replicated servers can be delayed relative to current time, when you insert directly in *ReplicatedMegreTree table on one server clickhouse need time to replicate new parts of data to another servers in same shard in background", - "editable": true, - "error": false, "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^absolute.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^relative.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FADE2A", + "mode": "fixed" + } + } + ] + } + ] }, - "fill": 1, - "fillGradient": 0, - "grid": {}, "gridPos": { "h": 7, "w": 8, "x": 8, "y": 25 }, - "hiddenSeries": false, - "id": 7, - "isNew": true, - "legend": { - "avg": true, - "current": true, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, + "id": 59, "links": [ { "targetBlank": true, @@ -1840,126 +2256,113 @@ "url": "https://clickhouse.com/docs/en/operations/settings/settings#settings-max_replica_delay_for_distributed_queries" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - { - "alias": "/^absolute.+/", - "color": "#F2495C" + "legend": { + "calcs": [ + "mean", + "lastNotNull" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - { - "alias": "/^relative.+/", - "color": "#FADE2A" + "tooltip": { + "mode": "multi", + "sort": "none" } - ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + }, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "chi_clickhouse_metric_ReplicasMaxAbsoluteDelay{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_ReplicasMaxAbsoluteDelay{chi=~\"$chi\",hostname=~\"$hostname\"}", "intervalFactor": 2, "legendFormat": "absolute {{hostname}}", "refId": "A", "step": 10 }, { - "expr": "chi_clickhouse_metric_ReplicasMaxRelativeDelay{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_ReplicasMaxRelativeDelay{chi=~\"$chi\",hostname=~\"$hostname\"}", "intervalFactor": 2, "legendFormat": "relative {{hostname}}", "refId": "B", "step": 10 } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Max Replica Delay", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "Number of requests to ZooKeeper transactions per seconds.", - "editable": true, - "error": false, "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, - "grid": {}, "gridPos": { "h": 7, "w": 8, "x": 16, "y": 25 }, - "hiddenSeries": false, "id": 34, - "isNew": true, - "legend": { - "avg": true, - "current": true, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, "links": [ { "targetBlank": true, @@ -1967,114 +2370,110 @@ "url": "https://clickhouse.com/docs/en/development/architecture#replication" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [ + "mean", + "lastNotNull" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "rate(chi_clickhouse_event_ZooKeeperTransactions{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_ZooKeeperTransactions{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "legendFormat": "transactions {{ hostname }}", "refId": "B" }, { - "expr": "chi_clickhouse_metric_ZooKeeperRequest{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_ZooKeeperRequest{chi=~\"$chi\",hostname=~\"$hostname\"}", "hide": true, "legendFormat": "{{ hostname }}", "refId": "A" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Zookeeper Transactions", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "Show how intensive background merge processes", - "editable": true, - "error": false, "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, - "grid": {}, "gridPos": { "h": 7, "w": 8, "x": 0, "y": 32 }, - "hiddenSeries": false, "id": 2, - "isNew": true, - "legend": { - "avg": false, - "current": true, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, "links": [ { "targetBlank": true, @@ -2087,111 +2486,102 @@ "url": "https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": true, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "rate(chi_clickhouse_event_Merge{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_Merge{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "intervalFactor": 2, "legendFormat": "merges {{hostname}}", "refId": "A", "step": 4 } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Merges", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 2, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "decimals": null, - "format": "short", - "label": "", - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": "", - "logBase": 1, - "max": null, - "min": "0", - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "Show how intensive background merge processes", - "editable": true, - "error": false, "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, - "grid": {}, "gridPos": { "h": 7, "w": 8, "x": 8, "y": 32 }, - "hiddenSeries": false, "id": 36, - "isNew": true, - "legend": { - "avg": false, - "current": true, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, "links": [ { "targetBlank": true, @@ -2204,111 +2594,102 @@ "url": "https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": true, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "rate(chi_clickhouse_event_MergedRows{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_MergedRows{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "intervalFactor": 2, "legendFormat": "rows {{hostname}}", "refId": "B", "step": 4 } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Merged Rows", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 2, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "decimals": null, - "format": "short", - "label": "", - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": "", - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "Show how intensive background merge processes", - "editable": true, - "error": false, "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, - "grid": {}, "gridPos": { "h": 7, "w": 8, "x": 16, "y": 32 }, - "hiddenSeries": false, "id": 49, - "isNew": true, - "legend": { - "avg": false, - "current": true, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, "links": [ { "targetBlank": true, @@ -2321,109 +2702,102 @@ "url": "https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree/" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "desc" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": true, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "rate(chi_clickhouse_event_MergedUncompressedBytes{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_MergedUncompressedBytes{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", "intervalFactor": 2, "legendFormat": "bytes {{hostname}}", "refId": "B", "step": 4 } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Merged Uncompressed Bytes", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 2, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "decimals": null, - "format": "decbytes", - "label": "", - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": "", - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "decimals": 0, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "", "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 7, "w": 8, "x": 0, "y": 39 }, - "hiddenSeries": false, "id": 23, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "hideEmpty": false, - "hideZero": false, - "max": true, - "min": true, - "show": false, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, "links": [ { "targetBlank": true, @@ -2436,105 +2810,161 @@ "url": "https://github.com/ClickHouse/ClickHouse/search?q=parts_to_delay_insert" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "sum by(hostname) (chi_clickhouse_table_parts{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\",active=\"1\"})", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum by(hostname) (chi_clickhouse_table_parts{chi=~\"$chi\",hostname=~\"$hostname\",active=\"1\"})", "legendFormat": "Parts {{hostname}}", "refId": "C" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Active Parts", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": false - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "decimals": 0, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "", "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*detached_by_user.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#CA95E5", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*broken.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E02F44", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/.*(clone|ignored).*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFEE52", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^Inactive/" + }, + "properties": [ + { + "id": "custom.axisPlacement", + "value": "hidden" + } + ] + } + ] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 7, "w": 8, "x": 8, "y": 39 }, - "hiddenSeries": false, "id": 50, - "legend": { - "alignAsTable": true, - "avg": true, - "current": true, - "hideEmpty": false, - "hideZero": false, - "max": true, - "min": true, - "show": false, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 1, "links": [ { "targetBlank": true, @@ -2542,136 +2972,114 @@ "url": "https://clickhouse.com/docs/en/operations/system-tables/detached_parts/" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - { - "$$hashKey": "object:254", - "alias": "/.*detached_by_user.*/", - "color": "#CA95E5" + "legend": { + "calcs": [ + "mean", + "lastNotNull", + "max", + "min" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - { - "$$hashKey": "object:285", - "alias": "/.*broken.*/", - "color": "#E02F44" - }, - { - "$$hashKey": "object:355", - "alias": "/.*(clone|ignored).*/", - "color": "#FFEE52" - }, - { - "$$hashKey": "object:447", - "alias": "/^Inactive/", - "yaxis": 2 + "tooltip": { + "mode": "multi", + "sort": "none" } - ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + }, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "sum by(hostname,reason) (chi_clickhouse_metric_DetachedParts{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"})", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum by(hostname,reason) (chi_clickhouse_metric_DetachedParts{chi=~\"$chi\",hostname=~\"$hostname\"})", "interval": "", "legendFormat": "{{reason}} {{hostname}} ", "refId": "C" }, { - "expr": "sum by(hostname) (chi_clickhouse_table_parts{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\",active=\"0\"})", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum by(hostname) (chi_clickhouse_table_parts{chi=~\"$chi\",hostname=~\"$hostname\",active=\"0\"})", "hide": true, "interval": "", "legendFormat": "Inactive {{hostname}} ", "refId": "A" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Detached parts", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": false - } - ], - "yaxis": { - "align": true, - "alignLevel": 0 - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "Each logical partition defined over `PARTITION BY` contains few physical data \"parts\" ", - "editable": true, - "error": false, "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, - "grid": {}, "gridPos": { "h": 7, "w": 8, "x": 16, "y": 39 }, - "hiddenSeries": false, "id": 4, - "isNew": true, - "legend": { - "avg": false, - "current": true, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, "links": [ { "targetBlank": true, @@ -2689,104 +3097,178 @@ "url": "https://clickhouse.com/docs/en/operations/system-tables/part-log" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "chi_clickhouse_metric_MaxPartCountForPartition{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_MaxPartCountForPartition{chi=~\"$chi\",hostname=~\"$hostname\"}", "intervalFactor": 2, "legendFormat": "{{hostname}}", "refId": "A", "step": 10 } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Max Part count for Partition", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "Memory size allocated for clickhouse-server process\nAvailable for ClickHouse 20.4+\n\nVIRT \nThe total amount of virtual memory used by the task. It includes all code, data and shared libraries plus pages that have been swapped out.\n\nVIRT = SWAP + RES\n\n\nSWAP -- Swapped size (kb)\nThe swapped out portion of a task's total virtual memory image.\n\nRES -- Resident size (kb)\nThe non-swapped physical memory a task has used.\nRES = CODE + USED DATA.\n\nCODE -- Code size (kb)\nThe amount of physical memory devoted to executable code, also known as the 'text resident set' size or TRS\n\nDATA -- Data+Stack size (kb)\nThe amount of physical memory allocated to other than executable code, also known as the 'data resident set' size or DRS.\n\nSHR -- Shared Mem size (kb)\nThe amount of shared memory used by a task. It simply reflects memory that could be potentially shared with other processes.", "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/VIRT.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#73BF69", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/DATA.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/CODE.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF9830", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/RES.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FADE2A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/SHR.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#5794F2", + "mode": "fixed" + } + } + ] + } + ] }, - "fill": 1, - "fillGradient": 2, "gridPos": { "h": 7, "w": 8, "x": 0, "y": 46 }, - "hiddenSeries": false, "id": 46, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, "links": [ { "targetBlank": true, @@ -2794,142 +3276,130 @@ "url": "https://elinux.org/Runtime_Memory_Measurement" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - { - "alias": "/VIRT.+/", - "color": "#73BF69" + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - { - "alias": "/DATA.+/", - "color": "#C4162A" - }, - { - "alias": "/CODE.+/", - "color": "#FF9830" - }, - { - "alias": "/RES.+/", - "color": "#FADE2A" - }, - { - "alias": "/SHR.+/", - "color": "#5794F2" + "tooltip": { + "mode": "multi", + "sort": "none" } - ], - "spaceLength": 10, - "stack": false, - "steppedLine": true, + }, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "chi_clickhouse_metric_MemoryCode{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_MemoryCode{chi=~\"$chi\",hostname=~\"$hostname\"}", "legendFormat": "CODE {{ hostname }}", "refId": "A" }, { - "expr": "chi_clickhouse_metric_MemoryResident{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_MemoryResident{chi=~\"$chi\",hostname=~\"$hostname\"}", "legendFormat": "RES {{ hostname }}", "refId": "B" }, { - "expr": "chi_clickhouse_metric_MemoryShared{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_MemoryShared{chi=~\"$chi\",hostname=~\"$hostname\"}", "legendFormat": "SHR {{ hostname }}", "refId": "C" }, { - "expr": "chi_clickhouse_metric_MemoryDataAndStack{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_MemoryDataAndStack{chi=~\"$chi\",hostname=~\"$hostname\"}", "legendFormat": "DATA {{ hostname }}", "refId": "D" }, { - "expr": "chi_clickhouse_metric_MemoryVirtual{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_MemoryVirtual{chi=~\"$chi\",hostname=~\"$hostname\"}", "legendFormat": "VIRT {{ hostname }}", "refId": "E" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": " clickhouse-server Process Memory", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "Memory size allocated for primary keys", "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 7, "w": 8, "x": 8, "y": 46 }, - "hiddenSeries": false, "id": 45, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, "links": [ { "targetBlank": true, @@ -2937,101 +3407,98 @@ "url": "https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#selecting-the-primary-key" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "chi_clickhouse_metric_MemoryPrimaryKeyBytesAllocated{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_MemoryPrimaryKeyBytesAllocated{chi=~\"$chi\",hostname=~\"$hostname\"}", "legendFormat": "{{ hostname }}", "refId": "A" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Primary Keys Memory", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "Memory size allocated for dictionaries", "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 7, "w": 8, "x": 16, "y": 46 }, - "hiddenSeries": false, "id": 43, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, "links": [ { "targetBlank": true, @@ -3044,101 +3511,99 @@ "url": "https://clickhouse.com/docs/en/sql-reference/statements/create/dictionary" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "chi_clickhouse_metric_MemoryDictionaryBytesAllocated{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_MemoryDictionaryBytesAllocated{chi=~\"$chi\",hostname=~\"$hostname\"}", "legendFormat": "{{ hostname }}", "refId": "A" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Dictionary Memory", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, "description": "shows how much space available in the kubernetes pod\n\nbe careful with multiple volumes configuration, kubernetes volume claims and S3 as storage backend", "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 7, "w": 8, "x": 0, "y": 53 }, - "hiddenSeries": false, "id": 39, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, "links": [ { "targetBlank": true, @@ -3151,102 +3616,330 @@ "url": "https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#table_engine-mergetree-multiple-volumes" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "chi_clickhouse_metric_DiskFreeBytes{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"} / chi_clickhouse_metric_DiskTotalBytes{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_DiskFreeBytes{chi=~\"$chi\",hostname=~\"$hostname\"} / chi_clickhouse_metric_DiskTotalBytes{chi=~\"$chi\",hostname=~\"$hostname\"}", "legendFormat": "{{ disk }} {{hostname}}", "refId": "A" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Disk Space Free", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "decimals": null, - "format": "percentunit", - "label": null, - "logBase": 1, - "max": "1", - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "description": "Total data size for all ClickHouse *MergeTree tables\n\n", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Bytes" + }, + "properties": [ + { + "id": "unit", + "value": "decbytes" + }, + { + "id": "custom.cellOptions", + "value": { + "mode": "gradient", + "type": "gauge" + } + }, + { + "id": "color", + "value": { + "mode": "continuous-BlPu" + } + }, + { + "id": "custom.width", + "value": 233 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Rows" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "custom.width", + "value": 118 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "database" + }, + "properties": [ + { + "id": "custom.width", + "value": 199 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "table" + }, + "properties": [ + { + "id": "custom.width", + "value": 238 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Parts" + }, + "properties": [ + { + "id": "custom.width", + "value": 101 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "BytePerRow" + }, + "properties": [ + { + "id": "custom.width", + "value": 120 + } + ] + } + ] }, - "fill": 1, - "fillGradient": 0, "gridPos": { - "h": 7, - "w": 8, + "h": 14, + "w": 16, "x": 8, "y": 53 }, - "hiddenSeries": false, - "id": 41, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false + "id": 61, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": true + }, + "frameIndex": 2, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Bytes" + } + ] }, - "lines": true, - "linewidth": 1, + "pluginVersion": "10.4.3", + "targets": [ + { + "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (database, table) (chi_clickhouse_table_parts_bytes{chi=~\"$chi\",hostname=~\"$hostname\", active=\"1\"})", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "legendFormat": "Bytes", + "refId": "Bytes" + }, + { + "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (database, table) (chi_clickhouse_table_parts_rows{chi=~\"$chi\",hostname=~\"$hostname\", active=\"1\"})", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "legendFormat": "Rows", + "refId": "Rows" + }, + { + "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "editorMode": "code", + "exemplar": false, + "expr": "sum by (database, table) (chi_clickhouse_table_parts{chi=~\"$chi\",hostname=~\"$hostname\", active=\"1\"})", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "legendFormat": "Parts", + "refId": "Parts" + } + ], + "title": "Table Stats", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true + }, + "indexByName": {}, + "renameByName": { + "Value #Bytes": "Bytes", + "Value #Parts": "Parts", + "Value #Rows": "Rows" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "BytePerRow", + "binary": { + "left": "Bytes", + "operator": "/", + "reducer": "sum", + "right": "Rows" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "Total data size for all ClickHouse *MergeTree tables\n\n", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 60 + }, + "id": 41, "links": [ { "targetBlank": true, @@ -3254,107 +3947,1390 @@ "url": "https://clickhouse.com/docs/en/operations/system-tables/parts" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "chi_clickhouse_metric_DiskDataBytes{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_DiskDataBytes{chi=~\"$chi\",hostname=~\"$hostname\"}", "legendFormat": "{{ hostname }}", "refId": "A" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Clickhouse Data size on Disk", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "description": "Show different types of connections for each server", - "editable": true, - "error": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "BackgroundPoolTask\t\n---\nNumber of active tasks in BackgroundProcessingPool (merges, mutations, fetches, or replication queue bookkeeping)\n\n\nBackgroundMovePoolTask\n---\nNumber of active tasks in BackgroundProcessingPool for moves\n\n\nBackgroundSchedulePoolTask\t\n---\nA number of active tasks in BackgroundSchedulePool. This pool is used for periodic ReplicatedMergeTree tasks, like cleaning old data parts, altering data parts, replica re-initialization, etc.", "fieldConfig": { "defaults": { - "links": [] + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 67 + }, + "id": 9, + "links": [ + { + "targetBlank": true, + "title": "FETCH PARTITION", + "url": "https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#fetch-partitionpart" + }, + { + "targetBlank": true, + "title": "Mutations of data", + "url": "https://clickhouse.com/docs/en/sql-reference/statements/alter#mutations" + }, + { + "targetBlank": true, + "title": "Data TTL", + "url": "https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#table_engine-mergetree-ttl" + }, + { + "targetBlank": true, + "title": "MOVE PARTITION", + "url": "https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#move-partitionpart" + } + ], + "options": { + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.3", + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_BackgroundPoolTask{chi=~\"$chi\",hostname=~\"$hostname\"}", + "intervalFactor": 2, + "legendFormat": "merge, mutate, fetch {{hostname}}", + "refId": "A", + "step": 10 + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_BackgroundSchedulePoolTask{chi=~\"$chi\",hostname=~\"$hostname\"}", + "intervalFactor": 2, + "legendFormat": "clean, alter, replica re-init {{hostname}}", + "refId": "B", + "step": 10 + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_BackgroundMovePoolTask{chi=~\"$chi\",hostname=~\"$hostname\"}", + "intervalFactor": 2, + "legendFormat": "moves {{hostname}}", + "refId": "C", + "step": 10 + } + ], + "title": "Background Tasks", + "type": "timeseries" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "Number of active mutations (ALTER DELETE/ALTER UPDATE) and parts to mutate", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 67 + }, + "id": 26, + "links": [ + { + "targetBlank": true, + "title": "Mutations", + "url": "https://clickhouse.com/docs/en/sql-reference/statements/alter#mutations" + }, + { + "targetBlank": true, + "title": "system.mutations", + "url": "https://clickhouse.com/docs/en/operations/system-tables/mutations" + }, + { + "targetBlank": true, + "title": "KILL MUTATION", + "url": "https://clickhouse.com/docs/en/sql-reference/statements/kill#kill-mutation" + } + ], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.3", + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum by (hostname) (chi_clickhouse_table_mutations{chi=~\"$chi\",hostname=~\"$hostname\"})", + "legendFormat": "mutations {{hostname}}", + "refId": "A" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum by (hostname) (chi_clickhouse_table_mutations_parts_to_do{chi=~\"$chi\",hostname=~\"$hostname\"})", + "legendFormat": "parts_to_do {{hostname}}", + "refId": "B" + } + ], + "title": "Mutations", + "type": "timeseries" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "Show which percent of mark files (.mrk) read from memory instead of disk", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, - "grid": {}, "gridPos": { "h": 7, "w": 8, "x": 16, - "y": 53 + "y": 67 }, - "hiddenSeries": false, - "id": 48, - "isNew": true, + "id": 11, + "links": [ + { + "targetBlank": true, + "title": "mark_cache_size", + "url": "https://clickhouse.com/docs/en/operations/server-configuration-parameters/settings/#server-mark-cache-size" + }, + { + "targetBlank": true, + "title": "MergeTree architecture", + "url": "https://clickhouse.com/docs/en/development/architecture/#merge-tree" + } + ], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.3", + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_MarkCacheHits{chi=~\"$chi\",hostname=~\"$hostname\"}[1m]) / (irate(chi_clickhouse_event_MarkCacheHits{chi=~\"$chi\",hostname=~\"$hostname\"}[1m]) + irate(chi_clickhouse_event_MarkCacheMisses{chi=~\"$chi\",hostname=~\"$hostname\"}[1m]))", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{hostname}}", + "refId": "A", + "step": 4 + } + ], + "title": "Marks Cache Hit Rate", + "type": "timeseries" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "The time which CPU spent on various types of activity ", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "µs" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^Disk Read.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF9830", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^Disk Write.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0B400", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^Real Time.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#73BF69", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^User Time.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFF899", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^System Time.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^OS IO Wait.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^OS CPU Wait.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "rgb(95, 29, 29)", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^OS CPU Virtual.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B877D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^Network Receive.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C0D8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^Network Send.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 74 + }, + "id": 51, + "interval": "", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.3", + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_DiskReadElapsedMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "hide": true, + "legendFormat": "Disk Read syscall {{hostname}}", + "refId": "A" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_DiskWriteElapsedMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "hide": true, + "legendFormat": "Disk Write syscall {{hostname}}", + "refId": "B" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_NetworkReceiveElapsedMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "hide": true, + "legendFormat": "Network Receive {{hostname}}", + "refId": "C" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_NetworkSendElapsedMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "hide": true, + "legendFormat": "Network Send {{hostname}}", + "refId": "D" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_RealTimeMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "Real Time {{hostname}}", + "refId": "E" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_UserTimeMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "User Time {{hostname}}", + "refId": "F" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_SystemTimeMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "System Time {{hostname}}", + "refId": "G" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_OSIOWaitMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "OS IO Wait {{hostname}}", + "refId": "H" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_OSCPUWaitMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "OS CPU Wait {{hostname}}", + "refId": "I" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_OSCPUVirtualTimeMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "OS CPU Virtual {{hostname}}", + "refId": "J" + } + ], + "title": "CPU Time per second", + "type": "timeseries" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "The time which CPU spent on various types of activity ", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "µs" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^Disk Read.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FF9830", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^Disk Write.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#E0B400", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^Real Time.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#73BF69", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^User Time.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#FFF899", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^System Time.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^OS IO Wait.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C4162A", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^OS CPU Wait.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "rgb(95, 29, 29)", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^OS CPU Virtual.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#B877D9", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^Network Receive.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#C0D8FF", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^Network Send.+/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#8AB8FF", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 74 + }, + "id": 54, + "interval": "", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.3", + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_DiskReadElapsedMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "hide": false, + "legendFormat": "Disk Read syscall {{hostname}}", + "refId": "A" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_DiskWriteElapsedMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "hide": false, + "legendFormat": "Disk Write syscall {{hostname}}", + "refId": "B" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_NetworkReceiveElapsedMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "hide": false, + "legendFormat": "Network Receive {{hostname}}", + "refId": "C" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(chi_clickhouse_event_NetworkSendElapsedMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "hide": false, + "legendFormat": "Network Send {{hostname}}", + "refId": "D" + } + ], + "title": "Network / Disk CPU Time per second", + "type": "timeseries" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 74 + }, + "id": 55, + "interval": "", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.4.3", + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": true, + "expr": "chi_clickhouse_metric_LoadAverage1{chi=~\"$chi\",hostname=~\"$hostname\"}", + "hide": false, + "interval": "", + "legendFormat": "{{hostname}}", + "refId": "A" + } + ], + "title": "Load Average 1m", + "type": "timeseries" + }, + { + "aliasColors": {}, + "breakPoint": "50%", + "combine": { + "label": "Others", + "threshold": "0.01" + }, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "The time which CPU spent on various types of activity total for the selected period", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "unit": "µs" + }, + "overrides": [] + }, + "fontSize": "80%", + "format": "µs", + "gridPos": { + "h": 7, + "w": 16, + "x": 0, + "y": 81 + }, + "id": 52, + "interval": "1m", "legend": { - "avg": false, - "current": false, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false + "header": "", + "percentage": true, + "show": true, + "sort": "total", + "sortDesc": true, + "values": true }, - "lines": true, - "linewidth": 2, + "legendType": "Right side", + "nullPointMode": "connected", + "options": { + "legend": { + "displayMode": "list", + "placement": "right", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pieType": "pie", + "strokeWidth": "", + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_DiskReadElapsedMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "Disk Read syscall {{hostname}}", + "refId": "A" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_DiskWriteElapsedMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "Disk Write syscall {{hostname}}", + "refId": "B" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_NetworkReceiveElapsedMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "Network Receive {{hostname}}", + "refId": "C" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_NetworkSendElapsedMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "Network Send {{hostname}}", + "refId": "D" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_RealTimeMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "Real Time {{hostname}}", + "refId": "E" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_UserTimeMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "User Time {{hostname}}", + "refId": "F" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_SystemTimeMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "System Time {{hostname}}", + "refId": "G" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_OSIOWaitMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "OS IO Wait {{hostname}}", + "refId": "H" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_OSCPUWaitMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "OS CPU Wait {{hostname}}", + "refId": "I" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_OSCPUVirtualTimeMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "OS CPU Virtual {{hostname}}", + "refId": "J" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_ThrottlerSleepMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "Throttler Sleep {{hostname}}", + "refId": "K" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_DelayedInsertsMilliseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m]) * 1000", + "legendFormat": "Delayed Insert {{hostname}}", + "refId": "L" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_ZooKeeperWaitMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "Zookeeper Wait {{hostname}}", + "refId": "M" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_CompileExpressionsMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "Compile Expressions {{hostname}}", + "refId": "N" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_MergesTimeMilliseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m]) * 1000", + "legendFormat": "Merges {{hostname}}", + "refId": "O" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_RWLockReadersWaitMilliseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m]) * 1000", + "legendFormat": "RWLock Reader Wait {{hostname}}", + "refId": "P" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_RWLockWritersWaitMilliseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m]) * 1000", + "legendFormat": "RWLock Writer Wait {{hostname}}", + "refId": "Q" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_SelectQueryTimeMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "Select Query {{hostname}}", + "refId": "R" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_InsertQueryTimeMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "Insert Query {{hostname}}", + "refId": "S" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_S3ReadMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "S3 Read {{hostname}}", + "refId": "T" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "increase(chi_clickhouse_event_S3WriteMicroseconds{chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", + "legendFormat": "S3 Write {{hostname}}", + "refId": "U" + } + ], + "title": "CPU Time total", + "type": "piechart", + "valueName": "total" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "Show different types of connections for each server", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "stepAfter", + "lineWidth": 2, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 81 + }, + "id": 48, "links": [ { "targetBlank": true, @@ -3382,1188 +5358,69 @@ "url": "https://clickhouse.com/docs/en/interfaces/tcp/" } ], - "nullPointMode": "null", "options": { - "alertThreshold": true + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": true, + "pluginVersion": "10.4.3", "targets": [ { - "expr": "chi_clickhouse_metric_TCPConnection{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_TCPConnection{chi=~\"$chi\",hostname=~\"$hostname\"}", "intervalFactor": 2, "legendFormat": "tcp {{hostname}}", "refId": "A", "step": 10 }, { - "expr": "chi_clickhouse_metric_HTTPConnection{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_HTTPConnection{chi=~\"$chi\",hostname=~\"$hostname\"}", "intervalFactor": 2, "legendFormat": "http {{hostname}}", "refId": "B", "step": 10 }, { - "expr": "chi_clickhouse_metric_InterserverConnection{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_InterserverConnection{chi=~\"$chi\",hostname=~\"$hostname\"}", "intervalFactor": 2, "legendFormat": "interserver {{hostname}}", "refId": "C", "step": 10 }, { - "expr": "chi_clickhouse_metric_MySQLConnection{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "chi_clickhouse_metric_MySQLConnection{chi=~\"$chi\",hostname=~\"$hostname\"}", "intervalFactor": 2, "legendFormat": "mysql {{hostname}}", "refId": "D", "step": 10 } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Connections", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "description": "BackgroundPoolTask\t\n---\nNumber of active tasks in BackgroundProcessingPool (merges, mutations, fetches, or replication queue bookkeeping)\n\n\nBackgroundMovePoolTask\n---\nNumber of active tasks in BackgroundProcessingPool for moves\n\n\nBackgroundSchedulePoolTask\t\n---\nA number of active tasks in BackgroundSchedulePool. This pool is used for periodic ReplicatedMergeTree tasks, like cleaning old data parts, altering data parts, replica re-initialization, etc.", - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": {}, - "gridPos": { - "h": 7, - "w": 8, - "x": 0, - "y": 60 - }, - "hiddenSeries": false, - "id": 9, - "isNew": true, - "legend": { - "avg": false, - "current": true, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [ - { - "targetBlank": true, - "title": "FETCH PARTITION", - "url": "https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#fetch-partitionpart" - }, - { - "targetBlank": true, - "title": "Mutations of data", - "url": "https://clickhouse.com/docs/en/sql-reference/statements/alter#mutations" - }, - { - "targetBlank": true, - "title": "Data TTL", - "url": "https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#table_engine-mergetree-ttl" - }, - { - "targetBlank": true, - "title": "MOVE PARTITION", - "url": "https://clickhouse.com/docs/en/sql-reference/statements/alter/partition#move-partitionpart" - } - ], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": true, - "targets": [ - { - "expr": "chi_clickhouse_metric_BackgroundPoolTask{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", - "intervalFactor": 2, - "legendFormat": "merge, mutate, fetch {{hostname}}", - "refId": "A", - "step": 10 - }, - { - "expr": "chi_clickhouse_metric_BackgroundSchedulePoolTask{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", - "intervalFactor": 2, - "legendFormat": "clean, alter, replica re-init {{hostname}}", - "refId": "B", - "step": 10 - }, - { - "expr": "chi_clickhouse_metric_BackgroundMovePoolTask{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", - "intervalFactor": 2, - "legendFormat": "moves {{hostname}}", - "refId": "C", - "step": 10 - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Background Tasks", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "description": "Number of active mutations (ALTER DELETE/ALTER UPDATE) and parts to mutate", - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "gridPos": { - "h": 7, - "w": 8, - "x": 8, - "y": 60 - }, - "hiddenSeries": false, - "id": 26, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [ - { - "targetBlank": true, - "title": "Mutations", - "url": "https://clickhouse.com/docs/en/sql-reference/statements/alter#mutations" - }, - { - "targetBlank": true, - "title": "system.mutations", - "url": "https://clickhouse.com/docs/en/operations/system-tables/mutations/" - }, - { - "targetBlank": true, - "title": "KILL MUTATION", - "url": "https://clickhouse.com/docs/en/sql-reference/statements/kill#kill-mutation" - } - ], - "nullPointMode": "null as zero", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": true, - "targets": [ - { - "expr": "sum by (hostname) (chi_clickhouse_table_mutations{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"})", - "legendFormat": "mutations {{hostname}}", - "refId": "A" - }, - { - "expr": "sum by (hostname) (chi_clickhouse_table_mutations_parts_to_do{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"})", - "legendFormat": "parts_to_do {{hostname}}", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Mutations", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "description": "Show which percent of mark files (.mrk) read from memory instead of disk", - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": {}, - "gridPos": { - "h": 7, - "w": 8, - "x": 16, - "y": 60 - }, - "hiddenSeries": false, - "id": 11, - "isNew": true, - "legend": { - "avg": false, - "current": false, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 2, - "links": [ - { - "targetBlank": true, - "title": "mark_cache_size", - "url": "https://clickhouse.com/docs/en/operations/server-configuration-parameters/settings/#server-mark-cache-size" - }, - { - "targetBlank": true, - "title": "MergeTree architecture", - "url": "https://clickhouse.com/docs/en/development/architecture/#merge-tree" - } - ], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "rate(chi_clickhouse_event_MarkCacheHits{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m]) / (rate(chi_clickhouse_event_MarkCacheHits{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m]) + rate(chi_clickhouse_event_MarkCacheMisses{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m]))", - "hide": false, - "intervalFactor": 2, - "legendFormat": "{{hostname}}", - "refId": "A", - "step": 4 - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Marks Cache Hit Rate", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "percentunit", - "label": "", - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "description": "The time which CPU spent on various types of activity ", - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 1, - "gridPos": { - "h": 7, - "w": 8, - "x": 0, - "y": 67 - }, - "hiddenSeries": false, - "id": 51, - "interval": "", - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - { - "alias": "/^Disk Read.+/", - "color": "#FF9830" - }, - { - "alias": "/^Disk Write.+/", - "color": "#E0B400" - }, - { - "alias": "/^Real Time.+/", - "color": "#73BF69" - }, - { - "alias": "/^User Time.+/", - "color": "#FFF899" - }, - { - "alias": "/^System Time.+/", - "color": "#F2495C" - }, - { - "alias": "/^OS IO Wait.+/", - "color": "#C4162A" - }, - { - "alias": "/^OS CPU Wait.+/", - "color": "rgb(95, 29, 29)" - }, - { - "alias": "/^OS CPU Virtual.+/", - "color": "#B877D9" - }, - { - "alias": "/^Network Receive.+/", - "color": "#C0D8FF" - }, - { - "alias": "/^Network Send.+/", - "color": "#8AB8FF" - } - ], - "spaceLength": 10, - "stack": false, - "steppedLine": true, - "targets": [ - { - "expr": "rate(chi_clickhouse_event_DiskReadElapsedMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "hide": true, - "legendFormat": "Disk Read syscall {{hostname}}", - "refId": "A" - }, - { - "expr": "rate(chi_clickhouse_event_DiskWriteElapsedMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "hide": true, - "legendFormat": "Disk Write syscall {{hostname}}", - "refId": "B" - }, - { - "expr": "rate(chi_clickhouse_event_NetworkReceiveElapsedMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "hide": true, - "legendFormat": "Network Receive {{hostname}}", - "refId": "C" - }, - { - "expr": "rate(chi_clickhouse_event_NetworkSendElapsedMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "hide": true, - "legendFormat": "Network Send {{hostname}}", - "refId": "D" - }, - { - "expr": "rate(chi_clickhouse_event_RealTimeMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "Real Time {{hostname}}", - "refId": "E" - }, - { - "expr": "rate(chi_clickhouse_event_UserTimeMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "User Time {{hostname}}", - "refId": "F" - }, - { - "expr": "rate(chi_clickhouse_event_SystemTimeMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "System Time {{hostname}}", - "refId": "G" - }, - { - "expr": "rate(chi_clickhouse_event_OSIOWaitMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "OS IO Wait {{hostname}}", - "refId": "H" - }, - { - "expr": "rate(chi_clickhouse_event_OSCPUWaitMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "OS CPU Wait {{hostname}}", - "refId": "I" - }, - { - "expr": "rate(chi_clickhouse_event_OSCPUVirtualTimeMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "OS CPU Virtual {{hostname}}", - "refId": "J" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "CPU Time per second", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "µs", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "breakPoint": "50%", - "cacheTimeout": null, - "combine": { - "label": "Others", - "threshold": "0.01" - }, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "description": "The time which CPU spent on various types of activity total for the selected period", - "fieldConfig": { - "defaults": {}, - "overrides": [] - }, - "fontSize": "80%", - "format": "µs", - "gridPos": { - "h": 7, - "w": 16, - "x": 8, - "y": 67 - }, - "id": 52, - "interval": "1m", - "legend": { - "header": "", - "percentage": true, - "show": true, - "sideWidth": null, - "sort": "total", - "sortDesc": true, - "values": true - }, - "legendType": "Right side", - "links": [], - "nullPointMode": "connected", - "pieType": "pie", - "strokeWidth": "", - "targets": [ - { - "expr": "increase(chi_clickhouse_event_DiskReadElapsedMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "Disk Read syscall {{hostname}}", - "refId": "A" - }, - { - "expr": "increase(chi_clickhouse_event_DiskWriteElapsedMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "Disk Write syscall {{hostname}}", - "refId": "B" - }, - { - "expr": "increase(chi_clickhouse_event_NetworkReceiveElapsedMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "Network Receive {{hostname}}", - "refId": "C" - }, - { - "expr": "increase(chi_clickhouse_event_NetworkSendElapsedMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "Network Send {{hostname}}", - "refId": "D" - }, - { - "expr": "increase(chi_clickhouse_event_RealTimeMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "Real Time {{hostname}}", - "refId": "E" - }, - { - "expr": "increase(chi_clickhouse_event_UserTimeMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "User Time {{hostname}}", - "refId": "F" - }, - { - "expr": "increase(chi_clickhouse_event_SystemTimeMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "System Time {{hostname}}", - "refId": "G" - }, - { - "expr": "increase(chi_clickhouse_event_OSIOWaitMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "OS IO Wait {{hostname}}", - "refId": "H" - }, - { - "expr": "increase(chi_clickhouse_event_OSCPUWaitMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "OS CPU Wait {{hostname}}", - "refId": "I" - }, - { - "expr": "increase(chi_clickhouse_event_OSCPUVirtualTimeMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "OS CPU Virtual {{hostname}}", - "refId": "J" - }, - { - "expr": "increase(chi_clickhouse_event_ThrottlerSleepMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "Throttler Sleep {{hostname}}", - "refId": "K" - }, - { - "expr": "increase(chi_clickhouse_event_DelayedInsertsMilliseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m]) * 1000", - "legendFormat": "Delayed Insert {{hostname}}", - "refId": "L" - }, - { - "expr": "increase(chi_clickhouse_event_ZooKeeperWaitMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "Zookeeper Wait {{hostname}}", - "refId": "M" - }, - { - "expr": "increase(chi_clickhouse_event_CompileExpressionsMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "Compile Expressions {{hostname}}", - "refId": "N" - }, - { - "expr": "increase(chi_clickhouse_event_MergesTimeMilliseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m]) * 1000", - "legendFormat": "Merges {{hostname}}", - "refId": "O" - }, - { - "expr": "increase(chi_clickhouse_event_RWLockReadersWaitMilliseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m]) * 1000", - "legendFormat": "RWLock Reader Wait {{hostname}}", - "refId": "P" - }, - { - "expr": "increase(chi_clickhouse_event_RWLockWritersWaitMilliseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m]) * 1000", - "legendFormat": "RWLock Writer Wait {{hostname}}", - "refId": "Q" - }, - { - "expr": "increase(chi_clickhouse_event_SelectQueryTimeMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "Select Query {{hostname}}", - "refId": "R" - }, - { - "expr": "increase(chi_clickhouse_event_InsertQueryTimeMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "Insert Query {{hostname}}", - "refId": "S" - }, - { - "expr": "increase(chi_clickhouse_event_S3ReadMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "S3 Read {{hostname}}", - "refId": "T" - }, - { - "expr": "increase(chi_clickhouse_event_S3WriteMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "legendFormat": "S3 Write {{hostname}}", - "refId": "U" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "CPU Time total", - "type": "piechart", - "valueName": "total" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "description": "The time which CPU spent on various types of activity ", - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 1, - "gridPos": { - "h": 7, - "w": 8, - "x": 0, - "y": 74 - }, - "hiddenSeries": false, - "id": 54, - "interval": "", - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - { - "alias": "/^Disk Read.+/", - "color": "#FF9830" - }, - { - "alias": "/^Disk Write.+/", - "color": "#E0B400" - }, - { - "alias": "/^Real Time.+/", - "color": "#73BF69" - }, - { - "alias": "/^User Time.+/", - "color": "#FFF899" - }, - { - "alias": "/^System Time.+/", - "color": "#F2495C" - }, - { - "alias": "/^OS IO Wait.+/", - "color": "#C4162A" - }, - { - "alias": "/^OS CPU Wait.+/", - "color": "rgb(95, 29, 29)" - }, - { - "alias": "/^OS CPU Virtual.+/", - "color": "#B877D9" - }, - { - "alias": "/^Network Receive.+/", - "color": "#C0D8FF" - }, - { - "alias": "/^Network Send.+/", - "color": "#8AB8FF" - } - ], - "spaceLength": 10, - "stack": false, - "steppedLine": true, - "targets": [ - { - "expr": "rate(chi_clickhouse_event_DiskReadElapsedMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "hide": false, - "legendFormat": "Disk Read syscall {{hostname}}", - "refId": "A" - }, - { - "expr": "rate(chi_clickhouse_event_DiskWriteElapsedMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "hide": false, - "legendFormat": "Disk Write syscall {{hostname}}", - "refId": "B" - }, - { - "expr": "rate(chi_clickhouse_event_NetworkReceiveElapsedMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "hide": false, - "legendFormat": "Network Receive {{hostname}}", - "refId": "C" - }, - { - "expr": "rate(chi_clickhouse_event_NetworkSendElapsedMicroseconds{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}[1m])", - "hide": false, - "legendFormat": "Network Send {{hostname}}", - "refId": "D" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Network / Disk CPU Time per second", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:193", - "format": "µs", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "$$hashKey": "object:194", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "description": "", - "editable": true, - "error": false, - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 0, - "grid": {}, - "gridPos": { - "h": 7, - "w": 8, - "x": 8, - "y": 74 - }, - "hiddenSeries": false, - "id": 24, - "isNew": true, - "legend": { - "avg": false, - "current": false, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 2, - "links": [ - { - "targetBlank": true, - "title": "Howto show detail statistic on grafana for golang process", - "url": "https://grafana.com/grafana/dashboards/6671" - } - ], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "rate(go_memstats_alloc_bytes_total{app=\"clickhouse-operator\",namespace=~\"$exported_namespace|kube-system\"}[1m])", - "hide": false, - "legendFormat": "{{ namespace }} GO malloc bytes / sec", - "refId": "A" - }, - { - "expr": "process_resident_memory_bytes{app=\"clickhouse-operator\",namespace=~\"$exported_namespace|kube-system\"}", - "legendFormat": "{{ namespace }} RSS Memory", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Monitoring Agent", - "tooltip": { - "msResolution": false, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "description": "", - "fieldConfig": { - "defaults": { - "links": [] - }, - "overrides": [] - }, - "fill": 1, - "fillGradient": 1, - "gridPos": { - "h": 7, - "w": 8, - "x": 16, - "y": 74 - }, - "hiddenSeries": false, - "id": 55, - "interval": "", - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "options": { - "alertThreshold": true - }, - "percentage": false, - "pluginVersion": "7.5.15", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": true, - "targets": [ - { - "exemplar": true, - "expr": "chi_clickhouse_metric_LoadAverage1{exported_namespace=~\"$exported_namespace\",chi=~\"$chi\",hostname=~\"$hostname\"}", - "hide": false, - "interval": "", - "legendFormat": "{{hostname}}", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Load Average 1m", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:193", - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "$$hashKey": "object:194", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" } ], "refresh": "1m", - "schemaVersion": 27, + "schemaVersion": 38, "style": "dark", - "tags": [ - "Altinity", - "clickhouse", - "operator" - ], + "tags": [], "templating": { "list": [ { @@ -4585,48 +5442,48 @@ "type": "datasource" }, { - "allValue": ".*", - "current": {}, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "definition": "label_values({__name__ =~ \"chi_clickhouse_metric_Uptime|chi_clickhouse_metric_fetch_errors\"}, exported_namespace)", - "description": null, - "error": null, - "hide": 0, - "includeAll": true, - "label": "K8S Namespace", - "multi": true, - "name": "exported_namespace", - "options": [], - "query": { - "query": "label_values({__name__ =~ \"chi_clickhouse_metric_Uptime|chi_clickhouse_metric_fetch_errors\"}, exported_namespace)", - "refId": "clickhouse-operator-prometheus-exported_namespace-Variable-Query" + "current": { + "selected": false, + "text": "prometheus", + "value": "prometheus" }, - "refresh": 2, + "hide": 2, + "includeAll": false, + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, "regex": "", "skipUrlSync": false, - "sort": 1, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false + "type": "datasource" }, { "allValue": ".*", - "current": {}, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "definition": "label_values({__name__ =~ \"chi_clickhouse_metric_Uptime|chi_clickhouse_metric_fetch_errors\", exported_namespace=~\"$exported_namespace\"}, chi)", - "description": null, - "error": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values({__name__ =~ \"chi_clickhouse_metric_Uptime|chi_clickhouse_metric_fetch_errors\"}, chi)", "hide": 0, "includeAll": true, - "label": "K8S Clickhouse Installation", + "label": "Cluster", "multi": true, "name": "chi", "options": [], "query": { - "query": "label_values({__name__ =~ \"chi_clickhouse_metric_Uptime|chi_clickhouse_metric_fetch_errors\", exported_namespace=~\"$exported_namespace\"}, chi)", - "refId": "clickhouse-operator-prometheus-chi-Variable-Query" + "query": "label_values({__name__ =~ \"chi_clickhouse_metric_Uptime|chi_clickhouse_metric_fetch_errors\"}, chi)", + "refId": "StandardVariableQuery" }, "refresh": 2, "regex": "", @@ -4640,11 +5497,20 @@ }, { "allValue": ".*", - "current": {}, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "definition": "label_values({__name__ =~ \"chi_clickhouse_metric_Uptime|chi_clickhouse_metric_fetch_errors\",exported_namespace=~\"$exported_namespace\",chi=~\"$chi\"}, hostname)", - "description": null, - "error": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values({__name__ =~ \"chi_clickhouse_metric_Uptime|chi_clickhouse_metric_fetch_errors\",chi=~\"$chi\"}, hostname)", "hide": 0, "includeAll": true, "label": "Server", @@ -4652,8 +5518,8 @@ "name": "hostname", "options": [], "query": { - "query": "label_values({__name__ =~ \"chi_clickhouse_metric_Uptime|chi_clickhouse_metric_fetch_errors\",exported_namespace=~\"$exported_namespace\",chi=~\"$chi\"}, hostname)", - "refId": "clickhouse-operator-prometheus-hostname-Variable-Query" + "query": "label_values({__name__ =~ \"chi_clickhouse_metric_Uptime|chi_clickhouse_metric_fetch_errors\",chi=~\"$chi\"}, hostname)", + "refId": "StandardVariableQuery" }, "refresh": 2, "regex": "", @@ -4698,5 +5564,6 @@ "timezone": "browser", "title": "Altinity ClickHouse Operator Dashboard", "uid": "clickhouse-operator", - "version": 20220908 + "version": 20092024, + "weekStart": "" } diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/files/ClickHouseKeeper_dashboard.json b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/files/ClickHouseKeeper_dashboard.json index 819cd519..566f6824 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/files/ClickHouseKeeper_dashboard.json +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/files/ClickHouseKeeper_dashboard.json @@ -9,31 +9,35 @@ "pluginName": "Prometheus" } ], + "__elements": {}, "__requires": [ { "type": "grafana", "id": "grafana", "name": "Grafana", - "version": "7.1.1" - }, - { - "type": "panel", - "id": "graph", - "name": "Graph", - "version": "" + "version": "11.3.0" }, { "type": "datasource", "id": "prometheus", "name": "Prometheus", "version": "1.0.0" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" } ], "annotations": { "list": [ { "builtIn": 1, - "datasource": "-- Grafana --", + "datasource": { + "type": "datasource", + "uid": "grafana" + }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", @@ -41,7 +45,10 @@ "type": "dashboard" }, { - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "enable": true, "expr": "ALERTS{app=~\"clickhouse-keeper.*\"}", "hide": false, @@ -55,882 +62,921 @@ ] }, "editable": true, - "gnetId": null, + "fiscalYearStartMonth": 0, "graphTooltip": 1, "id": null, - "iteration": 1644828395145, "links": [], "panels": [ { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 9, "w": 8, "x": 0, "y": 0 }, - "hiddenSeries": false, "id": 2, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "percentage": false, - "pluginVersion": "7.1.1", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "11.3.0", "targets": [ { - "expr": "zk_avg_latency{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "ClickHouseAsyncMetrics_KeeperAvgLatency{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", "interval": "", "legendFormat": "avg {{namespace}}.{{pod_name}}", "refId": "A" }, { - "expr": "zk_max_latency{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "ClickHouseAsyncMetrics_KeeperMaxLatency{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", "interval": "", "legendFormat": "max {{namespace}}.{{pod_name}}", "refId": "B" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Latency", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:118", - "format": "ms", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:119", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 9, "w": 8, "x": 8, "y": 0 }, - "hiddenSeries": false, "id": 4, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "percentage": false, - "pluginVersion": "7.1.1", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "11.3.0", "targets": [ { - "expr": "zk_num_alive_connections{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "ClickHouseMetrics_KeeperAliveConnections{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", "hide": false, "interval": "", "legendFormat": "{{namespace}}.{{pod_name}}", "refId": "A" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Connections", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:118", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "$$hashKey": "object:119", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 9, "w": 8, "x": 16, "y": 0 }, - "hiddenSeries": false, "id": 3, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "percentage": false, - "pluginVersion": "7.1.1", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "11.3.0", "targets": [ { - "expr": "irate(zk_packets_sent{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}[1m])", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(ClickHouseAsyncMetrics_KeeperPacketsSent{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}[1m])", "hide": false, "interval": "", "legendFormat": "OUT {{namespace}}.{{pod_name}}", "refId": "A" }, { - "expr": "-irate(zk_packets_received{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}[1m])", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "-irate(ClickHouseAsyncMetrics_KeeperPacketsReceived{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}[1m])", "interval": "", "legendFormat": "IN {{namespace}}.{{pod_name}}", "refId": "B" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Packets per second", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:118", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:119", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 9, "w": 8, "x": 0, "y": 9 }, - "hiddenSeries": false, "id": 6, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "percentage": false, - "pluginVersion": "7.1.1", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "11.3.0", "targets": [ { - "expr": "zk_znode_count{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "ClickHouseAsyncMetrics_KeeperZnodeCount{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", "interval": "", "legendFormat": "{{namespace}}.{{pod_name}}", "refId": "A" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "ZNode count", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:118", - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:119", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 9, "w": 8, "x": 8, "y": 9 }, - "hiddenSeries": false, "id": 9, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "percentage": false, - "pluginVersion": "7.1.1", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "11.3.0", "targets": [ { - "expr": "zk_watch_count{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "ClickHouseAsyncMetrics_KeeperWatchCount{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", "interval": "", "legendFormat": "{{namespace}}.{{pod_name}}", "refId": "A" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Watch count", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:118", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "$$hashKey": "object:119", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 9, "w": 8, "x": 16, "y": 9 }, - "hiddenSeries": false, "id": 7, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "percentage": false, - "pluginVersion": "7.1.1", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "11.3.0", "targets": [ { - "expr": "zk_ephemerals_count{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "ClickHouseAsyncMetrics_KeeperEphemeralsCount{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", "interval": "", "legendFormat": "{{namespace}}.{{pod_name}}", "refId": "A" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, - "title": "Ethermals nodes", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:118", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "$$hashKey": "object:119", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "title": "Ephemeral Node count", + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 9, "w": 8, "x": 0, "y": 18 }, - "hiddenSeries": false, "id": 5, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "percentage": false, - "pluginVersion": "7.1.1", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "11.3.0", "targets": [ { - "expr": "zk_approximate_data_size{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "ClickHouseAsyncMetrics_KeeperApproximateDataSize{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", "interval": "", "legendFormat": "{{namespace}}.{{pod_name}}", "refId": "A" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Memory data size", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:118", - "format": "bytes", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "$$hashKey": "object:119", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, - "overrides": [] + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/.*/" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "#F2495C", + "mode": "fixed" + } + } + ] + } + ] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 9, "w": 8, "x": 8, "y": 18 }, - "hiddenSeries": false, "id": 8, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "percentage": false, - "pluginVersion": "7.1.1", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [ - { - "$$hashKey": "object:1855", - "alias": "/.*/", - "color": "#F2495C" + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" } - ], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + }, + "pluginVersion": "11.3.0", "targets": [ { - "expr": "irate(zk_outstanding_requests{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}[1m])", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "irate(ClickHouseMetrics_KeeperOutstandingRequests{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}[1m])", "interval": "", "legendFormat": "{{namespace}}.{{pod_name}}", "refId": "A" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Outstanding requests", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:118", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "$$hashKey": "object:119", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { - "custom": {} + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" }, "overrides": [] }, - "fill": 1, - "fillGradient": 0, "gridPos": { "h": 9, "w": 8, "x": 16, "y": 18 }, - "hiddenSeries": false, "id": 10, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": false, - "total": false, - "values": false + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } }, - "lines": true, - "linewidth": 1, - "nullPointMode": "null", - "percentage": false, - "pluginVersion": "7.1.1", - "pointradius": 2, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "pluginVersion": "11.3.0", "targets": [ { - "expr": "zk_open_file_descriptor_count{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "expr": "ClickHouseAsyncMetrics_KeeperOpenFileDescriptorCount{namespace=~\"$namespace\", pod_name=~\"$pod_name\", container_name=\"clickhouse-keeper\"}", "interval": "", "legendFormat": "{{namespace}}.{{pod_name}}", "refId": "A" } ], - "thresholds": [], - "timeFrom": null, - "timeRegions": [], - "timeShift": null, "title": "Open file descriptors", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "$$hashKey": "object:118", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "$$hashKey": "object:119", - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": false, - "alignLevel": null - } + "type": "timeseries" } ], - "refresh": false, - "schemaVersion": 26, - "style": "dark", + "refresh": "", + "schemaVersion": 40, "tags": [ "altinity", "clickhouse-keeper" @@ -958,46 +1004,44 @@ { "allValue": ".+", "current": {}, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "definition": "label_values(zk_ruok, namespace)", - "hide": 0, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(up{container_name=\"clickhouse-keeper\"},namespace)", "includeAll": true, - "label": null, "multi": true, "name": "namespace", "options": [], - "query": "label_values(zk_ruok, namespace)", + "query": { + "qryType": 1, + "query": "label_values(up{container_name=\"clickhouse-keeper\"},namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, "refresh": 2, "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false + "type": "query" }, { "allValue": ".+", "current": {}, - "datasource": {"type":"prometheus","uid":"${ds_prometheus}"}, - "definition": "label_values(zk_ruok, pod_name)", - "hide": 0, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(up{container_name=\"clickhouse-keeper\", namespace=~\"$namespace\"},pod_name)", "includeAll": true, - "label": null, "multi": true, "name": "pod_name", "options": [], - "query": "label_values(zk_ruok, pod_name)", + "query": { + "qryType": 1, + "query": "label_values(up{container_name=\"clickhouse-keeper\", namespace=~\"$namespace\"},pod_name)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, "refresh": 2, "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false + "type": "query" } ] }, @@ -1021,5 +1065,6 @@ "timezone": "", "title": "ClickHouseKeeper Dashboard", "uid": "clickhouse-keeper", - "version": 20220214 + "version": 2, + "weekStart": "" } diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/files/ClickHouse_Queries_dashboard.json b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/files/ClickHouse_Queries_dashboard.json index f348932a..ee27a17e 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/files/ClickHouse_Queries_dashboard.json +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/files/ClickHouse_Queries_dashboard.json @@ -147,8 +147,8 @@ "format": "time_series", "interval": "", "intervalFactor": 2, - "query": "SELECT\r\n t,\r\n arrayMap(a -> (a.1, a.2 / runningDifference(t / 1000)), groupArr)\r\nFROM (\r\n SELECT t, groupArray((q, c)) AS groupArr\r\n FROM (\r\n SELECT\r\n (intDiv(toUInt32(event_time), 2) * 2) * 1000 AS t,\r\n normalizeQuery(query) AS q,\r\n count() c\r\n FROM cluster('all-sharded',system.query_log)\r\n WHERE $timeFilter\r\n AND( ('$type' = '1,2,3,4' AND type != 'QueryStart') OR ('$type' != '1,2,3,4' AND type IN ($type)))\r\n $conditionalTest(AND query_kind IN ($query_kind), $query_kind)\r\n $conditionalTest(AND initial_user IN ($user), $user)\r\n $conditionalTest(AND query_duration_ms >= $min_duration_ms, $min_duration_ms)\r\n $conditionalTest(AND query_duration_ms <= $max_duration_ms, $max_duration_ms)\r\n AND normalized_query_hash GLOBAL IN (\r\n SELECT normalized_query_hash AS h\r\n FROM cluster('all-sharded',system.query_log)\r\n WHERE $timeFilter\r\n AND( ('$type' = '1,2,3,4' AND type != 'QueryStart') OR ('$type' != '1,2,3,4' AND type IN ($type)))\r\n $conditionalTest(AND query_kind IN ($query_kind), $query_kind)\r\n $conditionalTest(AND type IN ($type), $type)\r\n $conditionalTest(AND initial_user IN ($user), $user)\r\n $conditionalTest(AND query_duration_ms >= $min_duration_ms, $min_duration_ms)\r\n $conditionalTest(AND query_duration_ms <= $max_duration_ms, $max_duration_ms)\r\n GROUP BY h\r\n ORDER BY count() DESC\r\n LIMIT $top\r\n SETTINGS skip_unavailable_shards=1\r\n )\r\n GROUP BY t, query\r\n ORDER BY t\r\n )\r\n GROUP BY t\r\n ORDER BY t\r\n) SETTINGS skip_unavailable_shards=1", - "rawQuery": "SELECT\r\n t,\r\n arrayMap(a -> (a.1, a.2 / runningDifference(t / 1000)), groupArr)\r\nFROM (\r\n SELECT t, groupArray((q, c)) AS groupArr\r\n FROM (\r\n SELECT\r\n (intDiv(toUInt32(event_time), 2) * 2) * 1000 AS t,\r\n normalizeQuery(query) AS q,\r\n count() c\r\n FROM cluster('all-sharded',system.query_log)\r\n WHERE event_date >= toDate(1694531137) AND event_date <= toDate(1694534737) AND event_time >= toDateTime(1694531137) AND event_time <= toDateTime(1694534737)\r\n AND( ('1,2,3,4' = '1,2,3,4' AND type != 'QueryStart') OR ('1,2,3,4' != '1,2,3,4' AND type IN (1,2,3,4)))\r\n \r\n \r\n \r\n \r\n AND normalized_query_hash GLOBAL IN (\r\n SELECT normalized_query_hash AS h\r\n FROM cluster('all-sharded',system.query_log)\r\n WHERE event_date >= toDate(1694531137) AND event_date <= toDate(1694534737) AND event_time >= toDateTime(1694531137) AND event_time <= toDateTime(1694534737)\r\n AND( ('1,2,3,4' = '1,2,3,4' AND type != 'QueryStart') OR ('1,2,3,4' != '1,2,3,4' AND type IN (1,2,3,4)))\r\n \r\n \r\n \r\n \r\n \r\n GROUP BY h\r\n ORDER BY count() DESC\r\n LIMIT 30\r\n SETTINGS skip_unavailable_shards=1\r\n )\r\n GROUP BY t, query\r\n ORDER BY t\r\n )\r\n GROUP BY t\r\n ORDER BY t\r\n) SETTINGS skip_unavailable_shards=1", + "query": "SELECT\r\n t,\r\n arrayMap(a -> (a.1, a.2 / (t/1000 - lagInFrame(t/1000,1,0) OVER ()) ), groupArr)\r\nFROM (\r\n SELECT t, groupArray((q, c)) AS groupArr\r\n FROM (\r\n SELECT\r\n (intDiv(toUInt32(event_time), 2) * 2) * 1000 AS t,\r\n normalizeQuery(query) AS q,\r\n count() c\r\n FROM cluster('all-sharded',system.query_log)\r\n WHERE $timeFilter\r\n AND( ('$type' = '1,2,3,4' AND type != 'QueryStart') OR ('$type' != '1,2,3,4' AND type IN ($type)))\r\n $conditionalTest(AND query_kind IN ($query_kind), $query_kind)\r\n $conditionalTest(AND initial_user IN ($user), $user)\r\n $conditionalTest(AND query_duration_ms >= $min_duration_ms, $min_duration_ms)\r\n $conditionalTest(AND query_duration_ms <= $max_duration_ms, $max_duration_ms)\r\n AND normalized_query_hash GLOBAL IN (\r\n SELECT normalized_query_hash AS h\r\n FROM cluster('all-sharded',system.query_log)\r\n WHERE $timeFilter\r\n AND( ('$type' = '1,2,3,4' AND type != 'QueryStart') OR ('$type' != '1,2,3,4' AND type IN ($type)))\r\n $conditionalTest(AND query_kind IN ($query_kind), $query_kind)\r\n $conditionalTest(AND type IN ($type), $type)\r\n $conditionalTest(AND initial_user IN ($user), $user)\r\n $conditionalTest(AND query_duration_ms >= $min_duration_ms, $min_duration_ms)\r\n $conditionalTest(AND query_duration_ms <= $max_duration_ms, $max_duration_ms)\r\n GROUP BY h\r\n ORDER BY count() DESC\r\n LIMIT $top\r\n SETTINGS skip_unavailable_shards=1\r\n )\r\n GROUP BY t, query\r\n ORDER BY t\r\n )\r\n GROUP BY t\r\n ORDER BY t\r\n) SETTINGS skip_unavailable_shards=1", + "rawQuery": "SELECT\r\n t,\r\n arrayMap(a -> (a.1, a.2 / (t/1000 - lagInFrame(t/1000,1,0) OVER ()) ), groupArr)\r\nFROM (\r\n SELECT t, groupArray((q, c)) AS groupArr\r\n FROM (\r\n SELECT\r\n (intDiv(toUInt32(event_time), 2) * 2) * 1000 AS t,\r\n normalizeQuery(query) AS q,\r\n count() c\r\n FROM cluster('all-sharded',system.query_log)\r\n WHERE event_date >= toDate(1694531137) AND event_date <= toDate(1694534737) AND event_time >= toDateTime(1694531137) AND event_time <= toDateTime(1694534737)\r\n AND( ('1,2,3,4' = '1,2,3,4' AND type != 'QueryStart') OR ('1,2,3,4' != '1,2,3,4' AND type IN (1,2,3,4)))\r\n \r\n \r\n \r\n \r\n AND normalized_query_hash GLOBAL IN (\r\n SELECT normalized_query_hash AS h\r\n FROM cluster('all-sharded',system.query_log)\r\n WHERE event_date >= toDate(1694531137) AND event_date <= toDate(1694534737) AND event_time >= toDateTime(1694531137) AND event_time <= toDateTime(1694534737)\r\n AND( ('1,2,3,4' = '1,2,3,4' AND type != 'QueryStart') OR ('1,2,3,4' != '1,2,3,4' AND type IN (1,2,3,4)))\r\n \r\n \r\n \r\n \r\n \r\n GROUP BY h\r\n ORDER BY count() DESC\r\n LIMIT 30\r\n SETTINGS skip_unavailable_shards=1\r\n )\r\n GROUP BY t, query\r\n ORDER BY t\r\n )\r\n GROUP BY t\r\n ORDER BY t\r\n) SETTINGS skip_unavailable_shards=1", "refId": "A", "resultFormat": "time_series", "round": "0s", @@ -743,7 +743,7 @@ "interval": "", "intervalFactor": 2, "query": "$rate(count() c)\nFROM cluster('all-sharded',system.query_log)\nWHERE $timeFilter\n AND( ('$type' = '1,2,3,4' AND type != 'QueryStart') OR ('$type' != '1,2,3,4' AND type IN ($type)))\n $conditionalTest(AND query_kind IN ($query_kind), $query_kind)\n $conditionalTest(AND initial_user IN ($user), $user)\n $conditionalTest(AND query_duration_ms >= $min_duration_ms,$min_duration_ms)\n $conditionalTest(AND query_duration_ms <= $max_duration_ms,$max_duration_ms)\n", - "rawQuery": "SELECT t, c/runningDifference(t/1000) cRate FROM ( SELECT (intDiv(toUInt32(event_time), 4) * 4) * 1000 AS t, count() c FROM cluster('all-sharded',system.query_log)\nWHERE event_date >= toDate(1694531229) AND event_date <= toDate(1694534829) AND event_time >= toDateTime(1694531229) AND event_time <= toDateTime(1694534829) AND event_date >= toDate(1694531229) AND event_date <= toDate(1694534829) AND event_time >= toDateTime(1694531229) AND event_time <= toDateTime(1694534829)\n AND( ('1,2,3,4' = '1,2,3,4' AND type != 'QueryStart') OR ('1,2,3,4' != '1,2,3,4' AND type IN (1,2,3,4)))\n \n \n \n GROUP BY t ORDER BY t)", + "rawQuery": "SELECT t, c/(t/1000 - lagInFrame(t/1000,1,0) OVER ()) cRate FROM ( SELECT (intDiv(toUInt32(event_time), 4) * 4) * 1000 AS t, count() c FROM cluster('all-sharded',system.query_log)\nWHERE event_date >= toDate(1694531229) AND event_date <= toDate(1694534829) AND event_time >= toDateTime(1694531229) AND event_time <= toDateTime(1694534829) AND event_date >= toDate(1694531229) AND event_date <= toDate(1694534829) AND event_time >= toDateTime(1694531229) AND event_time <= toDateTime(1694534829)\n AND( ('1,2,3,4' = '1,2,3,4' AND type != 'QueryStart') OR ('1,2,3,4' != '1,2,3,4' AND type IN (1,2,3,4)))\n \n \n \n GROUP BY t ORDER BY t)", "refId": "A", "resultFormat": "time_series", "round": "0s", diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/_helpers.tpl b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/_helpers.tpl index ebac8ebf..f2d1aee2 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/_helpers.tpl +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/_helpers.tpl @@ -1,4 +1,15 @@ {{/* vim: set filetype=go-template: */}} +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts +*/}} +{{- define "altinity-clickhouse-operator.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + {{/* Expand the name of the chart. */}} @@ -40,8 +51,8 @@ helm.sh/chart: {{ include "altinity-clickhouse-operator.chart" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} -{{- if .Values.podLabels }} -{{ toYaml .Values.podLabels }} +{{- if .Values.commonLabels }} +{{ toYaml .Values.commonLabels }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end -}} @@ -54,6 +65,17 @@ app.kubernetes.io/name: {{ include "altinity-clickhouse-operator.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} {{- end -}} +{{/* +Common annotations +*/}} +{{- define "altinity-clickhouse-operator.annotations" -}} +meta.helm.sh/release-name: {{ .Release.Name }} +meta.helm.sh/release-namespace: {{ .Release.Namespace }} +{{- if .Values.commonAnnotations }} +{{ toYaml .Values.commonAnnotations }} +{{- end -}} +{{- end -}} + {{/* Create the name of the service account to use */}} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/dashboards-configmap.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/dashboards-configmap.yaml new file mode 100644 index 00000000..ac87683c --- /dev/null +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/dashboards-configmap.yaml @@ -0,0 +1,21 @@ +{{- if .Values.dashboards.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "altinity-clickhouse-operator.fullname" . }}-dashboards + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} + labels: + {{- include "altinity-clickhouse-operator.labels" . | nindent 4 }} + {{- if .Values.dashboards.additionalLabels }} + {{- toYaml .Values.dashboards.additionalLabels | nindent 4 }} + {{- end }} + annotations: + {{- include "altinity-clickhouse-operator.annotations" . | nindent 4 }} + {{- if .Values.dashboards.annotations }} + {{- toYaml .Values.dashboards.annotations | nindent 4 }} + {{- end }} +data: +{{- range $path, $_ := .Files.Glob "files/*.json" }} + {{ $path | trimPrefix "files/" }}: |- {{ $.Files.Get $path | nindent 4 -}} +{{ end }} +{{- end }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/dashboards-secret.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/dashboards-secret.yaml deleted file mode 100644 index 2ab5e98d..00000000 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/dashboards-secret.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- if .Values.dashboards.enabled }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "altinity-clickhouse-operator.fullname" . }}-dashboards - namespace: {{ .Release.Namespace }} - labels: - {{- include "altinity-clickhouse-operator.labels" . | nindent 4 }} -{{- if .Values.dashboards.additionalLabels }} - {{- toYaml .Values.dashboards.additionalLabels | nindent 4 }} -{{- end }} -{{- with .Values.dashboards.annotations }} - annotations: - {{- toYaml . | nindent 4 }} -{{- end }} -type: Opaque -data: -{{- range $path, $_ := .Files.Glob "files/*.json" }} - {{ $path | trimPrefix "files/" }}: {{ $.Files.Get $path | b64enc -}} -{{ end }} -{{- end }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ClusterRole-clickhouse-operator-kube-system.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ClusterRole-clickhouse-operator-kube-system.yaml index 03de65b3..387351a5 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ClusterRole-clickhouse-operator-kube-system.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ClusterRole-clickhouse-operator-kube-system.yaml @@ -1,4 +1,4 @@ -{{- if .Values.rbac.create -}} +{{- if (and .Values.rbac.create (not .Values.rbac.namespaceScoped)) -}} # Specifies either # ClusterRole # or @@ -12,7 +12,7 @@ metadata: name: {{ include "altinity-clickhouse-operator.fullname" . }} #namespace: kube-system labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} - namespace: {{ .Release.Namespace }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} rules: # # Core API group diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ClusterRoleBinding-clickhouse-operator-kube-system.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ClusterRoleBinding-clickhouse-operator-kube-system.yaml index cf7b3e03..1f696a54 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ClusterRoleBinding-clickhouse-operator-kube-system.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ClusterRoleBinding-clickhouse-operator-kube-system.yaml @@ -1,4 +1,4 @@ -{{- if .Values.rbac.create -}} +{{- if (and .Values.rbac.create (not .Values.rbac.namespaceScoped)) -}} # Specifies either # ClusterRoleBinding between ClusterRole and ServiceAccount. # or @@ -11,7 +11,7 @@ metadata: name: {{ include "altinity-clickhouse-operator.fullname" . }} #namespace: kube-system labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} - namespace: {{ .Release.Namespace }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole @@ -19,5 +19,15 @@ roleRef: subjects: - kind: ServiceAccount name: {{ include "altinity-clickhouse-operator.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} + +# Template Parameters: +# +# NAMESPACE=kube-system +# COMMENT= +# ROLE_KIND=Role +# ROLE_NAME=clickhouse-operator +# ROLE_BINDING_KIND=RoleBinding +# ROLE_BINDING_NAME=clickhouse-operator +# {{- end }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-confd-files.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-confd-files.yaml index 5e737e5d..a359e195 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-confd-files.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-confd-files.yaml @@ -8,6 +8,7 @@ apiVersion: v1 kind: ConfigMap metadata: name: {{ printf "%s-confd-files" (include "altinity-clickhouse-operator.fullname" .) }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} data: {{ include "altinity-clickhouse-operator.configmap-data" (list . .Values.configs.confdFiles) | nindent 2 }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-configd-files.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-configd-files.yaml index 2a4615eb..6b1480b8 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-configd-files.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-configd-files.yaml @@ -8,6 +8,7 @@ apiVersion: v1 kind: ConfigMap metadata: name: {{ printf "%s-configd-files" (include "altinity-clickhouse-operator.fullname" .) }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} data: {{ include "altinity-clickhouse-operator.configmap-data" (list . .Values.configs.configdFiles) | nindent 2 }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-files.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-files.yaml index 49a71235..bc6d21dd 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-files.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-files.yaml @@ -8,6 +8,7 @@ apiVersion: v1 kind: ConfigMap metadata: name: {{ printf "%s-files" (include "altinity-clickhouse-operator.fullname" .) }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} data: {{ include "altinity-clickhouse-operator.configmap-data" (list . .Values.configs.files) | nindent 2 }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-templatesd-files.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-templatesd-files.yaml index ba41cd85..5302b1f2 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-templatesd-files.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-templatesd-files.yaml @@ -8,6 +8,7 @@ apiVersion: v1 kind: ConfigMap metadata: name: {{ printf "%s-templatesd-files" (include "altinity-clickhouse-operator.fullname" .) }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} data: {{ include "altinity-clickhouse-operator.configmap-data" (list . .Values.configs.templatesdFiles) | nindent 2 }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-usersd-files.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-usersd-files.yaml index 42d44037..deca80c4 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-usersd-files.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-clickhouse-operator-usersd-files.yaml @@ -8,6 +8,7 @@ apiVersion: v1 kind: ConfigMap metadata: name: {{ printf "%s-usersd-files" (include "altinity-clickhouse-operator.fullname" .) }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} data: {{ include "altinity-clickhouse-operator.configmap-data" (list . .Values.configs.usersdFiles) | nindent 2 }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-keeper-operator-confd-files.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-keeper-operator-confd-files.yaml new file mode 100644 index 00000000..03b8f18a --- /dev/null +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-keeper-operator-confd-files.yaml @@ -0,0 +1,14 @@ +# Template Parameters: +# +# NAME=etc-keeper-operator-confd-files +# NAMESPACE=kube-system +# COMMENT= +# +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-keeper-confd-files" (include "altinity-clickhouse-operator.fullname" .) }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} + labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} +data: {{ include "altinity-clickhouse-operator.configmap-data" (list . .Values.configs.keeperConfdFiles) | nindent 2 }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-keeper-operator-configd-files.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-keeper-operator-configd-files.yaml new file mode 100644 index 00000000..31b92289 --- /dev/null +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-keeper-operator-configd-files.yaml @@ -0,0 +1,14 @@ +# Template Parameters: +# +# NAME=etc-keeper-operator-configd-files +# NAMESPACE=kube-system +# COMMENT= +# +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-keeper-configd-files" (include "altinity-clickhouse-operator.fullname" .) }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} + labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} +data: {{ include "altinity-clickhouse-operator.configmap-data" (list . .Values.configs.keeperConfigdFiles) | nindent 2 }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-keeper-operator-templatesd-files.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-keeper-operator-templatesd-files.yaml new file mode 100644 index 00000000..f99569a8 --- /dev/null +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-keeper-operator-templatesd-files.yaml @@ -0,0 +1,14 @@ +# Template Parameters: +# +# NAME=etc-keeper-operator-templatesd-files +# NAMESPACE=kube-system +# COMMENT= +# +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-keeper-templatesd-files" (include "altinity-clickhouse-operator.fullname" .) }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} + labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} +data: {{ include "altinity-clickhouse-operator.configmap-data" (list . .Values.configs.keeperTemplatesdFiles) | nindent 2 }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-keeper-operator-usersd-files.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-keeper-operator-usersd-files.yaml new file mode 100644 index 00000000..9e3e8da3 --- /dev/null +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ConfigMap-etc-keeper-operator-usersd-files.yaml @@ -0,0 +1,14 @@ +# Template Parameters: +# +# NAME=etc-keeper-operator-usersd-files +# NAMESPACE=kube-system +# COMMENT= +# +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-keeper-usersd-files" (include "altinity-clickhouse-operator.fullname" .) }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} + labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} +data: {{ include "altinity-clickhouse-operator.configmap-data" (list . .Values.configs.keeperUsersdFiles) | nindent 2 }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/Deployment-clickhouse-operator.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/Deployment-clickhouse-operator.yaml index 03b52fc5..08482ab1 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/Deployment-clickhouse-operator.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/Deployment-clickhouse-operator.yaml @@ -2,9 +2,9 @@ # # NAMESPACE=kube-system # COMMENT= -# OPERATOR_IMAGE=altinity/clickhouse-operator:0.23.4 +# OPERATOR_IMAGE=altinity/clickhouse-operator:0.25.2 # OPERATOR_IMAGE_PULL_POLICY=Always -# METRICS_EXPORTER_IMAGE=altinity/metrics-exporter:0.23.4 +# METRICS_EXPORTER_IMAGE=altinity/metrics-exporter:0.25.2 # METRICS_EXPORTER_IMAGE_PULL_POLICY=Always # # Setup Deployment for clickhouse-operator @@ -13,22 +13,27 @@ kind: Deployment apiVersion: apps/v1 metadata: name: {{ include "altinity-clickhouse-operator.fullname" . }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} spec: replicas: 1 selector: matchLabels: {{ include "altinity-clickhouse-operator.selectorLabels" . | nindent 6 }} template: metadata: - labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 8 }} + labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 8 }}{{ if .Values.podLabels }}{{ toYaml .Values.podLabels | nindent 8 }}{{ end }} annotations: - {{ toYaml .Values.podAnnotations | nindent 8 }} + {{ if .Values.podAnnotations }}{{ toYaml .Values.podAnnotations | nindent 8 }}{{ end }} checksum/files: {{ include (print $.Template.BasePath "/generated/ConfigMap-etc-clickhouse-operator-files.yaml") . | sha256sum }} checksum/confd-files: {{ include (print $.Template.BasePath "/generated/ConfigMap-etc-clickhouse-operator-confd-files.yaml") . | sha256sum }} checksum/configd-files: {{ include (print $.Template.BasePath "/generated/ConfigMap-etc-clickhouse-operator-configd-files.yaml") . | sha256sum }} checksum/templatesd-files: {{ include (print $.Template.BasePath "/generated/ConfigMap-etc-clickhouse-operator-templatesd-files.yaml") . | sha256sum }} checksum/usersd-files: {{ include (print $.Template.BasePath "/generated/ConfigMap-etc-clickhouse-operator-usersd-files.yaml") . | sha256sum }} + checksum/keeper-confd-files: {{ include (print $.Template.BasePath "/generated/ConfigMap-etc-keeper-operator-confd-files.yaml") . | sha256sum }} + checksum/keeper-configd-files: {{ include (print $.Template.BasePath "/generated/ConfigMap-etc-keeper-operator-configd-files.yaml") . | sha256sum }} + checksum/keeper-templatesd-files: {{ include (print $.Template.BasePath "/generated/ConfigMap-etc-keeper-operator-templatesd-files.yaml") . | sha256sum }} + checksum/keeper-usersd-files: {{ include (print $.Template.BasePath "/generated/ConfigMap-etc-keeper-operator-usersd-files.yaml") . | sha256sum }} spec: serviceAccountName: {{ include "altinity-clickhouse-operator.serviceAccountName" . }} volumes: @@ -47,6 +52,18 @@ spec: - name: etc-clickhouse-operator-usersd-folder configMap: name: {{ include "altinity-clickhouse-operator.fullname" . }}-usersd-files + - name: etc-keeper-operator-confd-folder + configMap: + name: {{ include "altinity-clickhouse-operator.fullname" . }}-keeper-confd-files + - name: etc-keeper-operator-configd-folder + configMap: + name: {{ include "altinity-clickhouse-operator.fullname" . }}-keeper-configd-files + - name: etc-keeper-operator-templatesd-folder + configMap: + name: {{ include "altinity-clickhouse-operator.fullname" . }}-keeper-templatesd-files + - name: etc-keeper-operator-usersd-folder + configMap: + name: {{ include "altinity-clickhouse-operator.fullname" . }}-keeper-usersd-files containers: - name: {{ .Chart.Name }} image: {{ .Values.operator.image.repository }}:{{ include "altinity-clickhouse-operator.operator.tag" . }} @@ -55,13 +72,21 @@ spec: - name: etc-clickhouse-operator-folder mountPath: /etc/clickhouse-operator - name: etc-clickhouse-operator-confd-folder - mountPath: /etc/clickhouse-operator/conf.d + mountPath: /etc/clickhouse-operator/chi/conf.d - name: etc-clickhouse-operator-configd-folder - mountPath: /etc/clickhouse-operator/config.d + mountPath: /etc/clickhouse-operator/chi/config.d - name: etc-clickhouse-operator-templatesd-folder - mountPath: /etc/clickhouse-operator/templates.d + mountPath: /etc/clickhouse-operator/chi/templates.d - name: etc-clickhouse-operator-usersd-folder - mountPath: /etc/clickhouse-operator/users.d + mountPath: /etc/clickhouse-operator/chi/users.d + - name: etc-keeper-operator-confd-folder + mountPath: /etc/clickhouse-operator/chk/conf.d + - name: etc-keeper-operator-configd-folder + mountPath: /etc/clickhouse-operator/chk/keeper_config.d + - name: etc-keeper-operator-templatesd-folder + mountPath: /etc/clickhouse-operator/chk/templates.d + - name: etc-keeper-operator-usersd-folder + mountPath: /etc/clickhouse-operator/chk/users.d env: # Pod-specific # spec.nodeName: ip-172-20-52-62.ec2.internal @@ -125,13 +150,21 @@ spec: - name: etc-clickhouse-operator-folder mountPath: /etc/clickhouse-operator - name: etc-clickhouse-operator-confd-folder - mountPath: /etc/clickhouse-operator/conf.d + mountPath: /etc/clickhouse-operator/chi/conf.d - name: etc-clickhouse-operator-configd-folder - mountPath: /etc/clickhouse-operator/config.d + mountPath: /etc/clickhouse-operator/chi/config.d - name: etc-clickhouse-operator-templatesd-folder - mountPath: /etc/clickhouse-operator/templates.d + mountPath: /etc/clickhouse-operator/chi/templates.d - name: etc-clickhouse-operator-usersd-folder - mountPath: /etc/clickhouse-operator/users.d + mountPath: /etc/clickhouse-operator/chi/users.d + - name: etc-keeper-operator-confd-folder + mountPath: /etc/clickhouse-operator/chk/conf.d + - name: etc-keeper-operator-configd-folder + mountPath: /etc/clickhouse-operator/chk/keeper_config.d + - name: etc-keeper-operator-templatesd-folder + mountPath: /etc/clickhouse-operator/chk/templates.d + - name: etc-keeper-operator-usersd-folder + mountPath: /etc/clickhouse-operator/chk/users.d env: # Pod-specific # spec.nodeName: ip-172-20-52-62.ec2.internal @@ -193,3 +226,4 @@ spec: affinity: {{ toYaml .Values.affinity | nindent 8 }} tolerations: {{ toYaml .Values.tolerations | nindent 8 }} securityContext: {{ toYaml .Values.podSecurityContext | nindent 8 }} + topologySpreadConstraints: {{ toYaml .Values.topologySpreadConstraints | nindent 8 }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/Role-clickhouse-operator.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/Role-clickhouse-operator.yaml new file mode 100644 index 00000000..2fb3015e --- /dev/null +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/Role-clickhouse-operator.yaml @@ -0,0 +1,211 @@ +{{- if (and .Values.rbac.create .Values.rbac.namespaceScoped) -}} +# Specifies either +# ClusterRole +# or +# Role +# to be bound to ServiceAccount. +# ClusterRole is namespace-less and must have unique name +# Role is namespace-bound +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "altinity-clickhouse-operator.fullname" . }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} + labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} +rules: + # + # Core API group + # + - apiGroups: + - "" + resources: + - configmaps + - services + - persistentvolumeclaims + - secrets + verbs: + - get + - list + - patch + - update + - watch + - create + - delete + - apiGroups: + - "" + resources: + - endpoints + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - events + verbs: + - create + - apiGroups: + - "" + resources: + - persistentvolumes + verbs: + - get + - list + - patch + - update + - watch + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - patch + - update + - watch + - delete + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + # + # apps.* resources + # + - apiGroups: + - apps + resources: + - statefulsets + verbs: + - get + - list + - patch + - update + - watch + - create + - delete + - apiGroups: + - apps + resources: + - replicasets + verbs: + - get + - patch + - update + - delete + # The operator deployment personally, identified by name + - apiGroups: + - apps + resources: + - deployments + resourceNames: + - {{ include "altinity-clickhouse-operator.fullname" . }} + verbs: + - get + - patch + - update + - delete + # + # policy.* resources + # + - apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - get + - list + - patch + - update + - watch + - create + - delete + # + # apiextensions + # + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - list + # clickhouse - related resources + - apiGroups: + - clickhouse.altinity.com + # + # The operators specific Custom Resources + # + + resources: + - clickhouseinstallations + verbs: + - get + - list + - watch + - patch + - update + - delete + - apiGroups: + - clickhouse.altinity.com + resources: + - clickhouseinstallationtemplates + - clickhouseoperatorconfigurations + verbs: + - get + - list + - watch + - apiGroups: + - clickhouse.altinity.com + resources: + - clickhouseinstallations/finalizers + - clickhouseinstallationtemplates/finalizers + - clickhouseoperatorconfigurations/finalizers + verbs: + - update + - apiGroups: + - clickhouse.altinity.com + resources: + - clickhouseinstallations/status + - clickhouseinstallationtemplates/status + - clickhouseoperatorconfigurations/status + verbs: + - get + - update + - patch + - create + - delete + # clickhouse-keeper - related resources + - apiGroups: + - clickhouse-keeper.altinity.com + resources: + - clickhousekeeperinstallations + verbs: + - get + - list + - watch + - patch + - update + - delete + - apiGroups: + - clickhouse-keeper.altinity.com + resources: + - clickhousekeeperinstallations/finalizers + verbs: + - update + - apiGroups: + - clickhouse-keeper.altinity.com + resources: + - clickhousekeeperinstallations/status + verbs: + - get + - update + - patch + - create + - delete +{{- end }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/RoleBinding-clickhouse-operator.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/RoleBinding-clickhouse-operator.yaml new file mode 100644 index 00000000..50d4af15 --- /dev/null +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/RoleBinding-clickhouse-operator.yaml @@ -0,0 +1,23 @@ +{{- if (and .Values.rbac.create .Values.rbac.namespaceScoped) -}} +# Specifies either +# ClusterRoleBinding between ClusterRole and ServiceAccount. +# or +# RoleBinding between Role and ServiceAccount. +# ClusterRoleBinding is namespace-less and must have unique name +# RoleBinding is namespace-bound +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "altinity-clickhouse-operator.fullname" . }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} + labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "altinity-clickhouse-operator.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ include "altinity-clickhouse-operator.serviceAccountName" . }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} +{{- end }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/Secret-clickhouse-operator.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/Secret-clickhouse-operator.yaml index a5f68b9c..1c3664c1 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/Secret-clickhouse-operator.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/Secret-clickhouse-operator.yaml @@ -3,7 +3,7 @@ # Template parameters available: # NAMESPACE=kube-system # COMMENT= -# OPERATOR_VERSION=0.23.4 +# OPERATOR_VERSION=0.25.2 # CH_USERNAME_SECRET_PLAIN=clickhouse_operator # CH_PASSWORD_SECRET_PLAIN=clickhouse_operator_password # @@ -11,8 +11,9 @@ apiVersion: v1 kind: Secret metadata: name: {{ include "altinity-clickhouse-operator.fullname" . }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} type: Opaque data: username: {{ .Values.secret.username | b64enc }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/Service-clickhouse-operator-metrics.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/Service-clickhouse-operator-metrics.yaml index 28a54e59..5ac9d4eb 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/Service-clickhouse-operator-metrics.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/Service-clickhouse-operator-metrics.yaml @@ -12,8 +12,9 @@ kind: Service apiVersion: v1 metadata: name: {{ printf "%s-metrics" (include "altinity-clickhouse-operator.fullname" .) }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} spec: ports: - port: 8888 diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ServiceAccount-clickhouse-operator.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ServiceAccount-clickhouse-operator.yaml index 3bc8d89a..bcc55c20 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ServiceAccount-clickhouse-operator.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/generated/ServiceAccount-clickhouse-operator.yaml @@ -10,9 +10,9 @@ apiVersion: v1 kind: ServiceAccount metadata: name: {{ include "altinity-clickhouse-operator.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} labels: {{ include "altinity-clickhouse-operator.labels" . | nindent 4 }} - annotations: {{ toYaml .Values.serviceAccount.annotations | nindent 4 }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }}{{ if .Values.serviceAccount.annotations }}{{ toYaml .Values.serviceAccount.annotations | nindent 4 }}{{ end }} # Template Parameters: # diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/servicemonitor.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/servicemonitor.yaml index f8dea8e6..da6d389b 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/servicemonitor.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/templates/servicemonitor.yaml @@ -3,16 +3,45 @@ apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: {{ printf "%s-clickhouse-metrics" (include "altinity-clickhouse-operator.fullname" .) }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "altinity-clickhouse-operator.namespace" . }} labels: {{- include "altinity-clickhouse-operator.labels" . | nindent 4 }} - {{- if .Values.serviceMonitor.additionalLabels }} + {{- if .Values.serviceMonitor.additionalLabels }} {{- toYaml .Values.serviceMonitor.additionalLabels | nindent 4 }} - {{- end }} + {{- end }} + annotations: {{ include "altinity-clickhouse-operator.annotations" . | nindent 4 }} spec: endpoints: - port: clickhouse-metrics # 8888 + {{- with .Values.serviceMonitor.clickhouseMetrics.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.serviceMonitor.clickhouseMetrics.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + {{- with .Values.serviceMonitor.clickhouseMetrics.relabelings }} + relabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.serviceMonitor.clickhouseMetrics.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 8 }} + {{- end }} - port: operator-metrics # 9999 + {{- with .Values.serviceMonitor.operatorMetrics.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.serviceMonitor.operatorMetrics.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + {{- with .Values.serviceMonitor.operatorMetrics.relabelings }} + relabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.serviceMonitor.operatorMetrics.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 8 }} + {{- end }} selector: matchLabels: {{- include "altinity-clickhouse-operator.selectorLabels" . | nindent 6 }} diff --git a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/values.yaml b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/values.yaml index fbbf8972..9ffaab19 100644 --- a/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/values.yaml +++ b/packages/system/clickhouse-operator/charts/altinity-clickhouse-operator/values.yaml @@ -1,3 +1,8 @@ +namespaceOverride: "" +# commonLabels -- set of labels that will be applied to all the resources for the operator +commonLabels: {} +# commonAnnotations -- set of annotations that will be applied to all the resources for the operator +commonAnnotations: {} operator: image: # operator.image.repository -- image repository @@ -7,7 +12,7 @@ operator: # operator.image.pullPolicy -- image pull policy pullPolicy: IfNotPresent containerSecurityContext: {} - # operator.resources -- custom resource configuration, look `kubectl explain pod.spec.containers.resources` for details + # operator.resources -- custom resource configuration, check `kubectl explain pod.spec.containers.resources` for details resources: {} # limits: # cpu: 100m @@ -17,7 +22,7 @@ operator: # memory: 128Mi # operator.env -- additional environment variables for the clickhouse-operator container in deployment - # possible format value [{"name": "SAMPLE", "value": "text"}] + # possible format value `[{"name": "SAMPLE", "value": "text"}]` env: [] metrics: enabled: true @@ -39,15 +44,16 @@ metrics: # memory: 128Mi # metrics.env -- additional environment variables for the deployment of metrics-exporter containers - # possible format value [{"name": "SAMPLE", "value": "text"}] + # possible format value `[{"name": "SAMPLE", "value": "text"}]` env: [] # imagePullSecrets -- image pull secret for private images in clickhouse-operator pod -# possible value format [{"name":"your-secret-name"}] -# look `kubectl explain pod.spec.imagePullSecrets` for details +# possible value format `[{"name":"your-secret-name"}]`, +# check `kubectl explain pod.spec.imagePullSecrets` for details imagePullSecrets: [] # podLabels -- labels to add to the clickhouse-operator pod podLabels: {} -# podAnnotations -- annotations to add to the clickhouse-operator pod, look `kubectl explain pod.spec.annotations` for details +# podAnnotations -- annotations to add to the clickhouse-operator pod, check `kubectl explain pod.spec.annotations` for details +# @default -- check the `values.yaml` file podAnnotations: prometheus.io/port: '8888' prometheus.io/scrape: 'true' @@ -65,8 +71,10 @@ serviceAccount: # serviceAccount.name -- the name of the service account to use; if not set and create is true, a name is generated using the fullname template name: rbac: - # rbac.create -- specifies whether cluster roles and cluster role bindings should be created + # rbac.create -- specifies whether rbac resources should be created create: true + # rbac.namespaceScoped -- specifies whether to create roles and rolebindings at the cluster level or namespace level + namespaceScoped: false secret: # secret.create -- create a secret with operator credentials create: true @@ -74,21 +82,42 @@ secret: username: clickhouse_operator # secret.password -- operator credentials password password: clickhouse_operator_password -# nodeSelector -- node for scheduler pod assignment, look `kubectl explain pod.spec.nodeSelector` for details +# nodeSelector -- node for scheduler pod assignment, check `kubectl explain pod.spec.nodeSelector` for details nodeSelector: {} -# tolerations -- tolerations for scheduler pod assignment, look `kubectl explain pod.spec.tolerations` for details +# tolerations -- tolerations for scheduler pod assignment, check `kubectl explain pod.spec.tolerations` for details tolerations: [] -# affinity -- affinity for scheduler pod assignment, look `kubectl explain pod.spec.affinity` for details +# affinity -- affinity for scheduler pod assignment, check `kubectl explain pod.spec.affinity` for details affinity: {} -# podSecurityContext - operator deployment SecurityContext, look `kubectl explain pod.spec.securityContext` for details +# podSecurityContext - operator deployment SecurityContext, check `kubectl explain pod.spec.securityContext` for details podSecurityContext: {} +# topologySpreadConstraints - topologySpreadConstraints affinity for scheduler pod assignment, check `kubectl explain pod.spec.topologySpreadConstraints` for details +topologySpreadConstraints: [] serviceMonitor: - # serviceMonitor.enabled -- ServiceMonitor Custom resource is created for a (prometheus-operator)[https://github.com/prometheus-operator/prometheus-operator] + # serviceMonitor.enabled -- ServiceMonitor Custom resource is created for a [prometheus-operator](https://github.com/prometheus-operator/prometheus-operator) + # In serviceMonitor will be created two endpoints clickhouse-metrics on port 8888 and operator-metrics # 9999. Ypu can specify interval, scrapeTimeout, relabelings, metricRelabelings for each endpoint below enabled: false # serviceMonitor.additionalLabels -- additional labels for service monitor additionalLabels: {} -# configs -- clickhouse-operator configs -# @default -- check the values.yaml file for the config content, auto-generated from latest operator release + clickhouseMetrics: + # serviceMonitor.interval for clickhouse-metrics endpoint -- + interval: 30s + # serviceMonitor.scrapeTimeout for clickhouse-metrics endpoint -- Prometheus ServiceMonitor scrapeTimeout. If empty, Prometheus uses the global scrape timeout unless it is less than the target's scrape interval value in which the latter is used. + scrapeTimeout: "" + # serviceMonitor.relabelings for clickhouse-metrics endpoint -- Prometheus [RelabelConfigs] to apply to samples before scraping + relabelings: [] + # serviceMonitor.metricRelabelings for clickhouse-metrics endpoint -- Prometheus [MetricRelabelConfigs] to apply to samples before ingestio + metricRelabelings: [] + operatorMetrics: + # serviceMonitor.interval for operator-metrics endpoint -- + interval: 30s + # serviceMonitor.scrapeTimeout for operator-metrics endpoint -- Prometheus ServiceMonitor scrapeTimeout. If empty, Prometheus uses the global scrape timeout unless it is less than the target's scrape interval value in which the latter is used. + scrapeTimeout: "" + # serviceMonitor.relabelings for operator-metrics endpoint -- Prometheus [RelabelConfigs] to apply to samples before scraping + relabelings: [] + # serviceMonitor.metricRelabelings for operator-metrics endpoint-- Prometheus [MetricRelabelConfigs] to apply to samples before ingestio + metricRelabelings: [] +# configs -- clickhouse operator configs +# @default -- check the `values.yaml` file for the config content (auto-generated from latest operator release) configs: confdFiles: null configdFiles: @@ -212,12 +241,12 @@ configs: # In case path is relative - it is relative to the folder where configuration file you are reading right now is located. path: # Path to the folder where ClickHouse configuration files common for all instances within a CHI are located. - common: config.d + common: chi/config.d # Path to the folder where ClickHouse configuration files unique for each instance (host) within a CHI are located. - host: conf.d + host: chi/conf.d # Path to the folder where ClickHouse configuration files with users' settings are located. # Files are common for all instances within a CHI. - user: users.d + user: chi/users.d ################################################ ## ## Configuration users section @@ -287,10 +316,13 @@ configs: - settings/macros/*: "no" - settings/remote_servers/*: "no" - settings/user_directories/*: "no" + # these settings should not lead to pod restarts + - settings/display_secrets_in_show_and_select: "no" - zookeeper/*: "yes" - files/*.xml: "yes" - files/config.d/*.xml: "yes" - files/config.d/*dict*.xml: "no" + - files/config.d/*no_restart*: "no" # exceptions in default profile - profiles/default/background_*_pool_size: "yes" - profiles/default/max_*_for_server: "yes" @@ -312,7 +344,6 @@ configs: # These credentials are used for: # 1. Metrics requests # 2. Schema maintenance - # 3. DROP DNS CACHE # User with these credentials can be specified in additional ClickHouse .xml config files, # located in 'clickhouse.configuration.file.path.user' folder username: "" @@ -339,6 +370,56 @@ configs: connect: 1 # Timout to perform SQL query from the operator to ClickHouse instances. In seconds. query: 4 + ################################################ + ## + ## Addons specifies additional configuration sections + ## Should it be called something like "templates"? + ## + ################################################ + addons: + rules: + - version: "*" + spec: + configuration: + users: + profiles: + quotas: + settings: + files: + - version: ">= 23.3" + spec: + configuration: + ### + ### users.d is global while description depends on CH version which may vary on per-host basis + ### In case of global-ness this may be better to implement via auto-templates + ### + ### As a solution, this may be applied on the whole cluster based on any of its hosts + ### + ### What to do when host is just created? CH version is not known prior to CH started and user config is required before CH started. + ### We do not have any info about the cluster on initial creation + ### + users: + "{clickhouseOperatorUser}/access_management": 1 + "{clickhouseOperatorUser}/named_collection_control": 1 + "{clickhouseOperatorUser}/show_named_collections": 1 + "{clickhouseOperatorUser}/show_named_collections_secrets": 1 + profiles: + quotas: + settings: + files: + - version: ">= 23.5" + spec: + configuration: + users: + profiles: + clickhouse_operator/format_display_secrets_in_show_and_select: 1 + quotas: + settings: + ## + ## this may be added on per-host basis into host's conf.d folder + ## + display_secrets_in_show_and_select: 1 + files: ################################################# ## ## Metrics collection @@ -352,6 +433,25 @@ configs: # Upon reaching this timeout metrics collection is aborted and no more metrics are collected in this cycle. # All collected metrics are returned. collect: 9 + keeper: + configuration: + ################################################ + ## + ## Configuration files section + ## + ################################################ + file: + # Each 'path' can be either absolute or relative. + # In case path is absolute - it is used as is + # In case path is relative - it is relative to the folder where configuration file you are reading right now is located. + path: + # Path to the folder where Keeper configuration files common for all instances within a CHK are located. + common: chk/keeper_config.d + # Path to the folder where Keeper configuration files unique for each instance (host) within a CHK are located. + host: chk/conf.d + # Path to the folder where Keeper configuration files with users' settings are located. + # Files are common for all instances within a CHI. + user: chk/users.d ################################################ ## ## Template(s) management section @@ -367,7 +467,17 @@ configs: # Path to the folder where ClickHouseInstallation templates .yaml manifests are located. # Templates are added to the list of all templates and used when CHI is reconciled. # Templates are applied in sorted alpha-numeric order. - path: templates.d + path: chi/templates.d + chk: + # CHK template updates handling policy + # Possible policy values: + # - ReadOnStart. Accept CHIT updates on the operators start only. + # - ApplyOnNextReconcile. Accept CHIT updates at all time. Apply news CHITs on next regular reconcile of the CHI + policy: ApplyOnNextReconcile + # Path to the folder where ClickHouseInstallation templates .yaml manifests are located. + # Templates are added to the list of all templates and used when CHI is reconciled. + # Templates are applied in sorted alpha-numeric order. + path: chk/templates.d ################################################ ## ## Reconcile section @@ -386,9 +496,9 @@ configs: # 3. The first shard is always reconciled alone. Concurrency starts from the second shard and onward. # Thus limiting number of shards being reconciled (and thus having hosts down) in each CHI by both number and percentage - # Max number of concurrent shard reconciles within one CHI in progress + # Max number of concurrent shard reconciles within one cluster in progress reconcileShardsThreadsNumber: 5 - # Max percentage of concurrent shard reconciles within one CHI in progress + # Max percentage of concurrent shard reconciles within one cluster in progress reconcileShardsMaxConcurrencyPercent: 50 # Reconcile StatefulSet scenario statefulSet: @@ -429,6 +539,10 @@ configs: exclude: true queries: true include: false + replicas: + all: no + new: yes + delay: 10 ################################################ ## ## Annotations management section @@ -473,6 +587,25 @@ configs: appendScope: "no" ################################################ ## + ## Metrics management section + ## + ################################################ + metrics: + labels: + exclude: [] + ################################################ + ## + ## Status management section + ## + ################################################ + status: + fields: + action: false + actions: false + error: false + errors: false + ################################################ + ## ## StatefulSet management section ## ################################################ @@ -631,20 +764,87 @@ configs: -# additionalResources -- list of additional resources to create (are processed via `tpl` function), useful for create ClickHouse clusters together with clickhouse-operator, look `kubectl explain chi` for details + keeperConfdFiles: null + keeperConfigdFiles: + 01-keeper-01-default-config.xml: | + + + + + + + + + + 10000 + 10000 + information + 100000 + + true + /var/lib/clickhouse-keeper/coordination/logs + /var/lib/clickhouse-keeper/coordination/snapshots + /var/lib/clickhouse-keeper + 2181 + + :: + 0.0.0.0 + 1 + + 1 + information + + 4096 + + 01-keeper-02-readiness.xml: | + + + + + + + + + + 9182 + + /ready + + + + + 01-keeper-03-enable-reconfig.xml: |- + + + + + + + + + false + + + keeperTemplatesdFiles: + readme: |- + Templates in this folder are packaged with an operator and available via 'useTemplate' + keeperUsersdFiles: null +# additionalResources -- list of additional resources to create (processed via `tpl` function), +# useful for create ClickHouse clusters together with clickhouse-operator. +# check `kubectl explain chi` for details additionalResources: [] # - | # apiVersion: v1 # kind: ConfigMap # metadata: # name: {{ include "altinity-clickhouse-operator.fullname" . }}-cm -# namespace: {{ .Release.Namespace }} +# namespace: {{ include "altinity-clickhouse-operator.namespace" . }} # - | # apiVersion: v1 # kind: Secret # metadata: # name: {{ include "altinity-clickhouse-operator.fullname" . }}-s -# namespace: {{ .Release.Namespace }} +# namespace: {{ include "altinity-clickhouse-operator.namespace" . }} # stringData: # mykey: my-value # - | @@ -652,15 +852,16 @@ additionalResources: [] # kind: ClickHouseInstallation # metadata: # name: {{ include "altinity-clickhouse-operator.fullname" . }}-chi -# namespace: {{ .Release.Namespace }} +# namespace: {{ include "altinity-clickhouse-operator.namespace" . }} # spec: # configuration: # clusters: # - name: default # layout: # shardsCount: 1 + dashboards: - # dashboards.enabled -- provision grafana dashboards as secrets (can be synced by grafana dashboards sidecar https://github.com/grafana/helm-charts/blob/grafana-6.33.1/charts/grafana/values.yaml#L679 ) + # dashboards.enabled -- provision grafana dashboards as configMaps (can be synced by grafana dashboards sidecar https://github.com/grafana/helm-charts/blob/grafana-8.3.4/charts/grafana/values.yaml#L778 ) enabled: false # dashboards.additionalLabels -- labels to add to a secret with dashboards additionalLabels: diff --git a/packages/system/clickhouse-rd/Chart.yaml b/packages/system/clickhouse-rd/Chart.yaml new file mode 100644 index 00000000..583d39a6 --- /dev/null +++ b/packages/system/clickhouse-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: clickhouse-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/clickhouse-rd/Makefile b/packages/system/clickhouse-rd/Makefile new file mode 100644 index 00000000..792ef31b --- /dev/null +++ b/packages/system/clickhouse-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=clickhouse-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/clickhouse-rd/cozyrds/clickhouse.yaml b/packages/system/clickhouse-rd/cozyrds/clickhouse.yaml new file mode 100644 index 00000000..3655a8db --- /dev/null +++ b/packages/system/clickhouse-rd/cozyrds/clickhouse.yaml @@ -0,0 +1,37 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: clickhouse +spec: + application: + kind: ClickHouse + singular: clickhouse + plural: clickhouses + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of ClickHouse replicas.","type":"integer","default":2},"shards":{"description":"Number of ClickHouse shards.","type":"integer","default":1},"resources":{"description":"Explicit CPU and memory configuration for each ClickHouse replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"logStorageSize":{"description":"Size of Persistent Volume for logs.","default":"2Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"logTTL":{"description":"TTL (expiration time) for `query_log` and `query_thread_log`.","type":"integer","default":15},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user.","type":"string"},"readonly":{"description":"User is readonly (default: false).","type":"boolean"}}}},"backup":{"description":"Backup configuration.","type":"object","default":{},"required":["cleanupStrategy","enabled","resticPassword","s3AccessKey","s3Bucket","s3Region","s3SecretKey","schedule"],"properties":{"cleanupStrategy":{"description":"Retention strategy for cleaning up old backups.","type":"string","default":"--keep-last=3 --keep-daily=3 --keep-within-weekly=1m"},"enabled":{"description":"Enable regular backups (default: false).","type":"boolean","default":false},"resticPassword":{"description":"Password for Restic backup encryption.","type":"string","default":""},"s3AccessKey":{"description":"Access key for S3 authentication.","type":"string","default":""},"s3Bucket":{"description":"S3 bucket used for storing backups.","type":"string","default":"s3.example.org/clickhouse-backups"},"s3Region":{"description":"AWS S3 region where backups are stored.","type":"string","default":"us-east-1"},"s3SecretKey":{"description":"Secret key for S3 authentication.","type":"string","default":""},"schedule":{"description":"Cron schedule for automated backups.","type":"string","default":"0 2 * * *"}}},"clickhouseKeeper":{"description":"ClickHouse Keeper configuration.","type":"object","default":{},"properties":{"enabled":{"description":"Deploy ClickHouse Keeper for cluster coordination.","type":"boolean","default":true},"replicas":{"description":"Number of Keeper replicas.","type":"integer","default":3},"resourcesPreset":{"description":"Default sizing preset.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}} + release: + prefix: clickhouse- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-clickhouse-application-default-clickhouse + namespace: cozy-system + dashboard: + category: PaaS + singular: ClickHouse + plural: ClickHouse + description: Managed ClickHouse service + tags: [] + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODNfMzIwMikiLz4KPHBhdGggZD0iTTIzIDEwNUgzNFYxMTZIMjNWMTA1WiIgZmlsbD0iI0ZGMDAwMCIvPgo8cGF0aCBkPSJNMjMgMjhIMzRWMTA1SDIzVjI4Wk00NSAyOEg1NS45OTk5VjExNkg0NVYyOFpNNjYuOTk5OSAyOEg3Ny45OTk5VjExNkg2Ni45OTk5VjI4Wk04OC45OTk5IDI4SDk5Ljk5OTlWMTE2SDg4Ljk5OTlWMjhaTTExMSA2My43NDk5SDEyMlY4MC4yNDk5SDExMVY2My43NDk5WiIgZmlsbD0id2hpdGUiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl82ODNfMzIwMiIgeDE9Ii0wLjQ5OTk5OCIgeTE9IjEuNSIgeDI9IjE1My41IiB5Mj0iMTYyIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiNGRkNDMDAiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjRkY3QTAwIi8+CjwvbGluZWFyR3JhZGllbnQ+CjwvZGVmcz4KPC9zdmc+Cg== + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "shards"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "logStorageSize"], ["spec", "logTTL"], ["spec", "users"], ["spec", "backup"], ["spec", "backup", "enabled"], ["spec", "backup", "s3Region"], ["spec", "backup", "s3Bucket"], ["spec", "backup", "schedule"], ["spec", "backup", "cleanupStrategy"], ["spec", "backup", "s3AccessKey"], ["spec", "backup", "s3SecretKey"], ["spec", "backup", "resticPassword"], ["spec", "clickhouseKeeper"], ["spec", "clickhouseKeeper", "enabled"], ["spec", "clickhouseKeeper", "size"], ["spec", "clickhouseKeeper", "resourcesPreset"], ["spec", "clickhouseKeeper", "replicas"]] + secrets: + exclude: [] + include: + - resourceNames: + - clickhouse-{{ .name }}-credentials + services: + exclude: [] + include: + - resourceNames: + - chendpoint-clickhouse-{{ .name }} diff --git a/packages/system/clickhouse-rd/templates/cozyrd.yaml b/packages/system/clickhouse-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/clickhouse-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/clickhouse-rd/values.yaml b/packages/system/clickhouse-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/clickhouse-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/cluster-autoscaler/Chart.yaml b/packages/system/cluster-autoscaler/Chart.yaml new file mode 100644 index 00000000..9aa2bb43 --- /dev/null +++ b/packages/system/cluster-autoscaler/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +name: cozy-cluster-autoscaler +description: Cluster Autoscaler for automatic node scaling +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/cluster-autoscaler/Makefile b/packages/system/cluster-autoscaler/Makefile new file mode 100644 index 00000000..605d4d4e --- /dev/null +++ b/packages/system/cluster-autoscaler/Makefile @@ -0,0 +1,10 @@ +export NAME=cluster-autoscaler +export NAMESPACE=cozy-$(NAME) + +include ../../../hack/package.mk + +update: + rm -rf charts + helm repo add autoscaler https://kubernetes.github.io/autoscaler + helm repo update autoscaler + helm pull autoscaler/cluster-autoscaler --untar --untardir charts diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/.helmignore b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/.helmignore similarity index 100% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/.helmignore rename to packages/system/cluster-autoscaler/charts/cluster-autoscaler/.helmignore diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/Chart.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/Chart.yaml new file mode 100644 index 00000000..0c46f2c8 --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v2 +appVersion: 1.35.0 +description: Scales Kubernetes worker nodes within autoscaling groups. +home: https://github.com/kubernetes/autoscaler +icon: https://github.com/kubernetes/kubernetes/raw/master/logo/logo.png +maintainers: +- email: guyjtempleton@googlemail.com + name: gjtempleton +name: cluster-autoscaler +sources: +- https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler +type: application +version: 9.55.0 diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/README.md b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/README.md new file mode 100644 index 00000000..8a9da750 --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/README.md @@ -0,0 +1,545 @@ +# cluster-autoscaler + +Scales Kubernetes worker nodes within autoscaling groups. + +## TL;DR + +```console +$ helm repo add autoscaler https://kubernetes.github.io/autoscaler + +# Method 1 - Using Autodiscovery +$ helm install my-release autoscaler/cluster-autoscaler \ + --set 'autoDiscovery.clusterName'= + +# Method 2 - Specifying groups manually +$ helm install my-release autoscaler/cluster-autoscaler \ + --set "autoscalingGroups[0].name=your-asg-name" \ + --set "autoscalingGroups[0].maxSize=10" \ + --set "autoscalingGroups[0].minSize=1" +``` + +## Introduction + +This chart bootstraps a cluster-autoscaler deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +## Prerequisites + +- Helm 3+ +- Kubernetes 1.8+ + - [Older versions](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler#releases) may work by overriding the `image`. Cluster autoscaler internally simulates the scheduler and bugs between mismatched versions may be subtle. +- Azure AKS specific Prerequisites: + - Kubernetes 1.10+ with RBAC-enabled. + +## Previous Helm Chart + +The previous `cluster-autoscaler` Helm chart hosted at [helm/charts](https://github.com/helm/charts) has been moved to this repository in accordance with the [Deprecation timeline](https://github.com/helm/charts#deprecation-timeline). Note that a few things have changed between this version and the old version: + +- This repository **only** supports Helm chart installations using Helm 3+ since the `apiVersion` on the charts has been marked as `v2`. +- Previous versions of the Helm chart have not been migrated + +## Migration from 1.X to 9.X+ versions of this Chart + +**TL;DR:** +You should choose to use versions >=9.0.0 of the `cluster-autoscaler` chart published from this repository; previous versions, and the `cluster-autoscaler-chart` with versioning 1.X.X published from this repository are deprecated. + +
+ Previous versions of this chart - further details +On initial migration of this chart from the `helm/charts` repository this chart was renamed from `cluster-autoscaler` to `cluster-autoscaler-chart` due to technical limitations. This affected all `1.X` releases of the chart, version 2.0.0 of this chart exists only to mark the [`cluster-autoscaler-chart` chart](https://artifacthub.io/packages/helm/cluster-autoscaler/cluster-autoscaler-chart) as deprecated. + +Releases of the chart from `9.0.0` onwards return the naming of the chart to `cluster-autoscaler` and return to following the versioning established by the chart's previous location at . + +To migrate from a 1.X release of the chart to a `9.0.0` or later release, you should first uninstall your `1.X` install of the `cluster-autoscaler-chart` chart, before performing the installation of the new `cluster-autoscaler` chart. +
+ +## Migration from 9.0 to 9.1 + +Starting from `9.1.0` the `envFromConfigMap` value is expected to contain the name of a ConfigMap that is used as ref for `envFrom`, similar to `envFromSecret`. If you want to keep the previous behaviour of `envFromConfigMap` you must rename it to `extraEnvConfigMaps`. + +## Installing the Chart + +**By default, no deployment is created and nothing will autoscale**. + +You must provide some minimal configuration, either to specify instance groups or enable auto-discovery. It is not recommended to do both. + +Either: + +- Set `autoDiscovery.clusterName` and provide additional autodiscovery options if necessary **or** +- Set static node group configurations for one or more node groups (using `autoscalingGroups` or `autoscalingGroupsnamePrefix`). + +To create a valid configuration, follow instructions for your cloud provider: + +- [AWS](#aws---using-auto-discovery-of-tagged-instance-groups) +- [GCE](#gce) +- [Azure](#azure) +- [OpenStack Magnum](#openstack-magnum) +- [Cluster API](#cluster-api) +- [Exoscale](#exoscale) +- [Hetzner Cloud](#hetzner-cloud) +- [Civo](#civo) + +### Templating the autoDiscovery.clusterName + +The cluster name can be templated in the `autoDiscovery.clusterName` variable. This is useful when the cluster name is dynamically generated based on other values coming from external systems like Argo CD or Flux. This also allows you to use global Helm values to set the cluster name, e.g., `autoDiscovery.clusterName={{ .Values.global.clusterName }}`, so that you don't need to set it in more than 1 location in the values file. + +### AWS - Using auto-discovery of tagged instance groups + +Auto-discovery finds ASGs tags as below and automatically manages them based on the min and max size specified in the ASG. `cloudProvider=aws` only. + +- Tag the ASGs with keys to match `.Values.autoDiscovery.tags`, by default: `k8s.io/cluster-autoscaler/enabled` and `k8s.io/cluster-autoscaler/` +- Verify the [IAM Permissions](#aws---iam) +- Set `autoDiscovery.clusterName=` +- Set `awsRegion=` +- Set (option) `awsAccessKeyID=` and `awsSecretAccessKey=` if you want to [use AWS credentials directly instead of an instance role](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#using-aws-credentials) + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set autoDiscovery.clusterName= \ + --set awsRegion= +``` + +Alternatively with your own AWS credentials + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set autoDiscovery.clusterName= \ + --set awsRegion= \ + --set awsAccessKeyID= \ + --set awsSecretAccessKey= +``` + +#### Specifying groups manually + +Without autodiscovery, specify an array of elements each containing ASG name, min size, max size. The sizes specified here will be applied to the ASG, assuming IAM permissions are correctly configured. + +- Verify the [IAM Permissions](#aws---iam) +- Either provide a yaml file setting `autoscalingGroups` (see values.yaml) or use `--set` e.g.: + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set "autoscalingGroups[0].name=your-asg-name" \ + --set "autoscalingGroups[0].maxSize=10" \ + --set "autoscalingGroups[0].minSize=1" +``` + +#### Auto-discovery + +For auto-discovery of instances to work, they must be tagged with the keys in `.Values.autoDiscovery.tags`, which by default are `k8s.io/cluster-autoscaler/enabled` and `k8s.io/cluster-autoscaler/`. + +The value of the tag does not matter, only the key. + +An example kops spec excerpt: + +```yaml +apiVersion: kops/v1alpha2 +kind: Cluster +metadata: + name: my.cluster.internal +spec: + additionalPolicies: + node: | + [ + {"Effect":"Allow","Action":["autoscaling:DescribeAutoScalingGroups","autoscaling:DescribeAutoScalingInstances","autoscaling:DescribeLaunchConfigurations","autoscaling:DescribeTags","autoscaling:SetDesiredCapacity","autoscaling:TerminateInstanceInAutoScalingGroup"],"Resource":"*"} + ] + ... +--- +apiVersion: kops/v1alpha2 +kind: InstanceGroup +metadata: + labels: + kops.k8s.io/cluster: my.cluster.internal + name: my-instances +spec: + cloudLabels: + k8s.io/cluster-autoscaler/enabled: "" + k8s.io/cluster-autoscaler/my.cluster.internal: "" + image: kops.io/k8s-1.8-debian-jessie-amd64-hvm-ebs-2018-01-14 + machineType: r4.large + maxSize: 4 + minSize: 0 +``` + +In this example you would need to `--set autoDiscovery.clusterName=my.cluster.internal` when installing. + +It is not recommended to try to mix this with setting `autoscalingGroups`. + +See [autoscaler AWS documentation](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#auto-discovery-setup) for a more discussion of the setup. + +### GCE + +The following parameters are required: + +- `autoDiscovery.clusterName=any-name` +- `cloud-provider=gce` +- `autoscalingGroupsnamePrefix[0].name=your-ig-prefix,autoscalingGroupsnamePrefix[0].maxSize=10,autoscalingGroupsnamePrefix[0].minSize=1` + +To use Managed Instance Group (MIG) auto-discovery, provide a YAML file setting `autoscalingGroupsnamePrefix` (see values.yaml) or use `--set` when installing the Chart - e.g. + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set "autoscalingGroupsnamePrefix[0].name=your-ig-prefix,autoscalingGroupsnamePrefix[0].maxSize=10,autoscalingGroupsnamePrefix[0].minSize=1" \ + --set autoDiscovery.clusterName= \ + --set cloudProvider=gce +``` + +Note that `your-ig-prefix` should be a _prefix_ matching one or more MIGs, and _not_ the full name of the MIG. For example, to match multiple instance groups - `k8s-node-group-a-standard`, `k8s-node-group-b-gpu`, you would use a prefix of `k8s-node-group-`. + +Prefixes will be rendered using `tpl` function so you can use any value of your choice if that's a valid prefix. For instance (ignore escaping characters): `gke-{{ .Values.autoDiscovery.clusterName }}` + +In the event you want to explicitly specify MIGs instead of using auto-discovery, set members of the `autoscalingGroups` array directly - e.g. + +``` +# where 'n' is the index, starting at 0 +--set autoscalingGroups[n].name=https://content.googleapis.com/compute/v1/projects/$PROJECTID/zones/$ZONENAME/instanceGroups/$FULL-MIG-NAME,autoscalingGroups[n].maxSize=$MAXSIZE,autoscalingGroups[n].minSize=$MINSIZE +``` + +### Azure + +The following parameters are required: + +- `cloudProvider=azure` +- `autoscalingGroups[0].name=your-vmss,autoscalingGroups[0].maxSize=10,autoscalingGroups[0].minSize=1` +- `azureClientID: "your-service-principal-app-id"` +- `azureClientSecret: "your-service-principal-client-secret"` +- `azureSubscriptionID: "your-azure-subscription-id"` +- `azureTenantID: "your-azure-tenant-id"` +- `azureResourceGroup: "your-aks-cluster-resource-group-name"` +- `azureVMType: "vmss"` + +### OpenStack Magnum + +`cloudProvider: magnum` must be set, and then one of + +- `magnumClusterName=` and `autoscalingGroups` with the names of node groups and min/max node counts +- or `autoDiscovery.clusterName=` with one or more `autoDiscovery.roles`. + +Additionally, `cloudConfigPath: "/etc/kubernetes/cloud-config"` must be set as this should be the location of the cloud-config file on the host. + +Example values files can be found [here](../../cluster-autoscaler/cloudprovider/magnum/examples). + +Install the chart with + +```console +$ helm install my-release autoscaler/cluster-autoscaler -f myvalues.yaml +``` + +### Cluster-API + +`cloudProvider: clusterapi` must be set, and then one or more of + +- `autoDiscovery.clusterName` +- or `autoDiscovery.namespace` +- or `autoDiscovery.labels` + +See [here](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/clusterapi/README.md#configuring-node-group-auto-discovery) for more details. + +Additional config parameters available, see the `values.yaml` for more details + +- `clusterAPIMode` +- `clusterAPIKubeconfigSecret` +- `clusterAPIWorkloadKubeconfigPath` +- `clusterAPICloudConfigPath` + +### Exoscale + +Create a `values.yaml` file with the following content: +```yaml +cloudProvider: exoscale +autoDiscovery: + clusterName: cluster.local # this value is not used, but must be set +``` + +Optionally, you may specify the minimum and maximum size of a particular nodepool by adding the following to the `values.yaml` file: +```yaml +autoscalingGroups: + - name: your-nodepool-name + maxSize: 10 + minSize: 1 +``` + +Create an Exoscale API key with appropriate permissions as described in [cluster-autoscaler/cloudprovider/exoscale/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/exoscale/README.md). +A secret of name `-exoscale-cluster-autoscaler` needs to be created, containing the api key and secret, as well as the zone. + +```console +$ kubectl create secret generic my-release-exoscale-cluster-autoscaler \ + --from-literal=api-key="EXOxxxxxxxxxxxxxxxxxxxxxxxx" \ + --from-literal=api-secret="xxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" --from-literal=api-zone="ch-gva-2" +``` + +After creating the secret, the chart may be installed: + +```console +$ helm install my-release autoscaler/cluster-autoscaler -f values.yaml +``` + +Read [cluster-autoscaler/cloudprovider/exoscale/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/exoscale/README.md) for further information on the setup without helm. + +### Hetzner Cloud + +The following parameters are required: + +- `cloudProvider=hetzner` +- `extraEnv.HCLOUD_TOKEN=...` +- `autoscalingGroups=...` + +Each autoscaling group requires an additional `instanceType` and `region` key to be set. + +Read [cluster-autoscaler/cloudprovider/hetzner/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/hetzner/README.md) for further information on the setup without helm. + +### Civo + +The following parameters are required: + +- `cloudProvider=civo` +- `autoscalingGroups=...` + +When installing the helm chart to the namespace `kube-system`, you can set `secretKeyRefNameOverride` to `civo-api-access`. +Otherwise specify the following parameters: + +- `civoApiUrl=https://api.civo.com` +- `civoApiKey=...` +- `civoClusterID=...` +- `civoRegion=...` + +Read [cluster-autoscaler/cloudprovider/civo/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/civo/README.md) for further information on the setup without helm. + +## Uninstalling the Chart + +To uninstall `my-release`: + +```console +$ helm uninstall my-release +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +> **Tip**: List all releases using `helm list` or start clean with `helm uninstall my-release` + +## Additional Configuration + +### AWS - IAM + +The worker running the cluster autoscaler will need access to certain resources and actions depending on the version you run and your configuration of it. + +For the up-to-date IAM permissions required, please see the [cluster autoscaler's AWS Cloudprovider Readme](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#iam-policy) and switch to the tag of the cluster autoscaler image you are using. + +### AWS - IAM Roles for Service Accounts (IRSA) + +For Kubernetes clusters that use Amazon EKS, the service account can be configured with an IAM role using [IAM Roles for Service Accounts](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) to avoid needing to grant access to the worker nodes for AWS resources. + +In order to accomplish this, you will first need to create a new IAM role with the above mentions policies. Take care in [configuring the trust relationship](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts-technical-overview.html#iam-role-configuration) to restrict access just to the service account used by cluster autoscaler. + +Once you have the IAM role configured, you would then need to `--set rbac.serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=arn:aws:iam::123456789012:role/MyRoleName` when installing. Alternatively, you can embed templates in values (ignore escaping characters): + +```yaml +rbac: + serviceAccount: + annotations: + eks.amazonaws.com/role-arn: "{{ .Values.aws.myroleARN }}" +``` + +### Azure - Using azure workload identity + +You can use the project [Azure workload identity](https://github.com/Azure/azure-workload-identity), to automatically configure the correct setup for your pods to use federated identity with Azure. + +You can also set the correct settings yourself instead of relying on this project. + +For example the following configuration will configure the Autoscaler to use your federated identity: + +```yaml +azureUseWorkloadIdentityExtension: true +extraEnv: + AZURE_CLIENT_ID: USER ASSIGNED IDENTITY CLIENT ID + AZURE_TENANT_ID: USER ASSIGNED IDENTITY TENANT ID + AZURE_FEDERATED_TOKEN_FILE: /var/run/secrets/tokens/azure-identity-token + AZURE_AUTHORITY_HOST: https://login.microsoftonline.com/ +extraVolumes: +- name: azure-identity-token + projected: + defaultMode: 420 + sources: + - serviceAccountToken: + audience: api://AzureADTokenExchange + expirationSeconds: 3600 + path: azure-identity-token +extraVolumeMounts: +- mountPath: /var/run/secrets/tokens + name: azure-identity-token + readOnly: true +``` + +### Custom arguments + +You can use the `customArgs` value to give any argument to cluster autoscaler command. + +Typical use case is to give an environment variable as an argument which will be interpolated at execution time. + +This is helpful when you need to inject values from configmap or secret. + +## Troubleshooting + +The chart will succeed even if the container arguments are incorrect. A few minutes after starting `kubectl logs -l "app=aws-cluster-autoscaler" --tail=50` should loop through something like + +``` +polling_autoscaler.go:111] Poll finished +static_autoscaler.go:97] Starting main loop +utils.go:435] No pod using affinity / antiaffinity found in cluster, disabling affinity predicate for this loop +static_autoscaler.go:230] Filtering out schedulables +``` + +If not, find a pod that the deployment created and `describe` it, paying close attention to the arguments under `Command`. e.g.: + +``` +Containers: + cluster-autoscaler: + Command: + ./cluster-autoscaler + --cloud-provider=aws +# if specifying ASGs manually + --nodes=1:10:your-scaling-group-name +# if using autodiscovery + --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/ + --v=4 +``` + +### PodSecurityPolicy + +Though enough for the majority of installations, the default PodSecurityPolicy _could_ be too restrictive depending on the specifics of your release. Please make sure to check that the template fits with any customizations made or disable it by setting `rbac.pspEnabled` to `false`. + +### VerticalPodAutoscaler + +The CA Helm Chart can install a [`VerticalPodAutoscaler`](https://github.com/kubernetes/autoscaler/blob/master/vertical-pod-autoscaler/README.md) object from Chart version `9.27.0` +onwards for the Cluster Autoscaler Deployment to scale the CA as appropriate, but for that, we +need to install the VPA to the cluster separately. A VPA can help minimize wasted resources +when usage spikes periodically or remediate containers that are being OOMKilled. + +The following example snippet can be used to install VPA that allows scaling down from the default recommendations of the deployment template: + +```yaml +vpa: + enabled: true + containerPolicy: + minAllowed: + cpu: 20m + memory: 50Mi +``` + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| additionalLabels | object | `{}` | Labels to add to each object of the chart. | +| affinity | object | `{}` | Affinity for pod assignment | +| autoDiscovery.clusterName | string | `nil` | Enable autodiscovery for `cloudProvider=aws`, for groups matching `autoDiscovery.tags`. autoDiscovery.clusterName -- Enable autodiscovery for `cloudProvider=azure`, using tags defined in https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/azure/README.md#auto-discovery-setup. Enable autodiscovery for `cloudProvider=clusterapi`, for groups matching `autoDiscovery.labels`. Enable autodiscovery for `cloudProvider=gce`, but no MIG tagging required. Enable autodiscovery for `cloudProvider=magnum`, for groups matching `autoDiscovery.roles`. | +| autoDiscovery.labels | list | `[]` | Cluster-API labels to match https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/clusterapi/README.md#configuring-node-group-auto-discovery | +| autoDiscovery.namespace | string | `nil` | Enable autodiscovery via cluster namespace for for `cloudProvider=clusterapi` | +| autoDiscovery.roles | list | `["worker"]` | Magnum node group roles to match. | +| autoDiscovery.tags | list | `["k8s.io/cluster-autoscaler/enabled","k8s.io/cluster-autoscaler/{{ .Values.autoDiscovery.clusterName }}"]` | ASG tags to match, run through `tpl`. | +| autoscalingGroups | list | `[]` | For AWS, Azure AKS, Exoscale or Magnum. At least one element is required if not using `autoDiscovery`. For example:
 - name: asg1
maxSize: 2
minSize: 1
For Hetzner Cloud, the `instanceType` and `region` keys are also required.
 - name: mypool
maxSize: 2
minSize: 1
instanceType: CPX21
region: FSN1
| +| autoscalingGroupsnamePrefix | list | `[]` | For GCE. At least one element is required if not using `autoDiscovery`. For example:
 - name: ig01
maxSize: 10
minSize: 0
| +| awsAccessKeyID | string | `""` | AWS access key ID ([if AWS user keys used](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#using-aws-credentials)) | +| awsRegion | string | `""` | AWS region (required if `cloudProvider=aws`) | +| awsSecretAccessKey | string | `""` | AWS access secret key ([if AWS user keys used](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#using-aws-credentials)) | +| azureClientID | string | `""` | Service Principal ClientID with contributor permission to Cluster and Node ResourceGroup. Required if `cloudProvider=azure` | +| azureClientSecret | string | `""` | Service Principal ClientSecret with contributor permission to Cluster and Node ResourceGroup. Required if `cloudProvider=azure` | +| azureEnableForceDelete | bool | `false` | Whether to force delete VMs or VMSS instances when scaling down. | +| azureResourceGroup | string | `""` | Azure resource group that the cluster is located. Required if `cloudProvider=azure` | +| azureSubscriptionID | string | `""` | Azure subscription where the resources are located. Required if `cloudProvider=azure` | +| azureTenantID | string | `""` | Azure tenant where the resources are located. Required if `cloudProvider=azure` | +| azureUseManagedIdentityExtension | bool | `false` | Whether to use Azure's managed identity extension for credentials. If using MSI, ensure subscription ID, resource group, and azure AKS cluster name are set. You can only use one authentication method at a time, either azureUseWorkloadIdentityExtension or azureUseManagedIdentityExtension should be set. | +| azureUseWorkloadIdentityExtension | bool | `false` | Whether to use Azure's workload identity extension for credentials. See the project here: https://github.com/Azure/azure-workload-identity for more details. You can only use one authentication method at a time, either azureUseWorkloadIdentityExtension or azureUseManagedIdentityExtension should be set. | +| azureUserAssignedIdentityID | string | `""` | When vmss has multiple user assigned identity assigned, azureUserAssignedIdentityID specifies which identity to be used | +| azureVMType | string | `"vmss"` | Azure VM type. | +| civoApiKey | string | `""` | API key for the Civo API. Required if `cloudProvider=civo` | +| civoApiUrl | string | `"https://api.civo.com"` | URL for the Civo API. Required if `cloudProvider=civo` | +| civoClusterID | string | `""` | Cluster ID for the Civo cluster. Required if `cloudProvider=civo` | +| civoRegion | string | `""` | Region for the Civo cluster. Required if `cloudProvider=civo` | +| cloudConfigPath | string | `""` | Configuration file for cloud provider. | +| cloudProvider | string | `"aws"` | The cloud provider where the autoscaler runs. Currently only `gce`, `aws`, `azure`, `magnum`, `clusterapi`, `civo` and `coreweave` are supported. `aws` supported for AWS. `gce` for GCE. `azure` for Azure AKS. `magnum` for OpenStack Magnum, `clusterapi` for Cluster API. `civo` for Civo Cloud. `coreweave` for CoreWeave. | +| clusterAPICloudConfigPath | string | `"/etc/kubernetes/mgmt-kubeconfig"` | Path to kubeconfig for connecting to Cluster API Management Cluster, only used if `clusterAPIMode=kubeconfig-kubeconfig or incluster-kubeconfig` | +| clusterAPIConfigMapsNamespace | string | `""` | Namespace on the workload cluster to store Leader election and status configmaps | +| clusterAPIKubeconfigSecret | string | `""` | Secret containing kubeconfig for connecting to Cluster API managed workloadcluster Required if `cloudProvider=clusterapi` and `clusterAPIMode=kubeconfig-kubeconfig,kubeconfig-incluster or incluster-kubeconfig` | +| clusterAPIMode | string | `"incluster-incluster"` | Cluster API mode, see https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/clusterapi/README.md#connecting-cluster-autoscaler-to-cluster-api-management-and-workload-clusters Syntax: workloadClusterMode-ManagementClusterMode for `kubeconfig-kubeconfig`, `incluster-kubeconfig` and `single-kubeconfig` you always must mount the external kubeconfig using either `extraVolumeSecrets` or `extraMounts` and `extraVolumes` if you dont set `clusterAPIKubeconfigSecret`and thus use an in-cluster config or want to use a non capi generated kubeconfig you must do so for the workload kubeconfig as well | +| clusterAPIWorkloadKubeconfigPath | string | `"/etc/kubernetes/value"` | Path to kubeconfig for connecting to Cluster API managed workloadcluster, only used if `clusterAPIMode=kubeconfig-kubeconfig or kubeconfig-incluster` | +| containerSecurityContext | object | `{}` | [Security context for container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) | +| customArgs | list | `[]` | Additional custom container arguments. Refer to https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#what-are-the-parameters-to-ca for the full list of cluster autoscaler parameters and their default values. List of arguments as strings. | +| deployment.annotations | object | `{}` | Annotations to add to the Deployment object. | +| deployment.selector | object | `{}` | Labels for Deployment `spec.selector.matchLabels`. | +| dnsConfig | object | `{}` | [Pod's DNS Config](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config) | +| dnsPolicy | string | `"ClusterFirst"` | Defaults to `ClusterFirst`. Valid values are: `ClusterFirstWithHostNet`, `ClusterFirst`, `Default` or `None`. If autoscaler does not depend on cluster DNS, recommended to set this to `Default`. | +| envFromConfigMap | string | `""` | ConfigMap name to use as envFrom. | +| envFromSecret | string | `""` | Secret name to use as envFrom. | +| expanderPriorities | object | `{}` | The expanderPriorities is used if `extraArgs.expander` contains `priority` and expanderPriorities is also set with the priorities. If `extraArgs.expander` contains `priority`, then expanderPriorities is used to define cluster-autoscaler-priority-expander priorities. See: https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/expander/priority/readme.md | +| extraArgs | object | `{"logtostderr":true,"stderrthreshold":"info","v":4}` | Additional container arguments. Refer to https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#what-are-the-parameters-to-ca for the full list of cluster autoscaler parameters and their default values. Everything after the first _ will be ignored allowing the use of multi-string arguments. | +| extraEnv | object | `{}` | Additional container environment variables. | +| extraEnvConfigMaps | object | `{}` | Additional container environment variables from ConfigMaps. | +| extraEnvSecrets | object | `{}` | Additional container environment variables from Secrets. | +| extraObjects | list | `[]` | Extra K8s manifests to deploy | +| extraVolumeMounts | list | `[]` | Additional volumes to mount. | +| extraVolumeSecrets | object | `{}` | Additional volumes to mount from Secrets. | +| extraVolumes | list | `[]` | Additional volumes. | +| fullnameOverride | string | `""` | String to fully override `cluster-autoscaler.fullname` template. | +| hostNetwork | bool | `false` | Whether to expose network interfaces of the host machine to pods. | +| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy | +| image.pullSecrets | list | `[]` | Image pull secrets | +| image.repository | string | `"registry.k8s.io/autoscaling/cluster-autoscaler"` | Image repository | +| image.tag | string | `"v1.34.2"` | Image tag | +| initContainers | list | `[]` | Any additional init containers. | +| kubeTargetVersionOverride | string | `""` | Allow overriding the `.Capabilities.KubeVersion.GitVersion` check. Useful for `helm template` commands. | +| kwokConfigMapName | string | `"kwok-provider-config"` | configmap for configuring kwok provider | +| magnumCABundlePath | string | `"/etc/kubernetes/ca-bundle.crt"` | Path to the host's CA bundle, from `ca-file` in the cloud-config file. | +| magnumClusterName | string | `""` | Cluster name or ID in Magnum. Required if `cloudProvider=magnum` and not setting `autoDiscovery.clusterName`. | +| nameOverride | string | `""` | String to partially override `cluster-autoscaler.fullname` template (will maintain the release name) | +| nodeSelector | object | `{}` | Node labels for pod assignment. Ref: https://kubernetes.io/docs/user-guide/node-selection/. | +| podAnnotations | object | `{}` | Annotations to add to each pod. | +| podDisruptionBudget | object | `{"annotations":{},"maxUnavailable":1,"selector":{}}` | Pod disruption budget. | +| podDisruptionBudget.annotations | object | `{}` | Annotations to add to the PodDisruptionBudget. | +| podDisruptionBudget.selector | object | `{}` | Override labels for PodDisruptionBudget `spec.selector.matchLabels`. | +| podLabels | object | `{}` | Labels to add to each pod. | +| priorityClassName | string | `"system-cluster-critical"` | priorityClassName | +| priorityConfigMapAnnotations | object | `{}` | Annotations to add to `cluster-autoscaler-priority-expander` ConfigMap. | +| prometheusRule.additionalLabels | object | `{}` | Additional labels to be set in metadata. | +| prometheusRule.enabled | bool | `false` | If true, creates a Prometheus Operator PrometheusRule. | +| prometheusRule.interval | string | `nil` | How often rules in the group are evaluated (falls back to `global.evaluation_interval` if not set). | +| prometheusRule.namespace | string | `"monitoring"` | Namespace which Prometheus is running in. | +| prometheusRule.rules | list | `[]` | Rules spec template (see https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#rule). | +| rbac.additionalRules | list | `[]` | Additional rules for role/clusterrole | +| rbac.annotations | object | `{}` | Additional annotations to add to RBAC resources (Role/RoleBinding/ClusterRole/ClusterRoleBinding). | +| rbac.clusterScoped | bool | `true` | if set to false will only provision RBAC to alter resources in the current namespace. Most useful for Cluster-API | +| rbac.create | bool | `true` | If `true`, create and use RBAC resources. | +| rbac.pspEnabled | bool | `false` | If `true`, creates and uses RBAC resources required in the cluster with [Pod Security Policies](https://kubernetes.io/docs/concepts/policy/pod-security-policy/) enabled. Must be used with `rbac.create` set to `true`. | +| rbac.serviceAccount.annotations | object | `{}` | Additional Service Account annotations. | +| rbac.serviceAccount.automountServiceAccountToken | bool | `true` | Automount API credentials for a Service Account. | +| rbac.serviceAccount.create | bool | `true` | If `true` and `rbac.create` is also true, a Service Account will be created. | +| rbac.serviceAccount.name | string | `""` | The name of the ServiceAccount to use. If not set and create is `true`, a name is generated using the fullname template. | +| replicaCount | int | `1` | Desired number of pods | +| resources | object | `{}` | Pod resource requests and limits. | +| revisionHistoryLimit | int | `10` | The number of revisions to keep. | +| secretKeyRefNameOverride | string | `""` | Overrides the name of the Secret to use when loading the secretKeyRef for AWS, Azure and Civo env variables | +| securityContext | object | `{}` | [Security context for pod](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) | +| service.annotations | object | `{}` | Annotations to add to service | +| service.clusterIP | string | `""` | IP address to assign to service | +| service.create | bool | `true` | If `true`, a Service will be created. | +| service.externalIPs | list | `[]` | List of IP addresses at which the service is available. Ref: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips. | +| service.labels | object | `{}` | Labels to add to service | +| service.loadBalancerIP | string | `""` | IP address to assign to load balancer (if supported). | +| service.loadBalancerSourceRanges | list | `[]` | List of IP CIDRs allowed access to load balancer (if supported). | +| service.portName | string | `"http"` | Name for service port. | +| service.selector | object | `{}` | Override labels for Service `spec.selector`. | +| service.servicePort | int | `8085` | Service port to expose. | +| service.type | string | `"ClusterIP"` | Type of service to create. | +| serviceMonitor.annotations | object | `{}` | Annotations to add to service monitor | +| serviceMonitor.enabled | bool | `false` | If true, creates a Prometheus Operator ServiceMonitor. | +| serviceMonitor.interval | string | `"10s"` | Interval that Prometheus scrapes Cluster Autoscaler metrics. | +| serviceMonitor.metricRelabelings | object | `{}` | MetricRelabelConfigs to apply to samples before ingestion. | +| serviceMonitor.namespace | string | `"monitoring"` | Namespace which Prometheus is running in. | +| serviceMonitor.path | string | `"/metrics"` | The path to scrape for metrics; autoscaler exposes `/metrics` (this is standard) | +| serviceMonitor.relabelings | object | `{}` | RelabelConfigs to apply to metrics before scraping. | +| serviceMonitor.selector | object | `{"release":"prometheus-operator"}` | Default to kube-prometheus install (CoreOS recommended), but should be set according to Prometheus install. | +| tolerations | list | `[]` | List of node taints to tolerate (requires Kubernetes >= 1.6). | +| topologySpreadConstraints | list | `[]` | You can use topology spread constraints to control how Pods are spread across your cluster among failure-domains such as regions, zones, nodes, and other user-defined topology domains. (requires Kubernetes >= 1.19). | +| updateStrategy | object | `{}` | [Deployment update strategy](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy) | +| vpa | object | `{"containerPolicy":{},"enabled":false,"recommender":"default","updateMode":"Auto"}` | Configure a VerticalPodAutoscaler for the cluster-autoscaler Deployment. | +| vpa.containerPolicy | object | `{}` | [ContainerResourcePolicy](https://github.com/kubernetes/autoscaler/blob/vertical-pod-autoscaler/v0.13.0/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1/types.go#L159). The containerName is always set to the deployment's container name. This value is required if VPA is enabled. | +| vpa.enabled | bool | `false` | If true, creates a VerticalPodAutoscaler. | +| vpa.recommender | string | `"default"` | Name of the VPA recommender that will provide recommendations for vertical scaling. | +| vpa.updateMode | string | `"Auto"` | [UpdateMode](https://github.com/kubernetes/autoscaler/blob/vertical-pod-autoscaler/v0.13.0/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1/types.go#L124) | diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/README.md.gotmpl b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/README.md.gotmpl new file mode 100644 index 00000000..0567e283 --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/README.md.gotmpl @@ -0,0 +1,426 @@ +{{ template "chart.header" . }} + +{{ template "chart.description" . }} + +## TL;DR + +```console +$ helm repo add autoscaler https://kubernetes.github.io/autoscaler + +# Method 1 - Using Autodiscovery +$ helm install my-release autoscaler/cluster-autoscaler \ + --set 'autoDiscovery.clusterName'= + +# Method 2 - Specifying groups manually +$ helm install my-release autoscaler/cluster-autoscaler \ + --set "autoscalingGroups[0].name=your-asg-name" \ + --set "autoscalingGroups[0].maxSize=10" \ + --set "autoscalingGroups[0].minSize=1" +``` + +## Introduction + +This chart bootstraps a cluster-autoscaler deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +## Prerequisites + +- Helm 3+ +- Kubernetes 1.8+ + - [Older versions](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler#releases) may work by overriding the `image`. Cluster autoscaler internally simulates the scheduler and bugs between mismatched versions may be subtle. +- Azure AKS specific Prerequisites: + - Kubernetes 1.10+ with RBAC-enabled. + +## Previous Helm Chart + +The previous `cluster-autoscaler` Helm chart hosted at [helm/charts](https://github.com/helm/charts) has been moved to this repository in accordance with the [Deprecation timeline](https://github.com/helm/charts#deprecation-timeline). Note that a few things have changed between this version and the old version: + +- This repository **only** supports Helm chart installations using Helm 3+ since the `apiVersion` on the charts has been marked as `v2`. +- Previous versions of the Helm chart have not been migrated + +## Migration from 1.X to 9.X+ versions of this Chart + +**TL;DR:** +You should choose to use versions >=9.0.0 of the `cluster-autoscaler` chart published from this repository; previous versions, and the `cluster-autoscaler-chart` with versioning 1.X.X published from this repository are deprecated. + +
+ Previous versions of this chart - further details +On initial migration of this chart from the `helm/charts` repository this chart was renamed from `cluster-autoscaler` to `cluster-autoscaler-chart` due to technical limitations. This affected all `1.X` releases of the chart, version 2.0.0 of this chart exists only to mark the [`cluster-autoscaler-chart` chart](https://artifacthub.io/packages/helm/cluster-autoscaler/cluster-autoscaler-chart) as deprecated. + +Releases of the chart from `9.0.0` onwards return the naming of the chart to `cluster-autoscaler` and return to following the versioning established by the chart's previous location at . + +To migrate from a 1.X release of the chart to a `9.0.0` or later release, you should first uninstall your `1.X` install of the `cluster-autoscaler-chart` chart, before performing the installation of the new `cluster-autoscaler` chart. +
+ +## Migration from 9.0 to 9.1 + +Starting from `9.1.0` the `envFromConfigMap` value is expected to contain the name of a ConfigMap that is used as ref for `envFrom`, similar to `envFromSecret`. If you want to keep the previous behaviour of `envFromConfigMap` you must rename it to `extraEnvConfigMaps`. + +## Installing the Chart + +**By default, no deployment is created and nothing will autoscale**. + +You must provide some minimal configuration, either to specify instance groups or enable auto-discovery. It is not recommended to do both. + +Either: + +- Set `autoDiscovery.clusterName` and provide additional autodiscovery options if necessary **or** +- Set static node group configurations for one or more node groups (using `autoscalingGroups` or `autoscalingGroupsnamePrefix`). + +To create a valid configuration, follow instructions for your cloud provider: + +- [AWS](#aws---using-auto-discovery-of-tagged-instance-groups) +- [GCE](#gce) +- [Azure](#azure) +- [OpenStack Magnum](#openstack-magnum) +- [Cluster API](#cluster-api) +- [Exoscale](#exoscale) +- [Hetzner Cloud](#hetzner-cloud) +- [Civo](#civo) + +### Templating the autoDiscovery.clusterName + +The cluster name can be templated in the `autoDiscovery.clusterName` variable. This is useful when the cluster name is dynamically generated based on other values coming from external systems like Argo CD or Flux. This also allows you to use global Helm values to set the cluster name, e.g., `autoDiscovery.clusterName={{`{{ .Values.global.clusterName }}`}}`, so that you don't need to set it in more than 1 location in the values file. + +### AWS - Using auto-discovery of tagged instance groups + +Auto-discovery finds ASGs tags as below and automatically manages them based on the min and max size specified in the ASG. `cloudProvider=aws` only. + +- Tag the ASGs with keys to match `.Values.autoDiscovery.tags`, by default: `k8s.io/cluster-autoscaler/enabled` and `k8s.io/cluster-autoscaler/` +- Verify the [IAM Permissions](#aws---iam) +- Set `autoDiscovery.clusterName=` +- Set `awsRegion=` +- Set (option) `awsAccessKeyID=` and `awsSecretAccessKey=` if you want to [use AWS credentials directly instead of an instance role](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#using-aws-credentials) + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set autoDiscovery.clusterName= \ + --set awsRegion= +``` + +Alternatively with your own AWS credentials + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set autoDiscovery.clusterName= \ + --set awsRegion= \ + --set awsAccessKeyID= \ + --set awsSecretAccessKey= +``` + +#### Specifying groups manually + +Without autodiscovery, specify an array of elements each containing ASG name, min size, max size. The sizes specified here will be applied to the ASG, assuming IAM permissions are correctly configured. + +- Verify the [IAM Permissions](#aws---iam) +- Either provide a yaml file setting `autoscalingGroups` (see values.yaml) or use `--set` e.g.: + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set "autoscalingGroups[0].name=your-asg-name" \ + --set "autoscalingGroups[0].maxSize=10" \ + --set "autoscalingGroups[0].minSize=1" +``` + +#### Auto-discovery + +For auto-discovery of instances to work, they must be tagged with the keys in `.Values.autoDiscovery.tags`, which by default are `k8s.io/cluster-autoscaler/enabled` and `k8s.io/cluster-autoscaler/`. + +The value of the tag does not matter, only the key. + +An example kops spec excerpt: + +```yaml +apiVersion: kops/v1alpha2 +kind: Cluster +metadata: + name: my.cluster.internal +spec: + additionalPolicies: + node: | + [ + {"Effect":"Allow","Action":["autoscaling:DescribeAutoScalingGroups","autoscaling:DescribeAutoScalingInstances","autoscaling:DescribeLaunchConfigurations","autoscaling:DescribeTags","autoscaling:SetDesiredCapacity","autoscaling:TerminateInstanceInAutoScalingGroup"],"Resource":"*"} + ] + ... +--- +apiVersion: kops/v1alpha2 +kind: InstanceGroup +metadata: + labels: + kops.k8s.io/cluster: my.cluster.internal + name: my-instances +spec: + cloudLabels: + k8s.io/cluster-autoscaler/enabled: "" + k8s.io/cluster-autoscaler/my.cluster.internal: "" + image: kops.io/k8s-1.8-debian-jessie-amd64-hvm-ebs-2018-01-14 + machineType: r4.large + maxSize: 4 + minSize: 0 +``` + +In this example you would need to `--set autoDiscovery.clusterName=my.cluster.internal` when installing. + +It is not recommended to try to mix this with setting `autoscalingGroups`. + +See [autoscaler AWS documentation](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#auto-discovery-setup) for a more discussion of the setup. + +### GCE + +The following parameters are required: + +- `autoDiscovery.clusterName=any-name` +- `cloud-provider=gce` +- `autoscalingGroupsnamePrefix[0].name=your-ig-prefix,autoscalingGroupsnamePrefix[0].maxSize=10,autoscalingGroupsnamePrefix[0].minSize=1` + +To use Managed Instance Group (MIG) auto-discovery, provide a YAML file setting `autoscalingGroupsnamePrefix` (see values.yaml) or use `--set` when installing the Chart - e.g. + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set "autoscalingGroupsnamePrefix[0].name=your-ig-prefix,autoscalingGroupsnamePrefix[0].maxSize=10,autoscalingGroupsnamePrefix[0].minSize=1" \ + --set autoDiscovery.clusterName= \ + --set cloudProvider=gce +``` + +Note that `your-ig-prefix` should be a _prefix_ matching one or more MIGs, and _not_ the full name of the MIG. For example, to match multiple instance groups - `k8s-node-group-a-standard`, `k8s-node-group-b-gpu`, you would use a prefix of `k8s-node-group-`. + +Prefixes will be rendered using `tpl` function so you can use any value of your choice if that's a valid prefix. For instance (ignore escaping characters): `gke-{{`{{ .Values.autoDiscovery.clusterName }}`}}` + +In the event you want to explicitly specify MIGs instead of using auto-discovery, set members of the `autoscalingGroups` array directly - e.g. + +``` +# where 'n' is the index, starting at 0 +--set autoscalingGroups[n].name=https://content.googleapis.com/compute/v1/projects/$PROJECTID/zones/$ZONENAME/instanceGroups/$FULL-MIG-NAME,autoscalingGroups[n].maxSize=$MAXSIZE,autoscalingGroups[n].minSize=$MINSIZE +``` + +### Azure + +The following parameters are required: + +- `cloudProvider=azure` +- `autoscalingGroups[0].name=your-vmss,autoscalingGroups[0].maxSize=10,autoscalingGroups[0].minSize=1` +- `azureClientID: "your-service-principal-app-id"` +- `azureClientSecret: "your-service-principal-client-secret"` +- `azureSubscriptionID: "your-azure-subscription-id"` +- `azureTenantID: "your-azure-tenant-id"` +- `azureResourceGroup: "your-aks-cluster-resource-group-name"` +- `azureVMType: "vmss"` + +### OpenStack Magnum + +`cloudProvider: magnum` must be set, and then one of + +- `magnumClusterName=` and `autoscalingGroups` with the names of node groups and min/max node counts +- or `autoDiscovery.clusterName=` with one or more `autoDiscovery.roles`. + +Additionally, `cloudConfigPath: "/etc/kubernetes/cloud-config"` must be set as this should be the location of the cloud-config file on the host. + +Example values files can be found [here](../../cluster-autoscaler/cloudprovider/magnum/examples). + +Install the chart with + +```console +$ helm install my-release autoscaler/cluster-autoscaler -f myvalues.yaml +``` + +### Cluster-API + +`cloudProvider: clusterapi` must be set, and then one or more of + +- `autoDiscovery.clusterName` +- or `autoDiscovery.namespace` +- or `autoDiscovery.labels` + +See [here](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/clusterapi/README.md#configuring-node-group-auto-discovery) for more details. + +Additional config parameters available, see the `values.yaml` for more details + +- `clusterAPIMode` +- `clusterAPIKubeconfigSecret` +- `clusterAPIWorkloadKubeconfigPath` +- `clusterAPICloudConfigPath` + +### Exoscale + +Create a `values.yaml` file with the following content: +```yaml +cloudProvider: exoscale +autoDiscovery: + clusterName: cluster.local # this value is not used, but must be set +``` + +Optionally, you may specify the minimum and maximum size of a particular nodepool by adding the following to the `values.yaml` file: +```yaml +autoscalingGroups: + - name: your-nodepool-name + maxSize: 10 + minSize: 1 +``` + +Create an Exoscale API key with appropriate permissions as described in [cluster-autoscaler/cloudprovider/exoscale/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/exoscale/README.md). +A secret of name `-exoscale-cluster-autoscaler` needs to be created, containing the api key and secret, as well as the zone. + +```console +$ kubectl create secret generic my-release-exoscale-cluster-autoscaler \ + --from-literal=api-key="EXOxxxxxxxxxxxxxxxxxxxxxxxx" \ + --from-literal=api-secret="xxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" --from-literal=api-zone="ch-gva-2" +``` + +After creating the secret, the chart may be installed: + +```console +$ helm install my-release autoscaler/cluster-autoscaler -f values.yaml +``` + +Read [cluster-autoscaler/cloudprovider/exoscale/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/exoscale/README.md) for further information on the setup without helm. + +### Hetzner Cloud + +The following parameters are required: + +- `cloudProvider=hetzner` +- `extraEnv.HCLOUD_TOKEN=...` +- `autoscalingGroups=...` + +Each autoscaling group requires an additional `instanceType` and `region` key to be set. + +Read [cluster-autoscaler/cloudprovider/hetzner/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/hetzner/README.md) for further information on the setup without helm. + +### Civo + +The following parameters are required: + +- `cloudProvider=civo` +- `autoscalingGroups=...` + +When installing the helm chart to the namespace `kube-system`, you can set `secretKeyRefNameOverride` to `civo-api-access`. +Otherwise specify the following parameters: + +- `civoApiUrl=https://api.civo.com` +- `civoApiKey=...` +- `civoClusterID=...` +- `civoRegion=...` + +Read [cluster-autoscaler/cloudprovider/civo/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/civo/README.md) for further information on the setup without helm. + +## Uninstalling the Chart + +To uninstall `my-release`: + +```console +$ helm uninstall my-release +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +> **Tip**: List all releases using `helm list` or start clean with `helm uninstall my-release` + +## Additional Configuration + +### AWS - IAM + +The worker running the cluster autoscaler will need access to certain resources and actions depending on the version you run and your configuration of it. + +For the up-to-date IAM permissions required, please see the [cluster autoscaler's AWS Cloudprovider Readme](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#iam-policy) and switch to the tag of the cluster autoscaler image you are using. + +### AWS - IAM Roles for Service Accounts (IRSA) + +For Kubernetes clusters that use Amazon EKS, the service account can be configured with an IAM role using [IAM Roles for Service Accounts](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) to avoid needing to grant access to the worker nodes for AWS resources. + +In order to accomplish this, you will first need to create a new IAM role with the above mentions policies. Take care in [configuring the trust relationship](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts-technical-overview.html#iam-role-configuration) to restrict access just to the service account used by cluster autoscaler. + +Once you have the IAM role configured, you would then need to `--set rbac.serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=arn:aws:iam::123456789012:role/MyRoleName` when installing. Alternatively, you can embed templates in values (ignore escaping characters): + +```yaml +rbac: + serviceAccount: + annotations: + eks.amazonaws.com/role-arn: "{{`{{ .Values.aws.myroleARN `}}}}" +``` + +### Azure - Using azure workload identity + +You can use the project [Azure workload identity](https://github.com/Azure/azure-workload-identity), to automatically configure the correct setup for your pods to use federated identity with Azure. + +You can also set the correct settings yourself instead of relying on this project. + +For example the following configuration will configure the Autoscaler to use your federated identity: + +```yaml +azureUseWorkloadIdentityExtension: true +extraEnv: + AZURE_CLIENT_ID: USER ASSIGNED IDENTITY CLIENT ID + AZURE_TENANT_ID: USER ASSIGNED IDENTITY TENANT ID + AZURE_FEDERATED_TOKEN_FILE: /var/run/secrets/tokens/azure-identity-token + AZURE_AUTHORITY_HOST: https://login.microsoftonline.com/ +extraVolumes: +- name: azure-identity-token + projected: + defaultMode: 420 + sources: + - serviceAccountToken: + audience: api://AzureADTokenExchange + expirationSeconds: 3600 + path: azure-identity-token +extraVolumeMounts: +- mountPath: /var/run/secrets/tokens + name: azure-identity-token + readOnly: true +``` + +### Custom arguments + +You can use the `customArgs` value to give any argument to cluster autoscaler command. + +Typical use case is to give an environment variable as an argument which will be interpolated at execution time. + +This is helpful when you need to inject values from configmap or secret. + +## Troubleshooting + +The chart will succeed even if the container arguments are incorrect. A few minutes after starting `kubectl logs -l "app=aws-cluster-autoscaler" --tail=50` should loop through something like + +``` +polling_autoscaler.go:111] Poll finished +static_autoscaler.go:97] Starting main loop +utils.go:435] No pod using affinity / antiaffinity found in cluster, disabling affinity predicate for this loop +static_autoscaler.go:230] Filtering out schedulables +``` + +If not, find a pod that the deployment created and `describe` it, paying close attention to the arguments under `Command`. e.g.: + +``` +Containers: + cluster-autoscaler: + Command: + ./cluster-autoscaler + --cloud-provider=aws +# if specifying ASGs manually + --nodes=1:10:your-scaling-group-name +# if using autodiscovery + --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/ + --v=4 +``` + +### PodSecurityPolicy + +Though enough for the majority of installations, the default PodSecurityPolicy _could_ be too restrictive depending on the specifics of your release. Please make sure to check that the template fits with any customizations made or disable it by setting `rbac.pspEnabled` to `false`. + +### VerticalPodAutoscaler + +The CA Helm Chart can install a [`VerticalPodAutoscaler`](https://github.com/kubernetes/autoscaler/blob/master/vertical-pod-autoscaler/README.md) object from Chart version `9.27.0` +onwards for the Cluster Autoscaler Deployment to scale the CA as appropriate, but for that, we +need to install the VPA to the cluster separately. A VPA can help minimize wasted resources +when usage spikes periodically or remediate containers that are being OOMKilled. + +The following example snippet can be used to install VPA that allows scaling down from the default recommendations of the deployment template: + +```yaml +vpa: + enabled: true + containerPolicy: + minAllowed: + cpu: 20m + memory: 50Mi +``` + +{{ template "chart.valuesSection" . }} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/NOTES.txt b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/NOTES.txt new file mode 100644 index 00000000..1a87a3d1 --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/NOTES.txt @@ -0,0 +1,18 @@ +{{- if or ( or .Values.autoDiscovery.clusterName .Values.autoDiscovery.namespace .Values.autoDiscovery.labels ) .Values.autoscalingGroups }} + +To verify that cluster-autoscaler has started, run: + + kubectl --namespace={{ .Release.Namespace }} get pods -l "app.kubernetes.io/name={{ template "cluster-autoscaler.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" + +{{- else -}} + +############################################################################## +#### ERROR: You must specify values for either #### +#### autoDiscovery or autoscalingGroups[] #### +############################################################################## + +The deployment and pod will not be created and the installation is not functional +See README: + open https://github.com/kubernetes/autoscaler/tree/master/charts/cluster-autoscaler + +{{- end -}} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/_helpers.tpl b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/_helpers.tpl new file mode 100644 index 00000000..c7e80f4d --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/_helpers.tpl @@ -0,0 +1,160 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "cluster-autoscaler.name" -}} +{{- default (printf "%s-%s" .Values.cloudProvider .Chart.Name) .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "cluster-autoscaler.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default (printf "%s-%s" .Values.cloudProvider .Chart.Name) .Values.nameOverride -}} +{{- if ne $name .Release.Name -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s" $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "cluster-autoscaler.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Return instance and name labels. +*/}} +{{- define "cluster-autoscaler.instance-name" -}} +app.kubernetes.io/instance: {{ .Release.Name | quote }} +app.kubernetes.io/name: {{ include "cluster-autoscaler.name" . | quote }} +{{- end -}} + + +{{/* +Return labels, including instance and name. +*/}} +{{- define "cluster-autoscaler.labels" -}} +{{ include "cluster-autoscaler.instance-name" . }} +app.kubernetes.io/managed-by: {{ .Release.Service | quote }} +helm.sh/chart: {{ include "cluster-autoscaler.chart" . | quote }} +{{- if .Values.additionalLabels }} +{{ toYaml .Values.additionalLabels }} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for deployment. +*/}} +{{- define "deployment.apiVersion" -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if semverCompare "<1.9-0" $kubeTargetVersion -}} +{{- print "apps/v1beta2" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for podsecuritypolicy. +*/}} +{{- define "podsecuritypolicy.apiVersion" -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if semverCompare "<1.10-0" $kubeTargetVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "policy/v1beta1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for podDisruptionBudget. +*/}} +{{- define "podDisruptionBudget.apiVersion" -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if semverCompare "<1.21-0" $kubeTargetVersion -}} +{{- print "policy/v1beta1" -}} +{{- else -}} +{{- print "policy/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the service account name used by the pod. +*/}} +{{- define "cluster-autoscaler.serviceAccountName" -}} +{{- if .Values.rbac.serviceAccount.create -}} + {{ default (include "cluster-autoscaler.fullname" .) .Values.rbac.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.rbac.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Return true if the priority expander is enabled +*/}} +{{- define "cluster-autoscaler.priorityExpanderEnabled" -}} +{{- $expanders := splitList "," (default "" .Values.extraArgs.expander) -}} +{{- if has "priority" $expanders -}} +{{- true -}} +{{- end -}} +{{- end -}} + +{{/* +autoDiscovery.clusterName for clusterapi. +*/}} +{{- define "cluster-autoscaler.capiAutodiscovery.clusterName" -}} +{{- print "clusterName=" -}}{{ tpl (.Values.autoDiscovery.clusterName) . }} +{{- end -}} + +{{/* +autoDiscovery.namespace for clusterapi. +*/}} +{{- define "cluster-autoscaler.capiAutodiscovery.namespace" -}} +{{- print "namespace=" }}{{ .Values.autoDiscovery.namespace -}} +{{- end -}} + +{{/* +autoDiscovery.labels for clusterapi. +*/}} +{{- define "cluster-autoscaler.capiAutodiscovery.labels" -}} +{{- range $i, $el := .Values.autoDiscovery.labels -}} +{{- if $i -}}{{- print "," -}}{{- end -}} +{{- range $key, $val := $el -}} +{{- $key -}}{{- print "=" -}}{{- $val -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the autodiscoveryparameters for clusterapi. +*/}} +{{- define "cluster-autoscaler.capiAutodiscoveryConfig" -}} +{{- if .Values.autoDiscovery.clusterName -}} +{{ include "cluster-autoscaler.capiAutodiscovery.clusterName" . }} + {{- if .Values.autoDiscovery.namespace }} + {{- print "," -}} + {{ include "cluster-autoscaler.capiAutodiscovery.namespace" . }} + {{- end -}} + {{- if .Values.autoDiscovery.labels }} + {{- print "," -}} + {{ include "cluster-autoscaler.capiAutodiscovery.labels" . }} + {{- end -}} +{{- else if .Values.autoDiscovery.namespace -}} +{{ include "cluster-autoscaler.capiAutodiscovery.namespace" . }} + {{- if .Values.autoDiscovery.labels }} + {{- print "," -}} + {{ include "cluster-autoscaler.capiAutodiscovery.labels" . }} + {{- end -}} +{{- else if .Values.autoDiscovery.labels -}} + {{ include "cluster-autoscaler.capiAutodiscovery.labels" . }} +{{- end -}} +{{- end -}} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/clusterrole.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/clusterrole.yaml new file mode 100644 index 00000000..e6a9018e --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/clusterrole.yaml @@ -0,0 +1,210 @@ +{{- if and .Values.rbac.create .Values.rbac.clusterScoped -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: +{{- with .Values.rbac.annotations }} + annotations: + {{- range $k, $v := . }} + {{- printf "%s: %s" (tpl $k $) (tpl $v $) | nindent 4 }} + {{- end }} +{{- end }} + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.fullname" . }} +rules: +{{- if (eq .Values.cloudProvider "coreweave") }} + - apiGroups: + - "compute.coreweave.com" + resources: + - nodepools + verbs: + - get + - list + - patch + - update +{{- end }} + - apiGroups: + - "" + resources: + - events + - endpoints + verbs: + - create + - patch + - apiGroups: + - "" + resources: + - pods/eviction + verbs: + - create + - apiGroups: + - "" + resources: + - pods/status + verbs: + - update + - apiGroups: + - "" + resources: + - endpoints + resourceNames: + - cluster-autoscaler + verbs: + - get + - update + - apiGroups: + - "" + resources: + - nodes + verbs: + - watch + - list +{{- if (eq .Values.cloudProvider "kwok") }} + - create +{{- end }} +{{- if or (eq .Values.cloudProvider "kwok") (eq .Values.cloudProvider "huaweicloud") }} + - delete +{{- end }} + - get + - update + - apiGroups: + - resource.k8s.io + resources: + - resourceslices + - deviceclasses + - resourceclaims + verbs: + - watch + - list + - get + - apiGroups: + - "" + resources: + - namespaces + - pods + - services + - replicationcontrollers + - persistentvolumeclaims + - persistentvolumes + verbs: + - watch + - list + - get + - apiGroups: + - batch + resources: + - jobs + - cronjobs + verbs: + - watch + - list + - get + - apiGroups: + - batch + - extensions + resources: + - jobs + verbs: + - get + - list + - patch + - watch + - apiGroups: + - extensions + resources: + - replicasets + - daemonsets + verbs: + - watch + - list + - get + - apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - watch + - list + - apiGroups: + - apps + resources: + - daemonsets + - replicasets + - statefulsets + verbs: + - watch + - list + - get + - apiGroups: + - storage.k8s.io + resources: + - storageclasses + - csinodes + - csidrivers + - csistoragecapacities + - volumeattachments + verbs: + - watch + - list + - get + - apiGroups: + - "" + resources: + - configmaps + verbs: + - list + - watch + - get + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - apiGroups: + - coordination.k8s.io + resourceNames: + - cluster-autoscaler + resources: + - leases + verbs: + - get + - update +{{- if .Values.rbac.pspEnabled }} + - apiGroups: + - extensions + - policy + resources: + - podsecuritypolicies + resourceNames: + - {{ template "cluster-autoscaler.fullname" . }} + verbs: + - use +{{- end -}} +{{- if and ( and ( eq .Values.cloudProvider "clusterapi" ) ( .Values.rbac.clusterScoped ) ( or ( eq .Values.clusterAPIMode "incluster-incluster" ) ( eq .Values.clusterAPIMode "kubeconfig-incluster" ) ))}} + - apiGroups: + - cluster.x-k8s.io + resources: + - machinedeployments + - machinepools + - machines + - machinesets + verbs: + - get + - list + - update + - watch + - apiGroups: + - cluster.x-k8s.io + resources: + - machinedeployments/scale + - machinepools/scale + verbs: + - get + - patch + - update +{{- end }} +{{- if .Values.rbac.additionalRules }} +{{ toYaml .Values.rbac.additionalRules | indent 2 }} +{{- end }} +{{- end -}} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/clusterrolebinding.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/clusterrolebinding.yaml new file mode 100644 index 00000000..59e6ef67 --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/clusterrolebinding.yaml @@ -0,0 +1,22 @@ +{{- if and .Values.rbac.create .Values.rbac.clusterScoped -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: +{{- with .Values.rbac.annotations }} + annotations: + {{- range $k, $v := . }} + {{- printf "%s: %s" (tpl $k $) (tpl $v $) | nindent 4 }} + {{- end }} +{{- end }} + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.fullname" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "cluster-autoscaler.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ template "cluster-autoscaler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/configmap.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/configmap.yaml new file mode 100644 index 00000000..6cd0c406 --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/configmap.yaml @@ -0,0 +1,416 @@ +{{- if or (eq .Values.cloudProvider "kwok") }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.kwokConfigMapName | default "kwok-provider-config" }} + namespace: {{ .Release.Namespace }} +data: + config: |- + # if you see '\n' everywhere, remove all the trailing spaces + apiVersion: v1alpha1 + readNodesFrom: configmap # possible values: [cluster,configmap] + nodegroups: + # to specify how to group nodes into a nodegroup + # e.g., you want to treat nodes with same instance type as a nodegroup + # node1: m5.xlarge + # node2: c5.xlarge + # node3: m5.xlarge + # nodegroup1: [node1,node3] + # nodegroup2: [node2] + fromNodeLabelKey: "kwok-nodegroup" + # you can either specify fromNodeLabelKey OR fromNodeAnnotation + # (both are not allowed) + # fromNodeAnnotation: "eks.amazonaws.com/nodegroup" + nodes: + # gpuConfig: + # # to tell kwok provider what label should be considered as GPU label + # gpuLabelKey: "k8s.amazonaws.com/accelerator" + # availableGPUTypes: + # "nvidia-tesla-k80": {} + # "nvidia-tesla-p100": {} + configmap: + name: kwok-provider-templates + kwok: {} # default: fetch latest release of kwok from github and install it + # # you can also manually specify which kwok release you want to install + # # for example: + # kwok: + # release: v0.3.0 + # # you can also disable installing kwok in CA code (and install your own kwok release) + # kwok: + # install: false (true if not specified) +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: kwok-provider-templates + namespace: {{ .Release.Namespace }} +data: + templates: |- + # if you see '\n' everywhere, remove all the trailing spaces + apiVersion: v1 + items: + - apiVersion: v1 + kind: Node + metadata: + annotations: + kubeadm.alpha.kubernetes.io/cri-socket: unix:///run/containerd/containerd.sock + node.alpha.kubernetes.io/ttl: "0" + volumes.kubernetes.io/controller-managed-attach-detach: "true" + creationTimestamp: "2023-05-31T04:39:16Z" + labels: + beta.kubernetes.io/arch: amd64 + beta.kubernetes.io/os: linux + kubernetes.io/arch: amd64 + kubernetes.io/hostname: kind-control-plane + kwok-nodegroup: control-plane + kubernetes.io/os: linux + node-role.kubernetes.io/control-plane: "" + node.kubernetes.io/exclude-from-external-load-balancers: "" + name: kind-control-plane + resourceVersion: "506" + uid: 86716ec7-3071-4091-b055-77b4361d1dca + spec: + podCIDR: 10.244.0.0/24 + podCIDRs: + - 10.244.0.0/24 + providerID: kind://docker/kind/kind-control-plane + taints: + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane + status: + addresses: + - address: 172.18.0.2 + type: InternalIP + - address: kind-control-plane + type: Hostname + allocatable: + cpu: "12" + ephemeral-storage: 959786032Ki + hugepages-1Gi: "0" + hugepages-2Mi: "0" + memory: 32781516Ki + pods: "110" + capacity: + cpu: "12" + ephemeral-storage: 959786032Ki + hugepages-1Gi: "0" + hugepages-2Mi: "0" + memory: 32781516Ki + pods: "110" + conditions: + - lastHeartbeatTime: "2023-05-31T04:39:58Z" + lastTransitionTime: "2023-05-31T04:39:13Z" + message: kubelet has sufficient memory available + reason: KubeletHasSufficientMemory + status: "False" + type: MemoryPressure + - lastHeartbeatTime: "2023-05-31T04:39:58Z" + lastTransitionTime: "2023-05-31T04:39:13Z" + message: kubelet has no disk pressure + reason: KubeletHasNoDiskPressure + status: "False" + type: DiskPressure + - lastHeartbeatTime: "2023-05-31T04:39:58Z" + lastTransitionTime: "2023-05-31T04:39:13Z" + message: kubelet has sufficient PID available + reason: KubeletHasSufficientPID + status: "False" + type: PIDPressure + - lastHeartbeatTime: "2023-05-31T04:39:58Z" + lastTransitionTime: "2023-05-31T04:39:46Z" + message: kubelet is posting ready status + reason: KubeletReady + status: "True" + type: Ready + daemonEndpoints: + kubeletEndpoint: + Port: 10250 + images: + - names: + - registry.k8s.io/etcd:3.5.6-0 + sizeBytes: 102542580 + - names: + - docker.io/library/import-2023-03-30@sha256:ba097b515c8c40689733c0f19de377e9bf8995964b7d7150c2045f3dfd166657 + - registry.k8s.io/kube-apiserver:v1.26.3 + sizeBytes: 80392681 + - names: + - docker.io/library/import-2023-03-30@sha256:8dbb345de79d1c44f59a7895da702a5f71997ae72aea056609445c397b0c10dc + - registry.k8s.io/kube-controller-manager:v1.26.3 + sizeBytes: 68538487 + - names: + - docker.io/library/import-2023-03-30@sha256:44db4d50a5f9c8efbac0d37ea974d1c0419a5928f90748d3d491a041a00c20b5 + - registry.k8s.io/kube-proxy:v1.26.3 + sizeBytes: 67217404 + - names: + - docker.io/library/import-2023-03-30@sha256:3dd2337f70af979c7362b5e52bbdfcb3a5fd39c78d94d02145150cd2db86ba39 + - registry.k8s.io/kube-scheduler:v1.26.3 + sizeBytes: 57761399 + - names: + - docker.io/kindest/kindnetd:v20230330-48f316cd@sha256:c19d6362a6a928139820761475a38c24c0cf84d507b9ddf414a078cf627497af + - docker.io/kindest/kindnetd@sha256:c19d6362a6a928139820761475a38c24c0cf84d507b9ddf414a078cf627497af + sizeBytes: 27726335 + - names: + - docker.io/kindest/local-path-provisioner:v0.0.23-kind.0@sha256:f2d0a02831ff3a03cf51343226670d5060623b43a4cfc4808bd0875b2c4b9501 + sizeBytes: 18664669 + - names: + - registry.k8s.io/coredns/coredns:v1.9.3 + sizeBytes: 14837849 + - names: + - docker.io/kindest/local-path-helper:v20230330-48f316cd@sha256:135203f2441f916fb13dad1561d27f60a6f11f50ec288b01a7d2ee9947c36270 + sizeBytes: 3052037 + - names: + - registry.k8s.io/pause:3.7 + sizeBytes: 311278 + nodeInfo: + architecture: amd64 + bootID: 2d71b318-5d07-4de2-9e61-2da28cf5bbf0 + containerRuntimeVersion: containerd://1.6.19-46-g941215f49 + kernelVersion: 5.15.0-72-generic + kubeProxyVersion: v1.26.3 + kubeletVersion: v1.26.3 + machineID: 96f8c8b8c8ae4600a3654341f207586e + operatingSystem: linux + osImage: Ubuntu 22.04.2 LTS + systemUUID: 111aa932-7f99-4bef-aaf7-36aa7fb9b012 + - apiVersion: v1 + kind: Node + metadata: + annotations: + kubeadm.alpha.kubernetes.io/cri-socket: unix:///run/containerd/containerd.sock + node.alpha.kubernetes.io/ttl: "0" + volumes.kubernetes.io/controller-managed-attach-detach: "true" + creationTimestamp: "2023-05-31T04:39:57Z" + labels: + beta.kubernetes.io/arch: amd64 + beta.kubernetes.io/os: linux + kubernetes.io/arch: amd64 + kubernetes.io/hostname: kind-worker + kwok-nodegroup: kind-worker + kubernetes.io/os: linux + name: kind-worker + resourceVersion: "577" + uid: 2ac0eb71-e5cf-4708-bbbf-476e8f19842b + spec: + podCIDR: 10.244.2.0/24 + podCIDRs: + - 10.244.2.0/24 + providerID: kind://docker/kind/kind-worker + status: + addresses: + - address: 172.18.0.3 + type: InternalIP + - address: kind-worker + type: Hostname + allocatable: + cpu: "12" + ephemeral-storage: 959786032Ki + hugepages-1Gi: "0" + hugepages-2Mi: "0" + memory: 32781516Ki + pods: "110" + capacity: + cpu: "12" + ephemeral-storage: 959786032Ki + hugepages-1Gi: "0" + hugepages-2Mi: "0" + memory: 32781516Ki + pods: "110" + conditions: + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:39:57Z" + message: kubelet has sufficient memory available + reason: KubeletHasSufficientMemory + status: "False" + type: MemoryPressure + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:39:57Z" + message: kubelet has no disk pressure + reason: KubeletHasNoDiskPressure + status: "False" + type: DiskPressure + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:39:57Z" + message: kubelet has sufficient PID available + reason: KubeletHasSufficientPID + status: "False" + type: PIDPressure + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:40:05Z" + message: kubelet is posting ready status + reason: KubeletReady + status: "True" + type: Ready + daemonEndpoints: + kubeletEndpoint: + Port: 10250 + images: + - names: + - registry.k8s.io/etcd:3.5.6-0 + sizeBytes: 102542580 + - names: + - docker.io/library/import-2023-03-30@sha256:ba097b515c8c40689733c0f19de377e9bf8995964b7d7150c2045f3dfd166657 + - registry.k8s.io/kube-apiserver:v1.26.3 + sizeBytes: 80392681 + - names: + - docker.io/library/import-2023-03-30@sha256:8dbb345de79d1c44f59a7895da702a5f71997ae72aea056609445c397b0c10dc + - registry.k8s.io/kube-controller-manager:v1.26.3 + sizeBytes: 68538487 + - names: + - docker.io/library/import-2023-03-30@sha256:44db4d50a5f9c8efbac0d37ea974d1c0419a5928f90748d3d491a041a00c20b5 + - registry.k8s.io/kube-proxy:v1.26.3 + sizeBytes: 67217404 + - names: + - docker.io/library/import-2023-03-30@sha256:3dd2337f70af979c7362b5e52bbdfcb3a5fd39c78d94d02145150cd2db86ba39 + - registry.k8s.io/kube-scheduler:v1.26.3 + sizeBytes: 57761399 + - names: + - docker.io/kindest/kindnetd:v20230330-48f316cd@sha256:c19d6362a6a928139820761475a38c24c0cf84d507b9ddf414a078cf627497af + - docker.io/kindest/kindnetd@sha256:c19d6362a6a928139820761475a38c24c0cf84d507b9ddf414a078cf627497af + sizeBytes: 27726335 + - names: + - docker.io/kindest/local-path-provisioner:v0.0.23-kind.0@sha256:f2d0a02831ff3a03cf51343226670d5060623b43a4cfc4808bd0875b2c4b9501 + sizeBytes: 18664669 + - names: + - registry.k8s.io/coredns/coredns:v1.9.3 + sizeBytes: 14837849 + - names: + - docker.io/kindest/local-path-helper:v20230330-48f316cd@sha256:135203f2441f916fb13dad1561d27f60a6f11f50ec288b01a7d2ee9947c36270 + sizeBytes: 3052037 + - names: + - registry.k8s.io/pause:3.7 + sizeBytes: 311278 + nodeInfo: + architecture: amd64 + bootID: 2d71b318-5d07-4de2-9e61-2da28cf5bbf0 + containerRuntimeVersion: containerd://1.6.19-46-g941215f49 + kernelVersion: 5.15.0-72-generic + kubeProxyVersion: v1.26.3 + kubeletVersion: v1.26.3 + machineID: a98a13ff474d476294935341f1ba9816 + operatingSystem: linux + osImage: Ubuntu 22.04.2 LTS + systemUUID: 5f3c1af8-a385-4776-85e4-73d7f4252b44 + - apiVersion: v1 + kind: Node + metadata: + annotations: + kubeadm.alpha.kubernetes.io/cri-socket: unix:///run/containerd/containerd.sock + node.alpha.kubernetes.io/ttl: "0" + volumes.kubernetes.io/controller-managed-attach-detach: "true" + creationTimestamp: "2023-05-31T04:39:57Z" + labels: + beta.kubernetes.io/arch: amd64 + beta.kubernetes.io/os: linux + kubernetes.io/arch: amd64 + kubernetes.io/hostname: kind-worker2 + kwok-nodegroup: kind-worker2 + kubernetes.io/os: linux + name: kind-worker2 + resourceVersion: "578" + uid: edc7df38-feb2-4089-9955-780562bdd21e + spec: + podCIDR: 10.244.1.0/24 + podCIDRs: + - 10.244.1.0/24 + providerID: kind://docker/kind/kind-worker2 + status: + addresses: + - address: 172.18.0.4 + type: InternalIP + - address: kind-worker2 + type: Hostname + allocatable: + cpu: "12" + ephemeral-storage: 959786032Ki + hugepages-1Gi: "0" + hugepages-2Mi: "0" + memory: 32781516Ki + pods: "110" + capacity: + cpu: "12" + ephemeral-storage: 959786032Ki + hugepages-1Gi: "0" + hugepages-2Mi: "0" + memory: 32781516Ki + pods: "110" + conditions: + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:39:57Z" + message: kubelet has sufficient memory available + reason: KubeletHasSufficientMemory + status: "False" + type: MemoryPressure + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:39:57Z" + message: kubelet has no disk pressure + reason: KubeletHasNoDiskPressure + status: "False" + type: DiskPressure + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:39:57Z" + message: kubelet has sufficient PID available + reason: KubeletHasSufficientPID + status: "False" + type: PIDPressure + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:40:08Z" + message: kubelet is posting ready status + reason: KubeletReady + status: "True" + type: Ready + daemonEndpoints: + kubeletEndpoint: + Port: 10250 + images: + - names: + - registry.k8s.io/etcd:3.5.6-0 + sizeBytes: 102542580 + - names: + - docker.io/library/import-2023-03-30@sha256:ba097b515c8c40689733c0f19de377e9bf8995964b7d7150c2045f3dfd166657 + - registry.k8s.io/kube-apiserver:v1.26.3 + sizeBytes: 80392681 + - names: + - docker.io/library/import-2023-03-30@sha256:8dbb345de79d1c44f59a7895da702a5f71997ae72aea056609445c397b0c10dc + - registry.k8s.io/kube-controller-manager:v1.26.3 + sizeBytes: 68538487 + - names: + - docker.io/library/import-2023-03-30@sha256:44db4d50a5f9c8efbac0d37ea974d1c0419a5928f90748d3d491a041a00c20b5 + - registry.k8s.io/kube-proxy:v1.26.3 + sizeBytes: 67217404 + - names: + - docker.io/library/import-2023-03-30@sha256:3dd2337f70af979c7362b5e52bbdfcb3a5fd39c78d94d02145150cd2db86ba39 + - registry.k8s.io/kube-scheduler:v1.26.3 + sizeBytes: 57761399 + - names: + - docker.io/kindest/kindnetd:v20230330-48f316cd@sha256:c19d6362a6a928139820761475a38c24c0cf84d507b9ddf414a078cf627497af + - docker.io/kindest/kindnetd@sha256:c19d6362a6a928139820761475a38c24c0cf84d507b9ddf414a078cf627497af + sizeBytes: 27726335 + - names: + - docker.io/kindest/local-path-provisioner:v0.0.23-kind.0@sha256:f2d0a02831ff3a03cf51343226670d5060623b43a4cfc4808bd0875b2c4b9501 + sizeBytes: 18664669 + - names: + - registry.k8s.io/coredns/coredns:v1.9.3 + sizeBytes: 14837849 + - names: + - docker.io/kindest/local-path-helper:v20230330-48f316cd@sha256:135203f2441f916fb13dad1561d27f60a6f11f50ec288b01a7d2ee9947c36270 + sizeBytes: 3052037 + - names: + - registry.k8s.io/pause:3.7 + sizeBytes: 311278 + nodeInfo: + architecture: amd64 + bootID: 2d71b318-5d07-4de2-9e61-2da28cf5bbf0 + containerRuntimeVersion: containerd://1.6.19-46-g941215f49 + kernelVersion: 5.15.0-72-generic + kubeProxyVersion: v1.26.3 + kubeletVersion: v1.26.3 + machineID: fa9f4cd3b3a743bc867b04e44941dcb2 + operatingSystem: linux + osImage: Ubuntu 22.04.2 LTS + systemUUID: f36c0f00-8ba5-4c8c-88bc-2981c8d377b9 + kind: List + metadata: + resourceVersion: "" + + +{{- end }} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/deployment.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/deployment.yaml new file mode 100644 index 00000000..cb4982b3 --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/deployment.yaml @@ -0,0 +1,380 @@ +{{- if or ( or .Values.autoDiscovery.clusterName .Values.autoDiscovery.namespace .Values.autoDiscovery.labels ) .Values.autoscalingGroups }} +{{/* one of the above is required */}} +apiVersion: {{ template "deployment.apiVersion" . }} +kind: Deployment +metadata: + annotations: +{{ toYaml .Values.deployment.annotations | indent 4 }} + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.fullname" . }} + namespace: {{ .Release.Namespace }} +spec: + replicas: {{ .Values.replicaCount }} + revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} + selector: + matchLabels: +{{- if .Values.deployment.selector }} +{{ toYaml .Values.deployment.selector | indent 6 }} +{{- else }} +{{ include "cluster-autoscaler.instance-name" . | indent 6 }} + {{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 6 }} + {{- end }} +{{- end }} +{{- if .Values.updateStrategy }} + strategy: + {{ toYaml .Values.updateStrategy | nindent 4 | trim }} +{{- end }} + template: + metadata: + {{- if .Values.podAnnotations }} + annotations: +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + labels: +{{ include "cluster-autoscaler.instance-name" . | indent 8 }} + {{- if .Values.additionalLabels }} +{{ toYaml .Values.additionalLabels | indent 8 }} + {{- end }} + {{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 8 }} + {{- end }} + spec: + {{- if .Values.priorityClassName }} + priorityClassName: "{{ .Values.priorityClassName }}" + {{- end }} + {{- with .Values.dnsConfig }} + dnsConfig: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.dnsPolicy }} + dnsPolicy: "{{ .Values.dnsPolicy }}" + {{- end }} + {{- if .Values.hostNetwork }} + hostNetwork: {{ .Values.hostNetwork }} + {{- end }} + {{- with .Values.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ template "cluster-autoscaler.name" . }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + command: + - ./cluster-autoscaler + - --cloud-provider={{ .Values.cloudProvider }} + {{- if and (eq .Values.cloudProvider "clusterapi") (eq .Values.clusterAPIMode "kubeconfig-incluster") }} + - --namespace={{ .Values.clusterAPIConfigMapsNamespace | default "kube-system" }} + {{- else }} + - --namespace={{ .Release.Namespace }} + {{- end }} + {{- if .Values.autoscalingGroups }} + {{- range .Values.autoscalingGroups }} + {{- if eq $.Values.cloudProvider "hetzner" }} + - --nodes={{ .minSize }}:{{ .maxSize }}:{{ .instanceType }}:{{ .region }}:{{ .name }} + {{- else }} + - --nodes={{ .minSize }}:{{ .maxSize }}:{{ .name }} + {{- end }} + {{- end }} + {{- end }} + {{- if eq .Values.cloudProvider "rancher" }} + {{- if .Values.cloudConfigPath }} + - --cloud-config={{ .Values.cloudConfigPath }} + {{- end }} + {{- end }} + {{- if eq .Values.cloudProvider "aws" }} + {{- if .Values.autoDiscovery.clusterName }} + - --node-group-auto-discovery=asg:tag={{ tpl (join "," .Values.autoDiscovery.tags) . }} + {{- end }} + {{- if .Values.cloudConfigPath }} + - --cloud-config={{ .Values.cloudConfigPath }} + {{- end }} + {{- else if eq .Values.cloudProvider "gce" }} + {{- if .Values.autoscalingGroupsnamePrefix }} + {{- range .Values.autoscalingGroupsnamePrefix }} + - --node-group-auto-discovery=mig:namePrefix={{ tpl .name $ }},min={{ .minSize }},max={{ .maxSize }} + {{- end }} + {{- end }} + {{- if eq .Values.cloudProvider "oci" }} + {{- if .Values.cloudConfigPath }} + - --nodes={{ .minSize }}:{{ .maxSize }}:{{ .name }} + - --balance-similar-node-groups + {{- end }} + {{- end }} + {{- else if eq .Values.cloudProvider "magnum" }} + {{- if .Values.autoDiscovery.clusterName }} + - --cluster-name={{ tpl (.Values.autoDiscovery.clusterName) . }} + - --node-group-auto-discovery=magnum:role={{ tpl (join "," .Values.autoDiscovery.roles) . }} + {{- else }} + - --cluster-name={{ tpl (.Values.magnumClusterName) . }} + {{- end }} + {{- else if eq .Values.cloudProvider "clusterapi" }} + {{- if or .Values.autoDiscovery.clusterName .Values.autoDiscovery.labels .Values.autoDiscovery.namespace }} + - --node-group-auto-discovery=clusterapi:{{ template "cluster-autoscaler.capiAutodiscoveryConfig" . }} + {{- end }} + {{- if eq .Values.clusterAPIMode "incluster-kubeconfig"}} + - --cloud-config={{ .Values.clusterAPICloudConfigPath }} + {{- else if eq .Values.clusterAPIMode "kubeconfig-incluster"}} + - --kubeconfig={{ .Values.clusterAPIWorkloadKubeconfigPath }} + - --clusterapi-cloud-config-authoritative + {{- else if eq .Values.clusterAPIMode "kubeconfig-kubeconfig"}} + - --kubeconfig={{ .Values.clusterAPIWorkloadKubeconfigPath }} + - --cloud-config={{ .Values.clusterAPICloudConfigPath }} + {{- else if eq .Values.clusterAPIMode "single-kubeconfig"}} + - --kubeconfig={{ .Values.clusterAPIWorkloadKubeconfigPath }} + {{- end }} + {{- else if eq .Values.cloudProvider "azure" }} + {{- if .Values.autoDiscovery.clusterName }} + - --node-group-auto-discovery=label:cluster-autoscaler-enabled=true,cluster-autoscaler-name={{ tpl (.Values.autoDiscovery.clusterName) . }} + {{- end }} + {{- end }} + {{- if eq .Values.cloudProvider "magnum" }} + - --cloud-config={{ .Values.cloudConfigPath }} + {{- end }} + {{- range $key, $value := .Values.extraArgs }} + {{- if not (kindIs "invalid" $value) }} + - --{{ $key | mustRegexFind "^[^_]+" }}={{ $value }} + {{- else }} + - --{{ $key | mustRegexFind "^[^_]+" }} + {{- end }} + {{- end }} + {{- range .Values.customArgs }} + - {{ . }} + {{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + {{- if and (eq .Values.cloudProvider "aws") (ne (tpl .Values.awsRegion $) "") }} + - name: AWS_REGION + value: "{{ tpl .Values.awsRegion $ }}" + {{- if .Values.awsAccessKeyID }} + - name: AWS_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + key: AwsAccessKeyId + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + {{- end }} + {{- if .Values.awsSecretAccessKey }} + - name: AWS_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + key: AwsSecretAccessKey + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + {{- end }} + {{- else if eq .Values.cloudProvider "azure" }} + - name: ARM_SUBSCRIPTION_ID + valueFrom: + secretKeyRef: + key: SubscriptionID + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: ARM_RESOURCE_GROUP + valueFrom: + secretKeyRef: + key: ResourceGroup + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: ARM_VM_TYPE + valueFrom: + secretKeyRef: + key: VMType + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: AZURE_ENABLE_FORCE_DELETE + value: "{{ .Values.azureEnableForceDelete }}" + {{- if .Values.azureUseWorkloadIdentityExtension }} + - name: ARM_USE_WORKLOAD_IDENTITY_EXTENSION + value: "true" + {{- else if .Values.azureUseManagedIdentityExtension }} + - name: ARM_USE_MANAGED_IDENTITY_EXTENSION + value: "true" + - name: ARM_USER_ASSIGNED_IDENTITY_ID + valueFrom: + secretKeyRef: + key: UserAssignedIdentityID + name: {{ template "cluster-autoscaler.fullname" . }} + {{- else }} + - name: ARM_TENANT_ID + valueFrom: + secretKeyRef: + key: TenantID + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: ARM_CLIENT_ID + valueFrom: + secretKeyRef: + key: ClientID + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: ARM_CLIENT_SECRET + valueFrom: + secretKeyRef: + key: ClientSecret + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + {{- end }} + {{- else if eq .Values.cloudProvider "exoscale" }} + - name: EXOSCALE_API_KEY + valueFrom: + secretKeyRef: + key: api-key + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: EXOSCALE_API_SECRET + valueFrom: + secretKeyRef: + key: api-secret + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: EXOSCALE_ZONE + valueFrom: + secretKeyRef: + key: api-zone + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + {{- else if eq .Values.cloudProvider "kwok" }} + - name: KWOK_PROVIDER_CONFIGMAP + value: "{{.Values.kwokConfigMapName | default "kwok-provider-config"}}" + {{- else if eq .Values.cloudProvider "civo" }} + - name: CIVO_API_URL + valueFrom: + secretKeyRef: + key: api-url + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: CIVO_API_KEY + valueFrom: + secretKeyRef: + key: api-key + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: CIVO_CLUSTER_ID + valueFrom: + secretKeyRef: + key: cluster-id + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: CIVO_REGION + valueFrom: + secretKeyRef: + key: region + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + {{- end }} + {{- range $key, $value := .Values.extraEnv }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{- range $key, $value := .Values.extraEnvConfigMaps }} + - name: {{ $key }} + valueFrom: + configMapKeyRef: + name: {{ default (include "cluster-autoscaler.fullname" $) $value.name }} + key: {{ required "Must specify key!" $value.key }} + {{- end }} + {{- range $key, $value := .Values.extraEnvSecrets }} + - name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ default (include "cluster-autoscaler.fullname" $) $value.name }} + key: {{ required "Must specify key!" $value.key }} + {{- end }} + {{- if or .Values.envFromSecret .Values.envFromConfigMap }} + envFrom: + {{- if .Values.envFromSecret }} + - secretRef: + name: {{ .Values.envFromSecret }} + {{- end }} + {{- if .Values.envFromConfigMap }} + - configMapRef: + name: {{ .Values.envFromConfigMap }} + {{- end }} + {{- end }} + livenessProbe: + httpGet: + path: /health-check + port: 8085 + ports: + - containerPort: 8085 + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- if .Values.containerSecurityContext }} + securityContext: + {{ toYaml .Values.containerSecurityContext | nindent 12 | trim }} + {{- end }} + {{- if or (eq .Values.cloudProvider "magnum") .Values.extraVolumeSecrets .Values.extraVolumeMounts .Values.clusterAPIKubeconfigSecret }} + volumeMounts: + {{- if eq .Values.cloudProvider "magnum" }} + - name: cloudconfig + mountPath: {{ .Values.cloudConfigPath }} + readOnly: true + {{- end }} + {{- if and (eq .Values.cloudProvider "magnum") (.Values.magnumCABundlePath) }} + - name: ca-bundle + mountPath: {{ .Values.magnumCABundlePath }} + readOnly: true + {{- end }} + {{- range $key, $value := .Values.extraVolumeSecrets }} + - name: {{ $key }} + mountPath: {{ required "Must specify mountPath!" $value.mountPath }} + readOnly: true + {{- end }} + {{- if .Values.clusterAPIKubeconfigSecret }} + - name: cluster-api-kubeconfig + mountPath: {{ .Values.clusterAPIWorkloadKubeconfigPath | trimSuffix "/value" }} + {{- end }} + {{- if .Values.extraVolumeMounts }} + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + serviceAccountName: {{ template "cluster-autoscaler.serviceAccountName" . }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- if .Values.topologySpreadConstraints }} + topologySpreadConstraints: +{{ toYaml .Values.topologySpreadConstraints | indent 8 }} + {{- end }} + {{- if .Values.securityContext }} + securityContext: + {{ toYaml .Values.securityContext | nindent 8 | trim }} + {{- end }} + {{- if or (eq .Values.cloudProvider "magnum") .Values.extraVolumeSecrets .Values.extraVolumes .Values.clusterAPIKubeconfigSecret }} + volumes: + {{- if eq .Values.cloudProvider "magnum" }} + - name: cloudconfig + hostPath: + path: {{ .Values.cloudConfigPath }} + {{- end }} + {{- if and (eq .Values.cloudProvider "magnum") (.Values.magnumCABundlePath) }} + - name: ca-bundle + hostPath: + path: {{ .Values.magnumCABundlePath }} + {{- end }} + {{- range $key, $value := .Values.extraVolumeSecrets }} + - name: {{ $key }} + secret: + secretName: {{ default (include "cluster-autoscaler.fullname" $) $value.name }} + {{- if $value.items }} + items: + {{- toYaml $value.items | nindent 14 }} + {{- end }} + {{- end }} + {{- if .Values.extraVolumes }} + {{- toYaml .Values.extraVolumes | nindent 8 }} + {{- end }} + {{- if .Values.clusterAPIKubeconfigSecret }} + - name: cluster-api-kubeconfig + secret: + secretName: {{ .Values.clusterAPIKubeconfigSecret }} + {{- end }} + {{- end }} + {{- if .Values.image.pullSecrets }} + imagePullSecrets: + {{- range .Values.image.pullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} +{{- end }} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/extra-manifests.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/extra-manifests.yaml new file mode 100644 index 00000000..a9bb3b6b --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/extra-manifests.yaml @@ -0,0 +1,4 @@ +{{ range .Values.extraObjects }} +--- +{{ tpl (toYaml .) $ }} +{{ end }} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/pdb.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/pdb.yaml new file mode 100644 index 00000000..0f8a69ec --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/pdb.yaml @@ -0,0 +1,29 @@ +{{- if .Values.podDisruptionBudget -}} +{{- if and .Values.podDisruptionBudget.minAvailable .Values.podDisruptionBudget.maxUnavailable }} + {{- fail "Only one of podDisruptionBudget.minAvailable or podDisruptionBudget.maxUnavailable should be set." }} +{{- end }}apiVersion: {{ template "podDisruptionBudget.apiVersion" . }} +kind: PodDisruptionBudget +metadata: +{{- if .Values.podDisruptionBudget.annotations }} + annotations: +{{ toYaml .Values.podDisruptionBudget.annotations | indent 4 }} +{{- end }} + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.fullname" . }} + namespace: {{ .Release.Namespace }} +spec: + selector: + matchLabels: +{{- if .Values.podDisruptionBudget.selector }} +{{ toYaml .Values.podDisruptionBudget.selector | indent 6 }} +{{- else }} +{{ include "cluster-autoscaler.instance-name" . | indent 6 }} + {{- if and .Values.podDisruptionBudget.minAvailable (not .Values.podDisruptionBudget.maxUnavailable) }} + minAvailable: {{ .Values.podDisruptionBudget.minAvailable }} + {{- end }} + {{- if and .Values.podDisruptionBudget.maxUnavailable (not .Values.podDisruptionBudget.minAvailable) }} + maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} + {{- end }} +{{- end -}} +{{- end }} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/podsecuritypolicy.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/podsecuritypolicy.yaml new file mode 100644 index 00000000..e3ce5997 --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/podsecuritypolicy.yaml @@ -0,0 +1,42 @@ +{{- if .Values.rbac.pspEnabled }} +apiVersion: {{ template "podsecuritypolicy.apiVersion" . }} +kind: PodSecurityPolicy +metadata: + name: {{ template "cluster-autoscaler.fullname" . }} + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} +spec: + # Prevents running in privileged mode + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + requiredDropCapabilities: + - ALL + volumes: + - 'configMap' + - 'secret' + - 'hostPath' + - 'emptyDir' + - 'projected' + - 'downwardAPI' + hostNetwork: {{ .Values.hostNetwork }} + hostIPC: false + hostPID: false + runAsUser: + rule: RunAsAny + seLinux: + rule: RunAsAny + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/priority-expander-configmap.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/priority-expander-configmap.yaml new file mode 100644 index 00000000..8259f14f --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/priority-expander-configmap.yaml @@ -0,0 +1,25 @@ +{{- if hasKey .Values.extraArgs "expander" }} +{{- if and (.Values.expanderPriorities) (include "cluster-autoscaler.priorityExpanderEnabled" .) -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: cluster-autoscaler-priority-expander + namespace: {{ .Release.Namespace }} + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + {{- if .Values.priorityConfigMapAnnotations }} + annotations: +{{ toYaml .Values.priorityConfigMapAnnotations | indent 4 }} + {{- end }} +data: + priorities: |- +{{- if kindIs "string" .Values.expanderPriorities }} +{{ .Values.expanderPriorities | indent 4 }} +{{- else }} +{{- range $k,$v := .Values.expanderPriorities }} + {{ $k | int }}: + {{- toYaml $v | nindent 6 }} +{{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/prometheusrule.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/prometheusrule.yaml new file mode 100644 index 00000000..097c969e --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/prometheusrule.yaml @@ -0,0 +1,15 @@ +{{- if .Values.prometheusRule.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ include "cluster-autoscaler.fullname" . }} + {{- if .Values.prometheusRule.namespace }} + namespace: {{ .Values.prometheusRule.namespace }} + {{- end }} + labels: {{- toYaml .Values.prometheusRule.additionalLabels | nindent 4 }} +spec: + groups: + - name: {{ include "cluster-autoscaler.fullname" . }} + interval: {{ .Values.prometheusRule.interval }} + rules: {{- tpl (toYaml .Values.prometheusRule.rules) . | nindent 8 }} +{{- end }} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/role.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/role.yaml new file mode 100644 index 00000000..80cf30a1 --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/role.yaml @@ -0,0 +1,96 @@ +{{- if .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: +{{- with .Values.rbac.annotations }} + annotations: + {{- range $k, $v := . }} + {{- printf "%s: %s" (tpl $k $) (tpl $v $) | nindent 4 }} + {{- end }} +{{- end }} + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.fullname" . }} + namespace: {{ .Release.Namespace }} +rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - create +{{- if (include "cluster-autoscaler.priorityExpanderEnabled" .) }} + - list + - watch +{{- end }} + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - cluster-autoscaler-status +{{- if (include "cluster-autoscaler.priorityExpanderEnabled" .) }} + - cluster-autoscaler-priority-expander +{{- end }} + verbs: + - delete + - get + - update +{{- if (include "cluster-autoscaler.priorityExpanderEnabled" .) }} + - watch +{{- end }} +{{- if eq (default "" (index .Values.extraArgs "leader-elect-resource-lock")) "configmaps" }} + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - cluster-autoscaler + verbs: + - get + - update +{{- end }} +{{- if and ( and ( eq .Values.cloudProvider "clusterapi" ) ( not .Values.rbac.clusterScoped ) ( or ( eq .Values.clusterAPIMode "incluster-incluster" ) ( eq .Values.clusterAPIMode "kubeconfig-incluster" ) ))}} + - apiGroups: + - cluster.x-k8s.io + resources: + - machinedeployments + - machinepools + - machines + - machinesets + verbs: + - get + - list + - update + - watch + - apiGroups: + - cluster.x-k8s.io + resources: + - machinedeployments/scale + - machinepools/scale + verbs: + - get + - patch + - update +{{- end }} +{{- if ( not .Values.rbac.clusterScoped ) }} + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - apiGroups: + - coordination.k8s.io + resourceNames: + - cluster-autoscaler + resources: + - leases + verbs: + - get + - update +{{- end }} +{{- if .Values.rbac.additionalRules }} +{{ toYaml .Values.rbac.additionalRules | indent 2}} +{{- end }} +{{- end -}} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/rolebinding.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/rolebinding.yaml new file mode 100644 index 00000000..9436aabe --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/rolebinding.yaml @@ -0,0 +1,23 @@ +{{- if .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: +{{- with .Values.rbac.annotations }} + annotations: + {{- range $k, $v := . }} + {{- printf "%s: %s" (tpl $k $) (tpl $v $) | nindent 4 }} + {{- end }} +{{- end }} + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.fullname" . }} + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "cluster-autoscaler.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ template "cluster-autoscaler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/secret.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/secret.yaml new file mode 100644 index 00000000..760cc3c5 --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/secret.yaml @@ -0,0 +1,32 @@ +{{- if not .Values.secretKeyRefNameOverride }} +{{- $isAzure := eq .Values.cloudProvider "azure" }} +{{- $isAws := eq .Values.cloudProvider "aws" }} +{{- $awsCredentialsProvided := and .Values.awsAccessKeyID .Values.awsSecretAccessKey }} +{{- $isCivo := eq .Values.cloudProvider "civo" }} + +{{- if or $isAzure (and $isAws $awsCredentialsProvided) $isCivo }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "cluster-autoscaler.fullname" . }} + namespace: {{ .Release.Namespace }} +data: +{{- if $isAzure }} + ClientID: "{{ .Values.azureClientID | b64enc }}" + ClientSecret: "{{ .Values.azureClientSecret | b64enc }}" + ResourceGroup: "{{ .Values.azureResourceGroup | b64enc }}" + SubscriptionID: "{{ .Values.azureSubscriptionID | b64enc }}" + TenantID: "{{ .Values.azureTenantID | b64enc }}" + VMType: "{{ .Values.azureVMType | b64enc }}" + UserAssignedIdentityID: "{{ .Values.azureUserAssignedIdentityID | b64enc }}" +{{- else if $isAws }} + AwsAccessKeyId: "{{ .Values.awsAccessKeyID | b64enc }}" + AwsSecretAccessKey: "{{ .Values.awsSecretAccessKey | b64enc }}" +{{- else if $isCivo }} + api-url: "{{ .Values.civoApiUrl | b64enc }}" + api-key: "{{ .Values.civoApiKey | b64enc }}" + cluster-id: "{{ .Values.civoClusterID | b64enc }}" + region: "{{ .Values.civoRegion | b64enc }}" +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/service.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/service.yaml new file mode 100644 index 00000000..c8bd4079 --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/service.yaml @@ -0,0 +1,43 @@ +{{- if .Values.service.create }} +apiVersion: v1 +kind: Service +metadata: +{{- if .Values.service.annotations }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +{{- end }} + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} +{{- if .Values.service.labels }} +{{ toYaml .Values.service.labels | indent 4 }} +{{- end }} + name: {{ template "cluster-autoscaler.fullname" . }} + namespace: {{ .Release.Namespace }} +spec: +{{- if .Values.service.clusterIP }} + clusterIP: "{{ .Values.service.clusterIP }}" +{{- end }} +{{- if .Values.service.externalIPs }} + externalIPs: +{{ toYaml .Values.service.externalIPs | indent 4 }} +{{- end }} +{{- if .Values.service.loadBalancerIP }} + loadBalancerIP: "{{ .Values.service.loadBalancerIP }}" +{{- end }} +{{- if .Values.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{ toYaml .Values.service.loadBalancerSourceRanges | indent 4 }} +{{- end }} + ports: + - port: {{ .Values.service.servicePort }} + protocol: TCP + targetPort: 8085 + name: {{ .Values.service.portName }} + selector: +{{- if .Values.service.selector }} +{{ toYaml .Values.service.selector | indent 4 }} +{{- else }} +{{ include "cluster-autoscaler.instance-name" . | indent 4 }} +{{- end }} + type: "{{ .Values.service.type }}" +{{- end }} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/serviceaccount.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/serviceaccount.yaml new file mode 100644 index 00000000..465b5aad --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/serviceaccount.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.rbac.create .Values.rbac.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + +{{- with .Values.rbac.serviceAccount.annotations }} + annotations: + {{- range $k, $v := . }} + {{- printf "%s: %s" (tpl $k $) (tpl $v $) | nindent 4 }} + {{- end }} +{{- end }} +automountServiceAccountToken: {{ .Values.rbac.serviceAccount.automountServiceAccountToken }} +{{- end }} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/servicemonitor.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/servicemonitor.yaml new file mode 100644 index 00000000..9ce83a2e --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/servicemonitor.yaml @@ -0,0 +1,36 @@ +{{ if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "cluster-autoscaler.fullname" . }} + {{- if .Values.serviceMonitor.namespace }} + namespace: {{ .Values.serviceMonitor.namespace }} + {{- end }} + {{- if .Values.serviceMonitor.annotations }} + annotations: +{{ toYaml .Values.serviceMonitor.annotations | indent 4 }} + {{- end }} + labels: + {{- range $key, $value := .Values.serviceMonitor.selector }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + selector: + matchLabels: +{{ include "cluster-autoscaler.instance-name" . | indent 6 }} + endpoints: + - port: {{ .Values.service.portName }} + interval: {{ .Values.serviceMonitor.interval }} + path: {{ .Values.serviceMonitor.path }} + {{- if .Values.serviceMonitor.relabelings }} + relabelings: +{{ tpl (toYaml .Values.serviceMonitor.relabelings | indent 6) . }} + {{- end }} + {{- if .Values.serviceMonitor.metricRelabelings }} + metricRelabelings: +{{ tpl (toYaml .Values.serviceMonitor.metricRelabelings | indent 6) . }} + {{- end }} + namespaceSelector: + matchNames: + - {{.Release.Namespace}} +{{ end }} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/vpa.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/vpa.yaml new file mode 100644 index 00000000..560dab00 --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/templates/vpa.yaml @@ -0,0 +1,22 @@ +{{- if .Values.vpa.enabled -}} +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.fullname" . }} + namespace: {{ .Release.Namespace }} +spec: + targetRef: + apiVersion: {{ template "deployment.apiVersion" . }} + kind: Deployment + name: {{ template "cluster-autoscaler.fullname" . }} + updatePolicy: + updateMode: {{ .Values.vpa.updateMode | quote }} + recommenders: + - name: {{ .Values.vpa.recommender | quote }} + resourcePolicy: + containerPolicies: + - containerName: {{ template "cluster-autoscaler.name" . }} + {{- .Values.vpa.containerPolicy | toYaml | nindent 6 }} +{{- end -}} diff --git a/packages/system/cluster-autoscaler/charts/cluster-autoscaler/values.yaml b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/values.yaml new file mode 100644 index 00000000..9e41d35b --- /dev/null +++ b/packages/system/cluster-autoscaler/charts/cluster-autoscaler/values.yaml @@ -0,0 +1,507 @@ +## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity +# affinity -- Affinity for pod assignment +affinity: {} + +# additionalLabels -- Labels to add to each object of the chart. +additionalLabels: {} + +autoDiscovery: + # cloudProviders `aws`, `gce`, `azure`, `magnum`, `clusterapi` and `oci` are supported by auto-discovery at this time + # AWS: Set tags as described in https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#auto-discovery-setup + + # autoDiscovery.clusterName -- Enable autodiscovery for `cloudProvider=aws`, for groups matching `autoDiscovery.tags`. + # autoDiscovery.clusterName -- Enable autodiscovery for `cloudProvider=azure`, using tags defined in https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/azure/README.md#auto-discovery-setup. + # Enable autodiscovery for `cloudProvider=clusterapi`, for groups matching `autoDiscovery.labels`. + # Enable autodiscovery for `cloudProvider=gce`, but no MIG tagging required. + # Enable autodiscovery for `cloudProvider=magnum`, for groups matching `autoDiscovery.roles`. + clusterName: # cluster.local + + # autoDiscovery.namespace -- Enable autodiscovery via cluster namespace for for `cloudProvider=clusterapi` + namespace: # default + + # autoDiscovery.tags -- ASG tags to match, run through `tpl`. + tags: + - k8s.io/cluster-autoscaler/enabled + - k8s.io/cluster-autoscaler/{{ .Values.autoDiscovery.clusterName }} + # - kubernetes.io/cluster/{{ .Values.autoDiscovery.clusterName }} + + # autoDiscovery.roles -- Magnum node group roles to match. + roles: + - worker + + # autoDiscovery.labels -- Cluster-API labels to match https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/clusterapi/README.md#configuring-node-group-auto-discovery + labels: [] + # - color: green + # - shape: circle +# autoscalingGroups -- For AWS, Azure AKS, Exoscale or Magnum. At least one element is required if not using `autoDiscovery`. For example: +#
+# - name: asg1
+# maxSize: 2
+# minSize: 1 +#
+# For Hetzner Cloud, the `instanceType` and `region` keys are also required. +#
+# - name: mypool
+# maxSize: 2
+# minSize: 1
+# instanceType: CPX21
+# region: FSN1 +#
+autoscalingGroups: [] +# - name: asg1 +# maxSize: 2 +# minSize: 1 +# - name: asg2 +# maxSize: 2 +# minSize: 1 + +# autoscalingGroupsnamePrefix -- For GCE. At least one element is required if not using `autoDiscovery`. For example: +#
+# - name: ig01
+# maxSize: 10
+# minSize: 0 +#
+autoscalingGroupsnamePrefix: [] +# - name: ig01 +# maxSize: 10 +# minSize: 0 +# - name: ig02 +# maxSize: 10 +# minSize: 0 + +# awsAccessKeyID -- AWS access key ID ([if AWS user keys used](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#using-aws-credentials)) +awsAccessKeyID: "" + +# awsRegion -- AWS region (required if `cloudProvider=aws`) +awsRegion: "" + +# awsSecretAccessKey -- AWS access secret key ([if AWS user keys used](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#using-aws-credentials)) +awsSecretAccessKey: "" + +# azureClientID -- Service Principal ClientID with contributor permission to Cluster and Node ResourceGroup. +# Required if `cloudProvider=azure` +azureClientID: "" + +# azureClientSecret -- Service Principal ClientSecret with contributor permission to Cluster and Node ResourceGroup. +# Required if `cloudProvider=azure` +azureClientSecret: "" + +# azureResourceGroup -- Azure resource group that the cluster is located. +# Required if `cloudProvider=azure` +azureResourceGroup: "" + +# azureSubscriptionID -- Azure subscription where the resources are located. +# Required if `cloudProvider=azure` +azureSubscriptionID: "" + +# azureTenantID -- Azure tenant where the resources are located. +# Required if `cloudProvider=azure` +azureTenantID: "" + +# azureUseManagedIdentityExtension -- Whether to use Azure's managed identity extension for credentials. If using MSI, ensure subscription ID, resource group, and azure AKS cluster name are set. You can only use one authentication method at a time, either azureUseWorkloadIdentityExtension or azureUseManagedIdentityExtension should be set. +azureUseManagedIdentityExtension: false + +# azureUserAssignedIdentityID -- When vmss has multiple user assigned identity assigned, azureUserAssignedIdentityID specifies which identity to be used +azureUserAssignedIdentityID: "" + +# azureUseWorkloadIdentityExtension -- Whether to use Azure's workload identity extension for credentials. See the project here: https://github.com/Azure/azure-workload-identity for more details. You can only use one authentication method at a time, either azureUseWorkloadIdentityExtension or azureUseManagedIdentityExtension should be set. +azureUseWorkloadIdentityExtension: false + +# azureVMType -- Azure VM type. +azureVMType: "vmss" + +# azureEnableForceDelete -- Whether to force delete VMs or VMSS instances when scaling down. +azureEnableForceDelete: false + +# civoApiUrl -- URL for the Civo API. +# Required if `cloudProvider=civo` +civoApiUrl: "https://api.civo.com" + +# civoApiKey -- API key for the Civo API. +# Required if `cloudProvider=civo` +civoApiKey: "" + +# civoClusterID -- Cluster ID for the Civo cluster. +# Required if `cloudProvider=civo` +civoClusterID: "" + +# civoRegion -- Region for the Civo cluster. +# Required if `cloudProvider=civo` +civoRegion: "" + +# cloudConfigPath -- Configuration file for cloud provider. +cloudConfigPath: "" + +# cloudProvider -- The cloud provider where the autoscaler runs. +# Currently only `gce`, `aws`, `azure`, `magnum`, `clusterapi`, `civo` and `coreweave` are supported. +# `aws` supported for AWS. `gce` for GCE. `azure` for Azure AKS. +# `magnum` for OpenStack Magnum, `clusterapi` for Cluster API. +# `civo` for Civo Cloud. +# `coreweave` for CoreWeave. +cloudProvider: aws + +# clusterAPICloudConfigPath -- Path to kubeconfig for connecting to Cluster API Management Cluster, only used if `clusterAPIMode=kubeconfig-kubeconfig or incluster-kubeconfig` +clusterAPICloudConfigPath: /etc/kubernetes/mgmt-kubeconfig + +# clusterAPIConfigMapsNamespace -- Namespace on the workload cluster to store Leader election and status configmaps +clusterAPIConfigMapsNamespace: "" + +# clusterAPIKubeconfigSecret -- Secret containing kubeconfig for connecting to Cluster API managed workloadcluster +# Required if `cloudProvider=clusterapi` and `clusterAPIMode=kubeconfig-kubeconfig,kubeconfig-incluster or incluster-kubeconfig` +clusterAPIKubeconfigSecret: "" + +# clusterAPIMode -- Cluster API mode, see https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/clusterapi/README.md#connecting-cluster-autoscaler-to-cluster-api-management-and-workload-clusters +# Syntax: workloadClusterMode-ManagementClusterMode +# for `kubeconfig-kubeconfig`, `incluster-kubeconfig` and `single-kubeconfig` you always must mount the external kubeconfig using either `extraVolumeSecrets` or `extraMounts` and `extraVolumes` +# if you dont set `clusterAPIKubeconfigSecret`and thus use an in-cluster config or want to use a non capi generated kubeconfig you must do so for the workload kubeconfig as well +clusterAPIMode: incluster-incluster # incluster-incluster, incluster-kubeconfig, kubeconfig-incluster, kubeconfig-kubeconfig, single-kubeconfig + +# clusterAPIWorkloadKubeconfigPath -- Path to kubeconfig for connecting to Cluster API managed workloadcluster, only used if `clusterAPIMode=kubeconfig-kubeconfig or kubeconfig-incluster` +clusterAPIWorkloadKubeconfigPath: /etc/kubernetes/value + +# containerSecurityContext -- [Security context for container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) +containerSecurityContext: {} + # allowPrivilegeEscalation: false + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + +deployment: + # deployment.annotations -- Annotations to add to the Deployment object. + annotations: {} + # deployment.selector -- Labels for Deployment `spec.selector.matchLabels`. + selector: {} + +# dnsConfig -- [Pod's DNS Config](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config) +dnsConfig: {} + # nameservers: + # - 1.2.3.4 + # searches: + # - ns1.svc.cluster-domain.example + # - my.dns.search.suffix + # options: + # - name: ndots + # value: "2" + # - name: edns0 + +# dnsPolicy -- Defaults to `ClusterFirst`. Valid values are: +# `ClusterFirstWithHostNet`, `ClusterFirst`, `Default` or `None`. +# If autoscaler does not depend on cluster DNS, recommended to set this to `Default`. +dnsPolicy: ClusterFirst + +# envFromConfigMap -- ConfigMap name to use as envFrom. +envFromConfigMap: "" + +# envFromSecret -- Secret name to use as envFrom. +envFromSecret: "" + +## Priorities Expander +# expanderPriorities -- The expanderPriorities is used if `extraArgs.expander` contains `priority` and expanderPriorities is also set with the priorities. +# If `extraArgs.expander` contains `priority`, then expanderPriorities is used to define cluster-autoscaler-priority-expander priorities. +# See: https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/expander/priority/readme.md +expanderPriorities: {} + +# extraArgs -- Additional container arguments. +# Refer to https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#what-are-the-parameters-to-ca for the full list of cluster autoscaler +# parameters and their default values. +# Everything after the first _ will be ignored allowing the use of multi-string arguments. +extraArgs: + logtostderr: true + stderrthreshold: info + v: 4 + # write-status-configmap: true + # status-config-map-name: cluster-autoscaler-status + # leader-elect: true + # leader-elect-resource-lock: endpoints + # skip-nodes-with-local-storage: true + # expander: random + # scale-down-enabled: true + # balance-similar-node-groups: true + # min-replica-count: 0 + # scale-down-utilization-threshold: 0.5 + # scale-down-non-empty-candidates-count: 30 + # max-node-provision-time: 15m0s + # scan-interval: 10s + # scale-down-delay-after-add: 10m + # scale-down-delay-after-delete: 0s + # scale-down-delay-after-failure: 3m + # scale-down-unneeded-time: 10m + # node-deletion-delay-timeout: 2m + # node-deletion-batcher-interval: 0s + # skip-nodes-with-system-pods: true + # balancing-ignore-label_1: first-label-to-ignore + # balancing-ignore-label_2: second-label-to-ignore + +# customArgs -- Additional custom container arguments. +# Refer to https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#what-are-the-parameters-to-ca for the full list of cluster autoscaler +# parameters and their default values. +# List of arguments as strings. +customArgs: [] + +# extraEnv -- Additional container environment variables. +extraEnv: {} + +# extraEnvConfigMaps -- Additional container environment variables from ConfigMaps. +extraEnvConfigMaps: {} + +# extraEnvSecrets -- Additional container environment variables from Secrets. +extraEnvSecrets: {} + +# extraObjects -- Extra K8s manifests to deploy +extraObjects: [] +# - apiVersion: v1 +# kind: ConfigMap +# metadata: +# name: my-configmap +# data: +# key: "value" +# - apiVersion: scheduling.k8s.io/v1 +# kind: PriorityClass +# metadata: +# name: high-priority +# value: 1000000 +# globalDefault: false +# description: "This priority class should be used for XYZ service pods only." + +# extraVolumeMounts -- Additional volumes to mount. +extraVolumeMounts: [] + # - name: ssl-certs + # mountPath: /etc/ssl/certs/ca-certificates.crt + # readOnly: true + +# extraVolumes -- Additional volumes. +extraVolumes: [] + # - name: ssl-certs + # hostPath: + # path: /etc/ssl/certs/ca-bundle.crt + +# extraVolumeSecrets -- Additional volumes to mount from Secrets. +extraVolumeSecrets: {} + # autoscaler-vol: + # mountPath: /data/autoscaler/ + # custom-vol: + # name: custom-secret + # mountPath: /data/custom/ + # items: + # - key: subkey + # path: mypath + +# initContainers -- Any additional init containers. +initContainers: [] + +# fullnameOverride -- String to fully override `cluster-autoscaler.fullname` template. +fullnameOverride: "" + +# hostNetwork -- Whether to expose network interfaces of the host machine to pods. +hostNetwork: false + +image: + # image.repository -- Image repository + repository: registry.k8s.io/autoscaling/cluster-autoscaler + # image.tag -- Image tag + tag: v1.34.2 + # image.pullPolicy -- Image pull policy + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # image.pullSecrets -- Image pull secrets + pullSecrets: [] + # - myRegistrKeySecretName + +# kubeTargetVersionOverride -- Allow overriding the `.Capabilities.KubeVersion.GitVersion` check. Useful for `helm template` commands. +kubeTargetVersionOverride: "" + +# kwokConfigMapName -- configmap for configuring kwok provider +kwokConfigMapName: "kwok-provider-config" + +# magnumCABundlePath -- Path to the host's CA bundle, from `ca-file` in the cloud-config file. +magnumCABundlePath: "/etc/kubernetes/ca-bundle.crt" + +# magnumClusterName -- Cluster name or ID in Magnum. +# Required if `cloudProvider=magnum` and not setting `autoDiscovery.clusterName`. +magnumClusterName: "" + +# nameOverride -- String to partially override `cluster-autoscaler.fullname` template (will maintain the release name) +nameOverride: "" + +# nodeSelector -- Node labels for pod assignment. Ref: https://kubernetes.io/docs/user-guide/node-selection/. +nodeSelector: {} + +# podAnnotations -- Annotations to add to each pod. +podAnnotations: {} + +# podDisruptionBudget -- Pod disruption budget. +podDisruptionBudget: + # podDisruptionBudget.annotations -- Annotations to add to the PodDisruptionBudget. + annotations: {} + # podDisruptionBudget.selector -- Override labels for PodDisruptionBudget `spec.selector.matchLabels`. + selector: {} + maxUnavailable: 1 + # minAvailable: 2 + +# podLabels -- Labels to add to each pod. +podLabels: {} + +# priorityClassName -- priorityClassName +priorityClassName: "system-cluster-critical" + +# priorityConfigMapAnnotations -- Annotations to add to `cluster-autoscaler-priority-expander` ConfigMap. +priorityConfigMapAnnotations: {} + # key1: "value1" + # key2: "value2" + +## Custom PrometheusRule to be defined +## The value is evaluated as a template, so, for example, the value can depend on .Release or .Chart +## ref: https://github.com/coreos/prometheus-operator#customresourcedefinitions +prometheusRule: + # prometheusRule.enabled -- If true, creates a Prometheus Operator PrometheusRule. + enabled: false + # prometheusRule.additionalLabels -- Additional labels to be set in metadata. + additionalLabels: {} + # prometheusRule.namespace -- Namespace which Prometheus is running in. + namespace: monitoring + # prometheusRule.interval -- How often rules in the group are evaluated (falls back to `global.evaluation_interval` if not set). + interval: null + # prometheusRule.rules -- Rules spec template (see https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#rule). + rules: [] + +rbac: + # rbac.create -- If `true`, create and use RBAC resources. + create: true + # rbac.pspEnabled -- If `true`, creates and uses RBAC resources required in the cluster with [Pod Security Policies](https://kubernetes.io/docs/concepts/policy/pod-security-policy/) enabled. + # Must be used with `rbac.create` set to `true`. + pspEnabled: false + # rbac.clusterScoped -- if set to false will only provision RBAC to alter resources in the current namespace. Most useful for Cluster-API + clusterScoped: true + # rbac.annotations -- Additional annotations to add to RBAC resources (Role/RoleBinding/ClusterRole/ClusterRoleBinding). + annotations: {} + serviceAccount: + # rbac.serviceAccount.annotations -- Additional Service Account annotations. + annotations: {} + # rbac.serviceAccount.create -- If `true` and `rbac.create` is also true, a Service Account will be created. + create: true + # rbac.serviceAccount.name -- The name of the ServiceAccount to use. If not set and create is `true`, a name is generated using the fullname template. + name: "" + # rbac.serviceAccount.automountServiceAccountToken -- Automount API credentials for a Service Account. + automountServiceAccountToken: true + # rbac.additionalRules -- Additional rules for role/clusterrole + additionalRules: [] + # - apiGroups: + # - infrastructure.cluster.x-k8s.io + # resources: + # - kubemarkmachinetemplates + # verbs: + # - get + # - list + # - watch + + +# replicaCount -- Desired number of pods +replicaCount: 1 + +# resources -- Pod resource requests and limits. +resources: {} + # limits: + # cpu: 100m + # memory: 300Mi + # requests: + # cpu: 100m + # memory: 300Mi + +# revisionHistoryLimit -- The number of revisions to keep. +revisionHistoryLimit: 10 + +# securityContext -- [Security context for pod](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) +securityContext: {} + # runAsNonRoot: true + # runAsUser: 65534 + # runAsGroup: 65534 + # seccompProfile: + # type: RuntimeDefault + +service: + # service.create -- If `true`, a Service will be created. + create: true + # service.annotations -- Annotations to add to service + annotations: {} + # service.labels -- Labels to add to service + labels: {} + # service.externalIPs -- List of IP addresses at which the service is available. Ref: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips. + externalIPs: [] + + # service.selector -- Override labels for Service `spec.selector`. + selector: {} + + # service.clusterIP -- IP address to assign to service + clusterIP: "" + + # service.loadBalancerIP -- IP address to assign to load balancer (if supported). + loadBalancerIP: "" + # service.loadBalancerSourceRanges -- List of IP CIDRs allowed access to load balancer (if supported). + loadBalancerSourceRanges: [] + # service.servicePort -- Service port to expose. + servicePort: 8085 + # service.portName -- Name for service port. + portName: http + # service.type -- Type of service to create. + type: ClusterIP + +## Are you using Prometheus Operator? +serviceMonitor: + # serviceMonitor.enabled -- If true, creates a Prometheus Operator ServiceMonitor. + enabled: false + # serviceMonitor.interval -- Interval that Prometheus scrapes Cluster Autoscaler metrics. + interval: 10s + # serviceMonitor.namespace -- Namespace which Prometheus is running in. + namespace: monitoring + ## [Prometheus Selector Label](https://github.com/helm/charts/tree/master/stable/prometheus-operator#prometheus-operator-1) + ## [Kube Prometheus Selector Label](https://github.com/helm/charts/tree/master/stable/prometheus-operator#exporters) + # serviceMonitor.selector -- Default to kube-prometheus install (CoreOS recommended), but should be set according to Prometheus install. + selector: + release: prometheus-operator + # serviceMonitor.path -- The path to scrape for metrics; autoscaler exposes `/metrics` (this is standard) + path: /metrics + # serviceMonitor.annotations -- Annotations to add to service monitor + annotations: {} + ## [RelabelConfig](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#monitoring.coreos.com/v1.RelabelConfig) + # serviceMonitor.relabelings -- RelabelConfigs to apply to metrics before scraping. + relabelings: {} + ## [RelabelConfig](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#monitoring.coreos.com/v1.RelabelConfig) + # serviceMonitor.metricRelabelings -- MetricRelabelConfigs to apply to samples before ingestion. + metricRelabelings: {} + +# tolerations -- List of node taints to tolerate (requires Kubernetes >= 1.6). +tolerations: [] + +# topologySpreadConstraints -- You can use topology spread constraints to control how Pods are spread across your cluster among failure-domains such as regions, zones, nodes, and other user-defined topology domains. (requires Kubernetes >= 1.19). +topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # whenUnsatisfiable: DoNotSchedule + # labelSelector: + # matchLabels: + # app.kubernetes.io/instance: cluster-autoscaler + +# updateStrategy -- [Deployment update strategy](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy) +updateStrategy: {} + # rollingUpdate: + # maxSurge: 1 + # maxUnavailable: 0 + # type: RollingUpdate + +# vpa -- Configure a VerticalPodAutoscaler for the cluster-autoscaler Deployment. +vpa: + # vpa.enabled -- If true, creates a VerticalPodAutoscaler. + enabled: false + # vpa.updateMode -- [UpdateMode](https://github.com/kubernetes/autoscaler/blob/vertical-pod-autoscaler/v0.13.0/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1/types.go#L124) + updateMode: "Auto" + # vpa.containerPolicy -- [ContainerResourcePolicy](https://github.com/kubernetes/autoscaler/blob/vertical-pod-autoscaler/v0.13.0/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1/types.go#L159). The containerName is always set to the deployment's container name. This value is required if VPA is enabled. + containerPolicy: {} + # vpa.recommender -- Name of the VPA recommender that will provide recommendations for vertical scaling. + recommender: default + +# secretKeyRefNameOverride -- Overrides the name of the Secret to use when loading the secretKeyRef for AWS, Azure and Civo env variables +secretKeyRefNameOverride: "" diff --git a/packages/system/cluster-autoscaler/values-azure.yaml b/packages/system/cluster-autoscaler/values-azure.yaml new file mode 100644 index 00000000..7720481a --- /dev/null +++ b/packages/system/cluster-autoscaler/values-azure.yaml @@ -0,0 +1,12 @@ +cluster-autoscaler: + cloudProvider: azure + rbac: + additionalRules: + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - get + - update diff --git a/packages/system/cluster-autoscaler/values-hetzner.yaml b/packages/system/cluster-autoscaler/values-hetzner.yaml new file mode 100644 index 00000000..8e19fc53 --- /dev/null +++ b/packages/system/cluster-autoscaler/values-hetzner.yaml @@ -0,0 +1,12 @@ +cluster-autoscaler: + cloudProvider: hetzner + rbac: + additionalRules: + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - get + - update diff --git a/packages/system/cluster-autoscaler/values.yaml b/packages/system/cluster-autoscaler/values.yaml new file mode 100644 index 00000000..eaef53d9 --- /dev/null +++ b/packages/system/cluster-autoscaler/values.yaml @@ -0,0 +1,3 @@ +cluster-autoscaler: + extraArgs: + enforce-node-group-min-size: true diff --git a/packages/system/kamaji-etcd/.helmignore b/packages/system/clustersecret-operator/.helmignore similarity index 57% rename from packages/system/kamaji-etcd/.helmignore rename to packages/system/clustersecret-operator/.helmignore index 216b462f..d5c178e8 100644 --- a/packages/system/kamaji-etcd/.helmignore +++ b/packages/system/clustersecret-operator/.helmignore @@ -1,2 +1,3 @@ images hack +.gitkeep diff --git a/packages/system/clustersecret-operator/Chart.yaml b/packages/system/clustersecret-operator/Chart.yaml new file mode 100644 index 00000000..bc9ef8e7 --- /dev/null +++ b/packages/system/clustersecret-operator/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-clustersecret-operator +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/clustersecret-operator/Makefile b/packages/system/clustersecret-operator/Makefile new file mode 100644 index 00000000..34fa1464 --- /dev/null +++ b/packages/system/clustersecret-operator/Makefile @@ -0,0 +1,11 @@ +export NAME=clustersecret-operator +export NAMESPACE=cozy-clustersecret-operator + +export REPO_NAME=clustersecret-operator +export REPO_URL=https://sap.github.io/clustersecret-operator-helm +export CHART_NAME=clustersecret-operator +export CHART_VERSION=^0.3 + +include ../../../hack/package.mk + +update: clean clustersecret-operator-update diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/.helmignore b/packages/system/clustersecret-operator/charts/clustersecret-operator/.helmignore similarity index 88% rename from packages/system/dashboard/charts/kubeapps/charts/common/.helmignore rename to packages/system/clustersecret-operator/charts/clustersecret-operator/.helmignore index d0e10845..0e8a0eb3 100644 --- a/packages/system/dashboard/charts/kubeapps/charts/common/.helmignore +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/.helmignore @@ -14,13 +14,10 @@ *.swp *.bak *.tmp +*.orig *~ # Various IDEs .project .idea/ *.tmproj .vscode/ -# img folder -img/ -# Changelog -CHANGELOG.md diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/Chart.yaml b/packages/system/clustersecret-operator/charts/clustersecret-operator/Chart.yaml new file mode 100644 index 00000000..447e8530 --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: v0.3.68 +description: A Helm chart for https://github.com/sap/clustersecret-operator +name: clustersecret-operator +type: application +version: 0.3.68 diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/README.md b/packages/system/clustersecret-operator/charts/clustersecret-operator/README.md new file mode 100644 index 00000000..11b21f84 --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/README.md @@ -0,0 +1,74 @@ +# clustersecret-operator + +![Version: 0.3.68](https://img.shields.io/badge/Version-0.3.68-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.3.68](https://img.shields.io/badge/AppVersion-v0.3.68-informational?style=flat-square) + +A Helm chart for https://github.com/sap/clustersecret-operator + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| fullnameOverride | string | `""` | Override full name | +| nameOverride | string | `""` | Override name | +| global.image.tag | string | `""` | Image tag (defauls to .Chart.AppVersion) | +| global.image.pullPolicy | string | `"IfNotPresent"` | Image pull policy | +| global.imagePullSecrets | list | `[]` | Image pull secrets | +| global.affinity | object | `{}` | Affinity settings | +| global.nodeSelector | object | `{}` | Node selector | +| global.topologySpreadConstraints | list | `[]` | Topology spread constraints (if unspecified, default constraints for hostname and zone will be generated) | +| global.defaultHostNameSpreadPolicy | string | `"ScheduleAnyway"` | Default topology spread policy for hostname | +| global.defaultZoneSpreadPolicy | string | `"ScheduleAnyway"` | Default topology spread policy for zone | +| global.tolerations | list | `[]` | Tolerations | +| global.priorityClassName | string | `""` | Priority class | +| global.podSecurityContext | object | `{}` | Pod security context | +| global.podAnnotations | object | `{}` | Additional pod annotations | +| global.podLabels | object | `{}` | Additional pod labels | +| global.securityContext | object | `{}` | Container security context | +| global.logLevel | int | `0` | Log level | +| controller.replicaCount | int | `1` | Replica count | +| controller.image.repository | string | `"ghcr.io/sap/clustersecret-operator/controller"` | Image repository | +| controller.image.tag | string | `""` | Image tag (defauls to .Chart.AppVersion) | +| controller.image.pullPolicy | string | `""` | Image pull policy | +| controller.imagePullSecrets | list | `[]` | Image pull secrets | +| controller.affinity | object | `{}` | Affinity settings | +| controller.nodeSelector | object | `{}` | Node selector | +| controller.topologySpreadConstraints | list | `[]` | Topology spread constraints (if unspecified, default constraints for hostname and zone will be generated) | +| controller.defaultHostNameSpreadPolicy | string | `""` | Default topology spread policy for hostname | +| controller.defaultZoneSpreadPolicy | string | `""` | Default topology spread policy for zone | +| controller.tolerations | list | `[]` | Tolerations | +| controller.priorityClassName | string | `""` | Priority class | +| controller.podSecurityContext | object | `{}` | Pod security context | +| controller.podAnnotations | object | `{}` | Additional pod annotations | +| controller.podLabels | object | `{}` | Additional pod labels | +| controller.securityContext | object | `{}` | Container security context | +| controller.resources.limits.memory | string | `"200Mi"` | Memory limit | +| controller.resources.limits.cpu | float | `0.1` | CPU limit | +| controller.resources.requests.memory | string | `"20Mi"` | Memory request | +| controller.resources.requests.cpu | float | `0.01` | CPU request | +| controller.logLevel | int | `0` | Log level | +| webhook.replicaCount | int | `1` | Replica count | +| webhook.image.repository | string | `"ghcr.io/sap/clustersecret-operator/webhook"` | Image repository | +| webhook.image.tag | string | `""` | Image tag (defauls to .Chart.AppVersion) | +| webhook.image.pullPolicy | string | `""` | Image pull policy | +| webhook.imagePullSecrets | list | `[]` | Image pull secrets | +| webhook.affinity | object | `{}` | Affinity settings | +| webhook.nodeSelector | object | `{}` | Node selector | +| webhook.topologySpreadConstraints | list | `[]` | Topology spread constraints (if unspecified, default constraints for hostname and zone will be generated) | +| webhook.defaultHostNameSpreadPolicy | string | `""` | Default topology spread policy for hostname | +| webhook.defaultZoneSpreadPolicy | string | `""` | Default topology spread policy for zone | +| webhook.tolerations | list | `[]` | Tolerations | +| webhook.priorityClassName | string | `""` | Priority class | +| webhook.podSecurityContext | object | `{}` | Pod security context | +| webhook.podAnnotations | object | `{}` | Additional pod annotations | +| webhook.podLabels | object | `{}` | Additional pod labels | +| webhook.securityContext | object | `{}` | Container security context | +| webhook.resources.limits.memory | string | `"100Mi"` | Memory limit | +| webhook.resources.limits.cpu | float | `0.1` | CPU limit | +| webhook.resources.requests.memory | string | `"20Mi"` | Memory request | +| webhook.resources.requests.cpu | float | `0.01` | CPU request | +| webhook.service.type | string | `"ClusterIP"` | Service type | +| webhook.service.port | int | `443` | Service port | +| webhook.logLevel | int | `0` | Log level | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/crds/clustersecrets.yaml b/packages/system/clustersecret-operator/charts/clustersecret-operator/crds/clustersecrets.yaml new file mode 100644 index 00000000..e28a99b3 --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/crds/clustersecrets.yaml @@ -0,0 +1,106 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clustersecrets.core.cs.sap.com +spec: + scope: Cluster + names: + plural: clustersecrets + singular: clustersecret + kind: ClusterSecret + group: core.cs.sap.com + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + - name: State + type: string + jsonPath: .status.state + subresources: + status: {} + schema: + openAPIV3Schema: + type: object + required: ["spec"] + properties: + spec: + type: object + required: ["template"] + properties: + namespaceSelector: + type: object + anyOf: + - required: ["matchLabels"] + - required: ["matchExpressions"] + properties: + matchLabels: + type: object + additionalProperties: + type: string + nullable: true + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + enum: ["In","NotIn","Exists","DoesNotExist"] + values: + type: array + items: + type: string + template: + type: object + required: ["type"] + properties: + type: + type: string + minLength: 1 + data: + type: object + additionalProperties: + type: string + nullable: true + stringData: + type: object + additionalProperties: + type: string + nullable: true + status: + type: object + properties: + observedGeneration: + type: integer + state: + type: string + enum: ["Ready","Processing","Deleting","Error"] + conditions: + type: array + items: + type: object + required: ["type","status"] + properties: + type: + type: string + enum: ["Ready"] + status: + type: string + enum: ["True","False","Unknown"] + lastUpdateTime: + type: string + format: datetime + lastTransitionTime: + type: string + format: datetime + reason: + type: string + minLength: 1 + message: + type: string diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/_helpers-controller.tpl b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/_helpers-controller.tpl new file mode 100644 index 00000000..4f012e93 --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/_helpers-controller.tpl @@ -0,0 +1,13 @@ +{{- define "clustersecret-operator.controller.fullname" -}} +{{ include "clustersecret-operator.fullname" . }}-controller +{{- end }} + +{{- define "clustersecret-operator.controller.labels" -}} +{{ include "clustersecret-operator.labels" . }} +app.kubernetes.io/component: controller +{{- end }} + +{{- define "clustersecret-operator.controller.selectorLabels" -}} +{{ include "clustersecret-operator.selectorLabels" . }} +app.kubernetes.io/component: controller +{{- end }} \ No newline at end of file diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/_helpers-webhook.tpl b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/_helpers-webhook.tpl new file mode 100644 index 00000000..77a8a372 --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/_helpers-webhook.tpl @@ -0,0 +1,13 @@ +{{- define "clustersecret-operator.webhook.fullname" -}} +{{ include "clustersecret-operator.fullname" . }}-webhook +{{- end }} + +{{- define "clustersecret-operator.webhook.labels" -}} +{{ include "clustersecret-operator.labels" . }} +app.kubernetes.io/component: webhook +{{- end }} + +{{- define "clustersecret-operator.webhook.selectorLabels" -}} +{{ include "clustersecret-operator.selectorLabels" . }} +app.kubernetes.io/component: webhook +{{- end }} \ No newline at end of file diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/_helpers.tpl b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/_helpers.tpl new file mode 100644 index 00000000..48b65844 --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/_helpers.tpl @@ -0,0 +1,51 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "clustersecret-operator.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "clustersecret-operator.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "clustersecret-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "clustersecret-operator.labels" -}} +helm.sh/chart: {{ include "clustersecret-operator.chart" . }} +{{ include "clustersecret-operator.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "clustersecret-operator.selectorLabels" -}} +app.kubernetes.io/name: {{ include "clustersecret-operator.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/controller-deployment.yaml b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/controller-deployment.yaml new file mode 100644 index 00000000..e42a33a3 --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/controller-deployment.yaml @@ -0,0 +1,96 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "clustersecret-operator.controller.fullname" . }} + labels: + {{- include "clustersecret-operator.controller.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.controller.replicaCount }} + selector: + matchLabels: + {{- include "clustersecret-operator.controller.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.controller.podAnnotations | default .Values.global.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "clustersecret-operator.controller.selectorLabels" . | nindent 8 }} + {{- with .Values.controller.podLabels | default .Values.global.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.controller.imagePullSecrets | default .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.controller.podSecurityContext | default .Values.global.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.controller.nodeSelector | default .Values.global.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.controller.affinity | default .Values.global.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.controller.topologySpreadConstraints | default .Values.global.topologySpreadConstraints }} + topologySpreadConstraints: + {{- range . }} + - {{ toYaml . | nindent 8 | trim }} + {{- if not .labelSelector }} + labelSelector: + matchLabels: + {{- include "clustersecret-operator.controller.selectorLabels" $ | nindent 12 }} + {{- end }} + {{- end }} + {{- else }} + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + nodeTaintsPolicy: Honor + whenUnsatisfiable: {{ .Values.controller.defaultHostNameSpreadPolicy | default .Values.global.defaultHostNameSpreadPolicy }} + labelSelector: + matchLabels: + {{- include "clustersecret-operator.controller.selectorLabels" . | nindent 12 }} + - maxSkew: 1 + topologyKey: topology.kubernetes.io/zone + nodeTaintsPolicy: Honor + whenUnsatisfiable: {{ .Values.controller.defaultZoneSpreadPolicy | default .Values.global.defaultZoneSpreadPolicy }} + labelSelector: + matchLabels: + {{- include "clustersecret-operator.controller.selectorLabels" . | nindent 12 }} + {{- end }} + {{- with .Values.controller.tolerations | default .Values.global.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.controller.priorityClassName | default .Values.global.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + serviceAccountName: {{ include "clustersecret-operator.controller.fullname" . }} + automountServiceAccountToken: true + containers: + - name: controller + image: {{ .Values.controller.image.repository }}:{{ .Values.controller.image.tag | default .Values.global.image.tag | default .Chart.AppVersion }} + imagePullPolicy: {{ .Values.controller.image.pullPolicy | default .Values.global.image.pullPolicy }} + {{- with .Values.controller.securityContext | default .Values.global.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.controller.resources | nindent 12 }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + args: + - "--lease_namespace={{ .Release.Namespace }}" + - "--lease_name={{ include "clustersecret-operator.controller.fullname" . }}" + - "--lease_id=$(POD_NAME)" + - "--v={{ .Values.controller.logLevel | default .Values.global.logLevel | default 0 }}" diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/controller-pdb.yaml b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/controller-pdb.yaml new file mode 100644 index 00000000..6f1985d5 --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/controller-pdb.yaml @@ -0,0 +1,13 @@ +{{- if ge (int .Values.controller.replicaCount) 2 }} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "clustersecret-operator.controller.fullname" . }} + labels: + {{- include "clustersecret-operator.controller.labels" . | nindent 4 }} +spec: + minAvailable: 1 + selector: + matchLabels: + {{- include "clustersecret-operator.controller.selectorLabels" . | nindent 6 }} +{{- end }} \ No newline at end of file diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/controller-rbac.yaml b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/controller-rbac.yaml new file mode 100644 index 00000000..040a5559 --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/controller-rbac.yaml @@ -0,0 +1,74 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "clustersecret-operator.controller.fullname" . }} + labels: + {{- include "clustersecret-operator.controller.labels" . | nindent 4 }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "clustersecret-operator.controller.fullname" . }} + labels: + {{- include "clustersecret-operator.controller.labels" . | nindent 4 }} +rules: +- apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["create"] +- apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + resourceNames: ["{{ include "clustersecret-operator.controller.fullname" . }}"] + verbs: ["get","list","watch","update","patch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "clustersecret-operator.controller.fullname" . }} + labels: + {{- include "clustersecret-operator.controller.labels" . | nindent 4 }} +subjects: +- kind: ServiceAccount + namespace: {{ .Release.Namespace }} + name: {{ include "clustersecret-operator.controller.fullname" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "clustersecret-operator.controller.fullname" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "clustersecret-operator.controller.fullname" . }} + labels: + {{- include "clustersecret-operator.controller.labels" . | nindent 4 }} +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get","list","watch","create","update","patch","delete"] +- apiGroups: [""] + resources: ["namespaces"] + verbs: ["get","list","watch"] +- apiGroups: ["core.cs.sap.com"] + resources: ["clustersecrets","clustersecrets/status"] + verbs: ["get","list","watch","update"] +- apiGroups: ["","events.k8s.io"] + resources: ["events"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "clustersecret-operator.controller.fullname" . }} + labels: + {{- include "clustersecret-operator.controller.labels" . | nindent 4 }} +subjects: +- kind: ServiceAccount + namespace: {{ .Release.Namespace }} + name: {{ include "clustersecret-operator.controller.fullname" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "clustersecret-operator.controller.fullname" . }} diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/tests/rbac.yaml b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/tests/rbac.yaml new file mode 100644 index 00000000..83205ec0 --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/tests/rbac.yaml @@ -0,0 +1,58 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "clustersecret-operator.fullname" . }}-test + labels: + {{- include "clustersecret-operator.labels" . | nindent 4 }} + annotations: + helm.sh/hook: test + helm.sh/hook-weight: "-1" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "clustersecret-operator.fullname" . }}-test + labels: + {{- include "clustersecret-operator.labels" . | nindent 4 }} + annotations: + helm.sh/hook: test + helm.sh/hook-weight: "-1" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded +rules: +- apiGroups: + - core.cs.sap.com + resources: + - clustersecrets + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "clustersecret-operator.fullname" . }}-test + labels: + {{- include "clustersecret-operator.labels" . | nindent 4 }} + annotations: + helm.sh/hook: test + helm.sh/hook-weight: "-1" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded +subjects: +- kind: ServiceAccount + namespace: {{ .Release.Namespace }} + name: {{ include "clustersecret-operator.fullname" . }}-test +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "clustersecret-operator.fullname" . }}-test diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/tests/test-1.yaml b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/tests/test-1.yaml new file mode 100644 index 00000000..2c163a78 --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/tests/test-1.yaml @@ -0,0 +1,44 @@ +{{- $clusterSecretName := printf "%s-test-1-%s" (include "clustersecret-operator.fullname" .) (randAlphaNum 10 | lower) }} +--- +apiVersion: core.cs.sap.com/v1alpha1 +kind: ClusterSecret +metadata: + name: {{ $clusterSecretName }} + labels: + {{- include "clustersecret-operator.labels" . | nindent 4 }} + annotations: + helm.sh/hook: test + helm.sh/hook-weight: "0" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded +spec: + namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: default + template: + type: Opaque + data: + mykey: bXl2YWx1ZQ== +--- +apiVersion: v1 +kind: Pod +metadata: + name: {{ include "clustersecret-operator.fullname" . }}-test-1 + labels: + {{- include "clustersecret-operator.labels" . | nindent 4 }} + annotations: + helm.sh/hook: test + helm.sh/hook-weight: "1" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded +spec: + containers: + - name: kubectl + image: ghcr.io/sap/kubectl-container:{{ .Capabilities.KubeVersion.Version }} + command: + - bash + - -ec + - | + kubectl wait clustersecrets.core.cs.sap.com/{{ $clusterSecretName }} --for condition=Ready --timeout 30s + kubectl -n default get secret {{ $clusterSecretName }} + serviceAccountName: {{ include "clustersecret-operator.fullname" . }}-test + terminationGracePeriodSeconds: 3 + restartPolicy: Never diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-admission.yaml b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-admission.yaml new file mode 100644 index 00000000..5e49e23c --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-admission.yaml @@ -0,0 +1,107 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "clustersecret-operator.webhook.fullname" . }} + labels: + {{- include "clustersecret-operator.webhook.labels" . | nindent 4 }} +spec: + type: {{ .Values.webhook.service.type }} + ports: + - port: {{ .Values.webhook.service.port }} + targetPort: 1443 + protocol: TCP + name: https + selector: + {{- include "clustersecret-operator.webhook.selectorLabels" . | nindent 4 }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "clustersecret-operator.webhook.fullname" . }}-tls + labels: + {{- include "clustersecret-operator.webhook.labels" . | nindent 4 }} +type: Opaque +data: + {{- $data := (lookup "v1" "Secret" .Release.Namespace (printf "%s-tls" (include "clustersecret-operator.webhook.fullname" .))).data }} + {{- $caCert := "" }} + {{- if $data }} + {{ $data | toYaml | nindent 2 }} + {{- $caCert = index $data "ca.crt" }} + {{- else }} + {{- $cn := printf "%s.%s.svc" (include "clustersecret-operator.webhook.fullname" .) .Release.Namespace }} + {{- $ca := genCA (printf "%s-ca" (include "clustersecret-operator.webhook.fullname" .)) 36500 }} + {{- $cert := genSignedCert $cn (list "127.0.0.1") (list $cn "localhost") 36500 $ca }} + ca.crt: {{ $ca.Cert | b64enc }} + tls.crt: {{ $cert.Cert | b64enc }} + tls.key: {{ $cert.Key | b64enc }} + {{- $caCert = $ca.Cert | b64enc }} + {{- end }} +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: clustersecret-operator + labels: + {{- include "clustersecret-operator.webhook.labels" . | nindent 4 }} +webhooks: +- name: clustersecret-operator.cs.sap.com + admissionReviewVersions: + - v1 + clientConfig: + caBundle: {{ $caCert }} + service: + name: {{ include "clustersecret-operator.webhook.fullname" . }} + namespace: {{ .Release.Namespace }} + path: /validation + port: {{ .Values.webhook.service.port }} + rules: + - apiGroups: + - core.cs.sap.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + - DELETE + resources: + - clustersecrets + scope: Cluster + matchPolicy: Exact + sideEffects: None + timeoutSeconds: 10 + failurePolicy: Fail +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: clustersecret-operator + labels: + {{- include "clustersecret-operator.webhook.labels" . | nindent 4 }} +webhooks: +- name: clustersecret-operator.cs.sap.com + admissionReviewVersions: + - v1 + clientConfig: + caBundle: {{ $caCert }} + service: + name: {{ include "clustersecret-operator.webhook.fullname" . }} + namespace: {{ .Release.Namespace }} + path: /mutation + port: {{ .Values.webhook.service.port }} + rules: + - apiGroups: + - core.cs.sap.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + - DELETE + resources: + - clustersecrets + scope: Cluster + matchPolicy: Exact + sideEffects: None + timeoutSeconds: 10 + failurePolicy: Fail \ No newline at end of file diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-deployment.yaml b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-deployment.yaml new file mode 100644 index 00000000..df766a52 --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-deployment.yaml @@ -0,0 +1,109 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "clustersecret-operator.webhook.fullname" . }} + labels: + {{- include "clustersecret-operator.webhook.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.webhook.replicaCount }} + selector: + matchLabels: + {{- include "clustersecret-operator.webhook.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.webhook.podAnnotations | default .Values.global.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "clustersecret-operator.webhook.selectorLabels" . | nindent 8 }} + {{- with .Values.webhook.podLabels | default .Values.global.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.webhook.imagePullSecrets | default .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.webhook.podSecurityContext | default .Values.global.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.webhook.nodeSelector | default .Values.global.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.webhook.affinity | default .Values.global.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.webhook.topologySpreadConstraints | default .Values.global.topologySpreadConstraints }} + topologySpreadConstraints: + {{- range . }} + - {{ toYaml . | nindent 8 | trim }} + {{- if not .labelSelector }} + labelSelector: + matchLabels: + {{- include "clustersecret-operator.webhook.selectorLabels" $ | nindent 12 }} + {{- end }} + {{- end }} + {{- else }} + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + nodeTaintsPolicy: Honor + whenUnsatisfiable: {{ .Values.webhook.defaultHostNameSpreadPolicy | default .Values.global.defaultHostNameSpreadPolicy }} + labelSelector: + matchLabels: + {{- include "clustersecret-operator.webhook.selectorLabels" . | nindent 12 }} + - maxSkew: 1 + topologyKey: topology.kubernetes.io/zone + nodeTaintsPolicy: Honor + whenUnsatisfiable: {{ .Values.webhook.defaultZoneSpreadPolicy | default .Values.global.defaultZoneSpreadPolicy }} + labelSelector: + matchLabels: + {{- include "clustersecret-operator.webhook.selectorLabels" . | nindent 12 }} + {{- end }} + {{- with .Values.webhook.tolerations | default .Values.global.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.webhook.priorityClassName | default .Values.global.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + serviceAccountName: {{ include "clustersecret-operator.webhook.fullname" . }} + automountServiceAccountToken: true + containers: + - name: webhook + image: {{ .Values.webhook.image.repository }}:{{ .Values.webhook.image.tag | default .Values.global.image.tag | default .Chart.AppVersion }} + imagePullPolicy: {{ .Values.webhook.image.pullPolicy | default .Values.global.image.pullPolicy }} + {{- with .Values.webhook.securityContext | default .Values.global.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.webhook.resources | nindent 12 }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + args: + - "--bind_address=:1443" + - "--tls_enabled=true" + - "--tls_key_file=/app/etc/ssl/tls.key" + - "--tls_cert_file=/app/etc/ssl/tls.crt" + - "--v={{ .Values.webhook.logLevel | default .Values.global.logLevel | default 0 }}" + volumeMounts: + - name: ssl + mountPath: /app/etc/ssl + volumes: + - name: ssl + secret: + secretName: {{ include "clustersecret-operator.webhook.fullname" . }}-tls + items: + - key: tls.key + path: tls.key + - key: tls.crt + path: tls.crt diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-pdb.yaml b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-pdb.yaml new file mode 100644 index 00000000..bdfc1bc1 --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-pdb.yaml @@ -0,0 +1,13 @@ +{{- if ge (int .Values.webhook.replicaCount) 2 }} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "clustersecret-operator.webhook.fullname" . }} + labels: + {{- include "clustersecret-operator.webhook.labels" . | nindent 4 }} +spec: + minAvailable: 1 + selector: + matchLabels: + {{- include "clustersecret-operator.webhook.selectorLabels" . | nindent 6 }} +{{- end }} \ No newline at end of file diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-rbac.yaml b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-rbac.yaml new file mode 100644 index 00000000..c149e28a --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/templates/webhook-rbac.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "clustersecret-operator.webhook.fullname" . }} + labels: + {{- include "clustersecret-operator.webhook.labels" . | nindent 4 }} diff --git a/packages/system/clustersecret-operator/charts/clustersecret-operator/values.yaml b/packages/system/clustersecret-operator/charts/clustersecret-operator/values.yaml new file mode 100644 index 00000000..3eb14836 --- /dev/null +++ b/packages/system/clustersecret-operator/charts/clustersecret-operator/values.yaml @@ -0,0 +1,138 @@ +# -- Override full name +fullnameOverride: "" +# -- Override name +nameOverride: "" + +global: + image: + # -- Image tag (defauls to .Chart.AppVersion) + tag: "" + # -- Image pull policy + pullPolicy: IfNotPresent + # -- Image pull secrets + imagePullSecrets: [] + # -- Affinity settings + affinity: {} + # -- Node selector + nodeSelector: {} + # -- Topology spread constraints (if unspecified, default constraints for hostname and zone will be generated) + topologySpreadConstraints: [] + # -- Default topology spread policy for hostname + defaultHostNameSpreadPolicy: ScheduleAnyway + # -- Default topology spread policy for zone + defaultZoneSpreadPolicy: ScheduleAnyway + # -- Tolerations + tolerations: [] + # -- Priority class + priorityClassName: "" + # -- Pod security context + podSecurityContext: {} + # -- Additional pod annotations + podAnnotations: {} + # -- Additional pod labels + podLabels: {} + # -- Container security context + securityContext: {} + # -- Log level + logLevel: 0 + +controller: + # -- Replica count + replicaCount: 1 + image: + # -- Image repository + repository: ghcr.io/sap/clustersecret-operator/controller + # -- Image tag (defauls to .Chart.AppVersion) + tag: "" + # -- Image pull policy + pullPolicy: "" + # -- Image pull secrets + imagePullSecrets: [] + # -- Affinity settings + affinity: {} + # -- Node selector + nodeSelector: {} + # -- Topology spread constraints (if unspecified, default constraints for hostname and zone will be generated) + topologySpreadConstraints: [] + # -- Default topology spread policy for hostname + defaultHostNameSpreadPolicy: "" + # -- Default topology spread policy for zone + defaultZoneSpreadPolicy: "" + # -- Tolerations + tolerations: [] + # -- Priority class + priorityClassName: "" + # -- Pod security context + podSecurityContext: {} + # -- Additional pod annotations + podAnnotations: {} + # -- Additional pod labels + podLabels: {} + # -- Container security context + securityContext: {} + resources: + limits: + # -- Memory limit + memory: 200Mi + # -- CPU limit + cpu: 0.1 + requests: + # -- Memory request + memory: 20Mi + # -- CPU request + cpu: 0.01 + # -- Log level + logLevel: 0 + +webhook: + # -- Replica count + replicaCount: 1 + image: + # -- Image repository + repository: ghcr.io/sap/clustersecret-operator/webhook + # -- Image tag (defauls to .Chart.AppVersion) + tag: "" + # -- Image pull policy + pullPolicy: "" + # -- Image pull secrets + imagePullSecrets: [] + # -- Affinity settings + affinity: {} + # -- Node selector + nodeSelector: {} + # -- Topology spread constraints (if unspecified, default constraints for hostname and zone will be generated) + topologySpreadConstraints: [] + # -- Default topology spread policy for hostname + defaultHostNameSpreadPolicy: "" + # -- Default topology spread policy for zone + defaultZoneSpreadPolicy: "" + # -- Tolerations + tolerations: [] + # -- Priority class + priorityClassName: "" + # -- Pod security context + podSecurityContext: {} + # -- Additional pod annotations + podAnnotations: {} + # -- Additional pod labels + podLabels: {} + # -- Container security context + securityContext: {} + resources: + limits: + # -- Memory limit + memory: 100Mi + # -- CPU limit + cpu: 0.1 + requests: + # -- Memory request + memory: 20Mi + # -- CPU request + cpu: 0.01 + service: + # -- Service type + type: ClusterIP + # -- Service port + port: 443 + # -- Log level + logLevel: 0 diff --git a/packages/system/clustersecret-operator/values.yaml b/packages/system/clustersecret-operator/values.yaml new file mode 100644 index 00000000..ff7b161a --- /dev/null +++ b/packages/system/clustersecret-operator/values.yaml @@ -0,0 +1 @@ +clustersecret-operator: {} diff --git a/packages/system/coredns/Chart.yaml b/packages/system/coredns/Chart.yaml new file mode 100644 index 00000000..12c2a408 --- /dev/null +++ b/packages/system/coredns/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-coredns +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/coredns/Makefile b/packages/system/coredns/Makefile new file mode 100644 index 00000000..4aca5b38 --- /dev/null +++ b/packages/system/coredns/Makefile @@ -0,0 +1,10 @@ +export NAME=coredns +export NAMESPACE=kube-system + +include ../../../hack/package.mk + +update: + rm -rf charts + helm repo add cozy-coredns https://coredns.github.io/helm + helm repo update cozy-coredns + helm pull cozy-coredns/coredns --untar --untardir charts diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/.helmignore b/packages/system/coredns/charts/coredns/.helmignore similarity index 88% rename from packages/system/dashboard/charts/kubeapps/charts/redis/.helmignore rename to packages/system/coredns/charts/coredns/.helmignore index 207983f3..ea595e9f 100644 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/.helmignore +++ b/packages/system/coredns/charts/coredns/.helmignore @@ -19,7 +19,5 @@ .project .idea/ *.tmproj -# img folder -img/ -# Changelog -CHANGELOG.md +OWNERS +*.tests diff --git a/packages/system/coredns/charts/coredns/Chart.yaml b/packages/system/coredns/charts/coredns/Chart.yaml new file mode 100644 index 00000000..f3e9282f --- /dev/null +++ b/packages/system/coredns/charts/coredns/Chart.yaml @@ -0,0 +1,24 @@ +annotations: + artifacthub.io/changes: | + - kind: changed + description: Bump to CoreDNS 1.12.3 +apiVersion: v2 +appVersion: 1.12.3 +description: CoreDNS is a DNS server that chains plugins and provides Kubernetes DNS + Services +home: https://coredns.io +icon: https://coredns.io/images/CoreDNS_Colour_Horizontal.png +keywords: +- coredns +- dns +- kubedns +maintainers: +- name: mrueg +- name: haad +- name: hagaibarel +- name: shubham-cmyk +name: coredns +sources: +- https://github.com/coredns/coredns +type: application +version: 1.43.2 diff --git a/packages/system/coredns/charts/coredns/README.md b/packages/system/coredns/charts/coredns/README.md new file mode 100644 index 00000000..1ba154d4 --- /dev/null +++ b/packages/system/coredns/charts/coredns/README.md @@ -0,0 +1,316 @@ +# CoreDNS + +[CoreDNS](https://coredns.io/) is a DNS server that chains plugins and provides DNS Services + +# TL;DR; + +```console +$ helm repo add coredns https://coredns.github.io/helm +$ helm --namespace=kube-system install coredns coredns/coredns +``` + +## Introduction + +This chart bootstraps a [CoreDNS](https://github.com/coredns/coredns) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. This chart will provide DNS Services and can be deployed in multiple configuration to support various scenarios listed below: + +- CoreDNS as a cluster dns service and a drop-in replacement for Kube/SkyDNS. This is the default mode and CoreDNS is deployed as cluster-service in kube-system namespace. This mode is chosen by setting `isClusterService` to true. +- CoreDNS as an external dns service. In this mode CoreDNS is deployed as any kubernetes app in user specified namespace. The CoreDNS service can be exposed outside the cluster by using using either the NodePort or LoadBalancer type of service. This mode is chosen by setting `isClusterService` to false. +- CoreDNS as an external dns provider for kubernetes federation. This is a sub case of 'external dns service' which uses etcd plugin for CoreDNS backend. This deployment mode as a dependency on `etcd-operator` chart, which needs to be pre-installed. + +## Prerequisites + +- Kubernetes 1.10 or later + +## Installing the Chart + +The chart can be installed as follows: + +```console +$ helm repo add coredns https://coredns.github.io/helm +$ helm --namespace=kube-system install coredns coredns/coredns +``` + +The command deploys CoreDNS on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists various ways to override default configuration during deployment. + +> **Tip**: List all releases using `helm list --all-namespaces` + +## OCI installing + +The chart can also be installed using the following: + +```console +$ helm --namespace=kube-system install coredns oci://ghcr.io/coredns/charts/coredns --version 1.38.0 +``` + +The command deploys the `1.38.0` version of CoreDNS on the Kubernetes cluster in the default configuration. + +## Helm Unit Testing & Debugging Guide + +This document explains how to write, run, and debug Helm unit tests for this chart using [helm-unittest](https://github.com/helm-unittest/helm-unittest). + +--- + +### Prerequisites + +Install the Helm unittest plugin: + +```bash +helm plugin install https://github.com/helm-unittest/helm-unittest +``` + +### Running Unit Tests + +Run all unit tests in the chart folder (e.g., `./coredns`): + +```bash +helm unittest ./coredns +``` + +To output results in **JUnit XML** format: + +```bash +mkdir -p test-results +helm unittest --strict \ + --output-type JUnit \ + --output-file test-results/helm-unittest-report.xml \ + ./coredns +``` + +--- + +### Debugging Helm Charts + +Render the chart templates with real values to debug: + +```bash +helm template ./coredns --debug +``` +## YAML Intellisense in VS Code + +Add this line at the top of your unit test YAML files for schema validation and autocompletion in VS Code: + +```yaml +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +``` + +This improves YAML editing and error highlighting for test definitions. + +## Uninstalling the Chart + +To uninstall/delete the `coredns` deployment: + +```console +$ helm uninstall coredns +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Configuration + +| Parameter | Description | Default | +| :--------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------- | +| `image.repository` | The image repository to pull from | coredns/coredns | +| `image.tag` | The image tag to pull from (derived from Chart.yaml) | `` | +| `image.pullPolicy` | Image pull policy | IfNotPresent | +| `image.pullSecrets` | Specify container image pull secrets | `[]` | +| `replicaCount` | Number of replicas | 1 | +| `resources.limits.cpu` | Container maximum CPU | `100m` | +| `resources.limits.memory` | Container maximum memory | `128Mi` | +| `resources.requests.cpu` | Container requested CPU | `100m` | +| `resources.requests.memory` | Container requested memory | `128Mi` | +| `serviceType` | Kubernetes Service type | `ClusterIP` | +| `prometheus.service.enabled` | Set this to `true` to create Service for Prometheus metrics | `false` | +| `prometheus.service.annotations` | Annotations to add to the metrics Service | `{prometheus.io/scrape: "true", prometheus.io/port: "9153"}` | +| `prometheus.service.selector` | Pod selector | `{}` | +| `prometheus.monitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `prometheus.monitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | {} | +| `prometheus.monitor.namespace` | Selector to select which namespaces the Endpoints objects are discovered from. | `""` | +| `prometheus.monitor.interval` | Scrape interval for polling the metrics endpoint. (E.g. "30s") | `""` | +| `prometheus.monitor.selector` | Service selector | `{}` | +| `service.clusterIP` | IP address to assign to service | `""` | +| `service.clusterIPs` | IP addresses to assign to service | `[]` | +| `service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `""` | +| `service.externalIPs` | External IP addresses | [] | +| `service.externalTrafficPolicy` | Enable client source IP preservation | [] | +| `service.ipFamilyPolicy` | Service dual-stack policy | `""` | +| `service.annotations` | Annotations to add to service | {} | +| `service.selector` | Pod selector | `{}` | +| `service.trafficDistribution` | Service traffic routing strategy | | +| `serviceAccount.create` | If true, create & use serviceAccount | false | +| `serviceAccount.name` | If not set & create is true, use template fullname | | +| `rbac.create` | If true, create & use RBAC resources | true | +| `rbac.pspEnable` | Specifies whether a PodSecurityPolicy should be created. | `false` | +| `isClusterService` | Specifies whether chart should be deployed as cluster-service or normal k8s app. | true | +| `priorityClassName` | Name of Priority Class to assign pods | `""` | +| `securityContext` | securityContext definition for pods | capabilities.add.NET_BIND_SERVICE | +| `servers` | Configuration for CoreDNS and plugins | See values.yml | +| `livenessProbe.enabled` | Enable/disable the Liveness probe | `true` | +| `livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | `60` | +| `livenessProbe.periodSeconds` | How often to perform the probe | `10` | +| `livenessProbe.timeoutSeconds` | When the probe times out | `5` | +| `livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | `5` | +| `livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed. | `1` | +| `readinessProbe.enabled` | Enable/disable the Readiness probe | `true` | +| `readinessProbe.initialDelaySeconds` | Delay before readiness probe is initiated | `30` | +| `readinessProbe.periodSeconds` | How often to perform the probe | `10` | +| `readinessProbe.timeoutSeconds` | When the probe times out | `5` | +| `readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | `5` | +| `readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed. | `1` | +| `affinity` | Affinity settings for pod assignment | {} | +| `nodeSelector` | Node labels for pod assignment | {} | +| `tolerations` | Tolerations for pod assignment | [] | +| `zoneFiles` | Configure custom Zone files | [] | +| `extraContainers` | Optional array of sidecar containers | [] | +| `extraVolumes` | Optional array of volumes to create | [] | +| `extraVolumeMounts` | Optional array of volumes to mount inside the CoreDNS container | [] | +| `extraSecrets` | Optional array of secrets to mount inside the CoreDNS container | [] | +| `env` | Optional array of environment variables for CoreDNS container | [] | +| `customLabels` | Optional labels for Deployment(s), Pod, Service, ServiceMonitor objects | {} | +| `customAnnotations` | Optional annotations for Deployment(s), Pod, Service, ServiceMonitor objects | +| `rollingUpdate.maxUnavailable` | Maximum number of unavailable replicas during rolling update | `1` | +| `rollingUpdate.maxSurge` | Maximum number of pods created above desired number of pods | `25%` | +| `podDisruptionBudget` | Optional PodDisruptionBudget | {} | +| `podAnnotations` | Optional Pod only Annotations | {} | +| `terminationGracePeriodSeconds` | Optional duration in seconds the pod needs to terminate gracefully. | 30 | +| `hpa.enabled` | Enable Hpa autoscaler instead of proportional one | `false` | +| `hpa.minReplicas` | Hpa minimum number of CoreDNS replicas | `1` | +| `hpa.maxReplicas` | Hpa maximum number of CoreDNS replicas | `2` | +| `hpa.metrics` | Metrics definitions used by Hpa to scale up and down | {} | +| `autoscaler.enabled` | Optionally enabled a cluster-proportional-autoscaler for CoreDNS | `false` | +| `autoscaler.coresPerReplica` | Number of cores in the cluster per CoreDNS replica | `256` | +| `autoscaler.nodesPerReplica` | Number of nodes in the cluster per CoreDNS replica | `16` | +| `autoscaler.min` | Min size of replicaCount | 0 | +| `autoscaler.max` | Max size of replicaCount | 0 (aka no max) | +| `autoscaler.includeUnschedulableNodes` | Should the replicas scale based on the total number or only schedulable nodes | `false` | +| `autoscaler.preventSinglePointFailure` | If true does not allow single points of failure to form | `true` | +| `autoscaler.customFlags` | A list of custom flags to pass into cluster-proportional-autoscaler | (no args) | +| `autoscaler.image.repository` | The image repository to pull autoscaler from | registry.k8s.io/cpa/cluster-proportional-autoscaler | +| `autoscaler.image.tag` | The image tag to pull autoscaler from | `1.8.5` | +| `autoscaler.image.pullPolicy` | Image pull policy for the autoscaler | IfNotPresent | +| `autoscaler.image.pullSecrets` | Specify container image pull secrets | `[]` | +| `autoscaler.priorityClassName` | Optional priority class for the autoscaler pod. `priorityClassName` used if not set. | `""` | +| `autoscaler.affinity` | Affinity settings for pod assignment for autoscaler | {} | +| `autoscaler.nodeSelector` | Node labels for pod assignment for autoscaler | {} | +| `autoscaler.tolerations` | Tolerations for pod assignment for autoscaler | [] | +| `autoscaler.resources.limits.cpu` | Container maximum CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.limits.memory` | Container maximum memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.resources.requests.cpu` | Container requested CPU for cluster-proportional-autoscaler | `20m` | +| `autoscaler.resources.requests.memory` | Container requested memory for cluster-proportional-autoscaler | `10Mi` | +| `autoscaler.configmap.annotations` | Annotations to add to autoscaler config map. For example to stop CI renaming them | {} | +| `autoscaler.livenessProbe.enabled` | Enable/disable the Liveness probe | `true` | +| `autoscaler.livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | `10` | +| `autoscaler.livenessProbe.periodSeconds` | How often to perform the probe | `5` | +| `autoscaler.livenessProbe.timeoutSeconds` | When the probe times out | `5` | +| `autoscaler.livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | `3` | +| `autoscaler.livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed. | `1` | +| `autoscaler.extraContainers` | Optional array of sidecar containers | [] | +| `deployment.enabled` | Optionally disable the main deployment and its respective resources. | `true` | +| `deployment.name` | Name of the deployment if `deployment.enabled` is true. Otherwise the name of an existing deployment for the autoscaler or HPA to target. | `""` | +| `deployment.annotations` | Annotations to add to the main deployment | `{}` | +| `deployment.selector` | Pod selector | `{}` | +| `clusterRole.nameOverride` | ClusterRole name override | | + +See `values.yaml` for configuration notes. Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install coredns \ + coredns/coredns \ + --set rbac.create=false +``` + +The above command disables automatic creation of RBAC rules. + +Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, + +```console +$ helm install coredns coredns/coredns -f values.yaml +``` + +> **Tip**: You can use the default [values.yaml](/charts/coredns/values.yaml) + +## Caveats + +The chart will automatically determine which protocols to listen on based on +the protocols you define in your zones. This means that you could potentially +use both "TCP" and "UDP" on a single port. +Some cloud environments like "GCE" or "Azure container service" cannot +create external loadbalancers with both "TCP" and "UDP" protocols. So +When deploying CoreDNS with `serviceType="LoadBalancer"` on such cloud +environments, make sure you do not attempt to use both protocols at the same +time. + +## Autoscaling + +By setting `autoscaler.enabled = true` a +[cluster-proportional-autoscaler](https://github.com/kubernetes-incubator/cluster-proportional-autoscaler) +will be deployed. This will default to a coredns replica for every 256 cores, or +16 nodes in the cluster. These can be changed with `autoscaler.coresPerReplica` +and `autoscaler.nodesPerReplica`. When cluster is using large nodes (with more +cores), `coresPerReplica` should dominate. If using small nodes, +`nodesPerReplica` should dominate. + +This also creates a ServiceAccount, ClusterRole, and ClusterRoleBinding for +the autoscaler deployment. + +`replicaCount` is ignored if this is enabled. + +By setting `hpa.enabled = true` a [Horizontal Pod Autoscaler](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) +is enabled for Coredns deployment. This can scale number of replicas based on meitrics +like CpuUtilization, MemoryUtilization or Custom ones. + +## Adopting existing CoreDNS resources + +If you do not want to delete the existing CoreDNS resources in your cluster, you can adopt the resources into a release as of Helm 3.2.0. + +You will also need to annotate and label your existing resources to allow Helm to assume control of them. See: https://github.com/helm/helm/pull/7649 + +``` +annotations: + meta.helm.sh/release-name: your-release-name + meta.helm.sh/release-namespace: your-release-namespace +labels: + app.kubernetes.io/managed-by: Helm +``` + +Once you have annotated and labeled all the resources this chart specifies, you may need to locally template the chart and compare against existing manifest to ensure there are no changes/diffs.s If +you have been careful this should not diff and leave all the resources unmodified and now under management of helm. + +Some values to investigate to help adopt your existing manifests to the Helm release are: + +- k8sAppLabelOverride +- service.name +- customLabels + +In some cases, you will need to orphan delete your existing deployment since selector labels are immutable. + +``` +kubectl delete deployment coredns --cascade=orphan +``` + +This will delete the deployment and leave the replicaset to ensure no downtime in the cluster. You will need to manually delete the replicaset AFTER Helm has released a new deployment. + +Here is an example script to modify the annotations and labels of existing resources: + +WARNING: Substitute YOUR_HELM_RELEASE_NAME_HERE with the name of your helm release. + +``` +#!/usr/bin/env bash + +set -euo pipefail + +for kind in config service serviceAccount; do + echo "setting annotations and labels on $kind/coredns" + kubectl -n kube-system annotate --overwrite $kind coredns meta.helm.sh/release-name=YOUR_HELM_RELEASE_NAME_HERE + kubectl -n kube-system annotate --overwrite $kind coredns meta.helm.sh/release-namespace=kube-system + kubectl -n kube-system label --overwrite $kind coredns app.kubernetes.io/managed-by=Helm +done +``` + +NOTE: Sometimes, previous deployments of kube-dns that have been migrated to CoreDNS still use kube-dns for the service name as well. + +``` +echo "setting annotations and labels on service/kube-dns" +kubectl -n kube-system annotate --overwrite service kube-dns meta.helm.sh/release-name=YOUR_HELM_RELEASE_NAME_HERE +kubectl -n kube-system annotate --overwrite service kube-dns meta.helm.sh/release-namespace=kube-system +kubectl -n kube-system label --overwrite service kube-dns app.kubernetes.io/managed-by=Helm +``` diff --git a/packages/system/coredns/charts/coredns/templates/NOTES.txt b/packages/system/coredns/charts/coredns/templates/NOTES.txt new file mode 100644 index 00000000..3a1883b3 --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/NOTES.txt @@ -0,0 +1,30 @@ +{{- if .Values.isClusterService }} +CoreDNS is now running in the cluster as a cluster-service. +{{- else }} +CoreDNS is now running in the cluster. +It can be accessed using the below endpoint +{{- if contains "NodePort" .Values.serviceType }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "coredns.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo "$NODE_IP:$NODE_PORT" +{{- else if contains "LoadBalancer" .Values.serviceType }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status by running 'kubectl get svc -w {{ template "coredns.fullname" . }}' + + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "coredns.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo $SERVICE_IP +{{- else if contains "ClusterIP" .Values.serviceType }} + "{{ template "coredns.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local" + from within the cluster +{{- end }} +{{- end }} + +It can be tested with the following: + +1. Launch a Pod with DNS tools: + +kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools + +2. Query the DNS server: + +/ # host kubernetes diff --git a/packages/system/coredns/charts/coredns/templates/_helpers.tpl b/packages/system/coredns/charts/coredns/templates/_helpers.tpl new file mode 100644 index 00000000..2c2a9d61 --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/_helpers.tpl @@ -0,0 +1,236 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "coredns.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "coredns.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "coredns.labels" -}} +app.kubernetes.io/managed-by: {{ .Release.Service | quote }} +app.kubernetes.io/instance: {{ .Release.Name | quote }} +helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" +{{- if .Values.isClusterService }} +k8s-app: {{ template "coredns.k8sapplabel" . }} +kubernetes.io/cluster-service: "true" +kubernetes.io/name: "CoreDNS" +{{- end }} +app.kubernetes.io/name: {{ template "coredns.name" . }} +{{- end -}} + +{{/* +Common labels with autoscaler +*/}} +{{- define "coredns.labels.autoscaler" -}} +app.kubernetes.io/managed-by: {{ .Release.Service | quote }} +app.kubernetes.io/instance: {{ .Release.Name | quote }} +helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" +{{- if .Values.isClusterService }} +k8s-app: {{ template "coredns.k8sapplabel" . }}-autoscaler +kubernetes.io/cluster-service: "true" +kubernetes.io/name: "CoreDNS" +{{- end }} +app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler +{{- end -}} + +{{/* +Allow k8s-app label to be overridden +*/}} +{{- define "coredns.k8sapplabel" -}} +{{- default .Chart.Name .Values.k8sAppLabelOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.servicePorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + {{- $serviceport := default .port .servicePort -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false "serviceport" $serviceport) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc://, https:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://" "") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq (default false .use_tcp) true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://" "https://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if .nodePort -}} + {{- $innerdict := set $innerdict "nodePort" .nodePort -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- $portList := list -}} + {{- if index $innerdict "isudp" -}} + {{- $portList = append $portList (dict "port" (get $innerdict "serviceport") "protocol" "UDP" "name" (printf "udp-%s" $port) "targetPort" ($port | int)) -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- $portList = append $portList (dict "port" (get $innerdict "serviceport") "protocol" "TCP" "name" (printf "tcp-%s" $port) "targetPort" ($port | int)) -}} + {{- end -}} + + {{- range $portDict := $portList -}} + {{- if index $innerdict "nodePort" -}} + {{- $portDict := set $portDict "nodePort" (get $innerdict "nodePort" | int) -}} + {{- end -}} + + {{- printf "- %s\n" (toJson $portDict) -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Generate the list of ports automatically from the server definitions +*/}} +{{- define "coredns.containerPorts" -}} + {{/* Set ports to be an empty dict */}} + {{- $ports := dict -}} + {{/* Iterate through each of the server blocks */}} + {{- range .Values.servers -}} + {{/* Capture port to avoid scoping awkwardness */}} + {{- $port := toString .port -}} + + {{/* If none of the server blocks has mentioned this port yet take note of it */}} + {{- if not (hasKey $ports $port) -}} + {{- $ports := set $ports $port (dict "istcp" false "isudp" false) -}} + {{- end -}} + {{/* Retrieve the inner dict that holds the protocols for a given port */}} + {{- $innerdict := index $ports $port -}} + + {{/* + Look at each of the zones and check which protocol they serve + At the moment the following are supported by CoreDNS: + UDP: dns:// + TCP: tls://, grpc://, https:// + */}} + {{- range .zones -}} + {{- if has (default "" .scheme) (list "dns://" "") -}} + {{/* Optionally enable tcp for this service as well */}} + {{- if eq (default false .use_tcp) true }} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end }} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if has (default "" .scheme) (list "tls://" "grpc://" "https://") -}} + {{- $innerdict := set $innerdict "istcp" true -}} + {{- end -}} + {{- end -}} + + {{/* If none of the zones specify scheme, default to dns:// udp */}} + {{- if and (not (index $innerdict "istcp")) (not (index $innerdict "isudp")) -}} + {{- $innerdict := set $innerdict "isudp" true -}} + {{- end -}} + + {{- if .hostPort -}} + {{- $innerdict := set $innerdict "hostPort" .hostPort -}} + {{- end -}} + + {{/* Write the dict back into the outer dict */}} + {{- $ports := set $ports $port $innerdict -}} + + {{/* Fetch port from the configuration if the prometheus section exists */}} + {{- range .plugins -}} + {{- if eq .name "prometheus" -}} + {{- $prometheus_addr := toString .parameters -}} + {{- $prometheus_addr_list := regexSplit ":" $prometheus_addr -1 -}} + {{- $prometheus_port := index $prometheus_addr_list 1 -}} + {{- $ports := set $ports $prometheus_port (dict "istcp" true "isudp" false) -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{/* Write out the ports according to the info collected above */}} + {{- range $port, $innerdict := $ports -}} + {{- $portList := list -}} + {{- if index $innerdict "isudp" -}} + {{- $portList = append $portList (dict "containerPort" ($port | int) "protocol" "UDP" "name" (printf "udp-%s" $port)) -}} + {{- end -}} + {{- if index $innerdict "istcp" -}} + {{- $portList = append $portList (dict "containerPort" ($port | int) "protocol" "TCP" "name" (printf "tcp-%s" $port)) -}} + {{- end -}} + + {{- range $portDict := $portList -}} + {{- if index $innerdict "hostPort" -}} + {{- $portDict := set $portDict "hostPort" (get $innerdict "hostPort" | int) -}} + {{- end -}} + + {{- printf "- %s\n" (toJson $portDict) -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "coredns.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "coredns.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "coredns.clusterRoleName" -}} +{{- if and .Values.clusterRole .Values.clusterRole.nameOverride -}} + {{ .Values.clusterRole.nameOverride }} +{{- else -}} + {{ template "coredns.fullname" . }} +{{- end -}} +{{- end -}} diff --git a/packages/system/coredns/charts/coredns/templates/clusterrole-autoscaler.yaml b/packages/system/coredns/charts/coredns/templates/clusterrole-autoscaler.yaml new file mode 100644 index 00000000..9bf57d23 --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/clusterrole-autoscaler.yaml @@ -0,0 +1,30 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: {{- include "coredns.labels.autoscaler" . | nindent 4 }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- with .Values.customAnnotations }} + annotations: +{{- toYaml . | nindent 4 }} +{{- end }} +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["list","watch"] + - apiGroups: [""] + resources: ["replicationcontrollers/scale"] + verbs: ["get", "update"] + - apiGroups: ["extensions", "apps"] + resources: ["deployments/scale", "replicasets/scale"] + verbs: ["get", "update"] +# Remove the configmaps rule once below issue is fixed: +# kubernetes-incubator/cluster-proportional-autoscaler#16 + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "create"] +{{- end }} diff --git a/packages/system/coredns/charts/coredns/templates/clusterrole.yaml b/packages/system/coredns/charts/coredns/templates/clusterrole.yaml new file mode 100644 index 00000000..ecdeafae --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/clusterrole.yaml @@ -0,0 +1,36 @@ +{{- if and .Values.deployment.enabled .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "coredns.clusterRoleName" . }} + labels: {{- include "coredns.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - endpoints + - services + - pods + - namespaces + verbs: + - list + - watch +- apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - list + - watch +{{- if .Values.rbac.pspEnable }} +- apiGroups: + - policy + - extensions + resources: + - podsecuritypolicies + verbs: + - use + resourceNames: + - {{ template "coredns.fullname" . }} +{{- end }} +{{- end }} diff --git a/packages/system/coredns/charts/coredns/templates/clusterrolebinding-autoscaler.yaml b/packages/system/coredns/charts/coredns/templates/clusterrolebinding-autoscaler.yaml new file mode 100644 index 00000000..ef32306f --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/clusterrolebinding-autoscaler.yaml @@ -0,0 +1,23 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + labels: {{- include "coredns.labels.autoscaler" . | nindent 4 }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- with .Values.customAnnotations }} + annotations: +{{- toYaml . | nindent 4 }} +{{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.fullname" . }}-autoscaler +subjects: +- kind: ServiceAccount + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/packages/system/coredns/charts/coredns/templates/clusterrolebinding.yaml b/packages/system/coredns/charts/coredns/templates/clusterrolebinding.yaml new file mode 100644 index 00000000..ebeaf143 --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if and .Values.deployment.enabled .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "coredns.clusterRoleName" . }} + labels: {{- include "coredns.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "coredns.clusterRoleName" . }} +subjects: +- kind: ServiceAccount + name: {{ template "coredns.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/packages/system/coredns/charts/coredns/templates/configmap-autoscaler.yaml b/packages/system/coredns/charts/coredns/templates/configmap-autoscaler.yaml new file mode 100644 index 00000000..b10eb59e --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/configmap-autoscaler.yaml @@ -0,0 +1,33 @@ +{{- if .Values.autoscaler.enabled }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: {{- include "coredns.labels.autoscaler" . | nindent 4 }} + {{- if .Values.customLabels }} + {{- toYaml .Values.customLabels | nindent 4 }} + {{- end }} + {{- if or .Values.autoscaler.configmap.annotations .Values.customAnnotations }} + annotations: + {{- if .Values.customAnnotations }} + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + {{- if .Values.autoscaler.configmap.annotations -}} + {{ toYaml .Values.autoscaler.configmap.annotations | nindent 4 }} + {{- end }} + {{- end }} +data: + # When cluster is using large nodes(with more cores), "coresPerReplica" should dominate. + # If using small nodes, "nodesPerReplica" should dominate. + linear: |- + { + "coresPerReplica": {{ .Values.autoscaler.coresPerReplica | float64 }}, + "nodesPerReplica": {{ .Values.autoscaler.nodesPerReplica | float64 }}, + "preventSinglePointFailure": {{ .Values.autoscaler.preventSinglePointFailure }}, + "min": {{ .Values.autoscaler.min | int }}, + "max": {{ .Values.autoscaler.max | int }}, + "includeUnschedulableNodes": {{ .Values.autoscaler.includeUnschedulableNodes }} + } +{{- end }} diff --git a/packages/system/coredns/charts/coredns/templates/configmap.yaml b/packages/system/coredns/charts/coredns/templates/configmap.yaml new file mode 100644 index 00000000..e37858c1 --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/configmap.yaml @@ -0,0 +1,37 @@ +{{- if .Values.deployment.enabled }} +{{- if not .Values.deployment.skipConfig }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "coredns.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: {{- include "coredns.labels" . | nindent 4 }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- with .Values.customAnnotations }} + annotations: +{{- toYaml . | nindent 4 }} +{{- end }} +data: + Corefile: |- + {{- range $name, $conf := .Values.extraConfig }} + {{ $name }}{{ if $conf.parameters }} {{ $conf.parameters }}{{ end }} + {{- end }} + {{ range .Values.servers }} + {{- range $idx, $zone := .zones }}{{ if $idx }} {{ else }}{{ end }}{{ default "" $zone.scheme }}{{ default "." $zone.zone }}{{ else }}.{{ end -}} + {{- if .port }}:{{ .port }} {{ end -}} + { + {{- range .plugins }} + {{ .name }}{{ if .parameters }} {{ .parameters }}{{ end }}{{ if .configBlock }} { +{{ .configBlock | indent 12 }} + }{{ end }} + {{- end }} + } + {{ end }} + {{- range .Values.zoneFiles }} + {{ .filename }}: {{ toYaml .contents | indent 4 }} + {{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/coredns/charts/coredns/templates/deployment-autoscaler.yaml b/packages/system/coredns/charts/coredns/templates/deployment-autoscaler.yaml new file mode 100644 index 00000000..bdbcaad2 --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/deployment-autoscaler.yaml @@ -0,0 +1,98 @@ +{{- if and (.Values.autoscaler.enabled) (not .Values.hpa.enabled) }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: {{- include "coredns.labels.autoscaler" . | nindent 4 }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- with .Values.customAnnotations }} + annotations: +{{- toYaml . | nindent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ template "coredns.k8sapplabel" . }}-autoscaler + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + template: + metadata: + labels: + {{- if .Values.isClusterService }} + {{- if not (hasKey .Values.customLabels "k8s-app")}} + k8s-app: {{ template "coredns.k8sapplabel" . }}-autoscaler + {{- end }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }}-autoscaler + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.customLabels }} + {{ toYaml .Values.customLabels | nindent 8 }} + {{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/configmap-autoscaler.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} + {{- with .Values.autoscaler.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ template "coredns.fullname" . }}-autoscaler + {{- $priorityClassName := default .Values.priorityClassName .Values.autoscaler.priorityClassName }} + {{- if $priorityClassName }} + priorityClassName: {{ $priorityClassName | quote }} + {{- end }} + {{- if .Values.autoscaler.affinity }} + affinity: +{{ toYaml .Values.autoscaler.affinity | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.tolerations }} + tolerations: +{{ toYaml .Values.autoscaler.tolerations | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.nodeSelector }} + nodeSelector: +{{ toYaml .Values.autoscaler.nodeSelector | indent 8 }} + {{- end }} + {{- if .Values.autoscaler.image.pullSecrets }} + imagePullSecrets: +{{ toYaml .Values.autoscaler.image.pullSecrets | indent 8 }} + {{- end }} + containers: + - name: autoscaler + image: "{{ .Values.autoscaler.image.repository }}:{{ .Values.autoscaler.image.tag }}" + imagePullPolicy: {{ .Values.autoscaler.image.pullPolicy }} + resources: +{{ toYaml .Values.autoscaler.resources | indent 10 }} + {{- if .Values.autoscaler.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /healthz + port: 8080 + scheme: HTTP + initialDelaySeconds: {{ .Values.autoscaler.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.autoscaler.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.autoscaler.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.autoscaler.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.autoscaler.livenessProbe.failureThreshold }} + {{- end }} + command: + - /cluster-proportional-autoscaler + - --namespace={{ .Release.Namespace }} + - --configmap={{ template "coredns.fullname" . }}-autoscaler + - --target=Deployment/{{ default (include "coredns.fullname" .) .Values.deployment.name }} + - --logtostderr=true + - --v=2 + {{- if .Values.autoscaler.customFlags }} +{{ toYaml .Values.autoscaler.customFlags | indent 10 }} + {{- end }} +{{- if .Values.autoscaler.extraContainers }} +{{ toYaml .Values.autoscaler.extraContainers | indent 6 }} +{{- end }} +{{- end }} diff --git a/packages/system/coredns/charts/coredns/templates/deployment.yaml b/packages/system/coredns/charts/coredns/templates/deployment.yaml new file mode 100644 index 00000000..a0119aa3 --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/deployment.yaml @@ -0,0 +1,174 @@ +{{- if .Values.deployment.enabled }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ default (include "coredns.fullname" .) .Values.deployment.name }} + namespace: {{ .Release.Namespace }} + labels: {{- include "coredns.labels" . | nindent 4 }} + app.kubernetes.io/version: {{ .Values.image.tag | default .Chart.AppVersion | replace ":" "-" | replace "@" "_" | trunc 63 | trimSuffix "-" | quote }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + {{- if or .Values.deployment.annotations .Values.customAnnotations }} + annotations: + {{- if .Values.customAnnotations }} + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + {{- if .Values.deployment.annotations }} + {{- toYaml .Values.deployment.annotations | nindent 4 }} + {{- end }} + {{- end }} +spec: + {{- if and (not .Values.autoscaler.enabled) (not .Values.hpa.enabled) }} + replicas: {{ .Values.replicaCount }} + {{- end }} + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: {{ .Values.rollingUpdate.maxUnavailable }} + maxSurge: {{ .Values.rollingUpdate.maxSurge }} + selector: + {{- if .Values.deployment.selector }} + {{- toYaml .Values.deployment.selector | nindent 4 }} + {{- else }} + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ template "coredns.k8sapplabel" . }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- end }} + template: + metadata: + labels: + {{- if .Values.isClusterService }} + k8s-app: {{ template "coredns.k8sapplabel" . }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 8 }} +{{- end }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- if .Values.isClusterService }} + scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]' + {{- end }} +{{- if .Values.podAnnotations }} +{{ toYaml .Values.podAnnotations | indent 8 }} +{{- end }} + spec: + {{- if .Values.podSecurityContext }} + securityContext: {{ toYaml .Values.podSecurityContext | nindent 8 }} + {{- end }} + {{- if .Values.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} + {{- end }} + serviceAccountName: {{ template "coredns.serviceAccountName" . }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.isClusterService }} + dnsPolicy: Default + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.topologySpreadConstraints }} + topologySpreadConstraints: +{{ tpl (toYaml .Values.topologySpreadConstraints) $ | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + {{- if .Values.image.pullSecrets }} + imagePullSecrets: +{{ toYaml .Values.image.pullSecrets | indent 8 }} + {{- end }} + {{- if .Values.initContainers }} + initContainers: +{{ toYaml .Values.initContainers | indent 8 }} + {{- end }} + containers: + - name: "coredns" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: [ "-conf", "/etc/coredns/Corefile" ] + volumeMounts: + - name: config-volume + mountPath: /etc/coredns +{{- range .Values.extraSecrets }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + readOnly: true +{{- end }} +{{- if .Values.extraVolumeMounts }} +{{- toYaml .Values.extraVolumeMounts | nindent 8}} +{{- end }} +{{- if .Values.env }} + env: +{{- toYaml .Values.env | nindent 10}} +{{- end }} + resources: +{{ toYaml .Values.resources | indent 10 }} + ports: +{{ include "coredns.containerPorts" . | indent 8 }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: /ready + port: 8181 + scheme: HTTP + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- end }} +{{- if .Values.securityContext }} + securityContext: +{{- toYaml .Values.securityContext | nindent 10 }} +{{- end }} +{{- if .Values.extraContainers }} +{{ toYaml .Values.extraContainers | indent 6 }} +{{- end }} + volumes: + - name: config-volume + configMap: + name: {{ template "coredns.fullname" . }} + items: + - key: Corefile + path: Corefile + {{ range .Values.zoneFiles }} + - key: {{ .filename }} + path: {{ .filename }} + {{ end }} +{{- range .Values.extraSecrets }} + - name: {{ .name }} + secret: + secretName: {{ .name }} + defaultMode: {{ default 400 .defaultMode }} +{{- end }} +{{- if .Values.extraVolumes }} +{{ toYaml .Values.extraVolumes | indent 8 }} +{{- end }} +{{- end }} diff --git a/packages/system/coredns/charts/coredns/templates/hpa.yaml b/packages/system/coredns/charts/coredns/templates/hpa.yaml new file mode 100644 index 00000000..7fcc9931 --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/hpa.yaml @@ -0,0 +1,33 @@ +{{- if and (.Values.hpa.enabled) (not .Values.autoscaler.enabled) }} +--- +{{- if .Capabilities.APIVersions.Has "autoscaling/v2" }} +apiVersion: autoscaling/v2 +{{- else }} +apiVersion: autoscaling/v2beta2 +{{- end }} +kind: HorizontalPodAutoscaler +metadata: + name: {{ template "coredns.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: {{- include "coredns.labels" . | nindent 4 }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- with .Values.customAnnotations }} + annotations: +{{- toYaml . | nindent 4 }} +{{- end }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ default (include "coredns.fullname" .) .Values.deployment.name }} + minReplicas: {{ .Values.hpa.minReplicas }} + maxReplicas: {{ .Values.hpa.maxReplicas }} + metrics: +{{ toYaml .Values.hpa.metrics | indent 4 }} +{{- if .Values.hpa.behavior }} + behavior: +{{ toYaml .Values.hpa.behavior | indent 4 }} +{{- end }} +{{- end }} diff --git a/packages/system/coredns/charts/coredns/templates/poddisruptionbudget.yaml b/packages/system/coredns/charts/coredns/templates/poddisruptionbudget.yaml new file mode 100644 index 00000000..136d8049 --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/poddisruptionbudget.yaml @@ -0,0 +1,26 @@ +{{- if and .Values.deployment.enabled .Values.podDisruptionBudget -}} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ template "coredns.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: {{- include "coredns.labels" . | nindent 4 }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- with .Values.customAnnotations }} + annotations: +{{- toYaml . | nindent 4 }} +{{- end }} +spec: + {{- if not .Values.podDisruptionBudget.selector }} + selector: + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ template "coredns.k8sapplabel" . }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- end }} +{{ toYaml .Values.podDisruptionBudget | indent 2 }} +{{- end }} diff --git a/packages/system/coredns/charts/coredns/templates/service-metrics.yaml b/packages/system/coredns/charts/coredns/templates/service-metrics.yaml new file mode 100644 index 00000000..0ae9a157 --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/service-metrics.yaml @@ -0,0 +1,39 @@ +{{- if and .Values.deployment.enabled .Values.prometheus.service.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "coredns.fullname" . }}-metrics + namespace: {{ .Release.Namespace }} + labels: {{- include "coredns.labels" . | nindent 4 }} + app.kubernetes.io/component: metrics +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + {{- if or .Values.prometheus.service.annotations .Values.service.annotations .Values.customAnnotations }} + annotations: + {{- if .Values.prometheus.service.annotations }} + {{- toYaml .Values.prometheus.service.annotations | nindent 4 }} + {{- end }} + {{- if .Values.service.annotations }} + {{- toYaml .Values.service.annotations | nindent 4 }} + {{- end }} + {{- if .Values.customAnnotations }} + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + {{- end }} +spec: + selector: + {{- if .Values.prometheus.service.selector }} + {{- toYaml .Values.prometheus.service.selector | nindent 4 }} + {{- else }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ template "coredns.k8sapplabel" . }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- end }} + ports: + - name: metrics + port: 9153 + targetPort: 9153 +{{- end }} diff --git a/packages/system/coredns/charts/coredns/templates/service.yaml b/packages/system/coredns/charts/coredns/templates/service.yaml new file mode 100644 index 00000000..1247d09b --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/service.yaml @@ -0,0 +1,61 @@ +{{- if .Values.deployment.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ default (include "coredns.fullname" .) .Values.service.name }} + namespace: {{ .Release.Namespace }} + labels: {{- include "coredns.labels" . | nindent 4 }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + {{- if or .Values.service.annotations .Values.customAnnotations }} + annotations: + {{- if .Values.service.annotations }} + {{- toYaml .Values.service.annotations | nindent 4 }} + {{- end }} + {{- if .Values.customAnnotations }} + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + {{- end }} +spec: + selector: + {{- if .Values.service.selector }} + {{- toYaml .Values.service.selector | nindent 4 }} + {{- else }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ template "coredns.k8sapplabel" . }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + {{- end }} + {{- if .Values.service.clusterIP }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + {{- if .Values.service.clusterIPs }} + clusterIPs: + {{ toYaml .Values.service.clusterIPs | nindent 4 }} + {{- end }} + {{- if .Values.service.externalIPs }} + externalIPs: + {{- toYaml .Values.service.externalIPs | nindent 4 }} + {{- end }} + {{- if .Values.service.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }} + {{- end }} + {{- if .Values.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + {{- if .Values.service.loadBalancerClass }} + loadBalancerClass: {{ .Values.service.loadBalancerClass }} + {{- end }} + ports: +{{ include "coredns.servicePorts" . | indent 2 -}} + type: {{ default "ClusterIP" .Values.serviceType }} + {{- if .Values.service.ipFamilyPolicy }} + ipFamilyPolicy: {{ .Values.service.ipFamilyPolicy }} + {{- end }} +{{- end }} + {{- if .Values.service.trafficDistribution }} + trafficDistribution: {{ .Values.service.trafficDistribution }} + {{- end }} diff --git a/packages/system/coredns/charts/coredns/templates/serviceaccount-autoscaler.yaml b/packages/system/coredns/charts/coredns/templates/serviceaccount-autoscaler.yaml new file mode 100644 index 00000000..bcef6baf --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/serviceaccount-autoscaler.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.autoscaler.enabled .Values.rbac.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.fullname" . }}-autoscaler + namespace: {{ .Release.Namespace }} + labels: {{- include "coredns.labels.autoscaler" . | nindent 4 }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +{{- with .Values.customAnnotations }} + annotations: +{{- toYaml . | nindent 4 }} +{{- end }} +{{- if .Values.autoscaler.image.pullSecrets }} +imagePullSecrets: +{{ toYaml .Values.autoscaler.image.pullSecrets | indent 2 }} +{{- end }} +{{- end }} diff --git a/packages/system/coredns/charts/coredns/templates/serviceaccount.yaml b/packages/system/coredns/charts/coredns/templates/serviceaccount.yaml new file mode 100644 index 00000000..25f08930 --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/serviceaccount.yaml @@ -0,0 +1,24 @@ +{{- if and .Values.deployment.enabled .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "coredns.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + labels: {{- include "coredns.labels" . | nindent 4 }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + {{- if or .Values.serviceAccount.annotations .Values.customAnnotations }} + annotations: + {{- if .Values.customAnnotations }} + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + {{- if .Values.serviceAccount.annotations }} + {{- toYaml .Values.serviceAccount.annotations | nindent 4 }} + {{- end }} + {{- end }} +{{- if .Values.image.pullSecrets }} +imagePullSecrets: +{{ toYaml .Values.image.pullSecrets | indent 2 }} +{{- end }} +{{- end }} diff --git a/packages/system/coredns/charts/coredns/templates/servicemonitor.yaml b/packages/system/coredns/charts/coredns/templates/servicemonitor.yaml new file mode 100644 index 00000000..53f8bdb5 --- /dev/null +++ b/packages/system/coredns/charts/coredns/templates/servicemonitor.yaml @@ -0,0 +1,40 @@ +{{- if and .Values.deployment.enabled .Values.prometheus.monitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "coredns.fullname" . }} + {{- if .Values.prometheus.monitor.namespace }} + namespace: {{ .Values.prometheus.monitor.namespace }} + {{- end }} + labels: {{- include "coredns.labels" . | nindent 4 }} + {{- if .Values.prometheus.monitor.additionalLabels }} +{{ toYaml .Values.prometheus.monitor.additionalLabels | indent 4 }} + {{- end }} +{{- with .Values.customAnnotations }} + annotations: +{{- toYaml . | nindent 4 }} +{{- end }} +spec: + {{- if ne .Values.prometheus.monitor.namespace .Release.Namespace }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + {{- end }} + selector: + {{- if .Values.prometheus.monitor.selector }} + {{- toYaml .Values.prometheus.monitor.selector | nindent 4 }} + {{- else }} + matchLabels: + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- if .Values.isClusterService }} + k8s-app: {{ template "coredns.k8sapplabel" . }} + {{- end }} + app.kubernetes.io/name: {{ template "coredns.name" . }} + app.kubernetes.io/component: metrics + {{- end }} + endpoints: + - port: metrics + {{- if .Values.prometheus.monitor.interval }} + interval: {{ .Values.prometheus.monitor.interval }} + {{- end }} +{{- end }} diff --git a/packages/system/coredns/charts/coredns/tests/clusterrole-autoscaler_test.yaml b/packages/system/coredns/charts/coredns/tests/clusterrole-autoscaler_test.yaml new file mode 100644 index 00000000..fabda4e2 --- /dev/null +++ b/packages/system/coredns/charts/coredns/tests/clusterrole-autoscaler_test.yaml @@ -0,0 +1,62 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: test ClusterRole for autoscaler + +templates: + - templates/clusterrole-autoscaler.yaml + +tests: + - it: should render ClusterRole when autoscaler and rbac are enabled + set: + autoscaler: + enabled: true + rbac: + create: true + customLabels: + team: devops + customAnnotations: + note: autoscaler + + asserts: + - hasDocuments: + count: 1 + + - isKind: + of: ClusterRole + + - matchRegex: + path: metadata.name + pattern: ^.*-autoscaler$ + + - equal: + path: rules[0].resources + value: ["nodes"] + + - equal: + path: metadata.labels.team + value: devops + + - equal: + path: metadata.annotations.note + value: autoscaler + + - it: should not render ClusterRole if autoscaler is disabled + set: + autoscaler: + enabled: false + rbac: + create: true + + asserts: + - hasDocuments: + count: 0 + + - it: should not render ClusterRole if rbac is disabled + set: + autoscaler: + enabled: true + rbac: + create: false + + asserts: + - hasDocuments: + count: 0 \ No newline at end of file diff --git a/packages/system/coredns/charts/coredns/tests/clusterrole_test.yaml b/packages/system/coredns/charts/coredns/tests/clusterrole_test.yaml new file mode 100644 index 00000000..c7fa44b5 --- /dev/null +++ b/packages/system/coredns/charts/coredns/tests/clusterrole_test.yaml @@ -0,0 +1,53 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: ClusterRole RBAC Test + +templates: + - templates/clusterrole.yaml + +set: + deployment: + enabled: true + rbac: + create: true + pspEnable: true + + +tests: + - it: should render ClusterRole with correct name and rules + asserts: + - isKind: + of: ClusterRole + - equal: + path: metadata.name + value: RELEASE-NAME-coredns + - contains: + path: rules[0].resources + content: endpoints + - contains: + path: rules[0].resources + content: services + - contains: + path: rules[0].resources + content: pods + - contains: + path: rules[0].resources + content: namespaces + + - equal: + path: rules[1].apiGroups[0] + value: discovery.k8s.io + - contains: + path: rules[1].resources + content: endpointslices + - equal: + path: rules[2].apiGroups[0] + value: policy + - equal: + path: rules[2].apiGroups[1] + value: extensions + - contains: + path: rules[2].resources + content: podsecuritypolicies + - contains: + path: rules[2].verbs + content: use diff --git a/packages/system/coredns/charts/coredns/tests/clusterrolebinding_autoscaler_test.yaml b/packages/system/coredns/charts/coredns/tests/clusterrolebinding_autoscaler_test.yaml new file mode 100644 index 00000000..70380198 --- /dev/null +++ b/packages/system/coredns/charts/coredns/tests/clusterrolebinding_autoscaler_test.yaml @@ -0,0 +1,60 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: ClusterRoleBinding Autoscaler Test + +templates: + - templates/clusterrolebinding-autoscaler.yaml + +set: + autoscaler: + enabled: true + rbac: + create: true + customLabels: + my-custom-label: "enabled" + customAnnotations: + custom-annotation: "test-value" + +release: + namespace: test-namespace + +tests: + - it: should render ClusterRoleBinding with correct metadata and subject + asserts: + - isKind: + of: ClusterRoleBinding + + - equal: + path: metadata.name + value: RELEASE-NAME-coredns-autoscaler + + - equal: + path: metadata.labels.my-custom-label + value: enabled + + - equal: + path: metadata.annotations.custom-annotation + value: test-value + + - equal: + path: roleRef.apiGroup + value: rbac.authorization.k8s.io + + - equal: + path: roleRef.kind + value: ClusterRole + + - equal: + path: roleRef.name + value: RELEASE-NAME-coredns-autoscaler + + - equal: + path: subjects[0].kind + value: ServiceAccount + + - equal: + path: subjects[0].name + value: RELEASE-NAME-coredns-autoscaler + + - equal: + path: subjects[0].namespace + value: test-namespace diff --git a/packages/system/coredns/charts/coredns/tests/clusterrolebinding_test.yaml b/packages/system/coredns/charts/coredns/tests/clusterrolebinding_test.yaml new file mode 100644 index 00000000..1ae74be9 --- /dev/null +++ b/packages/system/coredns/charts/coredns/tests/clusterrolebinding_test.yaml @@ -0,0 +1,52 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: ClusterRoleBinding Test + +templates: + - templates/clusterrolebinding.yaml + +set: + deployment: + enabled: true + rbac: + create: true + + nameOverride: coredns-test + serviceAccount: + name: coredns-test + +release: + namespace: test-namespace + +tests: + - it: should render ClusterRoleBinding with correct metadata and subjects + asserts: + - isKind: + of: ClusterRoleBinding + + - equal: + path: metadata.name + value: RELEASE-NAME-coredns-test + + - equal: + path: roleRef.apiGroup + value: rbac.authorization.k8s.io + + - equal: + path: roleRef.kind + value: ClusterRole + + - equal: + path: roleRef.name + value: RELEASE-NAME-coredns-test + + - equal: + path: subjects[0].kind + value: ServiceAccount + + - equal: + path: subjects[0].name + value: coredns-test + + - equal: + path: subjects[0].namespace + value: test-namespace diff --git a/packages/system/coredns/charts/coredns/tests/configmap_autoscaler_test.yaml b/packages/system/coredns/charts/coredns/tests/configmap_autoscaler_test.yaml new file mode 100644 index 00000000..66bd4ee6 --- /dev/null +++ b/packages/system/coredns/charts/coredns/tests/configmap_autoscaler_test.yaml @@ -0,0 +1,75 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: ConfigMap Autoscaler Test + +templates: + - templates/configmap-autoscaler.yaml + +set: + autoscaler: + enabled: true + coresPerReplica: 256 + nodesPerReplica: 32 + preventSinglePointFailure: true + min: 1 + max: 10 + includeUnschedulableNodes: false + configmap: + annotations: + autoscaler-note: "used by cluster-autoscaler" + customLabels: + my-custom-label: "enabled" + customAnnotations: + custom-annotation: "test-value" + +release: + namespace: test-namespace + +tests: + - it: should render ConfigMap with correct metadata and autoscaler values + asserts: + - isKind: + of: ConfigMap + + - equal: + path: metadata.name + value: RELEASE-NAME-coredns-autoscaler + + - equal: + path: metadata.namespace + value: test-namespace + + - equal: + path: metadata.labels.my-custom-label + value: enabled + + - equal: + path: metadata.annotations.custom-annotation + value: test-value + + - equal: + path: metadata.annotations.autoscaler-note + value: used by cluster-autoscaler + + - matchRegex: + path: data.linear + pattern: '"coresPerReplica": 256' + + - matchRegex: + path: data.linear + pattern: '"nodesPerReplica": 32' + + - matchRegex: + path: data.linear + pattern: '"preventSinglePointFailure": true' + + - matchRegex: + path: data.linear + pattern: '"min": 1' + + - matchRegex: + path: data.linear + pattern: '"max": 10' + + - matchRegex: + path: data.linear + pattern: '"includeUnschedulableNodes": false' diff --git a/packages/system/coredns/charts/coredns/tests/configmap_test.yaml b/packages/system/coredns/charts/coredns/tests/configmap_test.yaml new file mode 100644 index 00000000..f6c208ba --- /dev/null +++ b/packages/system/coredns/charts/coredns/tests/configmap_test.yaml @@ -0,0 +1,41 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: "Test coredns configmap generation" +templates: + - templates/configmap.yaml + +tests: + - it: "should create a configmap with custom Corefile and zone files" + set: + deployment: + enabled: true + skipConfig: false + customAnnotations: + custom-annotation: "test-value" + servers: + - zones: + - zone: "example.com" + scheme: "." + port: 5353 + plugins: + - name: forward + parameters: ". 8.8.8.8" + zoneFiles: + - filename: db.example.com + contents: | + example.com. IN A 192.0.2.1 + + asserts: + - isKind: + of: ConfigMap + - matchRegex: + path: data.Corefile + pattern: "example\\.com:5353 \\{" + - matchRegex: + path: data.Corefile + pattern: "forward \\. 8\\.8\\.8\\.8" + - equal: + path: metadata.annotations.custom-annotation + value: "test-value" + - matchRegex: + path: 'data["db.example.com"]' + pattern: "example\\.com\\.\\s+IN\\s+A\\s+192\\.0\\.2\\.1" diff --git a/packages/system/coredns/charts/coredns/tests/deployment-autoscaler_test.yaml b/packages/system/coredns/charts/coredns/tests/deployment-autoscaler_test.yaml new file mode 100644 index 00000000..3c026ed5 --- /dev/null +++ b/packages/system/coredns/charts/coredns/tests/deployment-autoscaler_test.yaml @@ -0,0 +1,77 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: test autoscaler deployment +templates: + - templates/configmap-autoscaler.yaml + - templates/deployment-autoscaler.yaml + +tests: + - it: should render autoscaler deployment with correct image + set: + autoscaler: + enabled: true + image: + repository: autoscaler + tag: v1.0.0 + pullPolicy: IfNotPresent + hpa: + enabled: false + template: templates/deployment-autoscaler.yaml + asserts: + - isKind: + of: Deployment + - equal: + path: metadata.name + value: RELEASE-NAME-coredns-autoscaler + - equal: + path: spec.template.spec.containers[0].image + value: autoscaler:v1.0.0 + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: IfNotPresent + + - it: should set correct priorityClassName and tolerations + set: + autoscaler: + enabled: true + priorityClassName: system-cluster-critical + tolerations: + - key: "CriticalAddonsOnly" + operator: "Exists" + image: + repository: autoscaler + tag: v1.0.0 + hpa: + enabled: false + template: templates/deployment-autoscaler.yaml + asserts: + - equal: + path: spec.template.spec.priorityClassName + value: system-cluster-critical + - equal: + path: spec.template.spec.tolerations[0].key + value: CriticalAddonsOnly + - equal: + path: spec.template.spec.tolerations[0].operator + value: Exists + + - it: should not render deployment if autoscaler disabled + set: + autoscaler: + enabled: false + hpa: + enabled: false + template: templates/deployment-autoscaler.yaml + asserts: + - hasDocuments: + count: 0 + + - it: should not render deployment if hpa enabled + set: + autoscaler: + enabled: true + hpa: + enabled: true + template: templates/deployment-autoscaler.yaml + asserts: + - hasDocuments: + count: 0 diff --git a/packages/system/coredns/charts/coredns/tests/deployment_test.yaml b/packages/system/coredns/charts/coredns/tests/deployment_test.yaml new file mode 100644 index 00000000..db79f642 --- /dev/null +++ b/packages/system/coredns/charts/coredns/tests/deployment_test.yaml @@ -0,0 +1,62 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: CoreDNS Deployment Tests +templates: + - templates/configmap.yaml + - templates/deployment.yaml + +tests: + - it: should render a deployment with the correct image + set: + deployment: + enabled: true + image: + repository: coredns/coredns + tag: 1.10.1 + documentIndex: 0 + template: templates/deployment.yaml + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: coredns/coredns:1.10.1 + + - it: should include tolerations when isClusterService is true + set: + deployment: + enabled: true + isClusterService: true + tolerations: + - key: CriticalAddonsOnly + operator: Exists + documentIndex: 0 + template: templates/deployment.yaml + asserts: + - exists: + path: spec.template.spec.tolerations + + - it: should contain checksum/config annotation + set: + deployment: + enabled: true + documentIndex: 0 + template: templates/deployment.yaml + asserts: + - matchRegex: + path: spec.template.metadata.annotations.checksum/config + pattern: ^[a-f0-9]{64}$ + + - it: should set pod security context and priority class + set: + deployment: + enabled: true + podSecurityContext: + runAsUser: 1000 + priorityClassName: system-cluster-critical + documentIndex: 0 + template: templates/deployment.yaml + asserts: + - equal: + path: spec.template.spec.securityContext.runAsUser + value: 1000 + - equal: + path: spec.template.spec.priorityClassName + value: system-cluster-critical diff --git a/packages/system/coredns/charts/coredns/tests/hpa_test.yaml b/packages/system/coredns/charts/coredns/tests/hpa_test.yaml new file mode 100644 index 00000000..68773083 --- /dev/null +++ b/packages/system/coredns/charts/coredns/tests/hpa_test.yaml @@ -0,0 +1,110 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: HPA Test + +templates: + - templates/hpa.yaml + +set: + hpa: + enabled: true + minReplicas: 1 + maxReplicas: 5 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 80 + behavior: + scaleUp: + stabilizationWindowSeconds: 300 + policies: + - type: Percent + value: 100 + periodSeconds: 15 + deployment: + name: coredns + customLabels: + custom-label: "true" + customAnnotations: + custom-annotation: "enabled" + autoscaler: + enabled: false + +release: + namespace: test-namespace + +tests: + - it: should render HPA with correct metadata and spec + asserts: + - isKind: + of: HorizontalPodAutoscaler + + - equal: + path: metadata.name + value: RELEASE-NAME-coredns + + - equal: + path: metadata.namespace + value: test-namespace + + - equal: + path: metadata.labels.custom-label + value: "true" + + - equal: + path: metadata.annotations.custom-annotation + value: "enabled" + + - equal: + path: spec.minReplicas + value: 1 + + - equal: + path: spec.maxReplicas + value: 5 + + - equal: + path: spec.scaleTargetRef.apiVersion + value: apps/v1 + + - equal: + path: spec.scaleTargetRef.kind + value: Deployment + + - equal: + path: spec.scaleTargetRef.name + value: coredns + + - equal: + path: spec.metrics[0].type + value: Resource + + - equal: + path: spec.metrics[0].resource.name + value: cpu + + - equal: + path: spec.metrics[0].resource.target.type + value: Utilization + + - equal: + path: spec.metrics[0].resource.target.averageUtilization + value: 80 + + - equal: + path: spec.behavior.scaleUp.stabilizationWindowSeconds + value: 300 + + - equal: + path: spec.behavior.scaleUp.policies[0].type + value: Percent + + - equal: + path: spec.behavior.scaleUp.policies[0].value + value: 100 + + - equal: + path: spec.behavior.scaleUp.policies[0].periodSeconds + value: 15 diff --git a/packages/system/coredns/charts/coredns/tests/poddisruptionbudget_test.yaml b/packages/system/coredns/charts/coredns/tests/poddisruptionbudget_test.yaml new file mode 100644 index 00000000..963b88d5 --- /dev/null +++ b/packages/system/coredns/charts/coredns/tests/poddisruptionbudget_test.yaml @@ -0,0 +1,61 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: PodDisruptionBudget Test + +templates: + - templates/poddisruptionbudget.yaml + +set: + deployment: + enabled: true + + isClusterService: true + + podDisruptionBudget: + maxUnavailable: 1 + + customLabels: + my-custom-label: "enabled" + + customAnnotations: + custom-annotation: "true" + +release: + namespace: test-namespace + +tests: + - it: should render PodDisruptionBudget with correct metadata and spec + asserts: + - isKind: + of: PodDisruptionBudget + + - equal: + path: metadata.name + value: RELEASE-NAME-coredns + + - equal: + path: metadata.namespace + value: test-namespace + + - equal: + path: metadata.labels.my-custom-label + value: enabled + + - equal: + path: metadata.annotations.custom-annotation + value: "true" + + - equal: + path: spec.maxUnavailable + value: 1 + + - equal: + path: spec.selector.matchLabels["app.kubernetes.io/instance"] + value: RELEASE-NAME + + - equal: + path: spec.selector.matchLabels["app.kubernetes.io/name"] + value: coredns + + - equal: + path: spec.selector.matchLabels["k8s-app"] + value: coredns diff --git a/packages/system/coredns/charts/coredns/tests/service-metrics_test.yaml b/packages/system/coredns/charts/coredns/tests/service-metrics_test.yaml new file mode 100644 index 00000000..30db5e60 --- /dev/null +++ b/packages/system/coredns/charts/coredns/tests/service-metrics_test.yaml @@ -0,0 +1,81 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: Prometheus Metrics Service Test + +templates: + - templates/service-metrics.yaml + +set: + deployment: + enabled: true + + prometheus: + service: + enabled: true + annotations: + prometheus.io/scrape: "true" + selector: + app: custom-coredns + + service: + annotations: + monitoring: "enabled" + + customLabels: + my-custom-label: "true" + + customAnnotations: + custom-annotation: "true" + isClusterService: true + +release: + namespace: test-namespace + +tests: + - it: should render Prometheus metrics Service with correct metadata and port + asserts: + - isKind: + of: Service + + - equal: + path: metadata.name + value: RELEASE-NAME-coredns-metrics + + - equal: + path: metadata.namespace + value: test-namespace + + - equal: + path: metadata.labels["app.kubernetes.io/component"] + value: metrics + + - equal: + path: metadata.labels["my-custom-label"] + value: "true" + + - equal: + path: metadata.annotations["prometheus.io/scrape"] + value: "true" + + - equal: + path: metadata.annotations["monitoring"] + value: "enabled" + + - equal: + path: metadata.annotations["custom-annotation"] + value: "true" + + - equal: + path: spec.selector.app + value: custom-coredns + + - equal: + path: spec.ports[0].name + value: metrics + + - equal: + path: spec.ports[0].port + value: 9153 + + - equal: + path: spec.ports[0].targetPort + value: 9153 diff --git a/packages/system/coredns/charts/coredns/tests/service_test.yaml b/packages/system/coredns/charts/coredns/tests/service_test.yaml new file mode 100644 index 00000000..e5fac213 --- /dev/null +++ b/packages/system/coredns/charts/coredns/tests/service_test.yaml @@ -0,0 +1,108 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: Service Rendering Test + +templates: + - templates/service.yaml + +set: + deployment: + enabled: true + + service: + name: "custom-service-name" + annotations: + service-annotation: "value" + selector: + component: "dns" + clusterIP: "10.96.0.10" + clusterIPs: + - "10.96.0.10" + - "fd00::10" + externalIPs: + - "1.2.3.4" + externalTrafficPolicy: "Local" + loadBalancerIP: "4.3.2.1" + loadBalancerClass: "my-lb-class" + ipFamilyPolicy: "PreferDualStack" + trafficDistribution: "Topology" + + customLabels: + my-custom-label: "enabled" + + customAnnotations: + custom-annotation: "test" + + isClusterService: true + +release: + namespace: test-ns + +tests: + - it: should render a valid Service with custom values + asserts: + - isKind: + of: Service + + - equal: + path: metadata.name + value: custom-service-name + + - equal: + path: metadata.namespace + value: test-ns + + - equal: + path: metadata.labels.my-custom-label + value: enabled + + - equal: + path: metadata.annotations.custom-annotation + value: test + + - equal: + path: metadata.annotations.service-annotation + value: value + + - equal: + path: spec.selector.component + value: dns + + - equal: + path: spec.clusterIP + value: 10.96.0.10 + + - equal: + path: spec.clusterIPs[0] + value: 10.96.0.10 + + - equal: + path: spec.clusterIPs[1] + value: fd00::10 + + - equal: + path: spec.externalIPs[0] + value: 1.2.3.4 + + - equal: + path: spec.externalTrafficPolicy + value: Local + + - equal: + path: spec.loadBalancerIP + value: 4.3.2.1 + + - equal: + path: spec.loadBalancerClass + value: my-lb-class + + - equal: + path: spec.type + value: ClusterIP + + - equal: + path: spec.ipFamilyPolicy + value: PreferDualStack + + - equal: + path: spec.trafficDistribution + value: Topology diff --git a/packages/system/coredns/charts/coredns/tests/serviceaccount_autoscaler_test.yaml b/packages/system/coredns/charts/coredns/tests/serviceaccount_autoscaler_test.yaml new file mode 100644 index 00000000..3b1c3aef --- /dev/null +++ b/packages/system/coredns/charts/coredns/tests/serviceaccount_autoscaler_test.yaml @@ -0,0 +1,48 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: Autoscaler ServiceAccount Test + +templates: + - templates/serviceaccount-autoscaler.yaml + +set: + autoscaler: + enabled: true + image: + pullSecrets: + - name: my-registry-secret + rbac: + create: true + customLabels: + my-custom-label: "true" + customAnnotations: + custom-annotation: "enabled" + +release: + name: release-name + namespace: test-namespace + +tests: + - it: should render ServiceAccount with correct name, namespace, labels, annotations, and pullSecrets + asserts: + - isKind: + of: ServiceAccount + + - equal: + path: metadata.name + value: release-name-coredns-autoscaler + + - equal: + path: metadata.namespace + value: test-namespace + + - equal: + path: metadata.labels.my-custom-label + value: "true" + + - equal: + path: metadata.annotations.custom-annotation + value: "enabled" + + - equal: + path: imagePullSecrets[0].name + value: my-registry-secret diff --git a/packages/system/coredns/charts/coredns/tests/serviceaccount_test.yaml b/packages/system/coredns/charts/coredns/tests/serviceaccount_test.yaml new file mode 100644 index 00000000..53a79d45 --- /dev/null +++ b/packages/system/coredns/charts/coredns/tests/serviceaccount_test.yaml @@ -0,0 +1,47 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: ServiceAccount Test + +templates: + - templates/serviceaccount.yaml + +set: + deployment: + enabled: true + serviceAccount: + create: true + annotations: + serviceaccount-annotation: "true" + customAnnotations: + custom-annotation: "yes" + image: + pullSecrets: + - name: my-pull-secret + +release: + namespace: test-namespace + name: test-release + +tests: + - it: should render ServiceAccount with correct name, annotations, and pullSecrets + asserts: + - isKind: + of: ServiceAccount + + - equal: + path: metadata.name + value: test-release-coredns + + - equal: + path: metadata.namespace + value: test-namespace + - equal: + path: metadata.annotations.custom-annotation + value: yes + + - equal: + path: metadata.annotations.serviceaccount-annotation + value: "true" + + - equal: + path: imagePullSecrets[0].name + value: my-pull-secret diff --git a/packages/system/coredns/charts/coredns/tests/servicemonitor_test.yaml b/packages/system/coredns/charts/coredns/tests/servicemonitor_test.yaml new file mode 100644 index 00000000..76ee8105 --- /dev/null +++ b/packages/system/coredns/charts/coredns/tests/servicemonitor_test.yaml @@ -0,0 +1,64 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/helm-unittest/helm-unittest/main/schema/helm-testsuite.json +suite: ServiceMonitor Rendering Test + +templates: + - templates/servicemonitor.yaml + +set: + deployment: + enabled: true + prometheus: + monitor: + enabled: true + namespace: monitoring + interval: 15s + additionalLabels: + team: infra + selector: + matchLabels: + my-custom-label: "true" + customAnnotations: + monitoring: "enabled" + isClusterService: true + +release: + name: test-release + namespace: default + +tests: + - it: should render ServiceMonitor with correct metadata and selector + asserts: + - isKind: + of: ServiceMonitor + + - equal: + path: metadata.name + value: test-release-coredns + + - equal: + path: metadata.namespace + value: monitoring + + - equal: + path: metadata.labels.team + value: infra + + - equal: + path: metadata.annotations.monitoring + value: "enabled" + + - equal: + path: spec.namespaceSelector.matchNames[0] + value: default + + - equal: + path: spec.selector.matchLabels.my-custom-label + value: "true" + + - equal: + path: spec.endpoints[0].port + value: metrics + + - equal: + path: spec.endpoints[0].interval + value: 15s diff --git a/packages/system/coredns/charts/coredns/values.yaml b/packages/system/coredns/charts/coredns/values.yaml new file mode 100644 index 00000000..9f05dbad --- /dev/null +++ b/packages/system/coredns/charts/coredns/values.yaml @@ -0,0 +1,408 @@ +# Default values for coredns. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: coredns/coredns + # Overrides the image tag whose default is the chart appVersion. + tag: "" + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + pullSecrets: [] + # pullSecrets: + # - name: myRegistryKeySecretName + +replicaCount: 1 + +resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + +rollingUpdate: + maxUnavailable: 1 + maxSurge: 25% + +terminationGracePeriodSeconds: 30 + +podAnnotations: {} +# cluster-autoscaler.kubernetes.io/safe-to-evict: "false" + +serviceType: "ClusterIP" + +prometheus: + service: + enabled: false + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9153" + selector: {} + monitor: + enabled: false + additionalLabels: {} + namespace: "" + interval: "" + selector: {} + +service: +# clusterIP: "" +# clusterIPs: [] +# loadBalancerIP: "" +# loadBalancerClass: "" +# externalIPs: [] +# externalTrafficPolicy: "" +# ipFamilyPolicy: "" +# trafficDistribution: PreferClose + # The name of the Service + # If not set, a name is generated using the fullname template + name: "" + annotations: {} + # Pod selector + selector: {} + +serviceAccount: + create: false + # The name of the ServiceAccount to use + # If not set and create is true, a name is generated using the fullname template + name: "" + annotations: {} + +rbac: + # If true, create & use RBAC resources + create: true + +clusterRole: + # By default a name is generated using the fullname template. + # Override here if desired: + nameOverride: "" + +# isClusterService specifies whether chart should be deployed as cluster-service or normal k8s app. +isClusterService: true + +# Optional priority class to be used for the coredns pods. Used for autoscaler if autoscaler.priorityClassName not set. +priorityClassName: "" + +# Configure the pod level securityContext. +podSecurityContext: {} + +# Configure SecurityContext for Pod. +# Ensure that required linux capability to bind port number below 1024 is assigned (`CAP_NET_BIND_SERVICE`). +securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - NET_BIND_SERVICE + drop: + - ALL + readOnlyRootFilesystem: true + +# Default zone is what Kubernetes recommends: +# https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#coredns-configmap-options +servers: +- zones: + - zone: . + use_tcp: true + port: 53 + # -- expose the service on a different port + # servicePort: 5353 + # If serviceType is nodePort you can specify nodePort here + # nodePort: 30053 + # hostPort: 53 + plugins: + - name: errors + # Serves a /health endpoint on :8080, required for livenessProbe + - name: health + configBlock: |- + lameduck 10s + # Serves a /ready endpoint on :8181, required for readinessProbe + - name: ready + # Required to query kubernetes API for data + - name: kubernetes + parameters: cluster.local in-addr.arpa ip6.arpa + configBlock: |- + pods insecure + fallthrough in-addr.arpa ip6.arpa + ttl 30 + # Serves a /metrics endpoint on :9153, required for serviceMonitor + - name: prometheus + parameters: 0.0.0.0:9153 + - name: forward + parameters: . /etc/resolv.conf + - name: cache + parameters: 30 + - name: loop + - name: reload + - name: loadbalance + +# Complete example with all the options: +# - zones: # the `zones` block can be left out entirely, defaults to "." +# - zone: hello.world. # optional, defaults to "." +# scheme: tls:// # optional, defaults to "" (which equals "dns://" in CoreDNS) +# - zone: foo.bar. +# scheme: dns:// +# use_tcp: true # set this parameter to optionally expose the port on tcp as well as udp for the DNS protocol +# # Note that this will not work if you are also exposing tls or grpc on the same server +# port: 12345 # optional, defaults to "" (which equals 53 in CoreDNS) +# plugins: # the plugins to use for this server block +# - name: kubernetes # name of plugin, if used multiple times ensure that the plugin supports it! +# parameters: foo bar # list of parameters after the plugin +# configBlock: |- # if the plugin supports extra block style config, supply it here +# hello world +# foo bar + +# Extra configuration that is applied outside of the default zone block. +# Example to include additional config files, which may come from extraVolumes: +# extraConfig: +# import: +# parameters: /opt/coredns/*.conf +extraConfig: {} + +# To use the livenessProbe, the health plugin needs to be enabled in CoreDNS' server config +livenessProbe: + enabled: true + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 5 + successThreshold: 1 +# To use the readinessProbe, the ready plugin needs to be enabled in CoreDNS' server config +readinessProbe: + enabled: true + initialDelaySeconds: 30 + periodSeconds: 5 + timeoutSeconds: 5 + failureThreshold: 1 + successThreshold: 1 + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core +# for example: +# affinity: +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: foo.bar.com/role +# operator: In +# values: +# - master +affinity: {} + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.21/#topologyspreadconstraint-v1-core +# and supports Helm templating. +# For example: +# topologySpreadConstraints: +# - labelSelector: +# matchLabels: +# app.kubernetes.io/name: '{{ template "coredns.name" . }}' +# app.kubernetes.io/instance: '{{ .Release.Name }}' +# topologyKey: topology.kubernetes.io/zone +# maxSkew: 1 +# whenUnsatisfiable: ScheduleAnyway +# - labelSelector: +# matchLabels: +# app.kubernetes.io/name: '{{ template "coredns.name" . }}' +# app.kubernetes.io/instance: '{{ .Release.Name }}' +# topologyKey: kubernetes.io/hostname +# maxSkew: 1 +# whenUnsatisfiable: ScheduleAnyway +topologySpreadConstraints: [] + +# Node labels for pod assignment +# Ref: https://kubernetes.io/docs/user-guide/node-selection/ +nodeSelector: {} + +# expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core +# for example: +# tolerations: +# - key: foo.bar.com/role +# operator: Equal +# value: master +# effect: NoSchedule +tolerations: [] + +# https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget +podDisruptionBudget: {} + +# configure custom zone files as per https://coredns.io/2017/05/08/custom-dns-entries-for-kubernetes/ +zoneFiles: [] +# - filename: example.db +# domain: example.com +# contents: | +# example.com. IN SOA sns.dns.icann.com. noc.dns.icann.com. 2015082541 7200 3600 1209600 3600 +# example.com. IN NS b.iana-servers.net. +# example.com. IN NS a.iana-servers.net. +# example.com. IN A 192.168.99.102 +# *.example.com. IN A 192.168.99.102 + +# optional array of sidecar containers +extraContainers: [] +# - name: some-container-name +# image: some-image:latest +# imagePullPolicy: Always +# optional array of extra volumes to create +extraVolumes: [] +# - name: some-volume-name +# emptyDir: {} +# optional array of mount points for extraVolumes +extraVolumeMounts: [] +# - name: some-volume-name +# mountPath: /etc/wherever + +# optional array of secrets to mount inside coredns container +# possible usecase: need for secure connection with etcd backend +extraSecrets: [] +# - name: etcd-client-certs +# mountPath: /etc/coredns/tls/etcd +# defaultMode: 420 +# - name: some-fancy-secret +# mountPath: /etc/wherever +# defaultMode: 440 + +# optional array of environment variables for coredns container +# possible usecase: provides username and password for etcd user authentications +env: [] +# - name: WHATEVER_ENV +# value: whatever +# - name: SOME_SECRET_ENV +# valueFrom: +# secretKeyRef: +# name: some-secret-name +# key: secret-key + +# To support legacy deployments using CoreDNS with the "k8s-app: kube-dns" label selectors. +# See https://github.com/coredns/helm/blob/master/charts/coredns/README.md#adopting-existing-coredns-resources +# k8sAppLabelOverride: "kube-dns" + +# Custom labels to apply to Deployment, Pod, Configmap, Service, ServiceMonitor. Including autoscaler if enabled. +customLabels: {} + +# Custom annotations to apply to Deployment, Pod, Configmap, Service, ServiceMonitor. Including autoscaler if enabled. +customAnnotations: {} + +## Alternative configuration for HPA deployment if wanted +## Create HorizontalPodAutoscaler object. +## +# hpa: +# enabled: false +# minReplicas: 1 +# maxReplicas: 10 +# metrics: +# metrics: +# - type: Resource +# resource: +# name: memory +# target: +# type: Utilization +# averageUtilization: 60 +# - type: Resource +# resource: +# name: cpu +# target: +# type: Utilization +# averageUtilization: 60 + +hpa: + enabled: false + minReplicas: 1 + maxReplicas: 2 + metrics: [] + +## Configue a cluster-proportional-autoscaler for coredns +# See https://github.com/kubernetes-incubator/cluster-proportional-autoscaler +autoscaler: + # Enabled the cluster-proportional-autoscaler + enabled: false + + # Number of cores in the cluster per coredns replica + coresPerReplica: 256 + # Number of nodes in the cluster per coredns replica + nodesPerReplica: 16 + # Min size of replicaCount + min: 0 + # Max size of replicaCount (default of 0 is no max) + max: 0 + # Whether to include unschedulable nodes in the nodes/cores calculations - this requires version 1.8.0+ of the autoscaler + includeUnschedulableNodes: false + # If true does not allow single points of failure to form + preventSinglePointFailure: true + + # Annotations for the coredns proportional autoscaler pods + podAnnotations: {} + + ## Optionally specify some extra flags to pass to cluster-proprtional-autoscaler. + ## Useful for e.g. the nodelabels flag. + # customFlags: + # - --nodelabels=topology.kubernetes.io/zone=us-east-1a + + image: + repository: registry.k8s.io/cpa/cluster-proportional-autoscaler + tag: "v1.9.0" + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + pullSecrets: [] + # pullSecrets: + # - name: myRegistryKeySecretName + + # Optional priority class to be used for the autoscaler pods. priorityClassName used if not set. + priorityClassName: "" + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#affinity-v1-core + affinity: {} + + # Node labels for pod assignment + # Ref: https://kubernetes.io/docs/user-guide/node-selection/ + nodeSelector: {} + + # expects input structure as per specification https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#toleration-v1-core + tolerations: [] + + # resources for autoscaler pod + resources: + requests: + cpu: "20m" + memory: "10Mi" + limits: + cpu: "20m" + memory: "10Mi" + + # Options for autoscaler configmap + configmap: + ## Annotations for the coredns-autoscaler configmap + # i.e. strategy.spinnaker.io/versioned: "false" to ensure configmap isn't renamed + annotations: {} + + # Enables the livenessProbe for cluster-proportional-autoscaler - this requires version 1.8.0+ of the autoscaler + livenessProbe: + enabled: true + initialDelaySeconds: 10 + periodSeconds: 5 + timeoutSeconds: 5 + failureThreshold: 3 + successThreshold: 1 + + # optional array of sidecar containers + extraContainers: [] + # - name: some-container-name + # image: some-image:latest + # imagePullPolicy: Always + +deployment: + skipConfig: false + enabled: true + name: "" + ## Annotations for the coredns deployment + annotations: {} + ## Pod selector + selector: {} + +# Configures initcontainers for the coredns deployment. +initContainers: [] diff --git a/packages/system/coredns/values.yaml b/packages/system/coredns/values.yaml new file mode 100644 index 00000000..7f6403b8 --- /dev/null +++ b/packages/system/coredns/values.yaml @@ -0,0 +1,11 @@ +coredns: + image: + repository: registry.k8s.io/coredns/coredns + tag: v1.12.4 + replicaCount: 2 + k8sAppLabelOverride: kube-dns + service: + name: kube-dns + serviceAccount: + create: true + name: kube-dns diff --git a/packages/system/cozy-proxy/Makefile b/packages/system/cozy-proxy/Makefile index 8f4f6192..c1da95c7 100644 --- a/packages/system/cozy-proxy/Makefile +++ b/packages/system/cozy-proxy/Makefile @@ -1,8 +1,8 @@ NAME=cozy-proxy NAMESPACE=cozy-system -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/cozy-proxy/charts/cozy-proxy/Chart.yaml b/packages/system/cozy-proxy/charts/cozy-proxy/Chart.yaml index 13352680..58f166f6 100644 --- a/packages/system/cozy-proxy/charts/cozy-proxy/Chart.yaml +++ b/packages/system/cozy-proxy/charts/cozy-proxy/Chart.yaml @@ -2,5 +2,5 @@ apiVersion: v2 name: cozy-proxy description: A simple kube-proxy addon for 1:1 NAT services in Kubernetes using an NFT backend type: application -version: 0.2.0 -appVersion: 0.2.0 +version: 0.3.0 +appVersion: 0.3.0 diff --git a/packages/system/cozy-proxy/charts/cozy-proxy/values.yaml b/packages/system/cozy-proxy/charts/cozy-proxy/values.yaml index 8cde5bed..e143e926 100644 --- a/packages/system/cozy-proxy/charts/cozy-proxy/values.yaml +++ b/packages/system/cozy-proxy/charts/cozy-proxy/values.yaml @@ -1,6 +1,6 @@ image: repository: ghcr.io/cozystack/cozystack/cozy-proxy - tag: v0.2.0 + tag: v0.3.0 pullPolicy: IfNotPresent daemonset: diff --git a/packages/system/cozystack-api/.gitignore b/packages/system/cozystack-api/.gitignore new file mode 100644 index 00000000..f907698c --- /dev/null +++ b/packages/system/cozystack-api/.gitignore @@ -0,0 +1 @@ +apiserver.local.config/ diff --git a/packages/system/cozystack-api/Makefile b/packages/system/cozystack-api/Makefile index 66853833..c4e6f459 100644 --- a/packages/system/cozystack-api/Makefile +++ b/packages/system/cozystack-api/Makefile @@ -1,23 +1,30 @@ NAME=cozystack-api NAMESPACE=cozy-system -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk + +run-local: + openssl req -nodes -new -x509 -keyout /tmp/ca.key -out /tmp/ca.crt -subj "/CN=kube-ca" + openssl req -out /tmp/client.csr -new -newkey rsa:2048 -nodes -keyout /tmp/client.key -subj "/C=US/ST=SomeState/L=L/OU=Dev/CN=development/O=system:masters" + openssl x509 -req -days 365 -in /tmp/client.csr -CA /tmp/ca.crt -CAkey /tmp/ca.key -set_serial 01 -sha256 -out /tmp/client.crt + openssl req -out /tmp/apiserver.csr -new -newkey rsa:2048 -nodes -keyout /tmp/apiserver.key -subj "/CN=cozystack-api" -config cozystack-api-openssl.cnf + openssl x509 -req -days 365 -in /tmp/apiserver.csr -CA /tmp/ca.crt -CAkey /tmp/ca.key -set_serial 01 -sha256 -out /tmp/apiserver.crt -extensions v3_req -extfile cozystack-api-openssl.cnf + CGO_ENABLED=0 go build -o /tmp/cozystack-api ../../../cmd/cozystack-api/main.go + /tmp/cozystack-api --client-ca-file /tmp/ca.crt --tls-cert-file /tmp/apiserver.crt --tls-private-key-file /tmp/apiserver.key --secure-port 6443 --kubeconfig $(KUBECONFIG) --authorization-kubeconfig $(KUBECONFIG) --authentication-kubeconfig $(KUBECONFIG) + +debug: + dlv debug ../../../cmd/cozystack-api/main.go -- --client-ca-file /tmp/ca.crt --tls-cert-file /tmp/apiserver.crt --tls-private-key-file /tmp/apiserver.key --secure-port 6443 --kubeconfig $(KUBECONFIG) --authorization-kubeconfig $(KUBECONFIG) --authentication-kubeconfig $(KUBECONFIG) 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 \ --metadata-file images/cozystack-api.json \ - --push=$(PUSH) \ - --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ - --load=$(LOAD) + $(BUILDX_ARGS) IMAGE="$(REGISTRY)/cozystack-api:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/cozystack-api.json -o json -r)" \ yq -i '.cozystackAPI.image = strenv(IMAGE)' values.yaml rm -f images/cozystack-api.json diff --git a/packages/system/cozystack-api/cozystack-api-openssl.cnf b/packages/system/cozystack-api/cozystack-api-openssl.cnf new file mode 100644 index 00000000..5425fb00 --- /dev/null +++ b/packages/system/cozystack-api/cozystack-api-openssl.cnf @@ -0,0 +1,13 @@ +[ req ] +distinguished_name = req_distinguished_name +req_extensions = v3_req +prompt = no + +[ req_distinguished_name ] +CN = cozystack-api + +[ v3_req ] +subjectAltName = @alt_names + +[ alt_names ] +IP.1 = 127.0.0.1 diff --git a/packages/system/cozystack-api/images/cozystack-api/Dockerfile b/packages/system/cozystack-api/images/cozystack-api/Dockerfile index ea7bdc10..b4b206a6 100644 --- a/packages/system/cozystack-api/images/cozystack-api/Dockerfile +++ b/packages/system/cozystack-api/images/cozystack-api/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.24-alpine AS builder +FROM golang:1.25-alpine AS builder ARG TARGETOS ARG TARGETARCH diff --git a/packages/system/cozystack-api/templates/api-ingress.yaml b/packages/system/cozystack-api/templates/api-ingress.yaml index d7670e71..9226d887 100644 --- a/packages/system/cozystack-api/templates/api-ingress.yaml +++ b/packages/system/cozystack-api/templates/api-ingress.yaml @@ -1,7 +1,6 @@ -{{- $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" }} +{{- $host := index .Values._cluster "root-host" }} +{{- $exposeServices := splitList "," ((index .Values._cluster "expose-services") | default "") }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} {{- if and (has "api" $exposeServices) }} apiVersion: networking.k8s.io/v1 @@ -10,6 +9,7 @@ metadata: annotations: nginx.ingress.kubernetes.io/backend-protocol: HTTPS nginx.ingress.kubernetes.io/ssl-passthrough: "true" + nginx.ingress.kubernetes.io/force-ssl-redirect: "true" name: kubernetes namespace: default spec: diff --git a/packages/system/cozystack-api/templates/apiservice.yaml b/packages/system/cozystack-api/templates/apiservice.yaml index 5829561e..3cd3665b 100644 --- a/packages/system/cozystack-api/templates/apiservice.yaml +++ b/packages/system/cozystack-api/templates/apiservice.yaml @@ -1,9 +1,10 @@ apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: + annotations: + cert-manager.io/inject-ca-from: "{{ .Release.Namespace }}/cozystack-api" name: v1alpha1.apps.cozystack.io spec: - insecureSkipTLSVerify: true group: apps.cozystack.io groupPriorityMinimum: 1000 versionPriority: 15 @@ -11,3 +12,18 @@ spec: name: cozystack-api namespace: cozy-system version: v1alpha1 +--- +apiVersion: apiregistration.k8s.io/v1 +kind: APIService +metadata: + annotations: + cert-manager.io/inject-ca-from: "{{ .Release.Namespace }}/cozystack-api" + name: v1alpha1.core.cozystack.io +spec: + group: core.cozystack.io + groupPriorityMinimum: 1000 + versionPriority: 15 + service: + name: cozystack-api + namespace: cozy-system + version: v1alpha1 diff --git a/packages/system/cozystack-api/templates/certmanager.yaml b/packages/system/cozystack-api/templates/certmanager.yaml new file mode 100644 index 00000000..4f73768a --- /dev/null +++ b/packages/system/cozystack-api/templates/certmanager.yaml @@ -0,0 +1,47 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: cozystack-api-selfsigned + namespace: {{ .Release.Namespace }} +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: cozystack-api-ca + namespace: {{ .Release.Namespace }} +spec: + secretName: cozystack-api-ca + duration: 43800h # 5 years + commonName: cozystack-api-ca + issuerRef: + name: cozystack-api-selfsigned + isCA: true + privateKey: + rotationPolicy: Never +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: cozystack-api-ca + namespace: {{ .Release.Namespace }} +spec: + ca: + secretName: cozystack-api-ca +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: cozystack-api + namespace: {{ .Release.Namespace }} +spec: + secretName: cozystack-api-cert + duration: 8760h + renewBefore: 720h + issuerRef: + name: cozystack-api-ca + commonName: cozystack-api + dnsNames: + - cozystack-api + - cozystack-api.{{ .Release.Namespace }}.svc diff --git a/packages/system/cozystack-api/templates/configmap.yaml b/packages/system/cozystack-api/templates/configmap.yaml deleted file mode 100644 index 8fccd427..00000000 --- a/packages/system/cozystack-api/templates/configmap.yaml +++ /dev/null @@ -1,330 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: cozystack-api - namespace: cozy-system -data: - config.yaml: | - resources: - - application: - kind: Bucket - singular: bucket - plural: buckets - release: - prefix: bucket- - labels: - cozystack.io/ui: "true" - chart: - name: bucket - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: ClickHouse - singular: clickhouse - plural: clickhouses - release: - prefix: clickhouse- - labels: - cozystack.io/ui: "true" - chart: - name: clickhouse - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: HTTPCache - singular: httpcache - plural: httpcaches - release: - prefix: http-cache- - labels: - cozystack.io/ui: "true" - chart: - name: http-cache - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: NATS - singular: nats - plural: natses - release: - prefix: nats- - labels: - cozystack.io/ui: "true" - chart: - name: nats - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: TCPBalancer - singular: tcpbalancer - plural: tcpbalancers - release: - prefix: tcp-balancer- - labels: - cozystack.io/ui: "true" - chart: - name: tcp-balancer - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: VirtualMachine - singular: virtualmachine - plural: virtualmachines - release: - prefix: virtual-machine- - labels: - cozystack.io/ui: "true" - chart: - name: virtual-machine - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: VPN - singular: vpn - plural: vpns - release: - prefix: vpn- - labels: - cozystack.io/ui: "true" - chart: - name: vpn - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: MySQL - singular: mysql - plural: mysqls - release: - prefix: mysql- - labels: - cozystack.io/ui: "true" - chart: - name: mysql - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: Tenant - singular: tenant - plural: tenants - release: - prefix: tenant- - labels: - cozystack.io/ui: "true" - chart: - name: tenant - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: Kubernetes - singular: kubernetes - plural: kuberneteses - release: - prefix: kubernetes- - labels: - cozystack.io/ui: "true" - chart: - name: kubernetes - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: Redis - singular: redis - plural: redises - release: - prefix: redis- - labels: - cozystack.io/ui: "true" - chart: - name: redis - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: RabbitMQ - singular: rabbitmq - plural: rabbitmqs - release: - prefix: rabbitmq- - labels: - cozystack.io/ui: "true" - chart: - name: rabbitmq - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: Postgres - singular: postgres - plural: postgreses - release: - prefix: postgres- - labels: - cozystack.io/ui: "true" - chart: - name: postgres - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: FerretDB - singular: ferretdb - plural: ferretdb - release: - prefix: ferretdb- - labels: - cozystack.io/ui: "true" - chart: - name: ferretdb - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: Kafka - singular: kafka - plural: kafkas - release: - prefix: kafka- - labels: - cozystack.io/ui: "true" - chart: - name: kafka - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: VMDisk - plural: vmdisks - singular: vmdisk - release: - prefix: vm-disk- - labels: - cozystack.io/ui: "true" - chart: - name: vm-disk - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: VMInstance - plural: vminstances - singular: vminstance - release: - prefix: vm-instance- - labels: - cozystack.io/ui: "true" - chart: - name: vm-instance - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: Monitoring - plural: monitorings - singular: monitoring - release: - prefix: "" - labels: - cozystack.io/ui: "true" - chart: - name: monitoring - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - - application: - kind: Etcd - plural: etcds - singular: etcd - release: - prefix: "" - labels: - cozystack.io/ui: "true" - chart: - name: etcd - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - - application: - kind: Ingress - plural: ingresses - singular: ingress - release: - prefix: "" - labels: - cozystack.io/ui: "true" - chart: - name: ingress - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - - application: - kind: SeaweedFS - plural: seaweedfses - singular: seaweedfs - release: - prefix: "" - labels: - cozystack.io/ui: "true" - chart: - name: seaweedfs - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - - application: - kind: BootBox - plural: bootboxes - singular: bootbox - release: - prefix: "" - labels: - cozystack.io/ui: "true" - chart: - name: bootbox - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - - application: - kind: Info - plural: infos - singular: info - release: - prefix: "" - labels: - cozystack.io/ui: "true" - chart: - name: info - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public diff --git a/packages/system/cozystack-api/templates/deployment.yaml b/packages/system/cozystack-api/templates/deployment.yaml index 3dd93bd8..9febfe1e 100644 --- a/packages/system/cozystack-api/templates/deployment.yaml +++ b/packages/system/cozystack-api/templates/deployment.yaml @@ -6,7 +6,7 @@ metadata: labels: app: cozystack-api spec: - replicas: 2 + replicas: {{ .Values.cozystackAPI.replicas }} selector: matchLabels: app: cozystack-api @@ -14,22 +14,33 @@ spec: metadata: labels: app: cozystack-api - annotations: - checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} spec: + tolerations: + - operator: Exists serviceAccountName: cozystack-api + affinity: + nodeAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + preference: + matchExpressions: + - key: node-role.kubernetes.io/control-plane + operator: Exists containers: - name: cozystack-api + args: + - --tls-cert-file=/tmp/cozystack-api-certs/tls.crt + - --tls-private-key-file=/tmp/cozystack-api-certs/tls.key image: "{{ .Values.cozystackAPI.image }}" - args: ["--config=/config/config.yaml"] + ports: + - containerPort: 443 + name: https volumeMounts: - - name: config-volume - mountPath: /config/config.yaml - subPath: config.yaml + - name: cozystack-api-certs + mountPath: /tmp/cozystack-api-certs + readOnly: true volumes: - - name: config-volume - configMap: - name: cozystack-api - items: - - key: config.yaml - path: config.yaml + - name: cozystack-api-certs + secret: + secretName: cozystack-api-cert + defaultMode: 0400 diff --git a/packages/system/cozystack-api/templates/hook.yaml b/packages/system/cozystack-api/templates/hook.yaml new file mode 100644 index 00000000..852b2db0 --- /dev/null +++ b/packages/system/cozystack-api/templates/hook.yaml @@ -0,0 +1,76 @@ +{{- $previous := lookup "apps/v1" "DaemonSet" .Release.Namespace "cozystack-api" }} +{{- if $previous }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: "cozystack-api-hook" + annotations: + helm.sh/hook: post-upgrade + helm.sh/hook-weight: "1" + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation +spec: + template: + metadata: + labels: + policy.cozystack.io/allow-to-apiserver: "true" + spec: + serviceAccountName: "cozystack-api-hook" + containers: + - name: kubectl + image: docker.io/alpine/k8s:1.33.4 + command: + - sh + args: + - -exc + - |- + kubectl --namespace={{ .Release.Namespace }} delete --ignore-not-found \ + daemonsets.apps cozystack-api + restartPolicy: Never +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + annotations: + helm.sh/hook: post-upgrade + helm.sh/hook-weight: "1" + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation + name: "cozystack-api-hook" +rules: +- apiGroups: + - "apps" + resources: + - "daemonsets" + verbs: + - get + - delete + resourceNames: + - "cozystack-api" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: "cozystack-api-hook" + annotations: + helm.sh/hook: post-upgrade + helm.sh/hook-weight: "1" + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: "cozystack-api-hook" +subjects: + - kind: ServiceAccount + name: "cozystack-api-hook" + namespace: "{{ .Release.Namespace }}" +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "cozystack-api-hook" + annotations: + helm.sh/hook: post-upgrade + helm.sh/hook-weight: "1" + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation +{{- end }} + diff --git a/packages/system/cozystack-api/templates/rbac.yaml b/packages/system/cozystack-api/templates/rbac.yaml index 7cfd4282..0429b9ef 100644 --- a/packages/system/cozystack-api/templates/rbac.yaml +++ b/packages/system/cozystack-api/templates/rbac.yaml @@ -4,14 +4,23 @@ metadata: name: cozystack-api rules: - apiGroups: [""] - resources: ["namespaces"] + resources: ["namespaces", "secrets", "services"] verbs: ["get", "watch", "list"] +- apiGroups: ["rbac.authorization.k8s.io"] + resources: ["rolebindings"] + verbs: ["get", "watch", "list"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "update", "patch", "delete"] - apiGroups: ["admissionregistration.k8s.io"] resources: ["mutatingwebhookconfigurations", "validatingwebhookconfigurations", "validatingadmissionpolicies", "validatingadmissionpolicybindings"] verbs: ["get", "watch", "list"] - apiGroups: ["flowcontrol.apiserver.k8s.io"] - resources: ['prioritylevelconfigurations', 'flowschemas'] - verbs: ['list', 'watch'] -- apiGroups: ['helm.toolkit.fluxcd.io'] - resources: ['*'] - verbs: ['*'] + resources: ["prioritylevelconfigurations", "flowschemas"] + verbs: ["list", "watch"] +- apiGroups: ["cozystack.io"] + resources: ["*"] + verbs: ["get", "watch", "list"] +- apiGroups: ["helm.toolkit.fluxcd.io"] + resources: ["*"] + verbs: ["*"] diff --git a/packages/system/cozystack-api/templates/service.yaml b/packages/system/cozystack-api/templates/service.yaml index 2dcd618b..64ba149d 100644 --- a/packages/system/cozystack-api/templates/service.yaml +++ b/packages/system/cozystack-api/templates/service.yaml @@ -4,9 +4,10 @@ metadata: name: cozystack-api namespace: cozy-system spec: + trafficDistribution: PreferClose ports: - port: 443 protocol: TCP - targetPort: 443 + targetPort: https selector: app: cozystack-api diff --git a/packages/system/cozystack-api/templates/tenantnamespaces-rbac.yaml b/packages/system/cozystack-api/templates/tenantnamespaces-rbac.yaml new file mode 100644 index 00000000..48cd3071 --- /dev/null +++ b/packages/system/cozystack-api/templates/tenantnamespaces-rbac.yaml @@ -0,0 +1,26 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: tenantnamespaces-read +rules: +- apiGroups: + - core.cozystack.io + resources: + - tenantnamespaces + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: tenantnamespaces-read-authenticated +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: tenantnamespaces-read +subjects: +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:authenticated diff --git a/packages/system/cozystack-api/values.yaml b/packages/system/cozystack-api/values.yaml index 212002b1..dddabf54 100644 --- a/packages/system/cozystack-api/values.yaml +++ b/packages/system/cozystack-api/values.yaml @@ -1,2 +1,3 @@ cozystackAPI: - image: ghcr.io/cozystack/cozystack/cozystack-api:v0.33.2@sha256:724a166d2daa9cae3caeb18bffdc7146d80de310a6f97360c2beaef340076e6d + image: ghcr.io/cozystack/cozystack/cozystack-api:v1.3.0@sha256:5fa8648821cf1e9e08cf7c2899c4b1c4226bb74c6773327141456c7d3f2b9b7e + replicas: 2 diff --git a/packages/system/cozystack-basics/Chart.yaml b/packages/system/cozystack-basics/Chart.yaml new file mode 100644 index 00000000..8135baef --- /dev/null +++ b/packages/system/cozystack-basics/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-basics +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/cozystack-basics/Makefile b/packages/system/cozystack-basics/Makefile new file mode 100644 index 00000000..2d5f6c59 --- /dev/null +++ b/packages/system/cozystack-basics/Makefile @@ -0,0 +1,4 @@ +export NAME=tenant-root +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/cozystack-basics/templates/clusterroles.yaml b/packages/system/cozystack-basics/templates/clusterroles.yaml new file mode 100644 index 00000000..f270f4e1 --- /dev/null +++ b/packages/system/cozystack-basics/templates/clusterroles.yaml @@ -0,0 +1,264 @@ +--- +# == default cluster role == +# Used by tenant ServiceAccounts +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cozy:tenant +aggregationRule: + clusterRoleSelectors: + - matchLabels: + rbac.cozystack.io/aggregate-to-tenant: "true" +rules: [] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cozy:tenant:base + labels: + rbac.cozystack.io/aggregate-to-tenant: "true" +rules: +- apiGroups: [""] + resources: ["pods", "services", "persistentvolumes", "endpoints", "events", "resourcequotas"] + verbs: ["get", "list", "watch"] +- apiGroups: ["discovery.k8s.io"] + resources: ["endpointslices"] + verbs: ["get", "list", "watch"] +- apiGroups: ["networking.k8s.io"] + resources: ["ingresses"] + verbs: ["get", "list", "watch"] +- apiGroups: ["rbac.authorization.k8s.io"] + resources: ["roles"] + verbs: ["get"] +- apiGroups: ["apps.cozystack.io"] + resources: ['*'] + verbs: ['*'] +- apiGroups: + - cozystack.io + resources: + - workloadmonitors + - workloads + verbs: ["get", "list", "watch"] +- apiGroups: + - core.cozystack.io + resources: + - tenantmodules + - tenantsecrets + verbs: ["get", "list", "watch"] +--- +# == view cluster role == +# Aggregates all roles labeled for view access +# Also aggregated into use, admin, and super-admin +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cozy:tenant:view + labels: + rbac.cozystack.io/aggregate-to-tenant-use: "true" + rbac.cozystack.io/aggregate-to-tenant-admin: "true" + rbac.cozystack.io/aggregate-to-tenant-super-admin: "true" +aggregationRule: + clusterRoleSelectors: + - matchLabels: + rbac.cozystack.io/aggregate-to-tenant-view: "true" +rules: [] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cozy:tenant:view:base + labels: + rbac.cozystack.io/aggregate-to-tenant-view: "true" +rules: +- apiGroups: + - rbac.authorization.k8s.io + resources: + - roles + verbs: + - get +- apiGroups: + - apps.cozystack.io + resources: + - "*" + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - pods + - services + - persistentvolumes + - endpoints + - events + - resourcequotas + verbs: + - get + - list + - watch +- apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - list + - watch +- apiGroups: + - networking.k8s.io + resources: + - ingresses + verbs: + - get + - list + - watch +- apiGroups: + - cozystack.io + resources: + - workloadmonitors + - workloads + verbs: ["get", "list", "watch"] +--- +# == use cluster role == +# Aggregates view + all roles labeled for use access +# Also aggregated into admin and super-admin +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cozy:tenant:use + labels: + rbac.cozystack.io/aggregate-to-tenant-admin: "true" + rbac.cozystack.io/aggregate-to-tenant-super-admin: "true" +aggregationRule: + clusterRoleSelectors: + - matchLabels: + rbac.cozystack.io/aggregate-to-tenant-use: "true" +rules: [] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cozy:tenant:use:base + labels: + rbac.cozystack.io/aggregate-to-tenant-use: "true" +rules: +- apiGroups: ["subresources.kubevirt.io"] + resources: + - virtualmachineinstances/console + - virtualmachineinstances/vnc + verbs: + - get + - list +- apiGroups: ["subresources.kubevirt.io"] + resources: + - virtualmachineinstances/portforward + verbs: + - get + - update +- apiGroups: + - core.cozystack.io + resources: + - tenantmodules + - tenantsecrets + verbs: ["get", "list", "watch"] +--- +# == admin cluster role == +# Aggregates use + all roles labeled for admin access +# Also aggregated into super-admin +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cozy:tenant:admin + labels: + rbac.cozystack.io/aggregate-to-tenant-super-admin: "true" +aggregationRule: + clusterRoleSelectors: + - matchLabels: + rbac.cozystack.io/aggregate-to-tenant-admin: "true" +rules: [] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cozy:tenant:admin:base + labels: + rbac.cozystack.io/aggregate-to-tenant-admin: "true" +rules: +- apiGroups: [""] + resources: + - pods + - services + - persistentvolumes + - endpoints + - events + verbs: + - delete +- apiGroups: ["kubevirt.io"] + resources: + - virtualmachines + verbs: + - get + - list +- apiGroups: ["apps.cozystack.io"] + resources: + - buckets + - clickhouses + - foos + - foundationdbs + - harbors + - httpcaches + - kafkas + - kuberneteses + - mariadbs + - mongodbs + - natses + - openbaos + - opensearches + - postgreses + - qdrants + - rabbitmqs + - redises + - seaweedfses + - tcpbalancers + - virtualmachines + - vmdisks + - vminstances + - vpns + - infos + - virtualprivateclouds + verbs: + - create + - update + - patch + - delete +--- +# == super admin cluster role == +# Aggregates admin + all roles labeled for super-admin access +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cozy:tenant:super-admin +aggregationRule: + clusterRoleSelectors: + - matchLabels: + rbac.cozystack.io/aggregate-to-tenant-super-admin: "true" +rules: [] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cozy:tenant:super-admin:base + labels: + rbac.cozystack.io/aggregate-to-tenant-super-admin: "true" +rules: +- apiGroups: ["kubevirt.io"] + resources: + - virtualmachines + verbs: + - '*' +- apiGroups: ["apps.cozystack.io"] + resources: + - '*' + verbs: + - '*' diff --git a/packages/system/cozystack-basics/templates/cozy-public.yaml b/packages/system/cozystack-basics/templates/cozy-public.yaml new file mode 100644 index 00000000..b76816b4 --- /dev/null +++ b/packages/system/cozystack-basics/templates/cozy-public.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: cozy-public diff --git a/packages/system/cozystack-basics/templates/cozystack-values-secret.yaml b/packages/system/cozystack-basics/templates/cozystack-values-secret.yaml new file mode 100644 index 00000000..8c0d1c7a --- /dev/null +++ b/packages/system/cozystack-basics/templates/cozystack-values-secret.yaml @@ -0,0 +1,20 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: cozystack-values + namespace: tenant-root + labels: + reconcile.fluxcd.io/watch: Enabled + internal.cozystack.io/managed-by-cozystack: "" +type: Opaque +stringData: + values.yaml: | + _cluster: + {{- .Values._cluster | toYaml | nindent 6 }} + _namespace: + host: {{ index .Values._cluster "root-host" | quote }} + etcd: tenant-root + ingress: tenant-root + monitoring: tenant-root + seaweedfs: tenant-root diff --git a/packages/system/cozystack-basics/templates/dashboard-role.yaml b/packages/system/cozystack-basics/templates/dashboard-role.yaml new file mode 100644 index 00000000..f7656319 --- /dev/null +++ b/packages/system/cozystack-basics/templates/dashboard-role.yaml @@ -0,0 +1,15 @@ +--- +# == dashboard role == +# Single namespaced role for tenant dashboard access to helm resources +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: cozy:tenant:dashboard + namespace: cozy-public +rules: +- apiGroups: ["source.toolkit.fluxcd.io"] + resources: ["helmrepositories"] + verbs: ["get", "list"] +- apiGroups: ["source.toolkit.fluxcd.io"] + resources: ["helmcharts"] + verbs: ["get", "list"] diff --git a/packages/system/cozystack-basics/templates/monitoring-external-services.yaml b/packages/system/cozystack-basics/templates/monitoring-external-services.yaml new file mode 100644 index 00000000..e36540c4 --- /dev/null +++ b/packages/system/cozystack-basics/templates/monitoring-external-services.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: vlinsert-generic + namespace: cozy-monitoring +spec: + type: ExternalName + externalName: vlinsert-generic.tenant-root.svc.cluster.local +--- +apiVersion: v1 +kind: Service +metadata: + name: vminsert-shortterm + namespace: cozy-monitoring +spec: + type: ExternalName + externalName: vminsert-shortterm.tenant-root.svc.cluster.local +--- +apiVersion: v1 +kind: Service +metadata: + name: vminsert-longterm + namespace: cozy-monitoring +spec: + type: ExternalName + externalName: vminsert-longterm.tenant-root.svc.cluster.local diff --git a/packages/system/cozystack-basics/templates/tenant-root.yaml b/packages/system/cozystack-basics/templates/tenant-root.yaml new file mode 100644 index 00000000..93f5129e --- /dev/null +++ b/packages/system/cozystack-basics/templates/tenant-root.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: tenant-root +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + annotations: + helm.sh/resource-policy: keep + labels: + sharding.fluxcd.io/key: tenants + apps.cozystack.io/application.kind: Tenant + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.name: tenant-root + name: tenant-root + namespace: tenant-root +spec: + chartRef: + kind: ExternalArtifact + name: cozystack-tenant-application-default-tenant + namespace: cozy-system + interval: 1m0s + timeout: 5m0s + valuesFrom: + - kind: Secret + name: cozystack-values diff --git a/packages/system/cozystack-basics/values.yaml b/packages/system/cozystack-basics/values.yaml new file mode 100644 index 00000000..b8b5e457 --- /dev/null +++ b/packages/system/cozystack-basics/values.yaml @@ -0,0 +1 @@ +_cluster: {} diff --git a/packages/system/cozystack-controller/Makefile b/packages/system/cozystack-controller/Makefile index a75faea9..d1cc1871 100644 --- a/packages/system/cozystack-controller/Makefile +++ b/packages/system/cozystack-controller/Makefile @@ -1,27 +1,19 @@ NAME=cozystack-controller NAMESPACE=cozy-system -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk -image: image-cozystack-controller update-version +image: image-cozystack-controller image-cozystack-controller: docker buildx build -f images/cozystack-controller/Dockerfile ../../.. \ - --provenance false \ - --builder=$(BUILDER) \ - --platform=$(PLATFORM) \ --tag $(REGISTRY)/cozystack-controller:$(call settag,$(TAG)) \ + --build-arg VERSION=$(call settag,$(TAG)) \ --cache-from type=registry,ref=$(REGISTRY)/cozystack-controller:latest \ --cache-to type=inline \ --metadata-file images/cozystack-controller.json \ - --push=$(PUSH) \ - --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ - --load=$(LOAD) + $(BUILDX_ARGS) IMAGE="$(REGISTRY)/cozystack-controller:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/cozystack-controller.json -o json -r)" \ yq -i '.cozystackController.image = strenv(IMAGE)' values.yaml rm -f images/cozystack-controller.json - -update-version: - TAG="$(call settag,$(TAG))" \ - yq -i '.cozystackController.cozystackVersion = strenv(TAG)' values.yaml diff --git a/packages/system/cozystack-controller/templates/crds/cozystack.io_workloadmonitors.yaml b/packages/system/cozystack-controller/definitions/cozystack.io_workloadmonitors.yaml similarity index 100% rename from packages/system/cozystack-controller/templates/crds/cozystack.io_workloadmonitors.yaml rename to packages/system/cozystack-controller/definitions/cozystack.io_workloadmonitors.yaml diff --git a/packages/system/cozystack-controller/templates/crds/cozystack.io_workloads.yaml b/packages/system/cozystack-controller/definitions/cozystack.io_workloads.yaml similarity index 100% rename from packages/system/cozystack-controller/templates/crds/cozystack.io_workloads.yaml rename to packages/system/cozystack-controller/definitions/cozystack.io_workloads.yaml diff --git a/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_breadcrumbs.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_breadcrumbs.yaml new file mode 100644 index 00000000..8ea3a23a --- /dev/null +++ b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_breadcrumbs.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: breadcrumbs.dashboard.cozystack.io +spec: + group: dashboard.cozystack.io + names: + kind: Breadcrumb + listKind: BreadcrumbList + plural: breadcrumbs + singular: breadcrumb + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ArbitrarySpec holds schemaless user data and preserves unknown fields. + We map the entire .spec to a single JSON payload to mirror the CRDs you provided. + NOTE: Using apiextensionsv1.JSON avoids losing arbitrary structure during round-trips. + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: CommonStatus is a generic Status block with Kubernetes conditions. + properties: + conditions: + description: Conditions represent the latest available observations + of an object's state. + 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 + type: array + observedGeneration: + description: ObservedGeneration reflects the most recent generation + observed by the controller. + format: int64 + type: integer + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_breadcrumbsinside.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_breadcrumbsinside.yaml new file mode 100644 index 00000000..3124ec1a --- /dev/null +++ b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_breadcrumbsinside.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: breadcrumbsinside.dashboard.cozystack.io +spec: + group: dashboard.cozystack.io + names: + kind: BreadcrumbInside + listKind: BreadcrumbInsideList + plural: breadcrumbsinside + singular: breadcrumbinside + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ArbitrarySpec holds schemaless user data and preserves unknown fields. + We map the entire .spec to a single JSON payload to mirror the CRDs you provided. + NOTE: Using apiextensionsv1.JSON avoids losing arbitrary structure during round-trips. + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: CommonStatus is a generic Status block with Kubernetes conditions. + properties: + conditions: + description: Conditions represent the latest available observations + of an object's state. + 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 + type: array + observedGeneration: + description: ObservedGeneration reflects the most recent generation + observed by the controller. + format: int64 + type: integer + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_cfomappings.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_cfomappings.yaml new file mode 100644 index 00000000..a46f6a23 --- /dev/null +++ b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_cfomappings.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: cfomappings.dashboard.cozystack.io +spec: + group: dashboard.cozystack.io + names: + kind: CFOMapping + listKind: CFOMappingList + plural: cfomappings + singular: cfomapping + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ArbitrarySpec holds schemaless user data and preserves unknown fields. + We map the entire .spec to a single JSON payload to mirror the CRDs you provided. + NOTE: Using apiextensionsv1.JSON avoids losing arbitrary structure during round-trips. + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: CommonStatus is a generic Status block with Kubernetes conditions. + properties: + conditions: + description: Conditions represent the latest available observations + of an object's state. + 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 + type: array + observedGeneration: + description: ObservedGeneration reflects the most recent generation + observed by the controller. + format: int64 + type: integer + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_customcolumnsoverrides.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_customcolumnsoverrides.yaml new file mode 100644 index 00000000..44e6392c --- /dev/null +++ b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_customcolumnsoverrides.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: customcolumnsoverrides.dashboard.cozystack.io +spec: + group: dashboard.cozystack.io + names: + kind: CustomColumnsOverride + listKind: CustomColumnsOverrideList + plural: customcolumnsoverrides + singular: customcolumnsoverride + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ArbitrarySpec holds schemaless user data and preserves unknown fields. + We map the entire .spec to a single JSON payload to mirror the CRDs you provided. + NOTE: Using apiextensionsv1.JSON avoids losing arbitrary structure during round-trips. + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: CommonStatus is a generic Status block with Kubernetes conditions. + properties: + conditions: + description: Conditions represent the latest available observations + of an object's state. + 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 + type: array + observedGeneration: + description: ObservedGeneration reflects the most recent generation + observed by the controller. + format: int64 + type: integer + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_customformsoverrides.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_customformsoverrides.yaml new file mode 100644 index 00000000..0f4d927f --- /dev/null +++ b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_customformsoverrides.yaml @@ -0,0 +1,120 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: customformsoverrides.dashboard.cozystack.io +spec: + group: dashboard.cozystack.io + names: + kind: CustomFormsOverride + listKind: CustomFormsOverrideList + plural: customformsoverrides + shortNames: + - cfo + singular: customformsoverride + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ArbitrarySpec holds schemaless user data and preserves unknown fields. + We map the entire .spec to a single JSON payload to mirror the CRDs you provided. + NOTE: Using apiextensionsv1.JSON avoids losing arbitrary structure during round-trips. + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: CommonStatus is a generic Status block with Kubernetes conditions. + properties: + conditions: + description: Conditions represent the latest available observations + of an object's state. + 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 + type: array + observedGeneration: + description: ObservedGeneration reflects the most recent generation + observed by the controller. + format: int64 + type: integer + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_customformsprefills.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_customformsprefills.yaml new file mode 100644 index 00000000..ef43df11 --- /dev/null +++ b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_customformsprefills.yaml @@ -0,0 +1,120 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: customformsprefills.dashboard.cozystack.io +spec: + group: dashboard.cozystack.io + names: + kind: CustomFormsPrefill + listKind: CustomFormsPrefillList + plural: customformsprefills + shortNames: + - cfp + singular: customformsprefill + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ArbitrarySpec holds schemaless user data and preserves unknown fields. + We map the entire .spec to a single JSON payload to mirror the CRDs you provided. + NOTE: Using apiextensionsv1.JSON avoids losing arbitrary structure during round-trips. + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: CommonStatus is a generic Status block with Kubernetes conditions. + properties: + conditions: + description: Conditions represent the latest available observations + of an object's state. + 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 + type: array + observedGeneration: + description: ObservedGeneration reflects the most recent generation + observed by the controller. + format: int64 + type: integer + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_factories.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_factories.yaml new file mode 100644 index 00000000..4c902d7a --- /dev/null +++ b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_factories.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: factories.dashboard.cozystack.io +spec: + group: dashboard.cozystack.io + names: + kind: Factory + listKind: FactoryList + plural: factories + singular: factory + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ArbitrarySpec holds schemaless user data and preserves unknown fields. + We map the entire .spec to a single JSON payload to mirror the CRDs you provided. + NOTE: Using apiextensionsv1.JSON avoids losing arbitrary structure during round-trips. + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: CommonStatus is a generic Status block with Kubernetes conditions. + properties: + conditions: + description: Conditions represent the latest available observations + of an object's state. + 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 + type: array + observedGeneration: + description: ObservedGeneration reflects the most recent generation + observed by the controller. + format: int64 + type: integer + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_marketplacepanels.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_marketplacepanels.yaml new file mode 100644 index 00000000..161366bf --- /dev/null +++ b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_marketplacepanels.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: marketplacepanels.dashboard.cozystack.io +spec: + group: dashboard.cozystack.io + names: + kind: MarketplacePanel + listKind: MarketplacePanelList + plural: marketplacepanels + singular: marketplacepanel + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ArbitrarySpec holds schemaless user data and preserves unknown fields. + We map the entire .spec to a single JSON payload to mirror the CRDs you provided. + NOTE: Using apiextensionsv1.JSON avoids losing arbitrary structure during round-trips. + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: CommonStatus is a generic Status block with Kubernetes conditions. + properties: + conditions: + description: Conditions represent the latest available observations + of an object's state. + 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 + type: array + observedGeneration: + description: ObservedGeneration reflects the most recent generation + observed by the controller. + format: int64 + type: integer + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_navigations.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_navigations.yaml new file mode 100644 index 00000000..61fd0d13 --- /dev/null +++ b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_navigations.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: navigations.dashboard.cozystack.io +spec: + group: dashboard.cozystack.io + names: + kind: Navigation + listKind: NavigationList + plural: navigations + singular: navigation + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ArbitrarySpec holds schemaless user data and preserves unknown fields. + We map the entire .spec to a single JSON payload to mirror the CRDs you provided. + NOTE: Using apiextensionsv1.JSON avoids losing arbitrary structure during round-trips. + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: CommonStatus is a generic Status block with Kubernetes conditions. + properties: + conditions: + description: Conditions represent the latest available observations + of an object's state. + 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 + type: array + observedGeneration: + description: ObservedGeneration reflects the most recent generation + observed by the controller. + format: int64 + type: integer + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_sidebars.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_sidebars.yaml new file mode 100644 index 00000000..abc3fc49 --- /dev/null +++ b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_sidebars.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: sidebars.dashboard.cozystack.io +spec: + group: dashboard.cozystack.io + names: + kind: Sidebar + listKind: SidebarList + plural: sidebars + singular: sidebar + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ArbitrarySpec holds schemaless user data and preserves unknown fields. + We map the entire .spec to a single JSON payload to mirror the CRDs you provided. + NOTE: Using apiextensionsv1.JSON avoids losing arbitrary structure during round-trips. + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: CommonStatus is a generic Status block with Kubernetes conditions. + properties: + conditions: + description: Conditions represent the latest available observations + of an object's state. + 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 + type: array + observedGeneration: + description: ObservedGeneration reflects the most recent generation + observed by the controller. + format: int64 + type: integer + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_tableurimappings.yaml b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_tableurimappings.yaml new file mode 100644 index 00000000..19a4c451 --- /dev/null +++ b/packages/system/cozystack-controller/definitions/dashboard.cozystack.io_tableurimappings.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: tableurimappings.dashboard.cozystack.io +spec: + group: dashboard.cozystack.io + names: + kind: TableUriMapping + listKind: TableUriMappingList + plural: tableurimappings + singular: tableurimapping + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + ArbitrarySpec holds schemaless user data and preserves unknown fields. + We map the entire .spec to a single JSON payload to mirror the CRDs you provided. + NOTE: Using apiextensionsv1.JSON avoids losing arbitrary structure during round-trips. + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: CommonStatus is a generic Status block with Kubernetes conditions. + properties: + conditions: + description: Conditions represent the latest available observations + of an object's state. + 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 + type: array + observedGeneration: + description: ObservedGeneration reflects the most recent generation + observed by the controller. + format: int64 + type: integer + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile b/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile index c7ada9ef..ea475317 100644 --- a/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile +++ b/packages/system/cozystack-controller/images/cozystack-controller/Dockerfile @@ -1,7 +1,8 @@ -FROM golang:1.24-alpine AS builder +FROM golang:1.25-alpine AS builder ARG TARGETOS ARG TARGETARCH +ARG VERSION=dev WORKDIR /workspace @@ -13,7 +14,9 @@ COPY pkg pkg/ COPY cmd cmd/ COPY internal internal/ -RUN GOOS=$TARGETOS GOARCH=$TARGETARCH 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 -X github.com/cozystack/cozystack/pkg/version.Version=${VERSION}" \ + -o /cozystack-controller cmd/cozystack-controller/main.go FROM scratch diff --git a/packages/system/cozystack-controller/templates/crds/crds.yaml b/packages/system/cozystack-controller/templates/crds/crds.yaml new file mode 100644 index 00000000..2cf3183b --- /dev/null +++ b/packages/system/cozystack-controller/templates/crds/crds.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "definitions/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/cozystack-controller/templates/deployment.yaml b/packages/system/cozystack-controller/templates/deployment.yaml index 33b309df..aab7bbe1 100644 --- a/packages/system/cozystack-controller/templates/deployment.yaml +++ b/packages/system/cozystack-controller/templates/deployment.yaml @@ -2,7 +2,6 @@ apiVersion: apps/v1 kind: Deployment metadata: name: cozystack-controller - namespace: cozy-system labels: app: cozystack-controller spec: @@ -20,7 +19,6 @@ spec: - name: cozystack-controller image: "{{ .Values.cozystackController.image }}" args: - - --cozystack-version={{ .Values.cozystackController.cozystackVersion }} {{- if .Values.cozystackController.debug }} - --zap-log-level=debug {{- else }} diff --git a/packages/system/cozystack-controller/templates/rbac.yaml b/packages/system/cozystack-controller/templates/rbac.yaml index eb680f70..9ef8970a 100644 --- a/packages/system/cozystack-controller/templates/rbac.yaml +++ b/packages/system/cozystack-controller/templates/rbac.yaml @@ -3,10 +3,7 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: cozystack-controller rules: -- apiGroups: [""] - resources: ["configmaps", "pods", "namespaces", "nodes", "services", "persistentvolumes", "persistentvolumeclaims"] - verbs: ["get", "watch", "list"] -- apiGroups: ['cozystack.io'] +- apiGroups: ['cozystack.io', 'dashboard.cozystack.io'] resources: ['*'] verbs: ['*'] - apiGroups: ["helm.toolkit.fluxcd.io"] @@ -15,3 +12,6 @@ rules: - apiGroups: [""] resources: ["namespaces"] verbs: ["get", "list", "watch", "patch", "update"] +- apiGroups: ['*'] + resources: ['*'] + verbs: ["get", "list", "watch"] diff --git a/packages/system/cozystack-controller/templates/role.yaml b/packages/system/cozystack-controller/templates/role.yaml new file mode 100644 index 00000000..734ba95b --- /dev/null +++ b/packages/system/cozystack-controller/templates/role.yaml @@ -0,0 +1,25 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: cozystack-controller-deployment-patch-update + namespace: cozy-system +rules: +- apiGroups: ["apps"] + resources: ["deployments", "daemonsets"] + resourceNames: ["cozystack-api"] + verbs: ["patch", "update"] + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: cozystack-controller-deployment-patch-update + namespace: cozy-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: cozystack-controller-deployment-patch-update +subjects: +- kind: ServiceAccount + name: cozystack-controller + namespace: cozy-system diff --git a/packages/system/cozystack-controller/values.yaml b/packages/system/cozystack-controller/values.yaml index 44689fe9..4d0d0fde 100644 --- a/packages/system/cozystack-controller/values.yaml +++ b/packages/system/cozystack-controller/values.yaml @@ -1,5 +1,4 @@ cozystackController: - image: ghcr.io/cozystack/cozystack/cozystack-controller:v0.33.2@sha256:34e641b1bda248c254bbf259450d6ccad6ef632b92d28f3a6da4bbfde7983335 + image: ghcr.io/cozystack/cozystack/cozystack-controller:v1.3.0@sha256:d03d19b78c4c98f970ac549a68b01ef6bd1ad755f5e0dcb9e08503511cdf2fdc debug: false disableTelemetry: false - cozystackVersion: "v0.33.2" diff --git a/packages/system/cozystack-scheduler/Chart.yaml b/packages/system/cozystack-scheduler/Chart.yaml new file mode 100644 index 00000000..f2dd13ee --- /dev/null +++ b/packages/system/cozystack-scheduler/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-cozystack-scheduler +version: 0.3.0 diff --git a/packages/system/cozystack-scheduler/Makefile b/packages/system/cozystack-scheduler/Makefile new file mode 100644 index 00000000..d075ec63 --- /dev/null +++ b/packages/system/cozystack-scheduler/Makefile @@ -0,0 +1,14 @@ +export NAME=cozystack-scheduler +export NAMESPACE=kube-system + +include ../../../hack/package.mk + +test: + helm unittest . + +update: + rm -rf charts + tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/cozystack/cozystack-scheduler | awk -F'[/^]' 'END{print $$3}') && \ + mkdir -p charts/cozystack-scheduler && \ + curl -sSL https://github.com/cozystack/cozystack-scheduler/archive/refs/tags/$${tag}.tar.gz | \ + tar xzvf - --strip 2 -C charts/cozystack-scheduler cozystack-scheduler-$${tag#*v}/chart diff --git a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/Chart.yaml b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/Chart.yaml new file mode 100644 index 00000000..f2dd13ee --- /dev/null +++ b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-cozystack-scheduler +version: 0.3.0 diff --git a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/crds/cozystack.io_schedulingclasses.yaml b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/crds/cozystack.io_schedulingclasses.yaml new file mode 100644 index 00000000..d6b60d8b --- /dev/null +++ b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/crds/cozystack.io_schedulingclasses.yaml @@ -0,0 +1,1123 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + name: schedulingclasses.cozystack.io +spec: + group: cozystack.io + names: + kind: SchedulingClass + listKind: SchedulingClassList + plural: schedulingclasses + singular: schedulingclass + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + nodeAffinity: + description: Node affinity is a group of node affinity scheduling + rules. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding + weight. + properties: + matchExpressions: + description: A list of node selector requirements by + node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by + node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding + nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The + terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by + node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by + node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podAffinity: + description: Pod affinity is a group of inter pod affinity scheduling + rules. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with + the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Pod anti affinity is a group of inter pod anti affinity + scheduling rules. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with + the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + topologySpreadConstraints: + items: + description: TopologySpreadConstraint specifies how to spread matching + pods among the given topology. + properties: + labelSelector: + description: |- + LabelSelector is used to find matching pods. + Pods that match this label selector are counted to determine the number of pods + in their corresponding topology domain. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select the pods over which + spreading will be calculated. The keys are used to lookup values from the + incoming pod labels, those key-value labels are ANDed with labelSelector + to select the group of existing pods over which spreading will be calculated + for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + MatchLabelKeys cannot be set when LabelSelector isn't set. + Keys that don't exist in the incoming pod labels will + be ignored. A null or empty list means only match against labelSelector. + + This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + description: |- + MaxSkew describes the degree to which pods may be unevenly distributed. + When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference + between the number of matching pods in the target topology and the global minimum. + The global minimum is the minimum number of matching pods in an eligible domain + or zero if the number of eligible domains is less than MinDomains. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 2/2/1: + In this case, the global minimum is 1. + | zone1 | zone2 | zone3 | + | P P | P P | P | + - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; + scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) + violate MaxSkew(1). + - if MaxSkew is 2, incoming pod can be scheduled onto any zone. + When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence + to topologies that satisfy it. + It's a required field. Default value is 1 and 0 is not allowed. + format: int32 + type: integer + minDomains: + description: |- + MinDomains indicates a minimum number of eligible domains. + When the number of eligible domains with matching topology keys is less than minDomains, + Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. + And when the number of eligible domains with matching topology keys equals or greater than minDomains, + this value has no effect on scheduling. + As a result, when the number of eligible domains is less than minDomains, + scheduler won't schedule more than maxSkew Pods to those domains. + If value is nil, the constraint behaves as if MinDomains is equal to 1. + Valid values are integers greater than 0. + When value is not nil, WhenUnsatisfiable must be DoNotSchedule. + + For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same + labelSelector spread as 2/2/2: + | zone1 | zone2 | zone3 | + | P P | P P | P P | + The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. + In this situation, new pod with the same labelSelector cannot be scheduled, + because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, + it will violate MaxSkew. + format: int32 + type: integer + nodeAffinityPolicy: + description: |- + NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector + when calculating pod topology spread skew. Options are: + - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. + - 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. + type: string + nodeTaintsPolicy: + description: |- + NodeTaintsPolicy indicates how we will treat node taints when calculating + pod topology spread skew. Options are: + - Honor: nodes without taints, along with tainted nodes for which the incoming pod + has a toleration, are included. + - Ignore: node taints are ignored. All nodes are included. + + If this value is nil, the behavior is equivalent to the Ignore policy. + type: string + topologyKey: + description: |- + TopologyKey is the key of node labels. Nodes that have a label with this key + and identical values are considered to be in the same topology. + We consider each as a "bucket", and try to put balanced number + of pods into each bucket. + We define a domain as a particular instance of a topology. + Also, we define an eligible domain as a domain whose nodes meet the requirements of + nodeAffinityPolicy and nodeTaintsPolicy. + e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. + And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. + It's a required field. + type: string + whenUnsatisfiable: + description: |- + WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy + the spread constraint. + - DoNotSchedule (default) tells the scheduler not to schedule it. + - ScheduleAnyway tells the scheduler to schedule the pod in any location, + but giving higher precedence to topologies that would help reduce the + skew. + A constraint is considered "Unsatisfiable" for an incoming pod + if and only if every possible node assignment for that pod would violate + "MaxSkew" on some topology. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 3/1/1: + | zone1 | zone2 | zone3 | + | P P P | P | P | + If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled + to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies + MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler + won't make it *more* imbalanced. + It's a required field. + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + type: object + type: object + served: true + storage: true diff --git a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/clusterrole.yaml b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/clusterrole.yaml new file mode 100644 index 00000000..22f196a5 --- /dev/null +++ b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/clusterrole.yaml @@ -0,0 +1,9 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cozystack-scheduler +rules: + - apiGroups: ["cozystack.io"] + resources: + - schedulingclasses + verbs: ["get", "list", "watch"] diff --git a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/clusterrolebinding.yaml b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/clusterrolebinding.yaml new file mode 100644 index 00000000..00fcd968 --- /dev/null +++ b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/clusterrolebinding.yaml @@ -0,0 +1,38 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cozystack-scheduler:kube-scheduler +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:kube-scheduler +subjects: + - kind: ServiceAccount + name: cozystack-scheduler + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cozystack-scheduler:volume-scheduler +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:volume-scheduler +subjects: + - kind: ServiceAccount + name: cozystack-scheduler + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cozystack-scheduler +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cozystack-scheduler +subjects: + - kind: ServiceAccount + name: cozystack-scheduler + namespace: {{ .Release.Namespace }} diff --git a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/configmap.yaml b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/configmap.yaml new file mode 100644 index 00000000..24e0bc6f --- /dev/null +++ b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/configmap.yaml @@ -0,0 +1,58 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: cozystack-scheduler-config + namespace: {{ .Release.Namespace }} +data: + scheduler-config.yaml: | + apiVersion: kubescheduler.config.k8s.io/v1 + kind: KubeSchedulerConfiguration + leaderElection: + leaderElect: true + resourceNamespace: {{ .Release.Namespace }} + resourceName: cozystack-scheduler + profiles: + - schedulerName: cozystack-scheduler + plugins: + preFilter: + disabled: + - name: InterPodAffinity + - name: NodeAffinity + - name: PodTopologySpread + enabled: + - name: CozystackInterPodAffinity + - name: CozystackNodeAffinity + - name: CozystackPodTopologySpread + - name: CozystackSchedulingClass + filter: + disabled: + - name: InterPodAffinity + - name: NodeAffinity + - name: PodTopologySpread + enabled: + - name: CozystackInterPodAffinity + - name: CozystackNodeAffinity + - name: CozystackPodTopologySpread + - name: CozystackSchedulingClass + preScore: + disabled: + - name: InterPodAffinity + - name: NodeAffinity + - name: PodTopologySpread + enabled: + - name: CozystackInterPodAffinity + - name: CozystackNodeAffinity + - name: CozystackPodTopologySpread + score: + disabled: + - name: InterPodAffinity + - name: NodeAffinity + - name: PodTopologySpread + enabled: + - name: CozystackInterPodAffinity + - name: CozystackNodeAffinity + - name: CozystackPodTopologySpread + {{- with .Values.extenders }} + extenders: + {{- toYaml . | nindent 6 }} + {{- end }} diff --git a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/deployment.yaml b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/deployment.yaml new file mode 100644 index 00000000..0365f0de --- /dev/null +++ b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/deployment.yaml @@ -0,0 +1,40 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cozystack-scheduler + namespace: {{ .Release.Namespace }} +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: cozystack-scheduler + template: + metadata: + labels: + app: cozystack-scheduler + spec: + serviceAccountName: cozystack-scheduler + containers: + - name: cozystack-scheduler + image: {{ .Values.image }} + command: + - /cozystack-scheduler + - --config=/etc/kubernetes/scheduler-config.yaml + {{- with .Values.defaultLabelSelectorKeys }} + - --default-label-selector-keys={{ join "," . }} + {{- end }} + livenessProbe: + httpGet: + path: /healthz + port: 10259 + scheme: HTTPS + initialDelaySeconds: 15 + volumeMounts: + - name: config + mountPath: /etc/kubernetes/scheduler-config.yaml + subPath: scheduler-config.yaml + readOnly: true + volumes: + - name: config + configMap: + name: cozystack-scheduler-config diff --git a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/rolebinding.yaml b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/rolebinding.yaml new file mode 100644 index 00000000..796bf55c --- /dev/null +++ b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/rolebinding.yaml @@ -0,0 +1,40 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: cozystack-scheduler:extension-apiserver-authentication-reader + namespace: kube-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: extension-apiserver-authentication-reader +subjects: + - kind: ServiceAccount + name: cozystack-scheduler + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: cozystack-scheduler:leader-election + namespace: {{ .Release.Namespace }} +rules: + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["create", "get", "list", "update", "watch"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leasecandidates"] + verbs: ["create", "get", "list", "update", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: cozystack-scheduler:leader-election + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: cozystack-scheduler:leader-election +subjects: + - kind: ServiceAccount + name: cozystack-scheduler + namespace: {{ .Release.Namespace }} diff --git a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/serviceaccount.yaml b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/serviceaccount.yaml new file mode 100644 index 00000000..876e5f01 --- /dev/null +++ b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/templates/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: cozystack-scheduler + namespace: {{ .Release.Namespace }} diff --git a/packages/system/cozystack-scheduler/charts/cozystack-scheduler/values.yaml b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/values.yaml new file mode 100644 index 00000000..55b6faff --- /dev/null +++ b/packages/system/cozystack-scheduler/charts/cozystack-scheduler/values.yaml @@ -0,0 +1,23 @@ +image: ghcr.io/cozystack/cozystack/cozystack-scheduler:v0.3.0@sha256:89c285c5c5fe3ed8d7d597acf32fc9f045394e0f8efafd1878d6080cf112f6c2 +replicas: 1 +# defaultLabelSelectorKeys overrides the pod label keys used to auto-populate +# nil LabelSelectors in SchedulingClass affinity and topology spread terms. +# When empty or unset, the binary defaults are used: +# - apps.cozystack.io/application.group +# - apps.cozystack.io/application.kind +# - apps.cozystack.io/application.name +# defaultLabelSelectorKeys: [] + +# extenders is a list of scheduler extenders to call during the scheduling cycle. +# Each entry is passed directly into KubeSchedulerConfiguration.extenders[]. +# Example: +# extenders: +# - urlPrefix: http://linstor-scheduler-extender.cozy-linstor.svc:8099 +# filterVerb: filter +# prioritizeVerb: prioritize +# weight: 5 +# enableHTTPS: false +# httpTimeout: 10s +# nodeCacheCapable: false +# ignorable: true +extenders: [] diff --git a/packages/system/cozystack-scheduler/templates/tenant-clusterroles.yaml b/packages/system/cozystack-scheduler/templates/tenant-clusterroles.yaml new file mode 100644 index 00000000..a7b8fd21 --- /dev/null +++ b/packages/system/cozystack-scheduler/templates/tenant-clusterroles.yaml @@ -0,0 +1,18 @@ +--- +# == schedulingclass view cluster role == +# Aggregated into cozy-tenant-view (and consequently use, admin, super-admin) +# Provides read-only access to SchedulingClass resources +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cozy:schedulingclass:view + labels: + rbac.cozystack.io/aggregate-to-tenant-view: "true" +rules: +- apiGroups: ["cozystack.io"] + resources: + - schedulingclasses + verbs: + - get + - list + - watch diff --git a/packages/system/cozystack-scheduler/tests/configmap_test.yaml b/packages/system/cozystack-scheduler/tests/configmap_test.yaml new file mode 100644 index 00000000..ce8f372d --- /dev/null +++ b/packages/system/cozystack-scheduler/tests/configmap_test.yaml @@ -0,0 +1,26 @@ +suite: scheduler configmap tests + +templates: + - charts/cozy-cozystack-scheduler/templates/configmap.yaml + +tests: + - it: renders extenders when configured + values: + - ../values-linstor.yaml + asserts: + - isKind: + of: ConfigMap + - matchRegex: + path: data["scheduler-config.yaml"] + pattern: "urlPrefix: http://linstor-scheduler-extender" + - matchRegex: + path: data["scheduler-config.yaml"] + pattern: "ignorable: true" + + - it: omits extenders by default + asserts: + - isKind: + of: ConfigMap + - notMatchRegex: + path: data["scheduler-config.yaml"] + pattern: "extenders:" diff --git a/packages/system/cozystack-scheduler/values-linstor.yaml b/packages/system/cozystack-scheduler/values-linstor.yaml new file mode 100644 index 00000000..ab16ca57 --- /dev/null +++ b/packages/system/cozystack-scheduler/values-linstor.yaml @@ -0,0 +1,10 @@ +cozy-cozystack-scheduler: + extenders: + - urlPrefix: http://linstor-scheduler-extender.cozy-linstor.svc:8099 + filterVerb: filter + prioritizeVerb: prioritize + weight: 5 + enableHTTPS: false + httpTimeout: 10s + nodeCacheCapable: false + ignorable: true diff --git a/packages/system/dashboard/Makefile b/packages/system/dashboard/Makefile index 10df5382..a9f680a3 100644 --- a/packages/system/dashboard/Makefile +++ b/packages/system/dashboard/Makefile @@ -1,74 +1,70 @@ export NAME=dashboard export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk -update: update-chart update-dockerfiles -image: image-dashboard image-kubeapps-apis +update: update-crd update-dockerfiles +image: image-openapi-ui image-openapi-ui-k8s-bff image-token-proxy update-tenant-text -update-chart: - rm -rf charts - helm repo add bitnami https://charts.bitnami.com/bitnami - helm repo update bitnami - helm pull bitnami/kubeapps --untar --untardir charts - rm -rf charts/kubeapps/charts/postgresql/ - sed -i 's/.cluster.local//g' charts/kubeapps/templates/kubeappsapis/deployment.yaml - patch --no-backup-if-mismatch charts/kubeapps/templates/frontend/configmap.yaml < patches/logos.patch update-dockerfiles: @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}') && \ - sed -i "s|FROM .* AS build|FROM $${node_image} AS build|" images/dashboard/Dockerfile && \ - version=$$(echo "$$tag" | sed 's/^v//') && \ - sed -i "s/ARG VERSION=.*/ARG VERSION=$${version}/" images/dashboard/Dockerfile -image-dashboard: update-version - docker buildx build images/dashboard \ +update-crd: + rm -rf crds + mkdir -p crds + wget -O- https://github.com/PRO-Robotech/helmfile-manifests/archive/refs/heads/main.tar.gz | tar -C crds -xzvf- helmfile-manifests-main/charts/incloud-main/incloud-web-1.0.0/incloud-web/templates --strip-components=6 + rm -f crds/_helpers.tpl + sed -i '/{{/d' crds/*.yml crds/*.yaml + +image-openapi-ui: + docker buildx build images/openapi-ui \ --provenance false \ --builder=$(BUILDER) \ - --platform=$(PLATFORM) \ - --tag $(REGISTRY)/dashboard:$(call settag,$(TAG)) \ - --cache-from type=registry,ref=$(REGISTRY)/dashboard:latest \ + --platform=linux/amd64 \ + --tag $(REGISTRY)/openapi-ui:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/openapi-ui:latest \ --cache-to type=inline \ - --metadata-file images/dashboard.json \ + --metadata-file images/openapi-ui.json \ --push=$(PUSH) \ --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ --load=$(LOAD) - REGISTRY="$(REGISTRY)" \ - yq -i '.kubeapps.dashboard.image.registry = strenv(REGISTRY)' values.yaml - REPOSITORY="dashboard" \ - yq -i '.kubeapps.dashboard.image.repository = strenv(REPOSITORY)' values.yaml - TAG="$(call settag,$(TAG))" \ - yq -i '.kubeapps.dashboard.image.tag = strenv(TAG)' values.yaml - DIGEST=$$(yq e '."containerimage.digest"' images/dashboard.json -o json -r) \ - yq -i '.kubeapps.dashboard.image.digest = strenv(DIGEST)' values.yaml - rm -f images/dashboard.json + IMAGE="$(REGISTRY)/openapi-ui:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/openapi-ui.json -r)" \ + yq -i '.openapiUI.image = strenv(IMAGE)' values.yaml + rm -f images/openapi-ui.json -image-kubeapps-apis: update-version - docker buildx build images/kubeapps-apis \ +image-openapi-ui-k8s-bff: + docker buildx build images/openapi-ui-k8s-bff \ --provenance false \ --builder=$(BUILDER) \ - --platform=$(PLATFORM) \ - --tag $(REGISTRY)/kubeapps-apis:$(call settag,$(TAG)) \ - --cache-from type=registry,ref=$(REGISTRY)/kubeapps-apis:latest \ + --platform=linux/amd64 \ + --tag $(REGISTRY)/openapi-ui-k8s-bff:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/openapi-ui-k8s-bff:latest \ --cache-to type=inline \ - --metadata-file images/kubeapps-apis.json \ + --metadata-file images/openapi-ui-k8s-bff.json \ --push=$(PUSH) \ --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ --load=$(LOAD) - REGISTRY="$(REGISTRY)" \ - yq -i '.kubeapps.kubeappsapis.image.registry = strenv(REGISTRY)' values.yaml - REPOSITORY="kubeapps-apis" \ - yq -i '.kubeapps.kubeappsapis.image.repository = strenv(REPOSITORY)' values.yaml - TAG="$(call settag,$(TAG))" \ - yq -i '.kubeapps.kubeappsapis.image.tag = strenv(TAG)' values.yaml - DIGEST=$$(yq e '."containerimage.digest"' images/kubeapps-apis.json -o json -r) \ - yq -i '.kubeapps.kubeappsapis.image.digest = strenv(DIGEST)' values.yaml - rm -f images/kubeapps-apis.json + IMAGE="$(REGISTRY)/openapi-ui-k8s-bff:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/openapi-ui-k8s-bff.json -r)" \ + yq -i '.openapiUIK8sBff.image = strenv(IMAGE)' values.yaml + rm -f images/openapi-ui-k8s-bff.json -update-version: - sed -i "s|\(\"appVersion\":\).*|\1 \"$(TAG)\",|g" ./charts/kubeapps/templates/dashboard/configmap.yaml +image-token-proxy: + docker buildx build images/token-proxy \ + --provenance false \ + --builder=$(BUILDER) \ + --platform=linux/amd64 \ + --tag $(REGISTRY)/token-proxy:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/token-proxy:latest \ + --cache-to type=inline \ + --metadata-file images/token-proxy.json \ + --push=$(PUSH) \ + --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ + --load=$(LOAD) + IMAGE="$(REGISTRY)/token-proxy:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/token-proxy.json -r)" \ + yq -i '.tokenProxy.image = strenv(IMAGE)' values.yaml + rm -f images/token-proxy.json + +update-tenant-text: + sed -i 's|\($$tenantText := "\)[^"]\+|\1$(TAG)|' templates/configmap.yaml diff --git a/packages/system/dashboard/charts/kubeapps/Chart.lock b/packages/system/dashboard/charts/kubeapps/Chart.lock deleted file mode 100644 index 93e54bb9..00000000 --- a/packages/system/dashboard/charts/kubeapps/Chart.lock +++ /dev/null @@ -1,12 +0,0 @@ -dependencies: -- name: redis - repository: oci://registry-1.docker.io/bitnamicharts - version: 20.2.1 -- name: postgresql - repository: oci://registry-1.docker.io/bitnamicharts - version: 16.1.0 -- name: common - repository: oci://registry-1.docker.io/bitnamicharts - version: 2.26.0 -digest: sha256:8765098cabaca39ce13d856f5260df97667201dac6d2209280e5de9ad1a33006 -generated: "2024-10-31T19:49:51.754205675Z" diff --git a/packages/system/dashboard/charts/kubeapps/Chart.yaml b/packages/system/dashboard/charts/kubeapps/Chart.yaml deleted file mode 100644 index d0529f4e..00000000 --- a/packages/system/dashboard/charts/kubeapps/Chart.yaml +++ /dev/null @@ -1,54 +0,0 @@ -annotations: - category: Infrastructure - images: | - - name: kubeapps-apis - image: docker.io/bitnami/kubeapps-apis:2.12.0-debian-12-r0 - - name: kubeapps-apprepository-controller - image: docker.io/bitnami/kubeapps-apprepository-controller:2.12.0-debian-12-r0 - - name: kubeapps-asset-syncer - image: docker.io/bitnami/kubeapps-asset-syncer:2.12.0-debian-12-r0 - - name: kubeapps-dashboard - image: docker.io/bitnami/kubeapps-dashboard:2.12.0-debian-12-r0 - - name: kubeapps-oci-catalog - image: docker.io/bitnami/kubeapps-oci-catalog:2.12.0-debian-12-r0 - - name: kubeapps-pinniped-proxy - image: docker.io/bitnami/kubeapps-pinniped-proxy:2.12.0-debian-12-r0 - - name: nginx - image: docker.io/bitnami/nginx:1.27.2-debian-12-r2 - - name: oauth2-proxy - image: docker.io/bitnami/oauth2-proxy:7.7.1-debian-12-r1 - licenses: Apache-2.0 -apiVersion: v2 -appVersion: 2.12.0 -dependencies: -- condition: packaging.flux.enabled - name: redis - repository: oci://registry-1.docker.io/bitnamicharts - version: 20.x.x -- condition: packaging.helm.enabled - name: postgresql - repository: oci://registry-1.docker.io/bitnamicharts - version: 16.x.x -- name: common - repository: oci://registry-1.docker.io/bitnamicharts - tags: - - bitnami-common - version: 2.x.x -description: Kubeapps is a web-based UI for launching and managing applications on - Kubernetes. It allows users to deploy trusted applications and operators to control - users access to the cluster. -home: https://bitnami.com -icon: https://bitnami.com/assets/stacks/kubeapps/img/kubeapps-stack-220x234.png -keywords: -- helm -- dashboard -- service catalog -- deployment -kubeVersion: '>=1.21.0-0' -maintainers: -- name: Broadcom, Inc. All Rights Reserved. - url: https://github.com/bitnami/charts -name: kubeapps -sources: -- https://github.com/bitnami/charts/tree/main/bitnami/kubeapps -version: 17.0.3 diff --git a/packages/system/dashboard/charts/kubeapps/README.md b/packages/system/dashboard/charts/kubeapps/README.md deleted file mode 100644 index 14855b42..00000000 --- a/packages/system/dashboard/charts/kubeapps/README.md +++ /dev/null @@ -1,1220 +0,0 @@ - - -# Bitnami package for Kubeapps - -Kubeapps is a web-based UI for launching and managing applications on Kubernetes. It allows users to deploy trusted applications and operators to control users access to the cluster. - -[Overview of Kubeapps](https://github.com/vmware-tanzu/kubeapps) - -## TL;DR - -```console -helm install my-release oci://registry-1.docker.io/bitnamicharts/kubeapps --namespace kubeapps --create-namespace -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. -> Check out the [getting started](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/tutorials/getting-started.md) to start deploying apps with Kubeapps. - -Looking to use Kubeapps in production? Try [VMware Tanzu Application Catalog](https://bitnami.com/enterprise), the commercial edition of the Bitnami catalog. - -## Introduction - -This chart bootstraps a [Kubeapps](https://kubeapps.dev) deployment on a [Kubernetes](https://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. - -With Kubeapps you can: - -- Customize deployments through an intuitive, form-based user interface -- Inspect, upgrade and delete applications installed in the cluster -- Browse and deploy [Helm](https://github.com/helm/helm) charts from public or private chart repositories (including [VMware Marketplace™](https://marketplace.cloud.vmware.com) and [Bitnami Application Catalog](https://bitnami.com/application-catalog)) -- Browse and deploy [Kubernetes Operators](https://operatorhub.io/) -- Secure authentication to Kubeapps using a [standalone OAuth2/OIDC provider](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/tutorials/using-an-OIDC-provider.md) or [using Pinniped](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/howto/OIDC/using-an-OIDC-provider-with-pinniped.md) -- Secure authorization based on Kubernetes [Role-Based Access Control](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/howto/access-control.md) - -**_Note:_** Kubeapps 2.0 and onwards supports Helm 3 only. While only the Helm 3 API is supported, in most cases, charts made for Helm 2 will still work. - -It also packages the [Bitnami PostgreSQL chart](https://github.com/bitnami/charts/tree/main/bitnami/postgresql), which is required for bootstrapping a deployment for the database requirements of the Kubeapps application. - -## Prerequisites - -- Kubernetes 1.23+ -- Helm 3.8.0+ -- Administrative access to the cluster to create Custom Resource Definitions (CRDs) -- PV provisioner support in the underlying infrastructure (required for PostgreSQL database) - -## Installing the Chart - -To install the chart with the release name `my-release`: - -```console -helm install my-release oci://REGISTRY_NAME/REPOSITORY_NAME/kubeapps --namespace kubeapps --create-namespace -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -The command deploys Kubeapps on the Kubernetes cluster in the `kubeapps` namespace. The [Parameters](#parameters) section lists the parameters that can be configured during installation. - -> **Caveat**: Only one Kubeapps installation is supported per namespace - -Once you have installed Kubeapps follow the [Getting Started Guide](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/tutorials/getting-started.md) for additional information on how to access and use Kubeapps. - -## Configuration and installation details - -### Resource requests and limits - -Bitnami charts allow setting resource requests and limits for all containers inside the chart deployment. These are inside the `resources` value (check parameter table). Setting requests is essential for production workloads and these should be adapted to your specific use case. - -To make this process easier, the chart contains the `resourcesPreset` values, which automatically sets the `resources` section according to different presets. Check these presets in [the bitnami/common chart](https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15). However, in production workloads using `resourcePreset` is discouraged as it may not fully adapt to your specific needs. Find more information on container resource management in the [official Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). - -### Configuring Initial Repositories - -By default, Kubeapps will track the [Bitnami Application Catalog](https://github.com/bitnami/charts). To change these defaults, override with your desired parameters the `apprepository.initialRepos` object present in the [values.yaml](https://github.com/bitnami/charts/tree/main/bitnami/kubeapps/values.yaml) file. - -### Enabling Operators - -Since v1.9.0 (and by default since v2.0), Kubeapps supports deploying and managing Operators within its dashboard. More information about how to enable and use this feature can be found in [this guide](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/tutorials/operators.md). - -### Exposing Externally - -> **Note**: The Kubeapps frontend sets up a proxy to the Kubernetes API service which means that when exposing the Kubeapps service to a network external to the Kubernetes cluster (perhaps on an internal or public network), the Kubernetes API will also be exposed for authenticated requests from that network. It is highly recommended that you [use an OAuth2/OIDC provider with Kubeapps](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/tutorials/using-an-OIDC-provider.md) to ensure that your authentication proxy is exposed rather than the Kubeapps frontend. This ensures that only the configured users trusted by your Identity Provider will be able to reach the Kubeapps frontend and therefore the Kubernetes API. Kubernetes service token authentication should only be used for users for demonstration purposes only, not production environments. - -#### LoadBalancer Service - -The simplest way to expose the Kubeapps Dashboard is to assign a LoadBalancer type to the Kubeapps frontend Service. For example, you can use the following parameter: `frontend.service.type=LoadBalancer` - -Wait for your cluster to assign a LoadBalancer IP or Hostname to the `kubeapps` Service and access it on that address: - -```console -kubectl get services --namespace kubeapps --watch -``` - -#### Ingress - -This chart provides support for Ingress resources. If you have an ingress controller installed on your cluster, such as [nginx-ingress-controller](https://github.com/bitnami/charts/tree/main/bitnami/nginx-ingress-controller) or [contour](https://github.com/bitnami/charts/tree/main/bitnami/contour) you can utilize the ingress controller to serve your application. - -To enable ingress integration, please set `ingress.enabled` to `true` - -##### Hosts - -Most likely you will only want to have one hostname that maps to this Kubeapps installation (use the `ingress.hostname` parameter to set the hostname), however, it is possible to have more than one host. To facilitate this, the `ingress.extraHosts` object is an array. - -##### Annotations - -For annotations, please see [this document](https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md). Not all annotations are supported by all ingress controllers, but this document does a good job of indicating which annotation is supported by many popular ingress controllers. Annotations can be set using `ingress.annotations`. - -##### TLS - -This chart will facilitate the creation of TLS secrets for use with the ingress controller, however, this is not required. There are four common use cases: - -- Helm generates/manages certificate secrets based on the parameters. -- The user generates/manages certificates separately. -- Helm creates self-signed certificates and generates/manages certificate secrets. -- An additional tool (like [cert-manager](https://github.com/jetstack/cert-manager/)) manages the secrets for the application. - -In the first two cases, it is needed a certificate and a key. We would expect them to look like this: - -- certificate files should look like (and there can be more than one certificate if there is a certificate chain) - - ```console - -----BEGIN CERTIFICATE----- - MIID6TCCAtGgAwIBAgIJAIaCwivkeB5EMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV - ... - jScrvkiBO65F46KioCL9h5tDvomdU1aqpI/CBzhvZn1c0ZTf87tGQR8NK7v7 - -----END CERTIFICATE----- - ``` - -- keys should look like: - - ```console - -----BEGIN RSA PRIVATE KEY----- - MIIEogIBAAKCAQEAvLYcyu8f3skuRyUgeeNpeDvYBCDcgq+LsWap6zbX5f8oLqp4 - ... - wrj2wDbCDCFmfqnSJ+dKI3vFLlEz44sAV8jX/kd4Y6ZTQhlLbYc= - -----END RSA PRIVATE KEY----- - ``` - -- If you are going to use Helm to manage the certificates based on the parameters, please copy these values into the `certificate` and `key` values for a given `ingress.secrets` entry. -- In case you are going to manage TLS secrets separately, please know that you must use a TLS secret with name _INGRESS_HOSTNAME-tls_ (where _INGRESS_HOSTNAME_ is a placeholder to be replaced with the hostname you set using the `ingress.hostname` parameter). -- To use self-signed certificates created by Helm, set both `ingress.tls` and `ingress.selfSigned` to `true`. -- If your cluster has a [cert-manager](https://github.com/jetstack/cert-manager) add-on to automate the management and issuance of TLS certificates, set `ingress.certManager` boolean to true to enable the corresponding annotations for cert-manager. - -## Parameters - -### Global parameters - -| Name | Description | Value | -| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -| `global.imageRegistry` | Global Docker image registry | `""` | -| `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` | -| `global.defaultStorageClass` | Global default StorageClass for Persistent Volume(s) | `""` | -| `global.storageClass` | DEPRECATED: use global.defaultStorageClass instead | `""` | -| `global.compatibility.openshift.adaptSecurityContext` | Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation) | `auto` | - -### Common parameters - -| Name | Description | Value | -| ------------------------ | --------------------------------------------------------------------------------------- | -------------- | -| `kubeVersion` | Override Kubernetes version | `""` | -| `nameOverride` | String to partially override common.names.fullname | `""` | -| `fullnameOverride` | String to fully override common.names.fullname | `""` | -| `commonLabels` | Labels to add to all deployed objects | `{}` | -| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | -| `extraDeploy` | Array of extra objects to deploy with the release | `[]` | -| `enableIPv6` | Enable IPv6 configuration | `false` | -| `diagnosticMode.enabled` | Enable diagnostic mode (all probes will be disabled and the command will be overridden) | `false` | -| `diagnosticMode.command` | Command to override all containers in the deployment | `["sleep"]` | -| `diagnosticMode.args` | Args to override all containers in the deployment | `["infinity"]` | - -### Traffic Exposure Parameters - -| Name | Description | Value | -| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | -| `ingress.enabled` | Enable ingress record generation for Kubeapps | `false` | -| `ingress.apiVersion` | Force Ingress API version (automatically detected if not set) | `""` | -| `ingress.hostname` | Default host for the ingress record | `kubeapps.local` | -| `ingress.path` | Default path for the ingress record | `/` | -| `ingress.pathType` | Ingress path type | `ImplementationSpecific` | -| `ingress.annotations` | Additional annotations for the Ingress resource. To enable certificate autogeneration, place here your cert-manager annotations. | `{}` | -| `ingress.tls` | Enable TLS configuration for the host defined at `ingress.hostname` parameter | `false` | -| `ingress.selfSigned` | Create a TLS secret for this ingress record using self-signed certificates generated by Helm | `false` | -| `ingress.extraHosts` | An array with additional hostname(s) to be covered with the ingress record | `[]` | -| `ingress.extraPaths` | An array with additional arbitrary paths that may need to be added to the ingress under the main host | `[]` | -| `ingress.extraTls` | TLS configuration for additional hostname(s) to be covered with this ingress record | `[]` | -| `ingress.secrets` | Custom TLS certificates as secrets | `[]` | -| `ingress.ingressClassName` | IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) | `""` | -| `ingress.extraRules` | Additional rules to be covered with this ingress record | `[]` | - -### Kubeapps packaging options - -| Name | Description | Value | -| -------------------------- | ---------------------------------------------------------- | ------- | -| `packaging.helm.enabled` | Enable the standard Helm packaging. | `true` | -| `packaging.carvel.enabled` | Enable support for the Carvel (kapp-controller) packaging. | `false` | -| `packaging.flux.enabled` | Enable support for Flux (v2) packaging. | `false` | - -### Frontend parameters - -| Name | Description | Value | -| ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | -| `frontend.image.registry` | NGINX image registry | `REGISTRY_NAME` | -| `frontend.image.repository` | NGINX image repository | `REPOSITORY_NAME/nginx` | -| `frontend.image.digest` | NGINX image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | -| `frontend.image.pullPolicy` | NGINX image pull policy | `IfNotPresent` | -| `frontend.image.pullSecrets` | NGINX image pull secrets | `[]` | -| `frontend.image.debug` | Enable image debug mode | `false` | -| `frontend.proxypassAccessTokenAsBearer` | Use access_token as the Bearer when talking to the k8s api server | `false` | -| `frontend.proxypassExtraSetHeader` | Set an additional proxy header for all requests proxied via NGINX | `""` | -| `frontend.largeClientHeaderBuffers` | Set large_client_header_buffers in NGINX config | `4 32k` | -| `frontend.replicaCount` | Number of frontend replicas to deploy | `2` | -| `frontend.updateStrategy.type` | Frontend deployment strategy type. | `RollingUpdate` | -| `frontend.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if frontend.resources is set (frontend.resources is recommended for production). | `micro` | -| `frontend.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | -| `frontend.extraEnvVars` | Array with extra environment variables to add to the NGINX container | `[]` | -| `frontend.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for the NGINX container | `""` | -| `frontend.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for the NGINX container | `""` | -| `frontend.containerPorts.http` | NGINX HTTP container port | `8080` | -| `frontend.podSecurityContext.enabled` | Enabled frontend pods' Security Context | `true` | -| `frontend.podSecurityContext.fsGroupChangePolicy` | Set filesystem group change policy | `Always` | -| `frontend.podSecurityContext.sysctls` | Set kernel settings using the sysctl interface | `[]` | -| `frontend.podSecurityContext.supplementalGroups` | Set filesystem extra groups | `[]` | -| `frontend.podSecurityContext.fsGroup` | Set frontend pod's Security Context fsGroup | `1001` | -| `frontend.containerSecurityContext.enabled` | Enabled containers' Security Context | `true` | -| `frontend.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | -| `frontend.containerSecurityContext.runAsUser` | Set containers' Security Context runAsUser | `1001` | -| `frontend.containerSecurityContext.runAsGroup` | Set containers' Security Context runAsGroup | `1001` | -| `frontend.containerSecurityContext.runAsNonRoot` | Set container's Security Context runAsNonRoot | `true` | -| `frontend.containerSecurityContext.privileged` | Set container's Security Context privileged | `false` | -| `frontend.containerSecurityContext.readOnlyRootFilesystem` | Set container's Security Context readOnlyRootFilesystem | `true` | -| `frontend.containerSecurityContext.allowPrivilegeEscalation` | Set container's Security Context allowPrivilegeEscalation | `false` | -| `frontend.containerSecurityContext.capabilities.drop` | List of capabilities to be dropped | `["ALL"]` | -| `frontend.containerSecurityContext.seccompProfile.type` | Set container's Security Context seccomp profile | `RuntimeDefault` | -| `frontend.livenessProbe.enabled` | Enable livenessProbe | `true` | -| `frontend.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `60` | -| `frontend.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `10` | -| `frontend.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `5` | -| `frontend.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `6` | -| `frontend.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | -| `frontend.readinessProbe.enabled` | Enable readinessProbe | `true` | -| `frontend.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `0` | -| `frontend.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | -| `frontend.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `5` | -| `frontend.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `6` | -| `frontend.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | -| `frontend.startupProbe.enabled` | Enable startupProbe | `false` | -| `frontend.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `0` | -| `frontend.startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | -| `frontend.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `5` | -| `frontend.startupProbe.failureThreshold` | Failure threshold for startupProbe | `6` | -| `frontend.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | -| `frontend.customLivenessProbe` | Custom livenessProbe that overrides the default one | `{}` | -| `frontend.customReadinessProbe` | Custom readinessProbe that overrides the default one | `{}` | -| `frontend.customStartupProbe` | Custom startupProbe that overrides the default one | `{}` | -| `frontend.lifecycleHooks` | Custom lifecycle hooks for frontend containers | `{}` | -| `frontend.command` | Override default container command (useful when using custom images) | `[]` | -| `frontend.args` | Override default container args (useful when using custom images) | `[]` | -| `frontend.podLabels` | Extra labels for frontend pods | `{}` | -| `frontend.podAnnotations` | Annotations for frontend pods | `{}` | -| `frontend.podAffinityPreset` | Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `frontend.podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `soft` | -| `frontend.nodeAffinityPreset.type` | Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `frontend.nodeAffinityPreset.key` | Node label key to match. Ignored if `affinity` is set | `""` | -| `frontend.nodeAffinityPreset.values` | Node label values to match. Ignored if `affinity` is set | `[]` | -| `frontend.affinity` | Affinity for pod assignment | `{}` | -| `frontend.nodeSelector` | Node labels for pod assignment | `{}` | -| `frontend.tolerations` | Tolerations for pod assignment | `[]` | -| `frontend.priorityClassName` | Priority class name for frontend pods | `""` | -| `frontend.schedulerName` | Name of the k8s scheduler (other than default) | `""` | -| `frontend.topologySpreadConstraints` | Topology Spread Constraints for pod assignment | `[]` | -| `frontend.automountServiceAccountToken` | Mount Service Account token in pod | `true` | -| `frontend.hostAliases` | Custom host aliases for frontend pods | `[]` | -| `frontend.extraVolumes` | Optionally specify extra list of additional volumes for frontend pods | `[]` | -| `frontend.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for frontend container(s) | `[]` | -| `frontend.sidecars` | Add additional sidecar containers to the frontend pod | `[]` | -| `frontend.initContainers` | Add additional init containers to the frontend pods | `[]` | -| `frontend.pdb.create` | Enable/disable a Pod Disruption Budget creation | `true` | -| `frontend.pdb.minAvailable` | Minimum number/percentage of pods that should remain scheduled | `""` | -| `frontend.pdb.maxUnavailable` | Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `frontend.pdb.minAvailable` and `frontend.pdb.maxUnavailable` are empty. | `""` | -| `frontend.service.type` | Frontend service type | `ClusterIP` | -| `frontend.service.ports.http` | Frontend service HTTP port | `80` | -| `frontend.service.nodePorts.http` | Node port for HTTP | `""` | -| `frontend.service.clusterIP` | Frontend service Cluster IP | `""` | -| `frontend.service.loadBalancerIP` | Frontend service Load Balancer IP | `""` | -| `frontend.service.loadBalancerSourceRanges` | Frontend service Load Balancer sources | `[]` | -| `frontend.service.externalTrafficPolicy` | Frontend service external traffic policy | `Cluster` | -| `frontend.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | -| `frontend.service.annotations` | Additional custom annotations for frontend service | `{}` | -| `frontend.service.sessionAffinity` | Session Affinity for Kubernetes service, can be "None" or "ClientIP" | `None` | -| `frontend.service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | -| `frontend.networkPolicy.enabled` | Specifies whether a NetworkPolicy should be created | `true` | -| `frontend.networkPolicy.allowExternal` | Don't require server label for connections | `true` | -| `frontend.networkPolicy.allowExternalEgress` | Allow the pod to access any range of port and all destinations. | `true` | -| `frontend.networkPolicy.kubeAPIServerPorts` | List of possible endpoints to kube-apiserver (limit to your cluster settings to increase security) | `[]` | -| `frontend.networkPolicy.extraIngress` | Add extra ingress rules to the NetworkPolicy | `[]` | -| `frontend.networkPolicy.extraEgress` | Add extra ingress rules to the NetworkPolicy | `[]` | -| `frontend.networkPolicy.ingressNSMatchLabels` | Labels to match to allow traffic from other namespaces | `{}` | -| `frontend.networkPolicy.ingressNSPodMatchLabels` | Pod labels to match to allow traffic from other namespaces | `{}` | - -### Dashboard parameters - -| Name | Description | Value | -| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | -| `dashboard.enabled` | Specifies whether Kubeapps Dashboard should be deployed or not | `true` | -| `dashboard.image.registry` | Dashboard image registry | `REGISTRY_NAME` | -| `dashboard.image.repository` | Dashboard image repository | `REPOSITORY_NAME/kubeapps-dashboard` | -| `dashboard.image.digest` | Dashboard image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | -| `dashboard.image.pullPolicy` | Dashboard image pull policy | `IfNotPresent` | -| `dashboard.image.pullSecrets` | Dashboard image pull secrets | `[]` | -| `dashboard.image.debug` | Enable image debug mode | `false` | -| `dashboard.customStyle` | Custom CSS injected to the Dashboard to customize Kubeapps look and feel | `""` | -| `dashboard.customAppViews` | Package names to signal a custom app view | `[]` | -| `dashboard.customComponents` | Custom Form components injected into the BasicDeploymentForm | `""` | -| `dashboard.remoteComponentsUrl` | Remote URL that can be used to load custom components vs loading from the local filesystem | `""` | -| `dashboard.skipAvailablePackageDetails` | Skip the package details view and go straight to the installation view of the latest version | `false` | -| `dashboard.customLocale` | Custom translations injected to the Dashboard to customize the strings used in Kubeapps | `""` | -| `dashboard.defaultTheme` | Default theme used in the Dashboard if the user has not selected any theme yet. | `""` | -| `dashboard.replicaCount` | Number of Dashboard replicas to deploy | `2` | -| `dashboard.createNamespaceLabels` | Labels added to newly created namespaces | `{}` | -| `dashboard.updateStrategy.type` | Dashboard deployment strategy type. | `RollingUpdate` | -| `dashboard.extraEnvVars` | Array with extra environment variables to add to the Dashboard container | `[]` | -| `dashboard.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for the Dashboard container | `""` | -| `dashboard.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for the Dashboard container | `""` | -| `dashboard.containerPorts.http` | Dashboard HTTP container port | `8080` | -| `dashboard.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if dashboard.resources is set (dashboard.resources is recommended for production). | `micro` | -| `dashboard.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | -| `dashboard.podSecurityContext.enabled` | Enabled Dashboard pods' Security Context | `true` | -| `dashboard.podSecurityContext.fsGroupChangePolicy` | Set filesystem group change policy | `Always` | -| `dashboard.podSecurityContext.sysctls` | Set kernel settings using the sysctl interface | `[]` | -| `dashboard.podSecurityContext.supplementalGroups` | Set filesystem extra groups | `[]` | -| `dashboard.podSecurityContext.fsGroup` | Set Dashboard pod's Security Context fsGroup | `1001` | -| `dashboard.containerSecurityContext.enabled` | Enabled containers' Security Context | `true` | -| `dashboard.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | -| `dashboard.containerSecurityContext.runAsUser` | Set containers' Security Context runAsUser | `1001` | -| `dashboard.containerSecurityContext.runAsGroup` | Set containers' Security Context runAsGroup | `1001` | -| `dashboard.containerSecurityContext.runAsNonRoot` | Set container's Security Context runAsNonRoot | `true` | -| `dashboard.containerSecurityContext.privileged` | Set container's Security Context privileged | `false` | -| `dashboard.containerSecurityContext.readOnlyRootFilesystem` | Set container's Security Context readOnlyRootFilesystem | `true` | -| `dashboard.containerSecurityContext.allowPrivilegeEscalation` | Set container's Security Context allowPrivilegeEscalation | `false` | -| `dashboard.containerSecurityContext.capabilities.drop` | List of capabilities to be dropped | `["ALL"]` | -| `dashboard.containerSecurityContext.seccompProfile.type` | Set container's Security Context seccomp profile | `RuntimeDefault` | -| `dashboard.livenessProbe.enabled` | Enable livenessProbe | `true` | -| `dashboard.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `60` | -| `dashboard.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `10` | -| `dashboard.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `5` | -| `dashboard.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `6` | -| `dashboard.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | -| `dashboard.readinessProbe.enabled` | Enable readinessProbe | `true` | -| `dashboard.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `0` | -| `dashboard.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | -| `dashboard.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `5` | -| `dashboard.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `6` | -| `dashboard.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | -| `dashboard.startupProbe.enabled` | Enable startupProbe | `true` | -| `dashboard.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `0` | -| `dashboard.startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | -| `dashboard.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `5` | -| `dashboard.startupProbe.failureThreshold` | Failure threshold for startupProbe | `6` | -| `dashboard.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | -| `dashboard.customLivenessProbe` | Custom livenessProbe that overrides the default one | `{}` | -| `dashboard.customReadinessProbe` | Custom readinessProbe that overrides the default one | `{}` | -| `dashboard.customStartupProbe` | Custom startupProbe that overrides the default one | `{}` | -| `dashboard.lifecycleHooks` | Custom lifecycle hooks for Dashboard containers | `{}` | -| `dashboard.command` | Override default container command (useful when using custom images) | `[]` | -| `dashboard.args` | Override default container args (useful when using custom images) | `[]` | -| `dashboard.podLabels` | Extra labels for Dashboard pods | `{}` | -| `dashboard.podAnnotations` | Annotations for Dashboard pods | `{}` | -| `dashboard.podAffinityPreset` | Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `dashboard.podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `soft` | -| `dashboard.nodeAffinityPreset.type` | Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `dashboard.nodeAffinityPreset.key` | Node label key to match. Ignored if `affinity` is set | `""` | -| `dashboard.nodeAffinityPreset.values` | Node label values to match. Ignored if `affinity` is set | `[]` | -| `dashboard.affinity` | Affinity for pod assignment | `{}` | -| `dashboard.nodeSelector` | Node labels for pod assignment | `{}` | -| `dashboard.tolerations` | Tolerations for pod assignment | `[]` | -| `dashboard.priorityClassName` | Priority class name for Dashboard pods | `""` | -| `dashboard.schedulerName` | Name of the k8s scheduler (other than default) | `""` | -| `dashboard.topologySpreadConstraints` | Topology Spread Constraints for pod assignment | `[]` | -| `dashboard.automountServiceAccountToken` | Mount Service Account token in pod | `true` | -| `dashboard.hostAliases` | Custom host aliases for Dashboard pods | `[]` | -| `dashboard.extraVolumes` | Optionally specify extra list of additional volumes for Dashboard pods | `[]` | -| `dashboard.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for Dashboard container(s) | `[]` | -| `dashboard.sidecars` | Add additional sidecar containers to the Dashboard pod | `[]` | -| `dashboard.initContainers` | Add additional init containers to the Dashboard pods | `[]` | -| `dashboard.pdb.create` | Enable/disable a Pod Disruption Budget creation | `true` | -| `dashboard.pdb.minAvailable` | Minimum number/percentage of pods that should remain scheduled | `""` | -| `dashboard.pdb.maxUnavailable` | Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `dashboard.pdb.minAvailable` and `dashboard.pdb.maxUnavailable` are empty. | `""` | -| `dashboard.service.ports.http` | Dashboard service HTTP port | `8080` | -| `dashboard.service.annotations` | Additional custom annotations for Dashboard service | `{}` | -| `dashboard.networkPolicy.enabled` | Specifies whether a NetworkPolicy should be created | `true` | -| `dashboard.networkPolicy.allowExternal` | Don't require server label for connections | `true` | -| `dashboard.networkPolicy.allowExternalEgress` | Allow the pod to access any range of port and all destinations. | `true` | -| `dashboard.networkPolicy.kubeAPIServerPorts` | List of possible endpoints to kube-apiserver (limit to your cluster settings to increase security) | `[]` | -| `dashboard.networkPolicy.extraIngress` | Add extra ingress rules to the NetworkPolicy | `[]` | -| `dashboard.networkPolicy.extraEgress` | Add extra ingress rules to the NetworkPolicy | `[]` | -| `dashboard.networkPolicy.ingressNSMatchLabels` | Labels to match to allow traffic from other namespaces | `{}` | -| `dashboard.networkPolicy.ingressNSPodMatchLabels` | Pod labels to match to allow traffic from other namespaces | `{}` | - -### AppRepository Controller parameters - -| Name | Description | Value | -| ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | -| `apprepository.image.registry` | Kubeapps AppRepository Controller image registry | `REGISTRY_NAME` | -| `apprepository.image.repository` | Kubeapps AppRepository Controller image repository | `REPOSITORY_NAME/kubeapps-apprepository-controller` | -| `apprepository.image.digest` | Kubeapps AppRepository Controller image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | -| `apprepository.image.pullPolicy` | Kubeapps AppRepository Controller image pull policy | `IfNotPresent` | -| `apprepository.image.pullSecrets` | Kubeapps AppRepository Controller image pull secrets | `[]` | -| `apprepository.syncImage.registry` | Kubeapps Asset Syncer image registry | `REGISTRY_NAME` | -| `apprepository.syncImage.repository` | Kubeapps Asset Syncer image repository | `REPOSITORY_NAME/kubeapps-asset-syncer` | -| `apprepository.syncImage.digest` | Kubeapps Asset Syncer image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | -| `apprepository.syncImage.pullPolicy` | Kubeapps Asset Syncer image pull policy | `IfNotPresent` | -| `apprepository.syncImage.pullSecrets` | Kubeapps Asset Syncer image pull secrets | `[]` | -| `apprepository.globalReposNamespaceSuffix` | Suffix for the namespace of global repos in the Helm plugin. Defaults to empty for backwards compatibility. Ignored if kubeappsapis.pluginConfig.helm.packages.v1alpha1.globalPackagingNamespace is set. | `""` | -| `apprepository.initialRepos` | Initial chart repositories to configure | `[]` | -| `apprepository.customAnnotations` | Custom annotations be added to each AppRepository-generated CronJob, Job and Pod | `{}` | -| `apprepository.customLabels` | Custom labels be added to each AppRepository-generated CronJob, Job and Pod | `{}` | -| `apprepository.initialReposProxy.enabled` | Enables the proxy | `false` | -| `apprepository.initialReposProxy.httpProxy` | URL for the http proxy | `""` | -| `apprepository.initialReposProxy.httpsProxy` | URL for the https proxy | `""` | -| `apprepository.initialReposProxy.noProxy` | URL to exclude from using the proxy | `""` | -| `apprepository.crontab` | Default schedule for syncing App repositories (defaults to every 10 minutes) | `""` | -| `apprepository.watchAllNamespaces` | Watch all namespaces to support separate AppRepositories per namespace | `true` | -| `apprepository.extraFlags` | Additional command line flags for AppRepository Controller | `[]` | -| `apprepository.replicaCount` | Number of AppRepository Controller replicas to deploy | `1` | -| `apprepository.updateStrategy.type` | AppRepository Controller deployment strategy type. | `RollingUpdate` | -| `apprepository.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if apprepository.resources is set (apprepository.resources is recommended for production). | `micro` | -| `apprepository.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | -| `apprepository.podSecurityContext.enabled` | Enabled AppRepository Controller pods' Security Context | `true` | -| `apprepository.podSecurityContext.fsGroupChangePolicy` | Set filesystem group change policy | `Always` | -| `apprepository.podSecurityContext.sysctls` | Set kernel settings using the sysctl interface | `[]` | -| `apprepository.podSecurityContext.supplementalGroups` | Set filesystem extra groups | `[]` | -| `apprepository.podSecurityContext.fsGroup` | Set AppRepository Controller pod's Security Context fsGroup | `1001` | -| `apprepository.containerSecurityContext.enabled` | Enabled containers' Security Context | `true` | -| `apprepository.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | -| `apprepository.containerSecurityContext.runAsUser` | Set containers' Security Context runAsUser | `1001` | -| `apprepository.containerSecurityContext.runAsGroup` | Set containers' Security Context runAsGroup | `1001` | -| `apprepository.containerSecurityContext.runAsNonRoot` | Set container's Security Context runAsNonRoot | `true` | -| `apprepository.containerSecurityContext.privileged` | Set container's Security Context privileged | `false` | -| `apprepository.containerSecurityContext.readOnlyRootFilesystem` | Set container's Security Context readOnlyRootFilesystem | `true` | -| `apprepository.containerSecurityContext.allowPrivilegeEscalation` | Set container's Security Context allowPrivilegeEscalation | `false` | -| `apprepository.containerSecurityContext.capabilities.drop` | List of capabilities to be dropped | `["ALL"]` | -| `apprepository.containerSecurityContext.seccompProfile.type` | Set container's Security Context seccomp profile | `RuntimeDefault` | -| `apprepository.lifecycleHooks` | Custom lifecycle hooks for AppRepository Controller containers | `{}` | -| `apprepository.command` | Override default container command (useful when using custom images) | `[]` | -| `apprepository.args` | Override default container args (useful when using custom images) | `[]` | -| `apprepository.extraEnvVars` | Array with extra environment variables to add to AppRepository Controller pod(s) | `[]` | -| `apprepository.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for AppRepository Controller pod(s) | `""` | -| `apprepository.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for AppRepository Controller pod(s) | `""` | -| `apprepository.extraVolumes` | Optionally specify extra list of additional volumes for the AppRepository Controller pod(s) | `[]` | -| `apprepository.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the AppRepository Controller container(s) | `[]` | -| `apprepository.podLabels` | Extra labels for AppRepository Controller pods | `{}` | -| `apprepository.podAnnotations` | Annotations for AppRepository Controller pods | `{}` | -| `apprepository.podAffinityPreset` | Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `apprepository.podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `soft` | -| `apprepository.nodeAffinityPreset.type` | Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `apprepository.nodeAffinityPreset.key` | Node label key to match. Ignored if `affinity` is set | `""` | -| `apprepository.nodeAffinityPreset.values` | Node label values to match. Ignored if `affinity` is set | `[]` | -| `apprepository.affinity` | Affinity for pod assignment | `{}` | -| `apprepository.nodeSelector` | Node labels for pod assignment | `{}` | -| `apprepository.tolerations` | Tolerations for pod assignment | `[]` | -| `apprepository.priorityClassName` | Priority class name for AppRepository Controller pods | `""` | -| `apprepository.schedulerName` | Name of the k8s scheduler (other than default) | `""` | -| `apprepository.topologySpreadConstraints` | Topology Spread Constraints for pod assignment | `[]` | -| `apprepository.automountServiceAccountToken` | Mount Service Account token in pod | `true` | -| `apprepository.hostAliases` | Custom host aliases for AppRepository Controller pods | `[]` | -| `apprepository.sidecars` | Add additional sidecar containers to the AppRepository Controller pod(s) | `[]` | -| `apprepository.initContainers` | Add additional init containers to the AppRepository Controller pod(s) | `[]` | -| `apprepository.pdb.create` | Enable/disable a Pod Disruption Budget creation | `true` | -| `apprepository.pdb.minAvailable` | Minimum number/percentage of pods that should remain scheduled | `""` | -| `apprepository.pdb.maxUnavailable` | Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `apprepository.pdb.minAvailable` and `apprepository.pdb.maxUnavailable` are empty. | `""` | -| `apprepository.networkPolicy.enabled` | Specifies whether a NetworkPolicy should be created | `true` | -| `apprepository.networkPolicy.allowExternalEgress` | Allow the pod to access any range of port and all destinations. | `true` | -| `apprepository.networkPolicy.kubeAPIServerPorts` | List of possible endpoints to kube-apiserver (limit to your cluster settings to increase security) | `[]` | -| `apprepository.networkPolicy.extraIngress` | Add extra ingress rules to the NetworkPolicy | `[]` | -| `apprepository.networkPolicy.extraEgress` | Add extra ingress rules to the NetworkPolicy | `[]` | -| `apprepository.serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` | -| `apprepository.serviceAccount.name` | Name of the service account to use. If not set and create is true, a name is generated using the fullname template. | `""` | -| `apprepository.serviceAccount.automountServiceAccountToken` | Automount service account token for the server service account | `false` | -| `apprepository.serviceAccount.annotations` | Annotations for service account. Evaluated as a template. Only used if `create` is `true`. | `{}` | - -### Auth Proxy parameters - -| Name | Description | Value | -| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | -| `authProxy.enabled` | Specifies whether Kubeapps should configure OAuth login/logout | `false` | -| `authProxy.image.registry` | OAuth2 Proxy image registry | `REGISTRY_NAME` | -| `authProxy.image.repository` | OAuth2 Proxy image repository | `REPOSITORY_NAME/oauth2-proxy` | -| `authProxy.image.digest` | OAuth2 Proxy image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | -| `authProxy.image.pullPolicy` | OAuth2 Proxy image pull policy | `IfNotPresent` | -| `authProxy.image.pullSecrets` | OAuth2 Proxy image pull secrets | `[]` | -| `authProxy.external` | Use an external Auth Proxy instead of deploying its own one | `false` | -| `authProxy.oauthLoginURI` | OAuth Login URI to which the Kubeapps frontend redirects for authn | `/oauth2/start` | -| `authProxy.oauthLogoutURI` | OAuth Logout URI to which the Kubeapps frontend redirects for authn | `/oauth2/sign_out` | -| `authProxy.skipKubeappsLoginPage` | Skip the Kubeapps login page when using OIDC and directly redirect to the IdP | `false` | -| `authProxy.provider` | OAuth provider | `""` | -| `authProxy.clientID` | OAuth Client ID | `""` | -| `authProxy.clientSecret` | OAuth Client secret | `""` | -| `authProxy.cookieSecret` | Secret used by oauth2-proxy to encrypt any credentials | `""` | -| `authProxy.existingOauth2Secret` | Name of an existing secret containing the OAuth client secrets, it should contain the keys clientID, clientSecret, and cookieSecret | `""` | -| `authProxy.cookieRefresh` | Duration after which to refresh the cookie | `2m` | -| `authProxy.scope` | OAuth scope specification | `openid email groups` | -| `authProxy.emailDomain` | Allowed email domains | `*` | -| `authProxy.extraFlags` | Additional command line flags for oauth2-proxy | `[]` | -| `authProxy.lifecycleHooks` | for the Auth Proxy container(s) to automate configuration before or after startup | `{}` | -| `authProxy.command` | Override default container command (useful when using custom images) | `[]` | -| `authProxy.args` | Override default container args (useful when using custom images) | `[]` | -| `authProxy.extraEnvVars` | Array with extra environment variables to add to the Auth Proxy container | `[]` | -| `authProxy.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for Auth Proxy containers(s) | `""` | -| `authProxy.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for Auth Proxy containers(s) | `""` | -| `authProxy.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the Auth Proxy container(s) | `[]` | -| `authProxy.containerPorts.proxy` | Auth Proxy HTTP container port | `3000` | -| `authProxy.containerSecurityContext.enabled` | Enabled containers' Security Context | `true` | -| `authProxy.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | -| `authProxy.containerSecurityContext.runAsUser` | Set containers' Security Context runAsUser | `1001` | -| `authProxy.containerSecurityContext.runAsGroup` | Set containers' Security Context runAsGroup | `1001` | -| `authProxy.containerSecurityContext.runAsNonRoot` | Set container's Security Context runAsNonRoot | `true` | -| `authProxy.containerSecurityContext.privileged` | Set container's Security Context privileged | `false` | -| `authProxy.containerSecurityContext.readOnlyRootFilesystem` | Set container's Security Context readOnlyRootFilesystem | `true` | -| `authProxy.containerSecurityContext.allowPrivilegeEscalation` | Set container's Security Context allowPrivilegeEscalation | `false` | -| `authProxy.containerSecurityContext.capabilities.drop` | List of capabilities to be dropped | `["ALL"]` | -| `authProxy.containerSecurityContext.seccompProfile.type` | Set container's Security Context seccomp profile | `RuntimeDefault` | -| `authProxy.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if authProxy.resources is set (authProxy.resources is recommended for production). | `micro` | -| `authProxy.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | - -### Pinniped Proxy parameters - -| Name | Description | Value | -| ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- | -| `pinnipedProxy.enabled` | Specifies whether Kubeapps should configure Pinniped Proxy | `false` | -| `pinnipedProxy.image.registry` | Pinniped Proxy image registry | `REGISTRY_NAME` | -| `pinnipedProxy.image.repository` | Pinniped Proxy image repository | `REPOSITORY_NAME/kubeapps-pinniped-proxy` | -| `pinnipedProxy.image.digest` | Pinniped Proxy image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | -| `pinnipedProxy.image.pullPolicy` | Pinniped Proxy image pull policy | `IfNotPresent` | -| `pinnipedProxy.image.pullSecrets` | Pinniped Proxy image pull secrets | `[]` | -| `pinnipedProxy.defaultPinnipedNamespace` | Namespace in which pinniped concierge is installed | `pinniped-concierge` | -| `pinnipedProxy.defaultAuthenticatorType` | Authenticator type | `JWTAuthenticator` | -| `pinnipedProxy.defaultAuthenticatorName` | Authenticator name | `jwt-authenticator` | -| `pinnipedProxy.defaultPinnipedAPISuffix` | API suffix | `pinniped.dev` | -| `pinnipedProxy.tls.existingSecret` | TLS secret with which to proxy requests | `""` | -| `pinnipedProxy.tls.caCertificate` | TLS CA cert config map which clients of pinniped proxy should use with TLS requests | `""` | -| `pinnipedProxy.lifecycleHooks` | For the Pinniped Proxy container(s) to automate configuration before or after startup | `{}` | -| `pinnipedProxy.command` | Override default container command (useful when using custom images) | `[]` | -| `pinnipedProxy.args` | Override default container args (useful when using custom images) | `[]` | -| `pinnipedProxy.extraEnvVars` | Array with extra environment variables to add to Pinniped Proxy container(s) | `[]` | -| `pinnipedProxy.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for Pinniped Proxy container(s) | `""` | -| `pinnipedProxy.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for Pinniped Proxy container(s) | `""` | -| `pinnipedProxy.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the Pinniped Proxy container(s) | `[]` | -| `pinnipedProxy.containerPorts.pinnipedProxy` | Pinniped Proxy container port | `3333` | -| `pinnipedProxy.containerSecurityContext.enabled` | Enabled containers' Security Context | `true` | -| `pinnipedProxy.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | -| `pinnipedProxy.containerSecurityContext.runAsUser` | Set containers' Security Context runAsUser | `1001` | -| `pinnipedProxy.containerSecurityContext.runAsGroup` | Set containers' Security Context runAsGroup | `1001` | -| `pinnipedProxy.containerSecurityContext.runAsNonRoot` | Set container's Security Context runAsNonRoot | `true` | -| `pinnipedProxy.containerSecurityContext.privileged` | Set container's Security Context privileged | `false` | -| `pinnipedProxy.containerSecurityContext.readOnlyRootFilesystem` | Set container's Security Context readOnlyRootFilesystem | `true` | -| `pinnipedProxy.containerSecurityContext.allowPrivilegeEscalation` | Set container's Security Context allowPrivilegeEscalation | `false` | -| `pinnipedProxy.containerSecurityContext.capabilities.drop` | List of capabilities to be dropped | `["ALL"]` | -| `pinnipedProxy.containerSecurityContext.seccompProfile.type` | Set container's Security Context seccomp profile | `RuntimeDefault` | -| `pinnipedProxy.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if pinnipedProxy.resources is set (pinnipedProxy.resources is recommended for production). | `micro` | -| `pinnipedProxy.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | -| `pinnipedProxy.service.ports.pinnipedProxy` | Pinniped Proxy service port | `3333` | -| `pinnipedProxy.service.annotations` | Additional custom annotations for Pinniped Proxy service | `{}` | - -### Other Parameters - -| Name | Description | Value | -| ------------- | --------------------------------------------------------- | ------ | -| `clusters` | List of clusters that Kubeapps can target for deployments | `[]` | -| `rbac.create` | Specifies whether RBAC resources should be created | `true` | - -### Feature flags - -| Name | Description | Value | -| --------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------- | -| `featureFlags.apiOnly.enabled` | Enable ingress for API operations only. Access to "/" will not be possible, so Dashboard will be unusable. | `false` | -| `featureFlags.apiOnly.grpc.annotations` | Specific annotations for the GRPC ingress in API-only mode | `{}` | -| `featureFlags.operators` | Enable support for Operators in Kubeapps | `false` | -| `featureFlags.schemaEditor.enabled` | Enable a visual editor for customizing the package schemas | `false` | - -### Database Parameters - -| Name | Description | Value | -| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | -| `postgresql.enabled` | Deploy a PostgreSQL server to satisfy the applications database requirements | `true` | -| `postgresql.auth.username` | Username for PostgreSQL server | `postgres` | -| `postgresql.auth.postgresPassword` | Password for 'postgres' user | `""` | -| `postgresql.auth.database` | Name for a custom database to create | `assets` | -| `postgresql.auth.existingSecret` | Name of existing secret to use for PostgreSQL credentials | `""` | -| `postgresql.primary.persistence.enabled` | Enable PostgreSQL Primary data persistence using PVC | `false` | -| `postgresql.architecture` | PostgreSQL architecture (`standalone` or `replication`) | `standalone` | -| `postgresql.securityContext.enabled` | Enabled PostgreSQL replicas pods' Security Context | `false` | -| `postgresql.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if postgresql.resources is set (postgresql.resources is recommended for production). | `micro` | -| `postgresql.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | - -### kubeappsapis parameters - -| Name | Description | Value | -| ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | -| `kubeappsapis.enabledPlugins` | Manually override which plugins are enabled for the Kubeapps-APIs service | `[]` | -| `kubeappsapis.pluginConfig.core.packages.v1alpha1.versionsInSummary.major` | Number of major versions to display in the summary | `3` | -| `kubeappsapis.pluginConfig.core.packages.v1alpha1.versionsInSummary.minor` | Number of minor versions to display in the summary | `3` | -| `kubeappsapis.pluginConfig.core.packages.v1alpha1.versionsInSummary.patch` | Number of patch versions to display in the summary | `3` | -| `kubeappsapis.pluginConfig.core.packages.v1alpha1.timeoutSeconds` | Value to wait for Kubernetes commands to complete | `300` | -| `kubeappsapis.pluginConfig.helm.packages.v1alpha1.globalPackagingNamespace` | Custom global packaging namespace. Using this value will override the current "kubeapps release namespace + suffix" pattern and will create a new namespace if not exists. | `""` | -| `kubeappsapis.pluginConfig.kappController.packages.v1alpha1.defaultUpgradePolicy` | Default upgrade policy generating version constraints | `none` | -| `kubeappsapis.pluginConfig.kappController.packages.v1alpha1.defaultPrereleasesVersionSelection` | Default policy for allowing prereleases containing one of the identifiers | `nil` | -| `kubeappsapis.pluginConfig.kappController.packages.v1alpha1.defaultAllowDowngrades` | Default policy for allowing applications to be downgraded to previous versions | `false` | -| `kubeappsapis.pluginConfig.kappController.packages.v1alpha1.globalPackagingNamespace` | Default global packaging namespace | `kapp-controller-packaging-global` | -| `kubeappsapis.pluginConfig.flux.packages.v1alpha1.defaultUpgradePolicy` | Default upgrade policy generating version constraints | `none` | -| `kubeappsapis.pluginConfig.flux.packages.v1alpha1.noCrossNamespaceRefs` | Enable this flag to disallow cross-namespace references, useful when running Flux on multi-tenant clusters | `false` | -| `kubeappsapis.pluginConfig.resources.packages.v1alpha1.trustedNamespaces.headerName` | Optional header name for trusted namespaces | `""` | -| `kubeappsapis.pluginConfig.resources.packages.v1alpha1.trustedNamespaces.headerPattern` | Optional header pattern for trusted namespaces | `""` | -| `kubeappsapis.image.registry` | Kubeapps-APIs image registry | `REGISTRY_NAME` | -| `kubeappsapis.image.repository` | Kubeapps-APIs image repository | `REPOSITORY_NAME/kubeapps-apis` | -| `kubeappsapis.image.digest` | Kubeapps-APIs image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | -| `kubeappsapis.image.pullPolicy` | Kubeapps-APIs image pull policy | `IfNotPresent` | -| `kubeappsapis.image.pullSecrets` | Kubeapps-APIs image pull secrets | `[]` | -| `kubeappsapis.replicaCount` | Number of frontend replicas to deploy | `2` | -| `kubeappsapis.updateStrategy.type` | KubeappsAPIs deployment strategy type. | `RollingUpdate` | -| `kubeappsapis.extraFlags` | Additional command line flags for KubeappsAPIs | `[]` | -| `kubeappsapis.qps` | KubeappsAPIs Kubernetes API client QPS limit | `50.0` | -| `kubeappsapis.burst` | KubeappsAPIs Kubernetes API client Burst limit | `100` | -| `kubeappsapis.terminationGracePeriodSeconds` | The grace time period for sig term | `300` | -| `kubeappsapis.extraEnvVars` | Array with extra environment variables to add to the KubeappsAPIs container | `[]` | -| `kubeappsapis.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for the KubeappsAPIs container | `""` | -| `kubeappsapis.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for the KubeappsAPIs container | `""` | -| `kubeappsapis.containerPorts.http` | KubeappsAPIs HTTP container port | `50051` | -| `kubeappsapis.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if kubeappsapis.resources is set (kubeappsapis.resources is recommended for production). | `micro` | -| `kubeappsapis.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | -| `kubeappsapis.podSecurityContext.enabled` | Enabled KubeappsAPIs pods' Security Context | `true` | -| `kubeappsapis.podSecurityContext.fsGroupChangePolicy` | Set filesystem group change policy | `Always` | -| `kubeappsapis.podSecurityContext.sysctls` | Set kernel settings using the sysctl interface | `[]` | -| `kubeappsapis.podSecurityContext.supplementalGroups` | Set filesystem extra groups | `[]` | -| `kubeappsapis.podSecurityContext.fsGroup` | Set KubeappsAPIs pod's Security Context fsGroup | `1001` | -| `kubeappsapis.containerSecurityContext.enabled` | Enabled containers' Security Context | `true` | -| `kubeappsapis.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | -| `kubeappsapis.containerSecurityContext.runAsUser` | Set containers' Security Context runAsUser | `1001` | -| `kubeappsapis.containerSecurityContext.runAsGroup` | Set containers' Security Context runAsGroup | `1001` | -| `kubeappsapis.containerSecurityContext.runAsNonRoot` | Set container's Security Context runAsNonRoot | `true` | -| `kubeappsapis.containerSecurityContext.privileged` | Set container's Security Context privileged | `false` | -| `kubeappsapis.containerSecurityContext.readOnlyRootFilesystem` | Set container's Security Context readOnlyRootFilesystem | `true` | -| `kubeappsapis.containerSecurityContext.allowPrivilegeEscalation` | Set container's Security Context allowPrivilegeEscalation | `false` | -| `kubeappsapis.containerSecurityContext.capabilities.drop` | List of capabilities to be dropped | `["ALL"]` | -| `kubeappsapis.containerSecurityContext.seccompProfile.type` | Set container's Security Context seccomp profile | `RuntimeDefault` | -| `kubeappsapis.livenessProbe.enabled` | Enable livenessProbe | `true` | -| `kubeappsapis.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `60` | -| `kubeappsapis.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `10` | -| `kubeappsapis.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `5` | -| `kubeappsapis.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `6` | -| `kubeappsapis.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | -| `kubeappsapis.readinessProbe.enabled` | Enable readinessProbe | `true` | -| `kubeappsapis.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `0` | -| `kubeappsapis.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | -| `kubeappsapis.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `5` | -| `kubeappsapis.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `6` | -| `kubeappsapis.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | -| `kubeappsapis.startupProbe.enabled` | Enable startupProbe | `false` | -| `kubeappsapis.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `0` | -| `kubeappsapis.startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | -| `kubeappsapis.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `5` | -| `kubeappsapis.startupProbe.failureThreshold` | Failure threshold for startupProbe | `6` | -| `kubeappsapis.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | -| `kubeappsapis.customLivenessProbe` | Custom livenessProbe that overrides the default one | `{}` | -| `kubeappsapis.customReadinessProbe` | Custom readinessProbe that overrides the default one | `{}` | -| `kubeappsapis.customStartupProbe` | Custom startupProbe that overrides the default one | `{}` | -| `kubeappsapis.lifecycleHooks` | Custom lifecycle hooks for KubeappsAPIs containers | `{}` | -| `kubeappsapis.command` | Override default container command (useful when using custom images) | `[]` | -| `kubeappsapis.args` | Override default container args (useful when using custom images) | `[]` | -| `kubeappsapis.extraVolumes` | Optionally specify extra list of additional volumes for the KubeappsAPIs pod(s) | `[]` | -| `kubeappsapis.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the KubeappsAPIs container(s) | `[]` | -| `kubeappsapis.podLabels` | Extra labels for KubeappsAPIs pods | `{}` | -| `kubeappsapis.podAnnotations` | Annotations for KubeappsAPIs pods | `{}` | -| `kubeappsapis.podAffinityPreset` | Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `kubeappsapis.podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `soft` | -| `kubeappsapis.nodeAffinityPreset.type` | Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `kubeappsapis.nodeAffinityPreset.key` | Node label key to match. Ignored if `affinity` is set | `""` | -| `kubeappsapis.nodeAffinityPreset.values` | Node label values to match. Ignored if `affinity` is set | `[]` | -| `kubeappsapis.affinity` | Affinity for pod assignment | `{}` | -| `kubeappsapis.nodeSelector` | Node labels for pod assignment | `{}` | -| `kubeappsapis.tolerations` | Tolerations for pod assignment | `[]` | -| `kubeappsapis.priorityClassName` | Priority class name for KubeappsAPIs pods | `""` | -| `kubeappsapis.schedulerName` | Name of the k8s scheduler (other than default) | `""` | -| `kubeappsapis.topologySpreadConstraints` | Topology Spread Constraints for pod assignment | `[]` | -| `kubeappsapis.automountServiceAccountToken` | Mount Service Account token in pod | `true` | -| `kubeappsapis.hostAliases` | Custom host aliases for KubeappsAPIs pods | `[]` | -| `kubeappsapis.sidecars` | Add additional sidecar containers to the KubeappsAPIs pod(s) | `[]` | -| `kubeappsapis.initContainers` | Add additional init containers to the KubeappsAPIs pod(s) | `[]` | -| `kubeappsapis.pdb.create` | Enable/disable a Pod Disruption Budget creation | `true` | -| `kubeappsapis.pdb.minAvailable` | Minimum number/percentage of pods that should remain scheduled | `""` | -| `kubeappsapis.pdb.maxUnavailable` | Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `kubeappsapis.pdb.minAvailable` and `kubeappsapis.pdb.maxUnavailable` are empty. | `""` | -| `kubeappsapis.service.ports.http` | KubeappsAPIs service HTTP port | `8080` | -| `kubeappsapis.service.annotations` | Additional custom annotations for KubeappsAPIs service | `{}` | -| `kubeappsapis.networkPolicy.enabled` | Specifies whether a NetworkPolicy should be created | `true` | -| `kubeappsapis.networkPolicy.allowExternal` | Don't require server label for connections | `true` | -| `kubeappsapis.networkPolicy.allowExternalEgress` | Allow the pod to access any range of port and all destinations. | `true` | -| `kubeappsapis.networkPolicy.kubeAPIServerPorts` | List of possible endpoints to kube-apiserver (limit to your cluster settings to increase security) | `[]` | -| `kubeappsapis.networkPolicy.extraIngress` | Add extra ingress rules to the NetworkPolicy | `[]` | -| `kubeappsapis.networkPolicy.extraEgress` | Add extra ingress rules to the NetworkPolicy | `[]` | -| `kubeappsapis.networkPolicy.ingressNSMatchLabels` | Labels to match to allow traffic from other namespaces | `{}` | -| `kubeappsapis.networkPolicy.ingressNSPodMatchLabels` | Pod labels to match to allow traffic from other namespaces | `{}` | -| `kubeappsapis.serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` | -| `kubeappsapis.serviceAccount.name` | Name of the service account to use. If not set and create is true, a name is generated using the fullname template. | `""` | -| `kubeappsapis.serviceAccount.automountServiceAccountToken` | Automount service account token for the server service account | `false` | -| `kubeappsapis.serviceAccount.annotations` | Annotations for service account. Evaluated as a template. Only used if `create` is `true`. | `{}` | - -### OCI Catalog chart configuration - -| Name | Description | Value | -| -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | -| `ociCatalog.enabled` | Enable the OCI catalog gRPC service for cataloging | `false` | -| `ociCatalog.image.registry` | OCI Catalog image registry | `REGISTRY_NAME` | -| `ociCatalog.image.repository` | OCI Catalog image repository | `REPOSITORY_NAME/kubeapps-oci-catalog` | -| `ociCatalog.image.digest` | OCI Catalog image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | -| `ociCatalog.image.pullPolicy` | OCI Catalog image pull policy | `IfNotPresent` | -| `ociCatalog.image.pullSecrets` | OCI Catalog image pull secrets | `[]` | -| `ociCatalog.image.debug` | Enable image debug mode | `false` | -| `ociCatalog.extraFlags` | Additional command line flags for OCI Catalog | `[]` | -| `ociCatalog.extraEnvVars` | Array with extra environment variables to add to the oci-catalog container | `[]` | -| `ociCatalog.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for the OCI Catalog container | `""` | -| `ociCatalog.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for the OCI Catalog container | `""` | -| `ociCatalog.containerPorts.grpc` | OCI Catalog gRPC container port | `50061` | -| `ociCatalog.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if ociCatalog.resources is set (ociCatalog.resources is recommended for production). | `micro` | -| `ociCatalog.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | -| `ociCatalog.containerSecurityContext.enabled` | Enabled containers' Security Context | `true` | -| `ociCatalog.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | -| `ociCatalog.containerSecurityContext.runAsUser` | Set containers' Security Context runAsUser | `1001` | -| `ociCatalog.containerSecurityContext.runAsGroup` | Set containers' Security Context runAsGroup | `1001` | -| `ociCatalog.containerSecurityContext.runAsNonRoot` | Set container's Security Context runAsNonRoot | `true` | -| `ociCatalog.containerSecurityContext.privileged` | Set container's Security Context privileged | `false` | -| `ociCatalog.containerSecurityContext.readOnlyRootFilesystem` | Set container's Security Context readOnlyRootFilesystem | `true` | -| `ociCatalog.containerSecurityContext.allowPrivilegeEscalation` | Set container's Security Context allowPrivilegeEscalation | `false` | -| `ociCatalog.containerSecurityContext.capabilities.drop` | List of capabilities to be dropped | `["ALL"]` | -| `ociCatalog.containerSecurityContext.seccompProfile.type` | Set container's Security Context seccomp profile | `RuntimeDefault` | -| `ociCatalog.livenessProbe.enabled` | Enable livenessProbe | `true` | -| `ociCatalog.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `60` | -| `ociCatalog.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `10` | -| `ociCatalog.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `5` | -| `ociCatalog.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `6` | -| `ociCatalog.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | -| `ociCatalog.readinessProbe.enabled` | Enable readinessProbe | `true` | -| `ociCatalog.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `0` | -| `ociCatalog.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | -| `ociCatalog.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `5` | -| `ociCatalog.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `6` | -| `ociCatalog.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | -| `ociCatalog.startupProbe.enabled` | Enable startupProbe | `false` | -| `ociCatalog.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `0` | -| `ociCatalog.startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | -| `ociCatalog.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `5` | -| `ociCatalog.startupProbe.failureThreshold` | Failure threshold for startupProbe | `6` | -| `ociCatalog.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | -| `ociCatalog.customLivenessProbe` | Custom livenessProbe that overrides the default one | `{}` | -| `ociCatalog.customReadinessProbe` | Custom readinessProbe that overrides the default one | `{}` | -| `ociCatalog.customStartupProbe` | Custom startupProbe that overrides the default one | `{}` | -| `ociCatalog.lifecycleHooks` | Custom lifecycle hooks for OCI Catalog containers | `{}` | -| `ociCatalog.command` | Override default container command (useful when using custom images) | `[]` | -| `ociCatalog.args` | Override default container args (useful when using custom images) | `[]` | -| `ociCatalog.extraVolumes` | Optionally specify extra list of additional volumes for the OCI Catalog pod(s) | `[]` | -| `ociCatalog.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the OCI Catalog container(s) | `[]` | - -### Redis® chart configuration - -| Name | Description | Value | -| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------- | -| `redis.auth.enabled` | Enable password authentication | `true` | -| `redis.auth.password` | Redis® password | `""` | -| `redis.auth.existingSecret` | The name of an existing secret with Redis® credentials | `""` | -| `redis.architecture` | Redis(R) architecture (`standalone` or `replication`) | `standalone` | -| `redis.master.extraFlags` | Array with additional command line flags for Redis® master | `["--maxmemory 200mb","--maxmemory-policy allkeys-lru"]` | -| `redis.master.disableCommands` | Array with commands to deactivate on Redis® | `[]` | -| `redis.master.persistence.enabled` | Enable Redis® master data persistence using PVC | `false` | -| `redis.master.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if master.resources is set (master.resources is recommended for production). | `nano` | -| `redis.master.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | -| `redis.replica.replicaCount` | Number of Redis® replicas to deploy | `1` | -| `redis.replica.extraFlags` | Array with additional command line flags for Redis® replicas | `["--maxmemory 200mb","--maxmemory-policy allkeys-lru"]` | -| `redis.replica.disableCommands` | Array with commands to deactivate on Redis® | `[]` | -| `redis.replica.persistence.enabled` | Enable Redis® replica data persistence using PVC | `false` | - -```console -helm install kubeapps --namespace kubeapps \ - --set ingress.enabled=true \ - oci://REGISTRY_NAME/REPOSITORY_NAME/kubeapps -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -The above command enables an Ingress Rule to expose Kubeapps. - -Alternatively, a YAML file that specifies the values for parameters can be provided while installing the chart. For example, - -```console -helm install kubeapps --namespace kubeapps -f custom-values.yaml oci://REGISTRY_NAME/REPOSITORY_NAME/kubeapps -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -## Troubleshooting - -### How to install Kubeapps for demo purposes? - -Install Kubeapps for exclusively **demo purposes** by simply following the [getting started](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/tutorials/getting-started.md) docs. - -### How to install Kubeapps in production scenarios? - -For any user-facing installation, you should [configure an OAuth2/OIDC provider](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/tutorials/using-an-OIDC-provider.md) to enable secure user authentication with Kubeapps and the cluster. -Please also refer to the [Access Control](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/howto/access-control.md) documentation to configure fine-grained access control for users. - -### How to use Kubeapps? - -Have a look at the [dashboard documentation](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/howto/dashboard.md) for knowing how to use the Kubeapps dashboard: deploying applications, listing and removing the applications running in your cluster and adding new repositories. - -### How to uninstall Kubeapps - -To uninstall/delete the `kubeapps` deployment: - -```console -helm uninstall -n kubeapps kubeapps - -# Optional: Only if there are no more instances of Kubeapps -$ kubectl delete crd apprepositories.kubeapps.com -``` - -The first command removes most of the Kubernetes components associated with the chart and deletes the release. After that, if there are no more instances of Kubeapps in the cluster you can manually delete the `apprepositories.kubeapps.com` CRD used by Kubeapps that is shared for the entire cluster. - -> **NOTE**: If you delete the CRD for `apprepositories.kubeapps.com` it will delete the repositories for **all** the installed instances of `kubeapps`. This will break existing installations of `kubeapps` if they exist. - -If you have dedicated a namespace only for Kubeapps you can completely clean the remaining completed/failed jobs or any stale resources by deleting the namespace - -```console -kubectl delete namespace kubeapps -``` - -### How to configure Kubeapps with Ingress - -The example below will match the URL `http://example.com` to the Kubeapps dashboard. For further configuration, please refer to your specific Ingress configuration docs (e.g., [NGINX](https://github.com/kubernetes/ingress-nginx) or [HAProxy](https://github.com/haproxytech/kubernetes-ingress)). - -```console -helm install kubeapps oci://REGISTRY_NAME/REPOSITORY_NAME/kubeapps \ - --namespace kubeapps \ - --set ingress.enabled=true \ - --set ingress.hostname=example.com \ - --set ingress.annotations."kubernetes\.io/ingress\.class"=nginx # or your preferred ingress controller -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -If you are using LDAP via Dex with OIDC or you are getting an error message like `upstream sent too big header while reading response header from upstream` it means the cookie size is too big and can't be processed by the Ingress Controller. -You can work around this problem by setting the following Nginx ingress annotations (look for similar annotations in your preferred Ingress Controller): - -```text - # rest of the helm install ... command - --set ingress.annotations."nginx\.ingress\.kubernetes\.io/proxy-read-timeout"=600 - --set ingress.annotations."nginx\.ingress\.kubernetes\.io/proxy-buffer-size"=8k - --set ingress.annotations."nginx\.ingress\.kubernetes\.io/proxy-buffers"=4 -``` - -#### Serving Kubeapps in a subpath - -You may want to serve Kubeapps with a subpath, for instance `http://example.com/subpath`, you have to set the proper Ingress configuration. If you are using the ingress configuration provided by the Kubeapps chart, you will have to set the `ingress.hostname` and `path` parameters: - -```console -helm install kubeapps oci://REGISTRY_NAME/REPOSITORY_NAME/kubeapps \ - --namespace kubeapps \ - --set ingress.enabled=true \ - --set ingress.hostname=example.com \ - --set ingress.path=/subpath \ - --set ingress.annotations."kubernetes\.io/ingress\.class"=nginx # or your preferred ingress controller -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -Besides, if you are using the OAuth2/OIDC login (more information at the [using an OIDC provider documentation](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/tutorials/using-an-OIDC-provider.md)), you will need, also, to configure the different URLs: - -```console -helm install kubeapps oci://REGISTRY_NAME/REPOSITORY_NAME/kubeapps \ - --namespace kubeapps \ - # ... other OIDC and ingress flags - --set authProxy.oauthLoginURI="/subpath/oauth2/login" \ - --set authProxy.oauthLogoutURI="/subpath/oauth2/logout" \ - --set authProxy.extraFlags="{,--proxy-prefix=/subpath/oauth2}" -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -### Can Kubeapps install apps into more than one cluster? - -Yes! Kubeapps 2.0+ supports multicluster environments. Have a look at the [Kubeapps dashboard documentation](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/howto/deploying-to-multiple-clusters.md) to know more. - -### Can Kubeapps be installed without Internet connection? - -Yes! Follow the [offline installation documentation](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/howto/offline-installation.md) to discover how to perform an installation in an air-gapped scenario. - -### Does Kubeapps support private repositories? - -Of course! Have a look at the [private package repositories documentation](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/howto/private-app-repository.md) to learn how to configure a private repository in Kubeapps. - -### Is there any API documentation? - -Yes! But it is not definitive and is still subject to change. Check out the [latest API online documentation](https://app.swaggerhub.com/apis/vmware-tanzu/Kubeapps) or download the Kubeapps [OpenAPI Specification yaml file](https://github.com/vmware-tanzu/kubeapps/blob/main/dashboard/public/openapi.yaml) from the repository. - -### Why can't I configure global private repositories? - -You can, but you will need to configure the `imagePullSecrets` manually. - -Kubeapps does not allow you to add `imagePullSecrets` to an AppRepository that is available to the whole cluster because it would require that Kubeapps copies those secrets to the target namespace when a user deploys an app. - -If you create a global AppRepository but the images are on a private registry requiring `imagePullSecrets`, the best way to configure that is to ensure your [Kubernetes nodes are configured with the required `imagePullSecrets`](https://kubernetes.io/docs/concepts/containers/images/#configuring-nodes-to-authenticate-to-a-private-registry) - this allows all users (of those nodes) to use those images in their deployments without ever requiring access to the secrets. - -You could alternatively ensure that the `imagePullSecret` is available in all namespaces in which you want people to deploy, but this unnecessarily compromises the secret. - -### Does Kubeapps support Operators? - -Yes! You can get started by following the [operators documentation](https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/tutorials/operators.md). - -### Slow response when listing namespaces - -Kubeapps uses the currently logged-in user credential to retrieve the list of all namespaces. If the user does not have permission to list namespaces, the backend will try again with its own service account. It will list all the namespaces and then will iterate through each namespace to check if the user has permissions to get secrets for each one. -This can lead to a slow response if the number of namespaces on the cluster is large. - -To reduce this response time, you can increase the number of checks that Kubeapps will perform in parallel (per connection) setting the value: `kubeappsapis.burst=` and `kubeappsapis.QPS=`. - -### Nginx Ipv6 error - -When starting the application with the `--set enableIPv6=true` option, the Nginx server present in the services `kubeapps` and `kubeapps-internal-dashboard` may fail with the following: - -```console -nginx: [emerg] socket() [::]:8080 failed (97: Address family not supported by protocol) -``` - -This usually means that your cluster is not compatible with IPv6. To deactivate it, install kubeapps with the flag: `--set enableIPv6=false`. - -### Forbidden error while installing the Chart - -If during installation you run into an error similar to: - -```console -Error: release kubeapps failed: clusterroles.rbac.authorization.k8s.io "kubeapps-apprepository-controller" is forbidden: attempt to grant extra privileges: [{[get] [batch] [cronjobs] [] []... -``` - -Or: - -```console -Error: namespaces "kubeapps" is forbidden: User "system:serviceaccount:kube-system:default" cannot get namespaces in the namespace "kubeapps" -``` - -It is possible, though uncommon, that your cluster does not have Role-Based Access Control (RBAC) enabled. To check if your cluster has RBAC you can run the following command: - -```console -kubectl api-versions -``` - -If the above command does not include entries for `rbac.authorization.k8s.io` you should perform the chart installation by setting `rbac.create=false`: - -```console -helm install --name kubeapps --namespace kubeapps oci://REGISTRY_NAME/REPOSITORY_NAME/kubeapps --set rbac.create=false -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -### Error while upgrading the Chart - -It is possible that when upgrading Kubeapps an error appears. That can be caused by a breaking change in the new chart or because the current chart installation is in an inconsistent state. If you find issues upgrading Kubeapps you can follow these steps: - -> Note: These steps assume that you have installed Kubeapps in the namespace `kubeapps` using the name `kubeapps`. If that is not the case replace the command with your namespace and/or name. -> Note: If you are upgrading from 2.3.1 see the [following section](#to-600). -> Note: If you are upgrading from 1.X to 2.X see the [following section](#to-400). - -1. (Optional) Backup your personal repositories (if you have any): - - ```console - kubectl get apprepository -A -o yaml > .yaml - ``` - -2. Delete Kubeapps: - - ```console - helm del --purge kubeapps - ``` - -3. (Optional) Delete the App Repositories CRD: - - > **Warning**: Do not run this step if you have more than one Kubeapps installation in your cluster. - - ```console - kubectl delete crd apprepositories.kubeapps.com - ``` - -4. (Optional) Clean the Kubeapps namespace: - - > **Warning**: Do not run this step if you have workloads other than Kubeapps in the `kubeapps` namespace. - - ```console - kubectl delete namespace kubeapps - ``` - -5. Install the latest version of Kubeapps (using any custom modifications you need): - - ```console - helm repo update - helm install --name kubeapps --namespace kubeapps oci://REGISTRY_NAME/REPOSITORY_NAME/kubeapps - ``` - - > Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -6. (Optional) Restore any repositories you backed up in the first step: - - ```console - kubectl apply -f .yaml - ``` - -After that you should be able to access the new version of Kubeapps. If the above doesn't work for you or you run into any other issues please open an [issue](https://github.com/vmware-tanzu/kubeapps/issues/new). - -### More questions? - -Feel free to [open an issue](https://github.com/vmware-tanzu/kubeapps/issues/new) if you have any questions! - -## Upgrading Kubeapps - -You can upgrade Kubeapps from the Kubeapps web interface. Select the namespace in which Kubeapps is installed (`kubeapps` if you followed the instructions in this guide) and click on the "Upgrade" button. Select the new version and confirm. - -You can also use the Helm CLI to upgrade Kubeapps, first ensure you have updated your local chart repository cache: - -```console -helm repo update -``` - -Now upgrade Kubeapps: - -```console -export RELEASE_NAME=kubeapps -helm upgrade $RELEASE_NAME oci://REGISTRY_NAME/REPOSITORY_NAME/kubeapps -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -If you find issues upgrading Kubeapps, check the [troubleshooting](#error-while-upgrading-the-chart) section. - -### To 17.0.0 - -This major updates the PostgreSQL subchart to its newest major, 16.0.0, which uses PostgreSQL 17.x. Follow the [official instructions](https://www.postgresql.org/docs/17/upgrading.html) to upgrade to 17.x. - -### To 16.0.0 - -This major updates the Redis® subchart to its newest major, 20.0.0. [Here](https://github.com/bitnami/charts/tree/main/bitnami/redis#to-2000) you can find more information about the changes introduced in that version. - -### To 15.0.0 - -This major bump changes the following security defaults: - -- `runAsGroup` is changed from `0` to `1001` -- `readOnlyRootFilesystem` is set to `true` -- `resourcesPreset` is changed from `none` to the minimum size working in our test suites (NOTE: `resourcesPreset` is not meant for production usage, but `resources` adapted to your use case). -- `global.compatibility.openshift.adaptSecurityContext` is changed from `disabled` to `auto`. -- The `networkPolicy` section has been normalized amongst all Bitnami charts. Compared to the previous approach, the values section has been simplified (check the Parameters section) and now it set to `enabled=true` by default. Egress traffic is allowed by default and ingress traffic is allowed by all pods but only to the ports set in `containerPorts`. -- The PostgreSQL subchart was updated to version 15.2.1, with the same security improvements. -- The Redis subchart was updated to version 19.0.2, with the same security improvements. - -This could potentially break any customization or init scripts used in your deployment. If this is the case, change the default values to the previous ones. - -### To 14.0.0 - -This major updates the PostgreSQL subchart to its newest major, 13.0.0. [Here](https://github.com/bitnami/charts/tree/master/bitnami/postgresql#to-1300) you can find more information about the changes introduced in that version. - -### To 13.0.0 - -This major updates the Redis® subchart to its newest major, 18.0.0. [Here](https://github.com/bitnami/charts/tree/main/bitnami/redis#to-1800) you can find more information about the changes introduced in that version. - -NOTE: Due to an error in our release process, Redis®' chart versions higher or equal than 17.15.4 already use Redis® 7.2 by default. - -### To 12.0.0 - -This major updates the PostgreSQL subchart to its newest major, 12.0.0. [Here](https://github.com/bitnami/charts/tree/master/bitnami/postgresql#to-1200) you can find more information about the changes introduced in that version. - -### To 8.0.0 - -This major release renames several values in this chart and adds missing features, in order to get aligned with the rest of the assets in the Bitnami charts repository. - -Additionally, it updates both the [PostgreSQL](https://github.com/bitnami/charts/tree/main/bitnami/postgresql) and the [Redis](https://github.com/bitnami/charts/tree/main/bitnami/redis) subcharts to their latest major versions, 11.0.0 and 16.0.0 respectively, where similar changes have been also performed. -Check [PostgreSQL Upgrading Notes](https://github.com/bitnami/charts/tree/master/bitnami/postgresql#to-1100) and [Redis Upgrading Notes](https://github.com/bitnami/charts/tree/main/bitnami/redis#to-1600) for more information. - -The following values have been renamed: - -- `frontend.service.port` renamed as `frontend.service.ports.http`. -- `frontend.service.nodePort` renamed as `frontend.service.nodePorts.http`. -- `frontend.containerPort` renamed as `frontend.containerPorts.http`. -- `dashboard.service.port` renamed as `dashboard.service.ports.http`. -- `dashboard.containerPort` renamed as `dashboard.containerPorts.http`. -- `apprepository.service.port` renamed as `apprepository.service.ports.http`. -- `apprepository.containerPort` renamed as `apprepository.containerPorts.http`. -- `kubeops.service.port` renamed as `kubeops.service.ports.http`. -- `kubeops.containerPort` renamed as `kubeops.containerPorts.http`. -- `assetsvc.service.port` renamed as `assetsvc.service.ports.http`. -- `assetsvc.containerPort` renamed as `assetsvc.containerPorts.http`. -- `authProxy.containerPort` renamed as `authProxy.containerPorts.proxy`. -- `authProxy.additionalFlags` renamed as `authProxy.extraFlags`, -- Pinniped Proxy service no longer uses `pinnipedProxy.containerPort`. Use `pinnipedProxy.service.ports.pinnipedProxy` to change the service port. -- `pinnipedProxy.containerPort` renamed as `pinnipedProxy.containerPorts.pinnipedProxy`. -- `postgresql.replication.enabled` has been removed. Use `postgresql.architecture` instead. -- `postgresql.postgresqlDatabase` renamed as `postgresql.auth.database`. -- `postgresql.postgresqlPassword` renamed as `postgresql.auth.password`. -- `postgresql.existingSecret` renamed as `postgresql.auth.existingSecret`. -- `redis.redisPassword` renamed as `redis.auth.password`. -- `redis.existingSecret` renamed as `redis.auth.existingSecret`. - -Note also that if you have an existing Postgresql secret that is used for Kubeapps, you will need to update the key from `postgresql-password` to `postgres-password`. - -### To 7.0.0 - -In this release, no breaking changes were included in Kubeapps (version 2.3.2). However, the chart adopted the standardizations included in the rest of the charts in the Bitnami catalog. - -Most of these standardizations simply add new parameters that allow to add more customizations such as adding custom env. variables, volumes or sidecar containers. That said, some of them include breaking changes: - -- Chart labels were adapted to follow the [Helm charts standard labels](https://helm.sh/docs/chart_best_practices/labels/#standard-labels). -- `securityContext.*` parameters are deprecated in favor of `XXX.podSecurityContext.*` and `XXX.containerSecurityContext.*`, where _XXX_ is placeholder you need to replace with the actual component(s). For instance, to modify the container security context for "kubeops" use `kubeops.podSecurityContext` and `kubeops.containerSecurityContext` parameters. - -### To 6.0.0 - -Kubeapps 2.3.1 (Chart version 6.0.0) introduces some breaking changes. Helm-specific functionality has been removed in order to support other installation methods (like using YAML manifests, [`kapp`](https://carvel.dev/kapp) or [`kustomize`](https://kustomize.io/)). Because of that, there are some steps required before upgrading from a previous version: - -1. Kubeapps will no longer create a database secret for you automatically but rather will rely on the default behavior of the PostgreSQL chart. If you try to upgrade Kubeapps and you installed it without setting a password, you will get the following error: - - ```console - Error: UPGRADE FAILED: template: kubeapps/templates/NOTES.txt:73:4: executing "kubeapps/templates/NOTES.txt" at : error calling include: template: kubeapps/charts/common/templates/_errors.tpl:18:48: executing "common.errors.upgrade.passwords.empty" at : error calling fail: - PASSWORDS ERROR: you must provide your current passwords when upgrade the release - 'postgresql.postgresqlPassword' must not be empty, please add '--set postgresql.postgresqlPassword=$POSTGRESQL_PASSWORD' to the command. To get the current value: - ``` - - The error gives you generic instructions for retrieving the PostgreSQL password, but if you have installed a Kubeapps version prior to 2.3.1, the name of the secret will differ. Run the following command: - - ```console - export POSTGRESQL_PASSWORD=$(kubectl get secret --namespace "kubeapps" kubeapps-db -o jsonpath="{.data.postgresql-password}" | base64 -d) - ``` - - > NOTE: Replace the namespace in the command with the namespace in which you have deployed Kubeapps. - - Make sure that you have stored the password in the variable `$POSTGRESQL_PASSWORD` before continuing with the next issue. - -2. The chart `initialRepos` are no longer installed using [Helm hooks](https://helm.sh/docs/topics/charts_hooks/), which caused these repos not to be handled by Helm after the first installation. Now they will be tracked for every update. However, if you do not delete the existing ones, it will fail to update with: - -```console -Error: UPGRADE FAILED: rendered manifests contain a resource that already exists. Unable to continue with update: AppRepository "bitnami" in namespace "kubeapps" exists and cannot be imported into the current release: invalid ownership metadata; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "kubeapps"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "kubeapps" -``` - -To bypass this issue, you will need to before delete all the initialRepos from the chart values (only the `bitnami` repo by default): - -```console -kubectl delete apprepositories.kubeapps.com -n kubeapps bitnami -``` - -> NOTE: Replace the namespace in the command with the namespace in which you have deployed Kubeapps. - -After that, you will be able to upgrade Kubeapps to 2.3.1 using the existing database secret: - -> **WARNING**: Make sure that the variable `$POSTGRESQL_PASSWORD` is properly populated. Setting a wrong (or empty) password will corrupt the release. - -```console -helm upgrade kubeapps oci://REGISTRY_NAME/REPOSITORY_NAME/kubeapps -n kubeapps --set postgresql.postgresqlPassword=$POSTGRESQL_PASSWORD -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -### To 5.0.0 - -[On November 13, 2020, Helm 2 support was formally finished](https://github.com/helm/charts#status-of-the-project), this major version is the result of the required changes applied to the Helm Chart to be able to incorporate the different features added in Helm 3 and to be consistent with the Helm project itself regarding the Helm 2 EOL. - -#### What changes were introduced in this major version? - -- Previous versions of this Helm Chart use `apiVersion: v1` (installable by both Helm 2 and 3), this Helm Chart was updated to `apiVersion: v2` (installable by Helm 3 only). [Here](https://helm.sh/docs/topics/charts/#the-apiversion-field) you can find more information about the `apiVersion` field. -- Move dependency information from the _requirements.yaml_ to the _Chart.yaml_ -- After running `helm dependency update`, a _Chart.lock_ file is generated containing the same structure used in the previous _requirements.lock_ -- The different fields present in the _Chart.yaml_ file has been ordered alphabetically in a homogeneous way for all the Bitnami Helm Charts -- In the case of PostgreSQL subchart, apart from the same changes that are described in this section, there are also other major changes due to the _master/slave_ nomenclature was replaced by _primary/readReplica_. [Here](https://github.com/bitnami/charts/pull/4385) you can find more information about the changes introduced. - -#### Considerations when upgrading to this version - -- If you want to upgrade to this version using Helm 2, this scenario is not supported as this version does not support Helm 2 anymore -- If you installed the previous version with Helm 2 and wants to upgrade to this version with Helm 3, please refer to the [official Helm documentation](https://helm.sh/docs/topics/v2_v3_migration/#migration-use-cases) about migrating from Helm 2 to 3 -- If you want to upgrade to this version from a previous one installed with Helm 3, you should not face any issues related to the new `apiVersion`. Due to the PostgreSQL major version bump, it is necessary to remove the existing statefulsets: - -> Note: The command below assumes that Kubeapps has been deployed in the kubeapps namespace using "kubeapps" as release name, if that is not the case, adapt the command accordingly. - -```console -kubectl delete statefulset -n kubeapps kubeapps-postgresql-master kubeapps-postgresql-slave -``` - -#### Useful links - -- -- -- - -### To 4.0.0 - -Kubeapps 2.0 (Chart version 4.0.0) introduces some breaking changes: - -- Helm 2 is no longer supported. If you are still using some Helm 2 charts, [migrate them with the available tools](https://helm.sh/docs/topics/v2_v3_migration/). Note that some charts (but not all of them) may require to be migrated to the [new Chart specification (v2)](https://helm.sh/docs/topics/charts/#the-apiversion-field). If you are facing any issue managing this migration and Kubeapps, please open a new issue! -- MongoDB® is no longer supported. Since 2.0, the only database supported is PostgreSQL. -- PostgreSQL chart dependency has been upgraded to a new major version. - -Due to the last point, it is necessary to run a command before upgrading to Kubeapps 2.0: - -> Note: The command below assumes that Kubeapps has been deployed in the kubeapps namespace using "kubeapps" as release name, if that is not the case, adapt the command accordingly. - -```console -kubectl delete statefulset -n kubeapps kubeapps-postgresql-master kubeapps-postgresql-slave -``` - -After that, you should be able to upgrade Kubeapps as always and the database will be repopulated. - -## License - -Copyright © 2024 Broadcom. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. \ No newline at end of file diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/Chart.yaml b/packages/system/dashboard/charts/kubeapps/charts/common/Chart.yaml deleted file mode 100644 index 0d437c4c..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/Chart.yaml +++ /dev/null @@ -1,23 +0,0 @@ -annotations: - category: Infrastructure - licenses: Apache-2.0 -apiVersion: v2 -appVersion: 2.26.0 -description: A Library Helm Chart for grouping common logic between bitnami charts. - This chart is not deployable by itself. -home: https://bitnami.com -icon: https://bitnami.com/downloads/logos/bitnami-mark.png -keywords: -- common -- helper -- template -- function -- bitnami -maintainers: -- name: Broadcom, Inc. All Rights Reserved. - url: https://github.com/bitnami/charts -name: common -sources: -- https://github.com/bitnami/charts/tree/main/bitnami/common -type: library -version: 2.26.0 diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/README.md b/packages/system/dashboard/charts/kubeapps/charts/common/README.md deleted file mode 100644 index fee26c99..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/README.md +++ /dev/null @@ -1,235 +0,0 @@ -# Bitnami Common Library Chart - -A [Helm Library Chart](https://helm.sh/docs/topics/library_charts/#helm) for grouping common logic between Bitnami charts. - -## TL;DR - -```yaml -dependencies: - - name: common - version: 2.x.x - repository: oci://registry-1.docker.io/bitnamicharts -``` - -```console -helm dependency update -``` - -```yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "common.names.fullname" . }} -data: - myvalue: "Hello World" -``` - -Looking to use our applications in production? Try [VMware Tanzu Application Catalog](https://bitnami.com/enterprise), the commercial edition of the Bitnami catalog. - -## Introduction - -This chart provides a common template helpers which can be used to develop new charts using [Helm](https://helm.sh) package manager. - -Bitnami charts can be used with [Kubeapps](https://kubeapps.dev/) for deployment and management of Helm Charts in clusters. - -## Prerequisites - -- Kubernetes 1.23+ -- Helm 3.8.0+ - -## Parameters - -## Special input schemas - -### ImageRoot - -```yaml -registry: - type: string - description: Docker registry where the image is located - example: docker.io - -repository: - type: string - description: Repository and image name - example: bitnami/nginx - -tag: - type: string - description: image tag - example: 1.16.1-debian-10-r63 - -pullPolicy: - type: string - description: Specify a imagePullPolicy. Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' - -pullSecrets: - type: array - items: - type: string - description: Optionally specify an array of imagePullSecrets (evaluated as templates). - -debug: - type: boolean - description: Set to true if you would like to see extra information on logs - example: false - -## An instance would be: -# registry: docker.io -# repository: bitnami/nginx -# tag: 1.16.1-debian-10-r63 -# pullPolicy: IfNotPresent -# debug: false -``` - -### Persistence - -```yaml -enabled: - type: boolean - description: Whether enable persistence. - example: true - -storageClass: - type: string - description: Ghost data Persistent Volume Storage Class, If set to "-", storageClassName: "" which disables dynamic provisioning. - example: "-" - -accessMode: - type: string - description: Access mode for the Persistent Volume Storage. - example: ReadWriteOnce - -size: - type: string - description: Size the Persistent Volume Storage. - example: 8Gi - -path: - type: string - description: Path to be persisted. - example: /bitnami - -## An instance would be: -# enabled: true -# storageClass: "-" -# accessMode: ReadWriteOnce -# size: 8Gi -# path: /bitnami -``` - -### ExistingSecret - -```yaml -name: - type: string - description: Name of the existing secret. - example: mySecret -keyMapping: - description: Mapping between the expected key name and the name of the key in the existing secret. - type: object - -## An instance would be: -# name: mySecret -# keyMapping: -# password: myPasswordKey -``` - -#### Example of use - -When we store sensitive data for a deployment in a secret, some times we want to give to users the possibility of using theirs existing secrets. - -```yaml -# templates/secret.yaml ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "common.names.fullname" . }} - labels: - app: {{ include "common.names.fullname" . }} -type: Opaque -data: - password: {{ .Values.password | b64enc | quote }} - -# templates/dpl.yaml ---- -... - env: - - name: PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "common.secrets.name" (dict "existingSecret" .Values.existingSecret "context" $) }} - key: {{ include "common.secrets.key" (dict "existingSecret" .Values.existingSecret "key" "password") }} -... - -# values.yaml ---- -name: mySecret -keyMapping: - password: myPasswordKey -``` - -### ValidateValue - -#### NOTES.txt - -```console -{{- $validateValueConf00 := (dict "valueKey" "path.to.value00" "secret" "secretName" "field" "password-00") -}} -{{- $validateValueConf01 := (dict "valueKey" "path.to.value01" "secret" "secretName" "field" "password-01") -}} - -{{ include "common.validations.values.multiple.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} -``` - -If we force those values to be empty we will see some alerts - -```console -helm install test mychart --set path.to.value00="",path.to.value01="" - 'path.to.value00' must not be empty, please add '--set path.to.value00=$PASSWORD_00' to the command. To get the current value: - - export PASSWORD_00=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-00}" | base64 -d) - - 'path.to.value01' must not be empty, please add '--set path.to.value01=$PASSWORD_01' to the command. To get the current value: - - export PASSWORD_01=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-01}" | base64 -d) -``` - -## Upgrading - -### To 1.0.0 - -[On November 13, 2020, Helm v2 support was formally finished](https://github.com/helm/charts#status-of-the-project), this major version is the result of the required changes applied to the Helm Chart to be able to incorporate the different features added in Helm v3 and to be consistent with the Helm project itself regarding the Helm v2 EOL. - -#### What changes were introduced in this major version? - -- Previous versions of this Helm Chart use `apiVersion: v1` (installable by both Helm 2 and 3), this Helm Chart was updated to `apiVersion: v2` (installable by Helm 3 only). [Here](https://helm.sh/docs/topics/charts/#the-apiversion-field) you can find more information about the `apiVersion` field. -- Use `type: library`. [Here](https://v3.helm.sh/docs/faq/#library-chart-support) you can find more information. -- The different fields present in the *Chart.yaml* file has been ordered alphabetically in a homogeneous way for all the Bitnami Helm Charts - -#### Considerations when upgrading to this version - -- If you want to upgrade to this version from a previous one installed with Helm v3, you shouldn't face any issues -- If you want to upgrade to this version using Helm v2, this scenario is not supported as this version doesn't support Helm v2 anymore -- If you installed the previous version with Helm v2 and wants to upgrade to this version with Helm v3, please refer to the [official Helm documentation](https://helm.sh/docs/topics/v2_v3_migration/#migration-use-cases) about migrating from Helm v2 to v3 - -#### Useful links - -- -- -- - -## License - -Copyright © 2024 Broadcom. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_affinities.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/_affinities.tpl deleted file mode 100644 index d387dbe6..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_affinities.tpl +++ /dev/null @@ -1,155 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} - -{{/* -Return a soft nodeAffinity definition -{{ include "common.affinities.nodes.soft" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} -*/}} -{{- define "common.affinities.nodes.soft" -}} -preferredDuringSchedulingIgnoredDuringExecution: - - preference: - matchExpressions: - - key: {{ .key }} - operator: In - values: - {{- range .values }} - - {{ . | quote }} - {{- end }} - weight: 1 -{{- end -}} - -{{/* -Return a hard nodeAffinity definition -{{ include "common.affinities.nodes.hard" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} -*/}} -{{- define "common.affinities.nodes.hard" -}} -requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: {{ .key }} - operator: In - values: - {{- range .values }} - - {{ . | quote }} - {{- end }} -{{- end -}} - -{{/* -Return a nodeAffinity definition -{{ include "common.affinities.nodes" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} -*/}} -{{- define "common.affinities.nodes" -}} - {{- if eq .type "soft" }} - {{- include "common.affinities.nodes.soft" . -}} - {{- else if eq .type "hard" }} - {{- include "common.affinities.nodes.hard" . -}} - {{- end -}} -{{- end -}} - -{{/* -Return a topologyKey definition -{{ include "common.affinities.topologyKey" (dict "topologyKey" "BAR") -}} -*/}} -{{- define "common.affinities.topologyKey" -}} -{{ .topologyKey | default "kubernetes.io/hostname" -}} -{{- end -}} - -{{/* -Return a soft podAffinity/podAntiAffinity definition -{{ include "common.affinities.pods.soft" (dict "component" "FOO" "customLabels" .Values.podLabels "extraMatchLabels" .Values.extraMatchLabels "topologyKey" "BAR" "extraPodAffinityTerms" .Values.extraPodAffinityTerms "extraNamespaces" (list "namespace1" "namespace2") "context" $) -}} -*/}} -{{- define "common.affinities.pods.soft" -}} -{{- $component := default "" .component -}} -{{- $customLabels := default (dict) .customLabels -}} -{{- $extraMatchLabels := default (dict) .extraMatchLabels -}} -{{- $extraPodAffinityTerms := default (list) .extraPodAffinityTerms -}} -{{- $extraNamespaces := default (list) .extraNamespaces -}} -preferredDuringSchedulingIgnoredDuringExecution: - - podAffinityTerm: - labelSelector: - matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" .context )) | nindent 10 }} - {{- if not (empty $component) }} - {{ printf "app.kubernetes.io/component: %s" $component }} - {{- end }} - {{- range $key, $value := $extraMatchLabels }} - {{ $key }}: {{ $value | quote }} - {{- end }} - {{- if $extraNamespaces }} - namespaces: - - {{ .context.Release.Namespace }} - {{- with $extraNamespaces }} - {{ include "common.tplvalues.render" (dict "value" . "context" $) | nindent 8 }} - {{- end }} - {{- end }} - topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} - weight: 1 - {{- range $extraPodAffinityTerms }} - - podAffinityTerm: - labelSelector: - matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" $.context )) | nindent 10 }} - {{- if not (empty $component) }} - {{ printf "app.kubernetes.io/component: %s" $component }} - {{- end }} - {{- range $key, $value := .extraMatchLabels }} - {{ $key }}: {{ $value | quote }} - {{- end }} - topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} - weight: {{ .weight | default 1 -}} - {{- end -}} -{{- end -}} - -{{/* -Return a hard podAffinity/podAntiAffinity definition -{{ include "common.affinities.pods.hard" (dict "component" "FOO" "customLabels" .Values.podLabels "extraMatchLabels" .Values.extraMatchLabels "topologyKey" "BAR" "extraPodAffinityTerms" .Values.extraPodAffinityTerms "extraNamespaces" (list "namespace1" "namespace2") "context" $) -}} -*/}} -{{- define "common.affinities.pods.hard" -}} -{{- $component := default "" .component -}} -{{- $customLabels := default (dict) .customLabels -}} -{{- $extraMatchLabels := default (dict) .extraMatchLabels -}} -{{- $extraPodAffinityTerms := default (list) .extraPodAffinityTerms -}} -{{- $extraNamespaces := default (list) .extraNamespaces -}} -requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" .context )) | nindent 8 }} - {{- if not (empty $component) }} - {{ printf "app.kubernetes.io/component: %s" $component }} - {{- end }} - {{- range $key, $value := $extraMatchLabels }} - {{ $key }}: {{ $value | quote }} - {{- end }} - {{- if $extraNamespaces }} - namespaces: - - {{ .context.Release.Namespace }} - {{- with $extraNamespaces }} - {{ include "common.tplvalues.render" (dict "value" . "context" $) | nindent 8 }} - {{- end }} - {{- end }} - topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} - {{- range $extraPodAffinityTerms }} - - labelSelector: - matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" $.context )) | nindent 8 }} - {{- if not (empty $component) }} - {{ printf "app.kubernetes.io/component: %s" $component }} - {{- end }} - {{- range $key, $value := .extraMatchLabels }} - {{ $key }}: {{ $value | quote }} - {{- end }} - topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} - {{- end -}} -{{- end -}} - -{{/* -Return a podAffinity/podAntiAffinity definition -{{ include "common.affinities.pods" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} -*/}} -{{- define "common.affinities.pods" -}} - {{- if eq .type "soft" }} - {{- include "common.affinities.pods.soft" . -}} - {{- else if eq .type "hard" }} - {{- include "common.affinities.pods.hard" . -}} - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_capabilities.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/_capabilities.tpl deleted file mode 100644 index 2fe81d32..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_capabilities.tpl +++ /dev/null @@ -1,229 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} - -{{/* -Return the target Kubernetes version -*/}} -{{- define "common.capabilities.kubeVersion" -}} -{{- default (default .Capabilities.KubeVersion.Version .Values.kubeVersion) ((.Values.global).kubeVersion) -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for poddisruptionbudget. -*/}} -{{- define "common.capabilities.policy.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.21-0" $kubeVersion) -}} -{{- print "policy/v1beta1" -}} -{{- else -}} -{{- print "policy/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for networkpolicy. -*/}} -{{- define "common.capabilities.networkPolicy.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.7-0" $kubeVersion) -}} -{{- print "extensions/v1beta1" -}} -{{- else -}} -{{- print "networking.k8s.io/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for cronjob. -*/}} -{{- define "common.capabilities.cronjob.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.21-0" $kubeVersion) -}} -{{- print "batch/v1beta1" -}} -{{- else -}} -{{- print "batch/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for daemonset. -*/}} -{{- define "common.capabilities.daemonset.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} -{{- print "extensions/v1beta1" -}} -{{- else -}} -{{- print "apps/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for deployment. -*/}} -{{- define "common.capabilities.deployment.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} -{{- print "extensions/v1beta1" -}} -{{- else -}} -{{- print "apps/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for statefulset. -*/}} -{{- define "common.capabilities.statefulset.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} -{{- print "apps/v1beta1" -}} -{{- else -}} -{{- print "apps/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for ingress. -*/}} -{{- define "common.capabilities.ingress.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if (.Values.ingress).apiVersion -}} -{{- .Values.ingress.apiVersion -}} -{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} -{{- print "extensions/v1beta1" -}} -{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.19-0" $kubeVersion) -}} -{{- print "networking.k8s.io/v1beta1" -}} -{{- else -}} -{{- print "networking.k8s.io/v1" -}} -{{- end }} -{{- end -}} - -{{/* -Return the appropriate apiVersion for RBAC resources. -*/}} -{{- define "common.capabilities.rbac.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.17-0" $kubeVersion) -}} -{{- print "rbac.authorization.k8s.io/v1beta1" -}} -{{- else -}} -{{- print "rbac.authorization.k8s.io/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for CRDs. -*/}} -{{- define "common.capabilities.crd.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.19-0" $kubeVersion) -}} -{{- print "apiextensions.k8s.io/v1beta1" -}} -{{- else -}} -{{- print "apiextensions.k8s.io/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for APIService. -*/}} -{{- define "common.capabilities.apiService.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.10-0" $kubeVersion) -}} -{{- print "apiregistration.k8s.io/v1beta1" -}} -{{- else -}} -{{- print "apiregistration.k8s.io/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for Horizontal Pod Autoscaler. -*/}} -{{- define "common.capabilities.hpa.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" .context -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} -{{- if .beta2 -}} -{{- print "autoscaling/v2beta2" -}} -{{- else -}} -{{- print "autoscaling/v2beta1" -}} -{{- end -}} -{{- else -}} -{{- print "autoscaling/v2" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for Vertical Pod Autoscaler. -*/}} -{{- define "common.capabilities.vpa.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" .context -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} -{{- if .beta2 -}} -{{- print "autoscaling/v2beta2" -}} -{{- else -}} -{{- print "autoscaling/v2beta1" -}} -{{- end -}} -{{- else -}} -{{- print "autoscaling/v2" -}} -{{- end -}} -{{- end -}} - -{{/* -Returns true if PodSecurityPolicy is supported -*/}} -{{- define "common.capabilities.psp.supported" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if or (empty $kubeVersion) (semverCompare "<1.25-0" $kubeVersion) -}} - {{- true -}} -{{- end -}} -{{- end -}} - -{{/* -Returns true if AdmissionConfiguration is supported -*/}} -{{- define "common.capabilities.admissionConfiguration.supported" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if or (empty $kubeVersion) (not (semverCompare "<1.23-0" $kubeVersion)) -}} - {{- true -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for AdmissionConfiguration. -*/}} -{{- define "common.capabilities.admissionConfiguration.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} -{{- print "apiserver.config.k8s.io/v1alpha1" -}} -{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.25-0" $kubeVersion) -}} -{{- print "apiserver.config.k8s.io/v1beta1" -}} -{{- else -}} -{{- print "apiserver.config.k8s.io/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for PodSecurityConfiguration. -*/}} -{{- define "common.capabilities.podSecurityConfiguration.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} -{{- print "pod-security.admission.config.k8s.io/v1alpha1" -}} -{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.25-0" $kubeVersion) -}} -{{- print "pod-security.admission.config.k8s.io/v1beta1" -}} -{{- else -}} -{{- print "pod-security.admission.config.k8s.io/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Returns true if the used Helm version is 3.3+. -A way to check the used Helm version was not introduced until version 3.3.0 with .Capabilities.HelmVersion, which contains an additional "{}}" structure. -This check is introduced as a regexMatch instead of {{ if .Capabilities.HelmVersion }} because checking for the key HelmVersion in <3.3 results in a "interface not found" error. -**To be removed when the catalog's minimun Helm version is 3.3** -*/}} -{{- define "common.capabilities.supportsHelmVersion" -}} -{{- if regexMatch "{(v[0-9])*[^}]*}}$" (.Capabilities | toString ) }} - {{- true -}} -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_compatibility.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/_compatibility.tpl deleted file mode 100644 index a61588d6..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_compatibility.tpl +++ /dev/null @@ -1,46 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} - -{{/* -Return true if the detected platform is Openshift -Usage: -{{- include "common.compatibility.isOpenshift" . -}} -*/}} -{{- define "common.compatibility.isOpenshift" -}} -{{- if .Capabilities.APIVersions.Has "security.openshift.io/v1" -}} -{{- true -}} -{{- end -}} -{{- end -}} - -{{/* -Render a compatible securityContext depending on the platform. By default it is maintained as it is. In other platforms like Openshift we remove default user/group values that do not work out of the box with the restricted-v1 SCC -Usage: -{{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.containerSecurityContext "context" $) -}} -*/}} -{{- define "common.compatibility.renderSecurityContext" -}} -{{- $adaptedContext := .secContext -}} - -{{- if (((.context.Values.global).compatibility).openshift) -}} - {{- if or (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "force") (and (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "auto") (include "common.compatibility.isOpenshift" .context)) -}} - {{/* Remove incompatible user/group values that do not work in Openshift out of the box */}} - {{- $adaptedContext = omit $adaptedContext "fsGroup" "runAsUser" "runAsGroup" -}} - {{- if not .secContext.seLinuxOptions -}} - {{/* If it is an empty object, we remove it from the resulting context because it causes validation issues */}} - {{- $adaptedContext = omit $adaptedContext "seLinuxOptions" -}} - {{- end -}} - {{- end -}} -{{- end -}} -{{/* Remove empty seLinuxOptions object if global.compatibility.omitEmptySeLinuxOptions is set to true */}} -{{- if and (((.context.Values.global).compatibility).omitEmptySeLinuxOptions) (not .secContext.seLinuxOptions) -}} - {{- $adaptedContext = omit $adaptedContext "seLinuxOptions" -}} -{{- end -}} -{{/* Remove fields that are disregarded when running the container in privileged mode */}} -{{- if $adaptedContext.privileged -}} - {{- $adaptedContext = omit $adaptedContext "capabilities" "seLinuxOptions" -}} -{{- end -}} -{{- omit $adaptedContext "enabled" | toYaml -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_errors.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/_errors.tpl deleted file mode 100644 index e9653651..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_errors.tpl +++ /dev/null @@ -1,28 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Through error when upgrading using empty passwords values that must not be empty. - -Usage: -{{- $validationError00 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password00" "secret" "secretName" "field" "password-00") -}} -{{- $validationError01 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password01" "secret" "secretName" "field" "password-01") -}} -{{ include "common.errors.upgrade.passwords.empty" (dict "validationErrors" (list $validationError00 $validationError01) "context" $) }} - -Required password params: - - validationErrors - String - Required. List of validation strings to be return, if it is empty it won't throw error. - - context - Context - Required. Parent context. -*/}} -{{- define "common.errors.upgrade.passwords.empty" -}} - {{- $validationErrors := join "" .validationErrors -}} - {{- if and $validationErrors .context.Release.IsUpgrade -}} - {{- $errorString := "\nPASSWORDS ERROR: You must provide your current passwords when upgrading the release." -}} - {{- $errorString = print $errorString "\n Note that even after reinstallation, old credentials may be needed as they may be kept in persistent volume claims." -}} - {{- $errorString = print $errorString "\n Further information can be obtained at https://docs.bitnami.com/general/how-to/troubleshoot-helm-chart-issues/#credential-errors-while-upgrading-chart-releases" -}} - {{- $errorString = print $errorString "\n%s" -}} - {{- printf $errorString $validationErrors | fail -}} - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_images.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/_images.tpl deleted file mode 100644 index 76bb7ce4..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_images.tpl +++ /dev/null @@ -1,115 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Return the proper image name. -If image tag and digest are not defined, termination fallbacks to chart appVersion. -{{ include "common.images.image" ( dict "imageRoot" .Values.path.to.the.image "global" .Values.global "chart" .Chart ) }} -*/}} -{{- define "common.images.image" -}} -{{- $registryName := default .imageRoot.registry ((.global).imageRegistry) -}} -{{- $repositoryName := .imageRoot.repository -}} -{{- $separator := ":" -}} -{{- $termination := .imageRoot.tag | toString -}} - -{{- if not .imageRoot.tag }} - {{- if .chart }} - {{- $termination = .chart.AppVersion | toString -}} - {{- end -}} -{{- end -}} -{{- if .imageRoot.digest }} - {{- $separator = "@" -}} - {{- $termination = .imageRoot.digest | toString -}} -{{- end -}} -{{- if $registryName }} - {{- printf "%s/%s%s%s" $registryName $repositoryName $separator $termination -}} -{{- else -}} - {{- printf "%s%s%s" $repositoryName $separator $termination -}} -{{- end -}} -{{- end -}} - -{{/* -Return the proper Docker Image Registry Secret Names (deprecated: use common.images.renderPullSecrets instead) -{{ include "common.images.pullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global) }} -*/}} -{{- define "common.images.pullSecrets" -}} - {{- $pullSecrets := list }} - - {{- range ((.global).imagePullSecrets) -}} - {{- if kindIs "map" . -}} - {{- $pullSecrets = append $pullSecrets .name -}} - {{- else -}} - {{- $pullSecrets = append $pullSecrets . -}} - {{- end }} - {{- end -}} - - {{- range .images -}} - {{- range .pullSecrets -}} - {{- if kindIs "map" . -}} - {{- $pullSecrets = append $pullSecrets .name -}} - {{- else -}} - {{- $pullSecrets = append $pullSecrets . -}} - {{- end -}} - {{- end -}} - {{- end -}} - - {{- if (not (empty $pullSecrets)) -}} -imagePullSecrets: - {{- range $pullSecrets | uniq }} - - name: {{ . }} - {{- end }} - {{- end }} -{{- end -}} - -{{/* -Return the proper Docker Image Registry Secret Names evaluating values as templates -{{ include "common.images.renderPullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "context" $) }} -*/}} -{{- define "common.images.renderPullSecrets" -}} - {{- $pullSecrets := list }} - {{- $context := .context }} - - {{- range (($context.Values.global).imagePullSecrets) -}} - {{- if kindIs "map" . -}} - {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" $context)) -}} - {{- else -}} - {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" $context)) -}} - {{- end -}} - {{- end -}} - - {{- range .images -}} - {{- range .pullSecrets -}} - {{- if kindIs "map" . -}} - {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" $context)) -}} - {{- else -}} - {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" $context)) -}} - {{- end -}} - {{- end -}} - {{- end -}} - - {{- if (not (empty $pullSecrets)) -}} -imagePullSecrets: - {{- range $pullSecrets | uniq }} - - name: {{ . }} - {{- end }} - {{- end }} -{{- end -}} - -{{/* -Return the proper image version (ingores image revision/prerelease info & fallbacks to chart appVersion) -{{ include "common.images.version" ( dict "imageRoot" .Values.path.to.the.image "chart" .Chart ) }} -*/}} -{{- define "common.images.version" -}} -{{- $imageTag := .imageRoot.tag | toString -}} -{{/* regexp from https://github.com/Masterminds/semver/blob/23f51de38a0866c5ef0bfc42b3f735c73107b700/version.go#L41-L44 */}} -{{- if regexMatch `^([0-9]+)(\.[0-9]+)?(\.[0-9]+)?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?$` $imageTag -}} - {{- $version := semver $imageTag -}} - {{- printf "%d.%d.%d" $version.Major $version.Minor $version.Patch -}} -{{- else -}} - {{- print .chart.AppVersion -}} -{{- end -}} -{{- end -}} - diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_ingress.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/_ingress.tpl deleted file mode 100644 index 7d2b8798..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_ingress.tpl +++ /dev/null @@ -1,73 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} - -{{/* -Generate backend entry that is compatible with all Kubernetes API versions. - -Usage: -{{ include "common.ingress.backend" (dict "serviceName" "backendName" "servicePort" "backendPort" "context" $) }} - -Params: - - serviceName - String. Name of an existing service backend - - servicePort - String/Int. Port name (or number) of the service. It will be translated to different yaml depending if it is a string or an integer. - - context - Dict - Required. The context for the template evaluation. -*/}} -{{- define "common.ingress.backend" -}} -{{- $apiVersion := (include "common.capabilities.ingress.apiVersion" .context) -}} -{{- if or (eq $apiVersion "extensions/v1beta1") (eq $apiVersion "networking.k8s.io/v1beta1") -}} -serviceName: {{ .serviceName }} -servicePort: {{ .servicePort }} -{{- else -}} -service: - name: {{ .serviceName }} - port: - {{- if typeIs "string" .servicePort }} - name: {{ .servicePort }} - {{- else if or (typeIs "int" .servicePort) (typeIs "float64" .servicePort) }} - number: {{ .servicePort | int }} - {{- end }} -{{- end -}} -{{- end -}} - -{{/* -Print "true" if the API pathType field is supported -Usage: -{{ include "common.ingress.supportsPathType" . }} -*/}} -{{- define "common.ingress.supportsPathType" -}} -{{- if (semverCompare "<1.18-0" (include "common.capabilities.kubeVersion" .)) -}} -{{- print "false" -}} -{{- else -}} -{{- print "true" -}} -{{- end -}} -{{- end -}} - -{{/* -Returns true if the ingressClassname field is supported -Usage: -{{ include "common.ingress.supportsIngressClassname" . }} -*/}} -{{- define "common.ingress.supportsIngressClassname" -}} -{{- if semverCompare "<1.18-0" (include "common.capabilities.kubeVersion" .) -}} -{{- print "false" -}} -{{- else -}} -{{- print "true" -}} -{{- end -}} -{{- end -}} - -{{/* -Return true if cert-manager required annotations for TLS signed -certificates are set in the Ingress annotations -Ref: https://cert-manager.io/docs/usage/ingress/#supported-annotations -Usage: -{{ include "common.ingress.certManagerRequest" ( dict "annotations" .Values.path.to.the.ingress.annotations ) }} -*/}} -{{- define "common.ingress.certManagerRequest" -}} -{{ if or (hasKey .annotations "cert-manager.io/cluster-issuer") (hasKey .annotations "cert-manager.io/issuer") (hasKey .annotations "kubernetes.io/tls-acme") }} - {{- true -}} -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_labels.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/_labels.tpl deleted file mode 100644 index 0a0cc548..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_labels.tpl +++ /dev/null @@ -1,46 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} - -{{/* -Kubernetes standard labels -{{ include "common.labels.standard" (dict "customLabels" .Values.commonLabels "context" $) -}} -*/}} -{{- define "common.labels.standard" -}} -{{- if and (hasKey . "customLabels") (hasKey . "context") -}} -{{- $default := dict "app.kubernetes.io/name" (include "common.names.name" .context) "helm.sh/chart" (include "common.names.chart" .context) "app.kubernetes.io/instance" .context.Release.Name "app.kubernetes.io/managed-by" .context.Release.Service -}} -{{- with .context.Chart.AppVersion -}} -{{- $_ := set $default "app.kubernetes.io/version" . -}} -{{- end -}} -{{ template "common.tplvalues.merge" (dict "values" (list .customLabels $default) "context" .context) }} -{{- else -}} -app.kubernetes.io/name: {{ include "common.names.name" . }} -helm.sh/chart: {{ include "common.names.chart" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- with .Chart.AppVersion }} -app.kubernetes.io/version: {{ . | quote }} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Labels used on immutable fields such as deploy.spec.selector.matchLabels or svc.spec.selector -{{ include "common.labels.matchLabels" (dict "customLabels" .Values.podLabels "context" $) -}} - -We don't want to loop over custom labels appending them to the selector -since it's very likely that it will break deployments, services, etc. -However, it's important to overwrite the standard labels if the user -overwrote them on metadata.labels fields. -*/}} -{{- define "common.labels.matchLabels" -}} -{{- if and (hasKey . "customLabels") (hasKey . "context") -}} -{{ merge (pick (include "common.tplvalues.render" (dict "value" .customLabels "context" .context) | fromYaml) "app.kubernetes.io/name" "app.kubernetes.io/instance") (dict "app.kubernetes.io/name" (include "common.names.name" .context) "app.kubernetes.io/instance" .context.Release.Name ) | toYaml }} -{{- else -}} -app.kubernetes.io/name: {{ include "common.names.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_names.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/_names.tpl deleted file mode 100644 index ba839568..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_names.tpl +++ /dev/null @@ -1,71 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "common.names.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "common.names.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "common.names.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create a default fully qualified dependency name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -Usage: -{{ include "common.names.dependency.fullname" (dict "chartName" "dependency-chart-name" "chartValues" .Values.dependency-chart "context" $) }} -*/}} -{{- define "common.names.dependency.fullname" -}} -{{- if .chartValues.fullnameOverride -}} -{{- .chartValues.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .chartName .chartValues.nameOverride -}} -{{- if contains $name .context.Release.Name -}} -{{- .context.Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .context.Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Allow the release namespace to be overridden for multi-namespace deployments in combined charts. -*/}} -{{- define "common.names.namespace" -}} -{{- default .Release.Namespace .Values.namespaceOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create a fully qualified app name adding the installation's namespace. -*/}} -{{- define "common.names.fullname.namespace" -}} -{{- printf "%s-%s" (include "common.names.fullname" .) (include "common.names.namespace" .) | trunc 63 | trimSuffix "-" -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_resources.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/_resources.tpl deleted file mode 100644 index d8a43e1c..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_resources.tpl +++ /dev/null @@ -1,50 +0,0 @@ -{{/* -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 "common.resources.preset" (dict "type" "nano") -}} -*/}} -{{- define "common.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") - ) - "micro" (dict - "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") - ) - "small" (dict - "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") - ) - "medium" (dict - "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "1536Mi" "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") - ) - "xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "3.0" "memory" "6144Mi" "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") - ) - }} -{{- if hasKey $presets .type -}} -{{- index $presets .type | toYaml -}} -{{- else -}} -{{- printf "ERROR: Preset key '%s' invalid. Allowed values are %s" .type (join "," (keys $presets)) | fail -}} -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_secrets.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/_secrets.tpl deleted file mode 100644 index 801918ce..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_secrets.tpl +++ /dev/null @@ -1,185 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Generate secret name. - -Usage: -{{ include "common.secrets.name" (dict "existingSecret" .Values.path.to.the.existingSecret "defaultNameSuffix" "mySuffix" "context" $) }} - -Params: - - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user - to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. - +info: https://github.com/bitnami/charts/tree/main/bitnami/common#existingsecret - - defaultNameSuffix - String - Optional. It is used only if we have several secrets in the same deployment. - - context - Dict - Required. The context for the template evaluation. -*/}} -{{- define "common.secrets.name" -}} -{{- $name := (include "common.names.fullname" .context) -}} - -{{- if .defaultNameSuffix -}} -{{- $name = printf "%s-%s" $name .defaultNameSuffix | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{- with .existingSecret -}} -{{- if not (typeIs "string" .) -}} -{{- with .name -}} -{{- $name = . -}} -{{- end -}} -{{- else -}} -{{- $name = . -}} -{{- end -}} -{{- end -}} - -{{- printf "%s" $name -}} -{{- end -}} - -{{/* -Generate secret key. - -Usage: -{{ include "common.secrets.key" (dict "existingSecret" .Values.path.to.the.existingSecret "key" "keyName") }} - -Params: - - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user - to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. - +info: https://github.com/bitnami/charts/tree/main/bitnami/common#existingsecret - - key - String - Required. Name of the key in the secret. -*/}} -{{- define "common.secrets.key" -}} -{{- $key := .key -}} - -{{- if .existingSecret -}} - {{- if not (typeIs "string" .existingSecret) -}} - {{- if .existingSecret.keyMapping -}} - {{- $key = index .existingSecret.keyMapping $.key -}} - {{- end -}} - {{- end }} -{{- end -}} - -{{- printf "%s" $key -}} -{{- end -}} - -{{/* -Generate secret password or retrieve one if already created. - -Usage: -{{ include "common.secrets.passwords.manage" (dict "secret" "secret-name" "key" "keyName" "providedValues" (list "path.to.password1" "path.to.password2") "length" 10 "strong" false "chartName" "chartName" "context" $) }} - -Params: - - secret - String - Required - Name of the 'Secret' resource where the password is stored. - - key - String - Required - Name of the key in the secret. - - providedValues - List - Required - The path to the validating value in the values.yaml, e.g: "mysql.password". Will pick first parameter with a defined value. - - length - int - Optional - Length of the generated random password. - - strong - Boolean - Optional - Whether to add symbols to the generated random password. - - chartName - String - Optional - Name of the chart used when said chart is deployed as a subchart. - - context - Context - Required - Parent context. - - failOnNew - Boolean - Optional - Default to true. If set to false, skip errors adding new keys to existing secrets. - - skipB64enc - Boolean - Optional - Default to false. If set to true, no the secret will not be base64 encrypted. - - skipQuote - Boolean - Optional - Default to false. If set to true, no quotes will be added around the secret. -The order in which this function returns a secret password: - 1. Already existing 'Secret' resource - (If a 'Secret' resource is found under the name provided to the 'secret' parameter to this function and that 'Secret' resource contains a key with the name passed as the 'key' parameter to this function then the value of this existing secret password will be returned) - 2. Password provided via the values.yaml - (If one of the keys passed to the 'providedValues' parameter to this function is a valid path to a key in the values.yaml and has a value, the value of the first key with a value will be returned) - 3. Randomly generated secret password - (A new random secret password with the length specified in the 'length' parameter will be generated and returned) - -*/}} -{{- define "common.secrets.passwords.manage" -}} - -{{- $password := "" }} -{{- $subchart := "" }} -{{- $chartName := default "" .chartName }} -{{- $passwordLength := default 10 .length }} -{{- $providedPasswordKey := include "common.utils.getKeyFromList" (dict "keys" .providedValues "context" $.context) }} -{{- $providedPasswordValue := include "common.utils.getValueFromKey" (dict "key" $providedPasswordKey "context" $.context) }} -{{- $secretData := (lookup "v1" "Secret" (include "common.names.namespace" .context) .secret).data }} -{{- if $secretData }} - {{- if hasKey $secretData .key }} - {{- $password = index $secretData .key | b64dec }} - {{- else if not (eq .failOnNew false) }} - {{- printf "\nPASSWORDS ERROR: The secret \"%s\" does not contain the key \"%s\"\n" .secret .key | fail -}} - {{- end -}} -{{- end }} - -{{- if not $password }} - {{- if $providedPasswordValue }} - {{- $password = $providedPasswordValue | toString }} - {{- else }} - {{- if .context.Values.enabled }} - {{- $subchart = $chartName }} - {{- end -}} - - {{- if not (eq .failOnNew false) }} - {{- $requiredPassword := dict "valueKey" $providedPasswordKey "secret" .secret "field" .key "subchart" $subchart "context" $.context -}} - {{- $requiredPasswordError := include "common.validations.values.single.empty" $requiredPassword -}} - {{- $passwordValidationErrors := list $requiredPasswordError -}} - {{- include "common.errors.upgrade.passwords.empty" (dict "validationErrors" $passwordValidationErrors "context" $.context) -}} - {{- end }} - - {{- if .strong }} - {{- $subStr := list (lower (randAlpha 1)) (randNumeric 1) (upper (randAlpha 1)) | join "_" }} - {{- $password = randAscii $passwordLength }} - {{- $password = regexReplaceAllLiteral "\\W" $password "@" | substr 5 $passwordLength }} - {{- $password = printf "%s%s" $subStr $password | toString | shuffle }} - {{- else }} - {{- $password = randAlphaNum $passwordLength }} - {{- end }} - {{- end -}} -{{- end -}} -{{- if not .skipB64enc }} -{{- $password = $password | b64enc }} -{{- end -}} -{{- if .skipQuote -}} -{{- printf "%s" $password -}} -{{- else -}} -{{- printf "%s" $password | quote -}} -{{- end -}} -{{- end -}} - -{{/* -Reuses the value from an existing secret, otherwise sets its value to a default value. - -Usage: -{{ include "common.secrets.lookup" (dict "secret" "secret-name" "key" "keyName" "defaultValue" .Values.myValue "context" $) }} - -Params: - - secret - String - Required - Name of the 'Secret' resource where the password is stored. - - key - String - Required - Name of the key in the secret. - - defaultValue - String - Required - The path to the validating value in the values.yaml, e.g: "mysql.password". Will pick first parameter with a defined value. - - context - Context - Required - Parent context. - -*/}} -{{- define "common.secrets.lookup" -}} -{{- $value := "" -}} -{{- $secretData := (lookup "v1" "Secret" (include "common.names.namespace" .context) .secret).data -}} -{{- if and $secretData (hasKey $secretData .key) -}} - {{- $value = index $secretData .key -}} -{{- else if .defaultValue -}} - {{- $value = .defaultValue | toString | b64enc -}} -{{- end -}} -{{- if $value -}} -{{- printf "%s" $value -}} -{{- end -}} -{{- end -}} - -{{/* -Returns whether a previous generated secret already exists - -Usage: -{{ include "common.secrets.exists" (dict "secret" "secret-name" "context" $) }} - -Params: - - secret - String - Required - Name of the 'Secret' resource where the password is stored. - - context - Context - Required - Parent context. -*/}} -{{- define "common.secrets.exists" -}} -{{- $secret := (lookup "v1" "Secret" (include "common.names.namespace" .context) .secret) }} -{{- if $secret }} - {{- true -}} -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_storage.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/_storage.tpl deleted file mode 100644 index aa75856c..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_storage.tpl +++ /dev/null @@ -1,21 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} - -{{/* -Return the proper Storage Class -{{ include "common.storage.class" ( dict "persistence" .Values.path.to.the.persistence "global" $) }} -*/}} -{{- define "common.storage.class" -}} -{{- $storageClass := (.global).storageClass | default .persistence.storageClass | default (.global).defaultStorageClass | default "" -}} -{{- if $storageClass -}} - {{- if (eq "-" $storageClass) -}} - {{- printf "storageClassName: \"\"" -}} - {{- else -}} - {{- printf "storageClassName: %s" $storageClass -}} - {{- end -}} -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_tplvalues.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/_tplvalues.tpl deleted file mode 100644 index a04f4c1e..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_tplvalues.tpl +++ /dev/null @@ -1,52 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Renders a value that contains template perhaps with scope if the scope is present. -Usage: -{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $ ) }} -{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $ "scope" $app ) }} -*/}} -{{- define "common.tplvalues.render" -}} -{{- $value := typeIs "string" .value | ternary .value (.value | toYaml) }} -{{- if contains "{{" (toJson .value) }} - {{- if .scope }} - {{- tpl (cat "{{- with $.RelativeScope -}}" $value "{{- end }}") (merge (dict "RelativeScope" .scope) .context) }} - {{- else }} - {{- tpl $value .context }} - {{- end }} -{{- else }} - {{- $value }} -{{- end }} -{{- end -}} - -{{/* -Merge a list of values that contains template after rendering them. -Merge precedence is consistent with http://masterminds.github.io/sprig/dicts.html#merge-mustmerge -Usage: -{{ include "common.tplvalues.merge" ( dict "values" (list .Values.path.to.the.Value1 .Values.path.to.the.Value2) "context" $ ) }} -*/}} -{{- define "common.tplvalues.merge" -}} -{{- $dst := dict -}} -{{- range .values -}} -{{- $dst = include "common.tplvalues.render" (dict "value" . "context" $.context "scope" $.scope) | fromYaml | merge $dst -}} -{{- end -}} -{{ $dst | toYaml }} -{{- end -}} - -{{/* -Merge a list of values that contains template after rendering them. -Merge precedence is consistent with https://masterminds.github.io/sprig/dicts.html#mergeoverwrite-mustmergeoverwrite -Usage: -{{ include "common.tplvalues.merge-overwrite" ( dict "values" (list .Values.path.to.the.Value1 .Values.path.to.the.Value2) "context" $ ) }} -*/}} -{{- define "common.tplvalues.merge-overwrite" -}} -{{- $dst := dict -}} -{{- range .values -}} -{{- $dst = include "common.tplvalues.render" (dict "value" . "context" $.context "scope" $.scope) | fromYaml | mergeOverwrite $dst -}} -{{- end -}} -{{ $dst | toYaml }} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_utils.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/_utils.tpl deleted file mode 100644 index d53c74aa..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_utils.tpl +++ /dev/null @@ -1,77 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Print instructions to get a secret value. -Usage: -{{ include "common.utils.secret.getvalue" (dict "secret" "secret-name" "field" "secret-value-field" "context" $) }} -*/}} -{{- define "common.utils.secret.getvalue" -}} -{{- $varname := include "common.utils.fieldToEnvVar" . -}} -export {{ $varname }}=$(kubectl get secret --namespace {{ include "common.names.namespace" .context | quote }} {{ .secret }} -o jsonpath="{.data.{{ .field }}}" | base64 -d) -{{- end -}} - -{{/* -Build env var name given a field -Usage: -{{ include "common.utils.fieldToEnvVar" dict "field" "my-password" }} -*/}} -{{- define "common.utils.fieldToEnvVar" -}} - {{- $fieldNameSplit := splitList "-" .field -}} - {{- $upperCaseFieldNameSplit := list -}} - - {{- range $fieldNameSplit -}} - {{- $upperCaseFieldNameSplit = append $upperCaseFieldNameSplit ( upper . ) -}} - {{- end -}} - - {{ join "_" $upperCaseFieldNameSplit }} -{{- end -}} - -{{/* -Gets a value from .Values given -Usage: -{{ include "common.utils.getValueFromKey" (dict "key" "path.to.key" "context" $) }} -*/}} -{{- define "common.utils.getValueFromKey" -}} -{{- $splitKey := splitList "." .key -}} -{{- $value := "" -}} -{{- $latestObj := $.context.Values -}} -{{- range $splitKey -}} - {{- if not $latestObj -}} - {{- printf "please review the entire path of '%s' exists in values" $.key | fail -}} - {{- end -}} - {{- $value = ( index $latestObj . ) -}} - {{- $latestObj = $value -}} -{{- end -}} -{{- printf "%v" (default "" $value) -}} -{{- end -}} - -{{/* -Returns first .Values key with a defined value or first of the list if all non-defined -Usage: -{{ include "common.utils.getKeyFromList" (dict "keys" (list "path.to.key1" "path.to.key2") "context" $) }} -*/}} -{{- define "common.utils.getKeyFromList" -}} -{{- $key := first .keys -}} -{{- $reverseKeys := reverse .keys }} -{{- range $reverseKeys }} - {{- $value := include "common.utils.getValueFromKey" (dict "key" . "context" $.context ) }} - {{- if $value -}} - {{- $key = . }} - {{- end -}} -{{- end -}} -{{- printf "%s" $key -}} -{{- end -}} - -{{/* -Checksum a template at "path" containing a *single* resource (ConfigMap,Secret) for use in pod annotations, excluding the metadata (see #18376). -Usage: -{{ include "common.utils.checksumTemplate" (dict "path" "/configmap.yaml" "context" $) }} -*/}} -{{- define "common.utils.checksumTemplate" -}} -{{- $obj := include (print .context.Template.BasePath .path) .context | fromYaml -}} -{{ omit $obj "apiVersion" "kind" "metadata" | toYaml | sha256sum }} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_warnings.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/_warnings.tpl deleted file mode 100644 index e4dbecde..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/_warnings.tpl +++ /dev/null @@ -1,109 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Warning about using rolling tag. -Usage: -{{ include "common.warnings.rollingTag" .Values.path.to.the.imageRoot }} -*/}} -{{- define "common.warnings.rollingTag" -}} - -{{- if and (contains "bitnami/" .repository) (not (.tag | toString | regexFind "-r\\d+$|sha256:")) }} -WARNING: Rolling tag detected ({{ .repository }}:{{ .tag }}), please note that it is strongly recommended to avoid using rolling tags in a production environment. -+info https://docs.vmware.com/en/VMware-Tanzu-Application-Catalog/services/tutorials/GUID-understand-rolling-tags-containers-index.html -{{- end }} -{{- end -}} - -{{/* -Warning about replaced images from the original. -Usage: -{{ include "common.warnings.modifiedImages" (dict "images" (list .Values.path.to.the.imageRoot) "context" $) }} -*/}} -{{- define "common.warnings.modifiedImages" -}} -{{- $affectedImages := list -}} -{{- $printMessage := false -}} -{{- $originalImages := .context.Chart.Annotations.images -}} -{{- range .images -}} - {{- $fullImageName := printf (printf "%s/%s:%s" .registry .repository .tag) -}} - {{- if not (contains $fullImageName $originalImages) }} - {{- $affectedImages = append $affectedImages (printf "%s/%s:%s" .registry .repository .tag) -}} - {{- $printMessage = true -}} - {{- end -}} -{{- end -}} -{{- if $printMessage }} - -⚠ SECURITY WARNING: Original containers have been substituted. This Helm chart was designed, tested, and validated on multiple platforms using a specific set of Bitnami and Tanzu Application Catalog containers. Substituting other containers is likely to cause degraded security and performance, broken chart features, and missing environment variables. - -Substituted images detected: -{{- range $affectedImages }} - - {{ . }} -{{- end }} -{{- end -}} -{{- end -}} - -{{/* -Warning about not setting the resource object in all deployments. -Usage: -{{ include "common.warnings.resources" (dict "sections" (list "path1" "path2") context $) }} -Example: -{{- include "common.warnings.resources" (dict "sections" (list "csiProvider.provider" "server" "volumePermissions" "") "context" $) }} -The list in the example assumes that the following values exist: - - csiProvider.provider.resources - - server.resources - - volumePermissions.resources - - resources -*/}} -{{- define "common.warnings.resources" -}} -{{- $values := .context.Values -}} -{{- $printMessage := false -}} -{{ $affectedSections := list -}} -{{- range .sections -}} - {{- if eq . "" -}} - {{/* Case where the resources section is at the root (one main deployment in the chart) */}} - {{- if not (index $values "resources") -}} - {{- $affectedSections = append $affectedSections "resources" -}} - {{- $printMessage = true -}} - {{- end -}} - {{- else -}} - {{/* Case where the are multiple resources sections (more than one main deployment in the chart) */}} - {{- $keys := split "." . -}} - {{/* We iterate through the different levels until arriving to the resource section. Example: a.b.c.resources */}} - {{- $section := $values -}} - {{- range $keys -}} - {{- $section = index $section . -}} - {{- end -}} - {{- if not (index $section "resources") -}} - {{/* If the section has enabled=false or replicaCount=0, do not include it */}} - {{- if and (hasKey $section "enabled") -}} - {{- if index $section "enabled" -}} - {{/* enabled=true */}} - {{- $affectedSections = append $affectedSections (printf "%s.resources" .) -}} - {{- $printMessage = true -}} - {{- end -}} - {{- else if and (hasKey $section "replicaCount") -}} - {{/* We need a casting to int because number 0 is not treated as an int by default */}} - {{- if (gt (index $section "replicaCount" | int) 0) -}} - {{/* replicaCount > 0 */}} - {{- $affectedSections = append $affectedSections (printf "%s.resources" .) -}} - {{- $printMessage = true -}} - {{- end -}} - {{- else -}} - {{/* Default case, add it to the affected sections */}} - {{- $affectedSections = append $affectedSections (printf "%s.resources" .) -}} - {{- $printMessage = true -}} - {{- end -}} - {{- end -}} - {{- end -}} -{{- end -}} -{{- if $printMessage }} - -WARNING: There are "resources" sections in the chart not set. Using "resourcesPreset" is not recommended for production. For production installations, please set the following values according to your workload needs: -{{- range $affectedSections }} - - {{ . }} -{{- end }} -+info https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_cassandra.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_cassandra.tpl deleted file mode 100644 index f8fd213b..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_cassandra.tpl +++ /dev/null @@ -1,51 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Auxiliary function to get the right value for existingSecret. - -Usage: -{{ include "common.cassandra.values.existingSecret" (dict "context" $) }} -Params: - - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false -*/}} -{{- define "common.cassandra.values.existingSecret" -}} - {{- if .subchart -}} - {{- .context.Values.cassandra.dbUser.existingSecret | quote -}} - {{- else -}} - {{- .context.Values.dbUser.existingSecret | quote -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for enabled cassandra. - -Usage: -{{ include "common.cassandra.values.enabled" (dict "context" $) }} -*/}} -{{- define "common.cassandra.values.enabled" -}} - {{- if .subchart -}} - {{- printf "%v" .context.Values.cassandra.enabled -}} - {{- else -}} - {{- printf "%v" (not .context.Values.enabled) -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for the key dbUser - -Usage: -{{ include "common.cassandra.values.key.dbUser" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false -*/}} -{{- define "common.cassandra.values.key.dbUser" -}} - {{- if .subchart -}} - cassandra.dbUser - {{- else -}} - dbUser - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_mariadb.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_mariadb.tpl deleted file mode 100644 index 6ea8c0f4..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_mariadb.tpl +++ /dev/null @@ -1,108 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Validate MariaDB required passwords are not empty. - -Usage: -{{ include "common.validations.values.mariadb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} -Params: - - secret - String - Required. Name of the secret where MariaDB values are stored, e.g: "mysql-passwords-secret" - - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false -*/}} -{{- define "common.validations.values.mariadb.passwords" -}} - {{- $existingSecret := include "common.mariadb.values.auth.existingSecret" . -}} - {{- $enabled := include "common.mariadb.values.enabled" . -}} - {{- $architecture := include "common.mariadb.values.architecture" . -}} - {{- $authPrefix := include "common.mariadb.values.key.auth" . -}} - {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} - {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} - {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} - {{- $valueKeyReplicationPassword := printf "%s.replicationPassword" $authPrefix -}} - - {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} - {{- $requiredPasswords := list -}} - - {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mariadb-root-password" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} - - {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} - {{- if not (empty $valueUsername) -}} - {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mariadb-password" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} - {{- end -}} - - {{- if (eq $architecture "replication") -}} - {{- $requiredReplicationPassword := dict "valueKey" $valueKeyReplicationPassword "secret" .secret "field" "mariadb-replication-password" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredReplicationPassword -}} - {{- end -}} - - {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} - - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for existingSecret. - -Usage: -{{ include "common.mariadb.values.auth.existingSecret" (dict "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false -*/}} -{{- define "common.mariadb.values.auth.existingSecret" -}} - {{- if .subchart -}} - {{- .context.Values.mariadb.auth.existingSecret | quote -}} - {{- else -}} - {{- .context.Values.auth.existingSecret | quote -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for enabled mariadb. - -Usage: -{{ include "common.mariadb.values.enabled" (dict "context" $) }} -*/}} -{{- define "common.mariadb.values.enabled" -}} - {{- if .subchart -}} - {{- printf "%v" .context.Values.mariadb.enabled -}} - {{- else -}} - {{- printf "%v" (not .context.Values.enabled) -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for architecture - -Usage: -{{ include "common.mariadb.values.architecture" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false -*/}} -{{- define "common.mariadb.values.architecture" -}} - {{- if .subchart -}} - {{- .context.Values.mariadb.architecture -}} - {{- else -}} - {{- .context.Values.architecture -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for the key auth - -Usage: -{{ include "common.mariadb.values.key.auth" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false -*/}} -{{- define "common.mariadb.values.key.auth" -}} - {{- if .subchart -}} - mariadb.auth - {{- else -}} - auth - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_mongodb.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_mongodb.tpl deleted file mode 100644 index e678a6de..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_mongodb.tpl +++ /dev/null @@ -1,67 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Auxiliary function to get the right value for existingSecret. - -Usage: -{{ include "common.mongodb.values.auth.existingSecret" (dict "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MongoDb is used as subchart or not. Default: false -*/}} -{{- define "common.mongodb.values.auth.existingSecret" -}} - {{- if .subchart -}} - {{- .context.Values.mongodb.auth.existingSecret | quote -}} - {{- else -}} - {{- .context.Values.auth.existingSecret | quote -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for enabled mongodb. - -Usage: -{{ include "common.mongodb.values.enabled" (dict "context" $) }} -*/}} -{{- define "common.mongodb.values.enabled" -}} - {{- if .subchart -}} - {{- printf "%v" .context.Values.mongodb.enabled -}} - {{- else -}} - {{- printf "%v" (not .context.Values.enabled) -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for the key auth - -Usage: -{{ include "common.mongodb.values.key.auth" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MongoDB® is used as subchart or not. Default: false -*/}} -{{- define "common.mongodb.values.key.auth" -}} - {{- if .subchart -}} - mongodb.auth - {{- else -}} - auth - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for architecture - -Usage: -{{ include "common.mongodb.values.architecture" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MongoDB® is used as subchart or not. Default: false -*/}} -{{- define "common.mongodb.values.architecture" -}} - {{- if .subchart -}} - {{- .context.Values.mongodb.architecture -}} - {{- else -}} - {{- .context.Values.architecture -}} - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_mysql.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_mysql.tpl deleted file mode 100644 index fbb65c33..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_mysql.tpl +++ /dev/null @@ -1,67 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Auxiliary function to get the right value for existingSecret. - -Usage: -{{ include "common.mysql.values.auth.existingSecret" (dict "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MySQL is used as subchart or not. Default: false -*/}} -{{- define "common.mysql.values.auth.existingSecret" -}} - {{- if .subchart -}} - {{- .context.Values.mysql.auth.existingSecret | quote -}} - {{- else -}} - {{- .context.Values.auth.existingSecret | quote -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for enabled mysql. - -Usage: -{{ include "common.mysql.values.enabled" (dict "context" $) }} -*/}} -{{- define "common.mysql.values.enabled" -}} - {{- if .subchart -}} - {{- printf "%v" .context.Values.mysql.enabled -}} - {{- else -}} - {{- printf "%v" (not .context.Values.enabled) -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for architecture - -Usage: -{{ include "common.mysql.values.architecture" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MySQL is used as subchart or not. Default: false -*/}} -{{- define "common.mysql.values.architecture" -}} - {{- if .subchart -}} - {{- .context.Values.mysql.architecture -}} - {{- else -}} - {{- .context.Values.architecture -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for the key auth - -Usage: -{{ include "common.mysql.values.key.auth" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MySQL is used as subchart or not. Default: false -*/}} -{{- define "common.mysql.values.key.auth" -}} - {{- if .subchart -}} - mysql.auth - {{- else -}} - auth - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_postgresql.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_postgresql.tpl deleted file mode 100644 index 51d47162..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_postgresql.tpl +++ /dev/null @@ -1,105 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Auxiliary function to decide whether evaluate global values. - -Usage: -{{ include "common.postgresql.values.use.global" (dict "key" "key-of-global" "context" $) }} -Params: - - key - String - Required. Field to be evaluated within global, e.g: "existingSecret" -*/}} -{{- define "common.postgresql.values.use.global" -}} - {{- if .context.Values.global -}} - {{- if .context.Values.global.postgresql -}} - {{- index .context.Values.global.postgresql .key | quote -}} - {{- end -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for existingSecret. - -Usage: -{{ include "common.postgresql.values.existingSecret" (dict "context" $) }} -*/}} -{{- define "common.postgresql.values.existingSecret" -}} - {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "existingSecret" "context" .context) -}} - - {{- if .subchart -}} - {{- default (.context.Values.postgresql.existingSecret | quote) $globalValue -}} - {{- else -}} - {{- default (.context.Values.existingSecret | quote) $globalValue -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for enabled postgresql. - -Usage: -{{ include "common.postgresql.values.enabled" (dict "context" $) }} -*/}} -{{- define "common.postgresql.values.enabled" -}} - {{- if .subchart -}} - {{- printf "%v" .context.Values.postgresql.enabled -}} - {{- else -}} - {{- printf "%v" (not .context.Values.enabled) -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for the key postgressPassword. - -Usage: -{{ include "common.postgresql.values.key.postgressPassword" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false -*/}} -{{- define "common.postgresql.values.key.postgressPassword" -}} - {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "postgresqlUsername" "context" .context) -}} - - {{- if not $globalValue -}} - {{- if .subchart -}} - postgresql.postgresqlPassword - {{- else -}} - postgresqlPassword - {{- end -}} - {{- else -}} - global.postgresql.postgresqlPassword - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for enabled.replication. - -Usage: -{{ include "common.postgresql.values.enabled.replication" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false -*/}} -{{- define "common.postgresql.values.enabled.replication" -}} - {{- if .subchart -}} - {{- printf "%v" .context.Values.postgresql.replication.enabled -}} - {{- else -}} - {{- printf "%v" .context.Values.replication.enabled -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for the key replication.password. - -Usage: -{{ include "common.postgresql.values.key.replicationPassword" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false -*/}} -{{- define "common.postgresql.values.key.replicationPassword" -}} - {{- if .subchart -}} - postgresql.replication.password - {{- else -}} - replication.password - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_redis.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_redis.tpl deleted file mode 100644 index 9fedfef9..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_redis.tpl +++ /dev/null @@ -1,48 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - - -{{/* vim: set filetype=mustache: */}} -{{/* -Auxiliary function to get the right value for enabled redis. - -Usage: -{{ include "common.redis.values.enabled" (dict "context" $) }} -*/}} -{{- define "common.redis.values.enabled" -}} - {{- if .subchart -}} - {{- printf "%v" .context.Values.redis.enabled -}} - {{- else -}} - {{- printf "%v" (not .context.Values.enabled) -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right prefix path for the values - -Usage: -{{ include "common.redis.values.key.prefix" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether redis is used as subchart or not. Default: false -*/}} -{{- define "common.redis.values.keys.prefix" -}} - {{- if .subchart -}}redis.{{- else -}}{{- end -}} -{{- end -}} - -{{/* -Checks whether the redis chart's includes the standarizations (version >= 14) - -Usage: -{{ include "common.redis.values.standarized.version" (dict "context" $) }} -*/}} -{{- define "common.redis.values.standarized.version" -}} - - {{- $standarizedAuth := printf "%s%s" (include "common.redis.values.keys.prefix" .) "auth" -}} - {{- $standarizedAuthValues := include "common.utils.getValueFromKey" (dict "key" $standarizedAuth "context" .context) }} - - {{- if $standarizedAuthValues -}} - {{- true -}} - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_validations.tpl b/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_validations.tpl deleted file mode 100644 index 7cdee617..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/templates/validations/_validations.tpl +++ /dev/null @@ -1,51 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Validate values must not be empty. - -Usage: -{{- $validateValueConf00 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-00") -}} -{{- $validateValueConf01 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-01") -}} -{{ include "common.validations.values.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} - -Validate value params: - - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" - - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" - - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" -*/}} -{{- define "common.validations.values.multiple.empty" -}} - {{- range .required -}} - {{- include "common.validations.values.single.empty" (dict "valueKey" .valueKey "secret" .secret "field" .field "context" $.context) -}} - {{- end -}} -{{- end -}} - -{{/* -Validate a value must not be empty. - -Usage: -{{ include "common.validations.value.empty" (dict "valueKey" "mariadb.password" "secret" "secretName" "field" "my-password" "subchart" "subchart" "context" $) }} - -Validate value params: - - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" - - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" - - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" - - subchart - String - Optional - Name of the subchart that the validated password is part of. -*/}} -{{- define "common.validations.values.single.empty" -}} - {{- $value := include "common.utils.getValueFromKey" (dict "key" .valueKey "context" .context) }} - {{- $subchart := ternary "" (printf "%s." .subchart) (empty .subchart) }} - - {{- if not $value -}} - {{- $varname := "my-value" -}} - {{- $getCurrentValue := "" -}} - {{- if and .secret .field -}} - {{- $varname = include "common.utils.fieldToEnvVar" . -}} - {{- $getCurrentValue = printf " To get the current value:\n\n %s\n" (include "common.utils.secret.getvalue" .) -}} - {{- end -}} - {{- printf "\n '%s' must not be empty, please add '--set %s%s=$%s' to the command.%s" .valueKey $subchart .valueKey $varname $getCurrentValue -}} - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/common/values.yaml b/packages/system/dashboard/charts/kubeapps/charts/common/values.yaml deleted file mode 100644 index de2cac57..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/common/values.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright Broadcom, Inc. All Rights Reserved. -# SPDX-License-Identifier: APACHE-2.0 - -## bitnami/common -## It is required by CI/CD tools and processes. -## @skip exampleValue -## -exampleValue: common-chart diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/Chart.lock b/packages/system/dashboard/charts/kubeapps/charts/redis/Chart.lock deleted file mode 100644 index c399b3a7..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/Chart.lock +++ /dev/null @@ -1,6 +0,0 @@ -dependencies: -- name: common - repository: oci://registry-1.docker.io/bitnamicharts - version: 2.23.0 -digest: sha256:fbd6439f12ded949c04553b9c52a4c8153a8f2790147d972b314ddcd46921a14 -generated: "2024-09-14T18:55:25.608679155Z" diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/Chart.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/Chart.yaml deleted file mode 100644 index ffb31a4d..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/Chart.yaml +++ /dev/null @@ -1,38 +0,0 @@ -annotations: - category: Database - images: | - - name: kubectl - image: docker.io/bitnami/kubectl:1.31.1-debian-12-r3 - - name: os-shell - image: docker.io/bitnami/os-shell:12-debian-12-r30 - - name: redis - image: docker.io/bitnami/redis:7.4.1-debian-12-r0 - - name: redis-exporter - image: docker.io/bitnami/redis-exporter:1.63.0-debian-12-r1 - - name: redis-sentinel - image: docker.io/bitnami/redis-sentinel:7.4.1-debian-12-r0 - licenses: Apache-2.0 -apiVersion: v2 -appVersion: 7.4.1 -dependencies: -- name: common - repository: oci://registry-1.docker.io/bitnamicharts - tags: - - bitnami-common - version: 2.x.x -description: Redis(R) is an open source, advanced key-value store. It is often referred - to as a data structure server since keys can contain strings, hashes, lists, sets - and sorted sets. -home: https://bitnami.com -icon: https://bitnami.com/assets/stacks/redis/img/redis-stack-220x234.png -keywords: -- redis -- keyvalue -- database -maintainers: -- name: Broadcom, Inc. All Rights Reserved. - url: https://github.com/bitnami/charts -name: redis -sources: -- https://github.com/bitnami/charts/tree/main/bitnami/redis -version: 20.2.1 diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/README.md b/packages/system/dashboard/charts/kubeapps/charts/redis/README.md deleted file mode 100644 index 9b01882e..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/README.md +++ /dev/null @@ -1,1288 +0,0 @@ - - -# Bitnami package for Redis(R) - -Redis(R) is an open source, advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets and sorted sets. - -[Overview of Redis®](http://redis.io) - -Disclaimer: Redis is a registered trademark of Redis Ltd. Any rights therein are reserved to Redis Ltd. Any use by Bitnami is for referential purposes only and does not indicate any sponsorship, endorsement, or affiliation between Redis Ltd. - -## TL;DR - -```console -helm install my-release oci://registry-1.docker.io/bitnamicharts/redis -``` - -Looking to use Redis® in production? Try [VMware Tanzu Application Catalog](https://bitnami.com/enterprise), the commercial edition of the Bitnami catalog. - -## Introduction - -This chart bootstraps a [Redis®](https://github.com/bitnami/containers/tree/main/bitnami/redis) deployment on a [Kubernetes](https://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. - -Bitnami charts can be used with [Kubeapps](https://kubeapps.dev/) for deployment and management of Helm Charts in clusters. - -### Choose between Redis® Helm Chart and Redis® Cluster Helm Chart - -You can choose any of the two Redis® Helm charts for deploying a Redis® cluster. - -1. [Redis® Helm Chart](https://github.com/bitnami/charts/tree/main/bitnami/redis) will deploy a master-replica cluster, with the [option](https://github.com/bitnami/charts/tree/main/bitnami/redis#redis-sentinel-configuration-parameters) of enabling using Redis® Sentinel. -2. [Redis® Cluster Helm Chart](https://github.com/bitnami/charts/tree/main/bitnami/redis-cluster) will deploy a Redis® Cluster topology with sharding. - -The main features of each chart are the following: - -| Redis® | Redis® Cluster | -|--------------------------------------------------------|------------------------------------------------------------------------| -| Supports multiple databases | Supports only one database. Better if you have a big dataset | -| Single write point (single master) | Multiple write points (multiple masters) | -| ![Redis® Topology](img/redis-topology.png) | ![Redis® Cluster Topology](img/redis-cluster-topology.png) | - -## Prerequisites - -- Kubernetes 1.23+ -- Helm 3.8.0+ -- PV provisioner support in the underlying infrastructure - -## Installing the Chart - -To install the chart with the release name `my-release`: - -```console -helm install my-release oci://REGISTRY_NAME/REPOSITORY_NAME/redis -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -The command deploys Redis® on the Kubernetes cluster in the default configuration. The [Parameters](#parameters) section lists the parameters that can be configured during installation. - -> **Tip**: List all releases using `helm list` - -## Configuration and installation details - -### Resource requests and limits - -Bitnami charts allow setting resource requests and limits for all containers inside the chart deployment. These are inside the `resources` value (check parameter table). Setting requests is essential for production workloads and these should be adapted to your specific use case. - -To make this process easier, the chart contains the `resourcesPreset` values, which automatically sets the `resources` section according to different presets. Check these presets in [the bitnami/common chart](https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15). However, in production workloads using `resourcePreset` is discouraged as it may not fully adapt to your specific needs. Find more information on container resource management in the [official Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). - -### [Rolling VS Immutable tags](https://docs.vmware.com/en/VMware-Tanzu-Application-Catalog/services/tutorials/GUID-understand-rolling-tags-containers-index.html) - -It is strongly recommended to use immutable tags in a production environment. This ensures your deployment does not change automatically if the same tag is updated with a different image. - -Bitnami will release a new chart updating its containers if a new version of the main container, significant changes, or critical vulnerabilities exist. - -### Use a different Redis® version - -To modify the application version used in this chart, specify a different version of the image using the `image.tag` parameter and/or a different repository using the `image.repository` parameter. - -### Bootstrapping with an External Cluster - -This chart is equipped with the ability to bring online a set of Pods that connect to an existing Redis deployment that lies outside of Kubernetes. This effectively creates a hybrid Redis Deployment where both Pods in Kubernetes and Instances such as Virtual Machines can partake in a single Redis Deployment. This is helpful in situations where one may be migrating Redis from Virtual Machines into Kubernetes, for example. To take advantage of this, use the following as an example configuration: - -```yaml -replica: - externalMaster: - enabled: true - host: external-redis-0.internal -sentinel: - externalMaster: - enabled: true - host: external-redis-0.internal -``` - -:warning: This is currently limited to clusters in which Sentinel and Redis run on the same node! :warning: - -Please also note that the external sentinel must be listening on port `26379`, and this is currently not configurable. - -Once the Kubernetes Redis Deployment is online and confirmed to be working with the existing cluster, the configuration can then be removed and the cluster will remain connected. - -### External DNS - -This chart is equipped to allow leveraging the ExternalDNS project. Doing so will enable ExternalDNS to publish the FQDN for each instance, in the format of `..`. -Example, when using the following configuration: - -```yaml -useExternalDNS: - enabled: true - suffix: prod.example.org - additionalAnnotations: - ttl: 10 -``` - -On a cluster where the name of the Helm release is `a`, the hostname of a Pod is generated as: `a-redis-node-0.a-redis.prod.example.org`. The IP of that FQDN will match that of the associated Pod. This modifies the following parameters of the Redis/Sentinel configuration using this new FQDN: - -- `replica-announce-ip` -- `known-sentinel` -- `known-replica` -- `announce-ip` - -:warning: This requires a working installation of `external-dns` to be fully functional. :warning: - -See the [official ExternalDNS documentation](https://github.com/kubernetes-sigs/external-dns) for additional configuration options. - -### Cluster topologies - -#### Default: Master-Replicas - -When installing the chart with `architecture=replication`, it will deploy a Redis® master StatefulSet and a Redis® replicas StatefulSet. The replicas will be read-replicas of the master. Two services will be exposed: - -- Redis® Master service: Points to the master, where read-write operations can be performed -- Redis® Replicas service: Points to the replicas, where only read operations are allowed by default. - -In case the master crashes, the replicas will wait until the master node is respawned again by the Kubernetes Controller Manager. - -#### Standalone - -When installing the chart with `architecture=standalone`, it will deploy a standalone Redis® StatefulSet. A single service will be exposed: - -- Redis® Master service: Points to the master, where read-write operations can be performed - -#### Master-Replicas with Sentinel - -When installing the chart with `architecture=replication` and `sentinel.enabled=true`, it will deploy a Redis® master StatefulSet (only one master allowed) and a Redis® replicas StatefulSet. In this case, the pods will contain an extra container with Redis® Sentinel. This container will form a cluster of Redis® Sentinel nodes, which will promote a new master in case the actual one fails. - -On graceful termination of the Redis® master pod, a failover of the master is initiated to promote a new master. The Redis® Sentinel container in this pod will wait for the failover to occur before terminating. If `sentinel.redisShutdownWaitFailover=true` is set (the default), the Redis® container will wait for the failover as well before terminating. This increases availability for reads during failover, but may cause stale reads until all clients have switched to the new master. - -In addition to this, only one service is exposed: - -- Redis® service: Exposes port 6379 for Redis® read-only operations and port 26379 for accessing Redis® Sentinel. - -For read-only operations, access the service using port 6379. For write operations, it's necessary to access the Redis® Sentinel cluster and query the current master using the command below (using redis-cli or similar): - -```console -SENTINEL get-master-addr-by-name -``` - -This command will return the address of the current master, which can be accessed from inside the cluster. - -In case the current master crashes, the Sentinel containers will elect a new master node. - -`master.count` greater than `1` is not designed for use when `sentinel.enabled=true`. - -### Multiple masters (experimental) - -When `master.count` is greater than `1`, special care must be taken to create a consistent setup. - -An example of use case is the creation of a redundant set of standalone masters or master-replicas per Kubernetes node where you must ensure: - -- No more than `1` master can be deployed per Kubernetes node -- Replicas and writers can only see the single master of their own Kubernetes node - -One way of achieving this is by setting `master.service.internalTrafficPolicy=Local` in combination with a `master.affinity.podAntiAffinity` spec to never schedule more than one master per Kubernetes node. - -It's recommended to only change `master.count` if you know what you are doing. -`master.count` greater than `1` is not designed for use when `sentinel.enabled=true`. - -### Using a password file - -To use a password file for Redis® you need to create a secret containing the password and then deploy the chart using that secret. Follow these instructions: - -- Create the secret with the password. It is important that the file with the password must be called `redis-password`. - -```console -kubectl create secret generic redis-password-secret --from-file=redis-password.yaml -``` - -- Deploy the Helm Chart using the secret name as parameter: - -```text -usePassword=true -usePasswordFile=true -existingSecret=redis-password-secret -sentinels.enabled=true -metrics.enabled=true -``` - -### Securing traffic using TLS - -TLS support can be enabled in the chart by specifying the `tls.` parameters while creating a release. The following parameters should be configured to properly enable the TLS support in the cluster: - -- `tls.enabled`: Enable TLS support. Defaults to `false` -- `tls.existingSecret`: Name of the secret that contains the certificates. No defaults. -- `tls.certFilename`: Certificate filename. No defaults. -- `tls.certKeyFilename`: Certificate key filename. No defaults. -- `tls.certCAFilename`: CA Certificate filename. No defaults. - -For example: - -First, create the secret with the certificates files: - -```console -kubectl create secret generic certificates-tls-secret --from-file=./cert.pem --from-file=./cert.key --from-file=./ca.pem -``` - -Then, use the following parameters: - -```console -tls.enabled="true" -tls.existingSecret="certificates-tls-secret" -tls.certFilename="cert.pem" -tls.certKeyFilename="cert.key" -tls.certCAFilename="ca.pem" -``` - -### Metrics - -The chart optionally can start a metrics exporter for [prometheus](https://prometheus.io). The metrics endpoint (port 9121) is exposed in the service. Metrics can be scraped from within the cluster using something similar as the described in the [example Prometheus scrape configuration](https://github.com/prometheus/prometheus/blob/master/documentation/examples/prometheus-kubernetes.yml). If metrics are to be scraped from outside the cluster, the Kubernetes API proxy can be utilized to access the endpoint. - -If you have enabled TLS by specifying `tls.enabled=true` you also need to specify TLS option to the metrics exporter. You can do that via `metrics.extraArgs`. You can find the metrics exporter CLI flags for TLS [here](https://github.com/oliver006/redis_exporter#command-line-flags). For example: - -You can either specify `metrics.extraArgs.skip-tls-verification=true` to skip TLS verification or providing the following values under `metrics.extraArgs` for TLS client authentication: - -```console -tls-client-key-file -tls-client-cert-file -tls-ca-cert-file -``` - -### Deploy a custom metrics script in the sidecar - -A custom Lua script can be added to the `redis-exporter` sidecar by way of the `metrics.extraArgs.script` parameter. The pathname of the script must exist on the container, or the `redis_exporter` process (and therefore the whole pod) will refuse to start. The script can be provided to the sidecar containers via the `metrics.extraVolumes` and `metrics.extraVolumeMounts` parameters: - -```yaml -metrics: - extraVolumeMounts: - - name: '{{ printf "%s-metrics-script-file" (include "common.names.fullname" .) }}' - mountPath: '{{ printf "/mnt/%s/" (include "common.names.name" .) }}' - readOnly: true - extraVolumes: - - name: '{{ printf "%s-metrics-script-file" (include "common.names.fullname" .) }}' - configMap: - name: '{{ printf "%s-metrics-script" (include "common.names.fullname" .) }}' - extraArgs: - script: '{{ printf "/mnt/%s/my_custom_metrics.lua" (include "common.names.name" .) }}' -``` - -Then deploy the script into the correct location via `extraDeploy`: - -```yaml -extraDeploy: - - apiVersion: v1 - kind: ConfigMap - metadata: - name: '{{ printf "%s-metrics-script" (include "common.names.fullname" .) }}' - data: - my_custom_metrics.lua: | - -- LUA SCRIPT CODE HERE, e.g., - return {'bitnami_makes_the_best_charts', '1'} -``` - -### Host Kernel Settings - -Redis® may require some changes in the kernel of the host machine to work as expected, in particular increasing the `somaxconn` value and disabling transparent huge pages. To do so, you can set up a privileged `initContainer` with the `sysctlImage` config values, for example: - -```yaml -sysctlImage: - enabled: true - mountHostSys: true - command: - - /bin/sh - - -c - - |- - install_packages procps - sysctl -w net.core.somaxconn=10000 - echo never > /host-sys/kernel/mm/transparent_hugepage/enabled -``` - -Alternatively, for Kubernetes 1.12+ you can set `securityContext.sysctls` which will configure `sysctls` for master and slave pods. Example: - -```yaml -securityContext: - sysctls: - - name: net.core.somaxconn - value: "10000" -``` - -Note that this will not disable transparent huge tables. - -### Backup and restore - -To backup and restore Redis deployments on Kubernetes, you will need to create a snapshot of the data in the source cluster, and later restore it in a new cluster with the new parameters. Follow the instructions below: - -#### Step 1: Backup the deployment - -- Connect to one of the nodes and start the Redis CLI tool. Then, run the commands below: - - ```text - $ kubectl exec -it my-release-master-0 bash - $ redis-cli - 127.0.0.1:6379> auth your_current_redis_password - OK - 127.0.0.1:6379> save - OK - ``` - -- Copy the dump file from the Redis node: - - ```console - kubectl cp my-release-master-0:/data/dump.rdb dump.rdb -c redis - ``` - -#### Step 2: Restore the data on the destination cluster - -To restore the data in a new cluster, you will need to create a PVC and then upload the *dump.rdb* file to the new volume. - -Follow the following steps: - -- In the [*values.yaml*](https://github.com/bitnami/charts/blob/main/bitnami/redis/values.yaml) file set the *appendonly* parameter to *no*. You can skip this step if it is already configured as *no* - - ```yaml - commonConfiguration: |- - # Enable AOF https://redis.io/topics/persistence#append-only-file - appendonly no - # Disable RDB persistence, AOF persistence already enabled. - save "" - ``` - - > *Note that the `Enable AOF` comment belongs to the original config file and what you're actually doing is disabling it. This change will only be neccessary for the temporal cluster you're creating to upload the dump.* - -- Start the new cluster to create the PVCs. Use the command below as an example: - - ```console - helm install new-redis -f values.yaml . --set cluster.enabled=true --set cluster.slaveCount=3 - ``` - -- Now that the PVC were created, stop it and copy the *dump.rdp* file on the persisted data by using a helping pod. - - ```text - $ helm delete new-redis - - $ kubectl run --generator=run-pod/v1 -i --rm --tty volpod --overrides=' - { - "apiVersion": "v1", - "kind": "Pod", - "metadata": { - "name": "redisvolpod" - }, - "spec": { - "containers": [{ - "command": [ - "tail", - "-f", - "/dev/null" - ], - "image": "bitnami/minideb", - "name": "mycontainer", - "volumeMounts": [{ - "mountPath": "/mnt", - "name": "redisdata" - }] - }], - "restartPolicy": "Never", - "volumes": [{ - "name": "redisdata", - "persistentVolumeClaim": { - "claimName": "redis-data-new-redis-master-0" - } - }] - } - }' --image="bitnami/minideb" - - $ kubectl cp dump.rdb redisvolpod:/mnt/dump.rdb - $ kubectl delete pod volpod - ``` - -- Restart the cluster: - - > **INFO:** The *appendonly* parameter can be safely restored to your desired value. - - ```console - helm install new-redis -f values.yaml . --set cluster.enabled=true --set cluster.slaveCount=3 - ``` - -### NetworkPolicy - -To enable network policy for Redis®, install [a networking plugin that implements the Kubernetes NetworkPolicy spec](https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy#before-you-begin), and set `networkPolicy.enabled` to `true`. - -With NetworkPolicy enabled, only pods with the generated client label will be able to connect to Redis. This label will be displayed in the output after a successful install. - -With `networkPolicy.ingressNSMatchLabels` pods from other namespaces can connect to Redis. Set `networkPolicy.ingressNSPodMatchLabels` to match pod labels in matched namespace. For example, for a namespace labeled `redis=external` and pods in that namespace labeled `redis-client=true` the fields should be set: - -```yaml -networkPolicy: - enabled: true - ingressNSMatchLabels: - redis: external - ingressNSPodMatchLabels: - redis-client: true -``` - -#### Setting Pod's affinity - -This chart allows you to set your custom affinity using the `XXX.affinity` parameter(s). Find more information about Pod's affinity in the [Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity). - -As an alternative, you can use of the preset configurations for pod affinity, pod anti-affinity, and node affinity available at the [bitnami/common](https://github.com/bitnami/charts/tree/main/bitnami/common#affinities) chart. To do so, set the `XXX.podAffinityPreset`, `XXX.podAntiAffinityPreset`, or `XXX.nodeAffinityPreset` parameters. - -## Persistence - -By default, the chart mounts a [Persistent Volume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) at the `/data` path. The volume is created using dynamic volume provisioning. If a Persistent Volume Claim already exists, specify it during installation. - -### Existing PersistentVolumeClaim - -1. Create the PersistentVolume -2. Create the PersistentVolumeClaim -3. Install the chart - -```console -helm install my-release --set master.persistence.existingClaim=PVC_NAME oci://REGISTRY_NAME/REPOSITORY_NAME/redis -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -## Parameters - -### Global parameters - -| Name | Description | Value | -| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -| `global.imageRegistry` | Global Docker image registry | `""` | -| `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` | -| `global.defaultStorageClass` | Global default StorageClass for Persistent Volume(s) | `""` | -| `global.storageClass` | DEPRECATED: use global.defaultStorageClass instead | `""` | -| `global.redis.password` | Global Redis® password (overrides `auth.password`) | `""` | -| `global.compatibility.openshift.adaptSecurityContext` | Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation) | `auto` | - -### Common parameters - -| Name | Description | Value | -| ------------------------- | -------------------------------------------------------------------------------------------------------------- | --------------- | -| `kubeVersion` | Override Kubernetes version | `""` | -| `nameOverride` | String to partially override common.names.fullname | `""` | -| `fullnameOverride` | String to fully override common.names.fullname | `""` | -| `namespaceOverride` | String to fully override common.names.namespace | `""` | -| `commonLabels` | Labels to add to all deployed objects | `{}` | -| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | -| `secretAnnotations` | Annotations to add to secret | `{}` | -| `clusterDomain` | Kubernetes cluster domain name | `cluster.local` | -| `extraDeploy` | Array of extra objects to deploy with the release | `[]` | -| `useHostnames` | Use hostnames internally when announcing replication. If false, the hostname will be resolved to an IP address | `true` | -| `nameResolutionThreshold` | Failure threshold for internal hostnames resolution | `5` | -| `nameResolutionTimeout` | Timeout seconds between probes for internal hostnames resolution | `5` | -| `diagnosticMode.enabled` | Enable diagnostic mode (all probes will be disabled and the command will be overridden) | `false` | -| `diagnosticMode.command` | Command to override all containers in the deployment | `["sleep"]` | -| `diagnosticMode.args` | Args to override all containers in the deployment | `["infinity"]` | - -### Redis® Image parameters - -| Name | Description | Value | -| ------------------- | ---------------------------------------------------------------------------------------------------------- | ----------------------- | -| `image.registry` | Redis® image registry | `REGISTRY_NAME` | -| `image.repository` | Redis® image repository | `REPOSITORY_NAME/redis` | -| `image.digest` | Redis® image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | -| `image.pullPolicy` | Redis® image pull policy | `IfNotPresent` | -| `image.pullSecrets` | Redis® image pull secrets | `[]` | -| `image.debug` | Enable image debug mode | `false` | - -### Redis® common configuration parameters - -| Name | Description | Value | -| -------------------------------- | ------------------------------------------------------------------------------------- | ------------- | -| `architecture` | Redis® architecture. Allowed values: `standalone` or `replication` | `replication` | -| `auth.enabled` | Enable password authentication | `true` | -| `auth.sentinel` | Enable password authentication on sentinels too | `true` | -| `auth.password` | Redis® password | `""` | -| `auth.existingSecret` | The name of an existing secret with Redis® credentials | `""` | -| `auth.existingSecretPasswordKey` | Password key to be retrieved from existing secret | `""` | -| `auth.usePasswordFiles` | Mount credentials as files instead of using an environment variable | `false` | -| `auth.usePasswordFileFromSecret` | Mount password file from secret | `true` | -| `commonConfiguration` | Common configuration to be added into the ConfigMap | `""` | -| `existingConfigmap` | The name of an existing ConfigMap with your custom configuration for Redis® nodes | `""` | - -### Redis® master configuration parameters - -| Name | Description | Value | -| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | -| `master.count` | Number of Redis® master instances to deploy (experimental, requires additional configuration) | `1` | -| `master.revisionHistoryLimit` | The number of old history to retain to allow rollback | `10` | -| `master.configuration` | Configuration for Redis® master nodes | `""` | -| `master.disableCommands` | Array with Redis® commands to disable on master nodes | `["FLUSHDB","FLUSHALL"]` | -| `master.command` | Override default container command (useful when using custom images) | `[]` | -| `master.args` | Override default container args (useful when using custom images) | `[]` | -| `master.enableServiceLinks` | Whether information about services should be injected into pod's environment variable | `true` | -| `master.preExecCmds` | Additional commands to run prior to starting Redis® master | `[]` | -| `master.extraFlags` | Array with additional command line flags for Redis® master | `[]` | -| `master.extraEnvVars` | Array with extra environment variables to add to Redis® master nodes | `[]` | -| `master.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for Redis® master nodes | `""` | -| `master.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for Redis® master nodes | `""` | -| `master.containerPorts.redis` | Container port to open on Redis® master nodes | `6379` | -| `master.startupProbe.enabled` | Enable startupProbe on Redis® master nodes | `false` | -| `master.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `20` | -| `master.startupProbe.periodSeconds` | Period seconds for startupProbe | `5` | -| `master.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `5` | -| `master.startupProbe.failureThreshold` | Failure threshold for startupProbe | `5` | -| `master.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | -| `master.livenessProbe.enabled` | Enable livenessProbe on Redis® master nodes | `true` | -| `master.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `20` | -| `master.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `5` | -| `master.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `5` | -| `master.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `5` | -| `master.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | -| `master.readinessProbe.enabled` | Enable readinessProbe on Redis® master nodes | `true` | -| `master.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `20` | -| `master.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `5` | -| `master.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `1` | -| `master.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `5` | -| `master.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | -| `master.customStartupProbe` | Custom startupProbe that overrides the default one | `{}` | -| `master.customLivenessProbe` | Custom livenessProbe that overrides the default one | `{}` | -| `master.customReadinessProbe` | Custom readinessProbe that overrides the default one | `{}` | -| `master.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if master.resources is set (master.resources is recommended for production). | `nano` | -| `master.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | -| `master.podSecurityContext.enabled` | Enabled Redis® master pods' Security Context | `true` | -| `master.podSecurityContext.fsGroupChangePolicy` | Set filesystem group change policy | `Always` | -| `master.podSecurityContext.sysctls` | Set kernel settings using the sysctl interface | `[]` | -| `master.podSecurityContext.supplementalGroups` | Set filesystem extra groups | `[]` | -| `master.podSecurityContext.fsGroup` | Set Redis® master pod's Security Context fsGroup | `1001` | -| `master.containerSecurityContext.enabled` | Enabled Redis® master containers' Security Context | `true` | -| `master.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | -| `master.containerSecurityContext.runAsUser` | Set Redis® master containers' Security Context runAsUser | `1001` | -| `master.containerSecurityContext.runAsGroup` | Set Redis® master containers' Security Context runAsGroup | `1001` | -| `master.containerSecurityContext.runAsNonRoot` | Set Redis® master containers' Security Context runAsNonRoot | `true` | -| `master.containerSecurityContext.allowPrivilegeEscalation` | Is it possible to escalate Redis® pod(s) privileges | `false` | -| `master.containerSecurityContext.readOnlyRootFilesystem` | Set container's Security Context read-only root filesystem | `true` | -| `master.containerSecurityContext.seccompProfile.type` | Set Redis® master containers' Security Context seccompProfile | `RuntimeDefault` | -| `master.containerSecurityContext.capabilities.drop` | Set Redis® master containers' Security Context capabilities to drop | `["ALL"]` | -| `master.kind` | Use either Deployment, StatefulSet (default) or DaemonSet | `StatefulSet` | -| `master.schedulerName` | Alternate scheduler for Redis® master pods | `""` | -| `master.updateStrategy.type` | Redis® master statefulset strategy type | `RollingUpdate` | -| `master.minReadySeconds` | How many seconds a pod needs to be ready before killing the next, during update | `0` | -| `master.priorityClassName` | Redis® master pods' priorityClassName | `""` | -| `master.automountServiceAccountToken` | Mount Service Account token in pod | `false` | -| `master.hostAliases` | Redis® master pods host aliases | `[]` | -| `master.podLabels` | Extra labels for Redis® master pods | `{}` | -| `master.podAnnotations` | Annotations for Redis® master pods | `{}` | -| `master.shareProcessNamespace` | Share a single process namespace between all of the containers in Redis® master pods | `false` | -| `master.podAffinityPreset` | Pod affinity preset. Ignored if `master.affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `master.podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `master.affinity` is set. Allowed values: `soft` or `hard` | `soft` | -| `master.nodeAffinityPreset.type` | Node affinity preset type. Ignored if `master.affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `master.nodeAffinityPreset.key` | Node label key to match. Ignored if `master.affinity` is set | `""` | -| `master.nodeAffinityPreset.values` | Node label values to match. Ignored if `master.affinity` is set | `[]` | -| `master.affinity` | Affinity for Redis® master pods assignment | `{}` | -| `master.nodeSelector` | Node labels for Redis® master pods assignment | `{}` | -| `master.tolerations` | Tolerations for Redis® master pods assignment | `[]` | -| `master.topologySpreadConstraints` | Spread Constraints for Redis® master pod assignment | `[]` | -| `master.dnsPolicy` | DNS Policy for Redis® master pod | `""` | -| `master.dnsConfig` | DNS Configuration for Redis® master pod | `{}` | -| `master.lifecycleHooks` | for the Redis® master container(s) to automate configuration before or after startup | `{}` | -| `master.extraVolumes` | Optionally specify extra list of additional volumes for the Redis® master pod(s) | `[]` | -| `master.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the Redis® master container(s) | `[]` | -| `master.sidecars` | Add additional sidecar containers to the Redis® master pod(s) | `[]` | -| `master.initContainers` | Add additional init containers to the Redis® master pod(s) | `[]` | -| `master.persistence.enabled` | Enable persistence on Redis® master nodes using Persistent Volume Claims | `true` | -| `master.persistence.medium` | Provide a medium for `emptyDir` volumes. | `""` | -| `master.persistence.sizeLimit` | Set this to enable a size limit for `emptyDir` volumes. | `""` | -| `master.persistence.path` | The path the volume will be mounted at on Redis® master containers | `/data` | -| `master.persistence.subPath` | The subdirectory of the volume to mount on Redis® master containers | `""` | -| `master.persistence.subPathExpr` | Used to construct the subPath subdirectory of the volume to mount on Redis® master containers | `""` | -| `master.persistence.storageClass` | Persistent Volume storage class | `""` | -| `master.persistence.accessModes` | Persistent Volume access modes | `["ReadWriteOnce"]` | -| `master.persistence.size` | Persistent Volume size | `8Gi` | -| `master.persistence.annotations` | Additional custom annotations for the PVC | `{}` | -| `master.persistence.labels` | Additional custom labels for the PVC | `{}` | -| `master.persistence.selector` | Additional labels to match for the PVC | `{}` | -| `master.persistence.dataSource` | Custom PVC data source | `{}` | -| `master.persistence.existingClaim` | Use a existing PVC which must be created manually before bound | `""` | -| `master.persistentVolumeClaimRetentionPolicy.enabled` | Controls if and how PVCs are deleted during the lifecycle of a StatefulSet | `false` | -| `master.persistentVolumeClaimRetentionPolicy.whenScaled` | Volume retention behavior when the replica count of the StatefulSet is reduced | `Retain` | -| `master.persistentVolumeClaimRetentionPolicy.whenDeleted` | Volume retention behavior that applies when the StatefulSet is deleted | `Retain` | -| `master.service.type` | Redis® master service type | `ClusterIP` | -| `master.service.portNames.redis` | Redis® master service port name | `tcp-redis` | -| `master.service.ports.redis` | Redis® master service port | `6379` | -| `master.service.nodePorts.redis` | Node port for Redis® master | `""` | -| `master.service.externalTrafficPolicy` | Redis® master service external traffic policy | `Cluster` | -| `master.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | -| `master.service.internalTrafficPolicy` | Redis® master service internal traffic policy (requires Kubernetes v1.22 or greater to be usable) | `Cluster` | -| `master.service.clusterIP` | Redis® master service Cluster IP | `""` | -| `master.service.loadBalancerIP` | Redis® master service Load Balancer IP | `""` | -| `master.service.loadBalancerClass` | master service Load Balancer class if service type is `LoadBalancer` (optional, cloud specific) | `""` | -| `master.service.loadBalancerSourceRanges` | Redis® master service Load Balancer sources | `[]` | -| `master.service.externalIPs` | Redis® master service External IPs | `[]` | -| `master.service.annotations` | Additional custom annotations for Redis® master service | `{}` | -| `master.service.sessionAffinity` | Session Affinity for Kubernetes service, can be "None" or "ClientIP" | `None` | -| `master.service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | -| `master.terminationGracePeriodSeconds` | Integer setting the termination grace period for the redis-master pods | `30` | -| `master.serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` | -| `master.serviceAccount.name` | The name of the ServiceAccount to use. | `""` | -| `master.serviceAccount.automountServiceAccountToken` | Whether to auto mount the service account token | `false` | -| `master.serviceAccount.annotations` | Additional custom annotations for the ServiceAccount | `{}` | -| `master.pdb.create` | Enable/disable a Pod Disruption Budget creation | `true` | -| `master.pdb.minAvailable` | Minimum number/percentage of pods that should remain scheduled | `{}` | -| `master.pdb.maxUnavailable` | Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `master.pdb.minAvailable` and `master.pdb.maxUnavailable` are empty. | `{}` | -| `master.extraPodSpec` | Optionally specify extra PodSpec for the Redis® master pod(s) | `{}` | - -### Redis® replicas configuration parameters - -| Name | Description | Value | -| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | -| `replica.kind` | Use either DaemonSet or StatefulSet (default) | `StatefulSet` | -| `replica.replicaCount` | Number of Redis® replicas to deploy | `3` | -| `replica.revisionHistoryLimit` | The number of old history to retain to allow rollback | `10` | -| `replica.configuration` | Configuration for Redis® replicas nodes | `""` | -| `replica.disableCommands` | Array with Redis® commands to disable on replicas nodes | `["FLUSHDB","FLUSHALL"]` | -| `replica.command` | Override default container command (useful when using custom images) | `[]` | -| `replica.args` | Override default container args (useful when using custom images) | `[]` | -| `replica.enableServiceLinks` | Whether information about services should be injected into pod's environment variable | `true` | -| `replica.preExecCmds` | Additional commands to run prior to starting Redis® replicas | `[]` | -| `replica.extraFlags` | Array with additional command line flags for Redis® replicas | `[]` | -| `replica.extraEnvVars` | Array with extra environment variables to add to Redis® replicas nodes | `[]` | -| `replica.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for Redis® replicas nodes | `""` | -| `replica.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for Redis® replicas nodes | `""` | -| `replica.externalMaster.enabled` | Use external master for bootstrapping | `false` | -| `replica.externalMaster.host` | External master host to bootstrap from | `""` | -| `replica.externalMaster.port` | Port for Redis service external master host | `6379` | -| `replica.containerPorts.redis` | Container port to open on Redis® replicas nodes | `6379` | -| `replica.startupProbe.enabled` | Enable startupProbe on Redis® replicas nodes | `true` | -| `replica.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `10` | -| `replica.startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | -| `replica.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `5` | -| `replica.startupProbe.failureThreshold` | Failure threshold for startupProbe | `22` | -| `replica.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | -| `replica.livenessProbe.enabled` | Enable livenessProbe on Redis® replicas nodes | `true` | -| `replica.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `20` | -| `replica.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `5` | -| `replica.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `5` | -| `replica.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `5` | -| `replica.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | -| `replica.readinessProbe.enabled` | Enable readinessProbe on Redis® replicas nodes | `true` | -| `replica.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `20` | -| `replica.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `5` | -| `replica.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `1` | -| `replica.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `5` | -| `replica.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | -| `replica.customStartupProbe` | Custom startupProbe that overrides the default one | `{}` | -| `replica.customLivenessProbe` | Custom livenessProbe that overrides the default one | `{}` | -| `replica.customReadinessProbe` | Custom readinessProbe that overrides the default one | `{}` | -| `replica.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if replica.resources is set (replica.resources is recommended for production). | `nano` | -| `replica.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | -| `replica.podSecurityContext.enabled` | Enabled Redis® replicas pods' Security Context | `true` | -| `replica.podSecurityContext.fsGroupChangePolicy` | Set filesystem group change policy | `Always` | -| `replica.podSecurityContext.sysctls` | Set kernel settings using the sysctl interface | `[]` | -| `replica.podSecurityContext.supplementalGroups` | Set filesystem extra groups | `[]` | -| `replica.podSecurityContext.fsGroup` | Set Redis® replicas pod's Security Context fsGroup | `1001` | -| `replica.containerSecurityContext.enabled` | Enabled Redis® replicas containers' Security Context | `true` | -| `replica.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | -| `replica.containerSecurityContext.runAsUser` | Set Redis® replicas containers' Security Context runAsUser | `1001` | -| `replica.containerSecurityContext.runAsGroup` | Set Redis® replicas containers' Security Context runAsGroup | `1001` | -| `replica.containerSecurityContext.runAsNonRoot` | Set Redis® replicas containers' Security Context runAsNonRoot | `true` | -| `replica.containerSecurityContext.allowPrivilegeEscalation` | Set Redis® replicas pod's Security Context allowPrivilegeEscalation | `false` | -| `replica.containerSecurityContext.readOnlyRootFilesystem` | Set container's Security Context read-only root filesystem | `true` | -| `replica.containerSecurityContext.seccompProfile.type` | Set Redis® replicas containers' Security Context seccompProfile | `RuntimeDefault` | -| `replica.containerSecurityContext.capabilities.drop` | Set Redis® replicas containers' Security Context capabilities to drop | `["ALL"]` | -| `replica.schedulerName` | Alternate scheduler for Redis® replicas pods | `""` | -| `replica.updateStrategy.type` | Redis® replicas statefulset strategy type | `RollingUpdate` | -| `replica.minReadySeconds` | How many seconds a pod needs to be ready before killing the next, during update | `0` | -| `replica.priorityClassName` | Redis® replicas pods' priorityClassName | `""` | -| `replica.podManagementPolicy` | podManagementPolicy to manage scaling operation of %%MAIN_CONTAINER_NAME%% pods | `""` | -| `replica.automountServiceAccountToken` | Mount Service Account token in pod | `false` | -| `replica.hostAliases` | Redis® replicas pods host aliases | `[]` | -| `replica.podLabels` | Extra labels for Redis® replicas pods | `{}` | -| `replica.podAnnotations` | Annotations for Redis® replicas pods | `{}` | -| `replica.shareProcessNamespace` | Share a single process namespace between all of the containers in Redis® replicas pods | `false` | -| `replica.podAffinityPreset` | Pod affinity preset. Ignored if `replica.affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `replica.podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `replica.affinity` is set. Allowed values: `soft` or `hard` | `soft` | -| `replica.nodeAffinityPreset.type` | Node affinity preset type. Ignored if `replica.affinity` is set. Allowed values: `soft` or `hard` | `""` | -| `replica.nodeAffinityPreset.key` | Node label key to match. Ignored if `replica.affinity` is set | `""` | -| `replica.nodeAffinityPreset.values` | Node label values to match. Ignored if `replica.affinity` is set | `[]` | -| `replica.affinity` | Affinity for Redis® replicas pods assignment | `{}` | -| `replica.nodeSelector` | Node labels for Redis® replicas pods assignment | `{}` | -| `replica.tolerations` | Tolerations for Redis® replicas pods assignment | `[]` | -| `replica.topologySpreadConstraints` | Spread Constraints for Redis® replicas pod assignment | `[]` | -| `replica.dnsPolicy` | DNS Policy for Redis® replica pods | `""` | -| `replica.dnsConfig` | DNS Configuration for Redis® replica pods | `{}` | -| `replica.lifecycleHooks` | for the Redis® replica container(s) to automate configuration before or after startup | `{}` | -| `replica.extraVolumes` | Optionally specify extra list of additional volumes for the Redis® replicas pod(s) | `[]` | -| `replica.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the Redis® replicas container(s) | `[]` | -| `replica.sidecars` | Add additional sidecar containers to the Redis® replicas pod(s) | `[]` | -| `replica.initContainers` | Add additional init containers to the Redis® replicas pod(s) | `[]` | -| `replica.persistence.enabled` | Enable persistence on Redis® replicas nodes using Persistent Volume Claims | `true` | -| `replica.persistence.medium` | Provide a medium for `emptyDir` volumes. | `""` | -| `replica.persistence.sizeLimit` | Set this to enable a size limit for `emptyDir` volumes. | `""` | -| `replica.persistence.path` | The path the volume will be mounted at on Redis® replicas containers | `/data` | -| `replica.persistence.subPath` | The subdirectory of the volume to mount on Redis® replicas containers | `""` | -| `replica.persistence.subPathExpr` | Used to construct the subPath subdirectory of the volume to mount on Redis® replicas containers | `""` | -| `replica.persistence.storageClass` | Persistent Volume storage class | `""` | -| `replica.persistence.accessModes` | Persistent Volume access modes | `["ReadWriteOnce"]` | -| `replica.persistence.size` | Persistent Volume size | `8Gi` | -| `replica.persistence.annotations` | Additional custom annotations for the PVC | `{}` | -| `replica.persistence.labels` | Additional custom labels for the PVC | `{}` | -| `replica.persistence.selector` | Additional labels to match for the PVC | `{}` | -| `replica.persistence.dataSource` | Custom PVC data source | `{}` | -| `replica.persistence.existingClaim` | Use a existing PVC which must be created manually before bound | `""` | -| `replica.persistentVolumeClaimRetentionPolicy.enabled` | Controls if and how PVCs are deleted during the lifecycle of a StatefulSet | `false` | -| `replica.persistentVolumeClaimRetentionPolicy.whenScaled` | Volume retention behavior when the replica count of the StatefulSet is reduced | `Retain` | -| `replica.persistentVolumeClaimRetentionPolicy.whenDeleted` | Volume retention behavior that applies when the StatefulSet is deleted | `Retain` | -| `replica.service.type` | Redis® replicas service type | `ClusterIP` | -| `replica.service.ports.redis` | Redis® replicas service port | `6379` | -| `replica.service.nodePorts.redis` | Node port for Redis® replicas | `""` | -| `replica.service.externalTrafficPolicy` | Redis® replicas service external traffic policy | `Cluster` | -| `replica.service.internalTrafficPolicy` | Redis® replicas service internal traffic policy (requires Kubernetes v1.22 or greater to be usable) | `Cluster` | -| `replica.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | -| `replica.service.clusterIP` | Redis® replicas service Cluster IP | `""` | -| `replica.service.loadBalancerIP` | Redis® replicas service Load Balancer IP | `""` | -| `replica.service.loadBalancerClass` | replicas service Load Balancer class if service type is `LoadBalancer` (optional, cloud specific) | `""` | -| `replica.service.loadBalancerSourceRanges` | Redis® replicas service Load Balancer sources | `[]` | -| `replica.service.annotations` | Additional custom annotations for Redis® replicas service | `{}` | -| `replica.service.sessionAffinity` | Session Affinity for Kubernetes service, can be "None" or "ClientIP" | `None` | -| `replica.service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | -| `replica.terminationGracePeriodSeconds` | Integer setting the termination grace period for the redis-replicas pods | `30` | -| `replica.autoscaling.enabled` | Enable replica autoscaling settings | `false` | -| `replica.autoscaling.minReplicas` | Minimum replicas for the pod autoscaling | `1` | -| `replica.autoscaling.maxReplicas` | Maximum replicas for the pod autoscaling | `11` | -| `replica.autoscaling.targetCPU` | Percentage of CPU to consider when autoscaling | `""` | -| `replica.autoscaling.targetMemory` | Percentage of Memory to consider when autoscaling | `""` | -| `replica.serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` | -| `replica.serviceAccount.name` | The name of the ServiceAccount to use. | `""` | -| `replica.serviceAccount.automountServiceAccountToken` | Whether to auto mount the service account token | `false` | -| `replica.serviceAccount.annotations` | Additional custom annotations for the ServiceAccount | `{}` | -| `replica.pdb.create` | Enable/disable a Pod Disruption Budget creation | `true` | -| `replica.pdb.minAvailable` | Minimum number/percentage of pods that should remain scheduled | `{}` | -| `replica.pdb.maxUnavailable` | Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `replica.pdb.minAvailable` and `replica.pdb.maxUnavailable` are empty. | `{}` | -| `replica.extraPodSpec` | Optionally specify extra PodSpec for the Redis® replicas pod(s) | `{}` | - -### Redis® Sentinel configuration parameters - -| Name | Description | Value | -| ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | -| `sentinel.enabled` | Use Redis® Sentinel on Redis® pods. | `false` | -| `sentinel.image.registry` | Redis® Sentinel image registry | `REGISTRY_NAME` | -| `sentinel.image.repository` | Redis® Sentinel image repository | `REPOSITORY_NAME/redis-sentinel` | -| `sentinel.image.digest` | Redis® Sentinel image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | -| `sentinel.image.pullPolicy` | Redis® Sentinel image pull policy | `IfNotPresent` | -| `sentinel.image.pullSecrets` | Redis® Sentinel image pull secrets | `[]` | -| `sentinel.image.debug` | Enable image debug mode | `false` | -| `sentinel.annotations` | Additional custom annotations for Redis® Sentinel resource | `{}` | -| `sentinel.masterSet` | Master set name | `mymaster` | -| `sentinel.quorum` | Sentinel Quorum | `2` | -| `sentinel.getMasterTimeout` | Amount of time to allow before get_sentinel_master_info() times out. | `90` | -| `sentinel.automateClusterRecovery` | Automate cluster recovery in cases where the last replica is not considered a good replica and Sentinel won't automatically failover to it. | `false` | -| `sentinel.redisShutdownWaitFailover` | Whether the Redis® master container waits for the failover at shutdown (in addition to the Redis® Sentinel container). | `true` | -| `sentinel.downAfterMilliseconds` | Timeout for detecting a Redis® node is down | `60000` | -| `sentinel.failoverTimeout` | Timeout for performing a election failover | `180000` | -| `sentinel.parallelSyncs` | Number of replicas that can be reconfigured in parallel to use the new master after a failover | `1` | -| `sentinel.configuration` | Configuration for Redis® Sentinel nodes | `""` | -| `sentinel.command` | Override default container command (useful when using custom images) | `[]` | -| `sentinel.args` | Override default container args (useful when using custom images) | `[]` | -| `sentinel.enableServiceLinks` | Whether information about services should be injected into pod's environment variable | `true` | -| `sentinel.preExecCmds` | Additional commands to run prior to starting Redis® Sentinel | `[]` | -| `sentinel.extraEnvVars` | Array with extra environment variables to add to Redis® Sentinel nodes | `[]` | -| `sentinel.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for Redis® Sentinel nodes | `""` | -| `sentinel.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for Redis® Sentinel nodes | `""` | -| `sentinel.externalMaster.enabled` | Use external master for bootstrapping | `false` | -| `sentinel.externalMaster.host` | External master host to bootstrap from | `""` | -| `sentinel.externalMaster.port` | Port for Redis service external master host | `6379` | -| `sentinel.containerPorts.sentinel` | Container port to open on Redis® Sentinel nodes | `26379` | -| `sentinel.startupProbe.enabled` | Enable startupProbe on Redis® Sentinel nodes | `true` | -| `sentinel.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `10` | -| `sentinel.startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | -| `sentinel.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `5` | -| `sentinel.startupProbe.failureThreshold` | Failure threshold for startupProbe | `22` | -| `sentinel.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | -| `sentinel.livenessProbe.enabled` | Enable livenessProbe on Redis® Sentinel nodes | `true` | -| `sentinel.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `20` | -| `sentinel.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `10` | -| `sentinel.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `5` | -| `sentinel.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `6` | -| `sentinel.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | -| `sentinel.readinessProbe.enabled` | Enable readinessProbe on Redis® Sentinel nodes | `true` | -| `sentinel.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `20` | -| `sentinel.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `5` | -| `sentinel.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `1` | -| `sentinel.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `6` | -| `sentinel.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | -| `sentinel.customStartupProbe` | Custom startupProbe that overrides the default one | `{}` | -| `sentinel.customLivenessProbe` | Custom livenessProbe that overrides the default one | `{}` | -| `sentinel.customReadinessProbe` | Custom readinessProbe that overrides the default one | `{}` | -| `sentinel.persistence.enabled` | Enable persistence on Redis® sentinel nodes using Persistent Volume Claims (Experimental) | `false` | -| `sentinel.persistence.storageClass` | Persistent Volume storage class | `""` | -| `sentinel.persistence.accessModes` | Persistent Volume access modes | `["ReadWriteOnce"]` | -| `sentinel.persistence.size` | Persistent Volume size | `100Mi` | -| `sentinel.persistence.annotations` | Additional custom annotations for the PVC | `{}` | -| `sentinel.persistence.labels` | Additional custom labels for the PVC | `{}` | -| `sentinel.persistence.selector` | Additional labels to match for the PVC | `{}` | -| `sentinel.persistence.dataSource` | Custom PVC data source | `{}` | -| `sentinel.persistence.medium` | Provide a medium for `emptyDir` volumes. | `""` | -| `sentinel.persistence.sizeLimit` | Set this to enable a size limit for `emptyDir` volumes. | `""` | -| `sentinel.persistentVolumeClaimRetentionPolicy.enabled` | Controls if and how PVCs are deleted during the lifecycle of a StatefulSet | `false` | -| `sentinel.persistentVolumeClaimRetentionPolicy.whenScaled` | Volume retention behavior when the replica count of the StatefulSet is reduced | `Retain` | -| `sentinel.persistentVolumeClaimRetentionPolicy.whenDeleted` | Volume retention behavior that applies when the StatefulSet is deleted | `Retain` | -| `sentinel.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if sentinel.resources is set (sentinel.resources is recommended for production). | `nano` | -| `sentinel.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | -| `sentinel.containerSecurityContext.enabled` | Enabled Redis® Sentinel containers' Security Context | `true` | -| `sentinel.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | -| `sentinel.containerSecurityContext.runAsUser` | Set Redis® Sentinel containers' Security Context runAsUser | `1001` | -| `sentinel.containerSecurityContext.runAsGroup` | Set Redis® Sentinel containers' Security Context runAsGroup | `1001` | -| `sentinel.containerSecurityContext.runAsNonRoot` | Set Redis® Sentinel containers' Security Context runAsNonRoot | `true` | -| `sentinel.containerSecurityContext.readOnlyRootFilesystem` | Set container's Security Context read-only root filesystem | `true` | -| `sentinel.containerSecurityContext.allowPrivilegeEscalation` | Set Redis® Sentinel containers' Security Context allowPrivilegeEscalation | `false` | -| `sentinel.containerSecurityContext.seccompProfile.type` | Set Redis® Sentinel containers' Security Context seccompProfile | `RuntimeDefault` | -| `sentinel.containerSecurityContext.capabilities.drop` | Set Redis® Sentinel containers' Security Context capabilities to drop | `["ALL"]` | -| `sentinel.lifecycleHooks` | for the Redis® sentinel container(s) to automate configuration before or after startup | `{}` | -| `sentinel.extraVolumes` | Optionally specify extra list of additional volumes for the Redis® Sentinel | `[]` | -| `sentinel.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the Redis® Sentinel container(s) | `[]` | -| `sentinel.service.type` | Redis® Sentinel service type | `ClusterIP` | -| `sentinel.service.ports.redis` | Redis® service port for Redis® | `6379` | -| `sentinel.service.ports.sentinel` | Redis® service port for Redis® Sentinel | `26379` | -| `sentinel.service.nodePorts.redis` | Node port for Redis® | `""` | -| `sentinel.service.nodePorts.sentinel` | Node port for Sentinel | `""` | -| `sentinel.service.externalTrafficPolicy` | Redis® Sentinel service external traffic policy | `Cluster` | -| `sentinel.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | -| `sentinel.service.clusterIP` | Redis® Sentinel service Cluster IP | `""` | -| `sentinel.service.createMaster` | Enable master service pointing to the current master (experimental) | `false` | -| `sentinel.service.loadBalancerIP` | Redis® Sentinel service Load Balancer IP | `""` | -| `sentinel.service.loadBalancerClass` | sentinel service Load Balancer class if service type is `LoadBalancer` (optional, cloud specific) | `""` | -| `sentinel.service.loadBalancerSourceRanges` | Redis® Sentinel service Load Balancer sources | `[]` | -| `sentinel.service.annotations` | Additional custom annotations for Redis® Sentinel service | `{}` | -| `sentinel.service.sessionAffinity` | Session Affinity for Kubernetes service, can be "None" or "ClientIP" | `None` | -| `sentinel.service.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | -| `sentinel.service.headless.annotations` | Annotations for the headless service. | `{}` | -| `sentinel.masterService.enabled` | Enable master service pointing to the current master (experimental) | `false` | -| `sentinel.masterService.type` | Redis® Sentinel master service type | `ClusterIP` | -| `sentinel.masterService.ports.redis` | Redis® service port for Redis® | `6379` | -| `sentinel.masterService.nodePorts.redis` | Node port for Redis® | `""` | -| `sentinel.masterService.externalTrafficPolicy` | Redis® master service external traffic policy | `""` | -| `sentinel.masterService.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | -| `sentinel.masterService.clusterIP` | Redis® master service Cluster IP | `""` | -| `sentinel.masterService.loadBalancerIP` | Redis® master service Load Balancer IP | `""` | -| `sentinel.masterService.loadBalancerClass` | master service Load Balancer class if service type is `LoadBalancer` (optional, cloud specific) | `""` | -| `sentinel.masterService.loadBalancerSourceRanges` | Redis® master service Load Balancer sources | `[]` | -| `sentinel.masterService.annotations` | Additional custom annotations for Redis® master service | `{}` | -| `sentinel.masterService.sessionAffinity` | Session Affinity for Kubernetes service, can be "None" or "ClientIP" | `None` | -| `sentinel.masterService.sessionAffinityConfig` | Additional settings for the sessionAffinity | `{}` | -| `sentinel.terminationGracePeriodSeconds` | Integer setting the termination grace period for the redis-node pods | `30` | -| `sentinel.extraPodSpec` | Optionally specify extra PodSpec for the Redis® Sentinel pod(s) | `{}` | - -### Other Parameters - -| Name | Description | Value | -| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------- | -| `serviceBindings.enabled` | Create secret for service binding (Experimental) | `false` | -| `networkPolicy.enabled` | Enable creation of NetworkPolicy resources | `true` | -| `networkPolicy.allowExternal` | Don't require client label for connections | `true` | -| `networkPolicy.allowExternalEgress` | Allow the pod to access any range of port and all destinations. | `true` | -| `networkPolicy.extraIngress` | Add extra ingress rules to the NetworkPolicy | `[]` | -| `networkPolicy.extraEgress` | Add extra egress rules to the NetworkPolicy | `[]` | -| `networkPolicy.ingressNSMatchLabels` | Labels to match to allow traffic from other namespaces | `{}` | -| `networkPolicy.ingressNSPodMatchLabels` | Pod labels to match to allow traffic from other namespaces | `{}` | -| `networkPolicy.metrics.allowExternal` | Don't require client label for connections for metrics endpoint | `true` | -| `networkPolicy.metrics.ingressNSMatchLabels` | Labels to match to allow traffic from other namespaces to metrics endpoint | `{}` | -| `networkPolicy.metrics.ingressNSPodMatchLabels` | Pod labels to match to allow traffic from other namespaces to metrics endpoint | `{}` | -| `podSecurityPolicy.create` | Whether to create a PodSecurityPolicy. WARNING: PodSecurityPolicy is deprecated in Kubernetes v1.21 or later, unavailable in v1.25 or later | `false` | -| `podSecurityPolicy.enabled` | Enable PodSecurityPolicy's RBAC rules | `false` | -| `rbac.create` | Specifies whether RBAC resources should be created | `false` | -| `rbac.rules` | Custom RBAC rules to set | `[]` | -| `serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` | -| `serviceAccount.name` | The name of the ServiceAccount to use. | `""` | -| `serviceAccount.automountServiceAccountToken` | Whether to auto mount the service account token | `false` | -| `serviceAccount.annotations` | Additional custom annotations for the ServiceAccount | `{}` | -| `pdb` | DEPRECATED Please use `master.pdb` and `replica.pdb` values instead | `{}` | -| `tls.enabled` | Enable TLS traffic | `false` | -| `tls.authClients` | Require clients to authenticate | `true` | -| `tls.autoGenerated` | Enable autogenerated certificates | `false` | -| `tls.existingSecret` | The name of the existing secret that contains the TLS certificates | `""` | -| `tls.certificatesSecret` | DEPRECATED. Use existingSecret instead. | `""` | -| `tls.certFilename` | Certificate filename | `""` | -| `tls.certKeyFilename` | Certificate Key filename | `""` | -| `tls.certCAFilename` | CA Certificate filename | `""` | -| `tls.dhParamsFilename` | File containing DH params (in order to support DH based ciphers) | `""` | - -### Metrics Parameters - -| Name | Description | Value | -| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | -| `metrics.enabled` | Start a sidecar prometheus exporter to expose Redis® metrics | `false` | -| `metrics.image.registry` | Redis® Exporter image registry | `REGISTRY_NAME` | -| `metrics.image.repository` | Redis® Exporter image repository | `REPOSITORY_NAME/redis-exporter` | -| `metrics.image.digest` | Redis® Exporter image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | -| `metrics.image.pullPolicy` | Redis® Exporter image pull policy | `IfNotPresent` | -| `metrics.image.pullSecrets` | Redis® Exporter image pull secrets | `[]` | -| `metrics.containerPorts.http` | Metrics HTTP container port | `9121` | -| `metrics.startupProbe.enabled` | Enable startupProbe on Redis® replicas nodes | `false` | -| `metrics.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `10` | -| `metrics.startupProbe.periodSeconds` | Period seconds for startupProbe | `10` | -| `metrics.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `5` | -| `metrics.startupProbe.failureThreshold` | Failure threshold for startupProbe | `5` | -| `metrics.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | -| `metrics.livenessProbe.enabled` | Enable livenessProbe on Redis® replicas nodes | `true` | -| `metrics.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `10` | -| `metrics.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `10` | -| `metrics.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `5` | -| `metrics.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `5` | -| `metrics.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | -| `metrics.readinessProbe.enabled` | Enable readinessProbe on Redis® replicas nodes | `true` | -| `metrics.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `5` | -| `metrics.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `10` | -| `metrics.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `1` | -| `metrics.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `3` | -| `metrics.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | -| `metrics.customStartupProbe` | Custom startupProbe that overrides the default one | `{}` | -| `metrics.customLivenessProbe` | Custom livenessProbe that overrides the default one | `{}` | -| `metrics.customReadinessProbe` | Custom readinessProbe that overrides the default one | `{}` | -| `metrics.command` | Override default metrics container init command (useful when using custom images) | `[]` | -| `metrics.redisTargetHost` | A way to specify an alternative Redis® hostname | `localhost` | -| `metrics.extraArgs` | Extra arguments for Redis® exporter, for example: | `{}` | -| `metrics.extraEnvVars` | Array with extra environment variables to add to Redis® exporter | `[]` | -| `metrics.containerSecurityContext.enabled` | Enabled Redis® exporter containers' Security Context | `true` | -| `metrics.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | -| `metrics.containerSecurityContext.runAsUser` | Set Redis® exporter containers' Security Context runAsUser | `1001` | -| `metrics.containerSecurityContext.runAsGroup` | Set Redis® exporter containers' Security Context runAsGroup | `1001` | -| `metrics.containerSecurityContext.runAsNonRoot` | Set Redis® exporter containers' Security Context runAsNonRoot | `true` | -| `metrics.containerSecurityContext.allowPrivilegeEscalation` | Set Redis® exporter containers' Security Context allowPrivilegeEscalation | `false` | -| `metrics.containerSecurityContext.readOnlyRootFilesystem` | Set container's Security Context read-only root filesystem | `true` | -| `metrics.containerSecurityContext.seccompProfile.type` | Set Redis® exporter containers' Security Context seccompProfile | `RuntimeDefault` | -| `metrics.containerSecurityContext.capabilities.drop` | Set Redis® exporter containers' Security Context capabilities to drop | `["ALL"]` | -| `metrics.extraVolumes` | Optionally specify extra list of additional volumes for the Redis® metrics sidecar | `[]` | -| `metrics.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the Redis® metrics sidecar | `[]` | -| `metrics.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if metrics.resources is set (metrics.resources is recommended for production). | `nano` | -| `metrics.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | -| `metrics.podLabels` | Extra labels for Redis® exporter pods | `{}` | -| `metrics.podAnnotations` | Annotations for Redis® exporter pods | `{}` | -| `metrics.service.enabled` | Create Service resource(s) for scraping metrics using PrometheusOperator ServiceMonitor, can be disabled when using a PodMonitor | `true` | -| `metrics.service.type` | Redis® exporter service type | `ClusterIP` | -| `metrics.service.ports.http` | Redis® exporter service port | `9121` | -| `metrics.service.externalTrafficPolicy` | Redis® exporter service external traffic policy | `Cluster` | -| `metrics.service.extraPorts` | Extra ports to expose (normally used with the `sidecar` value) | `[]` | -| `metrics.service.loadBalancerIP` | Redis® exporter service Load Balancer IP | `""` | -| `metrics.service.loadBalancerClass` | exporter service Load Balancer class if service type is `LoadBalancer` (optional, cloud specific) | `""` | -| `metrics.service.loadBalancerSourceRanges` | Redis® exporter service Load Balancer sources | `[]` | -| `metrics.service.annotations` | Additional custom annotations for Redis® exporter service | `{}` | -| `metrics.service.clusterIP` | Redis® exporter service Cluster IP | `""` | -| `metrics.serviceMonitor.port` | the service port to scrape metrics from | `http-metrics` | -| `metrics.serviceMonitor.enabled` | Create ServiceMonitor resource(s) for scraping metrics using PrometheusOperator | `false` | -| `metrics.serviceMonitor.namespace` | The namespace in which the ServiceMonitor will be created | `""` | -| `metrics.serviceMonitor.interval` | The interval at which metrics should be scraped | `30s` | -| `metrics.serviceMonitor.scrapeTimeout` | The timeout after which the scrape is ended | `""` | -| `metrics.serviceMonitor.relabelings` | Metrics RelabelConfigs to apply to samples before scraping. | `[]` | -| `metrics.serviceMonitor.metricRelabelings` | Metrics RelabelConfigs to apply to samples before ingestion. | `[]` | -| `metrics.serviceMonitor.honorLabels` | Specify honorLabels parameter to add the scrape endpoint | `false` | -| `metrics.serviceMonitor.additionalLabels` | Additional labels that can be used so ServiceMonitor resource(s) can be discovered by Prometheus | `{}` | -| `metrics.serviceMonitor.podTargetLabels` | Labels from the Kubernetes pod to be transferred to the created metrics | `[]` | -| `metrics.serviceMonitor.sampleLimit` | Limit of how many samples should be scraped from every Pod | `false` | -| `metrics.serviceMonitor.targetLimit` | Limit of how many targets should be scraped | `false` | -| `metrics.serviceMonitor.additionalEndpoints` | Additional endpoints to scrape (e.g sentinel) | `[]` | -| `metrics.podMonitor.port` | the pod port to scrape metrics from | `metrics` | -| `metrics.podMonitor.enabled` | Create PodMonitor resource(s) for scraping metrics using PrometheusOperator | `false` | -| `metrics.podMonitor.namespace` | The namespace in which the PodMonitor will be created | `""` | -| `metrics.podMonitor.interval` | The interval at which metrics should be scraped | `30s` | -| `metrics.podMonitor.scrapeTimeout` | The timeout after which the scrape is ended | `""` | -| `metrics.podMonitor.relabelings` | Metrics RelabelConfigs to apply to samples before scraping. | `[]` | -| `metrics.podMonitor.metricRelabelings` | Metrics RelabelConfigs to apply to samples before ingestion. | `[]` | -| `metrics.podMonitor.honorLabels` | Specify honorLabels parameter to add the scrape endpoint | `false` | -| `metrics.podMonitor.additionalLabels` | Additional labels that can be used so PodMonitor resource(s) can be discovered by Prometheus | `{}` | -| `metrics.podMonitor.podTargetLabels` | Labels from the Kubernetes pod to be transferred to the created metrics | `[]` | -| `metrics.podMonitor.sampleLimit` | Limit of how many samples should be scraped from every Pod | `false` | -| `metrics.podMonitor.targetLimit` | Limit of how many targets should be scraped | `false` | -| `metrics.podMonitor.additionalEndpoints` | Additional endpoints to scrape (e.g sentinel) | `[]` | -| `metrics.prometheusRule.enabled` | Create a custom prometheusRule Resource for scraping metrics using PrometheusOperator | `false` | -| `metrics.prometheusRule.namespace` | The namespace in which the prometheusRule will be created | `""` | -| `metrics.prometheusRule.additionalLabels` | Additional labels for the prometheusRule | `{}` | -| `metrics.prometheusRule.rules` | Custom Prometheus rules | `[]` | - -### Init Container Parameters - -| Name | Description | Value | -| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | -| `volumePermissions.enabled` | Enable init container that changes the owner/group of the PV mount point to `runAsUser:fsGroup` | `false` | -| `volumePermissions.image.registry` | OS Shell + Utility image registry | `REGISTRY_NAME` | -| `volumePermissions.image.repository` | OS Shell + Utility image repository | `REPOSITORY_NAME/os-shell` | -| `volumePermissions.image.digest` | OS Shell + Utility image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | -| `volumePermissions.image.pullPolicy` | OS Shell + Utility image pull policy | `IfNotPresent` | -| `volumePermissions.image.pullSecrets` | OS Shell + Utility image pull secrets | `[]` | -| `volumePermissions.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if volumePermissions.resources is set (volumePermissions.resources is recommended for production). | `nano` | -| `volumePermissions.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | -| `volumePermissions.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | -| `volumePermissions.containerSecurityContext.runAsUser` | Set init container's Security Context runAsUser | `0` | -| `volumePermissions.extraEnvVars` | Array with extra environment variables to add to volume permissions init container. | `[]` | -| `kubectl.image.registry` | Kubectl image registry | `REGISTRY_NAME` | -| `kubectl.image.repository` | Kubectl image repository | `REPOSITORY_NAME/kubectl` | -| `kubectl.image.digest` | Kubectl image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | -| `kubectl.image.pullPolicy` | Kubectl image pull policy | `IfNotPresent` | -| `kubectl.image.pullSecrets` | Kubectl pull secrets | `[]` | -| `kubectl.command` | kubectl command to execute | `["/opt/bitnami/scripts/kubectl-scripts/update-master-label.sh"]` | -| `kubectl.containerSecurityContext.enabled` | Enabled kubectl containers' Security Context | `true` | -| `kubectl.containerSecurityContext.seLinuxOptions` | Set SELinux options in container | `{}` | -| `kubectl.containerSecurityContext.runAsUser` | Set kubectl containers' Security Context runAsUser | `1001` | -| `kubectl.containerSecurityContext.runAsGroup` | Set kubectl containers' Security Context runAsGroup | `1001` | -| `kubectl.containerSecurityContext.runAsNonRoot` | Set kubectl containers' Security Context runAsNonRoot | `true` | -| `kubectl.containerSecurityContext.allowPrivilegeEscalation` | Set kubectl containers' Security Context allowPrivilegeEscalation | `false` | -| `kubectl.containerSecurityContext.readOnlyRootFilesystem` | Set container's Security Context read-only root filesystem | `true` | -| `kubectl.containerSecurityContext.seccompProfile.type` | Set kubectl containers' Security Context seccompProfile | `RuntimeDefault` | -| `kubectl.containerSecurityContext.capabilities.drop` | Set kubectl containers' Security Context capabilities to drop | `["ALL"]` | -| `kubectl.resources.limits` | The resources limits for the kubectl containers | `{}` | -| `kubectl.resources.requests` | The requested resources for the kubectl containers | `{}` | -| `sysctl.enabled` | Enable init container to modify Kernel settings | `false` | -| `sysctl.image.registry` | OS Shell + Utility image registry | `REGISTRY_NAME` | -| `sysctl.image.repository` | OS Shell + Utility image repository | `REPOSITORY_NAME/os-shell` | -| `sysctl.image.digest` | OS Shell + Utility image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag | `""` | -| `sysctl.image.pullPolicy` | OS Shell + Utility image pull policy | `IfNotPresent` | -| `sysctl.image.pullSecrets` | OS Shell + Utility image pull secrets | `[]` | -| `sysctl.command` | Override default init-sysctl container command (useful when using custom images) | `[]` | -| `sysctl.mountHostSys` | Mount the host `/sys` folder to `/host-sys` | `false` | -| `sysctl.resourcesPreset` | Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if sysctl.resources is set (sysctl.resources is recommended for production). | `nano` | -| `sysctl.resources` | Set container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | - -### useExternalDNS Parameters - -| Name | Description | Value | -| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -| `useExternalDNS.enabled` | Enable various syntax that would enable external-dns to work. Note this requires a working installation of `external-dns` to be usable. | `false` | -| `useExternalDNS.additionalAnnotations` | Extra annotations to be utilized when `external-dns` is enabled. | `{}` | -| `useExternalDNS.annotationKey` | The annotation key utilized when `external-dns` is enabled. Setting this to `false` will disable annotations. | `external-dns.alpha.kubernetes.io/` | -| `useExternalDNS.suffix` | The DNS suffix utilized when `external-dns` is enabled. Note that we prepend the suffix with the full name of the release. | `""` | - -Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, - -```console -helm install my-release \ - --set auth.password=secretpassword \ - oci://REGISTRY_NAME/REPOSITORY_NAME/redis -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -The above command sets the Redis® server password to `secretpassword`. - -> NOTE: Once this chart is deployed, it is not possible to change the application's access credentials, such as usernames or passwords, using Helm. To change these application credentials after deployment, delete any persistent volumes (PVs) used by the chart and re-deploy it, or use the application's built-in administrative tools if available. - -Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, - -```console -helm install my-release -f values.yaml oci://REGISTRY_NAME/REPOSITORY_NAME/redis -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. -> **Tip**: You can use the default [values.yaml](https://github.com/bitnami/charts/tree/main/bitnami/redis/values.yaml) - -## Troubleshooting - -Find more information about how to deal with common errors related to Bitnami's Helm charts in [this troubleshooting guide](https://docs.bitnami.com/general/how-to/troubleshoot-helm-chart-issues). - -## Upgrading - -A major chart version change (like v1.2.3 -> v2.0.0) indicates that there is an incompatible breaking change needing manual actions. - -### RDB compatibility - -It's common to have RDB format changes across Redis® releases where we see backward compatibility but no forward compatibility. For example, v7.0 can load an RDB created by v6.2 , but the opposite is not true. -When that's the case, the rolling update can cause replicas to temporarily stop synchronizing while they are running a lower version than master. -For example, on a rolling update `master-0` and `replica-2` are updated first from version v6.2 to v7.0; `replica-0` and `replica-1` won't be able to start a full sync with `master-0` because they are still running v6.2 and can't support the RDB format from version 7.0 that master is now using. -This issue can be mitigated by splitting the upgrade into two stages: one for all replicas and another for any master. - -- Stage 1 (replicas only, as there's no master with an ordinal higher than 99): -`helm upgrade oci://REGISTRY_NAME/REPOSITORY_NAME/redis --set master.updateStrategy.rollingUpdate.partition=99` -- Stage 2 (anything else that is not up to date, in this case only master): -`helm upgrade oci://REGISTRY_NAME/REPOSITORY_NAME/redis` - -### To 20.0.0 - -This major version updates the Redis® docker image version used from `7.2` to `7.4`, the new stable version. There are no major changes in the chart, but we recommend checking the [Redis® 7.4 release notes](https://raw.githubusercontent.com/redis/redis/7.4/00-RELEASENOTES) before upgrading. - -### To 19.0.0 - -This major bump changes the following security defaults: - -- `runAsGroup` is changed from `0` to `1001` -- `readOnlyRootFilesystem` is set to `true` -- `resourcesPreset` is changed from `none` to the minimum size working in our test suites (NOTE: `resourcesPreset` is not meant for production usage, but `resources` adapted to your use case). -- `global.compatibility.openshift.adaptSecurityContext` is changed from `disabled` to `auto`. - -This could potentially break any customization or init scripts used in your deployment. If this is the case, change the default values to the previous ones. - -### To 18.0.0 - -This major version updates the Redis® docker image version used from `7.0` to `7.2`, the new stable version. There are no major changes in the chart, but we recommend checking the [Redis® 7.2 release notes](https://raw.githubusercontent.com/redis/redis/7.2/00-RELEASENOTES) before upgrading. - -NOTE: Due to an error in our release process, versions higher or equal than 17.15.4 already use 7.2 by default. - -### To 17.0.0 - -This major version updates the Redis® docker image version used from `6.2` to `7.0`, the new stable version. There are no major changes in the chart, but we recommend checking the [Redis® 7.0 release notes](https://raw.githubusercontent.com/redis/redis/7.0/00-RELEASENOTES) before upgrading. - -### To 16.0.0 - -This major release renames several values in this chart and adds missing features, in order to be inline with the rest of assets in the Bitnami charts repository. - -Affected values: - -- `master.service.port` renamed as `master.service.ports.redis`. -- `master.service.nodePort` renamed as `master.service.nodePorts.redis`. -- `replica.service.port` renamed as `replica.service.ports.redis`. -- `replica.service.nodePort` renamed as `replica.service.nodePorts.redis`. -- `sentinel.service.port` renamed as `sentinel.service.ports.redis`. -- `sentinel.service.sentinelPort` renamed as `sentinel.service.ports.sentinel`. -- `master.containerPort` renamed as `master.containerPorts.redis`. -- `replica.containerPort` renamed as `replica.containerPorts.redis`. -- `sentinel.containerPort` renamed as `sentinel.containerPorts.sentinel`. -- `master.spreadConstraints` renamed as `master.topologySpreadConstraints` -- `replica.spreadConstraints` renamed as `replica.topologySpreadConstraints` - -### To 15.0.0 - -The parameter to enable the usage of StaticIDs was removed. The behavior is to [always use StaticIDs](https://github.com/bitnami/charts/pull/7278). - -### To 14.8.0 - -The Redis® sentinel exporter was removed in this version because the upstream project was deprecated. The regular Redis® exporter is included in the sentinel scenario as usual. - -### To 14.0.0 - -- Several parameters were renamed or disappeared in favor of new ones on this major version: - - The term *slave* has been replaced by the term *replica*. Therefore, parameters prefixed with `slave` are now prefixed with `replicas`. - - Credentials parameter are reorganized under the `auth` parameter. - - `cluster.enabled` parameter is deprecated in favor of `architecture` parameter that accepts two values: `standalone` and `replication`. - - `securityContext.*` is deprecated in favor of `XXX.podSecurityContext` and `XXX.containerSecurityContext`. - - `sentinel.metrics.*` parameters are deprecated in favor of `metrics.sentinel.*` ones. -- New parameters to add custom command, environment variables, sidecars, init containers, etc. were added. -- Chart labels were adapted to follow the [Helm charts standard labels](https://helm.sh/docs/chart_best_practices/labels/#standard-labels). -- values.yaml metadata was adapted to follow the format supported by [Readme Generator for Helm](https://github.com/bitnami/readme-generator-for-helm). - -Consequences: - -Backwards compatibility is not guaranteed. To upgrade to `14.0.0`, install a new release of the Redis® chart, and migrate the data from your previous release. You have 2 alternatives to do so: - -- Create a backup of the database, and restore it on the new release as explained in the [Backup and restore](#backup-and-restore) section. -- Reuse the PVC used to hold the master data on your previous release. To do so, use the `master.persistence.existingClaim` parameter. The following example assumes that the release name is `redis`: - -```console -helm install redis oci://REGISTRY_NAME/REPOSITORY_NAME/redis --set auth.password=[PASSWORD] --set master.persistence.existingClaim=[EXISTING_PVC] -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -| Note: you need to substitute the placeholder *[EXISTING_PVC]* with the name of the PVC used on your previous release, and *[PASSWORD]* with the password used in your previous release. - -### To 13.0.0 - -This major version updates the Redis® docker image version used from `6.0` to `6.2`, the new stable version. There are no major changes in the chart and there shouldn't be any breaking changes in it as `6.2` is basically a stricter superset of `6.0`. For more information, please refer to [Redis® 6.2 release notes](https://raw.githubusercontent.com/redis/redis/6.2/00-RELEASENOTES). - -### To 12.3.0 - -This version also introduces `bitnami/common`, a [library chart](https://helm.sh/docs/topics/library_charts/#helm) as a dependency. More documentation about this new utility could be found [here](https://github.com/bitnami/charts/tree/main/bitnami/common#bitnami-common-library-chart). Please, make sure that you have updated the chart dependencies before executing any upgrade. - -### To 12.0.0 - -[On November 13, 2020, Helm v2 support was formally finished](https://github.com/helm/charts#status-of-the-project), this major version is the result of the required changes applied to the Helm Chart to be able to incorporate the different features added in Helm v3 and to be consistent with the Helm project itself regarding the Helm v2 EOL. - -#### What changes were introduced in this major version? - -- Previous versions of this Helm Chart use `apiVersion: v1` (installable by both Helm 2 and 3), this Helm Chart was updated to `apiVersion: v2` (installable by Helm 3 only). [Here](https://helm.sh/docs/topics/charts/#the-apiversion-field) you can find more information about the `apiVersion` field. -- The different fields present in the *Chart.yaml* file has been ordered alphabetically in a homogeneous way for all the Bitnami Helm Charts - -#### Considerations when upgrading to this version - -- If you want to upgrade to this version from a previous one installed with Helm v3, you shouldn't face any issues -- If you want to upgrade to this version using Helm v2, this scenario is not supported as this version doesn't support Helm v2 anymore -- If you installed the previous version with Helm v2 and wants to upgrade to this version with Helm v3, please refer to the [official Helm documentation](https://helm.sh/docs/topics/v2_v3_migration/#migration-use-cases) about migrating from Helm v2 to v3 - -#### Useful links - -- -- -- - -### To 11.0.0 - -When using sentinel, a new statefulset called `-node` was introduced. This will break upgrading from a previous version where the statefulsets are called master and slave. Hence the PVC will not match the new naming and won't be reused. If you want to keep your data, you will need to perform a backup and then a restore the data in this new version. - -When deployed with sentinel enabled, only a group of nodes is deployed and the master/slave role is handled in the group. To avoid breaking the compatibility, the settings for this nodes are given through the `slave.xxxx` parameters in `values.yaml` - -### To 10.0.0 - -For releases with `usePassword: true`, the value `sentinel.usePassword` controls whether the password authentication also applies to the sentinel port. This defaults to `true` for a secure configuration, however it is possible to disable to account for the following cases: - -- Using a version of redis-sentinel prior to `5.0.1` where the authentication feature was introduced. -- Where redis clients need to be updated to support sentinel authentication. - -If using a master/slave topology, or with `usePassword: false`, no action is required. - -### To 9.0.0 - -The metrics exporter has been changed from a separate deployment to a sidecar container, due to the latest changes in the Redis® exporter code. Check the [official page](https://github.com/oliver006/redis_exporter/) for more information. The metrics container image was changed from oliver006/redis_exporter to bitnami/redis-exporter (Bitnami's maintained package of oliver006/redis_exporter). - -### To 8.0.18 - -For releases with `metrics.enabled: true` the default tag for the exporter image is now `v1.x.x`. This introduces many changes including metrics names. You'll want to use [this dashboard](https://github.com/oliver006/redis_exporter/blob/master/contrib/grafana_prometheus_redis_dashboard.json) now. Please see the [redis_exporter github page](https://github.com/oliver006/redis_exporter#upgrading-from-0x-to-1x) for more details. - -### To 7.0.0 - -This version causes a change in the Redis® Master StatefulSet definition, so the command helm upgrade would not work out of the box. As an alternative, one of the following could be done: - -- Recommended: Create a clone of the Redis® Master PVC (for example, using projects like [this one](https://github.com/edseymour/pvc-transfer)). Then launch a fresh release reusing this cloned PVC. - -```console -helm install my-release oci://REGISTRY_NAME/REPOSITORY_NAME/redis --set persistence.existingClaim= -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -- Alternative (not recommended, do at your own risk): `helm delete --purge` does not remove the PVC assigned to the Redis® Master StatefulSet. As a consequence, the following commands can be done to upgrade the release - -```console -helm delete --purge -helm install oci://REGISTRY_NAME/REPOSITORY_NAME/redis -``` - -> Note: You need to substitute the placeholders `REGISTRY_NAME` and `REPOSITORY_NAME` with a reference to your Helm chart registry and repository. For example, in the case of Bitnami, you need to use `REGISTRY_NAME=registry-1.docker.io` and `REPOSITORY_NAME=bitnamicharts`. - -Previous versions of the chart were not using persistence in the slaves, so this upgrade would add it to them. Another important change is that no values are inherited from master to slaves. For example, in 6.0.0 `slaves.readinessProbe.periodSeconds`, if empty, would be set to `master.readinessProbe.periodSeconds`. This approach lacked transparency and was difficult to maintain. From now on, all the slave parameters must be configured just as it is done with the masters. - -Some values have changed as well: - -- `master.port` and `slave.port` have been changed to `redisPort` (same value for both master and slaves) -- `master.securityContext` and `slave.securityContext` have been changed to `securityContext`(same values for both master and slaves) - -By default, the upgrade will not change the cluster topology. In case you want to use Redis® Sentinel, you must explicitly set `sentinel.enabled` to `true`. - -### To 6.0.0 - -Previous versions of the chart were using an init-container to change the permissions of the volumes. This was done in case the `securityContext` directive in the template was not enough for that (for example, with cephFS). In this new version of the chart, this container is disabled by default (which should not affect most of the deployments). If your installation still requires that init container, execute `helm upgrade` with the `--set volumePermissions.enabled=true`. - -### To 5.0.0 - -The default image in this release may be switched out for any image containing the `redis-server` -and `redis-cli` binaries. If `redis-server` is not the default image ENTRYPOINT, `master.command` -must be specified. - -#### Breaking changes - -- `master.args` and `slave.args` are removed. Use `master.command` or `slave.command` instead in order to override the image entrypoint, or `master.extraFlags` to pass additional flags to `redis-server`. -- `disableCommands` is now interpreted as an array of strings instead of a string of comma separated values. -- `master.persistence.path` now defaults to `/data`. - -### To 4.0.0 - -This version removes the `chart` label from the `spec.selector.matchLabels` -which is immutable since `StatefulSet apps/v1beta2`. It has been inadvertently -added, causing any subsequent upgrade to fail. See . - -It also fixes where a deployment `extensions/v1beta1` can not be upgraded if `spec.selector` is not explicitly set. - -Finally, it fixes by removing mutable labels in `spec.VolumeClaimTemplate.metadata.labels` so that it is upgradable. - -In order to upgrade, delete the Redis® StatefulSet before upgrading: - -```console -kubectl delete statefulsets.apps --cascade=false my-release-redis-master -``` - -And edit the Redis® slave (and metrics if enabled) deployment: - -```console -kubectl patch deployments my-release-redis-slave --type=json -p='[{"op": "remove", "path": "/spec/selector/matchLabels/chart"}]' -kubectl patch deployments my-release-redis-metrics --type=json -p='[{"op": "remove", "path": "/spec/selector/matchLabels/chart"}]' -``` - -## License - -Copyright © 2024 Broadcom. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. \ No newline at end of file diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/Chart.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/Chart.yaml deleted file mode 100644 index 8cc0aaa0..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/Chart.yaml +++ /dev/null @@ -1,23 +0,0 @@ -annotations: - category: Infrastructure - licenses: Apache-2.0 -apiVersion: v2 -appVersion: 2.23.0 -description: A Library Helm Chart for grouping common logic between bitnami charts. - This chart is not deployable by itself. -home: https://bitnami.com -icon: https://bitnami.com/downloads/logos/bitnami-mark.png -keywords: -- common -- helper -- template -- function -- bitnami -maintainers: -- name: Broadcom, Inc. All Rights Reserved. - url: https://github.com/bitnami/charts -name: common -sources: -- https://github.com/bitnami/charts/tree/main/bitnami/common -type: library -version: 2.23.0 diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/README.md b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/README.md deleted file mode 100644 index fee26c99..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/README.md +++ /dev/null @@ -1,235 +0,0 @@ -# Bitnami Common Library Chart - -A [Helm Library Chart](https://helm.sh/docs/topics/library_charts/#helm) for grouping common logic between Bitnami charts. - -## TL;DR - -```yaml -dependencies: - - name: common - version: 2.x.x - repository: oci://registry-1.docker.io/bitnamicharts -``` - -```console -helm dependency update -``` - -```yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "common.names.fullname" . }} -data: - myvalue: "Hello World" -``` - -Looking to use our applications in production? Try [VMware Tanzu Application Catalog](https://bitnami.com/enterprise), the commercial edition of the Bitnami catalog. - -## Introduction - -This chart provides a common template helpers which can be used to develop new charts using [Helm](https://helm.sh) package manager. - -Bitnami charts can be used with [Kubeapps](https://kubeapps.dev/) for deployment and management of Helm Charts in clusters. - -## Prerequisites - -- Kubernetes 1.23+ -- Helm 3.8.0+ - -## Parameters - -## Special input schemas - -### ImageRoot - -```yaml -registry: - type: string - description: Docker registry where the image is located - example: docker.io - -repository: - type: string - description: Repository and image name - example: bitnami/nginx - -tag: - type: string - description: image tag - example: 1.16.1-debian-10-r63 - -pullPolicy: - type: string - description: Specify a imagePullPolicy. Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' - -pullSecrets: - type: array - items: - type: string - description: Optionally specify an array of imagePullSecrets (evaluated as templates). - -debug: - type: boolean - description: Set to true if you would like to see extra information on logs - example: false - -## An instance would be: -# registry: docker.io -# repository: bitnami/nginx -# tag: 1.16.1-debian-10-r63 -# pullPolicy: IfNotPresent -# debug: false -``` - -### Persistence - -```yaml -enabled: - type: boolean - description: Whether enable persistence. - example: true - -storageClass: - type: string - description: Ghost data Persistent Volume Storage Class, If set to "-", storageClassName: "" which disables dynamic provisioning. - example: "-" - -accessMode: - type: string - description: Access mode for the Persistent Volume Storage. - example: ReadWriteOnce - -size: - type: string - description: Size the Persistent Volume Storage. - example: 8Gi - -path: - type: string - description: Path to be persisted. - example: /bitnami - -## An instance would be: -# enabled: true -# storageClass: "-" -# accessMode: ReadWriteOnce -# size: 8Gi -# path: /bitnami -``` - -### ExistingSecret - -```yaml -name: - type: string - description: Name of the existing secret. - example: mySecret -keyMapping: - description: Mapping between the expected key name and the name of the key in the existing secret. - type: object - -## An instance would be: -# name: mySecret -# keyMapping: -# password: myPasswordKey -``` - -#### Example of use - -When we store sensitive data for a deployment in a secret, some times we want to give to users the possibility of using theirs existing secrets. - -```yaml -# templates/secret.yaml ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "common.names.fullname" . }} - labels: - app: {{ include "common.names.fullname" . }} -type: Opaque -data: - password: {{ .Values.password | b64enc | quote }} - -# templates/dpl.yaml ---- -... - env: - - name: PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "common.secrets.name" (dict "existingSecret" .Values.existingSecret "context" $) }} - key: {{ include "common.secrets.key" (dict "existingSecret" .Values.existingSecret "key" "password") }} -... - -# values.yaml ---- -name: mySecret -keyMapping: - password: myPasswordKey -``` - -### ValidateValue - -#### NOTES.txt - -```console -{{- $validateValueConf00 := (dict "valueKey" "path.to.value00" "secret" "secretName" "field" "password-00") -}} -{{- $validateValueConf01 := (dict "valueKey" "path.to.value01" "secret" "secretName" "field" "password-01") -}} - -{{ include "common.validations.values.multiple.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} -``` - -If we force those values to be empty we will see some alerts - -```console -helm install test mychart --set path.to.value00="",path.to.value01="" - 'path.to.value00' must not be empty, please add '--set path.to.value00=$PASSWORD_00' to the command. To get the current value: - - export PASSWORD_00=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-00}" | base64 -d) - - 'path.to.value01' must not be empty, please add '--set path.to.value01=$PASSWORD_01' to the command. To get the current value: - - export PASSWORD_01=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-01}" | base64 -d) -``` - -## Upgrading - -### To 1.0.0 - -[On November 13, 2020, Helm v2 support was formally finished](https://github.com/helm/charts#status-of-the-project), this major version is the result of the required changes applied to the Helm Chart to be able to incorporate the different features added in Helm v3 and to be consistent with the Helm project itself regarding the Helm v2 EOL. - -#### What changes were introduced in this major version? - -- Previous versions of this Helm Chart use `apiVersion: v1` (installable by both Helm 2 and 3), this Helm Chart was updated to `apiVersion: v2` (installable by Helm 3 only). [Here](https://helm.sh/docs/topics/charts/#the-apiversion-field) you can find more information about the `apiVersion` field. -- Use `type: library`. [Here](https://v3.helm.sh/docs/faq/#library-chart-support) you can find more information. -- The different fields present in the *Chart.yaml* file has been ordered alphabetically in a homogeneous way for all the Bitnami Helm Charts - -#### Considerations when upgrading to this version - -- If you want to upgrade to this version from a previous one installed with Helm v3, you shouldn't face any issues -- If you want to upgrade to this version using Helm v2, this scenario is not supported as this version doesn't support Helm v2 anymore -- If you installed the previous version with Helm v2 and wants to upgrade to this version with Helm v3, please refer to the [official Helm documentation](https://helm.sh/docs/topics/v2_v3_migration/#migration-use-cases) about migrating from Helm v2 to v3 - -#### Useful links - -- -- -- - -## License - -Copyright © 2024 Broadcom. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_affinities.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_affinities.tpl deleted file mode 100644 index c2d29079..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_affinities.tpl +++ /dev/null @@ -1,139 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} - -{{/* -Return a soft nodeAffinity definition -{{ include "common.affinities.nodes.soft" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} -*/}} -{{- define "common.affinities.nodes.soft" -}} -preferredDuringSchedulingIgnoredDuringExecution: - - preference: - matchExpressions: - - key: {{ .key }} - operator: In - values: - {{- range .values }} - - {{ . | quote }} - {{- end }} - weight: 1 -{{- end -}} - -{{/* -Return a hard nodeAffinity definition -{{ include "common.affinities.nodes.hard" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}} -*/}} -{{- define "common.affinities.nodes.hard" -}} -requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: {{ .key }} - operator: In - values: - {{- range .values }} - - {{ . | quote }} - {{- end }} -{{- end -}} - -{{/* -Return a nodeAffinity definition -{{ include "common.affinities.nodes" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} -*/}} -{{- define "common.affinities.nodes" -}} - {{- if eq .type "soft" }} - {{- include "common.affinities.nodes.soft" . -}} - {{- else if eq .type "hard" }} - {{- include "common.affinities.nodes.hard" . -}} - {{- end -}} -{{- end -}} - -{{/* -Return a topologyKey definition -{{ include "common.affinities.topologyKey" (dict "topologyKey" "BAR") -}} -*/}} -{{- define "common.affinities.topologyKey" -}} -{{ .topologyKey | default "kubernetes.io/hostname" -}} -{{- end -}} - -{{/* -Return a soft podAffinity/podAntiAffinity definition -{{ include "common.affinities.pods.soft" (dict "component" "FOO" "customLabels" .Values.podLabels "extraMatchLabels" .Values.extraMatchLabels "topologyKey" "BAR" "extraPodAffinityTerms" .Values.extraPodAffinityTerms "context" $) -}} -*/}} -{{- define "common.affinities.pods.soft" -}} -{{- $component := default "" .component -}} -{{- $customLabels := default (dict) .customLabels -}} -{{- $extraMatchLabels := default (dict) .extraMatchLabels -}} -{{- $extraPodAffinityTerms := default (list) .extraPodAffinityTerms -}} -preferredDuringSchedulingIgnoredDuringExecution: - - podAffinityTerm: - labelSelector: - matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" .context )) | nindent 10 }} - {{- if not (empty $component) }} - {{ printf "app.kubernetes.io/component: %s" $component }} - {{- end }} - {{- range $key, $value := $extraMatchLabels }} - {{ $key }}: {{ $value | quote }} - {{- end }} - topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} - weight: 1 - {{- range $extraPodAffinityTerms }} - - podAffinityTerm: - labelSelector: - matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" $.context )) | nindent 10 }} - {{- if not (empty $component) }} - {{ printf "app.kubernetes.io/component: %s" $component }} - {{- end }} - {{- range $key, $value := .extraMatchLabels }} - {{ $key }}: {{ $value | quote }} - {{- end }} - topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} - weight: {{ .weight | default 1 -}} - {{- end -}} -{{- end -}} - -{{/* -Return a hard podAffinity/podAntiAffinity definition -{{ include "common.affinities.pods.hard" (dict "component" "FOO" "customLabels" .Values.podLabels "extraMatchLabels" .Values.extraMatchLabels "topologyKey" "BAR" "extraPodAffinityTerms" .Values.extraPodAffinityTerms "context" $) -}} -*/}} -{{- define "common.affinities.pods.hard" -}} -{{- $component := default "" .component -}} -{{- $customLabels := default (dict) .customLabels -}} -{{- $extraMatchLabels := default (dict) .extraMatchLabels -}} -{{- $extraPodAffinityTerms := default (list) .extraPodAffinityTerms -}} -requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" .context )) | nindent 8 }} - {{- if not (empty $component) }} - {{ printf "app.kubernetes.io/component: %s" $component }} - {{- end }} - {{- range $key, $value := $extraMatchLabels }} - {{ $key }}: {{ $value | quote }} - {{- end }} - topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} - {{- range $extraPodAffinityTerms }} - - labelSelector: - matchLabels: {{- (include "common.labels.matchLabels" ( dict "customLabels" $customLabels "context" $.context )) | nindent 8 }} - {{- if not (empty $component) }} - {{ printf "app.kubernetes.io/component: %s" $component }} - {{- end }} - {{- range $key, $value := .extraMatchLabels }} - {{ $key }}: {{ $value | quote }} - {{- end }} - topologyKey: {{ include "common.affinities.topologyKey" (dict "topologyKey" .topologyKey) }} - {{- end -}} -{{- end -}} - -{{/* -Return a podAffinity/podAntiAffinity definition -{{ include "common.affinities.pods" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}} -*/}} -{{- define "common.affinities.pods" -}} - {{- if eq .type "soft" }} - {{- include "common.affinities.pods.soft" . -}} - {{- else if eq .type "hard" }} - {{- include "common.affinities.pods.hard" . -}} - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_capabilities.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_capabilities.tpl deleted file mode 100644 index 2fe81d32..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_capabilities.tpl +++ /dev/null @@ -1,229 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} - -{{/* -Return the target Kubernetes version -*/}} -{{- define "common.capabilities.kubeVersion" -}} -{{- default (default .Capabilities.KubeVersion.Version .Values.kubeVersion) ((.Values.global).kubeVersion) -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for poddisruptionbudget. -*/}} -{{- define "common.capabilities.policy.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.21-0" $kubeVersion) -}} -{{- print "policy/v1beta1" -}} -{{- else -}} -{{- print "policy/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for networkpolicy. -*/}} -{{- define "common.capabilities.networkPolicy.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.7-0" $kubeVersion) -}} -{{- print "extensions/v1beta1" -}} -{{- else -}} -{{- print "networking.k8s.io/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for cronjob. -*/}} -{{- define "common.capabilities.cronjob.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.21-0" $kubeVersion) -}} -{{- print "batch/v1beta1" -}} -{{- else -}} -{{- print "batch/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for daemonset. -*/}} -{{- define "common.capabilities.daemonset.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} -{{- print "extensions/v1beta1" -}} -{{- else -}} -{{- print "apps/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for deployment. -*/}} -{{- define "common.capabilities.deployment.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} -{{- print "extensions/v1beta1" -}} -{{- else -}} -{{- print "apps/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for statefulset. -*/}} -{{- define "common.capabilities.statefulset.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} -{{- print "apps/v1beta1" -}} -{{- else -}} -{{- print "apps/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for ingress. -*/}} -{{- define "common.capabilities.ingress.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if (.Values.ingress).apiVersion -}} -{{- .Values.ingress.apiVersion -}} -{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.14-0" $kubeVersion) -}} -{{- print "extensions/v1beta1" -}} -{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.19-0" $kubeVersion) -}} -{{- print "networking.k8s.io/v1beta1" -}} -{{- else -}} -{{- print "networking.k8s.io/v1" -}} -{{- end }} -{{- end -}} - -{{/* -Return the appropriate apiVersion for RBAC resources. -*/}} -{{- define "common.capabilities.rbac.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.17-0" $kubeVersion) -}} -{{- print "rbac.authorization.k8s.io/v1beta1" -}} -{{- else -}} -{{- print "rbac.authorization.k8s.io/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for CRDs. -*/}} -{{- define "common.capabilities.crd.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.19-0" $kubeVersion) -}} -{{- print "apiextensions.k8s.io/v1beta1" -}} -{{- else -}} -{{- print "apiextensions.k8s.io/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for APIService. -*/}} -{{- define "common.capabilities.apiService.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.10-0" $kubeVersion) -}} -{{- print "apiregistration.k8s.io/v1beta1" -}} -{{- else -}} -{{- print "apiregistration.k8s.io/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for Horizontal Pod Autoscaler. -*/}} -{{- define "common.capabilities.hpa.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" .context -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} -{{- if .beta2 -}} -{{- print "autoscaling/v2beta2" -}} -{{- else -}} -{{- print "autoscaling/v2beta1" -}} -{{- end -}} -{{- else -}} -{{- print "autoscaling/v2" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for Vertical Pod Autoscaler. -*/}} -{{- define "common.capabilities.vpa.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" .context -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} -{{- if .beta2 -}} -{{- print "autoscaling/v2beta2" -}} -{{- else -}} -{{- print "autoscaling/v2beta1" -}} -{{- end -}} -{{- else -}} -{{- print "autoscaling/v2" -}} -{{- end -}} -{{- end -}} - -{{/* -Returns true if PodSecurityPolicy is supported -*/}} -{{- define "common.capabilities.psp.supported" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if or (empty $kubeVersion) (semverCompare "<1.25-0" $kubeVersion) -}} - {{- true -}} -{{- end -}} -{{- end -}} - -{{/* -Returns true if AdmissionConfiguration is supported -*/}} -{{- define "common.capabilities.admissionConfiguration.supported" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if or (empty $kubeVersion) (not (semverCompare "<1.23-0" $kubeVersion)) -}} - {{- true -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for AdmissionConfiguration. -*/}} -{{- define "common.capabilities.admissionConfiguration.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} -{{- print "apiserver.config.k8s.io/v1alpha1" -}} -{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.25-0" $kubeVersion) -}} -{{- print "apiserver.config.k8s.io/v1beta1" -}} -{{- else -}} -{{- print "apiserver.config.k8s.io/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for PodSecurityConfiguration. -*/}} -{{- define "common.capabilities.podSecurityConfiguration.apiVersion" -}} -{{- $kubeVersion := include "common.capabilities.kubeVersion" . -}} -{{- if and (not (empty $kubeVersion)) (semverCompare "<1.23-0" $kubeVersion) -}} -{{- print "pod-security.admission.config.k8s.io/v1alpha1" -}} -{{- else if and (not (empty $kubeVersion)) (semverCompare "<1.25-0" $kubeVersion) -}} -{{- print "pod-security.admission.config.k8s.io/v1beta1" -}} -{{- else -}} -{{- print "pod-security.admission.config.k8s.io/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Returns true if the used Helm version is 3.3+. -A way to check the used Helm version was not introduced until version 3.3.0 with .Capabilities.HelmVersion, which contains an additional "{}}" structure. -This check is introduced as a regexMatch instead of {{ if .Capabilities.HelmVersion }} because checking for the key HelmVersion in <3.3 results in a "interface not found" error. -**To be removed when the catalog's minimun Helm version is 3.3** -*/}} -{{- define "common.capabilities.supportsHelmVersion" -}} -{{- if regexMatch "{(v[0-9])*[^}]*}}$" (.Capabilities | toString ) }} - {{- true -}} -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_compatibility.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_compatibility.tpl deleted file mode 100644 index a61588d6..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_compatibility.tpl +++ /dev/null @@ -1,46 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} - -{{/* -Return true if the detected platform is Openshift -Usage: -{{- include "common.compatibility.isOpenshift" . -}} -*/}} -{{- define "common.compatibility.isOpenshift" -}} -{{- if .Capabilities.APIVersions.Has "security.openshift.io/v1" -}} -{{- true -}} -{{- end -}} -{{- end -}} - -{{/* -Render a compatible securityContext depending on the platform. By default it is maintained as it is. In other platforms like Openshift we remove default user/group values that do not work out of the box with the restricted-v1 SCC -Usage: -{{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.containerSecurityContext "context" $) -}} -*/}} -{{- define "common.compatibility.renderSecurityContext" -}} -{{- $adaptedContext := .secContext -}} - -{{- if (((.context.Values.global).compatibility).openshift) -}} - {{- if or (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "force") (and (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "auto") (include "common.compatibility.isOpenshift" .context)) -}} - {{/* Remove incompatible user/group values that do not work in Openshift out of the box */}} - {{- $adaptedContext = omit $adaptedContext "fsGroup" "runAsUser" "runAsGroup" -}} - {{- if not .secContext.seLinuxOptions -}} - {{/* If it is an empty object, we remove it from the resulting context because it causes validation issues */}} - {{- $adaptedContext = omit $adaptedContext "seLinuxOptions" -}} - {{- end -}} - {{- end -}} -{{- end -}} -{{/* Remove empty seLinuxOptions object if global.compatibility.omitEmptySeLinuxOptions is set to true */}} -{{- if and (((.context.Values.global).compatibility).omitEmptySeLinuxOptions) (not .secContext.seLinuxOptions) -}} - {{- $adaptedContext = omit $adaptedContext "seLinuxOptions" -}} -{{- end -}} -{{/* Remove fields that are disregarded when running the container in privileged mode */}} -{{- if $adaptedContext.privileged -}} - {{- $adaptedContext = omit $adaptedContext "capabilities" "seLinuxOptions" -}} -{{- end -}} -{{- omit $adaptedContext "enabled" | toYaml -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_errors.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_errors.tpl deleted file mode 100644 index e9653651..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_errors.tpl +++ /dev/null @@ -1,28 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Through error when upgrading using empty passwords values that must not be empty. - -Usage: -{{- $validationError00 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password00" "secret" "secretName" "field" "password-00") -}} -{{- $validationError01 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password01" "secret" "secretName" "field" "password-01") -}} -{{ include "common.errors.upgrade.passwords.empty" (dict "validationErrors" (list $validationError00 $validationError01) "context" $) }} - -Required password params: - - validationErrors - String - Required. List of validation strings to be return, if it is empty it won't throw error. - - context - Context - Required. Parent context. -*/}} -{{- define "common.errors.upgrade.passwords.empty" -}} - {{- $validationErrors := join "" .validationErrors -}} - {{- if and $validationErrors .context.Release.IsUpgrade -}} - {{- $errorString := "\nPASSWORDS ERROR: You must provide your current passwords when upgrading the release." -}} - {{- $errorString = print $errorString "\n Note that even after reinstallation, old credentials may be needed as they may be kept in persistent volume claims." -}} - {{- $errorString = print $errorString "\n Further information can be obtained at https://docs.bitnami.com/general/how-to/troubleshoot-helm-chart-issues/#credential-errors-while-upgrading-chart-releases" -}} - {{- $errorString = print $errorString "\n%s" -}} - {{- printf $errorString $validationErrors | fail -}} - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_images.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_images.tpl deleted file mode 100644 index 76bb7ce4..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_images.tpl +++ /dev/null @@ -1,115 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Return the proper image name. -If image tag and digest are not defined, termination fallbacks to chart appVersion. -{{ include "common.images.image" ( dict "imageRoot" .Values.path.to.the.image "global" .Values.global "chart" .Chart ) }} -*/}} -{{- define "common.images.image" -}} -{{- $registryName := default .imageRoot.registry ((.global).imageRegistry) -}} -{{- $repositoryName := .imageRoot.repository -}} -{{- $separator := ":" -}} -{{- $termination := .imageRoot.tag | toString -}} - -{{- if not .imageRoot.tag }} - {{- if .chart }} - {{- $termination = .chart.AppVersion | toString -}} - {{- end -}} -{{- end -}} -{{- if .imageRoot.digest }} - {{- $separator = "@" -}} - {{- $termination = .imageRoot.digest | toString -}} -{{- end -}} -{{- if $registryName }} - {{- printf "%s/%s%s%s" $registryName $repositoryName $separator $termination -}} -{{- else -}} - {{- printf "%s%s%s" $repositoryName $separator $termination -}} -{{- end -}} -{{- end -}} - -{{/* -Return the proper Docker Image Registry Secret Names (deprecated: use common.images.renderPullSecrets instead) -{{ include "common.images.pullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global) }} -*/}} -{{- define "common.images.pullSecrets" -}} - {{- $pullSecrets := list }} - - {{- range ((.global).imagePullSecrets) -}} - {{- if kindIs "map" . -}} - {{- $pullSecrets = append $pullSecrets .name -}} - {{- else -}} - {{- $pullSecrets = append $pullSecrets . -}} - {{- end }} - {{- end -}} - - {{- range .images -}} - {{- range .pullSecrets -}} - {{- if kindIs "map" . -}} - {{- $pullSecrets = append $pullSecrets .name -}} - {{- else -}} - {{- $pullSecrets = append $pullSecrets . -}} - {{- end -}} - {{- end -}} - {{- end -}} - - {{- if (not (empty $pullSecrets)) -}} -imagePullSecrets: - {{- range $pullSecrets | uniq }} - - name: {{ . }} - {{- end }} - {{- end }} -{{- end -}} - -{{/* -Return the proper Docker Image Registry Secret Names evaluating values as templates -{{ include "common.images.renderPullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "context" $) }} -*/}} -{{- define "common.images.renderPullSecrets" -}} - {{- $pullSecrets := list }} - {{- $context := .context }} - - {{- range (($context.Values.global).imagePullSecrets) -}} - {{- if kindIs "map" . -}} - {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" $context)) -}} - {{- else -}} - {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" $context)) -}} - {{- end -}} - {{- end -}} - - {{- range .images -}} - {{- range .pullSecrets -}} - {{- if kindIs "map" . -}} - {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" $context)) -}} - {{- else -}} - {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" $context)) -}} - {{- end -}} - {{- end -}} - {{- end -}} - - {{- if (not (empty $pullSecrets)) -}} -imagePullSecrets: - {{- range $pullSecrets | uniq }} - - name: {{ . }} - {{- end }} - {{- end }} -{{- end -}} - -{{/* -Return the proper image version (ingores image revision/prerelease info & fallbacks to chart appVersion) -{{ include "common.images.version" ( dict "imageRoot" .Values.path.to.the.image "chart" .Chart ) }} -*/}} -{{- define "common.images.version" -}} -{{- $imageTag := .imageRoot.tag | toString -}} -{{/* regexp from https://github.com/Masterminds/semver/blob/23f51de38a0866c5ef0bfc42b3f735c73107b700/version.go#L41-L44 */}} -{{- if regexMatch `^([0-9]+)(\.[0-9]+)?(\.[0-9]+)?(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?$` $imageTag -}} - {{- $version := semver $imageTag -}} - {{- printf "%d.%d.%d" $version.Major $version.Minor $version.Patch -}} -{{- else -}} - {{- print .chart.AppVersion -}} -{{- end -}} -{{- end -}} - diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_ingress.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_ingress.tpl deleted file mode 100644 index 7d2b8798..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_ingress.tpl +++ /dev/null @@ -1,73 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} - -{{/* -Generate backend entry that is compatible with all Kubernetes API versions. - -Usage: -{{ include "common.ingress.backend" (dict "serviceName" "backendName" "servicePort" "backendPort" "context" $) }} - -Params: - - serviceName - String. Name of an existing service backend - - servicePort - String/Int. Port name (or number) of the service. It will be translated to different yaml depending if it is a string or an integer. - - context - Dict - Required. The context for the template evaluation. -*/}} -{{- define "common.ingress.backend" -}} -{{- $apiVersion := (include "common.capabilities.ingress.apiVersion" .context) -}} -{{- if or (eq $apiVersion "extensions/v1beta1") (eq $apiVersion "networking.k8s.io/v1beta1") -}} -serviceName: {{ .serviceName }} -servicePort: {{ .servicePort }} -{{- else -}} -service: - name: {{ .serviceName }} - port: - {{- if typeIs "string" .servicePort }} - name: {{ .servicePort }} - {{- else if or (typeIs "int" .servicePort) (typeIs "float64" .servicePort) }} - number: {{ .servicePort | int }} - {{- end }} -{{- end -}} -{{- end -}} - -{{/* -Print "true" if the API pathType field is supported -Usage: -{{ include "common.ingress.supportsPathType" . }} -*/}} -{{- define "common.ingress.supportsPathType" -}} -{{- if (semverCompare "<1.18-0" (include "common.capabilities.kubeVersion" .)) -}} -{{- print "false" -}} -{{- else -}} -{{- print "true" -}} -{{- end -}} -{{- end -}} - -{{/* -Returns true if the ingressClassname field is supported -Usage: -{{ include "common.ingress.supportsIngressClassname" . }} -*/}} -{{- define "common.ingress.supportsIngressClassname" -}} -{{- if semverCompare "<1.18-0" (include "common.capabilities.kubeVersion" .) -}} -{{- print "false" -}} -{{- else -}} -{{- print "true" -}} -{{- end -}} -{{- end -}} - -{{/* -Return true if cert-manager required annotations for TLS signed -certificates are set in the Ingress annotations -Ref: https://cert-manager.io/docs/usage/ingress/#supported-annotations -Usage: -{{ include "common.ingress.certManagerRequest" ( dict "annotations" .Values.path.to.the.ingress.annotations ) }} -*/}} -{{- define "common.ingress.certManagerRequest" -}} -{{ if or (hasKey .annotations "cert-manager.io/cluster-issuer") (hasKey .annotations "cert-manager.io/issuer") (hasKey .annotations "kubernetes.io/tls-acme") }} - {{- true -}} -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_labels.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_labels.tpl deleted file mode 100644 index 0a0cc548..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_labels.tpl +++ /dev/null @@ -1,46 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} - -{{/* -Kubernetes standard labels -{{ include "common.labels.standard" (dict "customLabels" .Values.commonLabels "context" $) -}} -*/}} -{{- define "common.labels.standard" -}} -{{- if and (hasKey . "customLabels") (hasKey . "context") -}} -{{- $default := dict "app.kubernetes.io/name" (include "common.names.name" .context) "helm.sh/chart" (include "common.names.chart" .context) "app.kubernetes.io/instance" .context.Release.Name "app.kubernetes.io/managed-by" .context.Release.Service -}} -{{- with .context.Chart.AppVersion -}} -{{- $_ := set $default "app.kubernetes.io/version" . -}} -{{- end -}} -{{ template "common.tplvalues.merge" (dict "values" (list .customLabels $default) "context" .context) }} -{{- else -}} -app.kubernetes.io/name: {{ include "common.names.name" . }} -helm.sh/chart: {{ include "common.names.chart" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- with .Chart.AppVersion }} -app.kubernetes.io/version: {{ . | quote }} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Labels used on immutable fields such as deploy.spec.selector.matchLabels or svc.spec.selector -{{ include "common.labels.matchLabels" (dict "customLabels" .Values.podLabels "context" $) -}} - -We don't want to loop over custom labels appending them to the selector -since it's very likely that it will break deployments, services, etc. -However, it's important to overwrite the standard labels if the user -overwrote them on metadata.labels fields. -*/}} -{{- define "common.labels.matchLabels" -}} -{{- if and (hasKey . "customLabels") (hasKey . "context") -}} -{{ merge (pick (include "common.tplvalues.render" (dict "value" .customLabels "context" .context) | fromYaml) "app.kubernetes.io/name" "app.kubernetes.io/instance") (dict "app.kubernetes.io/name" (include "common.names.name" .context) "app.kubernetes.io/instance" .context.Release.Name ) | toYaml }} -{{- else -}} -app.kubernetes.io/name: {{ include "common.names.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_names.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_names.tpl deleted file mode 100644 index ba839568..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_names.tpl +++ /dev/null @@ -1,71 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "common.names.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "common.names.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "common.names.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create a default fully qualified dependency name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -Usage: -{{ include "common.names.dependency.fullname" (dict "chartName" "dependency-chart-name" "chartValues" .Values.dependency-chart "context" $) }} -*/}} -{{- define "common.names.dependency.fullname" -}} -{{- if .chartValues.fullnameOverride -}} -{{- .chartValues.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .chartName .chartValues.nameOverride -}} -{{- if contains $name .context.Release.Name -}} -{{- .context.Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .context.Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Allow the release namespace to be overridden for multi-namespace deployments in combined charts. -*/}} -{{- define "common.names.namespace" -}} -{{- default .Release.Namespace .Values.namespaceOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create a fully qualified app name adding the installation's namespace. -*/}} -{{- define "common.names.fullname.namespace" -}} -{{- printf "%s-%s" (include "common.names.fullname" .) (include "common.names.namespace" .) | trunc 63 | trimSuffix "-" -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_resources.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_resources.tpl deleted file mode 100644 index d8a43e1c..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_resources.tpl +++ /dev/null @@ -1,50 +0,0 @@ -{{/* -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 "common.resources.preset" (dict "type" "nano") -}} -*/}} -{{- define "common.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") - ) - "micro" (dict - "requests" (dict "cpu" "250m" "memory" "256Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "375m" "memory" "384Mi" "ephemeral-storage" "2Gi") - ) - "small" (dict - "requests" (dict "cpu" "500m" "memory" "512Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "768Mi" "ephemeral-storage" "2Gi") - ) - "medium" (dict - "requests" (dict "cpu" "500m" "memory" "1024Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "750m" "memory" "1536Mi" "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") - ) - "xlarge" (dict - "requests" (dict "cpu" "1.0" "memory" "3072Mi" "ephemeral-storage" "50Mi") - "limits" (dict "cpu" "3.0" "memory" "6144Mi" "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") - ) - }} -{{- if hasKey $presets .type -}} -{{- index $presets .type | toYaml -}} -{{- else -}} -{{- printf "ERROR: Preset key '%s' invalid. Allowed values are %s" .type (join "," (keys $presets)) | fail -}} -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_secrets.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_secrets.tpl deleted file mode 100644 index 801918ce..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_secrets.tpl +++ /dev/null @@ -1,185 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Generate secret name. - -Usage: -{{ include "common.secrets.name" (dict "existingSecret" .Values.path.to.the.existingSecret "defaultNameSuffix" "mySuffix" "context" $) }} - -Params: - - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user - to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. - +info: https://github.com/bitnami/charts/tree/main/bitnami/common#existingsecret - - defaultNameSuffix - String - Optional. It is used only if we have several secrets in the same deployment. - - context - Dict - Required. The context for the template evaluation. -*/}} -{{- define "common.secrets.name" -}} -{{- $name := (include "common.names.fullname" .context) -}} - -{{- if .defaultNameSuffix -}} -{{- $name = printf "%s-%s" $name .defaultNameSuffix | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{- with .existingSecret -}} -{{- if not (typeIs "string" .) -}} -{{- with .name -}} -{{- $name = . -}} -{{- end -}} -{{- else -}} -{{- $name = . -}} -{{- end -}} -{{- end -}} - -{{- printf "%s" $name -}} -{{- end -}} - -{{/* -Generate secret key. - -Usage: -{{ include "common.secrets.key" (dict "existingSecret" .Values.path.to.the.existingSecret "key" "keyName") }} - -Params: - - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user - to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility. - +info: https://github.com/bitnami/charts/tree/main/bitnami/common#existingsecret - - key - String - Required. Name of the key in the secret. -*/}} -{{- define "common.secrets.key" -}} -{{- $key := .key -}} - -{{- if .existingSecret -}} - {{- if not (typeIs "string" .existingSecret) -}} - {{- if .existingSecret.keyMapping -}} - {{- $key = index .existingSecret.keyMapping $.key -}} - {{- end -}} - {{- end }} -{{- end -}} - -{{- printf "%s" $key -}} -{{- end -}} - -{{/* -Generate secret password or retrieve one if already created. - -Usage: -{{ include "common.secrets.passwords.manage" (dict "secret" "secret-name" "key" "keyName" "providedValues" (list "path.to.password1" "path.to.password2") "length" 10 "strong" false "chartName" "chartName" "context" $) }} - -Params: - - secret - String - Required - Name of the 'Secret' resource where the password is stored. - - key - String - Required - Name of the key in the secret. - - providedValues - List - Required - The path to the validating value in the values.yaml, e.g: "mysql.password". Will pick first parameter with a defined value. - - length - int - Optional - Length of the generated random password. - - strong - Boolean - Optional - Whether to add symbols to the generated random password. - - chartName - String - Optional - Name of the chart used when said chart is deployed as a subchart. - - context - Context - Required - Parent context. - - failOnNew - Boolean - Optional - Default to true. If set to false, skip errors adding new keys to existing secrets. - - skipB64enc - Boolean - Optional - Default to false. If set to true, no the secret will not be base64 encrypted. - - skipQuote - Boolean - Optional - Default to false. If set to true, no quotes will be added around the secret. -The order in which this function returns a secret password: - 1. Already existing 'Secret' resource - (If a 'Secret' resource is found under the name provided to the 'secret' parameter to this function and that 'Secret' resource contains a key with the name passed as the 'key' parameter to this function then the value of this existing secret password will be returned) - 2. Password provided via the values.yaml - (If one of the keys passed to the 'providedValues' parameter to this function is a valid path to a key in the values.yaml and has a value, the value of the first key with a value will be returned) - 3. Randomly generated secret password - (A new random secret password with the length specified in the 'length' parameter will be generated and returned) - -*/}} -{{- define "common.secrets.passwords.manage" -}} - -{{- $password := "" }} -{{- $subchart := "" }} -{{- $chartName := default "" .chartName }} -{{- $passwordLength := default 10 .length }} -{{- $providedPasswordKey := include "common.utils.getKeyFromList" (dict "keys" .providedValues "context" $.context) }} -{{- $providedPasswordValue := include "common.utils.getValueFromKey" (dict "key" $providedPasswordKey "context" $.context) }} -{{- $secretData := (lookup "v1" "Secret" (include "common.names.namespace" .context) .secret).data }} -{{- if $secretData }} - {{- if hasKey $secretData .key }} - {{- $password = index $secretData .key | b64dec }} - {{- else if not (eq .failOnNew false) }} - {{- printf "\nPASSWORDS ERROR: The secret \"%s\" does not contain the key \"%s\"\n" .secret .key | fail -}} - {{- end -}} -{{- end }} - -{{- if not $password }} - {{- if $providedPasswordValue }} - {{- $password = $providedPasswordValue | toString }} - {{- else }} - {{- if .context.Values.enabled }} - {{- $subchart = $chartName }} - {{- end -}} - - {{- if not (eq .failOnNew false) }} - {{- $requiredPassword := dict "valueKey" $providedPasswordKey "secret" .secret "field" .key "subchart" $subchart "context" $.context -}} - {{- $requiredPasswordError := include "common.validations.values.single.empty" $requiredPassword -}} - {{- $passwordValidationErrors := list $requiredPasswordError -}} - {{- include "common.errors.upgrade.passwords.empty" (dict "validationErrors" $passwordValidationErrors "context" $.context) -}} - {{- end }} - - {{- if .strong }} - {{- $subStr := list (lower (randAlpha 1)) (randNumeric 1) (upper (randAlpha 1)) | join "_" }} - {{- $password = randAscii $passwordLength }} - {{- $password = regexReplaceAllLiteral "\\W" $password "@" | substr 5 $passwordLength }} - {{- $password = printf "%s%s" $subStr $password | toString | shuffle }} - {{- else }} - {{- $password = randAlphaNum $passwordLength }} - {{- end }} - {{- end -}} -{{- end -}} -{{- if not .skipB64enc }} -{{- $password = $password | b64enc }} -{{- end -}} -{{- if .skipQuote -}} -{{- printf "%s" $password -}} -{{- else -}} -{{- printf "%s" $password | quote -}} -{{- end -}} -{{- end -}} - -{{/* -Reuses the value from an existing secret, otherwise sets its value to a default value. - -Usage: -{{ include "common.secrets.lookup" (dict "secret" "secret-name" "key" "keyName" "defaultValue" .Values.myValue "context" $) }} - -Params: - - secret - String - Required - Name of the 'Secret' resource where the password is stored. - - key - String - Required - Name of the key in the secret. - - defaultValue - String - Required - The path to the validating value in the values.yaml, e.g: "mysql.password". Will pick first parameter with a defined value. - - context - Context - Required - Parent context. - -*/}} -{{- define "common.secrets.lookup" -}} -{{- $value := "" -}} -{{- $secretData := (lookup "v1" "Secret" (include "common.names.namespace" .context) .secret).data -}} -{{- if and $secretData (hasKey $secretData .key) -}} - {{- $value = index $secretData .key -}} -{{- else if .defaultValue -}} - {{- $value = .defaultValue | toString | b64enc -}} -{{- end -}} -{{- if $value -}} -{{- printf "%s" $value -}} -{{- end -}} -{{- end -}} - -{{/* -Returns whether a previous generated secret already exists - -Usage: -{{ include "common.secrets.exists" (dict "secret" "secret-name" "context" $) }} - -Params: - - secret - String - Required - Name of the 'Secret' resource where the password is stored. - - context - Context - Required - Parent context. -*/}} -{{- define "common.secrets.exists" -}} -{{- $secret := (lookup "v1" "Secret" (include "common.names.namespace" .context) .secret) }} -{{- if $secret }} - {{- true -}} -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_storage.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_storage.tpl deleted file mode 100644 index aa75856c..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_storage.tpl +++ /dev/null @@ -1,21 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} - -{{/* -Return the proper Storage Class -{{ include "common.storage.class" ( dict "persistence" .Values.path.to.the.persistence "global" $) }} -*/}} -{{- define "common.storage.class" -}} -{{- $storageClass := (.global).storageClass | default .persistence.storageClass | default (.global).defaultStorageClass | default "" -}} -{{- if $storageClass -}} - {{- if (eq "-" $storageClass) -}} - {{- printf "storageClassName: \"\"" -}} - {{- else -}} - {{- printf "storageClassName: %s" $storageClass -}} - {{- end -}} -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_tplvalues.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_tplvalues.tpl deleted file mode 100644 index c84d72c8..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_tplvalues.tpl +++ /dev/null @@ -1,38 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Renders a value that contains template perhaps with scope if the scope is present. -Usage: -{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $ ) }} -{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $ "scope" $app ) }} -*/}} -{{- define "common.tplvalues.render" -}} -{{- $value := typeIs "string" .value | ternary .value (.value | toYaml) }} -{{- if contains "{{" (toJson .value) }} - {{- if .scope }} - {{- tpl (cat "{{- with $.RelativeScope -}}" $value "{{- end }}") (merge (dict "RelativeScope" .scope) .context) }} - {{- else }} - {{- tpl $value .context }} - {{- end }} -{{- else }} - {{- $value }} -{{- end }} -{{- end -}} - -{{/* -Merge a list of values that contains template after rendering them. -Merge precedence is consistent with http://masterminds.github.io/sprig/dicts.html#merge-mustmerge -Usage: -{{ include "common.tplvalues.merge" ( dict "values" (list .Values.path.to.the.Value1 .Values.path.to.the.Value2) "context" $ ) }} -*/}} -{{- define "common.tplvalues.merge" -}} -{{- $dst := dict -}} -{{- range .values -}} -{{- $dst = include "common.tplvalues.render" (dict "value" . "context" $.context "scope" $.scope) | fromYaml | merge $dst -}} -{{- end -}} -{{ $dst | toYaml }} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_utils.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_utils.tpl deleted file mode 100644 index d53c74aa..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_utils.tpl +++ /dev/null @@ -1,77 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Print instructions to get a secret value. -Usage: -{{ include "common.utils.secret.getvalue" (dict "secret" "secret-name" "field" "secret-value-field" "context" $) }} -*/}} -{{- define "common.utils.secret.getvalue" -}} -{{- $varname := include "common.utils.fieldToEnvVar" . -}} -export {{ $varname }}=$(kubectl get secret --namespace {{ include "common.names.namespace" .context | quote }} {{ .secret }} -o jsonpath="{.data.{{ .field }}}" | base64 -d) -{{- end -}} - -{{/* -Build env var name given a field -Usage: -{{ include "common.utils.fieldToEnvVar" dict "field" "my-password" }} -*/}} -{{- define "common.utils.fieldToEnvVar" -}} - {{- $fieldNameSplit := splitList "-" .field -}} - {{- $upperCaseFieldNameSplit := list -}} - - {{- range $fieldNameSplit -}} - {{- $upperCaseFieldNameSplit = append $upperCaseFieldNameSplit ( upper . ) -}} - {{- end -}} - - {{ join "_" $upperCaseFieldNameSplit }} -{{- end -}} - -{{/* -Gets a value from .Values given -Usage: -{{ include "common.utils.getValueFromKey" (dict "key" "path.to.key" "context" $) }} -*/}} -{{- define "common.utils.getValueFromKey" -}} -{{- $splitKey := splitList "." .key -}} -{{- $value := "" -}} -{{- $latestObj := $.context.Values -}} -{{- range $splitKey -}} - {{- if not $latestObj -}} - {{- printf "please review the entire path of '%s' exists in values" $.key | fail -}} - {{- end -}} - {{- $value = ( index $latestObj . ) -}} - {{- $latestObj = $value -}} -{{- end -}} -{{- printf "%v" (default "" $value) -}} -{{- end -}} - -{{/* -Returns first .Values key with a defined value or first of the list if all non-defined -Usage: -{{ include "common.utils.getKeyFromList" (dict "keys" (list "path.to.key1" "path.to.key2") "context" $) }} -*/}} -{{- define "common.utils.getKeyFromList" -}} -{{- $key := first .keys -}} -{{- $reverseKeys := reverse .keys }} -{{- range $reverseKeys }} - {{- $value := include "common.utils.getValueFromKey" (dict "key" . "context" $.context ) }} - {{- if $value -}} - {{- $key = . }} - {{- end -}} -{{- end -}} -{{- printf "%s" $key -}} -{{- end -}} - -{{/* -Checksum a template at "path" containing a *single* resource (ConfigMap,Secret) for use in pod annotations, excluding the metadata (see #18376). -Usage: -{{ include "common.utils.checksumTemplate" (dict "path" "/configmap.yaml" "context" $) }} -*/}} -{{- define "common.utils.checksumTemplate" -}} -{{- $obj := include (print .context.Template.BasePath .path) .context | fromYaml -}} -{{ omit $obj "apiVersion" "kind" "metadata" | toYaml | sha256sum }} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_warnings.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_warnings.tpl deleted file mode 100644 index e4dbecde..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/_warnings.tpl +++ /dev/null @@ -1,109 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Warning about using rolling tag. -Usage: -{{ include "common.warnings.rollingTag" .Values.path.to.the.imageRoot }} -*/}} -{{- define "common.warnings.rollingTag" -}} - -{{- if and (contains "bitnami/" .repository) (not (.tag | toString | regexFind "-r\\d+$|sha256:")) }} -WARNING: Rolling tag detected ({{ .repository }}:{{ .tag }}), please note that it is strongly recommended to avoid using rolling tags in a production environment. -+info https://docs.vmware.com/en/VMware-Tanzu-Application-Catalog/services/tutorials/GUID-understand-rolling-tags-containers-index.html -{{- end }} -{{- end -}} - -{{/* -Warning about replaced images from the original. -Usage: -{{ include "common.warnings.modifiedImages" (dict "images" (list .Values.path.to.the.imageRoot) "context" $) }} -*/}} -{{- define "common.warnings.modifiedImages" -}} -{{- $affectedImages := list -}} -{{- $printMessage := false -}} -{{- $originalImages := .context.Chart.Annotations.images -}} -{{- range .images -}} - {{- $fullImageName := printf (printf "%s/%s:%s" .registry .repository .tag) -}} - {{- if not (contains $fullImageName $originalImages) }} - {{- $affectedImages = append $affectedImages (printf "%s/%s:%s" .registry .repository .tag) -}} - {{- $printMessage = true -}} - {{- end -}} -{{- end -}} -{{- if $printMessage }} - -⚠ SECURITY WARNING: Original containers have been substituted. This Helm chart was designed, tested, and validated on multiple platforms using a specific set of Bitnami and Tanzu Application Catalog containers. Substituting other containers is likely to cause degraded security and performance, broken chart features, and missing environment variables. - -Substituted images detected: -{{- range $affectedImages }} - - {{ . }} -{{- end }} -{{- end -}} -{{- end -}} - -{{/* -Warning about not setting the resource object in all deployments. -Usage: -{{ include "common.warnings.resources" (dict "sections" (list "path1" "path2") context $) }} -Example: -{{- include "common.warnings.resources" (dict "sections" (list "csiProvider.provider" "server" "volumePermissions" "") "context" $) }} -The list in the example assumes that the following values exist: - - csiProvider.provider.resources - - server.resources - - volumePermissions.resources - - resources -*/}} -{{- define "common.warnings.resources" -}} -{{- $values := .context.Values -}} -{{- $printMessage := false -}} -{{ $affectedSections := list -}} -{{- range .sections -}} - {{- if eq . "" -}} - {{/* Case where the resources section is at the root (one main deployment in the chart) */}} - {{- if not (index $values "resources") -}} - {{- $affectedSections = append $affectedSections "resources" -}} - {{- $printMessage = true -}} - {{- end -}} - {{- else -}} - {{/* Case where the are multiple resources sections (more than one main deployment in the chart) */}} - {{- $keys := split "." . -}} - {{/* We iterate through the different levels until arriving to the resource section. Example: a.b.c.resources */}} - {{- $section := $values -}} - {{- range $keys -}} - {{- $section = index $section . -}} - {{- end -}} - {{- if not (index $section "resources") -}} - {{/* If the section has enabled=false or replicaCount=0, do not include it */}} - {{- if and (hasKey $section "enabled") -}} - {{- if index $section "enabled" -}} - {{/* enabled=true */}} - {{- $affectedSections = append $affectedSections (printf "%s.resources" .) -}} - {{- $printMessage = true -}} - {{- end -}} - {{- else if and (hasKey $section "replicaCount") -}} - {{/* We need a casting to int because number 0 is not treated as an int by default */}} - {{- if (gt (index $section "replicaCount" | int) 0) -}} - {{/* replicaCount > 0 */}} - {{- $affectedSections = append $affectedSections (printf "%s.resources" .) -}} - {{- $printMessage = true -}} - {{- end -}} - {{- else -}} - {{/* Default case, add it to the affected sections */}} - {{- $affectedSections = append $affectedSections (printf "%s.resources" .) -}} - {{- $printMessage = true -}} - {{- end -}} - {{- end -}} - {{- end -}} -{{- end -}} -{{- if $printMessage }} - -WARNING: There are "resources" sections in the chart not set. Using "resourcesPreset" is not recommended for production. For production installations, please set the following values according to your workload needs: -{{- range $affectedSections }} - - {{ . }} -{{- end }} -+info https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_cassandra.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_cassandra.tpl deleted file mode 100644 index 3f41ff8f..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_cassandra.tpl +++ /dev/null @@ -1,77 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Validate Cassandra required passwords are not empty. - -Usage: -{{ include "common.validations.values.cassandra.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} -Params: - - secret - String - Required. Name of the secret where Cassandra values are stored, e.g: "cassandra-passwords-secret" - - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false -*/}} -{{- define "common.validations.values.cassandra.passwords" -}} - {{- $existingSecret := include "common.cassandra.values.existingSecret" . -}} - {{- $enabled := include "common.cassandra.values.enabled" . -}} - {{- $dbUserPrefix := include "common.cassandra.values.key.dbUser" . -}} - {{- $valueKeyPassword := printf "%s.password" $dbUserPrefix -}} - - {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} - {{- $requiredPasswords := list -}} - - {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "cassandra-password" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} - - {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} - - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for existingSecret. - -Usage: -{{ include "common.cassandra.values.existingSecret" (dict "context" $) }} -Params: - - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false -*/}} -{{- define "common.cassandra.values.existingSecret" -}} - {{- if .subchart -}} - {{- .context.Values.cassandra.dbUser.existingSecret | quote -}} - {{- else -}} - {{- .context.Values.dbUser.existingSecret | quote -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for enabled cassandra. - -Usage: -{{ include "common.cassandra.values.enabled" (dict "context" $) }} -*/}} -{{- define "common.cassandra.values.enabled" -}} - {{- if .subchart -}} - {{- printf "%v" .context.Values.cassandra.enabled -}} - {{- else -}} - {{- printf "%v" (not .context.Values.enabled) -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for the key dbUser - -Usage: -{{ include "common.cassandra.values.key.dbUser" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether Cassandra is used as subchart or not. Default: false -*/}} -{{- define "common.cassandra.values.key.dbUser" -}} - {{- if .subchart -}} - cassandra.dbUser - {{- else -}} - dbUser - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_mariadb.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_mariadb.tpl deleted file mode 100644 index 6ea8c0f4..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_mariadb.tpl +++ /dev/null @@ -1,108 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Validate MariaDB required passwords are not empty. - -Usage: -{{ include "common.validations.values.mariadb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} -Params: - - secret - String - Required. Name of the secret where MariaDB values are stored, e.g: "mysql-passwords-secret" - - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false -*/}} -{{- define "common.validations.values.mariadb.passwords" -}} - {{- $existingSecret := include "common.mariadb.values.auth.existingSecret" . -}} - {{- $enabled := include "common.mariadb.values.enabled" . -}} - {{- $architecture := include "common.mariadb.values.architecture" . -}} - {{- $authPrefix := include "common.mariadb.values.key.auth" . -}} - {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} - {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} - {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} - {{- $valueKeyReplicationPassword := printf "%s.replicationPassword" $authPrefix -}} - - {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} - {{- $requiredPasswords := list -}} - - {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mariadb-root-password" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} - - {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} - {{- if not (empty $valueUsername) -}} - {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mariadb-password" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} - {{- end -}} - - {{- if (eq $architecture "replication") -}} - {{- $requiredReplicationPassword := dict "valueKey" $valueKeyReplicationPassword "secret" .secret "field" "mariadb-replication-password" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredReplicationPassword -}} - {{- end -}} - - {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} - - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for existingSecret. - -Usage: -{{ include "common.mariadb.values.auth.existingSecret" (dict "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false -*/}} -{{- define "common.mariadb.values.auth.existingSecret" -}} - {{- if .subchart -}} - {{- .context.Values.mariadb.auth.existingSecret | quote -}} - {{- else -}} - {{- .context.Values.auth.existingSecret | quote -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for enabled mariadb. - -Usage: -{{ include "common.mariadb.values.enabled" (dict "context" $) }} -*/}} -{{- define "common.mariadb.values.enabled" -}} - {{- if .subchart -}} - {{- printf "%v" .context.Values.mariadb.enabled -}} - {{- else -}} - {{- printf "%v" (not .context.Values.enabled) -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for architecture - -Usage: -{{ include "common.mariadb.values.architecture" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false -*/}} -{{- define "common.mariadb.values.architecture" -}} - {{- if .subchart -}} - {{- .context.Values.mariadb.architecture -}} - {{- else -}} - {{- .context.Values.architecture -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for the key auth - -Usage: -{{ include "common.mariadb.values.key.auth" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false -*/}} -{{- define "common.mariadb.values.key.auth" -}} - {{- if .subchart -}} - mariadb.auth - {{- else -}} - auth - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_mongodb.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_mongodb.tpl deleted file mode 100644 index d4cd38cb..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_mongodb.tpl +++ /dev/null @@ -1,113 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Validate MongoDB® required passwords are not empty. - -Usage: -{{ include "common.validations.values.mongodb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} -Params: - - secret - String - Required. Name of the secret where MongoDB® values are stored, e.g: "mongodb-passwords-secret" - - subchart - Boolean - Optional. Whether MongoDB® is used as subchart or not. Default: false -*/}} -{{- define "common.validations.values.mongodb.passwords" -}} - {{- $existingSecret := include "common.mongodb.values.auth.existingSecret" . -}} - {{- $enabled := include "common.mongodb.values.enabled" . -}} - {{- $authPrefix := include "common.mongodb.values.key.auth" . -}} - {{- $architecture := include "common.mongodb.values.architecture" . -}} - {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} - {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} - {{- $valueKeyDatabase := printf "%s.database" $authPrefix -}} - {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} - {{- $valueKeyReplicaSetKey := printf "%s.replicaSetKey" $authPrefix -}} - {{- $valueKeyAuthEnabled := printf "%s.enabled" $authPrefix -}} - - {{- $authEnabled := include "common.utils.getValueFromKey" (dict "key" $valueKeyAuthEnabled "context" .context) -}} - - {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") (eq $authEnabled "true") -}} - {{- $requiredPasswords := list -}} - - {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mongodb-root-password" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} - - {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} - {{- $valueDatabase := include "common.utils.getValueFromKey" (dict "key" $valueKeyDatabase "context" .context) }} - {{- if and $valueUsername $valueDatabase -}} - {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mongodb-password" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} - {{- end -}} - - {{- if (eq $architecture "replicaset") -}} - {{- $requiredReplicaSetKey := dict "valueKey" $valueKeyReplicaSetKey "secret" .secret "field" "mongodb-replica-set-key" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredReplicaSetKey -}} - {{- end -}} - - {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} - - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for existingSecret. - -Usage: -{{ include "common.mongodb.values.auth.existingSecret" (dict "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MongoDb is used as subchart or not. Default: false -*/}} -{{- define "common.mongodb.values.auth.existingSecret" -}} - {{- if .subchart -}} - {{- .context.Values.mongodb.auth.existingSecret | quote -}} - {{- else -}} - {{- .context.Values.auth.existingSecret | quote -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for enabled mongodb. - -Usage: -{{ include "common.mongodb.values.enabled" (dict "context" $) }} -*/}} -{{- define "common.mongodb.values.enabled" -}} - {{- if .subchart -}} - {{- printf "%v" .context.Values.mongodb.enabled -}} - {{- else -}} - {{- printf "%v" (not .context.Values.enabled) -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for the key auth - -Usage: -{{ include "common.mongodb.values.key.auth" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MongoDB® is used as subchart or not. Default: false -*/}} -{{- define "common.mongodb.values.key.auth" -}} - {{- if .subchart -}} - mongodb.auth - {{- else -}} - auth - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for architecture - -Usage: -{{ include "common.mongodb.values.architecture" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MongoDB® is used as subchart or not. Default: false -*/}} -{{- define "common.mongodb.values.architecture" -}} - {{- if .subchart -}} - {{- .context.Values.mongodb.architecture -}} - {{- else -}} - {{- .context.Values.architecture -}} - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_mysql.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_mysql.tpl deleted file mode 100644 index 924812a9..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_mysql.tpl +++ /dev/null @@ -1,108 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Validate MySQL required passwords are not empty. - -Usage: -{{ include "common.validations.values.mysql.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} -Params: - - secret - String - Required. Name of the secret where MySQL values are stored, e.g: "mysql-passwords-secret" - - subchart - Boolean - Optional. Whether MySQL is used as subchart or not. Default: false -*/}} -{{- define "common.validations.values.mysql.passwords" -}} - {{- $existingSecret := include "common.mysql.values.auth.existingSecret" . -}} - {{- $enabled := include "common.mysql.values.enabled" . -}} - {{- $architecture := include "common.mysql.values.architecture" . -}} - {{- $authPrefix := include "common.mysql.values.key.auth" . -}} - {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}} - {{- $valueKeyUsername := printf "%s.username" $authPrefix -}} - {{- $valueKeyPassword := printf "%s.password" $authPrefix -}} - {{- $valueKeyReplicationPassword := printf "%s.replicationPassword" $authPrefix -}} - - {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} - {{- $requiredPasswords := list -}} - - {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mysql-root-password" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}} - - {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }} - {{- if not (empty $valueUsername) -}} - {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mysql-password" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}} - {{- end -}} - - {{- if (eq $architecture "replication") -}} - {{- $requiredReplicationPassword := dict "valueKey" $valueKeyReplicationPassword "secret" .secret "field" "mysql-replication-password" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredReplicationPassword -}} - {{- end -}} - - {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} - - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for existingSecret. - -Usage: -{{ include "common.mysql.values.auth.existingSecret" (dict "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MySQL is used as subchart or not. Default: false -*/}} -{{- define "common.mysql.values.auth.existingSecret" -}} - {{- if .subchart -}} - {{- .context.Values.mysql.auth.existingSecret | quote -}} - {{- else -}} - {{- .context.Values.auth.existingSecret | quote -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for enabled mysql. - -Usage: -{{ include "common.mysql.values.enabled" (dict "context" $) }} -*/}} -{{- define "common.mysql.values.enabled" -}} - {{- if .subchart -}} - {{- printf "%v" .context.Values.mysql.enabled -}} - {{- else -}} - {{- printf "%v" (not .context.Values.enabled) -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for architecture - -Usage: -{{ include "common.mysql.values.architecture" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MySQL is used as subchart or not. Default: false -*/}} -{{- define "common.mysql.values.architecture" -}} - {{- if .subchart -}} - {{- .context.Values.mysql.architecture -}} - {{- else -}} - {{- .context.Values.architecture -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for the key auth - -Usage: -{{ include "common.mysql.values.key.auth" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether MySQL is used as subchart or not. Default: false -*/}} -{{- define "common.mysql.values.key.auth" -}} - {{- if .subchart -}} - mysql.auth - {{- else -}} - auth - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_postgresql.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_postgresql.tpl deleted file mode 100644 index 0fa0b146..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_postgresql.tpl +++ /dev/null @@ -1,134 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Validate PostgreSQL required passwords are not empty. - -Usage: -{{ include "common.validations.values.postgresql.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} -Params: - - secret - String - Required. Name of the secret where postgresql values are stored, e.g: "postgresql-passwords-secret" - - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false -*/}} -{{- define "common.validations.values.postgresql.passwords" -}} - {{- $existingSecret := include "common.postgresql.values.existingSecret" . -}} - {{- $enabled := include "common.postgresql.values.enabled" . -}} - {{- $valueKeyPostgresqlPassword := include "common.postgresql.values.key.postgressPassword" . -}} - {{- $valueKeyPostgresqlReplicationEnabled := include "common.postgresql.values.key.replicationPassword" . -}} - {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} - {{- $requiredPasswords := list -}} - {{- $requiredPostgresqlPassword := dict "valueKey" $valueKeyPostgresqlPassword "secret" .secret "field" "postgresql-password" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlPassword -}} - - {{- $enabledReplication := include "common.postgresql.values.enabled.replication" . -}} - {{- if (eq $enabledReplication "true") -}} - {{- $requiredPostgresqlReplicationPassword := dict "valueKey" $valueKeyPostgresqlReplicationEnabled "secret" .secret "field" "postgresql-replication-password" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlReplicationPassword -}} - {{- end -}} - - {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to decide whether evaluate global values. - -Usage: -{{ include "common.postgresql.values.use.global" (dict "key" "key-of-global" "context" $) }} -Params: - - key - String - Required. Field to be evaluated within global, e.g: "existingSecret" -*/}} -{{- define "common.postgresql.values.use.global" -}} - {{- if .context.Values.global -}} - {{- if .context.Values.global.postgresql -}} - {{- index .context.Values.global.postgresql .key | quote -}} - {{- end -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for existingSecret. - -Usage: -{{ include "common.postgresql.values.existingSecret" (dict "context" $) }} -*/}} -{{- define "common.postgresql.values.existingSecret" -}} - {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "existingSecret" "context" .context) -}} - - {{- if .subchart -}} - {{- default (.context.Values.postgresql.existingSecret | quote) $globalValue -}} - {{- else -}} - {{- default (.context.Values.existingSecret | quote) $globalValue -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for enabled postgresql. - -Usage: -{{ include "common.postgresql.values.enabled" (dict "context" $) }} -*/}} -{{- define "common.postgresql.values.enabled" -}} - {{- if .subchart -}} - {{- printf "%v" .context.Values.postgresql.enabled -}} - {{- else -}} - {{- printf "%v" (not .context.Values.enabled) -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for the key postgressPassword. - -Usage: -{{ include "common.postgresql.values.key.postgressPassword" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false -*/}} -{{- define "common.postgresql.values.key.postgressPassword" -}} - {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "postgresqlUsername" "context" .context) -}} - - {{- if not $globalValue -}} - {{- if .subchart -}} - postgresql.postgresqlPassword - {{- else -}} - postgresqlPassword - {{- end -}} - {{- else -}} - global.postgresql.postgresqlPassword - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for enabled.replication. - -Usage: -{{ include "common.postgresql.values.enabled.replication" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false -*/}} -{{- define "common.postgresql.values.enabled.replication" -}} - {{- if .subchart -}} - {{- printf "%v" .context.Values.postgresql.replication.enabled -}} - {{- else -}} - {{- printf "%v" .context.Values.replication.enabled -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for the key replication.password. - -Usage: -{{ include "common.postgresql.values.key.replicationPassword" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false -*/}} -{{- define "common.postgresql.values.key.replicationPassword" -}} - {{- if .subchart -}} - postgresql.replication.password - {{- else -}} - replication.password - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_redis.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_redis.tpl deleted file mode 100644 index f4778256..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_redis.tpl +++ /dev/null @@ -1,81 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - - -{{/* vim: set filetype=mustache: */}} -{{/* -Validate Redis® required passwords are not empty. - -Usage: -{{ include "common.validations.values.redis.passwords" (dict "secret" "secretName" "subchart" false "context" $) }} -Params: - - secret - String - Required. Name of the secret where redis values are stored, e.g: "redis-passwords-secret" - - subchart - Boolean - Optional. Whether redis is used as subchart or not. Default: false -*/}} -{{- define "common.validations.values.redis.passwords" -}} - {{- $enabled := include "common.redis.values.enabled" . -}} - {{- $valueKeyPrefix := include "common.redis.values.keys.prefix" . -}} - {{- $standarizedVersion := include "common.redis.values.standarized.version" . }} - - {{- $existingSecret := ternary (printf "%s%s" $valueKeyPrefix "auth.existingSecret") (printf "%s%s" $valueKeyPrefix "existingSecret") (eq $standarizedVersion "true") }} - {{- $existingSecretValue := include "common.utils.getValueFromKey" (dict "key" $existingSecret "context" .context) }} - - {{- $valueKeyRedisPassword := ternary (printf "%s%s" $valueKeyPrefix "auth.password") (printf "%s%s" $valueKeyPrefix "password") (eq $standarizedVersion "true") }} - {{- $valueKeyRedisUseAuth := ternary (printf "%s%s" $valueKeyPrefix "auth.enabled") (printf "%s%s" $valueKeyPrefix "usePassword") (eq $standarizedVersion "true") }} - - {{- if and (or (not $existingSecret) (eq $existingSecret "\"\"")) (eq $enabled "true") -}} - {{- $requiredPasswords := list -}} - - {{- $useAuth := include "common.utils.getValueFromKey" (dict "key" $valueKeyRedisUseAuth "context" .context) -}} - {{- if eq $useAuth "true" -}} - {{- $requiredRedisPassword := dict "valueKey" $valueKeyRedisPassword "secret" .secret "field" "redis-password" -}} - {{- $requiredPasswords = append $requiredPasswords $requiredRedisPassword -}} - {{- end -}} - - {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right value for enabled redis. - -Usage: -{{ include "common.redis.values.enabled" (dict "context" $) }} -*/}} -{{- define "common.redis.values.enabled" -}} - {{- if .subchart -}} - {{- printf "%v" .context.Values.redis.enabled -}} - {{- else -}} - {{- printf "%v" (not .context.Values.enabled) -}} - {{- end -}} -{{- end -}} - -{{/* -Auxiliary function to get the right prefix path for the values - -Usage: -{{ include "common.redis.values.key.prefix" (dict "subchart" "true" "context" $) }} -Params: - - subchart - Boolean - Optional. Whether redis is used as subchart or not. Default: false -*/}} -{{- define "common.redis.values.keys.prefix" -}} - {{- if .subchart -}}redis.{{- else -}}{{- end -}} -{{- end -}} - -{{/* -Checks whether the redis chart's includes the standarizations (version >= 14) - -Usage: -{{ include "common.redis.values.standarized.version" (dict "context" $) }} -*/}} -{{- define "common.redis.values.standarized.version" -}} - - {{- $standarizedAuth := printf "%s%s" (include "common.redis.values.keys.prefix" .) "auth" -}} - {{- $standarizedAuthValues := include "common.utils.getValueFromKey" (dict "key" $standarizedAuth "context" .context) }} - - {{- if $standarizedAuthValues -}} - {{- true -}} - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_validations.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_validations.tpl deleted file mode 100644 index 7cdee617..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/templates/validations/_validations.tpl +++ /dev/null @@ -1,51 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} -{{/* -Validate values must not be empty. - -Usage: -{{- $validateValueConf00 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-00") -}} -{{- $validateValueConf01 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-01") -}} -{{ include "common.validations.values.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }} - -Validate value params: - - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" - - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" - - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" -*/}} -{{- define "common.validations.values.multiple.empty" -}} - {{- range .required -}} - {{- include "common.validations.values.single.empty" (dict "valueKey" .valueKey "secret" .secret "field" .field "context" $.context) -}} - {{- end -}} -{{- end -}} - -{{/* -Validate a value must not be empty. - -Usage: -{{ include "common.validations.value.empty" (dict "valueKey" "mariadb.password" "secret" "secretName" "field" "my-password" "subchart" "subchart" "context" $) }} - -Validate value params: - - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password" - - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret" - - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password" - - subchart - String - Optional - Name of the subchart that the validated password is part of. -*/}} -{{- define "common.validations.values.single.empty" -}} - {{- $value := include "common.utils.getValueFromKey" (dict "key" .valueKey "context" .context) }} - {{- $subchart := ternary "" (printf "%s." .subchart) (empty .subchart) }} - - {{- if not $value -}} - {{- $varname := "my-value" -}} - {{- $getCurrentValue := "" -}} - {{- if and .secret .field -}} - {{- $varname = include "common.utils.fieldToEnvVar" . -}} - {{- $getCurrentValue = printf " To get the current value:\n\n %s\n" (include "common.utils.secret.getvalue" .) -}} - {{- end -}} - {{- printf "\n '%s' must not be empty, please add '--set %s%s=$%s' to the command.%s" .valueKey $subchart .valueKey $varname $getCurrentValue -}} - {{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/values.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/values.yaml deleted file mode 100644 index de2cac57..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/values.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright Broadcom, Inc. All Rights Reserved. -# SPDX-License-Identifier: APACHE-2.0 - -## bitnami/common -## It is required by CI/CD tools and processes. -## @skip exampleValue -## -exampleValue: common-chart diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/NOTES.txt b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/NOTES.txt deleted file mode 100644 index 69bdec3c..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/NOTES.txt +++ /dev/null @@ -1,213 +0,0 @@ -CHART NAME: {{ .Chart.Name }} -CHART VERSION: {{ .Chart.Version }} -APP VERSION: {{ .Chart.AppVersion }} - -** Please be patient while the chart is being deployed ** - -{{- if .Values.diagnosticMode.enabled }} -The chart has been deployed in diagnostic mode. All probes have been disabled and the command has been overwritten with: - - command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 4 }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 4 }} - -Get the list of pods by executing: - - kubectl get pods --namespace {{ include "common.names.namespace" . }} -l app.kubernetes.io/instance={{ .Release.Name }} - -Access the pod you want to debug by executing - - kubectl exec --namespace {{ include "common.names.namespace" . }} -ti -- bash - -In order to replicate the container startup scripts execute this command: - -For Redis: - - /opt/bitnami/scripts/redis/entrypoint.sh /opt/bitnami/scripts/redis/run.sh - -{{- if .Values.sentinel.enabled }} - -For Redis Sentinel: - - /opt/bitnami/scripts/redis-sentinel/entrypoint.sh /opt/bitnami/scripts/redis-sentinel/run.sh - -{{- end }} -{{- else }} - -{{- if contains .Values.master.service.type "LoadBalancer" }} -{{- if not .Values.auth.enabled }} -{{ if and (not .Values.networkPolicy.enabled) (.Values.networkPolicy.allowExternal) }} - -------------------------------------------------------------------------------- - WARNING - - By specifying "master.service.type=LoadBalancer" and "auth.enabled=false" you have - most likely exposed the Redis® service externally without any authentication - mechanism. - - For security reasons, we strongly suggest that you switch to "ClusterIP" or - "NodePort". As alternative, you can also switch to "auth.enabled=true" - providing a valid password on "password" parameter. - -------------------------------------------------------------------------------- -{{- end }} -{{- end }} -{{- end }} - -{{- if and .Values.auth.usePasswordFiles (not .Values.auth.usePasswordFileFromSecret) (or (empty .Values.master.initContainers) (empty .Values.replica.initContainers)) }} - -------------------------------------------------------------------------------- - WARNING - - By specifying ".Values.auth.usePasswordFiles=true" and ".Values.auth.usePasswordFileFromSecret=false" - Redis is expecting that the password is mounted as a file in each pod - (by default in /opt/bitnami/redis/secrets/redis-password) - - Ensure that you specify the respective initContainers in - both .Values.master.initContainers and .Values.replica.initContainers - in order to populate the contents of this file. - -------------------------------------------------------------------------------- -{{- end }} - -{{- if eq .Values.architecture "replication" }} -{{- if .Values.sentinel.enabled }} - -Redis® can be accessed via port {{ .Values.sentinel.service.ports.redis }} on the following DNS name from within your cluster: - - {{ template "common.names.fullname" . }}.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }} for read only operations - -For read/write operations, first access the Redis® Sentinel cluster, which is available in port {{ .Values.sentinel.service.ports.sentinel }} using the same domain name above. - -{{- else }} - -Redis® can be accessed on the following DNS names from within your cluster: - - {{ printf "%s-master.%s.svc.%s" (include "common.names.fullname" .) (include "common.names.namespace" . ) .Values.clusterDomain }} for read/write operations (port {{ .Values.master.service.ports.redis }}) - {{ printf "%s-replicas.%s.svc.%s" (include "common.names.fullname" .) (include "common.names.namespace" . ) .Values.clusterDomain }} for read-only operations (port {{ .Values.replica.service.ports.redis }}) - -{{- end }} -{{- else }} - -Redis® can be accessed via port {{ .Values.master.service.ports.redis }} on the following DNS name from within your cluster: - - {{ template "common.names.fullname" . }}-master.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }} - -{{- end }} - -{{ if .Values.auth.enabled }} - -To get your password run: - - export REDIS_PASSWORD=$(kubectl get secret --namespace {{ include "common.names.namespace" . }} {{ template "redis.secretName" . }} -o jsonpath="{.data.redis-password}" | base64 -d) - -{{- end }} - -To connect to your Redis® server: - -1. Run a Redis® pod that you can use as a client: - - kubectl run --namespace {{ include "common.names.namespace" . }} redis-client --restart='Never' {{ if .Values.auth.enabled }} --env REDIS_PASSWORD=$REDIS_PASSWORD {{ end }} --image {{ template "redis.image" . }} --command -- sleep infinity - -{{- if .Values.tls.enabled }} - - Copy your TLS certificates to the pod: - - kubectl cp --namespace {{ include "common.names.namespace" . }} /path/to/client.cert redis-client:/tmp/client.cert - kubectl cp --namespace {{ include "common.names.namespace" . }} /path/to/client.key redis-client:/tmp/client.key - kubectl cp --namespace {{ include "common.names.namespace" . }} /path/to/CA.cert redis-client:/tmp/CA.cert - -{{- end }} - - Use the following command to attach to the pod: - - kubectl exec --tty -i redis-client \ - {{- if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }}--labels="{{ template "common.names.fullname" . }}-client=true" \{{- end }} - --namespace {{ include "common.names.namespace" . }} -- bash - -2. Connect using the Redis® CLI: - -{{- if eq .Values.architecture "replication" }} - {{- if .Values.sentinel.enabled }} - {{ if .Values.auth.enabled }}REDISCLI_AUTH="$REDIS_PASSWORD" {{ end }}redis-cli -h {{ template "common.names.fullname" . }} -p {{ .Values.sentinel.service.ports.redis }}{{ if .Values.tls.enabled }} --tls --cert /tmp/client.cert --key /tmp/client.key --cacert /tmp/CA.cert{{ end }} # Read only operations - {{ if .Values.auth.enabled }}REDISCLI_AUTH="$REDIS_PASSWORD" {{ end }}redis-cli -h {{ template "common.names.fullname" . }} -p {{ .Values.sentinel.service.ports.sentinel }}{{ if .Values.tls.enabled }} --tls --cert /tmp/client.cert --key /tmp/client.key --cacert /tmp/CA.cert{{ end }} # Sentinel access - {{- else }} - {{ if .Values.auth.enabled }}REDISCLI_AUTH="$REDIS_PASSWORD" {{ end }}redis-cli -h {{ printf "%s-master" (include "common.names.fullname" .) }}{{ if .Values.tls.enabled }} --tls --cert /tmp/client.cert --key /tmp/client.key --cacert /tmp/CA.cert{{ end }} - {{ if .Values.auth.enabled }}REDISCLI_AUTH="$REDIS_PASSWORD" {{ end }}redis-cli -h {{ printf "%s-replicas" (include "common.names.fullname" .) }}{{ if .Values.tls.enabled }} --tls --cert /tmp/client.cert --key /tmp/client.key --cacert /tmp/CA.cert{{ end }} - {{- end }} -{{- else }} - {{ if .Values.auth.enabled }}REDISCLI_AUTH="$REDIS_PASSWORD" {{ end }}redis-cli -h {{ template "common.names.fullname" . }}-master{{ if .Values.tls.enabled }} --tls --cert /tmp/client.cert --key /tmp/client.key --cacert /tmp/CA.cert{{ end }} -{{- end }} - -{{- if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }} - -Note: Since NetworkPolicy is enabled, only pods with label {{ template "common.names.fullname" . }}-client=true" will be able to connect to redis. - -{{- else }} - -To connect to your database from outside the cluster execute the following commands: - -{{- if and (eq .Values.architecture "replication") .Values.sentinel.enabled }} -{{- if contains "NodePort" .Values.sentinel.service.type }} - - export NODE_IP=$(kubectl get nodes --namespace {{ include "common.names.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}") - export NODE_PORT=$(kubectl get --namespace {{ include "common.names.namespace" . }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "common.names.fullname" . }}) - {{ if .Values.auth.enabled }}REDISCLI_AUTH="$REDIS_PASSWORD" {{ end }}redis-cli -h $NODE_IP -p $NODE_PORT {{- if .Values.tls.enabled }} --tls --cert /tmp/client.cert --key /tmp/client.key --cacert /tmp/CA.cert{{ end }} - -{{- else if contains "LoadBalancer" .Values.sentinel.service.type }} - - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - Watch the status with: 'kubectl get svc --namespace {{ include "common.names.namespace" . }} -w {{ template "common.names.fullname" . }}' - - export SERVICE_IP=$(kubectl get svc --namespace {{ include "common.names.namespace" . }} {{ template "common.names.fullname" . }} --template "{{ "{{ range (index .status.loadBalancer.ingress 0) }}{{ . }}{{ end }}" }}") - {{ if .Values.auth.enabled }}REDISCLI_AUTH="$REDIS_PASSWORD" {{ end }}redis-cli -h $SERVICE_IP -p {{ .Values.sentinel.service.ports.redis }} {{- if .Values.tls.enabled }} --tls --cert /tmp/client.cert --key /tmp/client.key --cacert /tmp/CA.cert{{ end }} - -{{- else if contains "ClusterIP" .Values.sentinel.service.type }} - - kubectl port-forward --namespace {{ include "common.names.namespace" . }} svc/{{ template "common.names.fullname" . }} {{ .Values.sentinel.service.ports.redis }}:{{ .Values.sentinel.service.ports.redis }} & - {{ if .Values.auth.enabled }}REDISCLI_AUTH="$REDIS_PASSWORD" {{ end }}redis-cli -h 127.0.0.1 -p {{ .Values.sentinel.service.ports.redis }} {{- if .Values.tls.enabled }} --tls --cert /tmp/client.cert --key /tmp/client.key --cacert /tmp/CA.cert{{ end }} - -{{- end }} -{{- else }} -{{- if contains "NodePort" .Values.master.service.type }} - - export NODE_IP=$(kubectl get nodes --namespace {{ include "common.names.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}") - export NODE_PORT=$(kubectl get --namespace {{ include "common.names.namespace" . }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ printf "%s-master" (include "common.names.fullname" .) }}) - {{ if .Values.auth.enabled }}REDISCLI_AUTH="$REDIS_PASSWORD" {{ end }}redis-cli -h $NODE_IP -p $NODE_PORT {{- if .Values.tls.enabled }} --tls --cert /tmp/client.cert --key /tmp/client.key --cacert /tmp/CA.cert{{ end }} - -{{- else if contains "LoadBalancer" .Values.master.service.type }} - - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - Watch the status with: 'kubectl get svc --namespace {{ include "common.names.namespace" . }} -w {{ template "common.names.fullname" . }}' - - export SERVICE_IP=$(kubectl get svc --namespace {{ include "common.names.namespace" . }} {{ printf "%s-master" (include "common.names.fullname" .) }} --template "{{ "{{ range (index .status.loadBalancer.ingress 0) }}{{ . }}{{ end }}" }}") - {{ if .Values.auth.enabled }}REDISCLI_AUTH="$REDIS_PASSWORD" {{ end }}redis-cli -h $SERVICE_IP -p {{ .Values.master.service.ports.redis }} {{- if .Values.tls.enabled }} --tls --cert /tmp/client.cert --key /tmp/client.key --cacert /tmp/CA.cert{{ end }} - -{{- else if contains "ClusterIP" .Values.master.service.type }} - - kubectl port-forward --namespace {{ include "common.names.namespace" . }} svc/{{ printf "%s-master" (include "common.names.fullname" .) }} {{ .Values.master.service.ports.redis }}:{{ .Values.master.service.ports.redis }} & - {{ if .Values.auth.enabled }}REDISCLI_AUTH="$REDIS_PASSWORD" {{ end }}redis-cli -h 127.0.0.1 -p {{ .Values.master.service.ports.redis }} {{- if .Values.tls.enabled }} --tls --cert /tmp/client.cert --key /tmp/client.key --cacert /tmp/CA.cert{{ end }} - -{{- end }} -{{- end }} - -{{- end }} -{{- end }} -{{- include "redis.checkRollingTags" . }} -{{- include "common.warnings.rollingTag" .Values.volumePermissions.image }} -{{- include "common.warnings.rollingTag" .Values.sysctl.image }} -{{- include "redis.validateValues" . }} - -{{- if and (eq .Values.architecture "replication") .Values.sentinel.enabled (eq .Values.sentinel.service.type "NodePort") (not .Release.IsUpgrade ) }} -{{- if $.Values.sentinel.service.nodePorts.sentinel }} -No need to upgrade, ports and nodeports have been set from values -{{- else }} -#!#!#!#!#!#!#!# IMPORTANT #!#!#!#!#!#!#!# -YOU NEED TO PERFORM AN UPGRADE FOR THE SERVICES AND WORKLOAD TO BE CREATED -{{- end }} -{{- end }} -{{- $resourceSections := list "metrics" "replica" "sentinel" "sysctl" "volumePermissions" }} -{{- if not (and (eq .Values.architecture "replication") .Values.sentinel.enabled) }} - {{- $resourceSections = append $resourceSections "master" -}} -{{- end }} -{{- include "common.warnings.resources" (dict "sections" $resourceSections "context" $) }} -{{- include "common.warnings.modifiedImages" (dict "images" (list .Values.image .Values.sentinel.image .Values.metrics.image .Values.volumePermissions.image .Values.kubectl.image .Values.sysctl.image) "context" $) }} \ No newline at end of file diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/_helpers.tpl b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/_helpers.tpl deleted file mode 100644 index 2f0bda6a..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/_helpers.tpl +++ /dev/null @@ -1,325 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} - -{{/* -Return the proper Redis image name -*/}} -{{- define "redis.image" -}} -{{ include "common.images.image" (dict "imageRoot" .Values.image "global" .Values.global) }} -{{- end -}} - -{{/* -Return the proper Redis Sentinel image name -*/}} -{{- define "redis.sentinel.image" -}} -{{ include "common.images.image" (dict "imageRoot" .Values.sentinel.image "global" .Values.global) }} -{{- end -}} - -{{/* -Return the proper image name (for the metrics image) -*/}} -{{- define "redis.metrics.image" -}} -{{ include "common.images.image" (dict "imageRoot" .Values.metrics.image "global" .Values.global) }} -{{- end -}} - -{{/* -Return the proper image name (for the init container volume-permissions image) -*/}} -{{- define "redis.volumePermissions.image" -}} -{{ include "common.images.image" (dict "imageRoot" .Values.volumePermissions.image "global" .Values.global) }} -{{- end -}} - -{{/* -Return kubectl image -*/}} -{{- define "redis.kubectl.image" -}} -{{ include "common.images.image" (dict "imageRoot" .Values.kubectl.image "global" .Values.global) }} -{{- end -}} - -{{/* -Return sysctl image -*/}} -{{- define "redis.sysctl.image" -}} -{{ include "common.images.image" (dict "imageRoot" .Values.sysctl.image "global" .Values.global) }} -{{- end -}} - -{{/* -Return the proper Docker Image Registry Secret Names -*/}} -{{- define "redis.imagePullSecrets" -}} -{{- include "common.images.renderPullSecrets" (dict "images" (list .Values.image .Values.sentinel.image .Values.metrics.image .Values.volumePermissions.image .Values.sysctl.image) "context" $) -}} -{{- end -}} - -{{/* -Return the appropriate apiVersion for networkpolicy. -*/}} -{{- define "networkPolicy.apiVersion" -}} -{{- if semverCompare ">=1.4-0, <1.7-0" .Capabilities.KubeVersion.GitVersion -}} -{{- print "extensions/v1beta1" -}} -{{- else -}} -{{- print "networking.k8s.io/v1" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the appropriate apiGroup for PodSecurityPolicy. -*/}} -{{- define "podSecurityPolicy.apiGroup" -}} -{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} -{{- print "policy" -}} -{{- else -}} -{{- print "extensions" -}} -{{- end -}} -{{- end -}} - -{{/* -Return true if a TLS secret object should be created -*/}} -{{- define "redis.createTlsSecret" -}} -{{- if and .Values.tls.enabled .Values.tls.autoGenerated (and (not .Values.tls.existingSecret) (not .Values.tls.certificatesSecret)) }} - {{- true -}} -{{- end -}} -{{- end -}} - -{{/* -Return the secret containing Redis TLS certificates -*/}} -{{- define "redis.tlsSecretName" -}} -{{- $secretName := coalesce .Values.tls.existingSecret .Values.tls.certificatesSecret -}} -{{- if $secretName -}} - {{- printf "%s" (tpl $secretName $) -}} -{{- else -}} - {{- printf "%s-crt" (include "common.names.fullname" .) -}} -{{- end -}} -{{- end -}} - -{{/* -Return the path to the cert file. -*/}} -{{- define "redis.tlsCert" -}} -{{- if (include "redis.createTlsSecret" . ) -}} - {{- printf "/opt/bitnami/redis/certs/%s" "tls.crt" -}} -{{- else -}} - {{- required "Certificate filename is required when TLS in enabled" .Values.tls.certFilename | printf "/opt/bitnami/redis/certs/%s" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the path to the cert key file. -*/}} -{{- define "redis.tlsCertKey" -}} -{{- if (include "redis.createTlsSecret" . ) -}} - {{- printf "/opt/bitnami/redis/certs/%s" "tls.key" -}} -{{- else -}} - {{- required "Certificate Key filename is required when TLS in enabled" .Values.tls.certKeyFilename | printf "/opt/bitnami/redis/certs/%s" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the path to the CA cert file. -*/}} -{{- define "redis.tlsCACert" -}} -{{- if (include "redis.createTlsSecret" . ) -}} - {{- printf "/opt/bitnami/redis/certs/%s" "ca.crt" -}} -{{- else -}} - {{- required "Certificate CA filename is required when TLS in enabled" .Values.tls.certCAFilename | printf "/opt/bitnami/redis/certs/%s" -}} -{{- end -}} -{{- end -}} - -{{/* -Return the path to the DH params file. -*/}} -{{- define "redis.tlsDHParams" -}} -{{- if .Values.tls.dhParamsFilename -}} -{{- printf "/opt/bitnami/redis/certs/%s" .Values.tls.dhParamsFilename -}} -{{- end -}} -{{- end -}} - -{{/* -Create the name of the shared service account to use -*/}} -{{- define "redis.serviceAccountName" -}} -{{- if .Values.serviceAccount.create -}} - {{ default (include "common.names.fullname" .) .Values.serviceAccount.name }} -{{- else -}} - {{ default "default" .Values.serviceAccount.name }} -{{- end -}} -{{- end -}} - -{{/* -Create the name of the master service account to use -*/}} -{{- define "redis.masterServiceAccountName" -}} -{{- if .Values.master.serviceAccount.create -}} - {{ default (printf "%s-master" (include "common.names.fullname" .)) .Values.master.serviceAccount.name }} -{{- else -}} - {{- if .Values.serviceAccount.create -}} - {{ template "redis.serviceAccountName" . }} - {{- else -}} - {{ default "default" .Values.master.serviceAccount.name }} - {{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create the name of the replicas service account to use -*/}} -{{- define "redis.replicaServiceAccountName" -}} -{{- if .Values.replica.serviceAccount.create -}} - {{ default (printf "%s-replica" (include "common.names.fullname" .)) .Values.replica.serviceAccount.name }} -{{- else -}} - {{- if .Values.serviceAccount.create -}} - {{ template "redis.serviceAccountName" . }} - {{- else -}} - {{ default "default" .Values.replica.serviceAccount.name }} - {{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Return the configuration configmap name -*/}} -{{- define "redis.configmapName" -}} -{{- if .Values.existingConfigmap -}} - {{- printf "%s" (tpl .Values.existingConfigmap $) -}} -{{- else -}} - {{- printf "%s-configuration" (include "common.names.fullname" .) -}} -{{- end -}} -{{- end -}} - -{{/* -Return true if a configmap object should be created -*/}} -{{- define "redis.createConfigmap" -}} -{{- if empty .Values.existingConfigmap }} - {{- true -}} -{{- end -}} -{{- end -}} - -{{/* -Get the password secret. -*/}} -{{- define "redis.secretName" -}} -{{- if .Values.auth.existingSecret -}} -{{- printf "%s" (tpl .Values.auth.existingSecret $) -}} -{{- else -}} -{{- printf "%s" (include "common.names.fullname" .) -}} -{{- end -}} -{{- end -}} - -{{/* -Get the password key to be retrieved from Redis® secret. -*/}} -{{- define "redis.secretPasswordKey" -}} -{{- if and .Values.auth.existingSecret .Values.auth.existingSecretPasswordKey -}} -{{- printf "%s" (tpl .Values.auth.existingSecretPasswordKey $) -}} -{{- else -}} -{{- printf "redis-password" -}} -{{- end -}} -{{- end -}} - -{{/* -Return Redis® password -*/}} -{{- define "redis.password" -}} -{{- if or .Values.auth.enabled .Values.global.redis.password -}} - {{- include "common.secrets.passwords.manage" (dict "secret" (include "redis.secretName" .) "key" (include "redis.secretPasswordKey" .) "providedValues" (list "global.redis.password" "auth.password") "length" 10 "skipB64enc" true "skipQuote" true "context" $) -}} -{{- end }} -{{- end }} - -{{/* Check if there are rolling tags in the images */}} -{{- define "redis.checkRollingTags" -}} -{{- include "common.warnings.rollingTag" .Values.image }} -{{- include "common.warnings.rollingTag" .Values.sentinel.image }} -{{- include "common.warnings.rollingTag" .Values.metrics.image }} -{{- end -}} - -{{/* -Compile all warnings into a single message, and call fail. -*/}} -{{- define "redis.validateValues" -}} -{{- $messages := list -}} -{{- $messages := append $messages (include "redis.validateValues.topologySpreadConstraints" .) -}} -{{- $messages := append $messages (include "redis.validateValues.architecture" .) -}} -{{- $messages := append $messages (include "redis.validateValues.podSecurityPolicy.create" .) -}} -{{- $messages := append $messages (include "redis.validateValues.tls" .) -}} -{{- $messages := append $messages (include "redis.validateValues.createMaster" .) -}} -{{- $messages := without $messages "" -}} -{{- $message := join "\n" $messages -}} - -{{- if $message -}} -{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}} -{{- end -}} -{{- end -}} - -{{/* Validate values of Redis® - spreadConstrainsts K8s version */}} -{{- define "redis.validateValues.topologySpreadConstraints" -}} -{{- if and (semverCompare "<1.16-0" .Capabilities.KubeVersion.GitVersion) .Values.replica.topologySpreadConstraints -}} -redis: topologySpreadConstraints - Pod Topology Spread Constraints are only available on K8s >= 1.16 - Find more information at https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ -{{- end -}} -{{- end -}} - -{{/* Validate values of Redis® - must provide a valid architecture */}} -{{- define "redis.validateValues.architecture" -}} -{{- if and (ne .Values.architecture "standalone") (ne .Values.architecture "replication") -}} -redis: architecture - Invalid architecture selected. Valid values are "standalone" and - "replication". Please set a valid architecture (--set architecture="xxxx") -{{- end -}} -{{- if and .Values.sentinel.enabled (not (eq .Values.architecture "replication")) }} -redis: architecture - Using redis sentinel on standalone mode is not supported. - To deploy redis sentinel, please select the "replication" mode - (--set "architecture=replication,sentinel.enabled=true") -{{- end -}} -{{- end -}} - -{{/* Validate values of Redis® - PodSecurityPolicy create */}} -{{- define "redis.validateValues.podSecurityPolicy.create" -}} -{{- if and .Values.podSecurityPolicy.create (not .Values.podSecurityPolicy.enabled) }} -redis: podSecurityPolicy.create - In order to create PodSecurityPolicy, you also need to enable - podSecurityPolicy.enabled field -{{- end -}} -{{- end -}} - -{{/* Validate values of Redis® - TLS enabled */}} -{{- define "redis.validateValues.tls" -}} -{{- if and .Values.tls.enabled (not .Values.tls.autoGenerated) (not .Values.tls.existingSecret) (not .Values.tls.certificatesSecret) }} -redis: tls.enabled - In order to enable TLS, you also need to provide - an existing secret containing the TLS certificates or - enable auto-generated certificates. -{{- end -}} -{{- end -}} - -{{/* Validate values of Redis® - master service enabled */}} -{{- define "redis.validateValues.createMaster" -}} -{{- if and (or .Values.sentinel.masterService.enabled .Values.sentinel.service.createMaster) (or (not .Values.rbac.create) (not .Values.replica.automountServiceAccountToken) (not .Values.serviceAccount.create)) }} -redis: sentinel.masterService.enabled - In order to redirect requests only to the master pod via the service, you also need to - create rbac and serviceAccount. In addition, you need to enable - replica.automountServiceAccountToken. -{{- end -}} -{{- end -}} - -{{/* Define the suffix utilized for external-dns */}} -{{- define "redis.externalDNS.suffix" -}} -{{ printf "%s.%s" (include "common.names.fullname" .) .Values.useExternalDNS.suffix }} -{{- end -}} - -{{/* Compile all annotations utilized for external-dns */}} -{{- define "redis.externalDNS.annotations" -}} -{{- if and .Values.useExternalDNS.enabled .Values.useExternalDNS.annotationKey }} -{{ .Values.useExternalDNS.annotationKey }}hostname: {{ include "redis.externalDNS.suffix" . }} -{{- range $key, $val := .Values.useExternalDNS.additionalAnnotations }} -{{ $.Values.useExternalDNS.annotationKey }}{{ $key }}: {{ $val | quote }} -{{- end }} -{{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/configmap.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/configmap.yaml deleted file mode 100644 index 22df3583..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/configmap.yaml +++ /dev/null @@ -1,64 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if (include "redis.createConfigmap" .) }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ printf "%s-configuration" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -data: - redis.conf: |- - # User-supplied common configuration: - {{- if .Values.commonConfiguration }} - {{- include "common.tplvalues.render" ( dict "value" .Values.commonConfiguration "context" $ ) | nindent 4 }} - {{- end }} - # End of common configuration - master.conf: |- - dir {{ .Values.master.persistence.path }} - # User-supplied master configuration: - {{- if .Values.master.configuration }} - {{- include "common.tplvalues.render" ( dict "value" .Values.master.configuration "context" $ ) | nindent 4 }} - {{- end }} - {{- if .Values.master.disableCommands }} - {{- range .Values.master.disableCommands }} - rename-command {{ . }} "" - {{- end }} - {{- end }} - # End of master configuration - replica.conf: |- - dir {{ .Values.replica.persistence.path }} - # User-supplied replica configuration: - {{- if .Values.replica.configuration }} - {{- include "common.tplvalues.render" ( dict "value" .Values.replica.configuration "context" $ ) | nindent 4 }} - {{- end }} - {{- if .Values.replica.disableCommands }} - {{- range .Values.replica.disableCommands }} - rename-command {{ . }} "" - {{- end }} - {{- end }} - # End of replica configuration - {{- if .Values.sentinel.enabled }} - sentinel.conf: |- - dir "/tmp" - port {{ .Values.sentinel.containerPorts.sentinel }} - sentinel monitor {{ .Values.sentinel.masterSet }} {{ template "common.names.fullname" . }}-node-0.{{ template "common.names.fullname" . }}-headless.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }} {{ .Values.sentinel.service.ports.redis }} {{ .Values.sentinel.quorum }} - sentinel down-after-milliseconds {{ .Values.sentinel.masterSet }} {{ .Values.sentinel.downAfterMilliseconds }} - sentinel failover-timeout {{ .Values.sentinel.masterSet }} {{ .Values.sentinel.failoverTimeout }} - sentinel parallel-syncs {{ .Values.sentinel.masterSet }} {{ .Values.sentinel.parallelSyncs }} - {{- if or .Values.sentinel.masterService.enabled .Values.sentinel.service.createMaster }} - sentinel client-reconfig-script {{ .Values.sentinel.masterSet }} /opt/bitnami/scripts/start-scripts/push-master-label.sh - {{- end }} - # User-supplied sentinel configuration: - {{- if .Values.sentinel.configuration }} - {{- include "common.tplvalues.render" ( dict "value" .Values.sentinel.configuration "context" $ ) | nindent 4 }} - {{- end }} - # End of sentinel configuration - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/extra-list.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/extra-list.yaml deleted file mode 100644 index 329f5c65..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/extra-list.yaml +++ /dev/null @@ -1,9 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- range .Values.extraDeploy }} ---- -{{ include "common.tplvalues.render" (dict "value" . "context" $) }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/headless-svc.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/headless-svc.yaml deleted file mode 100644 index 280d9de0..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/headless-svc.yaml +++ /dev/null @@ -1,35 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -apiVersion: v1 -kind: Service -metadata: - name: {{ printf "%s-headless" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if or .Values.sentinel.service.headless.annotations .Values.commonAnnotations (include "redis.externalDNS.annotations" .) }} - annotations: - {{- if or .Values.sentinel.service.headless.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.sentinel.service.headless.annotations .Values.commonAnnotations ) "context" . ) }} - {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} - {{- include "redis.externalDNS.annotations" . | nindent 4 }} - {{- end }} -spec: - type: ClusterIP - clusterIP: None - {{- if .Values.sentinel.enabled }} - publishNotReadyAddresses: true - {{- end }} - ports: - - name: tcp-redis - port: {{ if .Values.sentinel.enabled }}{{ .Values.sentinel.service.ports.redis }}{{ else }}{{ .Values.master.service.ports.redis }}{{ end }} - targetPort: redis - {{- if .Values.sentinel.enabled }} - - name: tcp-sentinel - port: {{ .Values.sentinel.service.ports.sentinel }} - targetPort: redis-sentinel - {{- end }} - selector: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/health-configmap.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/health-configmap.yaml deleted file mode 100644 index bdd72a05..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/health-configmap.yaml +++ /dev/null @@ -1,194 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ printf "%s-health" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -data: - ping_readiness_local.sh: |- - #!/bin/bash - - [[ -f $REDIS_PASSWORD_FILE ]] && export REDIS_PASSWORD="$(< "${REDIS_PASSWORD_FILE}")" - [[ -n "$REDIS_PASSWORD" ]] && export REDISCLI_AUTH="$REDIS_PASSWORD" - response=$( - timeout -s 15 $1 \ - redis-cli \ - -h localhost \ -{{- if .Values.tls.enabled }} - -p $REDIS_TLS_PORT \ - --tls \ - --cacert {{ template "redis.tlsCACert" . }} \ - {{- if .Values.tls.authClients }} - --cert {{ template "redis.tlsCert" . }} \ - --key {{ template "redis.tlsCertKey" . }} \ - {{- end }} -{{- else }} - -p $REDIS_PORT \ -{{- end }} - ping - ) - if [ "$?" -eq "124" ]; then - echo "Timed out" - exit 1 - fi - if [ "$response" != "PONG" ]; then - echo "$response" - exit 1 - fi - ping_liveness_local.sh: |- - #!/bin/bash - - [[ -f $REDIS_PASSWORD_FILE ]] && export REDIS_PASSWORD="$(< "${REDIS_PASSWORD_FILE}")" - [[ -n "$REDIS_PASSWORD" ]] && export REDISCLI_AUTH="$REDIS_PASSWORD" - response=$( - timeout -s 15 $1 \ - redis-cli \ - -h localhost \ -{{- if .Values.tls.enabled }} - -p $REDIS_TLS_PORT \ - --tls \ - --cacert {{ template "redis.tlsCACert" . }} \ - {{- if .Values.tls.authClients }} - --cert {{ template "redis.tlsCert" . }} \ - --key {{ template "redis.tlsCertKey" . }} \ - {{- end }} -{{- else }} - -p $REDIS_PORT \ -{{- end }} - ping - ) - if [ "$?" -eq "124" ]; then - echo "Timed out" - exit 1 - fi - responseFirstWord=$(echo $response | head -n1 | awk '{print $1;}') - if [ "$response" != "PONG" ] && [ "$responseFirstWord" != "LOADING" ] && [ "$responseFirstWord" != "MASTERDOWN" ]; then - echo "$response" - exit 1 - fi -{{- if .Values.sentinel.enabled }} - ping_sentinel.sh: |- - #!/bin/bash - -{{- if .Values.auth.sentinel }} - [[ -f $REDIS_PASSWORD_FILE ]] && export REDIS_PASSWORD="$(< "${REDIS_PASSWORD_FILE}")" - [[ -n "$REDIS_PASSWORD" ]] && export REDISCLI_AUTH="$REDIS_PASSWORD" -{{- end }} - response=$( - timeout -s 15 $1 \ - redis-cli \ - -h localhost \ -{{- if .Values.tls.enabled }} - -p $REDIS_SENTINEL_TLS_PORT_NUMBER \ - --tls \ - --cacert "$REDIS_SENTINEL_TLS_CA_FILE" \ - {{- if .Values.tls.authClients }} - --cert "$REDIS_SENTINEL_TLS_CERT_FILE" \ - --key "$REDIS_SENTINEL_TLS_KEY_FILE" \ - {{- end }} -{{- else }} - -p $REDIS_SENTINEL_PORT \ -{{- end }} - ping - ) - if [ "$?" -eq "124" ]; then - echo "Timed out" - exit 1 - fi - if [ "$response" != "PONG" ]; then - echo "$response" - exit 1 - fi - parse_sentinels.awk: |- - /ip/ {FOUND_IP=1} - /port/ {FOUND_PORT=1} - /runid/ {FOUND_RUNID=1} - !/ip|port|runid/ { - if (FOUND_IP==1) { - IP=$1; FOUND_IP=0; - } - else if (FOUND_PORT==1) { - PORT=$1; - FOUND_PORT=0; - } else if (FOUND_RUNID==1) { - printf "\nsentinel known-sentinel {{ .Values.sentinel.masterSet }} %s %s %s", IP, PORT, $0; FOUND_RUNID=0; - } - } -{{- end }} - ping_readiness_master.sh: |- - #!/bin/bash - - [[ -f $REDIS_MASTER_PASSWORD_FILE ]] && export REDIS_MASTER_PASSWORD="$(< "${REDIS_MASTER_PASSWORD_FILE}")" - [[ -n "$REDIS_MASTER_PASSWORD" ]] && export REDISCLI_AUTH="$REDIS_MASTER_PASSWORD" - response=$( - timeout -s 15 $1 \ - redis-cli \ - -h $REDIS_MASTER_HOST \ - -p $REDIS_MASTER_PORT_NUMBER \ -{{- if .Values.tls.enabled }} - --tls \ - --cacert {{ template "redis.tlsCACert" . }} \ - {{- if .Values.tls.authClients }} - --cert {{ template "redis.tlsCert" . }} \ - --key {{ template "redis.tlsCertKey" . }} \ - {{- end }} -{{- end }} - ping - ) - if [ "$?" -eq "124" ]; then - echo "Timed out" - exit 1 - fi - if [ "$response" != "PONG" ]; then - echo "$response" - exit 1 - fi - ping_liveness_master.sh: |- - #!/bin/bash - - [[ -f $REDIS_MASTER_PASSWORD_FILE ]] && export REDIS_MASTER_PASSWORD="$(< "${REDIS_MASTER_PASSWORD_FILE}")" - [[ -n "$REDIS_MASTER_PASSWORD" ]] && export REDISCLI_AUTH="$REDIS_MASTER_PASSWORD" - response=$( - timeout -s 15 $1 \ - redis-cli \ - -h $REDIS_MASTER_HOST \ - -p $REDIS_MASTER_PORT_NUMBER \ -{{- if .Values.tls.enabled }} - --tls \ - --cacert {{ template "redis.tlsCACert" . }} \ - {{- if .Values.tls.authClients }} - --cert {{ template "redis.tlsCert" . }} \ - --key {{ template "redis.tlsCertKey" . }} \ - {{- end }} -{{- end }} - ping - ) - if [ "$?" -eq "124" ]; then - echo "Timed out" - exit 1 - fi - responseFirstWord=$(echo $response | head -n1 | awk '{print $1;}') - if [ "$response" != "PONG" ] && [ "$responseFirstWord" != "LOADING" ]; then - echo "$response" - exit 1 - fi - ping_readiness_local_and_master.sh: |- - script_dir="$(dirname "$0")" - exit_status=0 - "$script_dir/ping_readiness_local.sh" $1 || exit_status=$? - "$script_dir/ping_readiness_master.sh" $1 || exit_status=$? - exit $exit_status - ping_liveness_local_and_master.sh: |- - script_dir="$(dirname "$0")" - exit_status=0 - "$script_dir/ping_liveness_local.sh" $1 || exit_status=$? - "$script_dir/ping_liveness_master.sh" $1 || exit_status=$? - exit $exit_status diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/application.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/application.yaml deleted file mode 100644 index 84f83021..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/application.yaml +++ /dev/null @@ -1,553 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if gt (int64 .Values.master.count) 0 -}} -{{- if or (not (eq .Values.architecture "replication")) (not .Values.sentinel.enabled) }} -apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} -kind: {{ .Values.master.kind }} -metadata: - name: {{ printf "%s-master" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: master - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - {{- if not (eq .Values.master.kind "DaemonSet") }} - replicas: {{ .Values.master.count }} - {{- end }} - revisionHistoryLimit: {{ .Values.master.revisionHistoryLimit }} - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.master.podLabels .Values.commonLabels ) "context" . ) }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: master - {{- if (eq .Values.master.kind "StatefulSet") }} - serviceName: {{ printf "%s-headless" (include "common.names.fullname" .) }} - {{- end }} - {{- if .Values.master.updateStrategy }} - {{- if (eq .Values.master.kind "Deployment") }} - strategy: {{- toYaml .Values.master.updateStrategy | nindent 4 }} - {{- else }} - updateStrategy: {{- toYaml .Values.master.updateStrategy | nindent 4 }} - {{- end }} - {{- if and .Values.master.minReadySeconds (semverCompare ">= 1.23-0" (include "common.capabilities.kubeVersion" .)) }} - minReadySeconds: {{ .Values.master.minReadySeconds }} - {{- end }} - {{- end }} - template: - metadata: - labels: {{- include "common.labels.standard" ( dict "customLabels" $podLabels "context" $ ) | nindent 8 }} - app.kubernetes.io/component: master - {{- if and .Values.metrics.enabled .Values.metrics.podLabels }} - {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.podLabels "context" $ ) | nindent 8 }} - {{- end }} - annotations: - {{- if (include "redis.createConfigmap" .) }} - checksum/configmap: {{ pick ( include (print $.Template.BasePath "/configmap.yaml") . | fromYaml ) "data" | toYaml | sha256sum }} - {{- end }} - checksum/health: {{ pick ( include (print $.Template.BasePath "/health-configmap.yaml") . | fromYaml ) "data" | toYaml | sha256sum }} - checksum/scripts: {{ pick ( include (print $.Template.BasePath "/scripts-configmap.yaml") . | fromYaml ) "data" | toYaml | sha256sum }} - checksum/secret: {{ pick ( include (print $.Template.BasePath "/secret.yaml") . | fromYaml ) "data" | toYaml | sha256sum }} - {{- if .Values.master.podAnnotations }} - {{- include "common.tplvalues.render" ( dict "value" .Values.master.podAnnotations "context" $ ) | nindent 8 }} - {{- end }} - {{- if and .Values.metrics.enabled .Values.metrics.podAnnotations }} - {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.podAnnotations "context" $ ) | nindent 8 }} - {{- end }} - spec: - {{- if .Values.master.extraPodSpec }} - {{- include "common.tplvalues.render" (dict "value" .Values.master.extraPodSpec "context" $) | nindent 6 }} - {{- end }} - {{- include "redis.imagePullSecrets" . | nindent 6 }} - {{- if .Values.master.hostAliases }} - hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.master.hostAliases "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.master.podSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.master.podSecurityContext "context" $) | nindent 8 }} - {{- end }} - serviceAccountName: {{ template "redis.masterServiceAccountName" . }} - automountServiceAccountToken: {{ .Values.master.automountServiceAccountToken }} - {{- if .Values.master.priorityClassName }} - priorityClassName: {{ .Values.master.priorityClassName | quote }} - {{- end }} - {{- if .Values.master.affinity }} - affinity: {{- include "common.tplvalues.render" (dict "value" .Values.master.affinity "context" $) | nindent 8 }} - {{- else }} - affinity: - podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.master.podAffinityPreset "component" "master" "customLabels" $podLabels "context" $) | nindent 10 }} - podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.master.podAntiAffinityPreset "component" "master" "customLabels" $podLabels "context" $) | nindent 10 }} - nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.master.nodeAffinityPreset.type "key" .Values.master.nodeAffinityPreset.key "values" .Values.master.nodeAffinityPreset.values) | nindent 10 }} - {{- end }} - {{- if .Values.master.nodeSelector }} - nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.master.nodeSelector "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.master.tolerations }} - tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.master.tolerations "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.master.topologySpreadConstraints }} - topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.master.topologySpreadConstraints "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.master.shareProcessNamespace }} - shareProcessNamespace: {{ .Values.master.shareProcessNamespace }} - {{- end }} - {{- if .Values.master.schedulerName }} - schedulerName: {{ .Values.master.schedulerName | quote }} - {{- end }} - {{- if .Values.master.dnsPolicy }} - dnsPolicy: {{ .Values.master.dnsPolicy }} - {{- end }} - {{- if .Values.master.dnsConfig }} - dnsConfig: {{- include "common.tplvalues.render" (dict "value" .Values.master.dnsConfig "context" $) | nindent 8 }} - {{- end }} - enableServiceLinks: {{ .Values.master.enableServiceLinks }} - terminationGracePeriodSeconds: {{ .Values.master.terminationGracePeriodSeconds }} - containers: - - name: redis - image: {{ template "redis.image" . }} - imagePullPolicy: {{ .Values.image.pullPolicy | quote }} - {{- if .Values.master.lifecycleHooks }} - lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.master.lifecycleHooks "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.master.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.master.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} - {{- else if .Values.master.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.master.command "context" $) | nindent 12 }} - {{- else }} - command: - - /bin/bash - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} - {{- else if .Values.master.args }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.master.args "context" $) | nindent 12 }} - {{- else }} - args: - - -c - - /opt/bitnami/scripts/start-scripts/start-master.sh - {{- end }} - env: - - name: BITNAMI_DEBUG - value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }} - - name: REDIS_REPLICATION_MODE - value: master - - name: ALLOW_EMPTY_PASSWORD - value: {{ ternary "no" "yes" .Values.auth.enabled | quote }} - {{- if .Values.auth.enabled }} - {{- if .Values.auth.usePasswordFiles }} - - name: REDIS_PASSWORD_FILE - value: "/opt/bitnami/redis/secrets/redis-password" - {{- else }} - - name: REDIS_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "redis.secretName" . }} - key: {{ template "redis.secretPasswordKey" . }} - {{- end }} - {{- end }} - - name: REDIS_TLS_ENABLED - value: {{ ternary "yes" "no" .Values.tls.enabled | quote }} - {{- if .Values.tls.enabled }} - - name: REDIS_TLS_PORT - value: {{ .Values.master.containerPorts.redis | quote }} - - name: REDIS_TLS_AUTH_CLIENTS - value: {{ ternary "yes" "no" .Values.tls.authClients | quote }} - - name: REDIS_TLS_CERT_FILE - value: {{ template "redis.tlsCert" . }} - - name: REDIS_TLS_KEY_FILE - value: {{ template "redis.tlsCertKey" . }} - - name: REDIS_TLS_CA_FILE - value: {{ template "redis.tlsCACert" . }} - {{- if .Values.tls.dhParamsFilename }} - - name: REDIS_TLS_DH_PARAMS_FILE - value: {{ template "redis.tlsDHParams" . }} - {{- end }} - {{- else }} - - name: REDIS_PORT - value: {{ .Values.master.containerPorts.redis | quote }} - {{- end }} - {{- if .Values.master.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.master.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - {{- if or .Values.master.extraEnvVarsCM .Values.master.extraEnvVarsSecret }} - envFrom: - {{- if .Values.master.extraEnvVarsCM }} - - configMapRef: - name: {{ .Values.master.extraEnvVarsCM }} - {{- end }} - {{- if .Values.master.extraEnvVarsSecret }} - - secretRef: - name: {{ .Values.master.extraEnvVarsSecret }} - {{- end }} - {{- end }} - ports: - - name: redis - containerPort: {{ .Values.master.containerPorts.redis }} - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.master.customStartupProbe }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.master.customStartupProbe "context" $) | nindent 12 }} - {{- else if .Values.master.startupProbe.enabled }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.master.startupProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: redis - {{- end }} - {{- if .Values.master.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.master.customLivenessProbe "context" $) | nindent 12 }} - {{- else if .Values.master.livenessProbe.enabled }} - livenessProbe: - initialDelaySeconds: {{ .Values.master.livenessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.master.livenessProbe.periodSeconds }} - # One second longer than command timeout should prevent generation of zombie processes. - timeoutSeconds: {{ add1 .Values.master.livenessProbe.timeoutSeconds }} - successThreshold: {{ .Values.master.livenessProbe.successThreshold }} - failureThreshold: {{ .Values.master.livenessProbe.failureThreshold }} - exec: - command: - - sh - - -c - - /health/ping_liveness_local.sh {{ .Values.master.livenessProbe.timeoutSeconds }} - {{- end }} - {{- if .Values.master.customReadinessProbe }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.master.customReadinessProbe "context" $) | nindent 12 }} - {{- else if .Values.master.readinessProbe.enabled }} - readinessProbe: - initialDelaySeconds: {{ .Values.master.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.master.readinessProbe.periodSeconds }} - timeoutSeconds: {{ add1 .Values.master.readinessProbe.timeoutSeconds }} - successThreshold: {{ .Values.master.readinessProbe.successThreshold }} - failureThreshold: {{ .Values.master.readinessProbe.failureThreshold }} - exec: - command: - - sh - - -c - - /health/ping_readiness_local.sh {{ .Values.master.readinessProbe.timeoutSeconds }} - {{- end }} - {{- end }} - {{- if .Values.master.resources }} - resources: {{- toYaml .Values.master.resources | nindent 12 }} - {{- else if ne .Values.master.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.master.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: start-scripts - mountPath: /opt/bitnami/scripts/start-scripts - - name: health - mountPath: /health - {{- if .Values.auth.usePasswordFiles }} - - name: redis-password - mountPath: /opt/bitnami/redis/secrets/ - {{- end }} - - name: redis-data - mountPath: {{ .Values.master.persistence.path }} - {{- if .Values.master.persistence.subPath }} - subPath: {{ .Values.master.persistence.subPath }} - {{- else if .Values.master.persistence.subPathExpr }} - subPathExpr: {{ .Values.master.persistence.subPathExpr }} - {{- end }} - - name: config - mountPath: /opt/bitnami/redis/mounted-etc - - name: empty-dir - mountPath: /opt/bitnami/redis/etc/ - subPath: app-conf-dir - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - {{- if .Values.tls.enabled }} - - name: redis-certificates - mountPath: /opt/bitnami/redis/certs - readOnly: true - {{- end }} - {{- if .Values.master.extraVolumeMounts }} - {{- include "common.tplvalues.render" ( dict "value" .Values.master.extraVolumeMounts "context" $ ) | nindent 12 }} - {{- end }} - {{- if .Values.metrics.enabled }} - - name: metrics - image: {{ include "redis.metrics.image" . }} - imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} - {{- if .Values.metrics.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.metrics.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} - {{- else if .Values.metrics.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.command "context" $) | nindent 12 }} - {{- else }} - command: - - /bin/bash - - -c - - | - if [[ -f '/secrets/redis-password' ]]; then - export REDIS_PASSWORD=$(cat /secrets/redis-password) - fi - redis_exporter{{- range $key, $value := .Values.metrics.extraArgs }} --{{ $key }}={{ $value }}{{- end }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} - {{- end }} - env: - - name: REDIS_ALIAS - value: {{ template "common.names.fullname" . }} - - name: REDIS_EXPORTER_WEB_LISTEN_ADDRESS - value: {{ printf ":%v" .Values.metrics.containerPorts.http }} - {{- if .Values.auth.enabled }} - - name: REDIS_USER - value: default - {{- if (not .Values.auth.usePasswordFiles) }} - - name: REDIS_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "redis.secretName" . }} - key: {{ template "redis.secretPasswordKey" . }} - {{- end }} - {{- end }} - {{- if .Values.tls.enabled }} - - name: REDIS_ADDR - value: rediss://{{ .Values.metrics.redisTargetHost }}:{{ .Values.master.containerPorts.redis }} - {{- if .Values.tls.authClients }} - - name: REDIS_EXPORTER_TLS_CLIENT_KEY_FILE - value: {{ template "redis.tlsCertKey" . }} - - name: REDIS_EXPORTER_TLS_CLIENT_CERT_FILE - value: {{ template "redis.tlsCert" . }} - {{- end }} - - name: REDIS_EXPORTER_TLS_CA_CERT_FILE - value: {{ template "redis.tlsCACert" . }} - {{- end }} - {{- if .Values.metrics.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.metrics.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - ports: - - name: metrics - containerPort: {{ .Values.metrics.containerPorts.http }} - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.metrics.customStartupProbe }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customStartupProbe "context" $) | nindent 12 }} - {{- else if .Values.metrics.startupProbe.enabled }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.startupProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: metrics - {{- end }} - {{- if .Values.metrics.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customLivenessProbe "context" $) | nindent 12 }} - {{- else if .Values.metrics.livenessProbe.enabled }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.livenessProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: metrics - {{- end }} - {{- if .Values.metrics.customReadinessProbe }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customReadinessProbe "context" $) | nindent 12 }} - {{- else if .Values.metrics.readinessProbe.enabled }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.readinessProbe "enabled") "context" $) | nindent 12 }} - httpGet: - path: / - port: metrics - {{- end }} - {{- end }} - {{- if .Values.metrics.resources }} - resources: {{- toYaml .Values.metrics.resources | nindent 12 }} - {{- else if ne .Values.metrics.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.metrics.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: app-tmp-dir - {{- if .Values.auth.usePasswordFiles }} - - name: redis-password - mountPath: /secrets/ - {{- end }} - {{- if .Values.tls.enabled }} - - name: redis-certificates - mountPath: /opt/bitnami/redis/certs - readOnly: true - {{- end }} - {{- if .Values.metrics.extraVolumeMounts }} - {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.extraVolumeMounts "context" $ ) | nindent 12 }} - {{- end }} - {{- end }} - {{- if .Values.master.sidecars }} - {{- include "common.tplvalues.render" (dict "value" .Values.master.sidecars "context" $) | nindent 8 }} - {{- end }} - {{- $needsVolumePermissions := and .Values.volumePermissions.enabled .Values.master.persistence.enabled .Values.master.podSecurityContext.enabled .Values.master.containerSecurityContext.enabled }} - {{- if or .Values.master.initContainers $needsVolumePermissions .Values.sysctl.enabled }} - initContainers: - {{- if .Values.master.initContainers }} - {{- include "common.tplvalues.render" (dict "value" .Values.master.initContainers "context" $) | nindent 8 }} - {{- end }} - {{- if $needsVolumePermissions }} - - name: volume-permissions - image: {{ include "redis.volumePermissions.image" . }} - imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} - command: - - /bin/bash - - -ec - - | - {{- if eq ( toString ( .Values.volumePermissions.containerSecurityContext.runAsUser )) "auto" }} - chown -R `id -u`:`id -G | cut -d " " -f2` {{ .Values.master.persistence.path }} - {{- else }} - chown -R {{ .Values.master.containerSecurityContext.runAsUser }}:{{ .Values.master.podSecurityContext.fsGroup }} {{ .Values.master.persistence.path }} - {{- end }} - {{- if eq ( toString ( .Values.volumePermissions.containerSecurityContext.runAsUser )) "auto" }} - securityContext: {{- omit .Values.volumePermissions.containerSecurityContext "runAsUser" | toYaml | nindent 12 }} - {{- else }} - securityContext: {{- .Values.volumePermissions.containerSecurityContext | toYaml | nindent 12 }} - {{- end }} - {{- if .Values.volumePermissions.extraEnvVars }} - env: - {{- include "common.tplvalues.render" (dict "value" .Values.volumePermissions.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.volumePermissions.resources }} - resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} - {{- else if ne .Values.volumePermissions.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.volumePermissions.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - - name: redis-data - mountPath: {{ .Values.master.persistence.path }} - {{- if .Values.master.persistence.subPath }} - subPath: {{ .Values.master.persistence.subPath }} - {{- else if .Values.master.persistence.subPathExpr }} - subPathExpr: {{ .Values.master.persistence.subPathExpr }} - {{- end }} - {{- end }} - {{- if .Values.sysctl.enabled }} - - name: init-sysctl - image: {{ include "redis.sysctl.image" . }} - imagePullPolicy: {{ default "" .Values.sysctl.image.pullPolicy | quote }} - securityContext: - privileged: true - runAsUser: 0 - {{- if .Values.sysctl.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.sysctl.command "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.sysctl.resources }} - resources: {{- toYaml .Values.sysctl.resources | nindent 12 }} - {{- else if ne .Values.sysctl.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.sysctl.resourcesPreset) | nindent 12 }} - {{- end }} - {{- if .Values.sysctl.mountHostSys }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - - name: host-sys - mountPath: /host-sys - {{- end }} - {{- end }} - {{- end }} - volumes: - - name: start-scripts - configMap: - name: {{ printf "%s-scripts" (include "common.names.fullname" .) }} - defaultMode: 0755 - - name: health - configMap: - name: {{ printf "%s-health" (include "common.names.fullname" .) }} - defaultMode: 0755 - {{- if .Values.auth.usePasswordFiles }} - - name: redis-password - {{ if .Values.auth.usePasswordFileFromSecret }} - secret: - secretName: {{ template "redis.secretName" . }} - items: - - key: {{ template "redis.secretPasswordKey" . }} - path: redis-password - {{- else }} - emptyDir: {} - {{- end }} - {{- end }} - - name: config - configMap: - name: {{ include "redis.configmapName" . }} - {{- if .Values.sysctl.mountHostSys }} - - name: host-sys - hostPath: - path: /sys - {{- end }} - - name: empty-dir - {{- if or .Values.master.persistence.medium .Values.master.persistence.sizeLimit }} - emptyDir: - {{- if .Values.master.persistence.medium }} - medium: {{ .Values.master.persistence.medium | quote }} - {{- end }} - {{- if .Values.master.persistence.sizeLimit }} - sizeLimit: {{ .Values.master.persistence.sizeLimit | quote }} - {{- end }} - {{- else }} - emptyDir: {} - {{- end }} - {{- if .Values.tls.enabled }} - - name: redis-certificates - secret: - secretName: {{ include "redis.tlsSecretName" . }} - defaultMode: 256 - {{- end }} - {{- if .Values.master.extraVolumes }} - {{- include "common.tplvalues.render" ( dict "value" .Values.master.extraVolumes "context" $ ) | nindent 8 }} - {{- end }} - {{- if .Values.metrics.extraVolumes }} - {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.extraVolumes "context" $ ) | nindent 8 }} - {{- end }} - {{- if or (not .Values.master.persistence.enabled) (eq .Values.master.kind "DaemonSet") }} - - name: redis-data - {{- if or .Values.master.persistence.medium .Values.master.persistence.sizeLimit }} - emptyDir: - {{- if .Values.master.persistence.medium }} - medium: {{ .Values.master.persistence.medium | quote }} - {{- end }} - {{- if .Values.master.persistence.sizeLimit }} - sizeLimit: {{ .Values.master.persistence.sizeLimit | quote }} - {{- end }} - {{- else }} - emptyDir: {} - {{- end }} - {{- else if .Values.master.persistence.existingClaim }} - - name: redis-data - persistentVolumeClaim: - claimName: {{ printf "%s" (tpl .Values.master.persistence.existingClaim .) }} - {{- else if (eq .Values.master.kind "Deployment") }} - - name: redis-data - persistentVolumeClaim: - claimName: {{ printf "redis-data-%s-master" (include "common.names.fullname" .) }} - {{- else }} - {{- if .Values.master.persistentVolumeClaimRetentionPolicy.enabled }} - persistentVolumeClaimRetentionPolicy: - whenDeleted: {{ .Values.master.persistentVolumeClaimRetentionPolicy.whenDeleted }} - whenScaled: {{ .Values.master.persistentVolumeClaimRetentionPolicy.whenScaled }} - {{- end }} - volumeClaimTemplates: - - apiVersion: v1 - kind: PersistentVolumeClaim - metadata: - name: redis-data - {{- $claimLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.master.persistence.labels .Values.commonLabels ) "context" . ) }} - labels: {{- include "common.labels.matchLabels" ( dict "customLabels" $claimLabels "context" $ ) | nindent 10 }} - app.kubernetes.io/component: master - {{- if .Values.master.persistence.annotations }} - annotations: {{- toYaml .Values.master.persistence.annotations | nindent 10 }} - {{- end }} - spec: - accessModes: - {{- range .Values.master.persistence.accessModes }} - - {{ . | quote }} - {{- end }} - resources: - requests: - storage: {{ .Values.master.persistence.size | quote }} - {{- if .Values.master.persistence.selector }} - selector: {{- include "common.tplvalues.render" (dict "value" .Values.master.persistence.selector "context" $) | nindent 10 }} - {{- end }} - {{- if .Values.master.persistence.dataSource }} - dataSource: {{- include "common.tplvalues.render" (dict "value" .Values.master.persistence.dataSource "context" $) | nindent 10 }} - {{- end }} - {{- include "common.storage.class" (dict "persistence" .Values.master.persistence "global" .Values.global) | nindent 8 }} - {{- end }} -{{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/pdb.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/pdb.yaml deleted file mode 100644 index dab636db..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/pdb.yaml +++ /dev/null @@ -1,27 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} -{{- $pdb := coalesce .Values.pdb .Values.master.pdb }} -{{- if and $pdb.create (gt (int64 .Values.master.count) 0) (or (not (eq .Values.architecture "replication")) (not .Values.sentinel.enabled)) }} -apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} -kind: PodDisruptionBudget -metadata: - name: {{ printf "%s-master" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: master - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - {{- if $pdb.minAvailable }} - minAvailable: {{ $pdb.minAvailable }} - {{- end }} - {{- if or $pdb.maxUnavailable (not $pdb.minAvailable)}} - maxUnavailable: {{ $pdb.maxUnavailable | default 1 }} - {{- end }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: master -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/psp.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/psp.yaml deleted file mode 100644 index 2a685f8e..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/psp.yaml +++ /dev/null @@ -1,47 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and (include "common.capabilities.psp.supported" .) .Values.podSecurityPolicy.create }} -apiVersion: policy/v1beta1 -kind: PodSecurityPolicy -metadata: - name: {{ printf "%s-master" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - allowPrivilegeEscalation: false - fsGroup: - rule: 'MustRunAs' - ranges: - - min: {{ .Values.master.podSecurityContext.fsGroup }} - max: {{ .Values.master.podSecurityContext.fsGroup }} - hostIPC: false - hostNetwork: false - hostPID: false - privileged: false - readOnlyRootFilesystem: false - requiredDropCapabilities: - - ALL - runAsUser: - rule: 'MustRunAs' - ranges: - - min: {{ .Values.master.containerSecurityContext.runAsUser }} - max: {{ .Values.master.containerSecurityContext.runAsUser }} - seLinux: - rule: 'RunAsAny' - supplementalGroups: - rule: 'MustRunAs' - ranges: - - min: {{ .Values.master.containerSecurityContext.runAsUser }} - max: {{ .Values.master.containerSecurityContext.runAsUser }} - volumes: - - 'configMap' - - 'secret' - - 'emptyDir' - - 'persistentVolumeClaim' -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/pvc.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/pvc.yaml deleted file mode 100644 index 13aee503..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/pvc.yaml +++ /dev/null @@ -1,33 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and (eq .Values.architecture "standalone") (eq .Values.master.kind "Deployment") (.Values.master.persistence.enabled) (not .Values.master.persistence.existingClaim) }} -kind: PersistentVolumeClaim -apiVersion: v1 -metadata: - name: {{ printf "redis-data-%s-master" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.master.persistence.labels .Values.commonLabels ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: master - {{- if .Values.master.persistence.annotations }} - annotations: {{- toYaml .Values.master.persistence.annotations | nindent 4 }} - {{- end }} -spec: - accessModes: - {{- range .Values.master.persistence.accessModes }} - - {{ . | quote }} - {{- end }} - resources: - requests: - storage: {{ .Values.master.persistence.size | quote }} - {{- if .Values.master.persistence.selector }} - selector: {{- include "common.tplvalues.render" (dict "value" .Values.master.persistence.selector "context" $) | nindent 4 }} - {{- end }} - {{- if .Values.master.persistence.dataSource }} - dataSource: {{- include "common.tplvalues.render" (dict "value" .Values.master.persistence.dataSource "context" $) | nindent 4 }} - {{- end }} - {{- include "common.storage.class" (dict "persistence" .Values.master.persistence "global" .Values.global) | nindent 2 }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/service.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/service.yaml deleted file mode 100644 index b9bf47da..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/service.yaml +++ /dev/null @@ -1,62 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and (not .Values.sentinel.enabled) (gt (int64 .Values.master.count) 0) }} -apiVersion: v1 -kind: Service -metadata: - name: {{ printf "%s-master" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: master - {{- if or .Values.master.service.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.master.service.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -spec: - type: {{ .Values.master.service.type }} - {{- if or (eq .Values.master.service.type "LoadBalancer") (eq .Values.master.service.type "NodePort") }} - externalTrafficPolicy: {{ .Values.master.service.externalTrafficPolicy | quote }} - {{- end }} - {{- if (semverCompare ">=1.22-0" (include "common.capabilities.kubeVersion" .)) }} - internalTrafficPolicy: {{ .Values.master.service.internalTrafficPolicy }} - {{- end }} - {{- if and (eq .Values.master.service.type "LoadBalancer") (not (empty .Values.master.service.loadBalancerIP)) }} - loadBalancerIP: {{ .Values.master.service.loadBalancerIP }} - {{- end }} - {{- if and (eq .Values.master.service.type "LoadBalancer") .Values.master.service.loadBalancerClass }} - loadBalancerClass: {{ .Values.master.service.loadBalancerClass }} - {{- end }} - {{- if and (eq .Values.master.service.type "LoadBalancer") (not (empty .Values.master.service.loadBalancerSourceRanges)) }} - loadBalancerSourceRanges: {{ toYaml .Values.master.service.loadBalancerSourceRanges | nindent 4 }} - {{- end }} - {{- if and .Values.master.service.clusterIP (eq .Values.master.service.type "ClusterIP") }} - clusterIP: {{ .Values.master.service.clusterIP }} - {{- end }} - {{- if .Values.master.service.sessionAffinity }} - sessionAffinity: {{ .Values.master.service.sessionAffinity }} - {{- end }} - {{- if .Values.master.service.sessionAffinityConfig }} - sessionAffinityConfig: {{- include "common.tplvalues.render" (dict "value" .Values.master.service.sessionAffinityConfig "context" $) | nindent 4 }} - {{- end }} - {{- if .Values.master.service.externalIPs }} - externalIPs: {{- include "common.tplvalues.render" (dict "value" .Values.master.service.externalIPs "context" $) | nindent 4 }} - {{- end }} - ports: - - name: {{ .Values.master.service.portNames.redis }} - port: {{ .Values.master.service.ports.redis }} - targetPort: redis - {{- if and (or (eq .Values.master.service.type "NodePort") (eq .Values.master.service.type "LoadBalancer")) .Values.master.service.nodePorts.redis}} - nodePort: {{ .Values.master.service.nodePorts.redis}} - {{- else if eq .Values.master.service.type "ClusterIP" }} - nodePort: null - {{- end }} - {{- if .Values.master.service.extraPorts }} - {{- include "common.tplvalues.render" (dict "value" .Values.master.service.extraPorts "context" $) | nindent 4 }} - {{- end }} - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.master.podLabels .Values.commonLabels ) "context" . ) }} - selector: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: master -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/serviceaccount.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/serviceaccount.yaml deleted file mode 100644 index bf58cc50..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/master/serviceaccount.yaml +++ /dev/null @@ -1,18 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.master.serviceAccount.create (or (not (eq .Values.architecture "replication")) (not .Values.sentinel.enabled)) }} -apiVersion: v1 -kind: ServiceAccount -automountServiceAccountToken: {{ .Values.master.serviceAccount.automountServiceAccountToken }} -metadata: - name: {{ template "redis.masterServiceAccountName" . }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if or .Values.master.serviceAccount.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.master.serviceAccount.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/metrics-svc.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/metrics-svc.yaml deleted file mode 100644 index 529122ef..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/metrics-svc.yaml +++ /dev/null @@ -1,44 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.metrics.enabled .Values.metrics.service.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: {{ printf "%s-metrics" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: metrics - {{- if or .Values.metrics.service.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.metrics.service.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -spec: - type: {{ .Values.metrics.service.type }} - {{- if and .Values.metrics.service.clusterIP (eq .Values.metrics.service.type "ClusterIP") }} - clusterIP: {{ .Values.metrics.service.clusterIP }} - {{- end }} - {{- if eq .Values.metrics.service.type "LoadBalancer" }} - externalTrafficPolicy: {{ .Values.metrics.service.externalTrafficPolicy }} - {{- end }} - {{- if and (eq .Values.metrics.service.type "LoadBalancer") .Values.metrics.service.loadBalancerIP }} - loadBalancerIP: {{ .Values.metrics.service.loadBalancerIP }} - {{- end }} - {{- if and (eq .Values.metrics.service.type "LoadBalancer") .Values.metrics.service.loadBalancerClass }} - loadBalancerClass: {{ .Values.metrics.service.loadBalancerClass }} - {{- end }} - {{- if and (eq .Values.metrics.service.type "LoadBalancer") .Values.metrics.service.loadBalancerSourceRanges }} - loadBalancerSourceRanges: {{- toYaml .Values.metrics.service.loadBalancerSourceRanges | nindent 4 }} - {{- end }} - ports: - - name: http-metrics - port: {{ coalesce .Values.metrics.service.ports.http .Values.metrics.service.port }} - protocol: TCP - targetPort: metrics - {{- if .Values.metrics.service.extraPorts }} - {{- include "common.tplvalues.render" (dict "value" .Values.metrics.service.extraPorts "context" $) | nindent 4 }} - {{- end }} - selector: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/networkpolicy.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/networkpolicy.yaml deleted file mode 100644 index 3d652c6e..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/networkpolicy.yaml +++ /dev/null @@ -1,108 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.networkPolicy.enabled }} -kind: NetworkPolicy -apiVersion: {{ template "networkPolicy.apiVersion" . }} -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - podSelector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 6 }} - policyTypes: - - Ingress - - Egress - {{- if .Values.networkPolicy.allowExternalEgress }} - egress: - - {} - {{- else }} - egress: - {{- if eq .Values.architecture "replication" }} - # Allow dns resolution - - ports: - - port: 53 - protocol: UDP - # Allow outbound connections to other cluster pods - - ports: - - port: {{ .Values.master.containerPorts.redis }} - {{- if .Values.sentinel.enabled }} - - port: {{ .Values.sentinel.containerPorts.sentinel }} - {{- end }} - to: - - podSelector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 14 }} - {{- end }} - {{- if .Values.networkPolicy.extraEgress }} - {{- include "common.tplvalues.render" ( dict "value" .Values.networkPolicy.extraEgress "context" $ ) | nindent 4 }} - {{- end }} - {{- end }} - ingress: - # Allow inbound connections - - ports: - - port: {{ .Values.master.containerPorts.redis }} - {{- if .Values.sentinel.enabled }} - - port: {{ .Values.sentinel.containerPorts.sentinel }} - {{- end }} - {{- if not .Values.networkPolicy.allowExternal }} - from: - - podSelector: - matchLabels: - {{ template "common.names.fullname" . }}-client: "true" - - podSelector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 14 }} - {{- if or .Values.networkPolicy.ingressNSMatchLabels .Values.networkPolicy.ingressNSPodMatchLabels }} - - namespaceSelector: - matchLabels: - {{- if .Values.networkPolicy.ingressNSMatchLabels }} - {{- range $key, $value := .Values.networkPolicy.ingressNSMatchLabels }} - {{ $key | quote }}: {{ $value | quote }} - {{- end }} - {{ else }} - {} - {{- end }} - {{- if .Values.networkPolicy.ingressNSPodMatchLabels }} - podSelector: - matchLabels: - {{- range $key, $value := .Values.networkPolicy.ingressNSPodMatchLabels }} - {{ $key | quote }}: {{ $value | quote }} - {{- end }} - {{- end }} - {{- end }} - {{- end }} - {{- if .Values.metrics.enabled }} - # Allow prometheus scrapes for metrics - - ports: - - port: {{ .Values.metrics.containerPorts.http }} - {{- if not .Values.networkPolicy.metrics.allowExternal }} - from: - {{- if or .Values.networkPolicy.metrics.ingressNSMatchLabels .Values.networkPolicy.metrics.ingressNSPodMatchLabels }} - - namespaceSelector: - matchLabels: - {{- if .Values.networkPolicy.metrics.ingressNSMatchLabels }} - {{- range $key, $value := .Values.networkPolicy.metrics.ingressNSMatchLabels }} - {{ $key | quote }}: {{ $value | quote }} - {{- end }} - {{ else }} - {} - {{- end }} - {{- if .Values.networkPolicy.metrics.ingressNSPodMatchLabels }} - podSelector: - matchLabels: - {{- range $key, $value := .Values.networkPolicy.metrics.ingressNSPodMatchLabels }} - {{ $key | quote }}: {{ $value | quote }} - {{- end }} - {{- end }} - {{- end }} - {{- end }} - {{- end }} - {{- if .Values.networkPolicy.extraIngress }} - {{- include "common.tplvalues.render" ( dict "value" .Values.networkPolicy.extraIngress "context" $ ) | nindent 4 }} - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/podmonitor.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/podmonitor.yaml deleted file mode 100644 index 32976106..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/podmonitor.yaml +++ /dev/null @@ -1,81 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.metrics.enabled .Values.metrics.podMonitor.enabled }} -apiVersion: monitoring.coreos.com/v1 -kind: PodMonitor -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ default (include "common.names.namespace" .) .Values.metrics.podMonitor.namespace | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.metrics.podMonitor.additionalLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.metrics.podMonitor.additionalLabels "context" $) | nindent 4 }} - {{- end }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - podMetricsEndpoints: - - port: {{ .Values.metrics.podMonitor.port }} - {{- if .Values.metrics.podMonitor.interval }} - interval: {{ .Values.metrics.podMonitor.interval }} - {{- end }} - {{- if .Values.metrics.podMonitor.scrapeTimeout }} - scrapeTimeout: {{ .Values.metrics.podMonitor.scrapeTimeout }} - {{- end }} - {{- if .Values.metrics.podMonitor.honorLabels }} - honorLabels: {{ .Values.metrics.podMonitor.honorLabels }} - {{- end }} - {{- with concat .Values.metrics.podMonitor.relabelings .Values.metrics.podMonitor.relabellings }} - relabelings: {{- toYaml . | nindent 6 }} - {{- end }} - {{- if .Values.metrics.podMonitor.metricRelabelings }} - metricRelabelings: {{- toYaml .Values.metrics.podMonitor.metricRelabelings | nindent 6 }} - {{- end }} - {{- range .Values.metrics.podMonitor.additionalEndpoints }} - - port: {{ .port }} - {{- if .interval }} - interval: {{ .interval }} - {{- end }} - {{- if .path }} - path: {{ .path }} - {{- end }} - {{- if .honorLabels }} - honorLabels: {{ .honorLabels }} - {{- end }} - {{- with concat .relabelings .relabellings }} - relabelings: {{- toYaml . | nindent 6 }} - {{- end }} - {{- if .metricRelabelings }} - metricRelabelings: {{- toYaml .metricRelabelings | nindent 6 }} - {{- end }} - {{- if .scrapeTimeout }} - scrapeTimeout: {{ .scrapeTimeout }} - {{- end }} - {{- if .params }} - params: - {{- range $key, $value := .params }} - {{ $key }}: - {{- range $value }} - - {{ . | quote }} - {{- end }} - {{- end }} - {{- end }} - {{- end }} - {{- if .Values.metrics.serviceMonitor.podTargetLabels }} - podTargetLabels: {{- toYaml .Values.metrics.podMonitor.podTargetLabels | nindent 4 }} - {{- end }} - {{- with .Values.metrics.podMonitor.sampleLimit -}} - sampleLimit: {{ . }} - {{- end }} - {{- with .Values.metrics.podMonitor.targetLimit -}} - targetLimit: {{ . }} - {{- end }} - namespaceSelector: - matchNames: - - {{ include "common.names.namespace" . | quote }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 6 }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/prometheusrule.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/prometheusrule.yaml deleted file mode 100644 index 56c013bd..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/prometheusrule.yaml +++ /dev/null @@ -1,23 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.metrics.enabled .Values.metrics.prometheusRule.enabled }} -apiVersion: monitoring.coreos.com/v1 -kind: PrometheusRule -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ default (include "common.names.namespace" .) .Values.metrics.prometheusRule.namespace | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.metrics.prometheusRule.additionalLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.metrics.prometheusRule.additionalLabels "context" $) | nindent 4 }} - {{- end }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - groups: - - name: {{ include "common.names.fullname" . }} - rules: {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.prometheusRule.rules "context" $ ) | nindent 8 }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/replicas/application.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/replicas/application.yaml deleted file mode 100644 index bba4c7e9..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/replicas/application.yaml +++ /dev/null @@ -1,568 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and (eq .Values.architecture "replication") (not .Values.sentinel.enabled) }} -apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} -kind: {{ .Values.replica.kind }} -metadata: - name: {{ printf "%s-replicas" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: replica - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - {{- if and (not (eq .Values.replica.kind "DaemonSet")) (not .Values.replica.autoscaling.enabled) }} - replicas: {{ .Values.replica.replicaCount }} - {{- end }} - revisionHistoryLimit: {{ .Values.replica.revisionHistoryLimit }} - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.replica.podLabels .Values.commonLabels ) "context" . ) }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: replica - {{- if (eq .Values.replica.kind "StatefulSet") }} - serviceName: {{ printf "%s-headless" (include "common.names.fullname" .) }} - {{- end }} - {{- if .Values.replica.updateStrategy }} - updateStrategy: {{- toYaml .Values.replica.updateStrategy | nindent 4 }} - {{- end }} - {{- if and .Values.replica.minReadySeconds (semverCompare ">= 1.23-0" (include "common.capabilities.kubeVersion" .)) }} - minReadySeconds: {{ .Values.replica.minReadySeconds }} - {{- end }} - {{- if .Values.replica.podManagementPolicy }} - podManagementPolicy: {{ .Values.replica.podManagementPolicy | quote }} - {{- end }} - template: - metadata: - labels: {{- include "common.labels.standard" ( dict "customLabels" $podLabels "context" $ ) | nindent 8 }} - app.kubernetes.io/component: replica - {{- if and .Values.metrics.enabled .Values.metrics.podLabels }} - {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.podLabels "context" $ ) | nindent 8 }} - {{- end }} - annotations: - {{- if (include "redis.createConfigmap" .) }} - checksum/configmap: {{ pick ( include (print $.Template.BasePath "/configmap.yaml") . | fromYaml ) "data" | toYaml | sha256sum }} - {{- end }} - checksum/health: {{ pick ( include (print $.Template.BasePath "/health-configmap.yaml") . | fromYaml ) "data" | toYaml | sha256sum }} - checksum/scripts: {{ pick ( include (print $.Template.BasePath "/scripts-configmap.yaml") . | fromYaml ) "data" | toYaml | sha256sum }} - checksum/secret: {{ pick ( include (print $.Template.BasePath "/secret.yaml") . | fromYaml ) "data" | toYaml | sha256sum }} - {{- if .Values.replica.podAnnotations }} - {{- include "common.tplvalues.render" ( dict "value" .Values.replica.podAnnotations "context" $ ) | nindent 8 }} - {{- end }} - {{- if and .Values.metrics.enabled .Values.metrics.podAnnotations }} - {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.podAnnotations "context" $ ) | nindent 8 }} - {{- end }} - spec: - {{- if .Values.replica.extraPodSpec }} - {{- include "common.tplvalues.render" (dict "value" .Values.replica.extraPodSpec "context" $) | nindent 6 }} - {{- end }} - {{- include "redis.imagePullSecrets" . | nindent 6 }} - {{- if .Values.replica.hostAliases }} - hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.replica.hostAliases "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.replica.podSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.replica.podSecurityContext "context" $) | nindent 8 }} - {{- end }} - serviceAccountName: {{ template "redis.replicaServiceAccountName" . }} - automountServiceAccountToken: {{ .Values.replica.automountServiceAccountToken }} - {{- if .Values.replica.priorityClassName }} - priorityClassName: {{ .Values.replica.priorityClassName | quote }} - {{- end }} - {{- if .Values.replica.affinity }} - affinity: {{- include "common.tplvalues.render" (dict "value" .Values.replica.affinity "context" $) | nindent 8 }} - {{- else }} - affinity: - podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.replica.podAffinityPreset "component" "replica" "customLabels" $podLabels "context" $) | nindent 10 }} - podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.replica.podAntiAffinityPreset "component" "replica" "customLabels" $podLabels "context" $) | nindent 10 }} - nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.replica.nodeAffinityPreset.type "key" .Values.replica.nodeAffinityPreset.key "values" .Values.replica.nodeAffinityPreset.values) | nindent 10 }} - {{- end }} - {{- if .Values.replica.nodeSelector }} - nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.replica.nodeSelector "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.replica.tolerations }} - tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.replica.tolerations "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.replica.topologySpreadConstraints }} - topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.replica.topologySpreadConstraints "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.replica.shareProcessNamespace }} - shareProcessNamespace: {{ .Values.replica.shareProcessNamespace }} - {{- end }} - {{- if .Values.replica.schedulerName }} - schedulerName: {{ .Values.replica.schedulerName | quote }} - {{- end }} - {{- if .Values.replica.dnsPolicy }} - dnsPolicy: {{ .Values.replica.dnsPolicy }} - {{- end }} - {{- if .Values.replica.dnsConfig }} - dnsConfig: {{- include "common.tplvalues.render" (dict "value" .Values.replica.dnsConfig "context" $) | nindent 8 }} - {{- end }} - enableServiceLinks: {{ .Values.replica.enableServiceLinks }} - terminationGracePeriodSeconds: {{ .Values.replica.terminationGracePeriodSeconds }} - containers: - - name: redis - image: {{ template "redis.image" . }} - imagePullPolicy: {{ .Values.image.pullPolicy | quote }} - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.replica.lifecycleHooks }} - lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.replica.lifecycleHooks "context" $) | nindent 12 }} - {{- end }} - {{- end }} - {{- if .Values.replica.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.replica.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} - {{- else if .Values.replica.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.replica.command "context" $) | nindent 12 }} - {{- else }} - command: - - /bin/bash - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} - {{- else if .Values.replica.args }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.replica.args "context" $) | nindent 12 }} - {{- else }} - args: - - -c - - /opt/bitnami/scripts/start-scripts/start-replica.sh - {{- end }} - env: - - name: BITNAMI_DEBUG - value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }} - - name: REDIS_REPLICATION_MODE - value: replica - - name: REDIS_MASTER_HOST - {{- if .Values.replica.externalMaster.enabled }} - value: {{ .Values.replica.externalMaster.host | quote }} - {{- else if and (eq (int64 .Values.master.count) 1) (eq .Values.master.kind "StatefulSet") }} - value: {{ template "common.names.fullname" . }}-master-0.{{ template "common.names.fullname" . }}-headless.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }} - {{- else }} - value: {{ template "common.names.fullname" . }}-master.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }} - {{- end }} - - name: REDIS_MASTER_PORT_NUMBER - {{- if .Values.replica.externalMaster.enabled }} - value: {{ .Values.replica.externalMaster.port | quote }} - {{- else }} - value: {{ .Values.master.containerPorts.redis | quote }} - {{- end }} - - name: ALLOW_EMPTY_PASSWORD - value: {{ ternary "no" "yes" .Values.auth.enabled | quote }} - {{- if .Values.auth.enabled }} - {{- if .Values.auth.usePasswordFiles }} - - name: REDIS_PASSWORD_FILE - value: "/opt/bitnami/redis/secrets/redis-password" - - name: REDIS_MASTER_PASSWORD_FILE - value: "/opt/bitnami/redis/secrets/redis-password" - {{- else }} - - name: REDIS_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "redis.secretName" . }} - key: {{ template "redis.secretPasswordKey" . }} - - name: REDIS_MASTER_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "redis.secretName" . }} - key: {{ template "redis.secretPasswordKey" . }} - {{- end }} - {{- end }} - - name: REDIS_TLS_ENABLED - value: {{ ternary "yes" "no" .Values.tls.enabled | quote }} - {{- if .Values.tls.enabled }} - - name: REDIS_TLS_PORT - value: {{ .Values.replica.containerPorts.redis | quote }} - - name: REDIS_TLS_AUTH_CLIENTS - value: {{ ternary "yes" "no" .Values.tls.authClients | quote }} - - name: REDIS_TLS_CERT_FILE - value: {{ template "redis.tlsCert" . }} - - name: REDIS_TLS_KEY_FILE - value: {{ template "redis.tlsCertKey" . }} - - name: REDIS_TLS_CA_FILE - value: {{ template "redis.tlsCACert" . }} - {{- if .Values.tls.dhParamsFilename }} - - name: REDIS_TLS_DH_PARAMS_FILE - value: {{ template "redis.tlsDHParams" . }} - {{- end }} - {{- else }} - - name: REDIS_PORT - value: {{ .Values.replica.containerPorts.redis | quote }} - {{- end }} - {{- if .Values.replica.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.replica.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - {{- if or .Values.replica.extraEnvVarsCM .Values.replica.extraEnvVarsSecret }} - envFrom: - {{- if .Values.replica.extraEnvVarsCM }} - - configMapRef: - name: {{ .Values.replica.extraEnvVarsCM }} - {{- end }} - {{- if .Values.replica.extraEnvVarsSecret }} - - secretRef: - name: {{ .Values.replica.extraEnvVarsSecret }} - {{- end }} - {{- end }} - ports: - - name: redis - containerPort: {{ .Values.replica.containerPorts.redis }} - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.replica.customStartupProbe }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.replica.customStartupProbe "context" $) | nindent 12 }} - {{- else if .Values.replica.startupProbe.enabled }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.replica.startupProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: redis - {{- end }} - {{- if .Values.replica.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.replica.customLivenessProbe "context" $) | nindent 12 }} - {{- else if .Values.replica.livenessProbe.enabled }} - livenessProbe: - initialDelaySeconds: {{ .Values.replica.livenessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.replica.livenessProbe.periodSeconds }} - timeoutSeconds: {{ add1 .Values.replica.livenessProbe.timeoutSeconds }} - successThreshold: {{ .Values.replica.livenessProbe.successThreshold }} - failureThreshold: {{ .Values.replica.livenessProbe.failureThreshold }} - exec: - command: - - sh - - -c - - /health/ping_liveness_local_and_master.sh {{ .Values.replica.livenessProbe.timeoutSeconds }} - {{- end }} - {{- if .Values.replica.customReadinessProbe }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.replica.customReadinessProbe "context" $) | nindent 12 }} - {{- else if .Values.replica.readinessProbe.enabled }} - readinessProbe: - initialDelaySeconds: {{ .Values.replica.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.replica.readinessProbe.periodSeconds }} - timeoutSeconds: {{ add1 .Values.replica.readinessProbe.timeoutSeconds }} - successThreshold: {{ .Values.replica.readinessProbe.successThreshold }} - failureThreshold: {{ .Values.replica.readinessProbe.failureThreshold }} - exec: - command: - - sh - - -c - - /health/ping_readiness_local_and_master.sh {{ .Values.replica.readinessProbe.timeoutSeconds }} - {{- end }} - {{- end }} - {{- if .Values.replica.resources }} - resources: {{- toYaml .Values.replica.resources | nindent 12 }} - {{- else if ne .Values.replica.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.replica.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: start-scripts - mountPath: /opt/bitnami/scripts/start-scripts - - name: health - mountPath: /health - {{- if .Values.auth.usePasswordFiles }} - - name: redis-password - mountPath: /opt/bitnami/redis/secrets/ - {{- end }} - - name: redis-data - mountPath: /data - {{- if .Values.replica.persistence.subPath }} - subPath: {{ .Values.replica.persistence.subPath }} - {{- else if .Values.replica.persistence.subPathExpr }} - subPathExpr: {{ .Values.replica.persistence.subPathExpr }} - {{- end }} - - name: config - mountPath: /opt/bitnami/redis/mounted-etc - - name: empty-dir - mountPath: /opt/bitnami/redis/etc - subPath: app-conf-dir - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - {{- if .Values.tls.enabled }} - - name: redis-certificates - mountPath: /opt/bitnami/redis/certs - readOnly: true - {{- end }} - {{- if .Values.replica.extraVolumeMounts }} - {{- include "common.tplvalues.render" ( dict "value" .Values.replica.extraVolumeMounts "context" $ ) | nindent 12 }} - {{- end }} - {{- if .Values.metrics.enabled }} - - name: metrics - image: {{ include "redis.metrics.image" . }} - imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} - {{- if .Values.metrics.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.metrics.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} - {{- else if .Values.metrics.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.command "context" $) | nindent 12 }} - {{- else }} - command: - - /bin/bash - - -c - - | - if [[ -f '/secrets/redis-password' ]]; then - export REDIS_PASSWORD=$(cat /secrets/redis-password) - fi - redis_exporter{{- range $key, $value := .Values.metrics.extraArgs }} --{{ $key }}={{ $value }}{{- end }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} - {{- end }} - env: - - name: REDIS_ALIAS - value: {{ template "common.names.fullname" . }} - - name: REDIS_EXPORTER_WEB_LISTEN_ADDRESS - value: {{ printf ":%v" .Values.metrics.containerPorts.http }} - {{- if .Values.auth.enabled }} - - name: REDIS_USER - value: default - {{- if (not .Values.auth.usePasswordFiles) }} - - name: REDIS_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "redis.secretName" . }} - key: {{ template "redis.secretPasswordKey" . }} - {{- end }} - {{- end }} - {{- if .Values.tls.enabled }} - - name: REDIS_ADDR - value: rediss://{{ .Values.metrics.redisTargetHost }}:{{ .Values.replica.containerPorts.redis }} - {{- if .Values.tls.authClients }} - - name: REDIS_EXPORTER_TLS_CLIENT_KEY_FILE - value: {{ template "redis.tlsCertKey" . }} - - name: REDIS_EXPORTER_TLS_CLIENT_CERT_FILE - value: {{ template "redis.tlsCert" . }} - {{- end }} - - name: REDIS_EXPORTER_TLS_CA_CERT_FILE - value: {{ template "redis.tlsCACert" . }} - {{- end }} - {{- if .Values.metrics.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.metrics.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - ports: - - name: metrics - containerPort: {{ .Values.metrics.containerPorts.http }} - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.metrics.customStartupProbe }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customStartupProbe "context" $) | nindent 12 }} - {{- else if .Values.metrics.startupProbe.enabled }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.startupProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: metrics - {{- end }} - {{- if .Values.metrics.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customLivenessProbe "context" $) | nindent 12 }} - {{- else if .Values.metrics.livenessProbe.enabled }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.livenessProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: metrics - {{- end }} - {{- if .Values.metrics.customReadinessProbe }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customReadinessProbe "context" $) | nindent 12 }} - {{- else if .Values.metrics.readinessProbe.enabled }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.readinessProbe "enabled") "context" $) | nindent 12 }} - httpGet: - path: / - port: metrics - {{- end }} - {{- end }} - {{- if .Values.metrics.resources }} - resources: {{- toYaml .Values.metrics.resources | nindent 12 }} - {{- else if ne .Values.metrics.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.metrics.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - {{- if .Values.auth.usePasswordFiles }} - - name: redis-password - mountPath: /secrets/ - {{- end }} - {{- if .Values.tls.enabled }} - - name: redis-certificates - mountPath: /opt/bitnami/redis/certs - readOnly: true - {{- end }} - {{- if .Values.metrics.extraVolumeMounts }} - {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.extraVolumeMounts "context" $ ) | nindent 12 }} - {{- end }} - {{- end }} - {{- if .Values.replica.sidecars }} - {{- include "common.tplvalues.render" (dict "value" .Values.replica.sidecars "context" $) | nindent 8 }} - {{- end }} - {{- $needsVolumePermissions := and .Values.volumePermissions.enabled .Values.replica.persistence.enabled .Values.replica.podSecurityContext.enabled .Values.replica.containerSecurityContext.enabled }} - {{- if or .Values.replica.initContainers $needsVolumePermissions .Values.sysctl.enabled }} - initContainers: - {{- if .Values.replica.initContainers }} - {{- include "common.tplvalues.render" (dict "value" .Values.replica.initContainers "context" $) | nindent 8 }} - {{- end }} - {{- if $needsVolumePermissions }} - - name: volume-permissions - image: {{ include "redis.volumePermissions.image" . }} - imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} - command: - - /bin/bash - - -ec - - | - {{- if eq ( toString ( .Values.volumePermissions.containerSecurityContext.runAsUser )) "auto" }} - chown -R `id -u`:`id -G | cut -d " " -f2` {{ .Values.replica.persistence.path }} - {{- else }} - chown -R {{ .Values.replica.containerSecurityContext.runAsUser }}:{{ .Values.replica.podSecurityContext.fsGroup }} {{ .Values.replica.persistence.path }} - {{- end }} - {{- if eq ( toString ( .Values.volumePermissions.containerSecurityContext.runAsUser )) "auto" }} - securityContext: {{- omit .Values.volumePermissions.containerSecurityContext "runAsUser" | toYaml | nindent 12 }} - {{- else }} - securityContext: {{- .Values.volumePermissions.containerSecurityContext | toYaml | nindent 12 }} - {{- end }} - {{- if .Values.volumePermissions.extraEnvVars }} - env: - {{- include "common.tplvalues.render" (dict "value" .Values.volumePermissions.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.volumePermissions.resources }} - resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} - {{- else if ne .Values.volumePermissions.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.volumePermissions.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - - name: redis-data - mountPath: {{ .Values.replica.persistence.path }} - {{- if .Values.replica.persistence.subPath }} - subPath: {{ .Values.replica.persistence.subPath }} - {{- else if .Values.replica.persistence.subPathExpr }} - subPathExpr: {{ .Values.replica.persistence.subPathExpr }} - {{- end }} - {{- end }} - {{- if .Values.sysctl.enabled }} - - name: init-sysctl - image: {{ include "redis.sysctl.image" . }} - imagePullPolicy: {{ default "" .Values.sysctl.image.pullPolicy | quote }} - securityContext: - privileged: true - runAsUser: 0 - {{- if .Values.sysctl.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.sysctl.command "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.sysctl.resources }} - resources: {{- toYaml .Values.sysctl.resources | nindent 12 }} - {{- else if ne .Values.sysctl.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.sysctl.resourcesPreset) | nindent 12 }} - {{- end }} - {{- if .Values.sysctl.mountHostSys }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - - name: host-sys - mountPath: /host-sys - {{- end }} - {{- end }} - {{- end }} - volumes: - - name: start-scripts - configMap: - name: {{ printf "%s-scripts" (include "common.names.fullname" .) }} - defaultMode: 0755 - - name: health - configMap: - name: {{ printf "%s-health" (include "common.names.fullname" .) }} - defaultMode: 0755 - {{- if .Values.auth.usePasswordFiles }} - - name: redis-password - {{ if .Values.auth.usePasswordFileFromSecret }} - secret: - secretName: {{ template "redis.secretName" . }} - items: - - key: {{ template "redis.secretPasswordKey" . }} - path: redis-password - {{- else }} - emptyDir: {} - {{- end }} - {{- end }} - - name: config - configMap: - name: {{ include "redis.configmapName" . }} - {{- if .Values.sysctl.mountHostSys }} - - name: host-sys - hostPath: - path: /sys - {{- end }} - - name: empty-dir - {{- if or .Values.replica.persistence.medium .Values.replica.persistence.sizeLimit }} - emptyDir: - {{- if .Values.replica.persistence.medium }} - medium: {{ .Values.replica.persistence.medium | quote }} - {{- end }} - {{- if .Values.replica.persistence.sizeLimit }} - sizeLimit: {{ .Values.replica.persistence.sizeLimit | quote }} - {{- end }} - {{- else }} - emptyDir: {} - {{- end }} - {{- if .Values.tls.enabled }} - - name: redis-certificates - secret: - secretName: {{ include "redis.tlsSecretName" . }} - defaultMode: 256 - {{- end }} - {{- if .Values.replica.extraVolumes }} - {{- include "common.tplvalues.render" ( dict "value" .Values.replica.extraVolumes "context" $ ) | nindent 8 }} - {{- end }} - {{- if .Values.metrics.extraVolumes }} - {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.extraVolumes "context" $ ) | nindent 8 }} - {{- end }} - {{- if or (not .Values.replica.persistence.enabled) (not (eq .Values.replica.kind "StatefulSet")) }} - - name: redis-data - {{- if or .Values.replica.persistence.medium .Values.replica.persistence.sizeLimit }} - emptyDir: - {{- if .Values.replica.persistence.medium }} - medium: {{ .Values.replica.persistence.medium | quote }} - {{- end }} - {{- if .Values.replica.persistence.sizeLimit }} - sizeLimit: {{ .Values.replica.persistence.sizeLimit | quote }} - {{- end }} - {{- else }} - emptyDir: {} - {{- end }} - {{- else if .Values.replica.persistence.existingClaim }} - - name: redis-data - persistentVolumeClaim: - claimName: {{ printf "%s" (tpl .Values.replica.persistence.existingClaim .) }} - {{- else }} - {{- if .Values.replica.persistentVolumeClaimRetentionPolicy.enabled }} - persistentVolumeClaimRetentionPolicy: - whenDeleted: {{ .Values.replica.persistentVolumeClaimRetentionPolicy.whenDeleted }} - whenScaled: {{ .Values.replica.persistentVolumeClaimRetentionPolicy.whenScaled }} - {{- end }} - volumeClaimTemplates: - - apiVersion: v1 - kind: PersistentVolumeClaim - metadata: - name: redis-data - {{- $claimLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.master.persistence.labels .Values.commonLabels ) "context" . ) }} - labels: {{- include "common.labels.matchLabels" ( dict "customLabels" $claimLabels "context" $ ) | nindent 10 }} - app.kubernetes.io/component: replica - {{- if .Values.replica.persistence.annotations }} - annotations: {{- toYaml .Values.replica.persistence.annotations | nindent 10 }} - {{- end }} - spec: - accessModes: - {{- range .Values.replica.persistence.accessModes }} - - {{ . | quote }} - {{- end }} - resources: - requests: - storage: {{ .Values.replica.persistence.size | quote }} - {{- if .Values.replica.persistence.selector }} - selector: {{- include "common.tplvalues.render" (dict "value" .Values.replica.persistence.selector "context" $) | nindent 10 }} - {{- end }} - {{- if .Values.replica.persistence.dataSource }} - dataSource: {{- include "common.tplvalues.render" (dict "value" .Values.replica.persistence.dataSource "context" $) | nindent 10 }} - {{- end }} - {{- include "common.storage.class" (dict "persistence" .Values.replica.persistence "global" .Values.global) | nindent 8 }} - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/replicas/hpa.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/replicas/hpa.yaml deleted file mode 100644 index 85adf724..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/replicas/hpa.yaml +++ /dev/null @@ -1,49 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.replica.autoscaling.enabled (not .Values.sentinel.enabled) }} -apiVersion: {{ include "common.capabilities.hpa.apiVersion" ( dict "context" $ ) }} -kind: HorizontalPodAutoscaler -metadata: - name: {{ printf "%s-replicas" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: replica - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - scaleTargetRef: - apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} - kind: StatefulSet - name: {{ printf "%s-replicas" (include "common.names.fullname" .) }} - minReplicas: {{ .Values.replica.autoscaling.minReplicas }} - maxReplicas: {{ .Values.replica.autoscaling.maxReplicas }} - metrics: - {{- if .Values.replica.autoscaling.targetCPU }} - - type: Resource - resource: - name: cpu - {{- if semverCompare "<1.23-0" (include "common.capabilities.kubeVersion" .) }} - targetAverageUtilization: {{ .Values.replica.autoscaling.targetCPU }} - {{- else }} - target: - type: Utilization - averageUtilization: {{ .Values.replica.autoscaling.targetCPU }} - {{- end }} - {{- end }} - {{- if .Values.replica.autoscaling.targetMemory }} - - type: Resource - resource: - name: memory - {{- if semverCompare "<1.23-0" (include "common.capabilities.kubeVersion" .) }} - targetAverageUtilization: {{ .Values.replica.autoscaling.targetMemory }} - {{- else }} - target: - type: Utilization - averageUtilization: {{ .Values.replica.autoscaling.targetMemory }} - {{- end }} - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/replicas/pdb.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/replicas/pdb.yaml deleted file mode 100644 index d7b777b5..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/replicas/pdb.yaml +++ /dev/null @@ -1,28 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- $pdb := coalesce .Values.pdb .Values.replica.pdb }} -{{- if and (eq .Values.architecture "replication") (not .Values.sentinel.enabled) $pdb.create }} -apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} -kind: PodDisruptionBudget -metadata: - name: {{ printf "%s-replicas" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: replica - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - {{- if $pdb.minAvailable }} - minAvailable: {{ $pdb.minAvailable }} - {{- end }} - {{- if or $pdb.maxUnavailable (not $pdb.minAvailable) }} - maxUnavailable: {{ $pdb.maxUnavailable | default 1 }} - {{- end }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: replica -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/replicas/service.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/replicas/service.yaml deleted file mode 100644 index ebb2a4fa..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/replicas/service.yaml +++ /dev/null @@ -1,59 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and (eq .Values.architecture "replication") (not .Values.sentinel.enabled) }} -apiVersion: v1 -kind: Service -metadata: - name: {{ printf "%s-replicas" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: replica - {{- if or .Values.replica.service.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.replica.service.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -spec: - type: {{ .Values.replica.service.type }} - {{- if or (eq .Values.replica.service.type "LoadBalancer") (eq .Values.replica.service.type "NodePort") }} - externalTrafficPolicy: {{ .Values.replica.service.externalTrafficPolicy | quote }} - {{- end }} - {{- if (semverCompare ">=1.22-0" (include "common.capabilities.kubeVersion" .)) }} - internalTrafficPolicy: {{ .Values.replica.service.internalTrafficPolicy }} - {{- end }} - {{- if and (eq .Values.replica.service.type "LoadBalancer") (not (empty .Values.replica.service.loadBalancerIP)) }} - loadBalancerIP: {{ .Values.replica.service.loadBalancerIP }} - {{- end }} - {{- if and (eq .Values.replica.service.type "LoadBalancer") .Values.replica.service.loadBalancerClass }} - loadBalancerClass: {{ .Values.replica.service.loadBalancerClass }} - {{- end }} - {{- if and (eq .Values.replica.service.type "LoadBalancer") (not (empty .Values.replica.service.loadBalancerSourceRanges)) }} - loadBalancerSourceRanges: {{ toYaml .Values.replica.service.loadBalancerSourceRanges | nindent 4 }} - {{- end }} - {{- if and .Values.replica.service.clusterIP (eq .Values.replica.service.type "ClusterIP") }} - clusterIP: {{ .Values.replica.service.clusterIP }} - {{- end }} - {{- if .Values.replica.service.sessionAffinity }} - sessionAffinity: {{ .Values.replica.service.sessionAffinity }} - {{- end }} - {{- if .Values.replica.service.sessionAffinityConfig }} - sessionAffinityConfig: {{- include "common.tplvalues.render" (dict "value" .Values.replica.service.sessionAffinityConfig "context" $) | nindent 4 }} - {{- end }} - ports: - - name: tcp-redis - port: {{ .Values.replica.service.ports.redis }} - targetPort: redis - {{- if and (or (eq .Values.replica.service.type "NodePort") (eq .Values.replica.service.type "LoadBalancer")) .Values.replica.service.nodePorts.redis}} - nodePort: {{ .Values.replica.service.nodePorts.redis}} - {{- else if eq .Values.replica.service.type "ClusterIP" }} - nodePort: null - {{- end }} - {{- if .Values.replica.service.extraPorts }} - {{- include "common.tplvalues.render" (dict "value" .Values.replica.service.extraPorts "context" $) | nindent 4 }} - {{- end }} - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.replica.podLabels .Values.commonLabels ) "context" . ) }} - selector: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: replica -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/replicas/serviceaccount.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/replicas/serviceaccount.yaml deleted file mode 100644 index 6cf3411b..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/replicas/serviceaccount.yaml +++ /dev/null @@ -1,18 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.replica.serviceAccount.create (eq .Values.architecture "replication") (not .Values.sentinel.enabled) }} -apiVersion: v1 -kind: ServiceAccount -automountServiceAccountToken: {{ .Values.replica.serviceAccount.automountServiceAccountToken }} -metadata: - name: {{ template "redis.replicaServiceAccountName" . }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if or .Values.replica.serviceAccount.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.replica.serviceAccount.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/role.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/role.yaml deleted file mode 100644 index 54a2b1bd..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/role.yaml +++ /dev/null @@ -1,34 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.rbac.create }} -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: Role -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -rules: - {{- if and (include "common.capabilities.psp.supported" .) .Values.podSecurityPolicy.enabled }} - - apiGroups: - - '{{ template "podSecurityPolicy.apiGroup" . }}' - resources: - - 'podsecuritypolicies' - verbs: - - 'use' - resourceNames: [{{ printf "%s-master" (include "common.names.fullname" .) }}] - {{- end }} - {{- if and .Values.sentinel.enabled (or .Values.sentinel.masterService.enabled .Values.sentinel.service.createMaster) }} - - apiGroups: [""] - resources: ["pods"] - verbs: ["list", "patch"] - {{- end -}} - {{- if .Values.rbac.rules }} - {{- include "common.tplvalues.render" ( dict "value" .Values.rbac.rules "context" $ ) | nindent 2 }} - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/rolebinding.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/rolebinding.yaml deleted file mode 100644 index a164289a..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/rolebinding.yaml +++ /dev/null @@ -1,23 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.rbac.create }} -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: RoleBinding -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: {{ template "common.names.fullname" . }} -subjects: - - kind: ServiceAccount - name: {{ template "redis.serviceAccountName" . }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/scripts-configmap.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/scripts-configmap.yaml deleted file mode 100644 index acb04424..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/scripts-configmap.yaml +++ /dev/null @@ -1,799 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ printf "%s-scripts" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -data: -{{- if and (eq .Values.architecture "replication") .Values.sentinel.enabled }} - start-node.sh: | - #!/bin/bash - - . /opt/bitnami/scripts/libos.sh - . /opt/bitnami/scripts/liblog.sh - . /opt/bitnami/scripts/libvalidations.sh - - get_port() { - hostname="$1" - type="$2" - - port_var=$(echo "${hostname^^}_SERVICE_PORT_$type" | sed "s/-/_/g") - port=${!port_var} - - if [ -z "$port" ]; then - case $type in - "SENTINEL") - echo {{ .Values.sentinel.containerPorts.sentinel }} - ;; - "REDIS") - echo {{ .Values.master.containerPorts.redis }} - ;; - esac - else - echo $port - fi - } - - get_full_hostname() { - hostname="$1" - - {{- if .Values.useExternalDNS.enabled }} - full_hostname="${hostname}.{{- include "redis.externalDNS.suffix" . }}" - {{- else if eq .Values.sentinel.service.type "NodePort" }} - full_hostname="${hostname}.{{- include "common.names.namespace" . }}" - {{- else }} - full_hostname="${hostname}.${HEADLESS_SERVICE}" - {{- end }} - - {{- if .Values.useHostnames }} - echo "${full_hostname}" - {{- else }} - retry_count=0 - until getent hosts "${full_hostname}" | awk '{ print $1; exit }' | grep .; do - if [[ $retry_count -lt {{ .Values.nameResolutionThreshold }} ]]; then - sleep {{ .Values.nameResolutionTimeout }} - else - error "IP address for ${full_hostname} not found" - exit 1 - fi - ((retry_count++)) - done - {{- end }} - } - - REDISPORT=$(get_port "$HOSTNAME" "REDIS") - - HEADLESS_SERVICE="{{ template "common.names.fullname" . }}-headless.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }}" - - if [ -n "$REDIS_EXTERNAL_MASTER_HOST" ]; then - REDIS_SERVICE="$REDIS_EXTERNAL_MASTER_HOST" - else - REDIS_SERVICE="{{ template "common.names.fullname" . }}.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }}" - fi - - SENTINEL_SERVICE_PORT=$(get_port "{{ include "common.names.fullname" . }}" "SENTINEL") - validate_quorum() { - if is_boolean_yes "$REDIS_TLS_ENABLED"; then - quorum_info_command="{{- if and .Values.auth.enabled .Values.auth.sentinel }}REDISCLI_AUTH="\$REDIS_PASSWORD" {{ end }}redis-cli -h $REDIS_SERVICE -p $SENTINEL_SERVICE_PORT --tls --cert ${REDIS_TLS_CERT_FILE} --key ${REDIS_TLS_KEY_FILE} --cacert ${REDIS_TLS_CA_FILE} sentinel master {{ .Values.sentinel.masterSet }}" - else - quorum_info_command="{{- if and .Values.auth.enabled .Values.auth.sentinel }}REDISCLI_AUTH="\$REDIS_PASSWORD" {{ end }}redis-cli -h $REDIS_SERVICE -p $SENTINEL_SERVICE_PORT sentinel master {{ .Values.sentinel.masterSet }}" - fi - info "about to run the command: $quorum_info_command" - eval $quorum_info_command | grep -Fq "s_down" - } - - trigger_manual_failover() { - if is_boolean_yes "$REDIS_TLS_ENABLED"; then - failover_command="{{- if and .Values.auth.enabled .Values.auth.sentinel }}REDISCLI_AUTH="\$REDIS_PASSWORD" {{ end }}redis-cli -h $REDIS_SERVICE -p $SENTINEL_SERVICE_PORT --tls --cert ${REDIS_TLS_CERT_FILE} --key ${REDIS_TLS_KEY_FILE} --cacert ${REDIS_TLS_CA_FILE} sentinel failover {{ .Values.sentinel.masterSet }}" - else - failover_command="{{- if and .Values.auth.enabled .Values.auth.sentinel }}REDISCLI_AUTH="\$REDIS_PASSWORD" {{ end }}redis-cli -h $REDIS_SERVICE -p $SENTINEL_SERVICE_PORT sentinel failover {{ .Values.sentinel.masterSet }}" - fi - - info "about to run the command: $failover_command" - eval $failover_command - } - - get_sentinel_master_info() { - if is_boolean_yes "$REDIS_TLS_ENABLED"; then - sentinel_info_command="{{- if and .Values.auth.enabled .Values.auth.sentinel }}REDISCLI_AUTH="\$REDIS_PASSWORD" {{ end }}timeout {{ .Values.sentinel.getMasterTimeout }} redis-cli -h $REDIS_SERVICE -p $SENTINEL_SERVICE_PORT --tls --cert ${REDIS_TLS_CERT_FILE} --key ${REDIS_TLS_KEY_FILE} --cacert ${REDIS_TLS_CA_FILE} sentinel get-master-addr-by-name {{ .Values.sentinel.masterSet }}" - else - sentinel_info_command="{{- if and .Values.auth.enabled .Values.auth.sentinel }}REDISCLI_AUTH="\$REDIS_PASSWORD" {{ end }}timeout {{ .Values.sentinel.getMasterTimeout }} redis-cli -h $REDIS_SERVICE -p $SENTINEL_SERVICE_PORT sentinel get-master-addr-by-name {{ .Values.sentinel.masterSet }}" - fi - - info "about to run the command: $sentinel_info_command" - retry_while "eval $sentinel_info_command" 2 5 - } - - {{- if and .Values.replica.containerSecurityContext.runAsUser (eq (.Values.replica.containerSecurityContext.runAsUser | int) 0) }} - useradd redis - chown -R redis {{ .Values.replica.persistence.path }} - {{- end }} - - [[ -f $REDIS_PASSWORD_FILE ]] && export REDIS_PASSWORD="$(< "${REDIS_PASSWORD_FILE}")" - [[ -f $REDIS_MASTER_PASSWORD_FILE ]] && export REDIS_MASTER_PASSWORD="$(< "${REDIS_MASTER_PASSWORD_FILE}")" - - # check if there is a master - master_in_persisted_conf="$(get_full_hostname "$HOSTNAME")" - master_port_in_persisted_conf="$REDIS_MASTER_PORT_NUMBER" - master_in_sentinel="$(get_sentinel_master_info)" - redisRetVal=$? - - if [[ -f /opt/bitnami/redis-sentinel/etc/sentinel.conf ]]; then - master_in_persisted_conf="$(awk '/monitor/ {print $4}' /opt/bitnami/redis-sentinel/etc/sentinel.conf)" - master_port_in_persisted_conf="$(awk '/monitor/ {print $5}' /opt/bitnami/redis-sentinel/etc/sentinel.conf)" - info "Found previous master ${master_in_persisted_conf}:${master_port_in_persisted_conf} in /opt/bitnami/redis-sentinel/etc/sentinel.conf" - debug "$(cat /opt/bitnami/redis-sentinel/etc/sentinel.conf | grep monitor)" - fi - - if [[ $redisRetVal -ne 0 ]]; then - if [[ "$master_in_persisted_conf" == "$(get_full_hostname "$HOSTNAME")" ]]; then - # Case 1: No active sentinel and in previous sentinel.conf we were the master --> MASTER - info "Configuring the node as master" - export REDIS_REPLICATION_MODE="master" - else - # Case 2: No active sentinel and in previous sentinel.conf we were not master --> REPLICA - info "Configuring the node as replica" - export REDIS_REPLICATION_MODE="replica" - REDIS_MASTER_HOST=${master_in_persisted_conf} - REDIS_MASTER_PORT_NUMBER=${master_port_in_persisted_conf} - fi - else - # Fetches current master's host and port - REDIS_SENTINEL_INFO=($(get_sentinel_master_info)) - info "Current master: REDIS_SENTINEL_INFO=(${REDIS_SENTINEL_INFO[0]},${REDIS_SENTINEL_INFO[1]})" - REDIS_MASTER_HOST=${REDIS_SENTINEL_INFO[0]} - REDIS_MASTER_PORT_NUMBER=${REDIS_SENTINEL_INFO[1]} - - if [[ "$REDIS_MASTER_HOST" == "$(get_full_hostname "$HOSTNAME")" ]]; then - # Case 3: Active sentinel and master it is this node --> MASTER - info "Configuring the node as master" - export REDIS_REPLICATION_MODE="master" - else - # Case 4: Active sentinel and master is not this node --> REPLICA - info "Configuring the node as replica" - export REDIS_REPLICATION_MODE="replica" - - {{- if and .Values.sentinel.automateClusterRecovery (le (int .Values.sentinel.downAfterMilliseconds) 2000) }} - retry_count=1 - while validate_quorum - do - info "sleeping, waiting for Redis master to come up" - sleep 1s - if ! ((retry_count % 11)); then - info "Trying to manually failover" - failover_result=$(trigger_manual_failover) - - debug "Failover result: $failover_result" - fi - - ((retry_count+=1)) - done - info "Redis master is up now" - {{- end }} - fi - fi - - if [[ -n "$REDIS_EXTERNAL_MASTER_HOST" ]]; then - REDIS_MASTER_HOST="$REDIS_EXTERNAL_MASTER_HOST" - REDIS_MASTER_PORT_NUMBER="${REDIS_EXTERNAL_MASTER_PORT}" - fi - - if [[ -f /opt/bitnami/redis/mounted-etc/replica.conf ]];then - cp /opt/bitnami/redis/mounted-etc/replica.conf /opt/bitnami/redis/etc/replica.conf - fi - - if [[ -f /opt/bitnami/redis/mounted-etc/redis.conf ]];then - cp /opt/bitnami/redis/mounted-etc/redis.conf /opt/bitnami/redis/etc/redis.conf - fi - - echo "" >> /opt/bitnami/redis/etc/replica.conf - echo "replica-announce-port $REDISPORT" >> /opt/bitnami/redis/etc/replica.conf - echo "replica-announce-ip $(get_full_hostname "$HOSTNAME")" >> /opt/bitnami/redis/etc/replica.conf - - {{- if .Values.tls.enabled }} - ARGS=("--port" "0") - ARGS+=("--tls-port" "${REDIS_TLS_PORT}") - ARGS+=("--tls-cert-file" "${REDIS_TLS_CERT_FILE}") - ARGS+=("--tls-key-file" "${REDIS_TLS_KEY_FILE}") - ARGS+=("--tls-ca-cert-file" "${REDIS_TLS_CA_FILE}") - ARGS+=("--tls-auth-clients" "${REDIS_TLS_AUTH_CLIENTS}") - ARGS+=("--tls-replication" "yes") - {{- if .Values.tls.dhParamsFilename }} - ARGS+=("--tls-dh-params-file" "${REDIS_TLS_DH_PARAMS_FILE}") - {{- end }} - {{- else }} - ARGS=("--port" "${REDIS_PORT}") - {{- end }} - - if [[ "$REDIS_REPLICATION_MODE" = "slave" ]] || [[ "$REDIS_REPLICATION_MODE" = "replica" ]]; then - ARGS+=("--replicaof" "${REDIS_MASTER_HOST}" "${REDIS_MASTER_PORT_NUMBER}") - fi - - {{- if .Values.auth.enabled }} - ARGS+=("--requirepass" "${REDIS_PASSWORD}") - ARGS+=("--masterauth" "${REDIS_MASTER_PASSWORD}") - {{- else }} - ARGS+=("--protected-mode" "no") - {{- end }} - ARGS+=("--include" "/opt/bitnami/redis/etc/replica.conf") - ARGS+=("--include" "/opt/bitnami/redis/etc/redis.conf") - {{- if .Values.replica.extraFlags }} - {{- range .Values.replica.extraFlags }} - ARGS+=({{ . | quote }}) - {{- end }} - {{- end }} - - {{- if .Values.replica.preExecCmds }} - {{- range $command := .Values.replica.preExecCmds }} - {{- $command | nindent 4 }} - {{- end }} - {{- end }} - - {{- if .Values.replica.command }} - exec {{ .Values.replica.command }} "${ARGS[@]}" - {{- else }} - exec redis-server "${ARGS[@]}" - {{- end }} - - start-sentinel.sh: | - #!/bin/bash - - . /opt/bitnami/scripts/libos.sh - . /opt/bitnami/scripts/libvalidations.sh - . /opt/bitnami/scripts/libfile.sh - - HEADLESS_SERVICE="{{ template "common.names.fullname" . }}-headless.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }}" - REDIS_SERVICE="{{ template "common.names.fullname" . }}.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }}" - - get_port() { - hostname="$1" - type="$2" - - port_var=$(echo "${hostname^^}_SERVICE_PORT_$type" | sed "s/-/_/g") - port=${!port_var} - - if [ -z "$port" ]; then - case $type in - "SENTINEL") - echo {{ .Values.sentinel.containerPorts.sentinel }} - ;; - "REDIS") - echo {{ .Values.master.containerPorts.redis }} - ;; - esac - else - echo $port - fi - } - - get_full_hostname() { - hostname="$1" - - {{- if .Values.useExternalDNS.enabled }} - full_hostname="${hostname}.{{- include "redis.externalDNS.suffix" . }}" - {{- else if eq .Values.sentinel.service.type "NodePort" }} - full_hostname="${hostname}.{{- include "common.names.namespace" . }}" - {{- else }} - full_hostname="${hostname}.${HEADLESS_SERVICE}" - {{- end }} - - {{- if .Values.useHostnames }} - echo "${full_hostname}" - {{- else }} - retry_count=0 - until getent hosts "${full_hostname}" | awk '{ print $1; exit }' | grep .; do - if [[ $retry_count -lt {{ .Values.nameResolutionThreshold }} ]]; then - sleep {{ .Values.nameResolutionTimeout }} - else - error "IP address for ${full_hostname} not found" - exit 1 - fi - ((retry_count++)) - done - {{- end }} - } - - SERVPORT=$(get_port "$HOSTNAME" "SENTINEL") - REDISPORT=$(get_port "$HOSTNAME" "REDIS") - SENTINEL_SERVICE_PORT=$(get_port "{{ include "common.names.fullname" . }}" "SENTINEL") - - sentinel_conf_set() { - local -r key="${1:?missing key}" - local value="${2:-}" - - # Sanitize inputs - value="${value//\\/\\\\}" - value="${value//&/\\&}" - value="${value//\?/\\?}" - [[ "$value" = "" ]] && value="\"$value\"" - - replace_in_file "/opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf" "^#*\s*${key} .*" "${key} ${value}" false - } - sentinel_conf_add() { - echo $'\n'"$@" >> "/opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf" - } - host_id() { - echo "$1" | openssl sha1 | awk '{print $2}' - } - get_sentinel_master_info() { - if is_boolean_yes "$REDIS_SENTINEL_TLS_ENABLED"; then - sentinel_info_command="{{- if and .Values.auth.enabled .Values.auth.sentinel }}REDISCLI_AUTH="\$REDIS_PASSWORD" {{ end }}timeout {{ .Values.sentinel.getMasterTimeout }} redis-cli -h $REDIS_SERVICE -p $SENTINEL_SERVICE_PORT --tls --cert ${REDIS_SENTINEL_TLS_CERT_FILE} --key ${REDIS_SENTINEL_TLS_KEY_FILE} --cacert ${REDIS_SENTINEL_TLS_CA_FILE} sentinel get-master-addr-by-name {{ .Values.sentinel.masterSet }}" - else - sentinel_info_command="{{- if and .Values.auth.enabled .Values.auth.sentinel }}REDISCLI_AUTH="\$REDIS_PASSWORD" {{ end }}timeout {{ .Values.sentinel.getMasterTimeout }} redis-cli -h $REDIS_SERVICE -p $SENTINEL_SERVICE_PORT sentinel get-master-addr-by-name {{ .Values.sentinel.masterSet }}" - fi - info "about to run the command: $sentinel_info_command" - retry_while "eval $sentinel_info_command" 2 5 - } - - [[ -f $REDIS_PASSWORD_FILE ]] && export REDIS_PASSWORD="$(< "${REDIS_PASSWORD_FILE}")" - - master_in_persisted_conf="$(get_full_hostname "$HOSTNAME")" - - if [[ -f /opt/bitnami/redis-sentinel/etc/sentinel.conf ]]; then - master_in_persisted_conf="$(awk '/monitor/ {print $4}' /opt/bitnami/redis-sentinel/etc/sentinel.conf)" - info "Found previous master $master_in_persisted_conf in /opt/bitnami/redis-sentinel/etc/sentinel.conf" - debug "$(cat /opt/bitnami/redis-sentinel/etc/sentinel.conf | grep monitor)" - fi - REDIS_SENTINEL_INFO=($(get_sentinel_master_info)) - if [ "$?" -eq "0" ]; then - # current master's host and port obtained from other Sentinel - info "printing REDIS_SENTINEL_INFO=(${REDIS_SENTINEL_INFO[0]},${REDIS_SENTINEL_INFO[1]})" - REDIS_MASTER_HOST=${REDIS_SENTINEL_INFO[0]} - REDIS_MASTER_PORT_NUMBER=${REDIS_SENTINEL_INFO[1]} - else - REDIS_MASTER_HOST="$master_in_persisted_conf" - REDIS_MASTER_PORT_NUMBER="$REDISPORT" - fi - if [[ "$REDIS_MASTER_HOST" == "$(get_full_hostname "$HOSTNAME")" ]]; then - export REDIS_REPLICATION_MODE="master" - else - export REDIS_REPLICATION_MODE="replica" - fi - - {{- if or .Values.sentinel.masterService.enabled .Values.sentinel.service.createMaster }} - if [[ "${REDIS_REPLICATION_MODE}" == "master" ]]; then - # Add isMaster label to master node for master service - echo "${REDIS_MASTER_HOST/.*}" > /etc/shared/current - fi - {{- end }} - - if [[ -n "$REDIS_EXTERNAL_MASTER_HOST" ]]; then - REDIS_MASTER_HOST="$REDIS_EXTERNAL_MASTER_HOST" - REDIS_MASTER_PORT_NUMBER="${REDIS_EXTERNAL_MASTER_PORT}" - fi - - # To prevent incomplete configuration and as the redis container accesses /opt/bitnami/redis-sentinel/etc/sentinel.conf - # as well, prepare the new config in `prepare-sentinel.conf` and move it atomically to the ultimate destination when it is complete. - cp /opt/bitnami/redis-sentinel/mounted-etc/sentinel.conf /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf - {{- if .Values.auth.enabled }} - printf "\nsentinel auth-pass %s %s" "{{ .Values.sentinel.masterSet }}" "$REDIS_PASSWORD" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf - {{- if and .Values.auth.enabled .Values.auth.sentinel }} - printf "\nrequirepass %s" "$REDIS_PASSWORD" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf - {{- end }} - {{- end }} - printf "\nsentinel myid %s" "$(host_id "$HOSTNAME")" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf - - if [[ -z "$REDIS_MASTER_HOST" ]] || [[ -z "$REDIS_MASTER_PORT_NUMBER" ]] - then - # Prevent incorrect configuration to be written to sentinel.conf - error "Redis master host is configured incorrectly (host: $REDIS_MASTER_HOST, port: $REDIS_MASTER_PORT_NUMBER)" - exit 1 - fi - - sentinel_conf_set "sentinel monitor" "{{ .Values.sentinel.masterSet }} "$REDIS_MASTER_HOST" "$REDIS_MASTER_PORT_NUMBER" {{ .Values.sentinel.quorum }}" - - add_known_sentinel() { - hostname="$1" - ip="$2" - - if [[ -n "$hostname" && -n "$ip" && "$hostname" != "$HOSTNAME" ]]; then - sentinel_conf_add "sentinel known-sentinel {{ .Values.sentinel.masterSet }} $(get_full_hostname "$hostname") $(get_port "$hostname" "SENTINEL") $(host_id "$hostname")" - fi - } - add_known_replica() { - hostname="$1" - ip="$2" - - if [[ -n "$ip" && "$(get_full_hostname "$hostname")" != "$REDIS_MASTER_HOST" ]]; then - sentinel_conf_add "sentinel known-replica {{ .Values.sentinel.masterSet }} $(get_full_hostname "$hostname") $(get_port "$hostname" "REDIS")" - fi - } - - # Add available hosts on the network as known replicas & sentinels - for node in $(seq 0 $(({{ .Values.replica.replicaCount }}-1))); do - hostname="{{ template "common.names.fullname" . }}-node-$node" - ip="$(getent hosts "$hostname.$HEADLESS_SERVICE" | awk '{ print $1 }')" - add_known_sentinel "$hostname" "$ip" - add_known_replica "$hostname" "$ip" - done - - echo "" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf - {{- if not (contains "sentinel announce-hostnames" .Values.sentinel.configuration) }} - echo "sentinel announce-hostnames yes" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf - {{- end }} - {{- if not (contains "sentinel resolve-hostnames" .Values.sentinel.configuration) }} - echo "sentinel resolve-hostnames yes" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf - {{- end }} - {{- if not (contains "sentinel announce-port" .Values.sentinel.configuration) }} - echo "sentinel announce-port $SERVPORT" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf - {{- end }} - {{- if not (contains "sentinel announce-ip" .Values.sentinel.configuration) }} - echo "sentinel announce-ip $(get_full_hostname "$HOSTNAME")" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf - {{- end }} - - {{- if .Values.tls.enabled }} - ARGS=("--port" "0") - ARGS+=("--tls-port" "${REDIS_SENTINEL_TLS_PORT_NUMBER}") - ARGS+=("--tls-cert-file" "${REDIS_SENTINEL_TLS_CERT_FILE}") - ARGS+=("--tls-key-file" "${REDIS_SENTINEL_TLS_KEY_FILE}") - ARGS+=("--tls-ca-cert-file" "${REDIS_SENTINEL_TLS_CA_FILE}") - ARGS+=("--tls-replication" "yes") - ARGS+=("--tls-auth-clients" "${REDIS_SENTINEL_TLS_AUTH_CLIENTS}") - {{- if .Values.tls.dhParamsFilename }} - ARGS+=("--tls-dh-params-file" "${REDIS_SENTINEL_TLS_DH_PARAMS_FILE}") - {{- end }} - {{- end }} - {{- if .Values.sentinel.preExecCmds }} - {{- range $command := .Values.sentinel.preExecCmds }} - {{- $command | nindent 4 }} - {{- end }} - {{- end }} - mv /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf /opt/bitnami/redis-sentinel/etc/sentinel.conf - exec redis-server /opt/bitnami/redis-sentinel/etc/sentinel.conf {{- if .Values.tls.enabled }} "${ARGS[@]}" {{- end }} --sentinel - prestop-sentinel.sh: | - #!/bin/bash - - . /opt/bitnami/scripts/libvalidations.sh - . /opt/bitnami/scripts/libos.sh - - HEADLESS_SERVICE="{{ template "common.names.fullname" . }}-headless.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }}" - - get_full_hostname() { - hostname="$1" - - {{- if .Values.useExternalDNS.enabled }} - full_hostname="${hostname}.{{- include "redis.externalDNS.suffix" . }}" - {{- else if eq .Values.sentinel.service.type "NodePort" }} - full_hostname="${hostname}.{{- include "common.names.namespace" . }}" - {{- else }} - full_hostname="${hostname}.${HEADLESS_SERVICE}" - {{- end }} - - {{- if .Values.useHostnames }} - echo "${full_hostname}" - {{- else }} - retry_count=0 - until getent hosts "${full_hostname}" | awk '{ print $1; exit }' | grep .; do - if [[ $retry_count -lt {{ .Values.nameResolutionThreshold }} ]]; then - sleep {{ .Values.nameResolutionTimeout }} - else - error "IP address for ${full_hostname} not found" - exit 1 - fi - ((retry_count++)) - done - {{- end }} - } - - run_sentinel_command() { - if is_boolean_yes "$REDIS_SENTINEL_TLS_ENABLED"; then - redis-cli -h "$REDIS_SERVICE" -p "$REDIS_SENTINEL_TLS_PORT_NUMBER" --tls --cert "$REDIS_SENTINEL_TLS_CERT_FILE" --key "$REDIS_SENTINEL_TLS_KEY_FILE" --cacert "$REDIS_SENTINEL_TLS_CA_FILE" sentinel "$@" - else - redis-cli -h "$REDIS_SERVICE" -p "$REDIS_SENTINEL_PORT" sentinel "$@" - fi - } - sentinel_failover_finished() { - REDIS_SENTINEL_INFO=($(run_sentinel_command get-master-addr-by-name "{{ .Values.sentinel.masterSet }}")) - REDIS_MASTER_HOST="${REDIS_SENTINEL_INFO[0]}" - [[ "$REDIS_MASTER_HOST" != "$(get_full_hostname $HOSTNAME)" ]] - } - - REDIS_SERVICE="{{ include "common.names.fullname" . }}.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }}" - - {{ if .Values.auth.sentinel -}} - # redis-cli automatically consumes credentials from the REDISCLI_AUTH variable - [[ -n "$REDIS_PASSWORD" ]] && export REDISCLI_AUTH="$REDIS_PASSWORD" - [[ -f "$REDIS_PASSWORD_FILE" ]] && export REDISCLI_AUTH="$(< "${REDIS_PASSWORD_FILE}")" - {{- end }} - - if ! sentinel_failover_finished; then - echo "I am the master pod and you are stopping me. Starting sentinel failover" - if retry_while "sentinel_failover_finished" "{{ sub .Values.sentinel.terminationGracePeriodSeconds 10 }}" 1; then - echo "Master has been successfuly failed over to a different pod." - exit 0 - else - echo "Master failover failed" - exit 1 - fi - else - exit 0 - fi - prestop-redis.sh: | - #!/bin/bash - - . /opt/bitnami/scripts/libvalidations.sh - . /opt/bitnami/scripts/libos.sh - - run_redis_command() { - if is_boolean_yes "$REDIS_TLS_ENABLED"; then - redis-cli -h 127.0.0.1 -p "$REDIS_TLS_PORT" --tls --cert "$REDIS_TLS_CERT_FILE" --key "$REDIS_TLS_KEY_FILE" --cacert "$REDIS_TLS_CA_FILE" "$@" - else - redis-cli -h 127.0.0.1 -p "$REDIS_PORT" "$@" - fi - } - is_master() { - REDIS_ROLE=$(run_redis_command role | head -1) - [[ "$REDIS_ROLE" == "master" ]] - } - - HEADLESS_SERVICE="{{ template "common.names.fullname" . }}-headless.{{- include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }}" - - get_full_hostname() { - hostname="$1" - - {{- if .Values.useExternalDNS.enabled }} - full_hostname="${hostname}.{{- include "redis.externalDNS.suffix" . }}" - {{- else if eq .Values.sentinel.service.type "NodePort" }} - full_hostname="${hostname}.{{- include "common.names.namespace" . }}" - {{- else }} - full_hostname="${hostname}.${HEADLESS_SERVICE}" - {{- end }} - - {{- if .Values.useHostnames }} - echo "${full_hostname}" - {{- else }} - retry_count=0 - until getent hosts "${full_hostname}" | awk '{ print $1; exit }' | grep .; do - if [[ $retry_count -lt {{ .Values.nameResolutionThreshold }} ]]; then - sleep {{ .Values.nameResolutionTimeout }} - else - error "IP address for ${full_hostname} not found" - exit 1 - fi - ((retry_count++)) - done - {{- end }} - } - - run_sentinel_command() { - if is_boolean_yes "$REDIS_SENTINEL_TLS_ENABLED"; then - {{ .Values.auth.sentinel | ternary "" "env -u REDISCLI_AUTH " -}} redis-cli -h "$REDIS_SERVICE" -p "$REDIS_SENTINEL_TLS_PORT_NUMBER" --tls --cert "$REDIS_SENTINEL_TLS_CERT_FILE" --key "$REDIS_SENTINEL_TLS_KEY_FILE" --cacert "$REDIS_SENTINEL_TLS_CA_FILE" sentinel "$@" - else - {{ .Values.auth.sentinel | ternary "" "env -u REDISCLI_AUTH " -}} redis-cli -h "$REDIS_SERVICE" -p "$REDIS_SENTINEL_PORT" sentinel "$@" - fi - } - sentinel_failover_finished() { - REDIS_SENTINEL_INFO=($(run_sentinel_command get-master-addr-by-name "{{ .Values.sentinel.masterSet }}")) - REDIS_MASTER_HOST="${REDIS_SENTINEL_INFO[0]}" - [[ "$REDIS_MASTER_HOST" != "$(get_full_hostname $HOSTNAME)" ]] - } - - REDIS_SERVICE="{{ include "common.names.fullname" . }}.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }}" - - # redis-cli automatically consumes credentials from the REDISCLI_AUTH variable - [[ -n "$REDIS_PASSWORD" ]] && export REDISCLI_AUTH="$REDIS_PASSWORD" - [[ -f "$REDIS_PASSWORD_FILE" ]] && export REDISCLI_AUTH="$(< "${REDIS_PASSWORD_FILE}")" - - - if is_master && ! sentinel_failover_finished; then - echo "I am the master pod and you are stopping me. Pausing client connections." - # Pausing client write connections to avoid data loss - run_redis_command CLIENT PAUSE "{{ mul (add 2 (sub .Values.sentinel.terminationGracePeriodSeconds 10)) 1000 }}" WRITE - - echo "Issuing failover" - # if I am the master, issue a command to failover once - run_sentinel_command failover "{{ .Values.sentinel.masterSet }}" - - {{- if .Values.sentinel.redisShutdownWaitFailover }} - echo "Waiting for sentinel to complete failover for up to {{ sub .Values.sentinel.terminationGracePeriodSeconds 10 }}s" - retry_while "sentinel_failover_finished" "{{ sub .Values.sentinel.terminationGracePeriodSeconds 10 }}" 1 - {{- end }} - else - exit 0 - fi - - {{- if or .Values.sentinel.masterService.enabled .Values.sentinel.service.createMaster }} - push-master-label.sh: | - #!/bin/bash - # https://download.redis.io/redis-stable/sentinel.conf - - echo "${6/.*}" > /etc/shared/current - echo "${4/.*}" > /etc/shared/previous - {{- end }} -{{- else }} - start-master.sh: | - #!/bin/bash - - [[ -f $REDIS_PASSWORD_FILE ]] && export REDIS_PASSWORD="$(< "${REDIS_PASSWORD_FILE}")" - {{- if and .Values.master.containerSecurityContext.runAsUser (eq (.Values.master.containerSecurityContext.runAsUser | int) 0) }} - useradd redis - chown -R redis {{ .Values.master.persistence.path }} - {{- end }} - if [[ -f /opt/bitnami/redis/mounted-etc/master.conf ]];then - cp /opt/bitnami/redis/mounted-etc/master.conf /opt/bitnami/redis/etc/master.conf - fi - if [[ -f /opt/bitnami/redis/mounted-etc/redis.conf ]];then - cp /opt/bitnami/redis/mounted-etc/redis.conf /opt/bitnami/redis/etc/redis.conf - fi - {{- if .Values.tls.enabled }} - ARGS=("--port" "0") - ARGS+=("--tls-port" "${REDIS_TLS_PORT}") - ARGS+=("--tls-cert-file" "${REDIS_TLS_CERT_FILE}") - ARGS+=("--tls-key-file" "${REDIS_TLS_KEY_FILE}") - ARGS+=("--tls-ca-cert-file" "${REDIS_TLS_CA_FILE}") - ARGS+=("--tls-auth-clients" "${REDIS_TLS_AUTH_CLIENTS}") - {{- if .Values.tls.dhParamsFilename }} - ARGS+=("--tls-dh-params-file" "${REDIS_TLS_DH_PARAMS_FILE}") - {{- end }} - {{- else }} - ARGS=("--port" "${REDIS_PORT}") - {{- end }} - {{- if .Values.auth.enabled }} - ARGS+=("--requirepass" "${REDIS_PASSWORD}") - ARGS+=("--masterauth" "${REDIS_PASSWORD}") - {{- else }} - ARGS+=("--protected-mode" "no") - {{- end }} - ARGS+=("--include" "/opt/bitnami/redis/etc/redis.conf") - ARGS+=("--include" "/opt/bitnami/redis/etc/master.conf") - {{- if .Values.master.extraFlags }} - {{- range .Values.master.extraFlags }} - ARGS+=({{ . | quote }}) - {{- end }} - {{- end }} - {{- if .Values.master.preExecCmds }} - {{- range $command := .Values.master.preExecCmds }} - {{- $command | nindent 4 }} - {{- end }} - {{- end }} - {{- if .Values.master.command }} - exec {{ .Values.master.command }} "${ARGS[@]}" - {{- else }} - exec redis-server "${ARGS[@]}" - {{- end }} - {{- if eq .Values.architecture "replication" }} - start-replica.sh: | - #!/bin/bash - - get_port() { - hostname="$1" - type="$2" - - port_var=$(echo "${hostname^^}_SERVICE_PORT_$type" | sed "s/-/_/g") - port=${!port_var} - - if [ -z "$port" ]; then - case $type in - "SENTINEL") - echo {{ .Values.sentinel.containerPorts.sentinel }} - ;; - "REDIS") - echo {{ .Values.master.containerPorts.redis }} - ;; - esac - else - echo $port - fi - } - - get_full_hostname() { - hostname="$1" - - {{- if .Values.useExternalDNS.enabled }} - full_hostname="${hostname}.{{- include "redis.externalDNS.suffix" . }}" - {{- else if eq .Values.sentinel.service.type "NodePort" }} - full_hostname="${hostname}.{{- include "common.names.namespace" . }}" - {{- else }} - full_hostname="${hostname}.${HEADLESS_SERVICE}" - {{- end }} - - {{- if .Values.useHostnames }} - echo "${full_hostname}" - {{- else }} - retry_count=0 - until getent hosts "${full_hostname}" | awk '{ print $1; exit }' | grep .; do - if [[ $retry_count -lt {{ .Values.nameResolutionThreshold }} ]]; then - sleep {{ .Values.nameResolutionTimeout }} - else - error "IP address for ${full_hostname} not found" - exit 1 - fi - ((retry_count++)) - done - {{- end }} - } - - REDISPORT=$(get_port "$HOSTNAME" "REDIS") - HEADLESS_SERVICE="{{ template "common.names.fullname" . }}-headless.{{ include "common.names.namespace" . }}.svc.{{ .Values.clusterDomain }}" - - [[ -f $REDIS_PASSWORD_FILE ]] && export REDIS_PASSWORD="$(< "${REDIS_PASSWORD_FILE}")" - [[ -f $REDIS_MASTER_PASSWORD_FILE ]] && export REDIS_MASTER_PASSWORD="$(< "${REDIS_MASTER_PASSWORD_FILE}")" - {{- if and .Values.replica.containerSecurityContext.runAsUser (eq (.Values.replica.containerSecurityContext.runAsUser | int) 0) }} - useradd redis - chown -R redis {{ .Values.replica.persistence.path }} - {{- end }} - if [[ -f /opt/bitnami/redis/mounted-etc/replica.conf ]];then - cp /opt/bitnami/redis/mounted-etc/replica.conf /opt/bitnami/redis/etc/replica.conf - fi - if [[ -f /opt/bitnami/redis/mounted-etc/redis.conf ]];then - cp /opt/bitnami/redis/mounted-etc/redis.conf /opt/bitnami/redis/etc/redis.conf - fi - - echo "" >> /opt/bitnami/redis/etc/replica.conf - echo "replica-announce-port $REDISPORT" >> /opt/bitnami/redis/etc/replica.conf - echo "replica-announce-ip $(get_full_hostname "$HOSTNAME")" >> /opt/bitnami/redis/etc/replica.conf - - {{- if .Values.tls.enabled }} - ARGS=("--port" "0") - ARGS+=("--tls-port" "${REDIS_TLS_PORT}") - ARGS+=("--tls-cert-file" "${REDIS_TLS_CERT_FILE}") - ARGS+=("--tls-key-file" "${REDIS_TLS_KEY_FILE}") - ARGS+=("--tls-ca-cert-file" "${REDIS_TLS_CA_FILE}") - ARGS+=("--tls-auth-clients" "${REDIS_TLS_AUTH_CLIENTS}") - ARGS+=("--tls-replication" "yes") - {{- if .Values.tls.dhParamsFilename }} - ARGS+=("--tls-dh-params-file" "${REDIS_TLS_DH_PARAMS_FILE}") - {{- end }} - {{- else }} - ARGS=("--port" "${REDIS_PORT}") - {{- end }} - ARGS+=("--replicaof" "${REDIS_MASTER_HOST}" "${REDIS_MASTER_PORT_NUMBER}") - {{- if .Values.auth.enabled }} - ARGS+=("--requirepass" "${REDIS_PASSWORD}") - ARGS+=("--masterauth" "${REDIS_MASTER_PASSWORD}") - {{- else }} - ARGS+=("--protected-mode" "no") - {{- end }} - ARGS+=("--include" "/opt/bitnami/redis/etc/redis.conf") - ARGS+=("--include" "/opt/bitnami/redis/etc/replica.conf") - {{- if .Values.replica.extraFlags }} - {{- range .Values.replica.extraFlags }} - ARGS+=({{ . | quote }}) - {{- end }} - {{- end }} - {{- if .Values.replica.preExecCmds }} - {{- range $command := .Values.replica.preExecCmds }} - {{- $command | nindent 4 }} - {{- end }} {{- end }} - {{- if .Values.replica.command }} - exec {{ .Values.replica.command }} "${ARGS[@]}" - {{- else }} - exec redis-server "${ARGS[@]}" - {{- end }} - {{- end }} -{{- end }} ---- -{{- if or .Values.sentinel.masterService.enabled .Values.sentinel.service.createMaster }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ printf "%s-kubectl-scripts" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -data: - update-master-label.sh: | - #!/bin/bash - while true; do - while [ ! -f "/etc/shared/current" ]; do - sleep 1 - done - echo "new master elected, updating label(s)..." - kubectl label pod --field-selector metadata.name="$(< "/etc/shared/current")" isMaster="true" --overwrite - kubectl label pod --field-selector metadata.name="$(< "/etc/shared/current")" app.kubernetes.io/role- - if [ -f /etc/shared/previous ]; then - kubectl label pod --field-selector metadata.name="$(< "/etc/shared/previous")" isMaster="false" --overwrite - fi - rm "/etc/shared/current" "/etc/shared/previous" - done -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/secret-svcbind.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/secret-svcbind.yaml deleted file mode 100644 index d3c74ff3..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/secret-svcbind.yaml +++ /dev/null @@ -1,37 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.serviceBindings.enabled }} -{{- $host := include "common.names.fullname" . }} -{{- if not .Values.sentinel.enabled }} -{{- $host = printf "%s-master" (include "common.names.fullname" .) }} -{{- end }} -{{- $port := print .Values.master.service.ports.redis }} -{{- if .Values.sentinel.enabled }} -{{- $port = print .Values.sentinel.service.ports.redis }} -{{- end }} -{{- $password := include "redis.password" . }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "common.names.fullname" . }}-svcbind - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -type: servicebinding.io/redis -data: - provider: {{ print "bitnami" | b64enc | quote }} - type: {{ print "redis" | b64enc | quote }} - host: {{ print $host | b64enc | quote }} - port: {{ print $port | b64enc | quote }} - password: {{ print $password | b64enc | quote }} - {{- if $password }} - uri: {{ printf "redis://:%s@%s:%s" $password $host $port | b64enc | quote }} - {{- else }} - uri: {{ printf "redis://%s:%s" $host $port | b64enc | quote }} - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/secret.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/secret.yaml deleted file mode 100644 index ec69fe25..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/secret.yaml +++ /dev/null @@ -1,25 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.auth.enabled (not .Values.auth.existingSecret) (or .Values.auth.usePasswordFileFromSecret (not .Values.auth.usePasswordFiles)) -}} -apiVersion: v1 -kind: Secret -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if or .Values.secretAnnotations .Values.commonAnnotations }} - annotations: - {{- if .Values.secretAnnotations }} - {{- include "common.tplvalues.render" ( dict "value" .Values.secretAnnotations "context" $ ) | nindent 4 }} - {{- end }} - {{- if .Values.commonAnnotations }} - {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} - {{- end }} -type: Opaque -data: - redis-password: {{ include "redis.password" . | b64enc | quote }} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/hpa.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/hpa.yaml deleted file mode 100644 index 54ec4857..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/hpa.yaml +++ /dev/null @@ -1,49 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.replica.autoscaling.enabled .Values.sentinel.enabled }} -apiVersion: {{ include "common.capabilities.hpa.apiVersion" ( dict "context" $ ) }} -kind: HorizontalPodAutoscaler -metadata: - name: {{ printf "%s-node" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: replica - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - scaleTargetRef: - apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} - kind: StatefulSet - name: {{ printf "%s-node" (include "common.names.fullname" .) }} - minReplicas: {{ .Values.replica.autoscaling.minReplicas }} - maxReplicas: {{ .Values.replica.autoscaling.maxReplicas }} - metrics: - {{- if .Values.replica.autoscaling.targetMemory }} - - type: Resource - resource: - name: memory - {{- if semverCompare "<1.23-0" (include "common.capabilities.kubeVersion" .) }} - targetAverageUtilization: {{ .Values.replica.autoscaling.targetMemory }} - {{- else }} - target: - type: Utilization - averageUtilization: {{ .Values.replica.autoscaling.targetMemory }} - {{- end }} - {{- end }} - {{- if .Values.replica.autoscaling.targetCPU }} - - type: Resource - resource: - name: cpu - {{- if semverCompare "<1.23-0" (include "common.capabilities.kubeVersion" .) }} - targetAverageUtilization: {{ .Values.replica.autoscaling.targetCPU }} - {{- else }} - target: - type: Utilization - averageUtilization: {{ .Values.replica.autoscaling.targetCPU }} - {{- end }} - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/node-services.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/node-services.yaml deleted file mode 100644 index 30ccad5e..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/node-services.yaml +++ /dev/null @@ -1,67 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and (eq .Values.architecture "replication") .Values.sentinel.enabled (eq .Values.sentinel.service.type "NodePort") (or .Release.IsUpgrade .Values.sentinel.service.nodePorts.redis ) }} - -{{- range $i := until (int .Values.replica.replicaCount) }} - -{{ $portsmap := (lookup "v1" "ConfigMap" (include "common.names.namespace" $) (printf "%s-%s" ( include "common.names.fullname" $ ) "ports-configmap")).data }} - -{{ $sentinelport := 0}} -{{ $redisport := 0}} -{{- if $portsmap }} -{{ $sentinelport = index $portsmap (printf "%s-node-%s-%s" (include "common.names.fullname" $) (toString $i) "sentinel") }} -{{ $redisport = index $portsmap (printf "%s-node-%s-%s" (include "common.names.fullname" $) (toString $i) "redis") }} -{{- else }} -{{- end }} -apiVersion: v1 -kind: Service -metadata: - name: {{ template "common.names.fullname" $ }}-node-{{ $i }} - namespace: {{ include "common.names.namespace" $ | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $.Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: node - {{- if or $.Values.commonAnnotations $.Values.sentinel.service.annotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list $.Values.sentinel.service.annotations $.Values.commonAnnotations ) "context" $ ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -spec: - type: NodePort - ports: - - name: sentinel - {{- if $.Values.sentinel.service.nodePorts.sentinel }} - nodePort: {{ (add $.Values.sentinel.service.nodePorts.sentinel $i 1) }} - port: {{ (add $.Values.sentinel.service.nodePorts.sentinel $i 1) }} - {{- else }} - nodePort: {{ $sentinelport }} - port: {{ $sentinelport }} - {{- end }} - protocol: TCP - targetPort: {{ $.Values.sentinel.containerPorts.sentinel }} - - name: redis - {{- if $.Values.sentinel.service.nodePorts.redis }} - nodePort: {{ (add $.Values.sentinel.service.nodePorts.redis $i 1) }} - port: {{ (add $.Values.sentinel.service.nodePorts.redis $i 1) }} - {{- else }} - nodePort: {{ $redisport }} - port: {{ $redisport }} - {{- end }} - protocol: TCP - targetPort: {{ $.Values.replica.containerPorts.redis }} - - name: sentinel-internal - nodePort: null - port: {{ $.Values.sentinel.containerPorts.sentinel }} - protocol: TCP - targetPort: {{ $.Values.sentinel.containerPorts.sentinel }} - - name: redis-internal - nodePort: null - port: {{ $.Values.replica.containerPorts.redis }} - protocol: TCP - targetPort: {{ $.Values.replica.containerPorts.redis }} - selector: - statefulset.kubernetes.io/pod-name: {{ template "common.names.fullname" $ }}-node-{{ $i }} ---- -{{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/pdb.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/pdb.yaml deleted file mode 100644 index 32ddad65..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/pdb.yaml +++ /dev/null @@ -1,27 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} -{{- $pdb := coalesce .Values.pdb .Values.replica.pdb }} -{{- if and (eq .Values.architecture "replication") .Values.sentinel.enabled $pdb.create }} -apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} -kind: PodDisruptionBudget -metadata: - name: {{ printf "%s-node" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: node - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - {{- if $pdb.minAvailable }} - minAvailable: {{ $pdb.minAvailable }} - {{- end }} - {{- if or $pdb.maxUnavailable (not $pdb.minAvailable) }} - maxUnavailable: {{ $pdb.maxUnavailable | default 1 }} - {{- end }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: node -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/ports-configmap.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/ports-configmap.yaml deleted file mode 100644 index d55f01a0..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/ports-configmap.yaml +++ /dev/null @@ -1,102 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and (eq .Values.architecture "replication") .Values.sentinel.enabled (eq .Values.sentinel.service.type "NodePort") (not .Values.sentinel.service.nodePorts.redis ) }} -{{- /* create a list to keep track of ports we choose to use */}} -{{ $chosenports := (list ) }} - -{{- /* Get list of all used nodeports */}} -{{ $usedports := (list ) }} -{{- range $index, $service := (lookup "v1" "Service" "" "").items }} - {{- range.spec.ports }} - {{- if .nodePort }} - {{- $usedports = (append $usedports .nodePort) }} - {{- end }} - {{- end }} -{{- end }} - -{{- /* -comments that start with # are rendered in the output when you debug, so you can less and search for them -Vars in the comment will be rendered out, so you can check their value this way. -https://helm.sh/docs/chart_best_practices/templates/#comments-yaml-comments-vs-template-comments - -remove the template comments and leave the yaml comments to help debug -*/}} - -{{- /* Sort the list */}} -{{ $usedports = $usedports | sortAlpha }} -#usedports {{ $usedports }} - -{{- /* How many nodeports per service do we want to create, except for the main service which is always two */}} -{{ $numberofPortsPerNodeService := 2 }} - -{{- /* for every nodeport we want, loop though the used ports to get an unused port */}} -{{- range $j := until (int (add (mul (int .Values.replica.replicaCount) $numberofPortsPerNodeService) 2)) }} - {{- /* #j={{ $j }} */}} - {{- $nodeport := (add $j 30000) }} - {{- $nodeportfound := false }} - {{- range $i := $usedports }} - {{- /* #i={{ $i }} - #nodeport={{ $nodeport }} - #usedports={{ $usedports }} */}} - {{- if and (has (toString $nodeport) $usedports) (eq $nodeportfound false) }} - {{- /* nodeport conflicts with in use */}} - {{- $nodeport = (add $nodeport 1) }} - {{- else if and ( has $nodeport $chosenports) (eq $nodeportfound false) }} - {{- /* nodeport already chosen, try another */}} - {{- $nodeport = (add $nodeport 1) }} - {{- else if (eq $nodeportfound false) }} - {{- /* nodeport free to use: not already claimed and not in use */}} - {{- /* select nodeport, and place into usedports */}} - {{- $chosenports = (append $chosenports $nodeport) }} - {{- $nodeportfound = true }} - {{- else }} - {{- /* nodeport has already been chosen and locked in, just work through the rest of the list to get to the next nodeport selection */}} - {{- end }} - {{- end }} - {{- if (eq $nodeportfound false) }} - {{- $chosenports = (append $chosenports $nodeport) }} - {{- end }} - -{{- end }} - -{{- /* print the usedports and chosenports for debugging */}} -#usedports {{ $usedports }} -#chosenports {{ $chosenports }}}} - ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "common.names.fullname" . }}-ports-configmap - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: - {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -data: -{{ $portsmap := (lookup "v1" "ConfigMap" (include "common.names.namespace" .) (printf "%s-%s" ( include "common.names.fullname" . ) "ports-configmap")).data }} -{{- if $portsmap }} -{{- /* configmap already exists, do not install again */ -}} - {{- range $name, $value := $portsmap }} - "{{ $name }}": "{{ $value }}" - {{- end }} -{{- else }} -{{- /* configmap being set for first time */ -}} - {{- range $index, $port := $chosenports }} - {{- $nodenumber := (floor (div $index 2)) }} - {{- if (eq $index 0) }} - "{{ template "common.names.fullname" $ }}-sentinel": "{{ $port }}" - {{- else if (eq $index 1) }} - "{{ template "common.names.fullname" $ }}-redis": "{{ $port }}" - {{- else if (eq (mod $index 2) 0) }} - "{{ template "common.names.fullname" $ }}-node-{{ (sub $nodenumber 1) }}-sentinel": "{{ $port }}" - {{- else if (eq (mod $index 2) 1) }} - "{{ template "common.names.fullname" $ }}-node-{{ (sub $nodenumber 1) }}-redis": "{{ $port }}" - {{- end }} - {{- end }} -{{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/service.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/service.yaml deleted file mode 100644 index 9530bde9..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/service.yaml +++ /dev/null @@ -1,160 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if or .Release.IsUpgrade (ne .Values.sentinel.service.type "NodePort") .Values.sentinel.service.nodePorts.redis -}} -{{- if and (eq .Values.architecture "replication") .Values.sentinel.enabled }} -{{ $portsmap := (lookup "v1" "ConfigMap" (include "common.names.namespace" .) (printf "%s-%s" ( include "common.names.fullname" . ) "ports-configmap")).data }} - -{{ $sentinelport := 0}} -{{ $redisport := 0}} -{{- if $portsmap }} -{{ $sentinelport = index $portsmap (printf "%s-%s" (include "common.names.fullname" $) "sentinel") }} -{{ $redisport = index $portsmap (printf "%s-%s" (include "common.names.fullname" $) "redis") }} -{{- else }} -{{- end }} - -apiVersion: v1 -kind: Service -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: node - {{- if or .Values.sentinel.service.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.sentinel.service.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -spec: - type: {{ .Values.sentinel.service.type }} - {{- if or (eq .Values.sentinel.service.type "LoadBalancer") (eq .Values.sentinel.service.type "NodePort") }} - externalTrafficPolicy: {{ .Values.sentinel.service.externalTrafficPolicy | quote }} - {{- end }} - {{- if and (eq .Values.sentinel.service.type "LoadBalancer") (not (empty .Values.sentinel.service.loadBalancerIP)) }} - loadBalancerIP: {{ .Values.sentinel.service.loadBalancerIP }} - {{- end }} - {{- if and (eq .Values.sentinel.service.type "LoadBalancer") .Values.sentinel.service.loadBalancerClass }} - loadBalancerClass: {{ .Values.sentinel.service.loadBalancerClass }} - {{- end }} - {{- if and (eq .Values.sentinel.service.type "LoadBalancer") (not (empty .Values.sentinel.service.loadBalancerSourceRanges)) }} - loadBalancerSourceRanges: {{ toYaml .Values.sentinel.service.loadBalancerSourceRanges | nindent 4 }} - {{- end }} - {{- if and .Values.sentinel.service.clusterIP (eq .Values.sentinel.service.type "ClusterIP") }} - clusterIP: {{ .Values.sentinel.service.clusterIP }} - {{- end }} - {{- if .Values.sentinel.service.sessionAffinity }} - sessionAffinity: {{ .Values.sentinel.service.sessionAffinity }} - {{- end }} - {{- if .Values.sentinel.service.sessionAffinityConfig }} - sessionAffinityConfig: {{- include "common.tplvalues.render" (dict "value" .Values.sentinel.service.sessionAffinityConfig "context" $) | nindent 4 }} - {{- end }} - ports: - - name: tcp-redis - {{- if and (or (eq .Values.sentinel.service.type "NodePort") (eq .Values.sentinel.service.type "LoadBalancer")) .Values.sentinel.service.nodePorts.redis }} - port: {{ .Values.sentinel.service.nodePorts.redis }} - {{- else if eq .Values.sentinel.service.type "NodePort" }} - port: {{ $redisport }} - {{- else}} - port: {{ .Values.sentinel.service.ports.redis }} - {{- end }} - targetPort: {{ .Values.replica.containerPorts.redis }} - {{- if and (or (eq .Values.sentinel.service.type "NodePort") (eq .Values.sentinel.service.type "LoadBalancer")) .Values.sentinel.service.nodePorts.redis }} - nodePort: {{ .Values.sentinel.service.nodePorts.redis }} - {{- else if eq .Values.sentinel.service.type "ClusterIP" }} - nodePort: null - {{- else if eq .Values.sentinel.service.type "NodePort" }} - nodePort: {{ $redisport }} - {{- end }} - - name: tcp-sentinel - {{- if and (or (eq .Values.sentinel.service.type "NodePort") (eq .Values.sentinel.service.type "LoadBalancer")) .Values.sentinel.service.nodePorts.sentinel }} - port: {{ .Values.sentinel.service.nodePorts.sentinel }} - {{- else if eq .Values.sentinel.service.type "NodePort" }} - port: {{ $sentinelport }} - {{- else }} - port: {{ .Values.sentinel.service.ports.sentinel }} - {{- end }} - targetPort: {{ .Values.sentinel.containerPorts.sentinel }} - {{- if and (or (eq .Values.sentinel.service.type "NodePort") (eq .Values.sentinel.service.type "LoadBalancer")) .Values.sentinel.service.nodePorts.sentinel }} - nodePort: {{ .Values.sentinel.service.nodePorts.sentinel }} - {{- else if eq .Values.sentinel.service.type "ClusterIP" }} - nodePort: null - {{- else if eq .Values.sentinel.service.type "NodePort" }} - nodePort: {{ $sentinelport }} - {{- end }} - {{- if eq .Values.sentinel.service.type "NodePort" }} - - name: sentinel-internal - nodePort: null - port: {{ .Values.sentinel.containerPorts.sentinel }} - protocol: TCP - targetPort: {{ .Values.sentinel.containerPorts.sentinel }} - - name: redis-internal - nodePort: null - port: {{ .Values.replica.containerPorts.redis }} - protocol: TCP - targetPort: {{ .Values.replica.containerPorts.redis }} - {{- end }} - {{- if .Values.sentinel.service.extraPorts }} - {{- include "common.tplvalues.render" (dict "value" .Values.sentinel.service.extraPorts "context" $) | nindent 4 }} - {{- end }} - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.replica.podLabels .Values.commonLabels ) "context" . ) }} - selector: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: node - -{{- $masterServiceConfig := ternary .Values.sentinel.masterService .Values.sentinel.service .Values.sentinel.masterService.enabled -}} -{{- if and .Values.sentinel.enabled (or .Values.sentinel.masterService.enabled .Values.sentinel.service.createMaster) }} ---- -apiVersion: v1 -kind: Service -metadata: - name: "{{ template "common.names.fullname" . }}-master" - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: node - {{- if or $masterServiceConfig.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list ($masterServiceConfig.annotations) .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -spec: - type: {{ $masterServiceConfig.type }} - {{- if or (eq $masterServiceConfig.type "LoadBalancer") (eq $masterServiceConfig.type "NodePort") }} - externalTrafficPolicy: {{ $masterServiceConfig.externalTrafficPolicy | quote }} - {{- end }} - {{- if and (eq $masterServiceConfig.type "LoadBalancer") (not (empty ($masterServiceConfig.loadBalancerIP))) }} - loadBalancerIP: {{ $masterServiceConfig.loadBalancerIP }} - {{- end }} - {{- if and (eq $masterServiceConfig.type "LoadBalancer") (not (empty ($masterServiceConfig.loadBalancerClass))) }} - loadBalancerClass: {{ $masterServiceConfig.loadBalancerClass }} - {{- end }} - {{- if and (eq $masterServiceConfig.type "LoadBalancer") (not (empty ($masterServiceConfig.loadBalancerSourceRanges))) }} - loadBalancerSourceRanges: {{ toYaml ($masterServiceConfig.loadBalancerSourceRanges) | nindent 4 }} - {{- end }} - {{- if and (eq $masterServiceConfig.type "ClusterIP") (not (empty ($masterServiceConfig.clusterIP))) }} - clusterIP: {{ $masterServiceConfig.clusterIP }} - {{- end }} - sessionAffinity: {{ $masterServiceConfig.sessionAffinity }} - {{- if $masterServiceConfig.sessionAffinityConfig }} - sessionAffinityConfig: {{- include "common.tplvalues.render" (dict "value" ($masterServiceConfig.sessionAffinityConfig) "context" $) | nindent 4 }} - {{- end }} - ports: - - name: tcp-redis - {{- if and (or (eq $masterServiceConfig.type "NodePort") (eq $masterServiceConfig.type "LoadBalancer")) ($masterServiceConfig.nodePorts.redis) }} - port: {{ $masterServiceConfig.nodePorts.redis }} - {{- else if eq $masterServiceConfig.type "NodePort" }} - port: {{ $redisport }} - {{- else }} - port: {{ $masterServiceConfig.ports.redis }} - {{- end }} - targetPort: {{ .Values.replica.containerPorts.redis }} - {{- if and (or (eq $masterServiceConfig.type "NodePort") (eq $masterServiceConfig.type "LoadBalancer")) ($masterServiceConfig.nodePorts.redis) }} - nodePort: {{ $masterServiceConfig.nodePorts.redis }} - {{- else if eq $masterServiceConfig.type "ClusterIP" }} - nodePort: null - {{- else if eq $masterServiceConfig.type "NodePort" }} - nodePort: {{ $redisport }} - {{- end }} - selector: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 4 }} - isMaster: "true" -{{- end }} -{{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/statefulset.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/statefulset.yaml deleted file mode 100644 index 45c7451e..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/sentinel/statefulset.yaml +++ /dev/null @@ -1,843 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if or .Release.IsUpgrade (ne .Values.sentinel.service.type "NodePort") .Values.sentinel.service.nodePorts.redis -}} -{{- if and (eq .Values.architecture "replication") .Values.sentinel.enabled }} -apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} -kind: StatefulSet -metadata: - name: {{ printf "%s-node" (include "common.names.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: node - {{- if or .Values.commonAnnotations .Values.sentinel.annotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.sentinel.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -spec: - replicas: {{ .Values.replica.replicaCount }} - revisionHistoryLimit: {{ .Values.replica.revisionHistoryLimit }} - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.replica.podLabels .Values.commonLabels ) "context" . ) }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: node - serviceName: {{ printf "%s-headless" (include "common.names.fullname" .) }} - {{- if .Values.replica.updateStrategy }} - updateStrategy: {{- toYaml .Values.replica.updateStrategy | nindent 4 }} - {{- end }} - {{- if and .Values.replica.minReadySeconds (semverCompare ">= 1.23-0" (include "common.capabilities.kubeVersion" .)) }} - minReadySeconds: {{ .Values.replica.minReadySeconds }} - {{- end }} - {{- if .Values.replica.podManagementPolicy }} - podManagementPolicy: {{ .Values.replica.podManagementPolicy | quote }} - {{- end }} - template: - metadata: - labels: {{- include "common.labels.standard" ( dict "customLabels" $podLabels "context" $ ) | nindent 8 }} - app.kubernetes.io/component: node - {{- if .Values.sentinel.masterService.enabled }} - app.kubernetes.io/role: slave - {{- end }} - {{- if and .Values.metrics.enabled .Values.metrics.podLabels }} - {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.podLabels "context" $ ) | nindent 8 }} - {{- end }} - annotations: - {{- if (include "redis.createConfigmap" .) }} - checksum/configmap: {{ pick ( include (print $.Template.BasePath "/configmap.yaml") . | fromYaml ) "data" | toYaml | sha256sum }} - {{- end }} - checksum/health: {{ pick ( include (print $.Template.BasePath "/health-configmap.yaml") . | fromYaml ) "data" | toYaml | sha256sum }} - checksum/scripts: {{ pick ( include (print $.Template.BasePath "/scripts-configmap.yaml") . | fromYaml ) "data" | toYaml | sha256sum }} - checksum/secret: {{ pick ( include (print $.Template.BasePath "/secret.yaml") . | fromYaml ) "data" | toYaml | sha256sum }} - {{- if .Values.replica.podAnnotations }} - {{- include "common.tplvalues.render" ( dict "value" .Values.replica.podAnnotations "context" $ ) | nindent 8 }} - {{- end }} - {{- if and .Values.metrics.enabled .Values.metrics.podAnnotations }} - {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.podAnnotations "context" $ ) | nindent 8 }} - {{- end }} - spec: - {{- if .Values.sentinel.extraPodSpec }} - {{- include "common.tplvalues.render" (dict "value" .Values.sentinel.extraPodSpec "context" $) | nindent 6 }} - {{- end }} - {{- include "redis.imagePullSecrets" . | nindent 6 }} - automountServiceAccountToken: {{ .Values.replica.automountServiceAccountToken }} - {{- if .Values.replica.hostAliases }} - hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.replica.hostAliases "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.replica.podSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.replica.podSecurityContext "context" $) | nindent 8 }} - {{- end }} - serviceAccountName: {{ template "redis.serviceAccountName" . }} - {{- if .Values.replica.priorityClassName }} - priorityClassName: {{ .Values.replica.priorityClassName | quote }} - {{- end }} - {{- if .Values.replica.affinity }} - affinity: {{- include "common.tplvalues.render" (dict "value" .Values.replica.affinity "context" $) | nindent 8 }} - {{- else }} - affinity: - podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.replica.podAffinityPreset "component" "node" "customLabels" $podLabels "context" $) | nindent 10 }} - podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.replica.podAntiAffinityPreset "component" "node" "customLabels" $podLabels "context" $) | nindent 10 }} - nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.replica.nodeAffinityPreset.type "key" .Values.replica.nodeAffinityPreset.key "values" .Values.replica.nodeAffinityPreset.values) | nindent 10 }} - {{- end }} - {{- if .Values.replica.nodeSelector }} - nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.replica.nodeSelector "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.replica.tolerations }} - tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.replica.tolerations "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.replica.topologySpreadConstraints }} - topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.replica.topologySpreadConstraints "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.replica.shareProcessNamespace }} - shareProcessNamespace: {{ .Values.replica.shareProcessNamespace }} - {{- end }} - {{- if .Values.replica.schedulerName }} - schedulerName: {{ .Values.replica.schedulerName | quote }} - {{- end }} - {{- if .Values.replica.dnsPolicy }} - dnsPolicy: {{ .Values.replica.dnsPolicy }} - {{- end }} - {{- if .Values.replica.dnsConfig }} - dnsConfig: {{- include "common.tplvalues.render" (dict "value" .Values.replica.dnsConfig "context" $) | nindent 8 }} - {{- end }} - enableServiceLinks: {{ .Values.sentinel.enableServiceLinks }} - terminationGracePeriodSeconds: {{ .Values.sentinel.terminationGracePeriodSeconds }} - containers: - - name: redis - image: {{ template "redis.image" . }} - imagePullPolicy: {{ .Values.image.pullPolicy | quote }} - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.replica.lifecycleHooks }} - lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.replica.lifecycleHooks "context" $) | nindent 12 }} - {{- else }} - lifecycle: - preStop: - exec: - command: - - /bin/bash - - -c - - /opt/bitnami/scripts/start-scripts/prestop-redis.sh - {{- end }} - {{- end }} - {{- if .Values.replica.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.replica.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} - {{- else if .Values.replica.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.replica.command "context" $) | nindent 12 }} - {{- else }} - command: - - /bin/bash - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} - {{- else if .Values.replica.args }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.replica.args "context" $) | nindent 12 }} - {{- else }} - args: - - -c - - /opt/bitnami/scripts/start-scripts/start-node.sh - {{- end }} - env: - - name: BITNAMI_DEBUG - value: {{ ternary "true" "false" (or .Values.image.debug .Values.diagnosticMode.enabled) | quote }} - - name: REDIS_MASTER_PORT_NUMBER - value: {{ .Values.replica.containerPorts.redis | quote }} - - name: ALLOW_EMPTY_PASSWORD - value: {{ ternary "no" "yes" .Values.auth.enabled | quote }} - {{- if .Values.auth.enabled }} - {{- if .Values.auth.usePasswordFiles }} - - name: REDIS_PASSWORD_FILE - value: "/opt/bitnami/redis/secrets/redis-password" - - name: REDIS_MASTER_PASSWORD_FILE - value: "/opt/bitnami/redis/secrets/redis-password" - {{- else }} - - name: REDIS_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "redis.secretName" . }} - key: {{ template "redis.secretPasswordKey" . }} - - name: REDIS_MASTER_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "redis.secretName" . }} - key: {{ template "redis.secretPasswordKey" . }} - {{- end }} - {{- end }} - - name: REDIS_TLS_ENABLED - value: {{ ternary "yes" "no" .Values.tls.enabled | quote }} - {{- if .Values.tls.enabled }} - - name: REDIS_TLS_PORT - value: {{ .Values.replica.containerPorts.redis | quote }} - - name: REDIS_TLS_AUTH_CLIENTS - value: {{ ternary "yes" "no" .Values.tls.authClients | quote }} - - name: REDIS_TLS_CERT_FILE - value: {{ template "redis.tlsCert" . }} - - name: REDIS_TLS_KEY_FILE - value: {{ template "redis.tlsCertKey" . }} - - name: REDIS_TLS_CA_FILE - value: {{ template "redis.tlsCACert" . }} - {{- if .Values.tls.dhParamsFilename }} - - name: REDIS_TLS_DH_PARAMS_FILE - value: {{ template "redis.tlsDHParams" . }} - {{- end }} - {{- else }} - - name: REDIS_PORT - value: {{ .Values.replica.containerPorts.redis | quote }} - {{- end }} - - name: REDIS_SENTINEL_TLS_ENABLED - value: {{ ternary "yes" "no" .Values.tls.enabled | quote }} - {{- if .Values.tls.enabled }} - - name: REDIS_SENTINEL_TLS_PORT_NUMBER - value: {{ .Values.sentinel.containerPorts.sentinel | quote }} - - name: REDIS_SENTINEL_TLS_AUTH_CLIENTS - value: {{ ternary "yes" "no" .Values.tls.authClients | quote }} - - name: REDIS_SENTINEL_TLS_CERT_FILE - value: {{ template "redis.tlsCert" . }} - - name: REDIS_SENTINEL_TLS_KEY_FILE - value: {{ template "redis.tlsCertKey" . }} - - name: REDIS_SENTINEL_TLS_CA_FILE - value: {{ template "redis.tlsCACert" . }} - {{- if .Values.tls.dhParamsFilename }} - - name: REDIS_SENTINEL_TLS_DH_PARAMS_FILE - value: {{ template "redis.tlsDHParams" . }} - {{- end }} - {{- else }} - - name: REDIS_SENTINEL_PORT - value: {{ .Values.sentinel.containerPorts.sentinel | quote }} - {{- end }} - - name: REDIS_DATA_DIR - value: {{ .Values.replica.persistence.path }} - {{- if .Values.replica.externalMaster.enabled }} - - name: REDIS_EXTERNAL_MASTER_HOST - value: {{ .Values.replica.externalMaster.host | quote }} - - name: REDIS_EXTERNAL_MASTER_PORT - value: {{ .Values.replica.externalMaster.port | quote }} - {{- end }} - {{- if .Values.replica.extraEnvVars }} - {{- include "common.tplvalues.render" ( dict "value" .Values.replica.extraEnvVars "context" $ ) | nindent 12 }} - {{- end }} - {{- if or .Values.replica.extraEnvVarsCM .Values.replica.extraEnvVarsSecret }} - envFrom: - {{- if .Values.replica.extraEnvVarsCM }} - - configMapRef: - name: {{ .Values.replica.extraEnvVarsCM }} - {{- end }} - {{- if .Values.replica.extraEnvVarsSecret }} - - secretRef: - name: {{ .Values.replica.extraEnvVarsSecret }} - {{- end }} - {{- end }} - ports: - - name: redis - containerPort: {{ .Values.replica.containerPorts.redis }} - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.replica.customStartupProbe }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.replica.customStartupProbe "context" $) | nindent 12 }} - {{- else if .Values.replica.startupProbe.enabled }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.replica.startupProbe "enabled") "context" $) | nindent 12 }} - exec: - command: - - sh - - -c - - /health/ping_liveness_local.sh {{ .Values.replica.livenessProbe.timeoutSeconds }} - {{- end }} - {{- if .Values.replica.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.replica.customLivenessProbe "context" $) | nindent 12 }} - {{- else if .Values.replica.livenessProbe.enabled }} - livenessProbe: - initialDelaySeconds: {{ .Values.replica.livenessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.replica.livenessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.replica.livenessProbe.timeoutSeconds }} - successThreshold: {{ .Values.replica.livenessProbe.successThreshold }} - failureThreshold: {{ .Values.replica.livenessProbe.failureThreshold }} - exec: - command: - - sh - - -c - - /health/ping_liveness_local.sh {{ .Values.replica.livenessProbe.timeoutSeconds }} - {{- end }} - {{- if .Values.replica.customReadinessProbe }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.replica.customReadinessProbe "context" $) | nindent 12 }} - {{- else if .Values.replica.readinessProbe.enabled }} - readinessProbe: - initialDelaySeconds: {{ .Values.replica.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.replica.readinessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.replica.readinessProbe.timeoutSeconds }} - successThreshold: {{ .Values.replica.readinessProbe.successThreshold }} - failureThreshold: {{ .Values.replica.readinessProbe.failureThreshold }} - exec: - command: - - sh - - -c - - /health/ping_readiness_local.sh {{ .Values.replica.readinessProbe.timeoutSeconds }} - {{- end }} - {{- end }} - {{- if .Values.replica.resources }} - resources: {{- toYaml .Values.replica.resources | nindent 12 }} - {{- else if ne .Values.replica.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.replica.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: start-scripts - mountPath: /opt/bitnami/scripts/start-scripts - - name: health - mountPath: /health - - name: sentinel-data - mountPath: /opt/bitnami/redis-sentinel/etc - {{- if .Values.auth.usePasswordFiles }} - - name: redis-password - mountPath: /opt/bitnami/redis/secrets/ - {{- end }} - - name: redis-data - mountPath: {{ .Values.replica.persistence.path }} - {{- if .Values.replica.persistence.subPath }} - subPath: {{ .Values.replica.persistence.subPath }} - {{- else if .Values.replica.persistence.subPathExpr }} - subPathExpr: {{ .Values.replica.persistence.subPathExpr }} - {{- end }} - - name: config - mountPath: /opt/bitnami/redis/mounted-etc - - name: empty-dir - mountPath: /opt/bitnami/redis/etc - subPath: app-conf-dir - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - {{- if .Values.tls.enabled }} - - name: redis-certificates - mountPath: /opt/bitnami/redis/certs - readOnly: true - {{- end }} - {{- if .Values.replica.extraVolumeMounts }} - {{- include "common.tplvalues.render" ( dict "value" .Values.replica.extraVolumeMounts "context" $ ) | nindent 12 }} - {{- end }} - - name: sentinel - image: {{ template "redis.sentinel.image" . }} - imagePullPolicy: {{ .Values.sentinel.image.pullPolicy | quote }} - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.sentinel.lifecycleHooks }} - lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.sentinel.lifecycleHooks "context" $) | nindent 12 }} - {{- else }} - lifecycle: - preStop: - exec: - command: - - /bin/bash - - -c - - /opt/bitnami/scripts/start-scripts/prestop-sentinel.sh - {{- end }} - {{- end }} - {{- if .Values.sentinel.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.sentinel.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} - {{- else if .Values.sentinel.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.sentinel.command "context" $) | nindent 12 }} - {{- else }} - command: - - /bin/bash - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} - {{- else if .Values.sentinel.args }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.sentinel.args "context" $) | nindent 12 }} - {{- else }} - args: - - -c - - /opt/bitnami/scripts/start-scripts/start-sentinel.sh - {{- end }} - env: - - name: BITNAMI_DEBUG - value: {{ ternary "true" "false" (or .Values.sentinel.image.debug .Values.diagnosticMode.enabled) | quote }} - {{- if .Values.auth.enabled }} - {{- if .Values.auth.usePasswordFiles }} - - name: REDIS_PASSWORD_FILE - value: "/opt/bitnami/redis/secrets/redis-password" - {{- else }} - - name: REDIS_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "redis.secretName" . }} - key: {{ template "redis.secretPasswordKey" . }} - {{- end }} - {{- else }} - - name: ALLOW_EMPTY_PASSWORD - value: "yes" - {{- end }} - - name: REDIS_SENTINEL_TLS_ENABLED - value: {{ ternary "yes" "no" .Values.tls.enabled | quote }} - {{- if .Values.tls.enabled }} - - name: REDIS_SENTINEL_TLS_PORT_NUMBER - value: {{ .Values.sentinel.containerPorts.sentinel | quote }} - - name: REDIS_SENTINEL_TLS_AUTH_CLIENTS - value: {{ ternary "yes" "no" .Values.tls.authClients | quote }} - - name: REDIS_SENTINEL_TLS_CERT_FILE - value: {{ template "redis.tlsCert" . }} - - name: REDIS_SENTINEL_TLS_KEY_FILE - value: {{ template "redis.tlsCertKey" . }} - - name: REDIS_SENTINEL_TLS_CA_FILE - value: {{ template "redis.tlsCACert" . }} - {{- if .Values.tls.dhParamsFilename }} - - name: REDIS_SENTINEL_TLS_DH_PARAMS_FILE - value: {{ template "redis.tlsDHParams" . }} - {{- end }} - {{- else }} - - name: REDIS_SENTINEL_PORT - value: {{ .Values.sentinel.containerPorts.sentinel | quote }} - {{- end }} - {{- if .Values.sentinel.externalMaster.enabled }} - - name: REDIS_EXTERNAL_MASTER_HOST - value: {{ .Values.sentinel.externalMaster.host | quote }} - - name: REDIS_EXTERNAL_MASTER_PORT - value: {{ .Values.sentinel.externalMaster.port | quote }} - {{- end }} - {{- if .Values.sentinel.extraEnvVars }} - {{- include "common.tplvalues.render" ( dict "value" .Values.sentinel.extraEnvVars "context" $ ) | nindent 12 }} - {{- end }} - {{- if or .Values.sentinel.extraEnvVarsCM .Values.sentinel.extraEnvVarsSecret }} - envFrom: - {{- if .Values.sentinel.extraEnvVarsCM }} - - configMapRef: - name: {{ .Values.sentinel.extraEnvVarsCM }} - {{- end }} - {{- if .Values.sentinel.extraEnvVarsSecret }} - - secretRef: - name: {{ .Values.sentinel.extraEnvVarsSecret }} - {{- end }} - {{- end }} - ports: - - name: redis-sentinel - containerPort: {{ .Values.sentinel.containerPorts.sentinel }} - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.sentinel.customStartupProbe }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.sentinel.customStartupProbe "context" $) | nindent 12 }} - {{- else if .Values.sentinel.startupProbe.enabled }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.sentinel.startupProbe "enabled") "context" $) | nindent 12 }} - exec: - command: - - sh - - -c - - /health/ping_sentinel.sh {{ .Values.sentinel.livenessProbe.timeoutSeconds }} - {{- end }} - {{- if .Values.sentinel.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.sentinel.customLivenessProbe "context" $) | nindent 12 }} - {{- else if .Values.sentinel.livenessProbe.enabled }} - livenessProbe: - initialDelaySeconds: {{ .Values.sentinel.livenessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.sentinel.livenessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.sentinel.livenessProbe.timeoutSeconds }} - successThreshold: {{ .Values.sentinel.livenessProbe.successThreshold }} - failureThreshold: {{ .Values.sentinel.livenessProbe.failureThreshold }} - exec: - command: - - sh - - -c - - /health/ping_sentinel.sh {{ .Values.sentinel.livenessProbe.timeoutSeconds }} - {{- end }} - {{- end }} - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.sentinel.customReadinessProbe }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.sentinel.customReadinessProbe "context" $) | nindent 12 }} - {{- else if .Values.sentinel.readinessProbe.enabled }} - readinessProbe: - initialDelaySeconds: {{ .Values.sentinel.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.sentinel.readinessProbe.periodSeconds }} - timeoutSeconds: {{ .Values.sentinel.readinessProbe.timeoutSeconds }} - successThreshold: {{ .Values.sentinel.readinessProbe.successThreshold }} - failureThreshold: {{ .Values.sentinel.readinessProbe.failureThreshold }} - exec: - command: - - sh - - -c - - /health/ping_sentinel.sh {{ .Values.sentinel.readinessProbe.timeoutSeconds }} - {{- end }} - {{- end }} - {{- if .Values.sentinel.resources }} - resources: {{- toYaml .Values.sentinel.resources | nindent 12 }} - {{- else if ne .Values.sentinel.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.sentinel.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - - name: start-scripts - mountPath: /opt/bitnami/scripts/start-scripts - - name: health - mountPath: /health - {{- if or .Values.sentinel.masterService.enabled .Values.sentinel.service.createMaster}} - - name: kubectl-shared - mountPath: /etc/shared - {{- end }} - - name: sentinel-data - mountPath: /opt/bitnami/redis-sentinel/etc - {{- if .Values.auth.usePasswordFiles }} - - name: redis-password - mountPath: /opt/bitnami/redis/secrets/ - {{- end }} - - name: redis-data - mountPath: {{ .Values.replica.persistence.path }} - {{- if .Values.replica.persistence.subPath }} - subPath: {{ .Values.replica.persistence.subPath }} - {{- else if .Values.replica.persistence.subPathExpr }} - subPathExpr: {{ .Values.replica.persistence.subPathExpr }} - {{- end }} - - name: config - mountPath: /opt/bitnami/redis-sentinel/mounted-etc - {{- if .Values.tls.enabled }} - - name: redis-certificates - mountPath: /opt/bitnami/redis/certs - readOnly: true - {{- end }} - {{- if .Values.sentinel.extraVolumeMounts }} - {{- include "common.tplvalues.render" ( dict "value" .Values.sentinel.extraVolumeMounts "context" $ ) | nindent 12 }} - {{- end }} - {{- if .Values.metrics.enabled }} - - name: metrics - image: {{ template "redis.metrics.image" . }} - imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }} - {{- if .Values.metrics.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.metrics.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} - {{- else }} - command: - - /bin/bash - - -c - - | - if [[ -f '/secrets/redis-password' ]]; then - export REDIS_PASSWORD=$(cat /secrets/redis-password) - fi - redis_exporter{{- range $key, $value := .Values.metrics.extraArgs }} --{{ $key }}={{ $value }}{{- end }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} - {{- end }} - env: - - name: REDIS_ALIAS - value: {{ template "common.names.fullname" . }} - - name: REDIS_EXPORTER_WEB_LISTEN_ADDRESS - value: {{ printf ":%v" .Values.metrics.containerPorts.http }} - {{- if .Values.auth.enabled }} - - name: REDIS_USER - value: default - {{- if (not .Values.auth.usePasswordFiles) }} - - name: REDIS_PASSWORD - valueFrom: - secretKeyRef: - name: {{ template "redis.secretName" . }} - key: {{ template "redis.secretPasswordKey" . }} - {{- end }} - {{- end }} - {{- if .Values.tls.enabled }} - - name: REDIS_ADDR - value: rediss://{{ .Values.metrics.redisTargetHost }}:{{ .Values.replica.containerPorts.redis }} - {{- if .Values.tls.authClients }} - - name: REDIS_EXPORTER_TLS_CLIENT_KEY_FILE - value: {{ template "redis.tlsCertKey" . }} - - name: REDIS_EXPORTER_TLS_CLIENT_CERT_FILE - value: {{ template "redis.tlsCert" . }} - {{- end }} - - name: REDIS_EXPORTER_TLS_CA_CERT_FILE - value: {{ template "redis.tlsCACert" . }} - {{- end }} - {{- if .Values.metrics.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.metrics.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - ports: - - name: metrics - containerPort: {{ .Values.metrics.containerPorts.http }} - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.metrics.customStartupProbe }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customStartupProbe "context" $) | nindent 12 }} - {{- else if .Values.metrics.startupProbe.enabled }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.startupProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: metrics - {{- end }} - {{- if .Values.metrics.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customLivenessProbe "context" $) | nindent 12 }} - {{- else if .Values.metrics.livenessProbe.enabled }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.livenessProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: metrics - {{- end }} - {{- if .Values.metrics.customReadinessProbe }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.metrics.customReadinessProbe "context" $) | nindent 12 }} - {{- else if .Values.metrics.readinessProbe.enabled }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.metrics.readinessProbe "enabled") "context" $) | nindent 12 }} - httpGet: - path: / - port: metrics - {{- end }} - {{- end }} - {{- if .Values.metrics.resources }} - resources: {{- toYaml .Values.metrics.resources | nindent 12 }} - {{- else if ne .Values.metrics.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.metrics.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - {{- if .Values.auth.usePasswordFiles }} - - name: redis-password - mountPath: /secrets/ - {{- end }} - {{- if .Values.tls.enabled }} - - name: redis-certificates - mountPath: /opt/bitnami/redis/certs - readOnly: true - {{- end }} - {{- if .Values.metrics.extraVolumeMounts }} - {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.extraVolumeMounts "context" $ ) | nindent 12 }} - {{- end }} - {{- end }} - {{- if or .Values.sentinel.masterService.enabled .Values.sentinel.service.createMaster }} - - name: kubectl-shared - image: {{ template "redis.kubectl.image" . }} - imagePullPolicy: {{ .Values.kubectl.image.pullPolicy | quote }} - command: {{- toYaml .Values.kubectl.command | nindent 12 }} - {{- if .Values.kubectl.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.kubectl.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - volumeMounts: - - name: kubectl-shared - mountPath: /etc/shared - - name: kubectl-scripts - mountPath: /opt/bitnami/scripts/kubectl-scripts - {{- if .Values.kubectl.resources }} - resources: {{- toYaml .Values.kubectl.resources | nindent 12 }} - {{- end }} - {{- end }} - {{- if .Values.replica.sidecars }} - {{- include "common.tplvalues.render" (dict "value" .Values.replica.sidecars "context" $) | nindent 8 }} - {{- end }} - {{- $needsVolumePermissions := and .Values.volumePermissions.enabled .Values.replica.persistence.enabled .Values.replica.podSecurityContext.enabled .Values.replica.containerSecurityContext.enabled }} - {{- if or .Values.replica.initContainers $needsVolumePermissions .Values.sysctl.enabled }} - initContainers: - {{- if .Values.replica.initContainers }} - {{- include "common.tplvalues.render" (dict "value" .Values.replica.initContainers "context" $) | nindent 8 }} - {{- end }} - {{- if $needsVolumePermissions }} - - name: volume-permissions - image: {{ include "redis.volumePermissions.image" . }} - imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} - command: - - /bin/bash - - -ec - - | - {{- if eq ( toString ( .Values.volumePermissions.containerSecurityContext.runAsUser )) "auto" }} - chown -R `id -u`:`id -G | cut -d " " -f2` {{ .Values.replica.persistence.path }} - {{- else }} - chown -R {{ .Values.replica.containerSecurityContext.runAsUser }}:{{ .Values.replica.podSecurityContext.fsGroup }} {{ .Values.replica.persistence.path }} - {{- end }} - {{- if eq ( toString ( .Values.volumePermissions.containerSecurityContext.runAsUser )) "auto" }} - securityContext: {{- omit .Values.volumePermissions.containerSecurityContext "runAsUser" | toYaml | nindent 12 }} - {{- else }} - securityContext: {{- .Values.volumePermissions.containerSecurityContext | toYaml | nindent 12 }} - {{- end }} - {{- if .Values.volumePermissions.extraEnvVars }} - env: - {{- include "common.tplvalues.render" (dict "value" .Values.volumePermissions.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.volumePermissions.resources }} - resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} - {{- else if ne .Values.volumePermissions.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.volumePermissions.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - - name: redis-data - mountPath: {{ .Values.replica.persistence.path }} - {{- if .Values.replica.persistence.subPath }} - subPath: {{ .Values.replica.persistence.subPath }} - {{- else if .Values.replica.persistence.subPathExpr }} - subPathExpr: {{ .Values.replica.persistence.subPathExpr }} - {{- end }} - {{- end }} - {{- if .Values.sysctl.enabled }} - - name: init-sysctl - image: {{ include "redis.sysctl.image" . }} - imagePullPolicy: {{ default "" .Values.sysctl.image.pullPolicy | quote }} - securityContext: - privileged: true - runAsUser: 0 - {{- if .Values.sysctl.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.sysctl.command "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.sysctl.resources }} - resources: {{- toYaml .Values.sysctl.resources | nindent 12 }} - {{- else if ne .Values.sysctl.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.sysctl.resourcesPreset) | nindent 12 }} - {{- end }} - {{- if .Values.sysctl.mountHostSys }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - - name: host-sys - mountPath: /host-sys - {{- end }} - {{- end }} - {{- end }} - volumes: - - name: start-scripts - configMap: - name: {{ printf "%s-scripts" (include "common.names.fullname" .) }} - defaultMode: 0755 - - name: health - configMap: - name: {{ printf "%s-health" (include "common.names.fullname" .) }} - defaultMode: 0755 - {{- if or .Values.sentinel.masterService.enabled .Values.sentinel.service.createMaster}} - - name: kubectl-shared - emptyDir: {} - - name: kubectl-scripts - configMap: - name: {{ printf "%s-kubectl-scripts" (include "common.names.fullname" .) }} - defaultMode: 0755 - {{- end }} - {{- if .Values.auth.usePasswordFiles }} - - name: redis-password - {{ if .Values.auth.usePasswordFileFromSecret }} - secret: - secretName: {{ template "redis.secretName" . }} - items: - - key: {{ template "redis.secretPasswordKey" . }} - path: redis-password - {{- else }} - emptyDir: {} - {{- end }} - {{- end }} - - name: config - configMap: - name: {{ include "redis.configmapName" . }} - {{- if .Values.sysctl.mountHostSys }} - - name: host-sys - hostPath: - path: /sys - {{- end }} - {{- if not .Values.sentinel.persistence.enabled }} - - name: sentinel-data - {{- if or .Values.sentinel.persistence.medium .Values.sentinel.persistence.sizeLimit }} - emptyDir: - {{- if .Values.sentinel.persistence.medium }} - medium: {{ .Values.sentinel.persistence.medium | quote }} - {{- end }} - {{- if .Values.sentinel.persistence.sizeLimit }} - sizeLimit: {{ .Values.sentinel.persistence.sizeLimit | quote }} - {{- end }} - {{- else }} - emptyDir: {} - {{- end }} - {{- end }} - - name: empty-dir - {{- if or .Values.sentinel.persistence.medium .Values.sentinel.persistence.sizeLimit }} - emptyDir: - {{- if .Values.sentinel.persistence.medium }} - medium: {{ .Values.sentinel.persistence.medium | quote }} - {{- end }} - {{- if .Values.sentinel.persistence.sizeLimit }} - sizeLimit: {{ .Values.sentinel.persistence.sizeLimit | quote }} - {{- end }} - {{- else }} - emptyDir: {} - {{- end }} - {{- if .Values.replica.extraVolumes }} - {{- include "common.tplvalues.render" ( dict "value" .Values.replica.extraVolumes "context" $ ) | nindent 8 }} - {{- end }} - {{- if .Values.metrics.extraVolumes }} - {{- include "common.tplvalues.render" ( dict "value" .Values.metrics.extraVolumes "context" $ ) | nindent 8 }} - {{- end }} - {{- if .Values.sentinel.extraVolumes }} - {{- include "common.tplvalues.render" ( dict "value" .Values.sentinel.extraVolumes "context" $ ) | nindent 8 }} - {{- end }} - {{- if .Values.tls.enabled }} - - name: redis-certificates - secret: - secretName: {{ include "redis.tlsSecretName" . }} - defaultMode: 256 - {{- end }} - {{- if not .Values.replica.persistence.enabled }} - - name: redis-data - {{- if or .Values.replica.persistence.medium .Values.replica.persistence.sizeLimit }} - emptyDir: - {{- if .Values.replica.persistence.medium }} - medium: {{ .Values.replica.persistence.medium | quote }} - {{- end }} - {{- if .Values.replica.persistence.sizeLimit }} - sizeLimit: {{ .Values.replica.persistence.sizeLimit | quote }} - {{- end }} - {{- else }} - emptyDir: {} - {{- end }} - {{- else if .Values.replica.persistence.existingClaim }} - - name: redis-data - persistentVolumeClaim: - claimName: {{ printf "%s" (tpl .Values.replica.persistence.existingClaim .) }} - {{- else }} - {{- if .Values.sentinel.persistentVolumeClaimRetentionPolicy.enabled }} - persistentVolumeClaimRetentionPolicy: - whenDeleted: {{ .Values.sentinel.persistentVolumeClaimRetentionPolicy.whenDeleted }} - whenScaled: {{ .Values.sentinel.persistentVolumeClaimRetentionPolicy.whenScaled }} - {{- end }} - volumeClaimTemplates: - - apiVersion: v1 - kind: PersistentVolumeClaim - metadata: - name: redis-data - labels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 10 }} - app.kubernetes.io/component: node - {{- if .Values.replica.persistence.annotations }} - annotations: {{- toYaml .Values.replica.persistence.annotations | nindent 10 }} - {{- end }} - spec: - accessModes: - {{- range .Values.replica.persistence.accessModes }} - - {{ . | quote }} - {{- end }} - resources: - requests: - storage: {{ .Values.replica.persistence.size | quote }} - {{- if .Values.replica.persistence.selector }} - selector: {{- include "common.tplvalues.render" ( dict "value" .Values.replica.persistence.selector "context" $) | nindent 10 }} - {{- end }} - {{- include "common.storage.class" (dict "persistence" .Values.replica.persistence "global" .Values.global) | nindent 8 }} - {{- if .Values.sentinel.persistence.enabled }} - - apiVersion: v1 - kind: PersistentVolumeClaim - metadata: - name: sentinel-data - {{- $claimLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.sentinel.persistence.labels .Values.commonLabels ) "context" . ) }} - labels: {{- include "common.labels.matchLabels" ( dict "customLabels" $claimLabels "context" $ ) | nindent 10 }} - app.kubernetes.io/component: node - {{- if .Values.sentinel.persistence.annotations }} - annotations: {{- toYaml .Values.sentinel.persistence.annotations | nindent 10 }} - {{- end }} - spec: - accessModes: - {{- range .Values.sentinel.persistence.accessModes }} - - {{ . | quote }} - {{- end }} - resources: - requests: - storage: {{ .Values.sentinel.persistence.size | quote }} - {{- if .Values.sentinel.persistence.selector }} - selector: {{- include "common.tplvalues.render" ( dict "value" .Values.sentinel.persistence.selector "context" $) | nindent 10 }} - {{- end }} - {{- if .Values.sentinel.persistence.dataSource }} - dataSource: {{- include "common.tplvalues.render" (dict "value" .Values.sentinel.persistence.dataSource "context" $) | nindent 10 }} - {{- end }} - {{- include "common.storage.class" (dict "persistence" .Values.sentinel.persistence "global" .Values.global) | nindent 8 }} - {{- end }} - {{- end }} -{{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/serviceaccount.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/serviceaccount.yaml deleted file mode 100644 index 0b7d39d5..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/serviceaccount.yaml +++ /dev/null @@ -1,18 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.serviceAccount.create .Values.sentinel.enabled }} -apiVersion: v1 -kind: ServiceAccount -automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} -metadata: - name: {{ template "redis.serviceAccountName" . }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if or .Values.commonAnnotations .Values.serviceAccount.annotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.serviceAccount.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/servicemonitor.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/servicemonitor.yaml deleted file mode 100644 index 1a9f6eea..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/servicemonitor.yaml +++ /dev/null @@ -1,82 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ default (include "common.names.namespace" .) .Values.metrics.serviceMonitor.namespace | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.metrics.serviceMonitor.additionalLabels }} - {{- include "common.tplvalues.render" (dict "value" .Values.metrics.serviceMonitor.additionalLabels "context" $) | nindent 4 }} - {{- end }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - endpoints: - - port: {{ .Values.metrics.serviceMonitor.port }} - {{- if .Values.metrics.serviceMonitor.interval }} - interval: {{ .Values.metrics.serviceMonitor.interval }} - {{- end }} - {{- if .Values.metrics.serviceMonitor.scrapeTimeout }} - scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }} - {{- end }} - {{- if .Values.metrics.serviceMonitor.honorLabels }} - honorLabels: {{ .Values.metrics.serviceMonitor.honorLabels }} - {{- end }} - {{- with concat .Values.metrics.serviceMonitor.relabelings .Values.metrics.serviceMonitor.relabellings }} - relabelings: {{- toYaml . | nindent 6 }} - {{- end }} - {{- if .Values.metrics.serviceMonitor.metricRelabelings }} - metricRelabelings: {{- toYaml .Values.metrics.serviceMonitor.metricRelabelings | nindent 6 }} - {{- end }} - {{- range .Values.metrics.serviceMonitor.additionalEndpoints }} - - port: {{ .port }} - {{- if .interval }} - interval: {{ .interval }} - {{- end }} - {{- if .scrapeTimeout }} - scrapeTimeout: {{ .scrapeTimeout }} - {{- end }} - {{- if .honorLabels }} - honorLabels: {{ .honorLabels }} - {{- end }} - {{- with concat $.Values.metrics.serviceMonitor.relabelings $.Values.metrics.serviceMonitor.relabellings }} - relabelings: {{- toYaml . | nindent 6 }} - {{- end }} - {{- if .metricRelabelings }} - metricRelabelings: {{- toYaml .metricRelabelings | nindent 6 }} - {{- end }} - {{- if .path }} - path: {{ .path }} - {{- end }} - {{- if .params }} - params: - {{- range $key, $value := .params }} - {{ $key }}: - {{- range $value }} - - {{ . | quote }} - {{- end }} - {{- end }} - {{- end }} - {{- end }} - {{- if .Values.metrics.serviceMonitor.podTargetLabels }} - podTargetLabels: {{- toYaml .Values.metrics.serviceMonitor.podTargetLabels | nindent 4 }} - {{- end }} - {{- with .Values.metrics.serviceMonitor.sampleLimit }} - sampleLimit: {{ . }} - {{- end }} - {{- with .Values.metrics.serviceMonitor.targetLimit }} - targetLimit: {{ . }} - {{- end }} - namespaceSelector: - matchNames: - - {{ include "common.names.namespace" . | quote }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: metrics -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/tls-secret.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/templates/tls-secret.yaml deleted file mode 100644 index aa1c1a78..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/templates/tls-secret.yaml +++ /dev/null @@ -1,31 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if (include "redis.createTlsSecret" .) }} -{{- $secretName := printf "%s-crt" (include "common.names.fullname" .) }} -{{- $ca := genCA "redis-ca" 365 }} -{{- $releaseNamespace := (include "common.names.namespace" .) }} -{{- $clusterDomain := .Values.clusterDomain }} -{{- $fullname := include "common.names.fullname" . }} -{{- $serviceName := include "common.names.fullname" . }} -{{- $headlessServiceName := printf "%s-headless" (include "common.names.fullname" .) }} -{{- $masterServiceName := printf "%s-master" (include "common.names.fullname" .) }} -{{- $altNames := list (printf "*.%s.%s.svc.%s" $serviceName $releaseNamespace $clusterDomain) (printf "%s.%s.svc.%s" $masterServiceName $releaseNamespace $clusterDomain) (printf "*.%s.%s.svc.%s" $masterServiceName $releaseNamespace $clusterDomain) (printf "*.%s.%s.svc.%s" $headlessServiceName $releaseNamespace $clusterDomain) (printf "%s.%s.svc.%s" $headlessServiceName $releaseNamespace $clusterDomain) "127.0.0.1" "localhost" $fullname }} -{{- $cert := genSignedCert $fullname nil $altNames 365 $ca }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ $secretName }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -type: kubernetes.io/tls -data: - tls.crt: {{ include "common.secrets.lookup" (dict "secret" $secretName "key" "tls.crt" "defaultValue" $cert.Cert "context" $) }} - tls.key: {{ include "common.secrets.lookup" (dict "secret" $secretName "key" "tls.key" "defaultValue" $cert.Key "context" $) }} - ca.crt: {{ include "common.secrets.lookup" (dict "secret" $secretName "key" "ca.crt" "defaultValue" $ca.Cert "context" $) }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/values.schema.json b/packages/system/dashboard/charts/kubeapps/charts/redis/values.schema.json deleted file mode 100644 index f872c957..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/values.schema.json +++ /dev/null @@ -1,3275 +0,0 @@ -{ - "$schema": "http://json-schema.org/schema#", - "type": "object", - "properties": { - "global": { - "type": "object", - "properties": { - "imageRegistry": { - "type": "string", - "description": "Global Docker image registry", - "default": "" - }, - "imagePullSecrets": { - "type": "array", - "description": "Global Docker registry secret names as an array", - "default": [], - "items": {} - }, - "defaultStorageClass": { - "type": "string", - "description": "Global default StorageClass for Persistent Volume(s)", - "default": "" - }, - "storageClass": { - "type": "string", - "description": "DEPRECATED: use global.defaultStorageClass instead", - "default": "" - }, - "redis": { - "type": "object", - "properties": { - "password": { - "type": "string", - "description": "Global Redis® password (overrides `auth.password`)", - "default": "" - } - } - }, - "compatibility": { - "type": "object", - "properties": { - "openshift": { - "type": "object", - "properties": { - "adaptSecurityContext": { - "type": "string", - "description": "Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation)", - "default": "auto" - } - } - } - } - } - } - }, - "kubeVersion": { - "type": "string", - "description": "Override Kubernetes version", - "default": "" - }, - "nameOverride": { - "type": "string", - "description": "String to partially override common.names.fullname", - "default": "" - }, - "fullnameOverride": { - "type": "string", - "description": "String to fully override common.names.fullname", - "default": "" - }, - "namespaceOverride": { - "type": "string", - "description": "String to fully override common.names.namespace", - "default": "" - }, - "commonLabels": { - "type": "object", - "description": "Labels to add to all deployed objects", - "default": {} - }, - "commonAnnotations": { - "type": "object", - "description": "Annotations to add to all deployed objects", - "default": {} - }, - "secretAnnotations": { - "type": "object", - "description": "Annotations to add to secret", - "default": {} - }, - "clusterDomain": { - "type": "string", - "description": "Kubernetes cluster domain name", - "default": "cluster.local" - }, - "extraDeploy": { - "type": "array", - "description": "Array of extra objects to deploy with the release", - "default": [], - "items": {} - }, - "useHostnames": { - "type": "boolean", - "description": "Use hostnames internally when announcing replication. If false, the hostname will be resolved to an IP address", - "default": true - }, - "nameResolutionThreshold": { - "type": "number", - "description": "Failure threshold for internal hostnames resolution", - "default": 5 - }, - "nameResolutionTimeout": { - "type": "number", - "description": "Timeout seconds between probes for internal hostnames resolution", - "default": 5 - }, - "diagnosticMode": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable diagnostic mode (all probes will be disabled and the command will be overridden)", - "default": false - }, - "command": { - "type": "array", - "description": "Command to override all containers in the deployment", - "default": [ - "sleep" - ], - "items": { - "type": "string" - } - }, - "args": { - "type": "array", - "description": "Args to override all containers in the deployment", - "default": [ - "infinity" - ], - "items": { - "type": "string" - } - } - } - }, - "image": { - "type": "object", - "properties": { - "registry": { - "type": "string", - "description": "Redis® image registry", - "default": "REGISTRY_NAME" - }, - "repository": { - "type": "string", - "description": "Redis® image repository", - "default": "REPOSITORY_NAME/redis" - }, - "digest": { - "type": "string", - "description": "Redis® image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag", - "default": "" - }, - "pullPolicy": { - "type": "string", - "description": "Redis® image pull policy", - "default": "IfNotPresent" - }, - "pullSecrets": { - "type": "array", - "description": "Redis® image pull secrets", - "default": [], - "items": {} - }, - "debug": { - "type": "boolean", - "description": "Enable image debug mode", - "default": false - } - } - }, - "architecture": { - "type": "string", - "description": "Redis® architecture. Allowed values: `standalone` or `replication`", - "default": "replication" - }, - "auth": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable password authentication", - "default": true - }, - "sentinel": { - "type": "boolean", - "description": "Enable password authentication on sentinels too", - "default": true - }, - "password": { - "type": "string", - "description": "Redis® password", - "default": "" - }, - "existingSecret": { - "type": "string", - "description": "The name of an existing secret with Redis® credentials", - "default": "" - }, - "existingSecretPasswordKey": { - "type": "string", - "description": "Password key to be retrieved from existing secret", - "default": "" - }, - "usePasswordFiles": { - "type": "boolean", - "description": "Mount credentials as files instead of using an environment variable", - "default": false - }, - "usePasswordFileFromSecret": { - "type": "boolean", - "description": "Mount password file from secret", - "default": true - } - } - }, - "commonConfiguration": { - "type": "string", - "description": "Common configuration to be added into the ConfigMap", - "default": "\"\"" - }, - "existingConfigmap": { - "type": "string", - "description": "The name of an existing ConfigMap with your custom configuration for Redis® nodes", - "default": "" - }, - "master": { - "type": "object", - "properties": { - "count": { - "type": "number", - "description": "Number of Redis® master instances to deploy (experimental, requires additional configuration)", - "default": 1 - }, - "revisionHistoryLimit": { - "type": "number", - "description": "The number of old history to retain to allow rollback", - "default": 10 - }, - "configuration": { - "type": "string", - "description": "Configuration for Redis® master nodes", - "default": "" - }, - "disableCommands": { - "type": "array", - "description": "Array with Redis® commands to disable on master nodes", - "default": [ - "FLUSHDB", - "FLUSHALL" - ], - "items": { - "type": "string" - } - }, - "command": { - "type": "array", - "description": "Override default container command (useful when using custom images)", - "default": [], - "items": {} - }, - "args": { - "type": "array", - "description": "Override default container args (useful when using custom images)", - "default": [], - "items": {} - }, - "enableServiceLinks": { - "type": "boolean", - "description": "Whether information about services should be injected into pod's environment variable", - "default": true - }, - "preExecCmds": { - "type": "array", - "description": "Additional commands to run prior to starting Redis® master", - "default": [], - "items": {} - }, - "extraFlags": { - "type": "array", - "description": "Array with additional command line flags for Redis® master", - "default": [], - "items": {} - }, - "extraEnvVars": { - "type": "array", - "description": "Array with extra environment variables to add to Redis® master nodes", - "default": [], - "items": {} - }, - "extraEnvVarsCM": { - "type": "string", - "description": "Name of existing ConfigMap containing extra env vars for Redis® master nodes", - "default": "" - }, - "extraEnvVarsSecret": { - "type": "string", - "description": "Name of existing Secret containing extra env vars for Redis® master nodes", - "default": "" - }, - "containerPorts": { - "type": "object", - "properties": { - "redis": { - "type": "number", - "description": "Container port to open on Redis® master nodes", - "default": 6379 - } - } - }, - "startupProbe": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable startupProbe on Redis® master nodes", - "default": false - }, - "initialDelaySeconds": { - "type": "number", - "description": "Initial delay seconds for startupProbe", - "default": 20 - }, - "periodSeconds": { - "type": "number", - "description": "Period seconds for startupProbe", - "default": 5 - }, - "timeoutSeconds": { - "type": "number", - "description": "Timeout seconds for startupProbe", - "default": 5 - }, - "failureThreshold": { - "type": "number", - "description": "Failure threshold for startupProbe", - "default": 5 - }, - "successThreshold": { - "type": "number", - "description": "Success threshold for startupProbe", - "default": 1 - } - } - }, - "livenessProbe": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable livenessProbe on Redis® master nodes", - "default": true - }, - "initialDelaySeconds": { - "type": "number", - "description": "Initial delay seconds for livenessProbe", - "default": 20 - }, - "periodSeconds": { - "type": "number", - "description": "Period seconds for livenessProbe", - "default": 5 - }, - "timeoutSeconds": { - "type": "number", - "description": "Timeout seconds for livenessProbe", - "default": 5 - }, - "failureThreshold": { - "type": "number", - "description": "Failure threshold for livenessProbe", - "default": 5 - }, - "successThreshold": { - "type": "number", - "description": "Success threshold for livenessProbe", - "default": 1 - } - } - }, - "readinessProbe": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable readinessProbe on Redis® master nodes", - "default": true - }, - "initialDelaySeconds": { - "type": "number", - "description": "Initial delay seconds for readinessProbe", - "default": 20 - }, - "periodSeconds": { - "type": "number", - "description": "Period seconds for readinessProbe", - "default": 5 - }, - "timeoutSeconds": { - "type": "number", - "description": "Timeout seconds for readinessProbe", - "default": 1 - }, - "failureThreshold": { - "type": "number", - "description": "Failure threshold for readinessProbe", - "default": 5 - }, - "successThreshold": { - "type": "number", - "description": "Success threshold for readinessProbe", - "default": 1 - } - } - }, - "customStartupProbe": { - "type": "object", - "description": "Custom startupProbe that overrides the default one", - "default": {} - }, - "customLivenessProbe": { - "type": "object", - "description": "Custom livenessProbe that overrides the default one", - "default": {} - }, - "customReadinessProbe": { - "type": "object", - "description": "Custom readinessProbe that overrides the default one", - "default": {} - }, - "resourcesPreset": { - "type": "string", - "description": "Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if master.resources is set (master.resources is recommended for production).", - "default": "nano" - }, - "resources": { - "type": "object", - "description": "Set container requests and limits for different resources like CPU or memory (essential for production workloads)", - "default": {} - }, - "podSecurityContext": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enabled Redis® master pods' Security Context", - "default": true - }, - "fsGroupChangePolicy": { - "type": "string", - "description": "Set filesystem group change policy", - "default": "Always" - }, - "sysctls": { - "type": "array", - "description": "Set kernel settings using the sysctl interface", - "default": [], - "items": {} - }, - "supplementalGroups": { - "type": "array", - "description": "Set filesystem extra groups", - "default": [], - "items": {} - }, - "fsGroup": { - "type": "number", - "description": "Set Redis® master pod's Security Context fsGroup", - "default": 1001 - } - } - }, - "containerSecurityContext": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enabled Redis® master containers' Security Context", - "default": true - }, - "runAsUser": { - "type": "number", - "description": "Set Redis® master containers' Security Context runAsUser", - "default": 1001 - }, - "runAsGroup": { - "type": "number", - "description": "Set Redis® master containers' Security Context runAsGroup", - "default": 1001 - }, - "runAsNonRoot": { - "type": "boolean", - "description": "Set Redis® master containers' Security Context runAsNonRoot", - "default": true - }, - "allowPrivilegeEscalation": { - "type": "boolean", - "description": "Is it possible to escalate Redis® pod(s) privileges", - "default": false - }, - "readOnlyRootFilesystem": { - "type": "boolean", - "description": "Set container's Security Context read-only root filesystem", - "default": true - }, - "seccompProfile": { - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "Set Redis® master containers' Security Context seccompProfile", - "default": "RuntimeDefault" - } - } - }, - "capabilities": { - "type": "object", - "properties": { - "drop": { - "type": "array", - "description": "Set Redis® master containers' Security Context capabilities to drop", - "default": [ - "ALL" - ], - "items": { - "type": "string" - } - } - } - } - } - }, - "kind": { - "type": "string", - "description": "Use either Deployment, StatefulSet (default) or DaemonSet", - "default": "StatefulSet" - }, - "schedulerName": { - "type": "string", - "description": "Alternate scheduler for Redis® master pods", - "default": "" - }, - "updateStrategy": { - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "Redis® master statefulset strategy type", - "default": "RollingUpdate" - } - } - }, - "minReadySeconds": { - "type": "number", - "description": "How many seconds a pod needs to be ready before killing the next, during update", - "default": 0 - }, - "priorityClassName": { - "type": "string", - "description": "Redis® master pods' priorityClassName", - "default": "" - }, - "automountServiceAccountToken": { - "type": "boolean", - "description": "Mount Service Account token in pod", - "default": false - }, - "hostAliases": { - "type": "array", - "description": "Redis® master pods host aliases", - "default": [], - "items": {} - }, - "podLabels": { - "type": "object", - "description": "Extra labels for Redis® master pods", - "default": {} - }, - "podAnnotations": { - "type": "object", - "description": "Annotations for Redis® master pods", - "default": {} - }, - "shareProcessNamespace": { - "type": "boolean", - "description": "Share a single process namespace between all of the containers in Redis® master pods", - "default": false - }, - "podAffinityPreset": { - "type": "string", - "description": "Pod affinity preset. Ignored if `master.affinity` is set. Allowed values: `soft` or `hard`", - "default": "" - }, - "podAntiAffinityPreset": { - "type": "string", - "description": "Pod anti-affinity preset. Ignored if `master.affinity` is set. Allowed values: `soft` or `hard`", - "default": "soft" - }, - "nodeAffinityPreset": { - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "Node affinity preset type. Ignored if `master.affinity` is set. Allowed values: `soft` or `hard`", - "default": "" - }, - "key": { - "type": "string", - "description": "Node label key to match. Ignored if `master.affinity` is set", - "default": "" - }, - "values": { - "type": "array", - "description": "Node label values to match. Ignored if `master.affinity` is set", - "default": [], - "items": {} - } - } - }, - "affinity": { - "type": "object", - "description": "Affinity for Redis® master pods assignment", - "default": {} - }, - "nodeSelector": { - "type": "object", - "description": "Node labels for Redis® master pods assignment", - "default": {} - }, - "tolerations": { - "type": "array", - "description": "Tolerations for Redis® master pods assignment", - "default": [], - "items": {} - }, - "topologySpreadConstraints": { - "type": "array", - "description": "Spread Constraints for Redis® master pod assignment", - "default": [], - "items": {} - }, - "dnsPolicy": { - "type": "string", - "description": "DNS Policy for Redis® master pod", - "default": "" - }, - "dnsConfig": { - "type": "object", - "description": "DNS Configuration for Redis® master pod", - "default": {} - }, - "lifecycleHooks": { - "type": "object", - "description": "for the Redis® master container(s) to automate configuration before or after startup", - "default": {} - }, - "extraVolumes": { - "type": "array", - "description": "Optionally specify extra list of additional volumes for the Redis® master pod(s)", - "default": [], - "items": {} - }, - "extraVolumeMounts": { - "type": "array", - "description": "Optionally specify extra list of additional volumeMounts for the Redis® master container(s)", - "default": [], - "items": {} - }, - "sidecars": { - "type": "array", - "description": "Add additional sidecar containers to the Redis® master pod(s)", - "default": [], - "items": {} - }, - "initContainers": { - "type": "array", - "description": "Add additional init containers to the Redis® master pod(s)", - "default": [], - "items": {} - }, - "persistence": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable persistence on Redis® master nodes using Persistent Volume Claims", - "default": true - }, - "medium": { - "type": "string", - "description": "Provide a medium for `emptyDir` volumes.", - "default": "" - }, - "sizeLimit": { - "type": "string", - "description": "Set this to enable a size limit for `emptyDir` volumes.", - "default": "" - }, - "path": { - "type": "string", - "description": "The path the volume will be mounted at on Redis® master containers", - "default": "/data" - }, - "subPath": { - "type": "string", - "description": "The subdirectory of the volume to mount on Redis® master containers", - "default": "" - }, - "subPathExpr": { - "type": "string", - "description": "Used to construct the subPath subdirectory of the volume to mount on Redis® master containers", - "default": "" - }, - "storageClass": { - "type": "string", - "description": "Persistent Volume storage class", - "default": "" - }, - "accessModes": { - "type": "array", - "description": "Persistent Volume access modes", - "default": [ - "ReadWriteOnce" - ], - "items": { - "type": "string" - } - }, - "size": { - "type": "string", - "description": "Persistent Volume size", - "default": "8Gi" - }, - "annotations": { - "type": "object", - "description": "Additional custom annotations for the PVC", - "default": {} - }, - "labels": { - "type": "object", - "description": "Additional custom labels for the PVC", - "default": {} - }, - "selector": { - "type": "object", - "description": "Additional labels to match for the PVC", - "default": {} - }, - "dataSource": { - "type": "object", - "description": "Custom PVC data source", - "default": {} - }, - "existingClaim": { - "type": "string", - "description": "Use a existing PVC which must be created manually before bound", - "default": "" - } - } - }, - "persistentVolumeClaimRetentionPolicy": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Controls if and how PVCs are deleted during the lifecycle of a StatefulSet", - "default": false - }, - "whenScaled": { - "type": "string", - "description": "Volume retention behavior when the replica count of the StatefulSet is reduced", - "default": "Retain" - }, - "whenDeleted": { - "type": "string", - "description": "Volume retention behavior that applies when the StatefulSet is deleted", - "default": "Retain" - } - } - }, - "service": { - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "Redis® master service type", - "default": "ClusterIP" - }, - "portNames": { - "type": "object", - "properties": { - "redis": { - "type": "string", - "description": "Redis® master service port name", - "default": "tcp-redis" - } - } - }, - "ports": { - "type": "object", - "properties": { - "redis": { - "type": "number", - "description": "Redis® master service port", - "default": 6379 - } - } - }, - "nodePorts": { - "type": "object", - "properties": { - "redis": { - "type": "string", - "description": "Node port for Redis® master", - "default": "" - } - } - }, - "externalTrafficPolicy": { - "type": "string", - "description": "Redis® master service external traffic policy", - "default": "Cluster" - }, - "extraPorts": { - "type": "array", - "description": "Extra ports to expose (normally used with the `sidecar` value)", - "default": [], - "items": {} - }, - "internalTrafficPolicy": { - "type": "string", - "description": "Redis® master service internal traffic policy (requires Kubernetes v1.22 or greater to be usable)", - "default": "Cluster" - }, - "clusterIP": { - "type": "string", - "description": "Redis® master service Cluster IP", - "default": "" - }, - "loadBalancerIP": { - "type": "string", - "description": "Redis® master service Load Balancer IP", - "default": "" - }, - "loadBalancerClass": { - "type": "string", - "description": "master service Load Balancer class if service type is `LoadBalancer` (optional, cloud specific)", - "default": "" - }, - "loadBalancerSourceRanges": { - "type": "array", - "description": "Redis® master service Load Balancer sources", - "default": [], - "items": {} - }, - "externalIPs": { - "type": "array", - "description": "Redis® master service External IPs", - "default": [], - "items": {} - }, - "annotations": { - "type": "object", - "description": "Additional custom annotations for Redis® master service", - "default": {} - }, - "sessionAffinity": { - "type": "string", - "description": "Session Affinity for Kubernetes service, can be \"None\" or \"ClientIP\"", - "default": "None" - }, - "sessionAffinityConfig": { - "type": "object", - "description": "Additional settings for the sessionAffinity", - "default": {} - } - } - }, - "terminationGracePeriodSeconds": { - "type": "number", - "description": "Integer setting the termination grace period for the redis-master pods", - "default": 30 - }, - "serviceAccount": { - "type": "object", - "properties": { - "create": { - "type": "boolean", - "description": "Specifies whether a ServiceAccount should be created", - "default": true - }, - "name": { - "type": "string", - "description": "The name of the ServiceAccount to use.", - "default": "" - }, - "automountServiceAccountToken": { - "type": "boolean", - "description": "Whether to auto mount the service account token", - "default": false - }, - "annotations": { - "type": "object", - "description": "Additional custom annotations for the ServiceAccount", - "default": {} - } - } - }, - "pdb": { - "type": "object", - "properties": { - "create": { - "type": "boolean", - "description": "Enable/disable a Pod Disruption Budget creation", - "default": true - } - } - } - } - }, - "replica": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "description": "Use either DaemonSet or StatefulSet (default)", - "default": "StatefulSet" - }, - "replicaCount": { - "type": "number", - "description": "Number of Redis® replicas to deploy", - "default": 3 - }, - "revisionHistoryLimit": { - "type": "number", - "description": "The number of old history to retain to allow rollback", - "default": 10 - }, - "configuration": { - "type": "string", - "description": "Configuration for Redis® replicas nodes", - "default": "" - }, - "disableCommands": { - "type": "array", - "description": "Array with Redis® commands to disable on replicas nodes", - "default": [ - "FLUSHDB", - "FLUSHALL" - ], - "items": { - "type": "string" - } - }, - "command": { - "type": "array", - "description": "Override default container command (useful when using custom images)", - "default": [], - "items": {} - }, - "args": { - "type": "array", - "description": "Override default container args (useful when using custom images)", - "default": [], - "items": {} - }, - "enableServiceLinks": { - "type": "boolean", - "description": "Whether information about services should be injected into pod's environment variable", - "default": true - }, - "preExecCmds": { - "type": "array", - "description": "Additional commands to run prior to starting Redis® replicas", - "default": [], - "items": {} - }, - "extraFlags": { - "type": "array", - "description": "Array with additional command line flags for Redis® replicas", - "default": [], - "items": {} - }, - "extraEnvVars": { - "type": "array", - "description": "Array with extra environment variables to add to Redis® replicas nodes", - "default": [], - "items": {} - }, - "extraEnvVarsCM": { - "type": "string", - "description": "Name of existing ConfigMap containing extra env vars for Redis® replicas nodes", - "default": "" - }, - "extraEnvVarsSecret": { - "type": "string", - "description": "Name of existing Secret containing extra env vars for Redis® replicas nodes", - "default": "" - }, - "externalMaster": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Use external master for bootstrapping", - "default": false - }, - "host": { - "type": "string", - "description": "External master host to bootstrap from", - "default": "" - }, - "port": { - "type": "number", - "description": "Port for Redis service external master host", - "default": 6379 - } - } - }, - "containerPorts": { - "type": "object", - "properties": { - "redis": { - "type": "number", - "description": "Container port to open on Redis® replicas nodes", - "default": 6379 - } - } - }, - "startupProbe": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable startupProbe on Redis® replicas nodes", - "default": true - }, - "initialDelaySeconds": { - "type": "number", - "description": "Initial delay seconds for startupProbe", - "default": 10 - }, - "periodSeconds": { - "type": "number", - "description": "Period seconds for startupProbe", - "default": 10 - }, - "timeoutSeconds": { - "type": "number", - "description": "Timeout seconds for startupProbe", - "default": 5 - }, - "failureThreshold": { - "type": "number", - "description": "Failure threshold for startupProbe", - "default": 22 - }, - "successThreshold": { - "type": "number", - "description": "Success threshold for startupProbe", - "default": 1 - } - } - }, - "livenessProbe": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable livenessProbe on Redis® replicas nodes", - "default": true - }, - "initialDelaySeconds": { - "type": "number", - "description": "Initial delay seconds for livenessProbe", - "default": 20 - }, - "periodSeconds": { - "type": "number", - "description": "Period seconds for livenessProbe", - "default": 5 - }, - "timeoutSeconds": { - "type": "number", - "description": "Timeout seconds for livenessProbe", - "default": 5 - }, - "failureThreshold": { - "type": "number", - "description": "Failure threshold for livenessProbe", - "default": 5 - }, - "successThreshold": { - "type": "number", - "description": "Success threshold for livenessProbe", - "default": 1 - } - } - }, - "readinessProbe": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable readinessProbe on Redis® replicas nodes", - "default": true - }, - "initialDelaySeconds": { - "type": "number", - "description": "Initial delay seconds for readinessProbe", - "default": 20 - }, - "periodSeconds": { - "type": "number", - "description": "Period seconds for readinessProbe", - "default": 5 - }, - "timeoutSeconds": { - "type": "number", - "description": "Timeout seconds for readinessProbe", - "default": 1 - }, - "failureThreshold": { - "type": "number", - "description": "Failure threshold for readinessProbe", - "default": 5 - }, - "successThreshold": { - "type": "number", - "description": "Success threshold for readinessProbe", - "default": 1 - } - } - }, - "customStartupProbe": { - "type": "object", - "description": "Custom startupProbe that overrides the default one", - "default": {} - }, - "customLivenessProbe": { - "type": "object", - "description": "Custom livenessProbe that overrides the default one", - "default": {} - }, - "customReadinessProbe": { - "type": "object", - "description": "Custom readinessProbe that overrides the default one", - "default": {} - }, - "resourcesPreset": { - "type": "string", - "description": "Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if replica.resources is set (replica.resources is recommended for production).", - "default": "nano" - }, - "resources": { - "type": "object", - "description": "Set container requests and limits for different resources like CPU or memory (essential for production workloads)", - "default": {} - }, - "podSecurityContext": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enabled Redis® replicas pods' Security Context", - "default": true - }, - "fsGroupChangePolicy": { - "type": "string", - "description": "Set filesystem group change policy", - "default": "Always" - }, - "sysctls": { - "type": "array", - "description": "Set kernel settings using the sysctl interface", - "default": [], - "items": {} - }, - "supplementalGroups": { - "type": "array", - "description": "Set filesystem extra groups", - "default": [], - "items": {} - }, - "fsGroup": { - "type": "number", - "description": "Set Redis® replicas pod's Security Context fsGroup", - "default": 1001 - } - } - }, - "containerSecurityContext": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enabled Redis® replicas containers' Security Context", - "default": true - }, - "runAsUser": { - "type": "number", - "description": "Set Redis® replicas containers' Security Context runAsUser", - "default": 1001 - }, - "runAsGroup": { - "type": "number", - "description": "Set Redis® replicas containers' Security Context runAsGroup", - "default": 1001 - }, - "runAsNonRoot": { - "type": "boolean", - "description": "Set Redis® replicas containers' Security Context runAsNonRoot", - "default": true - }, - "allowPrivilegeEscalation": { - "type": "boolean", - "description": "Set Redis® replicas pod's Security Context allowPrivilegeEscalation", - "default": false - }, - "readOnlyRootFilesystem": { - "type": "boolean", - "description": "Set container's Security Context read-only root filesystem", - "default": true - }, - "seccompProfile": { - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "Set Redis® replicas containers' Security Context seccompProfile", - "default": "RuntimeDefault" - } - } - }, - "capabilities": { - "type": "object", - "properties": { - "drop": { - "type": "array", - "description": "Set Redis® replicas containers' Security Context capabilities to drop", - "default": [ - "ALL" - ], - "items": { - "type": "string" - } - } - } - } - } - }, - "schedulerName": { - "type": "string", - "description": "Alternate scheduler for Redis® replicas pods", - "default": "" - }, - "updateStrategy": { - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "Redis® replicas statefulset strategy type", - "default": "RollingUpdate" - } - } - }, - "minReadySeconds": { - "type": "number", - "description": "How many seconds a pod needs to be ready before killing the next, during update", - "default": 0 - }, - "priorityClassName": { - "type": "string", - "description": "Redis® replicas pods' priorityClassName", - "default": "" - }, - "podManagementPolicy": { - "type": "string", - "description": "podManagementPolicy to manage scaling operation of %%MAIN_CONTAINER_NAME%% pods", - "default": "" - }, - "automountServiceAccountToken": { - "type": "boolean", - "description": "Mount Service Account token in pod", - "default": false - }, - "hostAliases": { - "type": "array", - "description": "Redis® replicas pods host aliases", - "default": [], - "items": {} - }, - "podLabels": { - "type": "object", - "description": "Extra labels for Redis® replicas pods", - "default": {} - }, - "podAnnotations": { - "type": "object", - "description": "Annotations for Redis® replicas pods", - "default": {} - }, - "shareProcessNamespace": { - "type": "boolean", - "description": "Share a single process namespace between all of the containers in Redis® replicas pods", - "default": false - }, - "podAffinityPreset": { - "type": "string", - "description": "Pod affinity preset. Ignored if `replica.affinity` is set. Allowed values: `soft` or `hard`", - "default": "" - }, - "podAntiAffinityPreset": { - "type": "string", - "description": "Pod anti-affinity preset. Ignored if `replica.affinity` is set. Allowed values: `soft` or `hard`", - "default": "soft" - }, - "nodeAffinityPreset": { - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "Node affinity preset type. Ignored if `replica.affinity` is set. Allowed values: `soft` or `hard`", - "default": "" - }, - "key": { - "type": "string", - "description": "Node label key to match. Ignored if `replica.affinity` is set", - "default": "" - }, - "values": { - "type": "array", - "description": "Node label values to match. Ignored if `replica.affinity` is set", - "default": [], - "items": {} - } - } - }, - "affinity": { - "type": "object", - "description": "Affinity for Redis® replicas pods assignment", - "default": {} - }, - "nodeSelector": { - "type": "object", - "description": "Node labels for Redis® replicas pods assignment", - "default": {} - }, - "tolerations": { - "type": "array", - "description": "Tolerations for Redis® replicas pods assignment", - "default": [], - "items": {} - }, - "topologySpreadConstraints": { - "type": "array", - "description": "Spread Constraints for Redis® replicas pod assignment", - "default": [], - "items": {} - }, - "dnsPolicy": { - "type": "string", - "description": "DNS Policy for Redis® replica pods", - "default": "" - }, - "dnsConfig": { - "type": "object", - "description": "DNS Configuration for Redis® replica pods", - "default": {} - }, - "lifecycleHooks": { - "type": "object", - "description": "for the Redis® replica container(s) to automate configuration before or after startup", - "default": {} - }, - "extraVolumes": { - "type": "array", - "description": "Optionally specify extra list of additional volumes for the Redis® replicas pod(s)", - "default": [], - "items": {} - }, - "extraVolumeMounts": { - "type": "array", - "description": "Optionally specify extra list of additional volumeMounts for the Redis® replicas container(s)", - "default": [], - "items": {} - }, - "sidecars": { - "type": "array", - "description": "Add additional sidecar containers to the Redis® replicas pod(s)", - "default": [], - "items": {} - }, - "initContainers": { - "type": "array", - "description": "Add additional init containers to the Redis® replicas pod(s)", - "default": [], - "items": {} - }, - "persistence": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable persistence on Redis® replicas nodes using Persistent Volume Claims", - "default": true - }, - "medium": { - "type": "string", - "description": "Provide a medium for `emptyDir` volumes.", - "default": "" - }, - "sizeLimit": { - "type": "string", - "description": "Set this to enable a size limit for `emptyDir` volumes.", - "default": "" - }, - "path": { - "type": "string", - "description": "The path the volume will be mounted at on Redis® replicas containers", - "default": "/data" - }, - "subPath": { - "type": "string", - "description": "The subdirectory of the volume to mount on Redis® replicas containers", - "default": "" - }, - "subPathExpr": { - "type": "string", - "description": "Used to construct the subPath subdirectory of the volume to mount on Redis® replicas containers", - "default": "" - }, - "storageClass": { - "type": "string", - "description": "Persistent Volume storage class", - "default": "" - }, - "accessModes": { - "type": "array", - "description": "Persistent Volume access modes", - "default": [ - "ReadWriteOnce" - ], - "items": { - "type": "string" - } - }, - "size": { - "type": "string", - "description": "Persistent Volume size", - "default": "8Gi" - }, - "annotations": { - "type": "object", - "description": "Additional custom annotations for the PVC", - "default": {} - }, - "labels": { - "type": "object", - "description": "Additional custom labels for the PVC", - "default": {} - }, - "selector": { - "type": "object", - "description": "Additional labels to match for the PVC", - "default": {} - }, - "dataSource": { - "type": "object", - "description": "Custom PVC data source", - "default": {} - }, - "existingClaim": { - "type": "string", - "description": "Use a existing PVC which must be created manually before bound", - "default": "" - } - } - }, - "persistentVolumeClaimRetentionPolicy": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Controls if and how PVCs are deleted during the lifecycle of a StatefulSet", - "default": false - }, - "whenScaled": { - "type": "string", - "description": "Volume retention behavior when the replica count of the StatefulSet is reduced", - "default": "Retain" - }, - "whenDeleted": { - "type": "string", - "description": "Volume retention behavior that applies when the StatefulSet is deleted", - "default": "Retain" - } - } - }, - "service": { - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "Redis® replicas service type", - "default": "ClusterIP" - }, - "ports": { - "type": "object", - "properties": { - "redis": { - "type": "number", - "description": "Redis® replicas service port", - "default": 6379 - } - } - }, - "nodePorts": { - "type": "object", - "properties": { - "redis": { - "type": "string", - "description": "Node port for Redis® replicas", - "default": "" - } - } - }, - "externalTrafficPolicy": { - "type": "string", - "description": "Redis® replicas service external traffic policy", - "default": "Cluster" - }, - "internalTrafficPolicy": { - "type": "string", - "description": "Redis® replicas service internal traffic policy (requires Kubernetes v1.22 or greater to be usable)", - "default": "Cluster" - }, - "extraPorts": { - "type": "array", - "description": "Extra ports to expose (normally used with the `sidecar` value)", - "default": [], - "items": {} - }, - "clusterIP": { - "type": "string", - "description": "Redis® replicas service Cluster IP", - "default": "" - }, - "loadBalancerIP": { - "type": "string", - "description": "Redis® replicas service Load Balancer IP", - "default": "" - }, - "loadBalancerClass": { - "type": "string", - "description": "replicas service Load Balancer class if service type is `LoadBalancer` (optional, cloud specific)", - "default": "" - }, - "loadBalancerSourceRanges": { - "type": "array", - "description": "Redis® replicas service Load Balancer sources", - "default": [], - "items": {} - }, - "annotations": { - "type": "object", - "description": "Additional custom annotations for Redis® replicas service", - "default": {} - }, - "sessionAffinity": { - "type": "string", - "description": "Session Affinity for Kubernetes service, can be \"None\" or \"ClientIP\"", - "default": "None" - }, - "sessionAffinityConfig": { - "type": "object", - "description": "Additional settings for the sessionAffinity", - "default": {} - } - } - }, - "terminationGracePeriodSeconds": { - "type": "number", - "description": "Integer setting the termination grace period for the redis-replicas pods", - "default": 30 - }, - "autoscaling": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable replica autoscaling settings", - "default": false - }, - "minReplicas": { - "type": "number", - "description": "Minimum replicas for the pod autoscaling", - "default": 1 - }, - "maxReplicas": { - "type": "number", - "description": "Maximum replicas for the pod autoscaling", - "default": 11 - }, - "targetCPU": { - "type": "string", - "description": "Percentage of CPU to consider when autoscaling", - "default": "" - }, - "targetMemory": { - "type": "string", - "description": "Percentage of Memory to consider when autoscaling", - "default": "" - } - } - }, - "serviceAccount": { - "type": "object", - "properties": { - "create": { - "type": "boolean", - "description": "Specifies whether a ServiceAccount should be created", - "default": true - }, - "name": { - "type": "string", - "description": "The name of the ServiceAccount to use.", - "default": "" - }, - "automountServiceAccountToken": { - "type": "boolean", - "description": "Whether to auto mount the service account token", - "default": false - }, - "annotations": { - "type": "object", - "description": "Additional custom annotations for the ServiceAccount", - "default": {} - } - } - }, - "pdb": { - "type": "object", - "properties": { - "create": { - "type": "boolean", - "description": "Enable/disable a Pod Disruption Budget creation", - "default": true - } - } - } - } - }, - "sentinel": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Use Redis® Sentinel on Redis® pods.", - "default": false - }, - "image": { - "type": "object", - "properties": { - "registry": { - "type": "string", - "description": "Redis® Sentinel image registry", - "default": "REGISTRY_NAME" - }, - "repository": { - "type": "string", - "description": "Redis® Sentinel image repository", - "default": "REPOSITORY_NAME/redis-sentinel" - }, - "digest": { - "type": "string", - "description": "Redis® Sentinel image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag", - "default": "" - }, - "pullPolicy": { - "type": "string", - "description": "Redis® Sentinel image pull policy", - "default": "IfNotPresent" - }, - "pullSecrets": { - "type": "array", - "description": "Redis® Sentinel image pull secrets", - "default": [], - "items": {} - }, - "debug": { - "type": "boolean", - "description": "Enable image debug mode", - "default": false - } - } - }, - "annotations": { - "type": "object", - "description": "Additional custom annotations for Redis® Sentinel resource", - "default": {} - }, - "masterSet": { - "type": "string", - "description": "Master set name", - "default": "mymaster" - }, - "quorum": { - "type": "number", - "description": "Sentinel Quorum", - "default": 2 - }, - "getMasterTimeout": { - "type": "number", - "description": "Amount of time to allow before get_sentinel_master_info() times out.", - "default": 90 - }, - "automateClusterRecovery": { - "type": "boolean", - "description": "Automate cluster recovery in cases where the last replica is not considered a good replica and Sentinel won't automatically failover to it.", - "default": false - }, - "redisShutdownWaitFailover": { - "type": "boolean", - "description": "Whether the Redis® master container waits for the failover at shutdown (in addition to the Redis® Sentinel container).", - "default": true - }, - "downAfterMilliseconds": { - "type": "number", - "description": "Timeout for detecting a Redis® node is down", - "default": 60000 - }, - "failoverTimeout": { - "type": "number", - "description": "Timeout for performing a election failover", - "default": 180000 - }, - "parallelSyncs": { - "type": "number", - "description": "Number of replicas that can be reconfigured in parallel to use the new master after a failover", - "default": 1 - }, - "configuration": { - "type": "string", - "description": "Configuration for Redis® Sentinel nodes", - "default": "" - }, - "command": { - "type": "array", - "description": "Override default container command (useful when using custom images)", - "default": [], - "items": {} - }, - "args": { - "type": "array", - "description": "Override default container args (useful when using custom images)", - "default": [], - "items": {} - }, - "enableServiceLinks": { - "type": "boolean", - "description": "Whether information about services should be injected into pod's environment variable", - "default": true - }, - "preExecCmds": { - "type": "array", - "description": "Additional commands to run prior to starting Redis® Sentinel", - "default": [], - "items": {} - }, - "extraEnvVars": { - "type": "array", - "description": "Array with extra environment variables to add to Redis® Sentinel nodes", - "default": [], - "items": {} - }, - "extraEnvVarsCM": { - "type": "string", - "description": "Name of existing ConfigMap containing extra env vars for Redis® Sentinel nodes", - "default": "" - }, - "extraEnvVarsSecret": { - "type": "string", - "description": "Name of existing Secret containing extra env vars for Redis® Sentinel nodes", - "default": "" - }, - "externalMaster": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Use external master for bootstrapping", - "default": false - }, - "host": { - "type": "string", - "description": "External master host to bootstrap from", - "default": "" - }, - "port": { - "type": "number", - "description": "Port for Redis service external master host", - "default": 6379 - } - } - }, - "containerPorts": { - "type": "object", - "properties": { - "sentinel": { - "type": "number", - "description": "Container port to open on Redis® Sentinel nodes", - "default": 26379 - } - } - }, - "startupProbe": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable startupProbe on Redis® Sentinel nodes", - "default": true - }, - "initialDelaySeconds": { - "type": "number", - "description": "Initial delay seconds for startupProbe", - "default": 10 - }, - "periodSeconds": { - "type": "number", - "description": "Period seconds for startupProbe", - "default": 10 - }, - "timeoutSeconds": { - "type": "number", - "description": "Timeout seconds for startupProbe", - "default": 5 - }, - "failureThreshold": { - "type": "number", - "description": "Failure threshold for startupProbe", - "default": 22 - }, - "successThreshold": { - "type": "number", - "description": "Success threshold for startupProbe", - "default": 1 - } - } - }, - "livenessProbe": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable livenessProbe on Redis® Sentinel nodes", - "default": true - }, - "initialDelaySeconds": { - "type": "number", - "description": "Initial delay seconds for livenessProbe", - "default": 20 - }, - "periodSeconds": { - "type": "number", - "description": "Period seconds for livenessProbe", - "default": 10 - }, - "timeoutSeconds": { - "type": "number", - "description": "Timeout seconds for livenessProbe", - "default": 5 - }, - "failureThreshold": { - "type": "number", - "description": "Failure threshold for livenessProbe", - "default": 6 - }, - "successThreshold": { - "type": "number", - "description": "Success threshold for livenessProbe", - "default": 1 - } - } - }, - "readinessProbe": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable readinessProbe on Redis® Sentinel nodes", - "default": true - }, - "initialDelaySeconds": { - "type": "number", - "description": "Initial delay seconds for readinessProbe", - "default": 20 - }, - "periodSeconds": { - "type": "number", - "description": "Period seconds for readinessProbe", - "default": 5 - }, - "timeoutSeconds": { - "type": "number", - "description": "Timeout seconds for readinessProbe", - "default": 1 - }, - "failureThreshold": { - "type": "number", - "description": "Failure threshold for readinessProbe", - "default": 6 - }, - "successThreshold": { - "type": "number", - "description": "Success threshold for readinessProbe", - "default": 1 - } - } - }, - "customStartupProbe": { - "type": "object", - "description": "Custom startupProbe that overrides the default one", - "default": {} - }, - "customLivenessProbe": { - "type": "object", - "description": "Custom livenessProbe that overrides the default one", - "default": {} - }, - "customReadinessProbe": { - "type": "object", - "description": "Custom readinessProbe that overrides the default one", - "default": {} - }, - "persistence": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable persistence on Redis® sentinel nodes using Persistent Volume Claims (Experimental)", - "default": false - }, - "storageClass": { - "type": "string", - "description": "Persistent Volume storage class", - "default": "" - }, - "accessModes": { - "type": "array", - "description": "Persistent Volume access modes", - "default": [ - "ReadWriteOnce" - ], - "items": { - "type": "string" - } - }, - "size": { - "type": "string", - "description": "Persistent Volume size", - "default": "100Mi" - }, - "annotations": { - "type": "object", - "description": "Additional custom annotations for the PVC", - "default": {} - }, - "labels": { - "type": "object", - "description": "Additional custom labels for the PVC", - "default": {} - }, - "selector": { - "type": "object", - "description": "Additional labels to match for the PVC", - "default": {} - }, - "dataSource": { - "type": "object", - "description": "Custom PVC data source", - "default": {} - }, - "medium": { - "type": "string", - "description": "Provide a medium for `emptyDir` volumes.", - "default": "" - }, - "sizeLimit": { - "type": "string", - "description": "Set this to enable a size limit for `emptyDir` volumes.", - "default": "" - } - } - }, - "persistentVolumeClaimRetentionPolicy": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Controls if and how PVCs are deleted during the lifecycle of a StatefulSet", - "default": false - }, - "whenScaled": { - "type": "string", - "description": "Volume retention behavior when the replica count of the StatefulSet is reduced", - "default": "Retain" - }, - "whenDeleted": { - "type": "string", - "description": "Volume retention behavior that applies when the StatefulSet is deleted", - "default": "Retain" - } - } - }, - "resourcesPreset": { - "type": "string", - "description": "Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if sentinel.resources is set (sentinel.resources is recommended for production).", - "default": "nano" - }, - "resources": { - "type": "object", - "description": "Set container requests and limits for different resources like CPU or memory (essential for production workloads)", - "default": {} - }, - "containerSecurityContext": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enabled Redis® Sentinel containers' Security Context", - "default": true - }, - "runAsUser": { - "type": "number", - "description": "Set Redis® Sentinel containers' Security Context runAsUser", - "default": 1001 - }, - "runAsGroup": { - "type": "number", - "description": "Set Redis® Sentinel containers' Security Context runAsGroup", - "default": 1001 - }, - "runAsNonRoot": { - "type": "boolean", - "description": "Set Redis® Sentinel containers' Security Context runAsNonRoot", - "default": true - }, - "readOnlyRootFilesystem": { - "type": "boolean", - "description": "Set container's Security Context read-only root filesystem", - "default": true - }, - "allowPrivilegeEscalation": { - "type": "boolean", - "description": "Set Redis® Sentinel containers' Security Context allowPrivilegeEscalation", - "default": false - }, - "seccompProfile": { - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "Set Redis® Sentinel containers' Security Context seccompProfile", - "default": "RuntimeDefault" - } - } - }, - "capabilities": { - "type": "object", - "properties": { - "drop": { - "type": "array", - "description": "Set Redis® Sentinel containers' Security Context capabilities to drop", - "default": [ - "ALL" - ], - "items": { - "type": "string" - } - } - } - } - } - }, - "lifecycleHooks": { - "type": "object", - "description": "for the Redis® sentinel container(s) to automate configuration before or after startup", - "default": {} - }, - "extraVolumes": { - "type": "array", - "description": "Optionally specify extra list of additional volumes for the Redis® Sentinel", - "default": [], - "items": {} - }, - "extraVolumeMounts": { - "type": "array", - "description": "Optionally specify extra list of additional volumeMounts for the Redis® Sentinel container(s)", - "default": [], - "items": {} - }, - "service": { - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "Redis® Sentinel service type", - "default": "ClusterIP" - }, - "ports": { - "type": "object", - "properties": { - "redis": { - "type": "number", - "description": "Redis® service port for Redis®", - "default": 6379 - }, - "sentinel": { - "type": "number", - "description": "Redis® service port for Redis® Sentinel", - "default": 26379 - } - } - }, - "nodePorts": { - "type": "object", - "properties": { - "redis": { - "type": "string", - "description": "Node port for Redis®", - "default": "" - }, - "sentinel": { - "type": "string", - "description": "Node port for Sentinel", - "default": "" - } - } - }, - "externalTrafficPolicy": { - "type": "string", - "description": "Redis® Sentinel service external traffic policy", - "default": "Cluster" - }, - "extraPorts": { - "type": "array", - "description": "Extra ports to expose (normally used with the `sidecar` value)", - "default": [], - "items": {} - }, - "clusterIP": { - "type": "string", - "description": "Redis® Sentinel service Cluster IP", - "default": "" - }, - "createMaster": { - "type": "boolean", - "description": "Enable master service pointing to the current master (experimental)", - "default": false - }, - "loadBalancerIP": { - "type": "string", - "description": "Redis® Sentinel service Load Balancer IP", - "default": "" - }, - "loadBalancerClass": { - "type": "string", - "description": "sentinel service Load Balancer class if service type is `LoadBalancer` (optional, cloud specific)", - "default": "" - }, - "loadBalancerSourceRanges": { - "type": "array", - "description": "Redis® Sentinel service Load Balancer sources", - "default": [], - "items": {} - }, - "annotations": { - "type": "object", - "description": "Additional custom annotations for Redis® Sentinel service", - "default": {} - }, - "sessionAffinity": { - "type": "string", - "description": "Session Affinity for Kubernetes service, can be \"None\" or \"ClientIP\"", - "default": "None" - }, - "sessionAffinityConfig": { - "type": "object", - "description": "Additional settings for the sessionAffinity", - "default": {} - }, - "headless": { - "type": "object", - "properties": { - "annotations": { - "type": "object", - "description": "Annotations for the headless service.", - "default": {} - } - } - } - } - }, - "masterService": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable master service pointing to the current master (experimental)", - "default": false - }, - "type": { - "type": "string", - "description": "Redis® Sentinel master service type", - "default": "ClusterIP" - }, - "ports": { - "type": "object", - "properties": { - "redis": { - "type": "number", - "description": "Redis® service port for Redis®", - "default": 6379 - } - } - }, - "nodePorts": { - "type": "object", - "properties": { - "redis": { - "type": "string", - "description": "Node port for Redis®", - "default": "" - } - } - }, - "externalTrafficPolicy": { - "type": "string", - "description": "Redis® master service external traffic policy", - "default": "" - }, - "extraPorts": { - "type": "array", - "description": "Extra ports to expose (normally used with the `sidecar` value)", - "default": [], - "items": {} - }, - "clusterIP": { - "type": "string", - "description": "Redis® master service Cluster IP", - "default": "" - }, - "loadBalancerIP": { - "type": "string", - "description": "Redis® master service Load Balancer IP", - "default": "" - }, - "loadBalancerClass": { - "type": "string", - "description": "master service Load Balancer class if service type is `LoadBalancer` (optional, cloud specific)", - "default": "" - }, - "loadBalancerSourceRanges": { - "type": "array", - "description": "Redis® master service Load Balancer sources", - "default": [], - "items": {} - }, - "annotations": { - "type": "object", - "description": "Additional custom annotations for Redis® master service", - "default": {} - }, - "sessionAffinity": { - "type": "string", - "description": "Session Affinity for Kubernetes service, can be \"None\" or \"ClientIP\"", - "default": "None" - }, - "sessionAffinityConfig": { - "type": "object", - "description": "Additional settings for the sessionAffinity", - "default": {} - } - } - }, - "terminationGracePeriodSeconds": { - "type": "number", - "description": "Integer setting the termination grace period for the redis-node pods", - "default": 30 - } - } - }, - "serviceBindings": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Create secret for service binding (Experimental)", - "default": false - } - } - }, - "networkPolicy": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable creation of NetworkPolicy resources", - "default": true - }, - "allowExternal": { - "type": "boolean", - "description": "Don't require client label for connections", - "default": true - }, - "allowExternalEgress": { - "type": "boolean", - "description": "Allow the pod to access any range of port and all destinations.", - "default": true - }, - "extraIngress": { - "type": "array", - "description": "Add extra ingress rules to the NetworkPolicy", - "default": [], - "items": {} - }, - "extraEgress": { - "type": "array", - "description": "Add extra egress rules to the NetworkPolicy", - "default": [], - "items": {} - }, - "ingressNSMatchLabels": { - "type": "object", - "description": "Labels to match to allow traffic from other namespaces", - "default": {} - }, - "ingressNSPodMatchLabels": { - "type": "object", - "description": "Pod labels to match to allow traffic from other namespaces", - "default": {} - }, - "metrics": { - "type": "object", - "properties": { - "allowExternal": { - "type": "boolean", - "description": "Don't require client label for connections for metrics endpoint", - "default": true - }, - "ingressNSMatchLabels": { - "type": "object", - "description": "Labels to match to allow traffic from other namespaces to metrics endpoint", - "default": {} - }, - "ingressNSPodMatchLabels": { - "type": "object", - "description": "Pod labels to match to allow traffic from other namespaces to metrics endpoint", - "default": {} - } - } - } - } - }, - "podSecurityPolicy": { - "type": "object", - "properties": { - "create": { - "type": "boolean", - "description": "Whether to create a PodSecurityPolicy. WARNING: PodSecurityPolicy is deprecated in Kubernetes v1.21 or later, unavailable in v1.25 or later", - "default": false - }, - "enabled": { - "type": "boolean", - "description": "Enable PodSecurityPolicy's RBAC rules", - "default": false - } - } - }, - "rbac": { - "type": "object", - "properties": { - "create": { - "type": "boolean", - "description": "Specifies whether RBAC resources should be created", - "default": false - }, - "rules": { - "type": "array", - "description": "Custom RBAC rules to set", - "default": [], - "items": {} - } - } - }, - "serviceAccount": { - "type": "object", - "properties": { - "create": { - "type": "boolean", - "description": "Specifies whether a ServiceAccount should be created", - "default": true - }, - "name": { - "type": "string", - "description": "The name of the ServiceAccount to use.", - "default": "" - }, - "automountServiceAccountToken": { - "type": "boolean", - "description": "Whether to auto mount the service account token", - "default": false - }, - "annotations": { - "type": "object", - "description": "Additional custom annotations for the ServiceAccount", - "default": {} - } - } - }, - "pdb": { - "type": "object", - "description": "DEPRECATED Please use `master.pdb` and `replica.pdb` values instead", - "default": {} - }, - "tls": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable TLS traffic", - "default": false - }, - "authClients": { - "type": "boolean", - "description": "Require clients to authenticate", - "default": true - }, - "autoGenerated": { - "type": "boolean", - "description": "Enable autogenerated certificates", - "default": false - }, - "existingSecret": { - "type": "string", - "description": "The name of the existing secret that contains the TLS certificates", - "default": "" - }, - "certificatesSecret": { - "type": "string", - "description": "DEPRECATED. Use existingSecret instead.", - "default": "" - }, - "certFilename": { - "type": "string", - "description": "Certificate filename", - "default": "" - }, - "certKeyFilename": { - "type": "string", - "description": "Certificate Key filename", - "default": "" - }, - "certCAFilename": { - "type": "string", - "description": "CA Certificate filename", - "default": "" - }, - "dhParamsFilename": { - "type": "string", - "description": "File containing DH params (in order to support DH based ciphers)", - "default": "" - } - } - }, - "metrics": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Start a sidecar prometheus exporter to expose Redis® metrics", - "default": false - }, - "image": { - "type": "object", - "properties": { - "registry": { - "type": "string", - "description": "Redis® Exporter image registry", - "default": "REGISTRY_NAME" - }, - "repository": { - "type": "string", - "description": "Redis® Exporter image repository", - "default": "REPOSITORY_NAME/redis-exporter" - }, - "digest": { - "type": "string", - "description": "Redis® Exporter image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag", - "default": "" - }, - "pullPolicy": { - "type": "string", - "description": "Redis® Exporter image pull policy", - "default": "IfNotPresent" - }, - "pullSecrets": { - "type": "array", - "description": "Redis® Exporter image pull secrets", - "default": [], - "items": {} - } - } - }, - "containerPorts": { - "type": "object", - "properties": { - "http": { - "type": "number", - "description": "Metrics HTTP container port", - "default": 9121 - } - } - }, - "startupProbe": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable startupProbe on Redis® replicas nodes", - "default": false - }, - "initialDelaySeconds": { - "type": "number", - "description": "Initial delay seconds for startupProbe", - "default": 10 - }, - "periodSeconds": { - "type": "number", - "description": "Period seconds for startupProbe", - "default": 10 - }, - "timeoutSeconds": { - "type": "number", - "description": "Timeout seconds for startupProbe", - "default": 5 - }, - "failureThreshold": { - "type": "number", - "description": "Failure threshold for startupProbe", - "default": 5 - }, - "successThreshold": { - "type": "number", - "description": "Success threshold for startupProbe", - "default": 1 - } - } - }, - "livenessProbe": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable livenessProbe on Redis® replicas nodes", - "default": true - }, - "initialDelaySeconds": { - "type": "number", - "description": "Initial delay seconds for livenessProbe", - "default": 10 - }, - "periodSeconds": { - "type": "number", - "description": "Period seconds for livenessProbe", - "default": 10 - }, - "timeoutSeconds": { - "type": "number", - "description": "Timeout seconds for livenessProbe", - "default": 5 - }, - "failureThreshold": { - "type": "number", - "description": "Failure threshold for livenessProbe", - "default": 5 - }, - "successThreshold": { - "type": "number", - "description": "Success threshold for livenessProbe", - "default": 1 - } - } - }, - "readinessProbe": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable readinessProbe on Redis® replicas nodes", - "default": true - }, - "initialDelaySeconds": { - "type": "number", - "description": "Initial delay seconds for readinessProbe", - "default": 5 - }, - "periodSeconds": { - "type": "number", - "description": "Period seconds for readinessProbe", - "default": 10 - }, - "timeoutSeconds": { - "type": "number", - "description": "Timeout seconds for readinessProbe", - "default": 1 - }, - "failureThreshold": { - "type": "number", - "description": "Failure threshold for readinessProbe", - "default": 3 - }, - "successThreshold": { - "type": "number", - "description": "Success threshold for readinessProbe", - "default": 1 - } - } - }, - "customStartupProbe": { - "type": "object", - "description": "Custom startupProbe that overrides the default one", - "default": {} - }, - "customLivenessProbe": { - "type": "object", - "description": "Custom livenessProbe that overrides the default one", - "default": {} - }, - "customReadinessProbe": { - "type": "object", - "description": "Custom readinessProbe that overrides the default one", - "default": {} - }, - "command": { - "type": "array", - "description": "Override default metrics container init command (useful when using custom images)", - "default": [], - "items": {} - }, - "redisTargetHost": { - "type": "string", - "description": "A way to specify an alternative Redis® hostname", - "default": "localhost" - }, - "extraArgs": { - "type": "object", - "description": "Extra arguments for Redis® exporter, for example:", - "default": {} - }, - "extraEnvVars": { - "type": "array", - "description": "Array with extra environment variables to add to Redis® exporter", - "default": [], - "items": {} - }, - "containerSecurityContext": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enabled Redis® exporter containers' Security Context", - "default": true - }, - "runAsUser": { - "type": "number", - "description": "Set Redis® exporter containers' Security Context runAsUser", - "default": 1001 - }, - "runAsGroup": { - "type": "number", - "description": "Set Redis® exporter containers' Security Context runAsGroup", - "default": 1001 - }, - "runAsNonRoot": { - "type": "boolean", - "description": "Set Redis® exporter containers' Security Context runAsNonRoot", - "default": true - }, - "allowPrivilegeEscalation": { - "type": "boolean", - "description": "Set Redis® exporter containers' Security Context allowPrivilegeEscalation", - "default": false - }, - "readOnlyRootFilesystem": { - "type": "boolean", - "description": "Set container's Security Context read-only root filesystem", - "default": true - }, - "seccompProfile": { - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "Set Redis® exporter containers' Security Context seccompProfile", - "default": "RuntimeDefault" - } - } - }, - "capabilities": { - "type": "object", - "properties": { - "drop": { - "type": "array", - "description": "Set Redis® exporter containers' Security Context capabilities to drop", - "default": [ - "ALL" - ], - "items": { - "type": "string" - } - } - } - } - } - }, - "extraVolumes": { - "type": "array", - "description": "Optionally specify extra list of additional volumes for the Redis® metrics sidecar", - "default": [], - "items": {} - }, - "extraVolumeMounts": { - "type": "array", - "description": "Optionally specify extra list of additional volumeMounts for the Redis® metrics sidecar", - "default": [], - "items": {} - }, - "resourcesPreset": { - "type": "string", - "description": "Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if metrics.resources is set (metrics.resources is recommended for production).", - "default": "nano" - }, - "resources": { - "type": "object", - "description": "Set container requests and limits for different resources like CPU or memory (essential for production workloads)", - "default": {} - }, - "podLabels": { - "type": "object", - "description": "Extra labels for Redis® exporter pods", - "default": {} - }, - "service": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Create Service resource(s) for scraping metrics using PrometheusOperator ServiceMonitor, can be disabled when using a PodMonitor", - "default": true - }, - "type": { - "type": "string", - "description": "Redis® exporter service type", - "default": "ClusterIP" - }, - "ports": { - "type": "object", - "properties": { - "http": { - "type": "number", - "description": "Redis® exporter service port", - "default": 9121 - } - } - }, - "externalTrafficPolicy": { - "type": "string", - "description": "Redis® exporter service external traffic policy", - "default": "Cluster" - }, - "extraPorts": { - "type": "array", - "description": "Extra ports to expose (normally used with the `sidecar` value)", - "default": [], - "items": {} - }, - "loadBalancerIP": { - "type": "string", - "description": "Redis® exporter service Load Balancer IP", - "default": "" - }, - "loadBalancerClass": { - "type": "string", - "description": "exporter service Load Balancer class if service type is `LoadBalancer` (optional, cloud specific)", - "default": "" - }, - "loadBalancerSourceRanges": { - "type": "array", - "description": "Redis® exporter service Load Balancer sources", - "default": [], - "items": {} - }, - "annotations": { - "type": "object", - "description": "Additional custom annotations for Redis® exporter service", - "default": {} - }, - "clusterIP": { - "type": "string", - "description": "Redis® exporter service Cluster IP", - "default": "" - } - } - }, - "serviceMonitor": { - "type": "object", - "properties": { - "port": { - "type": "string", - "description": "the service port to scrape metrics from", - "default": "http-metrics" - }, - "enabled": { - "type": "boolean", - "description": "Create ServiceMonitor resource(s) for scraping metrics using PrometheusOperator", - "default": false - }, - "namespace": { - "type": "string", - "description": "The namespace in which the ServiceMonitor will be created", - "default": "" - }, - "interval": { - "type": "string", - "description": "The interval at which metrics should be scraped", - "default": "30s" - }, - "scrapeTimeout": { - "type": "string", - "description": "The timeout after which the scrape is ended", - "default": "" - }, - "relabelings": { - "type": "array", - "description": "Metrics RelabelConfigs to apply to samples before scraping.", - "default": [], - "items": {} - }, - "metricRelabelings": { - "type": "array", - "description": "Metrics RelabelConfigs to apply to samples before ingestion.", - "default": [], - "items": {} - }, - "honorLabels": { - "type": "boolean", - "description": "Specify honorLabels parameter to add the scrape endpoint", - "default": false - }, - "additionalLabels": { - "type": "object", - "description": "Additional labels that can be used so ServiceMonitor resource(s) can be discovered by Prometheus", - "default": {} - }, - "podTargetLabels": { - "type": "array", - "description": "Labels from the Kubernetes pod to be transferred to the created metrics", - "default": [], - "items": {} - }, - "sampleLimit": { - "type": "boolean", - "description": "Limit of how many samples should be scraped from every Pod", - "default": false - }, - "targetLimit": { - "type": "boolean", - "description": "Limit of how many targets should be scraped", - "default": false - }, - "additionalEndpoints": { - "type": "array", - "description": "Additional endpoints to scrape (e.g sentinel)", - "default": [], - "items": {} - } - } - }, - "podMonitor": { - "type": "object", - "properties": { - "port": { - "type": "string", - "description": "the pod port to scrape metrics from", - "default": "metrics" - }, - "enabled": { - "type": "boolean", - "description": "Create PodMonitor resource(s) for scraping metrics using PrometheusOperator", - "default": false - }, - "namespace": { - "type": "string", - "description": "The namespace in which the PodMonitor will be created", - "default": "" - }, - "interval": { - "type": "string", - "description": "The interval at which metrics should be scraped", - "default": "30s" - }, - "scrapeTimeout": { - "type": "string", - "description": "The timeout after which the scrape is ended", - "default": "" - }, - "relabelings": { - "type": "array", - "description": "Metrics RelabelConfigs to apply to samples before scraping.", - "default": [], - "items": {} - }, - "metricRelabelings": { - "type": "array", - "description": "Metrics RelabelConfigs to apply to samples before ingestion.", - "default": [], - "items": {} - }, - "honorLabels": { - "type": "boolean", - "description": "Specify honorLabels parameter to add the scrape endpoint", - "default": false - }, - "additionalLabels": { - "type": "object", - "description": "Additional labels that can be used so PodMonitor resource(s) can be discovered by Prometheus", - "default": {} - }, - "podTargetLabels": { - "type": "array", - "description": "Labels from the Kubernetes pod to be transferred to the created metrics", - "default": [], - "items": {} - }, - "sampleLimit": { - "type": "boolean", - "description": "Limit of how many samples should be scraped from every Pod", - "default": false - }, - "targetLimit": { - "type": "boolean", - "description": "Limit of how many targets should be scraped", - "default": false - }, - "additionalEndpoints": { - "type": "array", - "description": "Additional endpoints to scrape (e.g sentinel)", - "default": [], - "items": {} - } - } - }, - "prometheusRule": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Create a custom prometheusRule Resource for scraping metrics using PrometheusOperator", - "default": false - }, - "namespace": { - "type": "string", - "description": "The namespace in which the prometheusRule will be created", - "default": "" - }, - "additionalLabels": { - "type": "object", - "description": "Additional labels for the prometheusRule", - "default": {} - }, - "rules": { - "type": "array", - "description": "Custom Prometheus rules", - "default": [], - "items": {} - } - } - } - } - }, - "volumePermissions": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable init container that changes the owner/group of the PV mount point to `runAsUser:fsGroup`", - "default": false - }, - "image": { - "type": "object", - "properties": { - "registry": { - "type": "string", - "description": "OS Shell + Utility image registry", - "default": "REGISTRY_NAME" - }, - "repository": { - "type": "string", - "description": "OS Shell + Utility image repository", - "default": "REPOSITORY_NAME/os-shell" - }, - "digest": { - "type": "string", - "description": "OS Shell + Utility image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag", - "default": "" - }, - "pullPolicy": { - "type": "string", - "description": "OS Shell + Utility image pull policy", - "default": "IfNotPresent" - }, - "pullSecrets": { - "type": "array", - "description": "OS Shell + Utility image pull secrets", - "default": [], - "items": {} - } - } - }, - "resourcesPreset": { - "type": "string", - "description": "Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if volumePermissions.resources is set (volumePermissions.resources is recommended for production).", - "default": "nano" - }, - "resources": { - "type": "object", - "description": "Set container requests and limits for different resources like CPU or memory (essential for production workloads)", - "default": {} - }, - "containerSecurityContext": { - "type": "object", - "properties": { - "runAsUser": { - "type": "number", - "description": "Set init container's Security Context runAsUser", - "default": 0 - } - } - } - } - }, - "kubectl": { - "type": "object", - "properties": { - "image": { - "type": "object", - "properties": { - "registry": { - "type": "string", - "description": "Kubectl image registry", - "default": "REGISTRY_NAME" - }, - "repository": { - "type": "string", - "description": "Kubectl image repository", - "default": "REPOSITORY_NAME/kubectl" - }, - "digest": { - "type": "string", - "description": "Kubectl image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag", - "default": "" - }, - "pullPolicy": { - "type": "string", - "description": "Kubectl image pull policy", - "default": "IfNotPresent" - }, - "pullSecrets": { - "type": "array", - "description": "Kubectl pull secrets", - "default": [], - "items": {} - } - } - }, - "command": { - "type": "array", - "description": "kubectl command to execute", - "default": [ - "/opt/bitnami/scripts/kubectl-scripts/update-master-label.sh" - ], - "items": { - "type": "string" - } - }, - "containerSecurityContext": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enabled kubectl containers' Security Context", - "default": true - }, - "runAsUser": { - "type": "number", - "description": "Set kubectl containers' Security Context runAsUser", - "default": 1001 - }, - "runAsGroup": { - "type": "number", - "description": "Set kubectl containers' Security Context runAsGroup", - "default": 1001 - }, - "runAsNonRoot": { - "type": "boolean", - "description": "Set kubectl containers' Security Context runAsNonRoot", - "default": true - }, - "allowPrivilegeEscalation": { - "type": "boolean", - "description": "Set kubectl containers' Security Context allowPrivilegeEscalation", - "default": false - }, - "readOnlyRootFilesystem": { - "type": "boolean", - "description": "Set container's Security Context read-only root filesystem", - "default": true - }, - "seccompProfile": { - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "Set kubectl containers' Security Context seccompProfile", - "default": "RuntimeDefault" - } - } - }, - "capabilities": { - "type": "object", - "properties": { - "drop": { - "type": "array", - "description": "Set kubectl containers' Security Context capabilities to drop", - "default": [ - "ALL" - ], - "items": { - "type": "string" - } - } - } - } - } - }, - "resources": { - "type": "object", - "properties": { - "limits": { - "type": "object", - "description": "The resources limits for the kubectl containers", - "default": {} - }, - "requests": { - "type": "object", - "description": "The requested resources for the kubectl containers", - "default": {} - } - } - } - } - }, - "sysctl": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable init container to modify Kernel settings", - "default": false - }, - "image": { - "type": "object", - "properties": { - "registry": { - "type": "string", - "description": "OS Shell + Utility image registry", - "default": "REGISTRY_NAME" - }, - "repository": { - "type": "string", - "description": "OS Shell + Utility image repository", - "default": "REPOSITORY_NAME/os-shell" - }, - "digest": { - "type": "string", - "description": "OS Shell + Utility image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag", - "default": "" - }, - "pullPolicy": { - "type": "string", - "description": "OS Shell + Utility image pull policy", - "default": "IfNotPresent" - }, - "pullSecrets": { - "type": "array", - "description": "OS Shell + Utility image pull secrets", - "default": [], - "items": {} - } - } - }, - "command": { - "type": "array", - "description": "Override default init-sysctl container command (useful when using custom images)", - "default": [], - "items": {} - }, - "mountHostSys": { - "type": "boolean", - "description": "Mount the host `/sys` folder to `/host-sys`", - "default": false - }, - "resourcesPreset": { - "type": "string", - "description": "Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if sysctl.resources is set (sysctl.resources is recommended for production).", - "default": "nano" - }, - "resources": { - "type": "object", - "description": "Set container requests and limits for different resources like CPU or memory (essential for production workloads)", - "default": {} - } - } - }, - "useExternalDNS": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Enable various syntax that would enable external-dns to work. Note this requires a working installation of `external-dns` to be usable.", - "default": false - }, - "additionalAnnotations": { - "type": "object", - "description": "Extra annotations to be utilized when `external-dns` is enabled.", - "default": {} - }, - "annotationKey": { - "type": "string", - "description": "The annotation key utilized when `external-dns` is enabled. Setting this to `false` will disable annotations.", - "default": "external-dns.alpha.kubernetes.io/" - }, - "suffix": { - "type": "string", - "description": "The DNS suffix utilized when `external-dns` is enabled. Note that we prepend the suffix with the full name of the release.", - "default": "" - } - } - } - } -} \ No newline at end of file diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/values.yaml b/packages/system/dashboard/charts/kubeapps/charts/redis/values.yaml deleted file mode 100644 index 09874845..00000000 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/values.yaml +++ /dev/null @@ -1,2254 +0,0 @@ -# Copyright Broadcom, Inc. All Rights Reserved. -# SPDX-License-Identifier: APACHE-2.0 - -## @section Global parameters -## Global Docker image parameters -## Please, note that this will override the image parameters, including dependencies, configured to use the global value -## Current available global Docker image parameters: imageRegistry, imagePullSecrets and storageClass -## - -## @param global.imageRegistry Global Docker image registry -## @param global.imagePullSecrets Global Docker registry secret names as an array -## @param global.defaultStorageClass Global default StorageClass for Persistent Volume(s) -## @param global.storageClass DEPRECATED: use global.defaultStorageClass instead -## @param global.redis.password Global Redis® password (overrides `auth.password`) -## -global: - imageRegistry: "" - ## E.g. - ## imagePullSecrets: - ## - myRegistryKeySecretName - ## - imagePullSecrets: [] - defaultStorageClass: "" - storageClass: "" - redis: - password: "" - ## Compatibility adaptations for Kubernetes platforms - ## - compatibility: - ## Compatibility adaptations for Openshift - ## - openshift: - ## @param global.compatibility.openshift.adaptSecurityContext Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation) - ## - adaptSecurityContext: auto -## @section Common parameters -## - -## @param kubeVersion Override Kubernetes version -## -kubeVersion: "" -## @param nameOverride String to partially override common.names.fullname -## -nameOverride: "" -## @param fullnameOverride String to fully override common.names.fullname -## -fullnameOverride: "" -## @param namespaceOverride String to fully override common.names.namespace -## -namespaceOverride: "" -## @param commonLabels Labels to add to all deployed objects -## -commonLabels: {} -## @param commonAnnotations Annotations to add to all deployed objects -## -commonAnnotations: {} -## @param secretAnnotations Annotations to add to secret -## -secretAnnotations: {} -## @param clusterDomain Kubernetes cluster domain name -## -clusterDomain: cluster.local -## @param extraDeploy Array of extra objects to deploy with the release -## -extraDeploy: [] -## @param useHostnames Use hostnames internally when announcing replication. If false, the hostname will be resolved to an IP address -## -useHostnames: true -## @param nameResolutionThreshold Failure threshold for internal hostnames resolution -## -nameResolutionThreshold: 5 -## @param nameResolutionTimeout Timeout seconds between probes for internal hostnames resolution -## -nameResolutionTimeout: 5 -## Enable diagnostic mode in the deployment -## -diagnosticMode: - ## @param diagnosticMode.enabled Enable diagnostic mode (all probes will be disabled and the command will be overridden) - ## - enabled: false - ## @param diagnosticMode.command Command to override all containers in the deployment - ## - command: - - sleep - ## @param diagnosticMode.args Args to override all containers in the deployment - ## - args: - - infinity -## @section Redis® Image parameters -## - -## Bitnami Redis® image -## ref: https://hub.docker.com/r/bitnami/redis/tags/ -## @param image.registry [default: REGISTRY_NAME] Redis® image registry -## @param image.repository [default: REPOSITORY_NAME/redis] Redis® image repository -## @skip image.tag Redis® image tag (immutable tags are recommended) -## @param image.digest Redis® image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag -## @param image.pullPolicy Redis® image pull policy -## @param image.pullSecrets Redis® image pull secrets -## @param image.debug Enable image debug mode -## -image: - registry: docker.io - repository: bitnami/redis - tag: 7.4.1-debian-12-r0 - digest: "" - ## Specify a imagePullPolicy - ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' - ## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images - ## - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## Enable debug mode - ## - debug: false -## @section Redis® common configuration parameters -## https://github.com/bitnami/containers/tree/main/bitnami/redis#configuration -## - -## @param architecture Redis® architecture. Allowed values: `standalone` or `replication` -## -architecture: replication -## Redis® Authentication parameters -## ref: https://github.com/bitnami/containers/tree/main/bitnami/redis#setting-the-server-password-on-first-run -## -auth: - ## @param auth.enabled Enable password authentication - ## - enabled: true - ## @param auth.sentinel Enable password authentication on sentinels too - ## - sentinel: true - ## @param auth.password Redis® password - ## Defaults to a random 10-character alphanumeric string if not set - ## - password: "" - ## @param auth.existingSecret The name of an existing secret with Redis® credentials - ## NOTE: When it's set, the previous `auth.password` parameter is ignored - ## - existingSecret: "" - ## @param auth.existingSecretPasswordKey Password key to be retrieved from existing secret - ## NOTE: ignored unless `auth.existingSecret` parameter is set - ## - existingSecretPasswordKey: "" - ## @param auth.usePasswordFiles Mount credentials as files instead of using an environment variable - ## - usePasswordFiles: false - ## @param auth.usePasswordFileFromSecret Mount password file from secret - ## - usePasswordFileFromSecret: true -## @param commonConfiguration [string] Common configuration to be added into the ConfigMap -## ref: https://redis.io/topics/config -## -commonConfiguration: |- - # Enable AOF https://redis.io/topics/persistence#append-only-file - appendonly yes - # Disable RDB persistence, AOF persistence already enabled. - save "" -## @param existingConfigmap The name of an existing ConfigMap with your custom configuration for Redis® nodes -## -existingConfigmap: "" -## @section Redis® master configuration parameters -## -master: - ## @param master.count Number of Redis® master instances to deploy (experimental, requires additional configuration) - ## - count: 1 - ## @param master.revisionHistoryLimit The number of old history to retain to allow rollback - ## NOTE: Explicitly setting this field to 0, will result in cleaning up all the history, breaking ability to rollback - revisionHistoryLimit: 10 - ## @param master.configuration Configuration for Redis® master nodes - ## ref: https://redis.io/topics/config - ## - configuration: "" - ## @param master.disableCommands Array with Redis® commands to disable on master nodes - ## Commands will be completely disabled by renaming each to an empty string. - ## ref: https://redis.io/topics/security#disabling-of-specific-commands - ## - disableCommands: - - FLUSHDB - - FLUSHALL - ## @param master.command Override default container command (useful when using custom images) - ## - command: [] - ## @param master.args Override default container args (useful when using custom images) - ## - args: [] - ## @param master.enableServiceLinks Whether information about services should be injected into pod's environment variable - ## - enableServiceLinks: true - ## @param master.preExecCmds Additional commands to run prior to starting Redis® master - ## - preExecCmds: [] - ## @param master.extraFlags Array with additional command line flags for Redis® master - ## e.g: - ## extraFlags: - ## - "--maxmemory-policy volatile-ttl" - ## - "--repl-backlog-size 1024mb" - ## - extraFlags: [] - ## @param master.extraEnvVars Array with extra environment variables to add to Redis® master nodes - ## e.g: - ## extraEnvVars: - ## - name: FOO - ## value: "bar" - ## - extraEnvVars: [] - ## @param master.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for Redis® master nodes - ## - extraEnvVarsCM: "" - ## @param master.extraEnvVarsSecret Name of existing Secret containing extra env vars for Redis® master nodes - ## - extraEnvVarsSecret: "" - ## @param master.containerPorts.redis Container port to open on Redis® master nodes - ## - containerPorts: - redis: 6379 - ## Configure extra options for Redis® containers' liveness and readiness probes - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes - ## @param master.startupProbe.enabled Enable startupProbe on Redis® master nodes - ## @param master.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe - ## @param master.startupProbe.periodSeconds Period seconds for startupProbe - ## @param master.startupProbe.timeoutSeconds Timeout seconds for startupProbe - ## @param master.startupProbe.failureThreshold Failure threshold for startupProbe - ## @param master.startupProbe.successThreshold Success threshold for startupProbe - ## - startupProbe: - enabled: false - initialDelaySeconds: 20 - periodSeconds: 5 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 5 - ## @param master.livenessProbe.enabled Enable livenessProbe on Redis® master nodes - ## @param master.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe - ## @param master.livenessProbe.periodSeconds Period seconds for livenessProbe - ## @param master.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe - ## @param master.livenessProbe.failureThreshold Failure threshold for livenessProbe - ## @param master.livenessProbe.successThreshold Success threshold for livenessProbe - ## - livenessProbe: - enabled: true - initialDelaySeconds: 20 - periodSeconds: 5 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 5 - ## @param master.readinessProbe.enabled Enable readinessProbe on Redis® master nodes - ## @param master.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe - ## @param master.readinessProbe.periodSeconds Period seconds for readinessProbe - ## @param master.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe - ## @param master.readinessProbe.failureThreshold Failure threshold for readinessProbe - ## @param master.readinessProbe.successThreshold Success threshold for readinessProbe - ## - readinessProbe: - enabled: true - initialDelaySeconds: 20 - periodSeconds: 5 - timeoutSeconds: 1 - successThreshold: 1 - failureThreshold: 5 - ## @param master.customStartupProbe Custom startupProbe that overrides the default one - ## - customStartupProbe: {} - ## @param master.customLivenessProbe Custom livenessProbe that overrides the default one - ## - customLivenessProbe: {} - ## @param master.customReadinessProbe Custom readinessProbe that overrides the default one - ## - customReadinessProbe: {} - ## Redis® master resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - ## @param master.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if master.resources is set (master.resources is recommended for production). - ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 - ## - resourcesPreset: "nano" - ## @param master.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - ## Example: - ## resources: - ## requests: - ## cpu: 2 - ## memory: 512Mi - ## limits: - ## cpu: 3 - ## memory: 1024Mi - ## - resources: {} - ## Configure Pods Security Context - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod - ## @param master.podSecurityContext.enabled Enabled Redis® master pods' Security Context - ## @param master.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy - ## @param master.podSecurityContext.sysctls Set kernel settings using the sysctl interface - ## @param master.podSecurityContext.supplementalGroups Set filesystem extra groups - ## @param master.podSecurityContext.fsGroup Set Redis® master pod's Security Context fsGroup - ## - podSecurityContext: - enabled: true - fsGroupChangePolicy: Always - sysctls: [] - supplementalGroups: [] - fsGroup: 1001 - ## Configure Container Security Context - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod - ## @param master.containerSecurityContext.enabled Enabled Redis® master containers' Security Context - ## @param master.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container - ## @param master.containerSecurityContext.runAsUser Set Redis® master containers' Security Context runAsUser - ## @param master.containerSecurityContext.runAsGroup Set Redis® master containers' Security Context runAsGroup - ## @param master.containerSecurityContext.runAsNonRoot Set Redis® master containers' Security Context runAsNonRoot - ## @param master.containerSecurityContext.allowPrivilegeEscalation Is it possible to escalate Redis® pod(s) privileges - ## @param master.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context read-only root filesystem - ## @param master.containerSecurityContext.seccompProfile.type Set Redis® master containers' Security Context seccompProfile - ## @param master.containerSecurityContext.capabilities.drop Set Redis® master containers' Security Context capabilities to drop - ## - containerSecurityContext: - enabled: true - seLinuxOptions: {} - runAsUser: 1001 - runAsGroup: 1001 - runAsNonRoot: true - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - seccompProfile: - type: RuntimeDefault - capabilities: - drop: ["ALL"] - ## @param master.kind Use either Deployment, StatefulSet (default) or DaemonSet - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/ - ## - kind: StatefulSet - ## @param master.schedulerName Alternate scheduler for Redis® master pods - ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ - ## - schedulerName: "" - ## @param master.updateStrategy.type Redis® master statefulset strategy type - ## @skip master.updateStrategy.rollingUpdate - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies - ## - updateStrategy: - ## StrategyType - ## Can be set to RollingUpdate, OnDelete (statefulset), Recreate (deployment) - ## - type: RollingUpdate - ## @param master.minReadySeconds How many seconds a pod needs to be ready before killing the next, during update - ## - minReadySeconds: 0 - ## @param master.priorityClassName Redis® master pods' priorityClassName - ## - priorityClassName: "" - ## @param master.automountServiceAccountToken Mount Service Account token in pod - ## - automountServiceAccountToken: false - ## @param master.hostAliases Redis® master pods host aliases - ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ - ## - hostAliases: [] - ## @param master.podLabels Extra labels for Redis® master pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ - ## - podLabels: {} - ## @param master.podAnnotations Annotations for Redis® master pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ - ## - podAnnotations: {} - ## @param master.shareProcessNamespace Share a single process namespace between all of the containers in Redis® master pods - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/ - ## - shareProcessNamespace: false - ## @param master.podAffinityPreset Pod affinity preset. Ignored if `master.affinity` is set. Allowed values: `soft` or `hard` - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity - ## - podAffinityPreset: "" - ## @param master.podAntiAffinityPreset Pod anti-affinity preset. Ignored if `master.affinity` is set. Allowed values: `soft` or `hard` - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity - ## - podAntiAffinityPreset: soft - ## Node master.affinity preset - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity - ## - nodeAffinityPreset: - ## @param master.nodeAffinityPreset.type Node affinity preset type. Ignored if `master.affinity` is set. Allowed values: `soft` or `hard` - ## - type: "" - ## @param master.nodeAffinityPreset.key Node label key to match. Ignored if `master.affinity` is set - ## - key: "" - ## @param master.nodeAffinityPreset.values Node label values to match. Ignored if `master.affinity` is set - ## E.g. - ## values: - ## - e2e-az1 - ## - e2e-az2 - ## - values: [] - ## @param master.affinity Affinity for Redis® master pods assignment - ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity - ## NOTE: `master.podAffinityPreset`, `master.podAntiAffinityPreset`, and `master.nodeAffinityPreset` will be ignored when it's set - ## - affinity: {} - ## @param master.nodeSelector Node labels for Redis® master pods assignment - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ - ## - nodeSelector: {} - ## @param master.tolerations Tolerations for Redis® master pods assignment - ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ - ## - tolerations: [] - ## @param master.topologySpreadConstraints Spread Constraints for Redis® master pod assignment - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - ## E.g. - ## topologySpreadConstraints: - ## - maxSkew: 1 - ## topologyKey: node - ## whenUnsatisfiable: DoNotSchedule - ## - topologySpreadConstraints: [] - ## @param master.dnsPolicy DNS Policy for Redis® master pod - ## ref: https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/ - ## E.g. - ## dnsPolicy: ClusterFirst - ## - dnsPolicy: "" - ## @param master.dnsConfig DNS Configuration for Redis® master pod - ## ref: https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/ - ## E.g. - ## dnsConfig: - ## options: - ## - name: ndots - ## value: "4" - ## - name: single-request-reopen - ## - dnsConfig: {} - ## @param master.lifecycleHooks for the Redis® master container(s) to automate configuration before or after startup - ## - lifecycleHooks: {} - ## @param master.extraVolumes Optionally specify extra list of additional volumes for the Redis® master pod(s) - ## - extraVolumes: [] - ## @param master.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the Redis® master container(s) - ## - extraVolumeMounts: [] - ## @param master.sidecars Add additional sidecar containers to the Redis® master pod(s) - ## e.g: - ## sidecars: - ## - name: your-image-name - ## image: your-image - ## imagePullPolicy: Always - ## ports: - ## - name: portname - ## containerPort: 1234 - ## - sidecars: [] - ## @param master.initContainers Add additional init containers to the Redis® master pod(s) - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - ## e.g: - ## initContainers: - ## - name: your-image-name - ## image: your-image - ## imagePullPolicy: Always - ## command: ['sh', '-c', 'echo "hello world"'] - ## - initContainers: [] - ## Persistence parameters - ## ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/ - ## - persistence: - ## @param master.persistence.enabled Enable persistence on Redis® master nodes using Persistent Volume Claims - ## - enabled: true - ## @param master.persistence.medium Provide a medium for `emptyDir` volumes. - ## - medium: "" - ## @param master.persistence.sizeLimit Set this to enable a size limit for `emptyDir` volumes. - ## - sizeLimit: "" - ## @param master.persistence.path The path the volume will be mounted at on Redis® master containers - ## NOTE: Useful when using different Redis® images - ## - path: /data - ## @param master.persistence.subPath The subdirectory of the volume to mount on Redis® master containers - ## NOTE: Useful in dev environments - ## - subPath: "" - ## @param master.persistence.subPathExpr Used to construct the subPath subdirectory of the volume to mount on Redis® master containers - ## - subPathExpr: "" - ## @param master.persistence.storageClass Persistent Volume storage class - ## If defined, storageClassName: - ## If set to "-", storageClassName: "", which disables dynamic provisioning - ## If undefined (the default) or set to null, no storageClassName spec is set, choosing the default provisioner - ## - storageClass: "" - ## @param master.persistence.accessModes Persistent Volume access modes - ## - accessModes: - - ReadWriteOnce - ## @param master.persistence.size Persistent Volume size - ## - size: 8Gi - ## @param master.persistence.annotations Additional custom annotations for the PVC - ## - annotations: {} - ## @param master.persistence.labels Additional custom labels for the PVC - ## - labels: {} - ## @param master.persistence.selector Additional labels to match for the PVC - ## e.g: - ## selector: - ## matchLabels: - ## app: my-app - ## - selector: {} - ## @param master.persistence.dataSource Custom PVC data source - ## - dataSource: {} - ## @param master.persistence.existingClaim Use a existing PVC which must be created manually before bound - ## NOTE: requires master.persistence.enabled: true - ## - existingClaim: "" - ## persistentVolumeClaimRetentionPolicy - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#persistentvolumeclaim-retention - ## @param master.persistentVolumeClaimRetentionPolicy.enabled Controls if and how PVCs are deleted during the lifecycle of a StatefulSet - ## @param master.persistentVolumeClaimRetentionPolicy.whenScaled Volume retention behavior when the replica count of the StatefulSet is reduced - ## @param master.persistentVolumeClaimRetentionPolicy.whenDeleted Volume retention behavior that applies when the StatefulSet is deleted - ## - persistentVolumeClaimRetentionPolicy: - enabled: false - whenScaled: Retain - whenDeleted: Retain - ## Redis® master service parameters - ## - service: - ## @param master.service.type Redis® master service type - ## - type: ClusterIP - ## @param master.service.portNames.redis Redis® master service port name - ## - portNames: - redis: "tcp-redis" - ## @param master.service.ports.redis Redis® master service port - ## - ports: - redis: 6379 - ## @param master.service.nodePorts.redis Node port for Redis® master - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport - ## NOTE: choose port between <30000-32767> - ## - nodePorts: - redis: "" - ## @param master.service.externalTrafficPolicy Redis® master service external traffic policy - ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip - ## - externalTrafficPolicy: Cluster - ## @param master.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) - ## - extraPorts: [] - ## @param master.service.internalTrafficPolicy Redis® master service internal traffic policy (requires Kubernetes v1.22 or greater to be usable) - ## ref: https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/ - ## - internalTrafficPolicy: Cluster - ## @param master.service.clusterIP Redis® master service Cluster IP - ## - clusterIP: "" - ## @param master.service.loadBalancerIP Redis® master service Load Balancer IP - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer - ## - loadBalancerIP: "" - ## @param master.service.loadBalancerClass master service Load Balancer class if service type is `LoadBalancer` (optional, cloud specific) - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-loadbalancer - ## - loadBalancerClass: "" - ## @param master.service.loadBalancerSourceRanges Redis® master service Load Balancer sources - ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service - ## e.g. - ## loadBalancerSourceRanges: - ## - 10.10.10.0/24 - ## - loadBalancerSourceRanges: [] - ## @param master.service.externalIPs Redis® master service External IPs - ## https://kubernetes.io/docs/concepts/services-networking/service/#external-ips - ## e.g. - ## externalIPs: - ## - 10.10.10.1 - ## - 201.22.30.1 - ## - externalIPs: [] - ## @param master.service.annotations Additional custom annotations for Redis® master service - ## - annotations: {} - ## @param master.service.sessionAffinity Session Affinity for Kubernetes service, can be "None" or "ClientIP" - ## If "ClientIP", consecutive client requests will be directed to the same Pod - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies - ## - sessionAffinity: None - ## @param master.service.sessionAffinityConfig Additional settings for the sessionAffinity - ## sessionAffinityConfig: - ## clientIP: - ## timeoutSeconds: 300 - ## - sessionAffinityConfig: {} - ## @param master.terminationGracePeriodSeconds Integer setting the termination grace period for the redis-master pods - ## - terminationGracePeriodSeconds: 30 - ## ServiceAccount configuration - ## - serviceAccount: - ## @param master.serviceAccount.create Specifies whether a ServiceAccount should be created - ## - create: true - ## @param master.serviceAccount.name The name of the ServiceAccount to use. - ## If not set and create is true, a name is generated using the common.names.fullname template - ## - name: "" - ## @param master.serviceAccount.automountServiceAccountToken Whether to auto mount the service account token - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server - ## - automountServiceAccountToken: false - ## @param master.serviceAccount.annotations Additional custom annotations for the ServiceAccount - ## - annotations: {} - ## Pod Disruption Budget configuration - ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb - ## @param master.pdb.create Enable/disable a Pod Disruption Budget creation - ## @param master.pdb.minAvailable [object] Minimum number/percentage of pods that should remain scheduled - ## @param master.pdb.maxUnavailable [object] Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `master.pdb.minAvailable` and `master.pdb.maxUnavailable` are empty. - ## - pdb: - create: true - minAvailable: "" - maxUnavailable: "" - ## @param master.extraPodSpec Optionally specify extra PodSpec for the Redis® master pod(s) - ## - extraPodSpec: {} -## @section Redis® replicas configuration parameters -## -replica: - ## @param replica.kind Use either DaemonSet or StatefulSet (default) - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/ - ## - kind: StatefulSet - ## @param replica.replicaCount Number of Redis® replicas to deploy - ## - replicaCount: 3 - ## @param replica.revisionHistoryLimit The number of old history to retain to allow rollback - ## NOTE: Explicitly setting this field to 0, will result in cleaning up all the history, breaking ability to rollback - revisionHistoryLimit: 10 - ## @param replica.configuration Configuration for Redis® replicas nodes - ## ref: https://redis.io/topics/config - ## - configuration: "" - ## @param replica.disableCommands Array with Redis® commands to disable on replicas nodes - ## Commands will be completely disabled by renaming each to an empty string. - ## ref: https://redis.io/topics/security#disabling-of-specific-commands - ## - disableCommands: - - FLUSHDB - - FLUSHALL - ## @param replica.command Override default container command (useful when using custom images) - ## - command: [] - ## @param replica.args Override default container args (useful when using custom images) - ## - args: [] - ## @param replica.enableServiceLinks Whether information about services should be injected into pod's environment variable - ## - enableServiceLinks: true - ## @param replica.preExecCmds Additional commands to run prior to starting Redis® replicas - ## - preExecCmds: [] - ## @param replica.extraFlags Array with additional command line flags for Redis® replicas - ## e.g: - ## extraFlags: - ## - "--maxmemory-policy volatile-ttl" - ## - "--repl-backlog-size 1024mb" - ## - extraFlags: [] - ## @param replica.extraEnvVars Array with extra environment variables to add to Redis® replicas nodes - ## e.g: - ## extraEnvVars: - ## - name: FOO - ## value: "bar" - ## - extraEnvVars: [] - ## @param replica.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for Redis® replicas nodes - ## - extraEnvVarsCM: "" - ## @param replica.extraEnvVarsSecret Name of existing Secret containing extra env vars for Redis® replicas nodes - ## - extraEnvVarsSecret: "" - ## @param replica.externalMaster.enabled Use external master for bootstrapping - ## @param replica.externalMaster.host External master host to bootstrap from - ## @param replica.externalMaster.port Port for Redis service external master host - ## - externalMaster: - enabled: false - host: "" - port: 6379 - ## @param replica.containerPorts.redis Container port to open on Redis® replicas nodes - ## - containerPorts: - redis: 6379 - ## Configure extra options for Redis® containers' liveness and readiness probes - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes - ## @param replica.startupProbe.enabled Enable startupProbe on Redis® replicas nodes - ## @param replica.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe - ## @param replica.startupProbe.periodSeconds Period seconds for startupProbe - ## @param replica.startupProbe.timeoutSeconds Timeout seconds for startupProbe - ## @param replica.startupProbe.failureThreshold Failure threshold for startupProbe - ## @param replica.startupProbe.successThreshold Success threshold for startupProbe - ## - startupProbe: - enabled: true - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 22 - ## @param replica.livenessProbe.enabled Enable livenessProbe on Redis® replicas nodes - ## @param replica.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe - ## @param replica.livenessProbe.periodSeconds Period seconds for livenessProbe - ## @param replica.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe - ## @param replica.livenessProbe.failureThreshold Failure threshold for livenessProbe - ## @param replica.livenessProbe.successThreshold Success threshold for livenessProbe - ## - livenessProbe: - enabled: true - initialDelaySeconds: 20 - periodSeconds: 5 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 5 - ## @param replica.readinessProbe.enabled Enable readinessProbe on Redis® replicas nodes - ## @param replica.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe - ## @param replica.readinessProbe.periodSeconds Period seconds for readinessProbe - ## @param replica.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe - ## @param replica.readinessProbe.failureThreshold Failure threshold for readinessProbe - ## @param replica.readinessProbe.successThreshold Success threshold for readinessProbe - ## - readinessProbe: - enabled: true - initialDelaySeconds: 20 - periodSeconds: 5 - timeoutSeconds: 1 - successThreshold: 1 - failureThreshold: 5 - ## @param replica.customStartupProbe Custom startupProbe that overrides the default one - ## - customStartupProbe: {} - ## @param replica.customLivenessProbe Custom livenessProbe that overrides the default one - ## - customLivenessProbe: {} - ## @param replica.customReadinessProbe Custom readinessProbe that overrides the default one - ## - customReadinessProbe: {} - ## Redis® replicas resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - ## @param replica.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if replica.resources is set (replica.resources is recommended for production). - ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 - ## - resourcesPreset: "nano" - ## @param replica.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - ## Example: - ## resources: - ## requests: - ## cpu: 2 - ## memory: 512Mi - ## limits: - ## cpu: 3 - ## memory: 1024Mi - ## - resources: {} - ## Configure Pods Security Context - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod - ## @param replica.podSecurityContext.enabled Enabled Redis® replicas pods' Security Context - ## @param replica.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy - ## @param replica.podSecurityContext.sysctls Set kernel settings using the sysctl interface - ## @param replica.podSecurityContext.supplementalGroups Set filesystem extra groups - ## @param replica.podSecurityContext.fsGroup Set Redis® replicas pod's Security Context fsGroup - ## - podSecurityContext: - enabled: true - fsGroupChangePolicy: Always - sysctls: [] - supplementalGroups: [] - fsGroup: 1001 - ## Configure Container Security Context - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod - ## @param replica.containerSecurityContext.enabled Enabled Redis® replicas containers' Security Context - ## @param replica.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container - ## @param replica.containerSecurityContext.runAsUser Set Redis® replicas containers' Security Context runAsUser - ## @param replica.containerSecurityContext.runAsGroup Set Redis® replicas containers' Security Context runAsGroup - ## @param replica.containerSecurityContext.runAsNonRoot Set Redis® replicas containers' Security Context runAsNonRoot - ## @param replica.containerSecurityContext.allowPrivilegeEscalation Set Redis® replicas pod's Security Context allowPrivilegeEscalation - ## @param replica.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context read-only root filesystem - ## @param replica.containerSecurityContext.seccompProfile.type Set Redis® replicas containers' Security Context seccompProfile - ## @param replica.containerSecurityContext.capabilities.drop Set Redis® replicas containers' Security Context capabilities to drop - ## - containerSecurityContext: - enabled: true - seLinuxOptions: {} - runAsUser: 1001 - runAsGroup: 1001 - runAsNonRoot: true - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - seccompProfile: - type: RuntimeDefault - capabilities: - drop: ["ALL"] - ## @param replica.schedulerName Alternate scheduler for Redis® replicas pods - ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ - ## - schedulerName: "" - ## @param replica.updateStrategy.type Redis® replicas statefulset strategy type - ## @skip replica.updateStrategy.rollingUpdate - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies - ## - updateStrategy: - ## StrategyType - ## Can be set to RollingUpdate, OnDelete (statefulset), Recreate (deployment) - ## - type: RollingUpdate - ## @param replica.minReadySeconds How many seconds a pod needs to be ready before killing the next, during update - ## - minReadySeconds: 0 - ## @param replica.priorityClassName Redis® replicas pods' priorityClassName - ## - priorityClassName: "" - ## @param replica.podManagementPolicy podManagementPolicy to manage scaling operation of %%MAIN_CONTAINER_NAME%% pods - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies - ## - podManagementPolicy: "" - ## @param replica.automountServiceAccountToken Mount Service Account token in pod - ## - automountServiceAccountToken: false - ## @param replica.hostAliases Redis® replicas pods host aliases - ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ - ## - hostAliases: [] - ## @param replica.podLabels Extra labels for Redis® replicas pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ - ## - podLabels: {} - ## @param replica.podAnnotations Annotations for Redis® replicas pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ - ## - podAnnotations: {} - ## @param replica.shareProcessNamespace Share a single process namespace between all of the containers in Redis® replicas pods - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/ - ## - shareProcessNamespace: false - ## @param replica.podAffinityPreset Pod affinity preset. Ignored if `replica.affinity` is set. Allowed values: `soft` or `hard` - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity - ## - podAffinityPreset: "" - ## @param replica.podAntiAffinityPreset Pod anti-affinity preset. Ignored if `replica.affinity` is set. Allowed values: `soft` or `hard` - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity - ## - podAntiAffinityPreset: soft - ## Node affinity preset - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity - ## - nodeAffinityPreset: - ## @param replica.nodeAffinityPreset.type Node affinity preset type. Ignored if `replica.affinity` is set. Allowed values: `soft` or `hard` - ## - type: "" - ## @param replica.nodeAffinityPreset.key Node label key to match. Ignored if `replica.affinity` is set - ## - key: "" - ## @param replica.nodeAffinityPreset.values Node label values to match. Ignored if `replica.affinity` is set - ## E.g. - ## values: - ## - e2e-az1 - ## - e2e-az2 - ## - values: [] - ## @param replica.affinity Affinity for Redis® replicas pods assignment - ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity - ## NOTE: `replica.podAffinityPreset`, `replica.podAntiAffinityPreset`, and `replica.nodeAffinityPreset` will be ignored when it's set - ## - affinity: {} - ## @param replica.nodeSelector Node labels for Redis® replicas pods assignment - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ - ## - nodeSelector: {} - ## @param replica.tolerations Tolerations for Redis® replicas pods assignment - ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ - ## - tolerations: [] - ## @param replica.topologySpreadConstraints Spread Constraints for Redis® replicas pod assignment - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - ## E.g. - ## topologySpreadConstraints: - ## - maxSkew: 1 - ## topologyKey: node - ## whenUnsatisfiable: DoNotSchedule - ## - topologySpreadConstraints: [] - ## @param replica.dnsPolicy DNS Policy for Redis® replica pods - ## ref: https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/ - ## E.g. - ## dnsPolicy: ClusterFirst - ## - dnsPolicy: "" - ## @param replica.dnsConfig DNS Configuration for Redis® replica pods - ## ref: https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/ - ## E.g. - ## dnsConfig: - ## options: - ## - name: ndots - ## value: "4" - ## - name: single-request-reopen - ## - dnsConfig: {} - ## @param replica.lifecycleHooks for the Redis® replica container(s) to automate configuration before or after startup - ## - lifecycleHooks: {} - ## @param replica.extraVolumes Optionally specify extra list of additional volumes for the Redis® replicas pod(s) - ## - extraVolumes: [] - ## @param replica.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the Redis® replicas container(s) - ## - extraVolumeMounts: [] - ## @param replica.sidecars Add additional sidecar containers to the Redis® replicas pod(s) - ## e.g: - ## sidecars: - ## - name: your-image-name - ## image: your-image - ## imagePullPolicy: Always - ## ports: - ## - name: portname - ## containerPort: 1234 - ## - sidecars: [] - ## @param replica.initContainers Add additional init containers to the Redis® replicas pod(s) - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - ## e.g: - ## initContainers: - ## - name: your-image-name - ## image: your-image - ## imagePullPolicy: Always - ## command: ['sh', '-c', 'echo "hello world"'] - ## - initContainers: [] - ## Persistence Parameters - ## ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/ - ## - persistence: - ## @param replica.persistence.enabled Enable persistence on Redis® replicas nodes using Persistent Volume Claims - ## - enabled: true - ## @param replica.persistence.medium Provide a medium for `emptyDir` volumes. - ## - medium: "" - ## @param replica.persistence.sizeLimit Set this to enable a size limit for `emptyDir` volumes. - ## - sizeLimit: "" - ## @param replica.persistence.path The path the volume will be mounted at on Redis® replicas containers - ## NOTE: Useful when using different Redis® images - ## - path: /data - ## @param replica.persistence.subPath The subdirectory of the volume to mount on Redis® replicas containers - ## NOTE: Useful in dev environments - ## - subPath: "" - ## @param replica.persistence.subPathExpr Used to construct the subPath subdirectory of the volume to mount on Redis® replicas containers - ## - subPathExpr: "" - ## @param replica.persistence.storageClass Persistent Volume storage class - ## If defined, storageClassName: - ## If set to "-", storageClassName: "", which disables dynamic provisioning - ## If undefined (the default) or set to null, no storageClassName spec is set, choosing the default provisioner - ## - storageClass: "" - ## @param replica.persistence.accessModes Persistent Volume access modes - ## - accessModes: - - ReadWriteOnce - ## @param replica.persistence.size Persistent Volume size - ## - size: 8Gi - ## @param replica.persistence.annotations Additional custom annotations for the PVC - ## - annotations: {} - ## @param replica.persistence.labels Additional custom labels for the PVC - ## - labels: {} - ## @param replica.persistence.selector Additional labels to match for the PVC - ## e.g: - ## selector: - ## matchLabels: - ## app: my-app - ## - selector: {} - ## @param replica.persistence.dataSource Custom PVC data source - ## - dataSource: {} - ## @param replica.persistence.existingClaim Use a existing PVC which must be created manually before bound - ## NOTE: requires replica.persistence.enabled: true - ## - existingClaim: "" - ## persistentVolumeClaimRetentionPolicy - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#persistentvolumeclaim-retention - ## @param replica.persistentVolumeClaimRetentionPolicy.enabled Controls if and how PVCs are deleted during the lifecycle of a StatefulSet - ## @param replica.persistentVolumeClaimRetentionPolicy.whenScaled Volume retention behavior when the replica count of the StatefulSet is reduced - ## @param replica.persistentVolumeClaimRetentionPolicy.whenDeleted Volume retention behavior that applies when the StatefulSet is deleted - ## - persistentVolumeClaimRetentionPolicy: - enabled: false - whenScaled: Retain - whenDeleted: Retain - ## Redis® replicas service parameters - ## - service: - ## @param replica.service.type Redis® replicas service type - ## - type: ClusterIP - ## @param replica.service.ports.redis Redis® replicas service port - ## - ports: - redis: 6379 - ## @param replica.service.nodePorts.redis Node port for Redis® replicas - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport - ## NOTE: choose port between <30000-32767> - ## - nodePorts: - redis: "" - ## @param replica.service.externalTrafficPolicy Redis® replicas service external traffic policy - ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip - ## - externalTrafficPolicy: Cluster - ## @param replica.service.internalTrafficPolicy Redis® replicas service internal traffic policy (requires Kubernetes v1.22 or greater to be usable) - ## ref: https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/ - ## - internalTrafficPolicy: Cluster - ## @param replica.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) - ## - extraPorts: [] - ## @param replica.service.clusterIP Redis® replicas service Cluster IP - ## - clusterIP: "" - ## @param replica.service.loadBalancerIP Redis® replicas service Load Balancer IP - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer - ## - loadBalancerIP: "" - ## @param replica.service.loadBalancerClass replicas service Load Balancer class if service type is `LoadBalancer` (optional, cloud specific) - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-loadbalancer - ## - loadBalancerClass: "" - ## @param replica.service.loadBalancerSourceRanges Redis® replicas service Load Balancer sources - ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service - ## e.g. - ## loadBalancerSourceRanges: - ## - 10.10.10.0/24 - ## - loadBalancerSourceRanges: [] - ## @param replica.service.annotations Additional custom annotations for Redis® replicas service - ## - annotations: {} - ## @param replica.service.sessionAffinity Session Affinity for Kubernetes service, can be "None" or "ClientIP" - ## If "ClientIP", consecutive client requests will be directed to the same Pod - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies - ## - sessionAffinity: None - ## @param replica.service.sessionAffinityConfig Additional settings for the sessionAffinity - ## sessionAffinityConfig: - ## clientIP: - ## timeoutSeconds: 300 - ## - sessionAffinityConfig: {} - ## @param replica.terminationGracePeriodSeconds Integer setting the termination grace period for the redis-replicas pods - ## - terminationGracePeriodSeconds: 30 - ## Autoscaling configuration - ## - autoscaling: - ## @param replica.autoscaling.enabled Enable replica autoscaling settings - ## - enabled: false - ## @param replica.autoscaling.minReplicas Minimum replicas for the pod autoscaling - ## - minReplicas: 1 - ## @param replica.autoscaling.maxReplicas Maximum replicas for the pod autoscaling - ## - maxReplicas: 11 - ## @param replica.autoscaling.targetCPU Percentage of CPU to consider when autoscaling - ## - targetCPU: "" - ## @param replica.autoscaling.targetMemory Percentage of Memory to consider when autoscaling - ## - targetMemory: "" - ## ServiceAccount configuration - ## - serviceAccount: - ## @param replica.serviceAccount.create Specifies whether a ServiceAccount should be created - ## - create: true - ## @param replica.serviceAccount.name The name of the ServiceAccount to use. - ## If not set and create is true, a name is generated using the common.names.fullname template - ## - name: "" - ## @param replica.serviceAccount.automountServiceAccountToken Whether to auto mount the service account token - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server - ## - automountServiceAccountToken: false - ## @param replica.serviceAccount.annotations Additional custom annotations for the ServiceAccount - ## - annotations: {} - ## Pod Disruption Budget configuration - ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb - ## @param replica.pdb.create Enable/disable a Pod Disruption Budget creation - ## @param replica.pdb.minAvailable [object] Minimum number/percentage of pods that should remain scheduled - ## @param replica.pdb.maxUnavailable [object] Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `replica.pdb.minAvailable` and `replica.pdb.maxUnavailable` are empty. - ## - pdb: - create: true - minAvailable: "" - maxUnavailable: "" - ## @param replica.extraPodSpec Optionally specify extra PodSpec for the Redis® replicas pod(s) - ## - extraPodSpec: {} -## @section Redis® Sentinel configuration parameters -## - -sentinel: - ## @param sentinel.enabled Use Redis® Sentinel on Redis® pods. - ## IMPORTANT: this will disable the master and replicas services and - ## create a single Redis® service exposing both the Redis and Sentinel ports - ## - enabled: false - ## Bitnami Redis® Sentinel image version - ## ref: https://hub.docker.com/r/bitnami/redis-sentinel/tags/ - ## @param sentinel.image.registry [default: REGISTRY_NAME] Redis® Sentinel image registry - ## @param sentinel.image.repository [default: REPOSITORY_NAME/redis-sentinel] Redis® Sentinel image repository - ## @skip sentinel.image.tag Redis® Sentinel image tag (immutable tags are recommended) - ## @param sentinel.image.digest Redis® Sentinel image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag - ## @param sentinel.image.pullPolicy Redis® Sentinel image pull policy - ## @param sentinel.image.pullSecrets Redis® Sentinel image pull secrets - ## @param sentinel.image.debug Enable image debug mode - ## - image: - registry: docker.io - repository: bitnami/redis-sentinel - tag: 7.4.1-debian-12-r0 - digest: "" - ## Specify a imagePullPolicy - ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' - ## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images - ## - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## Enable debug mode - ## - debug: false - ## @param sentinel.annotations Additional custom annotations for Redis® Sentinel resource - ## - annotations: {} - ## @param sentinel.masterSet Master set name - ## - masterSet: mymaster - ## @param sentinel.quorum Sentinel Quorum - ## - quorum: 2 - ## @param sentinel.getMasterTimeout Amount of time to allow before get_sentinel_master_info() times out. - ## - getMasterTimeout: 90 - ## @param sentinel.automateClusterRecovery Automate cluster recovery in cases where the last replica is not considered a good replica and Sentinel won't automatically failover to it. - ## This also prevents any new replica from starting until the last remaining replica is elected as master to guarantee that it is the one to be elected by Sentinel, and not a newly started replica with no data. - ## NOTE: This feature requires a "downAfterMilliseconds" value less or equal to 2000. - ## - automateClusterRecovery: false - ## @param sentinel.redisShutdownWaitFailover Whether the Redis® master container waits for the failover at shutdown (in addition to the Redis® Sentinel container). - ## - redisShutdownWaitFailover: true - ## Sentinel timing restrictions - ## @param sentinel.downAfterMilliseconds Timeout for detecting a Redis® node is down - ## @param sentinel.failoverTimeout Timeout for performing a election failover - ## - downAfterMilliseconds: 60000 - failoverTimeout: 180000 - ## @param sentinel.parallelSyncs Number of replicas that can be reconfigured in parallel to use the new master after a failover - ## - parallelSyncs: 1 - ## @param sentinel.configuration Configuration for Redis® Sentinel nodes - ## ref: https://redis.io/topics/sentinel - ## - configuration: "" - ## @param sentinel.command Override default container command (useful when using custom images) - ## - command: [] - ## @param sentinel.args Override default container args (useful when using custom images) - ## - args: [] - ## @param sentinel.enableServiceLinks Whether information about services should be injected into pod's environment variable - ## - enableServiceLinks: true - ## @param sentinel.preExecCmds Additional commands to run prior to starting Redis® Sentinel - ## - preExecCmds: [] - ## @param sentinel.extraEnvVars Array with extra environment variables to add to Redis® Sentinel nodes - ## e.g: - ## extraEnvVars: - ## - name: FOO - ## value: "bar" - ## - extraEnvVars: [] - ## @param sentinel.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for Redis® Sentinel nodes - ## - extraEnvVarsCM: "" - ## @param sentinel.extraEnvVarsSecret Name of existing Secret containing extra env vars for Redis® Sentinel nodes - ## - extraEnvVarsSecret: "" - ## @param sentinel.externalMaster.enabled Use external master for bootstrapping - ## @param sentinel.externalMaster.host External master host to bootstrap from - ## @param sentinel.externalMaster.port Port for Redis service external master host - ## - externalMaster: - enabled: false - host: "" - port: 6379 - ## @param sentinel.containerPorts.sentinel Container port to open on Redis® Sentinel nodes - ## - containerPorts: - sentinel: 26379 - ## Configure extra options for Redis® containers' liveness and readiness probes - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes - ## @param sentinel.startupProbe.enabled Enable startupProbe on Redis® Sentinel nodes - ## @param sentinel.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe - ## @param sentinel.startupProbe.periodSeconds Period seconds for startupProbe - ## @param sentinel.startupProbe.timeoutSeconds Timeout seconds for startupProbe - ## @param sentinel.startupProbe.failureThreshold Failure threshold for startupProbe - ## @param sentinel.startupProbe.successThreshold Success threshold for startupProbe - ## - startupProbe: - enabled: true - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 22 - ## @param sentinel.livenessProbe.enabled Enable livenessProbe on Redis® Sentinel nodes - ## @param sentinel.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe - ## @param sentinel.livenessProbe.periodSeconds Period seconds for livenessProbe - ## @param sentinel.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe - ## @param sentinel.livenessProbe.failureThreshold Failure threshold for livenessProbe - ## @param sentinel.livenessProbe.successThreshold Success threshold for livenessProbe - ## - livenessProbe: - enabled: true - initialDelaySeconds: 20 - periodSeconds: 10 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 6 - ## @param sentinel.readinessProbe.enabled Enable readinessProbe on Redis® Sentinel nodes - ## @param sentinel.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe - ## @param sentinel.readinessProbe.periodSeconds Period seconds for readinessProbe - ## @param sentinel.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe - ## @param sentinel.readinessProbe.failureThreshold Failure threshold for readinessProbe - ## @param sentinel.readinessProbe.successThreshold Success threshold for readinessProbe - ## - readinessProbe: - enabled: true - initialDelaySeconds: 20 - periodSeconds: 5 - timeoutSeconds: 1 - successThreshold: 1 - failureThreshold: 6 - ## @param sentinel.customStartupProbe Custom startupProbe that overrides the default one - ## - customStartupProbe: {} - ## @param sentinel.customLivenessProbe Custom livenessProbe that overrides the default one - ## - customLivenessProbe: {} - ## @param sentinel.customReadinessProbe Custom readinessProbe that overrides the default one - ## - customReadinessProbe: {} - ## Persistence parameters - ## ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/ - ## - persistence: - ## @param sentinel.persistence.enabled Enable persistence on Redis® sentinel nodes using Persistent Volume Claims (Experimental) - ## - enabled: false - ## @param sentinel.persistence.storageClass Persistent Volume storage class - ## If defined, storageClassName: - ## If set to "-", storageClassName: "", which disables dynamic provisioning - ## If undefined (the default) or set to null, no storageClassName spec is set, choosing the default provisioner - ## - storageClass: "" - ## @param sentinel.persistence.accessModes Persistent Volume access modes - ## - accessModes: - - ReadWriteOnce - ## @param sentinel.persistence.size Persistent Volume size - ## - size: 100Mi - ## @param sentinel.persistence.annotations Additional custom annotations for the PVC - ## - annotations: {} - ## @param sentinel.persistence.labels Additional custom labels for the PVC - ## - labels: {} - ## @param sentinel.persistence.selector Additional labels to match for the PVC - ## e.g: - ## selector: - ## matchLabels: - ## app: my-app - ## - selector: {} - ## @param sentinel.persistence.dataSource Custom PVC data source - ## - dataSource: {} - ## @param sentinel.persistence.medium Provide a medium for `emptyDir` volumes. - ## - medium: "" - ## @param sentinel.persistence.sizeLimit Set this to enable a size limit for `emptyDir` volumes. - ## - sizeLimit: "" - ## persistentVolumeClaimRetentionPolicy - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#persistentvolumeclaim-retention - ## @param sentinel.persistentVolumeClaimRetentionPolicy.enabled Controls if and how PVCs are deleted during the lifecycle of a StatefulSet - ## @param sentinel.persistentVolumeClaimRetentionPolicy.whenScaled Volume retention behavior when the replica count of the StatefulSet is reduced - ## @param sentinel.persistentVolumeClaimRetentionPolicy.whenDeleted Volume retention behavior that applies when the StatefulSet is deleted - ## - persistentVolumeClaimRetentionPolicy: - enabled: false - whenScaled: Retain - whenDeleted: Retain - ## Redis® Sentinel resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - ## @param sentinel.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if sentinel.resources is set (sentinel.resources is recommended for production). - ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 - ## - resourcesPreset: "nano" - ## @param sentinel.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - ## Example: - ## resources: - ## requests: - ## cpu: 2 - ## memory: 512Mi - ## limits: - ## cpu: 3 - ## memory: 1024Mi - ## - resources: {} - ## Configure Container Security Context - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod - ## @param sentinel.containerSecurityContext.enabled Enabled Redis® Sentinel containers' Security Context - ## @param sentinel.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container - ## @param sentinel.containerSecurityContext.runAsUser Set Redis® Sentinel containers' Security Context runAsUser - ## @param sentinel.containerSecurityContext.runAsGroup Set Redis® Sentinel containers' Security Context runAsGroup - ## @param sentinel.containerSecurityContext.runAsNonRoot Set Redis® Sentinel containers' Security Context runAsNonRoot - ## @param sentinel.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context read-only root filesystem - ## @param sentinel.containerSecurityContext.allowPrivilegeEscalation Set Redis® Sentinel containers' Security Context allowPrivilegeEscalation - ## @param sentinel.containerSecurityContext.seccompProfile.type Set Redis® Sentinel containers' Security Context seccompProfile - ## @param sentinel.containerSecurityContext.capabilities.drop Set Redis® Sentinel containers' Security Context capabilities to drop - ## - containerSecurityContext: - enabled: true - seLinuxOptions: {} - runAsUser: 1001 - runAsGroup: 1001 - runAsNonRoot: true - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - seccompProfile: - type: RuntimeDefault - capabilities: - drop: ["ALL"] - ## @param sentinel.lifecycleHooks for the Redis® sentinel container(s) to automate configuration before or after startup - ## - lifecycleHooks: {} - ## @param sentinel.extraVolumes Optionally specify extra list of additional volumes for the Redis® Sentinel - ## - extraVolumes: [] - ## @param sentinel.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the Redis® Sentinel container(s) - ## - extraVolumeMounts: [] - ## Redis® Sentinel service parameters - ## Note: values passed in this section also configure the master service, unless the sentinel.masterService is explicitly overridden. - service: - ## @param sentinel.service.type Redis® Sentinel service type - ## - type: ClusterIP - ## @param sentinel.service.ports.redis Redis® service port for Redis® - ## @param sentinel.service.ports.sentinel Redis® service port for Redis® Sentinel - ## - ports: - redis: 6379 - sentinel: 26379 - ## @param sentinel.service.nodePorts.redis Node port for Redis® - ## @param sentinel.service.nodePorts.sentinel Node port for Sentinel - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport - ## NOTE: choose port between <30000-32767> - ## NOTE: By leaving these values blank, they will be generated by ports-configmap - ## If setting manually, please leave at least replica.replicaCount + 1 in between sentinel.service.nodePorts.redis and sentinel.service.nodePorts.sentinel to take into account the ports that will be created while incrementing that base port - ## - nodePorts: - redis: "" - sentinel: "" - ## @param sentinel.service.externalTrafficPolicy Redis® Sentinel service external traffic policy - ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip - ## - externalTrafficPolicy: Cluster - ## @param sentinel.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) - ## - extraPorts: [] - ## @param sentinel.service.clusterIP Redis® Sentinel service Cluster IP - ## - clusterIP: "" - ## @param sentinel.service.createMaster Enable master service pointing to the current master (experimental) - ## NOTE: rbac.create need to be set to true - ## - createMaster: false - - ## @param sentinel.service.loadBalancerIP Redis® Sentinel service Load Balancer IP - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer - ## - loadBalancerIP: "" - ## @param sentinel.service.loadBalancerClass sentinel service Load Balancer class if service type is `LoadBalancer` (optional, cloud specific) - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-loadbalancer - ## - loadBalancerClass: "" - ## @param sentinel.service.loadBalancerSourceRanges Redis® Sentinel service Load Balancer sources - ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service - ## e.g. - ## loadBalancerSourceRanges: - ## - 10.10.10.0/24 - ## - loadBalancerSourceRanges: [] - ## @param sentinel.service.annotations Additional custom annotations for Redis® Sentinel service - ## - annotations: {} - ## @param sentinel.service.sessionAffinity Session Affinity for Kubernetes service, can be "None" or "ClientIP" - ## If "ClientIP", consecutive client requests will be directed to the same Pod - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies - ## - sessionAffinity: None - ## @param sentinel.service.sessionAffinityConfig Additional settings for the sessionAffinity - ## sessionAffinityConfig: - ## clientIP: - ## timeoutSeconds: 300 - ## - sessionAffinityConfig: {} - ## Headless service properties - ## - headless: - ## @param sentinel.service.headless.annotations Annotations for the headless service. - ## - annotations: {} - - ## Redis® master service parameters - ## - masterService: - ## @param sentinel.masterService.enabled Enable master service pointing to the current master (experimental) - ## NOTE: rbac.create need to be set to true - ## - enabled: false - ## @param sentinel.masterService.type Redis® Sentinel master service type - ## - type: ClusterIP - ## @param sentinel.masterService.ports.redis Redis® service port for Redis® - ## - ports: - redis: 6379 - ## @param sentinel.masterService.nodePorts.redis Node port for Redis® - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport - ## NOTE: choose port between <30000-32767> - ## NOTE: By leaving these values blank, they will be generated by ports-configmap - ## If setting manually, please leave at least replica.replicaCount + 1 in between sentinel.service.nodePorts.redis and sentinel.service.nodePorts.sentinel to take into account the ports that will be created while incrementing that base port - ## - nodePorts: - redis: "" - ## @param sentinel.masterService.externalTrafficPolicy Redis® master service external traffic policy - ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip - ## - externalTrafficPolicy: "" - ## @param sentinel.masterService.extraPorts Extra ports to expose (normally used with the `sidecar` value) - ## - extraPorts: [] - ## @param sentinel.masterService.clusterIP Redis® master service Cluster IP - ## - clusterIP: "" - ## @param sentinel.masterService.loadBalancerIP Redis® master service Load Balancer IP - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer - ## - loadBalancerIP: "" - ## @param sentinel.masterService.loadBalancerClass master service Load Balancer class if service type is `LoadBalancer` (optional, cloud specific) - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-loadbalancer - ## - loadBalancerClass: "" - ## @param sentinel.masterService.loadBalancerSourceRanges Redis® master service Load Balancer sources - ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service - ## e.g. - ## loadBalancerSourceRanges: - ## - 10.10.10.0/24 - ## - loadBalancerSourceRanges: [] - ## @param sentinel.masterService.annotations Additional custom annotations for Redis® master service - ## - annotations: {} - ## @param sentinel.masterService.sessionAffinity Session Affinity for Kubernetes service, can be "None" or "ClientIP" - ## If "ClientIP", consecutive client requests will be directed to the same Pod - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies - ## - sessionAffinity: None - ## @param sentinel.masterService.sessionAffinityConfig Additional settings for the sessionAffinity - ## sessionAffinityConfig: - ## clientIP: - ## timeoutSeconds: 300 - ## - sessionAffinityConfig: {} - ## @param sentinel.terminationGracePeriodSeconds Integer setting the termination grace period for the redis-node pods - ## - terminationGracePeriodSeconds: 30 - ## @param sentinel.extraPodSpec Optionally specify extra PodSpec for the Redis® Sentinel pod(s) - ## - extraPodSpec: {} -## @section Other Parameters -## - -## @param serviceBindings.enabled Create secret for service binding (Experimental) -## Ref: https://servicebinding.io/service-provider/ -## -serviceBindings: - enabled: false -## Network Policy configuration -## ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ -## -networkPolicy: - ## @param networkPolicy.enabled Enable creation of NetworkPolicy resources - ## - enabled: true - ## @param networkPolicy.allowExternal Don't require client label for connections - ## When set to false, only pods with the correct client label will have network access to the ports - ## Redis® is listening on. When true, Redis® will accept connections from any source - ## (with the correct destination port). - ## - allowExternal: true - ## @param networkPolicy.allowExternalEgress Allow the pod to access any range of port and all destinations. - ## - allowExternalEgress: true - ## @param networkPolicy.extraIngress Add extra ingress rules to the NetworkPolicy - ## e.g: - ## extraIngress: - ## - ports: - ## - port: 1234 - ## from: - ## - podSelector: - ## - matchLabels: - ## - role: frontend - ## - podSelector: - ## - matchExpressions: - ## - key: role - ## operator: In - ## values: - ## - frontend - ## - extraIngress: [] - ## @param networkPolicy.extraEgress Add extra egress rules to the NetworkPolicy - ## e.g: - ## extraEgress: - ## - ports: - ## - port: 1234 - ## to: - ## - podSelector: - ## - matchLabels: - ## - role: frontend - ## - podSelector: - ## - matchExpressions: - ## - key: role - ## operator: In - ## values: - ## - frontend - ## - extraEgress: [] - ## @param networkPolicy.ingressNSMatchLabels Labels to match to allow traffic from other namespaces - ## @param networkPolicy.ingressNSPodMatchLabels Pod labels to match to allow traffic from other namespaces - ## - ingressNSMatchLabels: {} - ingressNSPodMatchLabels: {} - metrics: - ## @param networkPolicy.metrics.allowExternal Don't require client label for connections for metrics endpoint - ## When set to false, only pods with the correct client label will have network access to the metrics port - ## - allowExternal: true - ## @param networkPolicy.metrics.ingressNSMatchLabels Labels to match to allow traffic from other namespaces to metrics endpoint - ## @param networkPolicy.metrics.ingressNSPodMatchLabels Pod labels to match to allow traffic from other namespaces to metrics endpoint - ## - ingressNSMatchLabels: {} - ingressNSPodMatchLabels: {} -## PodSecurityPolicy configuration -## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ -## -podSecurityPolicy: - ## @param podSecurityPolicy.create Whether to create a PodSecurityPolicy. WARNING: PodSecurityPolicy is deprecated in Kubernetes v1.21 or later, unavailable in v1.25 or later - ## - create: false - ## @param podSecurityPolicy.enabled Enable PodSecurityPolicy's RBAC rules - ## - enabled: false -## RBAC configuration -## -rbac: - ## @param rbac.create Specifies whether RBAC resources should be created - ## - create: false - ## @param rbac.rules Custom RBAC rules to set - ## e.g: - ## rules: - ## - apiGroups: - ## - "" - ## resources: - ## - pods - ## verbs: - ## - get - ## - list - ## - rules: [] -## ServiceAccount configuration -## -serviceAccount: - ## @param serviceAccount.create Specifies whether a ServiceAccount should be created - ## - create: true - ## @param serviceAccount.name The name of the ServiceAccount to use. - ## If not set and create is true, a name is generated using the common.names.fullname template - ## - name: "" - ## @param serviceAccount.automountServiceAccountToken Whether to auto mount the service account token - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server - ## - automountServiceAccountToken: false - ## @param serviceAccount.annotations Additional custom annotations for the ServiceAccount - ## - annotations: {} -## Redis® Pod Disruption Budget configuration -## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ -## @param pdb DEPRECATED Please use `master.pdb` and `replica.pdb` values instead -## -pdb: {} -## TLS configuration -## -tls: - ## @param tls.enabled Enable TLS traffic - ## - enabled: false - ## @param tls.authClients Require clients to authenticate - ## - authClients: true - ## @param tls.autoGenerated Enable autogenerated certificates - ## - autoGenerated: false - ## @param tls.existingSecret The name of the existing secret that contains the TLS certificates - ## - existingSecret: "" - ## @param tls.certificatesSecret DEPRECATED. Use existingSecret instead. - ## - certificatesSecret: "" - ## @param tls.certFilename Certificate filename - ## - certFilename: "" - ## @param tls.certKeyFilename Certificate Key filename - ## - certKeyFilename: "" - ## @param tls.certCAFilename CA Certificate filename - ## - certCAFilename: "" - ## @param tls.dhParamsFilename File containing DH params (in order to support DH based ciphers) - ## - dhParamsFilename: "" -## @section Metrics Parameters -## -metrics: - ## @param metrics.enabled Start a sidecar prometheus exporter to expose Redis® metrics - ## - enabled: false - ## Bitnami Redis® Exporter image - ## ref: https://hub.docker.com/r/bitnami/redis-exporter/tags/ - ## @param metrics.image.registry [default: REGISTRY_NAME] Redis® Exporter image registry - ## @param metrics.image.repository [default: REPOSITORY_NAME/redis-exporter] Redis® Exporter image repository - ## @skip metrics.image.tag Redis® Exporter image tag (immutable tags are recommended) - ## @param metrics.image.digest Redis® Exporter image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag - ## @param metrics.image.pullPolicy Redis® Exporter image pull policy - ## @param metrics.image.pullSecrets Redis® Exporter image pull secrets - ## - image: - registry: docker.io - repository: bitnami/redis-exporter - tag: 1.63.0-debian-12-r1 - digest: "" - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## @param metrics.containerPorts.http Metrics HTTP container port - ## - containerPorts: - http: 9121 - ## Configure extra options for Redis® containers' liveness, readiness & startup probes - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ - ## @param metrics.startupProbe.enabled Enable startupProbe on Redis® replicas nodes - ## @param metrics.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe - ## @param metrics.startupProbe.periodSeconds Period seconds for startupProbe - ## @param metrics.startupProbe.timeoutSeconds Timeout seconds for startupProbe - ## @param metrics.startupProbe.failureThreshold Failure threshold for startupProbe - ## @param metrics.startupProbe.successThreshold Success threshold for startupProbe - ## - startupProbe: - enabled: false - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 5 - ## @param metrics.livenessProbe.enabled Enable livenessProbe on Redis® replicas nodes - ## @param metrics.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe - ## @param metrics.livenessProbe.periodSeconds Period seconds for livenessProbe - ## @param metrics.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe - ## @param metrics.livenessProbe.failureThreshold Failure threshold for livenessProbe - ## @param metrics.livenessProbe.successThreshold Success threshold for livenessProbe - ## - livenessProbe: - enabled: true - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 5 - successThreshold: 1 - failureThreshold: 5 - ## @param metrics.readinessProbe.enabled Enable readinessProbe on Redis® replicas nodes - ## @param metrics.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe - ## @param metrics.readinessProbe.periodSeconds Period seconds for readinessProbe - ## @param metrics.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe - ## @param metrics.readinessProbe.failureThreshold Failure threshold for readinessProbe - ## @param metrics.readinessProbe.successThreshold Success threshold for readinessProbe - ## - readinessProbe: - enabled: true - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 1 - successThreshold: 1 - failureThreshold: 3 - ## @param metrics.customStartupProbe Custom startupProbe that overrides the default one - ## - customStartupProbe: {} - ## @param metrics.customLivenessProbe Custom livenessProbe that overrides the default one - ## - customLivenessProbe: {} - ## @param metrics.customReadinessProbe Custom readinessProbe that overrides the default one - ## - customReadinessProbe: {} - ## @param metrics.command Override default metrics container init command (useful when using custom images) - ## - command: [] - ## @param metrics.redisTargetHost A way to specify an alternative Redis® hostname - ## Useful for certificate CN/SAN matching - ## - redisTargetHost: "localhost" - ## @param metrics.extraArgs Extra arguments for Redis® exporter, for example: - ## e.g.: - ## extraArgs: - ## check-keys: myKey,myOtherKey - ## - extraArgs: {} - ## @param metrics.extraEnvVars Array with extra environment variables to add to Redis® exporter - ## e.g: - ## extraEnvVars: - ## - name: FOO - ## value: "bar" - ## - extraEnvVars: [] - ## Configure Container Security Context - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod - ## @param metrics.containerSecurityContext.enabled Enabled Redis® exporter containers' Security Context - ## @param metrics.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container - ## @param metrics.containerSecurityContext.runAsUser Set Redis® exporter containers' Security Context runAsUser - ## @param metrics.containerSecurityContext.runAsGroup Set Redis® exporter containers' Security Context runAsGroup - ## @param metrics.containerSecurityContext.runAsNonRoot Set Redis® exporter containers' Security Context runAsNonRoot - ## @param metrics.containerSecurityContext.allowPrivilegeEscalation Set Redis® exporter containers' Security Context allowPrivilegeEscalation - ## @param metrics.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context read-only root filesystem - ## @param metrics.containerSecurityContext.seccompProfile.type Set Redis® exporter containers' Security Context seccompProfile - ## @param metrics.containerSecurityContext.capabilities.drop Set Redis® exporter containers' Security Context capabilities to drop - ## - containerSecurityContext: - enabled: true - seLinuxOptions: {} - runAsUser: 1001 - runAsGroup: 1001 - runAsNonRoot: true - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - seccompProfile: - type: RuntimeDefault - capabilities: - drop: ["ALL"] - ## @param metrics.extraVolumes Optionally specify extra list of additional volumes for the Redis® metrics sidecar - ## - extraVolumes: [] - ## @param metrics.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the Redis® metrics sidecar - ## - extraVolumeMounts: [] - ## Redis® exporter resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - ## @param metrics.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if metrics.resources is set (metrics.resources is recommended for production). - ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 - ## - resourcesPreset: "nano" - ## @param metrics.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - ## Example: - ## resources: - ## requests: - ## cpu: 2 - ## memory: 512Mi - ## limits: - ## cpu: 3 - ## memory: 1024Mi - ## - resources: {} - ## @param metrics.podLabels Extra labels for Redis® exporter pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ - ## - podLabels: {} - ## @param metrics.podAnnotations [object] Annotations for Redis® exporter pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ - ## - podAnnotations: - prometheus.io/scrape: "true" - prometheus.io/port: "9121" - ## Redis® exporter service parameters - ## - service: - ## @param metrics.service.enabled Create Service resource(s) for scraping metrics using PrometheusOperator ServiceMonitor, can be disabled when using a PodMonitor - ## - enabled: true - ## @param metrics.service.type Redis® exporter service type - ## - type: ClusterIP - ## @param metrics.service.ports.http Redis® exporter service port - ## - ports: - http: 9121 - ## @param metrics.service.externalTrafficPolicy Redis® exporter service external traffic policy - ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip - ## - externalTrafficPolicy: Cluster - ## @param metrics.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) - ## - extraPorts: [] - ## @param metrics.service.loadBalancerIP Redis® exporter service Load Balancer IP - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer - ## - loadBalancerIP: "" - ## @param metrics.service.loadBalancerClass exporter service Load Balancer class if service type is `LoadBalancer` (optional, cloud specific) - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-loadbalancer - ## - loadBalancerClass: "" - ## @param metrics.service.loadBalancerSourceRanges Redis® exporter service Load Balancer sources - ## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service - ## e.g. - ## loadBalancerSourceRanges: - ## - 10.10.10.0/24 - ## - loadBalancerSourceRanges: [] - ## @param metrics.service.annotations Additional custom annotations for Redis® exporter service - ## - annotations: {} - ## @param metrics.service.clusterIP Redis® exporter service Cluster IP - ## - clusterIP: "" - ## Prometheus Service Monitor - ## ref: https://github.com/coreos/prometheus-operator - ## https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#endpoint - ## - serviceMonitor: - ## @param metrics.serviceMonitor.port the service port to scrape metrics from - ## - port: http-metrics - ## @param metrics.serviceMonitor.enabled Create ServiceMonitor resource(s) for scraping metrics using PrometheusOperator - ## - enabled: false - ## @param metrics.serviceMonitor.namespace The namespace in which the ServiceMonitor will be created - ## - namespace: "" - ## @param metrics.serviceMonitor.interval The interval at which metrics should be scraped - ## - interval: 30s - ## @param metrics.serviceMonitor.scrapeTimeout The timeout after which the scrape is ended - ## - scrapeTimeout: "" - ## @param metrics.serviceMonitor.relabelings Metrics RelabelConfigs to apply to samples before scraping. - ## - relabelings: [] - ## @skip metrics.serviceMonitor.relabellings DEPRECATED: Use `metrics.serviceMonitor.relabelings` instead. - ## - relabellings: [] - ## @param metrics.serviceMonitor.metricRelabelings Metrics RelabelConfigs to apply to samples before ingestion. - ## - metricRelabelings: [] - ## @param metrics.serviceMonitor.honorLabels Specify honorLabels parameter to add the scrape endpoint - ## - honorLabels: false - ## @param metrics.serviceMonitor.additionalLabels Additional labels that can be used so ServiceMonitor resource(s) can be discovered by Prometheus - ## - additionalLabels: {} - ## @param metrics.serviceMonitor.podTargetLabels Labels from the Kubernetes pod to be transferred to the created metrics - ## - podTargetLabels: [] - ## @param metrics.serviceMonitor.sampleLimit Limit of how many samples should be scraped from every Pod - ## - sampleLimit: false - ## @param metrics.serviceMonitor.targetLimit Limit of how many targets should be scraped - ## - targetLimit: false - ## @param metrics.serviceMonitor.additionalEndpoints Additional endpoints to scrape (e.g sentinel) - ## - additionalEndpoints: [] - # uncomment in order to scrape sentinel metrics, also to in order distinguish between Sentinel and Redis container metrics - # add metricRelabelings with label like app=redis to main redis pod-monitor port - # - interval: "30s" - # path: "/scrape" - # port: "http-metrics" - # params: - # target: ["localhost:26379"] - # metricRelabelings: - # - targetLabel: "app" - # replacement: "sentinel" - ## Prometheus Pod Monitor - ## ref: https://github.com/coreos/prometheus-operator - ## https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#podmonitor - ## - podMonitor: - ## @param metrics.podMonitor.port the pod port to scrape metrics from - ## - port: metrics - ## @param metrics.podMonitor.enabled Create PodMonitor resource(s) for scraping metrics using PrometheusOperator - ## - enabled: false - ## @param metrics.podMonitor.namespace The namespace in which the PodMonitor will be created - ## - namespace: "" - ## @param metrics.podMonitor.interval The interval at which metrics should be scraped - ## - interval: 30s - ## @param metrics.podMonitor.scrapeTimeout The timeout after which the scrape is ended - ## - scrapeTimeout: "" - ## @param metrics.podMonitor.relabelings Metrics RelabelConfigs to apply to samples before scraping. - ## - relabelings: [] - ## @skip metrics.podMonitor.relabellings DEPRECATED: Use `metrics.podMonitor.relabelings` instead. - ## - relabellings: [] - ## @param metrics.podMonitor.metricRelabelings Metrics RelabelConfigs to apply to samples before ingestion. - ## - metricRelabelings: [] - # - targetLabel: "app" - # replacement: "redis" - ## @param metrics.podMonitor.honorLabels Specify honorLabels parameter to add the scrape endpoint - ## - honorLabels: false - ## @param metrics.podMonitor.additionalLabels Additional labels that can be used so PodMonitor resource(s) can be discovered by Prometheus - ## - additionalLabels: {} - ## @param metrics.podMonitor.podTargetLabels Labels from the Kubernetes pod to be transferred to the created metrics - ## - podTargetLabels: [] - ## @param metrics.podMonitor.sampleLimit Limit of how many samples should be scraped from every Pod - ## - sampleLimit: false - ## @param metrics.podMonitor.targetLimit Limit of how many targets should be scraped - ## - targetLimit: false - ## @param metrics.podMonitor.additionalEndpoints Additional endpoints to scrape (e.g sentinel) - ## - additionalEndpoints: [] - # - interval: "30s" - # path: "/scrape" - # port: "metrics" - # params: - # target: ["localhost:26379"] - # metricRelabelings: - # - targetLabel: "app" - # replacement: "sentinel" - ## Custom PrometheusRule to be defined - ## ref: https://github.com/coreos/prometheus-operator#customresourcedefinitions - ## - prometheusRule: - ## @param metrics.prometheusRule.enabled Create a custom prometheusRule Resource for scraping metrics using PrometheusOperator - ## - enabled: false - ## @param metrics.prometheusRule.namespace The namespace in which the prometheusRule will be created - ## - namespace: "" - ## @param metrics.prometheusRule.additionalLabels Additional labels for the prometheusRule - ## - additionalLabels: {} - ## @param metrics.prometheusRule.rules Custom Prometheus rules - ## e.g: - ## rules: - ## - alert: RedisDown - ## expr: redis_up{service="{{ template "common.names.fullname" . }}-metrics"} == 0 - ## for: 2m - ## labels: - ## severity: error - ## annotations: - ## summary: Redis® instance {{ "{{ $labels.instance }}" }} down - ## description: Redis® instance {{ "{{ $labels.instance }}" }} is down - ## - alert: RedisMemoryHigh - ## expr: > - ## redis_memory_used_bytes{service="{{ template "common.names.fullname" . }}-metrics"} * 100 - ## / - ## redis_memory_max_bytes{service="{{ template "common.names.fullname" . }}-metrics"} - ## > 90 - ## for: 2m - ## labels: - ## severity: error - ## annotations: - ## summary: Redis® instance {{ "{{ $labels.instance }}" }} is using too much memory - ## description: | - ## Redis® instance {{ "{{ $labels.instance }}" }} is using {{ "{{ $value }}" }}% of its available memory. - ## - alert: RedisKeyEviction - ## expr: | - ## increase(redis_evicted_keys_total{service="{{ template "common.names.fullname" . }}-metrics"}[5m]) > 0 - ## for: 1s - ## labels: - ## severity: error - ## annotations: - ## summary: Redis® instance {{ "{{ $labels.instance }}" }} has evicted keys - ## description: | - ## Redis® instance {{ "{{ $labels.instance }}" }} has evicted {{ "{{ $value }}" }} keys in the last 5 minutes. - ## - rules: [] -## @section Init Container Parameters -## - -## 'volumePermissions' init container parameters -## Changes the owner and group of the persistent volume mount point to runAsUser:fsGroup values -## based on the *podSecurityContext/*containerSecurityContext parameters -## -volumePermissions: - ## @param volumePermissions.enabled Enable init container that changes the owner/group of the PV mount point to `runAsUser:fsGroup` - ## - enabled: false - ## OS Shell + Utility image - ## ref: https://hub.docker.com/r/bitnami/os-shell/tags/ - ## @param volumePermissions.image.registry [default: REGISTRY_NAME] OS Shell + Utility image registry - ## @param volumePermissions.image.repository [default: REPOSITORY_NAME/os-shell] OS Shell + Utility image repository - ## @skip volumePermissions.image.tag OS Shell + Utility image tag (immutable tags are recommended) - ## @param volumePermissions.image.digest OS Shell + Utility image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag - ## @param volumePermissions.image.pullPolicy OS Shell + Utility image pull policy - ## @param volumePermissions.image.pullSecrets OS Shell + Utility image pull secrets - ## - image: - registry: docker.io - repository: bitnami/os-shell - tag: 12-debian-12-r30 - digest: "" - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## Init container's resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - ## @param volumePermissions.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if volumePermissions.resources is set (volumePermissions.resources is recommended for production). - ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 - ## - resourcesPreset: "nano" - ## @param volumePermissions.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - ## Example: - ## resources: - ## requests: - ## cpu: 2 - ## memory: 512Mi - ## limits: - ## cpu: 3 - ## memory: 1024Mi - ## - resources: {} - ## Init container Container Security Context - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container - ## @param volumePermissions.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container - ## @param volumePermissions.containerSecurityContext.runAsUser Set init container's Security Context runAsUser - ## NOTE: when runAsUser is set to special value "auto", init container will try to chown the - ## data folder to auto-determined user&group, using commands: `id -u`:`id -G | cut -d" " -f2` - ## "auto" is especially useful for OpenShift which has scc with dynamic user ids (and 0 is not allowed) - ## - containerSecurityContext: - seLinuxOptions: {} - runAsUser: 0 - - ## @param volumePermissions.extraEnvVars Array with extra environment variables to add to volume permissions init container. - ## e.g: - ## extraEnvVars: - ## - name: FOO - ## value: "bar" - ## - extraEnvVars: [] - -## Kubectl InitContainer -## used by Sentinel to update the isMaster label on the Redis(TM) pods -## -kubectl: - ## Bitnami Kubectl image version - ## ref: https://hub.docker.com/r/bitnami/kubectl/tags/ - ## @param kubectl.image.registry [default: REGISTRY_NAME] Kubectl image registry - ## @param kubectl.image.repository [default: REPOSITORY_NAME/kubectl] Kubectl image repository - ## @skip kubectl.image.tag Kubectl image tag (immutable tags are recommended), by default, using the current version - ## @param kubectl.image.digest Kubectl image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag - ## @param kubectl.image.pullPolicy Kubectl image pull policy - ## @param kubectl.image.pullSecrets Kubectl pull secrets - ## - image: - registry: docker.io - repository: bitnami/kubectl - tag: 1.31.1-debian-12-r3 - digest: "" - ## Specify a imagePullPolicy - ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' - ## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images - ## - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## @param kubectl.command kubectl command to execute - ## - command: ["/opt/bitnami/scripts/kubectl-scripts/update-master-label.sh"] - ## Configure Container Security Context - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod - ## @param kubectl.containerSecurityContext.enabled Enabled kubectl containers' Security Context - ## @param kubectl.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container - ## @param kubectl.containerSecurityContext.runAsUser Set kubectl containers' Security Context runAsUser - ## @param kubectl.containerSecurityContext.runAsGroup Set kubectl containers' Security Context runAsGroup - ## @param kubectl.containerSecurityContext.runAsNonRoot Set kubectl containers' Security Context runAsNonRoot - ## @param kubectl.containerSecurityContext.allowPrivilegeEscalation Set kubectl containers' Security Context allowPrivilegeEscalation - ## @param kubectl.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context read-only root filesystem - ## @param kubectl.containerSecurityContext.seccompProfile.type Set kubectl containers' Security Context seccompProfile - ## @param kubectl.containerSecurityContext.capabilities.drop Set kubectl containers' Security Context capabilities to drop - ## - containerSecurityContext: - enabled: true - seLinuxOptions: {} - runAsUser: 1001 - runAsGroup: 1001 - runAsNonRoot: true - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - seccompProfile: - type: RuntimeDefault - capabilities: - drop: ["ALL"] - ## Bitnami Kubectl resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - ## @param kubectl.resources.limits The resources limits for the kubectl containers - ## @param kubectl.resources.requests The requested resources for the kubectl containers - ## - resources: - limits: {} - requests: {} - -## init-sysctl container parameters -## used to perform sysctl operation to modify Kernel settings (needed sometimes to avoid warnings) -## -sysctl: - ## @param sysctl.enabled Enable init container to modify Kernel settings - ## - enabled: false - ## OS Shell + Utility image - ## ref: https://hub.docker.com/r/bitnami/os-shell/tags/ - ## @param sysctl.image.registry [default: REGISTRY_NAME] OS Shell + Utility image registry - ## @param sysctl.image.repository [default: REPOSITORY_NAME/os-shell] OS Shell + Utility image repository - ## @skip sysctl.image.tag OS Shell + Utility image tag (immutable tags are recommended) - ## @param sysctl.image.digest OS Shell + Utility image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag - ## @param sysctl.image.pullPolicy OS Shell + Utility image pull policy - ## @param sysctl.image.pullSecrets OS Shell + Utility image pull secrets - ## - image: - registry: docker.io - repository: bitnami/os-shell - tag: 12-debian-12-r30 - digest: "" - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## @param sysctl.command Override default init-sysctl container command (useful when using custom images) - ## - command: [] - ## @param sysctl.mountHostSys Mount the host `/sys` folder to `/host-sys` - ## - mountHostSys: false - ## Init container's resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - ## @param sysctl.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if sysctl.resources is set (sysctl.resources is recommended for production). - ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 - ## - resourcesPreset: "nano" - ## @param sysctl.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - ## Example: - ## resources: - ## requests: - ## cpu: 2 - ## memory: 512Mi - ## limits: - ## cpu: 3 - ## memory: 1024Mi - ## - resources: {} -## @section useExternalDNS Parameters -## -## @param useExternalDNS.enabled Enable various syntax that would enable external-dns to work. Note this requires a working installation of `external-dns` to be usable. -## @param useExternalDNS.additionalAnnotations Extra annotations to be utilized when `external-dns` is enabled. -## @param useExternalDNS.annotationKey The annotation key utilized when `external-dns` is enabled. Setting this to `false` will disable annotations. -## @param useExternalDNS.suffix The DNS suffix utilized when `external-dns` is enabled. Note that we prepend the suffix with the full name of the release. -## -useExternalDNS: - enabled: false - suffix: "" - annotationKey: external-dns.alpha.kubernetes.io/ - additionalAnnotations: {} diff --git a/packages/system/dashboard/charts/kubeapps/crds/apprepository-crd.yaml b/packages/system/dashboard/charts/kubeapps/crds/apprepository-crd.yaml deleted file mode 100644 index 0bf8e831..00000000 --- a/packages/system/dashboard/charts/kubeapps/crds/apprepository-crd.yaml +++ /dev/null @@ -1,116 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: apprepositories.kubeapps.com -spec: - group: kubeapps.com - scope: Namespaced - names: - kind: AppRepository - plural: apprepositories - shortNames: - - apprepos - versions: - - name: v1alpha1 - storage: true - served: true - schema: - openAPIV3Schema: - type: object - required: - - spec - properties: - spec: - type: object - required: - - type - - url - properties: - type: - type: string - enum: ["helm", "oci"] - url: - type: string - description: - type: string - auth: - type: object - properties: - header: - type: object - required: - - secretKeyRef - properties: - secretKeyRef: - type: object - required: - - key - - name - properties: - key: - type: string - name: - type: string - customCA: - type: object - required: - - secretKeyRef - properties: - secretKeyRef: - type: object - required: - - key - - name - properties: - key: - type: string - name: - type: string - dockerRegistrySecrets: - type: array - items: - type: string - tlsInsecureSkipVerify: - type: boolean - passCredentials: - type: boolean - interval: - type: string - filterRule: - type: object - properties: - jq: - type: string - variables: - type: object - additionalProperties: - type: string - ociRepositories: - type: array - items: - type: string - resyncRequests: - type: integer - syncJobPodTemplate: - type: object - properties: - metadata: - type: object - x-kubernetes-preserve-unknown-fields: true - spec: - type: object - x-kubernetes-preserve-unknown-fields: true - status: - type: object - properties: - status: - type: string - additionalPrinterColumns: - - name: Type - type: string - description: The type of this repository. - jsonPath: .spec.type - - name: URL - type: string - description: The URL of this repository. - jsonPath: .spec.url diff --git a/packages/system/dashboard/charts/kubeapps/templates/NOTES.txt b/packages/system/dashboard/charts/kubeapps/templates/NOTES.txt deleted file mode 100644 index 9a5fe40d..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/NOTES.txt +++ /dev/null @@ -1,89 +0,0 @@ -CHART NAME: {{ .Chart.Name }} -CHART VERSION: {{ .Chart.Version }} -APP VERSION: {{ .Chart.AppVersion }} - -{{- $postgresqlSecretName := include "kubeapps.postgresql.secretName" . -}} - -{{- $redisSecretName := include "kubeapps.redis.secretName" . -}} - -** Please be patient while the chart is being deployed ** - -{{- if .Values.diagnosticMode.enabled }} -The chart has been deployed in diagnostic mode. All probes have been disabled and the command has been overwritten with: - - command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 4 }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 4 }} - -Get the list of pods by executing: - - kubectl get pods --namespace {{ .Release.Namespace }} -l app.kubernetes.io/instance={{ .Release.Name }} - -Access the pods you want to debug by executing - - kubectl exec --namespace {{ .Release.Namespace }} -ti -- bash - -{{- else }} - -Tip: - - Watch the deployment status using the command: kubectl get pods -w --namespace {{ .Release.Namespace }} - -Kubeapps can be accessed via port {{ .Values.frontend.service.ports.http }} on the following DNS name from within your cluster: - - {{ template "common.names.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local - -{{- $reposWithOrphanSecrets := include "kubeapps.repos-with-orphan-secrets" . }} -{{- if ne $reposWithOrphanSecrets "" }} - -CAVEAT: - Some App Repositories have been installed with a custom CA or authorization header. - This generates secrets that won't be cleaned up if the repository is deleted through the Web application. - You can delete them manually or when uninstalling this chart. - -{{- end }} - -To access Kubeapps from outside your K8s cluster, follow the steps below: - -{{- if .Values.ingress.enabled }} - -1. Get the Kubeapps URL and associate Kubeapps hostname to your cluster external IP: - - export CLUSTER_IP=$(minikube ip) # On Minikube. Use: `kubectl cluster-info` on others K8s clusters - echo "Kubeapps URL: {{ printf "%s://%s/" (ternary "http" "https" .Values.ingress.tls) .Values.ingress.hostname }}" - echo "$CLUSTER_IP {{ .Values.ingress.hostname }}" | sudo tee -a /etc/hosts - -{{- else }} - -1. Get the Kubeapps URL by running these commands: - -{{- if contains "NodePort" .Values.frontend.service.type }} - - export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "common.names.fullname" . }}) - echo "Kubeapps URL: http://$NODE_IP:$NODE_PORT" - -{{- else if contains "LoadBalancer" .Values.frontend.service.type }} - - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - Watch the status by running 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "common.names.fullname" . }}' - - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "common.names.fullname" . }} --template "{{ "{{ range (index .status.loadBalancer.ingress 0) }}{{ . }}{{ end }}" }}") - echo "Kubeapps URL: {{ printf "%s://$SERVICE_IP:%d" (ternary "http" "https" (eq ( .Values.frontend.service.ports.http | toString ) "443")) (int .Values.frontend.service.ports.http) }}" - -{{- else if contains "ClusterIP" .Values.frontend.service.type }} - -{{- $portNumber := include "kubeapps.frontend-port-number" . }} - echo "Kubeapps URL: http://127.0.0.1:{{ $portNumber }}" - kubectl port-forward --namespace {{ .Release.Namespace }} service/{{ template "common.names.fullname" . }} {{ $portNumber }}:{{ .Values.frontend.service.ports.http }} - -{{- end }} -{{- end }} - -2. Open a browser and access Kubeapps using the obtained URL. - -{{- end }} - -{{- include "kubeapps.checkRollingTags" . }} -{{- include "kubeapps.validateValues" . }} -{{- include "common.warnings.resources" (dict "sections" (list "apprepository" "authProxy" "dashboard" "frontend" "kubeappsapis" "ociCatalog" "pinnipedProxy" "postgresql") "context" $) }} -{{- include "common.warnings.modifiedImages" (dict "images" (list .Values.frontend.image .Values.dashboard.image .Values.apprepository.image .Values.apprepository.syncImage .Values.authProxy.image .Values.pinnipedProxy.image .Values.kubeappsapis.image .Values.ociCatalog.image) "context" $) }} \ No newline at end of file diff --git a/packages/system/dashboard/charts/kubeapps/templates/_helpers.tpl b/packages/system/dashboard/charts/kubeapps/templates/_helpers.tpl deleted file mode 100644 index 83e0bba0..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/_helpers.tpl +++ /dev/null @@ -1,371 +0,0 @@ -{{/* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{/* vim: set filetype=mustache: */}} - -{{/* -Return the proper Docker Image Registry Secret Names -*/}} -{{- define "kubeapps.imagePullSecrets" -}} -{{ include "common.images.renderPullSecrets" (dict "images" (list .Values.frontend.image .Values.dashboard.image .Values.apprepository.image .Values.apprepository.syncImage .Values.authProxy.image .Values.pinnipedProxy.image .Values.kubeappsapis.image) "context" $) }} -{{- end -}} - -{{/* -Return the proper Kubeapps apprepository-controller image name -*/}} -{{- define "kubeapps.apprepository.image" -}} -{{- include "common.images.image" (dict "imageRoot" .Values.apprepository.image "global" .Values.global) -}} -{{- end -}} - -{{/* -Return the proper apprepository-controller sync image name -*/}} -{{- define "kubeapps.apprepository.syncImage" -}} -{{- include "common.images.image" (dict "imageRoot" .Values.apprepository.syncImage "global" .Values.global) -}} -{{- end -}} - -{{/* -Return the proper dashboard image name -*/}} -{{- define "kubeapps.dashboard.image" -}} -{{- include "common.images.image" (dict "imageRoot" .Values.dashboard.image "global" .Values.global) -}} -{{- end -}} - -{{/* -Return the proper frontend image name -*/}} -{{- define "kubeapps.frontend.image" -}} -{{- include "common.images.image" (dict "imageRoot" .Values.frontend.image "global" .Values.global) -}} -{{- end -}} - -{{/* -Return the proper auth proxy image name -*/}} -{{- define "kubeapps.authProxy.image" -}} -{{- include "common.images.image" (dict "imageRoot" .Values.authProxy.image "global" .Values.global) -}} -{{- end -}} - -{{/* -Return the proper pinniped proxy image name -*/}} -{{- define "kubeapps.pinnipedProxy.image" -}} -{{- include "common.images.image" (dict "imageRoot" .Values.pinnipedProxy.image "global" .Values.global) -}} -{{- end -}} - -{{/* -Return the proper kubeappsapis image name -*/}} -{{- define "kubeapps.kubeappsapis.image" -}} -{{- include "common.images.image" (dict "imageRoot" .Values.kubeappsapis.image "global" .Values.global) -}} -{{- end -}} - -{{/* -Return the proper oci-catalog image name -*/}} -{{- define "kubeapps.ociCatalog.image" -}} -{{- include "common.images.image" (dict "imageRoot" .Values.ociCatalog.image "global" .Values.global) -}} -{{- end -}} - -{{/* -Create a default fully qualified app name for PostgreSQL dependency. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -*/}} -{{- define "kubeapps.postgresql.fullname" -}} -{{- include "common.names.dependency.fullname" (dict "chartName" "postgresql" "chartValues" .Values.postgresql "context" $) -}} -{{- end -}} - -{{/* -Return the Postgresql Hostname -*/}} -{{- define "kubeapps.postgresql.host" -}} -{{- if .Values.postgresql.enabled }} - {{- if eq .Values.postgresql.architecture "replication" }} - {{- printf "%s-primary" (include "kubeapps.postgresql.fullname" .) | trunc 63 | trimSuffix "-" -}} - {{- else -}} - {{- printf "%s" (include "kubeapps.postgresql.fullname" .) -}} - {{- end -}} -{{- else -}} - {{- printf "%s" .Values.externalDatabase.host -}} -{{- end -}} -{{- end -}} - -{{/* -Return the Postgresql Port -*/}} -{{- define "kubeapps.postgresql.port" -}} -{{- if .Values.postgresql.enabled }} - {{- print "5432" -}} -{{- else -}} - {{- printf "%d" (int .Values.externalDatabase.port) -}} -{{- end -}} -{{- end -}} - -{{/* -Create a default fully qualified app name for Redis dependency. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -*/}} -{{- define "kubeapps.redis.fullname" -}} -{{- include "common.names.dependency.fullname" (dict "chartName" "redis" "chartValues" .Values.redis "context" $) -}} -{{- end -}} - -{{/* -Create name for the apprepository-controller based on the fullname -*/}} -{{- define "kubeapps.apprepository.fullname" -}} -{{- printf "%s-internal-apprepository-controller" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create name for the apprepository-controller based on the namespace -*/}} -{{- define "kubeapps.apprepository.fullname.namespace" -}} -{{- printf "%s-internal-apprepository-controller" (include "common.names.fullname.namespace" .) | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create name for the dashboard based on the fullname -*/}} -{{- define "kubeapps.dashboard.fullname" -}} -{{- printf "%s-internal-dashboard" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create name for the dashboard config based on the fullname -*/}} -{{- define "kubeapps.dashboard-config.fullname" -}} -{{- printf "%s-internal-dashboard-config" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create name for the frontend config based on the fullname -*/}} -{{- define "kubeapps.frontend-config.fullname" -}} -{{- printf "%s-frontend-config" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create name for kubeappsapis based on the fullname -*/}} -{{- define "kubeapps.kubeappsapis.fullname" -}} -{{- printf "%s-internal-kubeappsapis" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create name for the clusters config based on the fullname -*/}} -{{- define "kubeapps.clusters-config.fullname" -}} -{{- printf "%s-clusters-config" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create the name of the apprepository-controller service account to use -*/}} -{{- define "kubeapps.apprepository.serviceAccountName" -}} -{{- if .Values.apprepository.serviceAccount.create -}} - {{- default (include "kubeapps.apprepository.fullname" .) .Values.apprepository.serviceAccount.name -}} -{{- else -}} - {{- default "default" .Values.apprepository.serviceAccount.name -}} -{{- end -}} -{{- end -}} - -{{/* -Create the name of the kubeappsapis service account to use -*/}} -{{- define "kubeapps.kubeappsapis.serviceAccountName" -}} -{{- if .Values.kubeappsapis.serviceAccount.create -}} - {{- default (include "kubeapps.kubeappsapis.fullname" .) .Values.kubeappsapis.serviceAccount.name -}} -{{- else -}} - {{- default "default" .Values.kubeappsapis.serviceAccount.name -}} -{{- end -}} -{{- end -}} - -{{/* -Create proxy_pass for the kubeappsapis -*/}} -{{- define "kubeapps.kubeappsapis.proxy_pass" -}} -{{- printf "http://%s:%d" (include "kubeapps.kubeappsapis.fullname" .) (int .Values.kubeappsapis.service.ports.http) -}} -{{- end -}} - -{{/* -Create name for the secrets related to oauth2_proxy -*/}} -{{- define "kubeapps.oauth2_proxy-secret.name" -}} -{{- if .Values.authProxy.existingOauth2Secret -}} -{{- printf "%s" (tpl .Values.authProxy.existingOauth2Secret $) -}} -{{- else -}} -{{- printf "%s-oauth2" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} - -{{/* -Create name for pinniped-proxy based on the fullname. -Currently used for a service name only. -*/}} -{{- define "kubeapps.pinniped-proxy.fullname" -}} -{{- printf "%s-internal-pinniped-proxy" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Repositories that include a caCert or an authorizationHeader -*/}} -{{- define "kubeapps.repos-with-orphan-secrets" -}} -{{- range .Values.apprepository.initialRepos }} -{{- if or .caCert .authorizationHeader }} -{{- print "%s" .name -}} -{{- end }} -{{- end }} -{{- end -}} - -{{/* -Frontend service port number -*/}} -{{- define "kubeapps.frontend-port-number" -}} -{{- if .Values.authProxy.enabled -}} -{{ .Values.authProxy.containerPorts.proxy | int }} -{{- else -}} -{{ .Values.frontend.containerPorts.http | int }} -{{- end -}} -{{- end -}} - -{{/* -Returns the kubeappsCluster based on the configured clusters by finding the cluster without -a defined apiServiceURL. -*/}} -{{- define "kubeapps.kubeappsCluster" -}} - {{- $kubeappsCluster := "" }} - {{- if eq (len .Values.clusters) 0 }} - {{- fail "At least one cluster must be defined." }} - {{- end }} - {{- range .Values.clusters }} - {{- if or .isKubeappsCluster ( eq (.apiServiceURL | toString) "") }} - {{- if eq $kubeappsCluster "" }} - {{- $kubeappsCluster = .name }} - {{- else }} - {{- fail "Only one cluster can be configured using either 'isKubeappsCluster: true' or without an apiServiceURL to refer to the cluster on which Kubeapps is installed. Please check the provided 'clusters' configuration." }} - {{- end }} - {{- end }} - {{- end }} - {{- $kubeappsCluster }} -{{- end -}} - -{{/* -Returns a JSON list of cluster names only (without sensitive tokens etc.) -*/}} -{{- define "kubeapps.clusterNames" -}} - {{- $sanitizedClusters := list }} - {{- range .Values.clusters }} - {{- $sanitizedClusters = append $sanitizedClusters .name }} - {{- end }} - {{- $sanitizedClusters | toJson }} -{{- end -}} - -{{/* -Returns the name of the global packaging namespace for the Helm plugin. -It uses the value passed in the plugin's config, but falls back to the "release namespace + suffix" formula. -*/}} -{{- define "kubeapps.helmGlobalPackagingNamespace" -}} - {{- if .Values.kubeappsapis.pluginConfig.helm.packages.v1alpha1.globalPackagingNamespace }} - {{- printf "%s" .Values.kubeappsapis.pluginConfig.helm.packages.v1alpha1.globalPackagingNamespace -}} - {{- else -}} - {{- printf "%s%s" .Release.Namespace .Values.apprepository.globalReposNamespaceSuffix -}} - {{- end -}} -{{- end -}} - -{{/* -Return the Postgresql secret name -*/}} -{{- define "kubeapps.postgresql.secretName" -}} - {{- if .Values.postgresql.auth.existingSecret }} - {{- printf "%s" .Values.postgresql.auth.existingSecret -}} - {{- else -}} - {{- printf "%s" (include "kubeapps.postgresql.fullname" .) -}} - {{- end -}} -{{- end -}} - -{{/* -Return the Redis secret name -*/}} -{{- define "kubeapps.redis.secretName" -}} - {{- if .Values.redis.auth.existingSecret }} - {{- printf "%s" .Values.redis.auth.existingSecret -}} - {{- else -}} - {{- printf "%s" (include "kubeapps.redis.fullname" .) -}} - {{- end -}} -{{- end -}} - -{{/* -Compile all warnings into a single message, and call fail. -*/}} -{{- define "kubeapps.validateValues" -}} -{{- $messages := list -}} -{{- $messages := append $messages (include "kubeapps.validateValues.ingress.tls" .) -}} -{{- $messages := without $messages "" -}} -{{- $message := join "\n" $messages -}} - -{{- if $message -}} -{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}} -{{- end -}} -{{- end -}} - -{{/* -Validate values of Kubeapps - TLS configuration for Ingress -*/}} -{{- define "kubeapps.validateValues.ingress.tls" -}} -{{- if and .Values.ingress.enabled .Values.ingress.tls (not (include "common.ingress.certManagerRequest" ( dict "annotations" .Values.ingress.annotations ))) (not .Values.ingress.selfSigned) (empty .Values.ingress.extraTls) }} -kubeapps: ingress.tls - You enabled the TLS configuration for the default ingress hostname but - you did not enable any of the available mechanisms to create the TLS secret - to be used by the Ingress Controller. - Please use any of these alternatives: - - Use the `ingress.extraTls` and `ingress.secrets` parameters to provide your custom TLS certificates. - - Rely on cert-manager to create it by adding its supported annotations in `ingress.annotations` - - Rely on Helm to create self-signed certificates by setting `ingress.selfSigned=true` -{{- end -}} -{{- end -}} - -{{/* -# Calculate the kubeappsapis enabledPlugins. -*/}} -{{- define "kubeapps.kubeappsapis.enabledPlugins" -}} - {{- $enabledPlugins := list }} - {{- if .Values.kubeappsapis.enabledPlugins }} - {{- $enabledPlugins = .Values.kubeappsapis.enabledPlugins }} - {{- else }} - {{- if and .Values.packaging.flux.enabled .Values.packaging.helm.enabled }} - {{- fail "packaging: Please enable only one of the flux and helm plugins, since they both operate on Helm releases." }} - {{- end -}} - {{- range $plugin, $options := .Values.packaging }} - {{- if $options.enabled }} - {{- if eq $plugin "carvel" }} - {{- $enabledPlugins = append $enabledPlugins "kapp-controller-packages" }} - {{- else if eq $plugin "flux" }} - {{- $enabledPlugins = append $enabledPlugins "fluxv2-packages" }} - {{- else if eq $plugin "helm" }} - {{- $enabledPlugins = append $enabledPlugins "helm-packages" }} - {{- else }} - {{ $msg := printf "packaging: Unsupported packaging option: %s" $plugin }} - {{- fail $msg }} - {{- end }} - {{- end }} - {{- end }} - {{- if not $enabledPlugins }} - {{- fail "packaging: Please enable at least one of the packaging plugins." }} - {{- end }} - {{- $enabledPlugins = append $enabledPlugins "resources" }} - {{- end }} - {{- $enabledPlugins | toJson }} -{{- end -}} - -{{/* -Check if there are rolling tags in the images -*/}} -{{- define "kubeapps.checkRollingTags" -}} -{{- include "common.warnings.rollingTag" .Values.frontend.image }} -{{- include "common.warnings.rollingTag" .Values.dashboard.image }} -{{- include "common.warnings.rollingTag" .Values.apprepository.image }} -{{- include "common.warnings.rollingTag" .Values.authProxy.image }} -{{- include "common.warnings.rollingTag" .Values.pinnipedProxy.image }} -{{- include "common.warnings.rollingTag" .Values.kubeappsapis.image }} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/templates/apprepository/apprepositories-secret.yaml b/packages/system/dashboard/charts/kubeapps/templates/apprepository/apprepositories-secret.yaml deleted file mode 100644 index bdd52c20..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/apprepository/apprepositories-secret.yaml +++ /dev/null @@ -1,60 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.packaging.helm.enabled }} -{{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.apprepository.image "chart" .Chart ) ) }} -{{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} -{{- range .Values.apprepository.initialRepos }} -{{- if or .caCert .authorizationHeader .basicAuth }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ printf "apprepo-%s-secrets" .name }} - namespace: {{ default (include "kubeapps.helmGlobalPackagingNamespace" $) .namespace | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - {{- if $.Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $.Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -data: - {{- if .caCert }} - ca.crt: |- - {{ .caCert | b64enc }} - {{- end }} - {{- $authorizationHeader := "" }} - {{- if .authorizationHeader }} - {{- $authorizationHeader = .authorizationHeader }} - {{- else if .basicAuth }} - {{- $authorizationHeader = printf "Basic %s" (printf "%s:%s" .basicAuth.user .basicAuth.password | b64enc) }} - {{- end }} - {{- if $authorizationHeader }} - authorizationHeader: |- - {{ $authorizationHeader | b64enc }} - {{- end }} ---- -{{/* credentials are required in the release namespace for syncer jobs */}} -{{- if or .namespace $.Values.apprepository.globalReposNamespaceSuffix $.Values.kubeappsapis.pluginConfig.helm.packages.v1alpha1.globalPackagingNamespace}} -apiVersion: v1 -kind: Secret -metadata: - name: {{ printf "%s-apprepo-%s" (default (include "kubeapps.helmGlobalPackagingNamespace" $) .namespace) .name }} - namespace: {{ $.Release.Namespace | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - {{- if $.Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $.Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -data: - {{- if .caCert }} - ca.crt: |- - {{ .caCert | b64enc }} - {{- end }} - {{- if $authorizationHeader }} - authorizationHeader: |- - {{ $authorizationHeader | b64enc }} - {{- end }} ---- -{{- end }} -{{- end }} -{{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/apprepository/apprepositories.yaml b/packages/system/dashboard/charts/kubeapps/templates/apprepository/apprepositories.yaml deleted file mode 100644 index 1158c79f..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/apprepository/apprepositories.yaml +++ /dev/null @@ -1,78 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.packaging.helm.enabled }} -{{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.apprepository.image "chart" .Chart ) ) }} -{{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} -{{- range .Values.apprepository.initialRepos }} -apiVersion: kubeapps.com/v1alpha1 -kind: AppRepository -metadata: - name: {{ .name }} - namespace: {{ default (include "kubeapps.helmGlobalPackagingNamespace" $) .namespace | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - {{- if $.Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $.Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - type: {{ default "helm" .type }} - url: {{ .url }} - {{- if .ociRepositories }} - ociRepositories: - {{- range .ociRepositories }} - - {{ . }} - {{- end }} - {{- end }} - {{- if or $.Values.apprepository.podSecurityContext.enabled $.Values.apprepository.containerSecurityContext.enabled $.Values.apprepository.initialReposProxy.enabled .nodeSelector .tolerations}} - syncJobPodTemplate: - spec: - {{- if or $.Values.apprepository.initialReposProxy.enabled $.Values.apprepository.containerSecurityContext.enabled }} - containers: - - - {{- if $.Values.apprepository.initialReposProxy.enabled }} - env: - - name: https_proxy - value: {{ $.Values.apprepository.initialReposProxy.httpsProxy }} - - name: http_proxy - value: {{ $.Values.apprepository.initialReposProxy.httpProxy }} - - name: no_proxy - value: {{ $.Values.apprepository.initialReposProxy.noProxy }} - {{- end }} - {{- if $.Values.apprepository.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" $.Values.apprepository.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - {{- end }} - {{- if $.Values.apprepository.podSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" $.Values.apprepository.podSecurityContext "context" $) | nindent 8 }} - {{- end }} - {{- if .nodeSelector }} - nodeSelector: {{- toYaml .nodeSelector | nindent 8 }} - {{- end }} - {{- if .tolerations }} - tolerations: {{- toYaml .tolerations | nindent 8 }} - {{- end }} - {{- end }} - {{- if or .caCert .authorizationHeader .basicAuth }} - auth: - {{- if .caCert }} - customCA: - secretKeyRef: - key: ca.crt - name: {{ printf "apprepo-%s-secrets" .name }} - {{- end }} - {{- if or .authorizationHeader .basicAuth }} - header: - secretKeyRef: - key: authorizationHeader - name: {{ printf "apprepo-%s-secrets" .name }} - {{- end }} - {{- end }} - {{- if .filterRule }} - filterRule: - {{- toYaml .filterRule | nindent 4 }} - {{- end }} ---- -{{ end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/templates/apprepository/deployment.yaml b/packages/system/dashboard/charts/kubeapps/templates/apprepository/deployment.yaml deleted file mode 100644 index 5a9ba1b4..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/apprepository/deployment.yaml +++ /dev/null @@ -1,166 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.packaging.helm.enabled }} -apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} -kind: Deployment -metadata: - name: {{ template "kubeapps.apprepository.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.apprepository.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: apprepository - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - replicas: {{ .Values.apprepository.replicaCount }} - {{- if .Values.apprepository.updateStrategy }} - strategy: {{- toYaml .Values.apprepository.updateStrategy | nindent 4 }} - {{- end }} - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.apprepository.podLabels .Values.commonLabels $versionLabel ) "context" . ) }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: apprepository - template: - metadata: - {{- if .Values.apprepository.podAnnotations }} - annotations: {{- include "common.tplvalues.render" (dict "value" .Values.apprepository.podAnnotations "context" $) | nindent 8 }} - {{- end }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $podLabels "context" $ ) | nindent 8 }} - app.kubernetes.io/component: apprepository - spec: - {{- include "kubeapps.imagePullSecrets" . | nindent 6 }} - serviceAccountName: {{ template "kubeapps.apprepository.serviceAccountName" . }} - automountServiceAccountToken: {{ .Values.apprepository.automountServiceAccountToken }} - {{- if .Values.apprepository.hostAliases }} - hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.apprepository.hostAliases "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.apprepository.affinity }} - affinity: {{- include "common.tplvalues.render" (dict "value" .Values.apprepository.affinity "context" $) | nindent 8 }} - {{- else }} - affinity: - podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.apprepository.podAffinityPreset "component" "apprepository" "customLabels" $podLabels "context" $) | nindent 10 }} - podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.apprepository.podAntiAffinityPreset "component" "apprepository" "customLabels" $podLabels "context" $) | nindent 10 }} - nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.apprepository.nodeAffinityPreset.type "key" .Values.apprepository.nodeAffinityPreset.key "values" .Values.apprepository.nodeAffinityPreset.values) | nindent 10 }} - {{- end }} - {{- if .Values.apprepository.schedulerName }} - schedulerName: {{ .Values.apprepository.schedulerName }} - {{- end }} - {{- if .Values.apprepository.topologySpreadConstraints }} - topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.apprepository.topologySpreadConstraints "context" .) | nindent 8 }} - {{- end }} - {{- if .Values.apprepository.nodeSelector }} - nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.apprepository.nodeSelector "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.apprepository.tolerations }} - tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.apprepository.tolerations "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.apprepository.priorityClassName }} - priorityClassName: {{ .Values.apprepository.priorityClassName | quote }} - {{- end }} - {{- if .Values.apprepository.podSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.apprepository.podSecurityContext "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.apprepository.initContainers }} - initContainers: {{- include "common.tplvalues.render" (dict "value" .Values.apprepository.initContainers "context" $) | trim | nindent 8 }} - {{- end }} - containers: - - name: controller - image: {{ include "kubeapps.apprepository.image" . }} - imagePullPolicy: {{ .Values.apprepository.image.pullPolicy | quote }} - {{- if .Values.apprepository.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.apprepository.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.apprepository.lifecycleHooks }} - lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.apprepository.lifecycleHooks "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.apprepository.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.apprepository.command "context" $) | nindent 12 }} - {{- else }} - command: - - /apprepository-controller - {{- end }} - {{- if .Values.apprepository.args }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.apprepository.args "context" $) | nindent 12 }} - {{- else }} - args: - - --user-agent-comment={{ printf "kubeapps/%s" .Chart.AppVersion }} - - --repo-sync-image=$(REPO_SYNC_IMAGE) - {{- if .Values.global }} - {{- if.Values.global.imagePullSecrets }} - {{- range $key, $value := .Values.global.imagePullSecrets }} - - --repo-sync-image-pullsecrets={{ $value | quote }} - {{- end }} - {{- end }} - {{- end }} - - --repo-sync-cmd=/asset-syncer - - --namespace={{ .Release.Namespace }} - - --global-repos-namespace={{ include "kubeapps.helmGlobalPackagingNamespace" . }} - - --database-secret-name={{ include "kubeapps.postgresql.secretName" . }} - - --database-secret-key=postgres-password - - --database-url={{ printf "%s:%d" (include "kubeapps.postgresql.host" .) (int (include "kubeapps.postgresql.port" .)) }} - - --database-user={{ .Values.postgresql.auth.username }} - - --database-name={{ .Values.postgresql.auth.database }} - {{- if .Values.apprepository.crontab }} - - --crontab={{ .Values.apprepository.crontab }} - {{- end }} - - --repos-per-namespace={{ .Values.apprepository.watchAllNamespaces }} - {{- if.Values.apprepository.customAnnotations }} - {{- range $key, $value := .Values.apprepository.customAnnotations }} - - --custom-annotations={{ (print $key "=" $value) | quote }} - {{- end }} - {{- end }} - {{- if.Values.apprepository.customLabels }} - {{- range $key, $value := .Values.apprepository.customLabels }} - - --custom-labels={{ (print $key "=" $value) | quote }} - {{- end }} - {{- end }} - {{- range .Values.apprepository.extraFlags }} - - {{ . }} - {{- end }} - {{- end }} - env: - - name: REPO_SYNC_IMAGE - value: {{ include "kubeapps.apprepository.syncImage" . }} - {{- if .Values.ociCatalog.enabled }} - - name: OCI_CATALOG_URL - value: {{ printf "%s:%d" (include "kubeapps.kubeappsapis.fullname" .) (int .Values.ociCatalog.containerPorts.grpc) | quote }} - {{- end }} - {{- if .Values.apprepository.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.apprepository.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - envFrom: - {{- if .Values.apprepository.extraEnvVarsCM }} - - configMapRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.apprepository.extraEnvVarsCM "context" $) }} - {{- end }} - {{- if .Values.apprepository.extraEnvVarsSecret }} - - secretRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.apprepository.extraEnvVarsSecret "context" $) }} - {{- end }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - {{- if .Values.apprepository.extraVolumeMounts }} - {{- include "common.tplvalues.render" (dict "value" .Values.apprepository.extraVolumeMounts "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.apprepository.resources }} - resources: {{- toYaml .Values.apprepository.resources | nindent 12 }} - {{- else if ne .Values.apprepository.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.apprepository.resourcesPreset) | nindent 12 }} - {{- end }} - {{- if .Values.apprepository.sidecars }} - {{- include "common.tplvalues.render" (dict "value" .Values.apprepository.sidecars "context" $) | trim | nindent 8 }} - {{- end }} - volumes: - - name: empty-dir - emptyDir: {} - {{- if .Values.apprepository.extraVolumes }} - {{- include "common.tplvalues.render" (dict "value" .Values.apprepository.extraVolumes "context" $) | nindent 8 }} - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/apprepository/networkpolicy.yaml b/packages/system/dashboard/charts/kubeapps/templates/apprepository/networkpolicy.yaml deleted file mode 100644 index 087b45a3..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/apprepository/networkpolicy.yaml +++ /dev/null @@ -1,59 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.packaging.helm.enabled .Values.apprepository.networkPolicy.enabled }} -kind: NetworkPolicy -apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} -metadata: - name: {{ include "kubeapps.apprepository.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.apprepository.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: apprepository - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - policyTypes: - - Ingress - - Egress - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.apprepository.podLabels .Values.commonLabels ) "context" . ) }} - podSelector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: apprepository - {{- if .Values.apprepository.networkPolicy.allowExternalEgress }} - egress: - - {} - {{- else }} - egress: - # Allow dns resolution - - ports: - - port: 53 - protocol: UDP - - port: 53 - protocol: TCP - {{- range $port := .Values.apprepository.networkPolicy.kubeAPIServerPorts }} - - port: {{ $port }} - {{- end }} - # Allow connection to PostgreSQL - - ports: - - port: {{ include "kubeapps.postgresql.port" . }} - {{- if .Values.postgresql.enabled }} - to: - - podSelector: - matchLabels: - app.kubernetes.io/name: postgresql - app.kubernetes.io/instance: {{ .Release.Name }} - {{- end }} - {{- if .Values.apprepository.networkPolicy.extraEgress }} - {{- include "common.tplvalues.render" ( dict "value" .Values.apprepository.networkPolicy.extraEgress "context" $ ) | nindent 4 }} - {{- end }} - {{- end }} - ingress: - {{- if .Values.apprepository.networkPolicy.extraIngress }} - {{- include "common.tplvalues.render" ( dict "value" .Values.apprepository.networkPolicy.extraIngress "context" $ ) | nindent 4 }} - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/apprepository/pdb.yaml b/packages/system/dashboard/charts/kubeapps/templates/apprepository/pdb.yaml deleted file mode 100644 index a71a3635..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/apprepository/pdb.yaml +++ /dev/null @@ -1,30 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.packaging.helm.enabled .Values.apprepository.pdb.create }} -apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} -kind: PodDisruptionBudget -metadata: - name: {{ template "kubeapps.apprepository.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.apprepository.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: apprepository - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - {{- if .Values.apprepository.pdb.minAvailable }} - minAvailable: {{ .Values.apprepository.pdb.minAvailable }} - {{- end }} - {{- if or .Values.apprepository.pdb.maxUnavailable ( not .Values.apprepository.pdb.minAvailable ) }} - maxUnavailable: {{ .Values.apprepository.pdb.maxUnavailable | default 1 }} - {{- end }} - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.apprepository.podLabels .Values.commonLabels $versionLabel ) "context" . ) }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: apprepository -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/apprepository/rbac.yaml b/packages/system/dashboard/charts/kubeapps/templates/apprepository/rbac.yaml deleted file mode 100644 index 3f39dab1..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/apprepository/rbac.yaml +++ /dev/null @@ -1,256 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.packaging.helm.enabled }} -{{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.apprepository.image "chart" .Chart ) ) }} -{{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} -{{- if .Values.rbac.create -}} -# Role for managing events, jobs and cronjobs in the release namespace -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: Role -metadata: - name: {{ template "kubeapps.apprepository.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: apprepository - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -rules: - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - - apiGroups: - - batch - resources: - - cronjobs - verbs: - - create - - get - - list - - update - - watch - - delete - - apiGroups: - - batch - resources: - - jobs - verbs: - - create ---- -# ClusterRole for managing AppRepository objects in every namespace, -# so that we can update the finalizers on AppRepository objects -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: ClusterRole -metadata: - name: {{ template "kubeapps.apprepository.fullname.namespace" . }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: apprepository - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -rules: - - apiGroups: - - kubeapps.com - resources: - - apprepositories - - apprepositories/finalizers - verbs: - - get - - list - - watch - - create - - update - - patch ---- -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: RoleBinding -metadata: - name: {{ template "kubeapps.apprepository.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: apprepository - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: {{ template "kubeapps.apprepository.fullname" . }} -subjects: - - kind: ServiceAccount - name: {{ template "kubeapps.apprepository.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} ---- -# ClusterRoleBinding for the apprepository controller SA -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: ClusterRoleBinding -metadata: - name: {{ template "kubeapps.apprepository.fullname.namespace" . }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: apprepository - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ template "kubeapps.apprepository.fullname.namespace" . }} -subjects: - - kind: ServiceAccount - name: {{ template "kubeapps.apprepository.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} ---- -# Define role, but no binding, so users can be bound to this role -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: Role -metadata: - name: {{ printf "%s-repositories-read" .Release.Name }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: apprepository - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -rules: - - apiGroups: - - kubeapps.com - resources: - - apprepositories - verbs: - - list - - get ---- -# Define role, but no binding, so users can be bound to this role -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: Role -metadata: - name: {{ printf "%s-repositories-write" .Release.Name }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: apprepository - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -rules: - - apiGroups: - - kubeapps.com - resources: - - apprepositories - verbs: - - "*" - - apiGroups: - - "" - resources: - - secrets - verbs: - - create ---- -# The Kubeapps app repository controller can read and watch its own -# AppRepository resources cluster-wide. The read and write cluster-roles can -# also be bound to users in specific namespaces as required. -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: ClusterRole -metadata: - name: {{ printf "kubeapps:%s:apprepositories-read" .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: apprepository - rbac.authorization.k8s.io/aggregate-to-view: "true" - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -rules: - - apiGroups: - - kubeapps.com - resources: - - apprepositories - - apprepositories/finalizers - verbs: - - get - - list - - watch ---- -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: ClusterRoleBinding -metadata: - name: {{ printf "kubeapps:controller:%s:apprepositories-read" .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: apprepository - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ printf "kubeapps:%s:apprepositories-read" .Release.Namespace | quote }} -subjects: - - kind: ServiceAccount - name: {{ template "kubeapps.apprepository.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} ---- -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: ClusterRole -metadata: - name: {{ printf "kubeapps:%s:apprepositories-write" .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: apprepository - rbac.authorization.k8s.io/aggregate-to-edit: "true" - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -rules: - - apiGroups: - - kubeapps.com - resources: - - apprepositories - verbs: - - '*' - - apiGroups: - - "" - resources: - - secrets - verbs: - - '*' ---- -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: ClusterRole -metadata: - name: {{ printf "kubeapps:%s:apprepositories-refresh" .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: apprepository - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -rules: - - apiGroups: - - kubeapps.com - resources: - - apprepositories - verbs: - - get - - update ---- -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: RoleBinding -metadata: - name: {{ printf "kubeapps:%s:global-repos-read" .Release.Namespace | quote }} - namespace: {{ include "kubeapps.helmGlobalPackagingNamespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ printf "kubeapps:%s:apprepositories-read" .Release.Namespace | quote }} -subjects: - - kind: Group - name: system:authenticated -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/templates/apprepository/serviceaccount.yaml b/packages/system/dashboard/charts/kubeapps/templates/apprepository/serviceaccount.yaml deleted file mode 100644 index eff68f9c..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/apprepository/serviceaccount.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.apprepository.serviceAccount.create .Values.packaging.helm.enabled }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ template "kubeapps.apprepository.serviceAccountName" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.apprepository.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: apprepository - {{- if or .Values.apprepository.serviceAccount.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.apprepository.serviceAccount.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -automountServiceAccountToken: {{ .Values.apprepository.serviceAccount.automountServiceAccountToken }} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/templates/dashboard/configmap.yaml b/packages/system/dashboard/charts/kubeapps/templates/dashboard/configmap.yaml deleted file mode 100644 index 0b8167a0..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/dashboard/configmap.yaml +++ /dev/null @@ -1,92 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.dashboard.enabled -}} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "kubeapps.dashboard-config.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.dashboard.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: dashboard - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -data: - vhost.conf: |- - server { - listen {{ .Values.dashboard.containerPorts.http }}; - {{- if .Values.frontend.largeClientHeaderBuffers }} - large_client_header_buffers {{ .Values.frontend.largeClientHeaderBuffers }}; - {{- end }} - {{- if .Values.enableIPv6 }} - listen [::]:{{ .Values.dashboard.containerPorts.http }}; - {{- end }} - server_name _; - - gzip on; - gzip_static on; - - location /custom_style.css { - root /app/custom-css/; - } - - location /custom_locale.json { - root /app/custom-locale/; - } - - location /custom_components.js { - root /app/custom-components/; - } - - location / { - # Redirects are required to be relative otherwise the internal hostname will be exposed - absolute_redirect off; - - # Trailing / is required in the path for the React app to be loaded correctly - # The rewrite rule adds a trailing "/" to any path that does not contain "." neither "/". - # i.e kubeapps => kubeapps/ - rewrite ^([^.]*[^/])$ $1/ permanent; - - # Support for ingress prefixes maintaining compatibility with the default / - # 1 - Exactly two fragment URLs for files existing inside of the public/ dir - # i.e /[prefix]/config.json => /config.json - rewrite ^/[^/]+/([^/]+)$ /$1 break; - - # 2 - Any static files bundled by webpack referenced by 3 or more URL segments - # i.e /[prefix]/static/main.js => static/main.js - rewrite ^/[^/]+/static/(.*) /static/$1 break; - - try_files $uri /index.html; - } - } - custom_style.css: |- -{{- .Values.dashboard.customStyle | nindent 4 }} - custom_components.js: |- -{{- .Values.dashboard.customComponents | nindent 4 }} - custom_locale.json: |- -{{- .Values.dashboard.customLocale | toJson | nindent 4 }} - config.json: |- - { - "kubeappsCluster": {{ include "kubeapps.kubeappsCluster" . | quote }}, - "kubeappsNamespace": {{ .Release.Namespace | quote }}, - "helmGlobalNamespace": {{ include "kubeapps.helmGlobalPackagingNamespace" . | quote }}, - "carvelGlobalNamespace": {{ .Values.kubeappsapis.pluginConfig.kappController.packages.v1alpha1.globalPackagingNamespace | quote }}, - "appVersion": "v0.33.2", - "authProxyEnabled": {{ .Values.authProxy.enabled }}, - "oauthLoginURI": {{ .Values.authProxy.oauthLoginURI | quote }}, - "oauthLogoutURI": {{ .Values.authProxy.oauthLogoutURI | quote }}, - "authProxySkipLoginPage": {{ .Values.authProxy.skipKubeappsLoginPage }}, - "featureFlags": {{ .Values.featureFlags | toJson }}, - "clusters": {{ include "kubeapps.clusterNames" . }}, - "theme": {{ .Values.dashboard.defaultTheme | quote }}, - "remoteComponentsUrl": {{ .Values.dashboard.remoteComponentsUrl | quote }}, - "customAppViews": {{ .Values.dashboard.customAppViews | toJson }}, - "skipAvailablePackageDetails": {{ .Values.dashboard.skipAvailablePackageDetails }}, - "createNamespaceLabels": {{ .Values.dashboard.createNamespaceLabels | toJson }} - } -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/templates/dashboard/deployment.yaml b/packages/system/dashboard/charts/kubeapps/templates/dashboard/deployment.yaml deleted file mode 100644 index e474ed18..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/dashboard/deployment.yaml +++ /dev/null @@ -1,202 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.dashboard.enabled }} -apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} -kind: Deployment -metadata: - name: {{ template "kubeapps.dashboard.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.dashboard.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: dashboard - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - replicas: {{ .Values.dashboard.replicaCount }} - {{- if .Values.dashboard.updateStrategy }} - strategy: {{- toYaml .Values.dashboard.updateStrategy | nindent 4 }} - {{- end }} - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.dashboard.podLabels .Values.commonLabels $versionLabel ) "context" . ) }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: dashboard - template: - metadata: - annotations: - checksum/config: {{ include (print $.Template.BasePath "/dashboard/configmap.yaml") . | sha256sum }} - {{- if .Values.dashboard.podAnnotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.podAnnotations "context" $) | nindent 8 }} - {{- end }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $podLabels "context" $ ) | nindent 8 }} - app.kubernetes.io/component: dashboard - spec: - {{- include "kubeapps.imagePullSecrets" . | nindent 6 }} - automountServiceAccountToken: {{ .Values.dashboard.automountServiceAccountToken }} - {{- if .Values.dashboard.hostAliases }} - hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.hostAliases "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.dashboard.affinity }} - affinity: {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.affinity "context" $) | nindent 8 }} - {{- else }} - affinity: - podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.dashboard.podAffinityPreset "component" "dashboard" "customLabels" $podLabels "context" $) | nindent 10 }} - podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.dashboard.podAntiAffinityPreset "component" "dashboard" "customLabels" $podLabels "context" $) | nindent 10 }} - nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.dashboard.nodeAffinityPreset.type "key" .Values.dashboard.nodeAffinityPreset.key "values" .Values.dashboard.nodeAffinityPreset.values) | nindent 10 }} - {{- end }} - {{- if .Values.dashboard.schedulerName }} - schedulerName: {{ .Values.dashboard.schedulerName }} - {{- end }} - {{- if .Values.dashboard.topologySpreadConstraints }} - topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.topologySpreadConstraints "context" .) | nindent 8 }} - {{- end }} - {{- if .Values.dashboard.nodeSelector }} - nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.nodeSelector "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.dashboard.tolerations }} - tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.tolerations "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.dashboard.priorityClassName }} - priorityClassName: {{ .Values.dashboard.priorityClassName | quote }} - {{- end }} - {{- if .Values.dashboard.podSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.dashboard.podSecurityContext "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.dashboard.initContainers }} - initContainers: {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.initContainers "context" $) | nindent 8 }} - {{- end }} - containers: - - name: dashboard - image: {{ include "kubeapps.dashboard.image" . }} - imagePullPolicy: {{ .Values.dashboard.image.pullPolicy | quote }} - {{- if .Values.dashboard.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.dashboard.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} - {{- else if .Values.dashboard.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.command "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} - {{- else if .Values.dashboard.args }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.args "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.dashboard.lifecycleHooks }} - lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.lifecycleHooks "context" $) | nindent 12 }} - {{- end }} - env: - - name: BITNAMI_DEBUG - value: {{ ternary "true" "false" .Values.dashboard.image.debug | quote }} - {{- if .Values.dashboard.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - envFrom: - {{- if .Values.dashboard.extraEnvVarsCM }} - - configMapRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.dashboard.extraEnvVarsCM "context" $) }} - {{- end }} - {{- if .Values.dashboard.extraEnvVarsSecret }} - - secretRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.dashboard.extraEnvVarsSecret "context" $) }} - {{- end }} - ports: - - name: http - containerPort: {{ .Values.dashboard.containerPorts.http }} - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.dashboard.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.customLivenessProbe "context" $) | nindent 12 }} - {{- else if .Values.dashboard.livenessProbe.enabled }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.dashboard.livenessProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: http - {{- end }} - {{- if .Values.dashboard.customReadinessProbe }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.customReadinessProbe "context" $) | nindent 12 }} - {{- else if .Values.dashboard.readinessProbe.enabled }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.dashboard.readinessProbe "enabled") "context" $) | nindent 12 }} - httpGet: - path: / - port: http - {{- end }} - {{- if .Values.dashboard.customStartupProbe }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.customStartupProbe "context" $) | nindent 12 }} - {{- else if .Values.dashboard.startupProbe.enabled }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.dashboard.startupProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: http - {{- end }} - {{- end }} - {{- if .Values.dashboard.resources }} - resources: {{- toYaml .Values.dashboard.resources | nindent 12 }} - {{- else if ne .Values.dashboard.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.dashboard.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: vhost - mountPath: /opt/bitnami/nginx/conf/server_blocks - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - - name: empty-dir - mountPath: /opt/bitnami/nginx/tmp - subPath: app-tmp-dir - - name: empty-dir - mountPath: /opt/bitnami/nginx/logs - subPath: app-logs-dir - - name: config - mountPath: /app/config.json - subPath: config.json - - mountPath: /app/custom-css - name: custom-css - - mountPath: /app/custom-locale - name: custom-locale - - mountPath: /app/custom-components - name: custom-components - {{- if .Values.dashboard.extraVolumeMounts }} - {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.extraVolumeMounts "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.dashboard.sidecars }} - {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.sidecars "context" $) | nindent 8 }} - {{- end }} - volumes: - - name: empty-dir - emptyDir: {} - - name: vhost - configMap: - name: {{ template "kubeapps.dashboard-config.fullname" . }} - items: - - key: vhost.conf - path: vhost.conf - - name: config - configMap: - name: {{ template "kubeapps.dashboard-config.fullname" . }} - items: - - key: config.json - path: config.json - - name: custom-css - configMap: - name: {{ template "kubeapps.dashboard-config.fullname" . }} - items: - - key: custom_style.css - path: custom_style.css - - name: custom-locale - configMap: - name: {{ template "kubeapps.dashboard-config.fullname" . }} - items: - - key: custom_locale.json - path: custom_locale.json - - name: custom-components - configMap: - name: {{ template "kubeapps.dashboard-config.fullname" . }} - items: - - key: custom_components.js - path: custom_components.js - {{- if .Values.dashboard.extraVolumes }} - {{- include "common.tplvalues.render" (dict "value" .Values.dashboard.extraVolumes "context" $) | nindent 8 }} - {{- end }} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/templates/dashboard/networkpolicy.yaml b/packages/system/dashboard/charts/kubeapps/templates/dashboard/networkpolicy.yaml deleted file mode 100644 index 63b27c42..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/dashboard/networkpolicy.yaml +++ /dev/null @@ -1,71 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.dashboard.enabled .Values.dashboard.networkPolicy.enabled }} -kind: NetworkPolicy -apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} -metadata: - name: {{ include "kubeapps.dashboard.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.dashboard.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: dashboard - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - policyTypes: - - Ingress - - Egress - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.dashboard.podLabels .Values.commonLabels $versionLabel ) "context" . ) }} - podSelector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: dashboard - {{- if .Values.dashboard.networkPolicy.allowExternalEgress }} - egress: - - {} - {{- else }} - egress: - # Allow dns resolution - - ports: - - port: 53 - protocol: UDP - - port: 53 - protocol: TCP - {{- range $port := .Values.dashboard.networkPolicy.kubeAPIServerPorts }} - - port: {{ $port }} - {{- end }} - {{- if .Values.dashboard.networkPolicy.extraEgress }} - {{- include "common.tplvalues.render" ( dict "value" .Values.dashboard.networkPolicy.extraEgress "context" $ ) | nindent 4 }} - {{- end }} - {{- end }} - ingress: - # Allow inbound connections - - ports: - - port: {{ .Values.dashboard.containerPorts.http }} - {{- if not .Values.dashboard.networkPolicy.allowExternal }} - from: - - podSelector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 14 }} - {{- if .Values.dashboard.networkPolicy.ingressNSMatchLabels }} - - namespaceSelector: - matchLabels: - {{- range $key, $value := .Values.dashboard.networkPolicy.ingressNSMatchLabels }} - {{ $key | quote }}: {{ $value | quote }} - {{- end }} - {{- if .Values.dashboard.networkPolicy.ingressNSPodMatchLabels }} - podSelector: - matchLabels: - {{- range $key, $value := .Values.dashboard.networkPolicy.ingressNSPodMatchLabels }} - {{ $key | quote }}: {{ $value | quote }} - {{- end }} - {{- end }} - {{- end }} - {{- end }} - {{- if .Values.dashboard.networkPolicy.extraIngress }} - {{- include "common.tplvalues.render" ( dict "value" .Values.dashboard.networkPolicy.extraIngress "context" $ ) | nindent 4 }} - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/dashboard/pdb.yaml b/packages/system/dashboard/charts/kubeapps/templates/dashboard/pdb.yaml deleted file mode 100644 index 67578402..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/dashboard/pdb.yaml +++ /dev/null @@ -1,30 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.dashboard.enabled .Values.dashboard.pdb.create }} -apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} -kind: PodDisruptionBudget -metadata: - name: {{ template "kubeapps.dashboard.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.dashboard.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: dashboard - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - {{- if .Values.dashboard.pdb.minAvailable }} - minAvailable: {{ .Values.dashboard.pdb.minAvailable }} - {{- end }} - {{- if or .Values.dashboard.pdb.maxUnavailable ( not .Values.dashboard.pdb.minAvailable ) }} - maxUnavailable: {{ .Values.dashboard.pdb.maxUnavailable | default 1 }} - {{- end }} - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.dashboard.podLabels .Values.commonLabels $versionLabel ) "context" . ) }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: dashboard -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/dashboard/service.yaml b/packages/system/dashboard/charts/kubeapps/templates/dashboard/service.yaml deleted file mode 100644 index d13cb2d7..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/dashboard/service.yaml +++ /dev/null @@ -1,30 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.dashboard.enabled -}} -apiVersion: v1 -kind: Service -metadata: - name: {{ template "kubeapps.dashboard.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.dashboard.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: dashboard - {{- if or .Values.dashboard.service.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.dashboard.service.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -spec: - type: ClusterIP - ports: - - port: {{ .Values.dashboard.service.ports.http }} - targetPort: http - protocol: TCP - name: http - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.dashboard.podLabels .Values.commonLabels ) "context" . ) }} - selector: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: dashboard -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/templates/extra-list.yaml b/packages/system/dashboard/charts/kubeapps/templates/extra-list.yaml deleted file mode 100644 index 329f5c65..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/extra-list.yaml +++ /dev/null @@ -1,9 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- range .Values.extraDeploy }} ---- -{{ include "common.tplvalues.render" (dict "value" . "context" $) }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/frontend/configmap.yaml b/packages/system/dashboard/charts/kubeapps/templates/frontend/configmap.yaml deleted file mode 100644 index cafdc5fc..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/frontend/configmap.yaml +++ /dev/null @@ -1,145 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "kubeapps.frontend-config.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.frontend.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: frontend - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -data: - k8s-api-proxy.conf: |- - # Deactivate buffering for log streaming - proxy_buffering off; - # Hide Www-Authenticate to prevent it triggering a basic auth prompt in - # the browser with some clusters - proxy_hide_header Www-Authenticate; - - # Keep the connection open with the API server even if idle (the default is 60 seconds) - # Setting it to 1 hour which should be enough for our current use case of deploying/upgrading apps - # If we enable other use-cases in the future we might need to bump this value - # More info here https://github.com/vmware-tanzu/kubeapps/issues/766 - proxy_read_timeout 1h; - - {{- if .Values.frontend.proxypassAccessTokenAsBearer }} - # Google Kubernetes Engine requires the access_token as the Bearer when talking to the k8s api server. - proxy_set_header Authorization "Bearer $http_x_forwarded_access_token"; - {{- end }} -{{- range .Values.clusters }} - {{- if .certificateAuthorityData }} - {{ printf "%s-ca.pem" .name }}: {{ .certificateAuthorityData }} - {{- end }} -{{- end }} - vhost.conf: |- - # Retain the default nginx handling of requests without a "Connection" header - map $http_upgrade $connection_upgrade { - default upgrade; - '' close; - } - - # Allow websocket connections - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $connection_upgrade; - - server { - listen {{ .Values.frontend.containerPorts.http }}; - {{- if .Values.frontend.largeClientHeaderBuffers }} - large_client_header_buffers {{ .Values.frontend.largeClientHeaderBuffers }}; - {{- end }} - {{- if .Values.enableIPv6 }} - listen [::]:{{ .Values.frontend.containerPorts.http }}; - {{- end }} - server_name _; - - location /healthz { - access_log off; - default_type text/plain; - return 200 "healthy\n"; - } - - # Only proxy to k8s API endpoints if operators are enabled. - {{- if $.Values.featureFlags.operators }} - - # Ensure each cluster can be reached (should only be - # used with an auth-proxy where k8s credentials never leave - # the cluster). See clusters option. - {{- range .Values.clusters }} - - location ~* /api/clusters/{{ .name }} { - {{/* We need to split the API service URL(s) into the base url and the path segment so - those configurations using a path can be appropriately rewritten below while - ensuring the proxy_pass statement is given the base URL only. */}} - {{- $parsed := urlParse (default "https://kubernetes.default" .apiServiceURL) }} - {{- $apiServiceBaseURL := urlJoin (pick $parsed "scheme" "host") }} - {{- $apiServiceURLPath := $parsed.path }} - rewrite /api/clusters/{{ .name }}/(.*) {{ $apiServiceURLPath }}/$1 break; - rewrite /api/clusters/{{ .name }} {{ $apiServiceURLPath }}/ break; - - {{/* Helm returns a nil pointer error when accessing foo.bar if foo doesn't - exist, even with the `default` function. - See https://github.com/helm/helm/issues/8026#issuecomment-756538254 */}} - {{- $pinnipedConfig := .pinnipedConfig | default dict }} - {{- if and $.Values.pinnipedProxy.enabled (or $pinnipedConfig.enabled $pinnipedConfig.enable) }} - # If pinniped proxy is enabled *and* the current cluster is configured - # to exchange credentials then we route via pinnipedProxy to exchange - # credentials for client certificates. Note, we are currently still supporting - # the deprecated `pinnipedConfig.enable` until the next feature release. - # All documentation should now reference the cluster-specific `pinnipedConfig.enabled`. - {{- if .apiServiceURL }} - proxy_set_header PINNIPED_PROXY_API_SERVER_URL {{ .apiServiceURL }}; - {{- end }} - {{- if .certificateAuthorityData }} - proxy_set_header PINNIPED_PROXY_API_SERVER_CERT {{ .certificateAuthorityData }}; - {{- end }} - proxy_pass {{ printf "http://%s.%s:%d" (include "kubeapps.pinniped-proxy.fullname" $) $.Release.Namespace (int $.Values.pinnipedProxy.service.ports.pinnipedProxy) }}; - {{- else }} - # Otherwise we route directly through to the clusters with existing credentials. - proxy_pass {{ $apiServiceBaseURL }}; - {{- if .certificateAuthorityData }} - proxy_ssl_trusted_certificate {{ printf "./server_blocks/%s-ca.pem" .name | quote }}; - {{- end }} - {{- end }} - include "./server_blocks/k8s-api-proxy.conf"; - } - {{- end }} - {{- end }} - - location ~* /apis { - rewrite ^ $request_uri; # pass the encoded url downstream as is, - rewrite /apis/([^?]*) /$1 break; - rewrite /apis / break; - - {{- if .Values.frontend.proxypassExtraSetHeader }} - proxy_set_header {{ .Values.frontend.proxypassExtraSetHeader }}; - {{- end }} - - {{- if .Values.frontend.proxypassAccessTokenAsBearer }} - # Google Kubernetes Engine requires the access_token as the Bearer when talking to the k8s api server. - proxy_set_header Authorization "Bearer $http_x_forwarded_access_token"; - {{- end }} - - proxy_pass {{ include "kubeapps.kubeappsapis.proxy_pass" . -}}; - } - - {{- if .Values.dashboard.enabled }} - location / { - # Add the Authorization header if exists - add_header Authorization $http_authorization; - proxy_pass {{ printf "http://%s:%d" (include "kubeapps.dashboard.fullname" .) (int .Values.dashboard.service.ports.http) }}; - } - {{- end }} - - location /logos { - # Add the Authorization header if exists - proxy_set_header Cookie ""; - proxy_pass http://cozystack.cozy-system.svc:80; - } - } diff --git a/packages/system/dashboard/charts/kubeapps/templates/frontend/deployment.yaml b/packages/system/dashboard/charts/kubeapps/templates/frontend/deployment.yaml deleted file mode 100644 index 9c7e9a47..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/frontend/deployment.yaml +++ /dev/null @@ -1,335 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} -kind: Deployment -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.frontend.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: frontend - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - replicas: {{ .Values.frontend.replicaCount }} - {{- if .Values.frontend.updateStrategy }} - strategy: {{- toYaml .Values.frontend.updateStrategy | nindent 4 }} - {{- end }} - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.frontend.podLabels .Values.commonLabels $versionLabel ) "context" . ) }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: frontend - template: - metadata: - annotations: - checksum/config: {{ include (print $.Template.BasePath "/frontend/configmap.yaml") . | sha256sum }} - {{- if .Values.frontend.podAnnotations }} - {{- include "common.tplvalues.render" (dict "value" .Values.frontend.podAnnotations "context" $) | nindent 8 }} - {{- end }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $podLabels "context" $ ) | nindent 8 }} - app.kubernetes.io/component: frontend - spec: - {{- include "kubeapps.imagePullSecrets" . | nindent 6 }} - automountServiceAccountToken: {{ .Values.frontend.automountServiceAccountToken }} - {{- if .Values.frontend.hostAliases }} - hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.hostAliases "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.frontend.affinity }} - affinity: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.affinity "context" $) | nindent 8 }} - {{- else }} - affinity: - podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.frontend.podAffinityPreset "component" "frontend" "customLabels" $podLabels "context" $) | nindent 10 }} - podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.frontend.podAntiAffinityPreset "component" "frontend" "customLabels" $podLabels "context" $) | nindent 10 }} - nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.frontend.nodeAffinityPreset.type "key" .Values.frontend.nodeAffinityPreset.key "values" .Values.frontend.nodeAffinityPreset.values) | nindent 10 }} - {{- end }} - {{- if .Values.frontend.schedulerName }} - schedulerName: {{ .Values.frontend.schedulerName }} - {{- end }} - {{- if .Values.frontend.topologySpreadConstraints }} - topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.topologySpreadConstraints "context" .) | nindent 8 }} - {{- end }} - {{- if .Values.frontend.nodeSelector }} - nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.nodeSelector "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.frontend.tolerations }} - tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.tolerations "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.frontend.priorityClassName }} - priorityClassName: {{ .Values.frontend.priorityClassName | quote }} - {{- end }} - {{- if .Values.frontend.podSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.frontend.podSecurityContext "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.frontend.initContainers }} - initContainers: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.initContainers "context" $) | nindent 8 }} - {{- end }} - containers: - - name: nginx - image: {{ include "kubeapps.frontend.image" . }} - imagePullPolicy: {{ .Values.frontend.image.pullPolicy | quote }} - {{- if .Values.frontend.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.frontend.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} - {{- else if .Values.frontend.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.command "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} - {{- else if .Values.frontend.args }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.args "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.frontend.lifecycleHooks }} - lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.lifecycleHooks "context" $) | nindent 12 }} - {{- end }} - env: - - name: BITNAMI_DEBUG - value: {{ ternary "true" "false" .Values.frontend.image.debug | quote }} - {{- if .Values.frontend.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.frontend.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - envFrom: - {{- if .Values.frontend.extraEnvVarsCM }} - - configMapRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.frontend.extraEnvVarsCM "context" $) }} - {{- end }} - {{- if .Values.frontend.extraEnvVarsSecret }} - - secretRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.frontend.extraEnvVarsSecret "context" $) }} - {{- end }} - ports: - - name: http - containerPort: {{ .Values.frontend.containerPorts.http }} - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.frontend.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.customLivenessProbe "context" $) | nindent 12 }} - {{- else if .Values.frontend.livenessProbe.enabled }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.frontend.livenessProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: http - {{- end }} - {{- if .Values.frontend.customReadinessProbe }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.customReadinessProbe "context" $) | nindent 12 }} - {{- else if .Values.frontend.readinessProbe.enabled }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.frontend.readinessProbe "enabled") "context" $) | nindent 12 }} - httpGet: - path: / - port: http - {{- end }} - {{- if .Values.frontend.customStartupProbe }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.customStartupProbe "context" $) | nindent 12 }} - {{- else if .Values.frontend.startupProbe.enabled }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.frontend.startupProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: http - {{- end }} - {{- end }} - {{- if .Values.frontend.resources }} - resources: {{- toYaml .Values.frontend.resources | nindent 12 }} - {{- else if ne .Values.frontend.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.frontend.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - - name: empty-dir - mountPath: /opt/bitnami/nginx/tmp - subPath: app-tmp-dir - - name: empty-dir - mountPath: /opt/bitnami/nginx/logs - subPath: app-logs-dir - - name: vhost - mountPath: /opt/bitnami/nginx/conf/server_blocks - {{- if .Values.frontend.extraVolumeMounts }} - {{- include "common.tplvalues.render" (dict "value" .Values.frontend.extraVolumeMounts "context" $) | nindent 12 }} - {{- end }} - {{- if and .Values.authProxy.enabled (not .Values.authProxy.external) }} - - name: auth-proxy - image: {{ include "kubeapps.authProxy.image" . }} - imagePullPolicy: {{ .Values.authProxy.image.pullPolicy | quote }} - {{- if .Values.authProxy.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.authProxy.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.authProxy.lifecycleHooks }} - lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.authProxy.lifecycleHooks "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} - {{- else if .Values.authProxy.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.authProxy.command "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} - {{- else if .Values.authProxy.args }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.authProxy.args "context" $) | nindent 12 }} - {{- else }} - args: - - --provider={{ required "You must fill \".Values.authProxy.provider\" with the provider. Valid values at https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/overview" .Values.authProxy.provider }} - - --upstream=http://localhost:{{ .Values.frontend.containerPorts.http }}/ - - --http-address=0.0.0.0:{{ .Values.authProxy.containerPorts.proxy }} - - --email-domain={{ .Values.authProxy.emailDomain }} - - --pass-basic-auth=false - - --pass-access-token=true - - --pass-authorization-header=true - - --skip-auth-regex=^\/config\.json$ - - --skip-auth-regex=^\/site\.webmanifest$ - - --skip-auth-regex=^\/custom_style\.css$ - - --skip-auth-regex=^\/clr-ui.min\.css$ - - --skip-auth-regex=^\/clr-ui-dark.min\.css$ - - --skip-auth-regex=^\/custom_locale\.json$ - - --skip-auth-regex=^\/favicon.*\.png$ - - --skip-auth-regex=^\/favicon.*\.ico$ - - --skip-auth-regex=^\/android-chrome-.*\.png$ - - --skip-auth-regex=^\/static\/ - - --skip-auth-regex=^\/apis/core/plugins/v1alpha1/configured-plugins$ - - --skip-auth-regex=^\/apis/kubeappsapis.core.plugins.v1alpha1.PluginsService/GetConfiguredPlugins$ - - --skip-auth-regex=^\/$ - - --scope={{ .Values.authProxy.scope }} - - --cookie-refresh={{ .Values.authProxy.cookieRefresh }} - {{- range .Values.authProxy.extraFlags }} - - {{ . }} - {{- end }} - {{- end }} - env: - - name: OAUTH2_PROXY_CLIENT_ID - valueFrom: - secretKeyRef: - name: {{ template "kubeapps.oauth2_proxy-secret.name" . }} - key: clientID - - name: OAUTH2_PROXY_CLIENT_SECRET - valueFrom: - secretKeyRef: - name: {{ template "kubeapps.oauth2_proxy-secret.name" . }} - key: clientSecret - - name: OAUTH2_PROXY_COOKIE_SECRET - valueFrom: - secretKeyRef: - name: {{ template "kubeapps.oauth2_proxy-secret.name" . }} - key: cookieSecret - {{- if .Values.authProxy.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.authProxy.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - envFrom: - {{- if .Values.authProxy.extraEnvVarsCM }} - - configMapRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.authProxy.extraEnvVarsCM "context" $) }} - {{- end }} - {{- if .Values.authProxy.extraEnvVarsSecret }} - - secretRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.authProxy.extraEnvVarsSecret "context" $) }} - {{- end }} - ports: - - name: proxy - containerPort: {{ .Values.authProxy.containerPorts.proxy }} - {{- if .Values.authProxy.resources }} - resources: {{- toYaml .Values.authProxy.resources | nindent 12 }} - {{- else if ne .Values.authProxy.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.authProxy.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - {{- if .Values.authProxy.extraVolumeMounts }} - {{- include "common.tplvalues.render" (dict "value" .Values.authProxy.extraVolumeMounts "context" $) | nindent 12 }} - {{- end }} - {{- end }} - {{- if and (gt (len .Values.clusters) 1) (not .Values.authProxy.enabled) }} - {{ fail "clusters can be configured only when using an auth proxy for cluster oidc authentication." }} - {{- end }} - {{- if .Values.pinnipedProxy.enabled }} - - name: pinniped-proxy - image: {{ include "kubeapps.pinnipedProxy.image" . }} - imagePullPolicy: {{ .Values.pinnipedProxy.image.pullPolicy | quote }} - {{- if .Values.pinnipedProxy.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.pinnipedProxy.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} - {{- else if .Values.pinnipedProxy.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.pinnipedProxy.command "context" $) | nindent 12 }} - {{- else }} - command: - - pinniped-proxy - {{- if .Values.pinnipedProxy.tls.existingSecret }} - - --proxy-tls-cert=/etc/pinniped-tls/tls.crt - - --proxy-tls-cert-key=/etc/pinniped-tls/tls.key - {{- end }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} - {{- else if .Values.pinnipedProxy.args }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.pinnipedProxy.args "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.pinnipedProxy.lifecycleHooks }} - lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.pinnipedProxy.lifecycleHooks "context" $) | nindent 12 }} - {{- end }} - env: - - name: DEFAULT_PINNIPED_NAMESPACE - value: {{ .Values.pinnipedProxy.defaultPinnipedNamespace | quote }} - - name: DEFAULT_PINNIPED_AUTHENTICATOR_TYPE - value: {{ .Values.pinnipedProxy.defaultAuthenticatorType | quote }} - - name: DEFAULT_PINNIPED_AUTHENTICATOR_NAME - value: {{ .Values.pinnipedProxy.defaultAuthenticatorName | quote }} - - name: DEFAULT_PINNIPED_API_SUFFIX - value: {{ .Values.pinnipedProxy.defaultPinnipedAPISuffix | quote }} - - name: RUST_LOG - # Use info,pinniped_proxy::pinniped=debug for module control. - value: info - {{- if .Values.pinnipedProxy.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.pinnipedProxy.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - envFrom: - {{- if .Values.pinnipedProxy.extraEnvVarsCM }} - - configMapRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.pinnipedProxy.extraEnvVarsCM "context" $) }} - {{- end }} - {{- if .Values.pinnipedProxy.extraEnvVarsSecret }} - - secretRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.pinnipedProxy.extraEnvVarsSecret "context" $) }} - {{- end }} - ports: - - name: pinniped-proxy - containerPort: {{ .Values.pinnipedProxy.containerPorts.pinnipedProxy }} - {{- if .Values.pinnipedProxy.resources }} - resources: {{- toYaml .Values.pinnipedProxy.resources | nindent 12 }} - {{- else if ne .Values.pinnipedProxy.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.pinnipedProxy.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - {{- if .Values.pinnipedProxy.tls.existingSecret }} - - name: pinniped-tls-secret - mountPath: "/etc/pinniped-tls" - readOnly: true - {{- end }} - {{- if .Values.pinnipedProxy.extraVolumeMounts }} - {{- include "common.tplvalues.render" (dict "value" .Values.pinnipedProxy.extraVolumeMounts "context" $) | nindent 12 }} - {{- end }} - {{- end }} - {{- if .Values.frontend.sidecars }} - {{- include "common.tplvalues.render" (dict "value" .Values.frontend.sidecars "context" $) | nindent 8 }} - {{- end }} - volumes: - - name: empty-dir - emptyDir: {} - - name: vhost - configMap: - name: {{ template "kubeapps.frontend-config.fullname" . }} - {{- if .Values.pinnipedProxy.tls.existingSecret }} - - name: pinniped-tls-secret - secret: - secretName: {{ .Values.pinnipedProxy.tls.existingSecret }} - {{- end }} - {{- if .Values.frontend.extraVolumes }} - {{- include "common.tplvalues.render" (dict "value" .Values.frontend.extraVolumes "context" $) | nindent 8 }} - {{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/frontend/networkpolicy.yaml b/packages/system/dashboard/charts/kubeapps/templates/frontend/networkpolicy.yaml deleted file mode 100644 index ac55f482..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/frontend/networkpolicy.yaml +++ /dev/null @@ -1,77 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.frontend.networkPolicy.enabled }} -kind: NetworkPolicy -apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} -metadata: - name: {{ include "common.names.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.frontend.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: frontend - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - policyTypes: - - Ingress - - Egress - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.frontend.podLabels .Values.commonLabels $versionLabel ) "context" . ) }} - podSelector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: frontend - {{- if .Values.frontend.networkPolicy.allowExternalEgress }} - egress: - - {} - {{- else }} - egress: - # Allow dns resolution - - ports: - - port: 53 - protocol: UDP - - port: 53 - protocol: TCP - {{- range $port := .Values.frontend.networkPolicy.kubeAPIServerPorts }} - - port: {{ $port }} - {{- end }} - {{- if .Values.frontend.networkPolicy.extraEgress }} - {{- include "common.tplvalues.render" ( dict "value" .Values.frontend.networkPolicy.extraEgress "context" $ ) | nindent 4 }} - {{- end }} - {{- end }} - ingress: - # Allow inbound connections - - ports: - - port: {{ .Values.frontend.containerPorts.http }} - {{- if and .Values.authProxy.enabled (not .Values.authProxy.external) }} - - port: {{ .Values.authProxy.containerPorts.proxy }} - {{- end }} - {{- if .Values.pinnipedProxy.enabled }} - - port: {{ .Values.pinnipedProxy.containerPorts.pinnipedProxy }} - {{- end }} - {{- if not .Values.frontend.networkPolicy.allowExternal }} - from: - - podSelector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 14 }} - {{- if .Values.frontend.networkPolicy.ingressNSMatchLabels }} - - namespaceSelector: - matchLabels: - {{- range $key, $value := .Values.frontend.networkPolicy.ingressNSMatchLabels }} - {{ $key | quote }}: {{ $value | quote }} - {{- end }} - {{- if .Values.frontend.networkPolicy.ingressNSPodMatchLabels }} - podSelector: - matchLabels: - {{- range $key, $value := .Values.frontend.networkPolicy.ingressNSPodMatchLabels }} - {{ $key | quote }}: {{ $value | quote }} - {{- end }} - {{- end }} - {{- end }} - {{- end }} - {{- if .Values.frontend.networkPolicy.extraIngress }} - {{- include "common.tplvalues.render" ( dict "value" .Values.frontend.networkPolicy.extraIngress "context" $ ) | nindent 4 }} - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/frontend/oauth2-secret.yaml b/packages/system/dashboard/charts/kubeapps/templates/frontend/oauth2-secret.yaml deleted file mode 100644 index e83afd5d..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/frontend/oauth2-secret.yaml +++ /dev/null @@ -1,23 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.authProxy.enabled (not .Values.authProxy.external) (not .Values.authProxy.existingOauth2Secret) }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ template "kubeapps.oauth2_proxy-secret.name" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.frontend.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: frontend - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -data: - clientID: {{ required "You must fill \".Values.authProxy.clientID\" with the Client ID of the provider" .Values.authProxy.clientID | b64enc }} - clientSecret: {{ required "You must fill \".Values.authProxy.clientSecret\" with the Client Secret of the provider" .Values.authProxy.clientSecret | b64enc }} - cookieSecret: {{ required "You must fill \".Values.authProxy.cookieSecret\". More info at https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/overview/#generating-a-cookie-secret" .Values.authProxy.cookieSecret | b64enc }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/frontend/pdb.yaml b/packages/system/dashboard/charts/kubeapps/templates/frontend/pdb.yaml deleted file mode 100644 index 3e9a8ec2..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/frontend/pdb.yaml +++ /dev/null @@ -1,30 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.frontend.pdb.create }} -apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} -kind: PodDisruptionBudget -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.frontend.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: frontend - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - {{- if .Values.frontend.pdb.minAvailable }} - minAvailable: {{ .Values.frontend.pdb.minAvailable }} - {{- end }} - {{- if or .Values.frontend.pdb.maxUnavailable ( not .Values.frontend.pdb.minAvailable ) }} - maxUnavailable: {{ .Values.frontend.pdb.maxUnavailable | default 1 }} - {{- end }} - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.frontend.podLabels .Values.commonLabels $versionLabel ) "context" . ) }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: frontend -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/frontend/service.yaml b/packages/system/dashboard/charts/kubeapps/templates/frontend/service.yaml deleted file mode 100644 index a4ccdccb..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/frontend/service.yaml +++ /dev/null @@ -1,84 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -apiVersion: v1 -kind: Service -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.frontend.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: frontend - {{- if or .Values.frontend.service.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.frontend.service.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -spec: - type: {{ .Values.frontend.service.type }} - {{- if and .Values.frontend.service.clusterIP (eq .Values.frontend.service.type "ClusterIP") }} - clusterIP: {{ .Values.frontend.service.clusterIP }} - {{- end }} - {{- if or (eq .Values.frontend.service.type "LoadBalancer") (eq .Values.frontend.service.type "NodePort") }} - externalTrafficPolicy: {{ .Values.frontend.service.externalTrafficPolicy | quote }} - {{- end }} - {{- if and (eq .Values.frontend.service.type "LoadBalancer") .Values.frontend.service.loadBalancerSourceRanges }} - loadBalancerSourceRanges: {{- toYaml .Values.frontend.service.loadBalancerSourceRanges | nindent 4 }} - {{- end }} - {{- if and (eq .Values.frontend.service.type "LoadBalancer") (not (empty .Values.frontend.service.loadBalancerIP)) }} - loadBalancerIP: {{ .Values.frontend.service.loadBalancerIP }} - {{- end }} - {{- if .Values.frontend.service.sessionAffinity }} - sessionAffinity: {{ .Values.frontend.service.sessionAffinity }} - {{- end }} - {{- if .Values.frontend.service.sessionAffinityConfig }} - sessionAffinityConfig: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.service.sessionAffinityConfig "context" $) | nindent 4 }} - {{- end }} - ports: - - name: http - port: {{ .Values.frontend.service.ports.http }} - protocol: TCP - {{- if and .Values.authProxy.enabled (not .Values.authProxy.external) }} - targetPort: proxy - {{- else }} - targetPort: http - {{- end }} - {{- if and (or (eq .Values.frontend.service.type "NodePort") (eq .Values.frontend.service.type "LoadBalancer")) (not (empty .Values.frontend.service.nodePorts.http)) }} - nodePort: {{ .Values.frontend.service.nodePorts.http }} - {{- else if eq .Values.frontend.service.type "ClusterIP" }} - nodePort: null - {{- end }} - {{- if .Values.frontend.service.extraPorts }} - {{- include "common.tplvalues.render" (dict "value" .Values.frontend.service.extraPorts "context" $) | nindent 4 }} - {{- end }} - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.frontend.podLabels .Values.commonLabels ) "context" . ) }} - selector: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: frontend -{{- if .Values.pinnipedProxy.enabled }} ---- -# Include an additional ClusterIP service for the pinniped-proxy as some configurations -# require the normal frontend service to use NodePort. -apiVersion: v1 -kind: Service -metadata: - name: {{ template "kubeapps.pinniped-proxy.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: frontend - {{- if or .Values.pinnipedProxy.service.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.pinnipedProxy.service.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -spec: - type: ClusterIP - ports: - - port: {{ .Values.pinnipedProxy.service.ports.pinnipedProxy }} - targetPort: pinniped-proxy - protocol: TCP - name: pinniped-proxy - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.frontend.podLabels .Values.commonLabels ) "context" . ) }} - selector: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: frontend -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/ingress-api.yaml b/packages/system/dashboard/charts/kubeapps/templates/ingress-api.yaml deleted file mode 100644 index 58f38446..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/ingress-api.yaml +++ /dev/null @@ -1,115 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.featureFlags.apiOnly.enabled (not .Values.ingress.enabled) -}} - {{ fail "Ingress must be enabled for the API mode to work. Please set \"ingress.enabled\" to true." }} -{{- end -}} -{{- if and .Values.ingress.enabled .Values.featureFlags.apiOnly.enabled -}} -{{- if and .Values.dashboard.enabled -}} - {{ fail "Dashboard is enabled but will NOT work with Ingress in API mode. Please set \"dashboard.enabled\" to false." }} -{{- end -}} ---- -apiVersion: {{ include "common.capabilities.ingress.apiVersion" . }} -kind: Ingress -metadata: - name: {{ template "common.names.fullname" . }}-http-api - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if or .Values.ingress.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.ingress.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -spec: - {{- if and .Values.ingress.ingressClassName (eq "true" (include "common.ingress.supportsIngressClassname" .)) }} - ingressClassName: {{ .Values.ingress.ingressClassName | quote }} - {{- end }} - rules: - {{- if .Values.ingress.hostname }} - - host: {{ .Values.ingress.hostname }} - http: - paths: - {{- if .Values.ingress.extraPaths }} - {{- toYaml .Values.ingress.extraPaths | nindent 10 }} - {{- end }} - - path: /apis - {{- if eq "true" (include "common.ingress.supportsPathType" $) }} - pathType: {{ $.Values.ingress.pathType }} - {{- end }} - backend: {{- include "common.ingress.backend" (dict "serviceName" (include "common.names.fullname" $) "servicePort" "http" "context" $) | nindent 14 }} - {{- if and .Values.ingress.path (ne (quote (trim .Values.ingress.path)) (quote "/")) }} - - path: {{ .Values.ingress.path }} - {{- if eq "true" (include "common.ingress.supportsPathType" $) }} - pathType: {{ $.Values.ingress.pathType }} - {{- end }} - backend: {{- include "common.ingress.backend" (dict "serviceName" (include "common.names.fullname" $) "servicePort" "http" "context" $) | nindent 14 }} - {{- end -}} - {{- end }} - {{- range .Values.ingress.extraHosts }} - - host: {{ .name }} - http: - paths: - - path: {{ default "/" .path }} - {{- if eq "true" (include "common.ingress.supportsPathType" $) }} - pathType: {{ $.Values.ingress.pathType }} - {{- end }} - backend: {{- include "common.ingress.backend" (dict "serviceName" (include "common.names.fullname" $) "servicePort" "http" "context" $) | nindent 14 }} - {{- end }} - {{- if .Values.ingress.extraRules }} - {{- include "common.tplvalues.render" (dict "value" .Values.ingress.extraRules "context" $) | nindent 4 }} - {{- end }} - {{- if or (and .Values.ingress.tls (or (include "common.ingress.certManagerRequest" ( dict "annotations" .Values.ingress.annotations )) .Values.ingress.selfSigned)) .Values.ingress.extraTls }} - tls: - {{- if and .Values.ingress.tls (or (include "common.ingress.certManagerRequest" ( dict "annotations" .Values.ingress.annotations )) .Values.ingress.selfSigned) }} - - hosts: - - {{ .Values.ingress.hostname | quote }} - secretName: {{ printf "%s-tls" .Values.ingress.hostname }} - {{- end }} - {{- if .Values.ingress.extraTls }} - {{- include "common.tplvalues.render" ( dict "value" .Values.ingress.extraTls "context" $ ) | nindent 4 }} - {{- end }} - {{- end }} ---- -apiVersion: {{ include "common.capabilities.ingress.apiVersion" . }} -kind: Ingress -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if or .Values.featureFlags.apiOnly.grpc.annotations .Values.ingress.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.featureFlags.apiOnly.grpc.annotations .Values.ingress.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -spec: - {{- if and .Values.ingress.ingressClassName (eq "true" (include "common.ingress.supportsIngressClassname" .)) }} - ingressClassName: {{ .Values.ingress.ingressClassName | quote }} - {{- end }} - rules: - {{- if .Values.ingress.hostname }} - - host: {{ .Values.ingress.hostname }} - http: - paths: - - path: / - {{- if eq "true" (include "common.ingress.supportsPathType" $) }} - pathType: {{ $.Values.ingress.pathType }} - {{- end }} - backend: - service: - name: {{ template "kubeapps.kubeappsapis.fullname" . }} - port: - name: grpc-http - {{- end }} - {{- if or (and .Values.ingress.tls (or (include "common.ingress.certManagerRequest" ( dict "annotations" .Values.ingress.annotations )) .Values.ingress.selfSigned)) .Values.ingress.extraTls }} - tls: - {{- if and .Values.ingress.tls (or (include "common.ingress.certManagerRequest" ( dict "annotations" .Values.ingress.annotations )) .Values.ingress.selfSigned) }} - - hosts: - - {{ .Values.ingress.hostname | quote }} - secretName: {{ printf "%s-tls" .Values.ingress.hostname }} - {{- end }} - {{- if .Values.ingress.extraTls }} - {{- include "common.tplvalues.render" ( dict "value" .Values.ingress.extraTls "context" $ ) | nindent 4 }} - {{- end }} - {{- end }} ---- -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/ingress.yaml b/packages/system/dashboard/charts/kubeapps/templates/ingress.yaml deleted file mode 100644 index 0d55ea64..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/ingress.yaml +++ /dev/null @@ -1,59 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if and .Values.ingress.enabled (not .Values.featureFlags.apiOnly.enabled) -}} -apiVersion: {{ include "common.capabilities.ingress.apiVersion" . }} -kind: Ingress -metadata: - name: {{ template "common.names.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if or .Values.ingress.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.ingress.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -spec: - {{- if and .Values.ingress.ingressClassName (eq "true" (include "common.ingress.supportsIngressClassname" .)) }} - ingressClassName: {{ .Values.ingress.ingressClassName | quote }} - {{- end }} - rules: - {{- if .Values.ingress.hostname }} - - host: {{ .Values.ingress.hostname }} - http: - paths: - {{- if .Values.ingress.extraPaths }} - {{- toYaml .Values.ingress.extraPaths | nindent 10 }} - {{- end }} - - path: {{ .Values.ingress.path }} - {{- if eq "true" (include "common.ingress.supportsPathType" $) }} - pathType: {{ $.Values.ingress.pathType }} - {{- end }} - backend: {{- include "common.ingress.backend" (dict "serviceName" (include "common.names.fullname" $) "servicePort" "http" "context" $) | nindent 14 }} - {{- end }} - {{- range .Values.ingress.extraHosts }} - - host: {{ .name }} - http: - paths: - - path: {{ default "/" .path }} - {{- if eq "true" (include "common.ingress.supportsPathType" $) }} - pathType: {{ $.Values.ingress.pathType }} - {{- end }} - backend: {{- include "common.ingress.backend" (dict "serviceName" (include "common.names.fullname" $) "servicePort" "http" "context" $) | nindent 14 }} - {{- end }} - {{- if .Values.ingress.extraRules }} - {{- include "common.tplvalues.render" (dict "value" .Values.ingress.extraRules "context" $) | nindent 4 }} - {{- end }} - {{- if or (and .Values.ingress.tls (or (include "common.ingress.certManagerRequest" ( dict "annotations" .Values.ingress.annotations )) .Values.ingress.selfSigned)) .Values.ingress.extraTls }} - tls: - {{- if and .Values.ingress.tls (or (include "common.ingress.certManagerRequest" ( dict "annotations" .Values.ingress.annotations )) .Values.ingress.selfSigned) }} - - hosts: - - {{ .Values.ingress.hostname | quote }} - secretName: {{ printf "%s-tls" .Values.ingress.hostname }} - {{- end }} - {{- if .Values.ingress.extraTls }} - {{- include "common.tplvalues.render" ( dict "value" .Values.ingress.extraTls "context" $ ) | nindent 4 }} - {{- end }} - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/configmap.yaml b/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/configmap.yaml deleted file mode 100644 index fae9f0cc..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/configmap.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ printf "%s-configmap" (include "kubeapps.kubeappsapis.fullname" .) }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.kubeappsapis.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -data: - plugins.conf: |- -{{- if .Values.kubeappsapis.pluginConfig }} -{{ .Values.kubeappsapis.pluginConfig | toPrettyJson | indent 4 }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/deployment.yaml b/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/deployment.yaml deleted file mode 100644 index ea3b91e0..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/deployment.yaml +++ /dev/null @@ -1,348 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} -kind: Deployment -metadata: - name: {{ template "kubeapps.kubeappsapis.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.kubeappsapis.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: kubeappsapis - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - replicas: {{ .Values.kubeappsapis.replicaCount }} - {{- if .Values.kubeappsapis.updateStrategy }} - strategy: {{- toYaml .Values.kubeappsapis.updateStrategy | nindent 4 }} - {{- end }} - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.kubeappsapis.podLabels .Values.commonLabels $versionLabel ) "context" . ) }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: kubeappsapis - template: - metadata: - {{- if .Values.kubeappsapis.podAnnotations }} - annotations: {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.podAnnotations "context" $) | nindent 8 }} - {{- end }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $podLabels "context" $ ) | nindent 8 }} - app.kubernetes.io/component: kubeappsapis - spec: - {{- include "kubeapps.imagePullSecrets" . | nindent 6 }} - serviceAccountName: {{ template "kubeapps.kubeappsapis.serviceAccountName" . }} - automountServiceAccountToken: {{ .Values.kubeappsapis.automountServiceAccountToken }} - {{- if .Values.kubeappsapis.hostAliases }} - hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.hostAliases "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.kubeappsapis.affinity }} - affinity: {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.affinity "context" $) | nindent 8 }} - {{- else }} - affinity: - podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.kubeappsapis.podAffinityPreset "component" "kubeappsapis" "customLabels" $podLabels "context" $) | nindent 10 }} - podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.kubeappsapis.podAntiAffinityPreset "component" "kubeappsapis" "customLabels" $podLabels "context" $) | nindent 10 }} - nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.kubeappsapis.nodeAffinityPreset.type "key" .Values.kubeappsapis.nodeAffinityPreset.key "values" .Values.kubeappsapis.nodeAffinityPreset.values) | nindent 10 }} - {{- end }} - {{- if .Values.kubeappsapis.schedulerName }} - schedulerName: {{ .Values.kubeappsapis.schedulerName }} - {{- end }} - {{- if .Values.kubeappsapis.topologySpreadConstraints }} - topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.topologySpreadConstraints "context" .) | nindent 8 }} - {{- end }} - {{- if .Values.kubeappsapis.nodeSelector }} - nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.nodeSelector "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.kubeappsapis.tolerations }} - tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.tolerations "context" $) | nindent 8 }} - {{- end }} - {{- if .Values.kubeappsapis.priorityClassName }} - priorityClassName: {{ .Values.kubeappsapis.priorityClassName | quote }} - {{- end }} - {{- if .Values.kubeappsapis.podSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.kubeappsapis.podSecurityContext "context" $) | nindent 8 }} - {{- end }} - # Increase termination timeout to let remaining operations to finish before ending the pods - # This is because new releases/upgrades/deletions are synchronous operations - terminationGracePeriodSeconds: {{ .Values.kubeappsapis.terminationGracePeriodSeconds }} - {{- if .Values.kubeappsapis.initContainers }} - initContainers: {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.initContainers "context" $) | trim | nindent 8 }} - {{- end }} - containers: - - name: kubeappsapis - image: {{ include "kubeapps.kubeappsapis.image" . }} - imagePullPolicy: {{ .Values.kubeappsapis.image.pullPolicy | quote }} - {{- if .Values.kubeappsapis.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.kubeappsapis.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.kubeappsapis.lifecycleHooks }} - lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.lifecycleHooks "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} - {{- else if .Values.kubeappsapis.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.command "context" $) | nindent 12 }} - {{- else }} - command: - - /kubeapps-apis - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} - {{- else if .Values.kubeappsapis.args }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.args "context" $) | nindent 12 }} - {{- else }} - args: - {{- $enabledPlugins := include "kubeapps.kubeappsapis.enabledPlugins" . | fromJsonArray }} - {{- range $enabledPlugins }} - - --plugin-dir - - /plugins/{{ . }} - {{- end }} - {{- if .Values.clusters }} - - --clusters-config-path=/config/clusters.conf - {{- end }} - {{- if .Values.kubeappsapis.pluginConfig }} - - --plugin-config-path=/config/kubeapps-apis/plugins.conf - {{- end }} - {{- if .Values.pinnipedProxy.enabled }} - - --pinniped-proxy-url={{ printf "http%s://%s.%s:%d" (eq .Values.pinnipedProxy.tls.caCertificate "" | ternary "" "s") (include "kubeapps.pinniped-proxy.fullname" .) .Release.Namespace (int .Values.pinnipedProxy.service.ports.pinnipedProxy) }} - {{- if .Values.pinnipedProxy.tls.caCertificate }} - - --pinniped-proxy-ca-cert=/etc/pinniped-proxy-tls/ca.crt - {{- end }} - {{- end }} - - --global-repos-namespace={{ include "kubeapps.helmGlobalPackagingNamespace" . }} - {{- if .Values.kubeappsapis.qps }} - - --kube-api-qps={{ .Values.kubeappsapis.qps }} - {{- end }} - {{- if .Values.kubeappsapis.burst }} - - --kube-api-burst={{ .Values.kubeappsapis.burst }} - {{- end }} - {{- range .Values.kubeappsapis.extraFlags }} - - {{ . }} - {{- end }} - {{- end }} - env: - - name: GOGC - value: "50" # default is 100. 50 means increasing x2 the frequency of GC - - name: PORT - value: {{ .Values.kubeappsapis.containerPorts.http | quote }} - {{- if .Values.packaging.flux.enabled }} - # REDIS-* vars are required by the plugins for caching functionality - # TODO (gfichtenolt) this as required by the kubeapps apis service (which will - # longer-term pass something to the plugins so that the plugins won't need to - # know these details). Currently they're used directly by the flux plugin - - name: REDIS_ADDR - value: {{ printf "%s-master.%s.svc:6379" (include "kubeapps.redis.fullname" .) .Release.Namespace }} - - name: REDIS_PASSWORD - valueFrom: - secretKeyRef: - key: redis-password - name: {{ include "kubeapps.redis.secretName" . }} - - name: REDIS_DB - value: "0" - {{- end }} - # TODO(agamez): pass this configuration using a separated config file - # These env vars are currently (and temporarily) required by the 'helm' plugin - {{- if .Values.packaging.helm.enabled }} - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: ASSET_SYNCER_DB_URL - {{- if .Values.postgresql.enabled }} - value: {{ printf "%s-hl:%d" (include "kubeapps.postgresql.host" .) (int (include "kubeapps.postgresql.port" .)) }} - {{- else }} - value: {{ printf "%s:%d" (include "kubeapps.postgresql.host" .) (int (include "kubeapps.postgresql.port" .)) }} - {{- end }} - - name: ASSET_SYNCER_DB_NAME - value: {{ .Values.postgresql.auth.database | quote }} - - name: ASSET_SYNCER_DB_USERNAME - value: {{ .Values.postgresql.auth.username | quote }} - - name: ASSET_SYNCER_DB_USERPASSWORD - valueFrom: - secretKeyRef: - key: postgres-password - name: {{ include "kubeapps.postgresql.secretName" . }} - {{- if .Values.ociCatalog.enabled }} - - name: OCI_CATALOG_URL - value: {{ printf ":%d" (int .Values.ociCatalog.containerPorts.grpc) | quote }} - {{- end }} - {{- end }} - {{- if .Values.kubeappsapis.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - envFrom: - {{- if .Values.kubeappsapis.extraEnvVarsCM }} - - configMapRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.extraEnvVarsCM "context" $) }} - {{- end }} - {{- if .Values.kubeappsapis.extraEnvVarsSecret }} - - secretRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.extraEnvVarsSecret "context" $) }} - {{- end }} - ports: - - name: grpc-http - containerPort: {{ .Values.kubeappsapis.containerPorts.http }} - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.kubeappsapis.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.customLivenessProbe "context" $) | nindent 12 }} - {{- else if .Values.kubeappsapis.livenessProbe.enabled }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.kubeappsapis.livenessProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: grpc-http - {{- end }} - {{- if .Values.kubeappsapis.customReadinessProbe }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.customReadinessProbe "context" $) | nindent 12 }} - {{- else if .Values.kubeappsapis.readinessProbe.enabled }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.kubeappsapis.readinessProbe "enabled") "context" $) | nindent 12 }} - exec: - command: ["grpc_health_probe", "-addr=:{{ .Values.kubeappsapis.containerPorts.http }}"] - {{- end }} - {{- if .Values.kubeappsapis.customStartupProbe }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.customStartupProbe "context" $) | nindent 12 }} - {{- else if .Values.kubeappsapis.startupProbe.enabled }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.kubeappsapis.startupProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: grpc-http - {{- end }} - {{- end }} - {{- if .Values.kubeappsapis.resources }} - resources: {{- toYaml .Values.kubeappsapis.resources | nindent 12 }} - {{- else if ne .Values.kubeappsapis.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.kubeappsapis.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - {{- if .Values.clusters }} - - name: clusters-config - mountPath: /config - - name: ca-certs - mountPath: /etc/additional-clusters-cafiles - {{- end }} - {{- if .Values.kubeappsapis.pluginConfig }} - - name: plugins-config - mountPath: /config/kubeapps-apis - {{- end }} - {{- if .Values.pinnipedProxy.tls.caCertificate }} - - name: pinniped-proxy-ca-cert - mountPath: /etc/pinniped-proxy-tls - {{- end }} - {{- if .Values.kubeappsapis.extraVolumeMounts }} - {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.extraVolumeMounts "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.ociCatalog.enabled }} - - name: oci-catalog - image: {{ include "kubeapps.ociCatalog.image" . }} - imagePullPolicy: {{ .Values.ociCatalog.image.pullPolicy | quote }} - {{- if .Values.ociCatalog.containerSecurityContext.enabled }} - securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.ociCatalog.containerSecurityContext "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.kubeappsapis.lifecycleHooks }} - lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.lifecycleHooks "context" $) | nindent 12 }} - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} - {{- else if .Values.ociCatalog.command }} - command: {{- include "common.tplvalues.render" (dict "value" .Values.ociCatalog.command "context" $) | nindent 12 }} - {{- else }} - command: - - /oci-catalog - {{- end }} - {{- if .Values.diagnosticMode.enabled }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} - {{- else if .Values.ociCatalog.args }} - args: {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.args "context" $) | nindent 12 }} - {{- else }} - args: - {{- range .Values.ociCatalog.extraFlags }} - - {{ . }} - {{- end }} - {{- end }} - env: - - name: OCI_CATALOG_PORT - value: {{ .Values.ociCatalog.containerPorts.grpc | quote }} - - name: RUST_LOG - # Use info,pinniped_proxy::pinniped=debug for module control. - value: info - {{- if .Values.ociCatalog.extraEnvVars }} - {{- include "common.tplvalues.render" (dict "value" .Values.ociCatalog.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - {{- if or .Values.ociCatalog.extraEnvVarsCM .Values.ociCatalog.extraEnvVarsSecret }} - envFrom: - {{- if .Values.ociCatalog.extraEnvVarsCM }} - - configMapRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.ociCatalog.extraEnvVarsCM "context" $) }} - {{- end }} - {{- if .Values.ociCatalog.extraEnvVarsSecret }} - - secretRef: - name: {{ include "common.tplvalues.render" (dict "value" .Values.ociCatalog.extraEnvVarsSecret "context" $) }} - {{- end }} - {{- end }} - ports: - - name: grpc - containerPort: {{ .Values.ociCatalog.containerPorts.grpc }} - {{- if not .Values.diagnosticMode.enabled }} - {{- if .Values.ociCatalog.customLivenessProbe }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.ociCatalog.customLivenessProbe "context" $) | nindent 12 }} - {{- else if .Values.ociCatalog.livenessProbe.enabled }} - livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.kubeappsapis.livenessProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: grpc-http - {{- end }} - {{- if .Values.ociCatalog.customReadinessProbe }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.ociCatalog.customReadinessProbe "context" $) | nindent 12 }} - {{- else if .Values.ociCatalog.readinessProbe.enabled }} - readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.ociCatalog.readinessProbe "enabled") "context" $) | nindent 12 }} - exec: - command: ["grpc_health_probe", "-addr=:{{ .Values.ociCatalog.containerPorts.grpc }}"] - {{- end }} - {{- if .Values.ociCatalog.customStartupProbe }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.ociCatalog.customStartupProbe "context" $) | nindent 12 }} - {{- else if .Values.ociCatalog.startupProbe.enabled }} - startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.ociCatalog.startupProbe "enabled") "context" $) | nindent 12 }} - tcpSocket: - port: grpc-http - {{- end }} - {{- end }} - {{- if .Values.ociCatalog.resources }} - resources: {{- toYaml .Values.ociCatalog.resources | nindent 12 }} - {{- else if ne .Values.ociCatalog.resourcesPreset "none" }} - resources: {{- include "common.resources.preset" (dict "type" .Values.ociCatalog.resourcesPreset) | nindent 12 }} - {{- end }} - volumeMounts: - - name: empty-dir - mountPath: /tmp - subPath: tmp-dir - {{- if .Values.ociCatalog.extraVolumeMounts }} - {{- include "common.tplvalues.render" (dict "value" .Values.ociCatalog.extraVolumeMounts "context" $) | nindent 12 }} - {{- end }} - {{- end }} - {{- if .Values.kubeappsapis.sidecars }} - {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.sidecars "context" $) | trim | nindent 8 }} - {{- end }} - volumes: - - name: empty-dir - emptyDir: {} - {{- if .Values.clusters }} - - name: clusters-config - configMap: - name: {{ template "kubeapps.clusters-config.fullname" . }} - - name: ca-certs - emptyDir: {} - {{- end }} - {{- if .Values.kubeappsapis.pluginConfig }} - - name: plugins-config - configMap: - name: {{ template "kubeapps.kubeappsapis.fullname" . }}-configmap - {{- end }} - {{- if .Values.pinnipedProxy.tls.caCertificate }} - - name: pinniped-proxy-ca-cert - configMap: - name: {{ .Values.pinnipedProxy.tls.caCertificate }} - {{- end }} - {{- if .Values.kubeappsapis.extraVolumes }} - {{- include "common.tplvalues.render" (dict "value" .Values.kubeappsapis.extraVolumes "context" $) | nindent 8 }} - {{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/networkpolicy.yaml b/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/networkpolicy.yaml deleted file mode 100644 index 7ec6ff01..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/networkpolicy.yaml +++ /dev/null @@ -1,74 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.kubeappsapis.networkPolicy.enabled }} -kind: NetworkPolicy -apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} -metadata: - name: {{ template "kubeapps.kubeappsapis.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.kubeappsapis.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: kubeappsapis - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - policyTypes: - - Ingress - - Egress - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.kubeappsapis.podLabels .Values.commonLabels $versionLabel ) "context" . ) }} - podSelector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: kubeappsapis - {{- if .Values.kubeappsapis.networkPolicy.allowExternalEgress }} - egress: - - {} - {{- else }} - egress: - # Allow dns resolution - - ports: - - port: 53 - protocol: UDP - - port: 53 - protocol: TCP - {{- range $port := .Values.kubeappsapis.networkPolicy.kubeAPIServerPorts }} - - port: {{ $port }} - {{- end }} - {{- if .Values.kubeappsapis.networkPolicy.extraEgress }} - {{- include "common.tplvalues.render" ( dict "value" .Values.kubeappsapis.networkPolicy.extraEgress "context" $ ) | nindent 4 }} - {{- end }} - {{- end }} - ingress: - # Allow inbound connections - - ports: - - port: {{ .Values.kubeappsapis.containerPorts.http }} - {{- if .Values.ociCatalog.enabled }} - - port: {{ .Values.ociCatalog.containerPorts.grpc }} - {{- end }} - {{- if not .Values.kubeappsapis.networkPolicy.allowExternal }} - from: - - podSelector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 14 }} - {{- if .Values.kubeappsapis.networkPolicy.ingressNSMatchLabels }} - - namespaceSelector: - matchLabels: - {{- range $key, $value := .Values.kubeappsapis.networkPolicy.ingressNSMatchLabels }} - {{ $key | quote }}: {{ $value | quote }} - {{- end }} - {{- if .Values.kubeappsapis.networkPolicy.ingressNSPodMatchLabels }} - podSelector: - matchLabels: - {{- range $key, $value := .Values.kubeappsapis.networkPolicy.ingressNSPodMatchLabels }} - {{ $key | quote }}: {{ $value | quote }} - {{- end }} - {{- end }} - {{- end }} - {{- end }} - {{- if .Values.kubeappsapis.networkPolicy.extraIngress }} - {{- include "common.tplvalues.render" ( dict "value" .Values.kubeappsapis.networkPolicy.extraIngress "context" $ ) | nindent 4 }} - {{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/pdb.yaml b/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/pdb.yaml deleted file mode 100644 index d5a27136..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/pdb.yaml +++ /dev/null @@ -1,30 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.kubeappsapis.pdb.create }} -apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} -kind: PodDisruptionBudget -metadata: - name: {{ template "kubeapps.kubeappsapis.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.kubeappsapis.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: kubeappsapis - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -spec: - {{- if .Values.kubeappsapis.pdb.minAvailable }} - minAvailable: {{ .Values.kubeappsapis.pdb.minAvailable }} - {{- end }} - {{- if or .Values.kubeappsapis.pdb.maxUnavailable ( not .Values.kubeappsapis.pdb.minAvailable ) }} - maxUnavailable: {{ .Values.kubeappsapis.pdb.maxUnavailable | default 1 }} - {{- end }} - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.kubeappsapis.podLabels .Values.commonLabels $versionLabel ) "context" . ) }} - selector: - matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} - app.kubernetes.io/component: kubeappsapis -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/rbac.yaml b/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/rbac.yaml deleted file mode 100644 index ba04414d..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/rbac.yaml +++ /dev/null @@ -1,80 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.rbac.create -}} -{{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.kubeappsapis.image "chart" .Chart ) ) }} -{{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: ClusterRole -metadata: - name: {{ printf "kubeapps:%s:kubeappsapis-ns-discovery" .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: kubeappsapis - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -rules: - - apiGroups: - - "" - resources: - - namespaces - verbs: - - list ---- -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: ClusterRoleBinding -metadata: - name: {{ printf "kubeapps:%s:kubeappsapis-ns-discovery" .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: kubeappsapis - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ printf "kubeapps:%s:kubeappsapis-ns-discovery" .Release.Namespace | quote }} -subjects: - - kind: ServiceAccount - name: {{ template "kubeapps.kubeappsapis.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} -{{- if $.Values.featureFlags.operators }} ---- -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: ClusterRole -metadata: - name: {{ printf "kubeapps:%s:kubeappsapis-operators" .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: kubeappsapis - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -rules: - - apiGroups: - - packages.operators.coreos.com - resources: - - packagemanifests/icon - verbs: - - get ---- -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: ClusterRoleBinding -metadata: - name: {{ printf "kubeapps:%s:kubeappsapis-operators" .Release.Namespace | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: kubeappsapis - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ printf "kubeapps:%s:kubeappsapis-operators" .Release.Namespace | quote }} -subjects: - - kind: ServiceAccount - name: {{ template "kubeapps.kubeappsapis.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} -{{- end -}} -{{- end -}} diff --git a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/rbac_fluxv2.yaml b/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/rbac_fluxv2.yaml deleted file mode 100644 index 3fd418c1..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/rbac_fluxv2.yaml +++ /dev/null @@ -1,58 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.packaging.flux.enabled }} -{{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.kubeappsapis.image "chart" .Chart ) ) }} -{{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} -{{- if .Values.rbac.create -}} -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: ClusterRole -metadata: - name: "kubeapps:controller:kubeapps-apis-fluxv2-plugin" - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: kubeappsapis - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -rules: - - apiGroups: ["source.toolkit.fluxcd.io"] - resources: ["helmrepositories"] - verbs: ["get", "list", "watch"] - # needed by fluxv2 plug-in to check whether flux CRDs have been installed - - apiGroups: ["apiextensions.k8s.io"] - resources: ["customresourcedefinitions"] - verbs: ["get", "list"] - # Temp hack to avoid - # Failed to read secret for repo due to: rpc error: code = PermissionDenied desc = Forbidden - # to get the secret 'helm-podinfo' due to 'secrets "helm-podinfo" is forbidden: - # User "system:serviceaccount:kubeapps:kubeapps-internal-kubeappsapis" cannot get resource - # "secrets" in API group "" in the namespace "default"' - # see discussion in https://github.com/vmware-tanzu/kubeapps/pull/4932#issuecomment-1161243049 - - apiGroups: - - "" - resources: - - secrets - verbs: - - get ---- -apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} -kind: ClusterRoleBinding -metadata: - name: "kubeapps:controller:kubeapps-apis-fluxv2-plugin" - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: kubeappsapis - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: "kubeapps:controller:kubeapps-apis-fluxv2-plugin" -subjects: - - kind: ServiceAccount - name: {{ template "kubeapps.kubeappsapis.serviceAccountName" . }} - namespace: {{ include "common.names.namespace" . | quote }} -{{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/service.yaml b/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/service.yaml deleted file mode 100644 index 2f352e5c..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/service.yaml +++ /dev/null @@ -1,34 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -apiVersion: v1 -kind: Service -metadata: - name: {{ template "kubeapps.kubeappsapis.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.kubeappsapis.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: kubeappsapis - {{- if or .Values.kubeappsapis.service.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.kubeappsapis.service.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -spec: - type: ClusterIP - ports: - - port: {{ .Values.kubeappsapis.service.ports.http }} - targetPort: grpc-http - protocol: TCP - name: grpc-http - {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.kubeappsapis.podLabels .Values.commonLabels ) "context" . ) }} - {{- if .Values.ociCatalog.enabled }} - - port: {{ .Values.ociCatalog.containerPorts.grpc }} - targetPort: grpc - protocol: TCP - name: grpc - {{- end }} - selector: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: kubeappsapis diff --git a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/serviceaccount.yaml b/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/serviceaccount.yaml deleted file mode 100644 index b1bac4f8..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/kubeappsapis/serviceaccount.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.kubeappsapis.serviceAccount.create }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ template "kubeapps.kubeappsapis.serviceAccountName" . }} - namespace: {{ include "common.names.namespace" . | quote }} - {{- $versionLabel := dict "app.kubernetes.io/version" ( include "common.images.version" ( dict "imageRoot" .Values.kubeappsapis.image "chart" .Chart ) ) }} - {{- $labels := include "common.tplvalues.merge" ( dict "values" ( list .Values.commonLabels $versionLabel ) "context" . ) }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $labels "context" $ ) | nindent 4 }} - app.kubernetes.io/component: kubeappsapis - {{- if or .Values.kubeappsapis.serviceAccount.annotations .Values.commonAnnotations }} - {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.kubeappsapis.serviceAccount.annotations .Values.commonAnnotations ) "context" . ) }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} - {{- end }} -automountServiceAccountToken: {{ .Values.kubeappsapis.serviceAccount.automountServiceAccountToken }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/shared/config.yaml b/packages/system/dashboard/charts/kubeapps/templates/shared/config.yaml deleted file mode 100644 index 2fdaaa0c..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/shared/config.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if gt (len .Values.clusters) 0 }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "kubeapps.clusters-config.fullname" . }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -data: - clusters.conf: |- -{{ .Values.clusters | toPrettyJson | indent 4 }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/shared/helm-global-repos-namespace.yaml b/packages/system/dashboard/charts/kubeapps/templates/shared/helm-global-repos-namespace.yaml deleted file mode 100644 index 7732d2c1..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/shared/helm-global-repos-namespace.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if or .Values.apprepository.globalReposNamespaceSuffix .Values.kubeappsapis.pluginConfig.helm.packages.v1alpha1.globalPackagingNamespace }} -apiVersion: v1 -kind: Namespace -metadata: - name: {{ include "kubeapps.helmGlobalPackagingNamespace" . | quote }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/templates/tls-secrets.yaml b/packages/system/dashboard/charts/kubeapps/templates/tls-secrets.yaml deleted file mode 100644 index 7e37f4fa..00000000 --- a/packages/system/dashboard/charts/kubeapps/templates/tls-secrets.yaml +++ /dev/null @@ -1,44 +0,0 @@ -{{- /* -Copyright Broadcom, Inc. All Rights Reserved. -SPDX-License-Identifier: APACHE-2.0 -*/}} - -{{- if .Values.ingress.enabled }} -{{- if .Values.ingress.secrets }} -{{- range .Values.ingress.secrets }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ .name }} - namespace: {{ $.Release.Namespace | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" $.Values.commonLabels "context" $ ) | nindent 4 }} - {{- if $.Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" $.Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -type: kubernetes.io/tls -data: - tls.crt: {{ .certificate | b64enc }} - tls.key: {{ .key | b64enc }} ---- -{{- end }} -{{- end }} -{{- if and .Values.ingress.tls .Values.ingress.selfSigned }} -{{- $secretName := printf "%s-tls" .Values.ingress.hostname }} -{{- $ca := genCA "kubeapps-ca" 365 }} -{{- $cert := genSignedCert .Values.ingress.hostname nil (list .Values.ingress.hostname) 365 $ca }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ $secretName }} - namespace: {{ include "common.names.namespace" . | quote }} - labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} - {{- if .Values.commonAnnotations }} - annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} - {{- end }} -type: kubernetes.io/tls -data: - tls.crt: {{ include "common.secrets.lookup" (dict "secret" $secretName "key" "tls.crt" "defaultValue" $cert.Cert "context" $) }} - tls.key: {{ include "common.secrets.lookup" (dict "secret" $secretName "key" "tls.key" "defaultValue" $cert.Key "context" $) }} - ca.crt: {{ include "common.secrets.lookup" (dict "secret" $secretName "key" "ca.crt" "defaultValue" $ca.Cert "context" $) }} -{{- end }} -{{- end }} diff --git a/packages/system/dashboard/charts/kubeapps/values.schema.json b/packages/system/dashboard/charts/kubeapps/values.schema.json deleted file mode 100644 index 913528b8..00000000 --- a/packages/system/dashboard/charts/kubeapps/values.schema.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "$schema": "http://json-schema.org/schema#", - "type": "object", - "properties": { - "frontend": { - "type": "object", - "title": "Frontend configuration", - "form": true, - "properties": { - "replicaCount": { - "type": "integer", - "title": "Number of replicas", - "form": true - } - } - }, - "dashboard": { - "type": "object", - "title": "Dashboard configuration", - "form": true, - "properties": { - "replicaCount": { - "type": "integer", - "title": "Number of replicas", - "form": true - } - } - }, - "kubeappsapis": { - "type": "object", - "title": "kubeappsapis configuration", - "form": true, - "properties": { - "replicaCount": { - "type": "integer", - "title": "Number of replicas", - "form": true - } - } - }, - "ingress": { - "type": "object", - "form": true, - "title": "Ingress configuration", - "properties": { - "enabled": { - "type": "boolean", - "form": true, - "title": "Use a custom hostname", - "description": "Enable the ingress resource that allows you to access the Kubeapps dashboard." - }, - "hostname": { - "type": "string", - "form": true, - "title": "Hostname", - "hidden": { - "value": false, - "path": "ingress/enabled" - } - }, - "tls": { - "type": "boolean", - "form": true, - "title": "Enable TLS configuration", - "hidden": { - "value": false, - "path": "ingress/enabled" - } - } - } - }, - "authProxy": { - "type": "object", - "title": "OIDC Proxy configuration", - "properties": { - "enabled": { - "type": "boolean", - "form": true, - "title": "Enable OIDC proxy", - "description": "Use an OIDC provider in order to manage accounts, groups and roles with a single application" - }, - "provider": { - "type": "string", - "form": true, - "title": "Identity Provider name", - "description": "See https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/overview#generating-a-cookie-secret to find available providers", - "hidden": { - "value": false, - "path": "authProxy/enabled" - } - }, - "clientID": { - "type": "string", - "form": true, - "title": "Client ID:", - "description": "Client ID of the Identity Provider", - "hidden": { - "value": false, - "path": "authProxy/enabled" - } - }, - "clientSecret": { - "type": "string", - "form": true, - "title": "Client Secret", - "description": "Secret used to validate the Client ID", - "hidden": { - "value": false, - "path": "authProxy/enabled" - } - }, - "cookieSecret": { - "type": "string", - "form": true, - "title": "Cookie Secret", - "description": "Used by OAuth2 Proxy to encrypt any credentials", - "hidden": { - "value": false, - "path": "authProxy/enabled" - } - } - } - } - } -} diff --git a/packages/system/dashboard/charts/kubeapps/values.yaml b/packages/system/dashboard/charts/kubeapps/values.yaml deleted file mode 100644 index e2f60969..00000000 --- a/packages/system/dashboard/charts/kubeapps/values.yaml +++ /dev/null @@ -1,2506 +0,0 @@ -# Copyright Broadcom, Inc. All Rights Reserved. -# SPDX-License-Identifier: APACHE-2.0 - -## @section Global parameters -## Global Docker image parameters -## Please, note that this will override the image parameters, including dependencies, configured to use the global value -## Current available global Docker image parameters: imageRegistry, imagePullSecrets and storageClass - -## @param global.imageRegistry Global Docker image registry -## @param global.imagePullSecrets Global Docker registry secret names as an array -## @param global.defaultStorageClass Global default StorageClass for Persistent Volume(s) -## @param global.storageClass DEPRECATED: use global.defaultStorageClass instead -## -global: - imageRegistry: "" - ## E.g. - ## imagePullSecrets: - ## - myRegistryKeySecretName - ## - imagePullSecrets: [] - defaultStorageClass: "" - storageClass: "" - ## Compatibility adaptations for Kubernetes platforms - ## - compatibility: - ## Compatibility adaptations for Openshift - ## - openshift: - ## @param global.compatibility.openshift.adaptSecurityContext Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation) - ## - adaptSecurityContext: auto -## @section Common parameters - -## @param kubeVersion Override Kubernetes version -## -kubeVersion: "" -## @param nameOverride String to partially override common.names.fullname -## -nameOverride: "" -## @param fullnameOverride String to fully override common.names.fullname -## -fullnameOverride: "" -## @param commonLabels Labels to add to all deployed objects -## -commonLabels: {} -## @param commonAnnotations Annotations to add to all deployed objects -## -commonAnnotations: {} -## @param extraDeploy Array of extra objects to deploy with the release -## -extraDeploy: [] -## @param enableIPv6 Enable IPv6 configuration -## -enableIPv6: false -## Enable diagnostic mode in the deployment -## -diagnosticMode: - ## @param diagnosticMode.enabled Enable diagnostic mode (all probes will be disabled and the command will be overridden) - ## - enabled: false - ## @param diagnosticMode.command Command to override all containers in the deployment - ## - command: - - sleep - ## @param diagnosticMode.args Args to override all containers in the deployment - ## - args: - - infinity -## @section Traffic Exposure Parameters - -## Configure the ingress resource that allows you to access the Kubeapps installation -## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/ -## -ingress: - ## @param ingress.enabled Enable ingress record generation for Kubeapps - ## - enabled: false - ## @param ingress.apiVersion Force Ingress API version (automatically detected if not set) - ## - apiVersion: "" - ## @param ingress.hostname Default host for the ingress record - ## - hostname: kubeapps.local - ## @param ingress.path Default path for the ingress record - ## NOTE: You may need to set this to '/*' in order to use this with ALB ingress controllers - ## - path: / - ## @param ingress.pathType Ingress path type - ## - pathType: ImplementationSpecific - ## @param ingress.annotations [object] Additional annotations for the Ingress resource. To enable certificate autogeneration, place here your cert-manager annotations. - ## For a full list of possible ingress annotations, please see - ## ref: https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md - ## Use this parameter to set the required annotations for cert-manager, see - ## ref: https://cert-manager.io/docs/usage/ingress/#supported-annotations - ## - ## e.g: - ## annotations: - ## kubernetes.io/ingress.class: nginx - ## cert-manager.io/cluster-issuer: cluster-issuer-name - ## - annotations: - nginx.ingress.kubernetes.io/proxy-read-timeout: "600" - ## @param ingress.tls Enable TLS configuration for the host defined at `ingress.hostname` parameter - ## TLS certificates will be retrieved from a TLS secret with name: `{{- printf "%s-tls" .Values.ingress.hostname }}` - ## You can: - ## - Use the `ingress.secrets` parameter to create this TLS secret - ## - Rely on cert-manager to create it by setting the corresponding annotations - ## - Rely on Helm to create self-signed certificates by setting `ingress.selfSigned=true` - ## - tls: false - ## @param ingress.selfSigned Create a TLS secret for this ingress record using self-signed certificates generated by Helm - ## - selfSigned: false - ## @param ingress.extraHosts An array with additional hostname(s) to be covered with the ingress record - ## e.g: - ## extraHosts: - ## - name: kubeapps.local - ## path: / - ## - extraHosts: [] - ## @param ingress.extraPaths An array with additional arbitrary paths that may need to be added to the ingress under the main host - ## e.g: - ## extraPaths: - ## - path: /* - ## backend: - ## serviceName: ssl-redirect - ## servicePort: use-annotation - ## - extraPaths: [] - ## @param ingress.extraTls TLS configuration for additional hostname(s) to be covered with this ingress record - ## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#tls - ## e.g: - ## extraTls: - ## - hosts: - ## - kubeapps.local - ## secretName: kubeapps.local-tls - ## - extraTls: [] - ## @param ingress.secrets Custom TLS certificates as secrets - ## NOTE: 'key' and 'certificate' are expected in PEM format - ## NOTE: 'name' should line up with a 'secretName' set further up - ## If it is not set and you're using cert-manager, this is unneeded, as it will create a secret for you with valid certificates - ## If it is not set and you're NOT using cert-manager either, self-signed certificates will be created valid for 365 days - ## It is also possible to create and manage the certificates outside of this helm chart - ## Please see README.md for more information - ## e.g: - ## secrets: - ## - name: kubeapps.local-tls - ## key: |- - ## -----BEGIN RSA PRIVATE KEY----- - ## ... - ## -----END RSA PRIVATE KEY----- - ## certificate: |- - ## -----BEGIN CERTIFICATE----- - ## ... - ## -----END CERTIFICATE----- - ## - secrets: [] - ## @param ingress.ingressClassName IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) - ## This is supported in Kubernetes 1.18+ and required if you have more than one IngressClass marked as the default for your cluster . - ## ref: https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/ - ## - ingressClassName: "" - ## @param ingress.extraRules Additional rules to be covered with this ingress record - ## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-rules - ## e.g: - ## extraRules: - ## - host: example.local - ## http: - ## path: / - ## backend: - ## service: - ## name: example-svc - ## port: - ## name: http - ## - extraRules: [] -## @section Kubeapps packaging options -## Note: the helm and flux plugins are mutually exclusive, you can only -## enable one or the other since they both operate on Helm release objects. -## Enabling carvel or flux does *not* install the required related Carvel or -## Flux controllers on your cluster. Please read the documentation for running -## Kubeapps with Carvel or Flux support. -packaging: - ## Default helm packaging - ## @param packaging.helm.enabled Enable the standard Helm packaging. - helm: - enabled: true - ## Carvel packaging - ## @param packaging.carvel.enabled Enable support for the Carvel (kapp-controller) packaging. - carvel: - enabled: false - ## Flux (v2) packaging - ## @param packaging.flux.enabled Enable support for Flux (v2) packaging. - flux: - enabled: false -## @section Frontend parameters - -## Frontend parameters -## -frontend: - ## Bitnami NGINX image - ## ref: https://hub.docker.com/r/bitnami/nginx/tags/ - ## @param frontend.image.registry [default: REGISTRY_NAME] NGINX image registry - ## @param frontend.image.repository [default: REPOSITORY_NAME/nginx] NGINX image repository - ## @skip frontend.image.tag NGINX image tag (immutable tags are recommended) - ## @param frontend.image.digest NGINX image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag - ## @param frontend.image.pullPolicy NGINX image pull policy - ## @param frontend.image.pullSecrets NGINX image pull secrets - ## @param frontend.image.debug Enable image debug mode - ## - image: - registry: docker.io - repository: bitnami/nginx - tag: 1.27.2-debian-12-r2 - digest: "" - ## Specify a imagePullPolicy - ## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images - ## - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## Enable debug mode - ## - debug: false - ## @param frontend.proxypassAccessTokenAsBearer Use access_token as the Bearer when talking to the k8s api server - ## NOTE: Some K8s distributions such as GKE requires it - ## - proxypassAccessTokenAsBearer: false - ## @param frontend.proxypassExtraSetHeader Set an additional proxy header for all requests proxied via NGINX - ## e.g: - ## proxypassExtraSetHeader: Authorization "Bearer $cookie_sessionid"; - ## - proxypassExtraSetHeader: "" - ## @param frontend.largeClientHeaderBuffers Set large_client_header_buffers in NGINX config - ## NOTE: Can be required when using OIDC or LDAP due to large cookies - ## - largeClientHeaderBuffers: "4 32k" - ## @param frontend.replicaCount Number of frontend replicas to deploy - ## - replicaCount: 2 - ## @param frontend.updateStrategy.type Frontend deployment strategy type. - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy - ## e.g: - ## updateStrategy: - ## type: RollingUpdate - ## rollingUpdate: - ## maxSurge: 25% - ## maxUnavailable: 25% - ## - updateStrategy: - type: RollingUpdate - ## Frontend containers' resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - ## @param frontend.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if frontend.resources is set (frontend.resources is recommended for production). - ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 - ## - resourcesPreset: "micro" - ## @param frontend.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - ## Example: - ## resources: - ## requests: - ## cpu: 2 - ## memory: 512Mi - ## limits: - ## cpu: 3 - ## memory: 1024Mi - ## - resources: {} - ## @param frontend.extraEnvVars Array with extra environment variables to add to the NGINX container - ## e.g: - ## extraEnvVars: - ## - name: FOO - ## value: "bar" - ## - extraEnvVars: [] - ## @param frontend.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for the NGINX container - ## - extraEnvVarsCM: "" - ## @param frontend.extraEnvVarsSecret Name of existing Secret containing extra env vars for the NGINX container - ## - extraEnvVarsSecret: "" - ## @param frontend.containerPorts.http NGINX HTTP container port - ## - containerPorts: - http: 8080 - ## Configure Pods Security Context - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod - ## @param frontend.podSecurityContext.enabled Enabled frontend pods' Security Context - ## @param frontend.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy - ## @param frontend.podSecurityContext.sysctls Set kernel settings using the sysctl interface - ## @param frontend.podSecurityContext.supplementalGroups Set filesystem extra groups - ## @param frontend.podSecurityContext.fsGroup Set frontend pod's Security Context fsGroup - ## - podSecurityContext: - enabled: true - fsGroupChangePolicy: Always - sysctls: [] - supplementalGroups: [] - fsGroup: 1001 - ## Configure Container Security Context for NGINX - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container - ## @param frontend.containerSecurityContext.enabled Enabled containers' Security Context - ## @param frontend.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container - ## @param frontend.containerSecurityContext.runAsUser Set containers' Security Context runAsUser - ## @param frontend.containerSecurityContext.runAsGroup Set containers' Security Context runAsGroup - ## @param frontend.containerSecurityContext.runAsNonRoot Set container's Security Context runAsNonRoot - ## @param frontend.containerSecurityContext.privileged Set container's Security Context privileged - ## @param frontend.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context readOnlyRootFilesystem - ## @param frontend.containerSecurityContext.allowPrivilegeEscalation Set container's Security Context allowPrivilegeEscalation - ## @param frontend.containerSecurityContext.capabilities.drop List of capabilities to be dropped - ## @param frontend.containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile - ## - containerSecurityContext: - enabled: true - seLinuxOptions: {} - runAsUser: 1001 - runAsGroup: 1001 - runAsNonRoot: true - privileged: false - readOnlyRootFilesystem: true - allowPrivilegeEscalation: false - capabilities: - drop: ["ALL"] - seccompProfile: - type: "RuntimeDefault" - ## Configure extra options for frontend containers' liveness and readiness probes - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes - ## @param frontend.livenessProbe.enabled Enable livenessProbe - ## @param frontend.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe - ## @param frontend.livenessProbe.periodSeconds Period seconds for livenessProbe - ## @param frontend.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe - ## @param frontend.livenessProbe.failureThreshold Failure threshold for livenessProbe - ## @param frontend.livenessProbe.successThreshold Success threshold for livenessProbe - ## - livenessProbe: - enabled: true - initialDelaySeconds: 60 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - ## @param frontend.readinessProbe.enabled Enable readinessProbe - ## @param frontend.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe - ## @param frontend.readinessProbe.periodSeconds Period seconds for readinessProbe - ## @param frontend.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe - ## @param frontend.readinessProbe.failureThreshold Failure threshold for readinessProbe - ## @param frontend.readinessProbe.successThreshold Success threshold for readinessProbe - ## - readinessProbe: - enabled: true - initialDelaySeconds: 0 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - ## @param frontend.startupProbe.enabled Enable startupProbe - ## @param frontend.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe - ## @param frontend.startupProbe.periodSeconds Period seconds for startupProbe - ## @param frontend.startupProbe.timeoutSeconds Timeout seconds for startupProbe - ## @param frontend.startupProbe.failureThreshold Failure threshold for startupProbe - ## @param frontend.startupProbe.successThreshold Success threshold for startupProbe - ## - startupProbe: - enabled: false - initialDelaySeconds: 0 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - ## @param frontend.customLivenessProbe Custom livenessProbe that overrides the default one - ## - customLivenessProbe: {} - ## @param frontend.customReadinessProbe Custom readinessProbe that overrides the default one - ## - customReadinessProbe: {} - ## @param frontend.customStartupProbe Custom startupProbe that overrides the default one - ## - customStartupProbe: {} - ## @param frontend.lifecycleHooks Custom lifecycle hooks for frontend containers - ## - lifecycleHooks: {} - ## @param frontend.command Override default container command (useful when using custom images) - ## - command: [] - ## @param frontend.args Override default container args (useful when using custom images) - ## - args: [] - ## @param frontend.podLabels Extra labels for frontend pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ - ## - podLabels: {} - ## @param frontend.podAnnotations Annotations for frontend pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ - ## - podAnnotations: {} - ## @param frontend.podAffinityPreset Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity - ## - podAffinityPreset: "" - ## @param frontend.podAntiAffinityPreset Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` - ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity - ## - podAntiAffinityPreset: soft - ## nodeAffinityPreset Node affinity preset - ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity - ## - nodeAffinityPreset: - ## @param frontend.nodeAffinityPreset.type Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` - ## - type: "" - ## @param frontend.nodeAffinityPreset.key Node label key to match. Ignored if `affinity` is set - ## - key: "" - ## @param frontend.nodeAffinityPreset.values Node label values to match. Ignored if `affinity` is set - ## E.g. - ## values: - ## - e2e-az1 - ## - e2e-az2 - ## - values: [] - ## @param frontend.affinity Affinity for pod assignment - ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity - ## NOTE: frontend.podAffinityPreset, frontend.podAntiAffinityPreset, and frontend.nodeAffinityPreset will be ignored when it's set - ## - affinity: {} - ## @param frontend.nodeSelector Node labels for pod assignment - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ - ## - nodeSelector: {} - ## @param frontend.tolerations Tolerations for pod assignment - ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ - ## - tolerations: [] - ## @param frontend.priorityClassName Priority class name for frontend pods - ## - priorityClassName: "" - ## @param frontend.schedulerName Name of the k8s scheduler (other than default) - ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ - ## - schedulerName: "" - ## @param frontend.topologySpreadConstraints Topology Spread Constraints for pod assignment - ## https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - ## The value is evaluated as a template - ## - topologySpreadConstraints: [] - ## @param frontend.automountServiceAccountToken Mount Service Account token in pod - ## - automountServiceAccountToken: true - ## @param frontend.hostAliases Custom host aliases for frontend pods - ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ - ## - hostAliases: [] - ## @param frontend.extraVolumes Optionally specify extra list of additional volumes for frontend pods - ## - extraVolumes: [] - ## @param frontend.extraVolumeMounts Optionally specify extra list of additional volumeMounts for frontend container(s) - ## - extraVolumeMounts: [] - ## @param frontend.sidecars Add additional sidecar containers to the frontend pod - ## e.g: - ## sidecars: - ## - name: your-image-name - ## image: your-image - ## imagePullPolicy: Always - ## ports: - ## - name: portname - ## containerPort: 1234 - ## - sidecars: [] - ## @param frontend.initContainers Add additional init containers to the frontend pods - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - ## e.g: - ## initContainers: - ## - name: your-image-name - ## image: your-image - ## imagePullPolicy: Always - ## command: ['sh', '-c', 'echo "hello world"'] - ## - initContainers: [] - ## Pod Disruption Budget configuration - ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb - ## @param frontend.pdb.create Enable/disable a Pod Disruption Budget creation - ## @param frontend.pdb.minAvailable Minimum number/percentage of pods that should remain scheduled - ## @param frontend.pdb.maxUnavailable Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `frontend.pdb.minAvailable` and `frontend.pdb.maxUnavailable` are empty. - ## - pdb: - create: true - minAvailable: "" - maxUnavailable: "" - ## Frontend service parameters - ## - service: - ## @param frontend.service.type Frontend service type - ## - type: ClusterIP - ## @param frontend.service.ports.http Frontend service HTTP port - ## - ports: - http: 80 - ## @param frontend.service.nodePorts.http Node port for HTTP - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#nodeport - ## - nodePorts: - http: "" - ## @param frontend.service.clusterIP Frontend service Cluster IP - ## e.g.: - ## clusterIP: None - ## - clusterIP: "" - ## @param frontend.service.loadBalancerIP Frontend service Load Balancer IP - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-loadbalancer - ## - loadBalancerIP: "" - ## @param frontend.service.loadBalancerSourceRanges Frontend service Load Balancer sources - ## ref: https://v1-17.docs.kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service - ## e.g: - ## loadBalancerSourceRanges: - ## - 10.10.10.0/24 - ## - loadBalancerSourceRanges: [] - ## @param frontend.service.externalTrafficPolicy Frontend service external traffic policy - ## ref https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip - ## - externalTrafficPolicy: Cluster - ## @param frontend.service.extraPorts Extra ports to expose (normally used with the `sidecar` value) - ## - extraPorts: [] - ## @param frontend.service.annotations Additional custom annotations for frontend service - ## - annotations: {} - ## @param frontend.service.sessionAffinity Session Affinity for Kubernetes service, can be "None" or "ClientIP" - ## If "ClientIP", consecutive client requests will be directed to the same Pod - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies - ## - sessionAffinity: None - ## @param frontend.service.sessionAffinityConfig Additional settings for the sessionAffinity - ## sessionAffinityConfig: - ## clientIP: - ## timeoutSeconds: 300 - ## - sessionAffinityConfig: {} - ## Network Policies - ## Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ - ## - networkPolicy: - ## @param frontend.networkPolicy.enabled Specifies whether a NetworkPolicy should be created - ## - enabled: true - ## @param frontend.networkPolicy.allowExternal Don't require server label for connections - ## The Policy model to apply. When set to false, only pods with the correct - ## server label will have network access to the ports server is listening - ## on. When true, server will accept connections from any source - ## (with the correct destination port). - ## - allowExternal: true - ## @param frontend.networkPolicy.allowExternalEgress Allow the pod to access any range of port and all destinations. - ## - allowExternalEgress: true - ## @param frontend.networkPolicy.kubeAPIServerPorts [array] List of possible endpoints to kube-apiserver (limit to your cluster settings to increase security) - ## - kubeAPIServerPorts: [443, 6443, 8443] - ## @param frontend.networkPolicy.extraIngress [array] Add extra ingress rules to the NetworkPolicy - ## e.g: - ## extraIngress: - ## - ports: - ## - port: 1234 - ## from: - ## - podSelector: - ## - matchLabels: - ## - role: frontend - ## - podSelector: - ## - matchExpressions: - ## - key: role - ## operator: In - ## values: - ## - frontend - extraIngress: [] - ## @param frontend.networkPolicy.extraEgress [array] Add extra ingress rules to the NetworkPolicy - ## e.g: - ## extraEgress: - ## - ports: - ## - port: 1234 - ## to: - ## - podSelector: - ## - matchLabels: - ## - role: frontend - ## - podSelector: - ## - matchExpressions: - ## - key: role - ## operator: In - ## values: - ## - frontend - ## - extraEgress: [] - ## @param frontend.networkPolicy.ingressNSMatchLabels [object] Labels to match to allow traffic from other namespaces - ## @param frontend.networkPolicy.ingressNSPodMatchLabels [object] Pod labels to match to allow traffic from other namespaces - ## - ingressNSMatchLabels: {} - ingressNSPodMatchLabels: {} -## @section Dashboard parameters - -## Dashboard parameters -## -dashboard: - ## @param dashboard.enabled Specifies whether Kubeapps Dashboard should be deployed or not - ## - enabled: true - ## Bitnami Kubeapps Dashboard image - ## ref: https://hub.docker.com/r/bitnami/kubeapps-dashboard/ - ## @param dashboard.image.registry [default: REGISTRY_NAME] Dashboard image registry - ## @param dashboard.image.repository [default: REPOSITORY_NAME/kubeapps-dashboard] Dashboard image repository - ## @skip dashboard.image.tag Dashboard image tag (immutable tags are recommended) - ## @param dashboard.image.digest Dashboard image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag - ## @param dashboard.image.pullPolicy Dashboard image pull policy - ## @param dashboard.image.pullSecrets Dashboard image pull secrets - ## @param dashboard.image.debug Enable image debug mode - ## - image: - registry: docker.io - repository: bitnami/kubeapps-dashboard - tag: 2.12.0-debian-12-r0 - digest: "" - ## Specify a imagePullPolicy - ## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images - ## - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## Enable debug mode - ## - debug: false - ## @param dashboard.customStyle Custom CSS injected to the Dashboard to customize Kubeapps look and feel - ## e.g: - ## customStyle: |- - ## .header.header-7 { - ## background-color: #991700; - ## } - ## - customStyle: "" - ## @param dashboard.customAppViews Package names to signal a custom app view - ## ref: https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/howto/custom-app-view-support.md - ## e.g: - ## customAppViews: - ## - plugin: helm - ## name: helm-chart - ## repository: bitnami - customAppViews: [] - ## @param dashboard.customComponents Custom Form components injected into the BasicDeploymentForm - ## ref: https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/howto/custom-form-component-support.md - ## - customComponents: "" - ## @param dashboard.remoteComponentsUrl Remote URL that can be used to load custom components vs loading from the local filesystem - ## - remoteComponentsUrl: "" - ## @param dashboard.skipAvailablePackageDetails Skip the package details view and go straight to the installation view of the latest version - ## - skipAvailablePackageDetails: false - ## @param dashboard.customLocale Custom translations injected to the Dashboard to customize the strings used in Kubeapps - ## ref: https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/reference/translations/translate-kubeapps.md - ## e.g: - ## customLocale: - ## "Kubeapps": "My Dashboard" - ## "login-oidc": "Login with my company SSO" - ## - customLocale: "" - ## @param dashboard.defaultTheme Default theme used in the Dashboard if the user has not selected any theme yet. - ## enum: [ "light", "dark" ] - ## e.g: - ## defaultTheme: dark - ## - defaultTheme: "" - ## @param dashboard.replicaCount Number of Dashboard replicas to deploy - ## - ## @param dashboard.createNamespaceLabels Labels added to newly created namespaces - ## e.g: - # createNamespaceLabels: - # "managed-by": "kubeapps" - createNamespaceLabels: {} - replicaCount: 2 - ## @param dashboard.updateStrategy.type Dashboard deployment strategy type. - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy - ## e.g: - ## updateStrategy: - ## type: RollingUpdate - ## rollingUpdate: - ## maxSurge: 25% - ## maxUnavailable: 25% - ## - updateStrategy: - type: RollingUpdate - ## @param dashboard.extraEnvVars Array with extra environment variables to add to the Dashboard container - ## e.g: - ## extraEnvVars: - ## - name: FOO - ## value: "bar" - ## - extraEnvVars: [] - ## @param dashboard.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for the Dashboard container - ## - extraEnvVarsCM: "" - ## @param dashboard.extraEnvVarsSecret Name of existing Secret containing extra env vars for the Dashboard container - ## - extraEnvVarsSecret: "" - ## @param dashboard.containerPorts.http Dashboard HTTP container port - ## - containerPorts: - http: 8080 - ## Dashboard containers' resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - ## @param dashboard.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if dashboard.resources is set (dashboard.resources is recommended for production). - ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 - ## - resourcesPreset: "micro" - ## @param dashboard.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - ## Example: - ## resources: - ## requests: - ## cpu: 2 - ## memory: 512Mi - ## limits: - ## cpu: 3 - ## memory: 1024Mi - ## - resources: {} - ## Configure Pods Security Context - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod - ## @param dashboard.podSecurityContext.enabled Enabled Dashboard pods' Security Context - ## @param dashboard.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy - ## @param dashboard.podSecurityContext.sysctls Set kernel settings using the sysctl interface - ## @param dashboard.podSecurityContext.supplementalGroups Set filesystem extra groups - ## @param dashboard.podSecurityContext.fsGroup Set Dashboard pod's Security Context fsGroup - ## - podSecurityContext: - enabled: true - fsGroupChangePolicy: Always - sysctls: [] - supplementalGroups: [] - fsGroup: 1001 - ## Configure Container Security Context for Dashboard - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container - ## @param dashboard.containerSecurityContext.enabled Enabled containers' Security Context - ## @param dashboard.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container - ## @param dashboard.containerSecurityContext.runAsUser Set containers' Security Context runAsUser - ## @param dashboard.containerSecurityContext.runAsGroup Set containers' Security Context runAsGroup - ## @param dashboard.containerSecurityContext.runAsNonRoot Set container's Security Context runAsNonRoot - ## @param dashboard.containerSecurityContext.privileged Set container's Security Context privileged - ## @param dashboard.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context readOnlyRootFilesystem - ## @param dashboard.containerSecurityContext.allowPrivilegeEscalation Set container's Security Context allowPrivilegeEscalation - ## @param dashboard.containerSecurityContext.capabilities.drop List of capabilities to be dropped - ## @param dashboard.containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile - ## - containerSecurityContext: - enabled: true - seLinuxOptions: {} - runAsUser: 1001 - runAsGroup: 1001 - runAsNonRoot: true - privileged: false - readOnlyRootFilesystem: true - allowPrivilegeEscalation: false - capabilities: - drop: ["ALL"] - seccompProfile: - type: "RuntimeDefault" - ## Configure extra options for Dashboard containers' liveness and readiness probes - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes - ## @param dashboard.livenessProbe.enabled Enable livenessProbe - ## @param dashboard.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe - ## @param dashboard.livenessProbe.periodSeconds Period seconds for livenessProbe - ## @param dashboard.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe - ## @param dashboard.livenessProbe.failureThreshold Failure threshold for livenessProbe - ## @param dashboard.livenessProbe.successThreshold Success threshold for livenessProbe - ## Dashboard containers' liveness and readiness probes - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes - ## - livenessProbe: - enabled: true - initialDelaySeconds: 60 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - ## @param dashboard.readinessProbe.enabled Enable readinessProbe - ## @param dashboard.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe - ## @param dashboard.readinessProbe.periodSeconds Period seconds for readinessProbe - ## @param dashboard.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe - ## @param dashboard.readinessProbe.failureThreshold Failure threshold for readinessProbe - ## @param dashboard.readinessProbe.successThreshold Success threshold for readinessProbe - ## - readinessProbe: - enabled: true - initialDelaySeconds: 0 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - ## @param dashboard.startupProbe.enabled Enable startupProbe - ## @param dashboard.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe - ## @param dashboard.startupProbe.periodSeconds Period seconds for startupProbe - ## @param dashboard.startupProbe.timeoutSeconds Timeout seconds for startupProbe - ## @param dashboard.startupProbe.failureThreshold Failure threshold for startupProbe - ## @param dashboard.startupProbe.successThreshold Success threshold for startupProbe - ## - startupProbe: - enabled: true - initialDelaySeconds: 0 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - ## @param dashboard.customLivenessProbe Custom livenessProbe that overrides the default one - ## - customLivenessProbe: {} - ## @param dashboard.customReadinessProbe Custom readinessProbe that overrides the default one - ## - customReadinessProbe: {} - ## @param dashboard.customStartupProbe Custom startupProbe that overrides the default one - ## - customStartupProbe: {} - ## @param dashboard.lifecycleHooks Custom lifecycle hooks for Dashboard containers - ## - lifecycleHooks: {} - ## @param dashboard.command Override default container command (useful when using custom images) - ## - command: [] - ## @param dashboard.args Override default container args (useful when using custom images) - ## - args: [] - ## @param dashboard.podLabels Extra labels for Dashboard pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ - ## - podLabels: {} - ## @param dashboard.podAnnotations Annotations for Dashboard pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ - ## - podAnnotations: {} - ## @param dashboard.podAffinityPreset Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity - ## - podAffinityPreset: "" - ## @param dashboard.podAntiAffinityPreset Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` - ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity - ## - podAntiAffinityPreset: soft - ## Node affinity preset - ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity - ## - nodeAffinityPreset: - ## @param dashboard.nodeAffinityPreset.type Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` - ## - type: "" - ## @param dashboard.nodeAffinityPreset.key Node label key to match. Ignored if `affinity` is set - ## - key: "" - ## @param dashboard.nodeAffinityPreset.values Node label values to match. Ignored if `affinity` is set - ## E.g. - ## values: - ## - e2e-az1 - ## - e2e-az2 - ## - values: [] - ## @param dashboard.affinity Affinity for pod assignment - ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity - ## NOTE: dashboard.podAffinityPreset, dashboard.podAntiAffinityPreset, and dashboard.nodeAffinityPreset will be ignored when it's set - ## - affinity: {} - ## @param dashboard.nodeSelector Node labels for pod assignment - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ - ## - nodeSelector: {} - ## @param dashboard.tolerations Tolerations for pod assignment - ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ - ## - tolerations: [] - ## @param dashboard.priorityClassName Priority class name for Dashboard pods - ## - priorityClassName: "" - ## @param dashboard.schedulerName Name of the k8s scheduler (other than default) - ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ - ## - schedulerName: "" - ## @param dashboard.topologySpreadConstraints Topology Spread Constraints for pod assignment - ## https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - ## The value is evaluated as a template - ## - topologySpreadConstraints: [] - ## @param dashboard.automountServiceAccountToken Mount Service Account token in pod - ## - automountServiceAccountToken: true - ## @param dashboard.hostAliases Custom host aliases for Dashboard pods - ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ - ## - hostAliases: [] - ## @param dashboard.extraVolumes Optionally specify extra list of additional volumes for Dashboard pods - ## - extraVolumes: [] - ## @param dashboard.extraVolumeMounts Optionally specify extra list of additional volumeMounts for Dashboard container(s) - ## - extraVolumeMounts: [] - ## @param dashboard.sidecars Add additional sidecar containers to the Dashboard pod - ## e.g: - ## sidecars: - ## - name: your-image-name - ## image: your-image - ## imagePullPolicy: Always - ## ports: - ## - name: portname - ## containerPort: 1234 - ## - sidecars: [] - ## @param dashboard.initContainers Add additional init containers to the Dashboard pods - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - ## e.g: - ## initContainers: - ## - name: your-image-name - ## image: your-image - ## imagePullPolicy: Always - ## command: ['sh', '-c', 'echo "hello world"'] - ## - initContainers: [] - ## Pod Disruption Budget configuration - ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb - ## @param dashboard.pdb.create Enable/disable a Pod Disruption Budget creation - ## @param dashboard.pdb.minAvailable Minimum number/percentage of pods that should remain scheduled - ## @param dashboard.pdb.maxUnavailable Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `dashboard.pdb.minAvailable` and `dashboard.pdb.maxUnavailable` are empty. - ## - pdb: - create: true - minAvailable: "" - maxUnavailable: "" - ## Dashboard service parameters - ## - service: - ## @param dashboard.service.ports.http Dashboard service HTTP port - ## - ports: - http: 8080 - ## @param dashboard.service.annotations Additional custom annotations for Dashboard service - ## - annotations: {} - ## Network Policies - ## Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ - ## - networkPolicy: - ## @param dashboard.networkPolicy.enabled Specifies whether a NetworkPolicy should be created - ## - enabled: true - ## @param dashboard.networkPolicy.allowExternal Don't require server label for connections - ## The Policy model to apply. When set to false, only pods with the correct - ## server label will have network access to the ports server is listening - ## on. When true, server will accept connections from any source - ## (with the correct destination port). - ## - allowExternal: true - ## @param dashboard.networkPolicy.allowExternalEgress Allow the pod to access any range of port and all destinations. - ## - allowExternalEgress: true - ## @param dashboard.networkPolicy.kubeAPIServerPorts [array] List of possible endpoints to kube-apiserver (limit to your cluster settings to increase security) - ## - kubeAPIServerPorts: [443, 6443, 8443] - ## @param dashboard.networkPolicy.extraIngress [array] Add extra ingress rules to the NetworkPolicy - ## e.g: - ## extraIngress: - ## - ports: - ## - port: 1234 - ## from: - ## - podSelector: - ## - matchLabels: - ## - role: frontend - ## - podSelector: - ## - matchExpressions: - ## - key: role - ## operator: In - ## values: - ## - frontend - extraIngress: [] - ## @param dashboard.networkPolicy.extraEgress [array] Add extra ingress rules to the NetworkPolicy - ## e.g: - ## extraEgress: - ## - ports: - ## - port: 1234 - ## to: - ## - podSelector: - ## - matchLabels: - ## - role: frontend - ## - podSelector: - ## - matchExpressions: - ## - key: role - ## operator: In - ## values: - ## - frontend - ## - extraEgress: [] - ## @param dashboard.networkPolicy.ingressNSMatchLabels [object] Labels to match to allow traffic from other namespaces - ## @param dashboard.networkPolicy.ingressNSPodMatchLabels [object] Pod labels to match to allow traffic from other namespaces - ## - ingressNSMatchLabels: {} - ingressNSPodMatchLabels: {} -## @section AppRepository Controller parameters - -## AppRepository Controller parameters -## -apprepository: - ## Bitnami Kubeapps AppRepository Controller image - ## ref: https://hub.docker.com/r/bitnami/kubeapps-apprepository-controller/tags/ - ## @param apprepository.image.registry [default: REGISTRY_NAME] Kubeapps AppRepository Controller image registry - ## @param apprepository.image.repository [default: REPOSITORY_NAME/kubeapps-apprepository-controller] Kubeapps AppRepository Controller image repository - ## @skip apprepository.image.tag Kubeapps AppRepository Controller image tag (immutable tags are recommended) - ## @param apprepository.image.digest Kubeapps AppRepository Controller image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag - ## @param apprepository.image.pullPolicy Kubeapps AppRepository Controller image pull policy - ## @param apprepository.image.pullSecrets Kubeapps AppRepository Controller image pull secrets - ## - image: - registry: docker.io - repository: bitnami/kubeapps-apprepository-controller - tag: 2.12.0-debian-12-r0 - digest: "" - ## Specify a imagePullPolicy - ## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images - ## - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## Bitnami Kubeapps Asset Syncer image - ## ref: https://hub.docker.com/r/bitnami/kubeapps-asset-syncer/tags/ - ## @param apprepository.syncImage.registry [default: REGISTRY_NAME] Kubeapps Asset Syncer image registry - ## @param apprepository.syncImage.repository [default: REPOSITORY_NAME/kubeapps-asset-syncer] Kubeapps Asset Syncer image repository - ## @skip apprepository.syncImage.tag Kubeapps Asset Syncer image tag (immutable tags are recommended) - ## @param apprepository.syncImage.digest Kubeapps Asset Syncer image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag - ## @param apprepository.syncImage.pullPolicy Kubeapps Asset Syncer image pull policy - ## @param apprepository.syncImage.pullSecrets Kubeapps Asset Syncer image pull secrets - ## - syncImage: - registry: docker.io - repository: bitnami/kubeapps-asset-syncer - tag: 2.12.0-debian-12-r0 - digest: "" - ## Specify a imagePullPolicy - ## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images - ## - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## @param apprepository.globalReposNamespaceSuffix Suffix for the namespace of global repos in the Helm plugin. Defaults to empty for backwards compatibility. Ignored if kubeappsapis.pluginConfig.helm.packages.v1alpha1.globalPackagingNamespace is set. - ## - globalReposNamespaceSuffix: "" - ## @param apprepository.initialRepos [array] Initial chart repositories to configure - ## e.g: - ## initialRepos: - ## - name: chartmuseum - ## url: https://chartmuseum.default:8080 - ## # Specify nodeSelector and tolerations: - ## nodeSelector: - ## somelabel: somevalue - ## tolerations: - ## - key: "cattle.io/os" - ## operator: "Equal" - ## value: "linux" - ## effect: "NoSchedule" - ## # Specify an Authorization Header if you are using an authentication method: - ## authorizationHeader: "Bearer xrxNC..." - ## # Specify the credentials if you are using a basic authentication method: - ## basicAuth: - ## user: - ## password: - ## # If you're providing your own certificates, please use this to add the certificates as secrets. - ## # It should start with -----BEGIN CERTIFICATE----- or - ## # -----BEGIN RSA PRIVATE KEY----- - ## caCert: - ## # Create this apprepository in a custom namespace - ## namespace: - ## # In case of an OCI registry, specify the type - ## type: oci - ## # And specify the list of repositories - ## ociRepositories: - ## - nginx - ## - jenkins - ## # Optionally filter out some charts. - ## # The jq query format is not exposed in the UI, so care needs to be taken to use the format which the UI expects to parse, - ## # which is why variables are used in the example below. - ## filterRule: - ## jq: .name == $var0 or .name == $var1 - ## variables: - ## $var0: nginx - ## $var1: jenkins - ## - initialRepos: - - name: bitnami - url: https://charts.bitnami.com/bitnami - ## @param apprepository.customAnnotations Custom annotations be added to each AppRepository-generated CronJob, Job and Pod - ## - customAnnotations: {} - ## @param apprepository.customLabels Custom labels be added to each AppRepository-generated CronJob, Job and Pod - ## - customLabels: {} - ## Proxy configuration to access chart repositories - ## - ## @param apprepository.initialReposProxy.enabled Enables the proxy - ## @param apprepository.initialReposProxy.httpProxy URL for the http proxy - ## @param apprepository.initialReposProxy.httpsProxy URL for the https proxy - ## @param apprepository.initialReposProxy.noProxy URL to exclude from using the proxy - ## - initialReposProxy: - enabled: false - httpProxy: "" - httpsProxy: "" - noProxy: "" - ## @param apprepository.crontab Default schedule for syncing App repositories (defaults to every 10 minutes) - ## e.g: - ## crontab: "*/10 * * * *" - ## - crontab: "" - ## @param apprepository.watchAllNamespaces Watch all namespaces to support separate AppRepositories per namespace - ## Switch this off only if you require running multiple instances of Kubeapps in different namespaces - ## without each instance watching AppRepositories of each other - ## - watchAllNamespaces: true - ## @param apprepository.extraFlags Additional command line flags for AppRepository Controller - ## - extraFlags: [] - ## @param apprepository.replicaCount Number of AppRepository Controller replicas to deploy - ## Running a single controller replica to avoid sync job duplication - ## - replicaCount: 1 - ## @param apprepository.updateStrategy.type AppRepository Controller deployment strategy type. - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy - ## e.g: - ## updateStrategy: - ## type: RollingUpdate - ## rollingUpdate: - ## maxSurge: 25% - ## maxUnavailable: 25% - ## - updateStrategy: - type: RollingUpdate - ## AppRepository Controller containers' resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - ## @param apprepository.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if apprepository.resources is set (apprepository.resources is recommended for production). - ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 - ## - resourcesPreset: "micro" - ## @param apprepository.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - ## Example: - ## resources: - ## requests: - ## cpu: 2 - ## memory: 512Mi - ## limits: - ## cpu: 3 - ## memory: 1024Mi - ## - resources: {} - ## Configure Pods Security Context - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod - ## @param apprepository.podSecurityContext.enabled Enabled AppRepository Controller pods' Security Context - ## @param apprepository.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy - ## @param apprepository.podSecurityContext.sysctls Set kernel settings using the sysctl interface - ## @param apprepository.podSecurityContext.supplementalGroups Set filesystem extra groups - ## @param apprepository.podSecurityContext.fsGroup Set AppRepository Controller pod's Security Context fsGroup - ## - podSecurityContext: - enabled: true - fsGroupChangePolicy: Always - sysctls: [] - supplementalGroups: [] - fsGroup: 1001 - ## Configure Container Security Context for App Repository jobs - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container - ## @param apprepository.containerSecurityContext.enabled Enabled containers' Security Context - ## @param apprepository.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container - ## @param apprepository.containerSecurityContext.runAsUser Set containers' Security Context runAsUser - ## @param apprepository.containerSecurityContext.runAsGroup Set containers' Security Context runAsGroup - ## @param apprepository.containerSecurityContext.runAsNonRoot Set container's Security Context runAsNonRoot - ## @param apprepository.containerSecurityContext.privileged Set container's Security Context privileged - ## @param apprepository.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context readOnlyRootFilesystem - ## @param apprepository.containerSecurityContext.allowPrivilegeEscalation Set container's Security Context allowPrivilegeEscalation - ## @param apprepository.containerSecurityContext.capabilities.drop List of capabilities to be dropped - ## @param apprepository.containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile - ## - containerSecurityContext: - enabled: true - seLinuxOptions: {} - runAsUser: 1001 - runAsGroup: 1001 - runAsNonRoot: true - privileged: false - readOnlyRootFilesystem: true - allowPrivilegeEscalation: false - capabilities: - drop: ["ALL"] - seccompProfile: - type: "RuntimeDefault" - ## @param apprepository.lifecycleHooks Custom lifecycle hooks for AppRepository Controller containers - ## - lifecycleHooks: {} - ## @param apprepository.command Override default container command (useful when using custom images) - ## - command: [] - ## @param apprepository.args Override default container args (useful when using custom images) - ## - args: [] - ## @param apprepository.extraEnvVars Array with extra environment variables to add to AppRepository Controller pod(s) - ## e.g: - ## extraEnvVars: - ## - name: FOO - ## value: "bar" - ## - extraEnvVars: [] - ## @param apprepository.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for AppRepository Controller pod(s) - ## - extraEnvVarsCM: "" - ## @param apprepository.extraEnvVarsSecret Name of existing Secret containing extra env vars for AppRepository Controller pod(s) - ## - extraEnvVarsSecret: "" - ## @param apprepository.extraVolumes Optionally specify extra list of additional volumes for the AppRepository Controller pod(s) - ## - extraVolumes: [] - ## @param apprepository.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the AppRepository Controller container(s) - ## - extraVolumeMounts: [] - ## @param apprepository.podLabels Extra labels for AppRepository Controller pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ - ## - podLabels: {} - ## @param apprepository.podAnnotations Annotations for AppRepository Controller pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ - ## - podAnnotations: {} - ## @param apprepository.podAffinityPreset Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity - ## - podAffinityPreset: "" - ## @param apprepository.podAntiAffinityPreset Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` - ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity - ## - podAntiAffinityPreset: soft - ## nodeAffinityPreset Node affinity preset - ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity - ## - nodeAffinityPreset: - ## @param apprepository.nodeAffinityPreset.type Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` - ## - type: "" - ## @param apprepository.nodeAffinityPreset.key Node label key to match. Ignored if `affinity` is set - ## - key: "" - ## @param apprepository.nodeAffinityPreset.values Node label values to match. Ignored if `affinity` is set - ## E.g. - ## values: - ## - e2e-az1 - ## - e2e-az2 - ## - values: [] - ## @param apprepository.affinity Affinity for pod assignment - ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity - ## NOTE: apprepository.podAffinityPreset, apprepository.podAntiAffinityPreset, and apprepository.nodeAffinityPreset will be ignored when it's set - ## - affinity: {} - ## @param apprepository.nodeSelector Node labels for pod assignment - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ - ## - nodeSelector: {} - ## @param apprepository.tolerations Tolerations for pod assignment - ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ - ## - tolerations: [] - ## @param apprepository.priorityClassName Priority class name for AppRepository Controller pods - ## - priorityClassName: "" - ## @param apprepository.schedulerName Name of the k8s scheduler (other than default) - ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ - ## - schedulerName: "" - ## @param apprepository.topologySpreadConstraints Topology Spread Constraints for pod assignment - ## https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - ## The value is evaluated as a template - ## - topologySpreadConstraints: [] - ## @param apprepository.automountServiceAccountToken Mount Service Account token in pod - ## - automountServiceAccountToken: true - ## @param apprepository.hostAliases Custom host aliases for AppRepository Controller pods - ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ - ## - hostAliases: [] - ## @param apprepository.sidecars Add additional sidecar containers to the AppRepository Controller pod(s) - ## e.g: - ## sidecars: - ## - name: your-image-name - ## image: your-image - ## imagePullPolicy: Always - ## ports: - ## - name: portname - ## containerPort: 1234 - ## - sidecars: [] - ## @param apprepository.initContainers Add additional init containers to the AppRepository Controller pod(s) - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - ## e.g: - ## initContainers: - ## - name: your-image-name - ## image: your-image - ## imagePullPolicy: Always - ## command: ['sh', '-c', 'echo "hello world"'] - ## - initContainers: [] - ## Pod Disruption Budget configuration - ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb - ## @param apprepository.pdb.create Enable/disable a Pod Disruption Budget creation - ## @param apprepository.pdb.minAvailable Minimum number/percentage of pods that should remain scheduled - ## @param apprepository.pdb.maxUnavailable Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `apprepository.pdb.minAvailable` and `apprepository.pdb.maxUnavailable` are empty. - ## - pdb: - create: true - minAvailable: "" - maxUnavailable: "" - ## Network Policies - ## Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ - ## - networkPolicy: - ## @param apprepository.networkPolicy.enabled Specifies whether a NetworkPolicy should be created - ## - enabled: true - ## @param apprepository.networkPolicy.allowExternalEgress Allow the pod to access any range of port and all destinations. - ## - allowExternalEgress: true - ## @param apprepository.networkPolicy.kubeAPIServerPorts [array] List of possible endpoints to kube-apiserver (limit to your cluster settings to increase security) - ## - kubeAPIServerPorts: [443, 6443, 8443] - ## @param apprepository.networkPolicy.extraIngress [array] Add extra ingress rules to the NetworkPolicy - ## e.g: - ## extraIngress: - ## - ports: - ## - port: 1234 - ## from: - ## - podSelector: - ## - matchLabels: - ## - role: frontend - ## - podSelector: - ## - matchExpressions: - ## - key: role - ## operator: In - ## values: - ## - frontend - extraIngress: [] - ## @param apprepository.networkPolicy.extraEgress [array] Add extra ingress rules to the NetworkPolicy - ## e.g: - ## extraEgress: - ## - ports: - ## - port: 1234 - ## to: - ## - podSelector: - ## - matchLabels: - ## - role: frontend - ## - podSelector: - ## - matchExpressions: - ## - key: role - ## operator: In - ## values: - ## - frontend - ## - extraEgress: [] - ## AppRepository Controller Service Account - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ - ## @param apprepository.serviceAccount.create Specifies whether a ServiceAccount should be created - ## @param apprepository.serviceAccount.name Name of the service account to use. If not set and create is true, a name is generated using the fullname template. - ## @param apprepository.serviceAccount.automountServiceAccountToken Automount service account token for the server service account - ## @param apprepository.serviceAccount.annotations Annotations for service account. Evaluated as a template. Only used if `create` is `true`. - ## - serviceAccount: - create: true - name: "" - automountServiceAccountToken: false - annotations: {} -## @section Auth Proxy parameters - -## Auth Proxy configuration for OIDC support -## ref: https://github.com/vmware-tanzu/kubeapps/blob/main/site/content/docs/latest/tutorials/using-an-OIDC-provider.md -## -authProxy: - ## @param authProxy.enabled Specifies whether Kubeapps should configure OAuth login/logout - ## - enabled: false - ## Bitnami OAuth2 Proxy image - ## ref: https://hub.docker.com/r/bitnami/oauth2-proxy/tags/ - ## @param authProxy.image.registry [default: REGISTRY_NAME] OAuth2 Proxy image registry - ## @param authProxy.image.repository [default: REPOSITORY_NAME/oauth2-proxy] OAuth2 Proxy image repository - ## @skip authProxy.image.tag OAuth2 Proxy image tag (immutable tags are recommended) - ## @param authProxy.image.digest OAuth2 Proxy image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag - ## @param authProxy.image.pullPolicy OAuth2 Proxy image pull policy - ## @param authProxy.image.pullSecrets OAuth2 Proxy image pull secrets - ## - image: - registry: docker.io - repository: bitnami/oauth2-proxy - tag: 7.7.1-debian-12-r1 - digest: "" - ## Specify a imagePullPolicy - ## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images - ## - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## @param authProxy.external Use an external Auth Proxy instead of deploying its own one - ## - external: false - ## @param authProxy.oauthLoginURI OAuth Login URI to which the Kubeapps frontend redirects for authn - ## @param authProxy.oauthLogoutURI OAuth Logout URI to which the Kubeapps frontend redirects for authn - ## - oauthLoginURI: /oauth2/start - oauthLogoutURI: /oauth2/sign_out - ## @param authProxy.skipKubeappsLoginPage Skip the Kubeapps login page when using OIDC and directly redirect to the IdP - ## - skipKubeappsLoginPage: false - ## @param authProxy.provider OAuth provider - ## @param authProxy.clientID OAuth Client ID - ## @param authProxy.clientSecret OAuth Client secret - ## NOTE: Mandatory parameters for the internal auth-proxy - ## - provider: "" - clientID: "" - clientSecret: "" - ## @param authProxy.cookieSecret Secret used by oauth2-proxy to encrypt any credentials - ## NOTE: It must be a particular number of bytes. It's recommended using the following - ## script to generate a cookieSecret: - ## python -c 'import os,base64; print base64.urlsafe_b64encode(os.urandom(16))' - ## ref: https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/overview#generating-a-cookie-secret - ## - cookieSecret: "" - ## @param authProxy.existingOauth2Secret Name of an existing secret containing the OAuth client secrets, it should contain the keys clientID, clientSecret, and cookieSecret - ## If set, the values `authProxy.provider`, `authProxy.clientID`, `authProxy.clientSecret` will be ignored - ## - existingOauth2Secret: "" - ## @param authProxy.cookieRefresh Duration after which to refresh the cookie - ## - cookieRefresh: 2m - ## @param authProxy.scope OAuth scope specification - ## - scope: "openid email groups" - ## @param authProxy.emailDomain Allowed email domains - ## Use "example.com" to restrict logins to emails from example.com - ## - emailDomain: "*" - ## @param authProxy.extraFlags Additional command line flags for oauth2-proxy - ## ref: https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/overview - ## e.g: - ## extraFlags: - ## - --ssl-insecure-skip-verify - ## - --cookie-secure=false - ## - --oidc-issuer-url=https://accounts.google.com # Only needed if provider is oidc - ## - extraFlags: [] - ## @param authProxy.lifecycleHooks for the Auth Proxy container(s) to automate configuration before or after startup - ## - lifecycleHooks: {} - ## @param authProxy.command Override default container command (useful when using custom images) - ## - command: [] - ## @param authProxy.args Override default container args (useful when using custom images) - ## - args: [] - ## @param authProxy.extraEnvVars Array with extra environment variables to add to the Auth Proxy container - ## e.g: - ## extraEnvVars: - ## - name: FOO - ## value: "bar" - ## - extraEnvVars: [] - ## @param authProxy.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for Auth Proxy containers(s) - ## - extraEnvVarsCM: "" - ## @param authProxy.extraEnvVarsSecret Name of existing Secret containing extra env vars for Auth Proxy containers(s) - ## - extraEnvVarsSecret: "" - ## @param authProxy.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the Auth Proxy container(s) - ## - extraVolumeMounts: [] - ## @param authProxy.containerPorts.proxy Auth Proxy HTTP container port - ## - containerPorts: - proxy: 3000 - ## Configure Container Security Context for Auth Proxy - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container - ## @param authProxy.containerSecurityContext.enabled Enabled containers' Security Context - ## @param authProxy.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container - ## @param authProxy.containerSecurityContext.runAsUser Set containers' Security Context runAsUser - ## @param authProxy.containerSecurityContext.runAsGroup Set containers' Security Context runAsGroup - ## @param authProxy.containerSecurityContext.runAsNonRoot Set container's Security Context runAsNonRoot - ## @param authProxy.containerSecurityContext.privileged Set container's Security Context privileged - ## @param authProxy.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context readOnlyRootFilesystem - ## @param authProxy.containerSecurityContext.allowPrivilegeEscalation Set container's Security Context allowPrivilegeEscalation - ## @param authProxy.containerSecurityContext.capabilities.drop List of capabilities to be dropped - ## @param authProxy.containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile - ## - containerSecurityContext: - enabled: true - seLinuxOptions: {} - runAsUser: 1001 - runAsGroup: 1001 - runAsNonRoot: true - privileged: false - readOnlyRootFilesystem: true - allowPrivilegeEscalation: false - capabilities: - drop: ["ALL"] - seccompProfile: - type: "RuntimeDefault" - ## OAuth2 Proxy containers' resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - ## @param authProxy.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if authProxy.resources is set (authProxy.resources is recommended for production). - ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 - ## - resourcesPreset: "micro" - ## @param authProxy.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - ## Example: - ## resources: - ## requests: - ## cpu: 2 - ## memory: 512Mi - ## limits: - ## cpu: 3 - ## memory: 1024Mi - ## - resources: {} -## @section Pinniped Proxy parameters - -## Pinniped Proxy configuration for converting user OIDC tokens to k8s client authorization certs -## -pinnipedProxy: - ## @param pinnipedProxy.enabled Specifies whether Kubeapps should configure Pinniped Proxy - ## - enabled: false - ## Bitnami Pinniped Proxy image - ## ref: https://hub.docker.com/r/bitnami/kubeapps-pinniped-proxy/tags/ - ## @param pinnipedProxy.image.registry [default: REGISTRY_NAME] Pinniped Proxy image registry - ## @param pinnipedProxy.image.repository [default: REPOSITORY_NAME/kubeapps-pinniped-proxy] Pinniped Proxy image repository - ## @skip pinnipedProxy.image.tag Pinniped Proxy image tag (immutable tags are recommended) - ## @param pinnipedProxy.image.digest Pinniped Proxy image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag - ## @param pinnipedProxy.image.pullPolicy Pinniped Proxy image pull policy - ## @param pinnipedProxy.image.pullSecrets Pinniped Proxy image pull secrets - ## - image: - registry: docker.io - repository: bitnami/kubeapps-pinniped-proxy - tag: 2.12.0-debian-12-r0 - digest: "" - ## Specify a imagePullPolicy - ## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images - ## - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## @param pinnipedProxy.defaultPinnipedNamespace Namespace in which pinniped concierge is installed - ## - defaultPinnipedNamespace: pinniped-concierge - ## @param pinnipedProxy.defaultAuthenticatorType Authenticator type - ## - defaultAuthenticatorType: JWTAuthenticator - ## @param pinnipedProxy.defaultAuthenticatorName Authenticator name - ## - defaultAuthenticatorName: jwt-authenticator - ## @param pinnipedProxy.defaultPinnipedAPISuffix API suffix - ## - defaultPinnipedAPISuffix: pinniped.dev - ## TLS settings for Pinniped Proxy - ## ref: https://kubeapps.dev/docs/latest/howto/oidc/using-an-oidc-provider-with-pinniped/#running-the-pinniped-proxy-service-over-tls - ## - tls: - ## @param pinnipedProxy.tls.existingSecret TLS secret with which to proxy requests - ## - existingSecret: "" - ## @param pinnipedProxy.tls.caCertificate TLS CA cert config map which clients of pinniped proxy should use with TLS requests - ## This config map must contain a ca.crt key with the CA cert content as the value. - ## - caCertificate: "" - ## @param pinnipedProxy.lifecycleHooks For the Pinniped Proxy container(s) to automate configuration before or after startup - ## - lifecycleHooks: {} - ## @param pinnipedProxy.command Override default container command (useful when using custom images) - ## - command: [] - ## @param pinnipedProxy.args Override default container args (useful when using custom images) - ## - args: [] - ## @param pinnipedProxy.extraEnvVars Array with extra environment variables to add to Pinniped Proxy container(s) - ## e.g: - ## extraEnvVars: - ## - name: FOO - ## value: "bar" - ## - extraEnvVars: [] - ## @param pinnipedProxy.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for Pinniped Proxy container(s) - ## - extraEnvVarsCM: "" - ## @param pinnipedProxy.extraEnvVarsSecret Name of existing Secret containing extra env vars for Pinniped Proxy container(s) - ## - extraEnvVarsSecret: "" - ## @param pinnipedProxy.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the Pinniped Proxy container(s) - ## - extraVolumeMounts: [] - ## @param pinnipedProxy.containerPorts.pinnipedProxy Pinniped Proxy container port - ## - containerPorts: - pinnipedProxy: 3333 - ## Configure Container Security Context for Pinniped Proxy - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container - ## @param pinnipedProxy.containerSecurityContext.enabled Enabled containers' Security Context - ## @param pinnipedProxy.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container - ## @param pinnipedProxy.containerSecurityContext.runAsUser Set containers' Security Context runAsUser - ## @param pinnipedProxy.containerSecurityContext.runAsGroup Set containers' Security Context runAsGroup - ## @param pinnipedProxy.containerSecurityContext.runAsNonRoot Set container's Security Context runAsNonRoot - ## @param pinnipedProxy.containerSecurityContext.privileged Set container's Security Context privileged - ## @param pinnipedProxy.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context readOnlyRootFilesystem - ## @param pinnipedProxy.containerSecurityContext.allowPrivilegeEscalation Set container's Security Context allowPrivilegeEscalation - ## @param pinnipedProxy.containerSecurityContext.capabilities.drop List of capabilities to be dropped - ## @param pinnipedProxy.containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile - ## - containerSecurityContext: - enabled: true - seLinuxOptions: {} - runAsUser: 1001 - runAsGroup: 1001 - runAsNonRoot: true - privileged: false - readOnlyRootFilesystem: true - allowPrivilegeEscalation: false - capabilities: - drop: ["ALL"] - seccompProfile: - type: "RuntimeDefault" - ## Pinniped Proxy containers' resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - ## @param pinnipedProxy.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if pinnipedProxy.resources is set (pinnipedProxy.resources is recommended for production). - ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 - ## - resourcesPreset: "micro" - ## @param pinnipedProxy.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - ## Example: - ## resources: - ## requests: - ## cpu: 2 - ## memory: 512Mi - ## limits: - ## cpu: 3 - ## memory: 1024Mi - ## - resources: {} - ## Pinniped Proxy service parameters - ## - service: - ## @param pinnipedProxy.service.ports.pinnipedProxy Pinniped Proxy service port - ## - ports: - pinnipedProxy: 3333 - ## @param pinnipedProxy.service.annotations Additional custom annotations for Pinniped Proxy service - ## - annotations: {} -## @section Other Parameters - -## @param clusters [array] List of clusters that Kubeapps can target for deployments -## When populated with a single cluster (as it is by default), Kubeapps will not allow users to -## change the target cluster. When populated with multiple clusters, Kubeapps will present the clusters to -## the user as potential targets for install or browsing. -## - Note that you can define a single cluster without an apiServiceURL and the chart will assume this is -## the name you are assigning to the cluster on which Kubeapps is itself installed. Specifying more than -## one cluster without an apiServiceURL will cause the chart display an error. -## - The base64-encoded certificateAuthorityData can be obtained from the additional cluster's kube config -## file, for example, to get the ca data for the 0th cluster in your config (adjust the index 0 as necessary): -## kubectl --kubeconfig ~/.kube/kind-config-kubeapps-additional config view --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' -## - serviceToken is an optional token configured to allow LIST namespaces and package manifests (operators) only on the additional cluster -## so that the UI can present a list of (only) those namespaces to which the user has access and the available operators. -## - isKubeappsCluster is an optional parameter that allows defining the cluster in which Kubeapps is installed; -## this param is useful when every cluster is using an apiServiceURL (e.g., when using the Pinniped Impersonation Proxy) -## as the chart cannot infer the cluster on which Kubeapps is installed in that case. -## - pinnipedConfig is an optional parameter that contains configuration options specific to a cluster running the pinniped concierge service. -## e.g.: -## clusters: -## - name: default -## domain: cluster.local -## - name: second-cluster -## domain: cluster.local -## apiServiceURL: https://second-cluster:6443 -## certificateAuthorityData: LS0tLS1CRUdJ... -## serviceToken: ... -## isKubeappsCluster: true -## pinnipedConfig: -## enabled: true - -## -clusters: - - name: default - domain: cluster.local -## RBAC configuration -## -rbac: - ## @param rbac.create Specifies whether RBAC resources should be created - ## - create: true -## @section Feature flags -## -## Opt-in features intended for development and advanced use cases. -## They might be removed in future releases without prior notice. -featureFlags: - ## For a full list of possible ingress annotations, please see - apiOnly: - ## @param featureFlags.apiOnly.enabled Enable ingress for API operations only. Access to "/" will not be possible, so Dashboard will be unusable. - ## - enabled: false - grpc: - ## @param featureFlags.apiOnly.grpc.annotations [object] Specific annotations for the GRPC ingress in API-only mode - ## ref: https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md - ## - annotations: - nginx.ingress.kubernetes.io/backend-protocol: GRPC - ## @param featureFlags.operators Enable support for Operators in Kubeapps - ## - operators: false - schemaEditor: - ## @param featureFlags.schemaEditor.enabled Enable a visual editor for customizing the package schemas - ## - enabled: false -## @section Database Parameters - -## PostgreSQL chart configuration -## ref: https://github.com/bitnami/charts/blob/main/bitnami/postgresql/values.yaml -## @param postgresql.enabled Deploy a PostgreSQL server to satisfy the applications database requirements -## @param postgresql.auth.username Username for PostgreSQL server -## @param postgresql.auth.postgresPassword Password for 'postgres' user -## ref: https://github.com/bitnami/containers/tree/main/bitnami/postgresql#setting-the-root-password-on-first-run -## @param postgresql.auth.database Name for a custom database to create -## @param postgresql.auth.existingSecret Name of existing secret to use for PostgreSQL credentials -## -postgresql: - enabled: true - auth: - username: "postgres" - postgresPassword: "" - database: assets - existingSecret: "" - ## PostgreSQL Primary persistence configuration - ## @param postgresql.primary.persistence.enabled Enable PostgreSQL Primary data persistence using PVC - primary: - persistence: - enabled: false - ## @param postgresql.architecture PostgreSQL architecture (`standalone` or `replication`) - ## - architecture: standalone - ## @param postgresql.securityContext.enabled Enabled PostgreSQL replicas pods' Security Context - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ - ## - securityContext: - enabled: false - ## PostgreSQL containers' resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - ## @param postgresql.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if postgresql.resources is set (postgresql.resources is recommended for production). - ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 - ## - resourcesPreset: "micro" - ## @param postgresql.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - ## Example: - ## resources: - ## requests: - ## cpu: 2 - ## memory: 512Mi - ## limits: - ## cpu: 3 - ## memory: 1024Mi - ## - ## - resources: {} -## @section kubeappsapis parameters -kubeappsapis: - ## @param kubeappsapis.enabledPlugins Manually override which plugins are enabled for the Kubeapps-APIs service - ## - ## NOTE: normally this should remain blank, with the top-level `packaging` - ## value automatically determining which plugins should be enabled. Only - ## set this value if you want to manually override the list of plugins - ## enabled for the service. - ## - enabledPlugins: [] - pluginConfig: - core: - packages: - v1alpha1: - versionsInSummary: - ## @param kubeappsapis.pluginConfig.core.packages.v1alpha1.versionsInSummary.major Number of major versions to display in the summary - major: 3 - ## @param kubeappsapis.pluginConfig.core.packages.v1alpha1.versionsInSummary.minor Number of minor versions to display in the summary - minor: 3 - ## @param kubeappsapis.pluginConfig.core.packages.v1alpha1.versionsInSummary.patch Number of patch versions to display in the summary - patch: 3 - ## @param kubeappsapis.pluginConfig.core.packages.v1alpha1.timeoutSeconds Value to wait for Kubernetes commands to complete - timeoutSeconds: 300 - helm: - packages: - v1alpha1: - ## @param kubeappsapis.pluginConfig.helm.packages.v1alpha1.globalPackagingNamespace Custom global packaging namespace. Using this value will override the current "kubeapps release namespace + suffix" pattern and will create a new namespace if not exists. - globalPackagingNamespace: "" - kappController: - packages: - v1alpha1: - ## @param kubeappsapis.pluginConfig.kappController.packages.v1alpha1.defaultUpgradePolicy Default upgrade policy generating version constraints - ## enum: [ "major", "minor", "patch", "none" ] - defaultUpgradePolicy: none - ## @param kubeappsapis.pluginConfig.kappController.packages.v1alpha1.defaultPrereleasesVersionSelection [array,nullable] Default policy for allowing prereleases containing one of the identifiers - ## ref: https://carvel.dev/kapp-controller/docs/latest/package-consumer-concepts/#prereleases - ## e.g: - # defaultPrereleasesVersionSelection: - # - rc - defaultPrereleasesVersionSelection: null - ## @param kubeappsapis.pluginConfig.kappController.packages.v1alpha1.defaultAllowDowngrades Default policy for allowing applications to be downgraded to previous versions - ## ref: https://carvel.dev/kapp-controller/docs/latest/package-consumer-concepts/#downgrading - defaultAllowDowngrades: false - ## @param kubeappsapis.pluginConfig.kappController.packages.v1alpha1.globalPackagingNamespace Default global packaging namespace - ## ref: https://carvel.dev/kapp-controller/docs/latest/package-consumer-concepts/#namespacing - globalPackagingNamespace: kapp-controller-packaging-global - flux: - packages: - v1alpha1: - ## @param kubeappsapis.pluginConfig.flux.packages.v1alpha1.defaultUpgradePolicy Default upgrade policy generating version constraints - ## enum: [ "major", "minor", "patch", "none" ] - defaultUpgradePolicy: none - ## @param kubeappsapis.pluginConfig.flux.packages.v1alpha1.noCrossNamespaceRefs Enable this flag to disallow cross-namespace references, useful when running Flux on multi-tenant clusters - noCrossNamespaceRefs: false - resources: - packages: - v1alpha1: - ## Trusted namespaces parameters - ## - trustedNamespaces: - ## @param kubeappsapis.pluginConfig.resources.packages.v1alpha1.trustedNamespaces.headerName Optional header name for trusted namespaces - ## e.g: - ## headerName: X-Consumer-Groups - ## - headerName: "" - ## @param kubeappsapis.pluginConfig.resources.packages.v1alpha1.trustedNamespaces.headerPattern Optional header pattern for trusted namespaces - ## e.g: - ## headerPattern: namespace:^([\w-]+):\w+$ - ## - headerPattern: "" - ## Bitnami Kubeapps-APIs image - ## ref: https://hub.docker.com/r/bitnami/kubeapps-apis/tags/ - ## @param kubeappsapis.image.registry [default: REGISTRY_NAME] Kubeapps-APIs image registry - ## @param kubeappsapis.image.repository [default: REPOSITORY_NAME/kubeapps-apis] Kubeapps-APIs image repository - ## @skip kubeappsapis.image.tag Kubeapps-APIs image tag (immutable tags are recommended) - ## @param kubeappsapis.image.digest Kubeapps-APIs image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag - ## @param kubeappsapis.image.pullPolicy Kubeapps-APIs image pull policy - ## @param kubeappsapis.image.pullSecrets Kubeapps-APIs image pull secrets - ## - image: - registry: docker.io - repository: bitnami/kubeapps-apis - tag: 2.12.0-debian-12-r0 - digest: "" - ## Specify a imagePullPolicy - ## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images - ## - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## @param kubeappsapis.replicaCount Number of frontend replicas to deploy - ## - replicaCount: 2 - ## @param kubeappsapis.updateStrategy.type KubeappsAPIs deployment strategy type. - ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy - ## e.g: - ## updateStrategy: - ## type: RollingUpdate - ## rollingUpdate: - ## maxSurge: 25% - ## maxUnavailable: 25% - ## - updateStrategy: - type: RollingUpdate - ## @param kubeappsapis.extraFlags Additional command line flags for KubeappsAPIs - ## - extraFlags: [] - ## @param kubeappsapis.qps KubeappsAPIs Kubernetes API client QPS limit - ## - qps: "50.0" - ## @param kubeappsapis.burst KubeappsAPIs Kubernetes API client Burst limit - ## - burst: "100" - ## @param kubeappsapis.terminationGracePeriodSeconds The grace time period for sig term - ## ref: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#hook-handler-execution - ## - terminationGracePeriodSeconds: 300 - ## @param kubeappsapis.extraEnvVars Array with extra environment variables to add to the KubeappsAPIs container - ## e.g: - ## extraEnvVars: - ## - name: FOO - ## value: "bar" - ## - extraEnvVars: [] - ## @param kubeappsapis.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for the KubeappsAPIs container - ## - extraEnvVarsCM: "" - ## @param kubeappsapis.extraEnvVarsSecret Name of existing Secret containing extra env vars for the KubeappsAPIs container - ## - extraEnvVarsSecret: "" - ## @param kubeappsapis.containerPorts.http KubeappsAPIs HTTP container port - ## - containerPorts: - http: 50051 - ## KubeappsAPIs containers' resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - ## @param kubeappsapis.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if kubeappsapis.resources is set (kubeappsapis.resources is recommended for production). - ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 - ## - resourcesPreset: "micro" - ## @param kubeappsapis.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - ## Example: - ## resources: - ## requests: - ## cpu: 2 - ## memory: 512Mi - ## limits: - ## cpu: 3 - ## memory: 1024Mi - ## - resources: {} - ## Configure Pods Security Context - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod - ## @param kubeappsapis.podSecurityContext.enabled Enabled KubeappsAPIs pods' Security Context - ## @param kubeappsapis.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy - ## @param kubeappsapis.podSecurityContext.sysctls Set kernel settings using the sysctl interface - ## @param kubeappsapis.podSecurityContext.supplementalGroups Set filesystem extra groups - ## @param kubeappsapis.podSecurityContext.fsGroup Set KubeappsAPIs pod's Security Context fsGroup - ## - podSecurityContext: - enabled: true - fsGroupChangePolicy: Always - sysctls: [] - supplementalGroups: [] - fsGroup: 1001 - ## Configure Container Security Context for Kubeapps APIs - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container - ## @param kubeappsapis.containerSecurityContext.enabled Enabled containers' Security Context - ## @param kubeappsapis.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container - ## @param kubeappsapis.containerSecurityContext.runAsUser Set containers' Security Context runAsUser - ## @param kubeappsapis.containerSecurityContext.runAsGroup Set containers' Security Context runAsGroup - ## @param kubeappsapis.containerSecurityContext.runAsNonRoot Set container's Security Context runAsNonRoot - ## @param kubeappsapis.containerSecurityContext.privileged Set container's Security Context privileged - ## @param kubeappsapis.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context readOnlyRootFilesystem - ## @param kubeappsapis.containerSecurityContext.allowPrivilegeEscalation Set container's Security Context allowPrivilegeEscalation - ## @param kubeappsapis.containerSecurityContext.capabilities.drop List of capabilities to be dropped - ## @param kubeappsapis.containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile - ## - containerSecurityContext: - enabled: true - seLinuxOptions: {} - runAsUser: 1001 - runAsGroup: 1001 - runAsNonRoot: true - privileged: false - readOnlyRootFilesystem: true - allowPrivilegeEscalation: false - capabilities: - drop: ["ALL"] - seccompProfile: - type: "RuntimeDefault" - ## Configure extra options for KubeappsAPIs containers' liveness and readiness probes - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes - ## @param kubeappsapis.livenessProbe.enabled Enable livenessProbe - ## @param kubeappsapis.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe - ## @param kubeappsapis.livenessProbe.periodSeconds Period seconds for livenessProbe - ## @param kubeappsapis.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe - ## @param kubeappsapis.livenessProbe.failureThreshold Failure threshold for livenessProbe - ## @param kubeappsapis.livenessProbe.successThreshold Success threshold for livenessProbe - ## KubeappsAPIs containers' liveness and readiness probes - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes - ## - livenessProbe: - enabled: true - initialDelaySeconds: 60 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - ## @param kubeappsapis.readinessProbe.enabled Enable readinessProbe - ## @param kubeappsapis.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe - ## @param kubeappsapis.readinessProbe.periodSeconds Period seconds for readinessProbe - ## @param kubeappsapis.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe - ## @param kubeappsapis.readinessProbe.failureThreshold Failure threshold for readinessProbe - ## @param kubeappsapis.readinessProbe.successThreshold Success threshold for readinessProbe - ## - readinessProbe: - enabled: true - initialDelaySeconds: 0 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - ## @param kubeappsapis.startupProbe.enabled Enable startupProbe - ## @param kubeappsapis.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe - ## @param kubeappsapis.startupProbe.periodSeconds Period seconds for startupProbe - ## @param kubeappsapis.startupProbe.timeoutSeconds Timeout seconds for startupProbe - ## @param kubeappsapis.startupProbe.failureThreshold Failure threshold for startupProbe - ## @param kubeappsapis.startupProbe.successThreshold Success threshold for startupProbe - ## - startupProbe: - enabled: false - initialDelaySeconds: 0 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - ## @param kubeappsapis.customLivenessProbe Custom livenessProbe that overrides the default one - ## - customLivenessProbe: {} - ## @param kubeappsapis.customReadinessProbe Custom readinessProbe that overrides the default one - ## - customReadinessProbe: {} - ## @param kubeappsapis.customStartupProbe Custom startupProbe that overrides the default one - ## - customStartupProbe: {} - ## @param kubeappsapis.lifecycleHooks Custom lifecycle hooks for KubeappsAPIs containers - ## - lifecycleHooks: {} - ## @param kubeappsapis.command Override default container command (useful when using custom images) - ## - command: [] - ## @param kubeappsapis.args Override default container args (useful when using custom images) - ## - args: [] - ## @param kubeappsapis.extraVolumes Optionally specify extra list of additional volumes for the KubeappsAPIs pod(s) - ## - extraVolumes: [] - ## @param kubeappsapis.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the KubeappsAPIs container(s) - ## - extraVolumeMounts: [] - ## @param kubeappsapis.podLabels Extra labels for KubeappsAPIs pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ - ## - podLabels: {} - ## @param kubeappsapis.podAnnotations Annotations for KubeappsAPIs pods - ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ - ## - podAnnotations: {} - ## @param kubeappsapis.podAffinityPreset Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity - ## - podAffinityPreset: "" - ## @param kubeappsapis.podAntiAffinityPreset Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard` - ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity - ## - podAntiAffinityPreset: soft - ## nodeAffinityPreset Node affinity preset - ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity - ## - nodeAffinityPreset: - ## @param kubeappsapis.nodeAffinityPreset.type Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard` - ## - type: "" - ## @param kubeappsapis.nodeAffinityPreset.key Node label key to match. Ignored if `affinity` is set - ## - key: "" - ## @param kubeappsapis.nodeAffinityPreset.values Node label values to match. Ignored if `affinity` is set - ## E.g. - ## values: - ## - e2e-az1 - ## - e2e-az2 - ## - values: [] - ## @param kubeappsapis.affinity Affinity for pod assignment - ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity - ## NOTE: kubeappsapis.podAffinityPreset, kubeappsapis.podAntiAffinityPreset, and kubeappsapis.nodeAffinityPreset will be ignored when it's set - ## - affinity: {} - ## @param kubeappsapis.nodeSelector Node labels for pod assignment - ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ - ## - nodeSelector: {} - ## @param kubeappsapis.tolerations Tolerations for pod assignment - ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ - ## - tolerations: [] - ## @param kubeappsapis.priorityClassName Priority class name for KubeappsAPIs pods - ## - priorityClassName: "" - ## @param kubeappsapis.schedulerName Name of the k8s scheduler (other than default) - ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ - ## - schedulerName: "" - ## @param kubeappsapis.topologySpreadConstraints Topology Spread Constraints for pod assignment - ## https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - ## The value is evaluated as a template - ## - topologySpreadConstraints: [] - ## @param kubeappsapis.automountServiceAccountToken Mount Service Account token in pod - ## - automountServiceAccountToken: true - ## @param kubeappsapis.hostAliases Custom host aliases for KubeappsAPIs pods - ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ - ## - hostAliases: [] - ## @param kubeappsapis.sidecars Add additional sidecar containers to the KubeappsAPIs pod(s) - ## e.g: - ## sidecars: - ## - name: your-image-name - ## image: your-image - ## imagePullPolicy: Always - ## ports: - ## - name: portname - ## containerPort: 1234 - ## - sidecars: [] - ## @param kubeappsapis.initContainers Add additional init containers to the KubeappsAPIs pod(s) - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - ## e.g: - ## initContainers: - ## - name: your-image-name - ## image: your-image - ## imagePullPolicy: Always - ## command: ['sh', '-c', 'echo "hello world"'] - ## - initContainers: [] - ## Pod Disruption Budget configuration - ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb - ## @param kubeappsapis.pdb.create Enable/disable a Pod Disruption Budget creation - ## @param kubeappsapis.pdb.minAvailable Minimum number/percentage of pods that should remain scheduled - ## @param kubeappsapis.pdb.maxUnavailable Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `kubeappsapis.pdb.minAvailable` and `kubeappsapis.pdb.maxUnavailable` are empty. - ## - pdb: - create: true - minAvailable: "" - maxUnavailable: "" - ## kubeappsapis service parameters - ## - service: - ## @param kubeappsapis.service.ports.http KubeappsAPIs service HTTP port - ## - ports: - http: 8080 - ## @param kubeappsapis.service.annotations Additional custom annotations for KubeappsAPIs service - ## - annotations: {} - ## Network Policies - ## Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ - ## - networkPolicy: - ## @param kubeappsapis.networkPolicy.enabled Specifies whether a NetworkPolicy should be created - ## - enabled: true - ## @param kubeappsapis.networkPolicy.allowExternal Don't require server label for connections - ## The Policy model to apply. When set to false, only pods with the correct - ## server label will have network access to the ports server is listening - ## on. When true, server will accept connections from any source - ## (with the correct destination port). - ## - allowExternal: true - ## @param kubeappsapis.networkPolicy.allowExternalEgress Allow the pod to access any range of port and all destinations. - ## - allowExternalEgress: true - ## @param kubeappsapis.networkPolicy.kubeAPIServerPorts [array] List of possible endpoints to kube-apiserver (limit to your cluster settings to increase security) - ## - kubeAPIServerPorts: [443, 6443, 8443] - ## @param kubeappsapis.networkPolicy.extraIngress [array] Add extra ingress rules to the NetworkPolicy - ## e.g: - ## extraIngress: - ## - ports: - ## - port: 1234 - ## from: - ## - podSelector: - ## - matchLabels: - ## - role: frontend - ## - podSelector: - ## - matchExpressions: - ## - key: role - ## operator: In - ## values: - ## - frontend - extraIngress: [] - ## @param kubeappsapis.networkPolicy.extraEgress [array] Add extra ingress rules to the NetworkPolicy - ## e.g: - ## extraEgress: - ## - ports: - ## - port: 1234 - ## to: - ## - podSelector: - ## - matchLabels: - ## - role: frontend - ## - podSelector: - ## - matchExpressions: - ## - key: role - ## operator: In - ## values: - ## - frontend - ## - extraEgress: [] - ## @param kubeappsapis.networkPolicy.ingressNSMatchLabels [object] Labels to match to allow traffic from other namespaces - ## @param kubeappsapis.networkPolicy.ingressNSPodMatchLabels [object] Pod labels to match to allow traffic from other namespaces - ## - ingressNSMatchLabels: {} - ingressNSPodMatchLabels: {} - ## kubeappsapis Service Account - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ - ## @param kubeappsapis.serviceAccount.create Specifies whether a ServiceAccount should be created - ## @param kubeappsapis.serviceAccount.name Name of the service account to use. If not set and create is true, a name is generated using the fullname template. - ## @param kubeappsapis.serviceAccount.automountServiceAccountToken Automount service account token for the server service account - ## @param kubeappsapis.serviceAccount.annotations Annotations for service account. Evaluated as a template. Only used if `create` is `true`. - ## - serviceAccount: - create: true - name: "" - automountServiceAccountToken: false - annotations: {} -## @section OCI Catalog chart configuration -ociCatalog: - ## @param ociCatalog.enabled Enable the OCI catalog gRPC service for cataloging - ## OCI repositories - enabled: false - ## Bitnami Kubeapps OCI Catalog image - ## ref: https://hub.docker.com/r/bitnami/kubeapps-ocicatalog/ - ## @param ociCatalog.image.registry [default: REGISTRY_NAME] OCI Catalog image registry - ## @param ociCatalog.image.repository [default: REPOSITORY_NAME/kubeapps-oci-catalog] OCI Catalog image repository - ## @skip ociCatalog.image.tag OCI Catalog image tag (immutable tags are recommended) - ## @param ociCatalog.image.digest OCI Catalog image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag - ## @param ociCatalog.image.pullPolicy OCI Catalog image pull policy - ## @param ociCatalog.image.pullSecrets OCI Catalog image pull secrets - ## @param ociCatalog.image.debug Enable image debug mode - ## - image: - registry: docker.io - repository: bitnami/kubeapps-oci-catalog - tag: 2.12.0-debian-12-r0 - digest: "" - ## Specify a imagePullPolicy - ## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images - ## - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## e.g: - ## pullSecrets: - ## - myRegistryKeySecretName - ## - pullSecrets: [] - ## Enable debug mode - ## - debug: false - ## @param ociCatalog.extraFlags Additional command line flags for OCI Catalog - ## - extraFlags: [] - ## @param ociCatalog.extraEnvVars Array with extra environment variables to add to the oci-catalog container - ## e.g: - ## extraEnvVars: - ## - name: FOO - ## value: "bar" - ## - extraEnvVars: [] - ## @param ociCatalog.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for the OCI Catalog container - ## - extraEnvVarsCM: "" - ## @param ociCatalog.extraEnvVarsSecret Name of existing Secret containing extra env vars for the OCI Catalog container - ## - extraEnvVarsSecret: "" - ## @param ociCatalog.containerPorts.grpc OCI Catalog gRPC container port - ## - containerPorts: - grpc: 50061 - ## OCI Catalog containers' resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - ## @param ociCatalog.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if ociCatalog.resources is set (ociCatalog.resources is recommended for production). - ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 - ## - resourcesPreset: "micro" - ## @param ociCatalog.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - ## Example: - ## resources: - ## requests: - ## cpu: 2 - ## memory: 512Mi - ## limits: - ## cpu: 3 - ## memory: 1024Mi - ## - resources: {} - ## Configure Container Security Context (only main container) - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container - ## @param ociCatalog.containerSecurityContext.enabled Enabled containers' Security Context - ## @param ociCatalog.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container - ## @param ociCatalog.containerSecurityContext.runAsUser Set containers' Security Context runAsUser - ## @param ociCatalog.containerSecurityContext.runAsGroup Set containers' Security Context runAsGroup - ## @param ociCatalog.containerSecurityContext.runAsNonRoot Set container's Security Context runAsNonRoot - ## @param ociCatalog.containerSecurityContext.privileged Set container's Security Context privileged - ## @param ociCatalog.containerSecurityContext.readOnlyRootFilesystem Set container's Security Context readOnlyRootFilesystem - ## @param ociCatalog.containerSecurityContext.allowPrivilegeEscalation Set container's Security Context allowPrivilegeEscalation - ## @param ociCatalog.containerSecurityContext.capabilities.drop List of capabilities to be dropped - ## @param ociCatalog.containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile - ## - containerSecurityContext: - enabled: true - seLinuxOptions: {} - runAsUser: 1001 - runAsGroup: 1001 - runAsNonRoot: true - privileged: false - readOnlyRootFilesystem: true - allowPrivilegeEscalation: false - capabilities: - drop: ["ALL"] - seccompProfile: - type: "RuntimeDefault" - ## Configure extra options for OCI Catalog containers' liveness and readiness probes - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes - ## @param ociCatalog.livenessProbe.enabled Enable livenessProbe - ## @param ociCatalog.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe - ## @param ociCatalog.livenessProbe.periodSeconds Period seconds for livenessProbe - ## @param ociCatalog.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe - ## @param ociCatalog.livenessProbe.failureThreshold Failure threshold for livenessProbe - ## @param ociCatalog.livenessProbe.successThreshold Success threshold for livenessProbe - ## OCI Catalog containers' liveness and readiness probes - ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes - ## - livenessProbe: - enabled: true - initialDelaySeconds: 60 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - ## @param ociCatalog.readinessProbe.enabled Enable readinessProbe - ## @param ociCatalog.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe - ## @param ociCatalog.readinessProbe.periodSeconds Period seconds for readinessProbe - ## @param ociCatalog.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe - ## @param ociCatalog.readinessProbe.failureThreshold Failure threshold for readinessProbe - ## @param ociCatalog.readinessProbe.successThreshold Success threshold for readinessProbe - ## - readinessProbe: - enabled: true - initialDelaySeconds: 0 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - ## @param ociCatalog.startupProbe.enabled Enable startupProbe - ## @param ociCatalog.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe - ## @param ociCatalog.startupProbe.periodSeconds Period seconds for startupProbe - ## @param ociCatalog.startupProbe.timeoutSeconds Timeout seconds for startupProbe - ## @param ociCatalog.startupProbe.failureThreshold Failure threshold for startupProbe - ## @param ociCatalog.startupProbe.successThreshold Success threshold for startupProbe - ## - startupProbe: - enabled: false - initialDelaySeconds: 0 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - ## @param ociCatalog.customLivenessProbe Custom livenessProbe that overrides the default one - ## - customLivenessProbe: {} - ## @param ociCatalog.customReadinessProbe Custom readinessProbe that overrides the default one - ## - customReadinessProbe: {} - ## @param ociCatalog.customStartupProbe Custom startupProbe that overrides the default one - ## - customStartupProbe: {} - ## @param ociCatalog.lifecycleHooks Custom lifecycle hooks for OCI Catalog containers - ## - lifecycleHooks: {} - ## @param ociCatalog.command Override default container command (useful when using custom images) - ## - command: [] - ## @param ociCatalog.args Override default container args (useful when using custom images) - ## - args: [] - ## @param ociCatalog.extraVolumes Optionally specify extra list of additional volumes for the OCI Catalog pod(s) - ## - extraVolumes: [] - ## @param ociCatalog.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the OCI Catalog container(s) - ## - extraVolumeMounts: [] -## @section Redis® chart configuration -## ref: https://github.com/bitnami/charts/blob/main/bitnami/redis/values.yaml -## -## Redis(R) will be enabled and installed if `packages.flux.enabled` is true. -redis: - ## @param redis.auth.enabled Enable password authentication - ## @param redis.auth.password Redis® password - ## @param redis.auth.existingSecret The name of an existing secret with Redis® credentials - ## - auth: - enabled: true - password: "" - existingSecret: "" - ## @param redis.architecture Redis(R) architecture (`standalone` or `replication`) - ## - architecture: standalone - master: - ## @param redis.master.extraFlags Array with additional command line flags for Redis® master - ## - extraFlags: - ## The maxmemory configuration directive is used in order to configure Redis(R) to use a specified - ## amount of memory for the data set. Setting maxmemory to zero results into no memory limits - ## see https://redis.io/topics/lru-cache for more details - ## - - "--maxmemory 200mb" - ## The exact behavior Redis(R) follows when the maxmemory limit is reached is configured using the - ## maxmemory-policy configuration directive - ## allkeys-lru: evict keys by trying to remove the less recently used (LRU) keys first, in order - ## to make space for the new data added - ## - - "--maxmemory-policy allkeys-lru" - ## ref https://stackoverflow.com/questions/22815364/flushall-and-flushdb-commands-on-redis-return-unk-command - ## Redis official Helm chart by default disables FLUSHDB and FLUSHALL commands - ## - ## @param redis.master.disableCommands Array with commands to deactivate on Redis® - disableCommands: [] - ## Redis(R) Master persistence configuration - # - persistence: - ## @param redis.master.persistence.enabled Enable Redis® master data persistence using PVC - ## - enabled: false - ## Redis® master resource requests and limits - ## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ - ## @param redis.master.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if master.resources is set (master.resources is recommended for production). - ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 - ## - resourcesPreset: "nano" - ## @param redis.master.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) - ## Example: - ## resources: - ## requests: - ## cpu: 2 - ## memory: 512Mi - ## limits: - ## cpu: 3 - ## memory: 1024Mi - ## - resources: {} - replica: - ## @param redis.replica.replicaCount Number of Redis® replicas to deploy - ## - replicaCount: 1 - ## @param redis.replica.extraFlags Array with additional command line flags for Redis® replicas - ## - extraFlags: - ## The maxmemory configuration directive is used in order to configure Redis(R) to use a specified - ## amount of memory for the data set. Setting maxmemory to zero results into no memory limits - ## - - "--maxmemory 200mb" - ## The exact behavior Redis(R) follows when the maxmemory limit is reached is configured using the - ## maxmemory-policy configuration directive - ## allkeys-lru: evict keys by trying to remove the less recently used (LRU) keys first, in order - ## to make space for the new data added - ## - - "--maxmemory-policy allkeys-lru" - ## ref https://stackoverflow.com/questions/22815364/flushall-and-flushdb-commands-on-redis-return-unk-command - ## Redis(R) official Helm chart by default disables FLUSHDB and FLUSHALL commands - ## @param redis.replica.disableCommands Array with commands to deactivate on Redis® - ## - disableCommands: [] - ## Redis(R) Replica persistence configuration - ## - persistence: - ## @param redis.replica.persistence.enabled Enable Redis® replica data persistence using PVC - ## - enabled: false diff --git a/packages/system/dashboard/images/dashboard.tag b/packages/system/dashboard/images/dashboard.tag deleted file mode 100644 index 6e88145f..00000000 --- a/packages/system/dashboard/images/dashboard.tag +++ /dev/null @@ -1 +0,0 @@ -ghcr.io/aenix-io/cozystack/dashboard:latest diff --git a/packages/system/dashboard/images/dashboard/Dockerfile b/packages/system/dashboard/images/dashboard/Dockerfile deleted file mode 100644 index 184428dc..00000000 --- a/packages/system/dashboard/images/dashboard/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -FROM bitnami/node:20.15.1 AS build -WORKDIR /app - -ARG COMMIT_REF=e1382f51c6db1bca0a8ecd454407c8e282fe0243 -RUN wget -O- https://github.com/cozystack/kubeapps/archive/${COMMIT_REF}.tar.gz | tar xzf - --strip-components=2 kubeapps-${COMMIT_REF}/dashboard - -RUN yarn install --frozen-lockfile - -RUN yarn run prettier-check && yarn run ts-compile-check -RUN yarn run build - -RUN sed -i \ - -e 's/#2d4048/#202124/g' \ - -e 's/#25333d/#1e2023/g' \ - -e 's/#fcfdfd/#f3f4f5/g' \ - -e 's/#f1f6f8/#e7e9eb/g' \ - -e 's/#e3eaed/#d3d6da/g' \ - -e 's/#cbd4d8/#b7bbc1/g' \ - -e 's/#aeb8bc/#989da3/g' \ - -e 's/#859399/#7b7f85/g' \ - -e 's/#6a7a81/#5b686e/g' \ - -e 's/#4f6169/#4f5256/g' \ - -e 's/#3a4d55/#3a3d41/g' \ - -e 's/#2d4048/#202124/g' \ - -e 's/#21333b/#383d44/g' \ - -e 's/#1b2b32/#2a2d2f/g' \ - $(grep -rl "#2d4048\|#25333d\|#fcfdfd\|#f1f6f8\|#e3eaed\|#cbd4d8\|#aeb8bc\|#859399\|#6a7a81\|#4f6169\|#3a4d55\|#2d4048\|#21333b\|#1b2b32") - -FROM bitnami/nginx:1.25.2 -COPY --from=build /app/build /app diff --git a/packages/system/dashboard/images/kubeapps-apis.tag b/packages/system/dashboard/images/kubeapps-apis.tag deleted file mode 100644 index b87bc749..00000000 --- a/packages/system/dashboard/images/kubeapps-apis.tag +++ /dev/null @@ -1 +0,0 @@ -ghcr.io/aenix-io/cozystack/kubeapps-apis:latest diff --git a/packages/system/dashboard/images/kubeapps-apis/Dockerfile b/packages/system/dashboard/images/kubeapps-apis/Dockerfile deleted file mode 100644 index 638219c8..00000000 --- a/packages/system/dashboard/images/kubeapps-apis/Dockerfile +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2021-2024 the Kubeapps contributors. -# SPDX-License-Identifier: Apache-2.0 - -# syntax = docker/dockerfile:1 - -FROM alpine AS source -ARG COMMIT_REF=e1382f51c6db1bca0a8ecd454407c8e282fe0243 -RUN apk add --no-cache patch -WORKDIR /source -RUN wget -O- https://github.com/cozystack/kubeapps/archive/${COMMIT_REF}.tar.gz | tar xzf - --strip-components=1 - -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 TARGETOS -ARG TARGETARCH -ARG VERSION="devel" - -# If true, run golangci-lint to detect issues -ARG lint - -# https://github.com/bufbuild/buf/releases/ -ARG BUF_VERSION="1.45.0" - -# https://github.com/golangci/golangci-lint/releases -ARG GOLANGCILINT_VERSION="1.61.0" - -# https://github.com/grpc-ecosystem/grpc-health-probe/releases/ -ARG GRPC_HEALTH_PROBE_VERSION="0.4.34" - -# Install lint tools -RUN if [ ! -z ${lint:-} ]; then \ - GOOS=$TARGETOS GOARCH=$TARGETARCH go install github.com/golangci/golangci-lint/cmd/golangci-lint@v$GOLANGCILINT_VERSION; \ - fi - -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" - -# With the trick below, Go's build cache is kept between builds. -# 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 \ - 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. -COPY --from=source /source/pkg pkg -COPY --from=source /source/cmd cmd - -RUN if [ ! -z ${lint:-} ]; then \ - # Run golangci-lint to detect issues - golangci-lint run --timeout=10m ./cmd/kubeapps-apis/... && \ - golangci-lint run --timeout=10m ./pkg/...; \ - fi - -# Lint the proto files to detect errors at build time -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 \ - 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 - -## Build 'fluxv2' plugin, version 'v1alpha1' -RUN --mount=type=cache,target=/go/pkg/mod \ - --mount=type=cache,target=/root/.cache/go-build \ - 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 \ - ./cmd/kubeapps-apis/plugins/fluxv2/packages/v1alpha1/*.go - -## Build 'helm' plugin, version 'v1alpha1' -RUN --mount=type=cache,target=/go/pkg/mod \ - --mount=type=cache,target=/root/.cache/go-build \ - 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 \ - ./cmd/kubeapps-apis/plugins/helm/packages/v1alpha1/*.go - -## Build 'resources' plugin, version 'v1alpha1' -RUN --mount=type=cache,target=/go/pkg/mod \ - --mount=type=cache,target=/root/.cache/go-build \ - 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 \ - ./cmd/kubeapps-apis/plugins/resources/v1alpha1/*.go - -# Note: unlike the other docker images for go, we cannot use scratch as the plugins -# are loaded using the dynamic linker. -FROM bitnami/minideb:bookworm -COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ -COPY --from=builder /go/src/github.com/vmware-tanzu/kubeapps/kubeapps-apis /kubeapps-apis -COPY --from=builder /fluxv2-packages-v1alpha1-plugin.so /plugins/fluxv2-packages/ -COPY --from=builder /helm-packages-v1alpha1-plugin.so /plugins/helm-packages/ -COPY --from=builder /resources-v1alpha1-plugin.so /plugins/resources/ -COPY --from=builder /bin/grpc_health_probe /bin/ - -# Ensure the container user will be able to write to the k8s discovery client cache. -RUN mkdir -p /.kube/cache && chown 1001:1001 /.kube/cache - -EXPOSE 50051 -USER 1001 -ENTRYPOINT [ "/kubeapps-apis" ] -CMD [ "--help" ] diff --git a/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile b/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile new file mode 100644 index 00000000..ea0c900d --- /dev/null +++ b/packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile @@ -0,0 +1,22 @@ +# imported from https://github.com/PRO-Robotech/openapi-ui-k8s-bff +ARG NODE_VERSION=20.18.1 +FROM node:${NODE_VERSION}-alpine AS builder +WORKDIR /src + +# release/1.4.0 +ARG COMMIT_REF=92e4b618eb9ad17b19827b5a2b7ceab33e8cf534 +RUN wget -O- https://github.com/PRO-Robotech/openapi-ui-k8s-bff/archive/${COMMIT_REF}.tar.gz | tar xzf - --strip-components=1 + +ENV PATH=/src/node_modules/.bin:$PATH +RUN npm install +RUN npm run build + +FROM node:${NODE_VERSION}-alpine +WORKDIR /app +COPY --from=builder /src/package*.json /app/ +COPY --from=builder /src/node_modules /app/node_modules +COPY --from=builder /src/src/swagger/swagger-output.json /app/dist/swagger/swagger-output.json +COPY --from=builder /src/dist /app/dist +EXPOSE 8080 +USER 1001 +CMD [ "node", "/app/dist/index.js"] diff --git a/packages/system/dashboard/images/openapi-ui/Dockerfile b/packages/system/dashboard/images/openapi-ui/Dockerfile new file mode 100644 index 00000000..82cc6db0 --- /dev/null +++ b/packages/system/dashboard/images/openapi-ui/Dockerfile @@ -0,0 +1,69 @@ +ARG NODE_VERSION=20.18.1 + +# openapi-k8s-toolkit +# imported from https://github.com/PRO-Robotech/openapi-k8s-toolkit +FROM node:${NODE_VERSION}-alpine AS openapi-k8s-toolkit-builder +RUN apk add git +WORKDIR /src +# release/1.4.0 +ARG COMMIT=d6b9e4ad0d1eb9d3730f7f0c664792c8dda3214d +RUN wget -O- https://github.com/PRO-Robotech/openapi-k8s-toolkit/archive/${COMMIT}.tar.gz | tar -xzvf- --strip-components=1 + +COPY openapi-k8s-toolkit/patches /patches +RUN git apply /patches/*.diff + +RUN npm install +RUN npm install --build-from-source @swc/core +RUN npm run build + + +# openapi-ui +# imported from https://github.com/PRO-Robotech/openapi-ui +FROM node:${NODE_VERSION}-alpine AS builder +#RUN apk add git +WORKDIR /src + +# release/1.4.0 +ARG COMMIT_REF=6addca6939264ef2e39801baa88c1460cc1aa53e +RUN wget -O- https://github.com/PRO-Robotech/openapi-ui/archive/${COMMIT_REF}.tar.gz | tar xzf - --strip-components=1 + +#COPY openapi-ui/patches /patches +#RUN git apply /patches/*.diff + +ENV PATH=/src/node_modules/.bin:$PATH + +RUN npm install + +# add patched openapi-k8s-toolkit +RUN rm -rf node_modules/@prorobotech/openapi-k8s-toolkit/dist +COPY --from=openapi-k8s-toolkit-builder /src/dist node_modules/@prorobotech/openapi-k8s-toolkit/dist + +RUN npm run build + +FROM node:${NODE_VERSION}-alpine AS builder2 +WORKDIR /src +ENV PATH=/src/node_modules/.bin:$PATH + +COPY --from=builder /src/server/package.json ./ +COPY --from=builder /src/server/package-lock.json ./ +RUN npm install +COPY --from=builder /src/server server +COPY --from=builder /src/tsconfig.server.json ./ +COPY --from=builder /src/build /src/build +RUN npm run server:build + +FROM node:${NODE_VERSION}-alpine +WORKDIR /app +COPY --from=builder2 /src/node_modules /app/node_modules +COPY --from=builder2 /src/build /app/build +EXPOSE 8080 +RUN sed -i -e 's|OpenAPI UI|Cozystack|g' build/index.html +# Fix Factory component: return null while loading instead of showing "Factory Not Found" 404 +RUN APP_JS=$(find build -name "App-react.js" -type f | head -1) && \ + if [ -n "$APP_JS" ]; then \ + sed -i 's|const { data: factoryData } = useK8sSmartResource({|const { data: factoryData, isLoading: factoryIsLoading } = useK8sSmartResource({|' "$APP_JS" && \ + sed -i '/Factory Not Found/s/return /return factoryIsLoading ? null : /' "$APP_JS" && \ + echo "Factory loading patch applied to $APP_JS"; \ + fi +USER 1001 +CMD ["node", "/app/build/index.js"] diff --git a/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/flatmap-unresolved-placeholder.diff b/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/flatmap-unresolved-placeholder.diff new file mode 100644 index 00000000..e98861a3 --- /dev/null +++ b/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/flatmap-unresolved-placeholder.diff @@ -0,0 +1,17 @@ +diff --git a/src/components/molecules/EnrichedTable/organisms/EnrichedTableProvider/utils.ts b/src/components/molecules/EnrichedTable/organisms/EnrichedTableProvider/utils.ts +--- a/src/components/molecules/EnrichedTable/organisms/EnrichedTableProvider/utils.ts ++++ b/src/components/molecules/EnrichedTable/organisms/EnrichedTableProvider/utils.ts +@@ -185,6 +185,11 @@ + return `['${escaped}']` + }) + } +- const jpQueryResult = jp.query(el, `$${resolvedJsonPath}`) +- fieldValue = Array.isArray(jpQueryResult) && jpQueryResult.length === 1 ? jpQueryResult[0] : jpQueryResult ++ if (/_flatMap[^\]]+_Key/.test(resolvedJsonPath)) { ++ // Placeholder was not resolved (row not yet expanded or key missing) — skip query ++ fieldValue = null ++ } else { ++ const jpQueryResult = jp.query(el, `$${resolvedJsonPath}`) ++ fieldValue = Array.isArray(jpQueryResult) && jpQueryResult.length === 1 ? jpQueryResult[0] : jpQueryResult ++ } + } diff --git a/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/formlistinput-allow-empty.diff b/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/formlistinput-allow-empty.diff new file mode 100644 index 00000000..1c83df7c --- /dev/null +++ b/packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/formlistinput-allow-empty.diff @@ -0,0 +1,37 @@ +diff --git a/src/localTypes/formExtensions.ts b/src/localTypes/formExtensions.ts +--- a/src/localTypes/formExtensions.ts ++++ b/src/localTypes/formExtensions.ts +@@ -59,2 +59,4 @@ + relatedValuePath?: string ++ allowEmpty?: boolean ++ persistType?: 'str' | 'number' | 'arr' | 'obj' + } +diff --git a/src/components/molecules/BlackholeForm/molecules/FormListInput/FormListInput.tsx b/src/components/molecules/BlackholeForm/molecules/FormListInput/FormListInput.tsx +--- a/src/components/molecules/BlackholeForm/molecules/FormListInput/FormListInput.tsx ++++ b/src/components/molecules/BlackholeForm/molecules/FormListInput/FormListInput.tsx +@@ -149,3 +149,10 @@ + }, [relatedPath, form, arrName, fixedName, relatedFieldValue, onValuesChangeCallBack, isTouchedPeristed]) + ++ // When allowEmpty is set, auto-persist the field so the BFF preserves empty values ++ useEffect(() => { ++ if (customProps.allowEmpty) { ++ persistedControls.onPersistMark(persistName || name, customProps.persistType ?? 'str') ++ } ++ }, [customProps.allowEmpty, customProps.persistType, persistedControls, persistName, name]) ++ + const uri = prepareTemplate({ +@@ -267,5 +274,14 @@ + validateTrigger="onBlur" + hasFeedback={designNewLayout ? { icons: feedbackIcons } : true} + style={{ flex: 1 }} ++ normalize={(value: unknown) => { ++ if (customProps.allowEmpty && (value === undefined || value === null)) { ++ if (customProps.persistType === 'number') return 0 ++ if (customProps.persistType === 'arr') return [] ++ if (customProps.persistType === 'obj') return {} ++ return '' ++ } ++ return value ++ }} + > + + + + + +`)) + +/* ----------------------------- JWK cache -------------------------------- */ + +var ( + jwkCache *jwk.Cache +) + +// saTokenTransport adds the service account token to requests and refreshes it periodically. +type saTokenTransport struct { + base http.RoundTripper + tokenPath string + mu sync.RWMutex + token string +} + +func (t *saTokenTransport) RoundTrip(req *http.Request) (*http.Response, error) { + t.mu.RLock() + token := t.token + t.mu.RUnlock() + + if token != "" { + req = req.Clone(req.Context()) + req.Header.Set("Authorization", "Bearer "+token) + } + return t.base.RoundTrip(req) +} + +func (t *saTokenTransport) refreshToken() { + data, err := os.ReadFile(t.tokenPath) + if err != nil { + log.Printf("warning: failed to read SA token: %v", err) + return + } + t.mu.Lock() + t.token = string(data) + t.mu.Unlock() +} + +func (t *saTokenTransport) startRefresh(ctx context.Context, interval time.Duration) { + t.refreshToken() + go func() { + ticker := time.NewTicker(interval) + defer ticker.Stop() + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + t.refreshToken() + } + } + }() +} + +/* ----------------------------- helpers ---------------------------------- */ + +// verifyAndParseJWT verifies the token signature and returns the parsed token. +func verifyAndParseJWT(ctx context.Context, raw string) (jwt.Token, error) { + if raw == "" { + return nil, fmt.Errorf("empty token") + } + + keySet, err := jwkCache.Lookup(ctx, jwksURL) + if err != nil { + return nil, fmt.Errorf("failed to get JWKS: %w", err) + } + + token, err := jwt.Parse([]byte(raw), jwt.WithKeySet(keySet)) + if err != nil { + return nil, fmt.Errorf("failed to verify token: %w", err) + } + + return token, nil +} + +// getClaim extracts a claim value from a verified token. +func getClaim(token jwt.Token, key string) any { + if token == nil { + return nil + } + var val any + if err := token.Get(key, &val); err != nil { + return nil + } + return val +} + +func encodeSession(sc *securecookie.SecureCookie, token string, exp, issued int64) (string, error) { + v := map[string]any{ + "access_token": token, + "expires": exp, + "issued": issued, + } + if sc != nil { + return sc.Encode(cookieName, v) + } + return token, nil +} + +/* ----------------------------- main ------------------------------------- */ + +func main() { + if upstream == "" { + log.Fatal("--upstream is required") + } + upURL, err := url.Parse(upstream) + if err != nil { + log.Fatalf("invalid upstream url: %v", err) + } + + if cookieSecretB64 == "" { + cookieSecretB64 = os.Getenv("COOKIE_SECRET") + } + var sc *securecookie.SecureCookie + if cookieSecretB64 != "" { + secret, err := base64.StdEncoding.DecodeString(cookieSecretB64) + if err != nil { + log.Fatalf("cookie-secret: %v", err) + } + sc = securecookie.New(secret, nil) + } else { + log.Println("warning: no cookie-secret provided, cookies will be stored unsigned") + } + + // control paths + signIn := path.Join(proxyPrefix, "sign_in") + signOut := path.Join(proxyPrefix, "sign_out") + userInfo := path.Join(proxyPrefix, "userinfo") + + proxy := httputil.NewSingleHostReverseProxy(upURL) + + /* ------------------------- /sign_in ---------------------------------- */ + + http.HandleFunc(signIn, func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + _ = loginTmpl.Execute(w, struct { + Action string + Err string + }{Action: signIn}) + case http.MethodPost: + token := strings.TrimSpace(r.FormValue("token")) + if token == "" { + _ = loginTmpl.Execute(w, struct { + Action string + Err string + }{Action: signIn, Err: "Token required"}) + return + } + + // Verify token signature using JWKS + verifiedToken, err := verifyAndParseJWT(r.Context(), token) + if err != nil { + log.Printf("token verification failed: %v", err) + _ = loginTmpl.Execute(w, struct { + Action string + Err string + }{Action: signIn, Err: "Invalid token"}) + return + } + + exp := time.Now().Add(24 * time.Hour).Unix() + if expTime, ok := verifiedToken.Expiration(); ok && !expTime.IsZero() { + exp = expTime.Unix() + } + session, _ := encodeSession(sc, token, exp, time.Now().Unix()) + http.SetCookie(w, &http.Cookie{ + Name: cookieName, + Value: session, + Path: "/", + Expires: time.Unix(exp, 0), + Secure: cookieSecure, + HttpOnly: true, + SameSite: http.SameSiteLaxMode, + }) + http.Redirect(w, r, "/", http.StatusSeeOther) + } + }) + + /* ------------------------- /sign_out --------------------------------- */ + + http.HandleFunc(signOut, func(w http.ResponseWriter, r *http.Request) { + http.SetCookie(w, &http.Cookie{ + Name: cookieName, + Value: "", + Path: "/", + MaxAge: -1, + Secure: cookieSecure, + HttpOnly: true, + }) + http.Redirect(w, r, signIn, http.StatusSeeOther) + }) + + /* ------------------------- /userinfo --------------------------------- */ + + http.HandleFunc(userInfo, func(w http.ResponseWriter, r *http.Request) { + c, err := r.Cookie(cookieName) + if err != nil { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + var token string + var sess map[string]any + if sc != nil { + if err := sc.Decode(cookieName, c.Value, &sess); err != nil { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + token, _ = sess["access_token"].(string) + } else { + token = c.Value + sess = map[string]any{ + "expires": time.Now().Add(24 * time.Hour).Unix(), + "issued": time.Now().Unix(), + } + } + + // Re-verify the token to ensure it's still valid + verifiedToken, err := verifyAndParseJWT(r.Context(), token) + if err != nil { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + out := map[string]any{ + "token": token, + "sub": getClaim(verifiedToken, "sub"), + "email": getClaim(verifiedToken, "email"), + "preferred_username": getClaim(verifiedToken, "preferred_username"), + "groups": getClaim(verifiedToken, "groups"), + "expires": sess["expires"], + "issued": sess["issued"], + "cookie_refresh_enable": cookieRefresh > 0, + } + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(out) + }) + + /* ----------------------------- proxy --------------------------------- */ + + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + c, err := r.Cookie(cookieName) + if err != nil { + http.Redirect(w, r, signIn, http.StatusFound) + return + } + var token string + var sess map[string]any + if sc != nil { + if err := sc.Decode(cookieName, c.Value, &sess); err != nil { + http.Redirect(w, r, signIn, http.StatusFound) + return + } + token, _ = sess["access_token"].(string) + } else { + token = c.Value + sess = map[string]any{ + "expires": time.Now().Add(24 * time.Hour).Unix(), + "issued": time.Now().Unix(), + } + } + if token == "" { + http.Redirect(w, r, signIn, http.StatusFound) + return + } + + // cookie refresh + if cookieRefresh > 0 { + if issued, ok := sess["issued"].(float64); ok { + if time.Since(time.Unix(int64(issued), 0)) > cookieRefresh { + enc, _ := encodeSession(sc, token, int64(sess["expires"].(float64)), time.Now().Unix()) + http.SetCookie(w, &http.Cookie{ + Name: cookieName, + Value: enc, + Path: "/", + Expires: time.Unix(int64(sess["expires"].(float64)), 0), + Secure: cookieSecure, + HttpOnly: true, + SameSite: http.SameSiteLaxMode, + }) + } + } + } + + r.Header.Set("Authorization", "Bearer "+token) + proxy.ServeHTTP(w, r) + }) + + log.Printf("Listening on %s → %s (control prefix %s)", httpAddr, upURL, proxyPrefix) + if err := http.ListenAndServe(httpAddr, nil); err != nil { + log.Fatal(err) + } +} diff --git a/packages/system/dashboard/patches/logos.patch b/packages/system/dashboard/patches/logos.patch deleted file mode 100644 index 477c3770..00000000 --- a/packages/system/dashboard/patches/logos.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/packages/system/dashboard/charts/kubeapps/templates/frontend/configmap.yaml b/packages/system/dashboard/charts/kubeapps/templates/frontend/configmap.yaml -index d43f521..31ff7d5 100644 ---- a/packages/system/dashboard/charts/kubeapps/templates/frontend/configmap.yaml -+++ b/packages/system/dashboard/charts/kubeapps/templates/frontend/configmap.yaml -@@ -136,4 +136,10 @@ data: - proxy_pass {{ printf "http://%s:%d" (include "kubeapps.dashboard.fullname" .) (int .Values.dashboard.service.ports.http) }}; - } - {{- end }} -+ -+ location /logos { -+ # Add the Authorization header if exists -+ proxy_set_header Cookie ""; -+ proxy_pass http://cozystack.cozy-system.svc:80; -+ } - } diff --git a/packages/system/dashboard/templates/allow-from-kubeapps.yaml b/packages/system/dashboard/templates/allow-from-kubeapps.yaml deleted file mode 100644 index c8850d88..00000000 --- a/packages/system/dashboard/templates/allow-from-kubeapps.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: allow-from-dashboard - namespace: cozy-fluxcd -spec: - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: cozy-dashboard - podSelector: {} - policyTypes: - - Ingress diff --git a/packages/system/dashboard/templates/clusterrolebinding-cluster-view.yaml b/packages/system/dashboard/templates/clusterrolebinding-cluster-view.yaml new file mode 100644 index 00000000..43d20f57 --- /dev/null +++ b/packages/system/dashboard/templates/clusterrolebinding-cluster-view.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: incloud-web-cluster-view +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: view +subjects: + - kind: ServiceAccount + name: incloud-web-web + namespace: incloud-web diff --git a/packages/system/dashboard/templates/clusterrolebinding-web-user-edit.yaml b/packages/system/dashboard/templates/clusterrolebinding-web-user-edit.yaml new file mode 100644 index 00000000..4d951787 --- /dev/null +++ b/packages/system/dashboard/templates/clusterrolebinding-web-user-edit.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + annotations: {} + name: incloud-web-web-user-edit +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: edit +subjects: + - apiGroup: rbac.authorization.k8s.io + kind: Group + name: cozystack-cluster-admin diff --git a/packages/system/dashboard/templates/configmap.yaml b/packages/system/dashboard/templates/configmap.yaml new file mode 100644 index 00000000..a2b7684c --- /dev/null +++ b/packages/system/dashboard/templates/configmap.yaml @@ -0,0 +1,24 @@ +{{- $brandingConfig := .Values._cluster.branding | default dict }} + +{{- $tenantText := "v1.3.0" }} +{{- $footerText := "Cozystack" }} +{{- $titleText := "Cozystack Dashboard" }} +{{- $logoText := "" }} +{{- $logoSvg := "PHN2ZyB3aWR0aD0iMTUwIiBoZWlnaHQ9IjMwIiB2aWV3Qm94PSIwIDAgMTUwIDMwIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxwYXRoIGQ9Ik0xMzMuMzMxMDkgMjIuMzczOTg3VjQuNzk1Mjc2OWgyLjA0NDUyVjEyLjc3Mzg5aC4wNDk5bDguNTI3NzEtNy45NzkxNjcyaDIuNjE4MjdsLTkuNzc0NjQgOS4xMDExNTgyLjAyNDktMS4wOTcwNTkgMTAuMjk4MjQgOS41NzQ4ODloLTIuNjkyNzlsLTkuMDAxNjktOC4yNzgzNjNoLS4wNDk5djguMjc4MzYzem0tOS4xNzIzNi4yMjQzOTljLTEuNzI4NjkuMC0zLjIwODA1LS4zNjU2ODYtNC40MzgxLTEuMDk3MDU5LTEuMjMwNTktLjczMTM3My0yLjE3ODA0LTEuNzcwMjU0LTIuODQyOTMtMy4xMTY2NDUtLjY0ODI3LTEuMzQ2NjY3LS45NzIzOS0yLjk1MDk3OC0uOTcyMzktNC44MTI2NTQuMC0xLjg2MTY3Ny4zMjQxMi0zLjQ1NzM5OS45NzIzOS00Ljc4NzQ0NS42NjQ4OS0xLjM0NjM5MDYgMS42MTIzNC0yLjM4NTI3MjUgMi44NDI2Ni0zLjExNjkyMjQgMS4yMzAwMy0uNzMxMzcyOSAyLjcwOTQxLTEuMDk3MDU5MiA0LjQzODM3LTEuMDk3MDU5MiAxLjIxMzQyLjAgMi4zMzU0MS4xOTExNTQzIDMuMzY2MjYuNTczNDYyOCAxLjAzMDU3LjM4MjMwODUgMS44OTQ5My45MzkxNDkxIDIuNTkzMDUgMS42NzA1MjE5bC0uNzk3ODYgMS42NzA1MjE5Yy0uNzY0NjItLjcxNDc1LTEuNTYyNDgtMS4yMzAwMzYtMi4zOTM1OS0xLjU0NTg1NjEtLjgxNDQ3LS4zMzI0NDIxLTEuNzIwMzgtLjQ5ODY2MzItMi43MTc3MS0uNDk4NjYzMi0xLjk3ODU5LjAtMy40OTEyLjYyMzMyOS00LjUzODM4IDEuODY5OTg4My0xLjA0NzIxIDEuMjQ2NjU3LTEuNTcwOCAzLjAwMDU2Ni0xLjU3MDggNS4yNjE0NTEuMCAyLjI2MDYwNi41MjM1OSA0LjAyMjU0OSAxLjU3MDggNS4yODYxMDggMS4wNDcxOCAxLjI0NjY1NyAyLjU1OTc5IDEuODY5OTg2IDQuNTM4MDkgMS44Njk5ODYuOTk3MzQuMCAxLjkwMzI0LS4xNTc5MDkgMi43MTc3My0uNDczNzMuODMxMzgtLjMzMjQ0MiAxLjYyOTI0LS44NTYwMzggMi4zOTM4Ni0xLjU3MDc4OWwuNzk3ODYgMS42NzA1MjJjLS42OTgxMi43MTQ3NTEtMS41NjI0OCAxLjI3MTg2OS0yLjU5MzA1IDEuNjcwNzk5LTEuMDMwNTguMzgyMzA5LTIuMTUyNTcuNTczNDYyLTMuMzY1OTcuNTczNDYyek05Ni45ODQ2MzEgMjIuMzczOTg3IDEwNC43Mzk0IDQuNzk0OTk5OWgxLjc0NTMzbDcuNzU0NzYgMTcuNTc4OTg3MWgtMi4xMTkzMmwtMi4xNjkxOS01LjAxMTg0MS45OTczMy41MjM1OTVoLTEwLjcyMjA5bDEuMDIyMjctLjUyMzU5NS0yLjE0NDI1NCA1LjAxMTg0MXptOC42MDI0OTktMTUuMTg1NDAzNC00LjAxNDI0IDkuNDUwNTAwNC0uNTk4NC0uNDczNzNoOS4yMjU1NWwtLjU0ODUzLjQ3MzczLTQuMDE0MjUtOS40NTA1MDA0ek04OS44OTM5MjEgMjIuMzczOTg3VjYuNTY1NTMxNkg4My41MTAyMDJWNC43OTUyNzY5aDE0LjgzNjMzVjYuNTY1NTMxNkg5MS45NjMzNjZWMjIuMzc0MjY1eiIgZmlsbD17dG9rZW4uY29sb3JUZXh0fT48L3BhdGg+CiAgPHBhdGggZD0ibTY3Ljg1NDM4NSA0Ljc3MzExNDJoMTQuMDgwODd2MS43NjAwMDQyaC0xNC4wODA4N3ptMCAxNS44NDA4Njk4aDE0LjA4MDg3djEuNzYwMDAzaC0xNC4wODA4N3ptMTQuMDgwODctNy45MjA0MzVoLTE0LjA4MDg3djEuNzYwMDA1aDE0LjA4MDg3eiIgZmlsbD17dG9rZW4uY29sb3JUZXh0fT48L3BhdGg+CiAgPHBhdGggZD0ibTU3LjY2NDQ3MyAyMi4zNzM5ODd2LTkuMTAxMTU4bC40NDg4MDQgMS40MjExOTEtNy4xODEzMDktOS44OTkwMjAxaDIuMzkzODYxbDUuNjYwMTA5IDcuODI5NTY3MWgtLjUyMzYwNmw1LjY2MDM5MS03LjgyOTU2NzFoMi4zMTg3ODdsLTcuMTU2MzczIDkuODk4NzQyMS40MjQxNC0xLjQyMTE4OXY5LjEwMTE1OHptLTIwLjE4ODEwMi4wVjIwLjg1MzA2NUw0OC4xNDg1OTYgNS43NjczOTMydi43OTc4NjEzSDM3LjQ3NjM3MVY0Ljc5NDk5OTlINTAuMDY4NDVWNi4zMTU5MjI4TDM5LjM5NjUwMSAyMS4zNzY2NjF2LS43NzI5MjdoMTEuMDIxMjl2MS43NzAyNTN6bS0xMC4zOTYyOTguMjI0Mzk5Yy0xLjIxMzQxNC4wLTIuMzE5MDYyLS4yMDc3NzYtMy4zMTYzODktLjYyMzMyOC0uOTk3MzI3LS40MzIxNzUtMS44NDUwNTUtMS4wMzg4ODItMi41NDMxODQtMS44MjAxMjEtLjY5ODQwNi0uNzgxMjM5LTEuMjM4NjI0LTEuNzI4Ny0xLjYyMDkzMy0yLjg0MjY1OC0uMzY1Njg2LTEuMTEzNjgyLS41NDg1MjktMi4zNjAzMzktLjU0ODUyOS0zLjc0MDI1MS4wLTEuMzk2MjU3LjE4Mjg0My0yLjY0MjkxNy41NDg1MjktMy43NDAyNTIuMzgyMzA5LTEuMTEzNjgyLjkyMjUyNy0yLjA1MjgzMDkgMS42MjA2NTYtMi44MTc0NDc1LjY5ODEyOS0uNzgxMjM5MiAxLjUzNzU0NS0xLjM3OTkxMjEgMi41MTgyNS0xLjc5NTQ2NDguOTk3NjA0LS40MzIxNzQ5IDIuMTExMjg3LS42NDgyNjIzIDMuMzQxNi0uNjQ4MjYyMyAxLjI0NjY1Ny4wIDIuMzYwMzM5LjIwNzc3NjMgMy4zNDEwNDQuNjIzMzI5MS45OTczMjcuNDE1NTUyNyAxLjg0NTA1NSAxLjAxMzk0ODYgMi41NDM0NTkgMS43OTUxODc3LjcxNDc1MS43ODEyMzk4IDEuMjU0OTY5IDEuNzI4Njk5OCAxLjYyMDY1NSAyLjg0MjY1NzguMzgyMzEgMS4wOTcwNTkuNTczNDY0IDIuMzM1NDA2LjU3MzQ2NCAzLjcxNTA0Mi4wIDEuMzk2NTMzLS4xOTExNTQgMi42NTE3NzktLjU3MzQ2NCAzLjc2NTQ2MS0uMzgyMzA4IDEuMTEzNjgyLS45MjI1MjYgMi4wNjExNDItMS42MjA2NTUgMi44NDIzODFzLTEuNTQ1ODU2IDEuMzg3OTQ2LTIuNTQzMTgzIDEuODIwMzk4Yy0uOTgwNzA0LjQxNTU1Mi0yLjA5NDY2My42MjMzMjgtMy4zNDEzMi42MjMzMjh6bTAtMS44MjAxMmMxLjI2MzI3OS4wIDIuMzI3MDk0LS4yODI1NzYgMy4xOTE0NDMtLjg0NzcyOC44ODA5NzMtLjU2NTE1MiAxLjU1NDE2OS0xLjM4Nzk0NiAyLjAxOTU4OC0yLjQ2ODY2LjQ2NTY5Ni0xLjA4MDQzNy42OTg0MDYtMi4zNzY5NjEuNjk4NDA2LTMuODg5ODUuMC0xLjUyOTIzNC0uMjMyNzEtMi44MjU3NTgtLjY5ODEyOS0zLjg4OTg1MS0uNDY1NDE5LTEuMDYzODE1LTEuMTM4NjE0LTEuODc4Mjk3OC0yLjAxOTU4Ny0yLjQ0MzQ1LS44NjQzNS0uNTY1MTUxOC0xLjkyODQ0Mi0uODQ3NzI3Ni0zLjE5MTcyMS0uODQ3NzI3Ni0xLjIzMDAzOC4wLTIuMjg1ODE4LjI4MjU3NTgtMy4xNjY3OTEuODQ3NzI3Ni0uODY0MzUuNTY1MTUyMi0xLjUyOTIzNCAxLjM4Nzk0Ni0xLjk5NDY1MyAyLjQ2ODM4My0uNDY1NDE5IDEuMDYzODE1LS42OTgxMjkgMi4zNTIwMjktLjY5ODEyOSAzLjg2NDY0MS4wIDEuNTEyODg5LjIzMjcxIDIuODA5NjkuNjk4MTI5IDMuODkwMTI3LjQ2NTQxOSAxLjA2MzgxNSAxLjEzMDMwMyAxLjg4NjYwOSAxLjk5NDY1MyAyLjQ2ODM4My44ODA5NzMuNTY1MTUxIDEuOTM2NDc4Ljg0NzcyNyAzLjE2NjUxMy44NDc3Mjd6bS0xNi4wNDE3MjQgMS44MjAxMmMtMS43Mjg2OTgxLjAtMy4yMDgzNDE3LS4zNjU2ODYtNC40Mzg2NTYxLTEuMDk3MDU5QzUuMzY5NjU3MSAyMC43Njk5NTQgNC40MjIxOTY2IDE5LjczMTA3MyAzLjc1NzMxMzEgMTguMzg0NjgyYy0uNjQ4MjYzLTEuMzQ2NjY3LS45NzIzOTM2LTIuOTUwOTc4LS45NzIzOTM2LTQuODEyNjU0LjAtMS44NjE2NzcuMzI0MTMwNi0zLjQ1NzM5OS45NzIzOTM2LTQuNzg3NDQ1LjY2NDg4MzUtMS4zNDYzOTA2IDEuNjEyMzQ0LTIuMzg1MjcyNSAyLjg0MjM3OTgtMy4xMTY5MjI0QzcuODI5NzI5OCA0LjkzNjI4NzcgOS4zMDkzNzM0IDQuNTcwNjAxNCAxMS4wMzgzNDkgNC41NzA2MDE0YzEuMjEzNDE0LjAgMi4zMzU0MDguMTkxMTU0MyAzLjM2NTk3OC41NzM0NjI4IDEuMDMwNTcyLjM4MjMwODUgMS44OTQ5MjIuOTM5MTQ5MSAyLjU5MzMyNiAxLjY3MDUyMTlMMTYuMTk5NzkxIDguNDg1MTA4QzE1LjQzNTE3NSA3Ljc3MDM1OCAxNC42MzczMTMgNy4yNTUwNzIgMTMuODA2MjA5IDYuOTM5MjUxOSAxMi45OTE0NDcgNi42MDY4MDk4IDEyLjA4NTU0MyA2LjQ0MDU4ODcgMTEuMDg4MjE2IDYuNDQwNTg4N2MtMS45NzgwMzA0LjAtMy40OTA5MTg4LjYyMzMyOS00LjUzODM4OTIgMS44Njk5ODgzLTEuMDQ3MTkyNyAxLjI0NjY1Ny0xLjU3MDc4ODYgMy4wMDA1NjYtMS41NzA3ODg2IDUuMjYxNDUxLjAgMi4yNjA2MDYuNTIzNTk1OSA0LjAyMjU0OSAxLjU3MDc4ODYgNS4yODYxMDggMS4wNDcxOTI5IDEuMjQ2NjU3IDIuNTYwMDgyMyAxLjg2OTk4NiA0LjUzODM4OTIgMS44Njk5ODYuOTk3MzI3LjAgMS45MDMyMzEtLjE1NzkwOSAyLjcxNzcxNS0uNDczNzMuODMxMTA2LS4zMzI0NDIgMS42Mjg5NjgtLjg1NjAzOCAyLjM5MzU4NC0xLjU3MDc4OWwuNzk4MTM4IDEuNjcwNTIyYy0uNjk4MTI4LjcxNDc1MS0xLjU2MjQ3OCAxLjI3MTg2OS0yLjU5MzA0OCAxLjY3MDc5OS0xLjAzMDU3Mi4zODIzMDktMi4xNTI4NDIuNTczNDYyLTMuMzY2MjU2LjU3MzQ2MnoiIGZpbGw9e3Rva2VuLmNvbG9yVGV4dH0+PC9wYXRoPgo8L3N2Zz4K" }} +{{- $iconSvg := "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgd2lkdGg9IjkxIgogICBoZWlnaHQ9IjkxIgogICB2aWV3Qm94PSIwIDAgNjguMjUwMDI0IDY4LjI1MDAyNCIKICAgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgbWVldCIKICAgdmVyc2lvbj0iMS4xIgogICBpZD0ic3ZnODI2IgogICBzb2RpcG9kaTpkb2NuYW1lPSJmYXZpY29uLnN2ZyIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMS4xLjEgKGMzMDg0ZWYsIDIwMjEtMDktMjIpIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxkZWZzCiAgICAgaWQ9ImRlZnM4MzAiIC8+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJuYW1lZHZpZXc4MjgiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZWNoZWNrZXJib2FyZD0iMCIKICAgICBzaG93Z3JpZD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6em9vbT0iMC43NzAzNTc0MSIKICAgICBpbmtzY2FwZTpjeD0iNDM2LjgxMDIzIgogICAgIGlua3NjYXBlOmN5PSI1NDEuOTU2MjMiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxNzIwIgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzODciCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjE3MjAiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjI1IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjAiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnODI2IiAvPgogIDxyZWN0CiAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC42MTc5MDUiCiAgICAgaWQ9InJlY3Q5MzgiCiAgICAgd2lkdGg9IjY4LjI1MDAyMyIKICAgICBoZWlnaHQ9IjY4LjI1MDAyMyIKICAgICB4PSIwIgogICAgIHk9Ii0xLjc3NjM1NjhlLTE1IiAvPgogIDxwYXRoCiAgICAgZmlsbC1ydWxlPSJldmVub2RkIgogICAgIGNsaXAtcnVsZT0iZXZlbm9kZCIKICAgICBkPSJtIDE2LjYwMTU5OCwxMy45MjY5MSBjIDAsLTEuMjgwMTE1IDEuMDE1MDUxLC0yLjMxNzg2MSAyLjI2NzQyNCwtMi4zMTc4NjEgaCAzMS43NDM5MzcgYyAxLjI1MjM3OCwwIDIuMjY3NDIsMS4wMzc3NDYgMi4yNjc0MiwyLjMxNzg2MSB2IDAgYyAwLDEuMjgwMTMzIC0xLjAxNTA0MiwyLjMxNzg3IC0yLjI2NzQyLDIuMzE3ODcgSCAxOC44NjkwMjIgYyAtMS4yNTIzNzMsMCAtMi4yNjc0MjQsLTEuMDM3NzM3IC0yLjI2NzQyNCwtMi4zMTc4NyB6IG0gMCw0MS43MjE1NzIgYyAwLC0xLjI4MDA4MSAxLjAxNTA1MSwtMi4zMTc4NjUgMi4yNjc0MjQsLTIuMzE3ODY1IGggMzEuNzQzOTM3IGMgMS4yNTIzNzgsMCAyLjI2NzQyLDEuMDM3Nzg0IDIuMjY3NDIsMi4zMTc4NjUgdiAwIGMgMCwxLjI4MDE1OCAtMS4wMTUwNDIsMi4zMTc4NjYgLTIuMjY3NDIsMi4zMTc4NjYgSCAxOC44NjkwMjIgYyAtMS4yNTIzNzMsMCAtMi4yNjc0MjQsLTEuMDM3NzA4IC0yLjI2NzQyNCwtMi4zMTc4NjYgeiBtIDM2LjI3ODc4MSwtMjAuODYwOCBjIDAsLTEuMjgwMDggLTEuMDE1MDQyLC0yLjMxNzg2NSAtMi4yNjc0MiwtMi4zMTc4NjUgSCAxOC44NjkwMjIgYyAtMS4yNTIzNzMsMCAtMi4yNjc0MjQsMS4wMzc3ODUgLTIuMjY3NDI0LDIuMzE3ODY1IHYgMCBjIDAsMS4yODAxNTggMS4wMTUwNTEsMi4zMTc4NjYgMi4yNjc0MjQsMi4zMTc4NjYgaCAzMS43NDM5MzcgYyAxLjI1MjM3OCwwIDIuMjY3NDIsLTEuMDM3NzA4IDIuMjY3NDIsLTIuMzE3ODY2IHoiCiAgICAgZmlsbD0iI2ZmZmZmZiIKICAgICBpZD0icGF0aDg0MCIKICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuNzY0MTYzIiAvPgo8L3N2Zz4K" }} + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: incloud-web-dashboard-config + labels: + app.kubernetes.io/instance: incloud-web + app.kubernetes.io/name: web +data: + CUSTOM_TENANT_TEXT: {{ $brandingConfig.tenantText | default $tenantText | quote }} + FOOTER_TEXT: {{ $brandingConfig.footerText | default $footerText | quote }} + TITLE_TEXT: {{ $brandingConfig.titleText | default $titleText | quote }} + LOGO_TEXT: {{ $brandingConfig.logoText | default $logoText | quote }} + CUSTOM_LOGO_SVG: {{ $brandingConfig.logoSvg | default $logoSvg | quote }} + ICON_SVG: {{ $brandingConfig.iconSvg | default $iconSvg | quote }} diff --git a/packages/system/dashboard/templates/dashboard-ingress.yaml b/packages/system/dashboard/templates/dashboard-ingress.yaml deleted file mode 100644 index 1fd7f85d..00000000 --- a/packages/system/dashboard/templates/dashboard-ingress.yaml +++ /dev/null @@ -1,40 +0,0 @@ -{{- $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" }} - -{{- if and (has "dashboard" $exposeServices) }} -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - cert-manager.io/cluster-issuer: letsencrypt-prod - {{- if eq $issuerType "cloudflare" }} - {{- else }} - 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 - name: dashboard - namespace: cozy-dashboard -spec: - ingressClassName: {{ $exposeIngress }} - rules: - - host: dashboard.{{ $host }} - http: - paths: - - backend: - service: - name: dashboard - port: - number: 80 - path: / - pathType: Prefix - tls: - - hosts: - - dashboard.{{ $host }} - secretName: dashboard-tls -{{- end }} diff --git a/packages/system/dashboard/templates/flowschema.yaml b/packages/system/dashboard/templates/flowschema.yaml new file mode 100644 index 00000000..9304fb44 --- /dev/null +++ b/packages/system/dashboard/templates/flowschema.yaml @@ -0,0 +1,20 @@ +apiVersion: flowcontrol.apiserver.k8s.io/v1 +kind: FlowSchema +metadata: + name: cozy-dashboard-exempt +spec: + matchingPrecedence: 2 + priorityLevelConfiguration: + name: exempt + rules: + - subjects: + - kind: ServiceAccount + serviceAccount: + name: incloud-web-web + namespace: {{ .Release.Namespace }} + resourceRules: + - verbs: ["*"] + apiGroups: ["*"] + resources: ["*"] + namespaces: ["*"] + clusterScope: true diff --git a/packages/system/dashboard/templates/gatekeeper-sa.yaml b/packages/system/dashboard/templates/gatekeeper-sa.yaml new file mode 100644 index 00000000..f9043c99 --- /dev/null +++ b/packages/system/dashboard/templates/gatekeeper-sa.yaml @@ -0,0 +1,31 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: incloud-web-gatekeeper +{{- $oidcEnabled := index .Values._cluster "oidc-enabled" }} +{{- if ne $oidcEnabled "true" }} +--- +# ClusterRole to allow token-proxy to fetch JWKS for JWT verification +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: incloud-web-gatekeeper-jwks +rules: +- nonResourceURLs: + - /openid/v1/jwks + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: incloud-web-gatekeeper-jwks +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: incloud-web-gatekeeper-jwks +subjects: +- kind: ServiceAccount + name: incloud-web-gatekeeper + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/packages/system/dashboard/templates/gatekeeper-svc.yaml b/packages/system/dashboard/templates/gatekeeper-svc.yaml new file mode 100644 index 00000000..513ebb70 --- /dev/null +++ b/packages/system/dashboard/templates/gatekeeper-svc.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: incloud-web-gatekeeper +spec: + ports: + - name: ingress + port: 8000 + protocol: TCP + targetPort: 8000 + selector: + app.kubernetes.io/instance: incloud-web + app.kubernetes.io/name: gatekeeper + type: ClusterIP diff --git a/packages/system/dashboard/templates/gatekeeper.yaml b/packages/system/dashboard/templates/gatekeeper.yaml new file mode 100644 index 00000000..f7b1c7f7 --- /dev/null +++ b/packages/system/dashboard/templates/gatekeeper.yaml @@ -0,0 +1,157 @@ +{{- $host := index .Values._cluster "root-host" }} +{{- $oidcEnabled := index .Values._cluster "oidc-enabled" }} +{{- $oidcInsecureSkipVerify := index .Values._cluster "oidc-insecure-skip-verify" }} +{{- $keycloakInternalUrl := index .Values._cluster "keycloak-internal-url" | default "" }} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: incloud-web-gatekeeper +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: incloud-web + app.kubernetes.io/name: gatekeeper + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + template: + metadata: + labels: + app.kubernetes.io/instance: incloud-web + app.kubernetes.io/name: gatekeeper + spec: + serviceAccountName: incloud-web-gatekeeper + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - appSpec + - key: app.kubernetes.io/instance + operator: In + values: + - incloud-web + topologyKey: kubernetes.io/hostname + dnsPolicy: ClusterFirst + enableServiceLinks: false + restartPolicy: Always + priorityClassName: system-cluster-critical + containers: + {{- if eq $oidcEnabled "true" }} + - name: auth-proxy + image: quay.io/oauth2-proxy/oauth2-proxy:v7.12.0 + imagePullPolicy: IfNotPresent + args: + - --provider=oidc + - --upstream=http://incloud-web-nginx.{{ .Release.Namespace }}.svc:8080 + - --http-address=0.0.0.0:8000 + - --redirect-url=https://dashboard.{{ $host }}/oauth2/callback + - --oidc-issuer-url=https://keycloak.{{ $host }}/realms/cozy + {{- if $keycloakInternalUrl }} + - --skip-oidc-discovery + - --login-url=https://keycloak.{{ $host }}/realms/cozy/protocol/openid-connect/auth + - --redeem-url={{ $keycloakInternalUrl }}/protocol/openid-connect/token + - --oidc-jwks-url={{ $keycloakInternalUrl }}/protocol/openid-connect/certs + - --validate-url={{ $keycloakInternalUrl }}/protocol/openid-connect/userinfo + - --backend-logout-url={{ $keycloakInternalUrl }}/protocol/openid-connect/logout?id_token_hint={id_token} + {{- else }} + - --backend-logout-url=https://keycloak.{{ $host }}/realms/cozy/protocol/openid-connect/logout?id_token_hint={id_token} + {{- end }} + - --whitelist-domain=keycloak.{{ $host }} + - --email-domain=* + - --pass-access-token=true + - --pass-authorization-header=true + - --cookie-refresh=3m + - --cookie-name=kc-access + - --cookie-secure=true + - --cookie-secret=$(OAUTH2_PROXY_COOKIE_SECRET) + - --skip-provider-button + - --scope=openid email profile offline_access + {{- if eq $oidcInsecureSkipVerify "true" }} + - --ssl-insecure-skip-verify=true + {{- end }} + env: + - name: OAUTH2_PROXY_CLIENT_ID + value: dashboard + - name: OAUTH2_PROXY_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: dashboard-client + key: client-secret-key + - name: OAUTH2_PROXY_COOKIE_SECRET + valueFrom: + secretKeyRef: + name: dashboard-auth-config + key: cookieSecret + {{- else }} + - name: token-proxy + image: {{ .Values.tokenProxy.image }} + imagePullPolicy: IfNotPresent + args: + - --upstream=http://incloud-web-nginx.{{ .Release.Namespace }}.svc:8080 + - --http-address=0.0.0.0:8000 + - --cookie-refresh=1h + - --cookie-name=kc-access + - --cookie-secure=true + - --cookie-secret=$(TOKEN_PROXY_COOKIE_SECRET) + env: + - name: TOKEN_PROXY_COOKIE_SECRET + valueFrom: + secretKeyRef: + name: dashboard-auth-config + key: cookieSecret + {{- end }} + ports: + - name: proxy + containerPort: 8000 + protocol: TCP + livenessProbe: + httpGet: + path: /ping + port: proxy + scheme: HTTP + initialDelaySeconds: 10 + periodSeconds: 15 + timeoutSeconds: 2 + successThreshold: 1 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /ping + port: proxy + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 2 + successThreshold: 1 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 128Mi + ephemeral-storage: 50Mi + limits: + cpu: 200m + memory: 256Mi + securityContext: + runAsNonRoot: true + runAsUser: 1001 + runAsGroup: 1001 + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File diff --git a/packages/system/dashboard/templates/ingress.yaml b/packages/system/dashboard/templates/ingress.yaml new file mode 100644 index 00000000..6cf01490 --- /dev/null +++ b/packages/system/dashboard/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- $solver := (index .Values._cluster "solver") | default "http01" }} +{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }} +{{- $host := index .Values._cluster "root-host" }} +{{- $exposeServices := splitList "," ((index .Values._cluster "expose-services") | default "") }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} + +{{- if and (has "dashboard" $exposeServices) }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + cert-manager.io/cluster-issuer: {{ $clusterIssuer }} + {{- if eq $solver "http01" }} + acme.cert-manager.io/http01-ingress-ingressclassname: {{ $exposeIngress }} + {{- end }} + nginx.ingress.kubernetes.io/rewrite-target: / + nginx.ingress.kubernetes.io/client-max-body-size: 100m + 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/proxy-read-timeout: "86400" + nginx.ingress.kubernetes.io/proxy-send-timeout: "86400" + name: dashboard-web-ingress +spec: + ingressClassName: {{ $exposeIngress }} + rules: + - host: dashboard.{{ $host }} + http: + paths: + - backend: + service: + name: incloud-web-gatekeeper + port: + number: 8000 + path: / + pathType: Prefix + tls: + - hosts: + - dashboard.{{ $host }} + secretName: dashboard-web-tls +{{- end }} diff --git a/packages/system/dashboard/templates/keycloakclient.yaml b/packages/system/dashboard/templates/keycloakclient.yaml new file mode 100644 index 00000000..fa33fea4 --- /dev/null +++ b/packages/system/dashboard/templates/keycloakclient.yaml @@ -0,0 +1,81 @@ +{{- $host := index .Values._cluster "root-host" }} +{{- $extraRedirectUris := splitList "," ((index .Values._cluster "extra-keycloak-redirect-uri-for-dashboard") | default "") }} + +{{- $existingDashboardSecret := lookup "v1" "Secret" .Release.Namespace "dashboard-client" }} + +{{ $dashboardClient := "" }} +{{- if $existingDashboardSecret }} + {{- $dashboardClient = index $existingDashboardSecret.data "client-secret-key" | b64dec }} +{{- else }} + {{- $dashboardClient = randAlphaNum 32 }} +{{- end }} + +{{- $existingAuthConfig := lookup "v1" "Secret" .Release.Namespace "dashboard-auth-config" }} +{{ $cookieSecret := "" }} +{{- if $existingAuthConfig }} + {{- $cookieSecret = index $existingAuthConfig.data "cookieSecret" | b64dec }} +{{- else }} + {{- $cookieSecret = randAlphaNum 16 }} +{{- end }} + + +--- + +apiVersion: v1 +kind: Secret +metadata: + name: dashboard-client +type: Opaque +data: + client-secret-key: {{ $dashboardClient | b64enc }} + +--- + +apiVersion: v1 +kind: Secret +metadata: + name: dashboard-auth-config +type: Opaque +data: + cookieSecret: {{ $cookieSecret | b64enc }} + + + +--- + +{{- if .Capabilities.APIVersions.Has "v1.edp.epam.com/v1" }} +--- +apiVersion: v1.edp.epam.com/v1 +kind: KeycloakClient +metadata: + name: dashboard-client + annotations: + secret-hash: {{ $dashboardClient | sha256sum }} +spec: + serviceAccount: + enabled: true + realmRef: + name: keycloakrealm-cozy + kind: ClusterKeycloakRealm + secret: $dashboard-client:client-secret-key + advancedProtocolMappers: true + name: dashboard + clientId: dashboard + directAccess: true + public: false + webUrl: "https://dashboard.{{ $host }}" + defaultClientScopes: + - groups + - kubernetes-client + optionalClientScopes: + - offline_access + attributes: + post.logout.redirect.uris: "+" + client.session.idle.timeout: "86400" + client.session.max.lifespan: "604800" + redirectUris: + - "https://dashboard.{{ $host }}/oauth2/callback/*" + {{- range $i, $v := $extraRedirectUris }} + - "{{ $v }}" + {{- end }} +{{- end }} diff --git a/packages/system/dashboard/templates/nginx-config.yaml b/packages/system/dashboard/templates/nginx-config.yaml new file mode 100644 index 00000000..989f1470 --- /dev/null +++ b/packages/system/dashboard/templates/nginx-config.yaml @@ -0,0 +1,97 @@ +{{- $host := index .Values._cluster "root-host" }} + +apiVersion: v1 +data: + nginx-config: |- + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + server { + listen 8080 default_server; + listen [::]:8080 default_server; + server_name _; + + location ~ ^(/clusterlist|/api/clusters)$ { + add_header Content-Type application/json; + set $cluster_list '[{"api":"{{ $host }}","baseDomain":"{{ $host }}","description":"dashboard.{{ $host }}","externalDomain":"dashboard.{{ $host }}","name":"default","tenant":"dev"}]'; + return 200 $cluster_list; + } + + location /api/clusters/default { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $host; + proxy_read_timeout 86400s; + proxy_send_timeout 86400s; + + rewrite /api/clusters/default/(.*) /$1 break; + proxy_pass http://incloud-web-nginx.{{ .Release.Namespace }}.svc:8080; + } + + location /k8s/clusters/default/ { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $host; + proxy_read_timeout 86400s; + proxy_send_timeout 86400s; + + rewrite /k8s/clusters/default/(.*) /$1 break; + proxy_pass https://kubernetes.default.svc:443; + } + + location /k8s { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $host; + proxy_read_timeout 86400s; + proxy_send_timeout 86400s; + + rewrite /k8s/(.*) /$1 break; + proxy_pass https://kubernetes.default.svc:443; + } + + location /openapi-bff { + proxy_pass http://incloud-web-web.{{ .Release.Namespace }}.svc:64231; + } + + + location /openapi-bff-ws/ { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $host; + proxy_read_timeout 86400s; + proxy_send_timeout 86400s; + + proxy_pass http://incloud-web-web.{{ .Release.Namespace }}.svc:64231; + } + + location = /docs { + return 301 https://cozystack.io/docs/; + } + + location = / { + return 301 https://dashboard.{{ $host }}/openapi-ui; + } + + location / { + proxy_pass http://incloud-web-web.{{ .Release.Namespace }}.svc:8080; + } + + location /healthcheck { + access_log off; + return 200 "Healthy\n"; + } + } +kind: ConfigMap +metadata: + name: incloud-web-nginx-config diff --git a/packages/system/dashboard/templates/nginx-sa.yaml b/packages/system/dashboard/templates/nginx-sa.yaml new file mode 100644 index 00000000..ea33ead3 --- /dev/null +++ b/packages/system/dashboard/templates/nginx-sa.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: incloud-web-nginx diff --git a/packages/system/dashboard/templates/nginx-svc.yaml b/packages/system/dashboard/templates/nginx-svc.yaml new file mode 100644 index 00000000..9501bf17 --- /dev/null +++ b/packages/system/dashboard/templates/nginx-svc.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: incloud-web-nginx +spec: + ports: + - name: nginx-http + port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app.kubernetes.io/instance: incloud-web + app.kubernetes.io/name: nginx + type: ClusterIP diff --git a/packages/system/dashboard/templates/nginx.yaml b/packages/system/dashboard/templates/nginx.yaml new file mode 100644 index 00000000..caa75fa7 --- /dev/null +++ b/packages/system/dashboard/templates/nginx.yaml @@ -0,0 +1,100 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: incloud-web-nginx +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: incloud-web + app.kubernetes.io/name: nginx + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/nginx-config.yaml") . | sha256sum }} + labels: + app.kubernetes.io/instance: incloud-web + app.kubernetes.io/name: nginx + spec: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - appSpec + - key: app.kubernetes.io/instance + operator: In + values: + - incloud-web + topologyKey: kubernetes.io/hostname + weight: 100 + containers: + - image: nginxinc/nginx-unprivileged:1.29-alpine + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthcheck + port: 8080 + scheme: HTTP + initialDelaySeconds: 3 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 2 + name: nginx + ports: + - containerPort: 8080 + name: http + protocol: TCP + resources: + limits: + cpu: 200m + memory: 256Mi + requests: + cpu: 100m + ephemeral-storage: 50Mi + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: [] + drop: + - ALL + privileged: false + readOnlyRootFilesystem: false + runAsGroup: 0 + runAsNonRoot: true + runAsUser: 101 + seccompProfile: + type: RuntimeDefault + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /etc/nginx/conf.d/default.conf + name: configurationnginxfile + subPath: nginx-config + dnsPolicy: ClusterFirst + enableServiceLinks: false + hostIPC: false + hostNetwork: false + hostPID: false + preemptionPolicy: null + priorityClassName: system-cluster-critical + restartPolicy: Always + runtimeClassName: null + schedulerName: default-scheduler + serviceAccountName: incloud-web-nginx + terminationGracePeriodSeconds: 30 + volumes: + - configMap: + name: incloud-web-nginx-config + name: configurationnginxfile diff --git a/packages/system/dashboard/templates/rbac.yaml b/packages/system/dashboard/templates/rbac.yaml new file mode 100644 index 00000000..eb687a3e --- /dev/null +++ b/packages/system/dashboard/templates/rbac.yaml @@ -0,0 +1,43 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cozystack-dashboard-readonly +rules: +- apiGroups: + - dashboard.cozystack.io + resources: + - '*' + verbs: + - get + - list + - watch +- apiGroups: + - backups.cozystack.io + resources: + - backupclasses + verbs: + - get + - list + - watch +- apiGroups: + - storage.k8s.io + resources: + - storageclasses + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cozystack-dashboard-readonly-authenticated +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cozystack-dashboard-readonly +subjects: +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:authenticated diff --git a/packages/system/dashboard/templates/vpa.yaml b/packages/system/dashboard/templates/vpa.yaml deleted file mode 100644 index 6eff7036..00000000 --- a/packages/system/dashboard/templates/vpa.yaml +++ /dev/null @@ -1,80 +0,0 @@ -apiVersion: autoscaling.k8s.io/v1 -kind: VerticalPodAutoscaler -metadata: - name: dashboard-internal-dashboard - namespace: cozy-dashboard -spec: - targetRef: - apiVersion: "apps/v1" - kind: Deployment - name: dashboard-internal-dashboard - updatePolicy: - updateMode: "Auto" - resourcePolicy: - containerPolicies: - - containerName: dashboard - controlledResources: ["cpu", "memory"] - minAllowed: - cpu: 50m - memory: 64Mi - maxAllowed: - cpu: 500m - memory: 512Mi ---- -apiVersion: autoscaling.k8s.io/v1 -kind: VerticalPodAutoscaler -metadata: - name: dashboard-internal-kubeappsapis - namespace: cozy-dashboard -spec: - targetRef: - apiVersion: "apps/v1" - kind: Deployment - name: dashboard-internal-kubeappsapis - updatePolicy: - updateMode: "Auto" - resourcePolicy: - containerPolicies: - - containerName: kubeappsapis - controlledResources: ["cpu", "memory"] - minAllowed: - cpu: 50m - memory: 100Mi - maxAllowed: - cpu: 1000m - memory: 1Gi ---- -apiVersion: autoscaling.k8s.io/v1 -kind: VerticalPodAutoscaler -metadata: - name: dashboard-vpa - namespace: cozy-dashboard -spec: - targetRef: - apiVersion: "apps/v1" - kind: Deployment - name: dashboard - updatePolicy: - updateMode: "Auto" - resourcePolicy: - containerPolicies: - - containerName: nginx - controlledResources: ["cpu", "memory"] - minAllowed: - cpu: "50m" - memory: "64Mi" - maxAllowed: - cpu: "500m" - memory: "512Mi" - {{- $dashboardKCconfig := lookup "v1" "ConfigMap" "cozy-dashboard" "kubeapps-auth-config" }} - {{- $dashboardKCValues := dig "data" "values.yaml" "" $dashboardKCconfig }} - {{- if $dashboardKCValues }} - - containerName: auth-proxy - controlledResources: ["cpu", "memory"] - minAllowed: - cpu: "50m" - memory: "64Mi" - maxAllowed: - cpu: "500m" - memory: "512Mi" - {{- end }} diff --git a/packages/system/dashboard/templates/web-sa.yaml b/packages/system/dashboard/templates/web-sa.yaml new file mode 100644 index 00000000..0f259753 --- /dev/null +++ b/packages/system/dashboard/templates/web-sa.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: incloud-web-web diff --git a/packages/system/dashboard/templates/web-svc.yaml b/packages/system/dashboard/templates/web-svc.yaml new file mode 100644 index 00000000..38026706 --- /dev/null +++ b/packages/system/dashboard/templates/web-svc.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: incloud-web-web +spec: + ports: + - name: bff-http + port: 64231 + protocol: TCP + targetPort: 64231 + - name: web-http + port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app.kubernetes.io/instance: incloud-web + app.kubernetes.io/name: web + type: ClusterIP diff --git a/packages/system/dashboard/templates/web.yaml b/packages/system/dashboard/templates/web.yaml new file mode 100644 index 00000000..7799afbf --- /dev/null +++ b/packages/system/dashboard/templates/web.yaml @@ -0,0 +1,274 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: incloud-web-web +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: incloud-web + app.kubernetes.io/name: web + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + labels: + app.kubernetes.io/instance: incloud-web + app.kubernetes.io/name: web + spec: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - appSpec + - key: app.kubernetes.io/instance + operator: In + values: + - incloud-web + topologyKey: kubernetes.io/hostname + weight: 100 + containers: + - env: + - name: BASE_API_GROUP + value: dashboard.cozystack.io + - name: BASE_API_VERSION + value: v1alpha1 + - name: BASE_NAMESPACE_FULL_PATH + value: "/apis/core.cozystack.io/v1alpha1/tenantnamespaces" + - name: BASE_NAVIGATION_RESOURCE_PLURAL + value: navigations + - name: BASE_NAVIGATION_RESOURCE_NAME + value: navigation + - name: BASE_FRONTEND_PREFIX + value: /openapi-ui + - name: BASE_FACTORY_NAMESPACED_API_KEY + value: base-factory-namespaced-api + - name: BASE_FACTORY_CLUSTERSCOPED_API_KEY + value: base-factory-clusterscoped-api + - name: BASE_FACTORY_NAMESPACED_BUILTIN_KEY + value: base-factory-namespaced-builtin + - name: BASE_FACTORY_CLUSTERSCOPED_BUILTIN_KEY + value: base-factory-clusterscoped-builtin + - name: BASE_NAMESPACE_FACTORY_KEY + value: base-factory-clusterscoped-builtin + - name: BASE_ALLOWED_AUTH_HEADERS + value: user-agent,accept,content-type,origin,referer,accept-encoding,cookie,authorization + - name: LOGGER + value: "true" + - name: LOGGER_WITH_HEADERS + value: "false" + - name: PORT + value: "64231" + image: {{ .Values.openapiUIK8sBff.image | quote }} + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthcheck + port: 64231 + scheme: HTTP + initialDelaySeconds: 3 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 2 + startupProbe: + httpGet: + path: /healthcheck + port: 64231 + scheme: HTTP + failureThreshold: 30 + periodSeconds: 2 + name: bff + ports: + - containerPort: 64231 + name: http-bff + protocol: TCP + resources: + limits: + cpu: 1 + memory: 1Gi + requests: + cpu: 100m + ephemeral-storage: 50Mi + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: [] + drop: + - ALL + privileged: false + readOnlyRootFilesystem: false + runAsGroup: 0 + runAsNonRoot: true + runAsUser: 101 + seccompProfile: + type: RuntimeDefault + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + - env: + - name: BASEPREFIX + value: /openapi-ui + - name: HIDE_INSIDE + value: "true" + - name: CUSTOMIZATION_API_GROUP + value: dashboard.cozystack.io + - name: CUSTOMIZATION_API_VERSION + value: v1alpha1 + - name: CUSTOMIZATION_CFOMAPPING_RESOURCE_NAME + value: cfomapping + - name: CUSTOMIZATION_CFOMAPPING_RESOURCE_PLURAL + value: cfomappings + - name: CUSTOMIZATION_CFO_FALLBACK_ID + value: "" + - name: CUSTOMIZATION_NAVIGATION_RESOURCE_NAME + value: navigation + - name: CUSTOMIZATION_NAVIGATION_RESOURCE_PLURAL + value: navigations + - name: CUSTOMIZATION_SIDEBAR_FALLBACK_ID + value: "" + - name: CUSTOMIZATION_BREADCRUMBS_FALLBACK_ID + value: stock-project-api-table + - name: INSTANCES_API_GROUP + value: dashboard.cozystack.io + - name: INSTANCES_API_VERSION + value: v1alpha1 + - name: INSTANCES_PLURAL + value: instances + - name: MARKETPLACE_KIND + value: MarketplacePanel + - name: MARKETPLACE_PLURAL + value: marketplacepanels + - name: NAVIGATE_FROM_CLUSTERLIST + value: /openapi-ui/~recordValue~/api-table/core.cozystack.io/v1alpha1/tenantnamespaces + - name: PROJECTS_API_GROUP + value: core.cozystack.io + - name: PROJECTS_API_VERSION + value: v1alpha1 + - name: PROJECTS_PLURAL + value: tenantnamespaces + - name: CUSTOM_NAMESPACE_API_RESOURCE_API_GROUP + value: core.cozystack.io + - name: CUSTOM_NAMESPACE_API_RESOURCE_API_VERSION + value: v1alpha1 + - name: CUSTOM_NAMESPACE_API_RESOURCE_PLURAL + value: tenantnamespaces + - name: BASE_FACTORY_NAMESPACED_API_KEY + value: base-factory-namespaced-api + - name: BASE_FACTORY_CLUSTERSCOPED_API_KEY + value: base-factory-clusterscoped-api + - name: BASE_FACTORY_NAMESPACED_BUILTIN_KEY + value: base-factory-namespaced-builtin + - name: BASE_FACTORY_CLUSTERSCOPED_BUILTIN_KEY + value: base-factory-clusterscoped-builtin + - name: BASE_NAMESPACE_FACTORY_KEY + value: base-factory-clusterscoped-builtin + - name: USE_NAMESPACE_NAV + value: "true" + - name: USE_NEW_NAVIGATION + value: "true" + - name: HIDE_NAVIGATION + value: "true" + - name: LOGIN_URL + value: "/oauth2/userinfo" + - name: LOGOUT_URL + value: "/oauth2/sign_out" + - name: LOGIN_USERNAME_FIELD + value: "preferredUsername" + - name: FOOTER_TEXT + valueFrom: + configMapKeyRef: + name: incloud-web-dashboard-config + key: FOOTER_TEXT + - name: TITLE_TEXT + valueFrom: + configMapKeyRef: + name: incloud-web-dashboard-config + key: TITLE_TEXT + - name: CUSTOM_TENANT_TEXT + valueFrom: + configMapKeyRef: + name: incloud-web-dashboard-config + key: CUSTOM_TENANT_TEXT + - name: LOGO_TEXT + valueFrom: + configMapKeyRef: + name: incloud-web-dashboard-config + key: LOGO_TEXT + - name: CUSTOM_LOGO_SVG + valueFrom: + configMapKeyRef: + name: incloud-web-dashboard-config + key: CUSTOM_LOGO_SVG + - name: ICON_SVG + valueFrom: + configMapKeyRef: + name: incloud-web-dashboard-config + key: ICON_SVG + image: {{ .Values.openapiUI.image | quote }} + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthcheck + port: 8080 + scheme: HTTP + initialDelaySeconds: 3 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 2 + startupProbe: + httpGet: + path: /healthcheck + port: 8080 + scheme: HTTP + failureThreshold: 30 + periodSeconds: 2 + name: web + ports: + - containerPort: 8080 + name: http + protocol: TCP + resources: + limits: + cpu: 200m + memory: 256Mi + requests: + cpu: 100m + ephemeral-storage: 50Mi + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: [] + drop: + - ALL + privileged: false + readOnlyRootFilesystem: false + runAsGroup: 0 + runAsNonRoot: true + runAsUser: 101 + seccompProfile: + type: RuntimeDefault + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + dnsPolicy: ClusterFirst + enableServiceLinks: false + hostIPC: false + hostNetwork: false + hostPID: false + priorityClassName: system-cluster-critical + restartPolicy: Always + schedulerName: default-scheduler + serviceAccountName: incloud-web-web + terminationGracePeriodSeconds: 30 diff --git a/packages/system/dashboard/values.yaml b/packages/system/dashboard/values.yaml index 227105ee..a5188825 100644 --- a/packages/system/dashboard/values.yaml +++ b/packages/system/dashboard/values.yaml @@ -1,368 +1,6 @@ -kubeapps: - ingress: - annotations: - nginx.ingress.kubernetes.io/proxy-read-timeout: "600" - nginx.ingress.kubernetes.io/client-max-body-size: 1m - nginx.ingress.kubernetes.io/proxy-body-size: 100m - nginx.ingress.kubernetes.io/proxy-buffer-size: 16k - nginx.ingress.kubernetes.io/proxy-buffers-number: "4" - fullnameOverride: dashboard - postgresql: - enabled: false - packaging: - helm: - enabled: false - flux: - enabled: true - dashboard: - resourcesPreset: "none" - image: - registry: ghcr.io/cozystack/cozystack - repository: dashboard - tag: v0.33.2 - digest: "sha256:ac2b5348d85fe37ad70a4cc159881c4eaded9175a4b586cfa09a52b0fbe5e1e5" - redis: - master: - resourcesPreset: "none" - resources: - requests: - cpu: 20m - memory: 128Mi - limits: - memory: 128Mi - kubeappsapis: - resourcesPreset: "none" - qps: "250.0" - burst: "500" - image: - registry: ghcr.io/cozystack/cozystack - repository: kubeapps-apis - tag: v0.33.2 - digest: "sha256:65325a916974e63e813fca1a89dc40ae58b5bfc2a8ffc4581916106136d19563" - pluginConfig: - flux: - packages: - v1alpha1: - resources: - - application: - kind: Bucket - singular: bucket - plural: buckets - release: - prefix: bucket- - labels: - cozystack.io/ui: "true" - chart: - name: bucket - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: ClickHouse - singular: clickhouse - plural: clickhouses - release: - prefix: clickhouse- - labels: - cozystack.io/ui: "true" - chart: - name: clickhouse - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: HTTPCache - singular: httpcache - plural: httpcaches - release: - prefix: http-cache- - labels: - cozystack.io/ui: "true" - chart: - name: http-cache - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: NATS - singular: nats - plural: natses - release: - prefix: nats- - labels: - cozystack.io/ui: "true" - chart: - name: nats - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: TCPBalancer - singular: tcpbalancer - plural: tcpbalancers - release: - prefix: tcp-balancer- - labels: - cozystack.io/ui: "true" - chart: - name: tcp-balancer - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: VirtualMachine - singular: virtualmachine - plural: virtualmachines - release: - prefix: virtual-machine- - labels: - cozystack.io/ui: "true" - chart: - name: virtual-machine - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: VPN - singular: vpn - plural: vpns - release: - prefix: vpn- - labels: - cozystack.io/ui: "true" - chart: - name: vpn - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: MySQL - singular: mysql - plural: mysqls - release: - prefix: mysql- - labels: - cozystack.io/ui: "true" - chart: - name: mysql - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: Tenant - singular: tenant - plural: tenants - release: - prefix: tenant- - labels: - cozystack.io/ui: "true" - chart: - name: tenant - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: Kubernetes - singular: kubernetes - plural: kuberneteses - release: - prefix: kubernetes- - labels: - cozystack.io/ui: "true" - chart: - name: kubernetes - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: Redis - singular: redis - plural: redises - release: - prefix: redis- - labels: - cozystack.io/ui: "true" - chart: - name: redis - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: RabbitMQ - singular: rabbitmq - plural: rabbitmqs - release: - prefix: rabbitmq- - labels: - cozystack.io/ui: "true" - chart: - name: rabbitmq - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: Postgres - singular: postgres - plural: postgreses - release: - prefix: postgres- - labels: - cozystack.io/ui: "true" - chart: - name: postgres - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: FerretDB - singular: ferretdb - plural: ferretdb - release: - prefix: ferretdb- - labels: - cozystack.io/ui: "true" - chart: - name: ferretdb - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: Kafka - singular: kafka - plural: kafkas - release: - prefix: kafka- - labels: - cozystack.io/ui: "true" - chart: - name: kafka - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: VMDisk - plural: vmdisks - singular: vmdisk - release: - prefix: vm-disk- - labels: - cozystack.io/ui: "true" - chart: - name: vm-disk - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: VMInstance - plural: vminstances - singular: vminstance - release: - prefix: vm-instance- - labels: - cozystack.io/ui: "true" - chart: - name: vm-instance - sourceRef: - kind: HelmRepository - name: cozystack-apps - namespace: cozy-public - - application: - kind: Monitoring - plural: monitorings - singular: monitoring - release: - prefix: "" - labels: - cozystack.io/ui: "true" - chart: - name: monitoring - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - - application: - kind: Etcd - plural: etcds - singular: etcd - release: - prefix: "" - labels: - cozystack.io/ui: "true" - chart: - name: etcd - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - - application: - kind: Ingress - plural: ingresses - singular: ingress - release: - prefix: "" - labels: - cozystack.io/ui: "true" - chart: - name: ingress - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - - application: - kind: SeaweedFS - plural: seaweedfses - singular: seaweedfs - release: - prefix: "" - labels: - cozystack.io/ui: "true" - chart: - name: seaweedfs - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - - application: - kind: BootBox - plural: bootboxes - singular: bootbox - release: - prefix: "" - labels: - cozystack.io/ui: "true" - chart: - name: bootbox - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public - - application: - kind: Info - plural: infos - singular: info - release: - prefix: "" - labels: - cozystack.io/ui: "true" - chart: - name: info - sourceRef: - kind: HelmRepository - name: cozystack-extra - namespace: cozy-public +openapiUI: + image: ghcr.io/cozystack/cozystack/openapi-ui:v1.3.0@sha256:0fa79c373a62840a617ff1ca1b0e31931c13a6cf7b0bb0ff0dc191f047a465a3 +openapiUIK8sBff: + image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v1.3.0@sha256:1b3ea6d4c7dbbe6a8def3b2807fffdfab2ac4afc39d7a846e57dd491fa168f92 +tokenProxy: + image: ghcr.io/cozystack/cozystack/token-proxy:v1.3.0@sha256:2e280991e07853ea48f97b0a42946afffa10d03d6a83d41099ed83e6ffc94fdc diff --git a/packages/system/etcd-operator/Chart.yaml b/packages/system/etcd-operator/Chart.yaml index b6483c15..e0ce7207 100644 --- a/packages/system/etcd-operator/Chart.yaml +++ b/packages/system/etcd-operator/Chart.yaml @@ -1,2 +1,2 @@ name: cozy-etcd-operator -version: 0.4.0 +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/etcd-operator/Makefile b/packages/system/etcd-operator/Makefile index a2154952..54a1edad 100644 --- a/packages/system/etcd-operator/Makefile +++ b/packages/system/etcd-operator/Makefile @@ -1,7 +1,7 @@ export NAME=etcd-operator export NAMESPACE=cozy-${NAME} -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/etcd-operator/charts/etcd-operator/README.md b/packages/system/etcd-operator/charts/etcd-operator/README.md index 144c2ef0..ff2e019a 100644 --- a/packages/system/etcd-operator/charts/etcd-operator/README.md +++ b/packages/system/etcd-operator/charts/etcd-operator/README.md @@ -38,8 +38,8 @@ | kubeRbacProxy.args[2] | string | `"--logtostderr=true"` | | | kubeRbacProxy.args[3] | string | `"--v=0"` | | | kubeRbacProxy.image.pullPolicy | string | `"IfNotPresent"` | Image pull policy | -| kubeRbacProxy.image.repository | string | `"gcr.io/kubebuilder/kube-rbac-proxy"` | Image repository | -| kubeRbacProxy.image.tag | string | `"v0.16.0"` | Version of image | +| kubeRbacProxy.image.repository | string | `"quay.io/brancz/kube-rbac-proxy"` | Image repository | +| kubeRbacProxy.image.tag | string | `"v0.18.1"` | Version of image | | kubeRbacProxy.livenessProbe | object | `{}` | https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ | | kubeRbacProxy.readinessProbe | object | `{}` | https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ | | kubeRbacProxy.resources | object | `{"limits":{"cpu":"250m","memory":"128Mi"},"requests":{"cpu":"100m","memory":"64Mi"}}` | ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | diff --git a/packages/system/etcd-operator/charts/etcd-operator/values.yaml b/packages/system/etcd-operator/charts/etcd-operator/values.yaml index 9687a10c..b2b5cd4e 100644 --- a/packages/system/etcd-operator/charts/etcd-operator/values.yaml +++ b/packages/system/etcd-operator/charts/etcd-operator/values.yaml @@ -98,13 +98,13 @@ kubeRbacProxy: image: # -- Image repository - repository: gcr.io/kubebuilder/kube-rbac-proxy + repository: quay.io/brancz/kube-rbac-proxy # -- Image pull policy pullPolicy: IfNotPresent # -- Version of image - tag: v0.16.0 + tag: v0.18.1 args: - --secure-listen-address=0.0.0.0:8443 diff --git a/packages/system/etcd-rd/Chart.yaml b/packages/system/etcd-rd/Chart.yaml new file mode 100644 index 00000000..8aa00f9b --- /dev/null +++ b/packages/system/etcd-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: etcd-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/etcd-rd/Makefile b/packages/system/etcd-rd/Makefile new file mode 100644 index 00000000..df993ae6 --- /dev/null +++ b/packages/system/etcd-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=etcd-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/etcd-rd/cozyrds/etcd.yaml b/packages/system/etcd-rd/cozyrds/etcd.yaml new file mode 100644 index 00000000..7ff7c39c --- /dev/null +++ b/packages/system/etcd-rd/cozyrds/etcd.yaml @@ -0,0 +1,37 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: etcd +spec: + application: + kind: Etcd + plural: etcds + singular: etcd + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"size":{"description":"Persistent Volume size.","default":"4Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"replicas":{"description":"Number of etcd replicas.","type":"integer","default":3},"resources":{"description":"Resource configuration for etcd.","type":"object","default":{},"properties":{"cpu":{"description":"Number of CPU cores allocated.","default":"1000m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Amount of memory allocated.","default":"512Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}} + release: + prefix: "" + labels: + sharding.fluxcd.io/key: tenants + internal.cozystack.io/tenantmodule: "true" + chartRef: + kind: ExternalArtifact + name: cozystack-etcd-application-default-etcd + namespace: cozy-system + dashboard: + category: Administration + singular: Etcd + plural: Etcd + name: etcd + description: Storage for Kubernetes clusters + module: true + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHg9Ii0wLjAwMTk1MzEyIiB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgcng9IjI0IiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfNjgzXzI5NjMpIi8+CjxwYXRoIGQ9Ik0xMjIuNDQyIDczLjQ3MjlDMTIxLjk1OSA3My41MTM0IDEyMS40NzQgNzMuNTMyMiAxMjAuOTU4IDczLjUzMjJDMTE3Ljk2NSA3My41MzIyIDExNS4wNjEgNzIuODMwNCAxMTIuNDQyIDcxLjU0NTFDMTEzLjMxNCA2Ni41NDIxIDExMy42ODUgNjEuNTAxOSAxMTMuNTg4IDU2LjQ4MDJDMTEwLjc0OCA1Mi4zNzIzIDEwNy41MDIgNDguNDk2NSAxMDMuODM4IDQ0LjkyNTdDMTA1LjQyOCA0MS45NDU0IDEwNy43NzggMzkuMzgxMSAxMTAuNzExIDM3LjU2MjhMMTExLjk3MSAzNi43ODQyTDExMC45ODkgMzUuNjc3NEMxMDUuOTMyIDI5Ljk4MzIgOTkuODk3MSAyNS41ODA5IDkzLjA1NDcgMjIuNTkzN0w5MS42OTAyIDIyTDkxLjM0MzcgMjMuNDQyM0M5MC41Mjc3IDI2LjgwMzYgODguODIyMiAyOS44MzYgODYuNDgwNyAzMi4yNjk1QzgxLjk4MDMgMjkuODc3NCA3Ny4yNzg4IDI3Ljk0NCA3Mi40MzA1IDI2LjQ3OTdDNjcuNTkzNyAyNy45NDA4IDYyLjkwMDUgMjkuODY4NiA1OC40MDIgMzIuMjU3MUM1Ni4wNzAxIDI5LjgyNjggNTQuMzY4OCAyNi44MDE4IDUzLjU1NiAyMy40NTAxTDUzLjIwNzIgMjIuMDA4M0w1MS44NDc3IDIyLjU5OTJDNDUuMDkxNCAyNS41NDMxIDM4Ljg5MDEgMzAuMDY0NyAzMy45MTYyIDM1LjY3NDJMMzIuOTMxOCAzNi43ODMzTDM0LjE5IDM3LjU2MTlDMzcuMTE0MiAzOS4zNzMzIDM5LjQ1NzYgNDEuOTIyNCA0MS4wNDQ0IDQ0Ljg4NjZDMzcuMzkxNyA0OC40NDM1IDM0LjE0OTUgNTIuMzA3IDMxLjMxMTkgNTYuMzk1OUMzMS4yMDE0IDYxLjQxNTQgMzEuNTUzNSA2Ni40OTI0IDMyLjQyOTcgNzEuNTY0NEMyOS44MjMxIDcyLjgzNzggMjYuOTM1OCA3My41MzE4IDIzLjk2MjggNzMuNTMxOEMyMy40NDA5IDczLjUzMTggMjIuOTUyNyA3My41MTI5IDIyLjQ3ODIgNzMuNDczM0wyMSA3My4zNjA2TDIxLjEzODUgNzQuODM2NUMyMS44NjI5IDgyLjMwMzMgMjQuMTgxNCA4OS40MDUzIDI4LjAzMzQgOTUuOTQ3MUwyOC43ODUzIDk3LjIyMzdMMjkuOTE0MiA5Ni4yNjU2QzMyLjUzMDUgOTQuMDQ2NSAzNS42OTE3IDkyLjU3NyAzOS4wNTMgOTEuOTg0N0M0MS4yNjg5IDk2LjUxNTUgNDMuODk1MyAxMDAuNzcyIDQ2Ljg3NDcgMTA0LjcyNUM1MS42Mjg3IDEwNi4zODcgNTYuNTgxOSAxMDcuNjI5IDYxLjY5NzEgMTA4LjM2N0M2Mi4xODc3IDExMS43NSA2MS43OTcgMTE1LjI0OSA2MC40NjI0IDExOC40ODRMNTkuODk5NSAxMTkuODU1TDYxLjM0NjkgMTIwLjE3NEM2NS4wNTI5IDEyMC45ODkgNjguNzkxNyAxMjEuNDA0IDcyLjQ1MjYgMTIxLjQwNEw4My41NTUxIDEyMC4xNzRMODUuMDAzOSAxMTkuODU1TDg0LjQzOTcgMTE4LjQ4MkM4My4xMDg3IDExNS4yNDYgODIuNzE4IDExMS43NDMgODMuMjA4NiAxMDguMzZDODguMzAzNiAxMDcuNjIxIDkzLjIzODQgMTA2LjM4MiA5Ny45NzQ4IDEwNC43MjVDMTAwLjk1NyAxMDAuNzY5IDEwMy41ODYgOTYuNTA5NSAxMDUuODA1IDkxLjk3MjhDMTA5LjE3NyA5Mi41NjE0IDExMi4zNTYgOTQuMDMxNyAxMTQuOTg5IDk2LjI1NzNMMTE2LjExOCA5Ny4yMTQxTDExNi44NjYgOTUuOTQwN0MxMjAuNzI1IDg5LjM5MDUgMTIzLjA0MyA4Mi4yODkxIDEyMy43NTYgNzQuODM0MkwxMjMuODk1IDczLjM2MUwxMjIuNDQyIDczLjQ3MjlaTTg4LjMxOTcgOTEuNTE4MUM4My4wNjczIDkyLjk0NjYgNzcuNzMzIDkzLjY2NzcgNzIuNDMwNSA5My42Njc3QzY3LjExMzcgOTMuNjY3NyA2MS43ODU5IDkyLjk0NyA1Ni41MjkgOTEuNTE4MUM1My42NDQ4IDg3LjAzNjYgNTEuMzY0NSA4Mi4yMzU3IDQ5LjcyMzQgNzcuMTgxMkM0OC4wODkyIDcyLjE1MDIgNDcuMTMyOSA2Ni44Nzk1IDQ2Ljg1NTQgNjEuNDUyMkM1MC4yNTA0IDU3LjI1NDcgNTQuMTExIDUzLjU3NzYgNTguMzc2NyA1MC40ODIzQzYyLjcxMTQgNDcuMzI5NCA2Ny40MjcxIDQ0Ljc2NzkgNzIuNDMwNSA0Mi44NDFDNzcuNDI1NiA0NC43NjgzIDgyLjEzMjYgNDcuMzI2MiA4Ni40NTcyIDUwLjQ2NTdDOTAuNzM5NCA1My41Nzc2IDk0LjYxNzEgNTcuMjgzMiA5OC4wMjg3IDYxLjUwN0M5Ny43Mzc4IDY2LjkwMzQgOTYuNzcgNzIuMTQzOCA5NS4xMzMgNzcuMTY2NUM5My40OTYxIDgyLjIyIDkxLjIwODQgODcuMDM2MSA4OC4zMTk3IDkxLjUxODFaTTc2Ljc2ODQgNjYuMTk3NEM3Ni43Njg0IDY5LjkwODEgNzkuNzc1NCA3Mi45MDk2IDgzLjQ4MSA3Mi45MDk2Qzg3LjE4NTcgNzIuOTA5NiA5MC4xODk1IDY5LjkwODYgOTAuMTg5NSA2Ni4xOTc0QzkwLjE4OTUgNjIuNTAxIDg3LjE4NTcgNTkuNDg4MSA4My40ODEgNTkuNDg4MUM3OS43NzU0IDU5LjQ4ODEgNzYuNzY4NCA2Mi41MDEgNzYuNzY4NCA2Ni4xOTc0Wk02OC4wOTU0IDY2LjE5NzRDNjguMDk1NCA2OS45MDgxIDY1LjA4ODggNzIuOTA5NiA2MS4zODMyIDcyLjkwOTZDNTcuNjc0OSA3Mi45MDk2IDU0LjY3NjYgNjkuOTA4NiA1NC42NzY2IDY2LjE5NzRDNTQuNjc2NiA2Mi41MDI0IDU3LjY3NTMgNTkuNDg5NCA2MS4zODMyIDU5LjQ4OTRDNjUuMDg4OCA1OS40ODk0IDY4LjA5NTQgNjIuNTAyNCA2OC4wOTU0IDY2LjE5NzRaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4M18yOTYzIiB4MT0iNS41IiB5MT0iMTEiIHgyPSIxNDEiIHkyPSIxMjQuNSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjNTNCMkYwIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzQxOUVEQSIvPgo8L2xpbmVhckdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPgo= + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "size"], ["spec", "storageClass"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resources", "cpu"], ["spec", "resources", "memory"]] + secrets: + exclude: [] + include: [] + services: + exclude: [] + include: + - resourceNames: + - etcd diff --git a/packages/system/etcd-rd/templates/cozyrd.yaml b/packages/system/etcd-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/etcd-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/etcd-rd/values.yaml b/packages/system/etcd-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/etcd-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/external-dns-rd/Chart.yaml b/packages/system/external-dns-rd/Chart.yaml new file mode 100644 index 00000000..b9575cd8 --- /dev/null +++ b/packages/system/external-dns-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: external-dns-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/external-dns-rd/Makefile b/packages/system/external-dns-rd/Makefile new file mode 100644 index 00000000..4abb36a6 --- /dev/null +++ b/packages/system/external-dns-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=external-dns-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/external-dns-rd/cozyrds/external-dns.yaml b/packages/system/external-dns-rd/cozyrds/external-dns.yaml new file mode 100644 index 00000000..849b16ad --- /dev/null +++ b/packages/system/external-dns-rd/cozyrds/external-dns.yaml @@ -0,0 +1,24 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: external-dns +spec: + application: + kind: ExternalDNS + plural: externaldns + singular: externaldns + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"provider":{"description":"DNS provider name.","type":"string","enum":["cloudflare","aws","azure","google","digitalocean","linode","ovh","exoscale","godaddy","inmemory"]},"domainFilters":{"description":"List of domains this external-dns instance can manage.","type":"array","default":[],"items":{"type":"string"}},"policy":{"description":"How DNS records are synchronized.","type":"string","default":"upsert-only","enum":["create-only","sync","upsert-only"]},"extraArgs":{"description":"Extra arguments for external-dns.","type":"array","default":[],"items":{"type":"string"}},"gatewayAPI":{"description":"Enable Gateway API HTTPRoute as a source for DNS records.","type":"boolean","default":false},"annotationPrefix":{"description":"Custom annotation prefix for external-dns (useful for running multiple instances).","type":"string","default":""},"cloudflare":{"description":"Cloudflare provider credentials.","type":"object","default":{"apiEmail":"","apiKey":"","apiToken":"","proxied":false},"x-kubernetes-preserve-unknown-fields":true},"aws":{"description":"AWS Route53 provider credentials.","type":"object","default":{"accessKeyId":"","region":"","secretAccessKey":"","zoneType":""},"x-kubernetes-preserve-unknown-fields":true},"azure":{"description":"Azure DNS provider credentials.","type":"object","default":{"aadClientId":"","aadClientSecret":"","resourceGroup":"","subscriptionId":"","tenantId":""},"x-kubernetes-preserve-unknown-fields":true},"google":{"description":"Google Cloud DNS provider credentials.","type":"object","default":{"project":"","serviceAccountKey":""},"x-kubernetes-preserve-unknown-fields":true},"digitalocean":{"description":"DigitalOcean DNS provider credentials.","type":"object","default":{"token":""},"x-kubernetes-preserve-unknown-fields":true},"linode":{"description":"Linode DNS provider credentials.","type":"object","default":{"token":""},"x-kubernetes-preserve-unknown-fields":true},"ovh":{"description":"OVH DNS provider credentials.","type":"object","default":{"applicationKey":"","applicationSecret":"","consumerKey":"","endpoint":""},"x-kubernetes-preserve-unknown-fields":true},"exoscale":{"description":"Exoscale DNS provider credentials.","type":"object","default":{"apiKey":"","apiSecret":""},"x-kubernetes-preserve-unknown-fields":true},"godaddy":{"description":"GoDaddy DNS provider credentials.","type":"object","default":{"apiKey":"","apiSecret":""},"x-kubernetes-preserve-unknown-fields":true},"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}} + release: + prefix: "" + chartRef: + kind: ExternalArtifact + name: cozystack-external-dns-application-default-external-dns + namespace: cozy-system + dashboard: + category: Networking + singular: External DNS + plural: External DNS + description: External DNS for automatic DNS record management + icon: PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNDQgMTQ0IiB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCI+CiAgPGRlZnM+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImJnIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjEwMCUiIHkyPSIxMDAlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3R5bGU9InN0b3AtY29sb3I6IzNCODJGNiIvPgogICAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0eWxlPSJzdG9wLWNvbG9yOiMxRDRFRDgiLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgogIDxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjgiIGZpbGw9InVybCgjYmcpIi8+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNzIsNzIpIiBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iNCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj4KICAgIDwhLS0gR2xvYmUgLS0+CiAgICA8Y2lyY2xlIGN4PSIwIiBjeT0iLTQiIHI9IjMyIi8+CiAgICA8ZWxsaXBzZSBjeD0iMCIgY3k9Ii00IiByeD0iMTQiIHJ5PSIzMiIvPgogICAgPGxpbmUgeDE9Ii0zMiIgeTE9Ii00IiB4Mj0iMzIiIHkyPSItNCIvPgogICAgPHBhdGggZD0iTS0yOCwxMiBRMCwxOCAyOCwxMiIvPgogICAgPHBhdGggZD0iTS0yOCwtMjAgUTAsLTE0IDI4LC0yMCIvPgogICAgPCEtLSBBcnJvdyBwb2ludGluZyBvdXQgLS0+CiAgICA8bGluZSB4MT0iMTgiIHkxPSIxOCIgeDI9IjM2IiB5Mj0iMzYiLz4KICAgIDxwb2x5bGluZSBwb2ludHM9IjI4LDM2IDM2LDM2IDM2LDI4Ii8+CiAgPC9nPgo8L3N2Zz4K + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "domainFilters"], ["spec", "policy"], ["spec", "extraArgs"], ["spec", "gatewayAPI"], ["spec", "annotationPrefix"], ["spec", "cloudflare"], ["spec", "cloudflare", "apiToken"], ["spec", "cloudflare", "apiKey"], ["spec", "cloudflare", "apiEmail"], ["spec", "cloudflare", "proxied"], ["spec", "aws"], ["spec", "aws", "accessKeyId"], ["spec", "aws", "secretAccessKey"], ["spec", "aws", "region"], ["spec", "aws", "zoneType"], ["spec", "azure"], ["spec", "azure", "tenantId"], ["spec", "azure", "subscriptionId"], ["spec", "azure", "resourceGroup"], ["spec", "azure", "aadClientId"], ["spec", "azure", "aadClientSecret"], ["spec", "google"], ["spec", "google", "project"], ["spec", "google", "serviceAccountKey"], ["spec", "digitalocean"], ["spec", "digitalocean", "token"], ["spec", "linode"], ["spec", "linode", "token"], ["spec", "ovh"], ["spec", "ovh", "endpoint"], ["spec", "ovh", "applicationKey"], ["spec", "ovh", "applicationSecret"], ["spec", "ovh", "consumerKey"], ["spec", "exoscale"], ["spec", "exoscale", "apiKey"], ["spec", "exoscale", "apiSecret"], ["spec", "godaddy"], ["spec", "godaddy", "apiKey"], ["spec", "godaddy", "apiSecret"], ["spec", "resources"], ["spec", "resourcesPreset"]] diff --git a/packages/system/external-dns-rd/templates/cozyrd.yaml b/packages/system/external-dns-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/external-dns-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/external-dns-rd/values.yaml b/packages/system/external-dns-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/external-dns-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/external-dns/Makefile b/packages/system/external-dns/Makefile index 1ddfa773..5b0197e1 100644 --- a/packages/system/external-dns/Makefile +++ b/packages/system/external-dns/Makefile @@ -1,7 +1,7 @@ export NAME=external-dns export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/external-dns/charts/external-dns/.helmignore b/packages/system/external-dns/charts/external-dns/.helmignore index 0e8a0eb3..e951b6fb 100644 --- a/packages/system/external-dns/charts/external-dns/.helmignore +++ b/packages/system/external-dns/charts/external-dns/.helmignore @@ -21,3 +21,7 @@ .idea/ *.tmproj .vscode/ +ci/ +schema/ +.schema.yaml +tests/ diff --git a/packages/system/external-dns/charts/external-dns/CHANGELOG.md b/packages/system/external-dns/charts/external-dns/CHANGELOG.md index 02b467e1..6b2401c2 100644 --- a/packages/system/external-dns/charts/external-dns/CHANGELOG.md +++ b/packages/system/external-dns/charts/external-dns/CHANGELOG.md @@ -18,11 +18,117 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [UNRELEASED] -## [v1.15.0] - 2023-09-10 +## [v1.20.0] + +### Added + +- Add option to set `annotationPrefix` ([#5889](https://github.com/kubernetes-sigs/external-dns/pull/5889)) _@lexfrei_ ### Changed -- Updated _ExternalDNS_ OCI image version to [v0.15.0](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.15.0). ([#xxxx](https://github.com/kubernetes-sigs/external-dns/pull/xxxx)) _@stevehipwell_ +- Grant `networking.k8s.io/ingresses` and `gateway.solo.io/gateways` permissions when using `gloo-proxy` source. ([#5909](https://github.com/kubernetes-sigs/external-dns/pull/5909)) _@cucxabong_ +- Update _ExternalDNS_ OCI image version to [v0.20.0](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.20.0). ([#6005](https://github.com/kubernetes-sigs/external-dns/pull/6005)) _@vflaux_ + +### Fixed + +- Fixed the missing schema for `.provider.webhook.serviceMonitor` configs ([#5932](https://github.com/kubernetes-sigs/external-dns/pull/5932)) _@chrisbsmith_ +- Fixed incorrect indentation of selector labels under `spec.template.spec.topologySpreadConstraints` when `topologySpreadConstraints` is set. ([#6054](https://github.com/kubernetes-sigs/external-dns/pull/6054)) _@andylim0221_ + +## [v1.19.0] - 2025-09-08 + +### Added + +- Add option to configure `annotationFilter` via dedicated chart value. ([#5737](https://github.com/kubernetes-sigs/external-dns/pull/5737)) _@dshatokhin_ + +### Changed + +- Grant `discovery.k8s.io/endpointslices` permission only when using `service` source. ([#5746](https://github.com/kubernetes-sigs/external-dns/pull/5746)) _@vflaux_ +- Update _ExternalDNS_ OCI image version to [v0.19.0](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.19.0). ([#5819](https://github.com/kubernetes-sigs/external-dns/pull/5819)) _@stevehipwell_ + +## [v1.18.0] - 2025-07-14 + +### Changed + +- Update RBAC for `Service` source to support `EndpointSlices`. ([#5493](https://github.com/kubernetes-sigs/external-dns/pull/5493)) _@vflaux_ +- Update _ExternalDNS_ OCI image version to [v0.18.0](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.18.0). ([#5633](https://github.com/kubernetes-sigs/external-dns/pull/5633)) _@elafarge_ + +### Fixed + +- Fixed the lack of schema support for `create-only` dns policy in helm values ([#5627](https://github.com/kubernetes-sigs/external-dns/pull/5627)) _@coltonhughes_ +- Fixed the type of `.extraContainers` from `object` to `list` (array). ([#5564](https://github.com/kubernetes-sigs/external-dns/pull/5564)) _@svengreb_ + +## [v1.17.0] - 2025-06-04 + +### Changed + +- Allow extraArgs to also be a map enabling overrides of individual values. ([#5293](https://github.com/kubernetes-sigs/external-dns/pull/5293)) _@frittentheke_ +- Update CRD. ([#5287](https://github.com/kubernetes-sigs/external-dns/pull/5287)) _@mloiseleur_ +- Update CRD. ([#5446](https://github.com/kubernetes-sigs/external-dns/pull/5446)) _@mloiseleur_ +- Update _ExternalDNS_ OCI image version to [v0.17.0](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.17.0). ([#5479](https://github.com/kubernetes-sigs/external-dns/pull/5479)) _@stevehipwell_ + +### Fixed + +- Fix wrong type definitions for webhook probes. ([#5297](https://github.com/kubernetes-sigs/external-dns/pull/5297)) _@semnell_ +- Update schema with latest plugin release. ([#5510](https://github.com/kubernetes-sigs/external-dns/pull/5510)) _@mloiseleur + +## [v1.16.1] - 2025-04-10 + +### Changed + +- Set defaults for `automountServiceAccountToken` and `serviceAccount.automountServiceAccountToken` to `true` in Helm chart values. ([#5207](https://github.com/kubernetes-sigs/external-dns/pull/5207)) _@t3mi_ + +### Fixed + +- Correctly handle `txtPrefix` and `txtSuffix` arguments when both are provided. ([#5250](https://github.com/kubernetes-sigs/external-dns/pull/5250)) _@ivankatliarchuk_ +- Add missing types in the schema for empty values. ([#5228](https://github.com/kubernetes-sigs/external-dns/pull/5228)) _@ivankatliarchuk_ +- Add missing types in the schema for empty values. ([#5207](https://github.com/kubernetes-sigs/external-dns/pull/5207)) _@t3mi_ + +## [v1.16.0] - 2025-03-20 + +### Added + +- Add helm testing framework `helm plugin unittest`. ([#5137](https://github.com/kubernetes-sigs/external-dns/pull/5137)) _@ivankatliarchuk_ +- Add ability to generate schema with `helm plugin schema`. ([#5075](https://github.com/kubernetes-sigs/external-dns/pull/5075)) _@ivankatliarchuk_ +- Add `docs/contributing/dev-guide.md#helm-values` guide. ([#5075](https://github.com/kubernetes-sigs/external-dns/pull/5075)) _@ivankatliarchuk_ + +### Changed + +- Regenerate JSON schema with `helm-values-schema-json' plugin. ([#5075](https://github.com/kubernetes-sigs/external-dns/pull/5075)) _@ivankatliarchuk_ +- Update _ExternalDNS_ OCI image version to [v0.16.1](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.16.1). ([#5201](https://github.com/kubernetes-sigs/external-dns/pull/5201)) _@stevehipwell_ + +## [v1.15.2] - 2025-02-14 + +### Changed + +- Added `transportservers` resource to ClusterRole when specifying `f5-transportserver` or `f5-virtualserver` as a source. ([#5066](https://github.com/kubernetes-sigs/external-dns/pull/5066)) _@visokoo_ + +### Fixed + +- Fixed handling of non-string types in `serviceAccount.metadata.annotations` field. ([#5067](https://github.com/kubernetes-sigs/external-dns/pull/5067)) _@hjoshi123_ +- Fixed regression where `affinity.nodeAffinity` was being ignored. ([#5046](https://github.com/kubernetes-sigs/external-dns/pull/5046)) _@mkhpalm_ + +## [v1.15.1] - 2025-01-27 + +### Added + +- Added ability to configure `imagePullSecrets` via helm `global` value. ([#4667](https://github.com/kubernetes-sigs/external-dns/pull/4667)) _@jkroepke_ +- Added options to configure `labelFilter` and `managedRecordTypes` via dedicated helm values. ([#4849](https://github.com/kubernetes-sigs/external-dns/pull/4849)) _@abaguas_ + +### Changed + +- Allow templating `serviceaccount.annotations` keys and values, by rendering them using the `tpl` built-in function. ([#4958](https://github.com/kubernetes-sigs/external-dns/pull/4958)) _@fcrespofastly_ +- Updated _ExternalDNS_ OCI image version to [v0.15.1](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.15.1). ([#5028](https://github.com/kubernetes-sigs/external-dns/pull/5028)) _@stevehipwell_ + +### Fixed + +- Fixed automatic addition of pod selector labels to `affinity` and `topologySpreadConstraints` if not defined. ([#4666](https://github.com/kubernetes-sigs/external-dns/pull/4666)) _@pvickery-ParamountCommerce_ +- Fixed missing Ingress permissions when using Istio sources. ([#4845](https://github.com/kubernetes-sigs/external-dns/pull/4845)) _@joekhoobyar_ + +## [v1.15.0] - 2024-09-11 + +### Changed + +- Updated _ExternalDNS_ OCI image version to [v0.15.0](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.15.0). ([#4735](https://github.com/kubernetes-sigs/external-dns/pull/4735)) _@stevehipwell_ ### Fixed @@ -31,7 +137,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed to add correct webhook metric port to `Service` and `ServiceMonitor`. ([#4643](https://github.com/kubernetes-sigs/external-dns/pull/4643)) _@kimsondrup_ - Fixed to no longer require the unauthenticated webhook provider port to be exposed for health probes. ([#4691](https://github.com/kubernetes-sigs/external-dns/pull/4691)) _@kimsondrup_ & _@hatrx_ -## [v1.14.5] - 2023-06-10 +## [v1.14.5] - 2024-06-10 ### Added @@ -48,7 +154,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed the `ServiceMonitor` job name to correctly use the instance label. ([#4541](https://github.com/kubernetes-sigs/external-dns/pull/4541)) _@stevehipwell_ -## [v1.14.4] - 2023-04-03 +## [v1.14.4] - 2024-04-05 ### Added @@ -59,7 +165,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated _ExternalDNS_ OCI image version to [v0.14.1](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.14.1). ([#4357](https://github.com/kubernetes-sigs/external-dns/pull/4357)) _@stevehipwell_ -## [v1.14.3] - 2023-01-26 +## [v1.14.3] - 2024-01-26 ### Fixed @@ -73,7 +179,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Restore template support in `.Values.provider` and `.Values.provider.name` -## [v1.14.1] - 2024-01-11 +## [v1.14.1] - 2024-01-12 ### Fixed @@ -97,7 +203,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `secretConfiguration` value has been deprecated in favour of creating secrets external to the Helm chart and configuring their use via the `extraVolumes` & `extraVolumeMounts` values. ([#4161](https://github.com/kubernetes-sigs/external-dns/pull/4161)) [@stevehipwell](https://github.com/stevehipwell) -## [v1.13.1] - 2023-09-07 +## [v1.13.1] - 2023-09-08 ### Added @@ -200,6 +306,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 RELEASE LINKS --> [UNRELEASED]: https://github.com/kubernetes-sigs/external-dns/tree/master/charts/external-dns +[v1.20.0]: https://github.com/kubernetes-sigs/external-dns/releases/tag/external-dns-helm-chart-1.20.0 +[v1.19.0]: https://github.com/kubernetes-sigs/external-dns/releases/tag/external-dns-helm-chart-1.19.0 +[v1.18.0]: https://github.com/kubernetes-sigs/external-dns/releases/tag/external-dns-helm-chart-1.18.0 +[v1.17.0]: https://github.com/kubernetes-sigs/external-dns/releases/tag/external-dns-helm-chart-1.17.0 +[v1.16.1]: https://github.com/kubernetes-sigs/external-dns/releases/tag/external-dns-helm-chart-1.16.1 +[v1.16.0]: https://github.com/kubernetes-sigs/external-dns/releases/tag/external-dns-helm-chart-1.16.0 +[v1.15.2]: https://github.com/kubernetes-sigs/external-dns/releases/tag/external-dns-helm-chart-1.15.2 +[v1.15.1]: https://github.com/kubernetes-sigs/external-dns/releases/tag/external-dns-helm-chart-1.15.1 [v1.15.0]: https://github.com/kubernetes-sigs/external-dns/releases/tag/external-dns-helm-chart-1.15.0 [v1.14.5]: https://github.com/kubernetes-sigs/external-dns/releases/tag/external-dns-helm-chart-1.14.5 [v1.14.4]: https://github.com/kubernetes-sigs/external-dns/releases/tag/external-dns-helm-chart-1.14.4 diff --git a/packages/system/external-dns/charts/external-dns/Chart.yaml b/packages/system/external-dns/charts/external-dns/Chart.yaml index c7245bd1..a03ace4e 100644 --- a/packages/system/external-dns/charts/external-dns/Chart.yaml +++ b/packages/system/external-dns/charts/external-dns/Chart.yaml @@ -1,28 +1,30 @@ annotations: - artifacthub.io/changes: | + artifacthub.io/changes: |- + - kind: added + description: "Add option to set annotationPrefix (#5889) @lexfrei." - kind: changed - description: "Updated _ExternalDNS_ OCI image version to [v0.15.0](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.15.0)." + description: "Grant networking.k8s.io/ingresses and gateway.solo.io/gateways permissions when using gloo-proxy source." + - kind: changed + description: "Update ExternalDNS OCI image version to v0.20.0." - kind: fixed - description: "Fixed `provider.webhook.resources` behavior to correctly leverage resource limits." + description: "Fixed the missing schema for .provider.webhook." - kind: fixed - description: "Fixed `provider.webhook.imagePullPolicy` behavior to correctly leverage pull policy." - - kind: fixed - description: "Fixed to add correct webhook metric port to `Service` and `ServiceMonitor`." - - kind: fixed - description: "Fixed to no longer require the unauthenticated webhook provider port to be exposed for health probes." + description: "Fixed incorrect indentation of selector labels under spec.template.spec.topologySpreadConstraints when topologySpreadConstraints is set." apiVersion: v2 -appVersion: 0.15.0 +appVersion: 0.20.0 description: ExternalDNS synchronizes exposed Kubernetes Services and Ingresses with DNS providers. home: https://github.com/kubernetes-sigs/external-dns/ icon: https://github.com/kubernetes-sigs/external-dns/raw/master/docs/img/external-dns.png keywords: - kubernetes +- k8s - externaldns - external-dns - dns - service - ingress +- gateway maintainers: - email: steve.hipwell@gmail.com name: stevehipwell @@ -30,4 +32,4 @@ name: external-dns sources: - https://github.com/kubernetes-sigs/external-dns/ type: application -version: 1.15.0 +version: 1.20.0 diff --git a/packages/system/external-dns/charts/external-dns/README.md b/packages/system/external-dns/charts/external-dns/README.md index 9b21ecde..0bbae925 100644 --- a/packages/system/external-dns/charts/external-dns/README.md +++ b/packages/system/external-dns/charts/external-dns/README.md @@ -1,6 +1,6 @@ # external-dns -![Version: 1.15.0](https://img.shields.io/badge/Version-1.15.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.15.0](https://img.shields.io/badge/AppVersion-0.15.0-informational?style=flat-square) +![Version: 1.20.0](https://img.shields.io/badge/Version-1.20.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.20.0](https://img.shields.io/badge/AppVersion-0.20.0-informational?style=flat-square) ExternalDNS synchronizes exposed Kubernetes Services and Ingresses with DNS providers. @@ -27,12 +27,15 @@ helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/ After you've installed the repo you can install the chart. ```shell -helm upgrade --install external-dns external-dns/external-dns --version 1.15.0 +helm upgrade --install external-dns external-dns/external-dns --version 1.20.0 ``` ## Providers -Configuring the _ExternalDNS_ provider should be done via the `provider.name` value with provider specific configuration being set via the `provider..` values, where supported, and the `extraArgs` value. For legacy support `provider` can be set to the name of the provider with all additional configuration being set via the `extraArgs` value. +> Legacy support of setting `provider: ` is deprecated. + +Configuring the _ExternalDNS_ provider should be done via the `provider.name` value with provider specific configuration being set via the `provider..` values, where supported, and the `extraArgs` value. + See [documentation](https://kubernetes-sigs.github.io/external-dns/#new-providers) for more info on available providers and tutorials. ### Providers with Specific Configuration Support @@ -45,13 +48,13 @@ See [documentation](https://kubernetes-sigs.github.io/external-dns/#new-provider For set up for a specific provider using the Helm chart, see the following links: -- [AWS](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/aws.md#using-helm-with-oidc) -- [akamai-edgedns](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/akamai-edgedns.md#using-helm) -- [cloudflare](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/cloudflare.md#using-helm) -- [digitalocean](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/digitalocean.md#using-helm) -- [godaddy](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/godaddy.md#using-helm) -- [ns1](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/ns1.md#using-helm) -- [plural](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/plural.md#using-helm) +* [AWS](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/aws.md#using-helm-with-oidc) +* [akamai-edgedns](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/akamai-edgedns.md#using-helm) +* [cloudflare](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/cloudflare.md#using-helm) +* [digitalocean](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/digitalocean.md#using-helm) +* [godaddy](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/godaddy.md#using-helm) +* [ns1](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/ns1.md#using-helm) +* [plural](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/plural.md#using-helm) ## Namespaced Scoped Installation @@ -91,36 +94,43 @@ If `namespaced` is set to `true`, please ensure that `sources` my only contains | Key | Type | Default | Description | |-----|------|---------|-------------| | affinity | object | `{}` | Affinity settings for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). If an explicit label selector is not provided for pod affinity or pod anti-affinity one will be created from the pod selector labels. | -| automountServiceAccountToken | bool | `nil` | Set this to `false` to [opt out of API credential automounting](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#opt-out-of-api-credential-automounting) for the `Pod`. | +| annotationFilter | string | `nil` | Filter resources queried for endpoints by annotation selector. | +| annotationPrefix | string | `nil` | Annotation prefix for external-dns annotations (useful for split horizon DNS with multiple instances). | +| automountServiceAccountToken | bool | `true` | Set this to `false` to [opt out of API credential automounting](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#opt-out-of-api-credential-automounting) for the `Pod`. | | commonLabels | object | `{}` | Labels to add to all chart resources. | | deploymentAnnotations | object | `{}` | Annotations to add to the `Deployment`. | | deploymentStrategy | object | `{"type":"Recreate"}` | [Deployment Strategy](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy). | | dnsConfig | object | `nil` | [DNS config](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config) for the pod, if not set the default will be used. | | dnsPolicy | string | `nil` | [DNS policy](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy) for the pod, if not set the default will be used. | -| domainFilters | list | `[]` | | +| domainFilters | list | `[]` | Limit possible target zones by domain suffixes. | +| enabled | bool | `nil` | No effect - reserved for use in sub-charting. | | env | list | `[]` | [Environment variables](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) for the `external-dns` container. | -| excludeDomains | list | `[]` | | -| extraArgs | list | `[]` | Extra arguments to provide to _ExternalDNS_. | -| extraContainers | object | `{}` | Extra containers to add to the `Deployment`. | +| excludeDomains | list | `[]` | Intentionally exclude domains from being managed. | +| extraArgs | object | `{}` | Extra arguments to provide to _ExternalDNS_. An array or map can be used, with maps allowing for value overrides; maps also support slice values to use the same arg multiple times. | +| extraContainers | list | `[]` | Extra containers to add to the `Deployment`. | | extraVolumeMounts | list | `[]` | Extra [volume mounts](https://kubernetes.io/docs/concepts/storage/volumes/) for the `external-dns` container. | | extraVolumes | list | `[]` | Extra [volumes](https://kubernetes.io/docs/concepts/storage/volumes/) for the `Pod`. | | fullnameOverride | string | `nil` | Override the full name of the chart. | +| gatewayNamespace | string | `nil` | _Gateway API_ gateway namespace to watch. | +| global.imagePullSecrets | list | `[]` | Global image pull secrets. | | image.pullPolicy | string | `"IfNotPresent"` | Image pull policy for the `external-dns` container. | | image.repository | string | `"registry.k8s.io/external-dns/external-dns"` | Image repository for the `external-dns` container. | | image.tag | string | `nil` | Image tag for the `external-dns` container, this will default to `.Chart.AppVersion` if not set. | | imagePullSecrets | list | `[]` | Image pull secrets. | | initContainers | list | `[]` | [Init containers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) to add to the `Pod` definition. | | interval | string | `"1m"` | Interval for DNS updates. | +| labelFilter | string | `nil` | Filter resources queried for endpoints by label selector. | | livenessProbe | object | See _values.yaml_ | [Liveness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) configuration for the `external-dns` container. | | logFormat | string | `"text"` | Log format. | | logLevel | string | `"info"` | Log level. | +| managedRecordTypes | list | `[]` | Record types to manage (default: A, AAAA, CNAME) | | nameOverride | string | `nil` | Override the name of the chart. | | namespaced | bool | `false` | if `true`, _ExternalDNS_ will run in a namespaced scope (`Role`` and `Rolebinding`` will be namespaced too). | | nodeSelector | object | `{}` | Node labels to match for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). | | podAnnotations | object | `{}` | Annotations to add to the `Pod`. | | podLabels | object | `{}` | Labels to add to the `Pod`. | | podSecurityContext | object | See _values.yaml_ | [Pod security context](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#podsecuritycontext-v1-core), this supports full customisation. | -| policy | string | `"upsert-only"` | How DNS records are synchronized between sources and providers; available values are `sync` & `upsert-only`. | +| policy | string | `"upsert-only"` | How DNS records are synchronized between sources and providers; available values are `create-only`, `sync`, & `upsert-only`. | | priorityClassName | string | `nil` | Priority class name for the `Pod`. | | provider.name | string | `"aws"` | _ExternalDNS_ provider name; for the available providers and how to configure them see [README](https://github.com/kubernetes-sigs/external-dns/blob/master/charts/external-dns/README.md#providers). | | provider.webhook.args | list | `[]` | Extra arguments to provide for the `webhook` container. | @@ -147,11 +157,11 @@ If `namespaced` is set to `true`, please ensure that `sources` my only contains | secretConfiguration.subPath | string | `nil` | Sub-path for mounting the `Secret`, this can be templated. | | securityContext | object | See _values.yaml_ | [Security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) for the `external-dns` container. | | service.annotations | object | `{}` | Service annotations. | -| service.ipFamilies | list | `[]` | Service IP families. | +| service.ipFamilies | list | `[]` | Service IP families (e.g. IPv4 and/or IPv6). | | service.ipFamilyPolicy | string | `nil` | Service IP family policy. | | service.port | int | `7979` | Service HTTP port. | -| serviceAccount.annotations | object | `{}` | Annotations to add to the service account. | -| serviceAccount.automountServiceAccountToken | string | `nil` | Set this to `false` to [opt out of API credential automounting](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#opt-out-of-api-credential-automounting) for the `ServiceAccount`. | +| serviceAccount.annotations | object | `{}` | Annotations to add to the service account. Templates are allowed in both the key and the value. Example: `example.com/annotation/{{ .Values.nameOverride }}: {{ .Values.nameOverride }}` | +| serviceAccount.automountServiceAccountToken | bool | `true` | Set this to `false` to [opt out of API credential automounting](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#opt-out-of-api-credential-automounting) for the `ServiceAccount`. | | serviceAccount.create | bool | `true` | If `true`, create a new `ServiceAccount`. | | serviceAccount.labels | object | `{}` | Labels to add to the service account. | | serviceAccount.name | string | `nil` | If this is set and `serviceAccount.create` is `true` this will be used for the created `ServiceAccount` name, if set and `serviceAccount.create` is `false` then this will define an existing `ServiceAccount` to use. | @@ -173,7 +183,7 @@ If `namespaced` is set to `true`, please ensure that `sources` my only contains | tolerations | list | `[]` | Node taints which will be tolerated for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). | | topologySpreadConstraints | list | `[]` | Topology spread constraints for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). If an explicit label selector is not provided one will be created from the pod selector labels. | | triggerLoopOnEvent | bool | `false` | If `true`, triggers run loop on create/update/delete events in addition of regular interval. | -| txtOwnerId | string | `nil` | Specify an identifier for this instance of _ExternalDNS_ wWhen using a registry other than `noop`. | +| txtOwnerId | string | `nil` | Specify an identifier for this instance of _ExternalDNS_ when using a registry other than `noop`. | | txtPrefix | string | `nil` | Specify a prefix for the domain names of TXT records created for the `txt` registry. Mutually exclusive with `txtSuffix`. | | txtSuffix | string | `nil` | Specify a suffix for the domain names of TXT records created for the `txt` registry. Mutually exclusive with `txtPrefix`. | diff --git a/packages/system/external-dns/charts/external-dns/README.md.gotmpl b/packages/system/external-dns/charts/external-dns/README.md.gotmpl index e313a2ba..fc4ada14 100644 --- a/packages/system/external-dns/charts/external-dns/README.md.gotmpl +++ b/packages/system/external-dns/charts/external-dns/README.md.gotmpl @@ -27,7 +27,10 @@ helm upgrade --install {{ template "chart.name" . }} external-dns/{{ template "c ## Providers -Configuring the _ExternalDNS_ provider should be done via the `provider.name` value with provider specific configuration being set via the `provider..` values, where supported, and the `extraArgs` value. For legacy support `provider` can be set to the name of the provider with all additional configuration being set via the `extraArgs` value. +> Legacy support of setting `provider: ` is deprecated. + +Configuring the _ExternalDNS_ provider should be done via the `provider.name` value with provider specific configuration being set via the `provider..` values, where supported, and the `extraArgs` value. + See [documentation](https://kubernetes-sigs.github.io/external-dns/#new-providers) for more info on available providers and tutorials. ### Providers with Specific Configuration Support @@ -40,13 +43,13 @@ See [documentation](https://kubernetes-sigs.github.io/external-dns/#new-provider For set up for a specific provider using the Helm chart, see the following links: -- [AWS](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/aws.md#using-helm-with-oidc) -- [akamai-edgedns](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/akamai-edgedns.md#using-helm) -- [cloudflare](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/cloudflare.md#using-helm) -- [digitalocean](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/digitalocean.md#using-helm) -- [godaddy](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/godaddy.md#using-helm) -- [ns1](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/ns1.md#using-helm) -- [plural](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/plural.md#using-helm) +* [AWS](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/aws.md#using-helm-with-oidc) +* [akamai-edgedns](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/akamai-edgedns.md#using-helm) +* [cloudflare](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/cloudflare.md#using-helm) +* [digitalocean](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/digitalocean.md#using-helm) +* [godaddy](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/godaddy.md#using-helm) +* [ns1](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/ns1.md#using-helm) +* [plural](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/plural.md#using-helm) ## Namespaced Scoped Installation diff --git a/packages/system/external-dns/charts/external-dns/RELEASE.md b/packages/system/external-dns/charts/external-dns/RELEASE.md index 02634a30..956cb0b5 100644 --- a/packages/system/external-dns/charts/external-dns/RELEASE.md +++ b/packages/system/external-dns/charts/external-dns/RELEASE.md @@ -1,10 +1,13 @@ +### Added + +- Add option to set `annotationPrefix` ([#5889](https://github.com/kubernetes-sigs/external-dns/pull/5889)) _@lexfrei_ + ### Changed -- Updated _ExternalDNS_ OCI image version to [v0.15.0](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.15.0). ([#xxxx](https://github.com/kubernetes-sigs/external-dns/pull/xxxx)) _@stevehipwell_ +- Grant `networking.k8s.io/ingresses` and `gateway.solo.io/gateways` permissions when using `gloo-proxy` source. ([#5909](https://github.com/kubernetes-sigs/external-dns/pull/5909)) _@cucxabong_ +- Update _ExternalDNS_ OCI image version to [v0.20.0](https://github.com/kubernetes-sigs/external-dns/releases/tag/v0.20.0). ([#6005](https://github.com/kubernetes-sigs/external-dns/pull/6005)) _@vflaux_ ### Fixed -- Fixed `provider.webhook.resources` behavior to correctly leverage resource limits. ([#4560](https://github.com/kubernetes-sigs/external-dns/pull/4560)) _@crutonjohn_ -- Fixed `provider.webhook.imagePullPolicy` behavior to correctly leverage pull policy. ([#4643](https://github.com/kubernetes-sigs/external-dns/pull/4643)) _@kimsondrup_ -- Fixed to add correct webhook metric port to `Service` and `ServiceMonitor`. ([#4643](https://github.com/kubernetes-sigs/external-dns/pull/4643)) _@kimsondrup_ -- Fixed to no longer require the unauthenticated webhook provider port to be exposed for health probes. ([#4691](https://github.com/kubernetes-sigs/external-dns/pull/4691)) _@kimsondrup_ & _@hatrx_ +- Fixed the missing schema for `.provider.webhook.serviceMonitor` configs ([#5932](https://github.com/kubernetes-sigs/external-dns/pull/5932)) _@chrisbsmith_ +- Fixed incorrect indentation of selector labels under `spec.template.spec.topologySpreadConstraints` when `topologySpreadConstraints` is set. ([#6054](https://github.com/kubernetes-sigs/external-dns/pull/6054)) _@andylim0221_ diff --git a/packages/system/external-dns/charts/external-dns/ci/ci-values.yaml b/packages/system/external-dns/charts/external-dns/ci/ci-values.yaml deleted file mode 100644 index 4d278e94..00000000 --- a/packages/system/external-dns/charts/external-dns/ci/ci-values.yaml +++ /dev/null @@ -1,2 +0,0 @@ -provider: - name: inmemory diff --git a/packages/system/external-dns/charts/external-dns/crds/dnsendpoint.yaml b/packages/system/external-dns/charts/external-dns/crds/dnsendpoints.externaldns.k8s.io.yaml similarity index 82% rename from packages/system/external-dns/charts/external-dns/crds/dnsendpoint.yaml rename to packages/system/external-dns/charts/external-dns/crds/dnsendpoints.externaldns.k8s.io.yaml index 822cd850..c983c8d7 100644 --- a/packages/system/external-dns/charts/external-dns/crds/dnsendpoint.yaml +++ b/packages/system/external-dns/charts/external-dns/crds/dnsendpoints.externaldns.k8s.io.yaml @@ -1,9 +1,9 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: - name: dnsendpoints.externaldns.k8s.io annotations: api-approved.kubernetes.io: https://github.com/kubernetes-sigs/external-dns/pull/2007 + name: dnsendpoints.externaldns.k8s.io spec: group: externaldns.k8s.io names: @@ -16,6 +16,9 @@ spec: - name: v1alpha1 schema: openAPIV3Schema: + description: |- + DNSEndpoint is a contract that a user-specified CRD must implement to be used as a source for external-dns. + The user-specified CRD should also have the status sub-resource. properties: apiVersion: description: |- @@ -39,9 +42,7 @@ spec: properties: endpoints: items: - description: - Endpoint is a high-level way of a connection between - a service and an IP + description: Endpoint is a high-level way of a connection between a service and an IP properties: dnsName: description: The hostname of the DNS record @@ -54,9 +55,7 @@ spec: providerSpecific: description: ProviderSpecific stores provider specific config items: - description: - ProviderSpecificProperty holds the name and value - of a configuration which is specific to individual DNS providers + description: ProviderSpecificProperty holds the name and value of a configuration which is specific to individual DNS providers properties: name: type: string @@ -69,15 +68,10 @@ spec: format: int64 type: integer recordType: - description: - RecordType type of record, e.g. CNAME, A, AAAA, - SRV, TXT etc + description: RecordType type of record, e.g. CNAME, A, AAAA, SRV, TXT etc type: string setIdentifier: - description: - Identifier to distinguish multiple records with - the same name and type (e.g. Route53 records with routing - policies other than 'simple') + description: Identifier to distinguish multiple records with the same name and type (e.g. Route53 records with routing policies other than 'simple') type: string targets: description: The targets the DNS record points to diff --git a/packages/system/external-dns/charts/external-dns/templates/NOTES.txt b/packages/system/external-dns/charts/external-dns/templates/NOTES.txt index 5e37ecca..dedcff42 100644 --- a/packages/system/external-dns/charts/external-dns/templates/NOTES.txt +++ b/packages/system/external-dns/charts/external-dns/templates/NOTES.txt @@ -5,3 +5,14 @@ App version: {{ .Chart.AppVersion }} Image tag: {{ include "external-dns.image" . }} *********************************************************************** + +{{- if eq (typeOf .Values.provider) "string" }} +🚧 DEPRECATIONS 🚧 + +The following features, functions, or methods are deprecated and no longer recommended for use. + +{{/* The deprecation message for legacy 'provider: name'. */}} +{{- if eq (typeOf .Values.provider) "string" -}} +❗❗❗ DEPRECATED ❗❗❗ The legacy 'provider: ' configuration is in use. Support will be removed in future releases. +{{- end -}} +{{- end }} diff --git a/packages/system/external-dns/charts/external-dns/templates/_helpers.tpl b/packages/system/external-dns/charts/external-dns/templates/_helpers.tpl index 3ce55cd8..aad09822 100644 --- a/packages/system/external-dns/charts/external-dns/templates/_helpers.tpl +++ b/packages/system/external-dns/charts/external-dns/templates/_helpers.tpl @@ -73,6 +73,7 @@ The image to use {{/* Provider name, Keeps backward compatibility on provider +TODO: line eq (typeOf .Values.provider) "string" to be removed in future releases */}} {{- define "external-dns.providerName" -}} {{- if eq (typeOf .Values.provider) "string" }} @@ -93,3 +94,21 @@ The image to use for optional webhook sidecar {{- printf "%s:%s" .repository .tag }} {{- end }} {{- end }} + +{{/* +The pod affinity default label Selector +*/}} +{{- define "external-dns.labelSelector" -}} +labelSelector: + matchLabels: + {{ include "external-dns.selectorLabels" . | nindent 4 }} +{{- end }} + +{{/* +Check if any Gateway API sources are enabled +*/}} +{{- define "external-dns.hasGatewaySources" -}} +{{- if or (has "gateway-httproute" .Values.sources) (has "gateway-grpcroute" .Values.sources) (has "gateway-tlsroute" .Values.sources) (has "gateway-tcproute" .Values.sources) (has "gateway-udproute" .Values.sources) -}} +true +{{- end -}} +{{- end }} diff --git a/packages/system/external-dns/charts/external-dns/templates/clusterrole.yaml b/packages/system/external-dns/charts/external-dns/templates/clusterrole.yaml index 44f72bd2..b3ef006c 100644 --- a/packages/system/external-dns/charts/external-dns/templates/clusterrole.yaml +++ b/packages/system/external-dns/charts/external-dns/templates/clusterrole.yaml @@ -18,10 +18,15 @@ rules: {{- end }} {{- if or (has "service" .Values.sources) (has "contour-httpproxy" .Values.sources) (has "gloo-proxy" .Values.sources) (has "istio-gateway" .Values.sources) (has "istio-virtualservice" .Values.sources) (has "openshift-route" .Values.sources) (has "skipper-routegroup" .Values.sources) }} - apiGroups: [""] - resources: ["services","endpoints"] + resources: ["services"] verbs: ["get","watch","list"] {{- end }} -{{- if or (has "ingress" .Values.sources) (has "contour-httpproxy" .Values.sources) (has "openshift-route" .Values.sources) (has "skipper-routegroup" .Values.sources) }} +{{- if has "service" .Values.sources }} + - apiGroups: ["discovery.k8s.io"] + resources: ["endpointslices"] + verbs: ["get","watch","list"] +{{- end }} +{{- if or (has "ingress" .Values.sources) (has "istio-gateway" .Values.sources) (has "istio-virtualservice" .Values.sources) (has "contour-httpproxy" .Values.sources) (has "openshift-route" .Values.sources) (has "skipper-routegroup" .Values.sources) (has "gloo-proxy" .Values.sources) }} - apiGroups: ["extensions","networking.k8s.io"] resources: ["ingresses"] verbs: ["get","watch","list"] @@ -55,13 +60,17 @@ rules: resources: ["dnsendpoints/status"] verbs: ["*"] {{- end }} -{{- if or (has "gateway-httproute" .Values.sources) (has "gateway-grpcroute" .Values.sources) (has "gateway-tlsroute" .Values.sources) (has "gateway-tcproute" .Values.sources) (has "gateway-udproute" .Values.sources) }} +{{- if include "external-dns.hasGatewaySources" . }} +{{- if or (not .Values.namespaced) (and .Values.namespaced (not .Values.gatewayNamespace)) }} - apiGroups: ["gateway.networking.k8s.io"] resources: ["gateways"] verbs: ["get","watch","list"] +{{- end }} +{{- if not .Values.namespaced }} - apiGroups: [""] resources: ["namespaces"] - verbs: ["get","watch","list"] + verbs: ["get","watch","list"] +{{- end }} {{- end }} {{- if has "gateway-httproute" .Values.sources }} - apiGroups: ["gateway.networking.k8s.io"] @@ -90,7 +99,7 @@ rules: {{- end }} {{- if has "gloo-proxy" .Values.sources }} - apiGroups: ["gloo.solo.io","gateway.solo.io"] - resources: ["proxies","virtualservices"] + resources: ["proxies","virtualservices","gateways"] verbs: ["get","watch","list"] {{- end }} {{- if has "kong-tcpingress" .Values.sources }} @@ -116,12 +125,39 @@ rules: resources: ["routegroups/status"] verbs: ["patch","update"] {{- end }} -{{- if has "f5-virtualserver" .Values.sources }} +{{- if or (has "f5-virtualserver" .Values.sources) (has "f5-transportserver" .Values.sources) }} - apiGroups: ["cis.f5.com"] - resources: ["virtualservers"] + resources: ["virtualservers", "transportservers"] verbs: ["get","watch","list"] {{- end }} {{- with .Values.rbac.additionalPermissions }} {{- toYaml . | nindent 2 }} {{- end }} +{{- if and .Values.rbac.create .Values.namespaced (include "external-dns.hasGatewaySources" .) }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "external-dns.fullname" . }}-namespaces + labels: + {{- include "external-dns.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: ["namespaces"] + verbs: ["get","watch","list"] +{{- if .Values.gatewayNamespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "external-dns.fullname" . }}-gateway + namespace: {{ .Values.gatewayNamespace }} + labels: + {{- include "external-dns.labels" . | nindent 4 }} +rules: + - apiGroups: ["gateway.networking.k8s.io"] + resources: ["gateways"] + verbs: ["get","watch","list"] +{{- end }} +{{- end }} {{- end }} diff --git a/packages/system/external-dns/charts/external-dns/templates/clusterrolebinding.yaml b/packages/system/external-dns/charts/external-dns/templates/clusterrolebinding.yaml index 74a51476..49400c0b 100644 --- a/packages/system/external-dns/charts/external-dns/templates/clusterrolebinding.yaml +++ b/packages/system/external-dns/charts/external-dns/templates/clusterrolebinding.yaml @@ -13,4 +13,39 @@ subjects: - kind: ServiceAccount name: {{ template "external-dns.serviceAccountName" . }} namespace: {{ .Release.Namespace }} +{{- if and .Values.rbac.create .Values.namespaced (include "external-dns.hasGatewaySources" .) }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "external-dns.fullname" . }}-namespaces + labels: + {{- include "external-dns.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "external-dns.fullname" . }}-namespaces +subjects: + - kind: ServiceAccount + name: {{ template "external-dns.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- if .Values.gatewayNamespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "external-dns.fullname" . }}-gateway + namespace: {{ .Values.gatewayNamespace }} + labels: + {{- include "external-dns.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "external-dns.fullname" . }}-gateway +subjects: + - kind: ServiceAccount + name: {{ template "external-dns.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} +{{- end }} {{- end }} diff --git a/packages/system/external-dns/charts/external-dns/templates/deployment.yaml b/packages/system/external-dns/charts/external-dns/templates/deployment.yaml index 02e9b397..b213f754 100644 --- a/packages/system/external-dns/charts/external-dns/templates/deployment.yaml +++ b/packages/system/external-dns/charts/external-dns/templates/deployment.yaml @@ -1,3 +1,4 @@ +{{- $defaultSelector := (include "external-dns.labelSelector" $ ) | fromYaml -}} {{- $providerName := tpl (include "external-dns.providerName" .) $ }} apiVersion: apps/v1 kind: Deployment @@ -40,7 +41,7 @@ spec: {{- if not (quote .Values.automountServiceAccountToken | empty) }} automountServiceAccountToken: {{ .Values.automountServiceAccountToken }} {{- end }} - {{- with .Values.imagePullSecrets }} + {{- with (default .Values.global.imagePullSecrets .Values.imagePullSecrets) }} imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} @@ -99,25 +100,59 @@ spec: {{- if .Values.txtOwnerId }} - --txt-owner-id={{ .Values.txtOwnerId }} {{- end }} + {{- if and .Values.txtPrefix .Values.txtSuffix }} + {{- fail (printf "'txtPrefix' and 'txtSuffix' are mutually exclusive") }} + {{- end }} {{- if .Values.txtPrefix }} - --txt-prefix={{ .Values.txtPrefix }} - {{- end }} - {{- if and (eq .Values.txtPrefix "") (ne .Values.txtSuffix "") }} + {{- else if .Values.txtSuffix }} - --txt-suffix={{ .Values.txtSuffix }} {{- end }} {{- if .Values.namespaced }} - --namespace={{ .Release.Namespace }} {{- end }} + {{- if .Values.gatewayNamespace }} + - --gateway-namespace={{ .Values.gatewayNamespace }} + {{- end }} {{- range .Values.domainFilters }} - --domain-filter={{ . }} {{- end }} {{- range .Values.excludeDomains }} - --exclude-domains={{ . }} {{- end }} + {{- if .Values.labelFilter }} + - --label-filter={{ .Values.labelFilter }} + {{- end }} + {{- if .Values.annotationFilter }} + - --annotation-filter={{ .Values.annotationFilter }} + {{- end }} + {{- if .Values.annotationPrefix }} + - --annotation-prefix={{ .Values.annotationPrefix }} + {{- end }} + {{- range .Values.managedRecordTypes }} + - --managed-record-types={{ . }} + {{- end }} - --provider={{ $providerName }} - {{- range .Values.extraArgs }} + {{- if kindIs "map" .Values.extraArgs }} + {{- range $key, $value := .Values.extraArgs }} + {{- if not (kindIs "invalid" $value) }} + {{- if kindIs "slice" $value }} + {{- range $value }} + - --{{ $key }}={{ tpl (. | toString) $ }} + {{- end }} + {{- else }} + - --{{ $key }}={{ tpl ($value | toString) $ }} + {{- end }} + {{- else }} + - --{{ $key }} + {{- end }} + {{- end }} + {{- end }} + {{- if kindIs "slice" .Values.extraArgs }} + {{- range .Values.extraArgs }} - {{ tpl . $ }} - {{- end }} + {{- end }} + {{- end }} ports: - name: http protocol: TCP @@ -197,11 +232,71 @@ spec: {{- end }} {{- with .Values.affinity }} affinity: - {{- toYaml . | nindent 8 }} + {{- with .nodeAffinity }} + nodeAffinity: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- with .podAffinity }} + podAffinity: + {{- with .preferredDuringSchedulingIgnoredDuringExecution }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- range . }} + - podAffinityTerm: + {{- if dig "podAffinityTerm" "labelSelector" nil . }} + {{- toYaml .podAffinityTerm | nindent 16 }} + {{- else }} + {{- (merge $defaultSelector .podAffinityTerm) | toYaml | nindent 16 }} + {{- end }} + weight: {{ .weight }} + {{- end }} + {{- end }} + {{- with .requiredDuringSchedulingIgnoredDuringExecution }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- range . }} + {{- if dig "labelSelector" nil . }} + - {{ toYaml . | indent 16 | trim }} + {{- else }} + - {{ (merge $defaultSelector .) | toYaml | indent 16 | trim }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- with .podAntiAffinity }} + podAntiAffinity: + {{- with .preferredDuringSchedulingIgnoredDuringExecution }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- range . }} + - podAffinityTerm: + {{- if dig "podAffinityTerm" "labelSelector" nil . }} + {{- toYaml .podAffinityTerm | nindent 16 }} + {{- else }} + {{- (merge $defaultSelector .podAffinityTerm) | toYaml | nindent 16 }} + {{- end }} + weight: {{ .weight }} + {{- end }} + {{- end }} + {{- with .requiredDuringSchedulingIgnoredDuringExecution }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- range . }} + {{- if dig "labelSelector" nil . }} + - {{ toYaml . | indent 16 | trim }} + {{- else }} + - {{ (merge $defaultSelector .) | toYaml | indent 16 | trim }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} {{- end }} {{- with .Values.topologySpreadConstraints }} topologySpreadConstraints: - {{- toYaml . | nindent 8 }} + {{- range . }} + - {{ toYaml . | nindent 10 | trim }} + {{- if not (hasKey . "labelSelector") }} + labelSelector: + matchLabels: + {{- include "external-dns.selectorLabels" $ | nindent 14 }} + {{- end }} + {{- end }} {{- end }} {{- with .Values.tolerations }} tolerations: diff --git a/packages/system/external-dns/charts/external-dns/templates/serviceaccount.yaml b/packages/system/external-dns/charts/external-dns/templates/serviceaccount.yaml index f627313a..27196a2a 100644 --- a/packages/system/external-dns/charts/external-dns/templates/serviceaccount.yaml +++ b/packages/system/external-dns/charts/external-dns/templates/serviceaccount.yaml @@ -11,7 +11,9 @@ metadata: {{- end }} {{- with .Values.serviceAccount.annotations }} annotations: - {{- toYaml . | nindent 4 }} + {{- range $k, $v := . }} + {{- printf "%s: %s" (toYaml (tpl $k $)) (toYaml (tpl $v $)) | nindent 4 }} + {{- end }} {{- end }} automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} {{- end }} diff --git a/packages/system/external-dns/charts/external-dns/values.schema.json b/packages/system/external-dns/charts/external-dns/values.schema.json index 614deeac..b4c5e3a4 100644 --- a/packages/system/external-dns/charts/external-dns/values.schema.json +++ b/packages/system/external-dns/charts/external-dns/values.schema.json @@ -1,54 +1,697 @@ { - "$schema": "http://json-schema.org/draft-07/schema", + "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { - "provider": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "name": { - "type": "string" - } - } - } + "affinity": { + "description": "Affinity settings for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). If an explicit label selector is not provided for pod affinity or pod anti-affinity one will be created from the pod selector labels.", + "type": "object" + }, + "annotationFilter": { + "description": "Filter resources queried for endpoints by annotation selector.", + "type": [ + "string", + "null" ] }, + "annotationPrefix": { + "description": "Annotation prefix for external-dns annotations (useful for split horizon DNS with multiple instances).", + "type": [ + "string", + "null" + ] + }, + "automountServiceAccountToken": { + "description": "Set this to `false` to [opt out of API credential automounting](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#opt-out-of-api-credential-automounting) for the `Pod`.", + "type": "boolean" + }, + "commonLabels": { + "description": "Labels to add to all chart resources.", + "type": "object" + }, + "deploymentAnnotations": { + "description": "Annotations to add to the `Deployment`.", + "type": "object" + }, + "deploymentStrategy": { + "description": "[Deployment Strategy](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy).", + "type": "object", + "properties": { + "type": { + "default": "Recreate", + "type": "string", + "enum": [ + "Recreate", + "RollingUpdate" + ] + } + }, + "additionalProperties": true + }, + "dnsConfig": { + "description": "[DNS config](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config) for the pod, if not set the default will be used.", + "type": [ + "object", + "null" + ] + }, + "dnsPolicy": { + "description": "[DNS policy](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy) for the pod, if not set the default will be used.", + "type": [ + "string", + "null" + ] + }, + "domainFilters": { + "description": "Limit possible target zones by domain suffixes.", + "type": "array" + }, + "enabled": { + "description": "No effect - reserved for use in sub-charting", + "type": [ + "boolean", + "null" + ] + }, + "env": { + "description": "[Environment variables](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) for the `external-dns` container.", + "type": "array" + }, + "excludeDomains": { + "description": "Intentionally exclude domains from being managed.", + "type": "array" + }, "extraArgs": { - "type": "array", + "description": "Extra arguments to provide to _ExternalDNS_. An array or map can be used, with maps allowing for value overrides; maps also support slice values to use the same arg multiple times.", + "type": [ + "array", + "null", + "object" + ], + "uniqueItems": true, "items": { "type": "string" } }, - "secretConfiguration": { - "$comment": "This value is DEPRECATED as secrets should be configured external to the chart and exposed to the container via extraVolumes & extraVolumeMounts.", + "extraContainers": { + "description": "Extra containers to add to the `Deployment`.", + "type": "array" + }, + "extraVolumeMounts": { + "description": "Extra [volume mounts](https://kubernetes.io/docs/concepts/storage/volumes/) for the `external-dns` container.", + "type": "array" + }, + "extraVolumes": { + "description": "Extra [volumes](https://kubernetes.io/docs/concepts/storage/volumes/) for the `Pod`.", + "type": "array" + }, + "fullnameOverride": { + "description": "Override the full name of the chart.", + "type": [ + "string", + "null" + ] + }, + "gatewayNamespace": { + "description": "_Gateway API_ gateway namespace to watch.", + "type": [ + "string", + "null" + ] + }, + "global": { "type": "object", "properties": { + "imagePullSecrets": { + "description": "Global image pull secrets.", + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "description": "Image pull policy for the `external-dns` container.", + "type": "string", + "enum": [ + "IfNotPresent", + "Always" + ] + }, + "repository": { + "description": "Image repository for the `external-dns` container.", + "type": "string" + }, + "tag": { + "description": "Image tag for the `external-dns` container, this will default to `.Chart.AppVersion` if not set.", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "imagePullSecrets": { + "description": "Image pull secrets.", + "type": "array", + "items": { + "type": "object" + } + }, + "initContainers": { + "description": "[Init containers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) to add to the `Pod` definition.", + "type": "array" + }, + "interval": { + "description": "Interval for DNS updates.", + "type": "string" + }, + "labelFilter": { + "description": "Filter resources queried for endpoints by label selector.", + "type": [ + "string", + "null" + ] + }, + "livenessProbe": { + "description": "[Liveness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) configuration for the `external-dns` container.", + "type": "object", + "properties": { + "failureThreshold": { + "type": "integer" + }, + "httpGet": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "port": { + "type": "string" + } + } + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "logFormat": { + "description": "Log format.", + "default": "text", + "type": "string", + "enum": [ + "text", + "json" + ] + }, + "logLevel": { + "description": "Log level.", + "default": "info", + "type": "string", + "enum": [ + "panic", + "debug", + "info", + "warning", + "error", + "fatal" + ] + }, + "managedRecordTypes": { + "description": "Record types to manage (default: A, AAAA, CNAME)", + "type": [ + "array", + "null" + ], + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "nameOverride": { + "description": "Override the name of the chart.", + "type": [ + "string", + "null" + ] + }, + "namespaced": { + "description": "if `true`, _ExternalDNS_ will run in a namespaced scope (`Role`` and `Rolebinding`` will be namespaced too).", + "type": "boolean" + }, + "nodeSelector": { + "description": "Node labels to match for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/).", + "type": "object" + }, + "podAnnotations": { + "description": "Annotations to add to the `Pod`.", + "type": "object" + }, + "podLabels": { + "description": "Labels to add to the `Pod`.", + "type": "object" + }, + "podSecurityContext": { + "description": "[Pod security context](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#podsecuritycontext-v1-core), this supports full customisation.", + "type": "object", + "properties": { + "fsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "seccompProfile": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + } + } + } + }, + "policy": { + "description": "How DNS records are synchronized between sources and providers; available values are `create-only`, `sync`, \u0026 `upsert-only`.", + "default": "upsert-only", + "type": "string", + "enum": [ + "create-only", + "sync", + "upsert-only" + ] + }, + "priorityClassName": { + "description": "Priority class name for the `Pod`.", + "type": [ + "string", + "null" + ] + }, + "provider": { + "type": [ + "object", + "string" + ], + "properties": { + "name": { + "description": "_ExternalDNS_ provider name; for the available providers and how to configure them see [README](https://github.com/kubernetes-sigs/external-dns/blob/master/charts/external-dns/README.md#providers).", + "type": "string" + }, + "webhook": { + "type": "object", + "properties": { + "args": { + "description": "Extra arguments to provide for the `webhook` container.", + "type": "array" + }, + "env": { + "description": "[Environment variables](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) for the `webhook` container.", + "type": "array" + }, + "extraVolumeMounts": { + "description": "Extra [volume mounts](https://kubernetes.io/docs/concepts/storage/volumes/) for the `webhook` container.", + "type": "array" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "description": "Image pull policy for the `webhook` container.", + "type": "string" + }, + "repository": { + "description": "Image repository for the `webhook` container.", + "type": [ + "string", + "null" + ] + }, + "tag": { + "description": "Image tag for the `webhook` container.", + "type": [ + "string", + "null" + ] + } + } + }, + "limits": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + }, + "livenessProbe": { + "description": "[Liveness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) configuration for the `external-dns` container.", + "type": "object", + "properties": { + "failureThreshold": { + "type": [ + "integer", + "null" + ] + }, + "httpGet": { + "type": "object", + "properties": { + "path": { + "type": [ + "string", + "null" + ] + }, + "port": { + "default": "string", + "type": [ + "integer", + "string" + ] + } + } + }, + "initialDelaySeconds": { + "type": [ + "integer", + "null" + ] + }, + "periodSeconds": { + "type": [ + "integer", + "null" + ] + }, + "successThreshold": { + "type": [ + "integer", + "null" + ] + }, + "timeoutSeconds": { + "type": [ + "integer", + "null" + ] + } + } + }, + "readinessProbe": { + "description": "[Readiness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) configuration for the `webhook` container.", + "type": "object", + "properties": { + "failureThreshold": { + "type": [ + "integer", + "null" + ] + }, + "httpGet": { + "type": "object", + "properties": { + "path": { + "type": [ + "string", + "null" + ] + }, + "port": { + "default": "string", + "type": [ + "integer", + "string" + ] + } + } + }, + "initialDelaySeconds": { + "type": [ + "integer", + "null" + ] + }, + "periodSeconds": { + "type": [ + "integer", + "null" + ] + }, + "successThreshold": { + "type": [ + "integer", + "null" + ] + }, + "timeoutSeconds": { + "type": [ + "integer", + "null" + ] + } + } + }, + "requests": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + }, + "resources": { + "description": "[Resources](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) for the `webhook` container.", + "type": "object" + }, + "securityContext": { + "description": "[Pod security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) for the `webhook` container.", + "type": "object" + }, + "service": { + "type": "object", + "properties": { + "port": { + "description": "Webhook exposed HTTP port for the service.", + "type": "integer" + } + } + }, + "serviceMonitor": { + "description": "Optional [Service Monitor](https://prometheus-operator.dev/docs/operator/design/#servicemonitor) configuration for the `webhook` container.", + "type": "object", + "properties": { + "bearerTokenFile": { + "type": [ + "string", + "null" + ] + }, + "interval": { + "type": [ + "string", + "null" + ] + }, + "metricRelabelings": { + "type": "array" + }, + "relabelings": { + "type": "array" + }, + "scheme": { + "type": [ + "string", + "null" + ] + }, + "scrapeTimeout": { + "type": [ + "string", + "null" + ] + }, + "tlsConfig": { + "type": "object" + } + } + } + } + } + } + }, + "rbac": { + "type": "object", + "properties": { + "additionalPermissions": { + "description": "Additional rules to add to the `ClusterRole`.", + "type": "array" + }, + "create": { + "description": "If `true`, create a `ClusterRole` \u0026 `ClusterRoleBinding` with access to the Kubernetes API.", + "type": "boolean" + } + }, + "additionalProperties": true + }, + "readinessProbe": { + "description": "[Readiness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) configuration for the `external-dns` container.", + "type": "object", + "properties": { + "failureThreshold": { + "type": "integer" + }, + "httpGet": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "port": { + "type": "string" + } + } + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "registry": { + "description": "Specify the registry for storing ownership and labels. Valid values are `txt`, `aws-sd`, `dynamodb` \u0026 `noop`.", + "default": "txt", + "type": "string", + "enum": [ + "txt", + "aws-sd", + "dynamodb", + "noop" + ] + }, + "resources": { + "description": "[Resources](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) for the `external-dns` container.", + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + }, + "requests": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + } + } + }, + "revisionHistoryLimit": { + "description": "Specify the number of old `ReplicaSets` to retain to allow rollback of the `Deployment``.", + "type": [ + "integer", + "null" + ], + "minimum": 0 + }, + "secretConfiguration": { + "type": "object", + "properties": { + "data": { + "description": "`Secret` data.", + "type": "object" + }, "enabled": { + "description": "If `true`, create a `Secret` to store sensitive provider configuration (**DEPRECATED**).", "type": "boolean" }, "mountPath": { + "description": "Mount path for the `Secret`, this can be templated.", "type": [ "string", "null" ] }, "subPath": { + "description": "Sub-path for mounting the `Secret`, this can be templated.", "type": [ "string", "null" ] + } + } + }, + "securityContext": { + "description": "[Security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) for the `external-dns` container.", + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" }, - "data": { + "capabilities": { "type": "object", - "patternProperties": { - ".+": { - "type": "string" + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } } } + }, + "privileged": { + "type": "boolean" + }, + "readOnlyRootFilesystem": { + "type": "boolean" + }, + "runAsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" } } }, @@ -56,36 +699,194 @@ "type": "object", "properties": { "annotations": { + "description": "Service annotations.", "type": "object" }, "ipFamilies": { - "type": "array", + "description": "Service IP families (e.g. IPv4 and/or IPv6).", + "type": [ + "array", + "null" + ], + "maxItems": 2, + "minItems": 0, + "uniqueItems": true, "items": { "type": "string", "enum": [ - "IPv6", - "IPv4" + "IPv4", + "IPv6" ] } }, "ipFamilyPolicy": { + "description": "Service IP family policy.", "type": [ "string", "null" ], - "items": { - "type": "string", - "enum": [ - "SingleStack", - "PreferDualStack", - "RequireDualStack" - ] - } + "enum": [ + "SingleStack", + "PreferDualStack", + "RequireDualStack", + null + ] }, "port": { - "type": "integer" + "description": "Service HTTP port.", + "default": 7979, + "type": "integer", + "minimum": 0 } } + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "description": "Annotations to add to the service account. Templates are allowed in both the key and the value. Example: `example.com/annotation/{{ .Values.nameOverride }}: {{ .Values.nameOverride }}`", + "type": "object" + }, + "automountServiceAccountToken": { + "description": "Set this to `false` to [opt out of API credential automounting](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#opt-out-of-api-credential-automounting) for the `ServiceAccount`.", + "type": "boolean" + }, + "create": { + "description": "If `true`, create a new `ServiceAccount`.", + "type": "boolean" + }, + "labels": { + "description": "Labels to add to the service account.", + "type": "object" + }, + "name": { + "description": "If this is set and `serviceAccount.create` is `true` this will be used for the created `ServiceAccount` name, if set and `serviceAccount.create` is `false` then this will define an existing `ServiceAccount` to use.", + "type": [ + "string", + "null" + ] + } + } + }, + "serviceMonitor": { + "type": "object", + "properties": { + "additionalLabels": { + "description": "Additional labels for the `ServiceMonitor`.", + "type": "object" + }, + "annotations": { + "description": "Annotations to add to the `ServiceMonitor`.", + "type": "object" + }, + "bearerTokenFile": { + "description": "Provide a bearer token file for the `ServiceMonitor`.", + "type": [ + "string", + "null" + ] + }, + "enabled": { + "description": "If `true`, create a `ServiceMonitor` resource to support the _Prometheus Operator_.", + "type": "boolean" + }, + "interval": { + "description": "If set override the _Prometheus_ default interval.", + "type": [ + "string", + "null" + ] + }, + "metricRelabelings": { + "description": "[Metric relabel configs](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs) to apply to samples before ingestion.", + "type": "array" + }, + "namespace": { + "description": "If set create the `ServiceMonitor` in an alternate namespace.", + "type": [ + "string", + "null" + ] + }, + "relabelings": { + "description": "[Relabel configs](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config) to apply to samples before ingestion.", + "type": "array" + }, + "scheme": { + "description": "If set overrides the _Prometheus_ default scheme.", + "type": [ + "string", + "null" + ] + }, + "scrapeTimeout": { + "description": "If set override the _Prometheus_ default scrape timeout.", + "type": [ + "string", + "null" + ] + }, + "targetLabels": { + "description": "Provide target labels for the `ServiceMonitor`.", + "type": "array" + }, + "tlsConfig": { + "description": "Configure the `ServiceMonitor` [TLS config](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#tlsconfig).", + "type": "object" + } + } + }, + "shareProcessNamespace": { + "description": "If `true`, the `Pod` will have [process namespace sharing](https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/) enabled.", + "type": "boolean" + }, + "sources": { + "description": "_Kubernetes_ resources to monitor for DNS entries.", + "type": "array", + "items": { + "type": "string" + } + }, + "terminationGracePeriodSeconds": { + "description": "Termination grace period for the `Pod` in seconds.", + "type": [ + "integer", + "null" + ] + }, + "tolerations": { + "description": "Node taints which will be tolerated for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/).", + "type": "array" + }, + "topologySpreadConstraints": { + "description": "Topology spread constraints for `Pod` [scheduling](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). If an explicit label selector is not provided one will be created from the pod selector labels.", + "type": "array" + }, + "triggerLoopOnEvent": { + "description": "If `true`, triggers run loop on create/update/delete events in addition of regular interval.", + "type": "boolean" + }, + "txtOwnerId": { + "description": "Specify an identifier for this instance of _ExternalDNS_ when using a registry other than `noop`.", + "type": [ + "string", + "null" + ] + }, + "txtPrefix": { + "description": "Specify a prefix for the domain names of TXT records created for the `txt` registry. Mutually exclusive with `txtSuffix`.", + "type": [ + "string", + "null" + ] + }, + "txtSuffix": { + "description": "Specify a suffix for the domain names of TXT records created for the `txt` registry. Mutually exclusive with `txtPrefix`.", + "type": [ + "string", + "null" + ] } - } + }, + "additionalProperties": true } diff --git a/packages/system/external-dns/charts/external-dns/values.yaml b/packages/system/external-dns/charts/external-dns/values.yaml index 9d7dea1b..46fbe8f7 100644 --- a/packages/system/external-dns/charts/external-dns/values.yaml +++ b/packages/system/external-dns/charts/external-dns/values.yaml @@ -2,22 +2,26 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -image: +global: + # -- Global image pull secrets. + imagePullSecrets: [] # @schema item: object + +image: # @schema additionalProperties: false # -- Image repository for the `external-dns` container. repository: registry.k8s.io/external-dns/external-dns - # -- (string) Image tag for the `external-dns` container, this will default to `.Chart.AppVersion` if not set. - tag: + # -- Image tag for the `external-dns` container, this will default to `.Chart.AppVersion` if not set. + tag: # @schema type:[string, null] # -- Image pull policy for the `external-dns` container. - pullPolicy: IfNotPresent + pullPolicy: IfNotPresent # @schema enum:[IfNotPresent, Always] # -- Image pull secrets. -imagePullSecrets: [] +imagePullSecrets: [] # @schema item: object # -- (string) Override the name of the chart. -nameOverride: +nameOverride: # @schema type:[string, null]; default: null # -- (string) Override the full name of the chart. -fullnameOverride: +fullnameOverride: # @schema type:[string, null]; default: null # -- Labels to add to all chart resources. commonLabels: {} @@ -27,24 +31,26 @@ serviceAccount: create: true # -- Labels to add to the service account. labels: {} - # -- Annotations to add to the service account. + # -- Annotations to add to the service account. Templates are allowed in both the key and the value. Example: `example.com/annotation/{{ .Values.nameOverride }}: {{ .Values.nameOverride }}` annotations: {} # -- (string) If this is set and `serviceAccount.create` is `true` this will be used for the created `ServiceAccount` name, if set and `serviceAccount.create` is `false` then this will define an existing `ServiceAccount` to use. - name: + name: # @schema type:[string, null]; default: null # -- Set this to `false` to [opt out of API credential automounting](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#opt-out-of-api-credential-automounting) for the `ServiceAccount`. - automountServiceAccountToken: + automountServiceAccountToken: true service: # -- Service annotations. annotations: {} # -- Service HTTP port. - port: 7979 - # -- Service IP families. - ipFamilies: [] - # -- (string) Service IP family policy. - ipFamilyPolicy: + port: 7979 # @schema minimum:0; default:7979 + # -- Service IP families (e.g. IPv4 and/or IPv6). + ipFamilies: [] # @schema type: [array, null]; item: string; itemEnum: ["IPv4", "IPv6"]; minItems:0; maxItems:2; uniqueItems: true + # - IPv4 + # - IPv6 + # -- Service IP family policy. + ipFamilyPolicy: # @schema type: [string, null]; enum:[SingleStack, PreferDualStack, RequireDualStack, null] -rbac: +rbac: # @schema additionalProperties: true # -- If `true`, create a `ClusterRole` & `ClusterRoleBinding` with access to the Kubernetes API. create: true # -- Additional rules to add to the `ClusterRole`. @@ -54,14 +60,14 @@ rbac: deploymentAnnotations: {} # -- Extra containers to add to the `Deployment`. -extraContainers: {} +extraContainers: [] # -- [Deployment Strategy](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy). -deploymentStrategy: - type: Recreate +deploymentStrategy: # @schema additionalProperties: true + type: Recreate # @schema enum:[Recreate, RollingUpdate]; type:string; default: Recreate # -- (int) Specify the number of old `ReplicaSets` to retain to allow rollback of the `Deployment``. -revisionHistoryLimit: +revisionHistoryLimit: # @schema type:[integer, null];minimum:0 # -- Labels to add to the `Pod`. podLabels: {} @@ -70,7 +76,7 @@ podLabels: {} podAnnotations: {} # -- (bool) Set this to `false` to [opt out of API credential automounting](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#opt-out-of-api-credential-automounting) for the `Pod`. -automountServiceAccountToken: +automountServiceAccountToken: true # -- If `true`, the `Pod` will have [process namespace sharing](https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/) enabled. shareProcessNamespace: false @@ -84,16 +90,16 @@ podSecurityContext: type: RuntimeDefault # -- (string) Priority class name for the `Pod`. -priorityClassName: +priorityClassName: # @schema type:[string, null]; default: null # -- (int) Termination grace period for the `Pod` in seconds. -terminationGracePeriodSeconds: +terminationGracePeriodSeconds: # @schema type:[integer, null] # -- (string) [DNS policy](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy) for the pod, if not set the default will be used. -dnsPolicy: +dnsPolicy: # @schema type:[string, null]; default: null # -- (object) [DNS config](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config) for the pod, if not set the default will be used. -dnsConfig: +dnsConfig: # @schema type:[object, null]; default: null # -- [Init containers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) to add to the `Pod` definition. initContainers: [] @@ -166,17 +172,17 @@ serviceMonitor: # -- Annotations to add to the `ServiceMonitor`. annotations: {} # -- (string) If set create the `ServiceMonitor` in an alternate namespace. - namespace: + namespace: # @schema type:[string, null]; default: null # -- (string) If set override the _Prometheus_ default interval. - interval: + interval: # @schema type:[string, null]; default: null # -- (string) If set override the _Prometheus_ default scrape timeout. - scrapeTimeout: + scrapeTimeout: # @schema type:[string, null]; default: null # -- (string) If set overrides the _Prometheus_ default scheme. - scheme: + scheme: # @schema type:[string, null]; default: null # -- Configure the `ServiceMonitor` [TLS config](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#tlsconfig). tlsConfig: {} # -- (string) Provide a bearer token file for the `ServiceMonitor`. - bearerTokenFile: + bearerTokenFile: # @schema type:[string, null]; default: null # -- [Relabel configs](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config) to apply to samples before ingestion. relabelings: [] # -- [Metric relabel configs](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#metric_relabel_configs) to apply to samples before ingestion. @@ -185,10 +191,10 @@ serviceMonitor: targetLabels: [] # -- Log level. -logLevel: info +logLevel: info # @schema enum:[panic, debug, info, warning, error, fatal]; type:string; default: "info" # -- Log format. -logFormat: text +logFormat: text # @schema enum:["text", "json"]; type:string; default: "text" # -- Interval for DNS updates. interval: 1m @@ -199,41 +205,56 @@ triggerLoopOnEvent: false # -- if `true`, _ExternalDNS_ will run in a namespaced scope (`Role`` and `Rolebinding`` will be namespaced too). namespaced: false +# -- _Gateway API_ gateway namespace to watch. +gatewayNamespace: # @schema type:[string, null]; default: null + # -- _Kubernetes_ resources to monitor for DNS entries. sources: - service - ingress -# -- How DNS records are synchronized between sources and providers; available values are `sync` & `upsert-only`. -policy: upsert-only +# -- How DNS records are synchronized between sources and providers; available values are `create-only`, `sync`, & `upsert-only`. +policy: upsert-only # @schema enum:[create-only, sync, upsert-only]; type:string; default: "upsert-only" # -- Specify the registry for storing ownership and labels. # Valid values are `txt`, `aws-sd`, `dynamodb` & `noop`. -registry: txt -# -- (string) Specify an identifier for this instance of _ExternalDNS_ wWhen using a registry other than `noop`. -txtOwnerId: +registry: txt # @schema enum:[txt, aws-sd, dynamodb, noop]; default: "txt" +# -- (string) Specify an identifier for this instance of _ExternalDNS_ when using a registry other than `noop`. +txtOwnerId: # @schema type:[string, null]; default: null # -- (string) Specify a prefix for the domain names of TXT records created for the `txt` registry. # Mutually exclusive with `txtSuffix`. -txtPrefix: +txtPrefix: # @schema type:[string, null]; default: null # -- (string) Specify a suffix for the domain names of TXT records created for the `txt` registry. # Mutually exclusive with `txtPrefix`. -txtSuffix: +txtSuffix: # @schema type:[string, null]; default: null -## - Limit possible target zones by domain suffixes. +# -- Limit possible target zones by domain suffixes. domainFilters: [] -## -- Intentionally exclude domains from being managed. +# -- Intentionally exclude domains from being managed. excludeDomains: [] -provider: +# -- Filter resources queried for endpoints by label selector. +labelFilter: # @schema type: [string,null]; default: null + +# -- Filter resources queried for endpoints by annotation selector. +annotationFilter: # @schema type: [string,null]; default: null + +# -- Annotation prefix for external-dns annotations (useful for split horizon DNS with multiple instances). +annotationPrefix: # @schema type: [string,null]; default: null + +# -- Record types to manage (default: A, AAAA, CNAME) +managedRecordTypes: [] # @schema type: [array, null]; item: string; uniqueItems: true + +provider: # @schema type: [object, string] # -- _ExternalDNS_ provider name; for the available providers and how to configure them see [README](https://github.com/kubernetes-sigs/external-dns/blob/master/charts/external-dns/README.md#providers). name: aws webhook: image: # -- (string) Image repository for the `webhook` container. - repository: + repository: # @schema type:[string, null]; default: null # -- (string) Image tag for the `webhook` container. - tag: + tag: # @schema type:[string, null]; default: null # -- Image pull policy for the `webhook` container. pullPolicy: IfNotPresent # -- [Environment variables](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) for the `webhook` container. @@ -251,47 +272,51 @@ provider: # @default -- See _values.yaml_ livenessProbe: httpGet: - path: /healthz - port: http-webhook - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 2 - successThreshold: 1 + path: /healthz # @schema type:[string, null]; default: null + port: http-webhook # @schema type:[integer,string]; default: string + initialDelaySeconds: 10 # @schema type:[integer, null]; default: null + periodSeconds: 10 # @schema type:[integer, null]; default: null + timeoutSeconds: 5 # @schema type:[integer, null]; default: null + failureThreshold: 2 # @schema type:[integer, null]; default: null + successThreshold: 1 # @schema type:[integer, null]; default: null # -- [Readiness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) configuration for the `webhook` container. # @default -- See _values.yaml_ readinessProbe: httpGet: - path: /healthz - port: http-webhook - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 + path: /healthz # @schema type:[string, null]; default: null + port: http-webhook # @schema type:[integer,string]; default: string + initialDelaySeconds: 5 # @schema type:[integer, null]; default: null + periodSeconds: 10 # @schema type:[integer, null]; default: null + timeoutSeconds: 5 # @schema type:[integer, null]; default: null + failureThreshold: 6 # @schema type:[integer, null]; default: null + successThreshold: 1 # @schema type:[integer, null]; default: null service: # -- Webhook exposed HTTP port for the service. port: 8080 # -- Optional [Service Monitor](https://prometheus-operator.dev/docs/operator/design/#servicemonitor) configuration for the `webhook` container. # @default -- See _values.yaml_ serviceMonitor: - interval: - scheme: + interval: # @schema type:[string, null]; default: null + scheme: # @schema type:[string, null]; default: null tlsConfig: {} - bearerTokenFile: - scrapeTimeout: + bearerTokenFile: # @schema type:[string, null]; default: null + scrapeTimeout: # @schema type:[string, null]; default: null metricRelabelings: [] relabelings: [] # -- Extra arguments to provide to _ExternalDNS_. -extraArgs: [] +# An array or map can be used, with maps allowing for value overrides; maps also support slice values to use the same arg multiple times. +extraArgs: {} # @schema type: [array, null, object]; item: string; uniqueItems: true secretConfiguration: # -- If `true`, create a `Secret` to store sensitive provider configuration (**DEPRECATED**). enabled: false # -- Mount path for the `Secret`, this can be templated. - mountPath: + mountPath: # @schema type:[string, null]; default: null # -- Sub-path for mounting the `Secret`, this can be templated. - subPath: + subPath: # @schema type:[string, null]; default: null # -- `Secret` data. data: {} + +# -- (bool) No effect - reserved for use in sub-charting. +enabled: # @schema type: [boolean, null]; description: No effect - reserved for use in sub-charting diff --git a/packages/system/external-secrets-operator/Makefile b/packages/system/external-secrets-operator/Makefile index f4d9215d..0e1cd83a 100644 --- a/packages/system/external-secrets-operator/Makefile +++ b/packages/system/external-secrets-operator/Makefile @@ -1,7 +1,7 @@ export NAME=external-secrets-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/flux-plunger/Chart.yaml b/packages/system/flux-plunger/Chart.yaml new file mode 100644 index 00000000..b87ca73a --- /dev/null +++ b/packages/system/flux-plunger/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: cozy-flux-plunger +description: Controller that automatically fixes HelmRelease resources with "has no deployed releases" error +type: application +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process +appVersion: "1.0.0" diff --git a/packages/system/flux-plunger/Makefile b/packages/system/flux-plunger/Makefile new file mode 100644 index 00000000..e1a561af --- /dev/null +++ b/packages/system/flux-plunger/Makefile @@ -0,0 +1,19 @@ +export NAME=flux-plunger +export NAMESPACE=cozy-fluxcd + +include ../../../scripts/common-envs.mk +include ../../../hack/package.mk + +image: + docker buildx build -f images/flux-plunger/Dockerfile ../../../ \ + --provenance false \ + --tag $(REGISTRY)/flux-plunger:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/flux-plunger:latest \ + --cache-to type=inline \ + --metadata-file images/flux-plunger.json \ + --push=$(PUSH) \ + --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ + --load=$(LOAD) + IMAGE="$(REGISTRY)/flux-plunger:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/flux-plunger.json -o json -r)" \ + yq -i '.image = strenv(IMAGE)' values.yaml + rm -f images/flux-plunger.json diff --git a/packages/system/flux-plunger/images/flux-plunger/Dockerfile b/packages/system/flux-plunger/images/flux-plunger/Dockerfile new file mode 100644 index 00000000..37821699 --- /dev/null +++ b/packages/system/flux-plunger/images/flux-plunger/Dockerfile @@ -0,0 +1,23 @@ +FROM golang:1.25-alpine AS builder + +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /workspace + +COPY go.mod go.sum ./ +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go mod download + +COPY pkg pkg/ +COPY cmd cmd/ +COPY internal internal/ +COPY api api/ + +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -ldflags="-extldflags=-static" -o /flux-plunger cmd/flux-plunger/main.go + +FROM scratch + +COPY --from=builder /flux-plunger /flux-plunger +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt + +ENTRYPOINT ["/flux-plunger"] diff --git a/packages/system/flux-plunger/templates/deployment.yaml b/packages/system/flux-plunger/templates/deployment.yaml new file mode 100644 index 00000000..7ce6bb13 --- /dev/null +++ b/packages/system/flux-plunger/templates/deployment.yaml @@ -0,0 +1,55 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: flux-plunger + labels: + app.kubernetes.io/name: flux-plunger + app.kubernetes.io/instance: {{ .Release.Name }} +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: flux-plunger + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: flux-plunger + app.kubernetes.io/instance: {{ .Release.Name }} + spec: + serviceAccountName: flux-plunger + containers: + - name: flux-plunger + image: "{{ .Values.image }}" + args: + {{- if .Values.debug }} + - --zap-log-level=debug + {{- else }} + - --zap-log-level=info + {{- end }} + - --metrics-bind-address=:8080 + - --metrics-secure=false + ports: + - name: metrics + containerPort: 8080 + - name: health + containerPort: 8081 + livenessProbe: + httpGet: + path: /healthz + port: health + initialDelaySeconds: 15 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /readyz + port: health + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi diff --git a/packages/system/flux-plunger/templates/rbac.yaml b/packages/system/flux-plunger/templates/rbac.yaml new file mode 100644 index 00000000..97d4eac7 --- /dev/null +++ b/packages/system/flux-plunger/templates/rbac.yaml @@ -0,0 +1,37 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: flux-plunger +rules: +- apiGroups: + - helm.toolkit.fluxcd.io + resources: + - helmreleases + verbs: + - get + - list + - watch + - update + - patch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - delete +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: flux-plunger +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: flux-plunger +subjects: +- kind: ServiceAccount + name: flux-plunger + namespace: {{ .Release.Namespace }} diff --git a/packages/system/flux-plunger/templates/service.yaml b/packages/system/flux-plunger/templates/service.yaml new file mode 100644 index 00000000..69aa6afb --- /dev/null +++ b/packages/system/flux-plunger/templates/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: flux-plunger + labels: + app.kubernetes.io/name: flux-plunger + app.kubernetes.io/instance: {{ .Release.Name }} +spec: + selector: + app.kubernetes.io/name: flux-plunger + app.kubernetes.io/instance: {{ .Release.Name }} + ports: + - name: metrics + port: 8080 + targetPort: 8080 + - name: health + port: 8081 + targetPort: 8081 diff --git a/packages/system/flux-plunger/templates/serviceaccount.yaml b/packages/system/flux-plunger/templates/serviceaccount.yaml new file mode 100644 index 00000000..aff76a13 --- /dev/null +++ b/packages/system/flux-plunger/templates/serviceaccount.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +automountServiceAccountToken: true +kind: ServiceAccount +metadata: + name: flux-plunger + labels: + app.kubernetes.io/name: flux-plunger + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/packages/system/flux-plunger/values.yaml b/packages/system/flux-plunger/values.yaml new file mode 100644 index 00000000..1da12610 --- /dev/null +++ b/packages/system/flux-plunger/values.yaml @@ -0,0 +1 @@ +image: "ghcr.io/cozystack/cozystack/flux-plunger:latest@sha256:6a6ec938973e6583c5e1573f7d25beddc1852a6699a089116b2407e29a564a72" diff --git a/packages/system/fluxcd-operator/Makefile b/packages/system/fluxcd-operator/Makefile index f41360ee..d9778f53 100644 --- a/packages/system/fluxcd-operator/Makefile +++ b/packages/system/fluxcd-operator/Makefile @@ -1,12 +1,13 @@ NAME=fluxcd-operator NAMESPACE=cozy-fluxcd -include ../../../scripts/package.mk +include ../../../hack/package.mk apply-locally: - cozypkg apply --plain -n $(NAMESPACE) $(NAME) + cozyhr apply --plain -n $(NAMESPACE) $(NAME) update: rm -rf charts helm pull oci://ghcr.io/controlplaneio-fluxcd/charts/flux-operator --untar --untardir charts patch --no-backup-if-mismatch -p1 < patches/kubernetesEnvs.diff + patch --no-backup-if-mismatch -p1 < patches/networkPolicy.diff diff --git a/packages/system/fluxcd-operator/charts/flux-operator/Chart.yaml b/packages/system/fluxcd-operator/charts/flux-operator/Chart.yaml index 1a25710a..d59dedfa 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.23.0 +appVersion: v0.33.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.23.0 +version: 0.33.0 diff --git a/packages/system/fluxcd-operator/charts/flux-operator/README.md b/packages/system/fluxcd-operator/charts/flux-operator/README.md index 1f07648e..036fc534 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.23.0](https://img.shields.io/badge/Version-0.23.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.23.0](https://img.shields.io/badge/AppVersion-v0.23.0-informational?style=flat-square) +![Version: 0.33.0](https://img.shields.io/badge/Version-0.33.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.33.0](https://img.shields.io/badge/AppVersion-v0.33.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 @@ -38,6 +38,8 @@ see the Flux Operator [documentation](https://fluxcd.control-plane.io/operator/) | commonLabels | object | `{}` | Common labels to add to all deployed objects including pods. | | extraArgs | list | `[]` | Container extra arguments. | | extraEnvs | list | `[]` | Container extra environment variables. | +| extraVolumeMounts | list | `[]` | Container extra volume mounts. | +| extraVolumes | list | `[]` | Pod extra volumes. | | fullnameOverride | string | `""` | | | hostNetwork | bool | `false` | If `true`, the container ports (`8080` and `8081`) are exposed on the host network. | | image | object | `{"imagePullPolicy":"IfNotPresent","pullSecrets":[],"repository":"ghcr.io/controlplaneio-fluxcd/flux-operator","tag":""}` | Container image settings. The image tag defaults to the chart appVersion. | @@ -45,7 +47,7 @@ see the Flux Operator [documentation](https://fluxcd.control-plane.io/operator/) | livenessProbe | object | `{"httpGet":{"path":"/healthz","port":8081},"initialDelaySeconds":15,"periodSeconds":20}` | Container liveness probe settings. | | logLevel | string | `"info"` | Container logging level flag. | | marketplace | object | `{"account":"","license":"","type":""}` | Marketplace settings. | -| multitenancy | object | `{"defaultServiceAccount":"flux-operator","enabled":false}` | Enable [multitenancy lockdown](https://fluxcd.control-plane.io/operator/resourceset/#role-based-access-control) for the ResourceSet APIs. | +| multitenancy | object | `{"defaultServiceAccount":"flux-operator","defaultWorkloadIdentityServiceAccount":"flux-operator","enabled":false,"enabledForWorkloadIdentity":false}` | Enable [multitenancy lockdown](https://fluxcd.control-plane.io/operator/resourceset/#role-based-access-control) for the ResourceSet APIs. | | nameOverride | string | `""` | | | nodeSelector | object | `{}` | Pod Node Selector settings. | | podSecurityContext | object | `{}` | Pod security context settings. | @@ -54,7 +56,7 @@ see the Flux Operator [documentation](https://fluxcd.control-plane.io/operator/) | rbac.createAggregation | bool | `true` | Grant the Kubernetes view, edit and admin roles access to ResourceSet APIs. | | readinessProbe | object | `{"httpGet":{"path":"/readyz","port":8081},"initialDelaySeconds":5,"periodSeconds":10}` | Container readiness probe settings. | | reporting | object | `{"interval":"5m"}` | Flux [reporting](https://fluxcd.control-plane.io/operator/fluxreport/) settings. | -| resources | object | `{"limits":{"cpu":"1000m","memory":"1Gi"},"requests":{"cpu":"100m","memory":"64Mi"}}` | Container resources requests and limits settings. | +| resources | object | `{"limits":{"cpu":"2000m","memory":"1Gi"},"requests":{"cpu":"100m","memory":"64Mi"}}` | Container resources requests and limits settings. | | securityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}` | Container security context settings. The default is compliant with the pod security restricted profile. | | serviceAccount | object | `{"automount":true,"create":true,"name":""}` | Pod service account settings. The name of the service account defaults to the release name. | | serviceMonitor | object | `{"create":false,"interval":"60s","labels":{},"scrapeTimeout":"30s"}` | Prometheus Operator scraping settings. | 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 29be5039..fdd6fe76 100644 --- a/packages/system/fluxcd-operator/charts/flux-operator/templates/crds.yaml +++ b/packages/system/fluxcd-operator/charts/flux-operator/templates/crds.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.19.0 helm.sh/resource-policy: keep labels: app.kubernetes.io/instance: '{{ .Release.Name }}' @@ -73,6 +73,12 @@ spec: description: Multitenant enables the multitenancy lockdown. Defaults to false. type: boolean + multitenantWorkloadIdentity: + default: false + description: |- + MultitenantWorkloadIdentity enables the multitenancy lockdown for + workload identity. Defaults to false. + type: boolean networkPolicy: default: true description: |- @@ -85,10 +91,39 @@ spec: required for object-level workload identity. This feature is only available in Flux v2.6.0 and later. type: boolean + size: + description: |- + Size defines the vertical scaling profile of the Flux controllers. + The size is used to determine the concurrency and CPU/Memory limits for the Flux controllers. + Accepted values are: 'small', 'medium' and 'large'. + enum: + - small + - medium + - large + type: string + tenantDefaultDecryptionServiceAccount: + description: |- + TenantDefaultDecryptionServiceAccount is the name of the service account + to use as default for kustomize-controller SOPS decryption when the + multitenant lockdown for workload identity is enabled. Defaults to the + 'default' service account from the tenant namespace. + type: string + tenantDefaultKubeConfigServiceAccount: + description: |- + TenantDefaultKubeConfigServiceAccount is the name of the service account + to use as default for kustomize-controller and helm-controller remote + cluster access via spec.kubeConfig.configMapRef when the multitenant + lockdown for workload identity is enabled. Defaults to the 'default' + service account from the tenant namespace. + type: string tenantDefaultServiceAccount: description: |- TenantDefaultServiceAccount is the name of the service account - to use as default when the multitenant lockdown is enabled. + to use as default when the multitenant lockdown is enabled, for + kustomize-controller and helm-controller. + This field will also be used for multitenant workload identity + lockdown for source-controller, notification-controller, + image-reflector-controller and image-automation-controller. Defaults to the 'default' service account from the tenant namespace. type: string type: @@ -104,6 +139,11 @@ spec: - gcp type: string type: object + x-kubernetes-validations: + - message: .objectLevelWorkloadIdentity must be set to true when .multitenantWorkloadIdentity + is set to true + rule: (has(self.objectLevelWorkloadIdentity) && self.objectLevelWorkloadIdentity) + || !has(self.multitenantWorkloadIdentity) || !self.multitenantWorkloadIdentity commonMetadata: description: |- CommonMetadata specifies the common labels and annotations that are @@ -134,6 +174,7 @@ spec: - notification-controller - image-reflector-controller - image-automation-controller + - source-watcher type: string type: array distribution: @@ -162,6 +203,15 @@ spec: Registry address to pull the distribution images from e.g. 'ghcr.io/fluxcd'. type: string + variant: + description: |- + Variant specifies the Flux distribution flavor stored + in the registry. + enum: + - upstream-alpine + - enterprise-alpine + - enterprise-distroless + type: string version: description: Version semver expression e.g. '2.x', '2.3.x'. type: string @@ -448,6 +498,57 @@ spec: - type type: object type: array + history: + description: |- + History contains the reconciliation history of the FluxInstance + as a list of snapshots ordered by the last reconciled time. + items: + description: |- + Snapshot represents a point-in-time record of a group of resources reconciliation, + including timing information, status, and a unique digest identifier. + properties: + digest: + description: Digest is the checksum in the format `:` + of the resources in this snapshot. + type: string + firstReconciled: + description: FirstReconciled is the time when this revision + was first reconciled to the cluster. + format: date-time + type: string + lastReconciled: + description: LastReconciled is the time when this revision was + last reconciled to the cluster. + format: date-time + type: string + lastReconciledDuration: + description: LastReconciledDuration is time it took to reconcile + the resources in this revision. + type: string + lastReconciledStatus: + description: LastReconciledStatus is the status of the last + reconciliation. + type: string + metadata: + additionalProperties: + type: string + description: Metadata contains additional information about + the snapshot. + type: object + totalReconciliations: + description: TotalReconciliations is the total number of reconciliations + that have occurred for this snapshot. + format: int64 + type: integer + required: + - digest + - firstReconciled + - lastReconciled + - lastReconciledDuration + - lastReconciledStatus + - totalReconciliations + type: object + type: array inventory: description: |- Inventory contains a list of Kubernetes resource object references @@ -491,6 +592,12 @@ spec: LastAttemptedRevision is the version and digest of the distribution config that was last attempted to reconcile. type: string + lastHandledForceAt: + description: |- + LastHandledForceAt holds the value of the most recent + force request value, so a change of the annotation value + can be detected. + type: string lastHandledReconcileAt: description: |- LastHandledReconcileAt holds the value of the most recent @@ -511,7 +618,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.19.0 helm.sh/resource-policy: keep labels: app.kubernetes.io/instance: '{{ .Release.Name }}' @@ -586,6 +693,9 @@ spec: description: ServerVersion is the version of the Kubernetes API server. type: string + required: + - platform + - serverVersion type: object components: description: ComponentsStatus is the status of the Flux controller @@ -637,6 +747,23 @@ spec: - entitlement - status type: object + operator: + description: Operator is the version information of the Flux Operator. + properties: + apiVersion: + description: APIVersion is the API version of the Flux Operator. + type: string + platform: + description: Platform is the os/arch of Flux Operator. + type: string + version: + description: Version is the version number of Flux Operator. + type: string + required: + - apiVersion + - platform + - version + type: object reconcilers: description: |- ReconcilersStatus is the list of Flux reconcilers and @@ -794,7 +921,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.19.0 helm.sh/resource-policy: keep labels: app.kubernetes.io/instance: '{{ .Release.Name }}' @@ -858,8 +985,10 @@ spec: - a PEM-encoded CA certificate (`ca.crt`) - a PEM-encoded client certificate (`tls.crt`) and private key (`tls.key`) - When connecting to a Git provider that uses self-signed certificates, the CA certificate + When connecting to a Git or OCI provider that uses self-signed certificates, the CA certificate must be set in the Secret under the 'ca.crt' key to establish the trust relationship. + When connecting to an OCI provider that supports client certificates (mTLS), the client certificate + and private key must be set in the Secret under the 'tls.crt' and 'tls.key' keys, respectively. properties: name: description: Name of the referent. @@ -884,11 +1013,21 @@ spec: ExcludeBranch specifies the regular expression to filter the branches that the input provider should exclude. type: string + excludeTag: + description: |- + ExcludeTag specifies the regular expression to filter the tags + that the input provider should exclude. + type: string includeBranch: description: |- IncludeBranch specifies the regular expression to filter the branches that the input provider should include. type: string + includeTag: + description: |- + IncludeTag specifies the regular expression to filter the tags + that the input provider should include. + type: string labels: description: Labels specifies the list of labels to filter the input provider response. @@ -896,13 +1035,17 @@ spec: type: string type: array limit: + default: 100 description: |- Limit specifies the maximum number of input sets to return. When not set, the default limit is 100. type: integer semver: - description: Semver specifies the semantic version range to filter - and order the tags. + description: |- + Semver specifies a semantic version range to filter and sort the tags. + If this field is not specified, the tags will be sorted in reverse + alphabetical order. + Supported only for tags at the moment. type: string type: object schedule: @@ -933,10 +1076,12 @@ spec: secretRef: description: |- SecretRef specifies the Kubernetes Secret containing the basic-auth credentials - to access the input provider. The secret must contain the keys - 'username' and 'password'. - When connecting to a Git provider, the password should be a personal access token + to access the input provider. + When connecting to a Git provider, the secret must contain the keys + 'username' and 'password', and the password should be a personal access token that grants read-only access to the repository. + When connecting to an OCI provider, the secret must contain a Kubernetes + Image Pull Secret, as if created by `kubectl create secret docker-registry`. properties: name: description: Name of the referent. @@ -944,6 +1089,14 @@ spec: required: - name type: object + serviceAccountName: + description: |- + ServiceAccountName specifies the name of the Kubernetes ServiceAccount + used for authentication with AWS, Azure or GCP services through + workload identity federation features. If not specified, the + authentication for these cloud providers will use the ServiceAccount + of the operator (or any other environment authentication configuration). + type: string skip: description: Skip defines whether we need to skip input provider response updates. @@ -966,12 +1119,20 @@ spec: - GitLabBranch - GitLabTag - GitLabMergeRequest + - AzureDevOpsBranch + - AzureDevOpsTag + - AzureDevOpsPullRequest + - OCIArtifactTag + - ACRArtifactTag + - ECRArtifactTag + - GARArtifactTag type: string url: description: |- - URL specifies the HTTP/S address of the input provider API. + URL specifies the HTTP/S or OCI address of the input provider API. When connecting to a Git provider, the URL should point to the repository address. - pattern: ^((http|https)://.*){0,1}$ + When connecting to an OCI provider, the URL should point to the OCI repository address. + pattern: ^((http|https|oci)://.*){0,1}$ type: string required: - type @@ -981,6 +1142,27 @@ spec: rule: self.type != 'Static' || !has(self.url) - message: spec.url must not be empty when spec.type is not 'Static' rule: self.type == 'Static' || has(self.url) + - message: spec.url must start with 'http://' or 'https://' when spec.type + is a Git provider + rule: '!self.type.startsWith(''Git'') || self.url.startsWith(''http'')' + - message: spec.url must start with 'http://' or 'https://' when spec.type + is a Git provider + rule: '!self.type.startsWith(''AzureDevOps'') || self.url.startsWith(''http'')' + - message: spec.url must start with 'oci://' when spec.type is an OCI + provider + rule: '!self.type.endsWith(''ArtifactTag'') || self.url.startsWith(''oci'')' + - message: cannot specify spec.serviceAccountName when spec.type is not + one of AzureDevOps* or *ArtifactTag + rule: '!has(self.serviceAccountName) || self.type.startsWith(''AzureDevOps'') + || self.type.endsWith(''ArtifactTag'')' + - message: cannot specify spec.certSecretRef when spec.type is one of + Static, AzureDevOps*, ACRArtifactTag, ECRArtifactTag or GARArtifactTag + rule: '!has(self.certSecretRef) || !(self.url == ''Static'' || self.type.startsWith(''AzureDevOps'') + || (self.type.endsWith(''ArtifactTag'') && self.type != ''OCIArtifactTag''))' + - message: cannot specify spec.secretRef when spec.type is one of Static, + ACRArtifactTag, ECRArtifactTag or GARArtifactTag + rule: '!has(self.secretRef) || !(self.url == ''Static'' || (self.type.endsWith(''ArtifactTag'') + && self.type != ''OCIArtifactTag''))' status: description: ResourceSetInputProviderStatus defines the observed state of ResourceSetInputProvider. @@ -1107,7 +1289,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.19.0 helm.sh/resource-policy: keep labels: app.kubernetes.io/instance: '{{ .Release.Name }}' @@ -1215,6 +1397,34 @@ spec: - name type: object type: array + inputStrategy: + description: |- + InputStrategy defines how the inputs are combined when multiple + input provider objects are used. Defaults to flattening all inputs + from all providers into a single list of input sets. + properties: + name: + description: |- + Name defines how the inputs are combined when multiple + input provider objects are used. Supported values are: + - Flatten: all inputs sets from all input provider objects are + flattened into a single list of input sets. + - Permute: all inputs sets from all input provider objects are + combined using a Cartesian product, resulting in a list of input sets + that contains every possible combination of input values. + For example, if provider A has inputs [{x: 1}, {x: 2}] and provider B has + inputs [{y: "a"}, {y: "b"}], the resulting input sets will be: + [{x: 1, y: "a"}, {x: 1, y: "b"}, {x: 2, y: "a"}, {x: 2, y: "b"}]. + This strategy can lead to a large number of input sets and should be + used with caution. Users should use filtering features from + ResourceSetInputProvider to limit the amount of exported inputs. + enum: + - Flatten + - Permute + type: string + required: + - name + type: object inputs: description: Inputs contains the list of ResourceSet inputs. items: @@ -1238,6 +1448,8 @@ spec: description: |- APIVersion of the input provider resource. When not set, the APIVersion of the ResourceSet is used. + enum: + - fluxcd.controlplane.io/v1 type: string kind: description: Kind of the input provider resource. @@ -1297,8 +1509,6 @@ spec: type: object type: object x-kubernetes-map-type: atomic - required: - - kind type: object x-kubernetes-validations: - message: at least one of name or selector must be set for input @@ -1393,6 +1603,57 @@ spec: - type type: object type: array + history: + description: |- + History contains the reconciliation history of the ResourceSet + as a list of snapshots ordered by the last reconciled time. + items: + description: |- + Snapshot represents a point-in-time record of a group of resources reconciliation, + including timing information, status, and a unique digest identifier. + properties: + digest: + description: Digest is the checksum in the format `:` + of the resources in this snapshot. + type: string + firstReconciled: + description: FirstReconciled is the time when this revision + was first reconciled to the cluster. + format: date-time + type: string + lastReconciled: + description: LastReconciled is the time when this revision was + last reconciled to the cluster. + format: date-time + type: string + lastReconciledDuration: + description: LastReconciledDuration is time it took to reconcile + the resources in this revision. + type: string + lastReconciledStatus: + description: LastReconciledStatus is the status of the last + reconciliation. + type: string + metadata: + additionalProperties: + type: string + description: Metadata contains additional information about + the snapshot. + type: object + totalReconciliations: + description: TotalReconciliations is the total number of reconciliations + that have occurred for this snapshot. + format: int64 + type: integer + required: + - digest + - firstReconciled + - lastReconciled + - lastReconciledDuration + - lastReconciledStatus + - totalReconciliations + type: object + type: array inventory: description: |- Inventory contains a list of Kubernetes resource object references diff --git a/packages/system/fluxcd-operator/charts/flux-operator/templates/deployment.yaml b/packages/system/fluxcd-operator/charts/flux-operator/templates/deployment.yaml index 8767d972..cebc1cf1 100644 --- a/packages/system/fluxcd-operator/charts/flux-operator/templates/deployment.yaml +++ b/packages/system/fluxcd-operator/charts/flux-operator/templates/deployment.yaml @@ -53,6 +53,9 @@ spec: {{- if .Values.multitenancy.enabled }} - --default-service-account={{ .Values.multitenancy.defaultServiceAccount }} {{- end }} + {{- if .Values.multitenancy.enabledForWorkloadIdentity }} + - --default-workload-identity-service-account={{ .Values.multitenancy.defaultWorkloadIdentityServiceAccount }} + {{- end }} {{- range .Values.extraArgs }} - {{ . }} {{- end }} @@ -99,9 +102,15 @@ spec: volumeMounts: - name: temp mountPath: /tmp + {{- if .Values.extraVolumeMounts }} + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + {{- end }} volumes: - name: temp emptyDir: {} + {{- if .Values.extraVolumes }} + {{- toYaml .Values.extraVolumes | nindent 8 }} + {{- end }} {{- with .Values.affinity }} affinity: {{- toYaml . | nindent 8 }} diff --git a/packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml b/packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml new file mode 100644 index 00000000..f97ddba3 --- /dev/null +++ b/packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml @@ -0,0 +1,20 @@ +{{- if .Capabilities.APIVersions.Has "cilium.io/v2/CiliumClusterwideNetworkPolicy" }} +apiVersion: cilium.io/v2 +kind: CiliumClusterwideNetworkPolicy +metadata: + name: {{ include "flux-operator.fullname" . }}-restrict +spec: + nodeSelector: {} + ingressDeny: + - fromEntities: + - world + toPorts: + - ports: + - port: "8080" + protocol: TCP + - port: "8081" + protocol: TCP + ingress: + - fromEntities: + - cluster +{{- 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 dc277e55..6c42d4f8 100644 --- a/packages/system/fluxcd-operator/charts/flux-operator/values.schema.json +++ b/packages/system/fluxcd-operator/charts/flux-operator/values.schema.json @@ -1,5 +1,10 @@ { "$schema": "https://json-schema.org/draft/2019-09/schema", + "type": "object", + "required": [ + "resources", + "securityContext" + ], "properties": { "affinity": { "default": { @@ -21,16 +26,23 @@ } } }, + "type": "object", "properties": { "nodeAffinity": { + "type": "object", "properties": { "requiredDuringSchedulingIgnoredDuringExecution": { + "type": "object", "properties": { "nodeSelectorTerms": { + "type": "array", "items": { + "type": "object", "properties": { "matchExpressions": { + "type": "array", "items": { + "type": "object", "properties": { "key": { "type": "string" @@ -39,29 +51,22 @@ "type": "string" }, "values": { + "type": "array", "items": { "type": "string" - }, - "type": "array" + } } - }, - "type": "object" - }, - "type": "array" + } + } } - }, - "type": "object" - }, - "type": "array" + } + } } - }, - "type": "object" + } } - }, - "type": "object" + } } - }, - "type": "object" + } }, "apiPriority": { "default": { @@ -69,6 +74,7 @@ "extraServiceAccounts": [], "level": "workload-high" }, + "type": "object", "properties": { "enabled": { "type": "boolean" @@ -79,30 +85,41 @@ "level": { "type": "string" } - }, - "type": "object" + } }, "commonAnnotations": { - "properties": {}, "type": "object" }, "commonLabels": { - "properties": {}, "type": "object" }, "extraArgs": { + "type": "array", + "uniqueItems": true, "items": { "type": "string" - }, - "type": "array", - "uniqueItems": true + } }, "extraEnvs": { + "type": "array", + "uniqueItems": true, "items": { "type": "object" - }, + } + }, + "extraVolumeMounts": { "type": "array", - "uniqueItems": true + "uniqueItems": true, + "items": { + "type": "object" + } + }, + "extraVolumes": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "object" + } }, "fullnameOverride": { "type": "string" @@ -112,21 +129,25 @@ "type": "boolean" }, "image": { + "type": "object", + "required": [ + "repository" + ], "properties": { "imagePullPolicy": { + "type": "string", "enum": [ "IfNotPresent", "Always", "Never" - ], - "type": "string" + ] }, "pullSecrets": { + "type": "array", + "uniqueItems": true, "items": { "type": "object" - }, - "type": "array", - "uniqueItems": true + } }, "repository": { "type": "string" @@ -134,11 +155,7 @@ "tag": { "type": "string" } - }, - "required": [ - "repository" - ], - "type": "object" + } }, "installCRDs": { "default": true, @@ -153,8 +170,10 @@ "initialDelaySeconds": 15, "periodSeconds": 20 }, + "type": "object", "properties": { "httpGet": { + "type": "object", "properties": { "path": { "type": "string" @@ -162,8 +181,7 @@ "port": { "type": "integer" } - }, - "type": "object" + } }, "initialDelaySeconds": { "type": "integer" @@ -171,18 +189,18 @@ "periodSeconds": { "type": "integer" } - }, - "type": "object" + } }, "logLevel": { + "type": "string", "enum": [ "debug", "info", "error" - ], - "type": "string" + ] }, "marketplace": { + "type": "object", "properties": { "account": { "type": "string" @@ -193,37 +211,39 @@ "type": { "type": "string" } - }, - "type": "object" + } }, "multitenancy": { + "type": "object", + "required": [ + "defaultServiceAccount", + "defaultWorkloadIdentityServiceAccount" + ], "properties": { "defaultServiceAccount": { "type": "string" }, + "defaultWorkloadIdentityServiceAccount": { + "type": "string" + }, "enabled": { "type": "boolean" + }, + "enabledForWorkloadIdentity": { + "type": "boolean" } - }, - "required": [ - "defaultServiceAccount" - ], - "type": "object" + } }, "nameOverride": { "type": "string" }, "nodeSelector": { - "properties": {}, - "type": [ - "object" - ] + "type": "object" }, "podSecurityContext": { "default": { "fsGroup": 1337 }, - "properties": {}, "type": "object" }, "priorityClassName": { @@ -231,6 +251,7 @@ "type": "string" }, "rbac": { + "type": "object", "properties": { "create": { "type": "boolean" @@ -238,8 +259,7 @@ "createAggregation": { "type": "boolean" } - }, - "type": "object" + } }, "readinessProbe": { "default": { @@ -250,8 +270,10 @@ "initialDelaySeconds": 5, "periodSeconds": 10 }, + "type": "object", "properties": { "httpGet": { + "type": "object", "properties": { "path": { "type": "string" @@ -259,8 +281,7 @@ "port": { "type": "integer" } - }, - "type": "object" + } }, "initialDelaySeconds": { "type": "integer" @@ -268,23 +289,24 @@ "periodSeconds": { "type": "integer" } - }, - "type": "object" + } }, "reporting": { + "type": "object", + "required": [ + "interval" + ], "properties": { "interval": { "type": "string" } - }, - "required": [ - "interval" - ], - "type": "object" + } }, "resources": { + "type": "object", "properties": { "limits": { + "type": "object", "properties": { "cpu": { "type": "string" @@ -292,14 +314,14 @@ "memory": { "type": "string" } - }, - "type": "object" + } }, "requests": { "default": { "cpu": "100m", "memory": "64Mi" }, + "type": "object", "properties": { "cpu": { "type": "string" @@ -307,13 +329,12 @@ "memory": { "type": "string" } - }, - "type": "object" + } } - }, - "type": "object" + } }, "securityContext": { + "type": "object", "properties": { "allowPrivilegeEscalation": { "default": false, @@ -325,16 +346,16 @@ "ALL" ] }, + "type": "object", "properties": { "drop": { + "type": "array", + "uniqueItems": true, "items": { "type": "string" - }, - "type": "array", - "uniqueItems": true + } } - }, - "type": "object" + } }, "readOnlyRootFilesystem": { "default": true, @@ -348,15 +369,14 @@ "default": { "type": "RuntimeDefault" }, + "type": "object", "properties": { "type": { "type": "string" } - }, - "type": "object" + } } - }, - "type": "object" + } }, "serviceAccount": { "default": { @@ -364,6 +384,7 @@ "create": true, "name": "" }, + "type": "object", "properties": { "automount": { "type": "boolean" @@ -374,8 +395,7 @@ "name": { "type": "string" } - }, - "type": "object" + } }, "serviceMonitor": { "default": { @@ -383,6 +403,7 @@ "interval": "60s", "scrapeTimeout": "30s" }, + "type": "object", "properties": { "create": { "type": "boolean" @@ -391,26 +412,19 @@ "type": "string" }, "labels": { - "properties": {}, "type": "object" }, "scrapeTimeout": { "type": "string" } - }, - "type": "object" + } }, "tolerations": { + "type": "array", + "uniqueItems": true, "items": { "type": "object" - }, - "type": "array", - "uniqueItems": true + } } - }, - "required": [ - "resources", - "securityContext" - ], - "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 91cad9d2..aa2a6b59 100644 --- a/packages/system/fluxcd-operator/charts/flux-operator/values.yaml +++ b/packages/system/fluxcd-operator/charts/flux-operator/values.yaml @@ -6,7 +6,9 @@ fullnameOverride: "" # -- Enable [multitenancy lockdown](https://fluxcd.control-plane.io/operator/resourceset/#role-based-access-control) for the ResourceSet APIs. multitenancy: enabled: false + enabledForWorkloadIdentity: false defaultServiceAccount: "flux-operator" # @schema required: true + defaultWorkloadIdentityServiceAccount: "flux-operator" # @schema required: true # -- Flux [reporting](https://fluxcd.control-plane.io/operator/fluxreport/) settings. reporting: @@ -46,7 +48,7 @@ apiPriority: # @schema default: {"enabled":false,"level":"workload-high","extraS # -- Container resources requests and limits settings. resources: # @schema required: true limits: - cpu: 1000m + cpu: 2000m memory: 1Gi requests: # @schema default: {"cpu":"100m","memory":"64Mi"} cpu: 100m @@ -116,12 +118,18 @@ nodeSelector: { } # @schema type: object # -- If `true`, the container ports (`8080` and `8081`) are exposed on the host network. hostNetwork: false # @schema default: false +# -- Pod extra volumes. +extraVolumes: [ ] # @schema item: object ; uniqueItems: true + # -- Container extra environment variables. extraEnvs: [ ] # @schema item: object ; uniqueItems: true # -- Container extra arguments. extraArgs: [ ] # @schema item: string ; uniqueItems: true +# -- Container extra volume mounts. +extraVolumeMounts: [ ] # @schema item: object ; uniqueItems: true + # -- Container logging level flag. logLevel: "info" # @schema enum:[debug,info,error] diff --git a/packages/system/fluxcd-operator/patches/networkPolicy.diff b/packages/system/fluxcd-operator/patches/networkPolicy.diff new file mode 100644 index 00000000..e074ae2f --- /dev/null +++ b/packages/system/fluxcd-operator/patches/networkPolicy.diff @@ -0,0 +1,25 @@ +diff --git a/charts/flux-operator/templates/network-policy.yaml b/packages/system/fluxcd-operator/charts/flux-operator/templates/network-policy.yaml +new file mode 100644 +--- /dev/null (revision 52a23eacfc32430d8b008b765c64a81526521bae) ++++ b/charts/flux-operator/templates/network-policy.yaml (revision 52a23eacfc32430d8b008b765c64a81526521bae) +@@ -0,0 +1,20 @@ ++{{- if .Capabilities.APIVersions.Has "cilium.io/v2/CiliumClusterwideNetworkPolicy" }} ++apiVersion: cilium.io/v2 ++kind: CiliumClusterwideNetworkPolicy ++metadata: ++ name: {{ include "flux-operator.fullname" . }}-restrict ++spec: ++ nodeSelector: {} ++ ingressDeny: ++ - fromEntities: ++ - world ++ toPorts: ++ - ports: ++ - port: "8080" ++ protocol: TCP ++ - port: "8081" ++ protocol: TCP ++ ingress: ++ - fromEntities: ++ - cluster ++{{- end }} diff --git a/packages/system/fluxcd/Makefile b/packages/system/fluxcd/Makefile index b5af8680..9aa32fe9 100644 --- a/packages/system/fluxcd/Makefile +++ b/packages/system/fluxcd/Makefile @@ -1,10 +1,10 @@ NAME=fluxcd NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk apply-locally: - cozypkg apply --plain -n $(NAMESPACE) $(NAME) + cozyhr apply --plain -n $(NAMESPACE) $(NAME) update: rm -rf charts diff --git a/packages/system/fluxcd/charts/flux-instance/Chart.yaml b/packages/system/fluxcd/charts/flux-instance/Chart.yaml index 0ab390b4..448e6600 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.23.0 +appVersion: v0.33.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.23.0 +version: 0.33.0 diff --git a/packages/system/fluxcd/charts/flux-instance/README.md b/packages/system/fluxcd/charts/flux-instance/README.md index 28c6ce23..e788edf1 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.23.0](https://img.shields.io/badge/Version-0.23.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.23.0](https://img.shields.io/badge/AppVersion-v0.23.0-informational?style=flat-square) +![Version: 0.33.0](https://img.shields.io/badge/Version-0.33.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.33.0](https://img.shields.io/badge/AppVersion-v0.33.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) @@ -37,7 +37,9 @@ helm -n flux-system uninstall flux | commonAnnotations | object | `{}` | Common annotations to add to all deployed objects including pods. | | commonLabels | object | `{}` | Common labels to add to all deployed objects including pods. | | fullnameOverride | string | `"flux"` | | -| instance.cluster | object | `{"domain":"cluster.local","multitenant":false,"networkPolicy":true,"tenantDefaultServiceAccount":"default","type":"kubernetes"}` | Cluster https://fluxcd.control-plane.io/operator/fluxinstance/#cluster-configuration | +| healthcheck.enabled | bool | `false` | Enable post-install and post-upgrade health checks. | +| healthcheck.timeout | string | `"5m"` | Health check timeout in Go duration format. | +| instance.cluster | object | `{"domain":"cluster.local","multitenant":false,"networkPolicy":true,"size":"","tenantDefaultServiceAccount":"default","type":"kubernetes"}` | Cluster https://fluxcd.control-plane.io/operator/fluxinstance/#cluster-configuration | | instance.commonMetadata | object | `{"annotations":{},"labels":{}}` | Common metadata https://fluxcd.control-plane.io/operator/fluxinstance/#common-metadata | | instance.components | list | `["source-controller","kustomize-controller","helm-controller","notification-controller"]` | Components https://fluxcd.control-plane.io/operator/fluxinstance/#components-configuration | | instance.distribution | object | `{"artifact":"oci://ghcr.io/controlplaneio-fluxcd/flux-operator-manifests:latest","artifactPullSecret":"","imagePullSecret":"","registry":"ghcr.io/fluxcd","version":"2.x"}` | Distribution https://fluxcd.control-plane.io/operator/fluxinstance/#distribution-configuration | diff --git a/packages/system/fluxcd/charts/flux-instance/templates/healthcheck.yaml b/packages/system/fluxcd/charts/flux-instance/templates/healthcheck.yaml new file mode 100644 index 00000000..41329d82 --- /dev/null +++ b/packages/system/fluxcd/charts/flux-instance/templates/healthcheck.yaml @@ -0,0 +1,78 @@ +{{- if .Values.healthcheck.enabled }} +apiVersion: batch/v1 +kind: Job +metadata: + name: "{{ .Release.Name }}-healthcheck" + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + annotations: + helm.sh/hook: post-install,post-upgrade + helm.sh/hook-weight: "-5" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded +spec: + template: + metadata: + name: "{{ .Release.Name }}" + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + spec: + restartPolicy: Never + {{- with .Values.healthcheck.image.pullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ .Values.healthcheck.serviceAccount.name }} + {{- with .Values.healthcheck.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.healthcheck.hostNetwork }} + hostNetwork: true + {{- end }} + containers: + - name: healthcheck + image: "{{ .Values.healthcheck.image.repository }}:{{ .Values.healthcheck.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: "{{ .Values.healthcheck.image.imagePullPolicy }}" + args: + - wait + - instance + - {{ include "flux-instance.fullname" . }} + - --namespace={{ .Release.Namespace }} + - --timeout={{ .Values.healthcheck.timeout }} + {{- range .Values.healthcheck.extraArgs }} + - {{ . }} + {{- end }} + {{- with .Values.healthcheck.envs }} + env: + {{- toYaml . | nindent 12 }} + {{- end }} + securityContext: + {{- toYaml .Values.healthcheck.securityContext | nindent 12 }} + resources: + {{- toYaml .Values.healthcheck.resources | nindent 12 }} + {{- with .Values.healthcheck.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.healthcheck.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.healthcheck.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.healthcheck.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.healthcheck.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/packages/system/fluxcd/charts/flux-instance/templates/instance.yaml b/packages/system/fluxcd/charts/flux-instance/templates/instance.yaml index 418b21c2..57688811 100644 --- a/packages/system/fluxcd/charts/flux-instance/templates/instance.yaml +++ b/packages/system/fluxcd/charts/flux-instance/templates/instance.yaml @@ -24,7 +24,12 @@ spec: imagePullSecret: {{ .Values.instance.distribution.imagePullSecret }} {{- end }} components: {{ .Values.instance.components | toYaml | nindent 4 }} - cluster: {{ .Values.instance.cluster | toYaml | nindent 4 }} + cluster: + {{- range $key, $value := .Values.instance.cluster }} + {{- if not (and (kindIs "string" $value) (eq $value "")) }} + {{ $key }}: {{ $value }} + {{- end }} + {{- end }} {{- if or .Values.instance.commonMetadata.annotations .Values.instance.commonMetadata.labels }} commonMetadata: {{- with .Values.instance.commonMetadata.annotations }} diff --git a/packages/system/fluxcd/charts/flux-instance/templates/serviceaccount.yaml b/packages/system/fluxcd/charts/flux-instance/templates/serviceaccount.yaml new file mode 100644 index 00000000..38448f3d --- /dev/null +++ b/packages/system/fluxcd/charts/flux-instance/templates/serviceaccount.yaml @@ -0,0 +1,17 @@ +{{- if .Values.healthcheck.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.healthcheck.serviceAccount.name }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "flux-instance.labels" . | nindent 4 }} + {{- with .Values.commonLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.commonAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.healthcheck.serviceAccount.automount }} +{{- end }} diff --git a/packages/system/fluxcd/charts/flux-instance/values.schema.json b/packages/system/fluxcd/charts/flux-instance/values.schema.json index cf07b60f..af0e7b1a 100644 --- a/packages/system/fluxcd/charts/flux-instance/values.schema.json +++ b/packages/system/fluxcd/charts/flux-instance/values.schema.json @@ -1,20 +1,275 @@ { "$schema": "https://json-schema.org/draft/2019-09/schema", + "type": "object", "properties": { "commonAnnotations": { - "properties": {}, "type": "object" }, "commonLabels": { - "properties": {}, "type": "object" }, "fullnameOverride": { "type": "string" }, + "healthcheck": { + "type": "object", + "required": [ + "resources", + "securityContext" + ], + "properties": { + "affinity": { + "default": { + "nodeAffinity": { + "requiredDuringSchedulingIgnoredDuringExecution": { + "nodeSelectorTerms": [ + { + "matchExpressions": [ + { + "key": "kubernetes.io/os", + "operator": "In", + "values": [ + "linux" + ] + } + ] + } + ] + } + } + }, + "type": "object", + "properties": { + "nodeAffinity": { + "type": "object", + "properties": { + "requiredDuringSchedulingIgnoredDuringExecution": { + "type": "object", + "properties": { + "nodeSelectorTerms": { + "type": "array", + "items": { + "type": "object", + "properties": { + "matchExpressions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "enabled": { + "type": "boolean" + }, + "envs": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "object" + } + }, + "extraArgs": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + }, + "hostNetwork": { + "default": false, + "type": "boolean" + }, + "image": { + "type": "object", + "required": [ + "repository" + ], + "properties": { + "imagePullPolicy": { + "type": "string", + "enum": [ + "IfNotPresent", + "Always", + "Never" + ] + }, + "pullSecrets": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "object" + } + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "nodeSelector": { + "type": "object" + }, + "podSecurityContext": { + "default": { + "fsGroup": 1337 + }, + "type": "object" + }, + "resources": { + "type": "object", + "properties": { + "limits": { + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + }, + "requests": { + "default": { + "cpu": "100m", + "memory": "64Mi" + }, + "type": "object", + "properties": { + "cpu": { + "type": "string" + }, + "memory": { + "type": "string" + } + } + } + } + }, + "securityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "default": false, + "type": "boolean" + }, + "capabilities": { + "default": { + "drop": [ + "ALL" + ] + }, + "type": "object", + "properties": { + "drop": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + } + } + }, + "readOnlyRootFilesystem": { + "default": true, + "type": "boolean" + }, + "runAsNonRoot": { + "default": true, + "type": "boolean" + }, + "seccompProfile": { + "default": { + "type": "RuntimeDefault" + }, + "type": "object", + "properties": { + "type": { + "type": "string" + } + } + } + } + }, + "serviceAccount": { + "default": { + "automount": true, + "create": false, + "name": "flux-operator" + }, + "type": "object", + "properties": { + "automount": { + "type": "boolean" + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } + }, + "timeout": { + "default": "5m", + "type": "string" + }, + "tolerations": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "object" + } + }, + "volumeMounts": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "object" + } + }, + "volumes": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "object" + } + } + } + }, "instance": { + "type": "object", + "required": [ + "distribution", + "cluster" + ], "properties": { "cluster": { + "type": "object", "properties": { "domain": { "type": "string" @@ -25,51 +280,63 @@ "networkPolicy": { "type": "boolean" }, + "size": { + "type": "string", + "enum": [ + "", + "small", + "medium", + "large" + ] + }, "tenantDefaultServiceAccount": { "type": "string" }, "type": { + "type": "string", "enum": [ "kubernetes", "openshift", "aws", "azure", "gcp" - ], - "type": "string" + ] } - }, - "type": "object" + } }, "commonMetadata": { + "type": "object", "properties": { "annotations": { - "properties": {}, "type": "object" }, "labels": { - "properties": {}, "type": "object" } - }, - "type": "object" + } }, "components": { + "type": "array", + "uniqueItems": true, "items": { + "type": "string", "enum": [ "source-controller", "kustomize-controller", "helm-controller", "notification-controller", "image-reflector-controller", - "image-automation-controller" - ], - "type": "string" - }, - "type": "array", - "uniqueItems": true + "image-automation-controller", + "source-watcher" + ] + } }, "distribution": { + "type": "object", + "required": [ + "version", + "registry" + ], "properties": { "artifact": { "type": "string" @@ -86,39 +353,35 @@ "version": { "type": "string" } - }, - "required": [ - "version", - "registry" - ], - "type": "object" + } }, "kustomize": { + "type": "object", "properties": { "patches": { + "type": "array", "items": { "type": "object" - }, - "type": "array" + } } - }, - "type": "object" + } }, "sharding": { + "type": "object", "properties": { "key": { "type": "string" }, "shards": { + "type": "array", "items": { "type": "string" - }, - "type": "array" + } } - }, - "type": "object" + } }, "storage": { + "type": "object", "properties": { "class": { "type": "string" @@ -126,21 +389,21 @@ "size": { "type": "string" } - }, - "type": "object" + } }, "sync": { + "type": "object", "properties": { "interval": { "type": "string" }, "kind": { + "type": "string", "enum": [ "GitRepository", "OCIRepository", "Bucket" - ], - "type": "string" + ] }, "name": { "type": "string" @@ -160,19 +423,12 @@ "url": { "type": "string" } - }, - "type": "object" + } } - }, - "required": [ - "distribution", - "cluster" - ], - "type": "object" + } }, "nameOverride": { "type": "string" } - }, - "type": "object" + } } diff --git a/packages/system/fluxcd/charts/flux-instance/values.yaml b/packages/system/fluxcd/charts/flux-instance/values.yaml index 5b324b04..84619eca 100644 --- a/packages/system/fluxcd/charts/flux-instance/values.yaml +++ b/packages/system/fluxcd/charts/flux-instance/values.yaml @@ -12,7 +12,7 @@ instance: artifactPullSecret: "" imagePullSecret: "" # -- Components https://fluxcd.control-plane.io/operator/fluxinstance/#components-configuration - components: # @schema item: string; uniqueItems: true; itemEnum: [source-controller,kustomize-controller,helm-controller,notification-controller,image-reflector-controller,image-automation-controller] + components: # @schema item: string; uniqueItems: true; itemEnum: [source-controller,kustomize-controller,helm-controller,notification-controller,image-reflector-controller,image-automation-controller,source-watcher] - source-controller - kustomize-controller - helm-controller @@ -20,6 +20,7 @@ instance: # -- Cluster https://fluxcd.control-plane.io/operator/fluxinstance/#cluster-configuration cluster: # @schema required: true type: kubernetes # @schema enum:[kubernetes,openshift,aws,azure,gcp] + size: "" # @schema enum:['',small,medium,large] domain: "cluster.local" networkPolicy: true multitenant: false @@ -35,7 +36,7 @@ instance: # -- Sharding https://fluxcd.control-plane.io/operator/fluxinstance/#sharding-configuration sharding: # @schema required: false key: "sharding.fluxcd.io/key" - shards: [] # @schema item: string + shards: [ ] # @schema item: string # -- Sync https://fluxcd.control-plane.io/operator/fluxinstance/#sync-configuration sync: # @schema required: false interval: 1m @@ -48,10 +49,101 @@ instance: provider: "" kustomize: # @schema required: false # -- Kustomize patches https://fluxcd.control-plane.io/operator/fluxinstance/#kustomize-patches - patches: [] # @schema item: object + patches: [ ] # @schema item: object # -- Common annotations to add to all deployed objects including pods. commonAnnotations: { } # -- Common labels to add to all deployed objects including pods. commonLabels: { } + +# Healthcheck job settings. +healthcheck: + # -- Enable post-install and post-upgrade health checks. + enabled: false + # -- Health check timeout in Go duration format. + timeout: 5m # @schema default: "5m" + + # Container image settings. + # The image tag defaults to the chart appVersion. + # @ignore + image: + repository: ghcr.io/controlplaneio-fluxcd/flux-operator-cli # @schema required: true + tag: "" + pullSecrets: [ ] # @schema item: object ; uniqueItems: true + imagePullPolicy: IfNotPresent # @schema enum:[IfNotPresent, Always, Never] + + # Container resources requests and limits settings. + # @ignore + resources: # @schema required: true + limits: + cpu: 1000m + memory: 1Gi + requests: # @schema default: {"cpu":"100m","memory":"64Mi"} + cpu: 100m + memory: 64Mi + + # Pod service account settings. + # The name of the service account defaults to the release name. + # @ignore + serviceAccount: # @schema default: {"create":false,"automount":true,"name":"flux-operator"} + create: false + automount: true + name: "flux-operator" + + # Pod security context settings. + # @ignore + podSecurityContext: { } # @schema default: {"fsGroup":1337} + + # Container security context settings. + # The default is compliant with the pod security restricted profile. + # @ignore + securityContext: # @schema required: true + runAsNonRoot: true # @schema default: true + readOnlyRootFilesystem: true # @schema default: true + allowPrivilegeEscalation: false # @schema default: false + capabilities: # @schema default: {"drop":["ALL"]} + drop: # @schema item: string ; uniqueItems: true + - "ALL" + seccompProfile: # @schema default: {"type":"RuntimeDefault"} + type: "RuntimeDefault" + + # Pod affinity and anti-affinity settings. + # @ignore + affinity: # @schema default: {"nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"kubernetes.io/os","operator":"In","values":["linux"]}]}]}}} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/os + operator: In + values: + - linux + + # Pod tolerations settings. + # @ignore + tolerations: [ ] # @schema item: object ; uniqueItems: true + + # Pod Node Selector settings. + # @ignore + nodeSelector: { } # @schema type: object + + # If `true`, the container ports (`8080` and `8081`) are exposed on the host network. + # @ignore + hostNetwork: false # @schema default: false + + # Pod extra volumes. + # @ignore + volumes: [ ] # @schema item: object ; uniqueItems: true + + # Container extra volume mounts. + # @ignore + volumeMounts: [ ] # @schema item: object ; uniqueItems: true + + # Container extra environment variables. + # @ignore + envs: [ ] # @schema item: object ; uniqueItems: true + + # Container extra arguments. + # @ignore + extraArgs: [ ] # @schema item: string ; uniqueItems: true diff --git a/packages/system/fluxcd/values.yaml b/packages/system/fluxcd/values.yaml index 837be8d8..7f5af0ff 100644 --- a/packages/system/fluxcd/values.yaml +++ b/packages/system/fluxcd/values.yaml @@ -5,10 +5,11 @@ flux-instance: domain: cozy.local # -- default value is overriden in patches distribution: artifact: "" - version: 2.6.x + version: 2.7.x registry: ghcr.io/fluxcd components: - source-controller + - source-watcher - kustomize-controller - helm-controller - notification-controller @@ -38,12 +39,16 @@ flux-instance: - op: add path: /spec/template/spec/containers/0/args/- value: --storage-adv-addr=source-controller.cozy-fluxcd.svc - - op: add - path: /spec/template/spec/containers/0/args/- - value: --events-addr=http://notification-controller.cozy-fluxcd.svc/ - target: kind: Deployment - name: (kustomize-controller|helm-controller|image-reflector-controller|image-automation-controller) + name: source-watcher + patch: | + - op: add + path: /spec/template/spec/containers/0/args/- + value: --storage-adv-addr=source-watcher.cozy-fluxcd.svc + - target: + kind: Deployment + name: (kustomize-controller|helm-controller|image-reflector-controller|image-automation-controller|source-controller|source-watcher) patch: | - op: add path: /spec/template/spec/containers/0/args/- diff --git a/packages/system/foundationdb-operator/.helmignore b/packages/system/foundationdb-operator/.helmignore new file mode 100644 index 00000000..33ceb8f0 --- /dev/null +++ b/packages/system/foundationdb-operator/.helmignore @@ -0,0 +1 @@ +Makefile \ No newline at end of file diff --git a/packages/system/foundationdb-operator/Chart.yaml b/packages/system/foundationdb-operator/Chart.yaml new file mode 100644 index 00000000..7685387c --- /dev/null +++ b/packages/system/foundationdb-operator/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-foundationdb-operator +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process \ No newline at end of file diff --git a/packages/system/foundationdb-operator/Makefile b/packages/system/foundationdb-operator/Makefile new file mode 100644 index 00000000..16ca953f --- /dev/null +++ b/packages/system/foundationdb-operator/Makefile @@ -0,0 +1,19 @@ +export NAME=foundationdb-operator +export NAMESPACE=cozy-$(NAME) + +include ../../../hack/package.mk + +update: + rm -rf charts + git clone --depth 1 --branch v2.13.0 https://github.com/FoundationDB/fdb-kubernetes-operator.git tmp-repo + mkdir -p charts + cp -r tmp-repo/charts/fdb-operator charts/ + # Remove symlinked CRDs and replace with actual files + rm -f charts/fdb-operator/crds/apps.foundationdb.org_foundationdbbackups.yaml + rm -f charts/fdb-operator/crds/apps.foundationdb.org_foundationdbclusters.yaml + rm -f charts/fdb-operator/crds/apps.foundationdb.org_foundationdbrestores.yaml + cp tmp-repo/config/crd/bases/apps.foundationdb.org_foundationdbbackups.yaml charts/fdb-operator/crds/ + cp tmp-repo/config/crd/bases/apps.foundationdb.org_foundationdbclusters.yaml charts/fdb-operator/crds/ + cp tmp-repo/config/crd/bases/apps.foundationdb.org_foundationdbrestores.yaml charts/fdb-operator/crds/ + rm -rf tmp-repo + rm -rf charts/fdb-operator/charts \ No newline at end of file diff --git a/packages/apps/virtual-machine/Chart.yaml b/packages/system/foundationdb-operator/charts/fdb-operator/Chart.yaml similarity index 63% rename from packages/apps/virtual-machine/Chart.yaml rename to packages/system/foundationdb-operator/charts/fdb-operator/Chart.yaml index c86bc876..e9824f59 100644 --- a/packages/apps/virtual-machine/Chart.yaml +++ b/packages/system/foundationdb-operator/charts/fdb-operator/Chart.yaml @@ -1,9 +1,9 @@ apiVersion: v2 -#name: Virtual Machine -name: virtual-machine -description: Virtual Machine (simple) -icon: /logos/vm.svg - +name: fdb-operator +description: A Helm chart for foundationDB operator +home: https://www.foundationdb.org/ +sources: + - https://github.com/FoundationDB/fdb-kubernetes-operator/tree/main/charts/fdb-operator # 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 @@ -13,14 +13,11 @@ icon: /logos/vm.svg # 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: 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.12.1 - +version: 0.2.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.12.0 +# incremented each time you make changes to the application. +appVersion: v2.13.0 +maintainers: + - name: "foundationdb-ci" diff --git a/packages/system/foundationdb-operator/charts/fdb-operator/crds/apps.foundationdb.org_foundationdbbackups.yaml b/packages/system/foundationdb-operator/charts/fdb-operator/crds/apps.foundationdb.org_foundationdbbackups.yaml new file mode 100644 index 00000000..ee1f50d6 --- /dev/null +++ b/packages/system/foundationdb-operator/charts/fdb-operator/crds/apps.foundationdb.org_foundationdbbackups.yaml @@ -0,0 +1,3899 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + foundationdb.org/release: v2.13.0 + name: foundationdbbackups.apps.foundationdb.org +spec: + group: apps.foundationdb.org + names: + kind: FoundationDBBackup + listKind: FoundationDBBackupList + plural: foundationdbbackups + shortNames: + - fdbbackup + singular: foundationdbbackup + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Latest generation of the spec + jsonPath: .metadata.generation + name: Generation + type: integer + - description: Last reconciled generation of the spec + jsonPath: .status.generations.reconciled + name: Reconciled + type: integer + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + agentCount: + type: integer + allowTagOverride: + default: false + type: boolean + backupDeploymentMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + backupState: + enum: + - Running + - Stopped + - Paused + type: string + backupType: + default: backup_agent + enum: + - backup_agent + - partitioned_log + maxLength: 64 + type: string + blobStoreConfiguration: + properties: + accountName: + maxLength: 100 + type: string + backupName: + maxLength: 1024 + type: string + bucket: + maxLength: 63 + minLength: 3 + type: string + urlParameters: + items: + maxLength: 1024 + type: string + maxItems: 100 + type: array + required: + - accountName + type: object + clusterName: + type: string + customParameters: + items: + maxLength: 100 + type: string + maxItems: 100 + type: array + encryptionKeyPath: + maxLength: 4096 + type: string + imageType: + default: split + enum: + - split + - unified + maxLength: 1024 + type: string + mainContainer: + properties: + enableLivenessProbe: + type: boolean + enableReadinessProbe: + type: boolean + enableTls: + type: boolean + imageConfigs: + items: + properties: + baseImage: + maxLength: 200 + type: string + tag: + maxLength: 100 + type: string + tagSuffix: + maxLength: 50 + type: string + version: + maxLength: 20 + type: string + type: object + maxItems: 100 + type: array + peerVerificationRules: + maxLength: 10000 + type: string + type: object + podTemplateSpec: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + activeDeadlineSeconds: + format: int64 + type: integer + affinity: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + automountServiceAccountToken: + type: boolean + containers: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + dnsConfig: + properties: + nameservers: + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + dnsPolicy: + type: string + enableServiceLinks: + type: boolean + ephemeralContainers: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + targetContainerName: + type: string + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + x-kubernetes-list-map-keys: + - ip + x-kubernetes-list-type: map + hostIPC: + type: boolean + hostNetwork: + type: boolean + hostPID: + type: boolean + hostUsers: + type: boolean + hostname: + type: string + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + initContainers: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + nodeName: + type: string + nodeSelector: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object + overhead: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + preemptionPolicy: + type: string + priority: + format: int32 + type: integer + priorityClassName: + type: string + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + x-kubernetes-list-type: atomic + resourceClaims: + items: + properties: + name: + type: string + resourceClaimName: + type: string + resourceClaimTemplateName: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + runtimeClassName: + type: string + schedulerName: + type: string + schedulingGates: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + securityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + serviceAccount: + type: string + serviceAccountName: + type: string + setHostnameAsFQDN: + type: boolean + shareProcessNamespace: + type: boolean + subdomain: + type: string + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + x-kubernetes-list-map-keys: + - topologyKey + - whenUnsatisfiable + x-kubernetes-list-type: map + volumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + required: + - containers + type: object + type: object + sidecarContainer: + properties: + enableLivenessProbe: + type: boolean + enableReadinessProbe: + type: boolean + enableTls: + type: boolean + imageConfigs: + items: + properties: + baseImage: + maxLength: 200 + type: string + tag: + maxLength: 100 + type: string + tagSuffix: + maxLength: 50 + type: string + version: + maxLength: 20 + type: string + type: object + maxItems: 100 + type: array + peerVerificationRules: + maxLength: 10000 + type: string + type: object + snapshotPeriodSeconds: + type: integer + version: + type: string + required: + - clusterName + - version + type: object + status: + properties: + agentCount: + type: integer + backupDetails: + properties: + paused: + type: boolean + running: + type: boolean + snapshotTime: + type: integer + url: + type: string + type: object + deploymentConfigured: + type: boolean + generations: + properties: + needsBackupAgentUpdate: + format: int64 + type: integer + needsBackupModification: + format: int64 + type: integer + needsBackupPauseToggle: + format: int64 + type: integer + needsBackupStart: + format: int64 + type: integer + needsBackupStop: + format: int64 + type: integer + reconciled: + format: int64 + type: integer + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/foundationdb-operator/charts/fdb-operator/crds/apps.foundationdb.org_foundationdbclusters.yaml b/packages/system/foundationdb-operator/charts/fdb-operator/crds/apps.foundationdb.org_foundationdbclusters.yaml new file mode 100644 index 00000000..d65a97b1 --- /dev/null +++ b/packages/system/foundationdb-operator/charts/fdb-operator/crds/apps.foundationdb.org_foundationdbclusters.yaml @@ -0,0 +1,4784 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + foundationdb.org/release: v2.13.0 + name: foundationdbclusters.apps.foundationdb.org +spec: + group: apps.foundationdb.org + names: + kind: FoundationDBCluster + listKind: FoundationDBClusterList + plural: foundationdbclusters + shortNames: + - fdb + singular: foundationdbcluster + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Latest generation of the spec + jsonPath: .metadata.generation + name: Generation + type: integer + - description: Last reconciled generation of the spec + jsonPath: .status.generations.reconciled + name: Reconciled + type: integer + - description: Database available + jsonPath: .status.health.available + name: Available + type: boolean + - description: Database fully replicated + jsonPath: .status.health.fullReplication + name: FullReplication + type: boolean + - description: Number of reconciled process groups + jsonPath: .status.reconciledProcessGroups + name: ReconciledProcessGroups + priority: 1 + type: integer + - description: Desired number of process groups + jsonPath: .status.desiredProcessGroups + name: DesiredProcessGroups + priority: 1 + type: integer + - description: Running version + jsonPath: .status.runningVersion + name: Version + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta2 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + automationOptions: + properties: + cacheDatabaseStatusForReconciliation: + type: boolean + configureDatabase: + type: boolean + databaseInteractionMode: + maxLength: 256 + type: string + deletionMode: + default: Zone + enum: + - All + - Zone + - ProcessGroup + - None + type: string + failedPodDurationSeconds: + type: integer + ignoreLogGroupsForUpgrade: + items: + maxLength: 256 + type: string + maxItems: 10 + type: array + ignoreMissingProcessesSeconds: + type: integer + ignorePendingPodsDuration: + format: int64 + type: integer + ignoreTerminatingPodsSeconds: + type: integer + killProcesses: + type: boolean + maintenanceModeOptions: + properties: + UseMaintenanceModeChecker: + type: boolean + maintenanceModeTimeSeconds: + type: integer + resetMaintenanceMode: + type: boolean + type: object + maxConcurrentReplacements: + minimum: 0 + type: integer + podUpdateStrategy: + default: ReplaceTransactionSystem + enum: + - Replace + - ReplaceTransactionSystem + - Delete + type: string + removalMode: + default: Zone + enum: + - All + - Zone + - ProcessGroup + - None + type: string + replacements: + properties: + enabled: + type: boolean + failureDetectionTimeSeconds: + type: integer + faultDomainBasedReplacements: + type: boolean + maxConcurrentReplacements: + default: 1 + minimum: 0 + type: integer + maxFaultDomainsWithTaintedProcessGroups: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + taintReplacementOptions: + items: + properties: + durationInSeconds: + format: int64 + minimum: 0 + type: integer + key: + maxLength: 256 + pattern: ^([\-._\/a-z0-9A-Z\*])*$ + type: string + required: + - durationInSeconds + - key + type: object + maxItems: 32 + type: array + taintReplacementTimeSeconds: + type: integer + type: object + synchronizationMode: + default: local + enum: + - local + - global + type: string + useLocalitiesForExclusion: + type: boolean + useManagementAPI: + type: boolean + useNonBlockingExcludes: + type: boolean + waitBetweenRemovalsSeconds: + type: integer + type: object + buggify: + properties: + blockRemoval: + items: + maxLength: 63 + pattern: ^(([\w-]+)-(\d+)|\*)$ + type: string + maxItems: 1000 + type: array + crashLoop: + items: + maxLength: 63 + pattern: ^(([\w-]+)-(\d+)|\*)$ + type: string + type: array + crashLoopContainers: + items: + properties: + containerName: + maxLength: 253 + minLength: 1 + type: string + targets: + items: + maxLength: 63 + pattern: ^(([\w-]+)-(\d+)|\*)$ + type: string + maxItems: 10000 + minItems: 0 + type: array + type: object + maxItems: 8 + minItems: 0 + type: array + emptyMonitorConf: + type: boolean + ignoreDuringRestart: + items: + maxLength: 63 + pattern: ^(([\w-]+)-(\d+)|\*)$ + type: string + maxItems: 1000 + type: array + noSchedule: + items: + maxLength: 63 + pattern: ^(([\w-]+)-(\d+)|\*)$ + type: string + type: array + type: object + configMap: + properties: + apiVersion: + type: string + binaryData: + additionalProperties: + format: byte + type: string + type: object + data: + additionalProperties: + type: string + type: object + immutable: + type: boolean + kind: + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + type: object + coordinatorSelection: + items: + properties: + priority: + type: integer + processClass: + type: string + type: object + type: array + dataCenter: + type: string + dataHall: + type: string + databaseConfiguration: + properties: + commit_proxies: + type: integer + excluded_servers: + items: + properties: + address: + maxLength: 48 + type: string + locality: + maxLength: 200 + type: string + type: object + maxItems: 1024 + type: array + grv_proxies: + type: integer + log_routers: + type: integer + log_spill: + type: integer + log_version: + type: integer + logs: + type: integer + perpetual_storage_wiggle: + type: integer + perpetual_storage_wiggle_engine: + enum: + - "" + - ssd + - ssd-1 + - ssd-2 + - memory + - memory-1 + - memory-2 + - ssd-redwood-1-experimental + - ssd-redwood-1 + - ssd-rocksdb-experimental + - ssd-rocksdb-v1 + - ssd-sharded-rocksdb + - memory-radixtree-beta + - custom + - none + maxLength: 100 + type: string + perpetual_storage_wiggle_locality: + type: string + proxies: + type: integer + redundancy_mode: + enum: + - single + - double + - triple + - three_data_hall + maxLength: 100 + type: string + regions: + items: + properties: + datacenters: + items: + properties: + id: + type: string + priority: + type: integer + satellite: + maximum: 1 + minimum: 0 + type: integer + type: object + type: array + satellite_logs: + type: integer + satellite_redundancy_mode: + maxLength: 100 + type: string + type: object + type: array + remote_logs: + type: integer + resolvers: + type: integer + storage: + type: integer + storage_engine: + default: ssd-2 + enum: + - ssd + - ssd-1 + - ssd-2 + - memory + - memory-1 + - memory-2 + - ssd-redwood-1-experimental + - ssd-redwood-1 + - ssd-rocksdb-experimental + - ssd-rocksdb-v1 + - ssd-sharded-rocksdb + - memory-radixtree-beta + - custom + maxLength: 100 + type: string + storage_migration_type: + enum: + - "" + - disabled + - aggressive + - gradual + maxLength: 100 + type: string + usable_regions: + type: integer + type: object + faultDomain: + properties: + key: + type: string + value: + type: string + valueFrom: + type: string + zoneCount: + type: integer + zoneIndex: + type: integer + type: object + ignoreUpgradabilityChecks: + type: boolean + imageType: + default: unified + enum: + - split + - unified + maxLength: 1024 + type: string + labels: + properties: + filterOnOwnerReference: + type: boolean + matchLabels: + additionalProperties: + type: string + type: object + processClassLabels: + items: + type: string + maxItems: 100 + type: array + processGroupIDLabels: + items: + type: string + maxItems: 100 + type: array + resourceLabels: + additionalProperties: + type: string + type: object + type: object + lockOptions: + properties: + denyList: + items: + properties: + allow: + type: boolean + id: + type: string + type: object + type: array + disableLocks: + type: boolean + lockDurationMinutes: + type: integer + lockKeyPrefix: + type: string + type: object + logGroup: + type: string + logServersPerPod: + type: integer + mainContainer: + properties: + enableLivenessProbe: + type: boolean + enableReadinessProbe: + type: boolean + enableTls: + type: boolean + imageConfigs: + items: + properties: + baseImage: + maxLength: 200 + type: string + tag: + maxLength: 100 + type: string + tagSuffix: + maxLength: 50 + type: string + version: + maxLength: 20 + type: string + type: object + maxItems: 100 + type: array + peerVerificationRules: + maxLength: 10000 + type: string + type: object + maxZonesWithUnavailablePods: + type: integer + minimumUptimeSecondsForBounce: + default: 600 + minimum: 1 + type: integer + partialConnectionString: + properties: + coordinators: + items: + type: string + type: array + databaseName: + type: string + generationID: + type: string + type: object + processCounts: + properties: + backup: + type: integer + cluster_controller: + type: integer + commit_proxy: + type: integer + coordinator: + type: integer + data_distributor: + type: integer + fast_restore: + type: integer + grv_proxy: + type: integer + log: + type: integer + master: + type: integer + proxy: + type: integer + ratekeeper: + type: integer + resolution: + type: integer + router: + type: integer + stateless: + type: integer + storage: + type: integer + storage_cache: + type: integer + test: + type: integer + tester: + type: integer + transaction: + type: integer + unset: + type: integer + type: object + processGroupIDPrefix: + maxLength: 43 + pattern: ^[a-z0-9A-Z]([\-._a-z0-9A-Z])*[a-z0-9A-Z]$ + type: string + processGroupsToRemove: + items: + maxLength: 63 + pattern: ^(([\w-]+)-(\d+)|\*)$ + type: string + maxItems: 500 + minItems: 0 + type: array + processGroupsToRemoveWithoutExclusion: + items: + maxLength: 63 + pattern: ^(([\w-]+)-(\d+)|\*)$ + type: string + maxItems: 500 + minItems: 0 + type: array + processes: + additionalProperties: + properties: + customParameters: + items: + maxLength: 100 + type: string + maxItems: 100 + type: array + podTemplate: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + activeDeadlineSeconds: + format: int64 + type: integer + affinity: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + automountServiceAccountToken: + type: boolean + containers: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + dnsConfig: + properties: + nameservers: + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + dnsPolicy: + type: string + enableServiceLinks: + type: boolean + ephemeralContainers: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + targetContainerName: + type: string + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + x-kubernetes-list-map-keys: + - ip + x-kubernetes-list-type: map + hostIPC: + type: boolean + hostNetwork: + type: boolean + hostPID: + type: boolean + hostUsers: + type: boolean + hostname: + type: string + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + initContainers: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + nodeName: + type: string + nodeSelector: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: atomic + os: + properties: + name: + type: string + required: + - name + type: object + overhead: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + preemptionPolicy: + type: string + priority: + format: int32 + type: integer + priorityClassName: + type: string + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + x-kubernetes-list-type: atomic + resourceClaims: + items: + properties: + name: + type: string + resourceClaimName: + type: string + resourceClaimTemplateName: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + runtimeClassName: + type: string + schedulerName: + type: string + schedulingGates: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + securityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + serviceAccount: + type: string + serviceAccountName: + type: string + setHostnameAsFQDN: + type: boolean + shareProcessNamespace: + type: boolean + subdomain: + type: string + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + x-kubernetes-list-map-keys: + - topologyKey + - whenUnsatisfiable + x-kubernetes-list-type: map + volumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + required: + - containers + type: object + type: object + volumeClaimTemplate: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: object + type: object + replaceInstancesWhenResourcesChange: + default: false + type: boolean + routing: + properties: + defineDNSLocalityFields: + type: boolean + dnsDomain: + maxLength: 253 + minLength: 1 + type: string + headlessService: + type: boolean + podIPFamily: + type: integer + publicIPSource: + type: string + useDNSInClusterFile: + type: boolean + type: object + seedConnectionString: + type: string + sidecarContainer: + properties: + enableLivenessProbe: + type: boolean + enableReadinessProbe: + type: boolean + enableTls: + type: boolean + imageConfigs: + items: + properties: + baseImage: + maxLength: 200 + type: string + tag: + maxLength: 100 + type: string + tagSuffix: + maxLength: 50 + type: string + version: + maxLength: 20 + type: string + type: object + maxItems: 100 + type: array + peerVerificationRules: + maxLength: 10000 + type: string + type: object + sidecarVariables: + items: + type: string + type: array + skip: + default: false + type: boolean + storageServersPerPod: + type: integer + trustedCAs: + items: + type: string + type: array + useExplicitListenAddress: + type: boolean + version: + pattern: (\d+)\.(\d+)\.(\d+) + type: string + required: + - version + type: object + status: + properties: + configured: + type: boolean + connectionString: + type: string + databaseConfiguration: + properties: + commit_proxies: + type: integer + excluded_servers: + items: + properties: + address: + maxLength: 48 + type: string + locality: + maxLength: 200 + type: string + type: object + maxItems: 1024 + type: array + grv_proxies: + type: integer + log_routers: + type: integer + log_spill: + type: integer + log_version: + type: integer + logs: + type: integer + perpetual_storage_wiggle: + type: integer + perpetual_storage_wiggle_engine: + enum: + - "" + - ssd + - ssd-1 + - ssd-2 + - memory + - memory-1 + - memory-2 + - ssd-redwood-1-experimental + - ssd-redwood-1 + - ssd-rocksdb-experimental + - ssd-rocksdb-v1 + - ssd-sharded-rocksdb + - memory-radixtree-beta + - custom + - none + maxLength: 100 + type: string + perpetual_storage_wiggle_locality: + type: string + proxies: + type: integer + redundancy_mode: + enum: + - single + - double + - triple + - three_data_hall + maxLength: 100 + type: string + regions: + items: + properties: + datacenters: + items: + properties: + id: + type: string + priority: + type: integer + satellite: + maximum: 1 + minimum: 0 + type: integer + type: object + type: array + satellite_logs: + type: integer + satellite_redundancy_mode: + maxLength: 100 + type: string + type: object + type: array + remote_logs: + type: integer + resolvers: + type: integer + storage: + type: integer + storage_engine: + default: ssd-2 + enum: + - ssd + - ssd-1 + - ssd-2 + - memory + - memory-1 + - memory-2 + - ssd-redwood-1-experimental + - ssd-redwood-1 + - ssd-rocksdb-experimental + - ssd-rocksdb-v1 + - ssd-sharded-rocksdb + - memory-radixtree-beta + - custom + maxLength: 100 + type: string + storage_migration_type: + enum: + - "" + - disabled + - aggressive + - gradual + maxLength: 100 + type: string + usable_regions: + type: integer + type: object + desiredProcessGroups: + type: integer + generations: + properties: + hasExtraListeners: + format: int64 + type: integer + hasPendingRemoval: + format: int64 + type: integer + hasUnhealthyProcess: + format: int64 + type: integer + missingDatabaseStatus: + format: int64 + type: integer + needsBounce: + format: int64 + type: integer + needsConfigurationChange: + format: int64 + type: integer + needsCoordinatorChange: + format: int64 + type: integer + needsGrow: + format: int64 + type: integer + needsLockConfigurationChanges: + format: int64 + type: integer + needsMonitorConfUpdate: + format: int64 + type: integer + needsPodDeletion: + format: int64 + type: integer + needsServiceUpdate: + format: int64 + type: integer + needsShrink: + format: int64 + type: integer + reconciled: + format: int64 + type: integer + type: object + hasIncorrectConfigMap: + type: boolean + hasIncorrectServiceConfig: + type: boolean + hasListenIPsForAllPods: + type: boolean + health: + properties: + available: + type: boolean + dataMovementPriority: + type: integer + fullReplication: + type: boolean + healthy: + type: boolean + type: object + imageTypes: + items: + maxLength: 1024 + type: string + maxItems: 10 + type: array + locks: + properties: + lockDenyList: + items: + type: string + type: array + type: object + logServersPerDisk: + items: + type: integer + maxItems: 5 + type: array + maintenanceModeInfo: + properties: + processGroups: + items: + type: string + maxItems: 200 + type: array + startTimestamp: + format: date-time + type: string + zoneID: + maxLength: 512 + type: string + type: object + needsNewCoordinators: + type: boolean + processGroups: + items: + properties: + addresses: + items: + type: string + type: array + exclusionSkipped: + type: boolean + exclusionTimestamp: + format: date-time + type: string + faultDomain: + maxLength: 512 + type: string + processClass: + type: string + processGroupConditions: + items: + properties: + timestamp: + format: int64 + type: integer + type: + type: string + type: object + type: array + processGroupID: + maxLength: 63 + pattern: ^(([\w-]+)-(\d+)|\*)$ + type: string + removalTimestamp: + format: date-time + type: string + type: object + type: array + reconciledProcessGroups: + type: integer + requiredAddresses: + properties: + nonTLS: + type: boolean + tls: + type: boolean + type: object + runningVersion: + type: string + storageServersPerDisk: + items: + type: integer + maxItems: 5 + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/foundationdb-operator/charts/fdb-operator/crds/apps.foundationdb.org_foundationdbrestores.yaml b/packages/system/foundationdb-operator/charts/fdb-operator/crds/apps.foundationdb.org_foundationdbrestores.yaml new file mode 100644 index 00000000..2f02fb0f --- /dev/null +++ b/packages/system/foundationdb-operator/charts/fdb-operator/crds/apps.foundationdb.org_foundationdbrestores.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + foundationdb.org/release: v2.13.0 + name: foundationdbrestores.apps.foundationdb.org +spec: + group: apps.foundationdb.org + names: + kind: FoundationDBRestore + listKind: FoundationDBRestoreList + plural: foundationdbrestores + shortNames: + - fdbrestore + singular: foundationdbrestore + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.state + name: State + type: string + name: v1beta2 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + blobStoreConfiguration: + properties: + accountName: + maxLength: 100 + type: string + backupName: + maxLength: 1024 + type: string + bucket: + maxLength: 63 + minLength: 3 + type: string + urlParameters: + items: + maxLength: 1024 + type: string + maxItems: 100 + type: array + required: + - accountName + type: object + customParameters: + items: + maxLength: 100 + type: string + maxItems: 100 + type: array + destinationClusterName: + type: string + encryptionKeyPath: + maxLength: 4096 + type: string + keyRanges: + items: + properties: + end: + pattern: ^[A-Za-z0-9\/\\-]+$ + type: string + start: + pattern: ^[A-Za-z0-9\/\\-]+$ + type: string + required: + - end + - start + type: object + type: array + required: + - destinationClusterName + type: object + status: + properties: + running: + type: boolean + state: + maxLength: 50 + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/foundationdb-operator/charts/fdb-operator/templates/NOTES.txt b/packages/system/foundationdb-operator/charts/fdb-operator/templates/NOTES.txt new file mode 100644 index 00000000..ae0e2e2c --- /dev/null +++ b/packages/system/foundationdb-operator/charts/fdb-operator/templates/NOTES.txt @@ -0,0 +1,6 @@ +FoundationDB operator has been installed successfully. + +To see the logs of the operator you can use below command +kubectl logs deployment/{{ include "fdb-operator.fullname" . }} -n {{ .Release.Namespace }} -f + +Thanks for trying out FoundationDB helm chart. diff --git a/packages/system/foundationdb-operator/charts/fdb-operator/templates/_helpers.tpl b/packages/system/foundationdb-operator/charts/fdb-operator/templates/_helpers.tpl new file mode 100644 index 00000000..5d9d5e12 --- /dev/null +++ b/packages/system/foundationdb-operator/charts/fdb-operator/templates/_helpers.tpl @@ -0,0 +1,60 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "fdb-operator.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "fdb-operator.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "fdb-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "fdb-operator.labels" -}} +helm.sh/chart: {{ include "fdb-operator.chart" . }} +{{ include "fdb-operator.selectorLabels" . }} +app.kubernetes.io/version: {{ .Values.image.tag | trimPrefix "v" | quote }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "fdb-operator.selectorLabels" -}} +app.kubernetes.io/name: {{ include "fdb-operator.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account +*/}} +{{- define "fdb-operator.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "fdb-operator.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/packages/system/foundationdb-operator/charts/fdb-operator/templates/manager/deployment.yaml b/packages/system/foundationdb-operator/charts/fdb-operator/templates/manager/deployment.yaml new file mode 100644 index 00000000..e4ef5699 --- /dev/null +++ b/packages/system/foundationdb-operator/charts/fdb-operator/templates/manager/deployment.yaml @@ -0,0 +1,117 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "fdb-operator.fullname" . }} + labels: + {{- include "fdb-operator.labels" . | nindent 4 }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with .Values.replicas }} + replicas: {{ . }} + {{- end }} + selector: + matchLabels: + {{- include "fdb-operator.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "fdb-operator.selectorLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "fdb-operator.serviceAccountName" . }} + {{- with .Values.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + securityContext: + {{- toYaml .Values.securityContext | nindent 8 }} + terminationGracePeriodSeconds: 10 + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + initContainers: + {{- range $version, $params := .Values.initContainers }} + - name: foundationdb-kubernetes-init-{{ $version | replace "." "-" }} + image: {{ $params.image.repository }}:{{ $params.image.tag }} + imagePullPolicy: {{ $params.image.pullPolicy }} + args: + - "--copy-library" + - "{{ $version }}" + - "--copy-binary" + - "fdbcli" + - "--copy-binary" + - "fdbbackup" + - "--copy-binary" + - "fdbrestore" + - "--output-dir" + - "/var/output-files" + - "--mode" + - "init" + volumeMounts: + - name: fdb-binaries + mountPath: /var/output-files + resources: + {{- toYaml $.Values.initContainersResources | nindent 10 }} + securityContext: + {{- toYaml $.Values.initContainerSecurityContext | nindent 10 }} + {{- end }} + containers: + - name: manager + image: {{ .Values.image.repository }}:{{ .Values.image.tag }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - /manager + {{- if not .Values.globalMode.enabled }} + env: + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- end }} + ports: + - containerPort: 8080 + name: metrics + volumeMounts: + - name: tmp + mountPath: /tmp + - name: logs + mountPath: /var/log/fdb + - name: fdb-binaries + mountPath: /usr/bin/fdb + securityContext: + {{- toYaml .Values.containerSecurityContext | nindent 10 }} + livenessProbe: + httpGet: + path: /metrics + port: metrics + resources: + {{- toYaml .Values.resources | nindent 10 }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: tmp + emptyDir: {} + - name: logs + emptyDir: {} + - name: fdb-binaries + emptyDir: {} diff --git a/packages/system/foundationdb-operator/charts/fdb-operator/templates/rbac/rbac_role.yaml b/packages/system/foundationdb-operator/charts/fdb-operator/templates/rbac/rbac_role.yaml new file mode 100644 index 00000000..7772774f --- /dev/null +++ b/packages/system/foundationdb-operator/charts/fdb-operator/templates/rbac/rbac_role.yaml @@ -0,0 +1,131 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +{{- if .Values.globalMode.enabled }} +kind: ClusterRole +{{- else }} +kind: Role +{{- end }} +metadata: + name: {{ include "fdb-operator.fullname" . }} + labels: + {{- include "fdb-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - pods + - configmaps + - persistentvolumeclaims + - events + verbs: + - get + - watch + - list + - create + - update + - patch + - delete +- apiGroups: + - apps.foundationdb.org + resources: + - foundationdbclusters + - foundationdbbackups + - foundationdbrestores + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - apps.foundationdb.org + resources: + - foundationdbclusters/status + - foundationdbbackups/status + - foundationdbrestores/status + verbs: + - get + - update + - patch +- apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + - validatingwebhookconfigurations + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - services + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +{{- if .Values.nodeReadClusterRole }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "fdb-operator.fullname" . }}-clusterrole + labels: + {{- include "fdb-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - nodes + verbs: + - get + - watch + - list +{{- end }} + diff --git a/packages/system/foundationdb-operator/charts/fdb-operator/templates/rbac/rbac_role_binding.yaml b/packages/system/foundationdb-operator/charts/fdb-operator/templates/rbac/rbac_role_binding.yaml new file mode 100644 index 00000000..2335c3c1 --- /dev/null +++ b/packages/system/foundationdb-operator/charts/fdb-operator/templates/rbac/rbac_role_binding.yaml @@ -0,0 +1,44 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +{{- if .Values.globalMode.enabled }} +kind: ClusterRoleBinding +{{- else }} +kind: RoleBinding +{{- end }} +metadata: + name: {{ include "fdb-operator.fullname" . }} + labels: + {{- include "fdb-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + {{- if .Values.globalMode.enabled }} + kind: ClusterRole + {{- else }} + kind: Role + {{- end }} + name: {{ include "fdb-operator.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ include "fdb-operator.serviceAccountName" . }} + {{- if .Values.globalMode.enabled }} + namespace: {{ .Release.Namespace }} + {{- end }} +{{- if .Values.nodeReadClusterRole }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "fdb-operator.fullname" . }}-clusterrolebinding + labels: + {{- include "fdb-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "fdb-operator.fullname" . }}-clusterrole +subjects: +- kind: ServiceAccount + name: {{ include "fdb-operator.serviceAccountName" . }} + {{- if .Values.globalMode.enabled }} + namespace: {{ .Release.Namespace }} + {{- end }} +{{- end }} diff --git a/packages/system/foundationdb-operator/charts/fdb-operator/templates/rbac/serviceaccount.yaml b/packages/system/foundationdb-operator/charts/fdb-operator/templates/rbac/serviceaccount.yaml new file mode 100644 index 00000000..de763cb8 --- /dev/null +++ b/packages/system/foundationdb-operator/charts/fdb-operator/templates/rbac/serviceaccount.yaml @@ -0,0 +1,17 @@ +--- +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "fdb-operator.serviceAccountName" . }} + labels: + {{- include "fdb-operator.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- with .Values.serviceAccount.imagePullSecrets }} +imagePullSecrets: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- end }} diff --git a/packages/system/foundationdb-operator/charts/fdb-operator/values.yaml b/packages/system/foundationdb-operator/charts/fdb-operator/values.yaml new file mode 100644 index 00000000..139af022 --- /dev/null +++ b/packages/system/foundationdb-operator/charts/fdb-operator/values.yaml @@ -0,0 +1,70 @@ +--- +image: + repository: foundationdb/fdb-kubernetes-operator + tag: v2.13.0 + pullPolicy: IfNotPresent +initContainers: + 7.1: + image: + repository: foundationdb/fdb-kubernetes-monitor + tag: 7.1.67 + pullPolicy: IfNotPresent + 7.3: + image: + repository: foundationdb/fdb-kubernetes-monitor + tag: 7.3.63 + pullPolicy: IfNotPresent + 7.4: + image: + repository: foundationdb/fdb-kubernetes-monitor + tag: 7.4.1 + pullPolicy: IfNotPresent +globalMode: + enabled: false +replicas: null +imagePullSecrets: [] +annotations: {} +podAnnotations: {} +podLabels: {} +serviceAccount: + create: true + name: null + imagePullSecrets: [] + annotations: {} +priorityClassName: null +securityContext: + runAsUser: 4059 + runAsGroup: 4059 + fsGroup: 4059 +containerSecurityContext: + allowPrivilegeEscalation: false + privileged: false + capabilities: + drop: + - all + readOnlyRootFilesystem: true +nodeSelector: {} +affinity: {} +tolerations: {} +resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 500m + memory: 256Mi +initContainersResources: + limits: + cpu: 10m + memory: 50Mi + requests: + cpu: 10m + memory: 50Mi +initContainerSecurityContext: + allowPrivilegeEscalation: false + privileged: false + capabilities: + drop: + - all + readOnlyRootFilesystem: true +nodeReadClusterRole: true diff --git a/packages/system/foundationdb-operator/values.yaml b/packages/system/foundationdb-operator/values.yaml new file mode 100644 index 00000000..044e81c7 --- /dev/null +++ b/packages/system/foundationdb-operator/values.yaml @@ -0,0 +1,4 @@ +fdb-operator: + globalMode: + enabled: true + nodeReadClusterRole: true \ No newline at end of file diff --git a/packages/system/foundationdb-rd/Chart.yaml b/packages/system/foundationdb-rd/Chart.yaml new file mode 100644 index 00000000..1c8afe3a --- /dev/null +++ b/packages/system/foundationdb-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: foundationdb-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/foundationdb-rd/Makefile b/packages/system/foundationdb-rd/Makefile new file mode 100644 index 00000000..2b3b51c6 --- /dev/null +++ b/packages/system/foundationdb-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=foundationdb-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/foundationdb-rd/cozyrds/foundationdb.yaml b/packages/system/foundationdb-rd/cozyrds/foundationdb.yaml new file mode 100644 index 00000000..e6f23f79 --- /dev/null +++ b/packages/system/foundationdb-rd/cozyrds/foundationdb.yaml @@ -0,0 +1,28 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: foundationdb +spec: + application: + kind: FoundationDB + singular: foundationdb + plural: foundationdbs + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"automaticReplacements":{"description":"Enable automatic pod replacements","type":"boolean","default":true},"backup":{"description":"Backup configuration","type":"object","default":{"enabled":false,"retentionPolicy":"7d","s3":{"bucket":"","credentials":{"accessKeyId":"","secretAccessKey":""},"endpoint":"","region":"us-east-1"}},"required":["enabled","retentionPolicy","s3"],"properties":{"enabled":{"description":"Enable backups","type":"boolean","default":false},"retentionPolicy":{"description":"Retention policy for backups","type":"string","default":"7d"},"s3":{"description":"S3 configuration for backups","type":"object","default":{"bucket":"","credentials":{"accessKeyId":"","secretAccessKey":""},"endpoint":"","region":"us-east-1"},"required":["bucket","credentials","endpoint","region"],"properties":{"bucket":{"description":"S3 bucket name","type":"string"},"credentials":{"description":"S3 credentials","type":"object","default":{"accessKeyId":"","secretAccessKey":""},"required":["accessKeyId","secretAccessKey"],"properties":{"accessKeyId":{"description":"S3 access key ID","type":"string"},"secretAccessKey":{"description":"S3 secret access key","type":"string"}}},"endpoint":{"description":"S3 endpoint URL","type":"string"},"region":{"description":"S3 region","type":"string","default":"us-east-1"}}}}},"cluster":{"description":"Cluster configuration","type":"object","default":{"faultDomain":{"key":"kubernetes.io/hostname","valueFrom":"spec.nodeName"},"processCounts":{"cluster_controller":1,"stateless":-1,"storage":3},"redundancyMode":"double","storageEngine":"ssd-2","version":"7.3.63"},"required":["faultDomain","processCounts","redundancyMode","storageEngine","version"],"properties":{"faultDomain":{"description":"Fault domain configuration","type":"object","default":{"key":"kubernetes.io/hostname","valueFrom":"spec.nodeName"},"required":["key","valueFrom"],"properties":{"key":{"description":"Fault domain key","type":"string","default":"kubernetes.io/hostname"},"valueFrom":{"description":"Fault domain value source","type":"string","default":"spec.nodeName"}}},"processCounts":{"description":"Process counts for different roles","type":"object","default":{"cluster_controller":1,"stateless":-1,"storage":3},"required":["cluster_controller","stateless","storage"],"properties":{"cluster_controller":{"description":"Number of cluster controller processes","type":"integer","default":1},"stateless":{"description":"Number of stateless processes (-1 for automatic)","type":"integer","default":-1},"storage":{"description":"Number of storage processes (determines cluster size)","type":"integer","default":3}}},"redundancyMode":{"description":"Database redundancy mode (single, double, triple, three_datacenter, three_datacenter_fallback)","type":"string","default":"double"},"storageEngine":{"description":"Storage engine (ssd-2, ssd-redwood-v1, ssd-rocksdb-v1, memory)","type":"string","default":"ssd-2"},"version":{"description":"Version of FoundationDB to use","type":"string","default":"7.3.63"}}},"customParameters":{"description":"Custom parameters to pass to FoundationDB","type":"array","default":[],"items":{"type":"string"}},"imageType":{"description":"Container image deployment type","type":"string","default":"unified","enum":["unified","split"]},"monitoring":{"description":"Monitoring configuration","type":"object","default":{"enabled":true},"required":["enabled"],"properties":{"enabled":{"description":"Enable WorkloadMonitor integration","type":"boolean","default":true}}},"resources":{"description":"Explicit CPU and memory configuration for each FoundationDB instance. When left empty, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each instance","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each instance","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. Allowed values: `small`, `medium`, `large`, `xlarge`, `2xlarge`.","type":"string","default":"medium","enum":["small","medium","large","xlarge","2xlarge"]},"securityContext":{"description":"Security context for containers","type":"object","default":{"runAsGroup":4059,"runAsUser":4059},"required":["runAsGroup","runAsUser"],"properties":{"runAsGroup":{"description":"Group ID to run the container","type":"integer","default":4059},"runAsUser":{"description":"User ID to run the container","type":"integer","default":4059}}},"storage":{"description":"Storage configuration","type":"object","default":{"size":"16Gi","storageClass":""},"required":["size","storageClass"],"properties":{"size":{"description":"Size of persistent volumes for each instance","default":"16Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"Storage class (if not set, uses cluster default)","type":"string"}}}}} + release: + prefix: foundationdb- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-foundationdb-application-default-foundationdb + namespace: cozy-system + dashboard: + category: PaaS + singular: FoundationDB + plural: FoundationDB + description: Managed FoundationDB service + tags: + - database + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX3JhZGlhbF84NThfMzA3MikiLz4KPHBhdGggZD0iTTEzNS43ODQgNzUuNjQ0NkwxMzUuOTM5IDg3Ljc2MzhMODkuNjg0NiA4MS41MzYyTDYyLjA4NjggODQuNTA3OUwzNS4zNDE3IDgxLjQzMjlMOC43NTE2NyA4NC41ODU0TDguNzI1ODMgODEuNTEwNEwzNS4zNjc2IDc3LjU4MjZWNjQuMTcxM0w2Mi4yOTM1IDcwLjczNDhMNjIuMzQ1MiA4MS4yNzc4TDg5LjQ3NzkgNzcuNjg2TDg5LjQwMDQgNjQuMTk3MkwxMzUuNzg0IDc1LjY0NDZaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNODkuNDc3OCA4Ni4wMzI1TDEzNS44ODggOTAuODM4OFYxMDIuNzI2SDguNjQ4MjVMOC41MTkwNCA5OS41NzNIMzUuMjY0MUMzNS4yNjQxIDk5LjU3MyAzNS4yNjQxIDkwLjczNTUgMzUuMjY0MSA4Ni4wNTgzQzQ0LjI1NjcgODYuOTM2OSA2Mi4wODY3IDg4LjY5NDEgNjIuMDg2NyA4OC42OTQxVjk5LjI2MjlIODkuNDc3OFY4Ni4wMzI1WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTYyLjI5MzQgNjYuODg0Nkw2Mi4yMTU4IDYzLjYyODZDNjIuMjE1OCA2My42Mjg2IDc5LjgxMzMgNTguMzU3MSA4OC45MDkyIDU1LjY2OTdDODguOTA5MiA1MS4zMDI2IDg4LjkwOTIgNDcuMDkwNiA4OC45MDkyIDQyQzEwNC44NzkgNDguNDA4NSAxMjAuMjI4IDU0LjYxMDIgMTM1LjczMyA2MC44Mzc4QzEzNS43MzMgNjQuNzEzOSAxMzUuNzMzIDY4LjQzNSAxMzUuNzMzIDcyLjU2OTVDMTE5Ljg0MSA2OC4yMDI0IDEwNC4yODQgNjMuOTEyOSA4OS4xNjc2IDU5Ljc1MjVDNzkuOTY4NCA2Mi4yMDc0IDYyLjI5MzQgNjYuODg0NiA2Mi4yOTM0IDY2Ljg4NDZaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMzUuMzk2MiA4MS43MDczTDguODA2MTIgODQuODU5OEw4Ljc4MDI3IDgxLjc4NDhMMzUuNDIyIDc3Ljg1N1Y2NC40NDU3TDYyLjM0OCA3MS4wMDkzTDYyLjM5OTYgODEuNTUyMkw4OS41MzIzIDc3Ljk2MDRMODkuNDU0OCA2NC40NzE2TDEzNS44MzkgNzUuOTE5TDEzNS45OTQgODguMDM4Mkw4OS43MzkxIDgxLjgxMDZMNjIuMTQxMiA4NC43ODIzTDM1LjM5NjIgODEuNzA3M1oiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik04OS41MzIzIDg2LjMwNjlMMTM1Ljk0MiA5MS4xMTMzVjEwM0g4LjcwMjdMOC41NzM0OSA5OS44NDc0SDM1LjMxODZDMzUuMzE4NiA5OS44NDc0IDM1LjMxODYgOTEuMDA5OSAzNS4zMTg2IDg2LjMzMjhDNDQuMzExMSA4Ny4yMTE0IDYyLjE0MTIgODguOTY4NSA2Mi4xNDEyIDg4Ljk2ODVWOTkuNTM3M0g4OS41MzIzVjg2LjMwNjlaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNNjIuMzQ4MyA2Ny4xNTlMNjIuMjcwOCA2My45MDMxQzYyLjI3MDggNjMuOTAzMSA3OS44NjgyIDU4LjYzMTYgODguOTY0MiA1NS45NDQyQzg4Ljk2NDIgNTEuNTc3MSA4OC45NjQyIDQ3LjM2NTEgODguOTY0MiA0Mi4yNzQ0QzEwNC45MzQgNDguNjgyOSAxMjAuMjgzIDU0Ljg4NDcgMTM1Ljc4NyA2MS4xMTIzQzEzNS43ODcgNjQuOTg4NCAxMzUuNzg3IDY4LjcwOTQgMTM1Ljc4NyA3Mi44NDM5QzExOS44OTUgNjguNDc2OSAxMDQuMzM5IDY0LjE4NzMgODkuMjIyNiA2MC4wMjdDODAuMDIzMyA2Mi40ODE4IDYyLjM0ODMgNjcuMTU5IDYyLjM0ODMgNjcuMTU5WiIgZmlsbD0id2hpdGUiLz4KPGRlZnM+CjxyYWRpYWxHcmFkaWVudCBpZD0icGFpbnQwX3JhZGlhbF84NThfMzA3MiIgY3g9IjAiIGN5PSIwIiByPSIxIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgtMjkuNSAtMTgpIHJvdGF0ZSgzOS42OTYzKSBzY2FsZSgzMDIuMTY4IDI3NS4yNzEpIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0JFRERGRiIvPgo8c3RvcCBvZmZzZXQ9IjAuMjU5NjE1IiBzdG9wLWNvbG9yPSIjOUVDQ0ZEIi8+CjxzdG9wIG9mZnNldD0iMC41OTEzNDYiIHN0b3AtY29sb3I9IiMzRjlBRkIiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMEI3MEUwIi8+CjwvcmFkaWFsR3JhZGllbnQ+CjwvZGVmcz4KPC9zdmc+Cg== + # keysOrder: [] diff --git a/packages/system/foundationdb-rd/templates/cozyrd.yaml b/packages/system/foundationdb-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/foundationdb-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/foundationdb-rd/values.yaml b/packages/system/foundationdb-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/foundationdb-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/gateway-api-crds/Makefile b/packages/system/gateway-api-crds/Makefile index c4311662..ad51d591 100644 --- a/packages/system/gateway-api-crds/Makefile +++ b/packages/system/gateway-api-crds/Makefile @@ -1,7 +1,7 @@ export NAME=gateway-api-crds export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf templates diff --git a/packages/system/goldpinger/Makefile b/packages/system/goldpinger/Makefile index 3ddd79ba..0aeef2ad 100644 --- a/packages/system/goldpinger/Makefile +++ b/packages/system/goldpinger/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/gpu-operator/Makefile b/packages/system/gpu-operator/Makefile index 286451f3..49b26e26 100644 --- a/packages/system/gpu-operator/Makefile +++ b/packages/system/gpu-operator/Makefile @@ -1,8 +1,8 @@ export NAME=gpu-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/gpu-operator/examples/README.md b/packages/system/gpu-operator/examples/README.md new file mode 100644 index 00000000..b6f170c8 --- /dev/null +++ b/packages/system/gpu-operator/examples/README.md @@ -0,0 +1,121 @@ +# GPU operator — native pod workload on Talos (reference) + +The files in this directory are **not** templates. They are reference +artifacts that document one working configuration for running GPU +workloads directly in pods on a Talos-based Cozystack cluster, together +with the DCGM metrics needed by the `gpu/gpu-performance` Grafana +dashboard. + +The out-of-the-box `values-talos.yaml` for this package targets the +sandbox (VFIO passthrough to KubeVirt VMs) scenario. The files here +illustrate an alternative — running CUDA workloads in regular pods with +the NVIDIA device plugin — and the workarounds it currently requires on +Talos. + +## Files + +- [`values-native-talos.yaml`](./values-native-talos.yaml) — Cozystack + `Package` values that disable sandbox workloads, enable the device + plugin, point `hostPaths.driverInstallDir` at the staging location + used by the compat DaemonSet, and wire DCGM to the custom metrics + ConfigMap. +- [`dcgm-custom-metrics.yaml`](./dcgm-custom-metrics.yaml) — `ConfigMap` + with a DCGM metrics CSV that adds profiling, ECC, throttling and + energy counters on top of the upstream defaults. The CSV is a + superset needed for full coverage of the `gpu/gpu-performance` + dashboard. Which parts are actually required depends on which + dashboards you ship — see the table below. +- [`nvidia-driver-compat.yaml`](./nvidia-driver-compat.yaml) — DaemonSet + that stages `libnvidia-ml.so.1` and `nvidia-smi` from the Talos glibc + tree into a path where the NVIDIA GPU Operator validator expects + them. See the "Why the compat DaemonSet exists" section below. + +## Why these are reference, not templates + +Shipping these as first-class templates would silently impose +assumptions that do not hold for every user: + +- Whether the NVIDIA Talos system extension is installed on the nodes. +- Whether GPUs are exposed directly to pods or passed through to VMs. +- The exact path the installed driver ends up at (depends on the + extension version and Talos release). + +The sandbox-oriented `values-talos.yaml` remains the default. Operators +who want native pod GPU workloads can start from this directory and +adapt as needed. + +## Why the compat DaemonSet exists + +The NVIDIA GPU Operator validator checks for `libnvidia-ml.so.1` and +`bin/nvidia-smi` in the path given by `hostPaths.driverInstallDir`. +Talos installs them under `/usr/local/glibc/usr/lib/` and +`/usr/local/bin/`, which the validator does not look at. Until upstream +addresses [NVIDIA/gpu-operator#1687][1], the DaemonSet copies those +files into a directory the validator does inspect and creates the +`.driver-ctr-ready` flag file so the validator proceeds. + +[1]: https://github.com/NVIDIA/gpu-operator/issues/1687 + +The compat DaemonSet runs privileged and bind-mounts host paths, so +the target namespace must allow privileged pods. On clusters that +enforce the Kubernetes Pod Security Standards at `baseline` or +`restricted`, label the namespace with +`pod-security.kubernetes.io/enforce: privileged` (and the matching +`audit`/`warn` labels if the admission webhook is configured to +surface violations) before applying the manifest. + +## Dashboards and what DCGM metrics they need + +Five GPU dashboards live under `gpu/*` in +`packages/system/monitoring/dashboards-infra.list`. All of them share +`packages/system/monitoring-agents/alerts/gpu-recording.rules.yaml` as +their source of aggregated series. The recording rules are safe to +ship on any cluster — they evaluate to empty series when DCGM is not +scraped, or when optional counters are missing. + +What each dashboard needs on top of the upstream DCGM Exporter +[`default-counters.csv`][default-csv]: + +| Dashboard | Scope | Needs beyond defaults | +| ----------------- | ---------------------------------- | ----------------------------------------------------------------------- | +| `gpu-performance` | Per-node, per-GPU deep dive | `DCGM_FI_DEV_POWER_VIOLATION`, `DCGM_FI_DEV_THERMAL_VIOLATION` | +| `gpu-efficiency` | Per-workload util vs tensor active | `DCGM_FI_DEV_POWER_VIOLATION`, `DCGM_FI_DEV_THERMAL_VIOLATION` (via `gpu:*_throttle_fraction:rate5m` recording rules) | +| `gpu-fleet` | Cluster-wide admin inventory | `DCGM_FI_DEV_POWER_MGMT_LIMIT` (for the TDP vs draw panel) | +| `gpu-quotas` | Kube-quota vs live usage | `kube_pod_container_resource_requests`, `kube_pod_status_phase`, `kube_node_status_allocatable` (via `namespace:gpu_count:allocated` / `cluster:gpu_count:*` recording rules) | +| `gpu-tenants` | Per-namespace tenant view | nothing (works on default counters) | + +`DCGM_FI_PROF_PIPE_TENSOR_ACTIVE` and `DCGM_FI_PROF_GR_ENGINE_ACTIVE` +are already in the upstream default set for the pinned DCGM Exporter +version, so the tensor-saturation and engine-active panels work without +any CSV override. The three counters listed in the table — throttling +violations and the power management limit — are the only extras the +tracked dashboards need. The recording rules in +`gpu-recording.rules.yaml` consume utilization, FB used, power, +temperature and the tensor-active profiling counter from the default +set, plus `DCGM_FI_DEV_POWER_VIOLATION` and +`DCGM_FI_DEV_THERMAL_VIOLATION` — used by the +`gpu.recording.efficiency.1m` group to derive the +`gpu:power_throttle_fraction:rate5m` and +`gpu:thermal_throttle_fraction:rate5m` series consumed by the +throttling panels on the efficiency and fleet dashboards. + +The `gpu.recording.throttle.validation.5m` group additionally ships the +`GPUThrottleFractionOverOne` alert (severity `warning`) as a regression +detector: it fires when either throttle-fraction series exceeds 1.0, +which would indicate that DCGM changed the scale/divisor of the +underlying violation counters and the recording rules need to be +re-derived. + +## Verification status + +The minimum-CSV claims above are verified by +`hack/check-gpu-recording-rules.bats`, which cross-checks every +`DCGM_FI_*` reference in the tracked GPU dashboards and recording rules +against the union of the upstream default set (snapshotted at +`hack/dcgm-default-counters.csv` for the pinned DCGM Exporter version) +and the custom CSV in `dcgm-custom-metrics.yaml`. When the DCGM +Exporter image in `packages/system/gpu-operator/charts/gpu-operator/values.yaml` +is bumped, refresh the snapshot from the matching tag of the +[`NVIDIA/dcgm-exporter`][default-csv] repository and rerun the test. + +[default-csv]: https://github.com/NVIDIA/dcgm-exporter/blob/main/etc/default-counters.csv diff --git a/packages/system/gpu-operator/examples/dcgm-custom-metrics.yaml b/packages/system/gpu-operator/examples/dcgm-custom-metrics.yaml new file mode 100644 index 00000000..ef2b0b88 --- /dev/null +++ b/packages/system/gpu-operator/examples/dcgm-custom-metrics.yaml @@ -0,0 +1,88 @@ +# Custom DCGM Exporter metrics CSV. Referenced from +# examples/values-native-talos.yaml via dcgmExporter.config.name. +# +# Extends the upstream default set with profiling counters, ECC, page +# retirement, row remap, energy and throttling violations — everything +# the gpu/gpu-performance dashboard and the GPU recording rules in +# monitoring-agents expect. +apiVersion: v1 +kind: ConfigMap +metadata: + name: dcgm-custom-metrics + namespace: cozy-gpu-operator +data: + dcgm-metrics.csv: | + # Format + # If line starts with a '#' it is considered a comment + # DCGM FIELD, Prometheus metric type, help message + + # Identity + DCGM_FI_DRIVER_VERSION, label, Driver version. + + # Clocks + DCGM_FI_DEV_SM_CLOCK, gauge, SM clock frequency (in MHz). + DCGM_FI_DEV_MEM_CLOCK, gauge, Memory clock frequency (in MHz). + + # Temperature + DCGM_FI_DEV_MEMORY_TEMP, gauge, Memory temperature (in C). + DCGM_FI_DEV_GPU_TEMP, gauge, GPU temperature (in C). + + # Power + DCGM_FI_DEV_POWER_USAGE, gauge, Power draw (in W). + DCGM_FI_DEV_POWER_MGMT_LIMIT, gauge, Current power management limit (in W). + DCGM_FI_DEV_TOTAL_ENERGY_CONSUMPTION, counter, Total energy consumption since boot (in mJ). + + # PCIE + DCGM_FI_DEV_PCIE_REPLAY_COUNTER, counter, Total number of PCIe retries. + + # Utilization (the sample period varies depending on the product) + DCGM_FI_DEV_GPU_UTIL, gauge, GPU utilization (in %). + DCGM_FI_DEV_MEM_COPY_UTIL, gauge, Memory utilization (in %). + DCGM_FI_DEV_ENC_UTIL, gauge, Encoder utilization (in %). + DCGM_FI_DEV_DEC_UTIL, gauge, Decoder utilization (in %). + + # Errors and violations + DCGM_FI_DEV_XID_ERRORS, gauge, Value of the last XID error encountered. + + # Memory usage + DCGM_FI_DEV_FB_FREE, gauge, Framebuffer memory free (in MiB). + DCGM_FI_DEV_FB_USED, gauge, Framebuffer memory used (in MiB). + DCGM_FI_DEV_FB_RESERVED, gauge, Framebuffer memory reserved (in MiB). + + # ECC (supported on datacenter-class GPUs such as A10) + DCGM_FI_DEV_ECC_SBE_VOL_TOTAL, counter, Total number of single-bit volatile ECC errors. + DCGM_FI_DEV_ECC_DBE_VOL_TOTAL, counter, Total number of double-bit volatile ECC errors. + DCGM_FI_DEV_ECC_SBE_AGG_TOTAL, counter, Total number of single-bit persistent ECC errors. + DCGM_FI_DEV_ECC_DBE_AGG_TOTAL, counter, Total number of double-bit persistent ECC errors. + + # Retired pages + DCGM_FI_DEV_RETIRED_SBE, counter, Total number of retired pages due to single-bit errors. + DCGM_FI_DEV_RETIRED_DBE, counter, Total number of retired pages due to double-bit errors. + DCGM_FI_DEV_RETIRED_PENDING, counter, Total number of pages pending retirement. + + # Row remapping (not applicable to GDDR6 but left for datacenter GPUs) + DCGM_FI_DEV_UNCORRECTABLE_REMAPPED_ROWS, counter, Number of remapped rows for uncorrectable errors. + DCGM_FI_DEV_CORRECTABLE_REMAPPED_ROWS, counter, Number of remapped rows for correctable errors. + DCGM_FI_DEV_ROW_REMAP_FAILURE, gauge, Whether remapping of rows has failed. + + # Throttle / violation counters (crucial for SLA and tenant monitoring) + DCGM_FI_DEV_POWER_VIOLATION, counter, Throttling duration due to power constraints (us per docs; ns on DCGM 3.x). + DCGM_FI_DEV_THERMAL_VIOLATION, counter, Throttling duration due to thermal constraints (us per docs; ns on DCGM 3.x). + DCGM_FI_DEV_SYNC_BOOST_VIOLATION, counter, Throttling duration due to sync-boost constraints (us per docs; ns on DCGM 3.x). + DCGM_FI_DEV_BOARD_LIMIT_VIOLATION, counter, Throttling duration due to board limit constraints (us per docs; ns on DCGM 3.x). + DCGM_FI_DEV_LOW_UTIL_VIOLATION, counter, Throttling duration due to low utilization (us per docs; ns on DCGM 3.x). + DCGM_FI_DEV_RELIABILITY_VIOLATION, counter, Throttling duration due to reliability constraints (us per docs; ns on DCGM 3.x). + + # NVLink — DCGM silently drops this metric on GPUs without NVLink, so + # enabling it unconditionally is safe and keeps this file reusable + # across GPU families. + DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL, counter, Total number of NVLink bandwidth counters for all lanes. + + # DCP (profiling) metrics — supported from Ampere onwards. + DCGM_FI_PROF_GR_ENGINE_ACTIVE, gauge, Ratio of time the graphics engine is active. + DCGM_FI_PROF_SM_ACTIVE, gauge, The ratio of cycles an SM has at least 1 warp assigned. + DCGM_FI_PROF_SM_OCCUPANCY, gauge, The ratio of number of warps resident on an SM. + DCGM_FI_PROF_PIPE_TENSOR_ACTIVE, gauge, Ratio of cycles the tensor (HMMA) pipe is active. + DCGM_FI_PROF_DRAM_ACTIVE, gauge, Ratio of cycles the device memory interface is active sending or receiving data. + DCGM_FI_PROF_PCIE_TX_BYTES, counter, The number of bytes of active PCIe tx (transmit) data including both header and payload. + DCGM_FI_PROF_PCIE_RX_BYTES, counter, The number of bytes of active PCIe rx (read) data including both header and payload. diff --git a/packages/system/gpu-operator/examples/nvidia-driver-compat.yaml b/packages/system/gpu-operator/examples/nvidia-driver-compat.yaml new file mode 100644 index 00000000..fc9d5981 --- /dev/null +++ b/packages/system/gpu-operator/examples/nvidia-driver-compat.yaml @@ -0,0 +1,109 @@ +# Workaround for https://github.com/NVIDIA/gpu-operator/issues/1687 +# +# On Talos, the NVIDIA system extension installs driver files under +# /usr/local/glibc/usr/lib/ and /usr/local/bin/. The GPU Operator +# validator only looks for libnvidia-ml.so.1 and bin/nvidia-smi under +# the path configured as hostPaths.driverInstallDir. This DaemonSet +# stages the required files into /var/nvidia-driver on each node and +# creates the .driver-ctr-ready flag so the validator proceeds. +# +# Paired with examples/values-native-talos.yaml, which sets +# hostPaths.driverInstallDir to /var/nvidia-driver. +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: nvidia-driver-compat + namespace: cozy-gpu-operator + labels: + app: nvidia-driver-compat +spec: + selector: + matchLabels: + app: nvidia-driver-compat + template: + metadata: + labels: + app: nvidia-driver-compat + # DaemonSet rather than a one-shot Job: staging is idempotent per-node, + # must re-run after every Talos reboot (hostPath contents are wiped on + # reboot when the system extension re-installs), and the pause container + # keeps the pod visible for operator observability (kubectl get pods). + spec: + priorityClassName: system-node-critical + # Restrict to GPU nodes only. Without this the DaemonSet schedules onto + # every node (including control-plane and CPU-only workers) and burns + # resources on hosts where the compat tree is meaningless. + # The label is published by Node Feature Discovery / GPU Operator's NFD + # subchart; if NFD is disabled, replace this with whatever label your + # cluster uses to mark GPU hosts. + nodeSelector: + nvidia.com/gpu.present: "true" + # Tolerate-all is intentionally broad: the nodeSelector above already + # confines scheduling to GPU nodes, so the "Exists" toleration only + # matters when those nodes carry extra taints (dedicated=gpu:NoSchedule, + # nvidia.com/gpu:NoSchedule from the GPU Operator's default policy, + # etc.). This mirrors the stance of the upstream nvidia-driver-daemonset + # and nvidia-device-plugin DaemonSets — blanket tolerations plus a + # narrow nodeSelector. + tolerations: + - operator: Exists + initContainers: + - name: create-driver-tree + image: busybox:1.37 + command: + - sh + - -c + - | + set -e + GLIBC_LIB="/host/usr/local/glibc/usr/lib" + SRC_BIN="/host/usr/local/bin" + DST="/host/var/nvidia-driver" + + mkdir -p "$DST/bin" + + [ -f "$GLIBC_LIB/libnvidia-ml.so.1" ] || { + echo "missing $GLIBC_LIB/libnvidia-ml.so.1" >&2 + exit 1 + } + [ -f "$SRC_BIN/nvidia-smi" ] || { + echo "missing $SRC_BIN/nvidia-smi" >&2 + exit 1 + } + + cp -f "$GLIBC_LIB/libnvidia-ml.so.1" "$DST/libnvidia-ml.so.1" + echo "Copied libnvidia-ml.so.1" + + cp -f "$SRC_BIN/nvidia-smi" "$DST/bin/nvidia-smi" + chmod +x "$DST/bin/nvidia-smi" + echo "Copied nvidia-smi" + + mkdir -p /host/run/nvidia/validations + touch /host/run/nvidia/validations/.driver-ctr-ready + echo "Created driver-ctr-ready flag" + echo "Done" + securityContext: + privileged: true + resources: + requests: + cpu: 10m + memory: 16Mi + limits: + cpu: 100m + memory: 64Mi + volumeMounts: + - name: host-root + mountPath: /host + containers: + - name: pause + image: registry.k8s.io/pause:3.10 + resources: + requests: + cpu: 10m + memory: 8Mi + limits: + cpu: 50m + memory: 16Mi + volumes: + - name: host-root + hostPath: + path: / diff --git a/packages/system/gpu-operator/examples/values-native-talos.yaml b/packages/system/gpu-operator/examples/values-native-talos.yaml new file mode 100644 index 00000000..ef7b2891 --- /dev/null +++ b/packages/system/gpu-operator/examples/values-native-talos.yaml @@ -0,0 +1,52 @@ +# Cozystack Package values for running GPU workloads natively in pods +# on Talos. This is the counterpart to values-talos.yaml, which targets +# the sandbox (VFIO passthrough) scenario. +# +# Prerequisites: +# - NVIDIA Talos system extension installed on GPU nodes. +# - examples/nvidia-driver-compat.yaml deployed to stage driver files +# where the gpu-operator validator looks for them. +# - examples/dcgm-custom-metrics.yaml applied so DCGM Exporter exports +# the full set of metrics used by the dashboard and recording rules. +apiVersion: cozystack.io/v1alpha1 +kind: Package +metadata: + name: cozystack.gpu-operator +spec: + variant: default + components: + gpu-operator: + values: + gpu-operator: + # The compat DaemonSet stages libnvidia-ml.so.1 and nvidia-smi + # under /var/nvidia-driver. Point the validator at that path. + hostPaths: + driverInstallDir: "/var/nvidia-driver" + # Disable the sandbox path — workloads run in pods, not VMs. + sandboxWorkloads: + enabled: false + vfioManager: + enabled: false + # The Talos extension provides the driver and runtime hooks, + # so the operator's own toolkit and driver components must be + # switched off to avoid conflicting installations. + toolkit: + enabled: false + devicePlugin: + enabled: true + # Export full set of DCGM metrics using the ConfigMap in + # examples/dcgm-custom-metrics.yaml. + dcgmExporter: + serviceMonitor: + enabled: true + # Matches the 1m evaluation cadence of GPU recording rules with + # 4x oversampling headroom. DCGM_FI_PROF_* counters have + # documented overhead concerns below 1s; 15s is safe. + interval: "15s" + honorLabels: true + relabelings: + - sourceLabels: [__meta_kubernetes_pod_node_name] + targetLabel: node + action: replace + config: + name: dcgm-custom-metrics diff --git a/packages/system/grafana-operator/Makefile b/packages/system/grafana-operator/Makefile index 82c734d4..34d36142 100644 --- a/packages/system/grafana-operator/Makefile +++ b/packages/system/grafana-operator/Makefile @@ -1,10 +1,22 @@ export NAME=grafana-operator export NAMESPACE=cozy-grafana-operator -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts mkdir -p charts curl -sSL https://github.com/grafana-operator/grafana-operator/archive/refs/heads/master.tar.gz | \ tar xzvf - --strip 3 -C charts grafana-operator-master/deploy/helm/grafana-operator + +image: + docker buildx build --file images/grafana-dashboards/Dockerfile ../../.. \ + --tag $(REGISTRY)/grafana-dashboards:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/grafana-dashboards:latest \ + --cache-to type=inline \ + --metadata-file images/grafana-dashboards.json \ + $(BUILDX_ARGS) + echo "$(REGISTRY)/grafana-dashboards:$(call settag,$(TAG))@$$(yq --exit-status '.["containerimage.digest"]' images/grafana-dashboards.json --output-format json -r)" \ + > images/grafana-dashboards.tag + rm -f images/grafana-dashboards.json diff --git a/packages/system/grafana-operator/images/grafana-dashboards.tag b/packages/system/grafana-operator/images/grafana-dashboards.tag new file mode 100644 index 00000000..cde83a70 --- /dev/null +++ b/packages/system/grafana-operator/images/grafana-dashboards.tag @@ -0,0 +1 @@ +ghcr.io/cozystack/cozystack/grafana-dashboards:v1.3.0@sha256:2c9aa0b48e2bf6167db198f4d15882bfe51700108edf2e9f6d0942940a2c1204 diff --git a/packages/system/grafana-operator/images/grafana-dashboards/Dockerfile b/packages/system/grafana-operator/images/grafana-dashboards/Dockerfile new file mode 100644 index 00000000..8ea43e76 --- /dev/null +++ b/packages/system/grafana-operator/images/grafana-dashboards/Dockerfile @@ -0,0 +1,11 @@ +FROM alpine:3.22 + +RUN apk add --no-cache darkhttpd + +COPY dashboards /var/www/dashboards + +WORKDIR /var/www + +EXPOSE 8080 + +CMD ["darkhttpd", "/var/www/dashboards", "--port", "8080", "--addr", "0.0.0.0"] diff --git a/packages/system/grafana-operator/images/grafana-dashboards/Dockerfile.dockerignore b/packages/system/grafana-operator/images/grafana-dashboards/Dockerfile.dockerignore new file mode 100644 index 00000000..fa588871 --- /dev/null +++ b/packages/system/grafana-operator/images/grafana-dashboards/Dockerfile.dockerignore @@ -0,0 +1,3 @@ +# Exclude everything except dashboards directory +* +!dashboards/** diff --git a/packages/system/grafana-operator/templates/dashboards-deployment.yaml b/packages/system/grafana-operator/templates/dashboards-deployment.yaml new file mode 100644 index 00000000..f9b1f99b --- /dev/null +++ b/packages/system/grafana-operator/templates/dashboards-deployment.yaml @@ -0,0 +1,41 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana-dashboards + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: grafana-dashboards + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: dashboards +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: grafana-dashboards + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: grafana-dashboards + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: dashboards + spec: + containers: + - name: dashboards + image: {{ $.Files.Get "images/grafana-dashboards.tag" | trim }} + ports: + - containerPort: 8080 + name: http + protocol: TCP + livenessProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 10 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 5 diff --git a/packages/system/grafana-operator/templates/dashboards-service.yaml b/packages/system/grafana-operator/templates/dashboards-service.yaml new file mode 100644 index 00000000..011072c3 --- /dev/null +++ b/packages/system/grafana-operator/templates/dashboards-service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: grafana-dashboards + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: grafana-dashboards + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: dashboards +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 8080 + protocol: TCP + name: http + selector: + app.kubernetes.io/name: grafana-dashboards + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/packages/system/hami/Chart.yaml b/packages/system/hami/Chart.yaml new file mode 100644 index 00000000..3fcf4c5d --- /dev/null +++ b/packages/system/hami/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-hami +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/hami/Makefile b/packages/system/hami/Makefile new file mode 100644 index 00000000..83663a66 --- /dev/null +++ b/packages/system/hami/Makefile @@ -0,0 +1,43 @@ +export NAME=hami +export NAMESPACE=cozy-$(NAME) + +include ../../../hack/common-envs.mk +include ../../../hack/package.mk + +# When bumping the HAMi version, run `make update` and then review +# the resulting diff in `charts/hami/`. The recipe below reproduces the +# top-level vendoring overrides automatically: +# +# 1. Removes the broken hami-dra subchart. Upstream's NVIDIA DRA driver +# path requires kubelet DRA support that cozystack does not enable +# and has no upstream fix tracked. See commit 3c5521e. +# 2. Empties Chart.yaml dependencies and drops Chart.lock so Helm does +# not try to re-pull hami-dra at build time. See commit 2734dc0. +# 3. Strips dra/hami-dra/podSecurityPolicy blocks from the upstream +# values.yaml since the corresponding code paths are gone. PSP is +# removed from Kubernetes 1.25+ and is unused by cozystack. +# +# Template-level patches are NOT reproduced automatically: +# +# * Scheduler templates have `{{- if .Values.dra.enabled }}` blocks +# that need to be removed because the dra value is gone (commit +# 2734dc0 stripped them). +# * device-plugin/monitorservice.yaml uses `indent` with leading +# whitespace; it must be rewritten to `nindent` for the labels block +# to render correctly when devicePlugin.service.labels is set +# (commit 3685254). +# +# After `make update`, run `git diff -- charts/hami/templates/` and +# replay these template patches against the new upstream version, then +# verify with `helm unittest`. If upstream restructured the affected +# files, the patches may need to be redesigned rather than reapplied. + +update: + rm -rf charts + helm repo add hami-charts https://project-hami.github.io/HAMi/ + helm repo update hami-charts + helm pull hami-charts/hami --untar --untardir charts + rm -rf charts/hami/charts/hami-dra + yq --inplace '.dependencies = []' charts/hami/Chart.yaml + rm -f charts/hami/Chart.lock + yq --inplace 'del(.dra) | del(.["hami-dra"]) | del(.podSecurityPolicy)' charts/hami/values.yaml diff --git a/packages/system/hami/README.md b/packages/system/hami/README.md new file mode 100644 index 00000000..68669ac7 --- /dev/null +++ b/packages/system/hami/README.md @@ -0,0 +1,82 @@ +# HAMi — GPU Virtualization Middleware + +[HAMi](https://github.com/Project-HAMi/HAMi) (Heterogeneous AI Computing Virtualization Middleware) is a CNCF Sandbox project that enables fractional GPU sharing in Kubernetes. It allows workloads to request specific amounts of GPU memory and compute cores instead of claiming entire GPUs. + +## Architecture + +HAMi consists of four components: + +- **MutatingWebhook** — intercepts pod creation, injects `schedulerName: hami-scheduler` +- **Scheduler Extender** — extends kube-scheduler with GPU-aware Filter and Bind logic +- **Device Plugin** (DaemonSet) — registers vGPU resources via the Kubernetes Device Plugin API +- **HAMi-core** (`libvgpu.so`) — `LD_PRELOAD` library injected into workload containers, intercepts CUDA API calls to enforce memory and compute isolation + +## Prerequisites + +- GPU Operator must be enabled (`addons.gpuOperator.enabled: true`) +- NVIDIA driver >= 440 on host nodes +- nvidia-container-toolkit configured as the default container runtime +- GPU nodes labeled with `gpu=on` + +## Known Limitations + +### glibc < 2.34 requirement for workload containers + +HAMi-core uses `LD_PRELOAD` to intercept `dlsym()` for CUDA symbol resolution. The fallback code path relies on `_dl_sym`, a private glibc internal symbol that was removed in glibc 2.34 when libdl and libpthread were merged into libc.so. + +**This limitation affects workload containers only**, not the host OS or HAMi's own components. + +| Distribution | glibc | Result | +| --------------- | ----- | -------------------------------------------- | +| Ubuntu 18.04 | 2.27 | Full isolation (memory + compute) | +| Ubuntu 20.04 | 2.31 | Full isolation (memory + compute) | +| Ubuntu 22.04 | 2.35 | Memory isolation works, compute breaks | +| Ubuntu 24.04 | 2.39 | Both memory and compute isolation break | +| Alpine (musl) | N/A | Completely incompatible (`dlvsym` absent) | + +Most modern ML/AI base images (CUDA 12.x, PyTorch 2.x, TensorFlow 2.x) use Ubuntu 22.04+ with glibc >= 2.35, which means compute isolation will not work with these images until the upstream fix is merged. + +**Upstream tracking issues:** + +- [HAMi-core#174](https://github.com/Project-HAMi/HAMi-core/issues/174) — `_dl_sym` removal in glibc 2.34 breaks HAMi-core's CUDA symbol resolution at the symbol level +- [HAMi#1190](https://github.com/Project-HAMi/HAMi/issues/1190) — maintainer thread confirming the empirical per-glibc-version isolation behavior shown in the table above + +### musl libc (Alpine) incompatibility + +HAMi-core is completely incompatible with musl libc. The `dlvsym()` function used by HAMi-core is a glibc extension not available in musl. Only glibc-based container images (Debian, Ubuntu, RHEL, etc.) can use HAMi GPU isolation. + +## Usage + +Enable HAMi in your tenant Kubernetes cluster values: + +```yaml +addons: + gpuOperator: + enabled: true + hami: + enabled: true +``` + +When HAMi is enabled, GPU Operator's built-in device plugin is automatically disabled to avoid conflicts. This default is preserved by setting `addons.gpuOperator.valuesOverride.gpu-operator.devicePlugin.enabled: false`; advanced topologies that partition GPU pools (e.g. some nodes use HAMi while others run the standard NVIDIA device plugin via node selectors) can re-enable it explicitly through `valuesOverride`. + +### Requesting fractional GPU resources + +```yaml +resources: + limits: + nvidia.com/gpu: 1 + nvidia.com/gpumem: 3000 # 3000 MB of GPU memory + nvidia.com/gpucores: 30 # 30% of GPU compute cores +``` + +## Parameters + +Default values shown below are inherited from the upstream HAMi chart and may change with upstream updates. + +| Name | Description | Default | +| --- | --- | --- | +| `hami.devicePlugin.runtimeClassName` | RuntimeClass for device plugin pods | `nvidia` | +| `hami.devicePlugin.deviceSplitCount` | Max virtual GPUs per physical GPU | `10` | +| `hami.devicePlugin.deviceMemoryScaling` | Memory overcommit factor (> 1.0 enables overcommit) | `1` | +| `hami.scheduler.defaultSchedulerPolicy.nodeSchedulerPolicy` | Node packing strategy (`binpack` or `spread`) | `binpack` | +| `hami.scheduler.defaultSchedulerPolicy.gpuSchedulerPolicy` | GPU packing strategy (`binpack` or `spread`) | `spread` | diff --git a/packages/system/hami/charts/hami/Chart.yaml b/packages/system/hami/charts/hami/Chart.yaml new file mode 100644 index 00000000..55f32ab6 --- /dev/null +++ b/packages/system/hami/charts/hami/Chart.yaml @@ -0,0 +1,18 @@ +apiVersion: v2 +appVersion: 2.8.1 +dependencies: [] +description: Heterogeneous AI Computing Virtualization Middleware +keywords: +- vgpu +- gpu +kubeVersion: '>= 1.18.0-0' +maintainers: +- email: archlitchi@gmail.com + name: limengxuan +- email: xiaozhang0210@hotmail.com + name: zhangxiao +name: hami +sources: +- https://github.com/Project-HAMi/HAMi +type: application +version: 2.8.1 diff --git a/packages/system/hami/charts/hami/README.md b/packages/system/hami/charts/hami/README.md new file mode 100644 index 00000000..e8217290 --- /dev/null +++ b/packages/system/hami/charts/hami/README.md @@ -0,0 +1,237 @@ +# HAMi Helm Chart Values Documentation + +This document provides detailed descriptions of all configurable values parameters for the HAMi Helm Chart. + +## Global Configuration + +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `global.imageRegistry` | Global Docker image registry | `""` | +| `global.imagePullSecrets` | Global Docker image pull secrets | `[]` | +| `global.imageTag` | Image tag | `"v2.8.1"` | +| `global.gpuHookPath` | GPU Hook path | `/usr/local` | +| `global.labels` | Global labels | `{}` | +| `global.annotations` | Global annotations | `{}` | +| `global.managedNodeSelectorEnable` | Whether to enable managed node selector | `false` | +| `global.managedNodeSelector.usage` | Managed node selector usage | `"gpu"` | +| `nameOverride` | Name override | `""` | +| `fullnameOverride` | Full name override | `""` | +| `namespaceOverride` | Namespace override | `""` | + +## Resource Name Configuration + +### NVIDIA GPU Resources +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `resourceName` | GPU resource name | `"nvidia.com/gpu"` | +| `resourceMem` | GPU memory resource name | `"nvidia.com/gpumem"` | +| `resourceMemPercentage` | GPU memory percentage resource name | `"nvidia.com/gpumem-percentage"` | +| `resourceCores` | GPU core resource name | `"nvidia.com/gpucores"` | +| `resourcePriority` | GPU priority resource name | `"nvidia.com/priority"` | + +### Cambricon MLU Resources +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `mluResourceName` | MLU resource name | `"cambricon.com/vmlu"` | +| `mluResourceMem` | MLU memory resource name | `"cambricon.com/mlu.smlu.vmemory"` | +| `mluResourceCores` | MLU core resource name | `"cambricon.com/mlu.smlu.vcore"` | + +### Hygon DCU Resources +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `dcuResourceName` | DCU resource name | `"hygon.com/dcunum"` | +| `dcuResourceMem` | DCU memory resource name | `"hygon.com/dcumem"` | +| `dcuResourceCores` | DCU core resource name | `"hygon.com/dcucores"` | + +### Metax GPU Resources +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `metaxResourceName` | GPU resource name | `"metax-tech.com/sgpu"` | +| `metaxResourceCore` | GPU core resource name | `"metax-tech.com/vcore"` | +| `metaxResourceMem` | GPU memory resource name | `"metax-tech.com/vmemory"` | +| `metaxsGPUTopologyAware` | GPU topology awareness | `"false"` | + +### Enflame GCU Resources +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `enflameResourceNameVGCU` | vGCU resource name | `"enflame.com/vgcu"` | +| `enflameResourceNameVGCUPercentage` | vGCU percentage resource name | `"enflame.com/vgcu-percentage"` | + +### Kunlunxin XPU Resources +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `kunlunResourceName` | XPU resource name | `"kunlunxin.com/xpu"` | + +## Scheduler Configuration + +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `schedulerName` | Scheduler name | `"hami-scheduler"` | +| `scheduler.nodeName` | Define node name, scheduler will schedule to this node | `""` | +| `scheduler.overwriteEnv` | Whether to overwrite environment variables | `"false"` | +| `scheduler.defaultSchedulerPolicy.nodeSchedulerPolicy` | Node scheduler policy | `binpack` | +| `scheduler.defaultSchedulerPolicy.gpuSchedulerPolicy` | GPU scheduler policy | `spread` | +| `scheduler.metricsBindAddress` | Metrics bind address | `":9395"` | +| `scheduler.forceOverwriteDefaultScheduler` | Whether to force overwrite default scheduler | `true` | +| `scheduler.livenessProbe` | Whether to enable liveness probe | `false` | +| `scheduler.leaderElect` | Whether to enable leader election | `true` | +| `scheduler.replicas` | Number of replicas | `1` | + +### Kube Scheduler Configuration + +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `scheduler.kubeScheduler.enabled` | Whether to run kube-scheduler container in scheduler pod | `true` | +| `scheduler.kubeScheduler.image.registry` | Kube scheduler image registry | `"registry.cn-hangzhou.aliyuncs.com"` | +| `scheduler.kubeScheduler.image.repository` | Kube scheduler image repository | `"google_containers/kube-scheduler"` | +| `scheduler.kubeScheduler.image.tag` | Kube scheduler image tag | `""` | +| `scheduler.kubeScheduler.image.pullPolicy` | Kube scheduler image pull policy | `IfNotPresent` | +| `scheduler.kubeScheduler.image.pullSecrets` | Kube scheduler image pull secrets | `[]` | +| `scheduler.kubeScheduler.extraNewArgs` | Extra new arguments | `["--config=/config/config.yaml", "-v=4"]` | +| `scheduler.kubeScheduler.extraArgs` | Extra arguments | `["--policy-config-file=/config/config.json", "-v=4"]` | + +### Extender Configuration + +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `scheduler.extender.image.registry` | Scheduler extender image registry | `"docker.io"` | +| `scheduler.extender.image.repository` | Scheduler extender image repository | `"projecthami/hami"` | +| `scheduler.extender.image.tag` | Scheduler extender image tag | `""` | +| `scheduler.extender.image.pullPolicy` | Scheduler extender image pull policy | `IfNotPresent` | +| `scheduler.extender.image.pullSecrets` | Scheduler extender image pull secrets | `[]` | +| `scheduler.extender.extraArgs` | Scheduler extender extra arguments | `["--debug", "-v=4"]` | + +### Admission Webhook Configuration + +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `scheduler.admissionWebhook.enabled` | Whether to enable admission webhook | `true` | +| `scheduler.admissionWebhook.customURL.enabled` | Whether to enable custom URL | `false` | +| `scheduler.admissionWebhook.customURL.host` | Custom URL host | `127.0.0.1` | +| `scheduler.admissionWebhook.customURL.port` | Custom URL port | `31998` | +| `scheduler.admissionWebhook.customURL.path` | Custom URL path | `/webhook` | +| `scheduler.admissionWebhook.reinvocationPolicy` | Reinvocation policy | `Never` | +| `scheduler.admissionWebhook.failurePolicy` | Failure policy | `Ignore` | + +### TLS Certificate Configuration + +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `scheduler.certManager.enabled` | Whether to use cert-manager to generate self-signed certificates | `false` | +| `scheduler.patch.enabled` | Whether to use kube-webhook-certgen to generate self-signed certificates | `true` | +| `scheduler.patch.image.registry` | Certgen image registry | `"docker.io"` | +| `scheduler.patch.image.repository` | Certgen image repository | `"jettech/kube-webhook-certgen"` | +| `scheduler.patch.image.tag` | Certgen image tag | `"v1.5.2"` | +| `scheduler.patch.image.pullPolicy` | Certgen image pull policy | `IfNotPresent` | +| `scheduler.patch.imageNew.registry` | New certgen image registry | `"docker.io"` | +| `scheduler.patch.imageNew.repository` | New certgen image repository | `"liangjw/kube-webhook-certgen"` | +| `scheduler.patch.imageNew.tag` | New certgen image tag | `"v1.1.1"` | + +### Scheduler Service Configuration + +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `scheduler.service.type` | Service type | `NodePort` | +| `scheduler.service.httpPort` | HTTP port | `443` | +| `scheduler.service.schedulerPort` | Scheduler NodePort | `31998` | +| `scheduler.service.monitorPort` | Monitor port | `31993` | +| `scheduler.service.monitorTargetPort` | Monitor target port | `9395` | + +## Device Plugin Configuration + +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `devicePlugin.image.registry` | Device plugin image registry | `"docker.io"` | +| `devicePlugin.image.repository` | Device plugin image repository | `"projecthami/hami"` | +| `devicePlugin.image.tag` | Device plugin image tag | `""` | +| `devicePlugin.image.pullPolicy` | Device plugin image pull policy | `IfNotPresent` | +| `devicePlugin.image.pullSecrets` | Device plugin image pull secrets | `[]` | + +### Monitor Configuration + +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `devicePlugin.monitor.image.registry` | Monitor image registry | `"docker.io"` | +| `devicePlugin.monitor.image.repository` | Monitor image repository | `"projecthami/hami"` | +| `devicePlugin.monitor.image.tag` | Monitor image tag | `""` | +| `devicePlugin.monitor.image.pullPolicy` | Monitor image pull policy | `IfNotPresent` | +| `devicePlugin.monitor.image.pullSecrets` | Monitor image pull secrets | `[]` | +| `devicePlugin.monitor.ctrPath` | Container path | `/usr/local/vgpu/containers` | +| `devicePlugin.monitor.extraArgs` | Monitor extra arguments | `["-v=4"]` | +| `devicePlugin.monitor.extraEnvs` | Monitor extra environments | `{}` | + +### Device Plugin Other Configuration + +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `devicePlugin.deviceSplitCount` | Integer type, default value: 10. Maximum number of tasks assigned to a single GPU device | `10` | +| `devicePlugin.deviceMemoryScaling` | Device memory scaling ratio | `1` | +| `devicePlugin.deviceCoreScaling` | Device core scaling ratio | `1` | +| `devicePlugin.runtimeClassName` | Runtime class name | `""` | +| `devicePlugin.createRuntimeClass` | Whether to create runtime class | `false` | +| `devicePlugin.migStrategy` | String type, "none" means ignore MIG functionality, "mixed" means allocate MIG devices through independent resources | `"none"` | +| `devicePlugin.disablecorelimit` | String type, "true" means disable core limit, "false" means enable core limit | `"false"` | +| `devicePlugin.passDeviceSpecsEnabled` | Whether to enable passing device specs | `false` | +| `devicePlugin.extraArgs` | Device plugin extra arguments | `["-v=4"]` | +| `devicePlugin.nodeConfiguration.config` | Node configuration for device plugin by json | An example of default configuration. | +| `devicePlugin.nodeConfiguration.externalConfigName` | Node configuration for device plugin by external congimap | `""` | +| `devicePlugin.extraEnvs` | Device plugin extra environments | `{}` | + +### Device Plugin Service Configuration + +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `devicePlugin.service.type` | Service type | `NodePort` | +| `devicePlugin.service.httpPort` | HTTP port | `31992` | + +### Device Plugin Deployment Configuration + +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `devicePlugin.pluginPath` | Plugin path | `/var/lib/kubelet/device-plugins` | +| `devicePlugin.libPath` | Library path | `/usr/local/vgpu` | +| `devicePlugin.nvidiaNodeSelector` | NVIDIA node selector | `{"gpu": "on"}` | +| `devicePlugin.updateStrategy.type` | Update strategy type | `RollingUpdate` | +| `devicePlugin.updateStrategy.rollingUpdate.maxUnavailable` | Maximum unavailable count | `1` | + +## Device Configuration + +### AWS Neuron +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `devices.awsneuron.customresources` | Custom resources | `["aws.amazon.com/neuron", "aws.amazon.com/neuroncore"]` | + +### Kunlunxin +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `devices.kunlun.enabled` | Whether to enable | `true` | +| `devices.kunlun.customresources` | Custom resources | `["kunlunxin.com/xpu"]` | + +### Mthreads +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `devices.mthreads.enabled` | Whether to enable | `true` | +| `devices.mthreads.customresources` | Custom resources | `["mthreads.com/vgpu"]` | + +### NVIDIA +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `devices.nvidia.gpuCorePolicy` | GPU core policy | `default` | +| `devices.nvidia.libCudaLogLevel` | CUDA library log level | `1` | + +### Huawei Ascend +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `devices.ascend.enabled` | Whether to enable | `false` | +| `devices.ascend.image` | Image | `""` | +| `devices.ascend.imagePullPolicy` | Image pull policy | `IfNotPresent` | +| `devices.ascend.extraArgs` | Extra arguments | `[]` | +| `devices.ascend.nodeSelector` | Node selector | `{"ascend": "on"}` | +| `devices.ascend.tolerations` | Tolerations | `[]` | +| `devices.ascend.customresources` | Custom resources | `["huawei.com/Ascend910A", "huawei.com/Ascend910A-memory", ...]` | + +### Iluvatar +| Parameter | Description | Default Value | +|-----------|-------------|---------------| +| `devices.iluvatar.enabled` | Whether to enable | `false` | +| `devices.iluvatar.customresources` | Custom resources | `["iluvatar.ai/BI-V150-vgpu", "iluvatar.ai/BI-V150.vMem","iluvatar.ai/BI-V150.vCore", ...]` | diff --git a/packages/system/hami/charts/hami/templates/NOTES.txt b/packages/system/hami/charts/hami/templates/NOTES.txt new file mode 100644 index 00000000..15bb1218 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/NOTES.txt @@ -0,0 +1,3 @@ +** Please be patient while the chart is being deployed ** +Resource name: {{ .Values.resourceName }} + diff --git a/packages/system/hami/charts/hami/templates/_commons.tpl b/packages/system/hami/charts/hami/templates/_commons.tpl new file mode 100644 index 00000000..b68018e4 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/_commons.tpl @@ -0,0 +1,49 @@ +{{/* +Return the proper image name +{{ include "common.images.image" ( dict "imageRoot" .Values.path.to.the.image "global" $) }} +*/}} +{{- define "common.images.image" -}} +{{- $registryName := .imageRoot.registry -}} +{{- $repositoryName := .imageRoot.repository -}} +{{- $tag := .imageRoot.tag | toString -}} +{{- if .global }} + {{- if .global.imageRegistry }} + {{- $registryName = .global.imageRegistry -}} + {{- end -}} +{{- end -}} +{{- if .tag }} + {{- $tag = .tag | toString -}} +{{- end -}} +{{- if $registryName }} +{{- printf "%s/%s:%s" $registryName $repositoryName $tag -}} +{{- else -}} +{{- printf "%s:%s" $repositoryName $tag -}} +{{- end -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names (deprecated: use common.images.renderPullSecrets instead) +{{ include "common.images.pullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global) }} +*/}} +{{- define "common.images.pullSecrets" -}} + {{- $pullSecrets := list }} + + {{- if .global }} + {{- range .global.imagePullSecrets -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end -}} + {{- end -}} + + {{- range .images -}} + {{- range .pullSecrets -}} + {{- $pullSecrets = append $pullSecrets . -}} + {{- end -}} + {{- end -}} + + {{- if (not (empty $pullSecrets)) }} +imagePullSecrets: + {{- range $pullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} +{{- end -}} diff --git a/packages/system/hami/charts/hami/templates/_helpers.tpl b/packages/system/hami/charts/hami/templates/_helpers.tpl new file mode 100644 index 00000000..ffcc61da --- /dev/null +++ b/packages/system/hami/charts/hami/templates/_helpers.tpl @@ -0,0 +1,163 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "hami-vgpu.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "hami-vgpu.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts +*/}} +{{- define "hami-vgpu.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{/* +The app name for Scheduler +*/}} +{{- define "hami-vgpu.scheduler" -}} +{{- printf "%s-scheduler" ( include "hami-vgpu.fullname" . ) | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +The app name for DevicePlugin +*/}} +{{- define "hami-vgpu.device-plugin" -}} +{{- printf "%s-device-plugin" ( include "hami-vgpu.fullname" . ) | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* + The app name for MockDevicePlugin + */}} +{{- define "hami-vgpu.mock-device-plugin" -}} +{{- printf "%s-mock-device-plugin" ( include "hami-vgpu.fullname" . ) | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +The tls secret name for Scheduler +*/}} +{{- define "hami-vgpu.scheduler.tls" -}} +{{- printf "%s-scheduler-tls" ( include "hami-vgpu.fullname" . ) | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +The webhook name +*/}} +{{- define "hami-vgpu.scheduler.webhook" -}} +{{- printf "%s-webhook" ( include "hami-vgpu.fullname" . ) | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "hami-vgpu.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "hami-vgpu.labels" -}} +helm.sh/chart: {{ include "hami-vgpu.chart" . }} +{{ include "hami-vgpu.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "hami-vgpu.selectorLabels" -}} +app.kubernetes.io/name: {{ include "hami-vgpu.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + + +{{/* + Resolve the tag for kubeScheduler. +*/}} +{{- define "resolvedKubeSchedulerTag" -}} +{{- if .Values.scheduler.kubeScheduler.image.tag }} +{{- .Values.scheduler.kubeScheduler.image.tag | trim -}} +{{- else }} +{{- include "strippedKubeVersion" . | trim -}} +{{- end }} +{{- end }} + +{{/* + Return the stripped Kubernetes version string by removing extra parts after semantic version number. + v1.31.1+k3s1 -> v1.31.1 + v1.30.8-eks-2d5f260 -> v1.30.8 + v1.31.1 -> v1.31.1 +*/}} +{{- define "strippedKubeVersion" -}} +{{ regexReplaceAll "^(v[0-9]+\\.[0-9]+\\.[0-9]+)(.*)$" .Capabilities.KubeVersion.Version "$1" }} +{{- end -}} + +{{- define "hami.scheduler.kubeScheduler.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.scheduler.kubeScheduler.image "global" .Values.global "tag" (include "resolvedKubeSchedulerTag" .)) }} +{{- end -}} + +{{- define "hami.scheduler.extender.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.scheduler.extender.image "global" .Values.global "tag" .Values.global.imageTag) }} +{{- end -}} + +{{- define "hami.devicePlugin.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.devicePlugin.image "global" .Values.global "tag" .Values.global.imageTag) }} +{{- end -}} + +{{- define "hami.mockDevicePlugin.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.mockDevicePlugin.image "global" .Values.global "tag" .Values.mockDevicePlugin.tag) }} +{{- end -}} + +{{- define "hami.devicePlugin.monitor.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.devicePlugin.monitor.image "global" .Values.global "tag" .Values.global.imageTag) }} +{{- end -}} + +{{- define "hami.scheduler.patch.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.scheduler.patch.image "global" .Values.global) }} +{{- end -}} + +{{- define "hami.scheduler.patch.new.image" -}} +{{ include "common.images.image" (dict "imageRoot" .Values.scheduler.patch.imageNew "global" .Values.global) }} +{{- end -}} + +{{- define "hami.scheduler.extender.imagePullSecrets" -}} +{{ include "common.images.pullSecrets" (dict "images" (list .Values.scheduler.extender.image) "global" .Values.global) }} +{{- end -}} + +{{- define "hami.devicePlugin.imagePullSecrets" -}} +{{ include "common.images.pullSecrets" (dict "images" (list .Values.devicePlugin.image) "global" .Values.global) }} +{{- end -}} + +{{- define "hami.scheduler.patch.imagePullSecrets" -}} +{{ include "common.images.pullSecrets" (dict "images" (list .Values.scheduler.patch.image) "global" .Values.global) }} +{{- end -}} + +{{- define "hami.scheduler.patch.new.imagePullSecrets" -}} +{{ include "common.images.pullSecrets" (dict "images" (list .Values.scheduler.patch.imageNew) "global" .Values.global) }} +{{- end -}} diff --git a/packages/system/hami/charts/hami/templates/device-plugin/configmap.yaml b/packages/system/hami/charts/hami/templates/device-plugin/configmap.yaml new file mode 100644 index 00000000..74631e24 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/device-plugin/configmap.yaml @@ -0,0 +1,13 @@ +{{- if and .Values.devicePlugin.enabled (not .Values.devicePlugin.nodeConfiguration.externalConfigName) -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "hami-vgpu.device-plugin" . }} + namespace: {{ include "hami-vgpu.namespace" . }} + labels: + app.kubernetes.io/component: hami-device-plugin + {{- include "hami-vgpu.labels" . | nindent 4 }} +data: + config.json: | +{{- .Values.devicePlugin.nodeConfiguration.config | nindent 4 }} +{{- end }} diff --git a/packages/system/hami/charts/hami/templates/device-plugin/daemonsetmock.yaml b/packages/system/hami/charts/hami/templates/device-plugin/daemonsetmock.yaml new file mode 100644 index 00000000..a0dc4ff3 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/device-plugin/daemonsetmock.yaml @@ -0,0 +1,55 @@ +{{- if .Values.mockDevicePlugin.enabled }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "hami-vgpu.mock-device-plugin" . }} + namespace: {{ include "hami-vgpu.namespace" . }} +spec: + selector: + matchLabels: + app.kubernetes.io/component: hami-mock-device-plugin + {{- include "hami-vgpu.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + scheduler.alpha.kubernetes.io/critical-pod: "" + labels: + app.kubernetes.io/component: hami-mock-device-plugin + {{- include "hami-vgpu.selectorLabels" . | nindent 8 }} + spec: + serviceAccountName: {{ include "hami-vgpu.mock-device-plugin" . }} + tolerations: + - key: CriticalAddonsOnly + operator: Exists + containers: + - image: {{ include "hami.mockDevicePlugin.image" . }} + imagePullPolicy: {{ .Values.mockDevicePlugin.image.pullPolicy }} + name: hami-mock-dp-cntr + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + command: + - ./k8s-device-plugin + - -v=5 + - --device-config-file=/device-config.yaml + volumeMounts: + - name: dp + mountPath: /var/lib/kubelet/device-plugins + - name: sys + mountPath: /sys + - name: device-config + mountPath: /device-config.yaml + subPath: device-config.yaml + volumes: + - name: dp + hostPath: + path: /var/lib/kubelet/device-plugins + - name: sys + hostPath: + path: /sys + - name: device-config + configMap: + name: {{ include "hami-vgpu.scheduler" . }}-device +{{- end -}} diff --git a/packages/system/hami/charts/hami/templates/device-plugin/daemonsetnvidia.yaml b/packages/system/hami/charts/hami/templates/device-plugin/daemonsetnvidia.yaml new file mode 100644 index 00000000..1f4c24f3 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/device-plugin/daemonsetnvidia.yaml @@ -0,0 +1,262 @@ +{{- if .Values.devicePlugin.enabled }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "hami-vgpu.device-plugin" . }} + namespace: {{ include "hami-vgpu.namespace" . }} + labels: + app.kubernetes.io/component: hami-device-plugin + {{- include "hami-vgpu.labels" . | nindent 4 }} + {{- with .Values.global.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if .Values.global.annotations }} + annotations: {{ toYaml .Values.global.annotations | nindent 4}} + {{- end }} +spec: + updateStrategy: + {{- with .Values.devicePlugin.updateStrategy }} + {{- toYaml . | nindent 4 }} + {{- end }} + selector: + matchLabels: + app.kubernetes.io/component: hami-device-plugin + {{- include "hami-vgpu.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + app.kubernetes.io/component: hami-device-plugin + hami.io/webhook: ignore + {{- include "hami-vgpu.selectorLabels" . | nindent 8 }} + annotations: + {{- if ge (regexReplaceAll "[^0-9]" .Capabilities.KubeVersion.Minor "" | int) 22 }} + checksum/hami-scheduler-newversion-config: {{ include (print $.Template.BasePath "/scheduler/configmapnew.yaml") . | sha256sum }} + {{- else }} + checksum/hami-scheduler-config: {{ include (print $.Template.BasePath "/scheduler/configmap.yaml") . | sha256sum }} + {{- end }} + checksum/hami-scheduler-device-config: {{ include (print $.Template.BasePath "/scheduler/device-configmap.yaml") . | sha256sum }} + {{- if .Values.devicePlugin.podAnnotations }} + {{- toYaml .Values.devicePlugin.podAnnotations | nindent 8 }} + {{- end }} + spec: + {{- if .Values.devicePlugin.runtimeClassName }} + runtimeClassName: {{ .Values.devicePlugin.runtimeClassName }} + {{- end }} + serviceAccountName: {{ include "hami-vgpu.device-plugin" . }} + priorityClassName: system-node-critical + hostPID: true + hostNetwork: true + {{- include "hami.devicePlugin.imagePullSecrets" . | nindent 6 }} + {{- if .Values.devicePlugin.gpuOperatorToolkitReady.enabled }} + initContainers: + - name: toolkit-validation + image: {{ include "hami.devicePlugin.image" . }} + imagePullPolicy: {{ .Values.devicePlugin.image.pullPolicy }} + securityContext: + privileged: true + runAsUser: 0 + command: ["sh", "-c"] + args: + - | + echo "Waiting for NVIDIA Toolkit to be ready..." + until [ -f {{ .Values.devicePlugin.gpuOperatorToolkitReady.hostPath }}/toolkit-ready ]; do + echo "Waiting for {{ .Values.devicePlugin.gpuOperatorToolkitReady.hostPath }}/toolkit-ready..." + sleep 5 + done + echo "NVIDIA Toolkit is ready!" + volumeMounts: + - name: nvidia-validations + mountPath: {{ .Values.devicePlugin.gpuOperatorToolkitReady.hostPath | quote }} + mountPropagation: HostToContainer + readOnly: true + {{- end }} + containers: + - name: device-plugin + image: {{ include "hami.devicePlugin.image" . }} + imagePullPolicy: {{ .Values.devicePlugin.image.pullPolicy }} + lifecycle: + postStart: + exec: + command: ["/bin/sh","-c", {{ printf "/k8s-vgpu/bin/vgpu-init.sh %s/vgpu/" .Values.global.gpuHookPath | quote }}] + command: + - nvidia-device-plugin + - --config-file=/device-config.yaml + - --mig-strategy={{ .Values.devicePlugin.migStrategy }} + - --disable-core-limit={{ .Values.devicePlugin.disablecorelimit }} + {{- range .Values.devicePlugin.extraArgs }} + - {{ . }} + {{- end }} + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: NVIDIA_MIG_MONITOR_DEVICES + value: all + - name: DEVICE_LIST_STRATEGY + value: {{ .Values.devicePlugin.deviceListStrategy }} + - name: HOOK_PATH + value: {{ .Values.global.gpuHookPath }} + {{- if typeIs "bool" .Values.devicePlugin.passDeviceSpecsEnabled }} + - name: PASS_DEVICE_SPECS + value: {{ .Values.devicePlugin.passDeviceSpecsEnabled | quote }} + {{- end }} + {{- if typeIs "string" .Values.devicePlugin.nvidiaDriverRoot }} + - name: NVIDIA_DRIVER_ROOT + value: {{ .Values.devicePlugin.nvidiaDriverRoot }} + {{- end }} + {{- if typeIs "string" .Values.devicePlugin.nvidiaHookPath }} + - name: NVIDIA_CDI_HOOK_PATH + value: {{ .Values.devicePlugin.nvidiaHookPath }} + {{- end }} + {{- if typeIs "bool" .Values.devicePlugin.gdrcopyEnabled }} + - name: GDRCOPY_ENABLED + value: {{ .Values.devicePlugin.gdrcopyEnabled | quote }} + {{- end }} + {{- if typeIs "bool" .Values.devicePlugin.gdsEnabled }} + - name: GDS_ENABLED + value: {{ .Values.devicePlugin.gdsEnabled | quote }} + {{- end }} + {{- if typeIs "bool" .Values.devicePlugin.mofedEnabled }} + - name: MOFED_ENABLED + value: {{ .Values.devicePlugin.mofedEnabled | quote }} + {{- end }} + {{- if eq (.Values.scheduler.defaultSchedulerPolicy.gpuSchedulerPolicy | default "spread") "topology-aware" }} + - name: ENABLE_TOPOLOGY_SCORE + value: "true" + {{- end }} + {{- with .Values.devicePlugin.extraEnvs }} + {{- . | toYaml | nindent 12 }} + {{- end }} + securityContext: + privileged: true + allowPrivilegeEscalation: true + capabilities: + drop: ["ALL"] + add: ["SYS_ADMIN"] + resources: + {{- toYaml .Values.devicePlugin.resources | nindent 12 }} + volumeMounts: + - name: device-plugin + mountPath: /var/lib/kubelet/device-plugins + - name: lib + mountPath: {{ printf "%s%s" .Values.global.gpuHookPath "/vgpu" }} + - name: usrbin + mountPath: /usrbin + - name: deviceconfig + mountPath: /config + - name: hosttmp + mountPath: /tmp + - name: device-config + mountPath: /device-config.yaml + subPath: device-config.yaml + - name: cdi-root + mountPath: /var/run/cdi + {{- if typeIs "string" .Values.devicePlugin.nvidiaDriverRoot }} + # We always mount the driver root at /driver-root in the container. + # This is required for CDI detection to work correctly. + - name: driver-root + mountPath: /driver-root + readOnly: true + {{- end }} + - name: vgpu-monitor + image: {{ include "hami.devicePlugin.monitor.image" . }} + imagePullPolicy: {{ .Values.devicePlugin.monitor.image.pullPolicy }} + command: + - "vGPUmonitor" + {{- range .Values.devicePlugin.monitor.extraArgs }} + - {{ . }} + {{- end }} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] + add: ["SYS_ADMIN"] + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: NVIDIA_VISIBLE_DEVICES + value: "all" + - name: NVIDIA_MIG_MONITOR_DEVICES + value: "all" + - name: HOOK_PATH + value: "{{ .Values.global.gpuHookPath }}/vgpu" + - name: HAMI_RESYNC_INTERVAL + value: {{ .Values.devicePlugin.monitor.resyncInterval | default "5m" | quote }} + {{- with .Values.devicePlugin.monitor.extraEnvs }} + {{- . | toYaml | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.devicePlugin.monitor.resources | nindent 12 }} + volumeMounts: + - name: ctrs + mountPath: {{ .Values.devicePlugin.monitor.ctrPath }} + - name: dockers + mountPath: /run/docker + - name: containerds + mountPath: /run/containerd + - name: sysinfo + mountPath: /sysinfo + - name: hostvar + mountPath: /hostvar + - name: hosttmp + mountPath: /tmp + volumes: + - name: ctrs + hostPath: + path: {{ .Values.devicePlugin.monitor.ctrPath }} + - name: hosttmp + hostPath: + path: /tmp + - name: dockers + hostPath: + path: /run/docker + - name: containerds + hostPath: + path: /run/containerd + - name: device-plugin + hostPath: + path: {{ .Values.devicePlugin.pluginPath }} + - name: lib + hostPath: + path: {{ .Values.devicePlugin.libPath }} + {{- if .Values.devicePlugin.gpuOperatorToolkitReady.enabled }} + - name: nvidia-validations + hostPath: + path: {{ .Values.devicePlugin.gpuOperatorToolkitReady.hostPath }} + type: DirectoryOrCreate + {{- end }} + {{- if typeIs "string" .Values.devicePlugin.nvidiaDriverRoot }} + - name: driver-root + hostPath: + path: {{ .Values.devicePlugin.nvidiaDriverRoot }} + type: Directory + {{- end }} + - name: cdi-root + hostPath: + path: /var/run/cdi + type: DirectoryOrCreate + - name: usrbin + hostPath: + path: /usr/bin + - name: sysinfo + hostPath: + path: /sys + - name: hostvar + hostPath: + path: /var + - name: deviceconfig + configMap: + name: {{ .Values.devicePlugin.nodeConfiguration.externalConfigName | default (include "hami-vgpu.device-plugin" .) }} + - name: device-config + configMap: + name: {{ include "hami-vgpu.scheduler" . }}-device + {{- if .Values.devicePlugin.nvidiaNodeSelector }} + nodeSelector: {{ toYaml .Values.devicePlugin.nvidiaNodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.devicePlugin.tolerations }} + tolerations: {{ toYaml .Values.devicePlugin.tolerations | nindent 8 }} + {{- end }} +{{- end }} diff --git a/packages/system/hami/charts/hami/templates/device-plugin/monitorrole.yaml b/packages/system/hami/charts/hami/templates/device-plugin/monitorrole.yaml new file mode 100644 index 00000000..6ac757f2 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/device-plugin/monitorrole.yaml @@ -0,0 +1,28 @@ +{{- if .Values.devicePlugin.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "hami-vgpu.device-plugin" . }}-monitor +rules: + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - create + - watch + - list + - update + - patch + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - update + - list + - patch +{{- end -}} + diff --git a/packages/system/hami/charts/hami/templates/device-plugin/monitorrolebinding.yaml b/packages/system/hami/charts/hami/templates/device-plugin/monitorrolebinding.yaml new file mode 100644 index 00000000..2f0a14ba --- /dev/null +++ b/packages/system/hami/charts/hami/templates/device-plugin/monitorrolebinding.yaml @@ -0,0 +1,17 @@ +{{- if .Values.devicePlugin.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "hami-vgpu.device-plugin" . }} + labels: + app.kubernetes.io/component: "hami-device-plugin" + {{- include "hami-vgpu.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "hami-vgpu.device-plugin" . }}-monitor +subjects: + - kind: ServiceAccount + name: {{ include "hami-vgpu.device-plugin" . }} + namespace: {{ include "hami-vgpu.namespace" . }} +{{- end -}} diff --git a/packages/system/hami/charts/hami/templates/device-plugin/monitorservice.yaml b/packages/system/hami/charts/hami/templates/device-plugin/monitorservice.yaml new file mode 100644 index 00000000..88f1b214 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/device-plugin/monitorservice.yaml @@ -0,0 +1,29 @@ +{{- if .Values.devicePlugin.enabled -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "hami-vgpu.device-plugin" . }}-monitor + namespace: {{ include "hami-vgpu.namespace" . }} + labels: + app.kubernetes.io/component: hami-device-plugin + {{- include "hami-vgpu.labels" . | nindent 4 }} + {{- with .Values.devicePlugin.service.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if .Values.devicePlugin.service.annotations }} # Use devicePlugin instead of scheduler + annotations: {{ toYaml .Values.devicePlugin.service.annotations | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.devicePlugin.service.type | default "NodePort" }} # Default type is NodePort + ports: + - name: monitorport + port: {{ .Values.devicePlugin.service.httpPort | default 31992 }} # Default HTTP port is 31992 + targetPort: 9394 + {{- if eq (.Values.devicePlugin.service.type | default "NodePort") "NodePort" }} # If type is NodePort, set nodePort + nodePort: {{ .Values.devicePlugin.service.httpPort | default 31992 }} + {{- end }} + protocol: TCP + selector: + app.kubernetes.io/component: hami-device-plugin + {{- include "hami-vgpu.selectorLabels" . | nindent 4 }} +{{- end -}} diff --git a/packages/system/hami/charts/hami/templates/device-plugin/monitorserviceaccount.yaml b/packages/system/hami/charts/hami/templates/device-plugin/monitorserviceaccount.yaml new file mode 100644 index 00000000..6e3c2a44 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/device-plugin/monitorserviceaccount.yaml @@ -0,0 +1,10 @@ +{{- if .Values.devicePlugin.enabled -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "hami-vgpu.device-plugin" . }} + namespace: {{ include "hami-vgpu.namespace" . }} + labels: + app.kubernetes.io/component: "hami-device-plugin" + {{- include "hami-vgpu.labels" . | nindent 4 }} +{{- end -}} diff --git a/packages/system/hami/charts/hami/templates/device-plugin/runtime-class.yaml b/packages/system/hami/charts/hami/templates/device-plugin/runtime-class.yaml new file mode 100644 index 00000000..ebcc2c9c --- /dev/null +++ b/packages/system/hami/charts/hami/templates/device-plugin/runtime-class.yaml @@ -0,0 +1,9 @@ +{{- if and .Values.devicePlugin.enabled .Values.devicePlugin.createRuntimeClass .Values.devicePlugin.runtimeClassName -}} +apiVersion: node.k8s.io/v1 +kind: RuntimeClass +metadata: + name: {{ .Values.devicePlugin.runtimeClassName }} + annotations: + helm.sh/hook: pre-install,pre-upgrade +handler: nvidia +{{- end -}} diff --git a/packages/system/hami/charts/hami/templates/scheduler/certmanager.yaml b/packages/system/hami/charts/hami/templates/scheduler/certmanager.yaml new file mode 100644 index 00000000..e6d28721 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/certmanager.yaml @@ -0,0 +1,31 @@ +{{- if .Values.scheduler.admissionWebhook.enabled -}} +{{- if .Values.scheduler.certManager.enabled }} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ include "hami-vgpu.scheduler" . }}-serving-cert + namespace: {{ include "hami-vgpu.namespace" . }} + labels: + app.kubernetes.io/component: hami-scheduler + {{- include "hami-vgpu.labels" . | nindent 4 }} +spec: + dnsNames: + - {{ include "hami-vgpu.scheduler" . }}.{{ include "hami-vgpu.namespace" . }}.svc + - {{ include "hami-vgpu.scheduler" . }}.{{ include "hami-vgpu.namespace" . }}.svc.cluster.local + issuerRef: + kind: Issuer + name: {{ include "hami-vgpu.scheduler" . }}-selfsigned-issuer + secretName: {{ include "hami-vgpu.scheduler.tls" . }} +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ include "hami-vgpu.scheduler" . }}-selfsigned-issuer + namespace: {{ include "hami-vgpu.namespace" . }} + labels: + app.kubernetes.io/component: hami-scheduler + {{- include "hami-vgpu.labels" . | nindent 4 }} +spec: + selfSigned: {} +{{- end }} +{{- end }} diff --git a/packages/system/hami/charts/hami/templates/scheduler/clusterrole.yaml b/packages/system/hami/charts/hami/templates/scheduler/clusterrole.yaml new file mode 100644 index 00000000..81c4fddf --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/clusterrole.yaml @@ -0,0 +1,34 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "hami-vgpu.scheduler" . }} + labels: + app.kubernetes.io/component: "hami-scheduler" + {{- include "hami-vgpu.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: ["pods", "configmaps"] + verbs: ["get", "list", "watch", "patch"] + - apiGroups: [""] + resources: ["pods/binding"] + verbs: ["create"] + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list", "patch", "watch"] + - apiGroups: [""] + resources: ["events"] + verbs: ["create", "get", "list"] + - apiGroups: [""] + resources: ["resourcequotas"] + verbs: ["get", "list", "watch"] +--- +{{- if .Values.mockDevicePlugin.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "hami-vgpu.mock-device-plugin" . }} +rules: + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "update", "list", "patch"] +{{- end -}} diff --git a/packages/system/hami/charts/hami/templates/scheduler/clusterrolebinding.yaml b/packages/system/hami/charts/hami/templates/scheduler/clusterrolebinding.yaml new file mode 100644 index 00000000..a81d425c --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/clusterrolebinding.yaml @@ -0,0 +1,47 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "hami-vgpu.scheduler" . }}-kube + labels: + app.kubernetes.io/component: "hami-scheduler" + {{- include "hami-vgpu.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:kube-scheduler +subjects: + - kind: ServiceAccount + name: {{ include "hami-vgpu.scheduler" . }} + namespace: {{ include "hami-vgpu.namespace" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "hami-vgpu.scheduler" . }}-volume + labels: + app.kubernetes.io/component: "hami-scheduler" + {{- include "hami-vgpu.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:volume-scheduler +subjects: + - kind: ServiceAccount + name: {{ include "hami-vgpu.scheduler" . }} + namespace: {{ include "hami-vgpu.namespace" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "hami-vgpu.scheduler" . }} + labels: + app.kubernetes.io/component: "hami-scheduler" + {{- include "hami-vgpu.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "hami-vgpu.scheduler" . }} +subjects: + - kind: ServiceAccount + name: {{ include "hami-vgpu.scheduler" . }} + namespace: {{ include "hami-vgpu.namespace" . }} diff --git a/packages/system/hami/charts/hami/templates/scheduler/configmap.yaml b/packages/system/hami/charts/hami/templates/scheduler/configmap.yaml new file mode 100644 index 00000000..109ecbce --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/configmap.yaml @@ -0,0 +1,142 @@ +{{- if .Values.scheduler.kubeScheduler.enabled -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "hami-vgpu.scheduler" . }} + namespace: {{ include "hami-vgpu.namespace" . }} + labels: + app.kubernetes.io/component: hami-scheduler + {{- include "hami-vgpu.labels" . | nindent 4 }} +data: + config.json: | + { + "kind": "Policy", + "apiVersion": "v1", + "extenders": [ + { + {{- if .Values.scheduler.admissionWebhook.enabled }} + "urlPrefix": "https://127.0.0.1:443", + "enableHttps": true, + "tlsConfig": { + "insecure": true + }, + {{- else }} + "urlPrefix": "http://127.0.0.1:80", + "enableHttps": false, + {{- end }} + "filterVerb": "filter", + "bindVerb": "bind", + "weight": 1, + "nodeCacheCapable": true, + "httpTimeout": 30000000000, + "managedResources": [ + {{- range .Values.devices.amd.customresources }} + { + "name": "{{ . }}", + "ignoredByScheduler": true + }, + {{- end }} + {{- if .Values.devices.ascend.enabled }} + {{- range .Values.devices.ascend.customresources }} + { + "name": "{{ . }}", + "ignoredByScheduler": true + }, + {{- end }} + {{- end }} + {{- if .Values.devices.mthreads.enabled }} + {{- range .Values.devices.mthreads.customresources }} + { + "name": "{{ . }}", + "ignoredByScheduler": true + }, + {{- end }} + {{- end }} + {{- if .Values.devices.enflame.enabled }} + {{- range .Values.devices.enflame.customresources }} + { + "name": "{{ . }}", + "ignoredByScheduler": true + }, + {{- end }} + {{- end }} + {{- if .Values.devices.kunlun.enabled }} + {{- range .Values.devices.kunlun.customresources }} + { + "name": "{{ . }}", + "ignoredByScheduler": true + }, + {{- end }} + {{- end }} + {{- range .Values.devices.awsneuron.customresources }} + { + "name": "{{ . }}", + "ignoredByScheduler": true + }, + {{- end }} + {{- if .Values.devices.iluvatar.enabled }} + {{- range .Values.devices.iluvatar.customresources }} + { + "name": "{{ . }}", + "ignoredByScheduler": true + }, + {{- end }} + {{- end }} + { + "name": "{{ .Values.resourceName }}", + "ignoredByScheduler": true + }, + { + "name": "{{ .Values.resourceMem }}", + "ignoredByScheduler": true + }, + { + "name": "{{ .Values.resourceCores }}", + "ignoredByScheduler": true + }, + { + "name": "{{ .Values.resourceMemPercentage }}", + "ignoredByScheduler": true + }, + { + "name": "{{ .Values.resourcePriority }}", + "ignoredByScheduler": true + }, + { + "name": "{{ .Values.mluResourceName }}", + "ignoredByScheduler": true + }, + { + "name": "{{ .Values.dcuResourceName }}", + "ignoredByScheduler": true + }, + { + "name": "{{ .Values.dcuResourceMem }}", + "ignoredByScheduler": true + }, + { + "name": "{{ .Values.dcuResourceCores }}", + "ignoredByScheduler": true + }, + { + "name": "metax-tech.com/gpu", + "ignoredByScheduler": true + }, + { + "name": "{{ .Values.metaxResourceName }}", + "ignoredByScheduler": true + }, + { + "name": "{{ .Values.metaxResourceCore }}", + "ignoredByScheduler": true + }, + { + "name": "{{ .Values.metaxResourceMem }}", + "ignoredByScheduler": true + } + ], + "ignoreable": false + } + ] + } +{{- end }} diff --git a/packages/system/hami/charts/hami/templates/scheduler/configmapnew.yaml b/packages/system/hami/charts/hami/templates/scheduler/configmapnew.yaml new file mode 100644 index 00000000..6f6db097 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/configmapnew.yaml @@ -0,0 +1,102 @@ +{{- if .Values.scheduler.kubeScheduler.enabled -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "hami-vgpu.scheduler" . }}-newversion + namespace: {{ include "hami-vgpu.namespace" . }} + labels: + app.kubernetes.io/component: hami-scheduler + {{- include "hami-vgpu.labels" . | nindent 4 }} +data: + config.yaml: | + {{- if gt (regexReplaceAll "[^0-9]" .Capabilities.KubeVersion.Minor "" | int) 25}} + apiVersion: kubescheduler.config.k8s.io/v1 + {{- else }} + apiVersion: kubescheduler.config.k8s.io/v1beta2 + {{- end }} + kind: KubeSchedulerConfiguration + leaderElection: + leaderElect: false + profiles: + - schedulerName: {{ .Values.schedulerName }} + extenders: + {{- if .Values.scheduler.admissionWebhook.enabled }} + - urlPrefix: "https://127.0.0.1:443" + enableHTTPS: true + tlsConfig: + insecure: true + {{- else }} + - urlPrefix: "http://127.0.0.1:80" + enableHTTPS: false + {{- end }} + filterVerb: filter + bindVerb: bind + nodeCacheCapable: true + weight: 1 + httpTimeout: 30s + managedResources: + - name: {{ .Values.resourceName }} + ignoredByScheduler: true + - name: {{ .Values.resourceMem }} + ignoredByScheduler: true + - name: {{ .Values.resourceCores }} + ignoredByScheduler: true + - name: {{ .Values.resourceMemPercentage }} + ignoredByScheduler: true + - name: {{ .Values.resourcePriority }} + ignoredByScheduler: true + - name: {{ .Values.mluResourceName }} + ignoredByScheduler: true + - name: {{ .Values.dcuResourceName }} + ignoredByScheduler: true + - name: {{ .Values.dcuResourceMem }} + ignoredByScheduler: true + - name: {{ .Values.dcuResourceCores }} + ignoredByScheduler: true + - name: "metax-tech.com/gpu" + ignoredByScheduler: true + - name: {{ .Values.metaxResourceName }} + ignoredByScheduler: true + - name: {{ .Values.metaxResourceCore }} + ignoredByScheduler: true + - name: {{ .Values.metaxResourceMem }} + ignoredByScheduler: true + {{- if .Values.devices.ascend.enabled }} + {{- range .Values.devices.ascend.customresources }} + - name: {{ . }} + ignoredByScheduler: true + {{- end }} + {{- end }} + {{- if .Values.devices.mthreads.enabled }} + {{- range .Values.devices.mthreads.customresources }} + - name: {{ . }} + ignoredByScheduler: true + {{- end }} + {{- end }} + {{- if .Values.devices.enflame.enabled }} + {{- range .Values.devices.enflame.customresources }} + - name: {{ . }} + ignoredByScheduler: true + {{- end }} + {{- end }} + {{- if .Values.devices.kunlun.enabled }} + {{- range .Values.devices.kunlun.customresources }} + - name: {{ . }} + ignoredByScheduler: true + {{- end }} + {{- end }} + {{- range .Values.devices.awsneuron.customresources }} + - name: {{ . }} + ignoredByScheduler: true + {{- end }} + {{- if .Values.devices.iluvatar.enabled }} + {{- range .Values.devices.iluvatar.customresources }} + - name: {{ . }} + ignoredByScheduler: true + {{- end }} + {{- end }} + {{- range .Values.devices.amd.customresources }} + - name: {{ . }} + ignoredByScheduler: true + {{- end }} +{{- end }} diff --git a/packages/system/hami/charts/hami/templates/scheduler/deployment.yaml b/packages/system/hami/charts/hami/templates/scheduler/deployment.yaml new file mode 100644 index 00000000..1d89e189 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/deployment.yaml @@ -0,0 +1,225 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "hami-vgpu.scheduler" . }} + namespace: {{ include "hami-vgpu.namespace" . }} + labels: + app.kubernetes.io/component: hami-scheduler + {{- include "hami-vgpu.labels" . | nindent 4 }} + {{- with .Values.global.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if .Values.global.annotations }} + annotations: {{ toYaml .Values.global.annotations | nindent 4}} + {{- end }} +spec: + {{- if .Values.scheduler.leaderElect }} + replicas: {{ .Values.scheduler.replicas }} + {{- else }} + replicas: 1 + {{- end }} + selector: + matchLabels: + app.kubernetes.io/component: hami-scheduler + {{- include "hami-vgpu.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + app.kubernetes.io/component: hami-scheduler + {{- include "hami-vgpu.selectorLabels" . | nindent 8 }} + hami.io/webhook: ignore + annotations: + {{- if ge (regexReplaceAll "[^0-9]" .Capabilities.KubeVersion.Minor "" | int) 22 }} + checksum/hami-scheduler-newversion-config: {{ include (print $.Template.BasePath "/scheduler/configmapnew.yaml") . | sha256sum }} + {{- else }} + checksum/hami-scheduler-config: {{ include (print $.Template.BasePath "/scheduler/configmap.yaml") . | sha256sum }} + {{- end }} + checksum/hami-scheduler-device-config: {{ include (print $.Template.BasePath "/scheduler/device-configmap.yaml") . | sha256sum }} + {{- if .Values.scheduler.podAnnotations }} + {{- toYaml .Values.scheduler.podAnnotations | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "hami-vgpu.scheduler" . }} + priorityClassName: system-node-critical + {{- include "hami.scheduler.extender.imagePullSecrets" . | nindent 6 }} + containers: + {{- if .Values.scheduler.kubeScheduler.enabled }} + - name: kube-scheduler + image: {{ include "hami.scheduler.kubeScheduler.image" . }} + imagePullPolicy: {{ .Values.scheduler.kubeScheduler.image.pullPolicy }} + command: + - kube-scheduler + {{- if ge (regexReplaceAll "[^0-9]" .Capabilities.KubeVersion.Minor "" | int) 22 }} + {{- range .Values.scheduler.kubeScheduler.extraNewArgs }} + - {{ . }} + {{- end }} + {{- else }} + - --scheduler-name={{ .Values.schedulerName }} + {{- range .Values.scheduler.kubeScheduler.extraArgs }} + - {{ . }} + {{- end }} + {{- end }} + - --leader-elect={{ .Values.scheduler.leaderElect }} + - --leader-elect-resource-name={{ .Values.schedulerName }} + - --leader-elect-resource-namespace={{ include "hami-vgpu.namespace" . }} + resources: + {{- toYaml .Values.scheduler.kubeScheduler.resources | nindent 12 }} + volumeMounts: + - name: scheduler-config + mountPath: /config + {{- end }} + {{- if .Values.scheduler.livenessProbe }} + livenessProbe: + failureThreshold: 8 + httpGet: + path: /healthz + port: 10259 + scheme: HTTPS + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 15 + {{- end }} + - name: vgpu-scheduler-extender + image: {{ include "hami.scheduler.extender.image" . }} + imagePullPolicy: {{ .Values.scheduler.extender.image.pullPolicy }} + env: + {{- if .Values.scheduler.nodeLockExpire }} + - name: HAMI_NODELOCK_EXPIRE + value: "{{ .Values.scheduler.nodeLockExpire }}" + {{- end }} + {{- if .Values.global.managedNodeSelectorEnable }} + {{- range $key, $value := .Values.global.managedNodeSelector }} + - name: NODE_SELECTOR_{{ $key | upper | replace "-" "_" }} + value: "{{ $value }}" + {{- end }} + {{- end }} + command: + - scheduler + {{- if .Values.scheduler.admissionWebhook.enabled }} + - --http_bind=0.0.0.0:443 + - --cert_file=/tls/tls.crt + - --key_file=/tls/tls.key + {{- else }} + - --http_bind=0.0.0.0:80 + {{- end }} + - --scheduler-name={{ .Values.schedulerName }} + - --metrics-bind-address={{ .Values.scheduler.metricsBindAddress }} + - --node-scheduler-policy={{ .Values.scheduler.defaultSchedulerPolicy.nodeSchedulerPolicy }} + - --gpu-scheduler-policy={{ .Values.scheduler.defaultSchedulerPolicy.gpuSchedulerPolicy }} + - --force-overwrite-default-scheduler={{ .Values.scheduler.forceOverwriteDefaultScheduler}} + - --device-config-file=/device-config.yaml + - --leader-elect={{ .Values.scheduler.leaderElect }} + - --leader-elect-resource-name={{ .Values.schedulerName }} + - --leader-elect-resource-namespace={{ include "hami-vgpu.namespace" . }} + {{- if .Values.devices.ascend.enabled }} + - --enable-ascend=true + {{- end }} + {{- if .Values.devices.iluvatar.enabled }} + - --enable-iluvatar=true + {{- end }} + {{- if .Values.scheduler.nodeLabelSelector }} + - --node-label-selector={{- $first := true -}} + {{- range $key, $value := .Values.scheduler.nodeLabelSelector -}} + {{- if not $first }},{{ end -}} + {{- $key }}={{ $value -}} + {{- $first = false -}} + {{- end -}} + {{- end }} + {{- range .Values.scheduler.extender.extraArgs }} + - {{ . }} + {{- end }} + ports: + {{- if .Values.scheduler.admissionWebhook.enabled }} + - name: https + containerPort: 443 + protocol: TCP + {{- else }} + - name: http + containerPort: 80 + protocol: TCP + {{- end }} + - name: metrics + containerPort: {{ last (splitList ":" .Values.scheduler.metricsBindAddress) | int }} + protocol: TCP + resources: + {{- toYaml .Values.scheduler.extender.resources | nindent 12 }} + volumeMounts: + - name: device-config + mountPath: /device-config.yaml + subPath: device-config.yaml + {{- if .Values.scheduler.admissionWebhook.enabled }} + - name: tls-config + mountPath: /tls + {{- end }} + {{- if .Values.scheduler.livenessProbe }} + livenessProbe: + httpGet: + path: /healthz + {{- if .Values.scheduler.admissionWebhook.enabled }} + port: https + scheme: HTTPS + {{- else }} + port: http + scheme: HTTP + {{- end }} + initialDelaySeconds: 10 + periodSeconds: 10 + failureThreshold: 3 + timeoutSeconds: 5 + {{- end }} + {{- if .Values.scheduler.leaderElect }} + readinessProbe: + httpGet: + path: /readyz + {{- if .Values.scheduler.admissionWebhook.enabled }} + port: https + scheme: HTTPS + {{- else }} + port: http + scheme: HTTP + {{- end }} + initialDelaySeconds: 10 + periodSeconds: 10 + failureThreshold: 3 + timeoutSeconds: 5 + {{- end }} + {{- if .Values.scheduler.leaderElect }} + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app.kubernetes.io/component + operator: In + values: + - hami-scheduler + topologyKey: "kubernetes.io/hostname" + {{- end }} + volumes: + {{- if .Values.scheduler.admissionWebhook.enabled }} + - name: tls-config + secret: + secretName: {{ template "hami-vgpu.scheduler.tls" . }} + {{- end }} + {{- if .Values.scheduler.kubeScheduler.enabled }} + - name: scheduler-config + configMap: + {{- if ge (regexReplaceAll "[^0-9]" .Capabilities.KubeVersion.Minor "" | int) 22 }} + name: {{ template "hami-vgpu.scheduler" . }}-newversion + {{- else }} + name: {{ template "hami-vgpu.scheduler" . }} + {{- end }} + {{- end }} + - name: device-config + configMap: + name: {{ include "hami-vgpu.scheduler" . }}-device + {{- if .Values.scheduler.nodeSelector }} + nodeSelector: {{ toYaml .Values.scheduler.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.scheduler.tolerations }} + tolerations: {{ toYaml .Values.scheduler.tolerations | nindent 8 }} + {{- end }} + {{- if .Values.scheduler.nodeName }} + nodeName: {{ .Values.scheduler.nodeName }} + {{- end }} diff --git a/packages/system/hami/charts/hami/templates/scheduler/device-configmap.yaml b/packages/system/hami/charts/hami/templates/scheduler/device-configmap.yaml new file mode 100644 index 00000000..873b813b --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/device-configmap.yaml @@ -0,0 +1,408 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "hami-vgpu.scheduler" . }}-device + namespace: {{ include "hami-vgpu.namespace" . }} + labels: + app.kubernetes.io/component: hami-scheduler + {{- include "hami-vgpu.labels" . | nindent 4 }} +data: + device-config.yaml: |- + {{- if .Files.Glob "files/device-config.yaml" }} + {{- .Files.Get "files/device-config.yaml" | nindent 4}} + {{- else }} + nvidia: + resourceCountName: {{ .Values.resourceName }} + resourceMemoryName: {{ .Values.resourceMem }} + resourceMemoryPercentageName: {{ .Values.resourceMemPercentage }} + resourceCoreName: {{ .Values.resourceCores }} + resourcePriorityName: {{ .Values.resourcePriority }} + overwriteEnv: false + defaultMemory: 0 + defaultCores: 0 + defaultGPUNum: 1 + memoryFactor: 1 + deviceSplitCount: {{ .Values.devicePlugin.deviceSplitCount }} + deviceMemoryScaling: {{ .Values.devicePlugin.deviceMemoryScaling }} + deviceCoreScaling: {{ .Values.devicePlugin.deviceCoreScaling }} + gpuCorePolicy: {{ .Values.devices.nvidia.gpuCorePolicy }} + libCudaLogLevel: {{ .Values.devices.nvidia.libCudaLogLevel }} + runtimeClassName: "{{ .Values.devicePlugin.runtimeClassName }}" + knownMigGeometries: + - models: [ "A30" ] + allowedGeometries: + - + - name: 1g.6gb + core: 25 + memory: 6144 + count: 4 + - + - name: 2g.12gb + core: 50 + memory: 12288 + count: 2 + - + - name: 4g.24gb + core: 100 + memory: 24576 + count: 1 + - models: [ "A100-SXM4-40GB", "A100-40GB-PCIe", "A100-PCIE-40GB"] + allowedGeometries: + - + - name: 1g.5gb + core: 14 + memory: 5120 + count: 7 + - + - name: 1g.5gb + core: 14 + memory: 5120 + count: 1 + - name: 2g.10gb + core: 28 + memory: 10240 + count: 3 + - + - name: 3g.20gb + core: 42 + memory: 20480 + count: 2 + - + - name: 7g.40gb + core: 100 + memory: 40960 + count: 1 + - models: [ "A100-SXM4-80GB", "A100-80GB-PCIe", "A100-PCIE-80GB"] + allowedGeometries: + - + - name: 1g.10gb + core: 14 + memory: 10240 + count: 7 + - + - name: 1g.10gb + core: 14 + memory: 10240 + count: 1 + - name: 2g.20gb + core: 28 + memory: 20480 + count: 3 + - + - name: 3g.40gb + core: 42 + memory: 40960 + count: 2 + - + - name: 7g.79gb + core: 100 + memory: 80896 + count: 1 + - models: [ "H100-PCIE-80GB", "H100-SXM5-80GB"] + allowedGeometries: + - + - name: 1g.10gb + core: 14 + memory: 10240 + count: 7 + - + - name: 1g.10gb + core: 14 + memory: 10240 + count: 1 + - name: 2g.20gb + core: 28 + memory: 20480 + count: 3 + - + - name: 3g.40gb + core: 42 + memory: 40960 + count: 2 + - + - name: 7g.80gb + core: 100 + memory: 81920 + count: 1 + - models: [ "H100-PCIE-94GB", "H100-SXM5-94GB"] + allowedGeometries: + - + - name: 1g.12gb + core: 14 + memory: 12288 + count: 7 + - + - name: 1g.12gb + core: 14 + memory: 12288 + count: 1 + - name: 2g.24gb + core: 28 + memory: 24576 + count: 3 + - + - name: 3g.47gb + core: 42 + memory: 48128 + count: 2 + - + - name: 7g.94gb + core: 100 + memory: 96256 + count: 1 + - models: [ "H20", "H100 on GH200"] + allowedGeometries: + - + - name: 1g.12gb + core: 14 + memory: 12288 + count: 7 + - + - name: 1g.12gb + core: 14 + memory: 12288 + count: 1 + - name: 2g.24gb + core: 28 + memory: 24576 + count: 3 + - + - name: 3g.48gb + core: 42 + memory: 49152 + count: 2 + - + - name: 7g.96gb + core: 100 + memory: 98304 + count: 1 + - models: [ "H200 NVL", "H200-SXM5"] + allowedGeometries: + - + - name: 1g.18gb + core: 14 + memory: 18432 + count: 7 + - + - name: 1g.18gb + core: 14 + memory: 18432 + count: 1 + - name: 2g.35gb + core: 28 + memory: 35840 + count: 3 + - + - name: 3g.71gb + core: 42 + memory: 72704 + count: 2 + - + - name: 7g.141gb + core: 100 + memory: 144384 + count: 1 + - models: [ "B200" ] + allowedGeometries: + - + - name: 1g.23gb + core: 14 + memory: 23552 + count: 7 + - + - name: 1g.23gb + core: 14 + memory: 23552 + count: 1 + - name: 2g.45gb + core: 28 + memory: 46080 + count: 3 + - + - name: 3g.90gb + core: 42 + memory: 92160 + count: 2 + - + - name: 7g.180gb + core: 100 + memory: 184320 + count: 1 + cambricon: + resourceCountName: {{ .Values.mluResourceName }} + resourceMemoryName: {{ .Values.mluResourceMem }} + resourceCoreName: {{ .Values.mluResourceCores }} + hygon: + resourceCountName: {{ .Values.dcuResourceName }} + resourceMemoryName: {{ .Values.dcuResourceMem }} + resourceCoreName: {{ .Values.dcuResourceCores }} + memoryFactor: 1 + metax: + resourceCountName: "metax-tech.com/gpu" + resourceVCountName: {{ .Values.metaxResourceName }} + resourceVMemoryName: {{ .Values.metaxResourceMem }} + resourceVCoreName: {{ .Values.metaxResourceCore }} + sgpuTopologyAware: {{ .Values.metaxsGPUTopologyAware }} + enflame: + resourceNameGCU: "enflame.com/gcu" + resourceNameVGCU: {{ .Values.enflameResourceNameVGCU }} + resourceNameVGCUPercentage: {{ .Values.enflameResourceNameVGCUPercentage }} + mthreads: + resourceCountName: "mthreads.com/vgpu" + resourceMemoryName: "mthreads.com/sgpu-memory" + resourceCoreName: "mthreads.com/sgpu-core" + iluvatars: + - chipName: MR-V100 + commonWord: MR-V100 + resourceCountName: iluvatar.ai/MR-V100-vgpu + resourceMemoryName: iluvatar.ai/MR-V100.vMem + resourceCoreName: iluvatar.ai/MR-V100.vCore + - chipName: MR-V50 + commonWord: MR-V50 + resourceCountName: iluvatar.ai/MR-V50-vgpu + resourceMemoryName: iluvatar.ai/MR-V50.vMem + resourceCoreName: iluvatar.ai/MR-V50.vCore + - chipName: BI-V150 + commonWord: BI-V150 + resourceCountName: iluvatar.ai/BI-V150-vgpu + resourceMemoryName: iluvatar.ai/BI-V150.vMem + resourceCoreName: iluvatar.ai/BI-V150.vCore + - chipName: BI-V100 + commonWord: BI-V100 + resourceCountName: iluvatar.ai/BI-V100-vgpu + resourceMemoryName: iluvatar.ai/BI-V100.vMem + resourceCoreName: iluvatar.ai/BI-V100.vCore + kunlun: + resourceCountName: {{ .Values.kunlunResourceName }} + resourceVCountName: {{ .Values.kunlunResourceVCountName }} + resourceVMemoryName: {{ .Values.kunlunResourceVMemoryName }} + awsneuron: + resourceCountName: "aws.amazon.com/neuron" + resourceCoreName: "aws.amazon.com/neuroncore" + amd: + resourceCountName: "amd.com/gpu" + vnpus: + - chipName: 910A + commonWord: Ascend910A + resourceName: huawei.com/Ascend910A + resourceMemoryName: huawei.com/Ascend910A-memory + memoryAllocatable: 32768 + memoryCapacity: 32768 + memoryFactor: 1 + aiCore: 30 + templates: + - name: vir02 + memory: 2184 + aiCore: 2 + - name: vir04 + memory: 4369 + aiCore: 4 + - name: vir08 + memory: 8738 + aiCore: 8 + - name: vir16 + memory: 17476 + aiCore: 16 + - chipName: 910B2 + commonWord: Ascend910B2 + resourceName: huawei.com/Ascend910B2 + resourceMemoryName: huawei.com/Ascend910B2-memory + memoryAllocatable: 65536 + memoryCapacity: 65536 + memoryFactor: 1 + aiCore: 24 + aiCPU: 6 + templates: + - name: vir03_1c_8g + memory: 8192 + aiCore: 3 + aiCPU: 1 + - name: vir06_1c_16g + memory: 16384 + aiCore: 6 + aiCPU: 1 + - name: vir12_3c_32g + memory: 32768 + aiCore: 12 + aiCPU: 3 + - chipName: 910B3 + commonWord: Ascend910B3 + resourceName: huawei.com/Ascend910B3 + resourceMemoryName: huawei.com/Ascend910B3-memory + memoryAllocatable: 65536 + memoryCapacity: 65536 + memoryFactor: 1 + aiCore: 20 + aiCPU: 7 + templates: + - name: vir05_1c_16g + memory: 16384 + aiCore: 5 + aiCPU: 1 + - name: vir10_3c_32g + memory: 32768 + aiCore: 10 + aiCPU: 3 + - chipName: 910B4-1 + commonWord: Ascend910B4-1 + resourceName: huawei.com/Ascend910B4-1 + resourceMemoryName: huawei.com/Ascend910B4-1-memory + memoryAllocatable: 65536 + memoryCapacity: 65536 + memoryFactor: 1 + aiCore: 20 + aiCPU: 7 + templates: + # NOTE: Names of vnpu template for 910B4-1 are fixed by Ascend runtime and must not be changed. + # The memory is used for scheduling so the correct values must be set. + # Template vir05_1c_8g actually provides 16GB memory, + - name: vir05_1c_8g + memory: 16384 + aiCore: 5 + aiCPU: 1 + # Template vir10_3c_16g actually provides 32GB memory + - name: vir10_3c_16g + memory: 32768 + aiCore: 10 + aiCPU: 3 + - chipName: 910B4 + commonWord: Ascend910B4 + resourceName: huawei.com/Ascend910B4 + resourceMemoryName: huawei.com/Ascend910B4-memory + memoryAllocatable: 32768 + memoryCapacity: 32768 + memoryFactor: 1 + aiCore: 20 + aiCPU: 7 + templates: + - name: vir05_1c_8g + memory: 8192 + aiCore: 5 + aiCPU: 1 + - name: vir10_3c_16g + memory: 16384 + aiCore: 10 + aiCPU: 3 + - chipName: 310P3 + commonWord: Ascend310P + resourceName: huawei.com/Ascend310P + resourceMemoryName: huawei.com/Ascend310P-memory + memoryAllocatable: 21527 + memoryCapacity: 24576 + memoryFactor: 1 + aiCore: 8 + aiCPU: 7 + templates: + - name: vir01 + memory: 3072 + aiCore: 1 + aiCPU: 1 + - name: vir02 + memory: 6144 + aiCore: 2 + aiCPU: 2 + - name: vir04 + memory: 12288 + aiCore: 4 + aiCPU: 4 + {{ end }} diff --git a/packages/system/hami/charts/hami/templates/scheduler/job-patch/clusterrole.yaml b/packages/system/hami/charts/hami/templates/scheduler/job-patch/clusterrole.yaml new file mode 100644 index 00000000..77e891cc --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/job-patch/clusterrole.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.scheduler.admissionWebhook.enabled (.Values.scheduler.patch.enabled) (not .Values.scheduler.certManager.enabled) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "hami-vgpu.fullname" . }}-admission + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + {{- include "hami-vgpu.labels" . | nindent 4 }} + app.kubernetes.io/component: admission-webhook +rules: + - apiGroups: + - admissionregistration.k8s.io + resources: + #- validatingwebhookconfigurations + - mutatingwebhookconfigurations + verbs: + - get + - update +{{- end }} diff --git a/packages/system/hami/charts/hami/templates/scheduler/job-patch/clusterrolebinding.yaml b/packages/system/hami/charts/hami/templates/scheduler/job-patch/clusterrolebinding.yaml new file mode 100644 index 00000000..2b82f926 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/job-patch/clusterrolebinding.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.scheduler.admissionWebhook.enabled (.Values.scheduler.patch.enabled) (not .Values.scheduler.certManager.enabled) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "hami-vgpu.fullname" . }}-admission + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + {{- include "hami-vgpu.labels" . | nindent 4 }} + app.kubernetes.io/component: admission-webhook +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "hami-vgpu.fullname" . }}-admission +subjects: + - kind: ServiceAccount + name: {{ include "hami-vgpu.fullname" . }}-admission + namespace: {{ include "hami-vgpu.namespace" . }} +{{- end }} diff --git a/packages/system/hami/charts/hami/templates/scheduler/job-patch/job-createSecret.yaml b/packages/system/hami/charts/hami/templates/scheduler/job-patch/job-createSecret.yaml new file mode 100644 index 00000000..0e36d95f --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/job-patch/job-createSecret.yaml @@ -0,0 +1,68 @@ +{{- if and .Values.scheduler.admissionWebhook.enabled (.Values.scheduler.patch.enabled) (not .Values.scheduler.certManager.enabled) -}} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "hami-vgpu.fullname" . }}-admission-create + namespace: {{ include "hami-vgpu.namespace" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + {{- include "hami-vgpu.labels" . | nindent 4 }} + app.kubernetes.io/component: admission-webhook +spec: + {{- if .Capabilities.APIVersions.Has "batch/v1alpha1" }} + # Alpha feature since k8s 1.12 + ttlSecondsAfterFinished: 0 + {{- end }} + template: + metadata: + name: {{ include "hami-vgpu.fullname" . }}-admission-create + {{- if .Values.scheduler.patch.podAnnotations }} + annotations: {{ toYaml .Values.scheduler.patch.podAnnotations | nindent 8 }} + {{- end }} + labels: + {{- include "hami-vgpu.labels" . | nindent 8 }} + app.kubernetes.io/component: admission-webhook + hami.io/webhook: ignore + spec: + {{- if .Values.scheduler.patch.priorityClassName }} + priorityClassName: {{ .Values.scheduler.patch.priorityClassName }} + {{- end }} + {{- if ge (regexReplaceAll "[^0-9]" .Capabilities.KubeVersion.Minor "" | int) 22 }} + {{- include "hami.scheduler.patch.new.imagePullSecrets" . | nindent 6 }} + {{- else }} + {{- include "hami.scheduler.patch.imagePullSecrets" . | nindent 6 }} + {{- end }} + containers: + - name: create + {{- if ge (regexReplaceAll "[^0-9]" .Capabilities.KubeVersion.Minor "" | int) 22 }} + image: {{ include "hami.scheduler.patch.new.image" . }} + imagePullPolicy: {{ .Values.scheduler.patch.imageNew.pullPolicy }} + {{- else }} + image: {{ include "hami.scheduler.patch.image" . }} + imagePullPolicy: {{ .Values.scheduler.patch.image.pullPolicy }} + {{- end }} + args: + - create + - --cert-name=tls.crt + - --key-name=tls.key + {{- if .Values.scheduler.admissionWebhook.customURL.enabled }} + - --host={{ printf "%s.%s.svc,127.0.0.1,%s" (include "hami-vgpu.scheduler" .) (include "hami-vgpu.namespace" .) .Values.scheduler.admissionWebhook.customURL.host}} + {{- else }} + - --host={{ printf "%s.%s.svc,127.0.0.1" (include "hami-vgpu.scheduler" .) (include "hami-vgpu.namespace" .) }} + {{- end }} + - --namespace={{ include "hami-vgpu.namespace" . }} + - --secret-name={{ include "hami-vgpu.scheduler.tls" . }} + restartPolicy: OnFailure + serviceAccountName: {{ include "hami-vgpu.fullname" . }}-admission + {{- if .Values.scheduler.patch.nodeSelector }} + nodeSelector: {{ toYaml .Values.scheduler.patch.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.scheduler.patch.tolerations }} + tolerations: {{ toYaml .Values.scheduler.patch.tolerations | nindent 8 }} + {{- end }} + securityContext: + runAsNonRoot: true + runAsUser: {{ .Values.scheduler.patch.runAsUser }} +{{- end }} diff --git a/packages/system/hami/charts/hami/templates/scheduler/job-patch/job-patchWebhook.yaml b/packages/system/hami/charts/hami/templates/scheduler/job-patch/job-patchWebhook.yaml new file mode 100644 index 00000000..ce52042c --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/job-patch/job-patchWebhook.yaml @@ -0,0 +1,63 @@ +{{- if and .Values.scheduler.admissionWebhook.enabled (.Values.scheduler.patch.enabled) (not .Values.scheduler.certManager.enabled) -}} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "hami-vgpu.fullname" . }}-admission-patch + namespace: {{ include "hami-vgpu.namespace" . }} + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + {{- include "hami-vgpu.labels" . | nindent 4 }} + app.kubernetes.io/component: admission-webhook +spec: + {{- if .Capabilities.APIVersions.Has "batch/v1alpha1" }} + # Alpha feature since k8s 1.12 + ttlSecondsAfterFinished: 0 + {{- end }} + template: + metadata: + name: {{ include "hami-vgpu.fullname" . }}-admission-patch + {{- if .Values.scheduler.patch.podAnnotations }} + annotations: {{ toYaml .Values.scheduler.patch.podAnnotations | nindent 8 }} + {{- end }} + labels: + {{- include "hami-vgpu.labels" . | nindent 8 }} + app.kubernetes.io/component: admission-webhook + hami.io/webhook: ignore + spec: + {{- if .Values.scheduler.patch.priorityClassName }} + priorityClassName: {{ .Values.scheduler.patch.priorityClassName }} + {{- end }} + {{- if ge (regexReplaceAll "[^0-9]" .Capabilities.KubeVersion.Minor "" | int) 22 }} + {{- include "hami.scheduler.patch.new.imagePullSecrets" . | nindent 6 }} + {{- else }} + {{- include "hami.scheduler.patch.imagePullSecrets" . | nindent 6 }} + {{- end }} + containers: + - name: patch + {{- if ge (regexReplaceAll "[^0-9]" .Capabilities.KubeVersion.Minor "" | int) 22 }} + image: {{ include "hami.scheduler.patch.new.image" . }} + imagePullPolicy: {{ .Values.scheduler.patch.imageNew.pullPolicy }} + {{- else }} + image: {{ include "hami.scheduler.patch.image" . }} + imagePullPolicy: {{ .Values.scheduler.patch.image.pullPolicy }} + {{- end }} + args: + - patch + - --webhook-name={{ include "hami-vgpu.scheduler.webhook" . }} + - --namespace={{ include "hami-vgpu.namespace" . }} + - --patch-validating=false + - --secret-name={{ include "hami-vgpu.scheduler.tls" . }} + restartPolicy: OnFailure + serviceAccountName: {{ include "hami-vgpu.fullname" . }}-admission + {{- if .Values.scheduler.patch.nodeSelector }} + nodeSelector: {{ toYaml .Values.scheduler.patch.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.scheduler.patch.tolerations }} + tolerations: {{ toYaml .Values.scheduler.patch.tolerations | nindent 8 }} + {{- end }} + securityContext: + runAsNonRoot: true + runAsUser: {{ .Values.scheduler.patch.runAsUser }} +{{- end }} diff --git a/packages/system/hami/charts/hami/templates/scheduler/job-patch/role.yaml b/packages/system/hami/charts/hami/templates/scheduler/job-patch/role.yaml new file mode 100644 index 00000000..56682f8e --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/job-patch/role.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.scheduler.admissionWebhook.enabled (.Values.scheduler.patch.enabled) (not .Values.scheduler.certManager.enabled) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "hami-vgpu.fullname" . }}-admission + namespace: {{ include "hami-vgpu.namespace" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + {{- include "hami-vgpu.labels" . | nindent 4 }} + app.kubernetes.io/component: admission-webhook +rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - create +{{- end }} diff --git a/packages/system/hami/charts/hami/templates/scheduler/job-patch/rolebinding.yaml b/packages/system/hami/charts/hami/templates/scheduler/job-patch/rolebinding.yaml new file mode 100644 index 00000000..7239b128 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/job-patch/rolebinding.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.scheduler.admissionWebhook.enabled (.Values.scheduler.patch.enabled) (not .Values.scheduler.certManager.enabled) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "hami-vgpu.fullname" . }}-admission + namespace: {{ include "hami-vgpu.namespace" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + {{- include "hami-vgpu.labels" . | nindent 4 }} + app.kubernetes.io/component: admission-webhook +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "hami-vgpu.fullname" . }}-admission +subjects: + - kind: ServiceAccount + name: {{ include "hami-vgpu.fullname" . }}-admission + namespace: {{ include "hami-vgpu.namespace" . }} +{{- end }} diff --git a/packages/system/hami/charts/hami/templates/scheduler/job-patch/serviceaccount.yaml b/packages/system/hami/charts/hami/templates/scheduler/job-patch/serviceaccount.yaml new file mode 100644 index 00000000..857c6a8d --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/job-patch/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if and .Values.scheduler.admissionWebhook.enabled (.Values.scheduler.patch.enabled) (not .Values.scheduler.certManager.enabled) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "hami-vgpu.fullname" . }}-admission + namespace: {{ include "hami-vgpu.namespace" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + {{- include "hami-vgpu.labels" . | nindent 4 }} + app.kubernetes.io/component: admission-webhook +{{- end }} diff --git a/packages/system/hami/charts/hami/templates/scheduler/role.yaml b/packages/system/hami/charts/hami/templates/scheduler/role.yaml new file mode 100644 index 00000000..5f7d7e44 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/role.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "hami-vgpu.scheduler" . }} + namespace: {{ include "hami-vgpu.namespace" . }} + labels: + app.kubernetes.io/component: "hami-scheduler" + {{- include "hami-vgpu.labels" . | nindent 4 }} +rules: + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["create", "list", "watch", "get", "update", "patch"] diff --git a/packages/system/hami/charts/hami/templates/scheduler/rolebinding.yaml b/packages/system/hami/charts/hami/templates/scheduler/rolebinding.yaml new file mode 100644 index 00000000..96e175a1 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/rolebinding.yaml @@ -0,0 +1,31 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "hami-vgpu.scheduler" . }} + namespace: {{ include "hami-vgpu.namespace" . }} + labels: + app.kubernetes.io/component: "hami-scheduler" + {{- include "hami-vgpu.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "hami-vgpu.scheduler" . }} +subjects: + - kind: ServiceAccount + name: {{ include "hami-vgpu.scheduler" . }} + namespace: {{ include "hami-vgpu.namespace" . }} +--- +{{- if .Values.mockDevicePlugin.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "hami-vgpu.mock-device-plugin" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "hami-vgpu.mock-device-plugin" . }} +subjects: + - kind: ServiceAccount + name: {{ include "hami-vgpu.mock-device-plugin" . }} + namespace: {{ include "hami-vgpu.namespace" . }} +{{- end -}} diff --git a/packages/system/hami/charts/hami/templates/scheduler/service.yaml b/packages/system/hami/charts/hami/templates/scheduler/service.yaml new file mode 100644 index 00000000..d7538fed --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/service.yaml @@ -0,0 +1,34 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "hami-vgpu.scheduler" . }} + namespace: {{ include "hami-vgpu.namespace" . }} + labels: + app.kubernetes.io/component: hami-scheduler + {{- include "hami-vgpu.labels" . | nindent 4 }} + {{- if .Values.scheduler.service.labels }} + {{ toYaml .Values.scheduler.service.labels | indent 4 }} + {{- end }} + {{- if .Values.scheduler.service.annotations }} + annotations: {{ toYaml .Values.scheduler.service.annotations | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.scheduler.service.type | default "NodePort" }} # Default type is NodePort + ports: + - name: http + port: {{ .Values.scheduler.service.httpPort | default 443 }} # Default HTTP port is 443 + targetPort: {{ .Values.scheduler.service.httpTargetPort | default 443 }} + {{- if eq (.Values.scheduler.service.type | default "NodePort") "NodePort" }} # If type is NodePort, set nodePort + nodePort: {{ .Values.scheduler.service.schedulerPort | default 31998 }} + {{- end }} + protocol: TCP + - name: monitor + port: {{ .Values.scheduler.service.monitorPort | default 31993 }} # Default monitoring port is 31993 + targetPort: {{ .Values.scheduler.service.monitorTargetPort | default 9395 }} + {{- if eq (.Values.scheduler.service.type | default "NodePort") "NodePort" }} # If type is NodePort, set nodePort + nodePort: {{ .Values.scheduler.service.monitorPort | default 31993 }} + {{- end }} + protocol: TCP + selector: + app.kubernetes.io/component: hami-scheduler + {{- include "hami-vgpu.selectorLabels" . | nindent 4 }} diff --git a/packages/system/hami/charts/hami/templates/scheduler/serviceaccount.yaml b/packages/system/hami/charts/hami/templates/scheduler/serviceaccount.yaml new file mode 100644 index 00000000..0435c003 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "hami-vgpu.scheduler" . }} + namespace: {{ include "hami-vgpu.namespace" . }} + labels: + app.kubernetes.io/component: "hami-scheduler" + {{- include "hami-vgpu.labels" . | nindent 4 }} +--- +{{- if .Values.mockDevicePlugin.enabled }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "hami-vgpu.mock-device-plugin" . }} + namespace: {{ include "hami-vgpu.namespace" . }} +{{- end -}} diff --git a/packages/system/hami/charts/hami/templates/scheduler/webhook.yaml b/packages/system/hami/charts/hami/templates/scheduler/webhook.yaml new file mode 100644 index 00000000..db9f8029 --- /dev/null +++ b/packages/system/hami/charts/hami/templates/scheduler/webhook.yaml @@ -0,0 +1,57 @@ +{{- if .Values.scheduler.admissionWebhook.enabled -}} +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + {{- if .Values.scheduler.certManager.enabled }} + annotations: + cert-manager.io/inject-ca-from: {{ include "hami-vgpu.namespace" . }}/{{ include "hami-vgpu.scheduler" . }}-serving-cert + {{- end }} + name: {{ include "hami-vgpu.scheduler.webhook" . }} +webhooks: + - admissionReviewVersions: + - v1beta1 + clientConfig: + {{- if .Values.scheduler.admissionWebhook.customURL.enabled }} + url: https://{{ .Values.scheduler.admissionWebhook.customURL.host}}:{{.Values.scheduler.admissionWebhook.customURL.port}}{{.Values.scheduler.admissionWebhook.customURL.path}} + {{- else }} + service: + name: {{ include "hami-vgpu.scheduler" . }} + namespace: {{ include "hami-vgpu.namespace" . }} + path: /webhook + port: {{ .Values.scheduler.service.httpPort }} + {{- end }} + failurePolicy: {{ .Values.scheduler.admissionWebhook.failurePolicy }} + matchPolicy: Equivalent + name: vgpu.hami.io + namespaceSelector: + matchExpressions: + - key: hami.io/webhook + operator: NotIn + values: + - ignore + {{- if .Values.scheduler.admissionWebhook.whitelistNamespaces }} + - key: kubernetes.io/metadata.name + operator: NotIn + values: + {{- toYaml .Values.scheduler.admissionWebhook.whitelistNamespaces | nindent 10 }} + {{- end }} + objectSelector: + matchExpressions: + - key: hami.io/webhook + operator: NotIn + values: + - ignore + reinvocationPolicy: {{ .Values.scheduler.admissionWebhook.reinvocationPolicy }} + rules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + resources: + - pods + scope: '*' + sideEffects: None + timeoutSeconds: 10 +{{- end }} diff --git a/packages/system/hami/charts/hami/values.yaml b/packages/system/hami/charts/hami/values.yaml new file mode 100644 index 00000000..01caca0b --- /dev/null +++ b/packages/system/hami/charts/hami/values.yaml @@ -0,0 +1,455 @@ +## @section Global configuration +## @param global.imageRegistry Global Docker image registry +## @param global.imagePullSecrets Global Docker image pull secrets +global: + ## @param global.imageRegistry Global Docker image registry + imageRegistry: "" + ## E.g. + ## imagePullSecrets: + ## - myRegistryKeySecretName + ## @param global.imagePullSecrets Global Docker image pull secrets + imagePullSecrets: [] + imageTag: "v2.8.1" + gpuHookPath: /usr/local + labels: {} + annotations: {} + managedNodeSelectorEnable: false + managedNodeSelector: + usage: "gpu" + +nameOverride: "" +fullnameOverride: "" +namespaceOverride: "" + +#Nvidia GPU Parameters +resourceName: "nvidia.com/gpu" +resourceMem: "nvidia.com/gpumem" +resourceMemPercentage: "nvidia.com/gpumem-percentage" +resourceCores: "nvidia.com/gpucores" +resourcePriority: "nvidia.com/priority" + +#MLU Parameters +mluResourceName: "cambricon.com/vmlu" +mluResourceMem: "cambricon.com/mlu.smlu.vmemory" +mluResourceCores: "cambricon.com/mlu.smlu.vcore" + +#Hygon DCU Parameters +dcuResourceName: "hygon.com/dcunum" +dcuResourceMem: "hygon.com/dcumem" +dcuResourceCores: "hygon.com/dcucores" + +#Metax sGPU Parameters +metaxResourceName: "metax-tech.com/sgpu" +metaxResourceCore: "metax-tech.com/vcore" +metaxResourceMem: "metax-tech.com/vmemory" +metaxsGPUTopologyAware: "false" + +#Enflame VGCU Parameters +enflameResourceNameVGCU: "enflame.com/vgcu" +enflameResourceNameVGCUPercentage: "enflame.com/vgcu-percentage" + +#Kunlun XPU Parameters +kunlunResourceName: "kunlunxin.com/xpu" +kunlunResourceVCountName: "kunlunxin.com/vxpu" +kunlunResourceVMemoryName: "kunlunxin.com/vxpu-memory" + +schedulerName: "hami-scheduler" + +scheduler: + # @param nodeName defines the node name and the nvidia-vgpu-scheduler-scheduler will schedule to the node. + # if we install the nvidia-vgpu-scheduler-scheduler as default scheduler, we need to remove the k8s default + # scheduler pod from the cluster first, we must specify node name to skip the schedule workflow. + nodeName: "" + #nodeLabelSelector: + # "gpu": "on" + overwriteEnv: "false" + defaultSchedulerPolicy: + nodeSchedulerPolicy: binpack + gpuSchedulerPolicy: spread + metricsBindAddress: ":9395" + # If set to false, When Pod.Spec.SchedulerName equals to the const DefaultSchedulerName in k8s.io/api/core/v1 package, webhook will not overwrite it + forceOverwriteDefaultScheduler: true + livenessProbe: false + leaderElect: true + # when leaderElect is true, replicas is available, otherwise replicas is 1. + replicas: 1 + kubeScheduler: + # @param enabled indicate whether to run kube-scheduler container in the scheduler pod, it's true by default. + enabled: true + ## @param image.registry kube scheduler image registry + ## @param image.repository kube scheduler image repository + ## @param image.tag kube scheduler image tag (immutable tags are recommended) + ## @param image.pullPolicy kube scheduler image pull policy + ## @param image.pullSecrets Specify docker-registry secret names as an array + image: + registry: "registry.cn-hangzhou.aliyuncs.com" + repository: "google_containers/kube-scheduler" + tag: "" + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## Example: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + resources: {} + # If you do want to specify resources, uncomment the following lines, adjust them as necessary. + # and remove the curly braces after 'resources:'. +# limits: +# cpu: 1000m +# memory: 1000Mi +# requests: +# cpu: 100m +# memory: 100Mi + extraNewArgs: + - --config=/config/config.yaml + - -v=4 + extraArgs: + - --policy-config-file=/config/config.json + - -v=4 + extender: + ## @param image.registry scheduler extender image registry + ## @param image.repository scheduler extender image repository + ## @param image.tag scheduler extender image tag (immutable tags are recommended) + ## @param image.pullPolicy scheduler extender image pull policy + ## @param image.pullSecrets Specify docker-registry secret names as an array + image: + registry: "docker.io" + repository: "projecthami/hami" + tag: "" + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## Example: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + resources: {} + # If you do want to specify resources, uncomment the following lines, adjust them as necessary, + # and remove the curly braces after 'resources:'. +# limits: +# cpu: 1000m +# memory: 1000Mi +# requests: +# cpu: 100m +# memory: 100Mi + extraArgs: + - --debug + - -v=4 + nodeLockExpire: "5m" + podAnnotations: {} + tolerations: [] + #serviceAccountName: "hami-vgpu-scheduler-sa" + admissionWebhook: + # If set to false, the admission webhook is not installed and any pods that should use HAMi must be + # configured to use the right 'schedulerName' and other device-specific configurations. + enabled: true + customURL: + enabled: false + # must be an endpoint using https. + # should generate host certs here + host: 127.0.0.1 # hostname or ip, can be your node'IP if you want to use https://:/ + port: 31998 + path: /webhook + whitelistNamespaces: + # Specify the namespaces that the webhook will not be applied to. + # - default + # - kube-system + # - istio-system + reinvocationPolicy: Never + failurePolicy: Ignore + ## TLS Certificate Option 1: Use cert-manager to generate self-signed certificate. + ## If enabled, always takes precedence over options 2. + certManager: + enabled: false + ## TLS Certificate Option 2: Use kube-webhook-certgen to generate self-signed certificate. + ## If true and certManager.enabled is false, Helm will automatically create a self-signed cert and secret for you. + patch: + enabled: true + ## @param image.registry scheduler extender image registry + ## @param image.repository scheduler extender image repository + ## @param image.tag scheduler extender image tag (immutable tags are recommended) + ## @param image.pullPolicy scheduler extender image pull policy + ## @param image.pullSecrets Specify docker-registry secret names as an array + image: + registry: "docker.io" + repository: "jettech/kube-webhook-certgen" + tag: "v1.5.2" + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## Example: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## @param image.registry scheduler extender image registry + ## @param image.repository scheduler extender image repository + ## @param image.tag scheduler extender image tag (immutable tags are recommended) + ## @param image.pullPolicy scheduler extender image pull policy + ## @param image.pullSecrets Specify docker-registry secret names as an array + imageNew: + registry: "docker.io" + repository: "liangjw/kube-webhook-certgen" + tag: "v1.1.1" + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## Example: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + priorityClassName: "" + podAnnotations: {} + nodeSelector: {} + tolerations: [] + runAsUser: 2000 + service: + type: NodePort # Default type is NodePort, can be changed to ClusterIP + httpPort: 443 # HTTP port + schedulerPort: 31998 # NodePort for HTTP + monitorPort: 31993 # Monitoring port + monitorTargetPort: 9395 + httpTargetPort: 443 + labels: {} + annotations: {} + +devicePlugin: + enabled: true + gpuOperatorToolkitReady: + enabled: false + hostPath: "/run/nvidia/validations" + ## @param image.registry devicePlugin image registry + ## @param image.repository devicePlugin image repository + ## @param image.tag devicePlugin image tag (immutable tags are recommended) + ## @param image.pullPolicy devicePlugin image pull policy + ## @param image.pullSecrets Specify docker-registry secret names as an array + image: + registry: "docker.io" + repository: "projecthami/hami" + tag: "" + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## Example: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + monitor: + ## @param image.registry monitor image registry + ## @param image.repository monitor image repository + ## @param image.tag monitor image tag (immutable tags are recommended) + ## @param image.pullPolicy monitor image pull policy + ## @param image.pullSecrets Specify docker-registry secret names as an array + image: + registry: "docker.io" + repository: "projecthami/hami" + tag: "" + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## Example: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ctrPath: /usr/local/vgpu/containers + resyncInterval: "5m" + extraArgs: + - -v=4 + extraEnvs: {} + resources: {} + # If you do want to specify resources, uncomment the following lines, adjust them as necessary. + # and remove the curly braces after 'resources:'. +# limits: +# cpu: 1000m +# memory: 1000Mi +# requests: +# cpu: 100m +# memory: 100Mi + + deviceSplitCount: 10 + deviceMemoryScaling: 1 + deviceCoreScaling: 1 + # Node configuration for device plugin, Priority: externalConfigName > config > default config + nodeConfiguration: + # If you want to use a custom config.json, you can set the content here. + # If this is set, it will override the default config.json(An example is as follows). + config: | + { + "nodeconfig": [ + { + "name": "your-node-name", + "operatingmode": "hami-core", + "devicememoryscaling": 1, + "devicesplitcount": 10, + "migstrategy": "none", + "filterdevices": { + "uuid": [], + "index": [] + } + } + ] + } + # If you want to use an existing ConfigMap, you can set the name here. + # If this is set, the chart will not create the ConfigMap and will use the existing one. + externalConfigName: "" + # The runtime class name to be used by the device plugin, and added to the pod.spec.runtimeClassName of applications utilizing NVIDIA GPUs + runtimeClassName: "" + # Whether to create runtime class, name comes from runtimeClassName when it is set + createRuntimeClass: false + migStrategy: "none" + disablecorelimit: "false" + passDeviceSpecsEnabled: false + deviceListStrategy: "envvar" + nvidiaHookPath: null + nvidiaDriverRoot: null + gdrcopyEnabled: null + gdsEnabled: null + mofedEnabled: null + + extraArgs: + - -v=4 + extraEnvs: {} + service: + type: NodePort # Default type is NodePort, can be changed to ClusterIP + httpPort: 31992 + labels: {} + annotations: {} + + pluginPath: /var/lib/kubelet/device-plugins + libPath: /usr/local/vgpu + + podAnnotations: {} + nvidiaNodeSelector: + gpu: "on" + tolerations: [] + # The updateStrategy for DevicePlugin DaemonSet. + # If you want to update the DaemonSet by manual, set type as "OnDelete". + # We recommend use OnDelete update strategy because DevicePlugin pod restart will cause business pod restart, this behavior is destructive. + # Otherwise, you can use RollingUpdate update strategy to rolling update DevicePlugin pod. + updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + + resources: {} + # If you do want to specify resources, uncomment the following lines, adjust them as necessary. + # and remove the curly braces after 'resources:'. +# limits: +# cpu: 1000m +# memory: 1000Mi +# requests: +# cpu: 100m +# memory: 100Mi + +mockDevicePlugin: + enabled: false + image: + registry: "docker.io" + repository: "projecthami/mock-device-plugin" + tag: "1.0.1" + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: https://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## Example: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] +devices: + amd: + customresources: + - amd.com/gpu + - amd.com/gpu-memory + awsneuron: + customresources: + - aws.amazon.com/neuron + - aws.amazon.com/neuroncore + kunlun: + enabled: true + customresources: + - kunlunxin.com/xpu + - kunlunxin.com/vxpu + - kunlunxin.com/vxpu-memory + enflame: + enabled: true + customresources: + - enflame.com/vgcu + - enflame.com/vgcu-percentage + - enflame.com/gcu + mthreads: + enabled: true + customresources: + - mthreads.com/vgpu + nvidia: + gpuCorePolicy: default + libCudaLogLevel: 1 + ascend: + enabled: false + image: "" + imagePullPolicy: IfNotPresent + extraArgs: [] + nodeSelector: + ascend: "on" + tolerations: [] + customresources: + - huawei.com/Ascend910A + - huawei.com/Ascend910A-memory + - huawei.com/Ascend910B2 + - huawei.com/Ascend910B2-memory + - huawei.com/Ascend910B3 + - huawei.com/Ascend910B3-memory + - huawei.com/Ascend910B4 + - huawei.com/Ascend910B4-memory + - huawei.com/Ascend910B4-1 + - huawei.com/Ascend910B4-1-memory + - huawei.com/Ascend310P + - huawei.com/Ascend310P-memory + iluvatar: + enabled: false + customresources: + - iluvatar.ai/BI-V100-vgpu + - iluvatar.ai/BI-V100.vCore + - iluvatar.ai/BI-V100.vMem + - iluvatar.ai/BI-V150-vgpu + - iluvatar.ai/BI-V150.vCore + - iluvatar.ai/BI-V150.vMem + - iluvatar.ai/MR-V100-vgpu + - iluvatar.ai/MR-V100.vCore + - iluvatar.ai/MR-V100.vMem + - iluvatar.ai/MR-V50-vgpu + - iluvatar.ai/MR-V50.vCore + - iluvatar.ai/MR-V50.vMem diff --git a/packages/system/hami/values.yaml b/packages/system/hami/values.yaml new file mode 100644 index 00000000..76e8d631 --- /dev/null +++ b/packages/system/hami/values.yaml @@ -0,0 +1,17 @@ +hami: + scheduler: + kubeScheduler: + image: + registry: registry.k8s.io + repository: kube-scheduler + devicePlugin: + runtimeClassName: nvidia + updateStrategy: + type: RollingUpdate + # See https://github.com/Project-HAMi/HAMi/blob/v2.8.1/deployments/charts/hami/values.yaml + # Each entry: {"name": "node-name", "operatingmode": "hami-core", "devicesplitcount": N, ...} + nodeConfiguration: + config: | + { + "nodeconfig": [] + } diff --git a/packages/system/harbor-rd/Chart.yaml b/packages/system/harbor-rd/Chart.yaml new file mode 100644 index 00000000..c27f19d0 --- /dev/null +++ b/packages/system/harbor-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: harbor-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/harbor-rd/Makefile b/packages/system/harbor-rd/Makefile new file mode 100644 index 00000000..ed36644a --- /dev/null +++ b/packages/system/harbor-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=harbor-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/harbor-rd/cozyrds/harbor.yaml b/packages/system/harbor-rd/cozyrds/harbor.yaml new file mode 100644 index 00000000..5682c053 --- /dev/null +++ b/packages/system/harbor-rd/cozyrds/harbor.yaml @@ -0,0 +1,45 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: harbor +spec: + application: + kind: Harbor + singular: harbor + plural: harbors + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"host":{"description":"Hostname for external access to Harbor (defaults to 'harbor' subdomain for the tenant host).","type":"string","default":""},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"core":{"description":"Core API server configuration.","type":"object","default":{},"properties":{"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"Number of CPU cores allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Amount of memory allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"registry":{"description":"Container image registry configuration.","type":"object","default":{},"properties":{"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"Number of CPU cores allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Amount of memory allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"jobservice":{"description":"Background job service configuration.","type":"object","default":{},"properties":{"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"Number of CPU cores allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Amount of memory allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"trivy":{"description":"Trivy vulnerability scanner configuration.","type":"object","default":{},"required":["enabled","size"],"properties":{"enabled":{"description":"Enable or disable the vulnerability scanner.","type":"boolean","default":true},"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"Number of CPU cores allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Amount of memory allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume size for vulnerability database cache.","default":"5Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"database":{"description":"PostgreSQL database configuration.","type":"object","default":{},"required":["replicas","size"],"properties":{"replicas":{"description":"Number of database instances.","type":"integer","default":2},"size":{"description":"Persistent Volume size for database storage.","default":"5Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"redis":{"description":"Redis cache configuration.","type":"object","default":{},"required":["replicas","size"],"properties":{"replicas":{"description":"Number of Redis replicas.","type":"integer","default":2},"size":{"description":"Persistent Volume size for cache storage.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}} + release: + prefix: "harbor-" + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-harbor-application-default-harbor + namespace: cozy-system + dashboard: + category: PaaS + singular: Harbor + plural: Harbor + name: harbor + description: Managed Harbor container registry + tags: + - registry + - container + icon: "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHJvbGU9ImltZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHZpZXdCb3g9IjEuMDUgLTEuOTUgMzU5LjQxIDM2MS42NiI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQiIHgxPSIyNjQuNzkiIHgyPSIyNjcuMjciIHkxPSI5NTIuMzkiIHkyPSI5NTIuMzkiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMzAuNDMgMCAwIC0zMC40MyAtNzk1NS4yMiAyOTI4NS43NSkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiM2MGI5MzIiLz48c3RvcCBvZmZzZXQ9Ii4yOCIgc3RvcC1jb2xvcj0iIzYwYjkzMiIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzM2N2MzNCIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQtMiIgeDE9IjI2My43NyIgeDI9IjI2Ni4yNiIgeTE9Ijk1NS42NSIgeTI9Ijk1NS42NSIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyNy4yMSAwIDAgLTI3LjIxIC03MDczLjg1IDI2MTY5LjQxKSIgeGxpbms6aHJlZj0iI2xpbmVhci1ncmFkaWVudCIvPjxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyLWdyYWRpZW50LTMiIHgxPSIyNjMuMjgiIHgyPSIyNjUuNzYiIHkxPSI5NTMuNzQiIHkyPSI5NTMuNzQiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMjUuNzUgMCAwIC0yNS43NSAtNjY3MS4xMyAyNDgxMi4yMykiIHhsaW5rOmhyZWY9IiNsaW5lYXItZ3JhZGllbnQiLz48bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhci1ncmFkaWVudC00IiB4MT0iMjYzLjc3IiB4Mj0iMjY2LjI1IiB5MT0iOTUzLjIiIHkyPSI5NTMuMiIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyNy4xIDAgMCAtMjcuMSAtNzA0MC45IDI2MTAyLjQ5KSIgeGxpbms6aHJlZj0iI2xpbmVhci1ncmFkaWVudCIvPjxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyLWdyYWRpZW50LTUiIHgxPSIyNjIuNzMiIHgyPSIyNjUuMjEiIHkxPSI5NTQuMzQiIHkyPSI5NTQuMzQiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMjQuNCAwIDAgLTI0LjQgLTYzMDEuMzYgMjM1MjEuOTcpIiB4bGluazpocmVmPSIjbGluZWFyLWdyYWRpZW50Ii8+PGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQtNiIgeDE9IjI3Mi4xNCIgeDI9IjI3NC42MiIgeTE9Ijk1NS4xNSIgeTI9Ijk1NS4xNSIgZ3JhZGllbnRUcmFuc2Zvcm09InNjYWxlKDY2LjA5IC02Ni4wOSkgcm90YXRlKDM2LjUyIDE1ODguMTUzIDY4LjE0OCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiM0NTk2ZDgiLz48c3RvcCBvZmZzZXQ9Ii4yIiBzdG9wLWNvbG9yPSIjNDU5NmQ4Ii8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjZmZmIi8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhci1ncmFkaWVudC03IiB4MT0iMjcwLjY1IiB4Mj0iMjczLjEzIiB5MT0iOTUyLjM4IiB5Mj0iOTUyLjM4IiBncmFkaWVudFRyYW5zZm9ybT0ic2NhbGUoNzcuOCAtNzcuOCkgcm90YXRlKC0xMS41NCAtNDU4Ny4yMDkgMTgwMy4zMjMpIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjNDE5NGQ3Ii8+PHN0b3Agb2Zmc2V0PSIuMiIgc3RvcC1jb2xvcj0iIzQxOTRkNyIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI2ZmZiIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQtOCIgeDE9IjI3MC45NyIgeDI9IjI3My40NSIgeTE9Ijk1My43NSIgeTI9Ijk1My43NSIgZ3JhZGllbnRUcmFuc2Zvcm09InNjYWxlKDcxLjM1IC03MS4zNSkgcm90YXRlKDEwLjIzIDU0NzcuMzcgLTEwMjQuNjAyKSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzQxOTRkNyIvPjxzdG9wIG9mZnNldD0iLjMzIiBzdG9wLWNvbG9yPSIjNDQ5NmQ4Ii8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjZmZmIi8+PC9saW5lYXJHcmFkaWVudD48Y2xpcFBhdGggaWQ9ImNsaXAtcGF0aCI+PHBhdGggZD0iTTE3NC40IDMwMi41MmwtNjguNjUtMzAuMjYtMy44MyA0My4yMSA3NS41IDIzLjk4LTMuMDItMzYuOTN6IiBjbGFzcz0iY2xzLTEiLz48L2NsaXBQYXRoPjxjbGlwUGF0aCBpZD0iY2xpcC1wYXRoLTIiPjxwYXRoIGQ9Ik0xMTkuMTkgMTM1LjM4aDM4LjU1djMyLjg5aC05LjE1di0xNGExMC4xMyAxMC4xMyAwIDEgMC0yMC4yNiAwdjE0aC05LjE1em0tNy43IDcybDU3LjIgMjUuMjEtMy45NC00OC4yNGg3LjQ5di0xNi4wOGgtNS41NXYtMzIuODloNS41NXYtOS40NWwtMzAuODYtMzAuMTl2LTIuMTJhMi45MSAyLjkxIDAgMCAwLTUuODIgMHYyLjEybC0zMC44NiAzMC4xOXY5LjQ1aDUuNTZ2MzIuODloLTUuNTZ2MTYuMTJoOC44MnoiIGNsYXNzPSJjbHMtMSIvPjwvY2xpcFBhdGg+PGNsaXBQYXRoIGlkPSJjbGlwLXBhdGgtMyI+PHBhdGggZD0iTTEwOC4xNCAyNDUuMjhsNjMuODggMjguMTYtLjk2LTExLjczLTYxLjk2LTI3LjMtLjk2IDEwLjg3eiIgY2xhc3M9ImNscy0xIi8+PC9jbGlwUGF0aD48Y2xpcFBhdGggaWQ9ImNsaXAtcGF0aC00Ij48cGF0aCBkPSJNMTA2LjQ2IDI2NC4yMWw2Ny4yMyAyOS42My0uOTYtMTEuNzItNjUuMzEtMjguNzgtLjk2IDEwLjg3eiIgY2xhc3M9ImNscy0xIi8+PC9jbGlwUGF0aD48Y2xpcFBhdGggaWQ9ImNsaXAtcGF0aC01Ij48cGF0aCBkPSJNMTEwLjc3IDIxNS40OGwtLjk2IDEwLjg3IDYwLjU0IDI2LjY4LS45NS0xMS43Mi01OC42My0yNS44M3oiIGNsYXNzPSJjbHMtMSIvPjwvY2xpcFBhdGg+PGNsaXBQYXRoIGlkPSJjbGlwLXBhdGgtNiI+PHBhdGggZD0iTTMxMy4xMyA2Ny41OWExNzUuMzEgMTc1LjMxIDAgMCAwLTI5Ljc1LTI4LjEzYy0xLjU3LTEuMTctMy4xOC0yLjMtNC43OS0zLjQyTDI1NiA1OS41bC04Mi4zNCA4NS42MyAxMTMuNDEtNTguNjggMjkuMDctMTVjLTEuMDEtMS4zMS0xLjk4LTIuNjItMy4wMS0zLjg2eiIgY2xhc3M9ImNscy0xIi8+PC9jbGlwUGF0aD48Y2xpcFBhdGggaWQ9ImNsaXAtcGF0aC03Ij48cGF0aCBkPSJNMzUzLjU5IDE3Ny42MWMwLTItLjE0LTQtLjIyLTUuOTNsLTMyLjIxLTIuMzEtMTQ3LjQ3LTEwLjU4TDMxOC4zNiAyMDlsMzAuNDEgMTAuNTVjLjA5LS4zNi4xOS0uNzEuMjgtMS4wOGExNzMuNjUgMTczLjY1IDAgMCAwIDQuNTctMzkuNDd2LTEuMzd6IiBjbGFzcz0iY2xzLTEiLz48L2NsaXBQYXRoPjxjbGlwUGF0aCBpZD0iY2xpcC1wYXRoLTgiPjxwYXRoIGQ9Ik0zNDguODQgMTM4LjYxYTE3Mi41NSAxNzIuNTUgMCAwIDAtMTMuODQtMzcuN2wtMzAuOTQgOS45NEwxNzUuOTIgMTUybDE0Mi00LjgzIDMyLjUtMS4xMWMtLjUtMi40OC0uOTktNC45OC0xLjU4LTcuNDV6IiBjbGFzcz0iY2xzLTEiLz48L2NsaXBQYXRoPjxzdHlsZT4uY2xzLTF7ZmlsbDpub25lfS5jbHMtMTN7ZmlsbDojNjk2NTY2fTwvc3R5bGU+PC9kZWZzPjxnIGlkPSJnMTIiPjxwYXRoIGlkPSJwYXRoMTQiIGZpbGw9IiNmZmYiIGQ9Ik0zMC44OSAxNzlhMTQ4Ljg3IDE0OC44NyAwIDEgMSAxNDguODcgMTQ4Ljg1QTE0OC44NyAxNDguODcgMCAwIDEgMzAuODkgMTc5Ii8+PGcgaWQ9ImczMCIgY2xpcC1wYXRoPSJ1cmwoI2NsaXAtcGF0aCkiPjxnIGlkPSJnMzIiPjxwYXRoIGlkPSJwYXRoNDYiIGZpbGw9InVybCgjbGluZWFyLWdyYWRpZW50KSIgZD0iTTE3NC40IDMwMi41MmwtNjguNjUtMzAuMjUtMy44MiA0My4yIDc1LjUgMjQtMy0zNi45MyIvPjwvZz48L2c+PGcgaWQ9Imc0OCIgY2xpcC1wYXRoPSJ1cmwoI2NsaXAtcGF0aC0yKSI+PGcgaWQ9Imc1MCI+PHBhdGggaWQ9InBhdGg2NCIgZmlsbD0idXJsKCNsaW5lYXItZ3JhZGllbnQtMikiIGQ9Ik0xMTkuMTkgMTM1LjM4aDM4LjU1djMyLjg5aC05LjE1di0xNGExMC4xMyAxMC4xMyAwIDEgMC0yMC4yNiAwdjE0aC05LjE1em0tNy43IDcybDU3LjIgMjUuMjEtMy45NC00OC4yNGg3LjQ5di0xNi4wOGgtNS41NXYtMzIuODloNS41NXYtOS40NWwtMzAuODYtMzAuMTl2LTIuMTJhMi45MSAyLjkxIDAgMCAwLTUuODIgMHYyLjEybC0zMC44NiAzMC4xOXY5LjQ1aDUuNTZ2MzIuODloLTUuNTZ2MTYuMTJoOC44MmwtMiAyMyIvPjwvZz48L2c+PGcgaWQ9Imc2NiIgY2xpcC1wYXRoPSJ1cmwoI2NsaXAtcGF0aC0zKSI+PGcgaWQ9Imc2OCI+PHBhdGggaWQ9InBhdGg4MiIgZmlsbD0idXJsKCNsaW5lYXItZ3JhZGllbnQtMykiIGQ9Ik0xMDguMTMgMjQ1LjI4TDE3MiAyNzMuNDRsLTEtMTEuNzItNjItMjcuMzEtMSAxMC44NyIvPjwvZz48L2c+PGcgaWQ9Imc4NCIgY2xpcC1wYXRoPSJ1cmwoI2NsaXAtcGF0aC00KSI+PGcgaWQ9Imc4NiI+PHBhdGggaWQ9InBhdGgxMDAiIGZpbGw9InVybCgjbGluZWFyLWdyYWRpZW50LTQpIiBkPSJNMTA2LjQ2IDI2NC4yMWw2Ny4yMyAyOS42My0xLTExLjcyLTY1LjMxLTI4Ljc4LTEgMTAuODciLz48L2c+PC9nPjxnIGlkPSJnMTAyIiBjbGlwLXBhdGg9InVybCgjY2xpcC1wYXRoLTUpIj48ZyBpZD0iZzEwNCI+PHBhdGggaWQ9InBhdGgxMTgiIGZpbGw9InVybCgjbGluZWFyLWdyYWRpZW50LTUpIiBkPSJNMTEwLjc3IDIxNS40OGwtMSAxMC44OEwxNzAuMzUgMjUzbC0xLTExLjcyLTU4LjYyLTI1LjgzIi8+PC9nPjwvZz48cGF0aCBpZD0icGF0aDEyMCIgZD0iTTMwNC4wNyAxMTAuODVsMzAuOTMtOS45NGMtLjExLS4yMi0uMjEtLjQ1LS4zMi0uNjZhMTc0LjQxIDE3NC40MSAwIDAgMC0xOC41NS0yOC44M2wtMjkuMDcgMTVhMTQyLjcxIDE0Mi43MSAwIDAgMSAxNi43MyAyMy44N2MuMS4xNy4xOC4zNS4yNy41MyIgY2xhc3M9ImNscy0xMyIvPjxwYXRoIGlkPSJwYXRoMTIyIiBkPSJNMzIxLjE1IDE2OS4zN2wzMi4yMSAyLjMxYTE3Mi44NiAxNzIuODYgMCAwIDAtMy0yNS41OWwtMzIuNSAxLjExYTE0MSAxNDEgMCAwIDEgMy4yNSAyMi4xNyIgY2xhc3M9ImNscy0xMyIvPjxwYXRoIGlkPSJwYXRoMTI0IiBkPSJNMTgyIDMyMC44MWMtNzguMiAwLTE0MS44My02My42Mi0xNDEuODMtMTQxLjgyUzEwMy44MiAzNy4xNiAxODIgMzcuMTZhMTQwLjkzIDE0MC45MyAwIDAgMSA3Ni4zIDIyLjM0TDI4MC44NSAzNkExNzIuODYgMTcyLjg2IDAgMCAwIDE4MiA1LjExQzg2LjE1IDUuMTEgOC4xNSA4My4xMSA4LjE1IDE3OXM3OCAxNzMuODUgMTczLjg1IDE3My44NWM4MS45IDAgMTUwLjY5LTU3IDE2OS0xMzMuMzJMMzIwLjYyIDIwOWMtMTMuOCA2My44NC03MC42OSAxMTEuODMtMTM4LjYgMTExLjgzIiBjbGFzcz0iY2xzLTEzIi8+PGcgaWQ9ImcxMjYiIGNsaXAtcGF0aD0idXJsKCNjbGlwLXBhdGgtNikiPjxnIGlkPSJnMTI4Ij48cGF0aCBpZD0icGF0aDE0MiIgZmlsbD0idXJsKCNsaW5lYXItZ3JhZGllbnQtNikiIGQ9Ik0zMTMuMTMgNjcuNTlhMTc1LjMxIDE3NS4zMSAwIDAgMC0yOS43NS0yOC4xM2MtMS41Ny0xLjE3LTMuMTgtMi4zLTQuNzktMy40MkwyNTYgNTkuNWwtODIuMzQgODUuNjMgMTEzLjQxLTU4LjY4IDI5LjA3LTE1Yy0xLTEuMjctMi0yLjU4LTMtMy44MiIvPjwvZz48L2c+PGcgaWQ9ImcxNDQiIGNsaXAtcGF0aD0idXJsKCNjbGlwLXBhdGgtNykiPjxnIGlkPSJnMTQ2Ij48cGF0aCBpZD0icGF0aDE2MCIgZmlsbD0idXJsKCNsaW5lYXItZ3JhZGllbnQtNykiIGQ9Ik0zNTMuNTkgMTc3LjYxYzAtMi0uMTQtNC0uMjItNS45M2wtMzIuMjEtMi4zMS0xNDcuNDctMTAuNThMMzE4LjM2IDIwOWwzMC40MSAxMC41NWMuMDktLjM2LjE5LS43MS4yOC0xLjA4YTE3My42NSAxNzMuNjUgMCAwIDAgNC41Ny0zOS40N3YtMS4zNyIvPjwvZz48L2c+PGcgaWQ9ImcxNjIiIGNsaXAtcGF0aD0idXJsKCNjbGlwLXBhdGgtOCkiPjxnIGlkPSJnMTY0Ij48cGF0aCBpZD0icGF0aDE3OCIgZmlsbD0idXJsKCNsaW5lYXItZ3JhZGllbnQtOCkiIGQ9Ik0zNDguODQgMTM4LjYxYTE3Mi41NSAxNzIuNTUgMCAwIDAtMTMuODQtMzcuN2wtMzAuOTQgOS45NEwxNzUuOTIgMTUybDE0Mi00LjgzIDMyLjUtMS4xMWMtLjQ4LTIuNTEtMS01LTEuNTYtNy40OCIvPjwvZz48L2c+PC9nPjwvc3ZnPg==" + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "host"], ["spec", "storageClass"], ["spec", "core"], ["spec", "core", "resources"], ["spec", "core", "resourcesPreset"], ["spec", "registry"], ["spec", "registry", "resources"], ["spec", "registry", "resourcesPreset"], ["spec", "jobservice"], ["spec", "jobservice", "resources"], ["spec", "jobservice", "resourcesPreset"], ["spec", "trivy"], ["spec", "trivy", "enabled"], ["spec", "trivy", "size"], ["spec", "trivy", "resources"], ["spec", "trivy", "resourcesPreset"], ["spec", "database"], ["spec", "database", "size"], ["spec", "database", "replicas"], ["spec", "redis"], ["spec", "redis", "size"], ["spec", "redis", "replicas"]] + secrets: + exclude: [] + include: + - resourceNames: + - "{{ .name }}-credentials" + services: + exclude: [] + include: + - resourceNames: + - "{{ .name }}" + ingresses: + exclude: [] + include: + - resourceNames: + - "{{ .name }}-ingress" diff --git a/packages/system/harbor-rd/templates/cozyrd.yaml b/packages/system/harbor-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/harbor-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/harbor-rd/values.yaml b/packages/system/harbor-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/harbor-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/harbor/Chart.yaml b/packages/system/harbor/Chart.yaml new file mode 100644 index 00000000..5e7007b1 --- /dev/null +++ b/packages/system/harbor/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-harbor +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/harbor/Makefile b/packages/system/harbor/Makefile new file mode 100644 index 00000000..5cae60ed --- /dev/null +++ b/packages/system/harbor/Makefile @@ -0,0 +1,10 @@ +export NAME=harbor-system +export NAMESPACE=cozy-system + +include ../../../hack/package.mk + +update: + rm -rf charts + helm repo add harbor https://helm.goharbor.io + helm repo update harbor + helm pull harbor/harbor --untar --untardir charts diff --git a/packages/system/harbor/charts/harbor/.helmignore b/packages/system/harbor/charts/harbor/.helmignore new file mode 100644 index 00000000..b4424fd5 --- /dev/null +++ b/packages/system/harbor/charts/harbor/.helmignore @@ -0,0 +1,6 @@ +.github/* +docs/* +.git/* +.gitignore +CONTRIBUTING.md +test/* \ No newline at end of file diff --git a/packages/system/harbor/charts/harbor/Chart.yaml b/packages/system/harbor/charts/harbor/Chart.yaml new file mode 100644 index 00000000..e30a1b58 --- /dev/null +++ b/packages/system/harbor/charts/harbor/Chart.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +appVersion: 2.14.2 +description: An open source trusted cloud native registry that stores, signs, and + scans content +home: https://goharbor.io +icon: https://raw.githubusercontent.com/goharbor/website/main/static/img/logos/harbor-icon-color.png +keywords: +- docker +- registry +- harbor +maintainers: +- email: yan-yw.wang@broadcom.com + name: Yan Wang +- email: stone.zhang@broadcom.com + name: Stone Zhang +- email: miner.yang@broadcom.com + name: Miner Yang +name: harbor +sources: +- https://github.com/goharbor/harbor +- https://github.com/goharbor/harbor-helm +version: 1.18.2 diff --git a/packages/system/harbor/charts/harbor/LICENSE b/packages/system/harbor/charts/harbor/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/packages/system/harbor/charts/harbor/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/system/harbor/charts/harbor/README.md b/packages/system/harbor/charts/harbor/README.md new file mode 100644 index 00000000..658150d6 --- /dev/null +++ b/packages/system/harbor/charts/harbor/README.md @@ -0,0 +1,775 @@ +# Helm Chart for Harbor + +**Notes:** The master branch is in heavy development, please use the other stable versions instead. A highly available solution for Harbor based on chart can be found [here](docs/High%20Availability.md). And refer to the [guide](docs/Upgrade.md) to upgrade the existing deployment. + +This repository, including the issues, focuses on deploying Harbor chart via helm. For functionality issues or Harbor questions, please open issues on [goharbor/harbor](https://github.com/goharbor/harbor) + +## Introduction + +This [Helm](https://github.com/kubernetes/helm) chart installs [Harbor](https://github.com/goharbor/harbor) in a Kubernetes cluster. Welcome to [contribute](CONTRIBUTING.md) to Helm Chart for Harbor. + +## Prerequisites + +- Kubernetes cluster 1.20+ +- Helm v3.2.0+ + +## Installation + +### Add Helm repository + +```bash +helm repo add harbor https://helm.goharbor.io +``` + +### Configure the chart + +The following items can be set via `--set` flag during installation or configured by editing the `values.yaml` directly (need to download the chart first). + +#### Configure how to expose Harbor service + +- **Ingress**: The ingress controller must be installed in the Kubernetes cluster. + **Notes:** if TLS is disabled, the port must be included in the command when pulling/pushing images. Refer to issue [#5291](https://github.com/goharbor/harbor/issues/5291) for details. +- **ClusterIP**: Exposes the service on a cluster-internal IP. Choosing this value makes the service only reachable from within the cluster. +- **NodePort**: Exposes the service on each Node’s IP at a static port (the NodePort). You’ll be able to contact the NodePort service, from outside the cluster, by requesting `NodeIP:NodePort`. +- **LoadBalancer**: Exposes the service externally using a cloud provider’s load balancer. +- **Gateway APIs**: Exposes the service using gateway-api CRDs using HTTPRoute. Requires v1.0.0+ + +#### Configure the external URL + +The external URL for Harbor core service is used to: + +1. populate the docker/helm commands showed on portal +2. populate the token service URL returned to docker client + +Format: `protocol://domain[:port]`. Usually: + +- if service exposed via `Ingress`, the `domain` should be the value of `expose.ingress.hosts.core` +- if service exposed via `ClusterIP`, the `domain` should be the value of `expose.clusterIP.name` +- if service exposed via `NodePort`, the `domain` should be the IP address of one Kubernetes node +- if service exposed via `LoadBalancer`, set the `domain` as your own domain name and add a CNAME record to map the domain name to the one you got from the cloud provider + +If Harbor is deployed behind the proxy, set it as the URL of proxy. + +#### Configure how to persist data + +- **Disable**: The data does not survive the termination of a pod. +- **Persistent Volume Claim(default)**: A default `StorageClass` is needed in the Kubernetes cluster to dynamically provision the volumes. Specify another StorageClass in the `storageClass` or set `existingClaim` if you already have existing persistent volumes to use. +- **External Storage(only for images and charts)**: For images and charts, the external storages are supported: `azure`, `gcs`, `s3` `swift` and `oss`. + +#### Configure the other items listed in [configuration](#configuration) section + +### Install the chart + +Install the Harbor helm chart with a release name `my-release`: + +```bash +helm install my-release harbor/harbor +``` + +## Uninstallation + +To uninstall/delete the `my-release` deployment: + +```bash +helm uninstall my-release +``` + +## Configuration + +The following table lists the configurable parameters of the Harbor chart and the default values. + + +| Parameter | Description | Default | +|----------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------| +| **Expose** | | | +| `expose.type` | How to expose the service: `ingress`, `clusterIP`, `nodePort`, `loadBalancer` or `route` other values will be ignored and the creation of service will be skipped. | `ingress` | +| `expose.tls.enabled` | Enable TLS or not. Delete the `ssl-redirect` annotations in `expose.ingress.annotations` when TLS is disabled and `expose.type` is `ingress`. Note: if the `expose.type` is `ingress` and TLS is disabled, the port must be included in the command when pulling/pushing images. Refer to https://github.com/goharbor/harbor/issues/5291 for details. | `true` | +| `expose.tls.certSource` | The source of the TLS certificate. Set as `auto`, `secret` or `none` and fill the information in the corresponding section: 1) auto: generate the TLS certificate automatically 2) secret: read the TLS certificate from the specified secret. The TLS certificate can be generated manually or by cert manager 3) none: configure no TLS certificate for the ingress. If the default TLS certificate is configured in the ingress controller, choose this option | `auto` | +| `expose.tls.auto.commonName` | The common name used to generate the certificate, it's necessary when the type isn't `ingress` | | +| `expose.tls.secret.secretName` | The name of secret which contains keys named: `tls.crt` - the certificate; `tls.key` - the private key | | +| `expose.ingress.hosts.core` | The host of Harbor core service in ingress rule | `core.harbor.domain` | +| `expose.ingress.controller` | The ingress controller type. Currently supports `default`, `gce`, `alb`, `f5-bigip` and `ncp` | `default` | +| `expose.ingress.kubeVersionOverride` | Allows the ability to override the kubernetes version used while templating the ingress | | +| `expose.ingress.className` | Specify the `ingressClassName` used to implement the Ingress (Kubernetes 1.18+) | | +| `expose.ingress.annotations` | The annotations used commonly for ingresses | | +| `expose.ingress.labels` | The labels specific to ingress | {} | +| `expose.clusterIP.name` | The name of ClusterIP service | `harbor` | +| `expose.clusterIP.annotations` | The annotations attached to the ClusterIP service | {} | +| `expose.clusterIP.ports.httpPort` | The service port Harbor listens on when serving HTTP | `80` | +| `expose.clusterIP.ports.httpsPort` | The service port Harbor listens on when serving HTTPS | `443` | +| `expose.clusterIP.annotations` | The annotations used commonly for clusterIP | | +| `expose.clusterIP.labels` | The labels specific to clusterIP | {} | +| `expose.nodePort.name` | The name of NodePort service | `harbor` | +| `expose.nodePort.ports.http.port` | The service port Harbor listens on when serving HTTP | `80` | +| `expose.nodePort.ports.http.nodePort` | The node port Harbor listens on when serving HTTP | `30002` | +| `expose.nodePort.ports.https.port` | The service port Harbor listens on when serving HTTPS | `443` | +| `expose.nodePort.ports.https.nodePort` | The node port Harbor listens on when serving HTTPS | `30003` | +| `expose.nodePort.annotations` | The annotations used commonly for nodePort | | +| `expose.nodePort.labels` | The labels specific to nodePort | {} | +| `expose.loadBalancer.name` | The name of service | `harbor` | +| `expose.loadBalancer.IP` | The IP of the loadBalancer. It only works when loadBalancer supports assigning IP | `""` | +| `expose.loadBalancer.ports.httpPort` | The service port Harbor listens on when serving HTTP | `80` | +| `expose.loadBalancer.ports.httpsPort` | The service port Harbor listens on when serving HTTPS | `30002` | +| `expose.loadBalancer.annotations` | The annotations attached to the loadBalancer service | {} | +| `expose.loadBalancer.labels` | The labels specific to loadBalancer | {} | +| `expose.loadBalancer.sourceRanges` | List of IP address ranges to assign to loadBalancerSourceRanges | [] | +| `expose.route.labels` | The labels to attach to the HTTPRoute | `{}` | +| `expose.route.annotations` | The annotations to attach to the HTTPRoute | `{}` | +| `expose.route.hosts` | The hosts that the HTTPRoute will request to the Gateway | `[]` | +| `expose.route.parentRefs` | The Gateways to attach to the HTTPRoute | `{}` | +| **Internal TLS** | | | +| `internalTLS.enabled` | Enable TLS for the components (core, jobservice, portal, registry, trivy) | `false` | +| `internalTLS.strong_ssl_ciphers` | Enable strong ssl ciphers for nginx and portal | `false` | +| `internalTLS.certSource` | Method to provide TLS for the components, options are `auto`, `manual`, `secret`. | `auto` | +| `internalTLS.trustCa` | The content of trust CA, only available when `certSource` is `manual`. **Note**: all the internal certificates of the components must be issued by this CA | | +| `internalTLS.core.secretName` | The secret name for core component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.core.crt` | Content of core's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.core.key` | Content of core's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.jobservice.secretName` | The secret name for jobservice component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.jobservice.crt` | Content of jobservice's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.jobservice.key` | Content of jobservice's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.registry.secretName` | The secret name for registry component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.registry.crt` | Content of registry's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.registry.key` | Content of registry's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.portal.secretName` | The secret name for portal component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.portal.crt` | Content of portal's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.portal.key` | Content of portal's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.trivy.secretName` | The secret name for trivy component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.trivy.crt` | Content of trivy's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.trivy.key` | Content of trivy's TLS key file, only available when `certSource` is `manual` | | +| **IPFamily** | | | +| `ipFamily.ipv4.enabled` | if cluster is ipv4 enabled, all ipv4 related configs will set correspondingly, but currently it only affects the nginx related components | `true` | +| `ipFamily.ipv6.enabled` | if cluster is ipv6 enabled, all ipv6 related configs will set correspondingly, but currently it only affects the nginx related components | `true` | +| `ipFamily.policy` | Sets the IP family policy for services to be able to configure dual-stack; see [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services). | `""` | +| `ipFamily.families` | A list of IP families for services that should be supported, in the order in which they should be applied. Can be "IPv4" and/or "IPv6". | [] | +| **Persistence** | | | +| `persistence.enabled` | Enable the data persistence or not | `true` | +| `persistence.resourcePolicy` | Setting it to `keep` to avoid removing PVCs during a helm delete operation. Leaving it empty will delete PVCs after the chart deleted. Does not affect PVCs created for internal database and redis components. | `keep` | +| `persistence.persistentVolumeClaim.registry.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components | | +| `persistence.persistentVolumeClaim.registry.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning | | +| `persistence.persistentVolumeClaim.registry.subPath` | The sub path used in the volume | | +| `persistence.persistentVolumeClaim.registry.accessMode` | The access mode of the volume | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.registry.size` | The size of the volume | `5Gi` | +| `persistence.persistentVolumeClaim.registry.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.subPath` | The sub path used in the volume | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.accessMode` | The access mode of the volume | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.jobservice.jobLog.size` | The size of the volume | `1Gi` | +| `persistence.persistentVolumeClaim.jobservice.jobLog.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.database.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. If external database is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.database.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning. If external database is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.database.subPath` | The sub path used in the volume. If external database is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.database.accessMode` | The access mode of the volume. If external database is used, the setting will be ignored | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.database.size` | The size of the volume. If external database is used, the setting will be ignored | `1Gi` | +| `persistence.persistentVolumeClaim.database.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.redis.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. If external Redis is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.redis.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning. If external Redis is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.redis.subPath` | The sub path used in the volume. If external Redis is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.redis.accessMode` | The access mode of the volume. If external Redis is used, the setting will be ignored | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.redis.size` | The size of the volume. If external Redis is used, the setting will be ignored | `1Gi` | +| `persistence.persistentVolumeClaim.redis.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.trivy.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components | | +| `persistence.persistentVolumeClaim.trivy.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning | | +| `persistence.persistentVolumeClaim.trivy.subPath` | The sub path used in the volume | | +| `persistence.persistentVolumeClaim.trivy.accessMode` | The access mode of the volume | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.trivy.size` | The size of the volume | `1Gi` | +| `persistence.persistentVolumeClaim.trivy.annotations` | The annotations of the volume | | +| `persistence.imageChartStorage.disableredirect` | The configuration for managing redirects from content backends. For backends which not supported it (such as using minio for `s3` storage type), please set it to `true` to disable redirects. Refer to the [guide](https://github.com/docker/distribution/blob/master/docs/configuration.md#redirect) for more details | `false` | +| `persistence.imageChartStorage.caBundleSecretName` | Specify the `caBundleSecretName` if the storage service uses a self-signed certificate. The secret must contain keys named `ca.crt` which will be injected into the trust store of registry's and containers. | | +| `persistence.imageChartStorage.type` | The type of storage for images and charts: `filesystem`, `azure`, `gcs`, `s3`, `swift` or `oss`. The type must be `filesystem` if you want to use persistent volumes for registry. Refer to the [guide](https://github.com/docker/distribution/blob/master/docs/configuration.md#storage) for more details | `filesystem` | +| `persistence.imageChartStorage.gcs.existingSecret` | An existing secret containing the gcs service account json key. The key must be gcs-key.json. | `""` | +| `persistence.imageChartStorage.gcs.useWorkloadIdentity` | A boolean to allow the use of workloadidentity in a GKE cluster. To use it, create a kubernetes service account and set the name in the key `serviceAccountName` of each component, then allow automounting the service account. | `false` | +| **General** | | | +| `externalURL` | The external URL for Harbor core service | `https://core.harbor.domain` | +| `caBundleSecretName` | The custom CA bundle secret name, the secret must contain key named "ca.crt" which will be injected into the trust store for core, jobservice, registry, trivy components. | | +| `uaaSecretName` | If using external UAA auth which has a self signed cert, you can provide a pre-created secret containing it under the key `ca.crt`. | | +| `imagePullPolicy` | The image pull policy | | +| `imagePullSecrets` | The imagePullSecrets names for all deployments | | +| `updateStrategy.type` | The update strategy for deployments with persistent volumes(jobservice, registry): `RollingUpdate` or `Recreate`. Set it as `Recreate` when `RWM` for volumes isn't supported | `RollingUpdate` | +| `logLevel` | The log level: `debug`, `info`, `warning`, `error` or `fatal` | `info` | +| `harborAdminPassword` | The initial password of Harbor admin. Change it from portal after launching Harbor | `Harbor12345` | +| `existingSecretAdminPassword` | The name of secret where admin password can be found. | | +| `existingSecretAdminPasswordKey` | The name of the key in the secret where to find harbor admin password Harbor | `HARBOR_ADMIN_PASSWORD` | +| `caSecretName` | The name of the secret which contains key named `ca.crt`. Setting this enables the download link on portal to download the CA certificate when the certificate isn't generated automatically | | +| `secretKey` | The key used for encryption. Must be a string of 16 chars | `not-a-secure-key` | +| `existingSecretSecretKey` | An existing secret containing the encoding secretKey | `""` | +| `proxy.httpProxy` | The URL of the HTTP proxy server | | +| `proxy.httpsProxy` | The URL of the HTTPS proxy server | | +| `proxy.noProxy` | The URLs that the proxy settings not apply to | 127.0.0.1,localhost,.local,.internal | +| `proxy.components` | The component list that the proxy settings apply to | core, jobservice, trivy | +| `enableMigrateHelmHook` | Run the migration job via helm hook, if it is true, the database migration will be separated from harbor-core, run with a preupgrade job migration-job | `false` | +| **Nginx** (if service exposed via `ingress`, Nginx will not be used) | | | +| `nginx.image.repository` | Image repository | `goharbor/nginx-photon` | +| `nginx.image.tag` | Image tag | `dev` | +| `nginx.replicas` | The replica count | `1` | +| `nginx.revisionHistoryLimit` | The revision history limit | `10` | +| `nginx.resources` | The [resources] to allocate for container | undefined | +| `nginx.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `nginx.nodeSelector` | Node labels for pod assignment | `{}` | +| `nginx.tolerations` | Tolerations for pod assignment | `[]` | +| `nginx.affinity` | Node/Pod affinities | `{}` | +| `nginx.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `nginx.podAnnotations` | Annotations to add to the nginx pod | `{}` | +| `nginx.priorityClassName` | The priority class to run the pod as | | +| **Portal** | | | +| `portal.image.repository` | Repository for portal image | `goharbor/harbor-portal` | +| `portal.image.tag` | Tag for portal image | `dev` | +| `portal.replicas` | The replica count | `1` | +| `portal.revisionHistoryLimit` | The revision history limit | `10` | +| `portal.resources` | The [resources] to allocate for container | undefined | +| `portal.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `portal.nodeSelector` | Node labels for pod assignment | `{}` | +| `portal.tolerations` | Tolerations for pod assignment | `[]` | +| `portal.affinity` | Node/Pod affinities | `{}` | +| `portal.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `portal.podAnnotations` | Annotations to add to the portal pod | `{}` | +| `portal.serviceAnnotations` | Annotations to add to the portal service | `{}` | +| `portal.priorityClassName` | The priority class to run the pod as | | +| `portal.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Core** | | | +| `core.image.repository` | Repository for Harbor core image | `goharbor/harbor-core` | +| `core.image.tag` | Tag for Harbor core image | `dev` | +| `core.replicas` | The replica count | `1` | +| `core.revisionHistoryLimit` | The revision history limit | `10` | +| `core.startupProbe.initialDelaySeconds` | The initial delay in seconds for the startup probe | `10` | +| `core.resources` | The [resources] to allocate for container | undefined | +| `core.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `core.nodeSelector` | Node labels for pod assignment | `{}` | +| `core.tolerations` | Tolerations for pod assignment | `[]` | +| `core.affinity` | Node/Pod affinities | `{}` | +| `core.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `core.podAnnotations` | Annotations to add to the core pod | `{}` | +| `core.serviceAnnotations` | Annotations to add to the core service | `{}` | +| `core.configureUserSettings` | A JSON string to set in the environment variable `CONFIG_OVERWRITE_JSON` to configure user settings. See the [official docs](https://goharbor.io/docs/latest/install-config/configure-user-settings-cli/#configure-users-settings-using-an-environment-variable). | | +| `core.quotaUpdateProvider` | The provider for updating project quota(usage), there are 2 options, redis or db. By default it is implemented by db but you can configure it to redis which can improve the performance of high concurrent pushing to the same project, and reduce the database connections spike and occupies. Using redis will bring up some delay for quota usage updation for display, so only suggest switch provider to redis if you were ran into the db connections spike around the scenario of high concurrent pushing to same project, no improvment for other scenes. | `db` | +| `core.secret` | Secret is used when core server communicates with other components. If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | | +| `core.secretName` | Fill the name of a kubernetes secret if you want to use your own TLS certificate and private key for token encryption/decryption. The secret must contain keys named: `tls.crt` - the certificate and `tls.key` - the private key. The default key pair will be used if it isn't set | | +| `core.tokenKey` | PEM-formatted RSA private key used to sign service tokens. Only used if `core.secretName` is unset. If set, `core.tokenCert` MUST also be set. | | +| `core.tokenCert` | PEM-formatted certificate signed by `core.tokenKey` used to validate service tokens. Only used if `core.secretName` is unset. If set, `core.tokenKey` MUST also be set. | | +| `core.xsrfKey` | The XSRF key. Will be generated automatically if it isn't specified | | +| `core.priorityClassName` | The priority class to run the pod as | | +| `core.artifactPullAsyncFlushDuration` | The time duration for async update artifact pull_time and repository pull_count | | +| `core.gdpr.deleteUser` | Enable GDPR compliant user delete | `false` | +| `core.gdpr.auditLogsCompliant` | Enable GDPR compliant for audit logs by changing username to its CRC32 value if that user was deleted from the system | `false` | +| `core.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Jobservice** | | | +| `jobservice.image.repository` | Repository for jobservice image | `goharbor/harbor-jobservice` | +| `jobservice.image.tag` | Tag for jobservice image | `dev` | +| `jobservice.replicas` | The replica count | `1` | +| `jobservice.revisionHistoryLimit` | The revision history limit | `10` | +| `jobservice.maxJobWorkers` | The max job workers | `10` | +| `jobservice.jobLoggers` | The loggers for jobs: `file`, `database` or `stdout` | `[file]` | +| `jobservice.loggerSweeperDuration` | The jobLogger sweeper duration in days (ignored if `jobLoggers` is set to `stdout`) | `14` | +| `jobservice.notification.webhook_job_max_retry` | The maximum retry of webhook sending notifications | `3` | +| `jobservice.notification.webhook_job_http_client_timeout` | The http client timeout value of webhook sending notifications | `3` | +| `jobservice.reaper.max_update_hours` | the max time to wait for a task to finish, if unfinished after max_update_hours, the task will be mark as error, but the task will continue to run, default value is 24 | `24` | +| `jobservice.reaper.max_dangling_hours` | the max time for execution in running state without new task created | `168` | +| `jobservice.resources` | The [resources] to allocate for container | undefined | +| `jobservice.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `jobservice.nodeSelector` | Node labels for pod assignment | `{}` | +| `jobservice.tolerations` | Tolerations for pod assignment | `[]` | +| `jobservice.affinity` | Node/Pod affinities | `{}` | +| `jobservice.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `jobservice.podAnnotations` | Annotations to add to the jobservice pod | `{}` | +| `jobservice.priorityClassName` | The priority class to run the pod as | | +| `jobservice.secret` | Secret is used when job service communicates with other components. If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | | +| `jobservice.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Registry** | | | +| `registry.registry.image.repository` | Repository for registry image | `goharbor/registry-photon` | +| `registry.registry.image.tag` | Tag for registry image | `dev` | +| `registry.registry.resources` | The [resources] to allocate for container | undefined | +| `registry.controller.image.repository` | Repository for registry controller image | `goharbor/harbor-registryctl` | +| `registry.controller.image.tag` | Tag for registry controller image | `dev` | +| `registry.controller.resources` | The [resources] to allocate for container | undefined | +| `registry.replicas` | The replica count | `1` | +| `registry.revisionHistoryLimit` | The revision history limit | `10` | +| `registry.nodeSelector` | Node labels for pod assignment | `{}` | +| `registry.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `registry.tolerations` | Tolerations for pod assignment | `[]` | +| `registry.affinity` | Node/Pod affinities | `{}` | +| `registry.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `registry.middleware` | Middleware is used to add support for a CDN between backend storage and `docker pull` recipient. See [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#middleware). | | +| `registry.podAnnotations` | Annotations to add to the registry pod | `{}` | +| `registry.priorityClassName` | The priority class to run the pod as | | +| `registry.secret` | Secret is used to secure the upload state from client and registry storage backend. See [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#http). If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | | +| `registry.credentials.username` | The username that harbor core uses internally to access the registry instance. Together with the `registry.credentials.password`, a htpasswd is created. This is an alternative to providing `registry.credentials.htpasswdString`. For more details see [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#htpasswd). | `harbor_registry_user` | +| `registry.credentials.password` | The password that harbor core uses internally to access the registry instance. Together with the `registry.credentials.username`, a htpasswd is created. This is an alternative to providing `registry.credentials.htpasswdString`. For more details see [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#htpasswd). It is suggested you update this value before installation. | `harbor_registry_password` | +| `registry.credentials.existingSecret` | An existing secret containing the password for accessing the registry instance, which is hosted by htpasswd auth mode. More details see [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#htpasswd). The key must be `REGISTRY_PASSWD` | `""` | +| `registry.credentials.htpasswdString` | Login and password in htpasswd string format. Excludes `registry.credentials.username` and `registry.credentials.password`. May come in handy when integrating with tools like argocd or flux. This allows the same line to be generated each time the template is rendered, instead of the `htpasswd` function from helm, which generates different lines each time because of the salt. | undefined | +| `registry.relativeurls` | If true, the registry returns relative URLs in Location headers. The client is responsible for resolving the correct URL. Needed if harbor is behind a reverse proxy | `false` | +| `registry.upload_purging.enabled` | If true, enable purge _upload directories | `true` | +| `registry.upload_purging.age` | Remove files in _upload directories which exist for a period of time, default is one week. | `168h` | +| `registry.upload_purging.interval` | The interval of the purge operations | `24h` | +| `registry.upload_purging.dryrun` | If true, enable dryrun for purging _upload, default false | `false` | +| `registry.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **[Trivy][trivy]** | | | +| `trivy.enabled` | The flag to enable Trivy scanner | `true` | +| `trivy.image.repository` | Repository for Trivy adapter image | `goharbor/trivy-adapter-photon` | +| `trivy.image.tag` | Tag for Trivy adapter image | `dev` | +| `trivy.resources` | The [resources] to allocate for Trivy adapter container | | +| `trivy.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `trivy.replicas` | The number of Pod replicas | `1` | +| `trivy.debugMode` | The flag to enable Trivy debug mode | `false` | +| `trivy.vulnType` | Comma-separated list of vulnerability types. Possible values `os` and `library`. | `os,library` | +| `trivy.severity` | Comma-separated list of severities to be checked | `UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL` | +| `trivy.ignoreUnfixed` | The flag to display only fixed vulnerabilities | `false` | +| `trivy.insecure` | The flag to skip verifying registry certificate | `false` | +| `trivy.skipUpdate` | The flag to disable [Trivy DB][trivy-db] downloads from GitHub | `false` | +| `trivy.skipJavaDBUpdate` | If the flag is enabled you have to manually download the `trivy-java.db` file [Trivy Java DB][trivy-java-db] and mount it in the `/home/scanner/.cache/trivy/java-db/trivy-java.db` path | `false` | +| `trivy.offlineScan` | The flag prevents Trivy from sending API requests to identify dependencies. | `false` | +| `trivy.securityCheck` | Comma-separated list of what security issues to detect. | `vuln` | +| `trivy.timeout` | The duration to wait for scan completion | `5m0s` | +| `trivy.gitHubToken` | The GitHub access token to download [Trivy DB][trivy-db] (see [GitHub rate limiting][trivy-rate-limiting]) | | +| `trivy.priorityClassName` | The priority class to run the pod as | | +| `trivy.topologySpreadConstraints` | The priority class to run the pod as | | +| `trivy.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Database** | | | +| `database.type` | If external database is used, set it to `external` | `internal` | +| `database.internal.image.repository` | Repository for database image | `goharbor/harbor-db` | +| `database.internal.image.tag` | Tag for database image | `dev` | +| `database.internal.password` | The password for database | `changeit` | +| `database.internal.shmSizeLimit` | The limit for the size of shared memory for internal PostgreSQL, conventionally it's around 50% of the memory limit of the container | `512Mi` | +| `database.internal.resources` | The [resources] to allocate for container | undefined | +| `database.internal.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `database.internal.initContainer.migrator.resources` | The [resources] to allocate for the database migrator initContainer | undefined | +| `database.internal.initContainer.permissions.resources` | The [resources] to allocate for the database permissions initContainer | undefined | +| `database.internal.nodeSelector` | Node labels for pod assignment | `{}` | +| `database.internal.tolerations` | Tolerations for pod assignment | `[]` | +| `database.internal.affinity` | Node/Pod affinities | `{}` | +| `database.internal.priorityClassName` | The priority class to run the pod as | | +| `database.internal.livenessProbe.timeoutSeconds` | The timeout used in liveness probe; 1 to 5 seconds | 1 | +| `database.internal.readinessProbe.timeoutSeconds` | The timeout used in readiness probe; 1 to 5 seconds | 1 | +| `database.internal.extrInitContainers` | Extra init containers to be run before the database's container starts. | `[]` | +| `database.external.host` | The hostname of external database | `192.168.0.1` | +| `database.external.port` | The port of external database | `5432` | +| `database.external.username` | The username of external database | `user` | +| `database.external.password` | The password of external database | `password` | +| `database.external.coreDatabase` | The database used by core service | `registry` | +| `database.external.existingSecret` | An existing password containing the database password. the key must be `password`. | `""` | +| `database.external.sslmode` | Connection method of external database (require, verify-full, verify-ca, disable) | `disable` | +| `database.maxIdleConns` | The maximum number of connections in the idle connection pool. If it <=0, no idle connections are retained. | `50` | +| `database.maxOpenConns` | The maximum number of open connections to the database. If it <= 0, then there is no limit on the number of open connections. | `100` | +| `database.podAnnotations` | Annotations to add to the database pod | `{}` | +| **Redis** | | | +| `redis.type` | If external redis is used, set it to `external` | `internal` | +| `redis.internal.image.repository` | Repository for redis image | `goharbor/redis-photon` | +| `redis.internal.image.tag` | Tag for redis image | `dev` | +| `redis.internal.resources` | The [resources] to allocate for container | undefined | +| `redis.internal.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `redis.internal.nodeSelector` | Node labels for pod assignment | `{}` | +| `redis.internal.tolerations` | Tolerations for pod assignment | `[]` | +| `redis.internal.affinity` | Node/Pod affinities | `{}` | +| `redis.internal.priorityClassName` | The priority class to run the pod as | | +| `redis.internal.jobserviceDatabaseIndex` | The database index for jobservice | `1` | +| `redis.internal.registryDatabaseIndex` | The database index for registry | `2` | +| `redis.internal.trivyAdapterIndex` | The database index for trivy adapter | `5` | +| `redis.internal.harborDatabaseIndex` | The database index for harbor miscellaneous business logic | `0` | +| `redis.internal.cacheLayerDatabaseIndex` | The database index for harbor cache layer | `0` | +| `redis.internal.initContainers` | Init containers to be run before the redis's container starts. | `[]` | +| `redis.external.addr` | The addr of external Redis: :. When using sentinel, it should be :,:,: | `192.168.0.2:6379` | +| `redis.external.sentinelMasterSet` | The name of the set of Redis instances to monitor | | +| `redis.external.coreDatabaseIndex` | The database index for core | `0` | +| `redis.external.jobserviceDatabaseIndex` | The database index for jobservice | `1` | +| `redis.external.registryDatabaseIndex` | The database index for registry | `2` | +| `redis.external.trivyAdapterIndex` | The database index for trivy adapter | `5` | +| `redis.external.harborDatabaseIndex` | The database index for harbor miscellaneous business logic | `0` | +| `redis.external.cacheLayerDatabaseIndex` | The database index for harbor cache layer | `0` | +| `redis.external.username` | The username of external Redis | | +| `redis.external.password` | The password of external Redis | | +| `redis.external.existingSecret` | Use an existing secret to connect to redis. The key must be `REDIS_PASSWORD`. | `""` | +| `redis.podAnnotations` | Annotations to add to the redis pod | `{}` | +| **Exporter** | | | +| `exporter.replicas` | The replica count | `1` | +| `exporter.revisionHistoryLimit` | The revision history limit | `10` | +| `exporter.podAnnotations` | Annotations to add to the exporter pod | `{}` | +| `exporter.image.repository` | Repository for redis image | `goharbor/harbor-exporter` | +| `exporter.image.tag` | Tag for exporter image | `dev` | +| `exporter.nodeSelector` | Node labels for pod assignment | `{}` | +| `exporter.tolerations` | Tolerations for pod assignment | `[]` | +| `exporter.affinity` | Node/Pod affinities | `{}` | +| `exporter.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `exporter.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `exporter.cacheDuration` | the cache duration for information that exporter collected from Harbor | `30` | +| `exporter.cacheCleanInterval` | cache clean interval for information that exporter collected from Harbor | `14400` | +| `exporter.priorityClassName` | The priority class to run the pod as | | +| **Metrics** | | | +| `metrics.enabled` | if enable harbor metrics | `false` | +| `metrics.core.path` | the url path for core metrics | `/metrics` | +| `metrics.core.port` | the port for core metrics | `8001` | +| `metrics.registry.path` | the url path for registry metrics | `/metrics` | +| `metrics.registry.port` | the port for registry metrics | `8001` | +| `metrics.exporter.path` | the url path for exporter metrics | `/metrics` | +| `metrics.exporter.port` | the port for exporter metrics | `8001` | +| `metrics.serviceMonitor.enabled` | create prometheus serviceMonitor. Requires prometheus CRD's | `false` | +| `metrics.serviceMonitor.additionalLabels` | additional labels to upsert to the manifest | `""` | +| `metrics.serviceMonitor.interval` | scrape period for harbor metrics | `""` | +| `metrics.serviceMonitor.metricRelabelings` | metrics relabel to add/mod/del before ingestion | `[]` | +| `metrics.serviceMonitor.relabelings` | relabels to add/mod/del to sample before scrape | `[]` | +| **Trace** | | | +| `trace.enabled` | Enable tracing or not | `false` | +| `trace.provider` | The tracing provider: `jaeger` or `otel`. `jaeger` should be 1.26+ | `jaeger` | +| `trace.sample_rate` | Set `sample_rate` to 1 if you want sampling 100% of trace data; set 0.5 if you want sampling 50% of trace data, and so forth | `1` | +| `trace.namespace` | Namespace used to differentiate different harbor services | | +| `trace.attributes` | `attributes` is a key value dict contains user defined attributes used to initialize trace provider | | +| `trace.jaeger.endpoint` | The endpoint of jaeger | `http://hostname:14268/api/traces` | +| `trace.jaeger.username` | The username of jaeger | | +| `trace.jaeger.password` | The password of jaeger | | +| `trace.jaeger.agent_host` | The agent host of jaeger | | +| `trace.jaeger.agent_port` | The agent port of jaeger | `6831` | +| `trace.otel.endpoint` | The endpoint of otel | `hostname:4318` | +| `trace.otel.url_path` | The URL path of otel | `/v1/traces` | +| `trace.otel.compression` | Whether enable compression or not for otel | `false` | +| `trace.otel.insecure` | Whether establish insecure connection or not for otel | `true` | +| `trace.otel.timeout` | The timeout in seconds of otel | `10` | +| **Cache** | | | +| `cache.enabled` | Enable cache layer or not | `false` | +| `cache.expireHours` | The expire hours of cache layer | `24` | +| Parameter | Description | Default | +|----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------| +| **Expose** | | | +| `expose.type` | How to expose the service: `ingress`, `clusterIP`, `nodePort` or `loadBalancer`, other values will be ignored and the creation of service will be skipped. | `ingress` | +| `expose.tls.enabled` | Enable TLS or not. Delete the `ssl-redirect` annotations in `expose.ingress.annotations` when TLS is disabled and `expose.type` is `ingress`. Note: if the `expose.type` is `ingress` and TLS is disabled, the port must be included in the command when pulling/pushing images. Refer to https://github.com/goharbor/harbor/issues/5291 for details. | `true` | +| `expose.tls.certSource` | The source of the TLS certificate. Set as `auto`, `secret` or `none` and fill the information in the corresponding section: 1) auto: generate the TLS certificate automatically 2) secret: read the TLS certificate from the specified secret. The TLS certificate can be generated manually or by cert manager 3) none: configure no TLS certificate for the ingress. If the default TLS certificate is configured in the ingress controller, choose this option | `auto` | +| `expose.tls.auto.commonName` | The common name used to generate the certificate, it's necessary when the type isn't `ingress` | | +| `expose.tls.secret.secretName` | The name of secret which contains keys named: `tls.crt` - the certificate; `tls.key` - the private key | | +| `expose.ingress.hosts.core` | The host of Harbor core service in ingress rule | `core.harbor.domain` | +| `expose.ingress.controller` | The ingress controller type. Currently supports `default`, `gce`, `alb`, `f5-bigip` and `ncp` | `default` | +| `expose.ingress.kubeVersionOverride` | Allows the ability to override the kubernetes version used while templating the ingress | | +| `expose.ingress.className` | Specify the `ingressClassName` used to implement the Ingress (Kubernetes 1.18+) | | +| `expose.ingress.annotations` | The annotations used commonly for ingresses | | +| `expose.ingress.labels` | The labels specific to ingress | {} | +| `expose.clusterIP.name` | The name of ClusterIP service | `harbor` | +| `expose.clusterIP.annotations` | The annotations attached to the ClusterIP service | {} | +| `expose.clusterIP.ports.httpPort` | The service port Harbor listens on when serving HTTP | `80` | +| `expose.clusterIP.ports.httpsPort` | The service port Harbor listens on when serving HTTPS | `443` | +| `expose.clusterIP.annotations` | The annotations used commonly for clusterIP | | +| `expose.clusterIP.labels` | The labels specific to clusterIP | {} | +| `expose.nodePort.name` | The name of NodePort service | `harbor` | +| `expose.nodePort.ports.http.port` | The service port Harbor listens on when serving HTTP | `80` | +| `expose.nodePort.ports.http.nodePort` | The node port Harbor listens on when serving HTTP | `30002` | +| `expose.nodePort.ports.https.port` | The service port Harbor listens on when serving HTTPS | `443` | +| `expose.nodePort.ports.https.nodePort` | The node port Harbor listens on when serving HTTPS | `30003` | +| `expose.nodePort.annotations` | The annotations used commonly for nodePort | | +| `expose.nodePort.labels` | The labels specific to nodePort | {} | +| `expose.loadBalancer.name` | The name of service | `harbor` | +| `expose.loadBalancer.IP` | The IP of the loadBalancer. It only works when loadBalancer supports assigning IP | `""` | +| `expose.loadBalancer.ports.httpPort` | The service port Harbor listens on when serving HTTP | `80` | +| `expose.loadBalancer.ports.httpsPort` | The service port Harbor listens on when serving HTTPS | `30002` | +| `expose.loadBalancer.annotations` | The annotations attached to the loadBalancer service | {} | +| `expose.loadBalancer.labels` | The labels specific to loadBalancer | {} | +| `expose.loadBalancer.sourceRanges` | List of IP address ranges to assign to loadBalancerSourceRanges | [] | +| **Internal TLS** | | | +| `internalTLS.enabled` | Enable TLS for the components (core, jobservice, portal, registry, trivy) | `false` | +| `internalTLS.strong_ssl_ciphers` | Enable strong ssl ciphers for nginx and portal | `false` | +| `internalTLS.certSource` | Method to provide TLS for the components, options are `auto`, `manual`, `secret`. | `auto` | +| `internalTLS.trustCa` | The content of trust CA, only available when `certSource` is `manual`. **Note**: all the internal certificates of the components must be issued by this CA | | +| `internalTLS.core.secretName` | The secret name for core component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.core.crt` | Content of core's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.core.key` | Content of core's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.jobservice.secretName` | The secret name for jobservice component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.jobservice.crt` | Content of jobservice's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.jobservice.key` | Content of jobservice's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.registry.secretName` | The secret name for registry component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.registry.crt` | Content of registry's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.registry.key` | Content of registry's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.portal.secretName` | The secret name for portal component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.portal.crt` | Content of portal's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.portal.key` | Content of portal's TLS key file, only available when `certSource` is `manual` | | +| `internalTLS.trivy.secretName` | The secret name for trivy component, only available when `certSource` is `secret`. The secret must contain keys named: `ca.crt` - the CA certificate which is used to issue internal key and crt pair for components and all Harbor components must be issued by the same CA, `tls.crt` - the content of the TLS cert file, `tls.key` - the content of the TLS key file. | | +| `internalTLS.trivy.crt` | Content of trivy's TLS cert file, only available when `certSource` is `manual` | | +| `internalTLS.trivy.key` | Content of trivy's TLS key file, only available when `certSource` is `manual` | | +| **IPFamily** | | | +| `ipFamily.ipv4.enabled` | if cluster is ipv4 enabled, all ipv4 related configs will set correspondingly, but currently it only affects the nginx related components | `true` | +| `ipFamily.ipv6.enabled` | if cluster is ipv6 enabled, all ipv6 related configs will set correspondingly, but currently it only affects the nginx related components | `true` | +| **Persistence** | | | +| `persistence.enabled` | Enable the data persistence or not | `true` | +| `persistence.resourcePolicy` | Setting it to `keep` to avoid removing PVCs during a helm delete operation. Leaving it empty will delete PVCs after the chart deleted. Does not affect PVCs created for internal database and redis components. | `keep` | +| `persistence.persistentVolumeClaim.registry.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components | | +| `persistence.persistentVolumeClaim.registry.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning | | +| `persistence.persistentVolumeClaim.registry.subPath` | The sub path used in the volume | | +| `persistence.persistentVolumeClaim.registry.accessMode` | The access mode of the volume | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.registry.size` | The size of the volume | `5Gi` | +| `persistence.persistentVolumeClaim.registry.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.subPath` | The sub path used in the volume | | +| `persistence.persistentVolumeClaim.jobservice.jobLog.accessMode` | The access mode of the volume | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.jobservice.jobLog.size` | The size of the volume | `1Gi` | +| `persistence.persistentVolumeClaim.jobservice.jobLog.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.database.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. If external database is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.database.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning. If external database is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.database.subPath` | The sub path used in the volume. If external database is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.database.accessMode` | The access mode of the volume. If external database is used, the setting will be ignored | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.database.size` | The size of the volume. If external database is used, the setting will be ignored | `1Gi` | +| `persistence.persistentVolumeClaim.database.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.redis.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components. If external Redis is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.redis.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning. If external Redis is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.redis.subPath` | The sub path used in the volume. If external Redis is used, the setting will be ignored | | +| `persistence.persistentVolumeClaim.redis.accessMode` | The access mode of the volume. If external Redis is used, the setting will be ignored | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.redis.size` | The size of the volume. If external Redis is used, the setting will be ignored | `1Gi` | +| `persistence.persistentVolumeClaim.redis.annotations` | The annotations of the volume | | +| `persistence.persistentVolumeClaim.trivy.existingClaim` | Use the existing PVC which must be created manually before bound, and specify the `subPath` if the PVC is shared with other components | | +| `persistence.persistentVolumeClaim.trivy.storageClass` | Specify the `storageClass` used to provision the volume. Or the default StorageClass will be used (the default). Set it to `-` to disable dynamic provisioning | | +| `persistence.persistentVolumeClaim.trivy.subPath` | The sub path used in the volume | | +| `persistence.persistentVolumeClaim.trivy.accessMode` | The access mode of the volume | `ReadWriteOnce` | +| `persistence.persistentVolumeClaim.trivy.size` | The size of the volume | `1Gi` | +| `persistence.persistentVolumeClaim.trivy.annotations` | The annotations of the volume | | +| `persistence.imageChartStorage.disableredirect` | The configuration for managing redirects from content backends. For backends which not supported it (such as using minio for `s3` storage type), please set it to `true` to disable redirects. Refer to the [guide](https://github.com/docker/distribution/blob/master/docs/configuration.md#redirect) for more details | `false` | +| `persistence.imageChartStorage.caBundleSecretName` | Specify the `caBundleSecretName` if the storage service uses a self-signed certificate. The secret must contain keys named `ca.crt` which will be injected into the trust store of registry's and containers. | | +| `persistence.imageChartStorage.type` | The type of storage for images and charts: `filesystem`, `azure`, `gcs`, `s3`, `swift` or `oss`. The type must be `filesystem` if you want to use persistent volumes for registry. Refer to the [guide](https://github.com/docker/distribution/blob/master/docs/configuration.md#storage) for more details | `filesystem` | +| `persistence.imageChartStorage.gcs.existingSecret` | An existing secret containing the gcs service account json key. The key must be gcs-key.json. | `""` | +| `persistence.imageChartStorage.gcs.useWorkloadIdentity` | A boolean to allow the use of workloadidentity in a GKE cluster. To use it, create a kubernetes service account and set the name in the key `serviceAccountName` of each component, then allow automounting the service account. | `false` | +| **General** | | | +| `externalURL` | The external URL for Harbor core service | `https://core.harbor.domain` | +| `caBundleSecretName` | The custom CA bundle secret name, the secret must contain key named "ca.crt" which will be injected into the trust store for core, jobservice, registry, trivy components. | | +| `uaaSecretName` | If using external UAA auth which has a self signed cert, you can provide a pre-created secret containing it under the key `ca.crt`. | | +| `imagePullPolicy` | The image pull policy | | +| `imagePullSecrets` | The imagePullSecrets names for all deployments | | +| `updateStrategy.type` | The update strategy for deployments with persistent volumes(jobservice, registry): `RollingUpdate` or `Recreate`. Set it as `Recreate` when `RWM` for volumes isn't supported | `RollingUpdate` | +| `logLevel` | The log level: `debug`, `info`, `warning`, `error` or `fatal` | `info` | +| `harborAdminPassword` | The initial password of Harbor admin. Change it from portal after launching Harbor | `Harbor12345` | +| `existingSecretAdminPassword` | The name of secret where admin password can be found. | | +| `existingSecretAdminPasswordKey` | The name of the key in the secret where to find harbor admin password Harbor | `HARBOR_ADMIN_PASSWORD` | +| `caSecretName` | The name of the secret which contains key named `ca.crt`. Setting this enables the download link on portal to download the CA certificate when the certificate isn't generated automatically | | +| `secretKey` | The key used for encryption. Must be a string of 16 chars | `not-a-secure-key` | +| `existingSecretSecretKey` | An existing secret containing the encoding secretKey | `""` | +| `proxy.httpProxy` | The URL of the HTTP proxy server | | +| `proxy.httpsProxy` | The URL of the HTTPS proxy server | | +| `proxy.noProxy` | The URLs that the proxy settings not apply to | 127.0.0.1,localhost,.local,.internal | +| `proxy.components` | The component list that the proxy settings apply to | core, jobservice, trivy | +| `enableMigrateHelmHook` | Run the migration job via helm hook, if it is true, the database migration will be separated from harbor-core, run with a preupgrade job migration-job | `false` | +| **Nginx** (if service exposed via `ingress`, Nginx will not be used) | | | +| `nginx.image.repository` | Image repository | `goharbor/nginx-photon` | +| `nginx.image.tag` | Image tag | `dev` | +| `nginx.replicas` | The replica count | `1` | +| `nginx.revisionHistoryLimit` | The revision history limit | `10` | +| `nginx.resources` | The [resources] to allocate for container | undefined | +| `nginx.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `nginx.nodeSelector` | Node labels for pod assignment | `{}` | +| `nginx.tolerations` | Tolerations for pod assignment | `[]` | +| `nginx.affinity` | Node/Pod affinities | `{}` | +| `nginx.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `nginx.podAnnotations` | Annotations to add to the nginx pod | `{}` | +| `nginx.priorityClassName` | The priority class to run the pod as | | +| **Portal** | | | +| `portal.image.repository` | Repository for portal image | `goharbor/harbor-portal` | +| `portal.image.tag` | Tag for portal image | `dev` | +| `portal.replicas` | The replica count | `1` | +| `portal.revisionHistoryLimit` | The revision history limit | `10` | +| `portal.resources` | The [resources] to allocate for container | undefined | +| `portal.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `portal.nodeSelector` | Node labels for pod assignment | `{}` | +| `portal.tolerations` | Tolerations for pod assignment | `[]` | +| `portal.affinity` | Node/Pod affinities | `{}` | +| `portal.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `portal.podAnnotations` | Annotations to add to the portal pod | `{}` | +| `portal.serviceAnnotations` | Annotations to add to the portal service | `{}` | +| `portal.priorityClassName` | The priority class to run the pod as | | +| `portal.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Core** | | | +| `core.image.repository` | Repository for Harbor core image | `goharbor/harbor-core` | +| `core.image.tag` | Tag for Harbor core image | `dev` | +| `core.replicas` | The replica count | `1` | +| `core.revisionHistoryLimit` | The revision history limit | `10` | +| `core.startupProbe.initialDelaySeconds` | The initial delay in seconds for the startup probe | `10` | +| `core.resources` | The [resources] to allocate for container | undefined | +| `core.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `core.nodeSelector` | Node labels for pod assignment | `{}` | +| `core.tolerations` | Tolerations for pod assignment | `[]` | +| `core.affinity` | Node/Pod affinities | `{}` | +| `core.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `core.podAnnotations` | Annotations to add to the core pod | `{}` | +| `core.serviceAnnotations` | Annotations to add to the core service | `{}` | +| `core.configureUserSettings` | A JSON string to set in the environment variable `CONFIG_OVERWRITE_JSON` to configure user settings. See the [official docs](https://goharbor.io/docs/latest/install-config/configure-user-settings-cli/#configure-users-settings-using-an-environment-variable). | | +| `core.quotaUpdateProvider` | The provider for updating project quota(usage), there are 2 options, `redis` or `db`. You can set it to be implemented by `redis` which can improve the performance of high concurrent pushing to the same project, and reduce database connection spikes and occupies. Using redis will bring up some delay for quota usage update for display, so only suggest switch provider to redis if you ran into the db connections spike around the scenario of high concurrent pushing to same project, no improvement for other scenes. | `db` | +| `core.secret` | Secret is used when core server communicates with other components. If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | | +| `core.secretName` | Fill the name of a kubernetes secret if you want to use your own TLS certificate and private key for token encryption/decryption. The secret must contain keys named: `tls.crt` - the certificate and `tls.key` - the private key. The default key pair will be used if it isn't set | | +| `core.tokenKey` | PEM-formatted RSA private key used to sign service tokens. Only used if `core.secretName` is unset. If set, `core.tokenCert` MUST also be set. | | +| `core.tokenCert` | PEM-formatted certificate signed by `core.tokenKey` used to validate service tokens. Only used if `core.secretName` is unset. If set, `core.tokenKey` MUST also be set. | | +| `core.xsrfKey` | The XSRF key. Will be generated automatically if it isn't specified | | +| `core.priorityClassName` | The priority class to run the pod as | | +| `core.artifactPullAsyncFlushDuration` | The time duration for async update artifact pull_time and repository pull_count | | +| `core.gdpr.deleteUser` | Enable GDPR compliant user delete | `false` | +| `core.gdpr.auditLogsCompliant` | Enable GDPR compliant for audit logs by changing username to its CRC32 value if that user was deleted from the system | `false` | +| `core.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Jobservice** | | | +| `jobservice.image.repository` | Repository for jobservice image | `goharbor/harbor-jobservice` | +| `jobservice.image.tag` | Tag for jobservice image | `dev` | +| `jobservice.replicas` | The replica count | `1` | +| `jobservice.revisionHistoryLimit` | The revision history limit | `10` | +| `jobservice.maxJobWorkers` | The max job workers | `10` | +| `jobservice.jobLoggers` | The loggers for jobs: `file`, `database` or `stdout` | `[file]` | +| `jobservice.loggerSweeperDuration` | The jobLogger sweeper duration in days (ignored if `jobLoggers` is set to `stdout`) | `14` | +| `jobservice.notification.webhook_job_max_retry` | The maximum retry of webhook sending notifications | `3` | +| `jobservice.notification.webhook_job_http_client_timeout` | The http client timeout value of webhook sending notifications | `3` | +| `jobservice.reaper.max_update_hours` | the max time to wait for a task to finish, if unfinished after max_update_hours, the task will be mark as error, but the task will continue to run | `24` | +| `jobservice.reaper.max_dangling_hours` | the max time for execution in running state without new task created | `168` | +| `jobservice.resources` | The [resources] to allocate for container | undefined | +| `jobservice.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `jobservice.nodeSelector` | Node labels for pod assignment | `{}` | +| `jobservice.tolerations` | Tolerations for pod assignment | `[]` | +| `jobservice.affinity` | Node/Pod affinities | `{}` | +| `jobservice.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `jobservice.podAnnotations` | Annotations to add to the jobservice pod | `{}` | +| `jobservice.priorityClassName` | The priority class to run the pod as | | +| `jobservice.secret` | Secret is used when job service communicates with other components. If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | | +| `jobservice.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Registry** | | | +| `registry.registry.image.repository` | Repository for registry image | `goharbor/registry-photon` | +| `registry.registry.image.tag` | Tag for registry image | `dev` | +| `registry.registry.resources` | The [resources] to allocate for container | undefined | +| `registry.controller.image.repository` | Repository for registry controller image | `goharbor/harbor-registryctl` | +| `registry.controller.image.tag` | Tag for registry controller image | `dev` | +| `registry.controller.resources` | The [resources] to allocate for container | undefined | +| `registry.replicas` | The replica count | `1` | +| `registry.revisionHistoryLimit` | The revision history limit | `10` | +| `registry.nodeSelector` | Node labels for pod assignment | `{}` | +| `registry.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `registry.tolerations` | Tolerations for pod assignment | `[]` | +| `registry.affinity` | Node/Pod affinities | `{}` | +| `registry.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `registry.middleware` | Middleware is used to add support for a CDN between backend storage and `docker pull` recipient. See [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#middleware). | | +| `registry.podAnnotations` | Annotations to add to the registry pod | `{}` | +| `registry.priorityClassName` | The priority class to run the pod as | | +| `registry.secret` | Secret is used to secure the upload state from client and registry storage backend. See [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#http). If a secret key is not specified, Helm will generate one. Must be a string of 16 chars. | | +| `registry.credentials.username` | The username that harbor core uses internally to access the registry instance. Together with the `registry.credentials.password`, a htpasswd is created. This is an alternative to providing `registry.credentials.htpasswdString`. For more details see [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#htpasswd). | `harbor_registry_user` | +| `registry.credentials.password` | The password that harbor core uses internally to access the registry instance. Together with the `registry.credentials.username`, a htpasswd is created. This is an alternative to providing `registry.credentials.htpasswdString`. For more details see [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#htpasswd). It is suggested you update this value before installation. | `harbor_registry_password` | +| `registry.credentials.existingSecret` | An existing secret containing the password for accessing the registry instance, which is hosted by htpasswd auth mode. More details see [official docs](https://github.com/docker/distribution/blob/master/docs/configuration.md#htpasswd). The key must be `REGISTRY_PASSWD` | `""` | +| `registry.credentials.htpasswdString` | Login and password in htpasswd string format. Excludes `registry.credentials.username` and `registry.credentials.password`. May come in handy when integrating with tools like argocd or flux. This allows the same line to be generated each time the template is rendered, instead of the `htpasswd` function from helm, which generates different lines each time because of the salt. | undefined | +| `registry.relativeurls` | If true, the registry returns relative URLs in Location headers. The client is responsible for resolving the correct URL. Needed if harbor is behind a reverse proxy | `false` | +| `registry.upload_purging.enabled` | If true, enable purge _upload directories | `true` | +| `registry.upload_purging.age` | Remove files in _upload directories which exist for a period of time, default is one week. | `168h` | +| `registry.upload_purging.interval` | The interval of the purge operations | `24h` | +| `registry.upload_purging.dryrun` | If true, enable dryrun for purging _upload | `false` | +| `registry.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **[Trivy][trivy]** | | | +| `trivy.enabled` | The flag to enable Trivy scanner | `true` | +| `trivy.image.repository` | Repository for Trivy adapter image | `goharbor/trivy-adapter-photon` | +| `trivy.image.tag` | Tag for Trivy adapter image | `dev` | +| `trivy.resources` | The [resources] to allocate for Trivy adapter container | | +| `trivy.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `trivy.replicas` | The number of Pod replicas | `1` | +| `trivy.debugMode` | The flag to enable Trivy debug mode | `false` | +| `trivy.vulnType` | Comma-separated list of vulnerability types. Possible values `os` and `library`. | `os,library` | +| `trivy.severity` | Comma-separated list of severities to be checked | `UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL` | +| `trivy.ignoreUnfixed` | The flag to display only fixed vulnerabilities | `false` | +| `trivy.insecure` | The flag to skip verifying registry certificate | `false` | +| `trivy.skipUpdate` | The flag to disable [Trivy DB][trivy-db] downloads from GitHub | `false` | +| `trivy.skipJavaDBUpdate` | If the flag is enabled you have to manually download the `trivy-java.db` file [Trivy Java DB][trivy-java-db] and mount it in the `/home/scanner/.cache/trivy/java-db/trivy-java.db` path | `false` | +| `trivy.dbRepository` | OCI repository(ies) to retrieve the trivy vulnerability database in order of priority | `mirror.gcr.io/aquasec/trivy-db,ghcr.io/aquasecurity/trivy-db` | +| `trivy.javaDBRepository` | OCI repository(ies) to retrieve the Java trivy vulnerability database in order of priority | `mirror.gcr.io/aquasec/trivy-java-db,ghcr.io/aquasecurity/trivy-java-db` | +| `trivy.offlineScan` | The flag prevents Trivy from sending API requests to identify dependencies. | `false` | +| `trivy.securityCheck` | Comma-separated list of what security issues to detect. | `vuln` | +| `trivy.timeout` | The duration to wait for scan completion | `5m0s` | +| `trivy.gitHubToken` | The GitHub access token to download [Trivy DB][trivy-db] (see [GitHub rate limiting][trivy-rate-limiting]) | | +| `trivy.priorityClassName` | The priority class to run the pod as | | +| `trivy.topologySpreadConstraints` | The priority class to run the pod as | | +| `trivy.initContainers` | Init containers to be run before the controller's container starts. | `[]` | +| **Database** | | | +| `database.type` | If external database is used, set it to `external` | `internal` | +| `database.internal.image.repository` | Repository for database image | `goharbor/harbor-db` | +| `database.internal.image.tag` | Tag for database image | `dev` | +| `database.internal.password` | The password for database | `changeit` | +| `database.internal.shmSizeLimit` | The limit for the size of shared memory for internal PostgreSQL, conventionally it's around 50% of the memory limit of the container | `512Mi` | +| `database.internal.resources` | The [resources] to allocate for container | undefined | +| `database.internal.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `database.internal.initContainer.migrator.resources` | The [resources] to allocate for the database migrator initContainer | undefined | +| `database.internal.initContainer.permissions.resources` | The [resources] to allocate for the database permissions initContainer | undefined | +| `database.internal.nodeSelector` | Node labels for pod assignment | `{}` | +| `database.internal.tolerations` | Tolerations for pod assignment | `[]` | +| `database.internal.affinity` | Node/Pod affinities | `{}` | +| `database.internal.priorityClassName` | The priority class to run the pod as | | +| `database.internal.livenessProbe.timeoutSeconds` | The timeout used in liveness probe; 1 to 5 seconds | 1 | +| `database.internal.readinessProbe.timeoutSeconds` | The timeout used in readiness probe; 1 to 5 seconds | 1 | +| `database.internal.extrInitContainers` | Extra init containers to be run before the database's container starts. | `[]` | +| `database.external.host` | The hostname of external database | `192.168.0.1` | +| `database.external.port` | The port of external database | `5432` | +| `database.external.username` | The username of external database | `user` | +| `database.external.password` | The password of external database | `password` | +| `database.external.coreDatabase` | The database used by core service | `registry` | +| `database.external.existingSecret` | An existing password containing the database password. the key must be `password`. | `""` | +| `database.external.sslmode` | Connection method of external database (require, verify-full, verify-ca, disable) | `disable` | +| `database.maxIdleConns` | The maximum number of connections in the idle connection pool. If it <=0, no idle connections are retained. | `50` | +| `database.maxOpenConns` | The maximum number of open connections to the database. If it <= 0, then there is no limit on the number of open connections. | `100` | +| `database.podAnnotations` | Annotations to add to the database pod | `{}` | +| **Redis** | | | +| `redis.type` | If external redis is used, set it to `external` | `internal` | +| `redis.internal.image.repository` | Repository for redis image | `goharbor/redis-photon` | +| `redis.internal.image.tag` | Tag for redis image | `dev` | +| `redis.internal.resources` | The [resources] to allocate for container | undefined | +| `redis.internal.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `redis.internal.nodeSelector` | Node labels for pod assignment | `{}` | +| `redis.internal.tolerations` | Tolerations for pod assignment | `[]` | +| `redis.internal.affinity` | Node/Pod affinities | `{}` | +| `redis.internal.priorityClassName` | The priority class to run the pod as | | +| `redis.internal.jobserviceDatabaseIndex` | The database index for jobservice | `1` | +| `redis.internal.registryDatabaseIndex` | The database index for registry | `2` | +| `redis.internal.trivyAdapterIndex` | The database index for trivy adapter | `5` | +| `redis.internal.harborDatabaseIndex` | The database index for harbor miscellaneous business logic | `0` | +| `redis.internal.cacheLayerDatabaseIndex` | The database index for harbor cache layer | `0` | +| `redis.internal.initContainers` | Init containers to be run before the redis's container starts. | `[]` | +| `redis.external.addr` | The addr of external Redis: :. When using sentinel, it should be :,:,: | `192.168.0.2:6379` | +| `redis.external.sentinelMasterSet` | The name of the set of Redis instances to monitor | | +| `redis.external.coreDatabaseIndex` | The database index for core | `0` | +| `redis.external.jobserviceDatabaseIndex` | The database index for jobservice | `1` | +| `redis.external.registryDatabaseIndex` | The database index for registry | `2` | +| `redis.external.trivyAdapterIndex` | The database index for trivy adapter | `5` | +| `redis.external.harborDatabaseIndex` | The database index for harbor miscellaneous business logic | `0` | +| `redis.external.cacheLayerDatabaseIndex` | The database index for harbor cache layer | `0` | +| `redis.external.username` | The username of external Redis | | +| `redis.external.password` | The password of external Redis | | +| `redis.external.existingSecret` | Use an existing secret to connect to redis. The key must be `REDIS_PASSWORD`. | `""` | +| `redis.podAnnotations` | Annotations to add to the redis pod | `{}` | +| **Exporter** | | | +| `exporter.replicas` | The replica count | `1` | +| `exporter.revisionHistoryLimit` | The revision history limit | `10` | +| `exporter.podAnnotations` | Annotations to add to the exporter pod | `{}` | +| `exporter.image.repository` | Repository for redis image | `goharbor/harbor-exporter` | +| `exporter.image.tag` | Tag for exporter image | `dev` | +| `exporter.nodeSelector` | Node labels for pod assignment | `{}` | +| `exporter.tolerations` | Tolerations for pod assignment | `[]` | +| `exporter.affinity` | Node/Pod affinities | `{}` | +| `exporter.topologySpreadConstraints` | Constraints that define how Pods are spread across failure-domains like regions or availability zones | `[]` | +| `exporter.automountServiceAccountToken` | Mount serviceAccountToken? | `false` | +| `exporter.cacheDuration` | the cache duration for information that exporter collected from Harbor | `30` | +| `exporter.cacheCleanInterval` | cache clean interval for information that exporter collected from Harbor | `14400` | +| `exporter.priorityClassName` | The priority class to run the pod as | | +| **Metrics** | | | +| `metrics.enabled` | if enable harbor metrics | `false` | +| `metrics.core.path` | the url path for core metrics | `/metrics` | +| `metrics.core.port` | the port for core metrics | `8001` | +| `metrics.registry.path` | the url path for registry metrics | `/metrics` | +| `metrics.registry.port` | the port for registry metrics | `8001` | +| `metrics.exporter.path` | the url path for exporter metrics | `/metrics` | +| `metrics.exporter.port` | the port for exporter metrics | `8001` | +| `metrics.serviceMonitor.enabled` | create prometheus serviceMonitor. Requires prometheus CRD's | `false` | +| `metrics.serviceMonitor.additionalLabels` | additional labels to upsert to the manifest | `""` | +| `metrics.serviceMonitor.interval` | scrape period for harbor metrics | `""` | +| `metrics.serviceMonitor.metricRelabelings` | metrics relabel to add/mod/del before ingestion | `[]` | +| `metrics.serviceMonitor.relabelings` | relabels to add/mod/del to sample before scrape | `[]` | +| **Trace** | | | +| `trace.enabled` | Enable tracing or not | `false` | +| `trace.provider` | The tracing provider: `jaeger` or `otel`. `jaeger` should be 1.26+ | `jaeger` | +| `trace.sample_rate` | Set `sample_rate` to 1 if you want sampling 100% of trace data; set 0.5 if you want sampling 50% of trace data, and so forth | `1` | +| `trace.namespace` | Namespace used to differentiate different harbor services | | +| `trace.attributes` | `attributes` is a key value dict contains user defined attributes used to initialize trace provider | | +| `trace.jaeger.endpoint` | The endpoint of jaeger | `http://hostname:14268/api/traces` | +| `trace.jaeger.username` | The username of jaeger | | +| `trace.jaeger.password` | The password of jaeger | | +| `trace.jaeger.agent_host` | The agent host of jaeger | | +| `trace.jaeger.agent_port` | The agent port of jaeger | `6831` | +| `trace.otel.endpoint` | The endpoint of otel | `hostname:4318` | +| `trace.otel.url_path` | The URL path of otel | `/v1/traces` | +| `trace.otel.compression` | Whether enable compression or not for otel | `false` | +| `trace.otel.insecure` | Whether establish insecure connection or not for otel | `true` | +| `trace.otel.timeout` | The timeout in seconds of otel | `10` | +| **Cache** | | | +| `cache.enabled` | Enable cache layer or not | `false` | +| `cache.expireHours` | The expire hours of cache layer | `24` | + +[resources]: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ +[trivy]: https://github.com/aquasecurity/trivy +[trivy-db]: https://github.com/aquasecurity/trivy-db +[trivy-java-db]: https://github.com/aquasecurity/trivy-java-db +[trivy-rate-limiting]: https://github.com/aquasecurity/trivy#github-rate-limiting diff --git a/packages/system/harbor/charts/harbor/templates/NOTES.txt b/packages/system/harbor/charts/harbor/templates/NOTES.txt new file mode 100644 index 00000000..0980c08a --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/NOTES.txt @@ -0,0 +1,3 @@ +Please wait for several minutes for Harbor deployment to complete. +Then you should be able to visit the Harbor portal at {{ .Values.externalURL }} +For more details, please visit https://github.com/goharbor/harbor diff --git a/packages/system/harbor/charts/harbor/templates/_helpers.tpl b/packages/system/harbor/charts/harbor/templates/_helpers.tpl new file mode 100644 index 00000000..95643c49 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/_helpers.tpl @@ -0,0 +1,606 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "harbor.name" -}} +{{- default "harbor" .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "harbor.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default "harbor" .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* Helm required labels: legacy */}} +{{- define "harbor.legacy.labels" -}} +heritage: {{ .Release.Service }} +release: {{ .Release.Name }} +chart: {{ .Chart.Name }} +app: "{{ template "harbor.name" . }}" +{{- end -}} + +{{/* Helm required labels */}} +{{- define "harbor.labels" -}} +heritage: {{ .Release.Service }} +release: {{ .Release.Name }} +chart: {{ .Chart.Name }} +app: "{{ template "harbor.name" . }}" +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/name: {{ include "harbor.name" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/part-of: {{ include "harbor.name" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +{{- end -}} + +{{/* matchLabels */}} +{{- define "harbor.matchLabels" -}} +release: {{ .Release.Name }} +app: "{{ template "harbor.name" . }}" +{{- end -}} + +{{/* Helper for printing values from existing secrets*/}} +{{- define "harbor.secretKeyHelper" -}} + {{- if and (not (empty .data)) (hasKey .data .key) }} + {{- index .data .key | b64dec -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.autoGenCert" -}} + {{- if and .Values.expose.tls.enabled (eq .Values.expose.tls.certSource "auto") -}} + {{- printf "true" -}} + {{- else -}} + {{- printf "false" -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.autoGenCertForIngress" -}} + {{- if and (eq (include "harbor.autoGenCert" .) "true") (eq .Values.expose.type "ingress") -}} + {{- printf "true" -}} + {{- else -}} + {{- printf "false" -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.autoGenCertForNginx" -}} + {{- if and (eq (include "harbor.autoGenCert" .) "true") (ne .Values.expose.type "ingress") -}} + {{- printf "true" -}} + {{- else -}} + {{- printf "false" -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.host" -}} + {{- if eq .Values.database.type "internal" -}} + {{- template "harbor.database" . }} + {{- else -}} + {{- .Values.database.external.host -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.port" -}} + {{- if eq .Values.database.type "internal" -}} + {{- printf "%s" "5432" -}} + {{- else -}} + {{- .Values.database.external.port -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.username" -}} + {{- if eq .Values.database.type "internal" -}} + {{- printf "%s" "postgres" -}} + {{- else -}} + {{- .Values.database.external.username -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.rawPassword" -}} + {{- if eq .Values.database.type "internal" -}} + {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (include "harbor.database" .) -}} + {{- if and (not (empty $existingSecret)) (hasKey $existingSecret.data "POSTGRES_PASSWORD") -}} + {{- .Values.database.internal.password | default (index $existingSecret.data "POSTGRES_PASSWORD" | b64dec) -}} + {{- else -}} + {{- .Values.database.internal.password -}} + {{- end -}} + {{- else -}} + {{- .Values.database.external.password -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.escapedRawPassword" -}} + {{- include "harbor.database.rawPassword" . | urlquery | replace "+" "%20" -}} +{{- end -}} + +{{- define "harbor.database.encryptedPassword" -}} + {{- include "harbor.database.rawPassword" . | b64enc | quote -}} +{{- end -}} + +{{- define "harbor.database.coreDatabase" -}} + {{- if eq .Values.database.type "internal" -}} + {{- printf "%s" "registry" -}} + {{- else -}} + {{- .Values.database.external.coreDatabase -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.database.sslmode" -}} + {{- if eq .Values.database.type "internal" -}} + {{- printf "%s" "disable" -}} + {{- else -}} + {{- .Values.database.external.sslmode -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.redis.scheme" -}} + {{- with .Values.redis }} + {{- if eq .type "external" -}} + {{- if not (not .external.sentinelMasterSet) -}} + {{- ternary "rediss+sentinel" "redis+sentinel" (.external.tlsOptions.enable) }} + {{- else -}} + {{- ternary "rediss" "redis" (.external.tlsOptions.enable) }} + {{- end -}} + {{- else -}} + {{ print "redis" }} + {{- end -}} + {{- end }} +{{- end -}} + +{{- define "harbor.redis.enableTLS" -}} + {{- with .Values.redis }} + {{- ternary "true" "false" (and ( eq .type "external") (.external.tlsOptions.enable)) }} + {{- end }} +{{- end -}} + +/*host:port*/ +{{- define "harbor.redis.addr" -}} + {{- with .Values.redis }} + {{- ternary (printf "%s:6379" (include "harbor.redis" $ )) .external.addr (eq .type "internal") }} + {{- end }} +{{- end -}} + +{{- define "harbor.redis.masterSet" -}} + {{- with .Values.redis }} + {{- ternary .external.sentinelMasterSet "" (contains "+sentinel" (include "harbor.redis.scheme" $)) }} + {{- end }} +{{- end -}} + +{{- define "harbor.redis.password" -}} + {{- with .Values.redis }} + {{- ternary "" .external.password (eq .type "internal") }} + {{- end }} +{{- end -}} + + +{{- define "harbor.redis.usernamefromsecret" -}} + {{- $existingSecret := (lookup "v1" "Secret" .Release.Namespace (.Values.redis.external.existingSecret)) -}} + {{- if and (not (empty $existingSecret)) (hasKey $existingSecret.data "REDIS_USERNAME") -}} + {{- printf "%s" ($existingSecret.data.REDIS_USERNAME | b64dec | trim ) }} + {{- end -}} +{{- end -}} + +{{- define "harbor.redis.pwdfromsecret" -}} + {{- (lookup "v1" "Secret" .Release.Namespace (.Values.redis.external.existingSecret)).data.REDIS_PASSWORD | b64dec }} +{{- end -}} + +{{- define "harbor.redis.cred" -}} + {{- with .Values.redis }} + {{- if (and (eq .type "external" ) (.external.existingSecret)) }} + {{- printf "%s:%s@" (include "harbor.redis.usernamefromsecret" $) (include "harbor.redis.pwdfromsecret" $) -}} + {{- else }} + {{- ternary (printf "%s:%s@" (.external.username | urlquery) (.external.password | urlquery)) "" (and (eq .type "external" ) (not (not .external.password))) }} + {{- end }} + {{- end }} +{{- end -}} + +/*scheme://[:password@]host:port[/master_set]*/ +{{- define "harbor.redis.url" -}} + {{- with .Values.redis }} + {{- $path := ternary "" (printf "/%s" (include "harbor.redis.masterSet" $)) (not (include "harbor.redis.masterSet" $)) }} + {{- printf "%s://%s%s%s" (include "harbor.redis.scheme" $) (include "harbor.redis.cred" $) (include "harbor.redis.addr" $) $path -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index?idle_timeout_seconds=30*/ +{{- define "harbor.redis.urlForCore" -}} + {{- with .Values.redis }} + {{- $index := ternary "0" .external.coreDatabaseIndex (eq .type "internal") }} + {{- printf "%s/%s?idle_timeout_seconds=30" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index*/ +{{- define "harbor.redis.urlForJobservice" -}} + {{- with .Values.redis }} + {{- $index := ternary .internal.jobserviceDatabaseIndex .external.jobserviceDatabaseIndex (eq .type "internal") }} + {{- printf "%s/%s" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index?idle_timeout_seconds=30*/ +{{- define "harbor.redis.urlForRegistry" -}} + {{- with .Values.redis }} + {{- $index := ternary .internal.registryDatabaseIndex .external.registryDatabaseIndex (eq .type "internal") }} + {{- printf "%s/%s?idle_timeout_seconds=30" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index?idle_timeout_seconds=30*/ +{{- define "harbor.redis.urlForTrivy" -}} + {{- with .Values.redis }} + {{- $index := ternary .internal.trivyAdapterIndex .external.trivyAdapterIndex (eq .type "internal") }} + {{- printf "%s/%s?idle_timeout_seconds=30" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index?idle_timeout_seconds=30*/ +{{- define "harbor.redis.urlForHarbor" -}} + {{- with .Values.redis }} + {{- $index := ternary .internal.harborDatabaseIndex .external.harborDatabaseIndex (eq .type "internal") }} + {{- printf "%s/%s?idle_timeout_seconds=30" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +/*scheme://[:password@]addr/db_index?idle_timeout_seconds=30*/ +{{- define "harbor.redis.urlForCache" -}} + {{- with .Values.redis }} + {{- $index := ternary .internal.cacheLayerDatabaseIndex .external.cacheLayerDatabaseIndex (eq .type "internal") }} + {{- printf "%s/%s?idle_timeout_seconds=30" (include "harbor.redis.url" $) $index -}} + {{- end }} +{{- end -}} + +{{- define "harbor.redis.dbForRegistry" -}} + {{- with .Values.redis }} + {{- ternary .internal.registryDatabaseIndex .external.registryDatabaseIndex (eq .type "internal") }} + {{- end }} +{{- end -}} + +{{- define "harbor.portal" -}} + {{- printf "%s-portal" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.core" -}} + {{- printf "%s-core" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.redis" -}} + {{- printf "%s-redis" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.jobservice" -}} + {{- printf "%s-jobservice" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.registry" -}} + {{- printf "%s-registry" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.registryCtl" -}} + {{- printf "%s-registryctl" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.database" -}} + {{- printf "%s-database" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.trivy" -}} + {{- printf "%s-trivy" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.nginx" -}} + {{- printf "%s-nginx" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.exporter" -}} + {{- printf "%s-exporter" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.ingress" -}} + {{- printf "%s-ingress" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.route" -}} + {{- printf "%s-route" (include "harbor.fullname" .) -}} +{{- end -}} + +{{- define "harbor.noProxy" -}} + {{- printf "%s,%s,%s,%s,%s,%s,%s,%s" (include "harbor.core" .) (include "harbor.jobservice" .) (include "harbor.database" .) (include "harbor.registry" .) (include "harbor.portal" .) (include "harbor.trivy" .) (include "harbor.exporter" .) .Values.proxy.noProxy -}} +{{- end -}} + +{{- define "harbor.caBundleVolume" -}} +- name: ca-bundle-certs + secret: + secretName: {{ .Values.caBundleSecretName }} +{{- end -}} + +{{- define "harbor.caBundleVolumeMount" -}} +- name: ca-bundle-certs + mountPath: /harbor_cust_cert/custom-ca.crt + subPath: ca.crt +{{- end -}} + +{{/* scheme for all components because it only support http mode */}} +{{- define "harbor.component.scheme" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "https" -}} + {{- else -}} + {{- printf "http" -}} + {{- end -}} +{{- end -}} + +{{/* core component container port */}} +{{- define "harbor.core.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* core component service port */}} +{{- define "harbor.core.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "443" -}} + {{- else -}} + {{- printf "80" -}} + {{- end -}} +{{- end -}} + +{{/* jobservice component container port */}} +{{- define "harbor.jobservice.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* jobservice component service port */}} +{{- define "harbor.jobservice.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "443" -}} + {{- else -}} + {{- printf "80" -}} + {{- end -}} +{{- end -}} + +{{/* portal component container port */}} +{{- define "harbor.portal.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* portal component service port */}} +{{- define "harbor.portal.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "443" -}} + {{- else -}} + {{- printf "80" -}} + {{- end -}} +{{- end -}} + +{{/* registry component container port */}} +{{- define "harbor.registry.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "5443" -}} + {{- else -}} + {{- printf "5000" -}} + {{- end -}} +{{- end -}} + +{{/* registry component service port */}} +{{- define "harbor.registry.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "5443" -}} + {{- else -}} + {{- printf "5000" -}} + {{- end -}} +{{- end -}} + +{{/* registryctl component container port */}} +{{- define "harbor.registryctl.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* registryctl component service port */}} +{{- define "harbor.registryctl.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* trivy component container port */}} +{{- define "harbor.trivy.containerPort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* trivy component service port */}} +{{- define "harbor.trivy.servicePort" -}} + {{- if .Values.internalTLS.enabled -}} + {{- printf "8443" -}} + {{- else -}} + {{- printf "8080" -}} + {{- end -}} +{{- end -}} + +{{/* CORE_URL */}} +{{/* port is included in this url as a workaround for issue https://github.com/aquasecurity/harbor-scanner-trivy/issues/108 */}} +{{- define "harbor.coreURL" -}} + {{- printf "%s://%s:%s" (include "harbor.component.scheme" .) (include "harbor.core" .) (include "harbor.core.servicePort" .) -}} +{{- end -}} + +{{/* JOBSERVICE_URL */}} +{{- define "harbor.jobserviceURL" -}} + {{- printf "%s://%s-jobservice" (include "harbor.component.scheme" .) (include "harbor.fullname" .) -}} +{{- end -}} + +{{/* PORTAL_URL */}} +{{- define "harbor.portalURL" -}} + {{- printf "%s://%s" (include "harbor.component.scheme" .) (include "harbor.portal" .) -}} +{{- end -}} + +{{/* REGISTRY_URL */}} +{{- define "harbor.registryURL" -}} + {{- printf "%s://%s:%s" (include "harbor.component.scheme" .) (include "harbor.registry" .) (include "harbor.registry.servicePort" .) -}} +{{- end -}} + +{{/* REGISTRY_CONTROLLER_URL */}} +{{- define "harbor.registryControllerURL" -}} + {{- printf "%s://%s:%s" (include "harbor.component.scheme" .) (include "harbor.registry" .) (include "harbor.registryctl.servicePort" .) -}} +{{- end -}} + +{{/* TOKEN_SERVICE_URL */}} +{{- define "harbor.tokenServiceURL" -}} + {{- printf "%s/service/token" (include "harbor.coreURL" .) -}} +{{- end -}} + +{{/* TRIVY_ADAPTER_URL */}} +{{- define "harbor.trivyAdapterURL" -}} + {{- printf "%s://%s:%s" (include "harbor.component.scheme" .) (include "harbor.trivy" .) (include "harbor.trivy.servicePort" .) -}} +{{- end -}} + +{{- define "harbor.internalTLS.core.secretName" -}} + {{- if eq .Values.internalTLS.certSource "secret" -}} + {{- .Values.internalTLS.core.secretName -}} + {{- else -}} + {{- printf "%s-core-internal-tls" (include "harbor.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.internalTLS.jobservice.secretName" -}} + {{- if eq .Values.internalTLS.certSource "secret" -}} + {{- .Values.internalTLS.jobservice.secretName -}} + {{- else -}} + {{- printf "%s-jobservice-internal-tls" (include "harbor.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.internalTLS.portal.secretName" -}} + {{- if eq .Values.internalTLS.certSource "secret" -}} + {{- .Values.internalTLS.portal.secretName -}} + {{- else -}} + {{- printf "%s-portal-internal-tls" (include "harbor.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.internalTLS.registry.secretName" -}} + {{- if eq .Values.internalTLS.certSource "secret" -}} + {{- .Values.internalTLS.registry.secretName -}} + {{- else -}} + {{- printf "%s-registry-internal-tls" (include "harbor.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.internalTLS.trivy.secretName" -}} + {{- if eq .Values.internalTLS.certSource "secret" -}} + {{- .Values.internalTLS.trivy.secretName -}} + {{- else -}} + {{- printf "%s-trivy-internal-tls" (include "harbor.fullname" .) -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.tlsCoreSecretForIngress" -}} + {{- if eq .Values.expose.tls.certSource "none" -}} + {{- printf "" -}} + {{- else if eq .Values.expose.tls.certSource "secret" -}} + {{- .Values.expose.tls.secret.secretName -}} + {{- else -}} + {{- include "harbor.ingress" . -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.tlsSecretForNginx" -}} + {{- if eq .Values.expose.tls.certSource "secret" -}} + {{- .Values.expose.tls.secret.secretName -}} + {{- else -}} + {{- include "harbor.nginx" . -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.metricsPortName" -}} + {{- if .Values.internalTLS.enabled }} + {{- printf "https-metrics" -}} + {{- else -}} + {{- printf "http-metrics" -}} + {{- end -}} +{{- end -}} + +{{- define "harbor.traceEnvs" -}} + TRACE_ENABLED: "{{ .Values.trace.enabled }}" + TRACE_SAMPLE_RATE: "{{ .Values.trace.sample_rate }}" + TRACE_NAMESPACE: "{{ .Values.trace.namespace }}" + {{- if .Values.trace.attributes }} + TRACE_ATTRIBUTES: {{ .Values.trace.attributes | toJson | squote }} + {{- end }} + {{- if eq .Values.trace.provider "jaeger" }} + TRACE_JAEGER_ENDPOINT: "{{ .Values.trace.jaeger.endpoint }}" + TRACE_JAEGER_USERNAME: "{{ .Values.trace.jaeger.username }}" + TRACE_JAEGER_AGENT_HOSTNAME: "{{ .Values.trace.jaeger.agent_host }}" + TRACE_JAEGER_AGENT_PORT: "{{ .Values.trace.jaeger.agent_port }}" + {{- else }} + TRACE_OTEL_ENDPOINT: "{{ .Values.trace.otel.endpoint }}" + TRACE_OTEL_URL_PATH: "{{ .Values.trace.otel.url_path }}" + TRACE_OTEL_COMPRESSION: "{{ .Values.trace.otel.compression }}" + TRACE_OTEL_INSECURE: "{{ .Values.trace.otel.insecure }}" + TRACE_OTEL_TIMEOUT: "{{ .Values.trace.otel.timeout }}" + {{- end }} +{{- end -}} + +{{- define "harbor.traceEnvsForCore" -}} + {{- if .Values.trace.enabled }} + TRACE_SERVICE_NAME: "harbor-core" + {{ include "harbor.traceEnvs" . }} + {{- end }} +{{- end -}} + +{{- define "harbor.traceEnvsForJobservice" -}} + {{- if .Values.trace.enabled }} + TRACE_SERVICE_NAME: "harbor-jobservice" + {{ include "harbor.traceEnvs" . }} + {{- end }} +{{- end -}} + +{{- define "harbor.traceEnvsForRegistryCtl" -}} + {{- if .Values.trace.enabled }} + TRACE_SERVICE_NAME: "harbor-registryctl" + {{ include "harbor.traceEnvs" . }} + {{- end }} +{{- end -}} + +{{- define "harbor.traceJaegerPassword" -}} + {{- if and .Values.trace.enabled (eq .Values.trace.provider "jaeger") }} + TRACE_JAEGER_PASSWORD: "{{ .Values.trace.jaeger.password | default "" | b64enc }}" + {{- end }} +{{- end -}} + +{{/* Allow KubeVersion to be overridden. */}} +{{- define "harbor.ingress.kubeVersion" -}} + {{- default .Capabilities.KubeVersion.Version .Values.expose.ingress.kubeVersionOverride -}} +{{- end -}} diff --git a/packages/system/harbor/charts/harbor/templates/core/core-cm.yaml b/packages/system/harbor/charts/harbor/templates/core/core-cm.yaml new file mode 100644 index 00000000..17a82078 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/core/core-cm.yaml @@ -0,0 +1,92 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "harbor.core" . }} + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + app.conf: |+ + appname = Harbor + runmode = prod + enablegzip = true + + [prod] + httpport = {{ ternary "8443" "8080" .Values.internalTLS.enabled }} + PORT: "{{ ternary "8443" "8080" .Values.internalTLS.enabled }}" + DATABASE_TYPE: "postgresql" + POSTGRESQL_HOST: "{{ template "harbor.database.host" . }}" + POSTGRESQL_PORT: "{{ template "harbor.database.port" . }}" + POSTGRESQL_USERNAME: "{{ template "harbor.database.username" . }}" + POSTGRESQL_DATABASE: "{{ template "harbor.database.coreDatabase" . }}" + POSTGRESQL_SSLMODE: "{{ template "harbor.database.sslmode" . }}" + POSTGRESQL_MAX_IDLE_CONNS: "{{ .Values.database.maxIdleConns }}" + POSTGRESQL_MAX_OPEN_CONNS: "{{ .Values.database.maxOpenConns }}" + EXT_ENDPOINT: "{{ .Values.externalURL }}" + CORE_URL: "{{ template "harbor.coreURL" . }}" + JOBSERVICE_URL: "{{ template "harbor.jobserviceURL" . }}" + REGISTRY_URL: "{{ template "harbor.registryURL" . }}" + TOKEN_SERVICE_URL: "{{ template "harbor.tokenServiceURL" . }}" + CORE_LOCAL_URL: "{{ ternary "https://127.0.0.1:8443" "http://127.0.0.1:8080" .Values.internalTLS.enabled }}" + WITH_TRIVY: {{ .Values.trivy.enabled | quote }} + TRIVY_ADAPTER_URL: "{{ template "harbor.trivyAdapterURL" . }}" + REGISTRY_STORAGE_PROVIDER_NAME: "{{ .Values.persistence.imageChartStorage.type }}" + LOG_LEVEL: "{{ .Values.logLevel }}" + CONFIG_PATH: "/etc/core/app.conf" + CHART_CACHE_DRIVER: "redis" + _REDIS_URL_CORE: "{{ template "harbor.redis.urlForCore" . }}" + _REDIS_URL_REG: "{{ template "harbor.redis.urlForRegistry" . }}" + {{- if or (and (eq .Values.redis.type "internal") .Values.redis.internal.harborDatabaseIndex) (and (eq .Values.redis.type "external") .Values.redis.external.harborDatabaseIndex) }} + _REDIS_URL_HARBOR: "{{ template "harbor.redis.urlForHarbor" . }}" + {{- end }} + {{- if or (and (eq .Values.redis.type "internal") .Values.redis.internal.cacheLayerDatabaseIndex) (and (eq .Values.redis.type "external") .Values.redis.external.cacheLayerDatabaseIndex) }} + _REDIS_URL_CACHE_LAYER: "{{ template "harbor.redis.urlForCache" . }}" + {{- end }} + PORTAL_URL: "{{ template "harbor.portalURL" . }}" + REGISTRY_CONTROLLER_URL: "{{ template "harbor.registryControllerURL" . }}" + REGISTRY_CREDENTIAL_USERNAME: "{{ .Values.registry.credentials.username }}" + {{- if .Values.uaaSecretName }} + UAA_CA_ROOT: "/etc/core/auth-ca/auth-ca.crt" + {{- end }} + {{- if has "core" .Values.proxy.components }} + HTTP_PROXY: "{{ .Values.proxy.httpProxy }}" + HTTPS_PROXY: "{{ .Values.proxy.httpsProxy }}" + NO_PROXY: "{{ template "harbor.noProxy" . }}" + {{- end }} + PERMITTED_REGISTRY_TYPES_FOR_PROXY_CACHE: "docker-hub,harbor,azure-acr,ali-acr,aws-ecr,google-gcr,docker-registry,github-ghcr,jfrog-artifactory" + REPLICATION_ADAPTER_WHITELIST: "ali-acr,aws-ecr,azure-acr,docker-hub,docker-registry,github-ghcr,google-gcr,harbor,huawei-SWR,jfrog-artifactory,tencent-tcr,volcengine-cr" + {{- if .Values.metrics.enabled}} + METRIC_ENABLE: "true" + METRIC_PATH: "{{ .Values.metrics.core.path }}" + METRIC_PORT: "{{ .Values.metrics.core.port }}" + METRIC_NAMESPACE: harbor + METRIC_SUBSYSTEM: core + {{- end }} + + {{- if hasKey .Values.core "gcTimeWindowHours" }} + #make the GC time window configurable for testing + GC_TIME_WINDOW_HOURS: "{{ .Values.core.gcTimeWindowHours }}" + {{- end }} + {{- template "harbor.traceEnvsForCore" . }} + + {{- if .Values.core.artifactPullAsyncFlushDuration }} + ARTIFACT_PULL_ASYNC_FLUSH_DURATION: {{ .Values.core.artifactPullAsyncFlushDuration | quote }} + {{- end }} + + {{- if .Values.core.gdpr}} + {{- if .Values.core.gdpr.deleteUser}} + GDPR_DELETE_USER: "true" + {{- end }} + {{- if .Values.core.gdpr.auditLogsCompliant}} + GDPR_AUDIT_LOGS: "true" + {{- end }} + {{- end }} + + {{- if .Values.cache.enabled }} + CACHE_ENABLED: "true" + CACHE_EXPIRE_HOURS: "{{ .Values.cache.expireHours }}" + {{- end }} + + {{- if .Values.core.quotaUpdateProvider }} + QUOTA_UPDATE_PROVIDER: "{{ .Values.core.quotaUpdateProvider }}" + {{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/core/core-dpl.yaml b/packages/system/harbor/charts/harbor/templates/core/core-dpl.yaml new file mode 100644 index 00000000..4705c5f6 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/core/core-dpl.yaml @@ -0,0 +1,258 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "harbor.core" . }} + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: core + app.kubernetes.io/component: core +spec: + replicas: {{ .Values.core.replicas }} + revisionHistoryLimit: {{ .Values.core.revisionHistoryLimit }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: core + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: core + app.kubernetes.io/component: core +{{- if .Values.core.podLabels }} +{{ toYaml .Values.core.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/core/core-cm.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/core/core-secret.yaml") . | sha256sum }} + checksum/secret-jobservice: {{ include (print $.Template.BasePath "/jobservice/jobservice-secrets.yaml") . | sha256sum }} +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/core/core-tls.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.core.podAnnotations }} +{{ toYaml .Values.core.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 10000 + fsGroup: 10000 +{{- if .Values.core.serviceAccountName }} + serviceAccountName: {{ .Values.core.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.core.automountServiceAccountToken | default false }} + terminationGracePeriodSeconds: 120 +{{- with .Values.core.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: core +{{- end }} +{{- end }} + {{- with .Values.core.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: core + image: {{ .Values.core.image.repository }}:{{ .Values.core.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if .Values.core.startupProbe.enabled }} + startupProbe: + httpGet: + path: /api/v2.0/ping + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.core.containerPort" . }} + failureThreshold: 360 + initialDelaySeconds: {{ .Values.core.startupProbe.initialDelaySeconds }} + periodSeconds: 10 + {{- end }} + livenessProbe: + httpGet: + path: /api/v2.0/ping + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.core.containerPort" . }} + failureThreshold: 2 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /api/v2.0/ping + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.core.containerPort" . }} + failureThreshold: 2 + periodSeconds: 10 + envFrom: + - configMapRef: + name: "{{ template "harbor.core" . }}" + - secretRef: + name: "{{ template "harbor.core" . }}" + env: + - name: CORE_SECRET + valueFrom: + secretKeyRef: + name: {{ default (include "harbor.core" .) .Values.core.existingSecret }} + key: secret + - name: JOBSERVICE_SECRET + valueFrom: + secretKeyRef: + name: {{ default (include "harbor.jobservice" .) .Values.jobservice.existingSecret }} + {{- if .Values.jobservice.existingSecret }} + key: {{ .Values.jobservice.existingSecretKey }} + {{- else }} + key: JOBSERVICE_SECRET + {{- end }} + {{- if .Values.existingSecretAdminPassword }} + - name: HARBOR_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.existingSecretAdminPassword }} + key: {{ .Values.existingSecretAdminPasswordKey }} + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: INTERNAL_TLS_ENABLED + value: "true" + - name: INTERNAL_TLS_KEY_PATH + value: /etc/harbor/ssl/core/tls.key + - name: INTERNAL_TLS_CERT_PATH + value: /etc/harbor/ssl/core/tls.crt + - name: INTERNAL_TLS_TRUST_CA_PATH + value: /etc/harbor/ssl/core/ca.crt + {{- end }} + {{- if .Values.database.external.existingSecret }} + - name: POSTGRESQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.database.external.existingSecret }} + key: password + {{- end }} + {{- if .Values.registry.credentials.existingSecret }} + - name: REGISTRY_CREDENTIAL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.registry.credentials.existingSecret }} + key: REGISTRY_PASSWD + {{- end }} + {{- if .Values.core.existingXsrfSecret }} + - name: CSRF_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.core.existingXsrfSecret }} + key: {{ .Values.core.existingXsrfSecretKey }} + {{- end }} +{{- with .Values.core.extraEnvVars }} +{{- toYaml . | nindent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + ports: + - containerPort: {{ template "harbor.core.containerPort" . }} + volumeMounts: + - name: config + mountPath: /etc/core/app.conf + subPath: app.conf + - name: secret-key + mountPath: /etc/core/key + subPath: key + - name: token-service-private-key + mountPath: /etc/core/private_key.pem + subPath: tls.key + {{- if .Values.expose.tls.enabled }} + - name: ca-download + mountPath: /etc/core/ca + {{- end }} + {{- if .Values.uaaSecretName }} + - name: auth-ca-cert + mountPath: /etc/core/auth-ca/auth-ca.crt + subPath: auth-ca.crt + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: core-internal-certs + mountPath: /etc/harbor/ssl/core + {{- end }} + - name: psc + mountPath: /etc/core/token + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 8 }} + {{- end }} +{{- if .Values.core.resources }} + resources: +{{ toYaml .Values.core.resources | indent 10 }} +{{- end }} + volumes: + - name: config + configMap: + name: {{ template "harbor.core" . }} + items: + - key: app.conf + path: app.conf + - name: secret-key + secret: + {{- if .Values.existingSecretSecretKey }} + secretName: {{ .Values.existingSecretSecretKey }} + {{- else }} + secretName: {{ template "harbor.core" . }} + {{- end }} + items: + - key: secretKey + path: key + - name: token-service-private-key + secret: + {{- if .Values.core.secretName }} + secretName: {{ .Values.core.secretName }} + {{- else }} + secretName: {{ template "harbor.core" . }} + {{- end }} + {{- if .Values.expose.tls.enabled }} + - name: ca-download + secret: + {{- if .Values.caSecretName }} + secretName: {{ .Values.caSecretName }} + {{- else if eq (include "harbor.autoGenCertForIngress" .) "true" }} + secretName: "{{ template "harbor.ingress" . }}" + {{- else if eq (include "harbor.autoGenCertForNginx" .) "true" }} + secretName: {{ template "harbor.tlsSecretForNginx" . }} + {{- end }} + {{- end }} + {{- if .Values.uaaSecretName }} + - name: auth-ca-cert + secret: + secretName: {{ .Values.uaaSecretName }} + items: + - key: ca.crt + path: auth-ca.crt + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: core-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.core.secretName" . }} + {{- end }} + - name: psc + emptyDir: {} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolume" . | indent 6 }} + {{- end }} + {{- with .Values.core.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.core.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.core.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.core.priorityClassName }} + priorityClassName: {{ .Values.core.priorityClassName }} + {{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/core/core-pre-upgrade-job.yaml b/packages/system/harbor/charts/harbor/templates/core/core-pre-upgrade-job.yaml new file mode 100644 index 00000000..87271569 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/core/core-pre-upgrade-job.yaml @@ -0,0 +1,78 @@ +{{- if .Values.enableMigrateHelmHook }} +apiVersion: batch/v1 +kind: Job +metadata: + name: migration-job + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: migrator + annotations: + # This is what defines this resource as a hook. Without this line, the + # job is considered part of the release. + "helm.sh/hook": pre-upgrade + "helm.sh/hook-weight": "-5" +spec: + template: + metadata: + labels: +{{ include "harbor.matchLabels" . | indent 8 }} + component: migrator + spec: + restartPolicy: Never + securityContext: + runAsUser: 10000 + fsGroup: 10000 +{{- if .Values.core.serviceAccountName }} + serviceAccountName: {{ .Values.core.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + terminationGracePeriodSeconds: 120 + containers: + - name: core-job + image: {{ .Values.core.image.repository }}:{{ .Values.core.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + command: ["/harbor/harbor_core", "-mode=migrate"] + envFrom: + - configMapRef: + name: "{{ template "harbor.core" . }}" + - secretRef: + name: "{{ template "harbor.core" . }}" + {{- if .Values.database.external.existingSecret }} + env: + - name: POSTGRESQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.database.external.existingSecret }} + key: password + {{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + volumeMounts: + - name: config + mountPath: /etc/core/app.conf + subPath: app.conf + volumes: + - name: config + configMap: + name: {{ template "harbor.core" . }} + items: + - key: app.conf + path: app.conf + {{- with .Values.core.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.core.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.core.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/core/core-secret.yaml b/packages/system/harbor/charts/harbor/templates/core/core-secret.yaml new file mode 100644 index 00000000..ea9d4cfa --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/core/core-secret.yaml @@ -0,0 +1,37 @@ +{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (include "harbor.core" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "harbor.core" . }} + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- if not .Values.existingSecretSecretKey }} + secretKey: {{ .Values.secretKey | b64enc | quote }} + {{- end }} + {{- if not .Values.core.existingSecret }} + secret: {{ .Values.core.secret | default (include "harbor.secretKeyHelper" (dict "key" "secret" "data" $existingSecret.data)) | default (randAlphaNum 16) | b64enc | quote }} + {{- end }} + {{- if not .Values.core.secretName }} + {{- $ca := genCA "harbor-token-ca" 365 }} + tls.key: {{ .Values.core.tokenKey | default $ca.Key | b64enc | quote }} + tls.crt: {{ .Values.core.tokenCert | default $ca.Cert | b64enc | quote }} + {{- end }} + {{- if not .Values.existingSecretAdminPassword }} + HARBOR_ADMIN_PASSWORD: {{ .Values.harborAdminPassword | b64enc | quote }} + {{- end }} + {{- if not .Values.database.external.existingSecret }} + POSTGRESQL_PASSWORD: {{ template "harbor.database.encryptedPassword" . }} + {{- end }} + {{- if not .Values.registry.credentials.existingSecret }} + REGISTRY_CREDENTIAL_PASSWORD: {{ .Values.registry.credentials.password | b64enc | quote }} + {{- end }} + {{- if not .Values.core.existingXsrfSecret }} + CSRF_KEY: {{ .Values.core.xsrfKey | default (include "harbor.secretKeyHelper" (dict "key" "CSRF_KEY" "data" $existingSecret.data)) | default (randAlphaNum 32) | b64enc | quote }} + {{- end }} +{{- if .Values.core.configureUserSettings }} + CONFIG_OVERWRITE_JSON: {{ .Values.core.configureUserSettings | b64enc | quote }} +{{- end }} + {{- template "harbor.traceJaegerPassword" . }} diff --git a/packages/system/harbor/charts/harbor/templates/core/core-svc.yaml b/packages/system/harbor/charts/harbor/templates/core/core-svc.yaml new file mode 100644 index 00000000..a1d2368d --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/core/core-svc.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "harbor.core" . }} + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- with .Values.core.serviceAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: +{{- if or (eq .Values.expose.ingress.controller "gce") (eq .Values.expose.ingress.controller "alb") (eq .Values.expose.ingress.controller "f5-bigip") }} + type: NodePort +{{- end }} +{{- if .Values.ipFamily.policy }} + ipFamilyPolicy: {{ .Values.ipFamily.policy }} +{{- end }} +{{- if .Values.ipFamily.families }} + ipFamilies: {{ toYaml .Values.ipFamily.families | nindent 4 }} +{{- end }} + ports: + - name: {{ ternary "https-web" "http-web" .Values.internalTLS.enabled }} + port: {{ template "harbor.core.servicePort" . }} + targetPort: {{ template "harbor.core.containerPort" . }} +{{- if .Values.metrics.enabled}} + - name: {{ template "harbor.metricsPortName" . }} + port: {{ .Values.metrics.core.port }} +{{- end }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: core diff --git a/packages/system/harbor/charts/harbor/templates/core/core-tls.yaml b/packages/system/harbor/charts/harbor/templates/core/core-tls.yaml new file mode 100644 index 00000000..d90d30c8 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/core/core-tls.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.internalTLS.enabled }} +{{- if eq .Values.internalTLS.certSource "manual" }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.core.secretName" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ (required "The \"internalTLS.trustCa\" is required!" .Values.internalTLS.trustCa) | b64enc | quote }} + tls.crt: {{ (required "The \"internalTLS.core.crt\" is required!" .Values.internalTLS.core.crt) | b64enc | quote }} + tls.key: {{ (required "The \"internalTLS.core.key\" is required!" .Values.internalTLS.core.key) | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/database/database-secret.yaml b/packages/system/harbor/charts/harbor/templates/database/database-secret.yaml new file mode 100644 index 00000000..0d07ec26 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/database/database-secret.yaml @@ -0,0 +1,12 @@ +{{- if eq .Values.database.type "internal" -}} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.database" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + POSTGRES_PASSWORD: {{ template "harbor.database.encryptedPassword" . }} +{{- end -}} diff --git a/packages/system/harbor/charts/harbor/templates/database/database-ss.yaml b/packages/system/harbor/charts/harbor/templates/database/database-ss.yaml new file mode 100644 index 00000000..8bddd291 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/database/database-ss.yaml @@ -0,0 +1,165 @@ +{{- if eq .Values.database.type "internal" -}} +{{- $database := .Values.persistence.persistentVolumeClaim.database -}} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: "{{ template "harbor.database" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: database + app.kubernetes.io/component: database +spec: + replicas: 1 + serviceName: "{{ template "harbor.database" . }}" + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: database + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: database + app.kubernetes.io/component: database +{{- if .Values.database.podLabels }} +{{ toYaml .Values.database.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/secret: {{ include (print $.Template.BasePath "/database/database-secret.yaml") . | sha256sum }} +{{- if .Values.database.podAnnotations }} +{{ toYaml .Values.database.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 999 + fsGroup: 999 +{{- if .Values.database.internal.serviceAccountName }} + serviceAccountName: {{ .Values.database.internal.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.database.internal.automountServiceAccountToken | default false }} + terminationGracePeriodSeconds: 120 + initContainers: + # with "fsGroup" set, each time a volume is mounted, Kubernetes must recursively chown() and chmod() all the files and directories inside the volume + # this causes the postgresql reports the "data directory /var/lib/postgresql/data/pgdata has group or world access" issue when using some CSIs e.g. Ceph + # use this init container to correct the permission + # as "fsGroup" applied before the init container running, the container has enough permission to execute the command + - name: "data-permissions-ensurer" + image: {{ .Values.database.internal.image.repository }}:{{ .Values.database.internal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + command: ["/bin/sh"] + args: ["-c", "chmod -R 700 /var/lib/postgresql/data/pgdata || true"] +{{- if .Values.database.internal.initContainer.permissions.resources }} + resources: +{{ toYaml .Values.database.internal.initContainer.permissions.resources | indent 10 }} +{{- end }} + volumeMounts: + - name: database-data + mountPath: /var/lib/postgresql/data + subPath: {{ $database.subPath }} + {{- with .Values.database.internal.extrInitContainers }} + {{- toYaml . | nindent 6 }} + {{- end }} + containers: + - name: database + image: {{ .Values.database.internal.image.repository }}:{{ .Values.database.internal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + livenessProbe: + exec: + command: + - /docker-healthcheck.sh + initialDelaySeconds: 300 + periodSeconds: 10 + timeoutSeconds: {{ .Values.database.internal.livenessProbe.timeoutSeconds }} + readinessProbe: + exec: + command: + - /docker-healthcheck.sh + initialDelaySeconds: 1 + periodSeconds: 10 + timeoutSeconds: {{ .Values.database.internal.readinessProbe.timeoutSeconds }} +{{- if .Values.database.internal.resources }} + resources: +{{ toYaml .Values.database.internal.resources | indent 10 }} +{{- end }} + envFrom: + - secretRef: + name: "{{ template "harbor.database" . }}" + env: + # put the data into a sub directory to avoid the permission issue in k8s with restricted psp enabled + # more detail refer to https://github.com/goharbor/harbor-helm/issues/756 + - name: PGDATA + value: "/var/lib/postgresql/data/pgdata" +{{- with .Values.database.internal.extraEnvVars }} +{{- toYaml . | nindent 10 }} +{{- end }} + volumeMounts: + - name: database-data + mountPath: /var/lib/postgresql/data + subPath: {{ $database.subPath }} + - name: shm-volume + mountPath: /dev/shm + volumes: + - name: shm-volume + emptyDir: + medium: Memory + sizeLimit: {{ .Values.database.internal.shmSizeLimit }} + {{- if not .Values.persistence.enabled }} + - name: "database-data" + emptyDir: {} + {{- else if $database.existingClaim }} + - name: "database-data" + persistentVolumeClaim: + claimName: {{ $database.existingClaim }} + {{- end -}} + {{- with .Values.database.internal.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.database.internal.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.database.internal.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.database.internal.priorityClassName }} + priorityClassName: {{ .Values.database.internal.priorityClassName }} + {{- end }} + {{- if and .Values.persistence.enabled (not $database.existingClaim) }} + volumeClaimTemplates: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: "database-data" + labels: +{{ include "harbor.legacy.labels" . | indent 8 }} + annotations: + {{- range $key, $value := $database.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + accessModes: [{{ $database.accessMode | quote }}] + {{- if $database.storageClass }} + {{- if (eq "-" $database.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ $database.storageClass }}" + {{- end }} + {{- end }} + resources: + requests: + storage: {{ $database.size | quote }} + {{- end -}} + {{- end -}} diff --git a/packages/system/harbor/charts/harbor/templates/database/database-svc.yaml b/packages/system/harbor/charts/harbor/templates/database/database-svc.yaml new file mode 100644 index 00000000..aef4c6df --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/database/database-svc.yaml @@ -0,0 +1,21 @@ +{{- if eq .Values.database.type "internal" -}} +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.database" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: +{{- if .Values.ipFamily.policy }} + ipFamilyPolicy: {{ .Values.ipFamily.policy }} +{{- end }} +{{- if .Values.ipFamily.families }} + ipFamilies: {{ toYaml .Values.ipFamily.families | nindent 4 }} +{{- end }} + ports: + - port: 5432 + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: database +{{- end -}} diff --git a/packages/system/harbor/charts/harbor/templates/exporter/exporter-cm-env.yaml b/packages/system/harbor/charts/harbor/templates/exporter/exporter-cm-env.yaml new file mode 100644 index 00000000..3f911032 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/exporter/exporter-cm-env.yaml @@ -0,0 +1,36 @@ +{{- if .Values.metrics.enabled}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.exporter" . }}-env" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + {{- if has "jobservice" .Values.proxy.components }} + HTTP_PROXY: "{{ .Values.proxy.httpProxy }}" + HTTPS_PROXY: "{{ .Values.proxy.httpsProxy }}" + NO_PROXY: "{{ template "harbor.noProxy" . }}" + {{- end }} + LOG_LEVEL: "{{ .Values.logLevel }}" + HARBOR_EXPORTER_PORT: "{{ .Values.metrics.exporter.port }}" + HARBOR_EXPORTER_METRICS_PATH: "{{ .Values.metrics.exporter.path }}" + HARBOR_EXPORTER_METRICS_ENABLED: "{{ .Values.metrics.enabled }}" + HARBOR_EXPORTER_CACHE_TIME: "{{ .Values.exporter.cacheDuration }}" + HARBOR_EXPORTER_CACHE_CLEAN_INTERVAL: "{{ .Values.exporter.cacheCleanInterval }}" + HARBOR_METRIC_NAMESPACE: harbor + HARBOR_METRIC_SUBSYSTEM: exporter + HARBOR_REDIS_URL: "{{ template "harbor.redis.urlForJobservice" . }}" + HARBOR_REDIS_NAMESPACE: harbor_job_service_namespace + HARBOR_REDIS_TIMEOUT: "3600" + HARBOR_SERVICE_SCHEME: "{{ template "harbor.component.scheme" . }}" + HARBOR_SERVICE_HOST: "{{ template "harbor.core" . }}" + HARBOR_SERVICE_PORT: "{{ template "harbor.core.servicePort" . }}" + HARBOR_DATABASE_HOST: "{{ template "harbor.database.host" . }}" + HARBOR_DATABASE_PORT: "{{ template "harbor.database.port" . }}" + HARBOR_DATABASE_USERNAME: "{{ template "harbor.database.username" . }}" + HARBOR_DATABASE_DBNAME: "{{ template "harbor.database.coreDatabase" . }}" + HARBOR_DATABASE_SSLMODE: "{{ template "harbor.database.sslmode" . }}" + HARBOR_DATABASE_MAX_IDLE_CONNS: "{{ .Values.database.maxIdleConns }}" + HARBOR_DATABASE_MAX_OPEN_CONNS: "{{ .Values.database.maxOpenConns }}" +{{- end}} diff --git a/packages/system/harbor/charts/harbor/templates/exporter/exporter-dpl.yaml b/packages/system/harbor/charts/harbor/templates/exporter/exporter-dpl.yaml new file mode 100644 index 00000000..30894a6d --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/exporter/exporter-dpl.yaml @@ -0,0 +1,146 @@ +{{- if .Values.metrics.enabled}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "harbor.exporter" . }} + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: exporter + app.kubernetes.io/component: exporter +spec: + replicas: {{ .Values.exporter.replicas }} + revisionHistoryLimit: {{ .Values.exporter.revisionHistoryLimit }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: exporter + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: exporter + app.kubernetes.io/component: exporter +{{- if .Values.exporter.podLabels }} +{{ toYaml .Values.exporter.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/exporter/exporter-cm-env.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/exporter/exporter-secret.yaml") . | sha256sum }} +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/core/core-tls.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.exporter.podAnnotations }} +{{ toYaml .Values.exporter.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 10000 + fsGroup: 10000 +{{- if .Values.exporter.serviceAccountName }} + serviceAccountName: {{ .Values.exporter.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.exporter.automountServiceAccountToken | default false }} +{{- with .Values.exporter.topologySpreadConstraints }} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: exporter +{{- end }} +{{- end }} + containers: + - name: exporter + image: {{ .Values.exporter.image.repository }}:{{ .Values.exporter.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: / + port: {{ .Values.metrics.exporter.port }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: {{ .Values.metrics.exporter.port }} + initialDelaySeconds: 30 + periodSeconds: 10 + args: ["-log-level", "{{ .Values.logLevel }}"] + envFrom: + - configMapRef: + name: "{{ template "harbor.exporter" . }}-env" + - secretRef: + name: "{{ template "harbor.exporter" . }}" + env: + {{- if .Values.database.external.existingSecret }} + - name: HARBOR_DATABASE_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.database.external.existingSecret }} + key: password + {{- end }} + {{- if .Values.existingSecretAdminPassword }} + - name: HARBOR_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.existingSecretAdminPassword }} + key: {{ .Values.existingSecretAdminPasswordKey }} + {{- end }} + {{- with .Values.exporter.extraEnvVars }} + {{- toYaml . | nindent 8 }} + {{- end }} +{{- if .Values.exporter.resources }} + resources: +{{ toYaml .Values.exporter.resources | indent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + ports: + - containerPort: {{ .Values.metrics.exporter.port }} + volumeMounts: + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 8 }} + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: core-internal-certs + mountPath: /etc/harbor/ssl/core + # There are some metric data are collectd from harbor core. + # When internal TLS is enabled, the Exporter need the CA file to collect these data. + {{- end }} + volumes: + - name: config + secret: + secretName: "{{ template "harbor.exporter" . }}" + {{- if .Values.internalTLS.enabled }} + - name: core-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.core.secretName" . }} + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolume" . | indent 6 }} + {{- end }} + {{- with .Values.exporter.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.exporter.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.exporter.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.exporter.priorityClassName }} + priorityClassName: {{ .Values.exporter.priorityClassName }} + {{- end }} +{{ end }} diff --git a/packages/system/harbor/charts/harbor/templates/exporter/exporter-secret.yaml b/packages/system/harbor/charts/harbor/templates/exporter/exporter-secret.yaml new file mode 100644 index 00000000..02c74d03 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/exporter/exporter-secret.yaml @@ -0,0 +1,17 @@ +{{- if .Values.metrics.enabled}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "harbor.exporter" . }} + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: +{{- if not .Values.existingSecretAdminPassword }} + HARBOR_ADMIN_PASSWORD: {{ .Values.harborAdminPassword | b64enc | quote }} +{{- end }} +{{- if not .Values.database.external.existingSecret }} + HARBOR_DATABASE_PASSWORD: {{ template "harbor.database.encryptedPassword" . }} +{{- end }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/exporter/exporter-svc.yaml b/packages/system/harbor/charts/harbor/templates/exporter/exporter-svc.yaml new file mode 100644 index 00000000..11306e27 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/exporter/exporter-svc.yaml @@ -0,0 +1,22 @@ +{{- if .Values.metrics.enabled}} +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.exporter" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: +{{- if .Values.ipFamily.policy }} + ipFamilyPolicy: {{ .Values.ipFamily.policy }} +{{- end }} +{{- if .Values.ipFamily.families }} + ipFamilies: {{ toYaml .Values.ipFamily.families | nindent 4 }} +{{- end }} + ports: + - name: {{ template "harbor.metricsPortName" . }} + port: {{ .Values.metrics.exporter.port }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: exporter +{{ end }} diff --git a/packages/system/harbor/charts/harbor/templates/gateway-apis/route.yaml b/packages/system/harbor/charts/harbor/templates/gateway-apis/route.yaml new file mode 100644 index 00000000..0999a5ff --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/gateway-apis/route.yaml @@ -0,0 +1,55 @@ +{{- if eq .Values.expose.type "route" }} +{{- $route := .Values.expose.route -}} +{{- $_ := set . "path_type" "PathPrefix" -}} +{{- $_ := set . "portal_path" "/" -}} +{{- $_ := set . "api_path" "/api/" -}} +{{- $_ := set . "service_path" "/service/" -}} +{{- $_ := set . "v2_path" "/v2/" -}} +{{- $_ := set . "controller_path" "/c/" -}} +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: "{{ template "harbor.route" . }}" + namespace: {{ .Release.Namespace | quote }} +{{- if $route.labels }} + labels: +{{ include "harbor.labels" . | indent 4 }} +{{ toYaml $route.labels | indent 4 }} +{{- end }} +{{- if $route.annotations }} + annotations: +{{ toYaml $route.annotations | indent 4 }} +{{- end }} +spec: + parentRefs: + {{- toYaml $route.parentRefs | nindent 2 }} + hostnames: + {{- toYaml $route.hosts | nindent 2 }} + rules: + - matches: + - path: + type: {{ .path_type }} + value: {{ .api_path }} + - path: + type: {{ .path_type }} + value: {{ .service_path }} + - path: + type: {{ .path_type }} + value: {{ .v2_path }} + - path: + type: {{ .path_type }} + value: {{ .controller_path }} + backendRefs: + - name: {{ template "harbor.core" . }} + namespace: {{ .Release.Namespace | quote }} + port: {{ template "harbor.core.servicePort" . }} + - matches: + - path: + type: {{ .path_type }} + value: {{ .portal_path }} + backendRefs: + - name: {{ template "harbor.portal" . }} + namespace: {{ .Release.Namespace | quote }} + port: {{ template "harbor.portal.servicePort" . }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/ingress/ingress.yaml b/packages/system/harbor/charts/harbor/templates/ingress/ingress.yaml new file mode 100644 index 00000000..06096b86 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/ingress/ingress.yaml @@ -0,0 +1,132 @@ +{{- if eq .Values.expose.type "ingress" }} +{{- $ingress := .Values.expose.ingress -}} +{{- $tls := .Values.expose.tls -}} +{{- if eq .Values.expose.ingress.controller "gce" }} + {{- $_ := set . "path_type" "ImplementationSpecific" -}} + {{- $_ := set . "portal_path" "/*" -}} + {{- $_ := set . "api_path" "/api/*" -}} + {{- $_ := set . "service_path" "/service/*" -}} + {{- $_ := set . "v2_path" "/v2/*" -}} + {{- $_ := set . "controller_path" "/c/*" -}} +{{- else if eq .Values.expose.ingress.controller "ncp" }} + {{- $_ := set . "path_type" "Prefix" -}} + {{- $_ := set . "portal_path" "/.*" -}} + {{- $_ := set . "api_path" "/api/.*" -}} + {{- $_ := set . "service_path" "/service/.*" -}} + {{- $_ := set . "v2_path" "/v2/.*" -}} + {{- $_ := set . "controller_path" "/c/.*" -}} +{{- else }} + {{- $_ := set . "path_type" "Prefix" -}} + {{- $_ := set . "portal_path" "/" -}} + {{- $_ := set . "api_path" "/api/" -}} + {{- $_ := set . "service_path" "/service/" -}} + {{- $_ := set . "v2_path" "/v2/" -}} + {{- $_ := set . "controller_path" "/c/" -}} +{{- end }} + +--- +{{- if semverCompare "<1.14-0" (include "harbor.ingress.kubeVersion" .) }} +apiVersion: extensions/v1beta1 +{{- else if semverCompare "<1.19-0" (include "harbor.ingress.kubeVersion" .) }} +apiVersion: networking.k8s.io/v1beta1 +{{- else }} +apiVersion: networking.k8s.io/v1 +{{- end }} +kind: Ingress +metadata: + name: "{{ template "harbor.ingress" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- if $ingress.labels }} +{{ toYaml $ingress.labels | indent 4 }} +{{- end }} + annotations: +{{ toYaml $ingress.annotations | indent 4 }} +{{- if .Values.internalTLS.enabled }} + nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" +{{- end }} +{{- if eq .Values.expose.ingress.controller "ncp" }} + ncp/use-regex: "true" + {{- if $tls.enabled }} + ncp/http-redirect: "true" + {{- end }} +{{- end }} +spec: + {{- if $ingress.className }} + ingressClassName: {{ $ingress.className }} + {{- end }} + {{- if $tls.enabled }} + tls: + - secretName: {{ template "harbor.tlsCoreSecretForIngress" . }} + {{- if $ingress.hosts.core }} + hosts: + - {{ $ingress.hosts.core }} + {{- end }} + {{- end }} + rules: + - http: + paths: +{{- if semverCompare "<1.19-0" (include "harbor.ingress.kubeVersion" .) }} + - path: {{ .api_path }} + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: {{ template "harbor.core.servicePort" . }} + - path: {{ .service_path }} + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: {{ template "harbor.core.servicePort" . }} + - path: {{ .v2_path }} + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: {{ template "harbor.core.servicePort" . }} + - path: {{ .controller_path }} + backend: + serviceName: {{ template "harbor.core" . }} + servicePort: {{ template "harbor.core.servicePort" . }} + - path: {{ .portal_path }} + backend: + serviceName: {{ template "harbor.portal" . }} + servicePort: {{ template "harbor.portal.servicePort" . }} +{{- else }} + - path: {{ .api_path }} + pathType: {{ .path_type }} + backend: + service: + name: {{ template "harbor.core" . }} + port: + number: {{ template "harbor.core.servicePort" . }} + - path: {{ .service_path }} + pathType: {{ .path_type }} + backend: + service: + name: {{ template "harbor.core" . }} + port: + number: {{ template "harbor.core.servicePort" . }} + - path: {{ .v2_path }} + pathType: {{ .path_type }} + backend: + service: + name: {{ template "harbor.core" . }} + port: + number: {{ template "harbor.core.servicePort" . }} + - path: {{ .controller_path }} + pathType: {{ .path_type }} + backend: + service: + name: {{ template "harbor.core" . }} + port: + number: {{ template "harbor.core.servicePort" . }} + - path: {{ .portal_path }} + pathType: {{ .path_type }} + backend: + service: + name: {{ template "harbor.portal" . }} + port: + number: {{ template "harbor.portal.servicePort" . }} +{{- end }} + {{- if $ingress.hosts.core }} + host: {{ $ingress.hosts.core }} + {{- end }} + +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/ingress/secret.yaml b/packages/system/harbor/charts/harbor/templates/ingress/secret.yaml new file mode 100644 index 00000000..48343b0f --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/ingress/secret.yaml @@ -0,0 +1,18 @@ +{{- if eq .Values.expose.type "ingress" }} +{{- if eq (include "harbor.autoGenCertForIngress" .) "true" }} +{{- $ca := genCA "harbor-ca" 365 }} +{{- $cert := genSignedCert .Values.expose.ingress.hosts.core nil (list .Values.expose.ingress.hosts.core) 365 $ca }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.ingress" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + tls.crt: {{ $cert.Cert | b64enc | quote }} + tls.key: {{ $cert.Key | b64enc | quote }} + ca.crt: {{ $ca.Cert | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/internal/auto-tls.yaml b/packages/system/harbor/charts/harbor/templates/internal/auto-tls.yaml new file mode 100644 index 00000000..32807cfd --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/internal/auto-tls.yaml @@ -0,0 +1,86 @@ +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} +{{- $ca := genCA "harbor-internal-ca" 365 }} +{{- $coreCN := (include "harbor.core" .) }} +{{- $coreCrt := genSignedCert $coreCN (list "127.0.0.1") (list "localhost" $coreCN) 365 $ca }} +{{- $jsCN := (include "harbor.jobservice" .) }} +{{- $jsCrt := genSignedCert $jsCN nil (list $jsCN) 365 $ca }} +{{- $regCN := (include "harbor.registry" .) }} +{{- $regCrt := genSignedCert $regCN nil (list $regCN) 365 $ca }} +{{- $portalCN := (include "harbor.portal" .) }} +{{- $portalCrt := genSignedCert $portalCN nil (list $portalCN) 365 $ca }} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.core.secretName" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $coreCrt.Cert | b64enc | quote }} + tls.key: {{ $coreCrt.Key | b64enc | quote }} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.jobservice.secretName" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $jsCrt.Cert | b64enc | quote }} + tls.key: {{ $jsCrt.Key | b64enc | quote }} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.registry.secretName" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $regCrt.Cert | b64enc | quote }} + tls.key: {{ $regCrt.Key | b64enc | quote }} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.portal.secretName" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $portalCrt.Cert | b64enc | quote }} + tls.key: {{ $portalCrt.Key | b64enc | quote }} + +{{- if and .Values.trivy.enabled}} +--- +{{- $trivyCN := (include "harbor.trivy" .) }} +{{- $trivyCrt := genSignedCert $trivyCN nil (list $trivyCN) 365 $ca }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.trivy.secretName" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ $ca.Cert | b64enc | quote }} + tls.crt: {{ $trivyCrt.Cert | b64enc | quote }} + tls.key: {{ $trivyCrt.Key | b64enc | quote }} +{{- end }} + +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-cm-env.yaml b/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-cm-env.yaml new file mode 100644 index 00000000..f1359131 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-cm-env.yaml @@ -0,0 +1,37 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.jobservice" . }}-env" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + CORE_URL: "{{ template "harbor.coreURL" . }}" + TOKEN_SERVICE_URL: "{{ template "harbor.tokenServiceURL" . }}" + REGISTRY_URL: "{{ template "harbor.registryURL" . }}" + REGISTRY_CONTROLLER_URL: "{{ template "harbor.registryControllerURL" . }}" + REGISTRY_CREDENTIAL_USERNAME: "{{ .Values.registry.credentials.username }}" + + JOBSERVICE_WEBHOOK_JOB_MAX_RETRY: "{{ .Values.jobservice.notification.webhook_job_max_retry }}" + JOBSERVICE_WEBHOOK_JOB_HTTP_CLIENT_TIMEOUT: "{{ .Values.jobservice.notification.webhook_job_http_client_timeout }}" + + LOG_LEVEL: "{{ .Values.logLevel }}" + + {{- if has "jobservice" .Values.proxy.components }} + HTTP_PROXY: "{{ .Values.proxy.httpProxy }}" + HTTPS_PROXY: "{{ .Values.proxy.httpsProxy }}" + NO_PROXY: "{{ template "harbor.noProxy" . }}" + {{- end }} + {{- if .Values.metrics.enabled}} + METRIC_NAMESPACE: harbor + METRIC_SUBSYSTEM: jobservice + {{- end }} + {{- template "harbor.traceEnvsForJobservice" . }} + {{- if .Values.cache.enabled }} + _REDIS_URL_CORE: "{{ template "harbor.redis.urlForCore" . }}" + CACHE_ENABLED: "true" + CACHE_EXPIRE_HOURS: "{{ .Values.cache.expireHours }}" + {{- end }} + {{- if or (and (eq .Values.redis.type "internal") .Values.redis.internal.cacheLayerDatabaseIndex) (and (eq .Values.redis.type "external") .Values.redis.external.cacheLayerDatabaseIndex) }} + _REDIS_URL_CACHE_LAYER: "{{ template "harbor.redis.urlForCache" . }}" + {{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-cm.yaml b/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-cm.yaml new file mode 100644 index 00000000..c950e678 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-cm.yaml @@ -0,0 +1,58 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.jobservice" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + config.yml: |+ + #Server listening port + protocol: "{{ template "harbor.component.scheme" . }}" + port: {{ template "harbor.jobservice.containerPort". }} + {{- if .Values.internalTLS.enabled }} + https_config: + cert: "/etc/harbor/ssl/jobservice/tls.crt" + key: "/etc/harbor/ssl/jobservice/tls.key" + {{- end }} + worker_pool: + workers: {{ .Values.jobservice.maxJobWorkers }} + backend: "redis" + redis_pool: + redis_url: "{{ template "harbor.redis.urlForJobservice" . }}" + namespace: "harbor_job_service_namespace" + idle_timeout_second: 3600 + job_loggers: + {{- if has "file" .Values.jobservice.jobLoggers }} + - name: "FILE" + level: {{ .Values.logLevel | upper }} + settings: # Customized settings of logger + base_dir: "/var/log/jobs" + sweeper: + duration: {{ .Values.jobservice.loggerSweeperDuration }} #days + settings: # Customized settings of sweeper + work_dir: "/var/log/jobs" + {{- end }} + {{- if has "database" .Values.jobservice.jobLoggers }} + - name: "DB" + level: {{ .Values.logLevel | upper }} + sweeper: + duration: {{ .Values.jobservice.loggerSweeperDuration }} #days + {{- end }} + {{- if has "stdout" .Values.jobservice.jobLoggers }} + - name: "STD_OUTPUT" + level: {{ .Values.logLevel | upper }} + {{- end }} + metric: + enabled: {{ .Values.metrics.enabled }} + path: {{ .Values.metrics.jobservice.path }} + port: {{ .Values.metrics.jobservice.port }} + #Loggers for the job service + loggers: + - name: "STD_OUTPUT" + level: {{ .Values.logLevel | upper }} + reaper: + # the max time to wait for a task to finish, if unfinished after max_update_hours, the task will be mark as error, but the task will continue to run, default value is 24 + max_update_hours: {{ .Values.jobservice.reaper.max_update_hours }} + # the max time for execution in running state without new task created + max_dangling_hours: {{ .Values.jobservice.reaper.max_dangling_hours }} diff --git a/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-dpl.yaml b/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-dpl.yaml new file mode 100644 index 00000000..3e426694 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-dpl.yaml @@ -0,0 +1,183 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ template "harbor.jobservice" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: jobservice + app.kubernetes.io/component: jobservice +spec: + replicas: {{ .Values.jobservice.replicas }} + revisionHistoryLimit: {{ .Values.jobservice.revisionHistoryLimit }} + strategy: + type: {{ .Values.updateStrategy.type }} + {{- if eq .Values.updateStrategy.type "Recreate" }} + rollingUpdate: null + {{- end }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: jobservice + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: jobservice + app.kubernetes.io/component: jobservice +{{- if .Values.jobservice.podLabels }} +{{ toYaml .Values.jobservice.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/jobservice/jobservice-cm.yaml") . | sha256sum }} + checksum/configmap-env: {{ include (print $.Template.BasePath "/jobservice/jobservice-cm-env.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/jobservice/jobservice-secrets.yaml") . | sha256sum }} + checksum/secret-core: {{ include (print $.Template.BasePath "/core/core-secret.yaml") . | sha256sum }} +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/jobservice/jobservice-tls.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.jobservice.podAnnotations }} +{{ toYaml .Values.jobservice.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 10000 + fsGroup: 10000 +{{- if .Values.jobservice.serviceAccountName }} + serviceAccountName: {{ .Values.jobservice.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.jobservice.automountServiceAccountToken | default false }} + terminationGracePeriodSeconds: 120 +{{- with .Values.jobservice.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: jobservice +{{- end }} +{{- end }} + {{- with .Values.jobservice.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: jobservice + image: {{ .Values.jobservice.image.repository }}:{{ .Values.jobservice.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: /api/v1/stats + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.jobservice.containerPort" . }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /api/v1/stats + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.jobservice.containerPort" . }} + initialDelaySeconds: 20 + periodSeconds: 10 +{{- if .Values.jobservice.resources }} + resources: +{{ toYaml .Values.jobservice.resources | indent 10 }} +{{- end }} + env: + - name: CORE_SECRET + valueFrom: + secretKeyRef: + name: {{ default (include "harbor.core" .) .Values.core.existingSecret }} + key: secret + {{- if .Values.jobservice.existingSecret }} + - name: JOBSERVICE_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.jobservice.existingSecret }} + key: {{ .Values.jobservice.existingSecretKey }} + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: INTERNAL_TLS_ENABLED + value: "true" + - name: INTERNAL_TLS_KEY_PATH + value: /etc/harbor/ssl/jobservice/tls.key + - name: INTERNAL_TLS_CERT_PATH + value: /etc/harbor/ssl/jobservice/tls.crt + - name: INTERNAL_TLS_TRUST_CA_PATH + value: /etc/harbor/ssl/jobservice/ca.crt + {{- end }} + {{- if .Values.registry.credentials.existingSecret }} + - name: REGISTRY_CREDENTIAL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.registry.credentials.existingSecret }} + key: REGISTRY_PASSWD + {{- end }} +{{- with .Values.jobservice.extraEnvVars }} +{{- toYaml . | nindent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + envFrom: + - configMapRef: + name: "{{ template "harbor.jobservice" . }}-env" + - secretRef: + name: "{{ template "harbor.jobservice" . }}" + ports: + - containerPort: {{ template "harbor.jobservice.containerPort" . }} + volumeMounts: + - name: jobservice-config + mountPath: /etc/jobservice/config.yml + subPath: config.yml + - name: job-logs + mountPath: /var/log/jobs + subPath: {{ .Values.persistence.persistentVolumeClaim.jobservice.jobLog.subPath }} + {{- if .Values.internalTLS.enabled }} + - name: jobservice-internal-certs + mountPath: /etc/harbor/ssl/jobservice + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 8 }} + {{- end }} + volumes: + - name: jobservice-config + configMap: + name: "{{ template "harbor.jobservice" . }}" + - name: job-logs + {{- if and .Values.persistence.enabled (has "file" .Values.jobservice.jobLoggers) }} + persistentVolumeClaim: + claimName: {{ .Values.persistence.persistentVolumeClaim.jobservice.jobLog.existingClaim | default (include "harbor.jobservice" .) }} + {{- else }} + emptyDir: {} + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: jobservice-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.jobservice.secretName" . }} + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolume" . | indent 6 }} + {{- end }} + {{- with .Values.jobservice.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.jobservice.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.jobservice.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.jobservice.priorityClassName }} + priorityClassName: {{ .Values.jobservice.priorityClassName }} + {{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-pvc.yaml b/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-pvc.yaml new file mode 100644 index 00000000..eb781eed --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-pvc.yaml @@ -0,0 +1,32 @@ +{{- $jobLog := .Values.persistence.persistentVolumeClaim.jobservice.jobLog -}} +{{- if and .Values.persistence.enabled (not $jobLog.existingClaim) (has "file" .Values.jobservice.jobLoggers) }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ template "harbor.jobservice" . }} + namespace: {{ .Release.Namespace | quote }} + annotations: + {{- range $key, $value := $jobLog.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- if eq .Values.persistence.resourcePolicy "keep" }} + helm.sh/resource-policy: keep + {{- end }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: jobservice + app.kubernetes.io/component: jobservice +spec: + accessModes: + - {{ $jobLog.accessMode }} + resources: + requests: + storage: {{ $jobLog.size }} + {{- if $jobLog.storageClass }} + {{- if eq "-" $jobLog.storageClass }} + storageClassName: "" + {{- else }} + storageClassName: {{ $jobLog.storageClass }} + {{- end }} + {{- end }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-secrets.yaml b/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-secrets.yaml new file mode 100644 index 00000000..7706c351 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-secrets.yaml @@ -0,0 +1,17 @@ +{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (include "harbor.jobservice" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.jobservice" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- if not .Values.jobservice.existingSecret }} + JOBSERVICE_SECRET: {{ .Values.jobservice.secret | default (include "harbor.secretKeyHelper" (dict "key" "JOBSERVICE_SECRET" "data" $existingSecret.data)) | default (randAlphaNum 16) | b64enc | quote }} + {{- end }} + {{- if not .Values.registry.credentials.existingSecret }} + REGISTRY_CREDENTIAL_PASSWORD: {{ .Values.registry.credentials.password | b64enc | quote }} + {{- end }} + {{- template "harbor.traceJaegerPassword" . }} diff --git a/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-svc.yaml b/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-svc.yaml new file mode 100644 index 00000000..9bddc43c --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-svc.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.jobservice" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: +{{- if .Values.ipFamily.policy }} + ipFamilyPolicy: {{ .Values.ipFamily.policy }} +{{- end }} +{{- if .Values.ipFamily.families }} + ipFamilies: {{ toYaml .Values.ipFamily.families | nindent 4 }} +{{- end }} + ports: + - name: {{ ternary "https-jobservice" "http-jobservice" .Values.internalTLS.enabled }} + port: {{ template "harbor.jobservice.servicePort" . }} + targetPort: {{ template "harbor.jobservice.containerPort" . }} +{{- if .Values.metrics.enabled }} + - name: {{ template "harbor.metricsPortName" . }} + port: {{ .Values.metrics.jobservice.port }} +{{- end }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: jobservice diff --git a/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-tls.yaml b/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-tls.yaml new file mode 100644 index 00000000..58809ec4 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/jobservice/jobservice-tls.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.internalTLS.enabled }} +{{- if eq .Values.internalTLS.certSource "manual" }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.jobservice.secretName" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ (required "The \"internalTLS.trustCa\" is required!" .Values.internalTLS.trustCa) | b64enc | quote }} + tls.crt: {{ (required "The \"internalTLS.jobservice.crt\" is required!" .Values.internalTLS.jobservice.crt) | b64enc | quote }} + tls.key: {{ (required "The \"internalTLS.jobservice.key\" is required!" .Values.internalTLS.jobservice.key) | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/metrics/metrics-svcmon.yaml b/packages/system/harbor/charts/harbor/templates/metrics/metrics-svcmon.yaml new file mode 100644 index 00000000..d566285e --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/metrics/metrics-svcmon.yaml @@ -0,0 +1,29 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "harbor.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: {{ include "harbor.labels" . | nindent 4 }} +{{- if .Values.metrics.serviceMonitor.additionalLabels }} +{{ toYaml .Values.metrics.serviceMonitor.additionalLabels | indent 4 }} +{{- end }} +spec: + jobLabel: app.kubernetes.io/name + endpoints: + - port: {{ template "harbor.metricsPortName" . }} + {{- if .Values.metrics.serviceMonitor.interval }} + interval: {{ .Values.metrics.serviceMonitor.interval }} + {{- end }} + honorLabels: true +{{- if .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: +{{ tpl (toYaml .Values.metrics.serviceMonitor.metricRelabelings | indent 4) . }} +{{- end }} +{{- if .Values.metrics.serviceMonitor.relabelings }} + relabelings: +{{ toYaml .Values.metrics.serviceMonitor.relabelings | indent 4 }} +{{- end }} + selector: + matchLabels: {{ include "harbor.matchLabels" . | nindent 6 }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/nginx/configmap-http.yaml b/packages/system/harbor/charts/harbor/templates/nginx/configmap-http.yaml new file mode 100644 index 00000000..78efa187 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/nginx/configmap-http.yaml @@ -0,0 +1,136 @@ +{{- if and (ne .Values.expose.type "ingress") (ne .Values.expose.type "route") (not .Values.expose.tls.enabled) }} +{{- $scheme := (include "harbor.component.scheme" .) -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "harbor.nginx" . }} + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + nginx.conf: |+ + worker_processes auto; + pid /tmp/nginx.pid; + + events { + worker_connections 3096; + use epoll; + multi_accept on; + } + + http { + client_body_temp_path /tmp/client_body_temp; + proxy_temp_path /tmp/proxy_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + tcp_nodelay on; + + # this is necessary for us to be able to disable request buffering in all cases + proxy_http_version 1.1; + + upstream core { + server "{{ template "harbor.core" . }}:{{ template "harbor.core.servicePort" . }}"; + } + + upstream portal { + server {{ template "harbor.portal" . }}:{{ template "harbor.portal.servicePort" . }}; + } + + log_format timed_combined '[$time_local]:$remote_addr - ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent" ' + '$request_time $upstream_response_time $pipe'; + + access_log /dev/stdout timed_combined; + + map $http_x_forwarded_proto $x_forwarded_proto { + default $http_x_forwarded_proto; + "" $scheme; + } + + server { + {{- if .Values.ipFamily.ipv4.enabled}} + listen 8080; + {{- end}} + {{- if .Values.ipFamily.ipv6.enabled }} + listen [::]:8080; + {{- end }} + server_tokens off; + # disable any limits to avoid HTTP 413 for large image uploads + client_max_body_size 0; + + # Add extra headers + add_header X-Frame-Options DENY; + add_header Content-Security-Policy "frame-ancestors 'none'"; + + location / { + proxy_pass {{ $scheme }}://portal/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /api/ { + proxy_pass {{ $scheme }}://core/api/; + {{- if and .Values.internalTLS.enabled }} + proxy_ssl_verify off; + proxy_ssl_session_reuse on; + {{- end }} + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /c/ { + proxy_pass {{ $scheme }}://core/c/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /v1/ { + return 404; + } + + location /v2/ { + proxy_pass {{ $scheme }}://core/v2/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + proxy_buffering off; + proxy_request_buffering off; + proxy_send_timeout 900; + proxy_read_timeout 900; + } + + location /service/ { + proxy_pass {{ $scheme }}://core/service/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /service/notifications { + return 404; + } + } + } +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/nginx/configmap-https.yaml b/packages/system/harbor/charts/harbor/templates/nginx/configmap-https.yaml new file mode 100644 index 00000000..3a80e292 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/nginx/configmap-https.yaml @@ -0,0 +1,173 @@ +{{- if and (ne .Values.expose.type "ingress") (ne .Values.expose.type "route") (.Values.expose.tls.enabled) }} +{{- $scheme := (include "harbor.component.scheme" .) -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "harbor.nginx" . }} + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + nginx.conf: |+ + worker_processes auto; + pid /tmp/nginx.pid; + + events { + worker_connections 3096; + use epoll; + multi_accept on; + } + + http { + client_body_temp_path /tmp/client_body_temp; + proxy_temp_path /tmp/proxy_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + tcp_nodelay on; + + # this is necessary for us to be able to disable request buffering in all cases + proxy_http_version 1.1; + + upstream core { + server "{{ template "harbor.core" . }}:{{ template "harbor.core.servicePort" . }}"; + } + + upstream portal { + server "{{ template "harbor.portal" . }}:{{ template "harbor.portal.servicePort" . }}"; + } + + log_format timed_combined '[$time_local]:$remote_addr - ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent" ' + '$request_time $upstream_response_time $pipe'; + + access_log /dev/stdout timed_combined; + + map $http_x_forwarded_proto $x_forwarded_proto { + default $http_x_forwarded_proto; + "" $scheme; + } + + server { + {{- if .Values.ipFamily.ipv4.enabled }} + listen 8443 ssl; + {{- end}} + {{- if .Values.ipFamily.ipv6.enabled }} + listen [::]:8443 ssl; + {{- end }} + # server_name harbordomain.com; + server_tokens off; + # SSL + ssl_certificate /etc/nginx/cert/tls.crt; + ssl_certificate_key /etc/nginx/cert/tls.key; + + # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html + ssl_protocols TLSv1.2 TLSv1.3; + {{- if .Values.internalTLS.strong_ssl_ciphers }} + ssl_ciphers ECDHE+AESGCM:DHE+AESGCM:ECDHE+RSA+SHA256:DHE+RSA+SHA256:!AES128; + {{ else }} + ssl_ciphers '!aNULL:kECDH+AESGCM:ECDH+AESGCM:RSA+AESGCM:kECDH+AES:ECDH+AES:RSA+AES:'; + {{- end }} + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + + # disable any limits to avoid HTTP 413 for large image uploads + client_max_body_size 0; + + # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486) + chunked_transfer_encoding on; + + # Add extra headers + add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload"; + add_header X-Frame-Options DENY; + add_header Content-Security-Policy "frame-ancestors 'none'"; + + location / { + proxy_pass {{ $scheme }}://portal/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_cookie_path / "/; HttpOnly; Secure"; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /api/ { + proxy_pass {{ $scheme }}://core/api/; + {{- if and .Values.internalTLS.enabled }} + proxy_ssl_verify off; + proxy_ssl_session_reuse on; + {{- end }} + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_cookie_path / "/; Secure"; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /c/ { + proxy_pass {{ $scheme }}://core/c/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_cookie_path / "/; Secure"; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /v1/ { + return 404; + } + + location /v2/ { + proxy_pass {{ $scheme }}://core/v2/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + proxy_buffering off; + proxy_request_buffering off; + proxy_send_timeout 900; + proxy_read_timeout 900; + } + + location /service/ { + proxy_pass {{ $scheme }}://core/service/; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $x_forwarded_proto; + + proxy_cookie_path / "/; Secure"; + + proxy_buffering off; + proxy_request_buffering off; + } + + location /service/notifications { + return 404; + } + } + server { + {{- if .Values.ipFamily.ipv4.enabled }} + listen 8080; + {{- end}} + {{- if .Values.ipFamily.ipv6.enabled }} + listen [::]:8080; + {{- end}} + #server_name harbordomain.com; + return 301 https://$host$request_uri; + } + } +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/nginx/deployment.yaml b/packages/system/harbor/charts/harbor/templates/nginx/deployment.yaml new file mode 100644 index 00000000..0c8bc40f --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/nginx/deployment.yaml @@ -0,0 +1,133 @@ +{{- if and (ne .Values.expose.type "ingress") (ne .Values.expose.type "route") }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "harbor.nginx" . }} + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: nginx + app.kubernetes.io/component: nginx +spec: + replicas: {{ .Values.nginx.replicas }} + revisionHistoryLimit: {{ .Values.nginx.revisionHistoryLimit }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: nginx + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: nginx + app.kubernetes.io/component: nginx +{{- if .Values.nginx.podLabels }} +{{ toYaml .Values.nginx.podLabels | indent 8 }} +{{- end }} + annotations: + {{- if not .Values.expose.tls.enabled }} + checksum/configmap: {{ include (print $.Template.BasePath "/nginx/configmap-http.yaml") . | sha256sum }} + {{- else }} + checksum/configmap: {{ include (print $.Template.BasePath "/nginx/configmap-https.yaml") . | sha256sum }} + {{- end }} + {{- if eq (include "harbor.autoGenCertForNginx" .) "true" }} + checksum/secret: {{ include (print $.Template.BasePath "/nginx/secret.yaml") . | sha256sum }} + {{- end }} +{{- if .Values.nginx.podAnnotations }} +{{ toYaml .Values.nginx.podAnnotations | indent 8 }} +{{- end }} + spec: +{{- if .Values.nginx.serviceAccountName }} + serviceAccountName: {{ .Values.nginx.serviceAccountName }} +{{- end }} + securityContext: + runAsUser: 10000 + fsGroup: 10000 + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.nginx.automountServiceAccountToken | default false }} +{{- with .Values.nginx.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: nginx +{{- end }} +{{- end }} + containers: + - name: nginx + image: "{{ .Values.nginx.image.repository }}:{{ .Values.nginx.image.tag }}" + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + {{- $_ := set . "scheme" "HTTP" -}} + {{- $_ := set . "port" "8080" -}} + {{- if .Values.expose.tls.enabled }} + {{- $_ := set . "scheme" "HTTPS" -}} + {{- $_ := set . "port" "8443" -}} + {{- end }} + livenessProbe: + httpGet: + scheme: {{ .scheme }} + path: / + port: {{ .port }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + scheme: {{ .scheme }} + path: / + port: {{ .port }} + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.nginx.resources }} + resources: +{{ toYaml .Values.nginx.resources | indent 10 }} +{{- end }} +{{- with .Values.nginx.extraEnvVars }} + env: +{{- toYaml . | nindent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + ports: + - containerPort: 8080 + {{- if .Values.expose.tls.enabled }} + - containerPort: 8443 + {{- end }} + volumeMounts: + - name: config + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + {{- if .Values.expose.tls.enabled }} + - name: certificate + mountPath: /etc/nginx/cert + {{- end }} + volumes: + - name: config + configMap: + name: {{ template "harbor.nginx" . }} + {{- if .Values.expose.tls.enabled }} + - name: certificate + secret: + secretName: {{ template "harbor.tlsSecretForNginx" . }} + {{- end }} + {{- with .Values.nginx.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.nginx.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.nginx.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.nginx.priorityClassName }} + priorityClassName: {{ .Values.nginx.priorityClassName }} + {{- end }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/nginx/secret.yaml b/packages/system/harbor/charts/harbor/templates/nginx/secret.yaml new file mode 100644 index 00000000..b855e7e9 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/nginx/secret.yaml @@ -0,0 +1,26 @@ +{{- if and (ne .Values.expose.type "ingress") (ne .Values.expose.type "route") (.Values.expose.tls.enabled) }} +{{- if eq (include "harbor.autoGenCertForNginx" .) "true" }} +{{- $ca := genCA "harbor-ca" 365 }} +{{- $cn := (required "The \"expose.tls.auto.commonName\" is required!" .Values.expose.tls.auto.commonName) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "harbor.nginx" . }} + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- if regexMatch `^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$` $cn }} + {{- $cert := genSignedCert $cn (list $cn) nil 365 $ca }} + tls.crt: {{ $cert.Cert | b64enc | quote }} + tls.key: {{ $cert.Key | b64enc | quote }} + ca.crt: {{ $ca.Cert | b64enc | quote }} + {{- else }} + {{- $cert := genSignedCert $cn nil (list $cn) 365 $ca }} + tls.crt: {{ $cert.Cert | b64enc | quote }} + tls.key: {{ $cert.Key | b64enc | quote }} + ca.crt: {{ $ca.Cert | b64enc | quote }} + {{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/nginx/service.yaml b/packages/system/harbor/charts/harbor/templates/nginx/service.yaml new file mode 100644 index 00000000..9554cd43 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/nginx/service.yaml @@ -0,0 +1,101 @@ +{{- if or (eq .Values.expose.type "clusterIP") (eq .Values.expose.type "nodePort") (eq .Values.expose.type "loadBalancer") }} +apiVersion: v1 +kind: Service +metadata: +{{- if eq .Values.expose.type "clusterIP" }} +{{- $clusterIP := .Values.expose.clusterIP }} + name: {{ $clusterIP.name }} + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- if .Values.expose.clusterIP.labels }} +{{ toYaml $clusterIP.labels | indent 4 }} +{{- end }} +{{- with $clusterIP.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + type: ClusterIP + {{- if .Values.expose.clusterIP.staticClusterIP }} + clusterIP: {{ .Values.expose.clusterIP.staticClusterIP }} + {{- end }} + {{- if .Values.ipFamily.policy }} + ipFamilyPolicy: {{ .Values.ipFamily.policy }} + {{- end }} + {{- if .Values.ipFamily.families }} + ipFamilies: {{ toYaml .Values.ipFamily.families }} + {{- end }} + ports: + - name: http + port: {{ $clusterIP.ports.httpPort }} + targetPort: 8080 + {{- if .Values.expose.tls.enabled }} + - name: https + port: {{ $clusterIP.ports.httpsPort }} + targetPort: 8443 + {{- end }} +{{- else if eq .Values.expose.type "nodePort" }} +{{- $nodePort := .Values.expose.nodePort }} + name: {{ $nodePort.name }} + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- if .Values.expose.nodePort.labels }} +{{ toYaml $nodePort.labels | indent 4 }} +{{- end }} +{{- with $nodePort.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + type: NodePort + ports: + - name: http + port: {{ $nodePort.ports.http.port }} + targetPort: 8080 + {{- if $nodePort.ports.http.nodePort }} + nodePort: {{ $nodePort.ports.http.nodePort }} + {{- end }} + {{- if .Values.expose.tls.enabled }} + - name: https + port: {{ $nodePort.ports.https.port }} + targetPort: 8443 + {{- if $nodePort.ports.https.nodePort }} + nodePort: {{ $nodePort.ports.https.nodePort }} + {{- end }} + {{- end }} +{{- else if eq .Values.expose.type "loadBalancer" }} +{{- $loadBalancer := .Values.expose.loadBalancer }} + name: {{ $loadBalancer.name }} + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- if .Values.expose.loadBalancer.labels }} +{{ toYaml $loadBalancer.labels | indent 4 }} +{{- end }} +{{- with $loadBalancer.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + type: LoadBalancer + {{- with $loadBalancer.sourceRanges }} + loadBalancerSourceRanges: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if $loadBalancer.IP }} + loadBalancerIP: {{ $loadBalancer.IP }} + {{- end }} + ports: + - name: http + port: {{ $loadBalancer.ports.httpPort }} + targetPort: 8080 + {{- if .Values.expose.tls.enabled }} + - name: https + port: {{ $loadBalancer.ports.httpsPort }} + targetPort: 8443 + {{- end }} +{{- end }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: nginx +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/portal/configmap.yaml b/packages/system/harbor/charts/harbor/templates/portal/configmap.yaml new file mode 100644 index 00000000..af56783a --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/portal/configmap.yaml @@ -0,0 +1,68 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.portal" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + nginx.conf: |+ + worker_processes auto; + pid /tmp/nginx.pid; + events { + worker_connections 1024; + } + http { + client_body_temp_path /tmp/client_body_temp; + proxy_temp_path /tmp/proxy_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + server { + {{- if .Values.internalTLS.enabled }} + {{- if .Values.ipFamily.ipv4.enabled}} + listen {{ template "harbor.portal.containerPort" . }} ssl; + {{- end }} + {{- if .Values.ipFamily.ipv6.enabled}} + listen [::]:{{ template "harbor.portal.containerPort" . }} ssl; + {{- end }} + # SSL + ssl_certificate /etc/harbor/ssl/portal/tls.crt; + ssl_certificate_key /etc/harbor/ssl/portal/tls.key; + + # Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html + ssl_protocols TLSv1.2 TLSv1.3; + {{- if .Values.internalTLS.strong_ssl_ciphers }} + ssl_ciphers ECDHE+AESGCM:DHE+AESGCM:ECDHE+RSA+SHA256:DHE+RSA+SHA256:!AES128; + {{ else }} + ssl_ciphers '!aNULL:kECDH+AESGCM:ECDH+AESGCM:RSA+AESGCM:kECDH+AES:ECDH+AES:RSA+AES:'; + {{- end }} + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + {{- else }} + {{- if .Values.ipFamily.ipv4.enabled }} + listen {{ template "harbor.portal.containerPort" . }}; + {{- end }} + {{- if .Values.ipFamily.ipv6.enabled}} + listen [::]:{{ template "harbor.portal.containerPort" . }}; + {{- end }} + {{- end }} + server_name localhost; + root /usr/share/nginx/html; + index index.html index.htm; + include /etc/nginx/mime.types; + gzip on; + gzip_min_length 1000; + gzip_proxied expired no-cache no-store private auth; + gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; + location /devcenter-api-2.0 { + try_files $uri $uri/ /swagger-ui-index.html; + } + location / { + try_files $uri $uri/ /index.html; + } + location = /index.html { + add_header Cache-Control "no-store, no-cache, must-revalidate"; + } + } + } diff --git a/packages/system/harbor/charts/harbor/templates/portal/deployment.yaml b/packages/system/harbor/charts/harbor/templates/portal/deployment.yaml new file mode 100644 index 00000000..88bcd497 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/portal/deployment.yaml @@ -0,0 +1,124 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ template "harbor.portal" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: portal + app.kubernetes.io/component: portal +spec: + replicas: {{ .Values.portal.replicas }} + revisionHistoryLimit: {{ .Values.portal.revisionHistoryLimit }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: portal + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: portal + app.kubernetes.io/component: portal +{{- if .Values.portal.podLabels }} +{{ toYaml .Values.portal.podLabels | indent 8 }} +{{- end }} + annotations: +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/portal/tls.yaml") . | sha256sum }} +{{- end }} + checksum/configmap: {{ include (print $.Template.BasePath "/portal/configmap.yaml") . | sha256sum }} +{{- if .Values.portal.podAnnotations }} +{{ toYaml .Values.portal.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 10000 + fsGroup: 10000 + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- if .Values.portal.serviceAccountName }} + serviceAccountName: {{ .Values.portal.serviceAccountName }} +{{- end }} + automountServiceAccountToken: {{ .Values.portal.automountServiceAccountToken | default false }} +{{- with .Values.portal.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: portal +{{- end }} +{{- end }} + {{- with .Values.portal.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: portal + image: {{ .Values.portal.image.repository }}:{{ .Values.portal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} +{{- if .Values.portal.resources }} + resources: +{{ toYaml .Values.portal.resources | indent 10 }} +{{- end }} +{{- with .Values.portal.extraEnvVars }} + env: +{{- toYaml . | nindent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + livenessProbe: + httpGet: + path: / + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.portal.containerPort" . }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.portal.containerPort" . }} + initialDelaySeconds: 1 + periodSeconds: 10 + ports: + - containerPort: {{ template "harbor.portal.containerPort" . }} + volumeMounts: + - name: portal-config + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + {{- if .Values.internalTLS.enabled }} + - name: portal-internal-certs + mountPath: /etc/harbor/ssl/portal + {{- end }} + volumes: + - name: portal-config + configMap: + name: "{{ template "harbor.portal" . }}" + {{- if .Values.internalTLS.enabled }} + - name: portal-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.portal.secretName" . }} + {{- end }} + {{- with .Values.portal.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.portal.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.portal.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.portal.priorityClassName }} + priorityClassName: {{ .Values.portal.priorityClassName }} + {{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/portal/service.yaml b/packages/system/harbor/charts/harbor/templates/portal/service.yaml new file mode 100644 index 00000000..2ce2482b --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/portal/service.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.portal" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +{{- with .Values.portal.serviceAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: +{{- if or (eq .Values.expose.ingress.controller "gce") (eq .Values.expose.ingress.controller "alb") (eq .Values.expose.ingress.controller "f5-bigip") }} + type: NodePort +{{- end }} +{{- if .Values.ipFamily.policy }} + ipFamilyPolicy: {{ .Values.ipFamily.policy }} +{{- end }} +{{- if .Values.ipFamily.families }} + ipFamilies: {{ toYaml .Values.ipFamily.families | nindent 4 }} +{{- end }} + ports: + - port: {{ template "harbor.portal.servicePort" . }} + targetPort: {{ template "harbor.portal.containerPort" . }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: portal diff --git a/packages/system/harbor/charts/harbor/templates/portal/tls.yaml b/packages/system/harbor/charts/harbor/templates/portal/tls.yaml new file mode 100644 index 00000000..e61a7d3a --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/portal/tls.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.internalTLS.enabled }} +{{- if eq .Values.internalTLS.certSource "manual" }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.portal.secretName" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ (required "The \"internalTLS.trustCa\" is required!" .Values.internalTLS.trustCa) | b64enc | quote }} + tls.crt: {{ (required "The \"internalTLS.portal.crt\" is required!" .Values.internalTLS.portal.crt) | b64enc | quote }} + tls.key: {{ (required "The \"internalTLS.portal.key\" is required!" .Values.internalTLS.portal.key) | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/redis/service.yaml b/packages/system/harbor/charts/harbor/templates/redis/service.yaml new file mode 100644 index 00000000..8bb8e85b --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/redis/service.yaml @@ -0,0 +1,21 @@ +{{- if eq .Values.redis.type "internal" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "harbor.redis" . }} + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: + {{- if .Values.ipFamily.policy }} + ipFamilyPolicy: {{ .Values.ipFamily.policy }} + {{- end }} + {{- if .Values.ipFamily.families }} + ipFamilies: {{ toYaml .Values.ipFamily.families }} + {{- end }} + ports: + - port: 6379 + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: redis +{{- end -}} diff --git a/packages/system/harbor/charts/harbor/templates/redis/statefulset.yaml b/packages/system/harbor/charts/harbor/templates/redis/statefulset.yaml new file mode 100644 index 00000000..2316f69b --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/redis/statefulset.yaml @@ -0,0 +1,128 @@ +{{- if eq .Values.redis.type "internal" -}} +{{- $redis := .Values.persistence.persistentVolumeClaim.redis -}} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ template "harbor.redis" . }} + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: redis + app.kubernetes.io/component: redis +spec: + replicas: 1 + serviceName: {{ template "harbor.redis" . }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: redis + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: redis + app.kubernetes.io/component: redis +{{- if .Values.redis.podLabels }} +{{ toYaml .Values.redis.podLabels | indent 8 }} +{{- end }} +{{- if .Values.redis.podAnnotations }} + annotations: +{{ toYaml .Values.redis.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 999 + fsGroup: 999 +{{- if .Values.redis.internal.serviceAccountName }} + serviceAccountName: {{ .Values.redis.internal.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.redis.internal.automountServiceAccountToken | default false }} + terminationGracePeriodSeconds: 120 + {{- with .Values.redis.internal.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: redis + image: {{ .Values.redis.internal.image.repository }}:{{ .Values.redis.internal.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + livenessProbe: + tcpSocket: + port: 6379 + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + tcpSocket: + port: 6379 + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.redis.internal.resources }} + resources: +{{ toYaml .Values.redis.internal.resources | indent 10 }} +{{- end }} +{{- with .Values.redis.internal.extraEnvVars }} + env: +{{- toYaml . | nindent 10 }} +{{- end }} + volumeMounts: + - name: data + mountPath: /var/lib/redis + subPath: {{ $redis.subPath }} + {{- if not .Values.persistence.enabled }} + volumes: + - name: data + emptyDir: {} + {{- else if $redis.existingClaim }} + volumes: + - name: data + persistentVolumeClaim: + claimName: {{ $redis.existingClaim }} + {{- end -}} + {{- with .Values.redis.internal.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.redis.internal.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.redis.internal.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.redis.internal.priorityClassName }} + priorityClassName: {{ .Values.redis.internal.priorityClassName }} + {{- end }} + {{- if and .Values.persistence.enabled (not $redis.existingClaim) }} + volumeClaimTemplates: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: data + labels: +{{ include "harbor.legacy.labels" . | indent 8 }} + annotations: + {{- range $key, $value := $redis.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + accessModes: [{{ $redis.accessMode | quote }}] + {{- if $redis.storageClass }} + {{- if (eq "-" $redis.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ $redis.storageClass }}" + {{- end }} + {{- end }} + resources: + requests: + storage: {{ $redis.size | quote }} + {{- end -}} + {{- end -}} diff --git a/packages/system/harbor/charts/harbor/templates/registry/registry-cm.yaml b/packages/system/harbor/charts/harbor/templates/registry/registry-cm.yaml new file mode 100644 index 00000000..2ef398ed --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/registry/registry-cm.yaml @@ -0,0 +1,248 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.registry" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + config.yml: |+ + version: 0.1 + log: + {{- if eq .Values.logLevel "warning" }} + level: warn + {{- else if eq .Values.logLevel "fatal" }} + level: error + {{- else }} + level: {{ .Values.logLevel }} + {{- end }} + fields: + service: registry + storage: + {{- $storage := .Values.persistence.imageChartStorage }} + {{- $type := $storage.type }} + {{- if eq $type "filesystem" }} + filesystem: + rootdirectory: {{ $storage.filesystem.rootdirectory }} + {{- if $storage.filesystem.maxthreads }} + maxthreads: {{ $storage.filesystem.maxthreads }} + {{- end }} + {{- else if eq $type "azure" }} + azure: + accountname: {{ $storage.azure.accountname }} + container: {{ $storage.azure.container }} + {{- if $storage.azure.realm }} + realm: {{ $storage.azure.realm }} + {{- end }} + {{- else if eq $type "gcs" }} + gcs: + bucket: {{ $storage.gcs.bucket }} + {{- if not .Values.persistence.imageChartStorage.gcs.useWorkloadIdentity }} + keyfile: /etc/registry/gcs-key.json + {{- end }} + {{- if $storage.gcs.rootdirectory }} + rootdirectory: {{ $storage.gcs.rootdirectory }} + {{- end }} + {{- if $storage.gcs.chunksize }} + chunksize: {{ $storage.gcs.chunksize }} + {{- end }} + {{- else if eq $type "s3" }} + s3: + region: {{ $storage.s3.region }} + bucket: {{ $storage.s3.bucket }} + {{- if $storage.s3.regionendpoint }} + regionendpoint: {{ $storage.s3.regionendpoint }} + {{- end }} + {{- if $storage.s3.encrypt }} + encrypt: {{ $storage.s3.encrypt }} + {{- end }} + {{- if $storage.s3.keyid }} + keyid: {{ $storage.s3.keyid }} + {{- end }} + {{- if $storage.s3.secure }} + secure: {{ $storage.s3.secure }} + {{- end }} + {{- if and $storage.s3.secure $storage.s3.skipverify }} + skipverify: {{ $storage.s3.skipverify }} + {{- end }} + {{- if $storage.s3.v4auth }} + v4auth: {{ $storage.s3.v4auth }} + {{- end }} + {{- if $storage.s3.chunksize }} + chunksize: {{ $storage.s3.chunksize }} + {{- end }} + {{- if $storage.s3.rootdirectory }} + rootdirectory: {{ $storage.s3.rootdirectory }} + {{- end }} + {{- if $storage.s3.storageclass }} + storageclass: {{ $storage.s3.storageclass }} + {{- end }} + {{- if $storage.s3.multipartcopychunksize }} + multipartcopychunksize: {{ $storage.s3.multipartcopychunksize }} + {{- end }} + {{- if $storage.s3.multipartcopymaxconcurrency }} + multipartcopymaxconcurrency: {{ $storage.s3.multipartcopymaxconcurrency }} + {{- end }} + {{- if $storage.s3.multipartcopythresholdsize }} + multipartcopythresholdsize: {{ $storage.s3.multipartcopythresholdsize }} + {{- end }} + {{- else if eq $type "swift" }} + swift: + authurl: {{ $storage.swift.authurl }} + username: {{ $storage.swift.username }} + container: {{ $storage.swift.container }} + {{- if $storage.swift.region }} + region: {{ $storage.swift.region }} + {{- end }} + {{- if $storage.swift.tenant }} + tenant: {{ $storage.swift.tenant }} + {{- end }} + {{- if $storage.swift.tenantid }} + tenantid: {{ $storage.swift.tenantid }} + {{- end }} + {{- if $storage.swift.domain }} + domain: {{ $storage.swift.domain }} + {{- end }} + {{- if $storage.swift.domainid }} + domainid: {{ $storage.swift.domainid }} + {{- end }} + {{- if $storage.swift.trustid }} + trustid: {{ $storage.swift.trustid }} + {{- end }} + {{- if $storage.swift.insecureskipverify }} + insecureskipverify: {{ $storage.swift.insecureskipverify }} + {{- end }} + {{- if $storage.swift.chunksize }} + chunksize: {{ $storage.swift.chunksize }} + {{- end }} + {{- if $storage.swift.prefix }} + prefix: {{ $storage.swift.prefix }} + {{- end }} + {{- if $storage.swift.authversion }} + authversion: {{ $storage.swift.authversion }} + {{- end }} + {{- if $storage.swift.endpointtype }} + endpointtype: {{ $storage.swift.endpointtype }} + {{- end }} + {{- if $storage.swift.tempurlcontainerkey }} + tempurlcontainerkey: {{ $storage.swift.tempurlcontainerkey }} + {{- end }} + {{- if $storage.swift.tempurlmethods }} + tempurlmethods: {{ $storage.swift.tempurlmethods }} + {{- end }} + {{- else if eq $type "oss" }} + oss: + accesskeyid: {{ $storage.oss.accesskeyid }} + region: {{ $storage.oss.region }} + bucket: {{ $storage.oss.bucket }} + {{- if $storage.oss.endpoint }} + endpoint: {{ $storage.oss.bucket }}.{{ $storage.oss.endpoint }} + {{- end }} + {{- if $storage.oss.internal }} + internal: {{ $storage.oss.internal }} + {{- end }} + {{- if $storage.oss.encrypt }} + encrypt: {{ $storage.oss.encrypt }} + {{- end }} + {{- if $storage.oss.secure }} + secure: {{ $storage.oss.secure }} + {{- end }} + {{- if $storage.oss.chunksize }} + chunksize: {{ $storage.oss.chunksize }} + {{- end }} + {{- if $storage.oss.rootdirectory }} + rootdirectory: {{ $storage.oss.rootdirectory }} + {{- end }} + {{- end }} + cache: + layerinfo: redis + maintenance: + uploadpurging: + {{- if .Values.registry.upload_purging.enabled }} + enabled: true + age: {{ .Values.registry.upload_purging.age }} + interval: {{ .Values.registry.upload_purging.interval }} + dryrun: {{ .Values.registry.upload_purging.dryrun }} + {{- else }} + enabled: false + {{- end }} + delete: + enabled: true + redirect: + disable: {{ $storage.disableredirect }} + redis: + addr: {{ template "harbor.redis.addr" . }} + {{- if eq "redis+sentinel" (include "harbor.redis.scheme" .) }} + sentinelMasterSet: {{ template "harbor.redis.masterSet" . }} + {{- end }} + db: {{ template "harbor.redis.dbForRegistry" . }} + {{- if not (eq (include "harbor.redis.password" .) "") }} + password: {{ template "harbor.redis.password" . }} + {{- end }} + readtimeout: 10s + writetimeout: 10s + dialtimeout: 10s + enableTLS: {{ template "harbor.redis.enableTLS" . }} + pool: + maxidle: 100 + maxactive: 500 + idletimeout: 60s + http: + addr: :{{ template "harbor.registry.containerPort" . }} + relativeurls: {{ .Values.registry.relativeurls }} + {{- if .Values.internalTLS.enabled }} + tls: + certificate: /etc/harbor/ssl/registry/tls.crt + key: /etc/harbor/ssl/registry/tls.key + minimumtls: tls1.2 + {{- end }} + # set via environment variable + # secret: placeholder + debug: + {{- if .Values.metrics.enabled}} + addr: :{{ .Values.metrics.registry.port }} + prometheus: + enabled: true + path: {{ .Values.metrics.registry.path }} + {{- else }} + addr: localhost:5001 + {{- end }} + auth: + htpasswd: + realm: harbor-registry-basic-realm + path: /etc/registry/passwd + validation: + disabled: true + compatibility: + schema1: + enabled: true + + {{- if .Values.registry.middleware.enabled }} + {{- $middleware := .Values.registry.middleware }} + {{- $middlewareType := $middleware.type }} + {{- if eq $middlewareType "cloudFront" }} + middleware: + storage: + - name: cloudfront + options: + baseurl: {{ $middleware.cloudFront.baseurl }} + privatekey: /etc/registry/pk.pem + keypairid: {{ $middleware.cloudFront.keypairid }} + duration: {{ $middleware.cloudFront.duration }} + ipfilteredby: {{ $middleware.cloudFront.ipfilteredby }} + {{- end }} + {{- end }} + ctl-config.yml: |+ + --- + {{- if .Values.internalTLS.enabled }} + protocol: "https" + port: 8443 + https_config: + cert: "/etc/harbor/ssl/registry/tls.crt" + key: "/etc/harbor/ssl/registry/tls.key" + {{- else }} + protocol: "http" + port: 8080 + {{- end }} + log_level: {{ .Values.logLevel }} + registry_config: "/etc/registry/config.yml" diff --git a/packages/system/harbor/charts/harbor/templates/registry/registry-dpl.yaml b/packages/system/harbor/charts/harbor/templates/registry/registry-dpl.yaml new file mode 100644 index 00000000..a86e2eee --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/registry/registry-dpl.yaml @@ -0,0 +1,431 @@ +{{- $storage := .Values.persistence.imageChartStorage }} +{{- $type := $storage.type }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ template "harbor.registry" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: registry + app.kubernetes.io/component: registry +spec: + replicas: {{ .Values.registry.replicas }} + revisionHistoryLimit: {{ .Values.registry.revisionHistoryLimit }} + strategy: + type: {{ .Values.updateStrategy.type }} + {{- if eq .Values.updateStrategy.type "Recreate" }} + rollingUpdate: null + {{- end }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: registry + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: registry + app.kubernetes.io/component: registry +{{- if .Values.registry.podLabels }} +{{ toYaml .Values.registry.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/registry/registry-cm.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/registry/registry-secret.yaml") . | sha256sum }} + checksum/secret-jobservice: {{ include (print $.Template.BasePath "/jobservice/jobservice-secrets.yaml") . | sha256sum }} + checksum/secret-core: {{ include (print $.Template.BasePath "/core/core-secret.yaml") . | sha256sum }} +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/registry/registry-tls.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.registry.podAnnotations }} +{{ toYaml .Values.registry.podAnnotations | indent 8 }} +{{- end }} + spec: + securityContext: + runAsUser: 10000 + fsGroup: 10000 + fsGroupChangePolicy: OnRootMismatch +{{- if .Values.registry.serviceAccountName }} + serviceAccountName: {{ .Values.registry.serviceAccountName }} +{{- end -}} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.registry.automountServiceAccountToken | default false }} + terminationGracePeriodSeconds: 120 +{{- with .Values.registry.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: registry +{{- end }} +{{- end }} + {{- with .Values.registry.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: registry + image: {{ .Values.registry.registry.image.repository }}:{{ .Values.registry.registry.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: / + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.registry.containerPort" . }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.registry.containerPort" . }} + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.registry.registry.resources }} + resources: +{{ toYaml .Values.registry.registry.resources | indent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + envFrom: + - secretRef: + name: "{{ template "harbor.registry" . }}" + {{- if .Values.persistence.imageChartStorage.s3.existingSecret }} + - secretRef: + name: {{ .Values.persistence.imageChartStorage.s3.existingSecret }} + {{- end }} + env: + {{- if .Values.registry.existingSecret }} + - name: REGISTRY_HTTP_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.registry.existingSecret }} + key: {{ .Values.registry.existingSecretKey }} + {{- end }} + {{- if has "registry" .Values.proxy.components }} + - name: HTTP_PROXY + value: "{{ .Values.proxy.httpProxy }}" + - name: HTTPS_PROXY + value: "{{ .Values.proxy.httpsProxy }}" + - name: NO_PROXY + value: "{{ template "harbor.noProxy" . }}" + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: INTERNAL_TLS_ENABLED + value: "true" + - name: INTERNAL_TLS_KEY_PATH + value: /etc/harbor/ssl/registry/tls.key + - name: INTERNAL_TLS_CERT_PATH + value: /etc/harbor/ssl/registry/tls.crt + - name: INTERNAL_TLS_TRUST_CA_PATH + value: /etc/harbor/ssl/registry/ca.crt + {{- end }} + {{- if .Values.redis.external.existingSecret }} + - name: REGISTRY_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.redis.external.existingSecret }} + key: REDIS_PASSWORD + {{- end }} + {{- if .Values.persistence.imageChartStorage.azure.existingSecret }} + - name: REGISTRY_STORAGE_AZURE_ACCOUNTKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.azure.existingSecret }} + key: AZURE_STORAGE_ACCESS_KEY + {{- end }} + {{- if .Values.persistence.imageChartStorage.swift.existingSecret }} + - name: REGISTRY_STORAGE_SWIFT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_PASSWORD + - name: REGISTRY_STORAGE_SWIFT_SECRETKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_SECRETKEY + optional: true + - name: REGISTRY_STORAGE_SWIFT_ACCESSKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_ACCESSKEY + optional: true + {{- end }} + {{- if .Values.persistence.imageChartStorage.oss.existingSecret }} + - name: REGISTRY_STORAGE_OSS_ACCESSKEYSECRET + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.oss.existingSecret }} + key: REGISTRY_STORAGE_OSS_ACCESSKEYSECRET + optional: true + {{- end}} +{{- with .Values.registry.registry.extraEnvVars }} +{{- toYaml . | nindent 8 }} +{{- end }} + ports: + - containerPort: {{ template "harbor.registry.containerPort" . }} + - containerPort: {{ ternary .Values.metrics.registry.port 5001 .Values.metrics.enabled }} + volumeMounts: + - name: registry-data + mountPath: {{ .Values.persistence.imageChartStorage.filesystem.rootdirectory }} + subPath: {{ .Values.persistence.persistentVolumeClaim.registry.subPath }} + - name: registry-htpasswd + mountPath: /etc/registry/passwd + subPath: passwd + - name: registry-config + mountPath: /etc/registry/config.yml + subPath: config.yml + {{- if .Values.internalTLS.enabled }} + - name: registry-internal-certs + mountPath: /etc/harbor/ssl/registry + {{- end }} + {{- if and (and .Values.persistence.enabled (eq .Values.persistence.imageChartStorage.type "gcs")) (not .Values.persistence.imageChartStorage.gcs.useWorkloadIdentity) }} + - name: gcs-key + mountPath: /etc/registry/gcs-key.json + subPath: gcs-key.json + {{- end }} + {{- if .Values.persistence.imageChartStorage.caBundleSecretName }} + - name: storage-service-ca + mountPath: /harbor_cust_cert/custom-ca-bundle.crt + subPath: ca.crt + {{- end }} + {{- if .Values.registry.middleware.enabled }} + {{- if eq .Values.registry.middleware.type "cloudFront" }} + - name: cloudfront-key + mountPath: /etc/registry/pk.pem + subPath: pk.pem + {{- end }} + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 8 }} + {{- end }} + - name: registryctl + image: {{ .Values.registry.controller.image.repository }}:{{ .Values.registry.controller.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + httpGet: + path: /api/health + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.registryctl.containerPort" . }} + initialDelaySeconds: 300 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /api/health + scheme: {{ include "harbor.component.scheme" . | upper }} + port: {{ template "harbor.registryctl.containerPort" . }} + initialDelaySeconds: 1 + periodSeconds: 10 +{{- if .Values.registry.controller.resources }} + resources: +{{ toYaml .Values.registry.controller.resources | indent 10 }} +{{- end }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 10 }} + {{- end }} + envFrom: + - configMapRef: + name: "{{ template "harbor.registryCtl" . }}" + - secretRef: + name: "{{ template "harbor.registry" . }}" + - secretRef: + name: "{{ template "harbor.registryCtl" . }}" + {{- if .Values.persistence.imageChartStorage.s3.existingSecret }} + - secretRef: + name: {{ .Values.persistence.imageChartStorage.s3.existingSecret }} + {{- end }} + env: + {{- if .Values.registry.existingSecret }} + - name: REGISTRY_HTTP_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.registry.existingSecret }} + key: {{ .Values.registry.existingSecretKey }} + {{- end }} + - name: CORE_SECRET + valueFrom: + secretKeyRef: + name: {{ default (include "harbor.core" .) .Values.core.existingSecret }} + key: secret + - name: JOBSERVICE_SECRET + valueFrom: + secretKeyRef: + name: {{ default (include "harbor.jobservice" .) .Values.jobservice.existingSecret }} + {{- if .Values.jobservice.existingSecret }} + key: {{ .Values.jobservice.existingSecretKey }} + {{- else }} + key: JOBSERVICE_SECRET + {{- end }} + {{- if has "registry" .Values.proxy.components }} + - name: HTTP_PROXY + value: "{{ .Values.proxy.httpProxy }}" + - name: HTTPS_PROXY + value: "{{ .Values.proxy.httpsProxy }}" + - name: NO_PROXY + value: "{{ template "harbor.noProxy" . }}" + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: INTERNAL_TLS_ENABLED + value: "true" + - name: INTERNAL_TLS_KEY_PATH + value: /etc/harbor/ssl/registry/tls.key + - name: INTERNAL_TLS_CERT_PATH + value: /etc/harbor/ssl/registry/tls.crt + - name: INTERNAL_TLS_TRUST_CA_PATH + value: /etc/harbor/ssl/registry/ca.crt + {{- end }} + {{- if .Values.redis.external.existingSecret }} + - name: REGISTRY_REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.redis.external.existingSecret }} + key: REDIS_PASSWORD + {{- end }} + {{- if .Values.persistence.imageChartStorage.azure.existingSecret }} + - name: REGISTRY_STORAGE_AZURE_ACCOUNTKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.azure.existingSecret }} + key: AZURE_STORAGE_ACCESS_KEY + {{- end }} + {{- if .Values.persistence.imageChartStorage.swift.existingSecret }} + - name: REGISTRY_STORAGE_SWIFT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_PASSWORD + - name: REGISTRY_STORAGE_SWIFT_SECRETKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_SECRETKEY + optional: true + - name: REGISTRY_STORAGE_SWIFT_ACCESSKEY + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.swift.existingSecret }} + key: REGISTRY_STORAGE_SWIFT_ACCESSKEY + optional: true + {{- end }} + {{- if .Values.persistence.imageChartStorage.oss.existingSecret }} + - name: REGISTRY_STORAGE_OSS_ACCESSKEYSECRET + valueFrom: + secretKeyRef: + name: {{ .Values.persistence.imageChartStorage.oss.existingSecret }} + key: REGISTRY_STORAGE_OSS_ACCESSKEYSECRET + optional: true + {{- end}} +{{- with .Values.registry.controller.extraEnvVars }} +{{- toYaml . | nindent 8 }} +{{- end }} + ports: + - containerPort: {{ template "harbor.registryctl.containerPort" . }} + volumeMounts: + - name: registry-data + mountPath: {{ .Values.persistence.imageChartStorage.filesystem.rootdirectory }} + subPath: {{ .Values.persistence.persistentVolumeClaim.registry.subPath }} + - name: registry-config + mountPath: /etc/registry/config.yml + subPath: config.yml + - name: registry-config + mountPath: /etc/registryctl/config.yml + subPath: ctl-config.yml + {{- if .Values.internalTLS.enabled }} + - name: registry-internal-certs + mountPath: /etc/harbor/ssl/registry + {{- end }} + {{- if .Values.persistence.imageChartStorage.caBundleSecretName }} + - name: storage-service-ca + mountPath: /harbor_cust_cert/custom-ca-bundle.crt + subPath: ca.crt + {{- end }} + {{- if and (and .Values.persistence.enabled (eq .Values.persistence.imageChartStorage.type "gcs")) (not .Values.persistence.imageChartStorage.gcs.useWorkloadIdentity ) }} + - name: gcs-key + mountPath: /etc/registry/gcs-key.json + subPath: gcs-key.json + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 8 }} + {{- end }} + volumes: + - name: registry-htpasswd + secret: + {{- if not .Values.registry.credentials.existingSecret }} + secretName: {{ template "harbor.registry" . }}-htpasswd + {{ else }} + secretName: {{ .Values.registry.credentials.existingSecret }} + {{- end }} + items: + - key: REGISTRY_HTPASSWD + path: passwd + - name: registry-config + configMap: + name: "{{ template "harbor.registry" . }}" + - name: registry-data + {{- if and .Values.persistence.enabled (eq .Values.persistence.imageChartStorage.type "filesystem") }} + persistentVolumeClaim: + claimName: {{ .Values.persistence.persistentVolumeClaim.registry.existingClaim | default (include "harbor.registry" .) }} + {{- else }} + emptyDir: {} + {{- end }} + {{- if .Values.internalTLS.enabled }} + - name: registry-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.registry.secretName" . }} + {{- end }} + {{- if and (and .Values.persistence.enabled (eq .Values.persistence.imageChartStorage.type "gcs")) (not .Values.persistence.imageChartStorage.gcs.useWorkloadIdentity ) }} + - name: gcs-key + secret: + {{- if and (eq $type "gcs") $storage.gcs.existingSecret }} + secretName: {{ $storage.gcs.existingSecret }} + {{- else }} + secretName: {{ template "harbor.registry" . }} + {{- end }} + items: + - key: GCS_KEY_DATA + path: gcs-key.json + {{- end }} + {{- if .Values.persistence.imageChartStorage.caBundleSecretName }} + - name: storage-service-ca + secret: + secretName: {{ .Values.persistence.imageChartStorage.caBundleSecretName }} + {{- end }} + {{- if .Values.registry.middleware.enabled }} + {{- if eq .Values.registry.middleware.type "cloudFront" }} + - name: cloudfront-key + secret: + secretName: {{ .Values.registry.middleware.cloudFront.privateKeySecret }} + items: + - key: CLOUDFRONT_KEY_DATA + path: pk.pem + {{- end }} + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolume" . | indent 6 }} + {{- end }} + {{- with .Values.registry.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.registry.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.registry.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.registry.priorityClassName }} + priorityClassName: {{ .Values.registry.priorityClassName }} + {{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/registry/registry-pvc.yaml b/packages/system/harbor/charts/harbor/templates/registry/registry-pvc.yaml new file mode 100644 index 00000000..712c2117 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/registry/registry-pvc.yaml @@ -0,0 +1,34 @@ +{{- if .Values.persistence.enabled }} +{{- $registry := .Values.persistence.persistentVolumeClaim.registry -}} +{{- if and (not $registry.existingClaim) (eq .Values.persistence.imageChartStorage.type "filesystem") }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ template "harbor.registry" . }} + namespace: {{ .Release.Namespace | quote }} + annotations: + {{- range $key, $value := $registry.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- if eq .Values.persistence.resourcePolicy "keep" }} + helm.sh/resource-policy: keep + {{- end }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: registry + app.kubernetes.io/component: registry +spec: + accessModes: + - {{ $registry.accessMode }} + resources: + requests: + storage: {{ $registry.size }} + {{- if $registry.storageClass }} + {{- if eq "-" $registry.storageClass }} + storageClassName: "" + {{- else }} + storageClassName: {{ $registry.storageClass }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/registry/registry-secret.yaml b/packages/system/harbor/charts/harbor/templates/registry/registry-secret.yaml new file mode 100644 index 00000000..11ada3b7 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/registry/registry-secret.yaml @@ -0,0 +1,57 @@ +{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace (include "harbor.registry" .) }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.registry" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- if not .Values.registry.existingSecret }} + REGISTRY_HTTP_SECRET: {{ .Values.registry.secret | default (include "harbor.secretKeyHelper" (dict "key" "REGISTRY_HTTP_SECRET" "data" $existingSecret.data)) | default (randAlphaNum 16) | b64enc | quote }} + {{- end }} + {{- if not .Values.redis.external.existingSecret }} + REGISTRY_REDIS_PASSWORD: {{ include "harbor.redis.password" . | b64enc | quote }} + {{- end }} + {{- $storage := .Values.persistence.imageChartStorage }} + {{- $type := $storage.type }} + {{- if and (eq $type "azure") (not $storage.azure.existingSecret) }} + REGISTRY_STORAGE_AZURE_ACCOUNTKEY: {{ $storage.azure.accountkey | b64enc | quote }} + {{- else if and (and (eq $type "gcs") (not $storage.gcs.existingSecret)) (not $storage.gcs.useWorkloadIdentity) }} + GCS_KEY_DATA: {{ $storage.gcs.encodedkey | quote }} + {{- else if eq $type "s3" }} + {{- if and (not $storage.s3.existingSecret) ($storage.s3.accesskey) }} + REGISTRY_STORAGE_S3_ACCESSKEY: {{ $storage.s3.accesskey | b64enc | quote }} + {{- end }} + {{- if and (not $storage.s3.existingSecret) ($storage.s3.secretkey) }} + REGISTRY_STORAGE_S3_SECRETKEY: {{ $storage.s3.secretkey | b64enc | quote }} + {{- end }} + {{- else if and (eq $type "swift") (not ($storage.swift.existingSecret)) }} + REGISTRY_STORAGE_SWIFT_PASSWORD: {{ $storage.swift.password | b64enc | quote }} + {{- if $storage.swift.secretkey }} + REGISTRY_STORAGE_SWIFT_SECRETKEY: {{ $storage.swift.secretkey | b64enc | quote }} + {{- end }} + {{- if $storage.swift.accesskey }} + REGISTRY_STORAGE_SWIFT_ACCESSKEY: {{ $storage.swift.accesskey | b64enc | quote }} + {{- end }} + {{- else if and (eq $type "oss") ((not ($storage.oss.existingSecret))) }} + REGISTRY_STORAGE_OSS_ACCESSKEYSECRET: {{ $storage.oss.accesskeysecret | b64enc | quote }} + {{- end }} +{{- if not .Values.registry.credentials.existingSecret }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.registry" . }}-htpasswd" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- if .Values.registry.credentials.htpasswdString }} + REGISTRY_HTPASSWD: {{ .Values.registry.credentials.htpasswdString | b64enc | quote }} + {{- else }} + REGISTRY_HTPASSWD: {{ htpasswd .Values.registry.credentials.username .Values.registry.credentials.password | b64enc | quote }} + {{- end }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/registry/registry-svc.yaml b/packages/system/harbor/charts/harbor/templates/registry/registry-svc.yaml new file mode 100644 index 00000000..7e30c478 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/registry/registry-svc.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.registry" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: +{{- if .Values.ipFamily.policy }} + ipFamilyPolicy: {{ .Values.ipFamily.policy }} +{{- end }} +{{- if .Values.ipFamily.families }} + ipFamilies: {{ toYaml .Values.ipFamily.families | nindent 4 }} +{{- end }} + ports: + - name: {{ ternary "https-registry" "http-registry" .Values.internalTLS.enabled }} + port: {{ template "harbor.registry.servicePort" . }} + + - name: {{ ternary "https-controller" "http-controller" .Values.internalTLS.enabled }} + port: {{ template "harbor.registryctl.servicePort" . }} +{{- if .Values.metrics.enabled}} + - name: {{ template "harbor.metricsPortName" . }} + port: {{ .Values.metrics.registry.port }} +{{- end }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: registry diff --git a/packages/system/harbor/charts/harbor/templates/registry/registry-tls.yaml b/packages/system/harbor/charts/harbor/templates/registry/registry-tls.yaml new file mode 100644 index 00000000..ec4540c2 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/registry/registry-tls.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.internalTLS.enabled }} +{{- if eq .Values.internalTLS.certSource "manual" }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.registry.secretName" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ (required "The \"internalTLS.trustCa\" is required!" .Values.internalTLS.trustCa) | b64enc | quote }} + tls.crt: {{ (required "The \"internalTLS.registry.crt\" is required!" .Values.internalTLS.registry.crt) | b64enc | quote }} + tls.key: {{ (required "The \"internalTLS.registry.key\" is required!" .Values.internalTLS.registry.key) | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/registry/registryctl-cm.yaml b/packages/system/harbor/charts/harbor/templates/registry/registryctl-cm.yaml new file mode 100644 index 00000000..61b2c5e1 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/registry/registryctl-cm.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ template "harbor.registryCtl" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +data: + {{- template "harbor.traceEnvsForRegistryCtl" . }} diff --git a/packages/system/harbor/charts/harbor/templates/registry/registryctl-secret.yaml b/packages/system/harbor/charts/harbor/templates/registry/registryctl-secret.yaml new file mode 100644 index 00000000..324a2e03 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/registry/registryctl-secret.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.registryCtl" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + {{- template "harbor.traceJaegerPassword" . }} diff --git a/packages/system/harbor/charts/harbor/templates/trivy/trivy-secret.yaml b/packages/system/harbor/charts/harbor/templates/trivy/trivy-secret.yaml new file mode 100644 index 00000000..b13f8800 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/trivy/trivy-secret.yaml @@ -0,0 +1,13 @@ +{{- if .Values.trivy.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "harbor.trivy" . }} + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: Opaque +data: + redisURL: {{ include "harbor.redis.urlForTrivy" . | b64enc }} + gitHubToken: {{ .Values.trivy.gitHubToken | default "" | b64enc | quote }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/trivy/trivy-sts.yaml b/packages/system/harbor/charts/harbor/templates/trivy/trivy-sts.yaml new file mode 100644 index 00000000..19b01a2e --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/trivy/trivy-sts.yaml @@ -0,0 +1,237 @@ +{{- if .Values.trivy.enabled }} +{{- $trivy := .Values.persistence.persistentVolumeClaim.trivy }} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ template "harbor.trivy" . }} + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} + component: trivy + app.kubernetes.io/component: trivy +spec: + replicas: {{ .Values.trivy.replicas }} + serviceName: {{ template "harbor.trivy" . }} + selector: + matchLabels: +{{ include "harbor.matchLabels" . | indent 6 }} + component: trivy + template: + metadata: + labels: +{{ include "harbor.labels" . | indent 8 }} + component: trivy + app.kubernetes.io/component: trivy +{{- if .Values.trivy.podLabels }} +{{ toYaml .Values.trivy.podLabels | indent 8 }} +{{- end }} + annotations: + checksum/secret: {{ include (print $.Template.BasePath "/trivy/trivy-secret.yaml") . | sha256sum }} +{{- if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "auto") }} + checksum/tls: {{ include (print $.Template.BasePath "/internal/auto-tls.yaml") . | sha256sum }} +{{- else if and .Values.internalTLS.enabled (eq .Values.internalTLS.certSource "manual") }} + checksum/tls: {{ include (print $.Template.BasePath "/trivy/trivy-tls.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.trivy.podAnnotations }} +{{ toYaml .Values.trivy.podAnnotations | indent 8 }} +{{- end }} + spec: +{{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} +{{- end }} +{{- if .Values.trivy.serviceAccountName }} + serviceAccountName: {{ .Values.trivy.serviceAccountName }} +{{- end }} + securityContext: + runAsUser: 10000 + fsGroup: 10000 + automountServiceAccountToken: {{ .Values.trivy.automountServiceAccountToken | default false }} +{{- with .Values.trivy.topologySpreadConstraints}} + topologySpreadConstraints: +{{- range . }} + - {{ . | toYaml | indent 8 | trim }} + labelSelector: + matchLabels: +{{ include "harbor.matchLabels" $ | indent 12 }} + component: trivy +{{- end }} +{{- end }} + {{- with .Values.trivy.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: trivy + image: {{ .Values.trivy.image.repository }}:{{ .Values.trivy.image.tag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if not (empty .Values.containerSecurityContext) }} + securityContext: {{ .Values.containerSecurityContext | toYaml | nindent 12 }} + {{- end }} + env: + {{- if has "trivy" .Values.proxy.components }} + - name: HTTP_PROXY + value: "{{ .Values.proxy.httpProxy }}" + - name: HTTPS_PROXY + value: "{{ .Values.proxy.httpsProxy }}" + - name: NO_PROXY + value: "{{ template "harbor.noProxy" . }}" + {{- end }} + - name: "SCANNER_LOG_LEVEL" + value: {{ .Values.logLevel | quote }} + - name: "SCANNER_TRIVY_CACHE_DIR" + value: "/home/scanner/.cache/trivy" + - name: "SCANNER_TRIVY_REPORTS_DIR" + value: "/home/scanner/.cache/reports" + - name: "SCANNER_TRIVY_DEBUG_MODE" + value: {{ .Values.trivy.debugMode | quote }} + - name: "SCANNER_TRIVY_VULN_TYPE" + value: {{ .Values.trivy.vulnType | quote }} + - name: "SCANNER_TRIVY_TIMEOUT" + value: {{ .Values.trivy.timeout | quote }} + - name: "SCANNER_TRIVY_GITHUB_TOKEN" + valueFrom: + secretKeyRef: + name: {{ template "harbor.trivy" . }} + key: gitHubToken + - name: "SCANNER_TRIVY_SEVERITY" + value: {{ .Values.trivy.severity | quote }} + - name: "SCANNER_TRIVY_IGNORE_UNFIXED" + value: {{ .Values.trivy.ignoreUnfixed | default false | quote }} + - name: "SCANNER_TRIVY_SKIP_UPDATE" + value: {{ .Values.trivy.skipUpdate | default false | quote }} + - name: "SCANNER_TRIVY_SKIP_JAVA_DB_UPDATE" + value: {{ .Values.trivy.skipJavaDBUpdate | default false | quote }} + - name: "SCANNER_TRIVY_DB_REPOSITORY" + value: {{ .Values.trivy.dbRepository | join "," | quote }} + - name: "SCANNER_TRIVY_JAVA_DB_REPOSITORY" + value: {{ .Values.trivy.javaDBRepository | join "," | quote }} + - name: "SCANNER_TRIVY_OFFLINE_SCAN" + value: {{ .Values.trivy.offlineScan | default false | quote }} + - name: "SCANNER_TRIVY_SECURITY_CHECKS" + value: {{ .Values.trivy.securityCheck | quote }} + - name: "SCANNER_TRIVY_INSECURE" + value: {{ .Values.trivy.insecure | default false | quote }} + - name: SCANNER_API_SERVER_ADDR + value: ":{{ template "harbor.trivy.containerPort" . }}" + {{- if .Values.internalTLS.enabled }} + - name: INTERNAL_TLS_ENABLED + value: "true" + - name: SCANNER_API_SERVER_TLS_KEY + value: /etc/harbor/ssl/trivy/tls.key + - name: SCANNER_API_SERVER_TLS_CERTIFICATE + value: /etc/harbor/ssl/trivy/tls.crt + {{- end }} + - name: "SCANNER_REDIS_URL" + valueFrom: + secretKeyRef: + name: {{ template "harbor.trivy" . }} + key: redisURL + - name: "SCANNER_STORE_REDIS_URL" + valueFrom: + secretKeyRef: + name: {{ template "harbor.trivy" . }} + key: redisURL + - name: "SCANNER_JOB_QUEUE_REDIS_URL" + valueFrom: + secretKeyRef: + name: {{ template "harbor.trivy" . }} + key: redisURL +{{- with .Values.trivy.extraEnvVars }} +{{- toYaml . | nindent 12 }} +{{- end }} + ports: + - name: api-server + containerPort: {{ template "harbor.trivy.containerPort" . }} + volumeMounts: + - name: data + mountPath: /home/scanner/.cache + subPath: {{ .Values.persistence.persistentVolumeClaim.trivy.subPath }} + readOnly: false + {{- if .Values.internalTLS.enabled }} + - name: trivy-internal-certs + mountPath: /etc/harbor/ssl/trivy + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolumeMount" . | indent 10 }} + {{- end }} + livenessProbe: + httpGet: + scheme: {{ include "harbor.component.scheme" . | upper }} + path: /probe/healthy + port: api-server + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + failureThreshold: 10 + readinessProbe: + httpGet: + scheme: {{ include "harbor.component.scheme" . | upper }} + path: /probe/ready + port: api-server + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + failureThreshold: 3 + resources: +{{ toYaml .Values.trivy.resources | indent 12 }} + {{- if or (or .Values.internalTLS.enabled .Values.caBundleSecretName) (or (not .Values.persistence.enabled) $trivy.existingClaim) }} + volumes: + {{- if .Values.internalTLS.enabled }} + - name: trivy-internal-certs + secret: + secretName: {{ template "harbor.internalTLS.trivy.secretName" . }} + {{- end }} + {{- if .Values.caBundleSecretName }} +{{ include "harbor.caBundleVolume" . | indent 6 }} + {{- end }} + {{- if not .Values.persistence.enabled }} + - name: "data" + emptyDir: {} + {{- else if $trivy.existingClaim }} + - name: "data" + persistentVolumeClaim: + claimName: {{ $trivy.existingClaim }} + {{- end }} + {{- end }} + {{- with .Values.trivy.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.trivy.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.trivy.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if .Values.trivy.priorityClassName }} + priorityClassName: {{ .Values.trivy.priorityClassName }} + {{- end }} +{{- if and .Values.persistence.enabled (not $trivy.existingClaim) }} + volumeClaimTemplates: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: data + labels: +{{ include "harbor.legacy.labels" . | indent 8 }} + annotations: + {{- range $key, $value := $trivy.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + accessModes: [{{ $trivy.accessMode | quote }}] + {{- if $trivy.storageClass }} + {{- if (eq "-" $trivy.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ $trivy.storageClass }}" + {{- end }} + {{- end }} + resources: + requests: + storage: {{ $trivy.size | quote }} +{{- end }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/templates/trivy/trivy-svc.yaml b/packages/system/harbor/charts/harbor/templates/trivy/trivy-svc.yaml new file mode 100644 index 00000000..a9fb9bf4 --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/trivy/trivy-svc.yaml @@ -0,0 +1,23 @@ +{{ if .Values.trivy.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: "{{ template "harbor.trivy" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +spec: +{{- if .Values.ipFamily.policy }} + ipFamilyPolicy: {{ .Values.ipFamily.policy }} +{{- end }} +{{- if .Values.ipFamily.families }} + ipFamilies: {{ toYaml .Values.ipFamily.families | nindent 4 }} +{{- end }} + ports: + - name: {{ ternary "https-trivy" "http-trivy" .Values.internalTLS.enabled }} + protocol: TCP + port: {{ template "harbor.trivy.servicePort" . }} + selector: +{{ include "harbor.matchLabels" . | indent 4 }} + component: trivy +{{ end }} diff --git a/packages/system/harbor/charts/harbor/templates/trivy/trivy-tls.yaml b/packages/system/harbor/charts/harbor/templates/trivy/trivy-tls.yaml new file mode 100644 index 00000000..58bce4ec --- /dev/null +++ b/packages/system/harbor/charts/harbor/templates/trivy/trivy-tls.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.trivy.enabled .Values.internalTLS.enabled }} +{{- if eq .Values.internalTLS.certSource "manual" }} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ template "harbor.internalTLS.trivy.secretName" . }}" + namespace: {{ .Release.Namespace | quote }} + labels: +{{ include "harbor.labels" . | indent 4 }} +type: kubernetes.io/tls +data: + ca.crt: {{ (required "The \"internalTLS.trustCa\" is required!" .Values.internalTLS.trustCa) | b64enc | quote }} + tls.crt: {{ (required "The \"internalTLS.trivy.crt\" is required!" .Values.internalTLS.trivy.crt) | b64enc | quote }} + tls.key: {{ (required "The \"internalTLS.trivy.key\" is required!" .Values.internalTLS.trivy.key) | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/packages/system/harbor/charts/harbor/values.yaml b/packages/system/harbor/charts/harbor/values.yaml new file mode 100644 index 00000000..e00fafc3 --- /dev/null +++ b/packages/system/harbor/charts/harbor/values.yaml @@ -0,0 +1,1095 @@ +expose: + # Set how to expose the service. Set the type as "ingress", "clusterIP", "nodePort" or "loadBalancer" + # and fill the information in the corresponding section + type: ingress + tls: + # Enable TLS or not. + # Delete the "ssl-redirect" annotations in "expose.ingress.annotations" when TLS is disabled and "expose.type" is "ingress" + # Note: if the "expose.type" is "ingress" and TLS is disabled, + # the port must be included in the command when pulling/pushing images. + # Refer to https://github.com/goharbor/harbor/issues/5291 for details. + enabled: true + # The source of the tls certificate. Set as "auto", "secret" + # or "none" and fill the information in the corresponding section + # 1) auto: generate the tls certificate automatically + # 2) secret: read the tls certificate from the specified secret. + # The tls certificate can be generated manually or by cert manager + # 3) none: configure no tls certificate for the ingress. If the default + # tls certificate is configured in the ingress controller, choose this option + certSource: auto + auto: + # The common name used to generate the certificate, it's necessary + # when the type isn't "ingress" + commonName: "" + secret: + # The name of secret which contains keys named: + # "tls.crt" - the certificate + # "tls.key" - the private key + secretName: "" + ingress: + hosts: + core: core.harbor.domain + # set to the type of ingress controller if it has specific requirements. + # leave as `default` for most ingress controllers. + # set to `gce` if using the GCE ingress controller + # set to `ncp` if using the NCP (NSX-T Container Plugin) ingress controller + # set to `alb` if using the ALB ingress controller + # set to `f5-bigip` if using the F5 BIG-IP ingress controller + controller: default + ## Allow .Capabilities.KubeVersion.Version to be overridden while creating ingress + kubeVersionOverride: "" + className: "" + annotations: + # note different ingress controllers may require a different ssl-redirect annotation + # for Envoy, use ingress.kubernetes.io/force-ssl-redirect: "true" and remove the nginx lines below + ingress.kubernetes.io/ssl-redirect: "true" + ingress.kubernetes.io/proxy-body-size: "0" + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "0" + # ingress-specific labels + labels: {} + route: + labels: {} + annotations: {} + # - name: envoy-internal + # namespace: networking + # sectionName: https + # group: gateway.networking.k8s.io + # kind: Gateway + parentRefs: {} + # - "harbor.example.com" + hosts: [] + clusterIP: + # The name of ClusterIP service + name: harbor + # The ip address of the ClusterIP service (leave empty for acquiring dynamic ip) + staticClusterIP: "" + ports: + # The service port Harbor listens on when serving HTTP + httpPort: 80 + # The service port Harbor listens on when serving HTTPS + httpsPort: 443 + # Annotations on the ClusterIP service + annotations: {} + # ClusterIP-specific labels + labels: {} + nodePort: + # The name of NodePort service + name: harbor + ports: + http: + # The service port Harbor listens on when serving HTTP + port: 80 + # The node port Harbor listens on when serving HTTP + nodePort: 30002 + https: + # The service port Harbor listens on when serving HTTPS + port: 443 + # The node port Harbor listens on when serving HTTPS + nodePort: 30003 + # Annotations on the nodePort service + annotations: {} + # nodePort-specific labels + labels: {} + loadBalancer: + # The name of LoadBalancer service + name: harbor + # Set the IP if the LoadBalancer supports assigning IP + IP: "" + ports: + # The service port Harbor listens on when serving HTTP + httpPort: 80 + # The service port Harbor listens on when serving HTTPS + httpsPort: 443 + # Annotations on the loadBalancer service + annotations: {} + # loadBalancer-specific labels + labels: {} + sourceRanges: [] + +# The external URL for Harbor core service. It is used to +# 1) populate the docker/helm commands showed on portal +# 2) populate the token service URL returned to docker client +# +# Format: protocol://domain[:port]. Usually: +# 1) if "expose.type" is "ingress", the "domain" should be +# the value of "expose.ingress.hosts.core" +# 2) if "expose.type" is "clusterIP", the "domain" should be +# the value of "expose.clusterIP.name" +# 3) if "expose.type" is "nodePort", the "domain" should be +# the IP address of k8s node +# +# If Harbor is deployed behind the proxy, set it as the URL of proxy +externalURL: https://core.harbor.domain + +# The persistence is enabled by default and a default StorageClass +# is needed in the k8s cluster to provision volumes dynamically. +# Specify another StorageClass in the "storageClass" or set "existingClaim" +# if you already have existing persistent volumes to use +# +# For storing images and charts, you can also use "azure", "gcs", "s3", +# "swift" or "oss". Set it in the "imageChartStorage" section +persistence: + enabled: true + # Setting it to "keep" to avoid removing PVCs during a helm delete + # operation. Leaving it empty will delete PVCs after the chart deleted + # (this does not apply for PVCs that are created for internal database + # and redis components, i.e. they are never deleted automatically) + resourcePolicy: "keep" + persistentVolumeClaim: + registry: + # Use the existing PVC which must be created manually before bound, + # and specify the "subPath" if the PVC is shared with other components + existingClaim: "" + # Specify the "storageClass" used to provision the volume. Or the default + # StorageClass will be used (the default). + # Set it to "-" to disable dynamic provisioning + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 5Gi + annotations: {} + jobservice: + jobLog: + existingClaim: "" + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 1Gi + annotations: {} + # If external database is used, the following settings for database will + # be ignored + database: + existingClaim: "" + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 1Gi + annotations: {} + # If external Redis is used, the following settings for Redis will + # be ignored + redis: + existingClaim: "" + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 1Gi + annotations: {} + trivy: + existingClaim: "" + storageClass: "" + subPath: "" + accessMode: ReadWriteOnce + size: 5Gi + annotations: {} + # Define which storage backend is used for registry to store + # images and charts. Refer to + # https://github.com/distribution/distribution/blob/release/2.8/docs/configuration.md#storage + # for the detail. + imageChartStorage: + # Specify whether to disable `redirect` for images and chart storage, for + # backends which not supported it (such as using minio for `s3` storage type), please disable + # it. To disable redirects, simply set `disableredirect` to `true` instead. + # Refer to + # https://github.com/distribution/distribution/blob/release/2.8/docs/configuration.md#redirect + # for the detail. + disableredirect: false + # Specify the "caBundleSecretName" if the storage service uses a self-signed certificate. + # The secret must contain keys named "ca.crt" which will be injected into the trust store + # of registry's containers. + # caBundleSecretName: + + # Specify the type of storage: "filesystem", "azure", "gcs", "s3", "swift", + # "oss" and fill the information needed in the corresponding section. The type + # must be "filesystem" if you want to use persistent volumes for registry + type: filesystem + filesystem: + rootdirectory: /storage + #maxthreads: 100 + azure: + accountname: accountname + accountkey: base64encodedaccountkey + container: containername + #realm: core.windows.net + # To use existing secret, the key must be AZURE_STORAGE_ACCESS_KEY + existingSecret: "" + gcs: + bucket: bucketname + # The base64 encoded json file which contains the key + encodedkey: base64-encoded-json-key-file + #rootdirectory: /gcs/object/name/prefix + #chunksize: "5242880" + # To use existing secret, the key must be GCS_KEY_DATA + existingSecret: "" + useWorkloadIdentity: false + s3: + # Set an existing secret for S3 accesskey and secretkey + # keys in the secret should be REGISTRY_STORAGE_S3_ACCESSKEY and REGISTRY_STORAGE_S3_SECRETKEY for registry + #existingSecret: "" + region: us-west-1 + bucket: bucketname + #accesskey: awsaccesskey + #secretkey: awssecretkey + #regionendpoint: http://myobjects.local + #encrypt: false + #keyid: mykeyid + #secure: true + #skipverify: false + #v4auth: true + #chunksize: "5242880" + #rootdirectory: /s3/object/name/prefix + #storageclass: STANDARD + #multipartcopychunksize: "33554432" + #multipartcopymaxconcurrency: 100 + #multipartcopythresholdsize: "33554432" + swift: + authurl: https://storage.myprovider.com/v3/auth + username: username + password: password + container: containername + # keys in existing secret must be REGISTRY_STORAGE_SWIFT_PASSWORD, REGISTRY_STORAGE_SWIFT_SECRETKEY, REGISTRY_STORAGE_SWIFT_ACCESSKEY + existingSecret: "" + #region: fr + #tenant: tenantname + #tenantid: tenantid + #domain: domainname + #domainid: domainid + #trustid: trustid + #insecureskipverify: false + #chunksize: 5M + #prefix: + #secretkey: secretkey + #accesskey: accesskey + #authversion: 3 + #endpointtype: public + #tempurlcontainerkey: false + #tempurlmethods: + oss: + accesskeyid: accesskeyid + accesskeysecret: accesskeysecret + region: regionname + bucket: bucketname + # key in existingSecret must be REGISTRY_STORAGE_OSS_ACCESSKEYSECRET + existingSecret: "" + #endpoint: endpoint + #internal: false + #encrypt: false + #secure: true + #chunksize: 10M + #rootdirectory: rootdirectory + +# The initial password of Harbor admin. Change it from portal after launching Harbor +# or give an existing secret for it +# key in secret is given via (default to HARBOR_ADMIN_PASSWORD) +existingSecretAdminPassword: "" +existingSecretAdminPasswordKey: HARBOR_ADMIN_PASSWORD +harborAdminPassword: "Harbor12345" + +# The internal TLS used for harbor components secure communicating. In order to enable https +# in each component tls cert files need to provided in advance. +internalTLS: + # If internal TLS enabled + enabled: false + # enable strong ssl ciphers (default: false) + strong_ssl_ciphers: false + # There are three ways to provide tls + # 1) "auto" will generate cert automatically + # 2) "manual" need provide cert file manually in following value + # 3) "secret" internal certificates from secret + certSource: "auto" + # The content of trust ca, only available when `certSource` is "manual" + trustCa: "" + # core related cert configuration + core: + # secret name for core's tls certs + secretName: "" + # Content of core's TLS cert file, only available when `certSource` is "manual" + crt: "" + # Content of core's TLS key file, only available when `certSource` is "manual" + key: "" + # jobservice related cert configuration + jobservice: + # secret name for jobservice's tls certs + secretName: "" + # Content of jobservice's TLS key file, only available when `certSource` is "manual" + crt: "" + # Content of jobservice's TLS key file, only available when `certSource` is "manual" + key: "" + # registry related cert configuration + registry: + # secret name for registry's tls certs + secretName: "" + # Content of registry's TLS key file, only available when `certSource` is "manual" + crt: "" + # Content of registry's TLS key file, only available when `certSource` is "manual" + key: "" + # portal related cert configuration + portal: + # secret name for portal's tls certs + secretName: "" + # Content of portal's TLS key file, only available when `certSource` is "manual" + crt: "" + # Content of portal's TLS key file, only available when `certSource` is "manual" + key: "" + # trivy related cert configuration + trivy: + # secret name for trivy's tls certs + secretName: "" + # Content of trivy's TLS key file, only available when `certSource` is "manual" + crt: "" + # Content of trivy's TLS key file, only available when `certSource` is "manual" + key: "" + +ipFamily: + # ipv6Enabled set to true if ipv6 is enabled in cluster, currently it affected the nginx related component + ipv6: + enabled: true + # ipv4Enabled set to true if ipv4 is enabled in cluster, currently it affected the nginx related component + ipv4: + enabled: true + + # Sets the IP family policy for services to be able to configure dual-stack; see [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services). + policy: "" + # A list of IP families for services that should be supported, in the order in which they should be applied to ClusterIP. Can be "IPv4" and/or "IPv6". + families: [] + +imagePullPolicy: IfNotPresent + +# Use this set to assign a list of default pullSecrets +imagePullSecrets: +# - name: docker-registry-secret +# - name: internal-registry-secret + +# The update strategy for deployments with persistent volumes(jobservice, registry): "RollingUpdate" or "Recreate" +# Set it as "Recreate" when "RWM" for volumes isn't supported +updateStrategy: + type: RollingUpdate + +# debug, info, warning, error or fatal +logLevel: info + +# The name of the secret which contains key named "ca.crt". Setting this enables the +# download link on portal to download the CA certificate when the certificate isn't +# generated automatically +caSecretName: "" + +# The secret key used for encryption. Must be a string of 16 chars. +secretKey: "not-a-secure-key" +# If using existingSecretSecretKey, the key must be secretKey +existingSecretSecretKey: "" + +# The proxy settings for updating trivy vulnerabilities from the Internet and replicating +# artifacts from/to the registries that cannot be reached directly +proxy: + httpProxy: + httpsProxy: + noProxy: 127.0.0.1,localhost,.local,.internal + components: + - core + - jobservice + - trivy + +# Run the migration job via helm hook +enableMigrateHelmHook: false + +# The custom ca bundle secret, the secret must contain key named "ca.crt" +# which will be injected into the trust store for core, jobservice, registry, trivy components +# caBundleSecretName: "" + +## UAA Authentication Options +# If you're using UAA for authentication behind a self-signed +# certificate you will need to provide the CA Cert. +# Set uaaSecretName below to provide a pre-created secret that +# contains a base64 encoded CA Certificate named `ca.crt`. +# uaaSecretName: + +metrics: + enabled: false + core: + path: /metrics + port: 8001 + registry: + path: /metrics + port: 8001 + jobservice: + path: /metrics + port: 8001 + exporter: + path: /metrics + port: 8001 + ## Create prometheus serviceMonitor to scrape harbor metrics. + ## This requires the monitoring.coreos.com/v1 CRD. Please see + ## https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/getting-started.md + ## + serviceMonitor: + enabled: false + additionalLabels: {} + # Scrape interval. If not set, the Prometheus default scrape interval is used. + interval: "" + # Metric relabel configs to apply to samples before ingestion. + metricRelabelings: + [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + # Relabel configs to apply to samples before ingestion. + relabelings: + [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + +trace: + enabled: false + # trace provider: jaeger or otel + # jaeger should be 1.26+ + provider: jaeger + # set sample_rate to 1 if you wanna sampling 100% of trace data; set 0.5 if you wanna sampling 50% of trace data, and so forth + sample_rate: 1 + # namespace used to differentiate different harbor services + # namespace: + # attributes is a key value dict contains user defined attributes used to initialize trace provider + # attributes: + # application: harbor + jaeger: + # jaeger supports two modes: + # collector mode(uncomment endpoint and uncomment username, password if needed) + # agent mode(uncomment agent_host and agent_port) + endpoint: http://hostname:14268/api/traces + # username: + # password: + # agent_host: hostname + # export trace data by jaeger.thrift in compact mode + # agent_port: 6831 + otel: + endpoint: hostname:4318 + url_path: /v1/traces + compression: false + insecure: true + # timeout is in seconds + timeout: 10 + +# cache layer configurations +# if this feature enabled, harbor will cache the resource +# `project/project_metadata/repository/artifact/manifest` in the redis +# which help to improve the performance of high concurrent pulling manifest. +cache: + # default is not enabled. + enabled: false + # default keep cache for one day. + expireHours: 24 + +## set Container Security Context to comply with PSP restricted policy if necessary +## each of the conatiner will apply the same security context +## containerSecurityContext:{} is initially an empty yaml that you could edit it on demand, we just filled with a common template for convenience +containerSecurityContext: + privileged: false + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + capabilities: + drop: + - ALL + +# If service exposed via "ingress", the Nginx will not be used +nginx: + image: + repository: goharbor/nginx-photon + tag: v2.14.2 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## The priority class to run the pod as + priorityClassName: + +portal: + image: + repository: goharbor/harbor-portal + tag: v2.14.2 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## Additional service annotations + serviceAnnotations: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + +core: + image: + repository: goharbor/harbor-core + tag: v2.14.2 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + ## Startup probe values + startupProbe: + enabled: true + initialDelaySeconds: 10 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## Additional service annotations + serviceAnnotations: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + ## User settings configuration json string + configureUserSettings: + # The provider for updating project quota(usage), there are 2 options, redis or db. + # By default it is implemented by db but you can configure it to redis which + # can improve the performance of high concurrent pushing to the same project, + # and reduce the database connections spike and occupies. + # Using redis will bring up some delay for quota usage updation for display, so only + # suggest switch provider to redis if you were ran into the db connections spike around + # the scenario of high concurrent pushing to same project, no improvment for other scenes. + quotaUpdateProvider: db # Or redis + # Secret is used when core server communicates with other components. + # If a secret key is not specified, Helm will generate one. Alternatively set existingSecret to use an existing secret + # Must be a string of 16 chars. + secret: "" + # Fill in the name of a kubernetes secret if you want to use your own + # If using existingSecret, the key must be secret + existingSecret: "" + # Fill the name of a kubernetes secret if you want to use your own + # TLS certificate and private key for token encryption/decryption. + # The secret must contain keys named: + # "tls.key" - the private key + # "tls.crt" - the certificate + secretName: "" + # If not specifying a preexisting secret, a secret can be created from tokenKey and tokenCert and used instead. + # If none of secretName, tokenKey, and tokenCert are specified, an ephemeral key and certificate will be autogenerated. + # tokenKey and tokenCert must BOTH be set or BOTH unset. + # The tokenKey value is formatted as a multiline string containing a PEM-encoded RSA key, indented one more than tokenKey on the following line. + tokenKey: | + # If tokenKey is set, the value of tokenCert must be set as a PEM-encoded certificate signed by tokenKey, and supplied as a multiline string, indented one more than tokenCert on the following line. + tokenCert: | + # The XSRF key. Will be generated automatically if it isn't specified + # While you specified, Please make sure it is 32 characters, otherwise would have validation issue at the harbor-core runtime + # https://github.com/goharbor/harbor/pull/21154 + xsrfKey: "" + # If using existingSecret, the key is defined by core.existingXsrfSecretKey + existingXsrfSecret: "" + # If using existingSecret, the key + existingXsrfSecretKey: CSRF_KEY + # The time duration for async update artifact pull_time and repository + # pull_count, the unit is second. Will be 10 seconds if it isn't set. + # eg. artifactPullAsyncFlushDuration: 10 + artifactPullAsyncFlushDuration: + gdpr: + deleteUser: false + auditLogsCompliant: false + +jobservice: + image: + repository: goharbor/harbor-jobservice + tag: v2.14.2 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + maxJobWorkers: 10 + # The logger for jobs: "file", "database" or "stdout" + jobLoggers: + - file + # - database + # - stdout + # The jobLogger sweeper duration (ignored if `jobLogger` is `stdout`) + loggerSweeperDuration: 14 #days + notification: + webhook_job_max_retry: 3 + webhook_job_http_client_timeout: 3 # in seconds + reaper: + # the max time to wait for a task to finish, if unfinished after max_update_hours, the task will be mark as error, but the task will continue to run, default value is 24 + max_update_hours: 24 + # the max time for execution in running state without new task created + max_dangling_hours: 168 + # Secret is used when job service communicates with other components. + # If a secret key is not specified, Helm will generate one. + # Must be a string of 16 chars. + secret: "" + # Use an existing secret resource + existingSecret: "" + # Key within the existing secret for the job service secret + existingSecretKey: JOBSERVICE_SECRET + +registry: + registry: + image: + repository: goharbor/registry-photon + tag: v2.14.2 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + controller: + image: + repository: goharbor/harbor-registryctl + tag: v2.14.2 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + # Secret is used to secure the upload state from client + # and registry storage backend. + # See: https://github.com/distribution/distribution/blob/release/2.8/docs/configuration.md#http + # If a secret key is not specified, Helm will generate one. + # Must be a string of 16 chars. + secret: "" + # Use an existing secret resource + existingSecret: "" + # Key within the existing secret for the registry service secret + existingSecretKey: REGISTRY_HTTP_SECRET + # If true, the registry returns relative URLs in Location headers. The client is responsible for resolving the correct URL. + relativeurls: false + credentials: + username: "harbor_registry_user" + password: "harbor_registry_password" + # If using existingSecret, the key must be REGISTRY_PASSWD and REGISTRY_HTPASSWD + existingSecret: "" + # Login and password in htpasswd string format. Excludes `registry.credentials.username` and `registry.credentials.password`. May come in handy when integrating with tools like argocd or flux. This allows the same line to be generated each time the template is rendered, instead of the `htpasswd` function from helm, which generates different lines each time because of the salt. + # htpasswdString: $apr1$XLefHzeG$Xl4.s00sMSCCcMyJljSZb0 # example string + htpasswdString: "" + middleware: + enabled: false + type: cloudFront + cloudFront: + baseurl: example.cloudfront.net + keypairid: KEYPAIRID + duration: 3000s + ipfilteredby: none + # The secret key that should be present is CLOUDFRONT_KEY_DATA, which should be the encoded private key + # that allows access to CloudFront + privateKeySecret: "my-secret" + # enable purge _upload directories + upload_purging: + enabled: true + # remove files in _upload directories which exist for a period of time, default is one week. + age: 168h + # the interval of the purge operations + interval: 24h + dryrun: false + +trivy: + # enabled the flag to enable Trivy scanner + enabled: true + image: + # repository the repository for Trivy adapter image + repository: goharbor/trivy-adapter-photon + # tag the tag for Trivy adapter image + tag: v2.14.2 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + # replicas the number of Pod replicas + replicas: 1 + resources: + requests: + cpu: 200m + memory: 512Mi + limits: + cpu: 1 + memory: 1Gi + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + # debugMode the flag to enable Trivy debug mode with more verbose scanning log + debugMode: false + # vulnType a comma-separated list of vulnerability types. Possible values are `os` and `library`. + vulnType: "os,library" + # severity a comma-separated list of severities to be checked + severity: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL" + # ignoreUnfixed the flag to display only fixed vulnerabilities + ignoreUnfixed: false + # insecure the flag to skip verifying registry certificate + insecure: false + # gitHubToken the GitHub access token to download Trivy DB + # + # Trivy DB contains vulnerability information from NVD, Red Hat, and many other upstream vulnerability databases. + # It is downloaded by Trivy from the GitHub release page https://github.com/aquasecurity/trivy-db/releases and cached + # in the local file system (`/home/scanner/.cache/trivy/db/trivy.db`). In addition, the database contains the update + # timestamp so Trivy can detect whether it should download a newer version from the Internet or use the cached one. + # Currently, the database is updated every 12 hours and published as a new release to GitHub. + # + # Anonymous downloads from GitHub are subject to the limit of 60 requests per hour. Normally such rate limit is enough + # for production operations. If, for any reason, it's not enough, you could increase the rate limit to 5000 + # requests per hour by specifying the GitHub access token. For more details on GitHub rate limiting please consult + # https://developer.github.com/v3/#rate-limiting + # + # You can create a GitHub token by following the instructions in + # https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line + gitHubToken: "" + # skipUpdate the flag to disable Trivy DB downloads from GitHub + # + # You might want to set the value of this flag to `true` in test or CI/CD environments to avoid GitHub rate limiting issues. + # If the value is set to `true` you have to manually download the `trivy.db` file and mount it in the + # `/home/scanner/.cache/trivy/db/trivy.db` path. + skipUpdate: false + # skipJavaDBUpdate If the flag is enabled you have to manually download the `trivy-java.db` file and mount it in the + # `/home/scanner/.cache/trivy/java-db/trivy-java.db` path + skipJavaDBUpdate: false + # The dbRepository and javaDBRepository flags can take multiple values, improving reliability when downloading databases. + # Databases are downloaded in priority order until one is successful. + # An attempt to download from the next repository is only made if a temporary error is received (e.g. status 429 or 5xx). + # + # OCI repository(ies) to retrieve the trivy vulnerability database in order of priority + dbRepository: + - "mirror.gcr.io/aquasec/trivy-db" + - "ghcr.io/aquasecurity/trivy-db" + # OCI repository(ies) to retrieve the Java trivy vulnerability database in order of priority + javaDBRepository: + - "mirror.gcr.io/aquasec/trivy-java-db" + - "ghcr.io/aquasecurity/trivy-java-db" + # The offlineScan option prevents Trivy from sending API requests to identify dependencies. + # + # Scanning JAR files and pom.xml may require Internet access for better detection, but this option tries to avoid it. + # For example, the offline mode will not try to resolve transitive dependencies in pom.xml when the dependency doesn't + # exist in the local repositories. It means a number of detected vulnerabilities might be fewer in offline mode. + # It would work if all the dependencies are in local. + # This option doesn’t affect DB download. You need to specify skipUpdate as well as offlineScan in an air-gapped environment. + offlineScan: false + # Comma-separated list of what security issues to detect. Defaults to `vuln`. + securityCheck: "vuln" + # The duration to wait for scan completion + timeout: 5m0s + +database: + # if external database is used, set "type" to "external" + # and fill the connection information in "external" section + type: internal + internal: + image: + repository: goharbor/harbor-db + tag: v2.14.2 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + # The timeout used in livenessProbe; 1 to 5 seconds + livenessProbe: + timeoutSeconds: 1 + # The timeout used in readinessProbe; 1 to 5 seconds + readinessProbe: + timeoutSeconds: 1 + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + extrInitContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + # The initial superuser password for internal database + password: "changeit" + # The size limit for Shared memory, pgSQL use it for shared_buffer + # More details see: + # https://github.com/goharbor/harbor/issues/15034 + shmSizeLimit: 512Mi + initContainer: + migrator: {} + # resources: + # requests: + # memory: 128Mi + # cpu: 100m + permissions: {} + # resources: + # requests: + # memory: 128Mi + # cpu: 100m + external: + host: "192.168.0.1" + port: "5432" + username: "user" + password: "password" + coreDatabase: "registry" + # if using existing secret, the key must be "password" + existingSecret: "" + # "disable" - No SSL + # "require" - Always SSL (skip verification) + # "verify-ca" - Always SSL (verify that the certificate presented by the + # server was signed by a trusted CA) + # "verify-full" - Always SSL (verify that the certification presented by the + # server was signed by a trusted CA and the server host name matches the one + # in the certificate) + sslmode: "disable" + # The maximum number of connections in the idle connection pool per pod (core+exporter). + # If it <=0, no idle connections are retained. + maxIdleConns: 100 + # The maximum number of open connections to the database per pod (core+exporter). + # If it <= 0, then there is no limit on the number of open connections. + # Note: the default number of connections is 1024 for harbor's postgres. + maxOpenConns: 900 + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + +redis: + # if external Redis is used, set "type" to "external" + # and fill the connection information in "external" section + type: internal + internal: + image: + repository: goharbor/redis-photon + tag: v2.14.2 + # set the service account to be used, default if left empty + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + nodeSelector: {} + tolerations: [] + affinity: {} + ## The priority class to run the pod as + priorityClassName: + # containers to be run before the controller's container starts. + initContainers: [] + # Example: + # + # - name: wait + # image: busybox + # command: [ 'sh', '-c', "sleep 20" ] + # # jobserviceDatabaseIndex defaults to "1" + # # registryDatabaseIndex defaults to "2" + # # trivyAdapterIndex defaults to "5" + # # harborDatabaseIndex defaults to "0", but it can be configured to "6", this config is optional + # # cacheLayerDatabaseIndex defaults to "0", but it can be configured to "7", this config is optional + jobserviceDatabaseIndex: "1" + registryDatabaseIndex: "2" + trivyAdapterIndex: "5" + # harborDatabaseIndex: "6" + # cacheLayerDatabaseIndex: "7" + external: + # support redis, redis+sentinel + # addr for redis: : + # addr for redis+sentinel: :,:,: + addr: "192.168.0.2:6379" + # The name of the set of Redis instances to monitor, it must be set to support redis+sentinel + sentinelMasterSet: "" + # TLS configuration for redis connection + # only server-authentication is supported, mTLS for redis connection is not supported + # tls connection will be disable by default + # Once `tlsOptions.enable` set as true, tls/ssl connection will be used for redis + # Please set the `caBundleSecretName` in this configuration file which conatins redis server rootCA if it is self-signed. + # The secret must contain keys named "ca.crt" which will be injected into the trust store + tlsOptions: + enable: false + # The "coreDatabaseIndex" must be "0" as the library Harbor + # used doesn't support configuring it + # harborDatabaseIndex defaults to "0", but it can be configured to "6", this config is optional + # cacheLayerDatabaseIndex defaults to "0", but it can be configured to "7", this config is optional + coreDatabaseIndex: "0" + jobserviceDatabaseIndex: "1" + registryDatabaseIndex: "2" + trivyAdapterIndex: "5" + # harborDatabaseIndex: "6" + # cacheLayerDatabaseIndex: "7" + # username field can be an empty string, and it will be authenticated against the default user + username: "" + password: "" + # If using existingSecret, the key must be REDIS_PASSWORD, if ACL mode enabled, also inlcudes data of username, the keys must be REDIS_USERNAME + existingSecret: "" + ## Additional deployment annotations + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + +exporter: + image: + repository: goharbor/harbor-exporter + tag: v2.14.2 + serviceAccountName: "" + # mount the service account token + automountServiceAccountToken: false + replicas: 1 + revisionHistoryLimit: 10 + # resources: + # requests: + # memory: 256Mi + # cpu: 100m + extraEnvVars: [] + podAnnotations: {} + ## Additional deployment labels + podLabels: {} + nodeSelector: {} + tolerations: [] + affinity: {} + # Spread Pods across failure-domains like regions, availability zones or nodes + topologySpreadConstraints: [] + ## The priority class to run the pod as + priorityClassName: + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # nodeTaintsPolicy: Honor + # whenUnsatisfiable: DoNotSchedule + cacheDuration: 23 + cacheCleanInterval: 14400 diff --git a/packages/system/harbor/templates/bucket-secret.yaml b/packages/system/harbor/templates/bucket-secret.yaml new file mode 100644 index 00000000..241fe638 --- /dev/null +++ b/packages/system/harbor/templates/bucket-secret.yaml @@ -0,0 +1,20 @@ +{{- if .Values.bucket.secretName }} +{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace .Values.bucket.secretName }} +{{- $bucketInfo := fromJson (b64dec (index $existingSecret.data "BucketInfo")) }} +{{- $accessKeyID := index $bucketInfo.spec.secretS3 "accessKeyID" }} +{{- $accessSecretKey := index $bucketInfo.spec.secretS3 "accessSecretKey" }} +{{- $endpoint := index $bucketInfo.spec.secretS3 "endpoint" }} +{{- $bucketName := $bucketInfo.spec.bucketName }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.harbor.fullnameOverride }}-registry-s3 +type: Opaque +stringData: + REGISTRY_STORAGE_S3_ACCESSKEY: {{ $accessKeyID | quote }} + REGISTRY_STORAGE_S3_SECRETKEY: {{ $accessSecretKey | quote }} + REGISTRY_STORAGE_S3_REGIONENDPOINT: {{ $endpoint | quote }} + REGISTRY_STORAGE_S3_BUCKET: {{ $bucketName | quote }} + REGISTRY_STORAGE_S3_REGION: "us-east-1" +{{- end }} diff --git a/packages/system/harbor/templates/database.yaml b/packages/system/harbor/templates/database.yaml new file mode 100644 index 00000000..9a948601 --- /dev/null +++ b/packages/system/harbor/templates/database.yaml @@ -0,0 +1,34 @@ +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: {{ .Values.harbor.fullnameOverride }}-db +spec: + instances: {{ .Values.db.replicas }} + {{- $existingCluster := lookup "postgresql.cnpg.io/v1" "Cluster" .Release.Namespace (printf "%s-db" .Values.harbor.fullnameOverride) }} + {{- $image := dig "spec" "imageName" "ghcr.io/cloudnative-pg/postgresql:17.7-standard-trixie" $existingCluster }} + imageName: {{ if regexMatch ":17\\." $image }}ghcr.io/cloudnative-pg/postgresql:17.7-standard-trixie{{ else if regexMatch ":[0-9]+\\.[0-9]+$" $image }}{{ printf "%s-standard-trixie" $image }}{{ else }}{{ $image }}{{ end }} + storage: + size: {{ .Values.db.size }} + {{- with .Values.db.storageClass }} + storageClass: {{ . }} + {{- end }} + bootstrap: + initdb: + database: app + owner: app + encoding: UTF8 + localeCollate: en_US.UTF-8 + localeCType: en_US.UTF-8 + monitoring: + enablePodMonitor: true + resources: + limits: + cpu: "1" + memory: 2048Mi + requests: + cpu: 100m + memory: 512Mi + inheritedMetadata: + labels: + policy.cozystack.io/allow-to-apiserver: "true" diff --git a/packages/system/harbor/templates/redis.yaml b/packages/system/harbor/templates/redis.yaml new file mode 100644 index 00000000..b39c2b04 --- /dev/null +++ b/packages/system/harbor/templates/redis.yaml @@ -0,0 +1,61 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.harbor.fullnameOverride }}-redis-auth +stringData: + password: {{ .Values.redis.password | quote }} +--- +apiVersion: databases.spotahome.com/v1 +kind: RedisFailover +metadata: + name: {{ .Values.harbor.fullnameOverride }}-redis + labels: + app.kubernetes.io/instance: {{ .Values.harbor.fullnameOverride }}-redis + app.kubernetes.io/managed-by: {{ .Release.Service }} +spec: + sentinel: + replicas: 3 + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 50m + memory: 64Mi + redis: + replicas: {{ .Values.redis.replicas }} + resources: + limits: + cpu: "1" + memory: 1024Mi + requests: + cpu: 100m + memory: 256Mi + storage: + persistentVolumeClaim: + metadata: + name: redisfailover-persistent-data + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.redis.size }} + {{- with .Values.redis.storageClass }} + storageClassName: {{ . }} + {{- end }} + exporter: + enabled: true + image: oliver006/redis_exporter:v1.55.0-alpine + args: + - --web.telemetry-path + - /metrics + env: + - name: REDIS_EXPORTER_LOG_FORMAT + value: txt + customConfig: + - tcp-keepalive 0 + - loglevel notice + auth: + secretPath: {{ .Values.harbor.fullnameOverride }}-redis-auth diff --git a/packages/system/harbor/values.yaml b/packages/system/harbor/values.yaml new file mode 100644 index 00000000..faac7068 --- /dev/null +++ b/packages/system/harbor/values.yaml @@ -0,0 +1,12 @@ +harbor: {} +bucket: + secretName: "" +db: + replicas: 2 + size: 5Gi + storageClass: "" +redis: + password: "" + replicas: 2 + size: 1Gi + storageClass: "" diff --git a/packages/system/hetzner-robotlb/Chart.yaml b/packages/system/hetzner-robotlb/Chart.yaml new file mode 100644 index 00000000..15b72a32 --- /dev/null +++ b/packages/system/hetzner-robotlb/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-hetzner-robotlb +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/hetzner-robotlb/Makefile b/packages/system/hetzner-robotlb/Makefile new file mode 100644 index 00000000..c5ea0e4d --- /dev/null +++ b/packages/system/hetzner-robotlb/Makefile @@ -0,0 +1,9 @@ +export NAME=hetzner-robotlb +export NAMESPACE=cozy-$(NAME) + +include ../../../hack/package.mk + +update: + rm -rf charts + mkdir -p charts + helm pull oci://ghcr.io/intreecom/charts/robotlb --untar --untardir charts diff --git a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/.helmignore b/packages/system/hetzner-robotlb/charts/robotlb/.helmignore similarity index 88% rename from packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/.helmignore rename to packages/system/hetzner-robotlb/charts/robotlb/.helmignore index d0e10845..0e8a0eb3 100644 --- a/packages/system/dashboard/charts/kubeapps/charts/redis/charts/common/.helmignore +++ b/packages/system/hetzner-robotlb/charts/robotlb/.helmignore @@ -14,13 +14,10 @@ *.swp *.bak *.tmp +*.orig *~ # Various IDEs .project .idea/ *.tmproj .vscode/ -# img folder -img/ -# Changelog -CHANGELOG.md diff --git a/packages/system/hetzner-robotlb/charts/robotlb/Chart.yaml b/packages/system/hetzner-robotlb/charts/robotlb/Chart.yaml new file mode 100644 index 00000000..192470dd --- /dev/null +++ b/packages/system/hetzner-robotlb/charts/robotlb/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: 0.0.6 +description: A Helm chart for robotlb (loadbalancer on hetzner cloud). +name: robotlb +type: application +version: 0.1.3 diff --git a/packages/system/hetzner-robotlb/charts/robotlb/templates/NOTES.txt b/packages/system/hetzner-robotlb/charts/robotlb/templates/NOTES.txt new file mode 100644 index 00000000..edef6874 --- /dev/null +++ b/packages/system/hetzner-robotlb/charts/robotlb/templates/NOTES.txt @@ -0,0 +1,4 @@ +The RobotLB Operator was successfully installed. +Please follow the readme to create loadbalanced services. + +README: https://github.com/intreecom/robotlb diff --git a/packages/system/hetzner-robotlb/charts/robotlb/templates/_helpers.tpl b/packages/system/hetzner-robotlb/charts/robotlb/templates/_helpers.tpl new file mode 100644 index 00000000..14261e8a --- /dev/null +++ b/packages/system/hetzner-robotlb/charts/robotlb/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "robotlb.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "robotlb.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "robotlb.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "robotlb.labels" -}} +helm.sh/chart: {{ include "robotlb.chart" . }} +{{ include "robotlb.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "robotlb.selectorLabels" -}} +app.kubernetes.io/name: {{ include "robotlb.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "robotlb.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "robotlb.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/packages/system/hetzner-robotlb/charts/robotlb/templates/deployment.yaml b/packages/system/hetzner-robotlb/charts/robotlb/templates/deployment.yaml new file mode 100644 index 00000000..41b4661a --- /dev/null +++ b/packages/system/hetzner-robotlb/charts/robotlb/templates/deployment.yaml @@ -0,0 +1,66 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "robotlb.fullname" . }} + labels: + {{- include "robotlb.labels" . | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "robotlb.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "robotlb.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "robotlb.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - /usr/local/bin/robotlb + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.envs }} + env: + {{- range $key, $val := . }} + - name: {{ $key | quote }} + value: {{ $val | quote }} + {{ end -}} + {{- end }} + {{- with .Values.existingSecrets }} + envFrom: + {{- range $val := . }} + - secretRef: + name: {{ $val | quote }} + {{ end -}} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/packages/system/hetzner-robotlb/charts/robotlb/templates/role.yaml b/packages/system/hetzner-robotlb/charts/robotlb/templates/role.yaml new file mode 100644 index 00000000..76bac249 --- /dev/null +++ b/packages/system/hetzner-robotlb/charts/robotlb/templates/role.yaml @@ -0,0 +1,21 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "robotlb.fullname" . }}-cr +rules: + {{- toYaml .Values.serviceAccount.permissions | nindent 2 }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "robotlb.fullname" . }}-crb +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "robotlb.fullname" . }}-cr +subjects: + - kind: ServiceAccount + name: {{ include "robotlb.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/packages/system/hetzner-robotlb/charts/robotlb/templates/serviceaccount.yaml b/packages/system/hetzner-robotlb/charts/robotlb/templates/serviceaccount.yaml new file mode 100644 index 00000000..ab3f843d --- /dev/null +++ b/packages/system/hetzner-robotlb/charts/robotlb/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "robotlb.serviceAccountName" . }} + labels: + {{- include "robotlb.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/packages/system/hetzner-robotlb/charts/robotlb/values.yaml b/packages/system/hetzner-robotlb/charts/robotlb/values.yaml new file mode 100644 index 00000000..4365f677 --- /dev/null +++ b/packages/system/hetzner-robotlb/charts/robotlb/values.yaml @@ -0,0 +1,76 @@ +# Default values for robotlb. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: ghcr.io/intreecom/robotlb + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +envs: + ROBOTLB_LOG_LEVEL: "INFO" + +existingSecrets: [] + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + # This is a list of cluster permissions to apply to the service account. + # By default it grants all permissions. + permissions: + - apiGroups: [""] + resources: [services, services/status] + verbs: [get, list, patch, update, watch] + - apiGroups: [""] + resources: [nodes, pods] + verbs: [get, list, watch] + - apiGroups: [discovery.k8s.io] + resources: [endpointslices] + verbs: [get, list, watch] + +podAnnotations: {} +podLabels: {} + +podSecurityContext: + {} + # fsGroup: 2000 + +securityContext: + {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +resources: + {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/packages/system/hetzner-robotlb/values.yaml b/packages/system/hetzner-robotlb/values.yaml new file mode 100644 index 00000000..603da350 --- /dev/null +++ b/packages/system/hetzner-robotlb/values.yaml @@ -0,0 +1,3 @@ +robotlb: + replicas: 1 + existingSecrets: ["hetzner-robotlb-credentials"] diff --git a/packages/system/http-cache-rd/Chart.yaml b/packages/system/http-cache-rd/Chart.yaml new file mode 100644 index 00000000..c82ad1aa --- /dev/null +++ b/packages/system/http-cache-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: http-cache-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/http-cache-rd/Makefile b/packages/system/http-cache-rd/Makefile new file mode 100644 index 00000000..1d4b5be4 --- /dev/null +++ b/packages/system/http-cache-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=http-cache-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/http-cache-rd/cozyrds/http-cache.yaml b/packages/system/http-cache-rd/cozyrds/http-cache.yaml new file mode 100644 index 00000000..6e5e0619 --- /dev/null +++ b/packages/system/http-cache-rd/cozyrds/http-cache.yaml @@ -0,0 +1,32 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: http-cache +spec: + application: + kind: HTTPCache + plural: httpcaches + singular: httpcache + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"size":{"description":"Persistent Volume Claim size available for application data.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"endpoints":{"description":"Endpoints configuration, as a list of .","type":"array","default":[],"items":{"type":"string"}},"haproxy":{"description":"HAProxy configuration.","type":"object","default":{},"required":["replicas","resourcesPreset"],"properties":{"replicas":{"description":"Number of HAProxy replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"nginx":{"description":"Nginx configuration.","type":"object","default":{},"required":["replicas","resourcesPreset"],"properties":{"replicas":{"description":"Number of Nginx replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}} + release: + prefix: http-cache- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-http-cache-application-default-http-cache + namespace: cozy-system + dashboard: + category: NaaS + singular: HTTP Cache + plural: HTTP Cache + description: Layer7 load balancer and caching service + tags: + - cache + - network + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODFfMjgyNSkiLz4KPHBhdGggZD0iTTI2LjAwMjYgMzcuODU4OEMyNi4wMDI2IDYwLjkxOSAyNi4wMDI2IDgzLjk4MTQgMjYuMDAyNiAxMDcuMDQ2QzI1Ljk3MyAxMDguMzIzIDI2LjE5OTYgMTA5LjU5MyAyNi42NjkyIDExMC43ODNDMjcuMTM4NyAxMTEuOTcyIDI3Ljg0MTggMTEzLjA1NiAyOC43Mzc0IDExMy45NzJDMzAuNDUzOSAxMTUuNjU5IDMyLjcgMTE2LjcwOSAzNS4xMDA5IDExNi45NDhDMzcuNTAxOSAxMTcuMTg3IDM5LjkxMjYgMTE2LjYgNDEuOTMxIDExNS4yODRDNDMuMjgyIDExNC4zNzEgNDQuMzg4MSAxMTMuMTQzIDQ1LjE1MjcgMTExLjcwN0M0NS45MTc0IDExMC4yNzEgNDYuMzE3NSAxMDguNjcxIDQ2LjMxODEgMTA3LjA0NkM0Ni4zMTgxIDkwLjM1MjggNDYuMjg2MSA3My42NTk3IDQ2LjMxODEgNTYuOTY2NkM2MS42MTY4IDc1LjE4ODkgNzYuOTQ3NCA5My4zODU2IDkyLjMxIDExMS41NTdDOTQuNDQ0NCAxMTMuNzA4IDk3LjA4NzUgMTE1LjI5MSA5OS45OTcgMTE2LjE2MkMxMDIuOTA2IDExNy4wMzIgMTA1Ljk4OSAxMTcuMTYyIDEwOC45NjIgMTE2LjUzOUMxMTEuMDYxIDExNi4xMjggMTEyLjk3MyAxMTUuMDU3IDExNC40MTUgMTEzLjQ4NUMxMTUuODU3IDExMS45MTMgMTE2Ljc1NCAxMDkuOTIxIDExNi45NzQgMTA3LjgwNEMxMTcuMDA5IDg0LjI2ODEgMTE3LjAwOSA2MC43MzQzIDExNi45NzQgMzcuMjAyNUMxMTYuNzU0IDM0LjY5MDcgMTE1LjU5NSAzMi4zNTIyIDExMy43MjYgMzAuNjQ4NkMxMTEuODU4IDI4Ljk0NSAxMDkuNDE1IDI4IDEwNi44ODEgMjhDMTA0LjM0NiAyOCAxMDEuOTAzIDI4Ljk0NSAxMDAuMDM1IDMwLjY0ODZDOTguMTY2MyAzMi4zNTIyIDk3LjAwNzQgMzQuNjkwNyA5Ni43ODY5IDM3LjIwMjVDOTYuNzg2OSA1NC4xNjMyIDk2LjY4NDQgNzEuMTA0OCA5Ni43ODY5IDg4LjA1OTFDODEuNzYxNiA3MC40MzU4IDY2LjkyMTkgNTIuNjU5NiA1MS45NTQzIDM0Ljk3MjVDNDkuOTgxIDMyLjQ1NTQgNDcuMzY4NSAzMC41MDczIDQ0LjM4NjMgMjkuMzI5MUM0MS40MDQxIDI4LjE1MDkgMzguMTU5OSAyNy43ODUyIDM0Ljk4ODMgMjguMjY5OEMzMi41ODU3IDI4LjUzNTkgMzAuMzU4MyAyOS42NDkzIDI4LjcwOTkgMzEuNDA4NEMyNy4wNjE1IDMzLjE2NzUgMjYuMTAxIDM1LjQ1NTkgMjYuMDAyNiAzNy44NTg4WiIgZmlsbD0id2hpdGUiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl82ODFfMjgyNSIgeDE9IjEwIiB5MT0iMTUuNSIgeDI9IjE0NCIgeTI9IjEzMS41IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiMwMEM1NEEiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDE5NjM5Ii8+CjwvbGluZWFyR3JhZGllbnQ+CjwvZGVmcz4KPC9zdmc+Cg== + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "endpoints"], ["spec", "haproxy"], ["spec", "haproxy", "replicas"], ["spec", "haproxy", "resources"], ["spec", "haproxy", "resourcesPreset"], ["spec", "nginx"], ["spec", "nginx", "replicas"], ["spec", "nginx", "resources"], ["spec", "nginx", "resourcesPreset"]] + secrets: + exclude: [] + include: [] diff --git a/packages/system/http-cache-rd/templates/cozyrd.yaml b/packages/system/http-cache-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/http-cache-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/http-cache-rd/values.yaml b/packages/system/http-cache-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/http-cache-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/info-rd/Chart.yaml b/packages/system/info-rd/Chart.yaml new file mode 100644 index 00000000..2f354177 --- /dev/null +++ b/packages/system/info-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: info-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/info-rd/Makefile b/packages/system/info-rd/Makefile new file mode 100644 index 00000000..15cf2513 --- /dev/null +++ b/packages/system/info-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=info-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/info-rd/cozyrds/info.yaml b/packages/system/info-rd/cozyrds/info.yaml new file mode 100644 index 00000000..61016f01 --- /dev/null +++ b/packages/system/info-rd/cozyrds/info.yaml @@ -0,0 +1,35 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: info +spec: + application: + kind: Info + plural: infos + singular: info + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{}} + release: + prefix: "" + labels: + sharding.fluxcd.io/key: tenants + internal.cozystack.io/tenantmodule: "true" + chartRef: + kind: ExternalArtifact + name: cozystack-info-application-default-info + namespace: cozy-system + dashboard: + name: info + category: Administration + singular: Info + plural: Info + description: Info + module: true + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX3JhZGlhbF8xNDRfMykiLz4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzE0NF8zKSI+CjxwYXRoIGQ9Ik03Ny42NDA3IDk3LjA4NDRMODIuODMzIDk3LjM2MDRWMTA0LjYzN0g2MS4xNzI4Vjk3LjcxOTdMNjQuMTc3MSA5Ny40NDk1QzY1LjgxMDEgOTcuMjY4NCA2Ni44MTA2IDk2LjcxOTMgNjYuODEwNiA5NC41MzQzVjY5LjIzMTRDNjYuODEwNiA2Ny4yMjE3IDY2LjI3MDEgNjYuNTg2NCA2NC41MzY1IDY2LjU4NjRMNjEuMzU2OCA2Ni40MDgxVjU4Ljg1ODRINzcuNjQ2NUw3Ny42NDA3IDk3LjA4NDRaTTcxLjI3MjYgMzkuMzYzQzc1LjI4MDQgMzkuMzYzIDc4LjE4NyA0Mi4zNzMxIDc4LjE4NyA0Ni4xODgzQzc4LjE4NyA1MC4wMTQ5IDc1LjI3MTggNTIuODM4MSA3MS4xNzc4IDUyLjgzODFDNjYuOTk3NSA1Mi44MzgxIDY0LjI2NjMgNTAuMDE0OSA2NC4yNjYzIDQ2LjE4ODNDNjQuMjY2MyA0Mi4zNzMxIDY2Ljk5NzUgMzkuMzYzIDcxLjI3MjYgMzkuMzYzWk03MiAxMThDNDYuNjM2OCAxMTggMjYgOTcuMzYzMiAyNiA3MkMyNiA0Ni42MzY4IDQ2LjYzNjggMjYgNzIgMjZDOTcuMzU3NSAyNiAxMTggNDYuNjM2OCAxMTggNzJDMTE4IDk3LjM2MzIgOTcuMzU3NSAxMTggNzIgMTE4Wk03MiAzNC42MjVDNTEuMzkyIDM0LjYyNSAzNC42MjUgNTEuMzkyIDM0LjYyNSA3MkMzNC42MjUgOTIuNjA4IDUxLjM5MiAxMDkuMzc1IDcyIDEwOS4zNzVDOTIuNjA4IDEwOS4zNzUgMTA5LjM3NSA5Mi42MDggMTA5LjM3NSA3MkMxMDkuMzc1IDUxLjM5MiA5Mi42MDggMzQuNjI1IDcyIDM0LjYyNVoiIGZpbGw9IndoaXRlIi8+CjwvZz4KPGRlZnM+CjxyYWRpYWxHcmFkaWVudCBpZD0icGFpbnQwX3JhZGlhbF8xNDRfMyIgY3g9IjAiIGN5PSIwIiByPSIxIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgxLjMyMjk4ZS0wNSAtNy41MDAwMSkgcm90YXRlKDQ0LjcxNzgpIHNjYWxlKDIxNS4zMTcgMzEyLjQ1NSkiPgo8c3RvcCBzdG9wLWNvbG9yPSIjMDBCNUU3Ii8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzAwMzk4NCIvPgo8L3JhZGlhbEdyYWRpZW50Pgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzE0NF8zIj4KPHJlY3Qgd2lkdGg9IjkyIiBoZWlnaHQ9IjkyIiBmaWxsPSJ3aGl0ZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjYgMjYpIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg== + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"]] + secrets: + exclude: [] + include: + - resourceNames: + - kubeconfig-{{ .namespace }} + - "{{ .namespace }}" diff --git a/packages/system/info-rd/templates/cozyrd.yaml b/packages/system/info-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/info-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/info-rd/values.yaml b/packages/system/info-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/info-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/ingress-nginx/Makefile b/packages/system/ingress-nginx/Makefile index 9ad10ae1..81d78744 100644 --- a/packages/system/ingress-nginx/Makefile +++ b/packages/system/ingress-nginx/Makefile @@ -1,6 +1,6 @@ NAME=ingress-nginx-system -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts @@ -8,5 +8,6 @@ update: helm repo update ingress-nginx helm pull ingress-nginx/ingress-nginx --untar --untardir charts patch --no-backup-if-mismatch -p 3 < patches/add-metrics2.patch + patch --no-backup-if-mismatch -p4 < patches/disable-ca-key-rotation.patch rm -f charts/ingress-nginx/templates/controller-deployment.yaml.orig rm -rf charts/ingress-nginx/changelog/ diff --git a/packages/system/ingress-nginx/charts/ingress-nginx/templates/admission-webhooks/cert-manager.yaml b/packages/system/ingress-nginx/charts/ingress-nginx/templates/admission-webhooks/cert-manager.yaml index db2946c3..fab1e02e 100644 --- a/packages/system/ingress-nginx/charts/ingress-nginx/templates/admission-webhooks/cert-manager.yaml +++ b/packages/system/ingress-nginx/charts/ingress-nginx/templates/admission-webhooks/cert-manager.yaml @@ -23,6 +23,8 @@ spec: name: {{ include "ingress-nginx.fullname" . }}-self-signed-issuer commonName: "ca.webhook.ingress-nginx" isCA: true + privateKey: + rotationPolicy: Never subject: organizations: - ingress-nginx diff --git a/packages/system/ingress-nginx/patches/disable-ca-key-rotation.patch b/packages/system/ingress-nginx/patches/disable-ca-key-rotation.patch new file mode 100644 index 00000000..721795e4 --- /dev/null +++ b/packages/system/ingress-nginx/patches/disable-ca-key-rotation.patch @@ -0,0 +1,13 @@ +diff --git a/packages/system/ingress-nginx/charts/ingress-nginx/templates/admission-webhooks/cert-manager.yaml b/packages/system/ingress-nginx/charts/ingress-nginx/templates/admission-webhooks/cert-manager.yaml +index db2946c3..fab1e02e 100644 +--- a/packages/system/ingress-nginx/charts/ingress-nginx/templates/admission-webhooks/cert-manager.yaml ++++ b/packages/system/ingress-nginx/charts/ingress-nginx/templates/admission-webhooks/cert-manager.yaml +@@ -23,6 +23,8 @@ spec: + name: {{ include "ingress-nginx.fullname" . }}-self-signed-issuer + commonName: "ca.webhook.ingress-nginx" + isCA: true ++ privateKey: ++ rotationPolicy: Never + subject: + organizations: + - ingress-nginx diff --git a/packages/system/ingress-nginx/values.yaml b/packages/system/ingress-nginx/values.yaml index 5571ff37..68436f51 100644 --- a/packages/system/ingress-nginx/values.yaml +++ b/packages/system/ingress-nginx/values.yaml @@ -54,9 +54,45 @@ ingress-nginx: requests: cpu: 100m memory: 90Mi + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 10 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - '{{ include "ingress-nginx.name" . }}' + - key: app.kubernetes.io/instance + operator: In + values: + - '{{ .Release.Name }}' + - key: app.kubernetes.io/component + operator: In + values: + - controller + topologyKey: kubernetes.io/hostname + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - '{{ include "ingress-nginx.name" . }}' + - key: app.kubernetes.io/instance + operator: In + values: + - '{{ .Release.Name }}' + - key: app.kubernetes.io/component + operator: In + values: + - controller + topologyKey: topology.kubernetes.io/zone defaultBackend: - ## enabled: true resources: limits: diff --git a/packages/system/ingress-rd/Chart.yaml b/packages/system/ingress-rd/Chart.yaml new file mode 100644 index 00000000..2e1b77d7 --- /dev/null +++ b/packages/system/ingress-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: ingress-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/ingress-rd/Makefile b/packages/system/ingress-rd/Makefile new file mode 100644 index 00000000..be48593e --- /dev/null +++ b/packages/system/ingress-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=ingress-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/ingress-rd/cozyrds/ingress.yaml b/packages/system/ingress-rd/cozyrds/ingress.yaml new file mode 100644 index 00000000..f814ac52 --- /dev/null +++ b/packages/system/ingress-rd/cozyrds/ingress.yaml @@ -0,0 +1,37 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: ingress +spec: + application: + kind: Ingress + plural: ingresses + singular: ingress + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of ingress-nginx replicas.","type":"integer","default":2},"whitelist":{"description":"List of client networks.","type":"array","default":[],"items":{"type":"string"}},"cloudflareProxy":{"description":"Restoring original visitor IPs when Cloudflare proxied is enabled.","type":"boolean","default":false},"resources":{"description":"Explicit CPU and memory configuration for each ingress-nginx replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}} + release: + prefix: "" + labels: + sharding.fluxcd.io/key: tenants + internal.cozystack.io/tenantmodule: "true" + chartRef: + kind: ExternalArtifact + name: cozystack-ingress-application-default-ingress + namespace: cozy-system + dashboard: + category: Administration + singular: Ingress + plural: Ingress + name: ingress + description: NGINX Ingress Controller + module: true + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODRfMzIyOSkiLz4KPHBhdGggZD0iTTg2LjkyNzQgMzcuMTA3NEgxN1YxMDcuMDM1SDg2LjkyNzRWMzcuMTA3NFoiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iNiIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPHBhdGggZD0iTTEyNy42NDMgMjlIMTA3LjQ1NVY0OS4xODgzSDEyNy42NDNWMjlaIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjQiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+CjxwYXRoIGQ9Ik0xMjcuNjQzIDYxLjcyNjZIMTA3LjQ1NVY4MS45MTQ5SDEyNy42NDNWNjEuNzI2NloiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iNCIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPHBhdGggZD0iTTEyNy42NDMgOTQuNDUyMUgxMDcuNDU1VjExNC42NEgxMjcuNjQzVjk0LjQ1MjFaIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjQiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+CjxwYXRoIGQ9Ik04OC41MTM3IDcyLjA3MTNIMTA2LjI3IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjMiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+CjxwYXRoIGQ9Ik04Ny41Njc0IDgwLjQyNDhMMTA3LjczIDk1Ljc4MDUiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPHBhdGggZD0iTTg3LjU2NzQgNjMuNzE4MUwxMDcuNzMgNDguMzYyMyIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4NF8zMjI5IiB4MT0iMTAiIHkxPSIxNS41IiB4Mj0iMTQ0IiB5Mj0iMTMxLjUiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iIzAwREE1MyIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMwMDk2MzkiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "whitelist"], ["spec", "cloudflareProxy"], ["spec", "resources"], ["spec", "resourcesPreset"]] + secrets: + exclude: [] + include: [] + services: + exclude: [] + include: + - resourceNames: + - "{{ slice .namespace 7 }}-ingress-controller" diff --git a/packages/system/ingress-rd/templates/cozyrd.yaml b/packages/system/ingress-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/ingress-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/ingress-rd/values.yaml b/packages/system/ingress-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/ingress-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/kafka-operator/Makefile b/packages/system/kafka-operator/Makefile index 32fa2207..0e4811e5 100644 --- a/packages/system/kafka-operator/Makefile +++ b/packages/system/kafka-operator/Makefile @@ -1,7 +1,7 @@ export NAME=kafka-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/kafka-operator/templates/alerts.yaml b/packages/system/kafka-operator/templates/alerts.yaml index 70d47014..1988991e 100644 --- a/packages/system/kafka-operator/templates/alerts.yaml +++ b/packages/system/kafka-operator/templates/alerts.yaml @@ -1,7 +1,11 @@ -{{- $files := .Files.Glob "alerts/*.yaml" -}} -{{- range $path, $file := $files }} ---- -# from: {{ $path }} -{{ toString $file }} - -{{- end -}} +{{- /* +# Disabled due to https://github.com/cozystack/cozystack/issues/790 +# {{- $files := .Files.Glob "alerts/*.yaml" -}} +# {{- range $path, $file := $files }} +# --- +# # from: {{ $path }} +# {{ toString $file }} +# +# {{- end -}} +# +*/ -}} diff --git a/packages/system/kafka-operator/values.yaml b/packages/system/kafka-operator/values.yaml index 3e85e449..ddfa2c9b 100644 --- a/packages/system/kafka-operator/values.yaml +++ b/packages/system/kafka-operator/values.yaml @@ -1,4 +1,7 @@ strimzi-kafka-operator: watchAnyNamespace: true generateNetworkPolicy: false - kubernetesServiceDnsDomain: cozy.local \ No newline at end of file + kubernetesServiceDnsDomain: cozy.local + resources: + limits: + memory: 512Mi diff --git a/packages/system/kafka-rd/Chart.yaml b/packages/system/kafka-rd/Chart.yaml new file mode 100644 index 00000000..87b84e32 --- /dev/null +++ b/packages/system/kafka-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: kafka-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/kafka-rd/Makefile b/packages/system/kafka-rd/Makefile new file mode 100644 index 00000000..f7d2b87d --- /dev/null +++ b/packages/system/kafka-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=kafka-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/kafka-rd/cozyrds/kafka.yaml b/packages/system/kafka-rd/cozyrds/kafka.yaml new file mode 100644 index 00000000..8685792f --- /dev/null +++ b/packages/system/kafka-rd/cozyrds/kafka.yaml @@ -0,0 +1,38 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: kafka +spec: + application: + kind: Kafka + plural: kafkas + singular: kafka + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"topics":{"description":"Topics configuration.","type":"array","default":[],"items":{"type":"object","required":["config","name","partitions","replicas"],"properties":{"config":{"description":"Topic configuration.","type":"object","x-kubernetes-preserve-unknown-fields":true},"name":{"description":"Topic name.","type":"string"},"partitions":{"description":"Number of partitions.","type":"integer"},"replicas":{"description":"Number of replicas.","type":"integer"}}}},"kafka":{"description":"Kafka configuration.","type":"object","default":{},"required":["replicas","resourcesPreset","size","storageClass"],"properties":{"replicas":{"description":"Number of Kafka replicas.","type":"integer","default":3},"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume size for Kafka.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the Kafka data.","type":"string","default":""}}},"zookeeper":{"description":"ZooKeeper configuration.","type":"object","default":{},"required":["replicas","resourcesPreset","size","storageClass"],"properties":{"replicas":{"description":"Number of ZooKeeper replicas.","type":"integer","default":3},"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume size for ZooKeeper.","default":"5Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the ZooKeeper data.","type":"string","default":""}}}}} + release: + prefix: kafka- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-kafka-application-default-kafka + namespace: cozy-system + dashboard: + category: PaaS + singular: Kafka + plural: Kafka + description: Managed Kafka service + tags: + - messaging + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODFfMjgyMCkiLz4KPHBhdGggZD0iTTkxLjAzMDcgNzcuODE4NUM4Ni44NTc3IDc3LjgxODUgODMuMTE2NiA3OS42ODE4IDgwLjU1NDcgODIuNjE1NEw3My45OTAxIDc3LjkzMTVDNzQuNjg2OSA3NS45OTc4IDc1LjA4NyA3My45MjE1IDc1LjA4NyA3MS43NDgyQzc1LjA4NyA2OS42MTI2IDc0LjcwMDggNjcuNTcxMSA3NC4wMjY5IDY1LjY2Nkw4MC41NzY5IDYxLjAzMThDODMuMTM4NSA2My45NTA1IDg2Ljg2OTkgNjUuODAzNyA5MS4wMzA3IDY1LjgwMzdDOTguNzMyOCA2NS44MDM3IDEwNSA1OS40ODg0IDEwNSA1MS43MjQ3QzEwNSA0My45NjEgOTguNzMyOCAzNy42NDU3IDkxLjAzMDcgMzcuNjQ1N0M4My4zMjg1IDM3LjY0NTcgNzcuMDYxNCA0My45NjEgNzcuMDYxNCA1MS43MjQ3Qzc3LjA2MTQgNTMuMTE0MyA3Ny4yNjk3IDU0LjQ1NDMgNzcuNjQzNSA1NS43MjMzTDcxLjA4OTEgNjAuMzU5OEM2OC4zNTEyIDU2LjkzNjUgNjQuNDA5IDU0LjU0NjMgNTkuOTE3NCA1My44MTY2VjQ1Ljg1NTNDNjYuMjQ1MSA0NC41MTU4IDcxLjAxMjggMzguODQ5NSA3MS4wMTI4IDMyLjA3OUM3MS4wMTI4IDI0LjMxNTMgNjQuNzQ1NyAxOCA1Ny4wNDM1IDE4QzQ5LjM0MTQgMTggNDMuMDc0MiAyNC4zMTUzIDQzLjA3NDIgMzIuMDc5QzQzLjA3NDIgMzguNzU4OSA0Ny43MTg0IDQ0LjM1NTIgNTMuOTE5NiA0NS43OTAzVjUzLjg1NTFDNDUuNDU2NyA1NS4zNTIzIDM5IDYyLjc5NjEgMzkgNzEuNzQ4MkMzOSA4MC43NDQgNDUuNTIwNiA4OC4yMTUxIDU0LjA0NDYgODkuNjYxM1Y5OC4xNzcyQzQ3Ljc4MDEgOTkuNTY1IDQzLjA3NDIgMTA1LjE5NiA0My4wNzQyIDExMS45MjFDNDMuMDc0MiAxMTkuNjg1IDQ5LjM0MTQgMTI2IDU3LjA0MzUgMTI2QzY0Ljc0NTcgMTI2IDcxLjAxMjggMTE5LjY4NSA3MS4wMTI4IDExMS45MjFDNzEuMDEyOCAxMDUuMTk2IDY2LjMwNyA5OS41NjUgNjAuMDQyNCA5OC4xNzcyVjg5LjY2MTFDNjQuMzU2OSA4OC45Mjg2IDY4LjI2MDEgODYuNjQwNyA3MS4wMjUyIDgzLjIyMzRMNzcuNjMzNyA4Ny45Mzc2Qzc3LjI2NjkgODkuMTk1MiA3Ny4wNjE0IDkwLjUyMTkgNzcuMDYxNCA5MS44OTc1Qzc3LjA2MTQgOTkuNjYxMiA4My4zMjg1IDEwNS45NzYgOTEuMDMwNyAxMDUuOTc2Qzk4LjczMjggMTA1Ljk3NiAxMDUgOTkuNjYxMiAxMDUgOTEuODk3NUMxMDUgODQuMTMzOCA5OC43MzI4IDc3LjgxODUgOTEuMDMwNyA3Ny44MTg1Wk05MS4wMzA3IDQ0Ljg5ODVDOTQuNzY1NiA0NC44OTg1IDk3LjgwMzQgNDcuOTYxNSA5Ny44MDM0IDUxLjcyNDdDOTcuODAzNCA1NS40ODc5IDk0Ljc2NTYgNTguNTUwNiA5MS4wMzA3IDU4LjU1MDZDODcuMjk1OCA1OC41NTA2IDg0LjI1OCA1NS40ODc5IDg0LjI1OCA1MS43MjQ3Qzg0LjI1OCA0Ny45NjE1IDg3LjI5NTggNDQuODk4NSA5MS4wMzA3IDQ0Ljg5ODVaTTUwLjI3MDUgMzIuMDc5QzUwLjI3MDUgMjguMzE1OCA1My4zMDg2IDI1LjI1MzEgNTcuMDQzNSAyNS4yNTMxQzYwLjc3ODUgMjUuMjUzMSA2My44MTYzIDI4LjMxNTggNjMuODE2MyAzMi4wNzlDNjMuODE2MyAzNS44NDIyIDYwLjc3ODUgMzguOTA0OSA1Ny4wNDM1IDM4LjkwNDlDNTMuMzA4NiAzOC45MDQ5IDUwLjI3MDUgMzUuODQyMiA1MC4yNzA1IDMyLjA3OVpNNjMuODE2MyAxMTEuOTIxQzYzLjgxNjMgMTE1LjY4NCA2MC43Nzg1IDExOC43NDcgNTcuMDQzNSAxMTguNzQ3QzUzLjMwODYgMTE4Ljc0NyA1MC4yNzA1IDExNS42ODQgNTAuMjcwNSAxMTEuOTIxQzUwLjI3MDUgMTA4LjE1OCA1My4zMDg2IDEwNS4wOTUgNTcuMDQzNSAxMDUuMDk1QzYwLjc3ODUgMTA1LjA5NSA2My44MTYzIDEwOC4xNTggNjMuODE2MyAxMTEuOTIxWk01Ny4wNDMgODEuMjY4MUM1MS44MzM5IDgxLjI2ODEgNDcuNTk2MiA3Ni45OTggNDcuNTk2MiA3MS43NDgyQzQ3LjU5NjIgNjYuNDk4MiA1MS44MzM5IDYyLjIyNzMgNTcuMDQzIDYyLjIyNzNDNjIuMjUxOSA2Mi4yMjczIDY2LjQ4OTUgNjYuNDk4MiA2Ni40ODk1IDcxLjc0ODJDNjYuNDg5NSA3Ni45OTggNjIuMjUxOSA4MS4yNjgxIDU3LjA0MyA4MS4yNjgxWk05MS4wMzA3IDk4LjcyMzdDODcuMjk1OCA5OC43MjM3IDg0LjI1OCA5NS42NjA3IDg0LjI1OCA5MS44OTc1Qzg0LjI1OCA4OC4xMzQzIDg3LjI5NTggODUuMDcxNiA5MS4wMzA3IDg1LjA3MTZDOTQuNzY1NiA4NS4wNzE2IDk3LjgwMzQgODguMTM0MyA5Ny44MDM0IDkxLjg5NzVDOTcuODAzNCA5NS42NjA3IDk0Ljc2NTYgOTguNzIzNyA5MS4wMzA3IDk4LjcyMzdaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4MV8yODIwIiB4MT0iMTQwIiB5MT0iMTMwLjUiIHgyPSI0IiB5Mj0iOS40OTk5OSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcC8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzQzNDE0MSIvPgo8L2xpbmVhckdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPgo= + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "external"], ["spec", "topics"], ["spec", "kafka"], ["spec", "kafka", "replicas"], ["spec", "kafka", "resources"], ["spec", "kafka", "resourcesPreset"], ["spec", "kafka", "size"], ["spec", "kafka", "storageClass"], ["spec", "zookeeper"], ["spec", "zookeeper", "replicas"], ["spec", "zookeeper", "resources"], ["spec", "zookeeper", "resourcesPreset"], ["spec", "zookeeper", "size"], ["spec", "zookeeper", "storageClass"]] + secrets: + exclude: [] + include: + - resourceNames: + - kafka-{{ .name }}-clients-ca + services: + exclude: [] + include: + - resourceNames: + - kafka-{{ .name }}-kafka-bootstrap diff --git a/packages/system/kafka-rd/templates/cozyrd.yaml b/packages/system/kafka-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/kafka-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/kafka-rd/values.yaml b/packages/system/kafka-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/kafka-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/kamaji-etcd/Makefile b/packages/system/kamaji-etcd/Makefile deleted file mode 100644 index a5419dbb..00000000 --- a/packages/system/kamaji-etcd/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -update: - rm -rf charts - helm repo add clastix https://clastix.github.io/charts - helm repo update clastix - helm pull clastix/kamaji-etcd --untar --untardir charts - sed -i 's/hook-failed/before-hook-creation,hook-failed/' `grep -rl hook-failed charts` - patch --no-backup-if-mismatch -p4 < patches/fix-svc.diff - patch --no-backup-if-mismatch -p4 < patches/fullnameOverride.diff - patch --no-backup-if-mismatch -p4 < patches/remove-plus.patch diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/Chart.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/Chart.yaml deleted file mode 100644 index ae934ae6..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/Chart.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v2 -appVersion: 3.5.6 -description: Helm chart for deploying a multi-tenant `etcd` cluster. -home: https://github.com/clastix/kamaji-etcd -kubeVersion: '>=1.22.0-0' -maintainers: -- email: me@bsctl.io - name: Adriano Pezzuto -- email: dario@tranchitella.eu - name: Dario Tranchitella -name: kamaji-etcd -sources: -- https://github.com/clastix/kamaji-etcd -type: application -version: 0.5.1 diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/README.md b/packages/system/kamaji-etcd/charts/kamaji-etcd/README.md deleted file mode 100644 index d23b1b23..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/README.md +++ /dev/null @@ -1,133 +0,0 @@ -# kamaji-etcd - -![Version: 0.5.1](https://img.shields.io/badge/Version-0.5.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 3.5.6](https://img.shields.io/badge/AppVersion-3.5.6-informational?style=flat-square) - -Helm chart for deploying a multi-tenant `etcd` cluster. - -[Kamaji](https://github.com/clastix/kamaji) turns any Kubernetes cluster into an _admin cluster_ to orchestrate other Kubernetes clusters called _tenant clusters_. -The Control Plane of a _tenant cluster_ is made of regular pods running in a namespace of the _admin cluster_ instead of a dedicated set of Virtual Machines. -This solution makes running control planes at scale cheaper and easier to deploy and operate. - -As of any Kubernetes cluster, a _tenant cluster_ needs a datastore where to save the state and be able to retrieve data. -This chart provides a multi-tenant `etcd` as datastore for Kamaji as well as a standalone multi-tenant `etcd` cluster. - -## Install kamaji-etcd - -To install the Chart with the release name `kamaji-etcd`: - - helm repo add clastix https://clastix.github.io/charts - helm repo update - helm install kamaji-etcd clastix/kamaji-etcd -n kamaji-etcd --create-namespace - -Show the status: - - helm status kamaji-etcd -n kamaji-etcd - -Upgrade the Chart - - helm upgrade kamaji-etcd -n kamaji-etcd clastix/kamaji-etcd - -Uninstall the Chart - - helm uninstall kamaji-etcd -n kamaji-etcd - -## Customize the installation - -There are two methods for specifying overrides of values during Chart installation: `--values` and `--set`. - -The `--values` option is the preferred method because it allows you to keep your overrides in a YAML file, rather than specifying them all on the command line. -Create a copy of the YAML file `values.yaml` and add your overrides to it. - -Specify your overrides file when you install the Chart: - - helm upgrade kamaji-etcd --install --namespace kamaji-etcd --create-namespacekamaji-etcd --values myvalues.yaml - -The values in your overrides file `myvalues.yaml` will override their counterparts in the Chart's values.yaml file. -Any values in `values.yaml` that weren't overridden will keep their defaults. - -If you only need to make minor customizations, you can specify them on the command line by using the `--set` option. For example: - - helm upgrade kamaji-etcd --install --namespace kamaji-etcd --create-namespace kamaji-etcd --set replicas=5 - -Here the values you can override: - -## Values - -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| affinity | object | `{}` | Kubernetes affinity rules to apply to etcd controller pods | -| alerts.annotations | object | `{}` | Assign additional Annotations | -| alerts.enabled | bool | `false` | Enable alerts for Alertmanager | -| alerts.labels | object | `{}` | Assign additional labels according to Prometheus' Alerts matching labels | -| alerts.namespace | string | `""` | Install the Alerts into a different Namespace, as the monitoring stack one (default: the release one) | -| alerts.rules | list | `[]` | The rules for alerts | -| autoCompactionMode | string | `"periodic"` | Interpret 'auto-compaction-retention' one of: periodic|revision. Use 'periodic' for duration based retention, 'revision' for revision number based retention. | -| autoCompactionRetention | string | `"5m"` | Auto compaction retention length. 0 means disable auto compaction. | -| backup | object | `{"all":false,"enabled":false,"s3":{"accessKey":{"value":"","valueFrom":{}},"bucket":"mybucket","image":{"pullPolicy":"IfNotPresent","repository":"minio/mc","tag":"RELEASE.2022-11-07T23-47-39Z"},"retention":"","secretKey":{"value":"","valueFrom":{}},"url":"http://mys3storage:9000"},"schedule":"20 3 * * *","snapshotDateFormat":"$(date +%Y%m%d)","snapshotNamePrefix":"mysnapshot"}` | Enable storage backup | -| backup.all | bool | `false` | Enable backup for all endpoints. When disabled, only the leader will be taken | -| backup.enabled | bool | `false` | Enable scheduling backup job | -| backup.s3 | object | `{"accessKey":{"value":"","valueFrom":{}},"bucket":"mybucket","image":{"pullPolicy":"IfNotPresent","repository":"minio/mc","tag":"RELEASE.2022-11-07T23-47-39Z"},"retention":"","secretKey":{"value":"","valueFrom":{}},"url":"http://mys3storage:9000"}` | The S3 storage config section | -| backup.s3.accessKey | object | `{"value":"","valueFrom":{}}` | The S3 storage ACCESS KEY credential. The plain value has precedence over the valueFrom that can be used to retrieve the value from a Secret. | -| backup.s3.bucket | string | `"mybucket"` | The S3 storage bucket | -| backup.s3.image | object | `{"pullPolicy":"IfNotPresent","repository":"minio/mc","tag":"RELEASE.2022-11-07T23-47-39Z"}` | The S3 client image config section | -| backup.s3.image.pullPolicy | string | `"IfNotPresent"` | Pull policy to use | -| backup.s3.image.repository | string | `"minio/mc"` | Install image from specific repo | -| backup.s3.image.tag | string | `"RELEASE.2022-11-07T23-47-39Z"` | Install image with specific tag | -| backup.s3.retention | string | `""` | The S3 storage object lifecycle management rules; N.B. enabling this option will delete previously set lifecycle rules | -| backup.s3.secretKey | object | `{"value":"","valueFrom":{}}` | The S3 storage SECRET KEY credential. The plain value has precedence over the valueFrom that can be used to retrieve the value from a Secret. | -| backup.s3.url | string | `"http://mys3storage:9000"` | The S3 storage url | -| backup.schedule | string | `"20 3 * * *"` | The job scheduled maintenance time for backup | -| backup.snapshotDateFormat | string | `"$(date +%Y%m%d)"` | The backup file date format (bash) | -| backup.snapshotNamePrefix | string | `"mysnapshot"` | The backup file name prefix | -| clientPort | int | `2379` | The client request port. | -| datastore.enabled | bool | `false` | Create a datastore custom resource for Kamaji | -| defragmentation | object | `{"schedule":"*/15 * * * *"}` | Enable storage defragmentation | -| defragmentation.schedule | string | `"*/15 * * * *"` | The job scheduled maintenance time for defrag (empty to disable) | -| extraArgs | list | `[]` | A list of extra arguments to add to the etcd default ones | -| image.pullPolicy | string | `"IfNotPresent"` | Pull policy to use | -| image.repository | string | `"quay.io/coreos/etcd"` | Install image from specific repo | -| image.tag | string | `""` | Install image with specific tag, overwrite the tag in the chart | -| livenessProbe | object | `{}` | The livenessProbe for the etcd container | -| metricsPort | int | `2381` | The port where etcd exposes metrics. | -| nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Kubernetes node selector rules to schedule etcd | -| peerApiPort | int | `2380` | The peer API port which servers are listening to. | -| persistentVolumeClaim.accessModes | list | `["ReadWriteOnce"]` | The Access Mode to storage | -| persistentVolumeClaim.customAnnotations | object | `{}` | The custom annotations to add to the PVC | -| persistentVolumeClaim.size | string | `"10Gi"` | The size of persistent storage for etcd data | -| persistentVolumeClaim.storageClassName | string | `""` | A specific storage class | -| podAnnotations | object | `{}` | Annotations to add to all etcd pods | -| podLabels | object | `{"application":"kamaji-etcd"}` | Labels to add to all etcd pods | -| priorityClassName | string | `"system-cluster-critical"` | The priorityClassName to apply to etcd | -| quotaBackendBytes | string | `"8589934592"` | Raise alarms when backend size exceeds the given quota. It will put the cluster into a maintenance mode which only accepts key reads and deletes. | -| replicas | int | `3` | Size of the etcd cluster | -| resources | object | `{"limits":{},"requests":{}}` | Resources assigned to the etcd containers | -| securityContext | object | `{"allowPrivilegeEscalation":false}` | The securityContext to apply to etcd | -| serviceAccount | object | `{"create":true,"name":""}` | Install an etcd with enabled multi-tenancy | -| serviceAccount.create | bool | `true` | Create a ServiceAccount, required to install and provision the etcd backing storage (default: true) | -| serviceAccount.name | string | `""` | Define the ServiceAccount name to use during the setup and provision of the etcd backing storage (default: "") | -| serviceMonitor.annotations | object | `{}` | Assign additional Annotations | -| serviceMonitor.enabled | bool | `false` | Enable ServiceMonitor for Prometheus | -| serviceMonitor.endpoint.interval | string | `"15s"` | Set the scrape interval for the endpoint of the serviceMonitor | -| serviceMonitor.endpoint.metricRelabelings | list | `[]` | Set metricRelabelings for the endpoint of the serviceMonitor | -| serviceMonitor.endpoint.relabelings | list | `[]` | Set relabelings for the endpoint of the serviceMonitor | -| serviceMonitor.endpoint.scrapeTimeout | string | `""` | Set the scrape timeout for the endpoint of the serviceMonitor | -| serviceMonitor.labels | object | `{}` | Assign additional labels according to Prometheus' serviceMonitorSelector matching labels | -| serviceMonitor.matchLabels | object | `{}` | Change matching labels | -| serviceMonitor.namespace | string | `""` | Install the ServiceMonitor into a different Namespace, as the monitoring stack one (default: the release one) | -| serviceMonitor.serviceAccount.name | string | `"etcd"` | ServiceAccount for Metrics RBAC | -| serviceMonitor.serviceAccount.namespace | string | `"etcd-system"` | ServiceAccount Namespace for Metrics RBAC | -| serviceMonitor.targetLabels | list | `[]` | Set targetLabels for the serviceMonitor | -| snapshotCount | string | `"10000"` | Number of committed transactions to trigger a snapshot to disk. | -| tolerations | list | `[]` | Kubernetes node taints that the etcd pods would tolerate | -| topologySpreadConstraints | list | `[]` | Kubernetes topology spread constraints to apply to etcd controller pods | - -## Maintainers - -| Name | Email | Url | -| ---- | ------ | --- | -| Adriano Pezzuto | | | -| Dario Tranchitella | | | - -## Source Code - -* diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/README.md.gotmpl b/packages/system/kamaji-etcd/charts/kamaji-etcd/README.md.gotmpl deleted file mode 100644 index 04c36a53..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/README.md.gotmpl +++ /dev/null @@ -1,59 +0,0 @@ -{{ template "chart.header" . }} -{{ template "chart.deprecationWarning" . }} - -{{ template "chart.badgesSection" . }} - -{{ template "chart.description" . }} - -[Kamaji](https://github.com/clastix/kamaji) turns any Kubernetes cluster into an _admin cluster_ to orchestrate other Kubernetes clusters called _tenant clusters_. -The Control Plane of a _tenant cluster_ is made of regular pods running in a namespace of the _admin cluster_ instead of a dedicated set of Virtual Machines. -This solution makes running control planes at scale cheaper and easier to deploy and operate. - -As of any Kubernetes cluster, a _tenant cluster_ needs a datastore where to save the state and be able to retrieve data. -This chart provides a multi-tenant `etcd` as datastore for Kamaji as well as a standalone multi-tenant `etcd` cluster. - -## Install kamaji-etcd - -To install the Chart with the release name `kamaji-etcd`: - - helm repo add clastix https://clastix.github.io/charts - helm repo update - helm install kamaji-etcd clastix/kamaji-etcd -n kamaji-etcd --create-namespace - -Show the status: - - helm status kamaji-etcd -n kamaji-etcd - -Upgrade the Chart - - helm upgrade kamaji-etcd -n kamaji-etcd clastix/kamaji-etcd - -Uninstall the Chart - - helm uninstall kamaji-etcd -n kamaji-etcd - -## Customize the installation - -There are two methods for specifying overrides of values during Chart installation: `--values` and `--set`. - -The `--values` option is the preferred method because it allows you to keep your overrides in a YAML file, rather than specifying them all on the command line. -Create a copy of the YAML file `values.yaml` and add your overrides to it. - -Specify your overrides file when you install the Chart: - - helm upgrade kamaji-etcd --install --namespace kamaji-etcd --create-namespacekamaji-etcd --values myvalues.yaml - -The values in your overrides file `myvalues.yaml` will override their counterparts in the Chart's values.yaml file. -Any values in `values.yaml` that weren't overridden will keep their defaults. - -If you only need to make minor customizations, you can specify them on the command line by using the `--set` option. For example: - - helm upgrade kamaji-etcd --install --namespace kamaji-etcd --create-namespace kamaji-etcd --set replicas=5 - -Here the values you can override: - -{{ template "chart.valuesSection" . }} - -{{ template "chart.maintainersSection" . }} - -{{ template "chart.sourcesSection" . }} diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/_helpers.tpl b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/_helpers.tpl deleted file mode 100644 index e68a9674..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/_helpers.tpl +++ /dev/null @@ -1,164 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "etcd.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified etcd name. -*/}} -{{- define "etcd.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "etcd.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create the etcd fully-qualified Docker image to use -*/}} -{{- define "etcd.fullyQualifiedDockerImage" -}} -{{- printf "%s:%s" .Values.image.repository ( .Values.image.tag | default (printf "v%s" .Chart.AppVersion) ) -}} -{{- end }} - -{{/* -Create the name of the Service to use -*/}} -{{- define "etcd.serviceName" -}} -{{- printf "%s" (include "etcd.fullname" .) | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "etcd.labels" -}} -helm.sh/chart: {{ include "etcd.chart" . }} -{{ include "etcd.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "etcd.selectorLabels" -}} -app.kubernetes.io/name: {{ include "etcd.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "etcd.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "etcd.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} - -{{/* -Name of the Stateful Set. -*/}} -{{- define "etcd.stsName" }} -{{- printf "%s" (include "etcd.fullname" .) | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Name of the etcd CA secret. -*/}} -{{- define "etcd.caSecretName" }} -{{- printf "%s-%s" (include "etcd.fullname" .) "certs" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Name of the certificate signing requests for the certificates required by etcd. -*/}} -{{- define "etcd.csrConfigMapName" }} -{{- printf "%s-csr" (include "etcd.fullname" .) }} -{{- end }} - -{{/* -Name of the etcd role -*/}} -{{- define "etcd.roleName" }} -{{- printf "%s-gen-certs-role" (include "etcd.fullname" .) }} -{{- end }} - -{{/* -Name of the etcd role binding -*/}} -{{- define "etcd.roleBindingName" }} -{{- printf "%s-gen-certs-rolebiding" (include "etcd.fullname" .) }} -{{- end }} - -{{/* -Name of the etcd root-client secret. -*/}} -{{- define "etcd.clientSecretName" }} -{{- printf "%s-root-client-certs" ( include "etcd.fullname" . ) }} -{{- end }} - -{{/* -Retrieve the current Kubernetes version to launch a kubectl container with the minimum version skew possible. -*/}} -{{- define "etcd.jobsTagKubeVersion" -}} -{{- print "v" .Capabilities.KubeVersion.Major "." (.Capabilities.KubeVersion.Minor | replace "+" "") -}} -{{- end }} - -{{/* -Comma separated list of etcd cluster peers. -*/}} -{{- define "etcd.initialCluster" }} -{{- $outer := . -}} -{{- $list := list -}} -{{- range $i, $count := until (int $.Values.replicas) -}} - {{- $list = append $list ( printf "%s-%d=https://%s-%d.%s.%s.svc.cluster.local:%d" ( include "etcd.stsName" $outer ) $i ( include "etcd.fullname" $outer ) $count ( include "etcd.serviceName" $outer ) $.Release.Namespace (int $.Values.peerApiPort) ) -}} -{{- end }} -{{- join "," $list -}} -{{- end }} - -{{/* -Space separated list of etcd cluster endpoints. -*/}} -{{- define "etcd.endpoints" }} -{{- $outer := . -}} -{{- $list := list -}} -{{- range $i, $count := until (int $.Values.replicas) -}} - {{- $list = append $list ( printf "%s-%d.%s.%s.svc.cluster.local:%d" ( include "etcd.stsName" $outer ) $count ( include "etcd.serviceName" $outer ) $.Release.Namespace (int $.Values.clientPort) ) -}} -{{- end }} -{{- join " " $list -}} -{{- end }} - -{{/* -Space separated list of etcd cluster endpoints. -*/}} -{{- define "etcd.endpointsYAML" }} -{{- $outer := . -}} -{{- range $i, $count := until (int $.Values.replicas) -}} - {{ printf "- %s-%d.%s.%s.svc.cluster.local:%d\n" ( include "etcd.stsName" $outer ) $count ( include "etcd.serviceName" $outer ) $.Release.Namespace (int $.Values.clientPort) }} -{{- end }} -{{- end }} - -{{/* -Create the minio-client fully-qualified Docker image to use -*/}} -{{- define "minio-client.fullyQualifiedDockerImage" -}} -{{- printf "%s:%s" .Values.backup.s3.image.repository .Values.backup.s3.image.tag -}} -{{- end }} diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_alerts.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_alerts.yaml deleted file mode 100644 index 30bc6f43..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_alerts.yaml +++ /dev/null @@ -1,22 +0,0 @@ -{{- if .Values.alerts.enabled }} -apiVersion: monitoring.coreos.com/v1 -kind: PrometheusRule -metadata: - name: {{ include "etcd.fullname" . }}-alerts - namespace: {{ .Values.alerts.namespace | default .Release.Namespace }} - labels: - {{- include "etcd.labels" . | nindent 4 }} - {{- with .Values.alerts.labels }} - {{- toYaml . | nindent 4 }} - {{- end }} - {{- with .Values.alerts.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - groups: - - name: kamaji-etcd - {{- with .Values.alerts.rules }} - rules: {{- toYaml . | nindent 6 }} - {{- end }} -{{- end }} \ No newline at end of file diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_cm.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_cm.yaml deleted file mode 100644 index bd8ddcb9..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_cm.yaml +++ /dev/null @@ -1,98 +0,0 @@ -{{- $outer := $ -}} -apiVersion: v1 -kind: ConfigMap -metadata: - annotations: - "helm.sh/hook": pre-install - "helm.sh/hook-weight": "5" - labels: - {{- include "etcd.labels" . | nindent 4 }} - name: {{ include "etcd.csrConfigMapName" . }} - namespace: {{ .Release.Namespace }} -data: - ca-csr.json: |- - { - "CN": "Clastix CA", - "key": { - "algo": "rsa", - "size": 2048 - }, - "names": [ - { - "C": "IT", - "ST": "Italy", - "L": "Milan" - } - ] - } - config.json: |- - { - "signing": { - "default": { - "expiry": "8760h" - }, - "profiles": { - "server-authentication": { - "usages": ["signing", "key encipherment", "server auth"], - "expiry": "8760h" - }, - "client-authentication": { - "usages": ["signing", "key encipherment", "client auth"], - "expiry": "8760h" - }, - "peer-authentication": { - "usages": ["signing", "key encipherment", "server auth", "client auth"], - "expiry": "8760h" - } - } - } - } - server-csr.json: |- - { - "CN": "etcd", - "key": { - "algo": "rsa", - "size": 2048 - }, - "hosts": [ -{{- range $count := until (int $.Values.replicas) -}} - {{ printf "\"%s-%d.%s.%s.svc.cluster.local\"," ( include "etcd.fullname" $outer ) $count (include "etcd.serviceName" $outer) $.Release.Namespace }} - {{ printf "\"%s-%d.%s.%s.svc\"," ( include "etcd.fullname" $outer ) $count (include "etcd.serviceName" $outer) $.Release.Namespace }} -{{- end }} - "etcd-server.{{ .Release.Namespace }}.svc.cluster.local", - "etcd-server.{{ .Release.Namespace }}.svc", - "etcd-server", - "127.0.0.1" - ] - } - peer-csr.json: |- - { - "CN": "etcd", - "key": { - "algo": "rsa", - "size": 2048 - }, - "hosts": [ -{{- range $count := until (int $.Values.replicas) -}} - {{ printf "\"%s-%d\"," ( include "etcd.stsName" $outer ) $count }} - {{ printf "\"%s-%d.%s\"," ( include "etcd.stsName" $outer ) $count (include "etcd.serviceName" $outer) }} - {{ printf "\"%s-%d.%s.%s.svc\"," ( include "etcd.stsName" $outer ) $count (include "etcd.serviceName" $outer) $.Release.Namespace }} - {{ printf "\"%s-%d.%s.%s.svc.cluster.local\"," ( include "etcd.stsName" $outer ) $count (include "etcd.serviceName" $outer) $.Release.Namespace }} -{{- end }} - "127.0.0.1" - ] - } - root-client-csr.json: |- - { - "CN": "root", - "key": { - "algo": "rsa", - "size": 2048 - }, - "names": [ - { - "O": "system:masters" - } - ] - } - diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_cronjob_backup.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_cronjob_backup.yaml deleted file mode 100644 index 034bbac2..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_cronjob_backup.yaml +++ /dev/null @@ -1,115 +0,0 @@ -{{- if .Values.backup.enabled -}} -apiVersion: batch/v1 -kind: CronJob -metadata: - labels: - {{- include "etcd.labels" . | nindent 4 }} - name: "{{ .Release.Name }}-backup" - namespace: {{ .Release.Namespace }} -spec: - schedule: "{{ .Values.backup.schedule }}" - successfulJobsHistoryLimit: 7 - jobTemplate: - spec: - template: - spec: - serviceAccountName: {{ include "etcd.serviceAccountName" . }} - restartPolicy: OnFailure - initContainers: - - name: etcd-client - image: {{ include "etcd.fullyQualifiedDockerImage" . }} - imagePullPolicy: {{ .Values.image.pullPolicy }} - command: - - bash - - -c - - |- - cd /opt/etcd-dump; - for ENDPOINT in {{ include "etcd.endpoints" . }}; do - isLeader=$(etcdctl --endpoints=${ENDPOINT} endpoint status | awk '{ print $6 }' | tr -d ',' ) - if ! {{ .Values.backup.all }} && ! ${isLeader} ; then - continue - elif ! {{ .Values.backup.all }} && ${isLeader} ; then - POD="etcd-leader" - else - POD=${ENDPOINT#*//} - POD=${POD%.{{ include "etcd.serviceName" . }}*} - fi - SNAPSHOT={{ .Values.backup.snapshotNamePrefix }}_${POD}_{{ .Values.backup.snapshotDateFormat }}.db - etcdctl --endpoints=${ENDPOINT} snapshot save ${SNAPSHOT} - etcdutl --write-out=table snapshot status ${SNAPSHOT} - md5sum ${SNAPSHOT}; - done; - env: - - name: ETCDCTL_CACERT - value: /opt/certs/ca/ca.crt - - name: ETCDCTL_CERT - value: /opt/certs/root-client-certs/tls.crt - - name: ETCDCTL_KEY - value: /opt/certs/root-client-certs/tls.key - volumeMounts: - - name: root-client-certs - mountPath: /opt/certs/root-client-certs - - name: certs - mountPath: /opt/certs/ca - - name: shared-data - mountPath: /opt/etcd-dump - containers: - - name: minio-client - image: {{ include "minio-client.fullyQualifiedDockerImage" . }} - imagePullPolicy: {{ .Values.backup.s3.image.pullPolicy }} - command: - - bash - - -c - - |- - cd /opt/etcd-dump - if $MC alias set myminio ${S3_URL} ${S3_ACCESS_KEY} ${S3_SECRET_KEY} \ - && $MC ping myminio -c 3 -e 3 ; then - echo -e "\nUploading snapshot(s):" - $MC cp {{ .Values.backup.snapshotNamePrefix }}_*.db myminio/{{ .Values.backup.s3.bucket }} - else - echo -e "\nERROR: S3 storage could not be configured;\nCheck your S3 URL/Credentials or network connectivity" - exit 1 - fi - env: - - name: S3_URL - value: {{ .Values.backup.s3.url | quote }} - - name: S3_ACCESS_KEY - {{- if .Values.backup.s3.accessKey.value }} - value: {{ .Values.backup.s3.accessKey.value | quote }} - {{- else }} - valueFrom: - {{- toYaml .Values.backup.s3.accessKey.valueFrom | nindent 16 }} - {{- end }} - - name: S3_SECRET_KEY - {{- if .Values.backup.s3.secretKey.value }} - value: {{ .Values.backup.s3.secretKey.value | quote }} - {{- else }} - valueFrom: - {{- toYaml .Values.backup.s3.secretKey.valueFrom | nindent 16 }} - {{- end }} - - name: MC_CONFIG_DIR - value: /tmp - - name: MC - value: "/usr/bin/mc --config-dir ${MC_CONFIG_DIR}" - volumeMounts: - - name: shared-data - mountPath: /opt/etcd-dump - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - {{- with .Values.tolerations }} - tolerations: {{- toYaml . | nindent 12 }} - {{- end }} - volumes: - - name: shared-data - emptyDir: {} - - name: root-client-certs - secret: - secretName: {{ include "etcd.clientSecretName" . }} - optional: true - - name: certs - secret: - secretName: {{ include "etcd.caSecretName" . }} - optional: true -{{- end }} diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_cronjob_defrag.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_cronjob_defrag.yaml deleted file mode 100644 index ef5ca25d..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_cronjob_defrag.yaml +++ /dev/null @@ -1,62 +0,0 @@ -{{- if .Values.defragmentation.schedule -}} -apiVersion: batch/v1 -kind: CronJob -metadata: - labels: - {{- include "etcd.labels" . | nindent 4 }} - name: "{{ .Release.Name }}-defrag" - namespace: {{ .Release.Namespace }} -spec: - schedule: "{{ .Values.defragmentation.schedule }}" - successfulJobsHistoryLimit: 4 - jobTemplate: - spec: - template: - spec: - serviceAccountName: {{ include "etcd.serviceAccountName" . }} - restartPolicy: OnFailure - containers: - - name: etcd-client - image: {{ include "etcd.fullyQualifiedDockerImage" . }} - imagePullPolicy: {{ .Values.image.pullPolicy }} - command: - - bash - - -c - - |- - for ENDPOINT in {{ include "etcd.endpoints" . }}; do - etcdctl --endpoints=https://${ENDPOINT} defrag; - etcdctl --endpoints=https://${ENDPOINT} alarm disarm; - etcdctl --endpoints=https://${ENDPOINT} alarm list; - etcdctl --endpoints=https://${ENDPOINT} endpoint status -w table; - etcdctl --endpoints=https://${ENDPOINT} member list -w table; - sleep 15; - done; - env: - - name: ETCDCTL_CACERT - value: /opt/certs/ca/ca.crt - - name: ETCDCTL_CERT - value: /opt/certs/root-client-certs/tls.crt - - name: ETCDCTL_KEY - value: /opt/certs/root-client-certs/tls.key - volumeMounts: - - name: root-client-certs - mountPath: /opt/certs/root-client-certs - - name: certs - mountPath: /opt/certs/ca - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - {{- with .Values.tolerations }} - tolerations: {{- toYaml . | nindent 12 }} - {{- end }} - volumes: - - name: root-client-certs - secret: - secretName: {{ include "etcd.clientSecretName" . }} - optional: true - - name: certs - secret: - secretName: {{ include "etcd.caSecretName" . }} - optional: true -{{- end }} diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_datastore.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_datastore.yaml deleted file mode 100644 index edf155c3..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_datastore.yaml +++ /dev/null @@ -1,35 +0,0 @@ -{{- if .Values.datastore.enabled }} -apiVersion: kamaji.clastix.io/v1alpha1 -kind: DataStore -metadata: - name: {{ include "etcd.fullname" . }} - labels: - {{- include "etcd.labels" . | nindent 4 }} -spec: - driver: etcd - endpoints: - {{- include "etcd.endpointsYAML" . | nindent 4 }} - tlsConfig: - certificateAuthority: - certificate: - secretReference: - keyPath: ca.crt - name: {{ include "etcd.caSecretName" . }} - namespace: {{ .Release.Namespace }} - privateKey: - secretReference: - keyPath: ca.key - name: {{ include "etcd.caSecretName" . }} - namespace: {{ .Release.Namespace }} - clientCertificate: - certificate: - secretReference: - keyPath: tls.crt - name: {{ include "etcd.clientSecretName" . }} - namespace: {{ .Release.Namespace }} - privateKey: - secretReference: - keyPath: tls.key - name: {{ include "etcd.clientSecretName" . }} - namespace: {{ .Release.Namespace }} -{{ end }} \ No newline at end of file diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_job_postdelete.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_job_postdelete.yaml deleted file mode 100644 index 71a9d5cc..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_job_postdelete.yaml +++ /dev/null @@ -1,32 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - labels: - {{- include "etcd.labels" . | nindent 4 }} - annotations: - "helm.sh/hook": pre-delete - "helm.sh/hook-weight": "10" - "helm.sh/hook-delete-policy": "hook-succeeded,before-hook-creation,hook-failed" - name: "{{ .Release.Name }}-etcd-teardown" - namespace: {{ .Release.Namespace }} -spec: - template: - metadata: - name: "{{ .Release.Name }}" - spec: - serviceAccountName: {{ include "etcd.serviceAccountName" . }} - restartPolicy: Never - containers: - - name: kubectl - image: {{ printf "clastix/kubectl:%s" (include "etcd.jobsTagKubeVersion" .) }} - command: - - kubectl - - --namespace={{ .Release.Namespace }} - - delete - - secret - - --ignore-not-found=true - - {{ include "etcd.caSecretName" . }} - - {{ include "etcd.clientSecretName" . }} - {{- with .Values.tolerations }} - tolerations: {{- toYaml . | nindent 8 }} - {{- end }} diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_job_preinstall_1.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_job_preinstall_1.yaml deleted file mode 100644 index 7fa78ce1..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_job_preinstall_1.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - labels: - {{- include "etcd.labels" . | nindent 4 }} - annotations: - "helm.sh/hook": pre-install - "helm.sh/hook-weight": "10" - "helm.sh/hook-delete-policy": "hook-succeeded,before-hook-creation,hook-failed" - name: "{{ .Release.Name }}-etcd-setup-1" - namespace: {{ .Release.Namespace }} -spec: - template: - metadata: - name: "{{ .Release.Name }}" - spec: - serviceAccountName: {{ include "etcd.serviceAccountName" . }} - restartPolicy: Never - initContainers: - - name: cfssl - image: cfssl/cfssl:latest - command: - - bash - - -c - - |- - cfssl gencert -initca /csr/ca-csr.json | cfssljson -bare /certs/ca && - mv /certs/ca.pem /certs/ca.crt && mv /certs/ca-key.pem /certs/ca.key && - cfssl gencert -ca=/certs/ca.crt -ca-key=/certs/ca.key -config=/csr/config.json -profile=peer-authentication /csr/peer-csr.json | cfssljson -bare /certs/peer && - cfssl gencert -ca=/certs/ca.crt -ca-key=/certs/ca.key -config=/csr/config.json -profile=peer-authentication /csr/server-csr.json | cfssljson -bare /certs/server && - cfssl gencert -ca=/certs/ca.crt -ca-key=/certs/ca.key -config=/csr/config.json -profile=client-authentication /csr/root-client-csr.json | cfssljson -bare /certs/root-client - volumeMounts: - - mountPath: /certs - name: certs - - mountPath: /csr - name: csr - containers: - - name: kubectl - image: {{ printf "clastix/kubectl:%s" (include "etcd.jobsTagKubeVersion" .) }} - command: ["/bin/sh", "-c"] - args: - - | - if kubectl get secret {{ include "etcd.caSecretName" . }} --namespace={{ .Release.Namespace }} &>/dev/null; then - echo "Secret {{ include "etcd.caSecretName" . }} already exists" - else - echo "Creating secret {{ include "etcd.caSecretName" . }}" - kubectl --namespace={{ .Release.Namespace }} create secret generic {{ include "etcd.caSecretName" . }} --from-file=/certs/ca.crt --from-file=/certs/ca.key --from-file=/certs/peer-key.pem --from-file=/certs/peer.pem --from-file=/certs/server-key.pem --from-file=/certs/server.pem - fi - if kubectl get secret {{ include "etcd.clientSecretName" . }} --namespace={{ .Release.Namespace }} &>/dev/null; then - echo "Secret {{ include "etcd.clientSecretName" . }} already exists" - else - echo "Creating secret {{ include "etcd.clientSecretName" . }}" - kubectl --namespace={{ .Release.Namespace }} create secret tls {{ include "etcd.clientSecretName" . }} --key=/certs/root-client-key.pem --cert=/certs/root-client.pem - fi - volumeMounts: - - mountPath: /certs - name: certs - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - {{- with .Values.tolerations }} - tolerations: {{- toYaml . | nindent 8 }} - {{- end }} - volumes: - - name: csr - configMap: - name: {{ include "etcd.csrConfigMapName" . }} - - name: certs - emptyDir: {} diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_job_preinstall_2.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_job_preinstall_2.yaml deleted file mode 100644 index be55cddc..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_job_preinstall_2.yaml +++ /dev/null @@ -1,71 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - labels: - {{- include "etcd.labels" . | nindent 4 }} - annotations: - "helm.sh/hook": post-install - "helm.sh/hook-weight": "10" - "helm.sh/hook-delete-policy": "hook-succeeded,before-hook-creation,hook-failed" - name: "{{ .Release.Name }}-etcd-setup-2" - namespace: {{ .Release.Namespace }} -spec: - backoffLimit: 12 - template: - metadata: - name: "{{ .Release.Name }}" - spec: - serviceAccountName: {{ include "etcd.serviceAccountName" . }} - restartPolicy: Never - initContainers: - - name: kubectl - image: {{ printf "clastix/kubectl:%s" (include "etcd.jobsTagKubeVersion" .) }} - command: - - sh - - -c - - kubectl --namespace={{ .Release.Namespace }} rollout status sts/{{ include "etcd.stsName" . }} --timeout=300s - containers: - - command: - - bash - - -c - - |- - etcdctl member list -w table - if etcdctl user get root &>/dev/null; then - echo "User already exists, nothing to do" - else - etcdctl user add --no-password=true root && - etcdctl role add root && - etcdctl user grant-role root root && - etcdctl auth enable - fi - env: - - name: ETCDCTL_ENDPOINTS - value: https://{{ include "etcd.fullname" . }}-0.{{ include "etcd.serviceName" . }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.clientPort }} - - name: ETCDCTL_CACERT - value: /opt/certs/ca/ca.crt - - name: ETCDCTL_CERT - value: /opt/certs/root-certs/tls.crt - - name: ETCDCTL_KEY - value: /opt/certs/root-certs/tls.key - image: {{ include "etcd.fullyQualifiedDockerImage" . }} - imagePullPolicy: IfNotPresent - name: etcd-client - volumeMounts: - - name: root-certs - mountPath: /opt/certs/root-certs - - name: ca - mountPath: /opt/certs/ca - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - {{- with .Values.tolerations }} - tolerations: {{- toYaml . | nindent 8 }} - {{- end }} - volumes: - - name: root-certs - secret: - secretName: {{ include "etcd.clientSecretName" . }} - - name: ca - secret: - secretName: {{ include "etcd.caSecretName" . }} diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_job_s3retention.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_job_s3retention.yaml deleted file mode 100644 index cebe79f0..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_job_s3retention.yaml +++ /dev/null @@ -1,77 +0,0 @@ -{{- if .Values.backup.enabled -}} -{{- if .Values.backup.s3.retention -}} -apiVersion: batch/v1 -kind: Job -metadata: - labels: - {{- include "etcd.labels" . | nindent 4 }} - annotations: - "helm.sh/hook": post-install,post-upgrade,post-rollback - "helm.sh/hook-weight": "5" - "helm.sh/hook-delete-policy": "hook-succeeded,before-hook-creation,hook-failed" - name: "{{ .Release.Name }}-s3-retention" - namespace: {{ .Release.Namespace }} -spec: - template: - metadata: - name: "{{ .Release.Name }}" - spec: - serviceAccountName: {{ include "etcd.serviceAccountName" . }} - restartPolicy: OnFailure - containers: - - name: minio-client - image: {{ include "minio-client.fullyQualifiedDockerImage" . }} - imagePullPolicy: {{ .Values.backup.s3.image.pullPolicy }} - command: - - bash - - -c - - |- - cd ${MC_CONFIG_DIR} - if $MC alias set myminio ${S3_URL} ${S3_ACCESS_KEY} ${S3_SECRET_KEY} \ - && $MC ping myminio -c 3 -e 3 ; then - echo -e "\nCheck for already created object lifecycle management rule(s):" - if $MC ilm ls myminio/${S3_BUCKET} ; then - echo -e "\nObject lifecycle management rule(s) found - Clean up:" - $MC ilm rm --all --force myminio/${S3_BUCKET} - else - echo -e "\nNo object lifecycle management rule(s) found - Continue" - fi - echo -e "\nAdding object lifecycle management rule(s):" - $MC ilm add {{ .Values.backup.s3.retention }} myminio/${S3_BUCKET} - $MC ilm ls myminio/${S3_BUCKET} - else - echo -e "\nERROR: S3 storage could not be configured;\nCheck your S3 URL/Credentials or network connectivity" - exit 1 - fi - env: - - name: S3_URL - value: {{ .Values.backup.s3.url | quote }} - - name: S3_ACCESS_KEY - {{- if .Values.backup.s3.accessKey.value }} - value: {{ .Values.backup.s3.accessKey.value | quote }} - {{- else }} - valueFrom: - {{- toYaml .Values.backup.s3.accessKey.valueFrom | nindent 12 }} - {{- end }} - - name: S3_SECRET_KEY - {{- if .Values.backup.s3.secretKey.value }} - value: {{ .Values.backup.s3.secretKey.value | quote }} - {{- else }} - valueFrom: - {{- toYaml .Values.backup.s3.secretKey.valueFrom | nindent 12 }} - {{- end }} - - name: S3_BUCKET - value: {{ .Values.backup.s3.bucket | quote }} - - name: MC_CONFIG_DIR - value: /tmp - - name: MC - value: "/usr/bin/mc --config-dir ${MC_CONFIG_DIR}" - {{- with .Values.tolerations }} - tolerations: {{- toYaml . | nindent 8 }} - {{- end }} - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 -{{- end }} -{{- end }} diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_metrics_rbac.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_metrics_rbac.yaml deleted file mode 100644 index fb6996fc..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_metrics_rbac.yaml +++ /dev/null @@ -1,46 +0,0 @@ -{{- if .Values.serviceMonitor.enabled }} -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - labels: - {{- include "etcd.labels" . | nindent 4 }} - {{- if .Values.serviceMonitor.labels }} - {{- toYaml .Values.serviceMonitor.labels | nindent 4 }} - {{- end }} - {{- with .Values.customAnnotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} - name: {{ include "etcd.fullname" . }}-metrics-role - namespace: {{ .Values.serviceMonitor.namespace | default .Release.Namespace }} -rules: -- apiGroups: - - "" - resources: - - services - - endpoints - - pods - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - labels: - {{- include "etcd.labels" . | nindent 4 }} - {{- if .Values.serviceMonitor.labels }} - {{- toYaml .Values.serviceMonitor.labels | nindent 4 }} - {{- end }} - name: {{ include "etcd.fullname" . }}-metrics-rolebinding - namespace: {{ .Values.serviceMonitor.namespace | default .Release.Namespace }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: {{ include "etcd.fullname" . }}-metrics-role -subjects: -- kind: ServiceAccount - name: {{ .Values.serviceMonitor.serviceAccount.name }} - namespace: {{ .Values.serviceMonitor.serviceAccount.namespace | default .Release.Namespace }} -{{- end }} diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_rbac.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_rbac.yaml deleted file mode 100644 index bdd41be1..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_rbac.yaml +++ /dev/null @@ -1,60 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - annotations: - "helm.sh/hook": pre-install,post-install,pre-delete - "helm.sh/hook-delete-policy": "hook-succeeded,before-hook-creation,hook-failed" - "helm.sh/hook-weight": "5" - labels: - {{- include "etcd.labels" . | nindent 4 }} - name: {{ include "etcd.roleName" . }} - namespace: {{ .Release.Namespace }} -rules: - - apiGroups: - - "" - resources: - - secrets - verbs: - - get - - patch - - delete - resourceNames: - - {{ include "etcd.caSecretName" . }} - - {{ include "etcd.clientSecretName" . }} - - apiGroups: - - "" - resources: - - secrets - verbs: - - create - - apiGroups: - - apps - resources: - - statefulsets - verbs: - - get - - list - - watch - - patch - resourceNames: - - {{ include "etcd.stsName" . }} ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - annotations: - "helm.sh/hook": pre-install,post-install,pre-delete - "helm.sh/hook-delete-policy": "hook-succeeded,before-hook-creation,hook-failed" - "helm.sh/hook-weight": "5" - labels: - {{- include "etcd.labels" . | nindent 4 }} - name: {{ include "etcd.roleBindingName" . }} - namespace: {{ .Release.Namespace }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: {{ include "etcd.roleName" . }} -subjects: - - kind: ServiceAccount - name: {{ include "etcd.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_sa.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_sa.yaml deleted file mode 100644 index 99061ba7..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_sa.yaml +++ /dev/null @@ -1,15 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "etcd.serviceAccountName" . }} - labels: - {{- include "etcd.labels" . | nindent 4 }} - annotations: - "helm.sh/hook": pre-install - "helm.sh/hook-delete-policy": "before-hook-creation,hook-failed" - "helm.sh/hook-weight": "0" - {{- with .Values.serviceAccount.annotations }} - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_service.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_service.yaml deleted file mode 100644 index 8b739e87..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_service.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - {{- include "etcd.labels" . | nindent 4 }} - name: {{ include "etcd.serviceName" . }} - namespace: {{ .Release.Namespace }} -spec: - clusterIP: None - ports: - - port: {{ .Values.clientPort }} - name: client - - port: {{ .Values.peerApiPort }} - name: peer - - port: {{ .Values.metricsPort }} - name: metrics - selector: - {{- include "etcd.selectorLabels" . | nindent 4 }} diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_service_monitor.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_service_monitor.yaml deleted file mode 100644 index 8b9c1aa3..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_service_monitor.yaml +++ /dev/null @@ -1,47 +0,0 @@ -{{- if .Values.serviceMonitor.enabled }} -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: {{ include "etcd.fullname" . }}-monitor - namespace: {{ .Values.serviceMonitor.namespace | default .Release.Namespace }} - labels: - {{- include "etcd.labels" . | nindent 4 }} - {{- with .Values.serviceMonitor.labels }} - {{- toYaml . | nindent 4 }} - {{- end }} - {{- with .Values.serviceMonitor.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - endpoints: - {{- with .Values.serviceMonitor.endpoint }} - - interval: {{ .interval }} - port: metrics - path: /metrics - {{- with .scrapeTimeout }} - scrapeTimeout: {{ . }} - {{- end }} - {{- with .metricRelabelings }} - metricRelabelings: {{- toYaml . | nindent 6 }} - {{- end }} - {{- with .relabelings }} - relabelings: {{- toYaml . | nindent 6 }} - {{- end }} - {{- end }} - jobLabel: app.kubernetes.io/name - {{- with .Values.serviceMonitor.targetLabels }} - targetLabels: {{- toYaml . | nindent 4 }} - {{- end }} - selector: - matchLabels: - {{- if .Values.serviceMonitor.matchLabels }} - {{- toYaml .Values.serviceMonitor.matchLabels | nindent 6 }} - {{- else }} - {{- include "etcd.labels" . | nindent 6 }} - {{- end }} - namespaceSelector: - matchNames: - - {{ .Release.Namespace }} -{{- end }} - diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_sts.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_sts.yaml deleted file mode 100644 index 16b84e9e..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_sts.yaml +++ /dev/null @@ -1,117 +0,0 @@ -apiVersion: apps/v1 -kind: StatefulSet -metadata: - labels: - {{- include "etcd.labels" . | nindent 4 }} - name: {{ include "etcd.stsName" . }} - namespace: {{ .Release.Namespace }} -spec: - serviceName: {{ include "etcd.serviceName" . }} - selector: - matchLabels: - {{- include "etcd.selectorLabels" . | nindent 6 }} - replicas: {{ .Values.replicas }} - template: - metadata: - name: etcd - labels: - {{- include "etcd.selectorLabels" . | nindent 8 }} - {{- if .Values.podLabels }} - {{- toYaml .Values.podLabels | nindent 8 }} - {{- end }} - annotations: - {{- if .Values.podAnnotations }} - {{- toYaml .Values.podAnnotations | nindent 8 }} - {{- end }} - spec: - volumes: - - name: certs - secret: - secretName: {{ include "etcd.caSecretName" . }} - containers: - - name: etcd - image: {{ include "etcd.fullyQualifiedDockerImage" . }} - imagePullPolicy: {{ .Values.image.pullPolicy }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 12 }} - ports: - - containerPort: {{ .Values.clientPort }} - name: client - - containerPort: {{ .Values.peerApiPort }} - name: peer - - containerPort: {{ .Values.metricsPort }} - name: metrics - volumeMounts: - - name: data - mountPath: /var/run/etcd - - name: certs - mountPath: /etc/etcd/pki - command: - - etcd - - --data-dir=/var/run/etcd - - --name=$(POD_NAME) - - --initial-cluster-state=new - - --initial-cluster={{ include "etcd.initialCluster" . }} - - --initial-advertise-peer-urls=https://$(POD_NAME).{{ include "etcd.serviceName" . }}.$(POD_NAMESPACE).svc.cluster.local:{{ .Values.peerApiPort }} - - --advertise-client-urls=https://$(POD_NAME).{{ include "etcd.serviceName" . }}.$(POD_NAMESPACE).svc.cluster.local:{{ .Values.clientPort }} - - --initial-cluster-token=kamaji - - --listen-client-urls=https://0.0.0.0:{{ .Values.clientPort }} - - --listen-metrics-urls=http://0.0.0.0:{{ .Values.metricsPort }} - - --listen-peer-urls=https://0.0.0.0:{{ .Values.peerApiPort }} - - --client-cert-auth=true - - --peer-client-cert-auth=true - - --trusted-ca-file=/etc/etcd/pki/ca.crt - - --cert-file=/etc/etcd/pki/server.pem - - --key-file=/etc/etcd/pki/server-key.pem - - --peer-trusted-ca-file=/etc/etcd/pki/ca.crt - - --peer-cert-file=/etc/etcd/pki/peer.pem - - --peer-key-file=/etc/etcd/pki/peer-key.pem - - --auto-compaction-mode={{ .Values.autoCompactionMode }} - - --auto-compaction-retention={{ .Values.autoCompactionRetention }} - - --snapshot-count={{ .Values.snapshotCount }} - - --quota-backend-bytes={{ .Values.quotaBackendBytes }} - {{- with .Values.extraArgs }} - {{- toYaml . | nindent 12 }} - {{- end }} - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - {{- with .Values.livenessProbe }} - livenessProbe: - {{- toYaml . | nindent 12 }} - {{- end }} - priorityClassName: {{- toYaml .Values.priorityClassName | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.topologySpreadConstraints }} - topologySpreadConstraints: {{- toYaml . | nindent 8 }} - {{- end }} - volumeClaimTemplates: - - metadata: - name: data - {{- with .Values.persistentVolumeClaim.customAnnotations }} - annotations: - {{- toYaml . | nindent 10 }} - {{- end }} - spec: - storageClassName: {{ .Values.persistentVolumeClaim.storageClassName }} - accessModes: - {{- range .Values.persistentVolumeClaim.accessModes }} - - {{ . | quote }} - {{- end }} - resources: - requests: - storage: {{ .Values.persistentVolumeClaim.size }} diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/values.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/values.yaml deleted file mode 100644 index ca7a1c08..00000000 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/values.yaml +++ /dev/null @@ -1,223 +0,0 @@ -# Default values for kamaji-crane. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -# -- Size of the etcd cluster -replicas: 3 - -# -- Install an etcd with enabled multi-tenancy -serviceAccount: - # -- Create a ServiceAccount, required to install and provision the etcd backing storage (default: true) - create: true - # -- Define the ServiceAccount name to use during the setup and provision of the etcd backing storage (default: "") - name: "" - -image: - # -- Install image from specific repo - repository: quay.io/coreos/etcd - # -- Install image with specific tag, overwrite the tag in the chart - tag: "" - # -- Pull policy to use - pullPolicy: IfNotPresent - -# -- The peer API port which servers are listening to. -peerApiPort: 2380 - -# -- The client request port. -clientPort: 2379 - -# -- The port where etcd exposes metrics. -metricsPort: 2381 - -# -- The livenessProbe for the etcd container -livenessProbe: {} -# failureThreshold: 8 -# httpGet: -# path: /health?serializable=true -# port: 2381 -# scheme: HTTP -# initialDelaySeconds: 10 -# periodSeconds: 10 -# timeoutSeconds: 15 - -# -- A list of extra arguments to add to the etcd default ones -extraArgs: [] -#- --log-level=warn -#- --logger=zap - -# -- Interpret 'auto-compaction-retention' one of: periodic|revision. Use 'periodic' for duration based retention, 'revision' for revision number based retention. -autoCompactionMode: periodic - -# -- Auto compaction retention length. 0 means disable auto compaction. -autoCompactionRetention: 5m - -# -- Number of committed transactions to trigger a snapshot to disk. -snapshotCount: "10000" - -# -- Raise alarms when backend size exceeds the given quota. It will put the cluster into a maintenance mode which only accepts key reads and deletes. -quotaBackendBytes: "8589934592" # 8Gi - -persistentVolumeClaim: - # -- The size of persistent storage for etcd data - size: 10Gi - # -- A specific storage class - storageClassName: "" - # -- The Access Mode to storage - accessModes: - - ReadWriteOnce - # -- The custom annotations to add to the PVC - customAnnotations: {} - # volumeType: local - -# -- Enable storage defragmentation -defragmentation: - # -- The job scheduled maintenance time for defrag (empty to disable) - schedule: "*/15 * * * *" # https://crontab.guru/ - -# -- Enable storage backup -backup: - # -- Enable scheduling backup job - enabled: false - # -- Enable backup for all endpoints. When disabled, only the leader will be taken - all: false - # -- The job scheduled maintenance time for backup - schedule: "20 3 * * *" # https://crontab.guru/ - # -- The backup file name prefix - snapshotNamePrefix: mysnapshot - # -- The backup file date format (bash) - snapshotDateFormat: $(date +%Y%m%d) - # -- The S3 storage config section - s3: - # -- The S3 storage url - url: http://mys3storage:9000 - # -- The S3 storage bucket - bucket: mybucket - # -- The S3 storage object lifecycle management rules; N.B. enabling this option will delete previously set lifecycle rules - retention: "" #"--expiry-days 7" - # -- The S3 storage ACCESS KEY credential. The plain value has precedence over the valueFrom that can be used to retrieve the value from a Secret. - accessKey: - value: "" - valueFrom: {} - # secretKeyRef: - # key: access_key - # name: minio-key - # -- The S3 storage SECRET KEY credential. The plain value has precedence over the valueFrom that can be used to retrieve the value from a Secret. - secretKey: - value: "" - valueFrom: {} - # secretKeyRef: - # key: secret_key - # name: minio-key - # -- The S3 client image config section - image: - # -- Install image from specific repo - repository: minio/mc - # -- Install image with specific tag - tag: "RELEASE.2022-11-07T23-47-39Z" - # -- Pull policy to use - pullPolicy: IfNotPresent - -# -- Labels to add to all etcd pods -podLabels: - application: kamaji-etcd - -# -- Annotations to add to all etcd pods -podAnnotations: {} - -# -- The securityContext to apply to etcd -securityContext: - allowPrivilegeEscalation: false - -# -- The priorityClassName to apply to etcd -priorityClassName: system-cluster-critical - -# -- Resources assigned to the etcd containers -resources: - limits: {} - requests: {} - -# -- Kubernetes node selector rules to schedule etcd -nodeSelector: - kubernetes.io/os: linux - -# -- Kubernetes node taints that the etcd pods would tolerate -tolerations: [] - -# -- Kubernetes affinity rules to apply to etcd controller pods -affinity: {} - -# -- Kubernetes topology spread constraints to apply to etcd controller pods -topologySpreadConstraints: [] -#- maxSkew: 1 -# topologyKey: topology.kubernetes.io/zone -# whenUnsatisfiable: DoNotSchedule -# labelSelector: -# matchLabels: -# application: kamaji-etcd - -datastore: - # -- Create a datastore custom resource for Kamaji - enabled: false - -serviceMonitor: - # -- Enable ServiceMonitor for Prometheus - enabled: false - # -- Install the ServiceMonitor into a different Namespace, as the monitoring stack one (default: the release one) - namespace: '' - # -- Assign additional labels according to Prometheus' serviceMonitorSelector matching labels - labels: {} - # -- Assign additional Annotations - annotations: {} - # -- Change matching labels - matchLabels: {} - # -- Set targetLabels for the serviceMonitor - targetLabels: [] - serviceAccount: - # -- ServiceAccount for Metrics RBAC - name: etcd - # -- ServiceAccount Namespace for Metrics RBAC - namespace: etcd-system - endpoint: - # -- Set the scrape interval for the endpoint of the serviceMonitor - interval: "15s" - # -- Set the scrape timeout for the endpoint of the serviceMonitor - scrapeTimeout: "" - # -- Set metricRelabelings for the endpoint of the serviceMonitor - metricRelabelings: [] - # -- Set relabelings for the endpoint of the serviceMonitor - relabelings: [] - #- action: replace - # regex: (.+) - # replacement: $1 - # sourceLabels: - # - __meta_kubernetes_pod_name - # targetLabel: member - # - -alerts: - # -- Enable alerts for Alertmanager - enabled: false - # -- Install the Alerts into a different Namespace, as the monitoring stack one (default: the release one) - namespace: '' - # -- Assign additional labels according to Prometheus' Alerts matching labels - labels: {} - # -- Assign additional Annotations - annotations: {} - # -- The rules for alerts - rules: [] - # - alert: etcdNoLeader - # annotations: - # message: 'etcd cluster: member {{ $labels.instance }} has no leader.' - # expr: count(etcd_server_has_leader{job=~".*etcd.*"}) == 0 - # for: 1m - # labels: - # severity: critical - # - alert: EtcdDataBaseSize - # annotations: - # message: 'etcd cluster: "member {{ $labels.instance }} db has almost exceeded 8GB".' - # expr: |- - # etcd_mvcc_db_total_size_in_bytes{job=~".*etcd.*"} >= 8589934592 - # for: 15m - # labels: - # severity: critical - # diff --git a/packages/system/kamaji-etcd/patches/fix-svc.diff b/packages/system/kamaji-etcd/patches/fix-svc.diff deleted file mode 100644 index a94ebf96..00000000 --- a/packages/system/kamaji-etcd/patches/fix-svc.diff +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_cm.yaml b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_cm.yaml -index 95a2671..bd8ddcb 100644 ---- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_cm.yaml -+++ b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/etcd_cm.yaml -@@ -57,6 +57,7 @@ data: - "hosts": [ - {{- range $count := until (int $.Values.replicas) -}} - {{ printf "\"%s-%d.%s.%s.svc.cluster.local\"," ( include "etcd.fullname" $outer ) $count (include "etcd.serviceName" $outer) $.Release.Namespace }} -+ {{ printf "\"%s-%d.%s.%s.svc\"," ( include "etcd.fullname" $outer ) $count (include "etcd.serviceName" $outer) $.Release.Namespace }} - {{- end }} - "etcd-server.{{ .Release.Namespace }}.svc.cluster.local", - "etcd-server.{{ .Release.Namespace }}.svc", diff --git a/packages/system/kamaji-etcd/patches/fullnameOverride.diff b/packages/system/kamaji-etcd/patches/fullnameOverride.diff deleted file mode 100644 index 29a1a7ed..00000000 --- a/packages/system/kamaji-etcd/patches/fullnameOverride.diff +++ /dev/null @@ -1,31 +0,0 @@ -diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/_helpers.tpl b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/_helpers.tpl -index 4f7014e..403e187 100644 ---- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/_helpers.tpl -+++ b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/_helpers.tpl -@@ -9,8 +9,17 @@ Expand the name of the chart. - Create a default fully qualified etcd name. - */}} - {{- define "etcd.fullname" -}} --{{- .Release.Name }} --{{- end }} -+{{- if .Values.fullnameOverride -}} -+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -+{{- else -}} -+{{- $name := default .Chart.Name .Values.nameOverride -}} -+{{- if contains $name .Release.Name -}} -+{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -+{{- else -}} -+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -+{{- end -}} -+{{- end -}} -+{{- end -}} - - {{/* - Create chart name and version as used by the chart label. -@@ -156,4 +165,4 @@ Create the minio-client fully-qualified Docker image to use - */}} - {{- define "minio-client.fullyQualifiedDockerImage" -}} - {{- printf "%s:%s" .Values.backup.s3.image.repository .Values.backup.s3.image.tag -}} --{{- end }} -\ No newline at end of file -+{{- end }} diff --git a/packages/system/kamaji-etcd/patches/remove-plus.patch b/packages/system/kamaji-etcd/patches/remove-plus.patch deleted file mode 100644 index 55bba3b8..00000000 --- a/packages/system/kamaji-etcd/patches/remove-plus.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/_helpers.tpl b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/_helpers.tpl -index 403e187..e68a967 100644 ---- a/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/_helpers.tpl -+++ b/packages/system/kamaji-etcd/charts/kamaji-etcd/templates/_helpers.tpl -@@ -119,11 +119,7 @@ Name of the etcd root-client secret. - Retrieve the current Kubernetes version to launch a kubectl container with the minimum version skew possible. - */}} - {{- define "etcd.jobsTagKubeVersion" -}} --{{- if contains "-eks-" .Capabilities.KubeVersion.GitVersion }} - {{- print "v" .Capabilities.KubeVersion.Major "." (.Capabilities.KubeVersion.Minor | replace "+" "") -}} --{{- else }} --{{- print "v" .Capabilities.KubeVersion.Major "." .Capabilities.KubeVersion.Minor -}} --{{- end }} - {{- end }} - - {{/* diff --git a/packages/system/kamaji-etcd/templates/datastore.yaml b/packages/system/kamaji-etcd/templates/datastore.yaml deleted file mode 100644 index 9ca2ffee..00000000 --- a/packages/system/kamaji-etcd/templates/datastore.yaml +++ /dev/null @@ -1,33 +0,0 @@ -apiVersion: kamaji.clastix.io/v1alpha1 -kind: DataStore -metadata: - name: {{ .Release.Namespace }} -spec: - driver: etcd - endpoints: - - etcd-0.etcd.{{ .Release.Namespace }}.svc:2379 - - etcd-1.etcd.{{ .Release.Namespace }}.svc:2379 - - etcd-2.etcd.{{ .Release.Namespace }}.svc:2379 - tlsConfig: - certificateAuthority: - certificate: - secretReference: - keyPath: ca.crt - name: etcd-certs - namespace: {{ .Release.Namespace }} - privateKey: - secretReference: - keyPath: ca.key - name: etcd-certs - namespace: {{ .Release.Namespace }} - clientCertificate: - certificate: - secretReference: - keyPath: tls.crt - name: etcd-root-client-certs - namespace: {{ .Release.Namespace }} - privateKey: - secretReference: - keyPath: tls.key - name: etcd-root-client-certs - namespace: {{ .Release.Namespace }} diff --git a/packages/system/kamaji/Makefile b/packages/system/kamaji/Makefile index aa864c1a..b23fb1bf 100644 --- a/packages/system/kamaji/Makefile +++ b/packages/system/kamaji/Makefile @@ -1,30 +1,26 @@ export NAME=kamaji export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts - tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/clastix/kamaji | grep refs/tags/edge- | awk -F'[/^]' 'END{print $$3}') && \ + tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/clastix/kamaji | grep -E 'refs/tags/[0-9]+\.[0-9]+\.[0-9]+-edge$$' | awk -F/ 'END{print $$NF}') && \ curl -sSL https://github.com/clastix/kamaji/archive/refs/tags/$${tag}.tar.gz | \ tar -xzvf - --strip 1 kamaji-$${tag}/charts && \ sed -i "/ARG VERSION/ s|=.*|=$${tag}|g" images/kamaji/Dockerfile 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 \ --metadata-file images/kamaji.json \ - --push=$(PUSH) \ - --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" - --load=$(LOAD) + $(BUILDX_ARGS) REPOSITORY="$(REGISTRY)/kamaji" \ yq -i '.kamaji.image.repository = strenv(REPOSITORY)' values.yaml TAG=$(TAG)@$$(yq e '."containerimage.digest"' images/kamaji.json -o json -r) \ yq -i '.kamaji.image.tag = strenv(TAG)' values.yaml + yq -i '.kamaji.extraArgs[0] = "--migrate-image=" + .kamaji.image.repository + ":" + .kamaji.image.tag' values.yaml rm -f images/kamaji.json diff --git a/packages/system/kamaji/charts/kamaji-crds/.helmignore b/packages/system/kamaji/charts/kamaji-crds/.helmignore new file mode 100644 index 00000000..a03977f5 --- /dev/null +++ b/packages/system/kamaji/charts/kamaji-crds/.helmignore @@ -0,0 +1,28 @@ +# 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/ +# Helm source files +README.md.gotmpl +.helmignore +# Build tools +Makefile diff --git a/packages/system/kamaji/charts/kamaji-crds/Chart.yaml b/packages/system/kamaji/charts/kamaji-crds/Chart.yaml new file mode 100644 index 00000000..0cb9e660 --- /dev/null +++ b/packages/system/kamaji/charts/kamaji-crds/Chart.yaml @@ -0,0 +1,39 @@ +apiVersion: v2 +appVersion: latest +description: Kamaji is the Hosted Control Plane Manager for Kubernetes. +home: https://github.com/clastix/kamaji +icon: https://github.com/clastix/kamaji/raw/master/assets/logo-colored.png +maintainers: + - email: dario@tranchitella.eu + name: Dario Tranchitella + url: https://clastix.io + - email: me@bsctl.io + name: Adriano Pezzuto + url: https://clastix.io +name: kamaji-crds +sources: + - https://github.com/clastix/kamaji +type: application +version: 0.0.0+latest +annotations: + artifacthub.io/crds: | + - kind: TenantControlPlane + version: v1alpha1 + name: tenantcontrolplanes.kamaji.clastix.io + displayName: TenantControlPlane + description: TenantControlPlane defines the desired state for a Control Plane backed by Kamaji. + - kind: DataStore + version: v1alpha1 + name: datastores.kamaji.clastix.io + displayName: DataStore + description: DataStores is holding all the required details to communicate with a Datastore, such as etcd, MySQL, PostgreSQL, and NATS. + artifacthub.io/links: | + - name: CLASTIX + url: https://clastix.io + - name: support + url: https://clastix.io/support + artifacthub.io/changes: | + - kind: changed + description: Upgrading support to Kubernetes v1.35 + - kind: added + description: Supporting multiple Datastore via etcd overrides diff --git a/packages/system/kamaji-etcd/charts/kamaji-etcd/Makefile b/packages/system/kamaji/charts/kamaji-crds/Makefile similarity index 98% rename from packages/system/kamaji-etcd/charts/kamaji-etcd/Makefile rename to packages/system/kamaji/charts/kamaji-crds/Makefile index 94f47498..a191fe4c 100644 --- a/packages/system/kamaji-etcd/charts/kamaji-etcd/Makefile +++ b/packages/system/kamaji/charts/kamaji-crds/Makefile @@ -6,4 +6,4 @@ docker: @hash docker 2>/dev/null || {\ echo "You need docker" &&\ exit 1;\ - } \ No newline at end of file + } diff --git a/packages/system/kamaji/charts/kamaji-crds/NOTES.txt b/packages/system/kamaji/charts/kamaji-crds/NOTES.txt new file mode 100644 index 00000000..c9ba0004 --- /dev/null +++ b/packages/system/kamaji/charts/kamaji-crds/NOTES.txt @@ -0,0 +1,2 @@ +Kamaji Custom Resource Definitions have been installed properly: +you can proceed to upgrade your Kamaji operator instance. diff --git a/packages/system/kamaji/charts/kamaji-crds/README.md b/packages/system/kamaji/charts/kamaji-crds/README.md new file mode 100644 index 00000000..c7b23dca --- /dev/null +++ b/packages/system/kamaji/charts/kamaji-crds/README.md @@ -0,0 +1,66 @@ +# kamaji-crds + +![Version: 0.0.0+latest](https://img.shields.io/badge/Version-0.0.0+latest-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: latest](https://img.shields.io/badge/AppVersion-latest-informational?style=flat-square) + +Kamaji is the Hosted Control Plane Manager for Kubernetes. + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| Dario Tranchitella | | | +| Adriano Pezzuto | | | + +## Source Code + +* + +[Kamaji](https://github.com/clastix/kamaji) Custom Resource Definitions packaged as Helm Charts. + +## How to use this chart + +Add `clastix` Helm repository: + + helm repo add clastix https://clastix.github.io/charts + +Install the Chart with the release name `kamaji-crds`: + + helm upgrade --install --namespace kamaji-system --create-namespace kamaji-crds clastix/kamaji-crds + +Show the status: + + helm status kamaji-crds -n kamaji-system + +Upgrade the Chart + + helm upgrade kamaji-crds -n kamaji-system clastix/kamaji-crds + +Uninstall the Chart + + helm uninstall kamaji-crds -n kamaji-system + +## Customize the installation + +There are two methods for specifying overrides of values during Chart installation: `--values` and `--set`. + +The `--values` option is the preferred method because it allows you to keep your overrides in a YAML file, rather than specifying them all on the command line. Create a copy of the YAML file `values.yaml` and add your overrides to it. + +Specify your overrides file when you install the Chart: + + helm upgrade kamaji-crds --install --namespace kamaji-system --create-namespace clastix/kamaji-crds --values myvalues.yaml + +The values in your overrides file `myvalues.yaml` will override their counterparts in the Chart's values.yaml file. Any values in `values.yaml` that weren’t overridden will keep their defaults. + +If you only need to make minor customizations, you can specify them on the command line by using the `--set` option. For example: + + helm upgrade kamaji-crds --install --namespace kamaji-system --create-namespace clastix/kamaji-crds --set kamajiCertificateName=kamaji + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| fullnameOverride | string | `""` | Overrides the full name of the resources created by the chart. | +| kamajiCertificateName | string | `"kamaji-serving-cert"` | The cert-manager Certificate resource name, holding the Certificate Authority for webhooks. | +| kamajiNamespace | string | `"kamaji-system"` | The namespace where Kamaji has been installed: required to inject the Certificate Authority for cert-manager. | +| kamajiService | string | `"kamaji-webhook-service"` | The Kamaji webhook Service name. | +| nameOverride | string | `""` | Overrides the name of the chart for resource naming purposes. | diff --git a/packages/system/kamaji/charts/kamaji-crds/README.md.gotmpl b/packages/system/kamaji/charts/kamaji-crds/README.md.gotmpl new file mode 100644 index 00000000..c7c26771 --- /dev/null +++ b/packages/system/kamaji/charts/kamaji-crds/README.md.gotmpl @@ -0,0 +1,54 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.badgesSection" . }} + +{{ template "chart.description" . }} + +{{ template "chart.maintainersSection" . }} + +{{ template "chart.sourcesSection" . }} + +{{ template "chart.requirementsSection" . }} + +[Kamaji](https://github.com/clastix/kamaji) Custom Resource Definitions packaged as Helm Charts. + +## How to use this chart + +Add `clastix` Helm repository: + + helm repo add clastix https://clastix.github.io/charts + +Install the Chart with the release name `kamaji-crds`: + + helm upgrade --install --namespace kamaji-system --create-namespace kamaji-crds clastix/kamaji-crds + +Show the status: + + helm status kamaji-crds -n kamaji-system + +Upgrade the Chart + + helm upgrade kamaji-crds -n kamaji-system clastix/kamaji-crds + +Uninstall the Chart + + helm uninstall kamaji-crds -n kamaji-system + +## Customize the installation + +There are two methods for specifying overrides of values during Chart installation: `--values` and `--set`. + +The `--values` option is the preferred method because it allows you to keep your overrides in a YAML file, rather than specifying them all on the command line. Create a copy of the YAML file `values.yaml` and add your overrides to it. + +Specify your overrides file when you install the Chart: + + helm upgrade kamaji-crds --install --namespace kamaji-system --create-namespace clastix/kamaji-crds --values myvalues.yaml + +The values in your overrides file `myvalues.yaml` will override their counterparts in the Chart's values.yaml file. Any values in `values.yaml` that weren’t overridden will keep their defaults. + +If you only need to make minor customizations, you can specify them on the command line by using the `--set` option. For example: + + helm upgrade kamaji-crds --install --namespace kamaji-system --create-namespace clastix/kamaji-crds --set kamajiCertificateName=kamaji + +{{ template "chart.valuesSection" . }} diff --git a/packages/system/kamaji/charts/kamaji-crds/hack/crd-conversion.yaml b/packages/system/kamaji/charts/kamaji-crds/hack/crd-conversion.yaml new file mode 100644 index 00000000..be48bdb0 --- /dev/null +++ b/packages/system/kamaji/charts/kamaji-crds/hack/crd-conversion.yaml @@ -0,0 +1,11 @@ +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: kamaji-webhook-service + namespace: kamaji-system + path: /convert + conversionReviewVersions: + - v1 diff --git a/packages/system/kamaji/charts/kamaji-crds/hack/kamaji.clastix.io_datastores_spec.yaml b/packages/system/kamaji/charts/kamaji-crds/hack/kamaji.clastix.io_datastores_spec.yaml new file mode 100644 index 00000000..c02419af --- /dev/null +++ b/packages/system/kamaji/charts/kamaji-crds/hack/kamaji.clastix.io_datastores_spec.yaml @@ -0,0 +1,361 @@ +group: kamaji.clastix.io +names: + kind: DataStore + listKind: DataStoreList + plural: datastores + singular: datastore +scope: Cluster +versions: + - additionalPrinterColumns: + - description: Kamaji data store driver + jsonPath: .spec.driver + name: Driver + type: string + - description: DataStore validated and ready for use + jsonPath: .status.ready + name: Ready + type: boolean + - description: Age + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: DataStore is the Schema for the datastores API. + 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: DataStoreSpec defines the desired state of DataStore. + properties: + basicAuth: + description: |- + In case of authentication enabled for the given data store, specifies the username and password pair. + This value is optional. + properties: + password: + properties: + content: + description: |- + Bare content of the file, base64 encoded. + It has precedence over the SecretReference value. + format: byte + type: string + secretReference: + properties: + keyPath: + description: |- + Name of the key for the given Secret reference where the content is stored. + This value is mandatory. + minLength: 1 + type: string + name: + description: name is unique within a namespace to reference a secret resource. + type: string + namespace: + description: namespace defines the space within which the secret name must be unique. + type: string + required: + - keyPath + type: object + x-kubernetes-map-type: atomic + type: object + username: + properties: + content: + description: |- + Bare content of the file, base64 encoded. + It has precedence over the SecretReference value. + format: byte + type: string + secretReference: + properties: + keyPath: + description: |- + Name of the key for the given Secret reference where the content is stored. + This value is mandatory. + minLength: 1 + type: string + name: + description: name is unique within a namespace to reference a secret resource. + type: string + namespace: + description: namespace defines the space within which the secret name must be unique. + type: string + required: + - keyPath + type: object + x-kubernetes-map-type: atomic + type: object + required: + - password + - username + type: object + driver: + description: The driver to use to connect to the shared datastore. + enum: + - etcd + - MySQL + - 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. + No need for protocol, just bare IP/FQDN and port. + items: + type: string + minItems: 1 + type: array + tlsConfig: + description: |- + Defines the TLS/SSL configuration required to connect to the data store in a secure way. + This value is optional. + properties: + certificateAuthority: + description: |- + Retrieve the Certificate Authority certificate and private key, such as bare content of the file, or a SecretReference. + The key reference is required since etcd authentication is based on certificates, and Kamaji is responsible in creating this. + properties: + certificate: + properties: + content: + description: |- + Bare content of the file, base64 encoded. + It has precedence over the SecretReference value. + format: byte + type: string + secretReference: + properties: + keyPath: + description: |- + Name of the key for the given Secret reference where the content is stored. + This value is mandatory. + minLength: 1 + type: string + name: + description: name is unique within a namespace to reference a secret resource. + type: string + namespace: + description: namespace defines the space within which the secret name must be unique. + type: string + required: + - keyPath + type: object + x-kubernetes-map-type: atomic + type: object + privateKey: + properties: + content: + description: |- + Bare content of the file, base64 encoded. + It has precedence over the SecretReference value. + format: byte + type: string + secretReference: + properties: + keyPath: + description: |- + Name of the key for the given Secret reference where the content is stored. + This value is mandatory. + minLength: 1 + type: string + name: + description: name is unique within a namespace to reference a secret resource. + type: string + namespace: + description: namespace defines the space within which the secret name must be unique. + type: string + required: + - keyPath + type: object + x-kubernetes-map-type: atomic + type: object + required: + - certificate + type: object + clientCertificate: + description: Specifies the SSL/TLS key and private key pair used to connect to the data store. + properties: + certificate: + properties: + content: + description: |- + Bare content of the file, base64 encoded. + It has precedence over the SecretReference value. + format: byte + type: string + secretReference: + properties: + keyPath: + description: |- + Name of the key for the given Secret reference where the content is stored. + This value is mandatory. + minLength: 1 + type: string + name: + description: name is unique within a namespace to reference a secret resource. + type: string + namespace: + description: namespace defines the space within which the secret name must be unique. + type: string + required: + - keyPath + type: object + x-kubernetes-map-type: atomic + type: object + privateKey: + properties: + content: + description: |- + Bare content of the file, base64 encoded. + It has precedence over the SecretReference value. + format: byte + type: string + secretReference: + properties: + keyPath: + description: |- + Name of the key for the given Secret reference where the content is stored. + This value is mandatory. + minLength: 1 + type: string + name: + description: name is unique within a namespace to reference a secret resource. + type: string + namespace: + description: namespace defines the space within which the secret name must be unique. + type: string + required: + - keyPath + type: object + x-kubernetes-map-type: atomic + type: object + required: + - certificate + - privateKey + type: object + required: + - certificateAuthority + type: object + required: + - 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' + - message: driver is immutable and cannot be changed after creation + rule: oldSelf == null || self.driver == oldSelf.driver + status: + description: DataStoreStatus defines the observed state of DataStore. + properties: + conditions: + description: Conditions contains the validation conditions for the given Datastore. + 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 + type: array + observedGeneration: + description: ObservedGeneration represents the .metadata.generation that was last reconciled. + format: int64 + type: integer + ready: + description: |- + Ready returns if the DataStore is accepted and ready to get used: + Kamaji will ensure certificates are available, or correctly referenced. + type: boolean + usedBy: + description: List of the Tenant Control Planes, namespaced named, using this data store. + items: + type: string + type: array + required: + - ready + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/kamaji/charts/kamaji-crds/hack/kamaji.clastix.io_kubeconfiggenerators_spec.yaml b/packages/system/kamaji/charts/kamaji-crds/hack/kamaji.clastix.io_kubeconfiggenerators_spec.yaml new file mode 100644 index 00000000..3f71f481 --- /dev/null +++ b/packages/system/kamaji/charts/kamaji-crds/hack/kamaji.clastix.io_kubeconfiggenerators_spec.yaml @@ -0,0 +1,218 @@ +group: kamaji.clastix.io +names: + categories: + - kamaji + kind: KubeconfigGenerator + listKind: KubeconfigGeneratorList + plural: kubeconfiggenerators + shortNames: + - kc + singular: kubeconfiggenerator +scope: Cluster +versions: + - additionalPrinterColumns: + - description: Age + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: KubeconfigGenerator is the Schema for the kubeconfiggenerators API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + controlPlaneEndpointFrom: + default: admin.svc + description: |- + ControlPlaneEndpointFrom is the key used to extract the Tenant Control Plane endpoint that must be used by the generator. + The targeted Secret is the `${TCP}-admin-kubeconfig` one, default to `admin.svc`. + type: string + groups: + description: |- + Groups is resolved a set of strings used to assign the x509 organisations field. + It will be recognised by Kubernetes as user groups. + items: + description: |- + CompoundValue allows defining a static, or a dynamic value. + Options are mutually exclusive, just one should be picked up. + properties: + fromDefinition: + description: |- + FromDefinition is used to generate a dynamic value, + it uses the dot notation to access fields from the referenced TenantControlPlane object: + e.g.: metadata.name + type: string + stringValue: + description: StringValue is a static string value. + type: string + type: object + x-kubernetes-validations: + - message: Either stringValue or fromDefinition must be set, but not both. + rule: (has(self.stringValue) || has(self.fromDefinition)) && !(has(self.stringValue) && has(self.fromDefinition)) + type: array + namespaceSelector: + description: NamespaceSelector is used to filter Namespaces from which the generator should extract TenantControlPlane objects. + 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 + tenantControlPlaneSelector: + description: TenantControlPlaneSelector is used to filter the TenantControlPlane objects that should be address by the generator. + 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 + user: + description: User resolves to a string to identify the client, assigned to the x509 Common Name field. + properties: + fromDefinition: + description: |- + FromDefinition is used to generate a dynamic value, + it uses the dot notation to access fields from the referenced TenantControlPlane object: + e.g.: metadata.name + type: string + stringValue: + description: StringValue is a static string value. + type: string + type: object + x-kubernetes-validations: + - message: Either stringValue or fromDefinition must be set, but not both. + rule: (has(self.stringValue) || has(self.fromDefinition)) && !(has(self.stringValue) && has(self.fromDefinition)) + required: + - user + type: object + status: + description: KubeconfigGeneratorStatus defines the observed state of KubeconfigGenerator. + properties: + availableResources: + default: 0 + description: |- + AvailableResources is the sum of successfully generated resources. + In case of a different value compared to Resources, check the field errors. + type: integer + errors: + description: Errors is the list of failed kubeconfig generations. + items: + properties: + message: + description: Message is the error message recorded upon the last generator run. + type: string + resource: + description: Resource is the Namespaced name of the errored resource. + type: string + required: + - message + - resource + type: object + type: array + observedGeneration: + description: ObservedGeneration represents the .metadata.generation that was last reconciled. + format: int64 + type: integer + resources: + default: 0 + description: Resources is the sum of targeted TenantControlPlane objects. + type: integer + required: + - availableResources + - resources + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/kamaji/charts/kamaji-crds/hack/kamaji.clastix.io_tenantcontrolplanes_spec.yaml b/packages/system/kamaji/charts/kamaji-crds/hack/kamaji.clastix.io_tenantcontrolplanes_spec.yaml new file mode 100644 index 00000000..9625abb4 --- /dev/null +++ b/packages/system/kamaji/charts/kamaji-crds/hack/kamaji.clastix.io_tenantcontrolplanes_spec.yaml @@ -0,0 +1,9253 @@ +group: kamaji.clastix.io +names: + categories: + - kamaji + kind: TenantControlPlane + listKind: TenantControlPlaneList + plural: tenantcontrolplanes + shortNames: + - tcp + singular: tenantcontrolplane +scope: Namespaced +versions: + - additionalPrinterColumns: + - description: Kubernetes version + jsonPath: .spec.kubernetes.version + name: Version + type: string + - description: The actual installed Kubernetes version from status + jsonPath: .status.kubernetesResources.version.version + name: Installed Version + type: string + - description: Status + jsonPath: .status.kubernetesResources.version.status + name: Status + type: string + - description: Tenant Control Plane Endpoint (API server) + jsonPath: .status.controlPlaneEndpoint + name: Control-Plane endpoint + type: string + - description: Secret which contains admin kubeconfig + jsonPath: .status.kubeconfig.admin.secretName + name: Kubeconfig + type: string + - description: DataStore actually used + jsonPath: .status.storage.dataStoreName + name: Datastore + type: string + - description: Age + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: TenantControlPlane is the Schema for the tenantcontrolplanes API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + addons: + description: Addons contain which addons are enabled + properties: + coreDNS: + description: |- + Enables the DNS addon in the Tenant Cluster. + The registry and the tag are configurable, the image is hard-coded to `coredns`. + properties: + imageRepository: + description: |- + ImageRepository sets the container registry to pull images from. + if not set, the default ImageRepository will be used instead. + type: string + imageTag: + description: |- + ImageTag allows to specify a tag for the image. + In case this value is set, kubeadm does not change automatically the version of the above components during upgrades. + type: string + type: object + konnectivity: + description: Enables the Konnectivity addon in the Tenant Cluster, required if the worker nodes are in a different network. + properties: + agent: + default: + image: registry.k8s.io/kas-network-proxy/proxy-agent + mode: DaemonSet + properties: + extraArgs: + description: |- + ExtraArgs allows adding additional arguments to said component. + WARNING - This option can override existing konnectivity + parameters and cause konnectivity components to misbehave in + unxpected ways. Only modify if you know what you are doing. + items: + type: string + type: array + hostNetwork: + default: false + description: |- + HostNetwork enables the konnectivity agent to use the Host network namespace. + By enabling this mode, the Agent doesn't need to wait for the CNI initialisation, + enabling a sort of out-of-band access to nodes for troubleshooting scenarios, + or when the agent needs direct access to the host network. + type: boolean + image: + default: registry.k8s.io/kas-network-proxy/proxy-agent + description: AgentImage defines the container image for Konnectivity's agent. + type: string + mode: + default: DaemonSet + description: 'Mode allows specifying the Agent deployment mode: Deployment, or DaemonSet (default).' + enum: + - DaemonSet + - Deployment + type: string + replicas: + description: |- + Replicas defines the number of replicas when Mode is Deployment. + Must be 0 if Mode is DaemonSet. + format: int32 + type: integer + tolerations: + default: + - key: CriticalAddonsOnly + operator: Exists + description: |- + Tolerations for the deployed agent. + Can be customized to start the konnectivity-agent even if the nodes are not ready or tainted. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + version: + description: |- + Version for Konnectivity agent. + If left empty, Kamaji will automatically inflect the version from the deployed Tenant Control Plane. + + WARNING: for last cut-off releases, the container image could be not available. + type: string + type: object + x-kubernetes-validations: + - message: replicas must be 0 (or unset) when mode is DaemonSet, and greater than 0 (or unset) when mode is Deployment + rule: '!(self.mode == ''DaemonSet'' && has(self.replicas) && self.replicas != 0) && !(self.mode == ''Deployment'' && has(self.replicas) && self.replicas == 0)' + server: + default: + image: registry.k8s.io/kas-network-proxy/proxy-server + port: 8132 + properties: + extraArgs: + description: |- + ExtraArgs allows adding additional arguments to said component. + WARNING - This option can override existing konnectivity + parameters and cause konnectivity components to misbehave in + unxpected ways. Only modify if you know what you are doing. + items: + type: string + type: array + image: + default: registry.k8s.io/kas-network-proxy/proxy-server + description: Container image used by the Konnectivity server. + type: string + port: + description: The port which Konnectivity server is listening to. + format: int32 + type: integer + resources: + description: Resources define the amount of CPU and memory to allocate to the Konnectivity server. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + version: + description: |- + Container image version of the Konnectivity server. + If left empty, Kamaji will automatically inflect the version from the deployed Tenant Control Plane. + + WARNING: for last cut-off releases, the container image could be not available. + type: string + required: + - port + type: object + type: object + kubeProxy: + description: |- + Enables the kube-proxy addon in the Tenant Cluster. + The registry and the tag are configurable, the image is hard-coded to `kube-proxy`. + properties: + imageRepository: + description: |- + ImageRepository sets the container registry to pull images from. + if not set, the default ImageRepository will be used instead. + type: string + imageTag: + description: |- + ImageTag allows to specify a tag for the image. + In case this value is set, kubeadm does not change automatically the version of the above components during upgrades. + type: string + type: object + type: object + controlPlane: + description: |- + ControlPlane defines how the Tenant Control Plane Kubernetes resources must be created in the Admin Cluster, + such as the number of Pod replicas, the Service resource, or the Ingress. + properties: + deployment: + description: Defining the options for the deployed Tenant Control Plane as Deployment resource. + properties: + additionalContainers: + description: AdditionalContainers allows adding additional containers to the Control Plane deployment. + items: + description: A single application container that you want to run within a pod. + properties: + args: + description: |- + Arguments to the entrypoint. + The container image's CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + description: |- + Entrypoint array. Not executed within a shell. + The container image's ENTRYPOINT is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + description: |- + List of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable present in a Container. + properties: + name: + description: |- + Name of the environment variable. + May consist of any printable ASCII characters except '='. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + description: |- + FileKeyRef selects a key of the env file. + Requires the EnvFiles feature gate to be enabled. + properties: + key: + description: |- + The key within the env file. An invalid key will prevent the pod from starting. + The keys defined within a source may consist of any printable ASCII characters except '='. + During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. + type: string + optional: + default: false + description: |- + Specify whether the file or its key must be defined. If the file or key + does not exist, then the env var is not published. + If optional is set to true and the specified key does not exist, + the environment variable will not be set in the Pod's containers. + + If optional is set to false and the specified key does not exist, + an error will be returned during Pod creation. + type: boolean + path: + description: |- + The path within the volume from which to select the file. + Must be relative and may not contain the '..' path or start with '..'. + type: string + volumeName: + description: The name of the volume mount containing the env file. + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + description: |- + List of sources to populate environment variables in the container. + The keys defined within a source may consist of any printable ASCII characters except '='. + When a key exists in multiple + sources, the value associated with the last source will take precedence. + 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 or Secrets + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: |- + Optional text to prepend to the name of each environment variable. + May consist of any printable ASCII characters except '='. + type: string + secretRef: + description: The Secret to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + description: |- + Container image name. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + imagePullPolicy: + description: |- + Image pull policy. + One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + type: string + lifecycle: + description: |- + Actions that the management system should take in response to container lifecycle events. + Cannot be updated. + properties: + postStart: + description: |- + PostStart is called immediately after a container is created. If the handler fails, + the container is terminated and restarted according to its restart policy. + Other management of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies a command to execute in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents a duration that the container should sleep. + properties: + seconds: + description: Seconds is the number of seconds to sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for backward compatibility. There is no validation of this field and + lifecycle hooks will fail at runtime when it is specified. + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: |- + PreStop is called immediately before a container is terminated due to an + API request or management event such as liveness/startup probe failure, + preemption, resource contention, etc. The handler is not called if the + container crashes or exits. The Pod's termination grace period countdown begins before the + PreStop hook is executed. Regardless of the outcome of the handler, the + container will eventually terminate within the Pod's termination grace + period (unless delayed by finalizers). Other management of the container blocks until the hook completes + or until the termination grace period is reached. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies a command to execute in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents a duration that the container should sleep. + properties: + seconds: + description: Seconds is the number of seconds to sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for backward compatibility. There is no validation of this field and + lifecycle hooks will fail at runtime when it is specified. + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - 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: |- + Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies a command to execute in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to a TCP port. + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + name: + description: |- + Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: |- + List of ports to expose from the container. Not specifying a port here + DOES NOT prevent that port from being exposed. Any port which is + listening on the default "0.0.0.0" address inside a container will be + accessible from the network. + Modifying this array with strategic merge patch may corrupt the data. + For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port in a single container. + properties: + containerPort: + description: |- + Number of port to expose on the pod's IP address. + This must be a valid port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external port to. + type: string + hostPort: + description: |- + Number of port to expose on the host. + If specified, this must be a valid port number, 0 < x < 65536. + If HostNetwork is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: |- + If specified, this must be an IANA_SVC_NAME and unique within the pod. Each + named port in a pod must have a unique name. Name for the port that can be + referred to by services. + type: string + protocol: + default: TCP + description: |- + Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: |- + Periodic probe of container service readiness. + Container will be removed from service endpoints if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies a command to execute in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to a TCP port. + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + resizePolicy: + description: |- + Resources resize policy for the container. + This field cannot be set on ephemeral containers. + items: + description: ContainerResizePolicy represents resource resize policy for the container. + properties: + resourceName: + description: |- + Name of the resource to which this resource resize policy applies. + Supported values: cpu, memory. + type: string + restartPolicy: + description: |- + Restart policy to apply when specified resource is resized. + If not specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: |- + Compute Resources required by this container. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + restartPolicy: + description: |- + RestartPolicy defines the restart behavior of individual containers in a pod. + This overrides the pod-level restart policy. When this field is not specified, + the restart behavior is defined by the Pod's restart policy and the container type. + Additionally, setting the RestartPolicy as "Always" for the init container will + have the following effect: + this init container will be continually restarted on + exit until all regular containers have terminated. Once all regular + containers have completed, all init containers with restartPolicy "Always" + will be shut down. This lifecycle differs from normal init containers and + is often referred to as a "sidecar" container. Although this init + container still starts in the init container sequence, it does not wait + for the container to complete before proceeding to the next init + container. Instead, the next init container starts immediately after this + init container is started, or after any startupProbe has successfully + completed. + type: string + restartPolicyRules: + description: |- + Represents a list of rules to be checked to determine if the + container should be restarted on exit. The rules are evaluated in + order. Once a rule matches a container exit condition, the remaining + rules are ignored. If no rule matches the container exit condition, + the Container-level restart policy determines the whether the container + is restarted or not. Constraints on the rules: + - At most 20 rules are allowed. + - Rules can have the same action. + - Identical rules are not forbidden in validations. + When rules are specified, container MUST set RestartPolicy explicitly + even it if matches the Pod's RestartPolicy. + items: + description: ContainerRestartRule describes how a container exit is handled. + properties: + action: + description: |- + Specifies the action taken on a container exit if the requirements + are satisfied. The only possible value is "Restart" to restart the + container. + type: string + exitCodes: + description: Represents the exit codes to check on container exits. + properties: + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. Possible values are: + - In: the requirement is satisfied if the container exit code is in the + set of specified values. + - NotIn: the requirement is satisfied if the container exit code is + not in the set of specified values. + type: string + values: + description: |- + Specifies the set of values to check for container exit codes. + At most 255 elements are allowed. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + description: |- + SecurityContext defines the security options the container should be run with. + If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + properties: + allowPrivilegeEscalation: + description: |- + AllowPrivilegeEscalation controls whether a process can gain more + privileges than its parent process. This bool directly controls if + the no_new_privs flag will be set on the container process. + AllowPrivilegeEscalation is true always when the container is: + 1) run as Privileged + 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows. + type: boolean + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by this container. If set, this profile + overrides the pod's appArmorProfile. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + capabilities: + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. + Note that this field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: |- + procMount denotes the type of proc mount to use for the containers. + The default value is Default which uses the container runtime defaults for + readonly paths and masked paths. + This requires the ProcMountType feature flag to be enabled. + Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: |- + Whether this container has a read-only root filesystem. + Default is false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by this container. If seccomp options are + provided at both the pod & container level, the container options + override the pod options. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + startupProbe: + description: |- + StartupProbe indicates that the Pod has successfully initialized. + If specified, no other probes are executed until this completes successfully. + If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. + This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, + when it might take a long time to load data or warm a cache, than during steady-state operation. + This cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies a command to execute in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to a TCP port. + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + stdin: + description: |- + Whether this container should allocate a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will always result in EOF. + Default is false. + type: boolean + stdinOnce: + description: |- + Whether the container runtime should close the stdin channel after it has been opened by + a single attach. When stdin is true the stdin stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the + first client attaches to stdin, and then remains open and accepts data until the client disconnects, + at which time stdin is closed and remains closed until the container is restarted. If this + flag is false, a container processes that reads from stdin will never receive an EOF. + Default is false + type: boolean + terminationMessagePath: + description: |- + Optional: Path at which the file to which the container's termination message + will be written is mounted into the container's filesystem. + Message written is intended to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. The total message length across + all containers will be limited to 12kb. + Defaults to /dev/termination-log. + Cannot be updated. + type: string + terminationMessagePolicy: + description: |- + Indicate how the termination message should be populated. File will use the contents of + terminationMessagePath to populate the container status message on both success and failure. + FallbackToLogsOnError will use the last chunk of container log output if the termination + message file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, whichever is smaller. + Defaults to File. + Cannot be updated. + type: string + tty: + description: |- + Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. + Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices to be used by the container. + items: + description: volumeDevice describes a mapping of a raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside of the container that the device will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim in the pod + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + description: |- + Pod volumes to mount into the container's filesystem. + Cannot be updated. + items: + description: VolumeMount describes a mounting of a Volume within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. + When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified + (which defaults to None). + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + recursiveReadOnly: + description: |- + RecursiveReadOnly specifies whether read-only mounts should be handled + recursively. + + If ReadOnly is false, this field has no meaning and must be unspecified. + + If ReadOnly is true, and this field is set to Disabled, the mount is not made + recursively read-only. If this field is set to IfPossible, the mount is made + recursively read-only, if it is supported by the container runtime. If this + field is set to Enabled, the mount is made recursively read-only if it is + supported by the container runtime, otherwise the pod will not be started and + an error will be generated to indicate the reason. + + If this field is set to IfPossible or Enabled, MountPropagation must be set to + None (or be unspecified, which defaults to None). + + If this field is not specified, it is treated as an equivalent of Disabled. + type: string + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + description: |- + Container's working directory. + If not specified, the container runtime's default will be used, which + might be configured in the container image. + Cannot be updated. + type: string + required: + - name + type: object + type: array + additionalInitContainers: + description: AdditionalInitContainers allows adding additional init containers to the Control Plane deployment. + items: + description: A single application container that you want to run within a pod. + properties: + args: + description: |- + Arguments to the entrypoint. + The container image's CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + description: |- + Entrypoint array. Not executed within a shell. + The container image's ENTRYPOINT is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + description: |- + List of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable present in a Container. + properties: + name: + description: |- + Name of the environment variable. + May consist of any printable ASCII characters except '='. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + description: |- + FileKeyRef selects a key of the env file. + Requires the EnvFiles feature gate to be enabled. + properties: + key: + description: |- + The key within the env file. An invalid key will prevent the pod from starting. + The keys defined within a source may consist of any printable ASCII characters except '='. + During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. + type: string + optional: + default: false + description: |- + Specify whether the file or its key must be defined. If the file or key + does not exist, then the env var is not published. + If optional is set to true and the specified key does not exist, + the environment variable will not be set in the Pod's containers. + + If optional is set to false and the specified key does not exist, + an error will be returned during Pod creation. + type: boolean + path: + description: |- + The path within the volume from which to select the file. + Must be relative and may not contain the '..' path or start with '..'. + type: string + volumeName: + description: The name of the volume mount containing the env file. + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + description: |- + List of sources to populate environment variables in the container. + The keys defined within a source may consist of any printable ASCII characters except '='. + When a key exists in multiple + sources, the value associated with the last source will take precedence. + 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 or Secrets + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: |- + Optional text to prepend to the name of each environment variable. + May consist of any printable ASCII characters except '='. + type: string + secretRef: + description: The Secret to select from + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + description: |- + Container image name. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + imagePullPolicy: + description: |- + Image pull policy. + One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + type: string + lifecycle: + description: |- + Actions that the management system should take in response to container lifecycle events. + Cannot be updated. + properties: + postStart: + description: |- + PostStart is called immediately after a container is created. If the handler fails, + the container is terminated and restarted according to its restart policy. + Other management of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies a command to execute in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents a duration that the container should sleep. + properties: + seconds: + description: Seconds is the number of seconds to sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for backward compatibility. There is no validation of this field and + lifecycle hooks will fail at runtime when it is specified. + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: |- + PreStop is called immediately before a container is terminated due to an + API request or management event such as liveness/startup probe failure, + preemption, resource contention, etc. The handler is not called if the + container crashes or exits. The Pod's termination grace period countdown begins before the + PreStop hook is executed. Regardless of the outcome of the handler, the + container will eventually terminate within the Pod's termination grace + period (unless delayed by finalizers). Other management of the container blocks until the hook completes + or until the termination grace period is reached. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies a command to execute in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents a duration that the container should sleep. + properties: + seconds: + description: Seconds is the number of seconds to sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for backward compatibility. There is no validation of this field and + lifecycle hooks will fail at runtime when it is specified. + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - 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: |- + Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies a command to execute in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to a TCP port. + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + name: + description: |- + Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: |- + List of ports to expose from the container. Not specifying a port here + DOES NOT prevent that port from being exposed. Any port which is + listening on the default "0.0.0.0" address inside a container will be + accessible from the network. + Modifying this array with strategic merge patch may corrupt the data. + For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port in a single container. + properties: + containerPort: + description: |- + Number of port to expose on the pod's IP address. + This must be a valid port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external port to. + type: string + hostPort: + description: |- + Number of port to expose on the host. + If specified, this must be a valid port number, 0 < x < 65536. + If HostNetwork is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: |- + If specified, this must be an IANA_SVC_NAME and unique within the pod. Each + named port in a pod must have a unique name. Name for the port that can be + referred to by services. + type: string + protocol: + default: TCP + description: |- + Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: |- + Periodic probe of container service readiness. + Container will be removed from service endpoints if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies a command to execute in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to a TCP port. + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + resizePolicy: + description: |- + Resources resize policy for the container. + This field cannot be set on ephemeral containers. + items: + description: ContainerResizePolicy represents resource resize policy for the container. + properties: + resourceName: + description: |- + Name of the resource to which this resource resize policy applies. + Supported values: cpu, memory. + type: string + restartPolicy: + description: |- + Restart policy to apply when specified resource is resized. + If not specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: |- + Compute Resources required by this container. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + restartPolicy: + description: |- + RestartPolicy defines the restart behavior of individual containers in a pod. + This overrides the pod-level restart policy. When this field is not specified, + the restart behavior is defined by the Pod's restart policy and the container type. + Additionally, setting the RestartPolicy as "Always" for the init container will + have the following effect: + this init container will be continually restarted on + exit until all regular containers have terminated. Once all regular + containers have completed, all init containers with restartPolicy "Always" + will be shut down. This lifecycle differs from normal init containers and + is often referred to as a "sidecar" container. Although this init + container still starts in the init container sequence, it does not wait + for the container to complete before proceeding to the next init + container. Instead, the next init container starts immediately after this + init container is started, or after any startupProbe has successfully + completed. + type: string + restartPolicyRules: + description: |- + Represents a list of rules to be checked to determine if the + container should be restarted on exit. The rules are evaluated in + order. Once a rule matches a container exit condition, the remaining + rules are ignored. If no rule matches the container exit condition, + the Container-level restart policy determines the whether the container + is restarted or not. Constraints on the rules: + - At most 20 rules are allowed. + - Rules can have the same action. + - Identical rules are not forbidden in validations. + When rules are specified, container MUST set RestartPolicy explicitly + even it if matches the Pod's RestartPolicy. + items: + description: ContainerRestartRule describes how a container exit is handled. + properties: + action: + description: |- + Specifies the action taken on a container exit if the requirements + are satisfied. The only possible value is "Restart" to restart the + container. + type: string + exitCodes: + description: Represents the exit codes to check on container exits. + properties: + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. Possible values are: + - In: the requirement is satisfied if the container exit code is in the + set of specified values. + - NotIn: the requirement is satisfied if the container exit code is + not in the set of specified values. + type: string + values: + description: |- + Specifies the set of values to check for container exit codes. + At most 255 elements are allowed. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + description: |- + SecurityContext defines the security options the container should be run with. + If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + properties: + allowPrivilegeEscalation: + description: |- + AllowPrivilegeEscalation controls whether a process can gain more + privileges than its parent process. This bool directly controls if + the no_new_privs flag will be set on the container process. + AllowPrivilegeEscalation is true always when the container is: + 1) run as Privileged + 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows. + type: boolean + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by this container. If set, this profile + overrides the pod's appArmorProfile. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + capabilities: + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. + Note that this field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: |- + procMount denotes the type of proc mount to use for the containers. + The default value is Default which uses the container runtime defaults for + readonly paths and masked paths. + This requires the ProcMountType feature flag to be enabled. + Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: |- + Whether this container has a read-only root filesystem. + Default is false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by this container. If seccomp options are + provided at both the pod & container level, the container options + override the pod options. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + startupProbe: + description: |- + StartupProbe indicates that the Pod has successfully initialized. + If specified, no other probes are executed until this completes successfully. + If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. + This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, + when it might take a long time to load data or warm a cache, than during steady-state operation. + This cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies a command to execute in the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to a TCP port. + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + stdin: + description: |- + Whether this container should allocate a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will always result in EOF. + Default is false. + type: boolean + stdinOnce: + description: |- + Whether the container runtime should close the stdin channel after it has been opened by + a single attach. When stdin is true the stdin stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the + first client attaches to stdin, and then remains open and accepts data until the client disconnects, + at which time stdin is closed and remains closed until the container is restarted. If this + flag is false, a container processes that reads from stdin will never receive an EOF. + Default is false + type: boolean + terminationMessagePath: + description: |- + Optional: Path at which the file to which the container's termination message + will be written is mounted into the container's filesystem. + Message written is intended to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. The total message length across + all containers will be limited to 12kb. + Defaults to /dev/termination-log. + Cannot be updated. + type: string + terminationMessagePolicy: + description: |- + Indicate how the termination message should be populated. File will use the contents of + terminationMessagePath to populate the container status message on both success and failure. + FallbackToLogsOnError will use the last chunk of container log output if the termination + message file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, whichever is smaller. + Defaults to File. + Cannot be updated. + type: string + tty: + description: |- + Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. + Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices to be used by the container. + items: + description: volumeDevice describes a mapping of a raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside of the container that the device will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim in the pod + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + description: |- + Pod volumes to mount into the container's filesystem. + Cannot be updated. + items: + description: VolumeMount describes a mounting of a Volume within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. + When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified + (which defaults to None). + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + recursiveReadOnly: + description: |- + RecursiveReadOnly specifies whether read-only mounts should be handled + recursively. + + If ReadOnly is false, this field has no meaning and must be unspecified. + + If ReadOnly is true, and this field is set to Disabled, the mount is not made + recursively read-only. If this field is set to IfPossible, the mount is made + recursively read-only, if it is supported by the container runtime. If this + field is set to Enabled, the mount is made recursively read-only if it is + supported by the container runtime, otherwise the pod will not be started and + an error will be generated to indicate the reason. + + If this field is set to IfPossible or Enabled, MountPropagation must be set to + None (or be unspecified, which defaults to None). + + If this field is not specified, it is treated as an equivalent of Disabled. + type: string + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + description: |- + Container's working directory. + If not specified, the container runtime's default will be used, which + might be configured in the container image. + Cannot be updated. + type: string + required: + - name + type: object + type: array + additionalMetadata: + description: AdditionalMetadata defines which additional metadata, such as labels and annotations, must be attached to the created resource. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + additionalVolumeMounts: + description: |- + AdditionalVolumeMounts allows to mount an additional volume into each component of the Control Plane + (kube-apiserver, controller-manager, and scheduler). + properties: + apiServer: + items: + description: VolumeMount describes a mounting of a Volume within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. + When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified + (which defaults to None). + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + recursiveReadOnly: + description: |- + RecursiveReadOnly specifies whether read-only mounts should be handled + recursively. + + If ReadOnly is false, this field has no meaning and must be unspecified. + + If ReadOnly is true, and this field is set to Disabled, the mount is not made + recursively read-only. If this field is set to IfPossible, the mount is made + recursively read-only, if it is supported by the container runtime. If this + field is set to Enabled, the mount is made recursively read-only if it is + supported by the container runtime, otherwise the pod will not be started and + an error will be generated to indicate the reason. + + If this field is set to IfPossible or Enabled, MountPropagation must be set to + None (or be unspecified, which defaults to None). + + If this field is not specified, it is treated as an equivalent of Disabled. + type: string + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + controllerManager: + items: + description: VolumeMount describes a mounting of a Volume within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. + When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified + (which defaults to None). + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + recursiveReadOnly: + description: |- + RecursiveReadOnly specifies whether read-only mounts should be handled + recursively. + + If ReadOnly is false, this field has no meaning and must be unspecified. + + If ReadOnly is true, and this field is set to Disabled, the mount is not made + recursively read-only. If this field is set to IfPossible, the mount is made + recursively read-only, if it is supported by the container runtime. If this + field is set to Enabled, the mount is made recursively read-only if it is + supported by the container runtime, otherwise the pod will not be started and + an error will be generated to indicate the reason. + + If this field is set to IfPossible or Enabled, MountPropagation must be set to + None (or be unspecified, which defaults to None). + + If this field is not specified, it is treated as an equivalent of Disabled. + type: string + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + scheduler: + items: + description: VolumeMount describes a mounting of a Volume within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. + When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified + (which defaults to None). + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + recursiveReadOnly: + description: |- + RecursiveReadOnly specifies whether read-only mounts should be handled + recursively. + + If ReadOnly is false, this field has no meaning and must be unspecified. + + If ReadOnly is true, and this field is set to Disabled, the mount is not made + recursively read-only. If this field is set to IfPossible, the mount is made + recursively read-only, if it is supported by the container runtime. If this + field is set to Enabled, the mount is made recursively read-only if it is + supported by the container runtime, otherwise the pod will not be started and + an error will be generated to indicate the reason. + + If this field is set to IfPossible or Enabled, MountPropagation must be set to + None (or be unspecified, which defaults to None). + + If this field is not specified, it is treated as an equivalent of Disabled. + type: string + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + type: object + additionalVolumes: + description: AdditionalVolumes allows to add additional volumes to the Control Plane deployment. + items: + description: Volume represents a named volume in a pod that may be accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: |- + awsElasticBlockStore represents an AWS Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + Deprecated: AWSElasticBlockStore is deprecated. All operations for the in-tree + awsElasticBlockStore type are redirected to the ebs.csi.aws.com CSI driver. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + properties: + fsType: + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + type: string + partition: + description: |- + partition is the partition in the volume that you want to mount. + If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition as "1". + Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + format: int32 + type: integer + readOnly: + description: |- + readOnly value true will force the readOnly setting in VolumeMounts. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + type: boolean + volumeID: + description: |- + volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + type: string + required: + - volumeID + type: object + azureDisk: + description: |- + azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. + Deprecated: AzureDisk is deprecated. All operations for the in-tree azureDisk type + are redirected to the disk.csi.azure.com CSI driver. + properties: + cachingMode: + description: 'cachingMode is the Host Caching mode: None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in the blob storage + type: string + fsType: + default: ext4 + description: |- + fsType is Filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared' + type: string + readOnly: + default: false + description: |- + readOnly Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: |- + azureFile represents an Azure File Service mount on the host and bind mount to the pod. + Deprecated: AzureFile is deprecated. All operations for the in-tree azureFile type + are redirected to the file.csi.azure.com CSI driver. + properties: + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret that contains Azure Storage Account Name and Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: |- + cephFS represents a Ceph FS mount on the host that shares a pod's lifetime. + Deprecated: CephFS is deprecated and the in-tree cephfs type is no longer supported. + properties: + monitors: + description: |- + monitors is Required: Monitors is a collection of Ceph monitors + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + description: 'path is Optional: Used as the mounted root, rather than the full Ceph tree, default is /' + type: string + readOnly: + description: |- + readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + type: boolean + secretFile: + description: |- + secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + type: string + secretRef: + description: |- + secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: |- + user is optional: User is the rados user name, default is admin + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + type: string + required: + - monitors + type: object + cinder: + description: |- + cinder represents a cinder volume attached and mounted on kubelets host machine. + Deprecated: Cinder is deprecated. All operations for the in-tree cinder type + are redirected to the cinder.csi.openstack.org CSI driver. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + type: string + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + type: boolean + secretRef: + description: |- + secretRef is optional: points to a secret object containing parameters used to connect + to OpenStack. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: |- + volumeID used to identify the volume in cinder. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that should populate this volume + properties: + defaultMode: + description: |- + defaultMode is optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: optional specify whether the ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers. + properties: + driver: + description: |- + driver is the name of the CSI driver that handles this volume. + Consult with your admin for the correct name as registered in the cluster. + type: string + fsType: + description: |- + fsType to mount. Ex. "ext4", "xfs", "ntfs". + If not provided, the empty value is passed to the associated CSI driver + which will determine the default filesystem to apply. + type: string + nodePublishSecretRef: + description: |- + nodePublishSecretRef is a reference to the secret object containing + sensitive information to pass to the CSI driver to complete the CSI + NodePublishVolume and NodeUnpublishVolume calls. + This field is optional, and may be empty if no secret is required. If the + secret object contains more than one secret, all secret references are passed. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: |- + readOnly specifies a read-only configuration for the volume. + Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: |- + volumeAttributes stores driver-specific properties that are passed to the CSI + driver. Consult your driver's documentation for supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API about the pod that should populate this volume + properties: + defaultMode: + description: |- + Optional: mode bits to use on created files by default. Must be a + Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: Items is a list of downward API volume file + items: + description: DownwardAPIVolumeFile represents information to create the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects a field of the pod: only annotations, labels, name, namespace and uid are supported.' + properties: + apiVersion: + description: Version of the schema the FieldPath is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: |- + Optional: mode bits used to set permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: 'Required: Path is the relative path name of the file to be created. Must not be absolute or contain the ''..'' path. Must be utf-8 encoded. The first item of the relative path must not start with ''..''' + type: string + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + description: |- + emptyDir represents a temporary directory that shares a pod's lifetime. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + properties: + medium: + description: |- + medium represents what type of storage medium should back this directory. + The default is "" which means to use the node's default medium. + Must be an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: |- + sizeLimit is the total amount of local storage required for this EmptyDir volume. + The size limit is also applicable for memory medium. + The maximum usage on memory medium EmptyDir would be the minimum value between + the SizeLimit specified here and the sum of memory limits of all containers in a pod. + The default is nil which means that the limit is undefined. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: |- + ephemeral represents a volume that is handled by a cluster storage driver. + The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, + and deleted when the pod is removed. + + Use this if: + a) the volume is only needed while the pod runs, + b) features of normal volumes like restoring from snapshot or capacity + tracking are needed, + c) the storage driver is specified through a storage class, and + d) the storage driver supports dynamic volume provisioning through + a PersistentVolumeClaim (see EphemeralVolumeSource for more + information on the connection between this volume type + and PersistentVolumeClaim). + + Use PersistentVolumeClaim or one of the vendor-specific + APIs for volumes that persist for longer than the lifecycle + of an individual pod. + + Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to + be used that way - see the documentation of the driver for + more information. + + A pod can use both types of ephemeral volumes and + persistent volumes at the same time. + properties: + volumeClaimTemplate: + description: |- + Will be used to create a stand-alone PVC to provision the volume. + The pod in which this EphemeralVolumeSource is embedded will be the + owner of the PVC, i.e. the PVC will be deleted together with the + pod. The name of the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` array + entry. Pod validation will reject the pod if the concatenated name + is not valid for a PVC (for example, too long). + + An existing PVC with that name that is not owned by the pod + will *not* be used for the pod to avoid using an unrelated + volume by mistake. Starting the pod is then blocked until + the unrelated PVC is removed. If such a pre-created PVC is + meant to be used by the pod, the PVC has to updated with an + owner reference to the pod once the pod exists. Normally + this should not be necessary, but it may be useful when + manually reconstructing a broken cluster. + + This field is read-only and no changes will be made by Kubernetes + to the PVC after it has been created. + + Required, must not be nil. + properties: + metadata: + description: |- + May contain labels and annotations that will be copied into the PVC + when creating it. No other fields are allowed and will be rejected during + validation. + type: object + spec: + description: |- + The specification for the PersistentVolumeClaim. The entire content is + copied unchanged into the PVC that gets created from this + template. The same fields as in a PersistentVolumeClaim + are also valid here. + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + Users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over volumes to consider for binding. + 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 + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference to the PersistentVolume backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + lun: + description: 'lun is Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: |- + readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target worldwide names (WWNs)' + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + description: |- + wwids Optional: FC volume world wide identifiers (wwids) + Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + description: |- + flexVolume represents a generic volume resource that is + provisioned/attached using an exec based plugin. + Deprecated: FlexVolume is deprecated. Consider using a CSIDriver instead. + properties: + driver: + description: driver is the name of the driver to use for this volume. + type: string + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field holds extra command options if any.' + type: object + readOnly: + description: |- + readOnly is Optional: defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: |- + secretRef is Optional: secretRef is reference to the secret object containing + sensitive information to pass to the plugin scripts. This may be + empty if no secret object is specified. If the secret object + contains more than one secret, all secrets are passed to the plugin + scripts. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: |- + flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running. + Deprecated: Flocker is deprecated and the in-tree flocker type is no longer supported. + properties: + datasetName: + description: |- + datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker + should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. This is unique identifier of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: |- + gcePersistentDisk represents a GCE Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + Deprecated: GCEPersistentDisk is deprecated. All operations for the in-tree + gcePersistentDisk type are redirected to the pd.csi.storage.gke.io CSI driver. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + properties: + fsType: + description: |- + fsType is filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + type: string + partition: + description: |- + partition is the partition in the volume that you want to mount. + If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition as "1". + Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + format: int32 + type: integer + pdName: + description: |- + pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + type: string + readOnly: + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + type: boolean + required: + - pdName + type: object + gitRepo: + description: |- + gitRepo represents a git repository at a particular revision. + Deprecated: GitRepo is deprecated. To provision a container with a git repo, mount an + EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir + into the Pod's container. + properties: + directory: + description: |- + directory is the target directory name. + Must not contain or start with '..'. If '.' is supplied, the volume directory will be the + git repository. Otherwise, if specified, the volume will contain the git repository in + the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: |- + glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. + Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported. + properties: + endpoints: + description: endpoints is the endpoint name that details Glusterfs topology. + type: string + path: + description: |- + path is the Glusterfs volume path. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + type: string + readOnly: + description: |- + readOnly here will force the Glusterfs volume to be mounted with read-only permissions. + Defaults to false. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: |- + hostPath represents a pre-existing file or directory on the host + machine that is directly exposed to the container. This is generally + used for system agents or other privileged things that are allowed + to see the host machine. Most containers will NOT need this. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + properties: + path: + description: |- + path of the directory on the host. + If the path is a symlink, it will follow the link to the real path. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + type: string + type: + description: |- + type for HostPath Volume + Defaults to "" + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + type: string + required: + - path + type: object + image: + description: |- + image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. + The volume is resolved at pod startup depending on which PullPolicy value is provided: + + - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + + The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. + A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. + 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) before 1.33. + The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. + properties: + pullPolicy: + description: |- + Policy for pulling OCI objects. Possible values are: + Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + type: string + reference: + description: |- + Required: Image or artifact reference to be used. + Behaves in the same way as pod.spec.containers[*].image. + Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + type: object + iscsi: + description: |- + iscsi represents an ISCSI Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support iSCSI Session CHAP authentication + type: boolean + fsType: + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + type: string + initiatorName: + description: |- + initiatorName is the custom iSCSI Initiator Name. + If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface + : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified Name. + type: string + iscsiInterface: + default: default + description: |- + iscsiInterface is the interface Name that uses an iSCSI transport. + Defaults to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: |- + portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and 3260). + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for iSCSI target and initiator authentication + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: |- + targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: |- + name of the volume. + Must be a DNS_LABEL and unique within the pod. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + nfs: + description: |- + nfs represents an NFS mount on the host that shares a pod's lifetime + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + properties: + path: + description: |- + path that is exported by the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + type: string + readOnly: + description: |- + readOnly here will force the NFS export to be mounted with read-only permissions. + Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + type: boolean + server: + description: |- + server is the hostname or IP address of the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: |- + persistentVolumeClaimVolumeSource represents a reference to a + PersistentVolumeClaim in the same namespace. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + properties: + claimName: + description: |- + claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + type: string + readOnly: + description: |- + readOnly Will force the ReadOnly setting in VolumeMounts. + Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: |- + photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine. + Deprecated: PhotonPersistentDisk is deprecated and the in-tree photonPersistentDisk type is no longer supported. + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: |- + portworxVolume represents a portworx volume attached and mounted on kubelets host machine. + Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type + are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate + is on. + properties: + fsType: + description: |- + fSType represents the filesystem type to mount + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources secrets, configmaps, and downward API + properties: + defaultMode: + description: |- + defaultMode are the mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + sources: + description: |- + sources is the list of volume projections. Each entry in this list + handles one source. + items: + description: |- + Projection that may be projected along with other supported volume types. + Exactly one of these fields must be set. + properties: + clusterTrustBundle: + description: |- + ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field + of ClusterTrustBundle objects in an auto-updating file. + + Alpha, gated by the ClusterTrustBundleProjection feature gate. + + ClusterTrustBundle objects can either be selected by name, or by the + combination of signer name and a label selector. + + Kubelet performs aggressive normalization of the PEM contents written + into the pod filesystem. Esoteric PEM features such as inter-block + comments and block headers are stripped. Certificates are deduplicated. + The ordering of certificates within the file is arbitrary, and Kubelet + may change the order over time. + properties: + labelSelector: + description: |- + Select all ClusterTrustBundles that match this label selector. Only has + effect if signerName is set. Mutually-exclusive with name. If unset, + interpreted as "match nothing". If set but empty, interpreted as "match + everything". + 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 + name: + description: |- + Select a single ClusterTrustBundle by object name. Mutually-exclusive + with signerName and labelSelector. + type: string + optional: + description: |- + If true, don't block pod startup if the referenced ClusterTrustBundle(s) + aren't available. If using name, then the named ClusterTrustBundle is + allowed not to exist. If using signerName, then the combination of + signerName and labelSelector is allowed to match zero + ClusterTrustBundles. + type: boolean + path: + description: Relative path from the volume root to write the bundle. + type: string + signerName: + description: |- + Select all ClusterTrustBundles that match this signer name. + Mutually-exclusive with name. The contents of all selected + ClusterTrustBundles will be unified and deduplicated. + type: string + required: + - path + type: object + configMap: + description: configMap information about the configMap data to project + properties: + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: optional specify whether the ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about the downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume file + items: + description: DownwardAPIVolumeFile represents information to create the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects a field of the pod: only annotations, labels, name, namespace and uid are supported.' + properties: + apiVersion: + description: Version of the schema the FieldPath is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: |- + Optional: mode bits used to set permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: 'Required: Path is the relative path name of the file to be created. Must not be absolute or contain the ''..'' path. Must be utf-8 encoded. The first item of the relative path must not start with ''..''' + type: string + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + description: |- + Projects an auto-rotating credential bundle (private key and certificate + chain) that the pod can use either as a TLS client or server. + + Kubelet generates a private key and uses it to send a + PodCertificateRequest to the named signer. Once the signer approves the + request and issues a certificate chain, Kubelet writes the key and + certificate chain to the pod filesystem. The pod does not start until + certificates have been issued for each podCertificate projected volume + source in its spec. + + Kubelet will begin trying to rotate the certificate at the time indicated + by the signer using the PodCertificateRequest.Status.BeginRefreshAt + timestamp. + + Kubelet can write a single file, indicated by the credentialBundlePath + field, or separate files, indicated by the keyPath and + certificateChainPath fields. + + The credential bundle is a single file in PEM format. The first PEM + entry is the private key (in PKCS#8 format), and the remaining PEM + entries are the certificate chain issued by the signer (typically, + signers will return their certificate chain in leaf-to-root order). + + Prefer using the credential bundle format, since your application code + can read it atomically. If you use keyPath and certificateChainPath, + your application must make two separate file reads. If these coincide + with a certificate rotation, it is possible that the private key and leaf + certificate you read may not correspond to each other. Your application + will need to check for this condition, and re-read until they are + consistent. + + The named signer controls chooses the format of the certificate it + issues; consult the signer implementation's documentation to learn how to + use the certificates it issues. + properties: + certificateChainPath: + description: |- + Write the certificate chain at this path in the projected volume. + + Most applications should use credentialBundlePath. When using keyPath + and certificateChainPath, your application needs to check that the key + and leaf certificate are consistent, because it is possible to read the + files mid-rotation. + type: string + credentialBundlePath: + description: |- + Write the credential bundle at this path in the projected volume. + + The credential bundle is a single file that contains multiple PEM blocks. + The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private + key. + + The remaining blocks are CERTIFICATE blocks, containing the issued + certificate chain from the signer (leaf and any intermediates). + + Using credentialBundlePath lets your Pod's application code make a single + atomic read that retrieves a consistent key and certificate chain. If you + project them to separate files, your application code will need to + additionally check that the leaf certificate was issued to the key. + type: string + keyPath: + description: |- + Write the key at this path in the projected volume. + + Most applications should use credentialBundlePath. When using keyPath + and certificateChainPath, your application needs to check that the key + and leaf certificate are consistent, because it is possible to read the + files mid-rotation. + type: string + keyType: + description: |- + The type of keypair Kubelet will generate for the pod. + + Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384", + "ECDSAP521", and "ED25519". + type: string + maxExpirationSeconds: + description: |- + maxExpirationSeconds is the maximum lifetime permitted for the + certificate. + + Kubelet copies this value verbatim into the PodCertificateRequests it + generates for this projection. + + If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver + will reject values shorter than 3600 (1 hour). The maximum allowable + value is 7862400 (91 days). + + The signer implementation is then free to issue a certificate with any + lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600 + seconds (1 hour). This constraint is enforced by kube-apiserver. + `kubernetes.io` signers will never issue certificates with a lifetime + longer than 24 hours. + format: int32 + type: integer + signerName: + description: Kubelet's generated CSRs will be addressed to this signer. + type: string + userAnnotations: + additionalProperties: + type: string + description: |- + userAnnotations allow pod authors to pass additional information to + the signer implementation. Kubernetes does not restrict or validate this + metadata in any way. + + These values are copied verbatim into the `spec.unverifiedUserAnnotations` field of + the PodCertificateRequest objects that Kubelet creates. + + Entries are subject to the same validation as object metadata annotations, + with the addition that all keys must be domain-prefixed. No restrictions + are placed on values, except an overall size limitation on the entire field. + + Signers should document the keys and values they support. Signers should + deny requests that contain keys they do not recognize. + type: object + required: + - keyType + - signerName + type: object + secret: + description: secret information about the secret data to project + properties: + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: optional field specify whether the Secret or its key must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information about the serviceAccountToken data to project + properties: + audience: + description: |- + audience is the intended audience of the token. A recipient of a token + must identify itself with an identifier specified in the audience of the + token, and otherwise should reject the token. The audience defaults to the + identifier of the apiserver. + type: string + expirationSeconds: + description: |- + expirationSeconds is the requested duration of validity of the service + account token. As the token approaches expiration, the kubelet volume + plugin will proactively rotate the service account token. The kubelet will + start trying to rotate the token if the token is older than 80 percent of + its time to live or if the token is older than 24 hours.Defaults to 1 hour + and must be at least 10 minutes. + format: int64 + type: integer + path: + description: |- + path is the path relative to the mount point of the file to project the + token into. + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + description: |- + quobyte represents a Quobyte mount on the host that shares a pod's lifetime. + Deprecated: Quobyte is deprecated and the in-tree quobyte type is no longer supported. + properties: + group: + description: |- + group to map volume access to + Default is no group + type: string + readOnly: + description: |- + readOnly here will force the Quobyte volume to be mounted with read-only permissions. + Defaults to false. + type: boolean + registry: + description: |- + registry represents a single or multiple Quobyte Registry services + specified as a string as host:port pair (multiple entries are separated with commas) + which acts as the central registry for volumes + type: string + tenant: + description: |- + tenant owning the given Quobyte volume in the Backend + Used with dynamically provisioned Quobyte volumes, value is set by the plugin + type: string + user: + description: |- + user to map volume access to + Defaults to serivceaccount user + type: string + volume: + description: volume is a string that references an already created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: |- + rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. + Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported. + properties: + fsType: + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + type: string + image: + description: |- + image is the rados image name. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + keyring: + default: /etc/ceph/keyring + description: |- + keyring is the path to key ring for RBDUser. + Default is /etc/ceph/keyring. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + monitors: + description: |- + monitors is a collection of Ceph monitors. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + description: |- + pool is the rados pool name. + Default is rbd. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + readOnly: + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: boolean + secretRef: + description: |- + secretRef is name of the authentication secret for RBDUser. If provided + overrides keyring. + Default is nil. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + description: |- + user is the rados user name. + Default is admin. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + required: + - image + - monitors + type: object + scaleIO: + description: |- + scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. + Deprecated: ScaleIO is deprecated and the in-tree scaleIO type is no longer supported. + properties: + fsType: + default: xfs + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". + Default is "xfs". + type: string + gateway: + description: gateway is the host address of the ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the ScaleIO Protection Domain for the configured storage. + type: string + readOnly: + description: |- + readOnly Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: |- + secretRef references to the secret for ScaleIO user and other + sensitive information. If this is not provided, Login operation will fail. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable SSL communication with Gateway, default false + type: boolean + storageMode: + default: ThinProvisioned + description: |- + storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. + Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage Pool associated with the protection domain. + type: string + system: + description: system is the name of the storage system as configured in ScaleIO. + type: string + volumeName: + description: |- + volumeName is the name of a volume already created in the ScaleIO system + that is associated with this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: |- + secret represents a secret that should populate this volume. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + properties: + defaultMode: + description: |- + defaultMode is Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values + for mode bits. Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: |- + items If unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + description: optional field specify whether the Secret or its keys must be defined + type: boolean + secretName: + description: |- + secretName is the name of the secret in the pod's namespace to use. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + type: string + type: object + storageos: + description: |- + storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes. + Deprecated: StorageOS is deprecated and the in-tree storageos type is no longer supported. + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: |- + secretRef specifies the secret to use for obtaining the StorageOS API + credentials. If not specified, default values will be attempted. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: |- + volumeName is the human-readable name of the StorageOS volume. Volume + names are only unique within a namespace. + type: string + volumeNamespace: + description: |- + volumeNamespace specifies the scope of the volume within StorageOS. If no + namespace is specified then the Pod's namespace will be used. This allows the + Kubernetes name scoping to be mirrored within StorageOS for tighter integration. + Set VolumeName to any name to override the default behaviour. + Set to "default" if you are not using namespaces within StorageOS. + Namespaces that do not pre-exist within StorageOS will be created. + type: string + type: object + vsphereVolume: + description: |- + vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine. + Deprecated: VsphereVolume is deprecated. All operations for the in-tree vsphereVolume type + are redirected to the csi.vsphere.vmware.com CSI driver. + properties: + fsType: + description: |- + fsType is filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage Policy Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + affinity: + description: |- + If specified, the Tenant Control Plane pod's scheduling constraints. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/ + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + extraArgs: + description: |- + ExtraArgs allows adding additional arguments to the Control Plane components, + such as kube-apiserver, controller-manager, and scheduler. WARNING - This option + can override existing parameters and cause components to misbehave in unxpected ways. + Only modify if you know what you are doing. + properties: + apiServer: + items: + type: string + type: array + controllerManager: + items: + type: string + type: array + kine: + description: Available only if Kamaji is running using Kine as backing storage. + items: + type: string + type: array + scheduler: + items: + type: string + type: array + type: object + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector is a selector which must be true for the pod to fit on a node. + Selector which must match a node's labels for the pod to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + podAdditionalMetadata: + description: AdditionalMetadata defines which additional metadata, such as labels and annotations, must be attached to the created resource. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + probes: + description: |- + Probes defines the probe configuration for the Control Plane components + (kube-apiserver, controller-manager, and scheduler). + Override TimeoutSeconds, PeriodSeconds, and FailureThreshold for resource-constrained environments. + properties: + apiServer: + description: APIServer defines probe overrides for kube-apiserver, taking precedence over global probe settings. + properties: + liveness: + description: Liveness defines parameters for the liveness probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + readiness: + description: Readiness defines parameters for the readiness probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + startup: + description: Startup defines parameters for the startup probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + type: object + controllerManager: + description: ControllerManager defines probe overrides for kube-controller-manager, taking precedence over global probe settings. + properties: + liveness: + description: Liveness defines parameters for the liveness probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + readiness: + description: Readiness defines parameters for the readiness probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + startup: + description: Startup defines parameters for the startup probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + type: object + liveness: + description: Liveness defines default parameters for liveness probes of all Control Plane components. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + readiness: + description: Readiness defines default parameters for the readiness probe of kube-apiserver. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + scheduler: + description: Scheduler defines probe overrides for kube-scheduler, taking precedence over global probe settings. + properties: + liveness: + description: Liveness defines parameters for the liveness probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + readiness: + description: Readiness defines parameters for the readiness probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + startup: + description: Startup defines parameters for the startup probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + type: object + startup: + description: Startup defines default parameters for startup probes of all Control Plane components. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + type: object + registrySettings: + default: + apiServerImage: kube-apiserver + controllerManagerImage: kube-controller-manager + registry: registry.k8s.io + schedulerImage: kube-scheduler + description: |- + RegistrySettings allows to override the default images for the given Tenant Control Plane instance. + It could be used to point to a different container registry rather than the public one. + properties: + apiServerImage: + default: kube-apiserver + type: string + controllerManagerImage: + default: kube-controller-manager + type: string + registry: + default: registry.k8s.io + type: string + schedulerImage: + default: kube-scheduler + type: string + tagSuffix: + description: |- + The tag to append to all the Control Plane container images. + Optional. + type: string + type: object + replicas: + default: 2 + format: int32 + type: integer + resources: + description: |- + Resources defines the amount of memory and CPU to allocate to each component of the Control Plane + (kube-apiserver, controller-manager, and scheduler). + properties: + apiServer: + description: ResourceRequirements describes the compute resource requirements. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + controllerManager: + description: ResourceRequirements describes the compute resource requirements. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + kine: + description: |- + Define the kine container resources. + Available only if Kamaji is running using Kine as backing storage. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + scheduler: + description: ResourceRequirements describes the compute resource requirements. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This field depends on the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + type: object + runtimeClassName: + description: |- + RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used + to run the Tenant Control Plane pod. If no RuntimeClass resource matches the named class, the pod will not be run. + If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an + empty definition that uses the default runtime handler. + More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class + type: string + serviceAccountName: + default: default + description: ServiceAccountName allows to specify the service account to be mounted to the pods of the Control plane deployment + type: string + strategy: + default: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 0 + type: RollingUpdate + description: |- + Strategy describes how to replace existing pods with new ones for the given Tenant Control Plane. + Default value is set to Rolling Update, with a blue/green strategy. + properties: + rollingUpdate: + description: |- + Rolling update config params. Present only if DeploymentStrategyType = + RollingUpdate. + properties: + maxSurge: + anyOf: + - type: integer + - type: string + description: |- + The maximum number of pods that can be scheduled above the desired number of + pods. + Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + This can not be 0 if MaxUnavailable is 0. + Absolute number is calculated from percentage by rounding up. + Defaults to 25%. + Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when + the rolling update starts, such that the total number of old and new pods do not exceed + 130% of desired pods. Once old pods have been killed, + new ReplicaSet can be scaled up further, ensuring that total number of pods running + at any time during the update is at most 130% of desired pods. + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + description: |- + The maximum number of pods that can be unavailable during the update. + Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + Absolute number is calculated from percentage by rounding down. + This can not be 0 if MaxSurge is 0. + Defaults to 25%. + Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods + immediately when the rolling update starts. Once new pods are ready, old ReplicaSet + can be scaled down further, followed by scaling up the new ReplicaSet, ensuring + that the total number of pods available at all times during the update is at + least 70% of desired pods. + x-kubernetes-int-or-string: true + type: object + type: + description: Type of deployment. Can be "Recreate" or "RollingUpdate". Default is RollingUpdate. + type: string + type: object + tolerations: + description: |- + If specified, the Tenant Control Plane pod's tolerations. + More info: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + topologySpreadConstraints: + description: |- + TopologySpreadConstraints describes how the Tenant Control Plane pods ought to spread across topology + domains. Scheduler will schedule pods in a way which abides by the constraints. + In case of nil underlying LabelSelector, the Kamaji one for the given Tenant Control Plane will be used. + All topologySpreadConstraints are ANDed. + items: + description: TopologySpreadConstraint specifies how to spread matching pods among the given topology. + properties: + labelSelector: + description: |- + LabelSelector is used to find matching pods. + Pods that match this label selector are counted to determine the number of pods + in their corresponding topology domain. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select the pods over which + spreading will be calculated. The keys are used to lookup values from the + incoming pod labels, those key-value labels are ANDed with labelSelector + to select the group of existing pods over which spreading will be calculated + for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + MatchLabelKeys cannot be set when LabelSelector isn't set. + Keys that don't exist in the incoming pod labels will + be ignored. A null or empty list means only match against labelSelector. + + This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + description: |- + MaxSkew describes the degree to which pods may be unevenly distributed. + When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference + between the number of matching pods in the target topology and the global minimum. + The global minimum is the minimum number of matching pods in an eligible domain + or zero if the number of eligible domains is less than MinDomains. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 2/2/1: + In this case, the global minimum is 1. + | zone1 | zone2 | zone3 | + | P P | P P | P | + - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; + scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) + violate MaxSkew(1). + - if MaxSkew is 2, incoming pod can be scheduled onto any zone. + When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence + to topologies that satisfy it. + It's a required field. Default value is 1 and 0 is not allowed. + format: int32 + type: integer + minDomains: + description: |- + MinDomains indicates a minimum number of eligible domains. + When the number of eligible domains with matching topology keys is less than minDomains, + Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. + And when the number of eligible domains with matching topology keys equals or greater than minDomains, + this value has no effect on scheduling. + As a result, when the number of eligible domains is less than minDomains, + scheduler won't schedule more than maxSkew Pods to those domains. + If value is nil, the constraint behaves as if MinDomains is equal to 1. + Valid values are integers greater than 0. + When value is not nil, WhenUnsatisfiable must be DoNotSchedule. + + For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same + labelSelector spread as 2/2/2: + | zone1 | zone2 | zone3 | + | P P | P P | P P | + The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. + In this situation, new pod with the same labelSelector cannot be scheduled, + because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, + it will violate MaxSkew. + format: int32 + type: integer + nodeAffinityPolicy: + description: |- + NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector + when calculating pod topology spread skew. Options are: + - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. + - 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. + type: string + nodeTaintsPolicy: + description: |- + NodeTaintsPolicy indicates how we will treat node taints when calculating + pod topology spread skew. Options are: + - Honor: nodes without taints, along with tainted nodes for which the incoming pod + has a toleration, are included. + - Ignore: node taints are ignored. All nodes are included. + + If this value is nil, the behavior is equivalent to the Ignore policy. + type: string + topologyKey: + description: |- + TopologyKey is the key of node labels. Nodes that have a label with this key + and identical values are considered to be in the same topology. + We consider each as a "bucket", and try to put balanced number + of pods into each bucket. + We define a domain as a particular instance of a topology. + Also, we define an eligible domain as a domain whose nodes meet the requirements of + nodeAffinityPolicy and nodeTaintsPolicy. + e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. + And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. + It's a required field. + type: string + whenUnsatisfiable: + description: |- + WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy + the spread constraint. + - DoNotSchedule (default) tells the scheduler not to schedule it. + - ScheduleAnyway tells the scheduler to schedule the pod in any location, + but giving higher precedence to topologies that would help reduce the + skew. + A constraint is considered "Unsatisfiable" for an incoming pod + if and only if every possible node assignment for that pod would violate + "MaxSkew" on some topology. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 3/1/1: + | zone1 | zone2 | zone3 | + | P P P | P | P | + If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled + to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies + MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler + won't make it *more* imbalanced. + It's a required field. + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + type: object + gateway: + description: Defining the options for an Optional Gateway which will expose API Server of the Tenant Control Plane + properties: + additionalMetadata: + description: AdditionalMetadata to add Labels and Annotations support. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + hostname: + description: Hostname is an optional field which will be used as a route hostname. + 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 + parentRefs: + description: GatewayParentRefs is the class of the Gateway resource to use. + 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 + type: array + type: object + ingress: + description: Defining the options for an Optional Ingress which will expose API Server of the Tenant Control Plane + properties: + additionalMetadata: + description: AdditionalMetadata defines which additional metadata, such as labels and annotations, must be attached to the created resource. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + hostname: + description: |- + Hostname is an optional field which will be used as Ingress's Host. If it is not defined, + Ingress's host will be "..", where domain is specified under NetworkProfileSpec + type: string + ingressClassName: + type: string + type: object + service: + description: Defining the options for the Tenant Control Plane Service resource. + properties: + additionalMetadata: + description: AdditionalMetadata defines which additional metadata, such as labels and annotations, must be attached to the created resource. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + additionalPorts: + description: |- + AdditionalPorts allows adding additional ports to the Service generated Kamaji + which targets the Tenant Control Plane pods. + items: + properties: + appProtocol: + description: |- + The application protocol for this port. + This is used as a hint for implementations to offer richer behavior for protocols that they understand. + This field follows standard Kubernetes label syntax. + Valid values are either: + + * Un-prefixed protocol names - reserved for IANA standard service names (as per + RFC-6335 and https://www.iana.org/assignments/service-names). + type: string + name: + description: |- + The name of this port within the Service created by Kamaji. + This must be a DNS_LABEL, must have unique names, and cannot be `kube-apiserver`, or `konnectivity-server`. + type: string + port: + description: The port that will be exposed by this service. + format: int32 + type: integer + protocol: + default: TCP + description: The IP protocol for this port. Supports "TCP", "UDP", and "SCTP". + enum: + - TCP + - UDP + - SCTP + type: string + targetPort: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the pods of the Tenant Control Plane. + Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + If this is a string, it will be looked up as a named port in the + target Pod's container ports. If this is not specified, the value + of the 'port' field is used (an identity map). + x-kubernetes-int-or-string: true + required: + - name + - port + - targetPort + type: object + type: array + serviceType: + description: ServiceType allows specifying how to expose the Tenant Control Plane. + enum: + - ClusterIP + - NodePort + - LoadBalancer + type: string + required: + - serviceType + type: object + required: + - service + type: object + x-kubernetes-validations: + - message: using both ingress and gateway is not supported + rule: '!(has(self.ingress) && has(self.gateway))' + dataStore: + description: |- + DataStore specifies the DataStore that should be used to store the Kubernetes data for the given Tenant Control Plane. + When Kamaji runs with the default DataStore flag, all empty values will inherit the default value. + By leaving it empty and running Kamaji with no default DataStore flag, it is possible to achieve automatic assignment to a specific DataStore object. + + Migration from one DataStore to another backed by the same Driver is possible. See: https://kamaji.clastix.io/guides/datastore-migration/ + Migration from one DataStore to another backed by a different Driver is not supported. + type: string + dataStoreOverrides: + description: DataStoreOverride defines which kubernetes resources will be stored in dedicated datastores. + items: + description: DataStoreOverride defines which kubernetes resource will be stored in a dedicated datastore. + properties: + dataStore: + description: DataStore specifies the DataStore that should be used to store the Kubernetes data for the given Resource. + type: string + resource: + description: Resource specifies which kubernetes resource to target. + type: string + type: object + type: array + dataStoreSchema: + description: |- + DataStoreSchema allows to specify the name of the database (for relational DataStores) or the key prefix (for etcd). This + value is optional and immutable. Note that Kamaji currently doesn't ensure that DataStoreSchema values are unique. It's up + to the user to avoid clashes between different TenantControlPlanes. If not set upon creation, Kamaji will default the + DataStoreSchema by concatenating the namespace and name of the TenantControlPlane. + type: string + x-kubernetes-validations: + - message: changing the dataStoreSchema is not supported + rule: self == oldSelf + dataStoreUsername: + description: |- + DataStoreUsername allows to specify the username of the database (for relational DataStores). This + value is optional and immutable. Note that Kamaji currently doesn't ensure that DataStoreUsername values are unique. It's up + to the user to avoid clashes between different TenantControlPlanes. If not set upon creation, Kamaji will default the + DataStoreUsername by concatenating the namespace and name of the TenantControlPlane. + type: string + x-kubernetes-validations: + - message: changing the dataStoreUsername is not supported + rule: self == oldSelf + kubernetes: + description: Kubernetes specification for tenant control plane + properties: + admissionControllers: + default: + - CertificateApproval + - CertificateSigning + - CertificateSubjectRestriction + - DefaultIngressClass + - DefaultStorageClass + - DefaultTolerationSeconds + - LimitRanger + - MutatingAdmissionWebhook + - NamespaceLifecycle + - PersistentVolumeClaimResize + - Priority + - ResourceQuota + - RuntimeClass + - ServiceAccount + - StorageObjectInUseProtection + - TaintNodesByCondition + - ValidatingAdmissionWebhook + description: |- + List of enabled Admission Controllers for the Tenant cluster. + Full reference available here: https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers + items: + enum: + - AlwaysAdmit + - AlwaysDeny + - AlwaysPullImages + - CertificateApproval + - CertificateSigning + - CertificateSubjectRestriction + - DefaultIngressClass + - DefaultStorageClass + - DefaultTolerationSeconds + - DenyEscalatingExec + - DenyExecOnPrivileged + - DenyServiceExternalIPs + - EventRateLimit + - ExtendedResourceToleration + - ImagePolicyWebhook + - LimitPodHardAntiAffinityTopology + - LimitRanger + - MutatingAdmissionWebhook + - NamespaceAutoProvision + - NamespaceExists + - NamespaceLifecycle + - NodeRestriction + - OwnerReferencesPermissionEnforcement + - PersistentVolumeClaimResize + - PersistentVolumeLabel + - PodNodeSelector + - PodSecurity + - PodSecurityPolicy + - PodTolerationRestriction + - Priority + - ResourceQuota + - RuntimeClass + - SecurityContextDeny + - ServiceAccount + - StorageObjectInUseProtection + - TaintNodesByCondition + - ValidatingAdmissionWebhook + type: string + type: array + kubelet: + properties: + cgroupfs: + description: |- + CGroupFS defines the cgroup driver for Kubelet + https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/configure-cgroup-driver/ + + Deprecated: use ConfigurationJSONPatches. + enum: + - systemd + - cgroupfs + type: string + configurationJSONPatches: + description: |- + ConfigurationJSONPatches contains the RFC 6902 JSON patches to customise the kubeadm generate configuration, + useful to customise and mangling the configuration according to your needs; + e.g.: configuring the cgroup driver used by Kubelet is possible via the following patch: + + [{"op": "replace", "path": "/cgroupDriver", "value": "systemd"}] + items: + properties: + from: + description: From specifies the source location for move or copy operations. + type: string + op: + description: Op is the RFC 6902 JSON Patch operation. + enum: + - add + - remove + - replace + - move + - copy + - test + type: string + path: + description: Path specifies the target location in the JSON document. Use "/" to separate keys; "-" for appending to arrays. + type: string + value: + description: Value is the operation value to be used when Op is add, replace, test. + x-kubernetes-preserve-unknown-fields: true + required: + - op + - path + type: object + type: array + preferredAddressTypes: + default: + - InternalIP + - ExternalIP + - Hostname + description: |- + Ordered list of the preferred NodeAddressTypes to use for kubelet connections. + Default to InternalIP, ExternalIP, Hostname. + items: + enum: + - Hostname + - InternalIP + - ExternalIP + - InternalDNS + - ExternalDNS + type: string + minItems: 1 + type: array + x-kubernetes-list-type: set + type: object + version: + description: Kubernetes Version for the tenant control plane + type: string + required: + - kubelet + - version + type: object + networkProfile: + description: NetworkProfile specifies how the network is + properties: + address: + description: |- + Address where API server will be exposed. + In the case of LoadBalancer Service, this can be empty in order to use the exposed IP provided by the cloud controller manager. + type: string + allowAddressAsExternalIP: + description: |- + AllowAddressAsExternalIP will include tenantControlPlane.Spec.NetworkProfile.Address in the section of + ExternalIPs of the Kubernetes Service (only ClusterIP or NodePort) + type: boolean + certSANs: + description: |- + CertSANs sets extra Subject Alternative Names (SANs) for the API Server signing certificate. + Use this field to add additional hostnames when exposing the Tenant Control Plane with third solutions. + items: + type: string + type: array + clusterDomain: + default: cluster.local + description: The default domain name used for DNS resolution within the cluster. + pattern: .*\..* + type: string + x-kubernetes-validations: + - message: changing the cluster domain is not supported + rule: self == oldSelf + dnsServiceIPs: + description: |- + The DNS Service for internal resolution, it must match the Service CIDR. + In case of an empty value, it is automatically computed according to the Service CIDR, e.g.: + Service CIDR 10.96.0.0/16, the resulting DNS Service IP will be 10.96.0.10 for IPv4, + for IPv6 from the CIDR 2001:db8:abcd::/64 the resulting DNS Service IP will be 2001:db8:abcd::10. + items: + type: string + maxItems: 8 + type: array + loadBalancerClass: + description: |- + Specify the LoadBalancer class in case of multiple load balancer implementations. + Field supported only for Tenant Control Plane instances exposed using a LoadBalancer Service. + minLength: 1 + type: string + x-kubernetes-validations: + - message: LoadBalancerClass is immutable + rule: self == oldSelf + loadBalancerSourceRanges: + description: |- + LoadBalancerSourceRanges restricts the IP ranges that can access + the LoadBalancer type Service. This field defines a list of IP + address ranges (in CIDR format) that are allowed to access the service. + If left empty, the service will allow traffic from all IP ranges (0.0.0.0/0). + This feature is useful for restricting access to API servers or services + to specific networks for security purposes. + Example: {"192.168.1.0/24", "10.0.0.0/8"} + items: + type: string + maxItems: 16 + type: array + x-kubernetes-validations: + - message: all LoadBalancer source range entries must be valid CIDR + rule: self.all(r, isCIDR(r)) + podCidr: + default: 10.244.0.0/16 + description: 'CIDR for Kubernetes Pods: if empty, defaulted to 10.244.0.0/16.' + type: string + x-kubernetes-validations: + - message: podCidr must be empty or a valid CIDR + rule: self == '' || isCIDR(self) + port: + default: 6443 + description: Port where API server will be exposed + format: int32 + type: integer + serviceCidr: + default: 10.96.0.0/16 + description: 'CIDR for Kubernetes Services: if empty, defaulted to 10.96.0.0/16.' + type: string + x-kubernetes-validations: + - message: serviceCidr must be empty or a valid CIDR + rule: self == '' || isCIDR(self) + type: object + x-kubernetes-validations: + - message: all DNS service IPs must be part of the Service CIDR + rule: '!has(self.dnsServiceIPs) || self.dnsServiceIPs.all(r, cidr(self.serviceCidr).containsIP(r))' + writePermissions: + description: |- + WritePermissions allows to select which operations (create, delete, update) must be blocked: + by default, all actions are allowed, and API Server can write to its Datastore. + + By blocking all actions, the Tenant Control Plane can enter in a Read Only mode: + this phase can be used to prevent Datastore quota exhaustion or for your own business logic + (e.g.: blocking creation and update, but allowing deletion to "clean up" space). + properties: + blockCreation: + type: boolean + blockDeletion: + type: boolean + blockUpdate: + type: boolean + type: object + required: + - controlPlane + - kubernetes + type: object + x-kubernetes-validations: + - message: unsetting the dataStore is not supported + rule: '!has(oldSelf.dataStore) || has(self.dataStore)' + - message: unsetting the dataStoreSchema is not supported + rule: '!has(oldSelf.dataStoreSchema) || has(self.dataStoreSchema)' + - message: unsetting the dataStoreUsername is not supported + rule: '!has(oldSelf.dataStoreUsername) || has(self.dataStoreUsername)' + - message: LoadBalancer source ranges are supported only with LoadBalancer service type + rule: '!has(self.networkProfile.loadBalancerSourceRanges) || (size(self.networkProfile.loadBalancerSourceRanges) == 0 || self.controlPlane.service.serviceType == ''LoadBalancer'')' + - message: LoadBalancerClass is supported only with LoadBalancer service type + rule: '!has(self.networkProfile.loadBalancerClass) || self.controlPlane.service.serviceType == ''LoadBalancer''' + - message: LoadBalancerClass cannot be set or unset at runtime + rule: self.controlPlane.service.serviceType != 'LoadBalancer' || (oldSelf.controlPlane.service.serviceType != 'LoadBalancer' && self.controlPlane.service.serviceType == 'LoadBalancer') || has(self.networkProfile.loadBalancerClass) == has(oldSelf.networkProfile.loadBalancerClass) + status: + description: TenantControlPlaneStatus defines the observed state of TenantControlPlane. + properties: + addons: + description: Addons contains the status of the different Addons + properties: + coreDNS: + description: AddonStatus defines the observed state of an Addon. + properties: + enabled: + type: boolean + lastUpdate: + format: date-time + type: string + required: + - enabled + type: object + konnectivity: + description: KonnectivityStatus defines the status of Konnectivity as Addon. + properties: + agent: + properties: + lastUpdate: + description: Last time when k8s object was updated + format: date-time + type: string + mode: + type: string + name: + type: string + namespace: + type: string + type: object + certificate: + description: CertificatePrivateKeyPairStatus defines the status. + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + secretName: + type: string + type: object + clusterrolebinding: + properties: + lastUpdate: + description: Last time when k8s object was updated + format: date-time + type: string + name: + type: string + namespace: + type: string + type: object + configMap: + properties: + checksum: + type: string + name: + type: string + type: object + enabled: + type: boolean + gateway: + description: KubernetesGatewayStatus defines the status for the Tenant Control Plane Gateway in the management cluster. + properties: + accessPoints: + description: A list of valid access points that the route exposes. + items: + properties: + port: + format: int32 + type: integer + type: + description: |- + AddressType defines how a network address is represented as a text string. + This may take two possible forms: + + * A predefined CamelCase string identifier (currently limited to `IPAddress` or `Hostname`) + * A domain-prefixed string identifier (like `acme.io/CustomAddressType`) + + Values `IPAddress` and `Hostname` have Extended support. + + The `NamedAddress` value has been deprecated in favor of implementation + specific domain-prefixed strings. + + All other values, including domain-prefixed values have Implementation-specific support, + which are used in implementation-specific behaviors. Support for additional + predefined CamelCase identifiers may be added in future releases. + 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 + urls: + items: + type: string + type: array + value: + type: string + required: + - port + - type + - value + type: object + type: array + 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. + + + Notes for implementors: + + While parents is not a listType `map`, this is due to the fact that the + list key is not scalar, and Kubernetes is unable to represent this. + + Parent status MUST be considered to be namespaced by the combination of + the parentRef and controllerName fields, and implementations should keep + the following rules in mind when updating this status: + + * Implementations MUST update only entries that have a matching value of + `controllerName` for that implementation. + * Implementations MUST NOT update entries with non-matching `controllerName` + fields. + * Implementations MUST treat each `parentRef`` in the Route separately and + update its status based on the relationship with that parent. + * Implementations MUST perform a read-modify-write cycle on this field + before modifying it. That is, when modifying this field, implementations + must be confident they have fetched the most recent version of this field, + and ensure that changes they make are on that recent version. + + + 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 nonexistent 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. + + + + Notes for implementors: + + Conditions are a listType `map`, which means that they function like a + map with a key of the `type` field _in the k8s apiserver_. + + This means that implementations must obey some rules when updating this + section. + + * Implementations MUST perform a read-modify-write cycle on this field + before modifying it. That is, when modifying this field, implementations + must be confident they have fetched the most recent version of this field, + and ensure that changes they make are on that recent version. + * Implementations MUST NOT remove or reorder Conditions that they are not + directly responsible for. For example, if an implementation sees a Condition + with type `special.io/SomeField`, it MUST NOT remove, change or update that + Condition. + * Implementations MUST always _merge_ changes into Conditions of the same Type, + rather than creating more than one Condition of the same Type. + * Implementations MUST always update the `observedGeneration` field of the + Condition to the `metadata.generation` of the Gateway at the time of update creation. + * If the `observedGeneration` of a Condition is _greater than_ the value the + implementation knows about, then it MUST NOT perform the update on that Condition, + but must wait for a future reconciliation and status update. (The assumption is that + the implementation's copy of the object is stale and an update will be re-triggered + if relevant.) + + + 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: + - conditions + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + x-kubernetes-list-type: atomic + routeRef: + description: Reference to the route created for this tenant. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + required: + - parents + type: object + kubeconfig: + description: KubeconfigStatus contains information about the generated kubeconfig. + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + secretName: + type: string + type: object + sa: + properties: + lastUpdate: + description: Last time when k8s object was updated + format: date-time + type: string + name: + type: string + namespace: + type: string + type: object + service: + description: KubernetesServiceStatus defines the status for the Tenant Control Plane Service in the management cluster. + properties: + conditions: + description: Current service state + 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 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + loadBalancer: + description: |- + LoadBalancer contains the current status of the load-balancer, + if one is present. + properties: + ingress: + description: |- + Ingress is a list containing ingress points for the load-balancer. + Traffic intended for the service should be sent to these ingress points. + items: + description: |- + LoadBalancerIngress represents the status of a load-balancer ingress point: + traffic intended for the service should be sent to an ingress point. + properties: + hostname: + description: |- + Hostname is set for load-balancer ingress points that are DNS based + (typically AWS load-balancers) + type: string + ip: + description: |- + IP is set for load-balancer ingress points that are IP based + (typically GCE or OpenStack load-balancers) + type: string + ipMode: + description: |- + IPMode specifies how the load-balancer IP behaves, and may only be specified when the ip field is specified. + Setting this to "VIP" indicates that traffic is delivered to the node with + the destination set to the load-balancer's IP and port. + Setting this to "Proxy" indicates that traffic is delivered to the node or pod with + the destination set to the node's IP and node port or the pod's IP and port. + Service implementations may use this information to adjust traffic routing. + type: string + ports: + description: |- + Ports is a list of records of service ports + If used, every port defined in the service should have an entry in it + items: + description: PortStatus represents the error condition of a service port + properties: + error: + description: |- + Error is to record the problem with the service port + The format of the error shall comply with the following rules: + - built-in error values shall be specified in this file and those shall use + CamelCase names + - cloud provider specific error values must have names that comply with the + format 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 + port: + description: Port is the port number of the service port of which status is recorded here + format: int32 + type: integer + protocol: + description: |- + Protocol is the protocol of the service port of which status is recorded here + The supported values are: "TCP", "UDP", "SCTP" + type: string + required: + - error + - port + - protocol + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + type: object + name: + description: The name of the Service for the given cluster. + type: string + namespace: + description: The namespace which the Service for the given cluster is deployed. + type: string + port: + description: The port where the service is running + format: int32 + type: integer + required: + - name + - namespace + - port + type: object + required: + - enabled + type: object + kubeProxy: + description: AddonStatus defines the observed state of an Addon. + properties: + enabled: + type: boolean + lastUpdate: + format: date-time + type: string + required: + - enabled + type: object + type: object + certificates: + description: |- + Certificates contains information about the different certificates + that are necessary to run a kubernetes control plane + properties: + apiServer: + description: CertificatePrivateKeyPairStatus defines the status. + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + secretName: + type: string + type: object + apiServerKubeletClient: + description: CertificatePrivateKeyPairStatus defines the status. + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + secretName: + type: string + type: object + ca: + description: CertificatePrivateKeyPairStatus defines the status. + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + secretName: + type: string + type: object + etcd: + description: ETCDCertificatesStatus defines the observed state of ETCD Certificate for API server. + properties: + apiServer: + description: APIServerCertificatesStatus defines the observed state of ETCD Certificate for API server. + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + secretName: + type: string + type: object + ca: + description: ETCDCertificateStatus defines the observed state of ETCD Certificate for API server. + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + secretName: + type: string + type: object + type: object + frontProxyCA: + description: CertificatePrivateKeyPairStatus defines the status. + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + secretName: + type: string + type: object + frontProxyClient: + description: CertificatePrivateKeyPairStatus defines the status. + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + secretName: + type: string + type: object + sa: + description: PublicKeyPrivateKeyPairStatus defines the status. + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + secretName: + type: string + type: object + type: object + controlPlaneEndpoint: + description: ControlPlaneEndpoint contains the status of the kubernetes control plane + type: string + kubeadmPhase: + description: KubeadmPhase contains the status of the kubeadm phases action + properties: + bootstrapToken: + description: KubeadmPhaseStatus contains the status of a kubeadm phase action. + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + type: object + required: + - bootstrapToken + type: object + kubeadmconfig: + description: KubeadmConfig contains the status of the configuration required by kubeadm + properties: + checksum: + description: Checksum of the kubeadm configuration to detect changes + type: string + configmapName: + type: string + lastUpdate: + format: date-time + type: string + type: object + kubeconfig: + description: KubeConfig contains information about the kubenconfigs that control plane pieces need + properties: + admin: + description: KubeconfigStatus contains information about the generated kubeconfig. + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + secretName: + type: string + type: object + controllerManager: + description: KubeconfigStatus contains information about the generated kubeconfig. + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + secretName: + type: string + type: object + scheduler: + description: KubeconfigStatus contains information about the generated kubeconfig. + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + secretName: + type: string + type: object + type: object + kubernetesResources: + description: Kubernetes contains information about the reconciliation of the required Kubernetes resources deployed in the admin cluster + properties: + deployment: + description: KubernetesDeploymentStatus defines the status for the Tenant Control Plane Deployment in the management cluster. + properties: + availableReplicas: + description: Total number of available non-terminating pods (ready for at least minReadySeconds) targeted by this deployment. + format: int32 + type: integer + collisionCount: + description: |- + Count of hash collisions for the Deployment. The Deployment controller uses this + field as a collision avoidance mechanism when it needs to create the name for the + newest ReplicaSet. + format: int32 + type: integer + conditions: + description: Represents the latest available observations of a deployment's current state. + items: + description: DeploymentCondition describes the state of a deployment at a certain point. + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + format: date-time + type: string + lastUpdateTime: + description: The last time this condition was updated. + format: date-time + type: string + message: + description: A human readable message indicating details about the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of deployment condition. + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + lastUpdate: + description: Last time when deployment was updated + format: date-time + type: string + name: + description: The name of the Deployment for the given cluster. + type: string + namespace: + description: The namespace which the Deployment for the given cluster is deployed. + type: string + observedGeneration: + description: The generation observed by the deployment controller. + format: int64 + type: integer + readyReplicas: + 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-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 a beta field and requires enabling DeploymentReplicaSetTerminatingReplicas feature (enabled by default). + format: int32 + type: integer + unavailableReplicas: + description: |- + Total number of unavailable pods targeted by this deployment. This is the total number of + pods that are still required for the deployment to have 100% available capacity. They may + either be pods that are running but not yet available or pods that still have not been created. + format: int32 + type: integer + updatedReplicas: + description: Total number of non-terminating pods targeted by this deployment that have the desired template spec. + format: int32 + type: integer + required: + - name + - namespace + - selector + type: object + gateway: + description: KubernetesGatewayStatus defines the status for the Tenant Control Plane Gateway in the management cluster. + properties: + accessPoints: + description: A list of valid access points that the route exposes. + items: + properties: + port: + format: int32 + type: integer + type: + description: |- + AddressType defines how a network address is represented as a text string. + This may take two possible forms: + + * A predefined CamelCase string identifier (currently limited to `IPAddress` or `Hostname`) + * A domain-prefixed string identifier (like `acme.io/CustomAddressType`) + + Values `IPAddress` and `Hostname` have Extended support. + + The `NamedAddress` value has been deprecated in favor of implementation + specific domain-prefixed strings. + + All other values, including domain-prefixed values have Implementation-specific support, + which are used in implementation-specific behaviors. Support for additional + predefined CamelCase identifiers may be added in future releases. + 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 + urls: + items: + type: string + type: array + value: + type: string + required: + - port + - type + - value + type: object + type: array + 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. + + + Notes for implementors: + + While parents is not a listType `map`, this is due to the fact that the + list key is not scalar, and Kubernetes is unable to represent this. + + Parent status MUST be considered to be namespaced by the combination of + the parentRef and controllerName fields, and implementations should keep + the following rules in mind when updating this status: + + * Implementations MUST update only entries that have a matching value of + `controllerName` for that implementation. + * Implementations MUST NOT update entries with non-matching `controllerName` + fields. + * Implementations MUST treat each `parentRef`` in the Route separately and + update its status based on the relationship with that parent. + * Implementations MUST perform a read-modify-write cycle on this field + before modifying it. That is, when modifying this field, implementations + must be confident they have fetched the most recent version of this field, + and ensure that changes they make are on that recent version. + + + 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 nonexistent 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. + + + + Notes for implementors: + + Conditions are a listType `map`, which means that they function like a + map with a key of the `type` field _in the k8s apiserver_. + + This means that implementations must obey some rules when updating this + section. + + * Implementations MUST perform a read-modify-write cycle on this field + before modifying it. That is, when modifying this field, implementations + must be confident they have fetched the most recent version of this field, + and ensure that changes they make are on that recent version. + * Implementations MUST NOT remove or reorder Conditions that they are not + directly responsible for. For example, if an implementation sees a Condition + with type `special.io/SomeField`, it MUST NOT remove, change or update that + Condition. + * Implementations MUST always _merge_ changes into Conditions of the same Type, + rather than creating more than one Condition of the same Type. + * Implementations MUST always update the `observedGeneration` field of the + Condition to the `metadata.generation` of the Gateway at the time of update creation. + * If the `observedGeneration` of a Condition is _greater than_ the value the + implementation knows about, then it MUST NOT perform the update on that Condition, + but must wait for a future reconciliation and status update. (The assumption is that + the implementation's copy of the object is stale and an update will be re-triggered + if relevant.) + + + 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: + - conditions + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + x-kubernetes-list-type: atomic + routeRef: + description: Reference to the route created for this tenant. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + required: + - parents + type: object + ingress: + description: KubernetesIngressStatus defines the status for the Tenant Control Plane Ingress in the management cluster. + properties: + loadBalancer: + description: loadBalancer contains the current status of the load-balancer. + properties: + ingress: + description: ingress is a list containing ingress points for the load-balancer. + items: + description: IngressLoadBalancerIngress represents the status of a load-balancer ingress point. + properties: + hostname: + description: hostname is set for load-balancer ingress points that are DNS based. + type: string + ip: + description: ip is set for load-balancer ingress points that are IP based. + type: string + ports: + description: ports provides information about the ports exposed by this LoadBalancer. + items: + description: IngressPortStatus represents the error condition of a service port + properties: + error: + description: |- + error is to record the problem with the service port + The format of the error shall comply with the following rules: + - built-in error values shall be specified in this file and those shall use + CamelCase names + - cloud provider specific error values must have names that comply with the + format 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 + port: + description: port is the port number of the ingress port. + format: int32 + type: integer + protocol: + description: |- + protocol is the protocol of the ingress port. + The supported values are: "TCP", "UDP", "SCTP" + type: string + required: + - error + - port + - protocol + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + type: object + name: + description: The name of the Ingress for the given cluster. + type: string + namespace: + description: The namespace which the Ingress for the given cluster is deployed. + type: string + required: + - name + - namespace + type: object + service: + description: KubernetesServiceStatus defines the status for the Tenant Control Plane Service in the management cluster. + properties: + conditions: + description: Current service state + 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 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + loadBalancer: + description: |- + LoadBalancer contains the current status of the load-balancer, + if one is present. + properties: + ingress: + description: |- + Ingress is a list containing ingress points for the load-balancer. + Traffic intended for the service should be sent to these ingress points. + items: + description: |- + LoadBalancerIngress represents the status of a load-balancer ingress point: + traffic intended for the service should be sent to an ingress point. + properties: + hostname: + description: |- + Hostname is set for load-balancer ingress points that are DNS based + (typically AWS load-balancers) + type: string + ip: + description: |- + IP is set for load-balancer ingress points that are IP based + (typically GCE or OpenStack load-balancers) + type: string + ipMode: + description: |- + IPMode specifies how the load-balancer IP behaves, and may only be specified when the ip field is specified. + Setting this to "VIP" indicates that traffic is delivered to the node with + the destination set to the load-balancer's IP and port. + Setting this to "Proxy" indicates that traffic is delivered to the node or pod with + the destination set to the node's IP and node port or the pod's IP and port. + Service implementations may use this information to adjust traffic routing. + type: string + ports: + description: |- + Ports is a list of records of service ports + If used, every port defined in the service should have an entry in it + items: + description: PortStatus represents the error condition of a service port + properties: + error: + description: |- + Error is to record the problem with the service port + The format of the error shall comply with the following rules: + - built-in error values shall be specified in this file and those shall use + CamelCase names + - cloud provider specific error values must have names that comply with the + format 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 + port: + description: Port is the port number of the service port of which status is recorded here + format: int32 + type: integer + protocol: + description: |- + Protocol is the protocol of the service port of which status is recorded here + The supported values are: "TCP", "UDP", "SCTP" + type: string + required: + - error + - port + - protocol + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + type: object + name: + description: The name of the Service for the given cluster. + type: string + namespace: + description: The namespace which the Service for the given cluster is deployed. + type: string + port: + description: The port where the service is running + format: int32 + type: integer + required: + - name + - namespace + - port + type: object + version: + description: KubernetesVersion contains the information regarding the running Kubernetes version, and its upgrade status. + properties: + status: + default: Provisioning + description: Status returns the current status of the Kubernetes version, such as its provisioning state, or completed upgrade. + enum: + - Unknown + - Provisioning + - CertificateAuthorityRotating + - Upgrading + - Migrating + - Ready + - NotReady + - Sleeping + - WriteLimited + type: string + version: + description: Version is the running Kubernetes version of the Tenant Control Plane. + type: string + type: object + type: object + observedGeneration: + description: ObservedGeneration represents the .metadata.generation that was last reconciled. + format: int64 + type: integer + storage: + description: Storage Status contains information about Kubernetes storage system + properties: + certificate: + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + secretName: + type: string + type: object + config: + properties: + checksum: + type: string + secretName: + type: string + type: object + dataStoreName: + type: string + driver: + type: string + setup: + properties: + checksum: + type: string + lastUpdate: + format: date-time + type: string + schema: + type: string + user: + type: string + type: object + type: object + type: object + type: object + served: true + storage: true + subresources: + scale: + labelSelectorPath: .status.kubernetesResources.deployment.selector + specReplicasPath: .spec.controlPlane.deployment.replicas + statusReplicasPath: .status.kubernetesResources.deployment.replicas + status: {} +conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: '{{ .Values.kamajiService }}' + namespace: '{{ .Values.kamajiNamespace }}' + path: /convert + conversionReviewVersions: + - v1 diff --git a/packages/system/kamaji/charts/kamaji-crds/templates/_helpers.tpl b/packages/system/kamaji/charts/kamaji-crds/templates/_helpers.tpl new file mode 100644 index 00000000..3fe45b08 --- /dev/null +++ b/packages/system/kamaji/charts/kamaji-crds/templates/_helpers.tpl @@ -0,0 +1,49 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "kamaji-crds.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "kamaji.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "kamaji-crds.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create the cert-manager annotation to inject Certificate CA. +*/}} +{{- define "kamaji-crds.certManagerAnnotation" -}} +{{- printf "%s/%s" (required "A valid .Values.kamajiNamespace is required" .Values.kamajiNamespace) (required "A valid .Values.kamajiCertificateName is required" .Values.kamajiCertificateName) }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "kamaji-crds.labels" -}} +helm.sh/chart: {{ include "kamaji-crds.chart" . }} +app.kubernetes.io/name: {{ include "kamaji-crds.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/component: "crds" +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} diff --git a/packages/system/kamaji/charts/kamaji-crds/templates/kamaji.clastix.io_datastores.yaml b/packages/system/kamaji/charts/kamaji-crds/templates/kamaji.clastix.io_datastores.yaml new file mode 100644 index 00000000..3ae0647c --- /dev/null +++ b/packages/system/kamaji/charts/kamaji-crds/templates/kamaji.clastix.io_datastores.yaml @@ -0,0 +1,10 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: {{ include "kamaji-crds.certManagerAnnotation" . }} + labels: + {{- include "kamaji-crds.labels" . | nindent 4 }} + name: datastores.kamaji.clastix.io +spec: + {{ tpl (.Files.Get "hack/kamaji.clastix.io_datastores_spec.yaml") . | nindent 2}} diff --git a/packages/system/kamaji/charts/kamaji-crds/templates/kamaji.clastix.io_kubeconfiggenerators.yaml b/packages/system/kamaji/charts/kamaji-crds/templates/kamaji.clastix.io_kubeconfiggenerators.yaml new file mode 100644 index 00000000..dd9b96f6 --- /dev/null +++ b/packages/system/kamaji/charts/kamaji-crds/templates/kamaji.clastix.io_kubeconfiggenerators.yaml @@ -0,0 +1,10 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: {{ include "kamaji-crds.certManagerAnnotation" . }} + labels: + {{- include "kamaji-crds.labels" . | nindent 4 }} + name: kubeconfiggenerators.kamaji.clastix.io +spec: + {{ tpl (.Files.Get "hack/kamaji.clastix.io_kubeconfiggenerators_spec.yaml") . | nindent 2 }} diff --git a/packages/system/kamaji/charts/kamaji-crds/templates/kamaji.clastix.io_tenantcontrolplanes.yaml b/packages/system/kamaji/charts/kamaji-crds/templates/kamaji.clastix.io_tenantcontrolplanes.yaml new file mode 100644 index 00000000..8d3081c0 --- /dev/null +++ b/packages/system/kamaji/charts/kamaji-crds/templates/kamaji.clastix.io_tenantcontrolplanes.yaml @@ -0,0 +1,10 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: {{ include "kamaji-crds.certManagerAnnotation" . }} + labels: + {{- include "kamaji-crds.labels" . | nindent 4 }} + name: tenantcontrolplanes.kamaji.clastix.io +spec: + {{ tpl (.Files.Get "hack/kamaji.clastix.io_tenantcontrolplanes_spec.yaml") . | nindent 2 }} diff --git a/packages/system/kamaji/charts/kamaji-crds/values.yaml b/packages/system/kamaji/charts/kamaji-crds/values.yaml new file mode 100644 index 00000000..074b586f --- /dev/null +++ b/packages/system/kamaji/charts/kamaji-crds/values.yaml @@ -0,0 +1,15 @@ +# Default values for kamaji-crds. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# -- Overrides the name of the chart for resource naming purposes. +nameOverride: "" +# -- Overrides the full name of the resources created by the chart. +fullnameOverride: "" + +# -- The namespace where Kamaji has been installed: required to inject the Certificate Authority for cert-manager. +kamajiNamespace: kamaji-system +# -- The Kamaji webhook Service name. +kamajiService: kamaji-webhook-service +# -- The cert-manager Certificate resource name, holding the Certificate Authority for webhooks. +kamajiCertificateName: kamaji-serving-cert diff --git a/packages/system/kamaji/charts/kamaji/.helmignore b/packages/system/kamaji/charts/kamaji/.helmignore index 0e8a0eb3..a03977f5 100644 --- a/packages/system/kamaji/charts/kamaji/.helmignore +++ b/packages/system/kamaji/charts/kamaji/.helmignore @@ -21,3 +21,8 @@ .idea/ *.tmproj .vscode/ +# Helm source files +README.md.gotmpl +.helmignore +# Build tools +Makefile diff --git a/packages/system/kamaji/charts/kamaji/Chart.lock b/packages/system/kamaji/charts/kamaji/Chart.lock index 14655f12..f22bdc05 100644 --- a/packages/system/kamaji/charts/kamaji/Chart.lock +++ b/packages/system/kamaji/charts/kamaji/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: kamaji-etcd repository: https://clastix.github.io/charts - version: 0.9.2 -digest: sha256:ba76d3a30e5e20dbbbbcc36a0e7465d4b1adacc956061e7f6ea47b99fc8f08a6 -generated: "2025-03-14T21:23:30.421915+09:00" + version: 0.11.0 +digest: sha256:96b4115b8c02f771f809ec1bed3be3a3903e7e8315d6966aa54b0f73230ea421 +generated: "2025-07-03T09:19:19.835421461+02:00" diff --git a/packages/system/kamaji/charts/kamaji/Chart.yaml b/packages/system/kamaji/charts/kamaji/Chart.yaml index c09bfd52..a7ec5faf 100644 --- a/packages/system/kamaji/charts/kamaji/Chart.yaml +++ b/packages/system/kamaji/charts/kamaji/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v2 -appVersion: v0.0.0 +appVersion: latest description: Kamaji is the Hosted Control Plane Manager for Kubernetes. home: https://github.com/clastix/kamaji icon: https://github.com/clastix/kamaji/raw/master/assets/logo-colored.png @@ -17,11 +17,11 @@ name: kamaji sources: - https://github.com/clastix/kamaji type: application -version: 0.0.0 +version: 0.0.0+latest dependencies: - name: kamaji-etcd repository: https://clastix.github.io/charts - version: ">=0.9.2" + version: ">=0.11.0" condition: kamaji-etcd.deploy annotations: catalog.cattle.io/certified: partner @@ -46,4 +46,5 @@ annotations: artifacthub.io/operator: "true" artifacthub.io/operatorCapabilities: "full lifecycle" artifacthub.io/changes: | - - Using dependency chart `kamaji-etcd` as a default DataStore. + - kind: added + description: Releasing latest chart at every push diff --git a/packages/system/kamaji/charts/kamaji/README.md b/packages/system/kamaji/charts/kamaji/README.md index 780c0c48..69a9cefd 100644 --- a/packages/system/kamaji/charts/kamaji/README.md +++ b/packages/system/kamaji/charts/kamaji/README.md @@ -1,6 +1,6 @@ # kamaji -![Version: 0.0.0](https://img.shields.io/badge/Version-0.0.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.0.0](https://img.shields.io/badge/AppVersion-v0.0.0-informational?style=flat-square) +![Version: 0.0.0+latest](https://img.shields.io/badge/Version-0.0.0+latest-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: latest](https://img.shields.io/badge/AppVersion-latest-informational?style=flat-square) Kamaji is the Hosted Control Plane Manager for Kubernetes. @@ -22,7 +22,7 @@ Kubernetes: `>=1.21.0-0` | Repository | Name | Version | |------------|------|---------| -| https://clastix.github.io/charts | kamaji-etcd | >=0.9.2 | +| https://clastix.github.io/charts | kamaji-etcd | >=0.11.0 | [Kamaji](https://github.com/clastix/kamaji) requires a [multi-tenant `etcd`](https://github.com/clastix/kamaji-internal/blob/master/deploy/getting-started-with-kamaji.md#setup-internal-multi-tenant-etcd) cluster. This Helm Chart starting from v0.1.1 provides the installation of an internal `etcd` in order to streamline the local test. If you'd like to use an externally managed etcd instance, you can specify the overrides and by setting the value `etcd.deploy=false`. @@ -82,10 +82,25 @@ Here the values you can override: | image.repository | string | `"clastix/kamaji"` | The container image of the Kamaji controller. | | image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | | imagePullSecrets | list | `[]` | | -| kamaji-etcd.datastore.enabled | bool | `true` | | -| kamaji-etcd.datastore.name | string | `"default"` | | -| kamaji-etcd.deploy | bool | `true` | | -| kamaji-etcd.fullnameOverride | string | `"kamaji-etcd"` | | +| kamaji-etcd | object | `{"clusterDomain":"cluster.local","datastore":{"enabled":true,"name":"default"},"deploy":true,"fullnameOverride":"kamaji-etcd"}` | Subchart: See https://github.com/clastix/kamaji-etcd/blob/master/charts/kamaji-etcd/values.yaml | +| kubeconfigGenerator.affinity | object | `{}` | Kubernetes affinity rules to apply to Kubeconfig Generator controller pods | +| kubeconfigGenerator.enableLeaderElect | bool | `true` | Enables the leader election. | +| kubeconfigGenerator.enabled | bool | `false` | Toggle to deploy the Kubeconfig Generator Deployment. | +| kubeconfigGenerator.extraArgs | list | `[]` | A list of extra arguments to add to the Kubeconfig Generator controller default ones. | +| kubeconfigGenerator.fullnameOverride | string | `""` | | +| kubeconfigGenerator.healthProbeBindAddress | string | `":8081"` | The address the probe endpoint binds to. | +| kubeconfigGenerator.loggingDevel.enable | bool | `false` | Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error) | +| kubeconfigGenerator.nodeSelector | object | `{}` | Kubernetes node selector rules to schedule Kubeconfig Generator controller | +| kubeconfigGenerator.podAnnotations | object | `{}` | The annotations to apply to the Kubeconfig Generator controller pods. | +| kubeconfigGenerator.podSecurityContext | object | `{"runAsNonRoot":true}` | The securityContext to apply to the Kubeconfig Generator controller pods. | +| kubeconfigGenerator.replicaCount | int | `2` | The number of the pod replicas for the Kubeconfig Generator controller. | +| kubeconfigGenerator.resources.limits.cpu | string | `"200m"` | | +| kubeconfigGenerator.resources.limits.memory | string | `"512Mi"` | | +| kubeconfigGenerator.resources.requests.cpu | string | `"200m"` | | +| kubeconfigGenerator.resources.requests.memory | string | `"512Mi"` | | +| kubeconfigGenerator.securityContext | object | `{"allowPrivilegeEscalation":false}` | The securityContext to apply to the Kubeconfig Generator controller container only. | +| kubeconfigGenerator.serviceAccountOverride | string | `""` | The name of the service account to use. If not set, the root Kamaji one will be used. | +| kubeconfigGenerator.tolerations | list | `[]` | Kubernetes node taints that the Kubeconfig Generator controller pods would tolerate | | livenessProbe | object | `{"httpGet":{"path":"/healthz","port":"healthcheck"},"initialDelaySeconds":15,"periodSeconds":20}` | The livenessProbe for the controller container | | loggingDevel.enable | bool | `false` | Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error) (default false) | | metricsBindAddress | string | `":8080"` | The address the metric endpoint binds to. (default ":8080") | diff --git a/packages/system/kamaji/charts/kamaji/app-readme.md b/packages/system/kamaji/charts/kamaji/app-readme.md deleted file mode 100644 index a87e8b7b..00000000 --- a/packages/system/kamaji/charts/kamaji/app-readme.md +++ /dev/null @@ -1,12 +0,0 @@ -# Kamaji - -Kamaji deploys and operates Kubernetes at scale with a fraction of the operational burden. - -Useful links: -- [Kamaji Github repository](https://github.com/clastix/kamaji) -- [Kamaji Documentation](https://kamaji.clastix.io) - -## Requirements - -* Kubernetes v1.22+ -* Helm v3 \ No newline at end of file diff --git a/packages/system/kamaji/charts/kamaji/controller-gen/clusterrole.yaml b/packages/system/kamaji/charts/kamaji/controller-gen/clusterrole.yaml index 93530197..2c2922ab 100644 --- a/packages/system/kamaji/charts/kamaji/controller-gen/clusterrole.yaml +++ b/packages/system/kamaji/charts/kamaji/controller-gen/clusterrole.yaml @@ -1,3 +1,25 @@ +- apiGroups: + - "" + resources: + - configmaps + - secrets + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - watch - apiGroups: - apps resources: @@ -21,11 +43,19 @@ - list - watch - apiGroups: - - "" + - gateway.networking.k8s.io resources: - - configmaps - - secrets - - services + - gateways + verbs: + - get + - list + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - grpcroutes + - httproutes + - tlsroutes verbs: - create - delete @@ -51,6 +81,7 @@ - kamaji.clastix.io resources: - datastores/status + - kubeconfiggenerators/status - tenantcontrolplanes/status verbs: - get @@ -59,6 +90,18 @@ - apiGroups: - kamaji.clastix.io resources: + - kubeconfiggenerators + verbs: + - create + - get + - list + - patch + - update + - watch +- apiGroups: + - kamaji.clastix.io + resources: + - kubeconfiggenerators/finalizers - tenantcontrolplanes/finalizers verbs: - update diff --git a/packages/system/kamaji/charts/kamaji/controller-gen/validating-webhook.yaml b/packages/system/kamaji/charts/kamaji/controller-gen/validating-webhook.yaml index 7042df0b..b7eb1690 100644 --- a/packages/system/kamaji/charts/kamaji/controller-gen/validating-webhook.yaml +++ b/packages/system/kamaji/charts/kamaji/controller-gen/validating-webhook.yaml @@ -19,46 +19,6 @@ resources: - tenantcontrolplanes sideEffects: None -- admissionReviewVersions: - - v1 - clientConfig: - service: - name: '{{ include "kamaji.webhookServiceName" . }}' - namespace: '{{ .Release.Namespace }}' - path: /validate-kamaji-clastix-io-v1alpha1-datastore - failurePolicy: Fail - name: vdatastore.kb.io - rules: - - apiGroups: - - kamaji.clastix.io - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - - DELETE - resources: - - datastores - sideEffects: None -- admissionReviewVersions: - - v1 - clientConfig: - service: - name: '{{ include "kamaji.webhookServiceName" . }}' - namespace: '{{ .Release.Namespace }}' - path: /validate--v1-secret - failurePolicy: Ignore - name: vdatastoresecrets.kb.io - rules: - - apiGroups: - - "" - apiVersions: - - v1 - operations: - - DELETE - resources: - - secrets - sideEffects: None - admissionReviewVersions: - v1 clientConfig: 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 aeb221e2..903f7c69 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 @@ -4,7 +4,7 @@ kind: CustomResourceDefinition metadata: annotations: cert-manager.io/inject-ca-from: kamaji-system/kamaji-serving-cert - controller-gen.kubebuilder.io/version: v0.16.1 + controller-gen.kubebuilder.io/version: v0.20.0 name: datastores.kamaji.clastix.io spec: group: kamaji.clastix.io @@ -20,6 +20,10 @@ spec: jsonPath: .spec.driver name: Driver type: string + - description: DataStore validated and ready for use + jsonPath: .status.ready + name: Ready + type: boolean - description: Age jsonPath: .metadata.creationTimestamp name: Age @@ -281,14 +285,83 @@ spec: 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' + - message: driver is immutable and cannot be changed after creation + rule: oldSelf == null || self.driver == oldSelf.driver status: description: DataStoreStatus defines the observed state of DataStore. properties: + conditions: + description: Conditions contains the validation conditions for the given Datastore. + 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 + type: array + observedGeneration: + description: ObservedGeneration represents the .metadata.generation that was last reconciled. + format: int64 + type: integer + ready: + description: |- + Ready returns if the DataStore is accepted and ready to get used: + Kamaji will ensure certificates are available, or correctly referenced. + type: boolean usedBy: description: List of the Tenant Control Planes, namespaced named, using this data store. items: type: string type: array + required: + - ready type: object type: object served: true diff --git a/packages/system/kamaji/charts/kamaji/crds/kamaji.clastix.io_kubeconfiggenerators.yaml b/packages/system/kamaji/charts/kamaji/crds/kamaji.clastix.io_kubeconfiggenerators.yaml new file mode 100644 index 00000000..af838f1d --- /dev/null +++ b/packages/system/kamaji/charts/kamaji/crds/kamaji.clastix.io_kubeconfiggenerators.yaml @@ -0,0 +1,226 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: kamaji-system/kamaji-serving-cert + controller-gen.kubebuilder.io/version: v0.20.0 + name: kubeconfiggenerators.kamaji.clastix.io +spec: + group: kamaji.clastix.io + names: + categories: + - kamaji + kind: KubeconfigGenerator + listKind: KubeconfigGeneratorList + plural: kubeconfiggenerators + shortNames: + - kc + singular: kubeconfiggenerator + scope: Cluster + versions: + - additionalPrinterColumns: + - description: Age + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: KubeconfigGenerator is the Schema for the kubeconfiggenerators API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + controlPlaneEndpointFrom: + default: admin.svc + description: |- + ControlPlaneEndpointFrom is the key used to extract the Tenant Control Plane endpoint that must be used by the generator. + The targeted Secret is the `${TCP}-admin-kubeconfig` one, default to `admin.svc`. + type: string + groups: + description: |- + Groups is resolved a set of strings used to assign the x509 organisations field. + It will be recognised by Kubernetes as user groups. + items: + description: |- + CompoundValue allows defining a static, or a dynamic value. + Options are mutually exclusive, just one should be picked up. + properties: + fromDefinition: + description: |- + FromDefinition is used to generate a dynamic value, + it uses the dot notation to access fields from the referenced TenantControlPlane object: + e.g.: metadata.name + type: string + stringValue: + description: StringValue is a static string value. + type: string + type: object + x-kubernetes-validations: + - message: Either stringValue or fromDefinition must be set, but not both. + rule: (has(self.stringValue) || has(self.fromDefinition)) && !(has(self.stringValue) && has(self.fromDefinition)) + type: array + namespaceSelector: + description: NamespaceSelector is used to filter Namespaces from which the generator should extract TenantControlPlane objects. + 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 + tenantControlPlaneSelector: + description: TenantControlPlaneSelector is used to filter the TenantControlPlane objects that should be address by the generator. + 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 + user: + description: User resolves to a string to identify the client, assigned to the x509 Common Name field. + properties: + fromDefinition: + description: |- + FromDefinition is used to generate a dynamic value, + it uses the dot notation to access fields from the referenced TenantControlPlane object: + e.g.: metadata.name + type: string + stringValue: + description: StringValue is a static string value. + type: string + type: object + x-kubernetes-validations: + - message: Either stringValue or fromDefinition must be set, but not both. + rule: (has(self.stringValue) || has(self.fromDefinition)) && !(has(self.stringValue) && has(self.fromDefinition)) + required: + - user + type: object + status: + description: KubeconfigGeneratorStatus defines the observed state of KubeconfigGenerator. + properties: + availableResources: + default: 0 + description: |- + AvailableResources is the sum of successfully generated resources. + In case of a different value compared to Resources, check the field errors. + type: integer + errors: + description: Errors is the list of failed kubeconfig generations. + items: + properties: + message: + description: Message is the error message recorded upon the last generator run. + type: string + resource: + description: Resource is the Namespaced name of the errored resource. + type: string + required: + - message + - resource + type: object + type: array + observedGeneration: + description: ObservedGeneration represents the .metadata.generation that was last reconciled. + format: int64 + type: integer + resources: + default: 0 + description: Resources is the sum of targeted TenantControlPlane objects. + type: integer + required: + - availableResources + - resources + type: object + type: object + served: true + storage: true + subresources: + status: {} 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 b3d3b668..f3c72dcd 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 @@ -3,7 +3,7 @@ kind: CustomResourceDefinition metadata: annotations: cert-manager.io/inject-ca-from: kamaji-system/kamaji-serving-cert - controller-gen.kubebuilder.io/version: v0.16.1 + controller-gen.kubebuilder.io/version: v0.20.0 name: tenantcontrolplanes.kamaji.clastix.io spec: group: kamaji.clastix.io @@ -23,6 +23,10 @@ spec: jsonPath: .spec.kubernetes.version name: Version type: string + - description: The actual installed Kubernetes version from status + jsonPath: .status.kubernetesResources.version.version + name: Installed Version + type: string - description: Status jsonPath: .status.kubernetesResources.version.status name: Status @@ -92,7 +96,7 @@ spec: agent: default: image: registry.k8s.io/kas-network-proxy/proxy-agent - version: v0.28.6 + mode: DaemonSet properties: extraArgs: description: |- @@ -103,10 +107,31 @@ spec: items: type: string type: array + hostNetwork: + default: false + description: |- + HostNetwork enables the konnectivity agent to use the Host network namespace. + By enabling this mode, the Agent doesn't need to wait for the CNI initialisation, + enabling a sort of out-of-band access to nodes for troubleshooting scenarios, + or when the agent needs direct access to the host network. + type: boolean image: default: registry.k8s.io/kas-network-proxy/proxy-agent description: AgentImage defines the container image for Konnectivity's agent. type: string + mode: + default: DaemonSet + description: 'Mode allows specifying the Agent deployment mode: Deployment, or DaemonSet (default).' + enum: + - DaemonSet + - Deployment + type: string + replicas: + description: |- + Replicas defines the number of replicas when Mode is Deployment. + Must be 0 if Mode is DaemonSet. + format: int32 + type: integer tolerations: default: - key: CriticalAddonsOnly @@ -132,9 +157,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -152,15 +178,20 @@ spec: type: object type: array version: - default: v0.28.6 - description: Version for Konnectivity agent. + description: |- + Version for Konnectivity agent. + If left empty, Kamaji will automatically inflect the version from the deployed Tenant Control Plane. + + WARNING: for last cut-off releases, the container image could be not available. type: string type: object + x-kubernetes-validations: + - message: replicas must be 0 (or unset) when mode is DaemonSet, and greater than 0 (or unset) when mode is Deployment + rule: '!(self.mode == ''DaemonSet'' && has(self.replicas) && self.replicas != 0) && !(self.mode == ''Deployment'' && has(self.replicas) && self.replicas == 0)' server: default: image: registry.k8s.io/kas-network-proxy/proxy-server port: 8132 - version: v0.28.6 properties: extraArgs: description: |- @@ -187,7 +218,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -239,8 +270,11 @@ spec: type: object type: object version: - default: v0.28.6 - description: Container image version of the Konnectivity server. + description: |- + Container image version of the Konnectivity server. + If left empty, Kamaji will automatically inflect the version from the deployed Tenant Control Plane. + + WARNING: for last cut-off releases, the container image could be not available. type: string required: - port @@ -312,7 +346,9 @@ spec: description: EnvVar represents an environment variable present in a Container. properties: name: - description: Name of the environment variable. Must be a C_IDENTIFIER. + description: |- + Name of the environment variable. + May consist of any printable ASCII characters except '='. type: string value: description: |- @@ -366,6 +402,42 @@ spec: - fieldPath type: object x-kubernetes-map-type: atomic + fileKeyRef: + description: |- + FileKeyRef selects a key of the env file. + Requires the EnvFiles feature gate to be enabled. + properties: + key: + description: |- + The key within the env file. An invalid key will prevent the pod from starting. + The keys defined within a source may consist of any printable ASCII characters except '='. + During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. + type: string + optional: + default: false + description: |- + Specify whether the file or its key must be defined. If the file or key + does not exist, then the env var is not published. + If optional is set to true and the specified key does not exist, + the environment variable will not be set in the Pod's containers. + + If optional is set to false and the specified key does not exist, + an error will be returned during Pod creation. + type: boolean + path: + description: |- + The path within the volume from which to select the file. + Must be relative and may not contain the '..' path or start with '..'. + type: string + volumeName: + description: The name of the volume mount containing the env file. + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic resourceFieldRef: description: |- Selects a resource of the container: only resources limits and requests @@ -421,8 +493,8 @@ spec: envFrom: description: |- List of sources to populate environment variables in the container. - The keys defined within a source must be a C_IDENTIFIER. All invalid keys - will be reported as an event when the container is starting. When a key exists in multiple + The keys defined within a source may consist of any printable ASCII characters except '='. + When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be updated. @@ -447,7 +519,9 @@ spec: type: object x-kubernetes-map-type: atomic prefix: - description: Optional text to prepend to the name of each environment variable. Must be a C_IDENTIFIER. + description: |- + Optional text to prepend to the name of each environment variable. + May consist of any printable ASCII characters except '='. type: string secretRef: description: The Secret to select from @@ -1061,7 +1135,9 @@ spec: type: integer type: object resizePolicy: - description: Resources resize policy for the container. + description: |- + Resources resize policy for the container. + This field cannot be set on ephemeral containers. items: description: ContainerResizePolicy represents resource resize policy for the container. properties: @@ -1092,7 +1168,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -1146,10 +1222,10 @@ spec: restartPolicy: description: |- RestartPolicy defines the restart behavior of individual containers in a pod. - This field may only be set for init containers, and the only allowed value is "Always". - For non-init containers or when this field is not specified, + This overrides the pod-level restart policy. When this field is not specified, the restart behavior is defined by the Pod's restart policy and the container type. - Setting the RestartPolicy as "Always" for the init container will have the following effect: + Additionally, setting the RestartPolicy as "Always" for the init container will + have the following effect: this init container will be continually restarted on exit until all regular containers have terminated. Once all regular containers have completed, all init containers with restartPolicy "Always" @@ -1161,6 +1237,57 @@ spec: init container is started, or after any startupProbe has successfully completed. type: string + restartPolicyRules: + description: |- + Represents a list of rules to be checked to determine if the + container should be restarted on exit. The rules are evaluated in + order. Once a rule matches a container exit condition, the remaining + rules are ignored. If no rule matches the container exit condition, + the Container-level restart policy determines the whether the container + is restarted or not. Constraints on the rules: + - At most 20 rules are allowed. + - Rules can have the same action. + - Identical rules are not forbidden in validations. + When rules are specified, container MUST set RestartPolicy explicitly + even it if matches the Pod's RestartPolicy. + items: + description: ContainerRestartRule describes how a container exit is handled. + properties: + action: + description: |- + Specifies the action taken on a container exit if the requirements + are satisfied. The only possible value is "Restart" to restart the + container. + type: string + exitCodes: + description: Represents the exit codes to check on container exits. + properties: + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. Possible values are: + - In: the requirement is satisfied if the container exit code is in the + set of specified values. + - NotIn: the requirement is satisfied if the container exit code is + not in the set of specified values. + type: string + values: + description: |- + Specifies the set of values to check for container exit codes. + At most 255 elements are allowed. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic securityContext: description: |- SecurityContext defines the security options the container should be run with. @@ -1683,7 +1810,9 @@ spec: description: EnvVar represents an environment variable present in a Container. properties: name: - description: Name of the environment variable. Must be a C_IDENTIFIER. + description: |- + Name of the environment variable. + May consist of any printable ASCII characters except '='. type: string value: description: |- @@ -1737,6 +1866,42 @@ spec: - fieldPath type: object x-kubernetes-map-type: atomic + fileKeyRef: + description: |- + FileKeyRef selects a key of the env file. + Requires the EnvFiles feature gate to be enabled. + properties: + key: + description: |- + The key within the env file. An invalid key will prevent the pod from starting. + The keys defined within a source may consist of any printable ASCII characters except '='. + During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. + type: string + optional: + default: false + description: |- + Specify whether the file or its key must be defined. If the file or key + does not exist, then the env var is not published. + If optional is set to true and the specified key does not exist, + the environment variable will not be set in the Pod's containers. + + If optional is set to false and the specified key does not exist, + an error will be returned during Pod creation. + type: boolean + path: + description: |- + The path within the volume from which to select the file. + Must be relative and may not contain the '..' path or start with '..'. + type: string + volumeName: + description: The name of the volume mount containing the env file. + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic resourceFieldRef: description: |- Selects a resource of the container: only resources limits and requests @@ -1792,8 +1957,8 @@ spec: envFrom: description: |- List of sources to populate environment variables in the container. - The keys defined within a source must be a C_IDENTIFIER. All invalid keys - will be reported as an event when the container is starting. When a key exists in multiple + The keys defined within a source may consist of any printable ASCII characters except '='. + When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be updated. @@ -1818,7 +1983,9 @@ spec: type: object x-kubernetes-map-type: atomic prefix: - description: Optional text to prepend to the name of each environment variable. Must be a C_IDENTIFIER. + description: |- + Optional text to prepend to the name of each environment variable. + May consist of any printable ASCII characters except '='. type: string secretRef: description: The Secret to select from @@ -2432,7 +2599,9 @@ spec: type: integer type: object resizePolicy: - description: Resources resize policy for the container. + description: |- + Resources resize policy for the container. + This field cannot be set on ephemeral containers. items: description: ContainerResizePolicy represents resource resize policy for the container. properties: @@ -2463,7 +2632,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -2517,10 +2686,10 @@ spec: restartPolicy: description: |- RestartPolicy defines the restart behavior of individual containers in a pod. - This field may only be set for init containers, and the only allowed value is "Always". - For non-init containers or when this field is not specified, + This overrides the pod-level restart policy. When this field is not specified, the restart behavior is defined by the Pod's restart policy and the container type. - Setting the RestartPolicy as "Always" for the init container will have the following effect: + Additionally, setting the RestartPolicy as "Always" for the init container will + have the following effect: this init container will be continually restarted on exit until all regular containers have terminated. Once all regular containers have completed, all init containers with restartPolicy "Always" @@ -2532,6 +2701,57 @@ spec: init container is started, or after any startupProbe has successfully completed. type: string + restartPolicyRules: + description: |- + Represents a list of rules to be checked to determine if the + container should be restarted on exit. The rules are evaluated in + order. Once a rule matches a container exit condition, the remaining + rules are ignored. If no rule matches the container exit condition, + the Container-level restart policy determines the whether the container + is restarted or not. Constraints on the rules: + - At most 20 rules are allowed. + - Rules can have the same action. + - Identical rules are not forbidden in validations. + When rules are specified, container MUST set RestartPolicy explicitly + even it if matches the Pod's RestartPolicy. + items: + description: ContainerRestartRule describes how a container exit is handled. + properties: + action: + description: |- + Specifies the action taken on a container exit if the requirements + are satisfied. The only possible value is "Restart" to restart the + container. + type: string + exitCodes: + description: Represents the exit codes to check on container exits. + properties: + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. Possible values are: + - In: the requirement is satisfied if the container exit code is in the + set of specified values. + - NotIn: the requirement is satisfied if the container exit code is + not in the set of specified values. + type: string + values: + description: |- + Specifies the set of values to check for container exit codes. + At most 255 elements are allowed. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic securityContext: description: |- SecurityContext defines the security options the container should be run with. @@ -3774,7 +3994,7 @@ spec: resources: description: |- resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + Users are allowed to specify resource requirements that are lower than previous value but must still be higher than capacity recorded in the status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources @@ -3858,15 +4078,13 @@ spec: volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. If specified, the CSI driver will create or update the volume with the attributes defined in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -4040,12 +4258,9 @@ spec: description: |- glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported. - More info: https://examples.k8s.io/volumes/glusterfs/README.md properties: endpoints: - description: |- - endpoints is the endpoint name that details Glusterfs topology. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + description: endpoints is the endpoint name that details Glusterfs topology. type: string path: description: |- @@ -4124,7 +4339,7 @@ spec: description: |- iscsi represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. - More info: https://examples.k8s.io/volumes/iscsi/README.md + More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi properties: chapAuthDiscovery: description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication @@ -4514,6 +4729,128 @@ spec: type: array x-kubernetes-list-type: atomic type: object + podCertificate: + description: |- + Projects an auto-rotating credential bundle (private key and certificate + chain) that the pod can use either as a TLS client or server. + + Kubelet generates a private key and uses it to send a + PodCertificateRequest to the named signer. Once the signer approves the + request and issues a certificate chain, Kubelet writes the key and + certificate chain to the pod filesystem. The pod does not start until + certificates have been issued for each podCertificate projected volume + source in its spec. + + Kubelet will begin trying to rotate the certificate at the time indicated + by the signer using the PodCertificateRequest.Status.BeginRefreshAt + timestamp. + + Kubelet can write a single file, indicated by the credentialBundlePath + field, or separate files, indicated by the keyPath and + certificateChainPath fields. + + The credential bundle is a single file in PEM format. The first PEM + entry is the private key (in PKCS#8 format), and the remaining PEM + entries are the certificate chain issued by the signer (typically, + signers will return their certificate chain in leaf-to-root order). + + Prefer using the credential bundle format, since your application code + can read it atomically. If you use keyPath and certificateChainPath, + your application must make two separate file reads. If these coincide + with a certificate rotation, it is possible that the private key and leaf + certificate you read may not correspond to each other. Your application + will need to check for this condition, and re-read until they are + consistent. + + The named signer controls chooses the format of the certificate it + issues; consult the signer implementation's documentation to learn how to + use the certificates it issues. + properties: + certificateChainPath: + description: |- + Write the certificate chain at this path in the projected volume. + + Most applications should use credentialBundlePath. When using keyPath + and certificateChainPath, your application needs to check that the key + and leaf certificate are consistent, because it is possible to read the + files mid-rotation. + type: string + credentialBundlePath: + description: |- + Write the credential bundle at this path in the projected volume. + + The credential bundle is a single file that contains multiple PEM blocks. + The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private + key. + + The remaining blocks are CERTIFICATE blocks, containing the issued + certificate chain from the signer (leaf and any intermediates). + + Using credentialBundlePath lets your Pod's application code make a single + atomic read that retrieves a consistent key and certificate chain. If you + project them to separate files, your application code will need to + additionally check that the leaf certificate was issued to the key. + type: string + keyPath: + description: |- + Write the key at this path in the projected volume. + + Most applications should use credentialBundlePath. When using keyPath + and certificateChainPath, your application needs to check that the key + and leaf certificate are consistent, because it is possible to read the + files mid-rotation. + type: string + keyType: + description: |- + The type of keypair Kubelet will generate for the pod. + + Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384", + "ECDSAP521", and "ED25519". + type: string + maxExpirationSeconds: + description: |- + maxExpirationSeconds is the maximum lifetime permitted for the + certificate. + + Kubelet copies this value verbatim into the PodCertificateRequests it + generates for this projection. + + If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver + will reject values shorter than 3600 (1 hour). The maximum allowable + value is 7862400 (91 days). + + The signer implementation is then free to issue a certificate with any + lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600 + seconds (1 hour). This constraint is enforced by kube-apiserver. + `kubernetes.io` signers will never issue certificates with a lifetime + longer than 24 hours. + format: int32 + type: integer + signerName: + description: Kubelet's generated CSRs will be addressed to this signer. + type: string + userAnnotations: + additionalProperties: + type: string + description: |- + userAnnotations allow pod authors to pass additional information to + the signer implementation. Kubernetes does not restrict or validate this + metadata in any way. + + These values are copied verbatim into the `spec.unverifiedUserAnnotations` field of + the PodCertificateRequest objects that Kubelet creates. + + Entries are subject to the same validation as object metadata annotations, + with the addition that all keys must be domain-prefixed. No restrictions + are placed on values, except an overall size limitation on the entire field. + + Signers should document the keys and values they support. Signers should + deny requests that contain keys they do not recognize. + type: object + required: + - keyType + - signerName + type: object secret: description: secret information about the secret data to project properties: @@ -4643,7 +4980,6 @@ spec: description: |- rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported. - More info: https://examples.k8s.io/volumes/rbd/README.md properties: fsType: description: |- @@ -5461,8 +5797,8 @@ spec: most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. items: description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) @@ -5837,6 +6173,397 @@ spec: type: string type: object type: object + probes: + description: |- + Probes defines the probe configuration for the Control Plane components + (kube-apiserver, controller-manager, and scheduler). + Override TimeoutSeconds, PeriodSeconds, and FailureThreshold for resource-constrained environments. + properties: + apiServer: + description: APIServer defines probe overrides for kube-apiserver, taking precedence over global probe settings. + properties: + liveness: + description: Liveness defines parameters for the liveness probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + readiness: + description: Readiness defines parameters for the readiness probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + startup: + description: Startup defines parameters for the startup probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + type: object + controllerManager: + description: ControllerManager defines probe overrides for kube-controller-manager, taking precedence over global probe settings. + properties: + liveness: + description: Liveness defines parameters for the liveness probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + readiness: + description: Readiness defines parameters for the readiness probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + startup: + description: Startup defines parameters for the startup probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + type: object + liveness: + description: Liveness defines default parameters for liveness probes of all Control Plane components. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + readiness: + description: Readiness defines default parameters for the readiness probe of kube-apiserver. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + scheduler: + description: Scheduler defines probe overrides for kube-scheduler, taking precedence over global probe settings. + properties: + liveness: + description: Liveness defines parameters for the liveness probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + readiness: + description: Readiness defines parameters for the readiness probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + startup: + description: Startup defines parameters for the startup probe. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + type: object + startup: + description: Startup defines default parameters for startup probes of all Control Plane components. + properties: + failureThreshold: + description: FailureThreshold is the consecutive failure count required to consider the probe failed. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: InitialDelaySeconds is the number of seconds after the container has started before the probe is initiated. + format: int32 + minimum: 0 + type: integer + periodSeconds: + description: PeriodSeconds is how often (in seconds) to perform the probe. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + SuccessThreshold is the minimum consecutive successes for the probe to be considered successful. + Must be 1 for liveness and startup probes. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: TimeoutSeconds is the number of seconds after which the probe times out. + format: int32 + minimum: 1 + type: integer + type: object + type: object registrySettings: default: apiServerImage: kube-apiserver @@ -5882,7 +6609,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -5941,7 +6668,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -6002,7 +6729,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -6061,7 +6788,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -6200,9 +6927,10 @@ spec: operator: description: |- Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). type: string tolerationSeconds: description: |- @@ -6395,6 +7123,178 @@ spec: type: object type: array type: object + gateway: + description: Defining the options for an Optional Gateway which will expose API Server of the Tenant Control Plane + properties: + additionalMetadata: + description: AdditionalMetadata to add Labels and Annotations support. + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + hostname: + description: Hostname is an optional field which will be used as a route hostname. + 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 + parentRefs: + description: GatewayParentRefs is the class of the Gateway resource to use. + 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 + type: array + type: object ingress: description: Defining the options for an Optional Ingress which will expose API Server of the Tenant Control Plane properties: @@ -6433,6 +7333,56 @@ spec: type: string type: object type: object + additionalPorts: + description: |- + AdditionalPorts allows adding additional ports to the Service generated Kamaji + which targets the Tenant Control Plane pods. + items: + properties: + appProtocol: + description: |- + The application protocol for this port. + This is used as a hint for implementations to offer richer behavior for protocols that they understand. + This field follows standard Kubernetes label syntax. + Valid values are either: + + * Un-prefixed protocol names - reserved for IANA standard service names (as per + RFC-6335 and https://www.iana.org/assignments/service-names). + type: string + name: + description: |- + The name of this port within the Service created by Kamaji. + This must be a DNS_LABEL, must have unique names, and cannot be `kube-apiserver`, or `konnectivity-server`. + type: string + port: + description: The port that will be exposed by this service. + format: int32 + type: integer + protocol: + default: TCP + description: The IP protocol for this port. Supports "TCP", "UDP", and "SCTP". + enum: + - TCP + - UDP + - SCTP + type: string + targetPort: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the pods of the Tenant Control Plane. + Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + If this is a string, it will be looked up as a named port in the + target Pod's container ports. If this is not specified, the value + of the 'port' field is used (an identity map). + x-kubernetes-int-or-string: true + required: + - name + - port + - targetPort + type: object + type: array serviceType: description: ServiceType allows specifying how to expose the Tenant Control Plane. enum: @@ -6446,6 +7396,9 @@ spec: required: - service type: object + x-kubernetes-validations: + - message: using both ingress and gateway is not supported + rule: '!(has(self.ingress) && has(self.gateway))' dataStore: description: |- DataStore specifies the DataStore that should be used to store the Kubernetes data for the given Tenant Control Plane. @@ -6455,6 +7408,19 @@ spec: Migration from one DataStore to another backed by the same Driver is possible. See: https://kamaji.clastix.io/guides/datastore-migration/ Migration from one DataStore to another backed by a different Driver is not supported. type: string + dataStoreOverrides: + description: DataStoreOverride defines which kubernetes resources will be stored in dedicated datastores. + items: + description: DataStoreOverride defines which kubernetes resource will be stored in a dedicated datastore. + properties: + dataStore: + description: DataStore specifies the DataStore that should be used to store the Kubernetes data for the given Resource. + type: string + resource: + description: Resource specifies which kubernetes resource to target. + type: string + type: object + type: array dataStoreSchema: description: |- DataStoreSchema allows to specify the name of the database (for relational DataStores) or the key prefix (for etcd). This @@ -6465,6 +7431,16 @@ spec: x-kubernetes-validations: - message: changing the dataStoreSchema is not supported rule: self == oldSelf + dataStoreUsername: + description: |- + DataStoreUsername allows to specify the username of the database (for relational DataStores). This + value is optional and immutable. Note that Kamaji currently doesn't ensure that DataStoreUsername values are unique. It's up + to the user to avoid clashes between different TenantControlPlanes. If not set upon creation, Kamaji will default the + DataStoreUsername by concatenating the namespace and name of the TenantControlPlane. + type: string + x-kubernetes-validations: + - message: changing the dataStoreUsername is not supported + rule: self == oldSelf kubernetes: description: Kubernetes specification for tenant control plane properties: @@ -6535,20 +7511,55 @@ spec: properties: cgroupfs: description: |- - CGroupFS defines the cgroup driver for Kubelet + CGroupFS defines the cgroup driver for Kubelet https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/configure-cgroup-driver/ + + Deprecated: use ConfigurationJSONPatches. enum: - systemd - cgroupfs type: string + configurationJSONPatches: + description: |- + ConfigurationJSONPatches contains the RFC 6902 JSON patches to customise the kubeadm generate configuration, + useful to customise and mangling the configuration according to your needs; + e.g.: configuring the cgroup driver used by Kubelet is possible via the following patch: + + [{"op": "replace", "path": "/cgroupDriver", "value": "systemd"}] + items: + properties: + from: + description: From specifies the source location for move or copy operations. + type: string + op: + description: Op is the RFC 6902 JSON Patch operation. + enum: + - add + - remove + - replace + - move + - copy + - test + type: string + path: + description: Path specifies the target location in the JSON document. Use "/" to separate keys; "-" for appending to arrays. + type: string + value: + description: Value is the operation value to be used when Op is add, replace, test. + x-kubernetes-preserve-unknown-fields: true + required: + - op + - path + type: object + type: array preferredAddressTypes: default: - - Hostname - InternalIP - ExternalIP + - Hostname description: |- Ordered list of the preferred NodeAddressTypes to use for kubelet connections. - Default to Hostname, InternalIP, ExternalIP. + Default to InternalIP, ExternalIP, Hostname. items: enum: - Hostname @@ -6559,6 +7570,7 @@ spec: type: string minItems: 1 type: array + x-kubernetes-list-type: set type: object version: description: Kubernetes Version for the tenant control plane @@ -6572,8 +7584,8 @@ spec: properties: address: description: |- - Address where API server of will be exposed. - In case of LoadBalancer Service, this can be empty in order to use the exposed IP provided by the cloud controller manager. + Address where API server will be exposed. + In the case of LoadBalancer Service, this can be empty in order to use the exposed IP provided by the cloud controller manager. type: string allowAddressAsExternalIP: description: |- @@ -6603,6 +7615,7 @@ spec: for IPv6 from the CIDR 2001:db8:abcd::/64 the resulting DNS Service IP will be 2001:db8:abcd::10. items: type: string + maxItems: 8 type: array loadBalancerClass: description: |- @@ -6624,20 +7637,49 @@ spec: Example: {"192.168.1.0/24", "10.0.0.0/8"} items: type: string + maxItems: 16 type: array + x-kubernetes-validations: + - message: all LoadBalancer source range entries must be valid CIDR + rule: self.all(r, isCIDR(r)) podCidr: default: 10.244.0.0/16 description: 'CIDR for Kubernetes Pods: if empty, defaulted to 10.244.0.0/16.' type: string + x-kubernetes-validations: + - message: podCidr must be empty or a valid CIDR + rule: self == '' || isCIDR(self) port: default: 6443 - description: Port where API server of will be exposed + description: Port where API server will be exposed format: int32 type: integer serviceCidr: default: 10.96.0.0/16 description: 'CIDR for Kubernetes Services: if empty, defaulted to 10.96.0.0/16.' type: string + x-kubernetes-validations: + - message: serviceCidr must be empty or a valid CIDR + rule: self == '' || isCIDR(self) + type: object + x-kubernetes-validations: + - message: all DNS service IPs must be part of the Service CIDR + rule: '!has(self.dnsServiceIPs) || self.dnsServiceIPs.all(r, cidr(self.serviceCidr).containsIP(r))' + writePermissions: + description: |- + WritePermissions allows to select which operations (create, delete, update) must be blocked: + by default, all actions are allowed, and API Server can write to its Datastore. + + By blocking all actions, the Tenant Control Plane can enter in a Read Only mode: + this phase can be used to prevent Datastore quota exhaustion or for your own business logic + (e.g.: blocking creation and update, but allowing deletion to "clean up" space). + properties: + blockCreation: + type: boolean + blockDeletion: + type: boolean + blockUpdate: + type: boolean type: object required: - controlPlane @@ -6648,6 +7690,8 @@ spec: rule: '!has(oldSelf.dataStore) || has(self.dataStore)' - message: unsetting the dataStoreSchema is not supported rule: '!has(oldSelf.dataStoreSchema) || has(self.dataStoreSchema)' + - message: unsetting the dataStoreUsername is not supported + rule: '!has(oldSelf.dataStoreUsername) || has(self.dataStoreUsername)' - message: LoadBalancer source ranges are supported only with LoadBalancer service type rule: '!has(self.networkProfile.loadBalancerSourceRanges) || (size(self.networkProfile.loadBalancerSourceRanges) == 0 || self.controlPlane.service.serviceType == ''LoadBalancer'')' - message: LoadBalancerClass is supported only with LoadBalancer service type @@ -6680,6 +7724,8 @@ spec: description: Last time when k8s object was updated format: date-time type: string + mode: + type: string name: type: string namespace: @@ -6716,6 +7762,383 @@ spec: type: object enabled: type: boolean + gateway: + description: KubernetesGatewayStatus defines the status for the Tenant Control Plane Gateway in the management cluster. + properties: + accessPoints: + description: A list of valid access points that the route exposes. + items: + properties: + port: + format: int32 + type: integer + type: + description: |- + AddressType defines how a network address is represented as a text string. + This may take two possible forms: + + * A predefined CamelCase string identifier (currently limited to `IPAddress` or `Hostname`) + * A domain-prefixed string identifier (like `acme.io/CustomAddressType`) + + Values `IPAddress` and `Hostname` have Extended support. + + The `NamedAddress` value has been deprecated in favor of implementation + specific domain-prefixed strings. + + All other values, including domain-prefixed values have Implementation-specific support, + which are used in implementation-specific behaviors. Support for additional + predefined CamelCase identifiers may be added in future releases. + 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 + urls: + items: + type: string + type: array + value: + type: string + required: + - port + - type + - value + type: object + type: array + 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. + + + Notes for implementors: + + While parents is not a listType `map`, this is due to the fact that the + list key is not scalar, and Kubernetes is unable to represent this. + + Parent status MUST be considered to be namespaced by the combination of + the parentRef and controllerName fields, and implementations should keep + the following rules in mind when updating this status: + + * Implementations MUST update only entries that have a matching value of + `controllerName` for that implementation. + * Implementations MUST NOT update entries with non-matching `controllerName` + fields. + * Implementations MUST treat each `parentRef`` in the Route separately and + update its status based on the relationship with that parent. + * Implementations MUST perform a read-modify-write cycle on this field + before modifying it. That is, when modifying this field, implementations + must be confident they have fetched the most recent version of this field, + and ensure that changes they make are on that recent version. + + + 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 nonexistent 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. + + + + Notes for implementors: + + Conditions are a listType `map`, which means that they function like a + map with a key of the `type` field _in the k8s apiserver_. + + This means that implementations must obey some rules when updating this + section. + + * Implementations MUST perform a read-modify-write cycle on this field + before modifying it. That is, when modifying this field, implementations + must be confident they have fetched the most recent version of this field, + and ensure that changes they make are on that recent version. + * Implementations MUST NOT remove or reorder Conditions that they are not + directly responsible for. For example, if an implementation sees a Condition + with type `special.io/SomeField`, it MUST NOT remove, change or update that + Condition. + * Implementations MUST always _merge_ changes into Conditions of the same Type, + rather than creating more than one Condition of the same Type. + * Implementations MUST always update the `observedGeneration` field of the + Condition to the `metadata.generation` of the Gateway at the time of update creation. + * If the `observedGeneration` of a Condition is _greater than_ the value the + implementation knows about, then it MUST NOT perform the update on that Condition, + but must wait for a future reconciliation and status update. (The assumption is that + the implementation's copy of the object is stale and an update will be re-triggered + if relevant.) + + + 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: + - conditions + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + x-kubernetes-list-type: atomic + routeRef: + description: Reference to the route created for this tenant. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + required: + - parents + type: object kubeconfig: description: KubeconfigStatus contains information about the generated kubeconfig. properties: @@ -7146,7 +8569,7 @@ spec: 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. + This is a beta field and requires enabling DeploymentReplicaSetTerminatingReplicas feature (enabled by default). format: int32 type: integer unavailableReplicas: @@ -7165,6 +8588,383 @@ spec: - namespace - selector type: object + gateway: + description: KubernetesGatewayStatus defines the status for the Tenant Control Plane Gateway in the management cluster. + properties: + accessPoints: + description: A list of valid access points that the route exposes. + items: + properties: + port: + format: int32 + type: integer + type: + description: |- + AddressType defines how a network address is represented as a text string. + This may take two possible forms: + + * A predefined CamelCase string identifier (currently limited to `IPAddress` or `Hostname`) + * A domain-prefixed string identifier (like `acme.io/CustomAddressType`) + + Values `IPAddress` and `Hostname` have Extended support. + + The `NamedAddress` value has been deprecated in favor of implementation + specific domain-prefixed strings. + + All other values, including domain-prefixed values have Implementation-specific support, + which are used in implementation-specific behaviors. Support for additional + predefined CamelCase identifiers may be added in future releases. + 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 + urls: + items: + type: string + type: array + value: + type: string + required: + - port + - type + - value + type: object + type: array + 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. + + + Notes for implementors: + + While parents is not a listType `map`, this is due to the fact that the + list key is not scalar, and Kubernetes is unable to represent this. + + Parent status MUST be considered to be namespaced by the combination of + the parentRef and controllerName fields, and implementations should keep + the following rules in mind when updating this status: + + * Implementations MUST update only entries that have a matching value of + `controllerName` for that implementation. + * Implementations MUST NOT update entries with non-matching `controllerName` + fields. + * Implementations MUST treat each `parentRef`` in the Route separately and + update its status based on the relationship with that parent. + * Implementations MUST perform a read-modify-write cycle on this field + before modifying it. That is, when modifying this field, implementations + must be confident they have fetched the most recent version of this field, + and ensure that changes they make are on that recent version. + + + 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 nonexistent 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. + + + + Notes for implementors: + + Conditions are a listType `map`, which means that they function like a + map with a key of the `type` field _in the k8s apiserver_. + + This means that implementations must obey some rules when updating this + section. + + * Implementations MUST perform a read-modify-write cycle on this field + before modifying it. That is, when modifying this field, implementations + must be confident they have fetched the most recent version of this field, + and ensure that changes they make are on that recent version. + * Implementations MUST NOT remove or reorder Conditions that they are not + directly responsible for. For example, if an implementation sees a Condition + with type `special.io/SomeField`, it MUST NOT remove, change or update that + Condition. + * Implementations MUST always _merge_ changes into Conditions of the same Type, + rather than creating more than one Condition of the same Type. + * Implementations MUST always update the `observedGeneration` field of the + Condition to the `metadata.generation` of the Gateway at the time of update creation. + * If the `observedGeneration` of a Condition is _greater than_ the value the + implementation knows about, then it MUST NOT perform the update on that Condition, + but must wait for a future reconciliation and status update. (The assumption is that + the implementation's copy of the object is stale and an update will be re-triggered + if relevant.) + + + 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: + - conditions + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + x-kubernetes-list-type: atomic + routeRef: + description: Reference to the route created for this tenant. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + required: + - parents + type: object ingress: description: KubernetesIngressStatus defines the status for the Tenant Control Plane Ingress in the management cluster. properties: @@ -7383,6 +9183,7 @@ spec: default: Provisioning description: Status returns the current status of the Kubernetes version, such as its provisioning state, or completed upgrade. enum: + - Unknown - Provisioning - CertificateAuthorityRotating - Upgrading @@ -7390,12 +9191,17 @@ spec: - Ready - NotReady - Sleeping + - WriteLimited type: string version: description: Version is the running Kubernetes version of the Tenant Control Plane. type: string type: object type: object + observedGeneration: + description: ObservedGeneration represents the .metadata.generation that was last reconciled. + format: int64 + type: integer storage: description: Storage Status contains information about Kubernetes storage system properties: diff --git a/packages/system/kamaji/charts/kamaji/templates/_helpers.tpl b/packages/system/kamaji/charts/kamaji/templates/_helpers.tpl index f44ca63d..f0bf1bed 100644 --- a/packages/system/kamaji/charts/kamaji/templates/_helpers.tpl +++ b/packages/system/kamaji/charts/kamaji/templates/_helpers.tpl @@ -89,3 +89,15 @@ Create the name of the cert-manager Certificate {{- define "kamaji.certificateName" -}} {{- printf "%s-serving-cert" (include "kamaji.fullname" .) }} {{- end }} + + +{{/* +Kubeconfig Generator Deployment name. +*/}} +{{- define "kamaji.kubeconfigGeneratorName" -}} +{{- if .Values.kubeconfigGenerator.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name "kubeconfig-generator" | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} diff --git a/packages/system/kamaji/charts/kamaji/templates/kubeconfiggenerator-deployment.yaml b/packages/system/kamaji/charts/kamaji/templates/kubeconfiggenerator-deployment.yaml new file mode 100644 index 00000000..d7199d21 --- /dev/null +++ b/packages/system/kamaji/charts/kamaji/templates/kubeconfiggenerator-deployment.yaml @@ -0,0 +1,54 @@ +{{- if .Values.kubeconfigGenerator.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + {{- include "kamaji.labels" . | nindent 4 }} + name: {{ include "kamaji.kubeconfigGeneratorName" . }} + namespace: {{ .Release.Namespace }} +spec: + replicas: {{ .Values.kubeconfigGenerator.replicaCount }} + selector: + matchLabels: + {{- include "kamaji.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.kubeconfigGenerator.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "kamaji.selectorLabels" . | nindent 8 }} + spec: + securityContext: + {{- toYaml .Values.kubeconfigGenerator.podSecurityContext | nindent 8 }} + serviceAccountName: {{ default .Values.kubeconfigGenerator.serviceAccountOverride (include "kamaji.serviceAccountName" .) }} + containers: + - args: + - kubeconfig-generator + - --health-probe-bind-address={{ .Values.kubeconfigGenerator.healthProbeBindAddress }} + - --leader-elect={{ .Values.kubeconfigGenerator.enableLeaderElect }} + {{- if .Values.kubeconfigGenerator.loggingDevel.enable }}- --zap-devel{{- end }} + {{- with .Values.kubeconfigGenerator.extraArgs }} + {{- toYaml . | nindent 10 }} + {{- end }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: controller + resources: + {{- toYaml .Values.kubeconfigGenerator.resources | nindent 12 }} + securityContext: + {{- toYaml .Values.kubeconfigGenerator.securityContext | nindent 12 }} + {{- with .Values.kubeconfigGenerator.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.kubeconfigGenerator.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.kubeconfigGenerator.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/packages/system/kamaji/charts/kamaji/values.yaml b/packages/system/kamaji/charts/kamaji/values.yaml index 79dd254a..0e99af10 100644 --- a/packages/system/kamaji/charts/kamaji/values.yaml +++ b/packages/system/kamaji/charts/kamaji/values.yaml @@ -98,9 +98,12 @@ loggingDevel: # -- If specified, all the Kamaji instances with an unassigned DataStore will inherit this default value. defaultDatastoreName: default +# -- Subchart: See https://github.com/clastix/kamaji-etcd/blob/master/charts/kamaji-etcd/values.yaml kamaji-etcd: deploy: true fullnameOverride: kamaji-etcd + ## -- Important, this must match your management cluster's clusterDomain, otherwise the init jobs will fail + clusterDomain: "cluster.local" datastore: enabled: true name: default @@ -108,4 +111,48 @@ kamaji-etcd: # -- Disable the analytics traces collection telemetry: disabled: false - \ No newline at end of file + +kubeconfigGenerator: + # -- Toggle to deploy the Kubeconfig Generator Deployment. + enabled: false + fullnameOverride: "" + # -- The number of the pod replicas for the Kubeconfig Generator controller. + replicaCount: 2 + # -- The annotations to apply to the Kubeconfig Generator controller pods. + podAnnotations: {} + # -- The securityContext to apply to the Kubeconfig Generator controller pods. + podSecurityContext: + runAsNonRoot: true + # -- The name of the service account to use. If not set, the root Kamaji one will be used. + serviceAccountOverride: "" + # -- The address the probe endpoint binds to. + healthProbeBindAddress: ":8081" + # -- Enables the leader election. + enableLeaderElect: true + loggingDevel: + # -- Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error) + enable: false + # -- A list of extra arguments to add to the Kubeconfig Generator controller default ones. + extraArgs: [] + resources: + limits: + cpu: 200m + memory: 512Mi + requests: + cpu: 200m + memory: 512Mi + # -- The securityContext to apply to the Kubeconfig Generator controller container only. + securityContext: + allowPrivilegeEscalation: false + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + # -- Kubernetes node selector rules to schedule Kubeconfig Generator controller + nodeSelector: {} + # -- Kubernetes node taints that the Kubeconfig Generator controller pods would tolerate + tolerations: [] + # -- Kubernetes affinity rules to apply to Kubeconfig Generator controller pods + affinity: {} diff --git a/packages/system/kamaji/images/kamaji/Dockerfile b/packages/system/kamaji/images/kamaji/Dockerfile index e7bd44be..4dd0bb3f 100644 --- a/packages/system/kamaji/images/kamaji/Dockerfile +++ b/packages/system/kamaji/images/kamaji/Dockerfile @@ -1,7 +1,7 @@ # Build the manager binary -FROM golang:1.24 as builder +FROM golang:1.26 AS builder -ARG VERSION=edge-25.4.1 +ARG VERSION=26.3.5-edge ARG TARGETOS ARG TARGETARCH diff --git a/packages/system/kamaji/images/kamaji/patches/disable-datastore-check.diff b/packages/system/kamaji/images/kamaji/patches/disable-datastore-check.diff deleted file mode 100644 index 0d28b780..00000000 --- a/packages/system/kamaji/images/kamaji/patches/disable-datastore-check.diff +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/cmd/manager/cmd.go b/cmd/manager/cmd.go -index 9a24d4e..a03a4e0 100644 ---- a/cmd/manager/cmd.go -+++ b/cmd/manager/cmd.go -@@ -31,7 +31,6 @@ import ( - "github.com/clastix/kamaji/controllers/soot" - "github.com/clastix/kamaji/internal" - "github.com/clastix/kamaji/internal/builders/controlplane" -- datastoreutils "github.com/clastix/kamaji/internal/datastore/utils" - "github.com/clastix/kamaji/internal/webhook" - "github.com/clastix/kamaji/internal/webhook/handlers" - "github.com/clastix/kamaji/internal/webhook/routes" -@@ -80,10 +79,6 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command { - return fmt.Errorf("unable to read webhook CA: %w", err) - } - -- if err = datastoreutils.CheckExists(ctx, scheme, datastore); err != nil { -- return err -- } -- - if controllerReconcileTimeout.Seconds() == 0 { - return fmt.Errorf("the controller reconcile timeout must be greater than zero") - } diff --git a/packages/system/kamaji/images/kamaji/patches/fix-kubelet-config-compat.diff b/packages/system/kamaji/images/kamaji/patches/fix-kubelet-config-compat.diff new file mode 100644 index 00000000..ceb10686 --- /dev/null +++ b/packages/system/kamaji/images/kamaji/patches/fix-kubelet-config-compat.diff @@ -0,0 +1,49 @@ +diff --git a/internal/kubeadm/uploadconfig.go b/internal/kubeadm/uploadconfig.go +index 89c9b54..1ee38cd 100644 +--- a/internal/kubeadm/uploadconfig.go ++++ b/internal/kubeadm/uploadconfig.go +@@ -41,7 +41,7 @@ func UploadKubeletConfig(client kubernetes.Interface, config *Configuration, pat + TenantControlPlaneCgroupDriver: config.Parameters.TenantControlPlaneCGroupDriver, + } + +- content, err := getKubeletConfigmapContent(kubeletConfiguration, patches) ++ content, err := getKubeletConfigmapContent(kubeletConfiguration, patches, config.Parameters.TenantControlPlaneVersion) + if err != nil { + return nil, err + } +@@ -72,7 +72,13 @@ func UploadKubeletConfig(client kubernetes.Interface, config *Configuration, pat + return nil, nil + } + +-func getKubeletConfigmapContent(kubeletConfiguration KubeletConfiguration, patch jsonpatchv5.Patch) ([]byte, error) { ++// minVerKubeletNewDefaults is the minimum Kubernetes version that supports the ++// CrashLoopBackOff and ImagePullCredentialsVerificationPolicy kubelet ++// configuration fields (gated by KubeletCrashLoopBackOffMax and ++// KubeletEnsureSecretPulledImages feature gates respectively). ++var minVerKubeletNewDefaults = semver.MustParse("1.35.0") ++ ++func getKubeletConfigmapContent(kubeletConfiguration KubeletConfiguration, patch jsonpatchv5.Patch, version string) ([]byte, error) { + var kc kubelettypes.KubeletConfiguration + + kubeletv1beta1.SetDefaults_KubeletConfiguration(&kc) +@@ -94,6 +100,20 @@ func getKubeletConfigmapContent(kubeletConfiguration KubeletConfiguration, patch + // determine the resolvConf location, as reported in clastix/kamaji#581. + kc.ResolverConfig = nil + ++ // Clear fields set by SetDefaults_KubeletConfiguration from Kubernetes >= 1.35. ++ // Older kubelets reject these fields because the corresponding feature gates ++ // (KubeletCrashLoopBackOffMax, KubeletEnsureSecretPulledImages) are not enabled. ++ // See: https://github.com/clastix/kamaji/issues/1062 ++ parsedVer, parseErr := semver.ParseTolerant(version) ++ if parseErr != nil { ++ return nil, fmt.Errorf("failed to parse kubernetes version %q for kubelet config: %w", version, parseErr) ++ } ++ ++ if parsedVer.LT(minVerKubeletNewDefaults) { ++ kc.CrashLoopBackOff = kubelettypes.CrashLoopBackOffConfig{} ++ kc.ImagePullCredentialsVerificationPolicy = "" ++ } ++ + if len(patch) > 0 { + kubeletConfig, patchErr := utilities.EncodeToJSON(&kc) + if patchErr != nil { diff --git a/packages/system/kamaji/values.yaml b/packages/system/kamaji/values.yaml index 1c761099..6ba649f0 100644 --- a/packages/system/kamaji/values.yaml +++ b/packages/system/kamaji/values.yaml @@ -3,12 +3,37 @@ kamaji: deploy: false image: pullPolicy: IfNotPresent - tag: v0.33.2@sha256:09465ae8285b4ae43203581e443409cd4e1e119dde62a5c14d63ce064fb840b0 + tag: v1.3.0@sha256:8c9af083b60600c0800eb56a2cda75f26007b7272a1cf019140de003bfce1a4d repository: ghcr.io/cozystack/cozystack/kamaji resources: limits: cpu: 200m - memory: 500Mi + memory: 512Mi requests: cpu: 100m - memory: 100Mi + memory: 256Mi + startupProbe: + httpGet: + path: /healthz + port: healthcheck + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 3 + successThreshold: 1 + failureThreshold: 12 + livenessProbe: + httpGet: + path: /healthz + port: healthcheck + initialDelaySeconds: 30 + periodSeconds: 20 + timeoutSeconds: 1 + readinessProbe: + httpGet: + path: /readyz + port: healthcheck + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 1 + extraArgs: + - --migrate-image=ghcr.io/cozystack/cozystack/kamaji:v1.3.0@sha256:8c9af083b60600c0800eb56a2cda75f26007b7272a1cf019140de003bfce1a4d diff --git a/packages/system/keycloak-configure/Makefile b/packages/system/keycloak-configure/Makefile index b9fd5c10..4cd5bd2e 100644 --- a/packages/system/keycloak-configure/Makefile +++ b/packages/system/keycloak-configure/Makefile @@ -1,5 +1,5 @@ export NAME=keycloak-configure export NAMESPACE=cozy-keycloak -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk diff --git a/packages/system/keycloak-configure/templates/configure-kk.yaml b/packages/system/keycloak-configure/templates/configure-kk.yaml index adee11b6..a5683957 100644 --- a/packages/system/keycloak-configure/templates/configure-kk.yaml +++ b/packages/system/keycloak-configure/templates/configure-kk.yaml @@ -1,73 +1,10 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- $extraRedirectUris := splitList "," ((index $cozyConfig.data "extra-keycloak-redirect-uri-for-dashboard") | default "") }} -{{- $rootSaConfigMap := lookup "v1" "ConfigMap" "kube-system" "kube-root-ca.crt" }} -{{- $k8sCa := index $rootSaConfigMap.data "ca.crt" | b64enc }} +{{- $host := index .Values._cluster "root-host" }} +{{- $extraRedirectUris := splitList "," ((index .Values._cluster "extra-keycloak-redirect-uri-for-dashboard") | default "") }} +{{- $k8sCa := index .Values._cluster "kube-root-ca" }} -{{- $existingK8sSecret := lookup "v1" "Secret" .Release.Namespace "k8s-client" }} {{- $existingKubeappsSecret := lookup "v1" "Secret" .Release.Namespace "kubeapps-client" }} {{- $existingAuthConfig := lookup "v1" "Secret" "cozy-dashboard" "kubeapps-auth-config" }} -{{- $cozystackBranding:= lookup "v1" "ConfigMap" "cozy-system" "cozystack-branding" }} - -{{ $k8sClient := "" }} -{{- if $existingK8sSecret }} - {{- $k8sClient = index $existingK8sSecret.data "client-secret-key" | b64dec }} -{{- else }} - {{- $k8sClient = randAlphaNum 32 }} -{{- end }} - -{{ $kubeappsClient := "" }} -{{- if $existingKubeappsSecret }} - {{- $kubeappsClient = index $existingKubeappsSecret.data "client-secret-key" | b64dec }} -{{- else }} - {{- $kubeappsClient = randAlphaNum 32 }} -{{- end }} - -{{ $cookieSecret := "" }} -{{- if $existingAuthConfig }} - {{- $cookieSecret = index $existingAuthConfig.data "cookieSecret" | b64dec }} -{{- else }} - {{- $cookieSecret = randAlphaNum 16 }} -{{- end }} - -{{ $branding := "" }} -{{- if $cozystackBranding }} - {{- $branding = index $cozystackBranding.data "branding" }} -{{- end }} - ---- - -apiVersion: v1 -kind: Secret -metadata: - name: k8s-client - namespace: {{ .Release.Namespace }} -type: Opaque -data: - client-secret-key: {{ $k8sClient | b64enc }} - ---- - -apiVersion: v1 -kind: Secret -metadata: - name: kubeapps-client - namespace: {{ .Release.Namespace }} -type: Opaque -data: - client-secret-key: {{ $kubeappsClient | b64enc }} - ---- - -apiVersion: v1 -kind: Secret -metadata: - name: kubeapps-auth-config - namespace: cozy-dashboard -type: Opaque -data: - cookieSecret: {{ $cookieSecret | b64enc }} - +{{- $brandingConfig := .Values._cluster.branding | default dict }} --- apiVersion: v1.edp.epam.com/v1alpha1 @@ -77,7 +14,8 @@ metadata: namespace: {{ .Release.Namespace }} spec: secret: keycloak-credentials - url: https://keycloak.{{ $host }} + url: http://keycloak-http.cozy-keycloak.svc:8080 + insecureSkipVerify: true --- @@ -89,10 +27,28 @@ metadata: spec: realmName: cozy clusterKeycloakRef: keycloak-cozy - {{- if $branding }} - displayHtmlName: {{ $branding }} - displayName: {{ $branding }} + {{- if $brandingConfig }} + {{- if hasKey $brandingConfig "brandName" }} + displayName: {{ $brandingConfig.brandName }} {{- end }} + {{- if hasKey $brandingConfig "brandHtmlName" }} + displayHtmlName: {{ $brandingConfig.brandHtmlName }} + {{- else if hasKey $brandingConfig "branding" }} + displayHtmlName: {{ $brandingConfig.branding }} + {{- end }} + {{- end }} + {{- with .Values.login }} + login: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.smtp }} + smtp: + {{- toYaml . | nindent 4 }} + {{- end }} + sessions: + ssoSessionSettings: + idleTimeout: 86400 + maxLifespan: 604800 --- @@ -128,23 +84,18 @@ kind: KeycloakClient metadata: name: keycloakclient spec: - serviceAccount: - enabled: true + advancedProtocolMappers: true + clientId: kubernetes + defaultClientScopes: + - groups + name: kubernetes + public: true realmRef: name: keycloakrealm-cozy kind: ClusterKeycloakRealm - secret: $k8s-client:client-secret-key - advancedProtocolMappers: true - authorizationServicesEnabled: true - name: kubernetes - clientId: kubernetes - directAccess: true - public: false webUrl: https://localhost:8000/oauth2/callback webOrigins: - /* - defaultClientScopes: - - groups redirectUris: - http://localhost:18000 - http://localhost:8000 @@ -178,58 +129,6 @@ spec: --- -apiVersion: v1.edp.epam.com/v1 -kind: KeycloakClient -metadata: - name: kubeapps-client -spec: - serviceAccount: - enabled: true - realmRef: - name: keycloakrealm-cozy - kind: ClusterKeycloakRealm - secret: $kubeapps-client:client-secret-key - advancedProtocolMappers: true - authorizationServicesEnabled: true - name: kubeapps - clientId: kubeapps - directAccess: true - public: false - webUrl: "https://dashboard.{{ $host }}" - defaultClientScopes: - - groups - - kubernetes-client - redirectUris: - - "http://dashboard.{{ $host }}/oauth2/callback/*" - {{- range $i, $v := $extraRedirectUris }} - - "{{ $v }}" - {{- end }} - ---- - -apiVersion: v1 -kind: ConfigMap -metadata: - name: kubeapps-auth-config - namespace: cozy-dashboard -data: - values.yaml: | - kubeapps: - authProxy: - resourcesPreset: "none" - enabled: true - provider: "oidc" - clientID: "kubeapps" - clientSecret: {{ $kubeappsClient }} - cookieSecret: {{ $cookieSecret }} - extraFlags: - - --ssl-insecure-skip-verify - - --cookie-secure=false - - --scope=openid email groups - - --oidc-issuer-url=https://keycloak.{{ $host }}/realms/cozy - ---- - apiVersion: v1.edp.epam.com/v1 kind: KeycloakRealmGroup metadata: diff --git a/packages/system/keycloak-configure/templates/delete.yaml b/packages/system/keycloak-configure/templates/delete.yaml new file mode 100644 index 00000000..99abd6e6 --- /dev/null +++ b/packages/system/keycloak-configure/templates/delete.yaml @@ -0,0 +1,135 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-weight": "10" + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed + name: {{ .Release.Name }}-flux-teardown +spec: + template: + spec: + serviceAccountName: {{ .Release.Name }}-flux-teardown + restartPolicy: Never + tolerations: + - key: CriticalAddonsOnly + operator: Exists + - key: node-role.kubernetes.io/control-plane + operator: Exists + effect: "NoSchedule" + containers: + - name: kubectl + image: docker.io/clastix/kubectl:v1.32 + command: + - /bin/sh + - -c + - | + for resource in KeycloakRealmGroup KeycloakClientScope KeycloakClient; do + kubectl get "$resource" -A --no-headers -o custom-columns="NAMESPACE:.metadata.namespace,NAME:.metadata.name" | \ + while read -r namespace name; do + kubectl patch "$resource" "$name" -n "$namespace" --type=merge -p '{"metadata":{"finalizers":[]}}' + done + done + + for resource in ClusterKeycloakRealm ClusterKeycloak; do + kubectl get "$resource" --no-headers -o custom-columns="NAME:.metadata.name" | \ + while read -r name; do + kubectl patch "$resource" "$name" --type=merge -p '{"metadata":{"finalizers":[]}}' + done + done + + kubectl patch hr keycloak-configure -n cozy-system --type=merge -p '{"metadata":{"finalizers":[]}}' + + +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Release.Name }}-flux-teardown + annotations: + helm.sh/hook: pre-delete + helm.sh/hook-delete-policy: before-hook-creation,hook-failed + helm.sh/hook-weight: "0" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + "helm.sh/hook": pre-install,post-install,pre-delete + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed + "helm.sh/hook-weight": "5" + name: {{ .Release.Name }}-flux-teardown +rules: + - apiGroups: + - "v1.edp.epam.com" + resources: + - keycloakrealmgroups + - keycloakclientscopes + - keycloakclients + - clusterkeycloakrealms + - clusterkeycloaks + - keycloakrealms + - keycloakrealmusers + - keycloakrealmroles + - keycloakrealmidentityproviders + - keycloakrealmcomponents + - keycloakauthflows + - keycloaks + verbs: + - get + - list + - delete + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ .Release.Name }}-flux-teardown +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .Release.Name }}-flux-teardown +subjects: + - kind: ServiceAccount + name: {{ .Release.Name }}-flux-teardown + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + annotations: + "helm.sh/hook": pre-install,post-install,pre-delete + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed + "helm.sh/hook-weight": "5" + name: {{ .Release.Name }}-flux-teardown +rules: + - apiGroups: + - "helm.toolkit.fluxcd.io" + resources: + - helmreleases + verbs: + - get + - list + - delete + - watch + - patch + resourceNames: + - {{ .Release.Name }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + annotations: + helm.sh/hook: pre-delete + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation,hook-failed + helm.sh/hook-weight: "5" + name: {{ .Release.Name }}-flux-teardown +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ .Release.Name }}-flux-teardown +subjects: + - kind: ServiceAccount + name: {{ .Release.Name }}-flux-teardown + namespace: {{ .Release.Namespace }} diff --git a/packages/system/keycloak-configure/values.yaml b/packages/system/keycloak-configure/values.yaml new file mode 100644 index 00000000..0b4fa03c --- /dev/null +++ b/packages/system/keycloak-configure/values.yaml @@ -0,0 +1,39 @@ +# login: +# userRegistration: false +# verifyEmail: false +# duplicateEmails: false +# editUsername: false +# emailAsUsername: false +# forgotPassword: false +# loginWithEmail: true +# rememberMe: false + +# smtp: +# template: +# from: "noreply@example.com" +# fromDisplayName: "" +# replyTo: "" +# replyToDisplayName: "" +# envelopeFrom: "" +# connection: +# host: "smtp.example.com" +# port: 587 +# enableSSL: false +# enableStartTLS: true +# authentication: +# username: +# value: "user" +# # secretKeyRef: +# # name: "secret-name" +# # key: "key" +# # configMapKeyRef: +# # name: "configmap-name" +# # key: "key" +# password: +# secretKeyRef: +# name: "smtp-credentials" +# key: "password" +# # value: "plaintext-password" +# # configMapKeyRef: +# # name: "configmap-name" +# # key: "key" diff --git a/packages/system/keycloak-operator/Makefile b/packages/system/keycloak-operator/Makefile index a4f50b67..3386cf18 100644 --- a/packages/system/keycloak-operator/Makefile +++ b/packages/system/keycloak-operator/Makefile @@ -1,8 +1,19 @@ export NAME=keycloak-operator export NAMESPACE=cozy-keycloak -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk + +image: + docker buildx build images/keycloak-operator \ + --tag $(REGISTRY)/keycloak-operator:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/keycloak-operator:latest \ + --cache-to type=inline \ + --metadata-file images/keycloak-operator.json \ + $(BUILDX_ARGS) + TAG="$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/keycloak-operator.json -r)" \ + yq -i '.keycloak-operator.image.tag = strenv(TAG)' values.yaml + rm -f images/keycloak-operator.json update: rm -rf charts diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/Chart.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/Chart.yaml index f9d53963..5bd434ce 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/Chart.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/Chart.yaml @@ -157,30 +157,29 @@ annotations: - apiVersion: v1.edp.epam.com/v1 kind: KeycloakRealmIdentityProvider metadata: - name: instagram-test + name: github-test spec: realm: d2-id-k8s-realm-name - alias: instagram + alias: github authenticateByDefault: false enabled: true firstBrokerLoginFlowAlias: "first broker login" - providerId: "instagram" + providerId: "github" config: clientId: "foo" clientSecret: "bar" - hideOnLoginPage: "true" syncMode: "IMPORT" useJwksUrl: "true" mappers: - name: "test3212" identityProviderMapper: "oidc-hardcoded-role-idp-mapper" - identityProviderAlias: "instagram" + identityProviderAlias: "github" config: role: "role-tr" syncMode: "INHERIT" - name: "test-33221" identityProviderMapper: "hardcoded-attribute-idp-mapper" - identityProviderAlias: "instagram" + identityProviderAlias: "github" config: attribute: "foo" "attribute.value": "bar" @@ -272,8 +271,8 @@ annotations: secret: secret-name-in-operator-ns url: https://keycloak.example.com artifacthub.io/images: | - - name: keycloak-operator:1.25.0 - image: epamedp/keycloak-operator:1.25.0 + - name: keycloak-operator:1.32.0 + image: epamedp/keycloak-operator:1.32.0 artifacthub.io/license: Apache-2.0 artifacthub.io/links: | - name: KubeRocketCI Documentation @@ -283,7 +282,7 @@ annotations: artifacthub.io/operator: "true" artifacthub.io/operatorCapabilities: Deep Insights apiVersion: v2 -appVersion: 1.25.0 +appVersion: 1.32.0 description: A Helm chart for KubeRocketCI Keycloak Operator home: https://docs.kuberocketci.io/ icon: https://docs.kuberocketci.io/img/logo.svg @@ -308,4 +307,4 @@ name: keycloak-operator sources: - https://github.com/epam/edp-keycloak-operator type: application -version: 1.25.0 +version: 1.32.0 diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/README.md b/packages/system/keycloak-operator/charts/keycloak-operator/README.md index abd23443..61355b59 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/README.md +++ b/packages/system/keycloak-operator/charts/keycloak-operator/README.md @@ -1,6 +1,6 @@ # keycloak-operator -![Version: 1.25.0](https://img.shields.io/badge/Version-1.25.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.25.0](https://img.shields.io/badge/AppVersion-1.25.0-informational?style=flat-square) +![Version: 1.32.0](https://img.shields.io/badge/Version-1.32.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.32.0](https://img.shields.io/badge/AppVersion-1.32.0-informational?style=flat-square) A Helm chart for KubeRocketCI Keycloak Operator @@ -16,6 +16,7 @@ _**NOTE:** Operator is platform-independent, which is why there is a unified ins 1. Linux machine or Windows Subsystem for Linux instance with [Helm 3](https://helm.sh/docs/intro/install/) installed; 2. Cluster admin access to the cluster; +3. [cert-manager](https://cert-manager.io/docs/installation/) installed in the cluster (required for webhook functionality, can be disabled via `enableWebhooks: false`); ## Installation Using Helm Chart @@ -32,7 +33,7 @@ To install the Keycloak Operator, follow the steps below: ```bash helm search repo epamedp/keycloak-operator -l NAME CHART VERSION APP VERSION DESCRIPTION - epamedp/keycloak-operator 1.24.0 1.24.0 A Helm chart for KRCI Keycloak Operator + epamedp/keycloak-operator 1.31.0 1.31.0 A Helm chart for KRCI Keycloak Operator ``` _**NOTE:** It is highly recommended to use the latest stable version._ @@ -129,14 +130,21 @@ Development versions are also available from the [snapshot helm chart repository |-----|------|---------|-------------| | affinity | object | `{}` | Affinity for pod assignment | | annotations | object | `{}` | Annotations to be added to the Deployment | +| clusterDomain | string | `"cluster.local"` | Cluster domain for constructing service DNS names | | clusterReconciliationEnabled | bool | `false` | If clusterReconciliationEnabled is true, the operator reconciles all Keycloak instances in the cluster; otherwise, it only reconciles instances in the same namespace by default, and cluster-scoped resources are ignored. | +| containerSecurityContext | object | `{"allowPrivilegeEscalation":false}` | Container Security Context Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ | +| enableOwnerRef | bool | `true` | If set to true, the operator will set the owner reference for all resources that have Keycloak or KeycloakRealm as reference. This is legacy behavior and not recommended for use. In the future, this will be set to false by default. | +| enableWebhooks | bool | `true` | If set to true, enables webhook resources (ValidatingWebhookConfiguration, Service, and Certificate). Webhooks require cert-manager to be installed in the cluster. | | extraVolumeMounts | list | `[]` | Additional volumeMounts to be added to the container | | extraVolumes | list | `[]` | Additional volumes to be added to the pod | +| image.registry | string | `""` | KubeRocketCI keycloak-operator Docker image registry. | | image.repository | string | `"epamedp/keycloak-operator"` | KubeRocketCI keycloak-operator Docker image name. The released image can be found on [Dockerhub](https://hub.docker.com/r/epamedp/keycloak-operator) | | image.tag | string | `nil` | KubeRocketCI keycloak-operator Docker image tag. The released image can be found on [Dockerhub](https://hub.docker.com/r/epamedp/keycloak-operator/tags) | | imagePullPolicy | string | `"IfNotPresent"` | If defined, a imagePullPolicy applied to the deployment | | imagePullSecrets | list | `[]` | If defined, imagePullSecrets are applied to deployment | | name | string | `"keycloak-operator"` | Application name string | | nodeSelector | object | `{}` | Node labels for pod assignment | +| podLabels | object | `{}` | Labels to be added to the pod | | resources | object | `{"limits":{"memory":"192Mi"},"requests":{"cpu":"50m","memory":"64Mi"}}` | Resource limits and requests for the pod | +| securityContext | object | `{"runAsNonRoot":true}` | Deployment Security Context Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ | | tolerations | list | `[]` | Node tolerations for server scheduling to nodes with taints | diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/README.md.gotmpl b/packages/system/keycloak-operator/charts/keycloak-operator/README.md.gotmpl index 9dffecab..3b67933b 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/README.md.gotmpl +++ b/packages/system/keycloak-operator/charts/keycloak-operator/README.md.gotmpl @@ -17,6 +17,7 @@ _**NOTE:** Operator is platform-independent, which is why there is a unified ins 1. Linux machine or Windows Subsystem for Linux instance with [Helm 3](https://helm.sh/docs/intro/install/) installed; 2. Cluster admin access to the cluster; +3. [cert-manager](https://cert-manager.io/docs/installation/) installed in the cluster (required for webhook functionality, can be disabled via `enableWebhooks: false`); ## Installation Using Helm Chart @@ -33,7 +34,7 @@ To install the Keycloak Operator, follow the steps below: ```bash helm search repo epamedp/keycloak-operator -l NAME CHART VERSION APP VERSION DESCRIPTION - epamedp/keycloak-operator 1.24.0 1.24.0 A Helm chart for KRCI Keycloak Operator + epamedp/keycloak-operator 1.31.0 1.31.0 A Helm chart for KRCI Keycloak Operator ``` _**NOTE:** It is highly recommended to use the latest stable version._ diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/clusterkeycloakrealm.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/clusterkeycloakrealm.yaml index 20d7c6f4..287938b4 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/clusterkeycloakrealm.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/clusterkeycloakrealm.yaml @@ -7,3 +7,25 @@ spec: realmName: realm-sample1234 authenticationFlows: browserFlow: browserFlow-sample + login: + userRegistration: true + forgotPassword: true + rememberMe: true + emailAsUsername: false + loginWithEmail: true + duplicateEmails: false + verifyEmail: true + editUsername: false + sessions: + ssoLoginSettings: + accessCodeLifespanLogin: 1800 # 30 minutes + accessCodeLifespanUserAction: 300 # 5 minutes + ssoSessionSettings: + idleTimeout: 1800 # 30 minutes + idleTimeoutRememberMe: 604800 # 7 days + maxLifespan: 36000 # 10 hours + maxLifespanRememberMe: 2592000 # 30 days + ssoOfflineSessionSettings: + idleTimeout: 2592000 # 30 days + maxLifespan: 5184000 # 60 days + maxLifespanEnabled: true diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakclient.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakclient.yaml index fdd9d018..97dde9c2 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakclient.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakclient.yaml @@ -14,11 +14,16 @@ spec: webUrl: https://argocd.example.com adminUrl: https://admin.example.com homeUrl: /home/ - defaultClientScopes: - - groups redirectUris: - /url1/* - /url2/* + clientRolesV2: + - name: roleA + description: "Role A" + associatedClientRoles: + - roleB + - name: roleB + description: "Role B" --- diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakclientscope.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakclientscope.yaml index d19a317c..5b4c2d13 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakclientscope.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakclientscope.yaml @@ -8,6 +8,7 @@ spec: name: keycloakrealm-sample kind: KeycloakRealm description: "Group Membership" + type: default protocol: openid-connect protocolMappers: - name: groups diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakorganizationorganization.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakorganizationorganization.yaml new file mode 100644 index 00000000..506da761 --- /dev/null +++ b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakorganizationorganization.yaml @@ -0,0 +1,45 @@ +# Organization with identity provider configuration +apiVersion: v1.edp.epam.com/v1alpha1 +kind: KeycloakOrganization +metadata: + name: test-keycloak-organization + namespace: default +spec: + name: "Test Organization" + alias: "test-org" + domains: + - "example.com" + - "test.com" + redirectUrl: "https://example.com/redirect" + description: "Test organization" + attributes: + department: + - "engineering" + - "qa" + location: + - "us-east" + identityProviders: + - alias: "test-org-idp" + realmRef: + kind: KeycloakRealm + name: test-org-realm + +--- + +apiVersion: v1.edp.epam.com/v1 +kind: KeycloakRealmIdentityProvider +metadata: + name: test-org-idp + namespace: default +spec: + alias: "test-org-idp" + enabled: true + providerId: "github" + realmRef: + kind: KeycloakRealm + name: test-org-realm + config: + clientId: "test-org-client-id" + clientSecret: "test-org-client-secret" + kc.org.domain: "example.com" + kc.org.broker.redirect.mode.email-matches: "true" \ No newline at end of file diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealm.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealm.yaml index 4f6c080a..bd8771e5 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealm.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealm.yaml @@ -3,7 +3,6 @@ kind: KeycloakRealm metadata: name: keycloakrealm-sample spec: - id: bfebeff6-ac63-4b46-a1f3-37df5099a9c4 realmName: realm-sample keycloakRef: name: keycloak-sample @@ -16,6 +15,7 @@ spec: realmEventConfig: adminEventsDetailsEnabled: false adminEventsEnabled: true + adminEventsExpiration: 544 enabledEventTypes: - UPDATE_CONSENT_ERROR - CLIENT_LOGIN @@ -32,6 +32,15 @@ spec: refreshTokenMaxReuse: 300 revokeRefreshToken: true defaultSignatureAlgorithm: RS256 + login: + userRegistration: true + forgotPassword: true + rememberMe: true + emailAsUsername: true + loginWithEmail: true + duplicateEmails: false + verifyEmail: true + editUsername: true userProfileConfig: unmanagedAttributePolicy: "ENABLED" attributes: @@ -94,3 +103,16 @@ spec: key: "password" username: value: "username" + sessions: + ssoLoginSettings: + accessCodeLifespanLogin: 1800 # 30 minutes + accessCodeLifespanUserAction: 300 # 5 minutes + ssoSessionSettings: + idleTimeout: 1800 # 30 minutes + idleTimeoutRememberMe: 604800 # 7 days + maxLifespan: 36000 # 10 hours + maxLifespanRememberMe: 2592000 # 30 days + ssoOfflineSessionSettings: + idleTimeout: 2592000 # 30 days + maxLifespan: 5184000 # 60 days + maxLifespanEnabled: true diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmgroup.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmgroup.yaml index 59333660..0f0ded93 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmgroup.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmgroup.yaml @@ -7,3 +7,29 @@ spec: name: keycloakrealm-sample kind: KeycloakRealm name: ArgoCDAdmins +--- +# Example of a child group using parentGroup +apiVersion: v1.edp.epam.com/v1 +kind: KeycloakRealmGroup +metadata: + name: keycloakrealmgroup-child-sample +spec: + realmRef: + name: keycloakrealm-sample + kind: KeycloakRealm + name: ArgoCDDevelopers + parentGroup: + name: keycloakrealmgroup-sample + +--- +apiVersion: v1.edp.epam.com/v1 +kind: KeycloakRealmGroup +metadata: + name: keycloakrealmgroup-child-sample2 +spec: + realmRef: + name: keycloakrealm-sample + kind: KeycloakRealm + name: ArgoCDGoDevs + parentGroup: + name: keycloakrealmgroup-child-sample \ No newline at end of file diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmidentityprovider.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmidentityprovider.yaml index a66a628c..812ed081 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmidentityprovider.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmidentityprovider.yaml @@ -5,23 +5,33 @@ metadata: spec: realmRef: kind: KeycloakRealm - name: realm - alias: instagram + name: keycloakrealm-sample + alias: github authenticateByDefault: false enabled: true firstBrokerLoginFlowAlias: "first broker login" - providerId: "instagram" + postBrokerLoginFlowAlias: "browser" + providerId: "github" config: clientId: "foo" - clientSecret: "$secretName:secretKey" - hideOnLoginPage: "true" + clientSecret: "$test-idp-secret:secret" syncMode: "IMPORT" useJwksUrl: "true" mappers: - name: "test-33221" identityProviderMapper: "hardcoded-attribute-idp-mapper" - identityProviderAlias: "instagram" + identityProviderAlias: "github" config: attribute: "foo" "attribute.value": "bar" syncMode: "IMPORT" + +--- + +apiVersion: v1 +kind: Secret +metadata: + name: test-idp-secret +type: Opaque +data: + secret: "c2VjcmV0" # base64 encoded value of "secret" \ No newline at end of file diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmuser.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmuser.yaml index 1847d992..97289a66 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmuser.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmuser.yaml @@ -13,8 +13,21 @@ spec: enabled: true emailVerified: true keepResource: true + passwordSecret: + key: password + name: keycloakrealmuser-sample-password + temporary: true requiredUserActions: - - UPDATE_PASSWORD - attributes: - foo: "bar" - baz: "jazz" + - UPDATE_PROFILE + attributesV2: + department: ["IT"] + location: ["Winterfell"] + +--- +apiVersion: v1 +kind: Secret +metadata: + name: keycloakrealmuser-sample-password +type: Opaque +data: + password: "U29tZVBhc3N3b3JkMTIzIQ==" # SomePassword123! \ No newline at end of file diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmuser_password.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmuser_password.yaml index daf3f6a7..ea99e794 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmuser_password.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/_crd_examples/keycloakrealmuser_password.yaml @@ -19,3 +19,5 @@ spec: passwordSecret: name: existing-k8s-secret key: key-which-contains-password + identityProviders: + - provider-alias diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_clusterkeycloakrealms.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_clusterkeycloakrealms.yaml index f2d8e337..b3a363c8 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_clusterkeycloakrealms.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_clusterkeycloakrealms.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.18.0 name: clusterkeycloakrealms.v1.edp.epam.com spec: group: v1.edp.epam.com @@ -97,6 +97,57 @@ spec: nullable: true type: boolean type: object + login: + description: Login settings for the realm. + nullable: true + properties: + duplicateEmails: + default: false + description: DuplicateEmails allows multiple users to have the + same email address. + type: boolean + editUsername: + default: false + description: EditUsername allows to edit username. + type: boolean + emailAsUsername: + default: false + description: EmailAsUsername allows users to set email as username. + type: boolean + forgotPassword: + default: false + description: ForgotPassword shows a link on the login page for + users who have forgotten their credentials. + type: boolean + loginWithEmail: + default: true + description: LoginWithEmail allows users to log in with their + email address. + type: boolean + rememberMe: + default: false + description: RememberMe shows checkbox on the login page to allow + the user to remain logged in between browser restarts until + the session expires. + type: boolean + userRegistration: + default: false + description: UserRegistration enables/disables the registration + page. A link for registration will show on the login page too. + type: boolean + verifyEmail: + default: false + description: VerifyEmail requires user to verify their email address + after initial login or after address changes are submitted. + type: boolean + type: object + organizationsEnabled: + default: false + description: |- + OrganizationsEnabled enables Keycloak Organizations feature for this realm. + When enabled, this realm can support Organization resources for multi-tenant scenarios, + identity provider groupings, and domain-based user routing. + type: boolean passwordPolicy: description: PasswordPolicies is a list of password policies to apply to the realm. @@ -153,6 +204,80 @@ spec: realmName: description: RealmName specifies the name of the realm. type: string + sessions: + description: Sessions defines the session settings for the realm. + properties: + ssoLoginSettings: + description: SSOLoginSettings defines the SSO login settings for + the realm. + properties: + accessCodeLifespanLogin: + default: 1800 + description: AccessCodeLifespanLogin represents the max time + a user has to complete a login. This is recommended to be + relatively long, such as 30 minutes or more. + type: integer + accessCodeLifespanUserAction: + default: 300 + description: AccessCodeLifespanUserAction represents the max + time a user has to complete login related actions like update + password or configure totp. This is recommended to be relatively + long, such as 5 minutes or more. + type: integer + type: object + ssoOfflineSessionSettings: + description: SSOOfflineSessionSettings defines the SSO offline + session settings for the realm. + properties: + idleTimeout: + default: 2592000 + description: |- + IdleTimeout represents the time an offline session is allowed to be idle before it expires. + You need to use offline token to refresh at least once within this period; otherwise offline session will expire. + type: integer + maxLifespan: + default: 5184000 + description: MaxLifespan represents the max time before an + offline session is expired regardless of activity. + type: integer + maxLifespanEnabled: + default: false + description: MaxLifespanEnabled enables the offline session + maximum lifetime. + type: boolean + type: object + ssoSessionSettings: + description: SSOSessionSettings defines the SSO session settings + for the realm. + properties: + idleTimeout: + default: 1800 + description: |- + IdleTimeout represents the time a session is allowed to be idle before it expires. + Tokens and browser sessions are invalidated when a session is expired. + type: integer + idleTimeoutRememberMe: + default: 0 + description: |- + IdleTimeoutRememberMe represents the time a session is allowed to be idle before it expires. + Tokens and browser sessions are invalidated when a session is expired. + If not set it uses the standard ssoSessionIdle value. + type: integer + maxLifespan: + default: 36000 + description: |- + MaxLifespan represents the max time before a session is expired. + Tokens and browser sessions are invalidated when a session is expired. + type: integer + maxLifespanRememberMe: + default: 0 + description: |- + MaxLifespanRememberMe represents the max time before a session is expired when a user has set the remember me option. + Tokens and browser sessions are invalidated when a session is expired. + If not set it uses the standard ssoSessionMax value. + type: integer + type: object + type: object smtp: description: Smtp is the configuration for email in the realm. nullable: true @@ -174,10 +299,13 @@ spec: description: The key to select. type: string name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string required: - key @@ -190,10 +318,13 @@ spec: description: The key of the secret to select from. type: string name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string required: - key @@ -210,10 +341,13 @@ spec: description: The key to select. type: string name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string required: - key @@ -226,10 +360,13 @@ spec: description: The key of the secret to select from. type: string name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string required: - key diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_clusterkeycloaks.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_clusterkeycloaks.yaml index 45628ebf..971a88b5 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_clusterkeycloaks.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_clusterkeycloaks.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.18.0 name: clusterkeycloaks.v1.edp.epam.com spec: group: v1.edp.epam.com @@ -66,10 +66,13 @@ spec: description: The key to select. type: string name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string required: - key @@ -82,10 +85,13 @@ spec: description: The key of the secret to select from. type: string name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string required: - key diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakauthflows.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakauthflows.yaml index 7ac30a14..7a2cca34 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakauthflows.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakauthflows.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.18.0 name: keycloakauthflows.v1.edp.epam.com spec: group: v1.edp.epam.com @@ -15,7 +15,7 @@ spec: scope: Namespaced versions: - additionalPrinterColumns: - - description: Reconcilation status + - description: Reconciliation status jsonPath: .status.value name: Status type: string @@ -109,15 +109,11 @@ spec: description: ProviderID for root auth flow and provider for child auth flows. type: string - realm: - description: |- - Deprecated: use RealmRef instead. - Realm is name of KeycloakRealm custom resource. - type: string realmRef: description: RealmRef is reference to Realm custom resource. properties: kind: + default: KeycloakRealm description: Kind specifies the kind of the Keycloak resource. enum: - KeycloakRealm @@ -126,6 +122,8 @@ spec: name: description: Name specifies the name of the Keycloak resource. type: string + required: + - name type: object topLevel: description: TopLevel is true if this is root auth flow. @@ -134,6 +132,7 @@ spec: - alias - builtIn - providerId + - realmRef - topLevel type: object status: diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakclients.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakclients.yaml index c79d8376..a1505689 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakclients.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakclients.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.18.0 name: keycloakclients.v1.edp.epam.com spec: group: v1.edp.epam.com @@ -15,7 +15,7 @@ spec: scope: Namespaced versions: - additionalPrinterColumns: - - description: Reconcilation status + - description: Reconciliation status jsonPath: .status.value name: Status type: string @@ -45,8 +45,10 @@ spec: description: KeycloakClientSpec defines the desired state of KeycloakClient. properties: adminFineGrainedPermissionsEnabled: - description: AdminFineGrainedPermissionsEnabled enable/disable fine-grained - admin permissions for a client. + description: |- + AdminFineGrainedPermissionsEnabled enable/disable fine-grained admin permissions for a client. + Feature flag admin-fine-grained-authz:v1 should be enabled in Keycloak server. + Important: FGAP:V1 Keycloak feature remains in preview and may be deprecated and removed in a future releases. type: boolean adminUrl: description: |- @@ -222,6 +224,8 @@ spec: within an access token or ID token representing the identity asking permissions. If not defined, user's groups are obtained from your realm configuration. type: string + required: + - groups type: object logic: default: POSITIVE @@ -419,12 +423,36 @@ spec: URI and tokens. type: string clientRoles: - description: ClientRoles is a list of client roles names assigned - to client. + description: |- + ClientRoles is a list of client roles names assigned to client. + Deprecated: Use ClientRolesV2 instead. items: type: string nullable: true type: array + clientRolesV2: + description: ClientRolesV2 is a list of client roles assigned to client. + items: + properties: + associatedClientRoles: + description: |- + AssociatedClientRoles is a list of client roles names associated with the current role. + These roles won't be created automatically, user should specify them separately in clientRolesV2. + items: + type: string + nullable: true + type: array + description: + description: Description is a client role description. + type: string + name: + description: Name is a client role name. + type: string + required: + - name + type: object + nullable: true + type: array consentRequired: description: ConsentRequired is a flag to enable consent. type: boolean @@ -524,6 +552,7 @@ spec: description: RealmRef is reference to Realm custom resource. properties: kind: + default: KeycloakRealm description: Kind specifies the kind of the Keycloak resource. enum: - KeycloakRealm @@ -532,6 +561,8 @@ spec: name: description: Name specifies the name of the Keycloak resource. type: string + required: + - name type: object realmRoles: description: RealmRoles is a list of realm roles assigned to client. @@ -582,7 +613,19 @@ spec: attributes: additionalProperties: type: string - description: Attributes is a map of service account attributes. + description: |- + Attributes is a map of service account attributes. + Deprecated: Use AttributesV2 instead. + nullable: true + type: object + attributesV2: + additionalProperties: + items: + type: string + type: array + description: |- + AttributesV2 is a map of service account attributes. + Each attribute can have multiple values. nullable: true type: object clientRoles: @@ -595,7 +638,7 @@ spec: type: string roles: description: Roles is a list of client roles names assigned - to service account. + to user. items: type: string nullable: true @@ -608,6 +651,12 @@ spec: enabled: description: Enabled is a flag to enable service account. type: boolean + groups: + description: Groups is a list of groups assigned to service account + items: + type: string + nullable: true + type: array realmRoles: description: RealmRoles is a list of realm roles assigned to service account. @@ -623,13 +672,6 @@ spec: surrogateAuthRequired: description: SurrogateAuthRequired is a flag to enable surrogate auth. type: boolean - targetRealm: - description: |- - Deprecated: use RealmRef instead. - TargetRealm is a realm name where client will be created. - It has higher priority than RealmRef for backward compatibility. - If both TargetRealm and RealmRef are specified, TargetRealm will be used for client creation. - type: string webOrigins: description: |- WebOrigins is a list of allowed CORS origins. @@ -647,12 +689,72 @@ spec: type: string required: - clientId + - realmRef type: object status: description: KeycloakClientStatus defines the observed state of KeycloakClient. properties: clientId: type: string + conditions: + description: Conditions represent the latest available observations + of an object's state. + 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 + nullable: true + type: array failureCount: format: int64 type: integer diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakclientscopes.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakclientscopes.yaml index 26e9876b..a5329ecb 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakclientscopes.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakclientscopes.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.18.0 name: keycloakclientscopes.v1.edp.epam.com spec: group: v1.edp.epam.com @@ -15,7 +15,7 @@ spec: scope: Namespaced versions: - additionalPrinterColumns: - - description: Reconcilation status + - description: Reconciliation status jsonPath: .status.value name: Status type: string @@ -52,7 +52,9 @@ spec: nullable: true type: object default: - description: Default is a flag to set client scope as default. + description: |- + Default is a flag to set client scope as default. + Deprecated: Use Type: default instead. type: boolean description: description: Description is a description of client scope. @@ -87,15 +89,11 @@ spec: type: object nullable: true type: array - realm: - description: |- - Deprecated: use RealmRef instead. - Realm is name of KeycloakRealm custom resource. - type: string realmRef: description: RealmRef is reference to Realm custom resource. properties: kind: + default: KeycloakRealm description: Kind specifies the kind of the Keycloak resource. enum: - KeycloakRealm @@ -104,10 +102,25 @@ spec: name: description: Name specifies the name of the Keycloak resource. type: string + required: + - name type: object + type: + default: none + description: |- + Type of the client scope. + If set to "default", the client scope is assigned to all clients by default. + If set to "optional", the client scope can be assigned to clients on demand. + If set to "none", the client scope is not assigned to any clients by default. + enum: + - default + - optional + - none + type: string required: - name - protocol + - realmRef type: object status: description: KeycloakClientScopeStatus defines the observed state of KeycloakClientScope. diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakorganizations.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakorganizations.yaml new file mode 100644 index 00000000..2ca7c1de --- /dev/null +++ b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakorganizations.yaml @@ -0,0 +1,149 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: keycloakorganizations.v1.edp.epam.com +spec: + group: v1.edp.epam.com + names: + kind: KeycloakOrganization + listKind: KeycloakOrganizationList + plural: keycloakorganizations + singular: keycloakorganization + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Reconciliation status + jsonPath: .status.value + name: Status + type: string + - description: Keycloak organization ID + jsonPath: .status.organizationId + name: Organization ID + type: string + - description: Keycloak realm name + jsonPath: .spec.realmName + name: Realm + type: string + - description: Keycloak instance name + jsonPath: .spec.keycloakRef.name + name: Keycloak + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: KeycloakOrganization is the Schema for the organizations API. + 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: KeycloakOrganizationSpec defines the desired state of Organization. + properties: + alias: + description: |- + Alias is the unique alias for the organization. + The alias should be unique across Organizations. + type: string + attributes: + additionalProperties: + items: + type: string + type: array + description: Attributes is a map of custom attributes for the organization. + nullable: true + type: object + description: + description: Description is an optional description of the organization. + type: string + domains: + description: |- + Domains is a list of email domains associated with the organization. + Each domain should be unique across Organizations. + items: + type: string + minItems: 1 + type: array + identityProviders: + description: |- + IdentityProviders is a list of identity providers associated with the organization. + One identity provider can't be assigned to multiple organizations. + items: + description: OrgIdentityProvider defines an identity provider for + an organization. + properties: + alias: + description: Alias is the unique identifier for the identity + provider within the organization. + type: string + required: + - alias + type: object + nullable: true + type: array + name: + description: |- + Name is the unique name of the organization. + The name should be unique across Organizations. + type: string + realmRef: + description: RealmRef is reference to Realm custom resource. + properties: + kind: + default: KeycloakRealm + description: Kind specifies the kind of the Keycloak resource. + enum: + - KeycloakRealm + - ClusterKeycloakRealm + type: string + name: + description: Name specifies the name of the Keycloak resource. + type: string + required: + - name + type: object + redirectUrl: + description: RedirectURL is the optional redirect URL for the organization. + type: string + required: + - alias + - domains + - name + - realmRef + type: object + status: + description: KeycloakOrganizationStatus defines the observed state of + Organization. + properties: + error: + description: Error is the error message if the reconciliation failed. + type: string + organizationId: + description: OrganizationID is the unique identifier of the organization + in Keycloak. + type: string + value: + description: Value contains the current reconciliation status. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmcomponents.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmcomponents.yaml index 52129b3a..c73c2b63 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmcomponents.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmcomponents.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.18.0 name: keycloakrealmcomponents.v1.edp.epam.com spec: group: v1.edp.epam.com @@ -15,7 +15,7 @@ spec: scope: Namespaced versions: - additionalPrinterColumns: - - description: Reconcilation status + - description: Reconciliation status jsonPath: .status.value name: Status type: string @@ -90,15 +90,11 @@ spec: providerType: description: ProviderType is a provider type of component. type: string - realm: - description: |- - Deprecated: use RealmRef instead. - Realm is name of KeycloakRealm custom resource. - type: string realmRef: description: RealmRef is reference to Realm custom resource. properties: kind: + default: KeycloakRealm description: Kind specifies the kind of the Keycloak resource. enum: - KeycloakRealm @@ -107,11 +103,14 @@ spec: name: description: Name specifies the name of the Keycloak resource. type: string + required: + - name type: object required: - name - providerId - providerType + - realmRef type: object status: description: KeycloakComponentStatus defines the observed state of KeycloakRealmComponent. diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmgroups.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmgroups.yaml index a8d3dee6..2eb3f1d2 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmgroups.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmgroups.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.18.0 name: keycloakrealmgroups.v1.edp.epam.com spec: group: v1.edp.epam.com @@ -15,7 +15,7 @@ spec: scope: Namespaced versions: - additionalPrinterColumns: - - description: Reconcilation status + - description: Reconciliation status jsonPath: .status.value name: Status type: string @@ -67,7 +67,7 @@ spec: type: string roles: description: Roles is a list of client roles names assigned - to service account. + to user. items: type: string nullable: true @@ -80,18 +80,28 @@ spec: name: description: Name of keycloak group. type: string + parentGroup: + description: |- + ParentGroup is a reference to a parent KeycloakRealmGroup custom resource. + If specified, this group will be created as a child group of the referenced parent. + The parent KeycloakRealmGroup must exist in the same namespace. + nullable: true + properties: + name: + description: Name specifies the name of the KeycloakRealmGroup + custom resource. + type: string + required: + - name + type: object path: description: Path is a group path. type: string - realm: - description: |- - Deprecated: use RealmRef instead. - Realm is name of KeycloakRealm custom resource. - type: string realmRef: description: RealmRef is reference to Realm custom resource. properties: kind: + default: KeycloakRealm description: Kind specifies the kind of the Keycloak resource. enum: - KeycloakRealm @@ -100,6 +110,8 @@ spec: name: description: Name specifies the name of the Keycloak resource. type: string + required: + - name type: object realmRoles: description: RealmRoles is a list of realm roles assigned to group. @@ -108,13 +120,16 @@ spec: nullable: true type: array subGroups: - description: SubGroups is a list of subgroups assigned to group. + description: |- + SubGroups is a list of subgroups assigned to group. + Deprecated: This filed doesn't allow to fully support child groups. Use ParentGroup approach instead. items: type: string nullable: true type: array required: - name + - realmRef type: object status: description: KeycloakRealmGroupStatus defines the observed state of KeycloakRealmGroup. diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmidentityproviders.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmidentityproviders.yaml index b779f5b1..ceaf14de 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmidentityproviders.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmidentityproviders.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.18.0 name: keycloakrealmidentityproviders.v1.edp.epam.com spec: group: v1.edp.epam.com @@ -15,7 +15,7 @@ spec: scope: Namespaced versions: - additionalPrinterColumns: - - description: Reconcilation status + - description: Reconciliation status jsonPath: .status.value name: Status type: string @@ -50,6 +50,12 @@ spec: description: AddReadTokenRoleOnCreate is a flag to add read token role on create. type: boolean + adminFineGrainedPermissionsEnabled: + description: |- + AdminFineGrainedPermissionsEnabled enable/disable fine-grained admin permissions for an identity provider. + Feature flag admin-fine-grained-authz:v1 should be enabled in Keycloak server. + Important: FGAP:V1 Keycloak feature remains in preview and may be deprecated and removed in a future releases. + type: boolean alias: description: Alias is a alias of identity provider. type: string @@ -102,18 +108,38 @@ spec: type: object nullable: true type: array + permission: + description: Permission is a identity provider permissions configuration + nullable: true + properties: + scopePermissions: + description: ScopePermissions mapping of scope and the policies + attached + items: + properties: + name: + type: string + policies: + items: + type: string + type: array + required: + - name + type: object + type: array + type: object + postBrokerLoginFlowAlias: + description: PostBrokerLoginFlowAlias is a post broker login flow + alias. + type: string providerId: description: ProviderID is a provider ID of identity provider. type: string - realm: - description: |- - Deprecated: use RealmRef instead. - Realm is name of KeycloakRealm custom resource. - type: string realmRef: description: RealmRef is reference to Realm custom resource. properties: kind: + default: KeycloakRealm description: Kind specifies the kind of the Keycloak resource. enum: - KeycloakRealm @@ -122,6 +148,8 @@ spec: name: description: Name specifies the name of the Keycloak resource. type: string + required: + - name type: object storeToken: description: StoreToken is a flag to store token. @@ -134,6 +162,7 @@ spec: - config - enabled - providerId + - realmRef type: object status: description: KeycloakRealmIdentityProviderStatus defines the observed diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmrolebatches.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmrolebatches.yaml index b691a407..aa926c6f 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmrolebatches.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmrolebatches.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.18.0 name: keycloakrealmrolebatches.v1.edp.epam.com spec: group: v1.edp.epam.com @@ -15,7 +15,7 @@ spec: scope: Namespaced versions: - additionalPrinterColumns: - - description: Reconcilation status + - description: Reconciliation status jsonPath: .status.value name: Status type: string @@ -44,15 +44,11 @@ spec: spec: description: KeycloakRealmRoleBatchSpec defines the desired state of KeycloakRealmRoleBatch. properties: - realm: - description: |- - Deprecated: use RealmRef instead. - Realm is name of KeycloakRealm custom resource. - type: string realmRef: description: RealmRef is reference to Realm custom resource. properties: kind: + default: KeycloakRealm description: Kind specifies the kind of the Keycloak resource. enum: - KeycloakRealm @@ -61,6 +57,8 @@ spec: name: description: Name specifies the name of the Keycloak resource. type: string + required: + - name type: object roles: description: Roles is a list of roles to be created. @@ -104,6 +102,7 @@ spec: type: object type: array required: + - realmRef - roles type: object status: diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmroles.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmroles.yaml index 20adde93..1ed11331 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmroles.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmroles.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.18.0 name: keycloakrealmroles.v1.edp.epam.com spec: group: v1.edp.epam.com @@ -15,7 +15,7 @@ spec: scope: Namespaced versions: - additionalPrinterColumns: - - description: Reconcilation status + - description: Reconciliation status jsonPath: .status.value name: Status type: string @@ -98,15 +98,11 @@ spec: name: description: Name of keycloak role. type: string - realm: - description: |- - Deprecated: use RealmRef instead. - Realm is name of KeycloakRealm custom resource. - type: string realmRef: description: RealmRef is reference to Realm custom resource. properties: kind: + default: KeycloakRealm description: Kind specifies the kind of the Keycloak resource. enum: - KeycloakRealm @@ -115,9 +111,12 @@ spec: name: description: Name specifies the name of the Keycloak resource. type: string + required: + - name type: object required: - name + - realmRef type: object status: description: KeycloakRealmRoleStatus defines the observed state of KeycloakRealmRole. diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealms.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealms.yaml index 69523264..312a6055 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealms.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealms.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.18.0 name: keycloakrealms.v1.edp.epam.com spec: group: v1.edp.epam.com @@ -19,7 +19,7 @@ spec: jsonPath: .status.available name: Available type: boolean - - description: Reconcilation status + - description: Reconciliation status jsonPath: .status.value name: Status type: string @@ -83,16 +83,11 @@ spec: description: ID is the ID of the realm. nullable: true type: string - keycloakOwner: - description: |- - Deprecated: use KeycloakRef instead. - KeycloakOwner specifies the name of the Keycloak instance that owns the realm. - nullable: true - type: string keycloakRef: description: KeycloakRef is reference to Keycloak custom resource. properties: kind: + default: Keycloak description: Kind specifies the kind of the Keycloak resource. enum: - Keycloak @@ -101,7 +96,60 @@ spec: name: description: Name specifies the name of the Keycloak resource. type: string + required: + - name type: object + login: + description: Login settings for the realm. + nullable: true + properties: + duplicateEmails: + default: false + description: DuplicateEmails allows multiple users to have the + same email address. + type: boolean + editUsername: + default: false + description: EditUsername allows to edit username. + type: boolean + emailAsUsername: + default: false + description: EmailAsUsername allows users to set email as username. + type: boolean + forgotPassword: + default: false + description: ForgotPassword shows a link on the login page for + users who have forgotten their credentials. + type: boolean + loginWithEmail: + default: true + description: LoginWithEmail allows users to log in with their + email address. + type: boolean + rememberMe: + default: false + description: RememberMe shows checkbox on the login page to allow + the user to remain logged in between browser restarts until + the session expires. + type: boolean + userRegistration: + default: false + description: UserRegistration enables/disables the registration + page. A link for registration will show on the login page too. + type: boolean + verifyEmail: + default: false + description: VerifyEmail requires user to verify their email address + after initial login or after address changes are submitted. + type: boolean + type: object + organizationsEnabled: + default: false + description: |- + OrganizationsEnabled enables Keycloak Organizations feature for this realm. + When enabled, this realm can support Organization resources for multi-tenant scenarios, + identity provider groupings, and domain-based user routing. + type: boolean passwordPolicy: description: PasswordPolicies is a list of password policies to apply to the realm. @@ -158,6 +206,83 @@ spec: realmName: description: RealmName specifies the name of the realm. type: string + x-kubernetes-validations: + - message: Value is immutable + rule: self == oldSelf + sessions: + description: Sessions defines the session settings for the realm. + properties: + ssoLoginSettings: + description: SSOLoginSettings defines the SSO login settings for + the realm. + properties: + accessCodeLifespanLogin: + default: 1800 + description: AccessCodeLifespanLogin represents the max time + a user has to complete a login. This is recommended to be + relatively long, such as 30 minutes or more. + type: integer + accessCodeLifespanUserAction: + default: 300 + description: AccessCodeLifespanUserAction represents the max + time a user has to complete login related actions like update + password or configure totp. This is recommended to be relatively + long, such as 5 minutes or more. + type: integer + type: object + ssoOfflineSessionSettings: + description: SSOOfflineSessionSettings defines the SSO offline + session settings for the realm. + properties: + idleTimeout: + default: 2592000 + description: |- + IdleTimeout represents the time an offline session is allowed to be idle before it expires. + You need to use offline token to refresh at least once within this period; otherwise offline session will expire. + type: integer + maxLifespan: + default: 5184000 + description: MaxLifespan represents the max time before an + offline session is expired regardless of activity. + type: integer + maxLifespanEnabled: + default: false + description: MaxLifespanEnabled enables the offline session + maximum lifetime. + type: boolean + type: object + ssoSessionSettings: + description: SSOSessionSettings defines the SSO session settings + for the realm. + properties: + idleTimeout: + default: 1800 + description: |- + IdleTimeout represents the time a session is allowed to be idle before it expires. + Tokens and browser sessions are invalidated when a session is expired. + type: integer + idleTimeoutRememberMe: + default: 0 + description: |- + IdleTimeoutRememberMe represents the time a session is allowed to be idle before it expires. + Tokens and browser sessions are invalidated when a session is expired. + If not set it uses the standard ssoSessionIdle value. + type: integer + maxLifespan: + default: 36000 + description: |- + MaxLifespan represents the max time before a session is expired. + Tokens and browser sessions are invalidated when a session is expired. + type: integer + maxLifespanRememberMe: + default: 0 + description: |- + MaxLifespanRememberMe represents the max time before a session is expired when a user has set the remember me option. + Tokens and browser sessions are invalidated when a session is expired. + If not set it uses the standard ssoSessionMax value. + type: integer + type: object + type: object smtp: description: Smtp is the configuration for email in the realm. nullable: true @@ -179,10 +304,13 @@ spec: description: The key to select. type: string name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string required: - key @@ -195,10 +323,13 @@ spec: description: The key of the secret to select from. type: string name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string required: - key @@ -215,10 +346,13 @@ spec: description: The key to select. type: string name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string required: - key @@ -231,10 +365,13 @@ spec: description: The key of the secret to select from. type: string name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string required: - key @@ -550,6 +687,7 @@ spec: nullable: true type: array required: + - keycloakRef - realmName type: object status: diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmusers.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmusers.yaml index 05097bcd..ac2538fe 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmusers.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloakrealmusers.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.18.0 name: keycloakrealmusers.v1.edp.epam.com spec: group: v1.edp.epam.com @@ -15,7 +15,7 @@ spec: scope: Namespaced versions: - additionalPrinterColumns: - - description: Reconcilation status + - description: Reconciliation status jsonPath: .status.value name: Status type: string @@ -47,9 +47,40 @@ spec: attributes: additionalProperties: type: string - description: Attributes is a map of user attributes. + description: |- + Attributes is a map of user attributes. + Deprecated: Use AttributesV2 instead. nullable: true type: object + attributesV2: + additionalProperties: + items: + type: string + type: array + description: |- + AttributesV2 is a map of service account attributes. + Each attribute can have multiple values. + nullable: true + type: object + clientRoles: + description: ClientRoles is a list of client roles assigned to user. + items: + properties: + clientId: + description: ClientID is a client ID. + type: string + roles: + description: Roles is a list of client roles names assigned + to user. + items: + type: string + nullable: true + type: array + required: + - clientId + type: object + nullable: true + type: array email: description: Email is a user email. type: string @@ -68,6 +99,13 @@ spec: type: string nullable: true type: array + identityProviders: + description: IdentityProviders is a list of identity providers aliases + linked to the user. + items: + type: string + nullable: true + type: array keepResource: default: true description: |- @@ -79,9 +117,9 @@ spec: description: LastName is a user last name. type: string password: - description: Password is a user password. Allows to keep user password - within Custom Resource. For security concerns, it is recommended - to use PasswordSecret instead. + description: |- + Password is a user password. Allows to keep user password within Custom Resource. For security concerns, it is recommended to use PasswordSecret instead. + Deperecated: use PasswordSecret instead. type: string passwordSecret: description: PasswordSecret defines Kubernetes secret Name and Key, @@ -94,19 +132,19 @@ spec: name: description: Name is the name of the secret. type: string + temporary: + default: false + description: Temporary indicates whether the password is temporary. + type: boolean required: - key - name type: object - realm: - description: |- - Deprecated: use RealmRef instead. - Realm is name of KeycloakRealm custom resource. - type: string realmRef: description: RealmRef is reference to Realm custom resource. properties: kind: + default: KeycloakRealm description: Kind specifies the kind of the Keycloak resource. enum: - KeycloakRealm @@ -115,11 +153,13 @@ spec: name: description: Name specifies the name of the Keycloak resource. type: string + required: + - name type: object reconciliationStrategy: description: |- - ReconciliationStrategy is a strategy for reconciliation. Possible values: full, create-only. - Default value: full. If set to create-only, user will be created only if it does not exist. If user exists, it will not be updated. + ReconciliationStrategy is a strategy for reconciliation. Possible values: full, addOnly. + Default value: full. If set to addOnly, user will be created only if it does not exist. If user exists, it will not be updated. If set to full, user will be created if it does not exist, or updated if it exists. type: string requiredUserActions: @@ -139,14 +179,79 @@ spec: description: Username is a username in keycloak. type: string required: + - realmRef - username type: object status: description: KeycloakRealmUserStatus defines the observed state of KeycloakRealmUser. properties: + conditions: + description: Conditions represent the latest available observations + of an object's state. + 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 + nullable: true + type: array failureCount: format: int64 type: integer + lastSyncedPasswordSecretVersion: + description: |- + LastSyncedPasswordSecretVersion stores the ResourceVersion of the password secret + that was last successfully synced to Keycloak. Used to detect secret changes. + type: string value: type: string type: object diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloaks.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloaks.yaml index 99660f8c..9b48d9ca 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloaks.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/crds/v1.edp.epam.com_keycloaks.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.18.0 name: keycloaks.v1.edp.epam.com spec: group: v1.edp.epam.com @@ -64,10 +64,13 @@ spec: description: The key to select. type: string name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string required: - key @@ -80,10 +83,13 @@ spec: description: The key of the secret to select from. type: string name: + default: "" description: |- Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid? type: string required: - key diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/templates/clusterrole.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/templates/clusterrole.yaml index fe8f80e8..4c290815 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/templates/clusterrole.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/templates/clusterrole.yaml @@ -156,6 +156,32 @@ rules: - get - patch - update + - apiGroups: + - v1.edp.epam.com + resources: + - keycloakorganizations + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - v1.edp.epam.com + resources: + - keycloakorganizations/finalizers + verbs: + - update + - apiGroups: + - v1.edp.epam.com + resources: + - keycloakorganizations/status + verbs: + - get + - patch + - update - apiGroups: - v1.edp.epam.com resources: diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/templates/deployment.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/templates/deployment.yaml index fbeaa42e..cd73c03a 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/templates/deployment.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/templates/deployment.yaml @@ -16,11 +16,20 @@ spec: template: metadata: labels: + {{- include "keycloak-operator.selectorLabels" . | nindent 8 }} name: {{ .Values.name }} + control-plane: controller-manager + {{- if hasKey .Values.podLabels "name" }} + {{ fail "The 'name' key is not allowed in podLabels" }} + {{- end }} + {{- range $key, $value := .Values.podLabels }} + {{ $key }}: {{ $value | quote }} + {{- end }} spec: serviceAccountName: edp-{{ .Values.name }} - securityContext: - runAsNonRoot: true + {{- if .Values.securityContext }} + securityContext: {{ toYaml .Values.securityContext | nindent 8 }} + {{- end }} {{- with .Values.imagePullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} @@ -28,12 +37,20 @@ spec: containers: - name: {{ .Values.name }} # Replace this with the built image name - image: {{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }} + image: {{ if .Values.image.registry }}{{ .Values.image.registry }}/{{ end }}{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }} imagePullPolicy: "{{ .Values.imagePullPolicy }}" command: - /manager - securityContext: - allowPrivilegeEscalation: false + args: + - --metrics-bind-address=:8443 + - --leader-elect + - --health-probe-bind-address=:8081 + {{- if .Values.enableWebhooks }} + - --webhook-cert-path=/tmp/k8s-webhook-server/serving-certs + {{- end }} + {{- if .Values.containerSecurityContext }} + securityContext: {{ toYaml .Values.containerSecurityContext | nindent 12 }} + {{- end }} env: - name: WATCH_NAMESPACE {{- if .Values.clusterReconciliationEnabled }} @@ -51,11 +68,26 @@ spec: valueFrom: fieldRef: fieldPath: metadata.name - {{- if .Values.extraVolumeMounts }} + - name: ENABLE_OWNER_REF + value: {{ .Values.enableOwnerRef | quote }} + - name: ENABLE_WEBHOOKS + value: {{ .Values.enableWebhooks | quote }} + {{- if or .Values.extraVolumeMounts .Values.enableWebhooks }} volumeMounts: + {{- if .Values.enableWebhooks }} + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: webhook-certs + readOnly: true + {{- end }} {{- if .Values.extraVolumeMounts }} {{- toYaml .Values.extraVolumeMounts | nindent 12 }} {{- end }} + {{- end }} + {{- if .Values.enableWebhooks }} + ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP {{- end }} livenessProbe: httpGet: @@ -71,8 +103,13 @@ spec: periodSeconds: 10 resources: {{ toYaml .Values.resources | indent 12 }} - {{- if .Values.extraVolumes }} + {{- if or .Values.extraVolumes .Values.enableWebhooks }} volumes: + {{- if .Values.enableWebhooks }} + - name: webhook-certs + secret: + secretName: webhook-server-cert + {{- end }} {{- if .Values.extraVolumes }} {{- toYaml .Values.extraVolumes | nindent 8 }} {{- end }} diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/templates/operator_role.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/templates/operator_role.yaml index 1d95a354..0f9f3b6e 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/templates/operator_role.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/templates/operator_role.yaml @@ -5,309 +5,82 @@ metadata: labels: {{- include "keycloak-operator.labels" . | nindent 4 }} rules: - - apiGroups: - - "" - resources: - - secrets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakauthflows - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakauthflows/finalizers - verbs: - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakauthflows/status - verbs: - - get - - patch - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakclients - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakclients/finalizers - verbs: - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakclients/status - verbs: - - get - - patch - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakclientscopes - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakclientscopes/finalizers - verbs: - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakclientscopes/status - verbs: - - get - - patch - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmcomponents - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmcomponents/finalizers - verbs: - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmcomponents/status - verbs: - - get - - patch - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmgroups - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmgroups/finalizers - verbs: - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmgroups/status - verbs: - - get - - patch - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmidentityproviders - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmidentityproviders/finalizers - verbs: - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmidentityproviders/status - verbs: - - get - - patch - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmrolebatches - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmrolebatches/finalizers - verbs: - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmrolebatches/status - verbs: - - get - - patch - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmroles - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmroles/finalizers - verbs: - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmroles/status - verbs: - - get - - patch - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealms - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealms/finalizers - verbs: - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealms/status - verbs: - - get - - patch - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmusers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmusers/finalizers - verbs: - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloakrealmusers/status - verbs: - - get - - patch - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloaks - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - v1.edp.epam.com - resources: - - keycloaks/finalizers - verbs: - - update - - apiGroups: - - v1.edp.epam.com - resources: - - keycloaks/status - verbs: - - get - - patch - - update +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - v1 + resources: + - configmap + verbs: + - get + - list + - watch +- apiGroups: + - v1.edp.epam.com + resources: + - keycloakauthflows + - keycloakclients + - keycloakclientscopes + - keycloakorganizations + - keycloakrealmcomponents + - keycloakrealmgroups + - keycloakrealmidentityproviders + - keycloakrealmrolebatches + - keycloakrealmroles + - keycloakrealms + - keycloakrealmusers + - keycloaks + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - v1.edp.epam.com + resources: + - keycloakauthflows/finalizers + - keycloakclients/finalizers + - keycloakclientscopes/finalizers + - keycloakorganizations/finalizers + - keycloakrealmcomponents/finalizers + - keycloakrealmgroups/finalizers + - keycloakrealmidentityproviders/finalizers + - keycloakrealmrolebatches/finalizers + - keycloakrealmroles/finalizers + - keycloakrealms/finalizers + - keycloakrealmusers/finalizers + - keycloaks/finalizers + verbs: + - update +- apiGroups: + - v1.edp.epam.com + resources: + - keycloakauthflows/status + - keycloakclients/status + - keycloakclientscopes/status + - keycloakorganizations/status + - keycloakrealmcomponents/status + - keycloakrealmgroups/status + - keycloakrealmidentityproviders/status + - keycloakrealmrolebatches/status + - keycloakrealmroles/status + - keycloakrealms/status + - keycloakrealmusers/status + - keycloaks/status + verbs: + - get + - patch + - update diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/templates/webhook/certmanager.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/templates/webhook/certmanager.yaml new file mode 100644 index 00000000..e3cec94e --- /dev/null +++ b/packages/system/keycloak-operator/charts/keycloak-operator/templates/webhook/certmanager.yaml @@ -0,0 +1,25 @@ +{{- if .Values.enableWebhooks }} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + labels: + {{- include "keycloak-operator.labels" . | nindent 4 }} + name: {{ .Values.name }}-serving-cert +spec: + dnsNames: + - {{ .Values.name }}-webhook-service.{{ .Release.Namespace }}.svc + - {{ .Values.name }}-webhook-service.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }} + issuerRef: + kind: Issuer + name: {{ .Values.name }}-selfsigned-issuer + secretName: webhook-server-cert +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + labels: + {{- include "keycloak-operator.labels" . | nindent 4 }} + name: {{ .Values.name }}-selfsigned-issuer +spec: + selfSigned: {} +{{- end }} diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/templates/webhook/manifest.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/templates/webhook/manifest.yaml new file mode 100644 index 00000000..2f5a222b --- /dev/null +++ b/packages/system/keycloak-operator/charts/keycloak-operator/templates/webhook/manifest.yaml @@ -0,0 +1,78 @@ +{{- if .Values.enableWebhooks }} +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: {{ .Values.name }}-mutating-webhook-configuration-{{ .Release.Namespace }} + labels: + {{- include "keycloak-operator.labels" . | nindent 4 }} + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ .Values.name }}-serving-cert +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ .Values.name }}-webhook-service + namespace: {{ .Release.Namespace }} + path: /mutate-v1-edp-epam-com-v1-keycloakclient + failurePolicy: Fail + name: mkeycloakclient-v1.kb.io + {{- /* Namespace-scoped webhook to prevent cross-namespace conflicts. */ -}} + {{- if not .Values.clusterReconciliationEnabled }} + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: In + values: + - {{ .Release.Namespace }} + {{- end }} + rules: + - apiGroups: + - v1.edp.epam.com + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - keycloakclients + sideEffects: None +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + labels: + {{- include "keycloak-operator.labels" . | nindent 4 }} + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ .Values.name }}-serving-cert + name: {{ .Values.name }}-validating-webhook-configuration-{{ .Release.Namespace }} +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ .Values.name }}-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-v1-edp-epam-com-v1-keycloakrealm + failurePolicy: Fail + name: vkeycloakrealm-v1.kb.io + {{- /* Namespace-scoped webhook validation to prevent cross-namespace conflicts. */ -}} + {{- if not .Values.clusterReconciliationEnabled }} + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: In + values: + - {{ .Release.Namespace }} + {{- end }} + rules: + - apiGroups: + - v1.edp.epam.com + apiVersions: + - v1 + operations: + - CREATE + resources: + - keycloakrealms + sideEffects: None +{{- end }} diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/templates/webhook/rbac.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/templates/webhook/rbac.yaml new file mode 100644 index 00000000..6fca5e20 --- /dev/null +++ b/packages/system/keycloak-operator/charts/keycloak-operator/templates/webhook/rbac.yaml @@ -0,0 +1,33 @@ +{{- if .Values.enableWebhooks }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "keycloak-operator.labels" . | nindent 4 }} + name: edp-{{ .Release.Namespace }}-webhook-clusterrole +rules: +- apiGroups: + - v1.edp.epam.com + resources: + - keycloakrealms + verbs: + - get + - list + - watch + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + {{- include "keycloak-operator.labels" . | nindent 4 }} + name: edp-{{ .Release.Namespace }}-webhook-clusterrolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: edp-{{ .Release.Namespace }}-webhook-clusterrole +subjects: + - kind: ServiceAccount + name: edp-{{ .Values.name }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/templates/webhook/service.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/templates/webhook/service.yaml new file mode 100644 index 00000000..96a7c245 --- /dev/null +++ b/packages/system/keycloak-operator/charts/keycloak-operator/templates/webhook/service.yaml @@ -0,0 +1,16 @@ +{{- if .Values.enableWebhooks }} +apiVersion: v1 +kind: Service +metadata: + labels: + {{- include "keycloak-operator.labels" . | nindent 4 }} + name: {{ .Values.name }}-webhook-service +spec: + ports: + - port: 443 + protocol: TCP + targetPort: 9443 + selector: + {{- include "keycloak-operator.selectorLabels" . | nindent 4 }} + control-plane: controller-manager +{{- end }} diff --git a/packages/system/keycloak-operator/charts/keycloak-operator/values.yaml b/packages/system/keycloak-operator/charts/keycloak-operator/values.yaml index fbd6ae53..64226135 100644 --- a/packages/system/keycloak-operator/charts/keycloak-operator/values.yaml +++ b/packages/system/keycloak-operator/charts/keycloak-operator/values.yaml @@ -2,6 +2,10 @@ name: keycloak-operator # -- Annotations to be added to the Deployment annotations: {} +# -- Cluster domain for constructing service DNS names +clusterDomain: cluster.local +# -- Labels to be added to the pod +podLabels: {} # -- Node labels for pod assignment nodeSelector: {} # -- Node tolerations for server scheduling to nodes with taints @@ -9,6 +13,8 @@ tolerations: [] # -- Affinity for pod assignment affinity: {} image: + # -- KubeRocketCI keycloak-operator Docker image registry. + registry: "" # -- KubeRocketCI keycloak-operator Docker image name. The released image can be found on [Dockerhub](https://hub.docker.com/r/epamedp/keycloak-operator) repository: epamedp/keycloak-operator # if not defined then .Chart.AppVersion is used @@ -27,6 +33,16 @@ resources: cpu: 50m memory: 64Mi +# -- Deployment Security Context +# Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +securityContext: + runAsNonRoot: true + +# -- Container Security Context +# Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +containerSecurityContext: + allowPrivilegeEscalation: false + # -- Additional volumes to be added to the pod extraVolumes: [] # - name: custom-ca @@ -44,3 +60,11 @@ extraVolumeMounts: [] # -- If clusterReconciliationEnabled is true, the operator reconciles all Keycloak instances in the cluster; # otherwise, it only reconciles instances in the same namespace by default, and cluster-scoped resources are ignored. clusterReconciliationEnabled: false + +# -- If set to true, the operator will set the owner reference for all resources that have Keycloak or KeycloakRealm as reference. +# This is legacy behavior and not recommended for use. In the future, this will be set to false by default. +enableOwnerRef: true + +# -- If set to true, enables webhook resources (ValidatingWebhookConfiguration, Service, and Certificate). +# Webhooks require cert-manager to be installed in the cluster. +enableWebhooks: true diff --git a/packages/system/keycloak-operator/images/keycloak-operator/Dockerfile b/packages/system/keycloak-operator/images/keycloak-operator/Dockerfile new file mode 100644 index 00000000..8167042f --- /dev/null +++ b/packages/system/keycloak-operator/images/keycloak-operator/Dockerfile @@ -0,0 +1,29 @@ +# syntax=docker/dockerfile:1.2 + +FROM alpine AS source +ARG COMMIT_REF=facbc36 +RUN apk add --no-cache curl tar git +WORKDIR /src + +RUN curl -sSL https://github.com/epam/edp-keycloak-operator/archive/${COMMIT_REF}.tar.gz \ + | tar -xz --strip-components=1 + +COPY patches /patches +RUN git apply /patches/*.diff + +FROM --platform=$BUILDPLATFORM docker.io/golang:1.24 AS builder +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /go/src/keycloak-operator + +COPY --from=source /src/go.mod /src/go.sum ./ +RUN go mod download + +COPY --from=source /src . +RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /build/manager ./cmd + +FROM gcr.io/distroless/static:nonroot +COPY --from=builder /build/manager /manager +USER 65532:65532 +ENTRYPOINT ["/manager"] diff --git a/packages/system/keycloak-operator/images/keycloak-operator/patches/pr309.diff b/packages/system/keycloak-operator/images/keycloak-operator/patches/pr309.diff new file mode 100644 index 00000000..80f08777 --- /dev/null +++ b/packages/system/keycloak-operator/images/keycloak-operator/patches/pr309.diff @@ -0,0 +1,187 @@ +diff --git a/internal/controller/keycloakrealmgroup/chain/chain.go b/internal/controller/keycloakrealmgroup/chain/chain.go +index 1ca497a0..dbc3844b 100644 +--- a/internal/controller/keycloakrealmgroup/chain/chain.go ++++ b/internal/controller/keycloakrealmgroup/chain/chain.go +@@ -15,6 +15,10 @@ type GroupContext struct { + // GroupID is the Keycloak group ID, set by CreateOrUpdateGroup handler. + GroupID string + ++ // ExistingGroupID is the Keycloak group ID from a previous reconciliation (status.ID). ++ // Used to detect renames: if set, the group is fetched by ID first. ++ ExistingGroupID string ++ + // ParentGroupID is the parent group's Keycloak ID (empty if top-level). + ParentGroupID string + +diff --git a/internal/controller/keycloakrealmgroup/chain/create_or_update_group.go b/internal/controller/keycloakrealmgroup/chain/create_or_update_group.go +index 0504d9dd..931fab27 100644 +--- a/internal/controller/keycloakrealmgroup/chain/create_or_update_group.go ++++ b/internal/controller/keycloakrealmgroup/chain/create_or_update_group.go +@@ -33,17 +33,34 @@ func (h *CreateOrUpdateGroup) Serve( + err error + ) + +- if groupCtx.ParentGroupID != "" { +- existingGroup, _, err = kClient.Groups.FindChildGroupByName(ctx, realm, groupCtx.ParentGroupID, spec.Name) +- } else { +- existingGroup, _, err = kClient.Groups.FindGroupByName(ctx, realm, spec.Name) ++ // If we already have an ID from a previous reconciliation, fetch by ID first. ++ // This handles renames: spec.Name may have changed but the ID stays the same. ++ if groupCtx.ExistingGroupID != "" { ++ existingGroup, _, err = kClient.Groups.GetGroup(ctx, realm, groupCtx.ExistingGroupID) ++ if err != nil && !keycloakv2.IsNotFound(err) { ++ return fmt.Errorf("unable to get group by ID %q: %w", groupCtx.ExistingGroupID, err) ++ } ++ ++ if keycloakv2.IsNotFound(err) { ++ log.Info("Group not found by ID, will search by name", "groupID", groupCtx.ExistingGroupID) ++ existingGroup = nil ++ } + } + +- if err != nil && !keycloakv2.IsNotFound(err) { +- return fmt.Errorf("unable to search for group %q: %w", spec.Name, err) ++ // If we didn't find the group by ID, search by name. ++ if existingGroup == nil { ++ if groupCtx.ParentGroupID != "" { ++ existingGroup, _, err = kClient.Groups.FindChildGroupByName(ctx, realm, groupCtx.ParentGroupID, spec.Name) ++ } else { ++ existingGroup, _, err = kClient.Groups.FindGroupByName(ctx, realm, spec.Name) ++ } ++ ++ if err != nil && !keycloakv2.IsNotFound(err) { ++ return fmt.Errorf("unable to search for group %q: %w", spec.Name, err) ++ } + } + +- if keycloakv2.IsNotFound(err) { ++ if existingGroup == nil { + groupRep := keycloakv2.GroupRepresentation{ + Name: &spec.Name, + Description: &spec.Description, +@@ -67,6 +84,7 @@ func (h *CreateOrUpdateGroup) Serve( + log.Info("Group created", "groupID", groupCtx.GroupID) + } else { + groupCtx.GroupID = *existingGroup.Id ++ existingGroup.Name = &spec.Name + existingGroup.Description = &spec.Description + existingGroup.Path = &spec.Path + existingGroup.Attributes = &spec.Attributes +diff --git a/internal/controller/keycloakrealmgroup/chain/create_or_update_group_test.go b/internal/controller/keycloakrealmgroup/chain/create_or_update_group_test.go +index 26841a71..000c7538 100644 +--- a/internal/controller/keycloakrealmgroup/chain/create_or_update_group_test.go ++++ b/internal/controller/keycloakrealmgroup/chain/create_or_update_group_test.go +@@ -265,3 +265,97 @@ func TestCreateOrUpdateGroup_Serve_FindChildGroupError(t *testing.T) { + err := h.Serve(context.Background(), group, kClient, groupCtx) + assert.ErrorContains(t, err, "unable to search for group") + } ++ ++func TestCreateOrUpdateGroup_Serve_RenameByID(t *testing.T) { ++ mockGroups := mocks.NewMockGroupsClient(t) ++ ++ kClient := &keycloakv2.KeycloakClient{Groups: mockGroups} ++ groupCtx := &GroupContext{RealmName: "test-realm", ExistingGroupID: "existing-id"} ++ ++ group := &keycloakApi.KeycloakRealmGroup{} ++ group.Spec.Name = "new-name" ++ group.Spec.Description = "Updated desc" ++ group.Spec.Path = "/new-name" ++ group.Spec.Attributes = map[string][]string{"key": {"val"}} ++ ++ mockGroups.EXPECT().GetGroup( ++ context.Background(), "test-realm", "existing-id", ++ ).Return(&keycloakv2.GroupRepresentation{ ++ Id: ptr.To("existing-id"), ++ Name: ptr.To("old-name"), ++ Path: ptr.To("/old-name"), ++ }, nil, nil) ++ ++ mockGroups.EXPECT().UpdateGroup( ++ context.Background(), "test-realm", "existing-id", ++ keycloakv2.GroupRepresentation{ ++ Id: ptr.To("existing-id"), ++ Name: ptr.To("new-name"), ++ Description: ptr.To("Updated desc"), ++ Path: ptr.To("/new-name"), ++ Attributes: &map[string][]string{"key": {"val"}}, ++ }, ++ ).Return(nil, nil) ++ ++ h := NewCreateOrUpdateGroup() ++ err := h.Serve(context.Background(), group, kClient, groupCtx) ++ require.NoError(t, err) ++ assert.Equal(t, "existing-id", groupCtx.GroupID) ++} ++ ++func TestCreateOrUpdateGroup_Serve_ExistingIDNotFound_FallsBackToName(t *testing.T) { ++ mockGroups := mocks.NewMockGroupsClient(t) ++ ++ kClient := &keycloakv2.KeycloakClient{Groups: mockGroups} ++ groupCtx := &GroupContext{RealmName: "test-realm", ExistingGroupID: "deleted-id"} ++ ++ group := &keycloakApi.KeycloakRealmGroup{} ++ group.Spec.Name = testGroupName ++ group.Spec.Path = "/test-group" ++ group.Spec.Attributes = map[string][]string{"key": {"val"}} ++ ++ mockGroups.EXPECT().GetGroup( ++ context.Background(), "test-realm", "deleted-id", ++ ).Return(nil, nil, keycloakv2.ErrNotFound) ++ ++ mockGroups.EXPECT().FindGroupByName( ++ context.Background(), "test-realm", testGroupName, ++ ).Return(nil, nil, keycloakv2.ErrNotFound) ++ ++ mockGroups.EXPECT().CreateGroup( ++ context.Background(), "test-realm", ++ keycloakv2.GroupRepresentation{ ++ Name: ptr.To(testGroupName), ++ Description: ptr.To(""), ++ Path: ptr.To("/test-group"), ++ Attributes: &map[string][]string{"key": {"val"}}, ++ }, ++ ).Return(&keycloakv2.Response{ ++ HTTPResponse: &http.Response{ ++ Header: http.Header{"Location": []string{"http://localhost/admin/realms/test-realm/groups/new-id"}}, ++ }, ++ }, nil) ++ ++ h := NewCreateOrUpdateGroup() ++ err := h.Serve(context.Background(), group, kClient, groupCtx) ++ require.NoError(t, err) ++ assert.Equal(t, "new-id", groupCtx.GroupID) ++} ++ ++func TestCreateOrUpdateGroup_Serve_GetGroupByIDError(t *testing.T) { ++ mockGroups := mocks.NewMockGroupsClient(t) ++ ++ kClient := &keycloakv2.KeycloakClient{Groups: mockGroups} ++ groupCtx := &GroupContext{RealmName: "test-realm", ExistingGroupID: "existing-id"} ++ ++ group := &keycloakApi.KeycloakRealmGroup{} ++ group.Spec.Name = testGroupName ++ ++ mockGroups.EXPECT().GetGroup( ++ context.Background(), "test-realm", "existing-id", ++ ).Return(nil, nil, errors.New("connection error")) ++ ++ h := NewCreateOrUpdateGroup() ++ err := h.Serve(context.Background(), group, kClient, groupCtx) ++ assert.ErrorContains(t, err, "unable to get group by ID") ++} +diff --git a/internal/controller/keycloakrealmgroup/keycloakrealmgroup_controller.go b/internal/controller/keycloakrealmgroup/keycloakrealmgroup_controller.go +index 0f7e6ce3..52015e24 100644 +--- a/internal/controller/keycloakrealmgroup/keycloakrealmgroup_controller.go ++++ b/internal/controller/keycloakrealmgroup/keycloakrealmgroup_controller.go +@@ -166,8 +166,9 @@ func (r *ReconcileKeycloakRealmGroup) tryReconcile(ctx context.Context, keycloak + } + + groupCtx := &chain.GroupContext{ +- RealmName: realmName, +- ParentGroupID: parentGroupID, ++ RealmName: realmName, ++ ParentGroupID: parentGroupID, ++ ExistingGroupID: keycloakRealmGroup.Status.ID, + } + + if err := chain.MakeChain().Serve(ctx, keycloakRealmGroup, kClientV2, groupCtx); err != nil { diff --git a/packages/system/keycloak-operator/values.yaml b/packages/system/keycloak-operator/values.yaml index fc61c51f..3bdacddc 100644 --- a/packages/system/keycloak-operator/values.yaml +++ b/packages/system/keycloak-operator/values.yaml @@ -1,4 +1,8 @@ keycloak-operator: + image: + registry: ghcr.io + repository: cozystack/cozystack/keycloak-operator + tag: "latest@sha256:27279247dfbd2d1e86fc4e827d34c891880ca65eefd75da1701bc0a1adf865a9" clusterReconciliationEnabled: true resources: limits: diff --git a/packages/system/keycloak/Makefile b/packages/system/keycloak/Makefile index 62f4e98d..09afc864 100644 --- a/packages/system/keycloak/Makefile +++ b/packages/system/keycloak/Makefile @@ -1,5 +1,5 @@ export NAME=keycloak export NAMESPACE=cozy-keycloak -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk diff --git a/packages/system/keycloak/templates/db.yaml b/packages/system/keycloak/templates/db.yaml index 70666d7b..6a57e93a 100644 --- a/packages/system/keycloak/templates/db.yaml +++ b/packages/system/keycloak/templates/db.yaml @@ -4,11 +4,13 @@ metadata: name: keycloak-db spec: instances: 2 + {{- $existingCluster := lookup "postgresql.cnpg.io/v1" "Cluster" .Release.Namespace "keycloak-db" }} + {{- $image := dig "spec" "imageName" "ghcr.io/cloudnative-pg/postgresql:17.7-standard-trixie" $existingCluster }} + imageName: {{ if regexMatch ":17\\." $image }}ghcr.io/cloudnative-pg/postgresql:17.7-standard-trixie{{ else if regexMatch ":[0-9]+\\.[0-9]+$" $image }}{{ printf "%s-standard-trixie" $image }}{{ else }}{{ $image }}{{ end }} storage: size: 20Gi - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- if $configMap }} - {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }} + {{- if .Values._cluster.scheduling }} + {{- $rawConstraints := get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }} {{- if $rawConstraints }} {{- $rawConstraints | fromYaml | toYaml | nindent 2 }} labelSelector: diff --git a/packages/system/keycloak/templates/ingress.yaml b/packages/system/keycloak/templates/ingress.yaml index 30120619..7f9fd476 100644 --- a/packages/system/keycloak/templates/ingress.yaml +++ b/packages/system/keycloak/templates/ingress.yaml @@ -1,7 +1,8 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} -{{- $exposeIngress := index $cozyConfig.data "expose-ingress" | default "tenant-root" }} +{{- $host := index .Values._cluster "root-host" }} +{{- $ingressHost := .Values.ingress.host | default (printf "keycloak.%s" $host) }} +{{- $solver := (index .Values._cluster "solver") | default "http01" }} +{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} apiVersion: networking.k8s.io/v1 kind: Ingress @@ -9,20 +10,20 @@ metadata: name: keycloak-ingress {{- with .Values.ingress.annotations }} annotations: - {{- if ne $issuerType "cloudflare" }} - acme.cert-manager.io/http01-ingress-class: {{ $exposeIngress }} + {{- if eq $solver "http01" }} + acme.cert-manager.io/http01-ingress-ingressclassname: {{ $exposeIngress }} {{- end }} - cert-manager.io/cluster-issuer: letsencrypt-prod + cert-manager.io/cluster-issuer: {{ $clusterIssuer }} {{- toYaml . | nindent 4 }} {{- end }} spec: ingressClassName: {{ $exposeIngress }} tls: - hosts: - - keycloak.{{ $host }} + - {{ $ingressHost }} secretName: web-tls rules: - - host: keycloak.{{ $host }} + - host: {{ $ingressHost }} http: paths: - path: / diff --git a/packages/system/keycloak/templates/sts.yaml b/packages/system/keycloak/templates/sts.yaml index 8994e3f1..c1827b93 100644 --- a/packages/system/keycloak/templates/sts.yaml +++ b/packages/system/keycloak/templates/sts.yaml @@ -1,6 +1,10 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $host := index $cozyConfig.data "root-host" }} -{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }} +{{- define "keycloak.theme.sanitizedName" -}} +{{- regexReplaceAll "-+" (regexReplaceAll "[^a-z0-9-]" (. | lower) "-") "-" | trimPrefix "-" | trimSuffix "-" -}} +{{- end -}} + +{{- $host := index .Values._cluster "root-host" }} +{{- $ingressHost := .Values.ingress.host | default (printf "keycloak.%s" $host) }} +{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }} {{- $existingPassword := lookup "v1" "Secret" "cozy-keycloak" (printf "%s-credentials" .Release.Name) }} {{- $password := randAlphaNum 16 -}} @@ -39,8 +43,48 @@ spec: app: keycloak-ha spec: restartPolicy: Always + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} securityContext: fsGroup: 1000 + {{- if .Values.themes }} + {{- $themeNames := list }} + {{- range .Values.themes }} + {{- if not .name }}{{ fail "theme entry missing required field: name" }}{{- end }} + {{- if not .image }}{{ fail "theme entry missing required field: image" }}{{- end }} + {{- $sanitized := include "keycloak.theme.sanitizedName" .name }} + {{- if not $sanitized }}{{ fail (printf "theme name %q produces empty container name after sanitization" .name) }}{{- end }} + {{- if gt (len (printf "theme-%s" $sanitized)) 63 }}{{ fail (printf "theme name %q produces container name exceeding 63 characters" .name) }}{{- end }} + {{- if has $sanitized $themeNames }}{{ fail (printf "duplicate theme name after sanitization: %s (from %s)" $sanitized .name) }}{{- end }} + {{- $themeNames = append $themeNames $sanitized }} + {{- end }} + initContainers: + {{- range .Values.themes }} + - name: theme-{{ include "keycloak.theme.sanitizedName" .name }} + image: "{{ .image }}" + imagePullPolicy: IfNotPresent + command: ["sh", "-c", "[ -d /themes ] && cp -r /themes/. /opt/keycloak/themes/ || { echo 'ERROR: /themes directory not found in image'; exit 1; }"] + resources: + requests: + cpu: 10m + memory: 32Mi + limits: + memory: 64Mi + securityContext: + runAsNonRoot: true + runAsUser: 1000 + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + volumeMounts: + - name: themes + mountPath: /opt/keycloak/themes + {{- end }} + {{- end }} containers: - name: keycloak image: {{ .Values.image }} @@ -76,18 +120,25 @@ spec: {{- end }} - name: KC_METRICS_ENABLED value: "true" + - name: KC_HEALTH_ENABLED + value: "true" - name: KC_LOG_LEVEL value: "info" - name: KC_CACHE value: "ispn" - name: KC_CACHE_STACK value: "kubernetes" - - name: KC_PROXY - value: "edge" + - name: KC_PROXY_HEADERS + value: "xforwarded" + - name: KC_HTTP_ENABLED + value: "true" - name: KEYCLOAK_ADMIN value: admin - name: KEYCLOAK_ADMIN_PASSWORD - value: {{ $password }} + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-credentials + key: password - name: KC_DB value: "postgres" - name: KC_DB_URL_HOST @@ -118,23 +169,45 @@ spec: - name: KC_FEATURES value: "docker" - name: KC_HOSTNAME - value: https://keycloak.{{ $host }} + value: https://{{ $ingressHost }} - name: JAVA_OPTS_APPEND value: "-Djgroups.dns.query=keycloak-headless.cozy-keycloak.svc.{{ $clusterDomain }}" + {{- if .Values.themes }} + volumeMounts: + - name: themes + mountPath: /opt/keycloak/themes + {{- end }} ports: - name: http containerPort: 8080 protocol: TCP + - name: management + containerPort: 9000 + protocol: TCP + startupProbe: + httpGet: + path: /health/ready + port: management + failureThreshold: 30 + periodSeconds: 10 livenessProbe: httpGet: - path: / - port: http - initialDelaySeconds: 120 + path: /health/live + port: management + periodSeconds: 15 timeoutSeconds: 5 + failureThreshold: 5 readinessProbe: httpGet: - path: /realms/master - port: http - initialDelaySeconds: 60 - timeoutSeconds: 1 + path: /health/ready + port: management + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + {{- if .Values.themes }} + volumes: + - name: themes + emptyDir: + sizeLimit: 256Mi + {{- end }} terminationGracePeriodSeconds: 60 diff --git a/packages/system/keycloak/values.yaml b/packages/system/keycloak/values.yaml index e93de556..4368ea2c 100644 --- a/packages/system/keycloak/values.yaml +++ b/packages/system/keycloak/values.yaml @@ -1,6 +1,10 @@ -image: quay.io/keycloak/keycloak:26.0.4 +image: quay.io/keycloak/keycloak:26.5.2 ingress: + # Custom hostname for the Keycloak Ingress. + # If set, this value will be used as the Ingress hostname (e.g., "auth.example.com"). + # If left empty, defaults to "keycloak." based on the cluster root-host setting. + host: "" annotations: nginx.ingress.kubernetes.io/affinity: "cookie" nginx.ingress.kubernetes.io/session-cookie-expires: "86400" @@ -10,3 +14,13 @@ resources: requests: memory: 500Mi cpu: 100m + +themes: [] +# - name: my-theme +# image: my-registry/my-keycloak-theme:v1.0 +# Theme images must contain theme files under /themes/ directory. +# Each theme is copied into Keycloak's /opt/keycloak/themes/ via init container. +# If multiple themes contain files with the same path, later entries take precedence. + +imagePullSecrets: [] +# - name: my-registry-secret diff --git a/packages/system/kilo/Chart.yaml b/packages/system/kilo/Chart.yaml new file mode 100644 index 00000000..d533883e --- /dev/null +++ b/packages/system/kilo/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-kilo +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/kilo/Makefile b/packages/system/kilo/Makefile new file mode 100644 index 00000000..c6f47322 --- /dev/null +++ b/packages/system/kilo/Makefile @@ -0,0 +1,13 @@ +export NAME=kilo +export NAMESPACE=cozy-$(NAME) + +include ../../../hack/common-envs.mk +include ../../../hack/package.mk + +update: + tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/squat/kilo | awk -F'[/^]' 'END{print $$3}') && \ + digest=$$(skopeo inspect --override-os linux --override-arch amd64 --format '{{.Digest}}' docker://ghcr.io/squat/kilo:$${tag}) && \ + REPOSITORY="ghcr.io/squat/kilo" \ + yq -i '.kilo.image.repository = strenv(REPOSITORY)' values.yaml && \ + TAG="$${tag}@$${digest}" \ + yq -i '.kilo.image.tag = strenv(TAG)' values.yaml diff --git a/packages/system/kilo/templates/configmap.yaml b/packages/system/kilo/templates/configmap.yaml new file mode 100644 index 00000000..36956984 --- /dev/null +++ b/packages/system/kilo/templates/configmap.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: kubeconfig-in-cluster + namespace: cozy-kilo +data: + kubeconfig: | + apiVersion: v1 + clusters: + - cluster: + certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + server: https://127.0.0.1:7445 + name: local + contexts: + - context: + cluster: local + user: service-account + name: local + current-context: local + kind: Config + users: + - name: service-account + user: + tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token \ No newline at end of file diff --git a/packages/system/kilo/templates/crds.yaml b/packages/system/kilo/templates/crds.yaml new file mode 100644 index 00000000..fdc3dee4 --- /dev/null +++ b/packages/system/kilo/templates/crds.yaml @@ -0,0 +1,93 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null + name: peers.kilo.squat.ai +spec: + group: kilo.squat.ai + names: + kind: Peer + listKind: PeerList + plural: peers + singular: peer + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Peer is a WireGuard peer that should have access to the VPN. + 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: 'Specification of the desired behavior of the Kilo Peer. + More info: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#spec-and-status' + properties: + allowedIPs: + description: AllowedIPs is the list of IP addresses that are allowed + for the given peer's tunnel. + items: + type: string + type: array + endpoint: + description: Endpoint is the initial endpoint for connections to the + peer. + properties: + dnsOrIP: + description: DNSOrIP is a DNS name or an IP address. + properties: + dns: + description: DNS must be a valid RFC 1123 subdomain. + type: string + ip: + description: IP must be a valid IP address. + type: string + type: object + port: + description: Port must be a valid port number. + format: int32 + type: integer + required: + - dnsOrIP + - port + type: object + persistentKeepalive: + description: PersistentKeepalive is the interval in seconds of the + emission of keepalive packets by the peer. This defaults to 0, which + disables the feature. + type: integer + presharedKey: + description: PresharedKey is the optional symmetric encryption key + for the peer. + type: string + publicKey: + description: PublicKey is the WireGuard public key for the peer. + type: string + required: + - allowedIPs + - publicKey + type: object + required: + - spec + type: object + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/packages/system/kilo/templates/kilo.yaml b/packages/system/kilo/templates/kilo.yaml new file mode 100644 index 00000000..ceac643d --- /dev/null +++ b/packages/system/kilo/templates/kilo.yaml @@ -0,0 +1,87 @@ +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: kilo + namespace: cozy-kilo + labels: + app.kubernetes.io/name: kilo + app.kubernetes.io/part-of: kilo +spec: + selector: + matchLabels: + app.kubernetes.io/name: kilo + app.kubernetes.io/part-of: kilo + template: + metadata: + labels: + app.kubernetes.io/name: kilo + app.kubernetes.io/part-of: kilo + spec: + serviceAccountName: kilo + hostNetwork: true + containers: + - name: kilo + image: "{{ .Values.kilo.image.repository }}:{{ .Values.kilo.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.kilo.image.pullPolicy }} + args: + - --kubeconfig=/etc/kubernetes/kubeconfig + - --hostname=$(NODE_NAME) + - --cni=false + - --clean-up-interface={{ .Values.kilo.cleanUpInterface | default "false" }} + {{- with .Values.kilo.compatibility }} + - --compatibility={{ . }} + {{- end }} + - --encapsulate=crosssubnet + - --local=false + - --mesh-granularity={{ .Values.kilo.meshGranularity | default "location" }} + {{- with .Values.kilo.transitCIDR }} + - --subnet={{ . }} + {{- end }} + - --mtu={{ .Values.kilo.mtu | default "auto" }} + - --internal-cidr=$(NODE_IP)/32 + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: NODE_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + ports: + - containerPort: 1107 + name: metrics + securityContext: + privileged: true + volumeMounts: + - name: kilo-dir + mountPath: /var/lib/kilo + - name: kubeconfig + mountPath: /etc/kubernetes + readOnly: true + - name: lib-modules + mountPath: /lib/modules + readOnly: true + - name: xtables-lock + mountPath: /run/xtables.lock + readOnly: false + tolerations: + - effect: NoSchedule + operator: Exists + - effect: NoExecute + operator: Exists + volumes: + - name: kilo-dir + hostPath: + path: /var/lib/kilo + - name: kubeconfig + configMap: + name: kubeconfig-in-cluster + - name: lib-modules + hostPath: + path: /lib/modules + - name: xtables-lock + hostPath: + path: /run/xtables.lock + type: FileOrCreate diff --git a/packages/system/kilo/templates/rbac.yaml b/packages/system/kilo/templates/rbac.yaml new file mode 100644 index 00000000..73bc4786 --- /dev/null +++ b/packages/system/kilo/templates/rbac.yaml @@ -0,0 +1,45 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kilo + namespace: cozy-kilo +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kilo +rules: +- apiGroups: + - "" + resources: + - nodes + verbs: + - list + - patch + - watch +- apiGroups: + - kilo.squat.ai + resources: + - peers + verbs: + - list + - watch +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: kilo +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kilo +subjects: + - kind: ServiceAccount + name: kilo + namespace: cozy-kilo \ No newline at end of file diff --git a/packages/system/kilo/values-cilium.yaml b/packages/system/kilo/values-cilium.yaml new file mode 100644 index 00000000..1a75fc41 --- /dev/null +++ b/packages/system/kilo/values-cilium.yaml @@ -0,0 +1,2 @@ +kilo: + compatibility: cilium diff --git a/packages/system/kilo/values.yaml b/packages/system/kilo/values.yaml new file mode 100644 index 00000000..0c2e4439 --- /dev/null +++ b/packages/system/kilo/values.yaml @@ -0,0 +1,9 @@ +kilo: + image: + pullPolicy: IfNotPresent + tag: 0.7.0@sha256:c7468aee96425f47369fd1d33b9736147aebc2e9c6e4355d0593461c30af308e + repository: ghcr.io/squat/kilo + transitCIDR: 100.66.0.0/16 + meshGranularity: location + cleanUpInterface: false + mtu: auto diff --git a/packages/system/kubeovn-plunger/Chart.yaml b/packages/system/kubeovn-plunger/Chart.yaml new file mode 100644 index 00000000..744ef9c0 --- /dev/null +++ b/packages/system/kubeovn-plunger/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: cozy-kubeovn-plunger +description: External monitoring agent for Kube-OVN ovn-central; collects cluster state and exposes metrics/alerts +type: application +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process +appVersion: "1.0.0" diff --git a/packages/system/kubeovn-plunger/Makefile b/packages/system/kubeovn-plunger/Makefile new file mode 100644 index 00000000..f56d935b --- /dev/null +++ b/packages/system/kubeovn-plunger/Makefile @@ -0,0 +1,19 @@ +export NAME=kubeovn-plunger +export NAMESPACE=cozy-kubeovn + +include ../../../hack/common-envs.mk +include ../../../hack/package.mk + +image: + docker buildx build -f images/kubeovn-plunger/Dockerfile ../../../ \ + --provenance false \ + --tag $(REGISTRY)/kubeovn-plunger:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/kubeovn-plunger:latest \ + --cache-to type=inline \ + --metadata-file images/kubeovn-plunger.json \ + --push=$(PUSH) \ + --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ + --load=$(LOAD) + IMAGE="$(REGISTRY)/kubeovn-plunger:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/kubeovn-plunger.json -o json -r)" \ + yq -i '.image = strenv(IMAGE)' values.yaml + rm -f images/kubeovn-plunger.json diff --git a/packages/system/kubeovn-plunger/images/kubeovn-plunger/Dockerfile b/packages/system/kubeovn-plunger/images/kubeovn-plunger/Dockerfile new file mode 100644 index 00000000..b0473244 --- /dev/null +++ b/packages/system/kubeovn-plunger/images/kubeovn-plunger/Dockerfile @@ -0,0 +1,22 @@ +FROM golang:1.25-alpine AS builder + +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /workspace + +COPY go.mod go.sum ./ +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go mod download + +COPY pkg pkg/ +COPY cmd cmd/ +COPY internal internal/ + +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -ldflags="-extldflags=-static" -o /kubeovn-plunger cmd/kubeovn-plunger/main.go + +FROM scratch + +COPY --from=builder /kubeovn-plunger /kubeovn-plunger +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt + +ENTRYPOINT ["/kubeovn-plunger"] diff --git a/packages/system/kubeovn-plunger/templates/deployment.yaml b/packages/system/kubeovn-plunger/templates/deployment.yaml new file mode 100644 index 00000000..37b49620 --- /dev/null +++ b/packages/system/kubeovn-plunger/templates/deployment.yaml @@ -0,0 +1,36 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kube-ovn-plunger + labels: + app.kubernetes.io/name: kube-ovn-plunger + app.kubernetes.io/instance: {{ .Release.Name }} +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: kube-ovn-plunger + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: kube-ovn-plunger + app.kubernetes.io/instance: {{ .Release.Name }} + spec: + serviceAccountName: kube-ovn-plunger + containers: + - name: kube-ovn-plunger + image: "{{ .Values.image }}" + args: + {{- if .Values.debug }} + - --zap-log-level=debug + {{- else }} + - --zap-log-level=info + {{- end }} + - --metrics-bind-address=:8080 + - --metrics-secure=false + - --kube-ovn-namespace={{ .Release.Namespace }} + - --ovn-central-name={{ .Values.ovnCentralName }} + ports: + - name: metrics + containerPort: 8080 diff --git a/packages/system/kubeovn-plunger/templates/podscrape.yaml b/packages/system/kubeovn-plunger/templates/podscrape.yaml new file mode 100644 index 00000000..e23b8dcc --- /dev/null +++ b/packages/system/kubeovn-plunger/templates/podscrape.yaml @@ -0,0 +1,11 @@ +apiVersion: operator.victoriametrics.com/v1beta1 +kind: VMPodScrape +metadata: + name: kube-ovn-plunger +spec: + podMetricsEndpoints: + - port: metrics + selector: + matchLabels: + app.kubernetes.io/name: kube-ovn-plunger + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/packages/system/kubeovn-plunger/templates/rbac.yaml b/packages/system/kubeovn-plunger/templates/rbac.yaml new file mode 100644 index 00000000..3ca22740 --- /dev/null +++ b/packages/system/kubeovn-plunger/templates/rbac.yaml @@ -0,0 +1,37 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: kube-ovn-plunger +rules: +- apiGroups: + - "" + resources: + - pods + - pods/exec + verbs: + - get + - list + - watch + - create +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: kube-ovn-plunger +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: kube-ovn-plunger +subjects: +- kind: ServiceAccount + name: kube-ovn-plunger + namespace: {{ .Release.Namespace }} diff --git a/packages/system/kubeovn-plunger/templates/service.yaml b/packages/system/kubeovn-plunger/templates/service.yaml new file mode 100644 index 00000000..f2b9dffc --- /dev/null +++ b/packages/system/kubeovn-plunger/templates/service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: kube-ovn-plunger + labels: + app.kubernetes.io/name: kube-ovn-plunger + app.kubernetes.io/instance: {{ .Release.Name }} +spec: + type: ClusterIP + ports: + - port: 8080 + targetPort: metrics + protocol: TCP + name: metrics + selector: + app.kubernetes.io/name: kube-ovn-plunger + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/packages/system/kubeovn-plunger/templates/serviceaccount.yaml b/packages/system/kubeovn-plunger/templates/serviceaccount.yaml new file mode 100644 index 00000000..76b3b228 --- /dev/null +++ b/packages/system/kubeovn-plunger/templates/serviceaccount.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +automountServiceAccountToken: true +kind: ServiceAccount +metadata: + name: kube-ovn-plunger + labels: + app.kubernetes.io/name: kube-ovn-plunger + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/packages/system/kubeovn-plunger/values.yaml b/packages/system/kubeovn-plunger/values.yaml new file mode 100644 index 00000000..02620593 --- /dev/null +++ b/packages/system/kubeovn-plunger/values.yaml @@ -0,0 +1,4 @@ +portSecurity: true +routes: "" +image: ghcr.io/cozystack/cozystack/kubeovn-plunger:v1.3.0@sha256:b75a0facb99c3b0fe8090414b3425f5c4858fff632d1de122ce9944c4daa89c0 +ovnCentralName: ovn-central diff --git a/packages/system/kubeovn-webhook/Chart.yaml b/packages/system/kubeovn-webhook/Chart.yaml index f2c1e1b0..b8c1f40b 100644 --- a/packages/system/kubeovn-webhook/Chart.yaml +++ b/packages/system/kubeovn-webhook/Chart.yaml @@ -2,5 +2,5 @@ apiVersion: v2 name: cozy-kubeovn-webhook description: Helm chart for a mutating admission webhook that copies Namespace annotations into Pods type: application -version: 0.1.0 +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process appVersion: "1.0.0" diff --git a/packages/system/kubeovn-webhook/Makefile b/packages/system/kubeovn-webhook/Makefile index 76bf5f5a..9b2e2744 100644 --- a/packages/system/kubeovn-webhook/Makefile +++ b/packages/system/kubeovn-webhook/Makefile @@ -1,21 +1,16 @@ export NAME=kubeovn-webhook export NAMESPACE=cozy-kubeovn -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/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 \ --metadata-file images/kubeovn-webhook.json \ - --push=$(PUSH) \ - --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" - --load=$(LOAD) + $(BUILDX_ARGS) IMAGE="$(REGISTRY)/kubeovn-webhook:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/kubeovn-webhook.json -o json -r)" \ yq -i '.image = strenv(IMAGE)' values.yaml rm -f images/kubeovn-webhook.json diff --git a/packages/system/kubeovn-webhook/templates/certmanager.yaml b/packages/system/kubeovn-webhook/templates/certmanager.yaml index be0f5af1..f8eee740 100644 --- a/packages/system/kubeovn-webhook/templates/certmanager.yaml +++ b/packages/system/kubeovn-webhook/templates/certmanager.yaml @@ -18,6 +18,8 @@ spec: issuerRef: name: {{ include "namespace-annotation-webhook.fullname" . }}-selfsigned-issuer isCA: true + privateKey: + rotationPolicy: Never --- apiVersion: cert-manager.io/v1 kind: Issuer diff --git a/packages/system/kubeovn-webhook/values.yaml b/packages/system/kubeovn-webhook/values.yaml index 43c06e41..0c6ce81a 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.33.2@sha256:c7f42022280a565da8b3091ed2f4fe2768fcd392327d23172a532c24794787c6 +image: ghcr.io/cozystack/cozystack/kubeovn-webhook:v1.3.0@sha256:e18f9fd679e38f65362a8d0042f25468272f6d081136ad47027168d8e7e07a4a diff --git a/packages/system/kubeovn/Chart.yaml b/packages/system/kubeovn/Chart.yaml index 16cb9dc5..b1a4e05b 100644 --- a/packages/system/kubeovn/Chart.yaml +++ b/packages/system/kubeovn/Chart.yaml @@ -1,3 +1,3 @@ apiVersion: v2 name: cozy-kubeovn -version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process +version: 0.38.0 diff --git a/packages/system/kubeovn/Makefile b/packages/system/kubeovn/Makefile index a5e20a2a..45629042 100644 --- a/packages/system/kubeovn/Makefile +++ b/packages/system/kubeovn/Makefile @@ -1,39 +1,11 @@ -KUBEOVN_TAG=$(shell awk '$$1 == "version:" {print $$2}' charts/kube-ovn/Chart.yaml) - export NAME=kubeovn export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: - rm -rf charts && mkdir -p charts/kube-ovn - tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/kubeovn/kube-ovn | awk -F'[/^]' 'END{print $$3}') && \ - curl -sSL https://github.com/kubeovn/kube-ovn/archive/refs/tags/$${tag}.tar.gz | \ - 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 - sed -i "s/ARG TAG=.*/ARG TAG=$${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 \ - --cache-to type=inline \ - --metadata-file images/kubeovn.json \ - --push=$(PUSH) \ - --label "org.opencontainers.image.source=https://github.com/cozystack/cozystack" \ - --load=$(LOAD) - REGISTRY="$(REGISTRY)" \ - yq -i '.global.registry.address = strenv(REGISTRY)' values.yaml - REPOSITORY="kubeovn" \ - yq -i '.global.images.kubeovn.repository = strenv(REPOSITORY)' values.yaml - TAG="$(call settag,$(KUBEOVN_TAG))@$$(yq e '."containerimage.digest"' images/kubeovn.json -o json -r)" \ - yq -i '.global.images.kubeovn.tag = strenv(TAG)' values.yaml - rm -f images/kubeovn.json + rm -rf charts values.yaml Chart.yaml + tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/cozystack/kubeovn-chart | awk -F'[/^]' 'END{print $$3}') && \ + curl -sSL https://github.com/cozystack/kubeovn-chart/archive/refs/tags/$${tag}.tar.gz | \ + tar xzvf - --strip 2 kubeovn-chart-$${tag#*v}/chart diff --git a/packages/system/kubeovn/charts/kube-ovn/Chart.yaml b/packages/system/kubeovn/charts/kube-ovn/Chart.yaml index a15ea747..9c01c123 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.13 +version: v1.15.10 # 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.13" +appVersion: "1.15.10" -kubeVersion: ">= 1.23.0-0" +kubeVersion: ">= 1.29.0-0" diff --git a/packages/system/kubeovn/charts/kube-ovn/README.md b/packages/system/kubeovn/charts/kube-ovn/README.md index 3af408e6..74e5c3f1 100644 --- a/packages/system/kubeovn/charts/kube-ovn/README.md +++ b/packages/system/kubeovn/charts/kube-ovn/README.md @@ -2,6 +2,18 @@ Currently supported version: 1.9 +## Installing the Chart + +### From OCI Registry + +The Helm chart is available from GitHub Container Registry: + +```bash +helm install kube-ovn oci://ghcr.io/kubeovn/charts/kube-ovn --version v1.15.0 +``` + +### From Source + Installation : ```bash diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/_helpers.tpl b/packages/system/kubeovn/charts/kube-ovn/templates/_helpers.tpl index 1b9a0575..ce144769 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/_helpers.tpl +++ b/packages/system/kubeovn/charts/kube-ovn/templates/_helpers.tpl @@ -1,8 +1,10 @@ {{/* -Get IP-addresses of master nodes +Get IP-addresses of master nodes. If no nodes are returned, we assume this is +a dry-run/template call and return nothing. */}} {{- define "kubeovn.nodeIPs" -}} {{- $nodes := lookup "v1" "Node" "" "" -}} +{{- if $nodes -}} {{- $ips := list -}} {{- range $node := $nodes.items -}} {{- $label := splitList "=" $.Values.MASTER_NODES_LABEL }} @@ -20,8 +22,12 @@ Get IP-addresses of master nodes {{- end -}} {{- end -}} {{- end -}} +{{- if and (eq (len $ips) 0) (not $.Values.MASTER_NODES) -}} + {{- fail (printf "No nodes found with label '%s'. Please check your MASTER_NODES_LABEL configuration or ensure master nodes are properly labeled." $.Values.MASTER_NODES_LABEL) -}} +{{- end -}} {{ join "," $ips }} {{- end -}} +{{- end -}} {{/* Number of master nodes @@ -63,7 +69,9 @@ Number of master nodes {{- $imageVersion := (index $ds.spec.template.spec.containers 0).image | splitList ":" | last | trimPrefix "v" -}} {{- $versionRegex := `^(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)` -}} {{- if and (ne $newChartVersion $chartVersion) (regexMatch $versionRegex $imageVersion) -}} - {{- if regexFind $versionRegex $imageVersion | semverCompare ">= 1.13.0" -}} + {{- if regexFind $versionRegex $imageVersion | semverCompare ">= 1.15.0" -}} + 25.03 + {{- else if regexFind $versionRegex $imageVersion | semverCompare ">= 1.13.0" -}} 24.03 {{- else if regexFind $versionRegex $imageVersion | semverCompare ">= 1.12.0" -}} 22.12 diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/central-deploy.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/central-deploy.yaml index bbc1e09d..1bb0ece4 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/central-deploy.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/central-deploy.yaml @@ -39,7 +39,11 @@ spec: topologyKey: kubernetes.io/hostname priorityClassName: system-cluster-critical serviceAccountName: ovn-ovs + automountServiceAccountToken: true hostNetwork: true + securityContext: + seccompProfile: + type: RuntimeDefault initContainers: - name: hostpath-init image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} @@ -118,6 +122,7 @@ spec: limits: cpu: {{ index .Values "ovn-central" "limits" "cpu" }} memory: {{ index .Values "ovn-central" "limits" "memory" }} + ephemeral-storage: {{ index .Values "ovn-central" "limits" "ephemeral-storage" }} volumeMounts: - mountPath: /var/run/ovn name: host-run-ovn 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 2f5ef406..69e27b23 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/controller-deploy.yaml @@ -46,7 +46,11 @@ spec: topologyKey: kubernetes.io/hostname priorityClassName: system-cluster-critical serviceAccountName: ovn + automountServiceAccountToken: true hostNetwork: true + securityContext: + seccompProfile: + type: RuntimeDefault initContainers: - name: hostpath-init image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} @@ -70,21 +74,45 @@ spec: image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} imagePullPolicy: {{ .Values.image.pullPolicy }} args: - {{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} - /kube-ovn/start-controller.sh - --default-ls={{ .Values.networking.DEFAULT_SUBNET }} - - --default-cidr={{ index $cozyConfig.data "ipv4-pod-cidr" }} - - --default-gateway={{ index $cozyConfig.data "ipv4-pod-gateway" }} + - --default-cidr= + {{- if eq .Values.networking.NET_STACK "dual_stack" -}} + {{ .Values.dual_stack.POD_CIDR }} + {{- else if eq .Values.networking.NET_STACK "ipv4" -}} + {{ .Values.ipv4.POD_CIDR }} + {{- else if eq .Values.networking.NET_STACK "ipv6" -}} + {{ .Values.ipv6.POD_CIDR }} + {{- end }} + - --default-gateway= + {{- if eq .Values.networking.NET_STACK "dual_stack" -}} + {{ .Values.dual_stack.POD_GATEWAY }} + {{- else if eq .Values.networking.NET_STACK "ipv4" -}} + {{ .Values.ipv4.POD_GATEWAY }} + {{- else if eq .Values.networking.NET_STACK "ipv6" -}} + {{ .Values.ipv6.POD_GATEWAY }} + {{- end }} - --default-gateway-check={{- .Values.func.CHECK_GATEWAY }} - --default-logical-gateway={{- .Values.func.LOGICAL_GATEWAY }} - --default-u2o-interconnection={{- .Values.func.U2O_INTERCONNECTION }} - --default-exclude-ips={{- .Values.networking.EXCLUDE_IPS }} - --cluster-router={{ .Values.networking.DEFAULT_VPC }} - --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 }} + - --node-switch-cidr= + {{- if eq .Values.networking.NET_STACK "dual_stack" -}} + {{ .Values.dual_stack.JOIN_CIDR }} + {{- else if eq .Values.networking.NET_STACK "ipv4" -}} + {{ .Values.ipv4.JOIN_CIDR }} + {{- else if eq .Values.networking.NET_STACK "ipv6" -}} + {{ .Values.ipv6.JOIN_CIDR }} + {{- end }} + - --service-cluster-ip-range= + {{- if eq .Values.networking.NET_STACK "dual_stack" -}} + {{ .Values.dual_stack.SVC_CIDR }} + {{- else if eq .Values.networking.NET_STACK "ipv4" -}} + {{ .Values.ipv4.SVC_CIDR }} + {{- else if eq .Values.networking.NET_STACK "ipv6" -}} + {{ .Values.ipv6.SVC_CIDR }} {{- end }} - --network-type={{- .Values.networking.NETWORK_TYPE }} - --default-provider-name={{ .Values.networking.vlan.PROVIDER_NAME }} @@ -97,6 +125,7 @@ spec: - --pod-nic-type={{- .Values.networking.POD_NIC_TYPE }} - --enable-lb={{- .Values.func.ENABLE_LB }} - --enable-np={{- .Values.func.ENABLE_NP }} + - --np-enforcement={{- .Values.func.NP_ENFORCEMENT }} - --enable-eip-snat={{- .Values.networking.ENABLE_EIP_SNAT }} - --enable-external-vpc={{- .Values.func.ENABLE_EXTERNAL_VPC }} - --enable-ecmp={{- .Values.networking.ENABLE_ECMP }} @@ -113,8 +142,14 @@ spec: - --secure-serving={{- .Values.func.SECURE_SERVING }} - --enable-ovn-ipsec={{- .Values.func.ENABLE_OVN_IPSEC }} - --enable-anp={{- .Values.func.ENABLE_ANP }} + - --enable-dns-name-resolver={{- .Values.func.ENABLE_DNS_NAME_RESOLVER }} - --ovsdb-con-timeout={{- .Values.func.OVSDB_CON_TIMEOUT }} - --ovsdb-inactivity-timeout={{- .Values.func.OVSDB_INACTIVITY_TIMEOUT }} + - --enable-live-migration-optimize={{- .Values.func.ENABLE_LIVE_MIGRATION_OPTIMIZE }} + - --enable-ovn-lb-prefer-local={{- .Values.func.ENABLE_OVN_LB_PREFER_LOCAL }} + - --image={{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} + - --skip-conntrack-dst-cidrs={{- .Values.networking.SKIP_CONNTRACK_DST_CIDRS }} + - --non-primary-cni-mode={{- .Values.cni_conf.NON_PRIMARY_CNI }} securityContext: runAsUser: {{ include "kubeovn.runAsUser" . }} privileged: false @@ -133,11 +168,7 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace - - name: KUBE_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: KUBE_NODE_NAME + - name: NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName @@ -187,6 +218,7 @@ spec: limits: cpu: {{ index .Values "kube-ovn-controller" "limits" "cpu" }} memory: {{ index .Values "kube-ovn-controller" "limits" "memory" }} + ephemeral-storage: {{ index .Values "kube-ovn-controller" "limits" "ephemeral-storage" }} nodeSelector: kubernetes.io/os: "linux" volumes: diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ic-controller-deploy.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/ic-controller-deploy.yaml index 4dec76ee..dc932a63 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ic-controller-deploy.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ic-controller-deploy.yaml @@ -3,7 +3,7 @@ kind: Deployment apiVersion: apps/v1 metadata: name: ovn-ic-controller - namespace: kube-system + namespace: {{ .Values.namespace }} annotations: kubernetes.io/description: | OVN IC Client @@ -40,7 +40,11 @@ spec: topologyKey: kubernetes.io/hostname priorityClassName: system-cluster-critical serviceAccountName: ovn + automountServiceAccountToken: true hostNetwork: true + securityContext: + seccompProfile: + type: RuntimeDefault initContainers: - name: hostpath-init image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} @@ -96,6 +100,7 @@ spec: limits: cpu: 3 memory: 1Gi + ephemeral-storage: 1Gi volumeMounts: - mountPath: /var/run/ovn name: host-run-ovn @@ -109,7 +114,9 @@ spec: name: kube-ovn-log nodeSelector: kubernetes.io/os: "linux" - kube-ovn/role: "master" + {{- with splitList "=" .Values.MASTER_NODES_LABEL }} + {{ index . 0 }}: "{{ if eq (len .) 2 }}{{ index . 1 }}{{ end }}" + {{- end }} volumes: - name: host-run-ovn hostPath: diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/kube-ovn-crd.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/kube-ovn-crd.yaml index 1c858734..62ae328e 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/kube-ovn-crd.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/kube-ovn-crd.yaml @@ -37,10 +37,14 @@ spec: properties: vpc: type: string + description: VPC name for the DNS service. This field is immutable after creation. subnet: type: string + description: Subnet name for the DNS service. This field is immutable after creation. replicas: type: integer + description: Number of DNS server replicas (1-3) + format: int32 minimum: 1 maximum: 3 status: @@ -48,23 +52,31 @@ spec: properties: active: type: boolean + description: Whether the VPC DNS service is active conditions: type: array + description: Conditions represent the latest state of the VPC DNS items: type: object properties: type: type: string + description: Type of the condition status: type: string + description: Status of the condition (True, False, Unknown) reason: type: string + description: Reason for the condition's last transition message: type: string + description: Human-readable message indicating details about the condition lastUpdateTime: type: string + description: Last time this condition was updated lastTransitionTime: type: string + description: Last time the condition transitioned from one status to another --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -117,14 +129,20 @@ spec: properties: name: type: string + description: Port name port: type: integer + description: Service port number (1-65535) + format: int32 minimum: 1 maximum: 65535 protocol: type: string + description: Protocol (TCP or UDP) targetPort: type: integer + description: Target port number (1-65535) + format: int32 minimum: 1 maximum: 65535 type: object @@ -142,8 +160,10 @@ spec: properties: ports: type: string + description: Configured ports service: type: string + description: Associated service name --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -186,12 +206,15 @@ spec: items: type: string type: array + description: External subnets configured for the NAT gateway selector: type: array items: type: string + description: Pod selector configured for the NAT gateway qosPolicy: type: string + description: QoS policy applied to the NAT gateway tolerations: type: array items: @@ -204,6 +227,8 @@ spec: enum: - Equal - Exists + - Lt + - Gt value: type: string effect: @@ -213,6 +238,7 @@ spec: - NoSchedule - PreferNoSchedule tolerationSeconds: + format: int64 type: integer affinity: properties: @@ -257,8 +283,10 @@ spec: type: array type: object weight: - format: int32 type: integer + format: int32 + minimum: 1 + maximum: 100 required: - preference - weight @@ -321,8 +349,6 @@ spec: properties: key: type: string - x-kubernetes-patch-strategy: merge - x-kubernetes-patch-merge-key: key operator: type: string values: @@ -334,6 +360,9 @@ spec: - operator type: object type: array + x-kubernetes-list-type: map + x-kubernetes-list-map-keys: + - key matchLabels: additionalProperties: type: string @@ -349,8 +378,10 @@ spec: - topologyKey type: object weight: - format: int32 type: integer + format: int32 + minimum: 1 + maximum: 100 required: - podAffinityTerm - weight @@ -366,8 +397,6 @@ spec: properties: key: type: string - x-kubernetes-patch-strategy: merge - x-kubernetes-patch-merge-key: key operator: type: string values: @@ -379,6 +408,9 @@ spec: - operator type: object type: array + x-kubernetes-list-type: map + x-kubernetes-list-map-keys: + - key matchLabels: additionalProperties: type: string @@ -409,8 +441,6 @@ spec: properties: key: type: string - x-kubernetes-patch-strategy: merge - x-kubernetes-patch-merge-key: key operator: type: string values: @@ -422,6 +452,9 @@ spec: - operator type: object type: array + x-kubernetes-list-type: map + x-kubernetes-list-map-keys: + - key matchLabels: additionalProperties: type: string @@ -437,8 +470,10 @@ spec: - topologyKey type: object weight: - format: int32 type: integer + format: int32 + minimum: 1 + maximum: 100 required: - podAffinityTerm - weight @@ -454,8 +489,6 @@ spec: properties: key: type: string - x-kubernetes-patch-strategy: merge - x-kubernetes-patch-merge-key: key operator: type: string values: @@ -467,6 +500,9 @@ spec: - operator type: object type: array + x-kubernetes-list-type: map + x-kubernetes-list-map-keys: + - key matchLabels: additionalProperties: type: string @@ -489,45 +525,79 @@ spec: properties: lanIp: type: string + description: LAN IP address for the NAT gateway. This field is immutable after creation. subnet: type: string + description: Subnet name for the NAT gateway. This field is immutable after creation. externalSubnets: items: type: string type: array + description: External subnets accessible through the NAT gateway vpc: type: string + description: VPC name for the NAT gateway. This field is immutable after creation. selector: type: array items: type: string + description: Pod selector for the NAT gateway qosPolicy: type: string + description: QoS policy name to apply to the NAT gateway + noDefaultEIP: + type: boolean + description: Disable default EIP assignment bgpSpeaker: type: object + description: BGP speaker configuration properties: enabled: type: boolean + description: Enable BGP speaker asn: type: integer + format: uint32 + description: Local AS number remoteAsn: type: integer + format: uint32 + description: Remote AS number neighbors: type: array items: type: string + description: BGP neighbor IP addresses holdTime: type: string + description: BGP hold time routerId: type: string + description: BGP router ID password: type: string + description: BGP authentication password enableGracefulRestart: type: boolean + description: Enable BGP graceful restart extraArgs: type: array items: type: string + description: Extra BGP arguments + routes: + type: array + description: Static routes for the NAT gateway + items: + type: object + properties: + cidr: + type: string + format: cidr + description: Destination CIDR for the route + nextHopIP: + type: string + description: Next hop IP address tolerations: type: array items: @@ -540,6 +610,8 @@ spec: enum: - Equal - Exists + - Lt + - Gt value: type: string effect: @@ -549,6 +621,7 @@ spec: - NoSchedule - PreferNoSchedule tolerationSeconds: + format: int64 type: integer affinity: properties: @@ -593,8 +666,10 @@ spec: type: array type: object weight: - format: int32 type: integer + format: int32 + minimum: 1 + maximum: 100 required: - preference - weight @@ -657,8 +732,6 @@ spec: properties: key: type: string - x-kubernetes-patch-strategy: merge - x-kubernetes-patch-merge-key: key operator: type: string values: @@ -670,6 +743,9 @@ spec: - operator type: object type: array + x-kubernetes-list-type: map + x-kubernetes-list-map-keys: + - key matchLabels: additionalProperties: type: string @@ -685,8 +761,10 @@ spec: - topologyKey type: object weight: - format: int32 type: integer + format: int32 + minimum: 1 + maximum: 100 required: - podAffinityTerm - weight @@ -702,8 +780,6 @@ spec: properties: key: type: string - x-kubernetes-patch-strategy: merge - x-kubernetes-patch-merge-key: key operator: type: string values: @@ -715,6 +791,9 @@ spec: - operator type: object type: array + x-kubernetes-list-type: map + x-kubernetes-list-map-keys: + - key matchLabels: additionalProperties: type: string @@ -745,8 +824,6 @@ spec: properties: key: type: string - x-kubernetes-patch-strategy: merge - x-kubernetes-patch-merge-key: key operator: type: string values: @@ -758,6 +835,9 @@ spec: - operator type: object type: array + x-kubernetes-list-type: map + x-kubernetes-list-map-keys: + - key matchLabels: additionalProperties: type: string @@ -773,8 +853,10 @@ spec: - topologyKey type: object weight: - format: int32 type: integer + format: int32 + minimum: 1 + maximum: 100 required: - podAffinityTerm - weight @@ -790,8 +872,6 @@ spec: properties: key: type: string - x-kubernetes-patch-strategy: merge - x-kubernetes-patch-merge-key: key operator: type: string values: @@ -803,6 +883,9 @@ spec: - operator type: object type: array + x-kubernetes-list-type: map + x-kubernetes-list-map-keys: + - key matchLabels: additionalProperties: type: string @@ -823,6 +906,527 @@ spec: --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition +metadata: + name: vpc-egress-gateways.kubeovn.io +spec: + group: kubeovn.io + names: + plural: vpc-egress-gateways + singular: vpc-egress-gateway + shortNames: + - vpc-egress-gw + - veg + kind: VpcEgressGateway + listKind: VpcEgressGatewayList + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.vpc + name: VPC + type: string + - jsonPath: .spec.replicas + name: REPLICAS + type: integer + - jsonPath: .spec.bfd.enabled + name: BFD ENABLED + type: boolean + - jsonPath: .spec.externalSubnet + name: EXTERNAL SUBNET + type: string + - jsonPath: .status.phase + name: PHASE + type: string + - jsonPath: .status.ready + name: READY + type: boolean + - jsonPath: .status.internalIPs + name: INTERNAL IPS + priority: 1 + type: string + - jsonPath: .status.externalIPs + name: EXTERNAL IPS + priority: 1 + type: string + - jsonPath: .status.workload.nodes + name: WORKING NODES + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + name: v1 + served: true + storage: true + subresources: + status: {} + scale: + # specReplicasPath defines the JSONPath inside of a custom resource that corresponds to Scale.Spec.Replicas. + specReplicasPath: .spec.replicas + # statusReplicasPath defines the JSONPath inside of a custom resource that corresponds to Scale.Status.Replicas. + statusReplicasPath: .status.replicas + # labelSelectorPath defines the JSONPath inside of a custom resource that corresponds to Scale.Status.Selector. + labelSelectorPath: .status.labelSelector + schema: + openAPIV3Schema: + type: object + properties: + status: + properties: + replicas: + type: integer + format: int32 + minimum: 0 + maximum: 10 + description: Number of egress gateway replicas + labelSelector: + type: string + description: Label selector for the egress gateway + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + maxLength: 32768 + type: string + observedGeneration: + format: int64 + minimum: 0 + type: integer + reason: + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + enum: + - "True" + - "False" + - Unknown + type: string + type: + 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 + - lastUpdateTime + - observedGeneration + - reason + - status + - type + type: object + type: array + description: Conditions represent the latest available observations of the egress gateway's current state + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + internalIPs: + items: + type: string + type: array + description: Internal IP addresses assigned to the egress gateway + externalIPs: + items: + type: string + type: array + description: External IP addresses assigned to the egress gateway + phase: + type: string + description: Current phase of the egress gateway (Pending, Processing, or Completed) + default: Pending + enum: + - Pending + - Processing + - Completed + ready: + type: boolean + description: Indicates whether the egress gateway is ready + default: false + workload: + type: object + description: Workload information for the egress gateway + properties: + apiVersion: + type: string + kind: + type: string + name: + type: string + nodes: + type: array + items: + type: string + required: + - conditions + - phase + type: object + spec: + type: object + required: + - externalSubnet + x-kubernetes-validations: + - rule: "!has(self.internalIPs) || size(self.internalIPs) == 0 || size(self.internalIPs) >= self.replicas" + message: 'Size of Internal IPs MUST be equal to or greater than Replicas' + fieldPath: ".internalIPs" + - rule: "!has(self.externalIPs) || size(self.externalIPs) == 0 || size(self.externalIPs) >= self.replicas" + message: 'Size of External IPs MUST be equal to or greater than Replicas' + fieldPath: ".externalIPs" + - rule: "size(self.policies) != 0 || size(self.selectors) != 0" + message: 'Each VPC Egress Gateway MUST have at least one policy or selector' + properties: + replicas: + type: integer + format: int32 + default: 1 + minimum: 0 + maximum: 10 + description: Number of egress gateway replicas + prefix: + type: string + description: Name prefix for egress gateway pods. This field is immutable after creation. + anyOf: + - pattern: ^$ + - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*[-\.]?$ + x-kubernetes-validations: + - rule: "self == oldSelf" + message: "This field is immutable." + vpc: + type: string + description: VPC name for the egress gateway. This field is immutable after creation. + internalSubnet: + type: string + description: Internal subnet name for the egress gateway. This field is immutable after creation. + externalSubnet: + type: string + description: External subnet name for the egress gateway. This field is immutable after creation and is required. + internalIPs: + items: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + - pattern: ^(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5]),((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|:)))$ + - pattern: ^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|:))),(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])$ + type: array + x-kubernetes-list-type: set + description: Internal IP addresses for the egress gateway + externalIPs: + items: + type: string + oneOf: + - format: ipv4 + - format: ipv6 + - pattern: ^(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5]),((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|:)))$ + - pattern: ^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|:))),(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])$ + type: array + x-kubernetes-list-type: set + description: External IP addresses for the egress gateway + image: + type: string + description: Container image for the egress gateway + bfd: + type: object + description: BFD (Bidirectional Forwarding Detection) configuration + properties: + enabled: + type: boolean + default: false + minRX: + type: integer + format: int32 + default: 1000 + minimum: 1 + maximum: 3600000 + minTX: + type: integer + format: int32 + default: 1000 + minimum: 1 + maximum: 3600000 + multiplier: + type: integer + format: int32 + default: 3 + minimum: 1 + maximum: 3600000 + selectors: + type: array + description: Selectors for pods to use this egress gateway + items: + type: object + properties: + namespaceSelector: + type: object + properties: + matchLabels: + additionalProperties: + type: string + type: object + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + x-kubernetes-validations: + - rule: "size(self.matchLabels) != 0 || size(self.matchExpressions) != 0" + message: 'Each namespace selector MUST have at least one matchLabels or matchExpressions' + podSelector: + type: object + properties: + matchLabels: + additionalProperties: + type: string + type: object + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + x-kubernetes-validations: + - rule: "size(self.matchLabels) != 0 || size(self.matchExpressions) != 0" + message: 'Each pod selector MUST have at least one matchLabels or matchExpressions' + policies: + type: array + description: Egress policies for the gateway + items: + type: object + properties: + snat: + type: boolean + default: false + ipBlocks: + type: array + x-kubernetes-list-type: set + items: + type: string + anyOf: + - format: ipv4 + - format: ipv6 + - format: cidr + subnets: + type: array + x-kubernetes-list-type: set + items: + type: string + minLength: 1 + x-kubernetes-validations: + - rule: "size(self.ipBlocks) != 0 || size(self.subnets) != 0" + message: 'Each policy MUST have at least one ipBlock or subnet' + trafficPolicy: + type: string + description: Traffic policy for the egress gateway (Local or Cluster) + enum: + - Local + - Cluster + default: Cluster + nodeSelector: + type: array + description: Node selector for egress gateway placement + items: + type: object + properties: + matchLabels: + additionalProperties: + type: string + type: object + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + enum: + - In + - NotIn + - Exists + - DoesNotExist + - Gt + - Lt + values: + type: array + x-kubernetes-list-type: set + items: + type: string + required: + - key + - operator + matchFields: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + enum: + - In + - NotIn + - Exists + - DoesNotExist + - Gt + - Lt + values: + type: array + x-kubernetes-list-type: set + items: + type: string + required: + - key + - operator + tolerations: + description: optional tolerations applied to the workload pods + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + enum: + - NoSchedule + - PreferNoSchedule + - NoExecute + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators). + type: string + enum: + - Exists + - Equal + - Lt + - Gt + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + resources: + description: |- + `resources` are the compute resources required by this container. + For more information, see https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. + + This field depends on the DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + bandwidth: + type: object + description: Optional bandwidth limit for each egress gateway instance in both ingress and egress directions. + properties: + ingress: + type: integer + format: int64 + description: ingress bandwidth limit in Mbps + egress: + type: integer + format: int64 + description: egress bandwidth limit in Mbps +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition metadata: name: iptables-eips.kubeovn.io spec: @@ -866,46 +1470,64 @@ spec: properties: ready: type: boolean + description: Indicates whether the EIP is ready ip: type: string + description: IP address assigned to the EIP nat: type: string + description: NAT configuration status redo: type: string + description: Redo operation status qosPolicy: type: string + description: QoS policy applied to the EIP conditions: type: array + description: Conditions represent the latest available observations of the EIP's current state items: type: object properties: type: type: string + description: Type of condition status: type: string + description: Status of the condition (True, False, Unknown) reason: type: string + description: Reason for the condition's last transition message: type: string + description: Human-readable message indicating details about the condition lastUpdateTime: type: string + description: Last time this condition was updated lastTransitionTime: type: string + description: Last time the condition transitioned from one status to another spec: type: object properties: v4ip: type: string + description: IPv4 address for the EIP v6ip: type: string + description: IPv6 address for the EIP macAddress: type: string + description: MAC address for the EIP natGwDp: type: string + description: NAT gateway datapath where the EIP is assigned qosPolicy: type: string + description: QoS policy name to apply to the EIP externalSubnet: type: string + description: External subnet name. This field is immutable after creation. --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -955,40 +1577,55 @@ spec: properties: ready: type: boolean + description: Indicates whether the FIP rule is ready v4ip: type: string + description: IPv4 address of the EIP v6ip: type: string + description: IPv6 address of the EIP natGwDp: type: string + description: NAT gateway datapath where the FIP is configured redo: type: string + description: Redo operation status internalIp: type: string + description: Internal IP address mapped to the FIP conditions: type: array + description: Conditions represent the latest available observations of the FIP rule's current state items: type: object properties: type: type: string + description: Type of condition status: type: string + description: Status of the condition (True, False, Unknown) reason: type: string + description: Reason for the condition's last transition message: type: string + description: Human-readable message indicating details about the condition lastUpdateTime: type: string + description: Last time this condition was updated lastTransitionTime: type: string + description: Last time the condition transitioned from one status to another spec: type: object properties: eip: type: string + description: EIP name to use for floating IP internalIp: type: string + description: Internal IP address to map to the floating IP --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -1047,52 +1684,73 @@ spec: properties: ready: type: boolean + description: Indicates whether the DNAT rule is ready v4ip: type: string + description: IPv4 address of the EIP v6ip: type: string + description: IPv6 address of the EIP natGwDp: type: string + description: NAT gateway datapath where the DNAT rule is configured redo: type: string + description: Redo operation status protocol: type: string + description: Protocol type of the DNAT rule internalIp: type: string + description: Internal IP address configured in the DNAT rule internalPort: type: string + description: Internal port configured in the DNAT rule externalPort: type: string + description: External port configured in the DNAT rule conditions: type: array + description: Conditions represent the latest available observations of the DNAT rule's current state items: type: object properties: type: type: string + description: Type of condition status: type: string + description: Status of the condition (True, False, Unknown) reason: type: string + description: Reason for the condition's last transition message: type: string + description: Human-readable message indicating details about the condition lastUpdateTime: type: string + description: Last time this condition was updated lastTransitionTime: type: string + description: Last time the condition transitioned from one status to another spec: type: object properties: eip: type: string + description: EIP name for DNAT rule externalPort: type: string + description: External port number protocol: type: string + description: Protocol type (TCP or UDP) internalIp: type: string + description: Internal IP address to forward traffic to internalPort: type: string + description: Internal port number to forward traffic to --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -1142,40 +1800,55 @@ spec: properties: ready: type: boolean + description: Indicates whether the SNAT rule is ready v4ip: type: string + description: IPv4 address of the EIP v6ip: type: string + description: IPv6 address of the EIP natGwDp: type: string + description: NAT gateway datapath where the SNAT rule is configured redo: type: string + description: Redo operation status internalCIDR: type: string + description: Internal CIDR configured in the SNAT rule conditions: type: array + description: Conditions represent the latest available observations of the SNAT rule's current state items: type: object properties: type: type: string + description: Type of condition status: type: string + description: Status of the condition (True, False, Unknown) reason: type: string + description: Reason for the condition's last transition message: type: string + description: Human-readable message indicating details about the condition lastUpdateTime: type: string + description: Last time this condition was updated lastTransitionTime: type: string + description: Last time the condition transitioned from one status to another spec: type: object properties: eip: type: string + description: EIP name for SNAT rule internalCIDR: type: string + description: Internal CIDR to be translated via SNAT --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -1228,46 +1901,64 @@ spec: properties: type: type: string + description: Type of the OVN EIP nat: type: string + description: NAT configuration status ready: type: boolean + description: Indicates whether the EIP is ready v4Ip: type: string + description: IPv4 address assigned to the EIP v6Ip: type: string + description: IPv6 address assigned to the EIP macAddress: type: string + description: MAC address assigned to the EIP conditions: type: array + description: Conditions represent the latest available observations of the EIP's current state items: type: object properties: type: type: string + description: Type of condition status: type: string + description: Status of the condition (True, False, Unknown) reason: type: string + description: Reason for the condition's last transition message: type: string + description: Human-readable message indicating details about the condition lastUpdateTime: type: string + description: Last time this condition was updated lastTransitionTime: type: string + description: Last time the condition transitioned from one status to another spec: type: object properties: externalSubnet: type: string + description: External subnet name. This field is immutable after creation. type: type: string + description: Type of the OVN EIP (e.g., normal, distributed) v4Ip: type: string + description: IPv4 address for the EIP v6Ip: type: string + description: IPv6 address for the EIP macAddress: type: string + description: MAC address for the EIP --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -1293,6 +1984,9 @@ spec: - jsonPath: .status.vpc name: Vpc type: string + - jsonPath: .spec.type + name: Type + type: string - jsonPath: .status.v4Eip name: V4Eip type: string @@ -1323,48 +2017,70 @@ spec: properties: ready: type: boolean + description: Indicates whether the FIP is ready v4Eip: type: string + description: IPv4 EIP address assigned v6Eip: type: string + description: IPv6 EIP address assigned v4Ip: type: string + description: IPv4 address mapped to the FIP v6Ip: type: string + description: IPv6 address mapped to the FIP vpc: type: string + description: VPC name where the FIP is configured conditions: type: array + description: Conditions represent the latest available observations of the FIP's current state items: type: object properties: type: type: string + description: Type of condition status: type: string + description: Status of the condition (True, False, Unknown) reason: type: string + description: Reason for the condition's last transition message: type: string + description: Human-readable message indicating details about the condition lastUpdateTime: type: string + description: Last time this condition was updated lastTransitionTime: type: string + description: Last time the condition transitioned from one status to another spec: type: object properties: ovnEip: type: string + description: OVN EIP name to use for floating IP ipType: type: string + description: IP type (e.g., ipv4, ipv6, dual) + type: + type: string + description: FIP type ipName: type: string + description: IP resource name vpc: type: string + description: VPC name. This field is immutable after creation. v4Ip: type: string + description: IPv4 address for the floating IP v6Ip: type: string + description: IPv6 address for the floating IP --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -1414,48 +2130,67 @@ spec: properties: ready: type: boolean + description: Indicates whether the SNAT rule is ready v4Eip: type: string + description: IPv4 EIP address assigned v6Eip: type: string + description: IPv6 EIP address assigned v4IpCidr: type: string + description: IPv4 CIDR configured in the SNAT rule v6IpCidr: type: string + description: IPv6 CIDR configured in the SNAT rule vpc: type: string + description: VPC name where the SNAT rule is configured conditions: type: array + description: Conditions represent the latest available observations of the SNAT rule's current state items: type: object properties: type: type: string + description: Type of condition status: type: string + description: Status of the condition (True, False, Unknown) reason: type: string + description: Reason for the condition's last transition message: type: string + description: Human-readable message indicating details about the condition lastUpdateTime: type: string + description: Last time this condition was updated lastTransitionTime: type: string + description: Last time the condition transitioned from one status to another spec: type: object properties: ovnEip: type: string + description: OVN EIP name for SNAT rule vpcSubnet: type: string + description: VPC subnet name for SNAT ipName: type: string + description: IP resource name vpc: type: string + description: VPC name. This field is immutable after creation. v4IpCidr: type: string + description: IPv4 CIDR for SNAT v6IpCidr: type: string + description: IPv6 CIDR for SNAT --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -1520,62 +2255,88 @@ spec: properties: ready: type: boolean + description: Indicates whether the DNAT rule is ready v4Eip: type: string + description: IPv4 EIP address assigned v6Eip: type: string + description: IPv6 EIP address assigned v4Ip: type: string + description: IPv4 address configured in the DNAT rule v6Ip: type: string + description: IPv6 address configured in the DNAT rule vpc: type: string + description: VPC name where the DNAT rule is configured externalPort: type: string + description: External port configured in the DNAT rule internalPort: type: string + description: Internal port configured in the DNAT rule protocol: type: string + description: Protocol type configured in the DNAT rule ipName: type: string + description: IP resource name conditions: type: array + description: Conditions represent the latest available observations of the DNAT rule's current state items: type: object properties: type: type: string + description: Type of condition status: type: string + description: Status of the condition (True, False, Unknown) reason: type: string + description: Reason for the condition's last transition message: type: string + description: Human-readable message indicating details about the condition lastUpdateTime: type: string + description: Last time this condition was updated lastTransitionTime: type: string + description: Last time the condition transitioned from one status to another spec: type: object properties: ovnEip: type: string + description: OVN EIP name for DNAT rule ipType: type: string + description: IP type (e.g., ipv4, ipv6, dual) ipName: type: string + description: IP resource name externalPort: type: string + description: External port number internalPort: type: string + description: Internal port number to forward traffic to protocol: type: string + description: Protocol type (TCP or UDP) vpc: type: string + description: VPC name. This field is immutable after creation. v4Ip: type: string + description: IPv4 address for DNAT v6Ip: type: string + description: IPv6 address for DNAT --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -1614,19 +2375,25 @@ spec: properties: defaultSubnet: type: string + description: The default subnet name for the VPC enableExternal: type: boolean + description: Enable external network access for the VPC enableBfd: type: boolean + description: Enable BFD (Bidirectional Forwarding Detection) for the VPC namespaces: + description: List of namespaces that can use this VPC items: type: string type: array extraExternalSubnets: + description: Extra external subnets for provider-network VLAN. Immutable after creation. items: type: string type: array staticRoutes: + description: Static routes for the VPC. items: properties: policy: @@ -1644,10 +2411,14 @@ spec: type: object type: array policyRoutes: + description: Policy routes for the VPC. items: properties: priority: type: integer + description: Priority of the policy route (0-32767) + min: 0 + max: 32767 action: type: string match: @@ -1657,6 +2428,7 @@ spec: type: object type: array vpcPeerings: + description: VPC peering configurations. items: properties: remoteVpc: @@ -1665,6 +2437,55 @@ spec: type: string type: object type: array + bfdPort: + properties: + enabled: + type: boolean + description: Enable BFD port + default: false + ip: + type: string + description: IP address for BFD port (IPv4, IPv6, or comma-separated pair) + anyOf: + - pattern: ^$ + - pattern: ^(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])$ + - pattern: ^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|:)))$ + - pattern: ^(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5]),((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|:)))$ + - pattern: ^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|:))),(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])$ + nodeSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + description: Label key + operator: + type: string + description: Label operator + enum: + - In + - NotIn + - Exists + - DoesNotExist + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: object + x-kubernetes-validations: + - rule: "self.enabled == false || self.ip != ''" + message: 'Port IP must be set when BFD Port is enabled' type: object status: properties: @@ -1686,6 +2507,7 @@ spec: type: object type: array default: + description: Whether this is the default subnet. type: boolean defaultLogicalSwitch: type: string @@ -1702,10 +2524,12 @@ spec: type: string type: array extraExternalSubnets: + description: Extra external subnets for provider-network VLAN. Immutable after creation. items: type: string type: array vpcPeerings: + description: VPC peering configurations. items: type: string type: array @@ -1721,6 +2545,20 @@ spec: type: string sctpSessionLoadBalancer: type: string + bfdPort: + type: object + properties: + ip: + type: string + description: BFD port IP address + name: + type: string + description: BFD port name + nodes: + type: array + description: Nodes where BFD port is deployed + items: + type: string type: object type: object served: true @@ -1771,36 +2609,49 @@ spec: properties: podName: type: string + description: Pod name that this IP belongs to namespace: type: string + description: Namespace of the pod subnet: type: string + description: Primary subnet name for the IP. This field is immutable after creation. attachSubnets: type: array + description: Additional attached subnets items: type: string nodeName: type: string + description: Node name where the pod resides ipAddress: type: string + description: IP address (deprecated, use v4IpAddress or v6IpAddress) v4IpAddress: type: string + description: IPv4 address v6IpAddress: type: string + description: IPv6 address attachIps: type: array + description: Additional IP addresses from attached subnets items: type: string macAddress: type: string + description: MAC address for the primary IP attachMacs: type: array + description: MAC addresses for attached IPs items: type: string containerID: type: string + description: Container ID podType: type: string + description: Pod type (e.g., pod, vm) scope: Cluster names: plural: ips @@ -1828,6 +2679,9 @@ spec: served: true storage: true additionalPrinterColumns: + - name: Namespace + type: string + jsonPath: .spec.namespace - name: V4IP type: string jsonPath: .status.v4ip @@ -1837,18 +2691,12 @@ spec: - name: Mac type: string jsonPath: .status.mac - - name: PMac - type: string - jsonPath: .spec.parentMac - name: Subnet type: string jsonPath: .spec.subnet - - jsonPath: .status.ready - name: Ready - type: boolean - - jsonPath: .status.type - name: Type + - name: Type type: string + jsonPath: .status.type schema: openAPIV3Schema: type: object @@ -1858,68 +2706,74 @@ spec: properties: type: type: string - ready: - type: boolean + description: Type of VIP (e.g., Layer2, HealthCheck) v4ip: type: string + description: Allocated IPv4 address v6ip: type: string + description: Allocated IPv6 address mac: type: string - pv4ip: - type: string - pv6ip: - type: string - pmac: - type: string + description: MAC address associated with the VIP selector: type: array + description: Pod names selected by this VIP items: type: string conditions: type: array + description: Conditions represent the latest state of the VIP items: type: object properties: type: type: string + description: Type of the condition status: type: string + description: Status of the condition (True, False, Unknown) reason: type: string + description: Reason for the condition's last transition message: type: string + description: Human-readable message indicating details about the condition lastUpdateTime: type: string + description: Last time this condition was updated lastTransitionTime: type: string + description: Last time the condition transitioned from one status to another spec: type: object properties: namespace: type: string + description: Namespace where the VIP is created. This field is immutable after creation. subnet: type: string + description: Subnet name for the VIP. This field is immutable after creation. type: type: string + description: Type of VIP. This field is immutable after creation. attachSubnets: type: array + description: Additional subnets to attach items: type: string v4ip: type: string + description: Specific IPv4 address to use (optional, will be allocated if not specified) macAddress: type: string + description: MAC address for the VIP v6ip: type: string - parentV4ip: - type: string - parentMac: - type: string - parentV6ip: - type: string + description: Specific IPv6 address to use (optional, will be allocated if not specified) selector: type: array + description: Pod names to be selected by this VIP items: type: string --- @@ -2009,6 +2863,7 @@ spec: dhcpV6OptionsUUID: type: string u2oInterconnectionIP: + description: Underlay to overlay interconnection IP. type: string u2oInterconnectionMAC: type: string @@ -2027,6 +2882,7 @@ spec: v6availableIPrange: type: string natOutgoingPolicyRules: + description: NAT outgoing policy rules. type: array items: type: object @@ -2066,50 +2922,89 @@ spec: type: object properties: vpc: + description: VPC name for the subnet. Immutable after creation. type: string default: + description: Whether this is the default subnet. type: boolean protocol: + description: Network protocol (IPv4, IPv6, or Dual). Immutable after creation. type: string enum: - IPv4 - IPv6 - Dual cidrBlock: + description: CIDR block for the subnet. Immutable after creation. type: string namespaces: + description: List of namespaces associated with this subnet. type: array items: type: string gateway: + description: Gateway IP address for the subnet. type: string provider: + description: Provider network name. type: string excludeIps: + description: IP addresses to exclude from allocation. type: array items: type: string vips: + description: Virtual IP addresses for the subnet. type: array items: type: string gatewayType: + description: Gateway type (distributed or centralized). type: string allowSubnets: + description: Allowed subnets for east-west traffic. type: array items: type: string gatewayNode: + description: Gateway node for centralized gateway mode. type: string + gatewayNodeSelectors: + description: Node selectors for gateway placement. + type: array + items: + type: object + properties: + matchLabels: + type: object + additionalProperties: + type: string + matchExpressions: + type: array + items: + type: object + properties: + key: + type: string + operator: + type: string + values: + type: array + items: + type: string natOutgoing: + description: Enable NAT for outgoing traffic. type: boolean externalEgressGateway: + description: External egress gateway for the subnet. type: string policyRoutingPriority: + description: Policy routing priority. type: integer minimum: 1 maximum: 32765 policyRoutingTableID: + description: Policy routing table ID. type: integer minimum: 1 maximum: 2147483647 @@ -2120,32 +3015,45 @@ spec: - 254 # main - 255 # local mtu: + description: Maximum transmission unit for the subnet. type: integer minimum: 68 maximum: 65535 private: + description: Whether the subnet is private. type: boolean vlan: + description: VLAN ID for the subnet. Immutable after creation. type: string logicalGateway: + description: Whether to use logical gateway. type: boolean disableGatewayCheck: + description: Disable gateway connectivity check. type: boolean disableInterConnection: + description: Disable subnet interconnection. type: boolean enableDHCP: + description: Enable DHCP for the subnet. type: boolean dhcpV4Options: + description: DHCPv4 options for the subnet. type: string dhcpV6Options: + description: DHCPv6 options for the subnet. type: string enableIPv6RA: + description: Enable IPv6 router advertisement. type: boolean ipv6RAConfigs: + description: IPv6 router advertisement configurations. type: string allowEWTraffic: + description: Allow east-west traffic between pods. type: boolean acls: + description: Access control lists for the subnet. type: array items: type: object @@ -2170,6 +3078,7 @@ spec: - drop - reject natOutgoingPolicyRules: + description: NAT outgoing policy rules. type: array items: type: object @@ -2187,18 +3096,28 @@ spec: dstIPs: type: string u2oInterconnection: + description: Enable underlay to overlay interconnection. type: boolean u2oInterconnectionIP: + description: Underlay to overlay interconnection IP. type: string enableLb: + description: Enable load balancer for the subnet. type: boolean enableEcmp: + description: Enable ECMP for the subnet. type: boolean enableMulticastSnoop: + description: Enable multicast snooping. + type: boolean + enableExternalLBAddress: + description: Enable external load balancer address. type: boolean routeTable: + description: Route table for the subnet. type: string namespaceSelectors: + description: Namespace selectors for subnet association. type: array items: type: object @@ -2220,6 +3139,9 @@ spec: type: array items: type: string + nodeNetwork: + description: Node network for the subnet. + type: string scope: Cluster names: plural: subnets @@ -2244,6 +3166,9 @@ spec: - name: Subnet type: string jsonPath: .spec.subnet + - name: enableAddressSet + type: boolean + jsonPath: .spec.enableAddressSet - name: IPs type: string jsonPath: .spec.ips @@ -2268,10 +3193,12 @@ spec: properties: subnet: type: string + description: Subnet name for the IP pool. This field is immutable. x-kubernetes-validations: - rule: "self == oldSelf" message: "This field is immutable." namespaces: + description: Namespaces that can use this IP pool type: array x-kubernetes-list-type: set items: @@ -2280,6 +3207,7 @@ spec: type: array minItems: 1 x-kubernetes-list-type: set + description: IP addresses or ranges in the pool (IPv4/IPv6 addresses or CIDR ranges) items: type: string anyOf: @@ -2288,6 +3216,10 @@ spec: - format: cidr - pattern: ^(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.\.(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])$ - pattern: ^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|:)))\.\.((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|:)))$ + enableAddressSet: + type: boolean + default: false + description: EnableAddressSet to work with policy-based routing and ACL required: - subnet - ips @@ -2296,37 +3228,52 @@ spec: properties: v4AvailableIPs: type: number + description: Number of available IPv4 addresses v4UsingIPs: type: number + description: Number of using IPv4 addresses v6AvailableIPs: type: number + description: Number of available IPv6 addresses v6UsingIPs: type: number + description: Number of using IPv6 addresses v4AvailableIPRange: type: string + description: Available IPv4 address range v4UsingIPRange: type: string + description: IPv4 address range in use v6AvailableIPRange: type: string + description: Available IPv6 address range v6UsingIPRange: type: string + description: IPv6 address range in use conditions: type: array + description: Conditions represent the latest state of the IP pool items: type: object properties: type: type: string + description: Type of the condition status: type: string + description: Status of the condition (True, False, Unknown) reason: type: string + description: Reason for the condition's last transition message: type: string + description: Human-readable message indicating details about the condition lastUpdateTime: type: string + description: Last time this condition was updated lastTransitionTime: type: string + description: Last time the condition transitioned from one status to another scope: Cluster names: plural: ippools @@ -2356,10 +3303,12 @@ spec: properties: id: type: integer + description: VLAN ID (0-4095). This field is immutable after creation. minimum: 0 maximum: 4095 provider: type: string + description: Provider network name. This field is immutable after creation. vlanId: type: integer description: Deprecated in favor of id @@ -2373,8 +3322,12 @@ spec: properties: subnets: type: array + description: List of subnet names using this VLAN items: type: string + conflict: + type: boolean + description: Whether there is a conflict with this VLAN additionalPrinterColumns: - name: ID type: string @@ -2382,6 +3335,9 @@ spec: - name: Provider type: string jsonPath: .spec.provider + - name: conflict + type: boolean + jsonPath: .status.conflict scope: Cluster names: plural: vlans @@ -2420,27 +3376,69 @@ spec: properties: defaultInterface: type: string + description: Default interface name for the provider network. This field is immutable after creation. maxLength: 15 pattern: '^[^/\s]+$' customInterfaces: type: array + description: Custom interface configurations for specific nodes items: type: object properties: interface: type: string + description: Interface name maxLength: 15 pattern: '^[^/\s]+$' nodes: type: array + description: Nodes that use this custom interface items: type: string exchangeLinkName: type: boolean + nodeSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: map + x-kubernetes-list-map-keys: + - key + matchLabels: + additionalProperties: + type: string + type: object + type: object excludeNodes: type: array items: type: string + autoCreateVlanSubinterfaces: + type: boolean + description: Automatically create VLAN subinterfaces + preserveVlanInterfaces: + type: boolean + description: Enable automatic detection and preservation of VLAN interfaces + vlanInterfaces: + type: array + items: + type: string + pattern: '^[a-zA-Z0-9_-]+\.[0-9]{1,4}$' + description: Optional explicit list of VLAN interface names to preserve (e.g., eth0.10, bond0.20) required: - defaultInterface status: @@ -2448,37 +3446,49 @@ spec: properties: ready: type: boolean + description: Whether the provider network is ready readyNodes: type: array + description: Nodes that are ready items: type: string notReadyNodes: type: array + description: Nodes that are not ready items: type: string vlans: type: array + description: VLANs in use by this provider network items: type: string conditions: type: array + description: Conditions of nodes in the provider network items: type: object properties: node: type: string + description: Node name type: type: string + description: Type of the condition status: type: string + description: Status of the condition reason: type: string + description: Reason for the condition message: type: string + description: Message about the condition lastUpdateTime: type: string + description: Last update time lastTransitionTime: type: string + description: Last transition time additionalPrinterColumns: - name: DefaultInterface type: string @@ -2520,67 +3530,106 @@ spec: properties: ingressRules: type: array + description: Ingress traffic rules for the security group items: type: object properties: ipVersion: type: string + description: IP version (IPv4 or IPv6) protocol: type: string + description: Protocol (tcp, udp, icmp, or all) priority: type: integer + description: Rule priority (1-200) + min: 1 + max: 200 remoteType: type: string + description: Type of remote (address, cidr, or securityGroup) remoteAddress: type: string + description: Remote address or CIDR remoteSecurityGroup: type: string + description: Remote security group name portRangeMin: type: integer + description: Start of port range (1-65535) + min: 1 + max: 65535 portRangeMax: type: integer + description: End of port range (1-65535) + min: 1 + max: 65535 policy: type: string + description: Policy action (allow or deny) egressRules: type: array + description: Egress traffic rules for the security group items: type: object properties: ipVersion: type: string + description: IP version (IPv4 or IPv6) protocol: type: string + description: Protocol (tcp, udp, icmp, or all) priority: type: integer + description: Rule priority (1-200) + min: 1 + max: 200 remoteType: type: string + description: Type of remote (address, cidr, or securityGroup) remoteAddress: type: string + description: Remote address or CIDR remoteSecurityGroup: type: string + description: Remote security group name portRangeMin: type: integer + description: Start of port range (1-65535) + min: 1 + max: 65535 portRangeMax: type: integer + description: End of port range (1-65535) + min: 1 + max: 65535 policy: type: string + description: Policy action (allow or deny) allowSameGroupTraffic: type: boolean + description: Allow traffic between pods in the same security group status: type: object properties: portGroup: type: string + description: OVN port group name allowSameGroupTraffic: type: boolean + description: Current allow same group traffic setting ingressMd5: type: string + description: MD5 hash of ingress rules egressMd5: type: string + description: MD5 hash of egress rules ingressLastSyncSuccess: type: boolean + description: Last ingress sync success status egressLastSyncSuccess: type: boolean + description: Last egress sync success status subresources: status: {} conversion: @@ -2622,74 +3671,103 @@ spec: properties: shared: type: boolean + description: Whether the QoS policy is shared bindingType: type: string + description: Binding type of the QoS policy bandwidthLimitRules: type: array + description: Active bandwidth limit rules items: type: object properties: name: type: string + description: Rule name interface: type: string + description: Interface name rateMax: type: string + description: Maximum rate (e.g., 100Mbps) burstMax: type: string + description: Maximum burst rate priority: type: integer + description: Rule priority direction: type: string + description: Traffic direction (ingress/egress) matchType: type: string + description: Match type matchValue: type: string + description: Match value conditions: type: array + description: Conditions of the QoS policy items: type: object properties: type: type: string + description: Type of the condition status: type: string + description: Status of the condition (True, False, Unknown) reason: type: string + description: Reason for the condition's last transition message: type: string + description: Human-readable message indicating details about the condition lastUpdateTime: type: string + description: Last time this condition was updated lastTransitionTime: type: string + description: Last time the condition transitioned from one status to another spec: type: object properties: shared: type: boolean + description: Whether the QoS policy is shared across multiple pods bindingType: type: string + description: Binding type (e.g., pod, namespace) bandwidthLimitRules: type: array + description: Bandwidth limit rules to apply items: type: object properties: name: type: string + description: Rule name interface: type: string + description: Network interface to apply the rule rateMax: type: string + description: Maximum rate (e.g., 100Mbps, 1Gbps) burstMax: type: string + description: Maximum burst rate priority: type: integer + description: Rule priority for ordering direction: type: string + description: Traffic direction (ingress or egress) matchType: type: string + description: Type of traffic matching (e.g., pod, namespace) matchValue: type: string + description: Value to match for the rule required: - name x-kubernetes-list-map-keys: diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/monitor-deploy.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/monitor-deploy.yaml index e4c3322c..2d498098 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/monitor-deploy.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/monitor-deploy.yaml @@ -37,7 +37,11 @@ spec: topologyKey: kubernetes.io/hostname priorityClassName: system-cluster-critical serviceAccountName: kube-ovn-app + automountServiceAccountToken: true hostNetwork: true + securityContext: + seccompProfile: + type: RuntimeDefault initContainers: - name: hostpath-init image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} @@ -77,7 +81,7 @@ spec: env: - name: ENABLE_SSL value: "{{ .Values.networking.ENABLE_SSL }}" - - name: KUBE_NODE_NAME + - name: NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName @@ -106,6 +110,7 @@ spec: limits: cpu: {{ index .Values "kube-ovn-monitor" "limits" "cpu" }} memory: {{ index .Values "kube-ovn-monitor" "limits" "memory" }} + ephemeral-storage: {{ index .Values "kube-ovn-monitor" "limits" "ephemeral-storage" }} volumeMounts: - mountPath: /var/run/ovn name: host-run-ovn diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ovn-CR.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/ovn-CR.yaml index a0f7a26a..1caaecdf 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ovn-CR.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovn-CR.yaml @@ -13,6 +13,8 @@ rules: - vpcs/status - vpc-nat-gateways - vpc-nat-gateways/status + - vpc-egress-gateways + - vpc-egress-gateways/status - subnets - subnets/status - ippools @@ -46,10 +48,18 @@ rules: - switch-lb-rules/status - vpc-dnses - vpc-dnses/status + - dnsnameresolvers + - dnsnameresolvers/status - qos-policies - qos-policies/status verbs: - - "*" + - create + - get + - list + - update + - patch + - watch + - delete - apiGroups: - "" resources: @@ -82,6 +92,8 @@ rules: - network-attachment-definitions verbs: - get + - list + - watch - apiGroups: - "" - networking.k8s.io @@ -98,6 +110,18 @@ rules: - daemonsets verbs: - get + - apiGroups: + - apps + resources: + - deployments + - deployments/scale + verbs: + - get + - list + - watch + - create + - update + - delete - apiGroups: - "" resources: @@ -121,12 +145,18 @@ rules: - get - list - watch + - apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - list + - watch - apiGroups: - apps resources: - statefulsets - - deployments - - deployments/scale verbs: - get - list @@ -146,7 +176,11 @@ rules: resources: - leases verbs: - - "*" + - create + - update + - patch + - get + - watch - apiGroups: - "kubevirt.io" resources: @@ -155,11 +189,13 @@ rules: verbs: - get - list + - watch - apiGroups: - "policy.networking.k8s.io" resources: - adminnetworkpolicies - baselineadminnetworkpolicies + - clusternetworkpolicies verbs: - get - list @@ -240,9 +276,14 @@ rules: - "" resources: - services - - endpoints verbs: - get + - apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - list - apiGroups: - apps resources: @@ -250,7 +291,6 @@ rules: verbs: - get - list - --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -278,6 +318,7 @@ rules: - nodes - nodes/status - pods + - services verbs: - get - list @@ -328,12 +369,23 @@ rules: - "list" - "watch" - "delete" - - apiGroups: - - "" - resources: - - "secrets" - verbs: - - "get" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: secret-reader-ovn-ipsec + namespace: {{ .Values.namespace }} +rules: +- apiGroups: + - "" + resources: + - "secrets" + resourceNames: + - "ovn-ipsec-ca" + verbs: + - "get" + - "list" + - "watch" --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ovn-CRB.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/ovn-CRB.yaml index 7cc43d84..638093ba 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ovn-CRB.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovn-CRB.yaml @@ -67,6 +67,20 @@ subjects: namespace: {{ .Values.namespace }} --- apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: kube-ovn-cni-secret-reader + namespace: {{ .Values.namespace }} +subjects: +- kind: ServiceAccount + name: kube-ovn-cni + namespace: {{ .Values.namespace }} +roleRef: + kind: Role + name: secret-reader-ovn-ipsec + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kube-ovn-app diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ovn-dpdk-ds.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/ovn-dpdk-ds.yaml index c46e3389..5e18230e 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ovn-dpdk-ds.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovn-dpdk-ds.yaml @@ -27,11 +27,15 @@ spec: - operator: Exists priorityClassName: system-node-critical serviceAccountName: ovn-ovs + automountServiceAccountToken: true hostNetwork: true hostPID: true + securityContext: + seccompProfile: + type: RuntimeDefault containers: - name: openvswitch - image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }}-dpdk + image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.DPDK_IMAGE_TAG }} imagePullPolicy: {{ .Values.image.pullPolicy }} command: ["/kube-ovn/start-ovs-dpdk-v2.sh"] securityContext: @@ -50,7 +54,7 @@ spec: value: "{{- .Values.networking.TUNNEL_TYPE }}" - name: DPDK_TUNNEL_IFACE value: "{{- .Values.networking.DPDK_TUNNEL_IFACE }}" - - name: KUBE_NODE_NAME + - name: NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/ovn-sa.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/ovn-sa.yaml index 1e5e9b5c..744b3b90 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ovn-sa.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovn-sa.yaml @@ -3,6 +3,7 @@ kind: ServiceAccount metadata: name: ovn namespace: {{ .Values.namespace }} +automountServiceAccountToken: false {{- if .Values.global.registry.imagePullSecrets }} imagePullSecrets: {{- range $index, $secret := .Values.global.registry.imagePullSecrets }} @@ -18,6 +19,7 @@ kind: ServiceAccount metadata: name: ovn-ovs namespace: {{ .Values.namespace }} +automountServiceAccountToken: false {{- if .Values.global.registry.imagePullSecrets }} imagePullSecrets: {{- range $index, $secret := .Values.global.registry.imagePullSecrets }} @@ -33,6 +35,7 @@ kind: ServiceAccount metadata: name: kube-ovn-cni namespace: {{ .Values.namespace }} +automountServiceAccountToken: false {{- if .Values.global.registry.imagePullSecrets }} imagePullSecrets: {{- range $index, $secret := .Values.global.registry.imagePullSecrets }} @@ -48,6 +51,7 @@ kind: ServiceAccount metadata: name: kube-ovn-app namespace: {{ .Values.namespace }} +automountServiceAccountToken: false {{- if .Values.global.registry.imagePullSecrets }} imagePullSecrets: {{- range $index, $secret := .Values.global.registry.imagePullSecrets }} 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 3a749f84..06971d01 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml @@ -26,8 +26,12 @@ spec: operator: Exists priorityClassName: system-node-critical serviceAccountName: kube-ovn-cni + automountServiceAccountToken: true hostNetwork: true hostPID: true + securityContext: + seccompProfile: + type: RuntimeDefault initContainers: - name: hostpath-init image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} @@ -35,7 +39,9 @@ spec: command: - sh - -xec - - iptables -V + - | + chmod +t /usr/local/sbin + iptables -V securityContext: allowPrivilegeEscalation: true capabilities: @@ -60,16 +66,21 @@ spec: imagePullPolicy: {{ .Values.image.pullPolicy }} command: - /kube-ovn/install-cni.sh - - --cni-conf-dir={{ .Values.cni_conf.CNI_CONF_DIR }} + - --cni-conf-dir={{ .Values.cni_conf.MOUNT_CNI_CONF_DIR }} - --cni-conf-file={{ .Values.cni_conf.CNI_CONF_FILE }} - --cni-conf-name={{- .Values.cni_conf.CNI_CONFIG_PRIORITY -}}-kube-ovn.conflist + env: + - name: POD_IPS + valueFrom: + fieldRef: + fieldPath: status.podIPs securityContext: runAsUser: 0 privileged: true volumeMounts: - mountPath: /opt/cni/bin name: cni-bin - - mountPath: /etc/cni/net.d + - mountPath: {{ .Values.cni_conf.MOUNT_CNI_CONF_DIR }} name: cni-conf {{- if .Values.cni_conf.MOUNT_LOCAL_BIN_DIR }} - mountPath: /usr/local/bin @@ -83,14 +94,17 @@ spec: - bash - /kube-ovn/start-cniserver.sh args: - {{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} - --enable-mirror={{- .Values.debug.ENABLE_MIRROR }} - --mirror-iface={{- .Values.debug.MIRROR_IFACE }} - --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 }} + - --service-cluster-ip-range= + {{- if eq .Values.networking.NET_STACK "dual_stack" -}} + {{ .Values.dual_stack.SVC_CIDR }} + {{- else if eq .Values.networking.NET_STACK "ipv4" -}} + {{ .Values.ipv4.SVC_CIDR }} + {{- else if eq .Values.networking.NET_STACK "ipv6" -}} + {{ .Values.ipv6.SVC_CIDR }} {{- end }} {{- if eq .Values.networking.NETWORK_TYPE "vlan" }} - --iface= @@ -111,6 +125,7 @@ spec: - --secure-serving={{- .Values.func.SECURE_SERVING }} - --enable-ovn-ipsec={{- .Values.func.ENABLE_OVN_IPSEC }} - --set-vxlan-tx-off={{- .Values.func.SET_VXLAN_TX_OFF }} + - --non-primary-cni-mode={{- .Values.cni_conf.NON_PRIMARY_CNI }} {{- with .Values.mtu }} - --mtu={{ . }} {{- end }} @@ -132,7 +147,7 @@ spec: valueFrom: fieldRef: fieldPath: status.podIP - - name: KUBE_NODE_NAME + - name: NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName @@ -216,6 +231,7 @@ spec: limits: cpu: {{ index .Values "kube-ovn-cni" "limits" "cpu" }} memory: {{ index .Values "kube-ovn-cni" "limits" "memory" }} + ephemeral-storage: {{ index .Values "kube-ovn-cni" "limits" "ephemeral-storage" }} nodeSelector: kubernetes.io/os: "linux" volumes: @@ -272,5 +288,5 @@ spec: {{- if .Values.func.ENABLE_OVN_IPSEC }} - name: ovs-ipsec-keys hostPath: - path: {{ .Values.OPENVSWITCH_DIR }} + path: {{ .Values.OVN_IPSEC_KEY_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 003d0c71..b15fd24e 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/ovsovn-ds.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovsovn-ds.yaml @@ -34,20 +34,21 @@ spec: operator: Exists priorityClassName: system-node-critical serviceAccountName: ovn-ovs + automountServiceAccountToken: true hostNetwork: true hostPID: true + securityContext: + seccompProfile: + type: RuntimeDefault initContainers: - name: hostpath-init - {{- if .Values.DPDK }} - image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.dpdkRepository }}:{{ .Values.DPDK_VERSION }}-{{ .Values.global.images.kubeovn.tag }} - {{- else }} image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} - {{- end }} imagePullPolicy: {{ .Values.image.pullPolicy }} command: - sh - -xec - | + chmod +t /usr/local/sbin chown -R nobody: /var/run/ovn /var/log/ovn /etc/openvswitch /var/run/openvswitch /var/log/openvswitch iptables -V {{- if not .Values.DISABLE_MODULES_MANAGEMENT }} @@ -82,17 +83,9 @@ spec: name: host-log-ovs containers: - name: openvswitch - {{- if .Values.DPDK }} - image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.dpdkRepository }}:{{ .Values.DPDK_VERSION }}-{{ .Values.global.images.kubeovn.tag }} - {{- else }} image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} - {{- end }} imagePullPolicy: {{ .Values.image.pullPolicy }} - {{- if .Values.DPDK }} - command: ["/kube-ovn/start-ovs-dpdk.sh"] - {{- else }} command: ["/kube-ovn/start-ovs.sh"] - {{- end }} securityContext: runAsUser: {{ include "kubeovn.runAsUser" . }} privileged: false @@ -122,7 +115,7 @@ spec: value: "{{- .Values.func.HW_OFFLOAD }}" - name: TUNNEL_TYPE value: "{{- .Values.networking.TUNNEL_TYPE }}" - - name: KUBE_NODE_NAME + - name: NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName @@ -156,59 +149,31 @@ spec: - mountPath: /var/run/containerd name: cruntime readOnly: true - {{- if .Values.DPDK }} - - mountPath: /opt/ovs-config - name: host-config-ovs - - mountPath: /dev/hugepages - name: hugepage - {{- end }} readinessProbe: exec: - {{- if .Values.DPDK }} - command: - - bash - - /kube-ovn/ovs-dpdk-healthcheck.sh - {{- else }} command: - bash - /kube-ovn/ovs-healthcheck.sh - {{- end }} initialDelaySeconds: 10 periodSeconds: 5 timeoutSeconds: 45 livenessProbe: exec: - {{- if .Values.DPDK }} - command: - - bash - - /kube-ovn/ovs-dpdk-healthcheck.sh - {{- else }} command: - bash - /kube-ovn/ovs-healthcheck.sh - {{- end }} initialDelaySeconds: 60 periodSeconds: 5 failureThreshold: 5 timeoutSeconds: 45 resources: requests: - {{- if .Values.DPDK }} - cpu: {{ .Values.DPDK_CPU }} - memory: {{ .Values.DPDK_MEMORY }} - {{- else }} cpu: {{ index .Values "ovs-ovn" "requests" "cpu" }} memory: {{ index .Values "ovs-ovn" "requests" "memory" }} - {{- end }} limits: - {{- if .Values.DPDK }} - cpu: {{ .Values.DPDK_CPU }} - memory: {{ .Values.DPDK_MEMORY }} - hugepages-1Gi: 1Gi - {{- else }} cpu: {{ index .Values "ovs-ovn" "limits" "cpu" }} memory: {{ index .Values "ovs-ovn" "limits" "memory" }} - {{- end }} + ephemeral-storage: {{ index .Values "ovs-ovn" "limits" "ephemeral-storage" }} nodeSelector: kubernetes.io/os: "linux" volumes: @@ -242,12 +207,3 @@ spec: - hostPath: path: /var/run/containerd name: cruntime - {{- if .Values.DPDK }} - - name: host-config-ovs - hostPath: - path: /opt/ovs-config - type: DirectoryOrCreate - - name: hugepage - emptyDir: - medium: HugePages - {{- end }} diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/pinger-ds.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/pinger-ds.yaml index a69a13ff..e52cf45d 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/pinger-ds.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/pinger-ds.yaml @@ -28,7 +28,11 @@ spec: - key: CriticalAddonsOnly operator: Exists serviceAccountName: kube-ovn-app - hostPID: true + automountServiceAccountToken: true + hostPID: false + securityContext: + seccompProfile: + type: RuntimeDefault initContainers: - name: hostpath-init image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} @@ -69,7 +73,6 @@ spec: {{- else if eq .Values.networking.NET_STACK "ipv6" -}} {{ .Values.ipv6.PINGER_EXTERNAL_DOMAIN }} {{- end }} - - --ds-namespace={{ .Values.namespace }} - --logtostderr=false - --alsologtostderr=true - --log_file=/var/log/kube-ovn/kube-ovn-pinger.log @@ -98,6 +101,10 @@ spec: valueFrom: fieldRef: fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace - name: NODE_NAME valueFrom: fieldRef: @@ -129,6 +136,19 @@ spec: limits: cpu: {{ index .Values "kube-ovn-pinger" "limits" "cpu" }} memory: {{ index .Values "kube-ovn-pinger" "limits" "memory" }} + ephemeral-storage: {{ index .Values "kube-ovn-pinger" "limits" "ephemeral-storage" }} + livenessProbe: + httpGet: + path: /metrics + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /metrics + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 10 nodeSelector: kubernetes.io/os: "linux" volumes: diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/pre-delete-hook.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/post-delete-hook.yaml similarity index 77% rename from packages/system/kubeovn/charts/kube-ovn/templates/pre-delete-hook.yaml rename to packages/system/kubeovn/charts/kube-ovn/templates/post-delete-hook.yaml index d81c5ca2..1272257f 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/pre-delete-hook.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/post-delete-hook.yaml @@ -1,14 +1,15 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: kube-ovn-pre-delete-hook + name: kube-ovn-post-delete-hook namespace: {{ .Values.namespace }} annotations: # This is what defines this resource as a hook. Without this line, the # job is considered part of the release. - "helm.sh/hook": pre-delete + "helm.sh/hook": post-delete "helm.sh/hook-weight": "1" "helm.sh/hook-delete-policy": hook-succeeded +automountServiceAccountToken: false --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -17,15 +18,17 @@ metadata: rbac.authorization.k8s.io/system-only: "true" # This is what defines this resource as a hook. Without this line, the # job is considered part of the release. - "helm.sh/hook": pre-delete + "helm.sh/hook": post-delete "helm.sh/hook-weight": "2" "helm.sh/hook-delete-policy": hook-succeeded - name: system:kube-ovn-pre-delete-hook + name: system:kube-ovn-post-delete-hook rules: - apiGroups: - kubeovn.io resources: - subnets + - vpcs + - ips verbs: - get - list @@ -34,26 +37,26 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - name: kube-ovn-pre-delete-hook + name: kube-ovn-post-delete-hook annotations: # This is what defines this resource as a hook. Without this line, the # job is considered part of the release. - "helm.sh/hook": pre-delete + "helm.sh/hook": post-delete "helm.sh/hook-weight": "3" "helm.sh/hook-delete-policy": hook-succeeded roleRef: - name: system:kube-ovn-pre-delete-hook + name: system:kube-ovn-post-delete-hook kind: ClusterRole apiGroup: rbac.authorization.k8s.io subjects: - kind: ServiceAccount - name: kube-ovn-pre-delete-hook + name: kube-ovn-post-delete-hook namespace: {{ .Values.namespace }} --- apiVersion: batch/v1 kind: Job metadata: - name: "{{ .Chart.Name }}-pre-delete-hook" + name: "{{ .Chart.Name }}-post-delete-hook" namespace: {{ .Values.namespace }} labels: app.kubernetes.io/managed-by: {{ .Release.Service | quote }} @@ -63,7 +66,7 @@ metadata: annotations: # This is what defines this resource as a hook. Without this line, the # job is considered part of the release. - "helm.sh/hook": pre-delete + "helm.sh/hook": post-delete "helm.sh/hook-weight": "4" "helm.sh/hook-delete-policy": hook-succeeded spec: @@ -75,7 +78,7 @@ spec: app.kubernetes.io/managed-by: {{ .Release.Service | quote }} app.kubernetes.io/instance: {{ .Release.Name | quote }} helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - app: kube-ovn-pre-delete-hook + app: kube-ovn-post-delete-hook component: job spec: tolerations: @@ -91,7 +94,7 @@ spec: - key: app operator: In values: - - kube-ovn-pre-delete-hook + - kube-ovn-post-delete-hook - key: component operator: In values: @@ -100,8 +103,11 @@ spec: hostNetwork: true nodeSelector: kubernetes.io/os: "linux" - serviceAccount: kube-ovn-pre-delete-hook - serviceAccountName: kube-ovn-pre-delete-hook + serviceAccountName: kube-ovn-post-delete-hook + automountServiceAccountToken: true + securityContext: + seccompProfile: + type: RuntimeDefault containers: - name: remove-subnet-finalizer image: "{{ .Values.global.registry.address}}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }}" @@ -113,7 +119,15 @@ spec: command: - sh - -c - - /kube-ovn/remove-subnet-finalizer.sh 2>&1 | tee -a /var/log/kube-ovn/remove-subnet-finalizer.log + - /kube-ovn/remove-finalizer.sh 2>&1 | tee -a /var/log/kube-ovn/remove-finalizer.log + resources: + requests: + cpu: 100m + memory: 200Mi + limits: + cpu: 1 + memory: 500Mi + ephemeral-storage: 1Gi volumeMounts: - mountPath: /var/log/kube-ovn name: kube-ovn-log diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/pre-upgrade-ovs-ovn.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/pre-upgrade-ovs-ovn.yaml new file mode 100644 index 00000000..a18a4111 --- /dev/null +++ b/packages/system/kubeovn/charts/kube-ovn/templates/pre-upgrade-ovs-ovn.yaml @@ -0,0 +1,129 @@ +{{- if include "kubeovn.ovn.versionCompatibility" . -}} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: ovs-ovn-pre-upgrade + namespace: {{ .Values.namespace }} + annotations: + "helm.sh/hook": pre-upgrade + "helm.sh/hook-weight": "1" + "helm.sh/hook-delete-policy": hook-succeeded +automountServiceAccountToken: false +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + rbac.authorization.k8s.io/system-only: "true" + "helm.sh/hook": pre-upgrade + "helm.sh/hook-weight": "2" + "helm.sh/hook-delete-policy": hook-succeeded + name: system:ovs-ovn-pre-upgrade +rules: + - apiGroups: + - "" + resources: + - pods + verbs: + - list + - get + - apiGroups: + - "" + resources: + - pods/exec + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: ovs-ovn-pre-upgrade + annotations: + "helm.sh/hook": pre-upgrade + "helm.sh/hook-weight": "3" + "helm.sh/hook-delete-policy": hook-succeeded +roleRef: + name: system:ovs-ovn-pre-upgrade + kind: ClusterRole + apiGroup: rbac.authorization.k8s.io +subjects: + - kind: ServiceAccount + name: ovs-ovn-pre-upgrade + namespace: {{ .Values.namespace }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: "{{ .Chart.Name }}-pre-upgrade-hook" + namespace: {{ .Values.namespace }} + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + annotations: + "helm.sh/hook": pre-upgrade + "helm.sh/hook-weight": "4" + "helm.sh/hook-delete-policy": hook-succeeded +spec: + completions: 1 + template: + metadata: + name: "{{ .Release.Name }}" + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app: pre-upgrade + component: job + spec: + tolerations: + - key: "" + operator: "Exists" + effect: "NoSchedule" + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - topologyKey: kubernetes.io/hostname + labelSelector: + matchExpressions: + - key: app + operator: In + values: + - pre-upgrade + - key: component + operator: In + values: + - job + restartPolicy: Never + hostNetwork: true + nodeSelector: + kubernetes.io/os: "linux" + serviceAccountName: ovs-ovn-pre-upgrade + automountServiceAccountToken: true + securityContext: + seccompProfile: + type: RuntimeDefault + containers: + - name: ovs-ovn-pre-upgrade + image: "{{ .Values.global.registry.address}}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }}" + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + command: + - bash + - -eo + - pipefail + - -c + - bash /kube-ovn/pre-upgrade-ovs.sh 2>&1 | tee -a /var/log/kube-ovn/pre-upgrade-ovs.log + volumeMounts: + - mountPath: /var/log/kube-ovn + name: kube-ovn-log + volumes: + - name: kube-ovn-log + hostPath: + path: {{ .Values.log_conf.LOG_DIR }}/kube-ovn +{{- end -}} diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/upgrade-ovs-ovn.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/upgrade-ovs-ovn.yaml index fc5ac4ba..b85ce8fa 100644 --- a/packages/system/kubeovn/charts/kube-ovn/templates/upgrade-ovs-ovn.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/upgrade-ovs-ovn.yaml @@ -11,6 +11,7 @@ metadata: "helm.sh/hook": post-upgrade "helm.sh/hook-weight": "1" "helm.sh/hook-delete-policy": hook-succeeded +automountServiceAccountToken: false --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -30,6 +31,8 @@ rules: - daemonsets verbs: - list + - get + - watch - apiGroups: - apps resources: @@ -133,8 +136,11 @@ spec: hostNetwork: true nodeSelector: kubernetes.io/os: "linux" - serviceAccount: ovs-ovn-upgrade serviceAccountName: ovs-ovn-upgrade + automountServiceAccountToken: true + securityContext: + seccompProfile: + type: RuntimeDefault containers: - name: ovs-ovn-upgrade image: "{{ .Values.global.registry.address}}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }}" diff --git a/packages/system/kubeovn/charts/kube-ovn/templates/vpc-nat-config.yaml b/packages/system/kubeovn/charts/kube-ovn/templates/vpc-nat-config.yaml index c005bec1..92e2fd94 100755 --- a/packages/system/kubeovn/charts/kube-ovn/templates/vpc-nat-config.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/templates/vpc-nat-config.yaml @@ -7,13 +7,13 @@ metadata: kubernetes.io/description: | kube-ovn vpc-nat common config data: - image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.vpcRepository }}:{{ .Values.global.images.kubeovn.tag }} + image: {{ .Values.global.registry.address }}/{{ .Values.global.images.natgateway.repository }}:{{ or .Values.global.images.natgateway.tag .Values.global.images.kubeovn.tag }} --- kind: ConfigMap apiVersion: v1 metadata: name: ovn-vpc-nat-gw-config - namespace: kube-system + namespace: {{ .Values.namespace }} data: - enable-vpc-nat-gw: "{{ .Values.func.ENABLE_NAT_GW }}" \ No newline at end of file + enable-vpc-nat-gw: "{{ .Values.func.ENABLE_NAT_GW }}" diff --git a/packages/system/kubeovn/charts/kube-ovn/values.yaml b/packages/system/kubeovn/charts/kube-ovn/values.yaml index a543304a..fd3472f6 100644 --- a/packages/system/kubeovn/charts/kube-ovn/values.yaml +++ b/packages/system/kubeovn/charts/kube-ovn/values.yaml @@ -8,11 +8,11 @@ global: images: kubeovn: repository: kube-ovn - dpdkRepository: kube-ovn-dpdk - vpcRepository: vpc-nat-gateway - tag: v1.13.13 - support_arm: true - thirdparty: true + tag: v1.15.10 + natgateway: + repository: vpc-nat-gateway + # Falls back to the same tag as kubeovn if empty + tag: v1.15.10 image: pullPolicy: IfNotPresent @@ -47,6 +47,8 @@ networking: ENABLE_METRICS: true # comma-separated string of nodelocal DNS ip addresses NODE_LOCAL_DNS_IP: "" + # comma-separated list of destination IP CIDRs that should skip conntrack processing + SKIP_CONNTRACK_DST_CIDRS: "" PROBE_INTERVAL: 180000 OVN_NORTHD_PROBE_INTERVAL: 5000 OVN_LEADER_PROBE_INTERVAL: 5 @@ -58,7 +60,8 @@ networking: func: ENABLE_LB: true ENABLE_NP: true - ENABLE_EXTERNAL_VPC: true + NP_ENFORCEMENT: standard + ENABLE_EXTERNAL_VPC: false HW_OFFLOAD: false ENABLE_LB_SVC: false ENABLE_KEEP_VM_IP: true @@ -74,12 +77,18 @@ func: ENABLE_NAT_GW: true ENABLE_OVN_IPSEC: false ENABLE_ANP: false + ENABLE_DNS_NAME_RESOLVER: false SET_VXLAN_TX_OFF: false OVSDB_CON_TIMEOUT: 3 OVSDB_INACTIVITY_TIMEOUT: 10 ENABLE_LIVE_MIGRATION_OPTIMIZE: true + ENABLE_OVN_LB_PREFER_LOCAL: false ipv4: + POD_CIDR: "10.16.0.0/16" + POD_GATEWAY: "10.16.0.1" + SVC_CIDR: "10.96.0.0/12" + JOIN_CIDR: "100.64.0.0/16" PINGER_EXTERNAL_ADDRESS: "1.1.1.1" PINGER_EXTERNAL_DOMAIN: "kube-ovn.io." @@ -111,10 +120,12 @@ debug: cni_conf: CNI_CONFIG_PRIORITY: "01" CNI_CONF_DIR: "/etc/cni/net.d" + MOUNT_CNI_CONF_DIR: "/etc/cni/net.d" CNI_BIN_DIR: "/opt/cni/bin" CNI_CONF_FILE: "/kube-ovn/01-kube-ovn.conflist" LOCAL_BIN_DIR: "/usr/local/bin" MOUNT_LOCAL_BIN_DIR: false + NON_PRIMARY_CNI: false kubelet_conf: KUBELET_DIR: "/var/lib/kubelet" @@ -123,6 +134,7 @@ log_conf: LOG_DIR: "/var/log" OPENVSWITCH_DIR: "/etc/origin/openvswitch" +OVN_IPSEC_KEY_DIR: "/etc/origin/ovs_ipsec_keys" OVN_DIR: "/etc/origin/ovn" DISABLE_MODULES_MANAGEMENT: false @@ -133,10 +145,7 @@ fullnameOverride: "" HYBRID_DPDK: false HUGEPAGE_SIZE_TYPE: hugepages-2Mi # Default HUGEPAGES: 1Gi - -# DPDK -DPDK: false -DPDK_VERSION: "19.11" +DPDK_IMAGE_TAG: "v1.15.0-dpdk" DPDK_CPU: "1000m" # Default CPU configuration DPDK_MEMORY: "2Gi" # Default Memory configuration @@ -147,6 +156,7 @@ ovn-central: limits: cpu: "3" memory: "4Gi" + ephemeral-storage: 1Gi ovs-ovn: requests: cpu: "200m" @@ -154,6 +164,7 @@ ovs-ovn: limits: cpu: "2" memory: "1000Mi" + ephemeral-storage: 1Gi kube-ovn-controller: requests: cpu: "200m" @@ -161,6 +172,7 @@ kube-ovn-controller: limits: cpu: "1000m" memory: "1Gi" + ephemeral-storage: 1Gi kube-ovn-cni: requests: cpu: "100m" @@ -168,6 +180,7 @@ kube-ovn-cni: limits: cpu: "1000m" memory: "1Gi" + ephemeral-storage: 1Gi kube-ovn-pinger: requests: cpu: "100m" @@ -175,6 +188,7 @@ kube-ovn-pinger: limits: cpu: "200m" memory: "400Mi" + ephemeral-storage: 1Gi kube-ovn-monitor: requests: cpu: "200m" @@ -182,3 +196,4 @@ kube-ovn-monitor: limits: cpu: "200m" memory: "200Mi" + ephemeral-storage: 1Gi diff --git a/packages/system/kubeovn/images/kubeovn/Dockerfile b/packages/system/kubeovn/images/kubeovn/Dockerfile deleted file mode 100644 index 9d9795f3..00000000 --- a/packages/system/kubeovn/images/kubeovn/Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -# syntax = docker/dockerfile:experimental -ARG VERSION=v1.13.13 -ARG BASE_TAG=$VERSION - -FROM golang:1.23-bookworm as builder - -ARG TAG=v1.13.13 -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 diff --git a/packages/system/kubeovn/images/kubeovn/patches/5294-db-healthcheck.diff b/packages/system/kubeovn/images/kubeovn/patches/5294-db-healthcheck.diff deleted file mode 100644 index b65073ee..00000000 --- a/packages/system/kubeovn/images/kubeovn/patches/5294-db-healthcheck.diff +++ /dev/null @@ -1,168 +0,0 @@ -diff --git a/mocks/pkg/ovs/interface.go b/mocks/pkg/ovs/interface.go -index e9c472bee..59076f9ed 100644 ---- a/mocks/pkg/ovs/interface.go -+++ b/mocks/pkg/ovs/interface.go -@@ -10,6 +10,7 @@ - package ovs - - import ( -+ context "context" - reflect "reflect" - - v1 "github.com/kubeovn/kube-ovn/pkg/apis/kubeovn/v1" -@@ -3322,6 +3323,20 @@ func (mr *MockNbClientMockRecorder) DeleteSecurityGroup(sgName any) *gomock.Call - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSecurityGroup", reflect.TypeOf((*MockNbClient)(nil).DeleteSecurityGroup), sgName) - } - -+// Echo mocks base method. -+func (m *MockNbClient) Echo(arg0 context.Context) error { -+ m.ctrl.T.Helper() -+ ret := m.ctrl.Call(m, "Echo", arg0) -+ ret0, _ := ret[0].(error) -+ return ret0 -+} -+ -+// Echo indicates an expected call of Echo. -+func (mr *MockNbClientMockRecorder) Echo(arg0 any) *gomock.Call { -+ mr.mock.ctrl.T.Helper() -+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Echo", reflect.TypeOf((*MockNbClient)(nil).Echo), arg0) -+} -+ - // EnablePortLayer2forward mocks base method. - func (m *MockNbClient) EnablePortLayer2forward(lspName string) error { - m.ctrl.T.Helper() -@@ -4770,6 +4785,20 @@ func (mr *MockSbClientMockRecorder) GetAllChassisByHost(nodeName any) *gomock.Ca - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllChassisByHost", reflect.TypeOf((*MockSbClient)(nil).GetAllChassisByHost), nodeName) - } - -+// Echo mocks base method. -+func (m *MockSbClient) Echo(arg0 context.Context) error { -+ m.ctrl.T.Helper() -+ ret := m.ctrl.Call(m, "Echo", arg0) -+ ret0, _ := ret[0].(error) -+ return ret0 -+} -+ -+// Echo indicates an expected call of Echo. -+func (mr *MockSbClientMockRecorder) Echo(arg0 any) *gomock.Call { -+ mr.mock.ctrl.T.Helper() -+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Echo", reflect.TypeOf((*MockSbClient)(nil).Echo), arg0) -+} -+ - // GetChassis mocks base method. - func (m *MockSbClient) GetChassis(chassisName string, ignoreNotFound bool) (*ovnsb.Chassis, error) { - m.ctrl.T.Helper() -@@ -4915,6 +4944,20 @@ func (m *MockCommon) EXPECT() *MockCommonMockRecorder { - return m.recorder - } - -+// Echo mocks base method. -+func (m *MockCommon) Echo(arg0 context.Context) error { -+ m.ctrl.T.Helper() -+ ret := m.ctrl.Call(m, "Echo", arg0) -+ ret0, _ := ret[0].(error) -+ return ret0 -+} -+ -+// Echo indicates an expected call of Echo. -+func (mr *MockCommonMockRecorder) Echo(arg0 any) *gomock.Call { -+ mr.mock.ctrl.T.Helper() -+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Echo", reflect.TypeOf((*MockCommon)(nil).Echo), arg0) -+} -+ - // GetEntityInfo mocks base method. - func (m *MockCommon) GetEntityInfo(entity any) error { - m.ctrl.T.Helper() -diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go -index cb594a4c8..a2a88eb06 100644 ---- a/pkg/controller/controller.go -+++ b/pkg/controller/controller.go -@@ -268,6 +268,9 @@ type Controller struct { - cmInformerFactory kubeinformers.SharedInformerFactory - kubeovnInformerFactory kubeovninformer.SharedInformerFactory - anpInformerFactory anpinformer.SharedInformerFactory -+ -+ // Database health check -+ dbFailureCount int - } - - func newTypedRateLimitingQueue[T comparable](name string, rateLimiter workqueue.TypedRateLimiter[T]) workqueue.TypedRateLimitingInterface[T] { -@@ -944,6 +947,48 @@ func (c *Controller) Run(ctx context.Context) { - klog.Info("Shutting down workers") - } - -+func (c *Controller) dbStatus() { -+ const maxFailures = 5 -+ -+ done := make(chan error, 2) -+ go func() { -+ done <- c.OVNNbClient.Echo(context.Background()) -+ }() -+ go func() { -+ done <- c.OVNSbClient.Echo(context.Background()) -+ }() -+ -+ resultsReceived := 0 -+ timeout := time.After(time.Duration(c.config.OvnTimeout) * time.Second) -+ -+ for resultsReceived < 2 { -+ select { -+ case err := <-done: -+ resultsReceived++ -+ if err != nil { -+ c.dbFailureCount++ -+ klog.Errorf("OVN database echo failed (%d/%d): %v", c.dbFailureCount, maxFailures, err) -+ if c.dbFailureCount >= maxFailures { -+ util.LogFatalAndExit(err, "OVN database connection failed after %d attempts", maxFailures) -+ } -+ return -+ } -+ case <-timeout: -+ c.dbFailureCount++ -+ klog.Errorf("OVN database echo timeout (%d/%d) after %ds", c.dbFailureCount, maxFailures, c.config.OvnTimeout) -+ if c.dbFailureCount >= maxFailures { -+ util.LogFatalAndExit(nil, "OVN database connection timeout after %d attempts", maxFailures) -+ } -+ return -+ } -+ } -+ -+ if c.dbFailureCount > 0 { -+ klog.Infof("OVN database connection recovered after %d failures", c.dbFailureCount) -+ c.dbFailureCount = 0 -+ } -+} -+ - func (c *Controller) shutdown() { - utilruntime.HandleCrash() - -@@ -1277,6 +1322,8 @@ func (c *Controller) startWorkers(ctx context.Context) { - if c.config.EnableLiveMigrationOptimize { - go wait.Until(runWorker("add/update vmiMigration ", c.addOrUpdateVMIMigrationQueue, c.handleAddOrUpdateVMIMigration), 50*time.Millisecond, ctx.Done()) - } -+ -+ go wait.Until(c.dbStatus, 15*time.Second, ctx.Done()) - } - - func (c *Controller) allSubnetReady(subnets ...string) (bool, error) { -diff --git a/pkg/ovs/interface.go b/pkg/ovs/interface.go -index df6907c4d..5e70dd6c7 100644 ---- a/pkg/ovs/interface.go -+++ b/pkg/ovs/interface.go -@@ -1,6 +1,8 @@ - package ovs - - import ( -+ "context" -+ - netv1 "k8s.io/api/networking/v1" - - "github.com/ovn-org/libovsdb/ovsdb" -@@ -235,6 +237,7 @@ type SbClient interface { - } - - type Common interface { -+ Echo(context.Context) error - Transact(method string, operations []ovsdb.Operation) error - GetEntityInfo(entity interface{}) error - } diff --git a/packages/system/kubeovn/patches/cozyconfig.diff b/packages/system/kubeovn/patches/cozyconfig.diff deleted file mode 100644 index f7a683f7..00000000 --- a/packages/system/kubeovn/patches/cozyconfig.diff +++ /dev/null @@ -1,103 +0,0 @@ - -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 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,15 @@ spec: - - bash - - /kube-ovn/start-cniserver.sh - args: -+ {{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} - - --enable-mirror={{- .Values.debug.ENABLE_MIRROR }} - - --mirror-iface={{- .Values.debug.MIRROR_IFACE }} - - --node-switch={{ .Values.networking.NODE_SUBNET }} - - --encap-checksum=true -- - --service-cluster-ip-range= -- {{- if eq .Values.networking.NET_STACK "dual_stack" -}} -- {{ .Values.dual_stack.SVC_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv4" -}} -- {{ .Values.ipv4.SVC_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv6" -}} -- {{ .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}} -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 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,22 @@ spec: - image: {{ .Values.global.registry.address }}/{{ .Values.global.images.kubeovn.repository }}:{{ .Values.global.images.kubeovn.tag }} - imagePullPolicy: {{ .Values.image.pullPolicy }} - args: -+ {{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} - - /kube-ovn/start-controller.sh - - --default-ls={{ .Values.networking.DEFAULT_SUBNET }} -- - --default-cidr= -- {{- if eq .Values.networking.NET_STACK "dual_stack" -}} -- {{ .Values.dual_stack.POD_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv4" -}} -- {{ .Values.ipv4.POD_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv6" -}} -- {{ .Values.ipv6.POD_CIDR }} -- {{- end }} -- - --default-gateway= -- {{- if eq .Values.networking.NET_STACK "dual_stack" -}} -- {{ .Values.dual_stack.POD_GATEWAY }} -- {{- else if eq .Values.networking.NET_STACK "ipv4" -}} -- {{ .Values.ipv4.POD_GATEWAY }} -- {{- else if eq .Values.networking.NET_STACK "ipv6" -}} -- {{ .Values.ipv6.POD_GATEWAY }} -- {{- end }} -+ - --default-cidr={{ index $cozyConfig.data "ipv4-pod-cidr" }} -+ - --default-gateway={{ index $cozyConfig.data "ipv4-pod-gateway" }} - - --default-gateway-check={{- .Values.func.CHECK_GATEWAY }} - - --default-logical-gateway={{- .Values.func.LOGICAL_GATEWAY }} - - --default-u2o-interconnection={{- .Values.func.U2O_INTERCONNECTION }} - - --default-exclude-ips={{- .Values.networking.EXCLUDE_IPS }} - - --cluster-router={{ .Values.networking.DEFAULT_VPC }} - - --node-switch={{ .Values.networking.NODE_SUBNET }} -- - --node-switch-cidr= -- {{- if eq .Values.networking.NET_STACK "dual_stack" -}} -- {{ .Values.dual_stack.JOIN_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv4" -}} -- {{ .Values.ipv4.JOIN_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv6" -}} -- {{ .Values.ipv6.JOIN_CIDR }} -- {{- end }} -- - --service-cluster-ip-range= -- {{- if eq .Values.networking.NET_STACK "dual_stack" -}} -- {{ .Values.dual_stack.SVC_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv4" -}} -- {{ .Values.ipv4.SVC_CIDR }} -- {{- else if eq .Values.networking.NET_STACK "ipv6" -}} -- {{ .Values.ipv6.SVC_CIDR }} -- {{- 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/charts/kube-ovn/values.yaml b/packages/system/kubeovn/charts/kube-ovn/values.yaml -index bfffc4d..b880749 100644 ---- a/packages/system/kubeovn/charts/kube-ovn/values.yaml -+++ b/packages/system/kubeovn/charts/kube-ovn/values.yaml -@@ -70,10 +70,6 @@ func: - ENABLE_TPROXY: false - - ipv4: -- POD_CIDR: "10.16.0.0/16" -- POD_GATEWAY: "10.16.0.1" -- SVC_CIDR: "10.96.0.0/12" -- JOIN_CIDR: "100.64.0.0/16" - PINGER_EXTERNAL_ADDRESS: "1.1.1.1" - PINGER_EXTERNAL_DOMAIN: "alauda.cn." - diff --git a/packages/system/kubeovn/patches/mtu.diff b/packages/system/kubeovn/patches/mtu.diff deleted file mode 100644 index da3de3aa..00000000 --- a/packages/system/kubeovn/patches/mtu.diff +++ /dev/null @@ -1,14 +0,0 @@ -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 63f4258..dafe1fd 100644 ---- a/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml -+++ b/packages/system/kubeovn/charts/kube-ovn/templates/ovncni-ds.yaml -@@ -112,6 +112,9 @@ spec: - - --secure-serving={{- .Values.func.SECURE_SERVING }} - - --enable-ovn-ipsec={{- .Values.func.ENABLE_OVN_IPSEC }} - - --set-vxlan-tx-off={{- .Values.func.SET_VXLAN_TX_OFF }} -+ {{- with .Values.mtu }} -+ - --mtu={{ . }} -+ {{- end }} - securityContext: - runAsUser: 0 - privileged: false diff --git a/packages/system/kubeovn/values.yaml b/packages/system/kubeovn/values.yaml index 91eda1b5..e9d2d10f 100644 --- a/packages/system/kubeovn/values.yaml +++ b/packages/system/kubeovn/values.yaml @@ -2,6 +2,7 @@ kube-ovn: namespace: cozy-kubeovn func: ENABLE_NP: false + ENABLE_LB: false ipv4: POD_CIDR: "10.244.0.0/16" POD_GATEWAY: "10.244.0.1" @@ -43,7 +44,7 @@ kube-ovn: memory: "50Mi" limits: cpu: "1000m" - memory: "1Gi" + memory: "2Gi" kube-ovn-pinger: requests: cpu: "10m" @@ -64,4 +65,4 @@ global: images: kubeovn: repository: kubeovn - tag: v1.13.13@sha256:c1414b747822390f14b9977fc7d1be9c89f462403704de1088771239dbd0050b + tag: v1.15.10@sha256:741299cbd0081a786a6b60c460fa3156b3a42a38141c559dd8ac031f50c5504f diff --git a/packages/system/kubernetes-rd/Chart.yaml b/packages/system/kubernetes-rd/Chart.yaml new file mode 100644 index 00000000..8fad1a45 --- /dev/null +++ b/packages/system/kubernetes-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: kubernetes-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/kubernetes-rd/Makefile b/packages/system/kubernetes-rd/Makefile new file mode 100644 index 00000000..2d38b5d3 --- /dev/null +++ b/packages/system/kubernetes-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=kubernetes-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/kubernetes-rd/cozyrds/kubernetes.yaml b/packages/system/kubernetes-rd/cozyrds/kubernetes.yaml new file mode 100644 index 00000000..f81eaff0 --- /dev/null +++ b/packages/system/kubernetes-rd/cozyrds/kubernetes.yaml @@ -0,0 +1,62 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: kubernetes + annotations: + # Kubernetes tenants boot a Kamaji control plane whose admin-kubeconfig + # Secret is provisioned asynchronously. Cold Kamaji start (image pull + + # etcd + apiserver Ready) plus admin-kubeconfig generation can exceed + # Flux helm-controller's default wait budget, causing remediation loops + # that uninstall the Cluster CR. This override is applied by cozystack-api + # to the HelmRelease Spec.Install.Timeout and Spec.Upgrade.Timeout. + # + # Coupling: the wait-for-kubeconfig init container in + # packages/apps/kubernetes/templates/_helpers.tpl hard-codes a 10m + # deadline chosen to stay strictly below this value so the pod's + # CrashLoopBackOff surfaces before flux remediation fires. If this + # annotation is raised, update that init deadline correspondingly. + release.cozystack.io/helm-install-timeout: "15m" +spec: + application: + kind: Kubernetes + singular: kubernetes + plural: kuberneteses + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":"replicated"},"nodeGroups":{"description":"Worker nodes configuration map.","type":"object","default":{"md0":{"ephemeralStorage":"20Gi","gpus":[],"instanceType":"u1.medium","maxReplicas":10,"minReplicas":0,"resources":{},"roles":["ingress-nginx"]}},"additionalProperties":{"type":"object","required":["ephemeralStorage","instanceType","maxReplicas","minReplicas","resources"],"properties":{"ephemeralStorage":{"description":"Ephemeral storage size.","default":"20Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"gpus":{"description":"List of GPUs to attach (NVIDIA driver requires at least 4 GiB RAM).","type":"array","items":{"type":"object","required":["name"],"properties":{"name":{"description":"Name of GPU, such as \"nvidia.com/AD102GL_L40S\".","type":"string"}}}},"instanceType":{"description":"Virtual machine instance type.","type":"string","default":"u1.medium"},"maxReplicas":{"description":"Maximum number of replicas.","type":"integer","default":10},"minReplicas":{"description":"Minimum number of replicas.","type":"integer","default":0},"resources":{"description":"CPU and memory resources for each worker node.","type":"object","properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"roles":{"description":"List of node roles.","type":"array","items":{"type":"string"}}}}},"version":{"description":"Kubernetes major.minor version to deploy","type":"string","default":"v1.35","enum":["v1.35","v1.34","v1.33","v1.32","v1.31","v1.30"]},"host":{"description":"External hostname for Kubernetes cluster. Defaults to `.` if empty.","type":"string","default":""},"addons":{"description":"Cluster addons configuration.","type":"object","default":{},"required":["certManager","cilium","coredns","fluxcd","gatewayAPI","gpuOperator","hami","ingressNginx","monitoringAgents","velero","verticalPodAutoscaler"],"properties":{"certManager":{"description":"Cert-manager addon.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable cert-manager.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"cilium":{"description":"Cilium CNI plugin.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"coredns":{"description":"CoreDNS addon.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"fluxcd":{"description":"FluxCD GitOps operator.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable FluxCD.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"gatewayAPI":{"description":"Gateway API addon.","type":"object","default":{},"required":["enabled"],"properties":{"enabled":{"description":"Enable Gateway API.","type":"boolean","default":false}}},"gpuOperator":{"description":"NVIDIA GPU Operator.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable GPU Operator.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"hami":{"description":"HAMi GPU virtualization middleware.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable HAMi (requires GPU Operator).","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"ingressNginx":{"description":"Ingress-NGINX controller.","type":"object","default":{},"required":["enabled","exposeMethod","valuesOverride"],"properties":{"enabled":{"description":"Enable the controller (requires nodes labeled `ingress-nginx`).","type":"boolean","default":false},"exposeMethod":{"description":"Method to expose the controller. Allowed values: `Proxied`, `LoadBalancer`.","type":"string","default":"Proxied","enum":["Proxied","LoadBalancer"]},"hosts":{"description":"Domains routed to this tenant cluster when `exposeMethod` is `Proxied`.","type":"array","default":[],"items":{"type":"string"}},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"monitoringAgents":{"description":"Monitoring agents.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable monitoring agents.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"velero":{"description":"Velero backup/restore addon.","type":"object","default":{},"required":["enabled","valuesOverride"],"properties":{"enabled":{"description":"Enable Velero.","type":"boolean","default":false},"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}},"verticalPodAutoscaler":{"description":"Vertical Pod Autoscaler.","type":"object","default":{},"required":["valuesOverride"],"properties":{"valuesOverride":{"description":"Custom Helm values overrides.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}}}},"controlPlane":{"description":"Kubernetes control-plane configuration.","type":"object","default":{},"required":["apiServer","controllerManager","konnectivity","replicas","scheduler"],"properties":{"apiServer":{"description":"API Server configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for API Server.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"large","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"controllerManager":{"description":"Controller Manager configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Controller Manager.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"konnectivity":{"description":"Konnectivity configuration.","type":"object","default":{},"required":["server"],"properties":{"server":{"description":"Konnectivity Server configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Konnectivity.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}},"replicas":{"description":"Number of control-plane replicas.","type":"integer","default":2},"scheduler":{"description":"Scheduler configuration.","type":"object","default":{},"required":["resources","resourcesPreset"],"properties":{"resources":{"description":"CPU and memory resources for Scheduler.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Preset if `resources` omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}},"images":{"description":"Optional image overrides for air-gapped or rate-limited registries.","type":"object","default":{},"properties":{"waitForKubeconfig":{"description":"Image used by the wait-for-kubeconfig init container. Empty falls back to images/busybox.tag.","type":"string","default":""}}}}} + release: + prefix: kubernetes- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-kubernetes-application-kubevirt-kubernetes + namespace: cozy-system + dashboard: + category: IaaS + singular: Kubernetes + plural: Kubernetes + weight: 40 + description: Managed Kubernetes service + tags: + - compute + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODFfMjg0NSkiLz4KPHBhdGggZD0iTTcxLjk5NjggMTlDNzAuMzAzOSAxOS4wMDAyIDY4LjkzMTIgMjAuNTMyMiA2OC45MzE0IDIyLjQyMjFDNjguOTMxNCAyMi40NTExIDY4LjkzNzMgMjIuNDc4OCA2OC45Mzc5IDIyLjUwNzZDNjguOTM1NCAyMi43NjQ0IDY4LjkyMzEgMjMuMDczNyA2OC45MzE0IDIzLjI5NzNDNjguOTcxNyAyNC4zODczIDY5LjIwODIgMjUuMjIxNiA2OS4zNTA2IDI2LjIyNThDNjkuNjA4NCAyOC4zNzUyIDY5LjgyNDUgMzAuMTU2OSA2OS42OTEyIDMxLjgxM0M2OS41NjE1IDMyLjQzNzUgNjkuMTAzNyAzMy4wMDg2IDY4LjY5NTYgMzMuNDA1Nkw2OC42MjM1IDM0LjcwODZDNjYuNzgzOSAzNC44NjE3IDY0LjkzMTkgMzUuMTQyMSA2My4wODIxIDM1LjU2NDFDNTUuMTIyNiAzNy4zNzk4IDQ4LjI2OTUgNDEuNDk5MSA0My4wNTIgNDcuMDYwOUM0Mi43MTM0IDQ2LjgyODggNDIuMTIxMSA0Ni40MDE5IDQxLjk0NSA0Ni4yNzEyQzQxLjM5NzcgNDYuMzQ1NCA0MC44NDQ1IDQ2LjUxNTEgNDAuMTI0MSA0Ni4wOTM1QzM4Ljc1MjIgNDUuMTY1NyAzNy41MDI4IDQzLjg4NTEgMzUuOTkxIDQyLjM0MjRDMzUuMjk4MiA0MS42MDQ0IDM0Ljc5NjYgNDAuOTAxOCAzMy45NzM1IDQwLjE5MDRDMzMuNzg2NiA0MC4wMjg5IDMzLjUwMTQgMzkuODEwNCAzMy4yOTIzIDM5LjY0NDJDMzIuNjQ4OSAzOS4xMjg4IDMxLjg5IDM4Ljg2IDMxLjE1NyAzOC44MzQ4QzMwLjIxNDcgMzguODAyNCAyOS4zMDc1IDM5LjE3MjUgMjguNzEzOCAzOS45MjA2QzI3LjY1ODQgNDEuMjUwNiAyNy45OTYzIDQzLjI4MzMgMjkuNDY3MSA0NC40NjE0QzI5LjQ4MiA0NC40NzM0IDI5LjQ5NzkgNDQuNDgyNyAyOS41MTI5IDQ0LjQ5NDNDMjkuNzE1IDQ0LjY1ODkgMjkuOTYyNSA0NC44Njk4IDMwLjE0ODMgNDUuMDA3NkMzMS4wMjE3IDQ1LjY1NTUgMzEuODE5NSA0NS45ODcyIDMyLjY4OTcgNDYuNTAxNUMzNC41MjMxIDQ3LjYzOTEgMzYuMDQzIDQ4LjU4MjMgMzcuMjQ4NiA0OS43MTk2QzM3LjcxOTQgNTAuMjIzNyAzNy44MDE2IDUxLjExMjIgMzcuODY0MyA1MS40OTY0TDM4Ljg0NjggNTIuMzc4MkMzMy41ODcyIDYwLjMzMDggMzEuMTUzIDcwLjE1MzkgMzIuNTkxNSA4MC4xNjI3TDMxLjMwNzcgODAuNTM3OEMzMC45NjkzIDgwLjk3NjggMzAuNDkxMiA4MS42Njc2IDI5Ljk5MTEgODEuODczOEMyOC40MTM4IDgyLjM3MjkgMjYuNjM4NyA4Mi41NTYyIDI0LjQ5NTYgODIuNzgxOUMyMy40ODk0IDgyLjg2NiAyMi42MjEzIDgyLjgxNTggMjEuNTU0NiA4My4wMTg4QzIxLjMxOTggODMuMDYzNSAyMC45OTI3IDgzLjE0OTEgMjAuNzM1OCA4My4yMDk3QzIwLjcyNjkgODMuMjExNiAyMC43MTg2IDgzLjIxNDIgMjAuNzA5NiA4My4yMTYyQzIwLjY5NTYgODMuMjE5NSAyMC42NzcyIDgzLjIyNjMgMjAuNjYzOCA4My4yMjk0QzE4Ljg1NyA4My42NjggMTcuNjk2MyA4NS4zMzY1IDE4LjA2OTkgODYuOTgwNUMxOC40NDM3IDg4LjYyNDggMjAuMjA4NiA4OS42MjQ4IDIyLjAyNjIgODkuMjMxMkMyMi4wMzkzIDg5LjIyODIgMjIuMDU4NCA4OS4yMjc3IDIyLjA3MiA4OS4yMjQ2QzIyLjA5MjYgODkuMjE5OSAyMi4xMTA2IDg5LjIwOTkgMjIuMTMxIDg5LjIwNDlDMjIuMzg0NCA4OS4xNDkgMjIuNzAxOSA4OS4wODY4IDIyLjkyMzYgODkuMDI3MkMyMy45NzIzIDg4Ljc0NTEgMjQuNzMxOCA4OC4zMzA2IDI1LjY3NDYgODcuOTY3N0MyNy43MDI5IDg3LjIzNjggMjkuMzgyOCA4Ni42MjYyIDMxLjAxOTUgODYuMzg4M0MzMS43MDMgODYuMzM0NSAzMi40MjMyIDg2LjgxMiAzMi43ODE0IDg3LjAxMzRMMzQuMTE3NyA4Ni43ODMxQzM3LjE5MjYgOTYuMzYxMyA0My42MzY2IDEwNC4xMDMgNTEuNzk2MyAxMDguOTYxTDUxLjIzOTYgMTEwLjMwM0M1MS40NDAzIDExMC44MjQgNTEuNjYxNiAxMTEuNTMgNTEuNTEyMSAxMTIuMDQ1QzUwLjkxNzEgMTEzLjU5NSA0OS44OTggMTE1LjIzMSA0OC43Mzc0IDExNy4wNTVDNDguMTc1NSAxMTcuODk4IDQ3LjYwMDQgMTE4LjU1MiA0Ny4wOTM0IDExOS41MTZDNDYuOTcyIDExOS43NDcgNDYuODE3NSAxMjAuMTAyIDQ2LjcwMDQgMTIwLjM0NkM0NS45MTI1IDEyMi4wMzkgNDYuNDkwNCAxMjMuOTkgNDguMDAzOCAxMjQuNzIyQzQ5LjUyNjggMTI1LjQ1OSA1MS40MTcxIDEyNC42ODIgNTIuMjM1MiAxMjIuOTg1QzUyLjIzNjQgMTIyLjk4MiA1Mi4yNDA2IDEyMi45OCA1Mi4yNDE3IDEyMi45NzhDNTIuMjQyNiAxMjIuOTc2IDUyLjI0MDkgMTIyLjk3MyA1Mi4yNDE3IDEyMi45NzFDNTIuMzU4MiAxMjIuNzMxIDUyLjUyMzMgMTIyLjQxNSA1Mi42MjE2IDEyMi4xODhDNTMuMDU2IDEyMS4xODkgNTMuMjAwNSAxMjAuMzMyIDUzLjUwNTkgMTE5LjM2NUM1NC4zMTcgMTE3LjMxOCA1NC43NjI2IDExNS4xNyA1NS44NzkxIDExMy44MzJDNTYuMTg0OSAxMTMuNDY2IDU2LjY4MzMgMTEzLjMyNSA1Ny4yMDAxIDExMy4xODZMNTcuODk0NCAxMTEuOTIyQzY1LjAwOCAxMTQuNjY1IDcyLjk3MDUgMTE1LjQwMiA4MC45MjQ1IDExMy41ODdDODIuNzM5MSAxMTMuMTczIDg0LjQ5MDggMTEyLjYzNyA4Ni4xODQzIDExMS45OTRDODYuMzc5NCAxMTIuMzQyIDg2Ljc0MiAxMTMuMDExIDg2LjgzOTMgMTEzLjE3OUM4Ny4zNjQ0IDExMy4zNTEgODcuOTM3NyAxMTMuNDM5IDg4LjQwNDcgMTE0LjEzM0M4OS4yNDAxIDExNS41NjcgODkuODExNCAxMTcuMjYzIDkwLjUwNzMgMTE5LjMxMkM5MC44MTI4IDEyMC4yNzkgOTAuOTYzOCAxMjEuMTM2IDkxLjM5ODEgMTIyLjEzNkM5MS40OTcxIDEyMi4zNjMgOTEuNjYxNCAxMjIuNjg0IDkxLjc3OCAxMjIuOTI1QzkyLjU5NDQgMTI0LjYyOCA5NC40OTA3IDEyNS40MDcgOTYuMDE1OSAxMjQuNjY5Qzk3LjUyOTIgMTIzLjkzNyA5OC4xMDc3IDEyMS45ODYgOTcuMzE5NCAxMjAuMjkzQzk3LjIwMjMgMTIwLjA0OSA5Ny4wNDEyIDExOS42OTUgOTYuOTE5OCAxMTkuNDY0Qzk2LjQxMjcgMTE4LjQ5OSA5NS44Mzc3IDExNy44NTIgOTUuMjc1OCAxMTcuMDA5Qzk0LjExNTIgMTE1LjE4NSA5My4xNTI2IDExMy42NyA5Mi41NTc1IDExMi4xMkM5Mi4zMDg3IDExMS4zMiA5Mi41OTk1IDExMC44MjMgOTIuNzkzMyAxMTAuMzAzQzkyLjY3NzIgMTEwLjE3IDkyLjQyODggMTA5LjQxNCA5Mi4yODI0IDEwOS4wNTlDMTAwLjc2MiAxMDQuMDI5IDEwNy4wMTcgOTUuOTk4NSAxMDkuOTU1IDg2LjcyMzlDMTEwLjM1MSA4Ni43ODY1IDExMS4wNDEgODYuOTA5MSAxMTEuMjY1IDg2Ljk1NDJDMTExLjcyNiA4Ni42NDg3IDExMi4xNDkgODYuMjUwMSAxMTIuOTgxIDg2LjMxNTlDMTE0LjYxNyA4Ni41NTM3IDExNi4yOTcgODcuMTY0NSAxMTguMzI2IDg3Ljg5NTNDMTE5LjI2OCA4OC4yNTgxIDEyMC4wMjggODguNjc5MyAxMjEuMDc3IDg4Ljk2MTRDMTIxLjI5OCA4OS4wMjEgMTIxLjYxNiA4OS4wNzY2IDEyMS44NjkgODkuMTMyNUMxMjEuODg5IDg5LjEzNzUgMTIxLjkwOCA4OS4xNDc1IDEyMS45MjggODkuMTUyMkMxMjEuOTQyIDg5LjE1NTMgMTIxLjk2MSA4OS4xNTU4IDEyMS45NzQgODkuMTU4OEMxMjMuNzkyIDg5LjU1MiAxMjUuNTU3IDg4LjU1MjYgMTI1LjkzIDg2LjkwODFDMTI2LjMwMyA4NS4yNjQxIDEyNS4xNDMgODMuNTk1MiAxMjMuMzM2IDgzLjE1N0MxMjMuMDc0IDgzLjA5NyAxMjIuNzAxIDgyLjk5NSAxMjIuNDQ2IDgyLjk0NjVDMTIxLjM3OSA4Mi43NDM1IDEyMC41MTEgODIuNzkzNSAxMTkuNTA1IDgyLjcwOTVDMTE3LjM2MSA4Mi40ODM5IDExNS41ODYgODIuMzAwNCAxMTQuMDA5IDgxLjgwMTRDMTEzLjM2NiA4MS41NTA3IDExMi45MDggODAuNzgxOSAxMTIuNjg2IDgwLjQ2NTVMMTExLjQ0OCA4MC4xMDM1QzExMi4wOSA3NS40MzggMTExLjkxNyA3MC41ODI1IDExMC44MDYgNjUuNzI0M0MxMDkuNjg1IDYwLjgyMDggMTA3LjcwNCA1Ni4zMzYxIDEwNS4wNjIgNTIuMzg0OEMxMDUuMzc5IDUyLjA5NDggMTA1Ljk3OSA1MS41NjEyIDEwNi4xNDkgNTEuNDA0M0MxMDYuMTk5IDUwLjg1MTcgMTA2LjE1NiA1MC4yNzIyIDEwNi43MjUgNDkuNjYwM0MxMDcuOTMxIDQ4LjUyMyAxMDkuNDUxIDQ3LjU3OTkgMTExLjI4NCA0Ni40NDIzQzExMi4xNTQgNDUuOTI3OSAxMTIuOTU5IDQ1LjU5NjQgMTEzLjgzMiA0NC45NDg0QzExNC4wMyA0NC44MDE5IDExNC4yOTkgNDQuNTY5OSAxMTQuNTA3IDQ0LjQwMjJDMTE1Ljk3NyA0My4yMjM3IDExNi4zMTYgNDEuMTkxMSAxMTUuMjYgMzkuODYxNEMxMTQuMjA0IDM4LjUzMTcgMTEyLjE1OSAzOC40MDY1IDExMC42ODggMzkuNTg1QzExMC40NzkgMzkuNzUxNiAxMTAuMTk1IDM5Ljk2ODggMTEwLjAwNyA0MC4xMzEyQzEwOS4xODQgNDAuODQyNiAxMDguNjc2IDQxLjU0NTIgMTA3Ljk4MyA0Mi4yODMyQzEwNi40NzEgNDMuODI1OSAxMDUuMjIyIDQ1LjExMyAxMDMuODUgNDYuMDQwOUMxMDMuMjU1IDQ2LjM4ODUgMTAyLjM4NSA0Ni4yNjgyIDEwMS45OSA0Ni4yNDQ5TDEwMC44MjQgNDcuMDgwNkM5NC4xNzUzIDQwLjA3NjMgODUuMTIzNSAzNS41OTgyIDc1LjM3NjYgMzQuNzI4M0M3NS4zNDk0IDM0LjMxNzkgNzUuMzEzNyAzMy41NzYxIDc1LjMwNDYgMzMuMzUyOUM3NC45MDU2IDMyLjk2OTMgNzQuNDIzNSAzMi42NDE4IDc0LjMwMjQgMzEuODEzQzc0LjE2OTEgMzAuMTU2OSA3NC4zOTE3IDI4LjM3NTIgNzQuNjQ5NiAyNi4yMjU4Qzc0Ljc5MTkgMjUuMjIxNiA3NS4wMjg0IDI0LjM4NzMgNzUuMDY4OCAyMy4yOTczQzc1LjA3OCAyMy4wNDk1IDc1LjA2MzIgMjIuNjkgNzUuMDYyMiAyMi40MjIxQzc1LjA2MiAyMC41MzIyIDczLjY4OTggMTguOTk5OCA3MS45OTY4IDE5Wk02OC4xNTg1IDQyLjg4ODZMNjcuMjQ4IDU5LjA0NDdMNjcuMTgyNSA1OS4wNzc2QzY3LjEyMTQgNjAuNTIyOSA2NS45Mzc1IDYxLjY3NyA2NC40ODM5IDYxLjY3N0M2My44ODg0IDYxLjY3NyA2My4zMzg4IDYxLjQ4NDkgNjIuODkyMiA2MS4xNTcxTDYyLjg2NiA2MS4xNzAzTDQ5LjY4MDcgNTEuNzc5NEM1My43MzMxIDQ3Ljc3NTkgNTguOTE2NCA0NC44MTcyIDY0Ljg5IDQzLjQ1NDZDNjUuOTgxMiA0My4yMDU2IDY3LjA3MTkgNDMuMDIwOSA2OC4xNTg1IDQyLjg4ODZaTTc1Ljg0MTcgNDIuODg4NkM4Mi44MTU5IDQzLjc1MDQgODkuMjY1NyA0Ni45MjMyIDk0LjIwODEgNTEuNzg2TDgxLjEwOCA2MS4xMTc2TDgxLjA2MjEgNjEuMDk3OUM3OS44OTk0IDYxLjk1MTIgNzguMjYxMSA2MS43Mzk0IDc3LjM1NDggNjAuNTk3OEM3Ni45ODM1IDYwLjEzMDEgNzYuNzg4NyA1OS41ODAxIDc2Ljc2NTMgNTkuMDI0OUw3Ni43NTIyIDU5LjAxODRMNzUuODQxNyA0Mi44ODg2Wk00NC44OTkxIDU3LjgxNEw1Ni45MzgyIDY4LjYzM0w1Ni45MjUxIDY4LjY5ODhDNTguMDExNyA2OS42NDc5IDU4LjE3MiA3MS4yOTQ5IDU3LjI2NTcgNzIuNDM2OEM1Ni44OTQ0IDcyLjkwNDUgNTYuMzk3NSA3My4yMTgyIDU1Ljg2MzkgNzMuMzY0N0w1NS44NTA4IDczLjQxNzNMNDAuNDE4OCA3Ny44OTIzQzM5LjYzMzQgNzAuNjc2NSA0MS4zMjYxIDYzLjY2MjEgNDQuODk5MSA1Ny44MTRaTTk5LjAwOTQgNTcuODIwNkMxMDAuNzk4IDYwLjczMzYgMTAyLjE1MyA2My45ODcxIDEwMi45NTkgNjcuNTE0M0MxMDMuNzU2IDcwLjk5OTEgMTAzLjk1NiA3NC40Nzc4IDEwMy42MjcgNzcuODM5N0w4OC4xMTY2IDczLjM1MTVMODguMTAzNSA3My4yODU3Qzg2LjcxNDUgNzIuOTA0MyA4NS44NjA5IDcxLjQ4NDggODYuMTg0MyA3MC4wNjExQzg2LjMxNjggNjkuNDc3OCA4Ni42MjQ5IDY4Ljk4NDQgODcuMDQyMyA2OC42MTk4TDg3LjAzNTggNjguNTg2OUw5OS4wMDk0IDU3LjgyMDZaTTY5LjUyNzQgNjkuNDY4OEg3NC40NTk2TDc3LjUyNTEgNzMuMzE4Nkw3Ni40MjQ3IDc4LjEyMjZMNzEuOTk2OCA4MC4yNjE0TDY3LjU1NTggNzguMTE2MUw2Ni40NTU0IDczLjMxMkw2OS41Mjc0IDY5LjQ2ODhaTTg1LjMzOTMgODIuNjQzN0M4NS41NDg5IDgyLjYzMzEgODUuNzU3NiA4Mi42NTIgODUuOTYxNiA4Mi42ODk4TDg1Ljk4NzggODIuNjU2OUwxMDEuOTUgODUuMzY4MkM5OS42MTQyIDkxLjk2MjQgOTUuMTQ0IDk3LjY3NSA4OS4xNzExIDEwMS40OThMODIuOTc0NyA4Ni40NjA2TDgyLjk5NDQgODYuNDM0M0M4Mi40MjUyIDg1LjEwNTUgODIuOTk0OCA4My41NDcyIDg0LjMwNDQgODIuOTEzNUM4NC42Mzk3IDgyLjc1MTMgODQuOTkgODIuNjYxNCA4NS4zMzkzIDgyLjY0MzdaTTU4LjUyOTggODIuNzA5NUM1OS43NDggODIuNzI2NyA2MC44NDA2IDgzLjU3NjEgNjEuMTIzNyA4NC44MjJDNjEuMjU2MiA4NS40MDUyIDYxLjE5MTcgODUuOTgzMSA2MC45NzMgODYuNDkzNUw2MS4wMTg5IDg2LjU1MjdMNTQuODg4IDEwMS40MzlDNDkuMTU1OSA5Ny43NDMyIDQ0LjU5MDQgOTIuMjA5OSA0Mi4xNDgxIDg1LjQyMDhMNTcuOTczMSA4Mi43MjI3TDU3Ljk5OTMgODIuNzU1NkM1OC4xNzYzIDgyLjcyMjkgNTguMzU1OCA4Mi43MDcxIDU4LjUyOTggODIuNzA5NVpNNzEuODk4NiA4OS4yMzEyQzcyLjMyMjkgODkuMjE1NSA3Mi43NTM0IDg5LjMwMyA3My4xNjI3IDg5LjUwMUM3My42OTkyIDg5Ljc2MDYgNzQuMTEzNiA5MC4xNjkyIDc0LjM3NDUgOTAuNjU5Mkg3NC40MzM0TDgyLjIzNDYgMTA0LjgyMUM4MS4yMjIxIDEwNS4xNjIgODAuMTgxMyAxMDUuNDU0IDc5LjExNjcgMTA1LjY5N0M3My4xNTA1IDEwNy4wNTggNjcuMjAzMiAxMDYuNjQ1IDYxLjgxOCAxMDQuODAyTDY5LjU5OTUgOTAuNjY1OEg2OS42MTI2QzcwLjA3OTUgODkuNzg4OCA3MC45NjUgODkuMjY1NiA3MS44OTg2IDg5LjIzMTJaIiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIwLjI1Ii8+CjxkZWZzPgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXJfNjgxXzI4NDUiIHgxPSIxMCIgeTE9IjE1LjUiIHgyPSIxNDQiIHkyPSIxMzEuNSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjNEQ4N0ZGIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzA1NDdEMCIvPgo8L2xpbmVhckdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPgo= + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "storageClass"], ["spec", "nodeGroups"], ["spec", "nodeGroups", "md0"], ["spec", "nodeGroups", "md0", "minReplicas"], ["spec", "nodeGroups", "md0", "maxReplicas"], ["spec", "nodeGroups", "md0", "instanceType"], ["spec", "nodeGroups", "md0", "ephemeralStorage"], ["spec", "nodeGroups", "md0", "roles"], ["spec", "nodeGroups", "md0", "resources"], ["spec", "nodeGroups", "md0", "gpus"], ["spec", "version"], ["spec", "host"], ["spec", "addons"], ["spec", "addons", "certManager"], ["spec", "addons", "certManager", "enabled"], ["spec", "addons", "certManager", "valuesOverride"], ["spec", "addons", "cilium"], ["spec", "addons", "cilium", "valuesOverride"], ["spec", "addons", "gatewayAPI"], ["spec", "addons", "gatewayAPI", "enabled"], ["spec", "addons", "ingressNginx"], ["spec", "addons", "ingressNginx", "enabled"], ["spec", "addons", "ingressNginx", "exposeMethod"], ["spec", "addons", "ingressNginx", "hosts"], ["spec", "addons", "ingressNginx", "valuesOverride"], ["spec", "addons", "gpuOperator"], ["spec", "addons", "gpuOperator", "enabled"], ["spec", "addons", "gpuOperator", "valuesOverride"], ["spec", "addons", "hami"], ["spec", "addons", "hami", "enabled"], ["spec", "addons", "hami", "valuesOverride"], ["spec", "addons", "fluxcd"], ["spec", "addons", "fluxcd", "enabled"], ["spec", "addons", "fluxcd", "valuesOverride"], ["spec", "addons", "monitoringAgents"], ["spec", "addons", "monitoringAgents", "enabled"], ["spec", "addons", "monitoringAgents", "valuesOverride"], ["spec", "addons", "verticalPodAutoscaler"], ["spec", "addons", "verticalPodAutoscaler", "valuesOverride"], ["spec", "addons", "velero"], ["spec", "addons", "velero", "enabled"], ["spec", "addons", "velero", "valuesOverride"], ["spec", "addons", "coredns"], ["spec", "addons", "coredns", "valuesOverride"], ["spec", "controlPlane"], ["spec", "controlPlane", "replicas"], ["spec", "controlPlane", "apiServer"], ["spec", "controlPlane", "apiServer", "resources"], ["spec", "controlPlane", "apiServer", "resourcesPreset"], ["spec", "controlPlane", "controllerManager"], ["spec", "controlPlane", "controllerManager", "resources"], ["spec", "controlPlane", "controllerManager", "resourcesPreset"], ["spec", "controlPlane", "scheduler"], ["spec", "controlPlane", "scheduler", "resources"], ["spec", "controlPlane", "scheduler", "resourcesPreset"], ["spec", "controlPlane", "konnectivity"], ["spec", "controlPlane", "konnectivity", "server"], ["spec", "controlPlane", "konnectivity", "server", "resources"], ["spec", "controlPlane", "konnectivity", "server", "resourcesPreset"], ["spec", "images"], ["spec", "images", "waitForKubeconfig"]] + secrets: + exclude: [] + include: + - resourceNames: + - kubernetes-{{ .name }}-admin-kubeconfig + services: + exclude: [] + include: + - resourceNames: + - kubernetes-{{ .name }} + - kubernetes-{{ .name }}-ingress-nginx + - matchLabels: + cluster.x-k8s.io/cluster-name: kubernetes-{{ .name }} + ingresses: + exclude: [] + include: + - resourceNames: + - kubernetes-{{ .name }} + - kubernetes-{{ .name }}-ingress-nginx diff --git a/packages/system/kubernetes-rd/templates/cozyrd.yaml b/packages/system/kubernetes-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/kubernetes-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/kubernetes-rd/values.yaml b/packages/system/kubernetes-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/kubernetes-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/kubevirt-cdi-operator/Makefile b/packages/system/kubevirt-cdi-operator/Makefile index 7022599f..7232216f 100644 --- a/packages/system/kubevirt-cdi-operator/Makefile +++ b/packages/system/kubevirt-cdi-operator/Makefile @@ -1,7 +1,7 @@ export NAME=kubevirt-cdi-operator export NAMESPACE=cozy-kubevirt-cdi -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf templates diff --git a/packages/system/kubevirt-cdi-operator/templates/cdi-operator.yaml b/packages/system/kubevirt-cdi-operator/templates/cdi-operator.yaml index a482a13d..f46ba09e 100644 --- a/packages/system/kubevirt-cdi-operator/templates/cdi-operator.yaml +++ b/packages/system/kubevirt-cdi-operator/templates/cdi-operator.yaml @@ -110,9 +110,9 @@ spec: description: CDIConfig at CDI level properties: dataVolumeTTLSeconds: - description: DataVolumeTTLSeconds is the time in seconds after - DataVolume completion it can be garbage collected. Disabled - by default. + description: |- + DataVolumeTTLSeconds is the time in seconds after DataVolume completion it can be garbage collected. Disabled by default. + Deprecated: Removed in v1.62. format: int32 type: integer featureGates: @@ -124,7 +124,7 @@ spec: filesystemOverhead: description: FilesystemOverhead describes the space reserved for overhead when using Filesystem volumes. A value is between 0 - and 1, if not defined it is 0.055 (5.5% overhead) + and 1, if not defined it is 0.06 (6% overhead) properties: global: description: Global is how much space of a Filesystem volume @@ -2642,9 +2642,9 @@ spec: description: CDIConfig at CDI level properties: dataVolumeTTLSeconds: - description: DataVolumeTTLSeconds is the time in seconds after - DataVolume completion it can be garbage collected. Disabled - by default. + description: |- + DataVolumeTTLSeconds is the time in seconds after DataVolume completion it can be garbage collected. Disabled by default. + Deprecated: Removed in v1.62. format: int32 type: integer featureGates: @@ -2656,7 +2656,7 @@ spec: filesystemOverhead: description: FilesystemOverhead describes the space reserved for overhead when using Filesystem volumes. A value is between 0 - and 1, if not defined it is 0.055 (5.5% overhead) + and 1, if not defined it is 0.06 (6% overhead) properties: global: description: Global is how much space of a Filesystem volume @@ -5164,6 +5164,14 @@ rules: - get - update - delete +- apiGroups: + - admissionregistration.k8s.io + resourceNames: + - cdi-api-dataimportcron-mutate + resources: + - mutatingwebhookconfigurations + verbs: + - delete - apiGroups: - apiregistration.k8s.io resources: @@ -5175,6 +5183,17 @@ rules: - create - update - delete +- apiGroups: + - populator.storage.k8s.io + resources: + - volumepopulators + verbs: + - get + - list + - watch + - create + - update + - delete - apiGroups: - authorization.k8s.io resources: @@ -5285,6 +5304,9 @@ rules: verbs: - create - patch + - get + - list + - watch - apiGroups: - "" resources: @@ -5325,6 +5347,14 @@ rules: - watch - create - delete +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - watch - apiGroups: - "" resources: @@ -5358,6 +5388,7 @@ rules: - get - apiGroups: - cdi.kubevirt.io + - forklift.cdi.kubevirt.io resources: - '*' verbs: @@ -5418,14 +5449,11 @@ rules: verbs: - update - apiGroups: - - forklift.cdi.kubevirt.io + - authorization.k8s.io resources: - - ovirtvolumepopulators - - openstackvolumepopulators + - subjectaccessreviews verbs: - - get - - list - - watch + - create - apiGroups: - "" resources: @@ -5670,6 +5698,7 @@ metadata: labels: cdi.kubevirt.io: cdi-operator name: cdi-operator + np.kubevirt.io/allow-access-cluster-services: "true" operator.cdi.kubevirt.io: "" prometheus.cdi.kubevirt.io: "true" name: cdi-operator @@ -5683,9 +5712,12 @@ spec: strategy: {} template: metadata: + annotations: + openshift.io/required-scc: restricted-v2 labels: cdi.kubevirt.io: cdi-operator name: cdi-operator + np.kubevirt.io/allow-access-cluster-services: "true" operator.cdi.kubevirt.io: "" prometheus.cdi.kubevirt.io: "true" spec: @@ -5706,33 +5738,50 @@ spec: - name: DEPLOY_CLUSTER_RESOURCES value: "true" - name: OPERATOR_VERSION - value: v1.61.0 + value: v1.64.0 - name: CONTROLLER_IMAGE - value: quay.io/kubevirt/cdi-controller:v1.61.0 + value: quay.io/kubevirt/cdi-controller:v1.64.0 - name: IMPORTER_IMAGE - value: quay.io/kubevirt/cdi-importer:v1.61.0 + value: quay.io/kubevirt/cdi-importer:v1.64.0 - name: CLONER_IMAGE - value: quay.io/kubevirt/cdi-cloner:v1.61.0 + value: quay.io/kubevirt/cdi-cloner:v1.64.0 - name: OVIRT_POPULATOR_IMAGE - value: quay.io/kubevirt/cdi-importer:v1.61.0 + value: quay.io/kubevirt/cdi-importer:v1.64.0 - name: APISERVER_IMAGE - value: quay.io/kubevirt/cdi-apiserver:v1.61.0 + value: quay.io/kubevirt/cdi-apiserver:v1.64.0 - name: UPLOAD_SERVER_IMAGE - value: quay.io/kubevirt/cdi-uploadserver:v1.61.0 + value: quay.io/kubevirt/cdi-uploadserver:v1.64.0 - name: UPLOAD_PROXY_IMAGE - value: quay.io/kubevirt/cdi-uploadproxy:v1.61.0 + value: quay.io/kubevirt/cdi-uploadproxy:v1.64.0 - name: VERBOSITY value: "1" - name: PULL_POLICY value: IfNotPresent - name: MONITORING_NAMESPACE - image: quay.io/kubevirt/cdi-operator:v1.61.0 + image: quay.io/kubevirt/cdi-operator:v1.64.0 imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /healthz + port: 8444 + scheme: HTTP + initialDelaySeconds: 5 + timeoutSeconds: 10 name: cdi-operator ports: - - containerPort: 8080 + - containerPort: 8443 name: metrics protocol: TCP + - containerPort: 8444 + name: health + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: 8444 + scheme: HTTP + initialDelaySeconds: 5 + timeoutSeconds: 10 resources: requests: cpu: 100m @@ -5746,13 +5795,19 @@ spec: seccompProfile: type: RuntimeDefault terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File + terminationMessagePolicy: FallbackToLogsOnError nodeSelector: kubernetes.io/os: linux securityContext: runAsNonRoot: true serviceAccountName: cdi-operator tolerations: - - key: CriticalAddonsOnly - operator: Exists ---- \ No newline at end of file + - key: CriticalAddonsOnly + operator: Exists + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane + operator: Exists + - effect: NoSchedule + key: node-role.kubernetes.io/master + operator: Exists +--- diff --git a/packages/system/kubevirt-cdi/Makefile b/packages/system/kubevirt-cdi/Makefile index 0b3791a1..709e4880 100644 --- a/packages/system/kubevirt-cdi/Makefile +++ b/packages/system/kubevirt-cdi/Makefile @@ -1,7 +1,7 @@ export NAME=kubevirt-cdi export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf templates diff --git a/packages/system/kubevirt-cdi/templates/cdi-cr.yaml b/packages/system/kubevirt-cdi/templates/cdi-cr.yaml index 8f57ec43..7dc15ee0 100644 --- a/packages/system/kubevirt-cdi/templates/cdi-cr.yaml +++ b/packages/system/kubevirt-cdi/templates/cdi-cr.yaml @@ -3,7 +3,7 @@ kind: CDI metadata: name: cdi spec: - cloneStrategyOverride: copy + cloneStrategyOverride: csi-clone config: {{- with .Values.uploadProxyURL }} uploadProxyURLOverride: {{ quote . }} diff --git a/packages/system/kubevirt-cdi/templates/cdi-uploadproxy-ingress.yaml b/packages/system/kubevirt-cdi/templates/cdi-uploadproxy-ingress.yaml index 58eef4fa..ee89953f 100644 --- a/packages/system/kubevirt-cdi/templates/cdi-uploadproxy-ingress.yaml +++ b/packages/system/kubevirt-cdi/templates/cdi-uploadproxy-ingress.yaml @@ -1,7 +1,6 @@ -{{- $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" }} +{{- $host := index .Values._cluster "root-host" }} +{{- $exposeServices := splitList "," ((index .Values._cluster "expose-services") | default "") }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} {{- if and (has "cdi-uploadproxy" $exposeServices) }} diff --git a/packages/system/kubevirt-csi-node/templates/deploy.yaml b/packages/system/kubevirt-csi-node/templates/deploy.yaml index bed710d9..4e95bf77 100644 --- a/packages/system/kubevirt-csi-node/templates/deploy.yaml +++ b/packages/system/kubevirt-csi-node/templates/deploy.yaml @@ -167,6 +167,7 @@ spec: args: - "--endpoint=unix:/csi/csi.sock" - "--node-name=$(KUBE_NODE_NAME)" + - "--run-controller-service=false" - "--v=5" env: - name: KUBE_NODE_NAME @@ -273,6 +274,7 @@ metadata: annotations: storageclass.kubernetes.io/is-default-class: "true" provisioner: csi.kubevirt.io +allowVolumeExpansion: true parameters: infraStorageClassName: {{ .Values.storageClass }} bus: scsi diff --git a/packages/system/kubevirt-csi-node/templates/volumesnapshotclass.yaml b/packages/system/kubevirt-csi-node/templates/volumesnapshotclass.yaml new file mode 100644 index 00000000..139c62e0 --- /dev/null +++ b/packages/system/kubevirt-csi-node/templates/volumesnapshotclass.yaml @@ -0,0 +1,8 @@ +apiVersion: snapshot.storage.k8s.io/v1 +kind: VolumeSnapshotClass +metadata: + name: kubevirt-snapshots + labels: + velero.io/csi-volumesnapshot-class: "true" +driver: csi.kubevirt.io +deletionPolicy: Delete diff --git a/packages/system/kubevirt-csi-node/values.yaml b/packages/system/kubevirt-csi-node/values.yaml index 50a91561..56e28543 100644 --- a/packages/system/kubevirt-csi-node/values.yaml +++ b/packages/system/kubevirt-csi-node/values.yaml @@ -1,3 +1,3 @@ storageClass: replicated csiDriver: - image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.25.2@sha256:761e7235ff9cb7f6f223f00954943e6a5af32ed6624ee592a8610122f96febb0 + image: ghcr.io/cozystack/cozystack/kubevirt-csi-driver:0.0.0@sha256:72154a97054e16cdf3dea6129d962b8d7e86b55cf9386095e8ac2ce7c8b69172 diff --git a/packages/system/kubevirt-instancetypes/Makefile b/packages/system/kubevirt-instancetypes/Makefile index d0498f10..b9f84b83 100644 --- a/packages/system/kubevirt-instancetypes/Makefile +++ b/packages/system/kubevirt-instancetypes/Makefile @@ -1,7 +1,7 @@ export NAME=kubevirt-instancetypes export NAMESPACE=cozy-kubevirt -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf templates diff --git a/packages/system/kubevirt-operator/Makefile b/packages/system/kubevirt-operator/Makefile index 42bf80a7..1734aa2a 100644 --- a/packages/system/kubevirt-operator/Makefile +++ b/packages/system/kubevirt-operator/Makefile @@ -1,12 +1,13 @@ export NAME=kubevirt-operator export NAMESPACE=cozy-kubevirt -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf templates mkdir templates - export RELEASE=$$(curl https://storage.googleapis.com/kubevirt-prow/release/kubevirt/kubevirt/stable.txt) && \ + # v1.7.0 blocked by https://github.com/kubevirt/kubevirt/issues/16386 + export RELEASE=v1.6.3 && \ wget https://github.com/kubevirt/kubevirt/releases/download/$${RELEASE}/kubevirt-operator.yaml -O templates/kubevirt-operator.yaml && \ sed -i 's/namespace: kubevirt/namespace: $(NAMESPACE)/g' templates/kubevirt-operator.yaml awk -i inplace -v RS="---" '!/kind: Namespace/{printf "%s", $$0 RS}' templates/kubevirt-operator.yaml diff --git a/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml b/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml index f20762df..72fabfa0 100644 --- a/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml +++ b/packages/system/kubevirt-operator/alerts/PrometheusRule.yaml @@ -10,7 +10,7 @@ spec: expr: | max_over_time( kubevirt_vm_info{ - status!="Running", + status!="running", exported_namespace=~".+", name=~".+" }[10m] diff --git a/packages/system/kubevirt-operator/templates/kubevirt-operator.yaml b/packages/system/kubevirt-operator/templates/kubevirt-operator.yaml index aa170001..8350d457 100644 --- a/packages/system/kubevirt-operator/templates/kubevirt-operator.yaml +++ b/packages/system/kubevirt-operator/templates/kubevirt-operator.yaml @@ -288,6 +288,10 @@ spec: developerConfiguration: description: DeveloperConfiguration holds developer options properties: + clusterProfiler: + description: Enable the ability to pprof profile KubeVirt + control plane + type: boolean cpuAllocationRatio: description: |- For each requested virtual CPU, CPUAllocationRatio defines how much physical CPU to request per VMI @@ -337,6 +341,8 @@ spec: type: integer virtOperator: type: integer + virtSynchronizationController: + type: integer type: object memoryOvercommit: description: |- @@ -594,6 +600,13 @@ spec: If set to true, migrations will still start in pre-copy, but switch to post-copy when CompletionTimeoutPerGiB triggers. Defaults to false type: boolean + allowWorkloadDisruption: + description: |- + AllowWorkloadDisruption indicates that the migration shouldn't be + canceled after acceptableCompletionTime is exceeded. Instead, if + permitted, migration will be switched to post-copy or the VMI will be + paused to allow the migration to complete + type: boolean bandwidthPerMigration: anyOf: - type: integer @@ -606,8 +619,8 @@ spec: completionTimeoutPerGiB: description: |- CompletionTimeoutPerGiB is the maximum number of seconds per GiB a migration is allowed to take. - If a live-migration takes longer to migrate than this value multiplied by the size of the VMI, - the migration will be cancelled, unless AllowPostCopy is true. Defaults to 150 + If the timeout is reached, the migration will be either paused, switched + to post-copy or cancelled depending on other settings. Defaults to 150 format: int64 type: integer disableTLS: @@ -965,17 +978,17 @@ spec: type: object type: object vmRolloutStrategy: - description: VMRolloutStrategy defines how changes to a VM object - propagate to its VMI + description: |- + VMRolloutStrategy defines how live-updatable fields, like CPU sockets, memory, + tolerations, and affinity, are propagated from a VM to its VMI. enum: - Stage - LiveUpdate nullable: true type: string vmStateStorageClass: - description: |- - VMStateStorageClass is the name of the storage class to use for the PVCs created to preserve VM state, like TPM. - The storage class must support RWX in filesystem mode. + description: VMStateStorageClass is the name of the storage class + to use for the PVCs created to preserve VM state, like TPM. type: string webhookConfiguration: description: |- @@ -2125,6 +2138,10 @@ spec: When ServiceMonitorNamespace is set, then we'll install the service monitor object in that namespace otherwise we will use the monitoring namespace. type: string + synchronizationPort: + description: Specify the port to listen on for VMI status synchronization + traffic. Default is 9185 + type: string uninstallStrategy: description: |- Specifies if kubevirt can be deleted if workloads are still present. @@ -3256,6 +3273,11 @@ spec: description: KubeVirtPhase is a label for the phase of a KubeVirt deployment at the current time. type: string + synchronizationAddresses: + items: + type: string + type: array + x-kubernetes-list-type: atomic targetDeploymentConfig: type: string targetDeploymentID: @@ -3545,6 +3567,10 @@ spec: developerConfiguration: description: DeveloperConfiguration holds developer options properties: + clusterProfiler: + description: Enable the ability to pprof profile KubeVirt + control plane + type: boolean cpuAllocationRatio: description: |- For each requested virtual CPU, CPUAllocationRatio defines how much physical CPU to request per VMI @@ -3594,6 +3620,8 @@ spec: type: integer virtOperator: type: integer + virtSynchronizationController: + type: integer type: object memoryOvercommit: description: |- @@ -3851,6 +3879,13 @@ spec: If set to true, migrations will still start in pre-copy, but switch to post-copy when CompletionTimeoutPerGiB triggers. Defaults to false type: boolean + allowWorkloadDisruption: + description: |- + AllowWorkloadDisruption indicates that the migration shouldn't be + canceled after acceptableCompletionTime is exceeded. Instead, if + permitted, migration will be switched to post-copy or the VMI will be + paused to allow the migration to complete + type: boolean bandwidthPerMigration: anyOf: - type: integer @@ -3863,8 +3898,8 @@ spec: completionTimeoutPerGiB: description: |- CompletionTimeoutPerGiB is the maximum number of seconds per GiB a migration is allowed to take. - If a live-migration takes longer to migrate than this value multiplied by the size of the VMI, - the migration will be cancelled, unless AllowPostCopy is true. Defaults to 150 + If the timeout is reached, the migration will be either paused, switched + to post-copy or cancelled depending on other settings. Defaults to 150 format: int64 type: integer disableTLS: @@ -4222,17 +4257,17 @@ spec: type: object type: object vmRolloutStrategy: - description: VMRolloutStrategy defines how changes to a VM object - propagate to its VMI + description: |- + VMRolloutStrategy defines how live-updatable fields, like CPU sockets, memory, + tolerations, and affinity, are propagated from a VM to its VMI. enum: - Stage - LiveUpdate nullable: true type: string vmStateStorageClass: - description: |- - VMStateStorageClass is the name of the storage class to use for the PVCs created to preserve VM state, like TPM. - The storage class must support RWX in filesystem mode. + description: VMStateStorageClass is the name of the storage class + to use for the PVCs created to preserve VM state, like TPM. type: string webhookConfiguration: description: |- @@ -5382,6 +5417,10 @@ spec: When ServiceMonitorNamespace is set, then we'll install the service monitor object in that namespace otherwise we will use the monitoring namespace. type: string + synchronizationPort: + description: Specify the port to listen on for VMI status synchronization + traffic. Default is 9185 + type: string uninstallStrategy: description: |- Specifies if kubevirt can be deleted if workloads are still present. @@ -6513,6 +6552,11 @@ spec: description: KubeVirtPhase is a label for the phase of a KubeVirt deployment at the current time. type: string + synchronizationAddresses: + items: + type: string + type: array + x-kubernetes-list-type: atomic targetDeploymentConfig: type: string targetDeploymentID: @@ -6588,6 +6632,8 @@ rules: - kubevirt-virt-api-certs - kubevirt-controller-certs - kubevirt-exportproxy-certs + - kubevirt-synchronization-controller-certs + - kubevirt-synchronization-controller-server-certs resources: - secrets verbs: @@ -6699,6 +6745,28 @@ rules: - get - list - watch +- apiGroups: + - "" + resourceNames: + - kubevirt-ca + resources: + - configmaps + verbs: + - get + - list + - watch +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - delete + - update + - create + - patch --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding @@ -6922,6 +6990,7 @@ rules: - persistentvolumeclaims verbs: - get + - list - apiGroups: - kubevirt.io resources: @@ -7141,6 +7210,7 @@ rules: resources: - virtualmachinesnapshots - virtualmachinesnapshots/status + - virtualmachinesnapshots/finalizers - virtualmachinesnapshotcontents - virtualmachinesnapshotcontents/status - virtualmachinesnapshotcontents/finalizers @@ -7193,15 +7263,18 @@ rules: - kubevirt.io resources: - virtualmachines/finalizers + - virtualmachineinstances/finalizers verbs: - update - apiGroups: - subresources.kubevirt.io resources: + - virtualmachines/stop - virtualmachineinstances/addvolume - virtualmachineinstances/removevolume - virtualmachineinstances/freeze - virtualmachineinstances/unfreeze + - virtualmachineinstances/reset - virtualmachineinstances/softreboot - virtualmachineinstances/sev/setupsession - virtualmachineinstances/sev/injectlaunchsecret @@ -7305,6 +7378,23 @@ rules: verbs: - list - watch +- apiGroups: + - batch + resources: + - jobs + verbs: + - create + - get + - delete +- apiGroups: + - resource.k8s.io + resources: + - resourceslices + - resourceclaims + verbs: + - list + - watch + - get - apiGroups: - kubevirt.io resources: @@ -7376,6 +7466,50 @@ rules: verbs: - list - watch +- apiGroups: + - kubevirt.io + resources: + - virtualmachineinstances + verbs: + - get + - list + - watch + - update + - patch +- apiGroups: + - kubevirt.io + resources: + - virtualmachineinstancemigrations + verbs: + - get + - list + - watch + - patch + - delete +- apiGroups: + - kubevirt.io + resources: + - kubevirts + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - events + verbs: + - update + - create + - patch +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - list + - watch - apiGroups: - kubevirt.io resources: @@ -7404,6 +7538,8 @@ rules: - virtualmachineinstances/sev/fetchcertchain - virtualmachineinstances/sev/querylaunchmeasurement - virtualmachineinstances/usbredir + - virtualmachines/objectgraph + - virtualmachineinstances/objectgraph verbs: - get - apiGroups: @@ -7416,6 +7552,7 @@ rules: - virtualmachineinstances/freeze - virtualmachineinstances/unfreeze - virtualmachineinstances/softreboot + - virtualmachineinstances/reset - virtualmachineinstances/sev/setupsession - virtualmachineinstances/sev/injectlaunchsecret verbs: @@ -7435,7 +7572,6 @@ rules: - virtualmachines/restart - virtualmachines/addvolume - virtualmachines/removevolume - - virtualmachines/migrate - virtualmachines/memorydump verbs: - update @@ -7452,7 +7588,6 @@ rules: - virtualmachineinstances - virtualmachineinstancepresets - virtualmachineinstancereplicasets - - virtualmachineinstancemigrations verbs: - get - delete @@ -7462,6 +7597,14 @@ rules: - list - watch - deletecollection +- apiGroups: + - kubevirt.io + resources: + - virtualmachineinstancemigrations + verbs: + - get + - list + - watch - apiGroups: - snapshot.kubevirt.io resources: @@ -7553,6 +7696,8 @@ rules: - virtualmachineinstances/sev/fetchcertchain - virtualmachineinstances/sev/querylaunchmeasurement - virtualmachineinstances/usbredir + - virtualmachines/objectgraph + - virtualmachineinstances/objectgraph verbs: - get - apiGroups: @@ -7565,6 +7710,7 @@ rules: - virtualmachineinstances/freeze - virtualmachineinstances/unfreeze - virtualmachineinstances/softreboot + - virtualmachineinstances/reset - virtualmachineinstances/sev/setupsession - virtualmachineinstances/sev/injectlaunchsecret verbs: @@ -7584,7 +7730,6 @@ rules: - virtualmachines/restart - virtualmachines/addvolume - virtualmachines/removevolume - - virtualmachines/migrate - virtualmachines/memorydump verbs: - update @@ -7601,7 +7746,6 @@ rules: - virtualmachineinstances - virtualmachineinstancepresets - virtualmachineinstancereplicasets - - virtualmachineinstancemigrations verbs: - get - delete @@ -7610,6 +7754,14 @@ rules: - patch - list - watch +- apiGroups: + - kubevirt.io + resources: + - virtualmachineinstancemigrations + verbs: + - get + - list + - watch - apiGroups: - snapshot.kubevirt.io resources: @@ -7706,6 +7858,8 @@ rules: - virtualmachineinstances/userlist - virtualmachineinstances/sev/fetchcertchain - virtualmachineinstances/sev/querylaunchmeasurement + - virtualmachines/objectgraph + - virtualmachineinstances/objectgraph verbs: - get - apiGroups: @@ -7788,6 +7942,25 @@ rules: - get - list - watch +- apiGroups: + - subresources.kubevirt.io + resources: + - virtualmachines/migrate + verbs: + - update +- apiGroups: + - kubevirt.io + resources: + - virtualmachineinstancemigrations + verbs: + - get + - delete + - create + - update + - patch + - list + - watch + - deletecollection - apiGroups: - authentication.k8s.io resources: @@ -7833,6 +8006,8 @@ spec: type: RollingUpdate template: metadata: + annotations: + openshift.io/required-scc: restricted-v2 labels: kubevirt.io: virt-operator name: virt-operator @@ -7861,15 +8036,22 @@ spec: - virt-operator env: - name: VIRT_OPERATOR_IMAGE - value: quay.io/kubevirt/virt-operator:v1.4.0 + value: quay.io/kubevirt/virt-operator:v1.6.3 - name: WATCH_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.annotations['olm.targetNamespaces'] - name: KUBEVIRT_VERSION - value: v1.4.0 - image: quay.io/kubevirt/virt-operator:v1.4.0 + value: v1.6.3 + image: quay.io/kubevirt/virt-operator:v1.6.3 imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: /metrics + port: 8443 + scheme: HTTPS + initialDelaySeconds: 5 + timeoutSeconds: 10 name: virt-operator ports: - containerPort: 8443 @@ -7896,6 +8078,7 @@ spec: - ALL seccompProfile: type: RuntimeDefault + terminationMessagePolicy: FallbackToLogsOnError volumeMounts: - mountPath: /etc/virt-operator/certificates name: kubevirt-operator-certs @@ -7920,4 +8103,4 @@ spec: secretName: kubevirt-operator-certs - emptyDir: {} name: profile-data ---- \ No newline at end of file +--- diff --git a/packages/system/kubevirt/Makefile b/packages/system/kubevirt/Makefile index 2c2e57ab..246001d0 100644 --- a/packages/system/kubevirt/Makefile +++ b/packages/system/kubevirt/Makefile @@ -1,7 +1,7 @@ export NAME=kubevirt export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf templates diff --git a/packages/system/kubevirt/templates/kubevirt-cr.yaml b/packages/system/kubevirt/templates/kubevirt-cr.yaml index b4ec5b70..e6538a68 100644 --- a/packages/system/kubevirt/templates/kubevirt-cr.yaml +++ b/packages/system/kubevirt/templates/kubevirt-cr.yaml @@ -22,7 +22,15 @@ spec: - GPU - VMExport evictionStrategy: LiveMigrate + virtualMachineOptions: + disableSerialConsoleLog: {} + vmRolloutStrategy: LiveUpdate + workloadUpdateStrategy: + workloadUpdateMethods: + - LiveMigrate + - Evict + batchEvictionInterval: 1m + batchEvictionSize: 10 customizeComponents: {} imagePullPolicy: IfNotPresent monitorNamespace: tenant-root - workloadUpdateStrategy: {} diff --git a/packages/system/kubevirt/templates/vm-exportproxy-ingress.yaml b/packages/system/kubevirt/templates/vm-exportproxy-ingress.yaml index b77743d0..a089f5ef 100644 --- a/packages/system/kubevirt/templates/vm-exportproxy-ingress.yaml +++ b/packages/system/kubevirt/templates/vm-exportproxy-ingress.yaml @@ -1,7 +1,6 @@ -{{- $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" }} +{{- $host := index .Values._cluster "root-host" }} +{{- $exposeServices := splitList "," ((index .Values._cluster "expose-services") | default "") }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} {{- if and (has "vm-exportproxy" $exposeServices) }} apiVersion: networking.k8s.io/v1 diff --git a/packages/system/lineage-controller-webhook/.gitignore b/packages/system/lineage-controller-webhook/.gitignore new file mode 100644 index 00000000..ada68ff0 --- /dev/null +++ b/packages/system/lineage-controller-webhook/.gitignore @@ -0,0 +1,27 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +bin/* +Dockerfile.cross + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Go workspace file +go.work + +# Kubernetes Generated files - skip generated files, except for vendored files +!vendor/**/zz_generated.* + +# editor and IDE paraphernalia +.idea +.vscode +*.swp +*.swo +*~ diff --git a/packages/system/lineage-controller-webhook/Chart.yaml b/packages/system/lineage-controller-webhook/Chart.yaml new file mode 100644 index 00000000..5b262f05 --- /dev/null +++ b/packages/system/lineage-controller-webhook/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-lineage-controller-webhook +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/lineage-controller-webhook/Makefile b/packages/system/lineage-controller-webhook/Makefile new file mode 100644 index 00000000..cdc1cf01 --- /dev/null +++ b/packages/system/lineage-controller-webhook/Makefile @@ -0,0 +1,23 @@ +NAME=lineage-controller-webhook +NAMESPACE=cozy-system + +include ../../../hack/common-envs.mk +include ../../../hack/package.mk + +.PHONY: test + +image: image-lineage-controller-webhook + +test: + helm unittest . + +image-lineage-controller-webhook: + docker buildx build -f images/lineage-controller-webhook/Dockerfile ../../.. \ + --tag $(REGISTRY)/lineage-controller-webhook:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/lineage-controller-webhook:latest \ + --cache-to type=inline \ + --metadata-file images/lineage-controller-webhook.json \ + $(BUILDX_ARGS) + IMAGE="$(REGISTRY)/lineage-controller-webhook:$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/lineage-controller-webhook.json -o json -r)" \ + yq -i '.lineageControllerWebhook.image = strenv(IMAGE)' values.yaml + rm -f images/lineage-controller-webhook.json diff --git a/packages/system/lineage-controller-webhook/README.md b/packages/system/lineage-controller-webhook/README.md new file mode 100644 index 00000000..1e43c9c8 --- /dev/null +++ b/packages/system/lineage-controller-webhook/README.md @@ -0,0 +1,67 @@ +# lineage-controller-webhook + +Cozystack system package for the **lineage controller webhook** — a mutating +admission webhook that stamps "lineage" labels onto tenant workloads, linking +each resource back to the Cozystack `Application` that ultimately owns it. + +The webhook intercepts CREATE and UPDATE on `pods`, `secrets`, `services`, +`persistentvolumeclaims`, `ingresses.networking.k8s.io`, and +`workloadmonitors.cozystack.io` outside system namespaces. For each request it +walks the ownership graph upward (Kubernetes `ownerReferences`, then the +`HelmRelease` Flux installed the resource with, then the Cozystack +`Application`-derived CRD that produced the HelmRelease) and writes the +discovered application's group, kind and name as labels +(`apps.cozystack.io/application.{group,kind,name}`) on the incoming object. +Those labels let the aggregated API server, the Cozystack dashboard, and other +lineage-aware consumers reason about which application a resource belongs to. + +The webhook serves TLS on port 9443 with a cert-manager issued certificate, and +runs with `failurePolicy: Fail` — every CREATE/UPDATE on the resources above +is gated on the webhook being reachable. + +## Topology + +The chart ships a single shape, modelled on `cozystack-api`: + +- **Deployment** with two replicas (override via `replicas`). +- **Soft `nodeAffinity`** preferring `node-role.kubernetes.io/control-plane` + (`Exists`, so it matches both Talos's empty value and k3s/kubeadm's `"true"`). + Soft means: the pod lands on a control-plane node when one is reachable, and + on any worker otherwise — no override needed for managed Kubernetes, + Cozy-in-Cozy tenants, or any other cluster where control-plane nodes aren't + visible. +- **Permissive `tolerations`** (`[{operator: Exists}]`) so the pod can land on + tainted control-plane nodes when the soft affinity is satisfiable. +- **Soft `podAntiAffinity`** on `kubernetes.io/hostname` so replicas spread + across nodes when possible (best-effort). +- **`PodDisruptionBudget`** with `maxUnavailable: 1`, unconditional. At + `replicas: 1` it's a useful no-op (allows full drain); at `replicas >= 2` + it caps disruption to one pod. +- **`Service` with `spec.trafficDistribution: PreferClose`** so the apiserver + prefers a webhook endpoint on its own node when one exists, and transparently + falls over to a remote endpoint otherwise. Requires Kubernetes ≥ 1.31; on + older clusters the field is silently ignored and traffic uses default + cluster-wide distribution. + +## Parameters + +All keys live under the top-level `lineageControllerWebhook:` map. + +| Name | Description | Value | +| ----------------------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------- | +| `image` | Container image (digest-pinned) | `ghcr.io/cozystack/cozystack/lineage-controller-webhook:v1.3.0@sha256:e898…6fb0` | +| `debug` | Enable `--zap-log-level=debug` instead of `info` | `false` | +| `replicas` | Deployment replica count | `2` | +| `localK8sAPIEndpoint.enabled` | **Deprecated.** See note below. | `false` | + +### `localK8sAPIEndpoint.enabled` (deprecated) + +When enabled, this injects `KUBERNETES_SERVICE_HOST=status.hostIP` and +`KUBERNETES_SERVICE_PORT=6443` so the webhook talks to the kube-apiserver on +its own node. It was originally added to avoid latency on the +webhook-to-apiserver path, but it is only valid when the pod is actually +scheduled on an apiserver-bearing node — which the chart's soft control-plane +affinity no longer guarantees. With this flag enabled and the pod scheduled +off a control-plane node, the controller will crash-loop dialing a non- +apiserver hostIP. Slated for removal once the latency motivation is addressed +in the webhook itself; **leave disabled**. diff --git a/packages/system/lineage-controller-webhook/images/lineage-controller-webhook/Dockerfile b/packages/system/lineage-controller-webhook/images/lineage-controller-webhook/Dockerfile new file mode 100644 index 00000000..d9232d98 --- /dev/null +++ b/packages/system/lineage-controller-webhook/images/lineage-controller-webhook/Dockerfile @@ -0,0 +1,23 @@ +FROM golang:1.25-alpine AS builder + +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /workspace + +COPY go.mod go.sum ./ +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go mod download + +COPY api api/ +COPY pkg pkg/ +COPY cmd cmd/ +COPY internal internal/ + +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -ldflags="-extldflags=-static" -o /lineage-controller-webhook cmd/lineage-controller-webhook/main.go + +FROM scratch + +COPY --from=builder /lineage-controller-webhook /lineage-controller-webhook +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt + +ENTRYPOINT ["/lineage-controller-webhook"] diff --git a/packages/system/lineage-controller-webhook/templates/certmanager.yaml b/packages/system/lineage-controller-webhook/templates/certmanager.yaml new file mode 100644 index 00000000..11b7f21a --- /dev/null +++ b/packages/system/lineage-controller-webhook/templates/certmanager.yaml @@ -0,0 +1,47 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: lineage-controller-webhook-selfsigned + namespace: {{ .Release.Namespace }} +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: lineage-controller-webhook-ca + namespace: {{ .Release.Namespace }} +spec: + secretName: lineage-controller-webhook-ca + duration: 43800h # 5 years + commonName: lineage-controller-webhook-ca + issuerRef: + name: lineage-controller-webhook-selfsigned + isCA: true + privateKey: + rotationPolicy: Never +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: lineage-controller-webhook-ca + namespace: {{ .Release.Namespace }} +spec: + ca: + secretName: lineage-controller-webhook-ca +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: lineage-controller-webhook + namespace: {{ .Release.Namespace }} +spec: + secretName: lineage-controller-webhook-cert + duration: 8760h + renewBefore: 720h + issuerRef: + name: lineage-controller-webhook-ca + commonName: lineage-controller-webhook + dnsNames: + - lineage-controller-webhook + - lineage-controller-webhook.{{ .Release.Namespace }}.svc diff --git a/packages/system/lineage-controller-webhook/templates/mutatingwebhookconfiguration.yaml b/packages/system/lineage-controller-webhook/templates/mutatingwebhookconfiguration.yaml new file mode 100644 index 00000000..88b62a21 --- /dev/null +++ b/packages/system/lineage-controller-webhook/templates/mutatingwebhookconfiguration.yaml @@ -0,0 +1,46 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: lineage + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/lineage-controller-webhook + labels: + app: cozystack-controller +webhooks: + - name: lineage.cozystack.io + admissionReviewVersions: ["v1"] + sideEffects: None + clientConfig: + service: + name: lineage-controller-webhook + namespace: {{ .Release.Namespace }} + path: /mutate-lineage + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods","secrets", "services", "persistentvolumeclaims"] + - operations: ["CREATE", "UPDATE"] + apiGroups: ["networking.k8s.io"] + apiVersions: ["v1"] + resources: ["ingresses"] + - operations: ["CREATE", "UPDATE"] + apiGroups: ["cozystack.io"] + apiVersions: ["v1alpha1"] + resources: ["workloadmonitors"] + failurePolicy: Fail + namespaceSelector: + matchExpressions: + - key: cozystack.io/system + operator: NotIn + values: + - "true" + - key: kubernetes.io/metadata.name + operator: NotIn + values: + - kube-system + - default + objectSelector: + matchExpressions: + - key: internal.cozystack.io/managed-by-cozystack + operator: DoesNotExist diff --git a/packages/system/lineage-controller-webhook/templates/pdb.yaml b/packages/system/lineage-controller-webhook/templates/pdb.yaml new file mode 100644 index 00000000..0786c8ff --- /dev/null +++ b/packages/system/lineage-controller-webhook/templates/pdb.yaml @@ -0,0 +1,9 @@ +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: lineage-controller-webhook +spec: + maxUnavailable: 1 + selector: + matchLabels: + app: lineage-controller-webhook diff --git a/packages/system/lineage-controller-webhook/templates/rbac-bind.yaml b/packages/system/lineage-controller-webhook/templates/rbac-bind.yaml new file mode 100644 index 00000000..9a509d08 --- /dev/null +++ b/packages/system/lineage-controller-webhook/templates/rbac-bind.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: lineage-controller-webhook +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: lineage-controller-webhook +subjects: +- kind: ServiceAccount + name: lineage-controller-webhook + namespace: {{ .Release.Namespace }} diff --git a/packages/system/lineage-controller-webhook/templates/rbac.yaml b/packages/system/lineage-controller-webhook/templates/rbac.yaml new file mode 100644 index 00000000..d8b3f871 --- /dev/null +++ b/packages/system/lineage-controller-webhook/templates/rbac.yaml @@ -0,0 +1,8 @@ +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: lineage-controller-webhook +rules: +- apiGroups: ['*'] + resources: ['*'] + verbs: ["get", "list", "watch"] diff --git a/packages/system/lineage-controller-webhook/templates/sa.yaml b/packages/system/lineage-controller-webhook/templates/sa.yaml new file mode 100644 index 00000000..a17761f0 --- /dev/null +++ b/packages/system/lineage-controller-webhook/templates/sa.yaml @@ -0,0 +1,4 @@ +kind: ServiceAccount +apiVersion: v1 +metadata: + name: lineage-controller-webhook diff --git a/packages/system/lineage-controller-webhook/templates/service.yaml b/packages/system/lineage-controller-webhook/templates/service.yaml new file mode 100644 index 00000000..fbb3ad54 --- /dev/null +++ b/packages/system/lineage-controller-webhook/templates/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: lineage-controller-webhook + labels: + app: lineage-controller-webhook +spec: + trafficDistribution: PreferClose + type: ClusterIP + ports: + - port: 443 + targetPort: 9443 + protocol: TCP + name: webhook + selector: + app: lineage-controller-webhook diff --git a/packages/system/lineage-controller-webhook/templates/workload.yaml b/packages/system/lineage-controller-webhook/templates/workload.yaml new file mode 100644 index 00000000..097919c6 --- /dev/null +++ b/packages/system/lineage-controller-webhook/templates/workload.yaml @@ -0,0 +1,66 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: lineage-controller-webhook + labels: + app: lineage-controller-webhook +spec: + replicas: {{ .Values.lineageControllerWebhook.replicas }} + selector: + matchLabels: + app: lineage-controller-webhook + template: + metadata: + labels: + app: lineage-controller-webhook + spec: + serviceAccountName: lineage-controller-webhook + tolerations: + - operator: Exists + affinity: + nodeAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + preference: + matchExpressions: + - key: node-role.kubernetes.io/control-plane + operator: Exists + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + topologyKey: kubernetes.io/hostname + labelSelector: + matchLabels: + app: lineage-controller-webhook + containers: + - name: lineage-controller-webhook + image: "{{ .Values.lineageControllerWebhook.image }}" + {{- if .Values.lineageControllerWebhook.localK8sAPIEndpoint.enabled }} + env: + - name: KUBERNETES_SERVICE_HOST + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: KUBERNETES_SERVICE_PORT + value: "6443" + {{- end }} + args: + {{- if .Values.lineageControllerWebhook.debug }} + - --zap-log-level=debug + {{- else }} + - --zap-log-level=info + {{- end }} + ports: + - name: webhook + containerPort: 9443 + volumeMounts: + - name: webhook-certs + mountPath: /tmp/k8s-webhook-server/serving-certs + readOnly: true + volumes: + - name: webhook-certs + secret: + secretName: lineage-controller-webhook-cert + defaultMode: 0400 diff --git a/packages/system/lineage-controller-webhook/tests/service_test.yaml b/packages/system/lineage-controller-webhook/tests/service_test.yaml new file mode 100644 index 00000000..3cdbddd8 --- /dev/null +++ b/packages/system/lineage-controller-webhook/tests/service_test.yaml @@ -0,0 +1,30 @@ +suite: lineage-controller-webhook service +templates: + - templates/service.yaml + +release: + name: lineage-controller-webhook + namespace: cozy-system + +tests: + - it: renders a ClusterIP service on 443 -> 9443 with PreferClose traffic distribution + asserts: + - isKind: + of: Service + - equal: + path: spec.type + value: ClusterIP + - equal: + path: spec.trafficDistribution + value: PreferClose + - notExists: + path: spec.internalTrafficPolicy + - equal: + path: spec.ports[0].port + value: 443 + - equal: + path: spec.ports[0].targetPort + value: 9443 + - equal: + path: spec.selector.app + value: lineage-controller-webhook diff --git a/packages/system/lineage-controller-webhook/tests/workload_test.yaml b/packages/system/lineage-controller-webhook/tests/workload_test.yaml new file mode 100644 index 00000000..bcb24014 --- /dev/null +++ b/packages/system/lineage-controller-webhook/tests/workload_test.yaml @@ -0,0 +1,99 @@ +suite: lineage-controller-webhook workload + PDB +templates: + - templates/workload.yaml + - templates/pdb.yaml + +release: + name: lineage-controller-webhook + namespace: cozy-system + +tests: + # ---- Default Deployment shape ---------------------------------------------- + + - it: defaults render a 2-replica Deployment with soft control-plane nodeAffinity, soft podAntiAffinity, and Exists tolerations + template: templates/workload.yaml + asserts: + - isKind: + of: Deployment + - equal: + path: spec.replicas + value: 2 + - equal: + path: spec.template.spec.tolerations + value: + - operator: Exists + - equal: + path: spec.template.spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution + value: + - weight: 100 + preference: + matchExpressions: + - key: node-role.kubernetes.io/control-plane + operator: Exists + - notExists: + path: spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution + - equal: + path: spec.template.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey + value: kubernetes.io/hostname + + - it: defaults inject no localK8sAPIEndpoint env vars (knob is opt-in) + template: templates/workload.yaml + asserts: + - notExists: + path: spec.template.spec.containers[0].env + + # ---- PDB -------------------------------------------------------------------- + + - it: PDB renders unconditionally with maxUnavailable=1 at the default replica count + template: templates/pdb.yaml + asserts: + - isKind: + of: PodDisruptionBudget + - equal: + path: spec.maxUnavailable + value: 1 + - notExists: + path: spec.minAvailable + + - it: PDB still renders at replicas=1 (no-op, but consistent shape) + set: + lineageControllerWebhook.replicas: 1 + template: templates/pdb.yaml + asserts: + - isKind: + of: PodDisruptionBudget + - equal: + path: spec.maxUnavailable + value: 1 + + # ---- Replica override ------------------------------------------------------- + + - it: replicas value drives spec.replicas + set: + lineageControllerWebhook.replicas: 5 + template: templates/workload.yaml + asserts: + - equal: + path: spec.replicas + value: 5 + + # ---- Deprecated localK8sAPIEndpoint knob ----------------------------------- + + - it: localK8sAPIEndpoint.enabled=true injects KUBERNETES_SERVICE_HOST and PORT env vars + set: + lineageControllerWebhook.localK8sAPIEndpoint.enabled: true + template: templates/workload.yaml + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: KUBERNETES_SERVICE_HOST + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - contains: + path: spec.template.spec.containers[0].env + content: + name: KUBERNETES_SERVICE_PORT + value: "6443" diff --git a/packages/system/lineage-controller-webhook/values.yaml b/packages/system/lineage-controller-webhook/values.yaml new file mode 100644 index 00000000..e56d332d --- /dev/null +++ b/packages/system/lineage-controller-webhook/values.yaml @@ -0,0 +1,13 @@ +lineageControllerWebhook: + image: ghcr.io/cozystack/cozystack/lineage-controller-webhook:v1.3.0@sha256:e8984709686a5eaf19b89da378d7b8c688ea5607e0783a88d9c9e4ccfca96fb0 + debug: false + replicas: 2 + # DEPRECATED. Injects KUBERNETES_SERVICE_HOST=status.hostIP and + # KUBERNETES_SERVICE_PORT=6443 so the webhook talks to the apiserver on its + # own node — only valid when the pod is actually scheduled on an apiserver- + # bearing node. Now that the chart's nodeAffinity to control-plane is soft + # (preferred, not required), the pod can land off-control-plane and crash- + # loop dialing a non-apiserver hostIP. Slated for removal once webhook + # performance work obviates the locality motivation. Leave disabled. + localK8sAPIEndpoint: + enabled: false diff --git a/packages/system/linstor-gui/Chart.yaml b/packages/system/linstor-gui/Chart.yaml new file mode 100644 index 00000000..e361a819 --- /dev/null +++ b/packages/system/linstor-gui/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-linstor-gui +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/linstor-gui/Makefile b/packages/system/linstor-gui/Makefile new file mode 100644 index 00000000..b408491d --- /dev/null +++ b/packages/system/linstor-gui/Makefile @@ -0,0 +1,29 @@ +export NAME=linstor-gui +export NAMESPACE=cozy-linstor + +include ../../../hack/common-envs.mk +include ../../../hack/package.mk + +LINSTOR_GUI_VERSION ?= 2.3.0 + +.PHONY: image image-linstor-gui test + +image: image-linstor-gui + +image-linstor-gui: + docker buildx build images/linstor-gui \ + --build-arg LINSTOR_GUI_VERSION=$(LINSTOR_GUI_VERSION) \ + --tag $(REGISTRY)/linstor-gui:$(call settag,$(LINSTOR_GUI_VERSION)) \ + --tag $(REGISTRY)/linstor-gui:$(call settag,$(LINSTOR_GUI_VERSION)-$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/linstor-gui:latest \ + --cache-to type=inline \ + --metadata-file images/linstor-gui.json \ + $(BUILDX_ARGS) + REPOSITORY="$(REGISTRY)/linstor-gui" \ + yq -i '.image.repository = strenv(REPOSITORY)' values.yaml + TAG="$(call settag,$(LINSTOR_GUI_VERSION))@$$(yq e '."containerimage.digest"' images/linstor-gui.json -o json -r)" \ + yq -i '.image.tag = strenv(TAG)' values.yaml + rm -f images/linstor-gui.json + +test: + helm unittest . diff --git a/packages/system/linstor-gui/README.md b/packages/system/linstor-gui/README.md new file mode 100644 index 00000000..8f8053ab --- /dev/null +++ b/packages/system/linstor-gui/README.md @@ -0,0 +1,64 @@ +# linstor-gui + +Cozystack system package for [LINBIT/linstor-gui](https://github.com/LINBIT/linstor-gui) +— a web UI for managing LINSTOR nodes, resources, volumes and snapshots. + +Installed alongside the `linstor` package in the `cozy-linstor` namespace. The UI +proxies the LINSTOR controller REST API at `https://linstor-controller.cozy-linstor.svc:3371` +using mTLS with the `linstor-client-tls` secret created by the `linstor` package. + +## Exposing the UI + +### Option 1 — Keycloak-protected Ingress (recommended) + +The chart ships an `oauth2-proxy` based gatekeeper plus a `KeycloakClient` CRD +so the UI can be published on `linstor-gui.` behind the cluster +Keycloak realm. Access is restricted to members of the +`cozystack-cluster-admin` Keycloak group — the same group that grants +cluster-admin RBAC on the host cluster. Authenticating against the `cozy` +realm alone is not sufficient; users outside that group receive a 403 from +oauth2-proxy before any request reaches the UI or the LINSTOR controller. + +To turn it on, add `linstor-gui` to `publishing.exposedServices` in the core +`cozystack` values (same list that controls `dashboard`). OIDC must be +enabled (`authentication.oidc.enabled: true`) — if it is not, the Ingress and +gatekeeper Deployment are deliberately **not** rendered, because the LINSTOR +REST API surface must not be exposed unauthenticated. + +Once enabled, the UI is reachable at `https://linstor-gui.` and +authentication is delegated to Keycloak via the `linstor-gui` client +(auto-provisioned through the `KeycloakClient` CRD; the client secret is +persisted in the `linstor-gui-client` Secret in `cozy-linstor`). + +### Option 2 — Port-forward + +If you have not set up Keycloak or want ad-hoc access, use the `ClusterIP` +Service: + +```bash +kubectl -n cozy-linstor port-forward svc/linstor-gui 3373:80 +``` + +then open . + +## Parameters + +### Image + +| Name | Description | Value | +| ------------------ | ---------------------------------------------------------- | ----------------------------------------- | +| `image.repository` | LINSTOR GUI container image repository | `ghcr.io/cozystack/cozystack/linstor-gui` | +| `image.tag` | LINSTOR GUI container image tag (digest recommended) | `2.3.0` | + +### Deployment + +| Name | Description | Value | +| ---------- | ------------------------------- | ----- | +| `replicas` | Number of linstor-gui replicas | `1` | + +### LINSTOR controller connection + +| Name | Description | Value | +| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------- | +| `linstor.endpoint` | In-cluster URL of the LINSTOR controller REST API (HTTPS, mTLS) | `https://linstor-controller.cozy-linstor.svc:3371` | +| `linstor.clientSecret` | Kubernetes Secret with `tls.crt`, `tls.key`, `ca.crt` used as the mTLS client certificate against the LINSTOR controller. Created by the `linstor` package. | `linstor-client-tls` | diff --git a/packages/system/linstor-gui/images/linstor-gui/Dockerfile b/packages/system/linstor-gui/images/linstor-gui/Dockerfile new file mode 100644 index 00000000..2082ef0d --- /dev/null +++ b/packages/system/linstor-gui/images/linstor-gui/Dockerfile @@ -0,0 +1,19 @@ +# Upstream: https://github.com/LINBIT/linstor-gui (GPL-3.0) +# Serves the pre-built LINSTOR GUI tarball published by LINBIT from a hardened +# nginx-unprivileged image. nginx.conf is supplied by the chart via ConfigMap, +# so the upstream docker-entrypoint.sh / nginx.conf.template is not used. +FROM nginxinc/nginx-unprivileged:1.29-alpine + +ARG LINSTOR_GUI_VERSION +USER root +RUN apk add --no-cache curl tar && \ + curl -fsSL "https://pkg.linbit.com/downloads/linstor/linstor-gui-${LINSTOR_GUI_VERSION}.tar.gz" -o /tmp/linstor-gui.tar.gz && \ + mkdir -p /usr/share/nginx/html && \ + tar -xzf /tmp/linstor-gui.tar.gz -C /usr/share/nginx/html --strip-components=2 "linstor-gui-${LINSTOR_GUI_VERSION}/dist" && \ + rm -f /tmp/linstor-gui.tar.gz && \ + apk del curl tar && \ + chown -R 101:101 /usr/share/nginx/html + +USER 101 +EXPOSE 3373 +CMD ["nginx", "-g", "daemon off;"] diff --git a/packages/system/linstor-gui/templates/_helpers.tpl b/packages/system/linstor-gui/templates/_helpers.tpl new file mode 100644 index 00000000..6cad99ee --- /dev/null +++ b/packages/system/linstor-gui/templates/_helpers.tpl @@ -0,0 +1,17 @@ +{{/* +Common labels +*/}} +{{- define "linstor-gui.labels" -}} +app.kubernetes.io/name: linstor-gui +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/part-of: cozystack +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "linstor-gui.selectorLabels" -}} +app.kubernetes.io/name: linstor-gui +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/packages/system/linstor-gui/templates/configmap-nginx.yaml b/packages/system/linstor-gui/templates/configmap-nginx.yaml new file mode 100644 index 00000000..86acd0f7 --- /dev/null +++ b/packages/system/linstor-gui/templates/configmap-nginx.yaml @@ -0,0 +1,113 @@ +{{/* +Parse the LINSTOR endpoint so nginx can set `proxy_ssl_name` correctly. +The endpoint must be an https:// URL — http:// would downgrade the +mTLS-protected controller path. +*/}} +{{- if not (hasPrefix "https://" .Values.linstor.endpoint) -}} +{{- fail "linstor.endpoint must start with https:// to enforce mTLS to the LINSTOR controller" -}} +{{- end -}} +{{- $endpoint := trimPrefix "https://" .Values.linstor.endpoint -}} +{{- $endpointHost := (splitList ":" $endpoint) | first -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: linstor-gui-nginx + labels: + {{- include "linstor-gui.labels" . | nindent 4 }} +data: + nginx.conf: | + worker_processes auto; + pid /tmp/nginx.pid; + + events { + worker_connections 1024; + } + + http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + server_tokens off; + + client_body_temp_path /tmp/client_body; + proxy_temp_path /tmp/proxy; + fastcgi_temp_path /tmp/fastcgi; + uwsgi_temp_path /tmp/uwsgi; + scgi_temp_path /tmp/scgi; + + sendfile on; + keepalive_timeout 65; + + server { + listen 3373; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + # Shared proxy + mTLS settings for the LINSTOR controller upstream + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_ssl_certificate /etc/linstor/client/tls.crt; + proxy_ssl_certificate_key /etc/linstor/client/tls.key; + proxy_ssl_trusted_certificate /etc/linstor/client/ca.crt; + proxy_ssl_verify on; + proxy_ssl_verify_depth 2; + proxy_ssl_server_name on; + proxy_ssl_name {{ $endpointHost }}; + + # Static UI assets + location / { + try_files $uri $uri/ /index.html; + } + + # Lock the linstor-gui in-app authentication panel. + # + # Unlike most LINSTOR features, the GUI's "authenticationEnabled" + # toggle and user list are NOT controller-side properties — they + # are persisted as ordinary KeyValueStore instances named + # `__gui__settings` and `__gui__users`. The SPA reads them on + # every page load and, if `authenticationEnabled=true`, gates the + # whole UI behind its own login screen against a self-managed + # admin user. + # + # Cozystack already enforces authentication at the Ingress + # (oauth2-proxy + Keycloak), and the in-app login is a foot-gun: + # if a user enables it and forgets/misconfigures the password, the + # only recovery is shelling into the linstor-controller pod and + # running `linstor key-value-store modify __gui__settings + # authenticationEnabled false`. + # + # We allow GETs (so the SPA can read state and render normally + # with auth=off) but reject every mutating method on those two + # KeyValueStore instances. Any other key-value-store entry the + # GUI uses (e.g. __gui__mode) keeps working as expected. + location ~ ^/v1/key-value-store/__gui__(settings|users)(/|$) { + default_type application/json; + # `if ... return` is the one documented-safe use of `if` in + # nginx (see "If is Evil"), so it's fine here. We allow GET/HEAD + # for the SPA's read path and reject every mutating method. + if ($request_method !~ ^(GET|HEAD)$) { + return 403 '{"ret_code":-1,"message":"linstor-gui in-app authentication is disabled by cozystack: authentication is enforced at the Ingress via Keycloak."}'; + } + proxy_pass {{ .Values.linstor.endpoint }}; + } + + # Proxy LINSTOR REST API over mTLS to the controller + location /v1 { + proxy_pass {{ .Values.linstor.endpoint }}; + } + + location /metrics { + proxy_pass {{ .Values.linstor.endpoint }}; + } + + location = /healthz { + access_log off; + # default_type must come BEFORE `return` — `add_header` after a + # `return` is silently dropped by nginx because the response is + # already finalized. + default_type text/plain; + return 200 'ok'; + } + } + } diff --git a/packages/system/linstor-gui/templates/deployment.yaml b/packages/system/linstor-gui/templates/deployment.yaml new file mode 100644 index 00000000..92e2f7a6 --- /dev/null +++ b/packages/system/linstor-gui/templates/deployment.yaml @@ -0,0 +1,100 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: linstor-gui + labels: + {{- include "linstor-gui.labels" . | nindent 4 }} + annotations: + reloader.stakater.com/auto: "true" +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + {{- include "linstor-gui.selectorLabels" . | nindent 6 }} + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 0 + maxSurge: 1 + template: + metadata: + labels: + {{- include "linstor-gui.labels" . | nindent 8 }} + spec: + serviceAccountName: linstor-gui + automountServiceAccountToken: false + securityContext: + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchLabels: + {{- include "linstor-gui.selectorLabels" . | nindent 20 }} + topologyKey: kubernetes.io/hostname + containers: + - name: linstor-gui + image: {{ .Values.image.repository }}:{{ .Values.image.tag }} + imagePullPolicy: IfNotPresent + ports: + - name: http + containerPort: 3373 + protocol: TCP + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi + livenessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 5 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 2 + periodSeconds: 10 + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 101 + runAsGroup: 101 + capabilities: + drop: + - ALL + volumeMounts: + - name: nginx-config + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + readOnly: true + - name: linstor-client-tls + mountPath: /etc/linstor/client + readOnly: true + - name: tmp + mountPath: /tmp + - name: nginx-cache + mountPath: /var/cache/nginx + volumes: + - name: nginx-config + configMap: + name: linstor-gui-nginx + - name: linstor-client-tls + secret: + secretName: {{ .Values.linstor.clientSecret }} + # 0444 so nginx (UID 101) can read the mTLS client keypair; + # the secret volume is pod-local, not a broader disclosure. + defaultMode: 0444 + - name: tmp + emptyDir: {} + - name: nginx-cache + emptyDir: {} diff --git a/packages/system/linstor-gui/templates/gatekeeper-sa.yaml b/packages/system/linstor-gui/templates/gatekeeper-sa.yaml new file mode 100644 index 00000000..d89f68dc --- /dev/null +++ b/packages/system/linstor-gui/templates/gatekeeper-sa.yaml @@ -0,0 +1,13 @@ +{{- $oidcEnabled := index .Values._cluster "oidc-enabled" }} +{{- if eq $oidcEnabled "true" }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: linstor-gui-gatekeeper + labels: + app.kubernetes.io/instance: linstor-gui + app.kubernetes.io/name: gatekeeper + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/part-of: cozystack +automountServiceAccountToken: false +{{- end }} diff --git a/packages/system/linstor-gui/templates/gatekeeper-svc.yaml b/packages/system/linstor-gui/templates/gatekeeper-svc.yaml new file mode 100644 index 00000000..7d50219e --- /dev/null +++ b/packages/system/linstor-gui/templates/gatekeeper-svc.yaml @@ -0,0 +1,22 @@ +{{- $oidcEnabled := index .Values._cluster "oidc-enabled" }} +{{- if eq $oidcEnabled "true" }} +apiVersion: v1 +kind: Service +metadata: + name: linstor-gui-gatekeeper + labels: + app.kubernetes.io/instance: linstor-gui + app.kubernetes.io/name: gatekeeper + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/part-of: cozystack +spec: + type: ClusterIP + ports: + - name: ingress + port: 8000 + protocol: TCP + targetPort: 8000 + selector: + app.kubernetes.io/instance: linstor-gui + app.kubernetes.io/name: gatekeeper +{{- end }} diff --git a/packages/system/linstor-gui/templates/gatekeeper.yaml b/packages/system/linstor-gui/templates/gatekeeper.yaml new file mode 100644 index 00000000..81451f41 --- /dev/null +++ b/packages/system/linstor-gui/templates/gatekeeper.yaml @@ -0,0 +1,148 @@ +{{- $host := index .Values._cluster "root-host" }} +{{- $oidcEnabled := index .Values._cluster "oidc-enabled" }} +{{- $oidcInsecureSkipVerify := index .Values._cluster "oidc-insecure-skip-verify" }} +{{- $keycloakInternalUrl := index .Values._cluster "keycloak-internal-url" | default "" }} + +{{- /* +Gatekeeper (oauth2-proxy) fronts the linstor-gui Service and handles the +OIDC flow against the cluster Keycloak realm. The Ingress below points at +this Service — not at linstor-gui directly — so every external request +authenticates before hitting nginx/mTLS→controller. + +Only rendered when oidc-enabled=true. If the cluster has OIDC disabled we +deliberately do not ship an unauthenticated token-proxy fallback (unlike +dashboard): linstor-gui surfaces raw storage state and should not be +reachable via Ingress without Keycloak login. + +Access is further restricted to the cozystack-cluster-admin group +(--allowed-group below). The proxy authenticates with a static mTLS client +cert and LINSTOR itself has no per-user RBAC, so group membership is the +only boundary between a realm user and raw storage state. +*/ -}} +{{- if eq $oidcEnabled "true" }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: linstor-gui-gatekeeper + labels: + app.kubernetes.io/instance: linstor-gui + app.kubernetes.io/name: gatekeeper + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/part-of: cozystack + annotations: + reloader.stakater.com/auto: "true" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: linstor-gui + app.kubernetes.io/name: gatekeeper + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + template: + metadata: + labels: + app.kubernetes.io/instance: linstor-gui + app.kubernetes.io/name: gatekeeper + spec: + serviceAccountName: linstor-gui-gatekeeper + automountServiceAccountToken: false + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchLabels: + app.kubernetes.io/instance: linstor-gui + app.kubernetes.io/name: gatekeeper + topologyKey: kubernetes.io/hostname + containers: + - name: auth-proxy + image: quay.io/oauth2-proxy/oauth2-proxy:v7.12.0 + imagePullPolicy: IfNotPresent + args: + - --provider=oidc + - --upstream=http://linstor-gui.{{ .Release.Namespace }}.svc:80 + - --http-address=0.0.0.0:8000 + - --redirect-url=https://linstor-gui.{{ $host }}/oauth2/callback + - --oidc-issuer-url=https://keycloak.{{ $host }}/realms/cozy + {{- if $keycloakInternalUrl }} + - --skip-oidc-discovery + - --login-url=https://keycloak.{{ $host }}/realms/cozy/protocol/openid-connect/auth + - --redeem-url={{ $keycloakInternalUrl }}/protocol/openid-connect/token + - --oidc-jwks-url={{ $keycloakInternalUrl }}/protocol/openid-connect/certs + - --validate-url={{ $keycloakInternalUrl }}/protocol/openid-connect/userinfo + - --backend-logout-url={{ $keycloakInternalUrl }}/protocol/openid-connect/logout?id_token_hint={id_token} + {{- else }} + - --backend-logout-url=https://keycloak.{{ $host }}/realms/cozy/protocol/openid-connect/logout?id_token_hint={id_token} + {{- end }} + - --whitelist-domain=keycloak.{{ $host }} + - --email-domain=* + - --pass-access-token=true + - --pass-authorization-header=true + - --cookie-refresh=3m + - --cookie-name=kc-access + - --cookie-secure=true + - --cookie-secret=$(OAUTH2_PROXY_COOKIE_SECRET) + - --skip-provider-button + - --scope=openid email profile groups offline_access + - --allowed-group=cozystack-cluster-admin + {{- if eq $oidcInsecureSkipVerify "true" }} + - --ssl-insecure-skip-verify=true + {{- end }} + env: + - name: OAUTH2_PROXY_CLIENT_ID + value: linstor-gui + - name: OAUTH2_PROXY_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: linstor-gui-client + key: client-secret-key + - name: OAUTH2_PROXY_COOKIE_SECRET + valueFrom: + secretKeyRef: + name: linstor-gui-auth-config + key: cookieSecret + ports: + - name: proxy + containerPort: 8000 + protocol: TCP + livenessProbe: + httpGet: + path: /ping + port: proxy + initialDelaySeconds: 10 + periodSeconds: 15 + timeoutSeconds: 2 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /ping + port: proxy + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 2 + failureThreshold: 3 + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 200m + memory: 256Mi + securityContext: + runAsNonRoot: true + runAsUser: 1001 + runAsGroup: 1001 + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault +{{- end }} diff --git a/packages/system/linstor-gui/templates/ingress.yaml b/packages/system/linstor-gui/templates/ingress.yaml new file mode 100644 index 00000000..c50b0f86 --- /dev/null +++ b/packages/system/linstor-gui/templates/ingress.yaml @@ -0,0 +1,54 @@ +{{- $solver := (index .Values._cluster "solver") | default "http01" }} +{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }} +{{- $host := index .Values._cluster "root-host" }} +{{- $oidcEnabled := index .Values._cluster "oidc-enabled" }} +{{- $exposeServices := splitList "," ((index .Values._cluster "expose-services") | default "") }} +{{- $exposeIngress := (index .Values._cluster "expose-ingress") | default "tenant-root" }} + +{{- /* +Only publish an Ingress when the operator has opted this service in AND +OIDC is enabled cluster-wide. If OIDC is off we deliberately do not +expose linstor-gui: without Keycloak there is no authentication layer in +front of the LINSTOR REST API proxy. Users can still reach the UI via +`kubectl port-forward` to the ClusterIP service. +*/ -}} +{{- if and (has "linstor-gui" $exposeServices) (eq $oidcEnabled "true") }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: linstor-gui-ingress + labels: + {{- include "linstor-gui.labels" . | nindent 4 }} + annotations: + cert-manager.io/cluster-issuer: {{ $clusterIssuer }} + {{- if eq $solver "http01" }} + acme.cert-manager.io/http01-ingress-ingressclassname: {{ $exposeIngress }} + {{- end }} + nginx.ingress.kubernetes.io/proxy-body-size: 100m + # Keycloak access+refresh+id tokens make the oauth2-proxy session + # cookie ~8–10 KB (split across multiple Set-Cookie headers), which + # overflows the default proxy_buffer_size and causes "upstream sent + # too big header" -> HTTP 502 on /oauth2/callback. Same numbers as + # dashboard ingress. + nginx.ingress.kubernetes.io/proxy-buffer-size: 100m + nginx.ingress.kubernetes.io/proxy-buffers-number: "4" + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" +spec: + ingressClassName: {{ $exposeIngress }} + rules: + - host: linstor-gui.{{ $host }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: linstor-gui-gatekeeper + port: + number: 8000 + tls: + - hosts: + - linstor-gui.{{ $host }} + secretName: linstor-gui-ingress-tls +{{- end }} diff --git a/packages/system/linstor-gui/templates/keycloakclient.yaml b/packages/system/linstor-gui/templates/keycloakclient.yaml new file mode 100644 index 00000000..e5dab87b --- /dev/null +++ b/packages/system/linstor-gui/templates/keycloakclient.yaml @@ -0,0 +1,72 @@ +{{- $host := index .Values._cluster "root-host" }} + +{{- /* +Persist client + cookie secrets across upgrades: if the Secrets already +exist, reuse their values; otherwise generate new random ones. The +KeycloakClient CRD references the same client secret so Keycloak stays +in sync with what oauth2-proxy reads. +*/ -}} +{{- $existingClientSecret := lookup "v1" "Secret" .Release.Namespace "linstor-gui-client" }} +{{- $clientSecret := "" }} +{{- if $existingClientSecret }} + {{- $clientSecret = index $existingClientSecret.data "client-secret-key" | b64dec }} +{{- else }} + {{- $clientSecret = randAlphaNum 32 }} +{{- end }} + +{{- $existingAuthConfig := lookup "v1" "Secret" .Release.Namespace "linstor-gui-auth-config" }} +{{- $cookieSecret := "" }} +{{- if $existingAuthConfig }} + {{- $cookieSecret = index $existingAuthConfig.data "cookieSecret" | b64dec }} +{{- else }} + {{- $cookieSecret = randAlphaNum 16 }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: linstor-gui-client + labels: + {{- include "linstor-gui.labels" . | nindent 4 }} +type: Opaque +data: + client-secret-key: {{ $clientSecret | b64enc }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: linstor-gui-auth-config + labels: + {{- include "linstor-gui.labels" . | nindent 4 }} +type: Opaque +data: + cookieSecret: {{ $cookieSecret | b64enc }} +{{- if .Capabilities.APIVersions.Has "v1.edp.epam.com/v1" }} +--- +apiVersion: v1.edp.epam.com/v1 +kind: KeycloakClient +metadata: + name: linstor-gui-client + annotations: + # Re-reconcile the Keycloak client if the random secret regenerates. + secret-hash: {{ $clientSecret | sha256sum }} +spec: + realmRef: + name: keycloakrealm-cozy + kind: ClusterKeycloakRealm + secret: $linstor-gui-client:client-secret-key + advancedProtocolMappers: true + name: linstor-gui + clientId: linstor-gui + directAccess: true + public: false + webUrl: "https://linstor-gui.{{ $host }}" + defaultClientScopes: + - groups + optionalClientScopes: + - offline_access + attributes: + post.logout.redirect.uris: "+" + redirectUris: + - "https://linstor-gui.{{ $host }}/oauth2/callback/*" +{{- end }} diff --git a/packages/system/linstor-gui/templates/service.yaml b/packages/system/linstor-gui/templates/service.yaml new file mode 100644 index 00000000..66ae2b2d --- /dev/null +++ b/packages/system/linstor-gui/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: linstor-gui + labels: + {{- include "linstor-gui.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - name: http + port: 80 + targetPort: http + protocol: TCP + selector: + {{- include "linstor-gui.selectorLabels" . | nindent 4 }} diff --git a/packages/system/linstor-gui/templates/serviceaccount.yaml b/packages/system/linstor-gui/templates/serviceaccount.yaml new file mode 100644 index 00000000..8e472671 --- /dev/null +++ b/packages/system/linstor-gui/templates/serviceaccount.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: linstor-gui + labels: + {{- include "linstor-gui.labels" . | nindent 4 }} +automountServiceAccountToken: false diff --git a/packages/system/linstor-gui/tests/deployment_test.yaml b/packages/system/linstor-gui/tests/deployment_test.yaml new file mode 100644 index 00000000..50711eb3 --- /dev/null +++ b/packages/system/linstor-gui/tests/deployment_test.yaml @@ -0,0 +1,95 @@ +suite: linstor-gui deployment +templates: + - templates/deployment.yaml + - templates/service.yaml + - templates/configmap-nginx.yaml + +tests: + - it: renders a ClusterIP service on port 80 -> http + template: templates/service.yaml + release: + name: linstor-gui + namespace: cozy-linstor + asserts: + - isKind: + of: Service + - equal: + path: spec.type + value: ClusterIP + - equal: + path: spec.ports[0].port + value: 80 + - equal: + path: spec.ports[0].targetPort + value: http + + - it: mounts the LINSTOR client TLS secret into the pod + template: templates/deployment.yaml + release: + name: linstor-gui + namespace: cozy-linstor + asserts: + - isKind: + of: Deployment + - contains: + path: spec.template.spec.volumes + content: + name: linstor-client-tls + secret: + secretName: linstor-client-tls + defaultMode: 0444 + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: linstor-client-tls + mountPath: /etc/linstor/client + readOnly: true + + - it: runs as a non-root user with a read-only root filesystem + template: templates/deployment.yaml + release: + name: linstor-gui + namespace: cozy-linstor + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext.runAsNonRoot + value: true + - equal: + path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem + value: true + - equal: + path: spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation + value: false + + - it: proxies /v1 to the configured LINSTOR controller with mTLS + template: templates/configmap-nginx.yaml + release: + name: linstor-gui + namespace: cozy-linstor + asserts: + - isKind: + of: ConfigMap + - matchRegex: + path: data["nginx.conf"] + pattern: "location /v1" + - matchRegex: + path: data["nginx.conf"] + pattern: "proxy_pass https://linstor-controller.cozy-linstor.svc:3371" + - matchRegex: + path: data["nginx.conf"] + pattern: "proxy_ssl_certificate\\s+/etc/linstor/client/tls.crt" + + - it: overrides linstor endpoint and client secret + template: templates/configmap-nginx.yaml + release: + name: linstor-gui + namespace: cozy-linstor + set: + linstor.endpoint: https://my-controller.example.svc:3371 + asserts: + - matchRegex: + path: data["nginx.conf"] + pattern: "proxy_pass https://my-controller.example.svc:3371" + - matchRegex: + path: data["nginx.conf"] + pattern: "proxy_ssl_name my-controller.example.svc" diff --git a/packages/system/linstor-gui/tests/ingress_auth_test.yaml b/packages/system/linstor-gui/tests/ingress_auth_test.yaml new file mode 100644 index 00000000..2f0b1d73 --- /dev/null +++ b/packages/system/linstor-gui/tests/ingress_auth_test.yaml @@ -0,0 +1,177 @@ +suite: linstor-gui ingress + keycloak auth +templates: + - templates/ingress.yaml + - templates/gatekeeper.yaml + - templates/gatekeeper-svc.yaml + - templates/gatekeeper-sa.yaml + - templates/keycloakclient.yaml + +release: + name: linstor-gui + namespace: cozy-linstor + +tests: + - it: does not render an Ingress when OIDC is disabled cluster-wide + template: templates/ingress.yaml + set: + _cluster: + root-host: example.org + oidc-enabled: "false" + expose-services: "linstor-gui" + expose-ingress: "tenant-root" + issuer-name: "letsencrypt-prod" + solver: "http01" + asserts: + - hasDocuments: + count: 0 + + - it: does not render an Ingress when linstor-gui is not in expose-services + template: templates/ingress.yaml + set: + _cluster: + root-host: example.org + oidc-enabled: "true" + expose-services: "dashboard,api" + expose-ingress: "tenant-root" + issuer-name: "letsencrypt-prod" + solver: "http01" + asserts: + - hasDocuments: + count: 0 + + - it: renders an Ingress to the gatekeeper service when exposed and OIDC enabled + template: templates/ingress.yaml + set: + _cluster: + root-host: dev10.example.org + oidc-enabled: "true" + expose-services: "dashboard,linstor-gui" + expose-ingress: "tenant-root" + issuer-name: "letsencrypt-prod" + solver: "http01" + asserts: + - isKind: + of: Ingress + - equal: + path: spec.ingressClassName + value: tenant-root + - equal: + path: spec.rules[0].host + value: linstor-gui.dev10.example.org + - equal: + path: spec.rules[0].http.paths[0].backend.service.name + value: linstor-gui-gatekeeper + - equal: + path: spec.rules[0].http.paths[0].backend.service.port.number + value: 8000 + - equal: + path: metadata.annotations["cert-manager.io/cluster-issuer"] + value: letsencrypt-prod + + - it: does not render the gatekeeper Deployment when OIDC is disabled + template: templates/gatekeeper.yaml + set: + _cluster: + root-host: example.org + oidc-enabled: "false" + expose-services: "linstor-gui" + asserts: + - hasDocuments: + count: 0 + + - it: renders an oauth2-proxy Deployment pointing at the cluster Keycloak realm + template: templates/gatekeeper.yaml + set: + _cluster: + root-host: dev10.example.org + oidc-enabled: "true" + oidc-insecure-skip-verify: "false" + keycloak-internal-url: "" + expose-services: "linstor-gui" + asserts: + - isKind: + of: Deployment + - equal: + path: metadata.name + value: linstor-gui-gatekeeper + - matchRegex: + path: spec.template.spec.containers[0].image + pattern: "^quay\\.io/oauth2-proxy/oauth2-proxy:" + - contains: + path: spec.template.spec.containers[0].args + content: --provider=oidc + - contains: + path: spec.template.spec.containers[0].args + content: --upstream=http://linstor-gui.cozy-linstor.svc:80 + - contains: + path: spec.template.spec.containers[0].args + content: --redirect-url=https://linstor-gui.dev10.example.org/oauth2/callback + - contains: + path: spec.template.spec.containers[0].args + content: --oidc-issuer-url=https://keycloak.dev10.example.org/realms/cozy + - contains: + path: spec.template.spec.containers[0].args + content: --scope=openid email profile groups offline_access + - contains: + path: spec.template.spec.containers[0].args + content: --allowed-group=cozystack-cluster-admin + - contains: + path: spec.template.spec.containers[0].env + content: + name: OAUTH2_PROXY_CLIENT_ID + value: linstor-gui + - equal: + path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem + value: true + + - it: creates client + cookie Secrets and a KeycloakClient CRD + template: templates/keycloakclient.yaml + capabilities: + apiVersions: + - v1.edp.epam.com/v1 + set: + _cluster: + root-host: dev10.example.org + asserts: + - hasDocuments: + count: 3 + - documentIndex: 0 + isKind: + of: Secret + - documentIndex: 0 + equal: + path: metadata.name + value: linstor-gui-client + - documentIndex: 1 + isKind: + of: Secret + - documentIndex: 1 + equal: + path: metadata.name + value: linstor-gui-auth-config + - documentIndex: 2 + isKind: + of: KeycloakClient + - documentIndex: 2 + equal: + path: spec.clientId + value: linstor-gui + - documentIndex: 2 + contains: + path: spec.redirectUris + content: "https://linstor-gui.dev10.example.org/oauth2/callback/*" + + - it: skips the KeycloakClient CRD when the API is absent, still creates Secrets + template: templates/keycloakclient.yaml + set: + _cluster: + root-host: example.org + asserts: + - hasDocuments: + count: 2 + - documentIndex: 0 + isKind: + of: Secret + - documentIndex: 1 + isKind: + of: Secret diff --git a/packages/system/linstor-gui/values.yaml b/packages/system/linstor-gui/values.yaml new file mode 100644 index 00000000..e3c49aea --- /dev/null +++ b/packages/system/linstor-gui/values.yaml @@ -0,0 +1,17 @@ +## @section Image +## @param image.repository LINSTOR GUI container image repository +## @param image.tag LINSTOR GUI container image tag (digest recommended) +image: + repository: ghcr.io/cozystack/cozystack/linstor-gui + tag: 2.3.0 + +## @section Deployment +## @param replicas Number of linstor-gui replicas +replicas: 1 + +## @section LINSTOR controller connection +## @param linstor.endpoint In-cluster URL of the LINSTOR controller REST API (HTTPS, mTLS) +## @param linstor.clientSecret Kubernetes Secret with `tls.crt`, `tls.key`, `ca.crt` used as the mTLS client certificate against the LINSTOR controller. Created by the `linstor` package. +linstor: + endpoint: "https://linstor-controller.cozy-linstor.svc:3371" + clientSecret: "linstor-client-tls" diff --git a/packages/system/linstor-scheduler/.helmignore b/packages/system/linstor-scheduler/.helmignore new file mode 100644 index 00000000..1e107f52 --- /dev/null +++ b/packages/system/linstor-scheduler/.helmignore @@ -0,0 +1 @@ +examples diff --git a/packages/system/linstor-scheduler/Chart.yaml b/packages/system/linstor-scheduler/Chart.yaml new file mode 100644 index 00000000..682d263b --- /dev/null +++ b/packages/system/linstor-scheduler/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-linstor-scheduler +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/linstor-scheduler/Makefile b/packages/system/linstor-scheduler/Makefile new file mode 100644 index 00000000..d83a2929 --- /dev/null +++ b/packages/system/linstor-scheduler/Makefile @@ -0,0 +1,15 @@ +export NAME=linstor-scheduler +export NAMESPACE=cozy-linstor + +include ../../../hack/package.mk + +test: + helm unittest . + +update: + rm -rf charts + helm repo add piraeus-charts https://piraeus.io/helm-charts/ + helm repo update piraeus-charts + helm pull piraeus-charts/linstor-scheduler --untar --untardir charts + patch --no-backup-if-mismatch -p4 < patches/disable-ca-key-rotation.patch + patch --no-backup-if-mismatch -p4 < patches/add-scheduler-component-label.patch diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/Chart.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/Chart.yaml new file mode 100644 index 00000000..4a521d1f --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/Chart.yaml @@ -0,0 +1,19 @@ +apiVersion: v2 +appVersion: v0.3.2 +deprecated: true +description: 'Deploys a new kubernetes scheduler, configured to take advantage of + storage system information. If a Pod is using a LINSTOR volume, the scheduler will + prefer nodes with local data instead of accessing the data via a DRBD diskless. ' +home: https://github.com/piraeusdatastore/helm-charts +icon: https://raw.githubusercontent.com/piraeusdatastore/piraeus/master/artwork/sandbox-artwork/icon/color.svg +keywords: +- storage +- scheduler +maintainers: +- name: The Piraeus Maintainers + url: https://github.com/piraeusdatastore/ +name: linstor-scheduler +sources: +- https://github.com/piraeusdatastore/linstor-scheduler-extender +type: application +version: 0.2.3 diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/LICENSE b/packages/system/linstor-scheduler/charts/linstor-scheduler/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/README.md b/packages/system/linstor-scheduler/charts/linstor-scheduler/README.md new file mode 100644 index 00000000..ddf92826 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/README.md @@ -0,0 +1,72 @@ +# linstor-scheduler + +Deploys a new Kubernetes scheduler, extended by +the [linstor-scheduler-extender](https://github.com/piraeusdatastore/linstor-scheduler-extender). + +> [!IMPORTANT] +> The LINSTOR Scheduler is no longer maintained. Prefer using `volumeBindingMode: WaitForFirstConsumer` on your +> StorageClasses. + +The schedule is volume placement aware. That means that it prefers placing Pods on the same nodes as any Persistent +Volume they might use. This works for any setup using LINSTOR, i.e. Piraeus Datastore or LINBIT SDS. + +## Installation + +The scheduler is meant to be installed in the same namespace as LINSTOR itself, otherwise additional steps may be +required. + +If installed along side Piraeus Operator, the LINSTOR endpoint is determined automatically. Otherwise, you need +to set `linstor.endpoint` and `linstor.clientSecret` values as appropriate. + +The following command will install the scheduler for a typical Piraeus Data-Store configuration with TLS enabled: + +``` +helm repo add piraeus-charts https://piraeus.io/helm-charts/ +helm install linstor-scheduler piraeus-charts/linstor-scheduler --set linstorEndpoint=https://piraeus-op-cs.piraeus.svc:3371 --set linstorClientSecret=piraeus-client-secret +``` + +## Usage + +To use the scheduler, you need to configure it on your Pods (or Pod templates): + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: some-pod +spec: + schedulerName: linstor-scheduler + ... +``` + +## Configuration + +The following options are available: + +| Option | Usage | Default | +|-----------------------------------------------|--------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------| +| `replicaCount` | Number of replicas to deploy. | `1` | +| `linstor.endpoint` | URL of the LINSTOR Controller API. | `""` | +| `linstor.clientSecret` | TLS secret to use to authenticate with the LINSTOR API | `""` | +| `extender.image.repository` | Repository to pull the linstor-scheduler-extender image from. | `quay.io/piraeusdatastore/linstor-scheduler-extender` | +| `extender.image.pullPolicy` | Pull policy to use. Possible values: `IfNotPresent`, `Always`, `Never` | `IfNotPresent` | +| `extender.image.tag` | Override the tag to pull. If not given, defaults to charts `AppVersion`. | `""` | +| `extender.resources` | Resources to request and limit on the container. | `{}` | +| `extender.securityContext` | Configure container security context. Defaults to dropping all capabilties and running as user 1000. | `{capabilities: {drop: [ALL]}, readOnlyRootFilesystem: true, runAsNonRoot: true, runAsUser: 1000}` | +| `scheduler.image.repository` | Repository to pull the kubernetes scheduler image from. | `registry.k8s.io/kube-scheduler` | +| `scheduler.image.pullPolicy` | Pull policy to use. Possible values: `IfNotPresent`, `Always`, `Never` | `IfNotPresent` | +| `scheduler.image.tag` | Override the tag to pull. If not given, defaults to kubernetes version. | `""` | +| `scheduler.image.compatibleKubernetesRelease` | Compatible kubernetes version for this scheduler, used to generate configuration in the right version. | `""` | +| `scheduler.resources` | Resources to request and limit on the container. | `{}` | +| `scheduler.securityContext` | Configure container security context. Defaults to dropping all capabilties and running as user 1000. | `{capabilities: {drop: [ALL]}, readOnlyRootFilesystem: true, runAsNonRoot: true, runAsUser: 1000}` | +| `imagePullSecrets` | Image pull secrets to add to the deployment. | `[]` | +| `podAnnotations` | Annotations to add to every pod in the deployment. | `{}` | +| `podSecurityContext` | Security context to set on the webhook pod. | `{}` | +| `nodeSelector` | Node selector to add to each webhook pod. | `{}` | +| `tolerations` | Tolerations to add to each webhook pod. | `[]` | +| `affinity` | Affinity to set on each webhook pod. | `{}` | +| `rbac.create` | Create the necessary roles and bindings for the snapshot controller. | `true` | +| `serviceAccount.create` | Create the service account resource | `true` | +| `serviceAccount.name` | Sets the name of the service account. If left empty, will use the release name as default | `""` | +| `podDisruptionBudget.enabled` | Enable creation of a pod disruption budget to protect the availability of the scheduler | `true` | +| `autoscaling.enabled` | Enable creation of a horizontal pod autoscaler to ensure availability in case of high usage` | `"false` | diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/NOTES.txt b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/NOTES.txt new file mode 100644 index 00000000..5e426f28 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/NOTES.txt @@ -0,0 +1,12 @@ +Scheduler {{ include "linstor-scheduler.fullname" . }} deployed! + +Used LINSTOR URL: {{ include "linstor-scheduler.linstorEndpoint" .}} + +Please run `helm test {{ .Release.Name }}` to ensure it's properly working. + +Specify the scheduler on your pods to start smart scheduling based on your Persistent Volumes: + +--- +spec: + schedulerName: {{ include "linstor-scheduler.fullname" . }} +--- diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/_helpers.tpl b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/_helpers.tpl new file mode 100644 index 00000000..04c793f9 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/_helpers.tpl @@ -0,0 +1,143 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "linstor-scheduler.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "linstor-scheduler.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "linstor-scheduler.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "linstor-scheduler.labels" -}} +helm.sh/chart: {{ include "linstor-scheduler.chart" . }} +{{ include "linstor-scheduler.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "linstor-scheduler.selectorLabels" -}} +app.kubernetes.io/name: {{ include "linstor-scheduler.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "linstor-scheduler.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "linstor-scheduler.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Get the kubernetes version we should assume for creating scheduler configs. +Strips distribution suffixes like +k3s1, +rke2r1 from version string. +*/}} +{{- define "linstor-scheduler.kubeVersion" }} +{{- $version := .Values.scheduler.image.compatibleKubernetesRelease | default .Capabilities.KubeVersion.Version }} +{{- regexReplaceAll "\\+.*$" $version "" }} +{{- end }} + +{{/* +Find the linstor client secret containing TLS certificates +*/}} +{{- define "linstor-scheduler.linstorClientSecretName" -}} +{{- if .Values.linstor.clientSecret }} +{{- .Values.linstor.clientSecret }} +{{- else if .Capabilities.APIVersions.Has "piraeus.linbit.com/v1/LinstorController" }} +{{- $crs := (lookup "piraeus.linbit.com/v1" "LinstorController" .Release.Namespace "").items }} +{{- if $crs }} +{{- if eq (len $crs) 1 }} +{{- $item := index $crs 0 }} +{{- $item.spec.linstorHttpsClientSecret }} +{{- end }} +{{- end }} +{{- else if .Capabilities.APIVersions.Has "linstor.linbit.com/v1/LinstorController" }} +{{- $crs := (lookup "linstor.linbit.com/v1" "LinstorController" .Release.Namespace "").items }} +{{- if $crs }} +{{- if eq (len $crs) 1 }} +{{- $item := index $crs 0 }} +{{- $item.spec.linstorHttpsClientSecret }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Find the linstor URL by operator resources +*/}} +{{- define "linstor-scheduler.linstorEndpointFromCRD" -}} +{{- if .Capabilities.APIVersions.Has "piraeus.linbit.com/v1/LinstorController" }} +{{- $crs := (lookup "piraeus.linbit.com/v1" "LinstorController" .Release.Namespace "").items }} +{{- if $crs }} +{{- if eq (len $crs) 1 }} +{{- $item := index $crs 0 }} +{{- if include "linstor-scheduler.linstorClientSecretName" . }} +{{- printf "https://%s.%s.svc:3371" $item.metadata.name $item.metadata.namespace }} +{{- else }} +{{- printf "http://%s.%s.svc:3370" $item.metadata.name $item.metadata.namespace }} +{{- end }} +{{- end }} +{{- end }} +{{- else if .Capabilities.APIVersions.Has "linstor.linbit.com/v1/LinstorController" }} +{{- $crs := (lookup "linstor.linbit.com/v1" "LinstorController" .Release.Namespace "").items }} +{{- if $crs }} +{{- if eq (len $crs) 1 }} +{{- $item := index $crs 0 }} +{{- if include "linstor-scheduler.linstorClientSecretName" . }} +{{- printf "https://%s.%s.svc:3371" $item.metadata.name $item.metadata.namespace }} +{{- else }} +{{- printf "http://%s.%s.svc:3370" $item.metadata.name $item.metadata.namespace }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Find the linstor URL either by override or cluster resources +*/}} +{{- define "linstor-scheduler.linstorEndpoint" -}} +{{- if .Values.linstor.endpoint }} +{{- .Values.linstor.endpoint }} +{{- else }} +{{- $piraeus := include "linstor-scheduler.linstorEndpointFromCRD" . }} +{{- if $piraeus }} +{{- $piraeus }} +{{- else }} +{{- fail "Please specify linstor.endpoint, no default URL could be determined" }} +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/admission-deployment.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/admission-deployment.yaml new file mode 100644 index 00000000..22f5326a --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/admission-deployment.yaml @@ -0,0 +1,98 @@ +{{- if .Values.admission.enabled }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} + app.kubernetes.io/component: admission +spec: + replicas: {{ .Values.admission.replicaCount }} + selector: + matchLabels: + {{- include "linstor-scheduler.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: admission + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "linstor-scheduler.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: admission + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "linstor-scheduler.serviceAccountName" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + containers: + - name: linstor-scheduler-admission + image: {{ .Values.extender.image.repository }}:{{ .Values.extender.image.tag | default .Chart.AppVersion }} + imagePullPolicy: {{ .Values.extender.image.pullPolicy }} + command: ["/linstor-scheduler-admission"] + args: + - -scheduler={{ include "linstor-scheduler.fullname" . }} + - -tls-cert-file=/etc/webhook/certs/tls.crt + - -tls-key-file=/etc/webhook/certs/tls.key + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + ports: + - containerPort: 8080 + name: https + protocol: TCP + env: + - name: LS_CONTROLLERS + value: {{ include "linstor-scheduler.linstorEndpoint" . }} + {{- if include "linstor-scheduler.linstorClientSecretName" . }} + - name: LS_USER_CERTIFICATE + valueFrom: + secretKeyRef: + name: {{ include "linstor-scheduler.linstorClientSecretName" . }} + key: tls.crt + - name: LS_USER_KEY + valueFrom: + secretKeyRef: + name: {{ include "linstor-scheduler.linstorClientSecretName" . }} + key: tls.key + - name: LS_ROOT_CA + valueFrom: + secretKeyRef: + name: {{ include "linstor-scheduler.linstorClientSecretName" . }} + key: ca.crt + {{- end }} + volumeMounts: + - name: webhook-certs + mountPath: /etc/webhook/certs + readOnly: true + resources: + {{- toYaml .Values.admission.resources | nindent 12 }} + volumes: + - name: webhook-certs + secret: + secretName: {{ include "linstor-scheduler.fullname" . }}-admission-tls + defaultMode: 0400 + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/admission-service.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/admission-service.yaml new file mode 100644 index 00000000..d2abd078 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/admission-service.yaml @@ -0,0 +1,20 @@ +{{- if .Values.admission.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} + app.kubernetes.io/component: admission +spec: + type: ClusterIP + ports: + - port: 443 + targetPort: 8080 + protocol: TCP + name: https + selector: + {{- include "linstor-scheduler.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: admission +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/certmanager.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/certmanager.yaml new file mode 100644 index 00000000..760a9d5d --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/certmanager.yaml @@ -0,0 +1,58 @@ +{{- if .Values.admission.enabled }} +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission-selfsigned + namespace: {{ .Release.Namespace }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission-root-ca + namespace: {{ .Release.Namespace }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +spec: + secretName: {{ include "linstor-scheduler.fullname" . }}-admission-root-ca + duration: 43800h # 5 years + commonName: {{ include "linstor-scheduler.fullname" . }}-admission-root-ca + issuerRef: + name: {{ include "linstor-scheduler.fullname" . }}-admission-selfsigned + isCA: true + privateKey: + rotationPolicy: Never +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission-ca-issuer + namespace: {{ .Release.Namespace }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +spec: + ca: + secretName: {{ include "linstor-scheduler.fullname" . }}-admission-root-ca +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission-cert + namespace: {{ .Release.Namespace }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +spec: + secretName: {{ include "linstor-scheduler.fullname" . }}-admission-tls + duration: 8760h # 1 year + renewBefore: 24h + issuerRef: + name: {{ include "linstor-scheduler.fullname" . }}-admission-ca-issuer + commonName: {{ include "linstor-scheduler.fullname" . }}-admission + dnsNames: + - {{ include "linstor-scheduler.fullname" . }}-admission + - {{ include "linstor-scheduler.fullname" . }}-admission.{{ .Release.Namespace }}.svc +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/config.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/config.yaml new file mode 100644 index 00000000..bff77d0f --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/config.yaml @@ -0,0 +1,46 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "linstor-scheduler.fullname" . }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +data: +{{- if semverCompare ">= 1.22-0" (include "linstor-scheduler.kubeVersion" .) }} + scheduler-config.yaml: |- +{{- if semverCompare ">= 1.25-0" (include "linstor-scheduler.kubeVersion" .) }} + apiVersion: kubescheduler.config.k8s.io/v1 +{{- else if semverCompare ">= 1.23-0" (include "linstor-scheduler.kubeVersion" .) }} + apiVersion: kubescheduler.config.k8s.io/v1beta3 +{{- else }} + apiVersion: kubescheduler.config.k8s.io/v1beta2 +{{- end }} + kind: KubeSchedulerConfiguration + profiles: + - schedulerName: {{ include "linstor-scheduler.fullname" . }} + extenders: + - urlPrefix: http://localhost:8099 + filterVerb: filter + prioritizeVerb: prioritize + weight: 5 + enableHTTPS: false + httpTimeout: 10s + nodeCacheCapable: false +{{- else }} + policy.cfg: |- + { + "kind": "Policy", + "apiVersion": "v1", + "extenders": [ + { + "urlPrefix": "http://localhost:8099", + "apiVersion": "v1beta1", + "filterVerb": "filter", + "prioritizeVerb": "prioritize", + "weight": 5, + "enableHttps": false, + "nodeCacheCapable": false + } + ] + } +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/deployment.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/deployment.yaml new file mode 100644 index 00000000..289021fd --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/deployment.yaml @@ -0,0 +1,127 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "linstor-scheduler.fullname" . }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "linstor-scheduler.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "linstor-scheduler.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: scheduler + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "linstor-scheduler.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: kube-scheduler + image: "{{ .Values.scheduler.image.repository }}:{{ .Values.scheduler.image.tag | default (include "linstor-scheduler.kubeVersion" .) }}" + securityContext: + {{- toYaml .Values.scheduler.securityContext | nindent 12 }} + command: + - kube-scheduler + {{- if semverCompare ">= 1.22-0" (include "linstor-scheduler.kubeVersion" .) }} + - --config=/etc/kubernetes/scheduler-config.yaml + {{- else }} + - --scheduler-name={{ include "linstor-scheduler.fullname" . }} + - --policy-configmap={{ include "linstor-scheduler.fullname" . }} + - --policy-configmap-namespace=$(NAMESPACE) + {{- end }} + - --leader-elect=true + - --leader-elect-resource-lock=leases + - --leader-elect-resource-name={{ include "linstor-scheduler.fullname" . }} + - --leader-elect-resource-namespace=$(NAMESPACE) + {{- if .Values.scheduler.args }} + {{- toYaml .Values.scheduler.args | nindent 12 }} + {{- end }} + env: + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + imagePullPolicy: {{ .Values.scheduler.image.pullPolicy }} + startupProbe: + httpGet: + path: /healthz + port: 10259 + scheme: HTTPS + livenessProbe: + httpGet: + path: /healthz + port: 10259 + scheme: HTTPS + readinessProbe: + httpGet: + path: /healthz + port: 10259 + scheme: HTTPS + {{- if semverCompare ">= 1.22-0" (include "linstor-scheduler.kubeVersion" .) }} + volumeMounts: + - mountPath: /etc/kubernetes + name: scheduler-config + {{- end }} + resources: + {{- toYaml .Values.scheduler.resources | nindent 12 }} + - name: linstor-scheduler-extender + image: {{ .Values.extender.image.repository }}:{{ .Values.extender.image.tag | default .Chart.AppVersion }} + resources: + {{- toYaml .Values.extender.resources | nindent 12 }} + securityContext: + {{- toYaml .Values.extender.securityContext | nindent 12 }} + imagePullPolicy: {{ .Values.extender.image.pullPolicy }} + args: + - --verbose=true + env: + - name: LS_CONTROLLERS + value: {{ include "linstor-scheduler.linstorEndpoint" . }} + {{- if include "linstor-scheduler.linstorClientSecretName" . }} + - name: LS_USER_CERTIFICATE + valueFrom: + secretKeyRef: + name: {{ include "linstor-scheduler.linstorClientSecretName" . }} + key: tls.crt + - name: LS_USER_KEY + valueFrom: + secretKeyRef: + name: {{ include "linstor-scheduler.linstorClientSecretName" . }} + key: tls.key + - name: LS_ROOT_CA + valueFrom: + secretKeyRef: + name: {{ include "linstor-scheduler.linstorClientSecretName" . }} + key: ca.crt + {{- end }} + {{- if semverCompare ">= 1.22-0" .Capabilities.KubeVersion.Version }} + volumes: + - configMap: + name: {{ include "linstor-scheduler.fullname" . }} + name: scheduler-config + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/hpa.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/hpa.yaml new file mode 100644 index 00000000..d370dc75 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "linstor-scheduler.fullname" . }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "linstor-scheduler.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/mutatingwebhookconfiguration.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/mutatingwebhookconfiguration.yaml new file mode 100644 index 00000000..fe387dda --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/mutatingwebhookconfiguration.yaml @@ -0,0 +1,32 @@ +{{- if .Values.admission.enabled }} +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "linstor-scheduler.fullname" . }}-admission-cert + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +webhooks: + - name: linstor-scheduler-admission.linbit.com + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + failurePolicy: {{ .Values.admission.failurePolicy }} + clientConfig: + service: + name: {{ include "linstor-scheduler.fullname" . }}-admission + namespace: {{ .Release.Namespace }} + path: /mutate + port: 443 + rules: + - operations: ["CREATE"] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + scope: "*" + {{- with .Values.admission.namespaceSelector }} + namespaceSelector: + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/poddisruptionbudget.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/poddisruptionbudget.yaml new file mode 100644 index 00000000..3365f8e6 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/poddisruptionbudget.yaml @@ -0,0 +1,18 @@ +{{- if .Values.podDisruptionBudget.enabled -}} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "linstor-scheduler.fullname" . }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "linstor-scheduler.selectorLabels" . | nindent 6 }} + {{- if .Values.podDisruptionBudget.minAvailable }} + minAvailable: {{ .Values.podDisruptionBudget.minAvailable }} + {{- end }} + {{- if .Values.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} + {{- end }} +{{- end -}} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/rbac.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/rbac.yaml new file mode 100644 index 00000000..38bf387b --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/rbac.yaml @@ -0,0 +1,108 @@ +{{- if .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "linstor-scheduler.fullname" . }} + namespace: {{ .Release.Namespace }} +rules: + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - get + - update +{{- if semverCompare "< 1.22-0" (include "linstor-scheduler.kubeVersion" .) }} + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch +{{- end }} +{{- if .Values.admission.enabled }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission +rules: + - apiGroups: [""] + resources: ["pods", "persistentvolumeclaims", "persistentvolumes"] + verbs: ["get"] + - apiGroups: ["storage.k8s.io"] + resources: ["storageclasses"] + verbs: ["get"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "linstor-scheduler.fullname" . }}-admission +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "linstor-scheduler.fullname" . }}-admission +subjects: + - kind: ServiceAccount + name: {{ include "linstor-scheduler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "linstor-scheduler.fullname" . | trunc 57 }}-as-ks +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:kube-scheduler +subjects: + - kind: ServiceAccount + name: {{ include "linstor-scheduler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "linstor-scheduler.fullname" . | trunc 57 }}-as-vs +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:volume-scheduler +subjects: + - kind: ServiceAccount + name: {{ include "linstor-scheduler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "linstor-scheduler.fullname" . }} + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "linstor-scheduler.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ include "linstor-scheduler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "linstor-scheduler.fullname" . | trunc 58 }}-auth + namespace: kube-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: extension-apiserver-authentication-reader +subjects: + - kind: ServiceAccount + name: {{ include "linstor-scheduler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/serviceaccount.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/serviceaccount.yaml new file mode 100644 index 00000000..2df9a5d5 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "linstor-scheduler.serviceAccountName" . }} + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/tests/test-scheduler.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/tests/test-scheduler.yaml new file mode 100644 index 00000000..be95a868 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/tests/test-scheduler.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "linstor-scheduler.fullname" . | trunc 49 }}-test-schedule" + labels: + {{- include "linstor-scheduler.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + # Smoke test: just test the scheduler without volumes + schedulerName: {{ include "linstor-scheduler.fullname" . }} + containers: + - name: wget + image: busybox + command: [] + restartPolicy: Never diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/values.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/values.yaml new file mode 100644 index 00000000..f0633294 --- /dev/null +++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/values.yaml @@ -0,0 +1,106 @@ +replicaCount: 1 + +linstor: + endpoint: "" + clientSecret: "" + +scheduler: + args: [] + image: + repository: registry.k8s.io/kube-scheduler + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the kubernetes release + tag: "" + # Overrides which config is written. The default is determined by the current Kubernetes version + compatibleKubernetesRelease: "" + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +extender: + image: + repository: quay.io/piraeusdatastore/linstor-scheduler-extender + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the app version + tag: "" + securityContext: + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + create: true + annotations: {} + name: "" + +rbac: + create: true + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 3 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + + +podDisruptionBudget: + enabled: true + minAvailable: 1 + # maxUnavailable: 1 + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +admission: + enabled: false + replicaCount: 2 + failurePolicy: Ignore + namespaceSelector: {} + # matchExpressions: + # - key: kubernetes.io/metadata.name + # operator: NotIn + # values: + # - kube-system + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 10m + # memory: 64Mi diff --git a/packages/system/linstor-scheduler/patches/add-scheduler-component-label.patch b/packages/system/linstor-scheduler/patches/add-scheduler-component-label.patch new file mode 100644 index 00000000..01eed9a8 --- /dev/null +++ b/packages/system/linstor-scheduler/patches/add-scheduler-component-label.patch @@ -0,0 +1,9 @@ +diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/deployment.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/deployment.yaml +--- a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/deployment.yaml ++++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/deployment.yaml +@@ -21,4 +21,5 @@ + labels: + {{- include "linstor-scheduler.selectorLabels" . | nindent 8 }} ++ app.kubernetes.io/component: scheduler + spec: + {{- with .Values.imagePullSecrets }} diff --git a/packages/system/linstor-scheduler/patches/disable-ca-key-rotation.patch b/packages/system/linstor-scheduler/patches/disable-ca-key-rotation.patch new file mode 100644 index 00000000..45715d6b --- /dev/null +++ b/packages/system/linstor-scheduler/patches/disable-ca-key-rotation.patch @@ -0,0 +1,13 @@ +diff --git a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/certmanager.yaml b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/certmanager.yaml +index 3942555b..760a9d5d 100644 +--- a/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/certmanager.yaml ++++ b/packages/system/linstor-scheduler/charts/linstor-scheduler/templates/certmanager.yaml +@@ -24,6 +24,8 @@ spec: + issuerRef: + name: {{ include "linstor-scheduler.fullname" . }}-admission-selfsigned + isCA: true ++ privateKey: ++ rotationPolicy: Never + --- + apiVersion: cert-manager.io/v1 + kind: Issuer diff --git a/packages/system/linstor-scheduler/templates/extender-service.yaml b/packages/system/linstor-scheduler/templates/extender-service.yaml new file mode 100644 index 00000000..e8148b43 --- /dev/null +++ b/packages/system/linstor-scheduler/templates/extender-service.yaml @@ -0,0 +1,26 @@ +{{/* + Exposes the linstor-scheduler-extender sidecar (port 8099) as a + cluster-internal Service so that other schedulers (e.g. cozystack-scheduler) + can use it as a scheduler extender. + + The selector labels match the subchart's deployment pods. They are + hardcoded here because the subchart helpers expect a subchart rendering + context that is unavailable in the wrapper chart. +*/}} +apiVersion: v1 +kind: Service +metadata: + name: linstor-scheduler-extender + labels: + app.kubernetes.io/component: extender +spec: + type: ClusterIP + ports: + - port: 8099 + targetPort: 8099 + protocol: TCP + name: http + selector: + app.kubernetes.io/name: linstor-scheduler + app.kubernetes.io/instance: linstor-scheduler + app.kubernetes.io/component: scheduler diff --git a/packages/system/linstor-scheduler/tests/extender-service_test.yaml b/packages/system/linstor-scheduler/tests/extender-service_test.yaml new file mode 100644 index 00000000..60e272c2 --- /dev/null +++ b/packages/system/linstor-scheduler/tests/extender-service_test.yaml @@ -0,0 +1,35 @@ +suite: extender service targets deployment pods + +templates: + - templates/extender-service.yaml + - charts/linstor-scheduler/templates/deployment.yaml + +release: + name: linstor-scheduler + +tests: + - it: service selector matches deployment pod labels + template: charts/linstor-scheduler/templates/deployment.yaml + asserts: + - equal: + path: spec.template.metadata.labels["app.kubernetes.io/name"] + value: linstor-scheduler + - equal: + path: spec.template.metadata.labels["app.kubernetes.io/instance"] + value: linstor-scheduler + - equal: + path: spec.template.metadata.labels["app.kubernetes.io/component"] + value: scheduler + + - it: service selector uses the same values + template: templates/extender-service.yaml + asserts: + - equal: + path: spec.selector["app.kubernetes.io/name"] + value: linstor-scheduler + - equal: + path: spec.selector["app.kubernetes.io/instance"] + value: linstor-scheduler + - equal: + path: spec.selector["app.kubernetes.io/component"] + value: scheduler diff --git a/packages/system/linstor-scheduler/values.yaml b/packages/system/linstor-scheduler/values.yaml new file mode 100644 index 00000000..652cb61a --- /dev/null +++ b/packages/system/linstor-scheduler/values.yaml @@ -0,0 +1,7 @@ +linstor-scheduler: + fullnameOverride: linstor-scheduler + linstor: + endpoint: "https://linstor-controller.cozy-linstor.svc:3371" + clientSecret: "linstor-client-tls" + admission: + enabled: true diff --git a/packages/system/linstor/Makefile b/packages/system/linstor/Makefile index 5de22194..8d566678 100644 --- a/packages/system/linstor/Makefile +++ b/packages/system/linstor/Makefile @@ -1,4 +1,41 @@ export NAME=linstor export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk + +LINSTOR_VERSION ?= 1.33.2 +LINSTOR_CSI_VERSION ?= v1.10.6 + +image: image-piraeus-server image-linstor-csi + +image-piraeus-server: + docker buildx build images/piraeus-server \ + --build-arg LINSTOR_VERSION=$(LINSTOR_VERSION) \ + --build-arg K8S_AWAIT_ELECTION_VERSION=v0.4.2 \ + --tag $(REGISTRY)/piraeus-server:$(call settag,$(LINSTOR_VERSION)) \ + --tag $(REGISTRY)/piraeus-server:$(call settag,$(LINSTOR_VERSION)-$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/piraeus-server:latest \ + --cache-to type=inline \ + --metadata-file images/piraeus-server.json \ + $(BUILDX_ARGS) + REPOSITORY="$(REGISTRY)/piraeus-server" \ + yq -i '.piraeusServer.image.repository = strenv(REPOSITORY)' values.yaml + TAG="$(call settag,$(LINSTOR_VERSION))@$$(yq e '."containerimage.digest"' images/piraeus-server.json -o json -r)" \ + yq -i '.piraeusServer.image.tag = strenv(TAG)' values.yaml + rm -f images/piraeus-server.json + +image-linstor-csi: + docker buildx build images/linstor-csi \ + --build-arg VERSION=$(LINSTOR_CSI_VERSION) \ + --tag $(REGISTRY)/linstor-csi:$(call settag,$(LINSTOR_CSI_VERSION)) \ + --tag $(REGISTRY)/linstor-csi:$(call settag,$(LINSTOR_CSI_VERSION)-$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/linstor-csi:latest \ + --cache-to type=inline \ + --metadata-file images/linstor-csi.json \ + $(BUILDX_ARGS) + REPOSITORY="$(REGISTRY)/linstor-csi" \ + yq -i '.linstorCSI.image.repository = strenv(REPOSITORY)' values.yaml + TAG="$(call settag,$(LINSTOR_CSI_VERSION))@$$(yq e '."containerimage.digest"' images/linstor-csi.json -o json -r)" \ + yq -i '.linstorCSI.image.tag = strenv(TAG)' values.yaml + rm -f images/linstor-csi.json diff --git a/packages/system/linstor/hack/plunger/plunger-satellite.sh b/packages/system/linstor/hack/plunger/plunger-satellite.sh index 688cfd65..4a488a51 100755 --- a/packages/system/linstor/hack/plunger/plunger-satellite.sh +++ b/packages/system/linstor/hack/plunger/plunger-satellite.sh @@ -10,10 +10,125 @@ trap terminate SIGINT SIGQUIT SIGTERM echo "Starting Linstor per-satellite plunger" +INTERVAL_SEC="${INTERVAL_SEC:-30}" +STALL_ITERS="${STALL_ITERS:-4}" +STATE_FILE="${STATE_FILE:-/run/drbd-sync-watch.state}" + +log() { printf '%s %s\n' "$(date -Is)" "$*" >&2; } + +drbd_status_json() { + drbdsetup status --json 2>/dev/null || true +} + +# Detect DRBD resources where resync is stuck: +# - at least one local device is Inconsistent +# - there is an active SyncTarget peer +# - there are other peers suspended with resync-suspended:dependency +# Output format: " " +drbd_stall_candidates() { + jq -r ' + .[]? + | . as $r + | select(any($r.devices[]?; ."disk-state" == "Inconsistent")) + | ( + [ $r.connections[]? + | . as $c + | $c.peer_devices[]? + | select(."replication-state" == "SyncTarget") + | { peer: $c.name, pct: (."percent-in-sync" // empty) } + ] | .[0]? + ) as $sync + | select($sync != null and ($sync.pct|tostring) != "") + | select(any($r.connections[]?.peer_devices[]?; ."resync-suspended" == "dependency")) + | "\($r.name) \($sync.peer) \($sync.pct)" + ' +} + +drbd_stall_load_state() { + [ -f "$STATE_FILE" ] && cat "$STATE_FILE" || true +} + +drbd_stall_save_state() { + local tmp="${STATE_FILE}.tmp" + cat >"$tmp" + mv "$tmp" "$STATE_FILE" +} + +# Break stalled resync by disconnecting the current SyncTarget peer. +# After reconnect, DRBD will typically pick another eligible peer and continue syncing. +drbd_stall_act() { + local res="$1" + local peer="$2" + local pct="$3" + log "STALL detected: res=$res sync_peer=$peer percent_in_sync=$pct -> disconnect/connect" + drbdadm disconnect "${res}:${peer}" && drbdadm connect "$res" || log "WARN: action failed for ${res}:${peer}" +} + +# Track percent-in-sync progress across iterations. +# If progress does not change for STALL_ITERS loops, trigger reconnect. +drbd_fix_stalled_sync() { + local now prev json out + now="$(date +%s)" + prev="$(drbd_stall_load_state)" + + json="$(drbd_status_json)" + [ -n "$json" ] || return 0 + + out="$(printf '%s' "$json" | drbd_stall_candidates)" + + local new_state="" + local acts="" + + while IFS= read -r line; do + [ -n "$line" ] || continue + set -- $line + local res="$1" peer="$2" pct="$3" + local key="${res} ${peer}" + + local prev_line + prev_line="$(printf '%s\n' "$prev" | awk -v k="$key" '$1" "$2==k {print; exit}')" + + local cnt last_act prev_pct prev_cnt prev_act + if [ -n "$prev_line" ]; then + set -- $prev_line + prev_pct="$3" + prev_cnt="$4" + prev_act="$5" + if [ "$pct" = "$prev_pct" ]; then + cnt=$((prev_cnt + 1)) + else + cnt=1 + fi + last_act="$prev_act" + else + cnt=1 + last_act=0 + fi + + if [ "$cnt" -ge "$STALL_ITERS" ]; then + acts="${acts}${res} ${peer} ${pct}"$'\n' + cnt=0 + last_act="$now" + fi + + new_state="${new_state}${res} ${peer} ${pct} ${cnt} ${last_act}"$'\n' + done <<< "$out" + + if [ -n "$acts" ]; then + while IFS= read -r a; do + [ -n "$a" ] || continue + set -- $a + drbd_stall_act "$1" "$2" "$3" + done <<< "$acts" + fi + + printf '%s' "$new_state" | drbd_stall_save_state +} + while true; do # timeout at the start of the loop to give a chance for the fresh linstor-satellite instance to cleanup itself - sleep 30 & + sleep "$INTERVAL_SEC" & pid=$! wait $pid @@ -21,7 +136,7 @@ while true; do # the `/` path could not be a backing file for a loop device, so it's a good indicator of a stuck loop device # TODO describe the issue in more detail # Using the direct /usr/sbin/losetup as the linstor-satellite image has own wrapper in /usr/local - stale_loopbacks=$(/usr/sbin/losetup --json | jq -r '.[][] | select(."back-file" == "/" or ."back-file" == "/ (deleted)").name' ) + stale_loopbacks=$(/usr/sbin/losetup --json | jq -r '.[][] | select(."back-file" == "/" or ."back-file" == "/ (deleted)").name') for stale_device in $stale_loopbacks; do ( echo "Detaching stuck loop device ${stale_device}" set -x @@ -39,4 +154,7 @@ while true; do drbdadm up "${secondary}" || echo "Command failed" ); done + # Detect and fix stalled DRBD resync by switching SyncTarget peer + drbd_fix_stalled_sync || true + done diff --git a/packages/system/linstor/images/linstor-csi/Dockerfile b/packages/system/linstor/images/linstor-csi/Dockerfile new file mode 100644 index 00000000..df5d179d --- /dev/null +++ b/packages/system/linstor/images/linstor-csi/Dockerfile @@ -0,0 +1,36 @@ +FROM golang:1.25 AS builder + +ARG VERSION=v1.10.6 +ARG LINSTOR_WAIT_UNTIL_VERSION=v0.3.1 +ARG TARGETARCH +ARG TARGETOS + +WORKDIR /src + +RUN curl -sSL https://github.com/piraeusdatastore/linstor-csi/archive/refs/tags/${VERSION}.tar.gz | tar -xzvf- --strip=1 + +COPY patches /patches +RUN git apply /patches/*.diff + +RUN go mod download + +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 \ + go build \ + -a \ + -ldflags "-X github.com/piraeusdatastore/linstor-csi/pkg/driver.Version=$VERSION -extldflags -static" \ + -o /linstor-csi \ + ./cmd/linstor-csi/linstor-csi.go + +RUN curl -fsSL https://github.com/LINBIT/linstor-wait-until/releases/download/$LINSTOR_WAIT_UNTIL_VERSION/linstor-wait-until-$LINSTOR_WAIT_UNTIL_VERSION-$TARGETOS-$TARGETARCH.tar.gz | tar xvzC / + +FROM debian:trixie-slim + +RUN apt-get update && apt-get install -y --no-install-recommends \ + xfsprogs e2fsprogs nfs-common \ + && apt-get clean && rm -rf /var/lib/apt/lists/* \ + && ln -sf /proc/mounts /etc/mtab + +COPY --from=builder /linstor-csi / +COPY --from=builder /linstor-wait-until /linstor-wait-until + +ENTRYPOINT ["/linstor-csi"] diff --git a/packages/system/linstor/images/linstor-csi/patches/001-relocate-after-clone-restore.diff b/packages/system/linstor/images/linstor-csi/patches/001-relocate-after-clone-restore.diff new file mode 100644 index 00000000..0e272670 --- /dev/null +++ b/packages/system/linstor/images/linstor-csi/patches/001-relocate-after-clone-restore.diff @@ -0,0 +1,308 @@ +diff --git a/pkg/client/linstor.go b/pkg/client/linstor.go +index ac4651d..46d565d 100644 +--- a/pkg/client/linstor.go ++++ b/pkg/client/linstor.go +@@ -462,6 +462,14 @@ func (s *Linstor) Clone(ctx context.Context, vol, src *volume.Info, params *volu + return err + } + ++ if params.RelocateAfterClone { ++ logger.Debug("relocate resources to optimal nodes") ++ ++ if err := s.relocateResources(ctx, vol.ID, rGroup.Name); err != nil { ++ logger.WithError(err).Warn("resource relocation failed, volume is still usable") ++ } ++ } ++ + logger.Debug("reconcile extra properties") + + err = s.client.ResourceDefinitions.Modify(ctx, vol.ID, lapi.GenericPropsModify{OverrideProps: vol.Properties}) +@@ -1297,6 +1305,14 @@ func (s *Linstor) VolFromSnap(ctx context.Context, snap *volume.Snapshot, vol *v + return err + } + ++ if snapParams != nil && snapParams.RelocateAfterRestore { ++ logger.Debug("relocate resources to optimal nodes") ++ ++ if err := s.relocateResources(ctx, vol.ID, rGroup.Name); err != nil { ++ logger.WithError(err).Warn("resource relocation failed, volume is still usable") ++ } ++ } ++ + logger.Debug("reconcile extra properties") + + err = s.client.ResourceDefinitions.Modify(ctx, vol.ID, lapi.GenericPropsModify{OverrideProps: vol.Properties}) +@@ -1487,9 +1503,8 @@ func (s *Linstor) reconcileSnapshotResources(ctx context.Context, snapshot *volu + return fmt.Errorf("snapshot '%s' not deployed on any node", snap.Name) + } + +- // Optimize the node we use to restore. It should be one of the preferred nodes, or just the first with a snapshot +- // if no preferred nodes match. +- var selectedNode string ++ // Collect available snapshot nodes, preferring those matching the topology hints. ++ var preferred, available []string + for _, snapNode := range snap.Nodes { + if err := s.NodeAvailable(ctx, snapNode); err != nil { + logger.WithField("selected node candidate", snapNode).WithError(err).Debug("node is not available") +@@ -1497,13 +1512,23 @@ func (s *Linstor) reconcileSnapshotResources(ctx context.Context, snapshot *volu + } + + if slices.Contains(preferredNodes, snapNode) { +- // We found a perfect candidate. +- selectedNode = snapNode +- break +- } else if selectedNode == "" { +- // Set a fallback if we have no candidate yet. +- selectedNode = snapNode ++ preferred = append(preferred, snapNode) + } ++ ++ available = append(available, snapNode) ++ } ++ ++ // Pick a random node from preferred candidates, falling back to any available node. ++ // Randomization distributes restore load across snapshot nodes, preventing all ++ // clones of the same source from concentrating on a single node. ++ candidates := preferred ++ if len(candidates) == 0 { ++ candidates = available ++ } ++ ++ var selectedNode string ++ if len(candidates) > 0 { ++ selectedNode = candidates[rand.Intn(len(candidates))] + } + + if selectedNode == "" { +@@ -1696,6 +1721,114 @@ func (s *Linstor) reconcileResourcePlacement(ctx context.Context, vol *volume.In + return nil + } + ++const propertyRelocationTriggered = "Aux/csi-relocation-triggered" ++ ++// relocateResources migrates replicas from their current nodes to the nodes that ++// LINSTOR's autoplacer considers optimal. This is a best-effort, fire-and-forget ++// operation: migrate-disk API is asynchronous and the volume remains usable on its ++// current nodes even if relocation fails. ++func (s *Linstor) relocateResources(ctx context.Context, volID, rgName string) error { ++ logger := s.log.WithFields(logrus.Fields{ ++ "volume": volID, ++ "resourceGroup": rgName, ++ }) ++ ++ // Check if relocation was already triggered (idempotency guard). ++ rd, err := s.client.ResourceDefinitions.Get(ctx, volID) ++ if err != nil { ++ return fmt.Errorf("failed to get resource definition: %w", err) ++ } ++ ++ if rd.Props[propertyRelocationTriggered] != "" { ++ logger.Debug("relocation already triggered, skipping") ++ return nil ++ } ++ ++ // Get current diskful nodes. ++ resources, err := s.client.Resources.GetAll(ctx, volID) ++ if err != nil { ++ return fmt.Errorf("failed to list resources: %w", err) ++ } ++ ++ currentNodes := util.DeployedDiskfullyNodes(resources) ++ ++ // Query optimal placement from LINSTOR autoplacer. ++ sizeInfo, err := s.client.ResourceGroups.QuerySizeInfo(ctx, rgName, lapi.QuerySizeInfoRequest{}) ++ if err != nil { ++ return fmt.Errorf("failed to query size info: %w", err) ++ } ++ ++ if sizeInfo.SpaceInfo == nil || len(sizeInfo.SpaceInfo.NextSpawnResult) == 0 { ++ logger.Debug("no spawn result from query-size-info, skipping relocation") ++ return nil ++ } ++ ++ // Build a map of optimal node -> storage pool. ++ optimalPools := make(map[string]string, len(sizeInfo.SpaceInfo.NextSpawnResult)) ++ for _, r := range sizeInfo.SpaceInfo.NextSpawnResult { ++ optimalPools[r.NodeName] = r.StorPoolName ++ } ++ ++ // Compute nodes to remove (current but not optimal) and nodes to add (optimal but not current). ++ var nodesToRemove, nodesToAdd []string ++ ++ for _, node := range currentNodes { ++ if _, ok := optimalPools[node]; !ok { ++ nodesToRemove = append(nodesToRemove, node) ++ } ++ } ++ ++ for _, r := range sizeInfo.SpaceInfo.NextSpawnResult { ++ if !slices.Contains(currentNodes, r.NodeName) { ++ nodesToAdd = append(nodesToAdd, r.NodeName) ++ } ++ } ++ ++ // Only migrate min(remove, add) pairs. ++ pairs := min(len(nodesToRemove), len(nodesToAdd)) ++ if pairs == 0 { ++ logger.Debug("no relocation needed, placement is already optimal") ++ return nil ++ } ++ ++ logger.Infof("relocating %d replica(s): %v -> %v", pairs, nodesToRemove[:pairs], nodesToAdd[:pairs]) ++ ++ // Mark relocation as triggered before starting migrations. ++ err = s.client.ResourceDefinitions.Modify(ctx, volID, lapi.GenericPropsModify{ ++ OverrideProps: map[string]string{propertyRelocationTriggered: "true"}, ++ }) ++ if err != nil { ++ return fmt.Errorf("failed to set relocation property: %w", err) ++ } ++ ++ // Migrate each pair sequentially (LINSTOR serializes at the RD level anyway). ++ for i := range pairs { ++ fromNode := nodesToRemove[i] ++ toNode := nodesToAdd[i] ++ storPool := optimalPools[toNode] ++ ++ logger := logger.WithFields(logrus.Fields{"from": fromNode, "to": toNode, "storagePool": storPool}) ++ ++ logger.Info("creating diskless resource on target node") ++ ++ err := s.client.Resources.MakeAvailable(ctx, volID, toNode, lapi.ResourceMakeAvailable{}) ++ if err != nil { ++ logger.WithError(err).Warn("failed to create diskless on target, skipping this pair") ++ continue ++ } ++ ++ logger.Info("initiating migrate-disk") ++ ++ err = s.client.Resources.Migrate(ctx, volID, fromNode, toNode, storPool) ++ if err != nil { ++ logger.WithError(err).Warn("migrate-disk failed, skipping this pair") ++ continue ++ } ++ } ++ ++ return nil ++} ++ + // FindSnapsByID searches the snapshot in the backend + func (s *Linstor) FindSnapsByID(ctx context.Context, id string) ([]*volume.Snapshot, error) { + snapshotId, err := volume.ParseSnapshotId(id) +diff --git a/pkg/volume/parameter.go b/pkg/volume/parameter.go +index 39acd95..54d1dfb 100644 +--- a/pkg/volume/parameter.go ++++ b/pkg/volume/parameter.go +@@ -50,6 +50,7 @@ const ( + nfsservicename + nfssquash + nfsrecoveryvolumesize ++ relocateafterclone + ) + + // Parameters configuration for linstor volumes. +@@ -118,6 +119,8 @@ type Parameters struct { + // NfsRecoveryVolumeSize sets the volume size (in bytes) of the recovery volume used by the NFS server. + // Defaults to 300MiB. + NfsRecoveryVolumeBytes int64 ++ // RelocateAfterClone triggers asynchronous relocation of replicas to optimal nodes after cloning. ++ RelocateAfterClone bool + } + + const DefaultDisklessStoragePoolName = "DfltDisklessStorPool" +@@ -140,6 +143,7 @@ func NewParameters(params map[string]string, topologyPrefix string) (Parameters, + NfsServiceName: "linstor-csi-nfs", + NfsSquash: "no_root_squash", + NfsRecoveryVolumeBytes: 300 * 1024 * 1024, ++ RelocateAfterClone: true, + } + + for k, v := range params { +@@ -287,6 +291,13 @@ func NewParameters(params map[string]string, topologyPrefix string) (Parameters, + } + + p.NfsRecoveryVolumeBytes = s.Value() ++ case relocateafterclone: ++ val, err := strconv.ParseBool(v) ++ if err != nil { ++ return p, err ++ } ++ ++ p.RelocateAfterClone = val + } + } + +diff --git a/pkg/volume/paramkey_enumer.go b/pkg/volume/paramkey_enumer.go +index 5474963..2eb8a7c 100644 +--- a/pkg/volume/paramkey_enumer.go ++++ b/pkg/volume/paramkey_enumer.go +@@ -7,11 +7,11 @@ import ( + "strings" + ) + +-const _paramKeyName = "allowremotevolumeaccessautoplaceclientlistdisklessonremainingdisklessstoragepooldonotplacewithregexencryptionfsoptslayerlistmountoptsnodelistplacementcountplacementpolicyreplicasondifferentreplicasonsamesizekibstoragepoolpostmountxfsoptsresourcegroupusepvcnameoverprovisionxreplicasondifferentnfsconfigtemplatenfsservicenamenfssquashnfsrecoveryvolumesize" ++const _paramKeyName = "allowremotevolumeaccessautoplaceclientlistdisklessonremainingdisklessstoragepooldonotplacewithregexencryptionfsoptslayerlistmountoptsnodelistplacementcountplacementpolicyreplicasondifferentreplicasonsamesizekibstoragepoolpostmountxfsoptsresourcegroupusepvcnameoverprovisionxreplicasondifferentnfsconfigtemplatenfsservicenamenfssquashnfsrecoveryvolumesizerelocateafterclone" + +-var _paramKeyIndex = [...]uint16{0, 23, 32, 42, 61, 80, 99, 109, 115, 124, 133, 141, 155, 170, 189, 203, 210, 221, 237, 250, 260, 273, 293, 310, 324, 333, 354} ++var _paramKeyIndex = [...]uint16{0, 23, 32, 42, 61, 80, 99, 109, 115, 124, 133, 141, 155, 170, 189, 203, 210, 221, 237, 250, 260, 273, 293, 310, 324, 333, 354, 372} + +-const _paramKeyLowerName = "allowremotevolumeaccessautoplaceclientlistdisklessonremainingdisklessstoragepooldonotplacewithregexencryptionfsoptslayerlistmountoptsnodelistplacementcountplacementpolicyreplicasondifferentreplicasonsamesizekibstoragepoolpostmountxfsoptsresourcegroupusepvcnameoverprovisionxreplicasondifferentnfsconfigtemplatenfsservicenamenfssquashnfsrecoveryvolumesize" ++const _paramKeyLowerName = "allowremotevolumeaccessautoplaceclientlistdisklessonremainingdisklessstoragepooldonotplacewithregexencryptionfsoptslayerlistmountoptsnodelistplacementcountplacementpolicyreplicasondifferentreplicasonsamesizekibstoragepoolpostmountxfsoptsresourcegroupusepvcnameoverprovisionxreplicasondifferentnfsconfigtemplatenfsservicenamenfssquashnfsrecoveryvolumesizerelocateafterclone" + + func (i paramKey) String() string { + if i < 0 || i >= paramKey(len(_paramKeyIndex)-1) { +@@ -50,9 +50,10 @@ func _paramKeyNoOp() { + _ = x[nfsservicename-(23)] + _ = x[nfssquash-(24)] + _ = x[nfsrecoveryvolumesize-(25)] ++ _ = x[relocateafterclone-(26)] + } + +-var _paramKeyValues = []paramKey{allowremotevolumeaccess, autoplace, clientlist, disklessonremaining, disklessstoragepool, donotplacewithregex, encryption, fsopts, layerlist, mountopts, nodelist, placementcount, placementpolicy, replicasondifferent, replicasonsame, sizekib, storagepool, postmountxfsopts, resourcegroup, usepvcname, overprovision, xreplicasondifferent, nfsconfigtemplate, nfsservicename, nfssquash, nfsrecoveryvolumesize} ++var _paramKeyValues = []paramKey{allowremotevolumeaccess, autoplace, clientlist, disklessonremaining, disklessstoragepool, donotplacewithregex, encryption, fsopts, layerlist, mountopts, nodelist, placementcount, placementpolicy, replicasondifferent, replicasonsame, sizekib, storagepool, postmountxfsopts, resourcegroup, usepvcname, overprovision, xreplicasondifferent, nfsconfigtemplate, nfsservicename, nfssquash, nfsrecoveryvolumesize, relocateafterclone} + + var _paramKeyNameToValueMap = map[string]paramKey{ + _paramKeyName[0:23]: allowremotevolumeaccess, +@@ -107,6 +108,8 @@ var _paramKeyNameToValueMap = map[string]paramKey{ + _paramKeyLowerName[324:333]: nfssquash, + _paramKeyName[333:354]: nfsrecoveryvolumesize, + _paramKeyLowerName[333:354]: nfsrecoveryvolumesize, ++ _paramKeyName[354:372]: relocateafterclone, ++ _paramKeyLowerName[354:372]: relocateafterclone, + } + + var _paramKeyNames = []string{ +@@ -136,6 +139,7 @@ var _paramKeyNames = []string{ + _paramKeyName[310:324], + _paramKeyName[324:333], + _paramKeyName[333:354], ++ _paramKeyName[354:372], + } + + // paramKeyString retrieves an enum value from the enum constants string name. +diff --git a/pkg/volume/snapshot_params.go b/pkg/volume/snapshot_params.go +index d167cb8..50b70fb 100644 +--- a/pkg/volume/snapshot_params.go ++++ b/pkg/volume/snapshot_params.go +@@ -35,6 +35,7 @@ type SnapshotParameters struct { + LinstorTargetUrl string `json:"linstor-target-url,omitempty"` + LinstorTargetClusterID string `json:"linstor-target-cluster-id,omitempty"` + LinstorTargetStoragePool string `json:"linstor-target-storage-pool,omitempty"` ++ RelocateAfterRestore bool `json:"relocate-after-restore,omitempty"` + } + + func NewSnapshotParameters(params, secrets map[string]string) (*SnapshotParameters, error) { +@@ -91,6 +92,13 @@ func NewSnapshotParameters(params, secrets map[string]string) (*SnapshotParamete + p.LinstorTargetClusterID = v + case "/linstor-target-storage-pool": + p.LinstorTargetStoragePool = v ++ case "/relocateAfterRestore": ++ b, err := strconv.ParseBool(v) ++ if err != nil { ++ return nil, err ++ } ++ ++ p.RelocateAfterRestore = b + default: + log.WithField("key", k).Warn("ignoring unknown snapshot parameter key") + } diff --git a/packages/system/linstor/images/linstor-csi/patches/002-protocol-c-override-for-dual-attach.diff b/packages/system/linstor/images/linstor-csi/patches/002-protocol-c-override-for-dual-attach.diff new file mode 100644 index 00000000..279c636b --- /dev/null +++ b/packages/system/linstor/images/linstor-csi/patches/002-protocol-c-override-for-dual-attach.diff @@ -0,0 +1,132 @@ +diff --git a/pkg/client/linstor.go b/pkg/client/linstor.go +index ac4651d..9d75c79 100644 +--- a/pkg/client/linstor.go ++++ b/pkg/client/linstor.go +@@ -653,11 +653,35 @@ func (s *Linstor) Attach(ctx context.Context, volId, node string, rwxBlock bool) + } + + if otherResInUse > 0 && rwxBlock { +- rdPropsModify := lapi.GenericPropsModify{OverrideProps: map[string]string{ ++ rdProps := map[string]string{ + linstor.PropertyAllowTwoPrimaries: "yes", +- }} ++ } + +- err = s.client.ResourceDefinitions.Modify(ctx, volId, rdPropsModify) ++ // DRBD requires Protocol C whenever allow-two-primaries is enabled. ++ // If the resource is configured with Protocol A or B (typically ++ // through its resource-group), drbdadm adjust on the satellites ++ // fails with "Protocol C required" (errno 139) and live migration ++ // cannot proceed. Override Protocol to C on the resource-definition ++ // itself so it applies to every connection (including diskless ++ // peers, e.g. a TieBreaker). The marker lets Detach revert exactly ++ // the override we installed without disturbing operator-set props. ++ proto, protoErr := s.getEffectiveDrbdProtocol(ctx, volId) ++ if protoErr != nil { ++ s.log.WithError(protoErr).WithField("volume", volId). ++ Warn("failed to determine effective DRBD protocol; skipping Protocol=C override for dual-attach") ++ } else if proto == "A" || proto == "B" { ++ s.log.WithFields(logrus.Fields{ ++ "volume": volId, ++ "protocol": proto, ++ }).Info("installing Protocol=C override on resource-definition for dual-attach") ++ ++ rdProps[linstor.PropertyDrbdNetProtocol] = "C" ++ rdProps[linstor.PropertyCsiProtocolOverride] = "yes" ++ } ++ ++ err = s.client.ResourceDefinitions.Modify(ctx, volId, lapi.GenericPropsModify{ ++ OverrideProps: rdProps, ++ }) + if err != nil { + return "", err + } +@@ -774,11 +798,26 @@ func (s *Linstor) Detach(ctx context.Context, volId, node string) error { + } + + if resInUse == 1 { +- rdPropsModify := lapi.GenericPropsModify{DeleteProps: []string{ +- linstor.PropertyAllowTwoPrimaries, +- }} ++ deleteProps := []string{linstor.PropertyAllowTwoPrimaries} ++ ++ // Drop the Protocol=C override only if Attach installed it (gated by ++ // our marker), so an operator-set Protocol property on the ++ // resource-definition is preserved. ++ rd, getErr := s.client.ResourceDefinitions.Get(ctx, volId) ++ if getErr != nil { ++ log.WithError(getErr).Warn("failed to fetch resource-definition props; skipping Protocol=C override removal") ++ } else if rd.Props[linstor.PropertyCsiProtocolOverride] != "" { ++ log.Info("removing Protocol=C override from resource-definition") + +- err = s.client.ResourceDefinitions.Modify(ctx, volId, rdPropsModify) ++ deleteProps = append(deleteProps, ++ linstor.PropertyDrbdNetProtocol, ++ linstor.PropertyCsiProtocolOverride, ++ ) ++ } ++ ++ err = s.client.ResourceDefinitions.Modify(ctx, volId, lapi.GenericPropsModify{ ++ DeleteProps: deleteProps, ++ }) + if err != nil { + return nil404(err) + } +@@ -805,6 +844,33 @@ func (s *Linstor) Detach(ctx context.Context, volId, node string) error { + return nil404(s.client.Resources.Delete(ctx, volId, node)) + } + ++// getEffectiveDrbdProtocol returns the DRBD network protocol ("A", "B" or "C") ++// that LINSTOR will hand to drbdadm for the given resource. Resource-definition ++// properties take precedence; otherwise the value is inherited from the ++// resource-group. An empty string is returned when neither level sets the ++// property (LINSTOR's compiled-in default is "C"). ++func (s *Linstor) getEffectiveDrbdProtocol(ctx context.Context, volId string) (string, error) { ++ rd, err := s.client.ResourceDefinitions.Get(ctx, volId) ++ if err != nil { ++ return "", err ++ } ++ ++ if v, ok := rd.Props[linstor.PropertyDrbdNetProtocol]; ok { ++ return v, nil ++ } ++ ++ if rd.ResourceGroupName == "" { ++ return "", nil ++ } ++ ++ rg, err := s.client.ResourceGroups.Get(ctx, rd.ResourceGroupName) ++ if err != nil { ++ return "", err ++ } ++ ++ return rg.Props[linstor.PropertyDrbdNetProtocol], nil ++} ++ + // CapacityBytes returns the amount of free space in the storage pool specified by the params and topology. + func (s *Linstor) CapacityBytes(ctx context.Context, storagePools []string, overProvision *float64, segments map[string]string) (int64, error) { + log := s.log.WithField("storage-pools", storagePools).WithField("segments", segments) +diff --git a/pkg/linstor/const.go b/pkg/linstor/const.go +index 9a5f79c..c8bc9c3 100644 +--- a/pkg/linstor/const.go ++++ b/pkg/linstor/const.go +@@ -44,6 +44,19 @@ const ( + // PropertyAllowTwoPrimaries is DRBD option to allow second primary. Mainly used for live-migration. + PropertyAllowTwoPrimaries = lc.NamespcDrbdNetOptions + "/allow-two-primaries" + ++ // PropertyDrbdNetProtocol is the DRBD network replication protocol option ++ // (A = async, B = semi-sync, C = sync). DRBD requires Protocol C whenever ++ // allow-two-primaries is enabled, otherwise drbdadm adjust fails with ++ // "Protocol C required" (errno 139). ++ PropertyDrbdNetProtocol = lc.NamespcDrbdNetOptions + "/protocol" ++ ++ // PropertyCsiProtocolOverride marks a resource-connection where this driver ++ // has installed a temporary Protocol=C override to make a Protocol-A/B ++ // resource compatible with allow-two-primaries during live migration. The ++ // marker lets us safely remove only the overrides we set, without touching ++ // connection-level overrides installed by the operator. ++ PropertyCsiProtocolOverride = lc.NamespcAuxiliary + "/csi-protocol-override" ++ + // CreatedForTemporaryDisklessAttach marks a resource as temporary, i.e. it should be removed after it is no longer + // needed. + CreatedForTemporaryDisklessAttach = "temporary-diskless-attach" diff --git a/packages/system/linstor/images/piraeus-server/Dockerfile b/packages/system/linstor/images/piraeus-server/Dockerfile new file mode 100644 index 00000000..f93e494f --- /dev/null +++ b/packages/system/linstor/images/piraeus-server/Dockerfile @@ -0,0 +1,174 @@ +ARG DISTRO=bookworm +ARG LINSTOR_VERSION + +# ------------------------------------------------------------------------------ +# Build linstor-server from source +FROM debian:bookworm AS builder + +ARG LINSTOR_VERSION +ARG VERSION=${LINSTOR_VERSION} +ARG DISTRO + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update \ + && apt-get -y upgrade \ + && apt-get -y install build-essential git default-jdk-headless python3-all debhelper wget unzip && \ + wget https://services.gradle.org/distributions/gradle-8.9-bin.zip -O /tmp/gradle.zip && \ + unzip -d /opt /tmp/gradle.zip && \ + rm /tmp/gradle.zip && \ + ln -s /opt/gradle-8.9/bin/gradle /usr/local/bin/gradle + +RUN git clone https://github.com/LINBIT/linstor-server.git /linstor-server +WORKDIR /linstor-server +RUN git checkout v${VERSION} + +# Apply patches +COPY patches /patches +RUN git apply /patches/*.diff && \ + git config user.email "build@cozystack.io" && \ + git config user.name "Cozystack Builder" && \ + git add -A && \ + git commit -m "Apply patches" + +# Initialize git submodules +RUN git submodule update --init --recursive || make check-submods + +# Pre-download ALL dependencies before make tarball +# This ensures all transitive dependencies are cached, including optional ones like AWS SDK +RUN ./gradlew getProtoc +RUN ./gradlew generateJava +RUN ./gradlew --no-daemon --gradle-user-home .gradlehome downloadDependencies + +# Manually create tarball without removing caches +# make tarball removes .gradlehome/caches/[0-9]* which deletes dependencies +# So we'll do the steps manually but keep the caches +RUN make check-submods versioninfo gen-java FORCE=1 VERSION=${VERSION} +RUN make server/jar.deps controller/jar.deps satellite/jar.deps jclcrypto/jar.deps FORCE=1 VERSION=${VERSION} +RUN make .filelist FORCE=1 VERSION=${VERSION} PRESERVE_DEBIAN=1 +# Don't remove caches - we need them for offline build +RUN rm -Rf .gradlehome/wrapper .gradlehome/native .gradlehome/.tmp || true +RUN mkdir -p ./libs +RUN make tgz VERSION=${VERSION} + +# Extract tarball and build DEB packages from it +RUN mv linstor-server-${VERSION}.tar.gz /linstor-server_${VERSION}.orig.tar.gz \ + && tar -C / -xvf /linstor-server_${VERSION}.orig.tar.gz + +WORKDIR /linstor-server-${VERSION} +# Verify .gradlehome is present in extracted tarball +RUN test -d .gradlehome && echo ".gradlehome found in tarball" || (echo ".gradlehome not found in tarball!" && exit 1) + +# Build DEB packages from tarball +# Override GRADLE_FLAGS to remove --offline flag, allowing Gradle to download missing dependencies +RUN sed -i 's/GRADLE_FLAGS = --offline/GRADLE_FLAGS =/' debian/rules || true +# Skip dh_strip_nondeterminism to avoid failures on some JAR files (logback-core) +RUN printf '\noverride_dh_strip_nondeterminism:\n\ttrue\n' >> debian/rules +RUN LD_LIBRARY_PATH='' dpkg-buildpackage -rfakeroot -b -uc + +# Copy built .deb packages to a location accessible from final image +# dpkg-buildpackage creates packages in parent directory +RUN mkdir -p /packages-output && \ + find .. -maxdepth 1 -name "linstor-*.deb" -exec cp {} /packages-output/ \; && \ + test -n "$(ls -A /packages-output)" || (echo "ERROR: No linstor .deb packages found after build." && exit 1) + +# ------------------------------------------------------------------------------ +# Final image +FROM debian:${DISTRO} + +LABEL maintainer="Roland Kammerer " + +ARG LINSTOR_VERSION +ARG DISTRO + +# Copy built .deb packages from builder stage +# dpkg-buildpackage creates packages in parent directory, we copied them to /packages-output +COPY --from=builder /packages-output/ /packages/ + +RUN { echo 'APT::Install-Recommends "false";' ; echo 'APT::Install-Suggests "false";' ; } > /etc/apt/apt.conf.d/99_piraeus + +RUN --mount=type=cache,target=/var/cache,sharing=private \ + --mount=type=cache,target=/var/lib/apt/lists,sharing=private \ + --mount=type=tmpfs,target=/var/log \ + # Install wget first for downloading keyring + apt-get update && apt-get install -y wget ca-certificates && \ + # Enable contrib repos for zfsutils \ + . /etc/os-release && \ + sed -i -r 's/^Components: (.*)$/Components: \1 contrib/' /etc/apt/sources.list.d/debian.sources && \ + echo "deb http://deb.debian.org/debian $VERSION_CODENAME-backports contrib" > /etc/apt/sources.list.d/backports.list && \ + wget https://packages.linbit.com/public/linbit-keyring.deb -O /var/cache/linbit-keyring.deb && \ + dpkg -i /var/cache/linbit-keyring.deb && \ + echo "deb http://packages.linbit.com/public $VERSION_CODENAME misc" > /etc/apt/sources.list.d/linbit.list && \ + apt-get update && \ + # Install useful utilities and general dependencies + apt-get install -y udev drbd-utils jq net-tools iputils-ping iproute2 dnsutils netcat-traditional sysstat curl util-linux && \ + # Install dependencies for optional features \ + apt-get install -y \ + # cryptsetup: luks layer + cryptsetup \ + # e2fsprogs: LINSTOR can create file systems \ + e2fsprogs \ + # lsscsi: exos layer \ + lsscsi \ + # lvm2: manage lvm storage pools \ + lvm2 \ + # multipath-tools: exos layer \ + multipath-tools \ + # nvme-cli: nvme layer + nvme-cli \ + # procps: used by LINSTOR to find orphaned send/receive processes \ + procps \ + # socat: used with thin-send-recv to send snapshots to another LINSTOR cluster + socat \ + # thin-send-recv: used to send/receive snapshots of LVM thin volumes \ + thin-send-recv \ + # xfsprogs: LINSTOR can create file systems; xfs deps \ + xfsprogs \ + # zstd: used with thin-send-recv to send snapshots to another LINSTOR cluster \ + zstd \ + # zfsutils-linux: for zfs storage pools \ + zfsutils-linux/$VERSION_CODENAME-backports \ + && \ + # remove udev, no need for it in the container \ + apt-get remove -y udev && \ + # Install linstor packages from built .deb files and linstor-client from repository + apt-get install -y default-jre-headless python3-all python3-natsort linstor-client \ + && ls packages/*.deb >/dev/null && (dpkg -i packages/*.deb || apt-get install -f -y) \ + && rm -rf /packages \ + && sed -i 's/"-Djdk.tls.acknowledgeCloseNotify=true"//g' /usr/share/linstor-server/bin/Controller \ + && apt-get clean + +# Log directory need to be group writable. OpenShift assigns random UID and GID, without extra RBAC changes we can only influence the GID. +RUN mkdir /var/log/linstor-controller && \ + chown 0:1000 /var/log/linstor-controller && \ + chmod -R 0775 /var/log/linstor-controller && \ + # Ensure we log to files in containers, otherwise SOS reports won't show any logs at all + sed -i 's###' /usr/share/linstor-server/lib/conf/logback.xml + + +RUN lvmconfig --type current --mergedconfig --config 'activation { udev_sync = 0 udev_rules = 0 monitoring = 0 } devices { global_filter = [ "r|^/dev/drbd|" ] obtain_device_list_from_udev = 0}' > /etc/lvm/lvm.conf.new && mv /etc/lvm/lvm.conf.new /etc/lvm/lvm.conf +RUN echo 'global { usage-count no; }' > /etc/drbd.d/global_common.conf + +# controller +EXPOSE 3376/tcp 3377/tcp 3370/tcp 3371/tcp + +# satellite +EXPOSE 3366/tcp 3367/tcp + +RUN wget https://raw.githubusercontent.com/piraeusdatastore/piraeus/refs/heads/master/dockerfiles/piraeus-server/entry.sh -O /usr/bin/piraeus-entry.sh \ + && chmod +x /usr/bin/piraeus-entry.sh + +ARG K8S_AWAIT_ELECTION_VERSION=v0.4.2 +# TARGETARCH is a docker special variable: https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope +ARG TARGETARCH + +RUN wget https://github.com/LINBIT/k8s-await-election/releases/download/${K8S_AWAIT_ELECTION_VERSION}/k8s-await-election-${K8S_AWAIT_ELECTION_VERSION}-linux-${TARGETARCH}.tar.gz -O - | tar -xvz -C /usr/bin/ + +ARG LOSETUP_CONTAINER_VERSION=v1.0.1 +RUN wget "https://github.com/LINBIT/losetup-container/releases/download/${LOSETUP_CONTAINER_VERSION}/losetup-container-$(uname -m)-unknown-linux-gnu.tar.gz" -O - | tar -xvz -C /usr/local/sbin && \ + printf '#!/bin/sh\nLOSETUP_CONTAINER_ORIGINAL_LOSETUP=%s exec /usr/local/sbin/losetup-container "$@"\n' $(command -v losetup) > /usr/local/sbin/losetup && \ + chmod +x /usr/local/sbin/losetup + +RUN wget "https://dl.k8s.io/$(wget -O - https://dl.k8s.io/release/stable.txt)/bin/linux/${TARGETARCH}/kubectl" -O /usr/local/bin/kubectl && chmod +x /usr/local/bin/kubectl + +CMD ["startSatellite"] +ENTRYPOINT ["/usr/bin/k8s-await-election", "/usr/bin/piraeus-entry.sh"] diff --git a/packages/system/linstor/images/piraeus-server/patches/README.md b/packages/system/linstor/images/piraeus-server/patches/README.md new file mode 100644 index 00000000..dfe75c2e --- /dev/null +++ b/packages/system/linstor/images/piraeus-server/patches/README.md @@ -0,0 +1,17 @@ +# LINSTOR Server Patches + +Custom patches for piraeus-server (linstor-server) v1.33.2. + +- **allow-toggle-disk-retry.diff** — Backport maintainer implementation of toggle-disk retry/abort + - Source PR/comment: [#475](https://github.com/LINBIT/linstor-server/pull/475), [maintainer note](https://github.com/LINBIT/linstor-server/pull/475#issuecomment-3949630419) + - Backported from upstream commit: [`3d97f71c9`](https://github.com/LINBIT/linstor-server/commit/3d97f71c95a493588d3d521c63eac4d846935fb3) +- **fix-duplicate-tcp-ports.diff** — Preserve DRBD TCP ports during toggle-disk and avoid redundant `ensureStackDataExists()` + - Source PR/review: [#476](https://github.com/LINBIT/linstor-server/pull/476), [review suggestion](https://github.com/LINBIT/linstor-server/pull/476#discussion_r3007725079) + - Backported from commits: [`79d6375c5`](https://github.com/kvaps/linstor-server/commit/79d6375c55d6181b35a7b7f0fe8dbdfb86e126cd), [`bcc89902f`](https://github.com/kvaps/linstor-server/commit/bcc89902f4f61ac1589dd07ebb7f5aae1935370d) +- **fix-luks-header-size.diff** — Account for LUKS2 `--offset`, metadata/keyslots sizing, and device `optimal_io_size` + - Source PR/comment: [#472](https://github.com/LINBIT/linstor-server/pull/472), [maintainer note](https://github.com/LINBIT/linstor-server/pull/472#issuecomment-3949687603) + - Backported from commits: [`ccc85fbd2`](https://github.com/LINBIT/linstor-server/commit/ccc85fbd2c65f0b97c52403fa80f1efdb886ec4e), [`71b601554`](https://github.com/LINBIT/linstor-server/commit/71b601554f41bcb50cd5bd06989c5b0d3a814acd) + - Note: upstream commit [`3d0402a0c`](https://github.com/LINBIT/linstor-server/commit/3d0402a0c25f0a4b57b380321f10e89982f26e7a) is already included in `v1.33.1` +- **retry-adjust-after-stale-bitmap.diff** — Retry `drbdadm adjust` after detaching a stale local bitmap state + - Source PR: [#491](https://github.com/LINBIT/linstor-server/pull/491) + - Backported from commit: [`51ae50a84`](https://github.com/kvaps/linstor-server/commit/51ae50a84dcb98093f543b819652c750a94d96c9) diff --git a/packages/system/linstor/images/piraeus-server/patches/allow-toggle-disk-retry.diff b/packages/system/linstor/images/piraeus-server/patches/allow-toggle-disk-retry.diff new file mode 100644 index 00000000..952ba16c --- /dev/null +++ b/packages/system/linstor/images/piraeus-server/patches/allow-toggle-disk-retry.diff @@ -0,0 +1,261 @@ +diff --git a/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java b/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java +index d93a18014..a944cb809 100644 +--- a/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java ++++ b/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java +@@ -111,6 +111,14 @@ import reactor.util.function.Tuple2; + @Singleton + public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionListener + { ++ private enum ToggleDiskAction ++ { ++ NOOP, ++ NORMAL, ++ ABORT, ++ RETRY ++ } ++ + private final AccessContext apiCtx; + private final ScopeRunner scopeRunner; + private final BackgroundRunner backgroundRunner; +@@ -386,69 +394,33 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL + "Toggle Disk on %s/%s %s", nodeNameStr, rscNameStr, removeDisk ? "removing disk" : "adding disk"); + + Resource rsc = ctrlApiDataLoader.loadRsc(nodeName, rscName, true); ++ ResourceDefinition rscDfn = rsc.getResourceDefinition(); + +- if (hasDiskAddRequested(rsc)) +- { +- throw new ApiRcException(ApiCallRcImpl.simpleEntry( +- ApiConsts.FAIL_RSC_BUSY, +- "Addition of disk to resource already requested", +- true +- )); +- } +- if (hasDiskRemoveRequested(rsc)) +- { +- throw new ApiRcException(ApiCallRcImpl.simpleEntry( +- ApiConsts.FAIL_RSC_BUSY, +- "Removal of disk from resource already requested", +- true +- )); +- } ++ ToggleDiskAction action = determineToggleDiskAction(rsc, removeDisk); ++ errorReporter.logDebug("Toggle Disk action: %s", action); + +- if (!removeDisk && !ctrlVlmCrtApiHelper.isDiskless(rsc)) ++ switch (action) + { +- throw new ApiRcException(ApiCallRcImpl.simpleEntry( +- ApiConsts.WARN_RSC_ALREADY_HAS_DISK, +- "Resource already has disk", +- true +- )); +- } +- if (removeDisk && ctrlVlmCrtApiHelper.isDiskless(rsc)) +- { +- throw new ApiRcException(ApiCallRcImpl.simpleEntry( +- ApiConsts.WARN_RSC_ALREADY_DISKLESS, +- "Resource already diskless", +- true +- )); ++ case NOOP: ++ return handleNoopAction(rsc, removeDisk); ++ case RETRY: ++ return handleRetryAction(rsc, removeDisk, toggleIntoTiebreakerRef, context); ++ case ABORT: ++ clearToggleDiskFlags(rsc); ++ errorReporter.logInfo( ++ "Aborting previous toggle disk transition, starting new transition to %s", ++ removeDisk ? "diskless" : "diskful" ++ ); ++ break; ++ case NORMAL: ++ break; ++ default: ++ throw new ImplementationError("Unhandled case: " + action); + } + +- ResourceDefinition rscDfn = rsc.getResourceDefinition(); +- AccessContext peerCtx = peerAccCtx.get(); +- if (removeDisk) +- { +- // Prevent removal of the last disk +- int haveDiskCount = countDisksAndIsOnline(rscDfn); +- if (haveDiskCount <= 1) +- { +- throw new ApiRcException(ApiCallRcImpl.simpleEntry( +- ApiConsts.FAIL_INSUFFICIENT_REPLICA_COUNT, +- "Cannot remove the disk from the only online resource with a disk", +- true +- )); +- } ++ validateToggleDiskPreconditions(rsc, removeDisk); + +- if (!LayerUtils.hasLayer(getLayerData(peerCtx, rsc), DeviceLayerKind.DRBD)) +- { +- throw new ApiRcException(ApiCallRcImpl.simpleEntry( +- ApiConsts.FAIL_INVLD_LAYER_STACK, +- "Toggle disk is only supported in combination with DRBD", +- true +- )); +- } +- } +- else +- { +- ensureAllPeersHavePeerSlotLeft(rscDfn); +- } ++ AccessContext peerCtx = peerAccCtx.get(); + + // Save the requested storage pool in the resource properties. + // This does not cause the storage pool to be used automatically. +@@ -628,10 +600,10 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL + + ctrlTransactionHelper.commit(); + +- String action = removeDisk ? "Removal of disk from" : "Addition of disk to"; ++ String actionStr = removeDisk ? "Removal of disk from" : "Addition of disk to"; + responses.addEntry(ApiCallRcImpl.simpleEntry( + ApiConsts.MODIFIED, +- action + " resource '" + rscDfn.getName().displayValue + "' " + ++ actionStr + " resource '" + rscDfn.getName().displayValue + "' " + + "on node '" + rsc.getNode().getName().displayValue + "' registered" + )); + +@@ -651,6 +623,40 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL + ); + } + ++ private Flux handleNoopAction(Resource rscRef, boolean removeDiskRef) ++ { ++ String state = removeDiskRef ? "diskless" : "diskful"; ++ ApiCallRcImpl responses = new ApiCallRcImpl(); ++ responses.addEntry(ApiCallRcImpl.simpleEntry( ++ ApiConsts.INFO_NOOP, ++ "Resource '" + rscRef.getResourceDefinition().getName().displayValue + "' on node '" + ++ rscRef.getNode().getName().displayValue + "' is already " + state ++ )); ++ return Flux.just(responses); ++ } ++ ++ private Flux handleRetryAction( ++ Resource rscRef, ++ boolean removeDisk, ++ boolean toggleIntoTiebreakerRef, ++ ResponseContext context ++ ) ++ { ++ String direction = removeDisk ? "diskless" : "diskful"; ++ ApiCallRcImpl responses = new ApiCallRcImpl(); ++ NodeName nodeName = rscRef.getNode().getName(); ++ ResourceName rscName = rscRef.getResourceDefinition().getName(); ++ responses.addEntry(ApiCallRcImpl.simpleEntry( ++ ApiConsts.INFO_NOOP, ++ "Retrying toggle disk to " + direction + " for resource '" + rscName.displayValue + ++ "' on node '" + nodeName.displayValue + "'" ++ )); ++ ++ return Flux ++ .just(responses) ++ .concatWith(updateAndAdjustDisk(nodeName, rscName, removeDisk, toggleIntoTiebreakerRef, context)); ++ } ++ + private long getVlmDfnSizePrivileged(VolumeDefinition vlmDfnRef) + { + try +@@ -781,6 +787,96 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL + } + } + ++ private ToggleDiskAction determineToggleDiskAction(Resource rsc, boolean removeDisk) ++ { ++ boolean isDiskless = ctrlVlmCrtApiHelper.isDiskless(rsc); ++ boolean diskAddRequested = hasDiskAddRequested(rsc); ++ boolean diskRemoveRequested = hasDiskRemoveRequested(rsc); ++ ++ ToggleDiskAction action; ++ if (isDiskless) ++ { ++ if (diskAddRequested) ++ { ++ action = removeDisk ? ToggleDiskAction.ABORT : ToggleDiskAction.RETRY; ++ } ++ else if (diskRemoveRequested) ++ { ++ action = removeDisk ? ToggleDiskAction.RETRY : ToggleDiskAction.ABORT; ++ } ++ else ++ { ++ action = removeDisk ? ToggleDiskAction.NOOP : ToggleDiskAction.NORMAL; ++ } ++ } ++ else ++ { ++ if (diskRemoveRequested) ++ { ++ action = removeDisk ? ToggleDiskAction.RETRY : ToggleDiskAction.ABORT; ++ } ++ else ++ { ++ action = removeDisk ? ToggleDiskAction.NORMAL : ToggleDiskAction.NOOP; ++ } ++ } ++ ++ return action; ++ } ++ ++ private void validateToggleDiskPreconditions(Resource rsc, boolean removeDisk) ++ { ++ ResourceDefinition rscDfn = rsc.getResourceDefinition(); ++ if (removeDisk) ++ { ++ validateDiskRemovalAllowed(rsc, rscDfn); ++ } ++ else ++ { ++ ensureAllPeersHavePeerSlotLeft(rscDfn); ++ } ++ } ++ ++ private void clearToggleDiskFlags(Resource rsc) ++ { ++ try ++ { ++ rsc.getStateFlags().disableFlags( ++ apiCtx, ++ Resource.Flags.DISK_ADD_REQUESTED, ++ Resource.Flags.DISK_ADDING, ++ Resource.Flags.DISK_REMOVE_REQUESTED, ++ Resource.Flags.DISK_REMOVING ++ ); ++ } ++ catch (AccessDeniedException | DatabaseException exc) ++ { ++ throw new ImplementationError(exc); ++ } ++ } ++ ++ private void validateDiskRemovalAllowed(Resource rsc, ResourceDefinition rscDfn) ++ { ++ int haveDiskCount = countDisksAndIsOnline(rscDfn); ++ if (haveDiskCount <= 1) ++ { ++ throw new ApiRcException(ApiCallRcImpl.simpleEntry( ++ ApiConsts.FAIL_INSUFFICIENT_REPLICA_COUNT, ++ "Cannot remove the disk from the only online resource with a disk", ++ true ++ )); ++ } ++ ++ if (!LayerUtils.hasLayer(getLayerData(peerAccCtx.get(), rsc), DeviceLayerKind.DRBD)) ++ { ++ throw new ApiRcException(ApiCallRcImpl.simpleEntry( ++ ApiConsts.FAIL_INVLD_LAYER_STACK, ++ "Toggle disk is only supported in combination with DRBD", ++ true ++ )); ++ } ++ } ++ + /** + * Although we need to rebuild the layerData as the layerList might have changed, if we do not + * deactivate (i.e. down) the current resource, we need to make sure that deleting DrbdRscData diff --git a/packages/system/linstor/images/piraeus-server/patches/fix-duplicate-tcp-ports.diff b/packages/system/linstor/images/piraeus-server/patches/fix-duplicate-tcp-ports.diff new file mode 100644 index 00000000..ed106f98 --- /dev/null +++ b/packages/system/linstor/images/piraeus-server/patches/fix-duplicate-tcp-ports.diff @@ -0,0 +1,137 @@ +diff --git a/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java b/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java +index d93a18014..01cfbbacf 100644 +--- a/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java ++++ b/controller/src/main/java/com/linbit/linstor/core/apicallhandler/controller/CtrlRscToggleDiskApiCallHandler.java +@@ -37,6 +37,7 @@ import com.linbit.linstor.core.objects.StorPool; + import com.linbit.linstor.core.objects.Volume; + import com.linbit.linstor.core.objects.VolumeDefinition; + import com.linbit.linstor.core.objects.utils.MixedStorPoolHelper; ++import com.linbit.linstor.core.types.TcpPortNumber; + import com.linbit.linstor.dbdrivers.DatabaseException; + import com.linbit.linstor.event.EventWaiter; + import com.linbit.linstor.event.ObjectIdentifier; +@@ -85,6 +86,7 @@ import java.util.List; + import java.util.Map; + import java.util.Map.Entry; + import java.util.Set; ++import java.util.TreeSet; + + import org.reactivestreams.Publisher; + import reactor.core.publisher.Flux; +@@ -575,12 +577,13 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL + + /* + * We also have to remove the currently diskless DrbdRscData and free up the node-id as now we must +- * use the shared resource's node-id ++ * use the shared resource's node-id. We still need to preserve TCP ports though. + */ ++ copyDrbdTcpPortsIfExists(rsc, payload); + } + else + { +- copyDrbdNodeIdIfExists(rsc, payload); ++ copyDrbdSettings(rsc, payload); + } + /* + * rebuilds the layerdata in case we just removed it.. +@@ -782,10 +785,20 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL + } + + /** +- * Although we need to rebuild the layerData as the layerList might have changed, if we do not +- * deactivate (i.e. down) the current resource, we need to make sure that deleting DrbdRscData +- * and recreating a new DrbdRscData ends up with the same node-id as before. ++ * Copies DRBD settings (node-id and TCP ports) from the existing DrbdRscData into the payload ++ * before removeLayerData() deletes them. This ensures that recreated DrbdRscData ends up with ++ * the same node-id and TCP ports as before. ++ * ++ * TCP ports must be preserved because if the satellite misses the update (e.g. due to controller ++ * restart or connectivity issues), it will keep the old ports while peers receive the new ones, ++ * causing DRBD connections to fail with StandAlone state. + */ ++ private void copyDrbdSettings(Resource rsc, LayerPayload payload) throws ImplementationError ++ { ++ copyDrbdNodeIdIfExists(rsc, payload); ++ copyDrbdTcpPortsIfExists(rsc, payload); ++ } ++ + private void copyDrbdNodeIdIfExists(Resource rsc, LayerPayload payload) throws ImplementationError + { + Set> drbdRscDataSet = LayerRscUtils.getRscDataByLayer( +@@ -804,6 +817,28 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL + } + } + ++ private void copyDrbdTcpPortsIfExists(Resource rsc, LayerPayload payload) throws ImplementationError ++ { ++ Set> drbdRscDataSet = LayerRscUtils.getRscDataByLayer( ++ getLayerData(apiCtx, rsc), ++ DeviceLayerKind.DRBD ++ ); ++ if (!drbdRscDataSet.isEmpty()) ++ { ++ DrbdRscData drbdRscData = (DrbdRscData) drbdRscDataSet.iterator().next(); ++ Collection tcpPorts = drbdRscData.getTcpPortList(); ++ if (tcpPorts != null && !tcpPorts.isEmpty()) ++ { ++ Set portInts = new TreeSet<>(); ++ for (TcpPortNumber port : tcpPorts) ++ { ++ portInts.add(port.value); ++ } ++ payload.drbdRsc.tcpPorts = portInts; ++ } ++ } ++ } ++ + private List removeLayerData(Resource rscRef) + { + List layerList; +@@ -1058,15 +1093,15 @@ public class CtrlRscToggleDiskApiCallHandler implements CtrlSatelliteConnectionL + /* + * We also have to remove the possible meta-children of previous StorageRscData. + * LayerData will be recreated with ensureStackDataExists. +- * However, we still need to remember our node-id if we had / have DRBD in the list ++ * However, we still need to remember our DRBD settings if we had / have DRBD in the list + */ +- copyDrbdNodeIdIfExists(rsc, payload); ++ copyDrbdSettings(rsc, payload); + layerList = removeLayerData(rsc); + } + else + { + markDiskAdded(rsc); +- ctrlLayerStackHelper.resetStoragePools(rsc); ++ ctrlLayerStackHelper.resetStoragePools(rsc, false); + } + ctrlLayerStackHelper.ensureStackDataExists(rsc, layerList, payload); + +diff --git a/controller/src/main/java/com/linbit/linstor/layer/resource/CtrlRscLayerDataFactory.java b/controller/src/main/java/com/linbit/linstor/layer/resource/CtrlRscLayerDataFactory.java +index 3538b380c..f9733b6f1 100644 +--- a/controller/src/main/java/com/linbit/linstor/layer/resource/CtrlRscLayerDataFactory.java ++++ b/controller/src/main/java/com/linbit/linstor/layer/resource/CtrlRscLayerDataFactory.java +@@ -263,6 +263,11 @@ public class CtrlRscLayerDataFactory + } + + public void resetStoragePools(Resource rscRef) ++ { ++ resetStoragePools(rscRef, true); ++ } ++ ++ public void resetStoragePools(Resource rscRef, boolean callEnsureStackDataExistsRef) + { + try + { +@@ -276,8 +281,10 @@ public class CtrlRscLayerDataFactory + + rscDataToProcess.addAll(rscData.getChildren()); + } +- +- ensureStackDataExists(rscRef, null, new LayerPayload()); ++ if (callEnsureStackDataExistsRef) ++ { ++ ensureStackDataExists(rscRef, null, new LayerPayload()); ++ } + } + catch (AccessDeniedException exc) + { diff --git a/packages/system/linstor/images/piraeus-server/patches/fix-luks-header-size.diff b/packages/system/linstor/images/piraeus-server/patches/fix-luks-header-size.diff new file mode 100644 index 00000000..8611825b --- /dev/null +++ b/packages/system/linstor/images/piraeus-server/patches/fix-luks-header-size.diff @@ -0,0 +1,570 @@ +diff --git a/satellite/src/main/java/com/linbit/linstor/layer/storage/AbsStorageProvider.java b/satellite/src/main/java/com/linbit/linstor/layer/storage/AbsStorageProvider.java +--- a/satellite/src/main/java/com/linbit/linstor/layer/storage/AbsStorageProvider.java ++++ b/satellite/src/main/java/com/linbit/linstor/layer/storage/AbsStorageProvider.java +@@ -2081,7 +2081,6 @@ public abstract class AbsStorageProvider< + ) + throws IOException, AccessDeniedException + { +- final StorPoolName storPoolObjName = storPoolObj.getName(); + if (storDevicePath != null) + { + errorReporter.logDebug("updateMinIoSize: Have storDevicePath \"%s\"", storDevicePath); +@@ -2094,35 +2093,18 @@ public abstract class AbsStorageProvider< + "updateMinIoSize: Block device path is \"%s\"", + blockDevicePath.toString() + ); +- final long minIoSize = BlockSizeInfo.getBlockSize(blockDevicePath); +- +- boolean updateValue = true; +- +- final String propKey = StorageConstants.NAMESPACE_INTERNAL + '/' + +- StorageConstants.BLK_DEV_MIN_IO_SIZE; +- final Props storPoolProps = storPoolObj.getProps(storDriverAccCtx); +- final @Nullable String currentPropValue = storPoolProps.getProp(propKey); +- if (currentPropValue != null) +- { +- try +- { +- final long currentPropMinIoSize = Long.parseLong(currentPropValue); +- updateValue = currentPropMinIoSize != minIoSize; +- } +- catch (NumberFormatException ignored) +- { +- } +- } +- +- if (updateValue) +- { +- final String propValue = Long.toString(minIoSize); +- errorReporter.logDebug( +- "Storage pool \"%s\": Set property \"%s\" = \"%s\"", +- storPoolObjName.displayValue, propKey, propValue +- ); +- propsChange.changeStorPoolProp(storPoolObj, propKey, propValue); +- } ++ updatePropIfNeeded( ++ propsChange, ++ storPoolObj, ++ StorageConstants.NAMESPACE_INTERNAL + '/' + StorageConstants.BLK_DEV_MIN_IO_SIZE, ++ Long.toString(BlockSizeInfo.getBlockSize(blockDevicePath)) ++ ); ++ updatePropIfNeeded( ++ propsChange, ++ storPoolObj, ++ StorageConstants.NAMESPACE_INTERNAL + '/' + StorageConstants.BLK_DEV_OPT_IO_SIZE, ++ Long.toString(BlockSizeInfo.getOptimalIoSize(blockDevicePath)) ++ ); + } + else + { +@@ -2130,6 +2112,28 @@ public abstract class AbsStorageProvider< + } + } + ++ private void updatePropIfNeeded( ++ LocalPropsChangePojo propsChangeRef, ++ StorPool storPoolObjRef, ++ String propKeyRef, ++ String propValueRef ++ ) ++ throws AccessDeniedException ++ { ++ final Props storPoolProps = storPoolObjRef.getProps(storDriverAccCtx); ++ final @Nullable String currentPropValue = storPoolProps.getProp(propKeyRef); ++ if (currentPropValue == null || !currentPropValue.equals(propValueRef)) ++ { ++ errorReporter.logDebug( ++ "Storage pool \"%s\": Set property \"%s\" = \"%s\"", ++ storPoolObjRef.getName().displayValue, ++ propKeyRef, ++ propValueRef ++ ); ++ propsChangeRef.changeStorPoolProp(storPoolObjRef, propKeyRef, propValueRef); ++ } ++ } ++ + @SuppressWarnings("unchecked") + @Override + public void updateAllocatedSize(VlmProviderObject vlmDataRef) +diff --git a/satellite/src/main/java/com/linbit/linstor/layer/storage/utils/BlockSizeInfo.java b/satellite/src/main/java/com/linbit/linstor/layer/storage/utils/BlockSizeInfo.java +--- a/satellite/src/main/java/com/linbit/linstor/layer/storage/utils/BlockSizeInfo.java ++++ b/satellite/src/main/java/com/linbit/linstor/layer/storage/utils/BlockSizeInfo.java +@@ -3,8 +3,11 @@ package com.linbit.linstor.layer.storage.utils; + import com.linbit.utils.MathUtils; + import com.linbit.utils.SymbolicLinkResolver; + ++import static com.linbit.linstor.layer.storage.BlockSizeConsts.DFLT_OPT_IO_SIZE; + import static com.linbit.linstor.layer.storage.BlockSizeConsts.DFLT_IO_SIZE; ++import static com.linbit.linstor.layer.storage.BlockSizeConsts.MAX_OPT_IO_SIZE; + import static com.linbit.linstor.layer.storage.BlockSizeConsts.MAX_IO_SIZE; ++import static com.linbit.linstor.layer.storage.BlockSizeConsts.MIN_OPT_IO_SIZE; + import static com.linbit.linstor.layer.storage.BlockSizeConsts.MIN_IO_SIZE; + + import java.io.FileInputStream; +@@ -13,6 +16,8 @@ import java.nio.file.Path; + + public class BlockSizeInfo + { ++ private static final int NUMBER_BUFFER_SIZE = 32; ++ + /** + * Determines the blocksize, aka minimum I/O size, for the specified backing storage path. + * +@@ -51,7 +56,7 @@ public class BlockSizeInfo + final Path infoSourceName = blockDevice.getFileName(); + final Path infoSource = Path.of("/sys/block", infoSourceName.toString(), "queue/physical_block_size"); + +- final byte[] data = new byte[32]; ++ final byte[] data = new byte[NUMBER_BUFFER_SIZE]; + try (final FileInputStream fileIn = new FileInputStream(infoSource.toString())) + { + final int readCount = fileIn.read(data); +@@ -75,4 +80,38 @@ public class BlockSizeInfo + } + return blockSize; + } ++ ++ public static long getOptimalIoSize(final Path storageObj) ++ { ++ long optIoSize = DFLT_OPT_IO_SIZE; ++ try ++ { ++ final Path blockDevice = SymbolicLinkResolver.resolveSymLink(storageObj); ++ final Path infoSourceName = blockDevice.getFileName(); ++ final Path infoSource = Path.of("/sys/block", infoSourceName.toString(), "queue/optimal_io_size"); ++ ++ final byte[] data = new byte[NUMBER_BUFFER_SIZE]; ++ try (final FileInputStream fileIn = new FileInputStream(infoSource.toString())) ++ { ++ final int readCount = fileIn.read(data); ++ if (readCount > 0) ++ { ++ String numberStr = new String(data, 0, readCount); ++ numberStr = numberStr.trim(); ++ try ++ { ++ final long unboundedOptIoSize = Long.parseLong(numberStr); ++ optIoSize = MathUtils.bounds(MIN_OPT_IO_SIZE, unboundedOptIoSize, MAX_OPT_IO_SIZE); ++ } ++ catch (NumberFormatException ignored) ++ { ++ } ++ } ++ } ++ } ++ catch (IOException ignored) ++ { ++ } ++ return optIoSize; ++ } + } +diff --git a/server/src/main/java/com/linbit/SizeConv.java b/server/src/main/java/com/linbit/SizeConv.java +--- a/server/src/main/java/com/linbit/SizeConv.java ++++ b/server/src/main/java/com/linbit/SizeConv.java +@@ -16,6 +16,7 @@ public class SizeConv + public enum SizeUnit + { + UNIT_B, ++ UNIT_SECTORS, + UNIT_KiB, + UNIT_MiB, + UNIT_GiB, +@@ -41,6 +42,9 @@ public class SizeConv + case UNIT_B: + factor = FACTOR_B; + break; ++ case UNIT_SECTORS: ++ factor = FACTOR_SECTORS; ++ break; + case UNIT_KiB: + factor = FACTOR_KiB; + break; +@@ -111,6 +115,9 @@ public class SizeConv + case "b": + unit = SizeUnit.UNIT_B; + break; ++ case "s": ++ unit = SizeUnit.UNIT_SECTORS; ++ break; + case "k": + // fall-through + case "kb": +@@ -217,6 +224,9 @@ public class SizeConv + // Factor 1 + public static final BigInteger FACTOR_B = BigInteger.valueOf(1L); + ++ // Factor 512 ++ public static final BigInteger FACTOR_SECTORS = BigInteger.valueOf(512L); ++ + // Factor 1,024 + // Naming convention exception: SI unit capitalization rules + @SuppressWarnings("checkstyle:constantname") +diff --git a/server/src/main/java/com/linbit/linstor/layer/luks/LuksLayerSizeCalculator.java b/server/src/main/java/com/linbit/linstor/layer/luks/LuksLayerSizeCalculator.java +--- a/server/src/main/java/com/linbit/linstor/layer/luks/LuksLayerSizeCalculator.java ++++ b/server/src/main/java/com/linbit/linstor/layer/luks/LuksLayerSizeCalculator.java +@@ -1,27 +1,62 @@ + package com.linbit.linstor.layer.luks; + ++import com.linbit.SizeConv; ++import com.linbit.SizeConv.SizeUnit; + import com.linbit.exceptions.InvalidSizeException; ++import com.linbit.linstor.PriorityProps; ++import com.linbit.linstor.annotation.Nullable; ++import com.linbit.linstor.api.ApiConsts; ++import com.linbit.linstor.core.objects.AbsResource; ++import com.linbit.linstor.core.objects.AbsVolume; ++import com.linbit.linstor.core.objects.Resource; ++import com.linbit.linstor.core.objects.ResourceDefinition; ++import com.linbit.linstor.core.objects.ResourceGroup; ++import com.linbit.linstor.core.objects.Snapshot; ++import com.linbit.linstor.core.objects.SnapshotVolume; ++import com.linbit.linstor.core.objects.StorPool; ++import com.linbit.linstor.core.objects.Volume; ++import com.linbit.linstor.core.objects.VolumeDefinition; + import com.linbit.linstor.dbdrivers.DatabaseException; + import com.linbit.linstor.layer.AbsLayerSizeCalculator; ++import com.linbit.linstor.netcom.Peer; ++import com.linbit.linstor.propscon.InvalidKeyException; ++import com.linbit.linstor.propscon.ReadOnlyProps; + import com.linbit.linstor.security.AccessDeniedException; ++import com.linbit.linstor.storage.StorageConstants; + import com.linbit.linstor.storage.data.adapter.luks.LuksVlmData; + import com.linbit.linstor.storage.interfaces.categories.resource.VlmProviderObject; + import com.linbit.linstor.storage.kinds.DeviceLayerKind; + import com.linbit.linstor.storage.kinds.ExtTools; + import com.linbit.linstor.storage.kinds.ExtToolsInfo; + import com.linbit.linstor.storage.kinds.ExtToolsInfo.Version; ++import com.linbit.linstor.utils.layer.LayerVlmUtils; ++import com.linbit.utils.ShellUtils; ++import com.linbit.utils.SignedAlign; + + import javax.inject.Inject; + import javax.inject.Singleton; + ++import java.util.Iterator; ++import java.util.LinkedList; ++import java.util.List; ++import java.util.Set; ++import java.util.regex.Matcher; ++import java.util.regex.Pattern; ++ + @Singleton + public class LuksLayerSizeCalculator extends AbsLayerSizeCalculator> + { ++ public static final String LUKS2_OPT_METADATA_SIZE = "--luks2-metadata-size"; ++ public static final String LUKS2_OPT_KEYSLOTS_SIZE = "--luks2-keyslots-size"; ++ public static final String LUKS2_OPT_OFFSET = "--offset"; ++ private static final String LUKS2_OPT_ALIGN_PAYLOAD = "--align-payload"; ++ private static final long DFLT_LUKS2_METADATA_SIZE_IN_BYTES = 16L << 10; ++ private static final long DFLT_ALIGNMENT_1MIB_IN_BYTES = 1L << 20; ++ private static final long LUKS1_HEADER_SIZE_IN_KIB = 2L << 10; ++ private static final long LUKS2_HEADER_SIZE_IN_KIB = 16L << 10; ++ private static final long LUKS2_HEADER_SIZE_IN_BYTES = LUKS2_HEADER_SIZE_IN_KIB << 10; + +- // linstor calculates in KiB +- private static final int MIB = 1024; +- private static final int LUKS1_HEADER_SIZE = 2 * MIB; +- private static final int LUKS2_HEADER_SIZE = 16 * MIB; ++ private static final Pattern PATTERN_SIZE = Pattern.compile("(\\d+)([kKmMgGtT]i?[bB]?|[sS]|)"); + + @Inject + public LuksLayerSizeCalculator(AbsLayerSizeCalculatorInit initRef) +@@ -74,30 +109,266 @@ public class LuksLayerSizeCalculator extends AbsLayerSizeCalculator vlmDataRef) +- throws AccessDeniedException ++ throws AccessDeniedException, InvalidSizeException + { +- ExtToolsInfo cryptSetupInfo = vlmDataRef.getRscLayerObject() ++ @Nullable Peer peer = vlmDataRef.getRscLayerObject() + .getAbsResource() + .getNode() +- .getPeer(sysCtx) +- .getExtToolsManager() ++ .getPeer(sysCtx); ++ if (peer == null) ++ { ++ throw new InvalidSizeException( ++ "Could not calculate size of LUKS volume, since cryptsetup's version could not be determined", ++ null ++ ); ++ } ++ ExtToolsInfo cryptSetupInfo = peer.getExtToolsManager() + .getExtToolInfo(ExtTools.CRYPT_SETUP); +- long luksHeaderSize; ++ ++ final long luksHeaderSize; + if (cryptSetupInfo != null && cryptSetupInfo.isSupported()) + { + if (cryptSetupInfo.hasVersionOrHigher(new Version(2, 1))) + { +- luksHeaderSize = LUKS2_HEADER_SIZE; ++ luksHeaderSize = calcLuks2HeaderSize(vlmDataRef); + } + else + { +- luksHeaderSize = LUKS1_HEADER_SIZE; ++ luksHeaderSize = LUKS1_HEADER_SIZE_IN_KIB; + } + } + else + { +- luksHeaderSize = -1; ++ throw new InvalidSizeException( ++ "Could not calculate size of LUKS volume, since cryptsetup's version could not be determined", ++ null ++ ); + } + return luksHeaderSize; + } ++ ++ private long calcLuks2HeaderSize(VlmProviderObject vlmDataRef) throws AccessDeniedException ++ { ++ PriorityProps prioProps = getPrioProps(vlmDataRef); ++ ++ final @Nullable String userOptProp = prioProps.getProp( ++ ApiConsts.KEY_STOR_DRIVER_LUKS_FORMAT_OPTIONS, ++ ApiConsts.NAMESPC_STORAGE_DRIVER ++ ); ++ List userOptions = userOptProp != null ? ++ ShellUtils.shellSplit(userOptProp) : ++ new LinkedList<>(); ++ ++ final long alignedHeaderSizeInBytes; ++ final long unalignedHeaderSizeInBytes; ++ @Nullable Long cryptsetupOffsetInBytes = getLongOptionValue( ++ userOptions, ++ LUKS2_OPT_OFFSET, ++ SizeUnit.UNIT_SECTORS ++ ); ++ if (cryptsetupOffsetInBytes != null) ++ { ++ alignedHeaderSizeInBytes = cryptsetupOffsetInBytes; ++ } ++ else ++ { ++ @Nullable Long cryptsetupLuks2KeyslotsSize = getLongOptionValue( ++ userOptions, ++ LUKS2_OPT_KEYSLOTS_SIZE ++ ); ++ if (cryptsetupLuks2KeyslotsSize == null) ++ { ++ unalignedHeaderSizeInBytes = LUKS2_HEADER_SIZE_IN_BYTES; ++ } ++ else ++ { ++ @Nullable Long cryptsetupLuks2MetadataSize = getLongOptionValue( ++ userOptions, ++ LUKS2_OPT_METADATA_SIZE ++ ); ++ cryptsetupLuks2MetadataSize = cryptsetupLuks2MetadataSize == null ? ++ DFLT_LUKS2_METADATA_SIZE_IN_BYTES : ++ cryptsetupLuks2MetadataSize; ++ ++ unalignedHeaderSizeInBytes = 2 * cryptsetupLuks2MetadataSize + cryptsetupLuks2KeyslotsSize; ++ } ++ ++ long alignment = getAlignment(vlmDataRef, userOptions); ++ alignedHeaderSizeInBytes = new SignedAlign(alignment).ceiling(unalignedHeaderSizeInBytes); ++ } ++ return SizeConv.convert( ++ alignedHeaderSizeInBytes, ++ SizeUnit.UNIT_B, ++ SizeUnit.UNIT_KiB ++ ); ++ } ++ ++ private long getAlignment(VlmProviderObject vlmDataRef, List userOptions) throws AccessDeniedException ++ { ++ @Nullable Long cryptsetupAlignPayloadInBytes = getLongOptionValue( ++ userOptions, ++ LUKS2_OPT_ALIGN_PAYLOAD, ++ SizeUnit.UNIT_SECTORS ++ ); ++ ++ long alignment = DFLT_ALIGNMENT_1MIB_IN_BYTES; ++ if (cryptsetupAlignPayloadInBytes != null) ++ { ++ alignment = cryptsetupAlignPayloadInBytes; ++ } ++ else ++ { ++ final long maxOptIoSize = getMaxOptIoSize(vlmDataRef); ++ alignment = Math.max(alignment, maxOptIoSize); ++ } ++ return alignment; ++ } ++ ++ private long getMaxOptIoSize(VlmProviderObject vlmDataRef) throws InvalidKeyException, AccessDeniedException ++ { ++ long ret = 0; ++ Set storPoolSet = LayerVlmUtils.getStorPoolSet(vlmDataRef, sysCtx); ++ for (StorPool sp : storPoolSet) ++ { ++ @Nullable String strValue = sp.getProps(sysCtx) ++ .getProp( ++ StorageConstants.BLK_DEV_OPT_IO_SIZE, ++ StorageConstants.NAMESPACE_INTERNAL ++ ); ++ if (strValue != null) ++ { ++ try ++ { ++ long parsed = Long.parseLong(strValue); ++ ret = Math.max(parsed, ret); ++ } ++ catch (NumberFormatException ignored) ++ { ++ errorReporter.logWarning( ++ "LuksHeaderSize: Failed to parse '%s' from prop %s. Defaulting to 0 opt_io_size " + ++ "(no recommendation/hint)", ++ strValue, ++ StorageConstants.NAMESPACE_INTERNAL + "/" + StorageConstants.BLK_DEV_OPT_IO_SIZE ++ ); ++ } ++ } ++ } ++ return ret; ++ } ++ ++ private @Nullable Long getLongOptionValue(List userOptionsRef, String optRef) ++ { ++ return getLongOptionValue(userOptionsRef, optRef, SizeUnit.UNIT_B); ++ } ++ ++ @SuppressWarnings("checkstyle:magicnumber") ++ private @Nullable Long getLongOptionValue(List userOptionsRef, String optRef, SizeUnit dfltSizeUnit) ++ { ++ @Nullable Long ret = null; ++ @Nullable String val = findLastValue(userOptionsRef, optRef); ++ if (val != null && !val.isBlank()) ++ { ++ Matcher matcher = PATTERN_SIZE.matcher(val); ++ if (matcher.matches()) ++ { ++ try ++ { ++ ret = Long.parseLong(matcher.group(1)); ++ String unit = matcher.group(2); ++ SizeUnit sizeUnit; ++ if (unit.isBlank()) ++ { ++ sizeUnit = dfltSizeUnit; ++ } ++ else ++ { ++ boolean forcePowerOfTwo = unit.length() == 1 || unit.length() == 3; ++ sizeUnit = SizeUnit.parse(unit, forcePowerOfTwo); ++ } ++ ++ ret = SizeConv.convert(ret, sizeUnit, SizeUnit.UNIT_B); ++ } ++ catch (NumberFormatException ignored) ++ { ++ errorReporter.logWarning( ++ "LuksHeaderSize: Failed to parse '%s' from option '%s %s'.", ++ matcher.group(1), ++ optRef, ++ val ++ ); ++ } ++ } ++ } ++ return ret; ++ } ++ ++ private @Nullable String findLastValue(List userOptionsRef, String optRef) ++ { ++ Iterator it = userOptionsRef.iterator(); ++ @Nullable String val = null; ++ while (it.hasNext()) ++ { ++ String opt = it.next(); ++ if (opt.equals(optRef)) ++ { ++ if (it.hasNext()) ++ { ++ val = it.next(); ++ } ++ else ++ { ++ val = null; ++ } ++ } ++ else if (opt.startsWith(optRef + "=")) ++ { ++ val = opt.substring(optRef.length() + 1); ++ if (val.isBlank()) ++ { ++ val = null; ++ } ++ } ++ } ++ return val; ++ } ++ ++ private PriorityProps getPrioProps(VlmProviderObject vlmDataRef) throws AccessDeniedException ++ { ++ final AbsVolume vlm = vlmDataRef.getVolume(); ++ final AbsResource rsc = vlm.getAbsResource(); ++ final ResourceDefinition rscDfn = vlm.getResourceDefinition(); ++ final VolumeDefinition vlmDfn = vlm.getVolumeDefinition(); ++ final ResourceGroup rscGrp = rscDfn.getResourceGroup(); ++ ++ final ReadOnlyProps vlmProps; ++ final ReadOnlyProps rscProps; ++ if (vlm instanceof Volume) ++ { ++ vlmProps = ((Volume) vlm).getProps(sysCtx); ++ rscProps = ((Resource) rsc).getProps(sysCtx); ++ } ++ else ++ { ++ vlmProps = ((SnapshotVolume) vlm).getVlmProps(sysCtx); ++ rscProps = ((Snapshot) rsc).getRscProps(sysCtx); ++ } ++ ++ final PriorityProps prioProps = new PriorityProps( ++ vlmProps, ++ rscProps ++ ); ++ for (StorPool storPool : LayerVlmUtils.getStorPoolSet(vlmDataRef, sysCtx)) ++ { ++ prioProps.addProps(storPool.getProps(sysCtx)); ++ } ++ prioProps.addProps( ++ rsc.getNode().getProps(sysCtx), ++ vlmDfn.getProps(sysCtx), ++ rscDfn.getProps(sysCtx), ++ rscGrp.getVolumeGroupProps(sysCtx, vlmDfn.getVolumeNumber()), ++ rscGrp.getProps(sysCtx), ++ stltProps ++ ); ++ return prioProps; ++ } + } +diff --git a/server/src/main/java/com/linbit/linstor/layer/storage/BlockSizeConsts.java b/server/src/main/java/com/linbit/linstor/layer/storage/BlockSizeConsts.java +--- a/server/src/main/java/com/linbit/linstor/layer/storage/BlockSizeConsts.java ++++ b/server/src/main/java/com/linbit/linstor/layer/storage/BlockSizeConsts.java +@@ -13,4 +13,9 @@ public class BlockSizeConsts + + // Default value for the minimum_io_size value of non-storage layers + public static final long DFLT_SPECIAL_IO_SIZE = (1L << 12); ++ ++ // optimal_io_size may be 0 to indicate no recommendation. ++ public static final long MIN_OPT_IO_SIZE = 0; ++ public static final long DFLT_OPT_IO_SIZE = 0; ++ public static final long MAX_OPT_IO_SIZE = Long.MAX_VALUE; + } +diff --git a/server/src/main/java/com/linbit/linstor/storage/StorageConstants.java b/server/src/main/java/com/linbit/linstor/storage/StorageConstants.java +--- a/server/src/main/java/com/linbit/linstor/storage/StorageConstants.java ++++ b/server/src/main/java/com/linbit/linstor/storage/StorageConstants.java +@@ -11,6 +11,7 @@ public class StorageConstants + public static final String NAMESPACE_NVME = ApiConsts.NAMESPC_STORAGE_DRIVER + "/NVME"; + public static final String NAMESPACE_INTERNAL = NAMESPACE_STOR_DRIVER + "/internal/"; + ++ public static final String BLK_DEV_OPT_IO_SIZE = "optIoSize"; + public static final String BLK_DEV_MIN_IO_SIZE = "minIoSize"; + public static final String BLK_DEV_MIN_IO_SIZE_AUTO = "minIoSizeAuto"; + public static final String BLK_DEV_MAX_BIO_SIZE = "maxBioSize"; diff --git a/packages/system/linstor/images/piraeus-server/patches/retry-adjust-after-stale-bitmap.diff b/packages/system/linstor/images/piraeus-server/patches/retry-adjust-after-stale-bitmap.diff new file mode 100644 index 00000000..00959167 --- /dev/null +++ b/packages/system/linstor/images/piraeus-server/patches/retry-adjust-after-stale-bitmap.diff @@ -0,0 +1,141 @@ +diff --git a/satellite/src/main/java/com/linbit/linstor/layer/drbd/utils/DrbdAdm.java b/satellite/src/main/java/com/linbit/linstor/layer/drbd/utils/DrbdAdm.java +index 5627d1be8..ece191292 100644 +--- a/satellite/src/main/java/com/linbit/linstor/layer/drbd/utils/DrbdAdm.java ++++ b/satellite/src/main/java/com/linbit/linstor/layer/drbd/utils/DrbdAdm.java +@@ -42,6 +42,9 @@ import java.util.Arrays; + import java.util.List; + import java.util.concurrent.ArrayBlockingQueue; + import java.util.concurrent.TimeUnit; ++import java.nio.charset.StandardCharsets; ++import java.util.regex.Matcher; ++import java.util.regex.Pattern; + import java.util.stream.Collectors; + + @Singleton +@@ -56,6 +58,9 @@ public class DrbdAdm + + public static final int WAIT_CONNECT_RES_TIME = 10; + private static final long DOWN_WAIT_TIMEOUT_SEC = 5; ++ private static final long FORCE_DETACH_RETRY_WAIT_MS = 250; ++ private static final String BITMAP_LEAK_ERR_MSG = "already has a bitmap, this should not happen"; ++ private static final Pattern BITMAP_LEAK_MINOR_PATTERN = Pattern.compile("\\bminor\\s+(\\d+)\\b"); + + private final ExtCmdFactory extCmdFactory; + private final AccessContext sysCtx; +@@ -131,8 +136,38 @@ public class DrbdAdm + // command.add(resName); + command.add(drbdRscData.getSuffixedResourceName()); + // execute(Arrays.asList("drbdsetup", "show", drbdRscData.getSuffixedResourceName())); +- execute(command); +- // execute(Arrays.asList("drbdsetup", "show", drbdRscData.getSuffixedResourceName())); ++ String[] commandArr = command.toArray(new String[0]); ++ try ++ { ++ File nullDevice = new File(Platform.nullDevice()); ++ ExtCmd extCmd = extCmdFactory.create(); ++ if (Platform.isWindows()) ++ { ++ extCmd.setTimeout(TimeoutType.WAIT, 5 * 60 * 1000); ++ } ++ ++ OutputData outputData = extCmd.pipeExec(ProcessBuilder.Redirect.from(nullDevice), commandArr); ++ if ( ++ outputData.exitCode != 0 && ++ isBitmapLeakOnAttach(outputData) && ++ cleanupStaleBitmapAndRetry(extCmd, nullDevice, outputData) ++ ) ++ { ++ outputData = extCmd.pipeExec(ProcessBuilder.Redirect.from(nullDevice), commandArr); ++ } ++ if (outputData.exitCode != 0) ++ { ++ throw new ExtCmdFailedException(commandArr, outputData); ++ } ++ } ++ catch (ChildProcessTimeoutException timeoutExc) ++ { ++ throw new ExtCmdFailedException(commandArr, timeoutExc); ++ } ++ catch (IOException ioExc) ++ { ++ throw new ExtCmdFailedException(commandArr, ioExc); ++ } + + drbdRscData.setAdjustRequired(false); + } +@@ -805,6 +840,75 @@ public class DrbdAdm + } + } + ++ static boolean isBitmapLeakOnAttach(OutputData outputData) ++ { ++ return extractBitmapLeakMinor(outputData) != null; ++ } ++ ++ static @Nullable Integer extractBitmapLeakMinor(OutputData outputData) ++ { ++ String stderr = new String(outputData.stderrData, StandardCharsets.UTF_8); ++ if (!stderr.contains(BITMAP_LEAK_ERR_MSG)) ++ { ++ return null; ++ } ++ ++ Matcher matcher = BITMAP_LEAK_MINOR_PATTERN.matcher(stderr); ++ if (!matcher.find()) ++ { ++ return null; ++ } ++ ++ return Integer.parseInt(matcher.group(1)); ++ } ++ ++ private boolean cleanupStaleBitmapAndRetry( ++ ExtCmd extCmd, ++ File nullDevice, ++ OutputData outputData ++ ) ++ throws IOException, ChildProcessTimeoutException, ExtCmdFailedException ++ { ++ @Nullable Integer minor = extractBitmapLeakMinor(outputData); ++ if (minor == null) ++ { ++ return false; ++ } ++ ++ OutputData detachOut = extCmd.pipeExec( ++ ProcessBuilder.Redirect.from(nullDevice), ++ DRBDSETUP_UTIL, ++ "detach", ++ Integer.toString(minor) ++ ); ++ if (detachOut.exitCode == 0) ++ { ++ return true; ++ } ++ ++ OutputData forceDetachOut = extCmd.pipeExec( ++ ProcessBuilder.Redirect.from(nullDevice), ++ DRBDSETUP_UTIL, ++ "detach", ++ Integer.toString(minor), ++ "--force" ++ ); ++ if (forceDetachOut.exitCode != 0) ++ { ++ throw new ExtCmdFailedException(forceDetachOut.executedCommand, forceDetachOut); ++ } ++ ++ try ++ { ++ Thread.sleep(FORCE_DETACH_RETRY_WAIT_MS); ++ } ++ catch (InterruptedException ignored) ++ { ++ Thread.currentThread().interrupt(); ++ } ++ return true; ++ } ++ + public static class DrbdPrimary implements AutoCloseable + { + private final DrbdAdm drbdAdm; diff --git a/packages/system/linstor/templates/_helpers.tpl b/packages/system/linstor/templates/_helpers.tpl deleted file mode 100644 index 20d43863..00000000 --- a/packages/system/linstor/templates/_helpers.tpl +++ /dev/null @@ -1,24 +0,0 @@ -{{- define "cozy.linstor.version" -}} -{{- $piraeusConfigMap := lookup "v1" "ConfigMap" "cozy-linstor" "piraeus-operator-image-config"}} -{{- if not $piraeusConfigMap }} - {{- fail "Piraeus controller is not yet installed, ConfigMap cozy-linstor/piraeus-operator-image-config is missing" }} -{{- end }} -{{- $piraeusImagesConfig := $piraeusConfigMap | dig "data" "0_piraeus_datastore_images.yaml" nil | required "No image config" | fromYaml }} -base: {{ $piraeusImagesConfig.base | required "No image base in piraeus config" }} -controller: - image: {{ $piraeusImagesConfig | dig "components" "linstor-controller" "image" nil | required "No controller image" }} - tag: {{ $piraeusImagesConfig | dig "components" "linstor-controller" "tag" nil | required "No controller tag" }} -satellite: - image: {{ $piraeusImagesConfig | dig "components" "linstor-satellite" "image" nil | required "No satellite image" }} - tag: {{ $piraeusImagesConfig | dig "components" "linstor-satellite" "tag" nil | required "No satellite tag" }} -{{- end -}} - -{{- define "cozy.linstor.version.controller" -}} -{{- $version := (include "cozy.linstor.version" .) | fromYaml }} -{{- printf "%s/%s:%s" $version.base $version.controller.image $version.controller.tag }} -{{- end -}} - -{{- define "cozy.linstor.version.satellite" -}} -{{- $version := (include "cozy.linstor.version" .) | fromYaml }} -{{- printf "%s/%s:%s" $version.base $version.satellite.image $version.satellite.tag }} -{{- end -}} diff --git a/packages/system/linstor/templates/cluster.yaml b/packages/system/linstor/templates/cluster.yaml index 68af90fd..e45b1dff 100644 --- a/packages/system/linstor/templates/cluster.yaml +++ b/packages/system/linstor/templates/cluster.yaml @@ -14,6 +14,14 @@ spec: name: linstor-api-ca kind: Issuer properties: + {{- if .Values.linstor.autoDiskful.enabled }} + - name: DrbdOptions/auto-diskful + value: {{ .Values.linstor.autoDiskful.minutes | quote }} + - name: DrbdOptions/auto-diskful-allow-cleanup + value: {{ .Values.linstor.autoDiskful.allowCleanup | quote }} + {{- end }} + - name: DrbdOptions/Net/verify-alg + value: "crc32c" - name: DrbdOptions/Net/connect-int value: "15" - name: DrbdOptions/Net/ping-int @@ -27,8 +35,10 @@ spec: podTemplate: spec: containers: + - name: linstor-controller + image: {{ .Values.piraeusServer.image.repository }}:{{ .Values.piraeusServer.image.tag }} - name: plunger - image: {{ include "cozy.linstor.version.controller" . }} + image: {{ .Values.piraeusServer.image.repository }}:{{ .Values.piraeusServer.image.tag }} command: - "/scripts/plunger-controller.sh" securityContext: @@ -52,6 +62,24 @@ spec: configMap: name: linstor-plunger defaultMode: 0755 + csiController: + podTemplate: + spec: + initContainers: + - name: linstor-wait-api-online + image: {{ .Values.linstorCSI.image.repository }}:{{ .Values.linstorCSI.image.tag }} + containers: + - name: linstor-csi + image: {{ .Values.linstorCSI.image.repository }}:{{ .Values.linstorCSI.image.tag }} + csiNode: + podTemplate: + spec: + initContainers: + - name: linstor-wait-node-online + image: {{ .Values.linstorCSI.image.repository }}:{{ .Values.linstorCSI.image.tag }} + containers: + - name: linstor-csi + image: {{ .Values.linstorCSI.image.repository }}:{{ .Values.linstorCSI.image.tag }} patches: - target: kind: Deployment diff --git a/packages/system/linstor/templates/linstor-api-tls.yaml b/packages/system/linstor/templates/linstor-api-tls.yaml index eeda9731..055e6d08 100644 --- a/packages/system/linstor/templates/linstor-api-tls.yaml +++ b/packages/system/linstor/templates/linstor-api-tls.yaml @@ -9,6 +9,8 @@ spec: secretName: linstor-api-ca duration: 87600h # 10 years isCA: true + privateKey: + rotationPolicy: Never usages: - signing - key encipherment diff --git a/packages/system/linstor/templates/linstor-internal-tls.yaml b/packages/system/linstor/templates/linstor-internal-tls.yaml index 5d536625..fe5ff4b1 100644 --- a/packages/system/linstor/templates/linstor-internal-tls.yaml +++ b/packages/system/linstor/templates/linstor-internal-tls.yaml @@ -9,6 +9,8 @@ spec: secretName: linstor-internal-ca duration: 87600h # 10 years isCA: true + privateKey: + rotationPolicy: Never usages: - signing - key encipherment diff --git a/packages/system/linstor/templates/podscrape.yaml b/packages/system/linstor/templates/podscrape.yaml index 9c334527..05b1483e 100644 --- a/packages/system/linstor/templates/podscrape.yaml +++ b/packages/system/linstor/templates/podscrape.yaml @@ -11,7 +11,7 @@ spec: relabelConfigs: - action: labeldrop regex: (endpoint|namespace|pod|container) - - replacement: linstor-controller + - replacement: linstor-satellite targetLabel: job - sourceLabels: [__meta_kubernetes_pod_node_name] targetLabel: node @@ -34,10 +34,10 @@ spec: relabelConfigs: - action: labeldrop regex: (endpoint|namespace|pod|container) - - replacement: linstor-satellite + - replacement: linstor-controller targetLabel: job - sourceLabels: [__meta_kubernetes_pod_node_name] - targetLabel: node + targetLabel: controller_node - targetLabel: tier replacement: cluster selector: diff --git a/packages/system/linstor/templates/satellites-cozy.yaml b/packages/system/linstor/templates/satellites-cozy.yaml index a4c1baa7..e6f877a0 100644 --- a/packages/system/linstor/templates/satellites-cozy.yaml +++ b/packages/system/linstor/templates/satellites-cozy.yaml @@ -13,6 +13,12 @@ spec: hostNetwork: true containers: - name: linstor-satellite + image: {{ .Values.piraeusServer.image.repository }}:{{ .Values.piraeusServer.image.tag }} + startupProbe: + tcpSocket: + port: linstor + periodSeconds: 10 + failureThreshold: 30 securityContext: # real-world installations need some debugging from time to time readOnlyRootFilesystem: false diff --git a/packages/system/linstor/templates/satellites-plunger.yaml b/packages/system/linstor/templates/satellites-plunger.yaml index e3cfa3b1..ab71298b 100644 --- a/packages/system/linstor/templates/satellites-plunger.yaml +++ b/packages/system/linstor/templates/satellites-plunger.yaml @@ -11,7 +11,7 @@ spec: spec: containers: - name: plunger - image: {{ include "cozy.linstor.version.satellite" . }} + image: {{ .Values.piraeusServer.image.repository }}:{{ .Values.piraeusServer.image.tag }} command: - "/scripts/plunger-satellite.sh" securityContext: @@ -48,7 +48,7 @@ spec: name: script-volume readOnly: true - name: drbd-logger - image: {{ include "cozy.linstor.version.satellite" . }} + image: {{ .Values.piraeusServer.image.repository }}:{{ .Values.piraeusServer.image.tag }} command: - "/scripts/plunger-drbd-logger.sh" securityContext: diff --git a/packages/system/linstor/templates/satellites-talos.yaml b/packages/system/linstor/templates/satellites-talos.yaml index c5be9204..21da32a6 100644 --- a/packages/system/linstor/templates/satellites-talos.yaml +++ b/packages/system/linstor/templates/satellites-talos.yaml @@ -1,3 +1,4 @@ +{{- if .Values.talos.enabled }} apiVersion: piraeus.io/v1 kind: LinstorSatelliteConfiguration metadata: @@ -41,3 +42,4 @@ spec: hostPath: path: /var/etc/lvm/archive type: DirectoryOrCreate +{{- end }} diff --git a/packages/system/linstor/values.yaml b/packages/system/linstor/values.yaml index 8b137891..62dd2cac 100644 --- a/packages/system/linstor/values.yaml +++ b/packages/system/linstor/values.yaml @@ -1 +1,16 @@ - +piraeusServer: + image: + repository: ghcr.io/cozystack/cozystack/piraeus-server + tag: 1.33.2@sha256:553f313ab35dc2e345ef3683156d29e75c23177e2750e9af3a83aa9e23941cbb +# Talos-specific workarounds (disable for generic Linux like Ubuntu/Debian) +talos: + enabled: true +linstor: + autoDiskful: + enabled: true + minutes: 30 + allowCleanup: true +linstorCSI: + image: + repository: ghcr.io/cozystack/cozystack/linstor-csi + tag: v1.10.5@sha256:b8f59b5659fb1791cb764d3f37df4cf29920aadcc10637231ba7d857233f377d diff --git a/packages/system/local-ccm/.helmignore b/packages/system/local-ccm/.helmignore new file mode 100644 index 00000000..1e107f52 --- /dev/null +++ b/packages/system/local-ccm/.helmignore @@ -0,0 +1 @@ +examples diff --git a/packages/system/local-ccm/Chart.yaml b/packages/system/local-ccm/Chart.yaml new file mode 100644 index 00000000..1ca0527b --- /dev/null +++ b/packages/system/local-ccm/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-local-ccm +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/local-ccm/Makefile b/packages/system/local-ccm/Makefile new file mode 100644 index 00000000..aff6386e --- /dev/null +++ b/packages/system/local-ccm/Makefile @@ -0,0 +1,15 @@ +export NAME=local-ccm +export NAMESPACE=cozy-$(NAME) + +include ../../../hack/package.mk + +update: + rm -rf charts + tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/cozystack/local-ccm | awk -F'[/^]' 'END{print $$3}') && \ + if [ -z "$$tag" ]; then \ + curl -sSL https://github.com/cozystack/local-ccm/archive/refs/heads/main.tar.gz | \ + tar xzvf - --strip 1 local-ccm-main/charts; \ + else \ + curl -sSL https://github.com/cozystack/local-ccm/archive/refs/tags/$${tag}.tar.gz | \ + tar xzvf - --strip 1 local-ccm-$${tag#*v}/charts; \ + fi diff --git a/packages/system/local-ccm/charts/local-ccm/.helmignore b/packages/system/local-ccm/charts/local-ccm/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/packages/system/local-ccm/charts/local-ccm/.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/system/local-ccm/charts/local-ccm/Chart.yaml b/packages/system/local-ccm/charts/local-ccm/Chart.yaml new file mode 100644 index 00000000..ef68023d --- /dev/null +++ b/packages/system/local-ccm/charts/local-ccm/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +name: local-ccm +description: Local Cloud Controller Manager for Kubernetes - detects and manages node IP addresses +type: application +version: 0.1.0 +appVersion: "0.1.0" +keywords: + - kubernetes + - cloud-controller-manager + - ccm + - node-controller +home: https://github.com/cozystack/local-ccm +sources: + - https://github.com/cozystack/local-ccm +maintainers: + - name: Andrei Kvapil + email: kvapss@gmail.com diff --git a/packages/system/local-ccm/charts/local-ccm/README.md b/packages/system/local-ccm/charts/local-ccm/README.md new file mode 100644 index 00000000..7b9187df --- /dev/null +++ b/packages/system/local-ccm/charts/local-ccm/README.md @@ -0,0 +1,97 @@ +# local-ccm Helm Chart + +Local Cloud Controller Manager for Kubernetes - automatically detects and manages node IP addresses. + +## Features + +- Automatic node IP address detection using routing table +- Support for both internal and external IP detection +- Automatic removal of cloud provider initialization taint +- Minimal resource footprint +- Runs as DaemonSet on all nodes + +## Installation + +### Quick Start + +Install with default configuration: + +```bash +helm install local-ccm ./charts/local-ccm --namespace kube-system +``` + +### Custom Configuration + +Create a `values.yaml` file: + +```yaml +ipDetection: + externalIPTarget: "1.1.1.1" + internalIPTarget: "10.0.0.1" + +controller: + verbosity: 3 +``` + +Install with custom values: + +```bash +helm install local-ccm ./charts/local-ccm \ + --namespace kube-system \ + --values values.yaml +``` + +### Inline Configuration + +```bash +helm install local-ccm ./charts/local-ccm \ + --namespace kube-system \ + --set ipDetection.externalIPTarget=1.1.1.1 \ + --set ipDetection.internalIPTarget=10.0.0.1 +``` + +## Configuration + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `image.repository` | Container image repository | `ghcr.io/cozystack/local-ccm` | +| `image.tag` | Container image tag | `v0.1.0` | +| `image.pullPolicy` | Image pull policy | `Always` | +| `serviceAccount.create` | Create service account | `true` | +| `serviceAccount.name` | Service account name | `local-ccm` | +| `ipDetection.externalIPTarget` | Target IP for external IP detection | `8.8.8.8` | +| `ipDetection.internalIPTarget` | Target IP for internal IP detection (empty = disabled) | `""` | +| `controller.removeTaint` | Remove uninitialized taint | `true` | +| `controller.reconcileInterval` | Reconciliation interval | `10s` | +| `controller.verbosity` | Log verbosity level (0-5) | `2` | +| `resources.requests.cpu` | CPU resource requests | `10m` | +| `resources.requests.memory` | Memory resource requests | `32Mi` | +| `resources.limits.cpu` | CPU resource limits | `100m` | +| `resources.limits.memory` | Memory resource limits | `64Mi` | +| `tolerations` | Pod tolerations | `[{operator: Exists}]` | +| `affinity` | Pod affinity rules | See values.yaml | +| `labels` | Additional labels for all resources | `{}` | +| `podAnnotations` | Additional pod annotations | `{}` | + +## Uninstallation + +```bash +helm uninstall local-ccm --namespace kube-system +``` + +## Upgrading + +```bash +helm upgrade local-ccm ./charts/local-ccm \ + --namespace kube-system \ + --values values.yaml +``` + +## Requirements + +- Kubernetes 1.19+ +- Helm 3.0+ + +## License + +Licensed under the Apache License, Version 2.0 diff --git a/packages/system/local-ccm/charts/local-ccm/templates/NOTES.txt b/packages/system/local-ccm/charts/local-ccm/templates/NOTES.txt new file mode 100644 index 00000000..3dd29683 --- /dev/null +++ b/packages/system/local-ccm/charts/local-ccm/templates/NOTES.txt @@ -0,0 +1,29 @@ +Thank you for installing {{ .Chart.Name }}! + +Your release is named {{ .Release.Name }}. + +The local-ccm DaemonSet has been deployed to namespace {{ .Release.Namespace }}. + +To check the status of the DaemonSet: + + kubectl --namespace {{ .Release.Namespace }} get daemonset {{ include "local-ccm.fullname" . }} + +To view the pods: + + kubectl --namespace {{ .Release.Namespace }} get pods -l "{{ include "local-ccm.selectorLabels" . | replace "\n" "," }}" + +To check logs from a specific pod: + + kubectl --namespace {{ .Release.Namespace }} logs -l app=local-ccm -c local-ccm + +Configuration: + - External IP detection target: {{ .Values.ipDetection.externalIPTarget }} + {{- if .Values.ipDetection.internalIPTarget }} + - Internal IP detection target: {{ .Values.ipDetection.internalIPTarget }} + {{- else }} + - Internal IP detection: disabled (using kubelet's InternalIP) + {{- end }} + - Remove uninitialized taint: {{ .Values.controller.removeTaint }} + - Reconcile interval: {{ .Values.controller.reconcileInterval }} + +For more information, visit: https://github.com/cozystack/local-ccm diff --git a/packages/system/local-ccm/charts/local-ccm/templates/_helpers.tpl b/packages/system/local-ccm/charts/local-ccm/templates/_helpers.tpl new file mode 100644 index 00000000..0de841f5 --- /dev/null +++ b/packages/system/local-ccm/charts/local-ccm/templates/_helpers.tpl @@ -0,0 +1,65 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "local-ccm.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "local-ccm.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "local-ccm.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "local-ccm.labels" -}} +helm.sh/chart: {{ include "local-ccm.chart" . }} +{{ include "local-ccm.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- with .Values.labels }} +{{ toYaml . }} +{{- end }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "local-ccm.selectorLabels" -}} +app.kubernetes.io/name: {{ include "local-ccm.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app: local-ccm +component: node-controller +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "local-ccm.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "local-ccm.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/packages/system/local-ccm/charts/local-ccm/templates/clusterrole.yaml b/packages/system/local-ccm/charts/local-ccm/templates/clusterrole.yaml new file mode 100644 index 00000000..d9d3dab3 --- /dev/null +++ b/packages/system/local-ccm/charts/local-ccm/templates/clusterrole.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "local-ccm.fullname" . }} + labels: + {{- include "local-ccm.labels" . | nindent 4 }} +rules: +# Permissions to get and update nodes +- apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list", "watch", "patch"] +# Permissions to update node status (for addresses) +- apiGroups: [""] + resources: ["nodes/status"] + verbs: ["patch"] diff --git a/packages/system/local-ccm/charts/local-ccm/templates/clusterrolebinding.yaml b/packages/system/local-ccm/charts/local-ccm/templates/clusterrolebinding.yaml new file mode 100644 index 00000000..0be6cc71 --- /dev/null +++ b/packages/system/local-ccm/charts/local-ccm/templates/clusterrolebinding.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "local-ccm.fullname" . }} + labels: + {{- include "local-ccm.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "local-ccm.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ include "local-ccm.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} diff --git a/packages/system/local-ccm/charts/local-ccm/templates/daemonset.yaml b/packages/system/local-ccm/charts/local-ccm/templates/daemonset.yaml new file mode 100644 index 00000000..c45afc67 --- /dev/null +++ b/packages/system/local-ccm/charts/local-ccm/templates/daemonset.yaml @@ -0,0 +1,54 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "local-ccm.fullname" . }} + labels: + {{- include "local-ccm.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "local-ccm.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "local-ccm.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "local-ccm.serviceAccountName" . }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: local-ccm + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - /usr/local/bin/local-ccm + args: + - --node-name=$(NODE_NAME) + - --external-ip-target={{ .Values.ipDetection.externalIPTarget }} + {{- if .Values.ipDetection.internalIPTarget }} + - --internal-ip-target={{ .Values.ipDetection.internalIPTarget }} + {{- end }} + - --remove-taint={{ .Values.controller.removeTaint }} + - --reconcile-interval={{ .Values.controller.reconcileInterval }} + - --v={{ .Values.controller.verbosity }} + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + securityContext: + {{- toYaml .Values.securityContext | nindent 10 }} + resources: + {{- toYaml .Values.resources | nindent 10 }} diff --git a/packages/system/local-ccm/charts/local-ccm/templates/nlc-clusterrole.yaml b/packages/system/local-ccm/charts/local-ccm/templates/nlc-clusterrole.yaml new file mode 100644 index 00000000..9661261d --- /dev/null +++ b/packages/system/local-ccm/charts/local-ccm/templates/nlc-clusterrole.yaml @@ -0,0 +1,22 @@ +{{- if .Values.nodeLifecycleController.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "local-ccm.fullname" . }}-nlc + labels: + {{- include "local-ccm.labels" . | nindent 4 }} + app.kubernetes.io/component: node-lifecycle-controller +rules: +# Node management +- apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list", "watch", "delete"] +# Events for recording actions +- apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] +# Leader election +- apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "create", "update"] +{{- end }} diff --git a/packages/system/local-ccm/charts/local-ccm/templates/nlc-clusterrolebinding.yaml b/packages/system/local-ccm/charts/local-ccm/templates/nlc-clusterrolebinding.yaml new file mode 100644 index 00000000..82194f81 --- /dev/null +++ b/packages/system/local-ccm/charts/local-ccm/templates/nlc-clusterrolebinding.yaml @@ -0,0 +1,17 @@ +{{- if .Values.nodeLifecycleController.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "local-ccm.fullname" . }}-nlc + labels: + {{- include "local-ccm.labels" . | nindent 4 }} + app.kubernetes.io/component: node-lifecycle-controller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "local-ccm.fullname" . }}-nlc +subjects: +- kind: ServiceAccount + name: {{ include "local-ccm.fullname" . }}-nlc + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/packages/system/local-ccm/charts/local-ccm/templates/nlc-deployment.yaml b/packages/system/local-ccm/charts/local-ccm/templates/nlc-deployment.yaml new file mode 100644 index 00000000..ea154d3d --- /dev/null +++ b/packages/system/local-ccm/charts/local-ccm/templates/nlc-deployment.yaml @@ -0,0 +1,78 @@ +{{- if .Values.nodeLifecycleController.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "local-ccm.fullname" . }}-nlc + labels: + {{- include "local-ccm.labels" . | nindent 4 }} + app.kubernetes.io/component: node-lifecycle-controller +spec: + replicas: {{ .Values.nodeLifecycleController.replicaCount }} + selector: + matchLabels: + {{- include "local-ccm.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: node-lifecycle-controller + template: + metadata: + labels: + {{- include "local-ccm.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: node-lifecycle-controller + {{- with .Values.nodeLifecycleController.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "local-ccm.fullname" . }}-nlc + {{- if .Values.nodeLifecycleController.hostNetwork }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + {{- end }} + {{- with .Values.nodeLifecycleController.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeLifecycleController.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeLifecycleController.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeLifecycleController.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: node-lifecycle-controller + image: "{{ .Values.nodeLifecycleController.image.repository }}:{{ .Values.nodeLifecycleController.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.nodeLifecycleController.image.pullPolicy }} + command: + - /usr/local/bin/node-lifecycle-controller + args: + - --watch-autoscaler-taint={{ .Values.nodeLifecycleController.controller.watchAutoscalerTaint }} + {{- if .Values.nodeLifecycleController.controller.nodeSelector }} + - --node-selector={{ .Values.nodeLifecycleController.controller.nodeSelector }} + {{- end }} + {{- if .Values.nodeLifecycleController.controller.protectedLabels }} + - --protected-labels={{ .Values.nodeLifecycleController.controller.protectedLabels }} + {{- end }} + - --not-ready-timeout={{ .Values.nodeLifecycleController.controller.notReadyTimeout }} + - --ping-timeout={{ .Values.nodeLifecycleController.controller.pingTimeout }} + - --ping-count={{ .Values.nodeLifecycleController.controller.pingCount }} + - --reconcile-interval={{ .Values.nodeLifecycleController.controller.reconcileInterval }} + - --leader-elect={{ .Values.nodeLifecycleController.leaderElection.enabled }} + - --leader-elect-id={{ .Values.nodeLifecycleController.leaderElection.resourceName }} + - --namespace=$(POD_NAMESPACE) + - --dry-run={{ .Values.nodeLifecycleController.controller.dryRun }} + - --v={{ .Values.nodeLifecycleController.controller.verbosity }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + securityContext: + {{- toYaml .Values.nodeLifecycleController.securityContext | nindent 10 }} + resources: + {{- toYaml .Values.nodeLifecycleController.resources | nindent 10 }} +{{- end }} diff --git a/packages/system/local-ccm/charts/local-ccm/templates/nlc-serviceaccount.yaml b/packages/system/local-ccm/charts/local-ccm/templates/nlc-serviceaccount.yaml new file mode 100644 index 00000000..a72ab136 --- /dev/null +++ b/packages/system/local-ccm/charts/local-ccm/templates/nlc-serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if and .Values.nodeLifecycleController.enabled .Values.nodeLifecycleController.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "local-ccm.fullname" . }}-nlc + labels: + {{- include "local-ccm.labels" . | nindent 4 }} + app.kubernetes.io/component: node-lifecycle-controller + {{- with .Values.nodeLifecycleController.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/packages/system/local-ccm/charts/local-ccm/templates/serviceaccount.yaml b/packages/system/local-ccm/charts/local-ccm/templates/serviceaccount.yaml new file mode 100644 index 00000000..a3582c56 --- /dev/null +++ b/packages/system/local-ccm/charts/local-ccm/templates/serviceaccount.yaml @@ -0,0 +1,8 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "local-ccm.serviceAccountName" . }} + labels: + {{- include "local-ccm.labels" . | nindent 4 }} +{{- end }} diff --git a/packages/system/local-ccm/charts/local-ccm/values.yaml b/packages/system/local-ccm/charts/local-ccm/values.yaml new file mode 100644 index 00000000..d84bac3f --- /dev/null +++ b/packages/system/local-ccm/charts/local-ccm/values.yaml @@ -0,0 +1,141 @@ +# Default values for local-ccm + +image: + repository: ghcr.io/cozystack/local-ccm + tag: v0.3.0 + pullPolicy: Always +# Service account configuration +serviceAccount: + create: true + name: local-ccm +# IP detection configuration +ipDetection: + # Target IP for external IP detection via 'ip route get' + externalIPTarget: "8.8.8.8" + # Target IP for internal IP detection via 'ip route get' + # If empty, internal IP detection is disabled and kubelet's InternalIP is preserved + internalIPTarget: "" +# Controller configuration +controller: + # Remove node.cloudprovider.kubernetes.io/uninitialized taint + removeTaint: true + # Interval between reconciliation loops + reconcileInterval: 10s + # Verbosity level (0-5) + verbosity: 2 +# Pod resources +resources: + requests: + cpu: 10m + memory: 32Mi + limits: + cpu: 100m + memory: 64Mi +# Security context for the container +securityContext: + capabilities: + add: + - NET_ADMIN # Required for netlink route queries + - NET_RAW + runAsUser: 0 # Must run as root to access netlink +# Tolerations - by default tolerate all taints to run on every node +tolerations: + - operator: Exists +# Node affinity configuration +affinity: + nodeAffinity: + # Prefer to schedule on nodes needing initialization first + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + preference: + matchExpressions: + - key: node.cloudprovider.kubernetes.io/uninitialized + operator: Exists +# Additional labels for all resources +labels: {} +# Additional annotations for pods +podAnnotations: {} +# Node Lifecycle Controller - deletes unreachable NotReady nodes +nodeLifecycleController: + # Enable node lifecycle controller + enabled: true + image: + repository: ghcr.io/cozystack/local-ccm + tag: "v0.3.0" # Defaults to appVersion + pullPolicy: IfNotPresent + # Controller configuration + controller: + # Watch only nodes with ToBeDeletedByClusterAutoscaler taint + # Ignored when nodeSelector is set + watchAutoscalerTaint: true + # Label selector for nodes to manage + # Only nodes matching this selector will be considered for deletion + # Example: "node.kubernetes.io/instance-type" (nodes created by autoscaler) + nodeSelector: "" + # Comma-separated list of labels/annotations that protect nodes from deletion + # Nodes with any of these labels will never be deleted + # Example: "kilo.squat.ai/leader,cluster-autoscaler.kubernetes.io/scale-down-disabled" + protectedLabels: "" + # Duration a node must be NotReady before considering deletion + notReadyTimeout: 5m + # Timeout for ping checks + pingTimeout: 5s + # Number of ping attempts before considering node unreachable + pingCount: 3 + # Interval between reconciliation loops + reconcileInterval: 30s + # Log actions without actually deleting nodes + dryRun: false + # Verbosity level (0-5) + verbosity: 2 + # Leader election for HA + leaderElection: + enabled: true + resourceName: node-lifecycle-controller + # Number of replicas (only 1 will be active due to leader election) + replicaCount: 1 + # Service account configuration + serviceAccount: + create: true + annotations: {} + # Pod resources + resources: + requests: + cpu: 10m + memory: 32Mi + limits: + cpu: 100m + memory: 64Mi + # Security context for the pod + podSecurityContext: + runAsNonRoot: false # Need root for ICMP ping + # Security context for the container + securityContext: + capabilities: + add: + - NET_RAW # Required for ICMP ping + runAsUser: 0 # Must run as root for raw sockets + # Node selector for the controller pod + nodeSelector: {} + # Tolerations for the controller pod + tolerations: + - key: node-role.kubernetes.io/control-plane + operator: Exists + effect: NoSchedule + - key: node-role.kubernetes.io/master + operator: Exists + effect: NoSchedule + # Affinity for the controller pod + affinity: + nodeAffinity: + # Prefer to run on control-plane nodes + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + preference: + matchExpressions: + - key: node-role.kubernetes.io/control-plane + operator: Exists + # Additional annotations for pods + podAnnotations: {} + # Use host network for ping to work across network boundaries + hostNetwork: true diff --git a/packages/system/mariadb-operator/Makefile b/packages/system/mariadb-operator/Makefile index ecbd51d9..905653ca 100644 --- a/packages/system/mariadb-operator/Makefile +++ b/packages/system/mariadb-operator/Makefile @@ -1,7 +1,7 @@ export NAME=mariadb-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/.helmignore b/packages/system/mariadb-operator/charts/mariadb-operator/.helmignore index 0e8a0eb3..691fa13d 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/.helmignore +++ b/packages/system/mariadb-operator/charts/mariadb-operator/.helmignore @@ -20,4 +20,4 @@ .project .idea/ *.tmproj -.vscode/ +.vscode/ \ No newline at end of file diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/Chart.lock b/packages/system/mariadb-operator/charts/mariadb-operator/Chart.lock new file mode 100644 index 00000000..6b08db06 --- /dev/null +++ b/packages/system/mariadb-operator/charts/mariadb-operator/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: mariadb-operator-crds + repository: file://../mariadb-operator-crds + version: 25.10.2 +digest: sha256:01b102dbdb92970e38346df382ed3e5cd93d02a3b642029e94320256c9bfad42 +generated: "2025-10-28T11:29:04.951947063Z" diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/Chart.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/Chart.yaml index af05bd6f..63049cc8 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/Chart.yaml +++ b/packages/system/mariadb-operator/charts/mariadb-operator/Chart.yaml @@ -1,5 +1,10 @@ apiVersion: v2 -appVersion: v0.0.30 +appVersion: 25.10.2 +dependencies: +- condition: crds.enabled + name: mariadb-operator-crds + repository: file://../mariadb-operator-crds + version: 25.10.2 description: Run and operate MariaDB in a cloud native way home: https://github.com/mariadb-operator/mariadb-operator icon: https://mariadb-operator.github.io/mariadb-operator/assets/mariadb_profile.svg @@ -12,8 +17,8 @@ keywords: - maxscale kubeVersion: '>=1.26.0-0' maintainers: -- email: mariadb-operator@proton.me +- email: martin.montes@mariadb.com name: mmontes11 name: mariadb-operator type: application -version: 0.30.0 +version: 25.10.2 diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/README.md b/packages/system/mariadb-operator/charts/mariadb-operator/README.md index 34e35ac1..3a9c1df8 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/README.md +++ b/packages/system/mariadb-operator/charts/mariadb-operator/README.md @@ -2,33 +2,30 @@ [//]: # (README.md generated by gotmpl. DO NOT EDIT.) -

-mariadb -

- -![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![Version: 0.30.0](https://img.shields.io/badge/Version-0.30.0-informational?style=flat-square) ![AppVersion: v0.0.30](https://img.shields.io/badge/AppVersion-v0.0.30-informational?style=flat-square) +![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![Version: 25.10.2](https://img.shields.io/badge/Version-25.10.2-informational?style=flat-square) ![AppVersion: 25.10.2](https://img.shields.io/badge/AppVersion-25.10.2-informational?style=flat-square) Run and operate MariaDB in a cloud native way ## Installing + +You can easily deploy the operator to your cluster by installing the `mariadb-operator-crds` and `mariadb-operator` Helm charts: + ```bash helm repo add mariadb-operator https://helm.mariadb.com/mariadb-operator +helm install mariadb-operator-crds mariadb-operator/mariadb-operator-crds helm install mariadb-operator mariadb-operator/mariadb-operator ``` -## Uninstalling -```bash -helm uninstall mariadb-operator -``` +Refer to the [helm documentation](https://github.com/mariadb-operator/mariadb-operator/blob/main/docs/helm.md) for further detail. ## Values | Key | Type | Default | Description | |-----|------|---------|-------------| | affinity | object | `{}` | Affinity to add to controller Pod | -| certController.affinity | object | `{}` | Affinity to add to controller Pod | -| certController.caValidity | string | `"35064h"` | CA certificate validity. It must be greater than certValidity. | -| certController.certValidity | string | `"8766h"` | Certificate validity. | +| certController.affinity | object | `{}` | Affinity to add to cert-controller container | +| certController.caLifetime | string | `"26280h"` | CA certificate lifetime. It must be greater than certLifetime. | +| certController.certLifetime | string | `"2160h"` | Certificate lifetime. | | certController.enabled | bool | `true` | Specifies whether the cert-controller should be created. | | certController.extrArgs | list | `[]` | Extra arguments to be passed to the cert-controller entrypoint | | certController.extraVolumeMounts | list | `[]` | Extra volumes to mount to cert-controller container | @@ -39,13 +36,16 @@ helm uninstall mariadb-operator | certController.image.repository | string | `"docker-registry3.mariadb.com/mariadb-operator/mariadb-operator"` | | | certController.image.tag | string | `""` | Image tag to use. By default the chart appVersion is used | | certController.imagePullSecrets | list | `[]` | | -| certController.lookaheadValidity | string | `"2160h"` | Duration used to verify whether a certificate is valid or not. | -| certController.nodeSelector | object | `{}` | Node selectors to add to controller Pod | +| certController.nodeSelector | object | `{}` | Node selectors to add to cert-controller container | +| certController.pdb.enabled | bool | `false` | Enable PodDisruptionBudget for the cert-controller. | +| certController.pdb.maxUnavailable | int | `1` | Maximum number of unavailable Pods. You may also give a percentage, like `50%` | | certController.podAnnotations | object | `{}` | Annotations to add to cert-controller Pod | | certController.podSecurityContext | object | `{}` | Security context to add to cert-controller Pod | +| certController.priorityClassName | string | `""` | priorityClassName to add to cert-controller container | +| certController.renewBeforePercentage | int | `33` | How long before the certificate expiration should the renewal process be triggered. For example, if a certificate is valid for 60 minutes, and renewBeforePercentage=25, cert-controller will begin to attempt to renew the certificate 45 minutes after it was issued (i.e. when there are 15 minutes (25%) remaining until the certificate is no longer valid). | | certController.requeueDuration | string | `"5m"` | Requeue duration to ensure that certificate gets renewed. | | certController.resources | object | `{}` | Resources to add to cert-controller container | -| certController.securityContext | object | `{}` | Security context to add to cert-controller container | +| certController.securityContext | object | `{}` | Security context to add to cert-controller Pod | | certController.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | | certController.serviceAccount.automount | bool | `true` | Automounts the service account token in all containers of the Pod | | certController.serviceAccount.enabled | bool | `true` | Specifies whether a service account should be created | @@ -54,16 +54,30 @@ helm uninstall mariadb-operator | certController.serviceMonitor.additionalLabels | object | `{}` | Labels to be added to the cert-controller ServiceMonitor | | certController.serviceMonitor.enabled | bool | `true` | Enable cert-controller ServiceMonitor. Metrics must be enabled | | certController.serviceMonitor.interval | string | `"30s"` | Interval to scrape metrics | +| certController.serviceMonitor.metricRelabelings | list | `[]` | | +| certController.serviceMonitor.relabelings | list | `[]` | | | certController.serviceMonitor.scrapeTimeout | string | `"25s"` | Timeout if metrics can't be retrieved in given time interval | -| certController.tolerations | list | `[]` | Tolerations to add to controller Pod | +| certController.tolerations | list | `[]` | Tolerations to add to cert-controller container | +| certController.topologySpreadConstraints | list | `[]` | topologySpreadConstraints to add to cert-controller container | | clusterName | string | `"cluster.local"` | Cluster DNS name | +| config | object | `{"exporterImage":"prom/mysqld-exporter:v0.15.1","exporterMaxscaleImage":"docker-registry2.mariadb.com/mariadb/maxscale-prometheus-exporter-ubi:v0.0.1","galeraLibPath":"/usr/lib/galera/libgalera_smm.so","mariadbDefaultVersion":"11.8","mariadbImage":"docker-registry1.mariadb.com/library/mariadb:11.8.2","mariadbImageName":"docker-registry1.mariadb.com/library/mariadb","maxscaleImage":"docker-registry2.mariadb.com/mariadb/maxscale:23.08.5"}` | Operator configuration | +| config.exporterImage | string | `"prom/mysqld-exporter:v0.15.1"` | Default MariaDB exporter image | +| config.exporterMaxscaleImage | string | `"docker-registry2.mariadb.com/mariadb/maxscale-prometheus-exporter-ubi:v0.0.1"` | Default MaxScale exporter image | +| config.galeraLibPath | string | `"/usr/lib/galera/libgalera_smm.so"` | Galera library path to be used with MariaDB Galera | +| config.mariadbDefaultVersion | string | `"11.8"` | Default MariaDB version to be used when unable to infer it via image tag | +| config.mariadbImage | string | `"docker-registry1.mariadb.com/library/mariadb:11.8.2"` | Default MariaDB image | +| config.mariadbImageName | string | `"docker-registry1.mariadb.com/library/mariadb"` | Default MariaDB image name | +| config.maxscaleImage | string | `"docker-registry2.mariadb.com/mariadb/maxscale:23.08.5"` | Default MaxScale image | +| crds | object | `{"enabled":false}` | CRDs | +| crds.enabled | bool | `false` | Whether the helm chart should create and update the CRDs. It is false by default, which implies that the CRDs must be managed independently with the mariadb-operator-crds helm chart. **WARNING** This should only be set to true during the initial deployment. If this chart manages the CRDs and is later uninstalled, all MariaDB instances will be DELETED. | +| currentNamespaceOnly | bool | `false` | Whether the operator should watch CRDs only in its own namespace or not. | | extrArgs | list | `[]` | Extra arguments to be passed to the controller entrypoint | | extraEnv | list | `[]` | Extra environment variables to be passed to the controller | | extraEnvFrom | list | `[]` | Extra environment variables from preexiting ConfigMap / Secret objects used by the controller using envFrom | | extraVolumeMounts | list | `[]` | Extra volumes to mount to the container. | | extraVolumes | list | `[]` | Extra volumes to pass to pod. | | fullnameOverride | string | `""` | | -| ha.enabled | bool | `false` | Enable high availability | +| ha.enabled | bool | `false` | Enable high availability of the controller. If you enable it we recommend to set `affinity` and `pdb` | | ha.replicas | int | `3` | Number of replicas | | image.pullPolicy | string | `"IfNotPresent"` | | | image.repository | string | `"docker-registry3.mariadb.com/mariadb-operator/mariadb-operator"` | | @@ -74,11 +88,18 @@ helm uninstall mariadb-operator | metrics.serviceMonitor.additionalLabels | object | `{}` | Labels to be added to the controller ServiceMonitor | | metrics.serviceMonitor.enabled | bool | `true` | Enable controller ServiceMonitor | | metrics.serviceMonitor.interval | string | `"30s"` | Interval to scrape metrics | +| metrics.serviceMonitor.metricRelabelings | list | `[]` | | +| metrics.serviceMonitor.relabelings | list | `[]` | | | metrics.serviceMonitor.scrapeTimeout | string | `"25s"` | Timeout if metrics can't be retrieved in given time interval | | nameOverride | string | `""` | | | nodeSelector | object | `{}` | Node selectors to add to controller Pod | +| pdb.enabled | bool | `false` | Enable PodDisruptionBudget for the controller. | +| pdb.maxUnavailable | int | `1` | Maximum number of unavailable Pods. You may also give a percentage, like `50%` | | podAnnotations | object | `{}` | Annotations to add to controller Pod | | podSecurityContext | object | `{}` | Security context to add to controller Pod | +| pprof.enabled | bool | `false` | Enable the pprof HTTP server. | +| pprof.port | int | `6060` | The port where the pprof HTTP server listens. | +| priorityClassName | string | `""` | priorityClassName to add to controller Pod | | rbac.aggregation.enabled | bool | `true` | Specifies whether the cluster roles aggrate to view and edit predefinied roles | | rbac.enabled | bool | `true` | Specifies whether RBAC resources should be created | | resources | object | `{}` | Resources to add to controller container | @@ -89,7 +110,8 @@ helm uninstall mariadb-operator | serviceAccount.extraLabels | object | `{}` | Extra Labels to add to the service account | | serviceAccount.name | string | `""` | The name of the service account to use. If not set and enabled is true, a name is generated using the fullname template | | tolerations | list | `[]` | Tolerations to add to controller Pod | -| webhook.affinity | object | `{}` | Affinity to add to controller Pod | +| topologySpreadConstraints | list | `[]` | topologySpreadConstraints to add to controller Pod | +| webhook.affinity | object | `{}` | Affinity to add to webhook Pod | | webhook.annotations | object | `{}` | Annotations for webhook configurations. | | webhook.cert.ca.key | string | `""` | File under 'ca.path' that contains the full CA trust chain. | | webhook.cert.ca.path | string | `""` | Path that contains the full CA trust chain. | @@ -101,6 +123,7 @@ helm uninstall mariadb-operator | webhook.cert.path | string | `"/tmp/k8s-webhook-server/serving-certs"` | Path where the certificate will be mounted. 'tls.crt' and 'tls.key' certificates files should be under this path. | | webhook.cert.secretAnnotations | object | `{}` | Annotatioms to be added to webhook TLS secret. | | webhook.cert.secretLabels | object | `{}` | Labels to be added to webhook TLS secret. | +| webhook.enabled | bool | `true` | Specifies whether the webhook should be created. | | webhook.extrArgs | list | `[]` | Extra arguments to be passed to the webhook entrypoint | | webhook.extraVolumeMounts | list | `[]` | Extra volumes to mount to webhook container | | webhook.extraVolumes | list | `[]` | Extra volumes to pass to webhook Pod | @@ -111,10 +134,13 @@ helm uninstall mariadb-operator | webhook.image.repository | string | `"docker-registry3.mariadb.com/mariadb-operator/mariadb-operator"` | | | webhook.image.tag | string | `""` | Image tag to use. By default the chart appVersion is used | | webhook.imagePullSecrets | list | `[]` | | -| webhook.nodeSelector | object | `{}` | Node selectors to add to controller Pod | +| webhook.nodeSelector | object | `{}` | Node selectors to add to webhook Pod | +| webhook.pdb.enabled | bool | `false` | Enable PodDisruptionBudget for the webhook. | +| webhook.pdb.maxUnavailable | int | `1` | Maximum number of unavailable Pods. You may also give a percentage, like `50%` | | webhook.podAnnotations | object | `{}` | Annotations to add to webhook Pod | | webhook.podSecurityContext | object | `{}` | Security context to add to webhook Pod | | webhook.port | int | `9443` | Port to be used by the webhook server | +| webhook.priorityClassName | string | `""` | priorityClassName to add to webhook Pod | | webhook.resources | object | `{}` | Resources to add to webhook container | | webhook.securityContext | object | `{}` | Security context to add to webhook container | | webhook.serviceAccount.annotations | object | `{}` | Annotations to add to the service account | @@ -125,6 +151,8 @@ helm uninstall mariadb-operator | webhook.serviceMonitor.additionalLabels | object | `{}` | Labels to be added to the webhook ServiceMonitor | | webhook.serviceMonitor.enabled | bool | `true` | Enable webhook ServiceMonitor. Metrics must be enabled | | webhook.serviceMonitor.interval | string | `"30s"` | Interval to scrape metrics | +| webhook.serviceMonitor.metricRelabelings | list | `[]` | | +| webhook.serviceMonitor.relabelings | list | `[]` | | | webhook.serviceMonitor.scrapeTimeout | string | `"25s"` | Timeout if metrics can't be retrieved in given time interval | -| webhook.tolerations | list | `[]` | Tolerations to add to controller Pod | - +| webhook.tolerations | list | `[]` | Tolerations to add to webhook Pod | +| webhook.topologySpreadConstraints | list | `[]` | topologySpreadConstraints to add to webhook Pod | diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/README.md.gotmpl b/packages/system/mariadb-operator/charts/mariadb-operator/README.md.gotmpl index 02a5d32c..234cebd1 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/README.md.gotmpl +++ b/packages/system/mariadb-operator/charts/mariadb-operator/README.md.gotmpl @@ -3,24 +3,20 @@ {{ $release := "mariadb-operator" }} [//]: # (README.md generated by gotmpl. DO NOT EDIT.) -

-mariadb -

- {{ template "chart.typeBadge" . }}{{ template "chart.versionBadge" . }}{{ template "chart.appVersionBadge" . }} {{ template "chart.description" . }} ## Installing + +You can easily deploy the operator to your cluster by installing the `mariadb-operator-crds` and `mariadb-operator` Helm charts: + ```bash -helm repo add {{ $org }} {{ $chartRepo }} -helm install {{ $release }} {{ $org }}/{{ template "chart.name" . }} +helm repo add mariadb-operator https://helm.mariadb.com/mariadb-operator +helm install mariadb-operator-crds mariadb-operator/mariadb-operator-crds +helm install mariadb-operator mariadb-operator/mariadb-operator ``` -## Uninstalling -```bash -helm uninstall {{ $release }} -``` +Refer to the [helm documentation](https://github.com/mariadb-operator/mariadb-operator/blob/main/docs/helm.md) for further detail. {{ template "chart.valuesSection" . }} - diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/charts/mariadb-operator-crds/.helmignore b/packages/system/mariadb-operator/charts/mariadb-operator/charts/mariadb-operator-crds/.helmignore new file mode 100644 index 00000000..691fa13d --- /dev/null +++ b/packages/system/mariadb-operator/charts/mariadb-operator/charts/mariadb-operator-crds/.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/ \ No newline at end of file diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/charts/mariadb-operator-crds/Chart.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/charts/mariadb-operator-crds/Chart.yaml new file mode 100644 index 00000000..0af1271a --- /dev/null +++ b/packages/system/mariadb-operator/charts/mariadb-operator/charts/mariadb-operator-crds/Chart.yaml @@ -0,0 +1,19 @@ +apiVersion: v2 +appVersion: 0.0.0 +description: mariadb-operator CRDs +home: https://github.com/mariadb-operator/mariadb-operator +icon: https://mariadb-operator.github.io/mariadb-operator/assets/mariadb_profile.svg +keywords: +- mariadb +- mysql +- operator +- mariadb-operator +- database +- maxscale +kubeVersion: '>=1.26.0-0' +maintainers: +- email: martin.montes@mariadb.com + name: mmontes11 +name: mariadb-operator-crds +type: application +version: 25.10.2 diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/charts/mariadb-operator-crds/templates/NOTES.txt b/packages/system/mariadb-operator/charts/mariadb-operator/charts/mariadb-operator-crds/templates/NOTES.txt new file mode 100644 index 00000000..ff7456b9 --- /dev/null +++ b/packages/system/mariadb-operator/charts/mariadb-operator/charts/mariadb-operator-crds/templates/NOTES.txt @@ -0,0 +1,5 @@ +mariadb-operator CRDs have been successfully installed! 🦭 + +To complete the mariadb-operator installation, please now proceed to install the +mariadb-operator chart: +https://github.com/mariadb-operator/mariadb-operator?tab=readme-ov-file#helm-installation \ No newline at end of file diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/charts/mariadb-operator-crds/templates/crds.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/charts/mariadb-operator-crds/templates/crds.yaml new file mode 100644 index 00000000..66a3a953 --- /dev/null +++ b/packages/system/mariadb-operator/charts/mariadb-operator/charts/mariadb-operator-crds/templates/crds.yaml @@ -0,0 +1,14971 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: backups.k8s.mariadb.com +spec: + group: k8s.mariadb.com + names: + kind: Backup + listKind: BackupList + plural: backups + shortNames: + - bmdb + singular: backup + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Complete")].status + name: Complete + type: string + - jsonPath: .status.conditions[?(@.type=="Complete")].message + name: Status + type: string + - jsonPath: .spec.mariaDbRef.name + name: MariaDB + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Backup is the Schema for the backups API. It is used to define + backup jobs and its storage. + 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: BackupSpec defines the desired state of Backup + properties: + affinity: + description: Affinity to be used in the Pod. + properties: + antiAffinityEnabled: + description: |- + AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. + Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. + type: boolean + nodeAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeaffinity-v1-core' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#preferredschedulingterm-v1-core' + properties: + preference: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselector-v1-core' + properties: + nodeSelectorTerms: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + type: object + podAntiAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podantiaffinity-v1-core.' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#weightedpodaffinityterm-v1-core.' + properties: + podAffinityTerm: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector operator + is the set of operators that can be + used in a selector requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector operator is + the set of operators that can be used in + a selector requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + args: + description: Args to be used in the Container. + items: + type: string + type: array + backoffLimit: + description: BackoffLimit defines the maximum number of attempts to + successfully take a Backup. + format: int32 + type: integer + compression: + description: Compression algorithm to be used in the Backup. + enum: + - none + - bzip2 + - gzip + type: string + databases: + description: Databases defines the logical databases to be backed + up. If not provided, all databases are backed up. + items: + type: string + type: array + failedJobsHistoryLimit: + description: FailedJobsHistoryLimit defines the maximum number of + failed Jobs to be displayed. + format: int32 + minimum: 0 + type: integer + ignoreGlobalPriv: + description: |- + IgnoreGlobalPriv indicates to ignore the mysql.global_priv in backups. + If not provided, it will default to true when the referred MariaDB instance has Galera enabled and otherwise to false. + See: https://github.com/mariadb-operator/mariadb-operator/issues/556 + type: boolean + imagePullSecrets: + description: ImagePullSecrets is the list of pull Secrets to be used + to pull the image. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: array + inheritMetadata: + description: InheritMetadata defines the metadata to be inherited + by children resources. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + logLevel: + default: info + description: LogLevel to be used n the Backup Job. It defaults to + 'info'. + type: string + mariaDbRef: + description: MariaDBRef is a reference to a MariaDB object. + properties: + kind: + description: Kind of the referent. + type: string + name: + type: string + namespace: + type: string + waitForIt: + default: true + description: WaitForIt indicates whether the controller using + this reference should wait for MariaDB to be ready. + type: boolean + type: object + maxRetention: + description: |- + MaxRetention defines the retention policy for backups. Old backups will be cleaned up by the Backup Job. + It defaults to 30 days. + type: string + nodeSelector: + additionalProperties: + type: string + description: NodeSelector to be used in the Pod. + type: object + podMetadata: + description: PodMetadata defines extra metadata for the Pod. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + podSecurityContext: + description: SecurityContext holds pod-level security attributes and + common container settings. + properties: + appArmorProfile: + description: AppArmorProfile defines a pod or container's AppArmor + settings. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + PodFSGroupChangePolicy holds policies that will be used for applying fsGroup to a volume + when volume is mounted. + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + description: SELinuxOptions are the labels to be applied to the + container + properties: + level: + description: Level is SELinux level label that applies to + the container. + type: string + role: + description: Role is a SELinux role label that applies to + the container. + type: string + type: + description: Type is a SELinux type label that applies to + the container. + type: string + user: + description: User is a SELinux user label that applies to + the container. + type: string + type: object + seccompProfile: + description: |- + SeccompProfile defines a pod/container's seccomp profile settings. + Only one profile source may be set. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + type: object + priorityClassName: + description: PriorityClassName to be used in the Pod. + type: string + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + type: object + restartPolicy: + default: OnFailure + description: RestartPolicy to be added to the Backup Pod. + enum: + - Always + - OnFailure + - Never + type: string + schedule: + description: Schedule defines when the Backup will be taken. + properties: + cron: + description: Cron is a cron expression that defines the schedule. + type: string + suspend: + default: false + description: Suspend defines whether the schedule is active or + not. + type: boolean + required: + - cron + type: object + securityContext: + description: SecurityContext holds security configuration that will + be applied to a container. + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + description: Adds and removes POSIX capabilities from running + containers. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + type: object + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + to be used by the Pods. + type: string + stagingStorage: + description: |- + StagingStorage defines the temporary storage used to keep external backups (i.e. S3) while they are being processed. + It defaults to an emptyDir volume, meaning that the backups will be temporarily stored in the node where the Backup Job is scheduled. + The staging area gets cleaned up after each backup is completed, consider this for sizing it appropriately. + properties: + persistentVolumeClaim: + description: PersistentVolumeClaim is a Kubernetes PVC specification. + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + resources: + description: VolumeResourceRequirements describes the storage + resource requirements for a volume. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + storageClassName: + type: string + type: object + volume: + description: Volume is a Kubernetes volume specification. + properties: + csi: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#csivolumesource-v1-core.' + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + emptyDir: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#emptydirvolumesource-v1-core.' + properties: + medium: + description: StorageMedium defines ways that storage can + be allocated to a volume. + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#hostpathvolumesource-v1-core' + properties: + path: + type: string + type: + type: string + required: + - path + type: object + nfs: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nfsvolumesource-v1-core.' + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#persistentvolumeclaimvolumesource-v1-core.' + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + type: object + type: object + storage: + description: Storage defines the final storage for backups. + properties: + persistentVolumeClaim: + description: PersistentVolumeClaim is a Kubernetes PVC specification. + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + resources: + description: VolumeResourceRequirements describes the storage + resource requirements for a volume. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + storageClassName: + type: string + type: object + s3: + description: S3 defines the configuration to store backups in + a S3 compatible storage. + properties: + accessKeyIdSecretKeyRef: + description: AccessKeyIdSecretKeyRef is a reference to a Secret + key containing the S3 access key id. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + bucket: + description: Bucket is the name Name of the bucket to store + backups. + type: string + endpoint: + description: Endpoint is the S3 API endpoint without scheme. + type: string + prefix: + description: 'Prefix indicates a folder/subfolder in the bucket. + For example: mariadb/ or mariadb/backups. A trailing slash + ''/'' is added if not provided.' + type: string + region: + description: Region is the S3 region name to use. + type: string + secretAccessKeySecretKeyRef: + description: AccessKeyIdSecretKeyRef is a reference to a Secret + key containing the S3 secret key. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + sessionTokenSecretKeyRef: + description: SessionTokenSecretKeyRef is a reference to a + Secret key containing the S3 session token. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + tls: + description: TLS provides the configuration required to establish + TLS connections with S3. + properties: + caSecretKeyRef: + description: |- + CASecretKeyRef is a reference to a Secret key containing a CA bundle in PEM format used to establish TLS connections with S3. + By default, the system trust chain will be used, but you can use this field to add more CAs to the bundle. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + enabled: + description: Enabled is a flag to enable TLS. + type: boolean + type: object + required: + - bucket + - endpoint + type: object + volume: + description: Volume is a Kubernetes volume specification. + properties: + csi: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#csivolumesource-v1-core.' + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + emptyDir: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#emptydirvolumesource-v1-core.' + properties: + medium: + description: StorageMedium defines ways that storage can + be allocated to a volume. + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#hostpathvolumesource-v1-core' + properties: + path: + type: string + type: + type: string + required: + - path + type: object + nfs: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nfsvolumesource-v1-core.' + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#persistentvolumeclaimvolumesource-v1-core.' + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + type: object + type: object + successfulJobsHistoryLimit: + description: SuccessfulJobsHistoryLimit defines the maximum number + of successful Jobs to be displayed. + format: int32 + minimum: 0 + type: integer + timeZone: + description: TimeZone defines the timezone associated with the cron + expression. + type: string + tolerations: + description: Tolerations to be used in the Pod. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + required: + - mariaDbRef + - storage + type: object + status: + description: BackupStatus defines the observed state of Backup + properties: + conditions: + description: Conditions for the Backup object. + 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 + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: connections.k8s.mariadb.com +spec: + group: k8s.mariadb.com + names: + kind: Connection + listKind: ConnectionList + plural: connections + shortNames: + - cmdb + singular: connection + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .spec.secretName + name: Secret + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Connection is the Schema for the connections API. It is used + to configure connection strings for the applications connecting to MariaDB. + 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: ConnectionSpec defines the desired state of Connection + properties: + database: + description: Database to use when configuring the Connection. + type: string + healthCheck: + description: HealthCheck to be used in the Connection. + properties: + interval: + description: Interval used to perform health checks. + type: string + retryInterval: + description: RetryInterval is the interval used to perform health + check retries. + type: string + type: object + host: + description: Host to connect to. If not provided, it defaults to the + MariaDB host or to the MaxScale host. + type: string + mariaDbRef: + description: MariaDBRef is a reference to the MariaDB to connect to. + Either MariaDBRef or MaxScaleRef must be provided. + properties: + kind: + description: Kind of the referent. + type: string + name: + type: string + namespace: + type: string + waitForIt: + default: true + description: WaitForIt indicates whether the controller using + this reference should wait for MariaDB to be ready. + type: boolean + type: object + maxScaleRef: + description: MaxScaleRef is a reference to the MaxScale to connect + to. Either MariaDBRef or MaxScaleRef must be provided. + properties: + name: + type: string + namespace: + type: string + type: object + params: + additionalProperties: + type: string + description: Params to be used in the Connection. + type: object + passwordSecretKeyRef: + description: |- + PasswordSecretKeyRef is a reference to the password to use for configuring the Connection. + Either passwordSecretKeyRef or tlsClientCertSecretRef must be provided as client credentials. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + port: + description: Port to connect to. If not provided, it defaults to the + MariaDB port or to the first MaxScale listener. + format: int32 + type: integer + secretName: + description: SecretName to be used in the Connection. + type: string + secretTemplate: + description: SecretTemplate to be used in the Connection. + properties: + databaseKey: + description: DatabaseKey to be used in the Secret. + type: string + format: + description: Format to be used in the Secret. + type: string + hostKey: + description: HostKey to be used in the Secret. + type: string + key: + description: Key to be used in the Secret. + type: string + metadata: + description: Metadata to be added to the Secret object. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + passwordKey: + description: PasswordKey to be used in the Secret. + type: string + portKey: + description: PortKey to be used in the Secret. + type: string + usernameKey: + description: UsernameKey to be used in the Secret. + type: string + type: object + serviceName: + description: ServiceName to be used in the Connection. + type: string + tlsClientCertSecretRef: + description: |- + TLSClientCertSecretRef is a reference to a Kubernetes TLS Secret used as authentication when checking the connection health. + Either passwordSecretKeyRef or tlsClientCertSecretRef must be provided as client credentials. + If not provided, the client certificate provided by the referred MariaDB is used if TLS is enabled. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the client certificate. + properties: + name: + default: "" + type: string + type: object + username: + description: Username to use for configuring the Connection. + type: string + required: + - username + type: object + status: + description: ConnectionStatus defines the observed state of Connection + properties: + conditions: + description: Conditions for the Connection object. + 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 + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: databases.k8s.mariadb.com +spec: + group: k8s.mariadb.com + names: + kind: Database + listKind: DatabaseList + plural: databases + shortNames: + - dmdb + singular: database + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .spec.characterSet + name: CharSet + type: string + - jsonPath: .spec.collate + name: Collate + type: string + - jsonPath: .spec.mariaDbRef.name + name: MariaDB + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .spec.name + name: Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Database is the Schema for the databases API. It is used to define + a logical database as if you were running a 'CREATE DATABASE' statement. + 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: DatabaseSpec defines the desired state of Database + properties: + characterSet: + default: utf8 + description: CharacterSet to use in the Database. + type: string + cleanupPolicy: + description: CleanupPolicy defines the behavior for cleaning up a + SQL resource. + enum: + - Skip + - Delete + type: string + collate: + default: utf8_general_ci + description: Collate to use in the Database. + type: string + mariaDbRef: + description: MariaDBRef is a reference to a MariaDB object. + properties: + kind: + description: Kind of the referent. + type: string + name: + type: string + namespace: + type: string + waitForIt: + default: true + description: WaitForIt indicates whether the controller using + this reference should wait for MariaDB to be ready. + type: boolean + type: object + name: + description: Name overrides the default Database name provided by + metadata.name. + maxLength: 80 + type: string + requeueInterval: + description: RequeueInterval is used to perform requeue reconciliations. + type: string + retryInterval: + description: RetryInterval is the interval used to perform retries. + type: string + required: + - mariaDbRef + type: object + status: + description: DatabaseStatus defines the observed state of Database + properties: + conditions: + description: Conditions for the Database object. + 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 + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: externalmariadbs.k8s.mariadb.com +spec: + group: k8s.mariadb.com + names: + kind: ExternalMariaDB + listKind: ExternalMariaDBList + plural: externalmariadbs + shortNames: + - emdb + singular: externalmariadb + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: ExternalMariaDB is the Schema for the external MariaDBs API. + It is used to define external MariaDB server. + 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: ExternalMariaDBSpec defines the desired state of an External + MariaDB + properties: + connection: + description: Connection defines a template to configure a Connection + for the external MariaDB. + properties: + healthCheck: + description: HealthCheck to be used in the Connection. + properties: + interval: + description: Interval used to perform health checks. + type: string + retryInterval: + description: RetryInterval is the interval used to perform + health check retries. + type: string + type: object + params: + additionalProperties: + type: string + description: Params to be used in the Connection. + type: object + port: + description: Port to connect to. If not provided, it defaults + to the MariaDB port or to the first MaxScale listener. + format: int32 + type: integer + secretName: + description: SecretName to be used in the Connection. + type: string + secretTemplate: + description: SecretTemplate to be used in the Connection. + properties: + databaseKey: + description: DatabaseKey to be used in the Secret. + type: string + format: + description: Format to be used in the Secret. + type: string + hostKey: + description: HostKey to be used in the Secret. + type: string + key: + description: Key to be used in the Secret. + type: string + metadata: + description: Metadata to be added to the Secret object. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + passwordKey: + description: PasswordKey to be used in the Secret. + type: string + portKey: + description: PortKey to be used in the Secret. + type: string + usernameKey: + description: UsernameKey to be used in the Secret. + type: string + type: object + serviceName: + description: ServiceName to be used in the Connection. + type: string + type: object + host: + description: Hostname of the external MariaDB. + type: string + image: + description: |- + Image name to be used to perform operations on the external MariaDB, for example, for taking backups. + The supported format is `:`. Only MariaDB official images are supported. + If not provided, the MariaDB image version be inferred by the operator in runtime. The default MariaDB image will be used in this case, + type: string + imagePullPolicy: + description: ImagePullPolicy is the image pull policy. One of `Always`, + `Never` or `IfNotPresent`. If not defined, it defaults to `IfNotPresent`. + enum: + - Always + - Never + - IfNotPresent + type: string + imagePullSecrets: + description: ImagePullSecrets is the list of pull Secrets to be used + to pull the image. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: array + inheritMetadata: + description: InheritMetadata defines the metadata to be inherited + by children resources. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + passwordSecretKeyRef: + description: PasswordSecretKeyRef is a reference to the password to + connect to the external MariaDB. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + port: + default: 3306 + description: Port of the external MariaDB. + format: int32 + type: integer + tls: + description: TLS defines the PKI to be used with the external MariaDB. + properties: + clientCASecretRef: + description: |- + ClientCASecretRef is a reference to a Secret containing the client certificate authority keypair. It is used to establish trust and issue client certificates. + One of: + - Secret containing both the 'ca.crt' and 'ca.key' keys. This allows you to bring your own CA to Kubernetes to issue certificates. + - Secret containing only the 'ca.crt' in order to establish trust. In this case, either clientCertSecretRef or clientCertIssuerRef fields must be provided. + If not provided, a self-signed CA will be provisioned to issue the client certificate. + properties: + name: + default: "" + type: string + type: object + clientCertIssuerRef: + description: |- + ClientCertIssuerRef is a reference to a cert-manager issuer object used to issue the client certificate. cert-manager must be installed previously in the cluster. + It is mutually exclusive with clientCertSecretRef. + By default, the Secret field 'ca.crt' provisioned by cert-manager will be added to the trust chain. A custom trust bundle may be specified via clientCASecretRef. + properties: + group: + description: Group of the resource being referred to. + type: string + kind: + description: Kind of the resource being referred to. + type: string + name: + description: Name of the resource being referred to. + type: string + required: + - name + type: object + clientCertSecretRef: + description: |- + ClientCertSecretRef is a reference to a TLS Secret containing the client certificate. + It is mutually exclusive with clientCertIssuerRef. + properties: + name: + default: "" + type: string + type: object + enabled: + description: |- + Enabled indicates whether TLS is enabled, determining if certificates should be issued and mounted to the MariaDB instance. + It is enabled by default. + type: boolean + galeraSSTEnabled: + description: |- + GaleraSSTEnabled determines whether Galera SST connections should use TLS. + It disabled by default. + type: boolean + required: + description: |- + Required specifies whether TLS must be enforced for all connections. + User TLS requirements take precedence over this. + It disabled by default. + type: boolean + serverCASecretRef: + description: |- + ServerCASecretRef is a reference to a Secret containing the server certificate authority keypair. It is used to establish trust and issue server certificates. + One of: + - Secret containing both the 'ca.crt' and 'ca.key' keys. This allows you to bring your own CA to Kubernetes to issue certificates. + - Secret containing only the 'ca.crt' in order to establish trust. In this case, either serverCertSecretRef or serverCertIssuerRef must be provided. + If not provided, a self-signed CA will be provisioned to issue the server certificate. + properties: + name: + default: "" + type: string + type: object + serverCertIssuerRef: + description: |- + ServerCertIssuerRef is a reference to a cert-manager issuer object used to issue the server certificate. cert-manager must be installed previously in the cluster. + It is mutually exclusive with serverCertSecretRef. + By default, the Secret field 'ca.crt' provisioned by cert-manager will be added to the trust chain. A custom trust bundle may be specified via serverCASecretRef. + properties: + group: + description: Group of the resource being referred to. + type: string + kind: + description: Kind of the resource being referred to. + type: string + name: + description: Name of the resource being referred to. + type: string + required: + - name + type: object + serverCertSecretRef: + description: |- + ServerCertSecretRef is a reference to a TLS Secret containing the server certificate. + It is mutually exclusive with serverCertIssuerRef. + properties: + name: + default: "" + type: string + type: object + type: object + username: + description: Username is the username to connect to the external MariaDB. + type: string + required: + - host + - username + type: object + status: + description: ExternalMariaDBStatus defines the observed state of MariaDB + properties: + conditions: + description: Conditions for the ExternalMariadb object. + 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 + type: array + isGaleraEnabled: + description: IsGaleraEnabled indicates that the external MariaDb has + Galera enabled. + type: boolean + version: + description: Version of the external MariaDB server. + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: grants.k8s.mariadb.com +spec: + group: k8s.mariadb.com + names: + kind: Grant + listKind: GrantList + plural: grants + shortNames: + - gmdb + singular: grant + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .spec.database + name: Database + type: string + - jsonPath: .spec.table + name: Table + type: string + - jsonPath: .spec.username + name: Username + type: string + - jsonPath: .spec.grantOption + name: GrantOpt + type: string + - jsonPath: .spec.mariaDbRef.name + name: MariaDB + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Grant is the Schema for the grants API. It is used to define + grants as if you were running a 'GRANT' statement. + 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: GrantSpec defines the desired state of Grant + properties: + cleanupPolicy: + description: CleanupPolicy defines the behavior for cleaning up a + SQL resource. + enum: + - Skip + - Delete + type: string + database: + default: '*' + description: Database to use in the Grant. + type: string + grantOption: + default: false + description: GrantOption to use in the Grant. + type: boolean + host: + description: Host to use in the Grant. It can be localhost, an IP + or '%'. + type: string + mariaDbRef: + description: MariaDBRef is a reference to a MariaDB object. + properties: + kind: + description: Kind of the referent. + type: string + name: + type: string + namespace: + type: string + waitForIt: + default: true + description: WaitForIt indicates whether the controller using + this reference should wait for MariaDB to be ready. + type: boolean + type: object + privileges: + description: Privileges to use in the Grant. + items: + type: string + minItems: 1 + type: array + requeueInterval: + description: RequeueInterval is used to perform requeue reconciliations. + type: string + retryInterval: + description: RetryInterval is the interval used to perform retries. + type: string + table: + default: '*' + description: Table to use in the Grant. + type: string + username: + description: Username to use in the Grant. + type: string + required: + - mariaDbRef + - privileges + - username + type: object + status: + description: GrantStatus defines the observed state of Grant + properties: + conditions: + description: Conditions for the Grant object. + 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 + type: array + currentPrivileges: + description: |- + CurrentPrivileges is the list of current privileges used in the Grant. + It allows to detect the divergence from the desired privileges. + items: + type: string + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: mariadbs.k8s.mariadb.com +spec: + group: k8s.mariadb.com + names: + kind: MariaDB + listKind: MariaDBList + plural: mariadbs + shortNames: + - mdb + singular: mariadb + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .status.currentPrimary + name: Primary + type: string + - jsonPath: .spec.updateStrategy.type + name: Updates + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: MariaDB is the Schema for the mariadbs API. It is used to define + MariaDB clusters. + 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: MariaDBSpec defines the desired state of MariaDB + properties: + affinity: + description: Affinity to be used in the Pod. + properties: + antiAffinityEnabled: + description: |- + AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. + Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. + type: boolean + nodeAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeaffinity-v1-core' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#preferredschedulingterm-v1-core' + properties: + preference: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselector-v1-core' + properties: + nodeSelectorTerms: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + type: object + podAntiAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podantiaffinity-v1-core.' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#weightedpodaffinityterm-v1-core.' + properties: + podAffinityTerm: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector operator + is the set of operators that can be + used in a selector requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector operator is + the set of operators that can be used in + a selector requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + args: + description: Args to be used in the Container. + items: + type: string + type: array + bootstrapFrom: + description: BootstrapFrom defines a source to bootstrap from. + properties: + backupContentType: + description: |- + BackupContentType is the backup content type available in the source to bootstrap from. + It is inferred based on the BackupRef and VolumeSnapshotRef fields. If inference is not possible, it defaults to Logical. + Set this field explicitly when using physical backups from S3 or Volume sources. + enum: + - Logical + - Physical + type: string + backupRef: + description: |- + BackupRef is reference to a backup object. If the Kind is not specified, a logical Backup is assumed. + This field takes precedence over S3 and Volume sources. + properties: + kind: + description: Kind of the referent. + type: string + name: + description: Name of the referent. + type: string + type: object + restoreJob: + description: RestoreJob defines additional properties for the + Job used to perform the restoration. + properties: + affinity: + description: Affinity to be used in the Pod. + properties: + antiAffinityEnabled: + description: |- + AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. + Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. + type: boolean + nodeAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeaffinity-v1-core' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#preferredschedulingterm-v1-core' + properties: + preference: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselector-v1-core' + properties: + nodeSelectorTerms: + items: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + type: object + podAntiAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podantiaffinity-v1-core.' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#weightedpodaffinityterm-v1-core.' + properties: + podAffinityTerm: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector + operator is the set of operators + that can be used in a selector + requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector operator + is the set of operators that can + be used in a selector requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + args: + description: Args to be used in the Container. + items: + type: string + type: array + metadata: + description: Metadata defines additional metadata for the + bootstrap Jobs. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: NodeSelector to be used in the Pod. + type: object + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + type: object + tolerations: + description: Tolerations to be used in the Pod. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + s3: + description: |- + S3 defines the configuration to restore backups from a S3 compatible storage. + This field takes precedence over the Volume source. + properties: + accessKeyIdSecretKeyRef: + description: AccessKeyIdSecretKeyRef is a reference to a Secret + key containing the S3 access key id. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + bucket: + description: Bucket is the name Name of the bucket to store + backups. + type: string + endpoint: + description: Endpoint is the S3 API endpoint without scheme. + type: string + prefix: + description: 'Prefix indicates a folder/subfolder in the bucket. + For example: mariadb/ or mariadb/backups. A trailing slash + ''/'' is added if not provided.' + type: string + region: + description: Region is the S3 region name to use. + type: string + secretAccessKeySecretKeyRef: + description: AccessKeyIdSecretKeyRef is a reference to a Secret + key containing the S3 secret key. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + sessionTokenSecretKeyRef: + description: SessionTokenSecretKeyRef is a reference to a + Secret key containing the S3 session token. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + tls: + description: TLS provides the configuration required to establish + TLS connections with S3. + properties: + caSecretKeyRef: + description: |- + CASecretKeyRef is a reference to a Secret key containing a CA bundle in PEM format used to establish TLS connections with S3. + By default, the system trust chain will be used, but you can use this field to add more CAs to the bundle. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + enabled: + description: Enabled is a flag to enable TLS. + type: boolean + type: object + required: + - bucket + - endpoint + type: object + stagingStorage: + description: |- + StagingStorage defines the temporary storage used to keep external backups (i.e. S3) while they are being processed. + It defaults to an emptyDir volume, meaning that the backups will be temporarily stored in the node where the Job is scheduled. + properties: + persistentVolumeClaim: + description: PersistentVolumeClaim is a Kubernetes PVC specification. + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + resources: + description: VolumeResourceRequirements describes the + storage resource requirements for a volume. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + storageClassName: + type: string + type: object + volume: + description: Volume is a Kubernetes volume specification. + properties: + csi: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#csivolumesource-v1-core.' + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + emptyDir: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#emptydirvolumesource-v1-core.' + properties: + medium: + description: StorageMedium defines ways that storage + can be allocated to a volume. + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#hostpathvolumesource-v1-core' + properties: + path: + type: string + type: + type: string + required: + - path + type: object + nfs: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nfsvolumesource-v1-core.' + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#persistentvolumeclaimvolumesource-v1-core.' + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + type: object + type: object + targetRecoveryTime: + description: |- + TargetRecoveryTime is a RFC3339 (1970-01-01T00:00:00Z) date and time that defines the point in time recovery objective. + It is used to determine the closest restoration source in time. + format: date-time + type: string + volume: + description: Volume is a Kubernetes Volume object that contains + a backup. + properties: + csi: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#csivolumesource-v1-core.' + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + emptyDir: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#emptydirvolumesource-v1-core.' + properties: + medium: + description: StorageMedium defines ways that storage can + be allocated to a volume. + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#hostpathvolumesource-v1-core' + properties: + path: + type: string + type: + type: string + required: + - path + type: object + nfs: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nfsvolumesource-v1-core.' + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#persistentvolumeclaimvolumesource-v1-core.' + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + type: object + volumeSnapshotRef: + description: |- + VolumeSnapshotRef is a reference to a VolumeSnapshot object. + This field takes precedence over S3 and Volume sources. + properties: + name: + default: "" + type: string + type: object + type: object + command: + description: Command to be used in the Container. + items: + type: string + type: array + connection: + description: |- + Connection defines a template to configure the general Connection object. + This Connection provides the initial User access to the initial Database. + It will make use of the Service to route network traffic to all Pods. + properties: + healthCheck: + description: HealthCheck to be used in the Connection. + properties: + interval: + description: Interval used to perform health checks. + type: string + retryInterval: + description: RetryInterval is the interval used to perform + health check retries. + type: string + type: object + params: + additionalProperties: + type: string + description: Params to be used in the Connection. + type: object + port: + description: Port to connect to. If not provided, it defaults + to the MariaDB port or to the first MaxScale listener. + format: int32 + type: integer + secretName: + description: SecretName to be used in the Connection. + type: string + secretTemplate: + description: SecretTemplate to be used in the Connection. + properties: + databaseKey: + description: DatabaseKey to be used in the Secret. + type: string + format: + description: Format to be used in the Secret. + type: string + hostKey: + description: HostKey to be used in the Secret. + type: string + key: + description: Key to be used in the Secret. + type: string + metadata: + description: Metadata to be added to the Secret object. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + passwordKey: + description: PasswordKey to be used in the Secret. + type: string + portKey: + description: PortKey to be used in the Secret. + type: string + usernameKey: + description: UsernameKey to be used in the Secret. + type: string + type: object + serviceName: + description: ServiceName to be used in the Connection. + type: string + type: object + database: + description: Database is the name of the initial Database. + type: string + env: + description: Env represents the environment variables to be injected + in a container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + type: string + valueFrom: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + configMapKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#configmapkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#objectfieldselector-v1-core.' + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#secretkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: EnvFrom represents the references (via ConfigMap and + Secrets) to environment variables to be injected in the container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envfromsource-v1-core.' + properties: + configMapRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + prefix: + type: string + secretRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: object + type: array + galera: + description: Replication configures high availability via Galera. + properties: + agent: + description: Agent is a sidecar agent that co-operates with mariadb-operator. + properties: + args: + description: Args to be used in the Container. + items: + type: string + type: array + basicAuth: + description: BasicAuth to be used by the agent container + properties: + enabled: + description: Enabled is a flag to enable BasicAuth + type: boolean + passwordSecretKeyRef: + description: PasswordSecretKeyRef to be used for basic + authentication + properties: + generate: + default: false + description: Generate indicates whether the Secret + should be generated if the Secret referenced is + not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: Username to be used for basic authentication + type: string + type: object + command: + description: Command to be used in the Container. + items: + type: string + type: array + env: + description: Env represents the environment variables to be + injected in a container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + type: string + valueFrom: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + configMapKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#configmapkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#objectfieldselector-v1-core.' + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#secretkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: EnvFrom represents the references (via ConfigMap + and Secrets) to environment variables to be injected in + the container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envfromsource-v1-core.' + properties: + configMapRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + prefix: + type: string + secretRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: object + type: array + gracefulShutdownTimeout: + description: GracefulShutdownTimeout is the time we give to + the agent container in order to gracefully terminate in-flight + requests. + type: string + image: + description: Image name to be used by the MariaDB instances. + The supported format is `:`. + type: string + imagePullPolicy: + description: ImagePullPolicy is the image pull policy. One + of `Always`, `Never` or `IfNotPresent`. If not defined, + it defaults to `IfNotPresent`. + enum: + - Always + - Never + - IfNotPresent + type: string + kubernetesAuth: + description: KubernetesAuth to be used by the agent container + properties: + authDelegatorRoleName: + description: |- + AuthDelegatorRoleName is the name of the ClusterRoleBinding that is associated with the "system:auth-delegator" ClusterRole. + It is necessary for creating TokenReview objects in order for the agent to validate the service account token. + type: string + enabled: + description: Enabled is a flag to enable KubernetesAuth + type: boolean + type: object + livenessProbe: + description: LivenessProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used + for connection to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + port: + description: Port where the agent will be listening for API + connections. + format: int32 + type: integer + probePort: + description: Port where the agent will be listening for probe + connections. + format: int32 + type: integer + readinessProbe: + description: ReadinessProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used + for connection to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + type: object + securityContext: + description: SecurityContext holds security configuration + that will be applied to a container. + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + description: Adds and removes POSIX capabilities from + running containers. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + type: object + startupProbe: + description: StartupProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used + for connection to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + volumeMounts: + description: VolumeMounts to be used in the Container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#volumemount-v1-core.' + properties: + mountPath: + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + type: boolean + subPath: + type: string + required: + - mountPath + - name + type: object + type: array + type: object + availableWhenDonor: + description: AvailableWhenDonor indicates whether a donor node + should be responding to queries. It defaults to false. + type: boolean + config: + description: GaleraConfig defines storage options for the Galera + configuration files. + properties: + reuseStorageVolume: + description: |- + ReuseStorageVolume indicates that storage volume used by MariaDB should be reused to store the Galera configuration files. + It defaults to false, which implies that a dedicated volume for the Galera configuration files is provisioned. + type: boolean + volumeClaimTemplate: + description: VolumeClaimTemplate is a template for the PVC + that will contain the Galera configuration files shared + between the InitContainer, Agent and MariaDB. + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + metadata: + description: Metadata to be added to the PVC metadata. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + resources: + description: VolumeResourceRequirements describes the + storage resource requirements for a volume. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + storageClassName: + type: string + type: object + type: object + enabled: + description: Enabled is a flag to enable Galera. + type: boolean + galeraLibPath: + description: |- + GaleraLibPath is a path inside the MariaDB image to the wsrep provider plugin. It is defaulted if not provided. + More info: https://galeracluster.com/library/documentation/mysql-wsrep-options.html#wsrep-provider. + type: string + initContainer: + description: InitContainer is an init container that runs in the + MariaDB Pod and co-operates with mariadb-operator. + properties: + args: + description: Args to be used in the Container. + items: + type: string + type: array + command: + description: Command to be used in the Container. + items: + type: string + type: array + env: + description: Env represents the environment variables to be + injected in a container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + type: string + valueFrom: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + configMapKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#configmapkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#objectfieldselector-v1-core.' + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#secretkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: EnvFrom represents the references (via ConfigMap + and Secrets) to environment variables to be injected in + the container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envfromsource-v1-core.' + properties: + configMapRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + prefix: + type: string + secretRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: object + type: array + image: + description: Image name to be used by the MariaDB instances. + The supported format is `:`. + type: string + imagePullPolicy: + description: ImagePullPolicy is the image pull policy. One + of `Always`, `Never` or `IfNotPresent`. If not defined, + it defaults to `IfNotPresent`. + enum: + - Always + - Never + - IfNotPresent + type: string + livenessProbe: + description: LivenessProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used + for connection to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + readinessProbe: + description: ReadinessProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used + for connection to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + type: object + securityContext: + description: SecurityContext holds security configuration + that will be applied to a container. + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + description: Adds and removes POSIX capabilities from + running containers. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + type: object + startupProbe: + description: StartupProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used + for connection to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + volumeMounts: + description: VolumeMounts to be used in the Container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#volumemount-v1-core.' + properties: + mountPath: + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + type: boolean + subPath: + type: string + required: + - mountPath + - name + type: object + type: array + required: + - image + type: object + initJob: + description: InitJob defines a Job that co-operates with mariadb-operator + by performing initialization tasks. + properties: + metadata: + description: Metadata defines additional metadata for the + Galera init Job. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + type: object + type: object + primary: + description: Primary is the Galera configuration for the primary + node. + properties: + autoFailover: + description: AutoFailover indicates whether the operator should + automatically update PodIndex to perform an automatic primary + failover. + type: boolean + podIndex: + description: PodIndex is the StatefulSet index of the primary + node. The user may change this field to perform a manual + switchover. + type: integer + type: object + providerOptions: + additionalProperties: + type: string + description: |- + ProviderOptions is map of Galera configuration parameters. + More info: https://mariadb.com/kb/en/galera-cluster-system-variables/#wsrep_provider_options. + type: object + recovery: + description: |- + GaleraRecovery is the recovery process performed by the operator whenever the Galera cluster is not healthy. + More info: https://galeracluster.com/library/documentation/crash-recovery.html. + properties: + clusterBootstrapTimeout: + description: |- + ClusterBootstrapTimeout is the time limit for bootstrapping a cluster. + Once this timeout is reached, the Galera recovery state is reset and a new cluster bootstrap will be attempted. + type: string + clusterDownscaleTimeout: + description: ClusterDownscaleTimeout represents the maximum + duration for downscaling the cluster's StatefulSet during + the recovery process. + type: string + clusterHealthyTimeout: + description: |- + ClusterHealthyTimeout represents the duration at which a Galera cluster, that consistently failed health checks, + is considered unhealthy, and consequently the Galera recovery process will be initiated by the operator. + type: string + clusterMonitorInterval: + description: ClusterMonitorInterval represents the interval + used to monitor the Galera cluster health. + type: string + clusterUpscaleTimeout: + description: ClusterUpscaleTimeout represents the maximum + duration for upscaling the cluster's StatefulSet during + the recovery process. + type: string + enabled: + description: Enabled is a flag to enable GaleraRecovery. + type: boolean + forceClusterBootstrapInPod: + description: |- + ForceClusterBootstrapInPod allows you to manually initiate the bootstrap process in a specific Pod. + IMPORTANT: Use this option only in exceptional circumstances. Not selecting the Pod with the highest sequence number may result in data loss. + IMPORTANT: Ensure you unset this field after completing the bootstrap to allow the operator to choose the appropriate Pod to bootstrap from in an event of cluster recovery. + type: string + job: + description: Job defines a Job that co-operates with mariadb-operator + by performing the Galera cluster recovery . + properties: + metadata: + description: Metadata defines additional metadata for + the Galera recovery Jobs. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + podAffinity: + description: PodAffinity indicates whether the recovery + Jobs should run in the same Node as the MariaDB Pods. + It defaults to true. + type: boolean + resources: + description: Resources describes the compute resource + requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + type: object + type: object + minClusterSize: + anyOf: + - type: integer + - type: string + description: |- + MinClusterSize is the minimum number of replicas to consider the cluster healthy. It can be either a number of replicas (1) or a percentage (50%). + If Galera consistently reports less replicas than this value for the given 'ClusterHealthyTimeout' interval, a cluster recovery is iniated. + It defaults to '1' replica, and it is highly recommendeded to keep this value at '1' in most cases. + If set to more than one replica, the cluster recovery process may restart the healthy replicas as well. + x-kubernetes-int-or-string: true + podRecoveryTimeout: + description: PodRecoveryTimeout is the time limit for recevorying + the sequence of a Pod during the cluster recovery. + type: string + podSyncTimeout: + description: PodSyncTimeout is the time limit for a Pod to + join the cluster after having performed a cluster bootstrap + during the cluster recovery. + type: string + type: object + replicaThreads: + description: |- + ReplicaThreads is the number of replica threads used to apply Galera write sets in parallel. + More info: https://mariadb.com/kb/en/galera-cluster-system-variables/#wsrep_slave_threads. + type: integer + sst: + description: |- + SST is the Snapshot State Transfer used when new Pods join the cluster. + More info: https://galeracluster.com/library/documentation/sst.html. + enum: + - rsync + - mariabackup + - mysqldump + type: string + type: object + image: + description: |- + Image name to be used by the MariaDB instances. The supported format is `:`. + Only MariaDB official images are supported. + type: string + imagePullPolicy: + description: ImagePullPolicy is the image pull policy. One of `Always`, + `Never` or `IfNotPresent`. If not defined, it defaults to `IfNotPresent`. + enum: + - Always + - Never + - IfNotPresent + type: string + imagePullSecrets: + description: ImagePullSecrets is the list of pull Secrets to be used + to pull the image. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: array + inheritMetadata: + description: InheritMetadata defines the metadata to be inherited + by children resources. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + initContainers: + description: InitContainers to be used in the Pod. + items: + description: Container object definition. + properties: + args: + description: Args to be used in the Container. + items: + type: string + type: array + command: + description: Command to be used in the Container. + items: + type: string + type: array + env: + description: Env represents the environment variables to be + injected in a container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + name: + description: Name of the environment variable. Must be + a C_IDENTIFIER. + type: string + value: + type: string + valueFrom: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + configMapKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#configmapkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#objectfieldselector-v1-core.' + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#secretkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + image: + description: Image name to be used by the container. The supported + format is `:`. + type: string + imagePullPolicy: + description: ImagePullPolicy is the image pull policy. One of + `Always`, `Never` or `IfNotPresent`. If not defined, it defaults + to `IfNotPresent`. + enum: + - Always + - Never + - IfNotPresent + type: string + name: + description: Name to be given to the container. + type: string + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + type: object + volumeMounts: + description: VolumeMounts to be used in the Container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#volumemount-v1-core.' + properties: + mountPath: + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + type: boolean + subPath: + type: string + required: + - mountPath + - name + type: object + type: array + required: + - image + type: object + type: array + livenessProbe: + description: LivenessProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used for connection + to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + maxScale: + description: |- + MaxScale is the MaxScale specification that defines the MaxScale resource to be used with the current MariaDB. + When enabling this field, MaxScaleRef is automatically set. + properties: + admin: + description: Admin configures the admin REST API and GUI. + properties: + guiEnabled: + description: GuiEnabled indicates whether the admin GUI should + be enabled. + type: boolean + port: + description: Port where the admin REST API and GUI will be + exposed. + format: int32 + type: integer + type: object + auth: + description: Auth defines the credentials required for MaxScale + to connect to MariaDB. + properties: + adminPasswordSecretKeyRef: + description: AdminPasswordSecretKeyRef is Secret key reference + to the admin password to call the admin REST API. It is + defaulted if not provided. + properties: + generate: + default: false + description: Generate indicates whether the Secret should + be generated if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + adminUsername: + description: AdminUsername is an admin username to call the + admin REST API. It is defaulted if not provided. + type: string + clientMaxConnections: + description: |- + ClientMaxConnections defines the maximum number of connections that the client can establish. + If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. + It defaults to 30 times the number of MaxScale replicas. + format: int32 + type: integer + clientPasswordSecretKeyRef: + description: |- + ClientPasswordSecretKeyRef is Secret key reference to the password to connect to MaxScale. It is defaulted if not provided. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. + properties: + generate: + default: false + description: Generate indicates whether the Secret should + be generated if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + clientUsername: + description: ClientUsername is the user to connect to MaxScale. + It is defaulted if not provided. + type: string + deleteDefaultAdmin: + description: DeleteDefaultAdmin determines whether the default + admin user should be deleted after the initial configuration. + If not provided, it defaults to true. + type: boolean + generate: + description: |- + Generate defies whether the operator should generate users and grants for MaxScale to work. + It only supports MariaDBs specified via spec.mariaDbRef. + type: boolean + metricsPasswordSecretKeyRef: + description: MetricsPasswordSecretKeyRef is Secret key reference + to the metrics password to call the admib REST API. It is + defaulted if metrics are enabled. + properties: + generate: + default: false + description: Generate indicates whether the Secret should + be generated if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + metricsUsername: + description: MetricsUsername is an metrics username to call + the REST API. It is defaulted if metrics are enabled. + type: string + monitorMaxConnections: + description: |- + MonitorMaxConnections defines the maximum number of connections that the monitor can establish. + If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. + It defaults to 30 times the number of MaxScale replicas. + format: int32 + type: integer + monitorPasswordSecretKeyRef: + description: |- + MonitorPasswordSecretKeyRef is Secret key reference to the password used by MaxScale monitor to connect to MariaDB server. It is defaulted if not provided. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. + properties: + generate: + default: false + description: Generate indicates whether the Secret should + be generated if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + monitorUsername: + description: MonitorUsername is the user used by MaxScale + monitor to connect to MariaDB server. It is defaulted if + not provided. + type: string + serverMaxConnections: + description: |- + ServerMaxConnections defines the maximum number of connections that the server can establish. + If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. + It defaults to 30 times the number of MaxScale replicas. + format: int32 + type: integer + serverPasswordSecretKeyRef: + description: |- + ServerPasswordSecretKeyRef is Secret key reference to the password used by MaxScale to connect to MariaDB server. It is defaulted if not provided. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. + properties: + generate: + default: false + description: Generate indicates whether the Secret should + be generated if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + serverUsername: + description: ServerUsername is the user used by MaxScale to + connect to MariaDB server. It is defaulted if not provided. + type: string + syncMaxConnections: + description: |- + SyncMaxConnections defines the maximum number of connections that the sync can establish. + If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. + It defaults to 30 times the number of MaxScale replicas. + format: int32 + type: integer + syncPasswordSecretKeyRef: + description: |- + SyncPasswordSecretKeyRef is Secret key reference to the password used by MaxScale config to connect to MariaDB server. It is defaulted when HA is enabled. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. + properties: + generate: + default: false + description: Generate indicates whether the Secret should + be generated if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + syncUsername: + description: MonitoSyncUsernamerUsername is the user used + by MaxScale config sync to connect to MariaDB server. It + is defaulted when HA is enabled. + type: string + type: object + config: + description: Config defines the MaxScale configuration. + properties: + params: + additionalProperties: + type: string + description: |- + Params is a key value pair of parameters to be used in the MaxScale static configuration file. + Any parameter supported by MaxScale may be specified here. See reference: + https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#global-settings. + type: object + sync: + description: Sync defines how to replicate configuration across + MaxScale replicas. It is defaulted when HA is enabled. + properties: + database: + description: Database is the MariaDB logical database + where the 'maxscale_config' table will be created in + order to persist and synchronize config changes. If + not provided, it defaults to 'mysql'. + type: string + interval: + description: Interval defines the config synchronization + interval. It is defaulted if not provided. + type: string + timeout: + description: Interval defines the config synchronization + timeout. It is defaulted if not provided. + type: string + type: object + volumeClaimTemplate: + description: VolumeClaimTemplate provides a template to define + the PVCs for storing MaxScale runtime configuration files. + It is defaulted if not provided. + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + metadata: + description: Metadata to be added to the PVC metadata. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + resources: + description: VolumeResourceRequirements describes the + storage resource requirements for a volume. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + storageClassName: + type: string + type: object + type: object + connection: + description: Connection provides a template to define the Connection + for MaxScale. + properties: + healthCheck: + description: HealthCheck to be used in the Connection. + properties: + interval: + description: Interval used to perform health checks. + type: string + retryInterval: + description: RetryInterval is the interval used to perform + health check retries. + type: string + type: object + params: + additionalProperties: + type: string + description: Params to be used in the Connection. + type: object + port: + description: Port to connect to. If not provided, it defaults + to the MariaDB port or to the first MaxScale listener. + format: int32 + type: integer + secretName: + description: SecretName to be used in the Connection. + type: string + secretTemplate: + description: SecretTemplate to be used in the Connection. + properties: + databaseKey: + description: DatabaseKey to be used in the Secret. + type: string + format: + description: Format to be used in the Secret. + type: string + hostKey: + description: HostKey to be used in the Secret. + type: string + key: + description: Key to be used in the Secret. + type: string + metadata: + description: Metadata to be added to the Secret object. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + passwordKey: + description: PasswordKey to be used in the Secret. + type: string + portKey: + description: PortKey to be used in the Secret. + type: string + usernameKey: + description: UsernameKey to be used in the Secret. + type: string + type: object + serviceName: + description: ServiceName to be used in the Connection. + type: string + type: object + enabled: + description: Enabled is a flag to enable a MaxScale instance to + be used with the current MariaDB. + type: boolean + guiKubernetesService: + description: GuiKubernetesService define a template for a Kubernetes + Service object to connect to MaxScale's GUI. + properties: + allocateLoadBalancerNodePorts: + description: AllocateLoadBalancerNodePorts Service field. + type: boolean + externalTrafficPolicy: + description: ExternalTrafficPolicy Service field. + type: string + loadBalancerIP: + description: LoadBalancerIP Service field. + type: string + loadBalancerSourceRanges: + description: LoadBalancerSourceRanges Service field. + items: + type: string + type: array + metadata: + description: Metadata to be added to the Service metadata. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + sessionAffinity: + description: SessionAffinity Service field. + type: string + type: + default: ClusterIP + description: Type is the Service type. One of `ClusterIP`, + `NodePort` or `LoadBalancer`. If not defined, it defaults + to `ClusterIP`. + enum: + - ClusterIP + - NodePort + - LoadBalancer + type: string + type: object + image: + description: |- + Image name to be used by the MaxScale instances. The supported format is `:`. + Only MariaDB official images are supported. + type: string + imagePullPolicy: + description: ImagePullPolicy is the image pull policy. One of + `Always`, `Never` or `IfNotPresent`. If not defined, it defaults + to `IfNotPresent`. + enum: + - Always + - Never + - IfNotPresent + type: string + kubernetesService: + description: KubernetesService defines a template for a Kubernetes + Service object to connect to MaxScale. + properties: + allocateLoadBalancerNodePorts: + description: AllocateLoadBalancerNodePorts Service field. + type: boolean + externalTrafficPolicy: + description: ExternalTrafficPolicy Service field. + type: string + loadBalancerIP: + description: LoadBalancerIP Service field. + type: string + loadBalancerSourceRanges: + description: LoadBalancerSourceRanges Service field. + items: + type: string + type: array + metadata: + description: Metadata to be added to the Service metadata. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + sessionAffinity: + description: SessionAffinity Service field. + type: string + type: + default: ClusterIP + description: Type is the Service type. One of `ClusterIP`, + `NodePort` or `LoadBalancer`. If not defined, it defaults + to `ClusterIP`. + enum: + - ClusterIP + - NodePort + - LoadBalancer + type: string + type: object + metrics: + description: Metrics configures metrics and how to scrape them. + properties: + enabled: + description: Enabled is a flag to enable Metrics + type: boolean + exporter: + description: Exporter defines the metrics exporter container. + properties: + affinity: + description: Affinity to be used in the Pod. + properties: + antiAffinityEnabled: + description: |- + AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. + Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. + type: boolean + nodeAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeaffinity-v1-core' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#preferredschedulingterm-v1-core' + properties: + preference: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselector-v1-core' + properties: + nodeSelectorTerms: + items: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + type: object + podAntiAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podantiaffinity-v1-core.' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#weightedpodaffinityterm-v1-core.' + properties: + podAffinityTerm: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector + operator is the set of operators + that can be used in a selector + requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector + operator is the set of operators + that can be used in a selector + requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + args: + description: Args to be used in the Container. + items: + type: string + type: array + image: + description: |- + Image name to be used as metrics exporter. The supported format is `:`. + Only mysqld-exporter >= v0.15.0 is supported: https://github.com/prometheus/mysqld_exporter + type: string + imagePullPolicy: + description: ImagePullPolicy is the image pull policy. + One of `Always`, `Never` or `IfNotPresent`. If not defined, + it defaults to `IfNotPresent`. + enum: + - Always + - Never + - IfNotPresent + type: string + imagePullSecrets: + description: ImagePullSecrets is the list of pull Secrets + to be used to pull the image. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: array + nodeSelector: + additionalProperties: + type: string + description: NodeSelector to be used in the Pod. + type: object + podMetadata: + description: PodMetadata defines extra metadata for the + Pod. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + podSecurityContext: + description: SecurityContext holds pod-level security + attributes and common container settings. + properties: + appArmorProfile: + description: AppArmorProfile defines a pod or container's + AppArmor settings. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + PodFSGroupChangePolicy holds policies that will be used for applying fsGroup to a volume + when volume is mounted. + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + description: SELinuxOptions are the labels to be applied + to the container + properties: + level: + description: Level is SELinux level label that + applies to the container. + type: string + role: + description: Role is a SELinux role label that + applies to the container. + type: string + type: + description: Type is a SELinux type label that + applies to the container. + type: string + user: + description: User is a SELinux user label that + applies to the container. + type: string + type: object + seccompProfile: + description: |- + SeccompProfile defines a pod/container's seccomp profile settings. + Only one profile source may be set. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + type: object + port: + description: Port where the exporter will be listening + for connections. + format: int32 + type: integer + priorityClassName: + description: PriorityClassName to be used in the Pod. + type: string + resources: + description: Resources describes the compute resource + requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + type: object + securityContext: + description: SecurityContext holds container-level security + attributes. + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + description: Adds and removes POSIX capabilities from + running containers. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + type: object + tolerations: + description: Tolerations to be used in the Pod. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + serviceMonitor: + description: ServiceMonitor defines the ServiceMonior object. + properties: + interval: + description: Interval for scraping metrics. + type: string + jobLabel: + description: JobLabel to add to the ServiceMonitor object. + type: string + prometheusRelease: + description: PrometheusRelease is the release label to + add to the ServiceMonitor object. + type: string + scrapeTimeout: + description: ScrapeTimeout defines the timeout for scraping + metrics. + type: string + type: object + type: object + monitor: + description: Monitor monitors MariaDB server instances. + properties: + cooperativeMonitoring: + description: CooperativeMonitoring enables coordination between + multiple MaxScale instances running monitors. It is defaulted + when HA is enabled. + enum: + - majority_of_all + - majority_of_running + type: string + interval: + description: Interval used to monitor MariaDB servers. It + is defaulted if not provided. + type: string + module: + description: Module is the module to use to monitor MariaDB + servers. It is mandatory when no MariaDB reference is provided. + type: string + name: + description: Name is the identifier of the monitor. It is + defaulted if not provided. + type: string + params: + additionalProperties: + type: string + description: |- + Params defines extra parameters to pass to the monitor. + Any parameter supported by MaxScale may be specified here. See reference: + https://mariadb.com/kb/en/mariadb-maxscale-2308-common-monitor-parameters/. + Monitor specific parameter are also supported: + https://mariadb.com/kb/en/mariadb-maxscale-2308-galera-monitor/#galera-monitor-optional-parameters. + https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-monitor/#configuration. + type: object + suspend: + default: false + description: |- + Suspend indicates whether the current resource should be suspended or not. + This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. + type: boolean + type: object + podDisruptionBudget: + description: PodDisruptionBudget defines the budget for replica + availability. + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + description: MaxUnavailable defines the number of maximum + unavailable Pods. + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + description: MinAvailable defines the number of minimum available + Pods. + x-kubernetes-int-or-string: true + type: object + replicas: + description: Replicas indicates the number of desired instances. + format: int32 + type: integer + requeueInterval: + description: RequeueInterval is used to perform requeue reconciliations. + type: string + services: + description: Services define how the traffic is forwarded to the + MariaDB servers. + items: + description: Services define how the traffic is forwarded to + the MariaDB servers. + properties: + listener: + description: MaxScaleListener defines how the MaxScale server + will listen for connections. + properties: + name: + description: Name is the identifier of the listener. + It is defaulted if not provided + type: string + params: + additionalProperties: + type: string + description: |- + Params defines extra parameters to pass to the listener. + Any parameter supported by MaxScale may be specified here. See reference: + https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#listener_1. + type: object + port: + description: Port is the network port where the MaxScale + server will listen. + format: int32 + type: integer + protocol: + description: Protocol is the MaxScale protocol to use + when communicating with the client. If not provided, + it defaults to MariaDBProtocol. + type: string + suspend: + default: false + description: |- + Suspend indicates whether the current resource should be suspended or not. + This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. + type: boolean + required: + - port + type: object + name: + description: Name is the identifier of the MaxScale service. + type: string + params: + additionalProperties: + type: string + description: |- + Params defines extra parameters to pass to the service. + Any parameter supported by MaxScale may be specified here. See reference: + https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#service_1. + Router specific parameter are also supported: + https://mariadb.com/kb/en/mariadb-maxscale-2308-readwritesplit/#configuration. + https://mariadb.com/kb/en/mariadb-maxscale-2308-readconnroute/#configuration. + type: object + router: + description: Router is the type of router to use. + enum: + - readwritesplit + - readconnroute + type: string + suspend: + default: false + description: |- + Suspend indicates whether the current resource should be suspended or not. + This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. + type: boolean + required: + - listener + - name + - router + type: object + type: array + tls: + description: TLS defines the PKI to be used with MaxScale. + properties: + adminCASecretRef: + description: |- + AdminCASecretRef is a reference to a Secret containing the admin certificate authority keypair. It is used to establish trust and issue certificates for the MaxScale's administrative REST API and GUI. + One of: + - Secret containing both the 'ca.crt' and 'ca.key' keys. This allows you to bring your own CA to Kubernetes to issue certificates. + - Secret containing only the 'ca.crt' in order to establish trust. In this case, either adminCertSecretRef or adminCertIssuerRef fields must be provided. + If not provided, a self-signed CA will be provisioned to issue the server certificate. + properties: + name: + default: "" + type: string + type: object + adminCertIssuerRef: + description: |- + AdminCertIssuerRef is a reference to a cert-manager issuer object used to issue the MaxScale's administrative REST API and GUI certificate. cert-manager must be installed previously in the cluster. + It is mutually exclusive with adminCertSecretRef. + By default, the Secret field 'ca.crt' provisioned by cert-manager will be added to the trust chain. A custom trust bundle may be specified via adminCASecretRef. + properties: + group: + description: Group of the resource being referred to. + type: string + kind: + description: Kind of the resource being referred to. + type: string + name: + description: Name of the resource being referred to. + type: string + required: + - name + type: object + adminCertSecretRef: + description: AdminCertSecretRef is a reference to a TLS Secret + used by the MaxScale's administrative REST API and GUI. + properties: + name: + default: "" + type: string + type: object + enabled: + description: |- + Enabled indicates whether TLS is enabled, determining if certificates should be issued and mounted to the MaxScale instance. + It is enabled by default when the referred MariaDB instance (via mariaDbRef) has TLS enabled and enforced. + type: boolean + listenerCASecretRef: + description: |- + ListenerCASecretRef is a reference to a Secret containing the listener certificate authority keypair. It is used to establish trust and issue certificates for the MaxScale's listeners. + One of: + - Secret containing both the 'ca.crt' and 'ca.key' keys. This allows you to bring your own CA to Kubernetes to issue certificates. + - Secret containing only the 'ca.crt' in order to establish trust. In this case, either listenerCertSecretRef or listenerCertIssuerRef fields must be provided. + If not provided, a self-signed CA will be provisioned to issue the listener certificate. + properties: + name: + default: "" + type: string + type: object + listenerCertIssuerRef: + description: |- + ListenerCertIssuerRef is a reference to a cert-manager issuer object used to issue the MaxScale's listeners certificate. cert-manager must be installed previously in the cluster. + It is mutually exclusive with listenerCertSecretRef. + By default, the Secret field 'ca.crt' provisioned by cert-manager will be added to the trust chain. A custom trust bundle may be specified via listenerCASecretRef. + properties: + group: + description: Group of the resource being referred to. + type: string + kind: + description: Kind of the resource being referred to. + type: string + name: + description: Name of the resource being referred to. + type: string + required: + - name + type: object + listenerCertSecretRef: + description: ListenerCertSecretRef is a reference to a TLS + Secret used by the MaxScale's listeners. + properties: + name: + default: "" + type: string + type: object + replicationSSLEnabled: + description: |- + ReplicationSSLEnabled specifies whether the replication SSL is enabled. If enabled, the SSL options will be added to the server configuration. + It is enabled by default when the referred MariaDB instance (via mariaDbRef) has replication enabled. + If the MariaDB servers are manually provided by the user via the 'servers' field, this must be set by the user as well. + type: boolean + serverCASecretRef: + description: |- + ServerCASecretRef is a reference to a Secret containing the MariaDB server CA certificates. It is used to establish trust with MariaDB servers. + The Secret should contain a 'ca.crt' key in order to establish trust. + If not provided, and the reference to a MariaDB resource is set (mariaDbRef), it will be defaulted to the referred MariaDB CA bundle. + properties: + name: + default: "" + type: string + type: object + serverCertSecretRef: + description: |- + ServerCertSecretRef is a reference to a TLS Secret used by MaxScale to connect to the MariaDB servers. + If not provided, and the reference to a MariaDB resource is set (mariaDbRef), it will be defaulted to the referred MariaDB client certificate (clientCertSecretRef). + properties: + name: + default: "" + type: string + type: object + verifyPeerCertificate: + description: |- + VerifyPeerCertificate specifies whether the peer certificate's signature should be validated against the CA. + It is disabled by default. + type: boolean + verifyPeerHost: + description: |- + VerifyPeerHost specifies whether the peer certificate's SANs should match the peer host. + It is disabled by default. + type: boolean + type: object + updateStrategy: + description: UpdateStrategy defines the update strategy for the + StatefulSet object. + properties: + rollingUpdate: + description: RollingUpdate is used to communicate parameters + when Type is RollingUpdateStatefulSetStrategyType. + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + description: |- + The maximum number of pods that can be unavailable during the update. + Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + Absolute number is calculated from percentage by rounding up. This can not be 0. + Defaults to 1. This field is alpha-level and is only honored by servers that enable the + MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to + Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it + will be counted towards MaxUnavailable. + x-kubernetes-int-or-string: true + partition: + description: |- + Partition indicates the ordinal at which the StatefulSet should be partitioned + for updates. During a rolling update, all pods from ordinal Replicas-1 to + Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. + This is helpful in being able to do a canary based deployment. The default value is 0. + format: int32 + type: integer + type: object + type: + description: |- + Type indicates the type of the StatefulSetUpdateStrategy. + Default is RollingUpdate. + type: string + type: object + type: object + maxScaleRef: + description: |- + MaxScaleRef is a reference to a MaxScale resource to be used with the current MariaDB. + Providing this field implies delegating high availability tasks such as primary failover to MaxScale. + properties: + name: + type: string + namespace: + type: string + type: object + metrics: + description: Metrics configures metrics and how to scrape them. + properties: + enabled: + description: Enabled is a flag to enable Metrics + type: boolean + exporter: + description: Exporter defines the metrics exporter container. + properties: + affinity: + description: Affinity to be used in the Pod. + properties: + antiAffinityEnabled: + description: |- + AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. + Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. + type: boolean + nodeAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeaffinity-v1-core' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#preferredschedulingterm-v1-core' + properties: + preference: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselector-v1-core' + properties: + nodeSelectorTerms: + items: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + type: object + podAntiAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podantiaffinity-v1-core.' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#weightedpodaffinityterm-v1-core.' + properties: + podAffinityTerm: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector + operator is the set of operators + that can be used in a selector + requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector operator + is the set of operators that can + be used in a selector requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + args: + description: Args to be used in the Container. + items: + type: string + type: array + image: + description: |- + Image name to be used as metrics exporter. The supported format is `:`. + Only mysqld-exporter >= v0.15.0 is supported: https://github.com/prometheus/mysqld_exporter + type: string + imagePullPolicy: + description: ImagePullPolicy is the image pull policy. One + of `Always`, `Never` or `IfNotPresent`. If not defined, + it defaults to `IfNotPresent`. + enum: + - Always + - Never + - IfNotPresent + type: string + imagePullSecrets: + description: ImagePullSecrets is the list of pull Secrets + to be used to pull the image. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: array + nodeSelector: + additionalProperties: + type: string + description: NodeSelector to be used in the Pod. + type: object + podMetadata: + description: PodMetadata defines extra metadata for the Pod. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + podSecurityContext: + description: SecurityContext holds pod-level security attributes + and common container settings. + properties: + appArmorProfile: + description: AppArmorProfile defines a pod or container's + AppArmor settings. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + PodFSGroupChangePolicy holds policies that will be used for applying fsGroup to a volume + when volume is mounted. + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + description: SELinuxOptions are the labels to be applied + to the container + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: |- + SeccompProfile defines a pod/container's seccomp profile settings. + Only one profile source may be set. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + type: object + port: + description: Port where the exporter will be listening for + connections. + format: int32 + type: integer + priorityClassName: + description: PriorityClassName to be used in the Pod. + type: string + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + type: object + securityContext: + description: SecurityContext holds container-level security + attributes. + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + description: Adds and removes POSIX capabilities from + running containers. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + type: object + tolerations: + description: Tolerations to be used in the Pod. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + passwordSecretKeyRef: + description: |- + PasswordSecretKeyRef is a reference to the password of the monitoring user used by the exporter. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. + properties: + generate: + default: false + description: Generate indicates whether the Secret should + be generated if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + serviceMonitor: + description: ServiceMonitor defines the ServiceMonior object. + properties: + interval: + description: Interval for scraping metrics. + type: string + jobLabel: + description: JobLabel to add to the ServiceMonitor object. + type: string + prometheusRelease: + description: PrometheusRelease is the release label to add + to the ServiceMonitor object. + type: string + scrapeTimeout: + description: ScrapeTimeout defines the timeout for scraping + metrics. + type: string + type: object + username: + description: Username is the username of the monitoring user used + by the exporter. + type: string + type: object + myCnf: + description: |- + MyCnf allows to specify the my.cnf file mounted by Mariadb. + Updating this field will trigger an update to the Mariadb resource. + type: string + myCnfConfigMapKeyRef: + description: |- + MyCnfConfigMapKeyRef is a reference to the my.cnf config file provided via a ConfigMap. + If not provided, it will be defaulted with a reference to a ConfigMap containing the MyCnf field. + If the referred ConfigMap is labeled with "k8s.mariadb.com/watch", an update to the Mariadb resource will be triggered when the ConfigMap is updated. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + nodeSelector: + additionalProperties: + type: string + description: NodeSelector to be used in the Pod. + type: object + passwordHashSecretKeyRef: + description: |- + PasswordHashSecretKeyRef is a reference to the password hash to be used by the initial User. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password hash. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + passwordPlugin: + description: PasswordPlugin is a reference to the password plugin + and arguments to be used by the initial User. + properties: + pluginArgSecretKeyRef: + description: |- + PluginArgSecretKeyRef is a reference to the arguments to be provided to the authentication plugin for the User. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the authentication plugin arguments. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + pluginNameSecretKeyRef: + description: |- + PluginNameSecretKeyRef is a reference to the authentication plugin to be used by the User. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the authentication plugin. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + passwordSecretKeyRef: + description: |- + PasswordSecretKeyRef is a reference to a Secret that contains the password to be used by the initial User. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. + properties: + generate: + default: false + description: Generate indicates whether the Secret should be generated + if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + podDisruptionBudget: + description: PodDisruptionBudget defines the budget for replica availability. + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + description: MaxUnavailable defines the number of maximum unavailable + Pods. + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + description: MinAvailable defines the number of minimum available + Pods. + x-kubernetes-int-or-string: true + type: object + podMetadata: + description: PodMetadata defines extra metadata for the Pod. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + podSecurityContext: + description: SecurityContext holds pod-level security attributes and + common container settings. + properties: + appArmorProfile: + description: AppArmorProfile defines a pod or container's AppArmor + settings. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + PodFSGroupChangePolicy holds policies that will be used for applying fsGroup to a volume + when volume is mounted. + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + description: SELinuxOptions are the labels to be applied to the + container + properties: + level: + description: Level is SELinux level label that applies to + the container. + type: string + role: + description: Role is a SELinux role label that applies to + the container. + type: string + type: + description: Type is a SELinux type label that applies to + the container. + type: string + user: + description: User is a SELinux user label that applies to + the container. + type: string + type: object + seccompProfile: + description: |- + SeccompProfile defines a pod/container's seccomp profile settings. + Only one profile source may be set. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + type: object + port: + default: 3306 + description: Port where the instances will be listening for connections. + format: int32 + type: integer + primaryConnection: + description: |- + PrimaryConnection defines a template to configure the primary Connection object. + This Connection provides the initial User access to the initial Database. + It will make use of the PrimaryService to route network traffic to the primary Pod. + properties: + healthCheck: + description: HealthCheck to be used in the Connection. + properties: + interval: + description: Interval used to perform health checks. + type: string + retryInterval: + description: RetryInterval is the interval used to perform + health check retries. + type: string + type: object + params: + additionalProperties: + type: string + description: Params to be used in the Connection. + type: object + port: + description: Port to connect to. If not provided, it defaults + to the MariaDB port or to the first MaxScale listener. + format: int32 + type: integer + secretName: + description: SecretName to be used in the Connection. + type: string + secretTemplate: + description: SecretTemplate to be used in the Connection. + properties: + databaseKey: + description: DatabaseKey to be used in the Secret. + type: string + format: + description: Format to be used in the Secret. + type: string + hostKey: + description: HostKey to be used in the Secret. + type: string + key: + description: Key to be used in the Secret. + type: string + metadata: + description: Metadata to be added to the Secret object. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + passwordKey: + description: PasswordKey to be used in the Secret. + type: string + portKey: + description: PortKey to be used in the Secret. + type: string + usernameKey: + description: UsernameKey to be used in the Secret. + type: string + type: object + serviceName: + description: ServiceName to be used in the Connection. + type: string + type: object + primaryService: + description: |- + PrimaryService defines a template to configure the primary Service object. + The network traffic of this Service will be routed to the primary Pod. + properties: + allocateLoadBalancerNodePorts: + description: AllocateLoadBalancerNodePorts Service field. + type: boolean + externalTrafficPolicy: + description: ExternalTrafficPolicy Service field. + type: string + loadBalancerIP: + description: LoadBalancerIP Service field. + type: string + loadBalancerSourceRanges: + description: LoadBalancerSourceRanges Service field. + items: + type: string + type: array + metadata: + description: Metadata to be added to the Service metadata. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + sessionAffinity: + description: SessionAffinity Service field. + type: string + type: + default: ClusterIP + description: Type is the Service type. One of `ClusterIP`, `NodePort` + or `LoadBalancer`. If not defined, it defaults to `ClusterIP`. + enum: + - ClusterIP + - NodePort + - LoadBalancer + type: string + type: object + priorityClassName: + description: PriorityClassName to be used in the Pod. + type: string + readinessProbe: + description: ReadinessProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used for connection + to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + replicas: + default: 1 + description: Replicas indicates the number of desired instances. + format: int32 + type: integer + replicasAllowEvenNumber: + default: false + description: disables the validation check for an odd number of replicas. + type: boolean + replication: + description: Replication configures high availability via replication. + This feature is still in alpha, use Galera if you are looking for + a more production-ready HA. + properties: + agent: + description: Agent is a sidecar agent that runs in the MariaDB + Pod and co-operates with mariadb-operator. + properties: + args: + description: Args to be used in the Container. + items: + type: string + type: array + basicAuth: + description: BasicAuth to be used by the agent container + properties: + enabled: + description: Enabled is a flag to enable BasicAuth + type: boolean + passwordSecretKeyRef: + description: PasswordSecretKeyRef to be used for basic + authentication + properties: + generate: + default: false + description: Generate indicates whether the Secret + should be generated if the Secret referenced is + not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: Username to be used for basic authentication + type: string + type: object + command: + description: Command to be used in the Container. + items: + type: string + type: array + env: + description: Env represents the environment variables to be + injected in a container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + type: string + valueFrom: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + configMapKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#configmapkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#objectfieldselector-v1-core.' + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#secretkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: EnvFrom represents the references (via ConfigMap + and Secrets) to environment variables to be injected in + the container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envfromsource-v1-core.' + properties: + configMapRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + prefix: + type: string + secretRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: object + type: array + gracefulShutdownTimeout: + description: GracefulShutdownTimeout is the time we give to + the agent container in order to gracefully terminate in-flight + requests. + type: string + image: + description: Image name to be used by the MariaDB instances. + The supported format is `:`. + type: string + imagePullPolicy: + description: ImagePullPolicy is the image pull policy. One + of `Always`, `Never` or `IfNotPresent`. If not defined, + it defaults to `IfNotPresent`. + enum: + - Always + - Never + - IfNotPresent + type: string + kubernetesAuth: + description: KubernetesAuth to be used by the agent container + properties: + authDelegatorRoleName: + description: |- + AuthDelegatorRoleName is the name of the ClusterRoleBinding that is associated with the "system:auth-delegator" ClusterRole. + It is necessary for creating TokenReview objects in order for the agent to validate the service account token. + type: string + enabled: + description: Enabled is a flag to enable KubernetesAuth + type: boolean + type: object + livenessProbe: + description: LivenessProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used + for connection to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + port: + description: Port where the agent will be listening for API + connections. + format: int32 + type: integer + probePort: + description: Port where the agent will be listening for probe + connections. + format: int32 + type: integer + readinessProbe: + description: ReadinessProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used + for connection to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + type: object + securityContext: + description: SecurityContext holds security configuration + that will be applied to a container. + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + description: Adds and removes POSIX capabilities from + running containers. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + type: object + startupProbe: + description: StartupProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used + for connection to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + volumeMounts: + description: VolumeMounts to be used in the Container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#volumemount-v1-core.' + properties: + mountPath: + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + type: boolean + subPath: + type: string + required: + - mountPath + - name + type: object + type: array + type: object + enabled: + description: Enabled is a flag to enable replication. + type: boolean + gtidStrictMode: + description: |- + GtidStrictMode determines whether the GTID strict mode is enabled. + See: https://mariadb.com/docs/server/ha-and-performance/standard-replication/gtid#gtid_strict_mode. + It is enabled by default. + type: boolean + initContainer: + description: InitContainer is an init container that runs in the + MariaDB Pod and co-operates with mariadb-operator. + properties: + args: + description: Args to be used in the Container. + items: + type: string + type: array + command: + description: Command to be used in the Container. + items: + type: string + type: array + env: + description: Env represents the environment variables to be + injected in a container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + name: + description: Name of the environment variable. Must + be a C_IDENTIFIER. + type: string + value: + type: string + valueFrom: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + configMapKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#configmapkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#objectfieldselector-v1-core.' + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#secretkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: EnvFrom represents the references (via ConfigMap + and Secrets) to environment variables to be injected in + the container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envfromsource-v1-core.' + properties: + configMapRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + prefix: + type: string + secretRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: object + type: array + image: + description: Image name to be used by the MariaDB instances. + The supported format is `:`. + type: string + imagePullPolicy: + description: ImagePullPolicy is the image pull policy. One + of `Always`, `Never` or `IfNotPresent`. If not defined, + it defaults to `IfNotPresent`. + enum: + - Always + - Never + - IfNotPresent + type: string + livenessProbe: + description: LivenessProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used + for connection to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + readinessProbe: + description: ReadinessProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used + for connection to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + type: object + securityContext: + description: SecurityContext holds security configuration + that will be applied to a container. + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + description: Adds and removes POSIX capabilities from + running containers. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + type: object + startupProbe: + description: StartupProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used + for connection to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + volumeMounts: + description: VolumeMounts to be used in the Container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#volumemount-v1-core.' + properties: + mountPath: + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + type: boolean + subPath: + type: string + required: + - mountPath + - name + type: object + type: array + required: + - image + type: object + primary: + description: Primary is the replication configuration for the + primary node. + properties: + autoFailover: + description: |- + AutoFailover indicates whether the operator should automatically update PodIndex to perform an automatic primary failover. + It is enabled by default. + type: boolean + autoFailoverDelay: + description: |- + AutoFailoverDelay indicates the duration before performing an automatic primary failover. + By default, no extra delay is added. + type: string + podIndex: + description: PodIndex is the StatefulSet index of the primary + node. The user may change this field to perform a manual + switchover. + type: integer + type: object + replica: + description: ReplicaReplication is the replication configuration + for the replica nodes. + properties: + bootstrapFrom: + description: |- + ReplicaBootstrapFrom defines the data sources used to bootstrap new replicas. + This will be used as part of the scaling out and recovery operations, when new replicas are created. + If not provided, scale out and recovery operations will return an error. + properties: + physicalBackupTemplateRef: + description: |- + PhysicalBackupTemplateRef is a reference to a PhysicalBackup object that will be used as template to create a new PhysicalBackup object + used synchronize the data from an up to date replica to the new replica to be bootstrapped. + properties: + name: + default: "" + type: string + type: object + restoreJob: + description: RestoreJob defines additional properties + for the Job used to perform the restoration. + properties: + affinity: + description: Affinity to be used in the Pod. + properties: + antiAffinityEnabled: + description: |- + AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. + Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. + type: boolean + nodeAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeaffinity-v1-core' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#preferredschedulingterm-v1-core' + properties: + preference: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselector-v1-core' + properties: + nodeSelectorTerms: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + type: object + podAntiAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podantiaffinity-v1-core.' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#weightedpodaffinityterm-v1-core.' + properties: + podAffinityTerm: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the + Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector + operator is the set + of operators that can + be used in a selector + requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector + operator is the set of operators + that can be used in a selector + requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + args: + description: Args to be used in the Container. + items: + type: string + type: array + metadata: + description: Metadata defines additional metadata + for the bootstrap Jobs. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children + resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: NodeSelector to be used in the Pod. + type: object + resources: + description: Resources describes the compute resource + requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource + name, quantity) pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource + name, quantity) pairs. + type: object + type: object + tolerations: + description: Tolerations to be used in the Pod. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + required: + - physicalBackupTemplateRef + type: object + connectionRetrySeconds: + description: |- + ConnectionRetrySeconds is the number of seconds that the replica will wait between connection retries. + See: https://mariadb.com/docs/server/reference/sql-statements/administrative-sql-statements/replication-statements/change-master-to#master_connect_retry. + type: integer + gtid: + description: |- + Gtid indicates which Global Transaction ID (GTID) position mode should be used when connecting a replica to the master. + By default, CurrentPos is used. + See: https://mariadb.com/docs/server/reference/sql-statements/administrative-sql-statements/replication-statements/change-master-to#master_use_gtid. + enum: + - CurrentPos + - SlavePos + type: string + maxLagSeconds: + description: |- + MaxLagSeconds is the maximum number of seconds that replicas are allowed to lag behind the primary. + If a replica exceeds this threshold, it is marked as not ready and read queries will no longer be forwarded to it. + If not provided, it defaults to 0, which means that replicas are not allowed to lag behind the primary (recommended). + Lagged replicas will not be taken into account as candidates for the new primary during failover, + and they will block other operations, such as switchover and upgrade. + This field is not taken into account by MaxScale, you can define the maximum lag as router parameters. + See: https://mariadb.com/docs/maxscale/reference/maxscale-routers/maxscale-readwritesplit#max_replication_lag. + type: integer + recovery: + description: |- + ReplicaRecovery defines how the replicas should be recovered after they enter an error state. + This process deletes data from faulty replicas and recreates them using the source defined in the bootstrapFrom field. + It is disabled by default, and it requires the bootstrapFrom field to be set. + properties: + enabled: + description: Enabled is a flag to enable replica recovery. + type: boolean + errorDurationThreshold: + description: |- + ErrorDurationThreshold defines the time duration after which, if a replica continues to report errors, + the operator will initiate the recovery process for that replica. + This threshold applies only to error codes not identified as recoverable by the operator. + Errors identified as recoverable will trigger the recovery process immediately. + It defaults to 5 minutes. + type: string + required: + - enabled + type: object + replPasswordSecretKeyRef: + description: |- + ReplPasswordSecretKeyRef provides a reference to the Secret to use as password for the replication user. + By default, a random password will be generated. + properties: + generate: + default: false + description: Generate indicates whether the Secret should + be generated if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + syncTimeout: + description: |- + SyncTimeout defines the timeout for the synchronization phase during switchover and failover operations. + During switchover, all replicas must be synced with the current primary before promoting the new primary. + During failover, the new primary must be synced before being promoted as primary. This implies processing all the events in the relay log. + When the timeout is reached, the operator restarts the operation from the beginning. + It defaults to 10s. + See: https://mariadb.com/docs/server/reference/sql-functions/secondary-functions/miscellaneous-functions/master_gtid_wait + type: string + type: object + semiSyncAckTimeout: + description: |- + SemiSyncAckTimeout for the replica to acknowledge transactions to the primary. + It requires semi-synchronous replication to be enabled. + See: https://mariadb.com/docs/server/ha-and-performance/standard-replication/semisynchronous-replication#rpl_semi_sync_master_timeout + type: string + semiSyncEnabled: + description: |- + SemiSyncEnabled determines whether semi-synchronous replication is enabled. + Semi-synchronous replication requires that at least one replica should have sent an ACK to the primary node + before committing the transaction back to the client. + See: https://mariadb.com/docs/server/ha-and-performance/standard-replication/semisynchronous-replication + It is enabled by default + type: boolean + semiSyncWaitPoint: + description: |- + SemiSyncWaitPoint determines whether the transaction should wait for an ACK after having synced the binlog (AfterSync) + or after having committed to the storage engine (AfterCommit, the default). + It requires semi-synchronous replication to be enabled. + See: https://mariadb.com/kb/en/semisynchronous-replication/#rpl_semi_sync_master_wait_point. + enum: + - AfterSync + - AfterCommit + type: string + standaloneProbes: + description: |- + StandaloneProbes indicates whether to use the default non-HA startup and liveness probes. + It is disabled by default + type: boolean + syncBinlog: + description: |- + SyncBinlog indicates after how many events the binary log is synchronized to the disk. + See: https://mariadb.com/docs/server/ha-and-performance/standard-replication/replication-and-binary-log-system-variables#sync_binlog + type: integer + type: object + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + type: object + rootEmptyPassword: + description: RootEmptyPassword indicates if the root password should + be empty. Don't use this feature in production, it is only intended + for development and test environments. + type: boolean + rootPasswordSecretKeyRef: + description: RootPasswordSecretKeyRef is a reference to a Secret key + containing the root password. + properties: + generate: + default: false + description: Generate indicates whether the Secret should be generated + if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + secondaryConnection: + description: |- + SecondaryConnection defines a template to configure the secondary Connection object. + This Connection provides the initial User access to the initial Database. + It will make use of the SecondaryService to route network traffic to the secondary Pods. + properties: + healthCheck: + description: HealthCheck to be used in the Connection. + properties: + interval: + description: Interval used to perform health checks. + type: string + retryInterval: + description: RetryInterval is the interval used to perform + health check retries. + type: string + type: object + params: + additionalProperties: + type: string + description: Params to be used in the Connection. + type: object + port: + description: Port to connect to. If not provided, it defaults + to the MariaDB port or to the first MaxScale listener. + format: int32 + type: integer + secretName: + description: SecretName to be used in the Connection. + type: string + secretTemplate: + description: SecretTemplate to be used in the Connection. + properties: + databaseKey: + description: DatabaseKey to be used in the Secret. + type: string + format: + description: Format to be used in the Secret. + type: string + hostKey: + description: HostKey to be used in the Secret. + type: string + key: + description: Key to be used in the Secret. + type: string + metadata: + description: Metadata to be added to the Secret object. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + passwordKey: + description: PasswordKey to be used in the Secret. + type: string + portKey: + description: PortKey to be used in the Secret. + type: string + usernameKey: + description: UsernameKey to be used in the Secret. + type: string + type: object + serviceName: + description: ServiceName to be used in the Connection. + type: string + type: object + secondaryService: + description: |- + SecondaryService defines a template to configure the secondary Service object. + The network traffic of this Service will be routed to the secondary Pods. + properties: + allocateLoadBalancerNodePorts: + description: AllocateLoadBalancerNodePorts Service field. + type: boolean + externalTrafficPolicy: + description: ExternalTrafficPolicy Service field. + type: string + loadBalancerIP: + description: LoadBalancerIP Service field. + type: string + loadBalancerSourceRanges: + description: LoadBalancerSourceRanges Service field. + items: + type: string + type: array + metadata: + description: Metadata to be added to the Service metadata. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + sessionAffinity: + description: SessionAffinity Service field. + type: string + type: + default: ClusterIP + description: Type is the Service type. One of `ClusterIP`, `NodePort` + or `LoadBalancer`. If not defined, it defaults to `ClusterIP`. + enum: + - ClusterIP + - NodePort + - LoadBalancer + type: string + type: object + securityContext: + description: SecurityContext holds security configuration that will + be applied to a container. + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + description: Adds and removes POSIX capabilities from running + containers. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + type: object + service: + description: |- + Service defines a template to configure the general Service object. + The network traffic of this Service will be routed to all Pods. + properties: + allocateLoadBalancerNodePorts: + description: AllocateLoadBalancerNodePorts Service field. + type: boolean + externalTrafficPolicy: + description: ExternalTrafficPolicy Service field. + type: string + loadBalancerIP: + description: LoadBalancerIP Service field. + type: string + loadBalancerSourceRanges: + description: LoadBalancerSourceRanges Service field. + items: + type: string + type: array + metadata: + description: Metadata to be added to the Service metadata. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + sessionAffinity: + description: SessionAffinity Service field. + type: string + type: + default: ClusterIP + description: Type is the Service type. One of `ClusterIP`, `NodePort` + or `LoadBalancer`. If not defined, it defaults to `ClusterIP`. + enum: + - ClusterIP + - NodePort + - LoadBalancer + type: string + type: object + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + to be used by the Pods. + type: string + servicePorts: + description: ServicePorts is the list of additional named ports to + be added to the Services created by the operator. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#serviceport-v1-core' + properties: + name: + type: string + port: + format: int32 + type: integer + required: + - name + - port + type: object + type: array + sidecarContainers: + description: SidecarContainers to be used in the Pod. + items: + description: Container object definition. + properties: + args: + description: Args to be used in the Container. + items: + type: string + type: array + command: + description: Command to be used in the Container. + items: + type: string + type: array + env: + description: Env represents the environment variables to be + injected in a container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + name: + description: Name of the environment variable. Must be + a C_IDENTIFIER. + type: string + value: + type: string + valueFrom: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + configMapKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#configmapkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#objectfieldselector-v1-core.' + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#secretkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + image: + description: Image name to be used by the container. The supported + format is `:`. + type: string + imagePullPolicy: + description: ImagePullPolicy is the image pull policy. One of + `Always`, `Never` or `IfNotPresent`. If not defined, it defaults + to `IfNotPresent`. + enum: + - Always + - Never + - IfNotPresent + type: string + name: + description: Name to be given to the container. + type: string + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + type: object + volumeMounts: + description: VolumeMounts to be used in the Container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#volumemount-v1-core.' + properties: + mountPath: + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + type: boolean + subPath: + type: string + required: + - mountPath + - name + type: object + type: array + required: + - image + type: object + type: array + startupProbe: + description: StartupProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used for connection + to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + storage: + description: Storage defines the storage options to be used for provisioning + the PVCs mounted by MariaDB. + properties: + ephemeral: + description: Ephemeral indicates whether to use ephemeral storage + in the PVCs. It is only compatible with non HA MariaDBs. + type: boolean + resizeInUseVolumes: + description: |- + ResizeInUseVolumes indicates whether the PVCs can be resized. The 'StorageClassName' used should have 'allowVolumeExpansion' set to 'true' to allow resizing. + It defaults to true. + type: boolean + size: + anyOf: + - type: integer + - type: string + description: Size of the PVCs to be mounted by MariaDB. Required + if not provided in 'VolumeClaimTemplate'. It supersedes the + storage size specified in 'VolumeClaimTemplate'. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + storageClassName: + description: |- + StorageClassName to be used to provision the PVCS. It supersedes the 'StorageClassName' specified in 'VolumeClaimTemplate'. + If not provided, the default 'StorageClass' configured in the cluster is used. + type: string + volumeClaimTemplate: + description: VolumeClaimTemplate provides a template to define + the PVCs. + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + metadata: + description: Metadata to be added to the PVC metadata. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + resources: + description: VolumeResourceRequirements describes the storage + resource requirements for a volume. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + storageClassName: + type: string + type: object + waitForVolumeResize: + description: |- + WaitForVolumeResize indicates whether to wait for the PVCs to be resized before marking the MariaDB object as ready. This will block other operations such as cluster recovery while the resize is in progress. + It defaults to true. + type: boolean + type: object + suspend: + default: false + description: |- + Suspend indicates whether the current resource should be suspended or not. + This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. + type: boolean + timeZone: + description: TimeZone sets the default timezone. If not provided, + it defaults to SYSTEM and the timezone data is not loaded. + type: string + tls: + description: TLS defines the PKI to be used with MariaDB. + properties: + clientCASecretRef: + description: |- + ClientCASecretRef is a reference to a Secret containing the client certificate authority keypair. It is used to establish trust and issue client certificates. + One of: + - Secret containing both the 'ca.crt' and 'ca.key' keys. This allows you to bring your own CA to Kubernetes to issue certificates. + - Secret containing only the 'ca.crt' in order to establish trust. In this case, either clientCertSecretRef or clientCertIssuerRef fields must be provided. + If not provided, a self-signed CA will be provisioned to issue the client certificate. + properties: + name: + default: "" + type: string + type: object + clientCertIssuerRef: + description: |- + ClientCertIssuerRef is a reference to a cert-manager issuer object used to issue the client certificate. cert-manager must be installed previously in the cluster. + It is mutually exclusive with clientCertSecretRef. + By default, the Secret field 'ca.crt' provisioned by cert-manager will be added to the trust chain. A custom trust bundle may be specified via clientCASecretRef. + properties: + group: + description: Group of the resource being referred to. + type: string + kind: + description: Kind of the resource being referred to. + type: string + name: + description: Name of the resource being referred to. + type: string + required: + - name + type: object + clientCertSecretRef: + description: |- + ClientCertSecretRef is a reference to a TLS Secret containing the client certificate. + It is mutually exclusive with clientCertIssuerRef. + properties: + name: + default: "" + type: string + type: object + enabled: + description: |- + Enabled indicates whether TLS is enabled, determining if certificates should be issued and mounted to the MariaDB instance. + It is enabled by default. + type: boolean + galeraSSTEnabled: + description: |- + GaleraSSTEnabled determines whether Galera SST connections should use TLS. + It disabled by default. + type: boolean + required: + description: |- + Required specifies whether TLS must be enforced for all connections. + User TLS requirements take precedence over this. + It disabled by default. + type: boolean + serverCASecretRef: + description: |- + ServerCASecretRef is a reference to a Secret containing the server certificate authority keypair. It is used to establish trust and issue server certificates. + One of: + - Secret containing both the 'ca.crt' and 'ca.key' keys. This allows you to bring your own CA to Kubernetes to issue certificates. + - Secret containing only the 'ca.crt' in order to establish trust. In this case, either serverCertSecretRef or serverCertIssuerRef must be provided. + If not provided, a self-signed CA will be provisioned to issue the server certificate. + properties: + name: + default: "" + type: string + type: object + serverCertIssuerRef: + description: |- + ServerCertIssuerRef is a reference to a cert-manager issuer object used to issue the server certificate. cert-manager must be installed previously in the cluster. + It is mutually exclusive with serverCertSecretRef. + By default, the Secret field 'ca.crt' provisioned by cert-manager will be added to the trust chain. A custom trust bundle may be specified via serverCASecretRef. + properties: + group: + description: Group of the resource being referred to. + type: string + kind: + description: Kind of the resource being referred to. + type: string + name: + description: Name of the resource being referred to. + type: string + required: + - name + type: object + serverCertSecretRef: + description: |- + ServerCertSecretRef is a reference to a TLS Secret containing the server certificate. + It is mutually exclusive with serverCertIssuerRef. + properties: + name: + default: "" + type: string + type: object + type: object + tolerations: + description: Tolerations to be used in the Pod. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + topologySpreadConstraints: + description: TopologySpreadConstraints to be used in the Pod. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#topologyspreadconstraint-v1-core.' + properties: + labelSelector: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + matchLabelKeys: + items: + type: string + type: array + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + description: NodeInclusionPolicy defines the type of node inclusion + policy + type: string + nodeTaintsPolicy: + description: NodeInclusionPolicy defines the type of node inclusion + policy + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + updateStrategy: + description: UpdateStrategy defines how a MariaDB resource is updated. + properties: + autoUpdateDataPlane: + description: |- + AutoUpdateDataPlane indicates whether the Galera data-plane version (agent and init containers) should be automatically updated based on the operator version. It defaults to false. + Updating the operator will trigger updates on all the MariaDB instances that have this flag set to true. Thus, it is recommended to progressively set this flag after having updated the operator. + type: boolean + rollingUpdate: + description: RollingUpdate defines parameters for the RollingUpdate + type. + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + description: |- + The maximum number of pods that can be unavailable during the update. + Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + Absolute number is calculated from percentage by rounding up. This can not be 0. + Defaults to 1. This field is alpha-level and is only honored by servers that enable the + MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to + Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it + will be counted towards MaxUnavailable. + x-kubernetes-int-or-string: true + partition: + description: |- + Partition indicates the ordinal at which the StatefulSet should be partitioned + for updates. During a rolling update, all pods from ordinal Replicas-1 to + Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. + This is helpful in being able to do a canary based deployment. The default value is 0. + format: int32 + type: integer + type: object + type: + default: ReplicasFirstPrimaryLast + description: Type defines the type of updates. One of `ReplicasFirstPrimaryLast`, + `RollingUpdate` or `OnDelete`. If not defined, it defaults to + `ReplicasFirstPrimaryLast`. + enum: + - ReplicasFirstPrimaryLast + - RollingUpdate + - OnDelete + - Never + type: string + type: object + username: + description: |- + Username is the initial username to be created by the operator once MariaDB is ready. + The initial User will have ALL PRIVILEGES in the initial Database. + type: string + volumeMounts: + description: VolumeMounts to be used in the Container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#volumemount-v1-core.' + properties: + mountPath: + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + type: boolean + subPath: + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + description: Volumes to be used in the Pod. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#volume-v1-core.' + properties: + configMap: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#configmapvolumesource-v1-core.' + properties: + defaultMode: + format: int32 + type: integer + name: + default: "" + type: string + type: object + csi: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#csivolumesource-v1-core.' + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + emptyDir: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#emptydirvolumesource-v1-core.' + properties: + medium: + description: StorageMedium defines ways that storage can + be allocated to a volume. + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#hostpathvolumesource-v1-core' + properties: + path: + type: string + type: + type: string + required: + - path + type: object + name: + type: string + nfs: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nfsvolumesource-v1-core.' + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#persistentvolumeclaimvolumesource-v1-core.' + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + secret: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#secretvolumesource-v1-core.' + properties: + defaultMode: + format: int32 + type: integer + secretName: + type: string + type: object + required: + - name + type: object + type: array + type: object + x-kubernetes-validations: + - message: 'An odd number of MariaDB instances (mariadb.spec.replicas) + is required to avoid split brain situations for Galera. Use ''mariadb.spec.replicasAllowEvenNumber: + true'' to disable this validation.' + rule: '!has(self.galera) || !self.galera.enabled || (self.replicas % + 2 == 1 || self.replicasAllowEvenNumber)' + status: + description: MariaDBStatus defines the observed state of MariaDB + properties: + conditions: + description: Conditions for the Mariadb object. + 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 + type: array + currentPrimary: + description: CurrentPrimary is the primary Pod. + type: string + currentPrimaryFailingSince: + description: CurrentPrimaryFailingSince is the timestamp of the moment + when the primary became not ready. + format: date-time + type: string + currentPrimaryPodIndex: + description: CurrentPrimaryPodIndex is the primary Pod index. + type: integer + defaultVersion: + description: |- + DefaultVersion is the MariaDB version used by the operator when it cannot infer the version + from spec.image. This can happen if the image uses a digest (e.g. sha256) instead + of a version tag. + type: string + galeraRecovery: + description: GaleraRecovery is the Galera recovery current state. + properties: + bootstrap: + description: Bootstrap indicates when and in which Pod the cluster + bootstrap process has been performed. + properties: + pod: + type: string + time: + format: date-time + type: string + type: object + podsRestarted: + description: PodsRestarted that the Pods have been restarted after + the cluster bootstrap. + type: boolean + recovered: + additionalProperties: + properties: + seqno: + type: integer + uuid: + type: string + required: + - seqno + - uuid + type: object + description: State is a per Pod representation of the sequence + recovery process. + type: object + state: + additionalProperties: + properties: + safeToBootstrap: + type: boolean + seqno: + type: integer + uuid: + type: string + version: + type: string + required: + - safeToBootstrap + - seqno + - uuid + - version + type: object + description: State is a per Pod representation of the Galera state + file (grastate.dat). + type: object + type: object + replicas: + description: Replicas indicates the number of current instances. + format: int32 + type: integer + replication: + description: Replication is the replication current status per each + Pod. + properties: + replicaToRecover: + description: ReplicaToRecover is the replica that is being recovered + by the operator. + type: string + replicas: + additionalProperties: + description: ReplicaStatus is the observed replica status. + properties: + gtidCurrentPos: + description: GtidCurrentPos is the last GTID position executed + by the SQL thread. + type: string + gtidIOPos: + description: GtidIOPos is the last GTID position received + by the IO thread and written to the relay log. + type: string + lastErrorTransitionTime: + description: LastErrorTransitionTime is the last time the + replica transitioned to an error state. + format: date-time + type: string + lastIOErrno: + description: LastIOErrno is the error code returned by the + IO thread. + type: integer + lastIOError: + description: LastIOErrno is the error message returned by + the IO thread. + type: string + lastSQLErrno: + description: LastSQLErrno is the error code returned by + the SQL thread. + type: integer + lastSQLError: + description: LastSQLError is the error message returned + by the SQL thread. + type: string + secondsBehindMaster: + description: SecondsBehindMaster measures the replication + lag with the primary. + type: integer + slaveIORunning: + description: SlaveIORunning indicates whether the slave + IO thread is running. + type: boolean + slaveSQLRunning: + description: SlaveSQLRunning indicates whether the slave + SQL thread is running. + type: boolean + type: object + description: Replicas is the observed replication status for each + replica. + type: object + roles: + additionalProperties: + description: ReplicationRole represents the observed replication + roles. + type: string + description: Roles is the observed replication roles for each + Pod. + type: object + type: object + scaleOutInitialIndex: + description: ScaleOutInitialIndex is the initial index where the scale + out operation started. + type: integer + tls: + description: TLS aggregates the status of the certificates used by + the MariaDB instance. + properties: + caBundle: + description: CABundle is the status of the Certificate Authority + bundle. + items: + description: CertificateStatus represents the current status + of a TLS certificate. + properties: + issuer: + description: Issuer is the issuer of the current certificate. + type: string + notAfter: + description: NotAfter indicates that the certificate is + not valid after the given date. + format: date-time + type: string + notBefore: + description: NotBefore indicates that the certificate is + not valid before the given date. + format: date-time + type: string + subject: + description: Subject is the subject of the current certificate. + type: string + required: + - issuer + - subject + type: object + type: array + clientCert: + description: ClientCert is the status of the client certificate. + properties: + issuer: + description: Issuer is the issuer of the current certificate. + type: string + notAfter: + description: NotAfter indicates that the certificate is not + valid after the given date. + format: date-time + type: string + notBefore: + description: NotBefore indicates that the certificate is not + valid before the given date. + format: date-time + type: string + subject: + description: Subject is the subject of the current certificate. + type: string + required: + - issuer + - subject + type: object + serverCert: + description: ServerCert is the status of the server certificate. + properties: + issuer: + description: Issuer is the issuer of the current certificate. + type: string + notAfter: + description: NotAfter indicates that the certificate is not + valid after the given date. + format: date-time + type: string + notBefore: + description: NotBefore indicates that the certificate is not + valid before the given date. + format: date-time + type: string + subject: + description: Subject is the subject of the current certificate. + type: string + required: + - issuer + - subject + type: object + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + scale: + specReplicasPath: .spec.replicas + statusReplicasPath: .status.replicas + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: maxscales.k8s.mariadb.com +spec: + group: k8s.mariadb.com + names: + kind: MaxScale + listKind: MaxScaleList + plural: maxscales + shortNames: + - mxs + singular: maxscale + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .status.primaryServer + name: Primary + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: MaxScale is the Schema for the maxscales API. It is used to define + MaxScale clusters. + 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: MaxScaleSpec defines the desired state of MaxScale. + properties: + admin: + description: Admin configures the admin REST API and GUI. + properties: + guiEnabled: + description: GuiEnabled indicates whether the admin GUI should + be enabled. + type: boolean + port: + description: Port where the admin REST API and GUI will be exposed. + format: int32 + type: integer + type: object + affinity: + description: Affinity to be used in the Pod. + properties: + antiAffinityEnabled: + description: |- + AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. + Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. + type: boolean + nodeAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeaffinity-v1-core' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#preferredschedulingterm-v1-core' + properties: + preference: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselector-v1-core' + properties: + nodeSelectorTerms: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + type: object + podAntiAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podantiaffinity-v1-core.' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#weightedpodaffinityterm-v1-core.' + properties: + podAffinityTerm: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector operator + is the set of operators that can be + used in a selector requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector operator is + the set of operators that can be used in + a selector requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + args: + description: Args to be used in the Container. + items: + type: string + type: array + auth: + description: Auth defines the credentials required for MaxScale to + connect to MariaDB. + properties: + adminPasswordSecretKeyRef: + description: AdminPasswordSecretKeyRef is Secret key reference + to the admin password to call the admin REST API. It is defaulted + if not provided. + properties: + generate: + default: false + description: Generate indicates whether the Secret should + be generated if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + adminUsername: + description: AdminUsername is an admin username to call the admin + REST API. It is defaulted if not provided. + type: string + clientMaxConnections: + description: |- + ClientMaxConnections defines the maximum number of connections that the client can establish. + If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. + It defaults to 30 times the number of MaxScale replicas. + format: int32 + type: integer + clientPasswordSecretKeyRef: + description: |- + ClientPasswordSecretKeyRef is Secret key reference to the password to connect to MaxScale. It is defaulted if not provided. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. + properties: + generate: + default: false + description: Generate indicates whether the Secret should + be generated if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + clientUsername: + description: ClientUsername is the user to connect to MaxScale. + It is defaulted if not provided. + type: string + deleteDefaultAdmin: + description: DeleteDefaultAdmin determines whether the default + admin user should be deleted after the initial configuration. + If not provided, it defaults to true. + type: boolean + generate: + description: |- + Generate defies whether the operator should generate users and grants for MaxScale to work. + It only supports MariaDBs specified via spec.mariaDbRef. + type: boolean + metricsPasswordSecretKeyRef: + description: MetricsPasswordSecretKeyRef is Secret key reference + to the metrics password to call the admib REST API. It is defaulted + if metrics are enabled. + properties: + generate: + default: false + description: Generate indicates whether the Secret should + be generated if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + metricsUsername: + description: MetricsUsername is an metrics username to call the + REST API. It is defaulted if metrics are enabled. + type: string + monitorMaxConnections: + description: |- + MonitorMaxConnections defines the maximum number of connections that the monitor can establish. + If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. + It defaults to 30 times the number of MaxScale replicas. + format: int32 + type: integer + monitorPasswordSecretKeyRef: + description: |- + MonitorPasswordSecretKeyRef is Secret key reference to the password used by MaxScale monitor to connect to MariaDB server. It is defaulted if not provided. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. + properties: + generate: + default: false + description: Generate indicates whether the Secret should + be generated if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + monitorUsername: + description: MonitorUsername is the user used by MaxScale monitor + to connect to MariaDB server. It is defaulted if not provided. + type: string + serverMaxConnections: + description: |- + ServerMaxConnections defines the maximum number of connections that the server can establish. + If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. + It defaults to 30 times the number of MaxScale replicas. + format: int32 + type: integer + serverPasswordSecretKeyRef: + description: |- + ServerPasswordSecretKeyRef is Secret key reference to the password used by MaxScale to connect to MariaDB server. It is defaulted if not provided. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. + properties: + generate: + default: false + description: Generate indicates whether the Secret should + be generated if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + serverUsername: + description: ServerUsername is the user used by MaxScale to connect + to MariaDB server. It is defaulted if not provided. + type: string + syncMaxConnections: + description: |- + SyncMaxConnections defines the maximum number of connections that the sync can establish. + If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. + It defaults to 30 times the number of MaxScale replicas. + format: int32 + type: integer + syncPasswordSecretKeyRef: + description: |- + SyncPasswordSecretKeyRef is Secret key reference to the password used by MaxScale config to connect to MariaDB server. It is defaulted when HA is enabled. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. + properties: + generate: + default: false + description: Generate indicates whether the Secret should + be generated if the Secret referenced is not present. + type: boolean + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + syncUsername: + description: MonitoSyncUsernamerUsername is the user used by MaxScale + config sync to connect to MariaDB server. It is defaulted when + HA is enabled. + type: string + type: object + command: + description: Command to be used in the Container. + items: + type: string + type: array + config: + description: Config defines the MaxScale configuration. + properties: + params: + additionalProperties: + type: string + description: |- + Params is a key value pair of parameters to be used in the MaxScale static configuration file. + Any parameter supported by MaxScale may be specified here. See reference: + https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#global-settings. + type: object + sync: + description: Sync defines how to replicate configuration across + MaxScale replicas. It is defaulted when HA is enabled. + properties: + database: + description: Database is the MariaDB logical database where + the 'maxscale_config' table will be created in order to + persist and synchronize config changes. If not provided, + it defaults to 'mysql'. + type: string + interval: + description: Interval defines the config synchronization interval. + It is defaulted if not provided. + type: string + timeout: + description: Interval defines the config synchronization timeout. + It is defaulted if not provided. + type: string + type: object + volumeClaimTemplate: + description: VolumeClaimTemplate provides a template to define + the PVCs for storing MaxScale runtime configuration files. It + is defaulted if not provided. + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + metadata: + description: Metadata to be added to the PVC metadata. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + resources: + description: VolumeResourceRequirements describes the storage + resource requirements for a volume. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + storageClassName: + type: string + type: object + type: object + connection: + description: Connection provides a template to define the Connection + for MaxScale. + properties: + healthCheck: + description: HealthCheck to be used in the Connection. + properties: + interval: + description: Interval used to perform health checks. + type: string + retryInterval: + description: RetryInterval is the interval used to perform + health check retries. + type: string + type: object + params: + additionalProperties: + type: string + description: Params to be used in the Connection. + type: object + port: + description: Port to connect to. If not provided, it defaults + to the MariaDB port or to the first MaxScale listener. + format: int32 + type: integer + secretName: + description: SecretName to be used in the Connection. + type: string + secretTemplate: + description: SecretTemplate to be used in the Connection. + properties: + databaseKey: + description: DatabaseKey to be used in the Secret. + type: string + format: + description: Format to be used in the Secret. + type: string + hostKey: + description: HostKey to be used in the Secret. + type: string + key: + description: Key to be used in the Secret. + type: string + metadata: + description: Metadata to be added to the Secret object. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + passwordKey: + description: PasswordKey to be used in the Secret. + type: string + portKey: + description: PortKey to be used in the Secret. + type: string + usernameKey: + description: UsernameKey to be used in the Secret. + type: string + type: object + serviceName: + description: ServiceName to be used in the Connection. + type: string + type: object + env: + description: Env represents the environment variables to be injected + in a container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + type: string + valueFrom: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envvarsource-v1-core.' + properties: + configMapKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#configmapkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#objectfieldselector-v1-core.' + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#secretkeyselector-v1-core.' + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: EnvFrom represents the references (via ConfigMap and + Secrets) to environment variables to be injected in the container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#envfromsource-v1-core.' + properties: + configMapRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + prefix: + type: string + secretRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: object + type: array + guiKubernetesService: + description: GuiKubernetesService defines a template for a Kubernetes + Service object to connect to MaxScale's GUI. + properties: + allocateLoadBalancerNodePorts: + description: AllocateLoadBalancerNodePorts Service field. + type: boolean + externalTrafficPolicy: + description: ExternalTrafficPolicy Service field. + type: string + loadBalancerIP: + description: LoadBalancerIP Service field. + type: string + loadBalancerSourceRanges: + description: LoadBalancerSourceRanges Service field. + items: + type: string + type: array + metadata: + description: Metadata to be added to the Service metadata. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + sessionAffinity: + description: SessionAffinity Service field. + type: string + type: + default: ClusterIP + description: Type is the Service type. One of `ClusterIP`, `NodePort` + or `LoadBalancer`. If not defined, it defaults to `ClusterIP`. + enum: + - ClusterIP + - NodePort + - LoadBalancer + type: string + type: object + image: + description: |- + Image name to be used by the MaxScale instances. The supported format is `:`. + Only MaxScale official images are supported. + type: string + imagePullPolicy: + description: ImagePullPolicy is the image pull policy. One of `Always`, + `Never` or `IfNotPresent`. If not defined, it defaults to `IfNotPresent`. + enum: + - Always + - Never + - IfNotPresent + type: string + imagePullSecrets: + description: ImagePullSecrets is the list of pull Secrets to be used + to pull the image. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: array + inheritMetadata: + description: InheritMetadata defines the metadata to be inherited + by children resources. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + kubernetesService: + description: KubernetesService defines a template for a Kubernetes + Service object to connect to MaxScale. + properties: + allocateLoadBalancerNodePorts: + description: AllocateLoadBalancerNodePorts Service field. + type: boolean + externalTrafficPolicy: + description: ExternalTrafficPolicy Service field. + type: string + loadBalancerIP: + description: LoadBalancerIP Service field. + type: string + loadBalancerSourceRanges: + description: LoadBalancerSourceRanges Service field. + items: + type: string + type: array + metadata: + description: Metadata to be added to the Service metadata. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + sessionAffinity: + description: SessionAffinity Service field. + type: string + type: + default: ClusterIP + description: Type is the Service type. One of `ClusterIP`, `NodePort` + or `LoadBalancer`. If not defined, it defaults to `ClusterIP`. + enum: + - ClusterIP + - NodePort + - LoadBalancer + type: string + type: object + livenessProbe: + description: LivenessProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used for connection + to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + mariaDbRef: + description: MariaDBRef is a reference to the MariaDB that MaxScale + points to. It is used to initialize the servers field. + properties: + kind: + description: Kind of the referent. + type: string + name: + type: string + namespace: + type: string + waitForIt: + default: true + description: WaitForIt indicates whether the controller using + this reference should wait for MariaDB to be ready. + type: boolean + type: object + metrics: + description: Metrics configures metrics and how to scrape them. + properties: + enabled: + description: Enabled is a flag to enable Metrics + type: boolean + exporter: + description: Exporter defines the metrics exporter container. + properties: + affinity: + description: Affinity to be used in the Pod. + properties: + antiAffinityEnabled: + description: |- + AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. + Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. + type: boolean + nodeAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeaffinity-v1-core' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#preferredschedulingterm-v1-core' + properties: + preference: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselector-v1-core' + properties: + nodeSelectorTerms: + items: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + type: object + podAntiAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podantiaffinity-v1-core.' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#weightedpodaffinityterm-v1-core.' + properties: + podAffinityTerm: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector + operator is the set of operators + that can be used in a selector + requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes + docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector operator + is the set of operators that can + be used in a selector requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + args: + description: Args to be used in the Container. + items: + type: string + type: array + image: + description: |- + Image name to be used as metrics exporter. The supported format is `:`. + Only mysqld-exporter >= v0.15.0 is supported: https://github.com/prometheus/mysqld_exporter + type: string + imagePullPolicy: + description: ImagePullPolicy is the image pull policy. One + of `Always`, `Never` or `IfNotPresent`. If not defined, + it defaults to `IfNotPresent`. + enum: + - Always + - Never + - IfNotPresent + type: string + imagePullSecrets: + description: ImagePullSecrets is the list of pull Secrets + to be used to pull the image. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: array + nodeSelector: + additionalProperties: + type: string + description: NodeSelector to be used in the Pod. + type: object + podMetadata: + description: PodMetadata defines extra metadata for the Pod. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + podSecurityContext: + description: SecurityContext holds pod-level security attributes + and common container settings. + properties: + appArmorProfile: + description: AppArmorProfile defines a pod or container's + AppArmor settings. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + PodFSGroupChangePolicy holds policies that will be used for applying fsGroup to a volume + when volume is mounted. + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + description: SELinuxOptions are the labels to be applied + to the container + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: |- + SeccompProfile defines a pod/container's seccomp profile settings. + Only one profile source may be set. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + type: object + port: + description: Port where the exporter will be listening for + connections. + format: int32 + type: integer + priorityClassName: + description: PriorityClassName to be used in the Pod. + type: string + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, + quantity) pairs. + type: object + type: object + securityContext: + description: SecurityContext holds container-level security + attributes. + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + description: Adds and removes POSIX capabilities from + running containers. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + type: object + tolerations: + description: Tolerations to be used in the Pod. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + serviceMonitor: + description: ServiceMonitor defines the ServiceMonior object. + properties: + interval: + description: Interval for scraping metrics. + type: string + jobLabel: + description: JobLabel to add to the ServiceMonitor object. + type: string + prometheusRelease: + description: PrometheusRelease is the release label to add + to the ServiceMonitor object. + type: string + scrapeTimeout: + description: ScrapeTimeout defines the timeout for scraping + metrics. + type: string + type: object + type: object + monitor: + description: Monitor monitors MariaDB server instances. It is required + if 'spec.mariaDbRef' is not provided. + properties: + cooperativeMonitoring: + description: CooperativeMonitoring enables coordination between + multiple MaxScale instances running monitors. It is defaulted + when HA is enabled. + enum: + - majority_of_all + - majority_of_running + type: string + interval: + description: Interval used to monitor MariaDB servers. It is defaulted + if not provided. + type: string + module: + description: Module is the module to use to monitor MariaDB servers. + It is mandatory when no MariaDB reference is provided. + type: string + name: + description: Name is the identifier of the monitor. It is defaulted + if not provided. + type: string + params: + additionalProperties: + type: string + description: |- + Params defines extra parameters to pass to the monitor. + Any parameter supported by MaxScale may be specified here. See reference: + https://mariadb.com/kb/en/mariadb-maxscale-2308-common-monitor-parameters/. + Monitor specific parameter are also supported: + https://mariadb.com/kb/en/mariadb-maxscale-2308-galera-monitor/#galera-monitor-optional-parameters. + https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-monitor/#configuration. + type: object + suspend: + default: false + description: |- + Suspend indicates whether the current resource should be suspended or not. + This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. + type: boolean + type: object + nodeSelector: + additionalProperties: + type: string + description: NodeSelector to be used in the Pod. + type: object + podDisruptionBudget: + description: PodDisruptionBudget defines the budget for replica availability. + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + description: MaxUnavailable defines the number of maximum unavailable + Pods. + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + description: MinAvailable defines the number of minimum available + Pods. + x-kubernetes-int-or-string: true + type: object + podMetadata: + description: PodMetadata defines extra metadata for the Pod. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + podSecurityContext: + description: SecurityContext holds pod-level security attributes and + common container settings. + properties: + appArmorProfile: + description: AppArmorProfile defines a pod or container's AppArmor + settings. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + PodFSGroupChangePolicy holds policies that will be used for applying fsGroup to a volume + when volume is mounted. + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + description: SELinuxOptions are the labels to be applied to the + container + properties: + level: + description: Level is SELinux level label that applies to + the container. + type: string + role: + description: Role is a SELinux role label that applies to + the container. + type: string + type: + description: Type is a SELinux type label that applies to + the container. + type: string + user: + description: User is a SELinux user label that applies to + the container. + type: string + type: object + seccompProfile: + description: |- + SeccompProfile defines a pod/container's seccomp profile settings. + Only one profile source may be set. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + type: object + primaryServer: + description: |- + PrimaryServer specifies the desired primary server. Setting this field triggers a switchover operation in MaxScale to the desired server. + This option is only valid when using monitors that support switchover, currently limited to the MariaDB monitor. + type: string + priorityClassName: + description: PriorityClassName to be used in the Pod. + type: string + readinessProbe: + description: ReadinessProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used for connection + to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + replicas: + default: 1 + description: Replicas indicates the number of desired instances. + format: int32 + type: integer + requeueInterval: + description: RequeueInterval is used to perform requeue reconciliations. + If not defined, it defaults to 10s. + type: string + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + type: object + securityContext: + description: SecurityContext holds security configuration that will + be applied to a container. + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + description: Adds and removes POSIX capabilities from running + containers. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + type: object + servers: + description: Servers are the MariaDB servers to forward traffic to. + It is required if 'spec.mariaDbRef' is not provided. + items: + description: MaxScaleServer defines a MariaDB server to forward + traffic to. + properties: + address: + description: Address is the network address of the MariaDB server. + type: string + maintenance: + description: Maintenance indicates whether the server is in + maintenance mode. + type: boolean + name: + description: Name is the identifier of the MariaDB server. + type: string + params: + additionalProperties: + type: string + description: |- + Params defines extra parameters to pass to the server. + Any parameter supported by MaxScale may be specified here. See reference: + https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#server_1. + type: object + port: + description: Port is the network port of the MariaDB server. + If not provided, it defaults to 3306. + format: int32 + type: integer + protocol: + description: Protocol is the MaxScale protocol to use when communicating + with this MariaDB server. If not provided, it defaults to + MariaDBBackend. + type: string + required: + - address + - name + type: object + type: array + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + to be used by the Pods. + type: string + services: + description: Services define how the traffic is forwarded to the MariaDB + servers. It is defaulted if not provided. + items: + description: Services define how the traffic is forwarded to the + MariaDB servers. + properties: + listener: + description: MaxScaleListener defines how the MaxScale server + will listen for connections. + properties: + name: + description: Name is the identifier of the listener. It + is defaulted if not provided + type: string + params: + additionalProperties: + type: string + description: |- + Params defines extra parameters to pass to the listener. + Any parameter supported by MaxScale may be specified here. See reference: + https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#listener_1. + type: object + port: + description: Port is the network port where the MaxScale + server will listen. + format: int32 + type: integer + protocol: + description: Protocol is the MaxScale protocol to use when + communicating with the client. If not provided, it defaults + to MariaDBProtocol. + type: string + suspend: + default: false + description: |- + Suspend indicates whether the current resource should be suspended or not. + This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. + type: boolean + required: + - port + type: object + name: + description: Name is the identifier of the MaxScale service. + type: string + params: + additionalProperties: + type: string + description: |- + Params defines extra parameters to pass to the service. + Any parameter supported by MaxScale may be specified here. See reference: + https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#service_1. + Router specific parameter are also supported: + https://mariadb.com/kb/en/mariadb-maxscale-2308-readwritesplit/#configuration. + https://mariadb.com/kb/en/mariadb-maxscale-2308-readconnroute/#configuration. + type: object + router: + description: Router is the type of router to use. + enum: + - readwritesplit + - readconnroute + type: string + suspend: + default: false + description: |- + Suspend indicates whether the current resource should be suspended or not. + This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. + type: boolean + required: + - listener + - name + - router + type: object + type: array + startupProbe: + description: StartupProbe to be used in the Container. + properties: + exec: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#execaction-v1-core.' + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + httpGet: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#httpgetaction-v1-core.' + properties: + host: + type: string + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: URIScheme identifies the scheme used for connection + to a host for Get actions + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#tcpsocketaction-v1-core.' + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + format: int32 + type: integer + type: object + suspend: + default: false + description: |- + Suspend indicates whether the current resource should be suspended or not. + This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. + type: boolean + tls: + description: TLS defines the PKI to be used with MaxScale. + properties: + adminCASecretRef: + description: |- + AdminCASecretRef is a reference to a Secret containing the admin certificate authority keypair. It is used to establish trust and issue certificates for the MaxScale's administrative REST API and GUI. + One of: + - Secret containing both the 'ca.crt' and 'ca.key' keys. This allows you to bring your own CA to Kubernetes to issue certificates. + - Secret containing only the 'ca.crt' in order to establish trust. In this case, either adminCertSecretRef or adminCertIssuerRef fields must be provided. + If not provided, a self-signed CA will be provisioned to issue the server certificate. + properties: + name: + default: "" + type: string + type: object + adminCertIssuerRef: + description: |- + AdminCertIssuerRef is a reference to a cert-manager issuer object used to issue the MaxScale's administrative REST API and GUI certificate. cert-manager must be installed previously in the cluster. + It is mutually exclusive with adminCertSecretRef. + By default, the Secret field 'ca.crt' provisioned by cert-manager will be added to the trust chain. A custom trust bundle may be specified via adminCASecretRef. + properties: + group: + description: Group of the resource being referred to. + type: string + kind: + description: Kind of the resource being referred to. + type: string + name: + description: Name of the resource being referred to. + type: string + required: + - name + type: object + adminCertSecretRef: + description: AdminCertSecretRef is a reference to a TLS Secret + used by the MaxScale's administrative REST API and GUI. + properties: + name: + default: "" + type: string + type: object + enabled: + description: |- + Enabled indicates whether TLS is enabled, determining if certificates should be issued and mounted to the MaxScale instance. + It is enabled by default when the referred MariaDB instance (via mariaDbRef) has TLS enabled and enforced. + type: boolean + listenerCASecretRef: + description: |- + ListenerCASecretRef is a reference to a Secret containing the listener certificate authority keypair. It is used to establish trust and issue certificates for the MaxScale's listeners. + One of: + - Secret containing both the 'ca.crt' and 'ca.key' keys. This allows you to bring your own CA to Kubernetes to issue certificates. + - Secret containing only the 'ca.crt' in order to establish trust. In this case, either listenerCertSecretRef or listenerCertIssuerRef fields must be provided. + If not provided, a self-signed CA will be provisioned to issue the listener certificate. + properties: + name: + default: "" + type: string + type: object + listenerCertIssuerRef: + description: |- + ListenerCertIssuerRef is a reference to a cert-manager issuer object used to issue the MaxScale's listeners certificate. cert-manager must be installed previously in the cluster. + It is mutually exclusive with listenerCertSecretRef. + By default, the Secret field 'ca.crt' provisioned by cert-manager will be added to the trust chain. A custom trust bundle may be specified via listenerCASecretRef. + properties: + group: + description: Group of the resource being referred to. + type: string + kind: + description: Kind of the resource being referred to. + type: string + name: + description: Name of the resource being referred to. + type: string + required: + - name + type: object + listenerCertSecretRef: + description: ListenerCertSecretRef is a reference to a TLS Secret + used by the MaxScale's listeners. + properties: + name: + default: "" + type: string + type: object + replicationSSLEnabled: + description: |- + ReplicationSSLEnabled specifies whether the replication SSL is enabled. If enabled, the SSL options will be added to the server configuration. + It is enabled by default when the referred MariaDB instance (via mariaDbRef) has replication enabled. + If the MariaDB servers are manually provided by the user via the 'servers' field, this must be set by the user as well. + type: boolean + serverCASecretRef: + description: |- + ServerCASecretRef is a reference to a Secret containing the MariaDB server CA certificates. It is used to establish trust with MariaDB servers. + The Secret should contain a 'ca.crt' key in order to establish trust. + If not provided, and the reference to a MariaDB resource is set (mariaDbRef), it will be defaulted to the referred MariaDB CA bundle. + properties: + name: + default: "" + type: string + type: object + serverCertSecretRef: + description: |- + ServerCertSecretRef is a reference to a TLS Secret used by MaxScale to connect to the MariaDB servers. + If not provided, and the reference to a MariaDB resource is set (mariaDbRef), it will be defaulted to the referred MariaDB client certificate (clientCertSecretRef). + properties: + name: + default: "" + type: string + type: object + verifyPeerCertificate: + description: |- + VerifyPeerCertificate specifies whether the peer certificate's signature should be validated against the CA. + It is disabled by default. + type: boolean + verifyPeerHost: + description: |- + VerifyPeerHost specifies whether the peer certificate's SANs should match the peer host. + It is disabled by default. + type: boolean + type: object + tolerations: + description: Tolerations to be used in the Pod. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + topologySpreadConstraints: + description: TopologySpreadConstraints to be used in the Pod. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#topologyspreadconstraint-v1-core.' + properties: + labelSelector: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + matchLabelKeys: + items: + type: string + type: array + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + description: NodeInclusionPolicy defines the type of node inclusion + policy + type: string + nodeTaintsPolicy: + description: NodeInclusionPolicy defines the type of node inclusion + policy + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + updateStrategy: + description: UpdateStrategy defines the update strategy for the StatefulSet + object. + properties: + rollingUpdate: + description: RollingUpdate is used to communicate parameters when + Type is RollingUpdateStatefulSetStrategyType. + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + description: |- + The maximum number of pods that can be unavailable during the update. + Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + Absolute number is calculated from percentage by rounding up. This can not be 0. + Defaults to 1. This field is alpha-level and is only honored by servers that enable the + MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to + Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it + will be counted towards MaxUnavailable. + x-kubernetes-int-or-string: true + partition: + description: |- + Partition indicates the ordinal at which the StatefulSet should be partitioned + for updates. During a rolling update, all pods from ordinal Replicas-1 to + Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. + This is helpful in being able to do a canary based deployment. The default value is 0. + format: int32 + type: integer + type: object + type: + description: |- + Type indicates the type of the StatefulSetUpdateStrategy. + Default is RollingUpdate. + type: string + type: object + volumeMounts: + description: VolumeMounts to be used in the Container. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#volumemount-v1-core.' + properties: + mountPath: + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + type: boolean + subPath: + type: string + required: + - mountPath + - name + type: object + type: array + type: object + status: + description: MaxScaleStatus defines the observed state of MaxScale + properties: + conditions: + description: Conditions for the MaxScale object. + 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 + type: array + configSync: + description: ConfigSync is the state of config sync. + properties: + databaseVersion: + type: integer + maxScaleVersion: + type: integer + required: + - databaseVersion + - maxScaleVersion + type: object + listeners: + description: Listeners is the state of the listeners in the MaxScale + API. + items: + description: MaxScaleResourceStatus indicates whether the resource + is in a given state. + properties: + name: + type: string + state: + type: string + required: + - name + - state + type: object + type: array + monitor: + description: Monitor is the state of the monitor in the MaxScale API. + properties: + name: + type: string + state: + type: string + required: + - name + - state + type: object + monitorSpec: + description: MonitorSpec is a hashed version of spec.monitor to be + able to track changes during reconciliation. + type: string + primaryServer: + description: PrimaryServer is the primary server in the MaxScale API. + type: string + replicas: + description: Replicas indicates the number of current instances. + format: int32 + type: integer + servers: + description: Servers is the state of the servers in the MaxScale API. + items: + description: MaxScaleAPIStatus is the state of the servers in the + MaxScale API. + properties: + name: + type: string + state: + type: string + required: + - name + - state + type: object + type: array + serversSpec: + description: ServersSpec is a hashed version of spec.servers to be + able to track changes during reconciliation. + type: string + services: + description: Services is the state of the services in the MaxScale + API. + items: + description: MaxScaleResourceStatus indicates whether the resource + is in a given state. + properties: + name: + type: string + state: + type: string + required: + - name + - state + type: object + type: array + servicesSpec: + description: ServicesSpec is a hashed version of spec.services to + be able to track changes during reconciliation. + type: string + tls: + description: TLS aggregates the status of the certificates used by + the MaxScale instance. + properties: + adminCert: + description: AdminCert is the status of the admin certificate. + properties: + issuer: + description: Issuer is the issuer of the current certificate. + type: string + notAfter: + description: NotAfter indicates that the certificate is not + valid after the given date. + format: date-time + type: string + notBefore: + description: NotBefore indicates that the certificate is not + valid before the given date. + format: date-time + type: string + subject: + description: Subject is the subject of the current certificate. + type: string + required: + - issuer + - subject + type: object + caBundle: + description: CABundle is the status of the Certificate Authority + bundle. + items: + description: CertificateStatus represents the current status + of a TLS certificate. + properties: + issuer: + description: Issuer is the issuer of the current certificate. + type: string + notAfter: + description: NotAfter indicates that the certificate is + not valid after the given date. + format: date-time + type: string + notBefore: + description: NotBefore indicates that the certificate is + not valid before the given date. + format: date-time + type: string + subject: + description: Subject is the subject of the current certificate. + type: string + required: + - issuer + - subject + type: object + type: array + listenerCert: + description: ListenerCert is the status of the listener certificate. + properties: + issuer: + description: Issuer is the issuer of the current certificate. + type: string + notAfter: + description: NotAfter indicates that the certificate is not + valid after the given date. + format: date-time + type: string + notBefore: + description: NotBefore indicates that the certificate is not + valid before the given date. + format: date-time + type: string + subject: + description: Subject is the subject of the current certificate. + type: string + required: + - issuer + - subject + type: object + serverCert: + description: ServerCert is the status of the MariaDB server certificate. + properties: + issuer: + description: Issuer is the issuer of the current certificate. + type: string + notAfter: + description: NotAfter indicates that the certificate is not + valid after the given date. + format: date-time + type: string + notBefore: + description: NotBefore indicates that the certificate is not + valid before the given date. + format: date-time + type: string + subject: + description: Subject is the subject of the current certificate. + type: string + required: + - issuer + - subject + type: object + type: object + type: object + type: object + served: true + storage: true + subresources: + scale: + specReplicasPath: .spec.replicas + statusReplicasPath: .status.replicas + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: physicalbackups.k8s.mariadb.com +spec: + group: k8s.mariadb.com + names: + kind: PhysicalBackup + listKind: PhysicalBackupList + plural: physicalbackups + shortNames: + - pbmdb + singular: physicalbackup + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Complete")].status + name: Complete + type: string + - jsonPath: .status.conditions[?(@.type=="Complete")].message + name: Status + type: string + - jsonPath: .spec.mariaDbRef.name + name: MariaDB + type: string + - jsonPath: .status.lastScheduleTime + name: Last Scheduled + type: date + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: PhysicalBackup is the Schema for the physicalbackups API. It + is used to define physical backup jobs and its storage. + 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: PhysicalBackupSpec defines the desired state of PhysicalBackup. + properties: + args: + description: Args to be used in the Container. + items: + type: string + type: array + backoffLimit: + description: BackoffLimit defines the maximum number of attempts to + successfully take a PhysicalBackup. + format: int32 + type: integer + compression: + description: Compression algorithm to be used in the Backup. + enum: + - none + - bzip2 + - gzip + type: string + imagePullSecrets: + description: ImagePullSecrets is the list of pull Secrets to be used + to pull the image. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: array + inheritMetadata: + description: InheritMetadata defines the metadata to be inherited + by children resources. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + mariaDbRef: + description: MariaDBRef is a reference to a MariaDB object. + properties: + kind: + description: Kind of the referent. + type: string + name: + type: string + namespace: + type: string + waitForIt: + default: true + description: WaitForIt indicates whether the controller using + this reference should wait for MariaDB to be ready. + type: boolean + type: object + maxRetention: + description: |- + MaxRetention defines the retention policy for backups. Old backups will be cleaned up by the Backup Job. + It defaults to 30 days. + type: string + podAffinity: + description: |- + PodAffinity indicates whether the Jobs should run in the same Node as the MariaDB Pods to be able to attach the PVC. + It defaults to true. + type: boolean + podMetadata: + description: PodMetadata defines extra metadata for the Pod. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + podSecurityContext: + description: SecurityContext holds pod-level security attributes and + common container settings. + properties: + appArmorProfile: + description: AppArmorProfile defines a pod or container's AppArmor + settings. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + PodFSGroupChangePolicy holds policies that will be used for applying fsGroup to a volume + when volume is mounted. + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + description: SELinuxOptions are the labels to be applied to the + container + properties: + level: + description: Level is SELinux level label that applies to + the container. + type: string + role: + description: Role is a SELinux role label that applies to + the container. + type: string + type: + description: Type is a SELinux type label that applies to + the container. + type: string + user: + description: User is a SELinux user label that applies to + the container. + type: string + type: object + seccompProfile: + description: |- + SeccompProfile defines a pod/container's seccomp profile settings. + Only one profile source may be set. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + type: object + priorityClassName: + description: PriorityClassName to be used in the Pod. + type: string + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + type: object + restartPolicy: + default: OnFailure + description: RestartPolicy to be added to the PhysicalBackup Pod. + enum: + - Always + - OnFailure + - Never + type: string + schedule: + description: Schedule defines when the PhysicalBackup will be taken. + properties: + cron: + description: Cron is a cron expression that defines the schedule. + type: string + immediate: + description: Immediate indicates whether the first backup should + be taken immediately after creating the PhysicalBackup. + type: boolean + suspend: + default: false + description: Suspend defines whether the schedule is active or + not. + type: boolean + type: object + securityContext: + description: SecurityContext holds security configuration that will + be applied to a container. + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + description: Adds and removes POSIX capabilities from running + containers. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + type: object + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + to be used by the Pods. + type: string + stagingStorage: + description: |- + StagingStorage defines the temporary storage used to keep external backups (i.e. S3) while they are being processed. + It defaults to an emptyDir volume, meaning that the backups will be temporarily stored in the node where the PhysicalBackup Job is scheduled. + The staging area gets cleaned up after each backup is completed, consider this for sizing it appropriately. + properties: + persistentVolumeClaim: + description: PersistentVolumeClaim is a Kubernetes PVC specification. + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + resources: + description: VolumeResourceRequirements describes the storage + resource requirements for a volume. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + storageClassName: + type: string + type: object + volume: + description: Volume is a Kubernetes volume specification. + properties: + csi: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#csivolumesource-v1-core.' + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + emptyDir: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#emptydirvolumesource-v1-core.' + properties: + medium: + description: StorageMedium defines ways that storage can + be allocated to a volume. + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#hostpathvolumesource-v1-core' + properties: + path: + type: string + type: + type: string + required: + - path + type: object + nfs: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nfsvolumesource-v1-core.' + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#persistentvolumeclaimvolumesource-v1-core.' + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + type: object + type: object + storage: + description: Storage defines the final storage for backups. + properties: + persistentVolumeClaim: + description: PersistentVolumeClaim is a Kubernetes PVC specification. + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + resources: + description: VolumeResourceRequirements describes the storage + resource requirements for a volume. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + storageClassName: + type: string + type: object + s3: + description: S3 defines the configuration to store backups in + a S3 compatible storage. + properties: + accessKeyIdSecretKeyRef: + description: AccessKeyIdSecretKeyRef is a reference to a Secret + key containing the S3 access key id. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + bucket: + description: Bucket is the name Name of the bucket to store + backups. + type: string + endpoint: + description: Endpoint is the S3 API endpoint without scheme. + type: string + prefix: + description: 'Prefix indicates a folder/subfolder in the bucket. + For example: mariadb/ or mariadb/backups. A trailing slash + ''/'' is added if not provided.' + type: string + region: + description: Region is the S3 region name to use. + type: string + secretAccessKeySecretKeyRef: + description: AccessKeyIdSecretKeyRef is a reference to a Secret + key containing the S3 secret key. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + sessionTokenSecretKeyRef: + description: SessionTokenSecretKeyRef is a reference to a + Secret key containing the S3 session token. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + tls: + description: TLS provides the configuration required to establish + TLS connections with S3. + properties: + caSecretKeyRef: + description: |- + CASecretKeyRef is a reference to a Secret key containing a CA bundle in PEM format used to establish TLS connections with S3. + By default, the system trust chain will be used, but you can use this field to add more CAs to the bundle. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + enabled: + description: Enabled is a flag to enable TLS. + type: boolean + type: object + required: + - bucket + - endpoint + type: object + volume: + description: Volume is a Kubernetes volume specification. + properties: + csi: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#csivolumesource-v1-core.' + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + emptyDir: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#emptydirvolumesource-v1-core.' + properties: + medium: + description: StorageMedium defines ways that storage can + be allocated to a volume. + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#hostpathvolumesource-v1-core' + properties: + path: + type: string + type: + type: string + required: + - path + type: object + nfs: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nfsvolumesource-v1-core.' + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#persistentvolumeclaimvolumesource-v1-core.' + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + type: object + volumeSnapshot: + description: VolumeSnapshot is a Kubernetes VolumeSnapshot specification. + properties: + metadata: + description: Metadata is extra metadata to the added to the + VolumeSnapshot objects. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + volumeSnapshotClassName: + description: VolumeSnapshotClassName is the VolumeSnapshot + class to be used to take snapshots. + type: string + required: + - volumeSnapshotClassName + type: object + type: object + successfulJobsHistoryLimit: + description: SuccessfulJobsHistoryLimit defines the maximum number + of successful Jobs to be displayed. It defaults to 5. + format: int32 + minimum: 0 + type: integer + timeout: + description: |- + Timeout defines the maximum duration of a PhysicalBackup job or snapshot. + If this duration is exceeded, the job or snapshot is considered expired and is deleted by the operator. + A new job or snapshot will then be created according to the schedule. + It defaults to 1 hour. + type: string + tolerations: + description: Tolerations to be used in the Pod. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + required: + - mariaDbRef + - storage + type: object + status: + description: PhysicalBackupStatus defines the observed state of PhysicalBackup. + properties: + conditions: + description: Conditions for the PhysicalBackup object. + 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 + type: array + lastScheduleCheckTime: + description: LastScheduleCheckTime is the last time that the schedule + was checked. + format: date-time + type: string + lastScheduleTime: + description: LastScheduleTime is the last time that a backup was scheduled. + format: date-time + type: string + nextScheduleTime: + description: NextScheduleTime is the next time that a backup will + be scheduled. + format: date-time + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: restores.k8s.mariadb.com +spec: + group: k8s.mariadb.com + names: + kind: Restore + listKind: RestoreList + plural: restores + shortNames: + - rmdb + singular: restore + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Complete")].status + name: Complete + type: string + - jsonPath: .status.conditions[?(@.type=="Complete")].message + name: Status + type: string + - jsonPath: .spec.mariaDbRef.name + name: MariaDB + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Restore is the Schema for the restores API. It is used to define + restore jobs and its restoration source. + 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: RestoreSpec defines the desired state of restore + properties: + affinity: + description: Affinity to be used in the Pod. + properties: + antiAffinityEnabled: + description: |- + AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. + Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. + type: boolean + nodeAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeaffinity-v1-core' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#preferredschedulingterm-v1-core' + properties: + preference: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselector-v1-core' + properties: + nodeSelectorTerms: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + type: object + podAntiAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podantiaffinity-v1-core.' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#weightedpodaffinityterm-v1-core.' + properties: + podAffinityTerm: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector operator + is the set of operators that can be + used in a selector requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector operator is + the set of operators that can be used in + a selector requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + args: + description: Args to be used in the Container. + items: + type: string + type: array + backoffLimit: + default: 5 + description: BackoffLimit defines the maximum number of attempts to + successfully perform a Backup. + format: int32 + type: integer + backupRef: + description: BackupRef is a reference to a Backup object. It has priority + over S3 and Volume. + properties: + name: + default: "" + type: string + type: object + database: + description: |- + Database defines the logical database to be restored. If not provided, all databases available in the backup are restored. + IMPORTANT: The database must previously exist. + type: string + imagePullSecrets: + description: ImagePullSecrets is the list of pull Secrets to be used + to pull the image. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: array + inheritMetadata: + description: InheritMetadata defines the metadata to be inherited + by children resources. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + logLevel: + default: info + description: LogLevel to be used n the Backup Job. It defaults to + 'info'. + type: string + mariaDbRef: + description: MariaDBRef is a reference to a MariaDB object. + properties: + kind: + description: Kind of the referent. + type: string + name: + type: string + namespace: + type: string + waitForIt: + default: true + description: WaitForIt indicates whether the controller using + this reference should wait for MariaDB to be ready. + type: boolean + type: object + nodeSelector: + additionalProperties: + type: string + description: NodeSelector to be used in the Pod. + type: object + podMetadata: + description: PodMetadata defines extra metadata for the Pod. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + podSecurityContext: + description: SecurityContext holds pod-level security attributes and + common container settings. + properties: + appArmorProfile: + description: AppArmorProfile defines a pod or container's AppArmor + settings. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + PodFSGroupChangePolicy holds policies that will be used for applying fsGroup to a volume + when volume is mounted. + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + description: SELinuxOptions are the labels to be applied to the + container + properties: + level: + description: Level is SELinux level label that applies to + the container. + type: string + role: + description: Role is a SELinux role label that applies to + the container. + type: string + type: + description: Type is a SELinux type label that applies to + the container. + type: string + user: + description: User is a SELinux user label that applies to + the container. + type: string + type: object + seccompProfile: + description: |- + SeccompProfile defines a pod/container's seccomp profile settings. + Only one profile source may be set. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + type: object + priorityClassName: + description: PriorityClassName to be used in the Pod. + type: string + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + type: object + restartPolicy: + default: OnFailure + description: RestartPolicy to be added to the Backup Job. + enum: + - Always + - OnFailure + - Never + type: string + s3: + description: S3 defines the configuration to restore backups from + a S3 compatible storage. It has priority over Volume. + properties: + accessKeyIdSecretKeyRef: + description: AccessKeyIdSecretKeyRef is a reference to a Secret + key containing the S3 access key id. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + bucket: + description: Bucket is the name Name of the bucket to store backups. + type: string + endpoint: + description: Endpoint is the S3 API endpoint without scheme. + type: string + prefix: + description: 'Prefix indicates a folder/subfolder in the bucket. + For example: mariadb/ or mariadb/backups. A trailing slash ''/'' + is added if not provided.' + type: string + region: + description: Region is the S3 region name to use. + type: string + secretAccessKeySecretKeyRef: + description: AccessKeyIdSecretKeyRef is a reference to a Secret + key containing the S3 secret key. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + sessionTokenSecretKeyRef: + description: SessionTokenSecretKeyRef is a reference to a Secret + key containing the S3 session token. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + tls: + description: TLS provides the configuration required to establish + TLS connections with S3. + properties: + caSecretKeyRef: + description: |- + CASecretKeyRef is a reference to a Secret key containing a CA bundle in PEM format used to establish TLS connections with S3. + By default, the system trust chain will be used, but you can use this field to add more CAs to the bundle. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + enabled: + description: Enabled is a flag to enable TLS. + type: boolean + type: object + required: + - bucket + - endpoint + type: object + securityContext: + description: SecurityContext holds security configuration that will + be applied to a container. + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + description: Adds and removes POSIX capabilities from running + containers. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + type: object + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + to be used by the Pods. + type: string + stagingStorage: + description: |- + StagingStorage defines the temporary storage used to keep external backups (i.e. S3) while they are being processed. + It defaults to an emptyDir volume, meaning that the backups will be temporarily stored in the node where the Restore Job is scheduled. + properties: + persistentVolumeClaim: + description: PersistentVolumeClaim is a Kubernetes PVC specification. + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + resources: + description: VolumeResourceRequirements describes the storage + resource requirements for a volume. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + storageClassName: + type: string + type: object + volume: + description: Volume is a Kubernetes volume specification. + properties: + csi: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#csivolumesource-v1-core.' + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + emptyDir: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#emptydirvolumesource-v1-core.' + properties: + medium: + description: StorageMedium defines ways that storage can + be allocated to a volume. + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#hostpathvolumesource-v1-core' + properties: + path: + type: string + type: + type: string + required: + - path + type: object + nfs: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nfsvolumesource-v1-core.' + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#persistentvolumeclaimvolumesource-v1-core.' + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + type: object + type: object + targetRecoveryTime: + description: |- + TargetRecoveryTime is a RFC3339 (1970-01-01T00:00:00Z) date and time that defines the point in time recovery objective. + It is used to determine the closest restoration source in time. + format: date-time + type: string + tolerations: + description: Tolerations to be used in the Pod. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + volume: + description: Volume is a Kubernetes Volume object that contains a + backup. + properties: + csi: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#csivolumesource-v1-core.' + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + emptyDir: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#emptydirvolumesource-v1-core.' + properties: + medium: + description: StorageMedium defines ways that storage can be + allocated to a volume. + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#hostpathvolumesource-v1-core' + properties: + path: + type: string + type: + type: string + required: + - path + type: object + nfs: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nfsvolumesource-v1-core.' + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#persistentvolumeclaimvolumesource-v1-core.' + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + type: object + required: + - mariaDbRef + type: object + status: + description: RestoreStatus defines the observed state of restore + properties: + conditions: + description: Conditions for the Restore object. + 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 + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: sqljobs.k8s.mariadb.com +spec: + group: k8s.mariadb.com + names: + kind: SqlJob + listKind: SqlJobList + plural: sqljobs + shortNames: + - smdb + singular: sqljob + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Complete")].status + name: Complete + type: string + - jsonPath: .status.conditions[?(@.type=="Complete")].message + name: Status + type: string + - jsonPath: .spec.mariaDbRef.name + name: MariaDB + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: SqlJob is the Schema for the sqljobs API. It is used to run sql + scripts as jobs. + 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: SqlJobSpec defines the desired state of SqlJob + properties: + affinity: + description: Affinity to be used in the Pod. + properties: + antiAffinityEnabled: + description: |- + AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. + Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. + type: boolean + nodeAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeaffinity-v1-core' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#preferredschedulingterm-v1-core' + properties: + preference: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselector-v1-core' + properties: + nodeSelectorTerms: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorterm-v1-core' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#nodeselectorrequirement-v1-core' + properties: + key: + type: string + operator: + description: |- + A node selector operator is the set of operators that can be used in + a node selector requirement. + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + type: object + podAntiAffinity: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podantiaffinity-v1-core.' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#weightedpodaffinityterm-v1-core.' + properties: + podAffinityTerm: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: + https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector operator + is the set of operators that can be + used in a selector requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#podaffinityterm-v1-core.' + properties: + labelSelector: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselector-v1-meta' + properties: + matchExpressions: + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#labelselectorrequirement-v1-meta' + properties: + key: + type: string + operator: + description: A label selector operator is + the set of operators that can be used in + a selector requirement. + type: string + values: + 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 + type: object + type: object + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + args: + description: Args to be used in the Container. + items: + type: string + type: array + backoffLimit: + default: 5 + description: BackoffLimit defines the maximum number of attempts to + successfully execute a SqlJob. + format: int32 + type: integer + database: + description: Username to be used when executing the SqlJob. + type: string + dependsOn: + description: DependsOn defines dependencies with other SqlJob objectecs. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: array + failedJobsHistoryLimit: + description: FailedJobsHistoryLimit defines the maximum number of + failed Jobs to be displayed. + format: int32 + minimum: 0 + type: integer + imagePullSecrets: + description: ImagePullSecrets is the list of pull Secrets to be used + to pull the image. + items: + description: 'Refer to the Kubernetes docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.34/#localobjectreference-v1-core.' + properties: + name: + default: "" + type: string + type: object + type: array + inheritMetadata: + description: InheritMetadata defines the metadata to be inherited + by children resources. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + mariaDbRef: + description: MariaDBRef is a reference to a MariaDB object. + properties: + kind: + description: Kind of the referent. + type: string + name: + type: string + namespace: + type: string + waitForIt: + default: true + description: WaitForIt indicates whether the controller using + this reference should wait for MariaDB to be ready. + type: boolean + type: object + nodeSelector: + additionalProperties: + type: string + description: NodeSelector to be used in the Pod. + type: object + passwordSecretKeyRef: + description: UserPasswordSecretKeyRef is a reference to the impersonated + user's password to be used when executing the SqlJob. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + podMetadata: + description: PodMetadata defines extra metadata for the Pod. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to be added to children resources. + type: object + labels: + additionalProperties: + type: string + description: Labels to be added to children resources. + type: object + type: object + podSecurityContext: + description: SecurityContext holds pod-level security attributes and + common container settings. + properties: + appArmorProfile: + description: AppArmorProfile defines a pod or container's AppArmor + settings. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + PodFSGroupChangePolicy holds policies that will be used for applying fsGroup to a volume + when volume is mounted. + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + description: SELinuxOptions are the labels to be applied to the + container + properties: + level: + description: Level is SELinux level label that applies to + the container. + type: string + role: + description: Role is a SELinux role label that applies to + the container. + type: string + type: + description: Type is a SELinux type label that applies to + the container. + type: string + user: + description: User is a SELinux user label that applies to + the container. + type: string + type: object + seccompProfile: + description: |- + SeccompProfile defines a pod/container's seccomp profile settings. + Only one profile source may be set. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + type: object + priorityClassName: + description: PriorityClassName to be used in the Pod. + type: string + resources: + description: Resources describes the compute resource requirements. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: ResourceList is a set of (resource name, quantity) + pairs. + type: object + type: object + restartPolicy: + default: OnFailure + description: RestartPolicy to be added to the SqlJob Pod. + enum: + - Always + - OnFailure + - Never + type: string + schedule: + description: Schedule defines when the SqlJob will be executed. + properties: + cron: + description: Cron is a cron expression that defines the schedule. + type: string + suspend: + default: false + description: Suspend defines whether the schedule is active or + not. + type: boolean + required: + - cron + type: object + securityContext: + description: SecurityContext holds security configuration that will + be applied to a container. + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + description: Adds and removes POSIX capabilities from running + containers. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + type: object + serviceAccountName: + description: ServiceAccountName is the name of the ServiceAccount + to be used by the Pods. + type: string + sql: + description: Sql is the script to be executed by the SqlJob. + type: string + sqlConfigMapKeyRef: + description: |- + SqlConfigMapKeyRef is a reference to a ConfigMap containing the Sql script. + It is defaulted to a ConfigMap with the contents of the Sql field. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + successfulJobsHistoryLimit: + description: SuccessfulJobsHistoryLimit defines the maximum number + of successful Jobs to be displayed. + format: int32 + minimum: 0 + type: integer + timeZone: + description: TimeZone defines the timezone associated with the cron + expression. + type: string + tlsCASecretRef: + description: |- + TLSCACertSecretRef is a reference toa CA Secret used to establish trust when executing the SqlJob. + If not provided, the CA bundle provided by the referred MariaDB is used. + properties: + name: + default: "" + type: string + type: object + tlsClientCertSecretRef: + description: |- + TLSClientCertSecretRef is a reference to a Kubernetes TLS Secret used as authentication when executing the SqlJob. + If not provided, the client certificate provided by the referred MariaDB is used. + properties: + name: + default: "" + type: string + type: object + tolerations: + description: Tolerations to be used in the Pod. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + username: + description: Username to be impersonated when executing the SqlJob. + type: string + required: + - mariaDbRef + - passwordSecretKeyRef + - username + type: object + status: + description: SqlJobStatus defines the observed state of SqlJob + properties: + conditions: + description: Conditions for the SqlJob object. + 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 + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: users.k8s.mariadb.com +spec: + group: k8s.mariadb.com + names: + kind: User + listKind: UserList + plural: users + shortNames: + - umdb + singular: user + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .spec.maxUserConnections + name: MaxConns + type: string + - jsonPath: .spec.mariaDbRef.name + name: MariaDB + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: User is the Schema for the users API. It is used to define grants + as if you were running a 'CREATE USER' statement. + 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: UserSpec defines the desired state of User + properties: + cleanupPolicy: + description: CleanupPolicy defines the behavior for cleaning up a + SQL resource. + enum: + - Skip + - Delete + type: string + host: + description: Host related to the User. + maxLength: 255 + type: string + mariaDbRef: + description: MariaDBRef is a reference to a MariaDB object. + properties: + kind: + description: Kind of the referent. + type: string + name: + type: string + namespace: + type: string + waitForIt: + default: true + description: WaitForIt indicates whether the controller using + this reference should wait for MariaDB to be ready. + type: boolean + type: object + maxUserConnections: + default: 10 + description: MaxUserConnections defines the maximum number of simultaneous + connections that the User can establish. + format: int32 + type: integer + name: + description: Name overrides the default name provided by metadata.name. + maxLength: 80 + type: string + passwordHashSecretKeyRef: + description: |- + PasswordHashSecretKeyRef is a reference to the password hash to be used by the User. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password hash. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + passwordPlugin: + description: PasswordPlugin is a reference to the password plugin + and arguments to be used by the User. + properties: + pluginArgSecretKeyRef: + description: |- + PluginArgSecretKeyRef is a reference to the arguments to be provided to the authentication plugin for the User. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the authentication plugin arguments. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + pluginNameSecretKeyRef: + description: |- + PluginNameSecretKeyRef is a reference to the authentication plugin to be used by the User. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the authentication plugin. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + passwordSecretKeyRef: + description: |- + PasswordSecretKeyRef is a reference to the password to be used by the User. + If not provided, the account will be locked and the password will expire. + If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. + properties: + key: + type: string + name: + default: "" + type: string + required: + - key + type: object + x-kubernetes-map-type: atomic + requeueInterval: + description: RequeueInterval is used to perform requeue reconciliations. + type: string + require: + description: 'Require specifies TLS requirements for the user to connect. + See: https://mariadb.com/kb/en/securing-connections-for-client-and-server/#requiring-tls.' + properties: + issuer: + description: Issuer indicates that the TLS certificate provided + by the user must be issued by a specific issuer. + type: string + ssl: + description: SSL indicates that the user must connect via TLS. + type: boolean + subject: + description: Subject indicates that the TLS certificate provided + by the user must have a specific subject. + type: string + x509: + description: X509 indicates that the user must provide a valid + x509 certificate to connect. + type: boolean + type: object + retryInterval: + description: RetryInterval is the interval used to perform retries. + type: string + required: + - mariaDbRef + type: object + status: + description: UserStatus defines the observed state of User + properties: + conditions: + description: Conditions for the User object. + 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 + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/charts/mariadb-operator-crds/values.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/charts/mariadb-operator-crds/values.yaml new file mode 100644 index 00000000..e69de29b diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/crds/crds.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/crds/crds.yaml deleted file mode 100644 index 985e88a0..00000000 --- a/packages/system/mariadb-operator/charts/mariadb-operator/crds/crds.yaml +++ /dev/null @@ -1,47920 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: backups.k8s.mariadb.com -spec: - group: k8s.mariadb.com - names: - kind: Backup - listKind: BackupList - plural: backups - shortNames: - - bmdb - singular: backup - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Complete")].status - name: Complete - type: string - - jsonPath: .status.conditions[?(@.type=="Complete")].message - name: Status - type: string - - jsonPath: .spec.mariaDbRef.name - name: MariaDB - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: Backup is the Schema for the backups API. It is used to define - backup jobs and its storage. - 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: BackupSpec defines the desired state of Backup - properties: - affinity: - description: Affinity to be used in the Pod. - properties: - antiAffinityEnabled: - description: |- - AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. - Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. - type: boolean - nodeAffinity: - description: Describes node affinity scheduling rules for the - pod. - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - properties: - preference: - description: A node selector term, associated with the - corresponding weight. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding - nodeSelectorTerm, in the range 1-100. - format: int32 - type: integer - required: - - preference - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. - The terms are ORed. - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - type: array - x-kubernetes-list-type: atomic - required: - - nodeSelectorTerms - type: object - x-kubernetes-map-type: atomic - type: object - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate - this pod in the same node, zone, etc. as some other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated - with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. - avoid putting this pod in the same node, zone, etc. as some - other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated - with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - type: object - args: - description: Args to be used in the Container. - items: - type: string - type: array - backoffLimit: - description: BackoffLimit defines the maximum number of attempts to - successfully take a Backup. - format: int32 - type: integer - databases: - description: Databases defines the logical databases to be backed - up. If not provided, all databases are backed up. - items: - type: string - type: array - failedJobsHistoryLimit: - description: FailedJobsHistoryLimit defines the maximum number of - failed Jobs to be displayed. - format: int32 - minimum: 0 - type: integer - ignoreGlobalPriv: - description: |- - IgnoreGlobalPriv indicates to ignore the mysql.global_priv in backups. - If not provided, it will default to true when the referred MariaDB instance has Galera enabled and otherwise to false. - See: https://github.com/mariadb-operator/mariadb-operator/issues/556 - type: boolean - imagePullSecrets: - description: ImagePullSecrets is the list of pull Secrets to be used - to pull the image. - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - inheritMetadata: - description: InheritMetadata defines the metadata to be inherited - by children resources. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - logLevel: - default: info - description: LogLevel to be used n the Backup Job. It defaults to - 'info'. - type: string - mariaDbRef: - description: MariaDBRef is a reference to a MariaDB object. - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - waitForIt: - default: true - description: WaitForIt indicates whether the controller using - this reference should wait for MariaDB to be ready. - type: boolean - type: object - x-kubernetes-map-type: atomic - maxRetention: - description: |- - MaxRetention defines the retention policy for backups. Old backups will be cleaned up by the Backup Job. - It defaults to 30 days. - type: string - nodeSelector: - additionalProperties: - type: string - description: NodeSelector to be used in the Pod. - type: object - podMetadata: - description: PodMetadata defines extra metadata for the Pod. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - podSecurityContext: - description: SecurityContext holds pod-level security attributes and - common container settings. - properties: - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies to - the container. - type: string - role: - description: Role is a SELinux role label that applies to - the container. - type: string - type: - description: Type is a SELinux type label that applies to - the container. - type: string - user: - description: User is a SELinux user label that applies to - the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in - addition to the container's primary GID and fsGroup (if specified). If - the SupplementalGroupsPolicy feature is enabled, the - supplementalGroupsPolicy field determines whether these are in addition - to or instead of any group memberships defined in the container image. - If unspecified, no additional groups are added, though group memberships - defined in the container image may still be used, depending on the - supplementalGroupsPolicy field. - Note that this field cannot be set when spec.os.name is windows. - items: - format: int64 - type: integer - type: array - x-kubernetes-list-type: atomic - supplementalGroupsPolicy: - description: |- - Defines how supplemental groups of the first container processes are calculated. - Valid values are "Merge" and "Strict". If not specified, "Merge" is used. - (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled - and the container runtime must implement support for this feature. - Note that this field cannot be set when spec.os.name is windows. - type: string - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - items: - description: Sysctl defines a kernel parameter to be set - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options within a container's SecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of the GMSA - credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - priorityClassName: - description: PriorityClassName to be used in the Pod. - type: string - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - restartPolicy: - default: OnFailure - description: RestartPolicy to be added to the Backup Pod. - enum: - - Always - - OnFailure - - Never - type: string - schedule: - description: Schedule defines when the Backup will be taken. - properties: - cron: - description: Cron is a cron expression that defines the schedule. - type: string - suspend: - default: false - description: Suspend defines whether the schedule is active or - not. - type: boolean - required: - - cron - type: object - securityContext: - description: SecurityContext holds security configuration that will - be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies to - the container. - type: string - role: - description: Role is a SELinux role label that applies to - the container. - type: string - type: - description: Type is a SELinux type label that applies to - the container. - type: string - user: - description: User is a SELinux user label that applies to - the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of the GMSA - credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to be used by the Pods. - type: string - storage: - description: Storage to be used in the Backup. - properties: - persistentVolumeClaim: - description: PersistentVolumeClaim is a Kubernetes PVC specification. - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes to consider - for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to the PersistentVolume - backing this claim. - type: string - type: object - s3: - description: S3 defines the configuration to store backups in - a S3 compatible storage. - properties: - accessKeyIdSecretKeyRef: - description: AccessKeyIdSecretKeyRef is a reference to a Secret - key containing the S3 access key id. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - bucket: - description: Bucket is the name Name of the bucket to store - backups. - type: string - endpoint: - description: Endpoint is the S3 API endpoint without scheme. - type: string - prefix: - description: 'Prefix indicates a folder/subfolder in the bucket. - For example: mariadb/ or mariadb/backups. A trailing slash - ''/'' is added if not provided.' - type: string - region: - description: Region is the S3 region name to use. - type: string - secretAccessKeySecretKeyRef: - description: AccessKeyIdSecretKeyRef is a reference to a Secret - key containing the S3 secret key. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - sessionTokenSecretKeyRef: - description: SessionTokenSecretKeyRef is a reference to a - Secret key containing the S3 session token. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - tls: - description: TLS provides the configuration required to establish - TLS connections with S3. - properties: - caSecretKeyRef: - description: |- - CASecretKeyRef is a reference to a Secret key containing a CA bundle in PEM format used to establish TLS connections with S3. - By default, the system trust chain will be used, but you can use this field to add more CAs to the bundle. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - enabled: - description: Enabled is a flag to enable TLS. - type: boolean - type: object - required: - - accessKeyIdSecretKeyRef - - bucket - - endpoint - - secretAccessKeySecretKeyRef - type: object - volume: - description: Volume is a Kubernetes volume specification. - properties: - awsElasticBlockStore: - description: |- - awsElasticBlockStore represents an AWS Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - format: int32 - type: integer - readOnly: - description: |- - readOnly value true will force the readOnly setting in VolumeMounts. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: boolean - volumeID: - description: |- - volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - required: - - volumeID - type: object - azureDisk: - description: azureDisk represents an Azure Data Disk mount - on the host and bind mount to the pod. - properties: - cachingMode: - description: 'cachingMode is the Host Caching mode: None, - Read Only, Read Write.' - type: string - diskName: - description: diskName is the Name of the data disk in - the blob storage - type: string - diskURI: - description: diskURI is the URI of data disk in the blob - storage - type: string - fsType: - default: ext4 - description: |- - fsType is Filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - kind: - description: 'kind expected values are Shared: multiple - blob disks per storage account Dedicated: single blob - disk per storage account Managed: azure managed data - disk (only in managed availability set). defaults to - shared' - type: string - readOnly: - default: false - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - required: - - diskName - - diskURI - type: object - azureFile: - description: azureFile represents an Azure File Service mount - on the host and bind mount to the pod. - properties: - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretName: - description: secretName is the name of secret that contains - Azure Storage Account Name and Key - type: string - shareName: - description: shareName is the azure share Name - type: string - required: - - secretName - - shareName - type: object - cephfs: - description: cephFS represents a Ceph FS mount on the host - that shares a pod's lifetime - properties: - monitors: - description: |- - monitors is Required: Monitors is a collection of Ceph monitors - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - path: - description: 'path is Optional: Used as the mounted root, - rather than the full Ceph tree, default is /' - type: string - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: boolean - secretFile: - description: |- - secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - secretRef: - description: |- - secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - description: |- - user is optional: User is the rados user name, default is admin - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - required: - - monitors - type: object - cinder: - description: |- - cinder represents a cinder volume attached and mounted on kubelets host machine. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: boolean - secretRef: - description: |- - secretRef is optional: points to a secret object containing parameters used to connect - to OpenStack. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeID: - description: |- - volumeID used to identify the volume in cinder. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - required: - - volumeID - type: object - configMap: - description: configMap represents a configMap that should - populate this volume - properties: - defaultMode: - description: |- - defaultMode is optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether the ConfigMap or - its keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - csi: - description: csi (Container Storage Interface) represents - ephemeral storage that is handled by certain external CSI - drivers (Beta feature). - properties: - driver: - description: |- - driver is the name of the CSI driver that handles this volume. - Consult with your admin for the correct name as registered in the cluster. - type: string - fsType: - description: |- - fsType to mount. Ex. "ext4", "xfs", "ntfs". - If not provided, the empty value is passed to the associated CSI driver - which will determine the default filesystem to apply. - type: string - nodePublishSecretRef: - description: |- - nodePublishSecretRef is a reference to the secret object containing - sensitive information to pass to the CSI driver to complete the CSI - NodePublishVolume and NodeUnpublishVolume calls. - This field is optional, and may be empty if no secret is required. If the - secret object contains more than one secret, all secret references are passed. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - readOnly: - description: |- - readOnly specifies a read-only configuration for the volume. - Defaults to false (read/write). - type: boolean - volumeAttributes: - additionalProperties: - type: string - description: |- - volumeAttributes stores driver-specific properties that are passed to the CSI - driver. Consult your driver's documentation for supported values. - type: object - required: - - driver - type: object - downwardAPI: - description: downwardAPI represents downward API about the - pod that should populate this volume - properties: - defaultMode: - description: |- - Optional: mode bits to use on created files by default. Must be a - Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: Items is a list of downward API volume file - items: - description: DownwardAPIVolumeFile represents information - to create the file containing the pod field - properties: - fieldRef: - description: 'Required: Selects a field of the pod: - only annotations, labels, name, namespace and - uid are supported.' - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in - the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path is the relative path - name of the file to be created. Must not be absolute - or contain the ''..'' path. Must be utf-8 encoded. - The first item of the relative path must not start - with ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of - the exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - emptyDir: - description: |- - emptyDir represents a temporary directory that shares a pod's lifetime. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - properties: - medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - ephemeral: - description: |- - ephemeral represents a volume that is handled by a cluster storage driver. - The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, - and deleted when the pod is removed. - - Use this if: - a) the volume is only needed while the pod runs, - b) features of normal volumes like restoring from snapshot or capacity - tracking are needed, - c) the storage driver is specified through a storage class, and - d) the storage driver supports dynamic volume provisioning through - a PersistentVolumeClaim (see EphemeralVolumeSource for more - information on the connection between this volume type - and PersistentVolumeClaim). - - Use PersistentVolumeClaim or one of the vendor-specific - APIs for volumes that persist for longer than the lifecycle - of an individual pod. - - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to - be used that way - see the documentation of the driver for - more information. - - A pod can use both types of ephemeral volumes and - persistent volumes at the same time. - properties: - volumeClaimTemplate: - description: |- - Will be used to create a stand-alone PVC to provision the volume. - The pod in which this EphemeralVolumeSource is embedded will be the - owner of the PVC, i.e. the PVC will be deleted together with the - pod. The name of the PVC will be `-` where - `` is the name from the `PodSpec.Volumes` array - entry. Pod validation will reject the pod if the concatenated name - is not valid for a PVC (for example, too long). - - An existing PVC with that name that is not owned by the pod - will *not* be used for the pod to avoid using an unrelated - volume by mistake. Starting the pod is then blocked until - the unrelated PVC is removed. If such a pre-created PVC is - meant to be used by the pod, the PVC has to updated with an - owner reference to the pod once the pod exists. Normally - this should not be necessary, but it may be useful when - manually reconstructing a broken cluster. - - This field is read-only and no changes will be made by Kubernetes - to the PVC after it has been created. - - Required, must not be nil. - properties: - metadata: - description: |- - May contain labels and annotations that will be copied into the PVC - when creating it. No other fields are allowed and will be rejected during - validation. - type: object - spec: - description: |- - The specification for the PersistentVolumeClaim. The entire content is - copied unchanged into the PVC that gets created from this - template. The same fields as in a PersistentVolumeClaim - are also valid here. - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource - being referenced - type: string - name: - description: Name is the name of resource - being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource - being referenced - type: string - name: - description: Name is the name of resource - being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes - to consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference - to the PersistentVolume backing this claim. - type: string - type: object - required: - - spec - type: object - type: object - fc: - description: fc represents a Fibre Channel resource that is - attached to a kubelet's host machine and then exposed to - the pod. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - lun: - description: 'lun is Optional: FC target lun number' - format: int32 - type: integer - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - targetWWNs: - description: 'targetWWNs is Optional: FC target worldwide - names (WWNs)' - items: - type: string - type: array - x-kubernetes-list-type: atomic - wwids: - description: |- - wwids Optional: FC volume world wide identifiers (wwids) - Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - flexVolume: - description: |- - flexVolume represents a generic volume resource that is - provisioned/attached using an exec based plugin. - properties: - driver: - description: driver is the name of the driver to use for - this volume. - type: string - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. - type: string - options: - additionalProperties: - type: string - description: 'options is Optional: this field holds extra - command options if any.' - type: object - readOnly: - description: |- - readOnly is Optional: defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef is Optional: secretRef is reference to the secret object containing - sensitive information to pass to the plugin scripts. This may be - empty if no secret object is specified. If the secret object - contains more than one secret, all secrets are passed to the plugin - scripts. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - required: - - driver - type: object - flocker: - description: flocker represents a Flocker volume attached - to a kubelet's host machine. This depends on the Flocker - control service being running - properties: - datasetName: - description: |- - datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker - should be considered as deprecated - type: string - datasetUUID: - description: datasetUUID is the UUID of the dataset. This - is unique identifier of a Flocker dataset - type: string - type: object - gcePersistentDisk: - description: |- - gcePersistentDisk represents a GCE Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - properties: - fsType: - description: |- - fsType is filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - format: int32 - type: integer - pdName: - description: |- - pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: boolean - required: - - pdName - type: object - gitRepo: - description: |- - gitRepo represents a git repository at a particular revision. - DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an - EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir - into the Pod's container. - properties: - directory: - description: |- - directory is the target directory name. - Must not contain or start with '..'. If '.' is supplied, the volume directory will be the - git repository. Otherwise, if specified, the volume will contain the git repository in - the subdirectory with the given name. - type: string - repository: - description: repository is the URL - type: string - revision: - description: revision is the commit hash for the specified - revision. - type: string - required: - - repository - type: object - glusterfs: - description: |- - glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/glusterfs/README.md - properties: - endpoints: - description: |- - endpoints is the endpoint name that details Glusterfs topology. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - path: - description: |- - path is the Glusterfs volume path. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - readOnly: - description: |- - readOnly here will force the Glusterfs volume to be mounted with read-only permissions. - Defaults to false. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: boolean - required: - - endpoints - - path - type: object - hostPath: - description: |- - hostPath represents a pre-existing file or directory on the host - machine that is directly exposed to the container. This is generally - used for system agents or other privileged things that are allowed - to see the host machine. Most containers will NOT need this. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - properties: - path: - description: |- - path of the directory on the host. - If the path is a symlink, it will follow the link to the real path. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - type: - description: |- - type for HostPath Volume - Defaults to "" - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - required: - - path - type: object - image: - description: |- - image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. - The volume is resolved at pod startup depending on which PullPolicy value is provided: - - - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - - The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. - A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. - 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). - The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. - properties: - pullPolicy: - description: |- - Policy for pulling OCI objects. Possible values are: - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. - type: string - reference: - description: |- - Required: Image or artifact reference to be used. - Behaves in the same way as pod.spec.containers[*].image. - Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. - More info: https://kubernetes.io/docs/concepts/containers/images - This field is optional to allow higher level config management to default or override - container images in workload controllers like Deployments and StatefulSets. - type: string - type: object - iscsi: - description: |- - iscsi represents an ISCSI Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://examples.k8s.io/volumes/iscsi/README.md - properties: - chapAuthDiscovery: - description: chapAuthDiscovery defines whether support - iSCSI Discovery CHAP authentication - type: boolean - chapAuthSession: - description: chapAuthSession defines whether support iSCSI - Session CHAP authentication - type: boolean - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - type: string - initiatorName: - description: |- - initiatorName is the custom iSCSI Initiator Name. - If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface - : will be created for the connection. - type: string - iqn: - description: iqn is the target iSCSI Qualified Name. - type: string - iscsiInterface: - default: default - description: |- - iscsiInterface is the interface Name that uses an iSCSI transport. - Defaults to 'default' (tcp). - type: string - lun: - description: lun represents iSCSI Target Lun number. - format: int32 - type: integer - portals: - description: |- - portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - items: - type: string - type: array - x-kubernetes-list-type: atomic - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - type: boolean - secretRef: - description: secretRef is the CHAP Secret for iSCSI target - and initiator authentication - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - targetPortal: - description: |- - targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - type: string - required: - - iqn - - lun - - targetPortal - type: object - nfs: - description: |- - nfs represents an NFS mount on the host that shares a pod's lifetime - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - properties: - path: - description: |- - path that is exported by the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - readOnly: - description: |- - readOnly here will force the NFS export to be mounted with read-only permissions. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: boolean - server: - description: |- - server is the hostname or IP address of the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - required: - - path - - server - type: object - persistentVolumeClaim: - description: |- - persistentVolumeClaimVolumeSource represents a reference to a - PersistentVolumeClaim in the same namespace. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - claimName: - description: |- - claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - type: string - readOnly: - description: |- - readOnly Will force the ReadOnly setting in VolumeMounts. - Default false. - type: boolean - required: - - claimName - type: object - photonPersistentDisk: - description: photonPersistentDisk represents a PhotonController - persistent disk attached and mounted on kubelets host machine - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - pdID: - description: pdID is the ID that identifies Photon Controller - persistent disk - type: string - required: - - pdID - type: object - portworxVolume: - description: portworxVolume represents a portworx volume attached - and mounted on kubelets host machine - properties: - fsType: - description: |- - fSType represents the filesystem type to mount - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - volumeID: - description: volumeID uniquely identifies a Portworx volume - type: string - required: - - volumeID - type: object - projected: - description: projected items for all in one resources secrets, - configmaps, and downward API - properties: - defaultMode: - description: |- - defaultMode are the mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - sources: - description: |- - sources is the list of volume projections. Each entry in this list - handles one source. - items: - description: |- - Projection that may be projected along with other supported volume types. - Exactly one of these fields must be set. - properties: - clusterTrustBundle: - description: |- - ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field - of ClusterTrustBundle objects in an auto-updating file. - - Alpha, gated by the ClusterTrustBundleProjection feature gate. - - ClusterTrustBundle objects can either be selected by name, or by the - combination of signer name and a label selector. - - Kubelet performs aggressive normalization of the PEM contents written - into the pod filesystem. Esoteric PEM features such as inter-block - comments and block headers are stripped. Certificates are deduplicated. - The ordering of certificates within the file is arbitrary, and Kubelet - may change the order over time. - properties: - labelSelector: - description: |- - Select all ClusterTrustBundles that match this label selector. Only has - effect if signerName is set. Mutually-exclusive with name. If unset, - interpreted as "match nothing". If set but empty, interpreted as "match - everything". - 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 - name: - description: |- - Select a single ClusterTrustBundle by object name. Mutually-exclusive - with signerName and labelSelector. - type: string - optional: - description: |- - If true, don't block pod startup if the referenced ClusterTrustBundle(s) - aren't available. If using name, then the named ClusterTrustBundle is - allowed not to exist. If using signerName, then the combination of - signerName and labelSelector is allowed to match zero - ClusterTrustBundles. - type: boolean - path: - description: Relative path from the volume root - to write the bundle. - type: string - signerName: - description: |- - Select all ClusterTrustBundles that match this signer name. - Mutually-exclusive with name. The contents of all selected - ClusterTrustBundles will be unified and deduplicated. - type: string - required: - - path - type: object - configMap: - description: configMap information about the configMap - data to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether the ConfigMap - or its keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - downwardAPI: - description: downwardAPI information about the downwardAPI - data to project - properties: - items: - description: Items is a list of DownwardAPIVolume - file - items: - description: DownwardAPIVolumeFile represents - information to create the file containing - the pod field - properties: - fieldRef: - description: 'Required: Selects a field - of the pod: only annotations, labels, - name, namespace and uid are supported.' - properties: - apiVersion: - description: Version of the schema - the FieldPath is written in terms - of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to - select in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path is the relative - path name of the file to be created. - Must not be absolute or contain the - ''..'' path. Must be utf-8 encoded. - The first item of the relative path - must not start with ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output - format of the exposed resources, - defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to - select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - secret: - description: secret information about the secret - data to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional field specify whether - the Secret or its key must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - serviceAccountToken: - description: serviceAccountToken is information - about the serviceAccountToken data to project - properties: - audience: - description: |- - audience is the intended audience of the token. A recipient of a token - must identify itself with an identifier specified in the audience of the - token, and otherwise should reject the token. The audience defaults to the - identifier of the apiserver. - type: string - expirationSeconds: - description: |- - expirationSeconds is the requested duration of validity of the service - account token. As the token approaches expiration, the kubelet volume - plugin will proactively rotate the service account token. The kubelet will - start trying to rotate the token if the token is older than 80 percent of - its time to live or if the token is older than 24 hours.Defaults to 1 hour - and must be at least 10 minutes. - format: int64 - type: integer - path: - description: |- - path is the path relative to the mount point of the file to project the - token into. - type: string - required: - - path - type: object - type: object - type: array - x-kubernetes-list-type: atomic - type: object - quobyte: - description: quobyte represents a Quobyte mount on the host - that shares a pod's lifetime - properties: - group: - description: |- - group to map volume access to - Default is no group - type: string - readOnly: - description: |- - readOnly here will force the Quobyte volume to be mounted with read-only permissions. - Defaults to false. - type: boolean - registry: - description: |- - registry represents a single or multiple Quobyte Registry services - specified as a string as host:port pair (multiple entries are separated with commas) - which acts as the central registry for volumes - type: string - tenant: - description: |- - tenant owning the given Quobyte volume in the Backend - Used with dynamically provisioned Quobyte volumes, value is set by the plugin - type: string - user: - description: |- - user to map volume access to - Defaults to serivceaccount user - type: string - volume: - description: volume is a string that references an already - created Quobyte volume by name. - type: string - required: - - registry - - volume - type: object - rbd: - description: |- - rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/rbd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - type: string - image: - description: |- - image is the rados image name. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - keyring: - default: /etc/ceph/keyring - description: |- - keyring is the path to key ring for RBDUser. - Default is /etc/ceph/keyring. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - monitors: - description: |- - monitors is a collection of Ceph monitors. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - pool: - default: rbd - description: |- - pool is the rados pool name. - Default is rbd. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: boolean - secretRef: - description: |- - secretRef is name of the authentication secret for RBDUser. If provided - overrides keyring. - Default is nil. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - default: admin - description: |- - user is the rados user name. - Default is admin. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - required: - - image - - monitors - type: object - scaleIO: - description: scaleIO represents a ScaleIO persistent volume - attached and mounted on Kubernetes nodes. - properties: - fsType: - default: xfs - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". - Default is "xfs". - type: string - gateway: - description: gateway is the host address of the ScaleIO - API Gateway. - type: string - protectionDomain: - description: protectionDomain is the name of the ScaleIO - Protection Domain for the configured storage. - type: string - readOnly: - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef references to the secret for ScaleIO user and other - sensitive information. If this is not provided, Login operation will fail. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - sslEnabled: - description: sslEnabled Flag enable/disable SSL communication - with Gateway, default false - type: boolean - storageMode: - default: ThinProvisioned - description: |- - storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. - Default is ThinProvisioned. - type: string - storagePool: - description: storagePool is the ScaleIO Storage Pool associated - with the protection domain. - type: string - system: - description: system is the name of the storage system - as configured in ScaleIO. - type: string - volumeName: - description: |- - volumeName is the name of a volume already created in the ScaleIO system - that is associated with this volume source. - type: string - required: - - gateway - - secretRef - - system - type: object - secret: - description: |- - secret represents a secret that should populate this volume. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - properties: - defaultMode: - description: |- - defaultMode is Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values - for mode bits. Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items If unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - optional: - description: optional field specify whether the Secret - or its keys must be defined - type: boolean - secretName: - description: |- - secretName is the name of the secret in the pod's namespace to use. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - type: string - type: object - storageos: - description: storageOS represents a StorageOS volume attached - and mounted on Kubernetes nodes. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef specifies the secret to use for obtaining the StorageOS API - credentials. If not specified, default values will be attempted. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeName: - description: |- - volumeName is the human-readable name of the StorageOS volume. Volume - names are only unique within a namespace. - type: string - volumeNamespace: - description: |- - volumeNamespace specifies the scope of the volume within StorageOS. If no - namespace is specified then the Pod's namespace will be used. This allows the - Kubernetes name scoping to be mirrored within StorageOS for tighter integration. - Set VolumeName to any name to override the default behaviour. - Set to "default" if you are not using namespaces within StorageOS. - Namespaces that do not pre-exist within StorageOS will be created. - type: string - type: object - vsphereVolume: - description: vsphereVolume represents a vSphere volume attached - and mounted on kubelets host machine - properties: - fsType: - description: |- - fsType is filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - storagePolicyID: - description: storagePolicyID is the storage Policy Based - Management (SPBM) profile ID associated with the StoragePolicyName. - type: string - storagePolicyName: - description: storagePolicyName is the storage Policy Based - Management (SPBM) profile name. - type: string - volumePath: - description: volumePath is the path that identifies vSphere - volume vmdk - type: string - required: - - volumePath - type: object - type: object - type: object - successfulJobsHistoryLimit: - description: SuccessfulJobsHistoryLimit defines the maximum number - of successful Jobs to be displayed. - format: int32 - minimum: 0 - type: integer - timeZone: - description: TimeZone defines the timezone associated with the cron - expression. - type: string - tolerations: - description: Tolerations to be used in the Pod. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - required: - - mariaDbRef - - storage - type: object - status: - description: BackupStatus defines the observed state of Backup - properties: - conditions: - description: Conditions for the Backup object. - 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 - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: connections.k8s.mariadb.com -spec: - group: k8s.mariadb.com - names: - kind: Connection - listKind: ConnectionList - plural: connections - shortNames: - - cmdb - singular: connection - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - type: string - - jsonPath: .spec.secretName - name: Secret - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: Connection is the Schema for the connections API. It is used - to configure connection strings for the applications connecting to MariaDB. - 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: ConnectionSpec defines the desired state of Connection - properties: - database: - description: Database to use when configuring the Connection. - type: string - healthCheck: - description: HealthCheck to be used in the Connection. - properties: - interval: - description: Interval used to perform health checks. - type: string - retryInterval: - description: RetryInterval is the interval used to perform health - check retries. - type: string - type: object - host: - description: Host to connect to. If not provided, it defaults to the - MariaDB host or to the MaxScale host. - type: string - mariaDbRef: - description: MariaDBRef is a reference to the MariaDB to connect to. - Either MariaDBRef or MaxScaleRef must be provided. - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - waitForIt: - default: true - description: WaitForIt indicates whether the controller using - this reference should wait for MariaDB to be ready. - type: boolean - type: object - x-kubernetes-map-type: atomic - maxScaleRef: - description: MaxScaleRef is a reference to the MaxScale to connect - to. Either MariaDBRef or MaxScaleRef must be provided. - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - params: - additionalProperties: - type: string - description: Params to be used in the Connection. - type: object - passwordSecretKeyRef: - description: |- - PasswordSecretKeyRef is a reference to the password to use for configuring the Connection. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. - properties: - key: - description: The key of the secret to select from. Must be a - valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - port: - description: Port to connect to. If not provided, it defaults to the - MariaDB port or to the first MaxScale listener. - format: int32 - type: integer - secretName: - description: SecretName to be used in the Connection. - type: string - secretTemplate: - description: SecretTemplate to be used in the Connection. - properties: - databaseKey: - description: DatabaseKey to be used in the Secret. - type: string - format: - description: Format to be used in the Secret. - type: string - hostKey: - description: HostKey to be used in the Secret. - type: string - key: - description: Key to be used in the Secret. - type: string - metadata: - description: Metadata to be added to the Secret object. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - passwordKey: - description: PasswordKey to be used in the Secret. - type: string - portKey: - description: PortKey to be used in the Secret. - type: string - usernameKey: - description: UsernameKey to be used in the Secret. - type: string - type: object - serviceName: - description: ServiceName to be used in the Connection. - type: string - username: - description: Username to use for configuring the Connection. - type: string - required: - - passwordSecretKeyRef - - username - type: object - status: - description: ConnectionStatus defines the observed state of Connection - properties: - conditions: - description: Conditions for the Connection object. - 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 - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: databases.k8s.mariadb.com -spec: - group: k8s.mariadb.com - names: - kind: Database - listKind: DatabaseList - plural: databases - shortNames: - - dmdb - singular: database - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - type: string - - jsonPath: .spec.characterSet - name: CharSet - type: string - - jsonPath: .spec.collate - name: Collate - type: string - - jsonPath: .spec.mariaDbRef.name - name: MariaDB - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - - jsonPath: .spec.name - name: Name - type: string - name: v1alpha1 - schema: - openAPIV3Schema: - description: Database is the Schema for the databases API. It is used to define - a logical database as if you were running a 'CREATE DATABASE' statement. - 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: DatabaseSpec defines the desired state of Database - properties: - characterSet: - default: utf8 - description: CharacterSet to use in the Database. - type: string - cleanupPolicy: - description: CleanupPolicy defines the behavior for cleaning up a - SQL resource. - enum: - - Skip - - Delete - type: string - collate: - default: utf8_general_ci - description: Collate to use in the Database. - type: string - mariaDbRef: - description: MariaDBRef is a reference to a MariaDB object. - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - waitForIt: - default: true - description: WaitForIt indicates whether the controller using - this reference should wait for MariaDB to be ready. - type: boolean - type: object - x-kubernetes-map-type: atomic - name: - description: Name overrides the default Database name provided by - metadata.name. - maxLength: 80 - type: string - requeueInterval: - description: RequeueInterval is used to perform requeue reconciliations. - type: string - retryInterval: - description: RetryInterval is the interval used to perform retries. - type: string - required: - - mariaDbRef - type: object - status: - description: DatabaseStatus defines the observed state of Database - properties: - conditions: - description: Conditions for the Database object. - 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 - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: grants.k8s.mariadb.com -spec: - group: k8s.mariadb.com - names: - kind: Grant - listKind: GrantList - plural: grants - shortNames: - - gmdb - singular: grant - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - type: string - - jsonPath: .spec.database - name: Database - type: string - - jsonPath: .spec.table - name: Table - type: string - - jsonPath: .spec.username - name: Username - type: string - - jsonPath: .spec.grantOption - name: GrantOpt - type: string - - jsonPath: .spec.mariaDbRef.name - name: MariaDB - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: Grant is the Schema for the grants API. It is used to define - grants as if you were running a 'GRANT' statement. - 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: GrantSpec defines the desired state of Grant - properties: - cleanupPolicy: - description: CleanupPolicy defines the behavior for cleaning up a - SQL resource. - enum: - - Skip - - Delete - type: string - database: - default: '*' - description: Database to use in the Grant. - type: string - grantOption: - default: false - description: GrantOption to use in the Grant. - type: boolean - host: - description: Host to use in the Grant. It can be localhost, an IP - or '%'. - type: string - mariaDbRef: - description: MariaDBRef is a reference to a MariaDB object. - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - waitForIt: - default: true - description: WaitForIt indicates whether the controller using - this reference should wait for MariaDB to be ready. - type: boolean - type: object - x-kubernetes-map-type: atomic - privileges: - description: Privileges to use in the Grant. - items: - type: string - minItems: 1 - type: array - requeueInterval: - description: RequeueInterval is used to perform requeue reconciliations. - type: string - retryInterval: - description: RetryInterval is the interval used to perform retries. - type: string - table: - default: '*' - description: Table to use in the Grant. - type: string - username: - description: Username to use in the Grant. - type: string - required: - - mariaDbRef - - privileges - - username - type: object - status: - description: GrantStatus defines the observed state of Grant - properties: - conditions: - description: Conditions for the Grant object. - 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 - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: mariadbs.k8s.mariadb.com -spec: - group: k8s.mariadb.com - names: - kind: MariaDB - listKind: MariaDBList - plural: mariadbs - shortNames: - - mdb - singular: mariadb - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - type: string - - jsonPath: .status.currentPrimary - name: Primary Pod - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: MariaDB is the Schema for the mariadbs API. It is used to define - MariaDB clusters. - 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: MariaDBSpec defines the desired state of MariaDB - properties: - affinity: - description: Affinity to be used in the Pod. - properties: - antiAffinityEnabled: - description: |- - AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. - Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. - type: boolean - nodeAffinity: - description: Describes node affinity scheduling rules for the - pod. - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - properties: - preference: - description: A node selector term, associated with the - corresponding weight. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding - nodeSelectorTerm, in the range 1-100. - format: int32 - type: integer - required: - - preference - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. - The terms are ORed. - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - type: array - x-kubernetes-list-type: atomic - required: - - nodeSelectorTerms - type: object - x-kubernetes-map-type: atomic - type: object - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate - this pod in the same node, zone, etc. as some other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated - with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. - avoid putting this pod in the same node, zone, etc. as some - other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated - with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - type: object - args: - description: Args to be used in the Container. - items: - type: string - type: array - bootstrapFrom: - description: BootstrapFrom defines a source to bootstrap from. - properties: - backupRef: - description: BackupRef is a reference to a Backup object. It has - priority over S3 and Volume. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - restoreJob: - description: RestoreJob defines additional properties for the - Job used to perform the Restore. - properties: - affinity: - description: Affinity to be used in the Pod. - properties: - antiAffinityEnabled: - description: |- - AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. - Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. - type: boolean - nodeAffinity: - description: Describes node affinity scheduling rules - for the pod. - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - properties: - preference: - description: A node selector term, associated - with the corresponding weight. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching - the corresponding nodeSelectorTerm, in the - range 1-100. - format: int32 - type: integer - required: - - preference - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - properties: - nodeSelectorTerms: - description: Required. A list of node selector - terms. The terms are ORed. - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - type: array - x-kubernetes-list-type: atomic - required: - - nodeSelectorTerms - type: object - x-kubernetes-map-type: atomic - type: object - podAffinity: - description: Describes pod affinity scheduling rules (e.g. - co-locate this pod in the same node, zone, etc. as some - other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred - node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, - associated with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules - (e.g. avoid putting this pod in the same node, zone, - etc. as some other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred - node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, - associated with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - type: object - args: - description: Args to be used in the Container. - items: - type: string - type: array - metadata: - description: Metadata defines additional metadata for the - bootstrap Jobs. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - type: object - s3: - description: S3 defines the configuration to restore backups from - a S3 compatible storage. It has priority over Volume. - properties: - accessKeyIdSecretKeyRef: - description: AccessKeyIdSecretKeyRef is a reference to a Secret - key containing the S3 access key id. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - bucket: - description: Bucket is the name Name of the bucket to store - backups. - type: string - endpoint: - description: Endpoint is the S3 API endpoint without scheme. - type: string - prefix: - description: 'Prefix indicates a folder/subfolder in the bucket. - For example: mariadb/ or mariadb/backups. A trailing slash - ''/'' is added if not provided.' - type: string - region: - description: Region is the S3 region name to use. - type: string - secretAccessKeySecretKeyRef: - description: AccessKeyIdSecretKeyRef is a reference to a Secret - key containing the S3 secret key. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - sessionTokenSecretKeyRef: - description: SessionTokenSecretKeyRef is a reference to a - Secret key containing the S3 session token. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - tls: - description: TLS provides the configuration required to establish - TLS connections with S3. - properties: - caSecretKeyRef: - description: |- - CASecretKeyRef is a reference to a Secret key containing a CA bundle in PEM format used to establish TLS connections with S3. - By default, the system trust chain will be used, but you can use this field to add more CAs to the bundle. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - enabled: - description: Enabled is a flag to enable TLS. - type: boolean - type: object - required: - - accessKeyIdSecretKeyRef - - bucket - - endpoint - - secretAccessKeySecretKeyRef - type: object - targetRecoveryTime: - description: |- - TargetRecoveryTime is a RFC3339 (1970-01-01T00:00:00Z) date and time that defines the point in time recovery objective. - It is used to determine the closest restoration source in time. - format: date-time - type: string - volume: - description: Volume is a Kubernetes Volume object that contains - a backup. - properties: - awsElasticBlockStore: - description: |- - awsElasticBlockStore represents an AWS Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - format: int32 - type: integer - readOnly: - description: |- - readOnly value true will force the readOnly setting in VolumeMounts. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: boolean - volumeID: - description: |- - volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - required: - - volumeID - type: object - azureDisk: - description: azureDisk represents an Azure Data Disk mount - on the host and bind mount to the pod. - properties: - cachingMode: - description: 'cachingMode is the Host Caching mode: None, - Read Only, Read Write.' - type: string - diskName: - description: diskName is the Name of the data disk in - the blob storage - type: string - diskURI: - description: diskURI is the URI of data disk in the blob - storage - type: string - fsType: - default: ext4 - description: |- - fsType is Filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - kind: - description: 'kind expected values are Shared: multiple - blob disks per storage account Dedicated: single blob - disk per storage account Managed: azure managed data - disk (only in managed availability set). defaults to - shared' - type: string - readOnly: - default: false - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - required: - - diskName - - diskURI - type: object - azureFile: - description: azureFile represents an Azure File Service mount - on the host and bind mount to the pod. - properties: - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretName: - description: secretName is the name of secret that contains - Azure Storage Account Name and Key - type: string - shareName: - description: shareName is the azure share Name - type: string - required: - - secretName - - shareName - type: object - cephfs: - description: cephFS represents a Ceph FS mount on the host - that shares a pod's lifetime - properties: - monitors: - description: |- - monitors is Required: Monitors is a collection of Ceph monitors - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - path: - description: 'path is Optional: Used as the mounted root, - rather than the full Ceph tree, default is /' - type: string - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: boolean - secretFile: - description: |- - secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - secretRef: - description: |- - secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - description: |- - user is optional: User is the rados user name, default is admin - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - required: - - monitors - type: object - cinder: - description: |- - cinder represents a cinder volume attached and mounted on kubelets host machine. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: boolean - secretRef: - description: |- - secretRef is optional: points to a secret object containing parameters used to connect - to OpenStack. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeID: - description: |- - volumeID used to identify the volume in cinder. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - required: - - volumeID - type: object - configMap: - description: configMap represents a configMap that should - populate this volume - properties: - defaultMode: - description: |- - defaultMode is optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether the ConfigMap or - its keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - csi: - description: csi (Container Storage Interface) represents - ephemeral storage that is handled by certain external CSI - drivers (Beta feature). - properties: - driver: - description: |- - driver is the name of the CSI driver that handles this volume. - Consult with your admin for the correct name as registered in the cluster. - type: string - fsType: - description: |- - fsType to mount. Ex. "ext4", "xfs", "ntfs". - If not provided, the empty value is passed to the associated CSI driver - which will determine the default filesystem to apply. - type: string - nodePublishSecretRef: - description: |- - nodePublishSecretRef is a reference to the secret object containing - sensitive information to pass to the CSI driver to complete the CSI - NodePublishVolume and NodeUnpublishVolume calls. - This field is optional, and may be empty if no secret is required. If the - secret object contains more than one secret, all secret references are passed. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - readOnly: - description: |- - readOnly specifies a read-only configuration for the volume. - Defaults to false (read/write). - type: boolean - volumeAttributes: - additionalProperties: - type: string - description: |- - volumeAttributes stores driver-specific properties that are passed to the CSI - driver. Consult your driver's documentation for supported values. - type: object - required: - - driver - type: object - downwardAPI: - description: downwardAPI represents downward API about the - pod that should populate this volume - properties: - defaultMode: - description: |- - Optional: mode bits to use on created files by default. Must be a - Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: Items is a list of downward API volume file - items: - description: DownwardAPIVolumeFile represents information - to create the file containing the pod field - properties: - fieldRef: - description: 'Required: Selects a field of the pod: - only annotations, labels, name, namespace and - uid are supported.' - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in - the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path is the relative path - name of the file to be created. Must not be absolute - or contain the ''..'' path. Must be utf-8 encoded. - The first item of the relative path must not start - with ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of - the exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - emptyDir: - description: |- - emptyDir represents a temporary directory that shares a pod's lifetime. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - properties: - medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - ephemeral: - description: |- - ephemeral represents a volume that is handled by a cluster storage driver. - The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, - and deleted when the pod is removed. - - Use this if: - a) the volume is only needed while the pod runs, - b) features of normal volumes like restoring from snapshot or capacity - tracking are needed, - c) the storage driver is specified through a storage class, and - d) the storage driver supports dynamic volume provisioning through - a PersistentVolumeClaim (see EphemeralVolumeSource for more - information on the connection between this volume type - and PersistentVolumeClaim). - - Use PersistentVolumeClaim or one of the vendor-specific - APIs for volumes that persist for longer than the lifecycle - of an individual pod. - - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to - be used that way - see the documentation of the driver for - more information. - - A pod can use both types of ephemeral volumes and - persistent volumes at the same time. - properties: - volumeClaimTemplate: - description: |- - Will be used to create a stand-alone PVC to provision the volume. - The pod in which this EphemeralVolumeSource is embedded will be the - owner of the PVC, i.e. the PVC will be deleted together with the - pod. The name of the PVC will be `-` where - `` is the name from the `PodSpec.Volumes` array - entry. Pod validation will reject the pod if the concatenated name - is not valid for a PVC (for example, too long). - - An existing PVC with that name that is not owned by the pod - will *not* be used for the pod to avoid using an unrelated - volume by mistake. Starting the pod is then blocked until - the unrelated PVC is removed. If such a pre-created PVC is - meant to be used by the pod, the PVC has to updated with an - owner reference to the pod once the pod exists. Normally - this should not be necessary, but it may be useful when - manually reconstructing a broken cluster. - - This field is read-only and no changes will be made by Kubernetes - to the PVC after it has been created. - - Required, must not be nil. - properties: - metadata: - description: |- - May contain labels and annotations that will be copied into the PVC - when creating it. No other fields are allowed and will be rejected during - validation. - type: object - spec: - description: |- - The specification for the PersistentVolumeClaim. The entire content is - copied unchanged into the PVC that gets created from this - template. The same fields as in a PersistentVolumeClaim - are also valid here. - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource - being referenced - type: string - name: - description: Name is the name of resource - being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource - being referenced - type: string - name: - description: Name is the name of resource - being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes - to consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference - to the PersistentVolume backing this claim. - type: string - type: object - required: - - spec - type: object - type: object - fc: - description: fc represents a Fibre Channel resource that is - attached to a kubelet's host machine and then exposed to - the pod. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - lun: - description: 'lun is Optional: FC target lun number' - format: int32 - type: integer - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - targetWWNs: - description: 'targetWWNs is Optional: FC target worldwide - names (WWNs)' - items: - type: string - type: array - x-kubernetes-list-type: atomic - wwids: - description: |- - wwids Optional: FC volume world wide identifiers (wwids) - Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - flexVolume: - description: |- - flexVolume represents a generic volume resource that is - provisioned/attached using an exec based plugin. - properties: - driver: - description: driver is the name of the driver to use for - this volume. - type: string - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. - type: string - options: - additionalProperties: - type: string - description: 'options is Optional: this field holds extra - command options if any.' - type: object - readOnly: - description: |- - readOnly is Optional: defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef is Optional: secretRef is reference to the secret object containing - sensitive information to pass to the plugin scripts. This may be - empty if no secret object is specified. If the secret object - contains more than one secret, all secrets are passed to the plugin - scripts. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - required: - - driver - type: object - flocker: - description: flocker represents a Flocker volume attached - to a kubelet's host machine. This depends on the Flocker - control service being running - properties: - datasetName: - description: |- - datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker - should be considered as deprecated - type: string - datasetUUID: - description: datasetUUID is the UUID of the dataset. This - is unique identifier of a Flocker dataset - type: string - type: object - gcePersistentDisk: - description: |- - gcePersistentDisk represents a GCE Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - properties: - fsType: - description: |- - fsType is filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - format: int32 - type: integer - pdName: - description: |- - pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: boolean - required: - - pdName - type: object - gitRepo: - description: |- - gitRepo represents a git repository at a particular revision. - DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an - EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir - into the Pod's container. - properties: - directory: - description: |- - directory is the target directory name. - Must not contain or start with '..'. If '.' is supplied, the volume directory will be the - git repository. Otherwise, if specified, the volume will contain the git repository in - the subdirectory with the given name. - type: string - repository: - description: repository is the URL - type: string - revision: - description: revision is the commit hash for the specified - revision. - type: string - required: - - repository - type: object - glusterfs: - description: |- - glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/glusterfs/README.md - properties: - endpoints: - description: |- - endpoints is the endpoint name that details Glusterfs topology. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - path: - description: |- - path is the Glusterfs volume path. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - readOnly: - description: |- - readOnly here will force the Glusterfs volume to be mounted with read-only permissions. - Defaults to false. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: boolean - required: - - endpoints - - path - type: object - hostPath: - description: |- - hostPath represents a pre-existing file or directory on the host - machine that is directly exposed to the container. This is generally - used for system agents or other privileged things that are allowed - to see the host machine. Most containers will NOT need this. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - properties: - path: - description: |- - path of the directory on the host. - If the path is a symlink, it will follow the link to the real path. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - type: - description: |- - type for HostPath Volume - Defaults to "" - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - required: - - path - type: object - image: - description: |- - image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. - The volume is resolved at pod startup depending on which PullPolicy value is provided: - - - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - - The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. - A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. - 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). - The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. - properties: - pullPolicy: - description: |- - Policy for pulling OCI objects. Possible values are: - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. - type: string - reference: - description: |- - Required: Image or artifact reference to be used. - Behaves in the same way as pod.spec.containers[*].image. - Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. - More info: https://kubernetes.io/docs/concepts/containers/images - This field is optional to allow higher level config management to default or override - container images in workload controllers like Deployments and StatefulSets. - type: string - type: object - iscsi: - description: |- - iscsi represents an ISCSI Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://examples.k8s.io/volumes/iscsi/README.md - properties: - chapAuthDiscovery: - description: chapAuthDiscovery defines whether support - iSCSI Discovery CHAP authentication - type: boolean - chapAuthSession: - description: chapAuthSession defines whether support iSCSI - Session CHAP authentication - type: boolean - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - type: string - initiatorName: - description: |- - initiatorName is the custom iSCSI Initiator Name. - If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface - : will be created for the connection. - type: string - iqn: - description: iqn is the target iSCSI Qualified Name. - type: string - iscsiInterface: - default: default - description: |- - iscsiInterface is the interface Name that uses an iSCSI transport. - Defaults to 'default' (tcp). - type: string - lun: - description: lun represents iSCSI Target Lun number. - format: int32 - type: integer - portals: - description: |- - portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - items: - type: string - type: array - x-kubernetes-list-type: atomic - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - type: boolean - secretRef: - description: secretRef is the CHAP Secret for iSCSI target - and initiator authentication - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - targetPortal: - description: |- - targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - type: string - required: - - iqn - - lun - - targetPortal - type: object - nfs: - description: |- - nfs represents an NFS mount on the host that shares a pod's lifetime - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - properties: - path: - description: |- - path that is exported by the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - readOnly: - description: |- - readOnly here will force the NFS export to be mounted with read-only permissions. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: boolean - server: - description: |- - server is the hostname or IP address of the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - required: - - path - - server - type: object - persistentVolumeClaim: - description: |- - persistentVolumeClaimVolumeSource represents a reference to a - PersistentVolumeClaim in the same namespace. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - claimName: - description: |- - claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - type: string - readOnly: - description: |- - readOnly Will force the ReadOnly setting in VolumeMounts. - Default false. - type: boolean - required: - - claimName - type: object - photonPersistentDisk: - description: photonPersistentDisk represents a PhotonController - persistent disk attached and mounted on kubelets host machine - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - pdID: - description: pdID is the ID that identifies Photon Controller - persistent disk - type: string - required: - - pdID - type: object - portworxVolume: - description: portworxVolume represents a portworx volume attached - and mounted on kubelets host machine - properties: - fsType: - description: |- - fSType represents the filesystem type to mount - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - volumeID: - description: volumeID uniquely identifies a Portworx volume - type: string - required: - - volumeID - type: object - projected: - description: projected items for all in one resources secrets, - configmaps, and downward API - properties: - defaultMode: - description: |- - defaultMode are the mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - sources: - description: |- - sources is the list of volume projections. Each entry in this list - handles one source. - items: - description: |- - Projection that may be projected along with other supported volume types. - Exactly one of these fields must be set. - properties: - clusterTrustBundle: - description: |- - ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field - of ClusterTrustBundle objects in an auto-updating file. - - Alpha, gated by the ClusterTrustBundleProjection feature gate. - - ClusterTrustBundle objects can either be selected by name, or by the - combination of signer name and a label selector. - - Kubelet performs aggressive normalization of the PEM contents written - into the pod filesystem. Esoteric PEM features such as inter-block - comments and block headers are stripped. Certificates are deduplicated. - The ordering of certificates within the file is arbitrary, and Kubelet - may change the order over time. - properties: - labelSelector: - description: |- - Select all ClusterTrustBundles that match this label selector. Only has - effect if signerName is set. Mutually-exclusive with name. If unset, - interpreted as "match nothing". If set but empty, interpreted as "match - everything". - 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 - name: - description: |- - Select a single ClusterTrustBundle by object name. Mutually-exclusive - with signerName and labelSelector. - type: string - optional: - description: |- - If true, don't block pod startup if the referenced ClusterTrustBundle(s) - aren't available. If using name, then the named ClusterTrustBundle is - allowed not to exist. If using signerName, then the combination of - signerName and labelSelector is allowed to match zero - ClusterTrustBundles. - type: boolean - path: - description: Relative path from the volume root - to write the bundle. - type: string - signerName: - description: |- - Select all ClusterTrustBundles that match this signer name. - Mutually-exclusive with name. The contents of all selected - ClusterTrustBundles will be unified and deduplicated. - type: string - required: - - path - type: object - configMap: - description: configMap information about the configMap - data to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether the ConfigMap - or its keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - downwardAPI: - description: downwardAPI information about the downwardAPI - data to project - properties: - items: - description: Items is a list of DownwardAPIVolume - file - items: - description: DownwardAPIVolumeFile represents - information to create the file containing - the pod field - properties: - fieldRef: - description: 'Required: Selects a field - of the pod: only annotations, labels, - name, namespace and uid are supported.' - properties: - apiVersion: - description: Version of the schema - the FieldPath is written in terms - of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to - select in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path is the relative - path name of the file to be created. - Must not be absolute or contain the - ''..'' path. Must be utf-8 encoded. - The first item of the relative path - must not start with ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output - format of the exposed resources, - defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to - select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - secret: - description: secret information about the secret - data to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional field specify whether - the Secret or its key must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - serviceAccountToken: - description: serviceAccountToken is information - about the serviceAccountToken data to project - properties: - audience: - description: |- - audience is the intended audience of the token. A recipient of a token - must identify itself with an identifier specified in the audience of the - token, and otherwise should reject the token. The audience defaults to the - identifier of the apiserver. - type: string - expirationSeconds: - description: |- - expirationSeconds is the requested duration of validity of the service - account token. As the token approaches expiration, the kubelet volume - plugin will proactively rotate the service account token. The kubelet will - start trying to rotate the token if the token is older than 80 percent of - its time to live or if the token is older than 24 hours.Defaults to 1 hour - and must be at least 10 minutes. - format: int64 - type: integer - path: - description: |- - path is the path relative to the mount point of the file to project the - token into. - type: string - required: - - path - type: object - type: object - type: array - x-kubernetes-list-type: atomic - type: object - quobyte: - description: quobyte represents a Quobyte mount on the host - that shares a pod's lifetime - properties: - group: - description: |- - group to map volume access to - Default is no group - type: string - readOnly: - description: |- - readOnly here will force the Quobyte volume to be mounted with read-only permissions. - Defaults to false. - type: boolean - registry: - description: |- - registry represents a single or multiple Quobyte Registry services - specified as a string as host:port pair (multiple entries are separated with commas) - which acts as the central registry for volumes - type: string - tenant: - description: |- - tenant owning the given Quobyte volume in the Backend - Used with dynamically provisioned Quobyte volumes, value is set by the plugin - type: string - user: - description: |- - user to map volume access to - Defaults to serivceaccount user - type: string - volume: - description: volume is a string that references an already - created Quobyte volume by name. - type: string - required: - - registry - - volume - type: object - rbd: - description: |- - rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/rbd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - type: string - image: - description: |- - image is the rados image name. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - keyring: - default: /etc/ceph/keyring - description: |- - keyring is the path to key ring for RBDUser. - Default is /etc/ceph/keyring. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - monitors: - description: |- - monitors is a collection of Ceph monitors. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - pool: - default: rbd - description: |- - pool is the rados pool name. - Default is rbd. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: boolean - secretRef: - description: |- - secretRef is name of the authentication secret for RBDUser. If provided - overrides keyring. - Default is nil. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - default: admin - description: |- - user is the rados user name. - Default is admin. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - required: - - image - - monitors - type: object - scaleIO: - description: scaleIO represents a ScaleIO persistent volume - attached and mounted on Kubernetes nodes. - properties: - fsType: - default: xfs - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". - Default is "xfs". - type: string - gateway: - description: gateway is the host address of the ScaleIO - API Gateway. - type: string - protectionDomain: - description: protectionDomain is the name of the ScaleIO - Protection Domain for the configured storage. - type: string - readOnly: - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef references to the secret for ScaleIO user and other - sensitive information. If this is not provided, Login operation will fail. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - sslEnabled: - description: sslEnabled Flag enable/disable SSL communication - with Gateway, default false - type: boolean - storageMode: - default: ThinProvisioned - description: |- - storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. - Default is ThinProvisioned. - type: string - storagePool: - description: storagePool is the ScaleIO Storage Pool associated - with the protection domain. - type: string - system: - description: system is the name of the storage system - as configured in ScaleIO. - type: string - volumeName: - description: |- - volumeName is the name of a volume already created in the ScaleIO system - that is associated with this volume source. - type: string - required: - - gateway - - secretRef - - system - type: object - secret: - description: |- - secret represents a secret that should populate this volume. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - properties: - defaultMode: - description: |- - defaultMode is Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values - for mode bits. Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items If unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - optional: - description: optional field specify whether the Secret - or its keys must be defined - type: boolean - secretName: - description: |- - secretName is the name of the secret in the pod's namespace to use. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - type: string - type: object - storageos: - description: storageOS represents a StorageOS volume attached - and mounted on Kubernetes nodes. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef specifies the secret to use for obtaining the StorageOS API - credentials. If not specified, default values will be attempted. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeName: - description: |- - volumeName is the human-readable name of the StorageOS volume. Volume - names are only unique within a namespace. - type: string - volumeNamespace: - description: |- - volumeNamespace specifies the scope of the volume within StorageOS. If no - namespace is specified then the Pod's namespace will be used. This allows the - Kubernetes name scoping to be mirrored within StorageOS for tighter integration. - Set VolumeName to any name to override the default behaviour. - Set to "default" if you are not using namespaces within StorageOS. - Namespaces that do not pre-exist within StorageOS will be created. - type: string - type: object - vsphereVolume: - description: vsphereVolume represents a vSphere volume attached - and mounted on kubelets host machine - properties: - fsType: - description: |- - fsType is filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - storagePolicyID: - description: storagePolicyID is the storage Policy Based - Management (SPBM) profile ID associated with the StoragePolicyName. - type: string - storagePolicyName: - description: storagePolicyName is the storage Policy Based - Management (SPBM) profile name. - type: string - volumePath: - description: volumePath is the path that identifies vSphere - volume vmdk - type: string - required: - - volumePath - type: object - type: object - type: object - command: - description: Command to be used in the Container. - items: - type: string - type: array - connection: - description: |- - Connection defines a template to configure the general Connection object. - This Connection provides the initial User access to the initial Database. - It will make use of the Service to route network traffic to all Pods. - properties: - healthCheck: - description: HealthCheck to be used in the Connection. - properties: - interval: - description: Interval used to perform health checks. - type: string - retryInterval: - description: RetryInterval is the interval used to perform - health check retries. - type: string - type: object - params: - additionalProperties: - type: string - description: Params to be used in the Connection. - type: object - port: - description: Port to connect to. If not provided, it defaults - to the MariaDB port or to the first MaxScale listener. - format: int32 - type: integer - secretName: - description: SecretName to be used in the Connection. - type: string - secretTemplate: - description: SecretTemplate to be used in the Connection. - properties: - databaseKey: - description: DatabaseKey to be used in the Secret. - type: string - format: - description: Format to be used in the Secret. - type: string - hostKey: - description: HostKey to be used in the Secret. - type: string - key: - description: Key to be used in the Secret. - type: string - metadata: - description: Metadata to be added to the Secret object. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - passwordKey: - description: PasswordKey to be used in the Secret. - type: string - portKey: - description: PortKey to be used in the Secret. - type: string - usernameKey: - description: UsernameKey to be used in the Secret. - type: string - type: object - serviceName: - description: ServiceName to be used in the Connection. - type: string - type: object - database: - description: Database is the name of the initial Database. - type: string - env: - description: Env represents the environment variables to be injected - in a container. - items: - description: EnvVar represents an environment variable present in - a Container. - properties: - name: - description: Name of the environment variable. Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. Cannot - be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath is - written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the specified - API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the exposed - resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's namespace - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via ConfigMap and - Secrets) to environment variables to be injected in the container. - items: - description: EnvFromSource represents the source of a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - galera: - description: Replication configures high availability via Galera. - properties: - agent: - description: GaleraAgent is a sidecar agent that co-operates with - mariadb-operator. - properties: - args: - description: Args to be used in the Container. - items: - type: string - type: array - command: - description: Command to be used in the Container. - items: - type: string - type: array - env: - description: Env represents the environment variables to be - injected in a container. - items: - description: EnvVar represents an environment variable present - in a Container. - properties: - name: - description: Name of the environment variable. Must - be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. - Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in - the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of - the exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's - namespace - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via ConfigMap - and Secrets) to environment variables to be injected in - the container. - items: - description: EnvFromSource represents the source of a set - of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must - be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be - defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - gracefulShutdownTimeout: - description: GracefulShutdownTimeout is the time we give to - the agent container in order to gracefully terminate in-flight - requests. - type: string - image: - description: Image name to be used by the MariaDB instances. - The supported format is `:`. - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. One - of `Always`, `Never` or `IfNotPresent`. If not defined, - it defaults to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - kubernetesAuth: - description: KubernetesAuth to be used by the agent container - properties: - authDelegatorRoleName: - description: |- - AuthDelegatorRoleName is the name of the ClusterRoleBinding that is associated with the "system:auth-delegator" ClusterRole. - It is necessary for creating TokenReview objects in order for the agent to validate the service account token. - type: string - enabled: - description: Enabled is a flag to enable KubernetesAuth - type: boolean - type: object - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC - port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a - TCP port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - port: - description: Port where the agent will be listening for connections. - format: int32 - type: integer - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC - port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a - TCP port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration - that will be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies - to the container. - type: string - role: - description: Role is a SELinux role label that applies - to the container. - type: string - type: - description: Type is a SELinux type label that applies - to the container. - type: string - user: - description: User is a SELinux user label that applies - to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of - the GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting of a Volume - within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - type: object - availableWhenDonor: - description: AvailableWhenDonor indicates whether a donor node - should be responding to queries. It defaults to false. - type: boolean - config: - description: GaleraConfig defines storage options for the Galera - configuration files. - properties: - reuseStorageVolume: - description: |- - ReuseStorageVolume indicates that storage volume used by MariaDB should be reused to store the Galera configuration files. - It defaults to false, which implies that a dedicated volume for the Galera configuration files is provisioned. - type: boolean - volumeClaimTemplate: - description: VolumeClaimTemplate is a template for the PVC - that will contain the Galera configuration files shared - between the InitContainer, Agent and MariaDB. - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - metadata: - description: Metadata to be added to the PVC metadata. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes to - consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to the - PersistentVolume backing this claim. - type: string - type: object - type: object - enabled: - description: Enabled is a flag to enable Galera. - type: boolean - galeraLibPath: - description: |- - GaleraLibPath is a path inside the MariaDB image to the wsrep provider plugin. It is defaulted if not provided. - More info: https://galeracluster.com/library/documentation/mysql-wsrep-options.html#wsrep-provider. - type: string - initContainer: - description: InitContainer is an init container that runs in the - MariaDB Pod and co-operates with mariadb-operator. - properties: - args: - description: Args to be used in the Container. - items: - type: string - type: array - command: - description: Command to be used in the Container. - items: - type: string - type: array - env: - description: Env represents the environment variables to be - injected in a container. - items: - description: EnvVar represents an environment variable present - in a Container. - properties: - name: - description: Name of the environment variable. Must - be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. - Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in - the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of - the exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's - namespace - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via ConfigMap - and Secrets) to environment variables to be injected in - the container. - items: - description: EnvFromSource represents the source of a set - of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must - be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be - defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: Image name to be used by the MariaDB instances. - The supported format is `:`. - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. One - of `Always`, `Never` or `IfNotPresent`. If not defined, - it defaults to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC - port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a - TCP port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC - port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a - TCP port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration - that will be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies - to the container. - type: string - role: - description: Role is a SELinux role label that applies - to the container. - type: string - type: - description: Type is a SELinux type label that applies - to the container. - type: string - user: - description: User is a SELinux user label that applies - to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of - the GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting of a Volume - within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - required: - - image - type: object - initJob: - description: InitJob defines a Job that co-operates with mariadb-operator - by performing initialization tasks. - properties: - affinity: - description: Affinity to be used in the Pod. - properties: - antiAffinityEnabled: - description: |- - AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. - Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. - type: boolean - nodeAffinity: - description: Describes node affinity scheduling rules - for the pod. - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - properties: - preference: - description: A node selector term, associated - with the corresponding weight. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching - the corresponding nodeSelectorTerm, in the - range 1-100. - format: int32 - type: integer - required: - - preference - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - properties: - nodeSelectorTerms: - description: Required. A list of node selector - terms. The terms are ORed. - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - type: array - x-kubernetes-list-type: atomic - required: - - nodeSelectorTerms - type: object - x-kubernetes-map-type: atomic - type: object - podAffinity: - description: Describes pod affinity scheduling rules (e.g. - co-locate this pod in the same node, zone, etc. as some - other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred - node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, - associated with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules - (e.g. avoid putting this pod in the same node, zone, - etc. as some other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred - node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, - associated with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - type: object - args: - description: Args to be used in the Container. - items: - type: string - type: array - metadata: - description: Metadata defines additional metadata for the - bootstrap Jobs. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - type: object - primary: - description: Primary is the Galera configuration for the primary - node. - properties: - automaticFailover: - description: AutomaticFailover indicates whether the operator - should automatically update PodIndex to perform an automatic - primary failover. - type: boolean - podIndex: - description: PodIndex is the StatefulSet index of the primary - node. The user may change this field to perform a manual - switchover. - type: integer - type: object - providerOptions: - additionalProperties: - type: string - description: |- - ProviderOptions is map of Galera configuration parameters. - More info: https://mariadb.com/kb/en/galera-cluster-system-variables/#wsrep_provider_options. - type: object - recovery: - description: |- - GaleraRecovery is the recovery process performed by the operator whenever the Galera cluster is not healthy. - More info: https://galeracluster.com/library/documentation/crash-recovery.html. - properties: - clusterBootstrapTimeout: - description: |- - ClusterBootstrapTimeout is the time limit for bootstrapping a cluster. - Once this timeout is reached, the Galera recovery state is reset and a new cluster bootstrap will be attempted. - type: string - clusterHealthyTimeout: - description: |- - ClusterHealthyTimeout represents the duration at which a Galera cluster, that consistently failed health checks, - is considered unhealthy, and consequently the Galera recovery process will be initiated by the operator. - type: string - clusterMonitorInterval: - description: ClusterMonitorInterval represents the interval - used to monitor the Galera cluster health. - type: string - enabled: - description: Enabled is a flag to enable GaleraRecovery. - type: boolean - forceClusterBootstrapInPod: - description: |- - ForceClusterBootstrapInPod allows you to manually initiate the bootstrap process in a specific Pod. - IMPORTANT: Use this option only in exceptional circumstances. Not selecting the Pod with the highest sequence number may result in data loss. - IMPORTANT: Ensure you unset this field after completing the bootstrap to allow the operator to choose the appropriate Pod to bootstrap from in an event of cluster recovery. - type: string - job: - description: Job defines a Job that co-operates with mariadb-operator - by performing the Galera cluster recovery . - properties: - metadata: - description: Metadata defines additional metadata for - the Galera recovery Jobs. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry - in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - type: object - minClusterSize: - anyOf: - - type: integer - - type: string - description: |- - MinClusterSize is the minimum number of replicas to consider the cluster healthy. It can be either a number of replicas (1) or a percentage (50%). - If Galera consistently reports less replicas than this value for the given 'ClusterHealthyTimeout' interval, a cluster recovery is iniated. - It defaults to '1' replica. - x-kubernetes-int-or-string: true - podRecoveryTimeout: - description: PodRecoveryTimeout is the time limit for recevorying - the sequence of a Pod during the cluster recovery. - type: string - podSyncTimeout: - description: PodSyncTimeout is the time limit for a Pod to - join the cluster after having performed a cluster bootstrap - during the cluster recovery. - type: string - type: object - replicaThreads: - description: |- - ReplicaThreads is the number of replica threads used to apply Galera write sets in parallel. - More info: https://mariadb.com/kb/en/galera-cluster-system-variables/#wsrep_slave_threads. - type: integer - sst: - description: |- - SST is the Snapshot State Transfer used when new Pods join the cluster. - More info: https://galeracluster.com/library/documentation/sst.html. - enum: - - rsync - - mariabackup - - mysqldump - type: string - type: object - image: - description: |- - Image name to be used by the MariaDB instances. The supported format is `:`. - Only MariaDB official images are supported. - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. One of `Always`, - `Never` or `IfNotPresent`. If not defined, it defaults to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - imagePullSecrets: - description: ImagePullSecrets is the list of pull Secrets to be used - to pull the image. - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - inheritMetadata: - description: InheritMetadata defines the metadata to be inherited - by children resources. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - initContainers: - description: InitContainers to be used in the Pod. - items: - description: Container object definition. - properties: - args: - description: Args to be used in the Container. - items: - type: string - type: array - command: - description: Command to be used in the Container. - items: - type: string - type: array - env: - description: Env represents the environment variables to be - injected in a container. - items: - description: EnvVar represents an environment variable present - in a Container. - properties: - name: - description: Name of the environment variable. Must be - a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. - Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the - specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the - exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's - namespace - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via ConfigMap - and Secrets) to environment variables to be injected in the - container. - items: - description: EnvFromSource represents the source of a set - of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be - defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: Image name to be used by the MariaDB instances. - The supported format is `:`. - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. One of - `Always`, `Never` or `IfNotPresent`. If not defined, it defaults - to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. HTTP - allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a TCP - port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. HTTP - allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a TCP - port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration that - will be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies - to the container. - type: string - role: - description: Role is a SELinux role label that applies - to the container. - type: string - type: - description: Type is a SELinux type label that applies - to the container. - type: string - user: - description: User is a SELinux user label that applies - to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of the - GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting of a Volume - within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - required: - - image - type: object - type: array - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC port. - properties: - port: - description: Port number of the gRPC service. Number must - be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. HTTP allows - repeated headers. - items: - description: HTTPHeader describes a custom header to be - used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a TCP port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - maxScale: - description: |- - MaxScale is the MaxScale specification that defines the MaxScale resource to be used with the current MariaDB. - When enabling this field, MaxScaleRef is automatically set. - properties: - admin: - description: Admin configures the admin REST API and GUI. - properties: - guiEnabled: - description: GuiEnabled indicates whether the admin GUI should - be enabled. - type: boolean - port: - description: Port where the admin REST API and GUI will be - exposed. - format: int32 - type: integer - type: object - auth: - description: Auth defines the credentials required for MaxScale - to connect to MariaDB. - properties: - adminPasswordSecretKeyRef: - description: AdminPasswordSecretKeyRef is Secret key reference - to the admin password to call the admin REST API. It is - defaulted if not provided. - properties: - generate: - default: false - description: Generate indicates whether the Secret should - be generated if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - adminUsername: - description: AdminUsername is an admin username to call the - admin REST API. It is defaulted if not provided. - type: string - clientMaxConnections: - description: |- - ClientMaxConnections defines the maximum number of connections that the client can establish. - If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. - It defaults to 30 times the number of MaxScale replicas. - format: int32 - type: integer - clientPasswordSecretKeyRef: - description: |- - ClientPasswordSecretKeyRef is Secret key reference to the password to connect to MaxScale. It is defaulted if not provided. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. - properties: - generate: - default: false - description: Generate indicates whether the Secret should - be generated if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - clientUsername: - description: ClientUsername is the user to connect to MaxScale. - It is defaulted if not provided. - type: string - deleteDefaultAdmin: - description: DeleteDefaultAdmin determines whether the default - admin user should be deleted after the initial configuration. - If not provided, it defaults to true. - type: boolean - generate: - description: |- - Generate defies whether the operator should generate users and grants for MaxScale to work. - It only supports MariaDBs specified via spec.mariaDbRef. - type: boolean - metricsPasswordSecretKeyRef: - description: |- - MetricsPasswordSecretKeyRef is Secret key reference to the metrics password to call the admib REST API. It is defaulted if metrics are enabled. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. - properties: - generate: - default: false - description: Generate indicates whether the Secret should - be generated if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - metricsUsername: - description: MetricsUsername is an metrics username to call - the REST API. It is defaulted if metrics are enabled. - type: string - monitorMaxConnections: - description: |- - MonitorMaxConnections defines the maximum number of connections that the monitor can establish. - If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. - It defaults to 30 times the number of MaxScale replicas. - format: int32 - type: integer - monitorPasswordSecretKeyRef: - description: |- - MonitorPasswordSecretKeyRef is Secret key reference to the password used by MaxScale monitor to connect to MariaDB server. It is defaulted if not provided. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. - properties: - generate: - default: false - description: Generate indicates whether the Secret should - be generated if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - monitorUsername: - description: MonitorUsername is the user used by MaxScale - monitor to connect to MariaDB server. It is defaulted if - not provided. - type: string - serverMaxConnections: - description: |- - ServerMaxConnections defines the maximum number of connections that the server can establish. - If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. - It defaults to 30 times the number of MaxScale replicas. - format: int32 - type: integer - serverPasswordSecretKeyRef: - description: |- - ServerPasswordSecretKeyRef is Secret key reference to the password used by MaxScale to connect to MariaDB server. It is defaulted if not provided. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. - properties: - generate: - default: false - description: Generate indicates whether the Secret should - be generated if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverUsername: - description: ServerUsername is the user used by MaxScale to - connect to MariaDB server. It is defaulted if not provided. - type: string - syncMaxConnections: - description: |- - SyncMaxConnections defines the maximum number of connections that the sync can establish. - If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. - It defaults to 30 times the number of MaxScale replicas. - format: int32 - type: integer - syncPasswordSecretKeyRef: - description: |- - SyncPasswordSecretKeyRef is Secret key reference to the password used by MaxScale config to connect to MariaDB server. It is defaulted when HA is enabled. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. - properties: - generate: - default: false - description: Generate indicates whether the Secret should - be generated if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - syncUsername: - description: MonitoSyncUsernamerUsername is the user used - by MaxScale config sync to connect to MariaDB server. It - is defaulted when HA is enabled. - type: string - type: object - config: - description: Config defines the MaxScale configuration. - properties: - params: - additionalProperties: - type: string - description: |- - Params is a key value pair of parameters to be used in the MaxScale static configuration file. - Any parameter supported by MaxScale may be specified here. See reference: - https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#global-settings. - type: object - sync: - description: Sync defines how to replicate configuration across - MaxScale replicas. It is defaulted when HA is enabled. - properties: - database: - description: Database is the MariaDB logical database - where the 'maxscale_config' table will be created in - order to persist and synchronize config changes. If - not provided, it defaults to 'mysql'. - type: string - interval: - description: Interval defines the config synchronization - interval. It is defaulted if not provided. - type: string - timeout: - description: Interval defines the config synchronization - timeout. It is defaulted if not provided. - type: string - type: object - volumeClaimTemplate: - description: VolumeClaimTemplate provides a template to define - the PVCs for storing MaxScale runtime configuration files. - It is defaulted if not provided. - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - metadata: - description: Metadata to be added to the PVC metadata. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes to - consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to the - PersistentVolume backing this claim. - type: string - type: object - type: object - connection: - description: Connection provides a template to define the Connection - for MaxScale. - properties: - healthCheck: - description: HealthCheck to be used in the Connection. - properties: - interval: - description: Interval used to perform health checks. - type: string - retryInterval: - description: RetryInterval is the interval used to perform - health check retries. - type: string - type: object - params: - additionalProperties: - type: string - description: Params to be used in the Connection. - type: object - port: - description: Port to connect to. If not provided, it defaults - to the MariaDB port or to the first MaxScale listener. - format: int32 - type: integer - secretName: - description: SecretName to be used in the Connection. - type: string - secretTemplate: - description: SecretTemplate to be used in the Connection. - properties: - databaseKey: - description: DatabaseKey to be used in the Secret. - type: string - format: - description: Format to be used in the Secret. - type: string - hostKey: - description: HostKey to be used in the Secret. - type: string - key: - description: Key to be used in the Secret. - type: string - metadata: - description: Metadata to be added to the Secret object. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - passwordKey: - description: PasswordKey to be used in the Secret. - type: string - portKey: - description: PortKey to be used in the Secret. - type: string - usernameKey: - description: UsernameKey to be used in the Secret. - type: string - type: object - serviceName: - description: ServiceName to be used in the Connection. - type: string - type: object - enabled: - description: Enabled is a flag to enable a MaxScale instance to - be used with the current MariaDB. - type: boolean - guiKubernetesService: - description: GuiKubernetesService define a template for a Kubernetes - Service object to connect to MaxScale's GUI. - properties: - allocateLoadBalancerNodePorts: - description: AllocateLoadBalancerNodePorts Service field. - type: boolean - externalTrafficPolicy: - description: ExternalTrafficPolicy Service field. - type: string - loadBalancerIP: - description: LoadBalancerIP Service field. - type: string - loadBalancerSourceRanges: - description: LoadBalancerSourceRanges Service field. - items: - type: string - type: array - metadata: - description: Metadata to be added to the Service metadata. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - sessionAffinity: - description: SessionAffinity Service field. - type: string - type: - default: ClusterIP - description: Type is the Service type. One of `ClusterIP`, - `NodePort` or `LoadBalancer`. If not defined, it defaults - to `ClusterIP`. - enum: - - ClusterIP - - NodePort - - LoadBalancer - type: string - type: object - image: - description: |- - Image name to be used by the MaxScale instances. The supported format is `:`. - Only MariaDB official images are supported. - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. One of - `Always`, `Never` or `IfNotPresent`. If not defined, it defaults - to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - kubernetesService: - description: KubernetesService defines a template for a Kubernetes - Service object to connect to MaxScale. - properties: - allocateLoadBalancerNodePorts: - description: AllocateLoadBalancerNodePorts Service field. - type: boolean - externalTrafficPolicy: - description: ExternalTrafficPolicy Service field. - type: string - loadBalancerIP: - description: LoadBalancerIP Service field. - type: string - loadBalancerSourceRanges: - description: LoadBalancerSourceRanges Service field. - items: - type: string - type: array - metadata: - description: Metadata to be added to the Service metadata. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - sessionAffinity: - description: SessionAffinity Service field. - type: string - type: - default: ClusterIP - description: Type is the Service type. One of `ClusterIP`, - `NodePort` or `LoadBalancer`. If not defined, it defaults - to `ClusterIP`. - enum: - - ClusterIP - - NodePort - - LoadBalancer - type: string - type: object - metrics: - description: Metrics configures metrics and how to scrape them. - properties: - enabled: - description: Enabled is a flag to enable Metrics - type: boolean - exporter: - description: Exporter defines the metrics exporter container. - properties: - affinity: - description: Affinity to be used in the Pod. - properties: - antiAffinityEnabled: - description: |- - AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. - Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. - type: boolean - nodeAffinity: - description: Describes node affinity scheduling rules - for the pod. - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - properties: - preference: - description: A node selector term, associated - with the corresponding weight. - properties: - matchExpressions: - description: A list of node selector - requirements by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that - the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector - requirements by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that - the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching - the corresponding nodeSelectorTerm, in - the range 1-100. - format: int32 - type: integer - required: - - preference - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - properties: - nodeSelectorTerms: - description: Required. A list of node selector - terms. The terms are ORed. - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - properties: - matchExpressions: - description: A list of node selector - requirements by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that - the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector - requirements by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that - the selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - type: array - x-kubernetes-list-type: atomic - required: - - nodeSelectorTerms - type: object - x-kubernetes-map-type: atomic - type: object - podAffinity: - description: Describes pod affinity scheduling rules - (e.g. co-locate this pod in the same node, zone, - etc. as some other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched - WeightedPodAffinityTerm fields are added per-node - to find the most preferred node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, - associated with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - podAntiAffinity: - description: Describes pod anti-affinity scheduling - rules (e.g. avoid putting this pod in the same node, - zone, etc. as some other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched - WeightedPodAffinityTerm fields are added per-node - to find the most preferred node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, - associated with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - type: object - args: - description: Args to be used in the Container. - items: - type: string - type: array - command: - description: Command to be used in the Container. - items: - type: string - type: array - env: - description: Env represents the environment variables - to be injected in a container. - items: - description: EnvVar represents an environment variable - present in a Container. - properties: - name: - description: Name of the environment variable. Must - be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for - volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the - pod's namespace - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via ConfigMap - and Secrets) to environment variables to be injected - in the container. - items: - description: EnvFromSource represents the source of - a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must - be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must - be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: |- - Image name to be used as metrics exporter. The supported format is `:`. - Only mysqld-exporter >= v0.15.0 is supported: https://github.com/prometheus/mysqld_exporter - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. - One of `Always`, `Never` or `IfNotPresent`. If not defined, - it defaults to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - imagePullSecrets: - description: ImagePullSecrets is the list of pull Secrets - to be used to pull the image. - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - initContainers: - description: InitContainers to be used in the Pod. - items: - description: Container object definition. - properties: - args: - description: Args to be used in the Container. - items: - type: string - type: array - command: - description: Command to be used in the Container. - items: - type: string - type: array - env: - description: Env represents the environment variables - to be injected in a container. - items: - description: EnvVar represents an environment - variable present in a Container. - properties: - name: - description: Name of the environment variable. - Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema - the FieldPath is written in terms - of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to - select in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output - format of the exposed resources, - defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to - select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret - in the pod's namespace - properties: - key: - description: The key of the secret - to select from. Must be a valid - secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via - ConfigMap and Secrets) to environment variables - to be injected in the container. - items: - description: EnvFromSource represents the source - of a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: Image name to be used by the MariaDB - instances. The supported format is `:`. - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. - One of `Always`, `Never` or `IfNotPresent`. If - not defined, it defaults to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the - request. HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP - server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the - request. HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP - server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - resources: - description: Resouces describes the compute resource - requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one - entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration - that will be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX - capabilities type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX - capabilities type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label - that applies to the container. - type: string - role: - description: Role is a SELinux role label - that applies to the container. - type: string - type: - description: Type is a SELinux type label - that applies to the container. - type: string - user: - description: User is a SELinux user label - that applies to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the - name of the GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting - of a Volume within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a - Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - required: - - image - type: object - type: array - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a - GRPC port. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to - perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect to, - defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - nodeSelector: - additionalProperties: - type: string - description: NodeSelector to be used in the Pod. - type: object - podMetadata: - description: PodMetadata defines extra metadata for the - Pod. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - podSecurityContext: - description: SecurityContext holds pod-level security - attributes and common container settings. - properties: - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that - applies to the container. - type: string - role: - description: Role is a SELinux role label that - applies to the container. - type: string - type: - description: Type is a SELinux type label that - applies to the container. - type: string - user: - description: User is a SELinux user label that - applies to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in - addition to the container's primary GID and fsGroup (if specified). If - the SupplementalGroupsPolicy feature is enabled, the - supplementalGroupsPolicy field determines whether these are in addition - to or instead of any group memberships defined in the container image. - If unspecified, no additional groups are added, though group memberships - defined in the container image may still be used, depending on the - supplementalGroupsPolicy field. - Note that this field cannot be set when spec.os.name is windows. - items: - format: int64 - type: integer - type: array - x-kubernetes-list-type: atomic - supplementalGroupsPolicy: - description: |- - Defines how supplemental groups of the first container processes are calculated. - Valid values are "Merge" and "Strict". If not specified, "Merge" is used. - (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled - and the container runtime must implement support for this feature. - Note that this field cannot be set when spec.os.name is windows. - type: string - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - items: - description: Sysctl defines a kernel parameter to - be set - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options within a container's SecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name - of the GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - port: - description: Port where the exporter will be listening - for connections. - format: int32 - type: integer - priorityClassName: - description: PriorityClassName to be used in the Pod. - type: string - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a - GRPC port. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to - perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect to, - defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry - in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration - that will be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that - applies to the container. - type: string - role: - description: Role is a SELinux role label that - applies to the container. - type: string - type: - description: Type is a SELinux type label that - applies to the container. - type: string - user: - description: User is a SELinux user label that - applies to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name - of the GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to be used by the Pods. - type: string - sidecarContainers: - description: SidecarContainers to be used in the Pod. - items: - description: Container object definition. - properties: - args: - description: Args to be used in the Container. - items: - type: string - type: array - command: - description: Command to be used in the Container. - items: - type: string - type: array - env: - description: Env represents the environment variables - to be injected in a container. - items: - description: EnvVar represents an environment - variable present in a Container. - properties: - name: - description: Name of the environment variable. - Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema - the FieldPath is written in terms - of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to - select in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output - format of the exposed resources, - defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to - select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret - in the pod's namespace - properties: - key: - description: The key of the secret - to select from. Must be a valid - secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via - ConfigMap and Secrets) to environment variables - to be injected in the container. - items: - description: EnvFromSource represents the source - of a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: Image name to be used by the MariaDB - instances. The supported format is `:`. - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. - One of `Always`, `Never` or `IfNotPresent`. If - not defined, it defaults to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the - request. HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP - server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the - request. HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP - server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - resources: - description: Resouces describes the compute resource - requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one - entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration - that will be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX - capabilities type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX - capabilities type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label - that applies to the container. - type: string - role: - description: Role is a SELinux role label - that applies to the container. - type: string - type: - description: Type is a SELinux type label - that applies to the container. - type: string - user: - description: User is a SELinux user label - that applies to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the - name of the GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting - of a Volume within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a - Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - required: - - image - type: object - type: array - tolerations: - description: Tolerations to be used in the Pod. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - topologySpreadConstraints: - description: TopologySpreadConstraints to be used in the - Pod. - items: - description: TopologySpreadConstraint specifies how - to spread matching pods among the given topology. - properties: - labelSelector: - description: |- - LabelSelector is used to find matching pods. - Pods that match this label selector are counted to determine the number of pods - in their corresponding topology domain. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select the pods over which - spreading will be calculated. The keys are used to lookup values from the - incoming pod labels, those key-value labels are ANDed with labelSelector - to select the group of existing pods over which spreading will be calculated - for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. - MatchLabelKeys cannot be set when LabelSelector isn't set. - Keys that don't exist in the incoming pod labels will - be ignored. A null or empty list means only match against labelSelector. - - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). - items: - type: string - type: array - x-kubernetes-list-type: atomic - maxSkew: - description: |- - MaxSkew describes the degree to which pods may be unevenly distributed. - When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference - between the number of matching pods in the target topology and the global minimum. - The global minimum is the minimum number of matching pods in an eligible domain - or zero if the number of eligible domains is less than MinDomains. - For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same - labelSelector spread as 2/2/1: - In this case, the global minimum is 1. - | zone1 | zone2 | zone3 | - | P P | P P | P | - - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; - scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) - violate MaxSkew(1). - - if MaxSkew is 2, incoming pod can be scheduled onto any zone. - When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence - to topologies that satisfy it. - It's a required field. Default value is 1 and 0 is not allowed. - format: int32 - type: integer - minDomains: - description: |- - MinDomains indicates a minimum number of eligible domains. - When the number of eligible domains with matching topology keys is less than minDomains, - Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. - And when the number of eligible domains with matching topology keys equals or greater than minDomains, - this value has no effect on scheduling. - As a result, when the number of eligible domains is less than minDomains, - scheduler won't schedule more than maxSkew Pods to those domains. - If value is nil, the constraint behaves as if MinDomains is equal to 1. - Valid values are integers greater than 0. - When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same - labelSelector spread as 2/2/2: - | zone1 | zone2 | zone3 | - | P P | P P | P P | - The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. - In this situation, new pod with the same labelSelector cannot be scheduled, - because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, - it will violate MaxSkew. - format: int32 - type: integer - nodeAffinityPolicy: - description: |- - NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector - when calculating pod topology spread skew. Options are: - - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - - 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: |- - NodeTaintsPolicy indicates how we will treat node taints when calculating - pod topology spread skew. Options are: - - Honor: nodes without taints, along with tainted nodes for which the incoming pod - has a toleration, are included. - - 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: |- - TopologyKey is the key of node labels. Nodes that have a label with this key - and identical values are considered to be in the same topology. - We consider each as a "bucket", and try to put balanced number - of pods into each bucket. - We define a domain as a particular instance of a topology. - Also, we define an eligible domain as a domain whose nodes meet the requirements of - nodeAffinityPolicy and nodeTaintsPolicy. - e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. - And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. - It's a required field. - type: string - whenUnsatisfiable: - description: |- - WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy - the spread constraint. - - DoNotSchedule (default) tells the scheduler not to schedule it. - - ScheduleAnyway tells the scheduler to schedule the pod in any location, - but giving higher precedence to topologies that would help reduce the - skew. - A constraint is considered "Unsatisfiable" for an incoming pod - if and only if every possible node assignment for that pod would violate - "MaxSkew" on some topology. - For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same - labelSelector spread as 3/1/1: - | zone1 | zone2 | zone3 | - | P P P | P | P | - If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled - to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies - MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler - won't make it *more* imbalanced. - It's a required field. - type: string - required: - - maxSkew - - topologyKey - - whenUnsatisfiable - type: object - type: array - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting of a Volume - within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - volumes: - description: Volumes to be used in the Pod. - items: - description: Volume represents a named volume in a pod - that may be accessed by any container in the pod. - properties: - awsElasticBlockStore: - description: |- - awsElasticBlockStore represents an AWS Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - format: int32 - type: integer - readOnly: - description: |- - readOnly value true will force the readOnly setting in VolumeMounts. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: boolean - volumeID: - description: |- - volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - required: - - volumeID - type: object - azureDisk: - description: azureDisk represents an Azure Data - Disk mount on the host and bind mount to the pod. - properties: - cachingMode: - description: 'cachingMode is the Host Caching - mode: None, Read Only, Read Write.' - type: string - diskName: - description: diskName is the Name of the data - disk in the blob storage - type: string - diskURI: - description: diskURI is the URI of data disk - in the blob storage - type: string - fsType: - default: ext4 - description: |- - fsType is Filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - kind: - description: 'kind expected values are Shared: - multiple blob disks per storage account Dedicated: - single blob disk per storage account Managed: - azure managed data disk (only in managed availability - set). defaults to shared' - type: string - readOnly: - default: false - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - required: - - diskName - - diskURI - type: object - azureFile: - description: azureFile represents an Azure File - Service mount on the host and bind mount to the - pod. - properties: - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretName: - description: secretName is the name of secret - that contains Azure Storage Account Name and - Key - type: string - shareName: - description: shareName is the azure share Name - type: string - required: - - secretName - - shareName - type: object - cephfs: - description: cephFS represents a Ceph FS mount on - the host that shares a pod's lifetime - properties: - monitors: - description: |- - monitors is Required: Monitors is a collection of Ceph monitors - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - path: - description: 'path is Optional: Used as the - mounted root, rather than the full Ceph tree, - default is /' - type: string - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: boolean - secretFile: - description: |- - secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - secretRef: - description: |- - secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - description: |- - user is optional: User is the rados user name, default is admin - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - required: - - monitors - type: object - cinder: - description: |- - cinder represents a cinder volume attached and mounted on kubelets host machine. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: boolean - secretRef: - description: |- - secretRef is optional: points to a secret object containing parameters used to connect - to OpenStack. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeID: - description: |- - volumeID used to identify the volume in cinder. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - required: - - volumeID - type: object - configMap: - description: configMap represents a configMap that - should populate this volume - properties: - defaultMode: - description: |- - defaultMode is optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether the ConfigMap - or its keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - csi: - description: csi (Container Storage Interface) represents - ephemeral storage that is handled by certain external - CSI drivers (Beta feature). - properties: - driver: - description: |- - driver is the name of the CSI driver that handles this volume. - Consult with your admin for the correct name as registered in the cluster. - type: string - fsType: - description: |- - fsType to mount. Ex. "ext4", "xfs", "ntfs". - If not provided, the empty value is passed to the associated CSI driver - which will determine the default filesystem to apply. - type: string - nodePublishSecretRef: - description: |- - nodePublishSecretRef is a reference to the secret object containing - sensitive information to pass to the CSI driver to complete the CSI - NodePublishVolume and NodeUnpublishVolume calls. - This field is optional, and may be empty if no secret is required. If the - secret object contains more than one secret, all secret references are passed. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - readOnly: - description: |- - readOnly specifies a read-only configuration for the volume. - Defaults to false (read/write). - type: boolean - volumeAttributes: - additionalProperties: - type: string - description: |- - volumeAttributes stores driver-specific properties that are passed to the CSI - driver. Consult your driver's documentation for supported values. - type: object - required: - - driver - type: object - downwardAPI: - description: downwardAPI represents downward API - about the pod that should populate this volume - properties: - defaultMode: - description: |- - Optional: mode bits to use on created files by default. Must be a - Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: Items is a list of downward API - volume file - items: - description: DownwardAPIVolumeFile represents - information to create the file containing - the pod field - properties: - fieldRef: - description: 'Required: Selects a field - of the pod: only annotations, labels, - name, namespace and uid are supported.' - properties: - apiVersion: - description: Version of the schema - the FieldPath is written in terms - of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to - select in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path is the relative - path name of the file to be created. - Must not be absolute or contain the - ''..'' path. Must be utf-8 encoded. - The first item of the relative path - must not start with ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output - format of the exposed resources, - defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to - select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - emptyDir: - description: |- - emptyDir represents a temporary directory that shares a pod's lifetime. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - properties: - medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - ephemeral: - description: |- - ephemeral represents a volume that is handled by a cluster storage driver. - The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, - and deleted when the pod is removed. - - Use this if: - a) the volume is only needed while the pod runs, - b) features of normal volumes like restoring from snapshot or capacity - tracking are needed, - c) the storage driver is specified through a storage class, and - d) the storage driver supports dynamic volume provisioning through - a PersistentVolumeClaim (see EphemeralVolumeSource for more - information on the connection between this volume type - and PersistentVolumeClaim). - - Use PersistentVolumeClaim or one of the vendor-specific - APIs for volumes that persist for longer than the lifecycle - of an individual pod. - - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to - be used that way - see the documentation of the driver for - more information. - - A pod can use both types of ephemeral volumes and - persistent volumes at the same time. - properties: - volumeClaimTemplate: - description: |- - Will be used to create a stand-alone PVC to provision the volume. - The pod in which this EphemeralVolumeSource is embedded will be the - owner of the PVC, i.e. the PVC will be deleted together with the - pod. The name of the PVC will be `-` where - `` is the name from the `PodSpec.Volumes` array - entry. Pod validation will reject the pod if the concatenated name - is not valid for a PVC (for example, too long). - - An existing PVC with that name that is not owned by the pod - will *not* be used for the pod to avoid using an unrelated - volume by mistake. Starting the pod is then blocked until - the unrelated PVC is removed. If such a pre-created PVC is - meant to be used by the pod, the PVC has to updated with an - owner reference to the pod once the pod exists. Normally - this should not be necessary, but it may be useful when - manually reconstructing a broken cluster. - - This field is read-only and no changes will be made by Kubernetes - to the PVC after it has been created. - - Required, must not be nil. - properties: - metadata: - description: |- - May contain labels and annotations that will be copied into the PVC - when creating it. No other fields are allowed and will be rejected during - validation. - type: object - spec: - description: |- - The specification for the PersistentVolumeClaim. The entire content is - copied unchanged into the PVC that gets created from this - template. The same fields as in a PersistentVolumeClaim - are also valid here. - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of - resource being referenced - type: string - name: - description: Name is the name of - resource being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of - resource being referenced - type: string - name: - description: Name is the name of - resource being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query - over volumes to consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding - reference to the PersistentVolume - backing this claim. - type: string - type: object - required: - - spec - type: object - type: object - fc: - description: fc represents a Fibre Channel resource - that is attached to a kubelet's host machine and - then exposed to the pod. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - lun: - description: 'lun is Optional: FC target lun - number' - format: int32 - type: integer - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - targetWWNs: - description: 'targetWWNs is Optional: FC target - worldwide names (WWNs)' - items: - type: string - type: array - x-kubernetes-list-type: atomic - wwids: - description: |- - wwids Optional: FC volume world wide identifiers (wwids) - Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - flexVolume: - description: |- - flexVolume represents a generic volume resource that is - provisioned/attached using an exec based plugin. - properties: - driver: - description: driver is the name of the driver - to use for this volume. - type: string - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. - type: string - options: - additionalProperties: - type: string - description: 'options is Optional: this field - holds extra command options if any.' - type: object - readOnly: - description: |- - readOnly is Optional: defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef is Optional: secretRef is reference to the secret object containing - sensitive information to pass to the plugin scripts. This may be - empty if no secret object is specified. If the secret object - contains more than one secret, all secrets are passed to the plugin - scripts. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - required: - - driver - type: object - flocker: - description: flocker represents a Flocker volume - attached to a kubelet's host machine. This depends - on the Flocker control service being running - properties: - datasetName: - description: |- - datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker - should be considered as deprecated - type: string - datasetUUID: - description: datasetUUID is the UUID of the - dataset. This is unique identifier of a Flocker - dataset - type: string - type: object - gcePersistentDisk: - description: |- - gcePersistentDisk represents a GCE Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - properties: - fsType: - description: |- - fsType is filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - format: int32 - type: integer - pdName: - description: |- - pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: boolean - required: - - pdName - type: object - gitRepo: - description: |- - gitRepo represents a git repository at a particular revision. - DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an - EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir - into the Pod's container. - properties: - directory: - description: |- - directory is the target directory name. - Must not contain or start with '..'. If '.' is supplied, the volume directory will be the - git repository. Otherwise, if specified, the volume will contain the git repository in - the subdirectory with the given name. - type: string - repository: - description: repository is the URL - type: string - revision: - description: revision is the commit hash for - the specified revision. - type: string - required: - - repository - type: object - glusterfs: - description: |- - glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/glusterfs/README.md - properties: - endpoints: - description: |- - endpoints is the endpoint name that details Glusterfs topology. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - path: - description: |- - path is the Glusterfs volume path. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - readOnly: - description: |- - readOnly here will force the Glusterfs volume to be mounted with read-only permissions. - Defaults to false. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: boolean - required: - - endpoints - - path - type: object - hostPath: - description: |- - hostPath represents a pre-existing file or directory on the host - machine that is directly exposed to the container. This is generally - used for system agents or other privileged things that are allowed - to see the host machine. Most containers will NOT need this. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - properties: - path: - description: |- - path of the directory on the host. - If the path is a symlink, it will follow the link to the real path. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - type: - description: |- - type for HostPath Volume - Defaults to "" - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - required: - - path - type: object - image: - description: |- - image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. - The volume is resolved at pod startup depending on which PullPolicy value is provided: - - - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - - The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. - A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. - 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). - The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. - properties: - pullPolicy: - description: |- - Policy for pulling OCI objects. Possible values are: - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. - type: string - reference: - description: |- - Required: Image or artifact reference to be used. - Behaves in the same way as pod.spec.containers[*].image. - Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. - More info: https://kubernetes.io/docs/concepts/containers/images - This field is optional to allow higher level config management to default or override - container images in workload controllers like Deployments and StatefulSets. - type: string - type: object - iscsi: - description: |- - iscsi represents an ISCSI Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://examples.k8s.io/volumes/iscsi/README.md - properties: - chapAuthDiscovery: - description: chapAuthDiscovery defines whether - support iSCSI Discovery CHAP authentication - type: boolean - chapAuthSession: - description: chapAuthSession defines whether - support iSCSI Session CHAP authentication - type: boolean - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - type: string - initiatorName: - description: |- - initiatorName is the custom iSCSI Initiator Name. - If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface - : will be created for the connection. - type: string - iqn: - description: iqn is the target iSCSI Qualified - Name. - type: string - iscsiInterface: - default: default - description: |- - iscsiInterface is the interface Name that uses an iSCSI transport. - Defaults to 'default' (tcp). - type: string - lun: - description: lun represents iSCSI Target Lun - number. - format: int32 - type: integer - portals: - description: |- - portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - items: - type: string - type: array - x-kubernetes-list-type: atomic - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - type: boolean - secretRef: - description: secretRef is the CHAP Secret for - iSCSI target and initiator authentication - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - targetPortal: - description: |- - targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - type: string - required: - - iqn - - lun - - targetPortal - type: object - name: - description: |- - name of the volume. - Must be a DNS_LABEL and unique within the pod. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - nfs: - description: |- - nfs represents an NFS mount on the host that shares a pod's lifetime - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - properties: - path: - description: |- - path that is exported by the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - readOnly: - description: |- - readOnly here will force the NFS export to be mounted with read-only permissions. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: boolean - server: - description: |- - server is the hostname or IP address of the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - required: - - path - - server - type: object - persistentVolumeClaim: - description: |- - persistentVolumeClaimVolumeSource represents a reference to a - PersistentVolumeClaim in the same namespace. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - claimName: - description: |- - claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - type: string - readOnly: - description: |- - readOnly Will force the ReadOnly setting in VolumeMounts. - Default false. - type: boolean - required: - - claimName - type: object - photonPersistentDisk: - description: photonPersistentDisk represents a PhotonController - persistent disk attached and mounted on kubelets - host machine - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - pdID: - description: pdID is the ID that identifies - Photon Controller persistent disk - type: string - required: - - pdID - type: object - portworxVolume: - description: portworxVolume represents a portworx - volume attached and mounted on kubelets host machine - properties: - fsType: - description: |- - fSType represents the filesystem type to mount - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - volumeID: - description: volumeID uniquely identifies a - Portworx volume - type: string - required: - - volumeID - type: object - projected: - description: projected items for all in one resources - secrets, configmaps, and downward API - properties: - defaultMode: - description: |- - defaultMode are the mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - sources: - description: |- - sources is the list of volume projections. Each entry in this list - handles one source. - items: - description: |- - Projection that may be projected along with other supported volume types. - Exactly one of these fields must be set. - properties: - clusterTrustBundle: - description: |- - ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field - of ClusterTrustBundle objects in an auto-updating file. - - Alpha, gated by the ClusterTrustBundleProjection feature gate. - - ClusterTrustBundle objects can either be selected by name, or by the - combination of signer name and a label selector. - - Kubelet performs aggressive normalization of the PEM contents written - into the pod filesystem. Esoteric PEM features such as inter-block - comments and block headers are stripped. Certificates are deduplicated. - The ordering of certificates within the file is arbitrary, and Kubelet - may change the order over time. - properties: - labelSelector: - description: |- - Select all ClusterTrustBundles that match this label selector. Only has - effect if signerName is set. Mutually-exclusive with name. If unset, - interpreted as "match nothing". If set but empty, interpreted as "match - everything". - 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 - name: - description: |- - Select a single ClusterTrustBundle by object name. Mutually-exclusive - with signerName and labelSelector. - type: string - optional: - description: |- - If true, don't block pod startup if the referenced ClusterTrustBundle(s) - aren't available. If using name, then the named ClusterTrustBundle is - allowed not to exist. If using signerName, then the combination of - signerName and labelSelector is allowed to match zero - ClusterTrustBundles. - type: boolean - path: - description: Relative path from the - volume root to write the bundle. - type: string - signerName: - description: |- - Select all ClusterTrustBundles that match this signer name. - Mutually-exclusive with name. The contents of all selected - ClusterTrustBundles will be unified and deduplicated. - type: string - required: - - path - type: object - configMap: - description: configMap information about - the configMap data to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to - a path within a volume. - properties: - key: - description: key is the key - to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether - the ConfigMap or its keys must be - defined - type: boolean - type: object - x-kubernetes-map-type: atomic - downwardAPI: - description: downwardAPI information about - the downwardAPI data to project - properties: - items: - description: Items is a list of DownwardAPIVolume - file - items: - description: DownwardAPIVolumeFile - represents information to create - the file containing the pod field - properties: - fieldRef: - description: 'Required: Selects - a field of the pod: only annotations, - labels, name, namespace and - uid are supported.' - properties: - apiVersion: - description: Version of - the schema the FieldPath - is written in terms of, - defaults to "v1". - type: string - fieldPath: - description: Path of the - field to select in the - specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path - is the relative path name - of the file to be created. - Must not be absolute or contain - the ''..'' path. Must be utf-8 - encoded. The first item of - the relative path must not - start with ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container - name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the - output format of the exposed - resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: - resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - secret: - description: secret information about - the secret data to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to - a path within a volume. - properties: - key: - description: key is the key - to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional field specify - whether the Secret or its key must - be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - serviceAccountToken: - description: serviceAccountToken is information - about the serviceAccountToken data to - project - properties: - audience: - description: |- - audience is the intended audience of the token. A recipient of a token - must identify itself with an identifier specified in the audience of the - token, and otherwise should reject the token. The audience defaults to the - identifier of the apiserver. - type: string - expirationSeconds: - description: |- - expirationSeconds is the requested duration of validity of the service - account token. As the token approaches expiration, the kubelet volume - plugin will proactively rotate the service account token. The kubelet will - start trying to rotate the token if the token is older than 80 percent of - its time to live or if the token is older than 24 hours.Defaults to 1 hour - and must be at least 10 minutes. - format: int64 - type: integer - path: - description: |- - path is the path relative to the mount point of the file to project the - token into. - type: string - required: - - path - type: object - type: object - type: array - x-kubernetes-list-type: atomic - type: object - quobyte: - description: quobyte represents a Quobyte mount - on the host that shares a pod's lifetime - properties: - group: - description: |- - group to map volume access to - Default is no group - type: string - readOnly: - description: |- - readOnly here will force the Quobyte volume to be mounted with read-only permissions. - Defaults to false. - type: boolean - registry: - description: |- - registry represents a single or multiple Quobyte Registry services - specified as a string as host:port pair (multiple entries are separated with commas) - which acts as the central registry for volumes - type: string - tenant: - description: |- - tenant owning the given Quobyte volume in the Backend - Used with dynamically provisioned Quobyte volumes, value is set by the plugin - type: string - user: - description: |- - user to map volume access to - Defaults to serivceaccount user - type: string - volume: - description: volume is a string that references - an already created Quobyte volume by name. - type: string - required: - - registry - - volume - type: object - rbd: - description: |- - rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/rbd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - type: string - image: - description: |- - image is the rados image name. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - keyring: - default: /etc/ceph/keyring - description: |- - keyring is the path to key ring for RBDUser. - Default is /etc/ceph/keyring. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - monitors: - description: |- - monitors is a collection of Ceph monitors. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - pool: - default: rbd - description: |- - pool is the rados pool name. - Default is rbd. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: boolean - secretRef: - description: |- - secretRef is name of the authentication secret for RBDUser. If provided - overrides keyring. - Default is nil. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - default: admin - description: |- - user is the rados user name. - Default is admin. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - required: - - image - - monitors - type: object - scaleIO: - description: scaleIO represents a ScaleIO persistent - volume attached and mounted on Kubernetes nodes. - properties: - fsType: - default: xfs - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". - Default is "xfs". - type: string - gateway: - description: gateway is the host address of - the ScaleIO API Gateway. - type: string - protectionDomain: - description: protectionDomain is the name of - the ScaleIO Protection Domain for the configured - storage. - type: string - readOnly: - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef references to the secret for ScaleIO user and other - sensitive information. If this is not provided, Login operation will fail. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - sslEnabled: - description: sslEnabled Flag enable/disable - SSL communication with Gateway, default false - type: boolean - storageMode: - default: ThinProvisioned - description: |- - storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. - Default is ThinProvisioned. - type: string - storagePool: - description: storagePool is the ScaleIO Storage - Pool associated with the protection domain. - type: string - system: - description: system is the name of the storage - system as configured in ScaleIO. - type: string - volumeName: - description: |- - volumeName is the name of a volume already created in the ScaleIO system - that is associated with this volume source. - type: string - required: - - gateway - - secretRef - - system - type: object - secret: - description: |- - secret represents a secret that should populate this volume. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - properties: - defaultMode: - description: |- - defaultMode is Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values - for mode bits. Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items If unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - optional: - description: optional field specify whether - the Secret or its keys must be defined - type: boolean - secretName: - description: |- - secretName is the name of the secret in the pod's namespace to use. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - type: string - type: object - storageos: - description: storageOS represents a StorageOS volume - attached and mounted on Kubernetes nodes. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef specifies the secret to use for obtaining the StorageOS API - credentials. If not specified, default values will be attempted. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeName: - description: |- - volumeName is the human-readable name of the StorageOS volume. Volume - names are only unique within a namespace. - type: string - volumeNamespace: - description: |- - volumeNamespace specifies the scope of the volume within StorageOS. If no - namespace is specified then the Pod's namespace will be used. This allows the - Kubernetes name scoping to be mirrored within StorageOS for tighter integration. - Set VolumeName to any name to override the default behaviour. - Set to "default" if you are not using namespaces within StorageOS. - Namespaces that do not pre-exist within StorageOS will be created. - type: string - type: object - vsphereVolume: - description: vsphereVolume represents a vSphere - volume attached and mounted on kubelets host machine - properties: - fsType: - description: |- - fsType is filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - storagePolicyID: - description: storagePolicyID is the storage - Policy Based Management (SPBM) profile ID - associated with the StoragePolicyName. - type: string - storagePolicyName: - description: storagePolicyName is the storage - Policy Based Management (SPBM) profile name. - type: string - volumePath: - description: volumePath is the path that identifies - vSphere volume vmdk - type: string - required: - - volumePath - type: object - required: - - name - type: object - type: array - type: object - serviceMonitor: - description: ServiceMonitor defines the ServiceMonior object. - properties: - interval: - description: Interval for scraping metrics. - type: string - jobLabel: - description: JobLabel to add to the ServiceMonitor object. - type: string - prometheusRelease: - description: PrometheusRelease is the release label to - add to the ServiceMonitor object. - type: string - scrapeTimeout: - description: ScrapeTimeout defines the timeout for scraping - metrics. - type: string - type: object - type: object - monitor: - description: Monitor monitors MariaDB server instances. - properties: - cooperativeMonitoring: - description: CooperativeMonitoring enables coordination between - multiple MaxScale instances running monitors. It is defaulted - when HA is enabled. - enum: - - majority_of_all - - majority_of_running - type: string - interval: - description: Interval used to monitor MariaDB servers. It - is defaulted if not provided. - type: string - module: - description: Module is the module to use to monitor MariaDB - servers. It is mandatory when no MariaDB reference is provided. - type: string - name: - description: Name is the identifier of the monitor. It is - defaulted if not provided. - type: string - params: - additionalProperties: - type: string - description: |- - Params defines extra parameters to pass to the monitor. - Any parameter supported by MaxScale may be specified here. See reference: - https://mariadb.com/kb/en/mariadb-maxscale-2308-common-monitor-parameters/. - Monitor specific parameter are also suported: - https://mariadb.com/kb/en/mariadb-maxscale-2308-galera-monitor/#galera-monitor-optional-parameters. - https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-monitor/#configuration. - type: object - suspend: - default: false - description: |- - Suspend indicates whether the current resource should be suspended or not. - This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. - type: boolean - type: object - podDisruptionBudget: - description: PodDisruptionBudget defines the budget for replica - availability. - properties: - maxUnavailable: - anyOf: - - type: integer - - type: string - description: MaxUnavailable defines the number of maximum - unavailable Pods. - x-kubernetes-int-or-string: true - minAvailable: - anyOf: - - type: integer - - type: string - description: MinAvailable defines the number of minimum available - Pods. - x-kubernetes-int-or-string: true - type: object - replicas: - description: Replicas indicates the number of desired instances. - format: int32 - type: integer - requeueInterval: - description: RequeueInterval is used to perform requeue reconciliations. - type: string - services: - description: Services define how the traffic is forwarded to the - MariaDB servers. - items: - description: Services define how the traffic is forwarded to - the MariaDB servers. - properties: - listener: - description: MaxScaleListener defines how the MaxScale server - will listen for connections. - properties: - name: - description: Name is the identifier of the listener. - It is defaulted if not provided - type: string - params: - additionalProperties: - type: string - description: |- - Params defines extra parameters to pass to the listener. - Any parameter supported by MaxScale may be specified here. See reference: - https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#listener_1. - type: object - port: - description: Port is the network port where the MaxScale - server will listen. - format: int32 - type: integer - protocol: - description: Protocol is the MaxScale protocol to use - when communicating with the client. If not provided, - it defaults to MariaDBProtocol. - type: string - suspend: - default: false - description: |- - Suspend indicates whether the current resource should be suspended or not. - This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. - type: boolean - required: - - port - type: object - name: - description: Name is the identifier of the MaxScale service. - type: string - params: - additionalProperties: - type: string - description: |- - Params defines extra parameters to pass to the service. - Any parameter supported by MaxScale may be specified here. See reference: - https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#service_1. - Router specific parameter are also suported: - https://mariadb.com/kb/en/mariadb-maxscale-2308-readwritesplit/#configuration. - https://mariadb.com/kb/en/mariadb-maxscale-2308-readconnroute/#configuration. - type: object - router: - description: Router is the type of router to use. - enum: - - readwritesplit - - readconnroute - type: string - suspend: - default: false - description: |- - Suspend indicates whether the current resource should be suspended or not. - This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. - type: boolean - required: - - listener - - name - - router - type: object - type: array - updateStrategy: - description: UpdateStrategy defines the update strategy for the - StatefulSet object. - properties: - rollingUpdate: - description: RollingUpdate is used to communicate parameters - when Type is RollingUpdateStatefulSetStrategyType. - properties: - maxUnavailable: - anyOf: - - type: integer - - type: string - description: |- - The maximum number of pods that can be unavailable during the update. - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). - Absolute number is calculated from percentage by rounding up. This can not be 0. - Defaults to 1. This field is alpha-level and is only honored by servers that enable the - MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to - Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it - will be counted towards MaxUnavailable. - x-kubernetes-int-or-string: true - partition: - description: |- - Partition indicates the ordinal at which the StatefulSet should be partitioned - for updates. During a rolling update, all pods from ordinal Replicas-1 to - Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. - This is helpful in being able to do a canary based deployment. The default value is 0. - format: int32 - type: integer - type: object - type: - description: |- - Type indicates the type of the StatefulSetUpdateStrategy. - Default is RollingUpdate. - type: string - type: object - type: object - maxScaleRef: - description: |- - MaxScaleRef is a reference to a MaxScale resource to be used with the current MariaDB. - Providing this field implies delegating high availability tasks such as primary failover to MaxScale. - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - type: object - x-kubernetes-map-type: atomic - metrics: - description: Metrics configures metrics and how to scrape them. - properties: - enabled: - description: Enabled is a flag to enable Metrics - type: boolean - exporter: - description: Exporter defines the metrics exporter container. - properties: - affinity: - description: Affinity to be used in the Pod. - properties: - antiAffinityEnabled: - description: |- - AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. - Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. - type: boolean - nodeAffinity: - description: Describes node affinity scheduling rules - for the pod. - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - properties: - preference: - description: A node selector term, associated - with the corresponding weight. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching - the corresponding nodeSelectorTerm, in the - range 1-100. - format: int32 - type: integer - required: - - preference - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - properties: - nodeSelectorTerms: - description: Required. A list of node selector - terms. The terms are ORed. - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - type: array - x-kubernetes-list-type: atomic - required: - - nodeSelectorTerms - type: object - x-kubernetes-map-type: atomic - type: object - podAffinity: - description: Describes pod affinity scheduling rules (e.g. - co-locate this pod in the same node, zone, etc. as some - other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred - node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, - associated with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules - (e.g. avoid putting this pod in the same node, zone, - etc. as some other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred - node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, - associated with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - type: object - args: - description: Args to be used in the Container. - items: - type: string - type: array - command: - description: Command to be used in the Container. - items: - type: string - type: array - env: - description: Env represents the environment variables to be - injected in a container. - items: - description: EnvVar represents an environment variable present - in a Container. - properties: - name: - description: Name of the environment variable. Must - be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. - Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in - the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of - the exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's - namespace - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via ConfigMap - and Secrets) to environment variables to be injected in - the container. - items: - description: EnvFromSource represents the source of a set - of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must - be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be - defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: |- - Image name to be used as metrics exporter. The supported format is `:`. - Only mysqld-exporter >= v0.15.0 is supported: https://github.com/prometheus/mysqld_exporter - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. One - of `Always`, `Never` or `IfNotPresent`. If not defined, - it defaults to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - imagePullSecrets: - description: ImagePullSecrets is the list of pull Secrets - to be used to pull the image. - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - initContainers: - description: InitContainers to be used in the Pod. - items: - description: Container object definition. - properties: - args: - description: Args to be used in the Container. - items: - type: string - type: array - command: - description: Command to be used in the Container. - items: - type: string - type: array - env: - description: Env represents the environment variables - to be injected in a container. - items: - description: EnvVar represents an environment variable - present in a Container. - properties: - name: - description: Name of the environment variable. - Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, defaults - to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in - the pod's namespace - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via - ConfigMap and Secrets) to environment variables to - be injected in the container. - items: - description: EnvFromSource represents the source of - a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must - be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: Image name to be used by the MariaDB instances. - The supported format is `:`. - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. - One of `Always`, `Never` or `IfNotPresent`. If not - defined, it defaults to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - resources: - description: Resouces describes the compute resource - requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry - in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration - that will be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that - applies to the container. - type: string - role: - description: Role is a SELinux role label that - applies to the container. - type: string - type: - description: Type is a SELinux type label that - applies to the container. - type: string - user: - description: User is a SELinux user label that - applies to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name - of the GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting of a - Volume within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - required: - - image - type: object - type: array - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC - port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a - TCP port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - nodeSelector: - additionalProperties: - type: string - description: NodeSelector to be used in the Pod. - type: object - podMetadata: - description: PodMetadata defines extra metadata for the Pod. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - podSecurityContext: - description: SecurityContext holds pod-level security attributes - and common container settings. - properties: - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies - to the container. - type: string - role: - description: Role is a SELinux role label that applies - to the container. - type: string - type: - description: Type is a SELinux type label that applies - to the container. - type: string - user: - description: User is a SELinux user label that applies - to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in - addition to the container's primary GID and fsGroup (if specified). If - the SupplementalGroupsPolicy feature is enabled, the - supplementalGroupsPolicy field determines whether these are in addition - to or instead of any group memberships defined in the container image. - If unspecified, no additional groups are added, though group memberships - defined in the container image may still be used, depending on the - supplementalGroupsPolicy field. - Note that this field cannot be set when spec.os.name is windows. - items: - format: int64 - type: integer - type: array - x-kubernetes-list-type: atomic - supplementalGroupsPolicy: - description: |- - Defines how supplemental groups of the first container processes are calculated. - Valid values are "Merge" and "Strict". If not specified, "Merge" is used. - (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled - and the container runtime must implement support for this feature. - Note that this field cannot be set when spec.os.name is windows. - type: string - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - items: - description: Sysctl defines a kernel parameter to be - set - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options within a container's SecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of - the GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - port: - description: Port where the exporter will be listening for - connections. - format: int32 - type: integer - priorityClassName: - description: PriorityClassName to be used in the Pod. - type: string - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC - port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a - TCP port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration - that will be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies - to the container. - type: string - role: - description: Role is a SELinux role label that applies - to the container. - type: string - type: - description: Type is a SELinux type label that applies - to the container. - type: string - user: - description: User is a SELinux user label that applies - to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of - the GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to be used by the Pods. - type: string - sidecarContainers: - description: SidecarContainers to be used in the Pod. - items: - description: Container object definition. - properties: - args: - description: Args to be used in the Container. - items: - type: string - type: array - command: - description: Command to be used in the Container. - items: - type: string - type: array - env: - description: Env represents the environment variables - to be injected in a container. - items: - description: EnvVar represents an environment variable - present in a Container. - properties: - name: - description: Name of the environment variable. - Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, defaults - to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in - the pod's namespace - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via - ConfigMap and Secrets) to environment variables to - be injected in the container. - items: - description: EnvFromSource represents the source of - a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must - be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: Image name to be used by the MariaDB instances. - The supported format is `:`. - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. - One of `Always`, `Never` or `IfNotPresent`. If not - defined, it defaults to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - resources: - description: Resouces describes the compute resource - requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry - in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration - that will be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that - applies to the container. - type: string - role: - description: Role is a SELinux role label that - applies to the container. - type: string - type: - description: Type is a SELinux type label that - applies to the container. - type: string - user: - description: User is a SELinux user label that - applies to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name - of the GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting of a - Volume within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - required: - - image - type: object - type: array - tolerations: - description: Tolerations to be used in the Pod. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - topologySpreadConstraints: - description: TopologySpreadConstraints to be used in the Pod. - items: - description: TopologySpreadConstraint specifies how to spread - matching pods among the given topology. - properties: - labelSelector: - description: |- - LabelSelector is used to find matching pods. - Pods that match this label selector are counted to determine the number of pods - in their corresponding topology domain. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select the pods over which - spreading will be calculated. The keys are used to lookup values from the - incoming pod labels, those key-value labels are ANDed with labelSelector - to select the group of existing pods over which spreading will be calculated - for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. - MatchLabelKeys cannot be set when LabelSelector isn't set. - Keys that don't exist in the incoming pod labels will - be ignored. A null or empty list means only match against labelSelector. - - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). - items: - type: string - type: array - x-kubernetes-list-type: atomic - maxSkew: - description: |- - MaxSkew describes the degree to which pods may be unevenly distributed. - When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference - between the number of matching pods in the target topology and the global minimum. - The global minimum is the minimum number of matching pods in an eligible domain - or zero if the number of eligible domains is less than MinDomains. - For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same - labelSelector spread as 2/2/1: - In this case, the global minimum is 1. - | zone1 | zone2 | zone3 | - | P P | P P | P | - - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; - scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) - violate MaxSkew(1). - - if MaxSkew is 2, incoming pod can be scheduled onto any zone. - When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence - to topologies that satisfy it. - It's a required field. Default value is 1 and 0 is not allowed. - format: int32 - type: integer - minDomains: - description: |- - MinDomains indicates a minimum number of eligible domains. - When the number of eligible domains with matching topology keys is less than minDomains, - Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. - And when the number of eligible domains with matching topology keys equals or greater than minDomains, - this value has no effect on scheduling. - As a result, when the number of eligible domains is less than minDomains, - scheduler won't schedule more than maxSkew Pods to those domains. - If value is nil, the constraint behaves as if MinDomains is equal to 1. - Valid values are integers greater than 0. - When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same - labelSelector spread as 2/2/2: - | zone1 | zone2 | zone3 | - | P P | P P | P P | - The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. - In this situation, new pod with the same labelSelector cannot be scheduled, - because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, - it will violate MaxSkew. - format: int32 - type: integer - nodeAffinityPolicy: - description: |- - NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector - when calculating pod topology spread skew. Options are: - - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - - 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: |- - NodeTaintsPolicy indicates how we will treat node taints when calculating - pod topology spread skew. Options are: - - Honor: nodes without taints, along with tainted nodes for which the incoming pod - has a toleration, are included. - - 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: |- - TopologyKey is the key of node labels. Nodes that have a label with this key - and identical values are considered to be in the same topology. - We consider each as a "bucket", and try to put balanced number - of pods into each bucket. - We define a domain as a particular instance of a topology. - Also, we define an eligible domain as a domain whose nodes meet the requirements of - nodeAffinityPolicy and nodeTaintsPolicy. - e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. - And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. - It's a required field. - type: string - whenUnsatisfiable: - description: |- - WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy - the spread constraint. - - DoNotSchedule (default) tells the scheduler not to schedule it. - - ScheduleAnyway tells the scheduler to schedule the pod in any location, - but giving higher precedence to topologies that would help reduce the - skew. - A constraint is considered "Unsatisfiable" for an incoming pod - if and only if every possible node assignment for that pod would violate - "MaxSkew" on some topology. - For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same - labelSelector spread as 3/1/1: - | zone1 | zone2 | zone3 | - | P P P | P | P | - If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled - to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies - MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler - won't make it *more* imbalanced. - It's a required field. - type: string - required: - - maxSkew - - topologyKey - - whenUnsatisfiable - type: object - type: array - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting of a Volume - within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - volumes: - description: Volumes to be used in the Pod. - items: - description: Volume represents a named volume in a pod that - may be accessed by any container in the pod. - properties: - awsElasticBlockStore: - description: |- - awsElasticBlockStore represents an AWS Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - format: int32 - type: integer - readOnly: - description: |- - readOnly value true will force the readOnly setting in VolumeMounts. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: boolean - volumeID: - description: |- - volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - required: - - volumeID - type: object - azureDisk: - description: azureDisk represents an Azure Data Disk - mount on the host and bind mount to the pod. - properties: - cachingMode: - description: 'cachingMode is the Host Caching mode: - None, Read Only, Read Write.' - type: string - diskName: - description: diskName is the Name of the data disk - in the blob storage - type: string - diskURI: - description: diskURI is the URI of data disk in - the blob storage - type: string - fsType: - default: ext4 - description: |- - fsType is Filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - kind: - description: 'kind expected values are Shared: multiple - blob disks per storage account Dedicated: single - blob disk per storage account Managed: azure - managed data disk (only in managed availability - set). defaults to shared' - type: string - readOnly: - default: false - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - required: - - diskName - - diskURI - type: object - azureFile: - description: azureFile represents an Azure File Service - mount on the host and bind mount to the pod. - properties: - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretName: - description: secretName is the name of secret that - contains Azure Storage Account Name and Key - type: string - shareName: - description: shareName is the azure share Name - type: string - required: - - secretName - - shareName - type: object - cephfs: - description: cephFS represents a Ceph FS mount on the - host that shares a pod's lifetime - properties: - monitors: - description: |- - monitors is Required: Monitors is a collection of Ceph monitors - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - path: - description: 'path is Optional: Used as the mounted - root, rather than the full Ceph tree, default - is /' - type: string - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: boolean - secretFile: - description: |- - secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - secretRef: - description: |- - secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - description: |- - user is optional: User is the rados user name, default is admin - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - required: - - monitors - type: object - cinder: - description: |- - cinder represents a cinder volume attached and mounted on kubelets host machine. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: boolean - secretRef: - description: |- - secretRef is optional: points to a secret object containing parameters used to connect - to OpenStack. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeID: - description: |- - volumeID used to identify the volume in cinder. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - required: - - volumeID - type: object - configMap: - description: configMap represents a configMap that should - populate this volume - properties: - defaultMode: - description: |- - defaultMode is optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether the ConfigMap - or its keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - csi: - description: csi (Container Storage Interface) represents - ephemeral storage that is handled by certain external - CSI drivers (Beta feature). - properties: - driver: - description: |- - driver is the name of the CSI driver that handles this volume. - Consult with your admin for the correct name as registered in the cluster. - type: string - fsType: - description: |- - fsType to mount. Ex. "ext4", "xfs", "ntfs". - If not provided, the empty value is passed to the associated CSI driver - which will determine the default filesystem to apply. - type: string - nodePublishSecretRef: - description: |- - nodePublishSecretRef is a reference to the secret object containing - sensitive information to pass to the CSI driver to complete the CSI - NodePublishVolume and NodeUnpublishVolume calls. - This field is optional, and may be empty if no secret is required. If the - secret object contains more than one secret, all secret references are passed. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - readOnly: - description: |- - readOnly specifies a read-only configuration for the volume. - Defaults to false (read/write). - type: boolean - volumeAttributes: - additionalProperties: - type: string - description: |- - volumeAttributes stores driver-specific properties that are passed to the CSI - driver. Consult your driver's documentation for supported values. - type: object - required: - - driver - type: object - downwardAPI: - description: downwardAPI represents downward API about - the pod that should populate this volume - properties: - defaultMode: - description: |- - Optional: mode bits to use on created files by default. Must be a - Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: Items is a list of downward API volume - file - items: - description: DownwardAPIVolumeFile represents - information to create the file containing the - pod field - properties: - fieldRef: - description: 'Required: Selects a field of - the pod: only annotations, labels, name, - namespace and uid are supported.' - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, defaults - to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path is the relative - path name of the file to be created. Must - not be absolute or contain the ''..'' path. - Must be utf-8 encoded. The first item of - the relative path must not start with ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - emptyDir: - description: |- - emptyDir represents a temporary directory that shares a pod's lifetime. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - properties: - medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - ephemeral: - description: |- - ephemeral represents a volume that is handled by a cluster storage driver. - The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, - and deleted when the pod is removed. - - Use this if: - a) the volume is only needed while the pod runs, - b) features of normal volumes like restoring from snapshot or capacity - tracking are needed, - c) the storage driver is specified through a storage class, and - d) the storage driver supports dynamic volume provisioning through - a PersistentVolumeClaim (see EphemeralVolumeSource for more - information on the connection between this volume type - and PersistentVolumeClaim). - - Use PersistentVolumeClaim or one of the vendor-specific - APIs for volumes that persist for longer than the lifecycle - of an individual pod. - - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to - be used that way - see the documentation of the driver for - more information. - - A pod can use both types of ephemeral volumes and - persistent volumes at the same time. - properties: - volumeClaimTemplate: - description: |- - Will be used to create a stand-alone PVC to provision the volume. - The pod in which this EphemeralVolumeSource is embedded will be the - owner of the PVC, i.e. the PVC will be deleted together with the - pod. The name of the PVC will be `-` where - `` is the name from the `PodSpec.Volumes` array - entry. Pod validation will reject the pod if the concatenated name - is not valid for a PVC (for example, too long). - - An existing PVC with that name that is not owned by the pod - will *not* be used for the pod to avoid using an unrelated - volume by mistake. Starting the pod is then blocked until - the unrelated PVC is removed. If such a pre-created PVC is - meant to be used by the pod, the PVC has to updated with an - owner reference to the pod once the pod exists. Normally - this should not be necessary, but it may be useful when - manually reconstructing a broken cluster. - - This field is read-only and no changes will be made by Kubernetes - to the PVC after it has been created. - - Required, must not be nil. - properties: - metadata: - description: |- - May contain labels and annotations that will be copied into the PVC - when creating it. No other fields are allowed and will be rejected during - validation. - type: object - spec: - description: |- - The specification for the PersistentVolumeClaim. The entire content is - copied unchanged into the PVC that gets created from this - template. The same fields as in a PersistentVolumeClaim - are also valid here. - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource - being referenced - type: string - name: - description: Name is the name of resource - being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource - being referenced - type: string - name: - description: Name is the name of resource - being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over - volumes to consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference - to the PersistentVolume backing this claim. - type: string - type: object - required: - - spec - type: object - type: object - fc: - description: fc represents a Fibre Channel resource - that is attached to a kubelet's host machine and then - exposed to the pod. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - lun: - description: 'lun is Optional: FC target lun number' - format: int32 - type: integer - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - targetWWNs: - description: 'targetWWNs is Optional: FC target - worldwide names (WWNs)' - items: - type: string - type: array - x-kubernetes-list-type: atomic - wwids: - description: |- - wwids Optional: FC volume world wide identifiers (wwids) - Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - flexVolume: - description: |- - flexVolume represents a generic volume resource that is - provisioned/attached using an exec based plugin. - properties: - driver: - description: driver is the name of the driver to - use for this volume. - type: string - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. - type: string - options: - additionalProperties: - type: string - description: 'options is Optional: this field holds - extra command options if any.' - type: object - readOnly: - description: |- - readOnly is Optional: defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef is Optional: secretRef is reference to the secret object containing - sensitive information to pass to the plugin scripts. This may be - empty if no secret object is specified. If the secret object - contains more than one secret, all secrets are passed to the plugin - scripts. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - required: - - driver - type: object - flocker: - description: flocker represents a Flocker volume attached - to a kubelet's host machine. This depends on the Flocker - control service being running - properties: - datasetName: - description: |- - datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker - should be considered as deprecated - type: string - datasetUUID: - description: datasetUUID is the UUID of the dataset. - This is unique identifier of a Flocker dataset - type: string - type: object - gcePersistentDisk: - description: |- - gcePersistentDisk represents a GCE Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - properties: - fsType: - description: |- - fsType is filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - format: int32 - type: integer - pdName: - description: |- - pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: boolean - required: - - pdName - type: object - gitRepo: - description: |- - gitRepo represents a git repository at a particular revision. - DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an - EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir - into the Pod's container. - properties: - directory: - description: |- - directory is the target directory name. - Must not contain or start with '..'. If '.' is supplied, the volume directory will be the - git repository. Otherwise, if specified, the volume will contain the git repository in - the subdirectory with the given name. - type: string - repository: - description: repository is the URL - type: string - revision: - description: revision is the commit hash for the - specified revision. - type: string - required: - - repository - type: object - glusterfs: - description: |- - glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/glusterfs/README.md - properties: - endpoints: - description: |- - endpoints is the endpoint name that details Glusterfs topology. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - path: - description: |- - path is the Glusterfs volume path. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - readOnly: - description: |- - readOnly here will force the Glusterfs volume to be mounted with read-only permissions. - Defaults to false. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: boolean - required: - - endpoints - - path - type: object - hostPath: - description: |- - hostPath represents a pre-existing file or directory on the host - machine that is directly exposed to the container. This is generally - used for system agents or other privileged things that are allowed - to see the host machine. Most containers will NOT need this. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - properties: - path: - description: |- - path of the directory on the host. - If the path is a symlink, it will follow the link to the real path. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - type: - description: |- - type for HostPath Volume - Defaults to "" - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - required: - - path - type: object - image: - description: |- - image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. - The volume is resolved at pod startup depending on which PullPolicy value is provided: - - - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - - The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. - A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. - 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). - The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. - properties: - pullPolicy: - description: |- - Policy for pulling OCI objects. Possible values are: - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. - type: string - reference: - description: |- - Required: Image or artifact reference to be used. - Behaves in the same way as pod.spec.containers[*].image. - Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. - More info: https://kubernetes.io/docs/concepts/containers/images - This field is optional to allow higher level config management to default or override - container images in workload controllers like Deployments and StatefulSets. - type: string - type: object - iscsi: - description: |- - iscsi represents an ISCSI Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://examples.k8s.io/volumes/iscsi/README.md - properties: - chapAuthDiscovery: - description: chapAuthDiscovery defines whether support - iSCSI Discovery CHAP authentication - type: boolean - chapAuthSession: - description: chapAuthSession defines whether support - iSCSI Session CHAP authentication - type: boolean - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - type: string - initiatorName: - description: |- - initiatorName is the custom iSCSI Initiator Name. - If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface - : will be created for the connection. - type: string - iqn: - description: iqn is the target iSCSI Qualified Name. - type: string - iscsiInterface: - default: default - description: |- - iscsiInterface is the interface Name that uses an iSCSI transport. - Defaults to 'default' (tcp). - type: string - lun: - description: lun represents iSCSI Target Lun number. - format: int32 - type: integer - portals: - description: |- - portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - items: - type: string - type: array - x-kubernetes-list-type: atomic - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - type: boolean - secretRef: - description: secretRef is the CHAP Secret for iSCSI - target and initiator authentication - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - targetPortal: - description: |- - targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - type: string - required: - - iqn - - lun - - targetPortal - type: object - name: - description: |- - name of the volume. - Must be a DNS_LABEL and unique within the pod. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - nfs: - description: |- - nfs represents an NFS mount on the host that shares a pod's lifetime - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - properties: - path: - description: |- - path that is exported by the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - readOnly: - description: |- - readOnly here will force the NFS export to be mounted with read-only permissions. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: boolean - server: - description: |- - server is the hostname or IP address of the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - required: - - path - - server - type: object - persistentVolumeClaim: - description: |- - persistentVolumeClaimVolumeSource represents a reference to a - PersistentVolumeClaim in the same namespace. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - claimName: - description: |- - claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - type: string - readOnly: - description: |- - readOnly Will force the ReadOnly setting in VolumeMounts. - Default false. - type: boolean - required: - - claimName - type: object - photonPersistentDisk: - description: photonPersistentDisk represents a PhotonController - persistent disk attached and mounted on kubelets host - machine - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - pdID: - description: pdID is the ID that identifies Photon - Controller persistent disk - type: string - required: - - pdID - type: object - portworxVolume: - description: portworxVolume represents a portworx volume - attached and mounted on kubelets host machine - properties: - fsType: - description: |- - fSType represents the filesystem type to mount - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - volumeID: - description: volumeID uniquely identifies a Portworx - volume - type: string - required: - - volumeID - type: object - projected: - description: projected items for all in one resources - secrets, configmaps, and downward API - properties: - defaultMode: - description: |- - defaultMode are the mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - sources: - description: |- - sources is the list of volume projections. Each entry in this list - handles one source. - items: - description: |- - Projection that may be projected along with other supported volume types. - Exactly one of these fields must be set. - properties: - clusterTrustBundle: - description: |- - ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field - of ClusterTrustBundle objects in an auto-updating file. - - Alpha, gated by the ClusterTrustBundleProjection feature gate. - - ClusterTrustBundle objects can either be selected by name, or by the - combination of signer name and a label selector. - - Kubelet performs aggressive normalization of the PEM contents written - into the pod filesystem. Esoteric PEM features such as inter-block - comments and block headers are stripped. Certificates are deduplicated. - The ordering of certificates within the file is arbitrary, and Kubelet - may change the order over time. - properties: - labelSelector: - description: |- - Select all ClusterTrustBundles that match this label selector. Only has - effect if signerName is set. Mutually-exclusive with name. If unset, - interpreted as "match nothing". If set but empty, interpreted as "match - everything". - 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 - name: - description: |- - Select a single ClusterTrustBundle by object name. Mutually-exclusive - with signerName and labelSelector. - type: string - optional: - description: |- - If true, don't block pod startup if the referenced ClusterTrustBundle(s) - aren't available. If using name, then the named ClusterTrustBundle is - allowed not to exist. If using signerName, then the combination of - signerName and labelSelector is allowed to match zero - ClusterTrustBundles. - type: boolean - path: - description: Relative path from the volume - root to write the bundle. - type: string - signerName: - description: |- - Select all ClusterTrustBundles that match this signer name. - Mutually-exclusive with name. The contents of all selected - ClusterTrustBundles will be unified and deduplicated. - type: string - required: - - path - type: object - configMap: - description: configMap information about the - configMap data to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a - path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether - the ConfigMap or its keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - downwardAPI: - description: downwardAPI information about - the downwardAPI data to project - properties: - items: - description: Items is a list of DownwardAPIVolume - file - items: - description: DownwardAPIVolumeFile represents - information to create the file containing - the pod field - properties: - fieldRef: - description: 'Required: Selects - a field of the pod: only annotations, - labels, name, namespace and uid - are supported.' - properties: - apiVersion: - description: Version of the - schema the FieldPath is written - in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field - to select in the specified - API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path is the - relative path name of the file - to be created. Must not be absolute - or contain the ''..'' path. Must - be utf-8 encoded. The first item - of the relative path must not - start with ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container name: - required for volumes, optional - for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output - format of the exposed resources, - defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource - to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - secret: - description: secret information about the - secret data to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a - path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional field specify whether - the Secret or its key must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - serviceAccountToken: - description: serviceAccountToken is information - about the serviceAccountToken data to project - properties: - audience: - description: |- - audience is the intended audience of the token. A recipient of a token - must identify itself with an identifier specified in the audience of the - token, and otherwise should reject the token. The audience defaults to the - identifier of the apiserver. - type: string - expirationSeconds: - description: |- - expirationSeconds is the requested duration of validity of the service - account token. As the token approaches expiration, the kubelet volume - plugin will proactively rotate the service account token. The kubelet will - start trying to rotate the token if the token is older than 80 percent of - its time to live or if the token is older than 24 hours.Defaults to 1 hour - and must be at least 10 minutes. - format: int64 - type: integer - path: - description: |- - path is the path relative to the mount point of the file to project the - token into. - type: string - required: - - path - type: object - type: object - type: array - x-kubernetes-list-type: atomic - type: object - quobyte: - description: quobyte represents a Quobyte mount on the - host that shares a pod's lifetime - properties: - group: - description: |- - group to map volume access to - Default is no group - type: string - readOnly: - description: |- - readOnly here will force the Quobyte volume to be mounted with read-only permissions. - Defaults to false. - type: boolean - registry: - description: |- - registry represents a single or multiple Quobyte Registry services - specified as a string as host:port pair (multiple entries are separated with commas) - which acts as the central registry for volumes - type: string - tenant: - description: |- - tenant owning the given Quobyte volume in the Backend - Used with dynamically provisioned Quobyte volumes, value is set by the plugin - type: string - user: - description: |- - user to map volume access to - Defaults to serivceaccount user - type: string - volume: - description: volume is a string that references - an already created Quobyte volume by name. - type: string - required: - - registry - - volume - type: object - rbd: - description: |- - rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/rbd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - type: string - image: - description: |- - image is the rados image name. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - keyring: - default: /etc/ceph/keyring - description: |- - keyring is the path to key ring for RBDUser. - Default is /etc/ceph/keyring. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - monitors: - description: |- - monitors is a collection of Ceph monitors. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - pool: - default: rbd - description: |- - pool is the rados pool name. - Default is rbd. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: boolean - secretRef: - description: |- - secretRef is name of the authentication secret for RBDUser. If provided - overrides keyring. - Default is nil. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - default: admin - description: |- - user is the rados user name. - Default is admin. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - required: - - image - - monitors - type: object - scaleIO: - description: scaleIO represents a ScaleIO persistent - volume attached and mounted on Kubernetes nodes. - properties: - fsType: - default: xfs - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". - Default is "xfs". - type: string - gateway: - description: gateway is the host address of the - ScaleIO API Gateway. - type: string - protectionDomain: - description: protectionDomain is the name of the - ScaleIO Protection Domain for the configured storage. - type: string - readOnly: - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef references to the secret for ScaleIO user and other - sensitive information. If this is not provided, Login operation will fail. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - sslEnabled: - description: sslEnabled Flag enable/disable SSL - communication with Gateway, default false - type: boolean - storageMode: - default: ThinProvisioned - description: |- - storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. - Default is ThinProvisioned. - type: string - storagePool: - description: storagePool is the ScaleIO Storage - Pool associated with the protection domain. - type: string - system: - description: system is the name of the storage system - as configured in ScaleIO. - type: string - volumeName: - description: |- - volumeName is the name of a volume already created in the ScaleIO system - that is associated with this volume source. - type: string - required: - - gateway - - secretRef - - system - type: object - secret: - description: |- - secret represents a secret that should populate this volume. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - properties: - defaultMode: - description: |- - defaultMode is Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values - for mode bits. Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items If unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - optional: - description: optional field specify whether the - Secret or its keys must be defined - type: boolean - secretName: - description: |- - secretName is the name of the secret in the pod's namespace to use. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - type: string - type: object - storageos: - description: storageOS represents a StorageOS volume - attached and mounted on Kubernetes nodes. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef specifies the secret to use for obtaining the StorageOS API - credentials. If not specified, default values will be attempted. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeName: - description: |- - volumeName is the human-readable name of the StorageOS volume. Volume - names are only unique within a namespace. - type: string - volumeNamespace: - description: |- - volumeNamespace specifies the scope of the volume within StorageOS. If no - namespace is specified then the Pod's namespace will be used. This allows the - Kubernetes name scoping to be mirrored within StorageOS for tighter integration. - Set VolumeName to any name to override the default behaviour. - Set to "default" if you are not using namespaces within StorageOS. - Namespaces that do not pre-exist within StorageOS will be created. - type: string - type: object - vsphereVolume: - description: vsphereVolume represents a vSphere volume - attached and mounted on kubelets host machine - properties: - fsType: - description: |- - fsType is filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - storagePolicyID: - description: storagePolicyID is the storage Policy - Based Management (SPBM) profile ID associated - with the StoragePolicyName. - type: string - storagePolicyName: - description: storagePolicyName is the storage Policy - Based Management (SPBM) profile name. - type: string - volumePath: - description: volumePath is the path that identifies - vSphere volume vmdk - type: string - required: - - volumePath - type: object - required: - - name - type: object - type: array - type: object - passwordSecretKeyRef: - description: |- - PasswordSecretKeyRef is a reference to the password of the monitoring user used by the exporter. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. - properties: - generate: - default: false - description: Generate indicates whether the Secret should - be generated if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serviceMonitor: - description: ServiceMonitor defines the ServiceMonior object. - properties: - interval: - description: Interval for scraping metrics. - type: string - jobLabel: - description: JobLabel to add to the ServiceMonitor object. - type: string - prometheusRelease: - description: PrometheusRelease is the release label to add - to the ServiceMonitor object. - type: string - scrapeTimeout: - description: ScrapeTimeout defines the timeout for scraping - metrics. - type: string - type: object - username: - description: Username is the username of the monitoring user used - by the exporter. - type: string - type: object - myCnf: - description: |- - MyCnf allows to specify the my.cnf file mounted by Mariadb. - Updating this field will trigger an update to the Mariadb resource. - type: string - myCnfConfigMapKeyRef: - description: |- - MyCnfConfigMapKeyRef is a reference to the my.cnf config file provided via a ConfigMap. - If not provided, it will be defaulted with a reference to a ConfigMap containing the MyCnf field. - If the referred ConfigMap is labeled with "k8s.mariadb.com/watch", an update to the Mariadb resource will be triggered when the ConfigMap is updated. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - nodeSelector: - additionalProperties: - type: string - description: NodeSelector to be used in the Pod. - type: object - passwordHashSecretKeyRef: - description: |- - PasswordHashSecretKeyRef is a reference to the password hash to be used by the initial User. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password hash. - properties: - key: - description: The key of the secret to select from. Must be a - valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - passwordPlugin: - description: PasswordPlugin is a reference to the password plugin - and arguments to be used by the initial User. - properties: - pluginArgSecretKeyRef: - description: |- - PluginArgSecretKeyRef is a reference to the arguments to be provided to the authentication plugin for the User. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the authentication plugin arguments. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - pluginNameSecretKeyRef: - description: |- - PluginNameSecretKeyRef is a reference to the authentication plugin to be used by the User. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the authentication plugin. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - passwordSecretKeyRef: - description: |- - PasswordSecretKeyRef is a reference to a Secret that contains the password to be used by the initial User. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. - properties: - generate: - default: false - description: Generate indicates whether the Secret should be generated - if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must be a - valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - podDisruptionBudget: - description: PodDisruptionBudget defines the budget for replica availability. - properties: - maxUnavailable: - anyOf: - - type: integer - - type: string - description: MaxUnavailable defines the number of maximum unavailable - Pods. - x-kubernetes-int-or-string: true - minAvailable: - anyOf: - - type: integer - - type: string - description: MinAvailable defines the number of minimum available - Pods. - x-kubernetes-int-or-string: true - type: object - podMetadata: - description: PodMetadata defines extra metadata for the Pod. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - podSecurityContext: - description: SecurityContext holds pod-level security attributes and - common container settings. - properties: - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies to - the container. - type: string - role: - description: Role is a SELinux role label that applies to - the container. - type: string - type: - description: Type is a SELinux type label that applies to - the container. - type: string - user: - description: User is a SELinux user label that applies to - the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in - addition to the container's primary GID and fsGroup (if specified). If - the SupplementalGroupsPolicy feature is enabled, the - supplementalGroupsPolicy field determines whether these are in addition - to or instead of any group memberships defined in the container image. - If unspecified, no additional groups are added, though group memberships - defined in the container image may still be used, depending on the - supplementalGroupsPolicy field. - Note that this field cannot be set when spec.os.name is windows. - items: - format: int64 - type: integer - type: array - x-kubernetes-list-type: atomic - supplementalGroupsPolicy: - description: |- - Defines how supplemental groups of the first container processes are calculated. - Valid values are "Merge" and "Strict". If not specified, "Merge" is used. - (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled - and the container runtime must implement support for this feature. - Note that this field cannot be set when spec.os.name is windows. - type: string - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - items: - description: Sysctl defines a kernel parameter to be set - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options within a container's SecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of the GMSA - credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - port: - default: 3306 - description: Port where the instances will be listening for connections. - format: int32 - type: integer - primaryConnection: - description: |- - PrimaryConnection defines a template to configure the primary Connection object. - This Connection provides the initial User access to the initial Database. - It will make use of the PrimaryService to route network traffic to the primary Pod. - properties: - healthCheck: - description: HealthCheck to be used in the Connection. - properties: - interval: - description: Interval used to perform health checks. - type: string - retryInterval: - description: RetryInterval is the interval used to perform - health check retries. - type: string - type: object - params: - additionalProperties: - type: string - description: Params to be used in the Connection. - type: object - port: - description: Port to connect to. If not provided, it defaults - to the MariaDB port or to the first MaxScale listener. - format: int32 - type: integer - secretName: - description: SecretName to be used in the Connection. - type: string - secretTemplate: - description: SecretTemplate to be used in the Connection. - properties: - databaseKey: - description: DatabaseKey to be used in the Secret. - type: string - format: - description: Format to be used in the Secret. - type: string - hostKey: - description: HostKey to be used in the Secret. - type: string - key: - description: Key to be used in the Secret. - type: string - metadata: - description: Metadata to be added to the Secret object. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - passwordKey: - description: PasswordKey to be used in the Secret. - type: string - portKey: - description: PortKey to be used in the Secret. - type: string - usernameKey: - description: UsernameKey to be used in the Secret. - type: string - type: object - serviceName: - description: ServiceName to be used in the Connection. - type: string - type: object - primaryService: - description: |- - PrimaryService defines a template to configure the primary Service object. - The network traffic of this Service will be routed to the primary Pod. - properties: - allocateLoadBalancerNodePorts: - description: AllocateLoadBalancerNodePorts Service field. - type: boolean - externalTrafficPolicy: - description: ExternalTrafficPolicy Service field. - type: string - loadBalancerIP: - description: LoadBalancerIP Service field. - type: string - loadBalancerSourceRanges: - description: LoadBalancerSourceRanges Service field. - items: - type: string - type: array - metadata: - description: Metadata to be added to the Service metadata. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - sessionAffinity: - description: SessionAffinity Service field. - type: string - type: - default: ClusterIP - description: Type is the Service type. One of `ClusterIP`, `NodePort` - or `LoadBalancer`. If not defined, it defaults to `ClusterIP`. - enum: - - ClusterIP - - NodePort - - LoadBalancer - type: string - type: object - priorityClassName: - description: PriorityClassName to be used in the Pod. - type: string - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC port. - properties: - port: - description: Port number of the gRPC service. Number must - be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. HTTP allows - repeated headers. - items: - description: HTTPHeader describes a custom header to be - used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a TCP port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - replicas: - default: 1 - description: Replicas indicates the number of desired instances. - format: int32 - type: integer - replicasAllowEvenNumber: - default: false - description: disables the validation check for an odd number of replicas. - type: boolean - replication: - description: Replication configures high availability via replication. - This feature is still in alpha, use Galera if you are looking for - a more production-ready HA. - properties: - enabled: - description: Enabled is a flag to enable Replication. - type: boolean - primary: - description: Primary is the replication configuration for the - primary node. - properties: - automaticFailover: - description: AutomaticFailover indicates whether the operator - should automatically update PodIndex to perform an automatic - primary failover. - type: boolean - podIndex: - description: PodIndex is the StatefulSet index of the primary - node. The user may change this field to perform a manual - switchover. - type: integer - type: object - probesEnabled: - description: |- - ProbesEnabled indicates to use replication specific liveness and readiness probes. - This probes check that the primary can receive queries and that the replica has the replication thread running. - type: boolean - replica: - description: ReplicaReplication is the replication configuration - for the replica nodes. - properties: - connectionRetries: - description: ConnectionRetries to be used when the replica - connects to the primary. - type: integer - connectionTimeout: - description: ConnectionTimeout to be used when the replica - connects to the primary. - type: string - gtid: - description: |- - Gtid indicates which Global Transaction ID should be used when connecting a replica to the master. - See: https://mariadb.com/kb/en/gtid/#using-current_pos-vs-slave_pos. - enum: - - CurrentPos - - SlavePos - type: string - replPasswordSecretKeyRef: - description: ReplPasswordSecretKeyRef provides a reference - to the Secret to use as password for the replication user. - properties: - generate: - default: false - description: Generate indicates whether the Secret should - be generated if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - syncTimeout: - description: |- - SyncTimeout defines the timeout for a replica to be synced with the primary when performing a primary switchover. - If the timeout is reached, the replica GTID will be reset and the switchover will continue. - type: string - waitPoint: - description: |- - WaitPoint defines whether the transaction should wait for ACK before committing to the storage engine. - More info: https://mariadb.com/kb/en/semisynchronous-replication/#rpl_semi_sync_master_wait_point. - enum: - - AfterSync - - AfterCommit - type: string - type: object - syncBinlog: - description: |- - SyncBinlog indicates whether the binary log should be synchronized to the disk after every event. - It trades off performance for consistency. - See: https://mariadb.com/kb/en/replication-and-binary-log-system-variables/#sync_binlog. - type: boolean - type: object - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - rootEmptyPassword: - description: RootEmptyPassword indicates if the root password should - be empty. Don't use this feature in production, it is only intended - for development and test environments. - type: boolean - rootPasswordSecretKeyRef: - description: RootPasswordSecretKeyRef is a reference to a Secret key - containing the root password. - properties: - generate: - default: false - description: Generate indicates whether the Secret should be generated - if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must be a - valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secondaryConnection: - description: |- - SecondaryConnection defines a template to configure the secondary Connection object. - This Connection provides the initial User access to the initial Database. - It will make use of the SecondaryService to route network traffic to the secondary Pods. - properties: - healthCheck: - description: HealthCheck to be used in the Connection. - properties: - interval: - description: Interval used to perform health checks. - type: string - retryInterval: - description: RetryInterval is the interval used to perform - health check retries. - type: string - type: object - params: - additionalProperties: - type: string - description: Params to be used in the Connection. - type: object - port: - description: Port to connect to. If not provided, it defaults - to the MariaDB port or to the first MaxScale listener. - format: int32 - type: integer - secretName: - description: SecretName to be used in the Connection. - type: string - secretTemplate: - description: SecretTemplate to be used in the Connection. - properties: - databaseKey: - description: DatabaseKey to be used in the Secret. - type: string - format: - description: Format to be used in the Secret. - type: string - hostKey: - description: HostKey to be used in the Secret. - type: string - key: - description: Key to be used in the Secret. - type: string - metadata: - description: Metadata to be added to the Secret object. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - passwordKey: - description: PasswordKey to be used in the Secret. - type: string - portKey: - description: PortKey to be used in the Secret. - type: string - usernameKey: - description: UsernameKey to be used in the Secret. - type: string - type: object - serviceName: - description: ServiceName to be used in the Connection. - type: string - type: object - secondaryService: - description: |- - SecondaryService defines a template to configure the secondary Service object. - The network traffic of this Service will be routed to the secondary Pods. - properties: - allocateLoadBalancerNodePorts: - description: AllocateLoadBalancerNodePorts Service field. - type: boolean - externalTrafficPolicy: - description: ExternalTrafficPolicy Service field. - type: string - loadBalancerIP: - description: LoadBalancerIP Service field. - type: string - loadBalancerSourceRanges: - description: LoadBalancerSourceRanges Service field. - items: - type: string - type: array - metadata: - description: Metadata to be added to the Service metadata. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - sessionAffinity: - description: SessionAffinity Service field. - type: string - type: - default: ClusterIP - description: Type is the Service type. One of `ClusterIP`, `NodePort` - or `LoadBalancer`. If not defined, it defaults to `ClusterIP`. - enum: - - ClusterIP - - NodePort - - LoadBalancer - type: string - type: object - securityContext: - description: SecurityContext holds security configuration that will - be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies to - the container. - type: string - role: - description: Role is a SELinux role label that applies to - the container. - type: string - type: - description: Type is a SELinux type label that applies to - the container. - type: string - user: - description: User is a SELinux user label that applies to - the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of the GMSA - credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - service: - description: |- - Service defines a template to configure the general Service object. - The network traffic of this Service will be routed to all Pods. - properties: - allocateLoadBalancerNodePorts: - description: AllocateLoadBalancerNodePorts Service field. - type: boolean - externalTrafficPolicy: - description: ExternalTrafficPolicy Service field. - type: string - loadBalancerIP: - description: LoadBalancerIP Service field. - type: string - loadBalancerSourceRanges: - description: LoadBalancerSourceRanges Service field. - items: - type: string - type: array - metadata: - description: Metadata to be added to the Service metadata. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - sessionAffinity: - description: SessionAffinity Service field. - type: string - type: - default: ClusterIP - description: Type is the Service type. One of `ClusterIP`, `NodePort` - or `LoadBalancer`. If not defined, it defaults to `ClusterIP`. - enum: - - ClusterIP - - NodePort - - LoadBalancer - type: string - type: object - serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to be used by the Pods. - type: string - sidecarContainers: - description: SidecarContainers to be used in the Pod. - items: - description: Container object definition. - properties: - args: - description: Args to be used in the Container. - items: - type: string - type: array - command: - description: Command to be used in the Container. - items: - type: string - type: array - env: - description: Env represents the environment variables to be - injected in a container. - items: - description: EnvVar represents an environment variable present - in a Container. - properties: - name: - description: Name of the environment variable. Must be - a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. - Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the - specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the - exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's - namespace - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via ConfigMap - and Secrets) to environment variables to be injected in the - container. - items: - description: EnvFromSource represents the source of a set - of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be - defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: Image name to be used by the MariaDB instances. - The supported format is `:`. - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. One of - `Always`, `Never` or `IfNotPresent`. If not defined, it defaults - to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. HTTP - allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a TCP - port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. HTTP - allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a TCP - port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration that - will be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies - to the container. - type: string - role: - description: Role is a SELinux role label that applies - to the container. - type: string - type: - description: Type is a SELinux type label that applies - to the container. - type: string - user: - description: User is a SELinux user label that applies - to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of the - GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting of a Volume - within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - required: - - image - type: object - type: array - storage: - description: Storage defines the storage options to be used for provisioning - the PVCs mounted by MariaDB. - properties: - ephemeral: - description: Ephemeral indicates whether to use ephemeral storage - in the PVCs. It is only compatible with non HA MariaDBs. - type: boolean - resizeInUseVolumes: - description: |- - ResizeInUseVolumes indicates whether the PVCs can be resized. The 'StorageClassName' used should have 'allowVolumeExpansion' set to 'true' to allow resizing. - It defaults to true. - type: boolean - size: - anyOf: - - type: integer - - type: string - description: Size of the PVCs to be mounted by MariaDB. Required - if not provided in 'VolumeClaimTemplate'. It superseeds the - storage size specified in 'VolumeClaimTemplate'. - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - storageClassName: - description: |- - StorageClassName to be used to provision the PVCS. It superseeds the 'StorageClassName' specified in 'VolumeClaimTemplate'. - If not provided, the default 'StorageClass' configured in the cluster is used. - type: string - volumeClaimTemplate: - description: VolumeClaimTemplate provides a template to define - the PVCs. - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - metadata: - description: Metadata to be added to the PVC metadata. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes to consider - for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to the PersistentVolume - backing this claim. - type: string - type: object - waitForVolumeResize: - description: |- - WaitForVolumeResize indicates whether to wait for the PVCs to be resized before marking the MariaDB object as ready. This will block other operations such as cluster recovery while the resize is in progress. - It defaults to true. - type: boolean - type: object - suspend: - default: false - description: |- - Suspend indicates whether the current resource should be suspended or not. - This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. - type: boolean - timeZone: - description: TimeZone sets the default timezone. If not provided, - it defaults to SYSTEM and the timezone data is not loaded. - type: string - tolerations: - description: Tolerations to be used in the Pod. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - topologySpreadConstraints: - description: TopologySpreadConstraints to be used in the Pod. - items: - description: TopologySpreadConstraint specifies how to spread matching - pods among the given topology. - properties: - labelSelector: - description: |- - LabelSelector is used to find matching pods. - Pods that match this label selector are counted to determine the number of pods - in their corresponding topology domain. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select the pods over which - spreading will be calculated. The keys are used to lookup values from the - incoming pod labels, those key-value labels are ANDed with labelSelector - to select the group of existing pods over which spreading will be calculated - for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. - MatchLabelKeys cannot be set when LabelSelector isn't set. - Keys that don't exist in the incoming pod labels will - be ignored. A null or empty list means only match against labelSelector. - - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). - items: - type: string - type: array - x-kubernetes-list-type: atomic - maxSkew: - description: |- - MaxSkew describes the degree to which pods may be unevenly distributed. - When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference - between the number of matching pods in the target topology and the global minimum. - The global minimum is the minimum number of matching pods in an eligible domain - or zero if the number of eligible domains is less than MinDomains. - For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same - labelSelector spread as 2/2/1: - In this case, the global minimum is 1. - | zone1 | zone2 | zone3 | - | P P | P P | P | - - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; - scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) - violate MaxSkew(1). - - if MaxSkew is 2, incoming pod can be scheduled onto any zone. - When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence - to topologies that satisfy it. - It's a required field. Default value is 1 and 0 is not allowed. - format: int32 - type: integer - minDomains: - description: |- - MinDomains indicates a minimum number of eligible domains. - When the number of eligible domains with matching topology keys is less than minDomains, - Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. - And when the number of eligible domains with matching topology keys equals or greater than minDomains, - this value has no effect on scheduling. - As a result, when the number of eligible domains is less than minDomains, - scheduler won't schedule more than maxSkew Pods to those domains. - If value is nil, the constraint behaves as if MinDomains is equal to 1. - Valid values are integers greater than 0. - When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same - labelSelector spread as 2/2/2: - | zone1 | zone2 | zone3 | - | P P | P P | P P | - The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. - In this situation, new pod with the same labelSelector cannot be scheduled, - because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, - it will violate MaxSkew. - format: int32 - type: integer - nodeAffinityPolicy: - description: |- - NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector - when calculating pod topology spread skew. Options are: - - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - - 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: |- - NodeTaintsPolicy indicates how we will treat node taints when calculating - pod topology spread skew. Options are: - - Honor: nodes without taints, along with tainted nodes for which the incoming pod - has a toleration, are included. - - 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: |- - TopologyKey is the key of node labels. Nodes that have a label with this key - and identical values are considered to be in the same topology. - We consider each as a "bucket", and try to put balanced number - of pods into each bucket. - We define a domain as a particular instance of a topology. - Also, we define an eligible domain as a domain whose nodes meet the requirements of - nodeAffinityPolicy and nodeTaintsPolicy. - e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. - And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. - It's a required field. - type: string - whenUnsatisfiable: - description: |- - WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy - the spread constraint. - - DoNotSchedule (default) tells the scheduler not to schedule it. - - ScheduleAnyway tells the scheduler to schedule the pod in any location, - but giving higher precedence to topologies that would help reduce the - skew. - A constraint is considered "Unsatisfiable" for an incoming pod - if and only if every possible node assignment for that pod would violate - "MaxSkew" on some topology. - For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same - labelSelector spread as 3/1/1: - | zone1 | zone2 | zone3 | - | P P P | P | P | - If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled - to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies - MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler - won't make it *more* imbalanced. - It's a required field. - type: string - required: - - maxSkew - - topologyKey - - whenUnsatisfiable - type: object - type: array - updateStrategy: - description: UpdateStrategy defines how a MariaDB resource is updated. - properties: - rollingUpdate: - description: RollingUpdate defines parameters for the RollingUpdate - type. - properties: - maxUnavailable: - anyOf: - - type: integer - - type: string - description: |- - The maximum number of pods that can be unavailable during the update. - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). - Absolute number is calculated from percentage by rounding up. This can not be 0. - Defaults to 1. This field is alpha-level and is only honored by servers that enable the - MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to - Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it - will be counted towards MaxUnavailable. - x-kubernetes-int-or-string: true - partition: - description: |- - Partition indicates the ordinal at which the StatefulSet should be partitioned - for updates. During a rolling update, all pods from ordinal Replicas-1 to - Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. - This is helpful in being able to do a canary based deployment. The default value is 0. - format: int32 - type: integer - type: object - type: - default: ReplicasFirstPrimaryLast - description: Type defines the type of updates. One of `ReplicasFirstPrimaryLast`, - `RollingUpdate` or `OnDelete`. If not defined, it defaults to - `ReplicasFirstPrimaryLast`. - enum: - - ReplicasFirstPrimaryLast - - RollingUpdate - - OnDelete - type: string - type: object - username: - description: |- - Username is the initial username to be created by the operator once MariaDB is ready. It has all privileges on the initial database. - The initial User will have ALL PRIVILEGES in the initial Database. - type: string - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting of a Volume within - a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - volumes: - description: Volumes to be used in the Pod. - items: - description: Volume represents a named volume in a pod that may - be accessed by any container in the pod. - properties: - awsElasticBlockStore: - description: |- - awsElasticBlockStore represents an AWS Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - format: int32 - type: integer - readOnly: - description: |- - readOnly value true will force the readOnly setting in VolumeMounts. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: boolean - volumeID: - description: |- - volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - required: - - volumeID - type: object - azureDisk: - description: azureDisk represents an Azure Data Disk mount on - the host and bind mount to the pod. - properties: - cachingMode: - description: 'cachingMode is the Host Caching mode: None, - Read Only, Read Write.' - type: string - diskName: - description: diskName is the Name of the data disk in the - blob storage - type: string - diskURI: - description: diskURI is the URI of data disk in the blob - storage - type: string - fsType: - default: ext4 - description: |- - fsType is Filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - kind: - description: 'kind expected values are Shared: multiple - blob disks per storage account Dedicated: single blob - disk per storage account Managed: azure managed data - disk (only in managed availability set). defaults to shared' - type: string - readOnly: - default: false - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - required: - - diskName - - diskURI - type: object - azureFile: - description: azureFile represents an Azure File Service mount - on the host and bind mount to the pod. - properties: - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretName: - description: secretName is the name of secret that contains - Azure Storage Account Name and Key - type: string - shareName: - description: shareName is the azure share Name - type: string - required: - - secretName - - shareName - type: object - cephfs: - description: cephFS represents a Ceph FS mount on the host that - shares a pod's lifetime - properties: - monitors: - description: |- - monitors is Required: Monitors is a collection of Ceph monitors - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - path: - description: 'path is Optional: Used as the mounted root, - rather than the full Ceph tree, default is /' - type: string - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: boolean - secretFile: - description: |- - secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - secretRef: - description: |- - secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - description: |- - user is optional: User is the rados user name, default is admin - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - required: - - monitors - type: object - cinder: - description: |- - cinder represents a cinder volume attached and mounted on kubelets host machine. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: boolean - secretRef: - description: |- - secretRef is optional: points to a secret object containing parameters used to connect - to OpenStack. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeID: - description: |- - volumeID used to identify the volume in cinder. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - required: - - volumeID - type: object - configMap: - description: configMap represents a configMap that should populate - this volume - properties: - defaultMode: - description: |- - defaultMode is optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether the ConfigMap or its - keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - csi: - description: csi (Container Storage Interface) represents ephemeral - storage that is handled by certain external CSI drivers (Beta - feature). - properties: - driver: - description: |- - driver is the name of the CSI driver that handles this volume. - Consult with your admin for the correct name as registered in the cluster. - type: string - fsType: - description: |- - fsType to mount. Ex. "ext4", "xfs", "ntfs". - If not provided, the empty value is passed to the associated CSI driver - which will determine the default filesystem to apply. - type: string - nodePublishSecretRef: - description: |- - nodePublishSecretRef is a reference to the secret object containing - sensitive information to pass to the CSI driver to complete the CSI - NodePublishVolume and NodeUnpublishVolume calls. - This field is optional, and may be empty if no secret is required. If the - secret object contains more than one secret, all secret references are passed. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - readOnly: - description: |- - readOnly specifies a read-only configuration for the volume. - Defaults to false (read/write). - type: boolean - volumeAttributes: - additionalProperties: - type: string - description: |- - volumeAttributes stores driver-specific properties that are passed to the CSI - driver. Consult your driver's documentation for supported values. - type: object - required: - - driver - type: object - downwardAPI: - description: downwardAPI represents downward API about the pod - that should populate this volume - properties: - defaultMode: - description: |- - Optional: mode bits to use on created files by default. Must be a - Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: Items is a list of downward API volume file - items: - description: DownwardAPIVolumeFile represents information - to create the file containing the pod field - properties: - fieldRef: - description: 'Required: Selects a field of the pod: - only annotations, labels, name, namespace and uid - are supported.' - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the - specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path is the relative path - name of the file to be created. Must not be absolute - or contain the ''..'' path. Must be utf-8 encoded. - The first item of the relative path must not start - with ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the - exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - emptyDir: - description: |- - emptyDir represents a temporary directory that shares a pod's lifetime. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - properties: - medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - ephemeral: - description: |- - ephemeral represents a volume that is handled by a cluster storage driver. - The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, - and deleted when the pod is removed. - - Use this if: - a) the volume is only needed while the pod runs, - b) features of normal volumes like restoring from snapshot or capacity - tracking are needed, - c) the storage driver is specified through a storage class, and - d) the storage driver supports dynamic volume provisioning through - a PersistentVolumeClaim (see EphemeralVolumeSource for more - information on the connection between this volume type - and PersistentVolumeClaim). - - Use PersistentVolumeClaim or one of the vendor-specific - APIs for volumes that persist for longer than the lifecycle - of an individual pod. - - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to - be used that way - see the documentation of the driver for - more information. - - A pod can use both types of ephemeral volumes and - persistent volumes at the same time. - properties: - volumeClaimTemplate: - description: |- - Will be used to create a stand-alone PVC to provision the volume. - The pod in which this EphemeralVolumeSource is embedded will be the - owner of the PVC, i.e. the PVC will be deleted together with the - pod. The name of the PVC will be `-` where - `` is the name from the `PodSpec.Volumes` array - entry. Pod validation will reject the pod if the concatenated name - is not valid for a PVC (for example, too long). - - An existing PVC with that name that is not owned by the pod - will *not* be used for the pod to avoid using an unrelated - volume by mistake. Starting the pod is then blocked until - the unrelated PVC is removed. If such a pre-created PVC is - meant to be used by the pod, the PVC has to updated with an - owner reference to the pod once the pod exists. Normally - this should not be necessary, but it may be useful when - manually reconstructing a broken cluster. - - This field is read-only and no changes will be made by Kubernetes - to the PVC after it has been created. - - Required, must not be nil. - properties: - metadata: - description: |- - May contain labels and annotations that will be copied into the PVC - when creating it. No other fields are allowed and will be rejected during - validation. - type: object - spec: - description: |- - The specification for the PersistentVolumeClaim. The entire content is - copied unchanged into the PVC that gets created from this - template. The same fields as in a PersistentVolumeClaim - are also valid here. - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes - to consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference - to the PersistentVolume backing this claim. - type: string - type: object - required: - - spec - type: object - type: object - fc: - description: fc represents a Fibre Channel resource that is - attached to a kubelet's host machine and then exposed to the - pod. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - lun: - description: 'lun is Optional: FC target lun number' - format: int32 - type: integer - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - targetWWNs: - description: 'targetWWNs is Optional: FC target worldwide - names (WWNs)' - items: - type: string - type: array - x-kubernetes-list-type: atomic - wwids: - description: |- - wwids Optional: FC volume world wide identifiers (wwids) - Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - flexVolume: - description: |- - flexVolume represents a generic volume resource that is - provisioned/attached using an exec based plugin. - properties: - driver: - description: driver is the name of the driver to use for - this volume. - type: string - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. - type: string - options: - additionalProperties: - type: string - description: 'options is Optional: this field holds extra - command options if any.' - type: object - readOnly: - description: |- - readOnly is Optional: defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef is Optional: secretRef is reference to the secret object containing - sensitive information to pass to the plugin scripts. This may be - empty if no secret object is specified. If the secret object - contains more than one secret, all secrets are passed to the plugin - scripts. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - required: - - driver - type: object - flocker: - description: flocker represents a Flocker volume attached to - a kubelet's host machine. This depends on the Flocker control - service being running - properties: - datasetName: - description: |- - datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker - should be considered as deprecated - type: string - datasetUUID: - description: datasetUUID is the UUID of the dataset. This - is unique identifier of a Flocker dataset - type: string - type: object - gcePersistentDisk: - description: |- - gcePersistentDisk represents a GCE Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - properties: - fsType: - description: |- - fsType is filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - format: int32 - type: integer - pdName: - description: |- - pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: boolean - required: - - pdName - type: object - gitRepo: - description: |- - gitRepo represents a git repository at a particular revision. - DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an - EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir - into the Pod's container. - properties: - directory: - description: |- - directory is the target directory name. - Must not contain or start with '..'. If '.' is supplied, the volume directory will be the - git repository. Otherwise, if specified, the volume will contain the git repository in - the subdirectory with the given name. - type: string - repository: - description: repository is the URL - type: string - revision: - description: revision is the commit hash for the specified - revision. - type: string - required: - - repository - type: object - glusterfs: - description: |- - glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/glusterfs/README.md - properties: - endpoints: - description: |- - endpoints is the endpoint name that details Glusterfs topology. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - path: - description: |- - path is the Glusterfs volume path. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - readOnly: - description: |- - readOnly here will force the Glusterfs volume to be mounted with read-only permissions. - Defaults to false. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: boolean - required: - - endpoints - - path - type: object - hostPath: - description: |- - hostPath represents a pre-existing file or directory on the host - machine that is directly exposed to the container. This is generally - used for system agents or other privileged things that are allowed - to see the host machine. Most containers will NOT need this. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - properties: - path: - description: |- - path of the directory on the host. - If the path is a symlink, it will follow the link to the real path. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - type: - description: |- - type for HostPath Volume - Defaults to "" - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - required: - - path - type: object - image: - description: |- - image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. - The volume is resolved at pod startup depending on which PullPolicy value is provided: - - - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - - The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. - A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. - 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). - The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. - properties: - pullPolicy: - description: |- - Policy for pulling OCI objects. Possible values are: - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. - type: string - reference: - description: |- - Required: Image or artifact reference to be used. - Behaves in the same way as pod.spec.containers[*].image. - Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. - More info: https://kubernetes.io/docs/concepts/containers/images - This field is optional to allow higher level config management to default or override - container images in workload controllers like Deployments and StatefulSets. - type: string - type: object - iscsi: - description: |- - iscsi represents an ISCSI Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://examples.k8s.io/volumes/iscsi/README.md - properties: - chapAuthDiscovery: - description: chapAuthDiscovery defines whether support iSCSI - Discovery CHAP authentication - type: boolean - chapAuthSession: - description: chapAuthSession defines whether support iSCSI - Session CHAP authentication - type: boolean - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - type: string - initiatorName: - description: |- - initiatorName is the custom iSCSI Initiator Name. - If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface - : will be created for the connection. - type: string - iqn: - description: iqn is the target iSCSI Qualified Name. - type: string - iscsiInterface: - default: default - description: |- - iscsiInterface is the interface Name that uses an iSCSI transport. - Defaults to 'default' (tcp). - type: string - lun: - description: lun represents iSCSI Target Lun number. - format: int32 - type: integer - portals: - description: |- - portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - items: - type: string - type: array - x-kubernetes-list-type: atomic - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - type: boolean - secretRef: - description: secretRef is the CHAP Secret for iSCSI target - and initiator authentication - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - targetPortal: - description: |- - targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - type: string - required: - - iqn - - lun - - targetPortal - type: object - name: - description: |- - name of the volume. - Must be a DNS_LABEL and unique within the pod. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - nfs: - description: |- - nfs represents an NFS mount on the host that shares a pod's lifetime - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - properties: - path: - description: |- - path that is exported by the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - readOnly: - description: |- - readOnly here will force the NFS export to be mounted with read-only permissions. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: boolean - server: - description: |- - server is the hostname or IP address of the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - required: - - path - - server - type: object - persistentVolumeClaim: - description: |- - persistentVolumeClaimVolumeSource represents a reference to a - PersistentVolumeClaim in the same namespace. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - claimName: - description: |- - claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - type: string - readOnly: - description: |- - readOnly Will force the ReadOnly setting in VolumeMounts. - Default false. - type: boolean - required: - - claimName - type: object - photonPersistentDisk: - description: photonPersistentDisk represents a PhotonController - persistent disk attached and mounted on kubelets host machine - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - pdID: - description: pdID is the ID that identifies Photon Controller - persistent disk - type: string - required: - - pdID - type: object - portworxVolume: - description: portworxVolume represents a portworx volume attached - and mounted on kubelets host machine - properties: - fsType: - description: |- - fSType represents the filesystem type to mount - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - volumeID: - description: volumeID uniquely identifies a Portworx volume - type: string - required: - - volumeID - type: object - projected: - description: projected items for all in one resources secrets, - configmaps, and downward API - properties: - defaultMode: - description: |- - defaultMode are the mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - sources: - description: |- - sources is the list of volume projections. Each entry in this list - handles one source. - items: - description: |- - Projection that may be projected along with other supported volume types. - Exactly one of these fields must be set. - properties: - clusterTrustBundle: - description: |- - ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field - of ClusterTrustBundle objects in an auto-updating file. - - Alpha, gated by the ClusterTrustBundleProjection feature gate. - - ClusterTrustBundle objects can either be selected by name, or by the - combination of signer name and a label selector. - - Kubelet performs aggressive normalization of the PEM contents written - into the pod filesystem. Esoteric PEM features such as inter-block - comments and block headers are stripped. Certificates are deduplicated. - The ordering of certificates within the file is arbitrary, and Kubelet - may change the order over time. - properties: - labelSelector: - description: |- - Select all ClusterTrustBundles that match this label selector. Only has - effect if signerName is set. Mutually-exclusive with name. If unset, - interpreted as "match nothing". If set but empty, interpreted as "match - everything". - 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 - name: - description: |- - Select a single ClusterTrustBundle by object name. Mutually-exclusive - with signerName and labelSelector. - type: string - optional: - description: |- - If true, don't block pod startup if the referenced ClusterTrustBundle(s) - aren't available. If using name, then the named ClusterTrustBundle is - allowed not to exist. If using signerName, then the combination of - signerName and labelSelector is allowed to match zero - ClusterTrustBundles. - type: boolean - path: - description: Relative path from the volume root - to write the bundle. - type: string - signerName: - description: |- - Select all ClusterTrustBundles that match this signer name. - Mutually-exclusive with name. The contents of all selected - ClusterTrustBundles will be unified and deduplicated. - type: string - required: - - path - type: object - configMap: - description: configMap information about the configMap - data to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether the ConfigMap - or its keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - downwardAPI: - description: downwardAPI information about the downwardAPI - data to project - properties: - items: - description: Items is a list of DownwardAPIVolume - file - items: - description: DownwardAPIVolumeFile represents - information to create the file containing - the pod field - properties: - fieldRef: - description: 'Required: Selects a field - of the pod: only annotations, labels, - name, namespace and uid are supported.' - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, - defaults to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path is the relative - path name of the file to be created. Must - not be absolute or contain the ''..'' - path. Must be utf-8 encoded. The first - item of the relative path must not start - with ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults - to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to - select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - secret: - description: secret information about the secret data - to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional field specify whether the - Secret or its key must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - serviceAccountToken: - description: serviceAccountToken is information about - the serviceAccountToken data to project - properties: - audience: - description: |- - audience is the intended audience of the token. A recipient of a token - must identify itself with an identifier specified in the audience of the - token, and otherwise should reject the token. The audience defaults to the - identifier of the apiserver. - type: string - expirationSeconds: - description: |- - expirationSeconds is the requested duration of validity of the service - account token. As the token approaches expiration, the kubelet volume - plugin will proactively rotate the service account token. The kubelet will - start trying to rotate the token if the token is older than 80 percent of - its time to live or if the token is older than 24 hours.Defaults to 1 hour - and must be at least 10 minutes. - format: int64 - type: integer - path: - description: |- - path is the path relative to the mount point of the file to project the - token into. - type: string - required: - - path - type: object - type: object - type: array - x-kubernetes-list-type: atomic - type: object - quobyte: - description: quobyte represents a Quobyte mount on the host - that shares a pod's lifetime - properties: - group: - description: |- - group to map volume access to - Default is no group - type: string - readOnly: - description: |- - readOnly here will force the Quobyte volume to be mounted with read-only permissions. - Defaults to false. - type: boolean - registry: - description: |- - registry represents a single or multiple Quobyte Registry services - specified as a string as host:port pair (multiple entries are separated with commas) - which acts as the central registry for volumes - type: string - tenant: - description: |- - tenant owning the given Quobyte volume in the Backend - Used with dynamically provisioned Quobyte volumes, value is set by the plugin - type: string - user: - description: |- - user to map volume access to - Defaults to serivceaccount user - type: string - volume: - description: volume is a string that references an already - created Quobyte volume by name. - type: string - required: - - registry - - volume - type: object - rbd: - description: |- - rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/rbd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - type: string - image: - description: |- - image is the rados image name. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - keyring: - default: /etc/ceph/keyring - description: |- - keyring is the path to key ring for RBDUser. - Default is /etc/ceph/keyring. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - monitors: - description: |- - monitors is a collection of Ceph monitors. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - pool: - default: rbd - description: |- - pool is the rados pool name. - Default is rbd. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: boolean - secretRef: - description: |- - secretRef is name of the authentication secret for RBDUser. If provided - overrides keyring. - Default is nil. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - default: admin - description: |- - user is the rados user name. - Default is admin. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - required: - - image - - monitors - type: object - scaleIO: - description: scaleIO represents a ScaleIO persistent volume - attached and mounted on Kubernetes nodes. - properties: - fsType: - default: xfs - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". - Default is "xfs". - type: string - gateway: - description: gateway is the host address of the ScaleIO - API Gateway. - type: string - protectionDomain: - description: protectionDomain is the name of the ScaleIO - Protection Domain for the configured storage. - type: string - readOnly: - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef references to the secret for ScaleIO user and other - sensitive information. If this is not provided, Login operation will fail. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - sslEnabled: - description: sslEnabled Flag enable/disable SSL communication - with Gateway, default false - type: boolean - storageMode: - default: ThinProvisioned - description: |- - storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. - Default is ThinProvisioned. - type: string - storagePool: - description: storagePool is the ScaleIO Storage Pool associated - with the protection domain. - type: string - system: - description: system is the name of the storage system as - configured in ScaleIO. - type: string - volumeName: - description: |- - volumeName is the name of a volume already created in the ScaleIO system - that is associated with this volume source. - type: string - required: - - gateway - - secretRef - - system - type: object - secret: - description: |- - secret represents a secret that should populate this volume. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - properties: - defaultMode: - description: |- - defaultMode is Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values - for mode bits. Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items If unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - optional: - description: optional field specify whether the Secret or - its keys must be defined - type: boolean - secretName: - description: |- - secretName is the name of the secret in the pod's namespace to use. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - type: string - type: object - storageos: - description: storageOS represents a StorageOS volume attached - and mounted on Kubernetes nodes. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef specifies the secret to use for obtaining the StorageOS API - credentials. If not specified, default values will be attempted. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeName: - description: |- - volumeName is the human-readable name of the StorageOS volume. Volume - names are only unique within a namespace. - type: string - volumeNamespace: - description: |- - volumeNamespace specifies the scope of the volume within StorageOS. If no - namespace is specified then the Pod's namespace will be used. This allows the - Kubernetes name scoping to be mirrored within StorageOS for tighter integration. - Set VolumeName to any name to override the default behaviour. - Set to "default" if you are not using namespaces within StorageOS. - Namespaces that do not pre-exist within StorageOS will be created. - type: string - type: object - vsphereVolume: - description: vsphereVolume represents a vSphere volume attached - and mounted on kubelets host machine - properties: - fsType: - description: |- - fsType is filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - storagePolicyID: - description: storagePolicyID is the storage Policy Based - Management (SPBM) profile ID associated with the StoragePolicyName. - type: string - storagePolicyName: - description: storagePolicyName is the storage Policy Based - Management (SPBM) profile name. - type: string - volumePath: - description: volumePath is the path that identifies vSphere - volume vmdk - type: string - required: - - volumePath - type: object - required: - - name - type: object - type: array - type: object - x-kubernetes-validations: - - message: 'An odd number of MariaDB instances (mariadb.spec.replicas) - is required to avoid split brain situations. Use ''mariadb.spec.replicasAllowEvenNumber: - true'' to disable this validation.' - rule: self.replicas %2 == 1 || self.replicasAllowEvenNumber - status: - description: MariaDBStatus defines the observed state of MariaDB - properties: - conditions: - description: Conditions for the Mariadb object. - 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 - type: array - currentPrimary: - description: CurrentPrimary is the primary Pod. - type: string - currentPrimaryPodIndex: - description: CurrentPrimaryPodIndex is the primary Pod index. - type: integer - galeraRecovery: - description: GaleraRecovery is the Galera recovery current state. - properties: - bootstrap: - description: Bootstrap indicates when and in which Pod the cluster - bootstrap process has been performed. - properties: - pod: - type: string - time: - format: date-time - type: string - type: object - podsRestarted: - description: PodsRestarted that the Pods have been restarted after - the cluster bootstrap. - type: boolean - recovered: - additionalProperties: - properties: - seqno: - type: integer - uuid: - type: string - required: - - seqno - - uuid - type: object - description: State is a per Pod representation of the sequence - recovery process. - type: object - state: - additionalProperties: - properties: - safeToBootstrap: - type: boolean - seqno: - type: integer - uuid: - type: string - version: - type: string - required: - - safeToBootstrap - - seqno - - uuid - - version - type: object - description: State is a per Pod representation of the Galera state - file (grastate.dat). - type: object - type: object - replicas: - description: Replicas indicates the number of current instances. - format: int32 - type: integer - replicationStatus: - additionalProperties: - type: string - description: ReplicationStatus is the replication current state for - each Pod. - type: object - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - scale: - specReplicasPath: .spec.replicas - statusReplicasPath: .status.replicas - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: maxscales.k8s.mariadb.com -spec: - group: k8s.mariadb.com - names: - kind: MaxScale - listKind: MaxScaleList - plural: maxscales - shortNames: - - mxs - singular: maxscale - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - type: string - - jsonPath: .status.primaryServer - name: Primary Server - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: MaxScale is the Schema for the maxscales API. It is used to define - MaxScale clusters. - 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: MaxScaleSpec defines the desired state of MaxScale. - properties: - admin: - description: Admin configures the admin REST API and GUI. - properties: - guiEnabled: - description: GuiEnabled indicates whether the admin GUI should - be enabled. - type: boolean - port: - description: Port where the admin REST API and GUI will be exposed. - format: int32 - type: integer - type: object - affinity: - description: Affinity to be used in the Pod. - properties: - antiAffinityEnabled: - description: |- - AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. - Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. - type: boolean - nodeAffinity: - description: Describes node affinity scheduling rules for the - pod. - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - properties: - preference: - description: A node selector term, associated with the - corresponding weight. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding - nodeSelectorTerm, in the range 1-100. - format: int32 - type: integer - required: - - preference - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. - The terms are ORed. - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - type: array - x-kubernetes-list-type: atomic - required: - - nodeSelectorTerms - type: object - x-kubernetes-map-type: atomic - type: object - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate - this pod in the same node, zone, etc. as some other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated - with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. - avoid putting this pod in the same node, zone, etc. as some - other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated - with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - type: object - args: - description: Args to be used in the Container. - items: - type: string - type: array - auth: - description: Auth defines the credentials required for MaxScale to - connect to MariaDB. - properties: - adminPasswordSecretKeyRef: - description: AdminPasswordSecretKeyRef is Secret key reference - to the admin password to call the admin REST API. It is defaulted - if not provided. - properties: - generate: - default: false - description: Generate indicates whether the Secret should - be generated if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - adminUsername: - description: AdminUsername is an admin username to call the admin - REST API. It is defaulted if not provided. - type: string - clientMaxConnections: - description: |- - ClientMaxConnections defines the maximum number of connections that the client can establish. - If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. - It defaults to 30 times the number of MaxScale replicas. - format: int32 - type: integer - clientPasswordSecretKeyRef: - description: |- - ClientPasswordSecretKeyRef is Secret key reference to the password to connect to MaxScale. It is defaulted if not provided. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. - properties: - generate: - default: false - description: Generate indicates whether the Secret should - be generated if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - clientUsername: - description: ClientUsername is the user to connect to MaxScale. - It is defaulted if not provided. - type: string - deleteDefaultAdmin: - description: DeleteDefaultAdmin determines whether the default - admin user should be deleted after the initial configuration. - If not provided, it defaults to true. - type: boolean - generate: - description: |- - Generate defies whether the operator should generate users and grants for MaxScale to work. - It only supports MariaDBs specified via spec.mariaDbRef. - type: boolean - metricsPasswordSecretKeyRef: - description: |- - MetricsPasswordSecretKeyRef is Secret key reference to the metrics password to call the admib REST API. It is defaulted if metrics are enabled. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. - properties: - generate: - default: false - description: Generate indicates whether the Secret should - be generated if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - metricsUsername: - description: MetricsUsername is an metrics username to call the - REST API. It is defaulted if metrics are enabled. - type: string - monitorMaxConnections: - description: |- - MonitorMaxConnections defines the maximum number of connections that the monitor can establish. - If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. - It defaults to 30 times the number of MaxScale replicas. - format: int32 - type: integer - monitorPasswordSecretKeyRef: - description: |- - MonitorPasswordSecretKeyRef is Secret key reference to the password used by MaxScale monitor to connect to MariaDB server. It is defaulted if not provided. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. - properties: - generate: - default: false - description: Generate indicates whether the Secret should - be generated if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - monitorUsername: - description: MonitorUsername is the user used by MaxScale monitor - to connect to MariaDB server. It is defaulted if not provided. - type: string - serverMaxConnections: - description: |- - ServerMaxConnections defines the maximum number of connections that the server can establish. - If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. - It defaults to 30 times the number of MaxScale replicas. - format: int32 - type: integer - serverPasswordSecretKeyRef: - description: |- - ServerPasswordSecretKeyRef is Secret key reference to the password used by MaxScale to connect to MariaDB server. It is defaulted if not provided. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. - properties: - generate: - default: false - description: Generate indicates whether the Secret should - be generated if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverUsername: - description: ServerUsername is the user used by MaxScale to connect - to MariaDB server. It is defaulted if not provided. - type: string - syncMaxConnections: - description: |- - SyncMaxConnections defines the maximum number of connections that the sync can establish. - If HA is enabled, make sure to increase this value, as more MaxScale replicas implies more connections. - It defaults to 30 times the number of MaxScale replicas. - format: int32 - type: integer - syncPasswordSecretKeyRef: - description: |- - SyncPasswordSecretKeyRef is Secret key reference to the password used by MaxScale config to connect to MariaDB server. It is defaulted when HA is enabled. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. - properties: - generate: - default: false - description: Generate indicates whether the Secret should - be generated if the Secret referenced is not present. - type: boolean - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - syncUsername: - description: MonitoSyncUsernamerUsername is the user used by MaxScale - config sync to connect to MariaDB server. It is defaulted when - HA is enabled. - type: string - type: object - command: - description: Command to be used in the Container. - items: - type: string - type: array - config: - description: Config defines the MaxScale configuration. - properties: - params: - additionalProperties: - type: string - description: |- - Params is a key value pair of parameters to be used in the MaxScale static configuration file. - Any parameter supported by MaxScale may be specified here. See reference: - https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#global-settings. - type: object - sync: - description: Sync defines how to replicate configuration across - MaxScale replicas. It is defaulted when HA is enabled. - properties: - database: - description: Database is the MariaDB logical database where - the 'maxscale_config' table will be created in order to - persist and synchronize config changes. If not provided, - it defaults to 'mysql'. - type: string - interval: - description: Interval defines the config synchronization interval. - It is defaulted if not provided. - type: string - timeout: - description: Interval defines the config synchronization timeout. - It is defaulted if not provided. - type: string - type: object - volumeClaimTemplate: - description: VolumeClaimTemplate provides a template to define - the PVCs for storing MaxScale runtime configuration files. It - is defaulted if not provided. - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - metadata: - description: Metadata to be added to the PVC metadata. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes to consider - for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to the PersistentVolume - backing this claim. - type: string - type: object - type: object - connection: - description: Connection provides a template to define the Connection - for MaxScale. - properties: - healthCheck: - description: HealthCheck to be used in the Connection. - properties: - interval: - description: Interval used to perform health checks. - type: string - retryInterval: - description: RetryInterval is the interval used to perform - health check retries. - type: string - type: object - params: - additionalProperties: - type: string - description: Params to be used in the Connection. - type: object - port: - description: Port to connect to. If not provided, it defaults - to the MariaDB port or to the first MaxScale listener. - format: int32 - type: integer - secretName: - description: SecretName to be used in the Connection. - type: string - secretTemplate: - description: SecretTemplate to be used in the Connection. - properties: - databaseKey: - description: DatabaseKey to be used in the Secret. - type: string - format: - description: Format to be used in the Secret. - type: string - hostKey: - description: HostKey to be used in the Secret. - type: string - key: - description: Key to be used in the Secret. - type: string - metadata: - description: Metadata to be added to the Secret object. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - passwordKey: - description: PasswordKey to be used in the Secret. - type: string - portKey: - description: PortKey to be used in the Secret. - type: string - usernameKey: - description: UsernameKey to be used in the Secret. - type: string - type: object - serviceName: - description: ServiceName to be used in the Connection. - type: string - type: object - env: - description: Env represents the environment variables to be injected - in a container. - items: - description: EnvVar represents an environment variable present in - a Container. - properties: - name: - description: Name of the environment variable. Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. Cannot - be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath is - written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the specified - API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the exposed - resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's namespace - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via ConfigMap and - Secrets) to environment variables to be injected in the container. - items: - description: EnvFromSource represents the source of a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - guiKubernetesService: - description: GuiKubernetesService defines a template for a Kubernetes - Service object to connect to MaxScale's GUI. - properties: - allocateLoadBalancerNodePorts: - description: AllocateLoadBalancerNodePorts Service field. - type: boolean - externalTrafficPolicy: - description: ExternalTrafficPolicy Service field. - type: string - loadBalancerIP: - description: LoadBalancerIP Service field. - type: string - loadBalancerSourceRanges: - description: LoadBalancerSourceRanges Service field. - items: - type: string - type: array - metadata: - description: Metadata to be added to the Service metadata. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - sessionAffinity: - description: SessionAffinity Service field. - type: string - type: - default: ClusterIP - description: Type is the Service type. One of `ClusterIP`, `NodePort` - or `LoadBalancer`. If not defined, it defaults to `ClusterIP`. - enum: - - ClusterIP - - NodePort - - LoadBalancer - type: string - type: object - image: - description: |- - Image name to be used by the MaxScale instances. The supported format is `:`. - Only MaxScale official images are supported. - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. One of `Always`, - `Never` or `IfNotPresent`. If not defined, it defaults to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - imagePullSecrets: - description: ImagePullSecrets is the list of pull Secrets to be used - to pull the image. - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - inheritMetadata: - description: InheritMetadata defines the metadata to be inherited - by children resources. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - initContainers: - description: InitContainers to be used in the Pod. - items: - description: Container object definition. - properties: - args: - description: Args to be used in the Container. - items: - type: string - type: array - command: - description: Command to be used in the Container. - items: - type: string - type: array - env: - description: Env represents the environment variables to be - injected in a container. - items: - description: EnvVar represents an environment variable present - in a Container. - properties: - name: - description: Name of the environment variable. Must be - a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. - Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the - specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the - exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's - namespace - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via ConfigMap - and Secrets) to environment variables to be injected in the - container. - items: - description: EnvFromSource represents the source of a set - of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be - defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: Image name to be used by the MariaDB instances. - The supported format is `:`. - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. One of - `Always`, `Never` or `IfNotPresent`. If not defined, it defaults - to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. HTTP - allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a TCP - port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. HTTP - allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a TCP - port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration that - will be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies - to the container. - type: string - role: - description: Role is a SELinux role label that applies - to the container. - type: string - type: - description: Type is a SELinux type label that applies - to the container. - type: string - user: - description: User is a SELinux user label that applies - to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of the - GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting of a Volume - within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - required: - - image - type: object - type: array - kubernetesService: - description: KubernetesService defines a template for a Kubernetes - Service object to connect to MaxScale. - properties: - allocateLoadBalancerNodePorts: - description: AllocateLoadBalancerNodePorts Service field. - type: boolean - externalTrafficPolicy: - description: ExternalTrafficPolicy Service field. - type: string - loadBalancerIP: - description: LoadBalancerIP Service field. - type: string - loadBalancerSourceRanges: - description: LoadBalancerSourceRanges Service field. - items: - type: string - type: array - metadata: - description: Metadata to be added to the Service metadata. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - sessionAffinity: - description: SessionAffinity Service field. - type: string - type: - default: ClusterIP - description: Type is the Service type. One of `ClusterIP`, `NodePort` - or `LoadBalancer`. If not defined, it defaults to `ClusterIP`. - enum: - - ClusterIP - - NodePort - - LoadBalancer - type: string - type: object - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC port. - properties: - port: - description: Port number of the gRPC service. Number must - be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. HTTP allows - repeated headers. - items: - description: HTTPHeader describes a custom header to be - used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a TCP port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - mariaDbRef: - description: MariaDBRef is a reference to the MariaDB that MaxScale - points to. It is used to initialize the servers field. - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - waitForIt: - default: true - description: WaitForIt indicates whether the controller using - this reference should wait for MariaDB to be ready. - type: boolean - type: object - x-kubernetes-map-type: atomic - metrics: - description: Metrics configures metrics and how to scrape them. - properties: - enabled: - description: Enabled is a flag to enable Metrics - type: boolean - exporter: - description: Exporter defines the metrics exporter container. - properties: - affinity: - description: Affinity to be used in the Pod. - properties: - antiAffinityEnabled: - description: |- - AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. - Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. - type: boolean - nodeAffinity: - description: Describes node affinity scheduling rules - for the pod. - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - properties: - preference: - description: A node selector term, associated - with the corresponding weight. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching - the corresponding nodeSelectorTerm, in the - range 1-100. - format: int32 - type: integer - required: - - preference - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - properties: - nodeSelectorTerms: - description: Required. A list of node selector - terms. The terms are ORed. - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the - selector applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - type: array - x-kubernetes-list-type: atomic - required: - - nodeSelectorTerms - type: object - x-kubernetes-map-type: atomic - type: object - podAffinity: - description: Describes pod affinity scheduling rules (e.g. - co-locate this pod in the same node, zone, etc. as some - other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred - node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, - associated with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules - (e.g. avoid putting this pod in the same node, zone, - etc. as some other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred - node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, - associated with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - type: object - args: - description: Args to be used in the Container. - items: - type: string - type: array - command: - description: Command to be used in the Container. - items: - type: string - type: array - env: - description: Env represents the environment variables to be - injected in a container. - items: - description: EnvVar represents an environment variable present - in a Container. - properties: - name: - description: Name of the environment variable. Must - be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. - Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in - the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of - the exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's - namespace - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via ConfigMap - and Secrets) to environment variables to be injected in - the container. - items: - description: EnvFromSource represents the source of a set - of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must - be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be - defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: |- - Image name to be used as metrics exporter. The supported format is `:`. - Only mysqld-exporter >= v0.15.0 is supported: https://github.com/prometheus/mysqld_exporter - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. One - of `Always`, `Never` or `IfNotPresent`. If not defined, - it defaults to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - imagePullSecrets: - description: ImagePullSecrets is the list of pull Secrets - to be used to pull the image. - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - initContainers: - description: InitContainers to be used in the Pod. - items: - description: Container object definition. - properties: - args: - description: Args to be used in the Container. - items: - type: string - type: array - command: - description: Command to be used in the Container. - items: - type: string - type: array - env: - description: Env represents the environment variables - to be injected in a container. - items: - description: EnvVar represents an environment variable - present in a Container. - properties: - name: - description: Name of the environment variable. - Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, defaults - to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in - the pod's namespace - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via - ConfigMap and Secrets) to environment variables to - be injected in the container. - items: - description: EnvFromSource represents the source of - a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must - be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: Image name to be used by the MariaDB instances. - The supported format is `:`. - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. - One of `Always`, `Never` or `IfNotPresent`. If not - defined, it defaults to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - resources: - description: Resouces describes the compute resource - requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry - in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration - that will be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that - applies to the container. - type: string - role: - description: Role is a SELinux role label that - applies to the container. - type: string - type: - description: Type is a SELinux type label that - applies to the container. - type: string - user: - description: User is a SELinux user label that - applies to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name - of the GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting of a - Volume within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - required: - - image - type: object - type: array - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC - port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a - TCP port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - nodeSelector: - additionalProperties: - type: string - description: NodeSelector to be used in the Pod. - type: object - podMetadata: - description: PodMetadata defines extra metadata for the Pod. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - podSecurityContext: - description: SecurityContext holds pod-level security attributes - and common container settings. - properties: - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies - to the container. - type: string - role: - description: Role is a SELinux role label that applies - to the container. - type: string - type: - description: Type is a SELinux type label that applies - to the container. - type: string - user: - description: User is a SELinux user label that applies - to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in - addition to the container's primary GID and fsGroup (if specified). If - the SupplementalGroupsPolicy feature is enabled, the - supplementalGroupsPolicy field determines whether these are in addition - to or instead of any group memberships defined in the container image. - If unspecified, no additional groups are added, though group memberships - defined in the container image may still be used, depending on the - supplementalGroupsPolicy field. - Note that this field cannot be set when spec.os.name is windows. - items: - format: int64 - type: integer - type: array - x-kubernetes-list-type: atomic - supplementalGroupsPolicy: - description: |- - Defines how supplemental groups of the first container processes are calculated. - Valid values are "Merge" and "Strict". If not specified, "Merge" is used. - (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled - and the container runtime must implement support for this feature. - Note that this field cannot be set when spec.os.name is windows. - type: string - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - items: - description: Sysctl defines a kernel parameter to be - set - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options within a container's SecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of - the GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - port: - description: Port where the exporter will be listening for - connections. - format: int32 - type: integer - priorityClassName: - description: PriorityClassName to be used in the Pod. - type: string - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC - port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a - TCP port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration - that will be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies - to the container. - type: string - role: - description: Role is a SELinux role label that applies - to the container. - type: string - type: - description: Type is a SELinux type label that applies - to the container. - type: string - user: - description: User is a SELinux user label that applies - to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of - the GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to be used by the Pods. - type: string - sidecarContainers: - description: SidecarContainers to be used in the Pod. - items: - description: Container object definition. - properties: - args: - description: Args to be used in the Container. - items: - type: string - type: array - command: - description: Command to be used in the Container. - items: - type: string - type: array - env: - description: Env represents the environment variables - to be injected in a container. - items: - description: EnvVar represents an environment variable - present in a Container. - properties: - name: - description: Name of the environment variable. - Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's - value. Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, defaults - to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in - the pod's namespace - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via - ConfigMap and Secrets) to environment variables to - be injected in the container. - items: - description: EnvFromSource represents the source of - a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must - be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: Image name to be used by the MariaDB instances. - The supported format is `:`. - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. - One of `Always`, `Never` or `IfNotPresent`. If not - defined, it defaults to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving - a GRPC port. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom - header to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. - properties: - host: - description: 'Optional: Host name to connect - to, defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - resources: - description: Resouces describes the compute resource - requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry - in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration - that will be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that - applies to the container. - type: string - role: - description: Role is a SELinux role label that - applies to the container. - type: string - type: - description: Type is a SELinux type label that - applies to the container. - type: string - user: - description: User is a SELinux user label that - applies to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name - of the GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting of a - Volume within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - required: - - image - type: object - type: array - tolerations: - description: Tolerations to be used in the Pod. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - topologySpreadConstraints: - description: TopologySpreadConstraints to be used in the Pod. - items: - description: TopologySpreadConstraint specifies how to spread - matching pods among the given topology. - properties: - labelSelector: - description: |- - LabelSelector is used to find matching pods. - Pods that match this label selector are counted to determine the number of pods - in their corresponding topology domain. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select the pods over which - spreading will be calculated. The keys are used to lookup values from the - incoming pod labels, those key-value labels are ANDed with labelSelector - to select the group of existing pods over which spreading will be calculated - for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. - MatchLabelKeys cannot be set when LabelSelector isn't set. - Keys that don't exist in the incoming pod labels will - be ignored. A null or empty list means only match against labelSelector. - - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). - items: - type: string - type: array - x-kubernetes-list-type: atomic - maxSkew: - description: |- - MaxSkew describes the degree to which pods may be unevenly distributed. - When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference - between the number of matching pods in the target topology and the global minimum. - The global minimum is the minimum number of matching pods in an eligible domain - or zero if the number of eligible domains is less than MinDomains. - For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same - labelSelector spread as 2/2/1: - In this case, the global minimum is 1. - | zone1 | zone2 | zone3 | - | P P | P P | P | - - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; - scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) - violate MaxSkew(1). - - if MaxSkew is 2, incoming pod can be scheduled onto any zone. - When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence - to topologies that satisfy it. - It's a required field. Default value is 1 and 0 is not allowed. - format: int32 - type: integer - minDomains: - description: |- - MinDomains indicates a minimum number of eligible domains. - When the number of eligible domains with matching topology keys is less than minDomains, - Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. - And when the number of eligible domains with matching topology keys equals or greater than minDomains, - this value has no effect on scheduling. - As a result, when the number of eligible domains is less than minDomains, - scheduler won't schedule more than maxSkew Pods to those domains. - If value is nil, the constraint behaves as if MinDomains is equal to 1. - Valid values are integers greater than 0. - When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same - labelSelector spread as 2/2/2: - | zone1 | zone2 | zone3 | - | P P | P P | P P | - The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. - In this situation, new pod with the same labelSelector cannot be scheduled, - because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, - it will violate MaxSkew. - format: int32 - type: integer - nodeAffinityPolicy: - description: |- - NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector - when calculating pod topology spread skew. Options are: - - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - - 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: |- - NodeTaintsPolicy indicates how we will treat node taints when calculating - pod topology spread skew. Options are: - - Honor: nodes without taints, along with tainted nodes for which the incoming pod - has a toleration, are included. - - 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: |- - TopologyKey is the key of node labels. Nodes that have a label with this key - and identical values are considered to be in the same topology. - We consider each as a "bucket", and try to put balanced number - of pods into each bucket. - We define a domain as a particular instance of a topology. - Also, we define an eligible domain as a domain whose nodes meet the requirements of - nodeAffinityPolicy and nodeTaintsPolicy. - e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. - And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. - It's a required field. - type: string - whenUnsatisfiable: - description: |- - WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy - the spread constraint. - - DoNotSchedule (default) tells the scheduler not to schedule it. - - ScheduleAnyway tells the scheduler to schedule the pod in any location, - but giving higher precedence to topologies that would help reduce the - skew. - A constraint is considered "Unsatisfiable" for an incoming pod - if and only if every possible node assignment for that pod would violate - "MaxSkew" on some topology. - For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same - labelSelector spread as 3/1/1: - | zone1 | zone2 | zone3 | - | P P P | P | P | - If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled - to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies - MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler - won't make it *more* imbalanced. - It's a required field. - type: string - required: - - maxSkew - - topologyKey - - whenUnsatisfiable - type: object - type: array - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting of a Volume - within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - volumes: - description: Volumes to be used in the Pod. - items: - description: Volume represents a named volume in a pod that - may be accessed by any container in the pod. - properties: - awsElasticBlockStore: - description: |- - awsElasticBlockStore represents an AWS Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - format: int32 - type: integer - readOnly: - description: |- - readOnly value true will force the readOnly setting in VolumeMounts. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: boolean - volumeID: - description: |- - volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - required: - - volumeID - type: object - azureDisk: - description: azureDisk represents an Azure Data Disk - mount on the host and bind mount to the pod. - properties: - cachingMode: - description: 'cachingMode is the Host Caching mode: - None, Read Only, Read Write.' - type: string - diskName: - description: diskName is the Name of the data disk - in the blob storage - type: string - diskURI: - description: diskURI is the URI of data disk in - the blob storage - type: string - fsType: - default: ext4 - description: |- - fsType is Filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - kind: - description: 'kind expected values are Shared: multiple - blob disks per storage account Dedicated: single - blob disk per storage account Managed: azure - managed data disk (only in managed availability - set). defaults to shared' - type: string - readOnly: - default: false - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - required: - - diskName - - diskURI - type: object - azureFile: - description: azureFile represents an Azure File Service - mount on the host and bind mount to the pod. - properties: - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretName: - description: secretName is the name of secret that - contains Azure Storage Account Name and Key - type: string - shareName: - description: shareName is the azure share Name - type: string - required: - - secretName - - shareName - type: object - cephfs: - description: cephFS represents a Ceph FS mount on the - host that shares a pod's lifetime - properties: - monitors: - description: |- - monitors is Required: Monitors is a collection of Ceph monitors - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - path: - description: 'path is Optional: Used as the mounted - root, rather than the full Ceph tree, default - is /' - type: string - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: boolean - secretFile: - description: |- - secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - secretRef: - description: |- - secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - description: |- - user is optional: User is the rados user name, default is admin - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - required: - - monitors - type: object - cinder: - description: |- - cinder represents a cinder volume attached and mounted on kubelets host machine. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: boolean - secretRef: - description: |- - secretRef is optional: points to a secret object containing parameters used to connect - to OpenStack. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeID: - description: |- - volumeID used to identify the volume in cinder. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - required: - - volumeID - type: object - configMap: - description: configMap represents a configMap that should - populate this volume - properties: - defaultMode: - description: |- - defaultMode is optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether the ConfigMap - or its keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - csi: - description: csi (Container Storage Interface) represents - ephemeral storage that is handled by certain external - CSI drivers (Beta feature). - properties: - driver: - description: |- - driver is the name of the CSI driver that handles this volume. - Consult with your admin for the correct name as registered in the cluster. - type: string - fsType: - description: |- - fsType to mount. Ex. "ext4", "xfs", "ntfs". - If not provided, the empty value is passed to the associated CSI driver - which will determine the default filesystem to apply. - type: string - nodePublishSecretRef: - description: |- - nodePublishSecretRef is a reference to the secret object containing - sensitive information to pass to the CSI driver to complete the CSI - NodePublishVolume and NodeUnpublishVolume calls. - This field is optional, and may be empty if no secret is required. If the - secret object contains more than one secret, all secret references are passed. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - readOnly: - description: |- - readOnly specifies a read-only configuration for the volume. - Defaults to false (read/write). - type: boolean - volumeAttributes: - additionalProperties: - type: string - description: |- - volumeAttributes stores driver-specific properties that are passed to the CSI - driver. Consult your driver's documentation for supported values. - type: object - required: - - driver - type: object - downwardAPI: - description: downwardAPI represents downward API about - the pod that should populate this volume - properties: - defaultMode: - description: |- - Optional: mode bits to use on created files by default. Must be a - Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: Items is a list of downward API volume - file - items: - description: DownwardAPIVolumeFile represents - information to create the file containing the - pod field - properties: - fieldRef: - description: 'Required: Selects a field of - the pod: only annotations, labels, name, - namespace and uid are supported.' - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, defaults - to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path is the relative - path name of the file to be created. Must - not be absolute or contain the ''..'' path. - Must be utf-8 encoded. The first item of - the relative path must not start with ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - emptyDir: - description: |- - emptyDir represents a temporary directory that shares a pod's lifetime. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - properties: - medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - ephemeral: - description: |- - ephemeral represents a volume that is handled by a cluster storage driver. - The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, - and deleted when the pod is removed. - - Use this if: - a) the volume is only needed while the pod runs, - b) features of normal volumes like restoring from snapshot or capacity - tracking are needed, - c) the storage driver is specified through a storage class, and - d) the storage driver supports dynamic volume provisioning through - a PersistentVolumeClaim (see EphemeralVolumeSource for more - information on the connection between this volume type - and PersistentVolumeClaim). - - Use PersistentVolumeClaim or one of the vendor-specific - APIs for volumes that persist for longer than the lifecycle - of an individual pod. - - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to - be used that way - see the documentation of the driver for - more information. - - A pod can use both types of ephemeral volumes and - persistent volumes at the same time. - properties: - volumeClaimTemplate: - description: |- - Will be used to create a stand-alone PVC to provision the volume. - The pod in which this EphemeralVolumeSource is embedded will be the - owner of the PVC, i.e. the PVC will be deleted together with the - pod. The name of the PVC will be `-` where - `` is the name from the `PodSpec.Volumes` array - entry. Pod validation will reject the pod if the concatenated name - is not valid for a PVC (for example, too long). - - An existing PVC with that name that is not owned by the pod - will *not* be used for the pod to avoid using an unrelated - volume by mistake. Starting the pod is then blocked until - the unrelated PVC is removed. If such a pre-created PVC is - meant to be used by the pod, the PVC has to updated with an - owner reference to the pod once the pod exists. Normally - this should not be necessary, but it may be useful when - manually reconstructing a broken cluster. - - This field is read-only and no changes will be made by Kubernetes - to the PVC after it has been created. - - Required, must not be nil. - properties: - metadata: - description: |- - May contain labels and annotations that will be copied into the PVC - when creating it. No other fields are allowed and will be rejected during - validation. - type: object - spec: - description: |- - The specification for the PersistentVolumeClaim. The entire content is - copied unchanged into the PVC that gets created from this - template. The same fields as in a PersistentVolumeClaim - are also valid here. - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource - being referenced - type: string - name: - description: Name is the name of resource - being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource - being referenced - type: string - name: - description: Name is the name of resource - being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over - volumes to consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference - to the PersistentVolume backing this claim. - type: string - type: object - required: - - spec - type: object - type: object - fc: - description: fc represents a Fibre Channel resource - that is attached to a kubelet's host machine and then - exposed to the pod. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - lun: - description: 'lun is Optional: FC target lun number' - format: int32 - type: integer - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - targetWWNs: - description: 'targetWWNs is Optional: FC target - worldwide names (WWNs)' - items: - type: string - type: array - x-kubernetes-list-type: atomic - wwids: - description: |- - wwids Optional: FC volume world wide identifiers (wwids) - Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - flexVolume: - description: |- - flexVolume represents a generic volume resource that is - provisioned/attached using an exec based plugin. - properties: - driver: - description: driver is the name of the driver to - use for this volume. - type: string - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. - type: string - options: - additionalProperties: - type: string - description: 'options is Optional: this field holds - extra command options if any.' - type: object - readOnly: - description: |- - readOnly is Optional: defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef is Optional: secretRef is reference to the secret object containing - sensitive information to pass to the plugin scripts. This may be - empty if no secret object is specified. If the secret object - contains more than one secret, all secrets are passed to the plugin - scripts. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - required: - - driver - type: object - flocker: - description: flocker represents a Flocker volume attached - to a kubelet's host machine. This depends on the Flocker - control service being running - properties: - datasetName: - description: |- - datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker - should be considered as deprecated - type: string - datasetUUID: - description: datasetUUID is the UUID of the dataset. - This is unique identifier of a Flocker dataset - type: string - type: object - gcePersistentDisk: - description: |- - gcePersistentDisk represents a GCE Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - properties: - fsType: - description: |- - fsType is filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - format: int32 - type: integer - pdName: - description: |- - pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: boolean - required: - - pdName - type: object - gitRepo: - description: |- - gitRepo represents a git repository at a particular revision. - DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an - EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir - into the Pod's container. - properties: - directory: - description: |- - directory is the target directory name. - Must not contain or start with '..'. If '.' is supplied, the volume directory will be the - git repository. Otherwise, if specified, the volume will contain the git repository in - the subdirectory with the given name. - type: string - repository: - description: repository is the URL - type: string - revision: - description: revision is the commit hash for the - specified revision. - type: string - required: - - repository - type: object - glusterfs: - description: |- - glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/glusterfs/README.md - properties: - endpoints: - description: |- - endpoints is the endpoint name that details Glusterfs topology. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - path: - description: |- - path is the Glusterfs volume path. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - readOnly: - description: |- - readOnly here will force the Glusterfs volume to be mounted with read-only permissions. - Defaults to false. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: boolean - required: - - endpoints - - path - type: object - hostPath: - description: |- - hostPath represents a pre-existing file or directory on the host - machine that is directly exposed to the container. This is generally - used for system agents or other privileged things that are allowed - to see the host machine. Most containers will NOT need this. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - properties: - path: - description: |- - path of the directory on the host. - If the path is a symlink, it will follow the link to the real path. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - type: - description: |- - type for HostPath Volume - Defaults to "" - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - required: - - path - type: object - image: - description: |- - image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. - The volume is resolved at pod startup depending on which PullPolicy value is provided: - - - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - - The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. - A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. - 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). - The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. - properties: - pullPolicy: - description: |- - Policy for pulling OCI objects. Possible values are: - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. - type: string - reference: - description: |- - Required: Image or artifact reference to be used. - Behaves in the same way as pod.spec.containers[*].image. - Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. - More info: https://kubernetes.io/docs/concepts/containers/images - This field is optional to allow higher level config management to default or override - container images in workload controllers like Deployments and StatefulSets. - type: string - type: object - iscsi: - description: |- - iscsi represents an ISCSI Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://examples.k8s.io/volumes/iscsi/README.md - properties: - chapAuthDiscovery: - description: chapAuthDiscovery defines whether support - iSCSI Discovery CHAP authentication - type: boolean - chapAuthSession: - description: chapAuthSession defines whether support - iSCSI Session CHAP authentication - type: boolean - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - type: string - initiatorName: - description: |- - initiatorName is the custom iSCSI Initiator Name. - If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface - : will be created for the connection. - type: string - iqn: - description: iqn is the target iSCSI Qualified Name. - type: string - iscsiInterface: - default: default - description: |- - iscsiInterface is the interface Name that uses an iSCSI transport. - Defaults to 'default' (tcp). - type: string - lun: - description: lun represents iSCSI Target Lun number. - format: int32 - type: integer - portals: - description: |- - portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - items: - type: string - type: array - x-kubernetes-list-type: atomic - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - type: boolean - secretRef: - description: secretRef is the CHAP Secret for iSCSI - target and initiator authentication - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - targetPortal: - description: |- - targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - type: string - required: - - iqn - - lun - - targetPortal - type: object - name: - description: |- - name of the volume. - Must be a DNS_LABEL and unique within the pod. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - nfs: - description: |- - nfs represents an NFS mount on the host that shares a pod's lifetime - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - properties: - path: - description: |- - path that is exported by the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - readOnly: - description: |- - readOnly here will force the NFS export to be mounted with read-only permissions. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: boolean - server: - description: |- - server is the hostname or IP address of the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - required: - - path - - server - type: object - persistentVolumeClaim: - description: |- - persistentVolumeClaimVolumeSource represents a reference to a - PersistentVolumeClaim in the same namespace. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - claimName: - description: |- - claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - type: string - readOnly: - description: |- - readOnly Will force the ReadOnly setting in VolumeMounts. - Default false. - type: boolean - required: - - claimName - type: object - photonPersistentDisk: - description: photonPersistentDisk represents a PhotonController - persistent disk attached and mounted on kubelets host - machine - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - pdID: - description: pdID is the ID that identifies Photon - Controller persistent disk - type: string - required: - - pdID - type: object - portworxVolume: - description: portworxVolume represents a portworx volume - attached and mounted on kubelets host machine - properties: - fsType: - description: |- - fSType represents the filesystem type to mount - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - volumeID: - description: volumeID uniquely identifies a Portworx - volume - type: string - required: - - volumeID - type: object - projected: - description: projected items for all in one resources - secrets, configmaps, and downward API - properties: - defaultMode: - description: |- - defaultMode are the mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - sources: - description: |- - sources is the list of volume projections. Each entry in this list - handles one source. - items: - description: |- - Projection that may be projected along with other supported volume types. - Exactly one of these fields must be set. - properties: - clusterTrustBundle: - description: |- - ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field - of ClusterTrustBundle objects in an auto-updating file. - - Alpha, gated by the ClusterTrustBundleProjection feature gate. - - ClusterTrustBundle objects can either be selected by name, or by the - combination of signer name and a label selector. - - Kubelet performs aggressive normalization of the PEM contents written - into the pod filesystem. Esoteric PEM features such as inter-block - comments and block headers are stripped. Certificates are deduplicated. - The ordering of certificates within the file is arbitrary, and Kubelet - may change the order over time. - properties: - labelSelector: - description: |- - Select all ClusterTrustBundles that match this label selector. Only has - effect if signerName is set. Mutually-exclusive with name. If unset, - interpreted as "match nothing". If set but empty, interpreted as "match - everything". - 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 - name: - description: |- - Select a single ClusterTrustBundle by object name. Mutually-exclusive - with signerName and labelSelector. - type: string - optional: - description: |- - If true, don't block pod startup if the referenced ClusterTrustBundle(s) - aren't available. If using name, then the named ClusterTrustBundle is - allowed not to exist. If using signerName, then the combination of - signerName and labelSelector is allowed to match zero - ClusterTrustBundles. - type: boolean - path: - description: Relative path from the volume - root to write the bundle. - type: string - signerName: - description: |- - Select all ClusterTrustBundles that match this signer name. - Mutually-exclusive with name. The contents of all selected - ClusterTrustBundles will be unified and deduplicated. - type: string - required: - - path - type: object - configMap: - description: configMap information about the - configMap data to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a - path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether - the ConfigMap or its keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - downwardAPI: - description: downwardAPI information about - the downwardAPI data to project - properties: - items: - description: Items is a list of DownwardAPIVolume - file - items: - description: DownwardAPIVolumeFile represents - information to create the file containing - the pod field - properties: - fieldRef: - description: 'Required: Selects - a field of the pod: only annotations, - labels, name, namespace and uid - are supported.' - properties: - apiVersion: - description: Version of the - schema the FieldPath is written - in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field - to select in the specified - API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path is the - relative path name of the file - to be created. Must not be absolute - or contain the ''..'' path. Must - be utf-8 encoded. The first item - of the relative path must not - start with ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container name: - required for volumes, optional - for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output - format of the exposed resources, - defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource - to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - secret: - description: secret information about the - secret data to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a - path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional field specify whether - the Secret or its key must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - serviceAccountToken: - description: serviceAccountToken is information - about the serviceAccountToken data to project - properties: - audience: - description: |- - audience is the intended audience of the token. A recipient of a token - must identify itself with an identifier specified in the audience of the - token, and otherwise should reject the token. The audience defaults to the - identifier of the apiserver. - type: string - expirationSeconds: - description: |- - expirationSeconds is the requested duration of validity of the service - account token. As the token approaches expiration, the kubelet volume - plugin will proactively rotate the service account token. The kubelet will - start trying to rotate the token if the token is older than 80 percent of - its time to live or if the token is older than 24 hours.Defaults to 1 hour - and must be at least 10 minutes. - format: int64 - type: integer - path: - description: |- - path is the path relative to the mount point of the file to project the - token into. - type: string - required: - - path - type: object - type: object - type: array - x-kubernetes-list-type: atomic - type: object - quobyte: - description: quobyte represents a Quobyte mount on the - host that shares a pod's lifetime - properties: - group: - description: |- - group to map volume access to - Default is no group - type: string - readOnly: - description: |- - readOnly here will force the Quobyte volume to be mounted with read-only permissions. - Defaults to false. - type: boolean - registry: - description: |- - registry represents a single or multiple Quobyte Registry services - specified as a string as host:port pair (multiple entries are separated with commas) - which acts as the central registry for volumes - type: string - tenant: - description: |- - tenant owning the given Quobyte volume in the Backend - Used with dynamically provisioned Quobyte volumes, value is set by the plugin - type: string - user: - description: |- - user to map volume access to - Defaults to serivceaccount user - type: string - volume: - description: volume is a string that references - an already created Quobyte volume by name. - type: string - required: - - registry - - volume - type: object - rbd: - description: |- - rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/rbd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - type: string - image: - description: |- - image is the rados image name. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - keyring: - default: /etc/ceph/keyring - description: |- - keyring is the path to key ring for RBDUser. - Default is /etc/ceph/keyring. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - monitors: - description: |- - monitors is a collection of Ceph monitors. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - pool: - default: rbd - description: |- - pool is the rados pool name. - Default is rbd. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: boolean - secretRef: - description: |- - secretRef is name of the authentication secret for RBDUser. If provided - overrides keyring. - Default is nil. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - default: admin - description: |- - user is the rados user name. - Default is admin. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - required: - - image - - monitors - type: object - scaleIO: - description: scaleIO represents a ScaleIO persistent - volume attached and mounted on Kubernetes nodes. - properties: - fsType: - default: xfs - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". - Default is "xfs". - type: string - gateway: - description: gateway is the host address of the - ScaleIO API Gateway. - type: string - protectionDomain: - description: protectionDomain is the name of the - ScaleIO Protection Domain for the configured storage. - type: string - readOnly: - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef references to the secret for ScaleIO user and other - sensitive information. If this is not provided, Login operation will fail. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - sslEnabled: - description: sslEnabled Flag enable/disable SSL - communication with Gateway, default false - type: boolean - storageMode: - default: ThinProvisioned - description: |- - storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. - Default is ThinProvisioned. - type: string - storagePool: - description: storagePool is the ScaleIO Storage - Pool associated with the protection domain. - type: string - system: - description: system is the name of the storage system - as configured in ScaleIO. - type: string - volumeName: - description: |- - volumeName is the name of a volume already created in the ScaleIO system - that is associated with this volume source. - type: string - required: - - gateway - - secretRef - - system - type: object - secret: - description: |- - secret represents a secret that should populate this volume. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - properties: - defaultMode: - description: |- - defaultMode is Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values - for mode bits. Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items If unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - optional: - description: optional field specify whether the - Secret or its keys must be defined - type: boolean - secretName: - description: |- - secretName is the name of the secret in the pod's namespace to use. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - type: string - type: object - storageos: - description: storageOS represents a StorageOS volume - attached and mounted on Kubernetes nodes. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef specifies the secret to use for obtaining the StorageOS API - credentials. If not specified, default values will be attempted. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeName: - description: |- - volumeName is the human-readable name of the StorageOS volume. Volume - names are only unique within a namespace. - type: string - volumeNamespace: - description: |- - volumeNamespace specifies the scope of the volume within StorageOS. If no - namespace is specified then the Pod's namespace will be used. This allows the - Kubernetes name scoping to be mirrored within StorageOS for tighter integration. - Set VolumeName to any name to override the default behaviour. - Set to "default" if you are not using namespaces within StorageOS. - Namespaces that do not pre-exist within StorageOS will be created. - type: string - type: object - vsphereVolume: - description: vsphereVolume represents a vSphere volume - attached and mounted on kubelets host machine - properties: - fsType: - description: |- - fsType is filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - storagePolicyID: - description: storagePolicyID is the storage Policy - Based Management (SPBM) profile ID associated - with the StoragePolicyName. - type: string - storagePolicyName: - description: storagePolicyName is the storage Policy - Based Management (SPBM) profile name. - type: string - volumePath: - description: volumePath is the path that identifies - vSphere volume vmdk - type: string - required: - - volumePath - type: object - required: - - name - type: object - type: array - type: object - serviceMonitor: - description: ServiceMonitor defines the ServiceMonior object. - properties: - interval: - description: Interval for scraping metrics. - type: string - jobLabel: - description: JobLabel to add to the ServiceMonitor object. - type: string - prometheusRelease: - description: PrometheusRelease is the release label to add - to the ServiceMonitor object. - type: string - scrapeTimeout: - description: ScrapeTimeout defines the timeout for scraping - metrics. - type: string - type: object - type: object - monitor: - description: Monitor monitors MariaDB server instances. It is required - if 'spec.mariaDbRef' is not provided. - properties: - cooperativeMonitoring: - description: CooperativeMonitoring enables coordination between - multiple MaxScale instances running monitors. It is defaulted - when HA is enabled. - enum: - - majority_of_all - - majority_of_running - type: string - interval: - description: Interval used to monitor MariaDB servers. It is defaulted - if not provided. - type: string - module: - description: Module is the module to use to monitor MariaDB servers. - It is mandatory when no MariaDB reference is provided. - type: string - name: - description: Name is the identifier of the monitor. It is defaulted - if not provided. - type: string - params: - additionalProperties: - type: string - description: |- - Params defines extra parameters to pass to the monitor. - Any parameter supported by MaxScale may be specified here. See reference: - https://mariadb.com/kb/en/mariadb-maxscale-2308-common-monitor-parameters/. - Monitor specific parameter are also suported: - https://mariadb.com/kb/en/mariadb-maxscale-2308-galera-monitor/#galera-monitor-optional-parameters. - https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-monitor/#configuration. - type: object - suspend: - default: false - description: |- - Suspend indicates whether the current resource should be suspended or not. - This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. - type: boolean - type: object - nodeSelector: - additionalProperties: - type: string - description: NodeSelector to be used in the Pod. - type: object - podDisruptionBudget: - description: PodDisruptionBudget defines the budget for replica availability. - properties: - maxUnavailable: - anyOf: - - type: integer - - type: string - description: MaxUnavailable defines the number of maximum unavailable - Pods. - x-kubernetes-int-or-string: true - minAvailable: - anyOf: - - type: integer - - type: string - description: MinAvailable defines the number of minimum available - Pods. - x-kubernetes-int-or-string: true - type: object - podMetadata: - description: PodMetadata defines extra metadata for the Pod. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - podSecurityContext: - description: SecurityContext holds pod-level security attributes and - common container settings. - properties: - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies to - the container. - type: string - role: - description: Role is a SELinux role label that applies to - the container. - type: string - type: - description: Type is a SELinux type label that applies to - the container. - type: string - user: - description: User is a SELinux user label that applies to - the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in - addition to the container's primary GID and fsGroup (if specified). If - the SupplementalGroupsPolicy feature is enabled, the - supplementalGroupsPolicy field determines whether these are in addition - to or instead of any group memberships defined in the container image. - If unspecified, no additional groups are added, though group memberships - defined in the container image may still be used, depending on the - supplementalGroupsPolicy field. - Note that this field cannot be set when spec.os.name is windows. - items: - format: int64 - type: integer - type: array - x-kubernetes-list-type: atomic - supplementalGroupsPolicy: - description: |- - Defines how supplemental groups of the first container processes are calculated. - Valid values are "Merge" and "Strict". If not specified, "Merge" is used. - (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled - and the container runtime must implement support for this feature. - Note that this field cannot be set when spec.os.name is windows. - type: string - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - items: - description: Sysctl defines a kernel parameter to be set - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options within a container's SecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of the GMSA - credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - priorityClassName: - description: PriorityClassName to be used in the Pod. - type: string - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC port. - properties: - port: - description: Port number of the gRPC service. Number must - be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. HTTP allows - repeated headers. - items: - description: HTTPHeader describes a custom header to be - used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a TCP port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - replicas: - default: 1 - description: Replicas indicates the number of desired instances. - format: int32 - type: integer - requeueInterval: - description: RequeueInterval is used to perform requeue reconciliations. - If not defined, it defaults to 10s. - type: string - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration that will - be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies to - the container. - type: string - role: - description: Role is a SELinux role label that applies to - the container. - type: string - type: - description: Type is a SELinux type label that applies to - the container. - type: string - user: - description: User is a SELinux user label that applies to - the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of the GMSA - credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - servers: - description: Servers are the MariaDB servers to forward traffic to. - It is required if 'spec.mariaDbRef' is not provided. - items: - description: MaxScaleServer defines a MariaDB server to forward - traffic to. - properties: - address: - description: Address is the network address of the MariaDB server. - type: string - maintenance: - description: Maintenance indicates whether the server is in - maintenance mode. - type: boolean - name: - description: Name is the identifier of the MariaDB server. - type: string - params: - additionalProperties: - type: string - description: |- - Params defines extra parameters to pass to the server. - Any parameter supported by MaxScale may be specified here. See reference: - https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#server_1. - type: object - port: - description: Port is the network port of the MariaDB server. - If not provided, it defaults to 3306. - format: int32 - type: integer - protocol: - description: Protocol is the MaxScale protocol to use when communicating - with this MariaDB server. If not provided, it defaults to - MariaDBBackend. - type: string - required: - - address - - name - type: object - type: array - serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to be used by the Pods. - type: string - services: - description: Services define how the traffic is forwarded to the MariaDB - servers. It is defaulted if not provided. - items: - description: Services define how the traffic is forwarded to the - MariaDB servers. - properties: - listener: - description: MaxScaleListener defines how the MaxScale server - will listen for connections. - properties: - name: - description: Name is the identifier of the listener. It - is defaulted if not provided - type: string - params: - additionalProperties: - type: string - description: |- - Params defines extra parameters to pass to the listener. - Any parameter supported by MaxScale may be specified here. See reference: - https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#listener_1. - type: object - port: - description: Port is the network port where the MaxScale - server will listen. - format: int32 - type: integer - protocol: - description: Protocol is the MaxScale protocol to use when - communicating with the client. If not provided, it defaults - to MariaDBProtocol. - type: string - suspend: - default: false - description: |- - Suspend indicates whether the current resource should be suspended or not. - This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. - type: boolean - required: - - port - type: object - name: - description: Name is the identifier of the MaxScale service. - type: string - params: - additionalProperties: - type: string - description: |- - Params defines extra parameters to pass to the service. - Any parameter supported by MaxScale may be specified here. See reference: - https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#service_1. - Router specific parameter are also suported: - https://mariadb.com/kb/en/mariadb-maxscale-2308-readwritesplit/#configuration. - https://mariadb.com/kb/en/mariadb-maxscale-2308-readconnroute/#configuration. - type: object - router: - description: Router is the type of router to use. - enum: - - readwritesplit - - readconnroute - type: string - suspend: - default: false - description: |- - Suspend indicates whether the current resource should be suspended or not. - This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. - type: boolean - required: - - listener - - name - - router - type: object - type: array - sidecarContainers: - description: SidecarContainers to be used in the Pod. - items: - description: Container object definition. - properties: - args: - description: Args to be used in the Container. - items: - type: string - type: array - command: - description: Command to be used in the Container. - items: - type: string - type: array - env: - description: Env represents the environment variables to be - injected in a container. - items: - description: EnvVar represents an environment variable present - in a Container. - properties: - name: - description: Name of the environment variable. Must be - a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. - Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the - specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the - exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's - namespace - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - envFrom: - description: EnvFrom represents the references (via ConfigMap - and Secrets) to environment variables to be injected in the - container. - items: - description: EnvFromSource represents the source of a set - of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be - defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: Image name to be used by the MariaDB instances. - The supported format is `:`. - type: string - imagePullPolicy: - description: ImagePullPolicy is the image pull policy. One of - `Always`, `Never` or `IfNotPresent`. If not defined, it defaults - to `IfNotPresent`. - enum: - - Always - - Never - - IfNotPresent - type: string - livenessProbe: - description: LivenessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. HTTP - allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a TCP - port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - readinessProbe: - description: ReadinessProbe to be used in the Container. - properties: - exec: - description: Exec specifies the action to take. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies an action involving a GRPC port. - properties: - port: - description: Port number of the gRPC service. Number - must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies the http request to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. HTTP - allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object - initialDelaySeconds: - description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. - format: int32 - type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies an action involving a TCP - port. - properties: - host: - description: 'Optional: Host name to connect to, defaults - to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - type: object - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - securityContext: - description: SecurityContext holds security configuration that - will be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities - type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies - to the container. - type: string - role: - description: Role is a SELinux role label that applies - to the container. - type: string - type: - description: Type is a SELinux type label that applies - to the container. - type: string - user: - description: User is a SELinux user label that applies - to the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of the - GMSA credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting of a Volume - within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - required: - - image - type: object - type: array - suspend: - default: false - description: |- - Suspend indicates whether the current resource should be suspended or not. - This can be useful for maintenance, as disabling the reconciliation prevents the operator from interfering with user operations during maintenance activities. - type: boolean - tolerations: - description: Tolerations to be used in the Pod. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - topologySpreadConstraints: - description: TopologySpreadConstraints to be used in the Pod. - items: - description: TopologySpreadConstraint specifies how to spread matching - pods among the given topology. - properties: - labelSelector: - description: |- - LabelSelector is used to find matching pods. - Pods that match this label selector are counted to determine the number of pods - in their corresponding topology domain. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select the pods over which - spreading will be calculated. The keys are used to lookup values from the - incoming pod labels, those key-value labels are ANDed with labelSelector - to select the group of existing pods over which spreading will be calculated - for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. - MatchLabelKeys cannot be set when LabelSelector isn't set. - Keys that don't exist in the incoming pod labels will - be ignored. A null or empty list means only match against labelSelector. - - This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). - items: - type: string - type: array - x-kubernetes-list-type: atomic - maxSkew: - description: |- - MaxSkew describes the degree to which pods may be unevenly distributed. - When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference - between the number of matching pods in the target topology and the global minimum. - The global minimum is the minimum number of matching pods in an eligible domain - or zero if the number of eligible domains is less than MinDomains. - For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same - labelSelector spread as 2/2/1: - In this case, the global minimum is 1. - | zone1 | zone2 | zone3 | - | P P | P P | P | - - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; - scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) - violate MaxSkew(1). - - if MaxSkew is 2, incoming pod can be scheduled onto any zone. - When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence - to topologies that satisfy it. - It's a required field. Default value is 1 and 0 is not allowed. - format: int32 - type: integer - minDomains: - description: |- - MinDomains indicates a minimum number of eligible domains. - When the number of eligible domains with matching topology keys is less than minDomains, - Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. - And when the number of eligible domains with matching topology keys equals or greater than minDomains, - this value has no effect on scheduling. - As a result, when the number of eligible domains is less than minDomains, - scheduler won't schedule more than maxSkew Pods to those domains. - If value is nil, the constraint behaves as if MinDomains is equal to 1. - Valid values are integers greater than 0. - When value is not nil, WhenUnsatisfiable must be DoNotSchedule. - - For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same - labelSelector spread as 2/2/2: - | zone1 | zone2 | zone3 | - | P P | P P | P P | - The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. - In this situation, new pod with the same labelSelector cannot be scheduled, - because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, - it will violate MaxSkew. - format: int32 - type: integer - nodeAffinityPolicy: - description: |- - NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector - when calculating pod topology spread skew. Options are: - - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - - 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: |- - NodeTaintsPolicy indicates how we will treat node taints when calculating - pod topology spread skew. Options are: - - Honor: nodes without taints, along with tainted nodes for which the incoming pod - has a toleration, are included. - - 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: |- - TopologyKey is the key of node labels. Nodes that have a label with this key - and identical values are considered to be in the same topology. - We consider each as a "bucket", and try to put balanced number - of pods into each bucket. - We define a domain as a particular instance of a topology. - Also, we define an eligible domain as a domain whose nodes meet the requirements of - nodeAffinityPolicy and nodeTaintsPolicy. - e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. - And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. - It's a required field. - type: string - whenUnsatisfiable: - description: |- - WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy - the spread constraint. - - DoNotSchedule (default) tells the scheduler not to schedule it. - - ScheduleAnyway tells the scheduler to schedule the pod in any location, - but giving higher precedence to topologies that would help reduce the - skew. - A constraint is considered "Unsatisfiable" for an incoming pod - if and only if every possible node assignment for that pod would violate - "MaxSkew" on some topology. - For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same - labelSelector spread as 3/1/1: - | zone1 | zone2 | zone3 | - | P P P | P | P | - If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled - to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies - MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler - won't make it *more* imbalanced. - It's a required field. - type: string - required: - - maxSkew - - topologyKey - - whenUnsatisfiable - type: object - type: array - updateStrategy: - description: UpdateStrategy defines the update strategy for the StatefulSet - object. - properties: - rollingUpdate: - description: RollingUpdate is used to communicate parameters when - Type is RollingUpdateStatefulSetStrategyType. - properties: - maxUnavailable: - anyOf: - - type: integer - - type: string - description: |- - The maximum number of pods that can be unavailable during the update. - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). - Absolute number is calculated from percentage by rounding up. This can not be 0. - Defaults to 1. This field is alpha-level and is only honored by servers that enable the - MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to - Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it - will be counted towards MaxUnavailable. - x-kubernetes-int-or-string: true - partition: - description: |- - Partition indicates the ordinal at which the StatefulSet should be partitioned - for updates. During a rolling update, all pods from ordinal Replicas-1 to - Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. - This is helpful in being able to do a canary based deployment. The default value is 0. - format: int32 - type: integer - type: object - type: - description: |- - Type indicates the type of the StatefulSetUpdateStrategy. - Default is RollingUpdate. - type: string - type: object - volumeMounts: - description: VolumeMounts to be used in the Container. - items: - description: VolumeMount describes a mounting of a Volume within - a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - volumes: - description: Volumes to be used in the Pod. - items: - description: Volume represents a named volume in a pod that may - be accessed by any container in the pod. - properties: - awsElasticBlockStore: - description: |- - awsElasticBlockStore represents an AWS Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - format: int32 - type: integer - readOnly: - description: |- - readOnly value true will force the readOnly setting in VolumeMounts. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: boolean - volumeID: - description: |- - volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - required: - - volumeID - type: object - azureDisk: - description: azureDisk represents an Azure Data Disk mount on - the host and bind mount to the pod. - properties: - cachingMode: - description: 'cachingMode is the Host Caching mode: None, - Read Only, Read Write.' - type: string - diskName: - description: diskName is the Name of the data disk in the - blob storage - type: string - diskURI: - description: diskURI is the URI of data disk in the blob - storage - type: string - fsType: - default: ext4 - description: |- - fsType is Filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - kind: - description: 'kind expected values are Shared: multiple - blob disks per storage account Dedicated: single blob - disk per storage account Managed: azure managed data - disk (only in managed availability set). defaults to shared' - type: string - readOnly: - default: false - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - required: - - diskName - - diskURI - type: object - azureFile: - description: azureFile represents an Azure File Service mount - on the host and bind mount to the pod. - properties: - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretName: - description: secretName is the name of secret that contains - Azure Storage Account Name and Key - type: string - shareName: - description: shareName is the azure share Name - type: string - required: - - secretName - - shareName - type: object - cephfs: - description: cephFS represents a Ceph FS mount on the host that - shares a pod's lifetime - properties: - monitors: - description: |- - monitors is Required: Monitors is a collection of Ceph monitors - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - path: - description: 'path is Optional: Used as the mounted root, - rather than the full Ceph tree, default is /' - type: string - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: boolean - secretFile: - description: |- - secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - secretRef: - description: |- - secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - description: |- - user is optional: User is the rados user name, default is admin - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - required: - - monitors - type: object - cinder: - description: |- - cinder represents a cinder volume attached and mounted on kubelets host machine. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: boolean - secretRef: - description: |- - secretRef is optional: points to a secret object containing parameters used to connect - to OpenStack. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeID: - description: |- - volumeID used to identify the volume in cinder. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - required: - - volumeID - type: object - configMap: - description: configMap represents a configMap that should populate - this volume - properties: - defaultMode: - description: |- - defaultMode is optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether the ConfigMap or its - keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - csi: - description: csi (Container Storage Interface) represents ephemeral - storage that is handled by certain external CSI drivers (Beta - feature). - properties: - driver: - description: |- - driver is the name of the CSI driver that handles this volume. - Consult with your admin for the correct name as registered in the cluster. - type: string - fsType: - description: |- - fsType to mount. Ex. "ext4", "xfs", "ntfs". - If not provided, the empty value is passed to the associated CSI driver - which will determine the default filesystem to apply. - type: string - nodePublishSecretRef: - description: |- - nodePublishSecretRef is a reference to the secret object containing - sensitive information to pass to the CSI driver to complete the CSI - NodePublishVolume and NodeUnpublishVolume calls. - This field is optional, and may be empty if no secret is required. If the - secret object contains more than one secret, all secret references are passed. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - readOnly: - description: |- - readOnly specifies a read-only configuration for the volume. - Defaults to false (read/write). - type: boolean - volumeAttributes: - additionalProperties: - type: string - description: |- - volumeAttributes stores driver-specific properties that are passed to the CSI - driver. Consult your driver's documentation for supported values. - type: object - required: - - driver - type: object - downwardAPI: - description: downwardAPI represents downward API about the pod - that should populate this volume - properties: - defaultMode: - description: |- - Optional: mode bits to use on created files by default. Must be a - Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: Items is a list of downward API volume file - items: - description: DownwardAPIVolumeFile represents information - to create the file containing the pod field - properties: - fieldRef: - description: 'Required: Selects a field of the pod: - only annotations, labels, name, namespace and uid - are supported.' - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the - specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path is the relative path - name of the file to be created. Must not be absolute - or contain the ''..'' path. Must be utf-8 encoded. - The first item of the relative path must not start - with ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the - exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - emptyDir: - description: |- - emptyDir represents a temporary directory that shares a pod's lifetime. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - properties: - medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - ephemeral: - description: |- - ephemeral represents a volume that is handled by a cluster storage driver. - The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, - and deleted when the pod is removed. - - Use this if: - a) the volume is only needed while the pod runs, - b) features of normal volumes like restoring from snapshot or capacity - tracking are needed, - c) the storage driver is specified through a storage class, and - d) the storage driver supports dynamic volume provisioning through - a PersistentVolumeClaim (see EphemeralVolumeSource for more - information on the connection between this volume type - and PersistentVolumeClaim). - - Use PersistentVolumeClaim or one of the vendor-specific - APIs for volumes that persist for longer than the lifecycle - of an individual pod. - - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to - be used that way - see the documentation of the driver for - more information. - - A pod can use both types of ephemeral volumes and - persistent volumes at the same time. - properties: - volumeClaimTemplate: - description: |- - Will be used to create a stand-alone PVC to provision the volume. - The pod in which this EphemeralVolumeSource is embedded will be the - owner of the PVC, i.e. the PVC will be deleted together with the - pod. The name of the PVC will be `-` where - `` is the name from the `PodSpec.Volumes` array - entry. Pod validation will reject the pod if the concatenated name - is not valid for a PVC (for example, too long). - - An existing PVC with that name that is not owned by the pod - will *not* be used for the pod to avoid using an unrelated - volume by mistake. Starting the pod is then blocked until - the unrelated PVC is removed. If such a pre-created PVC is - meant to be used by the pod, the PVC has to updated with an - owner reference to the pod once the pod exists. Normally - this should not be necessary, but it may be useful when - manually reconstructing a broken cluster. - - This field is read-only and no changes will be made by Kubernetes - to the PVC after it has been created. - - Required, must not be nil. - properties: - metadata: - description: |- - May contain labels and annotations that will be copied into the PVC - when creating it. No other fields are allowed and will be rejected during - validation. - type: object - spec: - description: |- - The specification for the PersistentVolumeClaim. The entire content is - copied unchanged into the PVC that gets created from this - template. The same fields as in a PersistentVolumeClaim - are also valid here. - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes - to consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference - to the PersistentVolume backing this claim. - type: string - type: object - required: - - spec - type: object - type: object - fc: - description: fc represents a Fibre Channel resource that is - attached to a kubelet's host machine and then exposed to the - pod. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - lun: - description: 'lun is Optional: FC target lun number' - format: int32 - type: integer - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - targetWWNs: - description: 'targetWWNs is Optional: FC target worldwide - names (WWNs)' - items: - type: string - type: array - x-kubernetes-list-type: atomic - wwids: - description: |- - wwids Optional: FC volume world wide identifiers (wwids) - Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - flexVolume: - description: |- - flexVolume represents a generic volume resource that is - provisioned/attached using an exec based plugin. - properties: - driver: - description: driver is the name of the driver to use for - this volume. - type: string - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. - type: string - options: - additionalProperties: - type: string - description: 'options is Optional: this field holds extra - command options if any.' - type: object - readOnly: - description: |- - readOnly is Optional: defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef is Optional: secretRef is reference to the secret object containing - sensitive information to pass to the plugin scripts. This may be - empty if no secret object is specified. If the secret object - contains more than one secret, all secrets are passed to the plugin - scripts. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - required: - - driver - type: object - flocker: - description: flocker represents a Flocker volume attached to - a kubelet's host machine. This depends on the Flocker control - service being running - properties: - datasetName: - description: |- - datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker - should be considered as deprecated - type: string - datasetUUID: - description: datasetUUID is the UUID of the dataset. This - is unique identifier of a Flocker dataset - type: string - type: object - gcePersistentDisk: - description: |- - gcePersistentDisk represents a GCE Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - properties: - fsType: - description: |- - fsType is filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - format: int32 - type: integer - pdName: - description: |- - pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: boolean - required: - - pdName - type: object - gitRepo: - description: |- - gitRepo represents a git repository at a particular revision. - DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an - EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir - into the Pod's container. - properties: - directory: - description: |- - directory is the target directory name. - Must not contain or start with '..'. If '.' is supplied, the volume directory will be the - git repository. Otherwise, if specified, the volume will contain the git repository in - the subdirectory with the given name. - type: string - repository: - description: repository is the URL - type: string - revision: - description: revision is the commit hash for the specified - revision. - type: string - required: - - repository - type: object - glusterfs: - description: |- - glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/glusterfs/README.md - properties: - endpoints: - description: |- - endpoints is the endpoint name that details Glusterfs topology. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - path: - description: |- - path is the Glusterfs volume path. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - readOnly: - description: |- - readOnly here will force the Glusterfs volume to be mounted with read-only permissions. - Defaults to false. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: boolean - required: - - endpoints - - path - type: object - hostPath: - description: |- - hostPath represents a pre-existing file or directory on the host - machine that is directly exposed to the container. This is generally - used for system agents or other privileged things that are allowed - to see the host machine. Most containers will NOT need this. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - properties: - path: - description: |- - path of the directory on the host. - If the path is a symlink, it will follow the link to the real path. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - type: - description: |- - type for HostPath Volume - Defaults to "" - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - required: - - path - type: object - image: - description: |- - image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. - The volume is resolved at pod startup depending on which PullPolicy value is provided: - - - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - - The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. - A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. - 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). - The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. - properties: - pullPolicy: - description: |- - Policy for pulling OCI objects. Possible values are: - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. - type: string - reference: - description: |- - Required: Image or artifact reference to be used. - Behaves in the same way as pod.spec.containers[*].image. - Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. - More info: https://kubernetes.io/docs/concepts/containers/images - This field is optional to allow higher level config management to default or override - container images in workload controllers like Deployments and StatefulSets. - type: string - type: object - iscsi: - description: |- - iscsi represents an ISCSI Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://examples.k8s.io/volumes/iscsi/README.md - properties: - chapAuthDiscovery: - description: chapAuthDiscovery defines whether support iSCSI - Discovery CHAP authentication - type: boolean - chapAuthSession: - description: chapAuthSession defines whether support iSCSI - Session CHAP authentication - type: boolean - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - type: string - initiatorName: - description: |- - initiatorName is the custom iSCSI Initiator Name. - If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface - : will be created for the connection. - type: string - iqn: - description: iqn is the target iSCSI Qualified Name. - type: string - iscsiInterface: - default: default - description: |- - iscsiInterface is the interface Name that uses an iSCSI transport. - Defaults to 'default' (tcp). - type: string - lun: - description: lun represents iSCSI Target Lun number. - format: int32 - type: integer - portals: - description: |- - portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - items: - type: string - type: array - x-kubernetes-list-type: atomic - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - type: boolean - secretRef: - description: secretRef is the CHAP Secret for iSCSI target - and initiator authentication - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - targetPortal: - description: |- - targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - type: string - required: - - iqn - - lun - - targetPortal - type: object - name: - description: |- - name of the volume. - Must be a DNS_LABEL and unique within the pod. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - nfs: - description: |- - nfs represents an NFS mount on the host that shares a pod's lifetime - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - properties: - path: - description: |- - path that is exported by the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - readOnly: - description: |- - readOnly here will force the NFS export to be mounted with read-only permissions. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: boolean - server: - description: |- - server is the hostname or IP address of the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - required: - - path - - server - type: object - persistentVolumeClaim: - description: |- - persistentVolumeClaimVolumeSource represents a reference to a - PersistentVolumeClaim in the same namespace. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - claimName: - description: |- - claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - type: string - readOnly: - description: |- - readOnly Will force the ReadOnly setting in VolumeMounts. - Default false. - type: boolean - required: - - claimName - type: object - photonPersistentDisk: - description: photonPersistentDisk represents a PhotonController - persistent disk attached and mounted on kubelets host machine - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - pdID: - description: pdID is the ID that identifies Photon Controller - persistent disk - type: string - required: - - pdID - type: object - portworxVolume: - description: portworxVolume represents a portworx volume attached - and mounted on kubelets host machine - properties: - fsType: - description: |- - fSType represents the filesystem type to mount - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - volumeID: - description: volumeID uniquely identifies a Portworx volume - type: string - required: - - volumeID - type: object - projected: - description: projected items for all in one resources secrets, - configmaps, and downward API - properties: - defaultMode: - description: |- - defaultMode are the mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - sources: - description: |- - sources is the list of volume projections. Each entry in this list - handles one source. - items: - description: |- - Projection that may be projected along with other supported volume types. - Exactly one of these fields must be set. - properties: - clusterTrustBundle: - description: |- - ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field - of ClusterTrustBundle objects in an auto-updating file. - - Alpha, gated by the ClusterTrustBundleProjection feature gate. - - ClusterTrustBundle objects can either be selected by name, or by the - combination of signer name and a label selector. - - Kubelet performs aggressive normalization of the PEM contents written - into the pod filesystem. Esoteric PEM features such as inter-block - comments and block headers are stripped. Certificates are deduplicated. - The ordering of certificates within the file is arbitrary, and Kubelet - may change the order over time. - properties: - labelSelector: - description: |- - Select all ClusterTrustBundles that match this label selector. Only has - effect if signerName is set. Mutually-exclusive with name. If unset, - interpreted as "match nothing". If set but empty, interpreted as "match - everything". - 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 - name: - description: |- - Select a single ClusterTrustBundle by object name. Mutually-exclusive - with signerName and labelSelector. - type: string - optional: - description: |- - If true, don't block pod startup if the referenced ClusterTrustBundle(s) - aren't available. If using name, then the named ClusterTrustBundle is - allowed not to exist. If using signerName, then the combination of - signerName and labelSelector is allowed to match zero - ClusterTrustBundles. - type: boolean - path: - description: Relative path from the volume root - to write the bundle. - type: string - signerName: - description: |- - Select all ClusterTrustBundles that match this signer name. - Mutually-exclusive with name. The contents of all selected - ClusterTrustBundles will be unified and deduplicated. - type: string - required: - - path - type: object - configMap: - description: configMap information about the configMap - data to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether the ConfigMap - or its keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - downwardAPI: - description: downwardAPI information about the downwardAPI - data to project - properties: - items: - description: Items is a list of DownwardAPIVolume - file - items: - description: DownwardAPIVolumeFile represents - information to create the file containing - the pod field - properties: - fieldRef: - description: 'Required: Selects a field - of the pod: only annotations, labels, - name, namespace and uid are supported.' - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, - defaults to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path is the relative - path name of the file to be created. Must - not be absolute or contain the ''..'' - path. Must be utf-8 encoded. The first - item of the relative path must not start - with ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults - to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to - select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - secret: - description: secret information about the secret data - to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional field specify whether the - Secret or its key must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - serviceAccountToken: - description: serviceAccountToken is information about - the serviceAccountToken data to project - properties: - audience: - description: |- - audience is the intended audience of the token. A recipient of a token - must identify itself with an identifier specified in the audience of the - token, and otherwise should reject the token. The audience defaults to the - identifier of the apiserver. - type: string - expirationSeconds: - description: |- - expirationSeconds is the requested duration of validity of the service - account token. As the token approaches expiration, the kubelet volume - plugin will proactively rotate the service account token. The kubelet will - start trying to rotate the token if the token is older than 80 percent of - its time to live or if the token is older than 24 hours.Defaults to 1 hour - and must be at least 10 minutes. - format: int64 - type: integer - path: - description: |- - path is the path relative to the mount point of the file to project the - token into. - type: string - required: - - path - type: object - type: object - type: array - x-kubernetes-list-type: atomic - type: object - quobyte: - description: quobyte represents a Quobyte mount on the host - that shares a pod's lifetime - properties: - group: - description: |- - group to map volume access to - Default is no group - type: string - readOnly: - description: |- - readOnly here will force the Quobyte volume to be mounted with read-only permissions. - Defaults to false. - type: boolean - registry: - description: |- - registry represents a single or multiple Quobyte Registry services - specified as a string as host:port pair (multiple entries are separated with commas) - which acts as the central registry for volumes - type: string - tenant: - description: |- - tenant owning the given Quobyte volume in the Backend - Used with dynamically provisioned Quobyte volumes, value is set by the plugin - type: string - user: - description: |- - user to map volume access to - Defaults to serivceaccount user - type: string - volume: - description: volume is a string that references an already - created Quobyte volume by name. - type: string - required: - - registry - - volume - type: object - rbd: - description: |- - rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/rbd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - type: string - image: - description: |- - image is the rados image name. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - keyring: - default: /etc/ceph/keyring - description: |- - keyring is the path to key ring for RBDUser. - Default is /etc/ceph/keyring. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - monitors: - description: |- - monitors is a collection of Ceph monitors. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - pool: - default: rbd - description: |- - pool is the rados pool name. - Default is rbd. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: boolean - secretRef: - description: |- - secretRef is name of the authentication secret for RBDUser. If provided - overrides keyring. - Default is nil. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - default: admin - description: |- - user is the rados user name. - Default is admin. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - required: - - image - - monitors - type: object - scaleIO: - description: scaleIO represents a ScaleIO persistent volume - attached and mounted on Kubernetes nodes. - properties: - fsType: - default: xfs - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". - Default is "xfs". - type: string - gateway: - description: gateway is the host address of the ScaleIO - API Gateway. - type: string - protectionDomain: - description: protectionDomain is the name of the ScaleIO - Protection Domain for the configured storage. - type: string - readOnly: - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef references to the secret for ScaleIO user and other - sensitive information. If this is not provided, Login operation will fail. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - sslEnabled: - description: sslEnabled Flag enable/disable SSL communication - with Gateway, default false - type: boolean - storageMode: - default: ThinProvisioned - description: |- - storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. - Default is ThinProvisioned. - type: string - storagePool: - description: storagePool is the ScaleIO Storage Pool associated - with the protection domain. - type: string - system: - description: system is the name of the storage system as - configured in ScaleIO. - type: string - volumeName: - description: |- - volumeName is the name of a volume already created in the ScaleIO system - that is associated with this volume source. - type: string - required: - - gateway - - secretRef - - system - type: object - secret: - description: |- - secret represents a secret that should populate this volume. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - properties: - defaultMode: - description: |- - defaultMode is Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values - for mode bits. Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items If unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - optional: - description: optional field specify whether the Secret or - its keys must be defined - type: boolean - secretName: - description: |- - secretName is the name of the secret in the pod's namespace to use. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - type: string - type: object - storageos: - description: storageOS represents a StorageOS volume attached - and mounted on Kubernetes nodes. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef specifies the secret to use for obtaining the StorageOS API - credentials. If not specified, default values will be attempted. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeName: - description: |- - volumeName is the human-readable name of the StorageOS volume. Volume - names are only unique within a namespace. - type: string - volumeNamespace: - description: |- - volumeNamespace specifies the scope of the volume within StorageOS. If no - namespace is specified then the Pod's namespace will be used. This allows the - Kubernetes name scoping to be mirrored within StorageOS for tighter integration. - Set VolumeName to any name to override the default behaviour. - Set to "default" if you are not using namespaces within StorageOS. - Namespaces that do not pre-exist within StorageOS will be created. - type: string - type: object - vsphereVolume: - description: vsphereVolume represents a vSphere volume attached - and mounted on kubelets host machine - properties: - fsType: - description: |- - fsType is filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - storagePolicyID: - description: storagePolicyID is the storage Policy Based - Management (SPBM) profile ID associated with the StoragePolicyName. - type: string - storagePolicyName: - description: storagePolicyName is the storage Policy Based - Management (SPBM) profile name. - type: string - volumePath: - description: volumePath is the path that identifies vSphere - volume vmdk - type: string - required: - - volumePath - type: object - required: - - name - type: object - type: array - type: object - status: - description: MaxScaleStatus defines the observed state of MaxScale - properties: - conditions: - description: Conditions for the MaxScale object. - 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 - type: array - configSync: - description: ConfigSync is the state of config sync. - properties: - databaseVersion: - type: integer - maxScaleVersion: - type: integer - required: - - databaseVersion - - maxScaleVersion - type: object - listeners: - description: Listeners is the state of the listeners in the MaxScale - API. - items: - description: MaxScaleResourceStatus indicates whether the resource - is in a given state. - properties: - name: - type: string - state: - type: string - required: - - name - - state - type: object - type: array - monitor: - description: Monitor is the state of the monitor in the MaxScale API. - properties: - name: - type: string - state: - type: string - required: - - name - - state - type: object - primaryServer: - description: PrimaryServer is the primary server in the MaxScale API. - type: string - replicas: - description: Replicas indicates the number of current instances. - format: int32 - type: integer - servers: - description: Servers is the state of the servers in the MaxScale API. - items: - description: MaxScaleAPIStatus is the state of the servers in the - MaxScale API. - properties: - name: - type: string - state: - type: string - required: - - name - - state - type: object - type: array - services: - description: Services is the state of the services in the MaxScale - API. - items: - description: MaxScaleResourceStatus indicates whether the resource - is in a given state. - properties: - name: - type: string - state: - type: string - required: - - name - - state - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - scale: - specReplicasPath: .spec.replicas - statusReplicasPath: .status.replicas - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: restores.k8s.mariadb.com -spec: - group: k8s.mariadb.com - names: - kind: Restore - listKind: RestoreList - plural: restores - shortNames: - - rmdb - singular: restore - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Complete")].status - name: Complete - type: string - - jsonPath: .status.conditions[?(@.type=="Complete")].message - name: Status - type: string - - jsonPath: .spec.mariaDbRef.name - name: MariaDB - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: Restore is the Schema for the restores API. It is used to define - restore jobs and its restoration source. - 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: RestoreSpec defines the desired state of restore - properties: - affinity: - description: Affinity to be used in the Pod. - properties: - antiAffinityEnabled: - description: |- - AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. - Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. - type: boolean - nodeAffinity: - description: Describes node affinity scheduling rules for the - pod. - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - properties: - preference: - description: A node selector term, associated with the - corresponding weight. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding - nodeSelectorTerm, in the range 1-100. - format: int32 - type: integer - required: - - preference - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. - The terms are ORed. - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - type: array - x-kubernetes-list-type: atomic - required: - - nodeSelectorTerms - type: object - x-kubernetes-map-type: atomic - type: object - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate - this pod in the same node, zone, etc. as some other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated - with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. - avoid putting this pod in the same node, zone, etc. as some - other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated - with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - type: object - args: - description: Args to be used in the Container. - items: - type: string - type: array - backoffLimit: - default: 5 - description: BackoffLimit defines the maximum number of attempts to - successfully perform a Backup. - format: int32 - type: integer - backupRef: - description: BackupRef is a reference to a Backup object. It has priority - over S3 and Volume. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - database: - description: |- - Database defines the logical database to be restored. If not provided, all databases available in the backup are restored. - IMPORTANT: The database must previously exist. - type: string - imagePullSecrets: - description: ImagePullSecrets is the list of pull Secrets to be used - to pull the image. - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - inheritMetadata: - description: InheritMetadata defines the metadata to be inherited - by children resources. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - logLevel: - default: info - description: LogLevel to be used n the Backup Job. It defaults to - 'info'. - type: string - mariaDbRef: - description: MariaDBRef is a reference to a MariaDB object. - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - waitForIt: - default: true - description: WaitForIt indicates whether the controller using - this reference should wait for MariaDB to be ready. - type: boolean - type: object - x-kubernetes-map-type: atomic - nodeSelector: - additionalProperties: - type: string - description: NodeSelector to be used in the Pod. - type: object - podMetadata: - description: PodMetadata defines extra metadata for the Pod. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - podSecurityContext: - description: SecurityContext holds pod-level security attributes and - common container settings. - properties: - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies to - the container. - type: string - role: - description: Role is a SELinux role label that applies to - the container. - type: string - type: - description: Type is a SELinux type label that applies to - the container. - type: string - user: - description: User is a SELinux user label that applies to - the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in - addition to the container's primary GID and fsGroup (if specified). If - the SupplementalGroupsPolicy feature is enabled, the - supplementalGroupsPolicy field determines whether these are in addition - to or instead of any group memberships defined in the container image. - If unspecified, no additional groups are added, though group memberships - defined in the container image may still be used, depending on the - supplementalGroupsPolicy field. - Note that this field cannot be set when spec.os.name is windows. - items: - format: int64 - type: integer - type: array - x-kubernetes-list-type: atomic - supplementalGroupsPolicy: - description: |- - Defines how supplemental groups of the first container processes are calculated. - Valid values are "Merge" and "Strict". If not specified, "Merge" is used. - (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled - and the container runtime must implement support for this feature. - Note that this field cannot be set when spec.os.name is windows. - type: string - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - items: - description: Sysctl defines a kernel parameter to be set - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options within a container's SecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of the GMSA - credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - priorityClassName: - description: PriorityClassName to be used in the Pod. - type: string - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - restartPolicy: - default: OnFailure - description: RestartPolicy to be added to the Backup Job. - enum: - - Always - - OnFailure - - Never - type: string - s3: - description: S3 defines the configuration to restore backups from - a S3 compatible storage. It has priority over Volume. - properties: - accessKeyIdSecretKeyRef: - description: AccessKeyIdSecretKeyRef is a reference to a Secret - key containing the S3 access key id. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - bucket: - description: Bucket is the name Name of the bucket to store backups. - type: string - endpoint: - description: Endpoint is the S3 API endpoint without scheme. - type: string - prefix: - description: 'Prefix indicates a folder/subfolder in the bucket. - For example: mariadb/ or mariadb/backups. A trailing slash ''/'' - is added if not provided.' - type: string - region: - description: Region is the S3 region name to use. - type: string - secretAccessKeySecretKeyRef: - description: AccessKeyIdSecretKeyRef is a reference to a Secret - key containing the S3 secret key. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - sessionTokenSecretKeyRef: - description: SessionTokenSecretKeyRef is a reference to a Secret - key containing the S3 session token. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - tls: - description: TLS provides the configuration required to establish - TLS connections with S3. - properties: - caSecretKeyRef: - description: |- - CASecretKeyRef is a reference to a Secret key containing a CA bundle in PEM format used to establish TLS connections with S3. - By default, the system trust chain will be used, but you can use this field to add more CAs to the bundle. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - enabled: - description: Enabled is a flag to enable TLS. - type: boolean - type: object - required: - - accessKeyIdSecretKeyRef - - bucket - - endpoint - - secretAccessKeySecretKeyRef - type: object - securityContext: - description: SecurityContext holds security configuration that will - be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies to - the container. - type: string - role: - description: Role is a SELinux role label that applies to - the container. - type: string - type: - description: Type is a SELinux type label that applies to - the container. - type: string - user: - description: User is a SELinux user label that applies to - the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of the GMSA - credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to be used by the Pods. - type: string - targetRecoveryTime: - description: |- - TargetRecoveryTime is a RFC3339 (1970-01-01T00:00:00Z) date and time that defines the point in time recovery objective. - It is used to determine the closest restoration source in time. - format: date-time - type: string - tolerations: - description: Tolerations to be used in the Pod. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - volume: - description: Volume is a Kubernetes Volume object that contains a - backup. - properties: - awsElasticBlockStore: - description: |- - awsElasticBlockStore represents an AWS Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - format: int32 - type: integer - readOnly: - description: |- - readOnly value true will force the readOnly setting in VolumeMounts. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: boolean - volumeID: - description: |- - volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - type: string - required: - - volumeID - type: object - azureDisk: - description: azureDisk represents an Azure Data Disk mount on - the host and bind mount to the pod. - properties: - cachingMode: - description: 'cachingMode is the Host Caching mode: None, - Read Only, Read Write.' - type: string - diskName: - description: diskName is the Name of the data disk in the - blob storage - type: string - diskURI: - description: diskURI is the URI of data disk in the blob storage - type: string - fsType: - default: ext4 - description: |- - fsType is Filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - kind: - description: 'kind expected values are Shared: multiple blob - disks per storage account Dedicated: single blob disk per - storage account Managed: azure managed data disk (only - in managed availability set). defaults to shared' - type: string - readOnly: - default: false - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - required: - - diskName - - diskURI - type: object - azureFile: - description: azureFile represents an Azure File Service mount - on the host and bind mount to the pod. - properties: - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretName: - description: secretName is the name of secret that contains - Azure Storage Account Name and Key - type: string - shareName: - description: shareName is the azure share Name - type: string - required: - - secretName - - shareName - type: object - cephfs: - description: cephFS represents a Ceph FS mount on the host that - shares a pod's lifetime - properties: - monitors: - description: |- - monitors is Required: Monitors is a collection of Ceph monitors - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - path: - description: 'path is Optional: Used as the mounted root, - rather than the full Ceph tree, default is /' - type: string - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: boolean - secretFile: - description: |- - secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - secretRef: - description: |- - secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - description: |- - user is optional: User is the rados user name, default is admin - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it - type: string - required: - - monitors - type: object - cinder: - description: |- - cinder represents a cinder volume attached and mounted on kubelets host machine. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: boolean - secretRef: - description: |- - secretRef is optional: points to a secret object containing parameters used to connect - to OpenStack. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeID: - description: |- - volumeID used to identify the volume in cinder. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md - type: string - required: - - volumeID - type: object - configMap: - description: configMap represents a configMap that should populate - this volume - properties: - defaultMode: - description: |- - defaultMode is optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether the ConfigMap or its - keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - csi: - description: csi (Container Storage Interface) represents ephemeral - storage that is handled by certain external CSI drivers (Beta - feature). - properties: - driver: - description: |- - driver is the name of the CSI driver that handles this volume. - Consult with your admin for the correct name as registered in the cluster. - type: string - fsType: - description: |- - fsType to mount. Ex. "ext4", "xfs", "ntfs". - If not provided, the empty value is passed to the associated CSI driver - which will determine the default filesystem to apply. - type: string - nodePublishSecretRef: - description: |- - nodePublishSecretRef is a reference to the secret object containing - sensitive information to pass to the CSI driver to complete the CSI - NodePublishVolume and NodeUnpublishVolume calls. - This field is optional, and may be empty if no secret is required. If the - secret object contains more than one secret, all secret references are passed. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - readOnly: - description: |- - readOnly specifies a read-only configuration for the volume. - Defaults to false (read/write). - type: boolean - volumeAttributes: - additionalProperties: - type: string - description: |- - volumeAttributes stores driver-specific properties that are passed to the CSI - driver. Consult your driver's documentation for supported values. - type: object - required: - - driver - type: object - downwardAPI: - description: downwardAPI represents downward API about the pod - that should populate this volume - properties: - defaultMode: - description: |- - Optional: mode bits to use on created files by default. Must be a - Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: Items is a list of downward API volume file - items: - description: DownwardAPIVolumeFile represents information - to create the file containing the pod field - properties: - fieldRef: - description: 'Required: Selects a field of the pod: - only annotations, labels, name, namespace and uid - are supported.' - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the - specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path is the relative path name - of the file to be created. Must not be absolute or - contain the ''..'' path. Must be utf-8 encoded. The - first item of the relative path must not start with - ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the - exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - emptyDir: - description: |- - emptyDir represents a temporary directory that shares a pod's lifetime. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - properties: - medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - ephemeral: - description: |- - ephemeral represents a volume that is handled by a cluster storage driver. - The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, - and deleted when the pod is removed. - - Use this if: - a) the volume is only needed while the pod runs, - b) features of normal volumes like restoring from snapshot or capacity - tracking are needed, - c) the storage driver is specified through a storage class, and - d) the storage driver supports dynamic volume provisioning through - a PersistentVolumeClaim (see EphemeralVolumeSource for more - information on the connection between this volume type - and PersistentVolumeClaim). - - Use PersistentVolumeClaim or one of the vendor-specific - APIs for volumes that persist for longer than the lifecycle - of an individual pod. - - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to - be used that way - see the documentation of the driver for - more information. - - A pod can use both types of ephemeral volumes and - persistent volumes at the same time. - properties: - volumeClaimTemplate: - description: |- - Will be used to create a stand-alone PVC to provision the volume. - The pod in which this EphemeralVolumeSource is embedded will be the - owner of the PVC, i.e. the PVC will be deleted together with the - pod. The name of the PVC will be `-` where - `` is the name from the `PodSpec.Volumes` array - entry. Pod validation will reject the pod if the concatenated name - is not valid for a PVC (for example, too long). - - An existing PVC with that name that is not owned by the pod - will *not* be used for the pod to avoid using an unrelated - volume by mistake. Starting the pod is then blocked until - the unrelated PVC is removed. If such a pre-created PVC is - meant to be used by the pod, the PVC has to updated with an - owner reference to the pod once the pod exists. Normally - this should not be necessary, but it may be useful when - manually reconstructing a broken cluster. - - This field is read-only and no changes will be made by Kubernetes - to the PVC after it has been created. - - Required, must not be nil. - properties: - metadata: - description: |- - May contain labels and annotations that will be copied into the PVC - when creating it. No other fields are allowed and will be rejected during - validation. - type: object - spec: - description: |- - The specification for the PersistentVolumeClaim. The entire content is - copied unchanged into the PVC that gets created from this - template. The same fields as in a PersistentVolumeClaim - are also valid here. - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes - to consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to - the PersistentVolume backing this claim. - type: string - type: object - required: - - spec - type: object - type: object - fc: - description: fc represents a Fibre Channel resource that is attached - to a kubelet's host machine and then exposed to the pod. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - lun: - description: 'lun is Optional: FC target lun number' - format: int32 - type: integer - readOnly: - description: |- - readOnly is Optional: Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - targetWWNs: - description: 'targetWWNs is Optional: FC target worldwide - names (WWNs)' - items: - type: string - type: array - x-kubernetes-list-type: atomic - wwids: - description: |- - wwids Optional: FC volume world wide identifiers (wwids) - Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - flexVolume: - description: |- - flexVolume represents a generic volume resource that is - provisioned/attached using an exec based plugin. - properties: - driver: - description: driver is the name of the driver to use for this - volume. - type: string - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. - type: string - options: - additionalProperties: - type: string - description: 'options is Optional: this field holds extra - command options if any.' - type: object - readOnly: - description: |- - readOnly is Optional: defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef is Optional: secretRef is reference to the secret object containing - sensitive information to pass to the plugin scripts. This may be - empty if no secret object is specified. If the secret object - contains more than one secret, all secrets are passed to the plugin - scripts. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - required: - - driver - type: object - flocker: - description: flocker represents a Flocker volume attached to a - kubelet's host machine. This depends on the Flocker control - service being running - properties: - datasetName: - description: |- - datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker - should be considered as deprecated - type: string - datasetUUID: - description: datasetUUID is the UUID of the dataset. This - is unique identifier of a Flocker dataset - type: string - type: object - gcePersistentDisk: - description: |- - gcePersistentDisk represents a GCE Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - properties: - fsType: - description: |- - fsType is filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - partition: - description: |- - partition is the partition in the volume that you want to mount. - If omitted, the default is to mount by volume name. - Examples: For volume /dev/sda1, you specify the partition as "1". - Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - format: int32 - type: integer - pdName: - description: |- - pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - type: boolean - required: - - pdName - type: object - gitRepo: - description: |- - gitRepo represents a git repository at a particular revision. - DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an - EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir - into the Pod's container. - properties: - directory: - description: |- - directory is the target directory name. - Must not contain or start with '..'. If '.' is supplied, the volume directory will be the - git repository. Otherwise, if specified, the volume will contain the git repository in - the subdirectory with the given name. - type: string - repository: - description: repository is the URL - type: string - revision: - description: revision is the commit hash for the specified - revision. - type: string - required: - - repository - type: object - glusterfs: - description: |- - glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/glusterfs/README.md - properties: - endpoints: - description: |- - endpoints is the endpoint name that details Glusterfs topology. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - path: - description: |- - path is the Glusterfs volume path. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: string - readOnly: - description: |- - readOnly here will force the Glusterfs volume to be mounted with read-only permissions. - Defaults to false. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod - type: boolean - required: - - endpoints - - path - type: object - hostPath: - description: |- - hostPath represents a pre-existing file or directory on the host - machine that is directly exposed to the container. This is generally - used for system agents or other privileged things that are allowed - to see the host machine. Most containers will NOT need this. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - properties: - path: - description: |- - path of the directory on the host. - If the path is a symlink, it will follow the link to the real path. - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - type: - description: |- - type for HostPath Volume - Defaults to "" - More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - type: string - required: - - path - type: object - image: - description: |- - image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. - The volume is resolved at pod startup depending on which PullPolicy value is provided: - - - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - - The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. - A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. - 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). - The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. - properties: - pullPolicy: - description: |- - Policy for pulling OCI objects. Possible values are: - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. - Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. - type: string - reference: - description: |- - Required: Image or artifact reference to be used. - Behaves in the same way as pod.spec.containers[*].image. - Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. - More info: https://kubernetes.io/docs/concepts/containers/images - This field is optional to allow higher level config management to default or override - container images in workload controllers like Deployments and StatefulSets. - type: string - type: object - iscsi: - description: |- - iscsi represents an ISCSI Disk resource that is attached to a - kubelet's host machine and then exposed to the pod. - More info: https://examples.k8s.io/volumes/iscsi/README.md - properties: - chapAuthDiscovery: - description: chapAuthDiscovery defines whether support iSCSI - Discovery CHAP authentication - type: boolean - chapAuthSession: - description: chapAuthSession defines whether support iSCSI - Session CHAP authentication - type: boolean - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - type: string - initiatorName: - description: |- - initiatorName is the custom iSCSI Initiator Name. - If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface - : will be created for the connection. - type: string - iqn: - description: iqn is the target iSCSI Qualified Name. - type: string - iscsiInterface: - default: default - description: |- - iscsiInterface is the interface Name that uses an iSCSI transport. - Defaults to 'default' (tcp). - type: string - lun: - description: lun represents iSCSI Target Lun number. - format: int32 - type: integer - portals: - description: |- - portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - items: - type: string - type: array - x-kubernetes-list-type: atomic - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - type: boolean - secretRef: - description: secretRef is the CHAP Secret for iSCSI target - and initiator authentication - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - targetPortal: - description: |- - targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port - is other than default (typically TCP ports 860 and 3260). - type: string - required: - - iqn - - lun - - targetPortal - type: object - nfs: - description: |- - nfs represents an NFS mount on the host that shares a pod's lifetime - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - properties: - path: - description: |- - path that is exported by the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - readOnly: - description: |- - readOnly here will force the NFS export to be mounted with read-only permissions. - Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: boolean - server: - description: |- - server is the hostname or IP address of the NFS server. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs - type: string - required: - - path - - server - type: object - persistentVolumeClaim: - description: |- - persistentVolumeClaimVolumeSource represents a reference to a - PersistentVolumeClaim in the same namespace. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - claimName: - description: |- - claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - type: string - readOnly: - description: |- - readOnly Will force the ReadOnly setting in VolumeMounts. - Default false. - type: boolean - required: - - claimName - type: object - photonPersistentDisk: - description: photonPersistentDisk represents a PhotonController - persistent disk attached and mounted on kubelets host machine - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - pdID: - description: pdID is the ID that identifies Photon Controller - persistent disk - type: string - required: - - pdID - type: object - portworxVolume: - description: portworxVolume represents a portworx volume attached - and mounted on kubelets host machine - properties: - fsType: - description: |- - fSType represents the filesystem type to mount - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - volumeID: - description: volumeID uniquely identifies a Portworx volume - type: string - required: - - volumeID - type: object - projected: - description: projected items for all in one resources secrets, - configmaps, and downward API - properties: - defaultMode: - description: |- - defaultMode are the mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - sources: - description: |- - sources is the list of volume projections. Each entry in this list - handles one source. - items: - description: |- - Projection that may be projected along with other supported volume types. - Exactly one of these fields must be set. - properties: - clusterTrustBundle: - description: |- - ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field - of ClusterTrustBundle objects in an auto-updating file. - - Alpha, gated by the ClusterTrustBundleProjection feature gate. - - ClusterTrustBundle objects can either be selected by name, or by the - combination of signer name and a label selector. - - Kubelet performs aggressive normalization of the PEM contents written - into the pod filesystem. Esoteric PEM features such as inter-block - comments and block headers are stripped. Certificates are deduplicated. - The ordering of certificates within the file is arbitrary, and Kubelet - may change the order over time. - properties: - labelSelector: - description: |- - Select all ClusterTrustBundles that match this label selector. Only has - effect if signerName is set. Mutually-exclusive with name. If unset, - interpreted as "match nothing". If set but empty, interpreted as "match - everything". - 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 - name: - description: |- - Select a single ClusterTrustBundle by object name. Mutually-exclusive - with signerName and labelSelector. - type: string - optional: - description: |- - If true, don't block pod startup if the referenced ClusterTrustBundle(s) - aren't available. If using name, then the named ClusterTrustBundle is - allowed not to exist. If using signerName, then the combination of - signerName and labelSelector is allowed to match zero - ClusterTrustBundles. - type: boolean - path: - description: Relative path from the volume root - to write the bundle. - type: string - signerName: - description: |- - Select all ClusterTrustBundles that match this signer name. - Mutually-exclusive with name. The contents of all selected - ClusterTrustBundles will be unified and deduplicated. - type: string - required: - - path - type: object - configMap: - description: configMap information about the configMap - data to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - ConfigMap will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the ConfigMap, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional specify whether the ConfigMap - or its keys must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - downwardAPI: - description: downwardAPI information about the downwardAPI - data to project - properties: - items: - description: Items is a list of DownwardAPIVolume - file - items: - description: DownwardAPIVolumeFile represents - information to create the file containing the - pod field - properties: - fieldRef: - description: 'Required: Selects a field of - the pod: only annotations, labels, name, - namespace and uid are supported.' - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, defaults - to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - mode: - description: |- - Optional: mode bits used to set permissions on this file, must be an octal value - between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: 'Required: Path is the relative - path name of the file to be created. Must - not be absolute or contain the ''..'' path. - Must be utf-8 encoded. The first item of - the relative path must not start with ''..''' - type: string - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults to - "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - required: - - path - type: object - type: array - x-kubernetes-list-type: atomic - type: object - secret: - description: secret information about the secret data - to project - properties: - items: - description: |- - items if unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: optional field specify whether the - Secret or its key must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - serviceAccountToken: - description: serviceAccountToken is information about - the serviceAccountToken data to project - properties: - audience: - description: |- - audience is the intended audience of the token. A recipient of a token - must identify itself with an identifier specified in the audience of the - token, and otherwise should reject the token. The audience defaults to the - identifier of the apiserver. - type: string - expirationSeconds: - description: |- - expirationSeconds is the requested duration of validity of the service - account token. As the token approaches expiration, the kubelet volume - plugin will proactively rotate the service account token. The kubelet will - start trying to rotate the token if the token is older than 80 percent of - its time to live or if the token is older than 24 hours.Defaults to 1 hour - and must be at least 10 minutes. - format: int64 - type: integer - path: - description: |- - path is the path relative to the mount point of the file to project the - token into. - type: string - required: - - path - type: object - type: object - type: array - x-kubernetes-list-type: atomic - type: object - quobyte: - description: quobyte represents a Quobyte mount on the host that - shares a pod's lifetime - properties: - group: - description: |- - group to map volume access to - Default is no group - type: string - readOnly: - description: |- - readOnly here will force the Quobyte volume to be mounted with read-only permissions. - Defaults to false. - type: boolean - registry: - description: |- - registry represents a single or multiple Quobyte Registry services - specified as a string as host:port pair (multiple entries are separated with commas) - which acts as the central registry for volumes - type: string - tenant: - description: |- - tenant owning the given Quobyte volume in the Backend - Used with dynamically provisioned Quobyte volumes, value is set by the plugin - type: string - user: - description: |- - user to map volume access to - Defaults to serivceaccount user - type: string - volume: - description: volume is a string that references an already - created Quobyte volume by name. - type: string - required: - - registry - - volume - type: object - rbd: - description: |- - rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. - More info: https://examples.k8s.io/volumes/rbd/README.md - properties: - fsType: - description: |- - fsType is the filesystem type of the volume that you want to mount. - Tip: Ensure that the filesystem type is supported by the host operating system. - Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - type: string - image: - description: |- - image is the rados image name. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - keyring: - default: /etc/ceph/keyring - description: |- - keyring is the path to key ring for RBDUser. - Default is /etc/ceph/keyring. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - monitors: - description: |- - monitors is a collection of Ceph monitors. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - items: - type: string - type: array - x-kubernetes-list-type: atomic - pool: - default: rbd - description: |- - pool is the rados pool name. - Default is rbd. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - readOnly: - description: |- - readOnly here will force the ReadOnly setting in VolumeMounts. - Defaults to false. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: boolean - secretRef: - description: |- - secretRef is name of the authentication secret for RBDUser. If provided - overrides keyring. - Default is nil. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - user: - default: admin - description: |- - user is the rados user name. - Default is admin. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it - type: string - required: - - image - - monitors - type: object - scaleIO: - description: scaleIO represents a ScaleIO persistent volume attached - and mounted on Kubernetes nodes. - properties: - fsType: - default: xfs - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". - Default is "xfs". - type: string - gateway: - description: gateway is the host address of the ScaleIO API - Gateway. - type: string - protectionDomain: - description: protectionDomain is the name of the ScaleIO Protection - Domain for the configured storage. - type: string - readOnly: - description: |- - readOnly Defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef references to the secret for ScaleIO user and other - sensitive information. If this is not provided, Login operation will fail. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - sslEnabled: - description: sslEnabled Flag enable/disable SSL communication - with Gateway, default false - type: boolean - storageMode: - default: ThinProvisioned - description: |- - storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. - Default is ThinProvisioned. - type: string - storagePool: - description: storagePool is the ScaleIO Storage Pool associated - with the protection domain. - type: string - system: - description: system is the name of the storage system as configured - in ScaleIO. - type: string - volumeName: - description: |- - volumeName is the name of a volume already created in the ScaleIO system - that is associated with this volume source. - type: string - required: - - gateway - - secretRef - - system - type: object - secret: - description: |- - secret represents a secret that should populate this volume. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - properties: - defaultMode: - description: |- - defaultMode is Optional: mode bits used to set permissions on created files by default. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values - for mode bits. Defaults to 0644. - Directories within the path are not affected by this setting. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - items: - description: |- - items If unspecified, each key-value pair in the Data field of the referenced - Secret will be projected into the volume as a file whose name is the - key and content is the value. If specified, the listed keys will be - projected into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in the Secret, - the volume setup will error unless it is marked optional. Paths must be - relative and may not contain the '..' path or start with '..'. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: key is the key to project. - type: string - mode: - description: |- - mode is Optional: mode bits used to set permissions on this file. - Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. - YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. - If not specified, the volume defaultMode will be used. - This might be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits set. - format: int32 - type: integer - path: - description: |- - path is the relative path of the file to map the key to. - May not be an absolute path. - May not contain the path element '..'. - May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - x-kubernetes-list-type: atomic - optional: - description: optional field specify whether the Secret or - its keys must be defined - type: boolean - secretName: - description: |- - secretName is the name of the secret in the pod's namespace to use. - More info: https://kubernetes.io/docs/concepts/storage/volumes#secret - type: string - type: object - storageos: - description: storageOS represents a StorageOS volume attached - and mounted on Kubernetes nodes. - properties: - fsType: - description: |- - fsType is the filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: |- - readOnly defaults to false (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: |- - secretRef specifies the secret to use for obtaining the StorageOS API - credentials. If not specified, default values will be attempted. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - volumeName: - description: |- - volumeName is the human-readable name of the StorageOS volume. Volume - names are only unique within a namespace. - type: string - volumeNamespace: - description: |- - volumeNamespace specifies the scope of the volume within StorageOS. If no - namespace is specified then the Pod's namespace will be used. This allows the - Kubernetes name scoping to be mirrored within StorageOS for tighter integration. - Set VolumeName to any name to override the default behaviour. - Set to "default" if you are not using namespaces within StorageOS. - Namespaces that do not pre-exist within StorageOS will be created. - type: string - type: object - vsphereVolume: - description: vsphereVolume represents a vSphere volume attached - and mounted on kubelets host machine - properties: - fsType: - description: |- - fsType is filesystem type to mount. - Must be a filesystem type supported by the host operating system. - Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - storagePolicyID: - description: storagePolicyID is the storage Policy Based Management - (SPBM) profile ID associated with the StoragePolicyName. - type: string - storagePolicyName: - description: storagePolicyName is the storage Policy Based - Management (SPBM) profile name. - type: string - volumePath: - description: volumePath is the path that identifies vSphere - volume vmdk - type: string - required: - - volumePath - type: object - type: object - required: - - mariaDbRef - type: object - status: - description: RestoreStatus defines the observed state of restore - properties: - conditions: - description: Conditions for the Restore object. - 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 - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: sqljobs.k8s.mariadb.com -spec: - group: k8s.mariadb.com - names: - kind: SqlJob - listKind: SqlJobList - plural: sqljobs - shortNames: - - smdb - singular: sqljob - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Complete")].status - name: Complete - type: string - - jsonPath: .status.conditions[?(@.type=="Complete")].message - name: Status - type: string - - jsonPath: .spec.mariaDbRef.name - name: MariaDB - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: SqlJob is the Schema for the sqljobs API. It is used to run sql - scripts as jobs. - 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: SqlJobSpec defines the desired state of SqlJob - properties: - affinity: - description: Affinity to be used in the Pod. - properties: - antiAffinityEnabled: - description: |- - AntiAffinityEnabled configures PodAntiAffinity so each Pod is scheduled in a different Node, enabling HA. - Make sure you have at least as many Nodes available as the replicas to not end up with unscheduled Pods. - type: boolean - nodeAffinity: - description: Describes node affinity scheduling rules for the - pod. - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node matches the corresponding matchExpressions; the - node(s) with the highest sum are the most preferred. - items: - description: |- - An empty preferred scheduling term matches all objects with implicit weight 0 - (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). - properties: - preference: - description: A node selector term, associated with the - corresponding weight. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - weight: - description: Weight associated with matching the corresponding - nodeSelectorTerm, in the range 1-100. - format: int32 - type: integer - required: - - preference - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from its node. - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. - The terms are ORed. - items: - description: |- - A null or empty node selector term matches no objects. The requirements of - them are ANDed. - The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: |- - A node selector requirement is a selector that contains values, a key, and an operator - that relates the key and values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: |- - Represents a key's relationship to a set of values. - Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. - type: string - values: - description: |- - 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. If the operator is Gt or Lt, the values - array must have a single element, which will be interpreted as an integer. - 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 - type: object - x-kubernetes-map-type: atomic - type: array - x-kubernetes-list-type: atomic - required: - - nodeSelectorTerms - type: object - x-kubernetes-map-type: atomic - type: object - podAffinity: - description: Describes pod affinity scheduling rules (e.g. co-locate - this pod in the same node, zone, etc. as some other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated - with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules (e.g. - avoid putting this pod in the same node, zone, etc. as some - other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: |- - The scheduler will prefer to schedule pods to nodes that satisfy - the anti-affinity expressions specified by this field, but it may choose - a node that violates one or more of the expressions. The node that is - most preferred is the one with the greatest sum of weights, i.e. - for each node that meets all of the scheduling requirements (resource - request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the - node(s) with the highest sum are the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated - with the corresponding weight. - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: |- - weight associated with matching the corresponding podAffinityTerm, - in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - x-kubernetes-list-type: atomic - requiredDuringSchedulingIgnoredDuringExecution: - description: |- - If the anti-affinity requirements specified by this field are not met at - scheduling time, the pod will not be scheduled onto the node. - If the anti-affinity requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod label update), the - system may or may not try to eventually evict the pod from its node. - When there are multiple elements, the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all terms must be satisfied. - items: - description: |- - Defines a set of pods (namely those matching the labelSelector - relative to the given namespace(s)) that this pod should be - co-located (affinity) or not co-located (anti-affinity) with, - where co-located is defined as running on a node whose value of - the label with key matches that of any node on which - a pod of the set of pods is running - properties: - labelSelector: - description: |- - A label query over a set of resources, in this case pods. - If it's null, this PodAffinityTerm matches with no Pods. - 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 - matchLabelKeys: - description: |- - MatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - mismatchLabelKeys: - description: |- - MismatchLabelKeys is a set of pod label keys to select which pods will - be taken into consideration. The keys are used to lookup values from the - incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` - to select the group of existing pods which pods will be taken into consideration - for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming - 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 - x-kubernetes-list-type: atomic - namespaceSelector: - description: |- - A label query over the set of namespaces that the term applies to. - The term is applied to the union of the namespaces selected by this field - and the ones listed in the namespaces field. - null selector and null or empty namespaces list means "this pod's namespace". - An empty selector ({}) matches all namespaces. - 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 - namespaces: - description: |- - namespaces specifies a static list of namespace names that the term applies to. - The term is applied to the union of the namespaces listed in this field - and the ones selected by namespaceSelector. - null or empty namespaces list and null namespaceSelector means "this pod's namespace". - items: - type: string - type: array - x-kubernetes-list-type: atomic - topologyKey: - description: |- - This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching - the labelSelector in the specified namespaces, where co-located is defined as running on a node - whose value of the label with key topologyKey matches that of any node on which any of the - selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - x-kubernetes-list-type: atomic - type: object - type: object - args: - description: Args to be used in the Container. - items: - type: string - type: array - backoffLimit: - default: 5 - description: BackoffLimit defines the maximum number of attempts to - successfully execute a SqlJob. - format: int32 - type: integer - database: - description: Username to be used when executing the SqlJob. - type: string - dependsOn: - description: DependsOn defines dependencies with other SqlJob objectecs. - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - failedJobsHistoryLimit: - description: FailedJobsHistoryLimit defines the maximum number of - failed Jobs to be displayed. - format: int32 - minimum: 0 - type: integer - imagePullSecrets: - description: ImagePullSecrets is the list of pull Secrets to be used - to pull the image. - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - inheritMetadata: - description: InheritMetadata defines the metadata to be inherited - by children resources. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - mariaDbRef: - description: MariaDBRef is a reference to a MariaDB object. - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - waitForIt: - default: true - description: WaitForIt indicates whether the controller using - this reference should wait for MariaDB to be ready. - type: boolean - type: object - x-kubernetes-map-type: atomic - nodeSelector: - additionalProperties: - type: string - description: NodeSelector to be used in the Pod. - type: object - passwordSecretKeyRef: - description: UserPasswordSecretKeyRef is a reference to the impersonated - user's password to be used when executing the SqlJob. - properties: - key: - description: The key of the secret to select from. Must be a - valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - podMetadata: - description: PodMetadata defines extra metadata for the Pod. - properties: - annotations: - additionalProperties: - type: string - description: Annotations to be added to children resources. - type: object - labels: - additionalProperties: - type: string - description: Labels to be added to children resources. - type: object - type: object - podSecurityContext: - description: SecurityContext holds pod-level security attributes and - common container settings. - properties: - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - fsGroup: - description: |- - A special supplemental group that applies to all containers in a pod. - Some volume types allow the Kubelet to change the ownership of that volume - to be owned by the pod: - - 1. The owning GID will be the FSGroup - 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) - 3. The permission bits are OR'd with rw-rw---- - - If unset, the Kubelet will not modify the ownership and permissions of any volume. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - fsGroupChangePolicy: - description: |- - fsGroupChangePolicy defines behavior of changing ownership and permission of the volume - before being exposed inside Pod. This field will only apply to - volume types which support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types such as: secret, configmaps - and emptydir. - Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. - Note that this field cannot be set when spec.os.name is windows. - type: string - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in SecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence - for that container. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to all containers. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in SecurityContext. If set in - both SecurityContext and PodSecurityContext, the value specified in SecurityContext - takes precedence for that container. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies to - the container. - type: string - role: - description: Role is a SELinux role label that applies to - the container. - type: string - type: - description: Type is a SELinux type label that applies to - the container. - type: string - user: - description: User is a SELinux user label that applies to - the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by the containers in this pod. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - supplementalGroups: - description: |- - A list of groups applied to the first process run in each container, in - addition to the container's primary GID and fsGroup (if specified). If - the SupplementalGroupsPolicy feature is enabled, the - supplementalGroupsPolicy field determines whether these are in addition - to or instead of any group memberships defined in the container image. - If unspecified, no additional groups are added, though group memberships - defined in the container image may still be used, depending on the - supplementalGroupsPolicy field. - Note that this field cannot be set when spec.os.name is windows. - items: - format: int64 - type: integer - type: array - x-kubernetes-list-type: atomic - supplementalGroupsPolicy: - description: |- - Defines how supplemental groups of the first container processes are calculated. - Valid values are "Merge" and "Strict". If not specified, "Merge" is used. - (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled - and the container runtime must implement support for this feature. - Note that this field cannot be set when spec.os.name is windows. - type: string - sysctls: - description: |- - Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail to launch. - Note that this field cannot be set when spec.os.name is windows. - items: - description: Sysctl defines a kernel parameter to be set - properties: - name: - description: Name of a property to set - type: string - value: - description: Value of a property to set - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options within a container's SecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of the GMSA - credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - priorityClassName: - description: PriorityClassName to be used in the Pod. - type: string - resources: - description: Resouces describes the compute resource requirements. - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - restartPolicy: - default: OnFailure - description: RestartPolicy to be added to the SqlJob Pod. - enum: - - Always - - OnFailure - - Never - type: string - schedule: - description: Schedule defines when the SqlJob will be executed. - properties: - cron: - description: Cron is a cron expression that defines the schedule. - type: string - suspend: - default: false - description: Suspend defines whether the schedule is active or - not. - type: boolean - required: - - cron - type: object - securityContext: - description: SecurityContext holds security configuration that will - be applied to a container. - properties: - allowPrivilegeEscalation: - description: |- - AllowPrivilegeEscalation controls whether a process can gain more - privileges than its parent process. This bool directly controls if - the no_new_privs flag will be set on the container process. - AllowPrivilegeEscalation is true always when the container is: - 1) run as Privileged - 2) has CAP_SYS_ADMIN - Note that this field cannot be set when spec.os.name is windows. - type: boolean - appArmorProfile: - description: |- - appArmorProfile is the AppArmor options to use by this container. If set, this profile - overrides the pod's appArmorProfile. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile loaded on the node that should be used. - The profile must be preconfigured on the node to work. - Must match the loaded name of the profile. - Must be set if and only if type is "Localhost". - type: string - type: - description: |- - type indicates which kind of AppArmor profile will be applied. - Valid options are: - Localhost - a profile pre-loaded on the node. - RuntimeDefault - the container runtime's default profile. - Unconfined - no AppArmor enforcement. - type: string - required: - - type - type: object - capabilities: - description: |- - The capabilities to add/drop when running containers. - Defaults to the default set of capabilities granted by the container runtime. - Note that this field cannot be set when spec.os.name is windows. - properties: - add: - description: Added capabilities - items: - description: Capability represent POSIX capabilities type - type: string - type: array - x-kubernetes-list-type: atomic - drop: - description: Removed capabilities - items: - description: Capability represent POSIX capabilities type - type: string - type: array - x-kubernetes-list-type: atomic - type: object - privileged: - description: |- - Run container in privileged mode. - Processes in privileged containers are essentially equivalent to root on the host. - Defaults to false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - procMount: - description: |- - procMount denotes the type of proc mount to use for the containers. - The default value is Default which uses the container runtime defaults for - readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. - Note that this field cannot be set when spec.os.name is windows. - type: string - readOnlyRootFilesystem: - description: |- - Whether this container has a read-only root filesystem. - Default is false. - Note that this field cannot be set when spec.os.name is windows. - type: boolean - runAsGroup: - description: |- - The GID to run the entrypoint of the container process. - Uses runtime default if unset. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - runAsNonRoot: - description: |- - Indicates that the container must run as a non-root user. - If true, the Kubelet will validate the image at runtime to ensure that it - does not run as UID 0 (root) and fail to start the container if it does. - If unset or false, no such validation will be performed. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: boolean - runAsUser: - description: |- - The UID to run the entrypoint of the container process. - Defaults to user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - format: int64 - type: integer - seLinuxOptions: - description: |- - The SELinux context to be applied to the container. - If unspecified, the container runtime will allocate a random SELinux context for each - container. May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is windows. - properties: - level: - description: Level is SELinux level label that applies to - the container. - type: string - role: - description: Role is a SELinux role label that applies to - the container. - type: string - type: - description: Type is a SELinux type label that applies to - the container. - type: string - user: - description: User is a SELinux user label that applies to - the container. - type: string - type: object - seccompProfile: - description: |- - The seccomp options to use by this container. If seccomp options are - provided at both the pod & container level, the container options - override the pod options. - Note that this field cannot be set when spec.os.name is windows. - properties: - localhostProfile: - description: |- - localhostProfile indicates a profile defined in a file on the node should be used. - The profile must be preconfigured on the node to work. - Must be a descending path, relative to the kubelet's configured seccomp profile location. - Must be set if type is "Localhost". Must NOT be set for any other type. - type: string - type: - description: |- - type indicates which kind of seccomp profile will be applied. - Valid options are: - - Localhost - a profile defined in a file on the node should be used. - RuntimeDefault - the container runtime default profile should be used. - Unconfined - no profile should be applied. - type: string - required: - - type - type: object - windowsOptions: - description: |- - The Windows specific settings applied to all containers. - If unspecified, the options from the PodSecurityContext will be used. - If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. - Note that this field cannot be set when spec.os.name is linux. - properties: - gmsaCredentialSpec: - description: |- - GMSACredentialSpec is where the GMSA admission webhook - (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the - GMSA credential spec named by the GMSACredentialSpecName field. - type: string - gmsaCredentialSpecName: - description: GMSACredentialSpecName is the name of the GMSA - credential spec to use. - type: string - hostProcess: - description: |- - HostProcess determines if a container should be run as a 'Host Process' container. - All of a Pod's containers must have the same effective HostProcess value - (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). - In addition, if HostProcess is true then HostNetwork must also be set to true. - type: boolean - runAsUserName: - description: |- - The UserName in Windows to run the entrypoint of the container process. - Defaults to the user specified in image metadata if unspecified. - May also be set in PodSecurityContext. If set in both SecurityContext and - PodSecurityContext, the value specified in SecurityContext takes precedence. - type: string - type: object - type: object - serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to be used by the Pods. - type: string - sql: - description: Sql is the script to be executed by the SqlJob. - type: string - sqlConfigMapKeyRef: - description: |- - SqlConfigMapKeyRef is a reference to a ConfigMap containing the Sql script. - It is defaulted to a ConfigMap with the contents of the Sql field. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - successfulJobsHistoryLimit: - description: SuccessfulJobsHistoryLimit defines the maximum number - of successful Jobs to be displayed. - format: int32 - minimum: 0 - type: integer - timeZone: - description: TimeZone defines the timezone associated with the cron - expression. - type: string - tolerations: - description: Tolerations to be used in the Pod. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - username: - description: Username to be impersonated when executing the SqlJob. - type: string - required: - - mariaDbRef - - passwordSecretKeyRef - - username - type: object - status: - description: SqlJobStatus defines the observed state of SqlJob - properties: - conditions: - description: Conditions for the SqlJob object. - 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 - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.16.1 - name: users.k8s.mariadb.com -spec: - group: k8s.mariadb.com - names: - kind: User - listKind: UserList - plural: users - shortNames: - - umdb - singular: user - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].message - name: Status - type: string - - jsonPath: .spec.maxUserConnections - name: MaxConns - type: string - - jsonPath: .spec.mariaDbRef.name - name: MariaDB - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: User is the Schema for the users API. It is used to define grants - as if you were running a 'CREATE USER' statement. - 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: UserSpec defines the desired state of User - properties: - cleanupPolicy: - description: CleanupPolicy defines the behavior for cleaning up a - SQL resource. - enum: - - Skip - - Delete - type: string - host: - description: Host related to the User. - maxLength: 255 - type: string - mariaDbRef: - description: MariaDBRef is a reference to a MariaDB object. - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: |- - If referring to a piece of an object instead of an entire object, this string - should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within a pod, this would take on a value like: - "spec.containers{name}" (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" (container with - index 2 in this pod). This syntax is chosen only to have some well-defined way of - referencing a part of an object. - type: string - kind: - description: |- - Kind of the referent. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - type: string - name: - description: |- - Name of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - namespace: - description: |- - Namespace of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ - type: string - resourceVersion: - description: |- - Specific resourceVersion to which this reference is made, if any. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency - type: string - uid: - description: |- - UID of the referent. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids - type: string - waitForIt: - default: true - description: WaitForIt indicates whether the controller using - this reference should wait for MariaDB to be ready. - type: boolean - type: object - x-kubernetes-map-type: atomic - maxUserConnections: - default: 10 - description: MaxUserConnections defines the maximum number of connections - that the User can establish. - format: int32 - type: integer - name: - description: Name overrides the default name provided by metadata.name. - maxLength: 80 - type: string - passwordHashSecretKeyRef: - description: |- - PasswordHashSecretKeyRef is a reference to the password hash to be used by the User. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password hash. - properties: - key: - description: The key of the secret to select from. Must be a - valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - passwordPlugin: - description: PasswordPlugin is a reference to the password plugin - and arguments to be used by the User. - properties: - pluginArgSecretKeyRef: - description: |- - PluginArgSecretKeyRef is a reference to the arguments to be provided to the authentication plugin for the User. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the authentication plugin arguments. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - pluginNameSecretKeyRef: - description: |- - PluginNameSecretKeyRef is a reference to the authentication plugin to be used by the User. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the authentication plugin. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - passwordSecretKeyRef: - description: |- - PasswordSecretKeyRef is a reference to the password to be used by the User. - If not provided, the account will be locked and the password will expire. - If the referred Secret is labeled with "k8s.mariadb.com/watch", updates may be performed to the Secret in order to update the password. - properties: - key: - description: The key of the secret to select from. Must be a - valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - requeueInterval: - description: RequeueInterval is used to perform requeue reconciliations. - type: string - retryInterval: - description: RetryInterval is the interval used to perform retries. - type: string - required: - - mariaDbRef - type: object - status: - description: UserStatus defines the observed state of User - properties: - conditions: - description: Conditions for the User object. - 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 - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/NOTES.txt b/packages/system/mariadb-operator/charts/mariadb-operator/templates/NOTES.txt index ff5e0bb1..d6a89cfb 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/NOTES.txt +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/NOTES.txt @@ -1,4 +1,4 @@ mariadb-operator has been successfully deployed! 🦭 Not sure what to do next? 😅 Check out: -https://github.com/mariadb-operator/mariadb-operator#quickstart \ No newline at end of file +https://github.com/mariadb-operator/mariadb-operator/blob/main/docs/quickstart.md diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/_helpers.tpl b/packages/system/mariadb-operator/charts/mariadb-operator/templates/_helpers.tpl index 597b9d5d..f842340b 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/_helpers.tpl +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/_helpers.tpl @@ -56,9 +56,9 @@ Webhook common labels {{- define "mariadb-operator-webhook.labels" -}} helm.sh/chart: {{ include "mariadb-operator.chart" . }} {{ include "mariadb-operator-webhook.selectorLabels" . }} -{{ if .Chart.AppVersion }} +{{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{ end }} +{{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end }} @@ -104,9 +104,9 @@ Cert-controller common labels {{- define "mariadb-operator-cert-controller.labels" -}} helm.sh/chart: {{ include "mariadb-operator.chart" . }} {{ include "mariadb-operator-cert-controller.selectorLabels" . }} -{{ if .Chart.AppVersion }} +{{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{ end }} +{{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end }} @@ -149,4 +149,22 @@ Create the name of the cert-controller service account to use {{- else }} {{- default "default" .Values.certController.serviceAccount.name }} {{- end }} +{{- end }} + +{{/* +Util function for generating the image URL based on the provided options. +*/}} +{{- define "image" -}} + {{- $defaultTag := index . 1 -}} + {{- with index . 0 -}} + {{- $repository := .repository | default "" -}} + {{- $digest := .digest -}} + {{- $tag := default $defaultTag .tag -}} + {{- printf "%s" $repository }} + {{- if $digest -}} + {{ printf "@%s" $digest }} + {{- else -}} + {{ printf ":%s" $tag }} + {{- end -}} + {{- end }} {{- end }} \ No newline at end of file diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller-deployment.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller/deployment.yaml similarity index 67% rename from packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller-deployment.yaml rename to packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller/deployment.yaml index 0afbbae1..f823f45e 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller-deployment.yaml +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller/deployment.yaml @@ -1,25 +1,25 @@ -{{- if and .Values.certController.enabled (not .Values.webhook.cert.certManager.enabled) -}} +{{- if and (not .Values.currentNamespaceOnly) .Values.certController.enabled (not .Values.webhook.cert.certManager.enabled) -}} apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "mariadb-operator.fullname" . }}-cert-controller labels: - {{ include "mariadb-operator-cert-controller.labels" . | nindent 4 }} + {{- include "mariadb-operator-cert-controller.labels" . | nindent 4 }} spec: - {{ if .Values.certController.ha.enabled }} + {{- if .Values.certController.ha.enabled }} replicas: {{ .Values.certController.ha.replicas}} - {{ end }} + {{- end }} selector: matchLabels: - {{ include "mariadb-operator-cert-controller.selectorLabels" . | nindent 6 }} + {{- include "mariadb-operator-cert-controller.selectorLabels" . | nindent 6 }} template: metadata: - {{ with .Values.certController.podAnnotations }} + {{- with .Values.certController.podAnnotations }} annotations: {{ toYaml . | nindent 8 }} - {{ end }} + {{- end }} labels: - {{ include "mariadb-operator-cert-controller.selectorLabels" . | nindent 8 }} + {{- include "mariadb-operator-cert-controller.selectorLabels" . | nindent 8 }} spec: {{- with .Values.certController.imagePullSecrets }} imagePullSecrets: @@ -27,35 +27,42 @@ spec: {{- end }} serviceAccountName: {{ include "mariadb-operator-cert-controller.serviceAccountName" . }}-cert-controller automountServiceAccountToken: {{ .Values.certController.serviceAccount.automount }} - {{ with .Values.certController.nodeSelector }} + {{- with .Values.certController.nodeSelector }} nodeSelector: {{ toYaml . | nindent 8 }} - {{ end }} - {{ with .Values.certController.tolerations }} + {{- end }} + {{- with .Values.certController.tolerations }} tolerations: {{ toYaml . | nindent 8 }} - {{ end }} - {{ with .Values.certController.affinity }} + {{- end }} + {{- with .Values.certController.topologySpreadConstraints }} + topologySpreadConstraints: + {{ toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.certController.priorityClassName }} + priorityClassName: {{ . | quote }} + {{- end }} + {{- with .Values.certController.affinity }} affinity: {{ toYaml . | nindent 8 }} - {{ end }} - {{ with .Values.certController.podSecurityContext }} + {{- end }} + {{- with .Values.certController.podSecurityContext }} securityContext: {{ toYaml . | nindent 8 }} - {{ end }} + {{- end }} containers: - - image: "{{ .Values.certController.image.repository }}:{{ .Values.certController.image.tag | default .Chart.AppVersion }}" + - image: "{{ template "image" (tuple .Values.certController.image $.Chart.AppVersion) }}" imagePullPolicy: {{ .Values.certController.image.pullPolicy }} name: cert-controller args: - cert-controller - --ca-secret-name={{ include "mariadb-operator.fullname" . }}-webhook-ca - --ca-secret-namespace={{ .Release.Namespace }} - - --ca-validity={{ .Values.certController.caValidity }} + - --ca-lifetime={{ .Values.certController.caLifetime }} - --cert-secret-name={{ include "mariadb-operator.fullname" . }}-webhook-cert - --cert-secret-namespace={{ .Release.Namespace }} - - --cert-validity={{ .Values.certController.certValidity }} - - --lookahead-validity={{ .Values.certController.lookaheadValidity }} + - --cert-lifetime={{ .Values.certController.certLifetime }} + - --renew-before-percentage={{ .Values.certController.renewBeforePercentage }} - --service-name={{ include "mariadb-operator.fullname" . }}-webhook - --service-namespace={{ .Release.Namespace }} - --requeue-duration={{ .Values.certController.requeueDuration }} @@ -100,4 +107,4 @@ spec: volumes: {{- toYaml . | nindent 8 }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller/pdb.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller/pdb.yaml new file mode 100644 index 00000000..01e73eb1 --- /dev/null +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller/pdb.yaml @@ -0,0 +1,13 @@ +{{- if and (not .Values.currentNamespaceOnly) .Values.certController.enabled (not .Values.webhook.cert.certManager.enabled) .Values.certController.pdb.enabled -}} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "mariadb-operator.fullname" . }}-cert-controller + labels: + {{ include "mariadb-operator-cert-controller.labels" . | nindent 4 }} +spec: + maxUnavailable: {{ .Values.certController.pdb.maxUnavailable }} + selector: + matchLabels: + {{ include "mariadb-operator-cert-controller.selectorLabels" . | nindent 6 }} +{{- end }} diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller-rbac.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller/rbac.yaml similarity index 87% rename from packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller-rbac.yaml rename to packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller/rbac.yaml index 347e72b7..7b5fa835 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller-rbac.yaml +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller/rbac.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.rbac.enabled .Values.certController.enabled (not .Values.webhook.cert.certManager.enabled) -}} +{{- if and (not .Values.currentNamespaceOnly) .Values.rbac.enabled .Values.certController.enabled (not .Values.webhook.cert.certManager.enabled) -}} {{ $fullName := include "mariadb-operator.fullname" . }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role @@ -51,10 +51,10 @@ rules: - patch - watch - apiGroups: - - "" + - discovery.k8s.io resources: - - endpoints - - endpoints/restricted + - endpointslices + - endpointslices/restricted verbs: - get - list diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller-serviceaccount.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller/serviceaccount.yaml similarity index 77% rename from packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller-serviceaccount.yaml rename to packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller/serviceaccount.yaml index 02588ca3..1bea8a83 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller-serviceaccount.yaml +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller/serviceaccount.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.certController.enabled (not .Values.webhook.cert.certManager.enabled) -}} +{{- if and (not .Values.currentNamespaceOnly) .Values.certController.enabled (not .Values.webhook.cert.certManager.enabled) -}} apiVersion: v1 kind: ServiceAccount metadata: diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller-servicemonitor.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller/servicemonitor.yaml similarity index 64% rename from packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller-servicemonitor.yaml rename to packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller/servicemonitor.yaml index 5cddac5b..e5338099 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller-servicemonitor.yaml +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/cert-controller/servicemonitor.yaml @@ -1,4 +1,4 @@ -{{ if and .Values.certController.enabled (not .Values.webhook.cert.certManager.enabled) .Values.metrics.enabled .Values.certController.serviceMonitor.enabled }} +{{ if and (not .Values.currentNamespaceOnly) .Values.certController.enabled (not .Values.webhook.cert.certManager.enabled) .Values.metrics.enabled .Values.certController.serviceMonitor.enabled }} apiVersion: v1 kind: Service metadata: @@ -33,4 +33,12 @@ spec: - port: metrics interval: {{ .Values.certController.serviceMonitor.interval }} scrapeTimeout: {{ .Values.certController.serviceMonitor.scrapeTimeout }} -{{ end }} \ No newline at end of file + {{- if .Values.certController.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml .Values.certController.serviceMonitor.metricRelabelings | nindent 6 }} + {{- end }} + {{- if .Values.certController.serviceMonitor.relabelings }} + relabelings: + {{- toYaml .Values.certController.serviceMonitor.relabelings | nindent 6 }} + {{- end }} +{{ end }} diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/configmap.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/configmap.yaml deleted file mode 100644 index c6e5796b..00000000 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/configmap.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -data: - MARIADB_ENTRYPOINT_VERSION: "11.4" - MARIADB_GALERA_LIB_PATH: /usr/lib/galera/libgalera_smm.so - MARIADB_OPERATOR_IMAGE: docker-registry3.mariadb.com/mariadb-operator/mariadb-operator:v0.0.30 - RELATED_IMAGE_EXPORTER: prom/mysqld-exporter:v0.15.1 - RELATED_IMAGE_EXPORTER_MAXSCALE: docker-registry2.mariadb.com/mariadb/maxscale-prometheus-exporter-ubi:v0.0.1 - RELATED_IMAGE_MARIADB: docker-registry1.mariadb.com/library/mariadb:11.4.3 - RELATED_IMAGE_MAXSCALE: docker-registry2.mariadb.com/mariadb/maxscale:23.08.5 -kind: ConfigMap -metadata: - creationTimestamp: null - name: mariadb-operator-env diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/configmap.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/configmap.yaml new file mode 100644 index 00000000..88acb245 --- /dev/null +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/configmap.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +data: + MARIADB_OPERATOR_IMAGE: "{{ template "image" (tuple .Values.image $.Chart.AppVersion) }}" + MARIADB_GALERA_LIB_PATH: "{{ .Values.config.galeraLibPath }}" + MARIADB_DEFAULT_VERSION: "{{ .Values.config.mariadbDefaultVersion }}" + RELATED_IMAGE_MARIADB: "{{ .Values.config.mariadbImage }}" + RELATED_IMAGE_MARIADB_NAME: "{{ .Values.config.mariadbImageName }}" + RELATED_IMAGE_MAXSCALE: "{{ .Values.config.maxscaleImage }}" + RELATED_IMAGE_EXPORTER: "{{ .Values.config.exporterImage }}" + RELATED_IMAGE_EXPORTER_MAXSCALE: "{{ .Values.config.exporterMaxscaleImage }}" +kind: ConfigMap +metadata: + creationTimestamp: null + name: mariadb-operator-env diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/deployment.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/deployment.yaml similarity index 66% rename from packages/system/mariadb-operator/charts/mariadb-operator/templates/deployment.yaml rename to packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/deployment.yaml index b44499ba..a194a960 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/deployment.yaml +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/deployment.yaml @@ -3,22 +3,22 @@ kind: Deployment metadata: name: {{ include "mariadb-operator.fullname" . }} labels: - {{ include "mariadb-operator.labels" . | nindent 4 }} + {{- include "mariadb-operator.labels" . | nindent 4 }} spec: - {{ if .Values.ha.enabled }} + {{- if .Values.ha.enabled }} replicas: {{ .Values.ha.replicas}} - {{ end }} + {{- end }} selector: matchLabels: - {{ include "mariadb-operator.selectorLabels" . | nindent 6 }} + {{- include "mariadb-operator.selectorLabels" . | nindent 6 }} template: metadata: - {{ with .Values.podAnnotations }} + {{- with .Values.podAnnotations }} annotations: {{ toYaml . | nindent 8 }} - {{ end }} + {{- end }} labels: - {{ include "mariadb-operator.selectorLabels" . | nindent 8 }} + {{- include "mariadb-operator.selectorLabels" . | nindent 8 }} spec: {{- with .Values.imagePullSecrets }} imagePullSecrets: @@ -27,24 +27,31 @@ spec: serviceAccountName: {{ include "mariadb-operator.serviceAccountName" . }} automountServiceAccountToken: {{ .Values.serviceAccount.automount }} terminationGracePeriodSeconds: 10 - {{ with .Values.nodeSelector }} + {{- with .Values.nodeSelector }} nodeSelector: {{ toYaml . | nindent 8 }} - {{ end }} - {{ with .Values.tolerations }} + {{- end }} + {{- with .Values.tolerations }} tolerations: {{ toYaml . | nindent 8 }} - {{ end }} - {{ with .Values.affinity }} + {{- end }} + {{- with .Values.topologySpreadConstraints }} + topologySpreadConstraints: + {{ toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.priorityClassName }} + priorityClassName: {{ . | quote }} + {{- end }} + {{- with .Values.affinity }} affinity: {{ toYaml . | nindent 8 }} - {{ end }} - {{ with .Values.podSecurityContext }} + {{- end }} + {{- with .Values.podSecurityContext }} securityContext: {{ toYaml . | nindent 8 }} - {{ end }} + {{- end }} containers: - - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + - image: "{{ template "image" (tuple .Values.image $.Chart.AppVersion) }}" imagePullPolicy: {{ .Values.image.pullPolicy }} name: controller args: @@ -53,6 +60,10 @@ spec: {{- if .Values.ha.enabled }} - --leader-elect {{- end }} + {{- if .Values.pprof.enabled }} + - --pprof + - --pprof-addr=:{{ .Values.pprof.port | int }} + {{- end }} {{- range .Values.extraArgs }} - {{ . }} {{- end }} @@ -60,6 +71,11 @@ spec: - containerPort: 8080 protocol: TCP name: metrics + {{- if .Values.pprof.enabled }} + - containerPort: {{ .Values.pprof.port }} + protocol: TCP + name: pprof + {{- end }} envFrom: - configMapRef: name: mariadb-operator-env @@ -69,6 +85,10 @@ spec: env: - name: CLUSTER_NAME value: {{ .Values.clusterName }} + {{- if .Values.currentNamespaceOnly }} + - name: WATCH_NAMESPACE + value: {{ .Release.Namespace }} + {{- end }} - name: MARIADB_OPERATOR_NAME valueFrom: fieldRef: diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/metrics-servicemonitor.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/metrics-servicemonitor.yaml similarity index 74% rename from packages/system/mariadb-operator/charts/mariadb-operator/templates/metrics-servicemonitor.yaml rename to packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/metrics-servicemonitor.yaml index 8fb37602..3f1393fe 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/metrics-servicemonitor.yaml +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/metrics-servicemonitor.yaml @@ -33,4 +33,12 @@ spec: - port: metrics interval: {{ .Values.metrics.serviceMonitor.interval }} scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }} -{{ end }} \ No newline at end of file + {{- if .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml .Values.metrics.serviceMonitor.metricRelabelings | nindent 6 }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.relabelings }} + relabelings: + {{- toYaml .Values.metrics.serviceMonitor.relabelings | nindent 6 }} + {{- end }} +{{ end }} diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/pdb.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/pdb.yaml new file mode 100644 index 00000000..deeba513 --- /dev/null +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/pdb.yaml @@ -0,0 +1,13 @@ +{{- if .Values.pdb.enabled }} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "mariadb-operator.fullname" . }} + labels: + {{ include "mariadb-operator.labels" . | nindent 4 }} +spec: + maxUnavailable: {{ .Values.pdb.maxUnavailable }} + selector: + matchLabels: + {{ include "mariadb-operator.selectorLabels" . | nindent 6 }} +{{- end }} diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/rbac-namespace.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/rbac-namespace.yaml new file mode 100644 index 00000000..3ef1b760 --- /dev/null +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/rbac-namespace.yaml @@ -0,0 +1,255 @@ +{{- if and .Values.currentNamespaceOnly .Values.rbac.enabled -}} +{{ $fullName := include "mariadb-operator.fullname" . }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ $fullName }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +- apiGroups: + - "" + resources: + - events + - secrets + - serviceaccounts + - services + verbs: + - create + - list + - patch + - watch +- apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - create + - delete + - deletecollection + - list + - patch + - watch +- apiGroups: + - "" + resources: + - pods + verbs: + - delete + - get + - list + - watch + - patch +- apiGroups: + - "" + resources: + - pods/log + verbs: + - get +- apiGroups: + - apps + resources: + - deployments + verbs: + - create + - list + - patch + - watch +- apiGroups: + - apps + resources: + - statefulsets + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: + - batch + resources: + - cronjobs + verbs: + - create + - list + - patch + - watch +- apiGroups: + - batch + resources: + - jobs + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: + - cert-manager.io + resources: + - certificates + verbs: + - create + - list + - patch + - watch +- apiGroups: + - discovery.k8s.io + resources: + - endpointslices + - endpointslices/restricted + verbs: + - create + - get + - list + - patch + - watch +- apiGroups: + - k8s.mariadb.com + resources: + - backups + - connections + - databases + - grants + - mariadbs + - externalmariadbs + - maxscales + - physicalbackups + - restores + - sqljobs + - users + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - k8s.mariadb.com + resources: + - backups/finalizers + - connections/finalizers + - databases/finalizers + - grants/finalizers + - mariadbs/finalizers + - externalmariadbs/finalizers + - maxscales/finalizers + - physicalbackups/finalizers + - restores/finalizers + - sqljobs/finalizers + - users/finalizers + verbs: + - update +- apiGroups: + - k8s.mariadb.com + resources: + - backups/status + - connections/status + - databases/status + - grants/status + - mariadbs/status + - externalmariadbs/status + - maxscales/status + - physicalbackups/status + - restores/status + - sqljobs/status + - users/status + verbs: + - get + - patch + - update +- apiGroups: + - k8s.mariadb.com + resources: + - maxscale + verbs: + - create + - list + - patch + - watch +- apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + verbs: + - create + - list + - patch + - watch +- apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - create + - list + - patch + - watch +- apiGroups: + - rbac.authorization.k8s.io + resources: + - rolebindings + - roles + verbs: + - create + - list + - patch + - watch +- apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshots + verbs: + - create + - delete + - get + - list + - patch + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ $fullName }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ $fullName }} +subjects: +- kind: ServiceAccount + name: {{ include "mariadb-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/rbac-user.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/rbac-user.yaml similarity index 92% rename from packages/system/mariadb-operator/charts/mariadb-operator/templates/rbac-user.yaml rename to packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/rbac-user.yaml index df049444..f9284cfe 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/rbac-user.yaml +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/rbac-user.yaml @@ -1,4 +1,4 @@ -{{- if .Values.rbac.enabled -}} +{{- if and (not .Values.currentNamespaceOnly) .Values.rbac.enabled -}} {{ $fullName := include "mariadb-operator.fullname" . }} # the mariadb-view ClusterRole allows viewing all k8s.mariadb.com resources apiVersion: rbac.authorization.k8s.io/v1 diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/rbac.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/rbac.yaml similarity index 87% rename from packages/system/mariadb-operator/charts/mariadb-operator/templates/rbac.yaml rename to packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/rbac.yaml index 7bb86cc9..600c6a72 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/rbac.yaml +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/rbac.yaml @@ -1,4 +1,4 @@ -{{- if .Values.rbac.enabled -}} +{{- if and (not .Values.currentNamespaceOnly) .Values.rbac.enabled -}} {{ $fullName := include "mariadb-operator.fullname" . }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role @@ -53,17 +53,6 @@ rules: - list - patch - watch -- apiGroups: - - "" - resources: - - endpoints - - endpoints/restricted - verbs: - - create - - get - - list - - patch - - watch - apiGroups: - "" resources: @@ -82,6 +71,7 @@ rules: - persistentvolumeclaims verbs: - create + - delete - deletecollection - list - patch @@ -95,6 +85,7 @@ rules: - get - list - watch + - patch - apiGroups: - "" resources: @@ -149,6 +140,27 @@ rules: verbs: - create - delete + - get + - list + - patch + - watch +- apiGroups: + - cert-manager.io + resources: + - certificates + verbs: + - create + - list + - patch + - watch +- apiGroups: + - discovery.k8s.io + resources: + - endpointslices + - endpointslices/restricted + verbs: + - create + - get - list - patch - watch @@ -160,7 +172,9 @@ rules: - databases - grants - mariadbs + - externalmariadbs - maxscales + - physicalbackups - restores - sqljobs - users @@ -180,7 +194,9 @@ rules: - databases/finalizers - grants/finalizers - mariadbs/finalizers + - externalmariadbs/finalizers - maxscales/finalizers + - physicalbackups/finalizers - restores/finalizers - sqljobs/finalizers - users/finalizers @@ -194,7 +210,9 @@ rules: - databases/status - grants/status - mariadbs/status + - externalmariadbs/status - maxscales/status + - physicalbackups/status - restores/status - sqljobs/status - users/status @@ -240,6 +258,17 @@ rules: - list - patch - watch +- apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshots + verbs: + - create + - delete + - get + - list + - patch + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/serviceaccount.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/serviceaccount.yaml similarity index 100% rename from packages/system/mariadb-operator/charts/mariadb-operator/templates/serviceaccount.yaml rename to packages/system/mariadb-operator/charts/mariadb-operator/templates/operator/serviceaccount.yaml diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-secret.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-secret.yaml deleted file mode 100644 index 1819da15..00000000 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-secret.yaml +++ /dev/null @@ -1,25 +0,0 @@ -{{- if not .Values.webhook.cert.certManager.enabled }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "mariadb-operator.fullname" . }}-webhook-ca - labels: - {{- include "mariadb-operator-webhook.labels" . | nindent 4 }} - mariadb-operator.io/component: webhook - {{- with .Values.webhook.cert.secretAnnotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "mariadb-operator.fullname" . }}-webhook-cert - labels: - {{- include "mariadb-operator-webhook.labels" . | nindent 4 }} - mariadb-operator.io/component: webhook - {{- with .Values.webhook.cert.secretAnnotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-service.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-service.yaml deleted file mode 100644 index 2217e1d2..00000000 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-service.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "mariadb-operator.fullname" . }}-webhook - labels: - {{ include "mariadb-operator-webhook.labels" . | nindent 4 }} -spec: - ports: - - port: 443 - protocol: TCP - targetPort: {{ .Values.webhook.port }} - selector: - {{ include "mariadb-operator-webhook.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-certificate.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/certificate.yaml similarity index 94% rename from packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-certificate.yaml rename to packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/certificate.yaml index 39959c66..c42195c4 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-certificate.yaml +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/certificate.yaml @@ -1,4 +1,4 @@ -{{ if .Values.webhook.cert.certManager.enabled }} +{{ if and (not .Values.currentNamespaceOnly) .Values.webhook.enabled .Values.webhook.cert.certManager.enabled }} {{ if not .Values.webhook.cert.certManager.issuerRef }} apiVersion: cert-manager.io/v1 kind: Issuer @@ -51,4 +51,4 @@ spec: {{- toYaml . | nindent 6 }} {{- end }} {{- end }} -{{ end }} +{{- end }} diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-config.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/config.yaml similarity index 77% rename from packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-config.yaml rename to packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/config.yaml index 194ba62d..4df29743 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-config.yaml +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/config.yaml @@ -1,56 +1,21 @@ +{{ if and (not .Values.currentNamespaceOnly) .Values.webhook.enabled }} {{ $fullName := include "mariadb-operator.fullname" . }} -apiVersion: admissionregistration.k8s.io/v1 -kind: MutatingWebhookConfiguration -metadata: - name: {{ $fullName }}-webhook - labels: - {{ include "mariadb-operator-webhook.labels" . | nindent 4 }} - annotations: - {{- if .Values.webhook.cert.certManager.enabled }} - cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "mariadb-operator.fullname" . }}-webhook-cert - {{- else }} - k8s.mariadb.com/webhook: "" - {{- end }} - {{ with .Values.webhook.annotations }} - {{ toYaml . | indent 4 }} - {{ end }} -webhooks: -- admissionReviewVersions: - - v1 - clientConfig: - service: - name: {{ $fullName }}-webhook - namespace: {{ .Release.Namespace }} - path: /mutate-k8s-mariadb-com-v1alpha1-mariadb - failurePolicy: Fail - name: mmariadb.kb.io - rules: - - apiGroups: - - k8s.mariadb.com - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - mariadbs - sideEffects: None --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: name: {{ $fullName }}-webhook labels: - {{ include "mariadb-operator-webhook.labels" . | nindent 4 }} + {{- include "mariadb-operator-webhook.labels" . | nindent 4 }} annotations: {{- if .Values.webhook.cert.certManager.enabled }} cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "mariadb-operator.fullname" . }}-webhook-cert {{- else }} k8s.mariadb.com/webhook: "" {{- end }} - {{ with .Values.webhook.annotations }} + {{- with .Values.webhook.annotations }} {{ toYaml . | indent 4 }} - {{ end }} + {{- end }} webhooks: - admissionReviewVersions: - v1 @@ -60,7 +25,7 @@ webhooks: namespace: {{ .Release.Namespace }} path: /validate-k8s-mariadb-com-v1alpha1-backup failurePolicy: Fail - name: vbackup.kb.io + name: vbackup-v1alpha1.kb.io rules: - apiGroups: - k8s.mariadb.com @@ -72,6 +37,26 @@ webhooks: resources: - backups sideEffects: None + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ $fullName }}-webhook + namespace: {{ .Release.Namespace }} + path: /validate-k8s-mariadb-com-v1alpha1-physicalbackup + failurePolicy: Fail + name: vphysicalbackup-v1alpha1.kb.io + rules: + - apiGroups: + - k8s.mariadb.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - physicalbackups + sideEffects: None - admissionReviewVersions: - v1 clientConfig: @@ -80,7 +65,7 @@ webhooks: namespace: {{ .Release.Namespace }} path: /validate-k8s-mariadb-com-v1alpha1-connection failurePolicy: Fail - name: vconnection.kb.io + name: vconnection-v1alpha1.kb.io rules: - apiGroups: - k8s.mariadb.com @@ -100,7 +85,7 @@ webhooks: namespace: {{ .Release.Namespace }} path: /validate-k8s-mariadb-com-v1alpha1-database failurePolicy: Fail - name: vdatabase.kb.io + name: vdatabase-v1alpha1.kb.io rules: - apiGroups: - k8s.mariadb.com @@ -120,7 +105,7 @@ webhooks: namespace: {{ .Release.Namespace }} path: /validate-k8s-mariadb-com-v1alpha1-grant failurePolicy: Fail - name: vgrant.kb.io + name: vgrant-v1alpha1.kb.io rules: - apiGroups: - k8s.mariadb.com @@ -140,7 +125,7 @@ webhooks: namespace: {{ .Release.Namespace }} path: /validate-k8s-mariadb-com-v1alpha1-mariadb failurePolicy: Fail - name: vmariadb.kb.io + name: vmariadb-v1alpha1.kb.io rules: - apiGroups: - k8s.mariadb.com @@ -160,7 +145,7 @@ webhooks: namespace: {{ .Release.Namespace }} path: /validate-k8s-mariadb-com-v1alpha1-maxscale failurePolicy: Fail - name: vmaxscale.kb.io + name: vmaxscale-v1alpha1.kb.io rules: - apiGroups: - k8s.mariadb.com @@ -180,7 +165,7 @@ webhooks: namespace: {{ .Release.Namespace }} path: /validate-k8s-mariadb-com-v1alpha1-restore failurePolicy: Fail - name: vrestore.kb.io + name: vrestore-v1alpha1.kb.io rules: - apiGroups: - k8s.mariadb.com @@ -200,7 +185,7 @@ webhooks: namespace: {{ .Release.Namespace }} path: /validate-k8s-mariadb-com-v1alpha1-sqljob failurePolicy: Fail - name: vsqljob.kb.io + name: vsqljob-v1alpha1.kb.io rules: - apiGroups: - k8s.mariadb.com @@ -220,7 +205,7 @@ webhooks: namespace: {{ .Release.Namespace }} path: /validate-k8s-mariadb-com-v1alpha1-user failurePolicy: Fail - name: vuser.kb.io + name: vuser-v1alpha1.kb.io rules: - apiGroups: - k8s.mariadb.com @@ -231,4 +216,5 @@ webhooks: - UPDATE resources: - users - sideEffects: None \ No newline at end of file + sideEffects: None +{{- end }} diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-deployment.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/deployment.yaml similarity index 73% rename from packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-deployment.yaml rename to packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/deployment.yaml index 37da277d..f7f6bd81 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-deployment.yaml +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/deployment.yaml @@ -1,25 +1,26 @@ +{{ if and (not .Values.currentNamespaceOnly) .Values.webhook.enabled }} {{ $fullName := include "mariadb-operator.fullname" . }} apiVersion: apps/v1 kind: Deployment metadata: name: {{ $fullName }}-webhook labels: - {{ include "mariadb-operator-webhook.labels" . | nindent 4 }} + {{- include "mariadb-operator-webhook.labels" . | nindent 4 }} spec: - {{ if .Values.webhook.ha.enabled }} + {{- if .Values.webhook.ha.enabled }} replicas: {{ .Values.webhook.ha.replicas}} - {{ end }} + {{- end }} selector: matchLabels: - {{ include "mariadb-operator-webhook.selectorLabels" . | nindent 6 }} + {{- include "mariadb-operator-webhook.selectorLabels" . | nindent 6 }} template: metadata: - {{ with .Values.webhook.podAnnotations }} + {{- with .Values.webhook.podAnnotations }} annotations: {{ toYaml . | nindent 8 }} - {{ end }} + {{- end }} labels: - {{ include "mariadb-operator-webhook.selectorLabels" . | nindent 8 }} + {{- include "mariadb-operator-webhook.selectorLabels" . | nindent 8 }} spec: {{- with .Values.webhook.imagePullSecrets }} imagePullSecrets: @@ -27,25 +28,32 @@ spec: {{- end }} serviceAccountName: {{ include "mariadb-operator-webhook.serviceAccountName" . }} automountServiceAccountToken: {{ .Values.webhook.serviceAccount.automount }} - {{ with .Values.webhook.nodeSelector }} + {{- with .Values.webhook.nodeSelector }} nodeSelector: {{ toYaml . | nindent 8 }} - {{ end }} - {{ with .Values.webhook.tolerations }} + {{- end }} + {{- with .Values.webhook.tolerations }} tolerations: {{ toYaml . | nindent 8 }} - {{ end }} - {{ with .Values.webhook.affinity }} + {{- end }} + {{- with .Values.webhook.topologySpreadConstraints }} + topologySpreadConstraints: + {{ toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.webhook.priorityClassName }} + priorityClassName: {{ . | quote }} + {{- end }} + {{- with .Values.webhook.affinity }} affinity: {{ toYaml . | nindent 8 }} - {{ end }} - {{ with .Values.webhook.podSecurityContext }} + {{- end }} + {{- with .Values.webhook.podSecurityContext }} securityContext: {{ toYaml . | nindent 8 }} - {{ end }} + {{- end }} hostNetwork: {{ .Values.webhook.hostNetwork }} containers: - - image: "{{ .Values.webhook.image.repository }}:{{ .Values.webhook.image.tag | default .Chart.AppVersion }}" + - image: "{{ template "image" (tuple .Values.webhook.image $.Chart.AppVersion) }}" imagePullPolicy: {{ .Values.webhook.image.pullPolicy }} name: webhook args: @@ -92,14 +100,14 @@ spec: port: 8081 initialDelaySeconds: 20 periodSeconds: 5 - {{ with .Values.webhook.resources }} + {{- with .Values.webhook.resources }} resources: {{ toYaml . | nindent 12 }} - {{ end }} - {{ with .Values.webhook.securityContext}} + {{- end }} + {{- with .Values.webhook.securityContext}} securityContext: {{ toYaml . | nindent 12 }} - {{ end }} + {{- end }} volumes: {{- if not .Values.webhook.cert.certManager.enabled }} - name: ca @@ -114,3 +122,4 @@ spec: {{- if .Values.webhook.extraVolumes }} {{- toYaml .Values.webhook.extraVolumes | nindent 8 }} {{- end }} +{{- end }} diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/pdb.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/pdb.yaml new file mode 100644 index 00000000..68505df9 --- /dev/null +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/pdb.yaml @@ -0,0 +1,13 @@ +{{ if and (not .Values.currentNamespaceOnly) .Values.webhook.enabled .Values.webhook.pdb.enabled }} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "mariadb-operator.fullname" . }}-webhook + labels: + {{ include "mariadb-operator-webhook.labels" . | nindent 4 }} +spec: + maxUnavailable: {{ .Values.webhook.pdb.maxUnavailable }} + selector: + matchLabels: + {{ include "mariadb-operator-webhook.selectorLabels" . | nindent 6 }} +{{- end }} diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/service.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/service.yaml new file mode 100644 index 00000000..c2e444c0 --- /dev/null +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/service.yaml @@ -0,0 +1,15 @@ +{{- if and (not .Values.currentNamespaceOnly) .Values.webhook.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "mariadb-operator.fullname" . }}-webhook + labels: + {{- include "mariadb-operator-webhook.labels" . | nindent 4 }} +spec: + ports: + - port: 443 + protocol: TCP + targetPort: {{ .Values.webhook.port }} + selector: + {{- include "mariadb-operator-webhook.selectorLabels" . | nindent 4 }} +{{- end }} \ No newline at end of file diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-serviceaccount.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/serviceaccount.yaml similarity index 80% rename from packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-serviceaccount.yaml rename to packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/serviceaccount.yaml index 669a0d19..3633213a 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-serviceaccount.yaml +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/serviceaccount.yaml @@ -1,3 +1,4 @@ +{{- if and (not .Values.currentNamespaceOnly) .Values.webhook.enabled }} apiVersion: v1 kind: ServiceAccount metadata: @@ -10,4 +11,5 @@ metadata: {{- with .Values.webhook.serviceAccount.annotations }} annotations: {{- toYaml . | nindent 4 }} - {{- end }} \ No newline at end of file + {{- end }} +{{- end -}} \ No newline at end of file diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-servicemonitor.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/servicemonitor.yaml similarity index 67% rename from packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-servicemonitor.yaml rename to packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/servicemonitor.yaml index b251dd5f..f162fa91 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook-servicemonitor.yaml +++ b/packages/system/mariadb-operator/charts/mariadb-operator/templates/webhook/servicemonitor.yaml @@ -1,4 +1,4 @@ -{{ if and .Values.metrics.enabled .Values.webhook.serviceMonitor.enabled }} +{{ if and (not .Values.currentNamespaceOnly) .Values.webhook.enabled .Values.metrics.enabled .Values.webhook.serviceMonitor.enabled }} apiVersion: v1 kind: Service metadata: @@ -33,4 +33,12 @@ spec: - port: metrics interval: {{ .Values.webhook.serviceMonitor.interval }} scrapeTimeout: {{ .Values.webhook.serviceMonitor.scrapeTimeout }} -{{ end }} \ No newline at end of file + {{- if .Values.webhook.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml .Values.webhook.serviceMonitor.metricRelabelings | nindent 6 }} + {{- end }} + {{- if .Values.webhook.serviceMonitor.relabelings }} + relabelings: + {{- toYaml .Values.webhook.serviceMonitor.relabelings | nindent 6 }} + {{- end }} +{{- end }} diff --git a/packages/system/mariadb-operator/charts/mariadb-operator/values.yaml b/packages/system/mariadb-operator/charts/mariadb-operator/values.yaml index ec9e477f..78f05909 100644 --- a/packages/system/mariadb-operator/charts/mariadb-operator/values.yaml +++ b/packages/system/mariadb-operator/charts/mariadb-operator/values.yaml @@ -1,25 +1,32 @@ nameOverride: "" fullnameOverride: "" - +# -- CRDs +crds: + # -- Whether the helm chart should create and update the CRDs. It is false by default, which implies that the CRDs must be + # managed independently with the mariadb-operator-crds helm chart. + # **WARNING** This should only be set to true during the initial deployment. If this chart manages the CRDs + # and is later uninstalled, all MariaDB instances will be DELETED. + enabled: false image: repository: docker-registry3.mariadb.com/mariadb-operator/mariadb-operator pullPolicy: IfNotPresent # -- Image tag to use. By default the chart appVersion is used tag: "" + # Setting a digest will override any tag + # digest: sha256:084a927ee9f3918a5c85d283f73822ae205757df352218de0b935853a0765060 imagePullSecrets: [] - # -- Controller log level logLevel: INFO - # -- Cluster DNS name clusterName: cluster.local - +# -- Whether the operator should watch CRDs only in its own namespace or not. +currentNamespaceOnly: false ha: - # -- Enable high availability + # -- Enable high availability of the controller. + # If you enable it we recommend to set `affinity` and `pdb` enabled: false # -- Number of replicas replicas: 3 - metrics: # -- Enable operator internal metrics. Prometheus must be installed in the cluster enabled: false @@ -33,7 +40,10 @@ metrics: interval: 30s # -- Timeout if metrics can't be retrieved in given time interval scrapeTimeout: 25s - + # MetricRelabelConfigs to apply to samples before ingestion. + metricRelabelings: [] + # RelabelConfigs to apply to samples before scraping. + relabelings: [] serviceAccount: # -- Specifies whether a service account should be created enabled: true @@ -46,40 +56,28 @@ serviceAccount: # -- The name of the service account to use. # If not set and enabled is true, a name is generated using the fullname template name: "" - rbac: # -- Specifies whether RBAC resources should be created enabled: true - aggregation: - # -- Specifies whether the cluster roles aggrate to view and edit predefinied roles enabled: true - # -- Extra arguments to be passed to the controller entrypoint extrArgs: [] - # -- Extra environment variables to be passed to the controller extraEnv: [] - # -- Extra environment variables from preexiting ConfigMap / Secret objects used by the controller using envFrom extraEnvFrom: [] - # -- Extra volumes to pass to pod. extraVolumes: [] - # -- Extra volumes to mount to the container. extraVolumeMounts: [] - # -- Annotations to add to controller Pod podAnnotations: {} - # -- Security context to add to controller Pod podSecurityContext: {} - # -- Security context to add to controller container securityContext: {} - # -- Resources to add to controller container resources: {} # requests: @@ -88,19 +86,50 @@ resources: {} # -- Node selectors to add to controller Pod nodeSelector: {} - # -- Tolerations to add to controller Pod tolerations: [] - +# -- topologySpreadConstraints to add to controller Pod +topologySpreadConstraints: [] +# -- priorityClassName to add to controller Pod +priorityClassName: "" # -- Affinity to add to controller Pod affinity: {} +# Sample on how to create an antiAffinity rule that place +# the pods on different nodes, to be used together with `ha.enabled: true` +# podAntiAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# - labelSelector: +# matchExpressions: +# - key: app.kubernetes.io/name +# operator: In +# values: +# - mariadb-operator +# - key: app.kubernetes.io/instance +# operator: In +# values: +# - mariadb-operator +# topologyKey: kubernetes.io/hostname +pdb: + # -- Enable PodDisruptionBudget for the controller. + enabled: false + # -- Maximum number of unavailable Pods. You may also give a percentage, like `50%` + maxUnavailable: 1 +pprof: + # -- Enable the pprof HTTP server. + enabled: false + # -- The port where the pprof HTTP server listens. + port: 6060 webhook: + # -- Specifies whether the webhook should be created. + enabled: true image: repository: docker-registry3.mariadb.com/mariadb-operator/mariadb-operator pullPolicy: IfNotPresent # -- Image tag to use. By default the chart appVersion is used tag: "" + # Setting a digest will override any tag + # digest: sha256:084a927ee9f3918a5c85d283f73822ae205757df352218de0b935853a0765060 imagePullSecrets: [] ha: # -- Enable high availability @@ -144,6 +173,10 @@ webhook: interval: 30s # -- Timeout if metrics can't be retrieved in given time interval scrapeTimeout: 25s + # MetricRelabelConfigs to apply to samples before ingestion. + metricRelabelings: [] + # RelabelConfigs to apply to samples before scraping. + relabelings: [] serviceAccount: # -- Specifies whether a service account should be created enabled: true @@ -175,13 +208,21 @@ webhook: # requests: # cpu: 10m # memory: 32Mi - # -- Node selectors to add to controller Pod + # -- Node selectors to add to webhook Pod nodeSelector: {} - # -- Tolerations to add to controller Pod + # -- Tolerations to add to webhook Pod tolerations: [] - # -- Affinity to add to controller Pod + # -- topologySpreadConstraints to add to webhook Pod + topologySpreadConstraints: [] + # -- priorityClassName to add to webhook Pod + priorityClassName: "" + # -- Affinity to add to webhook Pod affinity: {} - + pdb: + # -- Enable PodDisruptionBudget for the webhook. + enabled: false + # -- Maximum number of unavailable Pods. You may also give a percentage, like `50%` + maxUnavailable: 1 certController: # -- Specifies whether the cert-controller should be created. enabled: true @@ -190,18 +231,20 @@ certController: pullPolicy: IfNotPresent # -- Image tag to use. By default the chart appVersion is used tag: "" + # Setting a digest will override any tag + # digest: sha256:084a927ee9f3918a5c85d283f73822ae205757df352218de0b935853a0765060 imagePullSecrets: [] ha: # -- Enable high availability enabled: false # -- Number of replicas replicas: 3 - # -- CA certificate validity. It must be greater than certValidity. - caValidity: 35064h - # -- Certificate validity. - certValidity: 8766h - # -- Duration used to verify whether a certificate is valid or not. - lookaheadValidity: 2160h + # -- CA certificate lifetime. It must be greater than certLifetime. + caLifetime: 26280h + # -- Certificate lifetime. + certLifetime: 2160h + # -- How long before the certificate expiration should the renewal process be triggered. For example, if a certificate is valid for 60 minutes, and renewBeforePercentage=25, cert-controller will begin to attempt to renew the certificate 45 minutes after it was issued (i.e. when there are 15 minutes (25%) remaining until the certificate is no longer valid). + renewBeforePercentage: 33 # -- Requeue duration to ensure that certificate gets renewed. requeueDuration: 5m serviceMonitor: @@ -214,6 +257,10 @@ certController: interval: 30s # -- Timeout if metrics can't be retrieved in given time interval scrapeTimeout: 25s + # MetricRelabelConfigs to apply to samples before ingestion. + metricRelabelings: [] + # RelabelConfigs to apply to samples before scraping. + relabelings: [] serviceAccount: # -- Specifies whether a service account should be created enabled: true @@ -236,16 +283,41 @@ certController: podAnnotations: {} # -- Security context to add to cert-controller Pod podSecurityContext: {} - # -- Security context to add to cert-controller container + # -- Security context to add to cert-controller Pod securityContext: {} # -- Resources to add to cert-controller container resources: {} # requests: # cpu: 10m # memory: 32Mi - # -- Node selectors to add to controller Pod + # -- Node selectors to add to cert-controller container nodeSelector: {} - # -- Tolerations to add to controller Pod + # -- Tolerations to add to cert-controller container tolerations: [] - # -- Affinity to add to controller Pod + # -- topologySpreadConstraints to add to cert-controller container + topologySpreadConstraints: [] + # -- priorityClassName to add to cert-controller container + priorityClassName: "" + # -- Affinity to add to cert-controller container affinity: {} + pdb: + # -- Enable PodDisruptionBudget for the cert-controller. + enabled: false + # -- Maximum number of unavailable Pods. You may also give a percentage, like `50%` + maxUnavailable: 1 +# -- Operator configuration +config: + # -- Galera library path to be used with MariaDB Galera + galeraLibPath: /usr/lib/galera/libgalera_smm.so + # -- Default MariaDB version to be used when unable to infer it via image tag + mariadbDefaultVersion: "11.8" + # -- Default MariaDB image + mariadbImage: docker-registry1.mariadb.com/library/mariadb:11.8.2 + # -- Default MariaDB image name + mariadbImageName: docker-registry1.mariadb.com/library/mariadb + # -- Default MaxScale image + maxscaleImage: docker-registry2.mariadb.com/mariadb/maxscale:23.08.5 + # -- Default MariaDB exporter image + exporterImage: prom/mysqld-exporter:v0.15.1 + # -- Default MaxScale exporter image + exporterMaxscaleImage: docker-registry2.mariadb.com/mariadb/maxscale-prometheus-exporter-ubi:v0.0.1 diff --git a/packages/system/mariadb-rd/Chart.yaml b/packages/system/mariadb-rd/Chart.yaml new file mode 100644 index 00000000..091d535c --- /dev/null +++ b/packages/system/mariadb-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: mariadb-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/mariadb-rd/Makefile b/packages/system/mariadb-rd/Makefile new file mode 100644 index 00000000..def401d8 --- /dev/null +++ b/packages/system/mariadb-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=mariadb-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/mariadb-rd/cozyrds/mariadb.yaml b/packages/system/mariadb-rd/cozyrds/mariadb.yaml new file mode 100644 index 00000000..6dacdf0e --- /dev/null +++ b/packages/system/mariadb-rd/cozyrds/mariadb.yaml @@ -0,0 +1,39 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: mariadb +spec: + application: + kind: MariaDB + plural: mariadbs + singular: mariadb + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of MariaDB replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each MariaDB replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"version":{"description":"MariaDB major.minor version to deploy","type":"string","default":"v11.8","enum":["v11.8","v11.4","v10.11","v10.6"]},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","required":["maxUserConnections","password"],"properties":{"maxUserConnections":{"description":"Maximum number of connections.","type":"integer"},"password":{"description":"Password for the user.","type":"string"}}}},"databases":{"description":"Databases configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"roles":{"description":"Roles assigned to users.","type":"object","properties":{"admin":{"description":"List of users with admin privileges.","type":"array","items":{"type":"string"}},"readonly":{"description":"List of users with read-only privileges.","type":"array","items":{"type":"string"}}}}}}},"backup":{"description":"Backup configuration.","type":"object","default":{},"required":["cleanupStrategy","enabled","resticPassword","s3AccessKey","s3Bucket","s3Region","s3SecretKey","schedule"],"properties":{"cleanupStrategy":{"description":"Retention strategy for cleaning up old backups.","type":"string","default":"--keep-last=3 --keep-daily=3 --keep-within-weekly=1m"},"enabled":{"description":"Enable regular backups (default: false).","type":"boolean","default":false},"resticPassword":{"description":"Password for Restic backup encryption.","type":"string","default":""},"s3AccessKey":{"description":"Access key for S3 authentication.","type":"string","default":""},"s3Bucket":{"description":"S3 bucket used for storing backups.","type":"string","default":"s3.example.org/mariadb-backups"},"s3Region":{"description":"AWS S3 region where backups are stored.","type":"string","default":"us-east-1"},"s3SecretKey":{"description":"Secret key for S3 authentication.","type":"string","default":""},"schedule":{"description":"Cron schedule for automated backups.","type":"string","default":"0 2 * * *"}}}}} + release: + prefix: mariadb- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-mariadb-application-default-mariadb + namespace: cozy-system + dashboard: + category: PaaS + singular: MariaDB + plural: MariaDB + description: Managed MariaDB service + tags: + - database + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHg9Ii0wLjAwMTk1MzEyIiB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgcng9IjI0IiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfNjgzXzI5MzApIi8+CjxwYXRoIGQ9Ik0xMzMuMTkxIDI5LjAwMjJDMTMxLjIxMyAyOS4wNjU0IDEzMS44MzkgMjkuNjM1NCAxMjcuNTY0IDMwLjY4NzNDMTIzLjI0OCAzMS43NDk2IDExNy45NzUgMzEuNDIzOSAxMTMuMzI3IDMzLjM3MzNDOTkuNDUxNiAzOS4xOTI0IDk2LjY2NzYgNTkuMDgxMyA4NC4wNTM1IDY2LjIwNTlDNzQuNjI0NyA3MS41MzE4IDY1LjExMiA3MS45NTY1IDU2LjU1OTQgNzQuNjM2NUM1MC45Mzg5IDc2LjM5OSA0NC43OTA2IDgwLjAxMzUgMzkuNjk4MiA4NC40MDE4QzM1Ljc0NTUgODcuODA5MyAzNS42NDIzIDkwLjgwNTQgMzEuNTEyMyA5NS4wNzkxQzI3LjA5NDcgOTkuNjUwNCAxMy45NTUxIDk1LjE1NjQgOCAxMDIuMTUzQzkuOTE4MzUgMTA0LjA5MyAxMC43NTk0IDEwNC42MzYgMTQuNTM5OCAxMDQuMTMzQzEzLjc1NzEgMTA1LjYxNiA5LjE0MzMyIDEwNi44NjYgMTAuMDQ2NSAxMDkuMDQ5QzEwLjk5NjggMTExLjM0NSAyMi4xNTExIDExMi45MDEgMzIuMjkwOCAxMDYuNzhDMzcuMDEzMSAxMDMuOTI5IDQwLjc3NDMgOTkuODE5MyA0OC4xMjg4IDk4LjgzODRDNTcuNjQ1OSA5Ny41Njk5IDY4LjYwOTMgOTkuNjUyIDc5LjYyNjggMTAxLjI0MUM3Ny45OTMyIDEwNi4xMTIgNzQuNzEzMyAxMDkuMzUxIDcyLjA4NiAxMTMuMjMxQzcxLjI3MjQgMTE0LjEwNyA3My43MjAyIDExNC4yMDUgNzYuNTEyNiAxMTMuNjc1QzgxLjUzNTkgMTEyLjQzMyA4NS4xNTYxIDExMS40MzMgODguOTQ3MiAxMDkuMjI3QzkzLjYwNDcgMTA2LjUxNSA5NC4zMTA0IDk5LjU2MzkgMTAwLjAyNSA5OC4wNTk5QzEwMy4yMDkgMTAyLjk1NCAxMTEuODY5IDEwNC4xMSAxMTcuMjQyIDEwMC4xOTVDMTEyLjUyNyA5OC44NjA3IDExMS4yMjQgODguODI0NCAxMTIuODE1IDg0LjQwMThDMTE0LjMyMyA4MC4yMTU2IDExNS44MTMgNzMuNTE5MiAxMTcuMzMxIDY3Ljk4NTVDMTE4Ljk2MSA2Mi4wNDI1IDExOS41NjIgNTQuNTUxOSAxMjEuNTM1IDUxLjUyNDdDMTI0LjUwMyA0Ni45NzAxIDEyNy43ODMgNDUuNDA2IDEzMC42MyA0Mi44Mzc3QzEzMy40NzcgNDAuMjY5NSAxMzYuMDgzIDM3Ljc2OTQgMTM1Ljk5OCAzMS44OTI3QzEzNS45NyAyOS45OTk4IDEzNC45OTIgMjguOTQ0NyAxMzMuMTkxIDI5LjAwMjJaIiBmaWxsPSIjMDQyNDRFIi8+CjxwYXRoIGQ9Ik0xMjguOTUzIDMyLjQ4NDRDMTI5LjQyNyAzNC4xMDA0IDEzMC4xNjggMzQuODQyMSAxMzMuMzc1IDM1LjEzODdDMTMyLjkwNiAzOS4yMDQxIDEzMC4xOTUgNDEuNDI3NiAxMjcuMTU0IDQzLjU2MTFDMTI0LjQ3OSA0NS40Mzc2IDEyMS41NDcgNDcuMjQ0NSAxMTkuNjY0IDUwLjE3NTdDMTE3LjczNCA1My4xNzg1IDExNi41MDkgNjMuNDU1NCAxMTMuNTE3IDczLjYwNDRDMTEwLjkzMSA4Mi4zNzM4IDEwNy4wMjUgOTEuMDQ0NSAxMDAuMjA0IDk0Ljg0MzdDOTkuNDkxOSA5My4wNTAyIDEwMC4yOTUgODkuNzQgOTguODc4IDg4LjY1MkM5Ny45NjExIDkxLjI2NzQgOTYuOTI0MiA5My43NjI3IDk1LjcwOTggOTYuMDgyMUM5MS43MDc3IDEwMy43MzIgODUuNzgyMiAxMDkuNDU5IDc1Ljg4MDEgMTExLjIwOEM4MC41Nzg1IDEwNC44NSA4NS4wNzEgOTguMjg0NCA4NS4xNjgzIDg3LjMyNjJDODEuODYxNyA4OC4wNDE3IDgxLjkzMTkgOTUuODUyMiA3OC41MzQ1IDk3Ljk0MDJDNzYuMzU2MyA5OC4xNzcyIDc0LjE0OTggOTguMTc1OCA3MS45MjkxIDk4LjA0MjRDNjIuODA5MSA5Ny40OTU5IDUzLjQ1MzUgOTQuNzU0OSA0NC45MjE5IDk3LjQ5MjNDMzkuMTEyOCA5OS4zNTY4IDM0LjM2MTkgMTAzLjc1NSAyOS40NDI4IDEwNS44ODhDMjMuNjYxNCAxMDguMzk2IDE5LjI4MzEgMTA5LjQyNyAxMi4wODM2IDEwOC4zOTZDMTEuMTY5NSAxMDcuMTY0IDE3LjM1MjYgMTA1LjU3NSAxNi45ODI5IDEwMi45MDJDMTQuMTY1MyAxMDIuNTkgMTIuNTI5MyAxMDMuMjczIDEwLjA4MDEgMTAyLjE2QzEwLjM1MDUgMTAxLjY2MiAxMC43NDc5IDEwMS4yNDcgMTEuMjQ4MyAxMDAuOTAxQzE1LjczNzMgOTcuNzk0IDI4LjQ4ODIgMTAwLjE2NyAzMS45MDA2IDk2LjgxNjdDMzQuMDA3IDk0Ljc1IDM1LjM4ODkgOTIuNTg2NyAzNi44MTk3IDkwLjQ4MzhDMzguMjA3MiA4OC40NDM0IDM5LjY0MTUgODYuNDU5NyA0MS44MjY4IDg0LjY3MTlDNDIuNjMzNyA4NC4wMTE4IDQzLjUxMSA4My4zNTk2IDQ0LjQ0MjEgODIuNzIzQzQ4LjE2NiA4MC4xNzQzIDUyLjc3MjkgNzcuODYyOCA1Ny4zMDY2IDc2LjI2OTRDNjMuNDgyNiA3NC4wOTg0IDY5Ljc0MSA3My45MTk1IDc2LjMyMzcgNzEuNDA0M0M4MC4zOTA0IDY5Ljg1IDg0LjgxMjcgNjcuOTMwMiA4OC40MTc0IDY1LjI0MzlDODkuMjczMyA2NC42MDUxIDkwLjA4MzEgNjMuOTI0NSA5MC44MzE5IDYzLjE5NDlDMTAxLjEyNSA1My4xNjA4IDEwMy4xNjUgMzUuNDYxIDExOS4yMjQgMzMuODExNkMxMjEuMTY2IDMzLjYxMjEgMTIyLjc1NiAzMy42NzY3IDEyNC4yMDMgMzMuNjMyN0MxMjUuODcxIDMzLjU4MyAxMjcuMzQ3IDMzLjM4OTMgMTI4Ljk1MyAzMi40ODQ0Wk0xMDkuMzc1IDg5LjEzMzlDMTA5LjU2NyA5Mi4yMDEzIDExMS4zNDggOTguMjg3MiAxMTIuOTIgOTkuNzY2M0MxMDkuODQxIDEwMC41MTUgMTA0LjUzNyA5OS4yNzggMTAzLjE3NyA5Ny4xMDYyQzEwMy44NzYgOTMuOTcwNyAxMDcuNTE0IDkxLjEwNDEgMTA5LjM3NSA4OS4xMzM5WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTEzMC4xMDkgMzUuOTE4N0MxMjkuNDkgMzcuMjE2OSAxMjguMzA1IDM4Ljg5MDggMTI4LjMwNSA0Mi4xOTU2QzEyOC4zIDQyLjc2MyAxMjcuODc1IDQzLjE1MTcgMTI3Ljg2NyA0Mi4yNzdDMTI3Ljg5OSAzOS4wNDcgMTI4Ljc1NCAzNy42NTA3IDEyOS42NjIgMzUuODE1NUMxMzAuMDg1IDM1LjA2MzYgMTMwLjMzOSAzNS4zNzM4IDEzMC4xMDkgMzUuOTE4N1pNMTI5LjQ4NiAzNS40Mjk3QzEyOC43NTYgMzYuNjY4NCAxMjYuOTk4IDM4LjkyNzggMTI2LjcwNyA0Mi4yMjAzQzEyNi42NTMgNDIuNzg0OCAxMjYuMTk0IDQzLjEzNDMgMTI2LjI2NCA0Mi4yNjE4QzEyNi41ODEgMzkuMDQ3NyAxMjcuOTg2IDM3LjAzNiAxMjkuMDUyIDM1LjI4NzNDMTI5LjUzNiAzNC41NzYxIDEyOS43NjMgMzQuOTA3NCAxMjkuNDg2IDM1LjQyOTdaTTEyOC45MTggMzQuNzgxN0MxMjguMDg2IDM1Ljk1NDMgMTI1LjM4IDM4LjY2NzggMTI0LjgxNCA0MS45MjQ3QzEyNC43MTIgNDIuNDgxOSAxMjQuMjI1IDQyLjc5MjggMTI0LjM2OCA0MS45MjlDMTI0Ljk1NCAzOC43NTIgMTI3LjI4NyAzNi4yNTUgMTI4LjQ5NiAzNC42MDM3QzEyOS4wMzggMzMuOTM0NiAxMjkuMjM3IDM0LjI4NCAxMjguOTE4IDM0Ljc4MTdaTTEyOC40MTEgMzQuMDU4OEwxMjguMTM3IDM0LjM0OTlDMTI2LjkyNyAzNS42NDcyIDEyNC4xMTYgMzguODExNCAxMjMuMTc5IDQxLjcwNzRDMTIyLjk5OSA0Mi4yNDUgMTIyLjQ3NCA0Mi40ODQ4IDEyMi43MzcgNDEuNjQ5M0MxMjMuNzYzIDM4LjU4NjQgMTI2LjU4OSAzNS4yODczIDEyOC4wMTggMzMuODIyN0MxMjguNjUgMzMuMjM2NCAxMjguNzk2IDMzLjYxMDYgMTI4LjQxMSAzNC4wNTg4Wk0xMTMuODg2IDQwLjYxNjJDMTE0LjUxMyAzNy45MjMxIDExNi42MDcgMzYuNjk2IDEyMC4yMjMgMzYuOTk1M0MxMjEuMDk2IDQxLjAxNTEgMTE2LjIxMyA0Mi42MzY2IDExMy44ODYgNDAuNjE2MloiIGZpbGw9IiMwNDI0NEUiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl82ODNfMjkzMCIgeDE9IjE0MC41IiB5MT0iMTQxIiB4Mj0iNS45OTk5OSIgeTI9Ii01LjUwMjI4ZS0wNiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjQzQ5QTZDIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI0U3QkY5MyIvPgo8L2xpbmVhckdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPgo= + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "version"], ["spec", "users"], ["spec", "databases"], ["spec", "backup"], ["spec", "backup", "enabled"], ["spec", "backup", "s3Region"], ["spec", "backup", "s3Bucket"], ["spec", "backup", "schedule"], ["spec", "backup", "cleanupStrategy"], ["spec", "backup", "s3AccessKey"], ["spec", "backup", "s3SecretKey"], ["spec", "backup", "resticPassword"]] + secrets: + exclude: [] + include: + - resourceNames: + - mariadb-{{ .name }}-credentials + services: + exclude: [] + include: + - resourceNames: + - mariadb-{{ .name }}-primary + - mariadb-{{ .name }}-secondary diff --git a/packages/system/mariadb-rd/templates/cozyrd.yaml b/packages/system/mariadb-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/mariadb-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/mariadb-rd/values.yaml b/packages/system/mariadb-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/mariadb-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/metallb/Makefile b/packages/system/metallb/Makefile index fbc3dfa0..5262e558 100644 --- a/packages/system/metallb/Makefile +++ b/packages/system/metallb/Makefile @@ -1,8 +1,8 @@ export NAME=metallb export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts @@ -15,18 +15,13 @@ 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) + $(BUILDX_ARGS) 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) \ diff --git a/packages/system/metallb/values.yaml b/packages/system/metallb/values.yaml index d392f4c4..dd5f76e6 100644 --- a/packages/system/metallb/values.yaml +++ b/packages/system/metallb/values.yaml @@ -4,8 +4,8 @@ metallb: controller: image: repository: ghcr.io/cozystack/cozystack/metallb-controller - tag: v0.15.2@sha256:0e9080234fc8eedab78ad2831fb38df375c383e901a752d72b353c8d13b9605f + tag: v0.15.2@sha256:623ce74b5802bff6e29f29478ccab29ce4162a64148be006c69e16cc3207e289 speaker: image: repository: ghcr.io/cozystack/cozystack/metallb-speaker - tag: v0.15.2@sha256:e14d4c328c3ab91a6eadfeea90da96388503492d165e7e8582f291b1872e53b2 + tag: v0.15.2@sha256:f264058afd9228452a260ab9c9dd1859404745627a2a38c2ba4671e27f3b3bb2 diff --git a/packages/system/metrics-server/.helmignore b/packages/system/metrics-server/.helmignore new file mode 100644 index 00000000..e69de29b diff --git a/packages/system/metrics-server/Chart.yaml b/packages/system/metrics-server/Chart.yaml new file mode 100644 index 00000000..d035ddb3 --- /dev/null +++ b/packages/system/metrics-server/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-metrics-server +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/metrics-server/Makefile b/packages/system/metrics-server/Makefile new file mode 100644 index 00000000..87477ea0 --- /dev/null +++ b/packages/system/metrics-server/Makefile @@ -0,0 +1,10 @@ +export NAME=metrics-server +export NAMESPACE=cozy-monitoring + +include ../../../hack/package.mk + +update: + rm -rf charts + helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/ + helm repo update metrics-server + helm pull metrics-server/metrics-server --untar --untardir charts diff --git a/packages/system/metrics-server/charts/metrics-server/.helmignore b/packages/system/metrics-server/charts/metrics-server/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/packages/system/metrics-server/charts/metrics-server/.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/system/monitoring-agents/charts/metrics-server/CHANGELOG.md b/packages/system/metrics-server/charts/metrics-server/CHANGELOG.md similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/CHANGELOG.md rename to packages/system/metrics-server/charts/metrics-server/CHANGELOG.md diff --git a/packages/system/monitoring-agents/charts/metrics-server/Chart.yaml b/packages/system/metrics-server/charts/metrics-server/Chart.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/Chart.yaml rename to packages/system/metrics-server/charts/metrics-server/Chart.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/README.md b/packages/system/metrics-server/charts/metrics-server/README.md similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/README.md rename to packages/system/metrics-server/charts/metrics-server/README.md diff --git a/packages/system/monitoring-agents/charts/metrics-server/RELEASE.md b/packages/system/metrics-server/charts/metrics-server/RELEASE.md similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/RELEASE.md rename to packages/system/metrics-server/charts/metrics-server/RELEASE.md diff --git a/packages/system/monitoring-agents/charts/metrics-server/ci/ci-values.yaml b/packages/system/metrics-server/charts/metrics-server/ci/ci-values.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/ci/ci-values.yaml rename to packages/system/metrics-server/charts/metrics-server/ci/ci-values.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/NOTES.txt b/packages/system/metrics-server/charts/metrics-server/templates/NOTES.txt similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/NOTES.txt rename to packages/system/metrics-server/charts/metrics-server/templates/NOTES.txt diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/_helpers.tpl b/packages/system/metrics-server/charts/metrics-server/templates/_helpers.tpl similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/_helpers.tpl rename to packages/system/metrics-server/charts/metrics-server/templates/_helpers.tpl diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/apiservice.yaml b/packages/system/metrics-server/charts/metrics-server/templates/apiservice.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/apiservice.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/apiservice.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/clusterrole-aggregated-reader.yaml b/packages/system/metrics-server/charts/metrics-server/templates/clusterrole-aggregated-reader.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/clusterrole-aggregated-reader.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/clusterrole-aggregated-reader.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/clusterrole-nanny.yaml b/packages/system/metrics-server/charts/metrics-server/templates/clusterrole-nanny.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/clusterrole-nanny.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/clusterrole-nanny.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/clusterrole.yaml b/packages/system/metrics-server/charts/metrics-server/templates/clusterrole.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/clusterrole.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/clusterrole.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/clusterrolebinding-auth-delegator.yaml b/packages/system/metrics-server/charts/metrics-server/templates/clusterrolebinding-auth-delegator.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/clusterrolebinding-auth-delegator.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/clusterrolebinding-auth-delegator.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/clusterrolebinding-nanny.yaml b/packages/system/metrics-server/charts/metrics-server/templates/clusterrolebinding-nanny.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/clusterrolebinding-nanny.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/clusterrolebinding-nanny.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/clusterrolebinding.yaml b/packages/system/metrics-server/charts/metrics-server/templates/clusterrolebinding.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/clusterrolebinding.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/clusterrolebinding.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/configmaps-nanny.yaml b/packages/system/metrics-server/charts/metrics-server/templates/configmaps-nanny.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/configmaps-nanny.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/configmaps-nanny.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/deployment.yaml b/packages/system/metrics-server/charts/metrics-server/templates/deployment.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/deployment.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/deployment.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/pdb.yaml b/packages/system/metrics-server/charts/metrics-server/templates/pdb.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/pdb.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/pdb.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/psp.yaml b/packages/system/metrics-server/charts/metrics-server/templates/psp.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/psp.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/psp.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/role-nanny.yaml b/packages/system/metrics-server/charts/metrics-server/templates/role-nanny.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/role-nanny.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/role-nanny.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/rolebinding-nanny.yaml b/packages/system/metrics-server/charts/metrics-server/templates/rolebinding-nanny.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/rolebinding-nanny.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/rolebinding-nanny.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/rolebinding.yaml b/packages/system/metrics-server/charts/metrics-server/templates/rolebinding.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/rolebinding.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/rolebinding.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/service.yaml b/packages/system/metrics-server/charts/metrics-server/templates/service.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/service.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/service.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/serviceaccount.yaml b/packages/system/metrics-server/charts/metrics-server/templates/serviceaccount.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/serviceaccount.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/serviceaccount.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/templates/servicemonitor.yaml b/packages/system/metrics-server/charts/metrics-server/templates/servicemonitor.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/templates/servicemonitor.yaml rename to packages/system/metrics-server/charts/metrics-server/templates/servicemonitor.yaml diff --git a/packages/system/monitoring-agents/charts/metrics-server/values.yaml b/packages/system/metrics-server/charts/metrics-server/values.yaml similarity index 100% rename from packages/system/monitoring-agents/charts/metrics-server/values.yaml rename to packages/system/metrics-server/charts/metrics-server/values.yaml diff --git a/packages/system/metrics-server/values.yaml b/packages/system/metrics-server/values.yaml new file mode 100644 index 00000000..98d74b6c --- /dev/null +++ b/packages/system/metrics-server/values.yaml @@ -0,0 +1,15 @@ +metrics-server: + defaultArgs: + - --cert-dir=/tmp + - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname + - --kubelet-use-node-status-port + - --metric-resolution=15s + - --kubelet-insecure-tls + + metrics: + enabled: true + + serviceMonitor: + enabled: true + + diff --git a/packages/system/mongodb-operator/.helmignore b/packages/system/mongodb-operator/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/packages/system/mongodb-operator/.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/system/mongodb-operator/Chart.yaml b/packages/system/mongodb-operator/Chart.yaml new file mode 100644 index 00000000..6dc477a8 --- /dev/null +++ b/packages/system/mongodb-operator/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-mongodb-operator +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/mongodb-operator/Makefile b/packages/system/mongodb-operator/Makefile new file mode 100644 index 00000000..886eb569 --- /dev/null +++ b/packages/system/mongodb-operator/Makefile @@ -0,0 +1,11 @@ +export NAME=mongodb-operator +export NAMESPACE=cozy-$(NAME) + +include ../../../hack/package.mk + +update: + rm -rf charts + helm repo add percona https://percona.github.io/percona-helm-charts + helm repo update percona + helm pull percona/psmdb-operator --untar --untardir charts + rm -rf charts/psmdb-operator/charts diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/.helmignore b/packages/system/mongodb-operator/charts/psmdb-operator/.helmignore new file mode 100644 index 00000000..50af0317 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/.helmignore @@ -0,0 +1,22 @@ +# 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 +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/Chart.yaml b/packages/system/mongodb-operator/charts/psmdb-operator/Chart.yaml new file mode 100644 index 00000000..4c268c13 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v2 +appVersion: 1.21.1 +description: A Helm chart for deploying the Percona Operator for MongoDB +home: https://docs.percona.com/percona-operator-for-mongodb/ +maintainers: +- email: natalia.marukovich@percona.com + name: nmarukovich +- email: julio.pasinatto@percona.com + name: jvpasinatto +- email: eleonora.zinchenko@percona.com + name: eleo007 +name: psmdb-operator +version: 1.21.2 diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/LICENSE.txt b/packages/system/mongodb-operator/charts/psmdb-operator/LICENSE.txt new file mode 100644 index 00000000..6a31453a --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/LICENSE.txt @@ -0,0 +1,13 @@ +Copyright 2019 Paul Czarkowski + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/README.md b/packages/system/mongodb-operator/charts/psmdb-operator/README.md new file mode 100644 index 00000000..18292d17 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/README.md @@ -0,0 +1,77 @@ +# Percona Operator for MongoDB + +Percona Operator for MongoDB allows users to deploy and manage Percona Server for MongoDB Clusters on Kubernetes. +Useful links: +- [Operator Github repository](https://github.com/percona/percona-server-mongodb-operator) +- [Operator Documentation](https://www.percona.com/doc/kubernetes-operator-for-psmongodb/index.html) + +## Pre-requisites +* Kubernetes 1.30+ +* Helm v3 + +# Installation + +This chart will deploy the Operator Pod for the further Percona Server for MongoDB creation in Kubernetes. + +## Installing the chart + +To install the chart with the `psmdb` release name using a dedicated namespace (recommended): + +```sh +helm repo add percona https://percona.github.io/percona-helm-charts/ +helm install my-operator percona/psmdb-operator --version 1.21.2 --namespace my-namespace +``` + +The chart can be customized using the following configurable parameters: + +| Parameter | Description | Default | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------ | ----------------------------------------- | +| `image.repository` | PSMDB Operator Container image name | `percona/percona-server-mongodb-operator` | +| `image.tag` | PSMDB Operator Container image tag | `1.21.1` | +| `image.pullPolicy` | PSMDB Operator Container pull policy | `Always` | +| `image.pullSecrets` | PSMDB Operator Pod pull secret | `[]` | +| `replicaCount` | PSMDB Operator Pod quantity | `1` | +| `tolerations` | List of node taints to tolerate | `[]` | +| `annotations` | PSMDB Operator Deployment annotations | `{}` | +| `podAnnotations` | PSMDB Operator Pod annotations | `{}` | +| `labels` | PSMDB Operator Deployment labels | `{}` | +| `podLabels` | PSMDB Operator Pod labels | `{}` | +| `resources` | Resource requests and limits | `{}` | +| `nodeSelector` | Labels for Pod assignment | `{}` | +| `podAnnotations` | Annotations for pod | `{}` | +| `podSecurityContext` | Pod Security Context | `{}` | +| `watchNamespace` | Set when a different from default namespace is needed to watch (comma separated if multiple needed) | `""` | +| `createNamespace` | Set if you want to create watched namespaces with helm | `false` | +| `rbac.create` | If false RBAC will not be created. RBAC resources will need to be created manually | `true` | +| `securityContext` | Container Security Context | `{}` | +| `serviceAccount.create` | If false the ServiceAccounts will not be created. The ServiceAccounts must be created manually | `true` | +| `serviceAccount.annotations` | PSMDB Operator ServiceAccount annotations | `{}` | +| `logStructured` | Force PSMDB operator to print JSON-wrapped log messages | `false` | +| `logLevel` | PSMDB Operator logging level | `INFO` | +| `disableTelemetry` | Disable sending PSMDB Operator telemetry data to Percona | `false` | +| `maxConcurrentReconciles` | Number of concurrent workers that can reconcile resources in Percona Server for MongoDB clusters in parallel | `1` | + +Specify parameters using `--set key=value[,key=value]` argument to `helm install` + +Alternatively a YAML file that specifies the values for the parameters can be provided like this: + +```sh +helm install psmdb-operator -f values.yaml percona/psmdb-operator +``` + +## Deploy the database + +To deploy Percona Server for MongoDB run the following command: + +```sh +helm install my-db percona/psmdb-db +``` + +See more about Percona Server for MongoDB deployment in its chart [here](https://github.com/percona/percona-helm-charts/tree/main/charts/psmdb-db) or in the [Helm chart installation guide](https://www.percona.com/doc/kubernetes-operator-for-psmongodb/helm.html). + +# Need help? + +**Commercial Support** | **Community Support** | +:-: | :-: | +|
Enterprise-grade assistance for your mission-critical database deployments in containers and Kubernetes. Get expert guidance for complex tasks like multi-cloud replication, database migration and building platforms.

|
Connect with our engineers and fellow users for general questions, troubleshooting, and sharing feedback and ideas.

| +| **[Get Percona Support](https://hubs.ly/Q02ZTH8Q0)** | **[Visit our Forum](https://forums.percona.com/)** | diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/crds/crd.yaml b/packages/system/mongodb-operator/charts/psmdb-operator/crds/crd.yaml new file mode 100644 index 00000000..47d11591 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/crds/crd.yaml @@ -0,0 +1,25729 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/component: crd + app.kubernetes.io/name: percona-server-mongodb + app.kubernetes.io/part-of: percona-server-mongodb-operator + app.kubernetes.io/version: v1.21.1 + name: perconaservermongodbbackups.psmdb.percona.com +spec: + group: psmdb.percona.com + names: + kind: PerconaServerMongoDBBackup + listKind: PerconaServerMongoDBBackupList + plural: perconaservermongodbbackups + shortNames: + - psmdb-backup + singular: perconaservermongodbbackup + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Cluster name + jsonPath: .spec.clusterName + name: Cluster + type: string + - description: Storage name + jsonPath: .spec.storageName + name: Storage + type: string + - description: Backup destination + jsonPath: .status.destination + name: Destination + type: string + - description: Backup type + jsonPath: .status.type + name: Type + type: string + - description: Backup size + jsonPath: .status.size + name: Size + type: string + - description: Job status + jsonPath: .status.state + name: Status + type: string + - description: Completed time + jsonPath: .status.completed + name: Completed + type: date + - description: Created time + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + clusterName: + type: string + compressionLevel: + type: integer + compressionType: + type: string + startingDeadlineSeconds: + format: int64 + type: integer + storageName: + type: string + type: + enum: + - logical + - physical + - incremental + - incremental-base + type: string + type: object + status: + properties: + azure: + properties: + container: + type: string + credentialsSecret: + type: string + endpointUrl: + type: string + prefix: + type: string + required: + - credentialsSecret + type: object + completed: + format: date-time + type: string + destination: + type: string + error: + type: string + filesystem: + properties: + path: + type: string + required: + - path + type: object + gcs: + properties: + bucket: + type: string + chunkSize: + type: integer + credentialsSecret: + type: string + prefix: + type: string + retryer: + properties: + backoffInitial: + format: int64 + type: integer + backoffMax: + format: int64 + type: integer + backoffMultiplier: + type: number + required: + - backoffInitial + - backoffMax + - backoffMultiplier + type: object + required: + - bucket + - credentialsSecret + type: object + lastTransition: + format: date-time + type: string + lastWriteAt: + format: date-time + type: string + latestRestorableTime: + format: date-time + type: string + pbmName: + type: string + pbmPod: + type: string + pbmPods: + additionalProperties: + type: string + type: object + replsetNames: + items: + type: string + type: array + s3: + properties: + bucket: + type: string + credentialsSecret: + type: string + debugLogLevels: + type: string + endpointUrl: + type: string + forcePathStyle: + type: boolean + insecureSkipTLSVerify: + type: boolean + maxUploadParts: + format: int32 + type: integer + prefix: + type: string + region: + type: string + retryer: + properties: + maxRetryDelay: + type: string + minRetryDelay: + type: string + numMaxRetries: + type: integer + type: object + serverSideEncryption: + properties: + kmsKeyID: + type: string + sseAlgorithm: + type: string + sseCustomerAlgorithm: + type: string + sseCustomerKey: + type: string + type: object + storageClass: + type: string + uploadPartSize: + type: integer + required: + - bucket + type: object + size: + type: string + start: + format: date-time + type: string + state: + type: string + storageName: + type: string + type: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/component: crd + app.kubernetes.io/name: percona-server-mongodb + app.kubernetes.io/part-of: percona-server-mongodb-operator + app.kubernetes.io/version: v1.21.1 + name: perconaservermongodbrestores.psmdb.percona.com +spec: + group: psmdb.percona.com + names: + kind: PerconaServerMongoDBRestore + listKind: PerconaServerMongoDBRestoreList + plural: perconaservermongodbrestores + shortNames: + - psmdb-restore + singular: perconaservermongodbrestore + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Cluster name + jsonPath: .spec.clusterName + name: Cluster + type: string + - description: Job status + jsonPath: .status.state + name: Status + type: string + - description: Created time + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + backupName: + type: string + backupSource: + properties: + azure: + properties: + container: + type: string + credentialsSecret: + type: string + endpointUrl: + type: string + prefix: + type: string + required: + - credentialsSecret + type: object + completed: + format: date-time + type: string + destination: + type: string + error: + type: string + filesystem: + properties: + path: + type: string + required: + - path + type: object + gcs: + properties: + bucket: + type: string + chunkSize: + type: integer + credentialsSecret: + type: string + prefix: + type: string + retryer: + properties: + backoffInitial: + format: int64 + type: integer + backoffMax: + format: int64 + type: integer + backoffMultiplier: + type: number + required: + - backoffInitial + - backoffMax + - backoffMultiplier + type: object + required: + - bucket + - credentialsSecret + type: object + lastTransition: + format: date-time + type: string + lastWriteAt: + format: date-time + type: string + latestRestorableTime: + format: date-time + type: string + pbmName: + type: string + pbmPod: + type: string + pbmPods: + additionalProperties: + type: string + type: object + replsetNames: + items: + type: string + type: array + s3: + properties: + bucket: + type: string + credentialsSecret: + type: string + debugLogLevels: + type: string + endpointUrl: + type: string + forcePathStyle: + type: boolean + insecureSkipTLSVerify: + type: boolean + maxUploadParts: + format: int32 + type: integer + prefix: + type: string + region: + type: string + retryer: + properties: + maxRetryDelay: + type: string + minRetryDelay: + type: string + numMaxRetries: + type: integer + type: object + serverSideEncryption: + properties: + kmsKeyID: + type: string + sseAlgorithm: + type: string + sseCustomerAlgorithm: + type: string + sseCustomerKey: + type: string + type: object + storageClass: + type: string + uploadPartSize: + type: integer + required: + - bucket + type: object + size: + type: string + start: + format: date-time + type: string + state: + type: string + storageName: + type: string + type: + type: string + type: object + clusterName: + type: string + pitr: + properties: + date: + type: string + type: + type: string + type: object + x-kubernetes-validations: + - message: 'Time should be in format YYYY-MM-DD HH:MM:SS with valid + ranges (MM: 01-12, DD: 01-31, HH: 00-23, MM/SS: 00-59)' + rule: self.type != 'date' || (has(self.date) && self.date.matches('^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]) + ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$')) + - message: Date should not be used when 'latest' type is used + rule: self.type != 'latest' || !has(self.date) + replset: + type: string + selective: + properties: + namespaces: + items: + type: string + type: array + withUsersAndRoles: + type: boolean + type: object + storageName: + type: string + type: object + status: + properties: + completed: + format: date-time + type: string + error: + type: string + lastTransition: + format: date-time + type: string + pbmName: + type: string + pitrTarget: + type: string + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + labels: + app.kubernetes.io/component: crd + app.kubernetes.io/name: percona-server-mongodb + app.kubernetes.io/part-of: percona-server-mongodb-operator + app.kubernetes.io/version: v1.21.1 + name: perconaservermongodbs.psmdb.percona.com +spec: + group: psmdb.percona.com + names: + kind: PerconaServerMongoDB + listKind: PerconaServerMongoDBList + plural: perconaservermongodbs + shortNames: + - psmdb + singular: perconaservermongodb + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-2-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-2-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-3-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-3-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-4-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-4-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-5-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-5-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-6-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-6-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-7-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-7-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-8-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-8-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-9-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-9-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-10-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-10-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-11-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-11-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-12-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-12-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + allowUnsafeConfigurations: + type: boolean + backup: + properties: + annotations: + additionalProperties: + type: string + type: object + configuration: + properties: + backupOptions: + properties: + numParallelCollections: + type: integer + oplogSpanMin: + type: number + priority: + additionalProperties: + type: number + type: object + timeouts: + properties: + startingStatus: + format: int32 + type: integer + type: object + required: + - oplogSpanMin + type: object + restoreOptions: + properties: + batchSize: + type: integer + downloadChunkMb: + type: integer + maxDownloadBufferMb: + type: integer + mongodLocation: + type: string + mongodLocationMap: + additionalProperties: + type: string + type: object + numDownloadWorkers: + type: integer + numInsertionWorkers: + type: integer + numParallelCollections: + type: integer + type: object + type: object + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + enabled: + type: boolean + image: + type: string + labels: + additionalProperties: + type: string + type: object + pitr: + properties: + compressionLevel: + type: integer + compressionType: + type: string + enabled: + type: boolean + oplogOnly: + type: boolean + oplogSpanMin: + type: number + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + startingDeadlineSeconds: + format: int64 + type: integer + storages: + additionalProperties: + properties: + azure: + properties: + container: + type: string + credentialsSecret: + type: string + endpointUrl: + type: string + prefix: + type: string + required: + - credentialsSecret + type: object + filesystem: + properties: + path: + type: string + required: + - path + type: object + gcs: + properties: + bucket: + type: string + chunkSize: + type: integer + credentialsSecret: + type: string + prefix: + type: string + retryer: + properties: + backoffInitial: + format: int64 + type: integer + backoffMax: + format: int64 + type: integer + backoffMultiplier: + type: number + required: + - backoffInitial + - backoffMax + - backoffMultiplier + type: object + required: + - bucket + - credentialsSecret + type: object + main: + type: boolean + s3: + properties: + bucket: + type: string + credentialsSecret: + type: string + debugLogLevels: + type: string + endpointUrl: + type: string + forcePathStyle: + type: boolean + insecureSkipTLSVerify: + type: boolean + maxUploadParts: + format: int32 + type: integer + prefix: + type: string + region: + type: string + retryer: + properties: + maxRetryDelay: + type: string + minRetryDelay: + type: string + numMaxRetries: + type: integer + type: object + serverSideEncryption: + properties: + kmsKeyID: + type: string + sseAlgorithm: + type: string + sseCustomerAlgorithm: + type: string + sseCustomerKey: + type: string + type: object + storageClass: + type: string + uploadPartSize: + type: integer + required: + - bucket + type: object + type: + type: string + required: + - type + type: object + type: object + tasks: + items: + properties: + compressionLevel: + type: integer + compressionType: + type: string + enabled: + type: boolean + keep: + type: integer + name: + type: string + retention: + properties: + count: + minimum: 0 + type: integer + deleteFromStorage: + default: true + type: boolean + type: + enum: + - count + type: string + required: + - deleteFromStorage + - type + type: object + schedule: + type: string + storageName: + type: string + type: + enum: + - logical + - physical + - incremental + - incremental-base + type: string + required: + - enabled + - name + type: object + type: array + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + required: + - enabled + - image + type: object + clusterServiceDNSMode: + type: string + clusterServiceDNSSuffix: + type: string + crVersion: + type: string + enableExternalVolumeAutoscaling: + type: boolean + enableVolumeExpansion: + type: boolean + ignoreAnnotations: + items: + type: string + type: array + ignoreLabels: + items: + type: string + type: array + image: + type: string + imagePullPolicy: + type: string + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + initImage: + type: string + logcollector: + properties: + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + enabled: + type: boolean + image: + type: string + imagePullPolicy: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + type: object + multiCluster: + properties: + DNSSuffix: + type: string + enabled: + type: boolean + required: + - enabled + type: object + pause: + type: boolean + platform: + type: string + pmm: + properties: + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + customClusterName: + type: string + enabled: + type: boolean + image: + type: string + mongodParams: + type: string + mongosParams: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + serverHost: + type: string + required: + - image + type: object + replsets: + items: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + arbiter: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + priorityClassName: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + required: + - enabled + - size + type: object + clusterRole: + type: string + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + expose: + properties: + annotations: + additionalProperties: + type: string + type: object + enabled: + type: boolean + exposeType: + type: string + externalTrafficPolicy: + type: string + internalTrafficPolicy: + type: string + labels: + additionalProperties: + type: string + type: object + loadBalancerClass: + type: string + loadBalancerSourceRanges: + items: + type: string + type: array + serviceAnnotations: + additionalProperties: + type: string + type: object + serviceLabels: + additionalProperties: + type: string + type: object + type: + type: string + required: + - enabled + type: object + externalNodes: + items: + properties: + horizons: + additionalProperties: + type: string + type: object + host: + type: string + port: + type: integer + priority: + type: integer + tags: + additionalProperties: + type: string + type: object + votes: + type: integer + required: + - host + - priority + - votes + type: object + type: array + hidden: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - enabled + - size + type: object + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + nodeSelector: + additionalProperties: + type: string + type: object + nonvoting: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - enabled + - size + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + primaryPreferTagSelector: + additionalProperties: + type: string + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + replsetOverrides: + additionalProperties: + properties: + horizons: + additionalProperties: + type: string + type: object + host: + type: string + priority: + type: integer + tags: + additionalProperties: + type: string + type: object + type: object + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + splitHorizons: + additionalProperties: + additionalProperties: + type: string + type: object + type: object + storage: + properties: + directoryPerDB: + type: boolean + engine: + type: string + inMemory: + properties: + engineConfig: + properties: + inMemorySizeRatio: + type: number + type: object + type: object + mmapv1: + properties: + nsSize: + type: integer + smallfiles: + type: boolean + type: object + syncPeriodSecs: + type: integer + wiredTiger: + properties: + collectionConfig: + properties: + blockCompressor: + type: string + type: object + engineConfig: + properties: + cacheSizeRatio: + type: number + directoryForIndexes: + type: boolean + journalCompressor: + type: string + type: object + indexConfig: + properties: + prefixCompression: + type: boolean + type: object + type: object + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - size + type: object + type: array + roles: + items: + properties: + authenticationRestrictions: + items: + properties: + clientSource: + items: + type: string + type: array + serverAddress: + items: + type: string + type: array + type: object + type: array + db: + type: string + privileges: + items: + properties: + actions: + items: + type: string + type: array + resource: + properties: + cluster: + type: boolean + collection: + type: string + db: + type: string + type: object + required: + - actions + type: object + type: array + role: + type: string + roles: + items: + properties: + db: + type: string + role: + type: string + required: + - db + - role + type: object + type: array + required: + - db + - privileges + - role + type: object + type: array + schedulerName: + type: string + secrets: + properties: + encryptionKey: + type: string + keyFile: + type: string + ldapSecret: + type: string + sse: + type: string + ssl: + type: string + sslInternal: + type: string + users: + type: string + vault: + type: string + type: object + sharding: + properties: + balancer: + properties: + enabled: + type: boolean + type: object + configsvrReplSet: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + arbiter: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + priorityClassName: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + required: + - enabled + - size + type: object + clusterRole: + type: string + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + expose: + properties: + annotations: + additionalProperties: + type: string + type: object + enabled: + type: boolean + exposeType: + type: string + externalTrafficPolicy: + type: string + internalTrafficPolicy: + type: string + labels: + additionalProperties: + type: string + type: object + loadBalancerClass: + type: string + loadBalancerSourceRanges: + items: + type: string + type: array + serviceAnnotations: + additionalProperties: + type: string + type: object + serviceLabels: + additionalProperties: + type: string + type: object + type: + type: string + required: + - enabled + type: object + externalNodes: + items: + properties: + horizons: + additionalProperties: + type: string + type: object + host: + type: string + port: + type: integer + priority: + type: integer + tags: + additionalProperties: + type: string + type: object + votes: + type: integer + required: + - host + - priority + - votes + type: object + type: array + hidden: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - enabled + - size + type: object + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + nodeSelector: + additionalProperties: + type: string + type: object + nonvoting: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - enabled + - size + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + primaryPreferTagSelector: + additionalProperties: + type: string + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + replsetOverrides: + additionalProperties: + properties: + horizons: + additionalProperties: + type: string + type: object + host: + type: string + priority: + type: integer + tags: + additionalProperties: + type: string + type: object + type: object + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + splitHorizons: + additionalProperties: + additionalProperties: + type: string + type: object + type: object + storage: + properties: + directoryPerDB: + type: boolean + engine: + type: string + inMemory: + properties: + engineConfig: + properties: + inMemorySizeRatio: + type: number + type: object + type: object + mmapv1: + properties: + nsSize: + type: integer + smallfiles: + type: boolean + type: object + syncPeriodSecs: + type: integer + wiredTiger: + properties: + collectionConfig: + properties: + blockCompressor: + type: string + type: object + engineConfig: + properties: + cacheSizeRatio: + type: number + directoryForIndexes: + type: boolean + journalCompressor: + type: string + type: object + indexConfig: + properties: + prefixCompression: + type: boolean + type: object + type: object + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - size + type: object + enabled: + type: boolean + mongos: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + expose: + properties: + annotations: + additionalProperties: + type: string + type: object + exposeType: + type: string + externalTrafficPolicy: + type: string + internalTrafficPolicy: + type: string + labels: + additionalProperties: + type: string + type: object + loadBalancerClass: + type: string + loadBalancerSourceRanges: + items: + type: string + type: array + nodePort: + format: int32 + type: integer + serviceAnnotations: + additionalProperties: + type: string + type: object + serviceLabels: + additionalProperties: + type: string + type: object + servicePerPod: + type: boolean + type: + type: string + type: object + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostPort: + format: int32 + type: integer + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + port: + format: int32 + type: integer + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + setParameter: + properties: + cursorTimeoutMillis: + type: integer + type: object + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + type: object + required: + - enabled + type: object + tls: + properties: + allowInvalidCertificates: + type: boolean + certValidityDuration: + type: string + issuerConf: + properties: + group: + type: string + kind: + type: string + name: + type: string + required: + - name + type: object + mode: + type: string + type: object + unmanaged: + type: boolean + unsafeFlags: + properties: + backupIfUnhealthy: + type: boolean + mongosSize: + type: boolean + replsetSize: + type: boolean + terminationGracePeriod: + type: boolean + tls: + type: boolean + type: object + updateStrategy: + type: string + upgradeOptions: + properties: + apply: + type: string + schedule: + type: string + setFCV: + type: boolean + versionServiceEndpoint: + type: string + type: object + users: + items: + properties: + db: + type: string + name: + type: string + passwordSecretRef: + properties: + key: + type: string + name: + type: string + required: + - name + type: object + roles: + items: + properties: + db: + type: string + name: + type: string + required: + - db + - name + type: object + type: array + required: + - name + - roles + type: object + type: array + required: + - image + type: object + status: + properties: + backupConfigHash: + type: string + backupImage: + type: string + backupVersion: + type: string + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + host: + type: string + message: + type: string + mongoImage: + type: string + mongoVersion: + type: string + mongos: + properties: + message: + type: string + ready: + type: integer + size: + type: integer + status: + type: string + required: + - ready + - size + type: object + observedGeneration: + format: int64 + type: integer + pmmStatus: + type: string + pmmVersion: + type: string + ready: + format: int32 + type: integer + replsets: + additionalProperties: + properties: + added_as_shard: + type: boolean + clusterRole: + type: string + initialized: + type: boolean + members: + additionalProperties: + properties: + name: + type: string + state: + type: integer + stateStr: + type: string + type: object + type: object + message: + type: string + ready: + format: int32 + type: integer + size: + format: int32 + type: integer + status: + type: string + required: + - ready + - size + type: object + type: object + size: + format: int32 + type: integer + state: + type: string + required: + - ready + - size + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/templates/NOTES.txt b/packages/system/mongodb-operator/charts/psmdb-operator/templates/NOTES.txt new file mode 100644 index 00000000..9276ae03 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/templates/NOTES.txt @@ -0,0 +1,40 @@ +1. Percona Operator for MongoDB is deployed. + See if the operator Pod is running: + + kubectl get pods -l app.kubernetes.io/name=psmdb-operator --namespace {{ .Release.Namespace }} + + Check the operator logs if the Pod is not starting: + + export POD=$(kubectl get pods -l app.kubernetes.io/name=psmdb-operator --namespace {{ .Release.Namespace }} --output name) + kubectl logs $POD --namespace={{ .Release.Namespace }} + +2. Deploy the database cluster from psmdb-db chart: + + helm install my-db percona/psmdb-db --namespace={{ .Release.Namespace }} + +{{- if .Release.IsUpgrade }} + {{- $ctx := dict "upgradeCrd" false }} + {{- $crdNames := list "perconaservermongodbbackups.psmdb.percona.com" "perconaservermongodbrestores.psmdb.percona.com " "perconaservermongodbs.psmdb.percona.com" }} + {{- range $name := $crdNames }} + {{- $crd := lookup "apiextensions.k8s.io/v1" "CustomResourceDefinition" "" $name }} + {{- if $crd }} + {{- $crdLabels := (($crd).metadata).labels | default dict }} + {{- $crdVersion := index $crdLabels "app.kubernetes.io/version" }} + {{- if or (not $crdVersion) (semverCompare (printf "< %s" $.Chart.AppVersion) (trimPrefix "v" $crdVersion)) }} + {{- $_ := set $ctx "upgradeCrd" true }} + {{- end }} + {{- end }} + {{- end }} + {{- if $ctx.upgradeCrd }} + +** WARNING ** During Helm upgrade CRDs are not automatically upgraded. + +Consider upgrading to the latest version of the CRDs using the command below: + + kubectl apply --server-side --force-conflicts -f https://raw.githubusercontent.com/percona/percona-server-mongodb-operator/v{{ .Chart.AppVersion }}/deploy/crd.yaml + +Ensure all deprecated fields are reviewed as part of the upgrade process, especially when running multiple PSMDB Operator versions in the same cluster. Deprecated fields may be removed or unsupported in newer CRD versions. + {{- end }} +{{- end }} + +Read more in our documentation: https://docs.percona.com/percona-operator-for-mongodb/ diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/templates/_helpers.tpl b/packages/system/mongodb-operator/charts/psmdb-operator/templates/_helpers.tpl new file mode 100644 index 00000000..1bf81ed1 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/templates/_helpers.tpl @@ -0,0 +1,45 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "psmdb-operator.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "psmdb-operator.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "psmdb-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "psmdb-operator.labels" -}} +app.kubernetes.io/name: {{ include "psmdb-operator.name" . }} +helm.sh/chart: {{ include "psmdb-operator.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/templates/deployment.yaml b/packages/system/mongodb-operator/charts/psmdb-operator/templates/deployment.yaml new file mode 100644 index 00000000..14e2eb89 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/templates/deployment.yaml @@ -0,0 +1,112 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "psmdb-operator.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "psmdb-operator.labels" . | nindent 4 }} + {{- with .Values.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ include "psmdb-operator.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + app.kubernetes.io/name: {{ include "psmdb-operator.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "psmdb-operator.fullname" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - containerPort: 8080 + protocol: TCP + name: metrics + - containerPort: 8081 + protocol: TCP + name: health + command: + - percona-server-mongodb-operator + {{- if .Values.securityContext.readOnlyRootFilesystem }} + volumeMounts: + - name: tmpdir + mountPath: /tmp + {{- end }} + env: + - name: LOG_STRUCTURED + value: "{{ .Values.logStructured }}" + - name: LOG_LEVEL + value: "{{ .Values.logLevel }}" + - name: WATCH_NAMESPACE + {{- if .Values.watchAllNamespaces }} + value: "" + {{- else }} + value: "{{ default .Release.Namespace .Values.watchNamespace }}" + {{- end }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: OPERATOR_NAME + value: {{ default "percona-server-mongodb-operator" .Values.operatorName }} + - name: RESYNC_PERIOD + value: "{{ .Values.env.resyncPeriod }}" + - name: DISABLE_TELEMETRY + value: "{{ .Values.disableTelemetry }}" + {{- if .Values.maxConcurrentReconciles }} + - name: MAX_CONCURRENT_RECONCILES + value: "{{ .Values.maxConcurrentReconciles }}" + {{- end }} + livenessProbe: + httpGet: + path: /healthz + port: health + readinessProbe: + httpGet: + path: /healthz + port: health + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.securityContext.readOnlyRootFilesystem }} + volumes: + - name: tmpdir + emptyDir: {} + {{- end }} diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/templates/namespace.yaml b/packages/system/mongodb-operator/charts/psmdb-operator/templates/namespace.yaml new file mode 100644 index 00000000..cfc96d4d --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/templates/namespace.yaml @@ -0,0 +1,11 @@ +{{ if and .Values.watchNamespace .Values.createNamespace }} +{{ range ( split "," .Values.watchNamespace ) }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ trim . }} + annotations: + helm.sh/resource-policy: keep +--- +{{ end }} +{{ end }} diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/templates/role-binding.yaml b/packages/system/mongodb-operator/charts/psmdb-operator/templates/role-binding.yaml new file mode 100644 index 00000000..a815869d --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/templates/role-binding.yaml @@ -0,0 +1,41 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "psmdb-operator.fullname" . }} + namespace: {{ .Release.Namespace }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +--- +{{- end }} +{{- if .Values.rbac.create }} +{{- if or .Values.watchNamespace .Values.watchAllNamespaces }} +kind: ClusterRoleBinding +{{- else }} +kind: RoleBinding +{{- end }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: service-account-{{ include "psmdb-operator.fullname" . }} +{{- if not (or .Values.watchNamespace .Values.watchAllNamespaces) }} + namespace: {{ .Release.Namespace }} +{{- end }} + labels: +{{ include "psmdb-operator.labels" . | indent 4 }} +subjects: +- kind: ServiceAccount + name: {{ include "psmdb-operator.fullname" . }} + {{- if or .Values.watchNamespace .Values.watchAllNamespaces }} + namespace: {{ .Release.Namespace }} + {{- end }} +roleRef: + {{- if or .Values.watchNamespace .Values.watchAllNamespaces }} + kind: ClusterRole + {{- else }} + kind: Role + {{- end }} + name: {{ include "psmdb-operator.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/templates/role.yaml b/packages/system/mongodb-operator/charts/psmdb-operator/templates/role.yaml new file mode 100644 index 00000000..4d65e6a7 --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/templates/role.yaml @@ -0,0 +1,167 @@ +{{- if .Values.rbac.create }} +{{- if or .Values.watchNamespace .Values.watchAllNamespaces }} +kind: ClusterRole +{{- else }} +kind: Role +{{- end }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "psmdb-operator.fullname" . }} +{{- if not (or .Values.watchNamespace .Values.watchAllNamespaces) }} + namespace: {{ .Release.Namespace }} +{{- end }} + labels: +{{ include "psmdb-operator.labels" . | indent 4 }} +rules: + - apiGroups: + - psmdb.percona.com + resources: + - perconaservermongodbs + - perconaservermongodbs/status + - perconaservermongodbs/finalizers + - perconaservermongodbbackups + - perconaservermongodbbackups/status + - perconaservermongodbbackups/finalizers + - perconaservermongodbrestores + - perconaservermongodbrestores/status + - perconaservermongodbrestores/finalizers + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +{{- if or .Values.watchNamespace .Values.watchAllNamespaces }} + - apiGroups: + - admissionregistration.k8s.io + resources: + - validatingwebhookconfigurations + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - list + - watch +{{- end }} + - apiGroups: + - "" + resources: + - pods + - pods/exec + - services + - persistentvolumeclaims + - secrets + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - apps + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - batch + resources: + - cronjobs + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - events.k8s.io + - "" + resources: + - events + verbs: + - get + - list + - watch + - create + - patch + - apiGroups: + - certmanager.k8s.io + - cert-manager.io + resources: + - issuers + - certificates + - certificaterequests + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - deletecollection + - apiGroups: + - net.gke.io + - multicluster.x-k8s.io + resources: + - serviceexports + - serviceimports + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - deletecollection +{{- end }} diff --git a/packages/system/mongodb-operator/charts/psmdb-operator/values.yaml b/packages/system/mongodb-operator/charts/psmdb-operator/values.yaml new file mode 100644 index 00000000..cc5ece0b --- /dev/null +++ b/packages/system/mongodb-operator/charts/psmdb-operator/values.yaml @@ -0,0 +1,103 @@ +# Default values for psmdb-operator. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: percona/percona-server-mongodb-operator + tag: 1.21.1 + pullPolicy: IfNotPresent + +# disableTelemetry: according to +# https://docs.percona.com/percona-operator-for-mongodb/telemetry.html +# this is how you can disable telemetry collection +# default is false which means telemetry will be collected +disableTelemetry: false + +# set if you want to specify a namespace to watch +# defaults to `.Release.namespace` if left blank +# multiple namespaces can be specified and separated by comma +# watchNamespace: +# set if you want that watched namespaces are created by helm +# createNamespace: false + +# set if operator should be deployed in cluster wide mode. defaults to false +watchAllNamespaces: false + +# rbac: settings for deployer RBAC creation +rbac: + # rbac.create: if false RBAC resources should be in place + create: true + +# serviceAccount: settings for Service Accounts used by the deployer +serviceAccount: + # serviceAccount.create: Whether to create the Service Accounts or not + create: true + # annotations to add to the service account + annotations: {} + +# annotations to add to the operator deployment +annotations: {} + +# labels to add to the operator deployment +labels: {} + +# annotations to add to the operator pod +podAnnotations: {} + # prometheus.io/scrape: "true" + # prometheus.io/port: "8080" + +# labels to the operator pod +podLabels: {} + +podSecurityContext: {} + # runAsNonRoot: true + # runAsUser: 2 + # runAsGroup: 2 + # fsGroup: 2 + # fsGroupChangePolicy: "OnRootMismatch" + +securityContext: {} + # allowPrivilegeEscalation: false + # capabilities: + # drop: + # - ALL + # seccompProfile: + # type: RuntimeDefault + +# set if you want to use a different operator name +# defaults to `percona-server-mongodb-operator` +# operatorName: + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +env: + resyncPeriod: 5s + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +logStructured: false +logLevel: "INFO" + +# maxConcurrentReconciles controls the number of concurrent workers +# that can reconcile resources in Percona Server for MongoDB clusters in parallel. +maxConcurrentReconciles: "1" diff --git a/packages/system/mongodb-operator/values.yaml b/packages/system/mongodb-operator/values.yaml new file mode 100644 index 00000000..b51a4e1d --- /dev/null +++ b/packages/system/mongodb-operator/values.yaml @@ -0,0 +1,2 @@ +psmdb-operator: + watchAllNamespaces: true diff --git a/packages/system/mongodb-rd/Chart.yaml b/packages/system/mongodb-rd/Chart.yaml new file mode 100644 index 00000000..41aafc6d --- /dev/null +++ b/packages/system/mongodb-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: mongodb-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/mongodb-rd/Makefile b/packages/system/mongodb-rd/Makefile new file mode 100644 index 00000000..fa32b825 --- /dev/null +++ b/packages/system/mongodb-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=mongodb-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/mongodb-rd/cozyrds/mongodb.yaml b/packages/system/mongodb-rd/cozyrds/mongodb.yaml new file mode 100644 index 00000000..78141023 --- /dev/null +++ b/packages/system/mongodb-rd/cozyrds/mongodb.yaml @@ -0,0 +1,40 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: mongodb +spec: + application: + kind: MongoDB + singular: mongodb + plural: mongodbs + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of MongoDB replicas in replica set.","type":"integer","default":3},"resources":{"description":"Explicit CPU and memory configuration for each MongoDB replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"version":{"description":"MongoDB major version to deploy.","type":"string","default":"v8","enum":["v8","v7","v6"]},"sharding":{"description":"Enable sharded cluster mode. When disabled, deploys a replica set.","type":"boolean","default":false},"shardingConfig":{"description":"Configuration for sharded cluster mode.","type":"object","default":{},"required":["configServerSize","configServers","mongos"],"properties":{"configServerSize":{"description":"PVC size for config servers.","default":"3Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"configServers":{"description":"Number of config server replicas.","type":"integer","default":3},"mongos":{"description":"Number of mongos router replicas.","type":"integer","default":2},"shards":{"description":"List of shard configurations.","type":"array","default":[{"name":"rs0","replicas":3,"size":"10Gi"}],"items":{"type":"object","required":["name","replicas","size"],"properties":{"name":{"description":"Shard name.","type":"string"},"replicas":{"description":"Number of replicas in this shard.","type":"integer"},"size":{"description":"PVC size for this shard.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}}},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user (auto-generated if omitted).","type":"string"}}}},"databases":{"description":"Databases configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"roles":{"description":"Roles assigned to users.","type":"object","properties":{"admin":{"description":"List of users with admin privileges (readWrite + dbAdmin).","type":"array","items":{"type":"string"}},"readonly":{"description":"List of users with read-only privileges.","type":"array","items":{"type":"string"}}}}}}},"backup":{"description":"Backup configuration.","type":"object","default":{},"required":["enabled"],"properties":{"destinationPath":{"description":"Destination path for backups (e.g. s3://bucket/path/).","type":"string","default":"s3://bucket/path/to/folder/"},"enabled":{"description":"Enable regular backups.","type":"boolean","default":false},"endpointURL":{"description":"S3 endpoint URL for uploads.","type":"string","default":"http://minio-gateway-service:9000"},"retentionPolicy":{"description":"Retention policy (e.g. \"30d\").","type":"string","default":"30d"},"s3AccessKey":{"description":"Access key for S3 authentication.","type":"string","default":""},"s3SecretKey":{"description":"Secret key for S3 authentication.","type":"string","default":""},"schedule":{"description":"Cron schedule for automated backups.","type":"string","default":"0 2 * * *"}}},"bootstrap":{"description":"Bootstrap configuration.","type":"object","default":{},"required":["backupName","enabled"],"properties":{"backupName":{"description":"Name of backup to restore from.","type":"string","default":""},"enabled":{"description":"Whether to restore from a backup.","type":"boolean","default":false},"recoveryTime":{"description":"Timestamp for point-in-time recovery; empty means latest.","type":"string","default":""}}}}} + release: + prefix: mongodb- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-mongodb-application-default-mongodb + namespace: cozy-system + dashboard: + category: PaaS + singular: MongoDB + plural: MongoDB Instances + description: Managed MongoDB service + tags: + - database + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX3JhZGlhbF8zMzBfNDg5ODEpIi8+CjxwYXRoIGQ9Ik05NS4xMzg3IDYxLjQwMjhDODkuNjI3NiAzNy4yMjc1IDc2LjYwMzIgMjkuMjc4NSA3NS4yMDA3IDI2LjI0MTZDNzMuNjY3IDI0LjA5OSA3Mi4xMTI5IDIwLjI4NzkgNzIuMTEyOSAyMC4yODc5QzcyLjA4NzMgMjAuMjIzNiA3Mi4wNDY0IDIwLjExMDEgNzEuOTk4NyAyMEM3MS44NDAyIDIyLjE0MjYgNzEuNzU4NCAyMi45NjkyIDY5LjcyMDMgMjUuMTMwNUM2Ni41NjQzIDI3LjU4MzEgNTAuMzcyIDQxLjA4NzYgNDkuMDU0NyA2OC41NTRDNDcuODI2MSA5NC4xNzA4IDY3LjY3MiAxMDkuNDM1IDcwLjM1NiAxMTEuMzgxTDcwLjY2MSAxMTEuNTk2VjExMS41NzhDNzAuNjc4IDExMS43MDcgNzEuNTEzIDExNy42NzUgNzIuMDk5MyAxMjRINzQuMjAyMUM3NC42OTU1IDExOS41MjkgNzUuNDM1MSAxMTUuMDg5IDc2LjQxNzUgMTEwLjY5OUw3Ni41ODc5IDExMC41ODlDNzcuNzg4NCAxMDkuNzMzIDc4LjkzMzEgMTA4LjgwMiA4MC4wMTQ4IDEwNy44MDJMODAuMTM3NSAxMDcuNjkyQzg1Ljg0MjggMTAyLjQ1MyA5Ni4wOTk4IDkwLjMzNjEgOTUuOTk5MyA3MS4wMTY4Qzk1Ljk3OCA2Ny43OTQxIDk1LjY5MDIgNjQuNTc4NiA5NS4xMzg3IDYxLjQwMjhaTTcxLjg3NiA5Ni45MTgxQzcxLjg3NiA5Ni45MTgxIDcxLjg3NiA2MC45ODk2IDczLjA2ODkgNjAuOTk2M0M3My45OTkzIDYwLjk5NjMgNzUuMjA0MSAxMDcuMzQgNzUuMjA0MSAxMDcuMzRDNzMuNTQ3NyAxMDcuMTQyIDcxLjg3NiA5OS43MTI4IDcxLjg3NiA5Ni45MTgxWiIgZmlsbD0id2hpdGUiLz4KPGRlZnM+CjxyYWRpYWxHcmFkaWVudCBpZD0icGFpbnQwX3JhZGlhbF8zMzBfNDg5ODEiIGN4PSIwIiBjeT0iMCIgcj0iMSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoMS4zMjI5OGUtMDUgLTcuNTAwMDEpIHJvdGF0ZSg0NC43MTc4KSBzY2FsZSgyMTUuMzE3IDMxMi40NTUpIj4KPHN0b3Agc3RvcC1jb2xvcj0iIzI1RkY4MCIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMxM0FBNTIiLz4KPC9yYWRpYWxHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "version"], ["spec", "sharding"], ["spec", "shardingConfig"], ["spec", "shardingConfig", "configServers"], ["spec", "shardingConfig", "configServerSize"], ["spec", "shardingConfig", "mongos"], ["spec", "shardingConfig", "shards"], ["spec", "users"], ["spec", "databases"], ["spec", "backup"], ["spec", "backup", "enabled"], ["spec", "backup", "schedule"], ["spec", "backup", "retentionPolicy"], ["spec", "backup", "destinationPath"], ["spec", "backup", "endpointURL"], ["spec", "backup", "s3AccessKey"], ["spec", "backup", "s3SecretKey"], ["spec", "bootstrap"], ["spec", "bootstrap", "enabled"], ["spec", "bootstrap", "recoveryTime"], ["spec", "bootstrap", "backupName"]] + secrets: + exclude: [] + include: + - resourceNames: + - mongodb-{{ .name }}-credentials + services: + exclude: [] + include: + - resourceNames: + - mongodb-{{ .name }}-rs0 + - mongodb-{{ .name }}-mongos + - mongodb-{{ .name }}-external diff --git a/packages/system/mongodb-rd/templates/cozyrd.yaml b/packages/system/mongodb-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/mongodb-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/mongodb-rd/values.yaml b/packages/system/mongodb-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/mongodb-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/monitoring-agents/Makefile b/packages/system/monitoring-agents/Makefile index 42e762c3..339b15a2 100644 --- a/packages/system/monitoring-agents/Makefile +++ b/packages/system/monitoring-agents/Makefile @@ -1,7 +1,7 @@ export NAME=monitoring-agents export NAMESPACE=cozy-monitoring -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts @@ -11,10 +11,6 @@ update: helm pull prometheus-community/kube-state-metrics --untar --untardir charts # Node-exporter helm pull prometheus-community/prometheus-node-exporter --untar --untardir charts - # Metrics-server - helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/ - helm repo update metrics-server - helm pull metrics-server/metrics-server --untar --untardir charts # Fluent-bit helm repo add fluent https://fluent.github.io/helm-charts helm repo update fluent diff --git a/packages/system/monitoring-agents/alerts/gpu-recording.rules.yaml b/packages/system/monitoring-agents/alerts/gpu-recording.rules.yaml new file mode 100644 index 00000000..5e0f9ea0 --- /dev/null +++ b/packages/system/monitoring-agents/alerts/gpu-recording.rules.yaml @@ -0,0 +1,172 @@ +apiVersion: operator.victoriametrics.com/v1beta1 +kind: VMRule +metadata: + name: alerts-gpu-recording.rules +spec: + groups: + - name: gpu.recording.cluster.1m + interval: 1m + params: {} + rules: + - record: cluster:gpu_count:total + expr: count(group by (UUID) (DCGM_FI_DEV_GPU_UTIL)) + # Kube-allocated GPU count: GPUs requested by *active* pods — Pending + # and Running only. Source of truth for "what tenants asked for" — used + # for capacity planning and billing. Includes system pods so it stays + # consistent with cluster:gpu_count:total when computing :free. + # + # Phase filter via group_left() on kube_pod_status_phase matches the + # canonical pattern from k8s.rules.container_resource.yaml. Without it + # kube-state-metrics keeps series for Failed/Succeeded pods until the + # apiserver garbage-collects them, which inflates billing hours and + # can push :free negative. + - record: cluster:gpu_count:allocated + expr: | + sum( + kube_pod_container_resource_requests{resource="nvidia_com_gpu"} + * on (namespace, pod) group_left() max by (namespace, pod) ( + kube_pod_status_phase{phase=~"Pending|Running"} == 1 + ) + ) + # clamp_min guards against transients at DCGM/kube-state-metrics + # restart where cluster:gpu_count:total dips before :allocated catches + # up, or rare label drift between the two sources. + - record: cluster:gpu_count:free + expr: clamp_min(cluster:gpu_count:total - (cluster:gpu_count:allocated or vector(0)), 0) + # Cluster-layer filter asymmetry — intentional, not a bug: + # + # * cluster:gpu_count:total and cluster:gpu_power_watts:sum do NOT + # filter cozy-*/kube-* namespaces because they describe the + # physical hardware fleet. A GPU draws power and occupies a + # slot regardless of which namespace's pod happens to hold it; + # excluding infra pods would under-report raw capacity and + # break capacity-planning math. + # + # No namespace filter — DCGM exporter metrics carry the exporter's + # own namespace, not the workload namespace. Filtering by namespace + # here would silently drop all series. + - record: cluster:gpu_util:avg + expr: avg(DCGM_FI_DEV_GPU_UTIL) + - record: cluster:gpu_power_watts:sum + expr: sum(DCGM_FI_DEV_POWER_USAGE) + + - name: gpu.recording.node.1m + interval: 1m + params: {} + rules: + # Kube-requested GPU count per namespace — billable/allocation view. + # This is the only namespace-level rule that works correctly because + # kube_pod_container_resource_requests carries the real workload + # namespace, unlike DCGM exporter metrics which carry the exporter's + # own namespace (cozy-gpu-operator). + - record: namespace:gpu_count:allocated + expr: | + sum by (namespace) ( + kube_pod_container_resource_requests{resource="nvidia_com_gpu", namespace!="", namespace!~"cozy-.*|kube-.*"} + * on (namespace, pod) group_left() max by (namespace, pod) ( + kube_pod_status_phase{phase=~"Pending|Running"} == 1 + ) + ) + # Hardware metrics aggregated per node (Hostname). DCGM exporter + # metrics carry a capital-H "Hostname" label identifying the node + # but no usable workload namespace — so hardware telemetry is + # aggregated at node/GPU granularity, not namespace. + - record: node:gpu_util:avg + expr: avg by (Hostname) (DCGM_FI_DEV_GPU_UTIL) + - record: node:tensor_active:avg + expr: avg by (Hostname) (DCGM_FI_PROF_PIPE_TENSOR_ACTIVE) + - record: node:fb_used_bytes:sum + expr: sum by (Hostname) (DCGM_FI_DEV_FB_USED) * 1048576 + - record: node:power_watts:sum + expr: sum by (Hostname) (DCGM_FI_DEV_POWER_USAGE) + + # Known gap: there is no lower-bound sanity alert for under-reporting. + # If DCGM ever switches POWER/THERMAL_VIOLATION counter units the other + # direction — e.g. from the current nanoseconds back to microseconds, + # making rate()/1e9 produce values around 0.001 instead of real + # fractions — the throttle signal would silently collapse to near-zero + # instead of plateauing at 1.0. GPUThrottleFractionOverOne below catches + # the >1 drift; the <<1 drift would require correlation with independent + # signals (power draw vs TDP, clock dips) that we do not yet wire up. + # Documented here so future maintainers know this is a known gap, not + # an oversight. + - name: gpu.recording.efficiency.1m + interval: 1m + params: {} + rules: + # Tensor hardware saturation per GPU — the honest "am I using the GPU" + # metric for AI/LLM workloads. Aggregated at GPU level (Hostname + + # gpu + UUID) because DCGM metrics don't carry workload namespace. + # Stored as a 0..1 ratio; consumers multiply by 100 at display time. + - record: gpu:tensor_saturation:avg5m + expr: | + avg by (Hostname, gpu, UUID) ( + avg_over_time(DCGM_FI_PROF_PIPE_TENSOR_ACTIVE[5m]) + ) + + # Power efficiency per GPU — utilization per watt, reveals + # unoptimized workloads. Explicit on(...) pins the matching set + # to GPU-identifying labels. + - record: gpu:util_per_watt:avg5m + expr: | + max by (Hostname, gpu, UUID) ( + avg_over_time(DCGM_FI_DEV_GPU_UTIL[5m]) + ) + / on (Hostname, gpu, UUID) + clamp_min( + max by (Hostname, gpu, UUID) ( + avg_over_time(DCGM_FI_DEV_POWER_USAGE[5m]) + ), + 1 + ) + + # Fraction of time power-throttled (TDP cap) — 1.0 = fully throttled. + # DCGM_FI_DEV_*_VIOLATION is documented as µs but on A10/DCGM 3.x the + # counter grows in nanoseconds in practice — divide by 1e9 to get a + # 0..1 fraction (verified empirically when /1e6 yielded >100× reality). + # clamp_max protects against rate() artefacts at counter resets. + # + # max by (Hostname, gpu, UUID) collapses duplicate series from + # dcgm-exporter's pod-mapping labels (one physical GPU may appear + # under multiple pod/container labels during restarts or under + # MIG/MPS). Throttling is a physical-GPU property; taking max + # keeps consumer avg(...) honest — a naive avg() would dilute the + # signal by the number of pods sharing the GPU. + - record: gpu:power_throttle_fraction:rate5m + expr: clamp_max(max by (Hostname, gpu, UUID) (rate(DCGM_FI_DEV_POWER_VIOLATION[5m]) / 1e9), 1) + + # Fraction of time thermal-throttled. + - record: gpu:thermal_throttle_fraction:rate5m + expr: clamp_max(max by (Hostname, gpu, UUID) (rate(DCGM_FI_DEV_THERMAL_VIOLATION[5m]) / 1e9), 1) + + # Regression watch — the /1e9 divisor on *_VIOLATION was derived + # empirically against DCGM 3.x on A10. If a future DCGM version + # restores the documented µs units, pre-clamp values would exceed 1.0 + # while clamp_max(..., 1) silently masks the drift — recorded + # throttle fractions would plateau at 1.0 and consumers would think + # every GPU is always throttled. This alert fires on that condition + # so we can rescale to /1e6 before dashboards start lying. + - name: gpu.recording.throttle.validation.5m + interval: 5m + params: {} + rules: + - alert: GPUThrottleFractionOverOne + expr: | + max by (Hostname, gpu, UUID) (rate(DCGM_FI_DEV_POWER_VIOLATION[5m]) / 1e9) > 1 + or + max by (Hostname, gpu, UUID) (rate(DCGM_FI_DEV_THERMAL_VIOLATION[5m]) / 1e9) > 1 + for: 15m + labels: + severity: warning + component: gpu-monitoring + annotations: + summary: "DCGM throttle fraction exceeds 1.0 pre-clamp on {{ $labels.Hostname }}/{{ $labels.gpu }}" + description: | + gpu:{power,thermal}_throttle_fraction:rate5m clamps to 1.0, but the raw + rate(DCGM_FI_DEV_*_VIOLATION)/1e9 value is already >1 on this GPU — the + empirical nanosecond assumption is broken. Likely the DCGM exporter + version changed and the counter now grows in its documented µs units. + Re-verify on the exporter Pod and adjust the divisor (/1e9 → /1e6) in + gpu.recording.efficiency.1m before dashboards plateau at 100% throttle. + verified_on: "NVIDIA A10, DCGM 3.x — other GPU families (H100, L40S) may require a different divisor" + runbook: "If this alert fires, DCGM may have changed POWER_VIOLATION/THERMAL_VIOLATION counter units. Recalibrate by comparing raw counter rate against known throttle events; see gpu-recording.rules.yaml comments." diff --git a/packages/system/monitoring-agents/alerts/kubeovn-plunger.yaml b/packages/system/monitoring-agents/alerts/kubeovn-plunger.yaml new file mode 100644 index 00000000..92517a3f --- /dev/null +++ b/packages/system/monitoring-agents/alerts/kubeovn-plunger.yaml @@ -0,0 +1,56 @@ +apiVersion: operator.victoriametrics.com/v1beta1 +kind: VMRule +metadata: + name: alerts-kubeovn-plunger +spec: + groups: + - name: kubeovn-plunger + params: {} + rules: + - alert: OVNMemberNotConnected + expr: ovn_member_connected == 0 + for: 2m + labels: { severity: warning } + annotations: + summary: "OVN {{ $labels.db }} member not connected" + description: "Member {{ $labels.sid }} (ip={{ $labels.ip }}) reports no cluster connectivity." + + - alert: OVNFollowerStale + expr: ovn_member_last_msg_ms > 10000 + for: 1m + labels: { severity: warning } + annotations: + summary: "OVN {{ $labels.db }} follower stale" + description: "Follower {{ $labels.sid }} has last_msg_ms={{ $value }} (>10s) to leader." + + - alert: OVNMemberLagging + expr: ovn_member_index_gap > 1000 + for: 2m + labels: { severity: warning } + annotations: + summary: "OVN {{ $labels.db }} member lagging" + description: "Log index gap {{ $value }} behind leader (sid={{ $labels.sid }}) is high." + + - alert: OVNMemberMissingSelfReporter + expr: ovn_member_missing_reporter == 1 + for: 10m + labels: { severity: warning } + annotations: + summary: "OVN {{ $labels.db }} member not reporting" + description: "SID {{ $labels.sid }} appears in DB but produced no self-view for ≥10m." + + - alert: OVNConsensusSplitView + expr: ovn_cluster_all_agree == 0 and on (db, cid) ovn_cluster_quorum == 1 + for: 5m + labels: { severity: warning } + annotations: + summary: "OVN {{ $labels.db }} inconsistent views" + description: "Majority exists but not all members agree. Investigate minority nodes." + + - alert: OVNSuspectStale + expr: sum by (db,cid) (ovn_consensus_suspect_stale) > 0 + for: 2m + labels: { severity: warning } + annotations: + summary: "OVN {{ $labels.db }} stale member(s) suspected" + description: "Candidates exist to kick from cluster membership." diff --git a/packages/system/monitoring-agents/templates/cadvisor-scrape.yaml b/packages/system/monitoring-agents/templates/cadvisor-scrape.yaml index 9c42daa1..a1822332 100644 --- a/packages/system/monitoring-agents/templates/cadvisor-scrape.yaml +++ b/packages/system/monitoring-agents/templates/cadvisor-scrape.yaml @@ -19,10 +19,8 @@ spec: - __name__ path: /metrics/cadvisor relabelConfigs: - - action: labelmap - regex: __meta_kubernetes_node_label_(.+) - - action: labeldrop - regex: '.*node_kubevirt_io.*' + - action: labelkeep + regex: "__address__|instance|__scheme__|__scrape_timeout__|__scrape_interval__|metrics_path|node|job|__metrics_path__" - sourceLabels: [__metrics_path__] targetLabel: metrics_path - replacement: cadvisor diff --git a/packages/system/monitoring-agents/templates/coredns-scrape.yaml b/packages/system/monitoring-agents/templates/coredns-scrape.yaml index 9c7253eb..223d553f 100644 --- a/packages/system/monitoring-agents/templates/coredns-scrape.yaml +++ b/packages/system/monitoring-agents/templates/coredns-scrape.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Service metadata: - name: coredns + name: coredns-metrics namespace: kube-system labels: app: coredns @@ -19,7 +19,7 @@ spec: apiVersion: operator.victoriametrics.com/v1beta1 kind: VMServiceScrape metadata: - name: coredns + name: coredns-metrics namespace: cozy-monitoring spec: selector: diff --git a/packages/system/monitoring-agents/templates/kube-ovn-plunger-scrape.yaml b/packages/system/monitoring-agents/templates/kube-ovn-plunger-scrape.yaml new file mode 100644 index 00000000..8a0a03c6 --- /dev/null +++ b/packages/system/monitoring-agents/templates/kube-ovn-plunger-scrape.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: operator.victoriametrics.com/v1beta1 +kind: VMServiceScrape +metadata: + name: kubeovn-plunger + namespace: cozy-monitoring +spec: + selector: + matchLabels: + app.kubernetes.io/name: kube-ovn-plunger + app.kubernetes.io/instance: kubeovn-plunger + namespaceSelector: + matchNames: + - "cozy-kubeovn" + endpoints: + - port: metrics + relabelConfigs: + - action: labeldrop + regex: (endpoint|pod|container) + - replacement: kubeovn-plunger + targetLabel: job + - targetLabel: tier + replacement: cluster diff --git a/packages/system/monitoring-agents/templates/kubelet-scrape.yaml b/packages/system/monitoring-agents/templates/kubelet-scrape.yaml index d513e7ad..33dcc3bc 100644 --- a/packages/system/monitoring-agents/templates/kubelet-scrape.yaml +++ b/packages/system/monitoring-agents/templates/kubelet-scrape.yaml @@ -19,10 +19,8 @@ spec: - __name__ path: /metrics/probes relabelConfigs: - - action: labelmap - regex: __meta_kubernetes_node_label_(.+) - - action: labeldrop - regex: '.*node_kubevirt_io.*' + - action: labelkeep + regex: "__address__|instance|__scheme__|__scrape_timeout__|__scrape_interval__|metrics_path|node|job|__metrics_path__|container|pod|namespace" - sourceLabels: [__metrics_path__] targetLabel: metrics_path - replacement: kubelet @@ -51,10 +49,8 @@ spec: regex: (rest_client_request_duration_seconds_bucket|rest_client_request_duration_seconds_sum|rest_client_request_duration_seconds_count) source_labels: [__name__] relabelConfigs: - - action: labelmap - regex: __meta_kubernetes_node_label_(.+) - - action: labeldrop - regex: '.*node_kubevirt_io.*' + - action: labelkeep + regex: "__address__|instance|__scheme__|__scrape_timeout__|__scrape_interval__|metrics_path|node|job|__metrics_path__|container|pod|namespace" - sourceLabels: - __metrics_path__ targetLabel: metrics_path diff --git a/packages/system/monitoring-agents/templates/vmagent.yaml b/packages/system/monitoring-agents/templates/vmagent.yaml index 56b756e7..00ab63c1 100644 --- a/packages/system/monitoring-agents/templates/vmagent.yaml +++ b/packages/system/monitoring-agents/templates/vmagent.yaml @@ -10,12 +10,12 @@ spec: shardCount: 1 externalLabels: cluster: {{ .Values.vmagent.externalLabels.cluster }} - tenant: {{ .Values.vmagent.externalLabels.tenant }} + tenant: {{ .Values.global.target }} extraArgs: {{- toYaml (deepCopy .Values.vmagent.extraArgs | mergeOverwrite (fromYaml (include "monitoring-agents.vmagent.defaultExtraArgs" .))) | nindent 4 }} remoteWrite: {{- range .Values.vmagent.remoteWrite.urls }} - - url: {{ . | quote }} + - url: {{ tpl . $ | quote }} {{- end }} scrapeInterval: 30s diff --git a/packages/system/monitoring-agents/templates/vpa.yaml b/packages/system/monitoring-agents/templates/vpa.yaml index fa672d82..4da978e7 100644 --- a/packages/system/monitoring-agents/templates/vpa.yaml +++ b/packages/system/monitoring-agents/templates/vpa.yaml @@ -9,6 +9,7 @@ spec: name: vmagent updatePolicy: updateMode: Auto + minReplicas: 1 resourcePolicy: containerPolicies: - containerName: config-reloader diff --git a/packages/system/monitoring-agents/values.yaml b/packages/system/monitoring-agents/values.yaml index 8c13c079..bcdee0e0 100644 --- a/packages/system/monitoring-agents/values.yaml +++ b/packages/system/monitoring-agents/values.yaml @@ -1,31 +1,5 @@ -metrics-server: - defaultArgs: - - --cert-dir=/tmp - - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname - - --kubelet-use-node-status-port - - --metric-resolution=15s - - --kubelet-insecure-tls - - metrics: - enabled: true - - serviceMonitor: - enabled: true - - victoria-logs-single: - server: - persistentVolume: - enabled: true - size: 10Gi - - grafana: - enabled: false - kube-state-metrics: - enabled: false - prometheus-node-exporter: - enabled: false - alertmanager: - name: vmalertmanager-alertmanager +global: + target: cozy-monitoring kube-state-metrics: extraArgs: @@ -304,11 +278,10 @@ kube-state-metrics: vmagent: externalLabels: cluster: cozystack - tenant: tenant-root remoteWrite: urls: - - http://vminsert-shortterm.tenant-root.svc:8480/insert/0/prometheus - - http://vminsert-longterm.tenant-root.svc:8480/insert/0/prometheus + - http://vminsert-shortterm.{{ .Values.global.target }}.svc:8480/insert/0/prometheus + - http://vminsert-longterm.{{ .Values.global.target }}.svc:8480/insert/0/prometheus extraArgs: {} fluent-bit: @@ -371,8 +344,8 @@ fluent-bit: [OUTPUT] Name http Match kube.* - Host vlogs-generic.tenant-root.svc - port 9428 + Host vlinsert-generic.{{ .Values.global.target }}.svc + port 9481 compress gzip uri /insert/jsonline?_stream_fields=log_source,stream,kubernetes_pod_name,kubernetes_container_name,kubernetes_namespace_name&_msg_field=log&_time_field=date format json_lines @@ -382,8 +355,8 @@ fluent-bit: [OUTPUT] Name http Match events.* - Host vlogs-generic.tenant-root.svc - port 9428 + Host vlinsert-generic.{{ .Values.global.target }}.svc + port 9481 compress gzip uri /insert/jsonline?_stream_fields=log_source,reason,meatdata_namespace,metadata_name&_msg_field=message&_time_field=date format json_lines @@ -393,8 +366,8 @@ fluent-bit: [OUTPUT] Name http Match audit.* - Host vlogs-generic.tenant-root.svc - port 9428 + Host vlinsert-generic.{{ .Values.global.target }}.svc + port 9481 compress gzip uri /insert/jsonline?_stream_fields=log_source,stage,user_username,verb,requestUri&_msg_field=requestURI&_time_field=date format json_lines @@ -445,7 +418,7 @@ fluent-bit: [FILTER] Name modify Match * - Add tenant tenant-root + Add tenant {{ .Values.global.target }} [FILTER] Name modify Match * diff --git a/packages/system/monitoring-rd/Chart.yaml b/packages/system/monitoring-rd/Chart.yaml new file mode 100644 index 00000000..cac8a99d --- /dev/null +++ b/packages/system/monitoring-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: monitoring-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/monitoring-rd/Makefile b/packages/system/monitoring-rd/Makefile new file mode 100644 index 00000000..5b0bf43b --- /dev/null +++ b/packages/system/monitoring-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=monitoring-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/monitoring-rd/cozyrds/monitoring.yaml b/packages/system/monitoring-rd/cozyrds/monitoring.yaml new file mode 100644 index 00000000..ce4d75c5 --- /dev/null +++ b/packages/system/monitoring-rd/cozyrds/monitoring.yaml @@ -0,0 +1,46 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: monitoring +spec: + application: + kind: Monitoring + singular: monitoring + plural: monitorings + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"host":{"description":"The hostname used to access Grafana externally (defaults to 'grafana' subdomain for the tenant host).","type":"string","default":""},"metricsStorages":{"description":"Configuration of metrics storage instances.","type":"array","default":[{"deduplicationInterval":"15s","name":"shortterm","retentionPeriod":"3d","storage":"10Gi","storageClassName":""},{"deduplicationInterval":"5m","name":"longterm","retentionPeriod":"14d","storage":"10Gi","storageClassName":""}],"items":{"type":"object","required":["deduplicationInterval","name","retentionPeriod","storage"],"properties":{"deduplicationInterval":{"description":"Deduplication interval for metrics.","type":"string"},"name":{"description":"Name of the storage instance.","type":"string"},"retentionPeriod":{"description":"Retention period for metrics.","type":"string"},"storage":{"description":"Persistent volume size.","type":"string","default":"10Gi"},"storageClassName":{"description":"StorageClass used for the data.","type":"string"},"vminsert":{"description":"Configuration for vminsert.","type":"object","properties":{"maxAllowed":{"description":"Maximum allowed resources.","type":"object","properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"minAllowed":{"description":"Minimum guaranteed resources.","type":"object","properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}},"vmselect":{"description":"Configuration for vmselect.","type":"object","properties":{"maxAllowed":{"description":"Maximum allowed resources.","type":"object","properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"minAllowed":{"description":"Minimum guaranteed resources.","type":"object","properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}},"vmstorage":{"description":"Configuration for vmstorage.","type":"object","properties":{"maxAllowed":{"description":"Maximum allowed resources.","type":"object","properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"minAllowed":{"description":"Minimum guaranteed resources.","type":"object","properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}}}}},"logsStorages":{"description":"Configuration of logs storage instances.","type":"array","default":[{"name":"generic","retentionPeriod":"1","storage":"10Gi","storageClassName":"replicated"}],"items":{"type":"object","required":["name","retentionPeriod","storage","storageClassName"],"properties":{"name":{"description":"Name of the storage instance.","type":"string"},"retentionPeriod":{"description":"Retention period for logs.","type":"string","default":"1"},"storage":{"description":"Persistent volume size.","type":"string","default":"10Gi"},"storageClassName":{"description":"StorageClass used to store the data.","type":"string","default":"replicated"}}}},"alerta":{"description":"Configuration for the Alerta service.","type":"object","default":{},"properties":{"alerts":{"description":"Alert routing configuration.","type":"object","default":{},"properties":{"slack":{"description":"Configuration for Slack alerts.","type":"object","default":{},"required":["url"],"properties":{"disabledSeverity":{"description":"List of severities without alerts (e.g. [\"informational\",\"warning\"]).","type":"array","default":[],"items":{"type":"string"}},"url":{"description":"Configuration uri for Slack alerts.","type":"string","default":""}}},"telegram":{"description":"Configuration for Telegram alerts.","type":"object","default":{},"required":["chatID","token"],"properties":{"chatID":{"description":"Telegram chat ID(s), separated by commas.","type":"string","default":""},"disabledSeverity":{"description":"List of severities without alerts (e.g. [\"informational\",\"warning\"]).","type":"array","default":[],"items":{"type":"string"}},"token":{"description":"Telegram bot token.","type":"string","default":""}}}}},"resources":{"description":"Resource configuration.","type":"object","default":{},"properties":{"limits":{"description":"Resource limits.","type":"object","default":{},"properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"requests":{"description":"Resource requests.","type":"object","default":{},"properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}},"storage":{"description":"Persistent volume size for the database.","type":"string","default":"10Gi"},"storageClassName":{"description":"StorageClass used for the database.","type":"string","default":""}}},"grafana":{"description":"Configuration for Grafana.","type":"object","default":{},"properties":{"db":{"description":"Database configuration.","type":"object","default":{},"properties":{"size":{"description":"Persistent volume size for the database.","type":"string","default":"10Gi"}}},"resources":{"description":"Resource configuration.","type":"object","default":{},"properties":{"limits":{"description":"Resource limits.","type":"object","default":{},"properties":{"cpu":{"description":"CPU limit.","default":1,"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory limit.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"requests":{"description":"Resource requests.","type":"object","default":{},"properties":{"cpu":{"description":"CPU request.","default":"100m","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory request.","default":"256Mi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}}}}},"vmagent":{"description":"Configuration for VictoriaMetrics Agent.","type":"object","default":{},"properties":{"externalLabels":{"description":"External labels applied to all metrics.","type":"object","default":{"cluster":"cozystack"}},"remoteWrite":{"description":"Remote write configuration.","type":"object","default":{"urls":["http://vminsert-shortterm:8480/insert/0/prometheus","http://vminsert-longterm:8480/insert/0/prometheus"]}}}}}} + release: + prefix: "" + labels: + sharding.fluxcd.io/key: tenants + internal.cozystack.io/tenantmodule: "true" + chartRef: + kind: ExternalArtifact + name: cozystack-monitoring-application-default-monitoring + namespace: cozy-system + dashboard: + category: Administration + singular: Monitoring + plural: Monitoring + name: monitoring + description: Monitoring and observability stack + module: true + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODdfMzI2OCkiLz4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzY4N18zMjY4KSI+CjxwYXRoIGQ9Ik04OS41MDM5IDExMS43MDdINTQuNDk3QzU0LjE3MjcgMTExLjcwNyA1NC4wMTA4IDExMS4yMjEgNTQuMzM0OSAxMTEuMDU5TDU3LjI1MjIgMTA4Ljk1MkM2MC4zMzE0IDEwNi42ODMgNjEuOTUyMiAxMDIuNjMxIDYwLjk3OTcgOTguNzQxMkg4My4wMjFDODIuMDQ4NSAxMDIuNjMxIDgzLjY2OTMgMTA2LjY4MyA4Ni43NDg1IDEwOC45NTJMODkuNjY1OCAxMTEuMDU5Qzg5Ljk5IDExMS4yMjEgODkuODI3OSAxMTEuNzA3IDg5LjUwMzkgMTExLjcwN1oiIGZpbGw9IiNCMEI2QkIiLz4KPHBhdGggZD0iTTExMy4zMjggOTguNzQxSDMwLjY3MjVDMjcuNTkzMSA5OC43NDEgMjUgOTYuMTQ4IDI1IDkzLjA2ODdWMzMuMTAzMkMyNSAzMC4wMjM5IDI3LjU5MzEgMjcuNDMwNyAzMC42NzI1IDI3LjQzMDdIMTEzLjMyOEMxMTYuNDA3IDI3LjQzMDcgMTE5IDMwLjAyMzcgMTE5IDMzLjEwMzJWOTMuMDY4N0MxMTkgOTYuMTQ4IDExNi40MDcgOTguNzQxIDExMy4zMjggOTguNzQxWiIgZmlsbD0iI0U4RURFRSIvPgo8cGF0aCBkPSJNMTE5IDg0LjE1NDlIMjVWMzMuMTAzMkMyNSAzMC4wMjM5IDI3LjU5MzEgMjcuNDMwNyAzMC42NzI1IDI3LjQzMDdIMTEzLjMyOEMxMTYuNDA3IDI3LjQzMDcgMTE5IDMwLjAyMzcgMTE5IDMzLjEwMzJMMTE5IDg0LjE1NDlaIiBmaWxsPSIjMzg0NTRGIi8+CjxwYXRoIGQ9Ik05MC42Mzc0IDExNi41NjlINTMuMzYxNkM1Mi4wNjUxIDExNi41NjkgNTAuOTMwNyAxMTUuNDM1IDUwLjkzMDcgMTE0LjEzOEM1MC45MzA3IDExMi44NDEgNTIuMDY1MSAxMTEuNzA3IDUzLjM2MTYgMTExLjcwN0g5MC42Mzc0QzkxLjkzMzkgMTExLjcwNyA5My4wNjg0IDExMi44NDEgOTMuMDY4NCAxMTQuMTM4QzkzLjA2ODQgMTE1LjQzNSA5MS45MzM5IDExNi41NjkgOTAuNjM3NCAxMTYuNTY5WiIgZmlsbD0iI0U4RURFRSIvPgo8cGF0aCBkPSJNNTQuMTcyMiAzOC43NzU3SDMzLjEwMzJDMzIuMTMwNyAzOC43NzU3IDMxLjQ4MjQgMzguMTI3NCAzMS40ODI0IDM3LjE1NDlDMzEuNDgyNCAzNi4xODI0IDMyLjEzMDcgMzUuNTM0MiAzMy4xMDMyIDM1LjUzNDJINTQuMTcyMkM1NS4xNDQ3IDM1LjUzNDIgNTUuNzkzIDM2LjE4MjQgNTUuNzkzIDM3LjE1NDlDNTUuNzkyOCAzOC4xMjc0IDU1LjE0NDUgMzguNzc1NyA1NC4xNzIyIDM4Ljc3NTdaIiBmaWxsPSIjREQzNDJFIi8+CjxwYXRoIGQ9Ik02My44OTYzIDQ1LjI1OTFINDEuMjA2N0M0MC4yMzQyIDQ1LjI1OTEgMzkuNTg1OSA0NC42MTA4IDM5LjU4NTkgNDMuNjM4M0MzOS41ODU5IDQyLjY2NTggNDAuMjM0MiA0Mi4wMTc2IDQxLjIwNjcgNDIuMDE3Nkg2My44OTYzQzY0Ljg2ODggNDIuMDE3NiA2NS41MTcxIDQyLjY2NTggNjUuNTE3MSA0My42MzgzQzY1LjUxNzEgNDQuNjEwOCA2NC44Njg4IDQ1LjI1OTEgNjMuODk2MyA0NS4yNTkxWiIgZmlsbD0iIzczODNCRiIvPgo8cGF0aCBkPSJNMzQuNzI0IDQ1LjI1OTFIMzMuMTAzMkMzMi4xMzA3IDQ1LjI1OTEgMzEuNDgyNCA0NC42MTA4IDMxLjQ4MjQgNDMuNjM4M0MzMS40ODI0IDQyLjY2NTggMzIuMTMwNyA0Mi4wMTc2IDMzLjEwMzIgNDIuMDE3NkgzNC43MjRDMzUuNjk2NCA0Mi4wMTc2IDM2LjM0NDcgNDIuNjY1OCAzNi4zNDQ3IDQzLjYzODNDMzYuMzQ0NyA0NC42MTA4IDM1LjY5NjMgNDUuMjU5MSAzNC43MjQgNDUuMjU5MVoiIGZpbGw9IiM0MkIwNUMiLz4KPHBhdGggZD0iTTYzLjg5NjMgMzguNzc1N0g2MC42NTQ5QzU5LjY4MjQgMzguNzc1NyA1OS4wMzQyIDM4LjEyNzQgNTkuMDM0MiAzNy4xNTQ5QzU5LjAzNDIgMzYuMTgyNCA1OS42ODI0IDM1LjUzNDIgNjAuNjU0OSAzNS41MzQySDYzLjg5NjNDNjQuODY4OCAzNS41MzQyIDY1LjUxNzEgMzYuMTgyNCA2NS41MTcxIDM3LjE1NDlDNjUuNTE3MSAzOC4xMjc0IDY0Ljg2ODggMzguNzc1NyA2My44OTYzIDM4Ljc3NTdaIiBmaWxsPSIjRUNCQTE2Ii8+CjxwYXRoIGQ9Ik00Ny42ODkzIDUxLjc0MTNIMzMuMTAzMkMzMi4xMzA3IDUxLjc0MTMgMzEuNDgyNCA1MS4wOTMxIDMxLjQ4MjQgNTAuMTIwNkMzMS40ODI0IDQ5LjE0ODEgMzIuMTMwNyA0OC41IDMzLjEwMzIgNDguNUg0Ny42ODkzQzQ4LjY2MTggNDguNSA0OS4zMTAxIDQ5LjE0ODMgNDkuMzEwMSA1MC4xMjA4QzQ5LjMxMDEgNTEuMDkzMyA0OC42NjE4IDUxLjc0MTMgNDcuNjg5MyA1MS43NDEzWiIgZmlsbD0iI0REMzQyRSIvPgo8cGF0aCBkPSJNNjMuODk2OCA1MS43NDEzSDU0LjE3MjVDNTMuMiA1MS43NDEzIDUyLjU1MTggNTEuMDkzMSA1Mi41NTE4IDUwLjEyMDZDNTIuNTUxOCA0OS4xNDgxIDUzLjIwMDIgNDguNSA1NC4xNzI3IDQ4LjVINjMuODk2OUM2NC44Njk0IDQ4LjUgNjUuNTE3NyA0OS4xNDgzIDY1LjUxNzcgNTAuMTIwOEM2NS41MTc3IDUxLjA5MzMgNjQuODY5MiA1MS43NDEzIDYzLjg5NjggNTEuNzQxM1oiIGZpbGw9IiNFQ0JBMTYiLz4KPHBhdGggZD0iTTU0LjE3MjIgNTguMjI0SDMzLjEwMzJDMzIuMTMwNyA1OC4yMjQgMzEuNDgyNCA1Ny41NzU3IDMxLjQ4MjQgNTYuNjAzMkMzMS40ODI0IDU1LjYzMDcgMzIuMTMwNyA1NC45ODI0IDMzLjEwMzIgNTQuOTgyNEg1NC4xNzIyQzU1LjE0NDcgNTQuOTgyNCA1NS43OTMgNTUuNjMwNyA1NS43OTMgNTYuNjAzMkM1NS43OTMgNTcuNTc1NyA1NS4xNDQ1IDU4LjIyNCA1NC4xNzIyIDU4LjIyNFoiIGZpbGw9IiM0MkIwNUMiLz4KPHBhdGggZD0iTTYzLjg5NjMgNjQuNzA3NEg0MS4yMDY3QzQwLjIzNDIgNjQuNzA3NCAzOS41ODU5IDY0LjA1OTEgMzkuNTg1OSA2My4wODY2QzM5LjU4NTkgNjIuMTE0MSA0MC4yMzQyIDYxLjQ2NTggNDEuMjA2NyA2MS40NjU4SDYzLjg5NjNDNjQuODY4OCA2MS40NjU4IDY1LjUxNzEgNjIuMTE0MSA2NS41MTcxIDYzLjA4NjZDNjUuNTE3MSA2NC4wNTkxIDY0Ljg2ODggNjQuNzA3NCA2My44OTYzIDY0LjcwNzRaIiBmaWxsPSIjRUNCQTE2Ii8+CjxwYXRoIGQ9Ik0zNC43MjQgNjQuNzA3NEgzMy4xMDMyQzMyLjEzMDcgNjQuNzA3NCAzMS40ODI0IDY0LjA1OTEgMzEuNDgyNCA2My4wODY2QzMxLjQ4MjQgNjIuMTE0MSAzMi4xMzA3IDYxLjQ2NTggMzMuMTAzMiA2MS40NjU4SDM0LjcyNEMzNS42OTY0IDYxLjQ2NTggMzYuMzQ0NyA2Mi4xMTQxIDM2LjM0NDcgNjMuMDg2NkMzNi4zNDQ3IDY0LjA1OTEgMzUuNjk2MyA2NC43MDc0IDM0LjcyNCA2NC43MDc0WiIgZmlsbD0iI0REMzQyRSIvPgo8cGF0aCBkPSJNNDcuNjg5MyA3MS4xODk4SDMzLjEwMzJDMzIuMTMwNyA3MS4xODk4IDMxLjQ4MjQgNzAuNTQxNSAzMS40ODI0IDY5LjU2OUMzMS40ODI0IDY4LjU5NjUgMzIuMTMwNyA2Ny45NDgyIDMzLjEwMzIgNjcuOTQ4Mkg0Ny42ODkzQzQ4LjY2MTggNjcuOTQ4MiA0OS4zMTAxIDY4LjU5NjUgNDkuMzEwMSA2OS41NjlDNDkuMzEwMSA3MC41NDE1IDQ4LjY2MTggNzEuMTg5OCA0Ny42ODkzIDcxLjE4OThaIiBmaWxsPSIjNDJCMDVDIi8+CjxwYXRoIGQ9Ik02My44OTY4IDcxLjE4OThINTQuMTcyNUM1My4yIDcxLjE4OTggNTIuNTUxOCA3MC41NDE1IDUyLjU1MTggNjkuNTY5QzUyLjU1MTggNjguNTk2NSA1My4yIDY3Ljk0ODIgNTQuMTcyNSA2Ny45NDgySDYzLjg5NjhDNjQuODY5MiA2Ny45NDgyIDY1LjUxNzUgNjguNTk2NSA2NS41MTc1IDY5LjU2OUM2NS41MTc1IDcwLjU0MTUgNjQuODY5MiA3MS4xODk4IDYzLjg5NjggNzEuMTg5OFoiIGZpbGw9IiM3MzgzQkYiLz4KPHBhdGggZD0iTTU0LjE3MjIgNzcuNjcyMkgzMy4xMDMyQzMyLjEzMDcgNzcuNjcyMiAzMS40ODI0IDc3LjAyMzkgMzEuNDgyNCA3Ni4wNTE0QzMxLjQ4MjQgNzUuMDc4OSAzMi4xMzA3IDc0LjQzMDcgMzMuMTAzMiA3NC40MzA3SDU0LjE3MjJDNTUuMTQ0NyA3NC40MzA3IDU1Ljc5MyA3NS4wNzg5IDU1Ljc5MyA3Ni4wNTE0QzU1Ljc5MjggNzcuMDIzOSA1NS4xNDQ1IDc3LjY3MjIgNTQuMTcyMiA3Ny42NzIyWiIgZmlsbD0iI0VDQkExNiIvPgo8cGF0aCBkPSJNNjMuODk2MyA3Ny42NzIySDYwLjY1NDlDNTkuNjgyNCA3Ny42NzIyIDU5LjAzNDIgNzcuMDIzOSA1OS4wMzQyIDc2LjA1MTRDNTkuMDM0MiA3NS4wNzg5IDU5LjY4MjQgNzQuNDMwNyA2MC42NTQ5IDc0LjQzMDdINjMuODk2M0M2NC44Njg4IDc0LjQzMDcgNjUuNTE3MSA3NS4wNzg5IDY1LjUxNzEgNzYuMDUxNEM2NS41MTcxIDc3LjAyMzkgNjQuODY4OCA3Ny42NzIyIDYzLjg5NjMgNzcuNjcyMloiIGZpbGw9IiM0MkIwNUMiLz4KPHBhdGggZD0iTTEwMS4xNzIgNzcuNjcyMkg4MC4xMDMyQzc5LjEzMDcgNzcuNjcyMiA3OC40ODI0IDc3LjAyMzkgNzguNDgyNCA3Ni4wNTE0Qzc4LjQ4MjQgNzUuMDc4OSA3OS4xMzA3IDc0LjQzMDcgODAuMTAzMiA3NC40MzA3SDEwMS4xNzJDMTAyLjE0NSA3NC40MzA3IDEwMi43OTMgNzUuMDc4OSAxMDIuNzkzIDc2LjA1MTRDMTAyLjc5MyA3Ny4wMjM5IDEwMi4xNDUgNzcuNjcyMiAxMDEuMTcyIDc3LjY3MjJaIiBmaWxsPSIjREQzNDJFIi8+CjxwYXRoIGQ9Ik0xMTAuODk2IDc3LjY3MjJIMTA3LjY1NUMxMDYuNjgyIDc3LjY3MjIgMTA2LjAzNCA3Ny4wMjM5IDEwNi4wMzQgNzYuMDUxNEMxMDYuMDM0IDc1LjA3ODkgMTA2LjY4MiA3NC40MzA3IDEwNy42NTUgNzQuNDMwN0gxMTAuODk2QzExMS44NjkgNzQuNDMwNyAxMTIuNTE3IDc1LjA3ODkgMTEyLjUxNyA3Ni4wNTE0QzExMi41MTcgNzcuMDIzOSAxMTEuODY5IDc3LjY3MjIgMTEwLjg5NiA3Ny42NzIyWiIgZmlsbD0iIzQyQjA1QyIvPgo8cGF0aCBkPSJNNjMuODk2MyA1OC4yMjRINjAuNjU0OUM1OS42ODI0IDU4LjIyNCA1OS4wMzQyIDU3LjU3NTcgNTkuMDM0MiA1Ni42MDMyQzU5LjAzNDIgNTUuNjMwNyA1OS42ODI0IDU0Ljk4MjQgNjAuNjU0OSA1NC45ODI0SDYzLjg5NjNDNjQuODY4OCA1NC45ODI0IDY1LjUxNzEgNTUuNjMwNyA2NS41MTcxIDU2LjYwMzJDNjUuNTE3MSA1Ny41NzU3IDY0Ljg2ODggNTguMjI0IDYzLjg5NjMgNTguMjI0WiIgZmlsbD0iIzczODNCRiIvPgo8cGF0aCBkPSJNMTEyLjUxNyA1MS43NDExQzExMi41MTcgNjAuNjU0OSAxMDUuMjI0IDY3Ljk0OCA5Ni4zMTA0IDY3Ljk0OEM4Ny4zOTY2IDY3Ljk0OCA4MC4xMDM1IDYwLjY1NDkgODAuMTAzNSA1MS43NDExQzgwLjEwMzUgNDIuODI3MyA4Ny4zOTY2IDM1LjUzNDIgOTYuMzEwNCAzNS41MzQyQzEwNS4yMjQgMzUuNTM0MiAxMTIuNTE3IDQyLjgyNzMgMTEyLjUxNyA1MS43NDExWiIgZmlsbD0iI0VDQkExNiIvPgo8cGF0aCBkPSJNODAuMTAzNSA1MS43NDExQzgwLjEwMzUgNTIuMjI3MyA4MC4xMDM1IDUyLjg3NTUgODAuMTAzNSA1My4zNjE5SDk2LjMxMDRWMzUuNTM0MkM4Ny4zOTY2IDM1LjUzNDIgODAuMTAzNSA0Mi44MjczIDgwLjEwMzUgNTEuNzQxMVoiIGZpbGw9IiM0MkIwNUMiLz4KPC9nPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4N18zMjY4IiB4MT0iMS4yMzIzOWUtMDYiIHkxPSItOS41MDAwMSIgeDI9IjE2OCIgeTI9IjE2MiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjOEZEREZGIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzAwNzVGRiIvPgo8L2xpbmVhckdyYWRpZW50Pgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzY4N18zMjY4Ij4KPHJlY3Qgd2lkdGg9Ijk0IiBoZWlnaHQ9Ijk0IiBmaWxsPSJ3aGl0ZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjUgMjUpIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg== + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "host"], ["spec", "metricsStorages"], ["spec", "logsStorages"], ["spec", "alerta"], ["spec", "alerta", "storage"], ["spec", "alerta", "storageClassName"], ["spec", "alerta", "resources"], ["spec", "alerta", "resources", "limits"], ["spec", "alerta", "resources", "limits", "cpu"], ["spec", "alerta", "resources", "limits", "memory"], ["spec", "alerta", "resources", "requests"], ["spec", "alerta", "resources", "requests", "cpu"], ["spec", "alerta", "resources", "requests", "memory"], ["spec", "alerta", "alerts"], ["spec", "alerta", "alerts", "telegram"], ["spec", "alerta", "alerts", "telegram", "token"], ["spec", "alerta", "alerts", "telegram", "chatID"], ["spec", "alerta", "alerts", "telegram", "disabledSeverity"], ["spec", "alerta", "alerts", "slack"], ["spec", "alerta", "alerts", "slack", "url"], ["spec", "alerta", "alerts", "slack", "disabledSeverity"], ["spec", "grafana"], ["spec", "grafana", "db"], ["spec", "grafana", "db", "size"], ["spec", "grafana", "resources"], ["spec", "grafana", "resources", "limits"], ["spec", "grafana", "resources", "limits", "cpu"], ["spec", "grafana", "resources", "limits", "memory"], ["spec", "grafana", "resources", "requests"], ["spec", "grafana", "resources", "requests", "cpu"], ["spec", "grafana", "resources", "requests", "memory"], ["spec", "vmagent"], ["spec", "vmagent", "externalLabels"], ["spec", "vmagent", "externalLabels", "cluster"], ["spec", "vmagent", "remoteWrite"], ["spec", "vmagent", "remoteWrite", "urls"]] + secrets: + exclude: [] + include: + - resourceNames: + - grafana-admin-password + services: + exclude: [] + include: + - resourceNames: + - grafana-service + - alerta + ingresses: + exclude: [] + include: + - resourceNames: + - grafana-ingress + - alerta diff --git a/packages/system/monitoring-rd/templates/cozyrd.yaml b/packages/system/monitoring-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/monitoring-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/monitoring-rd/values.yaml b/packages/system/monitoring-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/monitoring-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/apps/mysql/.helmignore b/packages/system/monitoring/.helmignore similarity index 100% rename from packages/apps/mysql/.helmignore rename to packages/system/monitoring/.helmignore diff --git a/packages/system/monitoring/Chart.yaml b/packages/system/monitoring/Chart.yaml new file mode 100644 index 00000000..a97b02de --- /dev/null +++ b/packages/system/monitoring/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: monitoring +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/monitoring/Makefile b/packages/system/monitoring/Makefile new file mode 100644 index 00000000..e35543cd --- /dev/null +++ b/packages/system/monitoring/Makefile @@ -0,0 +1,18 @@ +GRAFANA_TAG = $(shell awk '$$1 == "version:" {print $$2}' Chart.yaml) + +NAME=monitoring +NAMESPACE=cozy-$(NAME) + +include ../../../hack/common-envs.mk +include ../../../hack/package.mk + +image: + docker buildx build images/grafana \ + --tag $(REGISTRY)/grafana:$(call settag,$(GRAFANA_TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/grafana:latest \ + --cache-to type=inline \ + --metadata-file images/grafana.json \ + $(BUILDX_ARGS) + echo "$(REGISTRY)/grafana:$(call settag,$(GRAFANA_TAG))@$$(yq e '."containerimage.digest"' images/grafana.json -o json -r)" \ + > images/grafana.tag + rm -f images/grafana.json diff --git a/packages/system/monitoring/charts/cozy-lib b/packages/system/monitoring/charts/cozy-lib new file mode 120000 index 00000000..e1813509 --- /dev/null +++ b/packages/system/monitoring/charts/cozy-lib @@ -0,0 +1 @@ +../../../library/cozy-lib \ No newline at end of file diff --git a/packages/extra/monitoring/dashboards.list b/packages/system/monitoring/dashboards-infra.list similarity index 71% rename from packages/extra/monitoring/dashboards.list rename to packages/system/monitoring/dashboards-infra.list index dec05cf5..4c7e494d 100644 --- a/packages/extra/monitoring/dashboards.list +++ b/packages/system/monitoring/dashboards-infra.list @@ -1,23 +1,3 @@ -dotdc/k8s-views-global -dotdc/k8s-views-namespaces -dotdc/k8s-system-coredns -dotdc/k8s-views-pods -cache/nginx-vts-stats -victoria-metrics/vmalert -victoria-metrics/vmagent -victoria-metrics/victoriametrics-cluster -victoria-metrics/backupmanager -victoria-metrics/victoriametrics -victoria-metrics/operator -ingress/controller-detail -ingress/controllers -ingress/namespaces -ingress/vhosts -ingress/vhost-detail -ingress/namespace-detail -db/cloudnativepg -db/maria-db -db/redis main/controller main/namespaces main/capacity-planning @@ -31,10 +11,29 @@ control-plane/control-plane-status control-plane/deprecated-resources control-plane/dns-coredns control-plane/kube-etcd -kubevirt/kubevirt-control-plane +victoria-metrics/vmalert +victoria-metrics/vmagent +victoria-metrics/victoriametrics-cluster +victoria-metrics/backupmanager +victoria-metrics/victoriametrics +victoria-metrics/operator +dotdc/k8s-views-global +dotdc/k8s-views-namespaces +dotdc/k8s-system-coredns +dotdc/k8s-views-pods flux/flux-control-plane flux/flux-stats -kafka/strimzi-kafka +kubevirt/kubevirt-control-plane goldpinger/goldpinger -clickhouse/altinity-clickhouse-operator-dashboard -storage/linstor \ No newline at end of file +cache/nginx-vts-stats +storage/linstor +seaweedfs/seaweedfs +hubble/overview +hubble/dns-namespace +hubble/l7-http-metrics +hubble/network-overview +gpu/gpu-performance +gpu/gpu-efficiency +gpu/gpu-quotas +gpu/gpu-fleet +gpu/gpu-tenants diff --git a/packages/system/monitoring/dashboards.list b/packages/system/monitoring/dashboards.list new file mode 100644 index 00000000..aee8c2dc --- /dev/null +++ b/packages/system/monitoring/dashboards.list @@ -0,0 +1,15 @@ +ingress/controller-detail +ingress/controllers +ingress/namespaces +ingress/vhosts +ingress/vhost-detail +ingress/namespace-detail +db/cloudnativepg +db/maria-db +db/redis +kafka/strimzi-kafka +clickhouse/altinity-clickhouse-operator-dashboard +nats/nats-jetstream +nats/nats-server +mongodb/mongodb-overview +mongodb/mongodb-inmemory diff --git a/packages/system/monitoring/images/grafana.tag b/packages/system/monitoring/images/grafana.tag new file mode 100644 index 00000000..06eb755a --- /dev/null +++ b/packages/system/monitoring/images/grafana.tag @@ -0,0 +1 @@ +ghcr.io/cozystack/cozystack/grafana:0.0.0@sha256:58ee26efdccf81ee79b4d5478df347b91398280600971eaf4b9626b0ca72ed35 diff --git a/packages/extra/monitoring/images/grafana/Dockerfile b/packages/system/monitoring/images/grafana/Dockerfile similarity index 84% rename from packages/extra/monitoring/images/grafana/Dockerfile rename to packages/system/monitoring/images/grafana/Dockerfile index f8597a5c..cc65c9d3 100644 --- a/packages/extra/monitoring/images/grafana/Dockerfile +++ b/packages/system/monitoring/images/grafana/Dockerfile @@ -13,3 +13,4 @@ RUN curl -L https://github.com/VictoriaMetrics/victorialogs-datasource/releases/ RUN grafana-cli --pluginsDir /var/lib/grafana-plugins plugins install natel-discrete-panel RUN grafana-cli --pluginsDir /var/lib/grafana-plugins plugins install grafana-worldmap-panel +RUN grafana-cli --pluginsDir /var/lib/grafana-plugins plugins install marcusolsson-dynamictext-panel diff --git a/packages/extra/monitoring/patches/1.diff b/packages/system/monitoring/patches/1.diff similarity index 100% rename from packages/extra/monitoring/patches/1.diff rename to packages/system/monitoring/patches/1.diff diff --git a/packages/extra/monitoring/templates/alerta/alerta-db.yaml b/packages/system/monitoring/templates/alerta/alerta-db.yaml similarity index 55% rename from packages/extra/monitoring/templates/alerta/alerta-db.yaml rename to packages/system/monitoring/templates/alerta/alerta-db.yaml index a2cca187..af9dc72c 100644 --- a/packages/extra/monitoring/templates/alerta/alerta-db.yaml +++ b/packages/system/monitoring/templates/alerta/alerta-db.yaml @@ -5,9 +5,11 @@ metadata: name: alerta-db spec: instances: 2 - {{- $configMap := lookup "v1" "ConfigMap" "cozy-system" "cozystack-scheduling" }} - {{- if $configMap }} - {{- $rawConstraints := get $configMap.data "globalAppTopologySpreadConstraints" }} + {{- $existingCluster := lookup "postgresql.cnpg.io/v1" "Cluster" .Release.Namespace "alerta-db" }} + {{- $image := dig "spec" "imageName" "ghcr.io/cloudnative-pg/postgresql:17.7-standard-trixie" $existingCluster }} + imageName: {{ if regexMatch ":17\\." $image }}ghcr.io/cloudnative-pg/postgresql:17.7-standard-trixie{{ else if regexMatch ":[0-9]+\\.[0-9]+$" $image }}{{ printf "%s-standard-trixie" $image }}{{ else }}{{ $image }}{{ end }} + {{- if .Values._cluster.scheduling }} + {{- $rawConstraints := get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }} {{- if $rawConstraints }} {{- $rawConstraints | fromYaml | toYaml | nindent 2 }} labelSelector: @@ -34,17 +36,3 @@ spec: inheritedMetadata: labels: policy.cozystack.io/allow-to-apiserver: "true" ---- -apiVersion: cozystack.io/v1alpha1 -kind: WorkloadMonitor -metadata: - name: alerta-db -spec: - replicas: 2 - minReplicas: 1 - kind: monitoring - type: postgres - selector: - cnpg.io/cluster: alerta-db - cnpg.io/podRole: instance - version: {{ $.Chart.Version }} diff --git a/packages/extra/monitoring/templates/alerta/alerta.yaml b/packages/system/monitoring/templates/alerta/alerta.yaml similarity index 71% rename from packages/extra/monitoring/templates/alerta/alerta.yaml rename to packages/system/monitoring/templates/alerta/alerta.yaml index 13c37788..d30e698d 100644 --- a/packages/extra/monitoring/templates/alerta/alerta.yaml +++ b/packages/system/monitoring/templates/alerta/alerta.yaml @@ -1,9 +1,7 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $solver := (index .Values._cluster "solver") | default "http01" }} +{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }} +{{- $ingress := .Values._namespace.ingress }} +{{- $host := .Values._namespace.host }} {{- $apiKey := randAlphaNum 32 }} {{- $existingSecret := lookup "v1" "Secret" .Release.Namespace "alerta" }} @@ -109,17 +107,47 @@ spec: - name: AUTH_REQUIRED value: "True" + {{- $plugins := list }} {{- if and .Values.alerta.alerts.telegram.chatID .Values.alerta.alerts.telegram.token }} + {{- $plugins = append $plugins "telegram" }} + {{- end }} + {{- if .Values.alerta.alerts.slack.url }} + {{- $plugins = append $plugins "slack" }} + {{- end }} + + {{- if gt (len $plugins) 0 }} - name: "PLUGINS" - value: "telegram" + value: "{{ default "" (join "," $plugins) }}" + {{- end }} + + {{- if and .Values.alerta.alerts.telegram.chatID .Values.alerta.alerts.telegram.token }} - name: TELEGRAM_CHAT_ID value: "{{ .Values.alerta.alerts.telegram.chatID }}" - name: TELEGRAM_TOKEN value: "{{ .Values.alerta.alerts.telegram.token }}" - name: TELEGRAM_WEBHOOK_URL value: "https://{{ printf "alerta.%s" (.Values.host | default $host) }}/api/webhooks/telegram?api-key={{ $apiKey }}" + {{- if .Values.alerta.alerts.telegram.disabledSeverity }} - name: TELEGRAM_DISABLE_NOTIFICATION_SEVERITY - value: "{{ .Values.alerta.alerts.telegram.disabledSeverity }}" + value: {{ .Values.alerta.alerts.telegram.disabledSeverity | toJson | quote }} + {{- end }} + {{- end }} + + {{- if .Values.alerta.alerts.slack.url }} + - name: "SLACK_WEBHOOK_URL" + value: "{{ .Values.alerta.alerts.slack.url }}" + {{- if .Values.alerta.alerts.slack.disabledSeverity }} + - name: SLACK_SEVERITY_FILTER + value: {{ .Values.alerta.alerts.slack.disabledSeverity | toJson | quote }} + {{- end }} + {{- if .Values.alerta.alerts.slack.dashboardUrl }} + - name: DASHBOARD_URL + value: {{ .Values.alerta.alerts.slack.dashboardUrl | quote }} + {{- end }} + {{- if .Values.alerta.alerts.slack.summaryFmt }} + - name: SLACK_SUMMARY_FMT + value: {{ .Values.alerta.alerts.slack.summaryFmt | quote }} + {{- end }} {{- end }} ports: @@ -152,10 +180,10 @@ metadata: labels: app: alerta annotations: - {{- if ne $issuerType "cloudflare" }} - acme.cert-manager.io/http01-ingress-class: {{ $ingress }} + {{- if eq $solver "http01" }} + acme.cert-manager.io/http01-ingress-ingressclassname: {{ $ingress }} {{- end }} - cert-manager.io/cluster-issuer: letsencrypt-prod + cert-manager.io/cluster-issuer: {{ $clusterIssuer }} spec: ingressClassName: {{ $ingress }} tls: @@ -174,20 +202,6 @@ spec: port: name: http --- -apiVersion: cozystack.io/v1alpha1 -kind: WorkloadMonitor -metadata: - name: alerta -spec: - replicas: 1 - minReplicas: 1 - kind: monitoring - type: alerta - selector: - app: alerta - release: alerta - version: {{ $.Chart.Version }} ---- apiVersion: v1 kind: Secret metadata: @@ -230,22 +244,13 @@ kind: VMAlertmanager metadata: name: alertmanager spec: + managedMetadata: + labels: + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.kind: Monitoring + apps.cozystack.io/application.name: {{ $.Release.Name }} replicaCount: 3 configSecret: alertmanager podMetadata: labels: policy.cozystack.io/allow-to-apiserver: "true" ---- -apiVersion: cozystack.io/v1alpha1 -kind: WorkloadMonitor -metadata: - name: alertmanager -spec: - replicas: 3 - minReplicas: 2 - kind: monitoring - type: alertmanager - selector: - app.kubernetes.io/instance: alertmanager - app.kubernetes.io/name: vmalertmanager - version: {{ $.Chart.Version }} diff --git a/packages/system/monitoring/templates/dashboards.yaml b/packages/system/monitoring/templates/dashboards.yaml new file mode 100644 index 00000000..0427bfa0 --- /dev/null +++ b/packages/system/monitoring/templates/dashboards.yaml @@ -0,0 +1,34 @@ +{{- range (split "\n" (.Files.Get "dashboards.list")) }} +{{- $parts := split "/" . }} +{{- if eq (len $parts) 2 }} +--- +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + name: {{ $parts._0 }}-{{ $parts._1 }} +spec: + folder: {{ $parts._0 }} + instanceSelector: + matchLabels: + dashboards: grafana + url: http://grafana-dashboards.cozy-grafana-operator.svc/{{ . }}.json +{{- end }} +{{- end }} +{{- if or (eq .Release.Namespace "tenant-root") (eq .Release.Namespace "cozy-monitoring") }} +{{- range (split "\n" (.Files.Get "dashboards-infra.list")) }} +{{- $parts := split "/" . }} +{{- if eq (len $parts) 2 }} +--- +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + name: {{ $parts._0 }}-{{ $parts._1 }} +spec: + folder: {{ $parts._0 }} + instanceSelector: + matchLabels: + dashboards: grafana + url: http://grafana-dashboards.cozy-grafana-operator.svc/{{ . }}.json +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/monitoring/templates/grafana/db.yaml b/packages/system/monitoring/templates/grafana/db.yaml new file mode 100644 index 00000000..afc2d0d7 --- /dev/null +++ b/packages/system/monitoring/templates/grafana/db.yaml @@ -0,0 +1,32 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: grafana-db +spec: + instances: 2 + {{- $existingCluster := lookup "postgresql.cnpg.io/v1" "Cluster" .Release.Namespace "grafana-db" }} + {{- $image := dig "spec" "imageName" "ghcr.io/cloudnative-pg/postgresql:17.7-standard-trixie" $existingCluster }} + imageName: {{ if regexMatch ":17\\." $image }}ghcr.io/cloudnative-pg/postgresql:17.7-standard-trixie{{ else if regexMatch ":[0-9]+\\.[0-9]+$" $image }}{{ printf "%s-standard-trixie" $image }}{{ else }}{{ $image }}{{ end }} + storage: + size: {{ .Values.grafana.db.size }} + {{- if .Values._cluster.scheduling }} + {{- $rawConstraints := get .Values._cluster.scheduling "globalAppTopologySpreadConstraints" }} + {{- if $rawConstraints }} + {{- $rawConstraints | fromYaml | toYaml | nindent 2 }} + labelSelector: + matchLabels: + cnpg.io/cluster: grafana-db + {{- end }} + {{- end }} + monitoring: + enablePodMonitor: true + resources: + limits: + cpu: "1" + memory: 2048Mi + requests: + cpu: 100m + memory: 512Mi + inheritedMetadata: + labels: + policy.cozystack.io/allow-to-apiserver: "true" diff --git a/packages/extra/monitoring/templates/grafana/grafana.yaml b/packages/system/monitoring/templates/grafana/grafana.yaml similarity index 78% rename from packages/extra/monitoring/templates/grafana/grafana.yaml rename to packages/system/monitoring/templates/grafana/grafana.yaml index 2397fd10..d65a7dc4 100644 --- a/packages/extra/monitoring/templates/grafana/grafana.yaml +++ b/packages/system/monitoring/templates/grafana/grafana.yaml @@ -1,9 +1,7 @@ -{{- $cozyConfig := lookup "v1" "ConfigMap" "cozy-system" "cozystack" }} -{{- $issuerType := (index $cozyConfig.data "clusterissuer") | default "http01" }} - -{{- $myNS := lookup "v1" "Namespace" "" .Release.Namespace }} -{{- $ingress := index $myNS.metadata.annotations "namespace.cozystack.io/ingress" }} -{{- $host := index $myNS.metadata.annotations "namespace.cozystack.io/host" }} +{{- $solver := (index .Values._cluster "solver") | default "http01" }} +{{- $clusterIssuer := (index .Values._cluster "issuer-name") | default "letsencrypt-prod" }} +{{- $ingress := .Values._namespace.ingress }} +{{- $host := .Values._namespace.host }} --- apiVersion: grafana.integreatly.org/v1beta1 kind: Grafana @@ -75,10 +73,10 @@ spec: ingress: metadata: annotations: - {{- if ne $issuerType "cloudflare" }} - acme.cert-manager.io/http01-ingress-class: "{{ $ingress }}" + {{- if eq $solver "http01" }} + acme.cert-manager.io/http01-ingress-ingressclassname: "{{ $ingress }}" {{- end }} - cert-manager.io/cluster-issuer: letsencrypt-prod + cert-manager.io/cluster-issuer: {{ $clusterIssuer }} spec: ingressClassName: "{{ $ingress }}" rules: @@ -96,16 +94,3 @@ spec: - hosts: - "{{ printf "grafana.%s" (.Values.host | default $host) }}" secretName: grafana-ingress-tls ---- -apiVersion: cozystack.io/v1alpha1 -kind: WorkloadMonitor -metadata: - name: grafana -spec: - replicas: 2 - minReplicas: 1 - kind: monitoring - type: grafana - selector: - app: grafana - version: {{ $.Chart.Version }} diff --git a/packages/extra/monitoring/templates/grafana/secret.yaml b/packages/system/monitoring/templates/grafana/secret.yaml similarity index 100% rename from packages/extra/monitoring/templates/grafana/secret.yaml rename to packages/system/monitoring/templates/grafana/secret.yaml diff --git a/packages/extra/monitoring/templates/vlogs/grafana-datasource.yaml b/packages/system/monitoring/templates/vlogs/grafana-datasource.yaml similarity index 81% rename from packages/extra/monitoring/templates/vlogs/grafana-datasource.yaml rename to packages/system/monitoring/templates/vlogs/grafana-datasource.yaml index 0fa41288..72755c6f 100644 --- a/packages/extra/monitoring/templates/vlogs/grafana-datasource.yaml +++ b/packages/system/monitoring/templates/vlogs/grafana-datasource.yaml @@ -8,7 +8,7 @@ spec: access: proxy type: victoriametrics-logs-datasource name: vlogs-{{ .name }} - url: http://vlogs-{{ .name }}.{{ $.Release.Namespace }}.svc:9428 + url: http://vlselect-{{ .name }}.{{ $.Release.Namespace }}.svc:9471 instanceSelector: matchLabels: dashboards: grafana diff --git a/packages/system/monitoring/templates/vlogs/vlogs.yaml b/packages/system/monitoring/templates/vlogs/vlogs.yaml new file mode 100644 index 00000000..106d3aaf --- /dev/null +++ b/packages/system/monitoring/templates/vlogs/vlogs.yaml @@ -0,0 +1,32 @@ +{{- range .Values.logsStorages }} +--- +apiVersion: operator.victoriametrics.com/v1 +kind: VLCluster +metadata: + name: {{ .name }} +spec: + managedMetadata: + labels: + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.kind: Monitoring + apps.cozystack.io/application.name: {{ $.Release.Name }} + vlinsert: + replicaCount: 2 + resources: {} + vlselect: + replicaCount: 2 + resources: {} + vlstorage: + retentionPeriod: {{ .retentionPeriod | quote }} + replicaCount: 2 + resources: {} + storage: + volumeClaimTemplate: + spec: + {{- with .storageClassName }} + storageClassName: {{ . }} + {{- end }} + resources: + requests: + storage: {{ .storage }} +{{- end }} diff --git a/packages/extra/monitoring/templates/vm/grafana-datasource.yaml b/packages/system/monitoring/templates/vm/grafana-datasource.yaml similarity index 100% rename from packages/extra/monitoring/templates/vm/grafana-datasource.yaml rename to packages/system/monitoring/templates/vm/grafana-datasource.yaml diff --git a/packages/system/monitoring/templates/vm/vmagent.yaml b/packages/system/monitoring/templates/vm/vmagent.yaml new file mode 100644 index 00000000..98bff1e1 --- /dev/null +++ b/packages/system/monitoring/templates/vm/vmagent.yaml @@ -0,0 +1,37 @@ +{{- if and (ne .Release.Namespace "tenant-root") (ne .Release.Namespace "cozy-monitoring") }} +apiVersion: operator.victoriametrics.com/v1beta1 +kind: VMAgent +metadata: + name: vmagent +spec: + podMetadata: + labels: + policy.cozystack.io/allow-to-apiserver: "true" + shardCount: 1 + externalLabels: + cluster: {{ .Values.vmagent.externalLabels.cluster }} + tenant: {{ .Release.Namespace }} + {{- if .Values.vmagent.externalLabels.environment }} + environment: {{ .Values.vmagent.externalLabels.environment | quote }} + {{- end }} + extraArgs: + promscrape.maxScrapeSize: "32MB" + promscrape.streamParse: "true" + remoteWrite: + {{- range .Values.vmagent.remoteWrite.urls }} + - url: {{ . | quote }} + {{- end }} + + scrapeInterval: 30s + selectAllByDefault: false + {{- with .Values.vmagent.inlineScrapeConfig }} + inlineScrapeConfig: | + {{- . | nindent 4 }} + {{- end }} + podScrapeNamespaceSelector: + matchLabels: + namespace.cozystack.io/monitoring: {{ .Release.Namespace }} + serviceScrapeNamespaceSelector: + matchLabels: + namespace.cozystack.io/monitoring: {{ .Release.Namespace }} +{{- end }} diff --git a/packages/extra/monitoring/templates/vm/vmalert-scrape.yaml b/packages/system/monitoring/templates/vm/vmalert-scrape.yaml similarity index 100% rename from packages/extra/monitoring/templates/vm/vmalert-scrape.yaml rename to packages/system/monitoring/templates/vm/vmalert-scrape.yaml diff --git a/packages/extra/monitoring/templates/vm/vmalert.yaml b/packages/system/monitoring/templates/vm/vmalert.yaml similarity index 70% rename from packages/extra/monitoring/templates/vm/vmalert.yaml rename to packages/system/monitoring/templates/vm/vmalert.yaml index 8db6a2ed..8da03e15 100644 --- a/packages/extra/monitoring/templates/vm/vmalert.yaml +++ b/packages/system/monitoring/templates/vm/vmalert.yaml @@ -5,6 +5,11 @@ kind: VMAlert metadata: name: vmalert-{{ .name }} spec: + managedMetadata: + labels: + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.kind: Monitoring + apps.cozystack.io/application.name: {{ $.Release.Name }} datasource: url: http://vmselect-{{ .name }}.{{ $.Release.Namespace }}.svc:8481/select/0/prometheus evaluationInterval: 15s @@ -18,19 +23,5 @@ spec: url: http://vminsert-{{ .name }}.{{ $.Release.Namespace }}.svc:8480/insert/0/prometheus/api/v1/write resources: {} selectAllByDefault: true ---- -apiVersion: cozystack.io/v1alpha1 -kind: WorkloadMonitor -metadata: - name: vmalert-{{ .name }} -spec: - replicas: 1 - minReplicas: 1 - kind: monitoring - type: vmalert - selector: - app.kubernetes.io/instance: vmalert-{{ .name }} - app.kubernetes.io/name: vmalert - version: {{ $.Chart.Version }} {{- break }} {{- end }} diff --git a/packages/extra/monitoring/templates/vm/vmcluster-scrape.yaml b/packages/system/monitoring/templates/vm/vmcluster-scrape.yaml similarity index 100% rename from packages/extra/monitoring/templates/vm/vmcluster-scrape.yaml rename to packages/system/monitoring/templates/vm/vmcluster-scrape.yaml diff --git a/packages/extra/monitoring/templates/vm/vmcluster.yaml b/packages/system/monitoring/templates/vm/vmcluster.yaml similarity index 54% rename from packages/extra/monitoring/templates/vm/vmcluster.yaml rename to packages/system/monitoring/templates/vm/vmcluster.yaml index 344afff1..1bc39923 100644 --- a/packages/extra/monitoring/templates/vm/vmcluster.yaml +++ b/packages/system/monitoring/templates/vm/vmcluster.yaml @@ -5,6 +5,11 @@ kind: VMCluster metadata: name: {{ .name }} spec: + managedMetadata: + labels: + apps.cozystack.io/application.group: apps.cozystack.io + apps.cozystack.io/application.kind: Monitoring + apps.cozystack.io/application.name: {{ $.Release.Name }} replicationFactor: 2 retentionPeriod: {{ .retentionPeriod | quote }} vminsert: @@ -44,49 +49,4 @@ spec: requests: storage: {{ .storage }} storageDataPath: /vm-data ---- -apiVersion: cozystack.io/v1alpha1 -kind: WorkloadMonitor -metadata: - name: {{ .name }}-vmstorage -spec: - replicas: 2 - minReplicas: 1 - kind: monitoring - type: vmstorage - selector: - app.kubernetes.io/component: monitoring - app.kubernetes.io/instance: {{ .name }} - app.kubernetes.io/name: vmstorage - version: {{ $.Chart.Version }} ---- -apiVersion: cozystack.io/v1alpha1 -kind: WorkloadMonitor -metadata: - name: {{ .name }}-vmselect -spec: - replicas: 2 - minReplicas: 1 - kind: monitoring - type: vmselect - selector: - app.kubernetes.io/component: monitoring - app.kubernetes.io/instance: {{ .name }} - app.kubernetes.io/name: vmselect - version: {{ $.Chart.Version }} ---- -apiVersion: cozystack.io/v1alpha1 -kind: WorkloadMonitor -metadata: - name: {{ .name }}-vminsert -spec: - replicas: 2 - minReplicas: 1 - kind: monitoring - type: vminsert - selector: - app.kubernetes.io/component: monitoring - app.kubernetes.io/instance: {{ .name }} - app.kubernetes.io/name: vminsert - version: {{ $.Chart.Version }} {{- end }} diff --git a/packages/extra/monitoring/templates/vpa.yaml b/packages/system/monitoring/templates/vpa.yaml similarity index 50% rename from packages/extra/monitoring/templates/vpa.yaml rename to packages/system/monitoring/templates/vpa.yaml index 8b90c0ba..551f8310 100644 --- a/packages/extra/monitoring/templates/vpa.yaml +++ b/packages/system/monitoring/templates/vpa.yaml @@ -87,3 +87,92 @@ spec: memory: 8Gi {{- end }} {{- end }} +{{- range .Values.logsStorages }} +--- +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: vpa-vlinsert-{{ .name }} +spec: + targetRef: + apiVersion: apps/v1 + kind: Deployment + name: vlinsert-{{ .name }} + updatePolicy: + updateMode: Auto + resourcePolicy: + containerPolicies: + - containerName: vlinsert + minAllowed: + {{- if and .vlinsert .vlinsert.minAllowed }} + {{- toYaml .vlinsert.minAllowed | nindent 10 }} + {{- else }} + cpu: 25m + memory: 64Mi + {{- end }} + maxAllowed: + {{- if and .vlinsert .vlinsert.maxAllowed }} + {{- toYaml .vlinsert.maxAllowed | nindent 10 }} + {{- else }} + cpu: 2000m + memory: 4Gi + {{- end }} +--- +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: vpa-vlselect-{{ .name }} +spec: + targetRef: + apiVersion: apps/v1 + kind: Deployment + name: vlselect-{{ .name }} + updatePolicy: + updateMode: Auto + resourcePolicy: + containerPolicies: + - containerName: vlselect + minAllowed: + {{- if and .vlselect .vlselect.minAllowed }} + {{- toYaml .vlselect.minAllowed | nindent 10 }} + {{- else }} + cpu: 25m + memory: 64Mi + {{- end }} + maxAllowed: + {{- if and .vlselect .vlselect.maxAllowed }} + {{- toYaml .vlselect.maxAllowed | nindent 10 }} + {{- else }} + cpu: 4000m + memory: 8Gi + {{- end }} +--- +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: vpa-vlstorage-{{ .name }} +spec: + targetRef: + apiVersion: apps/v1 + kind: StatefulSet + name: vlstorage-{{ .name }} + updatePolicy: + updateMode: Auto + resourcePolicy: + containerPolicies: + - containerName: vlstorage + minAllowed: + {{- if and .vlstorage .vlstorage.minAllowed }} + {{- toYaml .vlstorage.minAllowed | nindent 10 }} + {{- else }} + cpu: 25m + memory: 64Mi + {{- end }} + maxAllowed: + {{- if and .vlstorage .vlstorage.maxAllowed }} + {{- toYaml .vlstorage.maxAllowed | nindent 10 }} + {{- else }} + cpu: 4000m + memory: 8Gi + {{- end }} +{{- end }} diff --git a/packages/system/monitoring/values.yaml b/packages/system/monitoring/values.yaml new file mode 100644 index 00000000..3b632cbe --- /dev/null +++ b/packages/system/monitoring/values.yaml @@ -0,0 +1,89 @@ +host: "" + +metricsStorages: +## Example: +## metricsStorages: +## - name: shortterm +## retentionPeriod: "3d" +## deduplicationInterval: "15s" +## storage: 10Gi +## storageClassName: "" +## vminsert: +## minAllowed: +## cpu: 200m +## memory: 512Mi +## maxAllowed: +## cpu: 1500m +## memory: 3Gi +## vmselect: +## minAllowed: +## cpu: 300m +## memory: 1Gi +## maxAllowed: +## cpu: 3500m +## memory: 6Gi +## vmstorage: +## minAllowed: +## cpu: 500m +## memory: 2Gi +## maxAllowed: +## cpu: 4000m +## memory: 8Gi +- name: shortterm + retentionPeriod: "3d" + deduplicationInterval: "15s" + storage: 10Gi + storageClassName: "" +- name: longterm + retentionPeriod: "14d" + deduplicationInterval: "5m" + storage: 10Gi + storageClassName: "" + +logsStorages: +- name: generic + retentionPeriod: "1" + storage: 10Gi + storageClassName: "" +alerta: + storage: 10Gi + storageClassName: "" + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 100m + memory: 256Mi + alerts: + telegram: + token: "" + chatID: "" + disabledSeverity: [] + slack: + url: "" + disabledSeverity: [] + dashboardUrl: "" + summaryFmt: "" +grafana: + db: + size: 10Gi + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 100m + memory: 256Mi +vmagent: + externalLabels: + cluster: cozystack + environment: "" + remoteWrite: + urls: + - http://vminsert-shortterm:8480/insert/0/prometheus + - http://vminsert-longterm:8480/insert/0/prometheus + ## inlineScrapeConfig: | + ## - job_name: "custom" + ## static_configs: + ## - targets: ["my-service:9090"] diff --git a/packages/system/multus/Chart.yaml b/packages/system/multus/Chart.yaml new file mode 100644 index 00000000..a019fc25 --- /dev/null +++ b/packages/system/multus/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-multus +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/multus/Makefile b/packages/system/multus/Makefile new file mode 100644 index 00000000..399af728 --- /dev/null +++ b/packages/system/multus/Makefile @@ -0,0 +1,25 @@ +export NAME=multus +export NAMESPACE=cozy-$(NAME) + +include ../../../hack/common-envs.mk +include ../../../hack/package.mk + +update: + rm -rf templates + mkdir templates + $(eval RELEASE := $(shell curl -s https://api.github.com/repos/k8snetworkplumbingwg/multus-cni/releases/latest?per_page=1 | jq -r '.name')) + wget -q https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/refs/tags/$(RELEASE)/deployments/multus-daemonset-thick.yml -O templates/multus-daemonset-thick.yml + sed -i '/multus-cni/s/snapshot-thick/$(RELEASE)-thick/' templates/multus-daemonset-thick.yml && \ + patch --no-backup-if-mismatch -p4 < patches/customize-deployment.patch + $(SED_INPLACE) "/ARG VERSION/ s|=.*|=$(RELEASE)|g" images/multus-cni/Dockerfile + +image: + docker buildx build images/multus-cni \ + --tag $(REGISTRY)/multus-cni:$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/multus-cni:latest \ + --cache-to type=inline \ + --metadata-file images/multus-cni.json \ + $(BUILDX_ARGS) + DIGEST=$$(yq e '."containerimage.digest"' images/multus-cni.json -o json -r) && \ + sed -i "s|image: .*multus-cni.*|image: $(REGISTRY)/multus-cni:$(TAG)@$${DIGEST}|g" templates/multus-daemonset-thick.yml + rm -f images/multus-cni.json diff --git a/packages/system/multus/images/multus-cni/Dockerfile b/packages/system/multus/images/multus-cni/Dockerfile new file mode 100644 index 00000000..feecbc6c --- /dev/null +++ b/packages/system/multus/images/multus-cni/Dockerfile @@ -0,0 +1,25 @@ +FROM --platform=$BUILDPLATFORM golang:1.24 AS build + +ARG VERSION=v4.2.3 +ARG TARGETPLATFORM + +WORKDIR /usr/src/multus-cni + +RUN curl -sSL https://github.com/k8snetworkplumbingwg/multus-cni/archive/refs/tags/${VERSION}.tar.gz | \ + tar -xzf - --strip=1 + +COPY patches /patches +RUN git init && git config user.email "build@cozystack" && git config user.name "build" && \ + git add -A && git commit -m "init" && git tag ${VERSION} && \ + git apply /patches/*.diff + +RUN ./hack/build-go.sh + +FROM debian:stable-slim +LABEL org.opencontainers.image.source=https://github.com/cozystack/cozystack +COPY --from=build /usr/src/multus-cni/bin /usr/src/multus-cni/bin +COPY --from=build /usr/src/multus-cni/LICENSE /usr/src/multus-cni/LICENSE +COPY --from=build /usr/src/multus-cni/bin/cert-approver / +WORKDIR / + +ENTRYPOINT ["/usr/src/multus-cni/bin/multus-daemon"] diff --git a/packages/system/multus/images/multus-cni/patches/fix-del-without-cache.diff b/packages/system/multus/images/multus-cni/patches/fix-del-without-cache.diff new file mode 100644 index 00000000..7595ddb2 --- /dev/null +++ b/packages/system/multus/images/multus-cni/patches/fix-del-without-cache.diff @@ -0,0 +1,49 @@ +diff --git a/pkg/multus/multus.go b/pkg/multus/multus.go +index a7941fe..eff0406 100644 +--- a/pkg/multus/multus.go ++++ b/pkg/multus/multus.go +@@ -954,33 +954,19 @@ func CmdDel(args *skel.CmdArgs, exec invoke.Exec, kubeClient *k8s.ClientInfo) er + } + + if !useCacheConf { +- // Fetch delegates again if cache is not exist and pod info can be read +- if os.IsNotExist(err) && pod != nil { +- if in.ClusterNetwork != "" { +- _, err = k8s.GetDefaultNetworks(pod, in, kubeClient, nil) +- if err != nil { +- return cmdErr(k8sArgs, "failed to get clusterNetwork/defaultNetworks: %v", err) +- } +- // First delegate is always the master plugin +- in.Delegates[0].MasterPlugin = true +- } +- +- // Get pod annotation and so on +- _, _, err := k8s.TryLoadPodDelegates(pod, in, kubeClient, nil) +- if err != nil { +- if len(in.Delegates) == 0 { +- // No delegate available so send error +- return cmdErr(k8sArgs, "failed to get delegates: %v", err) +- } +- // Get clusterNetwork before, so continue to delete +- logging.Errorf("Multus: failed to get delegates: %v, but continue to delete clusterNetwork", err) +- } +- } else { +- // The options to continue with a delete have been exhausted (cachefile + API query didn't work) +- // We cannot exit with an error as this may cause a sandbox to never get deleted. +- logging.Errorf("Multus: failed to get the cached delegates file: %v, cannot properly delete", err) ++ // If cache does not exist, ADD was never completed for this sandbox. ++ // Attempting DEL with a config reconstructed from the API will fail because ++ // delegate plugins (e.g. kube-ovn) require runtime state that only exists ++ // after a successful ADD (socket paths, cached results, etc.). ++ // Return success to allow containerd to release the sandbox name reservation. ++ if os.IsNotExist(err) { ++ logging.Verbosef("Multus: no cache found for container %s (ADD was never completed), skip DEL", args.ContainerID) + return nil + } ++ // The options to continue with a delete have been exhausted ++ // We cannot exit with an error as this may cause a sandbox to never get deleted. ++ logging.Errorf("Multus: failed to get the cached delegates file: %v, cannot properly delete", err) ++ return nil + } + + // set CNIVersion in delegate CNI config if there is no CNIVersion and multus conf have CNIVersion. diff --git a/packages/system/multus/patches/customize-deployment.patch b/packages/system/multus/patches/customize-deployment.patch new file mode 100644 index 00000000..b62d57e7 --- /dev/null +++ b/packages/system/multus/patches/customize-deployment.patch @@ -0,0 +1,48 @@ +--- a/packages/system/multus/templates/multus-daemonset-thick.yml ++++ b/packages/system/multus/templates/multus-daemonset-thick.yml +@@ -93,19 +93,19 @@ roleRef: + subjects: + - kind: ServiceAccount + name: multus +- namespace: kube-system ++ namespace: cozy-multus + --- + apiVersion: v1 + kind: ServiceAccount + metadata: + name: multus +- namespace: kube-system ++ namespace: cozy-multus + --- + kind: ConfigMap + apiVersion: v1 + metadata: + name: multus-daemon-config +- namespace: kube-system ++ namespace: cozy-multus + labels: + tier: node + app: multus +@@ -125,8 +125,8 @@ data: + apiVersion: apps/v1 + kind: DaemonSet + metadata: +- name: kube-multus-ds +- namespace: kube-system ++ name: cozy-multus ++ namespace: cozy-multus + labels: + tier: node + app: multus +@@ -159,10 +159,9 @@ spec: + resources: + requests: + cpu: "100m" +- memory: "50Mi" ++ memory: "100Mi" + limits: + cpu: "100m" +- memory: "50Mi" + securityContext: + privileged: true + terminationMessagePolicy: FallbackToLogsOnError diff --git a/packages/system/multus/templates/multus-daemonset-thick.yml b/packages/system/multus/templates/multus-daemonset-thick.yml new file mode 100644 index 00000000..cad330ea --- /dev/null +++ b/packages/system/multus/templates/multus-daemonset-thick.yml @@ -0,0 +1,256 @@ +# Note: +# This deployment file is designed for 'quickstart' of multus, easy installation to test it, +# hence this deployment yaml does not care about following things intentionally. +# - various configuration options +# - minor deployment scenario +# - upgrade/update/uninstall scenario +# Multus team understand users deployment scenarios are diverse, hence we do not cover +# comprehensive deployment scenario. We expect that it is covered by each platform deployment. +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: network-attachment-definitions.k8s.cni.cncf.io +spec: + group: k8s.cni.cncf.io + scope: Namespaced + names: + plural: network-attachment-definitions + singular: network-attachment-definition + kind: NetworkAttachmentDefinition + shortNames: + - net-attach-def + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + description: 'NetworkAttachmentDefinition is a CRD schema specified by the Network Plumbing + Working Group to express the intent for attaching pods to one or more logical or physical + networks. More information available at: https://github.com/k8snetworkplumbingwg/multi-net-spec' + type: object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this represen + tation 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: 'NetworkAttachmentDefinition spec defines the desired state of a network attachment' + type: object + properties: + config: + description: 'NetworkAttachmentDefinition config is a JSON-formatted CNI configuration' + type: string +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: multus +rules: + - apiGroups: ["k8s.cni.cncf.io"] + resources: + - '*' + verbs: + - '*' + - apiGroups: + - "" + resources: + - pods + - pods/status + verbs: + - get + - list + - update + - watch + - apiGroups: + - "" + - events.k8s.io + resources: + - events + verbs: + - create + - patch + - update +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: multus +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: multus +subjects: + - kind: ServiceAccount + name: multus + namespace: cozy-multus +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: multus + namespace: cozy-multus +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: multus-daemon-config + namespace: cozy-multus + labels: + tier: node + app: multus +data: + daemon-config.json: | + { + "chrootDir": "/hostroot", + "cniVersion": "0.3.1", + "logLevel": "verbose", + "logToStderr": true, + "cniConfigDir": "/host/etc/cni/net.d", + "multusAutoconfigDir": "/host/etc/cni/net.d", + "multusConfigFile": "auto", + "multusMasterCNI": "05-cilium.conflist", + "socketDir": "/host/run/multus/" + } +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: cozy-multus + namespace: cozy-multus + labels: + tier: node + app: multus + name: multus +spec: + selector: + matchLabels: + name: multus + updateStrategy: + type: RollingUpdate + template: + metadata: + labels: + tier: node + app: multus + name: multus + spec: + hostNetwork: true + hostPID: true + tolerations: + - operator: Exists + effect: NoSchedule + - operator: Exists + effect: NoExecute + serviceAccountName: multus + containers: + - name: kube-multus + image: ghcr.io/cozystack/cozystack/multus-cni:v1.3.0@sha256:6735ffc12e5e660951f5a42943b38c308f33774a55836e94c191001405b58ec0 + command: [ "/usr/src/multus-cni/bin/multus-daemon" ] + resources: + requests: + cpu: "100m" + memory: "100Mi" + limits: + cpu: "100m" + securityContext: + privileged: true + terminationMessagePolicy: FallbackToLogsOnError + volumeMounts: + - name: cni + mountPath: /host/etc/cni/net.d + # multus-daemon expects that cnibin path must be identical between pod and container host. + # e.g. if the cni bin is in '/opt/cni/bin' on the container host side, then it should be mount to '/opt/cni/bin' in multus-daemon, + # not to any other directory, like '/opt/bin' or '/usr/bin'. + - name: cnibin + mountPath: /opt/cni/bin + - name: host-run + mountPath: /host/run + - name: host-var-lib-cni-multus + mountPath: /var/lib/cni/multus + - name: host-var-lib-kubelet + mountPath: /var/lib/kubelet + mountPropagation: HostToContainer + - name: host-run-k8s-cni-cncf-io + mountPath: /run/k8s.cni.cncf.io + - name: host-run-netns + mountPath: /run/netns + mountPropagation: HostToContainer + - name: multus-daemon-config + mountPath: /etc/cni/net.d/multus.d + readOnly: true + - name: hostroot + mountPath: /hostroot + mountPropagation: HostToContainer + - mountPath: /etc/cni/multus/net.d + name: multus-conf-dir + env: + - name: MULTUS_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + initContainers: + - name: install-multus-binary + image: ghcr.io/cozystack/cozystack/multus-cni:v1.3.0@sha256:6735ffc12e5e660951f5a42943b38c308f33774a55836e94c191001405b58ec0 + command: + - "/usr/src/multus-cni/bin/install_multus" + - "-d" + - "/host/opt/cni/bin" + - "-t" + - "thick" + resources: + requests: + cpu: "10m" + memory: "15Mi" + securityContext: + privileged: true + terminationMessagePolicy: FallbackToLogsOnError + volumeMounts: + - name: cnibin + mountPath: /host/opt/cni/bin + mountPropagation: Bidirectional + terminationGracePeriodSeconds: 10 + volumes: + - name: cni + hostPath: + path: /etc/cni/net.d + - name: cnibin + hostPath: + path: /opt/cni/bin + - name: hostroot + hostPath: + path: / + - name: multus-daemon-config + configMap: + name: multus-daemon-config + items: + - key: daemon-config.json + path: daemon-config.json + - name: host-run + hostPath: + path: /run + - name: host-var-lib-cni-multus + hostPath: + path: /var/lib/cni/multus + - name: host-var-lib-kubelet + hostPath: + path: /var/lib/kubelet + - name: host-run-k8s-cni-cncf-io + hostPath: + path: /run/k8s.cni.cncf.io + - name: host-run-netns + hostPath: + path: /run/netns/ + - name: multus-conf-dir + hostPath: + path: /etc/cni/multus/net.d diff --git a/packages/system/multus/values.yaml b/packages/system/multus/values.yaml new file mode 100644 index 00000000..e69de29b diff --git a/packages/system/nats-rd/Chart.yaml b/packages/system/nats-rd/Chart.yaml new file mode 100644 index 00000000..9be57a87 --- /dev/null +++ b/packages/system/nats-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: nats-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/nats-rd/Makefile b/packages/system/nats-rd/Makefile new file mode 100644 index 00000000..4a72284c --- /dev/null +++ b/packages/system/nats-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=nats-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/nats-rd/cozyrds/nats.yaml b/packages/system/nats-rd/cozyrds/nats.yaml new file mode 100644 index 00000000..69cad09c --- /dev/null +++ b/packages/system/nats-rd/cozyrds/nats.yaml @@ -0,0 +1,38 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: nats +spec: + application: + kind: NATS + plural: natses + singular: nats + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each NATS replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user.","type":"string"}}}},"jetstream":{"description":"Jetstream configuration.","type":"object","default":{},"required":["enabled","size"],"properties":{"enabled":{"description":"Enable or disable Jetstream for persistent messaging in NATS.","type":"boolean","default":true},"size":{"description":"Jetstream persistent storage size.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"config":{"description":"NATS configuration.","type":"object","default":{},"properties":{"merge":{"description":"Additional configuration to merge into NATS config.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true},"resolver":{"description":"Additional resolver configuration to merge into NATS config.","type":"object","default":{},"x-kubernetes-preserve-unknown-fields":true}}}}} + release: + prefix: nats- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-nats-application-default-nats + namespace: cozy-system + dashboard: + category: PaaS + singular: NATS + plural: NATS + description: Managed NATS service + tags: + - messaging + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODFfMjgyMSkiLz4KPHJlY3Qgd2lkdGg9IjE0NCIgaGVpZ2h0PSIxNDQiIHJ4PSIyNCIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC4zIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTE3LjQ4IDI1SDI3Vjk4Ljk2OTNINjYuMDY4OUw4Ny43MDc1IDExOVY5OC45NjkzSDExNy40OFYyNVoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik05Mi4xMzUyIDcyLjQ1NTJWNDIuNjI1SDEwMi43NzNWODEuMTk5OUg4Ni42NTE5TDU0LjExNCA1MC44NDE0VjgxLjIzMjJINDMuNDQ0M1Y0Mi42MjVINjAuMTI2Mkw5Mi4xMzUyIDcyLjQ1NTJaIiBmaWxsPSJibGFjayIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4MV8yODIxIiB4MT0iMTAiIHkxPSIxNS41IiB4Mj0iMTQ0IiB5Mj0iMTMxLjUiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iIzM4NUM5MyIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMzMkE1NzQiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "storageClass"], ["spec", "external"], ["spec", "users"], ["spec", "jetstream"], ["spec", "jetstream", "enabled"], ["spec", "jetstream", "size"], ["spec", "config"], ["spec", "config", "merge"], ["spec", "config", "resolver"]] + secrets: + exclude: [] + include: + - resourceNames: + - nats-{{ .name }}-credentials + services: + exclude: [] + include: + - resourceNames: + - nats-{{ .name }} diff --git a/packages/system/nats-rd/templates/cozyrd.yaml b/packages/system/nats-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/nats-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/nats-rd/values.yaml b/packages/system/nats-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/nats-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/nats/Makefile b/packages/system/nats/Makefile index 25657a89..88883ab0 100644 --- a/packages/system/nats/Makefile +++ b/packages/system/nats/Makefile @@ -1,4 +1,4 @@ -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/nats/charts/nats/Chart.yaml b/packages/system/nats/charts/nats/Chart.yaml index e59601a9..2f0edf48 100644 --- a/packages/system/nats/charts/nats/Chart.yaml +++ b/packages/system/nats/charts/nats/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v2 -appVersion: 2.10.17 +appVersion: 2.11.8 description: A Helm chart for the NATS.io High Speed Cloud Native Distributed Communications Technology. home: http://github.com/nats-io/k8s @@ -13,4 +13,4 @@ maintainers: name: The NATS Authors url: https://github.com/nats-io name: nats -version: 1.2.1 +version: 1.3.13 diff --git a/packages/system/nats/charts/nats/README.md b/packages/system/nats/charts/nats/README.md index 0916999d..0096a1bb 100644 --- a/packages/system/nats/charts/nats/README.md +++ b/packages/system/nats/charts/nats/README.md @@ -44,7 +44,7 @@ Everything in the NATS Config or Kubernetes Resources can be overridden by `merg | `container` | nats [k8s Container](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#container-v1-core) | yes | | `reloader` | config reloader [k8s Container](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#container-v1-core) | yes | | `promExporter` | prometheus exporter [k8s Container](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#container-v1-core) | no | -| `promExporter.podMonitor` | [prometheus PodMonitor](https://prometheus-operator.dev/docs/operator/api/#monitoring.coreos.com/v1.PodMonitor) | no | +| `promExporter.podMonitor` | [prometheus PodMonitor](https://prometheus-operator.dev/docs/api-reference/api/#monitoring.coreos.com/v1.PodMonitor) | no | | `service` | [k8s Service](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#service-v1-core) | yes | | `statefulSet` | [k8s StatefulSet](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#statefulset-v1-apps) | yes | | `podTemplate` | [k8s PodTemplate](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#pod-v1-core) | yes | @@ -60,7 +60,7 @@ Everything in the NATS Config or Kubernetes Resources can be overridden by `merg ### Merge -Merging is performed using the Helm `merge` function. Example - add NATS accounts and container resources: +Merging is performed using the Helm [`merge` function](https://helm.sh/docs/chart_template_guide/function_list/#merge-mustmerge). Example - add NATS accounts and container resources: ```yaml config: @@ -119,14 +119,22 @@ podTemplate: ### NATS Container Resources +We recommend setting both **requests and limits** - for both **CPU and memory** - **to the same value** for the following reasons: + +* It ensures your NATS pod has [predictable performance](https://www.datadoghq.com/blog/kubernetes-cpu-requests-limits/#predictability:~:text=If%20containers%20are,available%20capacity%20decreases.). +* The NATS server [automatically sets](https://github.com/nats-io/nats-server/blob/v2.11.0/main.go#L131-L132) [GOMAXPROCS](https://github.com/golang/go/blob/go1.24.1/src/runtime/extern.go#L230-L234) to the number of CPU cores defined in the `limits` section. If `limits` are not set, GOMAXPROCS defaults to the node's physical core count, which can lead to [poor performance](https://github.com/golang/go/issues/33803). +* The pod will be assigned to the ["Guaranteed" QoS class](https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/#guaranteed), making it less likely to be evicted when node resources are constrained. + +Deviate from this recommendation only if you fully understand the implications of your settings. + ```yaml container: env: - # different from k8s units, suffix must be B, KiB, MiB, GiB, or TiB - # should be ~90% of memory limit - GOMEMLIMIT: 7GiB + # Different from k8s units, suffix must be B, KiB, MiB, GiB, or TiB + # Should be ~80% of memory limit + GOMEMLIMIT: 6GiB merge: - # recommended limit is at least 2 CPU cores and 8Gi Memory for production JetStream clusters + # Recommended minimum: at least 2 CPU cores and 8Gi memory for production JetStream clusters resources: requests: cpu: "2" @@ -138,11 +146,27 @@ container: ### Specify Image Version -```yaml -container: - image: - tag: x.y.z-alpine -``` +The container image can now be overridden by specifying either the image tag, an image digest, or a full image name. Examples below illustrate the options: + +- To set the tag: + ```yaml + container: + image: + tag: x.y.z-alpine + ``` +- To use an image digest, which overrides the tag: + ```yaml + container: + image: + repository: nats + digest: sha256:abcdef1234567890... + ``` +- To override the registry, repository, tag, and digest all at once, specify a full image name: + ```yaml + container: + image: + fullImageName: custom-reg.io/myimage@sha256:abcdef1234567890... + ``` ### Operator Mode with NATS Resolver diff --git a/packages/system/nats/charts/nats/files/stateful-set/pod-template.yaml b/packages/system/nats/charts/nats/files/stateful-set/pod-template.yaml index bb1d8d7b..9832ba34 100644 --- a/packages/system/nats/charts/nats/files/stateful-set/pod-template.yaml +++ b/packages/system/nats/charts/nats/files/stateful-set/pod-template.yaml @@ -69,3 +69,7 @@ spec: - {{ merge (dict "topologyKey" $k "labelSelector" (dict "matchLabels" (include "nats.selectorLabels" $ | fromYaml))) $v | toYaml | nindent 4 }} {{- end }} {{- end}} + + # terminationGracePeriodSeconds determines how long to wait for graceful shutdown + # this should be at least `lameDuckGracePeriod` + 20s shutdown overhead + terminationGracePeriodSeconds: 60 diff --git a/packages/system/nats/charts/nats/files/stateful-set/prom-exporter-container.yaml b/packages/system/nats/charts/nats/files/stateful-set/prom-exporter-container.yaml index c3e1b6fb..75f8a77c 100644 --- a/packages/system/nats/charts/nats/files/stateful-set/prom-exporter-container.yaml +++ b/packages/system/nats/charts/nats/files/stateful-set/prom-exporter-container.yaml @@ -27,4 +27,5 @@ args: {{- if .Values.config.gateway.enabled }} - -gatewayz {{- end }} -- http://localhost:{{ .Values.config.monitor.port }}/ +{{- $monitorProto := ternary "https" "http" .Values.config.monitor.tls.enabled }} +- {{ $monitorProto }}://{{ .Values.promExporter.monitorDomain }}:{{ .Values.config.monitor.port }}/ diff --git a/packages/system/nats/charts/nats/templates/_helpers.tpl b/packages/system/nats/charts/nats/templates/_helpers.tpl index ba831397..d8485943 100644 --- a/packages/system/nats/charts/nats/templates/_helpers.tpl +++ b/packages/system/nats/charts/nats/templates/_helpers.tpl @@ -147,10 +147,18 @@ app.kubernetes.io/component: nats-box Print the image */}} {{- define "nats.image" }} -{{- $image := printf "%s:%s" .repository .tag }} +{{- $image := "" }} +{{- if .digest }} +{{- $image = printf "%s@%s" .repository .digest }} +{{- else }} +{{- $image = printf "%s:%s" .repository .tag }} +{{- end }} {{- if or .registry .global.image.registry }} {{- $image = printf "%s/%s" (.registry | default .global.image.registry) $image }} -{{- end -}} +{{- end }} +{{- if .fullImageName }} +{{- $image = .fullImageName }} +{{- end }} image: {{ $image }} {{- if or .pullPolicy .global.image.pullPolicy }} imagePullPolicy: {{ .pullPolicy | default .global.image.pullPolicy }} @@ -274,7 +282,7 @@ output: string with following format rules */}} {{- define "nats.formatConfig" -}} {{- - (regexReplaceAll "\"<<\\s+(.*)\\s+>>\"" + (regexReplaceAll "\"<<\\s+(.*?)\\s+>>\"" (regexReplaceAll "\".*\\$include\": \"(.*)\",?" (include "toPrettyRawJson" .) "include ${1};") "${1}") -}} diff --git a/packages/system/nats/charts/nats/values.yaml b/packages/system/nats/charts/nats/values.yaml index 0b14ebd4..fa402f18 100644 --- a/packages/system/nats/charts/nats/values.yaml +++ b/packages/system/nats/charts/nats/values.yaml @@ -238,6 +238,7 @@ config: tls: # config.nats.tls must be enabled also # when enabled, monitoring port will use HTTPS with the options from config.nats.tls + # if promExporter is also enabled, consider setting promExporter.monitorDomain enabled: false profiling: @@ -312,9 +313,13 @@ config: container: image: repository: nats - tag: 2.10.17-alpine + tag: 2.11.8-alpine pullPolicy: registry: + # if digest is provided, it overrides tag (example: "sha256:abcdef1234567890") + digest: + # if fullImageName is provided, it overrides registry, repository, tag, and digest + fullImageName: # container port options # must be enabled in the config section also @@ -353,9 +358,11 @@ reloader: enabled: true image: repository: natsio/nats-server-config-reloader - tag: 0.15.0 + tag: 0.19.1 pullPolicy: registry: + digest: + fullImageName: # env var map, see nats.env for an example env: {} @@ -363,7 +370,7 @@ reloader: # all nats container volume mounts with the following prefixes # will be mounted into the reloader container natsVolumeMountPrefixes: - - /etc/ + - /etc/ # merge or patch the container # https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#container-v1-core @@ -378,11 +385,16 @@ promExporter: enabled: false image: repository: natsio/prometheus-nats-exporter - tag: 0.15.0 + tag: 0.17.3 pullPolicy: registry: + digest: + fullImageName: port: 7777 + # if config.monitor.tls.enabled is set to true, monitorDomain must be set to the common name + # or a SAN used in the tls certificate + monitorDomain: localhost # env var map, see nats.env for an example env: {} @@ -398,13 +410,12 @@ promExporter: enabled: false # merge or patch the pod monitor - # https://prometheus-operator.dev/docs/operator/api/#monitoring.coreos.com/v1.PodMonitor + # https://prometheus-operator.dev/docs/api-reference/api/#monitoring.coreos.com/v1.PodMonitor merge: {} patch: [] # defaults to "{{ include "nats.fullname" $ }}" name: - ############################################################ # service ############################################################ @@ -511,7 +522,6 @@ serviceAccount: # defaults to "{{ include "nats.fullname" $ }}" name: - ############################################################ # natsBox # @@ -564,9 +574,11 @@ natsBox: container: image: repository: natsio/nats-box - tag: 0.14.3 + tag: 0.18.0 pullPolicy: registry: + digest: + fullImageName: # env var map, see nats.env for an example env: {} @@ -624,7 +636,6 @@ natsBox: # defaults to "{{ include "nats.fullname" $ }}-box" name: - ################################################################################ # Extra user-defined resources ################################################################################ diff --git a/packages/system/nats/values.yaml b/packages/system/nats/values.yaml index a28cadbe..87f730dd 100644 --- a/packages/system/nats/values.yaml +++ b/packages/system/nats/values.yaml @@ -9,3 +9,7 @@ nats: cluster: routeURLs: k8sClusterDomain: cozy.local + promExporter: + enabled: true + podMonitor: + enabled: true diff --git a/packages/system/nfs-driver/Makefile b/packages/system/nfs-driver/Makefile index e3af6c03..2f14aa28 100644 --- a/packages/system/nfs-driver/Makefile +++ b/packages/system/nfs-driver/Makefile @@ -1,8 +1,8 @@ export NAME=nfs-driver export NAMESPACE=cozy-$(NAME) -include ../../../scripts/common-envs.mk -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/objectstorage-controller/Makefile b/packages/system/objectstorage-controller/Makefile index 66c9e2d9..dacc3353 100644 --- a/packages/system/objectstorage-controller/Makefile +++ b/packages/system/objectstorage-controller/Makefile @@ -1,11 +1,29 @@ -export NAME=cosi-controller +export NAME=objectstorage-controller export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf templates - mkdir templates - kubectl kustomize github.com/kubernetes-sigs/container-object-storage-interface-api > templates/crds.yaml - kubectl kustomize github.com/kubernetes-sigs/container-object-storage-interface-controller > templates/controller.yaml - sed -i 's/namespace: default/namespace: {{ .Release.Namespace }}/g' templates/controller.yaml + mkdir -p templates + kubectl kustomize github.com/kubernetes-sigs/container-object-storage-interface > templates/controller.yaml + sed -i 's/namespace: container-object-storage-system/namespace: {{ .Release.Namespace }}/g' templates/controller.yaml + sed -i 's|image:.*|image: {{ .Values.objectstorage.controller.image }}|' templates/controller.yaml + +image: image-controller image-sidecar +image-controller image-sidecar: + $(eval TARGET := $(subst image-,,$@)) + $(eval VALUES_FILE := $(if $(filter sidecar,$(TARGET)),../seaweedfs/values.yaml,values.yaml)) + $(eval YAML_PATH := $(if $(filter sidecar,$(TARGET)),.seaweedfs.cosi.sidecar.image,.objectstorage.controller.image)) + docker buildx build images/objectstorage \ + --target $(TARGET) \ + --tag $(REGISTRY)/objectstorage-$(TARGET):$(call settag,$(TAG)) \ + --cache-from type=registry,ref=$(REGISTRY)/objectstorage-$(TARGET):latest \ + --cache-to type=inline \ + --metadata-file images/$(TARGET).json \ + $(BUILDX_ARGS) + IMAGE="$(REGISTRY)/objectstorage-$(TARGET):$(call settag,$(TAG))@$$(yq e '."containerimage.digest"' images/$(TARGET).json -r)" \ + yq -i '$(YAML_PATH) = strenv(IMAGE)' $(VALUES_FILE) + rm -f images/$(TARGET).json + yq .seaweedfs.cosi.sidecar.image ../seaweedfs/values.yaml > ../../extra/seaweedfs/images/objectstorage-sidecar.tag diff --git a/packages/system/objectstorage-controller/images/objectstorage/Dockerfile b/packages/system/objectstorage-controller/images/objectstorage/Dockerfile new file mode 100644 index 00000000..260446c3 --- /dev/null +++ b/packages/system/objectstorage-controller/images/objectstorage/Dockerfile @@ -0,0 +1,31 @@ +# syntax=docker/dockerfile:1.2 + +FROM alpine AS source +ARG COMMIT_REF=v0.2.2 +RUN apk add --no-cache curl tar +WORKDIR /src + +RUN curl -sSL https://github.com/kubernetes-sigs/container-object-storage-interface/archive/${COMMIT_REF}.tar.gz \ + | tar -xz --strip-components=1 + +FROM --platform=$BUILDPLATFORM docker.io/golang:1.24 AS builder +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /go/src/cosi + +COPY --from=source /src/go.mod /src/go.sum /src ./ +RUN go mod download + +RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /build/controller ./controller/cmd \ + && CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /build/sidecar ./sidecar/cmd + +FROM gcr.io/distroless/static:nonroot AS controller +COPY --from=builder /build/controller /controller +USER 65532:65532 +ENTRYPOINT ["/controller"] + +FROM gcr.io/distroless/static:nonroot AS sidecar +COPY --from=builder /build/sidecar /sidecar +USER 65532:65532 +ENTRYPOINT ["/sidecar"] diff --git a/packages/system/objectstorage-controller/templates/controller.yaml b/packages/system/objectstorage-controller/templates/controller.yaml index 197c1f4f..b51b05ea 100644 --- a/packages/system/objectstorage-controller/templates/controller.yaml +++ b/packages/system/objectstorage-controller/templates/controller.yaml @@ -1,22 +1,507 @@ apiVersion: v1 +kind: Namespace +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support + objectstorage.k8s.io/authors: Kubernetes Authors + objectstorage.k8s.io/license: Apache V2 + objectstorage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api + labels: + app.kubernetes.io/component: controller + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: container-object-storage-interface-controller + app.kubernetes.io/part-of: container-object-storage-interface + name: container-object-storage-system +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support + controller-gen.kubebuilder.io/version: v0.17.3 + objectstorage.k8s.io/authors: Kubernetes Authors + objectstorage.k8s.io/license: Apache V2 + objectstorage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api + name: bucketaccessclasses.objectstorage.k8s.io +spec: + group: objectstorage.k8s.io + names: + kind: BucketAccessClass + listKind: BucketAccessClassList + plural: bucketaccessclasses + singular: bucketaccessclass + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + authenticationType: + description: |- + AuthenticationType denotes the style of authentication + It can be one of + Key - access, secret tokens based authentication + IAM - implicit authentication of pods to the OSP based on service account mappings + type: string + driverName: + description: |- + DriverName is the name of driver associated with + this BucketAccess + 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 + parameters: + additionalProperties: + type: string + description: |- + Parameters is an opaque map for passing in configuration to a driver + for granting access to a bucket + type: object + required: + - authenticationType + - driverName + type: object + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support + controller-gen.kubebuilder.io/version: v0.17.3 + objectstorage.k8s.io/authors: Kubernetes Authors + objectstorage.k8s.io/license: Apache V2 + objectstorage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api + name: bucketaccesses.objectstorage.k8s.io +spec: + group: objectstorage.k8s.io + names: + kind: BucketAccess + listKind: BucketAccessList + plural: bucketaccesses + singular: bucketaccess + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + bucketAccessClassName: + description: BucketAccessClassName is the name of the BucketAccessClass + type: string + bucketClaimName: + description: BucketClaimName is the name of the BucketClaim. + type: string + credentialsSecretName: + description: |- + CredentialsSecretName is the name of the secret that COSI should populate + with the credentials. If a secret by this name already exists, then it is + assumed that credentials have already been generated. It is not overridden. + This secret is deleted when the BucketAccess is delted. + type: string + protocol: + description: |- + Protocol is the name of the Protocol + that this access credential is supposed to support + If left empty, it will choose the protocol supported + by the bucket. If the bucket supports multiple protocols, + the end protocol is determined by the driver. + type: string + serviceAccountName: + description: |- + ServiceAccountName is the name of the serviceAccount that COSI will map + to the OSP service account when IAM styled authentication is specified + type: string + required: + - bucketAccessClassName + - bucketClaimName + - credentialsSecretName + type: object + status: + properties: + accessGranted: + description: AccessGranted indicates the successful grant of privileges + to access the bucket + type: boolean + accountID: + description: |- + AccountID is the unique ID for the account in the OSP. It will be populated + by the COSI sidecar once access has been successfully granted. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support + controller-gen.kubebuilder.io/version: v0.17.3 + objectstorage.k8s.io/authors: Kubernetes Authors + objectstorage.k8s.io/license: Apache V2 + objectstorage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api + name: bucketclaims.objectstorage.k8s.io +spec: + group: objectstorage.k8s.io + names: + kind: BucketClaim + listKind: BucketClaimList + plural: bucketclaims + singular: bucketclaim + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + bucketClassName: + description: Name of the BucketClass + type: string + existingBucketName: + description: |- + Name of a bucket object that was manually + created to import a bucket created outside of COSI + If unspecified, then a new Bucket will be dynamically provisioned + type: string + protocols: + description: |- + Protocols are the set of data API this bucket is required to support. + The possible values for protocol are: + - S3: Indicates Amazon S3 protocol + - Azure: Indicates Microsoft Azure BlobStore protocol + - GCS: Indicates Google Cloud Storage protocol + items: + type: string + type: array + required: + - protocols + type: object + status: + properties: + bucketName: + description: |- + BucketName is the name of the provisioned Bucket in response + to this BucketClaim. It is generated and set by the COSI controller + before making the creation request to the OSP backend. + type: string + bucketReady: + description: |- + BucketReady indicates that the bucket is ready for consumpotion + by workloads + type: boolean + required: + - bucketReady + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support + controller-gen.kubebuilder.io/version: v0.17.3 + objectstorage.k8s.io/authors: Kubernetes Authors + objectstorage.k8s.io/license: Apache V2 + objectstorage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api + name: bucketclasses.objectstorage.k8s.io +spec: + group: objectstorage.k8s.io + names: + kind: BucketClass + listKind: BucketClassList + plural: bucketclasses + singular: bucketclass + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + deletionPolicy: + default: Retain + description: |- + DeletionPolicy is used to specify how COSI should handle deletion of this + bucket. There are 2 possible values: + - Retain: Indicates that the bucket should not be deleted from the OSP + - Delete: Indicates that the bucket should be deleted from the OSP + once all the workloads accessing this bucket are done + type: string + driverName: + description: DriverName is the name of driver associated with this bucket + 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 + parameters: + additionalProperties: + type: string + description: |- + Parameters is an opaque map for passing in configuration to a driver + for creating the bucket + type: object + required: + - deletionPolicy + - driverName + type: object + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support + controller-gen.kubebuilder.io/version: v0.17.3 + objectstorage.k8s.io/authors: Kubernetes Authors + objectstorage.k8s.io/license: Apache V2 + objectstorage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api + name: buckets.objectstorage.k8s.io +spec: + group: objectstorage.k8s.io + names: + kind: Bucket + listKind: BucketList + plural: buckets + singular: bucket + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + bucketClaim: + description: |- + Name of the BucketClaim that resulted in the creation of this Bucket + In case the Bucket object was created manually, then this should refer + to the BucketClaim with which this Bucket should be bound + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: |- + If referring to a piece of an object instead of an entire object, this string + should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within a pod, this would take on a value like: + "spec.containers{name}" (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to have some well-defined way of + referencing a part of an object. + type: string + kind: + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + namespace: + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + type: string + resourceVersion: + description: |- + Specific resourceVersion to which this reference is made, if any. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + type: string + uid: + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids + type: string + type: object + x-kubernetes-map-type: atomic + bucketClassName: + description: Name of the BucketClass specified in the BucketRequest + type: string + deletionPolicy: + default: Retain + description: |- + DeletionPolicy is used to specify how COSI should handle deletion of this + bucket. There are 2 possible values: + - Retain: Indicates that the bucket should not be deleted from the OSP (default) + - Delete: Indicates that the bucket should be deleted from the OSP + once all the workloads accessing this bucket are done + type: string + driverName: + description: DriverName is the name of driver associated with this + bucket + type: string + existingBucketID: + description: |- + ExistingBucketID is the unique id of the bucket in the OSP. This field should be + used to specify a bucket that has been created outside of COSI. + This field will be empty when the Bucket is dynamically provisioned by COSI. + type: string + parameters: + additionalProperties: + type: string + type: object + protocols: + description: |- + Protocols are the set of data APIs this bucket is expected to support. + The possible values for protocol are: + - S3: Indicates Amazon S3 protocol + - Azure: Indicates Microsoft Azure BlobStore protocol + - GCS: Indicates Google Cloud Storage protocol + items: + type: string + type: array + required: + - bucketClaim + - bucketClassName + - driverName + - protocols + type: object + status: + properties: + bucketID: + description: |- + BucketID is the unique id of the bucket in the OSP. This field will be + populated by COSI. + type: string + bucketReady: + description: |- + BucketReady is a boolean condition to reflect the successful creation + of a bucket. + type: boolean + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: v1 kind: ServiceAccount metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support + objectstorage.k8s.io/authors: Kubernetes Authors + objectstorage.k8s.io/license: Apache V2 + objectstorage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api labels: app.kubernetes.io/component: controller + app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: container-object-storage-interface-controller app.kubernetes.io/part-of: container-object-storage-interface - app.kubernetes.io/version: main - name: objectstorage-controller-sa + name: container-object-storage-controller-sa + namespace: {{ .Release.Namespace }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support + objectstorage.k8s.io/authors: Kubernetes Authors + objectstorage.k8s.io/license: Apache V2 + objectstorage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api labels: app.kubernetes.io/component: controller + app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: container-object-storage-interface-controller app.kubernetes.io/part-of: container-object-storage-interface app.kubernetes.io/version: main - name: objectstorage-controller + name: container-object-storage-controller namespace: {{ .Release.Namespace }} rules: - apiGroups: @@ -34,13 +519,17 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support + objectstorage.k8s.io/authors: Kubernetes Authors + objectstorage.k8s.io/license: Apache V2 + objectstorage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api labels: app.kubernetes.io/component: controller + app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: container-object-storage-interface-controller app.kubernetes.io/part-of: container-object-storage-interface - app.kubernetes.io/version: main - name: objectstorage-controller-role - namespace: {{ .Release.Namespace }} + name: container-object-storage-controller-role rules: - apiGroups: - objectstorage.k8s.io @@ -95,74 +584,94 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support + objectstorage.k8s.io/authors: Kubernetes Authors + objectstorage.k8s.io/license: Apache V2 + objectstorage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api labels: app.kubernetes.io/component: controller + app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: container-object-storage-interface-controller app.kubernetes.io/part-of: container-object-storage-interface app.kubernetes.io/version: main - name: objectstorage-controller + name: container-object-storage-controller namespace: {{ .Release.Namespace }} roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: objectstorage-controller + name: container-object-storage-controller subjects: - kind: ServiceAccount - name: objectstorage-controller-sa + name: container-object-storage-controller-sa namespace: {{ .Release.Namespace }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support + objectstorage.k8s.io/authors: Kubernetes Authors + objectstorage.k8s.io/license: Apache V2 + objectstorage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api labels: app.kubernetes.io/component: controller + app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: container-object-storage-interface-controller app.kubernetes.io/part-of: container-object-storage-interface app.kubernetes.io/version: main - name: objectstorage-controller - namespace: {{ .Release.Namespace }} + name: container-object-storage-controller roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: objectstorage-controller-role + name: container-object-storage-controller-role subjects: - kind: ServiceAccount - name: objectstorage-controller-sa + name: container-object-storage-controller-sa namespace: {{ .Release.Namespace }} --- apiVersion: apps/v1 kind: Deployment metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support + objectstorage.k8s.io/authors: Kubernetes Authors + objectstorage.k8s.io/license: Apache V2 + objectstorage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api labels: + app: container-object-storage-interface-controller app.kubernetes.io/component: controller + app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: container-object-storage-interface-controller app.kubernetes.io/part-of: container-object-storage-interface - app.kubernetes.io/version: main - name: objectstorage-controller + name: container-object-storage-controller + namespace: {{ .Release.Namespace }} spec: replicas: 1 selector: matchLabels: - app.kubernetes.io/component: controller - app.kubernetes.io/name: container-object-storage-interface-controller - app.kubernetes.io/part-of: container-object-storage-interface - app.kubernetes.io/version: main + app: container-object-storage-interface-controller strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 0 template: metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support + objectstorage.k8s.io/authors: Kubernetes Authors + objectstorage.k8s.io/license: Apache V2 + objectstorage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api labels: + app: container-object-storage-interface-controller app.kubernetes.io/component: controller + app.kubernetes.io/managed-by: kustomize app.kubernetes.io/name: container-object-storage-interface-controller app.kubernetes.io/part-of: container-object-storage-interface - app.kubernetes.io/version: main spec: containers: - args: - --v=5 - image: gcr.io/k8s-staging-sig-storage/objectstorage-controller:v20221027-v0.1.1-8-g300019f - imagePullPolicy: Always + image: {{ .Values.objectstorage.controller.image }} name: objectstorage-controller - serviceAccountName: objectstorage-controller-sa + serviceAccountName: container-object-storage-controller-sa diff --git a/packages/system/objectstorage-controller/templates/crds.yaml b/packages/system/objectstorage-controller/templates/crds.yaml deleted file mode 100644 index 49dbc484..00000000 --- a/packages/system/objectstorage-controller/templates/crds.yaml +++ /dev/null @@ -1,413 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support - controller-gen.kubebuilder.io/version: (devel) - cosi.storage.k8s.io/authors: Kubernetes Authors - cosi.storage.k8s.io/license: Apache V2 - cosi.storage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api - creationTimestamp: null - name: bucketaccessclasses.objectstorage.k8s.io -spec: - group: objectstorage.k8s.io - names: - kind: BucketAccessClass - listKind: BucketAccessClassList - plural: bucketaccessclasses - singular: bucketaccessclass - scope: Cluster - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - authenticationType: - description: AuthenticationType denotes the style of authentication It - can be one of Key - access, secret tokens based authentication IAM - - implicit authentication of pods to the OSP based on service account - mappings - type: string - driverName: - description: DriverName is the name of driver associated with this BucketAccess - 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 - parameters: - additionalProperties: - type: string - description: Parameters is an opaque map for passing in configuration - to a driver for granting access to a bucket - type: object - required: - - authenticationType - - driverName - type: object - served: true - storage: true ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support - controller-gen.kubebuilder.io/version: (devel) - cosi.storage.k8s.io/authors: Kubernetes Authors - cosi.storage.k8s.io/license: Apache V2 - cosi.storage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api - creationTimestamp: null - name: bucketaccesses.objectstorage.k8s.io -spec: - group: objectstorage.k8s.io - names: - kind: BucketAccess - listKind: BucketAccessList - plural: bucketaccesses - singular: bucketaccess - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - properties: - bucketAccessClassName: - description: BucketAccessClassName is the name of the BucketAccessClass - type: string - bucketClaimName: - description: BucketClaimName is the name of the BucketClaim. - type: string - credentialsSecretName: - description: CredentialsSecretName is the name of the secret that - COSI should populate with the credentials. If a secret by this name - already exists, then it is assumed that credentials have already - been generated. It is not overridden. This secret is deleted when - the BucketAccess is delted. - type: string - protocol: - description: Protocol is the name of the Protocol that this access - credential is supposed to support If left empty, it will choose - the protocol supported by the bucket. If the bucket supports multiple - protocols, the end protocol is determined by the driver. - type: string - serviceAccountName: - description: ServiceAccountName is the name of the serviceAccount - that COSI will map to the OSP service account when IAM styled authentication - is specified - type: string - required: - - bucketAccessClassName - - bucketClaimName - - credentialsSecretName - type: object - status: - properties: - accessGranted: - description: AccessGranted indicates the successful grant of privileges - to access the bucket - type: boolean - accountID: - description: AccountID is the unique ID for the account in the OSP. - It will be populated by the COSI sidecar once access has been successfully - granted. - type: string - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support - controller-gen.kubebuilder.io/version: (devel) - cosi.storage.k8s.io/authors: Kubernetes Authors - cosi.storage.k8s.io/license: Apache V2 - cosi.storage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api - creationTimestamp: null - name: bucketclaims.objectstorage.k8s.io -spec: - group: objectstorage.k8s.io - names: - kind: BucketClaim - listKind: BucketClaimList - plural: bucketclaims - singular: bucketclaim - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - properties: - bucketClassName: - description: Name of the BucketClass - type: string - existingBucketName: - description: Name of a bucket object that was manually created to - import a bucket created outside of COSI If unspecified, then a new - Bucket will be dynamically provisioned - type: string - protocols: - description: 'Protocols are the set of data API this bucket is required - to support. The possible values for protocol are: - S3: Indicates - Amazon S3 protocol - Azure: Indicates Microsoft Azure BlobStore - protocol - GCS: Indicates Google Cloud Storage protocol' - items: - type: string - type: array - required: - - protocols - type: object - status: - properties: - bucketName: - description: BucketName is the name of the provisioned Bucket in response - to this BucketClaim. It is generated and set by the COSI controller - before making the creation request to the OSP backend. - type: string - bucketReady: - description: BucketReady indicates that the bucket is ready for consumpotion - by workloads - type: boolean - required: - - bucketReady - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support - controller-gen.kubebuilder.io/version: (devel) - cosi.storage.k8s.io/authors: Kubernetes Authors - cosi.storage.k8s.io/license: Apache V2 - cosi.storage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api - creationTimestamp: null - name: bucketclasses.objectstorage.k8s.io -spec: - group: objectstorage.k8s.io - names: - kind: BucketClass - listKind: BucketClassList - plural: bucketclasses - singular: bucketclass - scope: Cluster - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - deletionPolicy: - default: Retain - description: 'DeletionPolicy is used to specify how COSI should handle - deletion of this bucket. There are 2 possible values: - Retain: Indicates - that the bucket should not be deleted from the OSP - Delete: Indicates - that the bucket should be deleted from the OSP once all the workloads - accessing this bucket are done' - type: string - driverName: - description: DriverName is the name of driver associated with this bucket - 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 - parameters: - additionalProperties: - type: string - description: Parameters is an opaque map for passing in configuration - to a driver for creating the bucket - type: object - required: - - deletionPolicy - - driverName - type: object - served: true - storage: true ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/1979-object-storage-support - controller-gen.kubebuilder.io/version: (devel) - cosi.storage.k8s.io/authors: Kubernetes Authors - cosi.storage.k8s.io/license: Apache V2 - cosi.storage.k8s.io/support: https://github.com/kubernetes-sigs/container-object-storage-api - creationTimestamp: null - name: buckets.objectstorage.k8s.io -spec: - group: objectstorage.k8s.io - names: - kind: Bucket - listKind: BucketList - plural: buckets - singular: bucket - scope: Cluster - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - properties: - bucketClaim: - description: Name of the BucketClaim that resulted in the creation - of this Bucket In case the Bucket object was created manually, then - this should refer to the BucketClaim with which this Bucket should - be bound - properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: 'If referring to a piece of an object instead of - an entire object, this string should contain a valid JSON/Go - field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within - a pod, this would take on a value like: "spec.containers{name}" - (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" - (container with index 2 in this pod). This syntax is chosen - only to have some well-defined way of referencing a part of - an object. TODO: this design is not final and this field is - subject to change in the future.' - type: string - kind: - description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - namespace: - description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' - type: string - resourceVersion: - description: 'Specific resourceVersion to which this reference - is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' - type: string - uid: - description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' - type: string - type: object - x-kubernetes-map-type: atomic - bucketClassName: - description: Name of the BucketClass specified in the BucketRequest - type: string - deletionPolicy: - default: Retain - description: 'DeletionPolicy is used to specify how COSI should handle - deletion of this bucket. There are 2 possible values: - Retain: - Indicates that the bucket should not be deleted from the OSP (default) - - Delete: Indicates that the bucket should be deleted from the OSP - once all the workloads accessing this bucket are done' - type: string - driverName: - description: DriverName is the name of driver associated with this - bucket - type: string - existingBucketID: - description: ExistingBucketID is the unique id of the bucket in the - OSP. This field should be used to specify a bucket that has been - created outside of COSI. This field will be empty when the Bucket - is dynamically provisioned by COSI. - type: string - parameters: - additionalProperties: - type: string - type: object - protocols: - description: 'Protocols are the set of data APIs this bucket is expected - to support. The possible values for protocol are: - S3: Indicates - Amazon S3 protocol - Azure: Indicates Microsoft Azure BlobStore - protocol - GCS: Indicates Google Cloud Storage protocol' - items: - type: string - type: array - required: - - bucketClaim - - bucketClassName - - driverName - - protocols - type: object - status: - properties: - bucketID: - description: BucketID is the unique id of the bucket in the OSP. This - field will be populated by COSI. - type: string - bucketReady: - description: BucketReady is a boolean condition to reflect the successful - creation of a bucket. - type: boolean - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/packages/system/objectstorage-controller/values.yaml b/packages/system/objectstorage-controller/values.yaml new file mode 100644 index 00000000..a3859194 --- /dev/null +++ b/packages/system/objectstorage-controller/values.yaml @@ -0,0 +1,3 @@ +objectstorage: + controller: + image: "ghcr.io/cozystack/cozystack/objectstorage-controller:v1.3.0@sha256:7a9e4bf9c3f95f364756396815bb51b6c0f58f85db653460574d94b96cd3c7d5" diff --git a/packages/system/openbao-rd/Chart.yaml b/packages/system/openbao-rd/Chart.yaml new file mode 100644 index 00000000..f93484c3 --- /dev/null +++ b/packages/system/openbao-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: openbao-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/openbao-rd/Makefile b/packages/system/openbao-rd/Makefile new file mode 100644 index 00000000..3ad0f7ba --- /dev/null +++ b/packages/system/openbao-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=openbao-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/openbao-rd/cozyrds/openbao.yaml b/packages/system/openbao-rd/cozyrds/openbao.yaml new file mode 100644 index 00000000..47691c88 --- /dev/null +++ b/packages/system/openbao-rd/cozyrds/openbao.yaml @@ -0,0 +1,37 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: openbao +spec: + application: + kind: OpenBAO + plural: openbaos + singular: openbao + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of OpenBAO replicas. HA with Raft is automatically enabled when replicas > 1. Switching between standalone (file storage) and HA (Raft storage) modes requires data migration.","type":"integer","default":1},"resources":{"description":"Explicit CPU and memory configuration for each OpenBAO replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size for data storage.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"ui":{"description":"Enable the OpenBAO web UI.","type":"boolean","default":true}}} + release: + prefix: openbao- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-openbao-application-default-openbao + namespace: cozy-system + dashboard: + category: PaaS + singular: OpenBAO + plural: OpenBAO + description: Managed OpenBAO secrets management service + tags: + - secrets + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcikiLz4KPHJlY3Qgd2lkdGg9IjE0NCIgaGVpZ2h0PSIxNDQiIHJ4PSIyNCIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC4zIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNzIgMzBDNTMuMjIyIDMwIDM4IDQ1LjIyMiAzOCA2NHY4Yy0zLjMxNCAwLTYgMi42ODYtNiA2djMwYzAgMy4zMTQgMi42ODYgNiA2IDZoNjhjMy4zMTQgMCA2LTIuNjg2IDYtNlY3OGMwLTMuMzE0LTIuNjg2LTYtNi02di04QzEwNiA0NS4yMjIgOTAuNzc4IDMwIDcyIDMwem0tOCA0MnYtOGMwLTQuNDE4IDMuNTgyLTggOC04czggMy41ODIgOCA4djhINjR6bTI2IDB2LThjMC04LjgzNy03LjE2My0xNi0xNi0xNnMtMTYgNy4xNjMtMTYgMTZ2OGgtMnYyOGg2MFY3Mkg5MHptLTIyIDE0YTQgNCAwIDExOCAwIDQgNCAwIDAxLTggMHptNC04YTggOCAwIDEwMCAxNiA4IDggMCAwMDAtMTZ6IiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyIiB4MT0iMTAiIHkxPSIxNS41IiB4Mj0iMTQ0IiB5Mj0iMTMxLjUiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iIzg3ZDZiZSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM3OWMwYWIiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "ui"]] + secrets: + exclude: [] + include: [] + services: + exclude: [] + include: + - resourceNames: + - openbao-{{ .name }} + - openbao-{{ .name }}-internal diff --git a/packages/system/openbao-rd/templates/cozyrd.yaml b/packages/system/openbao-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/openbao-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/openbao-rd/values.yaml b/packages/system/openbao-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/openbao-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/openbao/Chart.yaml b/packages/system/openbao/Chart.yaml new file mode 100644 index 00000000..104a5e95 --- /dev/null +++ b/packages/system/openbao/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-openbao +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/openbao/Makefile b/packages/system/openbao/Makefile new file mode 100644 index 00000000..4ae6190e --- /dev/null +++ b/packages/system/openbao/Makefile @@ -0,0 +1,10 @@ +export NAME=openbao +export NAMESPACE=cozy-openbao +export REPO_NAME=openbao +export REPO_URL=https://openbao.github.io/openbao-helm +export CHART_NAME=openbao +export CHART_VERSION=^0.25 + +include ../../../hack/package.mk + +update: clean openbao-update diff --git a/packages/system/dashboard/charts/kubeapps/.helmignore b/packages/system/openbao/charts/openbao/.helmignore similarity index 71% rename from packages/system/dashboard/charts/kubeapps/.helmignore rename to packages/system/openbao/charts/openbao/.helmignore index 34d55e3e..4007e243 100644 --- a/packages/system/dashboard/charts/kubeapps/.helmignore +++ b/packages/system/openbao/charts/openbao/.helmignore @@ -1,6 +1,3 @@ -# Copyright 2021-2022 the Kubeapps contributors. -# SPDX-License-Identifier: Apache-2.0 - # Patterns to ignore when building packages. # This supports shell glob matching, relative path matching, and # negation (prefixed with !). Only one pattern per line. @@ -8,6 +5,7 @@ # Common VCS dirs .git/ .gitignore +.terraform/ .bzr/ .bzrignore .hg/ @@ -22,7 +20,9 @@ .project .idea/ *.tmproj -# img folder -img/ -# Changelog -CHANGELOG.md + +# CI and test +.circleci/ +.github/ +.gitlab-ci.yml +test/ diff --git a/packages/system/openbao/charts/openbao/Chart.yaml b/packages/system/openbao/charts/openbao/Chart.yaml new file mode 100644 index 00000000..4914439e --- /dev/null +++ b/packages/system/openbao/charts/openbao/Chart.yaml @@ -0,0 +1,30 @@ +annotations: + artifacthub.io/changes: | + - kind: changed + description: | + fix: Add extraPorts to server Service in ha + artifacthub.io/containsSecurityUpdates: "false" + charts.openshift.io/name: Openbao +apiVersion: v2 +appVersion: v2.5.0 +description: Official OpenBao Chart +home: https://github.com/openbao/openbao-helm +icon: https://raw.githubusercontent.com/openbao/artwork/refs/heads/main/color/openbao-color.svg +keywords: +- vault +- openbao +- security +- encryption +- secrets +- management +- automation +- infrastructure +kubeVersion: '>= 1.30.0-0' +maintainers: +- email: openbao-security@lists.openssf.org + name: OpenBao + url: https://openbao.org +name: openbao +sources: +- https://github.com/openbao/openbao-helm +version: 0.25.3 diff --git a/packages/system/openbao/charts/openbao/README.md b/packages/system/openbao/charts/openbao/README.md new file mode 100644 index 00000000..bcdf92b1 --- /dev/null +++ b/packages/system/openbao/charts/openbao/README.md @@ -0,0 +1,365 @@ +# openbao + +![Version: 0.25.3](https://img.shields.io/badge/Version-0.25.3-informational?style=flat-square) ![AppVersion: v2.5.0](https://img.shields.io/badge/AppVersion-v2.5.0-informational?style=flat-square) + +Official OpenBao Chart + +**Homepage:** + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| OpenBao | | | + +## Source Code + +* + +## Requirements + +Kubernetes: `>= 1.30.0-0` + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| csi.agent.enabled | bool | `true` | | +| csi.agent.extraArgs | list | `[]` | | +| csi.agent.image.pullPolicy | string | `"IfNotPresent"` | image pull policy to use for agent image. if tag is "latest", set to "Always" | +| csi.agent.image.registry | string | `"quay.io"` | image registry to use for agent image | +| csi.agent.image.repository | string | `"openbao/openbao"` | image repo to use for agent image | +| csi.agent.image.tag | string | `""` | image tag to use for agent image - defaults to chart appVersion | +| csi.agent.logFormat | string | `"standard"` | | +| csi.agent.logLevel | string | `"info"` | | +| csi.agent.resources | object | `{}` | | +| csi.daemonSet.annotations | object | `{}` | | +| csi.daemonSet.endpoint | string | `"/provider/openbao.sock"` | | +| csi.daemonSet.extraLabels | object | `{}` | | +| csi.daemonSet.kubeletRootDir | string | `"/var/lib/kubelet"` | | +| csi.daemonSet.providersDir | string | `"/etc/kubernetes/secrets-store-csi-providers"` | | +| csi.daemonSet.securityContext.container | object | `{}` | | +| csi.daemonSet.securityContext.pod | object | `{}` | | +| csi.daemonSet.updateStrategy.maxUnavailable | string | `""` | | +| csi.daemonSet.updateStrategy.type | string | `"RollingUpdate"` | | +| csi.debug | bool | `false` | | +| csi.enabled | bool | `false` | True if you want to install a openbao-csi-provider daemonset. Requires installing the secrets-store-csi-driver separately, see: https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation With the driver and provider installed, you can mount OpenBao secrets into volumes similar to the OpenBao Agent injector, and you can also sync those secrets into Kubernetes secrets. | +| csi.extraArgs | list | `[]` | | +| csi.hmacSecretName | string | `""` | | +| csi.image.pullPolicy | string | `"IfNotPresent"` | image pull policy to use for csi image. if tag is "latest", set to "Always" | +| csi.image.registry | string | `"quay.io"` | image registry to use for csi image | +| csi.image.repository | string | `"openbao/openbao-csi-provider"` | image repo to use for csi image | +| csi.image.tag | string | `"2.0.0"` | image tag to use for csi image | +| csi.livenessProbe.failureThreshold | int | `2` | | +| csi.livenessProbe.initialDelaySeconds | int | `5` | | +| csi.livenessProbe.periodSeconds | int | `5` | | +| csi.livenessProbe.successThreshold | int | `1` | | +| csi.livenessProbe.timeoutSeconds | int | `3` | | +| csi.pod.affinity | object | `{}` | | +| csi.pod.annotations | object | `{}` | | +| csi.pod.extraLabels | object | `{}` | | +| csi.pod.nodeSelector | object | `{}` | | +| csi.pod.tolerations | list | `[]` | | +| csi.priorityClassName | string | `""` | | +| csi.readinessProbe.failureThreshold | int | `2` | | +| csi.readinessProbe.initialDelaySeconds | int | `5` | | +| csi.readinessProbe.periodSeconds | int | `5` | | +| csi.readinessProbe.successThreshold | int | `1` | | +| csi.readinessProbe.timeoutSeconds | int | `3` | | +| csi.resources | object | `{}` | | +| csi.serviceAccount.annotations | object | `{}` | | +| csi.serviceAccount.extraLabels | object | `{}` | | +| csi.volumeMounts | list | `[]` | volumeMounts is a list of volumeMounts for the main server container. These are rendered via toYaml rather than pre-processed like the extraVolumes value. The purpose is to make it easy to share volumes between containers. | +| csi.volumes | list | `[]` | volumes is a list of volumes made available to all containers. These are rendered via toYaml rather than pre-processed like the extraVolumes value. The purpose is to make it easy to share volumes between containers. | +| extraObjects | list | `[]` | | +| global.enabled | bool | `true` | enabled is the master enabled switch. Setting this to true or false will enable or disable all the components within this chart by default. | +| global.externalBaoAddr | string | `""` | External openbao server address for the injector and CSI provider to use. Setting this will disable deployment of a openbao server. | +| global.externalVaultAddr | string | `""` | Deprecated: Please use global.externalBaoAddr instead. | +| global.imagePullSecrets | list | `[]` | Image pull secret to use for registry authentication. Alternatively, the value may be specified as an array of strings. | +| global.namespace | string | `""` | The namespace to deploy to. Defaults to the `helm` installation namespace. | +| global.openshift | bool | `false` | If deploying to OpenShift | +| global.psp | object | `{"annotations":"seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default,runtime/default\napparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default\nseccomp.security.alpha.kubernetes.io/defaultProfileName: runtime/default\napparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default\n","enable":false}` | Create PodSecurityPolicy for pods | +| global.psp.annotations | string | `"seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default,runtime/default\napparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default\nseccomp.security.alpha.kubernetes.io/defaultProfileName: runtime/default\napparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default\n"` | Annotation for PodSecurityPolicy. This is a multi-line templated string map, and can also be set as YAML. | +| global.serverTelemetry.prometheusOperator | bool | `false` | Enable integration with the Prometheus Operator See the top level serverTelemetry section below before enabling this feature. | +| global.tlsDisable | bool | `true` | TLS for end-to-end encrypted transport | +| injector.affinity | string | `"podAntiAffinity:\n requiredDuringSchedulingIgnoredDuringExecution:\n - labelSelector:\n matchLabels:\n app.kubernetes.io/name: {{ template \"openbao.name\" . }}-agent-injector\n app.kubernetes.io/instance: \"{{ .Release.Name }}\"\n component: webhook\n topologyKey: kubernetes.io/hostname\n"` | | +| injector.agentDefaults.cpuLimit | string | `"500m"` | | +| injector.agentDefaults.cpuRequest | string | `"250m"` | | +| injector.agentDefaults.memLimit | string | `"128Mi"` | | +| injector.agentDefaults.memRequest | string | `"64Mi"` | | +| injector.agentDefaults.template | string | `"map"` | | +| injector.agentDefaults.templateConfig.exitOnRetryFailure | bool | `true` | | +| injector.agentDefaults.templateConfig.staticSecretRenderInterval | string | `""` | | +| injector.agentImage | object | `{"pullPolicy":"IfNotPresent","registry":"quay.io","repository":"openbao/openbao","tag":""}` | agentImage sets the repo and tag of the OpenBao image to use for the OpenBao Agent containers. This should be set to the official OpenBao image. OpenBao 1.3.1+ is required. | +| injector.agentImage.pullPolicy | string | `"IfNotPresent"` | image pull policy to use for agent image. if tag is "latest", set to "Always" | +| injector.agentImage.registry | string | `"quay.io"` | image registry to use for agent image | +| injector.agentImage.repository | string | `"openbao/openbao"` | image repo to use for agent image | +| injector.agentImage.tag | string | `""` | image tag to use for agent image - defaults to chart appVersion | +| injector.annotations | object | `{}` | | +| injector.authPath | string | `"auth/kubernetes"` | | +| injector.certs.caBundle | string | `""` | | +| injector.certs.certName | string | `"tls.crt"` | | +| injector.certs.keyName | string | `"tls.key"` | | +| injector.certs.secretName | string | `nil` | | +| injector.enabled | string | `"-"` | True if you want to enable openbao agent injection. @default: global.enabled | +| injector.externalVaultAddr | string | `""` | Deprecated: Please use global.externalBaoAddr instead. | +| injector.extraEnvironmentVars | object | `{}` | | +| injector.extraLabels | object | `{}` | | +| injector.failurePolicy | string | `"Ignore"` | | +| injector.hostNetwork | bool | `false` | | +| injector.image.pullPolicy | string | `"IfNotPresent"` | image pull policy to use for k8s image. if tag is "latest", set to "Always" | +| injector.image.registry | string | `"docker.io"` | image registry to use for k8s image | +| injector.image.repository | string | `"hashicorp/vault-k8s"` | image repo to use for k8s image | +| injector.image.tag | string | `"1.7.2"` | image tag to use for k8s image | +| injector.leaderElector | object | `{"enabled":true}` | If multiple replicas are specified, by default a leader will be determined so that only one injector attempts to create TLS certificates. | +| injector.livenessProbe.failureThreshold | int | `2` | When a probe fails, Kubernetes will try failureThreshold times before giving up | +| injector.livenessProbe.initialDelaySeconds | int | `5` | Number of seconds after the container has started before probe initiates | +| injector.livenessProbe.periodSeconds | int | `2` | How often (in seconds) to perform the probe | +| injector.livenessProbe.successThreshold | int | `1` | Minimum consecutive successes for the probe to be considered successful after having failed | +| injector.livenessProbe.timeoutSeconds | int | `5` | Number of seconds after which the probe times out. | +| injector.logFormat | string | `"standard"` | Configures the log format of the injector. Supported log formats: "standard", "json". | +| injector.logLevel | string | `"info"` | Configures the log verbosity of the injector. Supported log levels include: trace, debug, info, warn, error | +| injector.metrics | object | `{"enabled":false}` | If true, will enable a node exporter metrics endpoint at /metrics. | +| injector.namespaceSelector | object | `{}` | | +| injector.nodeSelector | object | `{}` | | +| injector.objectSelector | object | `{}` | | +| injector.podDisruptionBudget | object | `{}` | | +| injector.port | int | `8080` | Configures the port the injector should listen on | +| injector.priorityClassName | string | `""` | | +| injector.readinessProbe.failureThreshold | int | `2` | When a probe fails, Kubernetes will try failureThreshold times before giving up | +| injector.readinessProbe.initialDelaySeconds | int | `5` | Number of seconds after the container has started before probe initiates | +| injector.readinessProbe.periodSeconds | int | `2` | How often (in seconds) to perform the probe | +| injector.readinessProbe.successThreshold | int | `1` | Minimum consecutive successes for the probe to be considered successful after having failed | +| injector.readinessProbe.timeoutSeconds | int | `5` | Number of seconds after which the probe times out. | +| injector.replicas | int | `1` | | +| injector.resources | object | `{}` | | +| injector.revokeOnShutdown | bool | `false` | | +| injector.securityContext.container | object | `{}` | | +| injector.securityContext.pod | object | `{}` | | +| injector.service.annotations | object | `{}` | | +| injector.service.extraLabels | object | `{}` | | +| injector.serviceAccount.annotations | object | `{}` | | +| injector.startupProbe.failureThreshold | int | `12` | When a probe fails, Kubernetes will try failureThreshold times before giving up | +| injector.startupProbe.initialDelaySeconds | int | `5` | Number of seconds after the container has started before probe initiates | +| injector.startupProbe.periodSeconds | int | `5` | How often (in seconds) to perform the probe | +| injector.startupProbe.successThreshold | int | `1` | Minimum consecutive successes for the probe to be considered successful after having failed | +| injector.startupProbe.timeoutSeconds | int | `5` | Number of seconds after which the probe times out. | +| injector.strategy | object | `{}` | | +| injector.tolerations | list | `[]` | | +| injector.topologySpreadConstraints | list | `[]` | | +| injector.webhook.annotations | object | `{}` | | +| injector.webhook.failurePolicy | string | `"Ignore"` | | +| injector.webhook.matchPolicy | string | `"Exact"` | | +| injector.webhook.namespaceSelector | object | `{}` | | +| injector.webhook.objectSelector | string | `"matchExpressions:\n- key: app.kubernetes.io/name\n operator: NotIn\n values:\n - {{ template \"openbao.name\" . }}-agent-injector\n"` | | +| injector.webhook.timeoutSeconds | int | `30` | | +| injector.webhookAnnotations | object | `{}` | | +| server.affinity | string | `"podAntiAffinity:\n requiredDuringSchedulingIgnoredDuringExecution:\n - labelSelector:\n matchLabels:\n app.kubernetes.io/name: {{ template \"openbao.name\" . }}\n app.kubernetes.io/instance: \"{{ .Release.Name }}\"\n component: server\n topologyKey: kubernetes.io/hostname\n"` | | +| server.annotations | object | `{}` | | +| server.auditStorage.accessMode | string | `"ReadWriteOnce"` | | +| server.auditStorage.annotations | object | `{}` | | +| server.auditStorage.enabled | bool | `false` | | +| server.auditStorage.labels | object | `{}` | | +| server.auditStorage.mountPath | string | `"/openbao/audit"` | | +| server.auditStorage.size | string | `"10Gi"` | | +| server.auditStorage.storageClass | string | `nil` | | +| server.authDelegator.enabled | bool | `true` | | +| server.configAnnotation | bool | `false` | | +| server.dataStorage.accessMode | string | `"ReadWriteOnce"` | | +| server.dataStorage.annotations | object | `{}` | | +| server.dataStorage.enabled | bool | `true` | | +| server.dataStorage.labels | object | `{}` | | +| server.dataStorage.mountPath | string | `"/openbao/data"` | | +| server.dataStorage.size | string | `"10Gi"` | | +| server.dataStorage.storageClass | string | `nil` | | +| server.dev.devRootToken | string | `"root"` | | +| server.dev.enabled | bool | `false` | | +| server.enabled | string | `"-"` | | +| server.extraArgs | string | `""` | extraArgs is a string containing additional OpenBao server arguments. | +| server.extraContainers | string | `nil` | | +| server.extraEnvironmentVars | object | `{}` | | +| server.extraInitContainers | list | `[]` | extraInitContainers is a list of init containers. Specified as a YAML list. This is useful if you need to run a script to provision TLS certificates or write out configuration files in a dynamic way. | +| server.extraLabels | object | `{}` | | +| server.extraPorts | list | `[]` | extraPorts is a list of extra ports. Specified as a YAML list. This is useful if you need to add additional ports to the statefulset in dynamic way. | +| server.extraSecretEnvironmentVars | list | `[]` | | +| server.extraVolumes | list | `[]` | | +| server.gateway.httpRoute.activeService | bool | `true` | | +| server.gateway.httpRoute.annotations | object | `{}` | | +| server.gateway.httpRoute.apiVersion | string | `"gateway.networking.k8s.io/v1"` | | +| server.gateway.httpRoute.enabled | bool | `false` | | +| server.gateway.httpRoute.filters | list | `[]` | | +| server.gateway.httpRoute.hosts[0] | string | `"chart-example.local"` | | +| server.gateway.httpRoute.labels | object | `{}` | | +| server.gateway.httpRoute.matches.path.type | string | `"PathPrefix"` | | +| server.gateway.httpRoute.matches.path.value | string | `"/"` | | +| server.gateway.httpRoute.matches.timeouts | object | `{}` | | +| server.gateway.httpRoute.parentRefs | list | `[]` | | +| server.gateway.tlsPolicy.activeService | bool | `true` | | +| server.gateway.tlsPolicy.annotations | object | `{}` | | +| server.gateway.tlsPolicy.apiVersion | string | `"gateway.networking.k8s.io/v1"` | | +| server.gateway.tlsPolicy.enabled | bool | `false` | | +| server.gateway.tlsPolicy.labels | object | `{}` | | +| server.gateway.tlsPolicy.targetRefs | list | `[]` | | +| server.gateway.tlsPolicy.validation | object | `{}` | | +| server.gateway.tlsRoute.activeService | bool | `true` | | +| server.gateway.tlsRoute.annotations | object | `{}` | | +| server.gateway.tlsRoute.apiVersion | string | `"gateway.networking.k8s.io/v1alpha3"` | | +| server.gateway.tlsRoute.enabled | bool | `false` | | +| server.gateway.tlsRoute.hosts | list | `[]` | | +| server.gateway.tlsRoute.labels | object | `{}` | | +| server.gateway.tlsRoute.parentRefs | list | `[]` | | +| server.ha.apiAddr | string | `nil` | | +| server.ha.clusterAddr | string | `nil` | | +| server.ha.config | string | `"ui = true\n\nlistener \"tcp\" {\n tls_disable = 1\n address = \"[::]:8200\"\n cluster_address = \"[::]:8201\"\n}\nstorage \"consul\" {\n path = \"openbao\"\n address = \"HOST_IP:8500\"\n}\n\nservice_registration \"kubernetes\" {}\n\n# Example configuration for using auto-unseal, using Google Cloud KMS. The\n# GKMS keys must already exist, and the cluster must have a service account\n# that is authorized to access GCP KMS.\n#seal \"gcpckms\" {\n# project = \"openbao-helm-dev-246514\"\n# region = \"global\"\n# key_ring = \"openbao-helm-unseal-kr\"\n# crypto_key = \"openbao-helm-unseal-key\"\n#}\n\n# Example configuration for enabling Prometheus metrics.\n# If you are using Prometheus Operator you can enable a ServiceMonitor resource below.\n# You may wish to enable unauthenticated metrics in the listener block above.\n#telemetry {\n# prometheus_retention_time = \"30s\"\n# disable_hostname = true\n#}\n"` | | +| server.ha.disruptionBudget.enabled | bool | `true` | | +| server.ha.disruptionBudget.maxUnavailable | string | `nil` | | +| server.ha.enabled | bool | `false` | | +| server.ha.raft.config | string | `"ui = true\n\nlistener \"tcp\" {\n tls_disable = 1\n address = \"[::]:8200\"\n cluster_address = \"[::]:8201\"\n # Enable unauthenticated metrics access (necessary for Prometheus Operator)\n #telemetry {\n # unauthenticated_metrics_access = \"true\"\n #}\n}\n\nstorage \"raft\" {\n path = \"/openbao/data\"\n}\n\nservice_registration \"kubernetes\" {}\n"` | | +| server.ha.raft.enabled | bool | `false` | | +| server.ha.raft.setNodeId | bool | `false` | | +| server.ha.replicas | int | `3` | | +| server.hostAliases | list | `[]` | | +| server.hostNetwork | bool | `false` | | +| server.image.pullPolicy | string | `"IfNotPresent"` | image pull policy to use for server image. if tag is "latest", set to "Always" | +| server.image.registry | string | `"quay.io"` | image registry to use for server image | +| server.image.repository | string | `"openbao/openbao"` | image repo to use for server image | +| server.image.tag | string | `""` | image tag to use for server image - defaults to chart appVersion | +| server.ingress.activeService | bool | `true` | | +| server.ingress.annotations | object | `{}` | | +| server.ingress.enabled | bool | `false` | | +| server.ingress.extraPaths | list | `[]` | | +| server.ingress.hosts[0].host | string | `"chart-example.local"` | | +| server.ingress.hosts[0].paths | list | `[]` | | +| server.ingress.ingressClassName | string | `""` | | +| server.ingress.labels | object | `{}` | | +| server.ingress.pathType | string | `"Prefix"` | | +| server.ingress.tls | list | `[]` | | +| server.livenessProbe.enabled | bool | `false` | | +| server.livenessProbe.execCommand | list | `[]` | | +| server.livenessProbe.failureThreshold | int | `2` | | +| server.livenessProbe.initialDelaySeconds | int | `60` | | +| server.livenessProbe.path | string | `"/v1/sys/health?standbyok=true"` | | +| server.livenessProbe.periodSeconds | int | `5` | | +| server.livenessProbe.port | int | `8200` | | +| server.livenessProbe.successThreshold | int | `1` | | +| server.livenessProbe.timeoutSeconds | int | `3` | | +| server.logFormat | string | `""` | | +| server.logLevel | string | `""` | | +| server.networkPolicy.egress | list | `[]` | | +| server.networkPolicy.enabled | bool | `false` | | +| server.networkPolicy.ingress[0].from[0].namespaceSelector | object | `{}` | | +| server.networkPolicy.ingress[0].ports[0].port | int | `8200` | | +| server.networkPolicy.ingress[0].ports[0].protocol | string | `"TCP"` | | +| server.networkPolicy.ingress[0].ports[1].port | int | `8201` | | +| server.networkPolicy.ingress[0].ports[1].protocol | string | `"TCP"` | | +| server.nodeSelector | object | `{}` | | +| server.persistentVolumeClaimRetentionPolicy | object | `{}` | | +| server.podManagementPolicy | string | `"OrderedReady"` | | +| server.postStart | list | `[]` | | +| server.preStopSleepSeconds | int | `5` | | +| server.priorityClassName | string | `""` | | +| server.readinessProbe.enabled | bool | `true` | | +| server.readinessProbe.failureThreshold | int | `2` | | +| server.readinessProbe.initialDelaySeconds | int | `5` | | +| server.readinessProbe.periodSeconds | int | `5` | | +| server.readinessProbe.port | int | `8200` | | +| server.readinessProbe.successThreshold | int | `1` | | +| server.readinessProbe.timeoutSeconds | int | `3` | | +| server.resources | object | `{}` | | +| server.route.activeService | bool | `true` | | +| server.route.annotations | object | `{}` | | +| server.route.enabled | bool | `false` | | +| server.route.host | string | `"chart-example.local"` | | +| server.route.labels | object | `{}` | | +| server.route.tls.termination | string | `"passthrough"` | | +| server.service.active.annotations | object | `{}` | | +| server.service.active.enabled | bool | `true` | | +| server.service.active.extraLabels | object | `{}` | | +| server.service.annotations | object | `{}` | | +| server.service.enabled | bool | `true` | | +| server.service.externalTrafficPolicy | string | `"Cluster"` | | +| server.service.extraLabels | object | `{}` | | +| server.service.extraPorts | list | `[]` | extraPorts is a list of extra ports. Specified as a YAML list. This is useful if you need to add additional ports to the server service in dynamic way. | +| server.service.instanceSelector.enabled | bool | `true` | | +| server.service.ipFamilies | list | `[]` | | +| server.service.ipFamilyPolicy | string | `""` | | +| server.service.port | int | `8200` | | +| server.service.publishNotReadyAddresses | bool | `true` | | +| server.service.standby.annotations | object | `{}` | | +| server.service.standby.enabled | bool | `true` | | +| server.service.standby.extraLabels | object | `{}` | | +| server.service.targetPort | int | `8200` | | +| server.serviceAccount.annotations | object | `{}` | | +| server.serviceAccount.create | bool | `true` | | +| server.serviceAccount.createSecret | bool | `false` | | +| server.serviceAccount.extraLabels | object | `{}` | | +| server.serviceAccount.name | string | `""` | | +| server.serviceAccount.serviceDiscovery.enabled | bool | `true` | | +| server.shareProcessNamespace | bool | `false` | shareProcessNamespace enables process namespace sharing between OpenBao and the extraContainers This is useful if OpenBao must be signaled, e.g. to send a SIGHUP for a log rotation | +| server.standalone.config | string | `"ui = true\n\nlistener \"tcp\" {\n tls_disable = 1\n address = \"[::]:8200\"\n cluster_address = \"[::]:8201\"\n # Enable unauthenticated metrics access (necessary for Prometheus Operator)\n #telemetry {\n # unauthenticated_metrics_access = \"true\"\n #}\n}\nstorage \"file\" {\n path = \"/openbao/data\"\n}\n\n# Example configuration for using auto-unseal, using Google Cloud KMS. The\n# GKMS keys must already exist, and the cluster must have a service account\n# that is authorized to access GCP KMS.\n#seal \"gcpckms\" {\n# project = \"openbao-helm-dev\"\n# region = \"global\"\n# key_ring = \"openbao-helm-unseal-kr\"\n# crypto_key = \"openbao-helm-unseal-key\"\n#}\n\n# Example configuration for enabling Prometheus metrics in your config.\n#telemetry {\n# prometheus_retention_time = \"30s\"\n# disable_hostname = true\n#}\n"` | | +| server.standalone.enabled | string | `"-"` | | +| server.statefulSet.annotations | object | `{}` | | +| server.statefulSet.securityContext.container | object | `{}` | | +| server.statefulSet.securityContext.pod | object | `{}` | | +| server.terminationGracePeriodSeconds | int | `10` | | +| server.tolerations | list | `[]` | | +| server.topologySpreadConstraints | list | `[]` | | +| server.updateStrategyType | string | `"OnDelete"` | | +| server.volumeMounts | string | `nil` | | +| server.volumes | string | `nil` | | +| serverTelemetry.grafanaDashboard.defaultLabel | bool | `true` | | +| serverTelemetry.grafanaDashboard.enabled | bool | `false` | | +| serverTelemetry.grafanaDashboard.extraAnnotations | object | `{}` | | +| serverTelemetry.grafanaDashboard.extraLabel | object | `{}` | | +| serverTelemetry.prometheusRules.enabled | bool | `false` | | +| serverTelemetry.prometheusRules.rules | list | `[]` | | +| serverTelemetry.prometheusRules.selectors | object | `{}` | | +| serverTelemetry.serviceMonitor.authorization | object | `{}` | | +| serverTelemetry.serviceMonitor.enabled | bool | `false` | | +| serverTelemetry.serviceMonitor.interval | string | `"30s"` | | +| serverTelemetry.serviceMonitor.port | string | `""` | Port which Prometheus uses when scraping metrics. If empty will use `openbao.scheme` helper for its value | +| serverTelemetry.serviceMonitor.scheme | string | `""` | scheme to use when Prometheus scrapes metrics. If empty will use `openbao.scheme` helper for its value | +| serverTelemetry.serviceMonitor.scrapeClass | string | `""` | | +| serverTelemetry.serviceMonitor.scrapeTimeout | string | `"10s"` | | +| serverTelemetry.serviceMonitor.selectors | object | `{}` | | +| serverTelemetry.serviceMonitor.tlsConfig | object | `{}` | | +| snapshotAgent.annotations | object | `{}` | | +| snapshotAgent.config.baoAuthPath | string | `"kubernetes"` | | +| snapshotAgent.config.baoRole | string | `"snapshot"` | | +| snapshotAgent.config.s3Bucket | string | `"openbao-snapshots"` | | +| snapshotAgent.config.s3ExpireDays | string | `"14"` | | +| snapshotAgent.config.s3Host | string | `"s3.eu-east-1.amazonaws.com"` | | +| snapshotAgent.config.s3Uri | string | `"s3://openbao-snapshots"` | | +| snapshotAgent.config.s3cmdExtraFlag | string | `"-v"` | | +| snapshotAgent.enabled | bool | `false` | | +| snapshotAgent.extraEnvironmentVars | object | `{}` | Map of extra environment variables to set in the snapshot-agent cronjob | +| snapshotAgent.extraSecretEnvironmentVars | list | `[]` | List of extra environment variables to set in the snapshot-agent cronjob These variables take value from existing Secret objects. | +| snapshotAgent.extraVolumeMounts | list | `[]` | List of additional volumeMounts for the snapshot cronjob container. | +| snapshotAgent.extraVolumes | list | `[]` | List of extraVolumes made available to the snapshot cronjob container. | +| snapshotAgent.image.repository | string | `"ghcr.io/openbao/openbao-snapshot-agent"` | | +| snapshotAgent.image.tag | string | `"0.2.4"` | | +| snapshotAgent.resources | object | `{}` | | +| snapshotAgent.restartPolicy | string | `"OnFailure"` | | +| snapshotAgent.s3CredentialsSecret | string | `"my-s3-credentials"` | | +| snapshotAgent.schedule | string | `"*/15 * * * *"` | | +| snapshotAgent.securityContext.container | object | `{}` | | +| snapshotAgent.securityContext.pod | object | `{}` | | +| snapshotAgent.serviceAccount.annotations | object | `{}` | | +| snapshotAgent.serviceAccount.create | bool | `true` | | +| snapshotAgent.serviceAccount.extraLabels | object | `{}` | | +| snapshotAgent.serviceAccount.name | string | `""` | | +| ui.activeOpenbaoPodOnly | bool | `false` | | +| ui.annotations | object | `{}` | | +| ui.enabled | bool | `false` | | +| ui.externalPort | int | `8200` | | +| ui.externalTrafficPolicy | string | `"Cluster"` | | +| ui.extraLabels | object | `{}` | | +| ui.publishNotReadyAddresses | bool | `true` | | +| ui.serviceIPFamilies | list | `[]` | | +| ui.serviceIPFamilyPolicy | string | `""` | | +| ui.serviceNodePort | string | `nil` | | +| ui.serviceType | string | `"ClusterIP"` | | +| ui.targetPort | int | `8200` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2) diff --git a/packages/system/openbao/charts/openbao/grafana/dashboards/dashboard.json b/packages/system/openbao/charts/openbao/grafana/dashboards/dashboard.json new file mode 100644 index 00000000..b4eb93b9 --- /dev/null +++ b/packages/system/openbao/charts/openbao/grafana/dashboards/dashboard.json @@ -0,0 +1,2559 @@ +{ + "__inputs": [ + { + "name": "DS_PROMXY", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "7.0.3" + }, + { + "type": "panel", + "id": "grafana-piechart-panel", + "name": "Pie Chart", + "version": "1.5.0" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "${DS_PROMXY}", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": " OpenBao Metrics", + "editable": true, + "graphTooltip": 1, + "id": null, + "iteration": 1602255075192, + "links": [], + "panels": [ + { + "datasource": "${DS_PROMXY}", + "fieldConfig": { + "defaults": { + "custom": { + "align": null + }, + "mappings": [ + { + "from": "", + "id": 0, + "operator": "", + "text": "Standby", + "to": "", + "type": 1, + "value": "0" + }, + { + "from": "", + "id": 1, + "operator": "", + "text": "Active", + "to": "", + "type": 1, + "value": "1" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + }, + "unit": "Misc" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 9, + "x": 0, + "y": 0 + }, + "id": 39, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["last"], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.3", + "targets": [ + { + "expr": "up{job=\"openbao-internal\"}", + "format": "time_series", + "interval": "", + "legendFormat": "{{ instance }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Healthy Status", + "type": "stat" + }, + { + "datasource": "${DS_PROMXY}", + "fieldConfig": { + "defaults": { + "custom": { + "align": null, + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Mount Path" + }, + "properties": [ + { + "id": "custom.width", + "value": 166 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 5, + "x": 9, + "y": 0 + }, + "id": 59, + "maxDataPoints": 100, + "options": { + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Number of Entries" + } + ] + }, + "pluginVersion": "7.0.3", + "targets": [ + { + "expr": "sum by (exported_namespace,mount_point) (${metrics_prefix}_secret_kv_count)", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "{{ mount_point }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Secrets", + "transformations": [ + { + "id": "seriesToColumns", + "options": { + "byField": "mount_point" + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "__name__": true, + "cluster": true, + "env": true, + "instance": true, + "job": true, + "namespace": true, + "project": true + }, + "indexByName": {}, + "renameByName": { + "Value": "Number of Entries", + "mount_point": "Mount Path", + "exported_namespace": "Namespace" + } + } + } + ], + "type": "table" + }, + { + "datasource": "${DS_PROMXY}", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 14, + "y": 0 + }, + "id": 78, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.3", + "targets": [ + { + "expr": "avg(${metrics_prefix}_identity_num_entities)", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Number of Identity Entities", + "type": "stat" + }, + { + "aliasColors": {}, + "breakPoint": "50%", + "cacheTimeout": null, + "combine": { + "label": "Others", + "threshold": 0 + }, + "datasource": "${DS_PROMXY}", + "decimals": null, + "fieldConfig": { + "defaults": { + "custom": { + "align": null + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "fontSize": "80%", + "format": "short", + "gridPos": { + "h": 8, + "w": 5, + "x": 19, + "y": 0 + }, + "id": 49, + "interval": null, + "legend": { + "header": "count", + "percentage": false, + "show": true, + "sideWidth": null, + "values": true + }, + "legendType": "Right side", + "links": [], + "maxDataPoints": 1, + "nullPointMode": "connected", + "pieType": "pie", + "pluginVersion": "7.0.3", + "strokeWidth": "3", + "targets": [ + { + "expr": "avg without(instance) (${metrics_prefix}_identity_entity_alias_count)", + "format": "time_series", + "interval": "", + "legendFormat": "{{ auth_method }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Identity Entities Aliases by Method", + "type": "grafana-piechart-panel", + "valueName": "current" + }, + { + "datasource": "${DS_PROMXY}", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [ + { + "from": "", + "id": 0, + "operator": "", + "text": "UNSEALED", + "to": "", + "type": 1, + "value": "2" + }, + { + "from": "", + "id": 1, + "operator": "", + "text": "SEALED", + "to": "", + "type": 1, + "value": "1" + } + ], + "noValue": "N/A", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "green", + "value": 2 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 9, + "x": 0, + "y": 4 + }, + "id": 47, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["last"], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.3", + "targets": [ + { + "expr": "max(1 + ${metrics_prefix}_core_unsealed{})", + "format": "time_series", + "interval": "", + "legendFormat": "{{ instance }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Sealed Status", + "type": "stat" + }, + { + "datasource": "${DS_PROMXY}", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 100 + }, + { + "color": "#EF843C", + "value": 200 + }, + { + "color": "red", + "value": 400 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 14, + "y": 4 + }, + "id": 95, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.3", + "targets": [ + { + "expr": "avg(${metrics_prefix}_expire_num_leases)", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Number of Leases", + "type": "stat" + }, + { + "collapsed": true, + "datasource": "${DS_PROMXY}", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 74, + "panels": [ + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMXY}", + "decimals": 0, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "id": 24, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "sort": null, + "sortDesc": null, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "mountpoint": { + "selected": true, + "text": "secret", + "value": "secret" + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "avg(increase(${metrics_prefix}_route_create_${mountpoint}__count[5m]))", + "format": "time_series", + "hide": false, + "interval": "5m", + "legendFormat": "Create", + "refId": "A" + }, + { + "expr": "avg(increase(${metrics_prefix}_route_delete_${mountpoint}__count[5m]))", + "hide": false, + "interval": "5m", + "legendFormat": "Delete", + "refId": "B" + }, + { + "expr": "avg(increase(${metrics_prefix}_route_read_${mountpoint}__count[5m]))", + "format": "time_series", + "hide": false, + "instant": false, + "interval": "5m", + "intervalFactor": 1, + "legendFormat": "Read", + "refId": "C" + }, + { + "expr": "avg(increase(${metrics_prefix}_route_list_${mountpoint}__count[5m]))", + "format": "time_series", + "hide": false, + "interval": "5m", + "legendFormat": "List", + "refId": "D" + }, + { + "expr": "avg(increase(${metrics_prefix}_route_rollback_${mountpoint}__count[5m]))", + "hide": true, + "interval": "5m", + "legendFormat": "Rollback", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Number of Operations in \"$mountpoint\"", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:182", + "decimals": 0, + "format": "short", + "label": "Operations in 5 minute", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:183", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMXY}", + "decimals": 0, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 9 + }, + "hiddenSeries": false, + "id": 35, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "sort": null, + "sortDesc": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "scopedVars": { + "mountpoint": { + "selected": true, + "text": "secret", + "value": "secret" + } + }, + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg(rate(${metrics_prefix}_route_create_${mountpoint}__sum[1m]) / rate(${metrics_prefix}_route_create_${mountpoint}__count[1m]) * 1000)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Create", + "refId": "A" + }, + { + "expr": "avg(rate(${metrics_prefix}_route_delete_${mountpoint}__sum[1m]) / rate(${metrics_prefix}_route_delete_${mountpoint}__count[1m]) * 1000)", + "interval": "", + "legendFormat": "Delete", + "refId": "B" + }, + { + "expr": "avg(rate(${metrics_prefix}_route_read_${mountpoint}__sum[1m]) / rate(${metrics_prefix}_route_read_${mountpoint}__count[1m]) * 1000)", + "hide": false, + "interval": "", + "legendFormat": "Read", + "refId": "C" + }, + { + "expr": "avg(rate(${metrics_prefix}_route_list_${mountpoint}__sum[1m]) / rate(${metrics_prefix}_route_list_${mountpoint}__count[1m]) * 1000)", + "hide": false, + "interval": "", + "legendFormat": "List", + "refId": "D" + }, + { + "expr": "avg(rate(${metrics_prefix}_route_rollback_${mountpoint}__sum[1m]) / rate(${metrics_prefix}_route_rollback_${mountpoint}__count[1m]) * 1000)", + "hide": true, + "interval": "", + "legendFormat": "Rollback", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Time of Operations in \"$mountpoint\"", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:82", + "decimals": 0, + "format": "µs", + "label": "Time of one operation", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:83", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "repeat": "mountpoint", + "title": "Path Info: $mountpoint", + "type": "row" + }, + { + "collapsed": false, + "datasource": "${DS_PROMXY}", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 45, + "panels": [], + "repeat": null, + "title": "CPU/Mem Info: $node", + "type": "row" + }, + { + "datasource": "${DS_PROMXY}", + "description": "", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "noValue": "N/A", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 0.2 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 3, + "x": 0, + "y": 10 + }, + "id": 41, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["last"], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.3", + "targets": [ + { + "expr": "avg(${metrics_prefix}_runtime_heap_objects{} / ${metrics_prefix}_runtime_malloc_count{})", + "interval": "", + "intervalFactor": 10, + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Heap Objects Used", + "type": "stat" + }, + { + "datasource": "${DS_PROMXY}", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "noValue": "N/A", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 70 + }, + { + "color": "#EF843C", + "value": 100 + }, + { + "color": "#E24D42", + "value": 150 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 3, + "x": 3, + "y": 10 + }, + "id": 76, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["last"], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.3", + "targets": [ + { + "expr": "avg(${metrics_prefix}_runtime_num_goroutines{})", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Number of Goroutines", + "type": "stat" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMXY}", + "decimals": 3, + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 18, + "x": 6, + "y": 10 + }, + "hiddenSeries": false, + "id": 43, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pluginVersion": "7.0.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg(${metrics_prefix}_runtime_alloc_bytes{})", + "interval": "", + "intervalFactor": 5, + "legendFormat": "$node", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Allocated MB", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:373", + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:374", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": "${DS_PROMXY}", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 16, + "panels": [], + "title": "Token", + "type": "row" + }, + { + "datasource": "${DS_PROMXY}", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "noValue": "N/A", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 0, + "y": 16 + }, + "id": 53, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.3", + "targets": [ + { + "expr": "avg(${metrics_prefix}_token_count)", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Available Tokens", + "type": "stat" + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMXY}", + "decimals": 0, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 21, + "x": 3, + "y": 16 + }, + "hiddenSeries": false, + "id": 104, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg without(instance) (${metrics_prefix}_token_count_by_policy)", + "interval": "", + "legendFormat": "{{ policy }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Tokens by Policy", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": true, + "values": ["current"] + }, + "yaxes": [ + { + "$$hashKey": "object:575", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:576", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "datasource": "${DS_PROMXY}", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "noValue": "0", + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 1 + }, + { + "color": "red", + "value": 3 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 0, + "y": 20 + }, + "id": 8, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": ["lastNotNull"] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": ["last"], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.3", + "targets": [ + { + "expr": "avg(${metrics_prefix}_token_create_count - ${metrics_prefix}_token_store_count)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Pending Tokens", + "type": "stat" + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMXY}", + "decimals": 0, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 24 + }, + "hiddenSeries": false, + "id": 102, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg without(instance) (${metrics_prefix}_token_count_by_ttl)", + "format": "time_series", + "interval": "", + "legendFormat": "{{ creation_ttl }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Tokens by TTL", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": true, + "values": ["current"] + }, + "yaxes": [ + { + "$$hashKey": "object:390", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:391", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMXY}", + "decimals": 0, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 24 + }, + "hiddenSeries": false, + "id": 100, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg without(instance) (${metrics_prefix}_token_count_by_auth)", + "interval": "", + "legendFormat": "{{ auth_method }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Tokens by Auth Method", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": true, + "values": ["current"] + }, + "yaxes": [ + { + "$$hashKey": "object:136", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:137", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMXY}", + "decimals": 0, + "fieldConfig": { + "defaults": { + "custom": { + "align": null + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 32 + }, + "hiddenSeries": false, + "id": 65, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "maxDataPoints": 100, + "nullPointMode": "null as zero", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pluginVersion": "7.0.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "avg by(auth_method, creation_ttl) (${metrics_prefix}_token_creation)", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ auth_method }} - {{ creation_ttl }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Tokens Creation by Method & TTL", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1956", + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:1957", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Create": "rgb(84, 183, 90)", + "Store": "#0a437c" + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMXY}", + "decimals": 0, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 32 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "avg without(instance) (${metrics_prefix}_token_create_count)", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 10, + "legendFormat": "Create", + "refId": "A" + }, + { + "expr": "avg without(instance) (${metrics_prefix}_token_store_count)", + "format": "time_series", + "hide": false, + "instant": false, + "interval": "", + "intervalFactor": 10, + "legendFormat": "Store", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Token Creation/Storage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:877", + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:878", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Lookup": "#0a50a1" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMXY}", + "decimals": 3, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 38 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg(irate(${metrics_prefix}_token_lookup_count[1m]))", + "hide": false, + "interval": "", + "legendFormat": "Lookups", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Token Lookups", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:330", + "decimals": 0, + "format": "short", + "label": "Lookups per second", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:331", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": "${DS_PROMXY}", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 20, + "panels": [], + "title": "Audit", + "type": "row" + }, + { + "datasource": "${DS_PROMXY}", + "description": "", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 3, + "x": 0, + "y": 45 + }, + "id": 97, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["max"], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.3", + "targets": [ + { + "expr": "max(idelta(${metrics_prefix}_audit_log_request_failure[1m]))", + "format": "time_series", + "interval": "", + "legendFormat": "Request", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Log Request Failures", + "type": "stat" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMXY}", + "decimals": 3, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 11, + "x": 3, + "y": 45 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg(irate(${metrics_prefix}_audit_log_request_count[1m]))", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Request ", + "refId": "A" + }, + { + "expr": "avg(irate(${metrics_prefix}_audit_log_response_count[1m]))", + "format": "time_series", + "hide": false, + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Response", + "refId": "B" + }, + { + "expr": "avg(irate(${metrics_prefix}_core_handle_request_count[1m]))", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Handled", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Log Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:109", + "decimals": 0, + "format": "short", + "label": "Requests per second", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:110", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMXY}", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 10, + "x": 14, + "y": 45 + }, + "hiddenSeries": false, + "id": 61, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg(irate(${metrics_prefix}_consul_get_count[1m]))", + "interval": "", + "intervalFactor": 1, + "legendFormat": "GET", + "refId": "A" + }, + { + "expr": "avg(irate(${metrics_prefix}_consul_put_count[1m]))", + "interval": "", + "legendFormat": "PUT", + "refId": "B" + }, + { + "expr": "avg(irate(${metrics_prefix}_consul_delete_count[1m]))", + "interval": "", + "legendFormat": "DELETE", + "refId": "C" + }, + { + "expr": "irate(${metrics_prefix}_consul_list_count{instance=\"$node:$port\"}[1m])", + "interval": "", + "legendFormat": "LIST", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Consul Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:949", + "format": "short", + "label": "Requests per second", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:950", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": "${DS_PROMXY}", + "description": "", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 3, + "x": 0, + "y": 50 + }, + "id": 98, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": ["max"], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.3", + "targets": [ + { + "expr": "max(idelta(${metrics_prefix}_audit_log_response_failure[1m]))", + "format": "time_series", + "interval": "", + "legendFormat": "Request", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Log Response Failures", + "type": "stat" + }, + { + "collapsed": false, + "datasource": "${DS_PROMXY}", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 55 + }, + "id": 18, + "panels": [], + "title": "Policy", + "type": "row" + }, + { + "aliasColors": { + "set": "#629e51" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMXY}", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 56 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg(irate(${metrics_prefix}_policy_set_policy_count[1m]))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "SET", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Policy Set", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1834", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:1835", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "GET": "#1f78c1" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_PROMXY}", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 56 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg(irate(${metrics_prefix}_policy_get_policy_count[1m]))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "GET", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Policy Get", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:2132", + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:2133", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": false, + "schemaVersion": 25, + "style": "dark", + "tags": ["openbao"], + "templating": { + "list": [ + { + "current": {}, + "hide": 0, + "includeAll": false, + "multi": false, + "name": "DS_PROMXY", + "label": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": null, + "current": {}, + "datasource": "${DS_PROMXY}", + "definition": "label_values(up{job=\"openbao-internal\"}, instance)", + "hide": 2, + "includeAll": false, + "label": "Host:", + "multi": false, + "name": "node", + "options": [], + "query": "label_values(up{job=\"openbao-internal\"}, instance)", + "refresh": 1, + "regex": "/([^:]+):.*/", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "${DS_PROMXY}", + "definition": "label_values(up{job=\"openbao-internal\",instance=~\"$node:(.*)\"}, instance)", + "hide": 2, + "includeAll": false, + "label": null, + "multi": false, + "name": "port", + "options": [], + "query": "label_values(up{job=\"openbao-internal\",instance=~\"$node:(.*)\"}, instance)", + "refresh": 1, + "regex": "/[^:]+:(.*)/", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": "", + "current": {}, + "datasource": "${DS_PROMXY}", + "definition": "label_values(${metrics_prefix}_secret_kv_count, mount_point)", + "hide": 0, + "includeAll": true, + "label": "Mount Point:", + "multi": true, + "name": "mountpoint", + "options": [], + "query": "label_values(${metrics_prefix}_secret_kv_count, mount_point)", + "refresh": 2, + "regex": "/(.*)//", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": "", + "datasource": "${DS_PROMXY}", + "hide": 0, + "includeAll": true, + "label": "Metrics Prefix", + "current": { + "text": "vault", + "value": "vault" + }, + "description": "Metrics Prefix defined in the OpenBao configuration with `metrics_prefix`", + "name": "metrics_prefix", + "refresh": 2, + "options": [ + { + "selected": true, + "text": "vault", + "value": "vault" + } + ], + "query": "vault", + "type": "textbox" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] + }, + "timezone": "", + "title": "OpenBao", + "uid": "openbao", + "version": 1 +} diff --git a/packages/system/openbao/charts/openbao/templates/NOTES.txt b/packages/system/openbao/charts/openbao/templates/NOTES.txt new file mode 100644 index 00000000..fce87c26 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/NOTES.txt @@ -0,0 +1,18 @@ + +Thank you for installing OpenBao! + +Now that you have deployed OpenBao, you should look over the docs on using +OpenBao with Kubernetes available here: + +https://openbao.org/docs/ + + +Your release is named {{ .Release.Name }}. To learn more about the release, try: + + $ helm status {{ .Release.Name }} + $ helm get manifest {{ .Release.Name }} + +{{ if and (not .Values.global.tlsDisable) .Values.server.gateway.httpRoute.enabled }} +WARNING: Terminating TLS before reaching the OpenBao Server is not recommended +and may break things like certificate authentication. Prefer usage of `TLSRoute`. +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/_helpers.tpl b/packages/system/openbao/charts/openbao/templates/_helpers.tpl new file mode 100644 index 00000000..3597697b --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/_helpers.tpl @@ -0,0 +1,1212 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to +this (by the DNS naming spec). If release name contains chart name it will +be used as a full name. +*/}} +{{- define "openbao.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "openbao.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Expand the name of the chart. +*/}} +{{- define "openbao.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Allow the release namespace to be overridden +*/}} +{{- define "openbao.namespace" -}} +{{- default .Release.Namespace .Values.global.namespace -}} +{{- end -}} + +{{/* +Compute if the csi driver is enabled. +*/}} +{{- define "openbao.csiEnabled" -}} +{{- $_ := set . "csiEnabled" (or + (eq (.Values.csi.enabled | toString) "true") + (and (eq (.Values.csi.enabled | toString) "-") (eq (.Values.global.enabled | toString) "true"))) -}} +{{- end -}} + +{{/* +Compute if the injector is enabled. +*/}} +{{- define "openbao.injectorEnabled" -}} +{{- $_ := set . "injectorEnabled" (or + (eq (.Values.injector.enabled | toString) "true") + (and (eq (.Values.injector.enabled | toString) "-") (eq (.Values.global.enabled | toString) "true"))) -}} +{{- end -}} + +{{/* +Compute if the server is enabled. +*/}} +{{- define "openbao.serverEnabled" -}} +{{- $_ := set . "serverEnabled" (or + (eq (.Values.server.enabled | toString) "true") + (and (eq (.Values.server.enabled | toString) "-") (eq (.Values.global.enabled | toString) "true"))) -}} +{{- end -}} + +{{/* +Compute if the server serviceaccount is enabled. +*/}} +{{- define "openbao.serverServiceAccountEnabled" -}} +{{- $_ := set . "serverServiceAccountEnabled" + (and + (eq (.Values.server.serviceAccount.create | toString) "true" ) + (or + (eq (.Values.server.enabled | toString) "true") + (eq (.Values.global.enabled | toString) "true"))) -}} +{{- end -}} + +{{/* +Compute if the server serviceaccount should have a token created and mounted to the serviceaccount. +*/}} +{{- define "openbao.serverServiceAccountSecretCreationEnabled" -}} +{{- $_ := set . "serverServiceAccountSecretCreationEnabled" + (and + (eq (.Values.server.serviceAccount.create | toString) "true") + (eq (.Values.server.serviceAccount.createSecret | toString) "true")) -}} +{{- end -}} + + +{{/* +Compute if the server auth delegator serviceaccount is enabled. +*/}} +{{- define "openbao.serverAuthDelegator" -}} +{{- $_ := set . "serverAuthDelegator" + (and + (eq (.Values.server.authDelegator.enabled | toString) "true" ) + (or (eq (.Values.server.serviceAccount.create | toString) "true") + (not (eq .Values.server.serviceAccount.name ""))) + (or + (eq (.Values.server.enabled | toString) "true") + (eq (.Values.global.enabled | toString) "true"))) -}} +{{- end -}} + +{{/* +Compute if the server service is enabled. +*/}} +{{- define "openbao.serverServiceEnabled" -}} +{{- template "openbao.serverEnabled" . -}} +{{- $_ := set . "serverServiceEnabled" (and .serverEnabled (eq (.Values.server.service.enabled | toString) "true")) -}} +{{- end -}} + +{{/* +Compute if the ui is enabled. +*/}} +{{- define "openbao.uiEnabled" -}} +{{- $_ := set . "uiEnabled" (or + (eq (.Values.ui.enabled | toString) "true") + (and (eq (.Values.ui.enabled | toString) "-") (eq (.Values.global.enabled | toString) "true"))) -}} +{{- end -}} + +{{/* +Compute the maximum number of unavailable replicas for the PodDisruptionBudget. +This defaults to (n/2)-1 where n is the number of members of the server cluster. +Add a special case for replicas=1, where it should default to 0 as well. +*/}} +{{- define "openbao.pdb.maxUnavailable" -}} +{{- if eq (int .Values.server.ha.replicas) 1 -}} +{{ 0 }} +{{- else if .Values.server.ha.disruptionBudget.maxUnavailable -}} +{{ .Values.server.ha.disruptionBudget.maxUnavailable -}} +{{- else -}} +{{- div (sub (div (mul (int .Values.server.ha.replicas) 10) 2) 1) 10 -}} +{{- end -}} +{{- end -}} + +{{/* +Resolve the external OpenBao/Vault address by checking global and injector values in order of precedence: +1. global.externalBaoAddr +2. global.externalVaultAddr +*/}} + +{{- define "openbao.externalAddr" -}} + {{- if .Values.global.externalBaoAddr -}} + {{- .Values.global.externalBaoAddr -}} + {{- else -}} + {{- .Values.global.externalVaultAddr -}} + {{- end -}} +{{- end -}} + +{{/* +Set the variable 'mode' to the server mode requested by the user to simplify +template logic. +*/}} +{{- define "openbao.mode" -}} + {{- template "openbao.serverEnabled" . -}} + {{- if or (.Values.injector.externalVaultAddr) (.Values.global.externalVaultAddr) (.Values.global.externalBaoAddr) -}} + {{- $_ := set . "mode" "external" -}} + {{- else if not .serverEnabled -}} + {{- $_ := set . "mode" "external" -}} + {{- else if eq (.Values.server.dev.enabled | toString) "true" -}} + {{- $_ := set . "mode" "dev" -}} + {{- else if eq (.Values.server.ha.enabled | toString) "true" -}} + {{- $_ := set . "mode" "ha" -}} + {{- else if or (eq (.Values.server.standalone.enabled | toString) "true") (eq (.Values.server.standalone.enabled | toString) "-") -}} + {{- $_ := set . "mode" "standalone" -}} + {{- else -}} + {{- $_ := set . "mode" "" -}} + {{- end -}} +{{- end -}} + +{{/* +Set's the replica count based on the different modes configured by user +*/}} +{{- define "openbao.replicas" -}} + {{ if eq .mode "standalone" }} + {{- default 1 -}} + {{ else if eq .mode "ha" }} + {{- if or (kindIs "int64" .Values.server.ha.replicas) (kindIs "float64" .Values.server.ha.replicas) -}} + {{- .Values.server.ha.replicas -}} + {{ else }} + {{- 3 -}} + {{- end -}} + {{ else }} + {{- default 1 -}} + {{ end }} +{{- end -}} + +{{/* +Set's up configmap mounts if this isn't a dev deployment and the user +defined a custom configuration. Additionally iterates over any +extra volumes the user may have specified (such as a secret with TLS). +*/}} +{{- define "openbao.volumes" -}} + {{- if and (ne .mode "dev") (or (.Values.server.standalone.config) (.Values.server.ha.config)) }} + - name: config + configMap: + name: {{ template "openbao.fullname" . }}-config + {{ end }} + {{- range .Values.server.extraVolumes }} + - name: userconfig-{{ .name }} + {{ .type }}: + {{- if (eq .type "configMap") }} + name: {{ .name }} + {{- else if (eq .type "secret") }} + secretName: {{ .name }} + {{- end }} + defaultMode: {{ .defaultMode | default 420 }} + {{- end }} + {{- if .Values.server.volumes }} + {{- toYaml .Values.server.volumes | nindent 8}} + {{- end }} +{{- end -}} + +{{/* +Set's the args for custom command to render the OpenBao configuration +file with IP addresses to make the out of box experience easier +for users looking to use this chart with Consul Helm. +*/}} +{{- define "openbao.args" -}} + {{ if or (eq .mode "standalone") (eq .mode "ha") }} + - | + cp /openbao/config/extraconfig-from-values.hcl /tmp/storageconfig.hcl; + [ -n "${HOST_IP}" ] && sed -Ei "s|HOST_IP|${HOST_IP?}|g" /tmp/storageconfig.hcl; + [ -n "${POD_IP}" ] && sed -Ei "s|POD_IP|${POD_IP?}|g" /tmp/storageconfig.hcl; + [ -n "${HOSTNAME}" ] && sed -Ei "s|HOSTNAME|${HOSTNAME?}|g" /tmp/storageconfig.hcl; + [ -n "${API_ADDR}" ] && sed -Ei "s|API_ADDR|${API_ADDR?}|g" /tmp/storageconfig.hcl; + [ -n "${TRANSIT_ADDR}" ] && sed -Ei "s|TRANSIT_ADDR|${TRANSIT_ADDR?}|g" /tmp/storageconfig.hcl; + [ -n "${RAFT_ADDR}" ] && sed -Ei "s|RAFT_ADDR|${RAFT_ADDR?}|g" /tmp/storageconfig.hcl; + /usr/local/bin/docker-entrypoint.sh bao server -config=/tmp/storageconfig.hcl {{ .Values.server.extraArgs }} + {{ else if eq .mode "dev" }} + - | + /usr/local/bin/docker-entrypoint.sh bao server -dev {{ .Values.server.extraArgs }} + {{ end }} +{{- end -}} + +{{/* +Set's additional environment variables based on the mode. +*/}} +{{- define "openbao.envs" -}} + {{ if eq .mode "dev" }} + - name: VAULT_DEV_ROOT_TOKEN_ID + value: {{ .Values.server.dev.devRootToken }} + - name: VAULT_DEV_LISTEN_ADDRESS + value: "[::]:8200" + {{ end }} +{{- end -}} + +{{/* +Set's which additional volumes should be mounted to the container +based on the mode configured. +*/}} +{{- define "openbao.mounts" -}} + {{ if eq (.Values.server.auditStorage.enabled | toString) "true" }} + - name: audit + mountPath: {{ .Values.server.auditStorage.mountPath }} + {{ end }} + {{ if or (eq .mode "standalone") (and (eq .mode "ha") (eq (.Values.server.ha.raft.enabled | toString) "true")) }} + {{ if eq (.Values.server.dataStorage.enabled | toString) "true" }} + - name: data + mountPath: {{ .Values.server.dataStorage.mountPath }} + {{ end }} + {{ end }} + {{ if and (ne .mode "dev") (or (.Values.server.standalone.config) (.Values.server.ha.config)) }} + - name: config + mountPath: /openbao/config + {{ end }} + {{- range .Values.server.extraVolumes }} + - name: userconfig-{{ .name }} + readOnly: true + mountPath: {{ .path | default "/openbao/userconfig" }}/{{ .name }} + {{- end }} + {{- if .Values.server.volumeMounts }} + {{- toYaml .Values.server.volumeMounts | nindent 12}} + {{- end }} +{{- end -}} + +{{/* +Set's up the volumeClaimTemplates when data or audit storage is required. HA +might not use data storage since Consul is likely it's backend, however, audit +storage might be desired by the user. +*/}} +{{- define "openbao.volumeclaims" -}} + {{- if and (ne .mode "dev") (or .Values.server.dataStorage.enabled .Values.server.auditStorage.enabled) }} + volumeClaimTemplates: + {{- if and (eq (.Values.server.dataStorage.enabled | toString) "true") (or (eq .mode "standalone") (eq (.Values.server.ha.raft.enabled | toString ) "true" )) }} + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: data + {{- include "openbao.dataVolumeClaim.annotations" . | nindent 6 }} + {{- include "openbao.dataVolumeClaim.labels" . | nindent 6 }} + spec: + accessModes: + - {{ .Values.server.dataStorage.accessMode | default "ReadWriteOnce" }} + resources: + requests: + storage: {{ .Values.server.dataStorage.size }} + {{- if .Values.server.dataStorage.storageClass }} + storageClassName: {{ .Values.server.dataStorage.storageClass }} + {{- end }} + {{ end }} + {{- if eq (.Values.server.auditStorage.enabled | toString) "true" }} + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: audit + {{- include "openbao.auditVolumeClaim.annotations" . | nindent 6 }} + {{- include "openbao.auditVolumeClaim.labels" . | nindent 6 }} + spec: + accessModes: + - {{ .Values.server.auditStorage.accessMode | default "ReadWriteOnce" }} + resources: + requests: + storage: {{ .Values.server.auditStorage.size }} + {{- if .Values.server.auditStorage.storageClass }} + storageClassName: {{ .Values.server.auditStorage.storageClass }} + {{- end }} + {{ end }} + {{ end }} +{{- end -}} + +{{/* +Set's the affinity for pod placement when running in standalone and HA modes. +*/}} +{{- define "openbao.affinity" -}} + {{- if and (ne .mode "dev") .Values.server.affinity }} + affinity: + {{ $tp := typeOf .Values.server.affinity }} + {{- if eq $tp "string" }} + {{- tpl .Values.server.affinity . | nindent 8 | trim }} + {{- else }} + {{- toYaml .Values.server.affinity | nindent 8 }} + {{- end }} + {{ end }} +{{- end -}} + +{{/* +Sets the injector affinity for pod placement +*/}} +{{- define "injector.affinity" -}} + {{- if .Values.injector.affinity }} + affinity: + {{ $tp := typeOf .Values.injector.affinity }} + {{- if eq $tp "string" }} + {{- tpl .Values.injector.affinity . | nindent 8 | trim }} + {{- else }} + {{- toYaml .Values.injector.affinity | nindent 8 }} + {{- end }} + {{ end }} +{{- end -}} + +{{/* +Sets the topologySpreadConstraints when running in standalone and HA modes. +*/}} +{{- define "openbao.topologySpreadConstraints" -}} + {{- if and (ne .mode "dev") .Values.server.topologySpreadConstraints }} + topologySpreadConstraints: + {{ $tp := typeOf .Values.server.topologySpreadConstraints }} + {{- if eq $tp "string" }} + {{- tpl .Values.server.topologySpreadConstraints . | nindent 8 | trim }} + {{- else }} + {{- toYaml .Values.server.topologySpreadConstraints | nindent 8 }} + {{- end }} + {{ end }} +{{- end -}} + +{{/* +Sets the injector topologySpreadConstraints for pod placement +*/}} +{{- define "injector.topologySpreadConstraints" -}} + {{- if .Values.injector.topologySpreadConstraints }} + topologySpreadConstraints: + {{ $tp := typeOf .Values.injector.topologySpreadConstraints }} + {{- if eq $tp "string" }} + {{- tpl .Values.injector.topologySpreadConstraints . | nindent 8 | trim }} + {{- else }} + {{- toYaml .Values.injector.topologySpreadConstraints | nindent 8 }} + {{- end }} + {{ end }} +{{- end -}} + +{{/* +Sets the toleration for pod placement when running in standalone and HA modes. +*/}} +{{- define "openbao.tolerations" -}} + {{- if and (ne .mode "dev") .Values.server.tolerations }} + tolerations: + {{- $tp := typeOf .Values.server.tolerations }} + {{- if eq $tp "string" }} + {{ tpl .Values.server.tolerations . | nindent 8 | trim }} + {{- else }} + {{- toYaml .Values.server.tolerations | nindent 8 }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Sets the injector toleration for pod placement +*/}} +{{- define "injector.tolerations" -}} + {{- if .Values.injector.tolerations }} + tolerations: + {{- $tp := typeOf .Values.injector.tolerations }} + {{- if eq $tp "string" }} + {{ tpl .Values.injector.tolerations . | nindent 8 | trim }} + {{- else }} + {{- toYaml .Values.injector.tolerations | nindent 8 }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Set's the node selector for pod placement when running in standalone and HA modes. +*/}} +{{- define "openbao.nodeselector" -}} + {{- if and (ne .mode "dev") .Values.server.nodeSelector }} + nodeSelector: + {{- $tp := typeOf .Values.server.nodeSelector }} + {{- if eq $tp "string" }} + {{ tpl .Values.server.nodeSelector . | nindent 8 | trim }} + {{- else }} + {{- toYaml .Values.server.nodeSelector | nindent 8 }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Sets the injector node selector for pod placement +*/}} +{{- define "injector.nodeselector" -}} + {{- if .Values.injector.nodeSelector }} + nodeSelector: + {{- $tp := typeOf .Values.injector.nodeSelector }} + {{- if eq $tp "string" }} + {{ tpl .Values.injector.nodeSelector . | nindent 8 | trim }} + {{- else }} + {{- toYaml .Values.injector.nodeSelector | nindent 8 }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Sets the injector deployment update strategy +*/}} +{{- define "injector.strategy" -}} + {{- if .Values.injector.strategy }} + strategy: + {{- $tp := typeOf .Values.injector.strategy }} + {{- if eq $tp "string" }} + {{ tpl .Values.injector.strategy . | nindent 4 | trim }} + {{- else }} + {{- toYaml .Values.injector.strategy | nindent 4 }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Renders service annotations from either a string (templated) or a map with indent 4. +Usage: {{ include "openbao.annotations.render.4" (list . ) }} +*/}} +{{- define "openbao.annotations.render.4" -}} + {{- $ctx := index . 0 -}} + {{- $annotations := index . 1 -}} + {{- $annotationsType := typeOf $annotations -}} + {{- if eq $annotationsType "string" -}} + {{- tpl $annotations $ctx | nindent 4 -}} + {{- else -}} + {{- toYaml $annotations | nindent 4 -}} + {{- end -}} +{{- end -}} + +{{/* +Renders service annotations from either a string (templated) or a map with indent 8. +Usage: {{ include "openbao.annotations.render.4" (list . ) }} +*/}} +{{- define "openbao.annotations.render.8" -}} + {{- $ctx := index . 0 -}} + {{- $annotations := index . 1 -}} + {{- $annotationsType := typeOf $annotations -}} + {{- if eq $annotationsType "string" -}} + {{- tpl $annotations $ctx | nindent 8 -}} + {{- else -}} + {{- toYaml $annotations | nindent 8 -}} + {{- end -}} +{{- end -}} + +{{/* +Sets extra pod annotations +*/}} +{{- define "openbao.annotations" }} + {{- if or .Values.server.configAnnotation .Values.server.annotations }} + annotations: + {{- if .Values.server.configAnnotation }} + openbao.hashicorp.com/config-checksum: {{ include "openbao.config" . | sha256sum }} + {{- end }} + {{- $generic := .Values.server.annotations -}} + {{- if $generic }} + {{- include "openbao.annotations.render.8" (list . $generic) -}} + {{- end }} +{{- end -}} +{{- end -}} + +{{/* +Sets extra injector pod annotations +*/}} +{{- define "injector.annotations" -}} + {{- $generic := .Values.injector.annotations -}} + {{- if $generic }} + annotations: + {{- include "openbao.annotations.render.8" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Sets extra injector service annotations +*/}} +{{- define "injector.service.annotations" -}} + {{- $generic := .Values.injector.service.annotations -}} + {{- if $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +securityContext for the injector pod level. +*/}} +{{- define "injector.securityContext.pod" -}} + {{- if .Values.injector.securityContext.pod }} + securityContext: + {{- $tp := typeOf .Values.injector.securityContext.pod }} + {{- if eq $tp "string" }} + {{- tpl .Values.injector.securityContext.pod . | nindent 8 }} + {{- else }} + {{- toYaml .Values.injector.securityContext.pod | nindent 8 }} + {{- end }} + {{- else if not .Values.global.openshift }} + securityContext: + runAsNonRoot: true + runAsGroup: {{ .Values.injector.gid | default 1000 }} + runAsUser: {{ .Values.injector.uid | default 100 }} + fsGroup: {{ .Values.injector.gid | default 1000 }} + {{- end }} +{{- end -}} + +{{/* +securityContext for the injector container level. +*/}} +{{- define "injector.securityContext.container" -}} + {{- if .Values.injector.securityContext.container}} + securityContext: + {{- $tp := typeOf .Values.injector.securityContext.container }} + {{- if eq $tp "string" }} + {{- tpl .Values.injector.securityContext.container . | nindent 12 }} + {{- else }} + {{- toYaml .Values.injector.securityContext.container | nindent 12 }} + {{- end }} + {{- else if not .Values.global.openshift }} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + {{- end }} +{{- end -}} + +{{/* +securityContext for the statefulset pod template. +*/}} +{{- define "server.statefulSet.securityContext.pod" -}} + {{- if .Values.server.statefulSet.securityContext.pod }} + securityContext: + {{- $tp := typeOf .Values.server.statefulSet.securityContext.pod }} + {{- if eq $tp "string" }} + {{- tpl .Values.server.statefulSet.securityContext.pod . | nindent 8 }} + {{- else }} + {{- toYaml .Values.server.statefulSet.securityContext.pod | nindent 8 }} + {{- end }} + {{- else if not .Values.global.openshift }} + securityContext: + runAsNonRoot: true + runAsGroup: {{ .Values.server.gid | default 1000 }} + runAsUser: {{ .Values.server.uid | default 100 }} + fsGroup: {{ .Values.server.gid | default 1000 }} + {{- end }} +{{- end -}} + +{{/* +securityContext for the statefulset openbao container +*/}} +{{- define "server.statefulSet.securityContext.container" -}} + {{- if .Values.server.statefulSet.securityContext.container }} + securityContext: + {{- $tp := typeOf .Values.server.statefulSet.securityContext.container }} + {{- if eq $tp "string" }} + {{- tpl .Values.server.statefulSet.securityContext.container . | nindent 12 }} + {{- else }} + {{- toYaml .Values.server.statefulSet.securityContext.container | nindent 12 }} + {{- end }} + {{- else if not .Values.global.openshift }} + securityContext: + allowPrivilegeEscalation: false + {{- end }} +{{- end -}} + +{{/* +Sets extra injector service account annotations +*/}} +{{- define "injector.serviceAccount.annotations" -}} + {{- $generic := .Values.injector.serviceAccount.annotations -}} + {{- if and (ne .mode "dev") $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Sets extra injector webhook annotations +*/}} +{{- define "injector.webhookAnnotations" -}} + {{- $wa1 := ((.Values.injector.webhook)).annotations -}} + {{- $wa2 := .Values.injector.webhookAnnotations -}} + {{- if or $wa1 $wa2 }} + annotations: + {{- if $wa1 }} + {{- include "openbao.annotations.render.4" (list . $wa1) -}} + {{- end }} + {{- if $wa2 }} + {{- include "openbao.annotations.render.4" (list . $wa2) -}} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Set's the injector webhook objectSelector +*/}} +{{- define "injector.objectSelector" -}} + {{- $v := or (((.Values.injector.webhook)).objectSelector) (.Values.injector.objectSelector) -}} + {{ if $v }} + objectSelector: + {{- $tp := typeOf $v -}} + {{ if eq $tp "string" }} + {{ tpl $v . | indent 6 | trim }} + {{ else }} + {{ toYaml $v | indent 6 | trim }} + {{ end }} + {{ end }} +{{ end }} + +{{/* +Sets extra ui service annotations +*/}} +{{- define "openbao.ui.annotations" -}} + {{- $generic := .Values.ui.annotations -}} + {{- if $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "openbao.serviceAccount.name" -}} +{{- if .Values.server.serviceAccount.create -}} + {{ default (include "openbao.fullname" .) .Values.server.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.server.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Sets extra service account annotations +*/}} +{{- define "openbao.serviceAccount.annotations" -}} + {{- $generic := .Values.server.serviceAccount.annotations -}} + {{- if and (ne .mode "dev") $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Sets extra ingress annotations +*/}} +{{- define "openbao.ingress.annotations" -}} + {{- $generic := .Values.server.ingress.annotations -}} + {{- if $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Sets extra TLSRoute annotations +*/}} +{{- define "openbao.gateway.tlsRoute.annotations" -}} + {{- $generic := .Values.server.gateway.tlsRoute.annotations -}} + {{- if $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Sets extra HTTPRoute annotations +*/}} +{{- define "openbao.gateway.httpRoute.annotations" -}} + {{- $generic := .Values.server.gateway.httpRoute.annotations -}} + {{- if $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Sets extra BackendTLSPolicy annotations +*/}} +{{- define "openbao.gateway.tlsPolicy.annotations" -}} + {{- $generic := .Values.server.gateway.tlsPolicy.annotations -}} + {{- if $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Sets extra route annotations +*/}} +{{- define "openbao.route.annotations" -}} + {{- $generic := .Values.server.route.annotations -}} + {{- if $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Sets extra openbao server Service annotations +*/}} +{{- define "openbao.service.annotations" -}} + {{- $generic := .Values.server.service.annotations -}} + {{- if $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Sets extra openbao server Service (active) annotations +*/}} +{{- define "openbao.service.active.annotations" -}} + {{- $active := .Values.server.service.active.annotations -}} + {{- $generic := .Values.server.service.annotations -}} + {{- if or $active $generic }} + annotations: + {{- if $active }} + {{- include "openbao.annotations.render.4" (list . $active) -}} + {{- end }} + {{- if $generic }} + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Sets extra openbao server Service (standby) annotations +*/}} +{{- define "openbao.service.standby.annotations" -}} + {{- $standby := .Values.server.service.standby.annotations -}} + {{- $generic := .Values.server.service.annotations -}} + {{- if or $standby $generic }} + annotations: + {{- if $standby }} + {{- include "openbao.annotations.render.4" (list . $standby) -}} + {{- end }} + {{- if $generic }} + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Sets PodSecurityPolicy annotations +*/}} +{{- define "openbao.psp.annotations" -}} + {{- $generic := .Values.global.psp.annotations -}} + {{- if $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Sets extra statefulset annotations +*/}} +{{- define "openbao.statefulSet.annotations" -}} + {{- $generic := .Values.server.statefulSet.annotations -}} + {{- if $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Sets VolumeClaim annotations for data volume +*/}} +{{- define "openbao.dataVolumeClaim.annotations" -}} + {{- $generic := .Values.server.dataStorage.annotations -}} + {{- if and (ne .mode "dev") (.Values.server.dataStorage.enabled) $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Sets VolumeClaim labels for data volume +*/}} +{{- define "openbao.dataVolumeClaim.labels" -}} + {{- if and (ne .mode "dev") (.Values.server.dataStorage.enabled) (.Values.server.dataStorage.labels) }} + labels: + {{- $tp := typeOf .Values.server.dataStorage.labels }} + {{- if eq $tp "string" }} + {{- tpl .Values.server.dataStorage.labels . | nindent 4 }} + {{- else }} + {{- toYaml .Values.server.dataStorage.labels | nindent 4 }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Sets VolumeClaim annotations for audit volume +*/}} +{{- define "openbao.auditVolumeClaim.annotations" -}} + {{- $generic := .Values.server.auditStorage.annotations -}} + {{- if and (ne .mode "dev") (.Values.server.auditStorage.enabled) $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Sets VolumeClaim labels for audit volume +*/}} +{{- define "openbao.auditVolumeClaim.labels" -}} + {{- if and (ne .mode "dev") (.Values.server.auditStorage.enabled) (.Values.server.auditStorage.labels) }} + labels: + {{- $tp := typeOf .Values.server.auditStorage.labels }} + {{- if eq $tp "string" }} + {{- tpl .Values.server.auditStorage.labels . | nindent 4 }} + {{- else }} + {{- toYaml .Values.server.auditStorage.labels | nindent 4 }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Set's the container resources if the user has set any. +*/}} +{{- define "openbao.resources" -}} + {{- if .Values.server.resources -}} + resources: +{{ toYaml .Values.server.resources | indent 12}} + {{ end }} +{{- end -}} + +{{/* +Sets the container resources if the user has set any. +*/}} +{{- define "injector.resources" -}} + {{- if .Values.injector.resources -}} + resources: +{{ toYaml .Values.injector.resources | indent 12}} + {{ end }} +{{- end -}} + +{{/* +Sets the container resources if the user has set any. +*/}} +{{- define "csi.resources" -}} + {{- if .Values.csi.resources -}} + resources: +{{ toYaml .Values.csi.resources | indent 12}} + {{ end }} +{{- end -}} + +{{/* +Sets the container resources for CSI's Agent sidecar if the user has set any. +*/}} +{{- define "csi.agent.resources" -}} + {{- if .Values.csi.agent.resources -}} + resources: +{{ toYaml .Values.csi.agent.resources | indent 12}} + {{ end }} +{{- end -}} + +{{/* +Set's the container resources for the SnapshotAgent if the user has set any. +*/}} +{{- define "openbao.snapshotAgent.resources" -}} + {{- if .Values.snapshotAgent.resources -}} + resources: +{{ toYaml .Values.snapshotAgent.resources | indent 14}} + {{ end }} +{{- end -}} + +{{/* +Sets extra CSI daemonset annotations +*/}} +{{- define "csi.daemonSet.annotations" -}} + {{- $generic := .Values.csi.daemonSet.annotations -}} + {{- if $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Sets CSI daemonset securityContext for pod template +*/}} +{{- define "csi.daemonSet.securityContext.pod" -}} + {{- if .Values.csi.daemonSet.securityContext.pod }} + securityContext: + {{- $tp := typeOf .Values.csi.daemonSet.securityContext.pod }} + {{- if eq $tp "string" }} + {{- tpl .Values.csi.daemonSet.securityContext.pod . | nindent 8 }} + {{- else }} + {{- toYaml .Values.csi.daemonSet.securityContext.pod | nindent 8 }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Sets CSI daemonset securityContext for container +*/}} +{{- define "csi.daemonSet.securityContext.container" -}} + {{- if .Values.csi.daemonSet.securityContext.container }} + securityContext: + {{- $tp := typeOf .Values.csi.daemonSet.securityContext.container }} + {{- if eq $tp "string" }} + {{- tpl .Values.csi.daemonSet.securityContext.container . | nindent 12 }} + {{- else }} + {{- toYaml .Values.csi.daemonSet.securityContext.container | nindent 12 }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Sets the injector toleration for pod placement +*/}} +{{- define "csi.pod.tolerations" -}} + {{- if .Values.csi.pod.tolerations }} + tolerations: + {{- $tp := typeOf .Values.csi.pod.tolerations }} + {{- if eq $tp "string" }} + {{ tpl .Values.csi.pod.tolerations . | nindent 8 | trim }} + {{- else }} + {{- toYaml .Values.csi.pod.tolerations | nindent 8 }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Sets the CSI provider nodeSelector for pod placement +*/}} +{{- define "csi.pod.nodeselector" -}} + {{- if .Values.csi.pod.nodeSelector }} + nodeSelector: + {{- $tp := typeOf .Values.csi.pod.nodeSelector }} + {{- if eq $tp "string" }} + {{ tpl .Values.csi.pod.nodeSelector . | nindent 8 | trim }} + {{- else }} + {{- toYaml .Values.csi.pod.nodeSelector | nindent 8 }} + {{- end }} + {{- end }} +{{- end -}} +{{/* +Sets the CSI provider affinity for pod placement. +*/}} +{{- define "csi.pod.affinity" -}} + {{- if .Values.csi.pod.affinity }} + affinity: + {{ $tp := typeOf .Values.csi.pod.affinity }} + {{- if eq $tp "string" }} + {{- tpl .Values.csi.pod.affinity . | nindent 8 | trim }} + {{- else }} + {{- toYaml .Values.csi.pod.affinity | nindent 8 }} + {{- end }} + {{ end }} +{{- end -}} +{{/* +Sets extra CSI provider pod annotations +*/}} +{{- define "csi.pod.annotations" -}} + {{- $generic := .Values.csi.pod.annotations -}} + {{- if $generic }} + annotations: + {{- include "openbao.annotations.render.8" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Sets extra CSI service account annotations +*/}} +{{- define "csi.serviceAccount.annotations" -}} + {{- $generic := .Values.csi.serviceAccount.annotations -}} + {{- if $generic }} + annotations: + {{- include "openbao.annotations.render.4" (list . $generic) -}} + {{- end }} +{{- end -}} + +{{/* +Inject extra environment vars in the format key:value, if populated +*/}} +{{- define "openbao.extraEnvironmentVars" -}} +{{- if .extraEnvironmentVars -}} +{{- range $key, $value := .extraEnvironmentVars }} +- name: {{ printf "%s" $key | replace "." "_" | upper | quote }} + value: {{ $value | quote }} +{{- end }} +{{- end -}} +{{- end -}} + +{{/* +Inject extra environment populated by secrets, if populated +*/}} +{{- define "openbao.extraSecretEnvironmentVars" -}} +{{- if .extraSecretEnvironmentVars -}} +{{- range .extraSecretEnvironmentVars }} +- name: {{ .envName }} + valueFrom: + secretKeyRef: + name: {{ .secretName }} + key: {{ .secretKey }} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* Scheme for health check and local endpoint */}} +{{- define "openbao.scheme" -}} +{{- if .Values.global.tlsDisable -}} +{{ "http" }} +{{- else -}} +{{ "https" }} +{{- end -}} +{{- end -}} + +{{/* +imagePullSecrets generates pull secrets from either string or map values. +A map value must be indexable by the key 'name'. +*/}} +{{- define "imagePullSecrets" -}} +{{- with .Values.global.imagePullSecrets -}} +imagePullSecrets: +{{- range . -}} +{{- if typeIs "string" . }} + - name: {{ . }} +{{- else if index . "name" }} + - name: {{ .name }} +{{- end }} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +externalTrafficPolicy sets a Service's externalTrafficPolicy if applicable. +Supported inputs are Values.server.service and Values.ui +*/}} +{{- define "service.externalTrafficPolicy" -}} +{{- $type := "" -}} +{{- if .serviceType -}} +{{- $type = .serviceType -}} +{{- else if .type -}} +{{- $type = .type -}} +{{- end -}} +{{- if and .externalTrafficPolicy (or (eq $type "LoadBalancer") (eq $type "NodePort")) }} + externalTrafficPolicy: {{ .externalTrafficPolicy }} +{{- else }} +{{- end }} +{{- end -}} + +{{/* +loadBalancer configuration for the the UI service. +Supported inputs are Values.ui +*/}} +{{- define "service.loadBalancer" -}} +{{- if eq (.serviceType | toString) "LoadBalancer" }} +{{- if .loadBalancerIP }} + loadBalancerIP: {{ .loadBalancerIP }} +{{- end }} +{{- with .loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{- range . }} + - {{ . }} +{{- end }} +{{- end -}} +{{- end }} +{{- end -}} + +{{/* +config file from values +*/}} +{{- define "openbao.config" -}} + {{- if or (eq .mode "ha") (eq .mode "standalone") }} + {{- $type := typeOf (index .Values.server .mode).config }} + {{- if eq $type "string" }} + {{- if eq .mode "standalone" }} + {{ tpl .Values.server.standalone.config . | nindent 4 | trim }} + {{- else if and (eq .mode "ha") (eq (.Values.server.ha.raft.enabled | toString) "false") }} + {{ tpl .Values.server.ha.config . | nindent 4 | trim }} + {{- else if and (eq .mode "ha") (eq (.Values.server.ha.raft.enabled | toString) "true") }} + {{ tpl .Values.server.ha.raft.config . | nindent 4 | trim }} + {{ end }} + {{- else }} + {{- if and (eq .mode "ha") (eq (.Values.server.ha.raft.enabled | toString) "true") }} +{{ (index .Values.server .mode).raft.config | toPrettyJson | indent 4 }} + {{- else }} +{{ (index .Values.server .mode).config | toPrettyJson | indent 4 }} + {{- end }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Create the name of the service account to use for the snasphot-agent +*/}} +{{- define "openbao.snapshotAgent.serviceAccount.name" -}} +{{- if .Values.snapshotAgent.serviceAccount.create -}} + {{ default (printf "%s-%s" (include "openbao.fullname" .) "snapshot") .Values.snapshotAgent.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.snapshotAgent.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Sets extra service account annotations for the snapshot-agent +*/}} +{{- define "openbao.snapshotAgent.serviceAccount.annotations" -}} + {{- if and (ne .mode "dev") .Values.snapshotAgent.serviceAccount.annotations }} + annotations: + {{- $tp := typeOf .Values.snapshotAgent.serviceAccount.annotations }} + {{- if eq $tp "string" }} + {{- tpl .Values.snapshotAgent.serviceAccount.annotations . | nindent 4 }} + {{- else }} + {{- toYaml .Values.snapshotAgent.serviceAccount.annotations | nindent 4 }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +Sets extra snapshotAgent job annotations +*/}} +{{- define "openbao.snapshotAgent.annotations" -}} + {{- if .Values.snapshotAgent.annotations }} + annotations: + {{- $tp := typeOf .Values.snapshotAgent.annotations }} + {{- if eq $tp "string" }} + {{- tpl .Values.snapshotAgent.annotations . | nindent 4 }} + {{- else }} + {{- toYaml .Values.snapshotAgent.annotations | nindent 4 }} + {{- end }} + {{- end }} +{{- end -}} + +{{/* +securityContext for the snapshotAgent pod level. +*/}} +{{- define "snapshotAgent.securityContext.pod" -}} + {{- if .Values.snapshotAgent.securityContext.pod }} + securityContext: + {{- $tp := typeOf .Values.snapshotAgent.securityContext.pod }} + {{- if eq $tp "string" }} + {{- tpl .Values.snapshotAgent.securityContext.pod . | nindent 12 }} + {{- else }} + {{- toYaml .Values.snapshotAgent.securityContext.pod | nindent 12 }} + {{- end }} + {{- else if not .Values.global.openshift }} + securityContext: + runAsNonRoot: true + runAsGroup: {{ .Values.snapshotAgent.gid | default 1000 }} + runAsUser: {{ .Values.snapshotAgent.uid | default 100 }} + fsGroup: {{ .Values.snapshotAgent.gid | default 1000 }} + {{- end }} +{{- end -}} + +{{/* +securityContext for the snapshotAgent container level. +*/}} +{{- define "snapshotAgent.securityContext.container" -}} + {{- if .Values.snapshotAgent.securityContext.container }} + securityContext: + {{- $tp := typeOf .Values.snapshotAgent.securityContext.container }} + {{- if eq $tp "string" }} + {{- tpl .Values.snapshotAgent.securityContext.container . | nindent 14 }} + {{- else }} + {{- toYaml .Values.snapshotAgent.securityContext.container | nindent 14 }} + {{- end }} + {{- else if not .Values.global.openshift }} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + {{- end }} +{{- end -}} diff --git a/packages/system/openbao/charts/openbao/templates/csi-agent-configmap.yaml b/packages/system/openbao/charts/openbao/templates/csi-agent-configmap.yaml new file mode 100644 index 00000000..cf9dded9 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/csi-agent-configmap.yaml @@ -0,0 +1,34 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.csiEnabled" . -}} +{{- if and (.csiEnabled) (eq (.Values.csi.agent.enabled | toString) "true") -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "openbao.fullname" . }}-csi-provider-agent-config + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }}-csi-provider + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +data: + config.hcl: | + vault { + {{- if include "openbao.externalAddr" . }} + "address" = "{{ include "openbao.externalAddr" . }}" + {{- else }} + "address" = "{{ include "openbao.scheme" . }}://{{ template "openbao.fullname" . }}.{{ include "openbao.namespace" . }}.svc:{{ .Values.server.service.port }}" + {{- end }} + } + + cache {} + + listener "unix" { + address = "/var/run/vault/agent.sock" + tls_disable = true + } +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/csi-clusterrole.yaml b/packages/system/openbao/charts/openbao/templates/csi-clusterrole.yaml new file mode 100644 index 00000000..a3fbb612 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/csi-clusterrole.yaml @@ -0,0 +1,23 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.csiEnabled" . -}} +{{- if .csiEnabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "openbao.fullname" . }}-csi-provider-clusterrole + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-csi-provider + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +rules: +- apiGroups: + - "" + resources: + - serviceaccounts/token + verbs: + - create +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/csi-clusterrolebinding.yaml b/packages/system/openbao/charts/openbao/templates/csi-clusterrolebinding.yaml new file mode 100644 index 00000000..3c7847af --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/csi-clusterrolebinding.yaml @@ -0,0 +1,24 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.csiEnabled" . -}} +{{- if .csiEnabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "openbao.fullname" . }}-csi-provider-clusterrolebinding + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-csi-provider + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "openbao.fullname" . }}-csi-provider-clusterrole +subjects: +- kind: ServiceAccount + name: {{ template "openbao.fullname" . }}-csi-provider + namespace: {{ include "openbao.namespace" . }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/csi-daemonset.yaml b/packages/system/openbao/charts/openbao/templates/csi-daemonset.yaml new file mode 100644 index 00000000..73168ed0 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/csi-daemonset.yaml @@ -0,0 +1,157 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.csiEnabled" . -}} +{{- if .csiEnabled -}} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ template "openbao.fullname" . }}-csi-provider + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-csi-provider + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- if .Values.csi.daemonSet.extraLabels -}} + {{- toYaml .Values.csi.daemonSet.extraLabels | nindent 4 -}} + {{- end -}} + {{ template "csi.daemonSet.annotations" . }} +spec: + updateStrategy: + type: {{ .Values.csi.daemonSet.updateStrategy.type }} + {{- if .Values.csi.daemonSet.updateStrategy.maxUnavailable }} + rollingUpdate: + maxUnavailable: {{ .Values.csi.daemonSet.updateStrategy.maxUnavailable }} + {{- end }} + selector: + matchLabels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-csi-provider + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "openbao.name" . }}-csi-provider + app.kubernetes.io/instance: {{ .Release.Name }} + {{- if .Values.csi.pod.extraLabels -}} + {{- toYaml .Values.csi.pod.extraLabels | nindent 8 -}} + {{- end -}} + {{ template "csi.pod.annotations" . }} + spec: + {{ template "csi.daemonSet.securityContext.pod" . }} + {{- if .Values.csi.priorityClassName }} + priorityClassName: {{ .Values.csi.priorityClassName }} + {{- end }} + serviceAccountName: {{ template "openbao.fullname" . }}-csi-provider + {{- template "csi.pod.tolerations" . }} + {{- template "csi.pod.nodeselector" . }} + {{- template "csi.pod.affinity" . }} + containers: + - name: {{ include "openbao.name" . }}-csi-provider + {{ template "csi.resources" . }} + {{ template "csi.daemonSet.securityContext.container" . }} + image: "{{ .Values.csi.image.registry | default "docker.io" }}/{{ .Values.csi.image.repository }}:{{ .Values.csi.image.tag }}" + imagePullPolicy: {{ .Values.csi.image.pullPolicy }} + args: + - --endpoint={{ .Values.csi.daemonSet.endpoint }} + - --debug={{ .Values.csi.debug }} + {{- if .Values.csi.hmacSecretName }} + - --hmac-secret-name={{ .Values.csi.hmacSecretName }} + {{- else }} + - --hmac-secret-name={{- include "openbao.name" . }}-csi-provider-hmac-key + {{- end }} + {{- if .Values.csi.extraArgs }} + {{- toYaml .Values.csi.extraArgs | nindent 12 }} + {{- end }} + env: + - name: VAULT_ADDR + {{- if eq (.Values.csi.agent.enabled | toString) "true" }} + value: "unix:///var/run/vault/agent.sock" + {{- else if include "openbao.externalAddr" . }} + value: "{{ include "openbao.externalAddr" . }}" + {{- else }} + value: {{ include "openbao.scheme" . }}://{{ template "openbao.fullname" . }}.{{ include "openbao.namespace" . }}.svc:{{ .Values.server.service.port }} + {{- end }} + volumeMounts: + - name: providervol + mountPath: "/provider" + {{- if eq (.Values.csi.agent.enabled | toString) "true" }} + - name: agent-unix-socket + mountPath: /var/run/vault + {{- end }} + {{- if .Values.csi.volumeMounts }} + {{- toYaml .Values.csi.volumeMounts | nindent 12}} + {{- end }} + livenessProbe: + httpGet: + path: /health/ready + port: 8080 + failureThreshold: {{ .Values.csi.livenessProbe.failureThreshold }} + initialDelaySeconds: {{ .Values.csi.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.csi.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.csi.livenessProbe.successThreshold }} + timeoutSeconds: {{ .Values.csi.livenessProbe.timeoutSeconds }} + readinessProbe: + httpGet: + path: /health/ready + port: 8080 + failureThreshold: {{ .Values.csi.readinessProbe.failureThreshold }} + initialDelaySeconds: {{ .Values.csi.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.csi.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.csi.readinessProbe.successThreshold }} + timeoutSeconds: {{ .Values.csi.readinessProbe.timeoutSeconds }} + {{- if eq (.Values.csi.agent.enabled | toString) "true" }} + - name: {{ include "openbao.name" . }}-agent + image: "{{ .Values.csi.agent.image.registry | default "docker.io" }}/{{ .Values.csi.agent.image.repository }}:{{ .Values.csi.agent.image.tag | default (trimPrefix "v" .Chart.AppVersion) }}" + imagePullPolicy: {{ .Values.csi.agent.image.pullPolicy }} + {{ template "csi.agent.resources" . }} + command: + - bao + args: + - agent + - -config=/etc/vault/config.hcl + {{- if .Values.csi.agent.extraArgs }} + {{- toYaml .Values.csi.agent.extraArgs | nindent 12 }} + {{- end }} + ports: + - containerPort: 8200 + env: + - name: BAO_LOG_LEVEL + value: "{{ .Values.csi.agent.logLevel }}" + - name: BAO_LOG_FORMAT + value: "{{ .Values.csi.agent.logFormat }}" + securityContext: + runAsNonRoot: true + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsUser: 100 + runAsGroup: 1000 + volumeMounts: + - name: agent-config + mountPath: /etc/vault/config.hcl + subPath: config.hcl + readOnly: true + - name: agent-unix-socket + mountPath: /var/run/vault + {{- if .Values.csi.volumeMounts }} + {{- toYaml .Values.csi.volumeMounts | nindent 12 }} + {{- end }} + {{- end }} + volumes: + - name: providervol + hostPath: + path: {{ .Values.csi.daemonSet.providersDir }} + {{- if eq (.Values.csi.agent.enabled | toString) "true" }} + - name: agent-config + configMap: + name: {{ template "openbao.fullname" . }}-csi-provider-agent-config + - name: agent-unix-socket + emptyDir: + medium: Memory + {{- end }} + {{- if .Values.csi.volumes }} + {{- toYaml .Values.csi.volumes | nindent 8}} + {{- end }} + {{- include "imagePullSecrets" . | nindent 6 }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/csi-role.yaml b/packages/system/openbao/charts/openbao/templates/csi-role.yaml new file mode 100644 index 00000000..a7554a65 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/csi-role.yaml @@ -0,0 +1,32 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.csiEnabled" . -}} +{{- if .csiEnabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "openbao.fullname" . }}-csi-provider-role + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-csi-provider + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get"] + resourceNames: + {{- if .Values.csi.hmacSecretName }} + - {{ .Values.csi.hmacSecretName }} + {{- else }} + - {{ include "openbao.name" . }}-csi-provider-hmac-key + {{- end }} +# 'create' permissions cannot be restricted by resource name: +# https://kubernetes.io/docs/reference/access-authn-authz/rbac/#referring-to-resources +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create"] +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/csi-rolebinding.yaml b/packages/system/openbao/charts/openbao/templates/csi-rolebinding.yaml new file mode 100644 index 00000000..c46096e1 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/csi-rolebinding.yaml @@ -0,0 +1,25 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.csiEnabled" . -}} +{{- if .csiEnabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "openbao.fullname" . }}-csi-provider-rolebinding + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-csi-provider + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "openbao.fullname" . }}-csi-provider-role +subjects: +- kind: ServiceAccount + name: {{ template "openbao.fullname" . }}-csi-provider + namespace: {{ include "openbao.namespace" . }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/csi-serviceaccount.yaml b/packages/system/openbao/charts/openbao/templates/csi-serviceaccount.yaml new file mode 100644 index 00000000..2f5d346b --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/csi-serviceaccount.yaml @@ -0,0 +1,21 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.csiEnabled" . -}} +{{- if .csiEnabled -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "openbao.fullname" . }}-csi-provider + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-csi-provider + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- if .Values.csi.serviceAccount.extraLabels -}} + {{- toYaml .Values.csi.serviceAccount.extraLabels | nindent 4 -}} + {{- end -}} + {{ template "csi.serviceAccount.annotations" . }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/extra-objects.yaml b/packages/system/openbao/charts/openbao/templates/extra-objects.yaml new file mode 100644 index 00000000..b408fb07 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/extra-objects.yaml @@ -0,0 +1,8 @@ +{{- range .Values.extraObjects }} +--- +{{- if typeIs "string" . }} +{{ tpl . $ }} +{{- else }} +{{ tpl (. | toYaml) $ }} +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/grafana/configmap-dashboard.yaml b/packages/system/openbao/charts/openbao/templates/grafana/configmap-dashboard.yaml new file mode 100644 index 00000000..970369f0 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/grafana/configmap-dashboard.yaml @@ -0,0 +1,30 @@ +{{- if .Values.serverTelemetry.grafanaDashboard.enabled }} +{{- $files := .Files.Glob "grafana/dashboards/*.json" }} +{{- if $files }} +{{- range $path, $fileContents := $files }} +{{- $dashboardName := regexReplaceAll "(^.*/)(.*)\\.json$" $path "${2}" }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s-%s" (include "openbao.fullname" $) $dashboardName | trunc 63 | trimSuffix "-" }} + namespace: {{ include "openbao.namespace" $ }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" $ }}-grafana-dashboard + app.kubernetes.io/instance: {{ $.Release.Name }} + app.kubernetes.io/managed-by: {{ $.Release.Service }} + {{- if $.Values.serverTelemetry.grafanaDashboard.defaultLabel }} + grafana_dashboard: "1" + {{- end }} + {{- if $.Values.serverTelemetry.grafanaDashboard.extraLabels }} + {{- $.Values.serverTelemetry.grafanaDashboard.extraLabels | toYaml | nindent 4 }} + {{- end }} + {{- if $.Values.serverTelemetry.grafanaDashboard.extraAnnotations }} + annotations: + {{- $.Values.serverTelemetry.grafanaDashboard.extraAnnotations | toYaml | nindent 4 }} + {{- end }} +data: + {{ $dashboardName }}.json: {{ $.Files.Get $path | toJson }} +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/injector-certs-secret.yaml b/packages/system/openbao/charts/openbao/templates/injector-certs-secret.yaml new file mode 100644 index 00000000..b5de48bf --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/injector-certs-secret.yaml @@ -0,0 +1,19 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.injectorEnabled" . -}} +{{- if .injectorEnabled -}} +{{- if and (eq (.Values.injector.leaderElector.enabled | toString) "true") (gt (.Values.injector.replicas | int) 1) }} +apiVersion: v1 +kind: Secret +metadata: + name: openbao-injector-certs + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/injector-clusterrole.yaml b/packages/system/openbao/charts/openbao/templates/injector-clusterrole.yaml new file mode 100644 index 00000000..10ea35c1 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/injector-clusterrole.yaml @@ -0,0 +1,30 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.injectorEnabled" . -}} +{{- if .injectorEnabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "openbao.fullname" . }}-agent-injector-clusterrole + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +rules: +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["mutatingwebhookconfigurations"] + verbs: + - "get" + - "list" + - "watch" + - "patch" +{{- if and (eq (.Values.injector.leaderElector.enabled | toString) "true") (gt (.Values.injector.replicas | int) 1) }} +- apiGroups: [""] + resources: ["nodes"] + verbs: + - "get" +{{ end }} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/injector-clusterrolebinding.yaml b/packages/system/openbao/charts/openbao/templates/injector-clusterrolebinding.yaml new file mode 100644 index 00000000..353ee8ac --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/injector-clusterrolebinding.yaml @@ -0,0 +1,24 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.injectorEnabled" . -}} +{{- if .injectorEnabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "openbao.fullname" . }}-agent-injector-binding + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "openbao.fullname" . }}-agent-injector-clusterrole +subjects: +- kind: ServiceAccount + name: {{ template "openbao.fullname" . }}-agent-injector + namespace: {{ include "openbao.namespace" . }} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/injector-deployment.yaml b/packages/system/openbao/charts/openbao/templates/injector-deployment.yaml new file mode 100644 index 00000000..ac0fc915 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/injector-deployment.yaml @@ -0,0 +1,179 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.injectorEnabled" . -}} +{{- if .injectorEnabled -}} +# Deployment for the injector +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "openbao.fullname" . }}-agent-injector + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + component: webhook +spec: + replicas: {{ .Values.injector.replicas }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} + component: webhook + {{ template "injector.strategy" . }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} + component: webhook + {{- if .Values.injector.extraLabels -}} + {{- toYaml .Values.injector.extraLabels | nindent 8 -}} + {{- end -}} + {{ template "injector.annotations" . }} + spec: + {{ template "injector.affinity" . }} + {{ template "injector.topologySpreadConstraints" . }} + {{ template "injector.tolerations" . }} + {{ template "injector.nodeselector" . }} + {{- if .Values.injector.priorityClassName }} + priorityClassName: {{ .Values.injector.priorityClassName }} + {{- end }} + serviceAccountName: "{{ template "openbao.fullname" . }}-agent-injector" + {{ template "injector.securityContext.pod" . -}} + {{- if not .Values.global.openshift }} + hostNetwork: {{ .Values.injector.hostNetwork }} + {{- end }} + containers: + - name: sidecar-injector + {{ template "injector.resources" . }} + image: "{{ .Values.injector.image.registry | default "docker.io" }}/{{ .Values.injector.image.repository }}:{{ .Values.injector.image.tag }}" + imagePullPolicy: "{{ .Values.injector.image.pullPolicy }}" + {{- template "injector.securityContext.container" . }} + env: + - name: AGENT_INJECT_LISTEN + value: {{ printf ":%v" .Values.injector.port }} + - name: AGENT_INJECT_LOG_LEVEL + value: {{ .Values.injector.logLevel | default "info" }} + - name: AGENT_INJECT_VAULT_ADDR + {{- if include "openbao.externalAddr" . }} + value: "{{ include "openbao.externalAddr" . }}" + {{- else if .Values.injector.externalVaultAddr }} + value: "{{ .Values.injector.externalVaultAddr }}" + {{- else }} + value: {{ include "openbao.scheme" . }}://{{ template "openbao.fullname" . }}.{{ include "openbao.namespace" . }}.svc:{{ .Values.server.service.port }} + {{- end }} + - name: AGENT_INJECT_VAULT_AUTH_PATH + value: {{ .Values.injector.authPath }} + - name: AGENT_INJECT_VAULT_IMAGE + value: "{{ .Values.injector.agentImage.registry | default "quay.io" }}/{{ .Values.injector.agentImage.repository }}:{{ .Values.injector.agentImage.tag | default (trimPrefix "v" .Chart.AppVersion) }}" + {{- if .Values.injector.certs.secretName }} + - name: AGENT_INJECT_TLS_CERT_FILE + value: "/etc/webhook/certs/{{ .Values.injector.certs.certName }}" + - name: AGENT_INJECT_TLS_KEY_FILE + value: "/etc/webhook/certs/{{ .Values.injector.certs.keyName }}" + {{- else }} + - name: AGENT_INJECT_TLS_AUTO + value: {{ template "openbao.fullname" . }}-agent-injector-cfg + - name: AGENT_INJECT_TLS_AUTO_HOSTS + value: {{ template "openbao.fullname" . }}-agent-injector-svc,{{ template "openbao.fullname" . }}-agent-injector-svc.{{ include "openbao.namespace" . }},{{ template "openbao.fullname" . }}-agent-injector-svc.{{ include "openbao.namespace" . }}.svc + {{- end }} + - name: AGENT_INJECT_LOG_FORMAT + value: {{ .Values.injector.logFormat | default "standard" }} + - name: AGENT_INJECT_REVOKE_ON_SHUTDOWN + value: "{{ .Values.injector.revokeOnShutdown | default false }}" + {{- if .Values.global.openshift }} + - name: AGENT_INJECT_SET_SECURITY_CONTEXT + value: "false" + {{- end }} + {{- if .Values.injector.metrics.enabled }} + - name: AGENT_INJECT_TELEMETRY_PATH + value: "/metrics" + {{- end }} + {{- if and (eq (.Values.injector.leaderElector.enabled | toString) "true") (gt (.Values.injector.replicas | int) 1) }} + - name: AGENT_INJECT_USE_LEADER_ELECTOR + value: "true" + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- end }} + - name: AGENT_INJECT_CPU_REQUEST + value: "{{ .Values.injector.agentDefaults.cpuRequest }}" + - name: AGENT_INJECT_CPU_LIMIT + value: "{{ .Values.injector.agentDefaults.cpuLimit }}" + - name: AGENT_INJECT_MEM_REQUEST + value: "{{ .Values.injector.agentDefaults.memRequest }}" + - name: AGENT_INJECT_MEM_LIMIT + value: "{{ .Values.injector.agentDefaults.memLimit }}" + {{- if .Values.injector.agentDefaults.ephemeralRequest }} + - name: AGENT_INJECT_EPHEMERAL_REQUEST + value: "{{ .Values.injector.agentDefaults.ephemeralRequest }}" + {{- end }} + {{- if .Values.injector.agentDefaults.ephemeralLimit }} + - name: AGENT_INJECT_EPHEMERAL_LIMIT + value: "{{ .Values.injector.agentDefaults.ephemeralLimit }}" + {{- end }} + - name: AGENT_INJECT_DEFAULT_TEMPLATE + value: "{{ .Values.injector.agentDefaults.template }}" + - name: AGENT_INJECT_TEMPLATE_CONFIG_EXIT_ON_RETRY_FAILURE + value: "{{ .Values.injector.agentDefaults.templateConfig.exitOnRetryFailure }}" + {{- if .Values.injector.agentDefaults.templateConfig.staticSecretRenderInterval }} + - name: AGENT_INJECT_TEMPLATE_STATIC_SECRET_RENDER_INTERVAL + value: "{{ .Values.injector.agentDefaults.templateConfig.staticSecretRenderInterval }}" + {{- end }} + {{- include "openbao.extraEnvironmentVars" .Values.injector | nindent 12 }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + args: + - agent-inject + - 2>&1 + livenessProbe: + httpGet: + path: /health/ready + port: {{ .Values.injector.port }} + scheme: HTTPS + failureThreshold: {{ .Values.injector.livenessProbe.failureThreshold }} + initialDelaySeconds: {{ .Values.injector.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.injector.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.injector.livenessProbe.successThreshold }} + timeoutSeconds: {{ .Values.injector.livenessProbe.timeoutSeconds }} + readinessProbe: + httpGet: + path: /health/ready + port: {{ .Values.injector.port }} + scheme: HTTPS + failureThreshold: {{ .Values.injector.readinessProbe.failureThreshold }} + initialDelaySeconds: {{ .Values.injector.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.injector.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.injector.readinessProbe.successThreshold }} + timeoutSeconds: {{ .Values.injector.readinessProbe.timeoutSeconds }} + startupProbe: + httpGet: + path: /health/ready + port: {{ .Values.injector.port }} + scheme: HTTPS + failureThreshold: {{ .Values.injector.startupProbe.failureThreshold }} + initialDelaySeconds: {{ .Values.injector.startupProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.injector.startupProbe.periodSeconds }} + successThreshold: {{ .Values.injector.startupProbe.successThreshold }} + timeoutSeconds: {{ .Values.injector.startupProbe.timeoutSeconds }} +{{- if .Values.injector.certs.secretName }} + volumeMounts: + - name: webhook-certs + mountPath: /etc/webhook/certs + readOnly: true +{{- end }} +{{- if .Values.injector.certs.secretName }} + volumes: + - name: webhook-certs + secret: + secretName: "{{ .Values.injector.certs.secretName }}" +{{- end }} + {{- include "imagePullSecrets" . | nindent 6 }} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/injector-disruptionbudget.yaml b/packages/system/openbao/charts/openbao/templates/injector-disruptionbudget.yaml new file mode 100644 index 00000000..08749bd2 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/injector-disruptionbudget.yaml @@ -0,0 +1,25 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- if .Values.injector.podDisruptionBudget }} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ template "openbao.fullname" . }}-agent-injector + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + component: webhook +spec: + selector: + matchLabels: + app.kubernetes.io/name: {{ template "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} + component: webhook + {{- toYaml .Values.injector.podDisruptionBudget | nindent 2 }} +{{- end -}} diff --git a/packages/system/openbao/charts/openbao/templates/injector-mutating-webhook.yaml b/packages/system/openbao/charts/openbao/templates/injector-mutating-webhook.yaml new file mode 100644 index 00000000..8ffd2671 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/injector-mutating-webhook.yaml @@ -0,0 +1,44 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.injectorEnabled" . -}} +{{- if .injectorEnabled -}} +{{- if .Capabilities.APIVersions.Has "admissionregistration.k8s.io/v1" }} +apiVersion: admissionregistration.k8s.io/v1 +{{- else }} +apiVersion: admissionregistration.k8s.io/v1beta1 +{{- end }} +kind: MutatingWebhookConfiguration +metadata: + name: {{ template "openbao.fullname" . }}-agent-injector-cfg + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- template "injector.webhookAnnotations" . }} +webhooks: + - name: vault.hashicorp.com + failurePolicy: {{ ((.Values.injector.webhook)).failurePolicy | default .Values.injector.failurePolicy }} + matchPolicy: {{ ((.Values.injector.webhook)).matchPolicy | default "Exact" }} + sideEffects: None + timeoutSeconds: {{ ((.Values.injector.webhook)).timeoutSeconds | default "30" }} + admissionReviewVersions: ["v1", "v1beta1"] + clientConfig: + service: + name: {{ template "openbao.fullname" . }}-agent-injector-svc + namespace: {{ include "openbao.namespace" . }} + path: "/mutate" + caBundle: {{ .Values.injector.certs.caBundle | quote }} + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] +{{- if or (.Values.injector.namespaceSelector) (((.Values.injector.webhook)).namespaceSelector) }} + namespaceSelector: +{{ toYaml (((.Values.injector.webhook)).namespaceSelector | default .Values.injector.namespaceSelector) | indent 6}} +{{ end }} +{{- template "injector.objectSelector" . -}} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/injector-network-policy.yaml b/packages/system/openbao/charts/openbao/templates/injector-network-policy.yaml new file mode 100644 index 00000000..68a89754 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/injector-network-policy.yaml @@ -0,0 +1,30 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.injectorEnabled" . -}} +{{- if .injectorEnabled -}} +{{- if eq (.Values.global.openshift | toString) "true" }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ template "openbao.fullname" . }}-agent-injector + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ template "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: {{ template "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} + component: webhook + ingress: + - from: + - namespaceSelector: {} + ports: + - port: 8080 + protocol: TCP +{{ end }} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/injector-psp-role.yaml b/packages/system/openbao/charts/openbao/templates/injector-psp-role.yaml new file mode 100644 index 00000000..3f42450c --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/injector-psp-role.yaml @@ -0,0 +1,25 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.injectorEnabled" . -}} +{{- if .injectorEnabled -}} +{{- if eq (.Values.global.psp.enable | toString) "true" }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "openbao.fullname" . }}-agent-injector-psp + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +rules: +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "openbao.fullname" . }}-agent-injector +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/injector-psp-rolebinding.yaml b/packages/system/openbao/charts/openbao/templates/injector-psp-rolebinding.yaml new file mode 100644 index 00000000..62a609c7 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/injector-psp-rolebinding.yaml @@ -0,0 +1,26 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.injectorEnabled" . -}} +{{- if .injectorEnabled -}} +{{- if eq (.Values.global.psp.enable | toString) "true" }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "openbao.fullname" . }}-agent-injector-psp + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +roleRef: + kind: Role + name: {{ template "openbao.fullname" . }}-agent-injector-psp + apiGroup: rbac.authorization.k8s.io +subjects: + - kind: ServiceAccount + name: {{ template "openbao.fullname" . }}-agent-injector +{{- end }} +{{- end }} \ No newline at end of file diff --git a/packages/system/openbao/charts/openbao/templates/injector-psp.yaml b/packages/system/openbao/charts/openbao/templates/injector-psp.yaml new file mode 100644 index 00000000..5c1c58f7 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/injector-psp.yaml @@ -0,0 +1,51 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.injectorEnabled" . -}} +{{- if .injectorEnabled -}} +{{- if eq (.Values.global.psp.enable | toString) "true" }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "openbao.fullname" . }}-agent-injector + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- template "openbao.psp.annotations" . }} +spec: + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + volumes: + - configMap + - emptyDir + - projected + - secret + - downwardAPI + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + # Require the container to run without root privileges. + rule: MustRunAsNonRoot + seLinux: + # This policy assumes the nodes are using AppArmor rather than SELinux. + rule: RunAsAny + supplementalGroups: + rule: MustRunAs + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: MustRunAs + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} +{{- end }} \ No newline at end of file diff --git a/packages/system/openbao/charts/openbao/templates/injector-role.yaml b/packages/system/openbao/charts/openbao/templates/injector-role.yaml new file mode 100644 index 00000000..2e29aa7b --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/injector-role.yaml @@ -0,0 +1,34 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.injectorEnabled" . -}} +{{- if .injectorEnabled -}} +{{- if and (eq (.Values.injector.leaderElector.enabled | toString) "true") (gt (.Values.injector.replicas | int) 1) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "openbao.fullname" . }}-agent-injector-leader-elector-role + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +rules: + - apiGroups: [""] + resources: ["secrets", "configmaps"] + verbs: + - "create" + - "get" + - "watch" + - "list" + - "update" + - apiGroups: [""] + resources: ["pods"] + verbs: + - "get" + - "patch" + - "delete" +{{- end }} +{{- end }} \ No newline at end of file diff --git a/packages/system/openbao/charts/openbao/templates/injector-rolebinding.yaml b/packages/system/openbao/charts/openbao/templates/injector-rolebinding.yaml new file mode 100644 index 00000000..8e460c4b --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/injector-rolebinding.yaml @@ -0,0 +1,27 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.injectorEnabled" . -}} +{{- if .injectorEnabled -}} +{{- if and (eq (.Values.injector.leaderElector.enabled | toString) "true") (gt (.Values.injector.replicas | int) 1) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "openbao.fullname" . }}-agent-injector-leader-elector-binding + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "openbao.fullname" . }}-agent-injector-leader-elector-role +subjects: + - kind: ServiceAccount + name: {{ template "openbao.fullname" . }}-agent-injector + namespace: {{ include "openbao.namespace" . }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/packages/system/openbao/charts/openbao/templates/injector-service.yaml b/packages/system/openbao/charts/openbao/templates/injector-service.yaml new file mode 100644 index 00000000..f9db469f --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/injector-service.yaml @@ -0,0 +1,30 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.injectorEnabled" . -}} +{{- if .injectorEnabled -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "openbao.fullname" . }}-agent-injector-svc + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- if .Values.injector.service.extraLabels -}} + {{- toYaml .Values.injector.service.extraLabels | nindent 4 -}} + {{- end -}} + {{ template "injector.service.annotations" . }} +spec: + ports: + - name: https + port: 443 + targetPort: {{ .Values.injector.port }} + selector: + app.kubernetes.io/name: {{ include "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} + component: webhook +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/injector-serviceaccount.yaml b/packages/system/openbao/charts/openbao/templates/injector-serviceaccount.yaml new file mode 100644 index 00000000..a411788c --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/injector-serviceaccount.yaml @@ -0,0 +1,18 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- template "openbao.injectorEnabled" . -}} +{{- if .injectorEnabled -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "openbao.fullname" . }}-agent-injector + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{ template "injector.serviceAccount.annotations" . }} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/prometheus-prometheusrules.yaml b/packages/system/openbao/charts/openbao/templates/prometheus-prometheusrules.yaml new file mode 100644 index 00000000..d371da37 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/prometheus-prometheusrules.yaml @@ -0,0 +1,32 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ if and (.Values.serverTelemetry.prometheusRules.rules) + (or (.Values.global.serverTelemetry.prometheusOperator) (.Values.serverTelemetry.prometheusRules.enabled) ) +}} +--- +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ template "openbao.fullname" . }} + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- /* update the selectors docs in values.yaml whenever the defaults below change. */ -}} + {{- $selectors := .Values.serverTelemetry.prometheusRules.selectors }} + {{- if $selectors }} + {{- toYaml $selectors | nindent 4 }} + {{- else }} + release: prometheus + {{- end }} +spec: + groups: + - name: {{ include "openbao.fullname" . }} + rules: + {{- toYaml .Values.serverTelemetry.prometheusRules.rules | nindent 6 }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/prometheus-servicemonitor.yaml b/packages/system/openbao/charts/openbao/templates/prometheus-servicemonitor.yaml new file mode 100644 index 00000000..950c6194 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/prometheus-servicemonitor.yaml @@ -0,0 +1,62 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{ if or (.Values.global.serverTelemetry.prometheusOperator) (.Values.serverTelemetry.serviceMonitor.enabled) }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "openbao.fullname" . }} + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- /* update the selectors docs in values.yaml whenever the defaults below change. */ -}} + {{- $selectors := .Values.serverTelemetry.serviceMonitor.selectors }} + {{- if $selectors }} + {{- toYaml $selectors | nindent 4 }} + {{- else }} + release: prometheus + {{- end }} +spec: + {{- if .Values.serverTelemetry.serviceMonitor.scrapeClass }} + scrapeClass: {{ .Values.serverTelemetry.serviceMonitor.scrapeClass }} + {{- end }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + {{- if eq .mode "ha" }} + openbao-active: "true" + {{- else }} + openbao-internal: "true" + {{- end }} + endpoints: + - port: {{ .Values.serverTelemetry.serviceMonitor.port | default (include "openbao.scheme" .) }} + interval: {{ .Values.serverTelemetry.serviceMonitor.interval }} + scrapeTimeout: {{ .Values.serverTelemetry.serviceMonitor.scrapeTimeout }} + scheme: {{ .Values.serverTelemetry.serviceMonitor.scheme | default (include "openbao.scheme" .) | lower }} + path: /v1/sys/metrics + params: + format: + - prometheus + {{- with .Values.serverTelemetry.serviceMonitor.tlsConfig }} + tlsConfig: + {{- toYaml . | nindent 6 }} + {{- else }} + tlsConfig: + insecureSkipVerify: true + {{- end }} + {{- with .Values.serverTelemetry.serviceMonitor.authorization }} + authorization: + {{- toYaml . | nindent 6 }} + {{- end }} + namespaceSelector: + matchNames: + - {{ include "openbao.namespace" . }} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-backendtlspolicy.yaml b/packages/system/openbao/charts/openbao/templates/server-backendtlspolicy.yaml new file mode 100644 index 00000000..9b492d26 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-backendtlspolicy.yaml @@ -0,0 +1,43 @@ +{{ template "openbao.mode" . }} +{{- if ne .mode "external" }} +{{- if and (not .Values.global.tlsDisable) .Values.server.gateway.tlsPolicy.enabled -}} +{{- $serviceName := include "openbao.fullname" . -}} +{{- template "openbao.serverServiceEnabled" . -}} +{{- if .serverServiceEnabled -}} +{{- if and (eq .mode "ha" ) (eq (.Values.server.gateway.tlsPolicy.activeService | toString) "true") }} +{{- $serviceName = printf "%s-%s" $serviceName "active" -}} +{{- end }} +apiVersion: {{ .Values.server.gateway.tlsPolicy.apiVersion }} +kind: BackendTLSPolicy +metadata: + name: {{ template "openbao.fullname" . }} + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- with .Values.server.gateway.tlsPolicy.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- template "openbao.gateway.tlsPolicy.annotations" . }} +spec: + targetRefs: + {{- if .Values.server.gateway.tlsPolicy.targetRefs }} + {{- with .Values.server.gateway.tlsPolicy.targetRefs }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- else }} + - group: '' + kind: Service + name: {{ $serviceName }} + sectionName: {{ include "openbao.scheme" . }} + {{- end }} + validation: + {{- with .Values.server.gateway.tlsPolicy.validation }} + {{- toYaml . | nindent 4 }} + {{- end }} + hostname: {{ include "openbao.fullname" . }} +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-clusterrolebinding.yaml b/packages/system/openbao/charts/openbao/templates/server-clusterrolebinding.yaml new file mode 100644 index 00000000..0f851ec1 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-clusterrolebinding.yaml @@ -0,0 +1,29 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.serverAuthDelegator" . }} +{{- if .serverAuthDelegator -}} +{{- if .Capabilities.APIVersions.Has "rbac.authorization.k8s.io/v1" -}} +apiVersion: rbac.authorization.k8s.io/v1 +{{- else }} +apiVersion: rbac.authorization.k8s.io/v1beta1 +{{- end }} +kind: ClusterRoleBinding +metadata: + name: {{ template "openbao.fullname" . }}-server-binding + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: {{ template "openbao.serviceAccount.name" . }} + namespace: {{ include "openbao.namespace" . }} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-config-configmap.yaml b/packages/system/openbao/charts/openbao/templates/server-config-configmap.yaml new file mode 100644 index 00000000..57c4b0e6 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-config-configmap.yaml @@ -0,0 +1,31 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{- if ne .mode "external" }} +{{- if .serverEnabled -}} +{{- if ne .mode "dev" -}} +{{ if or (.Values.server.standalone.config) (.Values.server.ha.config) -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "openbao.fullname" . }}-config + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- if .Values.server.configAnnotation }} + annotations: + vault.hashicorp.com/config-checksum: {{ include "openbao.config" . | sha256sum }} +{{- end }} +data: + extraconfig-from-values.hcl: |- + {{ template "openbao.config" . }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-discovery-role.yaml b/packages/system/openbao/charts/openbao/templates/server-discovery-role.yaml new file mode 100644 index 00000000..082ff996 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-discovery-role.yaml @@ -0,0 +1,26 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{- if .serverEnabled -}} +{{- if eq .mode "ha" }} +{{- if eq (.Values.server.serviceAccount.serviceDiscovery.enabled | toString) "true" }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: {{ include "openbao.namespace" . }} + name: {{ template "openbao.fullname" . }}-discovery-role + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +rules: +- apiGroups: [""] + resources: ["pods"] + verbs: ["get", "watch", "list", "update", "patch"] +{{ end }} +{{ end }} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-discovery-rolebinding.yaml b/packages/system/openbao/charts/openbao/templates/server-discovery-rolebinding.yaml new file mode 100644 index 00000000..5d3f95e3 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-discovery-rolebinding.yaml @@ -0,0 +1,34 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{- if .serverEnabled -}} +{{- if eq .mode "ha" }} +{{- if eq (.Values.server.serviceAccount.serviceDiscovery.enabled | toString) "true" }} +{{- if .Capabilities.APIVersions.Has "rbac.authorization.k8s.io/v1" -}} +apiVersion: rbac.authorization.k8s.io/v1 +{{- else }} +apiVersion: rbac.authorization.k8s.io/v1beta1 +{{- end }} +kind: RoleBinding +metadata: + name: {{ template "openbao.fullname" . }}-discovery-rolebinding + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "openbao.fullname" . }}-discovery-role +subjects: +- kind: ServiceAccount + name: {{ template "openbao.serviceAccount.name" . }} + namespace: {{ include "openbao.namespace" . }} +{{ end }} +{{ end }} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-disruptionbudget.yaml b/packages/system/openbao/charts/openbao/templates/server-disruptionbudget.yaml new file mode 100644 index 00000000..7e6660a1 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-disruptionbudget.yaml @@ -0,0 +1,31 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{- if ne .mode "external" -}} +{{- if .serverEnabled -}} +{{- if and (eq .mode "ha") (eq (.Values.server.ha.disruptionBudget.enabled | toString) "true") -}} +# PodDisruptionBudget to prevent degrading the server cluster through +# voluntary cluster changes. +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ template "openbao.fullname" . }} + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +spec: + maxUnavailable: {{ template "openbao.pdb.maxUnavailable" . }} + selector: + matchLabels: + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + component: server +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/packages/system/openbao/charts/openbao/templates/server-ha-active-service.yaml b/packages/system/openbao/charts/openbao/templates/server-ha-active-service.yaml new file mode 100644 index 00000000..19f5afbd --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-ha-active-service.yaml @@ -0,0 +1,68 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{- if ne .mode "external" }} +{{- template "openbao.serverServiceEnabled" . -}} +{{- if .serverServiceEnabled -}} +{{- if eq .mode "ha" }} +{{- if eq (.Values.server.service.active.enabled | toString) "true" }} +# Service for active OpenBao pod +apiVersion: v1 +kind: Service +metadata: + name: {{ template "openbao.fullname" . }}-active + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + openbao-active: "true" + {{- if .Values.server.service.active.extraLabels -}} + {{- toYaml .Values.server.service.active.extraLabels | nindent 4 -}} + {{- end -}} +{{- template "openbao.service.active.annotations" . }} +spec: + {{- if .Values.server.service.type}} + type: {{ .Values.server.service.type }} + {{- end}} + {{- if (semverCompare ">= 1.23-0" .Capabilities.KubeVersion.Version) }} + {{- if .Values.server.service.ipFamilyPolicy }} + ipFamilyPolicy: {{ .Values.server.service.ipFamilyPolicy }} + {{- end }} + {{- if .Values.server.service.ipFamilies }} + ipFamilies: {{ .Values.server.service.ipFamilies | toYaml | nindent 2 }} + {{- end }} + {{- end }} + {{- if .Values.server.service.clusterIP }} + clusterIP: {{ .Values.server.service.clusterIP }} + {{- end }} + {{- include "service.externalTrafficPolicy" .Values.server.service }} + publishNotReadyAddresses: {{ .Values.server.service.publishNotReadyAddresses }} + ports: + - name: {{ include "openbao.scheme" . }} + port: {{ .Values.server.service.port }} + targetPort: {{ .Values.server.service.targetPort }} + {{- if and (.Values.server.service.activeNodePort) (eq (.Values.server.service.type | toString) "NodePort") }} + nodePort: {{ .Values.server.service.activeNodePort }} + {{- end }} + - name: https-internal + port: 8201 + targetPort: 8201 + {{- if .Values.server.service.extraPorts -}} + {{ toYaml .Values.server.service.extraPorts | nindent 4}} + {{- end }} + selector: + app.kubernetes.io/name: {{ include "openbao.name" . }} + {{- if eq (.Values.server.service.instanceSelector.enabled | toString) "true" }} + app.kubernetes.io/instance: {{ .Release.Name }} + {{- end }} + component: server + openbao-active: "true" +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-ha-standby-service.yaml b/packages/system/openbao/charts/openbao/templates/server-ha-standby-service.yaml new file mode 100644 index 00000000..f9ac4d42 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-ha-standby-service.yaml @@ -0,0 +1,67 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{- if ne .mode "external" }} +{{- template "openbao.serverServiceEnabled" . -}} +{{- if .serverServiceEnabled -}} +{{- if eq .mode "ha" }} +{{- if eq (.Values.server.service.standby.enabled | toString) "true" }} +# Service for standby OpenBao pod +apiVersion: v1 +kind: Service +metadata: + name: {{ template "openbao.fullname" . }}-standby + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- if .Values.server.service.standby.extraLabels -}} + {{- toYaml .Values.server.service.standby.extraLabels | nindent 4 -}} + {{- end -}} +{{- template "openbao.service.standby.annotations" . }} +spec: + {{- if .Values.server.service.type}} + type: {{ .Values.server.service.type }} + {{- end}} + {{- if (semverCompare ">= 1.23-0" .Capabilities.KubeVersion.Version) }} + {{- if .Values.server.service.ipFamilyPolicy }} + ipFamilyPolicy: {{ .Values.server.service.ipFamilyPolicy }} + {{- end }} + {{- if .Values.server.service.ipFamilies }} + ipFamilies: {{ .Values.server.service.ipFamilies | toYaml | nindent 2 }} + {{- end }} + {{- end }} + {{- if .Values.server.service.clusterIP }} + clusterIP: {{ .Values.server.service.clusterIP }} + {{- end }} + {{- include "service.externalTrafficPolicy" .Values.server.service }} + publishNotReadyAddresses: {{ .Values.server.service.publishNotReadyAddresses }} + ports: + - name: {{ include "openbao.scheme" . }} + port: {{ .Values.server.service.port }} + targetPort: {{ .Values.server.service.targetPort }} + {{- if and (.Values.server.service.standbyNodePort) (eq (.Values.server.service.type | toString) "NodePort") }} + nodePort: {{ .Values.server.service.standbyNodePort }} + {{- end }} + - name: https-internal + port: 8201 + targetPort: 8201 + {{- if .Values.server.service.extraPorts -}} + {{ toYaml .Values.server.service.extraPorts | nindent 4}} + {{- end }} + selector: + app.kubernetes.io/name: {{ include "openbao.name" . }} + {{- if eq (.Values.server.service.instanceSelector.enabled | toString) "true" }} + app.kubernetes.io/instance: {{ .Release.Name }} + {{- end }} + component: server + openbao-active: "false" +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-headless-service.yaml b/packages/system/openbao/charts/openbao/templates/server-headless-service.yaml new file mode 100644 index 00000000..b3441c8f --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-headless-service.yaml @@ -0,0 +1,46 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{- if ne .mode "external" }} +{{- template "openbao.serverServiceEnabled" . -}} +{{- if .serverServiceEnabled -}} +# Service for OpenBao cluster +apiVersion: v1 +kind: Service +metadata: + name: {{ template "openbao.fullname" . }}-internal + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + openbao-internal: "true" +{{ template "openbao.service.annotations" .}} +spec: + {{- if (semverCompare ">= 1.23-0" .Capabilities.KubeVersion.Version) }} + {{- if .Values.server.service.ipFamilyPolicy }} + ipFamilyPolicy: {{ .Values.server.service.ipFamilyPolicy }} + {{- end }} + {{- if .Values.server.service.ipFamilies }} + ipFamilies: {{ .Values.server.service.ipFamilies | toYaml | nindent 2 }} + {{- end }} + {{- end }} + clusterIP: None + publishNotReadyAddresses: true + ports: + - name: "{{ include "openbao.scheme" . }}" + port: {{ .Values.server.service.port }} + targetPort: {{ .Values.server.service.targetPort }} + - name: https-internal + port: 8201 + targetPort: 8201 + selector: + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + component: server +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-httproute.yaml b/packages/system/openbao/charts/openbao/templates/server-httproute.yaml new file mode 100644 index 00000000..ab840b42 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-httproute.yaml @@ -0,0 +1,50 @@ +{{ template "openbao.mode" . }} +{{- if ne .mode "external" }} +{{- if .Values.server.gateway.httpRoute.enabled -}} +{{- $serviceName := include "openbao.fullname" . -}} +{{- template "openbao.serverServiceEnabled" . -}} +{{- if .serverServiceEnabled -}} +{{- if and (eq .mode "ha" ) (eq (.Values.server.gateway.httpRoute.activeService | toString) "true") }} +{{- $serviceName = printf "%s-%s" $serviceName "active" -}} +{{- end }} +{{- $servicePort := .Values.server.service.port -}} +apiVersion: {{ .Values.server.gateway.httpRoute.apiVersion }} +kind: HTTPRoute +metadata: + name: {{ template "openbao.fullname" . }} + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- with .Values.server.gateway.httpRoute.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- template "openbao.gateway.httpRoute.annotations" . }} +spec: + hostnames: + {{- range .Values.server.gateway.httpRoute.hosts }} + - {{ . | quote }} + {{- end }} + parentRefs: + {{- with .Values.server.gateway.httpRoute.parentRefs }} + {{- toYaml . | nindent 4 }} + {{- end }} + rules: + - backendRefs: + - kind: Service + name: {{ $serviceName }} + port: {{ $servicePort }} + matches: + {{- with .Values.server.gateway.httpRoute.matches.path }} + - path: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.server.gateway.httpRoute.filters }} + filters: + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-ingress.yaml b/packages/system/openbao/charts/openbao/templates/server-ingress.yaml new file mode 100644 index 00000000..de33c66a --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-ingress.yaml @@ -0,0 +1,67 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{- if ne .mode "external" }} +{{- if .Values.server.ingress.enabled -}} +{{- $extraPaths := .Values.server.ingress.extraPaths -}} +{{- $serviceName := include "openbao.fullname" . -}} +{{- template "openbao.serverServiceEnabled" . -}} +{{- if .serverServiceEnabled -}} +{{- if and (eq .mode "ha" ) (eq (.Values.server.ingress.activeService | toString) "true") }} +{{- $serviceName = printf "%s-%s" $serviceName "active" -}} +{{- end }} +{{- $servicePort := .Values.server.service.port -}} +{{- $pathType := .Values.server.ingress.pathType -}} +{{- $kubeVersion := .Capabilities.KubeVersion.Version }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ template "openbao.fullname" . }} + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- with .Values.server.ingress.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- template "openbao.ingress.annotations" . }} +spec: +{{- if .Values.server.ingress.tls }} + tls: + {{- range .Values.server.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} +{{- if .Values.server.ingress.ingressClassName }} + ingressClassName: {{ .Values.server.ingress.ingressClassName }} +{{- end }} + rules: + {{- range .Values.server.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: +{{ if $extraPaths }} +{{ toYaml $extraPaths | indent 10 }} +{{- end }} + {{- range (.paths | default (list "/")) }} + - path: {{ . }} + pathType: {{ $pathType }} + backend: + service: + name: {{ $serviceName }} + port: + number: {{ $servicePort }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-network-policy.yaml b/packages/system/openbao/charts/openbao/templates/server-network-policy.yaml new file mode 100644 index 00000000..0891a508 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-network-policy.yaml @@ -0,0 +1,24 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- if eq (.Values.server.networkPolicy.enabled | toString) "true" }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ template "openbao.fullname" . }} + labels: + app.kubernetes.io/name: {{ template "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: {{ template "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + ingress: {{- toYaml .Values.server.networkPolicy.ingress | nindent 4 }} + {{- if .Values.server.networkPolicy.egress }} + egress: + {{- toYaml .Values.server.networkPolicy.egress | nindent 4 }} + {{ end }} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-psp-role.yaml b/packages/system/openbao/charts/openbao/templates/server-psp-role.yaml new file mode 100644 index 00000000..bfb71612 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-psp-role.yaml @@ -0,0 +1,25 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{- if .serverEnabled -}} +{{- if and (ne .mode "") (eq (.Values.global.psp.enable | toString) "true") }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "openbao.fullname" . }}-psp + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +rules: +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "openbao.fullname" . }} +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-psp-rolebinding.yaml b/packages/system/openbao/charts/openbao/templates/server-psp-rolebinding.yaml new file mode 100644 index 00000000..7f8bb975 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-psp-rolebinding.yaml @@ -0,0 +1,26 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{- if .serverEnabled -}} +{{- if and (ne .mode "") (eq (.Values.global.psp.enable | toString) "true") }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "openbao.fullname" . }}-psp + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +roleRef: + kind: Role + name: {{ template "openbao.fullname" . }}-psp + apiGroup: rbac.authorization.k8s.io +subjects: + - kind: ServiceAccount + name: {{ template "openbao.fullname" . }} +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-psp.yaml b/packages/system/openbao/charts/openbao/templates/server-psp.yaml new file mode 100644 index 00000000..d7c396a7 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-psp.yaml @@ -0,0 +1,54 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{- if .serverEnabled -}} +{{- if and (ne .mode "") (eq (.Values.global.psp.enable | toString) "true") }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "openbao.fullname" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- template "openbao.psp.annotations" . }} +spec: + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + volumes: + - configMap + - emptyDir + - projected + - secret + - downwardAPI + {{- if eq (.Values.server.dataStorage.enabled | toString) "true" }} + - persistentVolumeClaim + {{- end }} + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + # Require the container to run without root privileges. + rule: MustRunAsNonRoot + seLinux: + # This policy assumes the nodes are using AppArmor rather than SELinux. + rule: RunAsAny + supplementalGroups: + rule: MustRunAs + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: MustRunAs + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-route.yaml b/packages/system/openbao/charts/openbao/templates/server-route.yaml new file mode 100644 index 00000000..4c350d7d --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-route.yaml @@ -0,0 +1,39 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{- if .Values.global.openshift }} +{{- if ne .mode "external" }} +{{- if .Values.server.route.enabled -}} +{{- $serviceName := include "openbao.fullname" . -}} +{{- if and (eq .mode "ha" ) (eq (.Values.server.route.activeService | toString) "true") }} +{{- $serviceName = printf "%s-%s" $serviceName "active" -}} +{{- end }} +kind: Route +apiVersion: route.openshift.io/v1 +metadata: + name: {{ template "openbao.fullname" . }} + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- with .Values.server.route.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- template "openbao.route.annotations" . }} +spec: + host: {{ .Values.server.route.host }} + to: + kind: Service + name: {{ $serviceName }} + weight: 100 + port: + targetPort: 8200 + tls: + {{- toYaml .Values.server.route.tls | nindent 4 }} +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-service.yaml b/packages/system/openbao/charts/openbao/templates/server-service.yaml new file mode 100644 index 00000000..7f82db8e --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-service.yaml @@ -0,0 +1,64 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{- if ne .mode "external" }} +{{- template "openbao.serverServiceEnabled" . -}} +{{- if .serverServiceEnabled -}} +# Service for OpenBao cluster +apiVersion: v1 +kind: Service +metadata: + name: {{ template "openbao.fullname" . }} + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- if .Values.server.service.extraLabels -}} + {{- toYaml .Values.server.service.extraLabels | nindent 4 -}} + {{- end -}} +{{ template "openbao.service.annotations" .}} +spec: + {{- if .Values.server.service.type}} + type: {{ .Values.server.service.type }} + {{- end}} + {{- if (semverCompare ">= 1.23-0" .Capabilities.KubeVersion.Version) }} + {{- if .Values.server.service.ipFamilyPolicy }} + ipFamilyPolicy: {{ .Values.server.service.ipFamilyPolicy }} + {{- end }} + {{- if .Values.server.service.ipFamilies }} + ipFamilies: {{ .Values.server.service.ipFamilies | toYaml | nindent 2 }} + {{- end }} + {{- end }} + {{- if .Values.server.service.clusterIP }} + clusterIP: {{ .Values.server.service.clusterIP }} + {{- end }} + {{- include "service.externalTrafficPolicy" .Values.server.service }} + # We want the servers to become available even if they're not ready + # since this DNS is also used for join operations. + publishNotReadyAddresses: {{ .Values.server.service.publishNotReadyAddresses }} + ports: + - name: {{ include "openbao.scheme" . }} + port: {{ .Values.server.service.port }} + targetPort: {{ .Values.server.service.targetPort }} + {{- if and (.Values.server.service.nodePort) (eq (.Values.server.service.type | toString) "NodePort") }} + nodePort: {{ .Values.server.service.nodePort }} + {{- end }} + - name: https-internal + port: 8201 + targetPort: 8201 + {{- if .Values.server.service.extraPorts -}} + {{ toYaml .Values.server.service.extraPorts | nindent 4}} + {{- end }} + selector: + app.kubernetes.io/name: {{ include "openbao.name" . }} + {{- if eq (.Values.server.service.instanceSelector.enabled | toString) "true" }} + app.kubernetes.io/instance: {{ .Release.Name }} + {{- end }} + component: server +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-serviceaccount-secret.yaml b/packages/system/openbao/charts/openbao/templates/server-serviceaccount-secret.yaml new file mode 100644 index 00000000..e9ab3575 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-serviceaccount-secret.yaml @@ -0,0 +1,21 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.serverServiceAccountSecretCreationEnabled" . }} +{{- if .serverServiceAccountSecretCreationEnabled -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "openbao.serviceAccount.name" . }}-token + namespace: {{ include "openbao.namespace" . }} + annotations: + kubernetes.io/service-account.name: {{ template "openbao.serviceAccount.name" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +type: kubernetes.io/service-account-token +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-serviceaccount.yaml b/packages/system/openbao/charts/openbao/templates/server-serviceaccount.yaml new file mode 100644 index 00000000..aa615200 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-serviceaccount.yaml @@ -0,0 +1,22 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.serverServiceAccountEnabled" . }} +{{- if .serverServiceAccountEnabled -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "openbao.serviceAccount.name" . }} + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- if .Values.server.serviceAccount.extraLabels -}} + {{- toYaml .Values.server.serviceAccount.extraLabels | nindent 4 -}} + {{- end -}} + {{ template "openbao.serviceAccount.annotations" . }} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-statefulset.yaml b/packages/system/openbao/charts/openbao/templates/server-statefulset.yaml new file mode 100644 index 00000000..1628d139 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-statefulset.yaml @@ -0,0 +1,228 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{- if ne .mode "external" }} +{{- if ne .mode "" }} +{{- if .serverEnabled -}} +# StatefulSet to run the actual openbao server cluster. +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ template "openbao.fullname" . }} + namespace: {{ include "openbao.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- template "openbao.statefulSet.annotations" . }} +spec: + serviceName: {{ template "openbao.fullname" . }}-internal + podManagementPolicy: {{ .Values.server.podManagementPolicy }} + replicas: {{ template "openbao.replicas" . }} + updateStrategy: + type: {{ .Values.server.updateStrategyType }} + {{- if and (semverCompare ">= 1.23-0" .Capabilities.KubeVersion.Version) (.Values.server.persistentVolumeClaimRetentionPolicy) }} + persistentVolumeClaimRetentionPolicy: {{ toYaml .Values.server.persistentVolumeClaimRetentionPolicy | nindent 4 }} + {{- end }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + component: server + template: + metadata: + labels: + helm.sh/chart: {{ template "openbao.chart" . }} + app.kubernetes.io/name: {{ template "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + component: server + {{- if .Values.server.extraLabels -}} + {{- toYaml .Values.server.extraLabels | nindent 8 -}} + {{- end -}} + {{ template "openbao.annotations" . }} + spec: + {{ template "openbao.affinity" . }} + {{ template "openbao.topologySpreadConstraints" . }} + {{ template "openbao.tolerations" . }} + {{ template "openbao.nodeselector" . }} + {{- if .Values.server.priorityClassName }} + priorityClassName: {{ .Values.server.priorityClassName }} + {{- end }} + terminationGracePeriodSeconds: {{ .Values.server.terminationGracePeriodSeconds }} + serviceAccountName: {{ template "openbao.serviceAccount.name" . }} + {{ if .Values.server.shareProcessNamespace }} + shareProcessNamespace: true + {{ end }} + {{- template "server.statefulSet.securityContext.pod" . }} + {{- if not .Values.global.openshift }} + hostNetwork: {{ .Values.server.hostNetwork }} + {{- end }} + volumes: + {{ template "openbao.volumes" . }} + - name: home + emptyDir: {} + {{- if .Values.server.hostAliases }} + hostAliases: + {{ toYaml .Values.server.hostAliases | nindent 8}} + {{- end }} + {{- if .Values.server.extraInitContainers }} + initContainers: + {{ toYaml .Values.server.extraInitContainers | nindent 8}} + {{- end }} + containers: + - name: openbao + {{ template "openbao.resources" . }} + image: "{{ .Values.server.image.registry | default "docker.io" }}/{{ .Values.server.image.repository }}:{{ .Values.server.image.tag | default (trimPrefix "v" .Chart.AppVersion) }}" + imagePullPolicy: {{ .Values.server.image.pullPolicy }} + command: + - "/bin/sh" + - "-ec" + args: {{ template "openbao.args" . }} + {{- template "server.statefulSet.securityContext.container" . }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: BAO_K8S_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: BAO_K8S_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: BAO_ADDR + value: "{{ include "openbao.scheme" . }}://127.0.0.1:8200" + - name: BAO_API_ADDR + {{- if .Values.server.ha.apiAddr }} + value: {{ .Values.server.ha.apiAddr }} + {{- else }} + value: "{{ include "openbao.scheme" . }}://$(POD_IP):8200" + {{- end }} + - name: SKIP_CHOWN + value: "true" + - name: SKIP_SETCAP + value: "true" + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: BAO_CLUSTER_ADDR + {{- if .Values.server.ha.clusterAddr }} + value: {{ .Values.server.ha.clusterAddr | quote }} + {{- else }} + value: "https://$(HOSTNAME).{{ template "openbao.fullname" . }}-internal:8201" + {{- end }} + {{- if and (eq (.Values.server.ha.raft.enabled | toString) "true") (eq (.Values.server.ha.raft.setNodeId | toString) "true") }} + - name: BAO_RAFT_NODE_ID + valueFrom: + fieldRef: + fieldPath: metadata.name + {{- end }} + - name: HOME + value: "/home/openbao" + {{- if .Values.server.logLevel }} + - name: BAO_LOG_LEVEL + value: "{{ .Values.server.logLevel }}" + {{- end }} + {{- if .Values.server.logFormat }} + - name: BAO_LOG_FORMAT + value: "{{ .Values.server.logFormat }}" + {{- end }} + {{ template "openbao.envs" . }} + {{- include "openbao.extraSecretEnvironmentVars" .Values.server | nindent 12 }} + {{- include "openbao.extraEnvironmentVars" .Values.server | nindent 12 }} + volumeMounts: + {{ template "openbao.mounts" . }} + - name: home + mountPath: /home/openbao + ports: + - containerPort: 8200 + name: {{ include "openbao.scheme" . }} + - containerPort: 8201 + name: https-internal + - containerPort: 8202 + name: {{ include "openbao.scheme" . }}-rep + {{- if .Values.server.extraPorts -}} + {{ toYaml .Values.server.extraPorts | nindent 12}} + {{- end }} + {{- if .Values.server.readinessProbe.enabled }} + readinessProbe: + {{- if .Values.server.readinessProbe.path }} + httpGet: + path: {{ .Values.server.readinessProbe.path | quote }} + port: {{ .Values.server.readinessProbe.port }} + scheme: {{ include "openbao.scheme" . | upper }} + {{- else }} + # Check status; unsealed openbao servers return 0 + # The exit code reflects the seal status: + # 0 - unsealed + # 1 - error + # 2 - sealed + exec: + command: ["/bin/sh", "-ec", "bao status -tls-skip-verify"] + {{- end }} + failureThreshold: {{ .Values.server.readinessProbe.failureThreshold }} + initialDelaySeconds: {{ .Values.server.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.server.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.server.readinessProbe.successThreshold }} + timeoutSeconds: {{ .Values.server.readinessProbe.timeoutSeconds }} + {{- end }} + {{- if .Values.server.livenessProbe.enabled }} + livenessProbe: + {{- if .Values.server.livenessProbe.execCommand }} + exec: + command: + {{- range (.Values.server.livenessProbe.execCommand) }} + - {{ . | quote }} + {{- end }} + {{- else }} + httpGet: + path: {{ .Values.server.livenessProbe.path | quote }} + port: {{ .Values.server.livenessProbe.port }} + scheme: {{ include "openbao.scheme" . | upper }} + {{- end }} + failureThreshold: {{ .Values.server.livenessProbe.failureThreshold }} + initialDelaySeconds: {{ .Values.server.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.server.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.server.livenessProbe.successThreshold }} + timeoutSeconds: {{ .Values.server.livenessProbe.timeoutSeconds }} + {{- end }} + lifecycle: + # openbao container doesn't receive SIGTERM from Kubernetes + # and after the grace period ends, Kube sends SIGKILL. This + # causes issues with graceful shutdowns such as deregistering itself + # from Consul (zombie services). + preStop: + exec: + command: [ + "/bin/sh", "-c", + # Adding a sleep here to give the pod eviction a + # chance to propagate, so requests will not be made + # to this pod while it's terminating + "sleep {{ .Values.server.preStopSleepSeconds }} && kill -SIGTERM $(pidof bao)", + ] + {{- if .Values.server.postStart }} + postStart: + exec: + command: + {{- range (.Values.server.postStart) }} + - {{ . | quote }} + {{- end }} + {{- end }} + {{- if .Values.server.extraContainers }} + {{ toYaml .Values.server.extraContainers | nindent 8}} + {{- end }} + {{- include "imagePullSecrets" . | nindent 6 }} + {{ template "openbao.volumeclaims" . }} +{{ end }} +{{ end }} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/server-tlsroute.yaml b/packages/system/openbao/charts/openbao/templates/server-tlsroute.yaml new file mode 100644 index 00000000..14bd0d34 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/server-tlsroute.yaml @@ -0,0 +1,41 @@ +{{ template "openbao.mode" . }} +{{- if ne .mode "external" }} +{{- if .Values.server.gateway.tlsRoute.enabled -}} +{{- $serviceName := include "openbao.fullname" . -}} +{{- template "openbao.serverServiceEnabled" . -}} +{{- if .serverServiceEnabled -}} +{{- if and (eq .mode "ha" ) (eq (.Values.server.gateway.tlsRoute.activeService | toString) "true") }} +{{- $serviceName = printf "%s-%s" $serviceName "active" -}} +{{- end }} +{{- $servicePort := .Values.server.service.port -}} +{{- $kubeVersion := .Capabilities.KubeVersion.Version }} +apiVersion: {{ .Values.server.gateway.tlsRoute.apiVersion }} +kind: TLSRoute +metadata: + name: {{ template "openbao.fullname" . }} + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- with .Values.server.gateway.tlsRoute.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- template "openbao.gateway.tlsRoute.annotations" . }} +spec: + hostnames: + {{- range .Values.server.gateway.tlsRoute.hosts }} + - {{ . | quote }} + {{- end }} + parentRefs: + {{- with .Values.server.gateway.tlsRoute.parentRefs }} + {{- toYaml . | nindent 4 }} + {{- end }} + rules: + - backendRefs: + - name: {{ $serviceName }} + port: {{ $servicePort }} +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/snapshotagent-configmap.yaml b/packages/system/openbao/charts/openbao/templates/snapshotagent-configmap.yaml new file mode 100644 index 00000000..60be5505 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/snapshotagent-configmap.yaml @@ -0,0 +1,31 @@ + +--- +{{- if .Values.snapshotAgent.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "openbao.fullname" . }}-snapshot + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +data: + S3_HOST: {{ .Values.snapshotAgent.config.s3Host }} + S3_BUCKET: {{ .Values.snapshotAgent.config.s3Bucket }} + {{- if .Values.snapshotAgent.config.s3cmdExtraFlag }} + S3CMD_EXTRA_FLAG: {{ .Values.snapshotAgent.config.s3cmdExtraFlag }} + {{- end }} + S3_URI: {{ .Values.snapshotAgent.config.s3Uri }} + S3_EXPIRE_DAYS: {{ .Values.snapshotAgent.config.s3ExpireDays | quote }} + BAO_AUTH_PATH: {{ .Values.snapshotAgent.config.baoAuthPath }} + BAO_ROLE: {{ .Values.snapshotAgent.config.baoRole }} + {{- if include "openbao.externalAddr" . }} + BAO_ADDR: "{{ include "openbao.externalAddr" . }}" + {{- else if and (eq .mode "ha") (eq (.Values.server.service.active.enabled | toString) "true")}} + BAO_ADDR: {{ include "openbao.scheme" . }}://{{ template "openbao.fullname" . }}-active.{{ include "openbao.namespace" . }}.svc:{{ .Values.server.service.port }} + {{- else }} + BAO_ADDR: {{ include "openbao.scheme" . }}://{{ template "openbao.fullname" . }}.{{ include "openbao.namespace" . }}.svc:{{ .Values.server.service.port }} + {{- end }} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/snapshotagent-cronjob.yaml b/packages/system/openbao/charts/openbao/templates/snapshotagent-cronjob.yaml new file mode 100644 index 00000000..e1efadc0 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/snapshotagent-cronjob.yaml @@ -0,0 +1,66 @@ +{{- if .Values.snapshotAgent.enabled }} +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- template "openbao.snapshotAgent.annotations" . }} + name: {{ template "openbao.fullname" . }}-snapshot + namespace: {{ include "openbao.namespace" . }} +spec: + schedule: {{ .Values.snapshotAgent.schedule | quote }} + jobTemplate: + metadata: + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + component: snapshot-agent + spec: + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + component: snapshot-agent + spec: + restartPolicy: {{ .Values.snapshotAgent.restartPolicy }} + serviceAccountName: {{ template "openbao.snapshotAgent.serviceAccount.name" . }} + {{ template "snapshotAgent.securityContext.pod" .}} + containers: + - name: bao-snapshot + envFrom: + - configMapRef: + name: {{ template "openbao.fullname" . }}-snapshot + env: + - name: AWS_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + key: AWS_SECRET_ACCESS_KEY + name: {{ .Values.snapshotAgent.s3CredentialsSecret }} + - name: AWS_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + key: AWS_ACCESS_KEY_ID + name: {{ .Values.snapshotAgent.s3CredentialsSecret }} + {{- include "openbao.extraSecretEnvironmentVars" .Values.snapshotAgent | nindent 12 }} + {{- include "openbao.extraEnvironmentVars" .Values.snapshotAgent | nindent 12 }} + image: {{ .Values.snapshotAgent.image.repository }}:{{ .Values.snapshotAgent.image.tag }} + {{ template "openbao.snapshotAgent.resources". }} + {{ template "snapshotAgent.securityContext.container" .}} + volumeMounts: + - name: snapshot-dir + mountPath: /bao-snapshots + {{- with .Values.snapshotAgent.extraVolumeMounts }} + {{- toYaml . | nindent 14 }} + {{- end }} + imagePullPolicy: IfNotPresent + volumes: + - name: snapshot-dir + emptyDir: {} + {{- if .Values.snapshotAgent.extraVolumes }} + {{- toYaml .Values.snapshotAgent.extraVolumes | nindent 10 }} + {{- end }} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/snapshotagent-serviceaccount.yaml b/packages/system/openbao/charts/openbao/templates/snapshotagent-serviceaccount.yaml new file mode 100644 index 00000000..25fa3cb9 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/snapshotagent-serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.snapshotAgent.enabled .Values.snapshotAgent.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "openbao.snapshotAgent.serviceAccount.name" . }} + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- if .Values.snapshotAgent.serviceAccount.extraLabels -}} + {{- toYaml .Values.snapshotAgent.serviceAccount.extraLabels | nindent 4 -}} + {{- end -}} + {{ template "openbao.snapshotAgent.serviceAccount.annotations" . }} +{{ end }} diff --git a/packages/system/openbao/charts/openbao/templates/tests/server-test.yaml b/packages/system/openbao/charts/openbao/templates/tests/server-test.yaml new file mode 100644 index 00000000..8c42752e --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/tests/server-test.yaml @@ -0,0 +1,56 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{- if ne .mode "external" }} +{{- if .serverEnabled -}} +apiVersion: v1 +kind: Pod +metadata: + name: {{ template "openbao.fullname" . }}-server-test + namespace: {{ include "openbao.namespace" . }} + annotations: + "helm.sh/hook": test +spec: + {{- include "imagePullSecrets" . | nindent 2 }} + containers: + - name: {{ .Release.Name }}-server-test + image: {{ .Values.server.image.registry | default "docker.io" }}/{{ .Values.server.image.repository }}:{{ .Values.server.image.tag | default (trimPrefix "v" .Chart.AppVersion) }} + imagePullPolicy: {{ .Values.server.image.pullPolicy }} + env: + - name: VAULT_ADDR + value: {{ include "openbao.scheme" . }}://{{ template "openbao.fullname" . }}.{{ include "openbao.namespace" . }}.svc:{{ .Values.server.service.port }} + {{- include "openbao.extraEnvironmentVars" .Values.server | nindent 8 }} + command: + - /bin/sh + - -c + - | + echo "Checking for sealed info in 'bao status' output" + ATTEMPTS=10 + n=0 + until [ "$n" -ge $ATTEMPTS ] + do + echo "Attempt" $n... + bao status -format yaml | grep -E '^sealed: (true|false)' && break + n=$((n+1)) + sleep 5 + done + if [ $n -ge $ATTEMPTS ]; then + echo "timed out looking for sealed info in 'bao status' output" + exit 1 + fi + + exit 0 + volumeMounts: + {{- if .Values.server.volumeMounts }} + {{- toYaml .Values.server.volumeMounts | nindent 8}} + {{- end }} + volumes: + {{- if .Values.server.volumes }} + {{- toYaml .Values.server.volumes | nindent 4}} + {{- end }} + restartPolicy: Never +{{- end }} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/templates/ui-service.yaml b/packages/system/openbao/charts/openbao/templates/ui-service.yaml new file mode 100644 index 00000000..17ec0012 --- /dev/null +++ b/packages/system/openbao/charts/openbao/templates/ui-service.yaml @@ -0,0 +1,53 @@ +{{/* +Copyright (c) HashiCorp, Inc. +SPDX-License-Identifier: MPL-2.0 +*/}} + +{{ template "openbao.mode" . }} +{{- if ne .mode "external" }} +{{- template "openbao.uiEnabled" . -}} +{{- if .uiEnabled -}} + +apiVersion: v1 +kind: Service +metadata: + name: {{ template "openbao.fullname" . }}-ui + namespace: {{ include "openbao.namespace" . }} + labels: + helm.sh/chart: {{ include "openbao.chart" . }} + app.kubernetes.io/name: {{ include "openbao.name" . }}-ui + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- if .Values.ui.extraLabels -}} + {{- toYaml .Values.ui.extraLabels | nindent 4 -}} + {{- end -}} + {{- template "openbao.ui.annotations" . }} +spec: + {{- if (semverCompare ">= 1.23-0" .Capabilities.KubeVersion.Version) }} + {{- if .Values.ui.serviceIPFamilyPolicy }} + ipFamilyPolicy: {{ .Values.ui.serviceIPFamilyPolicy }} + {{- end }} + {{- if .Values.ui.serviceIPFamilies }} + ipFamilies: {{ .Values.ui.serviceIPFamilies | toYaml | nindent 2 }} + {{- end }} + {{- end }} + selector: + app.kubernetes.io/name: {{ include "openbao.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + component: server + {{- if and (.Values.ui.activeOpenbaoPodOnly) (eq .mode "ha") }} + openbao-active: "true" + {{- end }} + publishNotReadyAddresses: {{ .Values.ui.publishNotReadyAddresses }} + ports: + - name: {{ include "openbao.scheme" . }} + port: {{ .Values.ui.externalPort }} + targetPort: {{ .Values.ui.targetPort }} + {{- if .Values.ui.serviceNodePort }} + nodePort: {{ .Values.ui.serviceNodePort }} + {{- end }} + type: {{ .Values.ui.serviceType }} + {{- include "service.externalTrafficPolicy" .Values.ui }} + {{- include "service.loadBalancer" .Values.ui }} +{{- end -}} +{{- end }} diff --git a/packages/system/openbao/charts/openbao/values.openshift.yaml b/packages/system/openbao/charts/openbao/values.openshift.yaml new file mode 100644 index 00000000..964a81b0 --- /dev/null +++ b/packages/system/openbao/charts/openbao/values.openshift.yaml @@ -0,0 +1,30 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +# These overrides are appropriate defaults for deploying this chart on OpenShift + +global: + openshift: true + +injector: + image: + repository: "registry.connect.redhat.com/hashicorp/vault-k8s" + tag: "1.3.1-ubi" + + agentImage: + registry: "quay.io" + repository: "openbao/openbao-ubi" + tag: "2.3.2" + # Use UBI-based OpenBao image for better OpenShift compatibility + # See: https://openbao.org/docs/install/#container-registries + +server: + image: + registry: "quay.io" + repository: "openbao/openbao-ubi" + tag: "2.3.2" + # Use UBI-based OpenBao image for better OpenShift compatibility + # See: https://openbao.org/docs/install/#container-registries + + readinessProbe: + path: "/v1/sys/health?uninitcode=204" diff --git a/packages/system/openbao/charts/openbao/values.schema.json b/packages/system/openbao/charts/openbao/values.schema.json new file mode 100644 index 00000000..75298366 --- /dev/null +++ b/packages/system/openbao/charts/openbao/values.schema.json @@ -0,0 +1,1207 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "csi": { + "type": "object", + "properties": { + "agent": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "extraArgs": { + "type": "array" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "logFormat": { + "type": "string" + }, + "logLevel": { + "type": "string" + }, + "resources": { + "type": "object" + } + } + }, + "daemonSet": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + }, + "extraLabels": { + "type": "object" + }, + "kubeletRootDir": { + "type": "string" + }, + "providersDir": { + "type": "string" + }, + "securityContext": { + "type": "object", + "properties": { + "container": { + "type": [ + "object", + "string" + ] + }, + "pod": { + "type": [ + "object", + "string" + ] + } + } + }, + "updateStrategy": { + "type": "object", + "properties": { + "maxUnavailable": { + "type": "string" + }, + "type": { + "type": "string" + } + } + } + } + }, + "debug": { + "type": "boolean" + }, + "enabled": { + "type": [ + "boolean", + "string" + ] + }, + "extraArgs": { + "type": "array" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "livenessProbe": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "pod": { + "type": "object", + "properties": { + "affinity": { + "type": [ + "null", + "object", + "string" + ] + }, + "annotations": { + "type": [ + "object", + "string" + ] + }, + "extraLabels": { + "type": "object" + }, + "nodeSelector": { + "type": [ + "null", + "object", + "string" + ] + }, + "tolerations": { + "type": [ + "null", + "array", + "string" + ] + } + } + }, + "priorityClassName": { + "type": "string" + }, + "readinessProbe": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "resources": { + "type": "object" + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + }, + "extraLabels": { + "type": "object" + } + } + }, + "volumeMounts": { + "type": [ + "null", + "array" + ] + }, + "volumes": { + "type": [ + "null", + "array" + ] + } + } + }, + "global": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "namespace": { + "type": "string" + }, + "externalVaultAddr": { + "type": "string" + }, + "externalBaoAddr": { + "type": "string" + }, + "imagePullSecrets": { + "type": "array" + }, + "openshift": { + "type": "boolean" + }, + "psp": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + }, + "enable": { + "type": "boolean" + } + } + }, + "tlsDisable": { + "type": "boolean" + } + } + }, + "injector": { + "type": "object", + "properties": { + "affinity": { + "type": [ + "object", + "string" + ] + }, + "agentDefaults": { + "type": "object", + "properties": { + "cpuLimit": { + "type": "string" + }, + "cpuRequest": { + "type": "string" + }, + "memLimit": { + "type": "string" + }, + "memRequest": { + "type": "string" + }, + "ephemeralLimit": { + "type": "string" + }, + "ephemeralRequest": { + "type": "string" + }, + "template": { + "type": "string" + }, + "templateConfig": { + "type": "object", + "properties": { + "exitOnRetryFailure": { + "type": "boolean" + }, + "staticSecretRenderInterval": { + "type": "string" + } + } + } + } + }, + "agentImage": { + "type": "object", + "properties": { + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "annotations": { + "type": [ + "object", + "string" + ] + }, + "authPath": { + "type": "string" + }, + "certs": { + "type": "object", + "properties": { + "caBundle": { + "type": "string" + }, + "certName": { + "type": "string" + }, + "keyName": { + "type": "string" + }, + "secretName": { + "type": [ + "null", + "string" + ] + } + } + }, + "enabled": { + "type": [ + "boolean", + "string" + ] + }, + "externalVaultAddr": { + "type": "string" + }, + "extraEnvironmentVars": { + "type": "object" + }, + "extraLabels": { + "type": "object" + }, + "failurePolicy": { + "type": "string" + }, + "hostNetwork": { + "type": "boolean" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "leaderElector": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "logFormat": { + "type": "string" + }, + "logLevel": { + "type": "string" + }, + "metrics": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "namespaceSelector": { + "type": "object" + }, + "nodeSelector": { + "type": [ + "null", + "object", + "string" + ] + }, + "objectSelector": { + "type": [ + "object", + "string" + ] + }, + "podDisruptionBudget": { + "type": "object" + }, + "port": { + "type": "integer" + }, + "priorityClassName": { + "type": "string" + }, + "replicas": { + "type": "integer" + }, + "resources": { + "type": "object" + }, + "revokeOnShutdown": { + "type": "boolean" + }, + "securityContext": { + "type": "object", + "properties": { + "container": { + "type": [ + "object", + "string" + ] + }, + "pod": { + "type": [ + "object", + "string" + ] + } + } + }, + "service": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + } + } + }, + "strategy": { + "type": [ + "object", + "string" + ] + }, + "tolerations": { + "type": [ + "null", + "array", + "string" + ] + }, + "topologySpreadConstraints": { + "type": [ + "null", + "array", + "string" + ] + }, + "webhook": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + }, + "failurePolicy": { + "type": "string" + }, + "matchPolicy": { + "type": "string" + }, + "namespaceSelector": { + "type": "object" + }, + "objectSelector": { + "type": [ + "object", + "string" + ] + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "webhookAnnotations": { + "type": [ + "object", + "string" + ] + } + } + }, + "server": { + "type": "object", + "properties": { + "affinity": { + "type": [ + "object", + "string" + ] + }, + "annotations": { + "type": [ + "object", + "string" + ] + }, + "auditStorage": { + "type": "object", + "properties": { + "accessMode": { + "type": "string" + }, + "annotations": { + "type": [ + "object", + "string" + ] + }, + "labels": { + "type": [ + "object", + "string" + ] + }, + "enabled": { + "type": [ + "boolean", + "string" + ] + }, + "mountPath": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": [ + "null", + "string" + ] + } + } + }, + "authDelegator": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "dataStorage": { + "type": "object", + "properties": { + "accessMode": { + "type": "string" + }, + "annotations": { + "type": [ + "object", + "string" + ] + }, + "labels": { + "type": [ + "object", + "string" + ] + }, + "enabled": { + "type": [ + "boolean", + "string" + ] + }, + "mountPath": { + "type": "string" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": [ + "null", + "string" + ] + } + } + }, + "persistentVolumeClaimRetentionPolicy": { + "type": "object", + "properties": { + "whenDeleted": { + "type": "string" + }, + "whenScaled": { + "type": "string" + } + } + }, + "dev": { + "type": "object", + "properties": { + "devRootToken": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + }, + "enabled": { + "type": [ + "boolean", + "string" + ] + }, + "extraArgs": { + "type": "string" + }, + "extraPorts": { + "type": [ + "null", + "array" + ] + }, + "extraContainers": { + "type": [ + "null", + "array" + ] + }, + "extraEnvironmentVars": { + "type": "object" + }, + "extraInitContainers": { + "type": [ + "null", + "array" + ] + }, + "extraLabels": { + "type": "object" + }, + "extraSecretEnvironmentVars": { + "type": "array" + }, + "extraVolumes": { + "type": "array" + }, + "ha": { + "type": "object", + "properties": { + "apiAddr": { + "type": [ + "null", + "string" + ] + }, + "clusterAddr": { + "type": [ + "null", + "string" + ] + }, + "config": { + "type": [ + "string", + "object" + ] + }, + "disruptionBudget": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "maxUnavailable": { + "type": [ + "null", + "integer" + ] + } + } + }, + "enabled": { + "type": "boolean" + }, + "raft": { + "type": "object", + "properties": { + "config": { + "type": [ + "string", + "object" + ] + }, + "enabled": { + "type": "boolean" + }, + "setNodeId": { + "type": "boolean" + } + } + }, + "replicas": { + "type": "integer" + } + } + }, + "hostAliases": { + "type": "array" + }, + "image": { + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "ingress": { + "type": "object", + "properties": { + "activeService": { + "type": "boolean" + }, + "annotations": { + "type": [ + "object", + "string" + ] + }, + "enabled": { + "type": "boolean" + }, + "extraPaths": { + "type": "array" + }, + "hosts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "paths": { + "type": "array" + } + } + } + }, + "ingressClassName": { + "type": "string" + }, + "labels": { + "type": "object" + }, + "pathType": { + "type": "string" + }, + "tls": { + "type": "array" + } + } + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "path": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "execCommand": { + "type": "array" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "logFormat": { + "type": "string" + }, + "logLevel": { + "type": "string" + }, + "networkPolicy": { + "type": "object", + "properties": { + "egress": { + "type": "array" + }, + "enabled": { + "type": "boolean" + }, + "ingress": { + "type": "array" + } + } + }, + "nodeSelector": { + "type": [ + "null", + "object", + "string" + ] + }, + "postStart": { + "type": "array" + }, + "preStopSleepSeconds": { + "type": "integer" + }, + "priorityClassName": { + "type": "string" + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + } + }, + "resources": { + "type": "object" + }, + "route": { + "type": "object", + "properties": { + "activeService": { + "type": "boolean" + }, + "annotations": { + "type": [ + "object", + "string" + ] + }, + "enabled": { + "type": "boolean" + }, + "host": { + "type": "string" + }, + "labels": { + "type": "object" + }, + "tls": { + "type": "object" + } + } + }, + "service": { + "type": "object", + "properties": { + "active": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": [ + "object", + "string" + ] + } + } + }, + "annotations": { + "type": [ + "object", + "string" + ] + }, + "enabled": { + "type": "boolean" + }, + "externalTrafficPolicy": { + "type": "string" + }, + "instanceSelector": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "port": { + "type": "integer" + }, + "publishNotReadyAddresses": { + "type": "boolean" + }, + "standby": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "annotations": { + "type": [ + "object", + "string" + ] + } + } + }, + "targetPort": { + "type": "integer" + }, + "nodePort": { + "type": "integer" + }, + "activeNodePort": { + "type": "integer" + }, + "standbyNodePort": { + "type": "integer" + }, + "ipFamilyPolicy": { + "type": "string" + }, + "ipFamilies": { + "type": [ + "array" + ] + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + }, + "create": { + "type": "boolean" + }, + "extraLabels": { + "type": "object" + }, + "createSecret": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "serviceDiscovery": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + } + } + }, + "shareProcessNamespace": { + "type": "boolean" + }, + "standalone": { + "type": "object", + "properties": { + "config": { + "type": [ + "string", + "object" + ] + }, + "enabled": { + "type": [ + "string", + "boolean" + ] + } + } + }, + "statefulSet": { + "type": "object", + "properties": { + "annotations": { + "type": [ + "object", + "string" + ] + }, + "securityContext": { + "type": "object", + "properties": { + "container": { + "type": [ + "object", + "string" + ] + }, + "pod": { + "type": [ + "object", + "string" + ] + } + } + } + } + }, + "terminationGracePeriodSeconds": { + "type": "integer" + }, + "tolerations": { + "type": [ + "null", + "array", + "string" + ] + }, + "topologySpreadConstraints": { + "type": [ + "null", + "array", + "string" + ] + }, + "updateStrategyType": { + "type": "string" + }, + "volumeMounts": { + "type": [ + "null", + "array" + ] + }, + "volumes": { + "type": [ + "null", + "array" + ] + }, + "hostNetwork": { + "type": "boolean" + } + } + }, + "serverTelemetry": { + "type": "object", + "properties": { + "prometheusRules": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "rules": { + "type": "array" + }, + "selectors": { + "type": "object" + } + } + } + } + }, + "ui": { + "type": "object", + "properties": { + "activeOpenbaoPodOnly": { + "type": "boolean" + }, + "annotations": { + "type": [ + "object", + "string" + ] + }, + "enabled": { + "type": [ + "boolean", + "string" + ] + }, + "externalPort": { + "type": "integer" + }, + "externalTrafficPolicy": { + "type": "string" + }, + "publishNotReadyAddresses": { + "type": "boolean" + }, + "serviceNodePort": { + "type": [ + "null", + "integer" + ] + }, + "serviceType": { + "type": "string" + }, + "targetPort": { + "type": "integer" + }, + "serviceIPFamilyPolicy": { + "type": [ + "string" + ] + }, + "serviceIPFamilies": { + "type": [ + "array" + ] + } + } + } + } +} diff --git a/packages/system/openbao/charts/openbao/values.yaml b/packages/system/openbao/charts/openbao/values.yaml new file mode 100644 index 00000000..7e2f604f --- /dev/null +++ b/packages/system/openbao/charts/openbao/values.yaml @@ -0,0 +1,1583 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +# Available parameters and their default values for the OpenBao chart. + +global: + # -- enabled is the master enabled switch. Setting this to true or false + # will enable or disable all the components within this chart by default. + enabled: true + + # -- The namespace to deploy to. Defaults to the `helm` installation namespace. + namespace: "" + + # -- Image pull secret to use for registry authentication. + # Alternatively, the value may be specified as an array of strings. + imagePullSecrets: [] + # imagePullSecrets: + # - name: image-pull-secret + + # -- TLS for end-to-end encrypted transport + tlsDisable: true + + # -- External openbao server address for the injector and CSI provider to use. + # Setting this will disable deployment of a openbao server. + externalBaoAddr: "" + # -- Deprecated: Please use global.externalBaoAddr instead. + externalVaultAddr: "" + + # -- If deploying to OpenShift + openshift: false + + # -- Create PodSecurityPolicy for pods + psp: + enable: false + # -- Annotation for PodSecurityPolicy. + # This is a multi-line templated string map, and can also be set as YAML. + annotations: | + seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default,runtime/default + apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default + seccomp.security.alpha.kubernetes.io/defaultProfileName: runtime/default + apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default + + serverTelemetry: + # -- Enable integration with the Prometheus Operator + # See the top level serverTelemetry section below before enabling this feature. + prometheusOperator: false + +injector: + # -- True if you want to enable openbao agent injection. @default: global.enabled + enabled: "-" + + replicas: 1 + + # -- Configures the port the injector should listen on + port: 8080 + + # -- If multiple replicas are specified, by default a leader will be determined + # so that only one injector attempts to create TLS certificates. + leaderElector: + enabled: true + + # -- If true, will enable a node exporter metrics endpoint at /metrics. + metrics: + enabled: false + + # -- Deprecated: Please use global.externalBaoAddr instead. + externalVaultAddr: "" + + # image sets the repo and tag of the vault-k8s image to use for the injector. + image: + # -- image registry to use for k8s image + registry: "docker.io" + # -- image repo to use for k8s image + repository: "hashicorp/vault-k8s" + # -- image tag to use for k8s image + tag: "1.7.2" + # -- image pull policy to use for k8s image. if tag is "latest", set to "Always" + pullPolicy: IfNotPresent + + # -- agentImage sets the repo and tag of the OpenBao image to use for the OpenBao Agent + # containers. This should be set to the official OpenBao image. OpenBao 1.3.1+ is + # required. + agentImage: + # -- image registry to use for agent image + registry: "quay.io" + # -- image repo to use for agent image + repository: "openbao/openbao" + # -- image tag to use for agent image - defaults to chart appVersion + tag: "" + # -- image pull policy to use for agent image. if tag is "latest", set to "Always" + pullPolicy: IfNotPresent + + # The default values for the injected OpenBao Agent containers. + agentDefaults: + # For more information on configuring resources, see the K8s documentation: + # https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + cpuLimit: "500m" + cpuRequest: "250m" + memLimit: "128Mi" + memRequest: "64Mi" + # ephemeralLimit: "128Mi" + # ephemeralRequest: "64Mi" + + # Default template type for secrets when no custom template is specified. + # Possible values include: "json" and "map". + template: "map" + + # Default values within Agent's template_config stanza. + templateConfig: + exitOnRetryFailure: true + staticSecretRenderInterval: "" + + # Used to define custom livenessProbe settings + livenessProbe: + # -- When a probe fails, Kubernetes will try failureThreshold times before giving up + failureThreshold: 2 + # -- Number of seconds after the container has started before probe initiates + initialDelaySeconds: 5 + # -- How often (in seconds) to perform the probe + periodSeconds: 2 + # -- Minimum consecutive successes for the probe to be considered successful after having failed + successThreshold: 1 + # -- Number of seconds after which the probe times out. + timeoutSeconds: 5 + # Used to define custom readinessProbe settings + readinessProbe: + # -- When a probe fails, Kubernetes will try failureThreshold times before giving up + failureThreshold: 2 + # -- Number of seconds after the container has started before probe initiates + initialDelaySeconds: 5 + # -- How often (in seconds) to perform the probe + periodSeconds: 2 + # -- Minimum consecutive successes for the probe to be considered successful after having failed + successThreshold: 1 + # -- Number of seconds after which the probe times out. + timeoutSeconds: 5 + # Used to define custom startupProbe settings + startupProbe: + # -- When a probe fails, Kubernetes will try failureThreshold times before giving up + failureThreshold: 12 + # -- Number of seconds after the container has started before probe initiates + initialDelaySeconds: 5 + # -- How often (in seconds) to perform the probe + periodSeconds: 5 + # -- Minimum consecutive successes for the probe to be considered successful after having failed + successThreshold: 1 + # -- Number of seconds after which the probe times out. + timeoutSeconds: 5 + + # Mount Path of the OpenBao Kubernetes Auth Method. + authPath: "auth/kubernetes" + + # -- Configures the log verbosity of the injector. + # Supported log levels include: trace, debug, info, warn, error + logLevel: "info" + + # -- Configures the log format of the injector. Supported log formats: "standard", "json". + logFormat: "standard" + + # Configures all OpenBao Agent sidecars to revoke their token when shutting down + revokeOnShutdown: false + + webhook: + # Configures failurePolicy of the webhook. The "unspecified" default behaviour depends on the + # API Version of the WebHook. + # To block pod creation while the webhook is unavailable, set the policy to `Fail` below. + # See https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#failure-policy + # + failurePolicy: Ignore + + # matchPolicy specifies the approach to accepting changes based on the rules of + # the MutatingWebhookConfiguration. + # See https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-matchpolicy + # for more details. + # + matchPolicy: Exact + + # timeoutSeconds is the amount of seconds before the webhook request will be ignored + # or fails. + # If it is ignored or fails depends on the failurePolicy + # See https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#timeouts + # for more details. + # + timeoutSeconds: 30 + + # namespaceSelector is the selector for restricting the webhook to only + # specific namespaces. + # See https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-namespaceselector + # for more details. + # Example: + # namespaceSelector: + # matchLabels: + # sidecar-injector: enabled + namespaceSelector: {} + + # objectSelector is the selector for restricting the webhook to only + # specific labels. + # See https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-objectselector + # for more details. + # Example: + # objectSelector: + # matchLabels: + # vault-sidecar-injector: enabled + objectSelector: | + matchExpressions: + - key: app.kubernetes.io/name + operator: NotIn + values: + - {{ template "openbao.name" . }}-agent-injector + + # Extra annotations to attach to the webhook + annotations: {} + + # Deprecated: please use 'webhook.failurePolicy' instead + # Configures failurePolicy of the webhook. The "unspecified" default behaviour depends on the + # API Version of the WebHook. + # To block pod creation while webhook is unavailable, set the policy to `Fail` below. + # See https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#failure-policy + # + failurePolicy: Ignore + + # Deprecated: please use 'webhook.namespaceSelector' instead + # namespaceSelector is the selector for restricting the webhook to only + # specific namespaces. + # See https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-namespaceselector + # for more details. + # Example: + # namespaceSelector: + # matchLabels: + # sidecar-injector: enabled + namespaceSelector: {} + + # Deprecated: please use 'webhook.objectSelector' instead + # objectSelector is the selector for restricting the webhook to only + # specific labels. + # See https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-objectselector + # for more details. + # Example: + # objectSelector: + # matchLabels: + # vault-sidecar-injector: enabled + objectSelector: {} + + # Deprecated: please use 'webhook.annotations' instead + # Extra annotations to attach to the webhook + webhookAnnotations: {} + + certs: + # secretName is the name of the secret that has the TLS certificate and + # private key to serve the injector webhook. If this is null, then the + # injector will default to its automatic management mode that will assign + # a service account to the injector to generate its own certificates. + secretName: null + + # caBundle is a base64-encoded PEM-encoded certificate bundle for the CA + # that signed the TLS certificate that the webhook serves. This must be set + # if secretName is non-null unless an external service like cert-manager is + # keeping the caBundle updated. + caBundle: "" + + # certName and keyName are the names of the files within the secret for + # the TLS cert and private key, respectively. These have reasonable + # defaults but can be customized if necessary. + certName: tls.crt + keyName: tls.key + + # Security context for the pod template and the injector container + # The default pod securityContext is: + # runAsNonRoot: true + # runAsGroup: {{ .Values.injector.gid | default 1000 }} + # runAsUser: {{ .Values.injector.uid | default 100 }} + # fsGroup: {{ .Values.injector.gid | default 1000 }} + # and for container is + # allowPrivilegeEscalation: false + # capabilities: + # drop: + # - ALL + securityContext: + pod: {} + container: {} + + resources: {} + # resources: + # requests: + # memory: 256Mi + # cpu: 250m + # limits: + # memory: 256Mi + # cpu: 250m + + # extraEnvironmentVars is a list of extra environment variables to set in the + # injector deployment. + extraEnvironmentVars: {} + # KUBERNETES_SERVICE_HOST: kubernetes.default.svc + + # Affinity Settings for injector pods + # This can either be a multi-line string or YAML matching the PodSpec's affinity field. + # Commenting out or setting as empty the affinity variable, will allow + # deployment of multiple replicas to single node services such as Minikube. + affinity: | + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app.kubernetes.io/name: {{ template "openbao.name" . }}-agent-injector + app.kubernetes.io/instance: "{{ .Release.Name }}" + component: webhook + topologyKey: kubernetes.io/hostname + + # Topology settings for injector pods + # ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ + # This should be either a multi-line string or YAML matching the topologySpreadConstraints array + # in a PodSpec. + topologySpreadConstraints: [] + + # Toleration Settings for injector pods + # This should be either a multi-line string or YAML matching the Toleration array + # in a PodSpec. + tolerations: [] + + # nodeSelector labels for server pod assignment, formatted as a multi-line string or YAML map. + # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + # Example: + # nodeSelector: + # beta.kubernetes.io/arch: amd64 + nodeSelector: {} + + # Priority class for injector pods + priorityClassName: "" + + # Extra annotations to attach to the injector pods + # This can either be YAML or a YAML-formatted multi-line templated string map + # of the annotations to apply to the injector pods + annotations: {} + + # Extra labels to attach to the agent-injector + # This should be a YAML map of the labels to apply to the injector + extraLabels: {} + + # Should the injector pods run on the host network (useful when using + # an alternate CNI in EKS) + hostNetwork: false + + # Injector service specific config + service: + # Extra annotations to attach to the injector service + annotations: {} + # Extra labels for the service definition. + # This should be a YAML map of the labels to apply to the injector service + extraLabels: {} + + # Injector serviceAccount specific config + serviceAccount: + # Extra annotations to attach to the injector serviceAccount + annotations: {} + + # A disruption budget limits the number of pods of a replicated application + # that are down simultaneously from voluntary disruptions + podDisruptionBudget: {} + # podDisruptionBudget: + # maxUnavailable: 1 + + # strategy for updating the deployment. This can be a multi-line string or a + # YAML map. + strategy: {} + # strategy: | + # rollingUpdate: + # maxSurge: 25% + # maxUnavailable: 25% + # type: RollingUpdate + +server: + # If true, or "-" with global.enabled true, OpenBao server will be installed. + # See openbao.mode in _helpers.tpl for implementation details. + enabled: "-" + + # Resource requests, limits, etc. for the server cluster placement. This + # should map directly to the value of the resources field for a PodSpec. + # By default no direct resource request is made. + + image: + # -- image registry to use for server image + registry: "quay.io" + # -- image repo to use for server image + repository: "openbao/openbao" + # -- image tag to use for server image - defaults to chart appVersion + tag: "" + # -- image pull policy to use for server image. if tag is "latest", set to "Always" + pullPolicy: IfNotPresent + + # Configure the Update Strategy Type for the StatefulSet + # See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies + updateStrategyType: "OnDelete" + + # Configure the pod management policy for the StatefulSet + # See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies + podManagementPolicy: "OrderedReady" + + # Configure the logging verbosity for the OpenBao server. + # Supported log levels include: trace, debug, info, warn, error + logLevel: "" + + # Configure the logging format for the OpenBao server. + # Supported log formats include: standard, json + logFormat: "" + + resources: {} + # resources: + # requests: + # memory: 256Mi + # cpu: 250m + # limits: + # memory: 256Mi + # cpu: 250m + + # Ingress allows ingress services to be created to allow external access + # from Kubernetes to access OpenBao pods. + # If deployment is on OpenShift, the following block is ignored. + # In order to expose the service, use the route section below + ingress: + enabled: false + labels: {} + # traffic: external + annotations: {} + # | + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # or + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + + # Optionally use ingressClassName instead of deprecated annotation. + # See: https://kubernetes.io/docs/concepts/services-networking/ingress/#deprecated-annotation + ingressClassName: "" + + # As of Kubernetes 1.19, all Ingress Paths must have a pathType configured. The default value below should be sufficient in most cases. + # See: https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types for other possible values. + pathType: Prefix + + # When HA mode is enabled and K8s service registration is being used, + # configure the ingress to point to the OpenBao active service. + activeService: true + hosts: + - host: chart-example.local + paths: [] + ## Extra paths to prepend to the host configuration. This is useful when working with annotation based services. + extraPaths: [] + # - path: /* + # backend: + # service: + # name: ssl-redirect + # port: + # number: use-annotation + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + + # Gateway consolidates configuration related to the Kubernetes Gateway API + # Currently, only creating a TLSRoute is supported + # See: https://gateway-api.sigs.k8s.io/ + gateway: + # Configures a TLSRoute for the OpenBao server. This can be enabled independently of the ingress configuration to allow for side-by-side scenarios for migration. + tlsRoute: + enabled: false + labels: {} + # traffic: external + annotations: {} + # external-dns.alpha.kubernetes.io/hostname: chart-example.local + + hosts: [] + # - chart-example.local + + # Allows overriding the TLSRoutes apiVersion in case a different version of Gateway API is installed on the cluster. + apiVersion: gateway.networking.k8s.io/v1alpha3 + + # When HA mode is enabled and K8s service registration is being used, + # configure the ingress to point to the OpenBao active service. + activeService: true + + # List of ParentRefs. As the helm chart configures no gateways itself, + # this should be set to at least one gateway with one or more TLS listeners + parentRefs: [] + # - name: my-gw + # namespace: gateway-namespace + # # sectionName is optional to fix to a specific listener + # sectionName: listener-name + + # Configures a HTTPRoute for the OpenBao server. This can be enabled independently of the ingress configuration to allow for side-by-side scenarios for migration. + # WARNING: Terminating TLS before reaching the OpenBao Server is not recommended and may break things like certificate authentication. Prefer usage of `TLSRoute`. + httpRoute: + enabled: false + labels: {} + # traffic: external + annotations: {} + # external-dns.alpha.kubernetes.io/hostname: chart-example.local + + hosts: + - chart-example.local + + # Allows overriding the HTTPRoute apiVersion in case a different version of Gateway API is installed on the cluster. + apiVersion: gateway.networking.k8s.io/v1 + + # When HA mode is enabled and K8s service registration is being used, + # configure the ingress to point to the OpenBao active service. + activeService: true + + # List of ParentRefs. As the helm chart configures no gateways itself, + # this should be set to at least one gateway with one or more HTTP listeners + parentRefs: [] + # - name: my-gw + # namespace: gateway-namespace + # # sectionName is optional to fix to a specific listener + # sectionName: listener-name + + matches: + path: + type: PathPrefix + value: '/' + timeouts: {} + # request: 10s #Maximum time the Gateway waits to complete the full client request and response cycle. + # backendRequest: 10s # Maximum time the Gateway waits for a response from the backend service. + filters: [] + # - type: RequestHeaderModifier + # requestHeaderModifier: + # set: + # - name: X-Forwarded-Proto + # value: https + + # If TLS is enable on server (see global.tlsDisable) the gateway must be configured + # with BackendTLSPolicy to correctly handles TLS connection with server in case TLS termination happens at gateway + tlsPolicy: + enabled: false + labels: {} + # traffic: external + annotations: {} + # external-dns.alpha.kubernetes.io/hostname: chart-example.local + + # Allows overriding the BackendTLSPolicy apiVersion in case a different version of Gateway API is installed on the cluster. + apiVersion: gateway.networking.k8s.io/v1 + + # When HA mode is enabled and K8s service registration is being used, + # configure the ingress to point to the OpenBao active service. + activeService: true + + # Identifies an API object to apply the policy to. + # If no one is specified the default is to target the OpenBao service + targetRefs: [] + + validation: {} + # caCertificateRefs: + # - kind: ConfigMap + # name: vault-ca + + # hostAliases is a list of aliases to be added to /etc/hosts. Specified as a YAML list. + hostAliases: [] + # - ip: 127.0.0.1 + # hostnames: + # - chart-example.local + + # OpenShift only - create a route to expose the service + # By default the created route will be of type passthrough + route: + enabled: false + + # When HA mode is enabled and K8s service registration is being used, + # configure the route to point to the OpenBao active service. + activeService: true + + labels: {} + annotations: {} + host: chart-example.local + # tls will be passed directly to the route's TLS config, which + # can be used to configure other termination methods that terminate + # TLS at the router + tls: + termination: passthrough + + # authDelegator enables a cluster role binding to be attached to the service + # account. This cluster role binding can be used to setup Kubernetes auth + # method. See https://openbao.org/docs/auth/kubernetes + authDelegator: + enabled: true + + # -- extraInitContainers is a list of init containers. Specified as a YAML list. + # This is useful if you need to run a script to provision TLS certificates or + # write out configuration files in a dynamic way. + extraInitContainers: [] + # # This example installs a plugin pulled from github into the /usr/local/libexec/vault/oauthapp folder, + # # which is defined in the volumes value. + # - name: oauthapp + # image: "alpine" + # command: [sh, -c] + # args: + # - cd /tmp && + # wget https://github.com/puppetlabs/vault-plugin-secrets-oauthapp/releases/download/v1.2.0/vault-plugin-secrets-oauthapp-v1.2.0-linux-amd64.tar.xz -O oauthapp.xz && + # tar -xf oauthapp.xz && + # mv vault-plugin-secrets-oauthapp-v1.2.0-linux-amd64 /usr/local/libexec/vault/oauthapp && + # chmod +x /usr/local/libexec/vault/oauthapp + # volumeMounts: + # - name: plugins + # mountPath: /usr/local/libexec/vault + + # extraContainers is a list of sidecar containers. Specified as a YAML list. + extraContainers: null + + # -- shareProcessNamespace enables process namespace sharing between OpenBao and the extraContainers + # This is useful if OpenBao must be signaled, e.g. to send a SIGHUP for a log rotation + shareProcessNamespace: false + + # -- extraArgs is a string containing additional OpenBao server arguments. + extraArgs: "" + + # -- extraPorts is a list of extra ports. Specified as a YAML list. + # This is useful if you need to add additional ports to the statefulset in dynamic way. + extraPorts: [] + # - containerPort: 8300 + # name: http-monitoring + + # Used to define custom readinessProbe settings + readinessProbe: + enabled: true + # If you need to use a http path instead of the default exec + # path: /v1/sys/health?standbyok=true + + # Port number on which readinessProbe will be checked. + port: 8200 + # When a probe fails, Kubernetes will try failureThreshold times before giving up + failureThreshold: 2 + # Number of seconds after the container has started before probe initiates + initialDelaySeconds: 5 + # How often (in seconds) to perform the probe + periodSeconds: 5 + # Minimum consecutive successes for the probe to be considered successful after having failed + successThreshold: 1 + # Number of seconds after which the probe times out. + timeoutSeconds: 3 + # Used to enable a livenessProbe for the pods + livenessProbe: + enabled: false + # Used to define a liveness exec command. If provided, exec is preferred to httpGet (path) as the livenessProbe handler. + execCommand: [] + # - /bin/sh + # - -c + # - /openbao/userconfig/mylivenessscript/run.sh + # Path for the livenessProbe to use httpGet as the livenessProbe handler + path: "/v1/sys/health?standbyok=true" + # Port number on which livenessProbe will be checked if httpGet is used as the livenessProbe handler + port: 8200 + # When a probe fails, Kubernetes will try failureThreshold times before giving up + failureThreshold: 2 + # Number of seconds after the container has started before probe initiates + initialDelaySeconds: 60 + # How often (in seconds) to perform the probe + periodSeconds: 5 + # Minimum consecutive successes for the probe to be considered successful after having failed + successThreshold: 1 + # Number of seconds after which the probe times out. + timeoutSeconds: 3 + + # Optional duration in seconds the pod needs to terminate gracefully. + # See: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/ + terminationGracePeriodSeconds: 10 + + # Used to set the sleep time during the preStop step + preStopSleepSeconds: 5 + + # Used to define commands to run after the pod is ready. + # This can be used to automate processes such as initialization + # or bootstrapping auth methods. + postStart: [] + # - /bin/sh + # - -c + # - /openbao/userconfig/myscript/run.sh + + # extraEnvironmentVars is a list of extra environment variables to set with the stateful set. These could be + # used to include variables required for auto-unseal. + extraEnvironmentVars: {} + # GOOGLE_REGION: global + # GOOGLE_PROJECT: myproject + # GOOGLE_APPLICATION_CREDENTIALS: /openbao/userconfig/myproject/myproject-creds.json + + # extraSecretEnvironmentVars is a list of extra environment variables to set with the stateful set. + # These variables take value from existing Secret objects. + extraSecretEnvironmentVars: [] + # - envName: AWS_SECRET_ACCESS_KEY + # secretName: openbao + # secretKey: AWS_SECRET_ACCESS_KEY + + # Deprecated: please use 'volumes' instead. + # extraVolumes is a list of extra volumes to mount. These will be exposed + # to OpenBao in the path `/openbao/userconfig//`. The value below is + # an array of objects, examples are shown below. + extraVolumes: [] + # - type: secret (or "configMap") + # name: my-secret + # path: null # default is `/openbao/userconfig` + + # volumes is a list of volumes made available to all containers. These are rendered + # via toYaml rather than pre-processed like the extraVolumes value. + # The purpose is to make it easy to share volumes between containers. + volumes: null + # - name: plugins + # emptyDir: {} + + # volumeMounts is a list of volumeMounts for the main server container. These are rendered + # via toYaml rather than pre-processed like the extraVolumes value. + # The purpose is to make it easy to share volumes between containers. + volumeMounts: null + # - mountPath: /usr/local/libexec/vault + # name: plugins + # readOnly: true + + # Affinity Settings + # Commenting out or setting as empty the affinity variable, will allow + # deployment to single node services such as Minikube + # This should be either a multi-line string or YAML matching the PodSpec's affinity field. + affinity: | + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app.kubernetes.io/name: {{ template "openbao.name" . }} + app.kubernetes.io/instance: "{{ .Release.Name }}" + component: server + topologyKey: kubernetes.io/hostname + + # Topology settings for server pods + # ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ + # This should be either a multi-line string or YAML matching the topologySpreadConstraints array + # in a PodSpec. + topologySpreadConstraints: [] + + # Toleration Settings for server pods + # This should be either a multi-line string or YAML matching the Toleration array + # in a PodSpec. + tolerations: [] + + # nodeSelector labels for server pod assignment, formatted as a multi-line string or YAML map. + # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + # Example: + # nodeSelector: + # beta.kubernetes.io/arch: amd64 + nodeSelector: {} + + # Enables network policy for server pods + networkPolicy: + enabled: false + egress: [] + # egress: + # - to: + # - ipBlock: + # cidr: 10.0.0.0/24 + # ports: + # - protocol: TCP + # port: 443 + ingress: + - from: + - namespaceSelector: {} + ports: + - port: 8200 + protocol: TCP + - port: 8201 + protocol: TCP + + # Priority class for server pods + priorityClassName: "" + + # Extra labels to attach to the server pods + # This should be a YAML map of the labels to apply to the server pods + extraLabels: {} + + # Extra annotations to attach to the server pods + # This can either be YAML or a YAML-formatted multi-line templated string map + # of the annotations to apply to the server pods + annotations: {} + + # Add an annotation to the server configmap and the statefulset pods, + # vaultproject.io/config-checksum, that is a hash of the OpenBao configuration. + # This can be used together with an OnDelete deployment strategy to help + # identify which pods still need to be deleted during a deployment to pick up + # any configuration changes. + configAnnotation: false + + # Enables a headless service to be used by the OpenBao Statefulset + service: + enabled: true + # Enable or disable the openbao-active service, which selects OpenBao pods that + # have labeled themselves as the cluster leader with `openbao-active: "true"`. + active: + enabled: true + # Extra annotations for the service definition. This can either be YAML or a + # YAML-formatted multi-line templated string map of the annotations to apply + # to the active service. + annotations: {} + # Extra labels for the service definition. + # This should be a YAML map of the labels to apply to the active service + extraLabels: {} + # Enable or disable the openbao-standby service, which selects OpenBao pods that + # have labeled themselves as a cluster follower with `openbao-active: "false"`. + standby: + enabled: true + # Extra annotations for the service definition. This can either be YAML or a + # YAML-formatted multi-line templated string map of the annotations to apply + # to the standby service. + annotations: {} + # Extra labels for the service definition. + # This should be a YAML map of the labels to apply to the standby service + extraLabels: {} + # If enabled, the service selectors will include `app.kubernetes.io/instance: {{ .Release.Name }}` + # When disabled, services may select OpenBao pods not deployed from the chart. + # Does not affect the headless openbao-internal service with `ClusterIP: None` + instanceSelector: + enabled: true + # clusterIP controls whether a Cluster IP address is attached to the + # OpenBao service within Kubernetes. By default, the OpenBao service will + # be given a Cluster IP address, set to None to disable. When disabled + # Kubernetes will create a "headless" service. Headless services can be + # used to communicate with pods directly through DNS instead of a round-robin + # load balancer. + # clusterIP: None + + # Configures the service type for the main OpenBao service. Can be ClusterIP + # or NodePort. + # type: ClusterIP + + # The IP family and IP families options are to set the behaviour in a dual-stack environment. + # Omitting these values will let the service fall back to whatever the CNI dictates the defaults + # should be. + # These are only supported for kubernetes versions >=1.23.0 + # + # Configures the service's supported IP family policy, can be either: + # SingleStack: Single-stack service. The control plane allocates a cluster IP for the Service, using the first configured service cluster IP range. + # PreferDualStack: Allocates IPv4 and IPv6 cluster IPs for the Service. + # RequireDualStack: Allocates Service .spec.ClusterIPs from both IPv4 and IPv6 address ranges. + ipFamilyPolicy: "" + + # Sets the families that should be supported and the order in which they should be applied to ClusterIP as well. + # Can be IPv4 and/or IPv6. + ipFamilies: [] + + # Do not wait for pods to be ready before including them in the services' + # targets. Does not apply to the headless service, which is used for + # cluster-internal communication. + publishNotReadyAddresses: true + + # The externalTrafficPolicy can be set to either Cluster or Local + # and is only valid for LoadBalancer and NodePort service types. + # The default value is Cluster. + # ref: https://kubernetes.io/docs/concepts/services-networking/service/#external-traffic-policy + externalTrafficPolicy: Cluster + + # If type is set to "NodePort", a specific nodePort value can be configured, + # will be random if left blank. + # nodePort: 30000 + + # When HA mode is enabled + # If type is set to "NodePort", a specific nodePort value can be configured, + # will be random if left blank. + # activeNodePort: 30001 + + # When HA mode is enabled + # If type is set to "NodePort", a specific nodePort value can be configured, + # will be random if left blank. + # standbyNodePort: 30002 + + # Port on which OpenBao server is listening + port: 8200 + # Target port to which the service should be mapped to + targetPort: 8200 + + # -- extraPorts is a list of extra ports. Specified as a YAML list. + # This is useful if you need to add additional ports to the server service in dynamic way. + extraPorts: [] + # - name: metrics + # port: 9101 + # targetPort: 9101 + + # Extra annotations for the service definition. This can either be YAML or a + # YAML-formatted multi-line templated string map of the annotations to apply + # to the service. + annotations: {} + # Extra labels for the service definition. + # This should be a YAML map of the labels to apply to the service + extraLabels: {} + + # This configures the OpenBao Statefulset to create a PVC for data + # storage when using the file or raft backend storage engines. + # See https://openbao.org/docs/configuration/storage to know more + dataStorage: + enabled: true + # Size of the PVC created + size: 10Gi + # Location where the PVC will be mounted. + mountPath: "/openbao/data" + # Name of the storage class to use. If null it will use the + # configured default Storage Class. + storageClass: null + # Access Mode of the storage device being used for the PVC + accessMode: ReadWriteOnce + # Annotations to apply to the PVC + annotations: {} + # Labels to apply to the PVC + labels: {} + + # Persistent Volume Claim (PVC) retention policy + # ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#persistentvolumeclaim-retention + # Example: + # persistentVolumeClaimRetentionPolicy: + # whenDeleted: Retain + # whenScaled: Retain + persistentVolumeClaimRetentionPolicy: {} + + # This configures the OpenBao Statefulset to create a PVC for audit + # logs. Once OpenBao is deployed, initialized, and unsealed, OpenBao must + # be configured to use this for audit logs. This will be mounted to + # /openbao/audit + # See https://openbao.org/docs/audit to know more + auditStorage: + enabled: false + # Size of the PVC created + size: 10Gi + # Location where the PVC will be mounted. + mountPath: "/openbao/audit" + # Name of the storage class to use. If null it will use the + # configured default Storage Class. + storageClass: null + # Access Mode of the storage device being used for the PVC + accessMode: ReadWriteOnce + # Annotations to apply to the PVC + annotations: {} + # Labels to apply to the PVC + labels: {} + + # Run OpenBao in "dev" mode. This requires no further setup, no state management, + # and no initialization. This is useful for experimenting with OpenBao without + # needing to unseal, store keys, et. al. All data is lost on restart - do not + # use dev mode for anything other than experimenting. + # See https://openbao.org/docs/concepts/dev-server to know more + dev: + enabled: false + + # Set VAULT_DEV_ROOT_TOKEN_ID value + devRootToken: "root" + + # Run OpenBao in "standalone" mode. This is the default mode that will deploy if + # no arguments are given to helm. This requires a PVC for data storage to use + # the "file" backend. This mode is not highly available and should not be scaled + # past a single replica. + standalone: + enabled: "-" + + # config is a raw string of default configuration when using a Stateful + # deployment. Default is to use a PersistentVolumeClaim mounted at /openbao/data + # and store data there. This is only used when using a Replica count of 1, and + # using a stateful set. This should be HCL. + + # Note: Configuration files are stored in ConfigMaps so sensitive data + # such as passwords should be either mounted through extraSecretEnvironmentVars + # or through a Kube secret. For more information see: + # https://openbao.org/docs/platform/k8s/helm/run/#protecting-sensitive-openbao-configurations + config: | + ui = true + + listener "tcp" { + tls_disable = 1 + address = "[::]:8200" + cluster_address = "[::]:8201" + # Enable unauthenticated metrics access (necessary for Prometheus Operator) + #telemetry { + # unauthenticated_metrics_access = "true" + #} + } + storage "file" { + path = "/openbao/data" + } + + # Example configuration for using auto-unseal, using Google Cloud KMS. The + # GKMS keys must already exist, and the cluster must have a service account + # that is authorized to access GCP KMS. + #seal "gcpckms" { + # project = "openbao-helm-dev" + # region = "global" + # key_ring = "openbao-helm-unseal-kr" + # crypto_key = "openbao-helm-unseal-key" + #} + + # Example configuration for enabling Prometheus metrics in your config. + #telemetry { + # prometheus_retention_time = "30s" + # disable_hostname = true + #} + + # Run OpenBao in "HA" mode. There are no storage requirements unless the audit log + # persistence is required. In HA mode OpenBao will configure itself to use Consul + # for its storage backend. The default configuration provided will work the Consul + # Helm project by default. It is possible to manually configure OpenBao to use a + # different HA backend. + ha: + enabled: false + replicas: 3 + + # Set the api_addr configuration for OpenBao HA + # See https://openbao.org/docs/configuration/#high-availability-parameters + # If set to null, this will be set to the Pod IP Address + apiAddr: null + + # Set the cluster_addr configuration for OpenBao HA + # See https://openbao.org/docs/configuration/#high-availability-parameters + # If set to null, this will be set to https://$(HOSTNAME).{{ template "openbao.fullname" . }}-internal:8201 + clusterAddr: null + + # Enables OpenBao's integrated Raft storage. Unlike the typical HA modes where + # OpenBao's persistence is external (such as Consul), enabling Raft mode will create + # persistent volumes for OpenBao to store data according to the configuration under server.dataStorage. + # The OpenBao cluster will coordinate leader elections and failovers internally. + raft: + # Enables Raft integrated storage + enabled: false + # Set the Node Raft ID to the name of the pod + setNodeId: false + + # config is a raw string of default configuration when using a Stateful + # deployment. + # This should be HCL. + + # Note: Configuration files are stored in ConfigMaps so sensitive data + # such as passwords should be either mounted through extraSecretEnvironmentVars + # or through a Kube secret. For more information see: + # https://openbao.org/docs/platform/k8s/helm/run/#protecting-sensitive-openbao-configurations + config: | + ui = true + + listener "tcp" { + tls_disable = 1 + address = "[::]:8200" + cluster_address = "[::]:8201" + # Enable unauthenticated metrics access (necessary for Prometheus Operator) + #telemetry { + # unauthenticated_metrics_access = "true" + #} + } + + storage "raft" { + path = "/openbao/data" + } + + service_registration "kubernetes" {} + + # config is a raw string of default configuration when using a Stateful + # deployment. Default is to use a Consul for its HA storage backend. + # This should be HCL. + + # Note: Configuration files are stored in ConfigMaps so sensitive data + # such as passwords should be either mounted through extraSecretEnvironmentVars + # or through a Kube secret. For more information see: + # https://openbao.org/docs/platform/k8s/helm/run/#protecting-sensitive-openbao-configurations + config: | + ui = true + + listener "tcp" { + tls_disable = 1 + address = "[::]:8200" + cluster_address = "[::]:8201" + } + storage "consul" { + path = "openbao" + address = "HOST_IP:8500" + } + + service_registration "kubernetes" {} + + # Example configuration for using auto-unseal, using Google Cloud KMS. The + # GKMS keys must already exist, and the cluster must have a service account + # that is authorized to access GCP KMS. + #seal "gcpckms" { + # project = "openbao-helm-dev-246514" + # region = "global" + # key_ring = "openbao-helm-unseal-kr" + # crypto_key = "openbao-helm-unseal-key" + #} + + # Example configuration for enabling Prometheus metrics. + # If you are using Prometheus Operator you can enable a ServiceMonitor resource below. + # You may wish to enable unauthenticated metrics in the listener block above. + #telemetry { + # prometheus_retention_time = "30s" + # disable_hostname = true + #} + + # A disruption budget limits the number of pods of a replicated application + # that are down simultaneously from voluntary disruptions + disruptionBudget: + enabled: true + + # maxUnavailable will default to (n/2)-1 where n is the number of + # replicas. If you'd like a custom value, you can specify an override here. + maxUnavailable: null + + # Definition of the serviceAccount used to run Vault. + # These options are also used when using an external OpenBao server to validate + # Kubernetes tokens. + serviceAccount: + # Specifies whether a service account should be created + create: true + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + # Create a Secret API object to store a non-expiring token for the service account. + # Prior to v1.24.0, Kubernetes used to generate this secret for each service account by default. + # Kubernetes now recommends using short-lived tokens from the TokenRequest API or projected volumes instead if possible. + # For more details, see https://kubernetes.io/docs/concepts/configuration/secret/#serviceaccount-token-secrets + # serviceAccount.create must be equal to 'true' in order to use this feature. + createSecret: false + # Extra annotations for the serviceAccount definition. This can either be + # YAML or a YAML-formatted multi-line templated string map of the + # annotations to apply to the serviceAccount. + annotations: {} + # Extra labels to attach to the serviceAccount + # This should be a YAML map of the labels to apply to the serviceAccount + extraLabels: {} + # Enable or disable a service account role binding with the permissions required for + # OpenBao's Kubernetes service_registration config option. + # See https://openbao.org/docs/configuration/service-registration/kubernetes + serviceDiscovery: + enabled: true + + # Settings for the statefulSet used to run OpenBao. + statefulSet: + # Extra annotations for the statefulSet. This can either be YAML or a + # YAML-formatted multi-line templated string map of the annotations to apply + # to the statefulSet. + annotations: {} + + # Set the pod and container security contexts. + # If not set, these will default to, and for *not* OpenShift: + # pod: + # runAsNonRoot: true + # runAsGroup: {{ .Values.server.gid | default 1000 }} + # runAsUser: {{ .Values.server.uid | default 100 }} + # fsGroup: {{ .Values.server.gid | default 1000 }} + # container: + # allowPrivilegeEscalation: false + # + # If not set, these will default to, and for OpenShift: + # pod: {} + # container: {} + securityContext: + pod: {} + container: {} + + # Should the server pods run on the host network + hostNetwork: false + +# OpenBao UI +ui: + # True if you want to create a Service entry for the OpenBao UI. + # + # serviceType can be used to control the type of service created. For + # example, setting this to "LoadBalancer" will create an external load + # balancer (for supported K8S installations) to access the UI. + enabled: false + publishNotReadyAddresses: true + # The service should only contain selectors for active OpenBao pod + activeOpenbaoPodOnly: false + serviceType: "ClusterIP" + serviceNodePort: null + externalPort: 8200 + targetPort: 8200 + + # The IP family and IP families options are to set the behaviour in a dual-stack environment. + # Omitting these values will let the service fall back to whatever the CNI dictates the defaults + # should be. + # These are only supported for kubernetes versions >=1.23.0 + # + # Configures the service's supported IP family, can be either: + # SingleStack: Single-stack service. The control plane allocates a cluster IP for the Service, using the first configured service cluster IP range. + # PreferDualStack: Allocates IPv4 and IPv6 cluster IPs for the Service. + # RequireDualStack: Allocates Service .spec.ClusterIPs from both IPv4 and IPv6 address ranges. + serviceIPFamilyPolicy: "" + + # Sets the families that should be supported and the order in which they should be applied to ClusterIP as well + # Can be IPv4 and/or IPv6. + serviceIPFamilies: [] + + # The externalTrafficPolicy can be set to either Cluster or Local + # and is only valid for LoadBalancer and NodePort service types. + # The default value is Cluster. + # ref: https://kubernetes.io/docs/concepts/services-networking/service/#external-traffic-policy + externalTrafficPolicy: Cluster + + # loadBalancerSourceRanges: + # - 10.0.0.0/16 + # - 1.78.23.3/32 + + # loadBalancerIP: + + # Extra annotations to attach to the ui service + # This can either be YAML or a YAML-formatted multi-line templated string map + # of the annotations to apply to the ui service + annotations: {} + + # Extra labels for the service definition. + # This should be a YAML map of the labels to apply to the ui service + extraLabels: {} + +# openbao-csi-provider +csi: + # -- True if you want to install a openbao-csi-provider daemonset. + # + # Requires installing the secrets-store-csi-driver separately, see: + # https://secrets-store-csi-driver.sigs.k8s.io/getting-started/installation + # + # With the driver and provider installed, you can mount OpenBao secrets into volumes + # similar to the OpenBao Agent injector, and you can also sync those secrets into + # Kubernetes secrets. + enabled: false + + image: + # -- image registry to use for csi image + registry: "quay.io" + # -- image repo to use for csi image + repository: "openbao/openbao-csi-provider" + # -- image tag to use for csi image + tag: "2.0.0" + # -- image pull policy to use for csi image. if tag is "latest", set to "Always" + pullPolicy: IfNotPresent + + # -- volumes is a list of volumes made available to all containers. These are rendered + # via toYaml rather than pre-processed like the extraVolumes value. + # The purpose is to make it easy to share volumes between containers. + volumes: [] + # - name: tls + # secret: + # secretName: openbao-tls + + # -- volumeMounts is a list of volumeMounts for the main server container. These are rendered + # via toYaml rather than pre-processed like the extraVolumes value. + # The purpose is to make it easy to share volumes between containers. + volumeMounts: [] + # - name: tls + # mountPath: "/openbao/tls" + # readOnly: true + + resources: {} + # resources: + # requests: + # cpu: 50m + # memory: 128Mi + # limits: + # cpu: 50m + # memory: 128Mi + + # Override the default secret name for the CSI Provider's HMAC key used for + # generating secret versions. + hmacSecretName: "" + + # Settings for the daemonSet used to run the provider. + daemonSet: + updateStrategy: + type: RollingUpdate + maxUnavailable: "" + # Extra annotations for the daemonSet. This can either be YAML or a + # YAML-formatted multi-line templated string map of the annotations to apply + # to the daemonSet. + annotations: {} + # Provider host path (must match the CSI provider's path) + providersDir: "/etc/kubernetes/secrets-store-csi-providers" + # Kubelet host path + kubeletRootDir: "/var/lib/kubelet" + # endpoint path for the provider + endpoint: "/provider/openbao.sock" + + # Extra labels to attach to the openbao-csi-provider daemonSet + # This should be a YAML map of the labels to apply to the csi provider daemonSet + extraLabels: {} + # security context for the pod template and container in the csi provider daemonSet + securityContext: + pod: {} + container: {} + + pod: + # Extra annotations for the provider pods. This can either be YAML or a + # YAML-formatted multi-line templated string map of the annotations to apply + # to the pod. + annotations: {} + + # Toleration Settings for provider pods + # This should be either a multi-line string or YAML matching the Toleration array + # in a PodSpec. + tolerations: [] + + # nodeSelector labels for csi pod assignment, formatted as a multi-line string or YAML map. + # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + # Example: + # nodeSelector: + # beta.kubernetes.io/arch: amd64 + nodeSelector: {} + + # Affinity Settings + # This should be either a multi-line string or YAML matching the PodSpec's affinity field. + affinity: {} + + # Extra labels to attach to the openbao-csi-provider pod + # This should be a YAML map of the labels to apply to the csi provider pod + extraLabels: {} + + agent: + enabled: true + extraArgs: [] + + image: + # -- image registry to use for agent image + registry: "quay.io" + # -- image repo to use for agent image + repository: "openbao/openbao" + # -- image tag to use for agent image - defaults to chart appVersion + tag: "" + # -- image pull policy to use for agent image. if tag is "latest", set to "Always" + pullPolicy: IfNotPresent + + logFormat: standard + logLevel: info + + resources: {} + # resources: + # requests: + # memory: 256Mi + # cpu: 250m + # limits: + # memory: 256Mi + # cpu: 250m + + # Priority class for csi pods + priorityClassName: "" + + serviceAccount: + # Extra annotations for the serviceAccount definition. This can either be + # YAML or a YAML-formatted multi-line templated string map of the + # annotations to apply to the serviceAccount. + annotations: {} + + # Extra labels to attach to the openbao-csi-provider serviceAccount + # This should be a YAML map of the labels to apply to the csi provider serviceAccount + extraLabels: {} + + # Used to configure readinessProbe for the pods. + readinessProbe: + # When a probe fails, Kubernetes will try failureThreshold times before giving up + failureThreshold: 2 + # Number of seconds after the container has started before probe initiates + initialDelaySeconds: 5 + # How often (in seconds) to perform the probe + periodSeconds: 5 + # Minimum consecutive successes for the probe to be considered successful after having failed + successThreshold: 1 + # Number of seconds after which the probe times out. + timeoutSeconds: 3 + # Used to configure livenessProbe for the pods. + livenessProbe: + # When a probe fails, Kubernetes will try failureThreshold times before giving up + failureThreshold: 2 + # Number of seconds after the container has started before probe initiates + initialDelaySeconds: 5 + # How often (in seconds) to perform the probe + periodSeconds: 5 + # Minimum consecutive successes for the probe to be considered successful after having failed + successThreshold: 1 + # Number of seconds after which the probe times out. + timeoutSeconds: 3 + + # Enables debug logging. + debug: false + + # Pass arbitrary additional arguments to openbao-csi-provider. + # See https://openbao.org/docs/platform/k8s/csi/configurations + # for the available command line flags. + extraArgs: [] + +# OpenBao is able to collect and publish various runtime metrics. +# Enabling this feature requires setting adding `telemetry{}` stanza to +# the OpenBao configuration. There are a few examples included in the `config` sections above. +# +# For more information see: +# https://openbao.org/docs/configuration/telemetry +# https://openbao.org/docs/internals/telemetry +serverTelemetry: + # Enable support for the Prometheus Operator. If authorization is not required for + # OpenBao's metrics endpoint, the following OpenBao server `telemetry{}` config must be included + # in the `listener "tcp"{}` stanza + # telemetry { + # unauthenticated_metrics_access = "true" + # } + # + # See the `standalone.config` for a more complete example of this. + # + # In addition, a top level `telemetry{}` stanza must also be included in the OpenBao configuration: + # + # example: + # telemetry { + # prometheus_retention_time = "30s" + # disable_hostname = true + # } + # + # Configuration for monitoring the OpenBao server. + serviceMonitor: + # The Prometheus operator *must* be installed before enabling this feature, + # if not the chart will fail to install due to missing CustomResourceDefinitions + # provided by the operator. + # + # Instructions on how to install the Helm chart can be found here: + # https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack + # More information can be found here: + # https://github.com/prometheus-operator/prometheus-operator + # https://github.com/prometheus-operator/kube-prometheus + + # Enable deployment of the OpenBao Server ServiceMonitor CustomResource. + enabled: false + + # Selector labels to add to the ServiceMonitor. + # When empty, defaults to: + # release: prometheus + selectors: {} + + # -- Port which Prometheus uses when scraping metrics. If empty will use `openbao.scheme` helper for its value + port: "" + + # -- scheme to use when Prometheus scrapes metrics. If empty will use `openbao.scheme` helper for its value + scheme: "" + + # Interval at which Prometheus scrapes metrics + interval: 30s + + # Timeout for Prometheus scrapes + scrapeTimeout: 10s + + # tlsConfig used for scraping the Vault metrics API. + tlsConfig: {} + + # authorization used for scraping the Vault metrics API. + authorization: {} + + # scrapeClass to be used by the serviceMonitor + scrapeClass: "" + + prometheusRules: + # The Prometheus operator *must* be installed before enabling this feature, + # if not the chart will fail to install due to missing CustomResourceDefinitions + # provided by the operator. + + # Deploy the PrometheusRule custom resource for AlertManager based alerts. + # Requires that AlertManager is properly deployed. + enabled: false + + # Selector labels to add to the PrometheusRules. + # When empty, defaults to: + # release: prometheus + selectors: {} + + # Some example rules. + rules: [] + # - alert: vault-HighResponseTime + # annotations: + # message: The response time of OpenBao is over 500ms on average over the last 5 minutes. + # expr: vault_core_handle_request{quantile="0.5", namespace="mynamespace"} > 500 + # for: 5m + # labels: + # severity: warning + # - alert: vault-HighResponseTime + # annotations: + # message: The response time of OpenBao is over 1s on average over the last 10 minutes. + # expr: vault_core_handle_request{quantile="0.5", namespace="mynamespace"} > 1000 + # for: 10m + # labels: + # severity: critical + + grafanaDashboard: + # Enable deployment of the OpenBao Grafana dashboard. + # https://grafana.com/grafana/dashboards/23725-openbao + enabled: false + + # Add `grafana_dashboard: "1"` default label + defaultLabel: true + + # Extra labels for dashboard ConfigMap + extraLabel: {} + + # Extra annotations for dashboard ConfigMap + extraAnnotations: {} + +# extraObjects allows you to add any extra Kubernetes manifests to this chart +extraObjects: [] +# Examples: +# Defining as a Structured YAML Object Example: +# extraObjects: +# - apiVersion: v1 +# kind: ConfigMap +# metadata: +# name: cert-manager-configmap-{{ .Release.Name }} +# +# Using a String for Advanced Templating Example: +# extraObjects: +# - | +# apiVersion: v1 +# kind: ConfigMap +# metadata: +# name: cert-manager-configmap-{{ include "some-other-template" }} + +# Snapshot Agent Configuration +snapshotAgent: + # whether or not to enable the snapshot agent cronjob + enabled: false + # extra Annotations for the job + annotations: {} + # schedule of the cronjob + schedule: "*/15 * * * *" + restartPolicy: OnFailure + # service account settings for the snapshot agent + serviceAccount: + create: true + name: "" + annotations: {} + extraLabels: {} + # The image settings for the snapshot agent + image: + repository: ghcr.io/openbao/openbao-snapshot-agent + tag: 0.2.4 + + # -- List of extraVolumes made available to the snapshot cronjob container. + extraVolumes: [] + # - name: openbao-tls + # secret: + # defaultMode: 420 + # secretName: openbao-tls + + # -- List of additional volumeMounts for the snapshot cronjob container. + extraVolumeMounts: [] + # - mountPath: /openbao/tls/ca.crt + # name: openbao-tls + # readOnly: true + # subPath: ca.crt + + # s3CredentialsSecret to use + s3CredentialsSecret: "my-s3-credentials" + + # configuration for the snapshot agent + config: + s3Host: "s3.eu-east-1.amazonaws.com" + s3Bucket: "openbao-snapshots" + s3Uri: "s3://openbao-snapshots" + s3ExpireDays: "14" + s3cmdExtraFlag: "-v" + baoAuthPath: "kubernetes" + baoRole: "snapshot" + + # configuration of the CronJobs resources + resources: {} + + # -- Map of extra environment variables to set in the snapshot-agent cronjob + extraEnvironmentVars: {} + # BAO_CACERT: /openbao/tls/ca.crt + + # -- List of extra environment variables to set in the snapshot-agent cronjob + # These variables take value from existing Secret objects. + extraSecretEnvironmentVars: [] + # - envName: AWS_SECRET_ACCESS_KEY + # secretName: openbao + # secretKey: AWS_SECRET_ACCESS_KEY + + # Security context for the pod template and the snapshotAgent container + # The default pod securityContext is: + # runAsNonRoot: true + # runAsGroup: {{ .Values.snapshotAgent.gid | default 1000 }} + # runAsUser: {{ .Values.snapshotAgent.uid | default 100 }} + # fsGroup: {{ .Values.snapshotAgent.gid | default 1000 }} + # and for container is + # allowPrivilegeEscalation: false + # capabilities: + # drop: + # - ALL + securityContext: + pod: {} + container: {} diff --git a/packages/system/openbao/values.yaml b/packages/system/openbao/values.yaml new file mode 100644 index 00000000..957f37a0 --- /dev/null +++ b/packages/system/openbao/values.yaml @@ -0,0 +1,5 @@ +openbao: + injector: + enabled: false + csi: + enabled: false diff --git a/packages/system/opencost/Makefile b/packages/system/opencost/Makefile index cfef2167..43ee7032 100644 --- a/packages/system/opencost/Makefile +++ b/packages/system/opencost/Makefile @@ -1,7 +1,7 @@ export NAME=opencost export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package-system.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/opensearch-operator/.helmignore b/packages/system/opensearch-operator/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/packages/system/opensearch-operator/.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/system/opensearch-operator/Chart.yaml b/packages/system/opensearch-operator/Chart.yaml new file mode 100644 index 00000000..a991bdca --- /dev/null +++ b/packages/system/opensearch-operator/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-opensearch-operator +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/opensearch-operator/Makefile b/packages/system/opensearch-operator/Makefile new file mode 100644 index 00000000..36522495 --- /dev/null +++ b/packages/system/opensearch-operator/Makefile @@ -0,0 +1,10 @@ +export NAME=opensearch-operator +export NAMESPACE=cozy-$(NAME) + +include ../../../hack/package.mk + +update: + rm -rf charts + helm repo add opensearch-operator https://opensearch-project.github.io/opensearch-k8s-operator/ + helm repo update opensearch-operator + helm pull opensearch-operator/opensearch-operator --version 2.8.0 --untar --untardir charts diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/CHANGELOG.md b/packages/system/opensearch-operator/charts/opensearch-operator/CHANGELOG.md new file mode 100644 index 00000000..1866ab55 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/CHANGELOG.md @@ -0,0 +1,61 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +--- +## [Unreleased] +### Added +- Added support for custom image used by `kubeRbacProxy`. +### Changed +### Deprecated +### Removed +### Fixed +### Security + +--- +## [2.0.0] +### Added +### Changed +- Modified `version` to `2.0.0` and `appVersion` to `v2.0`. +- Allow chart image tag to pick from `appVersion`, unless explicitly passed `tag` values in `values.yaml` file. +### Deprecated +### Removed +### Fixed +### Security + +--- +## [1.0.3] +### Added +### Changed +- Added missing spec `dashboards.additionalConfig` +### Deprecated +### Removed +### Fixed +### Security + +--- +## [1.0.2] +### Added +### Changed +- Added README.md file to charts/ folder. +### Deprecated +### Removed +### Fixed +### Security + +--- +## [1.0.1] +### Added +### Changed +- Updated version to 1.0.1 +### Deprecated +### Removed +### Fixed +### Security + +[Unreleased]: https://github.com/opensearch-project/opensearch-k8s-operator/compare/opensearch-operator-2.0.0...HEAD +[2.0.0]: https://github.com/opensearch-project/opensearch-k8s-operator/compare/opensearch-operator-1.0.3...opensearch-operator-2.0.0 +[1.0.3]: https://github.com/opensearch-project/opensearch-k8s-operator/compare/opensearch-operator-1.0.2...opensearch-operator-1.0.3 +[1.0.2]: https://github.com/opensearch-project/opensearch-k8s-operator/compare/opensearch-operator-1.0.1...opensearch-operator-1.0.2 diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/Chart.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/Chart.yaml new file mode 100644 index 00000000..331cf1e2 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: 2.8.0 +description: The OpenSearch Operator Helm chart for Kubernetes +name: opensearch-operator +type: application +version: 2.8.0 diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/README.md b/packages/system/opensearch-operator/charts/opensearch-operator/README.md new file mode 100644 index 00000000..dc63c250 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/README.md @@ -0,0 +1,29 @@ +# OpenSearch-k8s-operator + +The Kubernetes [OpenSearch Operator](https://github.com/opensearch-project/opensearch-k8s-operator) is used for automating the deployment, provisioning, management, and orchestration of OpenSearch clusters and OpenSearch dashboards. + +## Getting started + +The Operator can be easily installed using helm on any CNCF-certified Kubernetes cluster. Please refer to the [User Guide](https://github.com/opensearch-project/opensearch-k8s-operator/blob/main/docs/userguide/main.md) for more information. + +### Installation Using Helm + +#### Get Repo Info +``` +helm repo add opensearch-operator https://opensearch-project.github.io/opensearch-k8s-operator/ +helm repo update +``` +#### Install Chart +``` +helm install [RELEASE_NAME] opensearch-operator/opensearch-operator +``` +#### Uninstall Chart +``` +helm uninstall [RELEASE_NAME] +``` +#### Upgrade Chart +``` +helm repo update +helm upgrade [RELEASE_NAME] opensearch-operator/opensearch-operator +``` + diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchactiongroups.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchactiongroups.yaml new file mode 100644 index 00000000..8ba4c7b2 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchactiongroups.yaml @@ -0,0 +1,94 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.0 + name: opensearchactiongroups.opensearch.opster.io +spec: + group: opensearch.opster.io + names: + kind: OpensearchActionGroup + listKind: OpensearchActionGroupList + plural: opensearchactiongroups + shortNames: + - opensearchactiongroup + singular: opensearchactiongroup + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: OpensearchActionGroup is the Schema for the opensearchactiongroups + API + 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: OpensearchActionGroupSpec defines the desired state of OpensearchActionGroup + properties: + allowedActions: + items: + type: string + type: array + description: + type: string + opensearchCluster: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: + type: string + required: + - allowedActions + - opensearchCluster + type: object + status: + description: OpensearchActionGroupStatus defines the observed state of + OpensearchActionGroup + properties: + existingActionGroup: + type: boolean + managedCluster: + description: |- + UID is a type that holds unique ID values, including UUIDs. Because we + don't ONLY use UUIDs, this is an alias to string. Being a type captures + intent and helps make sure that UIDs and names do not get conflated. + type: string + reason: + type: string + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchclusters.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchclusters.yaml new file mode 100644 index 00000000..063bbd00 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchclusters.yaml @@ -0,0 +1,6372 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.0 + name: opensearchclusters.opensearch.opster.io +spec: + group: opensearch.opster.io + names: + kind: OpenSearchCluster + listKind: OpenSearchClusterList + plural: opensearchclusters + shortNames: + - os + - opensearch + singular: opensearchcluster + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.health + name: health + type: string + - description: Available nodes + jsonPath: .status.availableNodes + name: nodes + type: integer + - description: Opensearch version + jsonPath: .status.version + name: version + type: string + - jsonPath: .status.phase + name: phase + type: string + - jsonPath: .metadata.creationTimestamp + name: age + type: date + name: v1 + schema: + openAPIV3Schema: + description: Es is the Schema for the es API + 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: ClusterSpec defines the desired state of OpenSearchCluster + properties: + bootstrap: + properties: + additionalConfig: + additionalProperties: + type: string + description: Extra items to add to the opensearch.yml, defaults + to General.AdditionalConfig + type: object + affinity: + description: Affinity is a group of affinity scheduling rules. + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for + the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with + the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the + corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. + The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, etc. + as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + jvm: + type: string + keystore: + items: + properties: + keyMappings: + additionalProperties: + type: string + description: Key mappings from secret to keystore keys + type: object + secret: + description: Secret containing key value pairs + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: object + type: array + nodeSelector: + additionalProperties: + type: string + type: object + pluginsList: + items: + type: string + type: array + resources: + description: ResourceRequirements describes the compute resource + requirements. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + tolerations: + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + confMgmt: + description: ConfMgmt defines which additional services will be deployed + properties: + VerUpdate: + type: boolean + autoScaler: + type: boolean + smartScaler: + type: boolean + type: object + dashboards: + properties: + additionalConfig: + additionalProperties: + type: string + description: Additional properties for opensearch_dashboards.yaml + type: object + additionalVolumes: + items: + properties: + configMap: + description: ConfigMap to use to populate the volume + properties: + defaultMode: + description: |- + defaultMode is optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within a + volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: CSI object to use to populate the volume + properties: + driver: + description: |- + driver is the name of the CSI driver that handles this volume. + Consult with your admin for the correct name as registered in the cluster. + type: string + fsType: + description: |- + fsType to mount. Ex. "ext4", "xfs", "ntfs". + If not provided, the empty value is passed to the associated CSI driver + which will determine the default filesystem to apply. + type: string + nodePublishSecretRef: + description: |- + nodePublishSecretRef is a reference to the secret object containing + sensitive information to pass to the CSI driver to complete the CSI + NodePublishVolume and NodeUnpublishVolume calls. + This field is optional, and may be empty if no secret is required. If the + secret object contains more than one secret, all secret references are passed. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: |- + readOnly specifies a read-only configuration for the volume. + Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: |- + volumeAttributes stores driver-specific properties that are passed to the CSI + driver. Consult your driver's documentation for supported values. + type: object + required: + - driver + type: object + emptyDir: + description: EmptyDir to use to populate the volume + properties: + medium: + description: |- + medium represents what type of storage medium should back this directory. + The default is "" which means to use the node's default medium. + Must be an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: |- + sizeLimit is the total amount of local storage required for this EmptyDir volume. + The size limit is also applicable for memory medium. + The maximum usage on memory medium EmptyDir would be the minimum value between + the SizeLimit specified here and the sum of memory limits of all containers in a pod. + The default is nil which means that the limit is undefined. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + name: + description: Name to use for the volume. Required. + type: string + path: + description: Path in the container to mount the volume at. + Required. + type: string + projected: + description: Projected object to use to populate the volume + properties: + defaultMode: + description: |- + defaultMode are the mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + sources: + description: |- + sources is the list of volume projections. Each entry in this list + handles one source. + items: + description: |- + Projection that may be projected along with other supported volume types. + Exactly one of these fields must be set. + properties: + clusterTrustBundle: + description: |- + ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field + of ClusterTrustBundle objects in an auto-updating file. + + Alpha, gated by the ClusterTrustBundleProjection feature gate. + + ClusterTrustBundle objects can either be selected by name, or by the + combination of signer name and a label selector. + + Kubelet performs aggressive normalization of the PEM contents written + into the pod filesystem. Esoteric PEM features such as inter-block + comments and block headers are stripped. Certificates are deduplicated. + The ordering of certificates within the file is arbitrary, and Kubelet + may change the order over time. + properties: + labelSelector: + description: |- + Select all ClusterTrustBundles that match this label selector. Only has + effect if signerName is set. Mutually-exclusive with name. If unset, + interpreted as "match nothing". If set but empty, interpreted as "match + everything". + 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 + name: + description: |- + Select a single ClusterTrustBundle by object name. Mutually-exclusive + with signerName and labelSelector. + type: string + optional: + description: |- + If true, don't block pod startup if the referenced ClusterTrustBundle(s) + aren't available. If using name, then the named ClusterTrustBundle is + allowed not to exist. If using signerName, then the combination of + signerName and labelSelector is allowed to match zero + ClusterTrustBundles. + type: boolean + path: + description: Relative path from the volume + root to write the bundle. + type: string + signerName: + description: |- + Select all ClusterTrustBundles that match this signer name. + Mutually-exclusive with name. The contents of all selected + ClusterTrustBundles will be unified and deduplicated. + type: string + required: + - path + type: object + configMap: + description: configMap information about the configMap + data to project + properties: + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: optional specify whether the + ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about the + downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name, namespace and uid are supported.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: |- + Optional: mode bits used to set permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file to + be created. Must not be absolute or + contain the ''..'' path. Must be utf-8 + encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. + properties: + containerName: + description: 'Container name: required + for volumes, optional for env + vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + secret: + description: secret information about the secret + data to project + properties: + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: optional field specify whether + the Secret or its key must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information + about the serviceAccountToken data to project + properties: + audience: + description: |- + audience is the intended audience of the token. A recipient of a token + must identify itself with an identifier specified in the audience of the + token, and otherwise should reject the token. The audience defaults to the + identifier of the apiserver. + type: string + expirationSeconds: + description: |- + expirationSeconds is the requested duration of validity of the service + account token. As the token approaches expiration, the kubelet volume + plugin will proactively rotate the service account token. The kubelet will + start trying to rotate the token if the token is older than 80 percent of + its time to live or if the token is older than 24 hours.Defaults to 1 hour + and must be at least 10 minutes. + format: int64 + type: integer + path: + description: |- + path is the path relative to the mount point of the file to project the + token into. + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + restartPods: + description: Whether to restart the pods on content change + type: boolean + secret: + description: Secret to use populate the volume + properties: + defaultMode: + description: |- + defaultMode is Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values + for mode bits. Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: |- + items If unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within a + volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + description: optional field specify whether the Secret + or its keys must be defined + type: boolean + secretName: + description: |- + secretName is the name of the secret in the pod's namespace to use. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + type: string + type: object + subPath: + description: SubPath of the referenced volume to mount. + type: string + required: + - name + - path + type: object + type: array + affinity: + description: Affinity is a group of affinity scheduling rules. + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for + the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with + the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the + corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. + The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, etc. + as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + annotations: + additionalProperties: + type: string + type: object + basePath: + description: Base Path for Opensearch Clusters running behind + a reverse proxy + type: string + enable: + type: boolean + env: + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be a + C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + image: + type: string + imagePullPolicy: + description: PullPolicy describes a policy for if/when to pull + a container image + type: string + imagePullSecrets: + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: array + labels: + additionalProperties: + type: string + type: object + nodeSelector: + additionalProperties: + type: string + type: object + opensearchCredentialsSecret: + description: Secret that contains fields username and password + for dashboards to use to login to opensearch, must only be supplied + if a custom securityconfig is provided + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + pluginsList: + items: + type: string + type: array + podSecurityContext: + description: Set security context for the dashboards pods + properties: + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxChangePolicy: + description: |- + seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod. + It has no effect on nodes that do not support SELinux or to volumes does not support SELinux. + Valid values are "MountOption" and "Recursive". + + "Recursive" means relabeling of all files on all Pod volumes by the container runtime. + This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node. + + "MountOption" mounts all eligible Pod volumes with `-o context` mount option. + This requires all Pods that share the same volume to use the same SELinux label. + It is not possible to share the same volume among privileged and unprivileged Pods. + Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes + whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their + CSIDriver instance. Other volumes are always re-labelled recursively. + "MountOption" value is allowed only when SELinuxMount feature gate is enabled. + + If not specified and SELinuxMount feature gate is enabled, "MountOption" is used. + If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes + and "Recursive" for all other volumes. + + This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers. + + All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state. + Note that this field cannot be set when spec.os.name is windows. + type: string + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options within a container's SecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the + GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + replicas: + format: int32 + type: integer + resources: + description: ResourceRequirements describes the compute resource + requirements. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + securityContext: + description: Set security context for the dashboards pods' container + properties: + allowPrivilegeEscalation: + description: |- + AllowPrivilegeEscalation controls whether a process can gain more + privileges than its parent process. This bool directly controls if + the no_new_privs flag will be set on the container process. + AllowPrivilegeEscalation is true always when the container is: + 1) run as Privileged + 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows. + type: boolean + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by this container. If set, this profile + overrides the pod's appArmorProfile. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + capabilities: + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. + Note that this field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: |- + procMount denotes the type of proc mount to use for the containers. + The default value is Default which uses the container runtime defaults for + readonly paths and masked paths. + This requires the ProcMountType feature flag to be enabled. + Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: |- + Whether this container has a read-only root filesystem. + Default is false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by this container. If seccomp options are + provided at both the pod & container level, the container options + override the pod options. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the + GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + service: + properties: + labels: + additionalProperties: + type: string + type: object + loadBalancerSourceRanges: + items: + type: string + type: array + type: + default: ClusterIP + description: Service Type string describes ingress methods + for a service + enum: + - ClusterIP + - NodePort + - LoadBalancer + type: string + type: object + tls: + properties: + caSecret: + description: Optional, secret that contains the ca certificate + as ca.crt. If this and generate=true is set the existing + CA cert from that secret is used to generate the node certs. + In this case must contain ca.crt and ca.key fields + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + enable: + description: Enable HTTPS for Dashboards + type: boolean + generate: + description: Generate certificate, if false secret must be + provided + type: boolean + secret: + description: Optional, name of a TLS secret that contains + ca.crt, tls.key and tls.crt data. If ca.crt is in a different + secret provide it via the caSecret field + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: object + tolerations: + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + version: + type: string + required: + - replicas + - version + type: object + general: + description: |- + INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + Important: Run "make" to regenerate code after modifying this file + properties: + additionalConfig: + additionalProperties: + type: string + description: Extra items to add to the opensearch.yml + type: object + additionalVolumes: + description: Additional volumes to mount to all pods in the cluster + items: + properties: + configMap: + description: ConfigMap to use to populate the volume + properties: + defaultMode: + description: |- + defaultMode is optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within a + volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: CSI object to use to populate the volume + properties: + driver: + description: |- + driver is the name of the CSI driver that handles this volume. + Consult with your admin for the correct name as registered in the cluster. + type: string + fsType: + description: |- + fsType to mount. Ex. "ext4", "xfs", "ntfs". + If not provided, the empty value is passed to the associated CSI driver + which will determine the default filesystem to apply. + type: string + nodePublishSecretRef: + description: |- + nodePublishSecretRef is a reference to the secret object containing + sensitive information to pass to the CSI driver to complete the CSI + NodePublishVolume and NodeUnpublishVolume calls. + This field is optional, and may be empty if no secret is required. If the + secret object contains more than one secret, all secret references are passed. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: |- + readOnly specifies a read-only configuration for the volume. + Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: |- + volumeAttributes stores driver-specific properties that are passed to the CSI + driver. Consult your driver's documentation for supported values. + type: object + required: + - driver + type: object + emptyDir: + description: EmptyDir to use to populate the volume + properties: + medium: + description: |- + medium represents what type of storage medium should back this directory. + The default is "" which means to use the node's default medium. + Must be an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: |- + sizeLimit is the total amount of local storage required for this EmptyDir volume. + The size limit is also applicable for memory medium. + The maximum usage on memory medium EmptyDir would be the minimum value between + the SizeLimit specified here and the sum of memory limits of all containers in a pod. + The default is nil which means that the limit is undefined. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + name: + description: Name to use for the volume. Required. + type: string + path: + description: Path in the container to mount the volume at. + Required. + type: string + projected: + description: Projected object to use to populate the volume + properties: + defaultMode: + description: |- + defaultMode are the mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + sources: + description: |- + sources is the list of volume projections. Each entry in this list + handles one source. + items: + description: |- + Projection that may be projected along with other supported volume types. + Exactly one of these fields must be set. + properties: + clusterTrustBundle: + description: |- + ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field + of ClusterTrustBundle objects in an auto-updating file. + + Alpha, gated by the ClusterTrustBundleProjection feature gate. + + ClusterTrustBundle objects can either be selected by name, or by the + combination of signer name and a label selector. + + Kubelet performs aggressive normalization of the PEM contents written + into the pod filesystem. Esoteric PEM features such as inter-block + comments and block headers are stripped. Certificates are deduplicated. + The ordering of certificates within the file is arbitrary, and Kubelet + may change the order over time. + properties: + labelSelector: + description: |- + Select all ClusterTrustBundles that match this label selector. Only has + effect if signerName is set. Mutually-exclusive with name. If unset, + interpreted as "match nothing". If set but empty, interpreted as "match + everything". + 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 + name: + description: |- + Select a single ClusterTrustBundle by object name. Mutually-exclusive + with signerName and labelSelector. + type: string + optional: + description: |- + If true, don't block pod startup if the referenced ClusterTrustBundle(s) + aren't available. If using name, then the named ClusterTrustBundle is + allowed not to exist. If using signerName, then the combination of + signerName and labelSelector is allowed to match zero + ClusterTrustBundles. + type: boolean + path: + description: Relative path from the volume + root to write the bundle. + type: string + signerName: + description: |- + Select all ClusterTrustBundles that match this signer name. + Mutually-exclusive with name. The contents of all selected + ClusterTrustBundles will be unified and deduplicated. + type: string + required: + - path + type: object + configMap: + description: configMap information about the configMap + data to project + properties: + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: optional specify whether the + ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about the + downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name, namespace and uid are supported.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: |- + Optional: mode bits used to set permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file to + be created. Must not be absolute or + contain the ''..'' path. Must be utf-8 + encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. + properties: + containerName: + description: 'Container name: required + for volumes, optional for env + vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + secret: + description: secret information about the secret + data to project + properties: + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: optional field specify whether + the Secret or its key must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information + about the serviceAccountToken data to project + properties: + audience: + description: |- + audience is the intended audience of the token. A recipient of a token + must identify itself with an identifier specified in the audience of the + token, and otherwise should reject the token. The audience defaults to the + identifier of the apiserver. + type: string + expirationSeconds: + description: |- + expirationSeconds is the requested duration of validity of the service + account token. As the token approaches expiration, the kubelet volume + plugin will proactively rotate the service account token. The kubelet will + start trying to rotate the token if the token is older than 80 percent of + its time to live or if the token is older than 24 hours.Defaults to 1 hour + and must be at least 10 minutes. + format: int64 + type: integer + path: + description: |- + path is the path relative to the mount point of the file to project the + token into. + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + restartPods: + description: Whether to restart the pods on content change + type: boolean + secret: + description: Secret to use populate the volume + properties: + defaultMode: + description: |- + defaultMode is Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values + for mode bits. Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: |- + items If unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within a + volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + description: optional field specify whether the Secret + or its keys must be defined + type: boolean + secretName: + description: |- + secretName is the name of the secret in the pod's namespace to use. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + type: string + type: object + subPath: + description: SubPath of the referenced volume to mount. + type: string + required: + - name + - path + type: object + type: array + annotations: + additionalProperties: + type: string + description: Adds support for annotations in services + type: object + command: + type: string + defaultRepo: + type: string + drainDataNodes: + description: Drain data nodes controls whether to drain data notes + on rolling restart operations + type: boolean + httpPort: + default: 9200 + format: int32 + type: integer + image: + type: string + imagePullPolicy: + description: PullPolicy describes a policy for if/when to pull + a container image + type: string + imagePullSecrets: + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: array + keystore: + description: Populate opensearch keystore before startup + items: + properties: + keyMappings: + additionalProperties: + type: string + description: Key mappings from secret to keystore keys + type: object + secret: + description: Secret containing key value pairs + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: object + type: array + monitoring: + properties: + enable: + type: boolean + labels: + additionalProperties: + type: string + type: object + monitoringUserSecret: + type: string + pluginUrl: + type: string + scrapeInterval: + type: string + tlsConfig: + properties: + insecureSkipVerify: + type: boolean + serverName: + type: string + type: object + type: object + pluginsList: + items: + type: string + type: array + podSecurityContext: + description: Set security context for the cluster pods + properties: + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxChangePolicy: + description: |- + seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod. + It has no effect on nodes that do not support SELinux or to volumes does not support SELinux. + Valid values are "MountOption" and "Recursive". + + "Recursive" means relabeling of all files on all Pod volumes by the container runtime. + This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node. + + "MountOption" mounts all eligible Pod volumes with `-o context` mount option. + This requires all Pods that share the same volume to use the same SELinux label. + It is not possible to share the same volume among privileged and unprivileged Pods. + Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes + whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their + CSIDriver instance. Other volumes are always re-labelled recursively. + "MountOption" value is allowed only when SELinuxMount feature gate is enabled. + + If not specified and SELinuxMount feature gate is enabled, "MountOption" is used. + If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes + and "Recursive" for all other volumes. + + This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers. + + All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state. + Note that this field cannot be set when spec.os.name is windows. + type: string + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options within a container's SecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the + GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + securityContext: + description: Set security context for the cluster pods' container + properties: + allowPrivilegeEscalation: + description: |- + AllowPrivilegeEscalation controls whether a process can gain more + privileges than its parent process. This bool directly controls if + the no_new_privs flag will be set on the container process. + AllowPrivilegeEscalation is true always when the container is: + 1) run as Privileged + 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows. + type: boolean + appArmorProfile: + description: |- + appArmorProfile is the AppArmor options to use by this container. If set, this profile + overrides the pod's appArmorProfile. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile loaded on the node that should be used. + The profile must be preconfigured on the node to work. + Must match the loaded name of the profile. + Must be set if and only if type is "Localhost". + type: string + type: + description: |- + type indicates which kind of AppArmor profile will be applied. + Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. + type: string + required: + - type + type: object + capabilities: + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. + Note that this field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: |- + procMount denotes the type of proc mount to use for the containers. + The default value is Default which uses the container runtime defaults for + readonly paths and masked paths. + This requires the ProcMountType feature flag to be enabled. + Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: |- + Whether this container has a read-only root filesystem. + Default is false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by this container. If seccomp options are + provided at both the pod & container level, the container options + override the pod options. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the + GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + serviceAccount: + type: string + serviceName: + type: string + setVMMaxMapCount: + type: boolean + snapshotRepositories: + items: + properties: + name: + type: string + settings: + additionalProperties: + type: string + type: object + type: + type: string + required: + - name + - type + type: object + type: array + vendor: + enum: + - Opensearch + - Op + - OP + - os + - opensearch + type: string + version: + type: string + required: + - serviceName + type: object + initHelper: + properties: + image: + type: string + imagePullPolicy: + description: PullPolicy describes a policy for if/when to pull + a container image + type: string + imagePullSecrets: + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: array + resources: + description: ResourceRequirements describes the compute resource + requirements. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + version: + type: string + type: object + nodePools: + items: + properties: + additionalConfig: + additionalProperties: + type: string + type: object + affinity: + description: Affinity is a group of affinity scheduling rules. + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for + the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the + corresponding nodeSelectorTerm, in the range + 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. + The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. + co-locate this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules + (e.g. avoid putting this pod in the same node, zone, etc. + as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + 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. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + annotations: + additionalProperties: + type: string + type: object + component: + type: string + diskSize: + type: string + env: + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be + a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + jvm: + type: string + labels: + additionalProperties: + type: string + type: object + nodeSelector: + additionalProperties: + type: string + type: object + pdb: + properties: + enable: + type: boolean + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + persistence: + description: PersistencConfig defines options for data persistence + properties: + emptyDir: + description: |- + Represents an empty directory for a pod. + Empty directory volumes support ownership management and SELinux relabeling. + properties: + medium: + description: |- + medium represents what type of storage medium should back this directory. + The default is "" which means to use the node's default medium. + Must be an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: |- + sizeLimit is the total amount of local storage required for this EmptyDir volume. + The size limit is also applicable for memory medium. + The maximum usage on memory medium EmptyDir would be the minimum value between + the SizeLimit specified here and the sum of memory limits of all containers in a pod. + The default is nil which means that the limit is undefined. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + description: |- + Represents a host path mapped into a pod. + Host path volumes do not support ownership management or SELinux relabeling. + properties: + path: + description: |- + path of the directory on the host. + If the path is a symlink, it will follow the link to the real path. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + type: string + type: + description: |- + type for HostPath Volume + Defaults to "" + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + type: string + required: + - path + type: object + pvc: + properties: + accessModes: + items: + type: string + type: array + storageClass: + type: string + type: object + type: object + priorityClassName: + type: string + probes: + properties: + liveness: + properties: + failureThreshold: + format: int32 + type: integer + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + readiness: + properties: + failureThreshold: + format: int32 + type: integer + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + startup: + properties: + failureThreshold: + format: int32 + type: integer + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + type: object + replicas: + format: int32 + type: integer + resources: + description: ResourceRequirements describes the compute resource + requirements. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + roles: + items: + type: string + type: array + tolerations: + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + topologySpreadConstraints: + items: + description: TopologySpreadConstraint specifies how to spread + matching pods among the given topology. + properties: + labelSelector: + description: |- + LabelSelector is used to find matching pods. + Pods that match this label selector are counted to determine the number of pods + in their corresponding topology domain. + 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 + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select the pods over which + spreading will be calculated. The keys are used to lookup values from the + incoming pod labels, those key-value labels are ANDed with labelSelector + to select the group of existing pods over which spreading will be calculated + for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + MatchLabelKeys cannot be set when LabelSelector isn't set. + Keys that don't exist in the incoming pod labels will + be ignored. A null or empty list means only match against labelSelector. + + This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + description: |- + MaxSkew describes the degree to which pods may be unevenly distributed. + When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference + between the number of matching pods in the target topology and the global minimum. + The global minimum is the minimum number of matching pods in an eligible domain + or zero if the number of eligible domains is less than MinDomains. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 2/2/1: + In this case, the global minimum is 1. + | zone1 | zone2 | zone3 | + | P P | P P | P | + - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; + scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) + violate MaxSkew(1). + - if MaxSkew is 2, incoming pod can be scheduled onto any zone. + When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence + to topologies that satisfy it. + It's a required field. Default value is 1 and 0 is not allowed. + format: int32 + type: integer + minDomains: + description: |- + MinDomains indicates a minimum number of eligible domains. + When the number of eligible domains with matching topology keys is less than minDomains, + Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. + And when the number of eligible domains with matching topology keys equals or greater than minDomains, + this value has no effect on scheduling. + As a result, when the number of eligible domains is less than minDomains, + scheduler won't schedule more than maxSkew Pods to those domains. + If value is nil, the constraint behaves as if MinDomains is equal to 1. + Valid values are integers greater than 0. + When value is not nil, WhenUnsatisfiable must be DoNotSchedule. + + For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same + labelSelector spread as 2/2/2: + | zone1 | zone2 | zone3 | + | P P | P P | P P | + The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. + In this situation, new pod with the same labelSelector cannot be scheduled, + because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, + it will violate MaxSkew. + format: int32 + type: integer + nodeAffinityPolicy: + description: |- + NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector + when calculating pod topology spread skew. Options are: + - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. + - 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. + type: string + nodeTaintsPolicy: + description: |- + NodeTaintsPolicy indicates how we will treat node taints when calculating + pod topology spread skew. Options are: + - Honor: nodes without taints, along with tainted nodes for which the incoming pod + has a toleration, are included. + - Ignore: node taints are ignored. All nodes are included. + + If this value is nil, the behavior is equivalent to the Ignore policy. + type: string + topologyKey: + description: |- + TopologyKey is the key of node labels. Nodes that have a label with this key + and identical values are considered to be in the same topology. + We consider each as a "bucket", and try to put balanced number + of pods into each bucket. + We define a domain as a particular instance of a topology. + Also, we define an eligible domain as a domain whose nodes meet the requirements of + nodeAffinityPolicy and nodeTaintsPolicy. + e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. + And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. + It's a required field. + type: string + whenUnsatisfiable: + description: |- + WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy + the spread constraint. + - DoNotSchedule (default) tells the scheduler not to schedule it. + - ScheduleAnyway tells the scheduler to schedule the pod in any location, + but giving higher precedence to topologies that would help reduce the + skew. + A constraint is considered "Unsatisfiable" for an incoming pod + if and only if every possible node assignment for that pod would violate + "MaxSkew" on some topology. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 3/1/1: + | zone1 | zone2 | zone3 | + | P P P | P | P | + If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled + to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies + MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler + won't make it *more* imbalanced. + It's a required field. + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + required: + - component + - replicas + - roles + type: object + type: array + security: + description: Security defines options for managing the opensearch-security + plugin + properties: + config: + properties: + adminCredentialsSecret: + description: Secret that contains fields username and password + to be used by the operator to access the opensearch cluster + for node draining. Must be set if custom securityconfig + is provided. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + adminSecret: + description: TLS Secret that contains a client certificate + (tls.key, tls.crt, ca.crt) with admin rights in the opensearch + cluster. Must be set if transport certificates are provided + by user and not generated + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + securityConfigSecret: + description: Secret that contains the differnt yml files of + the opensearch-security config (config.yml, internal_users.yml, + ...) + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + updateJob: + description: Specific configs for the SecurityConfig update + job + properties: + resources: + description: ResourceRequirements describes the compute + resource requirements. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry + in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + type: object + type: object + tls: + description: Configure tls usage for transport and http interface + properties: + http: + properties: + caSecret: + description: Optional, secret that contains the ca certificate + as ca.crt. If this and generate=true is set the existing + CA cert from that secret is used to generate the node + certs. In this case must contain ca.crt and ca.key fields + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + generate: + description: If set to true the operator will generate + a CA and certificates for the cluster to use, if false + secrets with existing certificates must be supplied + type: boolean + secret: + description: Optional, name of a TLS secret that contains + ca.crt, tls.key and tls.crt data. If ca.crt is in a + different secret provide it via the caSecret field + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: object + transport: + properties: + adminDn: + description: DNs of certificates that should have admin + access, mainly used for securityconfig updates via securityadmin.sh, + only used when existing certificates are provided + items: + type: string + type: array + caSecret: + description: Optional, secret that contains the ca certificate + as ca.crt. If this and generate=true is set the existing + CA cert from that secret is used to generate the node + certs. In this case must contain ca.crt and ca.key fields + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + generate: + description: If set to true the operator will generate + a CA and certificates for the cluster to use, if false + secrets with existing certificates must be supplied + type: boolean + nodesDn: + description: Allowed Certificate DNs for nodes, only used + when existing certificates are provided + items: + type: string + type: array + perNode: + description: Configure transport node certificate + type: boolean + secret: + description: Optional, name of a TLS secret that contains + ca.crt, tls.key and tls.crt data. If ca.crt is in a + different secret provide it via the caSecret field + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + type: object + type: object + type: object + required: + - nodePools + type: object + status: + description: ClusterStatus defines the observed state of Es + properties: + availableNodes: + description: AvailableNodes is the number of available instances. + format: int32 + type: integer + componentsStatus: + items: + properties: + component: + type: string + conditions: + items: + type: string + type: array + description: + type: string + status: + type: string + type: object + type: array + health: + description: OpenSearchHealth is the health of the cluster as returned + by the health API. + type: string + initialized: + type: boolean + phase: + description: |- + INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + Important: Run "make" to regenerate code after modifying this file + type: string + version: + type: string + required: + - componentsStatus + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchcomponenttemplates.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchcomponenttemplates.yaml new file mode 100644 index 00000000..7d4fd549 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchcomponenttemplates.yaml @@ -0,0 +1,136 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.0 + name: opensearchcomponenttemplates.opensearch.opster.io +spec: + group: opensearch.opster.io + names: + kind: OpensearchComponentTemplate + listKind: OpensearchComponentTemplateList + plural: opensearchcomponenttemplates + shortNames: + - opensearchcomponenttemplate + singular: opensearchcomponenttemplate + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: OpensearchComponentTemplate is the schema for the OpenSearch + component templates API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + _meta: + description: Optional user metadata about the component template + x-kubernetes-preserve-unknown-fields: true + allowAutoCreate: + description: If true, then indices can be automatically created using + this template + type: boolean + name: + description: The name of the component template. Defaults to metadata.name + type: string + opensearchCluster: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + template: + description: The template that should be applied + properties: + aliases: + additionalProperties: + description: Describes the specs of an index alias + properties: + alias: + description: The name of the alias. + type: string + filter: + description: Query used to limit documents the alias can + access. + x-kubernetes-preserve-unknown-fields: true + index: + description: The name of the index that the alias points + to. + type: string + isWriteIndex: + description: If true, the index is the write index for the + alias + type: boolean + routing: + description: Value used to route indexing and search operations + to a specific shard. + type: string + type: object + description: Aliases to add + type: object + mappings: + description: Mapping for fields in the index + x-kubernetes-preserve-unknown-fields: true + settings: + description: Configuration options for the index + x-kubernetes-preserve-unknown-fields: true + type: object + version: + description: Version number used to manage the component template + externally + type: integer + required: + - opensearchCluster + - template + type: object + status: + properties: + componentTemplateName: + description: Name of the currently managed component template + type: string + existingComponentTemplate: + type: boolean + managedCluster: + description: |- + UID is a type that holds unique ID values, including UUIDs. Because we + don't ONLY use UUIDs, this is an alias to string. Being a type captures + intent and helps make sure that UIDs and names do not get conflated. + type: string + reason: + type: string + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchindextemplates.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchindextemplates.yaml new file mode 100644 index 00000000..37e517ee --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchindextemplates.yaml @@ -0,0 +1,163 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.0 + name: opensearchindextemplates.opensearch.opster.io +spec: + group: opensearch.opster.io + names: + kind: OpensearchIndexTemplate + listKind: OpensearchIndexTemplateList + plural: opensearchindextemplates + shortNames: + - opensearchindextemplate + singular: opensearchindextemplate + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: OpensearchIndexTemplate is the schema for the OpenSearch index + templates API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + _meta: + description: Optional user metadata about the index template + x-kubernetes-preserve-unknown-fields: true + composedOf: + description: |- + An ordered list of component template names. Component templates are merged in the order specified, + meaning that the last component template specified has the highest precedence + items: + type: string + type: array + dataStream: + description: The dataStream config that should be applied + properties: + timestamp_field: + description: TimestampField for dataStream + properties: + name: + description: Name of the field that are used for the DataStream + type: string + required: + - name + type: object + type: object + indexPatterns: + description: Array of wildcard expressions used to match the names + of indices during creation + items: + type: string + type: array + name: + description: The name of the index template. Defaults to metadata.name + type: string + opensearchCluster: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + priority: + description: |- + Priority to determine index template precedence when a new data stream or index is created. + The index template with the highest priority is chosen + type: integer + template: + description: The template that should be applied + properties: + aliases: + additionalProperties: + description: Describes the specs of an index alias + properties: + alias: + description: The name of the alias. + type: string + filter: + description: Query used to limit documents the alias can + access. + x-kubernetes-preserve-unknown-fields: true + index: + description: The name of the index that the alias points + to. + type: string + isWriteIndex: + description: If true, the index is the write index for the + alias + type: boolean + routing: + description: Value used to route indexing and search operations + to a specific shard. + type: string + type: object + description: Aliases to add + type: object + mappings: + description: Mapping for fields in the index + x-kubernetes-preserve-unknown-fields: true + settings: + description: Configuration options for the index + x-kubernetes-preserve-unknown-fields: true + type: object + version: + description: Version number used to manage the component template + externally + type: integer + required: + - indexPatterns + - opensearchCluster + type: object + status: + properties: + existingIndexTemplate: + type: boolean + indexTemplateName: + description: Name of the currently managed index template + type: string + managedCluster: + description: |- + UID is a type that holds unique ID values, including UUIDs. Because we + don't ONLY use UUIDs, this is an alias to string. Being a type captures + intent and helps make sure that UIDs and names do not get conflated. + type: string + reason: + type: string + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchismpolicies.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchismpolicies.yaml new file mode 100644 index 00000000..2f4b261d --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchismpolicies.yaml @@ -0,0 +1,461 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.0 + name: opensearchismpolicies.opensearch.opster.io +spec: + group: opensearch.opster.io + names: + kind: OpenSearchISMPolicy + listKind: OpenSearchISMPolicyList + plural: opensearchismpolicies + shortNames: + - ismp + - ismpolicy + singular: opensearchismpolicy + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ISMPolicySpec is the specification for the ISM policy for + OS. + properties: + applyToExistingIndices: + description: If true, apply the policy to existing indices that match + the index patterns in the ISM template. + type: boolean + defaultState: + description: The default starting state for each index that uses this + policy. + type: string + description: + description: A human-readable description of the policy. + type: string + errorNotification: + properties: + channel: + type: string + destination: + description: The destination URL. + properties: + amazon: + properties: + url: + type: string + type: object + chime: + properties: + url: + type: string + type: object + customWebhook: + properties: + url: + type: string + type: object + slack: + properties: + url: + type: string + type: object + type: object + messageTemplate: + description: The text of the message + properties: + source: + type: string + type: object + type: object + ismTemplate: + description: Specify an ISM template pattern that matches the index + to apply the policy. + properties: + indexPatterns: + description: Index patterns on which this policy has to be applied + items: + type: string + type: array + priority: + description: Priority of the template, defaults to 0 + type: integer + required: + - indexPatterns + type: object + opensearchCluster: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + policyId: + type: string + states: + description: The states that you define in the policy. + items: + properties: + actions: + description: The actions to execute after entering a state. + items: + description: Actions are the steps that the policy sequentially + executes on entering a specific state. + properties: + alias: + properties: + actions: + description: Allocate the index to a node with a specified + attribute. + items: + properties: + add: + properties: + aliases: + description: The name of the alias. + items: + type: string + type: array + index: + description: The name of the index that + the alias points to. + type: string + isWriteIndex: + description: Specify the index that accepts + any write operations to the alias. + type: boolean + routing: + description: Limit search to an associated + shard value + type: string + type: object + remove: + properties: + aliases: + description: The name of the alias. + items: + type: string + type: array + index: + description: The name of the index that + the alias points to. + type: string + isWriteIndex: + description: Specify the index that accepts + any write operations to the alias. + type: boolean + routing: + description: Limit search to an associated + shard value + type: string + type: object + type: object + type: array + required: + - actions + type: object + allocation: + description: Allocate the index to a node with a specific + attribute set + properties: + exclude: + description: Allocate the index to a node with a specified + attribute. + type: string + include: + description: Allocate the index to a node with any + of the specified attributes. + type: string + require: + description: Don’t allocate the index to a node with + any of the specified attributes. + type: string + waitFor: + description: Wait for the policy to execute before + allocating the index to a node with a specified + attribute. + type: string + required: + - exclude + - include + - require + - waitFor + type: object + close: + description: Closes the managed index. + type: object + delete: + description: Deletes a managed index. + type: object + forceMerge: + description: Reduces the number of Lucene segments by + merging the segments of individual shards. + properties: + maxNumSegments: + description: The number of segments to reduce the + shard to. + format: int64 + type: integer + required: + - maxNumSegments + type: object + indexPriority: + description: Set the priority for the index in a specific + state. + properties: + priority: + description: The priority for the index as soon as + it enters a state. + format: int64 + type: integer + required: + - priority + type: object + notification: + description: Name string `json:"name,omitempty"` + properties: + destination: + type: string + messageTemplate: + properties: + source: + type: string + type: object + required: + - destination + - messageTemplate + type: object + open: + description: Opens a managed index. + type: object + readOnly: + description: Sets a managed index to be read only. + type: object + readWrite: + description: Sets a managed index to be writeable. + type: object + replicaCount: + description: Sets the number of replicas to assign to + an index. + properties: + numberOfReplicas: + format: int64 + type: integer + required: + - numberOfReplicas + type: object + retry: + description: The retry configuration for the action. + properties: + backoff: + description: The backoff policy type to use when retrying. + type: string + count: + description: The number of retry counts. + format: int64 + type: integer + delay: + description: The time to wait between retries. + type: string + required: + - count + type: object + rollover: + description: Rolls an alias over to a new index when the + managed index meets one of the rollover conditions. + properties: + minDocCount: + description: The minimum number of documents required + to roll over the index. + format: int64 + type: integer + minIndexAge: + description: The minimum age required to roll over + the index. + type: string + minPrimaryShardSize: + description: The minimum storage size of a single + primary shard required to roll over the index. + type: string + minSize: + description: The minimum size of the total primary + shard storage (not counting replicas) required to + roll over the index. + type: string + type: object + rollup: + description: Periodically reduce data granularity by rolling + up old data into summarized indexes. + type: object + shrink: + description: Allows you to reduce the number of primary + shards in your indexes + properties: + forceUnsafe: + description: If true, executes the shrink action even + if there are no replicas. + type: boolean + maxShardSize: + description: The maximum size in bytes of a shard + for the target index. + type: string + numNewShards: + description: The maximum number of primary shards + in the shrunken index. + type: integer + percentageOfSourceShards: + description: Percentage of the number of original + primary shards to shrink. + format: int64 + type: integer + targetIndexNameTemplate: + description: The name of the shrunken index. + type: string + type: object + snapshot: + description: Back up your cluster’s indexes and state + properties: + repository: + description: The repository name that you register + through the native snapshot API operations. + type: string + snapshot: + description: The name of the snapshot. + type: string + required: + - repository + - snapshot + type: object + timeout: + description: The timeout period for the action. Accepts + time units for minutes, hours, and days. + type: string + type: object + type: array + name: + description: The name of the state. + type: string + transitions: + description: The next states and the conditions required to + transition to those states. If no transitions exist, the policy + assumes that it’s complete and can now stop managing the index + items: + properties: + conditions: + description: conditions for the transition. + properties: + cron: + description: The cron job that triggers the transition + if no other transition happens first. + properties: + cron: + description: A wrapper for the cron job that triggers + the transition if no other transition happens + first. This wrapper is here to adhere to the + OpenSearch API. + properties: + expression: + description: The cron expression that triggers + the transition. + type: string + timezone: + description: The timezone that triggers the + transition. + type: string + required: + - expression + - timezone + type: object + required: + - cron + type: object + minDocCount: + description: The minimum document count of the index + required to transition. + format: int64 + type: integer + minIndexAge: + description: The minimum age of the index required + to transition. + type: string + minRolloverAge: + description: The minimum age required after a rollover + has occurred to transition to the next state. + type: string + minSize: + description: The minimum size of the total primary + shard storage (not counting replicas) required to + transition. + type: string + type: object + stateName: + description: The name of the state to transition to if + the conditions are met. + type: string + required: + - conditions + - stateName + type: object + type: array + required: + - actions + - name + type: object + type: array + required: + - defaultState + - description + - states + type: object + status: + description: OpensearchISMPolicyStatus defines the observed state of OpensearchISMPolicy + properties: + existingISMPolicy: + type: boolean + managedCluster: + description: |- + UID is a type that holds unique ID values, including UUIDs. Because we + don't ONLY use UUIDs, this is an alias to string. Being a type captures + intent and helps make sure that UIDs and names do not get conflated. + type: string + policyId: + type: string + reason: + type: string + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchroles.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchroles.yaml new file mode 100644 index 00000000..36ae514a --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchroles.yaml @@ -0,0 +1,123 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.0 + name: opensearchroles.opensearch.opster.io +spec: + group: opensearch.opster.io + names: + kind: OpensearchRole + listKind: OpensearchRoleList + plural: opensearchroles + shortNames: + - opensearchrole + singular: opensearchrole + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: OpensearchRole is the Schema for the opensearchroles API + 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: OpensearchRoleSpec defines the desired state of OpensearchRole + properties: + clusterPermissions: + items: + type: string + type: array + indexPermissions: + items: + properties: + allowedActions: + items: + type: string + type: array + dls: + type: string + fls: + items: + type: string + type: array + indexPatterns: + items: + type: string + type: array + maskedFields: + items: + type: string + type: array + type: object + type: array + opensearchCluster: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + tenantPermissions: + items: + properties: + allowedActions: + items: + type: string + type: array + tenantPatterns: + items: + type: string + type: array + type: object + type: array + required: + - opensearchCluster + type: object + status: + description: OpensearchRoleStatus defines the observed state of OpensearchRole + properties: + existingRole: + type: boolean + managedCluster: + description: |- + UID is a type that holds unique ID values, including UUIDs. Because we + don't ONLY use UUIDs, this is an alias to string. Being a type captures + intent and helps make sure that UIDs and names do not get conflated. + type: string + reason: + type: string + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchsnapshotpolicies.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchsnapshotpolicies.yaml new file mode 100644 index 00000000..2c32048d --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchsnapshotpolicies.yaml @@ -0,0 +1,203 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.0 + name: opensearchsnapshotpolicies.opensearch.opster.io +spec: + group: opensearch.opster.io + names: + kind: OpensearchSnapshotPolicy + listKind: OpensearchSnapshotPolicyList + plural: opensearchsnapshotpolicies + singular: opensearchsnapshotpolicy + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Existing policy state + jsonPath: .status.existingSnapshotPolicy + name: existingpolicy + type: boolean + - description: Snapshot policy name + jsonPath: .status.snapshotPolicyName + name: policyName + type: string + - jsonPath: .status.state + name: state + type: string + - jsonPath: .metadata.creationTimestamp + name: age + type: date + name: v1 + schema: + openAPIV3Schema: + description: OpensearchSnapshotPolicy is the Schema for the opensearchsnapshotpolicies + API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + creation: + properties: + schedule: + properties: + cron: + properties: + expression: + type: string + timezone: + type: string + required: + - expression + - timezone + type: object + required: + - cron + type: object + timeLimit: + type: string + required: + - schedule + type: object + deletion: + properties: + deleteCondition: + properties: + maxAge: + type: string + maxCount: + type: integer + minCount: + type: integer + type: object + schedule: + properties: + cron: + properties: + expression: + type: string + timezone: + type: string + required: + - expression + - timezone + type: object + required: + - cron + type: object + timeLimit: + type: string + type: object + description: + type: string + enabled: + type: boolean + notification: + properties: + channel: + properties: + id: + type: string + required: + - id + type: object + conditions: + properties: + creation: + type: boolean + deletion: + type: boolean + failure: + type: boolean + type: object + required: + - channel + type: object + opensearchCluster: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + policyName: + type: string + snapshotConfig: + properties: + dateFormat: + type: string + dateFormatTimezone: + type: string + ignoreUnavailable: + type: boolean + includeGlobalState: + type: boolean + indices: + type: string + metadata: + additionalProperties: + type: string + type: object + partial: + type: boolean + repository: + type: string + required: + - repository + type: object + required: + - creation + - opensearchCluster + - policyName + - snapshotConfig + type: object + status: + description: OpensearchSnapshotPolicyStatus defines the observed state + of OpensearchSnapshotPolicy + properties: + existingSnapshotPolicy: + type: boolean + managedCluster: + description: |- + UID is a type that holds unique ID values, including UUIDs. Because we + don't ONLY use UUIDs, this is an alias to string. Being a type captures + intent and helps make sure that UIDs and names do not get conflated. + type: string + reason: + type: string + snapshotPolicyName: + type: string + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchtenants.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchtenants.yaml new file mode 100644 index 00000000..d085f3ca --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchtenants.yaml @@ -0,0 +1,85 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.0 + name: opensearchtenants.opensearch.opster.io +spec: + group: opensearch.opster.io + names: + kind: OpensearchTenant + listKind: OpensearchTenantList + plural: opensearchtenants + shortNames: + - opensearchtenant + singular: opensearchtenant + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: OpensearchTenant is the Schema for the opensearchtenants API + 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: OpensearchTenantSpec defines the desired state of OpensearchTenant + properties: + description: + type: string + opensearchCluster: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + required: + - opensearchCluster + type: object + status: + description: OpensearchTenantStatus defines the observed state of OpensearchTenant + properties: + existingTenant: + type: boolean + managedCluster: + description: |- + UID is a type that holds unique ID values, including UUIDs. Because we + don't ONLY use UUIDs, this is an alias to string. Being a type captures + intent and helps make sure that UIDs and names do not get conflated. + type: string + reason: + type: string + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchuserrolebindings.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchuserrolebindings.yaml new file mode 100644 index 00000000..2e9453c6 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchuserrolebindings.yaml @@ -0,0 +1,109 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.0 + name: opensearchuserrolebindings.opensearch.opster.io +spec: + group: opensearch.opster.io + names: + kind: OpensearchUserRoleBinding + listKind: OpensearchUserRoleBindingList + plural: opensearchuserrolebindings + shortNames: + - opensearchuserrolebinding + singular: opensearchuserrolebinding + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: OpensearchUserRoleBinding is the Schema for the opensearchuserrolebindings + API + 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: OpensearchUserRoleBindingSpec defines the desired state of + OpensearchUserRoleBinding + properties: + backendRoles: + items: + type: string + type: array + opensearchCluster: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + roles: + items: + type: string + type: array + users: + items: + type: string + type: array + required: + - opensearchCluster + - roles + type: object + status: + description: OpensearchUserRoleBindingStatus defines the observed state + of OpensearchUserRoleBinding + properties: + managedCluster: + description: |- + UID is a type that holds unique ID values, including UUIDs. Because we + don't ONLY use UUIDs, this is an alias to string. Being a type captures + intent and helps make sure that UIDs and names do not get conflated. + type: string + provisionedBackendRoles: + items: + type: string + type: array + provisionedRoles: + items: + type: string + type: array + provisionedUsers: + items: + type: string + type: array + reason: + type: string + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchusers.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchusers.yaml new file mode 100644 index 00000000..8d573ee7 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/files/opensearch.opster.io_opensearchusers.yaml @@ -0,0 +1,117 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.0 + name: opensearchusers.opensearch.opster.io +spec: + group: opensearch.opster.io + names: + kind: OpensearchUser + listKind: OpensearchUserList + plural: opensearchusers + shortNames: + - opensearchuser + singular: opensearchuser + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: OpensearchUser is the Schema for the opensearchusers API + 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: OpensearchUserSpec defines the desired state of OpensearchUser + properties: + attributes: + additionalProperties: + type: string + type: object + backendRoles: + items: + type: string + type: array + opendistroSecurityRoles: + items: + type: string + type: array + opensearchCluster: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + type: object + x-kubernetes-map-type: atomic + passwordFrom: + description: SecretKeySelector selects a key of a Secret. + properties: + key: + description: The key of the secret to select from. Must be a + valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + required: + - opensearchCluster + - passwordFrom + type: object + status: + description: OpensearchUserStatus defines the observed state of OpensearchUser + properties: + managedCluster: + description: |- + UID is a type that holds unique ID values, including UUIDs. Because we + don't ONLY use UUIDs, this is an alias to string. Being a type captures + intent and helps make sure that UIDs and names do not get conflated. + type: string + reason: + type: string + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/templates/_helpers.tpl b/packages/system/opensearch-operator/charts/opensearch-operator/templates/_helpers.tpl new file mode 100644 index 00000000..32f313e3 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "opensearch-operator.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "opensearch-operator.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "opensearch-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "opensearch-operator.labels" -}} +helm.sh/chart: {{ include "opensearch-operator.chart" . }} +{{ include "opensearch-operator.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "opensearch-operator.selectorLabels" -}} +app.kubernetes.io/name: {{ include "opensearch-operator.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "opensearch-operator.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (printf "%s-%s" (include "opensearch-operator.fullname" .) "controller-manager") .Values.serviceAccount.name }} +{{- else }} +{{- default "opensearch-operator-controller-manager" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-controller-manager-deployment.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-controller-manager-deployment.yaml new file mode 100644 index 00000000..114e6b20 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-controller-manager-deployment.yaml @@ -0,0 +1,94 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + control-plane: controller-manager + name: {{ include "opensearch-operator.fullname" . }}-controller-manager +spec: + replicas: 1 + selector: + matchLabels: + control-plane: controller-manager + template: + metadata: + labels: + control-plane: controller-manager + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + containers: + {{- if or (.Values.kubeRbacProxy.enable) (eq (.Values.kubeRbacProxy.enable | toString) "") }} + - args: + - --secure-listen-address=0.0.0.0:8443 + - --upstream=http://127.0.0.1:8080/ + - --proxy-endpoints-port=10443 + - --logtostderr=true + - --v=10 + image: "{{ .Values.kubeRbacProxy.image.repository }}:{{ .Values.kubeRbacProxy.image.tag}}" + name: kube-rbac-proxy + resources: +{{- toYaml .Values.kubeRbacProxy.resources | nindent 10 }} + readinessProbe: +{{- toYaml .Values.kubeRbacProxy.readinessProbe | nindent 10 }} + livenessProbe: +{{- toYaml .Values.kubeRbacProxy.livenessProbe | nindent 10 }} + securityContext: +{{- toYaml .Values.kubeRbacProxy.securityContext | nindent 10 }} + ports: + - containerPort: 8443 + name: https + - containerPort: 10443 + name: https-proxy + protocol: TCP + {{- end}} + - args: + - --health-probe-bind-address=:8081 + - --metrics-bind-address=127.0.0.1:8080 + - --leader-elect + {{- if .Values.manager.watchNamespace }} + - --watch-namespace={{ .Values.manager.watchNamespace }} + {{- end }} + - --loglevel={{ .Values.manager.loglevel }} + command: + - /manager + image: "{{ .Values.manager.image.repository }}:{{ .Values.manager.image.tag | default .Chart.AppVersion }}" + name: operator-controller-manager + imagePullPolicy: "{{ .Values.manager.image.pullPolicy }}" + resources: +{{- toYaml .Values.manager.resources | nindent 10 }} + readinessProbe: +{{- toYaml .Values.manager.readinessProbe | nindent 10 }} + livenessProbe: +{{- toYaml .Values.manager.livenessProbe | nindent 10 }} + env: + - name: DNS_BASE + value: {{ .Values.manager.dnsBase }} + - name: PARALLEL_RECOVERY_ENABLED + value: "{{ .Values.manager.parallelRecoveryEnabled }}" + - name: PPROF_ENDPOINTS_ENABLED + value: "{{ .Values.manager.pprofEndpointsEnabled }}" + {{- if .Values.manager.extraEnv }} + {{- toYaml .Values.manager.extraEnv | nindent 10 }} + {{- end }} + securityContext: +{{- toYaml .Values.manager.securityContext | nindent 10 }} + nodeSelector: +{{- toYaml .Values.nodeSelector | nindent 8 }} + tolerations: +{{- toYaml .Values.tolerations | nindent 8 }} + securityContext: +{{- toYaml .Values.securityContext | nindent 8 }} + {{- if .Values.manager.imagePullSecrets }} + imagePullSecrets: + {{- toYaml .Values.manager.imagePullSecrets | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "opensearch-operator.serviceAccountName" . }} + terminationGracePeriodSeconds: 10 + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName }} + {{- end }} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-controller-manager-metrics-service-svc.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-controller-manager-metrics-service-svc.yaml new file mode 100644 index 00000000..e4c6e820 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-controller-manager-metrics-service-svc.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + control-plane: controller-manager + name: {{ include "opensearch-operator.fullname" . }}-controller-manager-metrics-service +spec: + ports: + - name: https + port: 8443 + targetPort: https + selector: + control-plane: controller-manager diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-controller-manager-sa.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-controller-manager-sa.yaml new file mode 100644 index 00000000..ee5a1ca2 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-controller-manager-sa.yaml @@ -0,0 +1,6 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "opensearch-operator.serviceAccountName" . }} +{{- end -}} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-crds.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-crds.yaml new file mode 100644 index 00000000..21fdeedb --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-crds.yaml @@ -0,0 +1,5 @@ +{{- if .Values.installCRDs -}} +{{- range $path, $bytes := .Files.Glob "files/*.yaml" }} +{{ $.Files.Get $path }} +{{- end }} +{{- end }} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-leader-election-role-role.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-leader-election-role-role.yaml new file mode 100644 index 00000000..aa8853e0 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-leader-election-role-role.yaml @@ -0,0 +1,48 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "opensearch-operator.fullname" . }}-leader-election-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +- apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + verbs: + - create + - delete + - get + - list + - patch + - update + - watch diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-leader-election-rolebinding-rb.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-leader-election-rolebinding-rb.yaml new file mode 100644 index 00000000..654a0a7d --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-leader-election-rolebinding-rb.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "opensearch-operator.fullname" . }}-leader-election-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "opensearch-operator.fullname" . }}-leader-election-role +subjects: +- kind: ServiceAccount + name: {{ include "opensearch-operator.serviceAccountName" . }} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-manager-config-cm.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-manager-config-cm.yaml new file mode 100644 index 00000000..c2e9a13f --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-manager-config-cm.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +data: + controller_manager_config.yaml: | + apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 + kind: ControllerManagerConfig + health: + healthProbeBindAddress: :8081 + metrics: + bindAddress: 127.0.0.1:8080 + webhook: + port: 9443 + leaderElection: + leaderElect: true + resourceName: a867c7dc.opensearch.opster.io +kind: ConfigMap +metadata: + name: {{ include "opensearch-operator.fullname" . }}-manager-config diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-manager-role-cr.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-manager-role-cr.yaml new file mode 100644 index 00000000..3daf70d4 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-manager-role-cr.yaml @@ -0,0 +1,414 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: {{ include "opensearch-operator.fullname" . }}-{{ .Release.Namespace }}-manager-role +rules: +- apiGroups: + - apps + resources: + - deployments + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - apps + resources: + - statefulsets + - statefulsets/status + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - batch + resources: + - jobs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + - update +- apiGroups: + - "" + resources: + - namespaces + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - pods + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "policy" + resources: + - poddisruptionbudgets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - opensearch.opster.io + resources: + - events + verbs: + - create + - patch +- apiGroups: + - opensearch.opster.io + resources: + - opensearchactiongroups + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - opensearch.opster.io + resources: + - opensearchactiongroups/finalizers + verbs: + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchactiongroups/status + verbs: + - get + - patch + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchclusters + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - opensearch.opster.io + resources: + - opensearchclusters/finalizers + verbs: + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchclusters/status + verbs: + - get + - patch + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchcomponenttemplates + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - opensearch.opster.io + resources: + - opensearchcomponenttemplates/finalizers + verbs: + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchcomponenttemplates/status + verbs: + - get + - patch + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchindextemplates + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - opensearch.opster.io + resources: + - opensearchindextemplates/finalizers + verbs: + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchindextemplates/status + verbs: + - get + - patch + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchroles + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - opensearch.opster.io + resources: + - opensearchroles/finalizers + verbs: + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchroles/status + verbs: + - get + - patch + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchtenants + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - opensearch.opster.io + resources: + - opensearchtenants/finalizers + verbs: + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchtenants/status + verbs: + - get + - patch + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchuserrolebindings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - opensearch.opster.io + resources: + - opensearchuserrolebindings/finalizers + verbs: + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchuserrolebindings/status + verbs: + - get + - patch + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchismpolicies/status + verbs: + - get + - patch + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchismpolicies/finalizers + verbs: + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchusers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - opensearch.opster.io + resources: + - opensearchismpolicies + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - opensearch.opster.io + resources: + - opensearchusers/finalizers + verbs: + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchusers/status + verbs: + - get + - patch + - update +- apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - opensearch.opster.io + resources: + - opensearchsnapshotpolicies + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - opensearch.opster.io + resources: + - opensearchsnapshotpolicies/status + verbs: + - get + - patch + - update +- apiGroups: + - opensearch.opster.io + resources: + - opensearchsnapshotpolicies/finalizers + verbs: + - update \ No newline at end of file diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-manager-rolebinding.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-manager-rolebinding.yaml new file mode 100644 index 00000000..a528ffdf --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-manager-rolebinding.yaml @@ -0,0 +1,27 @@ +{{- if .Values.useRoleBindings }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "opensearch-operator.fullname" . }}-{{ .Release.Namespace }}-manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "opensearch-operator.fullname" . }}-{{ .Release.Namespace }}-manager-role +subjects: +- kind: ServiceAccount + name: {{ include "opensearch-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- else }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "opensearch-operator.fullname" . }}-{{ .Release.Namespace }}-manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "opensearch-operator.fullname" . }}-{{ .Release.Namespace }}-manager-role +subjects: +- kind: ServiceAccount + name: {{ include "opensearch-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-metrics-reader-cr.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-metrics-reader-cr.yaml new file mode 100644 index 00000000..c8f9d89c --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-metrics-reader-cr.yaml @@ -0,0 +1,9 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "opensearch-operator.fullname" . }}-{{ .Release.Namespace }}-metrics-reader +rules: +- nonResourceURLs: + - /metrics + verbs: + - get diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-proxy-role-cr.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-proxy-role-cr.yaml new file mode 100644 index 00000000..cbd6cb77 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-proxy-role-cr.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "opensearch-operator.fullname" . }}-{{ .Release.Namespace }}-proxy-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-proxy-rolebinding.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-proxy-rolebinding.yaml new file mode 100644 index 00000000..5cba0693 --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/templates/opensearch-operator-proxy-rolebinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "opensearch-operator.fullname" . }}-{{ .Release.Namespace }}-proxy-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "opensearch-operator.fullname" . }}-{{ .Release.Namespace }}-proxy-role +subjects: +- kind: ServiceAccount + name: {{ include "opensearch-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} diff --git a/packages/system/opensearch-operator/charts/opensearch-operator/values.yaml b/packages/system/opensearch-operator/charts/opensearch-operator/values.yaml new file mode 100644 index 00000000..1ee839bb --- /dev/null +++ b/packages/system/opensearch-operator/charts/opensearch-operator/values.yaml @@ -0,0 +1,123 @@ +nameOverride: "" +fullnameOverride: "" + +podAnnotations: {} +podLabels: {} +nodeSelector: {} +tolerations: [] +securityContext: + runAsNonRoot: true +priorityClassName: "" +manager: + securityContext: + allowPrivilegeEscalation: false + extraEnv: [] + resources: + limits: + cpu: 200m + memory: 500Mi + requests: + cpu: 100m + memory: 350Mi + + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthz + port: 8081 + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 3 + initialDelaySeconds: 10 + + readinessProbe: + failureThreshold: 3 + httpGet: + path: /readyz + port: 8081 + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 3 + initialDelaySeconds: 10 + + # Set this to false to disable the experimental parallel recovery in case you are experiencing problems + parallelRecoveryEnabled: true + # Set this to true to enable the standard go pprof endpoints on port 6060 (https://pkg.go.dev/net/http/pprof) + # Should only be used for debugging purposes + pprofEndpointsEnabled: false + + image: + repository: opensearchproject/opensearch-operator + ## tag default uses appVersion from Chart.yaml, to override specify tag tag: "v1.1" + tag: "" + pullPolicy: "Always" + + ## Optional array of imagePullSecrets containing private registry credentials + imagePullSecrets: [] + # - name: secretName + + dnsBase: cluster.local + + # Log level of the operator. Possible values: debug, info, warn, error + loglevel: info + + # If a watchNamespace is specified, the manager's cache will be restricted to + # watch objects in the desired namespace. Defaults is to watch all namespaces. + watchNamespace: + +# Install the Custom Resource Definitions with Helm +installCRDs: true + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Override the service account name. Defaults to opensearch-operator-controller-manager + name: "" + +kubeRbacProxy: + enable: true + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + resources: + limits: + cpu: 50m + memory: 50Mi + requests: + cpu: 25m + memory: 25Mi + + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthz + port: 10443 + scheme: HTTPS + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 3 + initialDelaySeconds: 10 + + readinessProbe: + failureThreshold: 3 + httpGet: + path: /healthz + port: 10443 + scheme: HTTPS + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 3 + initialDelaySeconds: 10 + + image: + repository: "gcr.io/kubebuilder/kube-rbac-proxy" + tag: "v0.15.0" + +## If this is set to true, RoleBindings will be used instead of ClusterRoleBindings, inorder to restrict ClusterRoles +## to the namespace where the operator and OpenSearch cluster are in. In that case, specify the namespace where they +## are in in manager.watchNamespace field. +## If false, ClusterRoleBindings will be used +useRoleBindings: false diff --git a/packages/system/opensearch-operator/values.yaml b/packages/system/opensearch-operator/values.yaml new file mode 100644 index 00000000..619aa99b --- /dev/null +++ b/packages/system/opensearch-operator/values.yaml @@ -0,0 +1,4 @@ +opensearch-operator: + manager: + # Enable cluster-wide mode to watch all namespaces + watchNamespace: "" diff --git a/packages/system/opensearch-rd/Chart.yaml b/packages/system/opensearch-rd/Chart.yaml new file mode 100644 index 00000000..c0ca3b86 --- /dev/null +++ b/packages/system/opensearch-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: opensearch-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/opensearch-rd/Makefile b/packages/system/opensearch-rd/Makefile new file mode 100644 index 00000000..7d3c0311 --- /dev/null +++ b/packages/system/opensearch-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=opensearch-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/opensearch-rd/cozyrds/opensearch.yaml b/packages/system/opensearch-rd/cozyrds/opensearch.yaml new file mode 100644 index 00000000..d74430c1 --- /dev/null +++ b/packages/system/opensearch-rd/cozyrds/opensearch.yaml @@ -0,0 +1,42 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: opensearch +spec: + application: + kind: OpenSearch + singular: opensearch + plural: opensearches + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of OpenSearch nodes in the cluster.","type":"integer","default":3},"resources":{"description":"Explicit CPU and memory configuration for each OpenSearch node. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each node.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each node.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. OpenSearch requires minimum 2Gi memory.","type":"string","default":"large","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"topologySpreadPolicy":{"description":"How strictly to enforce pod distribution across nodes and zones.","type":"string","default":"soft","enum":["soft","hard"]},"version":{"description":"OpenSearch major version to deploy.","type":"string","default":"v2","enum":["v3","v2","v1"]},"images":{"description":"Container images used by the operator.","type":"object","default":{},"required":["opensearch"],"properties":{"opensearch":{"description":"OpenSearch image.","type":"string","default":""}}},"nodeRoles":{"description":"Node roles configuration.","type":"object","default":{},"required":["data","ingest","master","ml"],"properties":{"data":{"description":"Enable data role.","type":"boolean","default":true},"ingest":{"description":"Enable ingest role.","type":"boolean","default":true},"master":{"description":"Enable cluster_manager role.","type":"boolean","default":true},"ml":{"description":"Enable machine learning role.","type":"boolean","default":false}}},"users":{"description":"Custom OpenSearch users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user (auto-generated if omitted).","type":"string"},"roles":{"description":"List of OpenSearch roles.","type":"array","items":{"type":"string"}}}}},"dashboards":{"description":"OpenSearch Dashboards configuration.","type":"object","default":{},"required":["enabled","replicas","resourcesPreset"],"properties":{"enabled":{"description":"Enable OpenSearch Dashboards deployment.","type":"boolean","default":false},"replicas":{"description":"Number of Dashboards replicas.","type":"integer","default":1},"resources":{"description":"Explicit CPU and memory configuration for Dashboards.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each node.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each node.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset for Dashboards.","type":"string","default":"medium","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}} + release: + prefix: opensearch- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-opensearch-application-default-opensearch + namespace: cozy-system + dashboard: + category: PaaS + singular: OpenSearch + plural: OpenSearch Clusters + description: Managed OpenSearch service + tags: + - database + - search + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl9vcGVuc2VhcmNoKSIvPgo8cGF0aCBkPSJNNzIgMzZDNDQgMzYgMjggNTIgMjggNzJDMjggOTIgNDQgMTA4IDcyIDEwOEMxMDAgMTA4IDExNiA5MiAxMTYgNzIiIHN0cm9rZT0iIzAwNUVCOCIgc3Ryb2tlLXdpZHRoPSI4IiBzdHJva2UtbGluZWNhcD0icm91bmQiIGZpbGw9Im5vbmUiLz4KPGNpcmNsZSBjeD0iMTE2IiBjeT0iNzIiIHI9IjgiIGZpbGw9IiMwMDVFQjgiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl9vcGVuc2VhcmNoIiB4MT0iMTQwIiB5MT0iMTMwLjUiIHgyPSI0IiB5Mj0iOS40OTk5OSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjMDAzQjVDIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzAwNUVCOCIvPgo8L2xpbmVhckdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPgo= + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "topologySpreadPolicy"], ["spec", "version"], ["spec", "images"], ["spec", "images", "opensearch"], ["spec", "nodeRoles"], ["spec", "nodeRoles", "master"], ["spec", "nodeRoles", "data"], ["spec", "nodeRoles", "ingest"], ["spec", "nodeRoles", "ml"], ["spec", "users"], ["spec", "dashboards"], ["spec", "dashboards", "enabled"], ["spec", "dashboards", "replicas"], ["spec", "dashboards", "resources"], ["spec", "dashboards", "resourcesPreset"]] + secrets: + exclude: [] + include: + - resourceNames: + - opensearch-{{ .name }}-credentials + services: + exclude: [] + include: + - resourceNames: + - opensearch-{{ .name }} + - opensearch-{{ .name }}-external + - opensearch-{{ .name }}-dashboards + - opensearch-{{ .name }}-dashboards-external diff --git a/packages/system/opensearch-rd/templates/cozyrd.yaml b/packages/system/opensearch-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/opensearch-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/opensearch-rd/values.yaml b/packages/system/opensearch-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/opensearch-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/piraeus-operator-crds/.helmignore b/packages/system/piraeus-operator-crds/.helmignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/packages/system/piraeus-operator-crds/.helmignore @@ -0,0 +1 @@ +Makefile diff --git a/packages/system/piraeus-operator-crds/Chart.yaml b/packages/system/piraeus-operator-crds/Chart.yaml new file mode 100644 index 00000000..81ccbd88 --- /dev/null +++ b/packages/system/piraeus-operator-crds/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-piraeus-operator-crds +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/piraeus-operator-crds/Makefile b/packages/system/piraeus-operator-crds/Makefile new file mode 100644 index 00000000..e633a368 --- /dev/null +++ b/packages/system/piraeus-operator-crds/Makefile @@ -0,0 +1 @@ +include ../../../hack/package.mk diff --git a/packages/system/piraeus-operator-crds/templates/crds.yaml b/packages/system/piraeus-operator-crds/templates/crds.yaml new file mode 100644 index 00000000..5bd9212c --- /dev/null +++ b/packages/system/piraeus-operator-crds/templates/crds.yaml @@ -0,0 +1,2173 @@ + {{ if .Values.installCRDs }} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: linstorclusters.piraeus.io +spec: + group: piraeus.io + names: + kind: LinstorCluster + listKind: LinstorClusterList + plural: linstorclusters + singular: linstorcluster + scope: Cluster + versions: + - additionalPrinterColumns: + - description: If the LINSTOR Cluster is available + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Available + type: string + - description: If the LINSTOR Cluster is fully configured + jsonPath: .status.conditions[?(@.type=='Configured')].status + name: Configured + type: string + - description: The version of the LINSTOR Cluster + jsonPath: .status.version + name: Version + priority: 10 + type: string + - description: The number of running/expected Satellites + jsonPath: .status.satellites + name: Satellites + type: string + - description: The used capacity in all storage pools + jsonPath: .status.capacity + name: Used Capacity + type: string + - description: The number of volumes in the cluster + jsonPath: .status.numberOfVolumes + name: Volumes + type: integer + - description: The number of snapshots in the cluster + jsonPath: .status.numberOfSnapshots + name: Snapshots + priority: 10 + type: integer + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: LinstorCluster is the Schema for the linstorclusters API + 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: LinstorClusterSpec defines the desired state of LinstorCluster + properties: + affinityController: + description: AffinityController controls the deployment of the Affinity + Controller Deployment. + properties: + enabled: + default: true + description: Enable the component. + type: boolean + podTemplate: + description: |- + Template to apply to Pods of the component. + + The template is applied as a patch to the default deployment, so it can be "sparse", not listing any + containers or volumes that should remain unchanged. + See https://kubernetes.io/docs/concepts/workloads/pods/#pod-templates + type: object + x-kubernetes-map-type: atomic + x-kubernetes-preserve-unknown-fields: true + replicas: + description: Number of desired pods. Defaults to 1. + format: int32 + minimum: 0 + type: integer + type: object + apiTLS: + description: |- + ApiTLS secures the LINSTOR API. + + This configures the TLS key and certificate used to secure the LINSTOR API. + nullable: true + properties: + affinityControllerSecretName: + description: |- + AffinityControllerSecretName references a secret holding the TLS key and certificate used by the Affinity + Controller to monitor volume state. Defaults to "linstor-affinity-controller-tls". + type: string + apiSecretName: + description: |- + ApiSecretName references a secret holding the TLS key and certificate used to protect the API. + Defaults to "linstor-api-tls". + type: string + caReference: + description: |- + CAReference configures the CA certificate to use when validating TLS certificates. + If not set, the TLS secret is expected to contain a "ca.crt" containing the CA certificate. + properties: + key: + default: ca.crt + description: |- + Key to select in the resource. + Defaults to ca.crt if not specified. + type: string + kind: + default: Secret + description: Kind of the resource containing the CA Certificate, + either a ConfigMap or Secret. + enum: + - ConfigMap + - Secret + type: string + name: + description: Name of the resource containing the CA Certificate. + type: string + optional: + description: Optional specifies whether the resource and its + key must exist. + type: boolean + required: + - name + type: object + certManager: + description: |- + CertManager references a cert-manager Issuer or ClusterIssuer. + If set, cert-manager.io/Certificate resources will be created, provisioning the secrets referenced in + *SecretName using the issuer configured here. + properties: + group: + description: Group of the resource being referred to. + type: string + kind: + description: Kind of the resource being referred to. + type: string + name: + description: Name of the resource being referred to. + type: string + required: + - name + type: object + clientSecretName: + description: |- + ClientSecretName references a secret holding the TLS key and certificate used by the operator to configure + the cluster. Defaults to "linstor-client-tls". + type: string + csiControllerSecretName: + description: |- + CsiControllerSecretName references a secret holding the TLS key and certificate used by the CSI Controller + to provision volumes. Defaults to "linstor-csi-controller-tls". + type: string + csiNodeSecretName: + description: |- + CsiNodeSecretName references a secret holding the TLS key and certificate used by the CSI Nodes to query + the volume state. Defaults to "linstor-csi-node-tls". + type: string + nfsServerSecretName: + description: |- + NFSServerSecretName references a secret holding the TLS key and certificate used by the NFS Server to query + the cluster state. Defaults to "linstor-csi-nfs-server-tls". + type: string + type: object + controller: + description: Controller controls the deployment of the LINSTOR Controller + Deployment. + properties: + enabled: + default: true + description: Enable the component. + type: boolean + podTemplate: + description: |- + Template to apply to Pods of the component. + + The template is applied as a patch to the default deployment, so it can be "sparse", not listing any + containers or volumes that should remain unchanged. + See https://kubernetes.io/docs/concepts/workloads/pods/#pod-templates + type: object + x-kubernetes-map-type: atomic + x-kubernetes-preserve-unknown-fields: true + type: object + csiController: + description: CSIController controls the deployment of the CSI Controller + Deployment. + properties: + enabled: + default: true + description: Enable the component. + type: boolean + podTemplate: + description: |- + Template to apply to Pods of the component. + + The template is applied as a patch to the default deployment, so it can be "sparse", not listing any + containers or volumes that should remain unchanged. + See https://kubernetes.io/docs/concepts/workloads/pods/#pod-templates + type: object + x-kubernetes-map-type: atomic + x-kubernetes-preserve-unknown-fields: true + replicas: + description: Number of desired pods. Defaults to 1. + format: int32 + minimum: 0 + type: integer + type: object + csiNode: + description: CSINode controls the deployment of the CSI Node DaemonSet. + properties: + enabled: + default: true + description: Enable the component. + type: boolean + podTemplate: + description: |- + Template to apply to Pods of the component. + + The template is applied as a patch to the default deployment, so it can be "sparse", not listing any + containers or volumes that should remain unchanged. + See https://kubernetes.io/docs/concepts/workloads/pods/#pod-templates + type: object + x-kubernetes-map-type: atomic + x-kubernetes-preserve-unknown-fields: true + type: object + externalController: + description: |- + ExternalController references an external controller. + When set, the Operator will skip deploying a LINSTOR Controller and instead use the external cluster + to register satellites. + properties: + url: + description: URL of the external controller. + minLength: 3 + type: string + required: + - url + type: object + highAvailabilityController: + description: HighAvailabilityController controls the deployment of + the High Availability Controller DaemonSet. + properties: + enabled: + default: true + description: Enable the component. + type: boolean + podTemplate: + description: |- + Template to apply to Pods of the component. + + The template is applied as a patch to the default deployment, so it can be "sparse", not listing any + containers or volumes that should remain unchanged. + See https://kubernetes.io/docs/concepts/workloads/pods/#pod-templates + type: object + x-kubernetes-map-type: atomic + x-kubernetes-preserve-unknown-fields: true + type: object + internalTLS: + description: |- + InternalTLS secures the connection between LINSTOR Controller and Satellite. + + This configures the client certificate used when the Controller connects to a Satellite. This only has an effect + when the Satellite is configured to for secure connections using `LinstorSatellite.spec.internalTLS`. + nullable: true + properties: + caReference: + description: |- + CAReference configures the CA certificate to use when validating TLS certificates. + If not set, the TLS secret is expected to contain a "ca.crt" containing the CA certificate. + properties: + key: + default: ca.crt + description: |- + Key to select in the resource. + Defaults to ca.crt if not specified. + type: string + kind: + default: Secret + description: Kind of the resource containing the CA Certificate, + either a ConfigMap or Secret. + enum: + - ConfigMap + - Secret + type: string + name: + description: Name of the resource containing the CA Certificate. + type: string + optional: + description: Optional specifies whether the resource and its + key must exist. + type: boolean + required: + - name + type: object + certManager: + description: |- + CertManager references a cert-manager Issuer or ClusterIssuer. + If set, a Certificate resource will be created, provisioning the secret references in SecretName using the + issuer configured here. + properties: + group: + description: Group of the resource being referred to. + type: string + kind: + description: Kind of the resource being referred to. + type: string + name: + description: Name of the resource being referred to. + type: string + required: + - name + type: object + secretName: + description: SecretName references a secret holding the TLS key + and certificates. + type: string + type: object + linstorPassphraseSecret: + description: |- + LinstorPassphraseSecret used to configure the LINSTOR master passphrase. + + The referenced secret must contain a single key "MASTER_PASSPHRASE". The master passphrase is used to + * Derive encryption keys for volumes using the LUKS layer. + * Store credentials for accessing remotes for backups. + See https://linbit.com/drbd-user-guide/linstor-guide-1_0-en/#s-encrypt_commands for more information. + type: string + nfsServer: + description: NFSServer controls the deployment of the LINSTOR CSI + NFS Server DaemonSet. + properties: + enabled: + default: true + description: Enable the component. + type: boolean + podTemplate: + description: |- + Template to apply to Pods of the component. + + The template is applied as a patch to the default deployment, so it can be "sparse", not listing any + containers or volumes that should remain unchanged. + See https://kubernetes.io/docs/concepts/workloads/pods/#pod-templates + type: object + x-kubernetes-map-type: atomic + x-kubernetes-preserve-unknown-fields: true + type: object + nodeAffinity: + description: |- + NodeAffinity selects the nodes on which LINSTOR Satellites will be deployed. + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms + are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's + labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's + fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector selects the nodes on which LINSTOR Satellites will be deployed. + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + patches: + description: |- + Patches is a list of kustomize patches to apply. + + See https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patches/ for how to create patches. + items: + description: Patch represent either a Strategic Merge Patch or a + JSON patch and its targets. + properties: + options: + description: Options is a list of options for the patch + properties: + allowKindChange: + description: AllowKindChange allows kind changes to the + resource. + type: boolean + allowNameChange: + description: AllowNameChange allows name changes to the + resource. + type: boolean + type: object + patch: + description: Patch is the content of a patch. + minLength: 1 + type: string + target: + description: Target points to the resources that the patch is + applied to + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches against the resource annotations. + type: string + group: + type: string + kind: + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches against the resource labels. + type: string + name: + description: Name of the resource. + type: string + namespace: + description: Namespace the resource belongs to, if it can + belong to a namespace. + type: string + version: + type: string + type: object + required: + - patch + type: object + type: array + properties: + description: |- + Properties to apply on the cluster level. + + Use to create default settings for DRBD that should apply to all resources or to configure some other cluster + wide default. + items: + properties: + name: + description: Name of the property to set. + minLength: 1 + type: string + value: + description: Value to set the property to. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + repository: + description: Repository used to pull workload images. + type: string + tolerations: + description: |- + Tolerations selects the nodes on which LINSTOR Satellites will be deployed. + + The default tolerations for DaemonSets are automatically added. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + status: + description: LinstorClusterStatus defines the observed state of LinstorCluster + properties: + availableCapacityBytes: + description: The number of bytes in total in all storage pools in + the LINSTOR Cluster. + format: int64 + type: integer + capacity: + description: Capacity mirrors the information from TotalCapacityBytes + and FreeCapacityBytes in a human-readable string + type: string + conditions: + description: Current LINSTOR Cluster state + 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 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + freeCapacityBytes: + description: The number of bytes free in all storage pools in the + LINSTOR Cluster. + format: int64 + type: integer + numberOfSnapshots: + description: The number of snapshots in the LINSTOR Cluster. + format: int32 + type: integer + numberOfVolumes: + description: The number of volumes in the LINSTOR Cluster. + format: int32 + type: integer + runningSatellites: + description: The number of LINSTOR Satellites currently running. + format: int32 + type: integer + satellites: + description: Satellites mirrors the information from ScheduledSatellites + and RunningSatellites in a human-readable string + type: string + scheduledSatellites: + description: The number of LINSTOR Satellites that are expected to + run. + format: int32 + type: integer + version: + description: The Version of the LINSTOR Cluster. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: linstornodeconnections.piraeus.io +spec: + group: piraeus.io + names: + kind: LinstorNodeConnection + listKind: LinstorNodeConnectionList + plural: linstornodeconnections + singular: linstornodeconnection + scope: Cluster + versions: + - additionalPrinterColumns: + - description: If the LINSTOR Node Connection is fully configured + jsonPath: .status.conditions[?(@.type=='Configured')].status + name: Configured + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: LinstorNodeConnection is the Schema for the linstornodeconnections + API + 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: LinstorNodeConnectionSpec defines the desired state of LinstorNodeConnection + properties: + paths: + description: Paths configure the network path used when connecting + two nodes. + items: + properties: + interface: + description: Interface to use on both nodes. + type: string + name: + description: Name of the path. + type: string + required: + - interface + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + properties: + description: |- + Properties to apply for the node connection. + + Use to create default settings for DRBD that should apply to all resources connections between a set of + cluster nodes. + items: + properties: + name: + description: Name of the property to set. + minLength: 1 + type: string + value: + description: Value to set the property to. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + selector: + description: |- + Selector selects which pair of Satellites the connection should apply to. + If not given, the connection will be applied to all connections. + items: + description: SelectorTerm matches pairs of nodes by checking that + the nodes match all specified requirements. + properties: + matchLabels: + description: MatchLabels is a list of match expressions that + the node pairs must meet. + items: + properties: + key: + description: Key is the name of a node label. + minLength: 1 + type: string + op: + default: Exists + description: |- + Op to apply to the label. + Exists (default) checks for the presence of the label on both nodes in the pair. + DoesNotExist checks that the label is not present on either node in the pair. + In checks for the presence of the label value given by Values on both nodes in the pair. + NotIn checks that both nodes in the pair do not have any of the label values given by Values. + Same checks that the label value is equal in the node pair. + NotSame checks that the label value is not equal in the node pair. + enum: + - Exists + - DoesNotExist + - In + - NotIn + - Same + - NotSame + type: string + values: + description: Values to match on, using the provided Op. + items: + type: string + type: array + required: + - key + type: object + type: array + required: + - matchLabels + type: object + type: array + type: object + status: + description: LinstorNodeConnectionStatus defines the observed state of + LinstorNodeConnection + properties: + conditions: + description: Current LINSTOR Node Connection state + 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 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: linstorsatelliteconfigurations.piraeus.io +spec: + group: piraeus.io + names: + kind: LinstorSatelliteConfiguration + listKind: LinstorSatelliteConfigurationList + plural: linstorsatelliteconfigurations + singular: linstorsatelliteconfiguration + scope: Cluster + versions: + - additionalPrinterColumns: + - description: The node selector used + jsonPath: .spec.nodeSelector + name: Selector + type: string + - description: If the Configuration was applied + jsonPath: .status.conditions[?(@.type=='Applied')].status + name: Applied + type: string + - description: Number of Satellites this Configuration has been applied to + jsonPath: .status.matched + name: Matched + type: integer + - description: Satellites this Configuration has been applied to + jsonPath: .status.appliedTo + name: Satellites + priority: 10 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: LinstorSatelliteConfiguration is the Schema for the linstorsatelliteconfigurations + API + 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: |- + LinstorSatelliteConfigurationSpec defines a partial, desired state of a LinstorSatelliteSpec. + + All the LinstorSatelliteConfiguration resources with matching NodeSelector will + be merged into a single LinstorSatelliteSpec. + properties: + deletionPolicy: + description: |- + DeletionPolicy configures the way LinstorSatellite resources are deleted. + + A LinstorSatellite may be deleted because: + * It no longer matches the affinity and node selector of the LinstorCluster resource. + * The node it references has been removed from Kubernetes. + * It was manually deleted outside the Operator. + + A LinstorSatellite may store the last copy of a volume, in which case it is not desirable to unconditionally remove + the satellite from the cluster. For this reason, the following deletion policies exist: + + * DeletionPolicyEvacuate will start evacuation of the LINSTOR Satellite and wait until it completes before removing the LinstorSatellite object, comparable to the "linstor node evacuate" command. + * DeletionPolicyRetain will retain the LINSTOR Satellite, keeping it registered in LINSTOR, but removing associated Kubernetes resources. + * DeletionPolicyDelete will remove the LINSTOR Satellite from the LINSTOR Cluster without prior eviction, comparable to the "linstor node lost" command. + enum: + - Evacuate + - Retain + - Delete + type: string + evacuationStrategy: + description: EvacuationStrategy configures the evacuation of volumes + from a Satellite when DeletionPolicy "Evacuate" is used. + nullable: true + properties: + attachedVolumeReattachTimeout: + default: 5m + description: |- + AttachedVolumeReattachTimeout configures how long evacuation waits for attached volumes to reattach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + unattachedVolumeAttachTimeout: + default: 5m + description: |- + UnattachedVolumeAttachTimeout configures how long evacuation waits for unattached volumes to attach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + type: object + internalTLS: + description: |- + InternalTLS configures secure communication for the LINSTOR Satellite. + + If set, the control traffic between LINSTOR Controller and Satellite will be encrypted using mTLS. + nullable: true + properties: + caReference: + description: |- + CAReference configures the CA certificate to use when validating TLS certificates. + If not set, the TLS secret is expected to contain a "ca.crt" containing the CA certificate. + properties: + key: + default: ca.crt + description: |- + Key to select in the resource. + Defaults to ca.crt if not specified. + type: string + kind: + default: Secret + description: Kind of the resource containing the CA Certificate, + either a ConfigMap or Secret. + enum: + - ConfigMap + - Secret + type: string + name: + description: Name of the resource containing the CA Certificate. + type: string + optional: + description: Optional specifies whether the resource and its + key must exist. + type: boolean + required: + - name + type: object + certManager: + description: |- + CertManager references a cert-manager Issuer or ClusterIssuer. + If set, a Certificate resource will be created, provisioning the secret references in SecretName using the + issuer configured here. + properties: + group: + description: Group of the resource being referred to. + type: string + kind: + description: Kind of the resource being referred to. + type: string + name: + description: Name of the resource being referred to. + type: string + required: + - name + type: object + secretName: + description: SecretName references a secret holding the TLS key + and certificates. + type: string + tlsHandshakeDaemon: + description: |- + TLSHandshakeDaemon enables tlshd for establishing TLS sessions for use by DRBD. + + If enabled, adds a new sidecar to the LINSTOR Satellite that runs the tlshd handshake daemon. + The daemon uses the TLS certificate and key to establish secure connections on behalf of DRBD. + type: boolean + type: object + ipFamilies: + description: |- + IPFamilies configures the IP Family (IPv4 or IPv6) to use to connect to the LINSTOR Satellite. + + If set, the control traffic between LINSTOR Controller and Satellite will use only the given IP Family. + If not set, the Operator will configure all families found in the Satellites Pods' Status. + items: + description: IPFamily represents the IP Family (IPv4 or IPv6). + enum: + - IPv4 + - IPv6 + type: string + type: array + nodeAffinity: + description: |- + NodeAffinity selects which LinstorSatellite resources this spec should be applied to. + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms + are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's + labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + matchFields: + description: A list of node selector requirements by node's + fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + 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. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + 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 + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector selects which LinstorSatellite resources this spec should be applied to. + See https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + type: object + patches: + description: |- + Patches is a list of kustomize patches to apply. + + See https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patches/ for how to create patches. + items: + description: Patch represent either a Strategic Merge Patch or a + JSON patch and its targets. + properties: + options: + description: Options is a list of options for the patch + properties: + allowKindChange: + description: AllowKindChange allows kind changes to the + resource. + type: boolean + allowNameChange: + description: AllowNameChange allows name changes to the + resource. + type: boolean + type: object + patch: + description: Patch is the content of a patch. + minLength: 1 + type: string + target: + description: Target points to the resources that the patch is + applied to + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches against the resource annotations. + type: string + group: + type: string + kind: + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches against the resource labels. + type: string + name: + description: Name of the resource. + type: string + namespace: + description: Namespace the resource belongs to, if it can + belong to a namespace. + type: string + version: + type: string + type: object + required: + - patch + type: object + type: array + podTemplate: + description: |- + Template to apply to Satellite Pods. + + The template is applied as a patch to the default resource, so it can be "sparse", not listing any + containers or volumes that should remain unchanged. + See https://kubernetes.io/docs/concepts/workloads/pods/#pod-templates + type: object + x-kubernetes-map-type: atomic + x-kubernetes-preserve-unknown-fields: true + properties: + description: Properties is a list of properties to set on the node. + items: + properties: + expandFrom: + description: |- + ExpandFrom can reference multiple resource fields at once. + It either sets the property to an aggregate value based on matched resource fields, or expands to multiple + properties. + properties: + delimiter: + description: Delimiter used to join multiple key and value + pairs together. + type: string + nameTemplate: + description: |- + NameTemplate defines how the property key is expanded. + If set, the template is appended to the defined property name, creating multiple properties instead of one + aggregate. + * $1 is replaced with the matched key. + * $2 is replaced with the matched value. + type: string + nodeFieldRef: + description: Select a field of the node. Supports `metadata.name`, + `metadata.labels['']`, `metadata.annotations['']`. + minLength: 1 + type: string + valueTemplate: + description: |- + ValueTemplate defines how the property value is expanded. + * $1 is replaced with the matched key. + * $2 is replaced with the matched value. + type: string + required: + - nodeFieldRef + type: object + name: + description: Name of the property to set. + minLength: 1 + type: string + optional: + description: Optional values are only set if they have a non-empty + value + type: boolean + value: + description: Value to set the property to. + type: string + valueFrom: + description: ValueFrom sets the value from an existing resource. + properties: + nodeFieldRef: + description: Select a field of the node. Supports `metadata.name`, + `metadata.labels['']`, `metadata.annotations['']`. + minLength: 1 + type: string + required: + - nodeFieldRef + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + storagePools: + description: StoragePools is a list of storage pools to configure + on the node. + items: + properties: + filePool: + description: Configures a file system based storage pool, allocating + a regular file per volume. + properties: + directory: + description: Directory is the path to the host directory + used to store volume data. + type: string + type: object + fileThinPool: + description: Configures a file system based storage pool, allocating + a sparse file per volume. + properties: + directory: + description: Directory is the path to the host directory + used to store volume data. + type: string + type: object + lvmPool: + description: Configures a LVM Volume Group as storage pool. + properties: + volumeGroup: + type: string + type: object + lvmThinPool: + description: Configures a LVM Thin Pool as storage pool. + properties: + thinPool: + description: ThinPool is the name of the thinpool LV (without + VG prefix). + type: string + volumeGroup: + type: string + type: object + name: + description: Name of the storage pool in linstor. + minLength: 3 + type: string + properties: + description: Properties to set on the storage pool. + items: + properties: + expandFrom: + description: |- + ExpandFrom can reference multiple resource fields at once. + It either sets the property to an aggregate value based on matched resource fields, or expands to multiple + properties. + properties: + delimiter: + description: Delimiter used to join multiple key and + value pairs together. + type: string + nameTemplate: + description: |- + NameTemplate defines how the property key is expanded. + If set, the template is appended to the defined property name, creating multiple properties instead of one + aggregate. + * $1 is replaced with the matched key. + * $2 is replaced with the matched value. + type: string + nodeFieldRef: + description: Select a field of the node. Supports + `metadata.name`, `metadata.labels['']`, `metadata.annotations['']`. + minLength: 1 + type: string + valueTemplate: + description: |- + ValueTemplate defines how the property value is expanded. + * $1 is replaced with the matched key. + * $2 is replaced with the matched value. + type: string + required: + - nodeFieldRef + type: object + name: + description: Name of the property to set. + minLength: 1 + type: string + optional: + description: Optional values are only set if they have + a non-empty value + type: boolean + value: + description: Value to set the property to. + type: string + valueFrom: + description: ValueFrom sets the value from an existing + resource. + properties: + nodeFieldRef: + description: Select a field of the node. Supports + `metadata.name`, `metadata.labels['']`, `metadata.annotations['']`. + minLength: 1 + type: string + required: + - nodeFieldRef + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + source: + properties: + hostDevices: + description: HostDevices is a list of device paths used + to configure the given pool. + items: + type: string + minItems: 1 + type: array + type: object + zfsPool: + description: Configures a ZFS system based storage pool, allocating + zvols from the given zpool. + properties: + zPool: + description: ZPool is the name of the ZFS zpool. + type: string + type: object + zfsThinPool: + description: Configures a ZFS system based storage pool, allocating + sparse zvols from the given zpool. + properties: + zPool: + description: ZPool is the name of the ZFS zpool. + type: string + type: object + required: + - name + type: object + type: array + type: object + status: + description: LinstorSatelliteConfigurationStatus defines the observed + state of LinstorSatelliteConfiguration + properties: + appliedTo: + description: AppliedTo lists the LinstorSatellite resource this configuration + was applied to + items: + type: string + type: array + conditions: + description: Current LINSTOR Satellite Config state + 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 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + matched: + description: Number of configured LinstorSatellite resource. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.18.0 + name: linstorsatellites.piraeus.io +spec: + group: piraeus.io + names: + kind: LinstorSatellite + listKind: LinstorSatelliteList + plural: linstorsatellites + singular: linstorsatellite + scope: Cluster + versions: + - additionalPrinterColumns: + - description: If the LINSTOR Satellite is connected + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Connected + type: string + - description: If the LINSTOR Satellite is fully configured + jsonPath: .status.conditions[?(@.type=='Configured')].status + name: Configured + type: string + - description: The Satellite Configurations applied to this Satellite + jsonPath: .metadata.annotations.piraeus\.io/applied-configurations + name: Applied Configurations + priority: 10 + type: string + - description: The deletion policy of the Satellite + jsonPath: .spec.deletionPolicy + name: Deletion Policy + type: string + - description: The used capacity on the node + jsonPath: .status.capacity + name: Used Capacity + type: string + - description: The number of volumes on the node + jsonPath: .status.numberOfVolumes + name: Volumes + type: integer + - description: The number of snapshots on the node + jsonPath: .status.numberOfSnapshots + name: Snapshots + priority: 10 + type: integer + - description: The storage providers supported by the node + jsonPath: .status.storageProviders + name: Storage Providers + priority: 10 + type: string + - description: The device layers supported by the node + jsonPath: .status.deviceLayers + name: Device Layers + priority: 10 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: LinstorSatellite is the Schema for the linstorsatellites API + 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: LinstorSatelliteSpec defines the desired state of LinstorSatellite + properties: + clusterRef: + description: ClusterRef references the LinstorCluster used to create + this LinstorSatellite. + properties: + caReference: + description: |- + CAReference configures the CA certificate to use when validating TLS certificates. + If not set, the TLS secret is expected to contain a "ca.crt" containing the CA certificate. + properties: + key: + default: ca.crt + description: |- + Key to select in the resource. + Defaults to ca.crt if not specified. + type: string + kind: + default: Secret + description: Kind of the resource containing the CA Certificate, + either a ConfigMap or Secret. + enum: + - ConfigMap + - Secret + type: string + name: + description: Name of the resource containing the CA Certificate. + type: string + optional: + description: Optional specifies whether the resource and its + key must exist. + type: boolean + required: + - name + type: object + clientSecretName: + description: ClientSecretName references the secret used by the + operator to validate the https endpoint. + type: string + externalController: + description: |- + ExternalController references an external controller. + When set, the Operator uses the external cluster to register satellites. + properties: + url: + description: URL of the external controller. + minLength: 3 + type: string + required: + - url + type: object + name: + description: Name of the LinstorCluster resource controlling this + satellite. + type: string + type: object + deletionPolicy: + default: Retain + description: |- + DeletionPolicy configures the way LinstorSatellite resources are deleted. + + A LinstorSatellite may be deleted because: + * It no longer matches the affinity and node selector of the LinstorCluster resource. + * The node it references has been removed from Kubernetes. + * It was manually deleted outside the Operator. + + A LinstorSatellite may store the last copy of a volume, in which case it is not desirable to unconditionally remove + the satellite from the cluster. For this reason, the following deletion policies exist: + + * DeletionPolicyEvacuate will start evacuation of the LINSTOR Satellite and wait until it completes before removing the LinstorSatellite object, comparable to the "linstor node evacuate" command. + * DeletionPolicyRetain will retain the LINSTOR Satellite, keeping it registered in LINSTOR, but removing associated Kubernetes resources. + * DeletionPolicyDelete will remove the LINSTOR Satellite from the LINSTOR Cluster without prior eviction, comparable to the "linstor node lost" command. + enum: + - Evacuate + - Retain + - Delete + type: string + evacuationStrategy: + description: EvacuationStrategy configures the evacuation of volumes + from a Satellite when DeletionPolicy "Evacuate" is used. + properties: + attachedVolumeReattachTimeout: + default: 5m + description: |- + AttachedVolumeReattachTimeout configures how long evacuation waits for attached volumes to reattach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + unattachedVolumeAttachTimeout: + default: 5m + description: |- + UnattachedVolumeAttachTimeout configures how long evacuation waits for unattached volumes to attach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + type: object + internalTLS: + description: |- + InternalTLS configures secure communication for the LINSTOR Satellite. + + If set, the control traffic between LINSTOR Controller and Satellite will be encrypted using mTLS. + The Controller will use the client key from `LinstorCluster.spec.internalTLS` when connecting. + nullable: true + properties: + caReference: + description: |- + CAReference configures the CA certificate to use when validating TLS certificates. + If not set, the TLS secret is expected to contain a "ca.crt" containing the CA certificate. + properties: + key: + default: ca.crt + description: |- + Key to select in the resource. + Defaults to ca.crt if not specified. + type: string + kind: + default: Secret + description: Kind of the resource containing the CA Certificate, + either a ConfigMap or Secret. + enum: + - ConfigMap + - Secret + type: string + name: + description: Name of the resource containing the CA Certificate. + type: string + optional: + description: Optional specifies whether the resource and its + key must exist. + type: boolean + required: + - name + type: object + certManager: + description: |- + CertManager references a cert-manager Issuer or ClusterIssuer. + If set, a Certificate resource will be created, provisioning the secret references in SecretName using the + issuer configured here. + properties: + group: + description: Group of the resource being referred to. + type: string + kind: + description: Kind of the resource being referred to. + type: string + name: + description: Name of the resource being referred to. + type: string + required: + - name + type: object + secretName: + description: SecretName references a secret holding the TLS key + and certificates. + type: string + tlsHandshakeDaemon: + description: |- + TLSHandshakeDaemon enables tlshd for establishing TLS sessions for use by DRBD. + + If enabled, adds a new sidecar to the LINSTOR Satellite that runs the tlshd handshake daemon. + The daemon uses the TLS certificate and key to establish secure connections on behalf of DRBD. + type: boolean + type: object + ipFamilies: + description: |- + IPFamilies configures the IP Family (IPv4 or IPv6) to use to connect to the LINSTOR Satellite. + + If set, the control traffic between LINSTOR Controller and Satellite will use only the given IP Family. + If not set, the Operator will configure all families found in the Satellites Pods' Status. + items: + description: IPFamily represents the IP Family (IPv4 or IPv6). + enum: + - IPv4 + - IPv6 + type: string + type: array + patches: + description: |- + Patches is a list of kustomize patches to apply. + + See https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patches/ for how to create patches. + items: + description: Patch represent either a Strategic Merge Patch or a + JSON patch and its targets. + properties: + options: + description: Options is a list of options for the patch + properties: + allowKindChange: + description: AllowKindChange allows kind changes to the + resource. + type: boolean + allowNameChange: + description: AllowNameChange allows name changes to the + resource. + type: boolean + type: object + patch: + description: Patch is the content of a patch. + minLength: 1 + type: string + target: + description: Target points to the resources that the patch is + applied to + properties: + annotationSelector: + description: |- + AnnotationSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches against the resource annotations. + type: string + group: + type: string + kind: + type: string + labelSelector: + description: |- + LabelSelector is a string that follows the label selection expression + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + It matches against the resource labels. + type: string + name: + description: Name of the resource. + type: string + namespace: + description: Namespace the resource belongs to, if it can + belong to a namespace. + type: string + version: + type: string + type: object + required: + - patch + type: object + type: array + properties: + description: Properties is a list of properties to set on the node. + items: + properties: + expandFrom: + description: |- + ExpandFrom can reference multiple resource fields at once. + It either sets the property to an aggregate value based on matched resource fields, or expands to multiple + properties. + properties: + delimiter: + description: Delimiter used to join multiple key and value + pairs together. + type: string + nameTemplate: + description: |- + NameTemplate defines how the property key is expanded. + If set, the template is appended to the defined property name, creating multiple properties instead of one + aggregate. + * $1 is replaced with the matched key. + * $2 is replaced with the matched value. + type: string + nodeFieldRef: + description: Select a field of the node. Supports `metadata.name`, + `metadata.labels['']`, `metadata.annotations['']`. + minLength: 1 + type: string + valueTemplate: + description: |- + ValueTemplate defines how the property value is expanded. + * $1 is replaced with the matched key. + * $2 is replaced with the matched value. + type: string + required: + - nodeFieldRef + type: object + name: + description: Name of the property to set. + minLength: 1 + type: string + optional: + description: Optional values are only set if they have a non-empty + value + type: boolean + value: + description: Value to set the property to. + type: string + valueFrom: + description: ValueFrom sets the value from an existing resource. + properties: + nodeFieldRef: + description: Select a field of the node. Supports `metadata.name`, + `metadata.labels['']`, `metadata.annotations['']`. + minLength: 1 + type: string + required: + - nodeFieldRef + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + repository: + description: Repository used to pull workload images. + type: string + storagePools: + description: StoragePools is a list of storage pools to configure + on the node. + items: + properties: + filePool: + description: Configures a file system based storage pool, allocating + a regular file per volume. + properties: + directory: + description: Directory is the path to the host directory + used to store volume data. + type: string + type: object + fileThinPool: + description: Configures a file system based storage pool, allocating + a sparse file per volume. + properties: + directory: + description: Directory is the path to the host directory + used to store volume data. + type: string + type: object + lvmPool: + description: Configures a LVM Volume Group as storage pool. + properties: + volumeGroup: + type: string + type: object + lvmThinPool: + description: Configures a LVM Thin Pool as storage pool. + properties: + thinPool: + description: ThinPool is the name of the thinpool LV (without + VG prefix). + type: string + volumeGroup: + type: string + type: object + name: + description: Name of the storage pool in linstor. + minLength: 3 + type: string + properties: + description: Properties to set on the storage pool. + items: + properties: + expandFrom: + description: |- + ExpandFrom can reference multiple resource fields at once. + It either sets the property to an aggregate value based on matched resource fields, or expands to multiple + properties. + properties: + delimiter: + description: Delimiter used to join multiple key and + value pairs together. + type: string + nameTemplate: + description: |- + NameTemplate defines how the property key is expanded. + If set, the template is appended to the defined property name, creating multiple properties instead of one + aggregate. + * $1 is replaced with the matched key. + * $2 is replaced with the matched value. + type: string + nodeFieldRef: + description: Select a field of the node. Supports + `metadata.name`, `metadata.labels['']`, `metadata.annotations['']`. + minLength: 1 + type: string + valueTemplate: + description: |- + ValueTemplate defines how the property value is expanded. + * $1 is replaced with the matched key. + * $2 is replaced with the matched value. + type: string + required: + - nodeFieldRef + type: object + name: + description: Name of the property to set. + minLength: 1 + type: string + optional: + description: Optional values are only set if they have + a non-empty value + type: boolean + value: + description: Value to set the property to. + type: string + valueFrom: + description: ValueFrom sets the value from an existing + resource. + properties: + nodeFieldRef: + description: Select a field of the node. Supports + `metadata.name`, `metadata.labels['']`, `metadata.annotations['']`. + minLength: 1 + type: string + required: + - nodeFieldRef + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + source: + properties: + hostDevices: + description: HostDevices is a list of device paths used + to configure the given pool. + items: + type: string + minItems: 1 + type: array + type: object + zfsPool: + description: Configures a ZFS system based storage pool, allocating + zvols from the given zpool. + properties: + zPool: + description: ZPool is the name of the ZFS zpool. + type: string + type: object + zfsThinPool: + description: Configures a ZFS system based storage pool, allocating + sparse zvols from the given zpool. + properties: + zPool: + description: ZPool is the name of the ZFS zpool. + type: string + type: object + required: + - name + type: object + type: array + required: + - clusterRef + type: object + status: + description: LinstorSatelliteStatus defines the observed state of LinstorSatellite + properties: + availableCapacityBytes: + description: The number of bytes in total in all storage pools on + this Satellite. + format: int64 + type: integer + capacity: + description: Capacity mirrors the information from TotalCapacityBytes + and FreeCapacityBytes in a human-readable string. + type: string + conditions: + description: Current LINSTOR Satellite state + 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 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + deviceLayers: + description: DeviceLayers lists the device layers (LUKS, CACHE, etc...) + this Satellite supports. + items: + type: string + type: array + freeCapacityBytes: + description: The number of bytes free in all storage pools on this + Satellite. + format: int64 + type: integer + numberOfSnapshots: + description: The number of snapshots on this Satellite. + format: int32 + type: integer + numberOfVolumes: + description: The number of volumes on this Satellite. + format: int32 + type: integer + storageProviders: + description: StorageProviders lists the storage providers (LVM, ZFS, + etc...) this Satellite supports. + items: + type: string + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +{{ end }} diff --git a/packages/system/piraeus-operator-crds/values.yaml b/packages/system/piraeus-operator-crds/values.yaml new file mode 100644 index 00000000..1b4551cc --- /dev/null +++ b/packages/system/piraeus-operator-crds/values.yaml @@ -0,0 +1 @@ +installCRDs: true diff --git a/packages/system/piraeus-operator/Makefile b/packages/system/piraeus-operator/Makefile index a10c7369..7e507f63 100644 --- a/packages/system/piraeus-operator/Makefile +++ b/packages/system/piraeus-operator/Makefile @@ -1,10 +1,11 @@ export NAME=piraeus-operator export NAMESPACE=cozy-linstor -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts tag=$$(git ls-remote --tags --sort="v:refname" https://github.com/piraeusdatastore/piraeus-operator | awk -F'[/^]' 'END{print $$3}') && \ curl -sSL https://github.com/piraeusdatastore/piraeus-operator/archive/refs/tags/$${tag}.tar.gz | \ tar xzvf - --strip 1 piraeus-operator-$${tag#*v}/charts + mv charts/piraeus/templates/crds.yaml ../piraeus-operator-crds/templates/crds.yaml diff --git a/packages/system/piraeus-operator/alerts/piraeus-datastore.yaml b/packages/system/piraeus-operator/alerts/piraeus-datastore.yaml index 77512847..0cc39fe8 100644 --- a/packages/system/piraeus-operator/alerts/piraeus-datastore.yaml +++ b/packages/system/piraeus-operator/alerts/piraeus-datastore.yaml @@ -7,19 +7,31 @@ spec: groups: - name: linstor.rules rules: - - alert: linstorControllerOffline + - alert: linstorControllerUnavailable annotations: description: | - LINSTOR Controller is not reachable. - expr: up{job="linstor-controller"} == 0 + LINSTOR Controller deployment has no available replicas. + expr: kube_deployment_status_replicas_available{namespace="cozy-linstor",deployment="linstor-controller"} < 1 + for: 3m labels: severity: critical + - alert: linstorControllerMetricsScrapeFailing + annotations: + description: | + LINSTOR Controller metrics endpoint is not being scraped successfully. + expr: up{job="linstor-controller"} == 0 + for: 10m + labels: + severity: warning - alert: linstorSatelliteErrorRate annotations: description: | - LINSTOR Satellite "{{ $labels.name }}" reports {{ $value }} errors in the last 15 minutes. - Use "linstor error-reports list --nodes {{ $labels.name }} --since 15minutes" to see them. - expr: increase(linstor_error_reports_count{module="SATELLITE"}[15m]) > 0 + LINSTOR Satellite "{{ $labels.hostname }}" reports {{ $value }} errors in the last 15 minutes. + Use "linstor error-reports list --nodes {{ $labels.hostname }}" to inspect the reports. + expr: | + increase(linstor_error_reports_count{module="SATELLITE"}[15m]) > 0 + and on(instance, job) + min_over_time(up{job="linstor-controller"}[15m]) == 1 labels: severity: warning - alert: linstorControllerErrorRate @@ -33,7 +45,7 @@ spec: - alert: linstorSatelliteNotOnline annotations: description: | - LINSTOR Satellite "{{ $labels.name }}" is not ONLINE. + LINSTOR Satellite "{{ $labels.hostname }}" is not ONLINE. Check that the Satellite is running and reachable from the LINSTOR Controller. expr: linstor_node_state{nodetype="SATELLITE"} != 2 labels: diff --git a/packages/system/piraeus-operator/charts/piraeus/Chart.yaml b/packages/system/piraeus-operator/charts/piraeus/Chart.yaml index 598dff4c..777722f3 100644 --- a/packages/system/piraeus-operator/charts/piraeus/Chart.yaml +++ b/packages/system/piraeus-operator/charts/piraeus/Chart.yaml @@ -3,8 +3,8 @@ name: piraeus description: | The Piraeus Operator manages software defined storage clusters using LINSTOR in Kubernetes. type: application -version: 2.8.1 -appVersion: "v2.8.1" +version: 2.10.2 +appVersion: "v2.10.2" maintainers: - name: Piraeus Datastore url: https://piraeus.io diff --git a/packages/system/piraeus-operator/charts/piraeus/README.md b/packages/system/piraeus-operator/charts/piraeus/README.md index abda911d..efb6f254 100644 --- a/packages/system/piraeus-operator/charts/piraeus/README.md +++ b/packages/system/piraeus-operator/charts/piraeus/README.md @@ -3,33 +3,8 @@ Deploys the [Piraeus Operator](https://github.com/piraeusdatastore/piraeus-operator) which deploys and manages a simple and resilient storage solution for Kubernetes. -The main deployment method for Piraeus Operator switched to [`kustomize`](../../docs/tutorial) +The main deployment method for Piraeus Operator switched to [`kustomize`](https://piraeus.io/docs/stable/tutorial/get-started/) in release `v2.0.0`. This chart is intended for users who want to continue using Helm. This chart **only** configures the Operator, but does not create the `LinstorCluster` resource creating the actual -storage system. Refer to the existing [tutorials](../../docs/tutorial) -and [how-to guides](../../docs/how-to). - -## Deploying Piraeus Operator - -To deploy Piraeus Operator with Helm, clone this repository and deploy the chart: - -``` -$ git clone --branch v2 https://github.com/piraeusdatastore/piraeus-operator -$ cd piraeus-operator -$ helm install piraeus-operator charts/piraeus-operator --create-namespace -n piraeus-datastore -``` - -Follow the instructions printed by Helm to create your storage cluster: - -``` -$ kubectl apply -f - < using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + x-kubernetes-list-type: atomic type: object status: description: LinstorClusterStatus defines the observed state of LinstorCluster properties: + availableCapacityBytes: + description: The number of bytes in total in all storage pools in + the LINSTOR Cluster. + format: int64 + type: integer + capacity: + description: Capacity mirrors the information from TotalCapacityBytes + and FreeCapacityBytes in a human-readable string + type: string conditions: description: Current LINSTOR Cluster state items: @@ -510,6 +661,35 @@ spec: x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map + freeCapacityBytes: + description: The number of bytes free in all storage pools in the + LINSTOR Cluster. + format: int64 + type: integer + numberOfSnapshots: + description: The number of snapshots in the LINSTOR Cluster. + format: int32 + type: integer + numberOfVolumes: + description: The number of volumes in the LINSTOR Cluster. + format: int32 + type: integer + runningSatellites: + description: The number of LINSTOR Satellites currently running. + format: int32 + type: integer + satellites: + description: Satellites mirrors the information from ScheduledSatellites + and RunningSatellites in a human-readable string + type: string + scheduledSatellites: + description: The number of LINSTOR Satellites that are expected to + run. + format: int32 + type: integer + version: + description: The Version of the LINSTOR Cluster. + type: string type: object type: object served: true @@ -521,7 +701,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.1 + controller-gen.kubebuilder.io/version: v0.18.0 name: linstornodeconnections.piraeus.io spec: group: piraeus.io @@ -532,7 +712,15 @@ spec: singular: linstornodeconnection scope: Cluster versions: - - name: v1 + - additionalPrinterColumns: + - description: If the LINSTOR Node Connection is fully configured + jsonPath: .status.conditions[?(@.type=='Configured')].status + name: Configured + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 schema: openAPIV3Schema: description: LinstorNodeConnection is the Schema for the linstornodeconnections @@ -723,7 +911,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.1 + controller-gen.kubebuilder.io/version: v0.18.0 name: linstorsatelliteconfigurations.piraeus.io spec: group: piraeus.io @@ -734,7 +922,28 @@ spec: singular: linstorsatelliteconfiguration scope: Cluster versions: - - name: v1 + - additionalPrinterColumns: + - description: The node selector used + jsonPath: .spec.nodeSelector + name: Selector + type: string + - description: If the Configuration was applied + jsonPath: .status.conditions[?(@.type=='Applied')].status + name: Applied + type: string + - description: Number of Satellites this Configuration has been applied to + jsonPath: .status.matched + name: Matched + type: integer + - description: Satellites this Configuration has been applied to + jsonPath: .status.appliedTo + name: Satellites + priority: 10 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 schema: openAPIV3Schema: description: LinstorSatelliteConfiguration is the Schema for the linstorsatelliteconfigurations @@ -764,6 +973,44 @@ spec: All the LinstorSatelliteConfiguration resources with matching NodeSelector will be merged into a single LinstorSatelliteSpec. properties: + deletionPolicy: + description: |- + DeletionPolicy configures the way LinstorSatellite resources are deleted. + + A LinstorSatellite may be deleted because: + * It no longer matches the affinity and node selector of the LinstorCluster resource. + * The node it references has been removed from Kubernetes. + * It was manually deleted outside the Operator. + + A LinstorSatellite may store the last copy of a volume, in which case it is not desirable to unconditionally remove + the satellite from the cluster. For this reason, the following deletion policies exist: + + * DeletionPolicyEvacuate will start evacuation of the LINSTOR Satellite and wait until it completes before removing the LinstorSatellite object, comparable to the "linstor node evacuate" command. + * DeletionPolicyRetain will retain the LINSTOR Satellite, keeping it registered in LINSTOR, but removing associated Kubernetes resources. + * DeletionPolicyDelete will remove the LINSTOR Satellite from the LINSTOR Cluster without prior eviction, comparable to the "linstor node lost" command. + enum: + - Evacuate + - Retain + - Delete + type: string + evacuationStrategy: + description: EvacuationStrategy configures the evacuation of volumes + from a Satellite when DeletionPolicy "Evacuate" is used. + nullable: true + properties: + attachedVolumeReattachTimeout: + default: 5m + description: |- + AttachedVolumeReattachTimeout configures how long evacuation waits for attached volumes to reattach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + unattachedVolumeAttachTimeout: + default: 5m + description: |- + UnattachedVolumeAttachTimeout configures how long evacuation waits for unattached volumes to attach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + type: object internalTLS: description: |- InternalTLS configures secure communication for the LINSTOR Satellite. @@ -950,9 +1197,16 @@ spec: JSON patch and its targets. properties: options: - additionalProperties: - type: boolean description: Options is a list of options for the patch + properties: + allowKindChange: + description: AllowKindChange allows kind changes to the + resource. + type: boolean + allowNameChange: + description: AllowNameChange allows name changes to the + resource. + type: boolean type: object patch: description: Patch is the content of a patch. @@ -1211,6 +1465,12 @@ spec: description: LinstorSatelliteConfigurationStatus defines the observed state of LinstorSatelliteConfiguration properties: + appliedTo: + description: AppliedTo lists the LinstorSatellite resource this configuration + was applied to + items: + type: string + type: array conditions: description: Current LINSTOR Satellite Config state items: @@ -1271,6 +1531,10 @@ spec: x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map + matched: + description: Number of configured LinstorSatellite resource. + format: int64 + type: integer type: object type: object served: true @@ -1282,7 +1546,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.1 + controller-gen.kubebuilder.io/version: v0.18.0 name: linstorsatellites.piraeus.io spec: group: piraeus.io @@ -1293,7 +1557,51 @@ spec: singular: linstorsatellite scope: Cluster versions: - - name: v1 + - additionalPrinterColumns: + - description: If the LINSTOR Satellite is connected + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Connected + type: string + - description: If the LINSTOR Satellite is fully configured + jsonPath: .status.conditions[?(@.type=='Configured')].status + name: Configured + type: string + - description: The Satellite Configurations applied to this Satellite + jsonPath: .metadata.annotations.piraeus\.io/applied-configurations + name: Applied Configurations + priority: 10 + type: string + - description: The deletion policy of the Satellite + jsonPath: .spec.deletionPolicy + name: Deletion Policy + type: string + - description: The used capacity on the node + jsonPath: .status.capacity + name: Used Capacity + type: string + - description: The number of volumes on the node + jsonPath: .status.numberOfVolumes + name: Volumes + type: integer + - description: The number of snapshots on the node + jsonPath: .status.numberOfSnapshots + name: Snapshots + priority: 10 + type: integer + - description: The storage providers supported by the node + jsonPath: .status.storageProviders + name: Storage Providers + priority: 10 + type: string + - description: The device layers supported by the node + jsonPath: .status.deviceLayers + name: Device Layers + priority: 10 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 schema: openAPIV3Schema: description: LinstorSatellite is the Schema for the linstorsatellites API @@ -1372,6 +1680,44 @@ spec: satellite. type: string type: object + deletionPolicy: + default: Retain + description: |- + DeletionPolicy configures the way LinstorSatellite resources are deleted. + + A LinstorSatellite may be deleted because: + * It no longer matches the affinity and node selector of the LinstorCluster resource. + * The node it references has been removed from Kubernetes. + * It was manually deleted outside the Operator. + + A LinstorSatellite may store the last copy of a volume, in which case it is not desirable to unconditionally remove + the satellite from the cluster. For this reason, the following deletion policies exist: + + * DeletionPolicyEvacuate will start evacuation of the LINSTOR Satellite and wait until it completes before removing the LinstorSatellite object, comparable to the "linstor node evacuate" command. + * DeletionPolicyRetain will retain the LINSTOR Satellite, keeping it registered in LINSTOR, but removing associated Kubernetes resources. + * DeletionPolicyDelete will remove the LINSTOR Satellite from the LINSTOR Cluster without prior eviction, comparable to the "linstor node lost" command. + enum: + - Evacuate + - Retain + - Delete + type: string + evacuationStrategy: + description: EvacuationStrategy configures the evacuation of volumes + from a Satellite when DeletionPolicy "Evacuate" is used. + properties: + attachedVolumeReattachTimeout: + default: 5m + description: |- + AttachedVolumeReattachTimeout configures how long evacuation waits for attached volumes to reattach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + unattachedVolumeAttachTimeout: + default: 5m + description: |- + UnattachedVolumeAttachTimeout configures how long evacuation waits for unattached volumes to attach on + different nodes. Setting this to 0 disable this evacuation step. + type: string + type: object internalTLS: description: |- InternalTLS configures secure communication for the LINSTOR Satellite. @@ -1462,9 +1808,16 @@ spec: JSON patch and its targets. properties: options: - additionalProperties: - type: boolean description: Options is a list of options for the patch + properties: + allowKindChange: + description: AllowKindChange allows kind changes to the + resource. + type: boolean + allowNameChange: + description: AllowNameChange allows name changes to the + resource. + type: boolean type: object patch: description: Patch is the content of a patch. @@ -1717,6 +2070,15 @@ spec: status: description: LinstorSatelliteStatus defines the observed state of LinstorSatellite properties: + availableCapacityBytes: + description: The number of bytes in total in all storage pools on + this Satellite. + format: int64 + type: integer + capacity: + description: Capacity mirrors the information from TotalCapacityBytes + and FreeCapacityBytes in a human-readable string. + type: string conditions: description: Current LINSTOR Satellite state items: @@ -1777,6 +2139,31 @@ spec: x-kubernetes-list-map-keys: - type x-kubernetes-list-type: map + deviceLayers: + description: DeviceLayers lists the device layers (LUKS, CACHE, etc...) + this Satellite supports. + items: + type: string + type: array + freeCapacityBytes: + description: The number of bytes free in all storage pools on this + Satellite. + format: int64 + type: integer + numberOfSnapshots: + description: The number of snapshots on this Satellite. + format: int32 + type: integer + numberOfVolumes: + description: The number of volumes on this Satellite. + format: int32 + type: integer + storageProviders: + description: StorageProviders lists the storage providers (LVM, ZFS, + etc...) this Satellite supports. + items: + type: string + type: array type: object type: object served: true diff --git a/packages/system/piraeus-operator/charts/piraeus/templates/deployment.yaml b/packages/system/piraeus-operator/charts/piraeus/templates/deployment.yaml index b3b9f817..c6750197 100644 --- a/packages/system/piraeus-operator/charts/piraeus/templates/deployment.yaml +++ b/packages/system/piraeus-operator/charts/piraeus/templates/deployment.yaml @@ -13,9 +13,15 @@ spec: template: metadata: labels: - {{- include "piraeus-operator.selectorLabels" . | nindent 8 }} + {{- include "piraeus-operator.selectorLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} annotations: kubectl.kubernetes.io/default-container: manager + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} spec: containers: - args: @@ -90,6 +96,9 @@ spec: {{- end }} securityContext: runAsNonRoot: true + {{- with .Values.podSecurityContext }} + {{ toYaml . | nindent 8 }} + {{- end }} serviceAccountName: {{ include "piraeus-operator.serviceAccountName" . }} terminationGracePeriodSeconds: 10 priorityClassName: {{ .Values.priorityClassName | default "system-cluster-critical" }} diff --git a/packages/system/piraeus-operator/charts/piraeus/templates/rbac.yaml b/packages/system/piraeus-operator/charts/piraeus/templates/rbac.yaml index e487114c..c532e02d 100644 --- a/packages/system/piraeus-operator/charts/piraeus/templates/rbac.yaml +++ b/packages/system/piraeus-operator/charts/piraeus/templates/rbac.yaml @@ -1,11 +1,5 @@ -{{ if .Values.serviceAccount.create }} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "piraeus-operator.serviceAccountName" . }} - labels: - {{- include "piraeus-operator.labels" . | nindent 4 }} +# DO NOT EDIT; Automatically created by tools/copy-rbac-config-to-chart.sh +{{ if .Values.rbac.create }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -14,448 +8,338 @@ metadata: labels: {{- include "piraeus-operator.labels" . | nindent 4 }} rules: - - apiGroups: - - "" - resources: - - configmaps - - events - - persistentvolumes - - secrets - - serviceaccounts - - services - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - "" - resources: - - configmaps - - pods - - secrets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - "" - resources: - - nodes - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - nodes - - persistentvolumeclaims - verbs: - - get - - list - - patch - - update - - watch - - apiGroups: - - "" - resources: - - persistentvolumeclaims/status - verbs: - - patch - - apiGroups: - - "" - resources: - - pods - verbs: - - delete - - list - - watch - - apiGroups: - - "" - resources: - - pods/eviction - verbs: - - create - - apiGroups: - - apiextensions.k8s.io - resources: - - customresourcedefinitions - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - apps - resources: - - daemonsets - - deployments - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - apps - resources: - - replicasets - verbs: - - get - - apiGroups: - - cert-manager.io - resources: - - certificates - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - events.k8s.io - resources: - - events - verbs: - - create - - get - - list - - patch - - update - - watch - - apiGroups: - - internal.linstor.linbit.com - resources: - - '*' - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch - - apiGroups: - - piraeus.io - resources: - - linstorclusters - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - piraeus.io - resources: - - linstorclusters/finalizers - verbs: - - update - - apiGroups: - - piraeus.io - resources: - - linstorclusters/status - verbs: - - get - - patch - - update - - apiGroups: - - piraeus.io - resources: - - linstornodeconnections - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - piraeus.io - resources: - - linstornodeconnections/finalizers - verbs: - - update - - apiGroups: - - piraeus.io - resources: - - linstornodeconnections/status - verbs: - - get - - patch - - update - - apiGroups: - - piraeus.io - resources: - - linstorsatelliteconfigurations - verbs: - - get - - list - - watch - - apiGroups: - - piraeus.io - resources: - - linstorsatelliteconfigurations/status - verbs: - - get - - patch - - update - - apiGroups: - - piraeus.io - resources: - - linstorsatellites - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - piraeus.io - resources: - - linstorsatellites/finalizers - verbs: - - update - - apiGroups: - - piraeus.io - resources: - - linstorsatellites/status - verbs: - - get - - patch - - update - - apiGroups: - - rbac.authorization.k8s.io - resources: - - clusterrolebindings - - clusterroles - - rolebindings - - roles - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - security.openshift.io - resourceNames: - - privileged - resources: - - securitycontextconstraints - verbs: - - use - - apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshotclasses - - volumesnapshots - verbs: - - get - - list - - watch - - apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshotcontents - verbs: - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshotcontents/status - verbs: - - patch - - update - - apiGroups: - - storage.k8s.io - resources: - - csidrivers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - storage.k8s.io - resources: - - csinodes - verbs: - - get - - list - - patch - - watch - - apiGroups: - - storage.k8s.io - resources: - - csistoragecapacities - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - storage.k8s.io - resources: - - storageclasses - verbs: - - get - - list - - watch - - apiGroups: - - storage.k8s.io - resources: - - volumeattachments - verbs: - - delete - - get - - list - - patch - - watch - - apiGroups: - - storage.k8s.io - resources: - - volumeattachments/status - verbs: - - patch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ include "piraeus-operator.fullname" . }}-manager-rolebinding - labels: - {{- include "piraeus-operator.labels" . | nindent 4 }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: '{{ include "piraeus-operator.fullname" . }}-controller-manager' -subjects: - - kind: ServiceAccount - name: '{{ include "piraeus-operator.serviceAccountName" . }}' - namespace: '{{ .Release.Namespace }}' -{{ end }} -{{ if.Values.rbac.create }} ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ include "piraeus-operator.fullname" . }}-proxy-role - labels: - {{- include "piraeus-operator.labels" . | nindent 4 }} -rules: - - apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create - - apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ include "piraeus-operator.fullname" . }}-proxy-rolebinding - labels: - {{- include "piraeus-operator.labels" . | nindent 4 }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: '{{ include "piraeus-operator.fullname" . }}-proxy-role' -subjects: - - kind: ServiceAccount - name: {{ include "piraeus-operator.serviceAccountName" . }} - namespace: '{{ .Release.Namespace }}' +- apiGroups: + - "" + resources: + - configmaps + - events + - persistentvolumes + - pods + - secrets + - serviceaccounts + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - nodes + verbs: + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - persistentvolumeclaims/status + verbs: + - patch +- apiGroups: + - "" + resources: + - pods/eviction + verbs: + - create +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - apps + resources: + - daemonsets + - deployments + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - apps + resources: + - replicasets + verbs: + - get +- apiGroups: + - cert-manager.io + resources: + - certificates + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - cluster.x-k8s.io + resources: + - machines + verbs: + - get + - update +- apiGroups: + - discovery.k8s.io + resources: + - endpointslices + - endpointslices/restricted + verbs: + - create + - delete +- apiGroups: + - events.k8s.io + resources: + - events + verbs: + - create + - get + - list + - patch + - update + - watch +- apiGroups: + - groupsnapshot.storage.k8s.io + resources: + - volumegroupsnapshotclasses + - volumesnapshots + verbs: + - get + - list + - watch +- apiGroups: + - groupsnapshot.storage.k8s.io + resources: + - volumegroupsnapshotcontents + verbs: + - get + - list + - patch + - update + - watch +- apiGroups: + - groupsnapshot.storage.k8s.io + resources: + - volumegroupsnapshotcontents/status + verbs: + - patch + - update +- apiGroups: + - internal.linstor.linbit.com + resources: + - '*' + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - piraeus.io + resources: + - linstorclusters + - linstornodeconnections + - linstorsatellites + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - piraeus.io + resources: + - linstorclusters/finalizers + - linstornodeconnections/finalizers + - linstorsatellites/finalizers + verbs: + - update +- apiGroups: + - piraeus.io + resources: + - linstorclusters/status + - linstornodeconnections/status + - linstorsatelliteconfigurations/status + - linstorsatellites/status + verbs: + - get + - patch + - update +- apiGroups: + - piraeus.io + resources: + - linstorsatelliteconfigurations + verbs: + - get + - list + - watch +- apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterrolebindings + - clusterroles + - rolebindings + - roles + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - security.openshift.io + resourceNames: + - privileged + resources: + - securitycontextconstraints + verbs: + - use +- apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshotclasses + - volumesnapshots + verbs: + - get + - list + - watch +- apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshotcontents + verbs: + - get + - list + - patch + - update + - watch +- apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshotcontents/status + verbs: + - patch + - update +- apiGroups: + - storage.k8s.io + resources: + - csidrivers + - csistoragecapacities + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - storage.k8s.io + resources: + - csinodes + verbs: + - get + - list + - patch + - watch +- apiGroups: + - storage.k8s.io + resources: + - storageclasses + verbs: + - get + - list + - watch +- apiGroups: + - storage.k8s.io + resources: + - volumeattachments + verbs: + - delete + - get + - list + - patch + - watch +- apiGroups: + - storage.k8s.io + resources: + - volumeattachments/status + verbs: + - patch --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: {{ include "piraeus-operator.fullname" . }}-leader-election-role + name: {{ include "piraeus-operator.fullname" . }}-leader-election labels: {{- include "piraeus-operator.labels" . | nindent 4 }} rules: - - apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: {{ include "piraeus-operator.fullname" . }}-leader-election-rolebinding - labels: - {{- include "piraeus-operator.labels" . | nindent 4 }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: '{{ include "piraeus-operator.fullname" . }}-leader-election-role' -subjects: - - kind: ServiceAccount - name: {{ include "piraeus-operator.serviceAccountName" . }} - namespace: '{{ .Release.Namespace }}' +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch {{ end }} diff --git a/packages/system/piraeus-operator/charts/piraeus/templates/rolebindings.yaml b/packages/system/piraeus-operator/charts/piraeus/templates/rolebindings.yaml new file mode 100644 index 00000000..97e53b95 --- /dev/null +++ b/packages/system/piraeus-operator/charts/piraeus/templates/rolebindings.yaml @@ -0,0 +1,33 @@ +{{ if .Values.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "piraeus-operator.fullname" . }}-leader-election + namespace: {{ .Release.Namespace }} + labels: + {{- include "piraeus-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "piraeus-operator.fullname" . }}-leader-election +subjects: +- kind: ServiceAccount + name: {{ include "piraeus-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "piraeus-operator.fullname" . }}-controller-manager + labels: + {{- include "piraeus-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "piraeus-operator.fullname" . }}-controller-manager +subjects: +- kind: ServiceAccount + name: {{ include "piraeus-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{ end }} diff --git a/packages/system/piraeus-operator/charts/piraeus/templates/serviceaccount.yaml b/packages/system/piraeus-operator/charts/piraeus/templates/serviceaccount.yaml new file mode 100644 index 00000000..89315de9 --- /dev/null +++ b/packages/system/piraeus-operator/charts/piraeus/templates/serviceaccount.yaml @@ -0,0 +1,9 @@ +{{ if .Values.serviceAccount.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "piraeus-operator.serviceAccountName" . }} + labels: + {{- include "piraeus-operator.labels" . | nindent 4 }} +{{ end }} diff --git a/packages/system/piraeus-operator/charts/piraeus/values.yaml b/packages/system/piraeus-operator/charts/piraeus/values.yaml index 87ca5064..bcc4dc9a 100644 --- a/packages/system/piraeus-operator/charts/piraeus/values.yaml +++ b/packages/system/piraeus-operator/charts/piraeus/values.yaml @@ -1,3 +1,4 @@ +--- replicaCount: 1 installCRDs: false @@ -18,6 +19,7 @@ operator: options: leaderElect: true + #clusterApiKubeconfig: "" # set to "" to disable ClusterAPI integration resources: { } # limits: @@ -80,6 +82,7 @@ rbac: create: true podAnnotations: { } +podLabels: {} podSecurityContext: {} # fsGroup: 2000 diff --git a/packages/system/piraeus-operator/values.yaml b/packages/system/piraeus-operator/values.yaml index 4cb448d1..eb4ec1ac 100644 --- a/packages/system/piraeus-operator/values.yaml +++ b/packages/system/piraeus-operator/values.yaml @@ -1,5 +1,5 @@ piraeus: - installCRDs: true + installCRDs: false autogenerate: false tls: certManagerIssuerRef: diff --git a/packages/system/postgres-operator/Makefile b/packages/system/postgres-operator/Makefile index f1a0bba0..5279f8a7 100644 --- a/packages/system/postgres-operator/Makefile +++ b/packages/system/postgres-operator/Makefile @@ -1,11 +1,14 @@ export NAME=postgres-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk + +test: + helm unittest . update: rm -rf charts helm repo add cnpg https://cloudnative-pg.github.io/charts helm repo update cnpg - helm pull cnpg/cloudnative-pg --untar --untardir charts + helm pull cnpg/cloudnative-pg --untar --untardir charts --version 0.26.1 rm -rf charts/cloudnative-pg/charts diff --git a/packages/system/postgres-operator/alerts/cnpg-default-alerts.yaml b/packages/system/postgres-operator/alerts/cnpg-default-alerts.yaml index a23fb3f4..9c346e41 100644 --- a/packages/system/postgres-operator/alerts/cnpg-default-alerts.yaml +++ b/packages/system/postgres-operator/alerts/cnpg-default-alerts.yaml @@ -92,7 +92,7 @@ spec: potential service disruption and/or data loss. runbook_url: https://github.com/cloudnative-pg/charts/blob/main/charts/cluster/docs/runbooks/CNPGClusterOffline.md expr: | - sum by (namespace, pod) (cnpg_collector_up)) OR on() vector(0) == 0 + (sum by (namespace, pod) (cnpg_collector_up) OR on() vector(0)) == 0 for: 5m labels: severity: critical diff --git a/packages/system/postgres-operator/charts/cloudnative-pg/Chart.yaml b/packages/system/postgres-operator/charts/cloudnative-pg/Chart.yaml index 191ae9c9..31e6afd0 100644 --- a/packages/system/postgres-operator/charts/cloudnative-pg/Chart.yaml +++ b/packages/system/postgres-operator/charts/cloudnative-pg/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v2 -appVersion: 1.25.0 +appVersion: 1.27.1 dependencies: - alias: monitoring condition: monitoring.grafanaDashboard.create @@ -22,4 +22,4 @@ name: cloudnative-pg sources: - https://github.com/cloudnative-pg/charts type: application -version: 0.23.0 +version: 0.26.1 diff --git a/packages/system/postgres-operator/charts/cloudnative-pg/README.md b/packages/system/postgres-operator/charts/cloudnative-pg/README.md index 9ac1378d..10a69657 100644 --- a/packages/system/postgres-operator/charts/cloudnative-pg/README.md +++ b/packages/system/postgres-operator/charts/cloudnative-pg/README.md @@ -1,6 +1,6 @@ # cloudnative-pg -![Version: 0.23.0](https://img.shields.io/badge/Version-0.23.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.25.0](https://img.shields.io/badge/AppVersion-1.25.0-informational?style=flat-square) +![Version: 0.26.1](https://img.shields.io/badge/Version-0.26.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.27.1](https://img.shields.io/badge/AppVersion-1.27.1-informational?style=flat-square) CloudNativePG Operator Helm Chart @@ -26,7 +26,7 @@ CloudNativePG Operator Helm Chart | Key | Type | Default | Description | |-----|------|---------|-------------| -| additionalArgs | list | `[]` | Additinal arguments to be added to the operator's args list. | +| additionalArgs | list | `[]` | Additional arguments to be added to the operator's args list. | | additionalEnv | list | `[]` | Array containing extra environment variables which can be templated. For example: - name: RELEASE_NAME value: "{{ .Release.Name }}" - name: MY_VAR value: "mySpecialKey" | | affinity | object | `{}` | Affinity for the operator to be installed. | | commonAnnotations | object | `{}` | Annotations to be added to all other resources. | @@ -57,7 +57,7 @@ CloudNativePG Operator Helm Chart | monitoring.podMonitorMetricRelabelings | list | `[]` | Metrics relabel configurations to apply to samples before ingestion. | | monitoring.podMonitorRelabelings | list | `[]` | Relabel configurations to apply to samples before scraping. | | monitoringQueriesConfigMap.name | string | `"cnpg-default-monitoring"` | The name of the default monitoring configmap. | -| monitoringQueriesConfigMap.queries | string | `"backends:\n query: |\n SELECT sa.datname\n , sa.usename\n , sa.application_name\n , states.state\n , COALESCE(sa.count, 0) AS total\n , COALESCE(sa.max_tx_secs, 0) AS max_tx_duration_seconds\n FROM ( VALUES ('active')\n , ('idle')\n , ('idle in transaction')\n , ('idle in transaction (aborted)')\n , ('fastpath function call')\n , ('disabled')\n ) AS states(state)\n LEFT JOIN (\n SELECT datname\n , state\n , usename\n , COALESCE(application_name, '') AS application_name\n , COUNT(*)\n , COALESCE(EXTRACT (EPOCH FROM (max(now() - xact_start))), 0) AS max_tx_secs\n FROM pg_catalog.pg_stat_activity\n GROUP BY datname, state, usename, application_name\n ) sa ON states.state = sa.state\n WHERE sa.usename IS NOT NULL\n metrics:\n - datname:\n usage: \"LABEL\"\n description: \"Name of the database\"\n - usename:\n usage: \"LABEL\"\n description: \"Name of the user\"\n - application_name:\n usage: \"LABEL\"\n description: \"Name of the application\"\n - state:\n usage: \"LABEL\"\n description: \"State of the backend\"\n - total:\n usage: \"GAUGE\"\n description: \"Number of backends\"\n - max_tx_duration_seconds:\n usage: \"GAUGE\"\n description: \"Maximum duration of a transaction in seconds\"\n\nbackends_waiting:\n query: |\n SELECT count(*) AS total\n FROM pg_catalog.pg_locks blocked_locks\n JOIN pg_catalog.pg_locks blocking_locks\n ON blocking_locks.locktype = blocked_locks.locktype\n AND blocking_locks.database IS NOT DISTINCT FROM blocked_locks.database\n AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation\n AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page\n AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple\n AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid\n AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid\n AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid\n AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid\n AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid\n AND blocking_locks.pid != blocked_locks.pid\n JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid\n WHERE NOT blocked_locks.granted\n metrics:\n - total:\n usage: \"GAUGE\"\n description: \"Total number of backends that are currently waiting on other queries\"\n\npg_database:\n query: |\n SELECT datname\n , pg_catalog.pg_database_size(datname) AS size_bytes\n , pg_catalog.age(datfrozenxid) AS xid_age\n , pg_catalog.mxid_age(datminmxid) AS mxid_age\n FROM pg_catalog.pg_database\n WHERE datallowconn\n metrics:\n - datname:\n usage: \"LABEL\"\n description: \"Name of the database\"\n - size_bytes:\n usage: \"GAUGE\"\n description: \"Disk space used by the database\"\n - xid_age:\n usage: \"GAUGE\"\n description: \"Number of transactions from the frozen XID to the current one\"\n - mxid_age:\n usage: \"GAUGE\"\n description: \"Number of multiple transactions (Multixact) from the frozen XID to the current one\"\n\npg_postmaster:\n query: |\n SELECT EXTRACT(EPOCH FROM pg_postmaster_start_time) AS start_time\n FROM pg_catalog.pg_postmaster_start_time()\n metrics:\n - start_time:\n usage: \"GAUGE\"\n description: \"Time at which postgres started (based on epoch)\"\n\npg_replication:\n query: \"SELECT CASE WHEN (\n NOT pg_catalog.pg_is_in_recovery()\n OR pg_catalog.pg_last_wal_receive_lsn() = pg_catalog.pg_last_wal_replay_lsn())\n THEN 0\n ELSE GREATEST (0,\n EXTRACT(EPOCH FROM (now() - pg_catalog.pg_last_xact_replay_timestamp())))\n END AS lag,\n pg_catalog.pg_is_in_recovery() AS in_recovery,\n EXISTS (TABLE pg_stat_wal_receiver) AS is_wal_receiver_up,\n (SELECT count(*) FROM pg_catalog.pg_stat_replication) AS streaming_replicas\"\n metrics:\n - lag:\n usage: \"GAUGE\"\n description: \"Replication lag behind primary in seconds\"\n - in_recovery:\n usage: \"GAUGE\"\n description: \"Whether the instance is in recovery\"\n - is_wal_receiver_up:\n usage: \"GAUGE\"\n description: \"Whether the instance wal_receiver is up\"\n - streaming_replicas:\n usage: \"GAUGE\"\n description: \"Number of streaming replicas connected to the instance\"\n\npg_replication_slots:\n query: |\n SELECT slot_name,\n slot_type,\n database,\n active,\n (CASE pg_catalog.pg_is_in_recovery()\n WHEN TRUE THEN pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_last_wal_receive_lsn(), restart_lsn)\n ELSE pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_current_wal_lsn(), restart_lsn)\n END) as pg_wal_lsn_diff\n FROM pg_catalog.pg_replication_slots\n WHERE NOT temporary\n metrics:\n - slot_name:\n usage: \"LABEL\"\n description: \"Name of the replication slot\"\n - slot_type:\n usage: \"LABEL\"\n description: \"Type of the replication slot\"\n - database:\n usage: \"LABEL\"\n description: \"Name of the database\"\n - active:\n usage: \"GAUGE\"\n description: \"Flag indicating whether the slot is active\"\n - pg_wal_lsn_diff:\n usage: \"GAUGE\"\n description: \"Replication lag in bytes\"\n\npg_stat_archiver:\n query: |\n SELECT archived_count\n , failed_count\n , COALESCE(EXTRACT(EPOCH FROM (now() - last_archived_time)), -1) AS seconds_since_last_archival\n , COALESCE(EXTRACT(EPOCH FROM (now() - last_failed_time)), -1) AS seconds_since_last_failure\n , COALESCE(EXTRACT(EPOCH FROM last_archived_time), -1) AS last_archived_time\n , COALESCE(EXTRACT(EPOCH FROM last_failed_time), -1) AS last_failed_time\n , COALESCE(CAST(CAST('x'||pg_catalog.right(pg_catalog.split_part(last_archived_wal, '.', 1), 16) AS pg_catalog.bit(64)) AS pg_catalog.int8), -1) AS last_archived_wal_start_lsn\n , COALESCE(CAST(CAST('x'||pg_catalog.right(pg_catalog.split_part(last_failed_wal, '.', 1), 16) AS pg_catalog.bit(64)) AS pg_catalog.int8), -1) AS last_failed_wal_start_lsn\n , EXTRACT(EPOCH FROM stats_reset) AS stats_reset_time\n FROM pg_catalog.pg_stat_archiver\n metrics:\n - archived_count:\n usage: \"COUNTER\"\n description: \"Number of WAL files that have been successfully archived\"\n - failed_count:\n usage: \"COUNTER\"\n description: \"Number of failed attempts for archiving WAL files\"\n - seconds_since_last_archival:\n usage: \"GAUGE\"\n description: \"Seconds since the last successful archival operation\"\n - seconds_since_last_failure:\n usage: \"GAUGE\"\n description: \"Seconds since the last failed archival operation\"\n - last_archived_time:\n usage: \"GAUGE\"\n description: \"Epoch of the last time WAL archiving succeeded\"\n - last_failed_time:\n usage: \"GAUGE\"\n description: \"Epoch of the last time WAL archiving failed\"\n - last_archived_wal_start_lsn:\n usage: \"GAUGE\"\n description: \"Archived WAL start LSN\"\n - last_failed_wal_start_lsn:\n usage: \"GAUGE\"\n description: \"Last failed WAL LSN\"\n - stats_reset_time:\n usage: \"GAUGE\"\n description: \"Time at which these statistics were last reset\"\n\npg_stat_bgwriter:\n runonserver: \"<17.0.0\"\n query: |\n SELECT checkpoints_timed\n , checkpoints_req\n , checkpoint_write_time\n , checkpoint_sync_time\n , buffers_checkpoint\n , buffers_clean\n , maxwritten_clean\n , buffers_backend\n , buffers_backend_fsync\n , buffers_alloc\n FROM pg_catalog.pg_stat_bgwriter\n metrics:\n - checkpoints_timed:\n usage: \"COUNTER\"\n description: \"Number of scheduled checkpoints that have been performed\"\n - checkpoints_req:\n usage: \"COUNTER\"\n description: \"Number of requested checkpoints that have been performed\"\n - checkpoint_write_time:\n usage: \"COUNTER\"\n description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in milliseconds\"\n - checkpoint_sync_time:\n usage: \"COUNTER\"\n description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in milliseconds\"\n - buffers_checkpoint:\n usage: \"COUNTER\"\n description: \"Number of buffers written during checkpoints\"\n - buffers_clean:\n usage: \"COUNTER\"\n description: \"Number of buffers written by the background writer\"\n - maxwritten_clean:\n usage: \"COUNTER\"\n description: \"Number of times the background writer stopped a cleaning scan because it had written too many buffers\"\n - buffers_backend:\n usage: \"COUNTER\"\n description: \"Number of buffers written directly by a backend\"\n - buffers_backend_fsync:\n usage: \"COUNTER\"\n description: \"Number of times a backend had to execute its own fsync call (normally the background writer handles those even when the backend does its own write)\"\n - buffers_alloc:\n usage: \"COUNTER\"\n description: \"Number of buffers allocated\"\n\npg_stat_bgwriter_17:\n runonserver: \">=17.0.0\"\n name: pg_stat_bgwriter\n query: |\n SELECT buffers_clean\n , maxwritten_clean\n , buffers_alloc\n , EXTRACT(EPOCH FROM stats_reset) AS stats_reset_time\n FROM pg_catalog.pg_stat_bgwriter\n metrics:\n - buffers_clean:\n usage: \"COUNTER\"\n description: \"Number of buffers written by the background writer\"\n - maxwritten_clean:\n usage: \"COUNTER\"\n description: \"Number of times the background writer stopped a cleaning scan because it had written too many buffers\"\n - buffers_alloc:\n usage: \"COUNTER\"\n description: \"Number of buffers allocated\"\n - stats_reset_time:\n usage: \"GAUGE\"\n description: \"Time at which these statistics were last reset\"\n\npg_stat_checkpointer:\n runonserver: \">=17.0.0\"\n query: |\n SELECT num_timed AS checkpoints_timed\n , num_requested AS checkpoints_req\n , restartpoints_timed\n , restartpoints_req\n , restartpoints_done\n , write_time\n , sync_time\n , buffers_written\n , EXTRACT(EPOCH FROM stats_reset) AS stats_reset_time\n FROM pg_catalog.pg_stat_checkpointer\n metrics:\n - checkpoints_timed:\n usage: \"COUNTER\"\n description: \"Number of scheduled checkpoints that have been performed\"\n - checkpoints_req:\n usage: \"COUNTER\"\n description: \"Number of requested checkpoints that have been performed\"\n - restartpoints_timed:\n usage: \"COUNTER\"\n description: \"Number of scheduled restartpoints due to timeout or after a failed attempt to perform it\"\n - restartpoints_req:\n usage: \"COUNTER\"\n description: \"Number of requested restartpoints that have been performed\"\n - restartpoints_done:\n usage: \"COUNTER\"\n description: \"Number of restartpoints that have been performed\"\n - write_time:\n usage: \"COUNTER\"\n description: \"Total amount of time that has been spent in the portion of processing checkpoints and restartpoints where files are written to disk, in milliseconds\"\n - sync_time:\n usage: \"COUNTER\"\n description: \"Total amount of time that has been spent in the portion of processing checkpoints and restartpoints where files are synchronized to disk, in milliseconds\"\n - buffers_written:\n usage: \"COUNTER\"\n description: \"Number of buffers written during checkpoints and restartpoints\"\n - stats_reset_time:\n usage: \"GAUGE\"\n description: \"Time at which these statistics were last reset\"\n\npg_stat_database:\n query: |\n SELECT datname\n , xact_commit\n , xact_rollback\n , blks_read\n , blks_hit\n , tup_returned\n , tup_fetched\n , tup_inserted\n , tup_updated\n , tup_deleted\n , conflicts\n , temp_files\n , temp_bytes\n , deadlocks\n , blk_read_time\n , blk_write_time\n FROM pg_catalog.pg_stat_database\n metrics:\n - datname:\n usage: \"LABEL\"\n description: \"Name of this database\"\n - xact_commit:\n usage: \"COUNTER\"\n description: \"Number of transactions in this database that have been committed\"\n - xact_rollback:\n usage: \"COUNTER\"\n description: \"Number of transactions in this database that have been rolled back\"\n - blks_read:\n usage: \"COUNTER\"\n description: \"Number of disk blocks read in this database\"\n - blks_hit:\n usage: \"COUNTER\"\n description: \"Number of times disk blocks were found already in the buffer cache, so that a read was not necessary (this only includes hits in the PostgreSQL buffer cache, not the operating system's file system cache)\"\n - tup_returned:\n usage: \"COUNTER\"\n description: \"Number of rows returned by queries in this database\"\n - tup_fetched:\n usage: \"COUNTER\"\n description: \"Number of rows fetched by queries in this database\"\n - tup_inserted:\n usage: \"COUNTER\"\n description: \"Number of rows inserted by queries in this database\"\n - tup_updated:\n usage: \"COUNTER\"\n description: \"Number of rows updated by queries in this database\"\n - tup_deleted:\n usage: \"COUNTER\"\n description: \"Number of rows deleted by queries in this database\"\n - conflicts:\n usage: \"COUNTER\"\n description: \"Number of queries canceled due to conflicts with recovery in this database\"\n - temp_files:\n usage: \"COUNTER\"\n description: \"Number of temporary files created by queries in this database\"\n - temp_bytes:\n usage: \"COUNTER\"\n description: \"Total amount of data written to temporary files by queries in this database\"\n - deadlocks:\n usage: \"COUNTER\"\n description: \"Number of deadlocks detected in this database\"\n - blk_read_time:\n usage: \"COUNTER\"\n description: \"Time spent reading data file blocks by backends in this database, in milliseconds\"\n - blk_write_time:\n usage: \"COUNTER\"\n description: \"Time spent writing data file blocks by backends in this database, in milliseconds\"\n\npg_stat_replication:\n primary: true\n query: |\n SELECT usename\n , COALESCE(application_name, '') AS application_name\n , COALESCE(client_addr::text, '') AS client_addr\n , COALESCE(client_port::text, '') AS client_port\n , EXTRACT(EPOCH FROM backend_start) AS backend_start\n , COALESCE(pg_catalog.age(backend_xmin), 0) AS backend_xmin_age\n , pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_current_wal_lsn(), sent_lsn) AS sent_diff_bytes\n , pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_current_wal_lsn(), write_lsn) AS write_diff_bytes\n , pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_current_wal_lsn(), flush_lsn) AS flush_diff_bytes\n , COALESCE(pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_current_wal_lsn(), replay_lsn),0) AS replay_diff_bytes\n , COALESCE((EXTRACT(EPOCH FROM write_lag)),0)::float AS write_lag_seconds\n , COALESCE((EXTRACT(EPOCH FROM flush_lag)),0)::float AS flush_lag_seconds\n , COALESCE((EXTRACT(EPOCH FROM replay_lag)),0)::float AS replay_lag_seconds\n FROM pg_catalog.pg_stat_replication\n metrics:\n - usename:\n usage: \"LABEL\"\n description: \"Name of the replication user\"\n - application_name:\n usage: \"LABEL\"\n description: \"Name of the application\"\n - client_addr:\n usage: \"LABEL\"\n description: \"Client IP address\"\n - client_port:\n usage: \"LABEL\"\n description: \"Client TCP port\"\n - backend_start:\n usage: \"COUNTER\"\n description: \"Time when this process was started\"\n - backend_xmin_age:\n usage: \"COUNTER\"\n description: \"The age of this standby's xmin horizon\"\n - sent_diff_bytes:\n usage: \"GAUGE\"\n description: \"Difference in bytes from the last write-ahead log location sent on this connection\"\n - write_diff_bytes:\n usage: \"GAUGE\"\n description: \"Difference in bytes from the last write-ahead log location written to disk by this standby server\"\n - flush_diff_bytes:\n usage: \"GAUGE\"\n description: \"Difference in bytes from the last write-ahead log location flushed to disk by this standby server\"\n - replay_diff_bytes:\n usage: \"GAUGE\"\n description: \"Difference in bytes from the last write-ahead log location replayed into the database on this standby server\"\n - write_lag_seconds:\n usage: \"GAUGE\"\n description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it\"\n - flush_lag_seconds:\n usage: \"GAUGE\"\n description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it\"\n - replay_lag_seconds:\n usage: \"GAUGE\"\n description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it\"\n\npg_settings:\n query: |\n SELECT name,\n CASE setting WHEN 'on' THEN '1' WHEN 'off' THEN '0' ELSE setting END AS setting\n FROM pg_catalog.pg_settings\n WHERE vartype IN ('integer', 'real', 'bool')\n ORDER BY 1\n metrics:\n - name:\n usage: \"LABEL\"\n description: \"Name of the setting\"\n - setting:\n usage: \"GAUGE\"\n description: \"Setting value\"\n"` | A string representation of a YAML defining monitoring queries. | +| monitoringQueriesConfigMap.queries | string | `"backends:\n query: |\n SELECT sa.datname\n , sa.usename\n , sa.application_name\n , states.state\n , COALESCE(sa.count, 0) AS total\n , COALESCE(sa.max_tx_secs, 0) AS max_tx_duration_seconds\n FROM ( VALUES ('active')\n , ('idle')\n , ('idle in transaction')\n , ('idle in transaction (aborted)')\n , ('fastpath function call')\n , ('disabled')\n ) AS states(state)\n LEFT JOIN (\n SELECT datname\n , state\n , usename\n , COALESCE(application_name, '') AS application_name\n , COUNT(*)\n , COALESCE(EXTRACT (EPOCH FROM (max(now() - xact_start))), 0) AS max_tx_secs\n FROM pg_catalog.pg_stat_activity\n GROUP BY datname, state, usename, application_name\n ) sa ON states.state = sa.state\n WHERE sa.usename IS NOT NULL\n metrics:\n - datname:\n usage: \"LABEL\"\n description: \"Name of the database\"\n - usename:\n usage: \"LABEL\"\n description: \"Name of the user\"\n - application_name:\n usage: \"LABEL\"\n description: \"Name of the application\"\n - state:\n usage: \"LABEL\"\n description: \"State of the backend\"\n - total:\n usage: \"GAUGE\"\n description: \"Number of backends\"\n - max_tx_duration_seconds:\n usage: \"GAUGE\"\n description: \"Maximum duration of a transaction in seconds\"\n\nbackends_waiting:\n query: |\n SELECT count(*) AS total\n FROM pg_catalog.pg_locks blocked_locks\n JOIN pg_catalog.pg_locks blocking_locks\n ON blocking_locks.locktype = blocked_locks.locktype\n AND blocking_locks.database IS NOT DISTINCT FROM blocked_locks.database\n AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation\n AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page\n AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple\n AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid\n AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid\n AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid\n AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid\n AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid\n AND blocking_locks.pid != blocked_locks.pid\n JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid\n WHERE NOT blocked_locks.granted\n metrics:\n - total:\n usage: \"GAUGE\"\n description: \"Total number of backends that are currently waiting on other queries\"\n\npg_database:\n query: |\n SELECT datname\n , pg_catalog.pg_database_size(datname) AS size_bytes\n , pg_catalog.age(datfrozenxid) AS xid_age\n , pg_catalog.mxid_age(datminmxid) AS mxid_age\n FROM pg_catalog.pg_database\n WHERE datallowconn\n metrics:\n - datname:\n usage: \"LABEL\"\n description: \"Name of the database\"\n - size_bytes:\n usage: \"GAUGE\"\n description: \"Disk space used by the database\"\n - xid_age:\n usage: \"GAUGE\"\n description: \"Number of transactions from the frozen XID to the current one\"\n - mxid_age:\n usage: \"GAUGE\"\n description: \"Number of multiple transactions (Multixact) from the frozen XID to the current one\"\n\npg_postmaster:\n query: |\n SELECT EXTRACT(EPOCH FROM pg_postmaster_start_time) AS start_time\n FROM pg_catalog.pg_postmaster_start_time()\n metrics:\n - start_time:\n usage: \"GAUGE\"\n description: \"Time at which postgres started (based on epoch)\"\n\npg_replication:\n query: \"SELECT CASE WHEN (\n NOT pg_catalog.pg_is_in_recovery()\n OR pg_catalog.pg_last_wal_receive_lsn() = pg_catalog.pg_last_wal_replay_lsn())\n THEN 0\n ELSE GREATEST (0,\n EXTRACT(EPOCH FROM (now() - pg_catalog.pg_last_xact_replay_timestamp())))\n END AS lag,\n pg_catalog.pg_is_in_recovery() AS in_recovery,\n EXISTS (TABLE pg_stat_wal_receiver) AS is_wal_receiver_up,\n (SELECT count(*) FROM pg_catalog.pg_stat_replication) AS streaming_replicas\"\n metrics:\n - lag:\n usage: \"GAUGE\"\n description: \"Replication lag behind primary in seconds\"\n - in_recovery:\n usage: \"GAUGE\"\n description: \"Whether the instance is in recovery\"\n - is_wal_receiver_up:\n usage: \"GAUGE\"\n description: \"Whether the instance wal_receiver is up\"\n - streaming_replicas:\n usage: \"GAUGE\"\n description: \"Number of streaming replicas connected to the instance\"\n\npg_replication_slots:\n query: |\n SELECT slot_name,\n slot_type,\n database,\n active,\n (CASE pg_catalog.pg_is_in_recovery()\n WHEN TRUE THEN pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_last_wal_receive_lsn(), restart_lsn)\n ELSE pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_current_wal_lsn(), restart_lsn)\n END) as pg_wal_lsn_diff\n FROM pg_catalog.pg_replication_slots\n WHERE NOT temporary\n metrics:\n - slot_name:\n usage: \"LABEL\"\n description: \"Name of the replication slot\"\n - slot_type:\n usage: \"LABEL\"\n description: \"Type of the replication slot\"\n - database:\n usage: \"LABEL\"\n description: \"Name of the database\"\n - active:\n usage: \"GAUGE\"\n description: \"Flag indicating whether the slot is active\"\n - pg_wal_lsn_diff:\n usage: \"GAUGE\"\n description: \"Replication lag in bytes\"\n\npg_stat_archiver:\n query: |\n SELECT archived_count\n , failed_count\n , COALESCE(EXTRACT(EPOCH FROM (now() - last_archived_time)), -1) AS seconds_since_last_archival\n , COALESCE(EXTRACT(EPOCH FROM (now() - last_failed_time)), -1) AS seconds_since_last_failure\n , COALESCE(EXTRACT(EPOCH FROM last_archived_time), -1) AS last_archived_time\n , COALESCE(EXTRACT(EPOCH FROM last_failed_time), -1) AS last_failed_time\n , COALESCE(CAST(CAST('x'||pg_catalog.right(pg_catalog.split_part(last_archived_wal, '.', 1), 16) AS pg_catalog.bit(64)) AS pg_catalog.int8), -1) AS last_archived_wal_start_lsn\n , COALESCE(CAST(CAST('x'||pg_catalog.right(pg_catalog.split_part(last_failed_wal, '.', 1), 16) AS pg_catalog.bit(64)) AS pg_catalog.int8), -1) AS last_failed_wal_start_lsn\n , EXTRACT(EPOCH FROM stats_reset) AS stats_reset_time\n FROM pg_catalog.pg_stat_archiver\n metrics:\n - archived_count:\n usage: \"COUNTER\"\n description: \"Number of WAL files that have been successfully archived\"\n - failed_count:\n usage: \"COUNTER\"\n description: \"Number of failed attempts for archiving WAL files\"\n - seconds_since_last_archival:\n usage: \"GAUGE\"\n description: \"Seconds since the last successful archival operation\"\n - seconds_since_last_failure:\n usage: \"GAUGE\"\n description: \"Seconds since the last failed archival operation\"\n - last_archived_time:\n usage: \"GAUGE\"\n description: \"Epoch of the last time WAL archiving succeeded\"\n - last_failed_time:\n usage: \"GAUGE\"\n description: \"Epoch of the last time WAL archiving failed\"\n - last_archived_wal_start_lsn:\n usage: \"GAUGE\"\n description: \"Archived WAL start LSN\"\n - last_failed_wal_start_lsn:\n usage: \"GAUGE\"\n description: \"Last failed WAL LSN\"\n - stats_reset_time:\n usage: \"GAUGE\"\n description: \"Time at which these statistics were last reset\"\n\npg_stat_bgwriter:\n runonserver: \"<17.0.0\"\n query: |\n SELECT checkpoints_timed\n , checkpoints_req\n , checkpoint_write_time\n , checkpoint_sync_time\n , buffers_checkpoint\n , buffers_clean\n , maxwritten_clean\n , buffers_backend\n , buffers_backend_fsync\n , buffers_alloc\n FROM pg_catalog.pg_stat_bgwriter\n metrics:\n - checkpoints_timed:\n usage: \"COUNTER\"\n description: \"Number of scheduled checkpoints that have been performed\"\n - checkpoints_req:\n usage: \"COUNTER\"\n description: \"Number of requested checkpoints that have been performed\"\n - checkpoint_write_time:\n usage: \"COUNTER\"\n description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in milliseconds\"\n - checkpoint_sync_time:\n usage: \"COUNTER\"\n description: \"Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in milliseconds\"\n - buffers_checkpoint:\n usage: \"COUNTER\"\n description: \"Number of buffers written during checkpoints\"\n - buffers_clean:\n usage: \"COUNTER\"\n description: \"Number of buffers written by the background writer\"\n - maxwritten_clean:\n usage: \"COUNTER\"\n description: \"Number of times the background writer stopped a cleaning scan because it had written too many buffers\"\n - buffers_backend:\n usage: \"COUNTER\"\n description: \"Number of buffers written directly by a backend\"\n - buffers_backend_fsync:\n usage: \"COUNTER\"\n description: \"Number of times a backend had to execute its own fsync call (normally the background writer handles those even when the backend does its own write)\"\n - buffers_alloc:\n usage: \"COUNTER\"\n description: \"Number of buffers allocated\"\n\npg_stat_bgwriter_17:\n runonserver: \">=17.0.0\"\n name: pg_stat_bgwriter\n query: |\n SELECT buffers_clean\n , maxwritten_clean\n , buffers_alloc\n , EXTRACT(EPOCH FROM stats_reset) AS stats_reset_time\n FROM pg_catalog.pg_stat_bgwriter\n metrics:\n - buffers_clean:\n usage: \"COUNTER\"\n description: \"Number of buffers written by the background writer\"\n - maxwritten_clean:\n usage: \"COUNTER\"\n description: \"Number of times the background writer stopped a cleaning scan because it had written too many buffers\"\n - buffers_alloc:\n usage: \"COUNTER\"\n description: \"Number of buffers allocated\"\n - stats_reset_time:\n usage: \"GAUGE\"\n description: \"Time at which these statistics were last reset\"\n\npg_stat_checkpointer:\n runonserver: \">=17.0.0\"\n query: |\n SELECT num_timed AS checkpoints_timed\n , num_requested AS checkpoints_req\n , restartpoints_timed\n , restartpoints_req\n , restartpoints_done\n , write_time\n , sync_time\n , buffers_written\n , EXTRACT(EPOCH FROM stats_reset) AS stats_reset_time\n FROM pg_catalog.pg_stat_checkpointer\n metrics:\n - checkpoints_timed:\n usage: \"COUNTER\"\n description: \"Number of scheduled checkpoints that have been performed\"\n - checkpoints_req:\n usage: \"COUNTER\"\n description: \"Number of requested checkpoints that have been performed\"\n - restartpoints_timed:\n usage: \"COUNTER\"\n description: \"Number of scheduled restartpoints due to timeout or after a failed attempt to perform it\"\n - restartpoints_req:\n usage: \"COUNTER\"\n description: \"Number of requested restartpoints that have been performed\"\n - restartpoints_done:\n usage: \"COUNTER\"\n description: \"Number of restartpoints that have been performed\"\n - write_time:\n usage: \"COUNTER\"\n description: \"Total amount of time that has been spent in the portion of processing checkpoints and restartpoints where files are written to disk, in milliseconds\"\n - sync_time:\n usage: \"COUNTER\"\n description: \"Total amount of time that has been spent in the portion of processing checkpoints and restartpoints where files are synchronized to disk, in milliseconds\"\n - buffers_written:\n usage: \"COUNTER\"\n description: \"Number of buffers written during checkpoints and restartpoints\"\n - stats_reset_time:\n usage: \"GAUGE\"\n description: \"Time at which these statistics were last reset\"\n\npg_stat_database:\n query: |\n SELECT datname\n , xact_commit\n , xact_rollback\n , blks_read\n , blks_hit\n , tup_returned\n , tup_fetched\n , tup_inserted\n , tup_updated\n , tup_deleted\n , conflicts\n , temp_files\n , temp_bytes\n , deadlocks\n , blk_read_time\n , blk_write_time\n FROM pg_catalog.pg_stat_database\n metrics:\n - datname:\n usage: \"LABEL\"\n description: \"Name of this database\"\n - xact_commit:\n usage: \"COUNTER\"\n description: \"Number of transactions in this database that have been committed\"\n - xact_rollback:\n usage: \"COUNTER\"\n description: \"Number of transactions in this database that have been rolled back\"\n - blks_read:\n usage: \"COUNTER\"\n description: \"Number of disk blocks read in this database\"\n - blks_hit:\n usage: \"COUNTER\"\n description: \"Number of times disk blocks were found already in the buffer cache, so that a read was not necessary (this only includes hits in the PostgreSQL buffer cache, not the operating system's file system cache)\"\n - tup_returned:\n usage: \"COUNTER\"\n description: \"Number of rows returned by queries in this database\"\n - tup_fetched:\n usage: \"COUNTER\"\n description: \"Number of rows fetched by queries in this database\"\n - tup_inserted:\n usage: \"COUNTER\"\n description: \"Number of rows inserted by queries in this database\"\n - tup_updated:\n usage: \"COUNTER\"\n description: \"Number of rows updated by queries in this database\"\n - tup_deleted:\n usage: \"COUNTER\"\n description: \"Number of rows deleted by queries in this database\"\n - conflicts:\n usage: \"COUNTER\"\n description: \"Number of queries canceled due to conflicts with recovery in this database\"\n - temp_files:\n usage: \"COUNTER\"\n description: \"Number of temporary files created by queries in this database\"\n - temp_bytes:\n usage: \"COUNTER\"\n description: \"Total amount of data written to temporary files by queries in this database\"\n - deadlocks:\n usage: \"COUNTER\"\n description: \"Number of deadlocks detected in this database\"\n - blk_read_time:\n usage: \"COUNTER\"\n description: \"Time spent reading data file blocks by backends in this database, in milliseconds\"\n - blk_write_time:\n usage: \"COUNTER\"\n description: \"Time spent writing data file blocks by backends in this database, in milliseconds\"\n\npg_stat_replication:\n primary: true\n query: |\n SELECT usename\n , COALESCE(application_name, '') AS application_name\n , COALESCE(client_addr::text, '') AS client_addr\n , COALESCE(client_port::text, '') AS client_port\n , EXTRACT(EPOCH FROM backend_start) AS backend_start\n , COALESCE(pg_catalog.age(backend_xmin), 0) AS backend_xmin_age\n , pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_current_wal_lsn(), sent_lsn) AS sent_diff_bytes\n , pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_current_wal_lsn(), write_lsn) AS write_diff_bytes\n , pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_current_wal_lsn(), flush_lsn) AS flush_diff_bytes\n , COALESCE(pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_current_wal_lsn(), replay_lsn),0) AS replay_diff_bytes\n , COALESCE((EXTRACT(EPOCH FROM write_lag)),0)::float AS write_lag_seconds\n , COALESCE((EXTRACT(EPOCH FROM flush_lag)),0)::float AS flush_lag_seconds\n , COALESCE((EXTRACT(EPOCH FROM replay_lag)),0)::float AS replay_lag_seconds\n FROM pg_catalog.pg_stat_replication\n metrics:\n - usename:\n usage: \"LABEL\"\n description: \"Name of the replication user\"\n - application_name:\n usage: \"LABEL\"\n description: \"Name of the application\"\n - client_addr:\n usage: \"LABEL\"\n description: \"Client IP address\"\n - client_port:\n usage: \"LABEL\"\n description: \"Client TCP port\"\n - backend_start:\n usage: \"COUNTER\"\n description: \"Time when this process was started\"\n - backend_xmin_age:\n usage: \"COUNTER\"\n description: \"The age of this standby's xmin horizon\"\n - sent_diff_bytes:\n usage: \"GAUGE\"\n description: \"Difference in bytes from the last write-ahead log location sent on this connection\"\n - write_diff_bytes:\n usage: \"GAUGE\"\n description: \"Difference in bytes from the last write-ahead log location written to disk by this standby server\"\n - flush_diff_bytes:\n usage: \"GAUGE\"\n description: \"Difference in bytes from the last write-ahead log location flushed to disk by this standby server\"\n - replay_diff_bytes:\n usage: \"GAUGE\"\n description: \"Difference in bytes from the last write-ahead log location replayed into the database on this standby server\"\n - write_lag_seconds:\n usage: \"GAUGE\"\n description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it\"\n - flush_lag_seconds:\n usage: \"GAUGE\"\n description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it\"\n - replay_lag_seconds:\n usage: \"GAUGE\"\n description: \"Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it\"\n\npg_settings:\n query: |\n SELECT name,\n CASE setting WHEN 'on' THEN '1' WHEN 'off' THEN '0' ELSE setting END AS setting\n FROM pg_catalog.pg_settings\n WHERE vartype IN ('integer', 'real', 'bool')\n ORDER BY 1\n metrics:\n - name:\n usage: \"LABEL\"\n description: \"Name of the setting\"\n - setting:\n usage: \"GAUGE\"\n description: \"Setting value\"\n\npg_extensions:\n query: |\n SELECT\n current_database() as datname,\n name as extname,\n default_version,\n installed_version,\n CASE\n WHEN default_version = installed_version THEN 0\n ELSE 1\n END AS update_available\n FROM pg_catalog.pg_available_extensions\n WHERE installed_version IS NOT NULL\n metrics:\n - datname:\n usage: \"LABEL\"\n description: \"Name of the database\"\n - extname:\n usage: \"LABEL\"\n description: \"Extension name\"\n - default_version:\n usage: \"LABEL\"\n description: \"Default version\"\n - installed_version:\n usage: \"LABEL\"\n description: \"Installed version\"\n - update_available:\n usage: \"GAUGE\"\n description: \"An update is available\"\n target_databases:\n - '*'\n"` | A string representation of a YAML defining monitoring queries. | | nameOverride | string | `""` | | | namespaceOverride | string | `""` | | | nodeSelector | object | `{}` | Nodeselector for the operator to be installed. | @@ -77,5 +77,7 @@ CloudNativePG Operator Helm Chart | serviceAccount.create | bool | `true` | Specifies whether the service account should be created. | | serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template. | | tolerations | list | `[]` | Tolerations for the operator to be installed. | -| webhook | object | `{"livenessProbe":{"initialDelaySeconds":3},"mutating":{"create":true,"failurePolicy":"Fail"},"port":9443,"readinessProbe":{"initialDelaySeconds":3},"validating":{"create":true,"failurePolicy":"Fail"}}` | The webhook configuration. | +| topologySpreadConstraints | list | `[]` | Topology Spread Constraints for the operator to be installed. | +| updateStrategy | object | `{}` | Update strategy for the operator. ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy For example: type: RollingUpdate rollingUpdate: maxSurge: 25% maxUnavailable: 25% | +| webhook | object | `{"livenessProbe":{"initialDelaySeconds":3},"mutating":{"create":true,"failurePolicy":"Fail"},"port":9443,"readinessProbe":{"initialDelaySeconds":3},"startupProbe":{"failureThreshold":6,"periodSeconds":5},"validating":{"create":true,"failurePolicy":"Fail"}}` | The webhook configuration. | diff --git a/packages/system/postgres-operator/charts/cloudnative-pg/templates/NOTES.txt b/packages/system/postgres-operator/charts/cloudnative-pg/templates/NOTES.txt index d0b65b9b..4c8ef66d 100644 --- a/packages/system/postgres-operator/charts/cloudnative-pg/templates/NOTES.txt +++ b/packages/system/postgres-operator/charts/cloudnative-pg/templates/NOTES.txt @@ -1,5 +1,5 @@ -CloudNativePG operator should be installed in namespace "{{ .Release.Namespace }}". +CloudNativePG operator should be installed in namespace "{{ include "cloudnative-pg.namespace" . }}". You can now create a PostgreSQL cluster with 3 nodes as follows: cat <= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -4322,41 +4382,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -4366,8 +4426,11 @@ spec: type: object type: array podMonitorRelabelings: - description: The list of relabelings for the `PodMonitor`. Applied - to samples before scraping. + description: |- + The list of relabelings for the `PodMonitor`. Applied to samples before scraping. + + Deprecated: This feature will be removed in an upcoming release. If + you need this functionality, you can create a PodMonitor manually. items: description: |- RelabelConfig allows dynamic rewriting of the label set for targets, alerts, @@ -4378,7 +4441,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -4410,41 +4473,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -4493,6 +4556,13 @@ spec: default: true description: Enabled is true if this plugin will be used type: boolean + isWALArchiver: + default: false + description: |- + Marks the plugin as the WAL archiver. At most one plugin can be + designated as a WAL archiver. This cannot be enabled if the + `.spec.backup.barmanObjectStore` configuration is present. + type: boolean name: description: Name is the plugin name type: string @@ -4527,6 +4597,67 @@ spec: This should only be used for debugging and troubleshooting. Defaults to false. type: boolean + extensions: + description: The configuration of the extensions to be added + items: + description: |- + ExtensionConfiguration is the configuration used to add + PostgreSQL extensions to the Cluster. + properties: + dynamic_library_path: + description: |- + The list of directories inside the image which should be added to dynamic_library_path. + If not defined, defaults to "/lib". + items: + type: string + type: array + extension_control_path: + description: |- + The list of directories inside the image which should be added to extension_control_path. + If not defined, defaults to "/share". + items: + type: string + type: array + image: + description: The image containing the extension, required + properties: + pullPolicy: + description: |- + Policy for pulling OCI objects. Possible values are: + Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + type: string + reference: + description: |- + Required: Image or artifact reference to be used. + Behaves in the same way as pod.spec.containers[*].image. + Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + type: object + x-kubernetes-validations: + - message: An image reference is required + rule: has(self.reference) + ld_library_path: + description: The list of directories inside the image which + should be added to ld_library_path. + items: + type: string + type: array + name: + description: The name of the extension, required + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - image + - name + type: object + type: array ldap: description: Options to specify LDAP configuration properties: @@ -4654,7 +4785,6 @@ spec: feature properties: dataDurability: - default: required description: |- If set to "required", data durability is strictly enforced. Write operations with synchronous commit settings (`on`, `remote_write`, or `remote_apply`) will @@ -4766,6 +4896,30 @@ spec: More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes format: int32 type: integer + isolationCheck: + description: |- + Configure the feature that extends the liveness probe for a primary + instance. In addition to the basic checks, this verifies whether the + primary is isolated from the Kubernetes API server and from its + replicas, ensuring that it can be safely shut down if network + partition or API unavailability is detected. Enabled by default. + properties: + connectionTimeout: + default: 1000 + description: Timeout in milliseconds for connections during + the primary isolation check + type: integer + enabled: + default: true + description: Whether primary isolation checking is enabled + for the liveness probe + type: boolean + requestTimeout: + default: 1000 + description: Timeout in milliseconds for requests during + the primary isolation check + type: integer + type: object periodSeconds: description: |- How often (in seconds) to perform the probe. @@ -4815,6 +4969,13 @@ spec: More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes format: int32 type: integer + maximumLag: + anyOf: + - type: integer + - type: string + description: Lag limit. Used only for `streaming` strategy + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true periodSeconds: description: |- How often (in seconds) to perform the probe. @@ -4848,6 +5009,13 @@ spec: More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes format: int32 type: integer + type: + description: The probe strategy + enum: + - pg_isready + - streaming + - query + type: string type: object startup: description: The startup probe configuration @@ -4864,6 +5032,13 @@ spec: More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes format: int32 type: integer + maximumLag: + anyOf: + - type: integer + - type: string + description: Lag limit. Used only for `streaming` strategy + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true periodSeconds: description: |- How often (in seconds) to perform the probe. @@ -4897,6 +5072,13 @@ spec: More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes format: int32 type: integer + type: + description: The probe strategy + enum: + - pg_isready + - streaming + - query + type: string type: object type: object projectedVolumeTemplate: @@ -5147,6 +5329,111 @@ spec: type: array x-kubernetes-list-type: atomic type: object + podCertificate: + description: |- + Projects an auto-rotating credential bundle (private key and certificate + chain) that the pod can use either as a TLS client or server. + + Kubelet generates a private key and uses it to send a + PodCertificateRequest to the named signer. Once the signer approves the + request and issues a certificate chain, Kubelet writes the key and + certificate chain to the pod filesystem. The pod does not start until + certificates have been issued for each podCertificate projected volume + source in its spec. + + Kubelet will begin trying to rotate the certificate at the time indicated + by the signer using the PodCertificateRequest.Status.BeginRefreshAt + timestamp. + + Kubelet can write a single file, indicated by the credentialBundlePath + field, or separate files, indicated by the keyPath and + certificateChainPath fields. + + The credential bundle is a single file in PEM format. The first PEM + entry is the private key (in PKCS#8 format), and the remaining PEM + entries are the certificate chain issued by the signer (typically, + signers will return their certificate chain in leaf-to-root order). + + Prefer using the credential bundle format, since your application code + can read it atomically. If you use keyPath and certificateChainPath, + your application must make two separate file reads. If these coincide + with a certificate rotation, it is possible that the private key and leaf + certificate you read may not correspond to each other. Your application + will need to check for this condition, and re-read until they are + consistent. + + The named signer controls chooses the format of the certificate it + issues; consult the signer implementation's documentation to learn how to + use the certificates it issues. + properties: + certificateChainPath: + description: |- + Write the certificate chain at this path in the projected volume. + + Most applications should use credentialBundlePath. When using keyPath + and certificateChainPath, your application needs to check that the key + and leaf certificate are consistent, because it is possible to read the + files mid-rotation. + type: string + credentialBundlePath: + description: |- + Write the credential bundle at this path in the projected volume. + + The credential bundle is a single file that contains multiple PEM blocks. + The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private + key. + + The remaining blocks are CERTIFICATE blocks, containing the issued + certificate chain from the signer (leaf and any intermediates). + + Using credentialBundlePath lets your Pod's application code make a single + atomic read that retrieves a consistent key and certificate chain. If you + project them to separate files, your application code will need to + additionally check that the leaf certificate was issued to the key. + type: string + keyPath: + description: |- + Write the key at this path in the projected volume. + + Most applications should use credentialBundlePath. When using keyPath + and certificateChainPath, your application needs to check that the key + and leaf certificate are consistent, because it is possible to read the + files mid-rotation. + type: string + keyType: + description: |- + The type of keypair Kubelet will generate for the pod. + + Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384", + "ECDSAP521", and "ED25519". + type: string + maxExpirationSeconds: + description: |- + maxExpirationSeconds is the maximum lifetime permitted for the + certificate. + + Kubelet copies this value verbatim into the PodCertificateRequests it + generates for this projection. + + If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver + will reject values shorter than 3600 (1 hour). The maximum allowable + value is 7862400 (91 days). + + The signer implementation is then free to issue a certificate with any + lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600 + seconds (1 hour). This constraint is enforced by kube-apiserver. + `kubernetes.io` signers will never issue certificates with a lifetime + longer than 24 hours. + format: int32 + type: integer + signerName: + description: Kubelet's generated CSRs will be addressed + to this signer. + type: string + required: + - keyType + - signerName + type: object secret: description: secret information about the secret data to project @@ -5309,6 +5596,15 @@ spec: This can only be set at creation time. By default set to `_cnpg_`. pattern: ^[0-9a-z_]*$ type: string + synchronizeLogicalDecoding: + description: |- + When enabled, the operator automatically manages synchronization of logical + decoding (replication) slots across high-availability clusters. + + Requires one of the following conditions: + - PostgreSQL version 17 or later + - PostgreSQL version < 17 with pg_failover_slots extension enabled + type: boolean type: object synchronizeReplicas: description: Configures the synchronization of the user defined @@ -5348,7 +5644,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -5469,7 +5765,7 @@ spec: description: |- The time in seconds that controls the window of time reserved for the smart shutdown of Postgres to complete. Make sure you reserve enough time for the operator to request a fast shutdown of Postgres - (that is: `stopDelay` - `smartShutdownTimeout`). + (that is: `stopDelay` - `smartShutdownTimeout`). Default is 180 seconds. format: int32 type: integer startDelay: @@ -5669,15 +5965,13 @@ spec: volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. If specified, the CSI driver will create or update the volume with the attributes defined in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -5927,15 +6221,13 @@ spec: volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. If specified, the CSI driver will create or update the volume with the attributes defined in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -6104,7 +6396,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: |- @@ -6115,7 +6406,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: |- @@ -6339,15 +6629,13 @@ spec: volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. If specified, the CSI driver will create or update the volume with the attributes defined in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -6407,10 +6695,6 @@ spec: - hash type: object type: array - azurePVCUpdateEnabled: - description: AzurePVCUpdateEnabled shows if the PVC online upgrade - is enabled for this cluster - type: boolean certificates: description: The configuration for the CA and related certificates, initialized with defaults. @@ -6572,14 +6856,18 @@ spec: firstRecoverabilityPoint: description: |- The first recoverability point, stored as a date in RFC3339 format. - This field is calculated from the content of FirstRecoverabilityPointByMethod + This field is calculated from the content of FirstRecoverabilityPointByMethod. + + Deprecated: the field is not set for backup plugins. type: string firstRecoverabilityPointByMethod: additionalProperties: format: date-time type: string - description: The first recoverability point, stored as a date in RFC3339 - format, per backup method type + description: |- + The first recoverability point, stored as a date in RFC3339 format, per backup method type. + + Deprecated: the field is not set for backup plugins. type: object healthyPVC: description: List of all the PVCs not dangling nor initializing @@ -6609,6 +6897,9 @@ spec: description: InstanceReportedState describes the last reported state of an instance during a reconciliation loop properties: + ip: + description: IP address of the instance + type: string isPrimary: description: indicates if an instance is the primary one type: boolean @@ -6634,7 +6925,10 @@ spec: format: int32 type: integer lastFailedBackup: - description: Stored as a date in RFC3339 format + description: |- + Last failed backup, stored as a date in RFC3339 format. + + Deprecated: the field is not set for backup plugins. type: string lastPromotionToken: description: |- @@ -6643,15 +6937,19 @@ spec: type: string lastSuccessfulBackup: description: |- - Last successful backup, stored as a date in RFC3339 format - This field is calculated from the content of LastSuccessfulBackupByMethod + Last successful backup, stored as a date in RFC3339 format. + This field is calculated from the content of LastSuccessfulBackupByMethod. + + Deprecated: the field is not set for backup plugins. type: string lastSuccessfulBackupByMethod: additionalProperties: format: date-time type: string - description: Last successful backup, stored as a date in RFC3339 format, - per backup method type + description: |- + Last successful backup, stored as a date in RFC3339 format, per backup method type. + + Deprecated: the field is not set for backup plugins. type: object latestGeneratedNode: description: ID of the latest generated node (used to avoid node name @@ -6699,6 +6997,20 @@ spec: description: OnlineUpdateEnabled shows if the online upgrade is enabled inside the cluster type: boolean + pgDataImageInfo: + description: PGDataImageInfo contains the details of the latest image + that has run on the current data directory. + properties: + image: + description: Image is the image name + type: string + majorVersion: + description: MajorVersion is the major version of the image + type: integer + required: + - image + - majorVersion + type: object phase: description: Current phase of the cluster type: string @@ -6854,6 +7166,9 @@ spec: of switching a cluster to a replica cluster. type: boolean type: object + systemID: + description: SystemID is the latest detected PostgreSQL SystemID + type: string tablespacesStatus: description: TablespacesStatus reports the state of the declarative tablespaces in the cluster @@ -6943,7 +7258,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.19.0 helm.sh/resource-policy: keep name: databases.postgresql.cnpg.io spec: @@ -7065,6 +7380,43 @@ spec: - present - absent type: string + extensions: + description: The list of extensions to be managed in the database + items: + description: ExtensionSpec configures an extension in a database + properties: + ensure: + default: present + description: |- + Specifies whether an extension/schema should be present or absent in + the database. If set to `present`, the extension/schema will be + created if it does not exist. If set to `absent`, the + extension/schema will be removed if it exists. + enum: + - present + - absent + type: string + name: + description: Name of the extension/schema + type: string + schema: + description: |- + The name of the schema in which to install the extension's objects, + in case the extension allows its contents to be relocated. If not + specified (default), and the extension's control file does not + specify a schema either, the current default object creation schema + is used. + type: string + version: + description: |- + The version of the extension to install. If empty, the operator will + install the default version (whatever is specified in the + extension's control file) + type: string + required: + - name + type: object + type: array icuLocale: description: |- Maps to the `ICU_LOCALE` parameter of `CREATE DATABASE`. This @@ -7144,6 +7496,35 @@ spec: Maps to the `OWNER TO` command of `ALTER DATABASE`. The role name of the user who owns the database inside PostgreSQL. type: string + schemas: + description: The list of schemas to be managed in the database + items: + description: SchemaSpec configures a schema in a database + properties: + ensure: + default: present + description: |- + Specifies whether an extension/schema should be present or absent in + the database. If set to `present`, the extension/schema will be + created if it does not exist. If set to `absent`, the + extension/schema will be removed if it exists. + enum: + - present + - absent + type: string + name: + description: Name of the extension/schema + type: string + owner: + description: |- + The role name of the user who owns the schema inside PostgreSQL. + It maps to the `AUTHORIZATION` parameter of `CREATE SCHEMA` and the + `OWNER TO` command of `ALTER SCHEMA`. + type: string + required: + - name + type: object + type: array tablespace: description: |- Maps to the `TABLESPACE` parameter of `CREATE DATABASE`. @@ -7183,6 +7564,28 @@ spec: applied: description: Applied is true if the database was reconciled correctly type: boolean + extensions: + description: Extensions is the status of the managed extensions + items: + description: DatabaseObjectStatus is the status of the managed database + objects + properties: + applied: + description: |- + True of the object has been installed successfully in + the database + type: boolean + message: + description: Message is the object reconciliation message + type: string + name: + description: The name of the object + type: string + required: + - applied + - name + type: object + type: array message: description: Message is the reconciliation output message type: string @@ -7192,6 +7595,28 @@ spec: desired state that was synchronized format: int64 type: integer + schemas: + description: Schemas is the status of the managed schemas + items: + description: DatabaseObjectStatus is the status of the managed database + objects + properties: + applied: + description: |- + True of the object has been installed successfully in + the database + type: boolean + message: + description: Message is the object reconciliation message + type: string + name: + description: The name of the object + type: string + required: + - applied + - name + type: object + type: array type: object required: - metadata @@ -7206,7 +7631,85 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.19.0 + helm.sh/resource-policy: keep + name: failoverquorums.postgresql.cnpg.io +spec: + group: postgresql.cnpg.io + names: + kind: FailoverQuorum + listKind: FailoverQuorumList + plural: failoverquorums + singular: failoverquorum + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: |- + FailoverQuorum contains the information about the current failover + quorum status of a PG cluster. It is updated by the instance manager + of the primary node and reset to zero by the operator to trigger + an update. + 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 + status: + description: Most recently observed status of the failover quorum. + properties: + method: + description: Contains the latest reported Method value. + type: string + primary: + description: |- + Primary is the name of the primary instance that updated + this object the latest time. + type: string + standbyNames: + description: |- + StandbyNames is the list of potentially synchronous + instance names. + items: + type: string + type: array + standbyNumber: + description: |- + StandbyNumber is the number of synchronous standbys that transactions + need to wait for replies from. + type: integer + type: object + required: + - metadata + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 helm.sh/resource-policy: keep name: imagecatalogs.postgresql.cnpg.io spec: @@ -7287,7 +7790,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.19.0 helm.sh/resource-policy: keep name: poolers.postgresql.cnpg.io spec: @@ -7401,8 +7904,11 @@ spec: format: int32 type: integer monitoring: - description: The configuration of the monitoring infrastructure of - this pooler. + description: |- + The configuration of the monitoring infrastructure of this pooler. + + Deprecated: This feature will be removed in an upcoming release. If + you need this functionality, you can create a PodMonitor manually. properties: enablePodMonitor: default: false @@ -7421,7 +7927,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -7453,41 +7959,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -7509,7 +8015,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -7541,41 +8047,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -7986,13 +8492,12 @@ spec: type: object trafficDistribution: description: |- - TrafficDistribution offers a way to express preferences for how traffic is - distributed to Service endpoints. Implementations can use this field as a - hint, but are not required to guarantee strict adherence. If the field is - not set, the implementation will apply its default routing strategy. If set - to "PreferClose", implementations should prioritize endpoints that are - topologically close (e.g., same zone). - This is a beta field and requires enabling ServiceTrafficDistribution feature. + TrafficDistribution offers a way to express preferences for how traffic + is distributed to Service endpoints. Implementations can use this field + as a hint, but are not required to guarantee strict adherence. If the + field is not set, the implementation will apply its default routing + strategy. If set to "PreferClose", implementations should prioritize + endpoints that are in the same zone. type: string type: description: |- @@ -8346,7 +8851,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 @@ -8361,7 +8865,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 @@ -8529,7 +9032,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 @@ -8544,7 +9046,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 @@ -8638,8 +9139,8 @@ spec: most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), - compute a sum by iterating through the elements of this field and adding - "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + compute a sum by iterating through the elements of this field and subtracting + "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. items: description: The weights of all of the matched WeightedPodAffinityTerm @@ -8710,7 +9211,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 @@ -8725,7 +9225,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 @@ -8893,7 +9392,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 @@ -8908,7 +9406,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 @@ -9041,8 +9538,9 @@ spec: present in a Container. properties: name: - description: Name of the environment variable. - Must be a C_IDENTIFIER. + description: |- + Name of the environment variable. + May consist of any printable ASCII characters except '='. type: string value: description: |- @@ -9101,6 +9599,43 @@ spec: - fieldPath type: object x-kubernetes-map-type: atomic + fileKeyRef: + description: |- + FileKeyRef selects a key of the env file. + Requires the EnvFiles feature gate to be enabled. + properties: + key: + description: |- + The key within the env file. An invalid key will prevent the pod from starting. + The keys defined within a source may consist of any printable ASCII characters except '='. + During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. + type: string + optional: + default: false + description: |- + Specify whether the file or its key must be defined. If the file or key + does not exist, then the env var is not published. + If optional is set to true and the specified key does not exist, + the environment variable will not be set in the Pod's containers. + + If optional is set to false and the specified key does not exist, + an error will be returned during Pod creation. + type: boolean + path: + description: |- + The path within the volume from which to select the file. + Must be relative and may not contain the '..' path or start with '..'. + type: string + volumeName: + description: The name of the volume mount + containing the env file. + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic resourceFieldRef: description: |- Selects a resource of the container: only resources limits and requests @@ -9163,14 +9698,14 @@ spec: envFrom: description: |- List of sources to populate environment variables in the container. - The keys defined within a source must be a C_IDENTIFIER. All invalid keys - will be reported as an event when the container is starting. When a key exists in multiple + The keys defined within a source may consist of any printable ASCII characters except '='. + When a key exists in multiple sources, the value associated with the last source will take precedence. 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 + a set of ConfigMaps or Secrets properties: configMapRef: description: The ConfigMap to select from @@ -9191,8 +9726,9 @@ 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. + May consist of any printable ASCII characters except '='. type: string secretRef: description: The Secret to select from @@ -9458,6 +9994,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: |- @@ -9865,7 +10407,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -9920,10 +10462,10 @@ spec: restartPolicy: description: |- RestartPolicy defines the restart behavior of individual containers in a pod. - This field may only be set for init containers, and the only allowed value is "Always". - For non-init containers or when this field is not specified, + This overrides the pod-level restart policy. When this field is not specified, the restart behavior is defined by the Pod's restart policy and the container type. - Setting the RestartPolicy as "Always" for the init container will have the following effect: + Additionally, setting the RestartPolicy as "Always" for the init container will + have the following effect: this init container will be continually restarted on exit until all regular containers have terminated. Once all regular containers have completed, all init containers with restartPolicy "Always" @@ -9935,6 +10477,59 @@ spec: init container is started, or after any startupProbe has successfully completed. type: string + restartPolicyRules: + description: |- + Represents a list of rules to be checked to determine if the + container should be restarted on exit. The rules are evaluated in + order. Once a rule matches a container exit condition, the remaining + rules are ignored. If no rule matches the container exit condition, + the Container-level restart policy determines the whether the container + is restarted or not. Constraints on the rules: + - At most 20 rules are allowed. + - Rules can have the same action. + - Identical rules are not forbidden in validations. + When rules are specified, container MUST set RestartPolicy explicitly + even it if matches the Pod's RestartPolicy. + items: + description: ContainerRestartRule describes how a + container exit is handled. + properties: + action: + description: |- + Specifies the action taken on a container exit if the requirements + are satisfied. The only possible value is "Restart" to restart the + container. + type: string + exitCodes: + description: Represents the exit codes to check + on container exits. + properties: + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. Possible values are: + - In: the requirement is satisfied if the container exit code is in the + set of specified values. + - NotIn: the requirement is satisfied if the container exit code is + not in the set of specified values. + type: string + values: + description: |- + Specifies the set of values to check for container exit codes. + At most 255 elements are allowed. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic securityContext: description: |- SecurityContext defines the security options the container should be run with. @@ -10555,8 +11150,9 @@ spec: present in a Container. properties: name: - description: Name of the environment variable. - Must be a C_IDENTIFIER. + description: |- + Name of the environment variable. + May consist of any printable ASCII characters except '='. type: string value: description: |- @@ -10615,6 +11211,43 @@ spec: - fieldPath type: object x-kubernetes-map-type: atomic + fileKeyRef: + description: |- + FileKeyRef selects a key of the env file. + Requires the EnvFiles feature gate to be enabled. + properties: + key: + description: |- + The key within the env file. An invalid key will prevent the pod from starting. + The keys defined within a source may consist of any printable ASCII characters except '='. + During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. + type: string + optional: + default: false + description: |- + Specify whether the file or its key must be defined. If the file or key + does not exist, then the env var is not published. + If optional is set to true and the specified key does not exist, + the environment variable will not be set in the Pod's containers. + + If optional is set to false and the specified key does not exist, + an error will be returned during Pod creation. + type: boolean + path: + description: |- + The path within the volume from which to select the file. + Must be relative and may not contain the '..' path or start with '..'. + type: string + volumeName: + description: The name of the volume mount + containing the env file. + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic resourceFieldRef: description: |- Selects a resource of the container: only resources limits and requests @@ -10677,14 +11310,14 @@ spec: envFrom: description: |- List of sources to populate environment variables in the container. - The keys defined within a source must be a C_IDENTIFIER. All invalid keys - will be reported as an event when the container is starting. When a key exists in multiple + The keys defined within a source may consist of any printable ASCII characters except '='. + When a key exists in multiple sources, the value associated with the last source will take precedence. 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 + a set of ConfigMaps or Secrets properties: configMapRef: description: The ConfigMap to select from @@ -10705,8 +11338,9 @@ 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. + May consist of any printable ASCII characters except '='. type: string secretRef: description: The Secret to select from @@ -10969,6 +11603,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: Probes are not allowed for ephemeral containers. @@ -11359,7 +11999,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -11415,9 +12055,53 @@ spec: description: |- Restart policy for the container to manage the restart behavior of each container within a pod. - This may only be set for init containers. You cannot set this field on - ephemeral containers. + You cannot set this field on ephemeral containers. type: string + restartPolicyRules: + description: |- + Represents a list of rules to be checked to determine if the + container should be restarted on exit. You cannot set this field on + ephemeral containers. + items: + description: ContainerRestartRule describes how a + container exit is handled. + properties: + action: + description: |- + Specifies the action taken on a container exit if the requirements + are satisfied. The only possible value is "Restart" to restart the + container. + type: string + exitCodes: + description: Represents the exit codes to check + on container exits. + properties: + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. Possible values are: + - In: the requirement is satisfied if the container exit code is in the + set of specified values. + - NotIn: the requirement is satisfied if the container exit code is + not in the set of specified values. + type: string + values: + description: |- + Specifies the set of values to check for container exit codes. + At most 255 elements are allowed. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic securityContext: description: |- Optional: SecurityContext defines the security options the ephemeral container should be run with. @@ -11956,7 +12640,9 @@ spec: hostNetwork: description: |- Host networking requested for this pod. Use the host's network namespace. - If this option is set, the ports that will be used must be specified. + When using HostNetwork you should specify ports so the scheduler is aware. + When `hostNetwork` is true, specified `hostPort` fields in port definitions must match `containerPort`, + and unspecified `hostPort` fields in port definitions are defaulted to match `containerPort`. Default to false. type: boolean hostPID: @@ -11981,6 +12667,19 @@ spec: Specifies the hostname of the Pod If not specified, the pod's hostname will be set to a system-defined value. type: string + hostnameOverride: + description: |- + HostnameOverride specifies an explicit override for the pod's hostname as perceived by the pod. + This field only specifies the pod's hostname and does not affect its DNS records. + When this field is set to a non-empty string: + - It takes precedence over the values set in `hostname` and `subdomain`. + - The Pod's hostname will be set to this value. + - `setHostnameAsFQDN` must be nil or set to false. + - `hostNetwork` must be set to false. + + This field must be a valid DNS subdomain as defined in RFC 1123 and contain at most 64 characters. + Requires the HostnameOverride feature gate to be enabled. + type: string imagePullSecrets: description: |- ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. @@ -12016,7 +12715,7 @@ spec: Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. The resourceRequirements of an init container are taken into account during scheduling by finding the highest request/limit for each resource type, and then using the max of - of that value or the sum of the normal containers. Limits are applied to init containers + that value or the sum of the normal containers. Limits are applied to init containers in a similar fashion. Init containers cannot currently be added or removed. Cannot be updated. @@ -12062,8 +12761,9 @@ spec: present in a Container. properties: name: - description: Name of the environment variable. - Must be a C_IDENTIFIER. + description: |- + Name of the environment variable. + May consist of any printable ASCII characters except '='. type: string value: description: |- @@ -12122,6 +12822,43 @@ spec: - fieldPath type: object x-kubernetes-map-type: atomic + fileKeyRef: + description: |- + FileKeyRef selects a key of the env file. + Requires the EnvFiles feature gate to be enabled. + properties: + key: + description: |- + The key within the env file. An invalid key will prevent the pod from starting. + The keys defined within a source may consist of any printable ASCII characters except '='. + During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. + type: string + optional: + default: false + description: |- + Specify whether the file or its key must be defined. If the file or key + does not exist, then the env var is not published. + If optional is set to true and the specified key does not exist, + the environment variable will not be set in the Pod's containers. + + If optional is set to false and the specified key does not exist, + an error will be returned during Pod creation. + type: boolean + path: + description: |- + The path within the volume from which to select the file. + Must be relative and may not contain the '..' path or start with '..'. + type: string + volumeName: + description: The name of the volume mount + containing the env file. + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic resourceFieldRef: description: |- Selects a resource of the container: only resources limits and requests @@ -12184,14 +12921,14 @@ spec: envFrom: description: |- List of sources to populate environment variables in the container. - The keys defined within a source must be a C_IDENTIFIER. All invalid keys - will be reported as an event when the container is starting. When a key exists in multiple + The keys defined within a source may consist of any printable ASCII characters except '='. + When a key exists in multiple sources, the value associated with the last source will take precedence. 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 + a set of ConfigMaps or Secrets properties: configMapRef: description: The ConfigMap to select from @@ -12212,8 +12949,9 @@ 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. + May consist of any printable ASCII characters except '='. type: string secretRef: description: The Secret to select from @@ -12479,6 +13217,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: |- @@ -12886,7 +13630,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -12941,10 +13685,10 @@ spec: restartPolicy: description: |- RestartPolicy defines the restart behavior of individual containers in a pod. - This field may only be set for init containers, and the only allowed value is "Always". - For non-init containers or when this field is not specified, + This overrides the pod-level restart policy. When this field is not specified, the restart behavior is defined by the Pod's restart policy and the container type. - Setting the RestartPolicy as "Always" for the init container will have the following effect: + Additionally, setting the RestartPolicy as "Always" for the init container will + have the following effect: this init container will be continually restarted on exit until all regular containers have terminated. Once all regular containers have completed, all init containers with restartPolicy "Always" @@ -12956,6 +13700,59 @@ spec: init container is started, or after any startupProbe has successfully completed. type: string + restartPolicyRules: + description: |- + Represents a list of rules to be checked to determine if the + container should be restarted on exit. The rules are evaluated in + order. Once a rule matches a container exit condition, the remaining + rules are ignored. If no rule matches the container exit condition, + the Container-level restart policy determines the whether the container + is restarted or not. Constraints on the rules: + - At most 20 rules are allowed. + - Rules can have the same action. + - Identical rules are not forbidden in validations. + When rules are specified, container MUST set RestartPolicy explicitly + even it if matches the Pod's RestartPolicy. + items: + description: ContainerRestartRule describes how a + container exit is handled. + properties: + action: + description: |- + Specifies the action taken on a container exit if the requirements + are satisfied. The only possible value is "Restart" to restart the + container. + type: string + exitCodes: + description: Represents the exit codes to check + on container exits. + properties: + operator: + description: |- + Represents the relationship between the container exit code(s) and the + specified values. Possible values are: + - In: the requirement is satisfied if the container exit code is in the + set of specified values. + - NotIn: the requirement is satisfied if the container exit code is + not in the set of specified values. + type: string + values: + description: |- + Specifies the set of values to check for container exit codes. + At most 255 elements are allowed. + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic securityContext: description: |- SecurityContext defines the security options the container should be run with. @@ -13489,6 +14286,7 @@ spec: - spec.hostPID - spec.hostIPC - spec.hostUsers + - spec.resources - spec.securityContext.appArmorProfile - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile @@ -13642,7 +14440,7 @@ spec: description: |- Resources is the total amount of CPU and Memory resources required by all containers in the pod. It supports specifying Requests and Limits for - "cpu" and "memory" resource names only. ResourceClaims are not supported. + "cpu", "memory" and "hugepages-" resource names only. ResourceClaims are not supported. This field enables fine-grained control over resource allocation for the entire pod, allowing resource sharing among containers in a pod. @@ -13655,7 +14453,7 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the + This field depends on the DynamicResourceAllocation feature gate. This field is immutable. It can only be set for containers. @@ -14193,7 +14991,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: |- @@ -14204,7 +15001,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: |- @@ -14934,15 +15730,13 @@ spec: volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. If specified, the CSI driver will create or update the volume with the attributes defined in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. + it can be changed after the claim is created. An empty string or nil value indicates that no + VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + this field can be reset to its previous value (including nil) to cancel the modification. If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -15124,12 +15918,10 @@ spec: description: |- glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported. - More info: https://examples.k8s.io/volumes/glusterfs/README.md properties: endpoints: - description: |- - endpoints is the endpoint name that details Glusterfs topology. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + description: endpoints is the endpoint name that + details Glusterfs topology. type: string path: description: |- @@ -15183,7 +15975,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: @@ -15208,7 +16000,7 @@ spec: description: |- iscsi represents an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod. - More info: https://examples.k8s.io/volumes/iscsi/README.md + More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi properties: chapAuthDiscovery: description: chapAuthDiscovery defines whether support @@ -15634,6 +16426,111 @@ spec: type: array x-kubernetes-list-type: atomic type: object + podCertificate: + description: |- + Projects an auto-rotating credential bundle (private key and certificate + chain) that the pod can use either as a TLS client or server. + + Kubelet generates a private key and uses it to send a + PodCertificateRequest to the named signer. Once the signer approves the + request and issues a certificate chain, Kubelet writes the key and + certificate chain to the pod filesystem. The pod does not start until + certificates have been issued for each podCertificate projected volume + source in its spec. + + Kubelet will begin trying to rotate the certificate at the time indicated + by the signer using the PodCertificateRequest.Status.BeginRefreshAt + timestamp. + + Kubelet can write a single file, indicated by the credentialBundlePath + field, or separate files, indicated by the keyPath and + certificateChainPath fields. + + The credential bundle is a single file in PEM format. The first PEM + entry is the private key (in PKCS#8 format), and the remaining PEM + entries are the certificate chain issued by the signer (typically, + signers will return their certificate chain in leaf-to-root order). + + Prefer using the credential bundle format, since your application code + can read it atomically. If you use keyPath and certificateChainPath, + your application must make two separate file reads. If these coincide + with a certificate rotation, it is possible that the private key and leaf + certificate you read may not correspond to each other. Your application + will need to check for this condition, and re-read until they are + consistent. + + The named signer controls chooses the format of the certificate it + issues; consult the signer implementation's documentation to learn how to + use the certificates it issues. + properties: + certificateChainPath: + description: |- + Write the certificate chain at this path in the projected volume. + + Most applications should use credentialBundlePath. When using keyPath + and certificateChainPath, your application needs to check that the key + and leaf certificate are consistent, because it is possible to read the + files mid-rotation. + type: string + credentialBundlePath: + description: |- + Write the credential bundle at this path in the projected volume. + + The credential bundle is a single file that contains multiple PEM blocks. + The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private + key. + + The remaining blocks are CERTIFICATE blocks, containing the issued + certificate chain from the signer (leaf and any intermediates). + + Using credentialBundlePath lets your Pod's application code make a single + atomic read that retrieves a consistent key and certificate chain. If you + project them to separate files, your application code will need to + additionally check that the leaf certificate was issued to the key. + type: string + keyPath: + description: |- + Write the key at this path in the projected volume. + + Most applications should use credentialBundlePath. When using keyPath + and certificateChainPath, your application needs to check that the key + and leaf certificate are consistent, because it is possible to read the + files mid-rotation. + type: string + keyType: + description: |- + The type of keypair Kubelet will generate for the pod. + + Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384", + "ECDSAP521", and "ED25519". + type: string + maxExpirationSeconds: + description: |- + maxExpirationSeconds is the maximum lifetime permitted for the + certificate. + + Kubelet copies this value verbatim into the PodCertificateRequests it + generates for this projection. + + If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver + will reject values shorter than 3600 (1 hour). The maximum allowable + value is 7862400 (91 days). + + The signer implementation is then free to issue a certificate with any + lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600 + seconds (1 hour). This constraint is enforced by kube-apiserver. + `kubernetes.io` signers will never issue certificates with a lifetime + longer than 24 hours. + format: int32 + type: integer + signerName: + description: Kubelet's generated CSRs + will be addressed to this signer. + type: string + required: + - keyType + - signerName + type: object secret: description: secret information about the secret data to project @@ -15768,7 +16665,6 @@ spec: description: |- rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported. - More info: https://examples.k8s.io/volumes/rbd/README.md properties: fsType: description: |- @@ -16066,6 +16962,7 @@ spec: enum: - rw - ro + - r type: string required: - cluster @@ -16146,7 +17043,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.19.0 helm.sh/resource-policy: keep name: publications.postgresql.cnpg.io spec: @@ -16342,7 +17239,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.19.0 helm.sh/resource-policy: keep name: scheduledbackups.postgresql.cnpg.io spec: @@ -16534,7 +17431,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.16.5 + controller-gen.kubebuilder.io/version: v0.19.0 helm.sh/resource-policy: keep name: subscriptions.postgresql.cnpg.io spec: @@ -16625,8 +17522,11 @@ spec: additionalProperties: type: string description: |- - Subscription parameters part of the `WITH` clause as expected by - PostgreSQL `CREATE SUBSCRIPTION` command + Subscription parameters included in the `WITH` clause of the PostgreSQL + `CREATE SUBSCRIPTION` command. Most parameters cannot be changed + after the subscription is created and will be ignored if modified + later, except for a limited set documented at: + https://www.postgresql.org/docs/current/sql-altersubscription.html#SQL-ALTERSUBSCRIPTION-PARAMS-SET type: object publicationDBName: description: |- diff --git a/packages/system/postgres-operator/charts/cloudnative-pg/templates/deployment.yaml b/packages/system/postgres-operator/charts/cloudnative-pg/templates/deployment.yaml index 7e0bce72..760b3768 100644 --- a/packages/system/postgres-operator/charts/cloudnative-pg/templates/deployment.yaml +++ b/packages/system/postgres-operator/charts/cloudnative-pg/templates/deployment.yaml @@ -1,5 +1,6 @@ # -# Copyright The CloudNativePG Contributors +# Copyright © contributors to CloudNativePG, established as +# CloudNativePG a Series of LF Projects, LLC. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# --- apiVersion: apps/v1 kind: Deployment @@ -30,6 +33,10 @@ spec: selector: matchLabels: {{- include "cloudnative-pg.selectorLabels" . | nindent 6 }} + {{- if .Values.updateStrategy }} + strategy: + {{- toYaml .Values.updateStrategy | nindent 4 }} + {{- end }} template: metadata: annotations: @@ -84,7 +91,7 @@ spec: value: "{{ .Values.monitoringQueriesConfigMap.name }}" {{- if not .Values.config.clusterWide }} - name: WATCH_NAMESPACE - value: "{{ .Release.Namespace }}" + value: "{{ include "cloudnative-pg.namespace" . }}" {{- end }} {{- if .Values.additionalEnv }} {{- tpl (.Values.additionalEnv | toYaml) . | nindent 8 }} @@ -119,6 +126,17 @@ spec: {{- toYaml .Values.resources | nindent 10 }} securityContext: {{- toYaml .Values.containerSecurityContext | nindent 10 }} + startupProbe: + {{- if .Values.webhook.startupProbe.failureThreshold }} + failureThreshold: {{ .Values.webhook.startupProbe.failureThreshold }} + {{- end }} + httpGet: + path: /readyz + port: {{ .Values.webhook.port }} + scheme: HTTPS + {{- if .Values.webhook.startupProbe.periodSeconds }} + periodSeconds: {{ .Values.webhook.startupProbe.periodSeconds }} + {{- end }} volumeMounts: - mountPath: /controller name: scratch-data @@ -135,6 +153,10 @@ spec: nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} + {{- with .Values.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 8 }} + {{- end }} {{- with .Values.affinity }} affinity: {{- toYaml . | nindent 8 }} @@ -151,5 +173,3 @@ spec: defaultMode: 420 optional: true secretName: cnpg-webhook-cert - - diff --git a/packages/system/postgres-operator/charts/cloudnative-pg/templates/monitoring-configmap.yaml b/packages/system/postgres-operator/charts/cloudnative-pg/templates/monitoring-configmap.yaml index aa5937d5..d47bc744 100644 --- a/packages/system/postgres-operator/charts/cloudnative-pg/templates/monitoring-configmap.yaml +++ b/packages/system/postgres-operator/charts/cloudnative-pg/templates/monitoring-configmap.yaml @@ -1,5 +1,6 @@ # -# Copyright The CloudNativePG Contributors +# Copyright © contributors to CloudNativePG, established as +# CloudNativePG a Series of LF Projects, LLC. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# --- apiVersion: v1 kind: ConfigMap diff --git a/packages/system/postgres-operator/charts/cloudnative-pg/templates/mutatingwebhookconfiguration.yaml b/packages/system/postgres-operator/charts/cloudnative-pg/templates/mutatingwebhookconfiguration.yaml index 200695b1..c58628a6 100644 --- a/packages/system/postgres-operator/charts/cloudnative-pg/templates/mutatingwebhookconfiguration.yaml +++ b/packages/system/postgres-operator/charts/cloudnative-pg/templates/mutatingwebhookconfiguration.yaml @@ -1,5 +1,6 @@ # -# Copyright The CloudNativePG Contributors +# Copyright © contributors to CloudNativePG, established as +# CloudNativePG a Series of LF Projects, LLC. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# {{- if .Values.webhook.mutating.create }} --- apiVersion: admissionregistration.k8s.io/v1 @@ -31,7 +34,7 @@ webhooks: clientConfig: service: name: {{ .Values.service.name }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudnative-pg.namespace" . }} path: /mutate-postgresql-cnpg-io-v1-backup port: {{ .Values.service.port }} failurePolicy: {{ .Values.webhook.mutating.failurePolicy }} @@ -52,7 +55,7 @@ webhooks: clientConfig: service: name: {{ .Values.service.name }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudnative-pg.namespace" . }} path: /mutate-postgresql-cnpg-io-v1-cluster port: {{ .Values.service.port }} failurePolicy: {{ .Values.webhook.mutating.failurePolicy }} @@ -73,7 +76,28 @@ webhooks: clientConfig: service: name: {{ .Values.service.name }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudnative-pg.namespace" . }} + path: /mutate-postgresql-cnpg-io-v1-database + port: {{ .Values.service.port }} + failurePolicy: {{ .Values.webhook.mutating.failurePolicy }} + name: mdatabase.cnpg.io + rules: + - apiGroups: + - postgresql.cnpg.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - databases + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ .Values.service.name }} + namespace: {{ include "cloudnative-pg.namespace" . }} path: /mutate-postgresql-cnpg-io-v1-scheduledbackup port: {{ .Values.service.port }} failurePolicy: {{ .Values.webhook.mutating.failurePolicy }} diff --git a/packages/system/postgres-operator/charts/cloudnative-pg/templates/podmonitor.yaml b/packages/system/postgres-operator/charts/cloudnative-pg/templates/podmonitor.yaml index 8984c00f..0d22102b 100644 --- a/packages/system/postgres-operator/charts/cloudnative-pg/templates/podmonitor.yaml +++ b/packages/system/postgres-operator/charts/cloudnative-pg/templates/podmonitor.yaml @@ -1,5 +1,6 @@ # -# Copyright The CloudNativePG Contributors +# Copyright © contributors to CloudNativePG, established as +# CloudNativePG a Series of LF Projects, LLC. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# {{- if .Values.monitoring.podMonitorEnabled }} apiVersion: monitoring.coreos.com/v1 kind: PodMonitor diff --git a/packages/system/postgres-operator/charts/cloudnative-pg/templates/rbac.yaml b/packages/system/postgres-operator/charts/cloudnative-pg/templates/rbac.yaml index cf213f35..0dc17080 100644 --- a/packages/system/postgres-operator/charts/cloudnative-pg/templates/rbac.yaml +++ b/packages/system/postgres-operator/charts/cloudnative-pg/templates/rbac.yaml @@ -1,5 +1,6 @@ # -# Copyright The CloudNativePG Contributors +# Copyright © contributors to CloudNativePG, established as +# CloudNativePG a Series of LF Projects, LLC. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# {{- if .Values.serviceAccount.create }} --- apiVersion: v1 @@ -67,7 +70,7 @@ roleRef: subjects: - kind: ServiceAccount name: {{ include "cloudnative-pg.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudnative-pg.namespace" . }} {{/* If we're doing a single-namespace installation we create a Role with the common rules for the operator, @@ -108,7 +111,7 @@ roleRef: subjects: - kind: ServiceAccount name: {{ include "cloudnative-pg.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudnative-pg.namespace" . }} {{- end }} --- apiVersion: rbac.authorization.k8s.io/v1 @@ -128,10 +131,14 @@ rules: resources: - backups - clusters + - clusters/status - databases + - failoverquorums - poolers - publications - scheduledbackups + - imagecatalogs + - clusterimagecatalogs - subscriptions verbs: - get @@ -154,10 +161,14 @@ rules: resources: - backups - clusters + - clusters/status - databases + - failoverquorums - poolers - publications - scheduledbackups + - imagecatalogs + - clusterimagecatalogs - subscriptions verbs: - create diff --git a/packages/system/postgres-operator/charts/cloudnative-pg/templates/service.yaml b/packages/system/postgres-operator/charts/cloudnative-pg/templates/service.yaml index 13be46ae..8afa02fc 100644 --- a/packages/system/postgres-operator/charts/cloudnative-pg/templates/service.yaml +++ b/packages/system/postgres-operator/charts/cloudnative-pg/templates/service.yaml @@ -1,5 +1,6 @@ # -# Copyright The CloudNativePG Contributors +# Copyright © contributors to CloudNativePG, established as +# CloudNativePG a Series of LF Projects, LLC. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# --- apiVersion: v1 kind: Service diff --git a/packages/system/postgres-operator/charts/cloudnative-pg/templates/validatingwebhookconfiguration.yaml b/packages/system/postgres-operator/charts/cloudnative-pg/templates/validatingwebhookconfiguration.yaml index be9fff18..c171c911 100644 --- a/packages/system/postgres-operator/charts/cloudnative-pg/templates/validatingwebhookconfiguration.yaml +++ b/packages/system/postgres-operator/charts/cloudnative-pg/templates/validatingwebhookconfiguration.yaml @@ -1,5 +1,6 @@ # -# Copyright The CloudNativePG Contributors +# Copyright © contributors to CloudNativePG, established as +# CloudNativePG a Series of LF Projects, LLC. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# {{- if .Values.webhook.validating.create }} --- apiVersion: admissionregistration.k8s.io/v1 @@ -31,7 +34,7 @@ webhooks: clientConfig: service: name: {{ .Values.service.name }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudnative-pg.namespace" . }} path: /validate-postgresql-cnpg-io-v1-backup port: {{ .Values.service.port }} failurePolicy: {{ .Values.webhook.validating.failurePolicy }} @@ -52,7 +55,7 @@ webhooks: clientConfig: service: name: {{ .Values.service.name }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudnative-pg.namespace" . }} path: /validate-postgresql-cnpg-io-v1-cluster port: {{ .Values.service.port }} failurePolicy: {{ .Values.webhook.validating.failurePolicy }} @@ -73,7 +76,7 @@ webhooks: clientConfig: service: name: {{ .Values.service.name }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudnative-pg.namespace" . }} path: /validate-postgresql-cnpg-io-v1-scheduledbackup port: {{ .Values.service.port }} failurePolicy: {{ .Values.webhook.validating.failurePolicy }} @@ -89,12 +92,33 @@ webhooks: resources: - scheduledbackups sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ .Values.service.name }} + namespace: {{ include "cloudnative-pg.namespace" . }} + path: /validate-postgresql-cnpg-io-v1-database + port: {{ .Values.service.port }} + failurePolicy: {{ .Values.webhook.validating.failurePolicy }} + name: vdatabase.cnpg.io + rules: + - apiGroups: + - postgresql.cnpg.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - databases + sideEffects: None - admissionReviewVersions: - v1 clientConfig: service: name: {{ .Values.service.name }} - namespace: {{ .Release.Namespace }} + namespace: {{ include "cloudnative-pg.namespace" . }} path: /validate-postgresql-cnpg-io-v1-pooler port: {{ .Values.service.port }} failurePolicy: {{ .Values.webhook.validating.failurePolicy }} diff --git a/packages/system/postgres-operator/charts/cloudnative-pg/values.schema.json b/packages/system/postgres-operator/charts/cloudnative-pg/values.schema.json index 4ba70818..4c69aae6 100644 --- a/packages/system/postgres-operator/charts/cloudnative-pg/values.schema.json +++ b/packages/system/postgres-operator/charts/cloudnative-pg/values.schema.json @@ -246,6 +246,12 @@ "tolerations": { "type": "array" }, + "topologySpreadConstraints": { + "type": "array" + }, + "updateStrategy": { + "type": "object" + }, "webhook": { "type": "object", "properties": { @@ -279,6 +285,17 @@ } } }, + "startupProbe": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + } + } + }, "validating": { "type": "object", "properties": { diff --git a/packages/system/postgres-operator/charts/cloudnative-pg/values.yaml b/packages/system/postgres-operator/charts/cloudnative-pg/values.yaml index cdfb4cf8..cbba7505 100644 --- a/packages/system/postgres-operator/charts/cloudnative-pg/values.yaml +++ b/packages/system/postgres-operator/charts/cloudnative-pg/values.yaml @@ -1,5 +1,6 @@ # -# Copyright The CloudNativePG Contributors +# Copyright © contributors to CloudNativePG, established as +# CloudNativePG a Series of LF Projects, LLC. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# # Default values for CloudNativePG. # This is a YAML-formatted file. # Please declare variables to be passed to your templates. @@ -33,6 +36,15 @@ namespaceOverride: "" hostNetwork: false dnsPolicy: "" +# -- Update strategy for the operator. +# ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy +# For example: +# type: RollingUpdate +# rollingUpdate: +# maxSurge: 25% +# maxUnavailable: 25% +updateStrategy: {} + crds: # -- Specifies whether the CRDs should be created when installing the chart. create: true @@ -50,6 +62,9 @@ webhook: initialDelaySeconds: 3 readinessProbe: initialDelaySeconds: 3 + startupProbe: + failureThreshold: 6 + periodSeconds: 5 # Operator configuration. config: @@ -73,7 +88,7 @@ config: # -- The maximum number of concurrent reconciles. Defaults to 10. maxConcurrentReconciles: 10 -# -- Additinal arguments to be added to the operator's args list. +# -- Additional arguments to be added to the operator's args list. additionalArgs: [] # -- Array containing extra environment variables which can be templated. @@ -152,6 +167,9 @@ resources: {} # -- Nodeselector for the operator to be installed. nodeSelector: {} +# -- Topology Spread Constraints for the operator to be installed. +topologySpreadConstraints: [] + # -- Tolerations for the operator to be installed. tolerations: [] @@ -637,3 +655,35 @@ monitoringQueriesConfigMap: - setting: usage: "GAUGE" description: "Setting value" + + pg_extensions: + query: | + SELECT + current_database() as datname, + name as extname, + default_version, + installed_version, + CASE + WHEN default_version = installed_version THEN 0 + ELSE 1 + END AS update_available + FROM pg_catalog.pg_available_extensions + WHERE installed_version IS NOT NULL + metrics: + - datname: + usage: "LABEL" + description: "Name of the database" + - extname: + usage: "LABEL" + description: "Extension name" + - default_version: + usage: "LABEL" + description: "Default version" + - installed_version: + usage: "LABEL" + description: "Installed version" + - update_available: + usage: "GAUGE" + description: "An update is available" + target_databases: + - '*' diff --git a/packages/system/postgres-operator/templates/webhook-ready-hook.yaml b/packages/system/postgres-operator/templates/webhook-ready-hook.yaml new file mode 100644 index 00000000..51a8ba81 --- /dev/null +++ b/packages/system/postgres-operator/templates/webhook-ready-hook.yaml @@ -0,0 +1,148 @@ +{{- /* + Post-install gate: block the HelmRelease from reporting Ready until the + cnpg admission webhook actually serves through the cluster Service. Helm + --wait on the controller pod passes once its readinessProbe passes, but + EndpointSlice propagation and kube-proxy/cilium data-plane programming + can lag by a second or two — long enough for any HelmRelease that + depends on postgres-operator (e.g. cozy-keycloak, tenant Postgres apps) + to fire its own install and have kube-apiserver hit the mcluster.cnpg.io + mutating webhook with "dial tcp :443: connect: connection refused". + + The Job uses the apiserver service proxy, which exercises the same + endpoint-resolution and apiserver-initiated pod dial that the admission + webhook path uses. Once /readyz answers through the proxy the data-plane + race is resolved. It does not verify the webhook's TLS CA bundle, so + this gate is scoped to reachability regressions, not cert rotation. + + The service name and port name are hardcoded literals. Upstream cnpg + pins the service name in charts/cloudnative-pg/values.yaml with a + comment "DO NOT CHANGE THE SERVICE NAME as it is currently used to + generate the certificate and can not be configured". The port name is + fixed in charts/cloudnative-pg/templates/service.yaml (ports[0].name: + webhook-server). If a future `make update` ever changes either literal + upstream, the sync-check helm-unittest test + (tests/webhook-ready-hook_test.yaml) renders the subchart Service and + fails if the literal drifts — forcing this template to be updated in + the same change. +*/}} +{{- $_ := required "webhookReady.image.repository must be set to the container image providing kubectl for the post-install readiness Job" .Values.webhookReady.image.repository -}} +{{- $_ := required "webhookReady.image.tag must be set for the post-install readiness Job" .Values.webhookReady.image.tag -}} +{{- /* $svcName and $portName are hardcoded literals; see header comment. */ -}} +{{- $svcName := "cnpg-webhook-service" -}} +{{- /* $portName is the service port NAME, not number — matches ports[0].name in the vendored subchart's Service. */ -}} +{{- $portName := "webhook-server" -}} +{{- $resourceName := printf "https:%s:%s" $svcName $portName -}} +{{- $maxAttempts := .Values.webhookReady.maxAttempts | default 60 -}} +{{- $sleepSeconds := .Values.webhookReady.sleepSeconds | default 2 -}} +{{- /* Derive activeDeadlineSeconds from retries + 60s slack so a values override that raises maxAttempts doesn't get silently cut. */ -}} +{{- $deadline := add (mul (int $maxAttempts) (int $sleepSeconds)) 60 -}} +{{- $image := printf "%s:%s" .Values.webhookReady.image.repository .Values.webhookReady.image.tag -}} +{{- if .Values.webhookReady.image.digest }} +{{- $image = printf "%s@%s" $image .Values.webhookReady.image.digest -}} +{{- end }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Release.Name }}-webhook-ready + namespace: {{ .Release.Namespace }} + annotations: + helm.sh/hook: post-install,post-upgrade + helm.sh/hook-weight: "0" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ .Release.Name }}-webhook-ready + namespace: {{ .Release.Namespace }} + annotations: + helm.sh/hook: post-install,post-upgrade + helm.sh/hook-weight: "0" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded +rules: + - apiGroups: [""] + resources: ["services/proxy"] + resourceNames: [{{ $resourceName | quote }}] + verbs: ["get"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ .Release.Name }}-webhook-ready + namespace: {{ .Release.Namespace }} + annotations: + helm.sh/hook: post-install,post-upgrade + helm.sh/hook-weight: "0" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ .Release.Name }}-webhook-ready +subjects: + - kind: ServiceAccount + name: {{ .Release.Name }}-webhook-ready + namespace: {{ .Release.Namespace }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ .Release.Name }}-webhook-ready + namespace: {{ .Release.Namespace }} + annotations: + helm.sh/hook: post-install,post-upgrade + helm.sh/hook-weight: "10" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded +spec: + backoffLimit: {{ .Values.webhookReady.backoffLimit | default 2 }} + activeDeadlineSeconds: {{ $deadline }} + template: + spec: + restartPolicy: Never + serviceAccountName: {{ .Release.Name }}-webhook-ready + securityContext: + runAsNonRoot: true + runAsUser: 65532 + runAsGroup: 65532 + seccompProfile: + type: RuntimeDefault + containers: + - name: wait + image: {{ $image }} + imagePullPolicy: {{ if .Values.webhookReady.image.digest }}IfNotPresent{{ else }}Always{{ end }} + resources: + requests: + cpu: 10m + memory: 32Mi + limits: + cpu: 100m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: ["ALL"] + command: + - sh + - -c + - | + set -e + ns={{ .Release.Namespace }} + proxy="/api/v1/namespaces/${ns}/services/{{ $resourceName }}/proxy/readyz" + max_attempts={{ $maxAttempts }} + sleep_seconds={{ $sleepSeconds }} + i=0 + last_err="" + until last_err=$(kubectl get --raw "$proxy" 2>&1 >/dev/null); do + i=$((i + 1)) + if [ $i -gt $max_attempts ]; then + echo "timeout: cnpg webhook did not respond through the apiserver proxy after ${max_attempts} attempts (${sleep_seconds}s each)" + echo "last error: ${last_err}" + exit 1 + fi + if [ $((i % 10)) -eq 1 ]; then + echo "attempt $i/${max_attempts}: ${last_err}" + fi + sleep "$sleep_seconds" + done + echo "cnpg webhook is ready" diff --git a/packages/system/postgres-operator/tests/webhook-ready-hook_test.yaml b/packages/system/postgres-operator/tests/webhook-ready-hook_test.yaml new file mode 100644 index 00000000..3253c663 --- /dev/null +++ b/packages/system/postgres-operator/tests/webhook-ready-hook_test.yaml @@ -0,0 +1,328 @@ +suite: cnpg webhook post-install readiness gate + +templates: + - templates/webhook-ready-hook.yaml + - charts/cloudnative-pg/templates/service.yaml + +release: + name: postgres-operator + namespace: cozy-postgres-operator + +tests: + - it: renders four hook objects (SA + Role + RoleBinding + Job) + template: templates/webhook-ready-hook.yaml + asserts: + - hasDocuments: + count: 4 + + - it: every rendered object carries post-install and post-upgrade hook annotations + template: templates/webhook-ready-hook.yaml + asserts: + - documentIndex: 0 + equal: + path: metadata.annotations["helm.sh/hook"] + value: post-install,post-upgrade + - documentIndex: 1 + equal: + path: metadata.annotations["helm.sh/hook"] + value: post-install,post-upgrade + - documentIndex: 2 + equal: + path: metadata.annotations["helm.sh/hook"] + value: post-install,post-upgrade + - documentIndex: 3 + equal: + path: metadata.annotations["helm.sh/hook"] + value: post-install,post-upgrade + + - it: RBAC is created before the Job (hook-weight ordering) + template: templates/webhook-ready-hook.yaml + asserts: + - documentIndex: 0 + equal: + path: kind + value: ServiceAccount + - documentIndex: 0 + equal: + path: metadata.annotations["helm.sh/hook-weight"] + value: "0" + - documentIndex: 1 + equal: + path: kind + value: Role + - documentIndex: 1 + equal: + path: metadata.annotations["helm.sh/hook-weight"] + value: "0" + - documentIndex: 2 + equal: + path: kind + value: RoleBinding + - documentIndex: 2 + equal: + path: metadata.annotations["helm.sh/hook-weight"] + value: "0" + - documentIndex: 3 + equal: + path: kind + value: Job + - documentIndex: 3 + equal: + path: metadata.annotations["helm.sh/hook-weight"] + value: "10" + + - it: RBAC resourceName matches the exact proxy URL segment the Job probes + template: templates/webhook-ready-hook.yaml + asserts: + - documentIndex: 1 + equal: + path: rules[0].resources[0] + value: services/proxy + - documentIndex: 1 + equal: + path: rules[0].resourceNames[0] + value: https:cnpg-webhook-service:webhook-server + - documentIndex: 3 + matchRegex: + path: spec.template.spec.containers[0].command[2] + pattern: "/api/v1/namespaces/\\$\\{ns\\}/services/https:cnpg-webhook-service:webhook-server/proxy/readyz" + + - it: hardcoded service name in the hook matches the vendored cnpg subchart Service (drift guard for make update) + template: charts/cloudnative-pg/templates/service.yaml + asserts: + - equal: + path: metadata.name + value: cnpg-webhook-service + - equal: + path: spec.ports[0].name + value: webhook-server + + - it: Job calls kubectl get --raw on the proxy path + template: templates/webhook-ready-hook.yaml + asserts: + - documentIndex: 3 + matchRegex: + path: spec.template.spec.containers[0].command[2] + pattern: "kubectl get --raw" + + - it: Job image is digest-pinned when webhookReady.image.digest is set + template: templates/webhook-ready-hook.yaml + set: + webhookReady: + image: + repository: docker.io/clastix/kubectl + tag: v1.32 + digest: sha256:b9ef7d8dbe65bcc81a46c09b8dc7543103055021c4f43287bf59e92a8f4fe05c + asserts: + - documentIndex: 3 + equal: + path: spec.template.spec.containers[0].image + value: docker.io/clastix/kubectl:v1.32@sha256:b9ef7d8dbe65bcc81a46c09b8dc7543103055021c4f43287bf59e92a8f4fe05c + + - it: Job image falls back to tag-only when digest is not configured + template: templates/webhook-ready-hook.yaml + set: + webhookReady: + image: + repository: docker.io/clastix/kubectl + tag: v1.32 + digest: "" + asserts: + - documentIndex: 3 + equal: + path: spec.template.spec.containers[0].image + value: docker.io/clastix/kubectl:v1.32 + + - it: backoffLimit defaults to 2 so transient pod-level failures retry instead of killing the HelmRelease + template: templates/webhook-ready-hook.yaml + asserts: + - documentIndex: 3 + equal: + path: spec.backoffLimit + value: 2 + + - it: backoffLimit is overridable + template: templates/webhook-ready-hook.yaml + set: + webhookReady: + backoffLimit: 5 + asserts: + - documentIndex: 3 + equal: + path: spec.backoffLimit + value: 5 + + - it: chart render fails when webhookReady.image.repository is empty + template: templates/webhook-ready-hook.yaml + set: + webhookReady: + image: + repository: "" + tag: v1.32 + asserts: + - failedTemplate: + errorMessage: "webhookReady.image.repository must be set to the container image providing kubectl for the post-install readiness Job" + + - it: chart render fails when webhookReady.image.tag is empty + template: templates/webhook-ready-hook.yaml + set: + webhookReady: + image: + repository: docker.io/clastix/kubectl + tag: "" + asserts: + - failedTemplate: + errorMessage: "webhookReady.image.tag must be set for the post-install readiness Job" + + - it: retry loop bounds default when blanked so a wiped override still produces a working Job + template: templates/webhook-ready-hook.yaml + set: + webhookReady: + image: + repository: docker.io/clastix/kubectl + tag: v1.32 + maxAttempts: null + sleepSeconds: null + asserts: + - documentIndex: 3 + matchRegex: + path: spec.template.spec.containers[0].command[2] + pattern: "max_attempts=60" + - documentIndex: 3 + matchRegex: + path: spec.template.spec.containers[0].command[2] + pattern: "sleep_seconds=2" + + - it: Job pod runs non-root with seccomp RuntimeDefault for restricted-PSA clusters + template: templates/webhook-ready-hook.yaml + asserts: + - documentIndex: 3 + equal: + path: spec.template.spec.securityContext.runAsNonRoot + value: true + - documentIndex: 3 + equal: + path: spec.template.spec.securityContext.seccompProfile.type + value: RuntimeDefault + + - it: wait container declares resource requests and limits for predictable scheduling + template: templates/webhook-ready-hook.yaml + asserts: + - documentIndex: 3 + equal: + path: spec.template.spec.containers[0].resources.requests.cpu + value: 10m + - documentIndex: 3 + equal: + path: spec.template.spec.containers[0].resources.requests.memory + value: 32Mi + - documentIndex: 3 + equal: + path: spec.template.spec.containers[0].resources.limits.cpu + value: 100m + - documentIndex: 3 + equal: + path: spec.template.spec.containers[0].resources.limits.memory + value: 64Mi + + - it: Job container drops all capabilities and runs read-only rootfs + template: templates/webhook-ready-hook.yaml + asserts: + - documentIndex: 3 + equal: + path: spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation + value: false + - documentIndex: 3 + equal: + path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem + value: true + - documentIndex: 3 + equal: + path: spec.template.spec.containers[0].securityContext.capabilities.drop[0] + value: ALL + + - it: imagePullPolicy is IfNotPresent when digest-pinned, Always when tag-only + template: templates/webhook-ready-hook.yaml + set: + webhookReady: + image: + repository: docker.io/clastix/kubectl + tag: v1.32 + digest: sha256:b9ef7d8dbe65bcc81a46c09b8dc7543103055021c4f43287bf59e92a8f4fe05c + asserts: + - documentIndex: 3 + equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: IfNotPresent + + - it: imagePullPolicy is Always when no digest is configured + template: templates/webhook-ready-hook.yaml + set: + webhookReady: + image: + repository: docker.io/clastix/kubectl + tag: v1.32 + digest: "" + asserts: + - documentIndex: 3 + equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: Always + + - it: retry loop captures and surfaces the last kubectl error message on timeout + template: templates/webhook-ready-hook.yaml + asserts: + - documentIndex: 3 + matchRegex: + path: spec.template.spec.containers[0].command[2] + pattern: 'last_err=\$\(kubectl get --raw' + - documentIndex: 3 + matchRegex: + path: spec.template.spec.containers[0].command[2] + pattern: 'last error: \$\{last_err\}' + + - it: retry loop error message stays in sync when maxAttempts is bumped + template: templates/webhook-ready-hook.yaml + set: + webhookReady: + image: + repository: docker.io/clastix/kubectl + tag: v1.32 + maxAttempts: 90 + sleepSeconds: 3 + asserts: + - documentIndex: 3 + matchRegex: + path: spec.template.spec.containers[0].command[2] + pattern: "max_attempts=90" + - documentIndex: 3 + matchRegex: + path: spec.template.spec.containers[0].command[2] + pattern: "sleep_seconds=3" + - documentIndex: 3 + matchRegex: + path: spec.template.spec.containers[0].command[2] + pattern: 'after \$\{max_attempts\} attempts' + + - it: activeDeadlineSeconds scales with retry bounds so an override raise does not silently cut + template: templates/webhook-ready-hook.yaml + set: + webhookReady: + image: + repository: docker.io/clastix/kubectl + tag: v1.32 + maxAttempts: 180 + sleepSeconds: 3 + asserts: + - documentIndex: 3 + equal: + path: spec.activeDeadlineSeconds + value: 600 + + - it: activeDeadlineSeconds defaults include 60s slack over the default retry window + template: templates/webhook-ready-hook.yaml + asserts: + - documentIndex: 3 + equal: + path: spec.activeDeadlineSeconds + value: 180 diff --git a/packages/system/postgres-operator/values.yaml b/packages/system/postgres-operator/values.yaml index 6bc9595b..c408220e 100644 --- a/packages/system/postgres-operator/values.yaml +++ b/packages/system/postgres-operator/values.yaml @@ -1,3 +1,32 @@ cloudnative-pg: crds: create: true + image: + tag: "1.27.3" +# Image used by the post-install webhook-readiness Job (see templates/webhook-ready-hook.yaml). +# Any image with kubectl on PATH works; the Job calls the apiserver service proxy with the +# hook ServiceAccount's token to confirm the mcluster.cnpg.io webhook is reachable end-to-end +# before the HelmRelease reports Ready, closing the "connection refused" bootstrap race. +# +# The tag is digest-pinned so an upstream retag does not change what runs on every install +# and upgrade across the fleet. Refresh by resolving the current manifest-list digest +# (`docker manifest inspect docker.io/clastix/kubectl:v1.32`) and updating `digest` below. +# renovate: datasource=docker depName=docker.io/clastix/kubectl +webhookReady: + image: + repository: docker.io/clastix/kubectl + tag: v1.32 + digest: sha256:b9ef7d8dbe65bcc81a46c09b8dc7543103055021c4f43287bf59e92a8f4fe05c + # Retry loop bounds for the readiness probe. Defaults total ~120s wall clock. + # Both are `default`-coerced in the template so an override that blanks them still + # produces a working Job. + maxAttempts: 60 + sleepSeconds: 2 + # Pod-level retry budget for transient node/registry failures (image pull rate limit, + # OOM, CNI hiccup). The shell loop inside the container only covers reachability retries. + # Pod retries and activeDeadlineSeconds (wall-clock bound on the whole Job across all + # pod retries) are ANDed, so activeDeadlineSeconds is the shorter of the two gates with + # the defaults above: the 60*2+60 = 180s deadline cuts the Job before backoffLimit=2 + # ever matters if pod-level failures eat more than ~60s of the budget. Raise + # maxAttempts/sleepSeconds alongside backoffLimit when tuning for slow image pulls. + backoffLimit: 2 diff --git a/packages/system/postgres-rd/Chart.yaml b/packages/system/postgres-rd/Chart.yaml new file mode 100644 index 00000000..ca2e2d2a --- /dev/null +++ b/packages/system/postgres-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: postgres-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/postgres-rd/Makefile b/packages/system/postgres-rd/Makefile new file mode 100644 index 00000000..7da8103a --- /dev/null +++ b/packages/system/postgres-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=postgres-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/postgres-rd/cozyrds/postgres.yaml b/packages/system/postgres-rd/cozyrds/postgres.yaml new file mode 100644 index 00000000..72d013f1 --- /dev/null +++ b/packages/system/postgres-rd/cozyrds/postgres.yaml @@ -0,0 +1,49 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: postgres +spec: + application: + kind: Postgres + singular: postgres + plural: postgreses + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of Postgres replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each PostgreSQL replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"micro","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"version":{"description":"PostgreSQL major version to deploy","type":"string","default":"v18","enum":["v18","v17","v16","v15","v14","v13"]},"postgresql":{"description":"PostgreSQL server configuration.","type":"object","default":{},"properties":{"parameters":{"description":"PostgreSQL server parameters.","type":"object","default":{},"properties":{"max_connections":{"description":"Maximum number of concurrent connections to the database server.","type":"integer","default":100}}}}},"quorum":{"description":"Quorum configuration for synchronous replication.","type":"object","default":{},"required":["maxSyncReplicas","minSyncReplicas"],"properties":{"maxSyncReplicas":{"description":"Maximum number of synchronous replicas allowed (must be less than total replicas).","type":"integer","default":0},"minSyncReplicas":{"description":"Minimum number of synchronous replicas required for commit.","type":"integer","default":0}}},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user.","type":"string"},"replication":{"description":"Whether the user has replication privileges.","type":"boolean"}}}},"databases":{"description":"Databases configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"extensions":{"description":"List of enabled PostgreSQL extensions.","type":"array","items":{"type":"string"}},"roles":{"description":"Roles assigned to users.","type":"object","properties":{"admin":{"description":"List of users with admin privileges.","type":"array","items":{"type":"string"}},"readonly":{"description":"List of users with read-only privileges.","type":"array","items":{"type":"string"}}}}}}},"backup":{"description":"Backup configuration.","type":"object","default":{},"required":["enabled"],"properties":{"destinationPath":{"description":"Destination path for backups (e.g. s3://bucket/path/).","type":"string","default":"s3://bucket/path/to/folder/"},"enabled":{"description":"Enable regular backups.","type":"boolean","default":false},"endpointURL":{"description":"S3 endpoint URL for uploads.","type":"string","default":"http://minio-gateway-service:9000"},"retentionPolicy":{"description":"Retention policy (e.g. \"30d\").","type":"string","default":"30d"},"s3AccessKey":{"description":"Access key for S3 authentication.","type":"string","default":""},"s3SecretKey":{"description":"Secret key for S3 authentication.","type":"string","default":""},"schedule":{"description":"Cron schedule for automated backups.","type":"string","default":"0 2 * * * *"}}},"bootstrap":{"description":"Bootstrap configuration.","type":"object","default":{},"required":["enabled","oldName"],"properties":{"enabled":{"description":"Whether to restore from a backup.","type":"boolean","default":false},"oldName":{"description":"Previous cluster name before deletion.","type":"string","default":""},"recoveryTime":{"description":"Timestamp (RFC3339) for point-in-time recovery; empty means latest.","type":"string","default":""},"serverName":{"description":"Barman server name (S3 path prefix) used by the original cluster when writing backups. Set this only when the original cluster had an explicit barmanObjectStore.serverName that differed from its Kubernetes resource name.","type":"string","default":""}}}}} + release: + prefix: postgres- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-postgres-application-default-postgres + namespace: cozy-system + dashboard: + category: PaaS + singular: PostgreSQL + plural: PostgreSQL + description: Managed PostgreSQL service + tags: + - database + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODNfMjg0OSkiLz4KPHBhdGggZD0iTTk0LjQ4MSA5My4zMDQ5Qzk1LjA3MTggODguMzQ3NyA5NC44OTQ4IDg3LjYyMDggOTguNTYxMiA4OC40MjM4TDk5LjQ5MiA4OC41MDYxQzEwMi4zMTEgODguNjM1MyAxMDUuOTk5IDg4LjA0OTUgMTA4LjE2NiA4Ny4wMzU4QzExMi44MyA4NC44NTY0IDExNS41OTUgODEuMjE3NiAxMTAuOTk2IDgyLjE3MzhDMTAwLjUwNiA4NC4zNTMyIDk5Ljc4NDkgODAuNzc1OSA5OS43ODQ5IDgwLjc3NTlDMTEwLjg2MiA2NC4yMjQgMTE1LjQ5MyA0My4yMTI4IDExMS40OTYgMzguMDY5N0MxMDAuNTk0IDI0LjA0MTIgODEuNzIzMSAzMC42NzUgODEuNDA3MyAzMC44NDcyTDgxLjMwNjggMzAuODY1OUM3OS4yMzQgMzAuNDMyOCA3Ni45MTQzIDMwLjE3NCA3NC4zMDg1IDMwLjEzMTZDNjkuNTYxMyAzMC4wNTMgNjUuOTU5MSAzMS4zODQ5IDYzLjIyNjYgMzMuNDcyMUM2My4yMjY2IDMzLjQ3MjEgMjkuNTYyMSAxOS41MDQ3IDMxLjEyODIgNTEuMDM3NUMzMS40NjEzIDU3Ljc0NTQgNDAuNjc1OCAxMDEuNzk1IDUxLjY2NTkgODguNDkwMUM1NS42ODI3IDgzLjYyNDkgNTkuNTY0NiA3OS41MTEzIDU5LjU2NDYgNzkuNTExM0M2MS40OTIyIDgwLjgwMDkgNjMuOCA4MS40NTg4IDY2LjIyMDQgODEuMjIyNUw2Ni40MDc1IDgxLjA2MThDNjYuMzQ4OSA4MS42NjU5IDY2LjM3NDcgODIuMjU2NyA2Ni40ODI0IDgyLjk1NjJDNjMuNjUxNyA4Ni4xNDE5IDY0LjQ4MzUgODYuNzAxMiA1OC44MjMxIDg3Ljg3NDVDNTMuMDk2NSA4OS4wNjMxIDU2LjQ2MDkgOTEuMTc5MyA1OC42NTY5IDkxLjczMjRDNjEuMzE5OSA5Mi40MDMgNjcuNDgwNCA5My4zNTMgNzEuNjQ0IDg3LjQ4NDVMNzEuNDc4MiA4OC4xNTQxQzcyLjU4ODggODkuMDQ4OSA3Mi41MTM3IDk0LjU4NTQgNzIuNjcxMiA5OC41NDExQzcyLjgyODkgMTAyLjQ5NyA3My4wOTE5IDEwNi4xODkgNzMuODkyNiAxMDguMzY1Qzc0LjY5MzMgMTEwLjU0MSA3NS42MzgxIDExNi4xNDcgODMuMDc3MSAxMTQuNTQxQzg5LjI5NDMgMTEzLjIgOTQuMDQ3OCAxMTEuMjY5IDk0LjQ4MSA5My4zMDQ5WiIgZmlsbD0iYmxhY2siIHN0cm9rZT0iYmxhY2siIHN0cm9rZS13aWR0aD0iNiIvPgo8cGF0aCBkPSJNMTEwLjk5OCA4Mi4xNzI3QzEwMC41MDYgODQuMzUyMSA5OS43ODQ5IDgwLjc3NDggOTkuNzg0OSA4MC43NzQ4QzExMC44NjIgNjQuMjIxOCAxMTUuNDkzIDQzLjIxMDIgMTExLjQ5NyAzOC4wNjc4QzEwMC41OTUgMjQuMDQwMSA4MS43MjMxIDMwLjY3NDMgODEuNDA4MiAzMC44NDY1TDgxLjMwNjggMzAuODY0OEM3OS4yMzQxIDMwLjQzMTUgNzYuOTE0NCAzMC4xNzMzIDc0LjMwNzMgMzAuMTMwNUM2OS41NiAzMC4wNTIxIDY1Ljk1OTEgMzEuMzgzOCA2My4yMjY3IDMzLjQ3MDZDNjMuMjI2NyAzMy40NzA2IDI5LjU2MTUgMTkuNTAzOCAzMS4xMjcyIDUxLjAzNjRDMzEuNDYwMyA1Ny43NDQ3IDQwLjY3NDYgMTAxLjc5NSA1MS42NjUxIDg4LjQ4OTVDNTUuNjgyMSA4My42MjQzIDU5LjU2MzQgNzkuNTEwNiA1OS41NjM0IDc5LjUxMDZDNjEuNDkxMiA4MC44MDAyIDYzLjc5OSA4MS40NTgxIDY2LjIxODQgODEuMjIxOEw2Ni40MDYzIDgxLjA2MTFDNjYuMzQ3OSA4MS42NjUyIDY2LjM3NDYgODIuMjU2IDY2LjQ4MTYgODIuOTU1NUM2My42NTAzIDg2LjE0MTIgNjQuNDgyMiA4Ni43MDA1IDU4LjgyMjMgODcuODczOEM1My4wOTUzIDg5LjA2MjUgNTYuNDU5NyA5MS4xNzg2IDU4LjY1NjMgOTEuNzMxN0M2MS4zMTkzIDkyLjQwMjMgNjcuNDgwMiA5My4zNTI0IDcxLjY0MyA4Ny40ODM4TDcxLjQ3NyA4OC4xNTM0QzcyLjU4NjQgODkuMDQ4MiA3My4zNjU0IDkzLjk3MzkgNzMuMjM0OCA5OC40MzlDNzMuMTA0MiAxMDIuOTA0IDczLjAxNzEgMTA1Ljk3IDczLjg5MTIgMTA4LjM2NEM3NC43NjUzIDExMC43NTkgNzUuNjM2NSAxMTYuMTQ2IDgzLjA3NjkgMTE0LjU0MUM4OS4yOTQxIDExMy4xOTkgOTIuNTE1OSAxMDkuNzIyIDkyLjk2NDEgMTAzLjkyMkM5My4yODIyIDk5Ljc5ODggOTQuMDAxOSAxMDAuNDA4IDk0LjA0NzQgOTYuNzIxOUw5NC42MjQ3IDk0Ljk3NjZDOTUuMjkwNSA4OS4zODcyIDk0LjczMDUgODcuNTg0IDk4LjU2MDggODguNDIyN0w5OS40OTE3IDg4LjUwNUMxMDIuMzExIDg4LjYzNDIgMTA2LjAwMSA4OC4wNDg0IDEwOC4xNjYgODcuMDM0N0MxMTIuODI5IDg0Ljg1NTMgMTE1LjU5NSA4MS4yMTY2IDExMC45OTcgODIuMTcyN0gxMTAuOTk4WiIgZmlsbD0iIzMzNjc5MSIvPgo8cGF0aCBkPSJNNzIuMDkzMyA4NS4zNzdDNzEuODA0NSA5NS43Nzc0IDcyLjE2NTkgMTA2LjI1IDczLjE3NjQgMTA4Ljc5NkM3NC4xODc2IDExMS4zNDEgNzYuMzUxNCAxMTYuMjkyIDgzLjc5MjUgMTE0LjY4NkM5MC4wMDkxIDExMy4zNDQgOTIuMjcxIDExMC43NDcgOTMuMjUyNiAxMDUuMDE0QzkzLjk3NTUgMTAwLjc5NiA5NS4zNjkxIDg5LjA4MSA5NS41NDc5IDg2LjY4MDkiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+CjxwYXRoIGQ9Ik02My4xNzUgMzMuMjM5M0M2My4xNzUgMzMuMjM5MyAyOS40ODY4IDE5LjM3MzIgMzEuMDUzIDUwLjkwNThDMzEuMzg2IDU3LjYxNDEgNDAuNjAxIDEwMS42NjUgNTEuNTkxMyA4OC4zNTk3QzU1LjYwNzUgODMuNDkzOCA1OS4yMzk3IDc5LjY3NzYgNTkuMjM5NyA3OS42Nzc2IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPgo8cGF0aCBkPSJNODEuMzcxMyAzMC43MDc4QzgwLjIwNTIgMzEuMDc2IDEwMC4xMTEgMjMuMzc5NiAxMTEuNDIzIDM3LjkzNjhDMTE1LjQxOSA0My4wNzk1IDExMC43ODkgNjQuMDkxMSA5OS43MTE1IDgwLjY0NDUiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+CjxwYXRoIGQ9Ik05OS43MTEgODAuNjQ0OEM5OS43MTEgODAuNjQ0OCAxMDAuNDMzIDg0LjIyMyAxMTAuOTI0IDgyLjA0MjJDMTE1LjUyMSA4MS4wODYxIDExMi43NTUgODQuNzI1MiAxMDguMDkzIDg2LjkwNTdDMTA0LjI2NyA4OC42OTQgOTUuNjg4MyA4OS4xNTIzIDk1LjU0ODIgODYuNjgxMkM5NS4xODc2IDgwLjMwNTMgMTAwLjA2MyA4Mi4yNDIzIDk5LjcxMSA4MC42NDQ4Wk05OS43MTEgODAuNjQ0OEM5OS4zOTI5IDc5LjIwNiA5Ny4yMTI4IDc3Ljc5MzkgOTUuNzcwNSA3NC4yNzI1Qzk0LjUxMTQgNzEuMTk5IDc4LjUwMTkgNDcuNjI4OSAxMDAuMjEgNTEuMTI5NEMxMDEuMDA2IDUwLjk2MzcgOTQuNTQ4NSAzMC4zMzQ4IDc0LjIzMjUgMjkuOTk5NEM1My45MjExIDI5LjY2MzkgNTQuNTg3NSA1NS4xNTQ1IDU0LjU4NzUgNTUuMTU0NSIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0iYmV2ZWwiLz4KPHBhdGggZD0iTTY2LjQwNzcgODIuODI1M0M2My41NzYgODYuMDEwOCA2NC40MDg4IDg2LjU3MDIgNTguNzQ4NSA4Ny43NDM5QzUzLjAyMTQgODguOTMyNyA1Ni4zODYyIDkxLjA0ODUgNTguNTgyMiA5MS42MDEzQzYxLjI0NTIgOTIuMjcyNCA2Ny40MDYxIDkzLjIyMjQgNzEuNTY4OSA4Ny4zNTI0QzcyLjgzNjYgODUuNTY1MSA3MS41NjE0IDgyLjcxMzQgNjkuODIwMSA4MS45ODY0QzY4Ljk3ODcgODEuNjM1NCA2Ny44NTM3IDgxLjE5NTYgNjYuNDA3NyA4Mi44MjUzWiIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPHBhdGggZD0iTTY2LjIyMjUgODIuNzY5MUM2NS45MzcyIDgwLjg5NjEgNjYuODMzNiA3OC42Njc0IDY3Ljc5NDMgNzYuMDU5OUM2OS4yMzggNzIuMTQ3NyA3Mi41NjkgNjguMjM0OCA2OS45MDQ0IDU1LjgyNDZDNjcuOTE4MiA0Ni41NzY3IDU0LjU5NjMgNTMuOSA1NC41ODggNTUuMTU0QzU0LjU3OTggNTYuNDA3NSA1NS4xOTA1IDYxLjUwOTkgNTQuMzY1NCA2Ny40NTE1QzUzLjI4ODggNzUuMjA0OCA1OS4yNjQzIDgxLjc2MjEgNjYuMTQ1MSA4MS4wOTEzIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPgo8cGF0aCBkPSJNNjMuMDUyOCA1NC45NjY1QzYyLjk5MjggNTUuMzk0OCA2My44MzE0IDU2LjUzNzcgNjQuOTI0OSA1Ni42OTA0QzY2LjAxNjYgNTYuODQzNyA2Ni45NTEgNTUuOTUwNiA2Ny4wMTAyIDU1LjUyMjdDNjcuMDY5NCA1NS4wOTQ1IDY2LjIzMTggNTQuNjIyNyA2NS4xMzc5IDU0LjQ2OTRDNjQuMDQ1NiA1NC4zMTU4IDYzLjExMDggNTQuNTM5MyA2My4wNTMxIDU0Ljk2NjVINjMuMDUyOFoiIGZpbGw9IndoaXRlIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiLz4KPHBhdGggZD0iTTk2LjMwMzQgNTQuMDkyNEM5Ni4zNjI3IDU0LjUyMDcgOTUuNTI1MSA1NS42NjM1IDk0LjQzMTMgNTUuODE2MkM5My4zMzg5IDU1Ljk2OTYgOTIuNDA0NSA1NS4wNzY1IDkyLjM0NDYgNTQuNjQ4NkM5Mi4yODY4IDU0LjIyMDMgOTMuMTI0NyA1My43NDg2IDk0LjIxNzMgNTMuNTk1M0M5NS4zMSA1My40NDE5IDk2LjI0NDIgNTMuNjY1MiA5Ni4zMDM0IDU0LjA5MjZWNTQuMDkyNFoiIGZpbGw9IndoaXRlIiBzdHJva2U9IndoaXRlIi8+CjxwYXRoIGQ9Ik0xMDAuMjEgNTEuMTI4OUMxMDAuMzkgNTQuNDg4MyA5OS40OTIgNTYuNzc2NSA5OS4zNzg3IDYwLjM1MjdDOTkuMjExIDY1LjU1MDggMTAxLjg0IDcxLjUwMDUgOTcuODc4OSA3Ny40NTc1IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4M18yODQ5IiB4MT0iMTQwIiB5MT0iMTMwLjUiIHgyPSI0IiB5Mj0iOS40OTk5OSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjMDAyQzRDIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzAwNDc3QiIvPgo8L2xpbmVhckdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPgo= + #tabs: + # services: + # labelSelector: + # cnpg.io/cluster: "{reqs[0]['metadata','name']}" + # workloadMonitors: + # labelSelector: + # helm.toolkit.fluxcd.io/name: "{reqs[0]['metadata','name']}" + + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "version"], ["spec", "postgresql"], ["spec", "postgresql", "parameters"], ["spec", "postgresql", "parameters", "max_connections"], ["spec", "quorum"], ["spec", "quorum", "minSyncReplicas"], ["spec", "quorum", "maxSyncReplicas"], ["spec", "users"], ["spec", "databases"], ["spec", "backup"], ["spec", "backup", "enabled"], ["spec", "backup", "retentionPolicy"], ["spec", "backup", "destinationPath"], ["spec", "backup", "endpointURL"], ["spec", "backup", "schedule"], ["spec", "backup", "s3AccessKey"], ["spec", "backup", "s3SecretKey"], ["spec", "bootstrap"], ["spec", "bootstrap", "enabled"], ["spec", "bootstrap", "recoveryTime"], ["spec", "bootstrap", "oldName"], ["spec", "bootstrap", "serverName"]] + secrets: + exclude: [] + include: + - resourceNames: + - postgres-{{ .name }}-credentials + services: + exclude: [] + include: + - resourceNames: + - postgres-{{ .name }}-r + - postgres-{{ .name }}-ro + - postgres-{{ .name }}-rw + - postgres-{{ .name }}-external-write diff --git a/packages/system/postgres-rd/templates/cozyrd.yaml b/packages/system/postgres-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/postgres-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/postgres-rd/values.yaml b/packages/system/postgres-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/postgres-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/prometheus-operator-crds/Chart.yaml b/packages/system/prometheus-operator-crds/Chart.yaml new file mode 100644 index 00000000..576c241f --- /dev/null +++ b/packages/system/prometheus-operator-crds/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-prometheus-operator-crds +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/prometheus-operator-crds/Makefile b/packages/system/prometheus-operator-crds/Makefile new file mode 100644 index 00000000..ed55f286 --- /dev/null +++ b/packages/system/prometheus-operator-crds/Makefile @@ -0,0 +1,10 @@ +export NAME=prometheus-operator-crds +export NAMESPACE=cozy-victoria-metrics-operator + +include ../../../hack/package.mk + +update: + helm repo add prometheus-community https://prometheus-community.github.io/helm-charts + helm repo update prometheus-community + helm pull prometheus-community/prometheus-operator-crds --untar --untardir charts + rm -f -- `find charts/prometheus-operator-crds/charts/crds/templates -maxdepth 1 -mindepth 1 | grep -v 'servicemonitor\|podmonitor\|prometheusrule\|probe'` diff --git a/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/.helmignore b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/.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/system/victoria-metrics-operator/charts/prometheus-operator-crds/Chart.lock b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/Chart.lock similarity index 76% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/Chart.lock rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/Chart.lock index f1acf647..336e8e35 100644 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/Chart.lock +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/Chart.lock @@ -3,4 +3,4 @@ dependencies: repository: "" version: 0.0.0 digest: sha256:aeada3fbffa2565a325406ad014001fd2685f7c0c9cfc1167da4f10c75a1bd65 -generated: "2025-03-15T22:08:36.140314181Z" +generated: "2025-11-21T15:12:44.500376661Z" diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/Chart.yaml b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/Chart.yaml similarity index 97% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/Chart.yaml rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/Chart.yaml index 6c0097f0..20e194ee 100644 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/Chart.yaml +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/Chart.yaml @@ -10,7 +10,7 @@ annotations: - name: QuentinBisson email: quentin.bisson@gmail.com apiVersion: v2 -appVersion: v0.81.0 +appVersion: v0.87.0 dependencies: - name: crds repository: "" @@ -39,4 +39,4 @@ name: prometheus-operator-crds sources: - https://github.com/prometheus-community/helm-charts type: application -version: 19.0.0 +version: 25.0.0 diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/README.md b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/README.md similarity index 63% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/README.md rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/README.md index b4dfcedd..21e979b5 100644 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/README.md +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/README.md @@ -9,27 +9,26 @@ For more information on Prometheus Operator and CRDs, please, see [documentation - Kubernetes >= 1.16.0 - Helm 3 -## Get Repository Info - -```console -helm repo add prometheus-community https://prometheus-community.github.io/helm-charts -helm repo update -``` +## Usage -_See [`helm repo`](https://helm.sh/docs/helm/helm_repo/) for command documentation._ - +The chart is distributed as an [OCI Artifact](https://helm.sh/docs/topics/registries/) as well as via a traditional [Helm Repository](https://helm.sh/docs/topics/chart_repository/). -## Install Chart +- OCI Artifact: `oci://ghcr.io/prometheus-community/charts/prometheus-operator-crds` +- Helm Repository: `https://prometheus-community.github.io/helm-charts` with chart `prometheus-operator-crds` + +The installation instructions use the OCI registry. Refer to the [`helm repo`]([`helm repo`](https://helm.sh/docs/helm/helm_repo/)) command documentation for information on installing charts via the traditional repository. + +### Install Chart ```console -helm install [RELEASE_NAME] prometheus-community/prometheus-operator-crds +helm install [RELEASE_NAME] oci://ghcr.io/prometheus-community/charts/prometheus-operator-crds ``` _See [configuration](#configuring) below._ _See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._ -## Uninstall Chart +### Uninstall Chart ```console helm uninstall [RELEASE_NAME] @@ -40,7 +39,7 @@ _including_ resources of Kind `Prometheus`, `Alertmanager`, `ServiceMonitor`, et _See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._ -## Upgrading Chart +### Upgrading Chart ```console helm upgrade [RELEASE_NAME] [CHART] --install @@ -48,7 +47,7 @@ helm upgrade [RELEASE_NAME] [CHART] --install _See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._ -## Upgrading to v6.0.0 +#### Upgrading to v6.0.0 The upgraded chart now the following changes: @@ -59,5 +58,5 @@ The upgraded chart now the following changes: See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). To see all configurable options with detailed comments, visit the chart's [values.yaml](./values.yaml), or run these configuration commands: ```console -helm show values prometheus-community/prometheus-operator-crds +helm show values oci://ghcr.io/prometheus-community/charts/prometheus-operator-crds ``` diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/Chart.yaml b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/Chart.yaml similarity index 100% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/Chart.yaml rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/Chart.yaml diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-podmonitors.yaml b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-podmonitors.yaml similarity index 69% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-podmonitors.yaml rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-podmonitors.yaml index dcb71f7c..608d53e5 100644 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-podmonitors.yaml +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-podmonitors.yaml @@ -1,4 +1,5 @@ -# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.81.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +{{- if .Values.podmonitors.enabled -}} +# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.87.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -7,8 +8,8 @@ metadata: {{- with .Values.annotations }} {{- toYaml . | nindent 4 }} {{- end }} - controller-gen.kubebuilder.io/version: v0.17.2 - operator.prometheus.io/version: 0.81.0 + controller-gen.kubebuilder.io/version: v0.19.0 + operator.prometheus.io/version: 0.87.0 name: podmonitors.monitoring.coreos.com spec: group: monitoring.coreos.com @@ -54,19 +55,19 @@ spec: metadata: type: object spec: - description: Specification of desired Pod selection for target discovery - by Prometheus. + description: spec defines the specification of desired Pod selection for + target discovery by Prometheus. properties: attachMetadata: description: |- - `attachMetadata` defines additional metadata which is added to the + attachMetadata defines additional metadata which is added to the discovered targets. It requires Prometheus >= v2.35.0. properties: node: description: |- - When set to true, Prometheus attaches node metadata to the discovered + node when set to true, Prometheus attaches node metadata to the discovered targets. The Prometheus service account must have the `list` and `watch` @@ -75,15 +76,20 @@ spec: type: object bodySizeLimit: description: |- - When defined, bodySizeLimit specifies a job level limit on the size + bodySizeLimit when defined specifies a job level limit on the size of uncompressed response body that will be accepted by Prometheus. It requires Prometheus >= v2.28.0. pattern: (^0|([0-9]*[.])?[0-9]+((K|M|G|T|E|P)i?)?B)$ type: string + convertClassicHistogramsToNHCB: + description: |- + convertClassicHistogramsToNHCB defines whether to convert all scraped classic histograms into a native histogram with custom buckets. + It requires Prometheus >= v3.0.0. + type: boolean fallbackScrapeProtocol: description: |- - The protocol to use if a scrape returns blank, unparseable, or otherwise invalid Content-Type. + fallbackScrapeProtocol defines the protocol to use if a scrape returns blank, unparseable, or otherwise invalid Content-Type. It requires Prometheus >= v3.0.0. enum: @@ -95,7 +101,7 @@ spec: type: string jobLabel: description: |- - The label to use to retrieve the job name from. + jobLabel defines the label to use to retrieve the job name from. `jobLabel` selects the label from the associated Kubernetes `Pod` object which will be used as the `job` label for all metrics. @@ -108,7 +114,7 @@ spec: type: string keepDroppedTargets: description: |- - Per-scrape limit on the number of targets dropped by relabeling + keepDroppedTargets defines the per-scrape limit on the number of targets dropped by relabeling that will be kept in memory. 0 means no limit. It requires Prometheus >= v2.47.0. @@ -116,44 +122,45 @@ spec: type: integer labelLimit: description: |- - Per-scrape limit on number of labels that will be accepted for a sample. + labelLimit defines the per-scrape limit on number of labels that will be accepted for a sample. It requires Prometheus >= v2.27.0. format: int64 type: integer labelNameLengthLimit: description: |- - Per-scrape limit on length of labels name that will be accepted for a sample. + labelNameLengthLimit defines the per-scrape limit on length of labels name that will be accepted for a sample. It requires Prometheus >= v2.27.0. format: int64 type: integer labelValueLengthLimit: description: |- - Per-scrape limit on length of labels value that will be accepted for a sample. + labelValueLengthLimit defines the per-scrape limit on length of labels value that will be accepted for a sample. It requires Prometheus >= v2.27.0. format: int64 type: integer namespaceSelector: description: |- - `namespaceSelector` defines in which namespace(s) Prometheus should discover the pods. + namespaceSelector defines in which namespace(s) Prometheus should discover the pods. By default, the pods are discovered in the same namespace as the `PodMonitor` object but it is possible to select pods across different/all namespaces. properties: any: description: |- - Boolean describing whether all namespaces are selected in contrast to a + any defines the boolean describing whether all namespaces are selected in contrast to a list restricting them. type: boolean matchNames: - description: List of namespace names to select from. + description: matchNames defines the list of namespace names to + select from. items: type: string type: array type: object nativeHistogramBucketLimit: description: |- - If there are more than this many buckets in a native histogram, + nativeHistogramBucketLimit defines ff there are more than this many buckets in a native histogram, buckets will be merged to stay within the limit. It requires Prometheus >= v2.45.0. format: int64 @@ -163,13 +170,14 @@ spec: - type: integer - type: string description: |- - If the growth factor of one bucket to the next is smaller than this, + nativeHistogramMinBucketFactor defines if the growth factor of one bucket to the next is smaller than this, buckets will be merged to increase the factor sufficiently. It requires Prometheus >= v2.50.0. pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true podMetricsEndpoints: - description: Defines how to scrape metrics from the selected pods. + description: podMetricsEndpoints defines how to scrape metrics from + the selected pods. items: description: |- PodMetricsEndpoint defines an endpoint serving Prometheus metrics to be scraped by @@ -177,14 +185,14 @@ spec: properties: authorization: description: |- - `authorization` configures the Authorization header credentials to use when - scraping the target. + authorization configures the Authorization header credentials used by + the client. - Cannot be set at the same time as `basicAuth`, or `oauth2`. + Cannot be set at the same time as `basicAuth`, `bearerTokenSecret` or `oauth2`. properties: credentials: - description: Selects a key of a Secret in the namespace - that contains the credentials for authentication. + description: credentials defines a key of a Secret in the + namespace that contains the credentials for authentication. properties: key: description: The key of the secret to select from. Must @@ -209,7 +217,7 @@ spec: x-kubernetes-map-type: atomic type: description: |- - Defines the authentication type. The value is case-insensitive. + type defines the authentication type. The value is case-insensitive. "Basic" is not a supported value. @@ -218,14 +226,14 @@ spec: type: object basicAuth: description: |- - `basicAuth` configures the Basic Authentication credentials to use when - scraping the target. + basicAuth defines the Basic Authentication credentials used by the + client. - Cannot be set at the same time as `authorization`, or `oauth2`. + Cannot be set at the same time as `authorization`, `bearerTokenSecret` or `oauth2`. properties: password: description: |- - `password` specifies a key of a Secret containing the password for + password defines a key of a Secret containing the password for authentication. properties: key: @@ -251,7 +259,7 @@ spec: x-kubernetes-map-type: atomic username: description: |- - `username` specifies a key of a Secret containing the username for + username defines a key of a Secret containing the username for authentication. properties: key: @@ -278,9 +286,12 @@ spec: type: object bearerTokenSecret: description: |- - `bearerTokenSecret` specifies a key of a Secret containing the bearer - token for scraping targets. The secret needs to be in the same namespace - as the PodMonitor object and readable by the Prometheus Operator. + bearerTokenSecret defines a key of a Secret containing the bearer token + used by the client for authentication. The secret needs to be in the + same namespace as the custom resource and readable by the Prometheus + Operator. + + Cannot be set at the same time as `authorization`, `basicAuth` or `oauth2`. Deprecated: use `authorization` instead. properties: @@ -306,12 +317,11 @@ spec: type: object x-kubernetes-map-type: atomic enableHttp2: - description: '`enableHttp2` can be used to disable HTTP2 when - scraping the target.' + description: enableHttp2 can be used to disable HTTP2. type: boolean filterRunning: description: |- - When true, the pods which are not running (e.g. either in Failed or + filterRunning when true, the pods which are not running (e.g. either in Failed or Succeeded state) are dropped during the target discovery. If unset, the filtering is enabled. @@ -320,29 +330,29 @@ spec: type: boolean followRedirects: description: |- - `followRedirects` defines whether the scrape requests should follow HTTP - 3xx redirects. + followRedirects defines whether the client should follow HTTP 3xx + redirects. type: boolean honorLabels: description: |- - When true, `honorLabels` preserves the metric's labels when they collide + honorLabels when true preserves the metric's labels when they collide with the target's labels. type: boolean honorTimestamps: description: |- - `honorTimestamps` controls whether Prometheus preserves the timestamps + honorTimestamps defines whether Prometheus preserves the timestamps when exposed by the target. type: boolean interval: description: |- - Interval at which Prometheus scrapes the metrics from the target. + interval at which Prometheus scrapes the metrics from the target. If empty, Prometheus uses the global scrape interval. pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ type: string metricRelabelings: description: |- - `metricRelabelings` configures the relabeling rules to apply to the + metricRelabelings defines the relabeling rules to apply to the samples before ingestion. items: description: |- @@ -354,7 +364,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -386,41 +396,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -429,22 +439,30 @@ spec: type: string type: object type: array + noProxy: + description: |- + noProxy defines a comma-separated string that can contain IPs, CIDR notation, domain names + that should be excluded from proxying. IP and domain names can + contain port numbers. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: string oauth2: description: |- - `oauth2` configures the OAuth2 settings to use when scraping the target. + oauth2 defines the OAuth2 settings used by the client. It requires Prometheus >= 2.27.0. - Cannot be set at the same time as `authorization`, or `basicAuth`. + Cannot be set at the same time as `authorization`, `basicAuth` or `bearerTokenSecret`. properties: clientId: description: |- - `clientId` specifies a key of a Secret or ConfigMap containing the + clientId defines a key of a Secret or ConfigMap containing the OAuth2 client's ID. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -467,7 +485,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -493,7 +512,7 @@ spec: type: object clientSecret: description: |- - `clientSecret` specifies a key of a Secret containing the OAuth2 + clientSecret defines a key of a Secret containing the OAuth2 client's secret. properties: key: @@ -521,16 +540,16 @@ spec: additionalProperties: type: string description: |- - `endpointParams` configures the HTTP parameters to append to the token + endpointParams configures the HTTP parameters to append to the token URL. type: object noProxy: description: |- - `noProxy` is a comma-separated string that can contain IPs, CIDR notation, domain names + noProxy defines a comma-separated string that can contain IPs, CIDR notation, domain names that should be excluded from proxying. IP and domain names can contain port numbers. - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: string proxyConnectHeader: additionalProperties: @@ -560,41 +579,40 @@ spec: x-kubernetes-map-type: atomic type: array description: |- - ProxyConnectHeader optionally specifies headers to send to + proxyConnectHeader optionally specifies headers to send to proxies during CONNECT requests. - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: object x-kubernetes-map-type: atomic proxyFromEnvironment: description: |- - Whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). + proxyFromEnvironment defines whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: boolean proxyUrl: - description: '`proxyURL` defines the HTTP proxy server to - use.' - pattern: ^http(s)?://.+$ + description: proxyUrl defines the HTTP proxy server to use. + pattern: ^(http|https|socks5)://.+$ type: string scopes: - description: '`scopes` defines the OAuth2 scopes used for - the token request.' + description: scopes defines the OAuth2 scopes used for the + token request. items: type: string type: array tlsConfig: description: |- - TLS configuration to use when connecting to the OAuth2 server. + tlsConfig defines the TLS configuration to use when connecting to the OAuth2 server. It requires Prometheus >= v2.43.0. properties: ca: - description: Certificate authority used when verifying - server certificates. + description: ca defines the Certificate authority used + when verifying server certificates. properties: configMap: - description: ConfigMap containing data to use for - the targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -617,8 +635,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the - targets. + description: secret defines the Secret containing + data to use for the targets. properties: key: description: The key of the secret to select @@ -643,12 +661,12 @@ spec: x-kubernetes-map-type: atomic type: object cert: - description: Client certificate to present when doing - client-authentication. + description: cert defines the Client certificate to + present when doing client-authentication. properties: configMap: - description: ConfigMap containing data to use for - the targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -671,8 +689,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the - targets. + description: secret defines the Secret containing + data to use for the targets. properties: key: description: The key of the secret to select @@ -697,11 +715,12 @@ spec: x-kubernetes-map-type: atomic type: object insecureSkipVerify: - description: Disable target certificate validation. + description: insecureSkipVerify defines how to disable + target certificate validation. type: boolean keySecret: - description: Secret containing the client key file for - the targets. + description: keySecret defines the Secret containing + the client key file for the targets. properties: key: description: The key of the secret to select from. Must @@ -726,9 +745,9 @@ spec: x-kubernetes-map-type: atomic maxVersion: description: |- - Maximum acceptable TLS version. + maxVersion defines the maximum acceptable TLS version. - It requires Prometheus >= v2.41.0. + It requires Prometheus >= v2.41.0 or Thanos >= v0.31.0. enum: - TLS10 - TLS11 @@ -737,9 +756,9 @@ spec: type: string minVersion: description: |- - Minimum acceptable TLS version. + minVersion defines the minimum acceptable TLS version. - It requires Prometheus >= v2.35.0. + It requires Prometheus >= v2.35.0 or Thanos >= v0.28.0. enum: - TLS10 - TLS11 @@ -747,12 +766,13 @@ spec: - TLS13 type: string serverName: - description: Used to verify the hostname for the targets. + description: serverName is used to verify the hostname + for the targets. type: string type: object tokenUrl: - description: '`tokenURL` configures the URL to fetch the - token from.' + description: tokenUrl defines the URL to fetch the token + from. minLength: 1 type: string required: @@ -765,34 +785,92 @@ spec: items: type: string type: array - description: '`params` define optional HTTP URL parameters.' + description: params define optional HTTP URL parameters. type: object path: description: |- - HTTP path from which to scrape for metrics. + path defines the HTTP path from which to scrape for metrics. If empty, Prometheus uses the default value (e.g. `/metrics`). type: string port: description: |- - The `Pod` port name which exposes the endpoint. + port defines the `Pod` port name which exposes the endpoint. + + If the pod doesn't expose a port with the same name, it will result + in no targets being discovered. + + If a `Pod` has multiple `Port`s with the same name (which is not + recommended), one target instance per unique port number will be + generated. It takes precedence over the `portNumber` and `targetPort` fields. type: string portNumber: - description: The `Pod` port number which exposes the endpoint. + description: |- + portNumber defines the `Pod` port number which exposes the endpoint. + + The `Pod` must declare the specified `Port` in its spec or the + target will be dropped by Prometheus. + + This cannot be used to enable scraping of an undeclared port. + To scrape targets on a port which isn't exposed, you need to use + relabeling to override the `__address__` label (but beware of + duplicate targets if the `Pod` has other declared ports). + + In practice Prometheus will select targets for which the + matches the target's __meta_kubernetes_pod_container_port_number. format: int32 maximum: 65535 minimum: 1 type: integer - proxyUrl: + proxyConnectHeader: + additionalProperties: + items: + description: SecretKeySelector selects a key of a Secret. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: array description: |- - `proxyURL` configures the HTTP Proxy URL (e.g. - "http://proxyserver:2195") to go through when scraping the target. + proxyConnectHeader optionally specifies headers to send to + proxies during CONNECT requests. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: object + x-kubernetes-map-type: atomic + proxyFromEnvironment: + description: |- + proxyFromEnvironment defines whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: boolean + proxyUrl: + description: proxyUrl defines the HTTP proxy server to use. + pattern: ^(http|https|socks5)://.+$ type: string relabelings: description: |- - `relabelings` configures the relabeling rules to apply the target's + relabelings defines the relabeling rules to apply the target's metadata labels. The Operator automatically adds relabelings for a few standard Kubernetes fields. @@ -810,7 +888,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -842,41 +920,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -886,20 +964,16 @@ spec: type: object type: array scheme: - description: |- - HTTP scheme to use for scraping. - - `http` and `https` are the expected values unless you rewrite the - `__scheme__` label via relabeling. - - If empty, Prometheus uses the default value `http`. + description: scheme defines the HTTP scheme to use for scraping. enum: - http - https + - HTTP + - HTTPS type: string scrapeTimeout: description: |- - Timeout after which Prometheus considers the scrape to be failed. + scrapeTimeout defines the timeout after which Prometheus considers the scrape to be failed. If empty, Prometheus uses the global scrape timeout unless it is less than the target's scrape interval value in which the latter is used. @@ -911,21 +985,22 @@ spec: - type: integer - type: string description: |- - Name or number of the target port of the `Pod` object behind the Service, the + targetPort defines the name or number of the target port of the `Pod` object behind the Service, the port must be specified with container port property. Deprecated: use 'port' or 'portNumber' instead. x-kubernetes-int-or-string: true tlsConfig: - description: TLS configuration to use when scraping the target. + description: tlsConfig defines the TLS configuration used by + the client. properties: ca: - description: Certificate authority used when verifying server - certificates. + description: ca defines the Certificate authority used when + verifying server certificates. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -948,7 +1023,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -973,11 +1049,12 @@ spec: x-kubernetes-map-type: atomic type: object cert: - description: Client certificate to present when doing client-authentication. + description: cert defines the Client certificate to present + when doing client-authentication. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -1000,7 +1077,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -1025,11 +1103,12 @@ spec: x-kubernetes-map-type: atomic type: object insecureSkipVerify: - description: Disable target certificate validation. + description: insecureSkipVerify defines how to disable target + certificate validation. type: boolean keySecret: - description: Secret containing the client key file for the - targets. + description: keySecret defines the Secret containing the + client key file for the targets. properties: key: description: The key of the secret to select from. Must @@ -1054,9 +1133,9 @@ spec: x-kubernetes-map-type: atomic maxVersion: description: |- - Maximum acceptable TLS version. + maxVersion defines the maximum acceptable TLS version. - It requires Prometheus >= v2.41.0. + It requires Prometheus >= v2.41.0 or Thanos >= v0.31.0. enum: - TLS10 - TLS11 @@ -1065,9 +1144,9 @@ spec: type: string minVersion: description: |- - Minimum acceptable TLS version. + minVersion defines the minimum acceptable TLS version. - It requires Prometheus >= v2.35.0. + It requires Prometheus >= v2.35.0 or Thanos >= v0.28.0. enum: - TLS10 - TLS11 @@ -1075,12 +1154,13 @@ spec: - TLS13 type: string serverName: - description: Used to verify the hostname for the targets. + description: serverName is used to verify the hostname for + the targets. type: string type: object trackTimestampsStaleness: description: |- - `trackTimestampsStaleness` defines whether Prometheus tracks staleness of + trackTimestampsStaleness defines whether Prometheus tracks staleness of the metrics that have an explicit timestamp present in scraped data. Has no effect if `honorTimestamps` is false. @@ -1090,29 +1170,31 @@ spec: type: array podTargetLabels: description: |- - `podTargetLabels` defines the labels which are transferred from the + podTargetLabels defines the labels which are transferred from the associated Kubernetes `Pod` object onto the ingested metrics. items: type: string type: array sampleLimit: description: |- - `sampleLimit` defines a per-scrape limit on the number of scraped samples + sampleLimit defines a per-scrape limit on the number of scraped samples that will be accepted. format: int64 type: integer scrapeClass: - description: The scrape class to apply. + description: scrapeClass defines the scrape class to apply. minLength: 1 type: string scrapeClassicHistograms: description: |- - Whether to scrape a classic histogram that is also exposed as a native histogram. + scrapeClassicHistograms defines whether to scrape a classic histogram that is also exposed as a native histogram. It requires Prometheus >= v2.45.0. + + Notice: `scrapeClassicHistograms` corresponds to the `always_scrape_classic_histograms` field in the Prometheus configuration. type: boolean scrapeProtocols: description: |- - `scrapeProtocols` defines the protocols to negotiate during a scrape. It tells clients the + scrapeProtocols defines the protocols to negotiate during a scrape. It tells clients the protocols supported by Prometheus in order of preference (from most to least preferred). If unset, Prometheus uses its default value. @@ -1137,8 +1219,8 @@ spec: type: array x-kubernetes-list-type: set selector: - description: Label selector to select the Kubernetes `Pod` objects - to scrape metrics from. + description: selector defines the label selector to select the Kubernetes + `Pod` objects to scrape metrics from. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. @@ -1185,7 +1267,7 @@ spec: x-kubernetes-map-type: atomic selectorMechanism: description: |- - Mechanism used to select the endpoints to scrape. + selectorMechanism defines the mechanism used to select the endpoints to scrape. By default, the selection process relies on relabel configurations to filter the discovered targets. Alternatively, you can opt in for role selectors, which may offer better efficiency in large clusters. Which strategy is best for your use case needs to be carefully evaluated. @@ -1197,15 +1279,121 @@ spec: type: string targetLimit: description: |- - `targetLimit` defines a limit on the number of scraped targets that will + targetLimit defines a limit on the number of scraped targets that will be accepted. format: int64 type: integer required: - selector type: object + status: + description: |- + status defines the status subresource. It is under active development and is updated only when the + "StatusForConfigurationResources" feature gate is enabled. + + Most recent observed status of the PodMonitor. Read-only. + More info: + https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + bindings: + description: bindings defines the list of workload resources (Prometheus, + PrometheusAgent, ThanosRuler or Alertmanager) which select the configuration + resource. + items: + description: WorkloadBinding is a link between a configuration resource + and a workload resource. + properties: + conditions: + description: conditions defines the current state of the configuration + resource when bound to the referenced Workload object. + items: + description: ConfigResourceCondition describes the status + of configuration resources linked to Prometheus, PrometheusAgent, + Alertmanager or ThanosRuler. + properties: + lastTransitionTime: + description: lastTransitionTime defines the time of the + last update to the current status property. + format: date-time + type: string + message: + description: message defines the human-readable message + indicating details for the condition's last transition. + type: string + observedGeneration: + description: |- + observedGeneration defines the .metadata.generation that the + condition was set based upon. For instance, if `.metadata.generation` is + currently 12, but the `.status.conditions[].observedGeneration` is 9, the + condition is out of date with respect to the current state of the object. + format: int64 + type: integer + reason: + description: reason for the condition's last transition. + type: string + status: + description: status of the condition. + minLength: 1 + type: string + type: + description: |- + type of the condition being reported. + Currently, only "Accepted" is supported. + enum: + - Accepted + minLength: 1 + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + group: + description: group defines the group of the referenced resource. + enum: + - monitoring.coreos.com + type: string + name: + description: name defines the name of the referenced object. + minLength: 1 + type: string + namespace: + description: namespace defines the namespace of the referenced + object. + minLength: 1 + type: string + resource: + description: resource defines the type of resource being referenced + (e.g. Prometheus, PrometheusAgent, ThanosRuler or Alertmanager). + enum: + - prometheuses + - prometheusagents + - thanosrulers + - alertmanagers + type: string + required: + - group + - name + - namespace + - resource + type: object + type: array + x-kubernetes-list-map-keys: + - group + - resource + - name + - namespace + x-kubernetes-list-type: map + type: object required: - spec type: object served: true storage: true + subresources: + status: {} +{{- end -}} diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-probes.yaml b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-probes.yaml similarity index 69% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-probes.yaml rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-probes.yaml index 05a75775..f2d06e03 100644 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-probes.yaml +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-probes.yaml @@ -1,4 +1,5 @@ -# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.81.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +{{- if .Values.probes.enabled -}} +# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.87.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -7,8 +8,8 @@ metadata: {{- with .Values.annotations }} {{- toYaml . | nindent 4 }} {{- end }} - controller-gen.kubebuilder.io/version: v0.17.2 - operator.prometheus.io/version: 0.81.0 + controller-gen.kubebuilder.io/version: v0.19.0 + operator.prometheus.io/version: 0.87.0 name: probes.monitoring.coreos.com spec: group: monitoring.coreos.com @@ -53,15 +54,15 @@ spec: metadata: type: object spec: - description: Specification of desired Ingress selection for target discovery - by Prometheus. + description: spec defines the specification of desired Ingress selection + for target discovery by Prometheus. properties: authorization: - description: Authorization section for this endpoint + description: authorization section for this endpoint properties: credentials: - description: Selects a key of a Secret in the namespace that contains - the credentials for authentication. + description: credentials defines a key of a Secret in the namespace + that contains the credentials for authentication. properties: key: description: The key of the secret to select from. Must be @@ -86,7 +87,7 @@ spec: x-kubernetes-map-type: atomic type: description: |- - Defines the authentication type. The value is case-insensitive. + type defines the authentication type. The value is case-insensitive. "Basic" is not a supported value. @@ -95,12 +96,12 @@ spec: type: object basicAuth: description: |- - BasicAuth allow an endpoint to authenticate over basic authentication. + basicAuth allow an endpoint to authenticate over basic authentication. More info: https://prometheus.io/docs/operating/configuration/#endpoint properties: password: description: |- - `password` specifies a key of a Secret containing the password for + password defines a key of a Secret containing the password for authentication. properties: key: @@ -126,7 +127,7 @@ spec: x-kubernetes-map-type: atomic username: description: |- - `username` specifies a key of a Secret containing the username for + username defines a key of a Secret containing the username for authentication. properties: key: @@ -153,7 +154,7 @@ spec: type: object bearerTokenSecret: description: |- - Secret to mount to read bearer token for scraping targets. The secret + bearerTokenSecret defines the secret to mount to read bearer token for scraping targets. The secret needs to be in the same namespace as the probe and accessible by the Prometheus Operator. properties: @@ -177,9 +178,14 @@ spec: - key type: object x-kubernetes-map-type: atomic + convertClassicHistogramsToNHCB: + description: |- + convertClassicHistogramsToNHCB defines whether to convert all scraped classic histograms into a native histogram with custom buckets. + It requires Prometheus >= v3.0.0. + type: boolean fallbackScrapeProtocol: description: |- - The protocol to use if a scrape returns blank, unparseable, or otherwise invalid Content-Type. + fallbackScrapeProtocol defines the protocol to use if a scrape returns blank, unparseable, or otherwise invalid Content-Type. It requires Prometheus >= v3.0.0. enum: @@ -191,16 +197,16 @@ spec: type: string interval: description: |- - Interval at which targets are probed using the configured prober. + interval at which targets are probed using the configured prober. If not specified Prometheus' global scrape interval is used. pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ type: string jobName: - description: The job name assigned to scraped metrics by default. + description: jobName assigned to scraped metrics by default. type: string keepDroppedTargets: description: |- - Per-scrape limit on the number of targets dropped by relabeling + keepDroppedTargets defines the per-scrape limit on the number of targets dropped by relabeling that will be kept in memory. 0 means no limit. It requires Prometheus >= v2.47.0. @@ -208,24 +214,25 @@ spec: type: integer labelLimit: description: |- - Per-scrape limit on number of labels that will be accepted for a sample. + labelLimit defines the per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. format: int64 type: integer labelNameLengthLimit: description: |- - Per-scrape limit on length of labels name that will be accepted for a sample. + labelNameLengthLimit defines the per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. format: int64 type: integer labelValueLengthLimit: description: |- - Per-scrape limit on length of labels value that will be accepted for a sample. + labelValueLengthLimit defines the per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. format: int64 type: integer metricRelabelings: - description: MetricRelabelConfigs to apply to samples before ingestion. + description: metricRelabelings defines the RelabelConfig to apply + to samples before ingestion. items: description: |- RelabelConfig allows dynamic rewriting of the label set for targets, alerts, @@ -236,7 +243,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -268,40 +275,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against which + the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated SourceLabels. + description: separator defines the string between concatenated + SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -312,13 +320,13 @@ spec: type: array module: description: |- - The module to use for probing specifying how to probe the target. + module to use for probing specifying how to probe the target. Example module configuring in the blackbox exporter: https://github.com/prometheus/blackbox_exporter/blob/master/example.yml type: string nativeHistogramBucketLimit: description: |- - If there are more than this many buckets in a native histogram, + nativeHistogramBucketLimit defines ff there are more than this many buckets in a native histogram, buckets will be merged to stay within the limit. It requires Prometheus >= v2.45.0. format: int64 @@ -328,22 +336,23 @@ spec: - type: integer - type: string description: |- - If the growth factor of one bucket to the next is smaller than this, + nativeHistogramMinBucketFactor defines if the growth factor of one bucket to the next is smaller than this, buckets will be merged to increase the factor sufficiently. It requires Prometheus >= v2.50.0. pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true oauth2: - description: OAuth2 for the URL. Only valid in Prometheus versions + description: oauth2 for the URL. Only valid in Prometheus versions 2.27.0 and newer. properties: clientId: description: |- - `clientId` specifies a key of a Secret or ConfigMap containing the + clientId defines a key of a Secret or ConfigMap containing the OAuth2 client's ID. properties: configMap: - description: ConfigMap containing data to use for the targets. + description: configMap defines the ConfigMap containing data + to use for the targets. properties: key: description: The key to select. @@ -366,7 +375,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data to + use for the targets. properties: key: description: The key of the secret to select from. Must @@ -392,7 +402,7 @@ spec: type: object clientSecret: description: |- - `clientSecret` specifies a key of a Secret containing the OAuth2 + clientSecret defines a key of a Secret containing the OAuth2 client's secret. properties: key: @@ -420,16 +430,16 @@ spec: additionalProperties: type: string description: |- - `endpointParams` configures the HTTP parameters to append to the token + endpointParams configures the HTTP parameters to append to the token URL. type: object noProxy: description: |- - `noProxy` is a comma-separated string that can contain IPs, CIDR notation, domain names + noProxy defines a comma-separated string that can contain IPs, CIDR notation, domain names that should be excluded from proxying. IP and domain names can contain port numbers. - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: string proxyConnectHeader: additionalProperties: @@ -459,40 +469,40 @@ spec: x-kubernetes-map-type: atomic type: array description: |- - ProxyConnectHeader optionally specifies headers to send to + proxyConnectHeader optionally specifies headers to send to proxies during CONNECT requests. - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: object x-kubernetes-map-type: atomic proxyFromEnvironment: description: |- - Whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). + proxyFromEnvironment defines whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: boolean proxyUrl: - description: '`proxyURL` defines the HTTP proxy server to use.' - pattern: ^http(s)?://.+$ + description: proxyUrl defines the HTTP proxy server to use. + pattern: ^(http|https|socks5)://.+$ type: string scopes: - description: '`scopes` defines the OAuth2 scopes used for the - token request.' + description: scopes defines the OAuth2 scopes used for the token + request. items: type: string type: array tlsConfig: description: |- - TLS configuration to use when connecting to the OAuth2 server. + tlsConfig defines the TLS configuration to use when connecting to the OAuth2 server. It requires Prometheus >= v2.43.0. properties: ca: - description: Certificate authority used when verifying server - certificates. + description: ca defines the Certificate authority used when + verifying server certificates. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -515,7 +525,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -540,11 +551,12 @@ spec: x-kubernetes-map-type: atomic type: object cert: - description: Client certificate to present when doing client-authentication. + description: cert defines the Client certificate to present + when doing client-authentication. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -567,7 +579,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -592,11 +605,12 @@ spec: x-kubernetes-map-type: atomic type: object insecureSkipVerify: - description: Disable target certificate validation. + description: insecureSkipVerify defines how to disable target + certificate validation. type: boolean keySecret: - description: Secret containing the client key file for the - targets. + description: keySecret defines the Secret containing the client + key file for the targets. properties: key: description: The key of the secret to select from. Must @@ -621,9 +635,9 @@ spec: x-kubernetes-map-type: atomic maxVersion: description: |- - Maximum acceptable TLS version. + maxVersion defines the maximum acceptable TLS version. - It requires Prometheus >= v2.41.0. + It requires Prometheus >= v2.41.0 or Thanos >= v0.31.0. enum: - TLS10 - TLS11 @@ -632,9 +646,9 @@ spec: type: string minVersion: description: |- - Minimum acceptable TLS version. + minVersion defines the minimum acceptable TLS version. - It requires Prometheus >= v2.35.0. + It requires Prometheus >= v2.35.0 or Thanos >= v0.28.0. enum: - TLS10 - TLS11 @@ -642,12 +656,12 @@ spec: - TLS13 type: string serverName: - description: Used to verify the hostname for the targets. + description: serverName is used to verify the hostname for + the targets. type: string type: object tokenUrl: - description: '`tokenURL` configures the URL to fetch the token - from.' + description: tokenUrl defines the URL to fetch the token from. minLength: 1 type: string required: @@ -655,52 +669,137 @@ spec: - clientSecret - tokenUrl type: object + params: + description: |- + params defines the list of HTTP query parameters for the scrape. + Please note that the `.spec.module` field takes precedence over the `module` parameter from this list when both are defined. + The module name must be added using Module under ProbeSpec. + items: + description: ProbeParam defines specification of extra parameters + for a Probe. + properties: + name: + description: name defines the parameter name + minLength: 1 + type: string + values: + description: values defines the parameter values + items: + minLength: 1 + type: string + minItems: 1 + type: array + required: + - name + type: object + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map prober: description: |- - Specification for the prober to use for probing targets. + prober defines the specification for the prober to use for probing targets. The prober.URL parameter is required. Targets cannot be probed if left empty. properties: + noProxy: + description: |- + noProxy defines a comma-separated string that can contain IPs, CIDR notation, domain names + that should be excluded from proxying. IP and domain names can + contain port numbers. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: string path: default: /probe description: |- - Path to collect metrics from. + path to collect metrics from. Defaults to `/probe`. type: string + proxyConnectHeader: + additionalProperties: + items: + description: SecretKeySelector selects a key of a Secret. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: array + description: |- + proxyConnectHeader optionally specifies headers to send to + proxies during CONNECT requests. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: object + x-kubernetes-map-type: atomic + proxyFromEnvironment: + description: |- + proxyFromEnvironment defines whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: boolean proxyUrl: - description: Optional ProxyURL. + description: proxyUrl defines the HTTP proxy server to use. + pattern: ^(http|https|socks5)://.+$ type: string scheme: - description: |- - HTTP scheme to use for scraping. - `http` and `https` are the expected values unless you rewrite the `__scheme__` label via relabeling. - If empty, Prometheus uses the default value `http`. + description: scheme defines the HTTP scheme to use when scraping + the prober. enum: - http - https + - HTTP + - HTTPS type: string url: - description: Mandatory URL of the prober. + description: |- + url defines the address of the prober. + + Unlike what the name indicates, the value should be in the form of + `address:port` without any scheme which should be specified in the + `scheme` field. + minLength: 1 type: string required: - url type: object sampleLimit: - description: SampleLimit defines per-scrape limit on number of scraped + description: sampleLimit defines per-scrape limit on number of scraped samples that will be accepted. format: int64 type: integer scrapeClass: - description: The scrape class to apply. + description: scrapeClass defines the scrape class to apply. minLength: 1 type: string scrapeClassicHistograms: description: |- - Whether to scrape a classic histogram that is also exposed as a native histogram. + scrapeClassicHistograms defines whether to scrape a classic histogram that is also exposed as a native histogram. It requires Prometheus >= v2.45.0. + + Notice: `scrapeClassicHistograms` corresponds to the `always_scrape_classic_histograms` field in the Prometheus configuration. type: boolean scrapeProtocols: description: |- - `scrapeProtocols` defines the protocols to negotiate during a scrape. It tells clients the + scrapeProtocols defines the protocols to negotiate during a scrape. It tells clients the protocols supported by Prometheus in order of preference (from most to least preferred). If unset, Prometheus uses its default value. @@ -726,18 +825,18 @@ spec: x-kubernetes-list-type: set scrapeTimeout: description: |- - Timeout for scraping metrics from the Prometheus exporter. + scrapeTimeout defines the timeout for scraping metrics from the Prometheus exporter. If not specified, the Prometheus global scrape timeout is used. The value cannot be greater than the scrape interval otherwise the operator will reject the resource. pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ type: string targetLimit: - description: TargetLimit defines a limit on the number of scraped + description: targetLimit defines a limit on the number of scraped targets that will be accepted. format: int64 type: integer targets: - description: Targets defines a set of static or dynamically discovered + description: targets defines a set of static or dynamically discovered targets to probe. properties: ingress: @@ -747,22 +846,24 @@ spec: If `staticConfig` is also defined, `staticConfig` takes precedence. properties: namespaceSelector: - description: From which namespaces to select Ingress objects. + description: namespaceSelector defines from which namespaces + to select Ingress objects. properties: any: description: |- - Boolean describing whether all namespaces are selected in contrast to a + any defines the boolean describing whether all namespaces are selected in contrast to a list restricting them. type: boolean matchNames: - description: List of namespace names to select from. + description: matchNames defines the list of namespace + names to select from. items: type: string type: array type: object relabelingConfigs: description: |- - RelabelConfigs to apply to the label set of the target before it gets + relabelingConfigs to apply to the label set of the target before it gets scraped. The original ingress address is available via the `__tmp_prometheus_ingress_address` label. It can be used to customize the @@ -779,7 +880,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -811,41 +912,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -855,7 +956,7 @@ spec: type: object type: array selector: - description: Selector to select the Ingress objects. + description: selector to select the Ingress objects. properties: matchExpressions: description: matchExpressions is a list of label selector @@ -911,12 +1012,12 @@ spec: labels: additionalProperties: type: string - description: Labels assigned to all metrics scraped from the - targets. + description: labels defines all labels assigned to all metrics + scraped from the targets. type: object relabelingConfigs: description: |- - RelabelConfigs to apply to the label set of the targets before it gets + relabelingConfigs defines relabelings to be apply to the label set of the targets before it gets scraped. More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config items: @@ -929,7 +1030,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -961,41 +1062,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -1005,21 +1106,23 @@ spec: type: object type: array static: - description: The list of hosts to probe. + description: static defines the list of hosts to probe. items: type: string type: array type: object type: object tlsConfig: - description: TLS configuration to use when scraping the endpoint. + description: tlsConfig defines the TLS configuration to use when scraping + the endpoint. properties: ca: - description: Certificate authority used when verifying server - certificates. + description: ca defines the Certificate authority used when verifying + server certificates. properties: configMap: - description: ConfigMap containing data to use for the targets. + description: configMap defines the ConfigMap containing data + to use for the targets. properties: key: description: The key to select. @@ -1042,7 +1145,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data to + use for the targets. properties: key: description: The key of the secret to select from. Must @@ -1067,10 +1171,12 @@ spec: x-kubernetes-map-type: atomic type: object cert: - description: Client certificate to present when doing client-authentication. + description: cert defines the Client certificate to present when + doing client-authentication. properties: configMap: - description: ConfigMap containing data to use for the targets. + description: configMap defines the ConfigMap containing data + to use for the targets. properties: key: description: The key to select. @@ -1093,7 +1199,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data to + use for the targets. properties: key: description: The key of the secret to select from. Must @@ -1118,10 +1225,12 @@ spec: x-kubernetes-map-type: atomic type: object insecureSkipVerify: - description: Disable target certificate validation. + description: insecureSkipVerify defines how to disable target + certificate validation. type: boolean keySecret: - description: Secret containing the client key file for the targets. + description: keySecret defines the Secret containing the client + key file for the targets. properties: key: description: The key of the secret to select from. Must be @@ -1146,9 +1255,9 @@ spec: x-kubernetes-map-type: atomic maxVersion: description: |- - Maximum acceptable TLS version. + maxVersion defines the maximum acceptable TLS version. - It requires Prometheus >= v2.41.0. + It requires Prometheus >= v2.41.0 or Thanos >= v0.31.0. enum: - TLS10 - TLS11 @@ -1157,9 +1266,9 @@ spec: type: string minVersion: description: |- - Minimum acceptable TLS version. + minVersion defines the minimum acceptable TLS version. - It requires Prometheus >= v2.35.0. + It requires Prometheus >= v2.35.0 or Thanos >= v0.28.0. enum: - TLS10 - TLS11 @@ -1167,12 +1276,119 @@ spec: - TLS13 type: string serverName: - description: Used to verify the hostname for the targets. + description: serverName is used to verify the hostname for the + targets. type: string type: object type: object + status: + description: |- + status defines the status subresource. It is under active development and is updated only when the + "StatusForConfigurationResources" feature gate is enabled. + + Most recent observed status of the Probe. Read-only. + More info: + https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + bindings: + description: bindings defines the list of workload resources (Prometheus, + PrometheusAgent, ThanosRuler or Alertmanager) which select the configuration + resource. + items: + description: WorkloadBinding is a link between a configuration resource + and a workload resource. + properties: + conditions: + description: conditions defines the current state of the configuration + resource when bound to the referenced Workload object. + items: + description: ConfigResourceCondition describes the status + of configuration resources linked to Prometheus, PrometheusAgent, + Alertmanager or ThanosRuler. + properties: + lastTransitionTime: + description: lastTransitionTime defines the time of the + last update to the current status property. + format: date-time + type: string + message: + description: message defines the human-readable message + indicating details for the condition's last transition. + type: string + observedGeneration: + description: |- + observedGeneration defines the .metadata.generation that the + condition was set based upon. For instance, if `.metadata.generation` is + currently 12, but the `.status.conditions[].observedGeneration` is 9, the + condition is out of date with respect to the current state of the object. + format: int64 + type: integer + reason: + description: reason for the condition's last transition. + type: string + status: + description: status of the condition. + minLength: 1 + type: string + type: + description: |- + type of the condition being reported. + Currently, only "Accepted" is supported. + enum: + - Accepted + minLength: 1 + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + group: + description: group defines the group of the referenced resource. + enum: + - monitoring.coreos.com + type: string + name: + description: name defines the name of the referenced object. + minLength: 1 + type: string + namespace: + description: namespace defines the namespace of the referenced + object. + minLength: 1 + type: string + resource: + description: resource defines the type of resource being referenced + (e.g. Prometheus, PrometheusAgent, ThanosRuler or Alertmanager). + enum: + - prometheuses + - prometheusagents + - thanosrulers + - alertmanagers + type: string + required: + - group + - name + - namespace + - resource + type: object + type: array + x-kubernetes-list-map-keys: + - group + - resource + - name + - namespace + x-kubernetes-list-type: map + type: object required: - spec type: object served: true storage: true + subresources: + status: {} +{{- end -}} diff --git a/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-prometheusrules.yaml b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-prometheusrules.yaml new file mode 100644 index 00000000..cf13c7c3 --- /dev/null +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-prometheusrules.yaml @@ -0,0 +1,272 @@ +{{- if .Values.prometheusrules.enabled -}} +# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.87.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: +{{- with .Values.annotations }} +{{- toYaml . | nindent 4 }} +{{- end }} + controller-gen.kubebuilder.io/version: v0.19.0 + operator.prometheus.io/version: 0.87.0 + name: prometheusrules.monitoring.coreos.com +spec: + group: monitoring.coreos.com + names: + categories: + - prometheus-operator + kind: PrometheusRule + listKind: PrometheusRuleList + plural: prometheusrules + shortNames: + - promrule + singular: prometheusrule + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: |- + The `PrometheusRule` custom resource definition (CRD) defines [alerting](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/) and [recording](https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/) rules to be evaluated by `Prometheus` or `ThanosRuler` objects. + + `Prometheus` and `ThanosRuler` objects select `PrometheusRule` objects using label and namespace selectors. + 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 specification of desired alerting rule definitions + for Prometheus. + properties: + groups: + description: groups defines the content of Prometheus rule file + items: + description: RuleGroup is a list of sequentially evaluated recording + and alerting rules. + properties: + interval: + description: interval defines how often rules in the group are + evaluated. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + labels: + additionalProperties: + type: string + description: |- + labels define the labels to add or overwrite before storing the result for its rules. + The labels defined at the rule level take precedence. + + It requires Prometheus >= 3.0.0. + The field is ignored for Thanos Ruler. + type: object + limit: + description: |- + limit defines the number of alerts an alerting rule and series a recording + rule can produce. + Limit is supported starting with Prometheus >= 2.31 and Thanos Ruler >= 0.24. + type: integer + name: + description: name defines the name of the rule group. + minLength: 1 + type: string + partial_response_strategy: + description: |- + partial_response_strategy is only used by ThanosRuler and will + be ignored by Prometheus instances. + More info: https://github.com/thanos-io/thanos/blob/main/docs/components/rule.md#partial-response + pattern: ^(?i)(abort|warn)?$ + type: string + query_offset: + description: |- + query_offset defines the offset the rule evaluation timestamp of this particular group by the specified duration into the past. + + It requires Prometheus >= v2.53.0. + It is not supported for ThanosRuler. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + rules: + description: rules defines the list of alerting and recording + rules. + items: + description: |- + Rule describes an alerting or recording rule + See Prometheus documentation: [alerting](https://www.prometheus.io/docs/prometheus/latest/configuration/alerting_rules/) or [recording](https://www.prometheus.io/docs/prometheus/latest/configuration/recording_rules/#recording-rules) rule + properties: + alert: + description: |- + alert defines the name of the alert. Must be a valid label value. + Only one of `record` and `alert` must be set. + type: string + annotations: + additionalProperties: + type: string + description: |- + annotations defines annotations to add to each alert. + Only valid for alerting rules. + type: object + expr: + anyOf: + - type: integer + - type: string + description: expr defines the PromQL expression to evaluate. + x-kubernetes-int-or-string: true + for: + description: for defines how alerts are considered firing + once they have been returned for this long. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + keep_firing_for: + description: keep_firing_for defines how long an alert + will continue firing after the condition that triggered + it has cleared. + minLength: 1 + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + labels: + additionalProperties: + type: string + description: labels defines labels to add or overwrite. + type: object + record: + description: |- + record defines the name of the time series to output to. Must be a valid metric name. + Only one of `record` and `alert` must be set. + type: string + required: + - expr + type: object + type: array + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + status: + description: |- + status defines the status subresource. It is under active development and is updated only when the + "StatusForConfigurationResources" feature gate is enabled. + + Most recent observed status of the PrometheusRule. Read-only. + More info: + https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + bindings: + description: bindings defines the list of workload resources (Prometheus, + PrometheusAgent, ThanosRuler or Alertmanager) which select the configuration + resource. + items: + description: WorkloadBinding is a link between a configuration resource + and a workload resource. + properties: + conditions: + description: conditions defines the current state of the configuration + resource when bound to the referenced Workload object. + items: + description: ConfigResourceCondition describes the status + of configuration resources linked to Prometheus, PrometheusAgent, + Alertmanager or ThanosRuler. + properties: + lastTransitionTime: + description: lastTransitionTime defines the time of the + last update to the current status property. + format: date-time + type: string + message: + description: message defines the human-readable message + indicating details for the condition's last transition. + type: string + observedGeneration: + description: |- + observedGeneration defines the .metadata.generation that the + condition was set based upon. For instance, if `.metadata.generation` is + currently 12, but the `.status.conditions[].observedGeneration` is 9, the + condition is out of date with respect to the current state of the object. + format: int64 + type: integer + reason: + description: reason for the condition's last transition. + type: string + status: + description: status of the condition. + minLength: 1 + type: string + type: + description: |- + type of the condition being reported. + Currently, only "Accepted" is supported. + enum: + - Accepted + minLength: 1 + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + group: + description: group defines the group of the referenced resource. + enum: + - monitoring.coreos.com + type: string + name: + description: name defines the name of the referenced object. + minLength: 1 + type: string + namespace: + description: namespace defines the namespace of the referenced + object. + minLength: 1 + type: string + resource: + description: resource defines the type of resource being referenced + (e.g. Prometheus, PrometheusAgent, ThanosRuler or Alertmanager). + enum: + - prometheuses + - prometheusagents + - thanosrulers + - alertmanagers + type: string + required: + - group + - name + - namespace + - resource + type: object + type: array + x-kubernetes-list-map-keys: + - group + - resource + - name + - namespace + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +{{- end -}} diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-servicemonitors.yaml b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-servicemonitors.yaml similarity index 70% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-servicemonitors.yaml rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-servicemonitors.yaml index 64e19e48..ff4472f2 100644 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-servicemonitors.yaml +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/charts/crds/templates/crd-servicemonitors.yaml @@ -1,4 +1,5 @@ -# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.81.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +{{- if .Values.servicemonitors.enabled -}} +# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.87.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -7,8 +8,8 @@ metadata: {{- with .Values.annotations }} {{- toYaml . | nindent 4 }} {{- end }} - controller-gen.kubebuilder.io/version: v0.17.2 - operator.prometheus.io/version: 0.81.0 + controller-gen.kubebuilder.io/version: v0.19.0 + operator.prometheus.io/version: 0.87.0 name: servicemonitors.monitoring.coreos.com spec: group: monitoring.coreos.com @@ -55,19 +56,19 @@ spec: type: object spec: description: |- - Specification of desired Service selection for target discovery by + spec defines the specification of desired Service selection for target discovery by Prometheus. properties: attachMetadata: description: |- - `attachMetadata` defines additional metadata which is added to the + attachMetadata defines additional metadata which is added to the discovered targets. It requires Prometheus >= v2.37.0. properties: node: description: |- - When set to true, Prometheus attaches node metadata to the discovered + node when set to true, Prometheus attaches node metadata to the discovered targets. The Prometheus service account must have the `list` and `watch` @@ -76,15 +77,20 @@ spec: type: object bodySizeLimit: description: |- - When defined, bodySizeLimit specifies a job level limit on the size + bodySizeLimit when defined, bodySizeLimit specifies a job level limit on the size of uncompressed response body that will be accepted by Prometheus. It requires Prometheus >= v2.28.0. pattern: (^0|([0-9]*[.])?[0-9]+((K|M|G|T|E|P)i?)?B)$ type: string + convertClassicHistogramsToNHCB: + description: |- + convertClassicHistogramsToNHCB defines whether to convert all scraped classic histograms into a native histogram with custom buckets. + It requires Prometheus >= v3.0.0. + type: boolean endpoints: description: |- - List of endpoints part of this ServiceMonitor. + endpoints defines the list of endpoints part of this ServiceMonitor. Defines how to scrape metrics from Kubernetes [Endpoints](https://kubernetes.io/docs/concepts/services-networking/service/#endpoints) objects. In most cases, an Endpoints object is backed by a Kubernetes [Service](https://kubernetes.io/docs/concepts/services-networking/service/) object with the same name and labels. items: @@ -94,14 +100,14 @@ spec: properties: authorization: description: |- - `authorization` configures the Authorization header credentials to use when + authorization configures the Authorization header credentials to use when scraping the target. Cannot be set at the same time as `basicAuth`, or `oauth2`. properties: credentials: - description: Selects a key of a Secret in the namespace - that contains the credentials for authentication. + description: credentials defines a key of a Secret in the + namespace that contains the credentials for authentication. properties: key: description: The key of the secret to select from. Must @@ -126,7 +132,7 @@ spec: x-kubernetes-map-type: atomic type: description: |- - Defines the authentication type. The value is case-insensitive. + type defines the authentication type. The value is case-insensitive. "Basic" is not a supported value. @@ -135,14 +141,14 @@ spec: type: object basicAuth: description: |- - `basicAuth` configures the Basic Authentication credentials to use when + basicAuth defines the Basic Authentication credentials to use when scraping the target. Cannot be set at the same time as `authorization`, or `oauth2`. properties: password: description: |- - `password` specifies a key of a Secret containing the password for + password defines a key of a Secret containing the password for authentication. properties: key: @@ -168,7 +174,7 @@ spec: x-kubernetes-map-type: atomic username: description: |- - `username` specifies a key of a Secret containing the username for + username defines a key of a Secret containing the username for authentication. properties: key: @@ -195,13 +201,13 @@ spec: type: object bearerTokenFile: description: |- - File to read bearer token for scraping the target. + bearerTokenFile defines the file to read bearer token for scraping the target. Deprecated: use `authorization` instead. type: string bearerTokenSecret: description: |- - `bearerTokenSecret` specifies a key of a Secret containing the bearer + bearerTokenSecret defines a key of a Secret containing the bearer token for scraping targets. The secret needs to be in the same namespace as the ServiceMonitor object and readable by the Prometheus Operator. @@ -229,12 +235,12 @@ spec: type: object x-kubernetes-map-type: atomic enableHttp2: - description: '`enableHttp2` can be used to disable HTTP2 when - scraping the target.' + description: enableHttp2 can be used to disable HTTP2 when scraping + the target. type: boolean filterRunning: description: |- - When true, the pods which are not running (e.g. either in Failed or + filterRunning when true, the pods which are not running (e.g. either in Failed or Succeeded state) are dropped during the target discovery. If unset, the filtering is enabled. @@ -243,29 +249,29 @@ spec: type: boolean followRedirects: description: |- - `followRedirects` defines whether the scrape requests should follow HTTP + followRedirects defines whether the scrape requests should follow HTTP 3xx redirects. type: boolean honorLabels: description: |- - When true, `honorLabels` preserves the metric's labels when they collide + honorLabels defines when true the metric's labels when they collide with the target's labels. type: boolean honorTimestamps: description: |- - `honorTimestamps` controls whether Prometheus preserves the timestamps + honorTimestamps defines whether Prometheus preserves the timestamps when exposed by the target. type: boolean interval: description: |- - Interval at which Prometheus scrapes the metrics from the target. + interval at which Prometheus scrapes the metrics from the target. If empty, Prometheus uses the global scrape interval. pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ type: string metricRelabelings: description: |- - `metricRelabelings` configures the relabeling rules to apply to the + metricRelabelings defines the relabeling rules to apply to the samples before ingestion. items: description: |- @@ -277,7 +283,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -309,41 +315,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -352,9 +358,17 @@ spec: type: string type: object type: array + noProxy: + description: |- + noProxy defines a comma-separated string that can contain IPs, CIDR notation, domain names + that should be excluded from proxying. IP and domain names can + contain port numbers. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: string oauth2: description: |- - `oauth2` configures the OAuth2 settings to use when scraping the target. + oauth2 defines the OAuth2 settings to use when scraping the target. It requires Prometheus >= 2.27.0. @@ -362,12 +376,12 @@ spec: properties: clientId: description: |- - `clientId` specifies a key of a Secret or ConfigMap containing the + clientId defines a key of a Secret or ConfigMap containing the OAuth2 client's ID. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -390,7 +404,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -416,7 +431,7 @@ spec: type: object clientSecret: description: |- - `clientSecret` specifies a key of a Secret containing the OAuth2 + clientSecret defines a key of a Secret containing the OAuth2 client's secret. properties: key: @@ -444,16 +459,16 @@ spec: additionalProperties: type: string description: |- - `endpointParams` configures the HTTP parameters to append to the token + endpointParams configures the HTTP parameters to append to the token URL. type: object noProxy: description: |- - `noProxy` is a comma-separated string that can contain IPs, CIDR notation, domain names + noProxy defines a comma-separated string that can contain IPs, CIDR notation, domain names that should be excluded from proxying. IP and domain names can contain port numbers. - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: string proxyConnectHeader: additionalProperties: @@ -483,41 +498,40 @@ spec: x-kubernetes-map-type: atomic type: array description: |- - ProxyConnectHeader optionally specifies headers to send to + proxyConnectHeader optionally specifies headers to send to proxies during CONNECT requests. - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: object x-kubernetes-map-type: atomic proxyFromEnvironment: description: |- - Whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). + proxyFromEnvironment defines whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). - It requires Prometheus >= v2.43.0 or Alertmanager >= 0.25.0. + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. type: boolean proxyUrl: - description: '`proxyURL` defines the HTTP proxy server to - use.' - pattern: ^http(s)?://.+$ + description: proxyUrl defines the HTTP proxy server to use. + pattern: ^(http|https|socks5)://.+$ type: string scopes: - description: '`scopes` defines the OAuth2 scopes used for - the token request.' + description: scopes defines the OAuth2 scopes used for the + token request. items: type: string type: array tlsConfig: description: |- - TLS configuration to use when connecting to the OAuth2 server. + tlsConfig defines the TLS configuration to use when connecting to the OAuth2 server. It requires Prometheus >= v2.43.0. properties: ca: - description: Certificate authority used when verifying - server certificates. + description: ca defines the Certificate authority used + when verifying server certificates. properties: configMap: - description: ConfigMap containing data to use for - the targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -540,8 +554,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the - targets. + description: secret defines the Secret containing + data to use for the targets. properties: key: description: The key of the secret to select @@ -566,12 +580,12 @@ spec: x-kubernetes-map-type: atomic type: object cert: - description: Client certificate to present when doing - client-authentication. + description: cert defines the Client certificate to + present when doing client-authentication. properties: configMap: - description: ConfigMap containing data to use for - the targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -594,8 +608,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the - targets. + description: secret defines the Secret containing + data to use for the targets. properties: key: description: The key of the secret to select @@ -620,11 +634,12 @@ spec: x-kubernetes-map-type: atomic type: object insecureSkipVerify: - description: Disable target certificate validation. + description: insecureSkipVerify defines how to disable + target certificate validation. type: boolean keySecret: - description: Secret containing the client key file for - the targets. + description: keySecret defines the Secret containing + the client key file for the targets. properties: key: description: The key of the secret to select from. Must @@ -649,9 +664,9 @@ spec: x-kubernetes-map-type: atomic maxVersion: description: |- - Maximum acceptable TLS version. + maxVersion defines the maximum acceptable TLS version. - It requires Prometheus >= v2.41.0. + It requires Prometheus >= v2.41.0 or Thanos >= v0.31.0. enum: - TLS10 - TLS11 @@ -660,9 +675,9 @@ spec: type: string minVersion: description: |- - Minimum acceptable TLS version. + minVersion defines the minimum acceptable TLS version. - It requires Prometheus >= v2.35.0. + It requires Prometheus >= v2.35.0 or Thanos >= v0.28.0. enum: - TLS10 - TLS11 @@ -670,12 +685,13 @@ spec: - TLS13 type: string serverName: - description: Used to verify the hostname for the targets. + description: serverName is used to verify the hostname + for the targets. type: string type: object tokenUrl: - description: '`tokenURL` configures the URL to fetch the - token from.' + description: tokenUrl defines the URL to fetch the token + from. minLength: 1 type: string required: @@ -692,24 +708,63 @@ spec: type: object path: description: |- - HTTP path from which to scrape for metrics. + path defines the HTTP path from which to scrape for metrics. If empty, Prometheus uses the default value (e.g. `/metrics`). type: string port: description: |- - Name of the Service port which this endpoint refers to. + port defines the name of the Service port which this endpoint refers to. It takes precedence over `targetPort`. type: string - proxyUrl: + proxyConnectHeader: + additionalProperties: + items: + description: SecretKeySelector selects a key of a Secret. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: array description: |- - `proxyURL` configures the HTTP Proxy URL (e.g. - "http://proxyserver:2195") to go through when scraping the target. + proxyConnectHeader optionally specifies headers to send to + proxies during CONNECT requests. + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: object + x-kubernetes-map-type: atomic + proxyFromEnvironment: + description: |- + proxyFromEnvironment defines whether to use the proxy configuration defined by environment variables (HTTP_PROXY, HTTPS_PROXY, and NO_PROXY). + + It requires Prometheus >= v2.43.0, Alertmanager >= v0.25.0 or Thanos >= v0.32.0. + type: boolean + proxyUrl: + description: proxyUrl defines the HTTP proxy server to use. + pattern: ^(http|https|socks5)://.+$ type: string relabelings: description: |- - `relabelings` configures the relabeling rules to apply the target's + relabelings defines the relabeling rules to apply the target's metadata labels. The Operator automatically adds relabelings for a few standard Kubernetes fields. @@ -727,7 +782,7 @@ spec: action: default: replace description: |- - Action to perform based on the regex matching. + action to perform based on the regex matching. `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. @@ -759,41 +814,41 @@ spec: type: string modulus: description: |- - Modulus to take of the hash of the source label values. + modulus to take of the hash of the source label values. Only applicable when the action is `HashMod`. format: int64 type: integer regex: - description: Regular expression against which the extracted - value is matched. + description: regex defines the regular expression against + which the extracted value is matched. type: string replacement: description: |- - Replacement value against which a Replace action is performed if the + replacement value against which a Replace action is performed if the regular expression matches. Regex capture groups are available. type: string separator: - description: Separator is the string between concatenated + description: separator defines the string between concatenated SourceLabels. type: string sourceLabels: description: |- - The source labels select values from existing labels. Their content is + sourceLabels defines the source labels select values from existing labels. Their content is concatenated using the configured Separator and matched against the configured regular expression. items: description: |- - LabelName is a valid Prometheus label name which may only contain ASCII - letters, numbers, as well as underscores. - pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + LabelName is a valid Prometheus label name. + For Prometheus 3.x, a label name is valid if it contains UTF-8 characters. + For Prometheus 2.x, a label name is only valid if it contains ASCII characters, letters, numbers, as well as underscores. type: string type: array targetLabel: description: |- - Label to which the resulting string is written in a replacement. + targetLabel defines the label to which the resulting string is written in a replacement. It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, `KeepEqual` and `DropEqual` actions. @@ -803,20 +858,17 @@ spec: type: object type: array scheme: - description: |- - HTTP scheme to use for scraping. - - `http` and `https` are the expected values unless you rewrite the - `__scheme__` label via relabeling. - - If empty, Prometheus uses the default value `http`. + description: scheme defines the HTTP scheme to use when scraping + the metrics. enum: - http - https + - HTTP + - HTTPS type: string scrapeTimeout: description: |- - Timeout after which Prometheus considers the scrape to be failed. + scrapeTimeout defines the timeout after which Prometheus considers the scrape to be failed. If empty, Prometheus uses the global scrape timeout unless it is less than the target's scrape interval value in which the latter is used. @@ -828,19 +880,20 @@ spec: - type: integer - type: string description: |- - Name or number of the target port of the `Pod` object behind the + targetPort defines the name or number of the target port of the `Pod` object behind the Service. The port must be specified with the container's port property. x-kubernetes-int-or-string: true tlsConfig: - description: TLS configuration to use when scraping the target. + description: tlsConfig defines the TLS configuration to use + when scraping the target. properties: ca: - description: Certificate authority used when verifying server - certificates. + description: ca defines the Certificate authority used when + verifying server certificates. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -863,7 +916,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -888,15 +942,16 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the Prometheus container - to use for the targets. + description: caFile defines the path to the CA cert in the + Prometheus container to use for the targets. type: string cert: - description: Client certificate to present when doing client-authentication. + description: cert defines the Client certificate to present + when doing client-authentication. properties: configMap: - description: ConfigMap containing data to use for the - targets. + description: configMap defines the ConfigMap containing + data to use for the targets. properties: key: description: The key to select. @@ -919,7 +974,8 @@ spec: type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. + description: secret defines the Secret containing data + to use for the targets. properties: key: description: The key of the secret to select from. Must @@ -944,19 +1000,20 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the Prometheus - container for the targets. + description: certFile defines the path to the client cert + file in the Prometheus container for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. + description: insecureSkipVerify defines how to disable target + certificate validation. type: boolean keyFile: - description: Path to the client key file in the Prometheus - container for the targets. + description: keyFile defines the path to the client key + file in the Prometheus container for the targets. type: string keySecret: - description: Secret containing the client key file for the - targets. + description: keySecret defines the Secret containing the + client key file for the targets. properties: key: description: The key of the secret to select from. Must @@ -981,9 +1038,9 @@ spec: x-kubernetes-map-type: atomic maxVersion: description: |- - Maximum acceptable TLS version. + maxVersion defines the maximum acceptable TLS version. - It requires Prometheus >= v2.41.0. + It requires Prometheus >= v2.41.0 or Thanos >= v0.31.0. enum: - TLS10 - TLS11 @@ -992,9 +1049,9 @@ spec: type: string minVersion: description: |- - Minimum acceptable TLS version. + minVersion defines the minimum acceptable TLS version. - It requires Prometheus >= v2.35.0. + It requires Prometheus >= v2.35.0 or Thanos >= v0.28.0. enum: - TLS10 - TLS11 @@ -1002,12 +1059,13 @@ spec: - TLS13 type: string serverName: - description: Used to verify the hostname for the targets. + description: serverName is used to verify the hostname for + the targets. type: string type: object trackTimestampsStaleness: description: |- - `trackTimestampsStaleness` defines whether Prometheus tracks staleness of + trackTimestampsStaleness defines whether Prometheus tracks staleness of the metrics that have an explicit timestamp present in scraped data. Has no effect if `honorTimestamps` is false. @@ -1017,7 +1075,7 @@ spec: type: array fallbackScrapeProtocol: description: |- - The protocol to use if a scrape returns blank, unparseable, or otherwise invalid Content-Type. + fallbackScrapeProtocol defines the protocol to use if a scrape returns blank, unparseable, or otherwise invalid Content-Type. It requires Prometheus >= v3.0.0. enum: @@ -1029,7 +1087,7 @@ spec: type: string jobLabel: description: |- - `jobLabel` selects the label from the associated Kubernetes `Service` + jobLabel selects the label from the associated Kubernetes `Service` object which will be used as the `job` label for all metrics. For example if `jobLabel` is set to `foo` and the Kubernetes `Service` @@ -1042,7 +1100,7 @@ spec: type: string keepDroppedTargets: description: |- - Per-scrape limit on the number of targets dropped by relabeling + keepDroppedTargets defines the per-scrape limit on the number of targets dropped by relabeling that will be kept in memory. 0 means no limit. It requires Prometheus >= v2.47.0. @@ -1050,44 +1108,45 @@ spec: type: integer labelLimit: description: |- - Per-scrape limit on number of labels that will be accepted for a sample. + labelLimit defines the per-scrape limit on number of labels that will be accepted for a sample. It requires Prometheus >= v2.27.0. format: int64 type: integer labelNameLengthLimit: description: |- - Per-scrape limit on length of labels name that will be accepted for a sample. + labelNameLengthLimit defines the per-scrape limit on length of labels name that will be accepted for a sample. It requires Prometheus >= v2.27.0. format: int64 type: integer labelValueLengthLimit: description: |- - Per-scrape limit on length of labels value that will be accepted for a sample. + labelValueLengthLimit defines the per-scrape limit on length of labels value that will be accepted for a sample. It requires Prometheus >= v2.27.0. format: int64 type: integer namespaceSelector: description: |- - `namespaceSelector` defines in which namespace(s) Prometheus should discover the services. + namespaceSelector defines in which namespace(s) Prometheus should discover the services. By default, the services are discovered in the same namespace as the `ServiceMonitor` object but it is possible to select pods across different/all namespaces. properties: any: description: |- - Boolean describing whether all namespaces are selected in contrast to a + any defines the boolean describing whether all namespaces are selected in contrast to a list restricting them. type: boolean matchNames: - description: List of namespace names to select from. + description: matchNames defines the list of namespace names to + select from. items: type: string type: array type: object nativeHistogramBucketLimit: description: |- - If there are more than this many buckets in a native histogram, + nativeHistogramBucketLimit defines ff there are more than this many buckets in a native histogram, buckets will be merged to stay within the limit. It requires Prometheus >= v2.45.0. format: int64 @@ -1097,36 +1156,38 @@ spec: - type: integer - type: string description: |- - If the growth factor of one bucket to the next is smaller than this, + nativeHistogramMinBucketFactor defines if the growth factor of one bucket to the next is smaller than this, buckets will be merged to increase the factor sufficiently. It requires Prometheus >= v2.50.0. pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true podTargetLabels: description: |- - `podTargetLabels` defines the labels which are transferred from the + podTargetLabels defines the labels which are transferred from the associated Kubernetes `Pod` object onto the ingested metrics. items: type: string type: array sampleLimit: description: |- - `sampleLimit` defines a per-scrape limit on the number of scraped samples + sampleLimit defines a per-scrape limit on the number of scraped samples that will be accepted. format: int64 type: integer scrapeClass: - description: The scrape class to apply. + description: scrapeClass defines the scrape class to apply. minLength: 1 type: string scrapeClassicHistograms: description: |- - Whether to scrape a classic histogram that is also exposed as a native histogram. + scrapeClassicHistograms defines whether to scrape a classic histogram that is also exposed as a native histogram. It requires Prometheus >= v2.45.0. + + Notice: `scrapeClassicHistograms` corresponds to the `always_scrape_classic_histograms` field in the Prometheus configuration. type: boolean scrapeProtocols: description: |- - `scrapeProtocols` defines the protocols to negotiate during a scrape. It tells clients the + scrapeProtocols defines the protocols to negotiate during a scrape. It tells clients the protocols supported by Prometheus in order of preference (from most to least preferred). If unset, Prometheus uses its default value. @@ -1151,8 +1212,8 @@ spec: type: array x-kubernetes-list-type: set selector: - description: Label selector to select the Kubernetes `Endpoints` objects - to scrape metrics from. + description: selector defines the label selector to select the Kubernetes + `Endpoints` objects to scrape metrics from. properties: matchExpressions: description: matchExpressions is a list of label selector requirements. @@ -1199,7 +1260,7 @@ spec: x-kubernetes-map-type: atomic selectorMechanism: description: |- - Mechanism used to select the endpoints to scrape. + selectorMechanism defines the mechanism used to select the endpoints to scrape. By default, the selection process relies on relabel configurations to filter the discovered targets. Alternatively, you can opt in for role selectors, which may offer better efficiency in large clusters. Which strategy is best for your use case needs to be carefully evaluated. @@ -1209,16 +1270,27 @@ spec: - RelabelConfig - RoleSelector type: string + serviceDiscoveryRole: + description: |- + serviceDiscoveryRole defines the service discovery role used to discover targets. + + If set, the value should be either "Endpoints" or "EndpointSlice". + Otherwise it defaults to the value defined in the + Prometheus/PrometheusAgent resource. + enum: + - Endpoints + - EndpointSlice + type: string targetLabels: description: |- - `targetLabels` defines the labels which are transferred from the + targetLabels defines the labels which are transferred from the associated Kubernetes `Service` object onto the ingested metrics. items: type: string type: array targetLimit: description: |- - `targetLimit` defines a limit on the number of scraped targets that will + targetLimit defines a limit on the number of scraped targets that will be accepted. format: int64 type: integer @@ -1226,8 +1298,114 @@ spec: - endpoints - selector type: object + status: + description: |- + status defines the status subresource. It is under active development and is updated only when the + "StatusForConfigurationResources" feature gate is enabled. + + Most recent observed status of the ServiceMonitor. Read-only. + More info: + https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + bindings: + description: bindings defines the list of workload resources (Prometheus, + PrometheusAgent, ThanosRuler or Alertmanager) which select the configuration + resource. + items: + description: WorkloadBinding is a link between a configuration resource + and a workload resource. + properties: + conditions: + description: conditions defines the current state of the configuration + resource when bound to the referenced Workload object. + items: + description: ConfigResourceCondition describes the status + of configuration resources linked to Prometheus, PrometheusAgent, + Alertmanager or ThanosRuler. + properties: + lastTransitionTime: + description: lastTransitionTime defines the time of the + last update to the current status property. + format: date-time + type: string + message: + description: message defines the human-readable message + indicating details for the condition's last transition. + type: string + observedGeneration: + description: |- + observedGeneration defines the .metadata.generation that the + condition was set based upon. For instance, if `.metadata.generation` is + currently 12, but the `.status.conditions[].observedGeneration` is 9, the + condition is out of date with respect to the current state of the object. + format: int64 + type: integer + reason: + description: reason for the condition's last transition. + type: string + status: + description: status of the condition. + minLength: 1 + type: string + type: + description: |- + type of the condition being reported. + Currently, only "Accepted" is supported. + enum: + - Accepted + minLength: 1 + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + group: + description: group defines the group of the referenced resource. + enum: + - monitoring.coreos.com + type: string + name: + description: name defines the name of the referenced object. + minLength: 1 + type: string + namespace: + description: namespace defines the namespace of the referenced + object. + minLength: 1 + type: string + resource: + description: resource defines the type of resource being referenced + (e.g. Prometheus, PrometheusAgent, ThanosRuler or Alertmanager). + enum: + - prometheuses + - prometheusagents + - thanosrulers + - alertmanagers + type: string + required: + - group + - name + - namespace + - resource + type: object + type: array + x-kubernetes-list-map-keys: + - group + - resource + - name + - namespace + x-kubernetes-list-type: map + type: object required: - spec type: object served: true storage: true + subresources: + status: {} +{{- end -}} diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/ci/lint.sh b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/ci/lint.sh similarity index 100% rename from packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/ci/lint.sh rename to packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/ci/lint.sh diff --git a/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/hack/renovate-post-upgrade-hook.sh b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/hack/renovate-post-upgrade-hook.sh new file mode 100644 index 00000000..f7f3c35d --- /dev/null +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/hack/renovate-post-upgrade-hook.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${0}")" &>/dev/null && pwd)" + +"${SCRIPT_DIR}/update_crds.sh" diff --git a/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/hack/update_crds.sh b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/hack/update_crds.sh new file mode 100644 index 00000000..bfa576de --- /dev/null +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/hack/update_crds.sh @@ -0,0 +1,51 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) + +if [[ $(uname -s) = "Darwin" ]]; then + VERSION="$(grep ^appVersion "${SCRIPT_DIR}/../Chart.yaml" | sed 's/appVersion: //g')" +else + VERSION="$(grep ^appVersion "${SCRIPT_DIR}/../Chart.yaml" | sed 's/appVersion:\s//g')" +fi + +CRDS=( + "alertmanagerconfigs : monitoring.coreos.com_alertmanagerconfigs.yaml" + "alertmanagers : monitoring.coreos.com_alertmanagers.yaml" + "podmonitors : monitoring.coreos.com_podmonitors.yaml" + "probes : monitoring.coreos.com_probes.yaml" + "prometheusagents : monitoring.coreos.com_prometheusagents.yaml" + "prometheuses : monitoring.coreos.com_prometheuses.yaml" + "prometheusrules : monitoring.coreos.com_prometheusrules.yaml" + "scrapeconfigs : monitoring.coreos.com_scrapeconfigs.yaml" + "servicemonitors : monitoring.coreos.com_servicemonitors.yaml" + "thanosrulers : monitoring.coreos.com_thanosrulers.yaml" +) + +for line in "${CRDS[@]}"; do + CRD=$(echo "${line%%:*}" | xargs) + SOURCE=$(echo "${line##*:}" | xargs) + DESTINATION="crd-${CRD}".yaml + + URL="https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/$VERSION/example/prometheus-operator-crd/$SOURCE" + + echo -e "Downloading Prometheus Operator CRD with Version ${VERSION}:\n${URL}\n" + + echo "# ${URL}" >"${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" + + if ! curl --silent --retry-all-errors --fail --location "${URL}" >>"${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}"; then + echo -e "Failed to download ${URL}!" + exit 1 + fi + + # Update or insert annotations block + if yq -e '.metadata.annotations' "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" >/dev/null; then + sed -i '/^ annotations:$/a {{- with .Values.annotations }}\n{{- toYaml . | nindent 4 }}\n{{- end }}' "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" + else + sed -i '/^metadata:$/a {{- with .Values.annotations }}\n annotations:\n{{- toYaml . | nindent 4 }}\n{{- end }}' "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" + fi + + # Insert enable option + sed -i "1i\{{- if .Values.${CRD}.enabled -}}" "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" + echo "{{- end -}}" >>"${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" +done diff --git a/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/values.yaml b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/values.yaml new file mode 100644 index 00000000..f462daf0 --- /dev/null +++ b/packages/system/prometheus-operator-crds/charts/prometheus-operator-crds/values.yaml @@ -0,0 +1,55 @@ +## Settings for CRDs +## +crds: + ## annotations add additional annotations to all CRDs + annotations: {} + + ## alertmanagerconfigs configures the AlertManagerConfig CRD + alertmanagerconfigs: + ## enabled defines if the CRD should be installed + enabled: true + + ## alertmanagers configures the AlertManager CRD + alertmanagers: + ## enabled defines if the CRD should be installed + enabled: true + + ## podmonitors configures the PodMonitor CRD + podmonitors: + ## enabled defines if the CRD should be installed + enabled: true + + ## probes configures the Probe CRD + probes: + ## enabled defines if the CRD should be installed + enabled: true + + ## prometheusagents configures the PrometheusAgent CRD + prometheusagents: + ## enabled defines if the CRD should be installed + enabled: true + + ## prometheuses configures the Prometheus CRD + prometheuses: + ## enabled defines if the CRD should be installed + enabled: true + + ## prometheusrules configures the PrometheusRule CRD + prometheusrules: + ## enabled defines if the CRD should be installed + enabled: true + + ## prometheusrules configures the PrometheusRule CRD + scrapeconfigs: + ## enabled defines if the CRD should be installed + enabled: true + + ## servicemonitors configures the ServiceMonitor CRD + servicemonitors: + ## enabled defines if the CRD should be installed + enabled: true + + ## thanosrulers configures the ThanosRuler CRD + thanosrulers: + ## enabled defines if the CRD should be installed + enabled: true diff --git a/packages/system/prometheus-operator-crds/values.yaml b/packages/system/prometheus-operator-crds/values.yaml new file mode 100644 index 00000000..e69de29b diff --git a/packages/system/qdrant-rd/Chart.yaml b/packages/system/qdrant-rd/Chart.yaml new file mode 100644 index 00000000..e4d7beb2 --- /dev/null +++ b/packages/system/qdrant-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: qdrant-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/qdrant-rd/Makefile b/packages/system/qdrant-rd/Makefile new file mode 100644 index 00000000..0b22a9ca --- /dev/null +++ b/packages/system/qdrant-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=qdrant-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/qdrant-rd/cozyrds/qdrant.yaml b/packages/system/qdrant-rd/cozyrds/qdrant.yaml new file mode 100644 index 00000000..37a695f0 --- /dev/null +++ b/packages/system/qdrant-rd/cozyrds/qdrant.yaml @@ -0,0 +1,41 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: qdrant +spec: + application: + kind: Qdrant + plural: qdrants + singular: qdrant + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of Qdrant replicas. Cluster mode is automatically enabled when replicas > 1.","type":"integer","default":1},"resources":{"description":"Explicit CPU and memory configuration for each Qdrant replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for vector data storage.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false}}} + release: + prefix: qdrant- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-qdrant-application-default-qdrant + namespace: cozy-system + dashboard: + description: Managed Qdrant vector database service + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcikiLz4KPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjIsIDIyKSBzY2FsZSgwLjU4KSI+CiAgPHBvbHlnb24gZmlsbD0iI2RjMjQ0YyIgcG9pbnRzPSI4Ni42IDAgMCA1MCAwIDE1MCA4Ni42IDIwMCAxMTkuMDggMTgxLjI1IDExOS4wOCAxNDMuNzUgODYuNiAxNjIuNSAzMi40OCAxMzEuMjUgMzIuNDggNjguNzUgODYuNiAzNy41IDE0MC43MyA2OC43NSAxNDAuNzMgMTkzLjc1IDE3My4yMSAxNzUgMTczLjIxIDUwIDg2LjYgMCIvPgogIDxwb2x5Z29uIGZpbGw9IiNkYzI0NGMiIHBvaW50cz0iNTQuMTMgODEuMjUgNTQuMTMgMTE4Ljc1IDg2LjYgMTM3LjUgMTE5LjA4IDExOC43NSAxMTkuMDggODEuMjUgODYuNiA2Mi41IDU0LjEzIDgxLjI1Ii8+CiAgPHBvbHlnb24gZmlsbD0iIzllMGQzOCIgcG9pbnRzPSIxMTkuMDggMTQzLjc1IDExOS4wOCAxODEuMjUgODYuNiAyMDAgODYuNiAxNjIuNSAxMTkuMDggMTQzLjc1Ii8+CiAgPHBvbHlnb24gZmlsbD0iIzllMGQzOCIgcG9pbnRzPSIxNzMuMjEgNTAgMTczLjIxIDE3NSAxNDAuNzMgMTkzLjc1IDE0MC43MyA2OC43NSAxNzMuMjEgNTAiLz4KICA8cG9seWdvbiBmaWxsPSIjZmY1MTZiIiBwb2ludHM9IjE3My4yMSA1MCAxNDAuNzMgNjguNzUgODYuNiAzNy41IDMyLjQ4IDY4Ljc1IDAgNTAgODYuNiAwIDE3My4yMSA1MCIvPgogIDxwb2x5Z29uIGZpbGw9IiNkYzI0NGMiIHBvaW50cz0iODYuNiAxNjIuNSA4Ni42IDIwMCAwIDE1MCAwIDUwIDMyLjQ4IDY4Ljc1IDMyLjQ4IDEzMS4yNSA4Ni42IDE2Mi41Ii8+CiAgPHBvbHlnb24gZmlsbD0iI2ZmNTE2YiIgcG9pbnRzPSIxMTkuMDggODEuMjUgODYuNiAxMDAgNTQuMTMgODEuMjUgODYuNiA2Mi41IDExOS4wOCA4MS4yNSIvPgogIDxwb2x5Z29uIGZpbGw9IiNkYzI0NGMiIHBvaW50cz0iODYuNiAxMDAgODYuNiAxMzcuNSA1NC4xMyAxMTguNzUgNTQuMTMgODEuMjUgODYuNiAxMDAiLz4KICA8cG9seWdvbiBmaWxsPSIjOWUwZDM4IiBwb2ludHM9IjExOS4wOCA4MS4yNSAxMTkuMDggMTE4Ljc1IDg2LjYgMTM3LjUgODYuNiAxMDAgMTE5LjA4IDgxLjI1Ii8+CjwvZz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhciIgeDE9IjE4OSIgeTE9IjIxMC41IiB4Mj0iMCIgeTI9IjAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iIzVjMDUyMCIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNmZmQwZDgiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K + category: PaaS + singular: Qdrant + plural: Qdrant + tags: + - vector-database + - ai + - ml + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"]] + secrets: + exclude: [] + include: + - resourceNames: + - qdrant-{{ .name }}-apikey + services: + exclude: [] + include: + - resourceNames: + - qdrant-{{ .name }} + - qdrant-{{ .name }}-headless diff --git a/packages/system/qdrant-rd/templates/cozyrd.yaml b/packages/system/qdrant-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/qdrant-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/qdrant-rd/values.yaml b/packages/system/qdrant-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/qdrant-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/qdrant/Chart.yaml b/packages/system/qdrant/Chart.yaml new file mode 100644 index 00000000..ef927c65 --- /dev/null +++ b/packages/system/qdrant/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-qdrant +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/qdrant/Makefile b/packages/system/qdrant/Makefile new file mode 100644 index 00000000..7e6fbe93 --- /dev/null +++ b/packages/system/qdrant/Makefile @@ -0,0 +1,7 @@ +include ../../../hack/package.mk + +update: + rm -rf charts + helm repo add qdrant https://qdrant.github.io/qdrant-helm + helm repo update qdrant + helm pull qdrant/qdrant --untar --untardir charts diff --git a/packages/system/qdrant/charts/qdrant/.helmignore b/packages/system/qdrant/charts/qdrant/.helmignore new file mode 100644 index 00000000..f4b11987 --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/.helmignore @@ -0,0 +1,2 @@ +.git +.github diff --git a/packages/system/qdrant/charts/qdrant/CHANGELOG.md b/packages/system/qdrant/charts/qdrant/CHANGELOG.md new file mode 100644 index 00000000..7d985e71 --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog + +## [qdrant-1.16.3](https://github.com/qdrant/qdrant-helm/tree/qdrant-1.16.3) (2025-12-19) + +- Update Qdrant to v1.16.3 +- Add support for global additional labels [#424](https://github.com/qdrant/qdrant-helm/pull/424) +- Add support for setting persistent volume claim labels [#418](https://github.com/qdrant/qdrant-helm/pull/418) +- Add the ability to set minReadySecond [#417](https://github.com/qdrant/qdrant-helm/pull/417) diff --git a/packages/system/qdrant/charts/qdrant/Chart.yaml b/packages/system/qdrant/charts/qdrant/Chart.yaml new file mode 100644 index 00000000..03227eff --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/Chart.yaml @@ -0,0 +1,37 @@ +annotations: + artifacthub.io/category: database + artifacthub.io/changes: | + - kind: added + description: Update Qdrant to v1.16.3 + - kind: added + description: Add support for global additional labels + links: + - name: GitHub Pull Request + url: https://github.com/qdrant/qdrant-helm/pull/424 + - kind: added + description: Add support for setting persistent volume claim labels + links: + - name: GitHub Pull Request + url: https://github.com/qdrant/qdrant-helm/pull/418 + - kind: fixed + description: Add the ability to set minReadySecond + links: + - name: GitHub Pull Request + url: https://github.com/qdrant/qdrant-helm/pull/417 +apiVersion: v2 +appVersion: v1.16.3 +description: Qdrant - Vector Database for the next generation of AI applications. +home: https://qdrant.tech +icon: https://qdrant.github.io/qdrant-helm/logo_with_text.svg +keywords: +- vector database +maintainers: +- email: info@qdrant.com + name: qdrant + url: https://github.com/qdrant +name: qdrant +sources: +- https://github.com/qdrant/qdrant +- https://github.com/qdrant/qdrant-helm +type: application +version: 1.16.3 diff --git a/packages/system/qdrant/charts/qdrant/LICENSE b/packages/system/qdrant/charts/qdrant/LICENSE new file mode 100644 index 00000000..f49a4e16 --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/packages/system/qdrant/charts/qdrant/README.md b/packages/system/qdrant/charts/qdrant/README.md new file mode 100644 index 00000000..512eda17 --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/README.md @@ -0,0 +1,157 @@ +# Qdrant helm chart + +[Qdrant documentation](https://qdrant.tech/documentation/) + +## TLDR + +```bash +helm repo add qdrant https://qdrant.github.io/qdrant-helm +helm repo update +helm upgrade -i your-qdrant-installation-name qdrant/qdrant +``` + +## Description + +This chart installs and bootstraps a Qdrant instance. + +## Prerequisites + +- Kubernetes v1.24+ (as you need grpc probe) +- Helm +- PV provisioner (by the infrastructure) + +## Installation & Setup + +You can install the chart from source via: + +```bash +helm upgrade -i your-qdrant-installation-name charts/qdrant +``` + +Uninstall via: + +```bash +helm uninstall your-qdrant-installation-name +``` + +Delete the volume with + +```bash +kubectl delete pvc -l app.kubernetes.io/instance=your-qdrant-installation-name +``` + +## Configuration + +For documentation of the settings please refer to [Qdrant Configuration File](https://github.com/qdrant/qdrant/blob/master/config/config.yaml) +All of these configuration options could be overwritten under config in `values.yaml`. +A modification example is provided there. + +### Overrides + +You can override any value in the Qdrant configuration by setting the Helm values under the key `config`. Those settings get included verbatim in a file called `config/production.yml` which is explained further here [Qdrant Order and Priority](https://qdrant.tech/documentation/guides/configuration/#order-and-priority) as well as an [example](https://github.com/qdrant/qdrant-helm/blob/b0bb6fc6d3eb9c0813c79bb5a78dc21aebc2b81d/charts/qdrant/values.yaml#L140). + +### Distributed setup + +Running a distributed cluster just needs a few changes in your `values.yaml` file. +Increase the number of replicas to the desired number of nodes and set `config.cluster.enabled` to true. + +Depending on your environment or cloud provider you might need to change the service in the `values.yaml` as well. +For example on AWS EKS you would need to change the `cluster.type` to `NodePort`. + +## Updating StatefulSets + +This Helm chart uses a Kubernetes [StatefulSet](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/) to manage your Qdrant cluster. StatefulSets have many fields that are immutable, meaning that you cannot change these fields without deleting and recreating the StatefulSet. If you try to change these fields, you will get an error like this: + +``` +Error: UPGRADE FAILED: cannot patch "qdrant" with kind StatefulSet: StatefulSet.apps "qdrant" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'ordinals', 'template', 'updateStrategy', 'persistentVolumeClaimRetentionPolicy' and 'minReadySeconds' are forbidden +``` + +If you need to change any immutable field, the process is described below, using the most common example of expanding a PVC volume. + +1. Delete the StatefulSet while leaving the Pods running: + + ```bash + kubectl delete statefulset --cascade=orphan qdrant + ``` + +2. Manually edit all PersistentVolumeClaims to increase their sizes: + + ```bash + # For each PersistentVolumeClaim: + kubectl edit pvc qdrant-storage-qdrant-0 + ``` + +3. Update your Helm values to match the new PVC size. +4. Reinstall the Helm chart using your updated values: + + ```bash + helm upgrade --install qdrant qdrant/qdrant -f my-values.yaml + ``` + +Some storage providers allow resizing volumes in-place, but most require a pod restart before the new size will take effect: + +```bash +kubectl rollout restart statefulset qdrant +``` + +### Immutable Pod fields + +In addition to immutable fields on StatefulSets, Pods also have some fields which are immutable, which means the above method may not work for some changes, such as setting `snapshotPersistence.enabled: true`. In that case, after following the above method, you'll see an error like this when you `kubectl describe` your StatefulSet: + +``` +pod updates may not change fields other than `spec.containers[*].image`, +`spec.initContainers[*].image`,`spec.activeDeadlineSeconds`, +`spec.tolerations` (only additions to existing tolerations), +`spec.terminationGracePeriodSeconds` (allow it to be set to 1 if it was previously negative) +``` + +To fix this, you must manually delete all of your Qdrant pods, starting with node-0. This will cause your cluster to go down, but will allow the StatefulSet to recreate your Pods with the correct configuration. + +## Restoring from Snapshots + +This helm chart allows you to restore a snapshot into your Qdrant cluster either from an internal or external PersistentVolumeClaim. + +### Restoring from the built-in PVC + +If you have set `snapshotPersistence.enabled: true` (recommended for production), this helm chart will create a separate PersistentVolume for snapshots, and any snapshots you create will be stored in that PersistentVolume. + +To restore from one of these snapshots, set the following values: + +```yaml +snapshotRestoration: + enabled: true + # Set blank to indicate we are not using an external PVC + pvcName: "" + snapshots: + - /qdrant/snapshots///: +``` + +And run "helm upgrade". This will restart your cluster and restore the specified collection from the snapshot. Qdrant will refuse to overwrite an existing collection, so ensure the collection is deleted before restoring. + +After the snapshot is restored, remove the above values and run "helm upgrade" again to trigger another rolling restart. Otherwise, the snapshot restore will be attempted again if your cluster ever restarts. + +### Restoring from an external PVC + +If you wish to restore from an externally-created snapshot, using the API is recommended: https://qdrant.github.io/qdrant/redoc/index.html#tag/collections/operation/recover_from_uploaded_snapshot + +If the file is too large, you can separately create a PersistentVolumeClaim, store your data in there, and refer to this separate PersistentVolumeClaim in this helm chart. + +Once you have created this PersistentVolumeClaim (must be in the same namespace as your Qdrant cluster), set the following values: + +```yml +snapshotRestoration: + enabled: true + pvcName: "" + snapshots: + - /qdrant/snapshots///: +``` + +And run "helm upgrade". This will restart your cluster and restore the specified collection from the snapshot. Qdrant will refuse to overwrite an existing collection, so ensure the collection is deleted before restoring. + +After the snapshot is restored, remove the above values and run "helm upgrade" again to trigger another rolling restart. Otherwise, the snapshot restore will be attempted again if your cluster ever restarts. + +## Metrics endpoints + +Metrics are available through rest api (default port set to 6333) at `/metrics` + +Refer to [qdrant metrics configuration](https://qdrant.tech/documentation/telemetry/#metrics) for more information. diff --git a/packages/system/qdrant/charts/qdrant/templates/NOTES.txt b/packages/system/qdrant/charts/qdrant/templates/NOTES.txt new file mode 100644 index 00000000..450736c3 --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/templates/NOTES.txt @@ -0,0 +1,24 @@ +Qdrant {{ .Chart.AppVersion }} has been deployed successfully. + +The full Qdrant documentation is available at https://qdrant.tech/documentation/. + +To forward Qdrant's ports execute one of the following commands: + export POD_NAME=$(kubectl get pods --namespace {{ $.Release.Namespace }} -l "app.kubernetes.io/name={{ include "qdrant.name" . }},app.kubernetes.io/instance={{ $.Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + +{{- if contains "ClusterIP" .Values.service.type }} + {{- range .Values.service.ports }} + +If you want to use Qdrant via {{ .name }} execute the following commands + kubectl --namespace {{ $.Release.Namespace }} port-forward $POD_NAME {{ .targetPort }}:{{ .targetPort }} + {{- end }} +{{- end }} + +{{- if .Values.ingress.enabled }} + +If you want to access Qdrant through the ingress controller +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/qdrant/charts/qdrant/templates/_helpers.tpl b/packages/system/qdrant/charts/qdrant/templates/_helpers.tpl new file mode 100644 index 00000000..f45ce29c --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/templates/_helpers.tpl @@ -0,0 +1,145 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "qdrant.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "qdrant.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "qdrant.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "qdrant.labels" -}} +helm.sh/chart: {{ include "qdrant.chart" . }} +{{ include "qdrant.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "qdrant.selectorLabels" -}} +app: {{ include "qdrant.name" . }} +app.kubernetes.io/name: {{ include "qdrant.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Additional (global) labels +*/}} +{{- define "qdrant.additionalLabels" -}} +{{- with .Values.additionalLabels }} +{{- range $key, $value := . }} +{{ $key }}: {{ $value | quote }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "qdrant.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "qdrant.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Create secret +*/}} +{{- define "qdrant.secret" -}} +{{- $readOnlyApiKey := false }} +{{- $apiKey := false }} +{{- if kindIs "map" .Values.apiKey -}} +{{- if .Values.apiKey.valueFrom -}} +{{- /* Retrieve the value from the secret as specified in valueFrom */ -}} +{{- $secretName := .Values.apiKey.valueFrom.secretKeyRef.name -}} +{{- $secretKey := .Values.apiKey.valueFrom.secretKeyRef.key -}} +{{- $secretObj := (lookup "v1" "Secret" .Release.Namespace $secretName) | default dict -}} +{{- $secretData := (get $secretObj "data") | default dict -}} +{{- $apiKey = (get $secretData $secretKey | b64dec) -}} +{{- end -}} +{{- else if .Values.apiKey | toJson | eq "true" -}} +{{- /* Retrieve existing randomly generated api key or create a new one */ -}} +{{- $secretObj := (lookup "v1" "Secret" .Release.Namespace (printf "%s-apikey" (include "qdrant.fullname" . ))) | default dict -}} +{{- $secretData := (get $secretObj "data") | default dict -}} +{{- $apiKey = (get $secretData "api-key" | b64dec) | default (randAlphaNum 32) -}} +{{- else if .Values.apiKey -}} +{{- $apiKey = .Values.apiKey -}} +{{- end -}} +{{- if kindIs "map" .Values.readOnlyApiKey -}} +{{- if .Values.readOnlyApiKey.valueFrom -}} +{{- /* Retrieve the value from the secret as specified in valueFrom */ -}} +{{- $secretName := .Values.readOnlyApiKey.valueFrom.secretKeyRef.name -}} +{{- $secretKey := .Values.readOnlyApiKey.valueFrom.secretKeyRef.key -}} +{{- $secretObj := (lookup "v1" "Secret" .Release.Namespace $secretName) | default dict -}} +{{- $secretData := (get $secretObj "data") | default dict -}} +{{- $readOnlyApiKey = (get $secretData $secretKey | b64dec) -}} +{{- end -}} +{{- else if eq (.Values.readOnlyApiKey | toJson) "true" -}} +{{- /* retrieve existing randomly generated api key or create new one */ -}} +{{- $secretObj := (lookup "v1" "Secret" .Release.Namespace (printf "%s-apikey" (include "qdrant.fullname" . ))) | default dict -}} +{{- $secretData := (get $secretObj "data") | default dict -}} +{{- $readOnlyApiKey = (get $secretData "read-only-api-key" | b64dec) | default (randAlphaNum 32) -}} +{{- else if .Values.readOnlyApiKey -}} +{{- $readOnlyApiKey = .Values.readOnlyApiKey -}} +{{- end -}} +{{- if and $apiKey $readOnlyApiKey -}} +api-key: {{ $apiKey | b64enc }} +read-only-api-key: {{ $readOnlyApiKey | b64enc }} +local.yaml: {{ printf "service:\n api_key: %s\n read_only_api_key: %s" $apiKey $readOnlyApiKey | b64enc }} +{{- else if $apiKey -}} +api-key: {{ $apiKey | b64enc }} +local.yaml: {{ printf "service:\n api_key: %s" $apiKey | b64enc }} +{{- else if $readOnlyApiKey -}} +read-only-api-key: {{ $readOnlyApiKey | b64enc }} +local.yaml: {{ printf "service:\n read_only_api_key: %s" $readOnlyApiKey | b64enc }} +{{- end -}} +{{- end -}} + +{{/* +Protocol to use for inter cluster communication +*/}} +{{- define "qdrant.p2p.protocol" -}} +{{ if eq (.Values.config.cluster.p2p.enable_tls | toJson) "true" -}} +https +{{- else -}} +http +{{- end -}} +{{- end -}} + +{{/* +Port to use for inter cluster communication +*/}} +{{- define "qdrant.p2p.port" -}} +{{- default 6335 .Values.config.cluster.p2p.port -}} +{{- end -}} diff --git a/packages/system/qdrant/charts/qdrant/templates/configmap.yaml b/packages/system/qdrant/charts/qdrant/templates/configmap.yaml new file mode 100644 index 00000000..ea061b07 --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/templates/configmap.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "qdrant.fullname" . }} + labels: + {{- include "qdrant.labels" . | nindent 4 }} + {{- include "qdrant.additionalLabels" . | nindent 4 }} +{{- with .Values.additionalAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +data: + initialize.sh: | + #!/bin/sh + echo "Soft limits" + ulimit -a -S + echo "Hard limits" + ulimit -a -H + ulimit -n $(ulimit -Hn) + SET_INDEX=${HOSTNAME##*-} + {{- if and (.Values.snapshotRestoration.enabled) (eq (.Values.replicaCount | quote) (1 | quote)) }} + echo "Starting initializing for pod $SET_INDEX and snapshots restoration" + exec ./entrypoint.sh --uri '{{ include "qdrant.p2p.protocol" . }}://{{ include "qdrant.fullname" . }}-0.{{ include "qdrant.fullname" . }}-headless:{{ include "qdrant.p2p.port" . }}' {{ range .Values.snapshotRestoration.snapshots }} --snapshot {{ . }} {{ end }} + {{- else }} + echo "Starting initializing for pod $SET_INDEX" + if [ "$SET_INDEX" = "0" ]; then + exec ./entrypoint.sh --uri '{{ include "qdrant.p2p.protocol" . }}://{{ include "qdrant.fullname" . }}-0.{{ include "qdrant.fullname" . }}-headless:{{ include "qdrant.p2p.port" . }}' + else + exec ./entrypoint.sh --bootstrap '{{ include "qdrant.p2p.protocol" . }}://{{ include "qdrant.fullname" . }}-0.{{ include "qdrant.fullname" . }}-headless:{{ include "qdrant.p2p.port" . }}' --uri '{{ include "qdrant.p2p.protocol" . }}://{{ include "qdrant.fullname" . }}-'"$SET_INDEX"'.{{ include "qdrant.fullname" . }}-headless:{{ include "qdrant.p2p.port" . }}' + fi + {{ end }} + production.yaml: | + {{- tpl (toYaml .Values.config) . | nindent 4 }} diff --git a/packages/system/qdrant/charts/qdrant/templates/ingress.yaml b/packages/system/qdrant/charts/qdrant/templates/ingress.yaml new file mode 100644 index 00000000..6ab27985 --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/templates/ingress.yaml @@ -0,0 +1,53 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "qdrant.fullname" . }} + labels: + {{- include "qdrant.labels" . | nindent 4 }} + {{- include "qdrant.additionalLabels" . | nindent 4 }} + {{- with .Values.ingress.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- if or .Values.ingress.annotations .Values.additionalAnnotations }} + annotations: +{{- with .Values.additionalAnnotations }} + {{- toYaml . | nindent 4 }} +{{- end }} +{{- with .Values.ingress.annotations }} + {{- toYaml . | nindent 4 }} +{{- end }} +{{- end }} +spec: + {{- if .Values.ingress.ingressClassName }} + ingressClassName: {{ .Values.ingress.ingressClassName }} + {{- end }} + {{- with .Values.ingress.hosts }} + rules: + {{- range . }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path | quote }} + pathType: {{ .pathType | default "Prefix" | quote }} + backend: + service: + name: {{ default .serviceName (include "qdrant.fullname" $) }} + port: + number: {{ .servicePort }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls}} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName | quote }} + {{- end }} + {{- end }} +{{- end }} + diff --git a/packages/system/qdrant/charts/qdrant/templates/pdb.yaml b/packages/system/qdrant/charts/qdrant/templates/pdb.yaml new file mode 100644 index 00000000..9904f185 --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/templates/pdb.yaml @@ -0,0 +1,26 @@ +{{- if .Values.podDisruptionBudget.enabled }} +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "qdrant.fullname" . }} + labels: + {{- include "qdrant.labels" . | nindent 4 }} + {{- include "qdrant.additionalLabels" . | nindent 4 }} +{{- with .Values.additionalAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + {{- with .Values.podDisruptionBudget.maxUnavailable}} + maxUnavailable: {{ . }} + {{- end }} + {{- with .Values.podDisruptionBudget.minAvailable }} + minAvailable: {{ . }} + {{- end }} + {{- with .Values.podDisruptionBudget.unhealthyPodEvictionPolicy }} + unhealthyPodEvictionPolicy: {{ . }} + {{- end }} + selector: + matchLabels: + {{- include "qdrant.selectorLabels" . | nindent 6 }} +{{- end }} diff --git a/packages/system/qdrant/charts/qdrant/templates/secret.yaml b/packages/system/qdrant/charts/qdrant/templates/secret.yaml new file mode 100644 index 00000000..d95db526 --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/templates/secret.yaml @@ -0,0 +1,15 @@ +{{- if or .Values.apiKey .Values.readOnlyApiKey }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "qdrant.fullname" . }}-apikey + labels: + {{- include "qdrant.labels" . | nindent 4 }} + {{- include "qdrant.additionalLabels" . | nindent 4 }} +{{- with .Values.additionalAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +data: +{{ include "qdrant.secret" . | indent 2}} +{{- end }} diff --git a/packages/system/qdrant/charts/qdrant/templates/service-headless.yaml b/packages/system/qdrant/charts/qdrant/templates/service-headless.yaml new file mode 100644 index 00000000..642b1c23 --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/templates/service-headless.yaml @@ -0,0 +1,35 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "qdrant.fullname" . }}-headless + labels: + {{- include "qdrant.labels" . | nindent 4 }} + {{- include "qdrant.additionalLabels" . | nindent 4 }} + app.kubernetes.io/component: cluster-discovery +{{- with .Values.service.additionalLabels }} +{{- toYaml . | nindent 4 }} +{{- end }} +{{- if or .Values.service.annotations .Values.additionalAnnotations }} + annotations: +{{- with .Values.additionalAnnotations }} + {{- toYaml . | nindent 4 }} +{{- end }} +{{- with .Values.service.annotations }} + {{- toYaml . | nindent 4 }} +{{- end }} +{{- end }} +spec: + clusterIP: None + publishNotReadyAddresses: true + ports: + {{- range .Values.service.ports }} + - name: {{ .name }} + port: {{ .port }} + targetPort: {{ .targetPort }} + protocol: {{ .protocol | default "TCP" }} + {{- if .appProtocol }} + appProtocol: {{ .appProtocol }} + {{- end }} + {{- end }} + selector: + {{- include "qdrant.selectorLabels" . | nindent 4 }} diff --git a/packages/system/qdrant/charts/qdrant/templates/service.yaml b/packages/system/qdrant/charts/qdrant/templates/service.yaml new file mode 100644 index 00000000..b16e065b --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/templates/service.yaml @@ -0,0 +1,39 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "qdrant.fullname" . }} + labels: + {{- include "qdrant.labels" . | nindent 4 }} + {{- include "qdrant.additionalLabels" . | nindent 4 }} +{{- with .Values.service.additionalLabels }} +{{- toYaml . | nindent 4 }} +{{- end }} +{{- if or .Values.service.annotations .Values.additionalAnnotations }} + annotations: +{{- with .Values.additionalAnnotations }} + {{- toYaml . | nindent 4 }} +{{- end }} +{{- with .Values.service.annotations }} + {{- toYaml . | nindent 4 }} +{{- end }} +{{- end }} +spec: + type: {{ .Values.service.type | default "ClusterIP" }} + {{- if .Values.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + ports: + {{- range .Values.service.ports }} + - name: {{ .name }} + port: {{ .port }} + targetPort: {{ .targetPort }} + {{- if and (or (eq $.Values.service.type "NodePort") (eq $.Values.service.type "LoadBalancer")) (not (empty .nodePort)) }} + nodePort: {{ .nodePort }} + {{- end }} + protocol: {{ .protocol | default "TCP" }} + {{- if .appProtocol }} + appProtocol: {{ .appProtocol }} + {{- end }} + {{- end }} + selector: + {{- include "qdrant.selectorLabels" . | nindent 4 }} diff --git a/packages/system/qdrant/charts/qdrant/templates/serviceaccount.yaml b/packages/system/qdrant/charts/qdrant/templates/serviceaccount.yaml new file mode 100644 index 00000000..b3b5ddf2 --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "qdrant.fullname" . }} +{{- if or .Values.serviceAccount.annotations .Values.additionalAnnotations }} + annotations: +{{- with .Values.additionalAnnotations }} + {{- toYaml . | nindent 4 }} +{{- end }} +{{- with .Values.serviceAccount.annotations }} + {{- toYaml . | nindent 4 }} +{{- end }} +{{- end }} + labels: + {{- include "qdrant.labels" . | nindent 4 }} + {{- include "qdrant.additionalLabels" . | nindent 4 }} \ No newline at end of file diff --git a/packages/system/qdrant/charts/qdrant/templates/servicemonitor.yaml b/packages/system/qdrant/charts/qdrant/templates/servicemonitor.yaml new file mode 100644 index 00000000..45af6b09 --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/templates/servicemonitor.yaml @@ -0,0 +1,52 @@ +{{- if .Values.metrics.serviceMonitor.enabled }} +kind: ServiceMonitor +apiVersion: monitoring.coreos.com/v1 +metadata: + labels: + {{- include "qdrant.labels" . | nindent 4 }} + {{- include "qdrant.additionalLabels" . | nindent 4 }} +{{- with .Values.metrics.serviceMonitor.additionalLabels }} +{{- toYaml . | nindent 4 }} +{{- end }} + name: {{ include "qdrant.fullname" . }} +{{- with .Values.additionalAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + endpoints: + - honorLabels: true + interval: {{ .Values.metrics.serviceMonitor.scrapeInterval }} + path: {{ .Values.metrics.serviceMonitor.targetPath }} + port: {{ .Values.metrics.serviceMonitor.targetPort }} + scheme: http + scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }} +{{- if .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: +{{ tpl (toYaml .Values.metrics.serviceMonitor.metricRelabelings | indent 8) . }} +{{- end }} +{{- if .Values.metrics.serviceMonitor.relabelings }} + relabelings: +{{ tpl (toYaml .Values.metrics.serviceMonitor.relabelings | indent 8) . }} +{{- end }} +{{- if .Values.metrics.serviceMonitor.authorization }} + authorization: +{{ tpl (toYaml .Values.metrics.serviceMonitor.authorization | indent 8) . }} +{{- else if .Values.readOnlyApiKey }} + authorization: + type: Bearer + credentials: + name: {{ include "qdrant.fullname" . }}-apikey + key: read-only-api-key +{{- else if .Values.apiKey }} + authorization: + type: Bearer + credentials: + name: {{ include "qdrant.fullname" . }}-apikey + key: api-key +{{- end }} + selector: + matchLabels: + {{- include "qdrant.labels" . | nindent 6 }} + app.kubernetes.io/component: cluster-discovery +{{- end }} diff --git a/packages/system/qdrant/charts/qdrant/templates/statefulset.yaml b/packages/system/qdrant/charts/qdrant/templates/statefulset.yaml new file mode 100644 index 00000000..dac36df8 --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/templates/statefulset.yaml @@ -0,0 +1,312 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "qdrant.fullname" . }} + labels: + {{- include "qdrant.labels" . | nindent 4 }} + {{- include "qdrant.additionalLabels" . | nindent 4 }} +{{- with .Values.additionalAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + replicas: {{ .Values.replicaCount }} + podManagementPolicy: {{ .Values.podManagementPolicy }} + {{- if .Values.minReadySeconds }} + minReadySeconds: {{ .Values.minReadySeconds }} + {{- end }} + updateStrategy: + type: RollingUpdate + rollingUpdate: + partition: 0 + selector: + matchLabels: + {{- include "qdrant.selectorLabels" . | nindent 6 }} + serviceName: {{ include "qdrant.fullname" . }}-headless + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- if or .Values.apiKey .Values.readOnlyApiKey }} + checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + {{- end }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "qdrant.selectorLabels" . | nindent 8 }} + {{- include "qdrant.additionalLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: "{{ .Values.priorityClassName }}" + {{- end }} + {{- if .Values.shareProcessNamespace }} + shareProcessNamespace: {{ .Values.shareProcessNamespace }} + {{- end }} + initContainers: + {{- if and .Values.updateVolumeFsOwnership (not .Values.image.useUnprivilegedImage) }} + {{- if and .Values.containerSecurityContext .Values.containerSecurityContext.runAsUser }} + - name: ensure-dir-ownership + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + command: + - chown + - -R + - {{ int64 .Values.containerSecurityContext.runAsUser }}:{{ int64 .Values.podSecurityContext.fsGroup }} + - /qdrant/storage + - /qdrant/snapshots + {{- if and .Values.snapshotRestoration.enabled .Values.snapshotRestoration.pvcName }} + - {{ .Values.snapshotRestoration.mountPath }} + {{- end }} + volumeMounts: + - name: {{ .Values.persistence.storageVolumeName | default "qdrant-storage" }} + mountPath: /qdrant/storage + {{- if .Values.persistence.storageSubPath }} + subPath: "{{ .Values.persistence.storageSubPath }}" + {{- end }} + - name: {{ .Values.snapshotPersistence.snapshotsVolumeName | default "qdrant-snapshots" }} + mountPath: /qdrant/snapshots + {{- if .Values.snapshotPersistence.snapshotsSubPath }} + subPath: "{{ .Values.snapshotPersistence.snapshotsSubPath }}" + {{- end }} + {{- if and .Values.snapshotRestoration.enabled .Values.snapshotRestoration.pvcName }} + - name: qdrant-snapshot-restoration + mountPath: {{ .Values.snapshotRestoration.mountPath }} + {{- end }} + {{- end }} + {{- end }} + containers: + {{- if .Values.sidecarContainers -}} + {{- toYaml .Values.sidecarContainers | trim | nindent 8 }} + {{- end}} + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}{{ .Values.image.useUnprivilegedImage | ternary "-unprivileged" "" }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: QDRANT_INIT_FILE_PATH + value: /qdrant/init/.qdrant-initialized + {{- range .Values.env }} + - name: {{ .name }} + {{- if .valueFrom }} + valueFrom: {{- toYaml .valueFrom | nindent 16 }} + {{- else }} + value: {{ .value | quote }} + {{- end }} + {{- end }} + command: ["/bin/bash", "-c"] + {{- with .Values.args }} + args: + {{- toYaml . | nindent 10 }} + {{- end }} + ports: + {{- range .Values.service.ports }} + - name: {{ .name }} + containerPort: {{ .targetPort }} + protocol: {{ .protocol }} + {{- end }} + + {{- $values := .Values -}} + {{- range .Values.service.ports }} + {{- if and $values.livenessProbe.enabled .checksEnabled }} + livenessProbe: + {{- if eq .name "grpc"}} + grpc: + port: {{ .targetPort }} + {{- end }} + {{- if eq .name "http"}} + httpGet: + path: / + port: {{ .targetPort }} + {{- if and $values.config.service $values.config.service.enable_tls }} + scheme: HTTPS + {{- end }} + {{- end }} + initialDelaySeconds: {{ $values.livenessProbe.initialDelaySeconds }} + timeoutSeconds: {{ $values.livenessProbe.timeoutSeconds }} + periodSeconds: {{ $values.livenessProbe.periodSeconds }} + successThreshold: {{ $values.livenessProbe.successThreshold }} + failureThreshold: {{ $values.livenessProbe.failureThreshold }} + {{- end }} + {{- if and $values.readinessProbe.enabled .checksEnabled }} + readinessProbe: + {{- if eq .name "grpc"}} + grpc: + port: {{ .targetPort }} + {{- end }} + {{- if eq .name "http"}} + httpGet: + path: "{{- if semverCompare ">=1.7.3" ($.Values.image.tag | default $.Chart.AppVersion) -}}/readyz{{else}}/{{end}}" + port: {{ .targetPort }} + {{- if and $values.config.service $values.config.service.enable_tls }} + scheme: HTTPS + {{- end }} + {{- end }} + initialDelaySeconds: {{ $values.readinessProbe.initialDelaySeconds }} + timeoutSeconds: {{ $values.readinessProbe.timeoutSeconds }} + periodSeconds: {{ $values.readinessProbe.periodSeconds }} + successThreshold: {{ $values.readinessProbe.successThreshold }} + failureThreshold: {{ $values.readinessProbe.failureThreshold }} + {{- end }} + {{- if and $values.startupProbe.enabled .checksEnabled }} + startupProbe: + {{- if eq .name "grpc"}} + grpc: + port: {{ .targetPort }} + {{- end }} + {{- if eq .name "http"}} + httpGet: + path: / + port: {{ .targetPort }} + {{- if and $values.config.service $values.config.service.enable_tls }} + scheme: HTTPS + {{- end }} + {{- end }} + initialDelaySeconds: {{ $values.startupProbe.initialDelaySeconds }} + timeoutSeconds: {{ $values.startupProbe.timeoutSeconds }} + periodSeconds: {{ $values.startupProbe.periodSeconds }} + successThreshold: {{ $values.startupProbe.successThreshold }} + failureThreshold: {{ $values.startupProbe.failureThreshold }} + {{- end }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.containerSecurityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.lifecycle }} + lifecycle: + {{- toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - name: {{ .Values.persistence.storageVolumeName | default "qdrant-storage" }} + mountPath: /qdrant/storage + {{- if .Values.persistence.storageSubPath }} + subPath: "{{ .Values.persistence.storageSubPath }}" + {{- end }} + - name: qdrant-config + mountPath: /qdrant/config/initialize.sh + subPath: initialize.sh + - name: qdrant-config + mountPath: /qdrant/config/production.yaml + subPath: production.yaml + {{- if or .Values.apiKey .Values.readOnlyApiKey }} + - name: qdrant-secret + mountPath: /qdrant/config/local.yaml + subPath: local.yaml + {{- end }} + {{- if and .Values.snapshotRestoration.enabled .Values.snapshotRestoration.pvcName }} + - name: qdrant-snapshot-restoration + mountPath: {{ .Values.snapshotRestoration.mountPath }} + {{- end }} + - name: {{ .Values.snapshotPersistence.snapshotsVolumeName | default "qdrant-snapshots" }} + mountPath: /qdrant/snapshots + {{- if .Values.snapshotPersistence.snapshotsSubPath }} + subPath: "{{ .Values.snapshotPersistence.snapshotsSubPath }}" + {{- end }} + - name: qdrant-init + mountPath: /qdrant/init + {{- if .Values.additionalVolumeMounts }} +{{- toYaml .Values.additionalVolumeMounts | default "" | nindent 10 }} + {{- end}} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- tpl (toYaml .) $ | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.topologySpreadConstraints}} + topologySpreadConstraints: + {{- tpl (toYaml .) $ | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "qdrant.fullname" . }} + volumes: + - name: qdrant-config + configMap: + name: {{ include "qdrant.fullname" . }} + defaultMode: 0755 + {{- if and .Values.snapshotRestoration.enabled .Values.snapshotRestoration.pvcName }} + - name: qdrant-snapshot-restoration + persistentVolumeClaim: + claimName: {{ .Values.snapshotRestoration.pvcName }} + {{- end }} + {{- if not .Values.snapshotPersistence.enabled }} + - name: {{ .Values.snapshotPersistence.snapshotsVolumeName | default "qdrant-snapshots" }} + emptyDir: {} + {{- end }} + - name: qdrant-init + emptyDir: {} + {{- if or .Values.apiKey .Values.readOnlyApiKey }} + - name: qdrant-secret + secret: + secretName: {{ include "qdrant.fullname" . }}-apikey + defaultMode: 0600 + {{- end }} + {{- if .Values.additionalVolumes }} +{{- toYaml .Values.additionalVolumes | default "" | nindent 8 }} + {{- end}} + volumeClaimTemplates: + - metadata: + name: {{ .Values.persistence.storageVolumeName | default "qdrant-storage" }} + labels: + app: {{ template "qdrant.name" . }} + {{- with .Values.persistence.additionalLabels }} + {{- toYaml . | nindent 10 }} + {{- end }} + {{- with .Values.persistence.annotations }} + annotations: + {{- toYaml . | nindent 10 }} + {{- end }} + spec: + storageClassName: {{ .Values.persistence.storageClassName }} + {{- if .Values.persistence.volumeAttributesClassName }} + volumeAttributesClassName: {{ .Values.persistence.volumeAttributesClassName }} + {{- end }} + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{- if .Values.snapshotPersistence.enabled }} + - metadata: + name: {{ .Values.snapshotPersistence.snapshotsVolumeName | default "qdrant-snapshots" }} + labels: + app: {{ template "qdrant.name" . }} + {{- with .Values.snapshotPersistence.additionalLabels }} + {{- toYaml . | nindent 10 }} + {{- end }} + {{- with .Values.snapshotPersistence.annotations }} + annotations: + {{- toYaml . | nindent 10 }} + {{- end }} + spec: + storageClassName: {{ .Values.snapshotPersistence.storageClassName }} + {{- if .Values.snapshotPersistence.volumeAttributesClassName }} + volumeAttributesClassName: {{ .Values.snapshotPersistence.volumeAttributesClassName }} + {{- end }} + accessModes: + {{- range .Values.snapshotPersistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.snapshotPersistence.size | quote }} + {{- end }} diff --git a/packages/system/qdrant/charts/qdrant/templates/tests/test-db-interaction.yaml b/packages/system/qdrant/charts/qdrant/templates/tests/test-db-interaction.yaml new file mode 100644 index 00000000..3b754088 --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/templates/tests/test-db-interaction.yaml @@ -0,0 +1,128 @@ +{{- $root := . }} +{{- $namespace := .Release.Namespace }} +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "qdrant.fullname" . }}-test-db-interaction" + labels: + {{- include "qdrant.labels" . | nindent 4 }} + {{- include "qdrant.additionalLabels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +{{- with .Values.additionalAnnotations }} + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + containers: + - name: test-script + image: {{ .Values.chartTests.dbInteraction.image | quote }} + args: ['bash', '/app/entrypoint.sh'] + volumeMounts: + - mountPath: /app + name: test-script + {{- if .Values.additionalVolumeMounts }} +{{- toYaml .Values.additionalVolumeMounts | default "" | nindent 8 }} + {{- end}} + resources: + {{- toYaml .Values.chartTests.dbInteraction.resources | nindent 8 }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 4 }} + {{- end }} + volumes: + - name: test-script + configMap: + name: "{{ include "qdrant.fullname" . }}-test-db-interaction" + {{- if .Values.additionalVolumes }} +{{- toYaml .Values.additionalVolumes | default "" | nindent 4 }} + {{- end}} + restartPolicy: Never + serviceAccountName: {{ include "qdrant.fullname" . }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ include "qdrant.fullname" . }}-test-db-interaction" + labels: + {{- include "qdrant.labels" . | nindent 4 }} + {{- include "qdrant.additionalLabels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +{{- with .Values.additionalAnnotations }} + {{- toYaml . | nindent 4 }} +{{- end }} +data: + entrypoint.sh: | + #!/bin/bash + set -xe + # Kind's networking is very flaky + echo 'connect-timeout = 5' > $HOME/.curlrc + echo 'retry = 60' >> $HOME/.curlrc + echo 'retry-delay = 5' >> $HOME/.curlrc + echo 'retry-all-errors' >> $HOME/.curlrc + # Don't clutter the logs with progress bars + echo 'no-progress-meter' >> $HOME/.curlrc + # Ensure errors cause the script to fail, but show the response body + echo 'fail-with-body' >> $HOME/.curlrc + + if [ -d /mnt/secrets/certs ]; then + cp /mnt/secrets/certs/ca.pem /usr/share/pki/trust/anchors/private-ca.pem + update-ca-certificates + fi + + QDRANT_COLLECTION="test_collection" + {{- range .Values.service.ports }} + {{- if eq .name "http" }} + echo "Connecting to {{ include "qdrant.fullname" $root }}.{{ $namespace }}:{{ .port }}" + QDRANT_URL="http://{{ include "qdrant.fullname" $root }}.{{ $namespace }}:{{ .port }}" + {{- if and $root.Values.config.service $root.Values.config.service.enable_tls }} + echo "Using https" + QDRANT_URL="https://{{ include "qdrant.fullname" $root }}.{{ $namespace }}:{{ .port }}" + {{- end }} + {{- end }} + {{- end }} + API_KEY_HEADER="" + {{- if .Values.apiKey }} + API_KEY_HEADER="Api-key: {{ .Values.apiKey }}" + {{- else if .Values.readOnlyApiKey }} + API_KEY_HEADER="Api-key: {{ .Values.readOnlyApiKey }}" + {{- end }} + + # Delete collection if exists + curl -X DELETE -H "${API_KEY_HEADER}" $QDRANT_URL/collections/${QDRANT_COLLECTION} + + # Create collection + curl -X PUT \ + -H 'Content-Type: application-json' \ + -d '{"vectors":{"size":4,"distance":"Dot"}}' \ + -H "${API_KEY_HEADER}" \ + $QDRANT_URL/collections/${QDRANT_COLLECTION} + + # Insert points + curl -X PUT \ + -H 'Content-Type: application-json' \ + -d '{"points":[ + {"id":1,"vector":[0.05, 0.61, 0.76, 0.74],"payload":{"city":"Berlin"}}, + {"id":2,"vector":[0.19, 0.81, 0.75, 0.11],"payload":{"city":"London"}}, + {"id":3,"vector":[0.36, 0.55, 0.47, 0.94],"payload":{"city":"Moscow"}}, + {"id":4,"vector":[0.18, 0.01, 0.85, 0.80],"payload":{"city":"New York"}}, + {"id":5,"vector":[0.24, 0.18, 0.22, 0.44],"payload":{"city":"Beijing"}}, + {"id":6,"vector":[0.35, 0.08, 0.11, 0.44],"payload":{"city":"Mumbai"}} + ]}' \ + -H "${API_KEY_HEADER}" \ + $QDRANT_URL/collections/${QDRANT_COLLECTION}/points + + # Run query + curl -X POST \ + -H 'Content-Type: application-json' \ + -d '{"vector":[0.2, 0.1, 0.9, 0.7],"limit":3}' \ + -H "${API_KEY_HEADER}" \ + $QDRANT_URL/collections/${QDRANT_COLLECTION}/points/search diff --git a/packages/system/qdrant/charts/qdrant/values.yaml b/packages/system/qdrant/charts/qdrant/values.yaml new file mode 100644 index 00000000..8a2fd9dc --- /dev/null +++ b/packages/system/qdrant/charts/qdrant/values.yaml @@ -0,0 +1,293 @@ +replicaCount: 1 + +image: + repository: docker.io/qdrant/qdrant + pullPolicy: IfNotPresent + tag: "" + useUnprivilegedImage: false + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" +args: ["./config/initialize.sh"] +env: [] + # - name: QDRANT_ALLOW_RECOVERY_MODE + # value: true +additionalLabels: {} + +# checks - Readiness and liveness checks can only be enabled for either http (REST) or grpc (multiple checks not supported) +# grpc checks are only available from k8s 1.24+ so as of per default we check http +service: + type: ClusterIP + additionalLabels: {} + annotations: {} + loadBalancerIP: "" + ports: + - name: http + port: 6333 + targetPort: 6333 + protocol: TCP + checksEnabled: true + # appProtocol: http + - name: grpc + port: 6334 + targetPort: 6334 + protocol: TCP + checksEnabled: false + # appProtocol: http2 + - name: p2p + port: 6335 + targetPort: 6335 + protocol: TCP + checksEnabled: false + +ingress: + enabled: false + ingressClassName: "" + additionalLabels: {} + annotations: {} + # kubernetes.io/ingress.class: alb + hosts: + - host: example-domain.com + paths: + - path: / + pathType: Prefix + servicePort: 6333 + tls: [] + # - hosts: + # - example-domain.com + # secretName: tls-secret-name + +livenessProbe: + enabled: false + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 1 + failureThreshold: 6 + successThreshold: 1 + +readinessProbe: + enabled: true + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 1 + failureThreshold: 6 + successThreshold: 1 + +startupProbe: + enabled: false + initialDelaySeconds: 10 + periodSeconds: 5 + timeoutSeconds: 1 + failureThreshold: 30 + successThreshold: 1 + +additionalLabels: {} +# additionalAnnotations will be added to all top-level resources (StatefulSet, Service, ConfigMap, etc.) +additionalAnnotations: {} +podAnnotations: {} +podLabels: {} + +resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +containerSecurityContext: + runAsNonRoot: true + runAsUser: 1000 + runAsGroup: 2000 + allowPrivilegeEscalation: false + privileged: false + readOnlyRootFilesystem: true + +podSecurityContext: + fsGroup: 3000 + fsGroupChangePolicy: Always + +lifecycle: + preStop: + exec: + # Sleeping before shutdown allows Qdrant to process requests that were + # in-flight before the node is removed from load-balancing. + # If using an external load balancer, you may need to increase this + # duration to be greater than the LB's health check interval. + command: ["sleep", "3"] + +# Unless .Values.image.useUnprivilegedImage is set to true, ensures that the pre-existing +# files on the storage and snapshot volume are owned by the container's user and fsGroup. +updateVolumeFsOwnership: true + +nodeSelector: {} + +tolerations: [] + +affinity: {} + # podAntiAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # - labelSelector: + # matchExpressions: + # - key: app.kubernetes.io/name + # operator: In + # values: + # - '{{ include "qdrant.name" . }}' + # - key: app.kubernetes.io/instance + # operator: In + # values: + # - '{{ .Release.Name }}' + # topologyKey: "kubernetes.io/hostname" + +topologySpreadConstraints: [] + +persistence: + accessModes: ["ReadWriteOnce"] + size: 10Gi + annotations: {} + additionalLabels: {} + # storageVolumeName: qdrant-storage + # storageSubPath: "" + # storageClassName: local-path + # volumeAttributesClassName: "" + +# If you use snapshots or the snapshot shard transfer mechanism, we recommend +# creating a separate volume of the same size as your main volume so that your +# cluster won't crash if the snapshot is too big. +snapshotPersistence: + enabled: false + accessModes: ["ReadWriteOnce"] + size: 10Gi + annotations: {} + additionalLabels: {} + # snapshotsVolumeName: qdrant-snapshots + # snapshotsSubPath: "" + # You can change the storageClassName to ensure snapshots are saved to cold storage. + # storageClassName: local-path + # volumeAttributesClassName: "" + +snapshotRestoration: + enabled: false + # Set pvcName if you want to restore from a separately-created PVC. Only supported for single-node clusters unless the PVC is ReadWriteMany. + # If you set snapshotPersistence.enabled and want to restore a snapshot from there, you can leave this blank to skip mounting an external volume. + pvcName: snapshots-pvc + # Must not conflict with /qdrant/snapshots or /qdrant/storage + mountPath: /qdrant/snapshot-restoration + snapshots: + # - /qdrant/snapshot-restoration/test_collection/test_collection-2022-10-24-13-56-50.snapshot:test_collection + +# modification example for configuration to overwrite defaults +config: + cluster: + enabled: true + p2p: + port: 6335 + enable_tls: false + consensus: + tick_period_ms: 100 + service: + enable_tls: false + +sidecarContainers: [] +# sidecarContainers: +# - name: my-sidecar +# image: qdrant/my-sidecar-image +# imagePullPolicy: Always +# ports: +# - name: my-port +# containerPort: 5000 +# protocol: TCP +# resources: +# requests: +# memory: 10Mi +# cpu: 10m +# limits: +# memory: 100Mi +# cpu: 100m + +metrics: + serviceMonitor: + enabled: false + additionalLabels: {} + scrapeInterval: 30s + scrapeTimeout: 10s + targetPort: http + targetPath: "/metrics" + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + ## Authorization to apply to the metrics endpoint for the cases when the API key(s) are configured externally + ## ref: https://prometheus-operator.dev/docs/api-reference/api/#monitoring.coreos.com/v1.SafeAuthorization + ## + authorization: {} + # authorization: + # type: Bearer + # credentials: + # name: external-secret-with-api-key + # key: api-key + +serviceAccount: + annotations: {} + +priorityClassName: "" + +shareProcessNamespace: false + +# We discourage changing this setting. Using the "OrderedReady" policy in a +# multi-node cluster will cause a deadlock where nodes refuse to become +# "Ready" until all nodes are running. +podManagementPolicy: Parallel + +podDisruptionBudget: + enabled: false + maxUnavailable: 1 + # do not enable if you are using not in 1.27 + unhealthyPodEvictionPolicy: "" + # minAvailable: 1 + +# api key for authentication at qdrant +# false: no api key will be configured +# true: an api key will be auto-generated +# string: the given string will be set as an apikey +# Also supports reading in from an external secret using +# valueFrom: +# secretKeyRef: +# name: +# key: +# apiKey: false + +# read-only api key for authentication at qdrant +# false: no read-only api key will be configured +# true: an read-only api key will be auto-generated +# string: the given string will be set as a read-only apikey +# Also supports reading in from an external secret using +# valueFrom: +# secretKeyRef: +# name: +# key: +# readOnlyApiKey: false + +additionalVolumes: [] +# - name: volumeName +# emptyDir: {} + +additionalVolumeMounts: [] +# - name: volumeName +# mountPath: "/mount/path" + +chartTests: + dbInteraction: + image: registry.suse.com/bci/bci-base:latest + resources: + requests: + cpu: 100m + memory: 200Mi + limits: + cpu: 100m + memory: 200Mi diff --git a/packages/system/qdrant/values.yaml b/packages/system/qdrant/values.yaml new file mode 100644 index 00000000..c675678f --- /dev/null +++ b/packages/system/qdrant/values.yaml @@ -0,0 +1 @@ +qdrant: {} diff --git a/packages/system/rabbitmq-operator/Makefile b/packages/system/rabbitmq-operator/Makefile index 12eda697..a75e37cd 100644 --- a/packages/system/rabbitmq-operator/Makefile +++ b/packages/system/rabbitmq-operator/Makefile @@ -1,7 +1,7 @@ export NAME=rabbitmq-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf templates/cluster-operator.yml diff --git a/packages/system/rabbitmq-rd/Chart.yaml b/packages/system/rabbitmq-rd/Chart.yaml new file mode 100644 index 00000000..9fa858de --- /dev/null +++ b/packages/system/rabbitmq-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: rabbitmq-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/rabbitmq-rd/Makefile b/packages/system/rabbitmq-rd/Makefile new file mode 100644 index 00000000..7db599d7 --- /dev/null +++ b/packages/system/rabbitmq-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=rabbitmq-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/rabbitmq-rd/cozyrds/rabbitmq.yaml b/packages/system/rabbitmq-rd/cozyrds/rabbitmq.yaml new file mode 100644 index 00000000..575c4c4c --- /dev/null +++ b/packages/system/rabbitmq-rd/cozyrds/rabbitmq.yaml @@ -0,0 +1,40 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: rabbitmq +spec: + application: + kind: RabbitMQ + plural: rabbitmqs + singular: rabbitmq + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of RabbitMQ replicas.","type":"integer","default":3},"resources":{"description":"Explicit CPU and memory configuration for each RabbitMQ replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"version":{"description":"RabbitMQ major.minor version to deploy","type":"string","default":"v4.2","enum":["v4.2","v4.1","v4.0","v3.13"]},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user.","type":"string"}}}},"vhosts":{"description":"Virtual hosts configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","required":["roles"],"properties":{"roles":{"description":"Virtual host roles list.","type":"object","properties":{"admin":{"description":"List of admin users.","type":"array","items":{"type":"string"}},"readonly":{"description":"List of readonly users.","type":"array","items":{"type":"string"}}}}}}}}} + release: + prefix: rabbitmq- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-rabbitmq-application-default-rabbitmq + namespace: cozy-system + dashboard: + category: PaaS + singular: RabbitMQ + plural: RabbitMQ + description: Managed RabbitMQ service + tags: + - messaging + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHg9Ii0wLjAwMTk1MzEyIiB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgcng9IjI0IiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfNjgzXzI5NzIpIi8+CjxwYXRoIGQ9Ik0xMTEuNDExIDYyLjhIODIuNDkzOUM4MS43OTY5IDYyLjc5OTcgODEuMTI4NSA2Mi41MjI4IDgwLjYzNTYgNjIuMDMwMUM4MC4xNDI3IDYxLjUzNzMgNzkuODY1NiA2MC44NjkxIDc5Ljg2NTMgNjAuMTcyMlYzMC4wNDEyQzc5Ljg2NTMgMjcuODEgNzguMDU1NiAyNiA3NS44MjQ5IDI2SDY1LjUwMjFDNjMuMjcgMjYgNjEuNDYxNCAyNy44MSA2MS40NjE0IDMwLjA0MTJWNTkuOTg5OEM2MS40NjE0IDYxLjU0MzUgNjAuMjA1IDYyLjgwNjUgNTguNjUwOCA2Mi44MTMzTDQ5LjE3NDMgNjIuODU4NEM0Ny42MDY5IDYyLjg2NjkgNDYuMzMzNiA2MS41OTU1IDQ2LjMzNjYgNjAuMDI5OEw0Ni4zOTU0IDMwLjA0OEM0Ni40MDA1IDI3LjgxMzQgNDQuNTkwMiAyNiA0Mi4zNTUgMjZIMzIuMDQwN0MyOS44MDgzIDI2IDI4IDI3LjgxIDI4IDMwLjA0MTJWMTE0LjQxMkMyOCAxMTYuMzk0IDI5LjYwNjEgMTE4IDMxLjU4NzEgMTE4SDExMS40MTFDMTEzLjM5NCAxMTggMTE1IDExNi4zOTQgMTE1IDExNC40MTJWNjYuMzg4QzExNSA2NC40MDU4IDExMy4zOTQgNjIuOCAxMTEuNDExIDYyLjhaTTk3Ljg1MDggOTQuNDc3OUM5Ny44NTA4IDk3LjA3NTUgOTUuNzQ0NSA5OS4xODE3IDkzLjE0NjQgOTkuMTgxN0g4NC45ODg0QzgyLjM5IDk5LjE4MTcgODAuMjgzNiA5Ny4wNzU1IDgwLjI4MzYgOTQuNDc3OVY4Ni4zMjE3QzgwLjI4MzYgODMuNzIzOCA4Mi4zOSA4MS42MTc5IDg0Ljk4ODQgODEuNjE3OUg5My4xNDY0Qzk1Ljc0NDUgODEuNjE3OSA5Ny44NTA4IDgzLjcyMzggOTcuODUwOCA4Ni4zMjE3Vjk0LjQ3NzlaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4M18yOTcyIiB4MT0iNSIgeTE9Ii03LjUiIHgyPSIxNDEiIHkyPSIxMjQuNSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjRkY4MjJGIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI0ZGNjYwMCIvPgo8L2xpbmVhckdyYWRpZW50Pgo8L2RlZnM+Cjwvc3ZnPgo= + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "version"], ["spec", "users"], ["spec", "vhosts"]] + secrets: + exclude: [] + include: + - resourceNames: + - rabbitmq-{{ .name }}-default-user + - matchLabels: + apps.cozystack.io/user-secret: "true" + services: + exclude: [] + include: + - resourceNames: + - rabbitmq-{{ .name }} diff --git a/packages/system/rabbitmq-rd/templates/cozyrd.yaml b/packages/system/rabbitmq-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/rabbitmq-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/rabbitmq-rd/values.yaml b/packages/system/rabbitmq-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/rabbitmq-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/redis-operator/Makefile b/packages/system/redis-operator/Makefile index 9ea964dd..9e21b1b4 100644 --- a/packages/system/redis-operator/Makefile +++ b/packages/system/redis-operator/Makefile @@ -1,7 +1,9 @@ +REDIS_OPERATOR_TAG=$(shell grep -F 'ARG VERSION=' images/redis-operator/Dockerfile | cut -f2 -d=) export NAME=redis-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts @@ -9,3 +11,16 @@ update: helm repo update redis-operator helm pull redis-operator/redis-operator --untar --untardir charts sed -i '/{{/d' charts/redis-operator/crds/databases.spotahome.com_redisfailovers.yaml + +image: + docker buildx build images/redis-operator \ + --tag $(REGISTRY)/redis-operator:$(REDIS_OPERATOR_TAG) \ + --cache-from type=registry,ref=$(REGISTRY)/redis-operator:latest \ + --cache-to type=inline \ + --metadata-file images/redis-operator.json \ + $(BUILDX_ARGS) + REPOSITORY="$(REGISTRY)/redis-operator" \ + yq -i '.redis-operator.image.repository = strenv(REPOSITORY)' values.yaml + TAG=$(REDIS_OPERATOR_TAG)@$$(yq e '."containerimage.digest"' images/redis-operator.json -o json -r) \ + yq -i '.redis-operator.image.tag = strenv(TAG)' values.yaml + rm -f images/redis-operator.json diff --git a/packages/system/redis-operator/images/redis-operator/Dockerfile b/packages/system/redis-operator/images/redis-operator/Dockerfile new file mode 100644 index 00000000..d0d6b682 --- /dev/null +++ b/packages/system/redis-operator/images/redis-operator/Dockerfile @@ -0,0 +1,27 @@ +FROM golang:1.20 AS builder + +ARG VERSION=v1.3.0-rc1 + +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /workspace + +RUN curl -sSL https://github.com/spotahome/redis-operator/archive/refs/tags/${VERSION}.tar.gz | tar -xzvf- --strip=1 + +COPY patches /patches +RUN git apply /patches/*.diff + +RUN GOOS=$TARGETOS GOARCH=$TARGETARCH VERSION=$VERSION ./scripts/build.sh + +FROM alpine:latest +RUN apk --no-cache add \ + ca-certificates +COPY --from=builder /workspace/bin/redis-operator /usr/local/bin +RUN addgroup -g 1000 rf && \ + adduser -D -u 1000 -G rf rf && \ + chown rf:rf /usr/local/bin/redis-operator +USER rf + +ENTRYPOINT ["/usr/local/bin/redis-operator"] + diff --git a/packages/system/redis-operator/images/redis-operator/patches/labels.diff b/packages/system/redis-operator/images/redis-operator/patches/labels.diff new file mode 100644 index 00000000..fe4c4254 --- /dev/null +++ b/packages/system/redis-operator/images/redis-operator/patches/labels.diff @@ -0,0 +1,23 @@ +diff --git a/service/k8s/service.go b/service/k8s/service.go +index 712cc4c0..e84afc92 100644 +--- a/service/k8s/service.go ++++ b/service/k8s/service.go +@@ -10,6 +10,7 @@ import ( + + "github.com/spotahome/redis-operator/log" + "github.com/spotahome/redis-operator/metrics" ++ "github.com/spotahome/redis-operator/operator/redisfailover/util" + ) + + // Service the ServiceAccount service that knows how to interact with k8s to manage them +@@ -95,6 +96,10 @@ func (s *ServiceService) CreateOrUpdateService(namespace string, service *corev1 + // namespace is our spec(https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#concurrency-control-and-consistency), + // we will replace the current namespace state. + service.ResourceVersion = storedService.ResourceVersion ++ newLabels := util.MergeLabels(storedService.GetLabels(), service.GetLabels()) ++ newAnnotations := util.MergeAnnotations(storedService.GetAnnotations(), service.GetAnnotations()) ++ service.SetLabels(newLabels) ++ service.SetAnnotations(newAnnotations) + return s.UpdateService(namespace, service) + } + diff --git a/packages/system/redis-operator/values.yaml b/packages/system/redis-operator/values.yaml index eb8c61a9..77e91011 100644 --- a/packages/system/redis-operator/values.yaml +++ b/packages/system/redis-operator/values.yaml @@ -1,3 +1,4 @@ redis-operator: image: - tag: v1.3.0-rc1 + repository: ghcr.io/cozystack/cozystack/redis-operator + tag: v1.3.0-rc1@sha256:a4012e6a1b5daaedb57cc27edfdbff52124de4164b5ec0ee53c5ce5710ef4c25 diff --git a/packages/system/redis-rd/Chart.yaml b/packages/system/redis-rd/Chart.yaml new file mode 100644 index 00000000..4ccfa4fd --- /dev/null +++ b/packages/system/redis-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: redis-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/redis-rd/Makefile b/packages/system/redis-rd/Makefile new file mode 100644 index 00000000..e6aca9de --- /dev/null +++ b/packages/system/redis-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=redis-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/redis-rd/cozyrds/redis.yaml b/packages/system/redis-rd/cozyrds/redis.yaml new file mode 100644 index 00000000..e5191aa4 --- /dev/null +++ b/packages/system/redis-rd/cozyrds/redis.yaml @@ -0,0 +1,41 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: redis +spec: + application: + kind: Redis + plural: redises + singular: redis + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of Redis replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each Redis replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for application data.","default":"1Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"version":{"description":"Redis major version to deploy","type":"string","default":"v8","enum":["v8","v7"]},"authEnabled":{"description":"Enable password generation.","type":"boolean","default":true}}} + release: + prefix: redis- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-redis-application-default-redis + namespace: cozy-system + dashboard: + category: PaaS + singular: Redis + plural: Redis + description: Managed Redis service + tags: + - cache + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODNfMzIxMykiLz4KPHBhdGggZD0iTTEyMC4xNDkgOTUuNTQ5MUMxMTQuNTg2IDk4LjQ0ODUgODUuNzcwOSAxMTAuMjk2IDc5LjYzNjMgMTEzLjQ5NUM3My41MDE2IDExNi42OTMgNzAuMDkzNyAxMTYuNjYyIDY1LjI0NzIgMTE0LjM0NkM2MC40MDEyIDExMi4wMjkgMjkuNzM2NCA5OS42NDIzIDI0LjIxMjUgOTcuMDAxOUMyMS40NTE5IDk1LjY4MjcgMjAgOTQuNTY4NyAyMCA5My41MTY2VjgyLjk4MDlDMjAgODIuOTgwOSA1OS45MjIgNzQuMjkwMSA2Ni4zNjY5IDcxLjk3NzhDNzIuODExNSA2OS42NjU2IDc1LjA0NzYgNjkuNTgyMSA4MC41MzIgNzEuNTkxQzg2LjAxNzMgNzMuNjAwOCAxMTguODEyIDc5LjUxNzYgMTI0LjIzMyA4MS41MDI5TDEyNC4yMyA5MS44ODk2QzEyNC4yMzEgOTIuOTMxMSAxMjIuOTggOTQuMDczNiAxMjAuMTQ5IDk1LjU0OTFaIiBmaWxsPSIjOTEyNjI2Ii8+CjxwYXRoIGQ9Ik0xMjAuMTQ3IDg1LjA3NTJDMTE0LjU4NSA4Ny45NzM0IDg1Ljc3IDk5LjgyMTggNzkuNjM1NCAxMDMuMDJDNzMuNTAxMSAxMDYuMjE5IDcwLjA5MzIgMTA2LjE4NyA2NS4yNDcyIDEwMy44NzFDNjAuNDAwNyAxMDEuNTU1IDI5LjczNzEgODkuMTY2OCAyNC4yMTM2IDg2LjUyOEMxOC42OTAxIDgzLjg4NzYgMTguNTc0NCA4Mi4wNzA0IDI0LjAwMDMgNzkuOTQ1OEMyOS40MjYxIDc3LjgyMDUgNTkuOTIxNSA2NS44NTYxIDY2LjM2NzIgNjMuNTQzOEM3Mi44MTE4IDYxLjIzMjQgNzUuMDQ3NSA2MS4xNDgxIDgwLjUzMTkgNjMuMTU3OEM4Ni4wMTY4IDY1LjE2NjggMTE0LjY2IDc2LjU2NzYgMTIwLjA3OSA3OC41NTI1QzEyNS41MDEgODAuNTM5OSAxMjUuNzA5IDgyLjE3NjMgMTIwLjE0NyA4NS4wNzUyWiIgZmlsbD0iI0M2MzAyQiIvPgo8cGF0aCBkPSJNMTIwLjE0OSA3OC41MDJDMTE0LjU4NiA4MS40MDE4IDg1Ljc3MDkgOTMuMjQ5MyA3OS42MzYzIDk2LjQ0ODhDNzMuNTAxNiA5OS42NDYyIDcwLjA5MzcgOTkuNjE1MiA2NS4yNDcyIDk3LjI5ODVDNjAuNDAwOCA5NC45ODMgMjkuNzM2NCA4Mi41OTUyIDI0LjIxMjUgNzkuOTU0N0MyMS40NTE5IDc4LjYzNTUgMjAgNzcuNTIzMiAyMCA3Ni40NzA3VjY1LjkzMzhDMjAgNjUuOTMzOCA1OS45MjIgNTcuMjQzNCA2Ni4zNjY5IDU0LjkzMTFDNzIuODExNSA1Mi42MTg5IDc1LjA0NzYgNTIuNTM1IDgwLjUzMiA1NC41NDQzQzg2LjAxNzcgNTYuNTUzNiAxMTguODEzIDYyLjQ2OTMgMTI0LjIzMyA2NC40NTVMMTI0LjIzIDc0Ljg0MjhDMTI0LjIzMSA3NS44ODQgMTIyLjk4IDc3LjAyNjQgMTIwLjE0OSA3OC41MDJaIiBmaWxsPSIjOTEyNjI2Ii8+CjxwYXRoIGQ9Ik0xMjAuMTQ3IDY4LjAyODJDMTE0LjU4NSA3MC45MjcxIDg1Ljc3IDgyLjc3NDcgNzkuNjM1NCA4NS45NzM3QzczLjUwMTEgODkuMTcxNiA3MC4wOTMyIDg5LjE0MDIgNjUuMjQ3MiA4Ni44MjM1QzYwLjQwMDcgODQuNTA4NCAyOS43MzcxIDcyLjEyMDEgMjQuMjEzNiA2OS40ODA5QzE4LjY5MDEgNjYuODQxMyAxOC41NzQ0IDY1LjAyMzcgMjQuMDAwMyA2Mi44OTg0QzI5LjQyNjEgNjAuNzc0MiA1OS45MjE5IDQ4LjgwOSA2Ni4zNjcyIDQ2LjQ5NzJDNzIuODExOCA0NC4xODUzIDc1LjA0NzUgNDQuMTAxNCA4MC41MzE5IDQ2LjExMDhDODYuMDE2OCA0OC4xMTk3IDExNC42NiA1OS41MTk3IDEyMC4wNzkgNjEuNTA1NUMxMjUuNTAxIDYzLjQ5MjQgMTI1LjcwOSA2NS4xMjkyIDEyMC4xNDcgNjguMDI4MloiIGZpbGw9IiNDNjMwMkIiLz4KPHBhdGggZD0iTTEyMC4xNDkgNjAuODIyNEMxMTQuNTg2IDYzLjcyMTQgODUuNzcwOSA3NS41Njk4IDc5LjYzNjMgNzguNzY5MkM3My41MDE2IDgxLjk2NzEgNzAuMDkzNyA4MS45MzU3IDY1LjI0NzIgNzkuNjE5QzYwLjQwMDggNzcuMzAzNSAyOS43MzY0IDY0LjkxNTIgMjQuMjEyNSA2Mi4yNzZDMjEuNDUxOSA2MC45NTU2IDIwIDU5Ljg0MjggMjAgNTguNzkxNVY0OC4yNTQyQzIwIDQ4LjI1NDIgNTkuOTIyIDM5LjU2NDIgNjYuMzY2OSAzNy4yNTI0QzcyLjgxMTUgMzQuOTM5NyA3NS4wNDc2IDM0Ljg1NjcgODAuNTMyIDM2Ljg2NTZDODYuMDE3NyAzOC44NzQ5IDExOC44MTMgNDQuNzkwNSAxMjQuMjMzIDQ2Ljc3NjNMMTI0LjIzIDU3LjE2MzdDMTI0LjIzMSA1OC4yMDQgMTIyLjk4IDU5LjM0NjUgMTIwLjE0OSA2MC44MjI0WiIgZmlsbD0iIzkxMjYyNiIvPgo8cGF0aCBkPSJNMTIwLjE0NyA1MC4zNDlDMTE0LjU4NSA1My4yNDc5IDg1Ljc2OTggNjUuMDk2MyA3OS42MzUyIDY4LjI5NDFDNzMuNTAwOSA3MS40OTIgNzAuMDkzIDcxLjQ2MDYgNjUuMjQ2OSA2OS4xNDUxQzYwLjQwMDkgNjYuODI4MyAyOS43MzY5IDU0LjQ0MDkgMjQuMjEzOCA1MS44MDEzQzE4LjY4OTkgNDkuMTYyMSAxOC41NzQ2IDQ3LjM0NDEgMjQgNDUuMjE5MkMyOS40MjU5IDQzLjA5NDYgNTkuOTIxNyAzMS4xMzEgNjYuMzY3IDI4LjgxODRDNzIuODExNiAyNi41MDYxIDc1LjA0NzMgMjYuNDIzIDgwLjUzMTcgMjguNDMyNEM4Ni4wMTY2IDMwLjQ0MTcgMTE0LjY1OSA0MS44NDE4IDEyMC4wNzkgNDMuODI3NUMxMjUuNTAxIDQ1LjgxMjggMTI1LjcwOSA0Ny40NSAxMjAuMTQ3IDUwLjM0OVoiIGZpbGw9IiNDNjMwMkIiLz4KPHBhdGggZD0iTTg0Ljg1NDEgNDAuMDk5NEw3NS44OTI2IDQxLjAyOThMNzMuODg2NSA0NS44NTdMNzAuNjQ2MyA0MC40NzAzTDYwLjI5ODMgMzkuNTQwNEw2OC4wMTk3IDM2Ljc1NThMNjUuNzAzIDMyLjQ4MTRMNzIuOTMyMSAzNS4zMDg4TDc5Ljc0NzEgMzMuMDc3NUw3Ny45MDUyIDM3LjQ5NzJMODQuODU0MSA0MC4wOTk0Wk03My4zNTE1IDYzLjUxODRMNTYuNjI2NiA1Ni41ODE2TDgwLjU5MiA1Mi45MDI5TDczLjM1MTUgNjMuNTE4NFpNNTAuMTYzNyA0Mi43ODI2QzU3LjIzODEgNDIuNzgyNiA2Mi45NzMgNDUuMDA1NyA2Mi45NzMgNDcuNzQ3NUM2Mi45NzMgNTAuNDkwMSA1Ny4yMzgxIDUyLjcxMjggNTAuMTYzNyA1Mi43MTI4QzQzLjA4OTMgNTIuNzEyOCAzNy4zNTQ1IDUwLjQ4OTcgMzcuMzU0NSA0Ny43NDc1QzM3LjM1NDUgNDUuMDA1NyA0My4wODkzIDQyLjc4MjYgNTAuMTYzNyA0Mi43ODI2WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTk1LjQ0MzQgNDEuNDE3NEwxMDkuNjI3IDQ3LjAyMjRMOTUuNDU1NiA1Mi42MjJMOTUuNDQzNCA0MS40MTc0WiIgZmlsbD0iIzYyMUIxQyIvPgo8cGF0aCBkPSJNNzkuNzUyOSA0Ny42MjYxTDk1LjQ0NDkgNDEuNDE4OUw5NS40NTcxIDUyLjYyMzZMOTMuOTE4NCA1My4yMjU0TDc5Ljc1MjkgNDcuNjI2MVoiIGZpbGw9IiM5QTI5MjgiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl82ODNfMzIxMyIgeDE9IjE4OSIgeTE9IjIxMC41IiB4Mj0iMCIgeTI9IjAiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0E4MDAwMCIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNGRkNGQ0YiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "version"], ["spec", "authEnabled"]] + secrets: + exclude: [] + include: + - resourceNames: + - redis-{{ .name }}-auth + services: + exclude: [] + include: + - resourceNames: + - rfs-redis-{{ .name }} + - rfrm-redis-{{ .name }} + - rfrs-redis-{{ .name }} + - redis-{{ .name }}-external-lb diff --git a/packages/system/redis-rd/templates/cozyrd.yaml b/packages/system/redis-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/redis-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/redis-rd/values.yaml b/packages/system/redis-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/redis-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/reloader/Makefile b/packages/system/reloader/Makefile index 378dc23c..6dc1f004 100644 --- a/packages/system/reloader/Makefile +++ b/packages/system/reloader/Makefile @@ -1,7 +1,7 @@ export NAME=reloader export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/seaweedfs-rd/Chart.yaml b/packages/system/seaweedfs-rd/Chart.yaml new file mode 100644 index 00000000..5799783b --- /dev/null +++ b/packages/system/seaweedfs-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: seaweedfs-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/seaweedfs-rd/Makefile b/packages/system/seaweedfs-rd/Makefile new file mode 100644 index 00000000..b4c5a2da --- /dev/null +++ b/packages/system/seaweedfs-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=seaweedfs-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/seaweedfs-rd/cozyrds/seaweedfs.yaml b/packages/system/seaweedfs-rd/cozyrds/seaweedfs.yaml new file mode 100644 index 00000000..8b23b9ed --- /dev/null +++ b/packages/system/seaweedfs-rd/cozyrds/seaweedfs.yaml @@ -0,0 +1,42 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: seaweedfs +spec: + application: + kind: SeaweedFS + singular: seaweedfs + plural: seaweedfses + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"host":{"description":"The hostname used to access SeaweedFS externally (defaults to 's3' subdomain for the tenant host).","type":"string","default":""},"topology":{"description":"The topology of the SeaweedFS cluster.","type":"string","default":"Simple","enum":["Simple","MultiZone","Client"]},"replicationFactor":{"description":"Replication factor: number of replicas for each volume in the SeaweedFS cluster.","type":"integer","default":2},"db":{"description":"Database configuration.","type":"object","default":{},"properties":{"replicas":{"description":"Number of database replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"Number of CPU cores allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Amount of memory allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume size.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""}}},"master":{"description":"Master service configuration.","type":"object","default":{},"properties":{"replicas":{"description":"Number of master replicas.","type":"integer","default":3},"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"Number of CPU cores allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Amount of memory allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}},"filer":{"description":"Filer service configuration.","type":"object","default":{},"properties":{"grpcHost":{"description":"The hostname used to expose or access the filer service externally.","type":"string","default":""},"grpcPort":{"description":"The port used to access the filer service externally.","type":"integer","default":443},"replicas":{"description":"Number of filer replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"Number of CPU cores allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Amount of memory allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"whitelist":{"description":"A list of IP addresses or CIDR ranges that are allowed to access the filer service.","type":"array","default":[],"items":{"type":"string"}}}},"volume":{"description":"Volume service configuration.","type":"object","default":{},"properties":{"diskType":{"description":"SeaweedFS disk type tag for the default volume servers (e.g., \"hdd\", \"ssd\").","type":"string","default":""},"pools":{"description":"A map of storage pools. Each pool creates a separate Volume StatefulSet with its own disk type.","type":"object","default":{},"additionalProperties":{"type":"object","required":["diskType"],"properties":{"diskType":{"description":"SeaweedFS disk type tag (e.g., \"ssd\", \"hdd\", \"nvme\").","type":"string"},"replicas":{"description":"Number of volume replicas. Defaults to volume.replicas (Simple) or zone.replicas/volume.replicas (MultiZone).","type":"integer"},"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","properties":{"cpu":{"description":"Number of CPU cores allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Amount of memory allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. Defaults to volume.resourcesPreset.","type":"string","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume size. Defaults to volume.size (Simple) or zone.size/volume.size (MultiZone).","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"Kubernetes StorageClass for the pool. Defaults to volume.storageClass.","type":"string"}}}},"replicas":{"description":"Number of volume replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"Number of CPU cores allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Amount of memory allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume size.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"zones":{"description":"A map of zones for MultiZone topology. Each zone can have its own number of replicas and size.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"dataCenter":{"description":"SeaweedFS data center name for this zone. Defaults to the zone name.","type":"string"},"nodeSelector":{"description":"YAML nodeSelector for this zone (default: topology.kubernetes.io/zone: ).","type":"string"},"pools":{"description":"A map of storage pools for this zone. Each pool creates a separate Volume StatefulSet per zone.","type":"object","additionalProperties":{"type":"object","required":["diskType"],"properties":{"diskType":{"description":"SeaweedFS disk type tag (e.g., \"ssd\", \"hdd\", \"nvme\").","type":"string"},"replicas":{"description":"Number of volume replicas. Defaults to volume.replicas (Simple) or zone.replicas/volume.replicas (MultiZone).","type":"integer"},"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","properties":{"cpu":{"description":"Number of CPU cores allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Amount of memory allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted. Defaults to volume.resourcesPreset.","type":"string","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume size. Defaults to volume.size (Simple) or zone.size/volume.size (MultiZone).","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"Kubernetes StorageClass for the pool. Defaults to volume.storageClass.","type":"string"}}}},"replicas":{"description":"Number of replicas in the zone.","type":"integer"},"size":{"description":"Zone storage size.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store zone data. Defaults to volume.storageClass.","type":"string"}}}}}},"s3":{"description":"S3 service configuration.","type":"object","default":{},"properties":{"replicas":{"description":"Number of S3 replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"Number of CPU cores allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Amount of memory allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"small","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]}}}}} + release: + prefix: "" + labels: + sharding.fluxcd.io/key: tenants + internal.cozystack.io/tenantmodule: "true" + chartRef: + kind: ExternalArtifact + name: cozystack-seaweedfs-application-default-seaweedfs + namespace: cozy-system + dashboard: + category: Administration + singular: SeaweedFS + plural: SeaweedFS + name: seaweedfs + description: Seaweedfs + module: true + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82NzlfMTkxMCkiLz4KPHBhdGggZD0iTTEzOC42ODUgMTIxLjA1N0MxMzguNjg1IDEyNi42NTIgMTM2LjQ2MiAxMzIuMDE3IDEzMi41MDQgMTM1Ljk3M0MxMjguNTQ3IDEzOS45MjkgMTIzLjE3OSAxNDIuMTUxIDExNy41ODIgMTQyLjE1MUMxMTEuOTg1IDE0Mi4xNTEgMTA2LjYxOCAxMzkuOTI5IDEwMi42NiAxMzUuOTczQzk4LjcwMjggMTMyLjAxNyA5Ni40Nzk1IDEyNi42NTIgOTYuNDc5NSAxMjEuMDU3Qzk2LjQ3OTUgMTE4LjI4NyA5Ny4wMjUzIDExNS41NDQgOTguMDg1OCAxMTIuOTg1Qzk5LjE0NjMgMTEwLjQyNSAxMDAuNzAxIDEwOC4xIDEwMi42NiAxMDYuMTQxQzEwNC42MiAxMDQuMTgyIDEwNi45NDYgMTAyLjYyOSAxMDkuNTA3IDEwMS41NjlDMTEyLjA2NyAxMDAuNTA5IDExNC44MTEgOTkuOTYyOSAxMTcuNTgyIDk5Ljk2MjlDMTIwLjM1MyA5OS45NjI5IDEyMy4wOTggMTAwLjUwOSAxMjUuNjU4IDEwMS41NjlDMTI4LjIxOCAxMDIuNjI5IDEzMC41NDQgMTA0LjE4MiAxMzIuNTA0IDEwNi4xNDFDMTM0LjQ2NCAxMDguMSAxMzYuMDE4IDExMC40MjUgMTM3LjA3OSAxMTIuOTg1QzEzOC4xMzkgMTE1LjU0NCAxMzguNjg1IDExOC4yODcgMTM4LjY4NSAxMjEuMDU3WiIgZmlsbD0idXJsKCNwYWludDFfcmFkaWFsXzY3OV8xOTEwKSIvPgo8cGF0aCBkPSJNMTEwLjMzNiAxMjYuMTQ3SDEyMy42OFYxMzYuODIzSDExMC4zMzZWMTI2LjE0N1oiIGZpbGw9IiMwRjVFOUMiLz4KPHBhdGggZD0iTTExOS4yNyAxMTIuMjk0QzExOS4yNyAxMTIuNzE0IDExOS4xNzggMTEzLjEzMSAxMTkgMTEzLjUxOUMxMTguODIxIDExMy45MDggMTE4LjU2IDExNC4yNjEgMTE4LjIzIDExNC41NThDMTE3LjkwMSAxMTQuODU1IDExNy41MDkgMTE1LjA5MSAxMTcuMDc5IDExNS4yNTJDMTE2LjY0OCAxMTUuNDEzIDExNi4xODYgMTE1LjQ5NiAxMTUuNzIgMTE1LjQ5NkMxMTQuNzc4IDExNS40OTYgMTEzLjg3NSAxMTUuMTU4IDExMy4yMSAxMTQuNTU4QzExMi41NDQgMTEzLjk1NyAxMTIuMTcgMTEzLjE0MyAxMTIuMTcgMTEyLjI5NEMxMTIuMTcgMTExLjQ0NSAxMTIuNTQ0IDExMC42MyAxMTMuMjEgMTEwLjAzQzExMy44NzUgMTA5LjQyOSAxMTQuNzc4IDEwOS4wOTIgMTE1LjcyIDEwOS4wOTJDMTE2LjE4NiAxMDkuMDkyIDExNi42NDggMTA5LjE3NSAxMTcuMDc5IDEwOS4zMzZDMTE3LjUwOSAxMDkuNDk2IDExNy45MDEgMTA5LjczMiAxMTguMjMgMTEwLjAzQzExOC41NiAxMTAuMzI3IDExOC44MjEgMTEwLjY4IDExOSAxMTEuMDY4QzExOS4xNzggMTExLjQ1NyAxMTkuMjcgMTExLjg3MyAxMTkuMjcgMTEyLjI5NFoiIGZpbGw9IiM1OTY4NkYiLz4KPHBhdGggZD0iTTEyOC4xMSAxMTQuMTAzQzEyOC4xMSAxMTQuOTUzIDEyNy43MzYgMTE1Ljc2NyAxMjcuMDcgMTE2LjM2OEMxMjYuNDA0IDExNi45NjggMTI1LjUwMSAxMTcuMzA1IDEyNC41NiAxMTcuMzA1QzEyNC4wOTQgMTE3LjMwNSAxMjMuNjMyIDExNy4yMjMgMTIzLjIwMSAxMTcuMDYyQzEyMi43NzEgMTE2LjkwMSAxMjIuMzc5IDExNi42NjUgMTIyLjA1IDExNi4zNjhDMTIxLjcyIDExNi4wNyAxMjEuNDU4IDExNS43MTcgMTIxLjI4IDExNS4zMjlDMTIxLjEwMiAxMTQuOTQgMTIxLjAxIDExNC41MjQgMTIxLjAxIDExNC4xMDNDMTIxLjAxIDExMy42ODMgMTIxLjEwMiAxMTMuMjY2IDEyMS4yOCAxMTIuODc4QzEyMS40NTggMTEyLjQ5IDEyMS43MiAxMTIuMTM3IDEyMi4wNSAxMTEuODM5QzEyMi4zNzkgMTExLjU0MiAxMjIuNzcxIDExMS4zMDYgMTIzLjIwMSAxMTEuMTQ1QzEyMy42MzIgMTEwLjk4NCAxMjQuMDk0IDExMC45MDEgMTI0LjU2IDExMC45MDFDMTI1LjUwMSAxMTAuOTAxIDEyNi40MDQgMTExLjIzOSAxMjcuMDcgMTExLjgzOUMxMjcuNzM2IDExMi40NCAxMjguMTEgMTEzLjI1NCAxMjguMTEgMTE0LjEwM1oiIGZpbGw9IiM1OTY4NkYiLz4KPHBhdGggZD0iTTEyMi4zMzMgMTE4Ljk3NkMxMjIuMzMzIDExOS44MjYgMTIxLjk1OCAxMjAuNjQgMTIxLjI5MyAxMjEuMjQxQzEyMC42MjcgMTIxLjg0MSAxMTkuNzI0IDEyMi4xNzggMTE4Ljc4MiAxMjIuMTc4QzExOC4zMTYgMTIyLjE3OCAxMTcuODU1IDEyMi4wOTYgMTE3LjQyNCAxMjEuOTM1QzExNi45OTMgMTIxLjc3NCAxMTYuNjAyIDEyMS41MzggMTE2LjI3MiAxMjEuMjQxQzExNS45NDMgMTIwLjk0MyAxMTUuNjgxIDEyMC41OSAxMTUuNTAzIDEyMC4yMDJDMTE1LjMyNCAxMTkuODEzIDExNS4yMzIgMTE5LjM5NyAxMTUuMjMyIDExOC45NzZDMTE1LjIzMiAxMTguNTU2IDExNS4zMjQgMTE4LjE0IDExNS41MDMgMTE3Ljc1MUMxMTUuNjgxIDExNy4zNjMgMTE1Ljk0MyAxMTcuMDEgMTE2LjI3MiAxMTYuNzEyQzExNi42MDIgMTE2LjQxNSAxMTYuOTkzIDExNi4xNzkgMTE3LjQyNCAxMTYuMDE4QzExNy44NTUgMTE1Ljg1NyAxMTguMzE2IDExNS43NzQgMTE4Ljc4MiAxMTUuNzc0QzExOS43MjQgMTE1Ljc3NCAxMjAuNjI3IDExNi4xMTIgMTIxLjI5MyAxMTYuNzEyQzEyMS45NTggMTE3LjMxMyAxMjIuMzMzIDExOC4xMjcgMTIyLjMzMyAxMTguOTc2WiIgZmlsbD0iIzU5Njg2RiIvPgo8cGF0aCBkPSJNMTE1LjMwOCAxMjEuOTA1QzExMy43MzUgMTIxLjQyNiAxMTUuNzA3IDEyMC42OCAxMTUuNDI5IDEyMC41NzNDMTE0LjY1MyAxMjAuMjc2IDExNS43MyAxMTkuMzMzIDExNi43NCAxMTguNTM5QzExNy42MjggMTE3Ljg0MSAxMTcuNjU5IDExNy44MzkgMTE3Ljg5MiAxMTguNDY4QzExOC4wMjQgMTE4LjgyMyAxMTguMzcxIDExOS4yMDYgMTE4LjY2NSAxMTkuMzE5QzExOS4yODkgMTE5LjU1OCAxMjAuOTUxIDExOS4yNjkgMTIwLjk1MSAxMTguODM1QzEyMC45NTEgMTE4LjIyMyAxMjEuNDE1IDExOC42OTkgMTIxLjc5NCAxMTkuNTMxQzEyMi40NTcgMTIwLjk4NyAxMjIuNDM3IDEyMi40NzIgMTIxLjQ1IDEyMi40NzJDMTIwLjg1OSAxMjIuNDcyIDEyMC4zMSAxMjIuNjkxIDEyMC4xOSAxMjMuMTQ3QzExNS4wNDYgMTI0LjYgMTE2LjQ3MSAxMjMuMjg0IDExNS4zMDggMTIxLjkwNVpNMTIzLjA5NCAxMTguMDU0QzEyMS42MDkgMTE3LjQ2NiAxMjAuNTQ3IDExNC44MzggMTIwLjU0NyAxMTMuMzA5QzEyMC41NDcgMTExLjMyMyAxMjIuNTQxIDEwOS4wOTUgMTI0LjMxNyAxMDkuMDk1QzEyOC4zMTUgMTA5LjA5NSAxMzAuNjg0IDExMi4yNjEgMTI4LjgzOCAxMTguNDA5QzEyOC4zODUgMTE5LjkxOSAxMjMuOTMzIDExOC4zODcgMTIzLjA5NCAxMTguMDU0Wk0xMjUuODY2IDExNS42NDlDMTI3LjU0NCAxMTQuNDc0IDEyNS44NTcgMTExLjc1NSAxMjMuOTgxIDExMi42MUMxMjIuNDc5IDExMy4yOTQgMTIzLjExOSAxMTYuMTE1IDEyNC43NyAxMTYuMTY0QzEyNC45NjEgMTE2LjE2OSAxMjUuNDU0IDExNS45MzggMTI1Ljg2NiAxMTUuNjQ5Wk0xMjQuMzM5IDExNC41NzlDMTIzLjc3MSAxMTQuMzgxIDEyMy44MDMgMTEzLjI1NiAxMjQuMzgzIDExMy4wMzRDMTI0LjkwMiAxMTIuODM1IDEyNS42MDQgMTEzLjM5OCAxMjUuNjA0IDExNC4wMTRDMTI1LjYwNCAxMTQuNDg5IDEyNC45MzYgMTE0Ljc4NyAxMjQuMzM5IDExNC41NzlaTTExMi4zMTkgMTE2Ljk4QzEwOS45NiAxMTUuNjcgMTEwLjI4NiAxMTEuMDA2IDExMi40MTcgMTA4Ljk2NUMxMTQuMzk2IDEwNy4wNjkgMTE4Ljc3OCAxMDcuMTAzIDExOS43NjQgMTA5LjQ2MkMxMjAuNDE1IDExMS4wMjEgMTIwLjIyOCAxMTIuNiAxMTkuMzk4IDExNC4wNzdDMTE4LjE5NCAxMTYuMjE5IDExNC4yNDIgMTE4LjA0OSAxMTIuMzE5IDExNi45OFpNMTE2LjU2IDExMy41OTNDMTE3LjMyNSAxMTIuOTAxIDExNy4yOTcgMTEyLjA2IDExNi41NzIgMTExLjI1OUMxMTUuNzc3IDExMC4zNzkgMTE0LjY5MiAxMTAuMzQ1IDExNC4wMzUgMTExLjM0N0MxMTMuNTI0IDExMi4xMjcgMTEzLjQzMSAxMTIuNTI4IDExMy45NDMgMTEzLjMwOUMxMTQuNTggMTE0LjI4IDExNS42NyAxMTQuMzk5IDExNi41NiAxMTMuNTkzWk0xMTQuMzc0IDExMi4zNEMxMTQuMTI4IDExMS42OTggMTE0Ljk4NSAxMTAuOTgxIDExNS42OCAxMTEuMjQ3QzExNS45NzQgMTExLjM2IDExNi4xNjQgMTExLjcxOCAxMTYuMTAyIDExMi4wNDRDMTE1Ljk2MSAxMTIuNzg1IDExNC42MzIgMTEzLjAxMiAxMTQuMzc0IDExMi4zNFoiIGZpbGw9IiNEM0Q2REEiLz4KPHBhdGggZD0iTTExOC40NjMgMTIxLjAwOEwxMTcuOTQ1IDEyMC43OEMxMTcuNTEgMTIwLjY4NSAxMTcuMjMxIDEyMS4xMDcgMTE3LjEzNiAxMjEuNTQzTDExNi44ODEgMTIyLjcwOUMxMTYuNzg2IDEyMy4xNDUgMTE3LjA2MSAxMjMuNTcxIDExNy40OTYgMTIzLjY2NkwxMTguNDQ3IDEyMy44NzRDMTE4Ljg4MiAxMjMuOTY5IDExOS4zMTEgMTIzLjY5NCAxMTkuNDA2IDEyMy4yNTlMMTE5LjY4NSAxMjEuNTU2QzExOS43OCAxMjEuMTIgMTE5LjQ3OSAxMjEuMjI4IDExOS4wNDMgMTIxLjEzM0wxMTguNjI4IDEyMS4wNDNDMTE4LjU3MyAxMjEuMzIxIDExOC41MTYgMTIxLjYxMyAxMTguNDcxIDEyMS44MzNDMTE4LjQzOCAxMjEuOTk4IDExOC40MDcgMTIyLjE0OCAxMTguMzc5IDEyMi4yODJDMTE4LjM1MSAxMjIuNDE1IDExOC4zMjcgMTIyLjUzMyAxMTguMzA1IDEyMi42MzVDMTE4LjI4MiAxMjIuNzM4IDExOC4yNjIgMTIyLjgyNSAxMTguMjQ1IDEyMi44OTdDMTE4LjIyOCAxMjIuOTY5IDExOC4yMTQgMTIzLjAyNSAxMTguMjAyIDEyMy4wNjhDMTE4LjE5NiAxMjMuMDg5IDExOC4xOTMgMTIzLjEwNyAxMTguMTg4IDEyMy4xMjFDMTE4LjE4MyAxMjMuMTM1IDExOC4xNzggMTIzLjE0NSAxMTguMTc1IDEyMy4xNTJDMTE4LjE3MyAxMjMuMTU1IDExOC4xNzIgMTIzLjE1NiAxMTguMTcxIDEyMy4xNThDMTE4LjE3IDEyMy4xNTkgMTE4LjE2OCAxMjMuMTYgMTE4LjE2NyAxMjMuMTZMMTE4LjE2NSAxMjMuMTU4QzExOC4xNjQgMTIzLjE1NiAxMTguMTYzIDEyMy4xNTIgMTE4LjE2MyAxMjMuMTQ4QzExOC4xNjIgMTIzLjE0IDExOC4xNjIgMTIzLjEyOSAxMTguMTYzIDEyMy4xMTVDMTE4LjE2MyAxMjMuMSAxMTguMTYzIDEyMy4wODMgMTE4LjE2NSAxMjMuMDYxQzExOC4xNjggMTIzLjAxOCAxMTguMTc1IDEyMi45NjEgMTE4LjE4MyAxMjIuODkxQzExOC4xOTIgMTIyLjgyIDExOC4yMDMgMTIyLjczNiAxMTguMjE2IDEyMi42NEMxMTguMjI5IDEyMi41NDMgMTE4LjI0NiAxMjIuNDMxIDExOC4yNjQgMTIyLjMwOEMxMTguMjgxIDEyMi4xODUgMTE4LjMwMSAxMjIuMDUxIDExOC4zMjMgMTIxLjkwM0MxMTguMzQ2IDEyMS43NTUgMTE4LjM3IDEyMS41OTIgMTE4LjM5NyAxMjEuNDE5QzExOC40MTYgMTIxLjI5OSAxMTguNDQyIDEyMS4xNCAxMTguNDYzIDEyMS4wMDhaIiBmaWxsPSIjOThDNkQ4Ii8+CjxwYXRoIGQ9Ik0xMDMuNTgxIDExNi4zNjdDMTAzLjQ3OSAxMTYuMTAzIDEwMy42MjIgMTE1LjY5OSAxMDMuODk4IDExNS40NjlDMTA0LjMwMyAxMTUuMTMzIDEwNC41MDQgMTE1LjE1NSAxMDQuOTMgMTE1LjU4MUMxMDUuMjIgMTE1Ljg3MSAxMDUuMzU1IDExNi4yNzYgMTA1LjIzIDExNi40NzlDMTA0LjkwMiAxMTcuMDA5IDEwMy43OTggMTE2LjkzNCAxMDMuNTgxIDExNi4zNjdaIiBmaWxsPSIjOThDNkQ4Ii8+CjxwYXRoIGQ9Ik0xMDYuMDM4IDExMi4yODFDMTA1LjY4IDExMS44NDkgMTA1LjcwMiAxMTEuNjYgMTA2LjE2NSAxMTEuMTk3QzEwNi42ODkgMTEwLjY3NCAxMDYuNzY0IDExMC42NzQgMTA3LjI4NyAxMTEuMTk3QzEwNy43NTEgMTExLjY2IDEwNy43NzMgMTExLjg0OSAxMDcuNDE1IDExMi4yODFDMTA3LjE3NiAxMTIuNTY4IDEwNi44NjYgMTEyLjgwMyAxMDYuNzI2IDExMi44MDNDMTA2LjU4NiAxMTIuODAzIDEwNi4yNzcgMTEyLjU2OCAxMDYuMDM4IDExMi4yODFaIiBmaWxsPSIjOThDNkQ4Ii8+CjxwYXRoIGQ9Ik0xMDYuMDM4IDEwNy4yMjRDMTA1LjY4MiAxMDYuNzk1IDEwNS42OTQgMTA2LjYxMiAxMDYuMTA2IDEwNi4yMDFDMTA2LjY1IDEwNS42NTcgMTA3LjczOCAxMDUuODggMTA3LjczOCAxMDYuNTM2QzEwNy43MzggMTA2Ljk3IDEwNy4wNzIgMTA3Ljc0NyAxMDYuNyAxMDcuNzQ3QzEwNi41NzUgMTA3Ljc0NyAxMDYuMjc3IDEwNy41MTIgMTA2LjAzOCAxMDcuMjI0WiIgZmlsbD0iIzk4QzZEOCIvPgo8cGF0aCBkPSJNMTE3Ljk1NSAxMzYuNTQxQzExNC41NzggMTM2LjExMSAxMTAuMDg3IDEzNC44ODEgMTA5LjQxIDEzNC4yNzRDMTA4LjEyMyAxMzMuMTE5IDEwOC45NDIgMTI3Ljg3OSAxMTAuNDY2IDEyNi41NEMxMTEuMzg3IDEyNS43MzEgMTE1LjAzOSAxMjQuNjYzIDExNy4xODIgMTI1LjE2OUMxMTkuNjQyIDEyNS43NDkgMTIzLjkzMiAxMjguNjQ4IDEyNC4yNSAxMjkuNTA4QzEyNC42MjUgMTMwLjUyMiAxMjQuMDQ4IDEzNC41NDEgMTIzLjMyMyAxMzUuNTM2QzEyMi42OTQgMTM2LjM5OSAxMjAuMzI1IDEzNi44NDMgMTE3Ljk1NSAxMzYuNTQxWk0xMjAuNTQgMTM0LjA4NEMxMjEuMjk3IDEzMy4zOTkgMTIxLjM0MiAxMzEuODQyIDEyMC42MjcgMTMxLjEyNkMxMTkuNDkgMTI5Ljk4OSAxMTcuMTEyIDEzMC44NjkgMTE3LjExMiAxMzIuNDI4QzExNy4xMTIgMTM0LjMwNCAxMTkuMTg5IDEzNS4zMDcgMTIwLjU0IDEzNC4wODRaTTExOC41ODIgMTMzLjEyNUMxMTguMzExIDEzMi40MTkgMTE4LjY4IDEzMS42MDggMTE5LjI3MiAxMzEuNjA4QzEyMCAxMzEuNjA4IDEyMC4yMjggMTMyLjE3MyAxMTkuODEyIDEzMi45NDlDMTE5LjM4MSAxMzMuNzU1IDExOC44NTMgMTMzLjgzIDExOC41ODIgMTMzLjEyNVpNMTE2LjQyMiAxMzMuMTQzQzExNy4wOTQgMTMyLjMzMyAxMTYuNzExIDEzMS4xNzYgMTE1LjY4MSAxMzAuOTAyQzExNC41ODEgMTMwLjYxIDExNC4wNTIgMTMxLjE4MyAxMTQuODY5IDEzMS43OEMxMTUuNjgzIDEzMi4zNzUgMTE1LjU1MSAxMzIuNjc5IDExNC41MzMgMTMyLjU1N0MxMTMuMzI3IDEzMi40MTMgMTEyLjgzMyAxMzEuNTY2IDExMy4yNTQgMTMwLjM2MkMxMTMuNjgxIDEyOS4xNDIgMTE1LjE5NyAxMjguODYzIDExNS43NTMgMTI5LjkwMkMxMTYuMTkzIDEzMC43MjUgMTE2LjYyNyAxMzAuNzkzIDExNi45IDEzMC4wODNDMTE3LjIyOSAxMjkuMjI0IDExNS45MTQgMTI4LjIzNyAxMTQuNDQgMTI4LjIzN0MxMTEuOTkzIDEyOC4yMzcgMTEwLjgxNiAxMzEuMDc0IDExMi41NDYgMTMyLjgwM0MxMTMuNSAxMzMuNzU4IDExNS43NDkgMTMzLjk1NSAxMTYuNDIyIDEzMy4xNDNaIiBmaWxsPSIjN0JBOUI5Ii8+CjxwYXRoIGQ9Ik0xMjAuMTE4IDEzOC41OTJDMTE4Ljc1MSAxMzcuMjk3IDEyMS45MTYgMTM2LjA5NiAxMjMuNjA2IDEzOC4yODNDMTI0LjQ2OSAxMzkuMzIyIDEyMi44NTMgMTM5Ljk3NiAxMjAuMTE4IDEzOC41OTJaTTEwNi4xMiAxMzUuNjU4QzEwNC43NTEgMTM0LjI4OSAxMDYuOTYzIDEzMy45MDQgMTA4LjU4MSAxMzUuMjNMMTA5Ljk0MSAxMzUuOTJMMTA4LjA1OSAxMzYuMDYxQzEwNy4yMTUgMTM2LjA2MiAxMDYuMzQzIDEzNS44ODEgMTA2LjEyIDEzNS42NThWMTM1LjY1OFpNMTI1LjM2MyAxMjcuODY2QzEyNS4wODIgMTI3LjQxIDEyOC4zMzMgMTI2LjI2NyAxMjguNjg4IDEyNi40ODZDMTI4Ljg0NiAxMjYuNTg0IDEyOC45NzUgMTI3LjMzNyAxMjguOTc1IDEyOC4xNjFDMTI4Ljk3NSAxMjkuMjM5IDEyOC44NCAxMjkuNjU4IDEyOC40OSAxMjkuNjU4QzEyOC4yMjIgMTI5LjY1OCAxMjUuNDc2IDEyOC4wNDcgMTI1LjM2MyAxMjcuODY2Wk0xMTguNjQxIDEyMS4wOTVDMTE0Ljg3MSAxMjAuNzUzIDExNS4zNzggMTE5LjMyNyAxMTYuMzYxIDExOC40OTlDMTE2LjkyOCAxMTguMDIxIDExNy4zNCAxMTcuNzc5IDExNy45MTMgMTE3LjY2N0MxMTcuOTEzIDExNy42NjcgMTE3Ljg3MiAxMTkuMDQ2IDExOC42NjYgMTE5LjMxOUMxMTkuMjk3IDExOS41MzYgMTIwLjI3OCAxMTkuMDY0IDEyMC40NzEgMTE4LjY3NUMxMjIuMTg4IDExNS4yMDEgMTIxLjQxNSAxMTguNjk5IDEyMS43OTQgMTE5LjUzMkMxMjMuMjM4IDEyNC4wMDcgMTIwLjE4OCAxMjEuNzMgMTE4LjY0MSAxMjEuMDk1Wk0xMDQuOTEyIDEyMS4yM0MxMDQuMjQyIDEyMC40ODcgMTAzLjY5MyAxMTkuNzI5IDEwMy42OTMgMTE5LjU0NEMxMDMuNjkzIDExOS4xMTYgMTA0Ljc0NiAxMTkuMTEyIDEwNS44NjMgMTE5LjUzN0MxMDYuNTkzIDExOS44MTQgMTEwLjM0NyAxMjAuMDA2IDExMC4zNDcgMTIxLjE1M0MxMTAuMzQ3IDEyMS44OTkgMTA4Ljg5IDEyMy43NjIgMTA4LjcyNiAxMjMuNzYyQzEwOC41NjMgMTIzLjc2MiAxMDUuNTgzIDEyMS45NzIgMTA0LjkxMiAxMjEuMjNaIiBmaWxsPSIjQTZCM0MyIi8+CjxwYXRoIGQ9Ik0xMTguNDYzIDEyMS4wMDhDMTE4LjQ0MiAxMjEuMTQgMTE4LjQxNiAxMjEuMjk5IDExOC4zOTcgMTIxLjQxOUMxMTguMzcgMTIxLjU5MiAxMTguMzQ1IDEyMS43NTUgMTE4LjMyMyAxMjEuOTAzQzExOC4zIDEyMi4wNTEgMTE4LjI4MSAxMjIuMTg1IDExOC4yNjMgMTIyLjMwOEMxMTguMjQ1IDEyMi40MzEgMTE4LjIyOSAxMjIuNTQyIDExOC4yMTYgMTIyLjYzOUMxMTguMjAzIDEyMi43MzYgMTE4LjE5MSAxMjIuODIgMTE4LjE4MyAxMjIuODlDMTE4LjE3NSAxMjIuOTYxIDExOC4xNjggMTIzLjAxOCAxMTguMTY1IDEyMy4wNjFDMTE4LjE2MyAxMjMuMDgzIDExOC4xNjQgMTIzLjEgMTE4LjE2MyAxMjMuMTE1QzExOC4xNjIgMTIzLjEyOSAxMTguMTYyIDEyMy4xNCAxMTguMTYzIDEyMy4xNDhDMTE4LjE2MyAxMjMuMTUyIDExOC4xNjQgMTIzLjE1NiAxMTguMTY1IDEyMy4xNThMMTE4LjE2NyAxMjMuMTZDMTE4LjE2OCAxMjMuMTYgMTE4LjE3IDEyMy4xNTkgMTE4LjE3MSAxMjMuMTU4QzExOC4xNzIgMTIzLjE1NyAxMTguMTczIDEyMy4xNTUgMTE4LjE3NSAxMjMuMTUyQzExOC4xNzggMTIzLjE0NSAxMTguMTgyIDEyMy4xMzUgMTE4LjE4NyAxMjMuMTIxQzExOC4xOTIgMTIzLjEwNyAxMTguMTk2IDEyMy4wODkgMTE4LjIwMiAxMjMuMDY3QzExOC4yMTMgMTIzLjAyNSAxMTguMjI4IDEyMi45NjkgMTE4LjI0NSAxMjIuODk3QzExOC4yNjIgMTIyLjgyNSAxMTguMjgyIDEyMi43MzggMTE4LjMwNSAxMjIuNjM1QzExOC4zMjcgMTIyLjUzMyAxMTguMzUxIDEyMi40MTUgMTE4LjM3OSAxMjIuMjgxQzExOC40MDYgMTIyLjE0OCAxMTguNDM4IDEyMS45OTggMTE4LjQ3MSAxMjEuODMzQzExOC41MTYgMTIxLjYxMyAxMTguNTczIDEyMS4zMjEgMTE4LjYyOCAxMjEuMDQzTDExOC40NjMgMTIxLjAwOFoiIGZpbGw9IiM0QzlDQkIiLz4KPHBhdGggZD0iTTMwLjk5ODYgMTQyLjY3M0MyNi40NDg5IDE0MC45MTYgMjEuNDY2NCAxMzYuODA1IDE4Ljc5MjEgMTMyLjYwM0MxNS40MDUzIDEyNy4yODEgMTQuNDA1MiAxMjMuNDE5IDE1LjA2MzYgMTE4LjIwM0MxNS42ODA2IDExMy4zMTUgMTcuMzU1OCAxMTAuNTU3IDIyLjIyMzIgMTA2LjQxM0MyOS4wNDE3IDEwMC42MDggMzQuNDg0NiA5Ny45Nzk5IDQwLjU5NDcgOTcuNTQxNUM0OS44MjEyIDk2Ljg3OTQgNTUuMDk3OCA5OS44MTA5IDU3LjY0NjUgMTA3LjAxNUM1OC41MDQzIDEwOS40MzkgNTguNjg1NiAxMTUuNTcgNTguMDU0NCAxMjAuODA5QzU3LjgzMTEgMTIyLjY2MyA1Ny40Nzg5IDEyNi4wNTUgNTcuMjcxOCAxMjguMzQ4QzU2LjU0NjcgMTM2LjM3NSA1NC40MTQ3IDE0MC40MTcgNDkuNjI1MyAxNDIuODQzQzQ4LjI5NzkgMTQzLjUxNiA0Ny43MTk5IDE0My41NjEgNDAuNjkyNCAxNDMuNTM5QzMzLjUxNTEgMTQzLjUxNiAzMy4wODEgMTQzLjQ3OCAzMC45OTg2IDE0Mi42NzNaTTAuMDc5NTc2NSAxMDQuOTY1QzAuMDgxNTcyMyAxMDMuODUzIDAuMTQ0NDAzIDEwMy40MzggMC4yMTk0MjcgMTA0LjA0NEMwLjI5NDQ1MSAxMDQuNjUgMC4yOTI4OTkgMTA1LjU2IDAuMjE1OTk2IDEwNi4wNjdDMC4xMzkwNzkgMTA2LjU3MyAwLjA3NzY4MzggMTA2LjA3OCAwLjA3OTU3NjUgMTA0Ljk2NVpNMC4wMDE3MzM1MSAxMDIuMjRDMC4wMTc4OTkyIDEwMS44NDggMC4wOTc3ODk3IDEwMS43NjggMC4yMDUzOTggMTAyLjAzN0MwLjMwMjc3MiAxMDIuMjggMC4yOTA3OTcgMTAyLjU3MSAwLjE3ODc4NyAxMDIuNjgzQzAuMDY2Nzc0OCAxMDIuNzk1IC0wLjAxMjkwMjEgMTAyLjU5NiAwLjAwMTczMzUxIDEwMi4yNFpNMC4wMjgzNDQ0IDc1LjEzMjZDMC4wMjgzNDQ0IDc0LjY2OTEgMC4xMDQ4NTcgNzQuNDc5NSAwLjE5ODM2OSA3NC43MTEyQzAuMjkxODg0IDc0Ljk0MyAwLjI5MTg4NCA3NS4zMjIyIDAuMTk4MzY5IDc1LjU1MzlDMC4xMDQ4NTcgNzUuNzg1NyAwLjAyODM0NDQgNzUuNTk2MSAwLjAyODM0NDQgNzUuMTMyNloiIGZpbGw9InVybCgjcGFpbnQyX3JhZGlhbF82NzlfMTkxMCkiLz4KPHBhdGggZD0iTTM1LjMxMzMgMTEyLjU0NEwzNy45IDExMS4wOTFMMzkuMzUxNyAxMjEuNDZMMzkuMjQ4IDEyOC45MjZMMzUuMzcwMyAxMzAuODUxTDMyLjkyMjkgMTI2LjQzN0wzNS4zMTMzIDExMi41NDRaIiBmaWxsPSIjMzA2MEFEIi8+CjxwYXRoIGQ9Ik0zOC43Mjk1IDExNi42OUwzOS4zNTE2IDEyNC41NzFMNDMuMjkxOSAxMjUuOTE5TDQzLjM5NTYgMTA5LjIyNUw0MC4xODEyIDExMC4wNTRMMzguNzI5NSAxMTYuNjlaIiBmaWxsPSIjNjA2MzY4Ii8+CjxwYXRoIGQ9Ik0zNS4zNjk5IDEzMC44NTFDMzMuMDMyNCAxMjkuNzMgMjkuNzMwMSAxMjYuNDA4IDI4LjY2MjEgMTI0LjEwM0MyOC4wMzMyIDEyMi43NDUgMjcuNjM5NyAxMjIuMzEgMjYuODkyMyAxMjIuMTQ2QzI1Ljc4NzkgMTIxLjkwMyAyNS44MDg0IDEyMS45NzEgMjYuMzIxOCAxMjAuMjU4QzI2LjU5MzYgMTE5LjM1IDI2LjkwMzIgMTE4Ljk1NCAyNy4zNDA2IDExOC45NTRDMjcuNjg2MiAxMTguOTU0IDI5LjE1OTcgMTE3Ljg0MSAzMC42MTQ5IDExNi40OEMzMi4wNzAyIDExNS4xMTkgMzMuNzIyNiAxMTMuNjc3IDM0LjI4NjkgMTEzLjI3NUwzNS4zMTI5IDExMi41NDRMMzUuNjc2NyAxMTQuMjQxQzM3LjA0NDMgMTIwLjYxOCAzNy4wMjcgMTI0LjI2NiAzNS42MTk4IDEyNi4yNDNDMzQuNTUyMSAxMjcuNzQ0IDM0Ljg0MTcgMTI4LjM5MyAzNi41NzkxIDEyOC4zOTNDMzcuMzk3IDEyOC4zOTMgMzcuODIyMiAxMjguMTg1IDM4LjEzMDUgMTI3LjYzNEMzOC42NzQ4IDEyNi42NjMgMzguNjMxNSAxMjAuOTY4IDM4LjA0NTQgMTE2LjQyNkMzNy4zNDQ2IDExMC45OTUgMzcuMzEyNyAxMTEuMTY3IDM5LjE1NzggMTEwLjM5OEM0MC4wMzYgMTEwLjAzMSA0MC44MTggMTA5Ljc5NyA0MC44OTU1IDEwOS44NzdDNDAuOTczMSAxMDkuOTU2IDQwLjgxOTEgMTExLjIzNSA0MC41NTM0IDExMi43MThDMzkuNjA2NyAxMTguMDAzIDM5LjkzMTUgMTIzLjIzOCA0MS4yNzUyIDEyNC4zNTNDNDEuNjg1MSAxMjQuNjkzIDQxLjcyMzMgMTIzLjk2OSA0MS41NDUyIDExOS4yMzJDNDEuMzE1NiAxMTMuMTIzIDQxLjUxNzQgMTEwLjkxOSA0Mi40MDc1IDEwOS44MkM0Mi45MTk4IDEwOS4xODggNDMuMjEzIDEwOS4xMTYgNDQuNDk1OSAxMDkuMzFDNDYuOTU2NiAxMDkuNjgyIDQ2Ljk1MDYgMTA5LjY2OCA0Ni4yMDk5IDExMy4yNTRDNDUuODQ5NiAxMTQuOTk5IDQ1LjQ0ODMgMTE3LjIyNCA0NS4zMTggMTE4LjJMNDUuMDgxMiAxMTkuOTczTDQ1Ljk0NDYgMTE5LjY0NUM0Ni40MTk1IDExOS40NjUgNDcuNDQxMyAxMTguOTk0IDQ4LjIxNTMgMTE4LjU5OUw0OS42MjI2IDExNy44ODFMNDkuMzg5MyAxMTguNjdDNDkuMjYxIDExOS4xMDUgNDkuMDY3MiAxMjAuNzAxIDQ4Ljk1ODcgMTIyLjIxOEw0OC43NjE0IDEyNC45NzZMNDcuMTA5NSAxMjQuMzI1QzQ2LjIwMSAxMjMuOTY3IDQ1LjMxMTYgMTIzLjY3NCA0NS4xMzMxIDEyMy42NzRDNDQuOTQxIDEyMy42NzQgNDQuODA4NSAxMjUuNTMyIDQ0LjgwODUgMTI4LjIyNEM0NC44MDg1IDEzMS44OTEgNDQuNzE3MSAxMzIuNzc1IDQ0LjMzODYgMTMyLjc3NUM0MS4wMTk4IDEzMi4yOTUgMzguNzg0MiAxMzIuNDU4IDM1LjM2OTkgMTMwLjg1MVoiIGZpbGw9IiNFRUMyM0IiLz4KPHBhdGggZD0iTTQxLjE2MzkgMTMyLjQxOEM0MS4xNjM5IDEzMi4yODMgNDEuMzQwOCAxMzAuNTE1IDQxLjY2OTIgMTI4LjE0NUM0MS45OTc3IDEyNS43NzUgNDIuMzU3NyAxMjIuOTYxIDQyLjQ2OTIgMTIxLjg5M0M0Mi41ODA4IDEyMC44MjQgNDIuNzk2OSAxMjAuMDI3IDQyLjk0OTUgMTIwLjEyMUM0My42NDQzIDEyMC41NTEgNDQuMjkzOCAxMjkuMzc1IDQ0LjA0NzQgMTMxLjQyQzQzLjg5MDkgMTMyLjcxOSA0My42NTk1IDEzMi43MzcgNDMuMzAxOSAxMzIuNjc3QzQyLjY2MDIgMTMyLjU3IDQxLjkxMDEgMTMyLjUxMyA0MS4xNjM5IDEzMi40MThaTTMyLjU5NjkgMTIyLjczNUMzMS42ODEzIDEyMi41ODMgMzAuODI0MiAxMjEuNDQyIDMwLjgyNDIgMTIwLjM3NEMzMC44MjQyIDExOS40MDcgMzIuMjM4MSAxMTcuOTM3IDMzLjE2ODUgMTE3LjkzN0MzNC42NjY2IDExNy45MzcgMzUuODM5MiAxMjAuNTEzIDM0Ljk0ODQgMTIxLjg0N0MzNC41NTE3IDEyMi40NDEgMzMuNDE0NyAxMjIuODcgMzIuNTk2OSAxMjIuNzM1WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTExNC4wMjEgMTM3LjQ5OEMxMDcuMzE4IDEzNS43NCAxMDYuMjczIDEzNC4xMDQgMTA2LjYwOSAxMjUuODkxQzEwNi43MTYgMTIzLjI4MSAxMDYuODg1IDEyMC41MzkgMTA2Ljk4NiAxMTkuNzk3QzEwNy41NDUgMTE1LjY2NCAxMDguMzQyIDExMi4xNzMgMTA5LjA4NiAxMTAuNTk5QzEwOS43NDQgMTA5LjIwNiAxMDkuODQyIDEwOC43MTIgMTA5LjUzNSAxMDguMzQyQzEwOC40NSAxMDcuMDM1IDExMC4zNzEgMTA0Ljk5NSAxMTEuOTEgMTA1LjgxOUMxMTIuNDU3IDEwNi4xMTEgMTEyLjkxOCAxMDYuMDc3IDExMy45NDUgMTA1LjY2NUMxMTcuMDYyIDEwNC40MTkgMTIzLjExNyAxMDUuNTcxIDEyNi44MTQgMTA4LjExNUMxMjguMTQ5IDEwOS4wMzMgMTI4LjQ4NSAxMDkuMTM2IDEyOS4wMzggMTA4Ljc5MUMxMzAuNTIzIDEwNy44NjMgMTMyLjQ1MSAxMTAuNTczIDEzMS4yNSAxMTEuOUMxMzAuNzg3IDExMi40MTIgMTMwLjc1NSAxMTIuNzA1IDEzMS4wNjUgMTEzLjU5NkMxMzEuODUgMTE1Ljg0NiAxMzEuNzk0IDExNi4xMDQgMTI4LjAwNiAxMjcuNzE5QzEyNS41OCAxMzUuMTYgMTI0LjU0MyAxMzcuMzY1IDEyMy4yNjQgMTM3LjgxMUMxMjEuNjUzIDEzOC4zNzMgMTE2LjcyMyAxMzguMjA2IDExNC4wMjEgMTM3LjQ5OFpNMTIyLjU0MSAxMzUuMjI5QzEyMy4wMDMgMTM0LjU0MSAxMjMuMzU5IDEzMy4zMTMgMTIzLjUxMyAxMzEuODc4QzEyMy43OTQgMTI5LjI1IDEyMy44MTkgMTI5LjI4MyAxMjAuMzE3IDEyNy42MDFDMTE3LjY4NSAxMjYuMzM4IDExMy44MzMgMTI1Ljk3MiAxMTEuODU1IDEyNi43OThDMTEwLjgyOSAxMjcuMjI3IDExMC41OTUgMTI3LjU1NiAxMTAuMDU5IDEyOS4zMjdDMTA5LjExNiAxMzIuNDQzIDEwOS43MDMgMTM0LjMwOCAxMTEuODMyIDEzNC45NThDMTEzLjEzOSAxMzUuMzU3IDEyMC4wOSAxMzYuNDMgMTIwLjk4IDEzNi4zN0MxMjEuNTA0IDEzNi4zMzUgMTIyLjA4MiAxMzUuOTEyIDEyMi41NDEgMTM1LjIyOVpNMTE5LjQ1MSAxMjIuNDJDMTE5LjYzIDEyMi4wODEgMTE5LjY4NSAxMjEuNTU2IDExOS42ODUgMTIxLjU1NkMxMjAuMTU2IDEyMS42NTQgMTIwLjQ4IDEyMS42ODMgMTIwLjcyNiAxMjEuNzE5QzEyMS4xMDUgMTIxLjc3NCAxMjEuNTY0IDEyMS41ODcgMTIxLjc0NSAxMjEuMzAzQzEyMi4xNDkgMTIwLjY3MSAxMjAuNDc0IDExNy43MDEgMTE5LjU0OCAxMTcuNDA4QzExOC42NjggMTE3LjEyOCAxMTUuOTM1IDExOC44MjcgMTE1LjkzNSAxMTkuNjUzQzExNS45MzUgMTIwLjAyMiAxMTYuNTUzIDEyMC40MTEgMTE2LjgzMSAxMjAuNTE4QzExNi45ODIgMTIwLjU3NiAxMTcuMjUyIDEyMC43MzggMTE3LjU3NiAxMjAuOTM4QzExNy4zOCAxMjEuMzUxIDExNy4zNDYgMTIxLjQ3OCAxMTcuMzEyIDEyMS43MjRDMTE3LjIwNCAxMjIuNDk4IDExNy40MzUgMTIyLjY4NiAxMTguNDE2IDEyMi45MTJDMTE5LjE1MSAxMjIuOTkxIDExOS4yNSAxMjIuODQ1IDExOS40NTEgMTIyLjQyWk0xMjcuMjY1IDExNi44MzZDMTMwLjkzMyAxMTMuNDc1IDEyNy4wNzQgMTA3LjQxIDEyMi43MDUgMTA5LjY3QzEyMS42MjYgMTEwLjIyOCAxMjAuNjU0IDExMi4wMTkgMTIwLjY1NCAxMTMuNDQ5QzEyMC42NTQgMTE1LjY2NCAxMjIuODMxIDExNy45MzcgMTI0Ljk1NyAxMTcuOTQxQzEyNS43MzMgMTE3Ljk0MyAxMjYuNDE0IDExNy42MTcgMTI3LjI2NSAxMTYuODM2Wk0xMTcuMTQxIDExNS42MjJDMTE5LjAzNSAxMTQuNDY4IDExOS44MDQgMTExLjc5NSAxMTguODAyIDEwOS44NTdDMTE4LjA4MiAxMDguNDY0IDExNy4wMDggMTA3LjgzIDExNS4zNjYgMTA3LjgzQzExMS41MDggMTA3LjgzIDEwOS40ODUgMTEzLjIzNCAxMTIuNDY1IDExNS41NzhDMTEzLjU3IDExNi40NDggMTE1Ljc1NCAxMTYuNDY4IDExNy4xNDEgMTE1LjYyMloiIGZpbGw9IiMwOTk2RDEiLz4KPHBhdGggb3BhY2l0eT0iMC45IiBkPSJNMzMuMTc1NyAyNkwzMi4zODEgMjcuMjE5QzMxLjk0NDkgMjcuODg5IDMxLjI4MzYgMjkuMzI0OCAzMC45MDkxIDMwLjQwODhDMzAuNTM0NyAzMS40OTI4IDI5Ljk5MjIgMzIuOTcwMSAyOS43MDQzIDMzLjY5MjhDMjkuNDE2MyAzNC40MTU0IDI5LjE3MzMgMzYuMTE1IDI5LjE2MzggMzcuNDdDMjkuMTQzNiA0MC4zNTMgMjguNzQ5NCA0MS44ODg4IDI3LjYzNjQgNDMuNDIyNUMyNi45MjEyIDQ0LjQwOCAyNi42NzUxIDQ0LjUyMjMgMjUuNDUzMiA0NC40NDFDMjMuODk5NSA0NC4zMzc3IDIyLjgxNTMgNDUuMDgxNSAyMS4yMTcgNDcuMzQ4MUMyMC43MTY1IDQ4LjA1OCAyMC4xMzY3IDQ4LjYzOTMgMTkuOTI4OSA0OC42MzkzQzE5LjcyMTEgNDguNjM5MyAxOS4xODA1IDQ4LjIzMTkgMTguNzI2MiA0Ny43MzUxQzE4LjI3MTkgNDcuMjM4MiAxNy45OTQ0IDQ3LjAxMTUgMTguMTExIDQ3LjIyOThDMTguNDkgNDcuOTM5NiAxNy41OTA0IDUzLjI2MTUgMTYuODM3OCA1NC43NjQyQzE1Ljk2NyA1Ni41MDI4IDE0LjM4NzIgNTcuNzIzMyAxMi41MzU0IDU4LjA4NDNDMTEuMDA1OSA1OC4zODI2IDExLjIyODMgNTguMDkgOC43MTc5NSA2My4wOTQ2QzYuNjYzMzQgNjcuMTkwNyA1Ljk2OTM1IDY3LjgyNjQgMi42NTUzMyA2OC42NTQyQzEuNDk3MTcgNjguOTQzNCAwLjQ1ODc1OSA2OS43MTQyIDAgNzAuNTI4N1Y3Mi44MjYzQzAuMzU2MTkzIDcyLjc0NzMgMC44Mjg3MjggNzIuNjIwMyAxLjYxNDk5IDcyLjM4NzNDMi45OTQ4NiA3MS45NzgyIDQuODIzNDggNzEuNDgwNiA1LjY3ODEgNzEuMjgwNkM3LjcyOTM0IDcwLjgwMDYgOS4zOTM1MSA2OS4yMTk1IDkuOTIyNzkgNjcuMjQ2N0MxMC4yNDI0IDY2LjA1NTQgMTAuNzAzMyA2NS40MjQxIDExLjk5OTIgNjQuNDA1OEMxMy4yODQgNjMuMzk2MiAxMy43NTY1IDYyLjc1NDYgMTQuMDY3MSA2MS41OTY5QzE0LjM3MzkgNjAuNDUzMiAxNC43MDExIDYwLjAwNCAxNS40NDA3IDU5LjcwNjNDMTcuMDE1MyA1OS4wNzI0IDIwLjY0NDQgNTUuODY1NSAyMS4yMzYzIDU0LjU4NThDMjEuNTM3MyA1My45MzQ5IDIyLjExOTggNTIuNTM5OSAyMi41Mjg3IDUxLjQ4NjJDMjMuMjYzNCA0OS41OTMyIDI1LjAxOTUgNDcuMzI2MSAyNS43NTAxIDQ3LjMyNjFDMjUuOTU3NCA0Ny4zMjYxIDI3LjEwOSA0Ni43MjQ4IDI4LjMwOTMgNDUuOTkwOEMzMS4yMzc2IDQ0LjIwMDMgMzEuNTk5MSA0My40MTM2IDMxLjU5OTEgMzguODYxNEMzMS41OTkxIDM1LjY4MTQgMzEuNjg3IDM1LjE1NTcgMzIuMzQ2OCAzNC4zNjg0QzMzLjAwMzcgMzMuNTg0NyAzMy4wOTk3IDMzLjAyNDkgMzMuMTM1MSAyOS43MzkxTDMzLjE3NTcgMjZaTTI0LjMzMzggNjMuNTk1OEMyNC4yMDM3IDYzLjYxMzUgMjQuMDczOCA2My42NjE4IDIzLjkyNTggNjMuNzM2MkMyMi45Mzk3IDY0LjIzMTUgMjIuNjEzNiA2NC45MTAyIDIxLjU5NzMgNjguNTg2QzIxLjAxNzkgNzAuNjgxNSAyMC40MjEyIDcyLjA4MTkgMTkuODc5OCA3Mi42MTc4QzE5LjQyMzUgNzMuMDY5NSAxOC45MzgzIDczLjg4MjMgMTguODAxIDc0LjQyNDJDMTguMTgxIDc2Ljg3MTUgMTYuNzQ1NCA3OC42MDczIDE0LjQ0OTUgNzkuNjg3MUMxMi40NTU1IDgwLjYyNDkgMTAuNjQwNyA4Mi4xMTc5IDkuMTExMDIgODQuMDc5OEM4LjMyMTA5IDg1LjA5MjkgNy40ODc1MiA4Ni4wMjkgNy4yNTY3OCA4Ni4xNjA5QzYuNzYxNjQgODYuNDQ0IDUuNzA4OTkgODguODk0MSA0LjYwNzg1IDkyLjMyOEMzLjcxMDkyIDk1LjEyNSAxLjcxMDY1IDk3LjQ2ODIgMC40Nzg1MTQgOTcuMTY1OEMwLjI1NDkzMSA5Ny4xMTA5IDAuMTA2OTExIDk3LjExMzcgMCA5Ny4yOTAxVjEwNC40OTJDMC41NTY0MTEgMTAzLjY2NCAxLjIzNDIgMTAyLjYyOSAyLjU2MzQ3IDEwMC41NEM0LjM0NTExIDk3LjczOTcgNi40NjM4NSA5NC40ODY3IDcuMjcxNzMgOTMuMzEyNEM4LjA3OTYgOTIuMTM4MSA5LjM1Njg3IDkwLjE0ODggMTAuMTA4NiA4OC44OTE2QzExLjIzNDIgODcuMDA5MiAxMi4xMDE2IDg2LjEyNDMgMTUuMDI4NCA4My44ODMzTDE4LjU4MzEgODEuMTYyN0wyMC40MDUzIDc1Ljk4ODFDMjMuMTg5NSA2OC4wODE3IDIzLjk1ODUgNjcuMTk5NyAyNy43NjI0IDY3LjU1MTVDMjkuNDYwNSA2Ny43MDg1IDMwLjYzMzQgNjcuNjE5NiAzMi4wNzM0IDY3LjIyNjdDMzQuMTgyNiA2Ni42NTEyIDM0LjQ3OTkgNjYuMTg3MiAzMy4zNTUxIDY1LjIzMThDMzIuNjU1NCA2NC42Mzc2IDMxLjMxNTMgNjQuNjQgMjguMjM4OCA2NS4yNDE4QzI3LjMzOTcgNjUuNDE3NyAyNi45MzQzIDY1LjI3NTcgMjUuODkzMiA2NC40MTc4QzI1LjEwNTEgNjMuNzY4NCAyNC43MjQxIDYzLjU0MjYgMjQuMzMzOCA2My41OTU4Wk0zMS43MTY2IDgzLjI1OThDMzEuNjYwNSA4My4yNzQ5IDMxLjU5MjEgODMuMzEyNiAzMS41MTE1IDgzLjM3MjFDMzEuMjcwOSA4My41NSAzMC42NTM2IDgzLjc5IDMwLjEzNzkgODMuOTA1NEMyOS4zODc2IDg0LjA3MzQgMjkuMDQ5OCA4NC40OTMyIDI4LjQ0ODIgODYuMDA0NUMyOC4wMzQ3IDg3LjA0MzIgMjcuNDkxNSA4OC4xMTUzIDI3LjI0MTIgODguMzg2M0MyNi45OTA5IDg4LjY1NzMgMjYuNDc1IDg5LjU1MSAyNi4wOTQxIDkwLjM3MzJDMjQuOTQyMiA5Mi44NTkyIDIzLjUyODIgOTQuMDYxOCAxOS45MDExIDk1LjY0MjFDMTYuNjEwNyA5Ny4wNzU2IDE2LjU2NyA5Ny4xMDg2IDE1LjY2NzEgOTguOTgwMkMxNS4xMDI3IDEwMC4xNTQgMTQuNjc5MiAxMDEuNzU3IDE0LjU0OTkgMTAzLjIwNUMxNC4yNzMxIDEwNi4zMDIgMTMuNTk2MiAxMDcuMDMxIDkuNTIxMTggMTA4LjYxNkM1LjkxNDk3IDExMC4wMTkgMy41NzcwMiAxMTEuNzQ1IDMuNDE1ODMgMTEzLjEyM0MzLjI0MDQxIDExNC42MjMgMi41OTgxMyAxMTUuMDg0IDAuOTI5MjYgMTE0LjkwN0MwLjUzOTUyOSAxMTQuODY2IDAuMjQ0MzMyIDExNC44NTEgMCAxMTQuODgxVjEyMUMxLjAyNjU4IDExOS42NTggMi43MTkyMiAxMTguMzYxIDYuMjI0OTcgMTE2LjIwNkMxMC4zNjA0IDExMy42NjUgMTIuNzA2NSAxMTEuNTc1IDEzLjU3NzkgMTA5LjY1NEMxMy45MjYgMTA4Ljg4NyAxNC42NTQ3IDEwNy4zOTMgMTUuMTk3MSAxMDYuMzM0QzE1LjczOTUgMTA1LjI3NSAxNi4yODQ1IDEwMy45MDEgMTYuNDA4NCAxMDMuMjgxQzE2LjczMjQgMTAxLjY2IDE4LjMwMzIgMTAwLjM0OSAyMC42NjU5IDk5LjcyNkMyNS4xNzcgOTguNTM3MiAyNS43NDYxIDk4LjAxNjMgMjYuMzUyNSA5NC41MzU0QzI2Ljg1NjEgOTEuNjQ1MiAyOC42MTIgODguMDY2MSAzMC41MjY3IDg2LjAyNDZDMzEuMzA5NSA4NS4xOSAzMS45NDk1IDg0LjE4IDMxLjk0OTUgODMuNzc5MUMzMS45NDk1IDgzLjM3NjYgMzEuODg0OSA4My4yMTQ2IDMxLjcxNjYgODMuMjU5OFoiIGZpbGw9IiMzNTkxMzYiLz4KPHBhdGggZD0iTTguMDgxNzcgNzQuNDA4M0M2LjAzNDE5IDczLjg3MDUgNS44OTQ0MyA3My43MzAyIDYuMDQyNzEgNzIuMzYxNUM2LjEzMDI1IDcxLjU1MzMgNi4yNDAxNyA3MC44NTc1IDYuMjg2OTYgNzAuODE1NEM2LjMzMzc2IDcwLjc3MzMgNy43MDQ0MyA3MS4wNjg3IDkuMzMyOTIgNzEuNDcxOUMxMS45NzY4IDcyLjEyNjQgMTIuNDg2NiA3Mi4xMjM4IDE0LjA5NDcgNzEuNDQ3NEMxNi40MDQxIDcwLjQ3NiAxNy4yMzgzIDY4Ljc3NTMgMTYuNDAyMiA2Ni43NDMxQzE1Ljk0MjQgNjUuNjI1NyAxNC45MjA0IDY0LjgyODEgMTIuMjM4NCA2My40OTRDNy42NDE3IDYxLjIwNzUgNi41MzA2MiA1OS45OTkgNi4yNzQ2NSA1Ny4wMDc2QzUuODkzMzcgNTIuNTUxOSA4Ljg0Njg5IDQ5Ljk4MzYgMTQuMzUyMiA0OS45ODM2QzE1Ljk3MzMgNDkuOTgzNiAxNy44NDg3IDUwLjE5MzcgMTguNTE5NiA1MC40NTA1QzE5LjYzNjggNTAuODc4MSAxOS42OTM3IDUxLjAzOTkgMTkuMTk0NSA1Mi4zNzEyQzE4LjcxODIgNTMuNjQxNiAxOC41MDI3IDUzLjc2ODggMTcuNDg2MSA1My4zNzk2QzE1LjUxOTkgNTIuNjI3IDEyLjE5NDggNTIuODU1NCAxMS4wMDU4IDUzLjgyNDdDOS43OTA1OCA1NC44MTUzIDkuNTU3MzYgNTYuOTI1MiAxMC41MzI0IDU4LjEwNzlDMTAuODcyNyA1OC41MjA3IDEyLjkwODcgNTkuNzc5IDE1LjA1NjkgNjAuOTA0MUMxOC40NjI4IDYyLjY4ODEgMTkuMDgyIDYzLjIyMTQgMTkuODk1MSA2NS4wNzE5QzIxLjExNTIgNjcuODQ4NyAyMC42Nzg4IDcwLjM0MzcgMTguNjA3OCA3Mi40MzIzQzE2LjE2MDcgNzQuOTAwMiAxMi41NDEzIDc1LjU3OTYgOC4wODE3NyA3NC40MDgzWk0yOC45MzI4IDc0LjM4MjNDMjUuMjM2NSA3Mi45OTU4IDIzLjcxMzggNzAuNTQwNSAyMy43MTM4IDY1Ljk2NjdDMjMuNzEzOCA2Mi41MDM0IDI0LjU1ODggNjAuNDY5NyAyNi44MzMzIDU4LjQ1OTNDMjguMzk2NCA1Ny4wNzc2IDI4Ljk4NjcgNTYuODY4NiAzMS4zMjY4IDU2Ljg2ODZDMzIuODE2OCA1Ni44Njg2IDM0LjY4MjEgNTcuMjEyOSAzNS41MDA1IDU3LjYzODlDMzcuMzE2OSA1OC41ODQ2IDM4LjgzMTkgNjEuNzQyNiAzOC44NDY2IDY0LjYxNDNMMzguODU3MyA2Ni43MDQ0SDMyLjk0MjNIMjcuMDI3M0wyNy4zNDIgNjguMDU2OUMyNy41MTUgNjguODAwNyAyOC4zMzU0IDcwLjAzOTEgMjkuMTY1IDcwLjgwOUMzMC41NzczIDcyLjExOTYgMzAuODk0OSA3Mi4xOTc5IDM0LjE1NDcgNzIuMDM4NUMzNy4zOTM4IDcxLjg4MDEgMzcuNjQ2MyA3MS45NDA5IDM3Ljc4NCA3Mi45MTIyQzM3Ljk2MjYgNzQuMTcyNSAzNy4xODgyIDc0LjUyMzYgMzMuNTI0MiA3NC44NDM0QzMxLjgwODUgNzQuOTkzMiAzMC4xMDU2IDc0LjgyMjIgMjguOTMyOCA3NC4zODIzWk0zNS4wODgxIDYyLjUyNDJDMzQuOTU1OCA2MC42NzMgMzMuMzY0NCA1OS4zMjc2IDMxLjMwNzIgNTkuMzI3NkMyOS43MDg2IDU5LjMyNzYgMjguNzI4MSA2MC4wOTA5IDI3LjY2MiA2Mi4xNjU1QzI2Ljc0NTcgNjMuOTQ4NiAyNy40MTIgNjQuMjk2NSAzMS40NDg4IDY0LjE0MjVMMzUuMTkzNiA2My45OTk2TDM1LjA4ODEgNjIuNTI0MlpNNDQuMzkxNCA3NC4zNzA4QzQyLjU3MTEgNzMuNTQ2OCA0MS43MDU5IDcyLjEyODYgNDEuNjQyMSA2OS44NjQ3QzQxLjU0MTYgNjYuMjk0NCA0NC4xMTEgNjQuMTQ2OCA0OS4yNTc2IDYzLjQ5OTRDNTEuODQxNCA2My4xNzQ0IDUyLjA0OTUgNjMuMDU3NyA1MS43NTkzIDYyLjA5NjlDNTAuOTY1IDU5LjQ2NjYgNDguMjQyMyA1OC41NjQ0IDQ0LjkyNzYgNTkuODMzMUM0My40MzAzIDYwLjQwNjMgNDMuNDg2OCA2MC40MzEzIDQzLjA1MTQgNTkuMDAzMkM0Mi43ODAxIDU4LjExMzUgNDIuOTk4MiA1Ny44NTExIDQ0LjM5NSA1Ny4zODdDNDYuOTM2NCA1Ni41NDI3IDUxLjM3NDUgNTYuNjM0MiA1Mi43Nzc5IDU3LjU2QzU0LjkzOTIgNTguOTg1NyA1NS4zNzUxIDYwLjYwMTkgNTUuNTQ4NyA2Ny44MzI4TDU1LjcxMDYgNzQuNTc0NUw1NC4xMjMgNzQuNTc0QzUzLjAzNzcgNzQuNTczMyA1Mi41MzUzIDc0LjMzOTYgNTIuNTM1MyA3My44MzU0QzUyLjUzNTMgNzIuOTA2NiA1Mi4wNTI4IDcyLjkwMjQgNTAuNzUyIDczLjgxOTZDNDkuMjAxMyA3NC45MTMgNDYuMTY5NyA3NS4xNzU3IDQ0LjM5MTQgNzQuMzcwOFpNNTAuOTQ3NyA3MC44MTc1QzUxLjcwOTkgNjkuOTczNSA1Mi4wNDY4IDY4Ljk4NiA1Mi4wNDY4IDY3LjU5NjZWNjUuNTkyOUw0OS44MTgyIDY1Ljg0NThDNDUuNzE5IDY2LjMxMSA0My44NzQ5IDY5LjUxMTggNDYuNTA1OCA3MS41OTUzQzQ4LjAzNzEgNzIuODA3OSA0OS4zNTk0IDcyLjU3NjMgNTAuOTQ3NyA3MC44MTc1Wk05Mi4wMDIgNzQuNTc4OEM4OC40MDI0IDczLjQ4NjQgODYuMjQxOSA3MC4yNDY2IDg2LjI0MTkgNjUuOTQxQzg2LjI0MTkgNjAuNDA0MiA4OS41MjExIDU2LjgzMjUgOTQuNjQxIDU2Ljc5MjVDOTguNjk4OSA1Ni43NjA5IDEwMS4yNjMgNTkuNDY3OSAxMDEuNTAzIDY0LjAzNjZMMTAxLjYzIDY2LjQ1ODVMOTYuMjU2MiA2Ni41ODg1QzkzLjMwMDcgNjYuNjYgOTAuNjE1OCA2Ni44MTYgOTAuMjg5NyA2Ni45MzUxQzg5LjM4MTggNjcuMjY2OCA5MC40Nzg4IDY5Ljk0NyA5Mi4wMzA2IDcxLjE4ODZDOTMuMTU5OSA3Mi4wOTIxIDkzLjc3MSA3Mi4xOTEyIDk2LjgxNzggNzEuOTY1QzEwMC4xOTMgNzEuNzE0NCAxMDAuMzE4IDcxLjc0NDkgMTAwLjUzMSA3Mi44Njg0QzEwMC43MyA3My45MTMzIDEwMC41MDkgNzQuMDgzNSA5OC4zNTc5IDc0LjU0OEM5NS42MTAzIDc1LjE0MTIgOTMuODgyOSA3NS4xNDk2IDkyLjAwMiA3NC41Nzg4Wk05Ny45NjU5IDYzLjA4MjNDOTcuOTY1OSA2MS4xMjMxIDk2LjE4NTggNTkuMzI3NiA5NC4yNDM0IDU5LjMyNzZDOTIuMjQ5NCA1OS4zMjc2IDkwLjE0OTkgNjEuMjU2MiA5MC4xNDk5IDYzLjA4NzhDOTAuMTQ5OSA2NC4yMDcgOTAuMjc5NyA2NC4yNDU1IDk0LjA1NzkgNjQuMjQ1NUM5Ny44NDE0IDY0LjI0NTUgOTcuOTY1OSA2NC4yMDg0IDk3Ljk2NTkgNjMuMDgyM1pNMTEwLjA0MiA3NC40N0MxMDYuMTQ5IDczLjQzIDEwMy45MyA2OS40MDI5IDEwNC41NCA2NC40ODYyQzEwNS4xNjYgNTkuNDQ0MiAxMDcuOTUxIDU2Ljg3MzYgMTEyLjc5MiA1Ni44NzA1QzExNS4zNzQgNTYuODY5IDExNS44MDUgNTcuMDI0OSAxMTcuMjYgNTguNDlDMTE4Ljg3OCA2MC4xMTg1IDExOS45NDEgNjIuODM0MyAxMTkuOTQ2IDY1LjM1MkwxMTkuOTQ5IDY2LjcwNDRIMTE0LjA4N0MxMDguNDg4IDY2LjcwNDQgMTA4LjIyNSA2Ni43NTAxIDEwOC4yMjUgNjcuNzIwM0MxMDguMjI1IDcwLjcxMjIgMTEwLjk1MiA3Mi4zNDQyIDExNS4zNTcgNzEuOTg4MkMxMTguMTM2IDcxLjc2MzcgMTE4LjQyMyA3MS44MzE1IDExOC42NjcgNzIuNzY3NEMxMTguOTk4IDc0LjA0NDMgMTE4Ljk2OCA3NC4wNzIgMTE2LjY5IDc0LjYwNDNDMTE0LjM2NyA3NS4xNDcgMTEyLjQzIDc1LjEwNzggMTEwLjA0MiA3NC40N1pNMTE2LjExOSA2Mi43NzAxQzExNS44NjQgNjAuODc4NyAxMTQuMTU5IDU5LjMyNzYgMTEyLjMzNSA1OS4zMjc2QzExMC41NjYgNTkuMzI3NiAxMDguMjI0IDYxLjYwMTQgMTA4LjIyNCA2My4zMTk1QzEwOC4yMjQgNjQuMjEyOCAxMDguNTI3IDY0LjI3NDYgMTEyLjI1NSA2NC4xNDI0QzExNi4yNDEgNjQuMDAxMSAxMTYuMjgzIDYzLjk4NjIgMTE2LjExOSA2Mi43NzAxWk0xMjYuODk0IDc0LjI0N0MxMjQuODI2IDczLjIyMDggMTIzLjUzMiA3MS4zNTg5IDEyMi44OTQgNjguNDg4OUMxMjEuOTc1IDY0LjM2MDUgMTIzLjA3NCA2MC40OTE0IDEyNS44MyA1OC4xNTY3QzEyNy44MjcgNTYuNDY1NyAxMzEuODM4IDU2LjMzMDUgMTMzLjgwNSA1Ny44ODc5TDEzNS4wOTIgNTguOTA3MlY1My45NTM2VjQ5SDEzNy4wNDZIMTM5VjYxLjc4NjVWNzQuNTczMUgxMzcuMjlDMTM1Ljc2MiA3NC41NzMxIDEzNS41OCA3NC40MzMxIDEzNS41OCA3My4yNTc5VjcxLjk0MjdMMTM0LjQ4MSA3Mi45NzkyQzEzMi4yMzMgNzUuMDk5OCAxMjkuNTI1IDc1LjU1MjMgMTI2Ljg5NCA3NC4yNDdaTTEzMy42NjQgNzAuNjc2NkMxMzQuOTc2IDY5LjM1NTcgMTM1LjA5MiA2OC45NTM3IDEzNS4wOTIgNjUuNzIwOUMxMzUuMDkyIDYyLjQ1NzIgMTM0Ljk4NSA2Mi4wOTQ1IDEzMy42MDcgNjAuNzA3NkMxMzIuMzY1IDU5LjQ1NzUgMTMxLjg2NSA1OS4yNjIyIDEzMC41NTQgNTkuNTE1NEMxMjYuMTQ0IDYwLjM2NzIgMTI0LjgzNSA2OC4xNDIzIDEyOC41OTggNzEuMTIyOUMxMzAuMzQ4IDcyLjUwODEgMTMxLjk4OCA3Mi4zNjM1IDEzMy42NjQgNzAuNjc2NlpNNjEuNDEwNyA2Ni4wNTg0QzYwLjAyMiA2MS4zNzU0IDU4Ljg4NTkgNTcuMzkxOSA1OC44ODU5IDU3LjIwNjJDNTguODg1OSA1Ny4wMjA2IDU5LjcyNzQgNTYuODY4NiA2MC43NTU5IDU2Ljg2ODZINjIuNjI1OUw2NC4yNTUxIDYzLjg3NjZDNjUuMTUxMiA2Ny43MzEgNjUuOTU2IDcwLjY2MzMgNjYuMDQzNyA3MC4zOTI5QzY2LjEzMTMgNzAuMTIyNCA2Ny4wNTU3IDY3LjAyNDEgNjguMDk3OCA2My41MDc4TDY5Ljk5MjYgNTcuMTE0NUg3MS41OTY5SDczLjIwMTJMNzQuODg2NSA2My4yNjE5Qzc1LjgxMzQgNjYuNjQzIDc2LjY4MzIgNjkuNzQxMiA3Ni44MTk0IDcwLjE0N0M3Ni45NTU3IDcwLjU1MjcgNzcuODQxOSA2Ny43MzEgNzguNzg5IDYzLjg3NjZMODAuNTEwOSA1Ni44Njg2SDgyLjQ1MTdDODMuOTUxNyA1Ni44Njg2IDg0LjMzMDMgNTcuMDMxNiA4NC4xMTkgNTcuNTg2QzgzLjk2ODYgNTcuOTgwNiA4Mi42OTU2IDYxLjk2NDEgODEuMjkwMiA2Ni40MzgyTDc4LjczNDkgNzQuNTczMUg3Ni45NjM1SDc1LjE5MjFMNzMuNTgxMiA2OC43OTQ1QzcyLjY5NTIgNjUuNjE2MyA3MS44NTg1IDYyLjY4NDEgNzEuNzIxNyA2Mi4yNzgzQzcxLjQ0NjUgNjEuNDYxNiA3MS41OTExIDYxLjA3MzMgNjkuMTExNCA2OS4yODYzTDY3LjUxNTIgNzQuNTczMUg2NS43MjU0SDYzLjkzNTZMNjEuNDEwNyA2Ni4wNTg0WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTE5Ljk3NDYgMTE5LjI3NEMxOS4wMTU4IDExOC4xMTkgMjAuMzM4MSAxMTYuMTY2IDIxLjU2MDQgMTE2LjkzMkMyMi43NjMyIDExNy42ODYgMjIuMzMwNSAxMTkuNzYxIDIwLjk3MDQgMTE5Ljc2MUMyMC42NDUgMTE5Ljc2MSAyMC4xOTY5IDExOS41NDIgMTkuOTc0NiAxMTkuMjc0WiIgZmlsbD0idXJsKCNwYWludDNfcmFkaWFsXzY3OV8xOTEwKSIvPgo8cGF0aCBkPSJNMjMuODM2IDExMi42M0MyMi4xMTUyIDExMS42ODkgMjEuODAyOSAxMDkuNzk3IDIzLjE0NjUgMTA4LjQ1M0MyNC4wODU3IDEwNy41MTQgMjUuMjEgMTA3LjM5NCAyNi4yNTA3IDEwOC4xMjNDMjcuODU3MSAxMDkuMjQ5IDI3LjQ2NTUgMTEyLjAxMyAyNS42MDc5IDExMi42NkMyNS42MDc5IDExMi42NiAyNC40NzQ1IDExMi45NzMgMjMuODM2IDExMi42M1oiIGZpbGw9InVybCgjcGFpbnQ0X3JhZGlhbF82NzlfMTkxMCkiLz4KPHBhdGggZD0iTTMzLjc4NTUgMTIwLjAzNkMzMy43ODU1IDEyMC4xODggMzMuNzU1NyAxMjAuMzM4IDMzLjY5NzYgMTIwLjQ3OUMzMy42Mzk1IDEyMC42MTkgMzMuNTU0NCAxMjAuNzQ2IDMzLjQ0NzEgMTIwLjg1M0MzMy4zMzk4IDEyMC45NjEgMzMuMjEyNCAxMjEuMDQ2IDMzLjA3MjMgMTIxLjEwNEMzMi45MzIxIDEyMS4xNjIgMzIuNzgxOCAxMjEuMTkyIDMyLjYzMDEgMTIxLjE5MkMzMi40NzgzIDEyMS4xOTIgMzIuMzI4MSAxMjEuMTYyIDMyLjE4NzkgMTIxLjEwNEMzMi4wNDc3IDEyMS4wNDYgMzEuOTIwMyAxMjAuOTYxIDMxLjgxMyAxMjAuODUzQzMxLjcwNTcgMTIwLjc0NiAzMS42MjA2IDEyMC42MTkgMzEuNTYyNiAxMjAuNDc5QzMxLjUwNDUgMTIwLjMzOCAzMS40NzQ2IDEyMC4xODggMzEuNDc0NiAxMjAuMDM2QzMxLjQ3NDYgMTE5LjczIDMxLjU5NjMgMTE5LjQzNiAzMS44MTMgMTE5LjIxOUMzMi4wMjk3IDExOS4wMDMgMzIuMzIzNiAxMTguODgxIDMyLjYzMDEgMTE4Ljg4MUMzMi45MzY1IDExOC44ODEgMzMuMjMwNCAxMTkuMDAzIDMzLjQ0NzEgMTE5LjIxOUMzMy42NjM4IDExOS40MzYgMzMuNzg1NSAxMTkuNzMgMzMuNzg1NSAxMjAuMDM2WiIgZmlsbD0iYmxhY2siLz4KPHBhdGggZD0iTTEyMC43MjEgMTE4LjI3NkMxMjAuNzIxIDExOC42MjMgMTIwLjU2NSAxMTguOTU2IDEyMC4yODcgMTE5LjIwMUMxMjAuMDA5IDExOS40NDYgMTE5LjYzMiAxMTkuNTg0IDExOS4yMzkgMTE5LjU4NEMxMTguODQ2IDExOS41ODQgMTE4LjQ2OSAxMTkuNDQ2IDExOC4xOTEgMTE5LjIwMUMxMTcuOTEzIDExOC45NTYgMTE3Ljc1NyAxMTguNjIzIDExNy43NTcgMTE4LjI3NkMxMTcuNzU3IDExOC4xMDUgMTE3Ljc5NSAxMTcuOTM1IDExNy44NyAxMTcuNzc2QzExNy45NDQgMTE3LjYxNyAxMTguMDUzIDExNy40NzMgMTE4LjE5MSAxMTcuMzUyQzExOC4zMjkgMTE3LjIzIDExOC40OTIgMTE3LjEzNCAxMTguNjcyIDExNy4wNjhDMTE4Ljg1MSAxMTcuMDAzIDExOS4wNDQgMTE2Ljk2OSAxMTkuMjM5IDExNi45NjlDMTE5LjQzMyAxMTYuOTY5IDExOS42MjYgMTE3LjAwMyAxMTkuODA2IDExNy4wNjhDMTE5Ljk4NiAxMTcuMTM0IDEyMC4xNDkgMTE3LjIzIDEyMC4yODcgMTE3LjM1MkMxMjAuNDI0IDExNy40NzMgMTIwLjUzMyAxMTcuNjE3IDEyMC42MDggMTE3Ljc3NkMxMjAuNjgyIDExNy45MzUgMTIwLjcyMSAxMTguMTA1IDEyMC43MjEgMTE4LjI3NloiIGZpbGw9IiM1OTY4NkYiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl82NzlfMTkxMCIgeDE9IjExIiB5MT0iLTQuNzc3NjhlLTA3IiB4Mj0iMTY0LjUiIHkyPSIxNTAuNSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjNjRCN0ZGIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzAwNURBRCIvPgo8L2xpbmVhckdyYWRpZW50Pgo8cmFkaWFsR3JhZGllbnQgaWQ9InBhaW50MV9yYWRpYWxfNjc5XzE5MTAiIGN4PSIwIiBjeT0iMCIgcj0iMSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTI0LjkwNCAxMjguNjM2KSByb3RhdGUoLTAuMDQ4NTUyKSBzY2FsZSgzNi4yODAyIDMxLjQwMzIpIj4KPHN0b3Agc3RvcC1jb2xvcj0iIzExNzdDRSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM3RUM3RkYiIHN0b3Atb3BhY2l0eT0iMCIvPgo8L3JhZGlhbEdyYWRpZW50Pgo8cmFkaWFsR3JhZGllbnQgaWQ9InBhaW50Ml9yYWRpYWxfNjc5XzE5MTAiIGN4PSIwIiBjeT0iMCIgcj0iMSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoMzkuMzUxMiAxMjEuNDYpIHJvdGF0ZSgtMC4wNTczKSBzY2FsZSg1MC4yMjc2IDUxLjMwOTEpIj4KPHN0b3Agc3RvcC1jb2xvcj0iIzExNzdDRSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM3RUM3RkYiIHN0b3Atb3BhY2l0eT0iMCIvPgo8L3JhZGlhbEdyYWRpZW50Pgo8cmFkaWFsR3JhZGllbnQgaWQ9InBhaW50M19yYWRpYWxfNjc5XzE5MTAiIGN4PSIwIiBjeT0iMCIgcj0iMSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjAuOTU0OCAxMTguMjYpIHNjYWxlKDEuMzA5MjkgMS41MDEyNykiPgo8c3RvcCBzdG9wLWNvbG9yPSIjODhBM0QwIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzVEODNCRiIvPgo8L3JhZGlhbEdyYWRpZW50Pgo8cmFkaWFsR3JhZGllbnQgaWQ9InBhaW50NF9yYWRpYWxfNjc5XzE5MTAiIGN4PSIwIiBjeT0iMCIgcj0iMSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjQuNzg0MyAxMTAuMjIxKSBzY2FsZSgyLjQ3Mjc3IDIuNTY5NTQpIj4KPHN0b3Agc3RvcC1jb2xvcj0iIzg4QTNEMCIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM1RDgzQkYiLz4KPC9yYWRpYWxHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "host"], ["spec", "topology"], ["spec", "replicationFactor"], ["spec", "db"], ["spec", "db", "replicas"], ["spec", "db", "size"], ["spec", "db", "storageClass"], ["spec", "db", "resources"], ["spec", "db", "resourcesPreset"], ["spec", "master"], ["spec", "master", "replicas"], ["spec", "master", "resources"], ["spec", "master", "resourcesPreset"], ["spec", "filer"], ["spec", "filer", "replicas"], ["spec", "filer", "resources"], ["spec", "filer", "resourcesPreset"], ["spec", "filer", "grpcHost"], ["spec", "filer", "grpcPort"], ["spec", "filer", "whitelist"], ["spec", "volume"], ["spec", "volume", "replicas"], ["spec", "volume", "size"], ["spec", "volume", "storageClass"], ["spec", "volume", "diskType"], ["spec", "volume", "resources"], ["spec", "volume", "resourcesPreset"], ["spec", "volume", "zones"], ["spec", "volume", "pools"], ["spec", "s3"], ["spec", "s3", "replicas"], ["spec", "s3", "resources"], ["spec", "s3", "resourcesPreset"]] + secrets: + exclude: [] + include: [] + services: + exclude: [] + include: + - resourceNames: + - seaweedfs-{{ .name }}-s3 + ingresses: + exclude: [] + include: + - resourceNames: + - ingress-seaweedfs-{{ .name }}-s3 diff --git a/packages/system/seaweedfs-rd/templates/cozyrd.yaml b/packages/system/seaweedfs-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/seaweedfs-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/seaweedfs-rd/values.yaml b/packages/system/seaweedfs-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/seaweedfs-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/seaweedfs/Makefile b/packages/system/seaweedfs/Makefile index 1868ccdd..cd938a4a 100644 --- a/packages/system/seaweedfs/Makefile +++ b/packages/system/seaweedfs/Makefile @@ -1,11 +1,16 @@ -NAME=seaweedfs-system +export NAME=seaweedfs-system -include ../../../scripts/package.mk +include ../../../hack/common-envs.mk +include ../../../hack/package.mk update: rm -rf charts mkdir -p charts - curl -sSL https://github.com/seaweedfs/seaweedfs/archive/refs/heads/master.tar.gz | \ - tar xzvf - --strip 3 -C charts seaweedfs-master/k8s/charts/seaweedfs - patch --no-backup-if-mismatch -p4 < patches/retention-policy-delete.yaml + version=$$(git ls-remote --tags --sort="v:refname" https://github.com/seaweedfs/seaweedfs | grep -v '\^{}' | grep 'refs/tags/[0-9]' | awk -F'/' 'END{print $$3}') && \ + curl -sSL https://github.com/seaweedfs/seaweedfs/archive/refs/tags/$${version}.tar.gz | \ + tar xzvf - --strip 3 -C charts seaweedfs-$${version}/k8s/charts/seaweedfs patch --no-backup-if-mismatch -p4 < patches/resize-api-server-annotation.diff + patch --no-backup-if-mismatch -p4 < patches/s3-traffic-distribution.patch + patch --no-backup-if-mismatch -p4 < patches/disable-ca-key-rotation.patch + #patch --no-backup-if-mismatch -p4 < patches/retention-policy-delete.yaml + diff --git a/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml b/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml index 073679af..107149cf 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v1 description: SeaweedFS name: seaweedfs -appVersion: "3.71" +appVersion: "4.05" # Dev note: Trigger a helm chart release by `git tag -a helm-` -version: 4.0.0 +version: 4.0.405 diff --git a/packages/system/seaweedfs/charts/seaweedfs/README.md b/packages/system/seaweedfs/charts/seaweedfs/README.md index 41707ba8..7f27cb22 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/README.md +++ b/packages/system/seaweedfs/charts/seaweedfs/README.md @@ -57,7 +57,7 @@ Here is an example: to label a node to be able to run all pod types in k8s: ``` -kubectl label node YOUR_NODE_NAME sw-volume=true,sw-backend=true +kubectl label node YOUR_NODE_NAME sw-volume=true sw-backend=true ``` on production k8s deployment you will want each pod to have a different host, @@ -144,3 +144,193 @@ stringData: # this key must be an inline json config file seaweedfs_s3_config: '{"identities":[{"name":"anvAdmin","credentials":[{"accessKey":"snu8yoP6QAlY0ne4","secretKey":"PNzBcmeLNEdR0oviwm04NQAicOrDH1Km"}],"actions":["Admin","Read","Write"]},{"name":"anvReadOnly","credentials":[{"accessKey":"SCigFee6c5lbi04A","secretKey":"kgFhbT38R8WUYVtiFQ1OiSVOrYr3NKku"}],"actions":["Read"]}]}' ``` + +## Admin Component + +The admin component provides a modern web-based administration interface for managing SeaweedFS clusters. It includes: + +- **Dashboard**: Real-time cluster status and metrics +- **Volume Management**: Monitor volume servers, capacity, and health +- **File Browser**: Browse and manage files in the filer +- **Maintenance Operations**: Trigger maintenance tasks via workers +- **Object Store Management**: Create and manage buckets with web interface + +### Enabling Admin + +To enable the admin interface, add the following to your values.yaml: + +```yaml +admin: + enabled: true + port: 23646 + grpcPort: 33646 # For worker connections + adminUser: "admin" + adminPassword: "your-secure-password" # Leave empty to disable auth + + # Optional: persist admin data + data: + type: "persistentVolumeClaim" + size: "10Gi" + storageClass: "your-storage-class" + + # Optional: enable ingress + ingress: + enabled: true + host: "admin.seaweedfs.local" + className: "nginx" +``` + +The admin interface will be available at `http://:23646` (or via ingress). Workers connect to the admin server via gRPC on port `33646`. + +### Admin Authentication + +If `adminPassword` is set, the admin interface requires authentication: +- Username: Value of `adminUser` (default: `admin`) +- Password: Value of `adminPassword` + +If `adminPassword` is empty or not set, the admin interface runs without authentication (not recommended for production). + +### Admin Data Persistence + +The admin component can store configuration and maintenance data. You can configure storage in several ways: + +- **emptyDir** (default): Data is lost when pod restarts +- **persistentVolumeClaim**: Data persists across pod restarts +- **hostPath**: Data stored on the host filesystem +- **existingClaim**: Use an existing PVC + +## Worker Component + +Workers are maintenance agents that execute cluster maintenance tasks such as vacuum, volume balancing, and erasure coding. Workers connect to the admin server via gRPC and receive task assignments. + +### Enabling Workers + +To enable workers, add the following to your values.yaml: + +```yaml +worker: + enabled: true + replicas: 2 # Scale based on workload + capabilities: "vacuum,balance,erasure_coding" # Tasks this worker can handle + maxConcurrent: 3 # Maximum concurrent tasks per worker + + # Working directory for task execution + # Default: "/tmp/seaweedfs-worker" + # Note: /tmp is ephemeral - use persistent storage (hostPath/existingClaim) for long-running tasks + workingDir: "/tmp/seaweedfs-worker" + + # Optional: configure admin server address + # If not specified, auto-discovers from admin service in the same namespace by looking for + # a service named "-admin" (e.g., "seaweedfs-admin"). + # Auto-discovery only works if the admin is in the same namespace and same Helm release. + # For cross-namespace or separate release scenarios, explicitly set this value. + # Example: If main SeaweedFS is deployed in "production" namespace: + # adminServer: "seaweedfs-admin.production.svc:33646" + adminServer: "" + + # Workers need storage for task execution + # Note: Workers use a Deployment, which does not support `volumeClaimTemplates` + # for dynamic PVC creation per pod. To use persistent storage, you must + # pre-provision a PersistentVolumeClaim and use `type: "existingClaim"`. + data: + type: "emptyDir" # Options: "emptyDir", "hostPath", or "existingClaim" + hostPathPrefix: /storage # For hostPath + # claimName: "worker-pvc" # For existingClaim with pre-provisioned PVC + + # Resource limits for worker pods + resources: + requests: + cpu: "500m" + memory: "512Mi" + limits: + cpu: "2" + memory: "2Gi" +``` + +### Worker Capabilities + +Workers can be configured with different capabilities: +- **vacuum**: Reclaim deleted file space +- **balance**: Balance volumes across volume servers +- **erasure_coding**: Handle erasure coding operations + +You can configure workers with all capabilities or create specialized worker pools with specific capabilities. + +### Worker Deployment Strategy + +For production deployments, consider: + +1. **Multiple Workers**: Deploy 2+ worker replicas for high availability +2. **Resource Allocation**: Workers need sufficient CPU/memory for maintenance tasks +3. **Storage**: Workers need temporary storage for vacuum and balance operations (size depends on volume size) +4. **Specialized Workers**: Create separate worker deployments for different capabilities if needed + +Example specialized worker configuration: + +For specialized worker pools, deploy separate Helm releases with different capabilities: + +**values-worker-vacuum.yaml** (for vacuum operations): +```yaml +# Disable all other components, enable only workers +master: + enabled: false +volume: + enabled: false +filer: + enabled: false +s3: + enabled: false +admin: + enabled: false + +worker: + enabled: true + replicas: 2 + capabilities: "vacuum" + maxConcurrent: 2 + # REQUIRED: Point to the admin service of your main SeaweedFS release + # Replace with the namespace where your main seaweedfs is deployed + # Example: If deploying in namespace "production": + # adminServer: "seaweedfs-admin.production.svc:33646" + adminServer: "seaweedfs-admin..svc:33646" +``` + +**values-worker-balance.yaml** (for balance operations): +```yaml +# Disable all other components, enable only workers +master: + enabled: false +volume: + enabled: false +filer: + enabled: false +s3: + enabled: false +admin: + enabled: false + +worker: + enabled: true + replicas: 1 + capabilities: "balance" + maxConcurrent: 1 + # REQUIRED: Point to the admin service of your main SeaweedFS release + # Replace with the namespace where your main seaweedfs is deployed + # Example: If deploying in namespace "production": + # adminServer: "seaweedfs-admin.production.svc:33646" + adminServer: "seaweedfs-admin..svc:33646" +``` + +Deploy the specialized workers as separate releases: +```bash +# Deploy vacuum workers +helm install seaweedfs-worker-vacuum seaweedfs/seaweedfs -f values-worker-vacuum.yaml + +# Deploy balance workers +helm install seaweedfs-worker-balance seaweedfs/seaweedfs -f values-worker-balance.yaml +``` + +## Enterprise + +For enterprise users, please visit [seaweedfs.com](https://seaweedfs.com) for the SeaweedFS Enterprise Edition, +which has a self-healing storage format with better data protection. diff --git a/packages/system/seaweedfs/charts/seaweedfs/dashboards/seaweedfs-grafana-dashboard.json b/packages/system/seaweedfs/charts/seaweedfs/dashboards/seaweedfs-grafana-dashboard.json index f4e3b020..ca08b7d0 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/dashboards/seaweedfs-grafana-dashboard.json +++ b/packages/system/seaweedfs/charts/seaweedfs/dashboards/seaweedfs-grafana-dashboard.json @@ -1505,6 +1505,191 @@ "title": "S3 Request Duration 99th percentile", "type": "timeseries" }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 84, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "sum(rate(SeaweedFS_s3_bucket_traffic_received_bytes_total{namespace=\"$NAMESPACE\"}[$__interval])) by (bucket)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{bucket}}", + "refId": "A" + } + ], + "title": "S3 Bucket Traffic Received", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 85, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "sum(rate(SeaweedFS_s3_bucket_traffic_sent_bytes_total{namespace=\"$NAMESPACE\"}[$__interval])) by (bucket)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{bucket}}", + "refId": "A" + } + ], + "title": "S3 Bucket Traffic Sent", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps", + "unitScale": true + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 41 + }, + "id": 86, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "expr": "sum(rate(SeaweedFS_s3_request_total{namespace=\"$NAMESPACE\"}[$__interval])) by (bucket)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{bucket}}", + "refId": "A" + } + ], + "title": "S3 API Calls per Bucket", + "type": "timeseries" + }, { "datasource": { "type": "prometheus", @@ -1569,9 +1754,9 @@ }, "gridPos": { "h": 7, - "w": 24, - "x": 0, - "y": 36 + "w": 12, + "x": 12, + "y": 41 }, "id": 72, "links": [], @@ -1689,7 +1874,7 @@ "h": 7, "w": 24, "x": 0, - "y": 43 + "y": 50 }, "id": 73, "links": [], @@ -1845,7 +2030,7 @@ "h": 7, "w": 24, "x": 0, - "y": 50 + "y": 57 }, "id": 55, "links": [], @@ -2002,7 +2187,7 @@ "h": 7, "w": 24, "x": 0, - "y": 57 + "y": 64 }, "hideTimeOverride": false, "id": 59, @@ -2074,7 +2259,7 @@ "h": 1, "w": 24, "x": 0, - "y": 64 + "y": 71 }, "id": 62, "panels": [], @@ -2146,7 +2331,7 @@ "h": 7, "w": 12, "x": 0, - "y": 65 + "y": 72 }, "id": 47, "links": [], @@ -2289,7 +2474,7 @@ "h": 7, "w": 12, "x": 12, - "y": 65 + "y": 72 }, "id": 40, "links": [], @@ -2386,7 +2571,7 @@ "h": 7, "w": 24, "x": 0, - "y": 72 + "y": 79 }, "id": 48, "links": [], @@ -2496,7 +2681,7 @@ "h": 7, "w": 24, "x": 0, - "y": 79 + "y": 86 }, "id": 50, "links": [], @@ -2598,7 +2783,7 @@ "h": 7, "w": 24, "x": 0, - "y": 86 + "y": 93 }, "id": 51, "links": [], @@ -2711,7 +2896,7 @@ "h": 7, "w": 12, "x": 0, - "y": 94 + "y": 101 }, "id": 12, "links": [], @@ -2806,7 +2991,7 @@ "h": 7, "w": 12, "x": 12, - "y": 94 + "y": 101 }, "id": 14, "links": [], @@ -2848,7 +3033,7 @@ "h": 1, "w": 24, "x": 0, - "y": 101 + "y": 108 }, "id": 64, "panels": [], @@ -2921,7 +3106,7 @@ "h": 7, "w": 12, "x": 0, - "y": 102 + "y": 109 }, "id": 52, "links": [], @@ -3049,7 +3234,7 @@ "h": 7, "w": 12, "x": 12, - "y": 102 + "y": 109 }, "id": 54, "links": [], @@ -3146,7 +3331,7 @@ "h": 7, "w": 24, "x": 0, - "y": 109 + "y": 116 }, "id": 53, "links": [], @@ -3176,6 +3361,209 @@ ], "title": "Filer Go Routines", "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 89, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "max(SeaweedFS_s3_bucket_size_bytes{namespace=\"$NAMESPACE\"}) by (bucket)", + "legendFormat": "{{bucket}} (logical)", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "max(SeaweedFS_s3_bucket_physical_size_bytes{namespace=\"$NAMESPACE\"}) by (bucket)", + "legendFormat": "{{bucket}} (physical)", + "range": true, + "refId": "B" + } + ], + "title": "S3 Bucket Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 48 + }, + "id": 90, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "max(SeaweedFS_s3_bucket_object_count{namespace=\"$NAMESPACE\"}) by (bucket)", + "legendFormat": "{{bucket}}", + "range": true, + "refId": "A" + } + ], + "title": "S3 Bucket Object Count", + "type": "timeseries" } ], "refresh": "", diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/_helpers.tpl b/packages/system/seaweedfs/charts/seaweedfs/templates/_helpers.tpl deleted file mode 100644 index d8261eb3..00000000 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/_helpers.tpl +++ /dev/null @@ -1,167 +0,0 @@ -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to -this (by the DNS naming spec). If release name contains chart name it will -be used as a full name. -*/}} -{{- define "seaweedfs.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "seaweedfs.chart" -}} -{{- printf "%s-helm" .Chart.Name | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Expand the name of the chart. -*/}} -{{- define "seaweedfs.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Inject extra environment vars in the format key:value, if populated -*/}} -{{- define "seaweedfs.extraEnvironmentVars" -}} -{{- if .extraEnvironmentVars -}} -{{- range $key, $value := .extraEnvironmentVars }} -- name: {{ $key }} - value: {{ $value | quote }} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* Return the proper filer image */}} -{{- define "filer.image" -}} -{{- if .Values.filer.imageOverride -}} -{{- $imageOverride := .Values.filer.imageOverride -}} -{{- printf "%s" $imageOverride -}} -{{- else -}} -{{- include "common.image" . }} -{{- end -}} -{{- end -}} - -{{/* Return the proper master image */}} -{{- define "master.image" -}} -{{- if .Values.master.imageOverride -}} -{{- $imageOverride := .Values.master.imageOverride -}} -{{- printf "%s" $imageOverride -}} -{{- else -}} -{{- include "common.image" . }} -{{- end -}} -{{- end -}} - -{{/* Return the proper s3 image */}} -{{- define "s3.image" -}} -{{- if .Values.s3.imageOverride -}} -{{- $imageOverride := .Values.s3.imageOverride -}} -{{- printf "%s" $imageOverride -}} -{{- else -}} -{{- include "common.image" . }} -{{- end -}} -{{- end -}} - -{{/* Return the proper volume image */}} -{{- define "volume.image" -}} -{{- if .Values.volume.imageOverride -}} -{{- $imageOverride := .Values.volume.imageOverride -}} -{{- printf "%s" $imageOverride -}} -{{- else -}} -{{- include "common.image" . }} -{{- end -}} -{{- end -}} - -{{/* Computes the container image name for all components (if they are not overridden) */}} -{{- define "common.image" -}} -{{- $registryName := default .Values.image.registry .Values.global.registry | toString -}} -{{- $repositoryName := .Values.image.repository | toString -}} -{{- $name := .Values.global.imageName | toString -}} -{{- $tag := .Chart.AppVersion | toString -}} -{{- if $registryName -}} -{{- printf "%s/%s%s:%s" $registryName $repositoryName $name $tag -}} -{{- else -}} -{{- printf "%s%s:%s" $repositoryName $name $tag -}} -{{- end -}} -{{- end -}} - -{{/* check if any Volume PVC exists */}} -{{- define "volume.pvc_exists" -}} -{{- if or (or (eq .Values.volume.data.type "persistentVolumeClaim") (and (eq .Values.volume.idx.type "persistentVolumeClaim") .Values.volume.dir_idx )) (eq .Values.volume.logs.type "persistentVolumeClaim") -}} -{{- printf "true" -}} -{{- else -}} -{{- printf "" -}} -{{- end -}} -{{- end -}} - -{{/* check if any Filer PVC exists */}} -{{- define "filer.pvc_exists" -}} -{{- if or (eq .Values.filer.data.type "persistentVolumeClaim") (eq .Values.filer.logs.type "persistentVolumeClaim") -}} -{{- printf "true" -}} -{{- else -}} -{{- printf "" -}} -{{- end -}} -{{- end -}} - -{{/* check if any Master PVC exists */}} -{{- define "master.pvc_exists" -}} -{{- if or (eq .Values.master.data.type "persistentVolumeClaim") (eq .Values.master.logs.type "persistentVolumeClaim") -}} -{{- printf "true" -}} -{{- else -}} -{{- printf "" -}} -{{- end -}} -{{- end -}} - -{{/* check if any InitContainers exist for Volumes */}} -{{- define "volume.initContainers_exists" -}} -{{- if or (not (empty .Values.volume.idx )) (not (empty .Values.volume.initContainers )) -}} -{{- printf "true" -}} -{{- else -}} -{{- printf "" -}} -{{- end -}} -{{- end -}} - -{{/* Return the proper imagePullSecrets */}} -{{- define "seaweedfs.imagePullSecrets" -}} -{{- if .Values.global.imagePullSecrets }} -{{- if kindIs "string" .Values.global.imagePullSecrets }} -imagePullSecrets: - - name: {{ .Values.global.imagePullSecrets }} -{{- else }} -imagePullSecrets: -{{- range .Values.global.imagePullSecrets }} - - name: {{ . }} -{{- end }} -{{- end }} -{{- end }} -{{- end -}} - -{{/* -Renders a value that contains template perhaps with scope if the scope is present. -Usage: -{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $ ) }} -{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $ "scope" $app ) }} -*/}} -{{- define "common.tplvalues.render" -}} -{{- $value := typeIs "string" .value | ternary .value (.value | toYaml) }} -{{- if contains "{{" (toJson .value) }} - {{- if .scope }} - {{- tpl (cat "{{- with $.RelativeScope -}}" $value "{{- end }}") (merge (dict "RelativeScope" .scope) .context) }} - {{- else }} - {{- tpl $value .context }} - {{- end }} -{{- else }} - {{- $value }} -{{- end }} -{{- end -}} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-ingress.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-ingress.yaml new file mode 100644 index 00000000..216ef8a8 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-ingress.yaml @@ -0,0 +1,52 @@ +{{- if and .Values.admin.enabled .Values.admin.ingress.enabled }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion }} +apiVersion: networking.k8s.io/v1beta1 +{{- else }} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: ingress-{{ template "seaweedfs.name" . }}-admin + namespace: {{ .Release.Namespace }} + annotations: + {{- if and (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) .Values.admin.ingress.className }} + kubernetes.io/ingress.class: {{ .Values.admin.ingress.className }} + {{- end }} + {{- with .Values.admin.ingress.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin +spec: + {{- if and (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) .Values.admin.ingress.className }} + ingressClassName: {{ .Values.admin.ingress.className | quote }} + {{- end }} + tls: + {{ .Values.admin.ingress.tls | default list | toYaml | nindent 6}} + rules: + - {{- if .Values.admin.ingress.host }} + host: {{ .Values.admin.ingress.host | quote }} + {{- end }} + http: + paths: + - path: {{ .Values.admin.ingress.path | quote }} + {{- if semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion }} + pathType: {{ .Values.admin.ingress.pathType | quote }} + {{- end }} + backend: +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} + service: + name: {{ template "seaweedfs.name" . }}-admin + port: + number: {{ .Values.admin.port }} +{{- else }} + serviceName: {{ template "seaweedfs.name" . }}-admin + servicePort: {{ .Values.admin.port }} +{{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-secret.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-secret.yaml new file mode 100644 index 00000000..bc104456 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-secret.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.admin.enabled .Values.admin.secret.adminPassword (not .Values.admin.secret.existingSecret) }} +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ template "seaweedfs.name" . }}-admin-secret + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/resource-policy": keep + "helm.sh/hook": "pre-install,pre-upgrade" + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin +data: + adminUser: {{ .Values.admin.secret.adminUser | b64enc }} + adminPassword: {{ .Values.admin.secret.adminPassword | b64enc }} +{{- end}} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-service.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-service.yaml new file mode 100644 index 00000000..825049a4 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-service.yaml @@ -0,0 +1,39 @@ +{{- if .Values.admin.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "seaweedfs.name" . }}-admin + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin +{{- if .Values.admin.service.annotations }} + annotations: + {{- toYaml .Values.admin.service.annotations | nindent 4 }} +{{- end }} +spec: + type: {{ .Values.admin.service.type }} + ports: + - name: "http" + port: {{ .Values.admin.port }} + targetPort: {{ .Values.admin.port }} + protocol: TCP + - name: "grpc" + port: {{ .Values.admin.grpcPort }} + targetPort: {{ .Values.admin.grpcPort }} + protocol: TCP + {{- if .Values.admin.metricsPort }} + - name: "metrics" + port: {{ .Values.admin.metricsPort }} + targetPort: {{ .Values.admin.metricsPort }} + protocol: TCP + {{- end }} + selector: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin +{{- end }} + diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-servicemonitor.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-servicemonitor.yaml new file mode 100644 index 00000000..271197a3 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if .Values.admin.enabled }} +{{- if .Values.admin.metricsPort }} +{{- if .Values.global.monitoring.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "seaweedfs.name" . }}-admin + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin + {{- with .Values.global.monitoring.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- with .Values.admin.serviceMonitor.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + endpoints: + - interval: 30s + port: metrics + scrapeTimeout: 5s + selector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/component: admin +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-statefulset.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-statefulset.yaml new file mode 100644 index 00000000..208f73d1 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/admin/admin-statefulset.yaml @@ -0,0 +1,345 @@ +{{- if .Values.admin.enabled }} +{{- if and (not .Values.admin.masters) (not .Values.global.masterServer) (not .Values.master.enabled) }} +{{- fail "admin.masters or global.masterServer must be set if master.enabled is false" -}} +{{- end }} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ template "seaweedfs.name" . }}-admin + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin +{{- if .Values.admin.annotations }} + annotations: + {{- toYaml .Values.admin.annotations | nindent 4 }} +{{- end }} +spec: + serviceName: {{ template "seaweedfs.name" . }}-admin + podManagementPolicy: {{ .Values.admin.podManagementPolicy }} + replicas: {{ .Values.admin.replicas }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin + {{ with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.admin.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + annotations: + {{ with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.admin.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + restartPolicy: {{ default .Values.global.restartPolicy .Values.admin.restartPolicy }} + {{- if .Values.admin.affinity }} + affinity: + {{ tpl .Values.admin.affinity . | nindent 8 | trim }} + {{- end }} + {{- if .Values.admin.topologySpreadConstraints }} + topologySpreadConstraints: + {{ tpl .Values.admin.topologySpreadConstraints . | nindent 8 | trim }} + {{- end }} + {{- if .Values.admin.tolerations }} + tolerations: + {{ tpl .Values.admin.tolerations . | nindent 8 | trim }} + {{- end }} + {{- include "seaweedfs.imagePullSecrets" . | nindent 6 }} + terminationGracePeriodSeconds: 30 + {{- if .Values.admin.priorityClassName }} + priorityClassName: {{ .Values.admin.priorityClassName | quote }} + {{- end }} + enableServiceLinks: false + {{- if .Values.admin.serviceAccountName }} + serviceAccountName: {{ .Values.admin.serviceAccountName | quote }} + {{- end }} + {{- if .Values.admin.initContainers }} + initContainers: + {{ tpl .Values.admin.initContainers . | nindent 8 | trim }} + {{- end }} + {{- if .Values.admin.podSecurityContext.enabled }} + securityContext: {{- omit .Values.admin.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: seaweedfs + image: {{ template "admin.image" . }} + imagePullPolicy: {{ default "IfNotPresent" .Values.global.imagePullPolicy }} + {{- $adminAuthEnabled := or .Values.admin.secret.existingSecret .Values.admin.secret.adminPassword }} + {{- if and .Values.admin.secret.existingSecret (not .Values.admin.secret.userKey) -}} + {{- fail "admin.secret.userKey must be set when admin.secret.existingSecret is provided" -}} + {{- end -}} + {{- if and .Values.admin.secret.existingSecret (not .Values.admin.secret.pwKey) -}} + {{- fail "admin.secret.pwKey must be set when admin.secret.existingSecret is provided" -}} + {{- end -}} + {{- $adminSecretName := .Values.admin.secret.existingSecret | default (printf "%s-admin-secret" (include "seaweedfs.name" .)) }} + env: + {{- if $adminAuthEnabled }} + - name: SEAWEEDFS_ADMIN_USER + valueFrom: + secretKeyRef: + name: {{ $adminSecretName }} + key: {{ if .Values.admin.secret.existingSecret }}{{ .Values.admin.secret.userKey }}{{ else }}adminUser{{ end }} + - name: SEAWEEDFS_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ $adminSecretName }} + key: {{ if .Values.admin.secret.existingSecret }}{{ .Values.admin.secret.pwKey }}{{ else }}adminPassword{{ end }} + {{- end }} + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SEAWEEDFS_FULLNAME + value: "{{ template "seaweedfs.name" . }}" + {{- if .Values.admin.extraEnvironmentVars }} + {{- range $key, $value := .Values.admin.extraEnvironmentVars }} + - name: {{ $key }} + {{- if kindIs "string" $value }} + value: {{ $value | quote }} + {{- else }} + valueFrom: + {{ toYaml $value | nindent 16 | trim }} + {{- end -}} + {{- end }} + {{- end }} + {{- if .Values.global.extraEnvironmentVars }} + {{- range $key, $value := .Values.global.extraEnvironmentVars }} + - name: {{ $key }} + {{- if kindIs "string" $value }} + value: {{ $value | quote }} + {{- else }} + valueFrom: + {{ toYaml $value | nindent 16 | trim }} + {{- end -}} + {{- end }} + {{- end }} + command: + - "/bin/sh" + - "-ec" + - | + exec /usr/bin/weed \ + {{- if or (eq .Values.admin.logs.type "hostPath") (eq .Values.admin.logs.type "persistentVolumeClaim") (eq .Values.admin.logs.type "emptyDir") (eq .Values.admin.logs.type "existingClaim") }} + -logdir=/logs \ + {{- else }} + -logtostderr=true \ + {{- end }} + {{- if .Values.admin.loggingOverrideLevel }} + -v={{ .Values.admin.loggingOverrideLevel }} \ + {{- else }} + -v={{ .Values.global.loggingLevel }} \ + {{- end }} + admin \ + -port={{ .Values.admin.port }} \ + -port.grpc={{ .Values.admin.grpcPort }} \ + {{- if or (eq .Values.admin.data.type "hostPath") (eq .Values.admin.data.type "persistentVolumeClaim") (eq .Values.admin.data.type "emptyDir") (eq .Values.admin.data.type "existingClaim") }} + -dataDir=/data \ + {{- else if .Values.admin.dataDir }} + -dataDir={{ .Values.admin.dataDir }} \ + {{- end }} + {{- if $adminAuthEnabled }} + -adminUser="${SEAWEEDFS_ADMIN_USER}" \ + -adminPassword="${SEAWEEDFS_ADMIN_PASSWORD}" \ + {{- end }} + {{- if .Values.admin.masters }} + -masters={{ .Values.admin.masters }}{{- if .Values.admin.extraArgs }} \{{ end }} + {{- else if .Values.global.masterServer }} + -masters={{ .Values.global.masterServer }}{{- if .Values.admin.extraArgs }} \{{ end }} + {{- else }} + -masters={{ range $index := until (.Values.master.replicas | int) }}${SEAWEEDFS_FULLNAME}-master-{{ $index }}.${SEAWEEDFS_FULLNAME}-master.{{ $.Release.Namespace }}:{{ $.Values.master.port }}{{ if lt $index (sub ($.Values.master.replicas | int) 1) }},{{ end }}{{ end }}{{- if .Values.admin.extraArgs }} \{{ end }} + {{- end }} + {{- range $index, $arg := .Values.admin.extraArgs }} + {{ $arg }}{{- if lt $index (sub (len $.Values.admin.extraArgs) 1) }} \{{ end }} + {{- end }} + volumeMounts: + {{- if or (eq .Values.admin.data.type "hostPath") (eq .Values.admin.data.type "persistentVolumeClaim") (eq .Values.admin.data.type "emptyDir") (eq .Values.admin.data.type "existingClaim") }} + - name: admin-data + mountPath: /data + {{- end }} + {{- if or (eq .Values.admin.logs.type "hostPath") (eq .Values.admin.logs.type "persistentVolumeClaim") (eq .Values.admin.logs.type "emptyDir") (eq .Values.admin.logs.type "existingClaim") }} + - name: admin-logs + mountPath: /logs + {{- end }} + {{- if .Values.global.enableSecurity }} + - name: security-config + readOnly: true + mountPath: /etc/seaweedfs/security.toml + subPath: security.toml + - name: ca-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/ca/ + - name: master-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/master/ + - name: volume-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/volume/ + - name: filer-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/filer/ + - name: client-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/client/ + - name: admin-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/admin/ + {{- end }} + {{ tpl .Values.admin.extraVolumeMounts . | nindent 12 | trim }} + ports: + - containerPort: {{ .Values.admin.port }} + name: http + - containerPort: {{ .Values.admin.grpcPort }} + name: grpc + {{- if .Values.admin.metricsPort }} + - containerPort: {{ .Values.admin.metricsPort }} + name: metrics + {{- end }} + {{- if .Values.admin.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: {{ .Values.admin.readinessProbe.httpGet.path }} + port: http + scheme: {{ .Values.admin.readinessProbe.httpGet.scheme }} + initialDelaySeconds: {{ .Values.admin.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.admin.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.admin.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.admin.readinessProbe.failureThreshold }} + timeoutSeconds: {{ .Values.admin.readinessProbe.timeoutSeconds }} + {{- end }} + {{- if .Values.admin.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: {{ .Values.admin.livenessProbe.httpGet.path }} + port: http + scheme: {{ .Values.admin.livenessProbe.httpGet.scheme }} + initialDelaySeconds: {{ .Values.admin.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.admin.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.admin.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.admin.livenessProbe.failureThreshold }} + timeoutSeconds: {{ .Values.admin.livenessProbe.timeoutSeconds }} + {{- end }} + {{- with .Values.admin.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if .Values.admin.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.admin.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.admin.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.admin.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + {{- if eq .Values.admin.data.type "hostPath" }} + - name: admin-data + hostPath: + path: {{ .Values.admin.data.hostPathPrefix }}/seaweedfs-admin-data + type: DirectoryOrCreate + {{- end }} + {{- if eq .Values.admin.data.type "emptyDir" }} + - name: admin-data + emptyDir: {} + {{- end }} + {{- if eq .Values.admin.data.type "existingClaim" }} + - name: admin-data + persistentVolumeClaim: + claimName: {{ .Values.admin.data.claimName }} + {{- end }} + {{- if eq .Values.admin.logs.type "hostPath" }} + - name: admin-logs + hostPath: + path: {{ .Values.admin.logs.hostPathPrefix }}/logs/seaweedfs/admin + type: DirectoryOrCreate + {{- end }} + {{- if eq .Values.admin.logs.type "emptyDir" }} + - name: admin-logs + emptyDir: {} + {{- end }} + {{- if eq .Values.admin.logs.type "existingClaim" }} + - name: admin-logs + persistentVolumeClaim: + claimName: {{ .Values.admin.logs.claimName }} + {{- end }} + {{- if .Values.global.enableSecurity }} + - name: security-config + configMap: + name: {{ template "seaweedfs.name" . }}-security-config + - name: ca-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-ca-cert + - name: master-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-master-cert + - name: volume-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-volume-cert + - name: filer-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-filer-cert + - name: client-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-client-cert + - name: admin-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-admin-cert + {{- end }} + {{ tpl .Values.admin.extraVolumes . | indent 8 | trim }} + {{- if .Values.admin.nodeSelector }} + nodeSelector: + {{ tpl .Values.admin.nodeSelector . | indent 8 | trim }} + {{- end }} + {{- $pvc_exists := include "admin.pvc_exists" . -}} + {{- if $pvc_exists }} + volumeClaimTemplates: + {{- if eq .Values.admin.data.type "persistentVolumeClaim" }} + - metadata: + name: admin-data + {{- with .Values.admin.data.annotations }} + annotations: + {{- toYaml . | nindent 10 }} + {{- end }} + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: {{ .Values.admin.data.storageClass }} + resources: + requests: + storage: {{ .Values.admin.data.size }} + {{- end }} + {{- if eq .Values.admin.logs.type "persistentVolumeClaim" }} + - metadata: + name: admin-logs + {{- with .Values.admin.logs.annotations }} + annotations: + {{- toYaml . | nindent 10 }} + {{- end }} + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: {{ .Values.admin.logs.storageClass }} + resources: + requests: + storage: {{ .Values.admin.logs.size }} + {{- end }} + {{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-deployment.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-deployment.yaml new file mode 100644 index 00000000..f6237bb7 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-deployment.yaml @@ -0,0 +1,482 @@ +{{- if .Values.allInOne.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "seaweedfs.name" . }}-all-in-one + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: seaweedfs-all-in-one + {{- if .Values.allInOne.annotations }} + annotations: + {{- toYaml .Values.allInOne.annotations | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.allInOne.replicas | default 1 }} + strategy: + type: {{ .Values.allInOne.updateStrategy.type | default "Recreate" }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: seaweedfs-all-in-one + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: seaweedfs-all-in-one + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.allInOne.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + annotations: + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.allInOne.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + restartPolicy: {{ default .Values.global.restartPolicy .Values.allInOne.restartPolicy }} + {{- if .Values.allInOne.affinity }} + affinity: + {{ tpl .Values.allInOne.affinity . | nindent 8 | trim }} + {{- end }} + {{- if .Values.allInOne.topologySpreadConstraints }} + topologySpreadConstraints: + {{ tpl .Values.allInOne.topologySpreadConstraints . | nindent 8 | trim }} + {{- end }} + {{- if .Values.allInOne.tolerations }} + tolerations: + {{- tpl .Values.allInOne.tolerations . | nindent 8 }} + {{- end }} + {{- include "seaweedfs.imagePullSecrets" . | nindent 6 }} + terminationGracePeriodSeconds: 60 + enableServiceLinks: false + {{- if .Values.allInOne.priorityClassName }} + priorityClassName: {{ .Values.allInOne.priorityClassName | quote }} + {{- end }} + {{- if .Values.allInOne.serviceAccountName }} + serviceAccountName: {{ .Values.allInOne.serviceAccountName | quote }} + {{- end }} + {{- if .Values.allInOne.initContainers }} + initContainers: + {{- tpl .Values.allInOne.initContainers . | nindent 8 }} + {{- end }} + {{- if .Values.allInOne.podSecurityContext.enabled }} + securityContext: + {{- omit .Values.allInOne.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: seaweedfs + image: {{ template "master.image" . }} + imagePullPolicy: {{ default "IfNotPresent" .Values.global.imagePullPolicy }} + env: + {{- /* Determine default cluster alias and the corresponding env var keys to avoid conflicts */}} + {{- $envMerged := merge (.Values.global.extraEnvironmentVars | default dict) (.Values.allInOne.extraEnvironmentVars | default dict) }} + {{- $clusterDefault := default "sw" (index $envMerged "WEED_CLUSTER_DEFAULT") }} + {{- $clusterUpper := upper $clusterDefault }} + {{- $clusterMasterKey := printf "WEED_CLUSTER_%s_MASTER" $clusterUpper }} + {{- $clusterFilerKey := printf "WEED_CLUSTER_%s_FILER" $clusterUpper }} + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SEAWEEDFS_FULLNAME + value: "{{ template "seaweedfs.name" . }}" + {{- if .Values.allInOne.extraEnvironmentVars }} + {{- range $key, $value := .Values.allInOne.extraEnvironmentVars }} + {{- if and (ne $key $clusterMasterKey) (ne $key $clusterFilerKey) }} + - name: {{ $key }} + {{- if kindIs "string" $value }} + value: {{ $value | quote }} + {{- else }} + valueFrom: + {{ toYaml $value | nindent 16 }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.global.extraEnvironmentVars }} + {{- range $key, $value := .Values.global.extraEnvironmentVars }} + {{- if and (ne $key $clusterMasterKey) (ne $key $clusterFilerKey) }} + - name: {{ $key }} + {{- if kindIs "string" $value }} + value: {{ $value | quote }} + {{- else }} + valueFrom: + {{ toYaml $value | nindent 16 }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + # Inject computed cluster endpoints for the default cluster + - name: {{ $clusterMasterKey }} + value: {{ include "seaweedfs.cluster.masterAddress" . | quote }} + - name: {{ $clusterFilerKey }} + value: {{ include "seaweedfs.cluster.filerAddress" . | quote }} + {{- if .Values.allInOne.secretExtraEnvironmentVars }} + {{- range $key, $value := .Values.allInOne.secretExtraEnvironmentVars }} + - name: {{ $key }} + valueFrom: + {{ toYaml $value | nindent 16 }} + {{- end }} + {{- end }} + command: + - "/bin/sh" + - "-ec" + - | + /usr/bin/weed \ + {{- if .Values.allInOne.loggingOverrideLevel }} + -v={{ .Values.allInOne.loggingOverrideLevel }} \ + {{- else }} + -v={{ .Values.global.loggingLevel }} \ + {{- end }} + server \ + -dir=/data \ + -master \ + -volume \ + -ip=${POD_IP} \ + -ip.bind=0.0.0.0 \ + {{- if .Values.allInOne.idleTimeout }} + -idleTimeout={{ .Values.allInOne.idleTimeout }} \ + {{- end }} + {{- if .Values.allInOne.dataCenter }} + -dataCenter={{ .Values.allInOne.dataCenter }} \ + {{- end }} + {{- if .Values.allInOne.rack }} + -rack={{ .Values.allInOne.rack }} \ + {{- end }} + {{- if .Values.allInOne.whiteList }} + -whiteList={{ .Values.allInOne.whiteList }} \ + {{- end }} + {{- if .Values.allInOne.disableHttp }} + -disableHttp={{ .Values.allInOne.disableHttp }} \ + {{- end }} + {{- if and (.Values.volume.dataDirs) (index .Values.volume.dataDirs 0 "maxVolumes") }} + -volume.max={{ index .Values.volume.dataDirs 0 "maxVolumes" }} \ + {{- end }} + -master.port={{ .Values.master.port }} \ + {{- if .Values.global.enableReplication }} + -master.defaultReplication={{ .Values.global.replicationPlacement }} \ + {{- else }} + -master.defaultReplication={{ .Values.master.defaultReplication }} \ + {{- end }} + {{- if .Values.master.volumePreallocate }} + -master.volumePreallocate \ + {{- end }} + -master.volumeSizeLimitMB={{ .Values.master.volumeSizeLimitMB }} \ + {{- if .Values.master.garbageThreshold }} + -master.garbageThreshold={{ .Values.master.garbageThreshold }} \ + {{- end }} + -volume.port={{ .Values.volume.port }} \ + -volume.readMode={{ .Values.volume.readMode }} \ + {{- if .Values.volume.imagesFixOrientation }} + -volume.images.fix.orientation \ + {{- end }} + {{- if .Values.volume.index }} + -volume.index={{ .Values.volume.index }} \ + {{- end }} + {{- if .Values.volume.fileSizeLimitMB }} + -volume.fileSizeLimitMB={{ .Values.volume.fileSizeLimitMB }} \ + {{- end }} + -volume.minFreeSpacePercent={{ .Values.volume.minFreeSpacePercent }} \ + -volume.compactionMBps={{ .Values.volume.compactionMBps }} \ + {{- if .Values.allInOne.metricsPort }} + -metricsPort={{ .Values.allInOne.metricsPort }} \ + {{- else if .Values.master.metricsPort }} + -metricsPort={{ .Values.master.metricsPort }} \ + {{- end }} + {{- if .Values.allInOne.metricsIp }} + -metricsIp={{ .Values.allInOne.metricsIp }} \ + {{- end }} + -filer \ + -filer.port={{ .Values.filer.port }} \ + {{- if .Values.filer.disableDirListing }} + -filer.disableDirListing \ + {{- end }} + -filer.dirListLimit={{ .Values.filer.dirListLimit }} \ + {{- if .Values.global.enableReplication }} + -filer.defaultReplicaPlacement={{ .Values.global.replicationPlacement }} \ + {{- else }} + -filer.defaultReplicaPlacement={{ .Values.filer.defaultReplicaPlacement }} \ + {{- end }} + {{- if .Values.filer.maxMB }} + -filer.maxMB={{ .Values.filer.maxMB }} \ + {{- end }} + {{- if .Values.filer.encryptVolumeData }} + -filer.encryptVolumeData \ + {{- end }} + {{- if .Values.filer.filerGroup}} + -filer.filerGroup={{ .Values.filer.filerGroup}} \ + {{- end }} + {{- if .Values.filer.rack }} + -filer.rack={{ .Values.filer.rack }} \ + {{- end }} + {{- if .Values.filer.dataCenter }} + -filer.dataCenter={{ .Values.filer.dataCenter }} \ + {{- end }} + {{- if .Values.allInOne.s3.enabled }} + -s3 \ + -s3.port={{ .Values.allInOne.s3.port | default .Values.s3.port }} \ + {{- $domainName := .Values.allInOne.s3.domainName | default .Values.s3.domainName }} + {{- if $domainName }} + -s3.domainName={{ $domainName }} \ + {{- end }} + {{- if .Values.global.enableSecurity }} + {{- $httpsPort := .Values.allInOne.s3.httpsPort | default .Values.s3.httpsPort }} + {{- if $httpsPort }} + -s3.port.https={{ $httpsPort }} \ + {{- end }} + -s3.cert.file=/usr/local/share/ca-certificates/client/tls.crt \ + -s3.key.file=/usr/local/share/ca-certificates/client/tls.key \ + {{- end }} + {{- if or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth .Values.filer.s3.enableAuth }} + -s3.config=/etc/sw/s3/seaweedfs_s3_config \ + {{- end }} + {{- $auditLogConfig := .Values.allInOne.s3.auditLogConfig | default .Values.s3.auditLogConfig }} + {{- if $auditLogConfig }} + -s3.auditLogConfig=/etc/sw/s3/s3_auditLogConfig.json \ + {{- end }} + {{- end }} + {{- if .Values.allInOne.sftp.enabled }} + -sftp \ + -sftp.port={{ .Values.allInOne.sftp.port | default .Values.sftp.port }} \ + {{- $sshPrivateKey := .Values.allInOne.sftp.sshPrivateKey | default .Values.sftp.sshPrivateKey }} + {{- if $sshPrivateKey }} + -sftp.sshPrivateKey={{ $sshPrivateKey }} \ + {{- end }} + {{- $hostKeysFolder := .Values.allInOne.sftp.hostKeysFolder | default .Values.sftp.hostKeysFolder }} + {{- if $hostKeysFolder }} + -sftp.hostKeysFolder={{ $hostKeysFolder }} \ + {{- end }} + {{- $authMethods := .Values.allInOne.sftp.authMethods | default .Values.sftp.authMethods }} + {{- if $authMethods }} + -sftp.authMethods={{ $authMethods }} \ + {{- end }} + {{- $maxAuthTries := .Values.allInOne.sftp.maxAuthTries | default .Values.sftp.maxAuthTries }} + {{- if $maxAuthTries }} + -sftp.maxAuthTries={{ $maxAuthTries }} \ + {{- end }} + {{- $bannerMessage := .Values.allInOne.sftp.bannerMessage | default .Values.sftp.bannerMessage }} + {{- if $bannerMessage }} + -sftp.bannerMessage="{{ $bannerMessage }}" \ + {{- end }} + {{- $loginGraceTime := .Values.allInOne.sftp.loginGraceTime | default .Values.sftp.loginGraceTime }} + {{- if $loginGraceTime }} + -sftp.loginGraceTime={{ $loginGraceTime }} \ + {{- end }} + {{- $clientAliveInterval := .Values.allInOne.sftp.clientAliveInterval | default .Values.sftp.clientAliveInterval }} + {{- if $clientAliveInterval }} + -sftp.clientAliveInterval={{ $clientAliveInterval }} \ + {{- end }} + {{- $clientAliveCountMax := .Values.allInOne.sftp.clientAliveCountMax | default .Values.sftp.clientAliveCountMax }} + {{- if $clientAliveCountMax }} + -sftp.clientAliveCountMax={{ $clientAliveCountMax }} \ + {{- end }} + {{- if or .Values.allInOne.sftp.enableAuth .Values.sftp.enableAuth }} + -sftp.userStoreFile=/etc/sw/sftp/seaweedfs_sftp_config \ + {{- end }} + {{- end }} + {{- $extraArgsCount := len .Values.allInOne.extraArgs }} + {{- range $i, $arg := .Values.allInOne.extraArgs }} + {{ $arg | quote }}{{ if ne (add1 $i) $extraArgsCount }} \{{ end }} + {{- end }} + + volumeMounts: + - name: data + mountPath: /data + {{- if and .Values.allInOne.s3.enabled (or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth .Values.filer.s3.enableAuth) }} + - name: config-s3-users + mountPath: /etc/sw/s3 + readOnly: true + {{- end }} + {{- if .Values.allInOne.sftp.enabled }} + - name: config-ssh + mountPath: /etc/sw/ssh + readOnly: true + {{- if or .Values.allInOne.sftp.enableAuth .Values.sftp.enableAuth }} + - mountPath: /etc/sw/sftp + name: config-users + readOnly: true + {{- end }} + {{- end }} + {{- if .Values.filer.notificationConfig }} + - name: notification-config + mountPath: /etc/seaweedfs/notification.toml + subPath: notification.toml + readOnly: true + {{- end }} + - name: master-config + mountPath: /etc/seaweedfs/master.toml + subPath: master.toml + readOnly: true + {{- if .Values.global.enableSecurity }} + - name: security-config + mountPath: /etc/seaweedfs/security.toml + subPath: security.toml + readOnly: true + - name: ca-cert + mountPath: /usr/local/share/ca-certificates/ca/ + readOnly: true + - name: master-cert + mountPath: /usr/local/share/ca-certificates/master/ + readOnly: true + - name: volume-cert + mountPath: /usr/local/share/ca-certificates/volume/ + readOnly: true + - name: filer-cert + mountPath: /usr/local/share/ca-certificates/filer/ + readOnly: true + - name: client-cert + mountPath: /usr/local/share/ca-certificates/client/ + readOnly: true + {{- end }} + {{ tpl .Values.allInOne.extraVolumeMounts . | nindent 12 }} + ports: + - containerPort: {{ .Values.master.port }} + name: swfs-mas + - containerPort: {{ .Values.master.grpcPort }} + name: swfs-mas-grpc + - containerPort: {{ .Values.volume.port }} + name: swfs-vol + - containerPort: {{ .Values.volume.grpcPort }} + name: swfs-vol-grpc + - containerPort: {{ .Values.filer.port }} + name: swfs-fil + - containerPort: {{ .Values.filer.grpcPort }} + name: swfs-fil-grpc + {{- if .Values.allInOne.s3.enabled }} + - containerPort: {{ .Values.allInOne.s3.port | default .Values.s3.port }} + name: swfs-s3 + {{- $httpsPort := .Values.allInOne.s3.httpsPort | default .Values.s3.httpsPort }} + {{- if $httpsPort }} + - containerPort: {{ $httpsPort }} + name: swfs-s3-tls + {{- end }} + {{- end }} + {{- if .Values.allInOne.sftp.enabled }} + - containerPort: {{ .Values.allInOne.sftp.port | default .Values.sftp.port }} + name: swfs-sftp + {{- end }} + {{- if .Values.allInOne.metricsPort }} + - containerPort: {{ .Values.allInOne.metricsPort }} + name: server-metrics + {{- end }} + {{- if .Values.allInOne.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: {{ .Values.allInOne.readinessProbe.httpGet.path }} + port: {{ .Values.master.port }} + scheme: {{ .Values.allInOne.readinessProbe.httpGet.scheme }} + initialDelaySeconds: {{ .Values.allInOne.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.allInOne.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.allInOne.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.allInOne.readinessProbe.failureThreshold }} + timeoutSeconds: {{ .Values.allInOne.readinessProbe.timeoutSeconds }} + {{- end }} + {{- if .Values.allInOne.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: {{ .Values.allInOne.livenessProbe.httpGet.path }} + port: {{ .Values.master.port }} + scheme: {{ .Values.allInOne.livenessProbe.httpGet.scheme }} + initialDelaySeconds: {{ .Values.allInOne.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.allInOne.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.allInOne.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.allInOne.livenessProbe.failureThreshold }} + timeoutSeconds: {{ .Values.allInOne.livenessProbe.timeoutSeconds }} + {{- end }} + {{- with .Values.allInOne.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if .Values.allInOne.containerSecurityContext.enabled }} + securityContext: + {{- omit .Values.allInOne.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.allInOne.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.allInOne.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + - name: data + {{- if eq .Values.allInOne.data.type "hostPath" }} + hostPath: + path: {{ .Values.allInOne.data.hostPathPrefix }}/seaweedfs-all-in-one-data/ + type: DirectoryOrCreate + {{- else if eq .Values.allInOne.data.type "persistentVolumeClaim" }} + persistentVolumeClaim: + claimName: {{ template "seaweedfs.name" . }}-all-in-one-data + {{- else if eq .Values.allInOne.data.type "existingClaim" }} + persistentVolumeClaim: + claimName: {{ .Values.allInOne.data.claimName }} + {{- else if eq .Values.allInOne.data.type "emptyDir" }} + emptyDir: {} + {{- end }} + {{- if and .Values.allInOne.s3.enabled (or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth .Values.filer.s3.enableAuth) }} + - name: config-s3-users + secret: + defaultMode: 420 + secretName: {{ default (printf "%s-s3-secret" (include "seaweedfs.name" .)) (or .Values.allInOne.s3.existingConfigSecret .Values.s3.existingConfigSecret .Values.filer.s3.existingConfigSecret) }} + {{- end }} + {{- if .Values.allInOne.sftp.enabled }} + - name: config-ssh + secret: + defaultMode: 420 + secretName: {{ default (printf "%s-sftp-ssh-secret" (include "seaweedfs.name" .)) (or .Values.allInOne.sftp.existingSshConfigSecret .Values.sftp.existingSshConfigSecret) }} + {{- if or .Values.allInOne.sftp.enableAuth .Values.sftp.enableAuth }} + - name: config-users + secret: + defaultMode: 420 + secretName: {{ default (printf "%s-sftp-secret" (include "seaweedfs.name" .)) (or .Values.allInOne.sftp.existingConfigSecret .Values.sftp.existingConfigSecret) }} + {{- end }} + {{- end }} + {{- if .Values.filer.notificationConfig }} + - name: notification-config + configMap: + name: {{ template "seaweedfs.name" . }}-notification-config + {{- end }} + - name: master-config + configMap: + name: {{ template "seaweedfs.name" . }}-master-config + {{- if .Values.global.enableSecurity }} + - name: security-config + configMap: + name: {{ template "seaweedfs.name" . }}-security-config + - name: ca-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-ca-cert + - name: master-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-master-cert + - name: volume-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-volume-cert + - name: filer-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-filer-cert + - name: client-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-client-cert + {{- end }} + {{ tpl .Values.allInOne.extraVolumes . | nindent 8 }} + {{- if .Values.allInOne.nodeSelector }} + nodeSelector: + {{ tpl .Values.allInOne.nodeSelector . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-pvc.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-pvc.yaml new file mode 100644 index 00000000..a62450c3 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-pvc.yaml @@ -0,0 +1,28 @@ +{{- if .Values.allInOne.enabled }} +{{- if eq .Values.allInOne.data.type "persistentVolumeClaim" }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ template "seaweedfs.name" . }}-all-in-one-data + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: seaweedfs-all-in-one + {{- with .Values.allInOne.data.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + accessModes: + {{- toYaml (.Values.allInOne.data.accessModes | default (list "ReadWriteOnce")) | nindent 4 }} + {{- if .Values.allInOne.data.storageClass }} + storageClassName: {{ .Values.allInOne.data.storageClass }} + {{- end }} + resources: + requests: + storage: {{ .Values.allInOne.data.size | default "10Gi" }} +{{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-service.yml b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-service.yml new file mode 100644 index 00000000..b13f5789 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-service.yml @@ -0,0 +1,85 @@ +{{- if .Values.allInOne.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "seaweedfs.name" . }}-all-in-one + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: seaweedfs-all-in-one + {{- if .Values.allInOne.service.annotations }} + annotations: + {{- toYaml .Values.allInOne.service.annotations | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.allInOne.service.type | default "ClusterIP" }} + internalTrafficPolicy: {{ .Values.allInOne.service.internalTrafficPolicy | default "Cluster" }} + ports: + # Master ports + - name: "swfs-master" + port: {{ .Values.master.port }} + targetPort: {{ .Values.master.port }} + protocol: TCP + - name: "swfs-master-grpc" + port: {{ .Values.master.grpcPort }} + targetPort: {{ .Values.master.grpcPort }} + protocol: TCP + + # Volume ports + - name: "swfs-volume" + port: {{ .Values.volume.port }} + targetPort: {{ .Values.volume.port }} + protocol: TCP + - name: "swfs-volume-grpc" + port: {{ .Values.volume.grpcPort }} + targetPort: {{ .Values.volume.grpcPort }} + protocol: TCP + + # Filer ports + - name: "swfs-filer" + port: {{ .Values.filer.port }} + targetPort: {{ .Values.filer.port }} + protocol: TCP + - name: "swfs-filer-grpc" + port: {{ .Values.filer.grpcPort }} + targetPort: {{ .Values.filer.grpcPort }} + protocol: TCP + + # S3 ports (if enabled) + {{- if .Values.allInOne.s3.enabled }} + - name: "swfs-s3" + port: {{ .Values.allInOne.s3.port | default .Values.s3.port }} + targetPort: {{ .Values.allInOne.s3.port | default .Values.s3.port }} + protocol: TCP + {{- $httpsPort := .Values.allInOne.s3.httpsPort | default .Values.s3.httpsPort }} + {{- if $httpsPort }} + - name: "swfs-s3-tls" + port: {{ $httpsPort }} + targetPort: {{ $httpsPort }} + protocol: TCP + {{- end }} + {{- end }} + + # SFTP ports (if enabled) + {{- if .Values.allInOne.sftp.enabled }} + - name: "swfs-sftp" + port: {{ .Values.allInOne.sftp.port | default .Values.sftp.port }} + targetPort: {{ .Values.allInOne.sftp.port | default .Values.sftp.port }} + protocol: TCP + {{- end }} + + # Server metrics port (single metrics endpoint for all services) + {{- if .Values.allInOne.metricsPort }} + - name: "server-metrics" + port: {{ .Values.allInOne.metricsPort }} + targetPort: {{ .Values.allInOne.metricsPort }} + protocol: TCP + {{- end }} + + selector: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/component: seaweedfs-all-in-one +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-servicemonitor.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-servicemonitor.yaml similarity index 70% rename from packages/system/seaweedfs/charts/seaweedfs/templates/volume-servicemonitor.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-servicemonitor.yaml index 4aeacc41..0f9ce392 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-servicemonitor.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/all-in-one/all-in-one-servicemonitor.yaml @@ -1,29 +1,29 @@ -{{- if .Values.volume.enabled }} -{{- if .Values.volume.metricsPort }} +{{- if .Values.allInOne.enabled }} {{- if .Values.global.monitoring.enabled }} apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: - name: {{ template "seaweedfs.name" . }}-volume + name: {{ template "seaweedfs.name" . }}-all-in-one namespace: {{ .Release.Namespace }} labels: app.kubernetes.io/name: {{ template "seaweedfs.name" . }} helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/component: volume + app.kubernetes.io/component: all-in-one {{- with .Values.global.monitoring.additionalLabels }} {{- toYaml . | nindent 4 }} {{- end }} spec: endpoints: + {{- if .Values.allInOne.metricsPort }} - interval: 30s - port: metrics + port: server-metrics scrapeTimeout: 5s + {{- end }} selector: matchLabels: app.kubernetes.io/name: {{ template "seaweedfs.name" . }} - app.kubernetes.io/component: volume -{{- end }} -{{- end }} + app.kubernetes.io/component: seaweedfs-all-in-one {{- end }} +{{- end }} \ No newline at end of file diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cert/admin-cert.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/admin-cert.yaml new file mode 100644 index 00000000..be526601 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/admin-cert.yaml @@ -0,0 +1,43 @@ +{{- if and .Values.global.enableSecurity (not .Values.certificates.externalCertificates.enabled)}} +apiVersion: cert-manager.io/v1{{ if .Values.global.certificates.alphacrds }}alpha1{{ end }} +kind: Certificate +metadata: + name: {{ template "seaweedfs.name" . }}-admin-cert + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin + {{- if .Values.admin.annotations }} + annotations: + {{- toYaml .Values.admin.annotations | nindent 4 }} + {{- end }} +spec: + secretName: {{ template "seaweedfs.name" . }}-admin-cert + issuerRef: + name: {{ template "seaweedfs.name" . }}-ca-issuer + kind: Issuer + commonName: {{ .Values.certificates.commonName }} + subject: + organizations: + - "SeaweedFS CA" + dnsNames: + - '*.{{ template "seaweedfs.name" . }}-admin' + - '*.{{ template "seaweedfs.name" . }}-admin.{{ .Release.Namespace }}' + - '*.{{ template "seaweedfs.name" . }}-admin.{{ .Release.Namespace }}.svc' + - '*.{{ template "seaweedfs.name" . }}-admin.{{ .Release.Namespace }}.svc.cluster.local' +{{- if .Values.certificates.ipAddresses }} + ipAddresses: + {{- range .Values.certificates.ipAddresses }} + - {{ . }} + {{- end }} +{{- end }} + privateKey: + algorithm: {{ .Values.certificates.keyAlgorithm }} + size: {{ .Values.certificates.keySize }} + duration: {{ .Values.certificates.duration }} + renewBefore: {{ .Values.certificates.renewBefore }} +{{- end }} + diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/ca-cert.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml similarity index 74% rename from packages/system/seaweedfs/charts/seaweedfs/templates/ca-cert.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml index 0fd6615e..a38287de 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/ca-cert.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml @@ -13,6 +13,14 @@ spec: secretName: {{ template "seaweedfs.name" . }}-ca-cert commonName: "{{ template "seaweedfs.name" . }}-root-ca" isCA: true + privateKey: + rotationPolicy: Never + {{- if .Values.certificates.ca.duration }} + duration: {{ .Values.certificates.ca.duration }} + {{- end }} + {{- if .Values.certificates.ca.renewBefore }} + renewBefore: {{ .Values.certificates.ca.renewBefore }} + {{- end }} issuerRef: name: {{ template "seaweedfs.name" . }}-issuer kind: Issuer diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cert-caissuer.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/cert-caissuer.yaml similarity index 100% rename from packages/system/seaweedfs/charts/seaweedfs/templates/cert-caissuer.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/cert/cert-caissuer.yaml diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cert-issuer.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/cert-issuer.yaml similarity index 100% rename from packages/system/seaweedfs/charts/seaweedfs/templates/cert-issuer.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/cert/cert-issuer.yaml diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/client-cert.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/client-cert.yaml similarity index 100% rename from packages/system/seaweedfs/charts/seaweedfs/templates/client-cert.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/cert/client-cert.yaml diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/filer-cert.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/filer-cert.yaml similarity index 93% rename from packages/system/seaweedfs/charts/seaweedfs/templates/filer-cert.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/cert/filer-cert.yaml index c17815af..4cb117ae 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/filer-cert.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/filer-cert.yaml @@ -10,6 +10,10 @@ metadata: app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/component: filer + {{- if .Values.filer.annotations }} + annotations: + {{- toYaml .Values.filer.annotations | nindent 4 }} + {{- end }} spec: secretName: {{ template "seaweedfs.name" . }}-filer-cert issuerRef: diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/master-cert.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/master-cert.yaml similarity index 93% rename from packages/system/seaweedfs/charts/seaweedfs/templates/master-cert.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/cert/master-cert.yaml index 47dcaacd..25678525 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/master-cert.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/master-cert.yaml @@ -10,6 +10,10 @@ metadata: app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/component: master +{{- if .Values.master.annotations }} + annotations: + {{- toYaml .Values.master.annotations | nindent 4 }} +{{- end }} spec: secretName: {{ template "seaweedfs.name" . }}-master-cert issuerRef: diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-cert.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/volume-cert.yaml similarity index 93% rename from packages/system/seaweedfs/charts/seaweedfs/templates/volume-cert.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/cert/volume-cert.yaml index 4df63db2..bd59a676 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-cert.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/volume-cert.yaml @@ -10,6 +10,10 @@ metadata: app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/component: volume +{{- if .Values.volume.annotations }} + annotations: + {{- toYaml .Values.volume.annotations | nindent 4 }} +{{- end }} spec: secretName: {{ template "seaweedfs.name" . }}-volume-cert issuerRef: diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cert/worker-cert.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/worker-cert.yaml new file mode 100644 index 00000000..85edeb33 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/worker-cert.yaml @@ -0,0 +1,43 @@ +{{- if and .Values.global.enableSecurity (not .Values.certificates.externalCertificates.enabled)}} +apiVersion: cert-manager.io/v1{{ if .Values.global.certificates.alphacrds }}alpha1{{ end }} +kind: Certificate +metadata: + name: {{ template "seaweedfs.name" . }}-worker-cert + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker + {{- if .Values.worker.annotations }} + annotations: + {{- toYaml .Values.worker.annotations | nindent 4 }} + {{- end }} +spec: + secretName: {{ template "seaweedfs.name" . }}-worker-cert + issuerRef: + name: {{ template "seaweedfs.name" . }}-ca-issuer + kind: Issuer + commonName: {{ .Values.certificates.commonName }} + subject: + organizations: + - "SeaweedFS CA" + dnsNames: + - '*.{{ template "seaweedfs.name" . }}-worker' + - '*.{{ template "seaweedfs.name" . }}-worker.{{ .Release.Namespace }}' + - '*.{{ template "seaweedfs.name" . }}-worker.{{ .Release.Namespace }}.svc' + - '*.{{ template "seaweedfs.name" . }}-worker.{{ .Release.Namespace }}.svc.cluster.local' +{{- if .Values.certificates.ipAddresses }} + ipAddresses: + {{- range .Values.certificates.ipAddresses }} + - {{ . }} + {{- end }} +{{- end }} + privateKey: + algorithm: {{ .Values.certificates.keyAlgorithm }} + size: {{ .Values.certificates.keySize }} + duration: {{ .Values.certificates.duration }} + renewBefore: {{ .Values.certificates.renewBefore }} +{{- end }} + diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cosi-bucket-class.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cosi-bucket-class.yaml deleted file mode 100644 index e5503abd..00000000 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/cosi-bucket-class.yaml +++ /dev/null @@ -1,16 +0,0 @@ -{{- if and .Values.cosi.enabled .Values.cosi.bucketClassName }} ---- -kind: BucketClass -apiVersion: objectstorage.k8s.io/v1alpha1 -metadata: - name: {{ .Values.cosi.bucketClassName }} -driverName: {{ .Values.cosi.driverName }} -deletionPolicy: Delete ---- -kind: BucketAccessClass -apiVersion: objectstorage.k8s.io/v1alpha1 -metadata: - name: {{ .Values.cosi.bucketClassName }} -driverName: {{ .Values.cosi.driverName }} -authenticationType: KEY -{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-bucket-class.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-bucket-class.yaml new file mode 100644 index 00000000..25e00252 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-bucket-class.yaml @@ -0,0 +1,38 @@ +{{- if and .Values.cosi.enabled .Values.cosi.bucketClassName }} +--- +kind: BucketClass +apiVersion: objectstorage.k8s.io/v1alpha1 +metadata: + name: {{ .Values.cosi.bucketClassName }} +driverName: {{ .Values.cosi.driverName }} +deletionPolicy: Delete +--- +kind: BucketClass +apiVersion: objectstorage.k8s.io/v1alpha1 +metadata: + name: {{ .Values.cosi.bucketClassName }}-lock +driverName: {{ .Values.cosi.driverName }} +deletionPolicy: Retain +parameters: + objectLockEnabled: "true" + objectLockRetentionMode: "COMPLIANCE" + objectLockRetentionDays: "365" +--- +kind: BucketAccessClass +apiVersion: objectstorage.k8s.io/v1alpha1 +metadata: + name: {{ .Values.cosi.bucketClassName }} +driverName: {{ .Values.cosi.driverName }} +authenticationType: KEY +parameters: + accessPolicy: readwrite +--- +kind: BucketAccessClass +apiVersion: objectstorage.k8s.io/v1alpha1 +metadata: + name: {{ .Values.cosi.bucketClassName }}-readonly +driverName: {{ .Values.cosi.driverName }} +authenticationType: KEY +parameters: + accessPolicy: readonly +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cosi-cluster-role.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-cluster-role.yaml similarity index 100% rename from packages/system/seaweedfs/charts/seaweedfs/templates/cosi-cluster-role.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-cluster-role.yaml diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cosi-deployment.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-deployment.yaml similarity index 94% rename from packages/system/seaweedfs/charts/seaweedfs/templates/cosi-deployment.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-deployment.yaml index 5c5c7e30..813af850 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/cosi-deployment.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-deployment.yaml @@ -9,12 +9,12 @@ metadata: helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: objectstorage-provisioner spec: replicas: {{ .Values.cosi.replicas }} selector: matchLabels: app.kubernetes.io/name: {{ template "seaweedfs.name" . }} - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/component: objectstorage-provisioner template: @@ -39,6 +39,14 @@ spec: {{- end }} spec: restartPolicy: {{ default .Values.global.restartPolicy .Values.cosi.restartPolicy }} + {{- if .Values.cosi.affinity }} + affinity: + {{ tpl .Values.cosi.affinity . | nindent 8 | trim }} + {{- end }} + {{- if .Values.cosi.topologySpreadConstraints }} + topologySpreadConstraints: + {{ tpl .Values.cosi.topologySpreadConstraint . | nindent 8 | trim }} + {{- end }} {{- if .Values.cosi.tolerations }} tolerations: {{ tpl .Values.cosi.tolerations . | nindent 8 | trim }} @@ -157,7 +165,7 @@ spec: volumeMounts: - mountPath: /var/lib/cosi name: socket - {{- with .Values.cosi.resources }} + {{- with .Values.cosi.sidecar.resources }} resources: {{- toYaml . | nindent 12 }} {{- end }} @@ -177,7 +185,7 @@ spec: {{- if .Values.cosi.existingConfigSecret }} secretName: {{ .Values.cosi.existingConfigSecret }} {{- else }} - secretName: seaweedfs-client-cert + secretName: seaweedfs-s3-secret {{- end }} {{- end }} {{- if .Values.global.enableSecurity }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cosi-service-account.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-service-account.yaml similarity index 100% rename from packages/system/seaweedfs/charts/seaweedfs/templates/cosi-service-account.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/cosi/cosi-service-account.yaml diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/filer-ingress.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-ingress.yaml similarity index 66% rename from packages/system/seaweedfs/charts/seaweedfs/templates/filer-ingress.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-ingress.yaml index 7a7c9886..b185a58b 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/filer-ingress.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-ingress.yaml @@ -1,5 +1,8 @@ -{{- if .Values.filer.enabled }} -{{- if .Values.filer.ingress.enabled }} +{{- /* Filer ingress works for both normal mode (filer.enabled) and all-in-one mode (allInOne.enabled) */}} +{{- $filerEnabled := or .Values.filer.enabled .Values.allInOne.enabled }} +{{- if and $filerEnabled .Values.filer.ingress.enabled }} +{{- /* Determine service name based on deployment mode */}} +{{- $serviceName := ternary (printf "%s-all-in-one" (include "seaweedfs.name" .)) (printf "%s-filer" (include "seaweedfs.name" .)) .Values.allInOne.enabled }} {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} apiVersion: networking.k8s.io/v1 {{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion }} @@ -28,21 +31,19 @@ spec: rules: - http: paths: - - path: /sw-filer/?(.*) - pathType: ImplementationSpecific + - path: {{ .Values.filer.ingress.path | quote }} + pathType: {{ .Values.filer.ingress.pathType | quote }} backend: {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} service: - name: {{ template "seaweedfs.name" . }}-filer + name: {{ $serviceName }} port: number: {{ .Values.filer.port }} - #name: {{- else }} - serviceName: {{ template "seaweedfs.name" . }}-filer + serviceName: {{ $serviceName }} servicePort: {{ .Values.filer.port }} {{- end }} {{- if .Values.filer.ingress.host }} host: {{ .Values.filer.ingress.host }} {{- end }} {{- end }} -{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/filer-service-client.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-service-client.yaml similarity index 90% rename from packages/system/seaweedfs/charts/seaweedfs/templates/filer-service-client.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-service-client.yaml index d7618c4c..1c32de0b 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/filer-service-client.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-service-client.yaml @@ -13,6 +13,10 @@ metadata: {{- if .Values.filer.metricsPort }} monitoring: "true" {{- end }} +{{- if .Values.filer.annotations }} + annotations: + {{- toYaml .Values.filer.annotations | nindent 4 }} +{{- end }} spec: clusterIP: None ports: diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/filer-service.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-service.yaml similarity index 92% rename from packages/system/seaweedfs/charts/seaweedfs/templates/filer-service.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-service.yaml index ab7e98df..67436972 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/filer-service.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-service.yaml @@ -12,6 +12,10 @@ metadata: app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/component: filer +{{- if .Values.filer.annotations }} + annotations: + {{- toYaml .Values.filer.annotations | nindent 4 }} +{{- end }} spec: clusterIP: None publishNotReadyAddresses: true diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/filer-servicemonitor.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-servicemonitor.yaml similarity index 88% rename from packages/system/seaweedfs/charts/seaweedfs/templates/filer-servicemonitor.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-servicemonitor.yaml index 76c981c1..e26c04b1 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/filer-servicemonitor.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-servicemonitor.yaml @@ -15,6 +15,10 @@ metadata: {{- with .Values.global.monitoring.additionalLabels }} {{- toYaml . | nindent 4 }} {{- end }} +{{- if .Values.filer.annotations }} + annotations: + {{- toYaml .Values.filer.annotations | nindent 4 }} +{{- end }} spec: endpoints: - interval: 30s diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/filer-statefulset.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-statefulset.yaml similarity index 88% rename from packages/system/seaweedfs/charts/seaweedfs/templates/filer-statefulset.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-statefulset.yaml index 49b62e86..e29239c3 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/filer-statefulset.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/filer/filer-statefulset.yaml @@ -10,6 +10,10 @@ metadata: app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/component: filer +{{- if .Values.filer.annotations }} + annotations: + {{- toYaml .Values.filer.annotations | nindent 4 }} +{{- end }} spec: serviceName: {{ template "seaweedfs.name" . }}-filer podManagementPolicy: {{ .Values.filer.podManagementPolicy }} @@ -49,7 +53,7 @@ spec: {{- $configSecret := (lookup "v1" "Secret" .Release.Namespace .Values.filer.s3.existingConfigSecret) | default dict }} checksum/s3config: {{ $configSecret | toYaml | sha256sum }} {{- else }} - checksum/s3config: {{ include (print .Template.BasePath "/s3-secret.yaml") . | sha256sum }} + checksum/s3config: {{ include (print .Template.BasePath "/s3/s3-secret.yaml") . | sha256sum }} {{- end }} spec: restartPolicy: {{ default .Values.global.restartPolicy .Values.filer.restartPolicy }} @@ -57,6 +61,10 @@ spec: affinity: {{ tpl .Values.filer.affinity . | nindent 8 | trim }} {{- end }} + {{- if .Values.filer.topologySpreadConstraints }} + topologySpreadConstraints: + {{ tpl .Values.filer.topologySpreadConstraints . | nindent 8 | trim }} + {{- end }} {{- if .Values.filer.tolerations }} tolerations: {{ tpl .Values.filer.tolerations . | nindent 8 | trim }} @@ -154,6 +162,9 @@ spec: {{- if .Values.filer.metricsPort }} -metricsPort={{ .Values.filer.metricsPort }} \ {{- end }} + {{- if .Values.filer.metricsIp }} + -metricsIp={{ .Values.filer.metricsIp }} \ + {{- end }} {{- if .Values.filer.redirectOnRead }} -redirectOnRead \ {{- end }} @@ -165,7 +176,7 @@ spec: {{- end }} -dirListLimit={{ .Values.filer.dirListLimit }} \ {{- if .Values.global.enableReplication }} - -defaultReplicaPlacement={{ .Values.global.replicationPlacment }} \ + -defaultReplicaPlacement={{ .Values.global.replicationPlacement }} \ {{- else }} -defaultReplicaPlacement={{ .Values.filer.defaultReplicaPlacement }} \ {{- end }} @@ -179,9 +190,16 @@ spec: -encryptVolumeData \ {{- end }} -ip=${POD_IP} \ + -ip.bind={{ .Values.filer.ipBind }} \ {{- if .Values.filer.filerGroup}} -filerGroup={{ .Values.filer.filerGroup}} \ {{- end }} + {{- if .Values.filer.rack }} + -rack={{ .Values.filer.rack }} \ + {{- end }} + {{- if .Values.filer.dataCenter }} + -dataCenter={{ .Values.filer.dataCenter }} \ + {{- end }} {{- if .Values.filer.s3.enabled }} -s3 \ -s3.port={{ .Values.filer.s3.port }} \ @@ -195,9 +213,6 @@ spec: -s3.cert.file=/usr/local/share/ca-certificates/client/tls.crt \ -s3.key.file=/usr/local/share/ca-certificates/client/tls.key \ {{- end }} - {{- if .Values.filer.s3.allowEmptyFolder }} - -s3.allowEmptyFolder={{ .Values.filer.s3.allowEmptyFolder }} \ - {{- end }} {{- if .Values.filer.s3.enableAuth }} -s3.config=/etc/sw/seaweedfs_s3_config \ {{- end }} @@ -205,7 +220,10 @@ spec: -s3.auditLogConfig=/etc/sw/filer_s3_auditLogConfig.json \ {{- end }} {{- end }} - -master={{ if .Values.global.masterServer }}{{.Values.global.masterServer}}{{ else }}{{ range $index := until (.Values.master.replicas | int) }}${SEAWEEDFS_FULLNAME}-master-{{ $index }}.${SEAWEEDFS_FULLNAME}-master.{{ $.Release.Namespace }}:{{ $.Values.master.port }}{{ if lt $index (sub ($.Values.master.replicas | int) 1) }},{{ end }}{{ end }}{{ end }} + -master={{ include "seaweedfs.masterServerArg" . }} \ + {{- range .Values.filer.extraArgs }} + {{ . }} \ + {{- end }} volumeMounts: {{- if (or (eq .Values.filer.logs.type "hostPath") (eq .Values.filer.logs.type "persistentVolumeClaim") (eq .Values.filer.logs.type "emptyDir")) }} - name: seaweedfs-filer-log-volume @@ -220,6 +238,12 @@ spec: - name: data-filer mountPath: /data {{- end }} + {{- if .Values.filer.notificationConfig }} + - name: notification-config + readOnly: true + mountPath: /etc/seaweedfs/notification.toml + subPath: notification.toml + {{- end }} {{- if .Values.global.enableSecurity }} - name: security-config readOnly: true @@ -249,12 +273,20 @@ spec: name: metrics - containerPort: {{ .Values.filer.grpcPort }} #name: swfs-filer-grpc + {{- if .Values.filer.s3.enabled }} + - containerPort: {{ .Values.filer.s3.port }} + name: swfs-s3 + {{- if .Values.filer.s3.httpsPort }} + - containerPort: {{ .Values.filer.s3.httpsPort }} + name: swfs-s3-tls + {{- end }} + {{- end }} {{- if .Values.filer.readinessProbe.enabled }} readinessProbe: httpGet: path: {{ .Values.filer.readinessProbe.httpGet.path }} port: {{ .Values.filer.port }} - scheme: {{ .Values.filer.readinessProbe.scheme }} + scheme: {{ .Values.filer.readinessProbe.httpGet.scheme }} initialDelaySeconds: {{ .Values.filer.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.filer.readinessProbe.periodSeconds }} successThreshold: {{ .Values.filer.readinessProbe.successThreshold }} @@ -266,7 +298,7 @@ spec: httpGet: path: {{ .Values.filer.livenessProbe.httpGet.path }} port: {{ .Values.filer.port }} - scheme: {{ .Values.filer.livenessProbe.scheme }} + scheme: {{ .Values.filer.livenessProbe.httpGet.scheme }} initialDelaySeconds: {{ .Values.filer.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.filer.livenessProbe.periodSeconds }} successThreshold: {{ .Values.filer.livenessProbe.successThreshold }} @@ -327,6 +359,11 @@ spec: secretName: seaweedfs-s3-secret {{- end }} {{- end }} + {{- if .Values.filer.notificationConfig }} + - name: notification-config + configMap: + name: {{ template "seaweedfs.name" . }}-notification-config + {{- end }} {{- if .Values.global.enableSecurity }} - name: security-config configMap: @@ -352,10 +389,12 @@ spec: nodeSelector: {{ tpl .Values.filer.nodeSelector . | indent 8 | trim }} {{- end }} - {{- if and (.Values.filer.enablePVC) (eq .Values.filer.data.type "persistentVolumeClaim") }} + {{- if and (.Values.filer.enablePVC) (not .Values.filer.data) }} # DEPRECATION: Deprecate in favor of filer.data section below volumeClaimTemplates: - - metadata: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: name: data-filer spec: accessModes: @@ -371,7 +410,9 @@ spec: {{- if $pvc_exists }} volumeClaimTemplates: {{- if eq .Values.filer.data.type "persistentVolumeClaim" }} - - metadata: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: name: data-filer {{- with .Values.filer.data.annotations }} annotations: @@ -385,7 +426,9 @@ spec: storage: {{ .Values.filer.data.size }} {{- end }} {{- if eq .Values.filer.logs.type "persistentVolumeClaim" }} - - metadata: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: name: seaweedfs-filer-log-volume {{- with .Values.filer.logs.annotations }} annotations: diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/master-configmap.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-configmap.yaml similarity index 72% rename from packages/system/seaweedfs/charts/seaweedfs/templates/master-configmap.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/master/master-configmap.yaml index 73155e87..b3d7fe7d 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/master-configmap.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-configmap.yaml @@ -1,4 +1,4 @@ -{{- if .Values.master.enabled }} +{{- if or .Values.master.enabled .Values.allInOne.enabled }} apiVersion: v1 kind: ConfigMap metadata: @@ -9,6 +9,10 @@ metadata: helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Values.master.annotations }} + annotations: + {{- toYaml .Values.master.annotations | nindent 4 }} +{{- end }} data: master.toml: |- {{ .Values.master.config | nindent 4 }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/master-ingress.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-ingress.yaml similarity index 92% rename from packages/system/seaweedfs/charts/seaweedfs/templates/master-ingress.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/master/master-ingress.yaml index 62d7f7a5..ac1cb339 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/master-ingress.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-ingress.yaml @@ -28,8 +28,8 @@ spec: rules: - http: paths: - - path: /sw-master/?(.*) - pathType: ImplementationSpecific + - path: {{ .Values.master.ingress.path | quote }} + pathType: {{ .Values.master.ingress.pathType | quote }} backend: {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} service: diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/master-service.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-service.yaml similarity index 91% rename from packages/system/seaweedfs/charts/seaweedfs/templates/master-service.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/master/master-service.yaml index 9e69f94e..0086b84c 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/master-service.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-service.yaml @@ -11,6 +11,9 @@ metadata: app.kubernetes.io/managed-by: {{ .Release.Service }} annotations: service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" +{{- if .Values.master.annotations }} + {{- toYaml .Values.master.annotations | nindent 4 }} +{{- end }} spec: clusterIP: None publishNotReadyAddresses: true diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/master-servicemonitor.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-servicemonitor.yaml similarity index 88% rename from packages/system/seaweedfs/charts/seaweedfs/templates/master-servicemonitor.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/master/master-servicemonitor.yaml index 81cade2e..7804e84a 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/master-servicemonitor.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-servicemonitor.yaml @@ -15,6 +15,10 @@ metadata: {{- with .Values.global.monitoring.additionalLabels }} {{- toYaml . | nindent 4 }} {{- end }} +{{- if .Values.master.annotations }} + annotations: + {{- toYaml .Values.master.annotations | nindent 4 }} +{{- end }} spec: endpoints: - interval: 30s diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/master-statefulset.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-statefulset.yaml similarity index 89% rename from packages/system/seaweedfs/charts/seaweedfs/templates/master-statefulset.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/master/master-statefulset.yaml index 73d1f9fb..50e0e97d 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/master-statefulset.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/master/master-statefulset.yaml @@ -9,6 +9,11 @@ metadata: helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: master +{{- if .Values.master.annotations }} + annotations: + {{- toYaml .Values.master.annotations | nindent 4 }} +{{- end }} spec: serviceName: {{ template "seaweedfs.name" . }}-master podManagementPolicy: {{ .Values.master.podManagementPolicy }} @@ -50,6 +55,10 @@ spec: affinity: {{ tpl .Values.master.affinity . | nindent 8 | trim }} {{- end }} + {{- if .Values.master.topologySpreadConstraints }} + topologySpreadConstraints: + {{ tpl .Values.master.topologySpreadConstraints . | nindent 8 | trim }} + {{- end }} {{- if .Values.master.tolerations }} tolerations: {{ tpl .Values.master.tolerations . | nindent 8 | trim }} @@ -131,7 +140,7 @@ spec: -mdir=/data \ -ip.bind={{ .Values.master.ipBind }} \ {{- if .Values.global.enableReplication }} - -defaultReplication={{ .Values.global.replicationPlacment }} \ + -defaultReplication={{ .Values.global.replicationPlacement }} \ {{- else }} -defaultReplication={{ .Values.master.defaultReplication }} \ {{- end }} @@ -149,18 +158,36 @@ spec: {{- if .Values.master.metricsPort }} -metricsPort={{ .Values.master.metricsPort }} \ {{- end }} + {{- if .Values.master.metricsIp }} + -metricsIp={{ .Values.master.metricsIp }} \ + {{- end }} -volumeSizeLimitMB={{ .Values.master.volumeSizeLimitMB }} \ {{- if .Values.master.disableHttp }} -disableHttp \ {{- end }} - {{- if .Values.master.pulseSeconds }} - -pulseSeconds={{ .Values.master.pulseSeconds }} \ + {{- if .Values.master.resumeState }} + -resumeState \ + {{- end }} + {{- if .Values.master.raftHashicorp }} + -raftHashicorp \ + {{- end }} + {{- if .Values.master.raftBootstrap }} + -raftBootstrap \ + {{- end }} + {{- if .Values.master.electionTimeout }} + -electionTimeout={{ .Values.master.electionTimeout }} \ + {{- end }} + {{- if .Values.master.heartbeatInterval }} + -heartbeatInterval={{ .Values.master.heartbeatInterval }} \ {{- end }} {{- if .Values.master.garbageThreshold }} -garbageThreshold={{ .Values.master.garbageThreshold }} \ {{- end }} -ip=${POD_NAME}.${SEAWEEDFS_FULLNAME}-master.{{ .Release.Namespace }} \ - -peers={{ range $index := until (.Values.master.replicas | int) }}${SEAWEEDFS_FULLNAME}-master-{{ $index }}.${SEAWEEDFS_FULLNAME}-master.{{ $.Release.Namespace }}:{{ $.Values.master.port }}{{ if lt $index (sub ($.Values.master.replicas | int) 1) }},{{ end }}{{ end }} + -peers={{ include "seaweedfs.masterServers" . }} \ + {{- range .Values.master.extraArgs }} + {{ . }} \ + {{- end }} volumeMounts: - name : data-{{ .Release.Namespace }} mountPath: /data @@ -208,7 +235,7 @@ spec: httpGet: path: {{ .Values.master.readinessProbe.httpGet.path }} port: {{ .Values.master.port }} - scheme: {{ .Values.master.readinessProbe.scheme }} + scheme: {{ .Values.master.readinessProbe.httpGet.scheme }} initialDelaySeconds: {{ .Values.master.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.master.readinessProbe.periodSeconds }} successThreshold: {{ .Values.master.readinessProbe.successThreshold }} @@ -220,7 +247,7 @@ spec: httpGet: path: {{ .Values.master.livenessProbe.httpGet.path }} port: {{ .Values.master.port }} - scheme: {{ .Values.master.livenessProbe.scheme }} + scheme: {{ .Values.master.livenessProbe.httpGet.scheme }} initialDelaySeconds: {{ .Values.master.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.master.livenessProbe.periodSeconds }} successThreshold: {{ .Values.master.livenessProbe.successThreshold }} @@ -300,7 +327,9 @@ spec: {{- if $pvc_exists }} volumeClaimTemplates: {{- if eq .Values.master.data.type "persistentVolumeClaim"}} - - metadata: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: name: data-{{ .Release.Namespace }} {{- with .Values.master.data.annotations }} annotations: @@ -314,7 +343,9 @@ spec: storage: {{ .Values.master.data.size }} {{- end }} {{- if eq .Values.master.logs.type "persistentVolumeClaim"}} - - metadata: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: name: seaweedfs-master-log-volume {{- with .Values.master.logs.annotations }} annotations: diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/post-install-bucket-hook.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/post-install-bucket-hook.yaml deleted file mode 100644 index 2260bd84..00000000 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/post-install-bucket-hook.yaml +++ /dev/null @@ -1,102 +0,0 @@ -{{- if .Values.master.enabled }} -{{- if .Values.filer.s3.enabled }} -{{- if .Values.filer.s3.createBuckets }} ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: "{{ $.Release.Name }}-bucket-hook" - labels: - app.kubernetes.io/managed-by: {{ .Release.Service | quote }} - app.kubernetes.io/instance: {{ .Release.Name | quote }} - annotations: - "helm.sh/hook": post-install - "helm.sh/hook-weight": "-5" - "helm.sh/hook-delete-policy": hook-succeeded -spec: - template: - metadata: - name: "{{ .Release.Name }}" - labels: - app.kubernetes.io/managed-by: {{ .Release.Service | quote }} - app.kubernetes.io/instance: {{ .Release.Name | quote }} - spec: - restartPolicy: Never - {{- if .Values.filer.podSecurityContext.enabled }} - securityContext: {{- omit .Values.filer.podSecurityContext "enabled" | toYaml | nindent 8 }} - {{- end }} - containers: - - name: post-install-job - image: {{ template "master.image" . }} - env: - - name: WEED_CLUSTER_DEFAULT - value: "sw" - - name: WEED_CLUSTER_SW_MASTER - value: "{{ template "seaweedfs.name" . }}-master.{{ .Release.Namespace }}:9333" - - name: WEED_CLUSTER_SW_FILER - value: "{{ template "seaweedfs.name" . }}-filer-client.{{ .Release.Namespace }}:8888" - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: SEAWEEDFS_FULLNAME - value: "{{ template "seaweedfs.name" . }}" - command: - - "/bin/sh" - - "-ec" - - | - {{- range $reg, $props := $.Values.filer.s3.createBuckets }} - exec /bin/echo \ - "s3.bucket.create --name {{ $props.name }}" |\ - /usr/bin/weed shell - {{- end }} - {{- range $reg, $props := $.Values.filer.s3.createBuckets }} - {{- if $props.anonymousRead }} - exec /bin/echo \ - "s3.configure --user anonymous \ - --buckets {{ $props.name }} \ - --actions Read \ - --apply true" |\ - /usr/bin/weed shell - {{- end }} - {{- end }} - {{- if .Values.filer.s3.enableAuth }} - volumeMounts: - - name: config-users - mountPath: /etc/sw - readOnly: true - {{- end }} - ports: - - containerPort: {{ .Values.master.port }} - name: swfs-master - {{- if and .Values.global.monitoring.enabled .Values.master.metricsPort }} - - containerPort: {{ .Values.master.metricsPort }} - name: metrics - {{- end }} - - containerPort: {{ .Values.master.grpcPort }} - #name: swfs-master-grpc - {{- if .Values.filer.containerSecurityContext.enabled }} - securityContext: {{- omit .Values.filer.containerSecurityContext "enabled" | toYaml | nindent 12 }} - {{- end }} - {{- if .Values.filer.s3.enableAuth }} - volumes: - - name: config-users - secret: - defaultMode: 420 - {{- if not (empty .Values.filer.s3.existingConfigSecret) }} - secretName: {{ .Values.filer.s3.existingConfigSecret }} - {{- else }} - secretName: seaweedfs-s3-secret - {{- end }} - {{- end }}{{/** if .Values.filer.s3.enableAuth **/}} -{{- end }}{{/** if .Values.master.enabled **/}} -{{- end }}{{/** if .Values.filer.s3.enabled **/}} -{{- end }}{{/** if .Values.filer.s3.createBuckets **/}} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/s3-ingress.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/s3-ingress.yaml deleted file mode 100644 index 7b279793..00000000 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/s3-ingress.yaml +++ /dev/null @@ -1,46 +0,0 @@ -{{- if .Values.s3.ingress.enabled }} -{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} -apiVersion: networking.k8s.io/v1 -{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion }} -apiVersion: networking.k8s.io/v1beta1 -{{- else }} -apiVersion: extensions/v1beta1 -{{- end }} -kind: Ingress -metadata: - name: ingress-{{ template "seaweedfs.name" . }}-s3 - namespace: {{ .Release.Namespace }} - {{- with .Values.s3.ingress.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} - labels: - app.kubernetes.io/name: {{ template "seaweedfs.name" . }} - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/component: s3 -spec: - ingressClassName: {{ .Values.s3.ingress.className | quote }} - tls: - {{ .Values.s3.ingress.tls | default list | toYaml | nindent 6}} - rules: - - http: - paths: - - path: / - pathType: ImplementationSpecific - backend: -{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} - service: - name: {{ template "seaweedfs.name" . }}-s3 - port: - number: {{ .Values.s3.port }} - #name: -{{- else }} - serviceName: {{ template "seaweedfs.name" . }}-s3 - servicePort: {{ .Values.s3.port }} -{{- end }} -{{- if .Values.s3.ingress.host }} - host: {{ .Values.s3.ingress.host }} -{{- end }} -{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/s3-deployment.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-deployment.yaml similarity index 91% rename from packages/system/seaweedfs/charts/seaweedfs/templates/s3-deployment.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-deployment.yaml index b678a0ef..29dd2d43 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/s3-deployment.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-deployment.yaml @@ -9,12 +9,16 @@ metadata: helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: s3 +{{- if .Values.s3.annotations }} + annotations: + {{- toYaml .Values.s3.annotations | nindent 4 }} +{{- end }} spec: replicas: {{ .Values.s3.replicas }} selector: matchLabels: app.kubernetes.io/name: {{ template "seaweedfs.name" . }} - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/component: s3 template: @@ -39,6 +43,14 @@ spec: {{- end }} spec: restartPolicy: {{ default .Values.global.restartPolicy .Values.s3.restartPolicy }} + {{- if .Values.s3.affinity }} + affinity: + {{ tpl .Values.s3.affinity . | nindent 8 | trim }} + {{- end }} + {{- if .Values.s3.topologySpreadConstraints }} + topologySpreadConstraints: + {{ tpl .Values.s3.topologySpreadConstraints . | nindent 8 | trim }} + {{- end }} {{- if .Values.s3.tolerations }} tolerations: {{ tpl .Values.s3.tolerations . | nindent 8 | trim }} @@ -131,16 +143,16 @@ spec: {{- if .Values.s3.domainName }} -domainName={{ .Values.s3.domainName }} \ {{- end }} - {{- if .Values.s3.allowEmptyFolder }} - -allowEmptyFolder={{ .Values.s3.allowEmptyFolder }} \ - {{- end }} {{- if .Values.s3.enableAuth }} -config=/etc/sw/seaweedfs_s3_config \ {{- end }} {{- if .Values.s3.auditLogConfig }} -auditLogConfig=/etc/sw/s3_auditLogConfig.json \ {{- end }} - -filer={{ template "seaweedfs.name" . }}-filer-client.{{ .Release.Namespace }}:{{ .Values.filer.port }} + -filer={{ template "seaweedfs.name" . }}-filer-client.{{ .Release.Namespace }}:{{ .Values.filer.port }} \ + {{- range .Values.s3.extraArgs }} + {{ . }} \ + {{- end }} volumeMounts: {{- if or (eq .Values.s3.logs.type "hostPath") (eq .Values.s3.logs.type "emptyDir") }} - name: logs @@ -176,16 +188,20 @@ spec: ports: - containerPort: {{ .Values.s3.port }} name: swfs-s3 + {{- if .Values.s3.httpsPort }} + - containerPort: {{ .Values.s3.httpsPort }} + name: swfs-s3-tls + {{- end }} {{- if .Values.s3.metricsPort }} - containerPort: {{ .Values.s3.metricsPort }} - name: "metrics" + name: metrics {{- end }} {{- if .Values.s3.readinessProbe.enabled }} readinessProbe: httpGet: path: {{ .Values.s3.readinessProbe.httpGet.path }} port: {{ .Values.s3.port }} - scheme: {{ .Values.s3.readinessProbe.scheme }} + scheme: {{ .Values.s3.readinessProbe.httpGet.scheme }} initialDelaySeconds: {{ .Values.s3.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.s3.readinessProbe.periodSeconds }} successThreshold: {{ .Values.s3.readinessProbe.successThreshold }} @@ -197,7 +213,7 @@ spec: httpGet: path: {{ .Values.s3.livenessProbe.httpGet.path }} port: {{ .Values.s3.port }} - scheme: {{ .Values.s3.livenessProbe.scheme }} + scheme: {{ .Values.s3.livenessProbe.httpGet.scheme }} initialDelaySeconds: {{ .Values.s3.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.s3.livenessProbe.periodSeconds }} successThreshold: {{ .Values.s3.livenessProbe.successThreshold }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-ingress.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-ingress.yaml new file mode 100644 index 00000000..e884f4fc --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-ingress.yaml @@ -0,0 +1,74 @@ +{{- /* S3 ingress works for standalone S3 gateway (s3.enabled), S3 on Filer (filer.s3.enabled), and all-in-one mode (allInOne.s3.enabled) */}} +{{- $s3Enabled := or .Values.s3.enabled (and .Values.filer.s3.enabled (not .Values.allInOne.enabled)) (and .Values.allInOne.enabled .Values.allInOne.s3.enabled) }} +{{- if and $s3Enabled .Values.s3.ingress.enabled }} +{{- /* Determine service name based on deployment mode */}} +{{- $serviceName := ternary (printf "%s-all-in-one" (include "seaweedfs.name" .)) (printf "%s-s3" (include "seaweedfs.name" .)) .Values.allInOne.enabled }} +{{- $s3Port := .Values.allInOne.s3.port | default .Values.s3.port }} +{{- /* Build hosts list - support both legacy .host (string) and new .hosts (array) for backwards compatibility */}} +{{- $hosts := list }} +{{- if kindIs "slice" .Values.s3.ingress.host }} + {{- $hosts = .Values.s3.ingress.host }} +{{- else if .Values.s3.ingress.host }} + {{- $hosts = list .Values.s3.ingress.host }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion }} +apiVersion: networking.k8s.io/v1beta1 +{{- else }} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: ingress-{{ template "seaweedfs.name" . }}-s3 + namespace: {{ .Release.Namespace }} + {{- with .Values.s3.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: s3 +spec: + ingressClassName: {{ .Values.s3.ingress.className | quote }} + tls: + {{ .Values.s3.ingress.tls | default list | toYaml | nindent 6}} + rules: +{{- if $hosts }} +{{- range $hosts }} + - host: {{ . | quote }} + http: + paths: + - path: {{ $.Values.s3.ingress.path | quote }} + pathType: {{ $.Values.s3.ingress.pathType | quote }} + backend: +{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $serviceName }} + port: + number: {{ $s3Port }} +{{- else }} + serviceName: {{ $serviceName }} + servicePort: {{ $s3Port }} +{{- end }} +{{- end }} +{{- else }} + - http: + paths: + - path: {{ .Values.s3.ingress.path | quote }} + pathType: {{ .Values.s3.ingress.pathType | quote }} + backend: +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $serviceName }} + port: + number: {{ $s3Port }} +{{- else }} + serviceName: {{ $serviceName }} + servicePort: {{ $s3Port }} +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/s3-secret.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-secret.yaml similarity index 56% rename from packages/system/seaweedfs/charts/seaweedfs/templates/s3-secret.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-secret.yaml index 969b31f5..587ea77c 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/s3-secret.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-secret.yaml @@ -1,8 +1,8 @@ -{{- if or (and .Values.filer.s3.enabled .Values.filer.s3.enableAuth (not .Values.filer.s3.existingConfigSecret)) (and .Values.s3.enabled .Values.s3.enableAuth (not .Values.s3.existingConfigSecret)) }} -{{- $access_key_admin := randAlphaNum 16 -}} -{{- $secret_key_admin := randAlphaNum 32 -}} -{{- $access_key_read := randAlphaNum 16 -}} -{{- $secret_key_read := randAlphaNum 32 -}} +{{- if or (and (or .Values.s3.enabled .Values.allInOne.enabled) .Values.s3.enableAuth (not .Values.s3.existingConfigSecret)) (and .Values.filer.s3.enabled .Values.filer.s3.enableAuth (not .Values.filer.s3.existingConfigSecret)) }} +{{- $access_key_admin := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" "seaweedfs-s3-secret" "key" "admin_access_key_id" "length" 20) -}} +{{- $secret_key_admin := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" "seaweedfs-s3-secret" "key" "admin_secret_access_key" "length" 40) -}} +{{- $access_key_read := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" "seaweedfs-s3-secret" "key" "read_access_key_id" "length" 20) -}} +{{- $secret_key_read := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" "seaweedfs-s3-secret" "key" "read_secret_access_key" "length" 40) -}} apiVersion: v1 kind: Secret type: Opaque @@ -11,7 +11,7 @@ metadata: namespace: {{ .Release.Namespace }} annotations: "helm.sh/resource-policy": keep - "helm.sh/hook": "pre-install" + "helm.sh/hook": "pre-install,pre-upgrade" labels: app.kubernetes.io/name: {{ template "seaweedfs.name" . }} helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} @@ -32,4 +32,4 @@ stringData: s3_auditLogConfig.json: | {{ toJson .Values.s3.auditLogConfig | nindent 4 }} {{- end }} -{{- end }} +{{- end }} \ No newline at end of file diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/s3-service.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml similarity index 89% rename from packages/system/seaweedfs/charts/seaweedfs/templates/s3-service.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml index 01d79ad7..86e0424e 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/s3-service.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml @@ -9,7 +9,12 @@ metadata: app.kubernetes.io/component: s3 helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- if .Values.s3.annotations }} + annotations: + {{- toYaml .Values.s3.annotations | nindent 4 }} +{{- end }} spec: + trafficDistribution: PreferClose internalTrafficPolicy: {{ .Values.s3.internalTrafficPolicy | default "Cluster" }} ports: - name: "swfs-s3" diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/s3-servicemonitor.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-servicemonitor.yaml similarity index 79% rename from packages/system/seaweedfs/charts/seaweedfs/templates/s3-servicemonitor.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-servicemonitor.yaml index b47ba8ee..34825591 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/s3-servicemonitor.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-servicemonitor.yaml @@ -15,6 +15,10 @@ metadata: {{- with .Values.global.monitoring.additionalLabels }} {{- toYaml . | nindent 4 }} {{- end }} +{{- if .Values.s3.annotations }} + annotations: + {{- toYaml .Values.s3.annotations | nindent 4 }} +{{- end }} spec: endpoints: - interval: 30s @@ -22,8 +26,8 @@ spec: scrapeTimeout: 5s selector: matchLabels: - app: {{ template "seaweedfs.name" . }} - component: s3 + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/component: s3 {{- end }} {{- end }} {{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/seaweedfs-grafana-dashboard.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/seaweedfs-grafana-dashboard.yaml deleted file mode 100644 index eb5a5eba..00000000 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/seaweedfs-grafana-dashboard.yaml +++ /dev/null @@ -1,20 +0,0 @@ -{{- if .Values.global.monitoring.enabled }} -{{- $files := .Files.Glob "dashboards/*.json" }} -{{- if $files }} -apiVersion: v1 -kind: ConfigMapList -items: -{{- range $path, $fileContents := $files }} -{{- $dashboardName := regexReplaceAll "(^.*/)(.*)\\.json$" $path "${2}" }} -- apiVersion: v1 - kind: ConfigMap - metadata: - name: {{ printf "%s" $dashboardName | lower | replace "_" "-" }} - namespace: {{ $.Release.Namespace }} - labels: - grafana_dashboard: "1" - data: - {{ $dashboardName }}.json: {{ $.Files.Get $path | toJson }} -{{- end }} -{{- end }} -{{- end }} \ No newline at end of file diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/sftp/sftp-deployment.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/sftp/sftp-deployment.yaml new file mode 100644 index 00000000..c0bcb2c4 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/sftp/sftp-deployment.yaml @@ -0,0 +1,301 @@ +{{- if .Values.sftp.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "seaweedfs.name" . }}-sftp + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: sftp +{{- if .Values.sftp.annotations }} + annotations: + {{- toYaml .Values.sftp.annotations | nindent 4 }} +{{- end }} +spec: + replicas: {{ .Values.sftp.replicas }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: sftp + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: sftp + {{ with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.sftp.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + annotations: + {{ with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.sftp.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + restartPolicy: {{ default .Values.global.restartPolicy .Values.sftp.restartPolicy }} + {{- if .Values.sftp.affinity }} + affinity: + {{ tpl .Values.sftp.affinity . | nindent 8 | trim }} + {{- end }} + {{- if .Values.sftp.topologySpreadConstraints }} + topologySpreadConstraints: + {{ tpl .Values.sftp.topologySpreadConstraint . | nindent 8 | trim }} + {{- end }} + {{- if .Values.sftp.tolerations }} + tolerations: + {{ tpl .Values.sftp.tolerations . | nindent 8 | trim }} + {{- end }} + {{- include "seaweedfs.imagePullSecrets" . | nindent 6 }} + terminationGracePeriodSeconds: 10 + {{- if .Values.sftp.priorityClassName }} + priorityClassName: {{ .Values.sftp.priorityClassName | quote }} + {{- end }} + enableServiceLinks: false + {{- if .Values.sftp.serviceAccountName }} + serviceAccountName: {{ .Values.sftp.serviceAccountName | quote }} + {{- end }} + {{- if .Values.sftp.initContainers }} + initContainers: + {{ tpl .Values.sftp.initContainers . | nindent 8 | trim }} + {{- end }} + {{- if .Values.sftp.podSecurityContext.enabled }} + securityContext: {{- omit .Values.sftp.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: seaweedfs + image: {{ template "sftp.image" . }} + imagePullPolicy: {{ default "IfNotPresent" .Values.global.imagePullPolicy }} + env: + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SEAWEEDFS_FULLNAME + value: "{{ template "seaweedfs.name" . }}" + {{- if .Values.sftp.extraEnvironmentVars }} + {{- range $key, $value := .Values.sftp.extraEnvironmentVars }} + - name: {{ $key }} + {{- if kindIs "string" $value }} + value: {{ $value | quote }} + {{- else }} + valueFrom: + {{ toYaml $value | nindent 16 | trim }} + {{- end -}} + {{- end }} + {{- end }} + {{- if .Values.global.extraEnvironmentVars }} + {{- range $key, $value := .Values.global.extraEnvironmentVars }} + - name: {{ $key }} + {{- if kindIs "string" $value }} + value: {{ $value | quote }} + {{- else }} + valueFrom: + {{ toYaml $value | nindent 16 | trim }} + {{- end -}} + {{- end }} + {{- end }} + command: + - "/bin/sh" + - "-ec" + - | + exec /usr/bin/weed \ + {{- if or (eq .Values.sftp.logs.type "hostPath") (eq .Values.sftp.logs.type "emptyDir") }} + -logdir=/logs \ + {{- else }} + -logtostderr=true \ + {{- end }} + {{- if .Values.sftp.loggingOverrideLevel }} + -v={{ .Values.sftp.loggingOverrideLevel }} \ + {{- else }} + -v={{ .Values.global.loggingLevel }} \ + {{- end }} + sftp \ + -ip.bind={{ .Values.sftp.bindAddress }} \ + -port={{ .Values.sftp.port }} \ + {{- if .Values.sftp.metricsPort }} + -metricsPort={{ .Values.sftp.metricsPort }} \ + {{- end }} + {{- if .Values.sftp.metricsIp }} + -metricsIp={{ .Values.sftp.metricsIp }} \ + {{- end }} + {{- if .Values.sftp.sshPrivateKey }} + -sshPrivateKey={{ .Values.sftp.sshPrivateKey }} \ + {{- end }} + {{- if .Values.sftp.hostKeysFolder }} + -hostKeysFolder={{ .Values.sftp.hostKeysFolder }} \ + {{- end }} + {{- if .Values.sftp.authMethods }} + -authMethods={{ .Values.sftp.authMethods }} \ + {{- end }} + {{- if .Values.sftp.maxAuthTries }} + -maxAuthTries={{ .Values.sftp.maxAuthTries }} \ + {{- end }} + {{- if .Values.sftp.bannerMessage }} + -bannerMessage="{{ .Values.sftp.bannerMessage }}" \ + {{- end }} + {{- if .Values.sftp.loginGraceTime }} + -loginGraceTime={{ .Values.sftp.loginGraceTime }} \ + {{- end }} + {{- if .Values.sftp.clientAliveInterval }} + -clientAliveInterval={{ .Values.sftp.clientAliveInterval }} \ + {{- end }} + {{- if .Values.sftp.clientAliveCountMax }} + -clientAliveCountMax={{ .Values.sftp.clientAliveCountMax }} \ + {{- end }} + {{- if .Values.sftp.dataCenter }} + -dataCenter={{ .Values.sftp.dataCenter }} \ + {{- end }} + {{- if .Values.sftp.localSocket }} + -localSocket={{ .Values.sftp.localSocket }} \ + {{- end }} + {{- if .Values.global.enableSecurity }} + -cert.file=/usr/local/share/ca-certificates/client/tls.crt \ + -key.file=/usr/local/share/ca-certificates/client/tls.key \ + {{- end }} + -userStoreFile=/etc/sw/seaweedfs_sftp_config \ + -filer={{ template "seaweedfs.name" . }}-filer-client.{{ .Release.Namespace }}:{{ .Values.filer.port }} + volumeMounts: + {{- if or (eq .Values.sftp.logs.type "hostPath") (eq .Values.sftp.logs.type "emptyDir") }} + - name: logs + mountPath: "/logs/" + {{- end }} + {{- if .Values.sftp.enableAuth }} + - mountPath: /etc/sw + name: config-users + readOnly: true + {{- end }} + - mountPath: /etc/sw/ssh + name: config-ssh + readOnly: true + {{- if .Values.global.enableSecurity }} + - name: security-config + readOnly: true + mountPath: /etc/seaweedfs/security.toml + subPath: security.toml + - name: ca-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/ca/ + - name: master-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/master/ + - name: volume-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/volume/ + - name: filer-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/filer/ + - name: client-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/client/ + {{- end }} + {{ tpl .Values.sftp.extraVolumeMounts . | nindent 12 | trim }} + ports: + - containerPort: {{ .Values.sftp.port }} + name: swfs-sftp + {{- if .Values.sftp.metricsPort }} + - containerPort: {{ .Values.sftp.metricsPort }} + name: metrics + {{- end }} + {{- if .Values.sftp.readinessProbe.enabled }} + readinessProbe: + tcpSocket: + port: {{ .Values.sftp.port }} + initialDelaySeconds: {{ .Values.sftp.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.sftp.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.sftp.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.sftp.readinessProbe.failureThreshold }} + timeoutSeconds: {{ .Values.sftp.readinessProbe.timeoutSeconds }} + {{- end }} + {{- if .Values.sftp.livenessProbe.enabled }} + livenessProbe: + tcpSocket: + port: {{ .Values.sftp.port }} + initialDelaySeconds: {{ .Values.sftp.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.sftp.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.sftp.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.sftp.livenessProbe.failureThreshold }} + timeoutSeconds: {{ .Values.sftp.livenessProbe.timeoutSeconds }} + {{- end }} + {{- with .Values.sftp.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if .Values.sftp.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.sftp.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.sftp.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.sftp.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + {{- if .Values.sftp.enableAuth }} + - name: config-users + secret: + defaultMode: 420 + {{- if .Values.sftp.existingConfigSecret }} + secretName: {{ .Values.sftp.existingConfigSecret }} + {{- else }} + secretName: seaweedfs-sftp-secret + {{- end }} + {{- end }} + - name: config-ssh + secret: + defaultMode: 420 + {{- if .Values.sftp.existingSshConfigSecret }} + secretName: {{ .Values.sftp.existingSshConfigSecret }} + {{- else }} + secretName: seaweedfs-sftp-ssh-secret + {{- end }} + {{- if eq .Values.sftp.logs.type "hostPath" }} + - name: logs + hostPath: + path: {{ .Values.sftp.logs.hostPathPrefix }}/logs/seaweedfs/sftp + type: DirectoryOrCreate + {{- end }} + {{- if eq .Values.sftp.logs.type "emptyDir" }} + - name: logs + emptyDir: {} + {{- end }} + {{- if .Values.global.enableSecurity }} + - name: security-config + configMap: + name: {{ template "seaweedfs.name" . }}-security-config + - name: ca-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-ca-cert + - name: master-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-master-cert + - name: volume-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-volume-cert + - name: filer-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-filer-cert + - name: client-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-client-cert + {{- end }} + {{ tpl .Values.sftp.extraVolumes . | indent 8 | trim }} + {{- if .Values.sftp.nodeSelector }} + nodeSelector: + {{ tpl .Values.sftp.nodeSelector . | indent 8 | trim }} + {{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/sftp/sftp-secret.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/sftp/sftp-secret.yaml new file mode 100644 index 00000000..2cec992a --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/sftp/sftp-secret.yaml @@ -0,0 +1,33 @@ +{{- if or .Values.sftp.enabled .Values.allInOne.enabled }} +{{- $admin_pwd := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" "seaweedfs-sftp-secret" "key" "admin_password" 20) -}} +{{- $read_user_pwd := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" "seaweedfs-sftp-secret" "key" "readonly_password" 20) -}} +{{- $public_user_pwd := include "getOrGeneratePassword" (dict "namespace" .Release.Namespace "secretName" "seaweedfs-sftp-secret" "key" "public_user_password" 20) -}} +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: seaweedfs-sftp-secret + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/resource-policy": keep + "helm.sh/hook": "pre-install,pre-upgrade" + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: sftp +stringData: + admin_password: {{ $admin_pwd }} + readonly_password: {{ $read_user_pwd }} + public_user_password: {{ $public_user_pwd }} + seaweedfs_sftp_config: '[{"Username":"admin","Password":"{{ $admin_pwd }}","PublicKeys":[],"HomeDir":"/","Permissions":{"/":["read","write","list"]},"Uid":0,"Gid":0},{"Username":"readonly_user","Password":"{{ $read_user_pwd }}","PublicKeys":[],"HomeDir":"/","Permissions":{"/":["read","list"]},"Uid":1112,"Gid":1112},{"Username":"public_user","Password":"{{ $public_user_pwd }}","PublicKeys":[],"HomeDir":"/public","Permissions":{"/public":["write","read","list"]},"Uid":1113,"Gid":1113}]' + seaweedfs_sftp_ssh_private_key: | + -----BEGIN OPENSSH PRIVATE KEY----- + b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW + QyNTUxOQAAACDH4McwcDphteXVullu6q7ephEN1N60z+w0qZw0UVW8OwAAAJDjxkmk48ZJ + pAAAAAtzc2gtZWQyNTUxOQAAACDH4McwcDphteXVullu6q7ephEN1N60z+w0qZw0UVW8Ow + AAAEAeVy/4+gf6rjj2jla/AHqJpC1LcS5hn04IUs4q+iVq/MfgxzBwOmG15dW6WW7qrt6m + EQ3U3rTP7DSpnDRRVbw7AAAADHNla291ckAwMDY2NwE= + -----END OPENSSH PRIVATE KEY----- +{{- end }} \ No newline at end of file diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/sftp/sftp-service.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/sftp/sftp-service.yaml new file mode 100644 index 00000000..5e67570d --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/sftp/sftp-service.yaml @@ -0,0 +1,32 @@ +{{- if .Values.sftp.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "seaweedfs.name" . }}-sftp + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/component: sftp + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- if .Values.sftp.annotations }} + annotations: + {{- toYaml .Values.sftp.annotations | nindent 4 }} +{{- end }} +spec: + internalTrafficPolicy: {{ .Values.sftp.internalTrafficPolicy | default "Cluster" }} + ports: + - name: "swfs-sftp" + port: {{ .Values.sftp.port }} + targetPort: {{ .Values.sftp.port }} + protocol: TCP +{{- if .Values.sftp.metricsPort }} + - name: "metrics" + port: {{ .Values.sftp.metricsPort }} + targetPort: {{ .Values.sftp.metricsPort }} + protocol: TCP +{{- end }} + selector: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/component: sftp +{{- end }} \ No newline at end of file diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/sftp/sftp-servicemonitor.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/sftp/sftp-servicemonitor.yaml new file mode 100644 index 00000000..4c718886 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/sftp/sftp-servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if .Values.sftp.enabled }} +{{- if .Values.sftp.metricsPort }} +{{- if .Values.global.monitoring.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "seaweedfs.name" . }}-sftp + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: sftp + {{- with .Values.global.monitoring.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- if .Values.sftp.annotations }} + annotations: + {{- toYaml .Values.sftp.annotations | nindent 4 }} +{{- end }} +spec: + endpoints: + - interval: 30s + port: metrics + scrapeTimeout: 5s + selector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/component: sftp +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/shared/_helpers.tpl b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/_helpers.tpl new file mode 100644 index 00000000..557bb9d4 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/_helpers.tpl @@ -0,0 +1,302 @@ +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to +this (by the DNS naming spec). If release name contains chart name it will +be used as a full name. +*/}} +{{- define "seaweedfs.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "seaweedfs.chart" -}} +{{- printf "%s-helm" .Chart.Name | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Expand the name of the chart. +*/}} +{{- define "seaweedfs.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Inject extra environment vars in the format key:value, if populated +*/}} +{{- define "seaweedfs.extraEnvironmentVars" -}} +{{- if .extraEnvironmentVars -}} +{{- range $key, $value := .extraEnvironmentVars }} +- name: {{ $key }} + value: {{ $value | quote }} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* Return the proper filer image */}} +{{- define "filer.image" -}} +{{- if .Values.filer.imageOverride -}} +{{- $imageOverride := .Values.filer.imageOverride -}} +{{- printf "%s" $imageOverride -}} +{{- else -}} +{{- include "common.image" . }} +{{- end -}} +{{- end -}} + +{{/* Return the proper master image */}} +{{- define "master.image" -}} +{{- if .Values.master.imageOverride -}} +{{- $imageOverride := .Values.master.imageOverride -}} +{{- printf "%s" $imageOverride -}} +{{- else -}} +{{- include "common.image" . }} +{{- end -}} +{{- end -}} + +{{/* Return the proper s3 image */}} +{{- define "s3.image" -}} +{{- if .Values.s3.imageOverride -}} +{{- $imageOverride := .Values.s3.imageOverride -}} +{{- printf "%s" $imageOverride -}} +{{- else -}} +{{- include "common.image" . }} +{{- end -}} +{{- end -}} + +{{/* Return the proper sftp image */}} +{{- define "sftp.image" -}} +{{- if .Values.sftp.imageOverride -}} +{{- $imageOverride := .Values.sftp.imageOverride -}} +{{- printf "%s" $imageOverride -}} +{{- else -}} +{{- include "common.image" . }} +{{- end -}} +{{- end -}} + +{{/* Return the proper admin image */}} +{{- define "admin.image" -}} +{{- if .Values.admin.imageOverride -}} +{{- $imageOverride := .Values.admin.imageOverride -}} +{{- printf "%s" $imageOverride -}} +{{- else -}} +{{- include "common.image" . }} +{{- end -}} +{{- end -}} + +{{/* Return the proper worker image */}} +{{- define "worker.image" -}} +{{- if .Values.worker.imageOverride -}} +{{- $imageOverride := .Values.worker.imageOverride -}} +{{- printf "%s" $imageOverride -}} +{{- else -}} +{{- include "common.image" . }} +{{- end -}} +{{- end -}} + +{{/* Return the proper volume image */}} +{{- define "volume.image" -}} +{{- if .Values.volume.imageOverride -}} +{{- $imageOverride := .Values.volume.imageOverride -}} +{{- printf "%s" $imageOverride -}} +{{- else -}} +{{- include "common.image" . }} +{{- end -}} +{{- end -}} + +{{/* Computes the container image name for all components (if they are not overridden) */}} +{{- define "common.image" -}} +{{- $registryName := default .Values.image.registry .Values.global.registry | toString -}} +{{- $repositoryName := default .Values.image.repository .Values.global.repository | toString -}} +{{- $name := .Values.global.imageName | toString -}} +{{- $tag := default .Chart.AppVersion .Values.image.tag | toString -}} +{{- if $repositoryName -}} +{{- $name = printf "%s/%s" (trimSuffix "/" $repositoryName) (base $name) -}} +{{- end -}} +{{- if $registryName -}} +{{- printf "%s/%s:%s" $registryName $name $tag -}} +{{- else -}} +{{- printf "%s:%s" $name $tag -}} +{{- end -}} +{{- end -}} + +{{/* check if any Volume PVC exists */}} +{{- define "volume.pvc_exists" -}} +{{- if or (or (eq .Values.volume.data.type "persistentVolumeClaim") (and (eq .Values.volume.idx.type "persistentVolumeClaim") .Values.volume.dir_idx )) (eq .Values.volume.logs.type "persistentVolumeClaim") -}} +{{- printf "true" -}} +{{- else -}} +{{- printf "" -}} +{{- end -}} +{{- end -}} + +{{/* check if any Filer PVC exists */}} +{{- define "filer.pvc_exists" -}} +{{- if or (eq .Values.filer.data.type "persistentVolumeClaim") (eq .Values.filer.logs.type "persistentVolumeClaim") -}} +{{- printf "true" -}} +{{- else -}} +{{- printf "" -}} +{{- end -}} +{{- end -}} + +{{/* check if any Master PVC exists */}} +{{- define "master.pvc_exists" -}} +{{- if or (eq .Values.master.data.type "persistentVolumeClaim") (eq .Values.master.logs.type "persistentVolumeClaim") -}} +{{- printf "true" -}} +{{- else -}} +{{- printf "" -}} +{{- end -}} +{{- end -}} + +{{/* check if any Admin PVC exists */}} +{{- define "admin.pvc_exists" -}} +{{- if or (eq .Values.admin.data.type "persistentVolumeClaim") (eq .Values.admin.logs.type "persistentVolumeClaim") -}} +{{- printf "true" -}} +{{- else -}} +{{- printf "" -}} +{{- end -}} +{{- end -}} + +{{/* check if any InitContainers exist for Volumes */}} +{{- define "volume.initContainers_exists" -}} +{{- if or (not (empty .Values.volume.idx )) (not (empty .Values.volume.initContainers )) -}} +{{- printf "true" -}} +{{- else -}} +{{- printf "" -}} +{{- end -}} +{{- end -}} + +{{/* Return the proper imagePullSecrets */}} +{{- define "seaweedfs.imagePullSecrets" -}} +{{- with .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- if kindIs "string" . }} + - name: {{ . }} +{{- else }} +{{- range . }} + {{- if kindIs "string" . }} + - name: {{ . }} + {{- else }} + - {{ toYaml . }} + {{- end}} +{{- end }} +{{- end }} +{{- end }} +{{- end -}} + +{{/* +Renders a value that contains template perhaps with scope if the scope is present. +Usage: +{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $ ) }} +{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $ "scope" $app ) }} +*/}} +{{- define "common.tplvalues.render" -}} +{{- $value := typeIs "string" .value | ternary .value (.value | toYaml) }} +{{- if contains "{{" (toJson .value) }} + {{- if .scope }} + {{- tpl (cat "{{- with $.RelativeScope -}}" $value "{{- end }}") (merge (dict "RelativeScope" .scope) .context) }} + {{- else }} + {{- tpl $value .context }} + {{- end }} +{{- else }} + {{- $value }} +{{- end }} +{{- end -}} + +{{/* +Converts a Kubernetes quantity like "256Mi" or "2G" to a float64 in base units, +handling both binary (Ki, Mi, Gi) and decimal (m, k, M) suffixes; numeric inputs +Usage: +{{ include "common.resource-quantity" "10Gi" }} +*/}} +{{- define "common.resource-quantity" -}} + {{- $value := . -}} + {{- $unit := 1.0 -}} + {{- if typeIs "string" . -}} + {{- $base2 := dict "Ki" 0x1p10 "Mi" 0x1p20 "Gi" 0x1p30 "Ti" 0x1p40 "Pi" 0x1p50 "Ei" 0x1p60 -}} + {{- $base10 := dict "m" 1e-3 "k" 1e3 "M" 1e6 "G" 1e9 "T" 1e12 "P" 1e15 "E" 1e18 -}} + {{- range $k, $v := merge $base2 $base10 -}} + {{- if hasSuffix $k $ -}} + {{- $value = trimSuffix $k $ -}} + {{- $unit = $v -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- mulf (float64 $value) $unit -}} +{{- end -}} + +{{/* +getOrGeneratePassword will check if a password exists in a secret and return it, +or generate a new random password if it doesn't exist. +*/}} +{{- define "getOrGeneratePassword" -}} +{{- $params := . -}} +{{- $namespace := $params.namespace -}} +{{- $secretName := $params.secretName -}} +{{- $key := $params.key -}} +{{- $length := default 16 $params.length -}} + +{{- $existingSecret := lookup "v1" "Secret" $namespace $secretName -}} +{{- if and $existingSecret (index $existingSecret.data $key) -}} + {{- index $existingSecret.data $key | b64dec -}} +{{- else -}} + {{- randAlphaNum $length -}} +{{- end -}} +{{- end -}} + +{{/* +Compute the master service address to be used in cluster env vars. +If allInOne is enabled, point to the all-in-one service; otherwise, point to the master service. +*/}} +{{- define "seaweedfs.cluster.masterAddress" -}} +{{- $serviceNameSuffix := "-master" -}} +{{- if .Values.allInOne.enabled -}} +{{- $serviceNameSuffix = "-all-in-one" -}} +{{- end -}} +{{- printf "%s%s.%s:%d" (include "seaweedfs.name" .) $serviceNameSuffix .Release.Namespace (int .Values.master.port) -}} +{{- end -}} + +{{/* +Compute the filer service address to be used in cluster env vars. +If allInOne is enabled, point to the all-in-one service; otherwise, point to the filer-client service. +*/}} +{{- define "seaweedfs.cluster.filerAddress" -}} +{{- $serviceNameSuffix := "-filer-client" -}} +{{- if .Values.allInOne.enabled -}} +{{- $serviceNameSuffix = "-all-in-one" -}} +{{- end -}} +{{- printf "%s%s.%s:%d" (include "seaweedfs.name" .) $serviceNameSuffix .Release.Namespace (int .Values.filer.port) -}} +{{- end -}} + +{{/* +Generate comma-separated list of master server addresses. +Usage: {{ include "seaweedfs.masterServers" . }} +Output example: ${SEAWEEDFS_FULLNAME}-master-0.${SEAWEEDFS_FULLNAME}-master.namespace:9333,${SEAWEEDFS_FULLNAME}-master-1... +*/}} +{{- define "seaweedfs.masterServers" -}} +{{- $fullname := include "seaweedfs.name" . -}} +{{- range $index := until (.Values.master.replicas | int) -}} +{{- if $index }},{{ end -}} +${SEAWEEDFS_FULLNAME}-master-{{ $index }}.${SEAWEEDFS_FULLNAME}-master.{{ $.Release.Namespace }}:{{ $.Values.master.port }} +{{- end -}} +{{- end -}} + +{{/* +Generate master server argument value, using global.masterServer if set, otherwise the generated list. +Usage: {{ include "seaweedfs.masterServerArg" . }} +*/}} +{{- define "seaweedfs.masterServerArg" -}} +{{- if .Values.global.masterServer -}} +{{- .Values.global.masterServer -}} +{{- else -}} +{{- include "seaweedfs.masterServers" . -}} +{{- end -}} +{{- end -}} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cluster-role.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/cluster-role.yaml similarity index 100% rename from packages/system/seaweedfs/charts/seaweedfs/templates/cluster-role.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/shared/cluster-role.yaml diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/shared/notification-configmap.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/notification-configmap.yaml new file mode 100644 index 00000000..c638c877 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/notification-configmap.yaml @@ -0,0 +1,19 @@ +{{- if and .Values.filer.enabled .Values.filer.notificationConfig }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "seaweedfs.name" . }}-notification-config + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Values.filer.annotations }} + annotations: + {{- toYaml .Values.filer.annotations | nindent 4 }} +{{- end }} +data: + notification.toml: |- + {{ .Values.filer.notificationConfig | nindent 4 }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/shared/post-install-bucket-hook.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/post-install-bucket-hook.yaml new file mode 100644 index 00000000..a0c56edc --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/post-install-bucket-hook.yaml @@ -0,0 +1,151 @@ +{{- /* Support bucket creation for both standalone filer.s3 and allInOne modes */}} +{{- $createBuckets := list }} +{{- $s3Enabled := false }} +{{- $enableAuth := false }} +{{- $existingConfigSecret := "" }} + +{{- /* Check allInOne mode first */}} +{{- if .Values.allInOne.enabled }} + {{- if .Values.allInOne.s3.enabled }} + {{- $s3Enabled = true }} + {{- if .Values.allInOne.s3.createBuckets }} + {{- $createBuckets = .Values.allInOne.s3.createBuckets }} + {{- end }} + {{- $enableAuth = or .Values.allInOne.s3.enableAuth .Values.s3.enableAuth .Values.filer.s3.enableAuth }} + {{- $existingConfigSecret = or .Values.allInOne.s3.existingConfigSecret .Values.s3.existingConfigSecret .Values.filer.s3.existingConfigSecret }} + {{- end }} +{{- else if .Values.master.enabled }} + {{- /* Check standalone filer.s3 mode */}} + {{- if .Values.filer.s3.enabled }} + {{- $s3Enabled = true }} + {{- if .Values.filer.s3.createBuckets }} + {{- $createBuckets = .Values.filer.s3.createBuckets }} + {{- end }} + {{- $enableAuth = .Values.filer.s3.enableAuth }} + {{- $existingConfigSecret = .Values.filer.s3.existingConfigSecret }} + {{- end }} +{{- end }} + +{{- if and $s3Enabled $createBuckets }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: "{{ $.Release.Name }}-bucket-hook" + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + annotations: + "helm.sh/hook": post-install + "helm.sh/hook-weight": "-5" + "helm.sh/hook-delete-policy": hook-succeeded +spec: + template: + metadata: + name: "{{ .Release.Name }}" + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + spec: + restartPolicy: Never + {{- if .Values.filer.podSecurityContext.enabled }} + securityContext: {{- omit .Values.filer.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: post-install-job + image: {{ template "master.image" . }} + env: + - name: WEED_CLUSTER_DEFAULT + value: "sw" + - name: WEED_CLUSTER_SW_MASTER + value: {{ include "seaweedfs.cluster.masterAddress" . | quote }} + - name: WEED_CLUSTER_SW_FILER + value: {{ include "seaweedfs.cluster.filerAddress" . | quote }} + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SEAWEEDFS_FULLNAME + value: "{{ template "seaweedfs.name" . }}" + command: + - "/bin/sh" + - "-ec" + - | + wait_for_service() { + local url=$1 + local max_attempts=60 # 5 minutes total (5s * 60) + local attempt=1 + + echo "Waiting for service at $url..." + while [ $attempt -le $max_attempts ]; do + if wget -q --spider "$url" >/dev/null 2>&1; then + echo "Service at $url is up!" + return 0 + fi + echo "Attempt $attempt: Service not ready yet, retrying in 5s..." + sleep 5 + attempt=$((attempt + 1)) + done + echo "Service at $url failed to become ready within 5 minutes" + exit 1 + } + {{- if .Values.allInOne.enabled }} + wait_for_service "http://$WEED_CLUSTER_SW_MASTER{{ .Values.allInOne.readinessProbe.httpGet.path }}" + wait_for_service "http://$WEED_CLUSTER_SW_FILER{{ .Values.filer.readinessProbe.httpGet.path }}" + {{- else }} + wait_for_service "http://$WEED_CLUSTER_SW_MASTER{{ .Values.master.readinessProbe.httpGet.path }}" + wait_for_service "http://$WEED_CLUSTER_SW_FILER{{ .Values.filer.readinessProbe.httpGet.path }}" + {{- end }} + {{- range $createBuckets }} + /bin/echo \ + "s3.bucket.create --name {{ .name }}" |\ + /usr/bin/weed shell + {{- end }} + {{- range $createBuckets }} + {{- if .anonymousRead }} + /bin/echo \ + "s3.configure --user anonymous \ + --buckets {{ .name }} \ + --actions Read \ + --apply true" |\ + /usr/bin/weed shell + {{- end }} + {{- end }} + {{- if $enableAuth }} + volumeMounts: + - name: config-users + mountPath: /etc/sw + readOnly: true + {{- end }} + ports: + - containerPort: {{ .Values.master.port }} + name: swfs-master + {{- if and .Values.global.monitoring.enabled .Values.master.metricsPort }} + - containerPort: {{ .Values.master.metricsPort }} + name: metrics + {{- end }} + - containerPort: {{ .Values.master.grpcPort }} + #name: swfs-master-grpc + {{- if .Values.filer.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.filer.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + {{- if $enableAuth }} + volumes: + - name: config-users + secret: + defaultMode: 420 + {{- if $existingConfigSecret }} + secretName: {{ $existingConfigSecret }} + {{- else }} + secretName: {{ template "seaweedfs.name" . }}-s3-secret + {{- end }} + {{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/shared/seaweedfs-grafana-dashboard.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/seaweedfs-grafana-dashboard.yaml new file mode 100644 index 00000000..cf7801cc --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/seaweedfs-grafana-dashboard.yaml @@ -0,0 +1,19 @@ +{{- if .Values.global.monitoring.enabled }} +{{- $files := .Files.Glob "dashboards/*.json" }} +{{- if $files }} +{{- range $path, $file := $files }} +{{- $dashboardName := regexReplaceAll "(^.*/)(.*)\\.json$" $path "${2}" }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ printf "%s" $dashboardName | lower | replace "_" "-" }} + namespace: {{ $.Release.Namespace }} + labels: + grafana_dashboard: "1" +data: + {{ $dashboardName }}.json: |- +{{ toString $file | indent 4 }} +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/secret-seaweedfs-db.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/secret-seaweedfs-db.yaml similarity index 100% rename from packages/system/seaweedfs/charts/seaweedfs/templates/secret-seaweedfs-db.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/shared/secret-seaweedfs-db.yaml diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/security-configmap.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/security-configmap.yaml similarity index 77% rename from packages/system/seaweedfs/charts/seaweedfs/templates/security-configmap.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/shared/security-configmap.yaml index 884fe6bb..f7fb69ea 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/security-configmap.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/security-configmap.yaml @@ -10,6 +10,8 @@ metadata: app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/instance: {{ .Release.Name }} data: + {{- $existing := (lookup "v1" "ConfigMap" .Release.Namespace (printf "%s-security-config" (include "seaweedfs.name" .))) }} + {{- $securityConfig := fromToml (dig "data" "security.toml" "" $existing) }} security.toml: |- # this file is read by master, volume server, and filer @@ -17,7 +19,7 @@ data: # the jwt signing key is read by master and volume server # a jwt expires in 10 seconds [jwt.signing] - key = "{{ randAlphaNum 10 | b64enc }}" + key = "{{ dig "jwt" "signing" "key" (randAlphaNum 10 | b64enc) $securityConfig }}" {{- end }} {{- if .Values.global.securityConfig.jwtSigning.volumeRead }} @@ -25,7 +27,7 @@ data: # - the Master server generates the JWT, which can be used to read a certain file on a volume server # - the Volume server validates the JWT on reading [jwt.signing.read] - key = "{{ randAlphaNum 10 | b64enc }}" + key = "{{ dig "jwt" "signing" "read" "key" (randAlphaNum 10 | b64enc) $securityConfig }}" {{- end }} {{- if .Values.global.securityConfig.jwtSigning.filerWrite }} @@ -34,7 +36,7 @@ data: # - the Filer server validates the JWT on writing # the jwt defaults to expire after 10 seconds. [jwt.filer_signing] - key = "{{ randAlphaNum 10 | b64enc }}" + key = "{{ dig "jwt" "filer_signing" "key" (randAlphaNum 10 | b64enc) $securityConfig }}" {{- end }} {{- if .Values.global.securityConfig.jwtSigning.filerRead }} @@ -43,7 +45,7 @@ data: # - the Filer server validates the JWT on writing # the jwt defaults to expire after 10 seconds. [jwt.filer_signing.read] - key = "{{ randAlphaNum 10 | b64enc }}" + key = "{{ dig "jwt" "filer_signing" "read" "key" (randAlphaNum 10 | b64enc) $securityConfig }}" {{- end }} # all grpc tls authentications are mutual @@ -63,6 +65,14 @@ data: cert = "/usr/local/share/ca-certificates/filer/tls.crt" key = "/usr/local/share/ca-certificates/filer/tls.key" + [grpc.admin] + cert = "/usr/local/share/ca-certificates/admin/tls.crt" + key = "/usr/local/share/ca-certificates/admin/tls.key" + + [grpc.worker] + cert = "/usr/local/share/ca-certificates/worker/tls.crt" + key = "/usr/local/share/ca-certificates/worker/tls.key" + # use this for any place needs a grpc client # i.e., "weed backup|benchmark|filer.copy|filer.replicate|mount|s3|upload" [grpc.client] diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/service-account.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/shared/service-account.yaml similarity index 100% rename from packages/system/seaweedfs/charts/seaweedfs/templates/service-account.yaml rename to packages/system/seaweedfs/charts/seaweedfs/templates/shared/service-account.yaml diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-resize-hook.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume-resize-hook.yaml deleted file mode 100644 index 9f186eaa..00000000 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-resize-hook.yaml +++ /dev/null @@ -1,117 +0,0 @@ -{{- if and .Values.volume.enabled .Values.volume.resizeHook.enabled }} -{{- $seaweedfsName := include "seaweedfs.name" $ }} -{{- $replicas := int .Values.volume.replicas -}} -{{- $statefulsetName := printf "%s-volume" $seaweedfsName -}} -{{- $statefulset := (lookup "apps/v1" "StatefulSet" .Release.Namespace $statefulsetName) -}} - -{{/* Check for changes in volumeClaimTemplates */}} -{{- $templateChangesRequired := false -}} -{{- if $statefulset -}} - {{- range $dir := .Values.volume.dataDirs -}} - {{- if eq .type "persistentVolumeClaim" -}} - {{- $desiredSize := .size -}} - {{- range $statefulset.spec.volumeClaimTemplates -}} - {{- if and (eq .metadata.name $dir.name) (ne .spec.resources.requests.storage $desiredSize) -}} - {{- $templateChangesRequired = true -}} - {{- end -}} - {{- end -}} - {{- end -}} - {{- end -}} -{{- end -}} - -{{/* Check for the need for patching existing PVCs */}} -{{- $pvcChangesRequired := false -}} -{{- range $dir := .Values.volume.dataDirs -}} - {{- if eq .type "persistentVolumeClaim" -}} - {{- $desiredSize := .size -}} - {{- range $i, $e := until $replicas }} - {{- $pvcName := printf "%s-%s-volume-%d" $dir.name $seaweedfsName $e -}} - {{- $currentPVC := (lookup "v1" "PersistentVolumeClaim" $.Release.Namespace $pvcName) -}} - {{- if and $currentPVC (ne ($currentPVC.spec.resources.requests.storage | toString) $desiredSize) -}} - {{- $pvcChangesRequired = true -}} - {{- end -}} - {{- end -}} - {{- end -}} -{{- end -}} - -{{- if or $templateChangesRequired $pvcChangesRequired }} -apiVersion: batch/v1 -kind: Job -metadata: - name: "{{ $seaweedfsName }}-volume-resize-hook" - annotations: - helm.sh/hook: pre-install,pre-upgrade - helm.sh/hook-weight: "0" - helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation -spec: - template: - metadata: - labels: - policy.cozystack.io/allow-to-apiserver: "true" - spec: - serviceAccountName: {{ $seaweedfsName }}-volume-resize-hook - restartPolicy: Never - backoffLimit: 1 - containers: - - name: resize - image: {{ .Values.volume.resizeHook.image }} - command: ["sh", "-xec"] - args: - - | - {{- if $pvcChangesRequired -}} - {{- range $dir := .Values.volume.dataDirs -}} - {{- if eq .type "persistentVolumeClaim" -}} - {{- $desiredSize := .size -}} - {{- range $i, $e := until $replicas }} - kubectl patch pvc {{ printf "%s-%s-volume-%d" $dir.name $seaweedfsName $e }} -p '{"spec":{"resources":{"requests":{"storage":"{{ $desiredSize }}"}}}}' - {{- end }} - {{- end }} - {{- end }} - {{- end -}} - - {{- if $templateChangesRequired }} - kubectl delete statefulset {{ $statefulsetName }} --cascade=orphan - {{- end }} -{{- end }} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ $seaweedfsName }}-volume-resize-hook - annotations: - helm.sh/hook: pre-install,pre-upgrade - helm.sh/hook-weight: "-5" - helm.sh/hook-delete-policy: before-hook-creation ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: {{ $seaweedfsName }}-volume-resize-hook - annotations: - helm.sh/hook: pre-install,pre-upgrade - helm.sh/hook-weight: "-5" - helm.sh/hook-delete-policy: before-hook-creation -rules: - - apiGroups: ["apps"] - resources: ["statefulsets"] - verbs: ["delete", "get", "list", "watch"] - - apiGroups: [""] - resources: ["persistentvolumeclaims"] - verbs: ["patch", "get", "list", "watch"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: {{ $seaweedfsName }}-volume-resize-hook - annotations: - helm.sh/hook: pre-install,pre-upgrade - helm.sh/hook-weight: "-5" - helm.sh/hook-delete-policy: before-hook-creation -subjects: - - kind: ServiceAccount - name: {{ $seaweedfsName }}-volume-resize-hook -roleRef: - kind: Role - name: {{ $seaweedfsName }}-volume-resize-hook - apiGroup: rbac.authorization.k8s.io -{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-service.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume-service.yaml deleted file mode 100644 index 1205f4fa..00000000 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-service.yaml +++ /dev/null @@ -1,33 +0,0 @@ -{{- if .Values.volume.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: {{ template "seaweedfs.name" . }}-volume - namespace: {{ .Release.Namespace }} - labels: - app.kubernetes.io/name: {{ template "seaweedfs.name" . }} - app.kubernetes.io/component: volume - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} - app.kubernetes.io/managed-by: {{ .Release.Service }} -spec: - clusterIP: None - internalTrafficPolicy: {{ .Values.volume.internalTrafficPolicy | default "Cluster" }} - ports: - - name: "swfs-volume" - port: {{ .Values.volume.port }} - targetPort: {{ .Values.volume.port }} - protocol: TCP - - name: "swfs-volume-18080" - port: {{ .Values.volume.grpcPort }} - targetPort: {{ .Values.volume.grpcPort }} - protocol: TCP -{{- if .Values.volume.metricsPort }} - - name: "metrics" - port: {{ .Values.volume.metricsPort }} - targetPort: {{ .Values.volume.metricsPort }} - protocol: TCP -{{- end }} - selector: - app.kubernetes.io/name: {{ template "seaweedfs.name" . }} - app.kubernetes.io/component: volume -{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-statefulset.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume-statefulset.yaml deleted file mode 100644 index eb3bb913..00000000 --- a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-statefulset.yaml +++ /dev/null @@ -1,388 +0,0 @@ -{{- if .Values.volume.enabled }} -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: {{ template "seaweedfs.name" . }}-volume - namespace: {{ .Release.Namespace }} - labels: - app.kubernetes.io/name: {{ template "seaweedfs.name" . }} - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} -spec: - persistentVolumeClaimRetentionPolicy: - whenDeleted: Delete - whenScaled: Delete - serviceName: {{ template "seaweedfs.name" . }}-volume - replicas: {{ .Values.volume.replicas }} - podManagementPolicy: {{ .Values.volume.podManagementPolicy }} - selector: - matchLabels: - app.kubernetes.io/name: {{ template "seaweedfs.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/component: volume - template: - metadata: - labels: - app.kubernetes.io/name: {{ template "seaweedfs.name" . }} - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/component: volume - {{ with .Values.podLabels }} - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.volume.podLabels }} - {{- toYaml . | nindent 8 }} - {{- end }} - annotations: - {{ with .Values.podAnnotations }} - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.volume.podAnnotations }} - {{- toYaml . | nindent 8 }} - {{- end }} - spec: - {{- if .Values.volume.affinity }} - affinity: - {{ tpl .Values.volume.affinity . | nindent 8 | trim }} - {{- end }} - restartPolicy: {{ default .Values.global.restartPolicy .Values.volume.restartPolicy }} - {{- if .Values.volume.tolerations }} - tolerations: - {{ tpl .Values.volume.tolerations . | nindent 8 | trim }} - {{- end }} - {{- include "seaweedfs.imagePullSecrets" . | nindent 6 }} - terminationGracePeriodSeconds: 150 - {{- if .Values.volume.priorityClassName }} - priorityClassName: {{ .Values.volume.priorityClassName | quote }} - {{- end }} - enableServiceLinks: false - {{- if .Values.global.createClusterRole }} - serviceAccountName: {{ .Values.volume.serviceAccountName | default .Values.global.serviceAccountName | quote }} # for deleting statefulset pods after migration - {{- end }} - {{- $initContainers_exists := include "volume.initContainers_exists" . -}} - {{- if $initContainers_exists }} - initContainers: - {{- if .Values.volume.idx }} - - name: seaweedfs-vol-move-idx - image: {{ template "volume.image" . }} - imagePullPolicy: {{ .Values.global.imagePullPolicy | default "IfNotPresent" }} - command: [ '/bin/sh', '-c' ] - args: [ '{{range $dir := .Values.volume.dataDirs }}if ls /{{$dir.name}}/*.idx >/dev/null 2>&1; then mv /{{$dir.name}}/*.idx /idx/ ; fi; {{end}}' ] - volumeMounts: - - name: idx - mountPath: /idx - {{- range $dir := .Values.volume.dataDirs }} - - name: {{ $dir.name }} - mountPath: /{{ $dir.name }} - {{- end }} - {{- end }} - {{- if .Values.volume.initContainers }} - {{ tpl .Values.volume.initContainers . | nindent 8 | trim }} - {{- end }} - {{- end }} - {{- if .Values.volume.podSecurityContext.enabled }} - securityContext: {{- omit .Values.volume.podSecurityContext "enabled" | toYaml | nindent 8 }} - {{- end }} - containers: - - name: seaweedfs - image: {{ template "volume.image" . }} - imagePullPolicy: {{ default "IfNotPresent" .Values.global.imagePullPolicy }} - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: HOST_IP - valueFrom: - fieldRef: - fieldPath: status.hostIP - - name: SEAWEEDFS_FULLNAME - value: "{{ template "seaweedfs.name" . }}" - {{- if .Values.volume.extraEnvironmentVars }} - {{- range $key, $value := .Values.volume.extraEnvironmentVars }} - - name: {{ $key }} - {{- if kindIs "string" $value }} - value: {{ $value | quote }} - {{- else }} - valueFrom: - {{ toYaml $value | nindent 16 | trim }} - {{- end -}} - {{- end }} - {{- end }} - {{- if .Values.global.extraEnvironmentVars }} - {{- range $key, $value := .Values.global.extraEnvironmentVars }} - - name: {{ $key }} - {{- if kindIs "string" $value }} - value: {{ $value | quote }} - {{- else }} - valueFrom: - {{ toYaml $value | nindent 16 | trim }} - {{- end -}} - {{- end }} - {{- end }} - command: - - "/bin/sh" - - "-ec" - - | - exec /usr/bin/weed \ - {{- if .Values.volume.logs }} - -logdir=/logs \ - {{- else }} - -logtostderr=true \ - {{- end }} - {{- if .Values.volume.loggingOverrideLevel }} - -v={{ .Values.volume.loggingOverrideLevel }} \ - {{- else }} - -v={{ .Values.global.loggingLevel }} \ - {{- end }} - volume \ - -port={{ .Values.volume.port }} \ - {{- if .Values.volume.metricsPort }} - -metricsPort={{ .Values.volume.metricsPort }} \ - {{- end }} - -dir {{range $index, $dir := .Values.volume.dataDirs }}{{if ne $index 0}},{{end}}/{{$dir.name}}{{end}} \ - {{- if .Values.volume.idx }} - -dir.idx=/idx \ - {{- end }} - -max {{range $index, $dir := .Values.volume.dataDirs }}{{if ne $index 0}},{{end}}{{$dir.maxVolumes}}{{end}} \ - {{- if .Values.volume.rack }} - -rack={{ .Values.volume.rack }} \ - {{- end }} - {{- if .Values.volume.dataCenter }} - -dataCenter={{ .Values.volume.dataCenter }} \ - {{- end }} - -ip.bind={{ .Values.volume.ipBind }} \ - -readMode={{ .Values.volume.readMode }} \ - {{- if .Values.volume.whiteList }} - -whiteList={{ .Values.volume.whiteList }} \ - {{- end }} - {{- if .Values.volume.imagesFixOrientation }} - -images.fix.orientation \ - {{- end }} - {{- if .Values.volume.pulseSeconds }} - -pulseSeconds={{ .Values.volume.pulseSeconds }} \ - {{- end }} - {{- if .Values.volume.index }} - -index={{ .Values.volume.index }} \ - {{- end }} - {{- if .Values.volume.fileSizeLimitMB }} - -fileSizeLimitMB={{ .Values.volume.fileSizeLimitMB }} \ - {{- end }} - -minFreeSpacePercent={{ .Values.volume.minFreeSpacePercent }} \ - -ip=${POD_NAME}.${SEAWEEDFS_FULLNAME}-volume.{{ .Release.Namespace }} \ - -compactionMBps={{ .Values.volume.compactionMBps }} \ - -mserver={{ if .Values.global.masterServer }}{{.Values.global.masterServer}}{{ else }}{{ range $index := until (.Values.master.replicas | int) }}${SEAWEEDFS_FULLNAME}-master-{{ $index }}.${SEAWEEDFS_FULLNAME}-master.{{ $.Release.Namespace }}:{{ $.Values.master.port }}{{ if lt $index (sub ($.Values.master.replicas | int) 1) }},{{ end }}{{ end }}{{ end }} - volumeMounts: - {{- range $dir := .Values.volume.dataDirs }} - - name: {{ $dir.name }} - mountPath: "/{{ $dir.name }}/" - {{- end }} - {{- if .Values.volume.logs }} - - name: logs - mountPath: "/logs/" - {{- end }} - {{- if .Values.volume.idx }} - - name: idx - mountPath: "/idx/" - {{- end }} - {{- if .Values.global.enableSecurity }} - - name: security-config - readOnly: true - mountPath: /etc/seaweedfs/security.toml - subPath: security.toml - - name: ca-cert - readOnly: true - mountPath: /usr/local/share/ca-certificates/ca/ - - name: master-cert - readOnly: true - mountPath: /usr/local/share/ca-certificates/master/ - - name: volume-cert - readOnly: true - mountPath: /usr/local/share/ca-certificates/volume/ - - name: filer-cert - readOnly: true - mountPath: /usr/local/share/ca-certificates/filer/ - - name: client-cert - readOnly: true - mountPath: /usr/local/share/ca-certificates/client/ - {{- end }} - {{ tpl .Values.volume.extraVolumeMounts . | nindent 12 | trim }} - ports: - - containerPort: {{ .Values.volume.port }} - name: swfs-vol - {{- if .Values.volume.metricsPort }} - - containerPort: {{ .Values.volume.metricsPort }} - name: metrics - {{- end }} - - containerPort: {{ .Values.volume.grpcPort }} - name: swfs-vol-grpc - {{- if .Values.volume.readinessProbe.enabled }} - readinessProbe: - httpGet: - path: {{ .Values.volume.readinessProbe.httpGet.path }} - port: {{ .Values.volume.port }} - scheme: {{ .Values.volume.readinessProbe.scheme }} - initialDelaySeconds: {{ .Values.volume.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.volume.readinessProbe.periodSeconds }} - successThreshold: {{ .Values.volume.readinessProbe.successThreshold }} - failureThreshold: {{ .Values.volume.readinessProbe.failureThreshold }} - timeoutSeconds: {{ .Values.volume.readinessProbe.timeoutSeconds }} - {{- end }} - {{- if .Values.volume.livenessProbe.enabled }} - livenessProbe: - httpGet: - path: {{ .Values.volume.livenessProbe.httpGet.path }} - port: {{ .Values.volume.port }} - scheme: {{ .Values.volume.livenessProbe.scheme }} - initialDelaySeconds: {{ .Values.volume.livenessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.volume.livenessProbe.periodSeconds }} - successThreshold: {{ .Values.volume.livenessProbe.successThreshold }} - failureThreshold: {{ .Values.volume.livenessProbe.failureThreshold }} - timeoutSeconds: {{ .Values.volume.livenessProbe.timeoutSeconds }} - {{- end }} - {{- with .Values.volume.resources }} - resources: - {{- toYaml . | nindent 12 }} - {{- end }} - {{- if .Values.volume.containerSecurityContext.enabled }} - securityContext: {{- omit .Values.volume.containerSecurityContext "enabled" | toYaml | nindent 12 }} - {{- end }} - {{- if .Values.volume.sidecars }} - {{- include "common.tplvalues.render" (dict "value" .Values.volume.sidecars "context" $) | nindent 8 }} - {{- end }} - volumes: - - {{- range $dir := .Values.volume.dataDirs }} - - {{- if eq $dir.type "hostPath" }} - - name: {{ $dir.name }} - hostPath: - path: {{ $dir.hostPathPrefix }}/object_store/ - type: DirectoryOrCreate - {{- end }} - {{- if eq $dir.type "existingClaim" }} - - name: {{ $dir.name }} - persistentVolumeClaim: - claimName: {{ $dir.claimName }} - {{- end }} - {{- if eq $dir.type "emptyDir" }} - - name: {{ $dir.name }} - emptyDir: {} - {{- end }} - - {{- end }} - - {{- if .Values.volume.idx }} - {{- if eq .Values.volume.idx.type "hostPath" }} - - name: idx - hostPath: - path: {{ .Values.volume.idx.hostPathPrefix }}/seaweedfs-volume-idx/ - type: DirectoryOrCreate - {{- end }} - {{- if eq .Values.volume.idx.type "existingClaim" }} - - name: idx - persistentVolumeClaim: - claimName: {{ .Values.volume.idx.claimName }} - {{- end }} - {{- if eq .Values.volume.idx.type "emptyDir" }} - - name: idx - emptyDir: {} - {{- end }} - {{- end }} - - {{- if .Values.volume.logs }} - {{- if eq .Values.volume.logs.type "hostPath" }} - - name: logs - hostPath: - path: {{ .Values.volume.logs.hostPathPrefix }}/logs/seaweedfs/volume - type: DirectoryOrCreate - {{- end }} - {{- if eq .Values.volume.logs.type "existingClaim" }} - - name: logs - persistentVolumeClaim: - claimName: {{ .Values.volume.logs.claimName }} - {{- end }} - {{- if eq .Values.volume.logs.type "emptyDir" }} - - name: logs - emptyDir: {} - {{- end }} - {{- end }} - {{- if .Values.global.enableSecurity }} - - name: security-config - configMap: - name: {{ template "seaweedfs.name" . }}-security-config - - name: ca-cert - secret: - secretName: {{ template "seaweedfs.name" . }}-ca-cert - - name: master-cert - secret: - secretName: {{ template "seaweedfs.name" . }}-master-cert - - name: volume-cert - secret: - secretName: {{ template "seaweedfs.name" . }}-volume-cert - - name: filer-cert - secret: - secretName: {{ template "seaweedfs.name" . }}-filer-cert - - name: client-cert - secret: - secretName: {{ template "seaweedfs.name" . }}-client-cert - {{- end }} - {{- if .Values.volume.extraVolumes }} - {{ tpl .Values.volume.extraVolumes . | indent 8 | trim }} - {{- end }} - {{- if .Values.volume.nodeSelector }} - nodeSelector: - {{ tpl .Values.volume.nodeSelector . | indent 8 | trim }} - {{- end }} - volumeClaimTemplates: - {{- range $dir := .Values.volume.dataDirs }} - {{- if eq $dir.type "persistentVolumeClaim" }} - - metadata: - name: {{ $dir.name }} - {{- with $dir.annotations }} - annotations: - {{- toYaml . | nindent 10 }} - {{- end }} - spec: - accessModes: [ "ReadWriteOnce" ] - storageClassName: {{ $dir.storageClass }} - resources: - requests: - storage: {{ $dir.size }} - {{- end }} - {{- end }} - - {{- if and .Values.volume.idx (eq .Values.volume.idx.type "persistentVolumeClaim") }} - - metadata: - name: idx - {{- with .Values.volume.idx.annotations }} - annotations: - {{- toYaml . | nindent 10 }} - {{- end }} - spec: - accessModes: [ "ReadWriteOnce" ] - storageClassName: {{ .Values.volume.idx.storageClass }} - resources: - requests: - storage: {{ .Values.volume.idx.size }} - {{- end }} - {{- if and .Values.volume.logs (eq .Values.volume.logs.type "persistentVolumeClaim") }} - - metadata: - name: logs - {{- with .Values.volume.logs.annotations }} - annotations: - {{- toYaml . | nindent 10 }} - {{- end }} - spec: - accessModes: [ "ReadWriteOnce" ] - storageClassName: {{ .Values.volume.logs.storageClass }} - resources: - requests: - storage: {{ .Values.volume.logs.size }} - {{- end }} - {{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-resize-hook.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-resize-hook.yaml new file mode 100644 index 00000000..8e3b5932 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-resize-hook.yaml @@ -0,0 +1,120 @@ +{{- $seaweedfsName := include "seaweedfs.name" $ }} +{{- $volumes := deepCopy .Values.volumes | mergeOverwrite (dict "" .Values.volume) }} + + +{{- if .Values.volume.resizeHook.enabled }} +{{- $commands := list }} +{{- range $vname, $volume := $volumes }} +{{- $volumeName := trimSuffix "-" (printf "volume-%s" $vname) }} +{{- $volume := mergeOverwrite (deepCopy $.Values.volume) (dict "enabled" true) $volume }} + +{{- if $volume.enabled }} +{{- $replicas := int $volume.replicas -}} +{{- $statefulsetName := printf "%s-%s" $seaweedfsName $volumeName -}} +{{- $statefulset := (lookup "apps/v1" "StatefulSet" $.Release.Namespace $statefulsetName) -}} + +{{/* Check for changes in volumeClaimTemplates */}} +{{- if $statefulset }} +{{- range $dir := $volume.dataDirs }} +{{- if eq .type "persistentVolumeClaim" }} +{{- $desiredSize := .size }} +{{- range $statefulset.spec.volumeClaimTemplates }} +{{- if and (eq .metadata.name $dir.name) (ne .spec.resources.requests.storage $desiredSize) }} +{{- $commands = append $commands (printf "kubectl delete statefulset %s --cascade=orphan" $statefulsetName) }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{/* Check for the need for patching existing PVCs */}} +{{- range $dir := $volume.dataDirs }} +{{- if eq .type "persistentVolumeClaim" }} +{{- $desiredSize := .size }} +{{- range $i, $e := until $replicas }} +{{- $pvcName := printf "%s-%s-%s-%d" $dir.name $seaweedfsName $volumeName $e }} +{{- $currentPVC := (lookup "v1" "PersistentVolumeClaim" $.Release.Namespace $pvcName) }} +{{- if and $currentPVC }} +{{- $oldSize := include "common.resource-quantity" $currentPVC.spec.resources.requests.storage }} +{{- $newSize := include "common.resource-quantity" $desiredSize }} +{{- if gt $newSize $oldSize }} +{{- $commands = append $commands (printf "kubectl patch pvc %s-%s-%s-%d -p '{\"spec\":{\"resources\":{\"requests\":{\"storage\":\"%s\"}}}}'" $dir.name $seaweedfsName $volumeName $e $desiredSize) }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{- end }} +{{- end }} + +{{- if $commands }} +apiVersion: batch/v1 +kind: Job +metadata: + name: "{{ $seaweedfsName }}-volume-resize-hook" + annotations: + helm.sh/hook: pre-install,pre-upgrade + helm.sh/hook-weight: "0" + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation +spec: + template: + metadata: + labels: + policy.cozystack.io/allow-to-apiserver: "true" + spec: + serviceAccountName: {{ $seaweedfsName }}-volume-resize-hook + restartPolicy: Never + backoffLimit: 1 + containers: + - name: resize + image: {{ .Values.volume.resizeHook.image }} + command: ["sh", "-xec"] + args: + - | + {{- range $commands }} + {{ . }} + {{- end }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ $seaweedfsName }}-volume-resize-hook + annotations: + helm.sh/hook: pre-install,pre-upgrade + helm.sh/hook-weight: "-5" + helm.sh/hook-delete-policy: before-hook-creation +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ $seaweedfsName }}-volume-resize-hook + annotations: + helm.sh/hook: pre-install,pre-upgrade + helm.sh/hook-weight: "-5" + helm.sh/hook-delete-policy: before-hook-creation +rules: + - apiGroups: ["apps"] + resources: ["statefulsets"] + verbs: ["delete", "get", "list", "watch"] + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["patch", "get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ $seaweedfsName }}-volume-resize-hook + annotations: + helm.sh/hook: pre-install,pre-upgrade + helm.sh/hook-weight: "-5" + helm.sh/hook-delete-policy: before-hook-creation +subjects: + - kind: ServiceAccount + name: {{ $seaweedfsName }}-volume-resize-hook +roleRef: + kind: Role + name: {{ $seaweedfsName }}-volume-resize-hook + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-service.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-service.yaml new file mode 100644 index 00000000..dfafc816 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-service.yaml @@ -0,0 +1,44 @@ +{{ $volumes := deepCopy .Values.volumes | mergeOverwrite (dict "" .Values.volume) }} +{{- range $vname, $volume := $volumes }} +{{- $volumeName := trimSuffix "-" (printf "volume-%s" $vname) }} +{{- $volume := mergeOverwrite (deepCopy $.Values.volume) (dict "enabled" true) $volume }} + +{{- if $volume.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "seaweedfs.name" $ }}-{{ $volumeName }} + namespace: {{ $.Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" $ }} + app.kubernetes.io/component: {{ $volumeName }} + helm.sh/chart: {{ $.Chart.Name }}-{{ $.Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ $.Release.Service }} +{{- if $volume.annotations }} + annotations: + {{- toYaml $volume.annotations | nindent 4 }} +{{- end }} +spec: + clusterIP: None + internalTrafficPolicy: {{ $volume.internalTrafficPolicy | default "Cluster" }} + ports: + - name: "swfs-volume" + port: {{ $volume.port }} + targetPort: {{ $volume.port }} + protocol: TCP + - name: "swfs-volume-18080" + port: {{ $volume.grpcPort }} + targetPort: {{ $volume.grpcPort }} + protocol: TCP +{{- if $volume.metricsPort }} + - name: "metrics" + port: {{ $volume.metricsPort }} + targetPort: {{ $volume.metricsPort }} + protocol: TCP +{{- end }} + selector: + app.kubernetes.io/name: {{ template "seaweedfs.name" $ }} + app.kubernetes.io/component: {{ $volumeName }} +{{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-servicemonitor.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-servicemonitor.yaml new file mode 100644 index 00000000..ac82eb57 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-servicemonitor.yaml @@ -0,0 +1,40 @@ +{{ $volumes := deepCopy .Values.volumes | mergeOverwrite (dict "" .Values.volume) }} +{{- range $vname, $volume := $volumes }} +{{- $volumeName := trimSuffix "-" (printf "volume-%s" $vname) }} +{{- $volume := mergeOverwrite (deepCopy $.Values.volume) (dict "enabled" true) $volume }} + +{{- if $volume.enabled }} +{{- if $volume.metricsPort }} +{{- if $.Values.global.monitoring.enabled }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "seaweedfs.name" $ }}-{{ $volumeName }} + namespace: {{ $.Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" $ }} + helm.sh/chart: {{ $.Chart.Name }}-{{ $.Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ $.Release.Service }} + app.kubernetes.io/instance: {{ $.Release.Name }} + app.kubernetes.io/component: {{ $volumeName }} + {{- with $.Values.global.monitoring.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- with $volume.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + endpoints: + - interval: 30s + port: metrics + scrapeTimeout: 5s + selector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" $ }} + app.kubernetes.io/component: {{ $volumeName }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml new file mode 100644 index 00000000..045b95c2 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml @@ -0,0 +1,423 @@ +{{ $volumes := deepCopy .Values.volumes | mergeOverwrite (dict "" .Values.volume) }} +{{- range $vname, $volume := $volumes }} +{{- $volumeName := trimSuffix "-" (printf "volume-%s" $vname) }} +{{- $volume := mergeOverwrite (deepCopy $.Values.volume) (dict "enabled" true) $volume }} + +{{- if $volume.enabled }} +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ template "seaweedfs.name" $ }}-{{ $volumeName }} + namespace: {{ $.Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" $ }} + helm.sh/chart: {{ $.Chart.Name }}-{{ $.Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ $.Release.Service }} + app.kubernetes.io/instance: {{ $.Release.Name }} + app.kubernetes.io/component: {{ $volumeName }} +{{- if $volume.annotations }} + annotations: + {{- toYaml $volume.annotations | nindent 4 }} +{{- end }} +spec: + serviceName: {{ template "seaweedfs.name" $ }}-{{ $volumeName }} + replicas: {{ $volume.replicas }} + podManagementPolicy: {{ $volume.podManagementPolicy }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" $ }} + app.kubernetes.io/instance: {{ $.Release.Name }} + app.kubernetes.io/component: {{ $volumeName }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" $ }} + helm.sh/chart: {{ $.Chart.Name }}-{{ $.Chart.Version | replace "+" "_" }} + app.kubernetes.io/instance: {{ $.Release.Name }} + app.kubernetes.io/component: {{ $volumeName }} + {{ with $.Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $volume.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + annotations: + {{ with $.Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $volume.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- if $volume.affinity }} + affinity: + {{ tpl (printf "{{ $volumeName := \"%s\" }}%s" $volumeName $volume.affinity) $ | indent 8 | trim }} + {{- end }} + {{- if $volume.topologySpreadConstraints }} + topologySpreadConstraints: + {{ tpl (printf "{{ $volumeName := \"%s\" }}%s" $volumeName $volume.topologySpreadConstraints) $ | nindent 8 | trim }} + {{- end }} + restartPolicy: {{ default $.Values.global.restartPolicy $volume.restartPolicy }} + {{- if $volume.tolerations }} + tolerations: + {{ tpl (printf "{{ $volumeName := \"%s\" }}%s" $volumeName $volume.tolerations) $ | indent 8 | trim }} + {{- end }} + {{- include "seaweedfs.imagePullSecrets" $ | nindent 6 }} + terminationGracePeriodSeconds: 150 + {{- if $volume.priorityClassName }} + priorityClassName: {{ $volume.priorityClassName | quote }} + {{- end }} + enableServiceLinks: false + {{- if $.Values.global.createClusterRole }} + serviceAccountName: {{ $volume.serviceAccountName | default $.Values.global.serviceAccountName | quote }} # for deleting statefulset pods after migration + {{- end }} + {{- $initContainers_exists := include "volume.initContainers_exists" $ -}} + {{- if $initContainers_exists }} + initContainers: + {{- if $volume.idx }} + - name: seaweedfs-vol-move-idx + image: {{ template "volume.image" $ }} + imagePullPolicy: {{ $.Values.global.imagePullPolicy | default "IfNotPresent" }} + command: [ '/bin/sh', '-c' ] + args: [ '{{range $dir := $volume.dataDirs }}if ls /{{$dir.name}}/*.idx >/dev/null 2>&1; then mv /{{$dir.name}}/*.idx /idx/ ; fi; {{end}}' ] + volumeMounts: + - name: idx + mountPath: /idx + {{- range $dir := $volume.dataDirs }} + - name: {{ $dir.name }} + mountPath: /{{ $dir.name }} + {{- end }} + {{- if $volume.containerSecurityContext.enabled }} + securityContext: {{- omit $volume.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + {{- end }} + {{- if $volume.initContainers }} + {{ tpl (printf "{{ $volumeName := \"%s\" }}%s" $volumeName $volume.initContainers) $ | indent 8 | trim }} + {{- end }} + {{- end }} + {{- if $volume.podSecurityContext.enabled }} + securityContext: {{- omit $volume.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: seaweedfs + image: {{ template "volume.image" $ }} + imagePullPolicy: {{ default "IfNotPresent" $.Values.global.imagePullPolicy }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: SEAWEEDFS_FULLNAME + value: "{{ template "seaweedfs.name" $ }}" + {{- if $volume.extraEnvironmentVars }} + {{- range $key, $value := $volume.extraEnvironmentVars }} + - name: {{ $key }} + {{- if kindIs "string" $value }} + value: {{ $value | quote }} + {{- else }} + valueFrom: + {{ toYaml $value | nindent 16 | trim }} + {{- end -}} + {{- end }} + {{- end }} + {{- if $.Values.global.extraEnvironmentVars }} + {{- range $key, $value := $.Values.global.extraEnvironmentVars }} + - name: {{ $key }} + {{- if kindIs "string" $value }} + value: {{ $value | quote }} + {{- else }} + valueFrom: + {{ toYaml $value | nindent 16 | trim }} + {{- end -}} + {{- end }} + {{- end }} + command: + - "/bin/sh" + - "-ec" + - | + exec /usr/bin/weed \ + {{- if $volume.logs }} + -logdir=/logs \ + {{- else }} + -logtostderr=true \ + {{- end }} + {{- if $volume.loggingOverrideLevel }} + -v={{ $volume.loggingOverrideLevel }} \ + {{- else }} + -v={{ $.Values.global.loggingLevel }} \ + {{- end }} + volume \ + -port={{ $volume.port }} \ + {{- if $volume.metricsPort }} + -metricsPort={{ $volume.metricsPort }} \ + {{- end }} + {{- if $volume.metricsIp }} + -metricsIp={{ $volume.metricsIp }} \ + {{- end }} + -dir {{range $index, $dir := $volume.dataDirs }}{{if ne $index 0}},{{end}}/{{$dir.name}}{{end}} \ + {{- if $volume.idx }} + -dir.idx=/idx \ + {{- end }} + -max {{range $index, $dir := $volume.dataDirs }}{{if ne $index 0}},{{end}} + {{- if eq ($dir.maxVolumes | toString) "0" }}0{{ else if not $dir.maxVolumes }}7{{ else }}{{$dir.maxVolumes}}{{ end }} + {{- end }} \ + {{- if $volume.rack }} + -rack={{ $volume.rack }} \ + {{- end }} + {{- if $volume.dataCenter }} + -dataCenter={{ $volume.dataCenter }} \ + {{- end }} + {{- if $volume.id }} + -id={{ $volume.id }} \ + {{- end }} + -ip.bind={{ $volume.ipBind }} \ + -readMode={{ $volume.readMode }} \ + {{- if $volume.whiteList }} + -whiteList={{ $volume.whiteList }} \ + {{- end }} + {{- if $volume.imagesFixOrientation }} + -images.fix.orientation \ + {{- end }} + {{- if $volume.pulseSeconds }} + -pulseSeconds={{ $volume.pulseSeconds }} \ + {{- end }} + {{- if $volume.index }} + -index={{ $volume.index }} \ + {{- end }} + {{- if $volume.fileSizeLimitMB }} + -fileSizeLimitMB={{ $volume.fileSizeLimitMB }} \ + {{- end }} + -minFreeSpacePercent={{ $volume.minFreeSpacePercent }} \ + -ip=${POD_NAME}.${SEAWEEDFS_FULLNAME}-{{ $volumeName }}.{{ $.Release.Namespace }} \ + -compactionMBps={{ $volume.compactionMBps }} \ + -master={{ include "seaweedfs.masterServerArg" $ }} \ + {{- range $volume.extraArgs }} + {{ . }} \ + {{- end }} + volumeMounts: + {{- range $dir := $volume.dataDirs }} + {{- if not ( eq $dir.type "custom" ) }} + - name: {{ $dir.name }} + mountPath: "/{{ $dir.name }}/" + {{- end }} + {{- end }} + {{- if $volume.logs }} + - name: logs + mountPath: "/logs/" + {{- end }} + {{- if $volume.idx }} + - name: idx + mountPath: "/idx/" + {{- end }} + {{- if $.Values.global.enableSecurity }} + - name: security-config + readOnly: true + mountPath: /etc/seaweedfs/security.toml + subPath: security.toml + - name: ca-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/ca/ + - name: master-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/master/ + - name: volume-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/volume/ + - name: filer-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/filer/ + - name: client-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/client/ + {{- end }} + {{ tpl (printf "{{ $volumeName := \"%s\" }}%s" $volumeName $volume.extraVolumeMounts) $ | indent 12 | trim }} + ports: + - containerPort: {{ $volume.port }} + name: swfs-vol + {{- if $volume.metricsPort }} + - containerPort: {{ $volume.metricsPort }} + name: metrics + {{- end }} + - containerPort: {{ $volume.grpcPort }} + name: swfs-vol-grpc + {{- if $volume.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: {{ $volume.readinessProbe.httpGet.path }} + port: {{ $volume.port }} + scheme: {{ $volume.readinessProbe.httpGet.scheme }} + initialDelaySeconds: {{ $volume.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ $volume.readinessProbe.periodSeconds }} + successThreshold: {{ $volume.readinessProbe.successThreshold }} + failureThreshold: {{ $volume.readinessProbe.failureThreshold }} + timeoutSeconds: {{ $volume.readinessProbe.timeoutSeconds }} + {{- end }} + {{- if $volume.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: {{ $volume.livenessProbe.httpGet.path }} + port: {{ $volume.port }} + scheme: {{ $volume.livenessProbe.httpGet.scheme }} + initialDelaySeconds: {{ $volume.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ $volume.livenessProbe.periodSeconds }} + successThreshold: {{ $volume.livenessProbe.successThreshold }} + failureThreshold: {{ $volume.livenessProbe.failureThreshold }} + timeoutSeconds: {{ $volume.livenessProbe.timeoutSeconds }} + {{- end }} + {{- with $volume.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if $volume.containerSecurityContext.enabled }} + securityContext: {{- omit $volume.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + {{- if $volume.sidecars }} + {{- include "common.tplvalues.render" (dict "value" (printf "{{ $volumeName := \"%s\" }}%s" $volumeName $volume.sidecars) "context" $) | nindent 8 }} + {{- end }} + volumes: + + {{- range $dir := $volume.dataDirs }} + + {{- if eq $dir.type "hostPath" }} + - name: {{ $dir.name }} + hostPath: + path: {{ $dir.hostPathPrefix }}/object_store/ + type: DirectoryOrCreate + {{- end }} + {{- if eq $dir.type "existingClaim" }} + - name: {{ $dir.name }} + persistentVolumeClaim: + claimName: {{ $dir.claimName }} + {{- end }} + {{- if eq $dir.type "emptyDir" }} + - name: {{ $dir.name }} + emptyDir: {} + {{- end }} + + {{- end }} + + {{- if $volume.idx }} + {{- if eq $volume.idx.type "hostPath" }} + - name: idx + hostPath: + path: {{ $volume.idx.hostPathPrefix }}/seaweedfs-volume-idx/ + type: DirectoryOrCreate + {{- end }} + {{- if eq $volume.idx.type "existingClaim" }} + - name: idx + persistentVolumeClaim: + claimName: {{ $volume.idx.claimName }} + {{- end }} + {{- if eq $volume.idx.type "emptyDir" }} + - name: idx + emptyDir: {} + {{- end }} + {{- end }} + + {{- if $volume.logs }} + {{- if eq $volume.logs.type "hostPath" }} + - name: logs + hostPath: + path: {{ $volume.logs.hostPathPrefix }}/logs/seaweedfs/volume + type: DirectoryOrCreate + {{- end }} + {{- if eq $volume.logs.type "existingClaim" }} + - name: logs + persistentVolumeClaim: + claimName: {{ $volume.logs.claimName }} + {{- end }} + {{- if eq $volume.logs.type "emptyDir" }} + - name: logs + emptyDir: {} + {{- end }} + {{- end }} + {{- if $.Values.global.enableSecurity }} + - name: security-config + configMap: + name: {{ template "seaweedfs.name" $ }}-security-config + - name: ca-cert + secret: + secretName: {{ template "seaweedfs.name" $ }}-ca-cert + - name: master-cert + secret: + secretName: {{ template "seaweedfs.name" $ }}-master-cert + - name: volume-cert + secret: + secretName: {{ template "seaweedfs.name" $ }}-volume-cert + - name: filer-cert + secret: + secretName: {{ template "seaweedfs.name" $ }}-filer-cert + - name: client-cert + secret: + secretName: {{ template "seaweedfs.name" $ }}-client-cert + {{- end }} + {{- if $volume.extraVolumes }} + {{ tpl $volume.extraVolumes $ | indent 8 | trim }} + {{- end }} + {{- if $volume.nodeSelector }} + nodeSelector: + {{ tpl (printf "{{ $volumeName := \"%s\" }}%s" $volumeName $volume.nodeSelector) $ | indent 8 | trim }} + {{- end }} + volumeClaimTemplates: + {{- range $dir := $volume.dataDirs }} + {{- if eq $dir.type "persistentVolumeClaim" }} + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: {{ $dir.name }} + {{- with $dir.annotations }} + annotations: + {{- toYaml . | nindent 10 }} + {{- end }} + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: {{ $dir.storageClass }} + resources: + requests: + storage: {{ $dir.size }} + {{- end }} + {{- end }} + + {{- if and $volume.idx (eq $volume.idx.type "persistentVolumeClaim") }} + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: idx + {{- with $volume.idx.annotations }} + annotations: + {{- toYaml . | nindent 10 }} + {{- end }} + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: {{ $volume.idx.storageClass }} + resources: + requests: + storage: {{ $volume.idx.size }} + {{- end }} + {{- if and $volume.logs (eq $volume.logs.type "persistentVolumeClaim") }} + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: logs + {{- with $volume.logs.annotations }} + annotations: + {{- toYaml . | nindent 10 }} + {{- end }} + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: {{ $volume.logs.storageClass }} + resources: + requests: + storage: {{ $volume.logs.size }} + {{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-deployment.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-deployment.yaml new file mode 100644 index 00000000..7a6e0524 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-deployment.yaml @@ -0,0 +1,288 @@ +{{- if .Values.worker.enabled }} +{{- if and (not .Values.worker.adminServer) (not .Values.admin.enabled) }} +{{- fail "worker.adminServer must be set if admin.enabled is false within the same release" -}} +{{- end }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "seaweedfs.name" . }}-worker + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker +{{- if .Values.worker.annotations }} + annotations: + {{- toYaml .Values.worker.annotations | nindent 4 }} +{{- end }} +spec: + replicas: {{ .Values.worker.replicas }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker + {{ with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.worker.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + annotations: + {{ with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.worker.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + restartPolicy: {{ default .Values.global.restartPolicy .Values.worker.restartPolicy }} + {{- if .Values.worker.affinity }} + affinity: + {{ tpl .Values.worker.affinity . | nindent 8 | trim }} + {{- end }} + {{- if .Values.worker.topologySpreadConstraints }} + topologySpreadConstraints: + {{ tpl .Values.worker.topologySpreadConstraints . | nindent 8 | trim }} + {{- end }} + {{- if .Values.worker.tolerations }} + tolerations: + {{ tpl .Values.worker.tolerations . | nindent 8 | trim }} + {{- end }} + {{- include "seaweedfs.imagePullSecrets" . | nindent 6 }} + terminationGracePeriodSeconds: 60 + {{- if .Values.worker.priorityClassName }} + priorityClassName: {{ .Values.worker.priorityClassName | quote }} + {{- end }} + enableServiceLinks: false + {{- if .Values.worker.serviceAccountName }} + serviceAccountName: {{ .Values.worker.serviceAccountName | quote }} + {{- end }} + {{- if .Values.worker.initContainers }} + initContainers: + {{ tpl .Values.worker.initContainers . | nindent 8 | trim }} + {{- end }} + {{- if .Values.worker.podSecurityContext.enabled }} + securityContext: {{- omit .Values.worker.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: seaweedfs + image: {{ template "worker.image" . }} + imagePullPolicy: {{ default "IfNotPresent" .Values.global.imagePullPolicy }} + env: + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SEAWEEDFS_FULLNAME + value: "{{ template "seaweedfs.name" . }}" + {{- if .Values.worker.extraEnvironmentVars }} + {{- range $key, $value := .Values.worker.extraEnvironmentVars }} + - name: {{ $key }} + {{- if kindIs "string" $value }} + value: {{ $value | quote }} + {{- else }} + valueFrom: + {{ toYaml $value | nindent 16 | trim }} + {{- end -}} + {{- end }} + {{- end }} + {{- if .Values.global.extraEnvironmentVars }} + {{- range $key, $value := .Values.global.extraEnvironmentVars }} + - name: {{ $key }} + {{- if kindIs "string" $value }} + value: {{ $value | quote }} + {{- else }} + valueFrom: + {{ toYaml $value | nindent 16 | trim }} + {{- end -}} + {{- end }} + {{- end }} + command: + - "/bin/sh" + - "-ec" + - | + exec /usr/bin/weed \ + {{- if or (eq .Values.worker.logs.type "hostPath") (eq .Values.worker.logs.type "emptyDir") (eq .Values.worker.logs.type "existingClaim") }} + -logdir=/logs \ + {{- else }} + -logtostderr=true \ + {{- end }} + {{- if .Values.worker.loggingOverrideLevel }} + -v={{ .Values.worker.loggingOverrideLevel }} \ + {{- else }} + -v={{ .Values.global.loggingLevel }} \ + {{- end }} + worker \ + {{- if .Values.worker.adminServer }} + -admin={{ .Values.worker.adminServer }} \ + {{- else }} + -admin={{ template "seaweedfs.name" . }}-admin.{{ .Release.Namespace }}:{{ .Values.admin.port }}{{ if .Values.admin.grpcPort }}.{{ .Values.admin.grpcPort }}{{ end }} \ + {{- end }} + -capabilities={{ .Values.worker.capabilities }} \ + -maxConcurrent={{ .Values.worker.maxConcurrent }} \ + -workingDir={{ .Values.worker.workingDir }}{{- if or .Values.worker.metricsPort .Values.worker.extraArgs }} \{{ end }} + {{- if .Values.worker.metricsPort }} + -metricsPort={{ .Values.worker.metricsPort }}{{- if .Values.worker.extraArgs }} \{{ end }} + {{- end }} + {{- range $index, $arg := .Values.worker.extraArgs }} + {{ $arg }}{{- if lt $index (sub (len $.Values.worker.extraArgs) 1) }} \{{ end }} + {{- end }} + volumeMounts: + {{- if or (eq .Values.worker.data.type "hostPath") (eq .Values.worker.data.type "emptyDir") (eq .Values.worker.data.type "existingClaim") }} + - name: worker-data + mountPath: {{ .Values.worker.workingDir }} + {{- end }} + {{- if or (eq .Values.worker.logs.type "hostPath") (eq .Values.worker.logs.type "emptyDir") (eq .Values.worker.logs.type "existingClaim") }} + - name: worker-logs + mountPath: /logs + {{- end }} + {{- if .Values.global.enableSecurity }} + - name: security-config + readOnly: true + mountPath: /etc/seaweedfs/security.toml + subPath: security.toml + - name: ca-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/ca/ + - name: master-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/master/ + - name: volume-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/volume/ + - name: filer-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/filer/ + - name: client-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/client/ + - name: worker-cert + readOnly: true + mountPath: /usr/local/share/ca-certificates/worker/ + {{- end }} + {{ tpl .Values.worker.extraVolumeMounts . | nindent 12 | trim }} + ports: + {{- if .Values.worker.metricsPort }} + - containerPort: {{ .Values.worker.metricsPort }} + name: metrics + {{- end }} + {{- with .Values.worker.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if .Values.worker.livenessProbe.enabled }} + livenessProbe: + {{- if .Values.worker.livenessProbe.httpGet }} + httpGet: + path: {{ .Values.worker.livenessProbe.httpGet.path }} + port: {{ .Values.worker.livenessProbe.httpGet.port }} + {{- else if .Values.worker.livenessProbe.tcpSocket }} + tcpSocket: + port: {{ .Values.worker.livenessProbe.tcpSocket.port }} + {{- end }} + initialDelaySeconds: {{ .Values.worker.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.worker.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.worker.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.worker.livenessProbe.failureThreshold }} + timeoutSeconds: {{ .Values.worker.livenessProbe.timeoutSeconds }} + {{- end }} + {{- if .Values.worker.readinessProbe.enabled }} + readinessProbe: + {{- if .Values.worker.readinessProbe.httpGet }} + httpGet: + path: {{ .Values.worker.readinessProbe.httpGet.path }} + port: {{ .Values.worker.readinessProbe.httpGet.port }} + {{- else if .Values.worker.readinessProbe.tcpSocket }} + tcpSocket: + port: {{ .Values.worker.readinessProbe.tcpSocket.port }} + {{- end }} + initialDelaySeconds: {{ .Values.worker.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.worker.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.worker.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.worker.readinessProbe.failureThreshold }} + timeoutSeconds: {{ .Values.worker.readinessProbe.timeoutSeconds }} + {{- end }} + {{- if .Values.worker.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.worker.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.worker.sidecars }} + {{- include "common.tplvalues.render" (dict "value" .Values.worker.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + {{- if eq .Values.worker.data.type "hostPath" }} + - name: worker-data + hostPath: + path: {{ .Values.worker.data.hostPathPrefix }}/seaweedfs-worker-data + type: DirectoryOrCreate + {{- end }} + {{- if eq .Values.worker.data.type "emptyDir" }} + - name: worker-data + emptyDir: {} + {{- end }} + {{- if eq .Values.worker.data.type "existingClaim" }} + - name: worker-data + persistentVolumeClaim: + claimName: {{ .Values.worker.data.claimName }} + {{- end }} + {{- if eq .Values.worker.logs.type "hostPath" }} + - name: worker-logs + hostPath: + path: {{ .Values.worker.logs.hostPathPrefix }}/logs/seaweedfs/worker + type: DirectoryOrCreate + {{- end }} + {{- if eq .Values.worker.logs.type "emptyDir" }} + - name: worker-logs + emptyDir: {} + {{- end }} + {{- if eq .Values.worker.logs.type "existingClaim" }} + - name: worker-logs + persistentVolumeClaim: + claimName: {{ .Values.worker.logs.claimName }} + {{- end }} + {{- if .Values.global.enableSecurity }} + - name: security-config + configMap: + name: {{ template "seaweedfs.name" . }}-security-config + - name: ca-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-ca-cert + - name: master-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-master-cert + - name: volume-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-volume-cert + - name: filer-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-filer-cert + - name: client-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-client-cert + - name: worker-cert + secret: + secretName: {{ template "seaweedfs.name" . }}-worker-cert + {{- end }} + {{ tpl .Values.worker.extraVolumes . | indent 8 | trim }} + {{- if .Values.worker.nodeSelector }} + nodeSelector: + {{ tpl .Values.worker.nodeSelector . | indent 8 | trim }} + {{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-service.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-service.yaml new file mode 100644 index 00000000..cf9885e2 --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-service.yaml @@ -0,0 +1,26 @@ +{{- if .Values.worker.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "seaweedfs.name" . }}-worker + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker +spec: + clusterIP: None # Headless service + {{- if .Values.worker.metricsPort }} + ports: + - name: "metrics" + port: {{ .Values.worker.metricsPort }} + targetPort: {{ .Values.worker.metricsPort }} + protocol: TCP + {{- end }} + selector: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-servicemonitor.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-servicemonitor.yaml new file mode 100644 index 00000000..7f9590da --- /dev/null +++ b/packages/system/seaweedfs/charts/seaweedfs/templates/worker/worker-servicemonitor.yaml @@ -0,0 +1,33 @@ +{{- if .Values.worker.enabled }} +{{- if .Values.worker.metricsPort }} +{{- if .Values.global.monitoring.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "seaweedfs.name" . }}-worker + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker + {{- with .Values.global.monitoring.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- with .Values.worker.serviceMonitor.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + endpoints: + - interval: 30s + port: metrics + scrapeTimeout: 5s + selector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/component: worker +{{- end }} +{{- end }} +{{- end }} diff --git a/packages/system/seaweedfs/charts/seaweedfs/values.yaml b/packages/system/seaweedfs/charts/seaweedfs/values.yaml index 3aecc5a7..c51b86e6 100644 --- a/packages/system/seaweedfs/charts/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/charts/seaweedfs/values.yaml @@ -3,6 +3,7 @@ global: createClusterRole: true registry: "" + # if repository is set, it overrides the namespace part of imageName repository: "" imageName: chrislusf/seaweedfs imagePullPolicy: IfNotPresent @@ -21,19 +22,21 @@ global: serviceAccountName: "seaweedfs" automountServiceAccountToken: true certificates: + duration: 87600h + renewBefore: 720h alphacrds: false monitoring: enabled: false gatewayHost: null gatewayPort: null additionalLabels: {} - # if enabled will use global.replicationPlacment and override master & filer defaultReplicaPlacement config + # if enabled will use global.replicationPlacement and override master & filer defaultReplicaPlacement config enableReplication: false # replication type is XYZ: # X number of replica in other data centers # Y number of replica in other racks in the same data center # Z number of replica in other servers in the same rack - replicationPlacment: "001" + replicationPlacement: "001" extraEnvironmentVars: WEED_CLUSTER_DEFAULT: "sw" WEED_CLUSTER_SW_MASTER: "seaweedfs-master.seaweedfs:9333" @@ -46,6 +49,7 @@ global: image: registry: "" repository: "" + tag: "" master: enabled: true @@ -55,12 +59,11 @@ master: port: 9333 grpcPort: 19333 metricsPort: 9327 + metricsIp: "" # Metrics listen IP. If empty, defaults to ipBind ipBind: "0.0.0.0" volumePreallocate: false volumeSizeLimitMB: 1000 loggingOverrideLevel: null - # number of seconds between heartbeats, default 5 - pulseSeconds: null # threshold to vacuum and reclaim spaces, default 0.3 (30%) garbageThreshold: null # Prometheus push interval in seconds, default 15 @@ -74,6 +77,25 @@ master: # Disable http request, only gRpc operations are allowed disableHttp: false + # Resume previous state on start master server + resumeState: false + # Use Hashicorp Raft + raftHashicorp: false + # Whether to bootstrap the Raft cluster. Only use it when use Hashicorp Raft + raftBootstrap: false + + # election timeout of master servers + electionTimeout: "10s" + # heartbeat interval of master servers, and will be randomly multiplied by [1, 1.25) + heartbeatInterval: "300ms" + + # Custom command line arguments to add to the master command + # Example to fix IPv6 metrics connectivity issues: + # extraArgs: ["-metricsIp", "0.0.0.0"] + # Example with multiple args: + # extraArgs: ["-customFlag", "value", "-anotherFlag"] + extraArgs: [] + config: |- # Enter any extra configuration for master.toml here. # It may be a multi-line string. @@ -100,6 +122,15 @@ master: storageClass: "" hostPathPrefix: /ssd + # You may use ANY storage-class, example with local-path-provisioner + # Annotations are optional. + # logs: + # type: "persistentVolumeClaim" + # size: "24Ti" + # storageClass: "local-path-provisioner" + # annotations: + # "key": "value" + # You can also use emptyDir storage: # logs: # type: "emptyDir" @@ -131,6 +162,9 @@ master: # Annotations to be added to the master pods podAnnotations: {} + # Annotations to be added to the master resources + annotations: {} + ## Set podManagementPolicy podManagementPolicy: Parallel @@ -157,6 +191,11 @@ master: app.kubernetes.io/component: master topologyKey: kubernetes.io/hostname + # Topology Spread Constraints Settings + # This should map directly to the value of the topologySpreadConstraints + # for a PodSpec. By Default no constraints are set. + topologySpreadConstraints: "" + # Toleration Settings for master pods # This should be a multi-line string matching the Toleration array # in a PodSpec. @@ -165,8 +204,7 @@ master: # nodeSelector labels for master pod assignment, formatted as a muli-line string. # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector # Example: - nodeSelector: | - kubernetes.io/arch: amd64 + nodeSelector: "" # nodeSelector: | # sw-backend: "true" @@ -199,25 +237,27 @@ master: ingress: enabled: false - className: "nginx" + className: "" # host: false for "*" hostname host: "master.seaweedfs.local" - annotations: - nginx.ingress.kubernetes.io/auth-type: "basic" - nginx.ingress.kubernetes.io/auth-secret: "default/ingress-basic-auth-secret" - nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - SW-Master' - nginx.ingress.kubernetes.io/service-upstream: "true" - nginx.ingress.kubernetes.io/rewrite-target: /$1 - nginx.ingress.kubernetes.io/use-regex: "true" - nginx.ingress.kubernetes.io/enable-rewrite-log: "true" - nginx.ingress.kubernetes.io/ssl-redirect: "false" - nginx.ingress.kubernetes.io/force-ssl-redirect: "false" - nginx.ingress.kubernetes.io/configuration-snippet: | - sub_filter '' ' '; #add base url - sub_filter '="/' '="./'; #make absolute paths to relative - sub_filter '=/' '=./'; - sub_filter '/seaweedfsstatic' './seaweedfsstatic'; - sub_filter_once off; + path: "/sw-master/?(.*)" + pathType: ImplementationSpecific + annotations: {} + # nginx.ingress.kubernetes.io/auth-type: "basic" + # nginx.ingress.kubernetes.io/auth-secret: "default/ingress-basic-auth-secret" + # nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - SW-Master' + # nginx.ingress.kubernetes.io/service-upstream: "true" + # nginx.ingress.kubernetes.io/rewrite-target: /$1 + # nginx.ingress.kubernetes.io/use-regex: "true" + # nginx.ingress.kubernetes.io/enable-rewrite-log: "true" + # nginx.ingress.kubernetes.io/ssl-redirect: "false" + # nginx.ingress.kubernetes.io/force-ssl-redirect: "false" + # nginx.ingress.kubernetes.io/configuration-snippet: | + # sub_filter '' ' '; #add base url + # sub_filter '="/' '="./'; #make absolute paths to relative + # sub_filter '=/' '=./'; + # sub_filter '/seaweedfsstatic' './seaweedfsstatic'; + # sub_filter_once off; tls: [] extraEnvironmentVars: @@ -259,6 +299,7 @@ volume: port: 8080 grpcPort: 18080 metricsPort: 9327 + metricsIp: "" # Metrics listen IP. If empty, defaults to ipBind ipBind: "0.0.0.0" replicas: 1 loggingOverrideLevel: null @@ -269,12 +310,19 @@ volume: # limit file size to avoid out of memory, default 256mb fileSizeLimitMB: null # minimum free disk space(in percents). If free disk space lower this value - all volumes marks as ReadOnly - minFreeSpacePercent: 7 + minFreeSpacePercent: 1 + + # Custom command line arguments to add to the volume command + # Example to fix IPv6 metrics connectivity issues: + # extraArgs: ["-metricsIp", "0.0.0.0"] + # Example with multiple args: + # extraArgs: ["-customFlag", "value", "-anotherFlag"] + extraArgs: [] # For each data disk you may use ANY storage-class, example with local-path-provisioner # Annotations are optional. # dataDirs: - # - name: data: + # - name: data # type: "persistentVolumeClaim" # size: "24Ti" # storageClass: "local-path-provisioner" @@ -292,6 +340,12 @@ volume: # - name: data # type: "emptyDir" # maxVolumes: 0 # If set to zero on non-windows OS, the limit will be auto configured. (default "7") + # + # If these don't meet your needs, you can use "custom" here along with extraVolumes and extraVolumeMounts + # Particularly useful when using more than 1 for the volume server replicas. + # - name: data + # type: "custom" + # maxVolumes: 0 # If set to zero on non-windows OS, the limit will be auto configured. (default "7") dataDirs: - name: data1 @@ -308,7 +362,7 @@ volume: # This will automatically create a job for patching Kubernetes resources if the dataDirs type is 'persistentVolumeClaim' and the size has changed. resizeHook: enabled: true - image: bitnami/kubectl + image: alpine/k8s:1.28.4 # idx can be defined by: # @@ -347,6 +401,10 @@ volume: # Volume server's rack name rack: null + # Stable identifier for the volume server, independent of IP address + # Useful for Kubernetes environments with hostPath volumes to maintain stable identity + id: null + # Volume server's data center name dataCenter: null @@ -372,6 +430,15 @@ volume: sidecars: [] initContainers: "" + # Example for use when using more than 1 volume server replica + # extraVolumeMounts: | + # - name: drive + # mountPath: /drive + # subPathExpr: $(POD_NAME) + # extraVolumes: | + # - name: drive + # hostPath: + # path: /var/mnt/ extraVolumes: "" extraVolumeMounts: "" @@ -381,6 +448,9 @@ volume: # Annotations to be added to the volume pods podAnnotations: {} + # Annotations to be added to the volume resources + annotations: {} + ## Set podManagementPolicy podManagementPolicy: Parallel @@ -394,9 +464,14 @@ volume: matchLabels: app.kubernetes.io/name: {{ template "seaweedfs.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/component: volume + app.kubernetes.io/component: {{ $volumeName }} topologyKey: kubernetes.io/hostname + # Topology Spread Constraints Settings + # This should map directly to the value of the topologySpreadConstraints + # for a PodSpec. By Default no constraints are set. + topologySpreadConstraints: "" + # Resource requests, limits, etc. for the server cluster placement. This # should map directly to the value of the resources field for a PodSpec, # formatted as a multi-line string. By default no direct resource request @@ -411,8 +486,7 @@ volume: # nodeSelector labels for server pod assignment, formatted as a muli-line string. # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector # Example: - nodeSelector: | - kubernetes.io/arch: amd64 + nodeSelector: "" # nodeSelector: | # sw-volume: "true" @@ -450,7 +524,7 @@ volume: livenessProbe: enabled: true httpGet: - path: /status + path: /healthz scheme: HTTP initialDelaySeconds: 20 periodSeconds: 90 @@ -463,7 +537,7 @@ volume: readinessProbe: enabled: true httpGet: - path: /status + path: /healthz scheme: HTTP initialDelaySeconds: 15 periodSeconds: 15 @@ -471,6 +545,31 @@ volume: failureThreshold: 100 timeoutSeconds: 30 +# Map of named volume groups for topology-aware deployments. +# Each key inherits all fields from the `volume` section but can override +# them locally—for example, replicas, nodeSelector, dataCenter, etc. +# To switch entirely to this scheme, set `volume.enabled: false` +# and define one entry per zone/data-center under `volumes`. +# +# volumes: +# dc1: +# replicas: 2 +# dataCenter: "dc1" +# nodeSelector: | +# topology.kubernetes.io/zone: dc1 +# dc2: +# replicas: 2 +# dataCenter: "dc2" +# nodeSelector: | +# topology.kubernetes.io/zone: dc2 +# dc3: +# replicas: 2 +# dataCenter: "dc3" +# nodeSelector: | +# topology.kubernetes.io/zone: dc3 +# +volumes: {} + filer: enabled: true imageOverride: null @@ -479,8 +578,14 @@ filer: port: 8888 grpcPort: 18888 metricsPort: 9327 + metricsIp: "" # Metrics listen IP. If empty, defaults to ipBind + ipBind: "0.0.0.0" # IP address to bind to. Set to 0.0.0.0 to allow external traffic loggingOverrideLevel: null filerGroup: "" + # prefer to read and write to volumes in this data center (not set by default) + dataCenter: null + # prefer to write to volumes in this rack (not set by default) + rack: null # replication type is XYZ: # X number of replica in other data centers # Y number of replica in other racks in the same data center @@ -502,6 +607,26 @@ filer: # Disable http request, only gRpc operations are allowed disableHttp: false + # Custom command line arguments to add to the filer command + # Example to fix IPv6 metrics connectivity issues: + # extraArgs: ["-metricsIp", "0.0.0.0"] + # Example with multiple args: + # extraArgs: ["-customFlag", "value", "-anotherFlag"] + extraArgs: [] + + # Add a custom notification.toml to configure filer notifications + # Example: + # notificationConfig: |- + # [notification.kafka] + # enabled = false + # hosts = [ + # "localhost:9092" + # ] + # topic = "seaweedfs_filer" + # offsetFile = "./last.offset" + # offsetSaveIntervalSeconds = 10 + notificationConfig: "" + # DEPRECATE: enablePVC, storage, storageClass # Consider replacing with filer.data section below instead. @@ -535,6 +660,15 @@ filer: storageClass: "" hostPathPrefix: /storage + # You may use ANY storage-class, example with local-path-provisioner + # Annotations are optional. + # logs: + # type: "persistentVolumeClaim" + # size: "24Ti" + # storageClass: "local-path-provisioner" + # annotations: + # "key": "value" + # You can also use emptyDir storage: # logs: # type: "emptyDir" @@ -566,6 +700,9 @@ filer: # Annotations to be added to the filer pods podAnnotations: {} + # Annotations to be added to the filer resource + annotations: {} + ## Set podManagementPolicy podManagementPolicy: Parallel @@ -582,6 +719,11 @@ filer: app.kubernetes.io/component: filer topologyKey: kubernetes.io/hostname + # Topology Spread Constraints Settings + # This should map directly to the value of the topologySpreadConstraints + # for a PodSpec. By Default no constraints are set. + topologySpreadConstraints: "" + # updatePartition is used to control a careful rolling update of SeaweedFS # masters. updatePartition: 0 @@ -600,8 +742,7 @@ filer: # nodeSelector labels for server pod assignment, formatted as a muli-line string. # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector # Example: - nodeSelector: | - kubernetes.io/arch: amd64 + nodeSelector: "" # nodeSelector: | # sw-backend: "true" @@ -634,28 +775,30 @@ filer: ingress: enabled: false - className: "nginx" + className: "" # host: false for "*" hostname host: "seaweedfs.cluster.local" - annotations: - nginx.ingress.kubernetes.io/backend-protocol: GRPC - nginx.ingress.kubernetes.io/auth-type: "basic" - nginx.ingress.kubernetes.io/auth-secret: "default/ingress-basic-auth-secret" - nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - SW-Filer' - nginx.ingress.kubernetes.io/service-upstream: "true" - nginx.ingress.kubernetes.io/rewrite-target: /$1 - nginx.ingress.kubernetes.io/use-regex: "true" - nginx.ingress.kubernetes.io/enable-rewrite-log: "true" - nginx.ingress.kubernetes.io/ssl-redirect: "false" - nginx.ingress.kubernetes.io/force-ssl-redirect: "false" - nginx.ingress.kubernetes.io/configuration-snippet: | - sub_filter '' ' '; #add base url - sub_filter '="/' '="./'; #make absolute paths to relative - sub_filter '=/' '=./'; - sub_filter '/seaweedfsstatic' './seaweedfsstatic'; - sub_filter_once off; + path: "/sw-filer/?(.*)" + pathType: ImplementationSpecific + annotations: {} + # nginx.ingress.kubernetes.io/backend-protocol: GRPC + # nginx.ingress.kubernetes.io/auth-type: "basic" + # nginx.ingress.kubernetes.io/auth-secret: "default/ingress-basic-auth-secret" + # nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - SW-Filer' + # nginx.ingress.kubernetes.io/service-upstream: "true" + # nginx.ingress.kubernetes.io/rewrite-target: /$1 + # nginx.ingress.kubernetes.io/use-regex: "true" + # nginx.ingress.kubernetes.io/enable-rewrite-log: "true" + # nginx.ingress.kubernetes.io/ssl-redirect: "false" + # nginx.ingress.kubernetes.io/force-ssl-redirect: "false" + # nginx.ingress.kubernetes.io/configuration-snippet: | + # sub_filter '' ' '; #add base url + # sub_filter '="/' '="./'; #make absolute paths to relative + # sub_filter '=/' '=./'; + # sub_filter '/seaweedfsstatic' './seaweedfsstatic'; + # sub_filter_once off; - # extraEnvVars is a list of extra enviroment variables to set with the stateful set. + # extraEnvVars is a list of extra environment variables to set with the stateful set. extraEnvironmentVars: WEED_MYSQL_ENABLED: "false" WEED_MYSQL_HOSTNAME: "mysql-db-host" @@ -717,8 +860,6 @@ filer: port: 8333 # add additional https port httpsPort: 0 - # allow empty folders - allowEmptyFolder: false # Suffix of the host name, {bucket}.{domainName} domainName: "" # enable user & permission to s3 (need to inject to all services) @@ -746,8 +887,6 @@ s3: httpsPort: 0 metricsPort: 9327 loggingOverrideLevel: null - # allow empty folders - allowEmptyFolder: true # enable user & permission to s3 (need to inject to all services) enableAuth: false # set to the name of an existing kubernetes Secret with the s3 json config file @@ -780,6 +919,9 @@ s3: # Annotations to be added to the s3 pods podAnnotations: {} + # Annotations to be added to the s3 resources + annotations: {} + # Resource requests, limits, etc. for the server cluster placement. This # should map directly to the value of the resources field for a PodSpec, # formatted as a multi-line string. By default no direct resource request @@ -794,8 +936,7 @@ s3: # nodeSelector labels for server pod assignment, formatted as a muli-line string. # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector # Example: - nodeSelector: | - kubernetes.io/arch: amd64 + nodeSelector: "" # nodeSelector: | # sw-backend: "true" @@ -837,6 +978,11 @@ s3: extraEnvironmentVars: + # Custom command line arguments to add to the s3 command + # Default idleTimeout is 120 seconds. Example to customize: + # extraArgs: ["-idleTimeout=300"] + extraArgs: [] + # used to configure livenessProbe on s3 containers # livenessProbe: @@ -865,26 +1011,554 @@ s3: ingress: enabled: false - className: "nginx" - # host: false for "*" hostname + className: "" + # host: false for "*" hostname, or an array for multiple hostnames host: "seaweedfs.cluster.local" + path: "/" + pathType: Prefix # additional ingress annotations for the s3 endpoint annotations: {} tls: [] +sftp: + enabled: false + imageOverride: null + restartPolicy: null + replicas: 1 + bindAddress: 0.0.0.0 + port: 2022 # Default SFTP port + metricsPort: 9327 + metricsIp: "" # If empty, defaults to bindAddress + loggingOverrideLevel: null + + # SSH server configuration + sshPrivateKey: "/etc/sw/seaweedfs_sftp_ssh_private_key" # Path to the SSH private key file for host authentication + hostKeysFolder: "/etc/sw/ssh" # path to folder containing SSH private key files for host authentication + authMethods: "password,publickey" # Comma-separated list of allowed auth methods: password, publickey, keyboard-interactive + maxAuthTries: 6 # Maximum number of authentication attempts per connection + bannerMessage: "SeaweedFS SFTP Server" # Message displayed before authentication + loginGraceTime: "2m" # Timeout for authentication + clientAliveInterval: "5s" # Interval for sending keep-alive messages + clientAliveCountMax: 3 # Maximum number of missed keep-alive messages before disconnecting + dataCenter: "" # Prefer to read and write to volumes in this data center + localSocket: "" # Default to /tmp/seaweedfs-sftp-.sock + + # User authentication + enableAuth: false + # Set to the name of an existing kubernetes Secret with the sftp json config file + # Should have a secret key called seaweedfs_sftp_config with an inline json config + existingConfigSecret: null + # Set to the name of an existing kubernetes Secret with the list of ssh private keys for sftp + existingSshConfigSecret: null + + # Additional resources + sidecars: [] + initContainers: "" + extraVolumes: "" + extraVolumeMounts: "" + podLabels: {} + podAnnotations: {} + annotations: {} + resources: {} + tolerations: "" + nodeSelector: "" + priorityClassName: "" + serviceAccountName: "" + podSecurityContext: {} + containerSecurityContext: {} + + logs: + type: "hostPath" + hostPathPrefix: /storage + + extraEnvironmentVars: {} + + # Health checks + # Health checks for SFTP - using tcpSocket instead of httpGet + livenessProbe: + enabled: true + initialDelaySeconds: 20 + periodSeconds: 60 + successThreshold: 1 + failureThreshold: 20 + timeoutSeconds: 10 + + # Health checks for SFTP - using tcpSocket instead of httpGet + readinessProbe: + enabled: true + initialDelaySeconds: 15 + periodSeconds: 15 + successThreshold: 1 + failureThreshold: 100 + timeoutSeconds: 10 + +admin: + enabled: false + imageOverride: null + restartPolicy: null + replicas: 1 + port: 23646 # Default admin port + grpcPort: 33646 # Default gRPC port for worker connections + metricsPort: 9327 + loggingOverrideLevel: null + + # Admin authentication + secret: + # Name of an existing secret containing admin credentials. If set, adminUser and adminPassword below are ignored. + existingSecret: "" + # Key in the existing secret for the admin username. Required if existingSecret is set. + userKey: "" + # Key in the existing secret for the admin password. Required if existingSecret is set. + pwKey: "" + adminUser: "admin" + adminPassword: "" # If empty, authentication is disabled. + + # Data directory for admin configuration and maintenance data + dataDir: "" # If empty, configuration is kept in memory only + + # Master servers to connect to + # If empty, uses global.masterServer or auto-discovers from master statefulset + masters: "" + + # Custom command line arguments to add to the admin command + # Example: ["-customFlag", "value", "-anotherFlag"] + extraArgs: [] + + # Storage configuration + data: + type: "emptyDir" # Options: "hostPath", "persistentVolumeClaim", "emptyDir", "existingClaim" + size: "10Gi" + storageClass: "" + hostPathPrefix: /storage + claimName: "" + annotations: {} + + logs: + type: "emptyDir" # Options: "hostPath", "persistentVolumeClaim", "emptyDir", "existingClaim" + size: "5Gi" + storageClass: "" + hostPathPrefix: /storage + claimName: "" + annotations: {} + + # Additional resources + sidecars: [] + initContainers: "" + extraVolumes: "" + extraVolumeMounts: "" + podLabels: {} + podAnnotations: {} + annotations: {} + + ## Set podManagementPolicy + podManagementPolicy: Parallel + + # Affinity Settings + # Commenting out or setting as empty the affinity variable, will allow + # deployment to single node services such as Minikube + affinity: | + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: admin + topologyKey: kubernetes.io/hostname + + # Topology Spread Constraints Settings + # This should map directly to the value of the topologySpreadConstraints + # for a PodSpec. By Default no constraints are set. + topologySpreadConstraints: "" + + resources: {} + tolerations: "" + nodeSelector: "" + priorityClassName: "" + serviceAccountName: "" + podSecurityContext: {} + containerSecurityContext: {} + + extraEnvironmentVars: {} + + # Health checks + livenessProbe: + enabled: true + httpGet: + path: /health + scheme: HTTP + initialDelaySeconds: 20 + periodSeconds: 60 + successThreshold: 1 + failureThreshold: 5 + timeoutSeconds: 10 + + readinessProbe: + enabled: true + httpGet: + path: /health + scheme: HTTP + initialDelaySeconds: 15 + periodSeconds: 15 + successThreshold: 1 + failureThreshold: 3 + timeoutSeconds: 10 + + ingress: + enabled: false + className: "nginx" + # host: false for "*" hostname + host: "admin.seaweedfs.local" + path: "/" + pathType: Prefix + annotations: {} + tls: [] + + service: + type: ClusterIP + annotations: {} + + # ServiceMonitor annotations (separate from pod/deployment annotations) + serviceMonitor: + annotations: {} + +worker: + enabled: false + imageOverride: null + restartPolicy: null + replicas: 1 + loggingOverrideLevel: null + metricsPort: 9327 + + # Admin server to connect to + adminServer: "" + + + # Worker capabilities - comma-separated list + # Available: vacuum, balance, erasure_coding + # Default: "vacuum,balance,erasure_coding" (all capabilities) + capabilities: "vacuum,balance,erasure_coding" + + # Maximum number of concurrent tasks + maxConcurrent: 3 + + # Working directory for task execution + workingDir: "/tmp/seaweedfs-worker" + + # Custom command line arguments to add to the worker command + # Example: ["-customFlag", "value", "-anotherFlag"] + extraArgs: [] + + # Storage configuration for working directory + # Note: Workers use Deployment, so use "emptyDir", "hostPath", or "existingClaim" + # Do NOT use "persistentVolumeClaim" - use "existingClaim" with pre-provisioned PVC instead + data: + type: "emptyDir" # Options: "hostPath", "emptyDir", "existingClaim" + hostPathPrefix: /storage + claimName: "" # For existingClaim type + + logs: + type: "emptyDir" # Options: "hostPath", "emptyDir", "existingClaim" + hostPathPrefix: /storage + claimName: "" # For existingClaim type + + # Additional resources + sidecars: [] + initContainers: "" + extraVolumes: "" + extraVolumeMounts: "" + podLabels: {} + podAnnotations: {} + annotations: {} + + # Affinity Settings + # Commenting out or setting as empty the affinity variable, will allow + # deployment to single node services such as Minikube + affinity: | + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: worker + topologyKey: kubernetes.io/hostname + + # Topology Spread Constraints Settings + # This should map directly to the value of the topologySpreadConstraints + # for a PodSpec. By Default no constraints are set. + topologySpreadConstraints: "" + + resources: + requests: + cpu: "500m" + memory: "512Mi" + limits: + cpu: "2" + memory: "2Gi" + tolerations: "" + nodeSelector: "" + priorityClassName: "" + serviceAccountName: "" + podSecurityContext: {} + containerSecurityContext: {} + + extraEnvironmentVars: {} + + # Health checks for worker pods + # Workers expose /health (liveness) and /ready (readiness) endpoints on the metricsPort + livenessProbe: + enabled: true + httpGet: + path: /health + port: metrics + initialDelaySeconds: 30 + periodSeconds: 60 + successThreshold: 1 + failureThreshold: 5 + timeoutSeconds: 10 + + readinessProbe: + enabled: true + httpGet: + path: /ready + port: metrics + initialDelaySeconds: 20 + periodSeconds: 15 + successThreshold: 1 + failureThreshold: 3 + timeoutSeconds: 10 + + # ServiceMonitor annotations (separate from pod/deployment annotations) + serviceMonitor: + annotations: {} + +# All-in-one deployment configuration +allInOne: + enabled: false + imageOverride: null + restartPolicy: Always + replicas: 1 # Number of replicas (note: multiple replicas may require shared storage) + + # Core configuration + idleTimeout: 30 # Connection idle seconds + dataCenter: "" # Current volume server's data center name + rack: "" # Current volume server's rack name + whiteList: "" # Comma separated IP addresses having write permission + disableHttp: false # Disable HTTP requests, only gRPC operations are allowed + metricsPort: 9324 # Prometheus metrics listen port + metricsIp: "" # Metrics listen IP. If empty, defaults to bindAddress + loggingOverrideLevel: null # Override logging level + + # Custom command line arguments to add to the server command + # Example to fix IPv6 metrics connectivity issues: + # extraArgs: ["-metricsIp", "0.0.0.0"] + # Example with multiple args: + # extraArgs: ["-customFlag", "value", "-anotherFlag"] + extraArgs: [] + + # Update strategy configuration + # type: Recreate or RollingUpdate + # For single replica, Recreate is recommended to avoid data conflicts. + # For multiple replicas with RollingUpdate, you MUST use shared storage + # (e.g., data.type: persistentVolumeClaim with ReadWriteMany access mode) + # to avoid data loss or inconsistency between pods. + updateStrategy: + type: Recreate + + # S3 gateway configuration + # Note: Most parameters below default to null, which means they inherit from + # the global s3.* settings. Set explicit values here to override for allInOne only. + s3: + enabled: false # Whether to enable S3 gateway + port: null # S3 gateway port (null inherits from s3.port) + httpsPort: null # S3 gateway HTTPS port (null inherits from s3.httpsPort) + domainName: null # Suffix of the host name (null inherits from s3.domainName) + enableAuth: false # Enable user & permission to S3 + # Set to the name of an existing kubernetes Secret with the s3 json config file + # should have a secret key called seaweedfs_s3_config with an inline json config + existingConfigSecret: null + auditLogConfig: null # S3 audit log configuration (null inherits from s3.auditLogConfig) + # You may specify buckets to be created during the install process. + # Buckets may be exposed publicly by setting `anonymousRead` to `true` + # createBuckets: + # - name: bucket-a + # anonymousRead: true + # - name: bucket-b + # anonymousRead: false + + # SFTP server configuration + # Note: Most parameters below default to null, which means they inherit from + # the global sftp.* settings. Set explicit values here to override for allInOne only. + sftp: + enabled: false # Whether to enable SFTP server + port: null # SFTP port (null inherits from sftp.port) + sshPrivateKey: null # Path to SSH private key (null inherits from sftp.sshPrivateKey) + hostKeysFolder: null # Path to SSH host keys folder (null inherits from sftp.hostKeysFolder) + authMethods: null # Comma-separated auth methods (null inherits from sftp.authMethods) + maxAuthTries: null # Maximum authentication attempts (null inherits from sftp.maxAuthTries) + bannerMessage: null # Banner message (null inherits from sftp.bannerMessage) + loginGraceTime: null # Login grace time (null inherits from sftp.loginGraceTime) + clientAliveInterval: null # Client keep-alive interval (null inherits from sftp.clientAliveInterval) + clientAliveCountMax: null # Maximum missed keep-alive messages (null inherits from sftp.clientAliveCountMax) + enableAuth: false # Enable SFTP authentication + # Set to the name of an existing kubernetes Secret with the sftp json config file + existingConfigSecret: null + # Set to the name of an existing kubernetes Secret with the SSH keys + existingSshConfigSecret: null + + # Service settings + service: + annotations: {} # Annotations for the service + type: ClusterIP # Service type (ClusterIP, NodePort, LoadBalancer) + internalTrafficPolicy: Cluster # Internal traffic policy + + # Note: For ingress in all-in-one mode, use the standard s3.ingress and + # filer.ingress settings. The templates automatically detect all-in-one mode + # and point to the correct service (seaweedfs-all-in-one instead of + # seaweedfs-s3 or seaweedfs-filer). + + # Storage configuration + data: + type: "emptyDir" # Options: "hostPath", "persistentVolumeClaim", "emptyDir", "existingClaim" + hostPathPrefix: /mnt/data # Path prefix for hostPath volumes + claimName: seaweedfs-data-pvc # Name of the PVC to use (for existingClaim type) + size: null # Size of the PVC (null defaults to 10Gi for persistentVolumeClaim type) + storageClass: null # Storage class for the PVC (null uses cluster default) + # accessModes for the PVC. Default is ["ReadWriteOnce"]. + # For multi-replica deployments, use ["ReadWriteMany"] with a compatible storage class. + accessModes: [] + annotations: {} # Annotations for the PVC + + # Health checks + readinessProbe: + enabled: true + httpGet: + path: /cluster/status + port: 9333 + scheme: HTTP + initialDelaySeconds: 10 + periodSeconds: 15 + successThreshold: 1 + failureThreshold: 3 + timeoutSeconds: 5 + + livenessProbe: + enabled: true + httpGet: + path: /cluster/status + port: 9333 + scheme: HTTP + initialDelaySeconds: 20 + periodSeconds: 30 + successThreshold: 1 + failureThreshold: 5 + timeoutSeconds: 5 + + # Additional resources + extraEnvironmentVars: {} # Additional environment variables + # Secret environment variables (for database credentials, etc.) + # Example: + # secretExtraEnvironmentVars: + # WEED_POSTGRES_USERNAME: + # secretKeyRef: + # name: postgres-credentials + # key: username + # WEED_POSTGRES_PASSWORD: + # secretKeyRef: + # name: postgres-credentials + # key: password + secretExtraEnvironmentVars: {} + extraVolumeMounts: "" # Additional volume mounts + extraVolumes: "" # Additional volumes + initContainers: "" # Init containers + sidecars: "" # Sidecar containers + annotations: {} # Annotations for the deployment + podAnnotations: {} # Annotations for the pods + podLabels: {} # Labels for the pods + + # Scheduling configuration + # Affinity Settings + # Commenting out or setting as empty the affinity variable, will allow + # deployment to single node services such as Minikube + affinity: | + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: seaweedfs-all-in-one + topologyKey: kubernetes.io/hostname + + # Topology Spread Constraints Settings + # This should map directly to the value of the topologySpreadConstraints + # for a PodSpec. By Default no constraints are set. + topologySpreadConstraints: "" + + # Toleration Settings for pods + # This should be a multi-line string matching the Toleration array + # in a PodSpec. + tolerations: "" + + # nodeSelector labels for pod assignment, formatted as a muli-line string. + # ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector + nodeSelector: "" + + # Used to assign priority to pods + # ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ + priorityClassName: "" + + # Used to assign a service account. + # ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + serviceAccountName: "" + + # Configure security context for Pod + # ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + # Example: + # podSecurityContext: + # enabled: true + # runAsUser: 1000 + # runAsGroup: 3000 + # fsGroup: 2000 + podSecurityContext: {} + + # Configure security context for Container + # ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + # Example: + # containerSecurityContext: + # enabled: true + # runAsUser: 2000 + # allowPrivilegeEscalation: false + containerSecurityContext: {} + + # Resource management + resources: + limits: + cpu: "2" + memory: "2Gi" + requests: + cpu: "500m" + memory: "1Gi" + # Deploy Kubernetes COSI Driver for SeaweedFS # Requires COSI CRDs and controller to be installed in the cluster # For more information, visit: https://container-object-storage-interface.github.io/docs/deployment-guide cosi: enabled: false - image: "ghcr.io/seaweedfs/seaweedfs-cosi-driver:v0.1.2" + image: "ghcr.io/seaweedfs/seaweedfs-cosi-driver:v0.3.0" driverName: "seaweedfs.objectstorage.k8s.io" bucketClassName: "seaweedfs" endpoint: "" region: "" sidecar: - image: gcr.io/k8s-staging-sig-storage/objectstorage-sidecar/objectstorage-sidecar:v20230130-v0.1.0-24-gc0cf995 + image: gcr.io/k8s-staging-sig-storage/objectstorage-sidecar:v20250711-controllerv0.2.0-rc1-80-gc2f6e65 + # Resource requests, limits, etc. for the server cluster placement. This + # should map directly to the value of the resources field for a PodSpec, + # formatted as a multi-line string. By default no direct resource request + # is made. + resources: {} # enable user & permission to s3 (need to inject to all services) enableAuth: false @@ -898,6 +1572,12 @@ cosi: extraVolumes: "" extraVolumeMounts: "" + # Resource requests, limits, etc. for the server cluster placement. This + # should map directly to the value of the resources field for a PodSpec, + # formatted as a multi-line string. By default no direct resource request + # is made. + resources: {} + certificates: commonName: "SeaweedFS CA" ipAddresses: [] @@ -905,6 +1585,9 @@ certificates: keySize: 2048 duration: 2160h # 90d renewBefore: 360h # 15d + ca: + duration: 87600h # 10 years + renewBefore: 720h # 30d externalCertificates: # This will avoid the need to use cert-manager and will rely on providing your own external certificates and CA # you will need to store your provided certificates in the secret read by the different services: diff --git a/packages/system/seaweedfs/patches/disable-ca-key-rotation.patch b/packages/system/seaweedfs/patches/disable-ca-key-rotation.patch new file mode 100644 index 00000000..8e2fe0f3 --- /dev/null +++ b/packages/system/seaweedfs/patches/disable-ca-key-rotation.patch @@ -0,0 +1,13 @@ +diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml +index b01a8dcc..a38287de 100644 +--- a/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml ++++ b/packages/system/seaweedfs/charts/seaweedfs/templates/cert/ca-cert.yaml +@@ -13,6 +13,8 @@ spec: + secretName: {{ template "seaweedfs.name" . }}-ca-cert + commonName: "{{ template "seaweedfs.name" . }}-root-ca" + isCA: true ++ privateKey: ++ rotationPolicy: Never + {{- if .Values.certificates.ca.duration }} + duration: {{ .Values.certificates.ca.duration }} + {{- end }} diff --git a/packages/system/seaweedfs/patches/resize-api-server-annotation.diff b/packages/system/seaweedfs/patches/resize-api-server-annotation.diff index 2b41f297..43af4579 100644 --- a/packages/system/seaweedfs/patches/resize-api-server-annotation.diff +++ b/packages/system/seaweedfs/patches/resize-api-server-annotation.diff @@ -1,7 +1,7 @@ -diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-resize-hook.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume-resize-hook.yaml +diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-resize-hook.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-resize-hook.yaml index 436a785..9f186ea 100644 ---- a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-resize-hook.yaml -+++ b/packages/system/seaweedfs/charts/seaweedfs/templates/volume-resize-hook.yaml +--- a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-resize-hook.yaml ++++ b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-resize-hook.yaml @@ -45,6 +45,9 @@ metadata: helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation spec: diff --git a/packages/system/seaweedfs/patches/retention-policy-delete.yaml b/packages/system/seaweedfs/patches/retention-policy-delete.yaml index d57d1ea4..af1c73cf 100644 --- a/packages/system/seaweedfs/patches/retention-policy-delete.yaml +++ b/packages/system/seaweedfs/patches/retention-policy-delete.yaml @@ -1,7 +1,7 @@ -diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-statefulset.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume-statefulset.yaml +diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml index 0a70d8c..eb3bb91 100644 ---- a/packages/system/seaweedfs/charts/seaweedfs/templates/volume-statefulset.yaml -+++ b/packages/system/seaweedfs/charts/seaweedfs/templates/volume-statefulset.yaml +--- a/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml ++++ b/packages/system/seaweedfs/charts/seaweedfs/templates/volume/volume-statefulset.yaml @@ -10,6 +10,9 @@ metadata: app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/packages/system/seaweedfs/patches/s3-traffic-distribution.patch b/packages/system/seaweedfs/patches/s3-traffic-distribution.patch new file mode 100644 index 00000000..93c72384 --- /dev/null +++ b/packages/system/seaweedfs/patches/s3-traffic-distribution.patch @@ -0,0 +1,12 @@ +diff --git a/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml +index 8afd4865..86e0424e 100644 +--- a/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml ++++ b/packages/system/seaweedfs/charts/seaweedfs/templates/s3/s3-service.yaml +@@ -14,6 +14,7 @@ metadata: + {{- toYaml .Values.s3.annotations | nindent 4 }} + {{- end }} + spec: ++ trafficDistribution: PreferClose + internalTrafficPolicy: {{ .Values.s3.internalTrafficPolicy | default "Cluster" }} + ports: + - name: "swfs-s3" diff --git a/packages/system/seaweedfs/templates/database.yaml b/packages/system/seaweedfs/templates/database.yaml index dc11b101..b9b50c49 100644 --- a/packages/system/seaweedfs/templates/database.yaml +++ b/packages/system/seaweedfs/templates/database.yaml @@ -4,9 +4,15 @@ kind: Cluster metadata: name: seaweedfs-db spec: - instances: 2 + instances: {{ .Values.db.replicas }} + {{- $existingCluster := lookup "postgresql.cnpg.io/v1" "Cluster" .Release.Namespace "seaweedfs-db" }} + {{- $image := dig "spec" "imageName" "ghcr.io/cloudnative-pg/postgresql:17.7-standard-trixie" $existingCluster }} + imageName: {{ if regexMatch ":17\\." $image }}ghcr.io/cloudnative-pg/postgresql:17.7-standard-trixie{{ else if regexMatch ":[0-9]+\\.[0-9]+$" $image }}{{ printf "%s-standard-trixie" $image }}{{ else }}{{ $image }}{{ end }} storage: - size: 10Gi + size: {{ .Values.db.size }} + {{- with .Values.db.storageClass }} + storageClass: {{ . }} + {{- end }} monitoring: enablePodMonitor: true diff --git a/packages/system/seaweedfs/templates/hook.yaml b/packages/system/seaweedfs/templates/hook.yaml new file mode 100644 index 00000000..ef02f4ee --- /dev/null +++ b/packages/system/seaweedfs/templates/hook.yaml @@ -0,0 +1,84 @@ +{{- $shouldRunUpdateHook := true }} +{{- $configMap := lookup "v1" "ConfigMap" .Release.Namespace "seaweedfs-deployed-version" }} +{{- if $configMap }} + {{- $deployedVersion := dig "data" "version" "0" $configMap }} + {{- if ge $deployedVersion "3" }} + {{- $shouldRunUpdateHook = false }} + {{- end }} +{{- end }} + +{{- if $shouldRunUpdateHook }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: seaweedfs-hook + annotations: + helm.sh/hook: pre-upgrade + helm.sh/hook-weight: "1" + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation +spec: + template: + metadata: + labels: + policy.cozystack.io/allow-to-apiserver: "true" + spec: + serviceAccountName: seaweedfs-hook + containers: + - name: kubectl + image: docker.io/alpine/k8s:1.33.4 + command: + - sh + args: + - -exc + - |- + kubectl --namespace={{ .Release.Namespace }} delete --cascade=orphan --ignore-not-found \ + sts/seaweedfs-filer sts/seaweedfs-master sts/seaweedfs-volume deploy/seaweedfs-objectstorage-provisioner + restartPolicy: Never +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + annotations: + helm.sh/hook: pre-upgrade + helm.sh/hook-weight: "1" + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation + name: seaweedfs-hook +rules: +- apiGroups: + - "apps" + resources: + - statefulsets + - deployments + verbs: + - get + - list + - watch + - delete +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: seaweedfs-hook + annotations: + helm.sh/hook: pre-upgrade + helm.sh/hook-weight: "1" + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: seaweedfs-hook +subjects: + - kind: ServiceAccount + name: seaweedfs-hook + namespace: {{ .Release.Namespace | quote }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: seaweedfs-hook + annotations: + helm.sh/hook: pre-upgrade + helm.sh/hook-weight: "1" + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation +{{- end }} diff --git a/packages/system/seaweedfs/templates/version.yaml b/packages/system/seaweedfs/templates/version.yaml new file mode 100644 index 00000000..69b6762f --- /dev/null +++ b/packages/system/seaweedfs/templates/version.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: seaweedfs-deployed-version +data: + version: "3" diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index f7e3c5d9..3542a77f 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -4,34 +4,32 @@ global: extraEnvironmentVars: WEED_CLUSTER_SW_MASTER: "seaweedfs-master:9333" WEED_CLUSTER_SW_FILER: "seaweedfs-filer-client:8888" - + monitoring: + enabled: true seaweedfs: master: + volumeSizeLimitMB: 30000 replicas: 3 - volumeSizeLimitMB: 100 # replication type is XYZ: # X number of replica in other data centers # Y number of replica in other racks in the same data center # Z number of replica in other servers in the same rack defaultReplication: "001" - data: type: "emptyDir" - logs: type: "" - volume: replicas: 2 + resizeHook: + image: docker.io/alpine/k8s:1.33.4 # minimum free disk space(in percents). If free disk space lower this value - all volumes marks as ReadOnly minFreeSpacePercent: 5 - dataDirs: - - name: data1 - type: "persistentVolumeClaim" - size: "10Gi" - maxVolumes: 0 - + - name: data1 + type: "persistentVolumeClaim" + size: "10Gi" + maxVolumes: 0 filer: replicas: 2 # replication type is XYZ: @@ -41,10 +39,8 @@ seaweedfs: defaultReplicaPlacement: "001" data: type: "emptyDir" - logs: type: "" - extraEnvironmentVars: WEED_LEVELDB2_ENABLED: "false" WEED_POSTGRES2_ENABLED: "true" @@ -73,9 +69,9 @@ seaweedfs: secretKeyRef: key: password name: seaweedfs-db-app - s3: - enabled: true + replicas: 2 + enabled: false port: 8333 httpsPort: 0 # Suffix of the host name, {bucket}.{domainName} @@ -86,27 +82,93 @@ seaweedfs: # should have a secret key called seaweedfs_s3_config with an inline json configure existingConfigSecret: null auditLogConfig: {} - s3: - enableAuth: true - + enabled: true + replicas: 2 + port: 8333 + extraArgs: + - -idleTimeout=60 + enableAuth: false + readinessProbe: + httpGet: + scheme: HTTPS + livenessProbe: + httpGet: + scheme: HTTPS logs: type: "" - ingress: enabled: true className: "tenant-root" - host: "seaweedfs2.demo.cozystack.io" + host: "seaweedfs.demo.cozystack.io" annotations: nginx.ingress.kubernetes.io/proxy-body-size: "0" + nginx.ingress.kubernetes.io/proxy-buffering: "off" + nginx.ingress.kubernetes.io/proxy-request-buffering: "off" nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" - acme.cert-manager.io/http01-ingress-class: tenant-root + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + nginx.ingress.kubernetes.io/client-body-timeout: "3600" + nginx.ingress.kubernetes.io/client-header-timeout: "120" + nginx.ingress.kubernetes.io/service-upstream: "true" + acme.cert-manager.io/http01-ingress-ingressclassname: tenant-root cert-manager.io/cluster-issuer: letsencrypt-prod tls: - hosts: - - seaweedfs.demo.cozystack.io + - seaweedfs.demo.cozystack.io secretName: seaweedfs-s3-ingress-tls - + affinity: | + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 10 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - '{{ template "seaweedfs.name" . }}' + - key: app.kubernetes.io/instance + operator: In + values: + - '{{ .Release.Name }}' + - key: app.kubernetes.io/component + operator: In + values: + - s3 + topologyKey: kubernetes.io/hostname + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - '{{ template "seaweedfs.name" . }}' + - key: app.kubernetes.io/instance + operator: In + values: + - '{{ .Release.Name }}' + - key: app.kubernetes.io/component + operator: In + values: + - s3 + topologyKey: topology.kubernetes.io/zone + podAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 20 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - ingress-nginx + - key: app.kubernetes.io/component + operator: In + values: + - controller + topologyKey: kubernetes.io/hostname cosi: enabled: true podLabels: @@ -114,14 +176,16 @@ seaweedfs: driverName: "seaweedfs.objectstorage.k8s.io" bucketClassName: "seaweedfs" region: "" - sidecar: - image: "ghcr.io/kvaps/test:cosi-provisioner-sidecar-25" - + image: "ghcr.io/cozystack/cozystack/objectstorage-sidecar:v1.3.0@sha256:5bcccbdb13979a16cee535eb5fbcdf0d87973689010a10b7b25e55c5be3edaa6" certificates: commonName: "SeaweedFS CA" ipAddresses: [] keyAlgorithm: RSA keySize: 2048 - duration: 2160h # 90d - renewBefore: 360h # 15d + duration: 87600h # 10 years + renewBefore: 720h # 30d +db: + replicas: 2 + size: 10Gi + storageClass: "" diff --git a/packages/system/snapshot-controller/Makefile b/packages/system/snapshot-controller/Makefile index 65d37f1f..ca5d39e7 100644 --- a/packages/system/snapshot-controller/Makefile +++ b/packages/system/snapshot-controller/Makefile @@ -1,7 +1,7 @@ export NAME=snapshot-controller export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/tcp-balancer-rd/Chart.yaml b/packages/system/tcp-balancer-rd/Chart.yaml new file mode 100644 index 00000000..9543455e --- /dev/null +++ b/packages/system/tcp-balancer-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: tcp-balancer-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/tcp-balancer-rd/Makefile b/packages/system/tcp-balancer-rd/Makefile new file mode 100644 index 00000000..c85634a6 --- /dev/null +++ b/packages/system/tcp-balancer-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=tcp-balancer-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/tcp-balancer-rd/cozyrds/tcp-balancer.yaml b/packages/system/tcp-balancer-rd/cozyrds/tcp-balancer.yaml new file mode 100644 index 00000000..cabeedb3 --- /dev/null +++ b/packages/system/tcp-balancer-rd/cozyrds/tcp-balancer.yaml @@ -0,0 +1,31 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: tcp-balancer +spec: + application: + kind: TCPBalancer + plural: tcpbalancers + singular: tcpbalancer + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of HAProxy replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each TCP Balancer replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"httpAndHttps":{"description":"HTTP and HTTPS configuration.","type":"object","default":{},"required":["mode","targetPorts"],"properties":{"endpoints":{"description":"Endpoint addresses list.","type":"array","default":[],"items":{"type":"string"}},"mode":{"description":"Mode for balancer.","type":"string","default":"tcp","enum":["tcp","tcp-with-proxy"]},"targetPorts":{"description":"Target ports configuration.","type":"object","default":{},"required":["http","https"],"properties":{"http":{"description":"HTTP port number.","type":"integer","default":80},"https":{"description":"HTTPS port number.","type":"integer","default":443}}}}},"whitelistHTTP":{"description":"Secure HTTP by whitelisting client networks (default: false).","type":"boolean","default":false},"whitelist":{"description":"List of allowed client networks.","type":"array","default":[],"items":{"type":"string"}}}} + release: + prefix: tcp-balancer- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-tcp-balancer-application-default-tcp-balancer + namespace: cozy-system + dashboard: + category: NaaS + singular: TCP Balancer + plural: TCP Balancer + description: Layer4 load balancer service + tags: + - network + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODNfMjk4NSkiLz4KPHBhdGggZD0iTTcyLjE2NDUgNTkuNDI0M0w2Mi41IDQ4LjQ5OCIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIwLjI2IiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTQxLjY4NTUgNTEuMDIxNUw0OS4yNDcgNjIuMDY5MyIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIwLjEzIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTcyLjE2NDYgNTkuNDQxNEw4MS43MjYzIDQ4LjM5MzZNODMuNzE3MSA3MS42Mjk0TDk1LjA2NCA2Mi4wNjc4TTgzLjcxNzEgNzEuNjEwOEw5NS4wNjQgODEuNTkzTTgxLjgyOTEgOTQuMjAxN0w3Mi4xNjQ2IDgzLjQ4MTFNNjIuNTAwMSA5NC4yMDE3TDcyLjE2NDYgODMuNDkwNE00OS4yNTU5IDgxLjE3MjRMNjAuMTgyMSA3MS42MTA4TTYwLjE5MTUgNzEuNjEwOEw0OS4yNjUyIDYyLjA0OTFMNzIuMTY0NiA1OS40MjI3TDk1LjA2NCA2Mi4wNDkxIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjAuMjYiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8cGF0aCBkPSJNODEuNzE2OCA0OC4zOTM2TDgzLjcxNyA3MS42MTA4TDgxLjgyOSA5NC4xOTI0IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjAuMjYiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8cGF0aCBkPSJNOTUuMDY0IDgxLjU5MjVMNzIuMTY0NiA4My40ODA1TTQ5LjI1NTkgODEuMTcxOUw3Mi4xNTUzIDgzLjQ5OTIiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMC4yNiIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+CjxwYXRoIGQ9Ik02Mi41MDEyIDk0LjIwMTRMNjAuMTczOCA3MS42MTk4TTYyLjUwMTIgNDguNDk2MUw2MC4xNzM4IDcxLjYxMDUiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMC4yNiIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+CjxwYXRoIGQ9Ik0zOC43NSA2NC45OTQ4TDQ5LjI1NTcgNjIuMDUwNk01MS40NjE1IDQwLjYxODdMNjIuNTA5MyA0OC40OTc5TTYyLjQ5MDYgNDguNDk3OUw2NS4wMTQyIDM1LjY4MzZMODEuNzE2OCA0OC4zOTUxIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjAuMTMiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8cGF0aCBkPSJNNzkuMjAzMSAzNS42ODM2TDgxLjcyNjcgNDguMzk1MU05Mi43NTU4IDQwLjYxODdMODEuNzA4IDQ4LjM5NTFNMTAyLjYyNiA1MS4wMjE1TDgxLjcxNzQgNDguMzk1MU0xMDIuNjI2IDUxLjAwMjhMOTUuMDY0NSA2Mi4wNTA2TDEwNS43NzYgNjQuOTk0OCIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIwLjEzIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTk1LjA2MzkgNjIuMDUwNkwxMDUuNTcgNzguMDE0OE03OS4yMDI1IDM1LjY4MzZMNjIuNSA0OC40OTc5IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjAuMTMiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8cGF0aCBkPSJNOTUuMDYzNyA2Mi4wNTExTDkyLjczNjMgNDAuNjE5MU05NS4wNjM3IDgxLjU5NTFMMTA1LjU2OSA3OC4wMTUzIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjAuMTMiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8cGF0aCBkPSJNOTUuMDY1IDgxLjU5NDlMMTA1Ljc3NiA2NC45OTUxTTk1LjA2NSA4MS41OTQ5TDEwMi42MjYgOTEuNzgyOE05NS4wNjUgODEuNTk0OUw5Mi43Mzc3IDEwMi4xODZNODEuODMwMSA5NC4yMDM1TDkyLjc1NjQgMTAyLjE4NiIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIwLjEzIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTgxLjgyOSA5NC4yMDNMMTAyLjYyNSA5MS43ODIyTTgxLjgyOSA5NC4yMDNMNzkuMzI0MSAxMDcuMTExTTgxLjgyOSA5NC4yMDNMNjUuMDE0MyAxMDcuMTAxTTYyLjUgOTQuMjAzTDY1LjAyMzYgMTA3LjEzOSIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIwLjEzIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTYyLjUwMTIgOTQuMjAzMUw3OS4zMjUzIDEwNy4xMTFNNTEuNDYyOCAxMDIuMTg1TDYyLjUxMDUgOTQuMjAzMUw0MS42NzY4IDkxLjg4NTFMNDkuMjU2OSA4MS4xNzM4IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjAuMTMiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8cGF0aCBkPSJNNTEuNDYxOCAxMDIuMTg1TDQ5LjI1NiA4MS4xNzMxTDM4LjY0NzUgNzcuOTExMUw0OS4yNTYgNjIuMDQ5OCIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIwLjEzIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTQ5LjI1NTcgODEuMTc0NUwzOC43NSA2NC45OTUzTTUxLjQ2MTUgNDAuNjE5MUw0OS4yNTU3IDYyLjA1MTEiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMC4xMyIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+CjxwYXRoIGQ9Ik00MS42ODU1IDUxLjAyMTdMNjIuNDgxOSA0OC40OTgiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMC4xMyIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+CjxwYXRoIGQ9Ik00My4zNzYgMzYuODMzOEw1MS40NjA5IDQwLjYxOTJMNTAuODM0NiAzMS43OTU5TDY1LjAxMzYgMzUuNjg0MSIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIwLjEwMSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+CjxwYXRoIGQ9Ik01OC45Mjg5IDI4LjIyNDRMNjUuMDEzNiAzNS42ODMxTDY3LjUzNzMgMjYuNzM4M0w3OS4yMDE5IDM1LjY4MzFNNTEuNDYwOSA0MC42MTgxTDU4LjkxOTYgMjguMjI0NCIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIwLjEwMSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+CjxwYXRoIGQ9Ik03Ni41NjY3IDI2LjQ0MDRMNzkuMjAyNSAzNS42ODQzTDg1LjI5NjYgMjguMjI1Nk02NS4wMDQ5IDM1LjY4NDNMNzYuNTU3NCAyNi40NDA0TTkyLjc1NTIgNDAuNjE5NEw4NS4yNzc5IDI4LjIyNTYiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMC4xMDEiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8cGF0aCBkPSJNOTIuNzU0OSA0MC42MTkyTDkzLjQ5MzIgMzEuNzk1OU05Mi43NTQ5IDQwLjYxOTJMMTAxLjAzNiAzNi40MTMyTTkyLjc1NDkgNDAuNjE5MkwxMDcuMTQ5IDQyLjgyNU03OS4yMDIxIDM1LjY4NDFMOTMuNDgzOSAzMS43OTU5IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjAuMTAxIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTEwMi42MjUgNTEuMDIxNEwxMDcuMTM5IDQyLjgyNDRNMTAyLjYyNSA1MS4wMjE0TDEwMS4wNDUgMzYuNDIxOU0xMDIuNjI1IDUxLjAyMTRMMTEyLjA4MyA1MC4yODNNMTAyLjYyNSA1MS4wMjE0TDExNS41NiA1OC4zNzczIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjAuMTAxIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTEwNS43NzQgNjQuOTk0OUwxMTIuMDgzIDUwLjI4MzJNMTA1Ljc3NCA2NC45OTQ5TDExNS41NDEgNTguMzc3NE0xMDUuNzc0IDY0Ljk5NDlMMTE2LjcgNjcuMjAwN0wxMDUuNTY4IDc4LjAxNDkiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMC4xMDEiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8cGF0aCBkPSJNMTE3LjAxOSA3NS45MTIxTDEwNS41NjkgNzguMDE1MUwxMTUuMzM3IDg0LjUyOTdMMTAyLjYyNSA5MS43ODI3TTEwNS43NzUgNjQuOTk1MUwxMTcuMDE5IDc1LjkyMTQiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMC4xMDEiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8cGF0aCBkPSJNMTAyLjYyNSA5MS43ODMzTDExMS45NzEgOTIuNzI3M00xMDUuNTc4IDc4LjAxNTZMMTExLjk3MSA5Mi43MThNMTA3LjA1NSAxMDAuMDY0TDEwMi42NDMgOTEuNzgzM0wxMDAuOTYxIDEwNi4yOCIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIwLjEwMSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+CjxwYXRoIGQ9Ik0xMDAuOTQzIDEwNi4yNzlMOTIuNzQ1OCAxMDIuMTg1TTkyLjc1NTEgMTAyLjE4NUw5My4zODEzIDExMS4zNDVNOTIuNzU1MSAxMDIuMTg1TDEwNy4wMzcgMTAwLjA4Mk05Mi43NTUxIDEwMi4xODVMODUuMjg3MSAxMTQuNzk0IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjAuMTAxIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTc5LjMyMzIgMTA3LjEwM0w4NS4yNzcgMTE0Ljc2N003OS4zMjMyIDEwNy4xMDNMOTMuMzk5MyAxMTEuMzA5TTc5LjMyMzIgMTA3LjEwM0w3Ni41NjU5IDExNi41NjFNNzkuMzIzMiAxMDcuMTAzTDY3LjU1NTcgMTE2LjU2MSIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIwLjEwMSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+CjxwYXRoIGQ9Ik02NS4wMTM2IDEwNy4xMDJMNjcuNTM3MyAxMTYuNTYxTTY1LjAxMzYgMTA3LjEwMkw3Ni41NTY4IDExNi41NjFNNjUuMDEzNiAxMDcuMTAyTDU5LjAyMjQgMTE0Ljc2Nk01MS40NjA5IDEwMi4xODZMNTkuMDIyNCAxMTQuNzk0IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjAuMTAxIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTY1LjAxMzkgMTA3LjEwMUw1MC43MzIyIDExMS41MTNNNTAuNzIyOCAxMTEuNTMyTDUxLjQ2MTIgMTAyLjE4NUw0My4yNjQyIDEwNi42OTlMNDEuNjg0NiA5MS44ODQ4IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjAuMTAxIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTUxLjQ2MSAxMDIuMTg2TDM3LjA2NzEgMTAwLjE5NU00MS42ODQ0IDkxLjg4NkwzNy4wNTc4IDEwMC4xNjdNNDEuNjg0NCA5MS44ODZMMzIuMjI1NSA5Mi44MzAxTTQxLjY4NDQgOTEuODg2TDI4LjY3MzggODQuNjQyM0wzOC42NDY3IDc3LjkxMjdMMjcuMjk5OCA3NS45MjE5IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjAuMTAxIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTM4LjY0NjcgNzcuOTEyM0wzMi4yNTM2IDkyLjgyOTZNMzguNzQ5NSA2NC45OTUxTDI3LjI5OTggNzUuOTIxNCIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIwLjEwMSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+CjxwYXRoIGQ9Ik0zOC42NDY3IDc3LjkxMjJMMjcuMjk5OCA2Ny4yMDA5TTM4Ljc1ODkgNjQuOTk1MUwyOC45ODIyIDU4LjQ4MDUiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMC4xMDEiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8cGF0aCBkPSJNMjcuMjk5OCA2Ny4yMDA3TDM4Ljc0OTUgNjQuOTk0OUwzMi4yNDQyIDUwLjI4MzIiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMC4xMDEiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8cGF0aCBkPSJNNDEuNjgzNiA1MS4wMjE3TDMyLjIyNDcgNTAuMjgzM000MS42ODM2IDUxLjAyMTdMMjguOTgxNCA1OC40ODA0TTQxLjY4MzYgNTEuMDIxN0wzNy4xNzg1IDQzLjI0NTNNNDEuNjgzNiA1MS4wMjE3TDQzLjM2NiAzNi44NDI4IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjAuMTAxIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiLz4KPHBhdGggZD0iTTUxLjQ2MSA0MC42MTkxTDM3LjE2OTkgNDMuMjQ1NiIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIwLjEwMSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIi8+CjxwYXRoIGQ9Ik01NC41NjQ1IDc3LjA3MDJMNTQuNjM5MiA2Ni4wMjI0TDY1LjY4NyA2Ni4wOTcxTDY1LjYxMjMgNzcuMTQ0OUw1NC41NjQ1IDc3LjA3MDJaTTY2LjUxODkgNjQuOTEwMUw2Ni41OTM3IDUzLjg2MjNMNzcuNjQxNSA1My45MzcxTDc3LjU2NjcgNjQuOTg0OUw2Ni41MTg5IDY0LjkxMDFaTTY2LjUxODkgODkuMTI3NEw2Ni41OTM3IDc4LjA3OTZMNzcuNjQxNSA3OC4xNTQ0TDc3LjU2NjcgODkuMjAyMkw2Ni41MTg5IDg5LjEyNzRaTTc4LjU3NjEgNzYuOTY3M0w3OC42NTA5IDY1LjkxOTVMODkuNjk4NyA2NS45OTQzTDg5LjYyMzkgNzcuMDQyMUw3OC41NzYxIDc2Ljk2NzNaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNNzcuOTQwNiA1Mi4yMzY2TDc3Ljk5NjYgNDQuNTcyM0w4NS42OTgzIDQ0LjYyODNMODUuNjQyMiA1Mi4yOTI2TDc3Ljk0MDYgNTIuMjM2NlpNNTguNjg2NCA1Mi4yMzY2TDU4Ljc0MjQgNDQuNTcyM0w2Ni40NDQxIDQ0LjYyODNMNjYuMzg4IDUyLjI5MjZMNTguNjg2NCA1Mi4yMzY2Wk00NS4zNTggNjUuODkyMUw0NS40MTQxIDU4LjIyNzhMNTMuMTE1NyA1OC4yODM5TDUzLjA1OTcgNjUuOTQ4Mkw0NS4zNTggNjUuODkyMVpNNDUuMzQ4NiA4NS4xNjVMNDUuNDMyOCA3Ny41MDA3TDUzLjEzNDQgNzcuNTg0OEw1My4wNTAzIDg1LjI0OTFMNDUuMzQ4NiA4NS4xNjVaTTkxLjI2OSA4NS4wMTU0TDkxLjMyNSA3Ny4zNTExTDk5LjAyNjcgNzcuNDA3Mkw5OC45NzA2IDg1LjA3MTVMOTEuMjY5IDg1LjAxNTRaTTkxLjQxODUgNjUuOTQ4Mkw5MS41MDI2IDU4LjI4MzlMOTkuMjA0MyA1OC4zNjhMOTkuMTIwMiA2Ni4wMzIzTDkxLjQxODUgNjUuOTQ4MloiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0zOS4xMTQzIDUzLjUyNjNMMzkuMTUxNyA0OC40NzkxTDQ0LjE4MDIgNDguNTE2NUw0NC4xNDI4IDUzLjU2MzdMMzkuMTE0MyA1My41MjYzWk00OC45NTYzIDQzLjI2MzdMNDguOTkzNyAzOC4yMTY0TDU0LjAyMjMgMzguMjUzOEw1My45ODQ5IDQzLjMwMUw0OC45NTYzIDQzLjI2MzdaTTYyLjQ5OTcgMzguMTg4NEw2Mi41MzcxIDMzLjE0MTJMNjcuNTY1NiAzMy4xNzg2TDY3LjUyODIgMzguMjI1OEw2Mi40OTk3IDM4LjE4ODRaTTM2LjE1MTQgNjcuNDkwM0wzNi4xODg4IDYyLjQ0MzFMNDEuMTg5MiA2Mi40ODA1TDQxLjE1MTkgNjcuNTI3N0wzNi4xNTE0IDY3LjQ5MDNaTTEwMC4wODMgNDguNTUzOUwxMDUuMTMgNDguNTE2NUwxMDUuMTY3IDUzLjU0NUwxMDAuMTIgNTMuNTgyNEwxMDAuMDgzIDQ4LjU1MzlaTTkwLjI0MDcgMzguMTEzNkw5NS4yODc5IDM4LjA3NjJMOTUuMzI1MyA0My4xMDQ4TDkwLjI3ODEgNDMuMTQyMUw5MC4yNDA3IDM4LjExMzZaTTc2LjY1MDYgMzMuMTY5Mkw4MS42OTc4IDMzLjEzMThMODEuNzM1MiAzOC4xNjA0TDc2LjY4OCAzOC4xOTc3TDc2LjY1MDYgMzMuMTY5MlpNMTAzLjAxOCA2Mi40OTkyTDEwOC4wNjUgNjIuNDYxOEwxMDguMTAyIDY3LjQ5MDNMMTAzLjA1NSA2Ny41Mjc3TDEwMy4wMTggNjIuNDk5MloiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik01OC41ODMgOTguMjQwNUw1OC42MzkxIDkwLjU3NjJMNjYuMzQwOCA5MC42MzIzTDY2LjI4NDcgOTguMjk2NUw1OC41ODMgOTguMjQwNVpNNzcuODM3MiA5OC4yNDA1TDc3Ljg5MzMgOTAuNTc2Mkw4NS41OTUgOTAuNjMyM0w4NS41Mzg5IDk4LjI5NjVMNzcuODM3MiA5OC4yNDA1WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTEwMC4wNDUgOTQuMzYxOUwxMDAuMDgyIDg5LjMxNDdMMTA1LjExMSA4OS4zNTIxTDEwNS4wNzQgOTQuMzk5M0wxMDAuMDQ1IDk0LjM2MTlaTTkwLjMxNTIgMTA0LjcyN0w5MC4zNTI2IDk5LjY4MDJMOTUuMzgxMSA5OS43MTc2TDk1LjM0MzcgMTA0Ljc2NUw5MC4zMTUyIDEwNC43MjdaTTc2Ljc3MTggMTA5LjdMNzYuODA5MiAxMDQuNjUzTDgxLjgzNzcgMTA0LjY5TDgxLjgwMDQgMTA5LjczN0w3Ni43NzE4IDEwOS43Wk0xMDMuMDA4IDgwLjM5NzlMMTAzLjA0NSA3NS4zNTA3TDEwOC4wNzQgNzUuMzg4MUwxMDguMDM3IDgwLjQzNTNMMTAzLjAwOCA4MC4zOTc5Wk0zOS4xMjMzIDg5LjMxNDdMNDQuMTcwNiA4OS4yNzczTDQ0LjIwNzkgOTQuMzA1OEwzOS4xNjA3IDk0LjM0MzJMMzkuMTIzMyA4OS4zMTQ3Wk00OC45NjU0IDk5LjY0MjhMNTQuMDEyNiA5OS42MDU0TDU0LjA1IDEwNC42MzRMNDkuMDAyOCAxMDQuNjcxTDQ4Ljk2NTQgOTkuNjQyOFpNNjIuNDQzMyAxMDQuNTk3TDY3LjQ5MDYgMTA0LjU1OUw2Ny41Mjc5IDEwOS41ODhMNjIuNDgwNyAxMDkuNjI1TDYyLjQ0MzMgMTA0LjU5N1pNMzYuMTg4NSA3NS4zNjk0TDQxLjIzNTcgNzUuMzMyTDQxLjI3MzEgODAuMzYwNkwzNi4yMjU5IDgwLjM5NzlMMzYuMTg4NSA3NS4zNjk0WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTExMC42MjUgNTEuNjM4NEwxMTAuNjQ0IDQ4LjkwOTJMMTEzLjQyOSA0OC45Mjc5TDExMy40MSA1MS42NTcxTDExMC42MjUgNTEuNjM4NFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0xMTQuMjI0IDU5Ljg5MTNMMTE0LjI0MiA1Ny4xNjIxTDExNy4wMjggNTcuMTgwOEwxMTcuMDA5IDU5LjkxTDExNC4yMjQgNTkuODkxM1oiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0xMDUuNzY3IDQ0LjMzNzZMMTA1Ljc4NSA0MS42MDg0TDEwOC41NzEgNDEuNjI3MUwxMDguNTUyIDQ0LjM1NjNMMTA1Ljc2NyA0NC4zMzc2WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTQxLjk3MzYgMzguMDk0NUw0MS45OTIzIDM1LjM2NTJMNDQuNzc3NiAzNS4zODM5TDQ0Ljc1ODkgMzguMTEzMkw0MS45NzM2IDM4LjA5NDVaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMjYgNjguNTU1NEwyNi4wMTg3IDY1LjgyNjJMMjguODA0IDY1Ljg0NDlMMjguNzg1MyA2OC41NzQxTDI2IDY4LjU1NTRaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNOTkuNjI0IDM4LjA5NDVMOTkuNjQyNyAzNS4zNjUyTDEwMi40MjggMzUuMzgzOUwxMDIuNDA5IDM4LjExMzJMOTkuNjI0IDM4LjA5NDVaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMjcuNTg5OCA1OS44ODE2TDI3LjYwODUgNTcuMTUyM0wzMC4zOTM5IDU3LjE3MUwzMC4zNzUyIDU5LjkwMDNMMjcuNTg5OCA1OS44ODE2WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTU3LjYyOTkgMjkuNjM1NUw1Ny42NDg2IDI2LjkwNjJMNjAuNDMzOSAyNi45MjQ5TDYwLjQxNTIgMjkuNjU0Mkw1Ny42Mjk5IDI5LjYzNTVaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMzAuOTcyNyA1MS42Mzg0TDMwLjk5MTMgNDguOTA5MkwzMy43NzY3IDQ4LjkyNzlMMzMuNzU4IDUxLjY1NzFMMzAuOTcyNyA1MS42Mzg0WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTM1Ljk0NTMgNDQuMjM2MUwzNS45NjQgNDEuNTA2OEwzOC43NDkzIDQxLjUyNTVMMzguNzMwNiA0NC4yNTQ4TDM1Ljk0NTMgNDQuMjM2MVoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik00OS40MjI5IDMwLjQyMDRMNTIuMTUyMSAzMC40MDE3TDUyLjE3MDggMzMuMTg3TDQ5LjQ0MTUgMzMuMjA1N0w0OS40MjI5IDMwLjQyMDRaTTY2LjMwMyAyNS4wNDZMNjkuMDMyMiAyNS4wMjczTDY5LjA1MDkgMjcuODEyN0w2Ni4zMjE3IDI3LjgzMTRMNjYuMzAzIDI1LjA0NloiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik05Mi4yMjI3IDMzLjIyNDRMOTIuMjQxNCAzMC40OTUxTDk1LjAyNjcgMzAuNTEzOEw5NS4wMDggMzMuMjQzTDkyLjIyMjcgMzMuMjI0NFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0xMTUuNTk4IDY4LjQ1MjlMMTE1LjYxNiA2NS43MjM2TDExOC40MDIgNjUuNzQyM0wxMTguMzgzIDY4LjQ3MTZMMTE1LjU5OCA2OC40NTI5WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTc1LjE5MTQgMjcuNzI5Mkw3NS4yMTAxIDI1TDc3Ljk5NTQgMjUuMDE4N0w3Ny45NzY3IDI3Ljc0NzlMNzUuMTkxNCAyNy43MjkyWiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTgzLjg2NjIgMjkuNTIzMkw4My44ODQ5IDI2Ljc5MzlMODYuNjcwMiAyNi44MTI2TDg2LjY1MTUgMjkuNTQxOUw4My44NjYyIDI5LjUyMzJaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNOTkuNjI0IDEwNy43TDk5LjY0MjcgMTA0Ljk3MUwxMDIuNDI4IDEwNC45ODlMMTAyLjQwOSAxMDcuNzE5TDk5LjYyNCAxMDcuN1oiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0xMTUuNTk4IDc3LjIzOUwxMTUuNjE2IDc0LjUwOThMMTE4LjQwMiA3NC41Mjg1TDExOC4zODMgNzcuMjU3N0wxMTUuNTk4IDc3LjIzOVoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik00MS45NzM2IDEwNy43TDQxLjk5MjMgMTA0Ljk3MUw0NC43Nzc2IDEwNC45ODlMNDQuNzU4OSAxMDcuNzE5TDQxLjk3MzYgMTA3LjdaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMTE0LjIyNCA4Ni4wMzI5TDExNC4yNDIgODMuMzAzN0wxMTcuMDI4IDgzLjMyMjRMMTE3LjAwOSA4Ni4wNTE2TDExNC4yMjQgODYuMDMyOVoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik04My44NjYyIDExNi4yN0w4My44ODQ5IDExMy41NDFMODYuNjcwMiAxMTMuNTZMODYuNjUxNSAxMTYuMjg5TDgzLjg2NjIgMTE2LjI3WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTExMC42MjUgOTQuMjY4M0wxMTAuNjQ0IDkxLjUzOTFMMTEzLjQyOSA5MS41NTc4TDExMy40MSA5NC4yODdMMTEwLjYyNSA5NC4yNjgzWiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTEwNS43NjcgMTAxLjY3MkwxMDUuNzg1IDk4Ljk0MjRMMTA4LjU3MSA5OC45NjExTDEwOC41NTIgMTAxLjY5TDEwNS43NjcgMTAxLjY3MloiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik05Mi4xMDk0IDExMC4wNjVMOTQuODM4NiAxMTAuMDQ2TDk0Ljg1NzMgMTEyLjgzMUw5Mi4xMjggMTEyLjg1TDkyLjEwOTQgMTEwLjA2NVpNNzUuMzMyIDExNS4yMTVMNzguMDYxMyAxMTUuMTk2TDc4LjA4IDExNy45ODFMNzUuMzUwNyAxMThMNzUuMzMyIDExNS4yMTVaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNNDkuNDc4NSAxMTIuODg2TDQ5LjQ5NzIgMTEwLjE1N0w1Mi4yODI1IDExMC4xNzZMNTIuMjYzOCAxMTIuOTA1TDQ5LjQ3ODUgMTEyLjg4NloiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0zMC44NTk0IDk0LjE2NThMMzAuODc4MSA5MS40MzY1TDMzLjY2MzQgOTEuNDU1MkwzMy42NDQ3IDk0LjE4NDVMMzAuODU5NCA5NC4xNjU4WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTI3LjU4MDEgODYuMDE0NEwyNy41OTg4IDgzLjI4NTJMMzAuMzg0MSA4My4zMDM5TDMwLjM2NTQgODYuMDMzMUwyNy41ODAxIDg2LjAxNDRaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMzUuODMyIDEwMS42NzJMMzUuODUwNyA5OC45NDI0TDM4LjYzNiA5OC45NjExTDM4LjYxNzMgMTAxLjY5TDM1LjgzMiAxMDEuNjcyWiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTI2IDc3LjIzOUwyNi4wMTg3IDc0LjUwOThMMjguODA0IDc0LjUyODVMMjguNzg1MyA3Ny4yNTc3TDI2IDc3LjIzOVoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik02Ni40MDUzIDExNy45NjJMNjYuNDI0IDExNS4yMzJMNjkuMjA5MyAxMTUuMjUxTDY5LjE5MDYgMTE3Ljk4TDY2LjQwNTMgMTE3Ljk2MloiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik01Ny41MTc2IDExNi4xNjhMNTcuNTM2MyAxMTMuNDM4TDYwLjMyMTYgMTEzLjQ1N0w2MC4zMDI5IDExNi4xODZMNTcuNTE3NiAxMTYuMTY4WiIgZmlsbD0id2hpdGUiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl82ODNfMjk4NSIgeDE9IjEwIiB5MT0iMTUuNSIgeDI9IjE0NCIgeTI9IjEzMS41IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiMwMEE4REEiLz4KPHN0b3Agb2Zmc2V0PSIwLjQ5NSIgc3RvcC1jb2xvcj0iIzM1NzlCQyIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMyODZFQTUiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "external"], ["spec", "httpAndHttps"], ["spec", "httpAndHttps", "mode"], ["spec", "httpAndHttps", "targetPorts"], ["spec", "httpAndHttps", "targetPorts", "http"], ["spec", "httpAndHttps", "targetPorts", "https"], ["spec", "httpAndHttps", "endpoints"], ["spec", "whitelistHTTP"], ["spec", "whitelist"]] + secrets: + exclude: [] + include: [] diff --git a/packages/system/tcp-balancer-rd/templates/cozyrd.yaml b/packages/system/tcp-balancer-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/tcp-balancer-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/tcp-balancer-rd/values.yaml b/packages/system/tcp-balancer-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/tcp-balancer-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/telepresence/Makefile b/packages/system/telepresence/Makefile index 1aec8917..d7f83e05 100644 --- a/packages/system/telepresence/Makefile +++ b/packages/system/telepresence/Makefile @@ -1,7 +1,7 @@ export NAME=traffic-manager export NAMESPACE=cozy-telepresence -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/tenant-rd/Chart.yaml b/packages/system/tenant-rd/Chart.yaml new file mode 100644 index 00000000..ad3d27f4 --- /dev/null +++ b/packages/system/tenant-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: tenant-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/tenant-rd/Makefile b/packages/system/tenant-rd/Makefile new file mode 100644 index 00000000..11db2069 --- /dev/null +++ b/packages/system/tenant-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=tenant-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/tenant-rd/cozyrds/tenant.yaml b/packages/system/tenant-rd/cozyrds/tenant.yaml new file mode 100644 index 00000000..9af11af0 --- /dev/null +++ b/packages/system/tenant-rd/cozyrds/tenant.yaml @@ -0,0 +1,29 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: tenant +spec: + application: + kind: Tenant + singular: tenant + plural: tenants + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"host":{"description":"The hostname used to access tenant services (defaults to using the tenant name as a subdomain for its parent tenant host).","type":"string","default":""},"etcd":{"description":"Deploy own Etcd cluster.","type":"boolean","default":false},"monitoring":{"description":"Deploy own Monitoring Stack.","type":"boolean","default":false},"ingress":{"description":"Deploy own Ingress Controller.","type":"boolean","default":false},"seaweedfs":{"description":"Deploy own SeaweedFS.","type":"boolean","default":false},"schedulingClass":{"description":"The name of a SchedulingClass CR to apply scheduling constraints for this tenant's workloads.","type":"string","default":""},"resourceQuotas":{"description":"Define resource quotas for the tenant.","type":"object","default":{},"additionalProperties":{"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}}} + release: + prefix: tenant- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-tenant-application-default-tenant + namespace: cozy-system + dashboard: + category: Administration + singular: Tenant + plural: Tenants + description: Separated tenant namespace + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODdfMzQwMykiLz4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzY4N18zNDAzKSI+CjxwYXRoIGQ9Ik03MiAyOUM2Ni4zOTI2IDI5IDYxLjAxNDggMzEuMjM4OCA1Ny4wNDk3IDM1LjIyNEM1My4wODQ3IDM5LjIwOTEgNTAuODU3MSA0NC42MTQxIDUwLjg1NzEgNTAuMjVDNTAuODU3MSA1NS44ODU5IDUzLjA4NDcgNjEuMjkwOSA1Ny4wNDk3IDY1LjI3NkM2MS4wMTQ4IDY5LjI2MTIgNjYuMzkyNiA3MS41IDcyIDcxLjVDNzcuNjA3NCA3MS41IDgyLjk4NTIgNjkuMjYxMiA4Ni45NTAzIDY1LjI3NkM5MC45MTUzIDYxLjI5MDkgOTMuMTQyOSA1NS44ODU5IDkzLjE0MjkgNTAuMjVDOTMuMTQyOSA0NC42MTQxIDkwLjkxNTMgMzkuMjA5MSA4Ni45NTAzIDM1LjIyNEM4Mi45ODUyIDMxLjIzODggNzcuNjA3NCAyOSA3MiAyOVpNNjAuOTgyNiA4My4zMDM3QzYwLjQ1NCA4Mi41ODk4IDU5LjU5NTEgODIuMTkxNCA1OC43MTk2IDgyLjI3NDRDNDUuMzg5NyA4My43MzU0IDM1IDk1LjEwNzQgMzUgMTA4LjkwM0MzNSAxMTEuNzI2IDM3LjI3OTUgMTE0IDQwLjA3MSAxMTRIMTAzLjkyOUMxMDYuNzM3IDExNCAxMDkgMTExLjcwOSAxMDkgMTA4LjkwM0MxMDkgOTUuMTA3NCA5OC42MTAzIDgzLjc1MiA4NS4yNjM4IDgyLjI5MUM4NC4zODg0IDgyLjE5MTQgODMuNTI5NSA4Mi42MDY0IDgzLjAwMDkgODMuMzIwM0w3NC4wOTc4IDk1LjI0MDJDNzMuMDQwNiA5Ni42NTE0IDcwLjkyNjMgOTYuNjUxNCA2OS44NjkyIDk1LjI0MDJMNjAuOTY2MSA4My4zMjAzTDYwLjk4MjYgODMuMzAzN1oiIGZpbGw9ImJsYWNrIi8+CjwvZz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl82ODdfMzQwMyIgeDE9IjcyIiB5MT0iMTQ0IiB4Mj0iLTEuMjgxN2UtMDUiIHkyPSI0IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiNDMEQ2RkYiLz4KPHN0b3Agb2Zmc2V0PSIwLjMiIHN0b3AtY29sb3I9IiNDNERBRkYiLz4KPHN0b3Agb2Zmc2V0PSIwLjY1IiBzdG9wLWNvbG9yPSIjRDNFOUZGIi8+CjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI0U5RkZGRiIvPgo8L2xpbmVhckdyYWRpZW50Pgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzY4N18zNDAzIj4KPHJlY3Qgd2lkdGg9Ijc0IiBoZWlnaHQ9Ijg1IiBmaWxsPSJ3aGl0ZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMzUgMjkpIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg== + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "host"], ["spec", "etcd"], ["spec", "monitoring"], ["spec", "ingress"], ["spec", "seaweedfs"], ["spec", "schedulingClass"], ["spec", "resourceQuotas"]] + secrets: + exclude: [] + include: [] diff --git a/packages/system/tenant-rd/templates/cozyrd.yaml b/packages/system/tenant-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/tenant-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/tenant-rd/values.yaml b/packages/system/tenant-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/tenant-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/velero/Makefile b/packages/system/velero/Makefile index ca4ebd5e..44eba951 100644 --- a/packages/system/velero/Makefile +++ b/packages/system/velero/Makefile @@ -1,7 +1,7 @@ export NAME=velero export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/velero/charts/velero/Chart.yaml b/packages/system/velero/charts/velero/Chart.yaml index 8b740531..2f303004 100644 --- a/packages/system/velero/charts/velero/Chart.yaml +++ b/packages/system/velero/charts/velero/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v2 -appVersion: 1.16.1 +appVersion: 1.17.0 description: A Helm chart for velero home: https://github.com/vmware-tanzu/velero icon: https://cdn-images-1.medium.com/max/1600/1*-9mb3AKnKdcL_QD3CMnthQ.png @@ -14,4 +14,4 @@ maintainers: name: velero sources: - https://github.com/vmware-tanzu/velero -version: 10.0.5 +version: 11.0.0 diff --git a/packages/system/velero/charts/velero/README.md b/packages/system/velero/charts/velero/README.md index 61d584ab..088b7f7c 100644 --- a/packages/system/velero/charts/velero/README.md +++ b/packages/system/velero/charts/velero/README.md @@ -102,6 +102,107 @@ CSI plugin has been merged into velero repo in v1.14 release. It will be install This version removes the `nodeAgent.privileged` field, you should use `nodeAgent.containerSecurityContext.privileged` instead +## Repository Maintenance Configuration + +Starting from Velero v1.15, you can configure repository maintenance jobs with different resource limits and node affinity settings per repository using a ConfigMap. This feature is supported through the Helm chart. + +### Basic Usage + +To enable per-repository maintenance configuration, provide repository-specific configurations and provide global configurations that will be applied across all repositories: + +```yaml +configuration: + repositoryMaintenanceJob: + repositoryConfigData: + name: "my-repo-maintenance-config" # Optional, defaults to "velero-repo-maintenance" + global: + podResources: + cpuRequest: "100m" + cpuLimit: "200m" + memoryRequest: "100Mi" + memoryLimit: "200Mi" + keepLatestMaintenanceJobs: 1 +``` + +### Per-Repository Configuration + +You can configure specific settings for individual repositories using repository keys. Repository keys are formed as: `{namespace}-{storageLocation}-{repositoryType}`. + +For example, if you have a BackupRepository for namespace `prod` using storage location `s3-backup` with repository type `kopia`, the key would be `prod-s3-backup-kopia`. + +```yaml +configuration: + repositoryMaintenanceJob: + repositoryConfigData: + global: + podResources: + cpuRequest: "100m" + cpuLimit: "200m" + memoryRequest: "100Mi" + memoryLimit: "200Mi" + repositories: + "prod-s3-backup-kopia": + podResources: + cpuRequest: "500m" + cpuLimit: "1000m" + memoryRequest: "512Mi" + memoryLimit: "1024Mi" + loadAffinity: + - nodeSelector: + matchLabels: + dedicated: "backup" +``` + +### Node Affinity and Priority Class + +You can specify node affinity and priority class for maintenance jobs: + +```yaml +configuration: + repositoryMaintenanceJob: + repositoryConfigData: + global: + podResources: + cpuRequest: "100m" + cpuLimit: "200m" + memoryRequest: "100Mi" + memoryLimit: "200Mi" + loadAffinity: + - nodeSelector: + matchExpressions: + - key: "cloud.google.com/machine-family" + operator: "In" + values: ["e2"] + - nodeSelector: + matchExpressions: + - key: "topology.kubernetes.io/zone" + operator: "In" + values: ["us-central1-a", "us-central1-b", "us-central1-c"] + priorityClassName: "low-priority" +``` + +**Note**: `priorityClassName` is only supported in the global configuration section and applies to all maintenance jobs. + +### Backward Compatibility + +When `repositoryConfigData.global` and `repositoryConfigData.repositories` are not provided (default), the chart continues to use the legacy global settings: + +```yaml +configuration: + repositoryMaintenanceJob: + requests: + cpu: 500m + memory: 512Mi + limits: + cpu: 1000m + memory: 1024Mi + latestJobsCount: 3 +``` + +Note: The legacy parameters (`--maintenance-job-cpu-request`, `--maintenance-job-mem-request`, `--maintenance-job-cpu-limit`, `--maintenance-job-mem-limit`) are deprecated in Velero v1.15 and will be removed in v1.17. + +For more information, see the [Velero Repository Maintenance documentation](https://velero.io/docs/main/repository-maintenance/). + ## Upgrading Velero ### Upgrading to v1.16 diff --git a/packages/system/velero/charts/velero/crds/backuprepositories.yaml b/packages/system/velero/charts/velero/crds/backuprepositories.yaml index 73da6eaa..7714f73a 100644 --- a/packages/system/velero/charts/velero/crds/backuprepositories.yaml +++ b/packages/system/velero/charts/velero/crds/backuprepositories.yaml @@ -73,7 +73,7 @@ spec: resticIdentifier: description: |- ResticIdentifier is the full restic-compatible string for identifying - this repository. + this repository. This field is only used when RepositoryType is "restic". type: string volumeNamespace: description: |- @@ -83,7 +83,6 @@ spec: required: - backupStorageLocation - maintenanceFrequency - - resticIdentifier - volumeNamespace type: object status: diff --git a/packages/system/velero/charts/velero/crds/backups.yaml b/packages/system/velero/charts/velero/crds/backups.yaml index f36d7b43..a6768029 100644 --- a/packages/system/velero/charts/velero/crds/backups.yaml +++ b/packages/system/velero/charts/velero/crds/backups.yaml @@ -512,6 +512,10 @@ spec: uploads to perform when using the uploader. type: integer type: object + volumeGroupSnapshotLabelKey: + description: VolumeGroupSnapshotLabelKey specifies the label key + to group PVCs under a VGS. + type: string volumeSnapshotLocations: description: VolumeSnapshotLocations is a list containing names of VolumeSnapshotLocations associated with this backup. diff --git a/packages/system/velero/charts/velero/crds/datauploads.yaml b/packages/system/velero/charts/velero/crds/datauploads.yaml index d17bd138..5a9fc2a6 100644 --- a/packages/system/velero/charts/velero/crds/datauploads.yaml +++ b/packages/system/velero/charts/velero/crds/datauploads.yaml @@ -89,6 +89,9 @@ spec: of the CSI snapshot. nullable: true properties: + driver: + description: Driver is the driver used by the VolumeSnapshotContent + type: string snapshotClass: description: SnapshotClass is the name of the snapshot class that the volume snapshot is created with diff --git a/packages/system/velero/charts/velero/crds/podvolumebackups.yaml b/packages/system/velero/charts/velero/crds/podvolumebackups.yaml index f83ff45f..a232b945 100644 --- a/packages/system/velero/charts/velero/crds/podvolumebackups.yaml +++ b/packages/system/velero/charts/velero/crds/podvolumebackups.yaml @@ -17,38 +17,41 @@ spec: scope: Namespaced versions: - additionalPrinterColumns: - - description: Pod Volume Backup status such as New/InProgress + - description: PodVolumeBackup status such as New/InProgress jsonPath: .status.phase name: Status type: string - - description: Time when this backup was started + - description: Time duration since this PodVolumeBackup was started jsonPath: .status.startTimestamp - name: Created + name: Started type: date - - description: Namespace of the pod containing the volume to be backed up - jsonPath: .spec.pod.namespace - name: Namespace - type: string - - description: Name of the pod containing the volume to be backed up - jsonPath: .spec.pod.name - name: Pod - type: string - - description: Name of the volume to be backed up - jsonPath: .spec.volume - name: Volume - type: string - - description: The type of the uploader to handle data transfer - jsonPath: .spec.uploaderType - name: Uploader Type - type: string + - description: Completed bytes + format: int64 + jsonPath: .status.progress.bytesDone + name: Bytes Done + type: integer + - description: Total bytes + format: int64 + jsonPath: .status.progress.totalBytes + name: Total Bytes + type: integer - description: Name of the Backup Storage Location where this backup should be stored jsonPath: .spec.backupStorageLocation name: Storage Location type: string - - jsonPath: .metadata.creationTimestamp + - description: Time duration since this PodVolumeBackup was created + jsonPath: .metadata.creationTimestamp name: Age type: date + - description: Name of the node where the PodVolumeBackup is processed + jsonPath: .status.node + name: Node + type: string + - description: The type of the uploader to handle data transfer + jsonPath: .spec.uploaderType + name: Uploader + type: string name: v1 schema: openAPIV3Schema: @@ -78,6 +81,11 @@ spec: BackupStorageLocation is the name of the backup storage location where the backup repository is stored. type: string + cancel: + description: |- + Cancel indicates request to cancel the ongoing PodVolumeBackup. It can be set + when the PodVolumeBackup is in InProgress phase + type: boolean node: description: Node is the name of the node that the Pod is running on. @@ -167,6 +175,13 @@ spec: status: description: PodVolumeBackupStatus is the current status of a PodVolumeBackup. properties: + acceptedTimestamp: + description: |- + AcceptedTimestamp records the time the pod volume backup is to be prepared. + The server's time is used for AcceptedTimestamp + format: date-time + nullable: true + type: string completionTimestamp: description: |- CompletionTimestamp records the time a backup was completed. @@ -188,7 +203,11 @@ spec: description: Phase is the current state of the PodVolumeBackup. enum: - New + - Accepted + - Prepared - InProgress + - Canceling + - Canceled - Completed - Failed type: string diff --git a/packages/system/velero/charts/velero/crds/podvolumerestores.yaml b/packages/system/velero/charts/velero/crds/podvolumerestores.yaml index 7bc5edad..1521ec96 100644 --- a/packages/system/velero/charts/velero/crds/podvolumerestores.yaml +++ b/packages/system/velero/charts/velero/crds/podvolumerestores.yaml @@ -17,39 +17,41 @@ spec: scope: Namespaced versions: - additionalPrinterColumns: - - description: Namespace of the pod containing the volume to be restored - jsonPath: .spec.pod.namespace - name: Namespace + - description: PodVolumeRestore status such as New/InProgress + jsonPath: .status.phase + name: Status type: string - - description: Name of the pod containing the volume to be restored - jsonPath: .spec.pod.name - name: Pod + - description: Time duration since this PodVolumeRestore was started + jsonPath: .status.startTimestamp + name: Started + type: date + - description: Completed bytes + format: int64 + jsonPath: .status.progress.bytesDone + name: Bytes Done + type: integer + - description: Total bytes + format: int64 + jsonPath: .status.progress.totalBytes + name: Total Bytes + type: integer + - description: Name of the Backup Storage Location where the backup data is + stored + jsonPath: .spec.backupStorageLocation + name: Storage Location + type: string + - description: Time duration since this PodVolumeRestore was created + jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Name of the node where the PodVolumeRestore is processed + jsonPath: .status.node + name: Node type: string - description: The type of the uploader to handle data transfer jsonPath: .spec.uploaderType name: Uploader Type type: string - - description: Name of the volume to be restored - jsonPath: .spec.volume - name: Volume - type: string - - description: Pod Volume Restore status such as New/InProgress - jsonPath: .status.phase - name: Status - type: string - - description: Pod Volume Restore status such as New/InProgress - format: int64 - jsonPath: .status.progress.totalBytes - name: TotalBytes - type: integer - - description: Pod Volume Restore status such as New/InProgress - format: int64 - jsonPath: .status.progress.bytesDone - name: BytesDone - type: integer - - jsonPath: .metadata.creationTimestamp - name: Age - type: date name: v1 schema: openAPIV3Schema: @@ -79,6 +81,11 @@ spec: BackupStorageLocation is the name of the backup storage location where the backup repository is stored. type: string + cancel: + description: |- + Cancel indicates request to cancel the ongoing PodVolumeRestore. It can be set + when the PodVolumeRestore is in InProgress phase + type: boolean pod: description: Pod is a reference to the pod containing the volume to be restored. @@ -164,6 +171,13 @@ spec: status: description: PodVolumeRestoreStatus is the current status of a PodVolumeRestore. properties: + acceptedTimestamp: + description: |- + AcceptedTimestamp records the time the pod volume restore is to be prepared. + The server's time is used for AcceptedTimestamp + format: date-time + nullable: true + type: string completionTimestamp: description: |- CompletionTimestamp records the time a restore was completed. @@ -176,11 +190,19 @@ spec: description: Message is a message about the pod volume restore's status. type: string + node: + description: Node is name of the node where the pod volume restore + is processed. + type: string phase: description: Phase is the current state of the PodVolumeRestore. enum: - New + - Accepted + - Prepared - InProgress + - Canceling + - Canceled - Completed - Failed type: string diff --git a/packages/system/velero/charts/velero/crds/schedules.yaml b/packages/system/velero/charts/velero/crds/schedules.yaml index f09bdb1a..ed521799 100644 --- a/packages/system/velero/charts/velero/crds/schedules.yaml +++ b/packages/system/velero/charts/velero/crds/schedules.yaml @@ -553,6 +553,10 @@ spec: parallel uploads to perform when using the uploader. type: integer type: object + volumeGroupSnapshotLabelKey: + description: VolumeGroupSnapshotLabelKey specifies the label + key to group PVCs under a VGS. + type: string volumeSnapshotLocations: description: VolumeSnapshotLocations is a list containing names of VolumeSnapshotLocations associated with this backup. diff --git a/packages/system/velero/charts/velero/templates/NOTES.txt b/packages/system/velero/charts/velero/templates/NOTES.txt index d2f0fb79..ea193341 100644 --- a/packages/system/velero/charts/velero/templates/NOTES.txt +++ b/packages/system/velero/charts/velero/templates/NOTES.txt @@ -75,6 +75,22 @@ More info on the official site: https://velero.io/docs {{- end }} {{- end }} +{{- if eq .Values.configuration.uploaderType "restic" }} +{{- $breaking = print $breaking "\n\nERROR: restic uploaderType was removed, please use a different one" }} +{{- end }} + +{{- if hasKey .Values.configuration.repositoryMaintenanceJob "requests" }} +{{- $breaking = print $breaking "\n\nREMOVED: configuration.repositoryMaintenanceJob.requests has been removed, please use the configmap" }} +{{- end }} + +{{- if hasKey .Values.configuration.repositoryMaintenanceJob "limits" }} +{{- $breaking = print $breaking "\n\nREMOVED: configuration.repositoryMaintenanceJob.limits has been removed, please use the configmap" }} +{{- end }} + +{{- if hasKey .Values.configuration.repositoryMaintenanceJob "latestJobsCount" }} +{{- $breaking = print $breaking "\n\nREMOVED: configuration.repositoryMaintenanceJob.latestJobsCount has been removed, please use the configmap" }} +{{- end }} + {{- if $breaking }} {{- fail (print $breaking_title $breaking) }} {{- end }} diff --git a/packages/system/velero/charts/velero/templates/deployment.yaml b/packages/system/velero/charts/velero/templates/deployment.yaml index 5789542b..d2a72639 100644 --- a/packages/system/velero/charts/velero/templates/deployment.yaml +++ b/packages/system/velero/charts/velero/templates/deployment.yaml @@ -3,7 +3,7 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ include "velero.fullname" . }} + name: velero namespace: {{ .Release.Namespace }} {{- with .Values.annotations }} annotations: @@ -21,7 +21,7 @@ metadata: {{- end }} spec: replicas: 1 - {{- if .Values.revisionHistoryLimit }} + {{- if hasKey .Values "revisionHistoryLimit" }} revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} {{- end }} strategy: @@ -57,7 +57,7 @@ spec: {{- end }} {{- end }} spec: - {{- with .Values.hostAliases -}} + {{- with .Values.hostAliases }} hostAliases: {{- toYaml . | nindent 8 }} {{- end }} @@ -180,24 +180,9 @@ spec: - --namespace={{ . }} {{- end }} {{- with .repositoryMaintenanceJob }} - {{- with .requests }} - {{- with .cpu }} - - --maintenance-job-cpu-request={{ . }} - {{- end }} - {{- with .memory }} - - --maintenance-job-mem-request={{ . }} - {{- end }} - {{- end }} - {{- with .limits }} - {{- with .cpu }} - - --maintenance-job-cpu-limit={{ . }} - {{- end }} - {{- with .memory }} - - --maintenance-job-mem-limit={{ . }} - {{- end }} - {{- end }} - {{- with .latestJobsCount }} - - --keep-latest-maintenance-jobs={{ . }} + {{- if and .repositoryConfigData (or .repositoryConfigData.global .repositoryConfigData.repositories) }} + - --repo-maintenance-job-configmap={{ default "velero-repo-maintenance" .repositoryConfigData.name }} + {{- else }} {{- end }} {{- end }} {{- with .extraArgs }} @@ -209,6 +194,10 @@ spec: resources: {{- toYaml . | nindent 12 }} {{- end }} + {{- with .Values.resizePolicy }} + resizePolicy: + {{- toYaml . | nindent 12 }} + {{- end }} {{- if .Values.metrics.enabled }} {{- with .Values.livenessProbe }} livenessProbe: {{- toYaml . | nindent 12 }} diff --git a/packages/system/velero/charts/velero/templates/label-namespace/labelnamespace.yaml b/packages/system/velero/charts/velero/templates/label-namespace/labelnamespace.yaml index de64ce67..2c78fa53 100644 --- a/packages/system/velero/charts/velero/templates/label-namespace/labelnamespace.yaml +++ b/packages/system/velero/charts/velero/templates/label-namespace/labelnamespace.yaml @@ -31,8 +31,8 @@ spec: - /bin/sh - -c - | - {{- range .Values.namespace.labels }} - kubectl label namespace {{ $.Release.Namespace }} {{ .key }}={{ .value }} + {{- range $key, $value := .Values.namespace.labels }} + kubectl label namespace {{ $.Release.Namespace }} {{ $key }}={{ $value }} {{- end }} {{- if .Values.kubectl.extraVolumeMounts }} volumeMounts: diff --git a/packages/system/velero/charts/velero/templates/node-agent-daemonset.yaml b/packages/system/velero/charts/velero/templates/node-agent-daemonset.yaml index 03e5cdd0..597ca459 100644 --- a/packages/system/velero/charts/velero/templates/node-agent-daemonset.yaml +++ b/packages/system/velero/charts/velero/templates/node-agent-daemonset.yaml @@ -49,7 +49,7 @@ spec: {{- end }} {{- end }} spec: - {{ with .Values.hostAliases -}} + {{- with .Values.nodeAgent.hostAliases }} hostAliases: {{- toYaml . | nindent 8 }} {{- end }} @@ -68,7 +68,7 @@ spec: {{- if .Values.nodeAgent.priorityClassName }} priorityClassName: {{ include "velero.nodeAgent.priorityClassName" . }} {{- end }} - {{- if .Values.runtimeClassName }} + {{- if .Values.nodeAgent.runtimeClassName }} runtimeClassName: {{ include "velero.nodeAgent.runtimeClassName" . }} {{- end }} terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} @@ -197,6 +197,10 @@ spec: resources: {{- toYaml . | nindent 12 }} {{- end }} + {{- with .Values.nodeAgent.resizePolicy }} + resizePolicy: + {{- toYaml . | nindent 12 }} + {{- end }} {{- with .Values.nodeAgent.tolerations }} tolerations: {{- toYaml . | nindent 8 }} diff --git a/packages/system/velero/charts/velero/templates/repo-maintenance-configmap.yaml b/packages/system/velero/charts/velero/templates/repo-maintenance-configmap.yaml new file mode 100644 index 00000000..25c0c373 --- /dev/null +++ b/packages/system/velero/charts/velero/templates/repo-maintenance-configmap.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.configuration .Values.configuration.repositoryMaintenanceJob .Values.configuration.repositoryMaintenanceJob.repositoryConfigData (or .Values.configuration.repositoryMaintenanceJob.repositoryConfigData.global .Values.configuration.repositoryMaintenanceJob.repositoryConfigData.repositories) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ default "velero-repo-maintenance" .Values.configuration.repositoryMaintenanceJob.repositoryConfigData.name }} + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ include "velero.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + helm.sh/chart: {{ include "velero.chart" . }} +data: + {{- with .Values.configuration.repositoryMaintenanceJob.repositoryConfigData.global }} + global: | + {{- . | toPrettyJson | nindent 4 }} + {{- end }} + {{- range $repoKey, $repoConfig := .Values.configuration.repositoryMaintenanceJob.repositoryConfigData.repositories }} + {{ $repoKey }}: | + {{- $repoConfig | toPrettyJson | nindent 4 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/packages/system/velero/charts/velero/templates/service.yaml b/packages/system/velero/charts/velero/templates/service.yaml index 7cccbc54..662ca646 100644 --- a/packages/system/velero/charts/velero/templates/service.yaml +++ b/packages/system/velero/charts/velero/templates/service.yaml @@ -23,6 +23,12 @@ spec: {{- if .Values.metrics.service.internalTrafficPolicy }} internalTrafficPolicy: {{ .Values.metrics.service.internalTrafficPolicy }} {{- end }} + {{- if .Values.metrics.service.ipFamilyPolicy }} + ipFamilyPolicy: {{ .Values.metrics.service.ipFamilyPolicy }} + {{- end }} + {{- if .Values.metrics.service.ipFamilies }} + ipFamilies: {{ toYaml .Values.metrics.service.ipFamilies | nindent 4 }} + {{- end }} type: {{ .Values.metrics.service.type }} ports: - name: http-monitoring diff --git a/packages/system/velero/charts/velero/values.schema.json b/packages/system/velero/charts/velero/values.schema.json index d23009d4..367e0d8c 100644 --- a/packages/system/velero/charts/velero/values.schema.json +++ b/packages/system/velero/charts/velero/values.schema.json @@ -105,7 +105,7 @@ "type": "string" }, "initContainers": { - "type": ["array", "null"], + "type": ["array", "string", "null"], "items": {} }, "podSecurityContext": { @@ -367,10 +367,10 @@ "type": ["string", "null"] }, "provider": { - "type": ["string", "null"] + "type": ["string"] }, "bucket": { - "type": ["string", "null"] + "type": ["string"] }, "caCert": { "type": ["string", "null"] @@ -405,8 +405,7 @@ }, "required": [ "provider", - "bucket", - "config" + "bucket" ] } }, @@ -419,7 +418,7 @@ "type": ["string", "null"] }, "provider": { - "type": ["string", "null"] + "type": ["string"] }, "credential": { "type": "object", @@ -438,9 +437,7 @@ } }, "required": [ - "name", - "provider", - "config" + "provider" ] } }, @@ -473,6 +470,80 @@ }, "latestJobsCount": { "type": "number" + }, + "repositoryConfigData": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the ConfigMap to create for per-repository maintenance configuration" + }, + "global": { + "type": "object", + "description": "Global configuration applied to all repositories when no specific repository configuration is found", + "properties": { + "podResources": { + "type": "object", + "properties": { + "cpuRequest": {"type": "string"}, + "cpuLimit": {"type": "string"}, + "memoryRequest": {"type": "string"}, + "memoryLimit": {"type": "string"} + } + }, + "keepLatestMaintenanceJobs": { + "type": "number" + }, + "priorityClassName": { + "type": "string" + }, + "loadAffinity": { + "type": "array", + "items": { + "type": "object", + "properties": { + "nodeSelector": { + "type": "object" + } + } + } + } + } + }, + "repositories": { + "type": "object", + "description": "Repository-specific configurations keyed by repository identifier (namespace-storageLocation-repositoryType)", + "additionalProperties": { + "type": "object", + "properties": { + "podResources": { + "type": "object", + "properties": { + "cpuRequest": {"type": "string"}, + "cpuLimit": {"type": "string"}, + "memoryRequest": {"type": "string"}, + "memoryLimit": {"type": "string"} + } + }, + "keepLatestMaintenanceJobs": { + "type": "number" + }, + "loadAffinity": { + "type": "array", + "items": { + "type": "object", + "properties": { + "nodeSelector": { + "type": "object" + } + } + } + } + } + } + } + }, + "required": [] } }, "required": [] @@ -688,7 +759,6 @@ }, "required": [ "podVolumePath", - "pluginVolumePath", "dnsPolicy" ] }, @@ -732,4 +802,4 @@ ] } } -} \ No newline at end of file +} diff --git a/packages/system/velero/charts/velero/values.yaml b/packages/system/velero/charts/velero/values.yaml index 659d0034..00ec9380 100644 --- a/packages/system/velero/charts/velero/values.yaml +++ b/packages/system/velero/charts/velero/values.yaml @@ -7,18 +7,12 @@ namespace: labels: {} # Enforce Pod Security Standards with Namespace Labels # https://kubernetes.io/docs/tasks/configure-pod-container/enforce-standards-namespace-labels/ - # - key: pod-security.kubernetes.io/enforce - # value: privileged - # - key: pod-security.kubernetes.io/enforce-version - # value: latest - # - key: pod-security.kubernetes.io/audit - # value: privileged - # - key: pod-security.kubernetes.io/audit-version - # value: latest - # - key: pod-security.kubernetes.io/warn - # value: privileged - # - key: pod-security.kubernetes.io/warn-version - # value: latest + # pod-security.kubernetes.io/enforce: privileged + # pod-security.kubernetes.io/enforce-version: latest + # pod-security.kubernetes.io/audit: privileged + # pod-security.kubernetes.io/audit-version: latest + # pod-security.kubernetes.io/warn: privileged + # pod-security.kubernetes.io/warn-version: latest ## ## End of namespace-related settings. @@ -33,7 +27,7 @@ namespace: # enabling node-agent). Required. image: repository: velero/velero - tag: v1.16.1 + tag: v1.17.0 # Digest value example: sha256:d238835e151cec91c6a811fe3a89a66d3231d9f64d09e5f3c49552672d271f38. # If used, it will take precedence over the image.tag. # digest: @@ -81,6 +75,14 @@ resources: {} # cpu: 1000m # memory: 512Mi +# Container resize policy for the Velero deployment. +# See: https://kubernetes.io/docs/tasks/configure-pod-container/resize-container-resources/ +resizePolicy: [] + # - resourceName: cpu + # restartPolicy: NotRequired + # - resourceName: memory + # restartPolicy: RestartContainer + # Configure hostAliases for Velero deployment. Optional # For more information, check: https://kubernetes.io/docs/tasks/network/customize-hosts-file-for-pods/ hostAliases: [] @@ -128,7 +130,7 @@ dnsPolicy: ClusterFirst # If the value is a string then it is evaluated as a template. initContainers: # - name: velero-plugin-for-aws - # image: velero/velero-plugin-for-aws:v1.12.1 + # image: velero/velero-plugin-for-aws:v1.13.0 # imagePullPolicy: IfNotPresent # volumeMounts: # - mountPath: /target @@ -247,6 +249,11 @@ metrics: externalTrafficPolicy: "" internalTrafficPolicy: "" + # the IP family policy for the metrics Service to be able to configure dual-stack; see [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services). + ipFamilyPolicy: "" + # a list of IP families for the metrics Service that should be supported, in the order in which they should be applied to ClusterIP. Can be "IPv4" and/or "IPv6". + ipFamilies: [] + # Pod annotations for Prometheus podAnnotations: prometheus.io/scrape: "true" @@ -291,31 +298,52 @@ metrics: # namespace: "" # Rules to be deployed spec: [] - # - alert: VeleroBackupPartialFailures + # - alert: VeleroBackupFailed # annotations: - # message: Velero backup {{ $labels.schedule }} has {{ $value | humanizePercentage }} partialy failed backups. + # message: Velero backup {{ $labels.schedule }} has failed # expr: |- - # velero_backup_partial_failure_total{schedule!=""} / velero_backup_attempt_total{schedule!=""} > 0.25 + # velero_backup_last_status{schedule!=""} != 1 # for: 15m # labels: # severity: warning - # - alert: VeleroBackupFailures + # - alert: VeleroBackupFailing # annotations: - # message: Velero backup {{ $labels.schedule }} has {{ $value | humanizePercentage }} failed backups. + # message: Velero backup {{ $labels.schedule }} has been failing for the last 12h # expr: |- - # velero_backup_failure_total{schedule!=""} / velero_backup_attempt_total{schedule!=""} > 0.25 + # velero_backup_last_status{schedule!=""} != 1 + # for: 12h + # labels: + # severity: critical + # - alert: VeleroNoNewBackup + # annotations: + # message: Velero backup {{ $labels.schedule }} has not run successfuly in the last 30h + # expr: |- + # ( + # rate(velero_backup_last_successful_timestamp{schedule!=""}[15m]) <=bool 0 + # or + # absent(velero_backup_last_successful_timestamp{schedule!=""}) + # ) == 1 + # for: 30h + # labels: + # severity: critical + # - alert: VeleroBackupPartialFailures + # annotations: + # message: Velero backup {{ $labels.schedule }} has {{ $value | humanizePercentage }} partialy failed backups + # expr: |- + # rate(velero_backup_partial_failure_total{schedule!=""}[25m]) + # / rate(velero_backup_attempt_total{schedule!=""}[25m]) > 0.5 # for: 15m # labels: # severity: warning kubectl: image: - repository: docker.io/bitnami/kubectl + repository: alpine/k8s # Digest value example: sha256:d238835e151cec91c6a811fe3a89a66d3231d9f64d09e5f3c49552672d271f38. # If used, it will take precedence over the kubectl.image.tag. # digest: # kubectl image tag. If used, it will take precedence over the cluster Kubernetes version. - # tag: 1.16.15 + tag: "1.35.0" # Container Level Security Context for the 'kubectl' container of the crd jobs. Optional. # See: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container containerSecurityContext: {} @@ -354,9 +382,9 @@ configuration: # a backup storage location will be created with the name "default". Optional. - name: # provider is the name for the backup storage location provider. - provider: + provider: "" # bucket is the name of the bucket to store backups in. Required. - bucket: + bucket: "" # caCert defines a base64 encoded CA bundle to use when verifying TLS connections to the provider. Optional. caCert: # prefix is the directory under which all Velero data should be stored within the bucket. Optional. @@ -398,10 +426,11 @@ configuration: # Parameters for the VolumeSnapshotLocation(s). Configure multiple by adding other element(s) to the volumeSnapshotLocation slice. # See https://velero.io/docs/v1.6/api-types/volumesnapshotlocation/ volumeSnapshotLocation: - # name is the name of the volume snapshot location where snapshots are being taken. Required. + # name is the name of the volume snapshot location where snapshots are being taken. If a name is not provided, + # a volume snapshot location will be created with the name "default". Optional. - name: # provider is the name for the volume snapshot provider. - provider: + provider: "" credential: # name of the secret used by this volumeSnapshotLocation. name: @@ -483,14 +512,48 @@ configuration: # Resource requests/limits to specify for the repository-maintenance job. Optional. # https://velero.io/docs/v1.14/repository-maintenance/#resource-limitation repositoryMaintenanceJob: - requests: - # cpu: 500m - # memory: 512Mi - limits: - # cpu: 1000m - # memory: 1024Mi - # Number of latest maintenance jobs to keep for each repository - latestJobsCount: 3 + # Per-repository resource settings ConfigMap + # This ConfigMap allows specifying different settings for different repositories + # See: https://velero.io/docs/main/repository-maintenance/ + repositoryConfigData: + # Name of the ConfigMap to create. If not provided, will use "velero-repo-maintenance" + name: "velero-repo-maintenance" + # Global configuration applied to all repositories + # This configuration is used when no specific repository configuration is found + # global: + # podResources: + # cpuRequest: "100m" + # cpuLimit: "200m" + # memoryRequest: "100Mi" + # memoryLimit: "200Mi" + # keepLatestMaintenanceJobs: 1 + # loadAffinity: + # - nodeSelector: + # matchExpressions: + # - key: "cloud.google.com/machine-family" + # operator: "In" + # values: ["e2"] + # - nodeSelector: + # matchExpressions: + # - key: "topology.kubernetes.io/zone" + # operator: "In" + # values: ["us-central1-a", "us-central1-b", "us-central1-c"] + # priorityClassName: "low-priority" # Note: priorityClassName is only supported in global configuration + global: + keepLatestMaintenanceJobs: 3 + # Repository-specific configurations + # Repository keys are formed as: "{namespace}-{storageLocation}-{repositoryType}" + # For example: "default-default-kopia" or "prod-s3-backup-kopia" + # Note: priorityClassName is NOT supported in repository-specific configurations + # repositories: + # "kibishii-default-kopia": + # podResources: + # cpuRequest: "200m" + # cpuLimit: "400m" + # memoryRequest: "200Mi" + # memoryLimit: "400Mi" + # keepLatestMaintenanceJobs: 2 + repositories: {} # `velero server` default: velero namespace: # additional command-line arguments that will be passed to the `velero server` @@ -601,6 +664,13 @@ nodeAgent: # limits: # cpu: 1000m # memory: 1024Mi + # Container resize policy for the node-agent daemonset. + # See: https://kubernetes.io/docs/tasks/configure-pod-container/resize-container-resources/ + resizePolicy: [] + # - resourceName: cpu + # restartPolicy: NotRequired + # - resourceName: memory + # restartPolicy: RestartContainer # Tolerations to use for the node-agent daemonset. Optional. tolerations: [] @@ -714,7 +784,7 @@ schedules: {} # velero.io/plugin-config: "" # velero.io/pod-volume-restore: RestoreItemAction # data: -# image: velero/velero-restore-helper:v1.10.2 +# image: velero/velero:v1.17.0 # cpuRequest: 200m # memRequest: 128Mi # cpuLimit: 200m diff --git a/packages/system/velero/templates/backupstrategy-controller-rbac.yaml b/packages/system/velero/templates/backupstrategy-controller-rbac.yaml new file mode 100644 index 00000000..43c51cd7 --- /dev/null +++ b/packages/system/velero/templates/backupstrategy-controller-rbac.yaml @@ -0,0 +1,26 @@ +# Grants the backupstrategy-controller permission to manage ResourceModifier +# ConfigMaps in the Velero install namespace. Lives here (not in the +# backupstrategy-controller chart) so that the Role is only created when +# velero is actually installed — otherwise the chart would try to create it +# in a namespace that does not exist. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: backups.cozystack.io:strategy-controller:velero-configmaps +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "list", "delete", "deletecollection", "patch", "update"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: backups.cozystack.io:strategy-controller:velero-configmaps +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: backups.cozystack.io:strategy-controller:velero-configmaps +subjects: +- kind: ServiceAccount + name: backupstrategy-controller + namespace: cozy-backup-controller diff --git a/packages/system/velero/values.yaml b/packages/system/velero/values.yaml index 8a03f67b..e15240d3 100644 --- a/packages/system/velero/values.yaml +++ b/packages/system/velero/values.yaml @@ -1,4 +1,7 @@ velero: + # Disable CRD upgrade job - CRDs are installed as part of helm chart + # The upgrade job has issues with kubectl image compatibility + upgradeCRDs: false initContainers: - name: velero-plugin-for-aws image: velero/velero-plugin-for-aws:v1.12.1 @@ -6,10 +9,20 @@ velero: volumeMounts: - mountPath: /target name: plugins - # deployNodeAgent: true + - image: quay.io/kubevirt/kubevirt-velero-plugin:v0.8.0 + name: kubevirt-kubevirt-velero-plugin + imagePullPolicy: IfNotPresent + volumeMounts: + - mountPath: /target + name: plugins + + deployNodeAgent: true configuration: # defaultVolumesToFsBackup: true backupStorageLocation: null volumeSnapshotLocation: null namespace: cozy-velero features: EnableCSI + # Increase timeout for item operations to 24 hours to prevent timeouts + # during backups of very large volumes. The Velero default is 4 hours. + defaultItemOperationTimeout: 24h diff --git a/packages/system/vertical-pod-autoscaler-crds/Makefile b/packages/system/vertical-pod-autoscaler-crds/Makefile index 9290640e..52b84278 100644 --- a/packages/system/vertical-pod-autoscaler-crds/Makefile +++ b/packages/system/vertical-pod-autoscaler-crds/Makefile @@ -1,7 +1,7 @@ export NAME=vertical-pod-autoscaler export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: curl -o ./templates/vpa-v1-crd-gen.yaml https://raw.githubusercontent.com/kubernetes/autoscaler/refs/heads/master/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml diff --git a/packages/system/vertical-pod-autoscaler/Makefile b/packages/system/vertical-pod-autoscaler/Makefile index 389f9c6e..1e5372e1 100644 --- a/packages/system/vertical-pod-autoscaler/Makefile +++ b/packages/system/vertical-pod-autoscaler/Makefile @@ -1,7 +1,7 @@ export NAME=vertical-pod-autoscaler export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts diff --git a/packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml b/packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml new file mode 100644 index 00000000..2df053b5 --- /dev/null +++ b/packages/system/vertical-pod-autoscaler/templates/vpa-for-vpa.yaml @@ -0,0 +1,81 @@ +{{- if .Values.vpaForVPA }} +--- +apiVersion: v1 +kind: Namespace +metadata: + labels: + cozystack.io/system: "true" + name: cozy-vpa-for-vpa +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + labels: + cozystack.io/repository: system + cozystack.io/system-app: "true" + name: vpa-for-vpa + namespace: cozy-vpa-for-vpa +spec: + chartRef: + kind: ExternalArtifact + name: cozystack-vertical-pod-autoscaler-default-vpa-for-vpa + namespace: cozy-system + dependsOn: + - name: monitoring-agents + namespace: cozy-monitoring + install: + crds: Skip + remediation: + retries: -1 + interval: 5m + releaseName: vertical-pod-autoscaler + upgrade: + crds: Skip + remediation: + retries: -1 + values: + vpaForVPA: false + vertical-pod-autoscaler: + nameOverride: vpa-for-vpa + fullnameOverride: vpa-for-vpa + admissionController: + enabled: false + recommender: + extraArgs: + vpa-object-namespace: {{ .Release.Namespace }} + recommender-name: vpa-for-vpa + resources: + limits: + memory: 512Mi + requests: + cpu: 100m + memory: 512Mi +--- +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: vpa-for-vpa + namespace: {{ .Release.Namespace }} +spec: + recommenders: + - name: vpa-for-vpa + targetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ dig "vertical-pod-autoscaler" "nameOverride" "" .Values.AsMap | default "vertical-pod-autoscaler" | trunc 63 | trimSuffix "-" }}-recommender + updatePolicy: + updateMode: Auto +--- +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: vpa-for-vpa + namespace: cozy-vpa-for-vpa +spec: + targetRef: + apiVersion: apps/v1 + kind: Deployment + name: vpa-for-vpa-recommender + updatePolicy: + updateMode: Auto +{{- end }} diff --git a/packages/system/vertical-pod-autoscaler/values.yaml b/packages/system/vertical-pod-autoscaler/values.yaml index df4a5d10..51327531 100644 --- a/packages/system/vertical-pod-autoscaler/values.yaml +++ b/packages/system/vertical-pod-autoscaler/values.yaml @@ -1,7 +1,14 @@ +vpaForVPA: true + vertical-pod-autoscaler: crds: enabled: false + image: + registry: docker.io + repository: alpine/k8s + tag: 1.33.4 + updater: resources: limits: @@ -23,12 +30,6 @@ vertical-pod-autoscaler: pod-namespace-label: namespace prometheus-address: http://vmselect-shortterm.tenant-root.svc.cozy.local:8481/select/0/prometheus/ prometheus-cadvisor-job-name: cadvisor - resources: - limits: - memory: 160Mi - requests: - cpu: 100m - memory: 160Mi admissionController: resources: diff --git a/packages/system/victoria-metrics-operator/Makefile b/packages/system/victoria-metrics-operator/Makefile index 0f31d7b7..bb57f807 100644 --- a/packages/system/victoria-metrics-operator/Makefile +++ b/packages/system/victoria-metrics-operator/Makefile @@ -1,7 +1,7 @@ export NAME=victoria-metrics-operator export NAMESPACE=cozy-$(NAME) -include ../../../scripts/package.mk +include ../../../hack/package.mk update: rm -rf charts @@ -9,8 +9,4 @@ update: helm repo add vm https://victoriametrics.github.io/helm-charts/ helm repo update vm helm pull vm/victoria-metrics-operator --untar --untardir charts - # Prometheus CRDs - helm repo add prometheus-community https://prometheus-community.github.io/helm-charts - helm repo update prometheus-community - helm pull prometheus-community/prometheus-operator-crds --untar --untardir charts - rm -f -- `find charts/prometheus-operator-crds/charts/crds/templates -maxdepth 1 -mindepth 1 | grep -v 'servicemonitor\|podmonitor\|prometheusrule\|probe'` + patch --no-backup-if-mismatch -p4 < patches/disable-ca-key-rotation.patch diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-prometheusrules.yaml b/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-prometheusrules.yaml deleted file mode 100644 index dd13e8fd..00000000 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/charts/crds/templates/crd-prometheusrules.yaml +++ /dev/null @@ -1,163 +0,0 @@ -# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.81.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: -{{- with .Values.annotations }} -{{- toYaml . | nindent 4 }} -{{- end }} - controller-gen.kubebuilder.io/version: v0.17.2 - operator.prometheus.io/version: 0.81.0 - name: prometheusrules.monitoring.coreos.com -spec: - group: monitoring.coreos.com - names: - categories: - - prometheus-operator - kind: PrometheusRule - listKind: PrometheusRuleList - plural: prometheusrules - shortNames: - - promrule - singular: prometheusrule - scope: Namespaced - versions: - - name: v1 - schema: - openAPIV3Schema: - description: |- - The `PrometheusRule` custom resource definition (CRD) defines [alerting](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/) and [recording](https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/) rules to be evaluated by `Prometheus` or `ThanosRuler` objects. - - `Prometheus` and `ThanosRuler` objects select `PrometheusRule` objects using label and namespace selectors. - 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: Specification of desired alerting rule definitions for Prometheus. - properties: - groups: - description: Content of Prometheus rule file - items: - description: RuleGroup is a list of sequentially evaluated recording - and alerting rules. - properties: - interval: - description: Interval determines how often rules in the group - are evaluated. - pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ - type: string - labels: - additionalProperties: - type: string - description: |- - Labels to add or overwrite before storing the result for its rules. - The labels defined at the rule level take precedence. - - It requires Prometheus >= 3.0.0. - The field is ignored for Thanos Ruler. - type: object - limit: - description: |- - Limit the number of alerts an alerting rule and series a recording - rule can produce. - Limit is supported starting with Prometheus >= 2.31 and Thanos Ruler >= 0.24. - type: integer - name: - description: Name of the rule group. - minLength: 1 - type: string - partial_response_strategy: - description: |- - PartialResponseStrategy is only used by ThanosRuler and will - be ignored by Prometheus instances. - More info: https://github.com/thanos-io/thanos/blob/main/docs/components/rule.md#partial-response - pattern: ^(?i)(abort|warn)?$ - type: string - query_offset: - description: |- - Defines the offset the rule evaluation timestamp of this particular group by the specified duration into the past. - - It requires Prometheus >= v2.53.0. - It is not supported for ThanosRuler. - pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ - type: string - rules: - description: List of alerting and recording rules. - items: - description: |- - Rule describes an alerting or recording rule - See Prometheus documentation: [alerting](https://www.prometheus.io/docs/prometheus/latest/configuration/alerting_rules/) or [recording](https://www.prometheus.io/docs/prometheus/latest/configuration/recording_rules/#recording-rules) rule - properties: - alert: - description: |- - Name of the alert. Must be a valid label value. - Only one of `record` and `alert` must be set. - type: string - annotations: - additionalProperties: - type: string - description: |- - Annotations to add to each alert. - Only valid for alerting rules. - type: object - expr: - anyOf: - - type: integer - - type: string - description: PromQL expression to evaluate. - x-kubernetes-int-or-string: true - for: - description: Alerts are considered firing once they have - been returned for this long. - pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ - type: string - keep_firing_for: - description: KeepFiringFor defines how long an alert will - continue firing after the condition that triggered it - has cleared. - minLength: 1 - pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ - type: string - labels: - additionalProperties: - type: string - description: Labels to add or overwrite. - type: object - record: - description: |- - Name of the time series to output to. Must be a valid metric name. - Only one of `record` and `alert` must be set. - type: string - required: - - expr - type: object - type: array - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - required: - - spec - type: object - served: true - storage: true diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/hack/update_crds.sh b/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/hack/update_crds.sh deleted file mode 100644 index d950ec16..00000000 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/hack/update_crds.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) - -if [[ $(uname -s) = "Darwin" ]]; then - VERSION="$(grep ^appVersion "${SCRIPT_DIR}/../Chart.yaml" | sed 's/appVersion: //g')" -else - VERSION="$(grep ^appVersion "${SCRIPT_DIR}/../Chart.yaml" | sed 's/appVersion:\s//g')" -fi - -FILES=( - "crd-alertmanagerconfigs.yaml : monitoring.coreos.com_alertmanagerconfigs.yaml" - "crd-alertmanagers.yaml : monitoring.coreos.com_alertmanagers.yaml" - "crd-podmonitors.yaml : monitoring.coreos.com_podmonitors.yaml" - "crd-probes.yaml : monitoring.coreos.com_probes.yaml" - "crd-prometheusagents.yaml : monitoring.coreos.com_prometheusagents.yaml" - "crd-prometheuses.yaml : monitoring.coreos.com_prometheuses.yaml" - "crd-prometheusrules.yaml : monitoring.coreos.com_prometheusrules.yaml" - "crd-scrapeconfigs.yaml : monitoring.coreos.com_scrapeconfigs.yaml" - "crd-servicemonitors.yaml : monitoring.coreos.com_servicemonitors.yaml" - "crd-thanosrulers.yaml : monitoring.coreos.com_thanosrulers.yaml" -) - -for line in "${FILES[@]}"; do - DESTINATION=$(echo "${line%%:*}" | xargs) - SOURCE=$(echo "${line##*:}" | xargs) - - URL="https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/$VERSION/example/prometheus-operator-crd/$SOURCE" - - echo -e "Downloading Prometheus Operator CRD with Version ${VERSION}:\n${URL}\n" - - echo "# ${URL}" > "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" - - if ! curl --silent --retry-all-errors --fail --location "${URL}" >> "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}"; then - echo -e "Failed to download ${URL}!" - exit 1 - fi - - # Update or insert annotations block - if yq -e '.metadata.annotations' "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" >/dev/null; then - sed -i '/^ annotations:$/a {{- with .Values.annotations }}\n{{- toYaml . | nindent 4 }}\n{{- end }}' "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" - else - sed -i '/^metadata:$/a {{- with .Values.annotations }}\n annotations:\n{{- toYaml . | nindent 4 }}\n{{- end }}' "${SCRIPT_DIR}/../charts/crds/templates/${DESTINATION}" - fi -done diff --git a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/values.yaml b/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/values.yaml deleted file mode 100644 index 7990c631..00000000 --- a/packages/system/victoria-metrics-operator/charts/prometheus-operator-crds/values.yaml +++ /dev/null @@ -1,4 +0,0 @@ -## Annotations for CRDs -## -crds: - annotations: {} diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/.helmignore b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/.helmignore index 2ccbd54f..a181e3c7 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/.helmignore +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/.helmignore @@ -20,5 +20,10 @@ .idea/ *.tmproj .vscode/ -*.md *.md.gotmpl +CHANGELOG.md +_changelog.md +_index.md +e2e/ +lint/ +tests/ diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/Chart.lock b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/Chart.lock index 6c7b4c55..2868e66f 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/Chart.lock +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/Chart.lock @@ -1,9 +1,9 @@ dependencies: - name: victoria-metrics-common - repository: https://victoriametrics.github.io/helm-charts - version: 0.0.42 + repository: oci://ghcr.io/victoriametrics/helm-charts + version: 0.3.0 - name: crds repository: "" version: 0.0.* -digest: sha256:d186ad6f54d64a2f828cd80a136e06dcf1f30dbc8ae94964bb9b166ee32eb30e -generated: "2025-03-19T09:59:22.84209872Z" +digest: sha256:adec954bf2814f744f5b69fcf67c8b246bf21f416adb0ab37d91c9b42f72d353 +generated: "2026-04-16T10:14:10.795552631Z" diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/Chart.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/Chart.yaml index b6574d02..030af8f0 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/Chart.yaml +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/Chart.yaml @@ -1,7 +1,7 @@ annotations: artifacthub.io/category: monitoring-logging artifacthub.io/changes: | - - updates operator to [v0.55.0](https://github.com/VictoriaMetrics/operator/releases/tag/v0.55.0) version + - revert change in Deployment's matchLabels, that was introduced in release 0.60.0 artifacthub.io/license: Apache-2.0 artifacthub.io/links: | - name: Sources @@ -9,21 +9,26 @@ annotations: - name: Charts repo url: https://victoriametrics.github.io/helm-charts/ - name: Docs - url: https://docs.victoriametrics.com/operator + url: https://docs.victoriametrics.com/operator/ - name: Changelog - url: https://docs.victoriametrics.com/operator/changelog + url: https://docs.victoriametrics.com/operator/changelog/ artifacthub.io/operator: "true" + artifacthub.io/readme: | + # VictoriaMetrics Operator Helm chart + + Chart documentation is available [here](https://docs.victoriametrics.com/helm/victoria-metrics-operator/). + Changelog is [here](https://docs.victoriametrics.com/helm/victoria-metrics-operator/changelog/). apiVersion: v2 -appVersion: v0.55.0 +appVersion: v0.68.4 dependencies: - name: victoria-metrics-common - repository: https://victoriametrics.github.io/helm-charts - version: 0.0.* + repository: oci://ghcr.io/victoriametrics/helm-charts + version: 0.3.* - condition: crds.plain name: crds repository: "" version: 0.0.* -description: Victoria Metrics Operator +description: VictoriaMetrics Operator home: https://github.com/VictoriaMetrics/operator icon: https://avatars.githubusercontent.com/u/43720803?s=200&v=4 keywords: @@ -42,4 +47,4 @@ sources: - https://github.com/VictoriaMetrics/helm-charts - https://github.com/VictoriaMetrics/operator type: application -version: 0.44.0 +version: 0.61.0 diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/README.md b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/README.md new file mode 100644 index 00000000..6a080424 --- /dev/null +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/README.md @@ -0,0 +1,4 @@ +# VictoriaMetrics Operator Helm chart + +Chart documentation is available [here](https://docs.victoriametrics.com/helm/victoria-metrics-operator/). +Changelog is [here](https://docs.victoriametrics.com/helm/victoria-metrics-operator/changelog/). diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/RELEASE_NOTES b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/RELEASE_NOTES index 55ceea77..3529783a 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/RELEASE_NOTES +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/RELEASE_NOTES @@ -1,7 +1,7 @@ -# Release notes for version 0.44.0 +# Release notes for version 0.61.0 -**Release date:** 02 Apr 2025 +**Release date:** 16 Apr 2026 -![Helm: v3](https://img.shields.io/badge/Helm-v3.14%2B-informational?color=informational&logo=helm&link=https%3A%2F%2Fgithub.com%2Fhelm%2Fhelm%2Freleases%2Ftag%2Fv3.14.0) ![AppVersion: v0.55.0](https://img.shields.io/badge/v0.55.0-success?logo=VictoriaMetrics&labelColor=gray&link=https%3A%2F%2Fdocs.victoriametrics.com%2Foperator%2Fchangelog%23v0550) +![Helm: v3](https://img.shields.io/badge/Helm-v3.14%2B-informational?color=informational&logo=helm&link=https%3A%2F%2Fgithub.com%2Fhelm%2Fhelm%2Freleases%2Ftag%2Fv3.14.0) ![AppVersion: v0.68.4](https://img.shields.io/badge/v0.68.4-success?logo=VictoriaMetrics&labelColor=gray&link=https%3A%2F%2Fdocs.victoriametrics.com%2Foperator%2Fchangelog%2F%23v0684) -- updates operator to [v0.55.0](https://github.com/VictoriaMetrics/operator/releases/tag/v0.55.0) version +- revert change in Deployment's matchLabels, that was introduced in release 0.60.0 diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/README.md b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/README.md new file mode 100644 index 00000000..e2bc8e0b --- /dev/null +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/README.md @@ -0,0 +1,9 @@ +--- +build: + list: never + publishResources: false + render: never +sitemap: + disable: true +--- +# Subchart for VictoriaMetrics Operator CRDs diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/crds/crd.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/crds/crd.yaml index 038cc276..bdf7e8d0 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/crds/crd.yaml +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/crds/crd.yaml @@ -2,7 +2,3185 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 + name: vlagents.operator.victoriametrics.com +spec: + group: operator.victoriametrics.com + names: + kind: VLAgent + listKind: VLAgentList + plural: vlagents + singular: vlagent + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: current number of replicas + jsonPath: .status.replicas + name: Replica Count + type: integer + - description: Current status of update rollout + jsonPath: .status.updateStatus + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + affinity: + type: object + x-kubernetes-preserve-unknown-fields: true + claimTemplates: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + x-kubernetes-preserve-unknown-fields: true + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + configMaps: + items: + type: string + type: array + containers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + disableAutomountServiceAccountToken: + type: boolean + disableSelfServiceScrape: + type: boolean + dnsConfig: + items: + x-kubernetes-preserve-unknown-fields: true + properties: + nameservers: + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + dnsPolicy: + type: string + extraArgs: + additionalProperties: + type: string + type: object + extraEnvs: + items: + properties: + name: + type: string + value: + type: string + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + extraEnvsFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + host_aliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostNetwork: + type: boolean + image: + properties: + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + k8sCollector: + properties: + checkpointsPath: + type: string + decolorizeFields: + items: + type: string + type: array + enabled: + type: boolean + excludeFilter: + type: string + extraFields: + type: string + ignoreFields: + items: + type: string + type: array + includeNodeAnnotations: + type: boolean + includeNodeLabels: + type: boolean + includePodAnnotations: + type: boolean + includePodLabels: + type: boolean + logsPath: + type: string + msgFields: + items: + type: string + type: array + streamFields: + items: + type: string + type: array + tenantID: + type: string + timeFields: + items: + type: string + type: array + type: object + license: + properties: + forceOffline: + type: boolean + key: + type: string + keyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + reloadInterval: + type: string + type: object + livenessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + logFormat: + enum: + - default + - json + type: string + logLevel: + enum: + - INFO + - WARN + - ERROR + - FATAL + - PANIC + type: string + managedMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + minReadySeconds: + format: int32 + type: integer + nodeSelector: + additionalProperties: + type: string + type: object + paused: + type: boolean + persistentVolumeClaimRetentionPolicy: + properties: + whenDeleted: + type: string + whenScaled: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + selectorLabels: + additionalProperties: + type: string + type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string + type: object + podMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + port: + type: string + priorityClassName: + type: string + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + readinessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + remoteWrite: + items: + properties: + bearerTokenPath: + type: string + bearerTokenSecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + headers: + items: + type: string + type: array + maxDiskUsage: + x-kubernetes-preserve-unknown-fields: true + oauth2: + properties: + clientIDFile: + type: string + clientIDSecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + clientSecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + clientSecretFile: + type: string + endpointParams: + additionalProperties: + type: string + type: object + scopes: + items: + type: string + type: array + tokenURL: + minLength: 1 + type: string + required: + - tokenURL + type: object + proxyURL: + type: string + sendTimeout: + pattern: '[0-9]+(ms|s|m|h)' + type: string + tlsConfig: + properties: + caFile: + type: string + caSecretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + certFile: + type: string + certSecretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + insecureSkipVerify: + type: boolean + keyFile: + type: string + keySecretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + type: string + type: object + url: + type: string + required: + - url + type: object + type: array + remoteWriteSettings: + properties: + flushInterval: + pattern: '[0-9]+(ms|s|m|h)' + type: string + maxBlockSize: + x-kubernetes-preserve-unknown-fields: true + maxDiskUsagePerURL: + x-kubernetes-preserve-unknown-fields: true + queues: + format: int32 + type: integer + showURL: + type: boolean + tmpDataPath: + type: string + type: object + replicaCount: + format: int32 + type: integer + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + revisionHistoryLimitCount: + format: int32 + type: integer + rollingUpdateStrategy: + type: string + runtimeClassName: + type: string + schedulerName: + type: string + secrets: + items: + type: string + type: array + securityContext: + type: object + x-kubernetes-preserve-unknown-fields: true + serviceAccountName: + type: string + serviceScrapeSpec: + required: + - endpoints + type: object + x-kubernetes-preserve-unknown-fields: true + serviceSpec: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + useAsDefault: + type: boolean + required: + - spec + type: object + startupProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + storage: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + volumeClaimTemplate: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: object + syslogSpec: + properties: + tcpListeners: + items: + properties: + compressMethod: + pattern: ^(none|zstd|gzip|deflate)$ + type: string + decolorizeFields: + type: string + ignoreFields: + type: string + listenPort: + format: int32 + type: integer + streamFields: + type: string + tenantID: + type: string + tlsConfig: + properties: + certFile: + type: string + certSecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - listenPort + type: object + type: array + udpListeners: + items: + properties: + compressMethod: + pattern: ^(none|zstd|gzip|deflate)$ + type: string + decolorizeFields: + type: string + ignoreFields: + type: string + listenPort: + format: int32 + type: integer + streamFields: + type: string + tenantID: + type: string + required: + - listenPort + type: object + type: array + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + tmpDataPath: + type: string + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + useDefaultResources: + type: boolean + useStrictSecurity: + type: boolean + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + required: + - remoteWrite + type: object + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + maxLength: 32768 + type: string + observedGeneration: + format: int64 + minimum: 0 + type: integer + reason: + maxLength: 1024 + minLength: 1 + type: string + status: + enum: + - "True" + - "False" + - Unknown + type: string + type: + maxLength: 316 + type: string + required: + - lastTransitionTime + - lastUpdateTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + format: int64 + type: integer + reason: + type: string + replicas: + format: int32 + type: integer + selector: + type: string + updateStatus: + type: string + type: object + type: object + served: true + storage: true + subresources: + scale: + labelSelectorPath: .status.selector + specReplicasPath: .spec.shardCount + statusReplicasPath: .status.shards + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.0 + name: vlclusters.operator.victoriametrics.com +spec: + group: operator.victoriametrics.com + names: + kind: VLCluster + listKind: VLClusterList + plural: vlclusters + singular: vlcluster + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: replicas of VLInsert + jsonPath: .spec.vlinsert.replicaCount + name: Insert Count + type: string + - description: replicas of VLStorage + jsonPath: .spec.vlstorage.replicaCount + name: Storage Count + type: string + - description: replicas of VLSelect + jsonPath: .spec.vlselect.replicaCount + name: Select Count + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Current status of cluster + jsonPath: .status.updateStatus + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + clusterDomainName: + type: string + clusterVersion: + type: string + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + license: + properties: + forceOffline: + type: boolean + key: + type: string + keyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + reloadInterval: + type: string + type: object + managedMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + paused: + type: boolean + requestsLoadBalancer: + properties: + disableInsertBalancing: + type: boolean + disableSelectBalancing: + type: boolean + enabled: + type: boolean + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + serviceAccountName: + type: string + useStrictSecurity: + type: boolean + vlinsert: + properties: + affinity: + type: object + x-kubernetes-preserve-unknown-fields: true + configMaps: + items: + type: string + type: array + containers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + disableAutomountServiceAccountToken: + type: boolean + disableSelfServiceScrape: + type: boolean + dnsConfig: + items: + x-kubernetes-preserve-unknown-fields: true + properties: + nameservers: + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + dnsPolicy: + type: string + extraArgs: + additionalProperties: + type: string + type: object + extraEnvs: + items: + properties: + name: + type: string + value: + type: string + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + extraEnvsFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + host_aliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostNetwork: + type: boolean + hpa: + type: object + x-kubernetes-preserve-unknown-fields: true + image: + properties: + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + livenessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + logFormat: + enum: + - default + - json + type: string + logLevel: + enum: + - INFO + - WARN + - ERROR + - FATAL + - PANIC + type: string + minReadySeconds: + format: int32 + type: integer + nodeSelector: + additionalProperties: + type: string + type: object + paused: + type: boolean + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + selectorLabels: + additionalProperties: + type: string + type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string + type: object + podMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + port: + type: string + priorityClassName: + type: string + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + readinessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + replicaCount: + format: int32 + type: integer + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + revisionHistoryLimitCount: + format: int32 + type: integer + rollingUpdate: + properties: + maxSurge: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + runtimeClassName: + type: string + schedulerName: + type: string + secrets: + items: + type: string + type: array + securityContext: + type: object + x-kubernetes-preserve-unknown-fields: true + serviceScrapeSpec: + required: + - endpoints + type: object + x-kubernetes-preserve-unknown-fields: true + serviceSpec: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + useAsDefault: + type: boolean + required: + - spec + type: object + startupProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + syslogSpec: + properties: + tcpListeners: + items: + properties: + compressMethod: + pattern: ^(none|zstd|gzip|deflate)$ + type: string + decolorizeFields: + type: string + ignoreFields: + type: string + listenPort: + format: int32 + type: integer + streamFields: + type: string + tenantID: + type: string + tlsConfig: + properties: + certFile: + type: string + certSecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - listenPort + type: object + type: array + udpListeners: + items: + properties: + compressMethod: + pattern: ^(none|zstd|gzip|deflate)$ + type: string + decolorizeFields: + type: string + ignoreFields: + type: string + listenPort: + format: int32 + type: integer + streamFields: + type: string + tenantID: + type: string + required: + - listenPort + type: object + type: array + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + updateStrategy: + enum: + - Recreate + - RollingUpdate + type: string + useDefaultResources: + type: boolean + useStrictSecurity: + type: boolean + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + vpa: + properties: + recommenders: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + resourcePolicy: + properties: + containerPolicies: + items: + properties: + containerName: + type: string + controlledResources: + items: + type: string + type: array + controlledValues: + enum: + - RequestsAndLimits + - RequestsOnly + type: string + maxAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + minAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + mode: + enum: + - Auto + - "Off" + type: string + type: object + type: array + type: object + updatePolicy: + properties: + evictionRequirements: + items: + properties: + changeRequirement: + enum: + - TargetHigherThanRequests + - TargetLowerThanRequests + type: string + resources: + items: + type: string + type: array + required: + - changeRequirement + - resources + type: object + type: array + minReplicas: + format: int32 + type: integer + updateMode: + enum: + - "Off" + - Initial + - Recreate + - InPlaceOrRecreate + - Auto + type: string + type: object + type: object + type: object + vlselect: + properties: + affinity: + type: object + x-kubernetes-preserve-unknown-fields: true + configMaps: + items: + type: string + type: array + containers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + disableAutomountServiceAccountToken: + type: boolean + disableSelfServiceScrape: + type: boolean + dnsConfig: + items: + x-kubernetes-preserve-unknown-fields: true + properties: + nameservers: + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + dnsPolicy: + type: string + extraArgs: + additionalProperties: + type: string + type: object + extraEnvs: + items: + properties: + name: + type: string + value: + type: string + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + extraEnvsFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + extraStorageNodes: + items: + properties: + addr: + type: string + required: + - addr + type: object + type: array + host_aliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostNetwork: + type: boolean + hpa: + type: object + x-kubernetes-preserve-unknown-fields: true + image: + properties: + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + livenessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + logFormat: + enum: + - default + - json + type: string + logLevel: + enum: + - INFO + - WARN + - ERROR + - FATAL + - PANIC + type: string + minReadySeconds: + format: int32 + type: integer + nodeSelector: + additionalProperties: + type: string + type: object + paused: + type: boolean + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + selectorLabels: + additionalProperties: + type: string + type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string + type: object + podMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + port: + type: string + priorityClassName: + type: string + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + readinessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + replicaCount: + format: int32 + type: integer + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + revisionHistoryLimitCount: + format: int32 + type: integer + rollingUpdate: + properties: + maxSurge: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + runtimeClassName: + type: string + schedulerName: + type: string + secrets: + items: + type: string + type: array + securityContext: + type: object + x-kubernetes-preserve-unknown-fields: true + serviceScrapeSpec: + required: + - endpoints + type: object + x-kubernetes-preserve-unknown-fields: true + serviceSpec: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + useAsDefault: + type: boolean + required: + - spec + type: object + startupProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + updateStrategy: + enum: + - Recreate + - RollingUpdate + type: string + useDefaultResources: + type: boolean + useStrictSecurity: + type: boolean + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + vpa: + properties: + recommenders: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + resourcePolicy: + properties: + containerPolicies: + items: + properties: + containerName: + type: string + controlledResources: + items: + type: string + type: array + controlledValues: + enum: + - RequestsAndLimits + - RequestsOnly + type: string + maxAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + minAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + mode: + enum: + - Auto + - "Off" + type: string + type: object + type: array + type: object + updatePolicy: + properties: + evictionRequirements: + items: + properties: + changeRequirement: + enum: + - TargetHigherThanRequests + - TargetLowerThanRequests + type: string + resources: + items: + type: string + type: array + required: + - changeRequirement + - resources + type: object + type: array + minReplicas: + format: int32 + type: integer + updateMode: + enum: + - "Off" + - Initial + - Recreate + - InPlaceOrRecreate + - Auto + type: string + type: object + type: object + type: object + vlstorage: + properties: + affinity: + type: object + x-kubernetes-preserve-unknown-fields: true + claimTemplates: + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + configMaps: + items: + type: string + type: array + containers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + disableAutomountServiceAccountToken: + type: boolean + disableSelfServiceScrape: + type: boolean + dnsConfig: + items: + x-kubernetes-preserve-unknown-fields: true + properties: + nameservers: + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + dnsPolicy: + type: string + extraArgs: + additionalProperties: + type: string + type: object + extraEnvs: + items: + properties: + name: + type: string + value: + type: string + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + extraEnvsFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + futureRetention: + pattern: ^[0-9]+(h|d|w|y)?$ + type: string + host_aliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostNetwork: + type: boolean + hpa: + properties: + behaviour: + properties: + scaleDown: + properties: + policies: + items: + properties: + periodSeconds: + format: int32 + type: integer + type: + type: string + value: + format: int32 + type: integer + required: + - periodSeconds + - type + - value + type: object + type: array + x-kubernetes-list-type: atomic + selectPolicy: + type: string + stabilizationWindowSeconds: + format: int32 + type: integer + tolerance: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + scaleUp: + properties: + policies: + items: + properties: + periodSeconds: + format: int32 + type: integer + type: + type: string + value: + format: int32 + type: integer + required: + - periodSeconds + - type + - value + type: object + type: array + x-kubernetes-list-type: atomic + selectPolicy: + type: string + stabilizationWindowSeconds: + format: int32 + type: integer + tolerance: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + maxReplicas: + format: int32 + type: integer + metrics: + items: + properties: + containerResource: + properties: + container: + type: string + name: + type: string + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - container + - name + - target + type: object + external: + properties: + metric: + properties: + name: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - metric + - target + type: object + object: + properties: + describedObject: + properties: + apiVersion: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + metric: + properties: + name: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - describedObject + - metric + - target + type: object + pods: + properties: + metric: + properties: + name: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - metric + - target + type: object + resource: + properties: + name: + type: string + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - name + - target + type: object + type: + type: string + required: + - type + type: object + type: array + minReplicas: + format: int32 + type: integer + type: object + image: + properties: + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + livenessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + logFormat: + enum: + - default + - json + type: string + logIngestedRows: + type: boolean + logLevel: + enum: + - INFO + - WARN + - ERROR + - FATAL + - PANIC + type: string + logNewStreams: + type: boolean + maintenanceInsertNodeIDs: + items: + format: int32 + type: integer + type: array + maintenanceSelectNodeIDs: + items: + format: int32 + type: integer + type: array + minReadySeconds: + format: int32 + type: integer + nodeSelector: + additionalProperties: + type: string + type: object + paused: + type: boolean + persistentVolumeClaimRetentionPolicy: + properties: + whenDeleted: + type: string + whenScaled: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + selectorLabels: + additionalProperties: + type: string + type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string + type: object + podMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + port: + type: string + priorityClassName: + type: string + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + readinessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + replicaCount: + format: int32 + type: integer + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + retentionMaxDiskSpaceUsageBytes: + type: string + retentionPeriod: + pattern: ^[0-9]+(h|d|w|y)?$ + type: string + revisionHistoryLimitCount: + format: int32 + type: integer + rollingUpdateStrategy: + type: string + rollingUpdateStrategyBehavior: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + runtimeClassName: + type: string + schedulerName: + type: string + secrets: + items: + type: string + type: array + securityContext: + type: object + x-kubernetes-preserve-unknown-fields: true + serviceScrapeSpec: + required: + - endpoints + type: object + x-kubernetes-preserve-unknown-fields: true + serviceSpec: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + useAsDefault: + type: boolean + required: + - spec + type: object + startupProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + storage: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + volumeClaimTemplate: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + storageDataPath: + type: string + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + useDefaultResources: + type: boolean + useStrictSecurity: + type: boolean + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + vpa: + properties: + recommenders: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + resourcePolicy: + properties: + containerPolicies: + items: + properties: + containerName: + type: string + controlledResources: + items: + type: string + type: array + controlledValues: + enum: + - RequestsAndLimits + - RequestsOnly + type: string + maxAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + minAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + mode: + enum: + - Auto + - "Off" + type: string + type: object + type: array + type: object + updatePolicy: + properties: + evictionRequirements: + items: + properties: + changeRequirement: + enum: + - TargetHigherThanRequests + - TargetLowerThanRequests + type: string + resources: + items: + type: string + type: array + required: + - changeRequirement + - resources + type: object + type: array + minReplicas: + format: int32 + type: integer + updateMode: + enum: + - "Off" + - Initial + - Recreate + - InPlaceOrRecreate + - Auto + type: string + type: object + type: object + type: object + type: object + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + maxLength: 32768 + type: string + observedGeneration: + format: int64 + minimum: 0 + type: integer + reason: + maxLength: 1024 + minLength: 1 + type: string + status: + enum: + - "True" + - "False" + - Unknown + type: string + type: + maxLength: 316 + type: string + required: + - lastTransitionTime + - lastUpdateTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + format: int64 + type: integer + reason: + type: string + updateStatus: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.0 name: vlogs.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -24,146 +3202,164 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: |- - VLogs is fast, cost-effective and scalable logs database. - VLogs is the Schema for the vlogs API 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: VLogsSpec defines the desired state of VLogs + required: + - retentionPeriod + type: object + x-kubernetes-preserve-unknown-fields: true + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + maxLength: 32768 + type: string + observedGeneration: + format: int64 + minimum: 0 + type: integer + reason: + maxLength: 1024 + minLength: 1 + type: string + status: + enum: + - "True" + - "False" + - Unknown + type: string + type: + maxLength: 316 + type: string + required: + - lastTransitionTime + - lastUpdateTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + format: int64 + type: integer + reason: + type: string + updateStatus: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.0 + name: vlsingles.operator.victoriametrics.com +spec: + group: operator.victoriametrics.com + names: + kind: VLSingle + listKind: VLSingleList + plural: vlsingles + singular: vlsingle + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Current status of logs instance update process + jsonPath: .status.status + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: properties: affinity: - description: Affinity If specified, the pod's scheduling constraints. type: object x-kubernetes-preserve-unknown-fields: true configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder items: type: string type: array containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. items: - description: A single application container that you want to run - within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. type: boolean disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable type: boolean dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. items: x-kubernetes-preserve-unknown-fields: true properties: nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. items: type: string type: array x-kubernetes-list-type: atomic options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. properties: name: - description: |- - Name is this DNS resolver option's name. - Required. type: string value: - description: Value is this DNS resolver option's value. type: string type: object type: array x-kubernetes-list-type: atomic searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. items: type: string type: array x-kubernetes-list-type: atomic type: object dnsPolicy: - description: DNSPolicy sets DNS policy for the pod type: string extraArgs: additionalProperties: type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp type: object extraEnvs: - description: ExtraEnvs that will be passed to the application container items: - description: EnvVar represents an environment variable present in - a Container. properties: name: - description: Name of the environment variable. Must be a C_IDENTIFIER. type: string value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". type: string required: - name @@ -171,175 +3367,121 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap items: - description: EnvFromSource represents the source of a set of ConfigMaps properties: configMapRef: - description: The ConfigMap to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap must be defined type: boolean 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. type: string secretRef: - description: The Secret to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret must be defined type: boolean type: object x-kubernetes-map-type: atomic type: object type: array futureRetention: - description: |- - FutureRetention for the stored logs - Log entries with timestamps bigger than now+futureRetention are rejected during data ingestion; see https://docs.victoriametrics.com/victorialogs/#retention + pattern: ^[0-9]+(h|d|y)?$ type: string host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostNetwork: - description: HostNetwork controls whether the pod may use the node - network namespace type: boolean image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config properties: pullPolicy: - description: PullPolicy describes how to pull docker image type: string repository: - description: Repository contains name of docker image + it's repository - if needed type: string tag: - description: Tag contains desired docker image version type: string type: object imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string type: object x-kubernetes-map-type: atomic type: array initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ items: - description: A single application container that you want to run - within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array + license: + properties: + forceOffline: + type: boolean + key: + type: string + keyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + reloadInterval: + type: string + type: object livenessProbe: - description: LivenessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true logFormat: - description: LogFormat for VLogs to be configured with. enum: - default - json type: string logIngestedRows: - description: Whether to log all the ingested log entries; this can - be useful for debugging of data ingestion; see https://docs.victoriametrics.com/victorialogs/data-ingestion/ type: boolean logLevel: - description: LogLevel for VictoriaLogs to be configured with. enum: - INFO - WARN @@ -348,144 +3490,67 @@ spec: - PANIC type: string logNewStreams: - description: LogNewStreams Whether to log creation of new streams; - this can be useful for debugging of high cardinality issues with - log streams; see https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields type: boolean managedMetadata: - description: |- - ManagedMetadata defines metadata that will be added to the all objects - created by operator for the given CustomResource properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object type: object minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle format: int32 type: integer nodeSelector: additionalProperties: type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. type: object paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. type: boolean podMetadata: - description: PodMetadata configures Labels and Annotations which are - propagated to the VLogs pods. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object port: - description: Port listen address type: string priorityClassName: - description: PriorityClassName class assigned to the Pods type: string readinessGates: - description: ReadinessGates defines pod readiness gates items: - description: PodReadinessGate contains the reference to a pod condition properties: conditionType: - description: ConditionType refers to a condition in the pod's - condition list with matching type. type: string required: - conditionType type: object type: array readinessProbe: - description: ReadinessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true - removePvcAfterDelete: - description: |- - RemovePvcAfterDelete - if true, controller adds ownership to pvc - and after VLogs object deletion - pvc will be garbage collected - by controller manager - type: boolean replicaCount: - description: ReplicaCount is the expected size of the Application. format: int32 type: integer resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used properties: claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. type: string request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. type: string required: - name @@ -501,9 +3566,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -512,145 +3574,74 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object + retentionMaxDiskSpaceUsageBytes: + type: string retentionPeriod: - description: RetentionPeriod for the stored logs + pattern: ^[0-9]+(h|d|w|y)?$ type: string revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. format: int32 type: integer runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ type: string schedulerName: - description: SchedulerName - defines kubernetes scheduler name type: string secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder items: type: string type: array securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. type: object x-kubernetes-preserve-unknown-fields: true serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to use to run the pods type: string serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vlogs VMServiceScrape - spec required: - endpoints type: object x-kubernetes-preserve-unknown-fields: true serviceSpec: - description: ServiceSpec that will be added to vlogs service spec properties: metadata: - description: EmbeddedObjectMetadata defines objectMeta for additional - service. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ type: object x-kubernetes-preserve-unknown-fields: true useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication type: boolean required: - spec type: object startupProbe: - description: StartupProbe that will be added to CRD pod type: object x-kubernetes-preserve-unknown-fields: true storage: - description: |- - Storage is the definition of how storage will be used by the VLogs - by default it`s empty dir properties: accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string type: array x-kubernetes-list-type: atomic dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. properties: apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. type: string kind: - description: Kind is the type of resource being referenced type: string name: - description: Name is the name of resource being referenced type: string required: - kind @@ -658,60 +3649,20 @@ spec: type: object x-kubernetes-map-type: atomic dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. properties: apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. type: string kind: - description: Kind is the type of resource being referenced type: string name: - description: Name is the name of resource being referenced type: string namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. type: string required: - kind - name type: object resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources properties: limits: additionalProperties: @@ -720,9 +3671,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -731,40 +3679,18 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object selector: - description: selector is a label query over volumes to consider - for binding. 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 @@ -778,133 +3704,132 @@ spec: 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 storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 type: string volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. type: string volumeName: - description: volumeName is the binding reference to the PersistentVolume - backing this claim. type: string type: object storageDataPath: - description: |- - StorageDataPath disables spec.storage option and overrides arg for victoria-logs binary --storageDataPath, - its users responsibility to mount proper device into given path. type: string storageMetadata: - description: StorageMeta defines annotations and labels attached to - PVC for given vlogs CR properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object + syslogSpec: + properties: + tcpListeners: + items: + properties: + compressMethod: + pattern: ^(none|zstd|gzip|deflate)$ + type: string + decolorizeFields: + type: string + ignoreFields: + type: string + listenPort: + format: int32 + type: integer + streamFields: + type: string + tenantID: + type: string + tlsConfig: + properties: + certFile: + type: string + certSecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - listenPort + type: object + type: array + udpListeners: + items: + properties: + compressMethod: + pattern: ^(none|zstd|gzip|deflate)$ + type: string + decolorizeFields: + type: string + ignoreFields: + type: string + listenPort: + format: int32 + type: integer + streamFields: + type: string + tenantID: + type: string + required: + - listenPort + type: object + type: array + type: object terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container graceful - termination format: int64 type: integer tolerations: - description: Tolerations If specified, the pod's tolerations. items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. type: string type: object type: array topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ items: - description: TopologySpreadConstraint specifies how to spread matching - pods among the given topology. required: - maxSkew - topologyKey @@ -913,77 +3838,25 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements type: boolean useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions type: boolean volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container items: - description: VolumeMount describes a mounting of a Volume within - a container. properties: mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. type: string mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). type: string name: - description: This must match the Name of a Volume. type: string readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. type: boolean recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). type: string subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. type: string required: - mountPath @@ -991,74 +3864,42 @@ spec: type: object type: array volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional items: - description: Volume represents a named volume in a pod that may - be accessed by any container in the pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array - required: - - retentionPeriod type: object status: - description: VLogsStatus defines the observed state of VLogs properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -1073,16 +3914,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -1095,7 +3931,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmagents.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -1125,170 +3961,78 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: |- - VMAgent - is a tiny but brave agent, which helps you collect metrics from various sources and stores them in VictoriaMetrics - or any other Prometheus-compatible storage system that supports the remote_write protocol. 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: VMAgentSpec defines the desired state of VMAgent properties: - aPIServerConfig: - description: |- - APIServerConfig allows specifying a host and auth methods to access apiserver. - If left empty, VMAgent is assumed to run inside of the cluster - and will discover API servers automatically and use the pod's CA certificate - and bearer token file at /var/run/secrets/kubernetes.io/serviceaccount/. - aPIServerConfig is deprecated use apiServerConfig instead - required: - - host - type: object - x-kubernetes-preserve-unknown-fields: true additionalScrapeConfigs: - description: |- - AdditionalScrapeConfigs As scrape configs are appended, the user is responsible to make sure it - is valid. Note that using this feature may expose the possibility to - break upgrades of VMAgent. It is advised to review VMAgent release - notes to ensure that no incompatible scrape configs are going to break - VMAgent after the upgrade. properties: key: - description: The key of the secret to select from. Must be a - valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic affinity: - description: Affinity If specified, the pod's scheduling constraints. type: object x-kubernetes-preserve-unknown-fields: true apiServerConfig: - description: |- - APIServerConfig allows specifying a host and auth methods to access apiserver. - If left empty, VMAgent is assumed to run inside of the cluster - and will discover API servers automatically and use the pod's CA certificate - and bearer token file at /var/run/secrets/kubernetes.io/serviceaccount/. properties: authorization: - description: Authorization configures generic authorization params properties: credentials: - description: Reference to the secret with value for authorization properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to bearer type: string type: object basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -1296,66 +4040,36 @@ spec: x-kubernetes-map-type: atomic type: object bearerToken: - description: Bearer token for accessing apiserver. type: string bearerTokenFile: - description: File to read bearer token for accessing apiserver. type: string host: - description: |- - Host of apiserver. - A valid string consisting of a hostname or IP followed by an optional port number type: string tlsConfig: - description: TLSConfig Config to use for accessing apiserver. properties: ca: - description: Struct containing the CA cert to use for the - targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -1363,56 +4077,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container to use for - the targets. type: string cert: - description: Struct containing the client cert file for the - targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -1420,120 +4108,59 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container - for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container - for the targets. type: string keySecret: - description: Secret containing the client key file for the - targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object required: - host type: object arbitraryFSAccessThroughSMs: - description: |- - ArbitraryFSAccessThroughSMs configures whether configuration - based on EndpointAuth can access arbitrary files on the file system - of the VMAgent container e.g. bearer token files, basic auth, tls certs properties: deny: type: boolean type: object claimTemplates: - description: ClaimTemplates allows adding additional VolumeClaimTemplates - for VMAgent in StatefulMode items: - description: PersistentVolumeClaim is a user's request for and claim - to a persistent volume 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: - description: |- - Standard object's metadata. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata type: object x-kubernetes-preserve-unknown-fields: true spec: - description: |- - spec defines the desired characteristics of a volume requested by a pod author. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims properties: accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string type: array x-kubernetes-list-type: atomic dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. properties: apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. type: string kind: - description: Kind is the type of resource being referenced type: string name: - description: Name is the name of resource being referenced type: string required: - kind @@ -1541,60 +4168,20 @@ spec: type: object x-kubernetes-map-type: atomic dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. properties: apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. type: string kind: - description: Kind is the type of resource being referenced type: string name: - description: Name is the name of resource being referenced type: string namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. type: string required: - kind - name type: object resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources properties: limits: additionalProperties: @@ -1603,9 +4190,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -1614,40 +4198,18 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object selector: - description: selector is a label query over volumes to consider - for binding. 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 @@ -1661,99 +4223,28 @@ spec: 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 storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 type: string volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. type: string volumeName: - description: volumeName is the binding reference to the - PersistentVolume backing this claim. type: string type: object status: - description: |- - status represents the current information/status of a persistent volume claim. - Read-only. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims properties: accessModes: - description: |- - accessModes contains the actual access modes the volume backing the PVC has. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string type: array x-kubernetes-list-type: atomic allocatedResourceStatuses: additionalProperties: - description: |- - When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource - that it does not recognizes, then it should ignore that update and let other controllers - handle it. type: string - description: "allocatedResourceStatuses stores status of - resource being resized for the given PVC.\nKey names follow - standard Kubernetes label syntax. Valid values are either:\n\t* - Un-prefixed keys:\n\t\t- storage - the capacity of the - volume.\n\t* Custom resources must use implementation-defined - prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not be used.\n\nClaimResourceStatus - can be in any of following states:\n\t- ControllerResizeInProgress:\n\t\tState - set when resize controller starts resizing the volume - in control-plane.\n\t- ControllerResizeFailed:\n\t\tState - set when resize has failed in resize controller with a - terminal error.\n\t- NodeResizePending:\n\t\tState set - when resize controller has finished resizing the volume - but further resizing of\n\t\tvolume is needed on the node.\n\t- - NodeResizeInProgress:\n\t\tState set when kubelet starts - resizing the volume.\n\t- NodeResizeFailed:\n\t\tState - set when resizing has failed in kubelet with a terminal - error. Transient errors don't set\n\t\tNodeResizeFailed.\nFor - example: if expanding a PVC for more capacity - this field - can be one of the following states:\n\t- pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeFailed\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizePending\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeFailed\"\nWhen this field is not set, it - means that no resize operation is in progress for the - given PVC.\n\nA controller that receives PVC update with - previously unknown resourceName or ClaimResourceStatus\nshould - ignore the update for the purpose it was designed. For - example - a controller that\nonly is responsible for resizing - capacity of the volume, should ignore PVC updates that - change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." type: object x-kubernetes-map-type: granular allocatedResources: @@ -1763,30 +4254,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: "allocatedResources tracks the resources allocated - to a PVC including its capacity.\nKey names follow standard - Kubernetes label syntax. Valid values are either:\n\t* - Un-prefixed keys:\n\t\t- storage - the capacity of the - volume.\n\t* Custom resources must use implementation-defined - prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not be used.\n\nCapacity - reported here may be larger than the actual capacity when - a volume expansion operation\nis requested.\nFor storage - quota, the larger value from allocatedResources and PVC.spec.resources - is used.\nIf allocatedResources is not set, PVC.spec.resources - alone is used for quota calculation.\nIf a volume expansion - capacity request is lowered, allocatedResources is only\nlowered - if there are no expansion operations in progress and if - the actual volume capacity\nis equal or lower than the - requested capacity.\n\nA controller that receives PVC - update with previously unknown resourceName\nshould ignore - the update for the purpose it was designed. For example - - a controller that\nonly is responsible for resizing - capacity of the volume, should ignore PVC updates that - change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." type: object capacity: additionalProperties: @@ -1795,47 +4262,23 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: capacity represents the actual resources of - the underlying volume. type: object conditions: - description: |- - conditions is the current Condition of persistent volume claim. If underlying persistent volume is being - resized then the Condition will be set to 'Resizing'. items: - description: PersistentVolumeClaimCondition contains details - about state of pvc properties: lastProbeTime: - description: lastProbeTime is the time we probed the - condition. format: date-time type: string lastTransitionTime: - description: lastTransitionTime is the time the condition - transitioned from one status to another. format: date-time type: string message: - description: message is the human-readable message - indicating details about last transition. type: string reason: - description: |- - reason is a unique, this should be a short, machine understandable string that gives the reason - for condition's last transition. If it reports "Resizing" that means the underlying - persistent volume is being resized. type: string status: - description: |- - Status is the status of the condition. - Can be True, False, Unknown. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=state%20of%20pvc-,conditions.status,-(string)%2C%20required type: string type: - description: |- - Type is the type of the condition. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=set%20to%20%27ResizeStarted%27.-,PersistentVolumeClaimCondition,-contains%20details%20about type: string required: - status @@ -1846,92 +4289,54 @@ spec: - type x-kubernetes-list-type: map currentVolumeAttributesClassName: - description: |- - currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. - When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). type: string modifyVolumeStatus: - description: |- - ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. - When this is unset, there is no ModifyVolume operation being attempted. - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). properties: status: - description: "status is the status of the ControllerModifyVolume - operation. It can be in any of following states:\n - - Pending\n Pending indicates that the PersistentVolumeClaim - cannot be modified due to unmet requirements, such - as\n the specified VolumeAttributesClass not existing.\n - - InProgress\n InProgress indicates that the volume - is being modified.\n - Infeasible\n Infeasible indicates - that the request has been rejected as invalid by the - CSI driver. To\n\t resolve the error, a valid VolumeAttributesClass - needs to be specified.\nNote: New statuses can be - added in the future. Consumers should check for unknown - statuses and fail appropriately." type: string targetVolumeAttributesClassName: - description: targetVolumeAttributesClassName is the - name of the VolumeAttributesClass the PVC currently - being reconciled type: string required: - status type: object phase: - description: phase represents the current phase of PersistentVolumeClaim. type: string type: object type: object type: array configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder items: type: string type: array + configReloadAuthKeySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic configReloaderExtraArgs: additionalProperties: type: string - description: |- - ConfigReloaderExtraArgs that will be passed to VMAuths config-reloader container - for example resyncInterval: "30s" type: object + configReloaderImage: + type: string configReloaderImageTag: - description: ConfigReloaderImageTag defines image:tag for config-reloader - container type: string configReloaderResources: - description: |- - ConfigReloaderResources config-reloader container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used properties: claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. type: string request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. type: string required: - name @@ -1947,9 +4352,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -1958,144 +4360,68 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. items: - description: A single application container that you want to run - within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array daemonSetMode: - description: |- - DaemonSetMode enables DaemonSet deployment mode instead of Deployment. - Supports only VMPodScrape - (available from v0.55.0). - Cannot be used with statefulMode type: boolean disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. type: boolean disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable type: boolean dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. items: x-kubernetes-preserve-unknown-fields: true properties: nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. items: type: string type: array x-kubernetes-list-type: atomic options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. properties: name: - description: |- - Name is this DNS resolver option's name. - Required. type: string value: - description: Value is this DNS resolver option's value. type: string type: object type: array x-kubernetes-list-type: atomic searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. items: type: string type: array x-kubernetes-list-type: atomic type: object dnsPolicy: - description: DNSPolicy sets DNS policy for the pod type: string enableKubernetesAPISelectors: - description: |- - EnableKubernetesAPISelectors instructs vmagent to use CRD scrape objects spec.selectors for - Kubernetes API list and watch requests. - https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#list-and-watch-filtering - It could be useful to reduce Kubernetes API server resource usage for serving less than 100 CRD scrape objects in total. type: boolean enforcedNamespaceLabel: - description: |- - EnforcedNamespaceLabel enforces adding a namespace label of origin for each alert - and metric that is user created. The label value will always be the namespace of the object that is - being created. + type: string + externalLabelName: type: string externalLabels: additionalProperties: type: string - description: |- - ExternalLabels The labels to add to any time series scraped by vmagent. - it doesn't affect metrics ingested directly by push API's type: object extraArgs: additionalProperties: type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp type: object extraEnvs: - description: ExtraEnvs that will be passed to the application container items: - description: EnvVar represents an environment variable present in - a Container. properties: name: - description: Name of the environment variable. Must be a C_IDENTIFIER. type: string value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". type: string required: - name @@ -2103,330 +4429,241 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap items: - description: EnvFromSource represents the source of a set of ConfigMaps properties: configMapRef: - description: The ConfigMap to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap must be defined type: boolean 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. type: string secretRef: - description: The Secret to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret must be defined type: boolean type: object x-kubernetes-map-type: atomic type: object type: array - host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field + globalScrapeMetricRelabelConfigs: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + globalScrapeRelabelConfigs: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + host_aliases: items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostNetwork: - description: HostNetwork controls whether the pod may use the node - network namespace type: boolean ignoreNamespaceSelectors: - description: |- - IgnoreNamespaceSelectors if set to true will ignore NamespaceSelector settings from - scrape objects, and they will only discover endpoints - within their current namespace. Defaults to false. type: boolean image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config properties: pullPolicy: - description: PullPolicy describes how to pull docker image type: string repository: - description: Repository contains name of docker image + it's repository - if needed type: string tag: - description: Tag contains desired docker image version type: string type: object imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string type: object x-kubernetes-map-type: atomic type: array ingestOnlyMode: - description: |- - IngestOnlyMode switches vmagent into unmanaged mode - it disables any config generation for scraping - Currently it prevents vmagent from managing tls and auth options for remote write type: boolean initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ items: - description: A single application container that you want to run - within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array inlineRelabelConfig: - description: InlineRelabelConfig - defines GlobalRelabelConfig for - vmagent, can be defined directly at CRD. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. Default - is 'replace' type: string if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source label - values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source label - values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array inlineScrapeConfig: - description: |- - InlineScrapeConfig As scrape configs are appended, the user is responsible to make sure it - is valid. Note that using this feature may expose the possibility to - break upgrades of VMAgent. It is advised to review VMAgent release - notes to ensure that no incompatible scrape configs are going to break - VMAgent after the upgrade. - it should be defined as single yaml file. - inlineScrapeConfig: | - - job_name: "prometheus" - static_configs: - - targets: ["localhost:9090"] type: string insertPorts: - description: InsertPorts - additional listen ports for data ingestion. properties: graphitePort: - description: GraphitePort listen port type: string influxPort: - description: InfluxPort listen port type: string openTSDBHTTPPort: - description: OpenTSDBHTTPPort for http connections. type: string openTSDBPort: - description: OpenTSDBPort for tcp and udp listen type: string type: object license: - description: |- - License allows to configure license key to be used for enterprise features. - Using license key is supported starting from VictoriaMetrics v1.94.0. - See [here](https://docs.victoriametrics.com/enterprise) properties: forceOffline: - description: Enforce offline verification of the license key. type: boolean key: - description: |- - Enterprise license key. This flag is available only in [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise). - To request a trial license, [go to](https://victoriametrics.com/products/enterprise/trial) type: string keyRef: - description: KeyRef is reference to secret with license key for - enterprise features. properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic reloadInterval: - description: Interval to be used for checking for license key - changes. Note that this is only applicable when using KeyRef. type: string type: object livenessProbe: - description: LivenessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true logFormat: - description: LogFormat for VMAgent to be configured with. enum: - default - json type: string logLevel: - description: |- - LogLevel for VMAgent to be configured with. - INFO, WARN, ERROR, FATAL, PANIC enum: - INFO - WARN @@ -2435,76 +4672,33 @@ spec: - PANIC type: string managedMetadata: - description: |- - ManagedMetadata defines metadata that will be added to the all objects - created by operator for the given CustomResource properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object type: object maxScrapeInterval: - description: |- - MaxScrapeInterval allows limiting maximum scrape interval for VMServiceScrape, VMPodScrape and other scrapes - If interval is higher than defined limit, `maxScrapeInterval` will be used. type: string minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle format: int32 type: integer minScrapeInterval: - description: |- - MinScrapeInterval allows limiting minimal scrape interval for VMServiceScrape, VMPodScrape and other scrapes - If interval is lower than defined limit, `minScrapeInterval` will be used. type: string nodeScrapeNamespaceSelector: - description: |- - NodeScrapeNamespaceSelector defines Namespaces to be selected for VMNodeScrape discovery. - Works in combination with Selector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault 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 @@ -2518,122 +4712,55 @@ spec: 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 nodeScrapeRelabelTemplate: - description: |- - NodeScrapeRelabelTemplate defines relabel config, that will be added to each VMNodeScrape. - it's useful for adding specific labels to all targets items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. Default - is 'replace' type: string if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source label - values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source label - values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array nodeScrapeSelector: - description: |- - NodeScrapeSelector defines VMNodeScrape to be selected for scraping. - Works in combination with NamespaceSelector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault 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 @@ -2647,127 +4774,71 @@ spec: 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 nodeSelector: additionalProperties: type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. type: object overrideHonorLabels: - description: |- - OverrideHonorLabels if set to true overrides all user configured honor_labels. - If HonorLabels is set in scrape objects to true, this overrides honor_labels to false. type: boolean overrideHonorTimestamps: - description: OverrideHonorTimestamps allows to globally enforce honoring - timestamps in all scrape configs. type: boolean paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. type: boolean + persistentVolumeClaimRetentionPolicy: + properties: + whenDeleted: + type: string + whenScaled: + type: string + type: object podDisruptionBudget: - description: PodDisruptionBudget created by operator properties: maxUnavailable: anyOf: - type: integer - type: string - description: |- - An eviction is allowed if at most "maxUnavailable" pods selected by - "selector" are unavailable after the eviction, i.e. even in absence of - the evicted pod. For example, one can prevent all voluntary evictions - by specifying 0. This is a mutually exclusive setting with "minAvailable". x-kubernetes-int-or-string: true minAvailable: anyOf: - type: integer - type: string - description: |- - An eviction is allowed if at least "minAvailable" pods selected by - "selector" will still be available after the eviction, i.e. even in the - absence of the evicted pod. So for example you can prevent all voluntary - evictions by specifying "100%". x-kubernetes-int-or-string: true selectorLabels: additionalProperties: type: string - description: |- - replaces default labels selector generated by operator - it's useful when you need to create custom budget type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string type: object podMetadata: - description: PodMetadata configures Labels and Annotations which are - propagated to the vmagent pods. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object podScrapeNamespaceSelector: - description: |- - PodScrapeNamespaceSelector defines Namespaces to be selected for VMPodScrape discovery. - Works in combination with Selector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault 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 @@ -2781,122 +4852,55 @@ spec: 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 podScrapeRelabelTemplate: - description: |- - PodScrapeRelabelTemplate defines relabel config, that will be added to each VMPodScrape. - it's useful for adding specific labels to all targets items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. Default - is 'replace' type: string if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source label - values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source label - values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array podScrapeSelector: - description: |- - PodScrapeSelector defines PodScrapes to be selected for target discovery. - Works in combination with NamespaceSelector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault 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 @@ -2910,50 +4914,23 @@ spec: 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 port: - description: Port listen address type: string priorityClassName: - description: PriorityClassName class assigned to the Pods type: string probeNamespaceSelector: - description: |- - ProbeNamespaceSelector defines Namespaces to be selected for VMProbe discovery. - Works in combination with Selector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault 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 @@ -2967,122 +4944,55 @@ spec: 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 probeScrapeRelabelTemplate: - description: |- - ProbeScrapeRelabelTemplate defines relabel config, that will be added to each VMProbeScrape. - it's useful for adding specific labels to all targets items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. Default - is 'replace' type: string if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source label - values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source label - values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array probeSelector: - description: |- - ProbeSelector defines VMProbe to be selected for target probing. - Works in combination with NamespaceSelector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault 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 @@ -3096,121 +5006,77 @@ spec: 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 readinessGates: - description: ReadinessGates defines pod readiness gates items: - description: PodReadinessGate contains the reference to a pod condition properties: conditionType: - description: ConditionType refers to a condition in the pod's - condition list with matching type. type: string required: - conditionType type: object type: array readinessProbe: - description: ReadinessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true relabelConfig: - description: |- - RelabelConfig ConfigMap with global relabel config -remoteWrite.relabelConfig - This relabeling is applied to all the collected metrics before sending them to remote storage. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic remoteWrite: - description: |- - RemoteWrite list of victoria metrics /some other remote write system - for vm it must looks like: http://victoria-metrics-single:8429/api/v1/write - or for cluster different url - https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/app/vmagent#splitting-data-streams-among-multiple-systems items: - description: VMAgentRemoteWriteSpec defines the remote storage configuration - for VmAgent properties: + aws: + properties: + ec2Endpoint: + type: string + region: + type: string + roleARN: + type: string + service: + type: string + stsEndpoint: + type: string + useSigv4: + type: boolean + type: object basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -3218,175 +5084,87 @@ spec: x-kubernetes-map-type: atomic type: object bearerTokenSecret: - description: Optional bearer auth token to use for -remoteWrite.url properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic forceVMProto: - description: ForceVMProto forces using VictoriaMetrics protocol - for sending data to -remoteWrite.url type: boolean headers: - description: |- - Headers allow configuring custom http headers - Must be in form of semicolon separated header with value - e.g. - headerName: headerValue - vmagent supports since 1.79.0 version items: type: string type: array inlineUrlRelabelConfig: - description: InlineUrlRelabelConfig defines relabeling config - for remoteWriteURL, it can be defined at crd spec. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. - Default is 'replace' type: string if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source - label values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source - label values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array maxDiskUsage: - description: |- - MaxDiskUsage defines the maximum file-based buffer size in bytes for the given remoteWrite - It overrides global configuration defined at remoteWriteSettings.maxDiskUsagePerURL x-kubernetes-preserve-unknown-fields: true oauth2: - description: OAuth2 defines auth configuration properties: client_id: - description: The secret or configmap containing the OAuth2 - client id properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -3394,385 +5172,187 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 client secret properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for client secret - file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: - client_id - token_url type: object + proxyURL: + type: string sendTimeout: - description: Timeout for sending a single block of data to -remoteWrite.url - (default 1m0s) pattern: '[0-9]+(ms|s|m|h)' type: string streamAggrConfig: - description: StreamAggrConfig defines stream aggregation configuration - for VMAgent for -remoteWrite.url properties: configmap: - description: ConfigMap with stream aggregation rules properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic dedupInterval: - description: Allows setting different de-duplication intervals - per each configured remote storage type: string dropInput: - description: Allow drop all the input samples after the - aggregation type: boolean dropInputLabels: - description: labels to drop from samples for aggregator - before stream de-duplication and aggregation items: type: string type: array enableWindows: - description: EnableWindows enables aggregating data in separate - windows ( available from v0.54.0). type: boolean ignoreFirstIntervals: - description: IgnoreFirstIntervals instructs to ignore first - interval type: integer + ignoreFirstSampleInterval: + type: string ignoreOldSamples: - description: IgnoreOldSamples instructs to ignore samples - with old timestamps outside the current aggregation interval. type: boolean keepInput: - description: Allows writing both raw and aggregate data type: boolean rules: - description: Stream aggregation rules items: - description: StreamAggrRule defines the rule in stream - aggregation config properties: by: - description: |- - By is an optional list of labels for grouping input series. - - See also Without. - - If neither By nor Without are set, then the Outputs are calculated - individually per each input time series. items: type: string type: array dedup_interval: - description: DedupInterval is an optional interval - for deduplication. type: string drop_input_labels: - description: |- - DropInputLabels is an optional list with labels, which must be dropped before further processing of input samples. - - Labels are dropped before de-duplication and aggregation. items: type: string type: array enable_windows: - description: EnableWindows enables aggregating data - in separate windows type: boolean flush_on_shutdown: - description: |- - FlushOnShutdown defines whether to flush the aggregation state on process termination - or config reload. Is `false` by default. - It is not recommended changing this setting, unless unfinished aggregations states - are preferred to missing data points. type: boolean ignore_first_intervals: type: integer ignore_old_samples: - description: IgnoreOldSamples instructs to ignore - samples with old timestamps outside the current - aggregation interval. type: boolean + ignoreFirstSampleInterval: + type: string input_relabel_configs: - description: |- - InputRelabelConfigs is an optional relabeling rules, which are applied on the input - before aggregation. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex - matching. Default is 'replace' type: string if: - description: 'If represents metricsQL match - expression (or list of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match - for `action: graphite`' type: object match: - description: 'Match is used together with Labels - for `action: graphite`' type: string modulus: - description: Modulus to take of the hash of - the source label values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated - source label values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array interval: - description: Interval is the interval between aggregations. type: string keep_metric_names: - description: KeepMetricNames instructs to leave metric - names as is for the output time series without adding - any suffix. type: boolean match: - description: |- - Match is a label selector (or list of label selectors) for filtering time series for the given selector. - - If the match isn't set, then all the input time series are processed. x-kubernetes-preserve-unknown-fields: true no_align_flush_to_interval: - description: |- - NoAlignFlushToInterval disables aligning of flushes to multiples of Interval. - By default flushes are aligned to Interval. type: boolean output_relabel_configs: - description: |- - OutputRelabelConfigs is an optional relabeling rules, which are applied - on the aggregated output before being sent to remote storage. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex - matching. Default is 'replace' type: string if: - description: 'If represents metricsQL match - expression (or list of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match - for `action: graphite`' type: object match: - description: 'Match is used together with Labels - for `action: graphite`' type: string modulus: - description: Modulus to take of the hash of - the source label values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated - source label values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array outputs: - description: |- - Outputs is a list of output aggregate functions to produce. - - The following names are allowed: - - - total - aggregates input counters - - increase - counts the increase over input counters - - count_series - counts the input series - - count_samples - counts the input samples - - sum_samples - sums the input samples - - last - the last biggest sample value - - min - the minimum sample value - - max - the maximum sample value - - avg - the average value across all the samples - - stddev - standard deviation across all the samples - - stdvar - standard variance across all the samples - - histogram_bucket - creates VictoriaMetrics histogram for input samples - - quantiles(phi1, ..., phiN) - quantiles' estimation for phi in the range [0..1] - - The output time series will have the following names: - - input_name:aggr__ items: type: string type: array staleness_interval: - description: |- - Staleness interval is interval after which the series state will be reset if no samples have been sent during it. - The parameter is only relevant for outputs: total, total_prometheus, increase, increase_prometheus and histogram_bucket. type: string without: - description: |- - Without is an optional list of labels, which must be excluded when grouping input series. - - See also By. - - If neither By nor Without are set, then the Outputs are calculated - individually per each input time series. items: type: string type: array @@ -3783,56 +5363,30 @@ spec: type: array type: object tlsConfig: - description: TLSConfig describes tls configuration for remote - write target properties: ca: - description: Struct containing the CA cert to use for the - targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -3840,56 +5394,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container to use - for the targets. type: string cert: - description: Struct containing the client cert file for - the targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -3897,67 +5425,37 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container - for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container - for the targets. type: string keySecret: - description: Secret containing the client key file for the - targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object url: - description: URL of the endpoint to send samples to. type: string urlRelabelConfig: - description: ConfigMap with relabeling config which is applied - to metrics before sending them to the corresponding -remoteWrite.url properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key must - be defined type: boolean required: - key @@ -3968,81 +5466,40 @@ spec: type: object type: array remoteWriteSettings: - description: RemoteWriteSettings defines global settings for all remoteWrite - urls. properties: flushInterval: - description: Interval for flushing the data to remote storage. - (default 1s) pattern: '[0-9]+(ms|s|m|h)' type: string label: additionalProperties: type: string - description: Labels in the form 'name=value' to add to all the - metrics before sending them. This overrides the label if it - already exists. type: object maxBlockSize: - description: The maximum size in bytes of unpacked request to - send to remote storage format: int32 type: integer maxDiskUsagePerURL: - description: The maximum file-based buffer size in bytes at -remoteWrite.tmpDataPath x-kubernetes-preserve-unknown-fields: true queues: - description: The number of concurrent queues format: int32 type: integer showURL: - description: Whether to show -remoteWrite.url in the exported - metrics. It is hidden by default, since it can contain sensitive - auth info type: boolean tmpDataPath: - description: Path to directory where temporary data for remote - write component is stored (default vmagent-remotewrite-data) type: string useMultiTenantMode: - description: |- - Configures vmagent accepting data via the same multitenant endpoints as vminsert at VictoriaMetrics cluster does, - see [here](https://docs.victoriametrics.com/vmagent/#multitenancy). - it's global setting and affects all remote storage configurations type: boolean type: object replicaCount: - description: ReplicaCount is the expected size of the Application. format: int32 type: integer resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used properties: claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. type: string request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. type: string required: - name @@ -4058,9 +5515,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -4069,97 +5523,350 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. format: int32 type: integer rollingUpdate: - description: RollingUpdate - overrides deployment update params. properties: maxSurge: anyOf: - type: integer - type: string - description: |- - The maximum number of pods that can be scheduled above the desired number of - pods. - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). - This can not be 0 if MaxUnavailable is 0. - Absolute number is calculated from percentage by rounding up. - Defaults to 25%. - Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when - the rolling update starts, such that the total number of old and new pods do not exceed - 130% of desired pods. Once old pods have been killed, - new ReplicaSet can be scaled up further, ensuring that total number of pods running - at any time during the update is at most 130% of desired pods. x-kubernetes-int-or-string: true maxUnavailable: anyOf: - type: integer - type: string - description: |- - The maximum number of pods that can be unavailable during the update. - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). - Absolute number is calculated from percentage by rounding down. - This can not be 0 if MaxSurge is 0. - Defaults to 25%. - Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods - immediately when the rolling update starts. Once new pods are ready, old ReplicaSet - can be scaled down further, followed by scaling up the new ReplicaSet, ensuring - that the total number of pods available at all times during the update is at - least 70% of desired pods. x-kubernetes-int-or-string: true type: object runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ type: string + sampleLimit: + type: integer schedulerName: - description: SchedulerName - defines kubernetes scheduler name type: string - scrapeConfigNamespaceSelector: - description: |- - ScrapeConfigNamespaceSelector defines Namespaces to be selected for VMScrapeConfig discovery. - Works in combination with Selector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault - 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. + scrapeClasses: + items: + properties: + attachMetadata: + properties: + namespace: + type: boolean + node: + type: boolean + type: object + authorization: + properties: + credentials: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + credentialsFile: + type: string + type: + type: string + type: object + basicAuth: + properties: + password: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + password_file: + type: string + username: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenFile: + type: string + bearerTokenSecret: + nullable: true + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + default: + type: boolean + metricRelabelConfigs: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + name: + minLength: 1 + type: string + oauth2: + properties: + client_id: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + client_secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + client_secret_file: + type: string + endpoint_params: + additionalProperties: + type: string + type: object + proxy_url: + type: string + scopes: + items: + type: string + type: array + tls_config: + x-kubernetes-preserve-unknown-fields: true + token_url: + minLength: 1 + type: string + required: + - client_id + - token_url + type: object + relabelConfigs: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + tlsConfig: + properties: + ca: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + caFile: + type: string + cert: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + certFile: + type: string + insecureSkipVerify: + type: boolean + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + type: string + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + scrapeConfigNamespaceSelector: + properties: + matchExpressions: + items: 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 @@ -4173,119 +5880,55 @@ spec: 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 scrapeConfigRelabelTemplate: - description: |- - ScrapeConfigRelabelTemplate defines relabel config, that will be added to each VMScrapeConfig. - it's useful for adding specific labels to all targets items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. Default - is 'replace' type: string if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source label - values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source label - values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array scrapeConfigSelector: - description: |- - ScrapeConfigSelector defines VMScrapeConfig to be selected for target discovery. - Works in combination with NamespaceSelector. 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 @@ -4299,77 +5942,36 @@ spec: 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 scrapeInterval: - description: ScrapeInterval defines how often scrape targets by default pattern: '[0-9]+(ms|s|m|h)' type: string scrapeTimeout: - description: ScrapeTimeout defines global timeout for targets scrape pattern: '[0-9]+(ms|s|m|h)' type: string secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder items: type: string type: array securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. type: object x-kubernetes-preserve-unknown-fields: true selectAllByDefault: - description: |- - SelectAllByDefault changes default behavior for empty CRD selectors, such ServiceScrapeSelector. - with selectAllByDefault: true and empty serviceScrapeSelector and ServiceScrapeNamespaceSelector - Operator selects all exist serviceScrapes - with selectAllByDefault: false - selects nothing type: boolean serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to use to run the pods type: string serviceScrapeNamespaceSelector: - description: |- - ServiceScrapeNamespaceSelector Namespaces to be selected for VMServiceScrape discovery. - Works in combination with Selector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault 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 @@ -4383,122 +5985,55 @@ spec: 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 serviceScrapeRelabelTemplate: - description: |- - ServiceScrapeRelabelTemplate defines relabel config, that will be added to each VMServiceScrape. - it's useful for adding specific labels to all targets items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. Default - is 'replace' type: string if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source label - values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source label - values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array serviceScrapeSelector: - description: |- - ServiceScrapeSelector defines ServiceScrapes to be selected for target discovery. - Works in combination with NamespaceSelector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault 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 @@ -4512,209 +6047,101 @@ spec: 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 serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vmagent VMServiceScrape - spec required: - endpoints type: object x-kubernetes-preserve-unknown-fields: true serviceSpec: - description: ServiceSpec that will be added to vmagent service spec properties: metadata: - description: EmbeddedObjectMetadata defines objectMeta for additional - service. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ type: object x-kubernetes-preserve-unknown-fields: true useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication type: boolean required: - spec type: object shardCount: - description: |- - ShardCount - numbers of shards of VMAgent - in this case operator will use 1 deployment/sts per shard with - replicas count according to spec.replicas, - see [here](https://docs.victoriametrics.com/vmagent/#scraping-big-number-of-targets) + format: int32 type: integer startupProbe: - description: StartupProbe that will be added to CRD pod type: object x-kubernetes-preserve-unknown-fields: true statefulMode: - description: |- - StatefulMode enables StatefulSet for `VMAgent` instead of Deployment - it allows using persistent storage for vmagent's persistentQueue type: boolean statefulRollingUpdateStrategy: - description: |- - StatefulRollingUpdateStrategy allows configuration for strategyType - set it to RollingUpdate for disabling operator statefulSet rollingUpdate type: string - statefulStorage: - description: StatefulStorage configures storage for StatefulSet + statefulRollingUpdateStrategyBehavior: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + statefulStorage: properties: - disableMountSubPath: - description: |- - Deprecated: subPath usage will be disabled by default in a future release, this option will become unnecessary. - DisableMountSubPath allows to remove any subPath usage in volume mounts. - type: boolean emptyDir: - description: |- - EmptyDirVolumeSource to be used by the Prometheus StatefulSets. If specified, used in place of any volumeClaimTemplate. More - info: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir properties: medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir type: string sizeLimit: anyOf: - type: integer - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true type: object volumeClaimTemplate: - description: A PVC spec to be used by the VMAlertManager StatefulSets. 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: - description: EmbeddedMetadata contains metadata relevant to - an EmbeddedResource. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object spec: - description: |- - Spec defines the desired characteristics of a volume requested by a pod author. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims properties: accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string type: array x-kubernetes-list-type: atomic dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. properties: apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. type: string kind: - description: Kind is the type of resource being referenced type: string name: - description: Name is the name of resource being referenced type: string required: - kind @@ -4722,60 +6149,20 @@ spec: type: object x-kubernetes-map-type: atomic dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. properties: apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. type: string kind: - description: Kind is the type of resource being referenced type: string name: - description: Name is the name of resource being referenced type: string namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. type: string required: - kind - name type: object resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources properties: limits: additionalProperties: @@ -4784,9 +6171,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -4795,40 +6179,18 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object selector: - description: selector is a label query over volumes to - consider for binding. 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 @@ -4842,100 +6204,28 @@ spec: 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 storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 type: string volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. type: string volumeName: - description: volumeName is the binding reference to the - PersistentVolume backing this claim. type: string type: object status: - description: |- - Status represents the current information/status of a persistent volume claim. - Read-only. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims properties: accessModes: - description: |- - accessModes contains the actual access modes the volume backing the PVC has. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string type: array x-kubernetes-list-type: atomic allocatedResourceStatuses: additionalProperties: - description: |- - When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource - that it does not recognizes, then it should ignore that update and let other controllers - handle it. type: string - description: "allocatedResourceStatuses stores status - of resource being resized for the given PVC.\nKey names - follow standard Kubernetes label syntax. Valid values - are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources must - use implementation-defined prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have - kubernetes.io prefix are considered\nreserved and hence - may not be used.\n\nClaimResourceStatus can be in any - of following states:\n\t- ControllerResizeInProgress:\n\t\tState - set when resize controller starts resizing the volume - in control-plane.\n\t- ControllerResizeFailed:\n\t\tState - set when resize has failed in resize controller with - a terminal error.\n\t- NodeResizePending:\n\t\tState - set when resize controller has finished resizing the - volume but further resizing of\n\t\tvolume is needed - on the node.\n\t- NodeResizeInProgress:\n\t\tState set - when kubelet starts resizing the volume.\n\t- NodeResizeFailed:\n\t\tState - set when resizing has failed in kubelet with a terminal - error. Transient errors don't set\n\t\tNodeResizeFailed.\nFor - example: if expanding a PVC for more capacity - this - field can be one of the following states:\n\t- pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeFailed\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizePending\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeFailed\"\nWhen this field is not set, - it means that no resize operation is in progress for - the given PVC.\n\nA controller that receives PVC update - with previously unknown resourceName or ClaimResourceStatus\nshould - ignore the update for the purpose it was designed. For - example - a controller that\nonly is responsible for - resizing capacity of the volume, should ignore PVC updates - that change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." type: object x-kubernetes-map-type: granular allocatedResources: @@ -4945,31 +6235,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: "allocatedResources tracks the resources - allocated to a PVC including its capacity.\nKey names - follow standard Kubernetes label syntax. Valid values - are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources must - use implementation-defined prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have - kubernetes.io prefix are considered\nreserved and hence - may not be used.\n\nCapacity reported here may be larger - than the actual capacity when a volume expansion operation\nis - requested.\nFor storage quota, the larger value from - allocatedResources and PVC.spec.resources is used.\nIf - allocatedResources is not set, PVC.spec.resources alone - is used for quota calculation.\nIf a volume expansion - capacity request is lowered, allocatedResources is only\nlowered - if there are no expansion operations in progress and - if the actual volume capacity\nis equal or lower than - the requested capacity.\n\nA controller that receives - PVC update with previously unknown resourceName\nshould - ignore the update for the purpose it was designed. For - example - a controller that\nonly is responsible for - resizing capacity of the volume, should ignore PVC updates - that change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." type: object capacity: additionalProperties: @@ -4978,47 +6243,23 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: capacity represents the actual resources - of the underlying volume. type: object conditions: - description: |- - conditions is the current Condition of persistent volume claim. If underlying persistent volume is being - resized then the Condition will be set to 'Resizing'. items: - description: PersistentVolumeClaimCondition contains - details about state of pvc properties: lastProbeTime: - description: lastProbeTime is the time we probed - the condition. format: date-time type: string lastTransitionTime: - description: lastTransitionTime is the time the - condition transitioned from one status to another. format: date-time type: string message: - description: message is the human-readable message - indicating details about last transition. type: string reason: - description: |- - reason is a unique, this should be a short, machine understandable string that gives the reason - for condition's last transition. If it reports "Resizing" that means the underlying - persistent volume is being resized. type: string status: - description: |- - Status is the status of the condition. - Can be True, False, Unknown. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=state%20of%20pvc-,conditions.status,-(string)%2C%20required type: string type: - description: |- - Type is the type of the condition. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=set%20to%20%27ResizeStarted%27.-,PersistentVolumeClaimCondition,-contains%20details%20about type: string required: - status @@ -5029,76 +6270,31 @@ spec: - type x-kubernetes-list-type: map currentVolumeAttributesClassName: - description: |- - currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. - When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). type: string modifyVolumeStatus: - description: |- - ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. - When this is unset, there is no ModifyVolume operation being attempted. - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). properties: status: - description: "status is the status of the ControllerModifyVolume - operation. It can be in any of following states:\n - - Pending\n Pending indicates that the PersistentVolumeClaim - cannot be modified due to unmet requirements, such - as\n the specified VolumeAttributesClass not existing.\n - - InProgress\n InProgress indicates that the volume - is being modified.\n - Infeasible\n Infeasible - indicates that the request has been rejected as - invalid by the CSI driver. To\n\t resolve the error, - a valid VolumeAttributesClass needs to be specified.\nNote: - New statuses can be added in the future. Consumers - should check for unknown statuses and fail appropriately." type: string targetVolumeAttributesClassName: - description: targetVolumeAttributesClassName is the - name of the VolumeAttributesClass the PVC currently - being reconciled type: string required: - status type: object phase: - description: phase represents the current phase of PersistentVolumeClaim. type: string type: object type: object type: object staticScrapeNamespaceSelector: - description: |- - StaticScrapeNamespaceSelector defines Namespaces to be selected for VMStaticScrape discovery. - Works in combination with NamespaceSelector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault 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 @@ -5112,122 +6308,55 @@ spec: 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 staticScrapeRelabelTemplate: - description: |- - StaticScrapeRelabelTemplate defines relabel config, that will be added to each VMStaticScrape. - it's useful for adding specific labels to all targets items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. Default - is 'replace' type: string if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source label - values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source label - values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array staticScrapeSelector: - description: |- - StaticScrapeSelector defines VMStaticScrape to be selected for target discovery. - Works in combination with NamespaceSelector. - If both nil - match everything. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. 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 @@ -5241,325 +6370,152 @@ spec: 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 streamAggrConfig: - description: StreamAggrConfig defines global stream aggregation configuration - for VMAgent properties: configmap: - description: ConfigMap with stream aggregation rules properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic dedupInterval: - description: Allows setting different de-duplication intervals - per each configured remote storage type: string dropInput: - description: Allow drop all the input samples after the aggregation type: boolean dropInputLabels: - description: labels to drop from samples for aggregator before - stream de-duplication and aggregation items: type: string type: array enableWindows: - description: EnableWindows enables aggregating data in separate - windows ( available from v0.54.0). type: boolean ignoreFirstIntervals: - description: IgnoreFirstIntervals instructs to ignore first interval type: integer + ignoreFirstSampleInterval: + type: string ignoreOldSamples: - description: IgnoreOldSamples instructs to ignore samples with - old timestamps outside the current aggregation interval. type: boolean keepInput: - description: Allows writing both raw and aggregate data type: boolean rules: - description: Stream aggregation rules items: - description: StreamAggrRule defines the rule in stream aggregation - config properties: by: - description: |- - By is an optional list of labels for grouping input series. - - See also Without. - - If neither By nor Without are set, then the Outputs are calculated - individually per each input time series. items: type: string type: array dedup_interval: - description: DedupInterval is an optional interval for deduplication. type: string drop_input_labels: - description: |- - DropInputLabels is an optional list with labels, which must be dropped before further processing of input samples. - - Labels are dropped before de-duplication and aggregation. items: type: string type: array enable_windows: - description: EnableWindows enables aggregating data in separate - windows type: boolean flush_on_shutdown: - description: |- - FlushOnShutdown defines whether to flush the aggregation state on process termination - or config reload. Is `false` by default. - It is not recommended changing this setting, unless unfinished aggregations states - are preferred to missing data points. type: boolean ignore_first_intervals: type: integer ignore_old_samples: - description: IgnoreOldSamples instructs to ignore samples - with old timestamps outside the current aggregation interval. type: boolean + ignoreFirstSampleInterval: + type: string input_relabel_configs: - description: |- - InputRelabelConfigs is an optional relabeling rules, which are applied on the input - before aggregation. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. - Default is 'replace' type: string if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for - `action: graphite`' type: object match: - description: 'Match is used together with Labels for - `action: graphite`' type: string modulus: - description: Modulus to take of the hash of the source - label values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated - source label values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array interval: - description: Interval is the interval between aggregations. type: string keep_metric_names: - description: KeepMetricNames instructs to leave metric names - as is for the output time series without adding any suffix. type: boolean match: - description: |- - Match is a label selector (or list of label selectors) for filtering time series for the given selector. - - If the match isn't set, then all the input time series are processed. x-kubernetes-preserve-unknown-fields: true no_align_flush_to_interval: - description: |- - NoAlignFlushToInterval disables aligning of flushes to multiples of Interval. - By default flushes are aligned to Interval. type: boolean output_relabel_configs: - description: |- - OutputRelabelConfigs is an optional relabeling rules, which are applied - on the aggregated output before being sent to remote storage. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. - Default is 'replace' type: string if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for - `action: graphite`' type: object match: - description: 'Match is used together with Labels for - `action: graphite`' type: string modulus: - description: Modulus to take of the hash of the source - label values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated - source label values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array outputs: - description: |- - Outputs is a list of output aggregate functions to produce. - - The following names are allowed: - - - total - aggregates input counters - - increase - counts the increase over input counters - - count_series - counts the input series - - count_samples - counts the input samples - - sum_samples - sums the input samples - - last - the last biggest sample value - - min - the minimum sample value - - max - the maximum sample value - - avg - the average value across all the samples - - stddev - standard deviation across all the samples - - stdvar - standard variance across all the samples - - histogram_bucket - creates VictoriaMetrics histogram for input samples - - quantiles(phi1, ..., phiN) - quantiles' estimation for phi in the range [0..1] - - The output time series will have the following names: - - input_name:aggr__ items: type: string type: array staleness_interval: - description: |- - Staleness interval is interval after which the series state will be reset if no samples have been sent during it. - The parameter is only relevant for outputs: total, total_prometheus, increase, increase_prometheus and histogram_bucket. type: string without: - description: |- - Without is an optional list of labels, which must be excluded when grouping input series. - - See also By. - - If neither By nor Without are set, then the Outputs are calculated - individually per each input time series. items: type: string type: array @@ -5570,58 +6526,26 @@ spec: type: array type: object terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container graceful - termination format: int64 type: integer tolerations: - description: Tolerations If specified, the pod's tolerations. items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. type: string type: object type: array topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ items: - description: TopologySpreadConstraint specifies how to spread matching - pods among the given topology. required: - maxSkew - topologyKey @@ -5630,97 +6554,34 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array updateStrategy: - description: |- - UpdateStrategy - overrides default update strategy. - works only for deployments, statefulset always use OnDelete. enum: - Recreate - RollingUpdate type: string useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements type: boolean useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions type: boolean useVMConfigReloader: - description: |- - UseVMConfigReloader replaces prometheus-like config-reloader - with vm one. It uses secrets watch instead of file watch - which greatly increases speed of config updates type: boolean vmAgentExternalLabelName: - description: |- - VMAgentExternalLabelName Name of vmAgent external label used to denote vmAgent instance - name. Defaults to the value of `prometheus`. External label will - _not_ be added when value is set to empty string (`""`). type: string volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container items: - description: VolumeMount describes a mounting of a Volume within - a container. properties: mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. type: string mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). type: string name: - description: This must match the Name of a Volume. type: string readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. type: boolean recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). type: string subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. type: string required: - mountPath @@ -5728,13 +6589,7 @@ spec: type: object type: array volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional items: - description: Volume represents a named volume in a pod that may - be accessed by any container in the pod. required: - name type: object @@ -5744,58 +6599,34 @@ spec: - remoteWrite type: object status: - description: VMAgentStatus defines the observed state of VMAgent properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -5810,28 +6641,19 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string replicas: - description: ReplicaCount Total number of pods targeted by this VMAgent format: int32 type: integer selector: - description: Selector string form of label value set for autoscaling type: string shards: - description: Shards represents total number of vmagent deployments - with uniq scrape targets format: int32 type: integer updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -5848,7 +6670,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmalertmanagerconfigs.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -5872,180 +6694,90 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMAlertmanagerConfig is the Schema for the vmalertmanagerconfigs - API 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: |- - VMAlertmanagerConfigSpec defines configuration for VMAlertmanagerConfig - it must reference only locally defined objects properties: inhibit_rules: - description: |- - InhibitRules will only apply for alerts matching - the resource's namespace. items: - description: |- - InhibitRule defines an inhibition rule that allows to mute alerts when other - alerts are already firing. - Note, it doesn't support deprecated alertmanager config options. - See https://prometheus.io/docs/alerting/latest/configuration/#inhibit_rule properties: equal: - description: |- - Labels that must have an equal value in the source and target alert for - the inhibition to take effect. items: type: string type: array source_matchers: - description: |- - SourceMatchers defines a list of matchers for which one or more alerts have - to exist for the inhibition to take effect. items: type: string type: array target_matchers: - description: |- - TargetMatchers defines a list of matchers that have to be fulfilled by the target - alerts to be muted. items: type: string type: array type: object type: array receivers: - description: Receivers defines alert receivers items: - description: Receiver defines one or more notification integrations. properties: discord_configs: items: properties: avatar_url: - description: |- - AvatarURL defines message avatar URL - Available from operator v0.55.0 and alertmanager v0.28.0 type: string content: - description: |- - Content defines message content template - Available from operator v0.55.0 and alertmanager v0.28.0 maxLength: 2000 type: string http_config: - description: HTTP client configuration. properties: authorization: - description: |- - Authorization header configuration for the client. - This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. properties: credentials: - description: Reference to the secret with value - for authorization properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to - bearer type: string type: object basic_auth: - description: BasicAuth for the client. properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key @@ -6053,88 +6785,45 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token_file: - description: BearerTokenFile defines filename for - bearer token, it must be mounted to pod. type: string bearer_token_secret: - description: |- - The secret's key that contains the bearer token - It must be at them same namespace as CRD properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic oauth2: - description: OAuth2 client credentials used to fetch - a token for the targets. properties: client_id: - description: The secret or configmap containing - the OAuth2 client id properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -6142,60 +6831,33 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 - client secret properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for - client secret file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token - URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token - request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: @@ -6203,60 +6865,32 @@ spec: - token_url type: object proxyURL: - description: Optional proxy URL. type: string tls_config: - description: TLS configuration for the client. properties: ca: - description: Struct containing the CA cert to - use for the targets. properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -6264,58 +6898,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container - to use for the targets. type: string cert: - description: Struct containing the client cert - file for the targets. properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -6323,89 +6929,46 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the - container for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the - container for the targets. type: string keySecret: - description: Secret containing the client key - file for the targets. properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the - targets. type: string type: object type: object message: - description: The message body template type: string send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean title: - description: The message title template type: string username: - description: |- - Username defines message username - Available from operator v0.55.0 and alertmanager v0.28.0 type: string webhook_url: - description: |- - The discord webhook URL - one of `urlSecret` and `url` must be defined. type: string webhook_url_secret: - description: |- - URLSecret defines secret name and key at the CRD namespace. - It must contain the webhook URL. - one of `urlSecret` and `url` must be defined. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -6414,153 +6977,81 @@ spec: type: object type: array email_configs: - description: EmailConfigs defines email notification configurations. items: - description: EmailConfig configures notifications via Email. properties: auth_identity: - description: The identity to use for authentication. type: string auth_password: - description: AuthPassword defines secret name and key - at CRD namespace. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic auth_secret: - description: |- - AuthSecret defines secrent name and key at CRD namespace. - It must contain the CRAM-MD5 secret. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic auth_username: - description: The username to use for authentication. type: string from: - description: |- - The sender address. - fallback to global setting if empty type: string headers: additionalProperties: type: string - description: |- - Further headers email header key/value pairs. Overrides any headers - previously set by the notification implementation. type: object hello: - description: The hostname to identify to the SMTP server. type: string html: - description: The HTML body of the email notification. type: string require_tls: - description: |- - The SMTP TLS requirement. - Note that Go does not support unencrypted connections to remote SMTP endpoints. type: boolean send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean smarthost: - description: |- - The SMTP host through which emails are sent. - fallback to global setting if empty type: string text: - description: The text body of the email notification. type: string tls_config: - description: TLS configuration properties: ca: - description: Struct containing the CA cert to use - for the targets. properties: configMap: - description: ConfigMap containing data to use - for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for - the targets. properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key @@ -6568,57 +7059,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container - to use for the targets. type: string cert: - description: Struct containing the client cert file - for the targets. properties: configMap: - description: ConfigMap containing data to use - for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for - the targets. properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key @@ -6626,121 +7090,94 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container - for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container - for the targets. type: string keySecret: - description: Secret containing the client key file - for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object to: - description: The email address to send notifications to. + type: string + type: object + type: array + incidentio_configs: + items: + properties: + alert_source_token: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + http_config: + x-kubernetes-preserve-unknown-fields: true + max_alerts: + type: integer + send_resolved: + type: boolean + timeout: + type: string + url: type: string type: object type: array jira_configs: items: - description: |- - JiraConfig represent alertmanager's jira_config entry - https://prometheus.io/docs/alerting/latest/configuration/#jira_config - available from v0.55.0 operator version - and v0.28.0 alertmanager version properties: api_url: - description: |- - The URL to send API requests to. The full API path must be included. - Example: https://company.atlassian.net/rest/api/2/ type: string custom_fields: additionalProperties: x-kubernetes-preserve-unknown-fields: true - description: |- - Other issue and custom fields. - Jira issue field can have multiple types. - Depends on the field type, the values must be provided differently. - See https://developer.atlassian.com/server/jira/platform/jira-rest-api-examples/#setting-custom-field-data-for-other-field-types for further examples. type: object description: - description: Issue description template. type: string http_config: - description: |- - The HTTP client's configuration. You must use this configuration to supply the personal access token (PAT) as part of the HTTP `Authorization` header. - For Jira Cloud, use basic_auth with the email address as the username and the PAT as the password. - For Jira Data Center, use the 'authorization' field with 'credentials: '. x-kubernetes-preserve-unknown-fields: true issue_type: - description: Type of the issue (e.g. Bug) type: string labels: - description: Labels to be added to the issue items: type: string type: array priority: - description: Priority of the issue type: string project: - description: The project key where issues are created type: string reopen_duration: - description: |- - If reopen_transition is defined, reopen the issue when it is not older than this value (rounded down to the nearest minute). - The resolutiondate field is used to determine the age of the issue. pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ type: string reopen_transition: - description: |- - Name of the workflow transition to resolve an issue. - The target status must have the category "done". type: string resolve_transition: - description: |- - Name of the workflow transition to reopen an issue. - The target status should not have the category "done". type: string send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean summary: - description: Issue summary template type: string wont_fix_resolution: - description: If reopen_transition is defined, ignore issues - with that resolution. type: string required: - issue_type @@ -6751,101 +7188,52 @@ spec: items: properties: http_config: - description: HTTP client configuration. properties: authorization: - description: |- - Authorization header configuration for the client. - This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. properties: credentials: - description: Reference to the secret with value - for authorization properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to - bearer type: string type: object basic_auth: - description: BasicAuth for the client. properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key @@ -6853,88 +7241,45 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token_file: - description: BearerTokenFile defines filename for - bearer token, it must be mounted to pod. type: string bearer_token_secret: - description: |- - The secret's key that contains the bearer token - It must be at them same namespace as CRD properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic oauth2: - description: OAuth2 client credentials used to fetch - a token for the targets. properties: client_id: - description: The secret or configmap containing - the OAuth2 client id properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -6942,60 +7287,33 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 - client secret properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for - client secret file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token - URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token - request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: @@ -7003,60 +7321,32 @@ spec: - token_url type: object proxyURL: - description: Optional proxy URL. type: string tls_config: - description: TLS configuration for the client. properties: ca: - description: Struct containing the CA cert to - use for the targets. properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -7064,58 +7354,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container - to use for the targets. type: string cert: - description: Struct containing the client cert - file for the targets. properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -7123,84 +7385,44 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the - container for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the - container for the targets. type: string keySecret: - description: Secret containing the client key - file for the targets. properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the - targets. type: string type: object type: object send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean text: - description: The text body of the teams notification. type: string title: - description: The title of the teams notification. type: string webhook_url: - description: |- - The incoming webhook URL - one of `urlSecret` and `url` must be defined. type: string webhook_url_secret: - description: |- - URLSecret defines secret name and key at the CRD namespace. - It must contain the webhook URL. - one of `urlSecret` and `url` must be defined. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -7210,51 +7432,25 @@ spec: type: array msteamsv2_configs: items: - description: |- - MSTeamsV2Config sends notifications using the new message format with adaptive cards as required by flows. - https://support.microsoft.com/en-gb/office/create-incoming-webhooks-with-workflows-for-microsoft-teams-8ae491c7-0394-4861-ba59-055e33f75498 - available from v0.55.0 operator version - and v0.28.0 alertmanager version properties: http_config: x-kubernetes-preserve-unknown-fields: true send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean text: - description: Message body template. type: string title: - description: Message title template. type: string webhook_url: - description: |- - The incoming webhook URL - one of `urlSecret` and `url` must be defined. type: string webhook_url_secret: - description: |- - URLSecret defines secret name and key at the CRD namespace. - It must contain the webhook URL. - one of `webhook_url` or `webhook_url_secret` must be defined. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -7263,165 +7459,95 @@ spec: type: object type: array name: - description: Name of the receiver. Must be unique across all - items from the list. minLength: 1 type: string opsgenie_configs: - description: OpsGenieConfigs defines ops genie notification - configurations. items: - description: |- - OpsGenieConfig configures notifications via OpsGenie. - See https://prometheus.io/docs/alerting/latest/configuration/#opsgenie_config properties: actions: - description: Comma separated list of actions that will - be available for the alert. type: string api_key: - description: |- - The secret's key that contains the OpsGenie API key. - It must be at them same namespace as CRD - fallback to global setting if empty properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic apiURL: - description: The URL to send OpsGenie API requests to. type: string description: - description: Description of the incident. type: string details: additionalProperties: type: string - description: A set of arbitrary key/value pairs that provide - further detail about the incident. type: object entity: - description: Optional field that can be used to specify - which domain alert is related to. type: string http_config: - description: HTTP client configuration. type: object x-kubernetes-preserve-unknown-fields: true message: - description: Alert text limited to 130 characters. type: string note: - description: Additional alert note. type: string priority: - description: Priority level of alert. Possible values - are P1, P2, P3, P4, and P5. type: string responders: - description: List of responders responsible for notifications. items: - description: |- - OpsGenieConfigResponder defines a responder to an incident. - One of `id`, `name` or `username` has to be defined. properties: id: - description: ID of the responder. type: string name: - description: Name of the responder. type: string type: - description: Type of responder. minLength: 1 type: string username: - description: Username of the responder. type: string required: - type type: object type: array send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean source: - description: Backlink to the sender of the notification. type: string tags: - description: Comma separated list of tags attached to - the notifications. type: string update_alerts: - description: |- - Whether to update message and description of the alert in OpsGenie if it already exists - By default, the alert is never updated in OpsGenie, the new message only appears in activity log. type: boolean type: object type: array pagerduty_configs: - description: PagerDutyConfigs defines pager duty notification - configurations. items: - description: |- - PagerDutyConfig configures notifications via PagerDuty. - See https://prometheus.io/docs/alerting/latest/configuration/#pagerduty_config properties: class: - description: The class/type of the event. type: string client: - description: Client identification. type: string client_url: - description: Backlink to the sender of notification. type: string component: - description: The part or component of the affected system - that is broken. type: string description: - description: Description of the incident. type: string details: additionalProperties: type: string - description: Arbitrary key/value pairs that provide further - detail about the incident. type: object group: - description: A cluster or grouping of sources. type: string http_config: - description: HTTP client configuration. type: object x-kubernetes-preserve-unknown-fields: true images: - description: Images to attach to the incident. items: - description: |- - ImageConfig is used to attach images to the incident. - See https://developer.pagerduty.com/docs/ZG9jOjExMDI5NTgx-send-an-alert-event#the-images-property - for more information. properties: alt: type: string @@ -7434,12 +7560,7 @@ spec: type: object type: array links: - description: Links to attach to the incident. items: - description: |- - LinkConfig is used to attach text links to the incident. - See https://developer.pagerduty.com/docs/ZG9jOjExMDI5NTgx-send-an-alert-event#the-links-property - for more information. properties: href: type: string @@ -7450,170 +7571,86 @@ spec: type: object type: array routing_key: - description: |- - The secret's key that contains the PagerDuty integration key (when using - Events API v2). Either this field or `serviceKey` needs to be defined. - It must be at them same namespace as CRD properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean service_key: - description: |- - The secret's key that contains the PagerDuty service key (when using - integration type "Prometheus"). Either this field or `routingKey` needs to - be defined. - It must be at them same namespace as CRD properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic severity: - description: Severity of the incident. type: string url: - description: The URL to send requests to. type: string type: object type: array pushover_configs: - description: PushoverConfigs defines push over notification - configurations. items: - description: |- - PushoverConfig configures notifications via Pushover. - See https://prometheus.io/docs/alerting/latest/configuration/#pushover_config properties: expire: - description: |- - How long your notification will continue to be retried for, unless the user - acknowledges the notification. type: string html: - description: Whether notification message is HTML or plain - text. type: boolean http_config: - description: HTTP client configuration. type: object x-kubernetes-preserve-unknown-fields: true message: - description: Notification message. type: string priority: - description: Priority, see https://pushover.net/api#priority type: string retry: - description: |- - How often the Pushover servers will send the same notification to the user. - Must be at least 30 seconds. type: string send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean sound: - description: The name of one of the sounds supported by - device clients to override the user's default sound - choice type: string title: - description: Notification title. type: string token: - description: |- - The secret's key that contains the registered application’s API token, see https://pushover.net/apps. - It must be at them same namespace as CRD properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic url: - description: A supplementary URL shown alongside the message. type: string url_title: - description: A title for supplementary URL, otherwise - just the URL is shown type: string user_key: - description: |- - The secret's key that contains the recipient user’s user key. - It must be at them same namespace as CRD properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -7623,17 +7660,9 @@ spec: type: array rocketchat_configs: items: - description: |- - RocketchatConfig configures notifications via Rocketchat. - https://prometheus.io/docs/alerting/latest/configuration/#rocketchat_config - available from v0.55.0 operator version - and v0.28.0 alertmanager version properties: actions: items: - description: |- - RocketchatAttachmentAction defines message attachements - https://github.com/RocketChat/Rocket.Chat.Go.SDK/blob/master/models/message.go properties: msg: type: string @@ -7648,8 +7677,6 @@ spec: api_url: type: string channel: - description: 'RocketChat channel override, (like #other-channel - or @username).' type: string color: type: string @@ -7657,9 +7684,6 @@ spec: type: string fields: items: - description: |- - RocketchatAttachmentField defines API fields - https://developer.rocket.chat/reference/api/rest-api/endpoints/messaging/chat-endpoints/postmessage#attachment-field-objects properties: short: type: boolean @@ -7678,8 +7702,6 @@ spec: link_names: type: boolean send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean short_fields: type: boolean @@ -7692,50 +7714,26 @@ spec: title_link: type: string token: - description: SecretKeySelector selects a key of a Secret. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic token_id: - description: |- - The sender token and token_id - See https://docs.rocket.chat/use-rocket.chat/user-guides/user-panel/my-account#personal-access-tokens properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -7744,29 +7742,12 @@ spec: type: object type: array slack_configs: - description: SlackConfigs defines slack notification configurations. items: - description: |- - SlackConfig configures notifications via Slack. - See https://prometheus.io/docs/alerting/latest/configuration/#slack_config properties: actions: - description: A list of Slack actions that are sent with - each notification. items: - description: |- - SlackAction configures a single Slack action that is sent with each - notification. - See https://api.slack.com/docs/message-attachments#action_fields and - https://api.slack.com/docs/message-buttons for more information. properties: confirm: - description: |- - SlackConfirmationField protect users from destructive actions or - particularly distinguished decisions by asking them to confirm their button - click one more time. - See https://api.slack.com/docs/interactive-message-field-guide#confirmation_fields - for more information. properties: dismiss_text: type: string @@ -7800,27 +7781,13 @@ spec: type: object type: array api_url: - description: |- - The secret's key that contains the Slack webhook URL. - It must be at them same namespace as CRD - fallback to global setting if empty properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -7829,20 +7796,13 @@ spec: callback_id: type: string channel: - description: The channel or user to send notifications - to. type: string color: type: string fallback: type: string fields: - description: A list of Slack fields that are sent with - each notification. items: - description: |- - SlackField configures a single Slack field that is sent with each notification. - See https://api.slack.com/docs/message-attachments#fields for more information. properties: short: type: boolean @@ -7860,7 +7820,6 @@ spec: footer: type: string http_config: - description: HTTP client configuration. type: object x-kubernetes-preserve-unknown-fields: true icon_emoji: @@ -7878,8 +7837,6 @@ spec: pretext: type: string send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean short_fields: type: boolean @@ -7899,109 +7856,58 @@ spec: items: properties: api_url: - description: The api URL type: string attributes: additionalProperties: type: string - description: SNS message attributes type: object http_config: - description: HTTP client configuration. properties: authorization: - description: |- - Authorization header configuration for the client. - This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. properties: credentials: - description: Reference to the secret with value - for authorization properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to - bearer type: string type: object basic_auth: - description: BasicAuth for the client. properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key @@ -8009,88 +7915,45 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token_file: - description: BearerTokenFile defines filename for - bearer token, it must be mounted to pod. type: string bearer_token_secret: - description: |- - The secret's key that contains the bearer token - It must be at them same namespace as CRD properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic oauth2: - description: OAuth2 client credentials used to fetch - a token for the targets. properties: client_id: - description: The secret or configmap containing - the OAuth2 client id properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -8098,60 +7961,33 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 - client secret properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for - client secret file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token - URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token - request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: @@ -8159,60 +7995,32 @@ spec: - token_url type: object proxyURL: - description: Optional proxy URL. type: string tls_config: - description: TLS configuration for the client. properties: ca: - description: Struct containing the CA cert to - use for the targets. properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -8220,58 +8028,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container - to use for the targets. type: string cert: - description: Struct containing the client cert - file for the targets. properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -8279,124 +8059,65 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the - container for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the - container for the targets. type: string keySecret: - description: Secret containing the client key - file for the targets. properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the - targets. type: string type: object type: object message: - description: The message content of the SNS notification. type: string phone_number: - description: |- - Phone number if message is delivered via SMS - Specify this, topic_arn or target_arn type: string send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean sigv4: - description: Configure the AWS Signature Verification - 4 signing process properties: access_key: - description: |- - The AWS API keys. Both access_key and secret_key must be supplied or both must be blank. - If blank the environment variables `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` are used. type: string access_key_selector: - description: secret key selector to get the keys from - a Kubernetes Secret properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic profile: - description: Named AWS profile used to authenticate type: string region: - description: AWS region, if blank the region from - the default credentials chain is used type: string role_arn: - description: AWS Role ARN, an alternative to using - AWS API keys type: string secret_key_selector: - description: secret key selector to get the keys from - a Kubernetes Secret properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key @@ -8404,81 +8125,45 @@ spec: x-kubernetes-map-type: atomic type: object subject: - description: The subject line if message is delivered - to an email endpoint. type: string target_arn: - description: |- - Mobile platform endpoint ARN if message is delivered via mobile notifications - Specify this, topic_arn or phone_number type: string topic_arn: - description: SNS topic ARN, either specify this, phone_number - or target_arn type: string type: object type: array telegram_configs: items: - description: |- - TelegramConfig configures notification via telegram - https://prometheus.io/docs/alerting/latest/configuration/#telegram_config properties: api_url: - description: APIUrl the Telegram API URL i.e. https://api.telegram.org. type: string bot_token: - description: |- - BotToken token for the bot - https://core.telegram.org/bots/api properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic chat_id: - description: ChatID is ID of the chat where to send the - messages. type: integer disable_notifications: - description: DisableNotifications type: boolean http_config: - description: HTTP client configuration. type: object x-kubernetes-preserve-unknown-fields: true message: - description: Message is templated message type: string message_thread_id: - description: MessageThreadID defines ID of the message - thread where to send the messages. type: integer parse_mode: - description: |- - ParseMode for telegram message, - supported values are MarkdownV2, Markdown, Markdown and empty string for plain text. type: string send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean required: - bot_token @@ -8486,149 +8171,76 @@ spec: type: object type: array victorops_configs: - description: VictorOpsConfigs defines victor ops notification - configurations. items: - description: |- - VictorOpsConfig configures notifications via VictorOps. - See https://prometheus.io/docs/alerting/latest/configuration/#victorops_config properties: api_key: - description: |- - The secret's key that contains the API key to use when talking to the VictorOps API. - It must be at them same namespace as CRD - fallback to global setting if empty properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic api_url: - description: The VictorOps API URL. type: string custom_fields: additionalProperties: type: string - description: |- - Adds optional custom fields - https://github.com/prometheus/alertmanager/blob/v0.24.0/config/notifiers.go#L537 type: object entity_display_name: - description: Contains summary of the alerted problem. type: string http_config: - description: The HTTP client's configuration. properties: authorization: - description: |- - Authorization header configuration for the client. - This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. properties: credentials: - description: Reference to the secret with value - for authorization properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to - bearer type: string type: object basic_auth: - description: BasicAuth for the client. properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key @@ -8636,88 +8248,45 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token_file: - description: BearerTokenFile defines filename for - bearer token, it must be mounted to pod. type: string bearer_token_secret: - description: |- - The secret's key that contains the bearer token - It must be at them same namespace as CRD properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic oauth2: - description: OAuth2 client credentials used to fetch - a token for the targets. properties: client_id: - description: The secret or configmap containing - the OAuth2 client id properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -8725,60 +8294,33 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 - client secret properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for - client secret file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token - URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token - request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: @@ -8786,60 +8328,32 @@ spec: - token_url type: object proxyURL: - description: Optional proxy URL. type: string tls_config: - description: TLS configuration for the client. properties: ca: - description: Struct containing the CA cert to - use for the targets. properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -8847,58 +8361,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container - to use for the targets. type: string cert: - description: Struct containing the client cert - file for the targets. properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -8906,65 +8392,37 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the - container for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the - container for the targets. type: string keySecret: - description: Secret containing the client key - file for the targets. properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the - targets. type: string type: object type: object message_type: - description: Describes the behavior of the alert (CRITICAL, - WARNING, INFO). type: string monitoring_tool: - description: The monitoring tool the state message is - from. type: string routing_key: - description: A key used to map the alert to a team. type: string send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean state_message: - description: Contains long explanation of the alerted - problem. type: string required: - routing_key @@ -8974,106 +8432,54 @@ spec: items: properties: api_url: - description: The Webex Teams API URL, i.e. https://webexapis.com/v1/messages type: string http_config: - description: HTTP client configuration. You must use this - configuration to supply the bot token as part of the - HTTP `Authorization` header. properties: authorization: - description: |- - Authorization header configuration for the client. - This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. properties: credentials: - description: Reference to the secret with value - for authorization properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to - bearer type: string type: object basic_auth: - description: BasicAuth for the client. properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key @@ -9081,88 +8487,45 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token_file: - description: BearerTokenFile defines filename for - bearer token, it must be mounted to pod. type: string bearer_token_secret: - description: |- - The secret's key that contains the bearer token - It must be at them same namespace as CRD properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic oauth2: - description: OAuth2 client credentials used to fetch - a token for the targets. properties: client_id: - description: The secret or configmap containing - the OAuth2 client id properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -9170,60 +8533,33 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 - client secret properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for - client secret file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token - URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token - request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: @@ -9231,60 +8567,32 @@ spec: - token_url type: object proxyURL: - description: Optional proxy URL. type: string tls_config: - description: TLS configuration for the client. properties: ca: - description: Struct containing the CA cert to - use for the targets. properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -9292,58 +8600,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container - to use for the targets. type: string cert: - description: Struct containing the client cert - file for the targets. properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -9351,110 +8631,63 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the - container for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the - container for the targets. type: string keySecret: - description: Secret containing the client key - file for the targets. properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the - targets. type: string type: object type: object message: - description: The message body template type: string room_id: - description: The ID of the Webex Teams room where to send - the messages type: string send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean required: - room_id type: object type: array webhook_configs: - description: WebhookConfigs defines webhook notification configurations. items: - description: |- - WebhookConfig configures notifications via a generic receiver supporting the webhook payload. - See https://prometheus.io/docs/alerting/latest/configuration/#webhook_config properties: http_config: - description: HTTP client configuration. type: object x-kubernetes-preserve-unknown-fields: true max_alerts: - description: Maximum number of alerts to be sent per webhook - message. When 0, all alerts are included. format: int32 minimum: 0 type: integer send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean + timeout: + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string url: - description: |- - URL to send requests to, - one of `urlSecret` and `url` must be defined. type: string url_secret: - description: |- - URLSecret defines secret name and key at the CRD namespace. - It must contain the webhook URL. - one of `urlSecret` and `url` must be defined. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -9463,147 +8696,74 @@ spec: type: object type: array wechat_configs: - description: WeChatConfigs defines wechat notification configurations. items: - description: |- - WeChatConfig configures notifications via WeChat. - See https://prometheus.io/docs/alerting/latest/configuration/#wechat_config properties: agent_id: type: string api_secret: - description: |- - The secret's key that contains the WeChat API key. - The secret needs to be in the same namespace as the AlertmanagerConfig - fallback to global alertmanager setting if empty properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic api_url: - description: |- - The WeChat API URL. - fallback to global alertmanager setting if empty type: string corp_id: - description: |- - The corp id for authentication. - fallback to global alertmanager setting if empty type: string http_config: - description: HTTP client configuration. properties: authorization: - description: |- - Authorization header configuration for the client. - This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. properties: credentials: - description: Reference to the secret with value - for authorization properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to - bearer type: string type: object basic_auth: - description: BasicAuth for the client. properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key @@ -9611,88 +8771,45 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token_file: - description: BearerTokenFile defines filename for - bearer token, it must be mounted to pod. type: string bearer_token_secret: - description: |- - The secret's key that contains the bearer token - It must be at them same namespace as CRD properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic oauth2: - description: OAuth2 client credentials used to fetch - a token for the targets. properties: client_id: - description: The secret or configmap containing - the OAuth2 client id properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -9700,60 +8817,33 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 - client secret properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for - client secret file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token - URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token - request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: @@ -9761,60 +8851,32 @@ spec: - token_url type: object proxyURL: - description: Optional proxy URL. type: string tls_config: - description: TLS configuration for the client. properties: ca: - description: Struct containing the CA cert to - use for the targets. properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -9822,58 +8884,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container - to use for the targets. type: string cert: - description: Struct containing the client cert - file for the targets. properties: configMap: - description: ConfigMap containing data to - use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap - or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use - for the targets. properties: key: - description: The key of the secret to - select from. Must be a valid secret - key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret - or its key must be defined type: boolean required: - key @@ -9881,56 +8915,33 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the - container for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the - container for the targets. type: string keySecret: - description: Secret containing the client key - file for the targets. properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the - targets. type: string type: object type: object message: - description: API request data as defined by the WeChat - API. type: string message_type: type: string send_resolved: - description: SendResolved controls notify about resolved - alerts. type: boolean to_party: type: string @@ -9945,59 +8956,37 @@ spec: type: object type: array route: - description: Route definition for alertmanager, may include nested - routes. properties: active_time_intervals: - description: |- - ActiveTimeIntervals Times when the route should be active - These must match the name at time_intervals items: type: string type: array continue: - description: |- - Continue indicating whether an alert should continue matching subsequent - sibling nodes. It will always be true for the first-level route if disableRouteContinueEnforce for vmalertmanager not set. type: boolean group_by: - description: List of labels to group by. items: type: string type: array group_interval: - description: How long to wait before sending an updated notification. pattern: '[0-9]+(ms|s|m|h)' type: string group_wait: - description: How long to wait before sending the initial notification. pattern: '[0-9]+(ms|s|m|h)' type: string matchers: - description: |- - List of matchers that the alert’s labels should match. For the first - level route, the operator adds a namespace: "CRD_NS" matcher. - https://prometheus.io/docs/alerting/latest/configuration/#matcher items: type: string type: array mute_time_intervals: - description: MuteTimeIntervals is a list of interval names that - will mute matched alert items: type: string type: array receiver: - description: Name of the receiver for this route. type: string repeat_interval: - description: How long to wait before repeating the last notification. pattern: '[0-9]+(ms|s|m|h)' type: string routes: - description: |- - Child routes. - https://prometheus.io/docs/alerting/latest/configuration/#route items: x-kubernetes-preserve-unknown-fields: true type: array @@ -10005,49 +8994,29 @@ spec: - receiver type: object time_intervals: - description: |- - TimeIntervals defines named interval for active/mute notifications interval - See https://prometheus.io/docs/alerting/latest/configuration/#time_interval items: - description: TimeIntervals for alerts properties: name: - description: Name of interval type: string time_intervals: - description: TimeIntervals interval configuration items: - description: TimeInterval defines intervals of time properties: days_of_month: - description: |- - DayOfMonth defines list of numerical days in the month. Days begin at 1. Negative values are also accepted. - for example, ['1:5', '-3:-1'] items: type: string type: array location: - description: Location in golang time location form, e.g. - UTC type: string months: - description: |- - Months defines list of calendar months identified by a case-insensitive name (e.g. ‘January’) or numeric 1. - For example, ['1:3', 'may:august', 'december'] items: type: string type: array times: - description: Times defines time range for mute items: - description: TimeRange ranges inclusive of the starting - time and exclusive of the end time properties: end_time: - description: EndTime for example HH:MM type: string start_time: - description: StartTime for example HH:MM type: string required: - end_time @@ -10055,15 +9024,10 @@ spec: type: object type: array weekdays: - description: Weekdays defines list of days of the week, - where the week begins on Sunday and ends on Saturday. items: type: string type: array years: - description: |- - Years defines numerical list of years, ranges are accepted. - For example, ['2020:2022', '2030'] items: type: string type: array @@ -10074,64 +9038,36 @@ spec: - time_intervals type: object type: array - required: - - receivers - - route type: object status: - description: VMAlertmanagerConfigStatus defines the observed state of - VMAlertmanagerConfig properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -10148,16 +9084,11 @@ spec: lastErrorParentAlertmanagerName: type: string observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -10170,7 +9101,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmalertmanagers.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -10198,103 +9129,46 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMAlertmanager represents Victoria-Metrics deployment for Alertmanager. 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: |- - Specification of the desired behavior of the VMAlertmanager cluster. More info: - https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status properties: additionalPeers: - description: AdditionalPeers allows injecting a set of additional - Alertmanagers to peer with to form a highly available cluster. items: type: string type: array affinity: - description: Affinity If specified, the pod's scheduling constraints. type: object x-kubernetes-preserve-unknown-fields: true claimTemplates: - description: ClaimTemplates allows adding additional VolumeClaimTemplates - for StatefulSet items: - description: PersistentVolumeClaim is a user's request for and claim - to a persistent volume 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: - description: |- - Standard object's metadata. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata type: object x-kubernetes-preserve-unknown-fields: true spec: - description: |- - spec defines the desired characteristics of a volume requested by a pod author. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims properties: accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string type: array x-kubernetes-list-type: atomic dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. properties: apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. type: string kind: - description: Kind is the type of resource being referenced type: string name: - description: Name is the name of resource being referenced type: string required: - kind @@ -10302,60 +9176,20 @@ spec: type: object x-kubernetes-map-type: atomic dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. properties: apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. type: string kind: - description: Kind is the type of resource being referenced type: string name: - description: Name is the name of resource being referenced type: string namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. type: string required: - kind - name type: object resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources properties: limits: additionalProperties: @@ -10364,9 +9198,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -10375,40 +9206,18 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object selector: - description: selector is a label query over volumes to consider - for binding. 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 @@ -10422,99 +9231,28 @@ spec: 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 storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 type: string volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. type: string volumeName: - description: volumeName is the binding reference to the - PersistentVolume backing this claim. type: string type: object status: - description: |- - status represents the current information/status of a persistent volume claim. - Read-only. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims properties: accessModes: - description: |- - accessModes contains the actual access modes the volume backing the PVC has. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string type: array x-kubernetes-list-type: atomic allocatedResourceStatuses: additionalProperties: - description: |- - When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource - that it does not recognizes, then it should ignore that update and let other controllers - handle it. type: string - description: "allocatedResourceStatuses stores status of - resource being resized for the given PVC.\nKey names follow - standard Kubernetes label syntax. Valid values are either:\n\t* - Un-prefixed keys:\n\t\t- storage - the capacity of the - volume.\n\t* Custom resources must use implementation-defined - prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not be used.\n\nClaimResourceStatus - can be in any of following states:\n\t- ControllerResizeInProgress:\n\t\tState - set when resize controller starts resizing the volume - in control-plane.\n\t- ControllerResizeFailed:\n\t\tState - set when resize has failed in resize controller with a - terminal error.\n\t- NodeResizePending:\n\t\tState set - when resize controller has finished resizing the volume - but further resizing of\n\t\tvolume is needed on the node.\n\t- - NodeResizeInProgress:\n\t\tState set when kubelet starts - resizing the volume.\n\t- NodeResizeFailed:\n\t\tState - set when resizing has failed in kubelet with a terminal - error. Transient errors don't set\n\t\tNodeResizeFailed.\nFor - example: if expanding a PVC for more capacity - this field - can be one of the following states:\n\t- pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeFailed\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizePending\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeFailed\"\nWhen this field is not set, it - means that no resize operation is in progress for the - given PVC.\n\nA controller that receives PVC update with - previously unknown resourceName or ClaimResourceStatus\nshould - ignore the update for the purpose it was designed. For - example - a controller that\nonly is responsible for resizing - capacity of the volume, should ignore PVC updates that - change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." type: object x-kubernetes-map-type: granular allocatedResources: @@ -10524,30 +9262,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: "allocatedResources tracks the resources allocated - to a PVC including its capacity.\nKey names follow standard - Kubernetes label syntax. Valid values are either:\n\t* - Un-prefixed keys:\n\t\t- storage - the capacity of the - volume.\n\t* Custom resources must use implementation-defined - prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not be used.\n\nCapacity - reported here may be larger than the actual capacity when - a volume expansion operation\nis requested.\nFor storage - quota, the larger value from allocatedResources and PVC.spec.resources - is used.\nIf allocatedResources is not set, PVC.spec.resources - alone is used for quota calculation.\nIf a volume expansion - capacity request is lowered, allocatedResources is only\nlowered - if there are no expansion operations in progress and if - the actual volume capacity\nis equal or lower than the - requested capacity.\n\nA controller that receives PVC - update with previously unknown resourceName\nshould ignore - the update for the purpose it was designed. For example - - a controller that\nonly is responsible for resizing - capacity of the volume, should ignore PVC updates that - change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." type: object capacity: additionalProperties: @@ -10556,47 +9270,23 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: capacity represents the actual resources of - the underlying volume. type: object conditions: - description: |- - conditions is the current Condition of persistent volume claim. If underlying persistent volume is being - resized then the Condition will be set to 'Resizing'. items: - description: PersistentVolumeClaimCondition contains details - about state of pvc properties: lastProbeTime: - description: lastProbeTime is the time we probed the - condition. format: date-time type: string lastTransitionTime: - description: lastTransitionTime is the time the condition - transitioned from one status to another. format: date-time type: string message: - description: message is the human-readable message - indicating details about last transition. type: string reason: - description: |- - reason is a unique, this should be a short, machine understandable string that gives the reason - for condition's last transition. If it reports "Resizing" that means the underlying - persistent volume is being resized. type: string status: - description: |- - Status is the status of the condition. - Can be True, False, Unknown. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=state%20of%20pvc-,conditions.status,-(string)%2C%20required type: string type: - description: |- - Type is the type of the condition. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=set%20to%20%27ResizeStarted%27.-,PersistentVolumeClaimCondition,-contains%20details%20about type: string required: - status @@ -10607,96 +9297,39 @@ spec: - type x-kubernetes-list-type: map currentVolumeAttributesClassName: - description: |- - currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. - When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). type: string modifyVolumeStatus: - description: |- - ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. - When this is unset, there is no ModifyVolume operation being attempted. - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). properties: status: - description: "status is the status of the ControllerModifyVolume - operation. It can be in any of following states:\n - - Pending\n Pending indicates that the PersistentVolumeClaim - cannot be modified due to unmet requirements, such - as\n the specified VolumeAttributesClass not existing.\n - - InProgress\n InProgress indicates that the volume - is being modified.\n - Infeasible\n Infeasible indicates - that the request has been rejected as invalid by the - CSI driver. To\n\t resolve the error, a valid VolumeAttributesClass - needs to be specified.\nNote: New statuses can be - added in the future. Consumers should check for unknown - statuses and fail appropriately." type: string targetVolumeAttributesClassName: - description: targetVolumeAttributesClassName is the - name of the VolumeAttributesClass the PVC currently - being reconciled type: string required: - status type: object phase: - description: phase represents the current phase of PersistentVolumeClaim. type: string type: object type: object type: array clusterAdvertiseAddress: - description: |- - ClusterAdvertiseAddress is the explicit address to advertise in cluster. - Needs to be provided for non RFC1918 [1] (public) addresses. - [1] RFC1918: https://tools.ietf.org/html/rfc1918 type: string clusterDomainName: - description: |- - ClusterDomainName defines domain name suffix for in-cluster dns addresses - aka .cluster.local - used to build pod peer addresses for in-cluster communication type: string configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder items: type: string type: array configNamespaceSelector: - description: |2- - ConfigNamespaceSelector defines namespace selector for VMAlertmanagerConfig. - Works in combination with Selector. - NamespaceSelector nil - only objects at VMAlertmanager namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault 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 @@ -10710,58 +9343,40 @@ spec: 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 configRawYaml: - description: |- - ConfigRawYaml - raw configuration for alertmanager, - it helps it to start without secret. - priority -> hardcoded ConfigRaw -> ConfigRaw, provided by user -> ConfigSecret. type: string + configReloadAuthKeySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic configReloaderExtraArgs: additionalProperties: type: string - description: |- - ConfigReloaderExtraArgs that will be passed to VMAuths config-reloader container - for example resyncInterval: "30s" type: object + configReloaderImage: + type: string configReloaderImageTag: - description: ConfigReloaderImageTag defines image:tag for config-reloader - container type: string configReloaderResources: - description: |- - ConfigReloaderResources config-reloader container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used properties: claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. type: string request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. type: string required: - name @@ -10777,9 +9392,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -10788,53 +9400,20 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object configSecret: - description: |- - ConfigSecret is the name of a Kubernetes Secret in the same namespace as the - VMAlertmanager object, which contains configuration for this VMAlertmanager, - configuration must be inside secret key: alertmanager.yaml. - It must be created by user. - instance. Defaults to 'vmalertmanager-' - The secret is mounted into /etc/alertmanager/config. type: string configSelector: - description: |- - ConfigSelector defines selector for VMAlertmanagerConfig, result config will be merged with with Raw or Secret config. - Works in combination with NamespaceSelector. - NamespaceSelector nil - only objects at VMAlertmanager namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault 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 @@ -10848,141 +9427,69 @@ spec: 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 containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. items: - description: A single application container that you want to run - within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. type: boolean disableNamespaceMatcher: - description: |- - DisableNamespaceMatcher disables top route namespace label matcher for VMAlertmanagerConfig - It may be useful if alert doesn't have namespace label for some reason type: boolean disableRouteContinueEnforce: - description: DisableRouteContinueEnforce cancel the behavior for VMAlertmanagerConfig - that always enforce first-level route continue to true type: boolean disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable type: boolean dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. items: x-kubernetes-preserve-unknown-fields: true properties: nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. items: type: string type: array x-kubernetes-list-type: atomic options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. properties: name: - description: |- - Name is this DNS resolver option's name. - Required. type: string value: - description: Value is this DNS resolver option's value. type: string type: object type: array x-kubernetes-list-type: atomic searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. items: type: string type: array x-kubernetes-list-type: atomic type: object dnsPolicy: - description: DNSPolicy sets DNS policy for the pod + type: string + enforcedNamespaceLabel: type: string enforcedTopRouteMatchers: - description: |- - EnforcedTopRouteMatchers defines label matchers to be added for the top route - of VMAlertmanagerConfig - It allows to make some set of labels required for alerts. - https://prometheus.io/docs/alerting/latest/configuration/#matcher items: type: string type: array externalURL: - description: |- - ExternalURL the VMAlertmanager instances will be available under. This is - necessary to generate correct URLs. This is necessary if VMAlertmanager is not - served from root of a DNS name. type: string extraArgs: additionalProperties: type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp type: object extraEnvs: - description: ExtraEnvs that will be passed to the application container items: - description: EnvVar represents an environment variable present in - a Container. properties: name: - description: Name of the environment variable. Must be a C_IDENTIFIER. type: string value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". type: string required: - name @@ -10990,286 +9497,145 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap items: - description: EnvFromSource represents the source of a set of ConfigMaps properties: configMapRef: - description: The ConfigMap to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap must be defined type: boolean 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. type: string secretRef: - description: The Secret to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret must be defined type: boolean type: object x-kubernetes-map-type: atomic type: object type: array gossipConfig: - description: GossipConfig defines gossip TLS configuration for Alertmanager - cluster properties: tls_client_config: - description: TLSClientConfig defines client TLS configuration - for alertmanager properties: ca_file: - description: |- - CAFile defines path to the pre-mounted file with CA - mutually exclusive with CASecretRef type: string ca_secret_ref: - description: |- - CA defines reference for secret with CA content under given key - mutually exclusive with CAFile properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic cert_file: - description: |- - CertFile defines path to the pre-mounted file with certificate - mutually exclusive with CertSecretRef type: string cert_secret_ref: - description: |- - CertSecretRef defines reference for secret with certificate content under given key - mutually exclusive with CertFile properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic insecure_skip_verify: - description: |- - Cert defines reference for secret with CA content under given key - mutually exclusive with CertFile type: boolean key_file: - description: |- - KeyFile defines path to the pre-mounted file with certificate key - mutually exclusive with KeySecretRef type: string key_secret_ref: - description: |- - Key defines reference for secret with certificate key content under given key - mutually exclusive with KeyFile properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic server_name: - description: ServerName indicates a name of a server type: string type: object tls_server_config: - description: TLSServerConfig defines server TLS configuration - for alertmanager properties: cert_file: - description: |- - CertFile defines path to the pre-mounted file with certificate - mutually exclusive with CertSecretRef type: string cert_secret_ref: - description: |- - CertSecretRef defines reference for secret with certificate content under given key - mutually exclusive with CertFile properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic cipher_suites: - description: |- - CipherSuites defines list of supported cipher suites for TLS versions up to TLS 1.2 - https://golang.org/pkg/crypto/tls/#pkg-constants items: type: string type: array client_auth_type: - description: |- - Cert defines reference for secret with CA content under given key - mutually exclusive with CertFile - ClientAuthType defines server policy for client authentication - If you want to enable client authentication (aka mTLS), you need to use RequireAndVerifyClientCert - Note, mTLS is supported only at enterprise version of VictoriaMetrics components enum: - NoClientCert - RequireAndVerifyClientCert type: string client_ca_file: - description: |- - ClientCAFile defines path to the pre-mounted file with CA - mutually exclusive with ClientCASecretRef type: string client_ca_secret_ref: - description: |- - ClientCASecretRef defines reference for secret with CA content under given key - mutually exclusive with ClientCAFile properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic curve_preferences: - description: |- - CurvePreferences defines elliptic curves that will be used in an ECDHE handshake, in preference order. - https://golang.org/pkg/crypto/tls/#CurveID items: type: string type: array key_file: - description: |- - KeyFile defines path to the pre-mounted file with certificate key - mutually exclusive with KeySecretRef type: string key_secret_ref: - description: |- - Key defines reference for secret with certificate key content under given key - mutually exclusive with KeyFile properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic max_version: - description: MaxVersion maximum TLS version that is acceptable. enum: - TLS10 - TLS11 @@ -11277,7 +9643,6 @@ spec: - TLS13 type: string min_version: - description: MinVersion minimum TLS version that is acceptable. enum: - TLS10 - TLS11 @@ -11285,132 +9650,75 @@ spec: - TLS13 type: string prefer_server_cipher_suites: - description: |- - PreferServerCipherSuites controls whether the server selects the - client's most preferred ciphersuite type: boolean type: object type: object host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostNetwork: - description: HostNetwork controls whether the pod may use the node - network namespace type: boolean image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config properties: pullPolicy: - description: PullPolicy describes how to pull docker image type: string repository: - description: Repository contains name of docker image + it's repository - if needed type: string tag: - description: Tag contains desired docker image version type: string type: object imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string type: object x-kubernetes-map-type: atomic type: array initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ items: - description: A single application container that you want to run - within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array listenLocal: - description: |- - ListenLocal makes the VMAlertmanager server listen on loopback, so that it - does not bind against the Pod IP. Note this is only for the VMAlertmanager - UI, not the gossip communication. type: boolean livenessProbe: - description: LivenessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true logFormat: - description: LogFormat for VMAlertmanager to be configured with. enum: - logfmt - json type: string logLevel: - description: Log level for VMAlertmanager to be configured with. enum: - debug - info @@ -11422,169 +9730,96 @@ spec: - ERROR type: string managedMetadata: - description: |- - ManagedMetadata defines metadata that will be added to the all objects - created by operator for the given CustomResource properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object type: object minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle format: int32 type: integer nodeSelector: additionalProperties: type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. type: object paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. type: boolean + persistentVolumeClaimRetentionPolicy: + properties: + whenDeleted: + type: string + whenScaled: + type: string + type: object podDisruptionBudget: - description: PodDisruptionBudget created by operator properties: maxUnavailable: anyOf: - type: integer - type: string - description: |- - An eviction is allowed if at most "maxUnavailable" pods selected by - "selector" are unavailable after the eviction, i.e. even in absence of - the evicted pod. For example, one can prevent all voluntary evictions - by specifying 0. This is a mutually exclusive setting with "minAvailable". x-kubernetes-int-or-string: true minAvailable: anyOf: - type: integer - type: string - description: |- - An eviction is allowed if at least "minAvailable" pods selected by - "selector" will still be available after the eviction, i.e. even in the - absence of the evicted pod. So for example you can prevent all voluntary - evictions by specifying "100%". x-kubernetes-int-or-string: true selectorLabels: additionalProperties: type: string - description: |- - replaces default labels selector generated by operator - it's useful when you need to create custom budget type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string type: object podMetadata: - description: PodMetadata configures Labels and Annotations which are - propagated to the alertmanager pods. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object port: - description: Port listen address type: string portName: - description: |- - PortName used for the pods and governing service. - This defaults to web type: string priorityClassName: - description: PriorityClassName class assigned to the Pods type: string readinessGates: - description: ReadinessGates defines pod readiness gates items: - description: PodReadinessGate contains the reference to a pod condition properties: conditionType: - description: ConditionType refers to a condition in the pod's - condition list with matching type. type: string required: - conditionType type: object type: array readinessProbe: - description: ReadinessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true replicaCount: - description: ReplicaCount is the expected size of the Application. format: int32 type: integer resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used properties: claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. type: string request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. type: string required: - name @@ -11600,9 +9835,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -11611,255 +9843,110 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object retention: - description: |- - Retention Time duration VMAlertmanager shall retain data for. Default is '120h', - and must match the regular expression `[0-9]+(ms|s|m|h)` (milliseconds seconds minutes hours). pattern: '[0-9]+(ms|s|m|h)' type: string revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. format: int32 type: integer rollingUpdateStrategy: - description: |- - RollingUpdateStrategy defines strategy for application updates - Default is OnDelete, in this case operator handles update process - Can be changed for RollingUpdate type: string routePrefix: - description: |- - RoutePrefix VMAlertmanager registers HTTP handlers for. This is useful, - if using ExternalURL and a proxy is rewriting HTTP routes of a request, - and the actual ExternalURL is still true, but the server serves requests - under a different route prefix. For example for use with `kubectl proxy`. type: string runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ type: string schedulerName: - description: SchedulerName - defines kubernetes scheduler name type: string secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder items: type: string type: array securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. type: object x-kubernetes-preserve-unknown-fields: true selectAllByDefault: - description: |- - SelectAllByDefault changes default behavior for empty CRD selectors, such ConfigSelector. - with selectAllByDefault: true and undefined ConfigSelector and ConfigNamespaceSelector - Operator selects all exist alertManagerConfigs - with selectAllByDefault: false - selects nothing type: boolean serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to use to run the pods type: string serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vmalertmanager - VMServiceScrape spec required: - endpoints type: object x-kubernetes-preserve-unknown-fields: true serviceSpec: - description: ServiceSpec that will be added to vmalertmanager service - spec properties: metadata: - description: EmbeddedObjectMetadata defines objectMeta for additional - service. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ type: object x-kubernetes-preserve-unknown-fields: true useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication type: boolean required: - spec type: object startupProbe: - description: StartupProbe that will be added to CRD pod type: object x-kubernetes-preserve-unknown-fields: true storage: - description: |- - Storage is the definition of how storage will be used by the VMAlertmanager - instances. properties: - disableMountSubPath: - description: |- - Deprecated: subPath usage will be disabled by default in a future release, this option will become unnecessary. - DisableMountSubPath allows to remove any subPath usage in volume mounts. - type: boolean emptyDir: - description: |- - EmptyDirVolumeSource to be used by the Prometheus StatefulSets. If specified, used in place of any volumeClaimTemplate. More - info: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir properties: medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir type: string sizeLimit: anyOf: - type: integer - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true type: object volumeClaimTemplate: - description: A PVC spec to be used by the VMAlertManager StatefulSets. 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: - description: EmbeddedMetadata contains metadata relevant to - an EmbeddedResource. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object spec: - description: |- - Spec defines the desired characteristics of a volume requested by a pod author. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims properties: accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string type: array x-kubernetes-list-type: atomic dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. properties: apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. type: string kind: - description: Kind is the type of resource being referenced type: string name: - description: Name is the name of resource being referenced type: string required: - kind @@ -11867,60 +9954,20 @@ spec: type: object x-kubernetes-map-type: atomic dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. properties: apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. type: string kind: - description: Kind is the type of resource being referenced type: string name: - description: Name is the name of resource being referenced type: string namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. type: string required: - kind - name type: object resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources properties: limits: additionalProperties: @@ -11929,9 +9976,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -11940,40 +9984,18 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object selector: - description: selector is a label query over volumes to - consider for binding. 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 @@ -11987,100 +10009,28 @@ spec: 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 storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 type: string volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. type: string volumeName: - description: volumeName is the binding reference to the - PersistentVolume backing this claim. type: string type: object status: - description: |- - Status represents the current information/status of a persistent volume claim. - Read-only. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims properties: accessModes: - description: |- - accessModes contains the actual access modes the volume backing the PVC has. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string type: array x-kubernetes-list-type: atomic allocatedResourceStatuses: additionalProperties: - description: |- - When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource - that it does not recognizes, then it should ignore that update and let other controllers - handle it. type: string - description: "allocatedResourceStatuses stores status - of resource being resized for the given PVC.\nKey names - follow standard Kubernetes label syntax. Valid values - are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources must - use implementation-defined prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have - kubernetes.io prefix are considered\nreserved and hence - may not be used.\n\nClaimResourceStatus can be in any - of following states:\n\t- ControllerResizeInProgress:\n\t\tState - set when resize controller starts resizing the volume - in control-plane.\n\t- ControllerResizeFailed:\n\t\tState - set when resize has failed in resize controller with - a terminal error.\n\t- NodeResizePending:\n\t\tState - set when resize controller has finished resizing the - volume but further resizing of\n\t\tvolume is needed - on the node.\n\t- NodeResizeInProgress:\n\t\tState set - when kubelet starts resizing the volume.\n\t- NodeResizeFailed:\n\t\tState - set when resizing has failed in kubelet with a terminal - error. Transient errors don't set\n\t\tNodeResizeFailed.\nFor - example: if expanding a PVC for more capacity - this - field can be one of the following states:\n\t- pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeFailed\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizePending\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeFailed\"\nWhen this field is not set, - it means that no resize operation is in progress for - the given PVC.\n\nA controller that receives PVC update - with previously unknown resourceName or ClaimResourceStatus\nshould - ignore the update for the purpose it was designed. For - example - a controller that\nonly is responsible for - resizing capacity of the volume, should ignore PVC updates - that change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." type: object x-kubernetes-map-type: granular allocatedResources: @@ -12090,31 +10040,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: "allocatedResources tracks the resources - allocated to a PVC including its capacity.\nKey names - follow standard Kubernetes label syntax. Valid values - are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources must - use implementation-defined prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have - kubernetes.io prefix are considered\nreserved and hence - may not be used.\n\nCapacity reported here may be larger - than the actual capacity when a volume expansion operation\nis - requested.\nFor storage quota, the larger value from - allocatedResources and PVC.spec.resources is used.\nIf - allocatedResources is not set, PVC.spec.resources alone - is used for quota calculation.\nIf a volume expansion - capacity request is lowered, allocatedResources is only\nlowered - if there are no expansion operations in progress and - if the actual volume capacity\nis equal or lower than - the requested capacity.\n\nA controller that receives - PVC update with previously unknown resourceName\nshould - ignore the update for the purpose it was designed. For - example - a controller that\nonly is responsible for - resizing capacity of the volume, should ignore PVC updates - that change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." type: object capacity: additionalProperties: @@ -12123,47 +10048,23 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: capacity represents the actual resources - of the underlying volume. type: object conditions: - description: |- - conditions is the current Condition of persistent volume claim. If underlying persistent volume is being - resized then the Condition will be set to 'Resizing'. items: - description: PersistentVolumeClaimCondition contains - details about state of pvc properties: lastProbeTime: - description: lastProbeTime is the time we probed - the condition. format: date-time type: string lastTransitionTime: - description: lastTransitionTime is the time the - condition transitioned from one status to another. format: date-time type: string message: - description: message is the human-readable message - indicating details about last transition. type: string reason: - description: |- - reason is a unique, this should be a short, machine understandable string that gives the reason - for condition's last transition. If it reports "Resizing" that means the underlying - persistent volume is being resized. type: string status: - description: |- - Status is the status of the condition. - Can be True, False, Unknown. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=state%20of%20pvc-,conditions.status,-(string)%2C%20required type: string type: - description: |- - Type is the type of the condition. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=set%20to%20%27ResizeStarted%27.-,PersistentVolumeClaimCondition,-contains%20details%20about type: string required: - status @@ -12174,64 +10075,28 @@ spec: - type x-kubernetes-list-type: map currentVolumeAttributesClassName: - description: |- - currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. - When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). type: string modifyVolumeStatus: - description: |- - ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. - When this is unset, there is no ModifyVolume operation being attempted. - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). properties: status: - description: "status is the status of the ControllerModifyVolume - operation. It can be in any of following states:\n - - Pending\n Pending indicates that the PersistentVolumeClaim - cannot be modified due to unmet requirements, such - as\n the specified VolumeAttributesClass not existing.\n - - InProgress\n InProgress indicates that the volume - is being modified.\n - Infeasible\n Infeasible - indicates that the request has been rejected as - invalid by the CSI driver. To\n\t resolve the error, - a valid VolumeAttributesClass needs to be specified.\nNote: - New statuses can be added in the future. Consumers - should check for unknown statuses and fail appropriately." type: string targetVolumeAttributesClassName: - description: targetVolumeAttributesClassName is the - name of the VolumeAttributesClass the PVC currently - being reconciled type: string required: - status type: object phase: - description: phase represents the current phase of PersistentVolumeClaim. type: string type: object type: object type: object templates: - description: |- - Templates is a list of ConfigMap key references for ConfigMaps in the same namespace as the VMAlertmanager - object, which shall be mounted into the VMAlertmanager Pods. - The Templates are mounted into /etc/vm/templates//. items: - description: ConfigMapKeyReference refers to a key in a ConfigMap. properties: key: - description: The ConfigMap key to refer to. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string required: - key @@ -12239,58 +10104,26 @@ spec: x-kubernetes-map-type: atomic type: array terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container graceful - termination format: int64 type: integer tolerations: - description: Tolerations If specified, the pod's tolerations. items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. type: string type: object type: array topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ items: - description: TopologySpreadConstraint specifies how to spread matching - pods among the given topology. required: - maxSkew - topologyKey @@ -12298,84 +10131,104 @@ spec: type: object x-kubernetes-preserve-unknown-fields: true type: array + tracingConfig: + properties: + client_type: + enum: + - http + - grpc + type: string + compression: + type: string + endpoint: + type: string + http_headers: + additionalProperties: + type: string + type: object + insecure: + type: boolean + sampling_fraction: + type: string + timeout: + type: string + tls_config: + properties: + ca_file: + type: string + ca_secret_ref: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + cert_file: + type: string + cert_secret_ref: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + insecure_skip_verify: + type: boolean + key_file: + type: string + key_secret_ref: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + server_name: + type: string + type: object + required: + - endpoint + type: object useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements type: boolean useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions type: boolean useVMConfigReloader: - description: |- - UseVMConfigReloader replaces prometheus-like config-reloader - with vm one. It uses secrets watch instead of file watch - which greatly increases speed of config updates type: boolean volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container items: - description: VolumeMount describes a mounting of a Volume within - a container. properties: mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. type: string mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). type: string name: - description: This must match the Name of a Volume. type: string readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. type: boolean recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). type: string subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. type: string required: - mountPath @@ -12383,170 +10236,88 @@ spec: type: object type: array volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional items: - description: Volume represents a named volume in a pod that may - be accessed by any container in the pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array webConfig: - description: |- - WebConfig defines configuration for webserver - https://github.com/prometheus/alertmanager/blob/main/docs/https.md properties: basic_auth_users: additionalProperties: type: string - description: |- - BasicAuthUsers Usernames and hashed passwords that have full access to the web server - Passwords must be hashed with bcrypt type: object http_server_config: - description: HTTPServerConfig defines http server configuration - for alertmanager web server properties: headers: additionalProperties: type: string - description: Headers defines list of headers that can be added - to HTTP responses. type: object http2: - description: |- - HTTP2 enables HTTP/2 support. Note that HTTP/2 is only supported with TLS. - This can not be changed on the fly. type: boolean type: object tls_server_config: - description: TLSServerConfig defines server TLS configuration - for alertmanager properties: cert_file: - description: |- - CertFile defines path to the pre-mounted file with certificate - mutually exclusive with CertSecretRef type: string cert_secret_ref: - description: |- - CertSecretRef defines reference for secret with certificate content under given key - mutually exclusive with CertFile properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic cipher_suites: - description: |- - CipherSuites defines list of supported cipher suites for TLS versions up to TLS 1.2 - https://golang.org/pkg/crypto/tls/#pkg-constants items: type: string type: array client_auth_type: - description: |- - Cert defines reference for secret with CA content under given key - mutually exclusive with CertFile - ClientAuthType defines server policy for client authentication - If you want to enable client authentication (aka mTLS), you need to use RequireAndVerifyClientCert - Note, mTLS is supported only at enterprise version of VictoriaMetrics components enum: - NoClientCert - RequireAndVerifyClientCert type: string client_ca_file: - description: |- - ClientCAFile defines path to the pre-mounted file with CA - mutually exclusive with ClientCASecretRef type: string client_ca_secret_ref: - description: |- - ClientCASecretRef defines reference for secret with CA content under given key - mutually exclusive with ClientCAFile properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic curve_preferences: - description: |- - CurvePreferences defines elliptic curves that will be used in an ECDHE handshake, in preference order. - https://golang.org/pkg/crypto/tls/#CurveID items: type: string type: array key_file: - description: |- - KeyFile defines path to the pre-mounted file with certificate key - mutually exclusive with KeySecretRef type: string key_secret_ref: - description: |- - Key defines reference for secret with certificate key content under given key - mutually exclusive with KeyFile properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic max_version: - description: MaxVersion maximum TLS version that is acceptable. enum: - TLS10 - TLS11 @@ -12554,7 +10325,6 @@ spec: - TLS13 type: string min_version: - description: MinVersion minimum TLS version that is acceptable. enum: - TLS10 - TLS11 @@ -12562,69 +10332,39 @@ spec: - TLS13 type: string prefer_server_cipher_suites: - description: |- - PreferServerCipherSuites controls whether the server selects the - client's most preferred ciphersuite type: boolean type: object type: object type: object status: - description: |- - Most recent observed status of the VMAlertmanager cluster. - Operator API itself. More info: - https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -12639,16 +10379,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object required: @@ -12663,7 +10398,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmalerts.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -12679,7 +10414,7 @@ spec: jsonPath: .status.updateStatus name: Status type: string - - description: The desired replicas number of Alertmanagers + - description: The desired replicas number of VMAlerts jsonPath: .spec.replicaCount name: ReplicaCount type: integer @@ -12689,80 +10424,51 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMAlert executes a list of given alerting or recording rules - against configured address. 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: VMAlertSpec defines the desired state of VMAlert properties: affinity: - description: Affinity If specified, the pod's scheduling constraints. type: object x-kubernetes-preserve-unknown-fields: true configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder items: type: string type: array + configReloadAuthKeySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic configReloaderExtraArgs: additionalProperties: type: string - description: |- - ConfigReloaderExtraArgs that will be passed to VMAuths config-reloader container - for example resyncInterval: "30s" type: object + configReloaderImage: + type: string configReloaderImageTag: - description: ConfigReloaderImageTag defines image:tag for config-reloader - container type: string configReloaderResources: - description: |- - ConfigReloaderResources config-reloader container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used properties: claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. type: string request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. type: string required: - name @@ -12778,9 +10484,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -12789,85 +10492,42 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. items: - description: A single application container that you want to run - within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array datasource: - description: Datasource Victoria Metrics or VMSelect url. Required - parameter. e.g. http://127.0.0.1:8428 properties: basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -12875,169 +10535,88 @@ spec: x-kubernetes-map-type: atomic type: object bearerTokenFile: - description: Path to bearer token file type: string bearerTokenSecret: - description: Optional bearer auth token to use for -remoteWrite.url properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic headers: - description: |- - Headers allow configuring custom http headers - Must be in form of semicolon separated header with value - e.g. - headerName:headerValue - vmalert supports it since 1.79.0 version items: type: string type: array oauth2: - description: OAuth2 defines OAuth2 configuration required: - client_id - token_url type: object x-kubernetes-preserve-unknown-fields: true tlsConfig: - description: TLSConfig specifies TLSConfig configuration parameters. type: object x-kubernetes-preserve-unknown-fields: true url: - description: Victoria Metrics or VMSelect url. Required parameter. - E.g. http://127.0.0.1:8428 type: string required: - url type: object disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. type: boolean disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable type: boolean dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. items: x-kubernetes-preserve-unknown-fields: true properties: nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. items: type: string type: array x-kubernetes-list-type: atomic options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. properties: name: - description: |- - Name is this DNS resolver option's name. - Required. type: string value: - description: Value is this DNS resolver option's value. type: string type: object type: array x-kubernetes-list-type: atomic searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. items: type: string type: array x-kubernetes-list-type: atomic type: object dnsPolicy: - description: DNSPolicy sets DNS policy for the pod type: string enforcedNamespaceLabel: - description: |- - EnforcedNamespaceLabel enforces adding a namespace label of origin for each alert - and metric that is user created. The label value will always be the namespace of the object that is - being created. type: string evaluationInterval: - description: EvaluationInterval defines how often to evaluate rules - by default pattern: '[0-9]+(ms|s|m|h)' type: string externalLabels: additionalProperties: type: string - description: 'ExternalLabels in the form ''name: value'' to add to - all generated recording rules and alerts.' type: object extraArgs: additionalProperties: type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp type: object extraEnvs: - description: ExtraEnvs that will be passed to the application container items: - description: EnvVar represents an environment variable present in - a Container. properties: name: - description: Name of the environment variable. Must be a C_IDENTIFIER. type: string value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". type: string required: - name @@ -13045,212 +10624,116 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap items: - description: EnvFromSource represents the source of a set of ConfigMaps properties: configMapRef: - description: The ConfigMap to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap must be defined type: boolean 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. type: string secretRef: - description: The Secret to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret must be defined type: boolean type: object x-kubernetes-map-type: atomic type: object type: array host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostNetwork: - description: HostNetwork controls whether the pod may use the node - network namespace type: boolean image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config properties: pullPolicy: - description: PullPolicy describes how to pull docker image type: string repository: - description: Repository contains name of docker image + it's repository - if needed type: string tag: - description: Tag contains desired docker image version type: string type: object imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string type: object x-kubernetes-map-type: atomic type: array initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ items: - description: A single application container that you want to run - within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array license: - description: |- - License allows to configure license key to be used for enterprise features. - Using license key is supported starting from VictoriaMetrics v1.94.0. - See [here](https://docs.victoriametrics.com/enterprise) properties: forceOffline: - description: Enforce offline verification of the license key. type: boolean key: - description: |- - Enterprise license key. This flag is available only in [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise). - To request a trial license, [go to](https://victoriametrics.com/products/enterprise/trial) type: string keyRef: - description: KeyRef is reference to secret with license key for - enterprise features. properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic reloadInterval: - description: Interval to be used for checking for license key - changes. Note that this is only applicable when using KeyRef. type: string type: object livenessProbe: - description: LivenessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true logFormat: - description: |- - LogFormat for VMAlert to be configured with. - default or json enum: - default - json type: string logLevel: - description: LogLevel for VMAlert to be configured with. enum: - INFO - WARN @@ -13259,103 +10742,50 @@ spec: - PANIC type: string managedMetadata: - description: |- - ManagedMetadata defines metadata that will be added to the all objects - created by operator for the given CustomResource properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object type: object minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle format: int32 type: integer nodeSelector: additionalProperties: type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. type: object notifier: - description: |- - Notifier prometheus alertmanager endpoint spec. Required at least one of notifier or notifiers when there are alerting rules. e.g. http://127.0.0.1:9093 - If specified both notifier and notifiers, notifier will be added as last element to notifiers. - only one of notifier options could be chosen: notifierConfigRef or notifiers + notifier properties: basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -13363,84 +10793,42 @@ spec: x-kubernetes-map-type: atomic type: object bearerTokenFile: - description: Path to bearer token file type: string bearerTokenSecret: - description: Optional bearer auth token to use for -remoteWrite.url properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic headers: - description: |- - Headers allow configuring custom http headers - Must be in form of semicolon separated header with value - e.g. - headerName:headerValue - vmalert supports it since 1.79.0 version items: type: string type: array oauth2: - description: OAuth2 defines OAuth2 configuration required: - client_id - token_url type: object x-kubernetes-preserve-unknown-fields: true selector: - description: |- - Selector allows service discovery for alertmanager - in this case all matched vmalertmanager replicas will be added into vmalert notifier.url - as statefulset pod.fqdn properties: labelSelector: - description: |- - A label selector is a label query over a set of resources. The result of matchLabels and - matchExpressions are ANDed. An empty label selector matches all objects. A null - label selector matches no objects. 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 @@ -13454,128 +10842,66 @@ spec: 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 namespaceSelector: - description: |- - NamespaceSelector is a selector for selecting either all namespaces or a - list of namespaces. properties: any: - description: |- - Boolean describing whether all namespaces are selected in contrast to a - list restricting them. type: boolean matchNames: - description: List of namespace names. items: type: string type: array type: object type: object tlsConfig: - description: TLSConfig specifies TLSConfig configuration parameters. type: object x-kubernetes-preserve-unknown-fields: true url: - description: AlertManager url. E.g. http://127.0.0.1:9093 type: string type: object notifierConfigRef: - description: |- - NotifierConfigRef reference for secret with notifier configuration for vmalert - only one of notifier options could be chosen: notifierConfigRef or notifiers + notifier properties: key: - description: The key of the secret to select from. Must be a - valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic notifiers: - description: |- - Notifiers prometheus alertmanager endpoints. Required at least one of notifier or notifiers when there are alerting rules. e.g. http://127.0.0.1:9093 - If specified both notifier and notifiers, notifier will be added as last element to notifiers. - only one of notifier options could be chosen: notifierConfigRef or notifiers + notifier items: - description: VMAlertNotifierSpec defines the notifier url for sending - information about alerts properties: basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -13583,84 +10909,42 @@ spec: x-kubernetes-map-type: atomic type: object bearerTokenFile: - description: Path to bearer token file type: string bearerTokenSecret: - description: Optional bearer auth token to use for -remoteWrite.url properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic headers: - description: |- - Headers allow configuring custom http headers - Must be in form of semicolon separated header with value - e.g. - headerName:headerValue - vmalert supports it since 1.79.0 version items: type: string type: array oauth2: - description: OAuth2 defines OAuth2 configuration required: - client_id - token_url type: object x-kubernetes-preserve-unknown-fields: true selector: - description: |- - Selector allows service discovery for alertmanager - in this case all matched vmalertmanager replicas will be added into vmalert notifier.url - as statefulset pod.fqdn properties: labelSelector: - description: |- - A label selector is a label query over a set of resources. The result of matchLabels and - matchExpressions are ANDed. An empty label selector matches all objects. A null - label selector matches no objects. 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 @@ -13674,194 +10958,106 @@ spec: 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 namespaceSelector: - description: |- - NamespaceSelector is a selector for selecting either all namespaces or a - list of namespaces. properties: any: - description: |- - Boolean describing whether all namespaces are selected in contrast to a - list restricting them. type: boolean matchNames: - description: List of namespace names. items: type: string type: array type: object type: object tlsConfig: - description: TLSConfig specifies TLSConfig configuration parameters. type: object x-kubernetes-preserve-unknown-fields: true url: - description: AlertManager url. E.g. http://127.0.0.1:9093 type: string type: object type: array paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. type: boolean podDisruptionBudget: - description: PodDisruptionBudget created by operator properties: maxUnavailable: anyOf: - type: integer - type: string - description: |- - An eviction is allowed if at most "maxUnavailable" pods selected by - "selector" are unavailable after the eviction, i.e. even in absence of - the evicted pod. For example, one can prevent all voluntary evictions - by specifying 0. This is a mutually exclusive setting with "minAvailable". x-kubernetes-int-or-string: true minAvailable: anyOf: - type: integer - type: string - description: |- - An eviction is allowed if at least "minAvailable" pods selected by - "selector" will still be available after the eviction, i.e. even in the - absence of the evicted pod. So for example you can prevent all voluntary - evictions by specifying "100%". x-kubernetes-int-or-string: true selectorLabels: additionalProperties: type: string - description: |- - replaces default labels selector generated by operator - it's useful when you need to create custom budget type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string type: object podMetadata: - description: PodMetadata configures Labels and Annotations which are - propagated to the VMAlert pods. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object port: - description: Port listen address type: string priorityClassName: - description: PriorityClassName class assigned to the Pods type: string readinessGates: - description: ReadinessGates defines pod readiness gates items: - description: PodReadinessGate contains the reference to a pod condition properties: conditionType: - description: ConditionType refers to a condition in the pod's - condition list with matching type. type: string required: - conditionType type: object type: array readinessProbe: - description: ReadinessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true remoteRead: - description: |- - RemoteRead Optional URL to read vmalert state (persisted via RemoteWrite) - This configuration only makes sense if alerts state has been successfully - persisted (via RemoteWrite) before. - see -remoteRead.url docs in vmalerts for details. - E.g. http://127.0.0.1:8428 properties: basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -13869,129 +11065,67 @@ spec: x-kubernetes-map-type: atomic type: object bearerTokenFile: - description: Path to bearer token file type: string bearerTokenSecret: - description: Optional bearer auth token to use for -remoteWrite.url properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic headers: - description: |- - Headers allow configuring custom http headers - Must be in form of semicolon separated header with value - e.g. - headerName:headerValue - vmalert supports it since 1.79.0 version items: type: string type: array lookback: - description: |- - Lookback defines how far to look into past for alerts timeseries. For example, if lookback=1h then range from now() to now()-1h will be scanned. (default 1h0m0s) - Applied only to RemoteReadSpec type: string oauth2: - description: OAuth2 defines OAuth2 configuration required: - client_id - token_url type: object x-kubernetes-preserve-unknown-fields: true tlsConfig: - description: TLSConfig specifies TLSConfig configuration parameters. type: object x-kubernetes-preserve-unknown-fields: true url: - description: URL of the endpoint to send samples to. type: string required: - url type: object remoteWrite: - description: |- - RemoteWrite Optional URL to remote-write compatible storage to persist - vmalert state and rule results to. - Rule results will be persisted according to each rule. - Alerts state will be persisted in the form of time series named ALERTS and ALERTS_FOR_STATE - see -remoteWrite.url docs in vmalerts for details. - E.g. http://127.0.0.1:8428 properties: basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -13999,111 +11133,61 @@ spec: x-kubernetes-map-type: atomic type: object bearerTokenFile: - description: Path to bearer token file type: string bearerTokenSecret: - description: Optional bearer auth token to use for -remoteWrite.url properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic concurrency: - description: Defines number of readers that concurrently write - into remote storage (default 1) format: int32 type: integer flushInterval: - description: Defines interval of flushes to remote write endpoint - (default 5s) pattern: '[0-9]+(ms|s|m|h)' type: string headers: - description: |- - Headers allow configuring custom http headers - Must be in form of semicolon separated header with value - e.g. - headerName:headerValue - vmalert supports it since 1.79.0 version items: type: string type: array maxBatchSize: - description: Defines defines max number of timeseries to be flushed - at once (default 1000) format: int32 type: integer maxQueueSize: - description: Defines the max number of pending datapoints to remote - write endpoint (default 100000) format: int32 type: integer oauth2: - description: OAuth2 defines OAuth2 configuration required: - client_id - token_url type: object x-kubernetes-preserve-unknown-fields: true tlsConfig: - description: TLSConfig specifies TLSConfig configuration parameters. type: object x-kubernetes-preserve-unknown-fields: true url: - description: URL of the endpoint to send samples to. type: string required: - url type: object replicaCount: - description: ReplicaCount is the expected size of the Application. format: int32 type: integer resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used properties: claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. type: string request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. type: string required: - name @@ -14119,9 +11203,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -14130,88 +11211,34 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. format: int32 type: integer rollingUpdate: - description: RollingUpdate - overrides deployment update params. properties: maxSurge: anyOf: - type: integer - type: string - description: |- - The maximum number of pods that can be scheduled above the desired number of - pods. - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). - This can not be 0 if MaxUnavailable is 0. - Absolute number is calculated from percentage by rounding up. - Defaults to 25%. - Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when - the rolling update starts, such that the total number of old and new pods do not exceed - 130% of desired pods. Once old pods have been killed, - new ReplicaSet can be scaled up further, ensuring that total number of pods running - at any time during the update is at most 130% of desired pods. x-kubernetes-int-or-string: true maxUnavailable: anyOf: - type: integer - type: string - description: |- - The maximum number of pods that can be unavailable during the update. - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). - Absolute number is calculated from percentage by rounding down. - This can not be 0 if MaxSurge is 0. - Defaults to 25%. - Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods - immediately when the rolling update starts. Once new pods are ready, old ReplicaSet - can be scaled down further, followed by scaling up the new ReplicaSet, ensuring - that the total number of pods available at all times during the update is at - least 70% of desired pods. x-kubernetes-int-or-string: true type: object ruleNamespaceSelector: - description: |- - RuleNamespaceSelector to be selected for VMRules discovery. - Works in combination with Selector. - If both nil - behaviour controlled by selectAllByDefault - NamespaceSelector nil - only objects at VMAlert namespace. 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 @@ -14225,56 +11252,23 @@ spec: 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 rulePath: - description: |- - RulePath to the file with alert rules. - Supports patterns. Flag can be specified multiple times. - Examples: - -rule /path/to/file. Path to a single file with alerting rules - -rule dir/*.yaml -rule /*.yaml. Relative path to all .yaml files in folder, - absolute path to all .yaml files in root. - by default operator adds /etc/vmalert/configs/base/vmalert.yaml items: type: string type: array ruleSelector: - description: |- - RuleSelector selector to select which VMRules to mount for loading alerting - rules from. - Works in combination with NamespaceSelector. - If both nil - behaviour controlled by selectAllByDefault - NamespaceSelector nil - only objects at VMAlert namespace. 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 @@ -14288,159 +11282,76 @@ spec: 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 runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ type: string schedulerName: - description: SchedulerName - defines kubernetes scheduler name type: string secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder items: type: string type: array securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. type: object x-kubernetes-preserve-unknown-fields: true selectAllByDefault: - description: |- - SelectAllByDefault changes default behavior for empty CRD selectors, such RuleSelector. - with selectAllByDefault: true and empty serviceScrapeSelector and RuleNamespaceSelector - Operator selects all exist serviceScrapes - with selectAllByDefault: false - selects nothing type: boolean serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to use to run the pods type: string serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vmalert VMServiceScrape - spec required: - endpoints type: object x-kubernetes-preserve-unknown-fields: true serviceSpec: - description: ServiceSpec that will be added to vmalert service spec properties: metadata: - description: EmbeddedObjectMetadata defines objectMeta for additional - service. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ type: object x-kubernetes-preserve-unknown-fields: true useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication type: boolean required: - spec type: object startupProbe: - description: StartupProbe that will be added to CRD pod type: object x-kubernetes-preserve-unknown-fields: true terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container graceful - termination format: int64 type: integer tolerations: - description: Tolerations If specified, the pod's tolerations. items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. type: string type: object type: array topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ items: - description: TopologySpreadConstraint specifies how to spread matching - pods among the given topology. required: - maxSkew - topologyKey @@ -14449,89 +11360,32 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array updateStrategy: - description: UpdateStrategy - overrides default update strategy. enum: - Recreate - RollingUpdate type: string useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements type: boolean useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions type: boolean useVMConfigReloader: - description: |- - UseVMConfigReloader replaces prometheus-like config-reloader - with vm one. It uses secrets watch instead of file watch - which greatly increases speed of config updates type: boolean volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container items: - description: VolumeMount describes a mounting of a Volume within - a container. properties: mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. type: string mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). type: string name: - description: This must match the Name of a Volume. type: string readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. type: boolean recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). type: string subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. type: string required: - mountPath @@ -14539,13 +11393,7 @@ spec: type: object type: array volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional items: - description: Volume represents a named volume in a pod that may - be accessed by any container in the pod. required: - name type: object @@ -14555,58 +11403,34 @@ spec: - datasource type: object status: - description: VMAlertStatus defines the observed state of VMAlert properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -14621,16 +11445,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -14643,7 +11462,1366 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 + name: vmanomalies.operator.victoriametrics.com +spec: + group: operator.victoriametrics.com + names: + kind: VMAnomaly + listKind: VMAnomalyList + plural: vmanomalies + singular: vmanomaly + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: current number of shards + jsonPath: .status.shards + name: Shards Count + type: integer + - description: Current status of update rollout + jsonPath: .status.updateStatus + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + affinity: + type: object + x-kubernetes-preserve-unknown-fields: true + claimTemplates: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + x-kubernetes-preserve-unknown-fields: true + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + configMaps: + items: + type: string + type: array + configRawYaml: + type: string + configSecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + containers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + disableAutomountServiceAccountToken: + type: boolean + disableSelfServiceScrape: + type: boolean + dnsConfig: + items: + x-kubernetes-preserve-unknown-fields: true + properties: + nameservers: + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + dnsPolicy: + type: string + extraArgs: + additionalProperties: + type: string + type: object + extraEnvs: + items: + properties: + name: + type: string + value: + type: string + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + extraEnvsFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + host_aliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostNetwork: + type: boolean + image: + properties: + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + license: + properties: + forceOffline: + type: boolean + key: + type: string + keyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + reloadInterval: + type: string + type: object + livenessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + logLevel: + enum: + - INFO + - WARN + - ERROR + - FATAL + - PANIC + type: string + managedMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + minReadySeconds: + format: int32 + type: integer + monitoring: + properties: + pull: + properties: + port: + type: string + required: + - port + type: object + push: + properties: + basicAuth: + properties: + password: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + password_file: + type: string + username: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearer: + properties: + bearerTokenFile: + type: string + bearerTokenSecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + extraLabels: + additionalProperties: + type: string + type: object + healthPath: + type: string + pushFrequency: + type: string + tenantID: + type: string + timeout: + type: string + tlsConfig: + properties: + ca: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + caFile: + type: string + cert: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + certFile: + type: string + insecureSkipVerify: + type: boolean + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + type: string + type: object + url: + type: string + required: + - url + type: object + type: object + nodeSelector: + additionalProperties: + type: string + type: object + paused: + type: boolean + persistentVolumeClaimRetentionPolicy: + properties: + whenDeleted: + type: string + whenScaled: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + selectorLabels: + additionalProperties: + type: string + type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string + type: object + podMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + port: + type: string + priorityClassName: + type: string + reader: + properties: + basicAuth: + properties: + password: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + password_file: + type: string + username: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearer: + properties: + bearerTokenFile: + type: string + bearerTokenSecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + dataRange: + items: + type: string + type: array + datasourceURL: + type: string + extraFilters: + items: + type: string + type: array + healthPath: + type: string + latencyOffset: + type: string + maxPointsPerQuery: + type: integer + queryFromLastSeenTimestamp: + type: boolean + queryRangePath: + type: string + samplingPeriod: + type: string + tenantID: + type: string + timeout: + type: string + tlsConfig: + properties: + ca: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + caFile: + type: string + cert: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + certFile: + type: string + insecureSkipVerify: + type: boolean + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + type: string + type: object + tz: + type: string + required: + - datasourceURL + - samplingPeriod + type: object + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + readinessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + replicaCount: + format: int32 + type: integer + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + revisionHistoryLimitCount: + format: int32 + type: integer + rollingUpdateStrategy: + type: string + runtimeClassName: + type: string + schedulerName: + type: string + secrets: + items: + type: string + type: array + securityContext: + type: object + x-kubernetes-preserve-unknown-fields: true + server: + properties: + addr: + type: string + maxConcurrentTasks: + maximum: 20 + minimum: 1 + type: integer + pathPrefix: + type: string + port: + type: string + uiDefaultState: + type: string + type: object + serviceAccountName: + type: string + serviceScrapeSpec: + required: + - endpoints + type: object + x-kubernetes-preserve-unknown-fields: true + shardCount: + format: int32 + type: integer + startupProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + storage: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + volumeClaimTemplate: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + useDefaultResources: + type: boolean + useStrictSecurity: + type: boolean + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + writer: + properties: + basicAuth: + properties: + password: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + password_file: + type: string + username: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearer: + properties: + bearerTokenFile: + type: string + bearerTokenSecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + datasourceURL: + type: string + healthPath: + type: string + metricFormat: + properties: + __name__: + type: string + extraLabels: + additionalProperties: + type: string + type: object + for: + type: string + required: + - __name__ + - for + type: object + tenantID: + type: string + timeout: + type: string + tlsConfig: + properties: + ca: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + caFile: + type: string + cert: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + certFile: + type: string + insecureSkipVerify: + type: boolean + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + type: string + type: object + required: + - datasourceURL + type: object + required: + - reader + - writer + type: object + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + maxLength: 32768 + type: string + observedGeneration: + format: int64 + minimum: 0 + type: integer + reason: + maxLength: 1024 + minLength: 1 + type: string + status: + enum: + - "True" + - "False" + - Unknown + type: string + type: + maxLength: 316 + type: string + required: + - lastTransitionTime + - lastUpdateTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + format: int64 + type: integer + reason: + type: string + shards: + format: int32 + type: integer + updateStatus: + type: string + type: object + type: object + served: true + storage: true + subresources: + scale: + labelSelectorPath: .status.selector + specReplicasPath: .spec.shardCount + statusReplicasPath: .status.shards + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.0 name: vmauths.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -14662,86 +12840,58 @@ spec: - jsonPath: .metadata.creationTimestamp name: Age type: date - - description: The desired replicas number of Alertmanagers + - description: The desired replicas number of VMAuth jsonPath: .spec.replicaCount name: ReplicaCount type: integer name: v1beta1 schema: openAPIV3Schema: - description: VMAuth is the Schema for the vmauths API 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: VMAuthSpec defines the desired state of VMAuth properties: affinity: - description: Affinity If specified, the pod's scheduling constraints. type: object x-kubernetes-preserve-unknown-fields: true configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder items: type: string type: array + configReloadAuthKeySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic configReloaderExtraArgs: additionalProperties: type: string - description: |- - ConfigReloaderExtraArgs that will be passed to VMAuths config-reloader container - for example resyncInterval: "30s" type: object + configReloaderImage: + type: string configReloaderImageTag: - description: ConfigReloaderImageTag defines image:tag for config-reloader - container type: string configReloaderResources: - description: |- - ConfigReloaderResources config-reloader container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used properties: claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. type: string request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. type: string required: - name @@ -14757,9 +12907,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -14768,129 +12915,60 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object configSecret: - description: |- - ConfigSecret is the name of a Kubernetes Secret in the same namespace as the - VMAuth object, which contains auth configuration for vmauth, - configuration must be inside secret key: config.yaml. - It must be created and managed manually. - If it's defined, configuration for vmauth becomes unmanaged and operator'll not create any related secrets/config-reloaders - Deprecated, use externalConfig.secretRef instead type: string containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. items: - description: A single application container that you want to run - within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. type: boolean disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable type: boolean dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. items: x-kubernetes-preserve-unknown-fields: true properties: nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. items: type: string type: array x-kubernetes-list-type: atomic options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. properties: name: - description: |- - Name is this DNS resolver option's name. - Required. type: string value: - description: Value is this DNS resolver option's value. type: string type: object type: array x-kubernetes-list-type: atomic searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. items: type: string type: array x-kubernetes-list-type: atomic type: object dnsPolicy: - description: DNSPolicy sets DNS policy for the pod type: string externalConfig: - description: |- - ExternalConfig defines a source of external VMAuth configuration. - If it's defined, configuration for vmauth becomes unmanaged and operator'll not create any related secrets/config-reloaders properties: localPath: - description: |- - LocalPath contains static path to a config, which is managed externally for cases - when using secrets is not applicable, e.g.: Vault sidecar. type: string secretRef: - description: SecretRef defines selector for externally managed - secret which contains configuration properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key @@ -14900,30 +12978,13 @@ spec: extraArgs: additionalProperties: type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp type: object extraEnvs: - description: ExtraEnvs that will be passed to the application container items: - description: EnvVar represents an environment variable present in - a Container. properties: name: - description: Name of the environment variable. Must be a C_IDENTIFIER. type: string value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". type: string required: - name @@ -14931,234 +12992,512 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap items: - description: EnvFromSource represents the source of a set of ConfigMaps properties: configMapRef: - description: The ConfigMap to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap must be defined type: boolean 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. type: string secretRef: - description: The Secret to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret must be defined type: boolean type: object x-kubernetes-map-type: atomic type: object type: array host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostNetwork: - description: HostNetwork controls whether the pod may use the node - network namespace type: boolean + hpa: + properties: + behaviour: + properties: + scaleDown: + properties: + policies: + items: + properties: + periodSeconds: + format: int32 + type: integer + type: + type: string + value: + format: int32 + type: integer + required: + - periodSeconds + - type + - value + type: object + type: array + x-kubernetes-list-type: atomic + selectPolicy: + type: string + stabilizationWindowSeconds: + format: int32 + type: integer + tolerance: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + scaleUp: + properties: + policies: + items: + properties: + periodSeconds: + format: int32 + type: integer + type: + type: string + value: + format: int32 + type: integer + required: + - periodSeconds + - type + - value + type: object + type: array + x-kubernetes-list-type: atomic + selectPolicy: + type: string + stabilizationWindowSeconds: + format: int32 + type: integer + tolerance: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + maxReplicas: + format: int32 + type: integer + metrics: + items: + properties: + containerResource: + properties: + container: + type: string + name: + type: string + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - container + - name + - target + type: object + external: + properties: + metric: + properties: + name: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - metric + - target + type: object + object: + properties: + describedObject: + properties: + apiVersion: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + metric: + properties: + name: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - describedObject + - metric + - target + type: object + pods: + properties: + metric: + properties: + name: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - metric + - target + type: object + resource: + properties: + name: + type: string + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - name + - target + type: object + type: + type: string + required: + - type + type: object + type: array + minReplicas: + format: int32 + type: integer + type: object + httpRoute: + properties: + annotations: + additionalProperties: + type: string + type: object + extraRules: + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + x-kubernetes-preserve-unknown-fields: true + hostnames: + items: + 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: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + parentRefs: + items: + properties: + group: + default: gateway.networking.k8s.io + 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 + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + maxLength: 253 + minLength: 1 + type: string + namespace: + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + 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 + type: array + type: object image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config properties: pullPolicy: - description: PullPolicy describes how to pull docker image type: string repository: - description: Repository contains name of docker image + it's repository - if needed type: string tag: - description: Tag contains desired docker image version type: string type: object imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string type: object x-kubernetes-map-type: atomic type: array ingress: - description: Ingress enables ingress configuration for VMAuth. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object class_name: - description: ClassName defines ingress class name for VMAuth type: string extraRules: - description: |- - ExtraRules - additional rules for ingress, - must be checked for correctness by user. items: - description: |- - IngressRule represents the rules mapping the paths under a specified host to - the related backend services. Incoming requests are first evaluated for a host - match, then routed to the backend associated with the matching IngressRuleValue. properties: host: - description: "host is the fully qualified domain name of - a network host, as defined by RFC 3986.\nNote the following - deviations from the \"host\" part of the\nURI as defined - in RFC 3986:\n1. IPs are not allowed. Currently an IngressRuleValue - can only apply to\n the IP in the Spec of the parent - Ingress.\n2. The `:` delimiter is not respected because - ports are not allowed.\n\t Currently the port of an Ingress - is implicitly :80 for http and\n\t :443 for https.\nBoth - these may change in the future.\nIncoming requests are - matched against the host before the\nIngressRuleValue. - If the host is unspecified, the Ingress routes all\ntraffic - based on the specified IngressRuleValue.\n\nhost can be - \"precise\" which is a domain name without the terminating - dot of\na network host (e.g. \"foo.bar.com\") or \"wildcard\", - which is a domain name\nprefixed with a single wildcard - label (e.g. \"*.foo.com\").\nThe wildcard character '*' - must appear by itself as the first DNS label and\nmatches - only a single label. You cannot have a wildcard label - by itself (e.g. Host == \"*\").\nRequests will be matched - against the Host field in the following way:\n1. If host - is precise, the request matches this rule if the http - host header is equal to Host.\n2. If host is a wildcard, - then the request matches this rule if the http host header\nis - to equal to the suffix (removing the first label) of the - wildcard rule." type: string http: - description: |- - HTTPIngressRuleValue is a list of http selectors pointing to backends. - In the example: http:///? -> backend where - where parts of the url correspond to RFC 3986, this resource will be used - to match against everything after the last '/' and before the first '?' - or '#'. properties: paths: - description: paths is a collection of paths that map - requests to backends. items: - description: |- - HTTPIngressPath associates a path with a backend. Incoming urls matching the - path are forwarded to the backend. properties: backend: - description: |- - backend defines the referenced service endpoint to which the traffic - will be forwarded to. properties: resource: - description: |- - resource is an ObjectRef to another Kubernetes resource in the namespace - of the Ingress object. If resource is specified, a service.Name and - service.Port must not be specified. - This is a mutually exclusive setting with "Service". properties: apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. type: string kind: - description: Kind is the type of resource - being referenced type: string name: - description: Name is the name of resource - being referenced type: string required: - kind @@ -15166,29 +13505,14 @@ spec: type: object x-kubernetes-map-type: atomic service: - description: |- - service references a service as a backend. - This is a mutually exclusive setting with "Resource". properties: name: - description: |- - name is the referenced service. The service must exist in - the same namespace as the Ingress object. type: string port: - description: |- - port of the referenced service. A port name or port number - is required for a IngressServiceBackend. properties: name: - description: |- - name is the name of the port on the Service. - This is a mutually exclusive setting with "Number". type: string number: - description: |- - number is the numerical port number (e.g. 80) on the Service. - This is a mutually exclusive setting with "Name". format: int32 type: integer type: object @@ -15198,28 +13522,8 @@ spec: type: object type: object path: - description: |- - path is matched against the path of an incoming request. Currently it can - contain characters disallowed from the conventional "path" part of a URL - as defined by RFC 3986. Paths must begin with a '/' and must be present - when using PathType with value "Exact" or "Prefix". type: string pathType: - description: |- - pathType determines the interpretation of the path matching. PathType can - be one of the following values: - * Exact: Matches the URL path exactly. - * Prefix: Matches based on a URL path prefix split by '/'. Matching is - done on a path element by element basis. A path element refers is the - list of labels in the path split by the '/' separator. A request is a - match for path p if every p is an element-wise prefix of p of the - request path. Note that if the last element of the path is a substring - of the last element in request path, it is not a match (e.g. /foo/bar - matches /foo/bar/baz, but does not match /foo/barbaz). - * ImplementationSpecific: Interpretation of the Path matching is up to - the IngressClass. Implementations can treat this as a separate PathType - or treat it identically to Prefix or Exact path types. - Implementations are required to support all path types. type: string required: - backend @@ -15233,138 +13537,76 @@ spec: type: object type: array extraTls: - description: |- - ExtraTLS - additional TLS configuration for ingress - must be checked for correctness by user. items: - description: IngressTLS describes the transport layer security - associated with an ingress. properties: hosts: - description: |- - hosts is a list of hosts included in the TLS certificate. The values in - this list must match the name/s used in the tlsSecret. Defaults to the - wildcard host setting for the loadbalancer controller fulfilling this - Ingress, if left unspecified. items: type: string type: array x-kubernetes-list-type: atomic secretName: - description: |- - secretName is the name of the secret used to terminate TLS traffic on - port 443. Field is left optional to allow TLS routing based on SNI - hostname alone. If the SNI host in a listener conflicts with the "Host" - header field used by an IngressRule, the SNI host is used for termination - and value of the "Host" header is used for routing. type: string type: object type: array host: - description: |- - Host defines ingress host parameter for default rule - It will be used, only if TlsHosts is empty type: string labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string + paths: + items: + type: string + type: array tlsHosts: - description: TlsHosts configures TLS access for ingress, tlsSecretName - must be defined for it. items: type: string type: array tlsSecretName: - description: |- - TlsSecretName defines secretname at the VMAuth namespace with cert and key - https://kubernetes.io/docs/concepts/services-networking/ingress/#tls type: string type: object initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ items: - description: A single application container that you want to run - within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array + internalListenPort: + type: string license: - description: |- - License allows to configure license key to be used for enterprise features. - Using license key is supported starting from VictoriaMetrics v1.94.0. - See [here](https://docs.victoriametrics.com/enterprise) properties: forceOffline: - description: Enforce offline verification of the license key. type: boolean key: - description: |- - Enterprise license key. This flag is available only in [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise). - To request a trial license, [go to](https://victoriametrics.com/products/enterprise/trial) type: string keyRef: - description: KeyRef is reference to secret with license key for - enterprise features. properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic reloadInterval: - description: Interval to be used for checking for license key - changes. Note that this is only applicable when using KeyRef. type: string type: object livenessProbe: - description: LivenessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true logFormat: - description: LogFormat for VMAuth to be configured with. enum: - default - json type: string logLevel: - description: LogLevel for victoria metrics single to be configured - with. enum: - INFO - WARN @@ -15373,164 +13615,87 @@ spec: - PANIC type: string managedMetadata: - description: |- - ManagedMetadata defines metadata that will be added to the all objects - created by operator for the given CustomResource properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object type: object minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle format: int32 type: integer nodeSelector: additionalProperties: type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. type: object paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. type: boolean podDisruptionBudget: - description: PodDisruptionBudget created by operator properties: maxUnavailable: anyOf: - type: integer - type: string - description: |- - An eviction is allowed if at most "maxUnavailable" pods selected by - "selector" are unavailable after the eviction, i.e. even in absence of - the evicted pod. For example, one can prevent all voluntary evictions - by specifying 0. This is a mutually exclusive setting with "minAvailable". x-kubernetes-int-or-string: true minAvailable: anyOf: - type: integer - type: string - description: |- - An eviction is allowed if at least "minAvailable" pods selected by - "selector" will still be available after the eviction, i.e. even in the - absence of the evicted pod. So for example you can prevent all voluntary - evictions by specifying "100%". x-kubernetes-int-or-string: true selectorLabels: additionalProperties: type: string - description: |- - replaces default labels selector generated by operator - it's useful when you need to create custom budget type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string type: object podMetadata: - description: PodMetadata configures Labels and Annotations which are - propagated to the VMAuth pods. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object port: - description: Port listen address type: string priorityClassName: - description: PriorityClassName class assigned to the Pods type: string readinessGates: - description: ReadinessGates defines pod readiness gates items: - description: PodReadinessGate contains the reference to a pod condition properties: conditionType: - description: ConditionType refers to a condition in the pod's - condition list with matching type. type: string required: - conditionType type: object type: array readinessProbe: - description: ReadinessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true replicaCount: - description: ReplicaCount is the expected size of the Application. format: int32 type: integer resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used properties: claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. type: string request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. type: string required: - name @@ -15546,9 +13711,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -15557,167 +13719,91 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. format: int32 type: integer + rollingUpdate: + properties: + maxSurge: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ type: string schedulerName: - description: SchedulerName - defines kubernetes scheduler name type: string secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder items: type: string type: array securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. type: object x-kubernetes-preserve-unknown-fields: true selectAllByDefault: - description: |- - SelectAllByDefault changes default behavior for empty CRD selectors, such userSelector. - with selectAllByDefault: true and empty userSelector and userNamespaceSelector - Operator selects all exist users - with selectAllByDefault: false - selects nothing type: boolean serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to use to run the pods type: string serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vmauth VMServiceScrape - spec required: - endpoints type: object x-kubernetes-preserve-unknown-fields: true serviceSpec: - description: ServiceSpec that will be added to vmsingle service spec properties: metadata: - description: EmbeddedObjectMetadata defines objectMeta for additional - service. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ type: object x-kubernetes-preserve-unknown-fields: true useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication type: boolean required: - spec type: object startupProbe: - description: StartupProbe that will be added to CRD pod type: object x-kubernetes-preserve-unknown-fields: true terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container graceful - termination format: int64 type: integer tolerations: - description: Tolerations If specified, the pod's tolerations. items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. type: string type: object type: array topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ items: - description: TopologySpreadConstraint specifies how to spread matching - pods among the given topology. required: - maxSkew - topologyKey @@ -15726,54 +13812,24 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array unauthorizedAccessConfig: - description: |- - UnauthorizedAccessConfig configures access for un authorized users - - Deprecated, use unauthorizedUserAccessSpec instead - will be removed at v1.0 release x-kubernetes-preserve-unknown-fields: true unauthorizedUserAccessSpec: - description: UnauthorizedUserAccessSpec defines unauthorized_user - config section of vmauth config properties: default_url: - description: |- - DefaultURLs backend url for non-matching paths filter - usually used for default backend with error message items: type: string type: array discover_backend_ips: - description: DiscoverBackendIPs instructs discovering URLPrefix - backend IPs via DNS. type: boolean drop_src_path_prefix_parts: - description: |- - DropSrcPathPrefixParts is the number of `/`-delimited request path prefix parts to drop before proxying the request to backend. - See [here](https://docs.victoriametrics.com/vmauth#dropping-request-path-prefix) for more details. type: integer dump_request_on_errors: - description: |- - DumpRequestOnErrors instructs vmauth to return detailed request params to the client - if routing rules don't allow to forward request to the backends. - Useful for debugging `src_hosts` and `src_headers` based routing rules - - available since v1.107.0 vmauth version type: boolean headers: - description: |- - Headers represent additional http headers, that vmauth uses - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.68.0 version of vmauth items: type: string type: array ip_filters: - description: |- - IPFilters defines per target src ip filters - supported only with enterprise version of [vmauth](https://docs.victoriametrics.com/vmauth/#ip-filters) properties: allow_list: items: @@ -15785,93 +13841,180 @@ spec: type: array type: object load_balancing_policy: - description: |- - LoadBalancingPolicy defines load balancing policy to use for backend urls. - Supported policies: least_loaded, first_available. - See [here](https://docs.victoriametrics.com/vmauth#load-balancing) for more details (default "least_loaded") enum: - least_loaded - first_available type: string max_concurrent_requests: - description: |- - MaxConcurrentRequests defines max concurrent requests per user - 300 is default value for vmauth type: integer metric_labels: additionalProperties: type: string - description: MetricLabels - additional labels for metrics exported - by vmauth for given user. type: object response_headers: - description: |- - ResponseHeaders represent additional http headers, that vmauth adds for request response - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.93.0 version of vmauth items: type: string type: array retry_status_codes: - description: |- - RetryStatusCodes defines http status codes in numeric format for request retries - e.g. [429,503] items: type: integer type: array + targetRefs: + items: + properties: + crd: + properties: + kind: + enum: + - VMAgent + - VMAlert + - VMSingle + - VLogs + - VMAlertManager + - VMAlertmanager + - VMCluster/vmselect + - VMCluster/vmstorage + - VMCluster/vminsert + - VLSingle + - VLCluster/vlinsert + - VLCluster/vlselect + - VLCluster/vlstorage + - VLAgent + - VTCluster/vtinsert + - VTCluster/vtselect + - VTCluster/vtstorage + - VTSingle + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + - namespace + type: object + discover_backend_ips: + type: boolean + drop_src_path_prefix_parts: + type: integer + headers: + items: + type: string + type: array + hosts: + items: + type: string + type: array + load_balancing_policy: + enum: + - least_loaded + - first_available + type: string + paths: + items: + type: string + type: array + query_args: + items: + properties: + name: + type: string + values: + items: + type: string + type: array + required: + - name + - values + type: object + type: array + response_headers: + items: + type: string + type: array + retry_status_codes: + items: + type: integer + type: array + src_headers: + items: + type: string + type: array + src_query_args: + items: + type: string + type: array + static: + properties: + url: + type: string + urls: + items: + type: string + type: array + type: object + target_path_suffix: + type: string + targetRefBasicAuth: + properties: + password: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + required: + - password + - username + type: object + type: object + type: array tlsConfig: - description: TLSConfig defines tls configuration for the backend - connection properties: ca: - description: Struct containing the CA cert to use for the - targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -15879,56 +14022,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container to use for - the targets. type: string cert: - description: Struct containing the client cert file for the - targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -15936,181 +14053,97 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container - for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container - for the targets. type: string keySecret: - description: Secret containing the client key file for the - targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object url_map: items: - description: |- - UnauthorizedAccessConfigURLMap defines element of url_map routing configuration - For UnauthorizedAccessConfig and VMAuthUnauthorizedUserAccessSpec.URLMap properties: discover_backend_ips: - description: DiscoverBackendIPs instructs discovering URLPrefix - backend IPs via DNS. type: boolean drop_src_path_prefix_parts: - description: |- - DropSrcPathPrefixParts is the number of `/`-delimited request path prefix parts to drop before proxying the request to backend. - See [here](https://docs.victoriametrics.com/vmauth#dropping-request-path-prefix) for more details. type: integer headers: - description: |- - RequestHeaders represent additional http headers, that vmauth uses - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.68.0 version of vmauth items: type: string type: array load_balancing_policy: - description: |- - LoadBalancingPolicy defines load balancing policy to use for backend urls. - Supported policies: least_loaded, first_available. - See [here](https://docs.victoriametrics.com/vmauth#load-balancing) for more details (default "least_loaded") enum: - least_loaded - first_available type: string response_headers: - description: |- - ResponseHeaders represent additional http headers, that vmauth adds for request response - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.93.0 version of vmauth items: type: string type: array retry_status_codes: - description: |- - RetryStatusCodes defines http status codes in numeric format for request retries - Can be defined per target or at VMUser.spec level - e.g. [429,503] items: type: integer type: array src_headers: - description: SrcHeaders is an optional list of headers, - which must match request headers. items: type: string type: array src_hosts: - description: SrcHosts is an optional list of regular expressions, - which must match the request hostname. items: type: string type: array src_paths: - description: SrcPaths is an optional list of regular expressions, - which must match the request path. items: type: string type: array src_query_args: - description: SrcQueryArgs is an optional list of query args, - which must match request URL query args. items: type: string type: array url_prefix: - description: |- - UrlPrefix contains backend url prefixes for the proxied request url. - URLPrefix defines prefix prefix for destination x-kubernetes-preserve-unknown-fields: true type: object type: array url_prefix: - description: URLPrefix defines prefix prefix for destination x-kubernetes-preserve-unknown-fields: true type: object + updateStrategy: + enum: + - Recreate + - RollingUpdate + type: string useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements + type: boolean + useProxyProtocol: type: boolean useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions type: boolean useVMConfigReloader: - description: |- - UseVMConfigReloader replaces prometheus-like config-reloader - with vm one. It uses secrets watch instead of file watch - which greatly increases speed of config updates type: boolean userNamespaceSelector: - description: |- - UserNamespaceSelector Namespaces to be selected for VMAuth discovery. - Works in combination with Selector. - NamespaceSelector nil - only objects at VMAuth namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault 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 @@ -16124,43 +14157,19 @@ spec: 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 userSelector: - description: |- - UserSelector defines VMUser to be selected for config file generation. - Works in combination with NamespaceSelector. - NamespaceSelector nil - only objects at VMAuth namespace. - If both nil - behaviour controlled by selectAllByDefault 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 @@ -16174,73 +14183,25 @@ spec: 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 volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container items: - description: VolumeMount describes a mounting of a Volume within - a container. properties: mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. type: string mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). type: string name: - description: This must match the Name of a Volume. type: string readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. type: boolean recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). type: string subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. type: string required: - mountPath @@ -16248,73 +14209,126 @@ spec: type: object type: array volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional items: - description: Volume represents a named volume in a pod that may - be accessed by any container in the pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array + vpa: + properties: + recommenders: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + resourcePolicy: + properties: + containerPolicies: + items: + properties: + containerName: + type: string + controlledResources: + items: + type: string + type: array + controlledValues: + enum: + - RequestsAndLimits + - RequestsOnly + type: string + maxAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + minAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + mode: + enum: + - Auto + - "Off" + type: string + type: object + type: array + type: object + updatePolicy: + properties: + evictionRequirements: + items: + properties: + changeRequirement: + enum: + - TargetHigherThanRequests + - TargetLowerThanRequests + type: string + resources: + items: + type: string + type: array + required: + - changeRequirement + - resources + type: object + type: array + minReplicas: + format: int32 + type: integer + updateMode: + enum: + - "Off" + - Initial + - Recreate + - InPlaceOrRecreate + - Auto + type: string + type: object + type: object type: object x-kubernetes-preserve-unknown-fields: true status: - description: VMAuthStatus defines the observed state of VMAuth properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -16329,16 +14343,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -16351,7 +14360,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmclusters.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -16385,146 +14394,67 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: |- - VMCluster is fast, cost-effective and scalable time-series database. - Cluster version with 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: VMClusterSpec defines the desired state of VMCluster properties: clusterDomainName: - description: |- - ClusterDomainName defines domain name suffix for in-cluster dns addresses - aka .cluster.local - used by vminsert and vmselect to build vmstorage address type: string clusterVersion: - description: |- - ClusterVersion defines default images tag for all components. - it can be overwritten with component specific image.tag value. type: string imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string type: object x-kubernetes-map-type: atomic type: array license: - description: |- - License allows to configure license key to be used for enterprise features. - Using license key is supported starting from VictoriaMetrics v1.94.0. - See [here](https://docs.victoriametrics.com/enterprise) properties: forceOffline: - description: Enforce offline verification of the license key. type: boolean key: - description: |- - Enterprise license key. This flag is available only in [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise). - To request a trial license, [go to](https://victoriametrics.com/products/enterprise/trial) type: string keyRef: - description: KeyRef is reference to secret with license key for - enterprise features. properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic reloadInterval: - description: Interval to be used for checking for license key - changes. Note that this is only applicable when using KeyRef. type: string type: object managedMetadata: - description: |- - ManagedMetadata defines metadata that will be added to the all objects - created by operator for the given CustomResource properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object type: object paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. type: boolean replicationFactor: - description: |- - ReplicationFactor defines how many copies of data make among - distinct storage nodes format: int32 type: integer requestsLoadBalancer: - description: |- - RequestsLoadBalancer configures load-balancing for vminsert and vmselect requests - it helps to evenly spread load across pods - usually it's not possible with kubernetes TCP based service properties: disableInsertBalancing: type: boolean @@ -16533,157 +14463,75 @@ spec: enabled: type: boolean spec: - description: |- - VMAuthLoadBalancerSpec defines configuration spec for VMAuth used as load-balancer - for VMCluster component type: object x-kubernetes-preserve-unknown-fields: true type: object retentionPeriod: - description: |- - RetentionPeriod for the stored metrics - Note VictoriaMetrics has data/ and indexdb/ folders - metrics from data/ removed eventually as soon as partition leaves retention period - reverse index data at indexdb rotates once at the half of configured - [retention period](https://docs.victoriametrics.com/Single-server-VictoriaMetrics/#retention) + pattern: ^[0-9]+(h|d|w|y)?$ type: string serviceAccountName: - description: |- - ServiceAccountName is the name of the ServiceAccount to use to run the - VMSelect, VMStorage and VMInsert Pods. type: string useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions type: boolean vminsert: properties: affinity: - description: Affinity If specified, the pod's scheduling constraints. type: object x-kubernetes-preserve-unknown-fields: true clusterNativeListenPort: - description: |- - ClusterNativePort for multi-level cluster setup. - More [details](https://docs.victoriametrics.com/Cluster-VictoriaMetrics#multi-level-cluster-setup) type: string configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder items: type: string type: array containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. items: - description: A single application container that you want to - run within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. type: boolean disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable type: boolean dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. items: x-kubernetes-preserve-unknown-fields: true properties: nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. items: type: string type: array x-kubernetes-list-type: atomic options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. properties: name: - description: |- - Name is this DNS resolver option's name. - Required. type: string value: - description: Value is this DNS resolver option's value. type: string type: object type: array x-kubernetes-list-type: atomic searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. items: type: string type: array x-kubernetes-list-type: atomic type: object dnsPolicy: - description: DNSPolicy sets DNS policy for the pod type: string extraArgs: additionalProperties: type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp type: object extraEnvs: - description: ExtraEnvs that will be passed to the application - container items: - description: EnvVar represents an environment variable present - in a Container. properties: name: - description: Name of the environment variable. Must be a - C_IDENTIFIER. type: string value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". type: string required: - name @@ -16691,190 +14539,108 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap items: - description: EnvFromSource represents the source of a set of - ConfigMaps properties: configMapRef: - description: The ConfigMap to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap must be defined type: boolean 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. type: string secretRef: - description: The Secret to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret must be defined type: boolean type: object x-kubernetes-map-type: atomic type: object type: array host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostNetwork: - description: HostNetwork controls whether the pod may use the - node network namespace type: boolean hpa: - description: HPA defines kubernetes PodAutoScaling configuration - version 2. type: object x-kubernetes-preserve-unknown-fields: true image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config properties: pullPolicy: - description: PullPolicy describes how to pull docker image type: string repository: - description: Repository contains name of docker image + it's - repository if needed type: string tag: - description: Tag contains desired docker image version type: string type: object imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string type: object x-kubernetes-map-type: atomic type: array initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ items: - description: A single application container that you want to - run within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array insertPorts: - description: InsertPorts - additional listen ports for data ingestion. properties: graphitePort: - description: GraphitePort listen port type: string influxPort: - description: InfluxPort listen port type: string openTSDBHTTPPort: - description: OpenTSDBHTTPPort for http connections. type: string openTSDBPort: - description: OpenTSDBPort for tcp and udp listen type: string type: object livenessProbe: - description: LivenessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true logFormat: - description: |- - LogFormat for VMInsert to be configured with. - default or json enum: - default - json type: string logLevel: - description: LogLevel for VMInsert to be configured with. enum: - INFO - WARN @@ -16883,142 +14649,76 @@ spec: - PANIC type: string minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle format: int32 type: integer nodeSelector: additionalProperties: type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. type: object paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. type: boolean podDisruptionBudget: - description: PodDisruptionBudget created by operator properties: maxUnavailable: anyOf: - type: integer - type: string - description: |- - An eviction is allowed if at most "maxUnavailable" pods selected by - "selector" are unavailable after the eviction, i.e. even in absence of - the evicted pod. For example, one can prevent all voluntary evictions - by specifying 0. This is a mutually exclusive setting with "minAvailable". x-kubernetes-int-or-string: true minAvailable: anyOf: - type: integer - type: string - description: |- - An eviction is allowed if at least "minAvailable" pods selected by - "selector" will still be available after the eviction, i.e. even in the - absence of the evicted pod. So for example you can prevent all voluntary - evictions by specifying "100%". x-kubernetes-int-or-string: true selectorLabels: additionalProperties: type: string - description: |- - replaces default labels selector generated by operator - it's useful when you need to create custom budget type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string type: object podMetadata: - description: PodMetadata configures Labels and Annotations which - are propagated to the VMInsert pods. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object port: - description: Port listen address type: string priorityClassName: - description: PriorityClassName class assigned to the Pods type: string readinessGates: - description: ReadinessGates defines pod readiness gates items: - description: PodReadinessGate contains the reference to a pod - condition properties: conditionType: - description: ConditionType refers to a condition in the - pod's condition list with matching type. type: string required: - conditionType type: object type: array readinessProbe: - description: ReadinessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true replicaCount: - description: ReplicaCount is the expected size of the Application. format: int32 type: integer resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used properties: claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. type: string request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. type: string required: - name @@ -17034,9 +14734,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -17045,194 +14742,87 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. format: int32 type: integer rollingUpdate: - description: RollingUpdate - overrides deployment update params. properties: maxSurge: anyOf: - type: integer - type: string - description: |- - The maximum number of pods that can be scheduled above the desired number of - pods. - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). - This can not be 0 if MaxUnavailable is 0. - Absolute number is calculated from percentage by rounding up. - Defaults to 25%. - Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when - the rolling update starts, such that the total number of old and new pods do not exceed - 130% of desired pods. Once old pods have been killed, - new ReplicaSet can be scaled up further, ensuring that total number of pods running - at any time during the update is at most 130% of desired pods. x-kubernetes-int-or-string: true maxUnavailable: anyOf: - type: integer - type: string - description: |- - The maximum number of pods that can be unavailable during the update. - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). - Absolute number is calculated from percentage by rounding down. - This can not be 0 if MaxSurge is 0. - Defaults to 25%. - Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods - immediately when the rolling update starts. Once new pods are ready, old ReplicaSet - can be scaled down further, followed by scaling up the new ReplicaSet, ensuring - that the total number of pods available at all times during the update is at - least 70% of desired pods. x-kubernetes-int-or-string: true type: object runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ type: string schedulerName: - description: SchedulerName - defines kubernetes scheduler name type: string secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder items: type: string type: array securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. type: object x-kubernetes-preserve-unknown-fields: true serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vminsert - VMServiceScrape spec required: - endpoints type: object x-kubernetes-preserve-unknown-fields: true serviceSpec: - description: ServiceSpec that will be added to vminsert service - spec properties: metadata: - description: EmbeddedObjectMetadata defines objectMeta for - additional service. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ type: object x-kubernetes-preserve-unknown-fields: true useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication type: boolean required: - spec type: object startupProbe: - description: StartupProbe that will be added to CRD pod type: object x-kubernetes-preserve-unknown-fields: true terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container - graceful termination format: int64 type: integer tolerations: - description: Tolerations If specified, the pod's tolerations. items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. type: string type: object type: array topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ items: - description: TopologySpreadConstraint specifies how to spread - matching pods among the given topology. required: - maxSkew - topologyKey @@ -17241,83 +14831,30 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array updateStrategy: - description: UpdateStrategy - overrides default update strategy. enum: - Recreate - RollingUpdate type: string useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements type: boolean useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions type: boolean volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container items: - description: VolumeMount describes a mounting of a Volume within - a container. properties: mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. type: string mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). type: string name: - description: This must match the Name of a Volume. type: string readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. type: boolean recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). type: string subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. type: string required: - mountPath @@ -17325,575 +14862,161 @@ spec: type: object type: array volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional items: - description: Volume represents a named volume in a pod that - may be accessed by any container in the pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array + vpa: + properties: + recommenders: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + resourcePolicy: + properties: + containerPolicies: + items: + properties: + containerName: + type: string + controlledResources: + items: + type: string + type: array + controlledValues: + enum: + - RequestsAndLimits + - RequestsOnly + type: string + maxAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + minAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + mode: + enum: + - Auto + - "Off" + type: string + type: object + type: array + type: object + updatePolicy: + properties: + evictionRequirements: + items: + properties: + changeRequirement: + enum: + - TargetHigherThanRequests + - TargetLowerThanRequests + type: string + resources: + items: + type: string + type: array + required: + - changeRequirement + - resources + type: object + type: array + minReplicas: + format: int32 + type: integer + updateMode: + enum: + - "Off" + - Initial + - Recreate + - InPlaceOrRecreate + - Auto + type: string + type: object + type: object type: object vmselect: - description: VMSelect defines configuration section for vmselect components - of the victoria-metrics cluster properties: affinity: - description: Affinity If specified, the pod's scheduling constraints. type: object x-kubernetes-preserve-unknown-fields: true cacheMountPath: - description: |- - CacheMountPath allows to add cache persistent for VMSelect, - will use "/cache" as default if not specified. type: string claimTemplates: - description: ClaimTemplates allows adding additional VolumeClaimTemplates - for StatefulSet items: - description: PersistentVolumeClaim is a user's request for and - claim to a persistent volume - 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: - description: |- - Standard object's metadata. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - type: object - x-kubernetes-preserve-unknown-fields: true - spec: - description: |- - spec defines the desired characteristics of a volume requested by a pod author. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes - to consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to - the PersistentVolume backing this claim. - type: string - type: object - status: - description: |- - status represents the current information/status of a persistent volume claim. - Read-only. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the actual access modes the volume backing the PVC has. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - allocatedResourceStatuses: - additionalProperties: - description: |- - When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource - that it does not recognizes, then it should ignore that update and let other controllers - handle it. - type: string - description: "allocatedResourceStatuses stores status - of resource being resized for the given PVC.\nKey - names follow standard Kubernetes label syntax. Valid - values are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources - must use implementation-defined prefixed names such - as \"example.com/my-custom-resource\"\nApart from - above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not - be used.\n\nClaimResourceStatus can be in any of following - states:\n\t- ControllerResizeInProgress:\n\t\tState - set when resize controller starts resizing the volume - in control-plane.\n\t- ControllerResizeFailed:\n\t\tState - set when resize has failed in resize controller with - a terminal error.\n\t- NodeResizePending:\n\t\tState - set when resize controller has finished resizing the - volume but further resizing of\n\t\tvolume is needed - on the node.\n\t- NodeResizeInProgress:\n\t\tState - set when kubelet starts resizing the volume.\n\t- - NodeResizeFailed:\n\t\tState set when resizing has - failed in kubelet with a terminal error. Transient - errors don't set\n\t\tNodeResizeFailed.\nFor example: - if expanding a PVC for more capacity - this field - can be one of the following states:\n\t- pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeFailed\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizePending\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeFailed\"\nWhen this field is not set, - it means that no resize operation is in progress for - the given PVC.\n\nA controller that receives PVC update - with previously unknown resourceName or ClaimResourceStatus\nshould - ignore the update for the purpose it was designed. - For example - a controller that\nonly is responsible - for resizing capacity of the volume, should ignore - PVC updates that change other valid\nresources associated - with PVC.\n\nThis is an alpha field and requires enabling - RecoverVolumeExpansionFailure feature." - type: object - x-kubernetes-map-type: granular - allocatedResources: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: "allocatedResources tracks the resources - allocated to a PVC including its capacity.\nKey names - follow standard Kubernetes label syntax. Valid values - are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources - must use implementation-defined prefixed names such - as \"example.com/my-custom-resource\"\nApart from - above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not - be used.\n\nCapacity reported here may be larger than - the actual capacity when a volume expansion operation\nis - requested.\nFor storage quota, the larger value from - allocatedResources and PVC.spec.resources is used.\nIf - allocatedResources is not set, PVC.spec.resources - alone is used for quota calculation.\nIf a volume - expansion capacity request is lowered, allocatedResources - is only\nlowered if there are no expansion operations - in progress and if the actual volume capacity\nis - equal or lower than the requested capacity.\n\nA controller - that receives PVC update with previously unknown resourceName\nshould - ignore the update for the purpose it was designed. - For example - a controller that\nonly is responsible - for resizing capacity of the volume, should ignore - PVC updates that change other valid\nresources associated - with PVC.\n\nThis is an alpha field and requires enabling - RecoverVolumeExpansionFailure feature." - type: object - capacity: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: capacity represents the actual resources - of the underlying volume. - type: object - conditions: - description: |- - conditions is the current Condition of persistent volume claim. If underlying persistent volume is being - resized then the Condition will be set to 'Resizing'. - items: - description: PersistentVolumeClaimCondition contains - details about state of pvc - properties: - lastProbeTime: - description: lastProbeTime is the time we probed - the condition. - format: date-time - type: string - lastTransitionTime: - description: lastTransitionTime is the time the - condition transitioned from one status to another. - format: date-time - type: string - message: - description: message is the human-readable message - indicating details about last transition. - type: string - reason: - description: |- - reason is a unique, this should be a short, machine understandable string that gives the reason - for condition's last transition. If it reports "Resizing" that means the underlying - persistent volume is being resized. - type: string - status: - description: |- - Status is the status of the condition. - Can be True, False, Unknown. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=state%20of%20pvc-,conditions.status,-(string)%2C%20required - type: string - type: - description: |- - Type is the type of the condition. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=set%20to%20%27ResizeStarted%27.-,PersistentVolumeClaimCondition,-contains%20details%20about - type: string - required: - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - currentVolumeAttributesClassName: - description: |- - currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. - When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - type: string - modifyVolumeStatus: - description: |- - ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. - When this is unset, there is no ModifyVolume operation being attempted. - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - properties: - status: - description: "status is the status of the ControllerModifyVolume - operation. It can be in any of following states:\n - - Pending\n Pending indicates that the PersistentVolumeClaim - cannot be modified due to unmet requirements, - such as\n the specified VolumeAttributesClass - not existing.\n - InProgress\n InProgress indicates - that the volume is being modified.\n - Infeasible\n - \ Infeasible indicates that the request has been - rejected as invalid by the CSI driver. To\n\t - \ resolve the error, a valid VolumeAttributesClass - needs to be specified.\nNote: New statuses can - be added in the future. Consumers should check - for unknown statuses and fail appropriately." - type: string - targetVolumeAttributesClassName: - description: targetVolumeAttributesClassName is - the name of the VolumeAttributesClass the PVC - currently being reconciled - type: string - required: - - status - type: object - phase: - description: phase represents the current phase of PersistentVolumeClaim. - type: string - type: object type: object type: array clusterNativeListenPort: - description: |- - ClusterNativePort for multi-level cluster setup. - More [details](https://docs.victoriametrics.com/Cluster-VictoriaMetrics#multi-level-cluster-setup) type: string configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder items: type: string type: array containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. items: - description: A single application container that you want to - run within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. type: boolean disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable type: boolean dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. items: x-kubernetes-preserve-unknown-fields: true properties: nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. items: type: string type: array x-kubernetes-list-type: atomic options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. properties: name: - description: |- - Name is this DNS resolver option's name. - Required. type: string value: - description: Value is this DNS resolver option's value. type: string type: object type: array x-kubernetes-list-type: atomic searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. items: type: string type: array x-kubernetes-list-type: atomic type: object dnsPolicy: - description: DNSPolicy sets DNS policy for the pod type: string extraArgs: additionalProperties: type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp type: object extraEnvs: - description: ExtraEnvs that will be passed to the application - container items: - description: EnvVar represents an environment variable present - in a Container. properties: name: - description: Name of the environment variable. Must be a - C_IDENTIFIER. type: string value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". type: string required: - name @@ -17901,175 +15024,97 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap items: - description: EnvFromSource represents the source of a set of - ConfigMaps properties: configMapRef: - description: The ConfigMap to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap must be defined type: boolean 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. type: string secretRef: - description: The Secret to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret must be defined type: boolean type: object x-kubernetes-map-type: atomic type: object type: array host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostNetwork: - description: HostNetwork controls whether the pod may use the - node network namespace type: boolean hpa: - description: |- - Configures horizontal pod autoscaling. - Note, enabling this option disables vmselect to vmselect communication. In most cases it's not an issue. type: object x-kubernetes-preserve-unknown-fields: true image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config properties: pullPolicy: - description: PullPolicy describes how to pull docker image type: string repository: - description: Repository contains name of docker image + it's - repository if needed type: string tag: - description: Tag contains desired docker image version type: string type: object imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string type: object x-kubernetes-map-type: atomic type: array initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ items: - description: A single application container that you want to - run within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array livenessProbe: - description: LivenessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true logFormat: - description: |- - LogFormat for VMSelect to be configured with. - default or json enum: - default - json type: string logLevel: - description: LogLevel for VMSelect to be configured with. enum: - INFO - WARN @@ -18078,184 +15123,83 @@ spec: - PANIC type: string minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle format: int32 type: integer nodeSelector: additionalProperties: type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. type: object paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. type: boolean - persistentVolume: - description: |- - Storage - add persistent volume for cacheMountPath - its useful for persistent cache - use storage instead of persistentVolume. + persistentVolumeClaimRetentionPolicy: properties: - disableMountSubPath: - description: |- - Deprecated: subPath usage will be disabled by default in a future release, this option will become unnecessary. - DisableMountSubPath allows to remove any subPath usage in volume mounts. - type: boolean - emptyDir: - description: |- - EmptyDirVolumeSource to be used by the Prometheus StatefulSets. If specified, used in place of any volumeClaimTemplate. More - info: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir - properties: - medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - volumeClaimTemplate: - description: A PVC spec to be used by the VMAlertManager StatefulSets. - type: object - x-kubernetes-preserve-unknown-fields: true + whenDeleted: + type: string + whenScaled: + type: string type: object podDisruptionBudget: - description: PodDisruptionBudget created by operator properties: maxUnavailable: anyOf: - type: integer - type: string - description: |- - An eviction is allowed if at most "maxUnavailable" pods selected by - "selector" are unavailable after the eviction, i.e. even in absence of - the evicted pod. For example, one can prevent all voluntary evictions - by specifying 0. This is a mutually exclusive setting with "minAvailable". x-kubernetes-int-or-string: true minAvailable: anyOf: - type: integer - type: string - description: |- - An eviction is allowed if at least "minAvailable" pods selected by - "selector" will still be available after the eviction, i.e. even in the - absence of the evicted pod. So for example you can prevent all voluntary - evictions by specifying "100%". x-kubernetes-int-or-string: true selectorLabels: additionalProperties: type: string - description: |- - replaces default labels selector generated by operator - it's useful when you need to create custom budget type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string type: object podMetadata: - description: PodMetadata configures Labels and Annotations which - are propagated to the VMSelect pods. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object port: - description: Port listen address type: string priorityClassName: - description: PriorityClassName class assigned to the Pods type: string readinessGates: - description: ReadinessGates defines pod readiness gates items: - description: PodReadinessGate contains the reference to a pod - condition properties: conditionType: - description: ConditionType refers to a condition in the - pod's condition list with matching type. type: string required: - conditionType type: object type: array readinessProbe: - description: ReadinessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true replicaCount: - description: ReplicaCount is the expected size of the Application. format: int32 type: integer resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used properties: claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. type: string request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. type: string required: - name @@ -18271,9 +15215,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -18282,233 +15223,109 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. format: int32 type: integer rollingUpdateStrategy: - description: |- - RollingUpdateStrategy defines strategy for application updates - Default is OnDelete, in this case operator handles update process - Can be changed for RollingUpdate type: string + rollingUpdateStrategyBehavior: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ type: string schedulerName: - description: SchedulerName - defines kubernetes scheduler name type: string secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder items: type: string type: array securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. type: object x-kubernetes-preserve-unknown-fields: true serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vmselect - VMServiceScrape spec required: - endpoints type: object x-kubernetes-preserve-unknown-fields: true serviceSpec: - description: ServiceSpec that will be added to vmselect service - spec properties: metadata: - description: EmbeddedObjectMetadata defines objectMeta for - additional service. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ type: object x-kubernetes-preserve-unknown-fields: true useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication type: boolean required: - spec type: object startupProbe: - description: StartupProbe that will be added to CRD pod type: object x-kubernetes-preserve-unknown-fields: true storage: - description: |- - StorageSpec - add persistent volume claim for cacheMountPath - its needed for persistent cache properties: - disableMountSubPath: - description: |- - Deprecated: subPath usage will be disabled by default in a future release, this option will become unnecessary. - DisableMountSubPath allows to remove any subPath usage in volume mounts. - type: boolean emptyDir: - description: |- - EmptyDirVolumeSource to be used by the Prometheus StatefulSets. If specified, used in place of any volumeClaimTemplate. More - info: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir properties: medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir type: string sizeLimit: anyOf: - type: integer - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true type: object volumeClaimTemplate: - description: A PVC spec to be used by the VMAlertManager StatefulSets. 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: - description: EmbeddedMetadata contains metadata relevant - to an EmbeddedResource. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object spec: - description: |- - Spec defines the desired characteristics of a volume requested by a pod author. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims properties: accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string type: array x-kubernetes-list-type: atomic dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. properties: apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. type: string kind: - description: Kind is the type of resource being - referenced type: string name: - description: Name is the name of resource being - referenced type: string required: - kind @@ -18516,62 +15333,20 @@ spec: type: object x-kubernetes-map-type: atomic dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. properties: apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. type: string kind: - description: Kind is the type of resource being - referenced type: string name: - description: Name is the name of resource being - referenced type: string namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. type: string required: - kind - name type: object resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources properties: limits: additionalProperties: @@ -18580,9 +15355,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -18591,41 +15363,18 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object selector: - description: selector is a label query over volumes - to consider for binding. 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 @@ -18639,103 +15388,28 @@ spec: 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 storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 type: string volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. type: string volumeName: - description: volumeName is the binding reference to - the PersistentVolume backing this claim. type: string type: object status: - description: |- - Status represents the current information/status of a persistent volume claim. - Read-only. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims properties: accessModes: - description: |- - accessModes contains the actual access modes the volume backing the PVC has. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string type: array x-kubernetes-list-type: atomic allocatedResourceStatuses: additionalProperties: - description: |- - When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource - that it does not recognizes, then it should ignore that update and let other controllers - handle it. type: string - description: "allocatedResourceStatuses stores status - of resource being resized for the given PVC.\nKey - names follow standard Kubernetes label syntax. Valid - values are either:\n\t* Un-prefixed keys:\n\t\t- - storage - the capacity of the volume.\n\t* Custom - resources must use implementation-defined prefixed - names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or - have kubernetes.io prefix are considered\nreserved - and hence may not be used.\n\nClaimResourceStatus - can be in any of following states:\n\t- ControllerResizeInProgress:\n\t\tState - set when resize controller starts resizing the volume - in control-plane.\n\t- ControllerResizeFailed:\n\t\tState - set when resize has failed in resize controller - with a terminal error.\n\t- NodeResizePending:\n\t\tState - set when resize controller has finished resizing - the volume but further resizing of\n\t\tvolume is - needed on the node.\n\t- NodeResizeInProgress:\n\t\tState - set when kubelet starts resizing the volume.\n\t- - NodeResizeFailed:\n\t\tState set when resizing has - failed in kubelet with a terminal error. Transient - errors don't set\n\t\tNodeResizeFailed.\nFor example: - if expanding a PVC for more capacity - this field - can be one of the following states:\n\t- pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeFailed\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizePending\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeFailed\"\nWhen this field is not set, - it means that no resize operation is in progress - for the given PVC.\n\nA controller that receives - PVC update with previously unknown resourceName - or ClaimResourceStatus\nshould ignore the update - for the purpose it was designed. For example - a - controller that\nonly is responsible for resizing - capacity of the volume, should ignore PVC updates - that change other valid\nresources associated with - PVC.\n\nThis is an alpha field and requires enabling - RecoverVolumeExpansionFailure feature." type: object x-kubernetes-map-type: granular allocatedResources: @@ -18745,33 +15419,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: "allocatedResources tracks the resources - allocated to a PVC including its capacity.\nKey - names follow standard Kubernetes label syntax. Valid - values are either:\n\t* Un-prefixed keys:\n\t\t- - storage - the capacity of the volume.\n\t* Custom - resources must use implementation-defined prefixed - names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or - have kubernetes.io prefix are considered\nreserved - and hence may not be used.\n\nCapacity reported - here may be larger than the actual capacity when - a volume expansion operation\nis requested.\nFor - storage quota, the larger value from allocatedResources - and PVC.spec.resources is used.\nIf allocatedResources - is not set, PVC.spec.resources alone is used for - quota calculation.\nIf a volume expansion capacity - request is lowered, allocatedResources is only\nlowered - if there are no expansion operations in progress - and if the actual volume capacity\nis equal or lower - than the requested capacity.\n\nA controller that - receives PVC update with previously unknown resourceName\nshould - ignore the update for the purpose it was designed. - For example - a controller that\nonly is responsible - for resizing capacity of the volume, should ignore - PVC updates that change other valid\nresources associated - with PVC.\n\nThis is an alpha field and requires - enabling RecoverVolumeExpansionFailure feature." type: object capacity: additionalProperties: @@ -18780,48 +15427,23 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: capacity represents the actual resources - of the underlying volume. type: object conditions: - description: |- - conditions is the current Condition of persistent volume claim. If underlying persistent volume is being - resized then the Condition will be set to 'Resizing'. items: - description: PersistentVolumeClaimCondition contains - details about state of pvc properties: lastProbeTime: - description: lastProbeTime is the time we probed - the condition. format: date-time type: string lastTransitionTime: - description: lastTransitionTime is the time - the condition transitioned from one status - to another. format: date-time type: string message: - description: message is the human-readable message - indicating details about last transition. type: string reason: - description: |- - reason is a unique, this should be a short, machine understandable string that gives the reason - for condition's last transition. If it reports "Resizing" that means the underlying - persistent volume is being resized. type: string status: - description: |- - Status is the status of the condition. - Can be True, False, Unknown. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=state%20of%20pvc-,conditions.status,-(string)%2C%20required type: string type: - description: |- - Type is the type of the condition. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=set%20to%20%27ResizeStarted%27.-,PersistentVolumeClaimCondition,-contains%20details%20about type: string required: - status @@ -18832,100 +15454,42 @@ spec: - type x-kubernetes-list-type: map currentVolumeAttributesClassName: - description: |- - currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. - When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). type: string modifyVolumeStatus: - description: |- - ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. - When this is unset, there is no ModifyVolume operation being attempted. - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). properties: status: - description: "status is the status of the ControllerModifyVolume - operation. It can be in any of following states:\n - - Pending\n Pending indicates that the PersistentVolumeClaim - cannot be modified due to unmet requirements, - such as\n the specified VolumeAttributesClass - not existing.\n - InProgress\n InProgress - indicates that the volume is being modified.\n - - Infeasible\n Infeasible indicates that the - request has been rejected as invalid by the - CSI driver. To\n\t resolve the error, a valid - VolumeAttributesClass needs to be specified.\nNote: - New statuses can be added in the future. Consumers - should check for unknown statuses and fail appropriately." type: string targetVolumeAttributesClassName: - description: targetVolumeAttributesClassName is - the name of the VolumeAttributesClass the PVC - currently being reconciled type: string required: - status type: object phase: - description: phase represents the current phase of - PersistentVolumeClaim. type: string type: object type: object type: object terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container - graceful termination format: int64 type: integer tolerations: - description: Tolerations If specified, the pod's tolerations. items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. type: string type: object type: array topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ items: - description: TopologySpreadConstraint specifies how to spread - matching pods among the given topology. required: - maxSkew - topologyKey @@ -18934,77 +15498,25 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements type: boolean useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions type: boolean volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container items: - description: VolumeMount describes a mounting of a Volume within - a container. properties: mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. type: string mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). type: string name: - description: This must match the Name of a Volume. type: string readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. type: boolean recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). type: string subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. type: string required: - mountPath @@ -19012,563 +15524,158 @@ spec: type: object type: array volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional items: - description: Volume represents a named volume in a pod that - may be accessed by any container in the pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array + vpa: + properties: + recommenders: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + resourcePolicy: + properties: + containerPolicies: + items: + properties: + containerName: + type: string + controlledResources: + items: + type: string + type: array + controlledValues: + enum: + - RequestsAndLimits + - RequestsOnly + type: string + maxAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + minAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + mode: + enum: + - Auto + - "Off" + type: string + type: object + type: array + type: object + updatePolicy: + properties: + evictionRequirements: + items: + properties: + changeRequirement: + enum: + - TargetHigherThanRequests + - TargetLowerThanRequests + type: string + resources: + items: + type: string + type: array + required: + - changeRequirement + - resources + type: object + type: array + minReplicas: + format: int32 + type: integer + updateMode: + enum: + - "Off" + - Initial + - Recreate + - InPlaceOrRecreate + - Auto + type: string + type: object + type: object type: object vmstorage: properties: affinity: - description: Affinity If specified, the pod's scheduling constraints. type: object x-kubernetes-preserve-unknown-fields: true claimTemplates: - description: ClaimTemplates allows adding additional VolumeClaimTemplates - for StatefulSet items: - description: PersistentVolumeClaim is a user's request for and - claim to a persistent volume - 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: - description: |- - Standard object's metadata. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - type: object - x-kubernetes-preserve-unknown-fields: true - spec: - description: |- - spec defines the desired characteristics of a volume requested by a pod author. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes - to consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to - the PersistentVolume backing this claim. - type: string - type: object - status: - description: |- - status represents the current information/status of a persistent volume claim. - Read-only. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the actual access modes the volume backing the PVC has. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - allocatedResourceStatuses: - additionalProperties: - description: |- - When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource - that it does not recognizes, then it should ignore that update and let other controllers - handle it. - type: string - description: "allocatedResourceStatuses stores status - of resource being resized for the given PVC.\nKey - names follow standard Kubernetes label syntax. Valid - values are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources - must use implementation-defined prefixed names such - as \"example.com/my-custom-resource\"\nApart from - above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not - be used.\n\nClaimResourceStatus can be in any of following - states:\n\t- ControllerResizeInProgress:\n\t\tState - set when resize controller starts resizing the volume - in control-plane.\n\t- ControllerResizeFailed:\n\t\tState - set when resize has failed in resize controller with - a terminal error.\n\t- NodeResizePending:\n\t\tState - set when resize controller has finished resizing the - volume but further resizing of\n\t\tvolume is needed - on the node.\n\t- NodeResizeInProgress:\n\t\tState - set when kubelet starts resizing the volume.\n\t- - NodeResizeFailed:\n\t\tState set when resizing has - failed in kubelet with a terminal error. Transient - errors don't set\n\t\tNodeResizeFailed.\nFor example: - if expanding a PVC for more capacity - this field - can be one of the following states:\n\t- pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeFailed\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizePending\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeFailed\"\nWhen this field is not set, - it means that no resize operation is in progress for - the given PVC.\n\nA controller that receives PVC update - with previously unknown resourceName or ClaimResourceStatus\nshould - ignore the update for the purpose it was designed. - For example - a controller that\nonly is responsible - for resizing capacity of the volume, should ignore - PVC updates that change other valid\nresources associated - with PVC.\n\nThis is an alpha field and requires enabling - RecoverVolumeExpansionFailure feature." - type: object - x-kubernetes-map-type: granular - allocatedResources: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: "allocatedResources tracks the resources - allocated to a PVC including its capacity.\nKey names - follow standard Kubernetes label syntax. Valid values - are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources - must use implementation-defined prefixed names such - as \"example.com/my-custom-resource\"\nApart from - above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not - be used.\n\nCapacity reported here may be larger than - the actual capacity when a volume expansion operation\nis - requested.\nFor storage quota, the larger value from - allocatedResources and PVC.spec.resources is used.\nIf - allocatedResources is not set, PVC.spec.resources - alone is used for quota calculation.\nIf a volume - expansion capacity request is lowered, allocatedResources - is only\nlowered if there are no expansion operations - in progress and if the actual volume capacity\nis - equal or lower than the requested capacity.\n\nA controller - that receives PVC update with previously unknown resourceName\nshould - ignore the update for the purpose it was designed. - For example - a controller that\nonly is responsible - for resizing capacity of the volume, should ignore - PVC updates that change other valid\nresources associated - with PVC.\n\nThis is an alpha field and requires enabling - RecoverVolumeExpansionFailure feature." - type: object - capacity: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: capacity represents the actual resources - of the underlying volume. - type: object - conditions: - description: |- - conditions is the current Condition of persistent volume claim. If underlying persistent volume is being - resized then the Condition will be set to 'Resizing'. - items: - description: PersistentVolumeClaimCondition contains - details about state of pvc - properties: - lastProbeTime: - description: lastProbeTime is the time we probed - the condition. - format: date-time - type: string - lastTransitionTime: - description: lastTransitionTime is the time the - condition transitioned from one status to another. - format: date-time - type: string - message: - description: message is the human-readable message - indicating details about last transition. - type: string - reason: - description: |- - reason is a unique, this should be a short, machine understandable string that gives the reason - for condition's last transition. If it reports "Resizing" that means the underlying - persistent volume is being resized. - type: string - status: - description: |- - Status is the status of the condition. - Can be True, False, Unknown. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=state%20of%20pvc-,conditions.status,-(string)%2C%20required - type: string - type: - description: |- - Type is the type of the condition. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=set%20to%20%27ResizeStarted%27.-,PersistentVolumeClaimCondition,-contains%20details%20about - type: string - required: - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - currentVolumeAttributesClassName: - description: |- - currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. - When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - type: string - modifyVolumeStatus: - description: |- - ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. - When this is unset, there is no ModifyVolume operation being attempted. - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - properties: - status: - description: "status is the status of the ControllerModifyVolume - operation. It can be in any of following states:\n - - Pending\n Pending indicates that the PersistentVolumeClaim - cannot be modified due to unmet requirements, - such as\n the specified VolumeAttributesClass - not existing.\n - InProgress\n InProgress indicates - that the volume is being modified.\n - Infeasible\n - \ Infeasible indicates that the request has been - rejected as invalid by the CSI driver. To\n\t - \ resolve the error, a valid VolumeAttributesClass - needs to be specified.\nNote: New statuses can - be added in the future. Consumers should check - for unknown statuses and fail appropriately." - type: string - targetVolumeAttributesClassName: - description: targetVolumeAttributesClassName is - the name of the VolumeAttributesClass the PVC - currently being reconciled - type: string - required: - - status - type: object - phase: - description: phase represents the current phase of PersistentVolumeClaim. - type: string - type: object type: object + x-kubernetes-preserve-unknown-fields: true type: array configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder items: type: string type: array containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. items: - description: A single application container that you want to - run within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. type: boolean disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable type: boolean dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. items: x-kubernetes-preserve-unknown-fields: true properties: nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. items: type: string type: array x-kubernetes-list-type: atomic options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. properties: name: - description: |- - Name is this DNS resolver option's name. - Required. type: string value: - description: Value is this DNS resolver option's value. type: string type: object type: array x-kubernetes-list-type: atomic searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. items: type: string type: array x-kubernetes-list-type: atomic type: object dnsPolicy: - description: DNSPolicy sets DNS policy for the pod type: string extraArgs: additionalProperties: type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp type: object extraEnvs: - description: ExtraEnvs that will be passed to the application - container items: - description: EnvVar represents an environment variable present - in a Container. properties: name: - description: Name of the environment variable. Must be a - C_IDENTIFIER. type: string value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". type: string required: - name @@ -19576,169 +15683,438 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap items: - description: EnvFromSource represents the source of a set of - ConfigMaps properties: configMapRef: - description: The ConfigMap to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap must be defined type: boolean 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. type: string secretRef: - description: The Secret to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret must be defined type: boolean type: object x-kubernetes-map-type: atomic type: object type: array host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostNetwork: - description: HostNetwork controls whether the pod may use the - node network namespace type: boolean + hpa: + properties: + behaviour: + properties: + scaleDown: + properties: + policies: + items: + properties: + periodSeconds: + format: int32 + type: integer + type: + type: string + value: + format: int32 + type: integer + required: + - periodSeconds + - type + - value + type: object + type: array + x-kubernetes-list-type: atomic + selectPolicy: + type: string + stabilizationWindowSeconds: + format: int32 + type: integer + tolerance: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + scaleUp: + properties: + policies: + items: + properties: + periodSeconds: + format: int32 + type: integer + type: + type: string + value: + format: int32 + type: integer + required: + - periodSeconds + - type + - value + type: object + type: array + x-kubernetes-list-type: atomic + selectPolicy: + type: string + stabilizationWindowSeconds: + format: int32 + type: integer + tolerance: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + maxReplicas: + format: int32 + type: integer + metrics: + items: + properties: + containerResource: + properties: + container: + type: string + name: + type: string + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - container + - name + - target + type: object + external: + properties: + metric: + properties: + name: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - metric + - target + type: object + object: + properties: + describedObject: + properties: + apiVersion: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + metric: + properties: + name: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - describedObject + - metric + - target + type: object + pods: + properties: + metric: + properties: + name: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - metric + - target + type: object + resource: + properties: + name: + type: string + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - name + - target + type: object + type: + type: string + required: + - type + type: object + type: array + minReplicas: + format: int32 + type: integer + type: object image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config properties: pullPolicy: - description: PullPolicy describes how to pull docker image type: string repository: - description: Repository contains name of docker image + it's - repository if needed type: string tag: - description: Tag contains desired docker image version type: string type: object imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string type: object x-kubernetes-map-type: atomic type: array initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ items: - description: A single application container that you want to - run within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array livenessProbe: - description: LivenessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true logFormat: - description: |- - LogFormat for VMStorage to be configured with. - default or json enum: - default - json type: string logLevel: - description: LogLevel for VMStorage to be configured with. enum: - INFO - WARN @@ -19747,159 +16123,93 @@ spec: - PANIC type: string maintenanceInsertNodeIDs: - description: |- - MaintenanceInsertNodeIDs - excludes given node ids from insert requests routing, must contain pod suffixes - for pod-0, id will be 0 and etc. - lets say, you have pod-0, pod-1, pod-2, pod-3. to exclude pod-0 and pod-3 from insert routing, define nodeIDs: [0,3]. - Useful at storage expanding, when you want to rebalance some data at cluster. items: format: int32 type: integer type: array maintenanceSelectNodeIDs: - description: MaintenanceInsertNodeIDs - excludes given node ids - from select requests routing, must contain pod suffixes - for - pod-0, id will be 0 and etc. items: format: int32 type: integer type: array minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle format: int32 type: integer nodeSelector: additionalProperties: type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. type: object paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. type: boolean + persistentVolumeClaimRetentionPolicy: + properties: + whenDeleted: + type: string + whenScaled: + type: string + type: object podDisruptionBudget: - description: PodDisruptionBudget created by operator properties: maxUnavailable: anyOf: - type: integer - type: string - description: |- - An eviction is allowed if at most "maxUnavailable" pods selected by - "selector" are unavailable after the eviction, i.e. even in absence of - the evicted pod. For example, one can prevent all voluntary evictions - by specifying 0. This is a mutually exclusive setting with "minAvailable". x-kubernetes-int-or-string: true minAvailable: anyOf: - type: integer - type: string - description: |- - An eviction is allowed if at least "minAvailable" pods selected by - "selector" will still be available after the eviction, i.e. even in the - absence of the evicted pod. So for example you can prevent all voluntary - evictions by specifying "100%". x-kubernetes-int-or-string: true selectorLabels: additionalProperties: type: string - description: |- - replaces default labels selector generated by operator - it's useful when you need to create custom budget type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string type: object podMetadata: - description: PodMetadata configures Labels and Annotations which - are propagated to the VMStorage pods. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object port: - description: Port listen address type: string priorityClassName: - description: PriorityClassName class assigned to the Pods type: string readinessGates: - description: ReadinessGates defines pod readiness gates items: - description: PodReadinessGate contains the reference to a pod - condition properties: conditionType: - description: ConditionType refers to a condition in the - pod's condition list with matching type. type: string required: - conditionType type: object type: array readinessProbe: - description: ReadinessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true replicaCount: - description: ReplicaCount is the expected size of the Application. format: int32 type: integer resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used properties: claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. type: string request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. type: string required: - name @@ -19915,9 +16225,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -19926,207 +16233,103 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. format: int32 type: integer rollingUpdateStrategy: - description: |- - RollingUpdateStrategy defines strategy for application updates - Default is OnDelete, in this case operator handles update process - Can be changed for RollingUpdate type: string + rollingUpdateStrategyBehavior: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ type: string schedulerName: - description: SchedulerName - defines kubernetes scheduler name type: string secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder items: type: string type: array securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. type: object x-kubernetes-preserve-unknown-fields: true serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vmstorage - VMServiceScrape spec required: - endpoints type: object x-kubernetes-preserve-unknown-fields: true serviceSpec: - description: ServiceSpec that will be create additional service - for vmstorage properties: metadata: - description: EmbeddedObjectMetadata defines objectMeta for - additional service. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ type: object x-kubernetes-preserve-unknown-fields: true useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication type: boolean required: - spec type: object startupProbe: - description: StartupProbe that will be added to CRD pod type: object x-kubernetes-preserve-unknown-fields: true storage: - description: |- - Storage - add persistent volume for StorageDataPath - its useful for persistent cache properties: - disableMountSubPath: - description: |- - Deprecated: subPath usage will be disabled by default in a future release, this option will become unnecessary. - DisableMountSubPath allows to remove any subPath usage in volume mounts. - type: boolean emptyDir: - description: |- - EmptyDirVolumeSource to be used by the Prometheus StatefulSets. If specified, used in place of any volumeClaimTemplate. More - info: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir properties: medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir type: string sizeLimit: anyOf: - type: integer - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true type: object volumeClaimTemplate: - description: A PVC spec to be used by the VMAlertManager StatefulSets. type: object x-kubernetes-preserve-unknown-fields: true type: object storageDataPath: - description: StorageDataPath - path to storage data type: string terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container - graceful termination format: int64 type: integer tolerations: - description: Tolerations If specified, the pod's tolerations. items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. type: string type: object type: array topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ items: - description: TopologySpreadConstraint specifies how to spread - matching pods among the given topology. required: - maxSkew - topologyKey @@ -20135,197 +16338,120 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements type: boolean useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions type: boolean vmBackup: - description: VMBackup configuration for backup properties: acceptEULA: - description: |- - AcceptEULA accepts enterprise feature usage, must be set to true. - otherwise backupmanager cannot be added to single/cluster version. - https://victoriametrics.com/legal/esa/ type: boolean concurrency: - description: Defines number of concurrent workers. Higher - concurrency may reduce backup duration (default 10) format: int32 type: integer credentialsSecret: - description: |- - CredentialsSecret is secret in the same namespace for access to remote storage - The secret is mounted into /etc/vm/creds. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic customS3Endpoint: - description: Custom S3 endpoint for use with S3-compatible - storages (e.g. MinIO). S3 is used if not set type: string destination: - description: Defines destination for backup type: string destinationDisableSuffixAdd: - description: |- - DestinationDisableSuffixAdd - disables suffix adding for cluster version backups - each vmstorage backup must have unique backup folder - so operator adds POD_NAME as suffix for backup destination folder. type: boolean disableDaily: - description: Defines if daily backups disabled (default false) type: boolean disableHourly: - description: Defines if hourly backups disabled (default false) type: boolean disableMonthly: - description: Defines if monthly backups disabled (default - false) type: boolean disableWeekly: - description: Defines if weekly backups disabled (default false) type: boolean extraArgs: additionalProperties: type: string - description: extra args like maxBytesPerSecond default 0 type: object extraEnvs: items: - description: EnvVar represents an environment variable present - in a Container. properties: name: - description: Name of the environment variable. Must - be a C_IDENTIFIER. type: string value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". type: string valueFrom: - description: Source for the environment variable's value. - Cannot be used if value is not empty. properties: configMapKeyRef: - description: Selects a key of a ConfigMap. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or - its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. properties: apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". type: string fieldPath: - description: Path of the field to select in - the specified API version. type: string required: - fieldPath type: object x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. properties: containerName: - description: 'Container name: required for volumes, - optional for env vars' type: string divisor: anyOf: - type: integer - type: string - description: Specifies the output format of - the exposed resources, defaults to "1" pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true resource: - description: 'Required: resource to select' type: string required: - resource type: object x-kubernetes-map-type: atomic secretKeyRef: - description: Selects a key of a secret in the pod's - namespace properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key @@ -20337,79 +16463,45 @@ spec: type: object type: array extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap items: - description: EnvFromSource represents the source of a set - of ConfigMaps properties: configMapRef: - description: The ConfigMap to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap must - be defined type: boolean 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. type: string secretRef: - description: The Secret to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret must be - defined type: boolean type: object x-kubernetes-map-type: atomic type: object type: array image: - description: Image - docker image settings for VMBackuper properties: pullPolicy: - description: PullPolicy describes how to pull docker image type: string repository: - description: Repository contains name of docker image - + it's repository if needed type: string tag: - description: Tag contains desired docker image version type: string type: object logFormat: - description: |- - LogFormat for VMBackup to be configured with. - default or json enum: - default - json type: string logLevel: - description: LogLevel for VMBackup to be configured with. enum: - INFO - WARN @@ -20418,36 +16510,15 @@ spec: - PANIC type: string port: - description: Port for health check connections type: string resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used properties: claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. type: string request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. type: string required: - name @@ -20463,9 +16534,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -20474,96 +16542,36 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object restore: - description: |- - Restore Allows to enable restore options for pod - Read [more](https://docs.victoriametrics.com/vmbackupmanager#restore-commands) properties: onStart: - description: OnStart defines configuration for restore - on pod start properties: enabled: - description: Enabled defines if restore on start enabled type: boolean type: object type: object snapshotCreateURL: - description: SnapshotCreateURL overwrites url for snapshot - create type: string snapshotDeleteURL: - description: SnapShotDeleteURL overwrites url for snapshot - delete type: string volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment definition. - VolumeMounts specified will be appended to other VolumeMounts in the vmbackupmanager container, - that are generated as a result of StorageSpec objects. items: - description: VolumeMount describes a mounting of a Volume - within a container. properties: mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. type: string mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). type: string name: - description: This must match the Name of a Volume. type: string readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. type: boolean recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). type: string subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. type: string required: - mountPath @@ -20572,71 +16580,25 @@ spec: type: array type: object vmInsertPort: - description: VMInsertPort for VMInsert connections type: string vmSelectPort: - description: VMSelectPort for VMSelect connections type: string volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container items: - description: VolumeMount describes a mounting of a Volume within - a container. properties: mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. type: string mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). type: string name: - description: This must match the Name of a Volume. type: string readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. type: boolean recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). type: string subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. type: string required: - mountPath @@ -20644,79 +16606,126 @@ spec: type: object type: array volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional items: - description: Volume represents a named volume in a pod that - may be accessed by any container in the pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array + vpa: + properties: + recommenders: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + resourcePolicy: + properties: + containerPolicies: + items: + properties: + containerName: + type: string + controlledResources: + items: + type: string + type: array + controlledValues: + enum: + - RequestsAndLimits + - RequestsOnly + type: string + maxAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + minAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + mode: + enum: + - Auto + - "Off" + type: string + type: object + type: array + type: object + updatePolicy: + properties: + evictionRequirements: + items: + properties: + changeRequirement: + enum: + - TargetHigherThanRequests + - TargetLowerThanRequests + type: string + resources: + items: + type: string + type: array + required: + - changeRequirement + - resources + type: object + type: array + minReplicas: + format: int32 + type: integer + updateMode: + enum: + - "Off" + - Initial + - Recreate + - InPlaceOrRecreate + - Auto + type: string + type: object + type: object type: object - required: - - retentionPeriod type: object status: - description: VMClusterStatus defines the observed state of VMCluster properties: - clusterStatus: - description: LegacyStatus is deprecated and will be removed at v0.52.0 - version - type: string conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -20731,16 +16740,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object required: @@ -20755,7 +16759,13074 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 + name: vmdistributed.operator.victoriametrics.com +spec: + group: operator.victoriametrics.com + names: + kind: VMDistributed + listKind: VMDistributedList + plural: vmdistributed + singular: vmdistributed + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: current status of update rollout + jsonPath: .status.updateStatus + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + license: + properties: + forceOffline: + type: boolean + key: + type: string + keyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + reloadInterval: + type: string + type: object + paused: + type: boolean + retain: + type: boolean + vmauth: + properties: + enabled: + default: true + type: boolean + name: + type: string + spec: + properties: + affinity: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + configMaps: + items: + type: string + type: array + configReloadAuthKeySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + configReloaderExtraArgs: + additionalProperties: + type: string + type: object + configReloaderImage: + type: string + configReloaderImageTag: + type: string + configReloaderResources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + configSecret: + type: string + containers: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + disableAutomountServiceAccountToken: + type: boolean + disableSelfServiceScrape: + type: boolean + dnsConfig: + properties: + nameservers: + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + dnsPolicy: + type: string + externalConfig: + properties: + localPath: + type: string + secretRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + extraArgs: + additionalProperties: + type: string + type: object + extraEnvs: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + extraEnvsFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + host_aliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostNetwork: + type: boolean + hpa: + properties: + behaviour: + properties: + scaleDown: + properties: + policies: + items: + properties: + periodSeconds: + format: int32 + type: integer + type: + type: string + value: + format: int32 + type: integer + required: + - periodSeconds + - type + - value + type: object + type: array + x-kubernetes-list-type: atomic + selectPolicy: + type: string + stabilizationWindowSeconds: + format: int32 + type: integer + tolerance: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + scaleUp: + properties: + policies: + items: + properties: + periodSeconds: + format: int32 + type: integer + type: + type: string + value: + format: int32 + type: integer + required: + - periodSeconds + - type + - value + type: object + type: array + x-kubernetes-list-type: atomic + selectPolicy: + type: string + stabilizationWindowSeconds: + format: int32 + type: integer + tolerance: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + maxReplicas: + format: int32 + type: integer + metrics: + items: + properties: + containerResource: + properties: + container: + type: string + name: + type: string + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - container + - name + - target + type: object + external: + properties: + metric: + properties: + name: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - metric + - target + type: object + object: + properties: + describedObject: + properties: + apiVersion: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + metric: + properties: + name: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - describedObject + - metric + - target + type: object + pods: + properties: + metric: + properties: + name: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - metric + - target + type: object + resource: + properties: + name: + type: string + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - name + - target + type: object + type: + type: string + required: + - type + type: object + type: array + minReplicas: + format: int32 + type: integer + type: object + httpRoute: + properties: + annotations: + additionalProperties: + type: string + type: object + extraRules: + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + x-kubernetes-preserve-unknown-fields: true + hostnames: + items: + 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: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + parentRefs: + items: + properties: + group: + default: gateway.networking.k8s.io + 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 + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + maxLength: 253 + minLength: 1 + type: string + namespace: + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + 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 + type: array + type: object + image: + properties: + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + ingress: + properties: + annotations: + additionalProperties: + type: string + type: object + class_name: + type: string + extraRules: + items: + properties: + host: + type: string + http: + properties: + paths: + items: + properties: + backend: + properties: + resource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + service: + properties: + name: + type: string + port: + properties: + name: + type: string + number: + format: int32 + type: integer + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + type: object + path: + type: string + pathType: + type: string + required: + - backend + - pathType + type: object + type: array + x-kubernetes-list-type: atomic + required: + - paths + type: object + type: object + type: array + extraTls: + items: + properties: + hosts: + items: + type: string + type: array + x-kubernetes-list-type: atomic + secretName: + type: string + type: object + type: array + host: + type: string + labels: + additionalProperties: + type: string + type: object + name: + type: string + paths: + items: + type: string + type: array + tlsHosts: + items: + type: string + type: array + tlsSecretName: + type: string + type: object + initContainers: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + internalListenPort: + type: string + license: + properties: + forceOffline: + type: boolean + key: + type: string + keyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + reloadInterval: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + logFormat: + enum: + - default + - json + type: string + logLevel: + enum: + - INFO + - WARN + - ERROR + - FATAL + - PANIC + type: string + managedMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + minReadySeconds: + format: int32 + type: integer + nodeSelector: + additionalProperties: + type: string + type: object + paused: + type: boolean + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + selectorLabels: + additionalProperties: + type: string + type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string + type: object + podMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + port: + type: string + priorityClassName: + type: string + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + replicaCount: + format: int32 + type: integer + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + revisionHistoryLimitCount: + format: int32 + type: integer + rollingUpdate: + properties: + maxSurge: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + runtimeClassName: + type: string + schedulerName: + type: string + secrets: + items: + type: string + type: array + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + selectAllByDefault: + type: boolean + serviceAccountName: + type: string + serviceScrapeSpec: + properties: + attach_metadata: + properties: + namespace: + type: boolean + node: + type: boolean + type: object + discoveryRole: + enum: + - endpoints + - service + - endpointslices + - endpointslice + type: string + endpoints: + items: + properties: + attach_metadata: + properties: + namespace: + type: boolean + node: + type: boolean + type: object + authorization: + properties: + credentials: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + credentialsFile: + type: string + type: + type: string + type: object + basicAuth: + properties: + password: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + password_file: + type: string + username: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenFile: + type: string + bearerTokenSecret: + nullable: true + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + follow_redirects: + type: boolean + honorLabels: + type: boolean + honorTimestamps: + type: boolean + interval: + type: string + max_scrape_size: + type: string + metricRelabelConfigs: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + oauth2: + properties: + client_id: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + client_secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + client_secret_file: + type: string + endpoint_params: + additionalProperties: + type: string + type: object + proxy_url: + type: string + scopes: + items: + type: string + type: array + tls_config: + x-kubernetes-preserve-unknown-fields: true + token_url: + minLength: 1 + type: string + required: + - client_id + - token_url + type: object + params: + additionalProperties: + items: + type: string + type: array + type: object + path: + type: string + port: + type: string + proxyURL: + type: string + relabelConfigs: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + sampleLimit: + type: integer + scheme: + enum: + - http + - https + - HTTPS + - HTTP + type: string + scrape_interval: + type: string + scrapeTimeout: + type: string + seriesLimit: + type: integer + targetPort: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + tlsConfig: + properties: + ca: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + caFile: + type: string + cert: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + certFile: + type: string + insecureSkipVerify: + type: boolean + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + type: string + type: object + vm_scrape_params: + properties: + disable_compression: + type: boolean + disable_keep_alive: + type: boolean + headers: + items: + type: string + type: array + no_stale_markers: + type: boolean + proxy_client_config: + properties: + basic_auth: + properties: + password: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + password_file: + type: string + username: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearer_token: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + bearer_token_file: + type: string + tls_config: + x-kubernetes-preserve-unknown-fields: true + type: object + scrape_align_interval: + type: string + scrape_offset: + type: string + stream_parse: + type: boolean + type: object + type: object + type: array + jobLabel: + type: string + namespaceSelector: + properties: + any: + type: boolean + matchNames: + items: + type: string + type: array + type: object + podTargetLabels: + items: + type: string + type: array + sampleLimit: + type: integer + scrapeClass: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + seriesLimit: + type: integer + targetLabels: + items: + type: string + type: array + required: + - endpoints + type: object + serviceSpec: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + spec: + properties: + allocateLoadBalancerNodePorts: + type: boolean + clusterIP: + type: string + clusterIPs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + externalIPs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + externalName: + type: string + externalTrafficPolicy: + type: string + healthCheckNodePort: + format: int32 + type: integer + internalTrafficPolicy: + type: string + ipFamilies: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ipFamilyPolicy: + type: string + loadBalancerClass: + type: string + loadBalancerIP: + type: string + loadBalancerSourceRanges: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ports: + items: + properties: + appProtocol: + type: string + name: + type: string + nodePort: + format: int32 + type: integer + port: + format: int32 + type: integer + protocol: + default: TCP + type: string + targetPort: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: array + x-kubernetes-list-map-keys: + - port + - protocol + x-kubernetes-list-type: map + publishNotReadyAddresses: + type: boolean + selector: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: atomic + sessionAffinity: + type: string + sessionAffinityConfig: + properties: + clientIP: + properties: + timeoutSeconds: + format: int32 + type: integer + type: object + type: object + trafficDistribution: + type: string + type: + type: string + type: object + useAsDefault: + type: boolean + required: + - spec + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + unauthorizedAccessConfig: + x-kubernetes-preserve-unknown-fields: true + unauthorizedUserAccessSpec: + properties: + default_url: + items: + type: string + type: array + discover_backend_ips: + type: boolean + drop_src_path_prefix_parts: + type: integer + dump_request_on_errors: + type: boolean + headers: + items: + type: string + type: array + ip_filters: + properties: + allow_list: + items: + type: string + type: array + deny_list: + items: + type: string + type: array + type: object + load_balancing_policy: + enum: + - least_loaded + - first_available + type: string + max_concurrent_requests: + type: integer + metric_labels: + additionalProperties: + type: string + type: object + response_headers: + items: + type: string + type: array + retry_status_codes: + items: + type: integer + type: array + targetRefs: + items: + properties: + crd: + properties: + kind: + enum: + - VMAgent + - VMAlert + - VMSingle + - VLogs + - VMAlertManager + - VMAlertmanager + - VMCluster/vmselect + - VMCluster/vmstorage + - VMCluster/vminsert + - VLSingle + - VLCluster/vlinsert + - VLCluster/vlselect + - VLCluster/vlstorage + - VLAgent + - VTCluster/vtinsert + - VTCluster/vtselect + - VTCluster/vtstorage + - VTSingle + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + - namespace + type: object + discover_backend_ips: + type: boolean + drop_src_path_prefix_parts: + type: integer + headers: + items: + type: string + type: array + hosts: + items: + type: string + type: array + load_balancing_policy: + enum: + - least_loaded + - first_available + type: string + paths: + items: + type: string + type: array + query_args: + items: + properties: + name: + type: string + values: + items: + type: string + type: array + required: + - name + - values + type: object + type: array + response_headers: + items: + type: string + type: array + retry_status_codes: + items: + type: integer + type: array + src_headers: + items: + type: string + type: array + src_query_args: + items: + type: string + type: array + static: + properties: + url: + type: string + urls: + items: + type: string + type: array + type: object + target_path_suffix: + type: string + targetRefBasicAuth: + properties: + password: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + required: + - password + - username + type: object + type: object + type: array + tlsConfig: + properties: + ca: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + caFile: + type: string + cert: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + certFile: + type: string + insecureSkipVerify: + type: boolean + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + type: string + type: object + url_map: + items: + properties: + discover_backend_ips: + type: boolean + drop_src_path_prefix_parts: + type: integer + headers: + items: + type: string + type: array + load_balancing_policy: + enum: + - least_loaded + - first_available + type: string + response_headers: + items: + type: string + type: array + retry_status_codes: + items: + type: integer + type: array + src_headers: + items: + type: string + type: array + src_hosts: + items: + type: string + type: array + src_paths: + items: + type: string + type: array + src_query_args: + items: + type: string + type: array + url_prefix: + x-kubernetes-preserve-unknown-fields: true + type: object + type: array + url_prefix: + x-kubernetes-preserve-unknown-fields: true + type: object + updateStrategy: + enum: + - Recreate + - RollingUpdate + type: string + useDefaultResources: + type: boolean + useProxyProtocol: + type: boolean + useStrictSecurity: + type: boolean + useVMConfigReloader: + type: boolean + userNamespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + userSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + vpa: + properties: + recommenders: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + resourcePolicy: + properties: + containerPolicies: + items: + properties: + containerName: + type: string + controlledResources: + items: + type: string + type: array + controlledValues: + enum: + - RequestsAndLimits + - RequestsOnly + type: string + maxAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + minAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + mode: + enum: + - Auto + - "Off" + type: string + type: object + type: array + type: object + updatePolicy: + properties: + evictionRequirements: + items: + properties: + changeRequirement: + enum: + - TargetHigherThanRequests + - TargetLowerThanRequests + type: string + resources: + items: + type: string + type: array + required: + - changeRequirement + - resources + type: object + type: array + minReplicas: + format: int32 + type: integer + updateMode: + enum: + - "Off" + - Initial + - Recreate + - InPlaceOrRecreate + - Auto + type: string + type: object + type: object + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + zoneCommon: + properties: + readyTimeout: + type: string + remoteWrite: + x-kubernetes-preserve-unknown-fields: true + updatePause: + type: string + vmagent: + properties: + name: + type: string + spec: + properties: + affinity: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + claimTemplates: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + configMaps: + items: + type: string + type: array + containers: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + disableAutomountServiceAccountToken: + type: boolean + disableSelfServiceScrape: + type: boolean + dnsConfig: + properties: + nameservers: + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + dnsPolicy: + type: string + extraArgs: + additionalProperties: + type: string + type: object + extraEnvs: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + extraEnvsFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + host_aliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostNetwork: + type: boolean + image: + properties: + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + license: + properties: + forceOffline: + type: boolean + key: + type: string + keyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + reloadInterval: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + logFormat: + enum: + - default + - json + type: string + logLevel: + enum: + - INFO + - WARN + - ERROR + - FATAL + - PANIC + type: string + managedMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + minReadySeconds: + format: int32 + type: integer + nodeSelector: + additionalProperties: + type: string + type: object + paused: + type: boolean + persistentVolumeClaimRetentionPolicy: + properties: + whenDeleted: + type: string + whenScaled: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + selectorLabels: + additionalProperties: + type: string + type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string + type: object + podMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + port: + type: string + priorityClassName: + type: string + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + remoteWriteSettings: + properties: + flushInterval: + pattern: '[0-9]+(ms|s|m|h)' + type: string + label: + additionalProperties: + type: string + type: object + maxBlockSize: + format: int32 + type: integer + maxDiskUsagePerURL: + x-kubernetes-preserve-unknown-fields: true + queues: + format: int32 + type: integer + showURL: + type: boolean + tmpDataPath: + type: string + useMultiTenantMode: + type: boolean + type: object + replicaCount: + format: int32 + type: integer + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + revisionHistoryLimitCount: + format: int32 + type: integer + rollingUpdate: + properties: + maxSurge: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + runtimeClassName: + type: string + schedulerName: + type: string + secrets: + items: + type: string + type: array + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + serviceAccountName: + type: string + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + statefulMode: + type: boolean + statefulRollingUpdateStrategy: + type: string + statefulRollingUpdateStrategyBehavior: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + statefulStorage: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + volumeClaimTemplate: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + updateStrategy: + enum: + - Recreate + - RollingUpdate + type: string + useDefaultResources: + type: boolean + useStrictSecurity: + type: boolean + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object + type: object + vmcluster: + properties: + name: + type: string + spec: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + zones: + items: + properties: + name: + type: string + remoteWrite: + x-kubernetes-preserve-unknown-fields: true + vmagent: + properties: + name: + type: string + spec: + properties: + affinity: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + claimTemplates: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + configMaps: + items: + type: string + type: array + containers: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + disableAutomountServiceAccountToken: + type: boolean + disableSelfServiceScrape: + type: boolean + dnsConfig: + properties: + nameservers: + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + dnsPolicy: + type: string + extraArgs: + additionalProperties: + type: string + type: object + extraEnvs: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + extraEnvsFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + host_aliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostNetwork: + type: boolean + image: + properties: + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + stopSignal: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + restartPolicyRules: + items: + properties: + action: + type: string + exitCodes: + properties: + operator: + type: string + values: + items: + format: int32 + type: integer + type: array + x-kubernetes-list-type: set + required: + - operator + type: object + required: + - action + type: object + type: array + x-kubernetes-list-type: atomic + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + license: + properties: + forceOffline: + type: boolean + key: + type: string + keyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + reloadInterval: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + logFormat: + enum: + - default + - json + type: string + logLevel: + enum: + - INFO + - WARN + - ERROR + - FATAL + - PANIC + type: string + managedMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + minReadySeconds: + format: int32 + type: integer + nodeSelector: + additionalProperties: + type: string + type: object + paused: + type: boolean + persistentVolumeClaimRetentionPolicy: + properties: + whenDeleted: + type: string + whenScaled: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + selectorLabels: + additionalProperties: + type: string + type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string + type: object + podMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + port: + type: string + priorityClassName: + type: string + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + remoteWriteSettings: + properties: + flushInterval: + pattern: '[0-9]+(ms|s|m|h)' + type: string + label: + additionalProperties: + type: string + type: object + maxBlockSize: + format: int32 + type: integer + maxDiskUsagePerURL: + x-kubernetes-preserve-unknown-fields: true + queues: + format: int32 + type: integer + showURL: + type: boolean + tmpDataPath: + type: string + useMultiTenantMode: + type: boolean + type: object + replicaCount: + format: int32 + type: integer + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + revisionHistoryLimitCount: + format: int32 + type: integer + rollingUpdate: + properties: + maxSurge: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + runtimeClassName: + type: string + schedulerName: + type: string + secrets: + items: + type: string + type: array + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxChangePolicy: + type: string + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + type: string + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + serviceAccountName: + type: string + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + default: "" + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + statefulMode: + type: boolean + statefulRollingUpdateStrategy: + type: string + statefulRollingUpdateStrategyBehavior: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + statefulStorage: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + volumeClaimTemplate: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + updateStrategy: + enum: + - Recreate + - RollingUpdate + type: string + useDefaultResources: + type: boolean + useStrictSecurity: + type: boolean + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + default: ext4 + type: string + kind: + type: string + readOnly: + default: false + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + image: + properties: + pullPolicy: + type: string + reference: + type: string + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + default: default + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podCertificate: + properties: + certificateChainPath: + type: string + credentialBundlePath: + type: string + keyPath: + type: string + keyType: + type: string + maxExpirationSeconds: + format: int32 + type: integer + signerName: + type: string + required: + - keyType + - signerName + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + default: /etc/ceph/keyring + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + default: rbd + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + default: admin + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + default: xfs + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + default: ThinProvisioned + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object + type: object + vmcluster: + properties: + name: + type: string + spec: + x-kubernetes-preserve-unknown-fields: true + type: object + required: + - name + type: object + type: array + type: object + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + maxLength: 32768 + type: string + observedGeneration: + format: int64 + minimum: 0 + type: integer + reason: + maxLength: 1024 + minLength: 1 + type: string + status: + enum: + - "True" + - "False" + - Unknown + type: string + type: + maxLength: 316 + type: string + required: + - lastTransitionTime + - lastUpdateTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + format: int64 + type: integer + reason: + type: string + updateStatus: + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.0 name: vmnodescrapes.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -20779,121 +29850,60 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: |- - VMNodeScrape defines discovery for targets placed on kubernetes nodes, - usually its node-exporters and other host services. - InternalIP is used as __address__ for scraping. 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: VMNodeScrapeSpec defines specification for VMNodeScrape. properties: authorization: - description: Authorization with http header Authorization properties: credentials: - description: Reference to the secret with value for authorization properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to bearer type: string type: object basicAuth: - description: BasicAuth allow an endpoint to authenticate over basic - authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key @@ -20901,181 +29911,94 @@ spec: x-kubernetes-map-type: atomic type: object bearerTokenFile: - description: File to read bearer token for scraping targets. type: string bearerTokenSecret: - description: |- - Secret to mount to read bearer token for scraping targets. The secret - needs to be in the same namespace as the scrape object and accessible by - the victoria-metrics operator. nullable: true properties: key: - description: The key of the secret to select from. Must be a - valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic follow_redirects: - description: FollowRedirects controls redirects for scraping. type: boolean honorLabels: - description: HonorLabels chooses the metric's labels on collisions - with target labels. type: boolean honorTimestamps: - description: HonorTimestamps controls whether vmagent respects the - timestamps present in scraped data. type: boolean interval: - description: Interval at which metrics should be scraped type: string jobLabel: - description: The label to use to retrieve the job name from. type: string max_scrape_size: - description: MaxScrapeSize defines a maximum size of scraped data - for a job type: string metricRelabelConfigs: - description: MetricRelabelConfigs to apply to samples after scrapping. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. Default - is 'replace' type: string if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source label - values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source label - values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array oauth2: - description: OAuth2 defines auth configuration properties: client_id: - description: The secret or configmap containing the OAuth2 client - id properties: configMap: - description: ConfigMap containing data to use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -21083,56 +30006,33 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 client secret properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for client secret file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: @@ -21144,101 +30044,52 @@ spec: items: type: string type: array - description: Optional HTTP URL parameters type: object path: - description: HTTP path to scrape for metrics. type: string port: - description: Name of the port exposed at Node. type: string proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes to - proxy through this endpoint. type: string relabelConfigs: - description: RelabelConfigs to apply to samples during service discovery. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. Default - is 'replace' type: string if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source label - values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source label - values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array sampleLimit: - description: SampleLimit defines per-scrape limit on number of scraped - samples that will be accepted. - format: int64 type: integer scheme: - description: HTTP scheme to use for scraping. enum: - http - https @@ -21246,39 +30097,21 @@ spec: - HTTP type: string scrape_interval: - description: |- - ScrapeInterval is the same as Interval and has priority over it. - one of scrape_interval or interval can be used + type: string + scrapeClass: type: string scrapeTimeout: - description: Timeout after which the scrape is ended type: string selector: - description: Selector to select kubernetes Nodes. 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 @@ -21292,73 +30125,40 @@ spec: 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 seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 type: integer targetLabels: - description: TargetLabels transfers labels on the Kubernetes Node - onto the target. items: type: string type: array tlsConfig: - description: TLSConfig configuration to use when scraping the endpoint properties: ca: - description: Struct containing the CA cert to use for the targets. properties: configMap: - description: ConfigMap containing data to use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -21366,54 +30166,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container to use for the - targets. type: string cert: - description: Struct containing the client cert file for the targets. properties: configMap: - description: ConfigMap containing data to use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -21421,131 +30197,66 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container for - the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container for - the targets. type: string keySecret: - description: Secret containing the client key file for the targets. properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object vm_scrape_params: - description: VMScrapeParams defines VictoriaMetrics specific scrape - parameters properties: disable_compression: - description: DisableCompression type: boolean disable_keep_alive: - description: |- - disable_keepalive allows disabling HTTP keep-alive when scraping targets. - By default, HTTP keep-alive is enabled, so TCP connections to scrape targets - could be reused. - See https://docs.victoriametrics.com/vmagent#scrape_config-enhancements type: boolean headers: - description: |- - Headers allows sending custom headers to scrape targets - must be in of semicolon separated header with it's value - eg: - headerName: headerValue - vmagent supports since 1.79.0 version items: type: string type: array no_stale_markers: type: boolean proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See feature description https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy properties: basic_auth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -21553,24 +30264,13 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token: - description: SecretKeySelector selects a key of a Secret. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -21590,58 +30290,34 @@ spec: type: object type: object status: - description: ScrapeObjectStatus defines the observed state of ScrapeObjects properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -21656,16 +30332,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -21678,7 +30349,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmpodscrapes.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -21702,165 +30373,88 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: |- - VMPodScrape is scrape configuration for pods, - it generates vmagent's config for scraping pod targets - based on selectors. 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: VMPodScrapeSpec defines the desired state of VMPodScrape properties: attach_metadata: - description: AttachMetadata configures metadata attaching from service - discovery properties: + namespace: + type: boolean node: - description: |- - Node instructs vmagent to add node specific metadata from service discovery - Valid for roles: pod, endpoints, endpointslice. type: boolean type: object jobLabel: - description: The label to use to retrieve the job name from. type: string namespaceSelector: - description: Selector to select which namespaces the Endpoints objects - are discovered from. properties: any: - description: |- - Boolean describing whether all namespaces are selected in contrast to a - list restricting them. type: boolean matchNames: - description: List of namespace names. items: type: string type: array type: object podMetricsEndpoints: - description: A list of endpoints allowed as part of this PodMonitor. items: - description: PodMetricsEndpoint defines a scrapeable endpoint of - a Kubernetes Pod serving metrics. properties: attach_metadata: - description: AttachMetadata configures metadata attaching from - service discovery properties: + namespace: + type: boolean node: - description: |- - Node instructs vmagent to add node specific metadata from service discovery - Valid for roles: pod, endpoints, endpointslice. type: boolean type: object authorization: - description: Authorization with http header Authorization properties: credentials: - description: Reference to the secret with value for authorization properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to bearer type: string type: object basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -21868,187 +30462,94 @@ spec: x-kubernetes-map-type: atomic type: object bearerTokenFile: - description: File to read bearer token for scraping targets. type: string bearerTokenSecret: - description: |- - Secret to mount to read bearer token for scraping targets. The secret - needs to be in the same namespace as the scrape object and accessible by - the victoria-metrics operator. nullable: true properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic filterRunning: - description: |- - FilterRunning applies filter with pod status == running - it prevents from scrapping metrics at failed or succeed state pods. - enabled by default type: boolean follow_redirects: - description: FollowRedirects controls redirects for scraping. type: boolean honorLabels: - description: HonorLabels chooses the metric's labels on collisions - with target labels. type: boolean honorTimestamps: - description: HonorTimestamps controls whether vmagent respects - the timestamps present in scraped data. type: boolean interval: - description: Interval at which metrics should be scraped type: string max_scrape_size: - description: MaxScrapeSize defines a maximum size of scraped - data for a job type: string metricRelabelConfigs: - description: MetricRelabelConfigs to apply to samples after - scrapping. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. - Default is 'replace' type: string if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source - label values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source - label values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array oauth2: - description: OAuth2 defines auth configuration properties: client_id: - description: The secret or configmap containing the OAuth2 - client id properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -22056,57 +30557,33 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 client secret properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for client secret - file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: @@ -22118,109 +30595,57 @@ spec: items: type: string type: array - description: Optional HTTP URL parameters type: object path: - description: HTTP path to scrape for metrics. type: string port: - description: Name of the port exposed at Pod. type: string portNumber: - description: PortNumber defines the `Pod` port number which - exposes the endpoint. format: int32 maximum: 65535 minimum: 1 type: integer proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes - to proxy through this endpoint. type: string relabelConfigs: - description: RelabelConfigs to apply to samples during service - discovery. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. - Default is 'replace' type: string if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source - label values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source - label values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array sampleLimit: - description: SampleLimit defines per-scrape limit on number - of scraped samples that will be accepted. - format: int64 type: integer scheme: - description: HTTP scheme to use for scraping. enum: - http - https @@ -22228,78 +30653,41 @@ spec: - HTTP type: string scrape_interval: - description: |- - ScrapeInterval is the same as Interval and has priority over it. - one of scrape_interval or interval can be used type: string scrapeTimeout: - description: Timeout after which the scrape is ended type: string seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 type: integer targetPort: anyOf: - type: integer - type: string - description: |- - TargetPort defines name or number of the pod port this endpoint refers to. - Mutually exclusive with Port and PortNumber. x-kubernetes-int-or-string: true tlsConfig: - description: TLSConfig configuration to use when scraping the - endpoint properties: ca: - description: Struct containing the CA cert to use for the - targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -22307,56 +30695,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container to use - for the targets. type: string cert: - description: Struct containing the client cert file for - the targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -22364,132 +30726,66 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container - for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container - for the targets. type: string keySecret: - description: Secret containing the client key file for the - targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object vm_scrape_params: - description: VMScrapeParams defines VictoriaMetrics specific - scrape parameters properties: disable_compression: - description: DisableCompression type: boolean disable_keep_alive: - description: |- - disable_keepalive allows disabling HTTP keep-alive when scraping targets. - By default, HTTP keep-alive is enabled, so TCP connections to scrape targets - could be reused. - See https://docs.victoriametrics.com/vmagent#scrape_config-enhancements type: boolean headers: - description: |- - Headers allows sending custom headers to scrape targets - must be in of semicolon separated header with it's value - eg: - headerName: headerValue - vmagent supports since 1.79.0 version items: type: string type: array no_stale_markers: type: boolean proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See feature description https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy properties: basic_auth: - description: BasicAuth allow an endpoint to authenticate - over basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key @@ -22497,24 +30793,13 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token: - description: SecretKeySelector selects a key of a Secret. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -22535,42 +30820,23 @@ spec: type: object type: array podTargetLabels: - description: PodTargetLabels transfers labels on the Kubernetes Pod - onto the target. items: type: string type: array sampleLimit: - description: SampleLimit defines per-scrape limit on number of scraped - samples that will be accepted. - format: int64 type: integer + scrapeClass: + type: string selector: - description: Selector to select Pod objects. 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 @@ -22584,75 +30850,43 @@ spec: 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 seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 type: integer required: - podMetricsEndpoints type: object status: - description: ScrapeObjectStatus defines the observed state of ScrapeObjects properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -22667,16 +30901,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -22689,7 +30918,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmprobes.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -22713,121 +30942,60 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: |- - VMProbe defines a probe for targets, that will be executed with prober, - like blackbox exporter. - It helps to monitor reachability of target with various checks. 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: VMProbeSpec contains specification parameters for a Probe. properties: authorization: - description: Authorization with http header Authorization properties: credentials: - description: Reference to the secret with value for authorization properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to bearer type: string type: object basicAuth: - description: BasicAuth allow an endpoint to authenticate over basic - authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key @@ -22835,187 +31003,96 @@ spec: x-kubernetes-map-type: atomic type: object bearerTokenFile: - description: File to read bearer token for scraping targets. type: string bearerTokenSecret: - description: |- - Secret to mount to read bearer token for scraping targets. The secret - needs to be in the same namespace as the scrape object and accessible by - the victoria-metrics operator. nullable: true properties: key: - description: The key of the secret to select from. Must be a - valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic follow_redirects: - description: FollowRedirects controls redirects for scraping. type: boolean honorLabels: - description: HonorLabels chooses the metric's labels on collisions - with target labels. type: boolean honorTimestamps: - description: HonorTimestamps controls whether vmagent respects the - timestamps present in scraped data. type: boolean interval: - description: Interval at which metrics should be scraped type: string jobName: - description: The job name assigned to scraped metrics by default. type: string max_scrape_size: - description: MaxScrapeSize defines a maximum size of scraped data - for a job type: string metricRelabelConfigs: - description: MetricRelabelConfigs to apply to samples after scrapping. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. Default - is 'replace' type: string if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source label - values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source label - values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array module: - description: |- - The module to use for probing specifying how to probe the target. - Example module configuring in the blackbox exporter: - https://github.com/prometheus/blackbox_exporter/blob/master/example.yml type: string oauth2: - description: OAuth2 defines auth configuration properties: client_id: - description: The secret or configmap containing the OAuth2 client - id properties: configMap: - description: ConfigMap containing data to use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -23023,56 +31100,33 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 client secret properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for client secret file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: @@ -23084,22 +31138,14 @@ spec: items: type: string type: array - description: Optional HTTP URL parameters type: object path: - description: HTTP path to scrape for metrics. type: string proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes to - proxy through this endpoint. type: string sampleLimit: - description: SampleLimit defines per-scrape limit on number of scraped - samples that will be accepted. - format: int64 type: integer scheme: - description: HTTP scheme to use for scraping. enum: - http - https @@ -23107,144 +31153,79 @@ spec: - HTTP type: string scrape_interval: - description: |- - ScrapeInterval is the same as Interval and has priority over it. - one of scrape_interval or interval can be used + type: string + scrapeClass: type: string scrapeTimeout: - description: Timeout after which the scrape is ended type: string seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 type: integer targets: - description: Targets defines a set of static and/or dynamically discovered - targets to be probed using the prober. properties: ingress: - description: Ingress defines the set of dynamically discovered - ingress objects which hosts are considered for probing. properties: namespaceSelector: - description: Select Ingress objects by namespace. properties: any: - description: |- - Boolean describing whether all namespaces are selected in contrast to a - list restricting them. type: boolean matchNames: - description: List of namespace names. items: type: string type: array type: object relabelingConfigs: - description: RelabelConfigs to apply to samples during service - discovery. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. - Default is 'replace' type: string if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for - `action: graphite`' type: object match: - description: 'Match is used together with Labels for - `action: graphite`' type: string modulus: - description: Modulus to take of the hash of the source - label values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source - label values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array + role: + enum: + - service + - ingress + - pod + - node + type: string selector: - description: Select Ingress objects by labels. 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 @@ -23258,104 +31239,185 @@ spec: 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 - staticConfig: - description: StaticConfig defines static targets which are considers - for probing. + kubernetes: + items: + properties: + namespaceSelector: + properties: + any: + type: boolean + matchNames: + items: + type: string + type: array + type: object + relabelingConfigs: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + role: + enum: + - service + - ingress + - pod + - node + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + type: object + type: array + static: + properties: + labels: + additionalProperties: + type: string + type: object + relabelingConfigs: + items: + properties: + action: + type: string + if: + x-kubernetes-preserve-unknown-fields: true + labels: + additionalProperties: + type: string + type: object + match: + type: string + modulus: + format: int64 + type: integer + regex: + x-kubernetes-preserve-unknown-fields: true + replacement: + type: string + separator: + type: string + source_labels: + items: + type: string + type: array + sourceLabels: + items: + type: string + type: array + target_label: + type: string + targetLabel: + type: string + type: object + type: array + targets: + items: + type: string + type: array + required: + - targets + type: object + staticConfig: properties: labels: additionalProperties: type: string - description: Labels assigned to all metrics scraped from the - targets. type: object relabelingConfigs: - description: RelabelConfigs to apply to samples during service - discovery. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. - Default is 'replace' type: string if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for - `action: graphite`' type: object match: - description: 'Match is used together with Labels for - `action: graphite`' type: string modulus: - description: Modulus to take of the hash of the source - label values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source - label values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array targets: - description: Targets is a list of URLs to probe using the - configured prober. items: type: string type: array @@ -23364,53 +31426,30 @@ spec: type: object type: object tlsConfig: - description: TLSConfig configuration to use when scraping the endpoint properties: ca: - description: Struct containing the CA cert to use for the targets. properties: configMap: - description: ConfigMap containing data to use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -23418,54 +31457,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container to use for the - targets. type: string cert: - description: Struct containing the client cert file for the targets. properties: configMap: - description: ConfigMap containing data to use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -23473,131 +31488,66 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container for - the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container for - the targets. type: string keySecret: - description: Secret containing the client key file for the targets. properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object vm_scrape_params: - description: VMScrapeParams defines VictoriaMetrics specific scrape - parameters properties: disable_compression: - description: DisableCompression type: boolean disable_keep_alive: - description: |- - disable_keepalive allows disabling HTTP keep-alive when scraping targets. - By default, HTTP keep-alive is enabled, so TCP connections to scrape targets - could be reused. - See https://docs.victoriametrics.com/vmagent#scrape_config-enhancements type: boolean headers: - description: |- - Headers allows sending custom headers to scrape targets - must be in of semicolon separated header with it's value - eg: - headerName: headerValue - vmagent supports since 1.79.0 version items: type: string type: array no_stale_markers: type: boolean proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See feature description https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy properties: basic_auth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -23605,24 +31555,13 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token: - description: SecretKeySelector selects a key of a Secret. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -23641,25 +31580,15 @@ spec: type: boolean type: object vmProberSpec: - description: |- - Specification for the prober to use for probing targets. - The prober.URL parameter is required. Targets cannot be probed if left empty. properties: path: - description: |- - Path to collect metrics from. - Defaults to `/probe`. type: string scheme: - description: |- - HTTP scheme to use for scraping. - Defaults to `http`. enum: - http - https type: string url: - description: Mandatory URL of the prober. type: string required: - url @@ -23668,58 +31597,34 @@ spec: - vmProberSpec type: object status: - description: ScrapeObjectStatus defines the observed state of ScrapeObjects properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -23734,16 +31639,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object required: @@ -23758,7 +31658,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmrules.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -23782,103 +31682,41 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMRule defines rule records for vmalert application 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: VMRuleSpec defines the desired state of VMRule properties: groups: - description: Groups list of group rules items: - description: RuleGroup is a list of sequentially evaluated recording - and alerting rules. properties: concurrency: - description: Concurrency defines how many rules execute at once. type: integer eval_alignment: - description: |- - Optional - The evaluation timestamp will be aligned with group's interval, - instead of using the actual timestamp that evaluation happens at. - It is enabled by default to get more predictable results - and to visually align with graphs plotted via Grafana or vmui. type: boolean eval_delay: - description: |- - Optional - Adjust the `time` parameter of group evaluation requests to compensate intentional query delay from the datasource. type: string eval_offset: - description: |- - Optional - Group will be evaluated at the exact offset in the range of [0...interval]. type: string - extra_filter_labels: - additionalProperties: - type: string - description: |- - ExtraFilterLabels optional list of label filters applied to every rule's - request within a group. Is compatible only with VM datasource. - See more details [here](https://docs.victoriametrics.com/#prometheus-querying-api-enhancements) - Deprecated, use params instead - type: object headers: - description: |- - Headers contains optional HTTP headers added to each rule request - Must be in form `header-name: value` - For example: - headers: - - "CustomHeader: foo" - - "CustomHeader2: bar" items: type: string type: array interval: - description: evaluation interval for group type: string labels: additionalProperties: type: string - description: |- - Labels optional list of labels added to every rule within a group. - It has priority over the external labels. - Labels are commonly used for adding environment - or tenant-specific tag. type: object limit: - description: |- - Limit the number of alerts an alerting rule and series a recording - rule can produce type: integer name: - description: Name of group type: string notifier_headers: - description: |- - NotifierHeaders contains optional HTTP headers added to each alert request which will send to notifier - Must be in form `header-name: value` - For example: - headers: - - "CustomHeader: foo" - - "CustomHeader2: bar" items: type: string type: array @@ -23887,67 +31725,37 @@ spec: items: type: string type: array - description: Params optional HTTP URL parameters added to each - rule request type: object rules: - description: Rules list of alert rules items: - description: Rule describes an alerting or recording rule. properties: alert: - description: Alert is a name for alert type: string annotations: additionalProperties: type: string - description: Annotations will be added to rule configuration type: object debug: - description: |- - Debug enables logging for rule - it useful for tracking type: boolean expr: - description: Expr is query, that will be evaluated at - dataSource type: string for: - description: |- - For evaluation interval in time.Duration format - 30s, 1m, 1h or nanoseconds type: string keep_firing_for: - description: |- - KeepFiringFor will make alert continue firing for this long - even when the alerting expression no longer has results. - Use time.Duration format, 30s, 1m, 1h or nanoseconds type: string labels: additionalProperties: type: string - description: Labels will be added to rule configuration type: object record: - description: Record represents a query, that will be recorded - to dataSource type: string update_entries_limit: - description: |- - UpdateEntriesLimit defines max number of rule's state updates stored in memory. - Overrides `-rule.updateEntriesLimit` in vmalert. type: integer type: object type: array tenant: - description: |- - Tenant id for group, can be used only with enterprise version of vmalert. - See more details [here](https://docs.victoriametrics.com/vmalert#multitenancy). type: string type: - description: |- - Type defines datasource type for enterprise version of vmalert - possible values - prometheus,graphite,vlogs type: string required: - name @@ -23958,58 +31766,34 @@ spec: - groups type: object status: - description: VMRuleStatus defines the observed state of VMRule properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -24024,16 +31808,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object required: @@ -24048,7 +31827,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmscrapeconfigs.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -24072,188 +31851,98 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMScrapeConfig specifies a set of targets and parameters describing - how to scrape them. 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: VMScrapeConfigSpec defines the desired state of VMScrapeConfig properties: authorization: - description: Authorization with http header Authorization properties: credentials: - description: Reference to the secret with value for authorization properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to bearer type: string type: object azureSDConfigs: - description: AzureSDConfigs defines a list of Azure service discovery - configurations. items: - description: |- - AzureSDConfig allow retrieving scrape targets from Azure VMs. - See [here](https://docs.victoriametrics.com/sd_configs#azure_sd_configs) properties: authenticationMethod: - description: |- - # The authentication method, either OAuth or ManagedIdentity. - See https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview enum: - OAuth - ManagedIdentity type: string clientID: - description: Optional client ID. Only required with the OAuth - authentication method. type: string clientSecret: - description: Optional client secret. Only required with the - OAuth authentication method. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic environment: - description: The Azure environment. type: string port: - description: |- - The port to scrape metrics from. If using the public IP address, this must - instead be specified in the relabeling rule. type: integer resourceGroup: - description: Optional resource group name. Limits discovery - to this resource group. type: string subscriptionID: - description: The subscription ID. Always required. minLength: 1 type: string tenantID: - description: Optional tenant ID. Only required with the OAuth - authentication method. type: string required: - subscriptionID type: object type: array basicAuth: - description: BasicAuth allow an endpoint to authenticate over basic - authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key @@ -24261,137 +31950,71 @@ spec: x-kubernetes-map-type: atomic type: object bearerTokenFile: - description: File to read bearer token for scraping targets. type: string bearerTokenSecret: - description: |- - Secret to mount to read bearer token for scraping targets. The secret - needs to be in the same namespace as the scrape object and accessible by - the victoria-metrics operator. nullable: true properties: key: - description: The key of the secret to select from. Must be a - valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic consulSDConfigs: - description: ConsulSDConfigs defines a list of Consul service discovery - configurations. items: - description: |- - ConsulSDConfig defines a Consul service discovery configuration. - See [here](https://docs.victoriametrics.com/sd_configs/#consul_sd_configs) properties: allowStale: - description: |- - Allow stale Consul results (see https://developer.hashicorp.com/consul/api-docs/features/consistency). Will reduce load on Consul. - If unset, use its default value. type: boolean authorization: - description: Authorization header to use on every scrape request. properties: credentials: - description: Reference to the secret with value for authorization properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to bearer type: string type: object basicAuth: - description: BasicAuth information to use on every scrape request. properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -24399,79 +32022,43 @@ spec: x-kubernetes-map-type: atomic type: object datacenter: - description: Consul Datacenter name, if not provided it will - use the local Consul Agent Datacenter. type: string filter: - description: |- - Filter defines filter for /v1/catalog/services requests - See https://developer.hashicorp.com/consul/api-docs/features/filtering type: string followRedirects: - description: |- - Configure whether HTTP requests follow HTTP 3xx redirects. - If unset, use its default value. type: boolean namespace: - description: Namespaces are only supported in Consul Enterprise. type: string nodeMeta: additionalProperties: type: string - description: Node metadata key/value pairs to filter nodes for - a given service. type: object x-kubernetes-map-type: atomic oauth2: - description: OAuth2 defines auth configuration properties: client_id: - description: The secret or configmap containing the OAuth2 - client id properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -24479,57 +32066,33 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 client secret properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for client secret - file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: @@ -24537,69 +32100,34 @@ spec: - token_url type: object partition: - description: Admin Partitions are only supported in Consul Enterprise. type: string proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See [feature description](https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy) properties: basic_auth: - description: BasicAuth allow an endpoint to authenticate - over basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -24607,24 +32135,13 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token: - description: SecretKeySelector selects a key of a Secret. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -24636,89 +32153,52 @@ spec: x-kubernetes-preserve-unknown-fields: true type: object proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes - to proxy through this endpoint. type: string scheme: - description: HTTP Scheme default "http" enum: - HTTP - HTTPS type: string server: - description: A valid string consisting of a hostname or IP followed - by an optional port number. minLength: 1 type: string services: - description: A list of services for which targets are retrieved. - If omitted, all services are scraped. items: type: string type: array x-kubernetes-list-type: atomic tagSeparator: - description: |- - The string by which Consul tags are joined into the tag label. - If unset, use its default value. type: string tags: - description: An optional list of tags used to filter nodes for - a given service. Services must contain all tags in the list. items: type: string type: array x-kubernetes-list-type: atomic tlsConfig: - description: TLS configuration to use on every scrape request properties: ca: - description: Struct containing the CA cert to use for the - targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -24726,56 +32206,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container to use - for the targets. type: string cert: - description: Struct containing the client cert file for - the targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -24783,65 +32237,35 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container - for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container - for the targets. type: string keySecret: - description: Secret containing the client key file for the - targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object tokenRef: - description: Consul ACL TokenRef, if not provided it will use - the ACL from the local Consul Agent. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -24852,102 +32276,55 @@ spec: type: object type: array digitalOceanSDConfigs: - description: DigitalOceanSDConfigs defines a list of DigitalOcean - service discovery configurations. items: - description: |- - DigitalOceanSDConfig allow retrieving scrape targets from DigitalOcean's Droplets API. - This service discovery uses the public IPv4 address by default, by that can be changed with relabeling. - See [here](https://docs.victoriametrics.com/sd_configs#digitalocean_sd_configs) properties: authorization: - description: Authorization header to use on every scrape request. properties: credentials: - description: Reference to the secret with value for authorization properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to bearer type: string type: object followRedirects: - description: Configure whether HTTP requests follow HTTP 3xx - redirects. type: boolean oauth2: - description: OAuth2 defines auth configuration properties: client_id: - description: The secret or configmap containing the OAuth2 - client id properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -24955,57 +32332,33 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 client secret properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for client secret - file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: @@ -25013,69 +32366,34 @@ spec: - token_url type: object port: - description: The port to scrape metrics from. type: integer proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See [feature description](https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy) properties: basic_auth: - description: BasicAuth allow an endpoint to authenticate - over basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -25083,24 +32401,13 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token: - description: SecretKeySelector selects a key of a Secret. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -25112,59 +32419,32 @@ spec: x-kubernetes-preserve-unknown-fields: true type: object proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes - to proxy through this endpoint. type: string tlsConfig: - description: TLS configuration to use on every scrape request properties: ca: - description: Struct containing the CA cert to use for the - targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -25172,56 +32452,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container to use - for the targets. type: string cert: - description: Struct containing the client cert file for - the targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -25229,66 +32483,38 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container - for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container - for the targets. type: string keySecret: - description: Secret containing the client key file for the - targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object type: object type: array dnsSDConfigs: - description: DNSSDConfigs defines a list of DNS service discovery - configurations. items: - description: |- - DNSSDConfig allows specifying a set of DNS domain names which are periodically queried to discover a list of targets. - The DNS servers to be contacted are read from /etc/resolv.conf. - See [here](https://docs.victoriametrics.com/sd_configs#dns_sd_configs) properties: names: - description: A list of DNS domain names to be queried. items: type: string minItems: 1 type: array port: - description: |- - The port number used if the query type is not SRV - Ignored for SRV records type: integer type: enum: @@ -25302,48 +32528,23 @@ spec: type: object type: array ec2SDConfigs: - description: EC2SDConfigs defines a list of EC2 service discovery - configurations. items: - description: |- - EC2SDConfig allow retrieving scrape targets from AWS EC2 instances. - The private IP address is used by default, but may be changed to the public IP address with relabeling. - The IAM credentials used must have the ec2:DescribeInstances permission to discover scrape targets. - See [here](https://docs.victoriametrics.com/sd_configs#ec2_sd_configs) properties: accessKey: - description: AccessKey is the AWS API key. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic filters: - description: |- - Filters can be used optionally to filter the instance list by other criteria. - Available filter criteria can be found here: - https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstances.html - Filter API documentation: https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_Filter.html items: - description: EC2Filter is the configuration for filtering - EC2 instances. properties: name: type: string @@ -25357,35 +32558,19 @@ spec: type: object type: array port: - description: |- - The port to scrape metrics from. If using the public IP address, this must - instead be specified in the relabeling rule. type: integer region: - description: The AWS region type: string roleARN: - description: AWS Role ARN, an alternative to using AWS API keys. type: string secretKey: - description: SecretKey is the AWS API secret. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -25394,15 +32579,9 @@ spec: type: object type: array fileSDConfigs: - description: FileSDConfigs defines a list of file service discovery - configurations. items: - description: |- - FileSDConfig defines a file service discovery configuration. - See [here](https://docs.victoriametrics.com/sd_configs#file_sd_configs) properties: files: - description: List of files to be used for file discovery. items: type: string minItems: 1 @@ -25412,44 +32591,20 @@ spec: type: object type: array follow_redirects: - description: FollowRedirects controls redirects for scraping. type: boolean gceSDConfigs: - description: GCESDConfigs defines a list of GCE service discovery - configurations. items: - description: |- - GCESDConfig configures scrape targets from GCP GCE instances. - The private IP address is used by default, but may be changed to - the public IP address with relabeling. - See [here](https://docs.victoriametrics.com/sd_configs#gce_sd_configs) - - The GCE service discovery will load the Google Cloud credentials - from the file specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable. - See https://cloud.google.com/kubernetes-engine/docs/tutorials/authenticating-to-cloud-platform properties: filter: - description: |- - Filter can be used optionally to filter the instance list by other criteria - Syntax of this filter is described in the filter query parameter section: - https://cloud.google.com/compute/docs/reference/latest/instances/list type: string port: - description: |- - The port to scrape metrics from. If using the public IP address, this must - instead be specified in the relabeling rule. type: integer project: - description: The Google Cloud Project ID minLength: 1 type: string tagSeparator: - description: The tag separator is used to separate the tags - on concatenation type: string zone: - description: The zone of the scrape targets. If you need multiple - zones use multiple GCESDConfigs. x-kubernetes-preserve-unknown-fields: true required: - project @@ -25457,110 +32612,57 @@ spec: type: object type: array honorLabels: - description: HonorLabels chooses the metric's labels on collisions - with target labels. type: boolean honorTimestamps: - description: HonorTimestamps controls whether vmagent respects the - timestamps present in scraped data. type: boolean httpSDConfigs: - description: HTTPSDConfigs defines a list of HTTP service discovery - configurations. items: - description: |- - HTTPSDConfig defines a HTTP service discovery configuration. - See [here](https://docs.victoriametrics.com/sd_configs#http_sd_configs) properties: authorization: - description: Authorization header to use on every scrape request. properties: credentials: - description: Reference to the secret with value for authorization properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to bearer type: string type: object basicAuth: - description: BasicAuth information to use on every scrape request. properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -25568,66 +32670,32 @@ spec: x-kubernetes-map-type: atomic type: object proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See [feature description](https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy) properties: basic_auth: - description: BasicAuth allow an endpoint to authenticate - over basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -25635,24 +32703,13 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token: - description: SecretKeySelector selects a key of a Secret. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -25664,59 +32721,32 @@ spec: x-kubernetes-preserve-unknown-fields: true type: object proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes - to proxy through this endpoint. type: string tlsConfig: - description: TLS configuration to use on every scrape request properties: ca: - description: Struct containing the CA cert to use for the - targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -25724,56 +32754,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container to use - for the targets. type: string cert: - description: Struct containing the client cert file for - the targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -25781,47 +32785,28 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container - for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container - for the targets. type: string keySecret: - description: Secret containing the client key file for the - targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object url: - description: URL from which the targets are fetched. minLength: 1 pattern: ^http(s)?://.+$ type: string @@ -25830,123 +32815,64 @@ spec: type: object type: array interval: - description: Interval at which metrics should be scraped type: string kubernetesSDConfigs: - description: KubernetesSDConfigs defines a list of Kubernetes service - discovery configurations. items: - description: |- - KubernetesSDConfig allows retrieving scrape targets from Kubernetes' REST API. - See [here](https://docs.victoriametrics.com/sd_configs#kubernetes_sd_configs) properties: apiServer: - description: |- - The API server address consisting of a hostname or IP address followed - by an optional port number. - If left empty, assuming process is running inside - of the cluster. It will discover API servers automatically and use the pod's - CA certificate and bearer token file at /var/run/secrets/kubernetes.io/serviceaccount/. type: string attach_metadata: - description: AttachMetadata configures metadata attaching from - service discovery properties: + namespace: + type: boolean node: - description: |- - Node instructs vmagent to add node specific metadata from service discovery - Valid for roles: pod, endpoints, endpointslice. type: boolean type: object authorization: - description: Authorization header to use on every scrape request. properties: credentials: - description: Reference to the secret with value for authorization properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to bearer type: string type: object basicAuth: - description: BasicAuth information to use on every scrape request. properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -25954,75 +32880,41 @@ spec: x-kubernetes-map-type: atomic type: object followRedirects: - description: Configure whether HTTP requests follow HTTP 3xx - redirects. type: boolean namespaces: - description: Optional namespace discovery. If omitted, discover - targets across all namespaces. properties: names: - description: |- - List of namespaces where to watch for resources. - If empty and `ownNamespace` isn't true, watch for resources in all namespaces. items: type: string type: array ownNamespace: - description: Includes the namespace in which the pod exists - to the list of watched namespaces. type: boolean type: object oauth2: - description: OAuth2 defines auth configuration properties: client_id: - description: The secret or configmap containing the OAuth2 - client id properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -26030,57 +32922,33 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 client secret properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for client secret - file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: @@ -26088,66 +32956,32 @@ spec: - token_url type: object proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See [feature description](https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy) properties: basic_auth: - description: BasicAuth allow an endpoint to authenticate - over basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -26155,24 +32989,13 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token: - description: SecretKeySelector selects a key of a Secret. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -26184,23 +33007,31 @@ spec: x-kubernetes-preserve-unknown-fields: true type: object proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes - to proxy through this endpoint. type: string role: - description: Role of the Kubernetes entities that should be - discovered. + enum: + - node + - pod + - service + - endpoints + - endpointslice + - ingress type: string selectors: - description: Selector to select objects. items: - description: K8SSelectorConfig is Kubernetes Selector Config properties: field: type: string label: type: string role: + enum: + - node + - pod + - service + - endpoints + - endpointslice + - ingress type: string required: - role @@ -26210,55 +33041,30 @@ spec: - role x-kubernetes-list-type: map tlsConfig: - description: TLS configuration to use on every scrape request properties: ca: - description: Struct containing the CA cert to use for the - targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -26266,56 +33072,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container to use - for the targets. type: string cert: - description: Struct containing the client cert file for - the targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -26323,43 +33103,25 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container - for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container - for the targets. type: string keySecret: - description: Secret containing the client key file for the - targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object required: @@ -26367,134 +33129,341 @@ spec: type: object type: array max_scrape_size: - description: MaxScrapeSize defines a maximum size of scraped data - for a job type: string metricRelabelConfigs: - description: MetricRelabelConfigs to apply to samples after scrapping. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. Default - is 'replace' type: string if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source label - values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source label - values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array + nomadSDConfigs: + items: + properties: + allowStale: + type: boolean + authorization: + properties: + credentials: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + credentialsFile: + type: string + type: + type: string + type: object + basicAuth: + properties: + password: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + password_file: + type: string + username: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + followRedirects: + type: boolean + namespace: + type: string + oauth2: + properties: + client_id: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + client_secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + client_secret_file: + type: string + endpoint_params: + additionalProperties: + type: string + type: object + proxy_url: + type: string + scopes: + items: + type: string + type: array + tls_config: + x-kubernetes-preserve-unknown-fields: true + token_url: + minLength: 1 + type: string + required: + - client_id + - token_url + type: object + proxy_client_config: + properties: + basic_auth: + properties: + password: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + password_file: + type: string + username: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearer_token: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + bearer_token_file: + type: string + tls_config: + x-kubernetes-preserve-unknown-fields: true + type: object + proxyURL: + type: string + region: + type: string + server: + minLength: 1 + type: string + tagSeparator: + type: string + tlsConfig: + properties: + ca: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + caFile: + type: string + cert: + properties: + configMap: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + certFile: + type: string + insecureSkipVerify: + type: boolean + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + type: string + type: object + required: + - server + type: object + type: array oauth2: - description: OAuth2 defines auth configuration properties: client_id: - description: The secret or configmap containing the OAuth2 client - id properties: configMap: - description: ConfigMap containing data to use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -26502,56 +33471,33 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 client secret properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for client secret file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: @@ -26559,56 +33505,28 @@ spec: - token_url type: object openstackSDConfigs: - description: OpenStackSDConfigs defines a list of OpenStack service - discovery configurations. items: - description: |- - OpenStackSDConfig allow retrieving scrape targets from OpenStack Nova instances. - See [here](https://docs.victoriametrics.com/sd_configs#openstack_sd_configs) properties: allTenants: - description: |- - Whether the service discovery should list all instances for all projects. - It is only relevant for the 'instance' role and usually requires admin permissions. type: boolean applicationCredentialId: - description: ApplicationCredentialID type: string applicationCredentialName: - description: |- - The ApplicationCredentialID or ApplicationCredentialName fields are - required if using an application credential to authenticate. Some providers - allow you to create an application credential to authenticate rather than a - password. type: string applicationCredentialSecret: - description: |- - The applicationCredentialSecret field is required if using an application - credential to authenticate. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic availability: - description: Availability of the endpoint to connect to. enum: - Public - public @@ -26618,65 +33536,34 @@ spec: - internal type: string domainID: - description: DomainID type: string domainName: - description: |- - At most one of domainId and domainName must be provided if using username - with Identity V3. Otherwise, either are optional. type: string identityEndpoint: - description: |- - IdentityEndpoint specifies the HTTP endpoint that is required to work with - the Identity API of the appropriate version. type: string password: - description: |- - Password for the Identity V2 and V3 APIs. Consult with your provider's - control panel to discover your account's preferred method of authentication. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic port: - description: |- - The port to scrape metrics from. If using the public IP address, this must - instead be specified in the relabeling rule. type: integer projectID: - description: ' ProjectID' type: string projectName: - description: |- - The ProjectId and ProjectName fields are optional for the Identity V2 API. - Some providers allow you to specify a ProjectName instead of the ProjectId. - Some require both. Your provider's authentication policies will determine - how these fields influence authentication. type: string region: - description: The OpenStack Region. minLength: 1 type: string role: - description: The OpenStack role of entities that should be discovered. enum: - Instance - instance @@ -26684,55 +33571,30 @@ spec: - hypervisor type: string tlsConfig: - description: TLS configuration to use on every scrape request properties: ca: - description: Struct containing the CA cert to use for the - targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -26740,56 +33602,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container to use - for the targets. type: string cert: - description: Struct containing the client cert file for - the targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -26797,54 +33633,30 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container - for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container - for the targets. type: string keySecret: - description: Secret containing the client key file for the - targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object userid: - description: UserID type: string username: - description: |- - Username is required if using Identity V2 API. Consult with your provider's - control panel to discover your account's username. - In Identity V3, either userid or a combination of username - and domainId or domainName are needed type: string required: - region @@ -26856,98 +33668,50 @@ spec: items: type: string type: array - description: Optional HTTP URL parameters type: object path: - description: HTTP path to scrape for metrics. type: string proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes to - proxy through this endpoint. type: string relabelConfigs: - description: RelabelConfigs to apply to samples during service discovery. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. Default - is 'replace' type: string if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source label - values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source label - values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array sampleLimit: - description: SampleLimit defines per-scrape limit on number of scraped - samples that will be accepted. - format: int64 type: integer scheme: - description: HTTP scheme to use for scraping. enum: - http - https @@ -26955,89 +33719,52 @@ spec: - HTTP type: string scrape_interval: - description: |- - ScrapeInterval is the same as Interval and has priority over it. - one of scrape_interval or interval can be used + type: string + scrapeClass: type: string scrapeTimeout: - description: Timeout after which the scrape is ended type: string seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 type: integer staticConfigs: - description: StaticConfigs defines a list of static targets with a - common label set. items: - description: |- - StaticConfig defines a static configuration. - See [here](https://docs.victoriametrics.com/sd_configs#static_configs) properties: labels: additionalProperties: type: string - description: Labels assigned to all metrics scraped from the - targets. type: object x-kubernetes-map-type: atomic targets: - description: List of targets for this static configuration. items: type: string type: array type: object type: array tlsConfig: - description: TLSConfig configuration to use when scraping the endpoint properties: ca: - description: Struct containing the CA cert to use for the targets. properties: configMap: - description: ConfigMap containing data to use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -27045,54 +33772,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container to use for the - targets. type: string cert: - description: Struct containing the client cert file for the targets. properties: configMap: - description: ConfigMap containing data to use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -27100,131 +33803,66 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container for - the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container for - the targets. type: string keySecret: - description: Secret containing the client key file for the targets. properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object vm_scrape_params: - description: VMScrapeParams defines VictoriaMetrics specific scrape - parameters properties: disable_compression: - description: DisableCompression type: boolean disable_keep_alive: - description: |- - disable_keepalive allows disabling HTTP keep-alive when scraping targets. - By default, HTTP keep-alive is enabled, so TCP connections to scrape targets - could be reused. - See https://docs.victoriametrics.com/vmagent#scrape_config-enhancements type: boolean headers: - description: |- - Headers allows sending custom headers to scrape targets - must be in of semicolon separated header with it's value - eg: - headerName: headerValue - vmagent supports since 1.79.0 version items: type: string type: array no_stale_markers: type: boolean proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See feature description https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy properties: basic_auth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -27232,24 +33870,13 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token: - description: SecretKeySelector selects a key of a Secret. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -27269,58 +33896,34 @@ spec: type: object type: object status: - description: ScrapeObjectStatus defines the observed state of ScrapeObjects properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -27335,16 +33938,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -27357,7 +33955,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmservicescrapes.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -27381,159 +33979,84 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: |- - VMServiceScrape is scrape configuration for endpoints associated with - kubernetes service, - it generates scrape configuration for vmagent based on selectors. - result config will scrape service endpoints 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: VMServiceScrapeSpec defines the desired state of VMServiceScrape properties: attach_metadata: - description: AttachMetadata configures metadata attaching from service - discovery properties: + namespace: + type: boolean node: - description: |- - Node instructs vmagent to add node specific metadata from service discovery - Valid for roles: pod, endpoints, endpointslice. type: boolean type: object discoveryRole: - description: |- - DiscoveryRole - defines kubernetes_sd role for objects discovery. - by default, its endpoints. - can be changed to service or endpointslices. - note, that with service setting, you have to use port: "name" - and cannot use targetPort for endpoints. enum: - endpoints - service - endpointslices + - endpointslice type: string endpoints: - description: A list of endpoints allowed as part of this ServiceScrape. items: - description: Endpoint defines a scrapeable endpoint serving metrics. properties: attach_metadata: - description: AttachMetadata configures metadata attaching from - service discovery properties: + namespace: + type: boolean node: - description: |- - Node instructs vmagent to add node specific metadata from service discovery - Valid for roles: pod, endpoints, endpointslice. type: boolean type: object authorization: - description: Authorization with http header Authorization properties: credentials: - description: Reference to the secret with value for authorization properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to bearer type: string type: object basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -27541,181 +34064,92 @@ spec: x-kubernetes-map-type: atomic type: object bearerTokenFile: - description: File to read bearer token for scraping targets. type: string bearerTokenSecret: - description: |- - Secret to mount to read bearer token for scraping targets. The secret - needs to be in the same namespace as the scrape object and accessible by - the victoria-metrics operator. nullable: true properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic follow_redirects: - description: FollowRedirects controls redirects for scraping. type: boolean honorLabels: - description: HonorLabels chooses the metric's labels on collisions - with target labels. type: boolean honorTimestamps: - description: HonorTimestamps controls whether vmagent respects - the timestamps present in scraped data. type: boolean interval: - description: Interval at which metrics should be scraped type: string max_scrape_size: - description: MaxScrapeSize defines a maximum size of scraped - data for a job type: string metricRelabelConfigs: - description: MetricRelabelConfigs to apply to samples after - scrapping. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. - Default is 'replace' type: string if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source - label values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source - label values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array oauth2: - description: OAuth2 defines auth configuration properties: client_id: - description: The secret or configmap containing the OAuth2 - client id properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -27723,57 +34157,33 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 client secret properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for client secret - file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: @@ -27785,102 +34195,52 @@ spec: items: type: string type: array - description: Optional HTTP URL parameters type: object path: - description: HTTP path to scrape for metrics. type: string port: - description: Name of the port exposed at Service. type: string proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes - to proxy through this endpoint. type: string relabelConfigs: - description: RelabelConfigs to apply to samples during service - discovery. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. - Default is 'replace' type: string if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source - label values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source - label values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array sampleLimit: - description: SampleLimit defines per-scrape limit on number - of scraped samples that will be accepted. - format: int64 type: integer scheme: - description: HTTP scheme to use for scraping. enum: - http - https @@ -27888,78 +34248,41 @@ spec: - HTTP type: string scrape_interval: - description: |- - ScrapeInterval is the same as Interval and has priority over it. - one of scrape_interval or interval can be used type: string scrapeTimeout: - description: Timeout after which the scrape is ended type: string seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 type: integer targetPort: anyOf: - type: integer - type: string - description: |- - TargetPort - Name or number of the pod port this endpoint refers to. Mutually exclusive with port. x-kubernetes-int-or-string: true tlsConfig: - description: TLSConfig configuration to use when scraping the - endpoint properties: ca: - description: Struct containing the CA cert to use for the - targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -27967,56 +34290,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container to use - for the targets. type: string cert: - description: Struct containing the client cert file for - the targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -28024,132 +34321,66 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container - for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container - for the targets. type: string keySecret: - description: Secret containing the client key file for the - targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object vm_scrape_params: - description: VMScrapeParams defines VictoriaMetrics specific - scrape parameters properties: disable_compression: - description: DisableCompression type: boolean disable_keep_alive: - description: |- - disable_keepalive allows disabling HTTP keep-alive when scraping targets. - By default, HTTP keep-alive is enabled, so TCP connections to scrape targets - could be reused. - See https://docs.victoriametrics.com/vmagent#scrape_config-enhancements type: boolean headers: - description: |- - Headers allows sending custom headers to scrape targets - must be in of semicolon separated header with it's value - eg: - headerName: headerValue - vmagent supports since 1.79.0 version items: type: string type: array no_stale_markers: type: boolean proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See feature description https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy properties: basic_auth: - description: BasicAuth allow an endpoint to authenticate - over basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key @@ -28157,24 +34388,13 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token: - description: SecretKeySelector selects a key of a Secret. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -28195,61 +34415,34 @@ spec: type: object type: array jobLabel: - description: The label to use to retrieve the job name from. type: string namespaceSelector: - description: Selector to select which namespaces the Endpoints objects - are discovered from. properties: any: - description: |- - Boolean describing whether all namespaces are selected in contrast to a - list restricting them. type: boolean matchNames: - description: List of namespace names. items: type: string type: array type: object podTargetLabels: - description: PodTargetLabels transfers labels on the Kubernetes Pod - onto the target. items: type: string type: array sampleLimit: - description: SampleLimit defines per-scrape limit on number of scraped - samples that will be accepted. - format: int64 type: integer + scrapeClass: + type: string selector: - description: Selector to select Endpoints objects by corresponding - Service labels. 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 @@ -28263,22 +34456,12 @@ spec: 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 seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 type: integer targetLabels: - description: TargetLabels transfers labels on the Kubernetes Service - onto the target. items: type: string type: array @@ -28286,58 +34469,34 @@ spec: - endpoints type: object status: - description: ScrapeObjectStatus defines the observed state of ScrapeObjects properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -28352,16 +34511,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object required: @@ -28376,7 +34530,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmsingles.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -28398,144 +34552,70 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMSingle is fast, cost-effective and scalable time-series database. 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: VMSingleSpec defines the desired state of VMSingle properties: affinity: - description: Affinity If specified, the pod's scheduling constraints. type: object x-kubernetes-preserve-unknown-fields: true configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder items: type: string type: array containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. items: - description: A single application container that you want to run - within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. type: boolean disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable type: boolean dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. items: x-kubernetes-preserve-unknown-fields: true properties: nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. items: type: string type: array x-kubernetes-list-type: atomic options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. properties: name: - description: |- - Name is this DNS resolver option's name. - Required. type: string value: - description: Value is this DNS resolver option's value. type: string type: object type: array x-kubernetes-list-type: atomic searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. items: type: string type: array x-kubernetes-list-type: atomic type: object dnsPolicy: - description: DNSPolicy sets DNS policy for the pod type: string extraArgs: additionalProperties: type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp type: object extraEnvs: - description: ExtraEnvs that will be passed to the application container items: - description: EnvVar represents an environment variable present in - a Container. properties: name: - description: Name of the environment variable. Must be a C_IDENTIFIER. type: string value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". type: string required: - name @@ -28543,227 +34623,127 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap items: - description: EnvFromSource represents the source of a set of ConfigMaps properties: configMapRef: - description: The ConfigMap to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap must be defined type: boolean 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. type: string secretRef: - description: The Secret to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret must be defined type: boolean type: object x-kubernetes-map-type: atomic type: object type: array host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. properties: hostnames: - description: Hostnames for the above IP address. items: type: string type: array x-kubernetes-list-type: atomic ip: - description: IP address of the host file entry. type: string required: - ip type: object type: array hostNetwork: - description: HostNetwork controls whether the pod may use the node - network namespace type: boolean image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config properties: pullPolicy: - description: PullPolicy describes how to pull docker image type: string repository: - description: Repository contains name of docker image + it's repository - if needed type: string tag: - description: Tag contains desired docker image version type: string type: object imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string type: object x-kubernetes-map-type: atomic type: array initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ items: - description: A single application container that you want to run - within a pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array insertPorts: - description: InsertPorts - additional listen ports for data ingestion. properties: graphitePort: - description: GraphitePort listen port type: string influxPort: - description: InfluxPort listen port type: string openTSDBHTTPPort: - description: OpenTSDBHTTPPort for http connections. type: string openTSDBPort: - description: OpenTSDBPort for tcp and udp listen type: string type: object license: - description: |- - License allows to configure license key to be used for enterprise features. - Using license key is supported starting from VictoriaMetrics v1.94.0. - See [here](https://docs.victoriametrics.com/enterprise) properties: forceOffline: - description: Enforce offline verification of the license key. type: boolean key: - description: |- - Enterprise license key. This flag is available only in [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise). - To request a trial license, [go to](https://victoriametrics.com/products/enterprise/trial) type: string keyRef: - description: KeyRef is reference to secret with license key for - enterprise features. properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic reloadInterval: - description: Interval to be used for checking for license key - changes. Note that this is only applicable when using KeyRef. type: string type: object livenessProbe: - description: LivenessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true logFormat: - description: LogFormat for VMSingle to be configured with. enum: - default - json type: string logLevel: - description: LogLevel for victoria metrics single to be configured - with. enum: - INFO - WARN @@ -28772,139 +34752,67 @@ spec: - PANIC type: string managedMetadata: - description: |- - ManagedMetadata defines metadata that will be added to the all objects - created by operator for the given CustomResource properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object type: object minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle format: int32 type: integer nodeSelector: additionalProperties: type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. type: object paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. type: boolean podMetadata: - description: PodMetadata configures Labels and Annotations which are - propagated to the VMSingle pods. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object port: - description: Port listen address type: string priorityClassName: - description: PriorityClassName class assigned to the Pods type: string readinessGates: - description: ReadinessGates defines pod readiness gates items: - description: PodReadinessGate contains the reference to a pod condition properties: conditionType: - description: ConditionType refers to a condition in the pod's - condition list with matching type. type: string required: - conditionType type: object type: array readinessProbe: - description: ReadinessProbe that will be added CRD pod type: object x-kubernetes-preserve-unknown-fields: true removePvcAfterDelete: - description: |- - RemovePvcAfterDelete - if true, controller adds ownership to pvc - and after VMSingle object deletion - pvc will be garbage collected - by controller manager type: boolean replicaCount: - description: ReplicaCount is the expected size of the Application. format: int32 type: integer resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used properties: claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. type: string request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. type: string required: - name @@ -28920,9 +34828,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -28931,150 +34836,72 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object retentionPeriod: - description: |- - RetentionPeriod for the stored metrics - Note VictoriaMetrics has data/ and indexdb/ folders - metrics from data/ removed eventually as soon as partition leaves retention period - reverse index data at indexdb rotates once at the half of configured [retention period](https://docs.victoriametrics.com/Single-server-VictoriaMetrics/#retention) + pattern: ^[0-9]+(h|d|w|y)?$ type: string revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. format: int32 type: integer runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ type: string schedulerName: - description: SchedulerName - defines kubernetes scheduler name type: string secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder items: type: string type: array securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. type: object x-kubernetes-preserve-unknown-fields: true serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to use to run the pods type: string serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vmsingle VMServiceScrape - spec required: - endpoints type: object x-kubernetes-preserve-unknown-fields: true serviceSpec: - description: ServiceSpec that will be added to vmsingle service spec properties: metadata: - description: EmbeddedObjectMetadata defines objectMeta for additional - service. properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ type: object x-kubernetes-preserve-unknown-fields: true useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication type: boolean required: - spec type: object startupProbe: - description: StartupProbe that will be added to CRD pod type: object x-kubernetes-preserve-unknown-fields: true storage: - description: |- - Storage is the definition of how storage will be used by the VMSingle - by default it`s empty dir - this option is ignored if storageDataPath is set properties: accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 items: type: string type: array x-kubernetes-list-type: atomic dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. properties: apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. type: string kind: - description: Kind is the type of resource being referenced type: string name: - description: Name is the name of resource being referenced type: string required: - kind @@ -29082,60 +34909,20 @@ spec: type: object x-kubernetes-map-type: atomic dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. properties: apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. type: string kind: - description: Kind is the type of resource being referenced type: string name: - description: Name is the name of resource being referenced type: string namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. type: string required: - kind - name type: object resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources properties: limits: additionalProperties: @@ -29144,9 +34931,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -29155,40 +34939,18 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object selector: - description: selector is a label query over volumes to consider - for binding. 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 @@ -29202,393 +34964,176 @@ spec: 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 storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 type: string volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. type: string volumeName: - description: volumeName is the binding reference to the PersistentVolume - backing this claim. type: string type: object storageDataPath: - description: |- - StorageDataPath disables spec.storage option and overrides arg for victoria-metrics binary --storageDataPath, - its users responsibility to mount proper device into given path. - It requires to provide spec.volumes and spec.volumeMounts with at least 1 value type: string storageMetadata: - description: StorageMeta defines annotations and labels attached to - PVC for given vmsingle CR properties: annotations: additionalProperties: type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations type: object labels: additionalProperties: type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels type: object name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names type: string type: object streamAggrConfig: - description: StreamAggrConfig defines stream aggregation configuration - for VMSingle properties: configmap: - description: ConfigMap with stream aggregation rules properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic dedupInterval: - description: Allows setting different de-duplication intervals - per each configured remote storage type: string dropInput: - description: Allow drop all the input samples after the aggregation type: boolean dropInputLabels: - description: labels to drop from samples for aggregator before - stream de-duplication and aggregation items: type: string type: array enableWindows: - description: EnableWindows enables aggregating data in separate - windows ( available from v0.54.0). type: boolean ignoreFirstIntervals: - description: IgnoreFirstIntervals instructs to ignore first interval type: integer + ignoreFirstSampleInterval: + type: string ignoreOldSamples: - description: IgnoreOldSamples instructs to ignore samples with - old timestamps outside the current aggregation interval. type: boolean keepInput: - description: Allows writing both raw and aggregate data type: boolean rules: - description: Stream aggregation rules items: - description: StreamAggrRule defines the rule in stream aggregation - config properties: by: - description: |- - By is an optional list of labels for grouping input series. - - See also Without. - - If neither By nor Without are set, then the Outputs are calculated - individually per each input time series. items: type: string type: array dedup_interval: - description: DedupInterval is an optional interval for deduplication. type: string drop_input_labels: - description: |- - DropInputLabels is an optional list with labels, which must be dropped before further processing of input samples. - - Labels are dropped before de-duplication and aggregation. items: type: string type: array enable_windows: - description: EnableWindows enables aggregating data in separate - windows type: boolean flush_on_shutdown: - description: |- - FlushOnShutdown defines whether to flush the aggregation state on process termination - or config reload. Is `false` by default. - It is not recommended changing this setting, unless unfinished aggregations states - are preferred to missing data points. type: boolean ignore_first_intervals: type: integer ignore_old_samples: - description: IgnoreOldSamples instructs to ignore samples - with old timestamps outside the current aggregation interval. type: boolean + ignoreFirstSampleInterval: + type: string input_relabel_configs: - description: |- - InputRelabelConfigs is an optional relabeling rules, which are applied on the input - before aggregation. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. - Default is 'replace' type: string if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for - `action: graphite`' type: object match: - description: 'Match is used together with Labels for - `action: graphite`' type: string modulus: - description: Modulus to take of the hash of the source - label values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated - source label values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array interval: - description: Interval is the interval between aggregations. type: string keep_metric_names: - description: KeepMetricNames instructs to leave metric names - as is for the output time series without adding any suffix. type: boolean match: - description: |- - Match is a label selector (or list of label selectors) for filtering time series for the given selector. - - If the match isn't set, then all the input time series are processed. x-kubernetes-preserve-unknown-fields: true no_align_flush_to_interval: - description: |- - NoAlignFlushToInterval disables aligning of flushes to multiples of Interval. - By default flushes are aligned to Interval. type: boolean output_relabel_configs: - description: |- - OutputRelabelConfigs is an optional relabeling rules, which are applied - on the aggregated output before being sent to remote storage. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. - Default is 'replace' type: string if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for - `action: graphite`' type: object match: - description: 'Match is used together with Labels for - `action: graphite`' type: string modulus: - description: Modulus to take of the hash of the source - label values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated - source label values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array outputs: - description: |- - Outputs is a list of output aggregate functions to produce. - - The following names are allowed: - - - total - aggregates input counters - - increase - counts the increase over input counters - - count_series - counts the input series - - count_samples - counts the input samples - - sum_samples - sums the input samples - - last - the last biggest sample value - - min - the minimum sample value - - max - the maximum sample value - - avg - the average value across all the samples - - stddev - standard deviation across all the samples - - stdvar - standard variance across all the samples - - histogram_bucket - creates VictoriaMetrics histogram for input samples - - quantiles(phi1, ..., phiN) - quantiles' estimation for phi in the range [0..1] - - The output time series will have the following names: - - input_name:aggr__ items: type: string type: array staleness_interval: - description: |- - Staleness interval is interval after which the series state will be reset if no samples have been sent during it. - The parameter is only relevant for outputs: total, total_prometheus, increase, increase_prometheus and histogram_bucket. type: string without: - description: |- - Without is an optional list of labels, which must be excluded when grouping input series. - - See also By. - - If neither By nor Without are set, then the Outputs are calculated - individually per each input time series. items: type: string type: array @@ -29599,58 +35144,26 @@ spec: type: array type: object terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container graceful - termination format: int64 type: integer tolerations: - description: Tolerations If specified, the pod's tolerations. items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . properties: effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. type: string tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. format: int64 type: integer value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. type: string type: object type: array topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ items: - description: TopologySpreadConstraint specifies how to spread matching - pods among the given topology. required: - maxSkew - topologyKey @@ -29659,196 +35172,120 @@ spec: x-kubernetes-preserve-unknown-fields: true type: array useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements type: boolean useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions type: boolean vmBackup: - description: VMBackup configuration for backup properties: acceptEULA: - description: |- - AcceptEULA accepts enterprise feature usage, must be set to true. - otherwise backupmanager cannot be added to single/cluster version. - https://victoriametrics.com/legal/esa/ type: boolean concurrency: - description: Defines number of concurrent workers. Higher concurrency - may reduce backup duration (default 10) format: int32 type: integer credentialsSecret: - description: |- - CredentialsSecret is secret in the same namespace for access to remote storage - The secret is mounted into /etc/vm/creds. properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic customS3Endpoint: - description: Custom S3 endpoint for use with S3-compatible storages - (e.g. MinIO). S3 is used if not set type: string destination: - description: Defines destination for backup type: string destinationDisableSuffixAdd: - description: |- - DestinationDisableSuffixAdd - disables suffix adding for cluster version backups - each vmstorage backup must have unique backup folder - so operator adds POD_NAME as suffix for backup destination folder. type: boolean disableDaily: - description: Defines if daily backups disabled (default false) type: boolean disableHourly: - description: Defines if hourly backups disabled (default false) type: boolean disableMonthly: - description: Defines if monthly backups disabled (default false) type: boolean disableWeekly: - description: Defines if weekly backups disabled (default false) type: boolean extraArgs: additionalProperties: type: string - description: extra args like maxBytesPerSecond default 0 type: object extraEnvs: items: - description: EnvVar represents an environment variable present - in a Container. properties: name: - description: Name of the environment variable. Must be a - C_IDENTIFIER. type: string value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". type: string valueFrom: - description: Source for the environment variable's value. - Cannot be used if value is not empty. properties: configMapKeyRef: - description: Selects a key of a ConfigMap. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. properties: apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". type: string fieldPath: - description: Path of the field to select in the - specified API version. type: string required: - fieldPath type: object x-kubernetes-map-type: atomic + fileKeyRef: + properties: + key: + type: string + optional: + default: false + type: boolean + path: + type: string + volumeName: + type: string + required: + - key + - path + - volumeName + type: object + x-kubernetes-map-type: atomic resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. properties: containerName: - description: 'Container name: required for volumes, - optional for env vars' type: string divisor: anyOf: - type: integer - type: string - description: Specifies the output format of the - exposed resources, defaults to "1" pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true resource: - description: 'Required: resource to select' type: string required: - resource type: object x-kubernetes-map-type: atomic secretKeyRef: - description: Selects a key of a secret in the pod's - namespace properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -29860,77 +35297,45 @@ spec: type: object type: array extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap items: - description: EnvFromSource represents the source of a set of - ConfigMaps properties: configMapRef: - description: The ConfigMap to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap must be defined type: boolean 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. type: string secretRef: - description: The Secret to select from properties: name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret must be defined type: boolean type: object x-kubernetes-map-type: atomic type: object type: array image: - description: Image - docker image settings for VMBackuper properties: pullPolicy: - description: PullPolicy describes how to pull docker image type: string repository: - description: Repository contains name of docker image + it's - repository if needed type: string tag: - description: Tag contains desired docker image version type: string type: object logFormat: - description: |- - LogFormat for VMBackup to be configured with. - default or json enum: - default - json type: string logLevel: - description: LogLevel for VMBackup to be configured with. enum: - INFO - WARN @@ -29939,36 +35344,15 @@ spec: - PANIC type: string port: - description: Port for health check connections type: string resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used properties: claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. type: string request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. type: string required: - name @@ -29984,9 +35368,6 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object requests: additionalProperties: @@ -29995,94 +35376,36 @@ spec: - type: string pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object restore: - description: |- - Restore Allows to enable restore options for pod - Read [more](https://docs.victoriametrics.com/vmbackupmanager#restore-commands) properties: onStart: - description: OnStart defines configuration for restore on - pod start properties: enabled: - description: Enabled defines if restore on start enabled type: boolean type: object type: object snapshotCreateURL: - description: SnapshotCreateURL overwrites url for snapshot create type: string snapshotDeleteURL: - description: SnapShotDeleteURL overwrites url for snapshot delete type: string volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment definition. - VolumeMounts specified will be appended to other VolumeMounts in the vmbackupmanager container, - that are generated as a result of StorageSpec objects. items: - description: VolumeMount describes a mounting of a Volume within - a container. properties: mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. type: string mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). type: string name: - description: This must match the Name of a Volume. type: string readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. type: boolean recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). type: string subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. type: string required: - mountPath @@ -30091,65 +35414,21 @@ spec: type: array type: object volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container items: - description: VolumeMount describes a mounting of a Volume within - a container. properties: mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. type: string mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). type: string name: - description: This must match the Name of a Volume. type: string readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. type: boolean recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). type: string subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. type: string required: - mountPath @@ -30157,74 +35436,42 @@ spec: type: object type: array volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional items: - description: Volume represents a named volume in a pod that may - be accessed by any container in the pod. required: - name type: object x-kubernetes-preserve-unknown-fields: true type: array - required: - - retentionPeriod type: object status: - description: VMSingleStatus defines the observed state of VMSingle properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -30239,20 +35486,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason - type: string - singleStatus: - description: LegacyStatus is deprecated and will be removed at v0.52.0 - version type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -30265,7 +35503,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmstaticscrapes.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -30289,137 +35527,71 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMStaticScrape defines static targets configuration for scraping. 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: VMStaticScrapeSpec defines the desired state of VMStaticScrape. properties: jobName: - description: JobName name of job. type: string sampleLimit: - description: SampleLimit defines per-scrape limit on number of scraped - samples that will be accepted. - format: int64 type: integer + scrapeClass: + type: string seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 type: integer targetEndpoints: - description: A list of target endpoints to scrape metrics from. items: - description: TargetEndpoint defines single static target endpoint. properties: authorization: - description: Authorization with http header Authorization properties: credentials: - description: Reference to the secret with value for authorization properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic credentialsFile: - description: File with value for authorization type: string type: - description: Type of authorization, default to bearer type: string type: object basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -30427,186 +35599,96 @@ spec: x-kubernetes-map-type: atomic type: object bearerTokenFile: - description: File to read bearer token for scraping targets. type: string bearerTokenSecret: - description: |- - Secret to mount to read bearer token for scraping targets. The secret - needs to be in the same namespace as the scrape object and accessible by - the victoria-metrics operator. nullable: true properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic follow_redirects: - description: FollowRedirects controls redirects for scraping. type: boolean honorLabels: - description: HonorLabels chooses the metric's labels on collisions - with target labels. type: boolean honorTimestamps: - description: HonorTimestamps controls whether vmagent respects - the timestamps present in scraped data. type: boolean interval: - description: Interval at which metrics should be scraped type: string labels: additionalProperties: type: string - description: Labels static labels for targets. type: object max_scrape_size: - description: MaxScrapeSize defines a maximum size of scraped - data for a job type: string metricRelabelConfigs: - description: MetricRelabelConfigs to apply to samples after - scrapping. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. - Default is 'replace' type: string if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source - label values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source - label values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array oauth2: - description: OAuth2 defines auth configuration properties: client_id: - description: The secret or configmap containing the OAuth2 - client id properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -30614,57 +35696,33 @@ spec: x-kubernetes-map-type: atomic type: object client_secret: - description: The secret containing the OAuth2 client secret properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic client_secret_file: - description: ClientSecretFile defines path for client secret - file. type: string endpoint_params: additionalProperties: type: string - description: Parameters to append to the token URL type: object proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family type: string scopes: - description: OAuth2 scopes used for the token request items: type: string type: array tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family x-kubernetes-preserve-unknown-fields: true token_url: - description: The URL to fetch the token from minLength: 1 type: string required: @@ -30676,99 +35734,50 @@ spec: items: type: string type: array - description: Optional HTTP URL parameters type: object path: - description: HTTP path to scrape for metrics. type: string proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes - to proxy through this endpoint. type: string relabelConfigs: - description: RelabelConfigs to apply to samples during service - discovery. items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling properties: action: - description: Action to perform based on regex matching. - Default is 'replace' type: string if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' x-kubernetes-preserve-unknown-fields: true labels: additionalProperties: type: string - description: 'Labels is used together with Match for `action: - graphite`' type: object match: - description: 'Match is used together with Labels for `action: - graphite`' type: string modulus: - description: Modulus to take of the hash of the source - label values. format: int64 type: integer regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements x-kubernetes-preserve-unknown-fields: true replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' type: string separator: - description: Separator placed between concatenated source - label values. default is ';'. type: string source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 items: type: string type: array sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. items: type: string type: array target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 type: string targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. type: string type: object type: array sampleLimit: - description: SampleLimit defines per-scrape limit on number - of scraped samples that will be accepted. - format: int64 type: integer scheme: - description: HTTP scheme to use for scraping. enum: - http - https @@ -30776,76 +35785,41 @@ spec: - HTTP type: string scrape_interval: - description: |- - ScrapeInterval is the same as Interval and has priority over it. - one of scrape_interval or interval can be used type: string scrapeTimeout: - description: Timeout after which the scrape is ended type: string seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 type: integer targets: - description: Targets static targets addresses in form of ["192.122.55.55:9100","some-name:9100"]. items: type: string minItems: 1 type: array tlsConfig: - description: TLSConfig configuration to use when scraping the - endpoint properties: ca: - description: Struct containing the CA cert to use for the - targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -30853,56 +35827,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container to use - for the targets. type: string cert: - description: Struct containing the client cert file for - the targets. properties: configMap: - description: ConfigMap containing data to use for the - targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -30910,132 +35858,66 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container - for the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container - for the targets. type: string keySecret: - description: Secret containing the client key file for the - targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object vm_scrape_params: - description: VMScrapeParams defines VictoriaMetrics specific - scrape parameters properties: disable_compression: - description: DisableCompression type: boolean disable_keep_alive: - description: |- - disable_keepalive allows disabling HTTP keep-alive when scraping targets. - By default, HTTP keep-alive is enabled, so TCP connections to scrape targets - could be reused. - See https://docs.victoriametrics.com/vmagent#scrape_config-enhancements type: boolean headers: - description: |- - Headers allows sending custom headers to scrape targets - must be in of semicolon separated header with it's value - eg: - headerName: headerValue - vmagent supports since 1.79.0 version items: type: string type: array no_stale_markers: type: boolean proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See feature description https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy properties: basic_auth: - description: BasicAuth allow an endpoint to authenticate - over basic authentication properties: password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted type: string username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object properties: key: - description: The key of the secret to select - from. Must be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its - key must be defined type: boolean required: - key @@ -31043,24 +35925,13 @@ spec: x-kubernetes-map-type: atomic type: object bearer_token: - description: SecretKeySelector selects a key of a Secret. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key - must be defined type: boolean required: - key @@ -31086,58 +35957,34 @@ spec: - targetEndpoints type: object status: - description: ScrapeObjectStatus defines the observed state of ScrapeObjects properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -31152,16 +35999,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -31174,7 +36016,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmusers.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -31198,79 +36040,36 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMUser is the Schema for the vmusers API 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: VMUserSpec defines the desired state of VMUser properties: bearerToken: - description: BearerToken Authorization header value for accessing - protected endpoint. type: string default_url: - description: |- - DefaultURLs backend url for non-matching paths filter - usually used for default backend with error message items: type: string type: array disable_secret_creation: - description: DisableSecretCreation skips related secret creation for - vmuser type: boolean discover_backend_ips: - description: DiscoverBackendIPs instructs discovering URLPrefix backend - IPs via DNS. type: boolean drop_src_path_prefix_parts: - description: |- - DropSrcPathPrefixParts is the number of `/`-delimited request path prefix parts to drop before proxying the request to backend. - See [here](https://docs.victoriametrics.com/vmauth#dropping-request-path-prefix) for more details. type: integer dump_request_on_errors: - description: |- - DumpRequestOnErrors instructs vmauth to return detailed request params to the client - if routing rules don't allow to forward request to the backends. - Useful for debugging `src_hosts` and `src_headers` based routing rules - - available since v1.107.0 vmauth version type: boolean generatePassword: - description: |- - GeneratePassword instructs operator to generate password for user - if spec.password if empty. type: boolean headers: - description: |- - Headers represent additional http headers, that vmauth uses - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.68.0 version of vmauth items: type: string type: array ip_filters: - description: |- - IPFilters defines per target src ip filters - supported only with enterprise version of [vmauth](https://docs.victoriametrics.com/vmauth/#ip-filters) properties: allow_list: items: @@ -31282,91 +36081,58 @@ spec: type: array type: object load_balancing_policy: - description: |- - LoadBalancingPolicy defines load balancing policy to use for backend urls. - Supported policies: least_loaded, first_available. - See [here](https://docs.victoriametrics.com/vmauth#load-balancing) for more details (default "least_loaded") enum: - least_loaded - first_available type: string + managedMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object max_concurrent_requests: - description: |- - MaxConcurrentRequests defines max concurrent requests per user - 300 is default value for vmauth type: integer metric_labels: additionalProperties: type: string - description: MetricLabels - additional labels for metrics exported - by vmauth for given user. type: object name: - description: Name of the VMUser object. type: string password: - description: Password basic auth password for accessing protected - endpoint. type: string passwordRef: - description: PasswordRef allows fetching password from user-create - secret by its name and key. properties: key: - description: The key of the secret to select from. Must be a - valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic response_headers: - description: |- - ResponseHeaders represent additional http headers, that vmauth adds for request response - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.93.0 version of vmauth items: type: string type: array retry_status_codes: - description: |- - RetryStatusCodes defines http status codes in numeric format for request retries - e.g. [429,503] items: type: integer type: array targetRefs: - description: TargetRefs - reference to endpoints, which user may access. items: - description: |- - TargetRef describes target for user traffic forwarding. - one of target types can be chosen: - crd or static per targetRef. - user can define multiple targetRefs with different ref Types. properties: crd: - description: |- - CRD describes exist operator's CRD object, - operator generates access url based on CRD params. properties: kind: - description: |- - Kind one of: - VMAgent,VMAlert, VMSingle, VMCluster/vmselect, VMCluster/vmstorage,VMCluster/vminsert or VMAlertManager enum: - VMAgent - VMAlert @@ -31377,12 +36143,19 @@ spec: - VMCluster/vmselect - VMCluster/vmstorage - VMCluster/vminsert + - VLSingle + - VLCluster/vlinsert + - VLCluster/vlselect + - VLCluster/vlstorage + - VLAgent + - VTCluster/vtinsert + - VTCluster/vtselect + - VTCluster/vtstorage + - VTSingle type: string name: - description: Name target CRD object name type: string namespace: - description: Namespace target CRD object namespace. type: string required: - kind @@ -31390,21 +36163,10 @@ spec: - namespace type: object discover_backend_ips: - description: DiscoverBackendIPs instructs discovering URLPrefix - backend IPs via DNS. type: boolean drop_src_path_prefix_parts: - description: |- - DropSrcPathPrefixParts is the number of `/`-delimited request path prefix parts to drop before proxying the request to backend. - See [here](https://docs.victoriametrics.com/vmauth#dropping-request-path-prefix) for more details. type: integer headers: - description: |- - RequestHeaders represent additional http headers, that vmauth uses - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.68.0 version of vmauth items: type: string type: array @@ -31413,123 +36175,78 @@ spec: type: string type: array load_balancing_policy: - description: |- - LoadBalancingPolicy defines load balancing policy to use for backend urls. - Supported policies: least_loaded, first_available. - See [here](https://docs.victoriametrics.com/vmauth#load-balancing) for more details (default "least_loaded") enum: - least_loaded - first_available type: string paths: - description: Paths - matched path to route. items: type: string type: array + query_args: + items: + properties: + name: + type: string + values: + items: + type: string + type: array + required: + - name + - values + type: object + type: array response_headers: - description: |- - ResponseHeaders represent additional http headers, that vmauth adds for request response - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.93.0 version of vmauth items: type: string type: array retry_status_codes: - description: |- - RetryStatusCodes defines http status codes in numeric format for request retries - Can be defined per target or at VMUser.spec level - e.g. [429,503] items: type: integer type: array src_headers: - description: SrcHeaders is an optional list of headers, which - must match request headers. items: type: string type: array src_query_args: - description: SrcQueryArgs is an optional list of query args, - which must match request URL query args. items: type: string type: array static: - description: |- - Static - user defined url for traffic forward, - for instance http://vmsingle:8429 properties: url: - description: URL http url for given staticRef. type: string urls: - description: URLs allows setting multiple urls for load-balancing - at vmauth-side. items: type: string type: array type: object target_path_suffix: - description: |- - TargetPathSuffix allows to add some suffix to the target path - It allows to hide tenant configuration from user with crd as ref. - it also may contain any url encoded params. type: string targetRefBasicAuth: - description: TargetRefBasicAuth allow an target endpoint to - authenticate over basic authentication properties: password: - description: |- - The secret in the service scrape namespace that contains the password - for authentication. - It must be at them same namespace as CRD properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic username: - description: |- - The secret in the service scrape namespace that contains the username - for authentication. - It must be at them same namespace as CRD properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -31542,53 +36259,30 @@ spec: type: object type: array tlsConfig: - description: TLSConfig defines tls configuration for the backend connection properties: ca: - description: Struct containing the CA cert to use for the targets. properties: configMap: - description: ConfigMap containing data to use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -31596,54 +36290,30 @@ spec: x-kubernetes-map-type: atomic type: object caFile: - description: Path to the CA cert in the container to use for the - targets. type: string cert: - description: Struct containing the client cert file for the targets. properties: configMap: - description: ConfigMap containing data to use for the targets. properties: key: - description: The key to select. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the ConfigMap or its key - must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic secret: - description: Secret containing data to use for the targets. properties: key: - description: The key of the secret to select from. Must - be a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must - be defined type: boolean required: - key @@ -31651,129 +36321,74 @@ spec: x-kubernetes-map-type: atomic type: object certFile: - description: Path to the client cert file in the container for - the targets. type: string insecureSkipVerify: - description: Disable target certificate validation. type: boolean keyFile: - description: Path to the client key file in the container for - the targets. type: string keySecret: - description: Secret containing the client key file for the targets. properties: key: - description: The key of the secret to select from. Must be - a valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be - defined type: boolean required: - key type: object x-kubernetes-map-type: atomic serverName: - description: Used to verify the hostname for the targets. type: string type: object tokenRef: - description: TokenRef allows fetching token from user-created secrets - by its name and key. properties: key: - description: The key of the secret to select from. Must be a - valid secret key. type: string name: default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: - description: Specify whether the Secret or its key must be defined type: boolean required: - key type: object x-kubernetes-map-type: atomic username: - description: |- - UserName basic auth user name for accessing protected endpoint, - will be replaced with metadata.name of VMUser if omitted. type: string required: - targetRefs type: object status: - description: VMUserStatus defines the observed state of VMUser properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -31788,16 +36403,2507 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.0 + name: vtclusters.operator.victoriametrics.com +spec: + group: operator.victoriametrics.com + names: + kind: VTCluster + listKind: VTClusterList + plural: vtclusters + singular: vtcluster + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: replicas of VTInsert + jsonPath: .spec.insert.replicaCount + name: Insert Count + type: string + - description: replicas of VTStorage + jsonPath: .spec.storage.replicaCount + name: Storage Count + type: string + - description: replicas of VTSelect + jsonPath: .spec.select.replicaCount + name: Select Count + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Current status of cluster + jsonPath: .status.updateStatus + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + clusterDomainName: + type: string + clusterVersion: + type: string + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + insert: + properties: + affinity: + type: object + x-kubernetes-preserve-unknown-fields: true + configMaps: + items: + type: string + type: array + containers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + disableAutomountServiceAccountToken: + type: boolean + disableSelfServiceScrape: + type: boolean + dnsConfig: + items: + x-kubernetes-preserve-unknown-fields: true + properties: + nameservers: + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + dnsPolicy: + type: string + extraArgs: + additionalProperties: + type: string + type: object + extraEnvs: + items: + properties: + name: + type: string + value: + type: string + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + extraEnvsFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + host_aliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostNetwork: + type: boolean + hpa: + type: object + x-kubernetes-preserve-unknown-fields: true + image: + properties: + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + livenessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + logFormat: + enum: + - default + - json + type: string + logLevel: + enum: + - INFO + - WARN + - ERROR + - FATAL + - PANIC + type: string + minReadySeconds: + format: int32 + type: integer + nodeSelector: + additionalProperties: + type: string + type: object + paused: + type: boolean + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + selectorLabels: + additionalProperties: + type: string + type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string + type: object + podMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + port: + type: string + priorityClassName: + type: string + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + readinessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + replicaCount: + format: int32 + type: integer + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + revisionHistoryLimitCount: + format: int32 + type: integer + rollingUpdate: + properties: + maxSurge: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + runtimeClassName: + type: string + schedulerName: + type: string + secrets: + items: + type: string + type: array + securityContext: + type: object + x-kubernetes-preserve-unknown-fields: true + serviceScrapeSpec: + required: + - endpoints + type: object + x-kubernetes-preserve-unknown-fields: true + serviceSpec: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + useAsDefault: + type: boolean + required: + - spec + type: object + startupProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + updateStrategy: + enum: + - Recreate + - RollingUpdate + type: string + useDefaultResources: + type: boolean + useStrictSecurity: + type: boolean + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + vpa: + properties: + recommenders: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + resourcePolicy: + properties: + containerPolicies: + items: + properties: + containerName: + type: string + controlledResources: + items: + type: string + type: array + controlledValues: + enum: + - RequestsAndLimits + - RequestsOnly + type: string + maxAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + minAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + mode: + enum: + - Auto + - "Off" + type: string + type: object + type: array + type: object + updatePolicy: + properties: + evictionRequirements: + items: + properties: + changeRequirement: + enum: + - TargetHigherThanRequests + - TargetLowerThanRequests + type: string + resources: + items: + type: string + type: array + required: + - changeRequirement + - resources + type: object + type: array + minReplicas: + format: int32 + type: integer + updateMode: + enum: + - "Off" + - Initial + - Recreate + - InPlaceOrRecreate + - Auto + type: string + type: object + type: object + type: object + managedMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + paused: + type: boolean + requestsLoadBalancer: + properties: + disableInsertBalancing: + type: boolean + disableSelectBalancing: + type: boolean + enabled: + type: boolean + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + select: + properties: + affinity: + type: object + x-kubernetes-preserve-unknown-fields: true + configMaps: + items: + type: string + type: array + containers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + disableAutomountServiceAccountToken: + type: boolean + disableSelfServiceScrape: + type: boolean + dnsConfig: + items: + x-kubernetes-preserve-unknown-fields: true + properties: + nameservers: + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + dnsPolicy: + type: string + extraArgs: + additionalProperties: + type: string + type: object + extraEnvs: + items: + properties: + name: + type: string + value: + type: string + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + extraEnvsFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + extraStorageNodes: + items: + properties: + addr: + type: string + required: + - addr + type: object + type: array + host_aliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostNetwork: + type: boolean + hpa: + type: object + x-kubernetes-preserve-unknown-fields: true + image: + properties: + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + livenessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + logFormat: + enum: + - default + - json + type: string + logLevel: + enum: + - INFO + - WARN + - ERROR + - FATAL + - PANIC + type: string + minReadySeconds: + format: int32 + type: integer + nodeSelector: + additionalProperties: + type: string + type: object + paused: + type: boolean + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + selectorLabels: + additionalProperties: + type: string + type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string + type: object + podMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + port: + type: string + priorityClassName: + type: string + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + readinessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + replicaCount: + format: int32 + type: integer + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + revisionHistoryLimitCount: + format: int32 + type: integer + rollingUpdate: + properties: + maxSurge: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + runtimeClassName: + type: string + schedulerName: + type: string + secrets: + items: + type: string + type: array + securityContext: + type: object + x-kubernetes-preserve-unknown-fields: true + serviceScrapeSpec: + required: + - endpoints + type: object + x-kubernetes-preserve-unknown-fields: true + serviceSpec: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + useAsDefault: + type: boolean + required: + - spec + type: object + startupProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + updateStrategy: + enum: + - Recreate + - RollingUpdate + type: string + useDefaultResources: + type: boolean + useStrictSecurity: + type: boolean + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + vpa: + properties: + recommenders: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + resourcePolicy: + properties: + containerPolicies: + items: + properties: + containerName: + type: string + controlledResources: + items: + type: string + type: array + controlledValues: + enum: + - RequestsAndLimits + - RequestsOnly + type: string + maxAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + minAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + mode: + enum: + - Auto + - "Off" + type: string + type: object + type: array + type: object + updatePolicy: + properties: + evictionRequirements: + items: + properties: + changeRequirement: + enum: + - TargetHigherThanRequests + - TargetLowerThanRequests + type: string + resources: + items: + type: string + type: array + required: + - changeRequirement + - resources + type: object + type: array + minReplicas: + format: int32 + type: integer + updateMode: + enum: + - "Off" + - Initial + - Recreate + - InPlaceOrRecreate + - Auto + type: string + type: object + type: object + type: object + serviceAccountName: + type: string + storage: + properties: + affinity: + type: object + x-kubernetes-preserve-unknown-fields: true + claimTemplates: + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + configMaps: + items: + type: string + type: array + containers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + disableAutomountServiceAccountToken: + type: boolean + disableSelfServiceScrape: + type: boolean + dnsConfig: + items: + x-kubernetes-preserve-unknown-fields: true + properties: + nameservers: + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + dnsPolicy: + type: string + extraArgs: + additionalProperties: + type: string + type: object + extraEnvs: + items: + properties: + name: + type: string + value: + type: string + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + extraEnvsFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + futureRetention: + pattern: ^[0-9]+(h|d|w|y)?$ + type: string + host_aliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostNetwork: + type: boolean + hpa: + properties: + behaviour: + properties: + scaleDown: + properties: + policies: + items: + properties: + periodSeconds: + format: int32 + type: integer + type: + type: string + value: + format: int32 + type: integer + required: + - periodSeconds + - type + - value + type: object + type: array + x-kubernetes-list-type: atomic + selectPolicy: + type: string + stabilizationWindowSeconds: + format: int32 + type: integer + tolerance: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + scaleUp: + properties: + policies: + items: + properties: + periodSeconds: + format: int32 + type: integer + type: + type: string + value: + format: int32 + type: integer + required: + - periodSeconds + - type + - value + type: object + type: array + x-kubernetes-list-type: atomic + selectPolicy: + type: string + stabilizationWindowSeconds: + format: int32 + type: integer + tolerance: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + maxReplicas: + format: int32 + type: integer + metrics: + items: + properties: + containerResource: + properties: + container: + type: string + name: + type: string + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - container + - name + - target + type: object + external: + properties: + metric: + properties: + name: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - metric + - target + type: object + object: + properties: + describedObject: + properties: + apiVersion: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + metric: + properties: + name: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - describedObject + - metric + - target + type: object + pods: + properties: + metric: + properties: + name: + type: string + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + required: + - name + type: object + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - metric + - target + type: object + resource: + properties: + name: + type: string + target: + properties: + averageUtilization: + format: int32 + type: integer + averageValue: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: + type: string + value: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + required: + - type + type: object + required: + - name + - target + type: object + type: + type: string + required: + - type + type: object + type: array + minReplicas: + format: int32 + type: integer + type: object + image: + properties: + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + livenessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + logFormat: + enum: + - default + - json + type: string + logIngestedRows: + type: boolean + logLevel: + enum: + - INFO + - WARN + - ERROR + - FATAL + - PANIC + type: string + logNewStreams: + type: boolean + maintenanceInsertNodeIDs: + items: + format: int32 + type: integer + type: array + maintenanceSelectNodeIDs: + items: + format: int32 + type: integer + type: array + minReadySeconds: + format: int32 + type: integer + nodeSelector: + additionalProperties: + type: string + type: object + paused: + type: boolean + persistentVolumeClaimRetentionPolicy: + properties: + whenDeleted: + type: string + whenScaled: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + selectorLabels: + additionalProperties: + type: string + type: object + unhealthyPodEvictionPolicy: + enum: + - IfHealthyBudget + - AlwaysAllow + type: string + type: object + podMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + port: + type: string + priorityClassName: + type: string + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + readinessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + replicaCount: + format: int32 + type: integer + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + retentionMaxDiskSpaceUsageBytes: + type: string + retentionPeriod: + pattern: ^[0-9]+(h|d|w|y)?$ + type: string + revisionHistoryLimitCount: + format: int32 + type: integer + rollingUpdateStrategy: + type: string + rollingUpdateStrategyBehavior: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + runtimeClassName: + type: string + schedulerName: + type: string + secrets: + items: + type: string + type: array + securityContext: + type: object + x-kubernetes-preserve-unknown-fields: true + serviceScrapeSpec: + required: + - endpoints + type: object + x-kubernetes-preserve-unknown-fields: true + serviceSpec: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + useAsDefault: + type: boolean + required: + - spec + type: object + startupProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + storage: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + volumeClaimTemplate: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + storageDataPath: + type: string + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + useDefaultResources: + type: boolean + useStrictSecurity: + type: boolean + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + vpa: + properties: + recommenders: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + resourcePolicy: + properties: + containerPolicies: + items: + properties: + containerName: + type: string + controlledResources: + items: + type: string + type: array + controlledValues: + enum: + - RequestsAndLimits + - RequestsOnly + type: string + maxAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + minAllowed: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + mode: + enum: + - Auto + - "Off" + type: string + type: object + type: array + type: object + updatePolicy: + properties: + evictionRequirements: + items: + properties: + changeRequirement: + enum: + - TargetHigherThanRequests + - TargetLowerThanRequests + type: string + resources: + items: + type: string + type: array + required: + - changeRequirement + - resources + type: object + type: array + minReplicas: + format: int32 + type: integer + updateMode: + enum: + - "Off" + - Initial + - Recreate + - InPlaceOrRecreate + - Auto + type: string + type: object + type: object + type: object + useStrictSecurity: + type: boolean + type: object + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + maxLength: 32768 + type: string + observedGeneration: + format: int64 + minimum: 0 + type: integer + reason: + maxLength: 1024 + minLength: 1 + type: string + status: + enum: + - "True" + - "False" + - Unknown + type: string + type: + maxLength: 316 + type: string + required: + - lastTransitionTime + - lastUpdateTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + format: int64 + type: integer + reason: + type: string + updateStatus: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.0 + name: vtsingles.operator.victoriametrics.com +spec: + group: operator.victoriametrics.com + names: + kind: VTSingle + listKind: VTSingleList + plural: vtsingles + singular: vtsingle + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Current status of traces instance update process + jsonPath: .status.status + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + affinity: + type: object + x-kubernetes-preserve-unknown-fields: true + configMaps: + items: + type: string + type: array + containers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + disableAutomountServiceAccountToken: + type: boolean + disableSelfServiceScrape: + type: boolean + dnsConfig: + items: + x-kubernetes-preserve-unknown-fields: true + properties: + nameservers: + items: + type: string + type: array + x-kubernetes-list-type: atomic + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + x-kubernetes-list-type: atomic + searches: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + dnsPolicy: + type: string + extraArgs: + additionalProperties: + type: string + type: object + extraEnvs: + items: + properties: + name: + type: string + value: + type: string + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + extraEnvsFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + futureRetention: + pattern: ^[0-9]+(h|d|y)?$ + type: string + host_aliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + required: + - ip + type: object + type: array + hostNetwork: + type: boolean + image: + properties: + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + imagePullSecrets: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + livenessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + logFormat: + enum: + - default + - json + type: string + logIngestedRows: + type: boolean + logLevel: + enum: + - INFO + - WARN + - ERROR + - FATAL + - PANIC + type: string + logNewStreams: + type: boolean + managedMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + minReadySeconds: + format: int32 + type: integer + nodeSelector: + additionalProperties: + type: string + type: object + paused: + type: boolean + podMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + port: + type: string + priorityClassName: + type: string + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + readinessProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + replicaCount: + format: int32 + type: integer + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + retentionMaxDiskSpaceUsageBytes: + type: string + retentionPeriod: + pattern: ^[0-9]+(h|d|w|y)?$ + type: string + revisionHistoryLimitCount: + format: int32 + type: integer + runtimeClassName: + type: string + schedulerName: + type: string + secrets: + items: + type: string + type: array + securityContext: + type: object + x-kubernetes-preserve-unknown-fields: true + serviceAccountName: + type: string + serviceScrapeSpec: + required: + - endpoints + type: object + x-kubernetes-preserve-unknown-fields: true + serviceSpec: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + useAsDefault: + type: boolean + required: + - spec + type: object + startupProbe: + type: object + x-kubernetes-preserve-unknown-fields: true + storage: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + 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 + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + storageDataPath: + type: string + storageMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + name: + type: string + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + useDefaultResources: + type: boolean + useStrictSecurity: + type: boolean + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + items: + required: + - name + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + type: object + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + maxLength: 32768 + type: string + observedGeneration: + format: int64 + minimum: 0 + type: integer + reason: + maxLength: 1024 + minLength: 1 + type: string + status: + enum: + - "True" + - "False" + - Unknown + type: string + type: + maxLength: 316 + type: string + required: + - lastTransitionTime + - lastUpdateTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + format: int64 + type: integer + reason: + type: string + updateStatus: type: string type: object type: object diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/files/crd.yaml.bz2 b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/files/crd.yaml.bz2 new file mode 100644 index 00000000..ab7c4d95 Binary files /dev/null and b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/files/crd.yaml.bz2 differ diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/templates/_helpers.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/templates/_helpers.yaml new file mode 100644 index 00000000..65e96fc6 --- /dev/null +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/templates/_helpers.yaml @@ -0,0 +1,13 @@ +{{- define "crds.upgrade.name" -}} +{{- print (include "vm.plain.fullname" .) "-upgrade-crds" }} +{{- end -}} + +{{- define "crds.upgrade.serviceAccountName" -}} +{{- $Values := (.helm).Values | default .Values }} +{{- $upgrade := $Values.upgrade }} +{{- if $upgrade.serviceAccount.create -}} + {{ default (include "crds.upgrade.name" .) $upgrade.serviceAccount.name }} +{{- else -}} + {{ default "default" $upgrade.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/templates/cm.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/templates/cm.yaml new file mode 100644 index 00000000..40cd8ed5 --- /dev/null +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/templates/cm.yaml @@ -0,0 +1,18 @@ +{{- if .Values.upgrade.enabled }} +{{- $ctx := dict "helm" . }} +{{- $upgrade := .Values.upgrade }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "crds.upgrade.serviceAccountName" $ctx }} + namespace: {{ template "vm.namespace" $ctx }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,pre-rollback + "helm.sh/hook-weight": "-2" + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + {{- $_ := set $ctx "extraLabels" (dict "app.kubernetes.io/component" "upgrade-crds") }} + labels: {{ include "vm.labels" $ctx | nindent 4 }} + {{- $_ := unset $ctx "extraLabels" }} +binaryData: + crd.yaml.bz2: {{ .Files.Get "files/crd.yaml.bz2" | b64enc }} +{{- end }} diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/templates/job.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/templates/job.yaml new file mode 100644 index 00000000..2884157f --- /dev/null +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/templates/job.yaml @@ -0,0 +1,126 @@ +{{- if .Values.upgrade.enabled }} +{{- $app := .Values.upgrade }} +{{- if empty (($app.kubectl).image).tag }} + {{- $tag := regexSplit "[+-]" .Capabilities.KubeVersion.Version -1 | first -}} + {{- $_ := set $app.kubectl.image "tag" $tag }} +{{- else if not (kindIs "string" (($app.kubectl).image).tag) }} + {{- fail "`crd.upgrade.kubectl.image.tag` is not string, most probably you need to enquote provided value" -}} +{{- end }} +{{- $ctx := dict "helm" . "noEnterprise" true }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "crds.upgrade.name" $ctx }} + namespace: {{ template "vm.namespace" $ctx }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,pre-rollback + "helm.sh/hook-weight": "5" + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + {{- with $app.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- $extraLabels := $app.labels | default dict }} + {{- $_ := set $ctx "extraLabels" $app.labels }} + {{- $_ := set $extraLabels "app.kubernetes.io/component" "upgrade-crds" }} + {{- $_ := set $ctx "extraLabels" $extraLabels }} + labels: {{ include "vm.labels" $ctx | nindent 4 }} + {{- $_ := unset $ctx "extraLabels" }} +spec: + backoffLimit: 3 + template: + metadata: + {{- with $app.podLabels }} + labels: {{ toYaml . | nindent 8 }} + {{- end }} + {{- with $app.podAnnotations }} + annotations: {{ toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with (.Values.imagePullSecrets | default (.Values.global).imagePullSecrets) }} + imagePullSecrets: {{ toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "crds.upgrade.serviceAccountName" . }} + {{- if ($app.podSecurityContext).enabled }} + securityContext: {{ include "vm.securityContext" (dict "securityContext" $app.podSecurityContext "helm" .) | nindent 8 }} + {{- end }} + initContainers: + - name: busybox + {{- $_ := set $ctx "appKey" (list "upgrade" "busybox") }} + image: {{ include "vm.image" $ctx }} + imagePullPolicy: {{ $app.busybox.image.pullPolicy }} + workingDir: /tmp/ + command: + - sh + args: + - -c + - bzcat /crds/crd.yaml.bz2 > /tmp/crd.yaml + {{- with $app.resources }} + resources: {{ toYaml . | nindent 12 }} + {{- end }} + {{- with $app.securityContext }} + securityContext: {{ toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - mountPath: /crds/ + name: crds + - mountPath: /tmp/ + name: tmp + {{- with $app.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with $app.env }} + env: {{ toYaml . | nindent 12 }} + {{- end }} + containers: + - name: kubectl + {{- $_ := set $ctx "appKey" (list "upgrade" "kubectl") }} + image: {{ include "vm.image" $ctx }} + imagePullPolicy: {{ $app.kubectl.image.pullPolicy }} + command: + - kubectl + args: + - apply + - --server-side + {{- if $app.forceConflicts }} + - --force-conflicts + {{- end }} + - --filename + - /tmp/crd.yaml + {{- with $app.resources }} + resources: {{ toYaml . | nindent 12 }} + {{- end }} + {{- with $app.securityContext }} + securityContext: {{ toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - mountPath: /tmp/ + name: tmp + {{- with $app.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with $app.env }} + env: {{ toYaml . | nindent 12 }} + {{- end }} + volumes: + - name: tmp + emptyDir: {} + - name: crds + configMap: + name: {{ template "crds.upgrade.name" . }} + {{- with $app.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: OnFailure + {{- with $app.nodeSelector }} + nodeSelector: {{ toYaml . | nindent 8 }} + {{- end }} + {{- with $app.tolerations }} + tolerations: {{ toYaml . | nindent 8 }} + {{- end }} + {{- with $app.affinity }} + affinity: {{ toYaml . | nindent 8 }} + {{- end }} + {{- with $app.topologySpreadConstraints }} + topologySpreadConstraints: {{ toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/templates/role.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/templates/role.yaml new file mode 100644 index 00000000..7cb71a2d --- /dev/null +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/templates/role.yaml @@ -0,0 +1,52 @@ +{{- if .Values.upgrade.enabled }} +{{- $ctx := dict "helm" . }} +{{- $_ := set $ctx "extraLabels" (dict "app.kubernetes.io/component" "upgrade-crds") }} +{{- $labels := include "vm.labels" $ctx }} +{{- $_ := unset $ctx "extraLabels" }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "crds.upgrade.name" . }} + namespace: {{ template "vm.namespace" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,pre-rollback + "helm.sh/hook-weight": "-5" + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: {{ $labels | nindent 4 }} + {{- $crds := .Files.Get "crds/crd.yaml" | splitList "---" }} +rules: + - apiGroups: + - "apiextensions.k8s.io" + resources: + - "customresourcedefinitions" + verbs: + - create + - patch + - update + - get + - list + resourceNames: + {{- range $crds }} + {{- $crd := fromYaml . }} + - {{ $crd.metadata.name }} + {{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "crds.upgrade.name" . }} + namespace: {{ template "vm.namespace" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,pre-rollback + "helm.sh/hook-weight": "-3" + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: {{ $labels | nindent 4 }} +subjects: + - kind: ServiceAccount + namespace: {{ template "vm.namespace" . }} + name: {{ template "crds.upgrade.serviceAccountName" . }} +roleRef: + kind: ClusterRole + name: {{ template "crds.upgrade.name" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/templates/serviceaccount.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/templates/serviceaccount.yaml new file mode 100644 index 00000000..2fa0dc40 --- /dev/null +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/templates/serviceaccount.yaml @@ -0,0 +1,25 @@ +{{- $upgrade := .Values.upgrade }} +{{- if and $upgrade.enabled $upgrade.serviceAccount.create }} +{{- $ctx := dict "helm" . }} +{{- $fullname := include "vm.plain.fullname" $ctx }} +{{- $ns := include "vm.namespace" $ctx }} +{{- $sa := $upgrade.serviceAccount }} +apiVersion: v1 +kind: ServiceAccount +automountServiceAccountToken: {{ $sa.automountServiceAccountToken }} +metadata: + name: {{ include "crds.upgrade.name" . }} + namespace: {{ $ns }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,pre-rollback + "helm.sh/hook-weight": "-4" + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + {{- with $sa.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- $extraLabels := $sa.labels | default dict }} + {{- $_ := set $extraLabels "app.kubernetes.io/component" "upgrade-crds" }} + {{- $_ := set $ctx "extraLabels" $extraLabels }} + labels: {{ include "vm.labels" $ctx | nindent 4 }} + {{- $_ := unset $ctx "extraLabels" }} +{{- end }} diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/values.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/values.yaml index e69de29b..89715f32 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/values.yaml +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/crds/values.yaml @@ -0,0 +1,17 @@ +upgrade: + enabled: false + serviceAccount: + labels: {} + create: true + forceConflicts: false + busybox: + image: + repository: busybox + tag: latest + pullPolicy: IfNotPresent + kubectl: + image: + repository: rancher/kubectl + # use image tag that matches k8s API version by default + tag: "" + pullPolicy: IfNotPresent diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/.helmignore b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/.helmignore index 2ccbd54f..e7746f26 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/.helmignore +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/.helmignore @@ -20,5 +20,7 @@ .idea/ *.tmproj .vscode/ -*.md *.md.gotmpl +CHANGELOG.md +_changelog.md +_index.md diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/Chart.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/Chart.yaml index a90e9d6e..e8f67b95 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/Chart.yaml +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/Chart.yaml @@ -1,16 +1,21 @@ annotations: artifacthub.io/category: monitoring-logging artifacthub.io/changes: | - - Support custom case for list empty argument. + - reverted usage of `app` label in `vm.selectorLabels` artifacthub.io/license: Apache-2.0 artifacthub.io/links: | - name: Sources url: https://github.com/VictoriaMetrics/helm-charts/tree/master/charts/victoria-metrics-common - name: Charts repo url: https://victoriametrics.github.io/helm-charts/ + artifacthub.io/readme: | + # VictoriaMetrics Common Helm chart + + Chart documentation is available [here](https://docs.victoriametrics.com/helm/victoria-metrics-common/). + Changelog is [here](https://docs.victoriametrics.com/helm/victoria-metrics-common/changelog/). apiVersion: v2 -description: Victoria Metrics Common - contains shared templates for all Victoria - Metrics helm charts +description: VictoriaMetrics Common - contains shared templates for all Victoria Metrics + helm charts keywords: - victoriametrics - monitoring @@ -25,4 +30,4 @@ name: victoria-metrics-common sources: - https://github.com/VictoriaMetrics/helm-charts type: library -version: 0.0.42 +version: 0.3.0 diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/README.md b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/README.md new file mode 100644 index 00000000..c8ee7051 --- /dev/null +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/README.md @@ -0,0 +1,4 @@ +# VictoriaMetrics Common Helm chart + +Chart documentation is available [here](https://docs.victoriametrics.com/helm/victoria-metrics-common/). +Changelog is [here](https://docs.victoriametrics.com/helm/victoria-metrics-common/changelog/). diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/RELEASE_NOTES b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/RELEASE_NOTES index 6de533d6..ad0cdfa9 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/RELEASE_NOTES +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/RELEASE_NOTES @@ -1,7 +1,7 @@ -# Release notes for version 0.0.42 +# Release notes for version 0.3.0 -**Release date:** 19 Mar 2025 +**Release date:** 16 Apr 2026 ![Helm: v3](https://img.shields.io/badge/Helm-v3.14%2B-informational?color=informational&logo=helm&link=https%3A%2F%2Fgithub.com%2Fhelm%2Fhelm%2Freleases%2Ftag%2Fv3.14.0) -- Support custom case for list empty argument. +- reverted usage of `app` label in `vm.selectorLabels` diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_enterprise.tpl b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_enterprise.tpl index 1890e499..ffdc750d 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_enterprise.tpl +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_enterprise.tpl @@ -36,7 +36,7 @@ {{- if eq (include "vm.enterprise.disabled" .) "true" }} {{ fail `Pass valid license at .Values.license or .Values.global.license if you have an enterprise license for running this software. See https://victoriametrics.com/legal/esa/ for details. - Documentation - https://docs.victoriametrics.com/enterprise + Documentation - https://docs.victoriametrics.com/victoriametrics/enterprise/ for more information, visit https://victoriametrics.com/products/enterprise/ To request a trial license, go to https://victoriametrics.com/products/enterprise/trial/` }} {{- end -}} diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_helpers.tpl b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_helpers.tpl index 7983440f..bd945678 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_helpers.tpl +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_helpers.tpl @@ -125,8 +125,8 @@ If release name contains chart name it will be used as a full name. {{- $ctx := . -}} {{- $values := $Values -}} {{- range $ak := $appKey }} - {{- $values = ternary (default dict) (index $values $ak | default dict) (empty $values) -}} - {{- $ctx = ternary (default dict) (index $ctx $ak | default dict) (empty $ctx) -}} + {{- $values = ternary (dict) (index $values $ak | default dict) (empty $values) -}} + {{- $ctx = ternary (dict) (index $ctx $ak | default dict) (empty $ctx) -}} {{- if and (empty $values) (empty $ctx) -}} {{- fail (printf "No data for appKey %s" (join "->" $appKey)) -}} {{- end -}} @@ -187,6 +187,9 @@ If release name contains chart name it will be used as a full name. {{- include "vm.validate.args" . -}} {{- $Release := (.helm).Release | default .Release -}} {{- $labels := fromYaml (include "vm.selectorLabels" .) -}} + {{- with $labels.app -}} + {{- $_ := set $labels "app.kubernetes.io/component" . -}} + {{- end -}} {{- $labels = mergeOverwrite $labels (.extraLabels | default dict) -}} {{- $_ := set $labels "app.kubernetes.io/managed-by" $Release.Service -}} {{- toYaml $labels -}} @@ -195,8 +198,10 @@ If release name contains chart name it will be used as a full name. {{- /* Common labels */ -}} {{- define "vm.labels" -}} {{- include "vm.validate.args" . -}} - {{- $labels := fromYaml (include "vm.selectorLabels" .) -}} - {{- $labels = mergeOverwrite $labels (fromYaml (include "vm.metaLabels" .)) -}} + {{- $Values := (.helm).Values | default .Values -}} + {{- $globalLabels := deepCopy (($Values.global).extraLabels | default dict) -}} + {{- $labels := fromYaml (include "vm.commonLabels" .) -}} + {{- $labels = mergeOverwrite $globalLabels $labels (fromYaml (include "vm.metaLabels" .)) -}} {{- with (include "vm.image.tag" .) }} {{- $_ := set $labels "app.kubernetes.io/version" (regexReplaceAll "(.*)(@sha.*)" . "${1}") -}} {{- end -}} @@ -229,11 +234,16 @@ If release name contains chart name it will be used as a full name. {{- $_ := set $labels "app.kubernetes.io/name" (include "vm.name" .) -}} {{- $_ := set $labels "app.kubernetes.io/instance" (include "vm.release" .) -}} {{- with (include "vm.app.name" .) -}} - {{- if eq $.style "managed" -}} - {{- $_ := set $labels "app.kubernetes.io/component" (printf "%s-%s" (include "vm.name" $) .) -}} - {{- else -}} - {{- $_ := set $labels "app" . -}} - {{- end -}} + {{- $_ := set $labels "app" . -}} {{- end -}} {{- toYaml $labels -}} {{- end }} + +{{- define "vm.commonLabels" -}} + {{- $labels := fromYaml (include "vm.selectorLabels" . ) -}} + {{- with $labels.app -}} + {{- $_ := set $labels "app.kubernetes.io/component" . -}} + {{- $_ := unset $labels "app" -}} + {{- end -}} + {{- toYaml $labels -}} +{{- end -}} diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_image.tpl b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_image.tpl index cae561dd..66d019e3 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_image.tpl +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_image.tpl @@ -42,14 +42,14 @@ Victoria Metrics Image {{- with .appKey -}} {{- $appKey := ternary (list .) . (kindIs "string" .) -}} {{- range $ak := $appKey -}} - {{- $values = ternary (default dict) (index $values $ak | default dict) (empty $values) -}} - {{- $ctx = ternary (default dict) (index $ctx $ak | default dict) (empty $ctx) -}} + {{- $values = ternary (dict) (index $values $ak | default dict) (empty $values) -}} + {{- $ctx = ternary (dict) (index $ctx $ak | default dict) (empty $ctx) -}} {{- if and (empty $values) (empty $ctx) -}} {{- fail (printf "No data for appKey %s" (join "->" $appKey)) -}} {{- end -}} {{- end -}} {{- end -}} - {{- $image := ternary $ctx.image $values.image (hasKey $ctx "image") -}} + {{- $image := ternary (deepCopy ($ctx.image | default dict)) (deepCopy ($values.image | default dict)) (hasKey $ctx "image") -}} {{- if not $image.registry }} {{- if (($Values.global).image).registry -}} {{- $_ := set $image "registry" (($Values.global).image).registry -}} diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_pod.tpl b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_pod.tpl index 7534ae2d..62981dfb 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_pod.tpl +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_pod.tpl @@ -39,9 +39,9 @@ Render probe {{- define "vm.probe" -}} {{- /* undefined value */ -}} {{- $null := (fromYaml "value: null").value -}} - {{- $probe := dig .type (default dict) .app.probe -}} + {{- $probe := dig .type (dict) .app.probe -}} {{- $probeType := "" -}} - {{- $defaultProbe := default dict -}} + {{- $defaultProbe := dict -}} {{- if ne (dig "httpGet" $null $probe) $null -}} {{- /* httpGet probe */ -}} {{- $defaultProbe = dict "path" (include "vm.probe.http.path" .) "scheme" (include "vm.probe.http.scheme" .) "port" (include "vm.probe.port" .) -}} @@ -51,7 +51,7 @@ Render probe {{- $defaultProbe = dict "port" (include "vm.probe.port" .) -}} {{- $probeType = "tcpSocket" -}} {{- end -}} - {{- $defaultProbe = ternary (default dict) (dict $probeType $defaultProbe) (empty $probeType) -}} + {{- $defaultProbe = ternary (dict) (dict $probeType $defaultProbe) (empty $probeType) -}} {{- $probe = mergeOverwrite $defaultProbe $probe -}} {{- range $key, $value := $probe -}} {{- if and (has (kindOf $value) (list "object" "map")) (ne $key $probeType) -}} @@ -100,7 +100,7 @@ Net probe port command line arguments */ -}} {{- define "vm.args" -}} - {{- $args := default list -}} + {{- $args := list -}} {{- range $key, $value := . -}} {{- if not $key -}} {{- fail "Empty key in command line args is not allowed" -}} diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_service.tpl b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_service.tpl index 77a1365f..77cdeee7 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_service.tpl +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/charts/victoria-metrics-common/templates/_service.tpl @@ -37,10 +37,10 @@ {{- $values := $Values -}} {{- $ctx := . -}} {{- range $ak := $appKey -}} - {{- $values = ternary (default dict) (index $values $ak | default dict) (empty $values) -}} - {{- $ctx = ternary (default dict) (index $ctx $ak | default dict) (empty $ctx) -}} + {{- $values = ternary (dict) (index $values $ak | default dict) (empty $values) -}} + {{- $ctx = ternary (dict) (index $ctx $ak | default dict) (empty $ctx) -}} {{- end -}} - {{- $spec := default dict -}} + {{- $spec := dict -}} {{- if $ctx -}} {{- $spec = $ctx -}} {{- else if $values -}} @@ -69,10 +69,10 @@ {{- $values := $Values -}} {{- $ctx := . -}} {{- range $ak := $appKey -}} - {{- $values = ternary (default dict) (index $values $ak | default dict) (empty $values) -}} - {{- $ctx = ternary (default dict) (index $ctx $ak | default dict) (empty $ctx) -}} + {{- $values = ternary (dict) (index $values $ak | default dict) (empty $values) -}} + {{- $ctx = ternary (dict) (index $ctx $ak | default dict) (empty $ctx) -}} {{- end -}} - {{- $spec := default dict -}} + {{- $spec := dict -}} {{- if $values -}} {{- $spec = $values -}} {{- else if $ctx -}} diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/crd.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/crd.yaml index 038cc276..d54c82eb 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/crd.yaml +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/crd.yaml @@ -2,7 +2,218 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 + name: vlagents.operator.victoriametrics.com +spec: + group: operator.victoriametrics.com + names: + kind: VLAgent + listKind: VLAgentList + plural: vlagents + singular: vlagent + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: current number of replicas + jsonPath: .status.replicas + name: Replica Count + type: integer + - description: Current status of update rollout + jsonPath: .status.updateStatus + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + required: + - remoteWrite + type: object + x-kubernetes-preserve-unknown-fields: true + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + maxLength: 32768 + type: string + observedGeneration: + format: int64 + minimum: 0 + type: integer + reason: + maxLength: 1024 + minLength: 1 + type: string + status: + enum: + - "True" + - "False" + - Unknown + type: string + type: + maxLength: 316 + type: string + required: + - lastTransitionTime + - lastUpdateTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + format: int64 + type: integer + reason: + type: string + replicas: + format: int32 + type: integer + selector: + type: string + updateStatus: + type: string + type: object + type: object + served: true + storage: true + subresources: + scale: + labelSelectorPath: .status.selector + specReplicasPath: .spec.shardCount + statusReplicasPath: .status.shards + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.0 + name: vlclusters.operator.victoriametrics.com +spec: + group: operator.victoriametrics.com + names: + kind: VLCluster + listKind: VLClusterList + plural: vlclusters + singular: vlcluster + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: replicas of VLInsert + jsonPath: .spec.vlinsert.replicaCount + name: Insert Count + type: string + - description: replicas of VLStorage + jsonPath: .spec.vlstorage.replicaCount + name: Storage Count + type: string + - description: replicas of VLSelect + jsonPath: .spec.vlselect.replicaCount + name: Select Count + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Current status of cluster + jsonPath: .status.updateStatus + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + maxLength: 32768 + type: string + observedGeneration: + format: int64 + minimum: 0 + type: integer + reason: + maxLength: 1024 + minLength: 1 + type: string + status: + enum: + - "True" + - "False" + - Unknown + type: string + type: + maxLength: 316 + type: string + required: + - lastTransitionTime + - lastUpdateTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + format: int64 + type: integer + reason: + type: string + updateStatus: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.0 name: vlogs.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -24,1041 +235,47 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: |- - VLogs is fast, cost-effective and scalable logs database. - VLogs is the Schema for the vlogs API 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: VLogsSpec defines the desired state of VLogs - properties: - affinity: - description: Affinity If specified, the pod's scheduling constraints. - type: object - x-kubernetes-preserve-unknown-fields: true - configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder - items: - type: string - type: array - containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. - items: - description: A single application container that you want to run - within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. - type: boolean - disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable - type: boolean - dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. - items: - x-kubernetes-preserve-unknown-fields: true - properties: - nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. - items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. - properties: - name: - description: |- - Name is this DNS resolver option's name. - Required. - type: string - value: - description: Value is this DNS resolver option's value. - type: string - type: object - type: array - x-kubernetes-list-type: atomic - searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - dnsPolicy: - description: DNSPolicy sets DNS policy for the pod - type: string - extraArgs: - additionalProperties: - type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp - type: object - extraEnvs: - description: ExtraEnvs that will be passed to the application container - items: - description: EnvVar represents an environment variable present in - a Container. - properties: - name: - description: Name of the environment variable. Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap - items: - description: EnvFromSource represents the source of a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - futureRetention: - description: |- - FutureRetention for the stored logs - Log entries with timestamps bigger than now+futureRetention are rejected during data ingestion; see https://docs.victoriametrics.com/victorialogs/#retention - type: string - host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostNetwork: - description: HostNetwork controls whether the pod may use the node - network namespace - type: boolean - image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config - properties: - pullPolicy: - description: PullPolicy describes how to pull docker image - type: string - repository: - description: Repository contains name of docker image + it's repository - if needed - type: string - tag: - description: Tag contains desired docker image version - type: string - type: object - imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - items: - description: A single application container that you want to run - within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - livenessProbe: - description: LivenessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - logFormat: - description: LogFormat for VLogs to be configured with. - enum: - - default - - json - type: string - logIngestedRows: - description: Whether to log all the ingested log entries; this can - be useful for debugging of data ingestion; see https://docs.victoriametrics.com/victorialogs/data-ingestion/ - type: boolean - logLevel: - description: LogLevel for VictoriaLogs to be configured with. - enum: - - INFO - - WARN - - ERROR - - FATAL - - PANIC - type: string - logNewStreams: - description: LogNewStreams Whether to log creation of new streams; - this can be useful for debugging of high cardinality issues with - log streams; see https://docs.victoriametrics.com/victorialogs/keyconcepts/#stream-fields - type: boolean - managedMetadata: - description: |- - ManagedMetadata defines metadata that will be added to the all objects - created by operator for the given CustomResource - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - type: object - minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle - format: int32 - type: integer - nodeSelector: - additionalProperties: - type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. - type: object - paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. - type: boolean - podMetadata: - description: PodMetadata configures Labels and Annotations which are - propagated to the VLogs pods. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - port: - description: Port listen address - type: string - priorityClassName: - description: PriorityClassName class assigned to the Pods - type: string - readinessGates: - description: ReadinessGates defines pod readiness gates - items: - description: PodReadinessGate contains the reference to a pod condition - properties: - conditionType: - description: ConditionType refers to a condition in the pod's - condition list with matching type. - type: string - required: - - conditionType - type: object - type: array - readinessProbe: - description: ReadinessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - removePvcAfterDelete: - description: |- - RemovePvcAfterDelete - if true, controller adds ownership to pvc - and after VLogs object deletion - pvc will be garbage collected - by controller manager - type: boolean - replicaCount: - description: ReplicaCount is the expected size of the Application. - format: int32 - type: integer - resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - retentionPeriod: - description: RetentionPeriod for the stored logs - type: string - revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. - format: int32 - type: integer - runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ - type: string - schedulerName: - description: SchedulerName - defines kubernetes scheduler name - type: string - secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder - items: - type: string - type: array - securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. - type: object - x-kubernetes-preserve-unknown-fields: true - serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to use to run the pods - type: string - serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vlogs VMServiceScrape - spec - required: - - endpoints - type: object - x-kubernetes-preserve-unknown-fields: true - serviceSpec: - description: ServiceSpec that will be added to vlogs service spec - properties: - metadata: - description: EmbeddedObjectMetadata defines objectMeta for additional - service. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ - type: object - x-kubernetes-preserve-unknown-fields: true - useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication - type: boolean - required: - - spec - type: object - startupProbe: - description: StartupProbe that will be added to CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - storage: - description: |- - Storage is the definition of how storage will be used by the VLogs - by default it`s empty dir - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes to consider - for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to the PersistentVolume - backing this claim. - type: string - type: object - storageDataPath: - description: |- - StorageDataPath disables spec.storage option and overrides arg for victoria-logs binary --storageDataPath, - its users responsibility to mount proper device into given path. - type: string - storageMetadata: - description: StorageMeta defines annotations and labels attached to - PVC for given vlogs CR - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container graceful - termination - format: int64 - type: integer - tolerations: - description: Tolerations If specified, the pod's tolerations. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - items: - description: TopologySpreadConstraint specifies how to spread matching - pods among the given topology. - required: - - maxSkew - - topologyKey - - whenUnsatisfiable - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements - type: boolean - useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions - type: boolean - volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container - items: - description: VolumeMount describes a mounting of a Volume within - a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional - items: - description: Volume represents a named volume in a pod that may - be accessed by any container in the pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array required: - retentionPeriod type: object + x-kubernetes-preserve-unknown-fields: true status: - description: VLogsStatus defines the observed state of VLogs properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -1073,16 +290,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -1095,7 +307,99 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 + name: vlsingles.operator.victoriametrics.com +spec: + group: operator.victoriametrics.com + names: + kind: VLSingle + listKind: VLSingleList + plural: vlsingles + singular: vlsingle + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Current status of logs instance update process + jsonPath: .status.status + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + maxLength: 32768 + type: string + observedGeneration: + format: int64 + minimum: 0 + type: integer + reason: + maxLength: 1024 + minLength: 1 + type: string + status: + enum: + - "True" + - "False" + - Unknown + type: string + type: + maxLength: 316 + type: string + required: + - lastTransitionTime + - lastUpdateTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + format: int64 + type: integer + reason: + type: string + updateStatus: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.0 name: vmagents.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -1125,4677 +429,47 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: |- - VMAgent - is a tiny but brave agent, which helps you collect metrics from various sources and stores them in VictoriaMetrics - or any other Prometheus-compatible storage system that supports the remote_write protocol. 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: VMAgentSpec defines the desired state of VMAgent - properties: - aPIServerConfig: - description: |- - APIServerConfig allows specifying a host and auth methods to access apiserver. - If left empty, VMAgent is assumed to run inside of the cluster - and will discover API servers automatically and use the pod's CA certificate - and bearer token file at /var/run/secrets/kubernetes.io/serviceaccount/. - aPIServerConfig is deprecated use apiServerConfig instead - required: - - host - type: object - x-kubernetes-preserve-unknown-fields: true - additionalScrapeConfigs: - description: |- - AdditionalScrapeConfigs As scrape configs are appended, the user is responsible to make sure it - is valid. Note that using this feature may expose the possibility to - break upgrades of VMAgent. It is advised to review VMAgent release - notes to ensure that no incompatible scrape configs are going to break - VMAgent after the upgrade. - properties: - key: - description: The key of the secret to select from. Must be a - valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - affinity: - description: Affinity If specified, the pod's scheduling constraints. - type: object - x-kubernetes-preserve-unknown-fields: true - apiServerConfig: - description: |- - APIServerConfig allows specifying a host and auth methods to access apiserver. - If left empty, VMAgent is assumed to run inside of the cluster - and will discover API servers automatically and use the pod's CA certificate - and bearer token file at /var/run/secrets/kubernetes.io/serviceaccount/. - properties: - authorization: - description: Authorization configures generic authorization params - properties: - credentials: - description: Reference to the secret with value for authorization - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to bearer - type: string - type: object - basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearerToken: - description: Bearer token for accessing apiserver. - type: string - bearerTokenFile: - description: File to read bearer token for accessing apiserver. - type: string - host: - description: |- - Host of apiserver. - A valid string consisting of a hostname or IP followed by an optional port number - type: string - tlsConfig: - description: TLSConfig Config to use for accessing apiserver. - properties: - ca: - description: Struct containing the CA cert to use for the - targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container to use for - the targets. - type: string - cert: - description: Struct containing the client cert file for the - targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container - for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container - for the targets. - type: string - keySecret: - description: Secret containing the client key file for the - targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - required: - - host - type: object - arbitraryFSAccessThroughSMs: - description: |- - ArbitraryFSAccessThroughSMs configures whether configuration - based on EndpointAuth can access arbitrary files on the file system - of the VMAgent container e.g. bearer token files, basic auth, tls certs - properties: - deny: - type: boolean - type: object - claimTemplates: - description: ClaimTemplates allows adding additional VolumeClaimTemplates - for VMAgent in StatefulMode - items: - description: PersistentVolumeClaim is a user's request for and claim - to a persistent volume - 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: - description: |- - Standard object's metadata. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - type: object - x-kubernetes-preserve-unknown-fields: true - spec: - description: |- - spec defines the desired characteristics of a volume requested by a pod author. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes to consider - for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to the - PersistentVolume backing this claim. - type: string - type: object - status: - description: |- - status represents the current information/status of a persistent volume claim. - Read-only. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the actual access modes the volume backing the PVC has. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - allocatedResourceStatuses: - additionalProperties: - description: |- - When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource - that it does not recognizes, then it should ignore that update and let other controllers - handle it. - type: string - description: "allocatedResourceStatuses stores status of - resource being resized for the given PVC.\nKey names follow - standard Kubernetes label syntax. Valid values are either:\n\t* - Un-prefixed keys:\n\t\t- storage - the capacity of the - volume.\n\t* Custom resources must use implementation-defined - prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not be used.\n\nClaimResourceStatus - can be in any of following states:\n\t- ControllerResizeInProgress:\n\t\tState - set when resize controller starts resizing the volume - in control-plane.\n\t- ControllerResizeFailed:\n\t\tState - set when resize has failed in resize controller with a - terminal error.\n\t- NodeResizePending:\n\t\tState set - when resize controller has finished resizing the volume - but further resizing of\n\t\tvolume is needed on the node.\n\t- - NodeResizeInProgress:\n\t\tState set when kubelet starts - resizing the volume.\n\t- NodeResizeFailed:\n\t\tState - set when resizing has failed in kubelet with a terminal - error. Transient errors don't set\n\t\tNodeResizeFailed.\nFor - example: if expanding a PVC for more capacity - this field - can be one of the following states:\n\t- pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeFailed\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizePending\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeFailed\"\nWhen this field is not set, it - means that no resize operation is in progress for the - given PVC.\n\nA controller that receives PVC update with - previously unknown resourceName or ClaimResourceStatus\nshould - ignore the update for the purpose it was designed. For - example - a controller that\nonly is responsible for resizing - capacity of the volume, should ignore PVC updates that - change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." - type: object - x-kubernetes-map-type: granular - allocatedResources: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: "allocatedResources tracks the resources allocated - to a PVC including its capacity.\nKey names follow standard - Kubernetes label syntax. Valid values are either:\n\t* - Un-prefixed keys:\n\t\t- storage - the capacity of the - volume.\n\t* Custom resources must use implementation-defined - prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not be used.\n\nCapacity - reported here may be larger than the actual capacity when - a volume expansion operation\nis requested.\nFor storage - quota, the larger value from allocatedResources and PVC.spec.resources - is used.\nIf allocatedResources is not set, PVC.spec.resources - alone is used for quota calculation.\nIf a volume expansion - capacity request is lowered, allocatedResources is only\nlowered - if there are no expansion operations in progress and if - the actual volume capacity\nis equal or lower than the - requested capacity.\n\nA controller that receives PVC - update with previously unknown resourceName\nshould ignore - the update for the purpose it was designed. For example - - a controller that\nonly is responsible for resizing - capacity of the volume, should ignore PVC updates that - change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." - type: object - capacity: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: capacity represents the actual resources of - the underlying volume. - type: object - conditions: - description: |- - conditions is the current Condition of persistent volume claim. If underlying persistent volume is being - resized then the Condition will be set to 'Resizing'. - items: - description: PersistentVolumeClaimCondition contains details - about state of pvc - properties: - lastProbeTime: - description: lastProbeTime is the time we probed the - condition. - format: date-time - type: string - lastTransitionTime: - description: lastTransitionTime is the time the condition - transitioned from one status to another. - format: date-time - type: string - message: - description: message is the human-readable message - indicating details about last transition. - type: string - reason: - description: |- - reason is a unique, this should be a short, machine understandable string that gives the reason - for condition's last transition. If it reports "Resizing" that means the underlying - persistent volume is being resized. - type: string - status: - description: |- - Status is the status of the condition. - Can be True, False, Unknown. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=state%20of%20pvc-,conditions.status,-(string)%2C%20required - type: string - type: - description: |- - Type is the type of the condition. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=set%20to%20%27ResizeStarted%27.-,PersistentVolumeClaimCondition,-contains%20details%20about - type: string - required: - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - currentVolumeAttributesClassName: - description: |- - currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. - When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - type: string - modifyVolumeStatus: - description: |- - ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. - When this is unset, there is no ModifyVolume operation being attempted. - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - properties: - status: - description: "status is the status of the ControllerModifyVolume - operation. It can be in any of following states:\n - - Pending\n Pending indicates that the PersistentVolumeClaim - cannot be modified due to unmet requirements, such - as\n the specified VolumeAttributesClass not existing.\n - - InProgress\n InProgress indicates that the volume - is being modified.\n - Infeasible\n Infeasible indicates - that the request has been rejected as invalid by the - CSI driver. To\n\t resolve the error, a valid VolumeAttributesClass - needs to be specified.\nNote: New statuses can be - added in the future. Consumers should check for unknown - statuses and fail appropriately." - type: string - targetVolumeAttributesClassName: - description: targetVolumeAttributesClassName is the - name of the VolumeAttributesClass the PVC currently - being reconciled - type: string - required: - - status - type: object - phase: - description: phase represents the current phase of PersistentVolumeClaim. - type: string - type: object - type: object - type: array - configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder - items: - type: string - type: array - configReloaderExtraArgs: - additionalProperties: - type: string - description: |- - ConfigReloaderExtraArgs that will be passed to VMAuths config-reloader container - for example resyncInterval: "30s" - type: object - configReloaderImageTag: - description: ConfigReloaderImageTag defines image:tag for config-reloader - container - type: string - configReloaderResources: - description: |- - ConfigReloaderResources config-reloader container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. - items: - description: A single application container that you want to run - within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - daemonSetMode: - description: |- - DaemonSetMode enables DaemonSet deployment mode instead of Deployment. - Supports only VMPodScrape - (available from v0.55.0). - Cannot be used with statefulMode - type: boolean - disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. - type: boolean - disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable - type: boolean - dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. - items: - x-kubernetes-preserve-unknown-fields: true - properties: - nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. - items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. - properties: - name: - description: |- - Name is this DNS resolver option's name. - Required. - type: string - value: - description: Value is this DNS resolver option's value. - type: string - type: object - type: array - x-kubernetes-list-type: atomic - searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - dnsPolicy: - description: DNSPolicy sets DNS policy for the pod - type: string - enableKubernetesAPISelectors: - description: |- - EnableKubernetesAPISelectors instructs vmagent to use CRD scrape objects spec.selectors for - Kubernetes API list and watch requests. - https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#list-and-watch-filtering - It could be useful to reduce Kubernetes API server resource usage for serving less than 100 CRD scrape objects in total. - type: boolean - enforcedNamespaceLabel: - description: |- - EnforcedNamespaceLabel enforces adding a namespace label of origin for each alert - and metric that is user created. The label value will always be the namespace of the object that is - being created. - type: string - externalLabels: - additionalProperties: - type: string - description: |- - ExternalLabels The labels to add to any time series scraped by vmagent. - it doesn't affect metrics ingested directly by push API's - type: object - extraArgs: - additionalProperties: - type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp - type: object - extraEnvs: - description: ExtraEnvs that will be passed to the application container - items: - description: EnvVar represents an environment variable present in - a Container. - properties: - name: - description: Name of the environment variable. Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap - items: - description: EnvFromSource represents the source of a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostNetwork: - description: HostNetwork controls whether the pod may use the node - network namespace - type: boolean - ignoreNamespaceSelectors: - description: |- - IgnoreNamespaceSelectors if set to true will ignore NamespaceSelector settings from - scrape objects, and they will only discover endpoints - within their current namespace. Defaults to false. - type: boolean - image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config - properties: - pullPolicy: - description: PullPolicy describes how to pull docker image - type: string - repository: - description: Repository contains name of docker image + it's repository - if needed - type: string - tag: - description: Tag contains desired docker image version - type: string - type: object - imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - ingestOnlyMode: - description: |- - IngestOnlyMode switches vmagent into unmanaged mode - it disables any config generation for scraping - Currently it prevents vmagent from managing tls and auth options for remote write - type: boolean - initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - items: - description: A single application container that you want to run - within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - inlineRelabelConfig: - description: InlineRelabelConfig - defines GlobalRelabelConfig for - vmagent, can be defined directly at CRD. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. Default - is 'replace' - type: string - if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source label - values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source label - values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - inlineScrapeConfig: - description: |- - InlineScrapeConfig As scrape configs are appended, the user is responsible to make sure it - is valid. Note that using this feature may expose the possibility to - break upgrades of VMAgent. It is advised to review VMAgent release - notes to ensure that no incompatible scrape configs are going to break - VMAgent after the upgrade. - it should be defined as single yaml file. - inlineScrapeConfig: | - - job_name: "prometheus" - static_configs: - - targets: ["localhost:9090"] - type: string - insertPorts: - description: InsertPorts - additional listen ports for data ingestion. - properties: - graphitePort: - description: GraphitePort listen port - type: string - influxPort: - description: InfluxPort listen port - type: string - openTSDBHTTPPort: - description: OpenTSDBHTTPPort for http connections. - type: string - openTSDBPort: - description: OpenTSDBPort for tcp and udp listen - type: string - type: object - license: - description: |- - License allows to configure license key to be used for enterprise features. - Using license key is supported starting from VictoriaMetrics v1.94.0. - See [here](https://docs.victoriametrics.com/enterprise) - properties: - forceOffline: - description: Enforce offline verification of the license key. - type: boolean - key: - description: |- - Enterprise license key. This flag is available only in [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise). - To request a trial license, [go to](https://victoriametrics.com/products/enterprise/trial) - type: string - keyRef: - description: KeyRef is reference to secret with license key for - enterprise features. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - reloadInterval: - description: Interval to be used for checking for license key - changes. Note that this is only applicable when using KeyRef. - type: string - type: object - livenessProbe: - description: LivenessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - logFormat: - description: LogFormat for VMAgent to be configured with. - enum: - - default - - json - type: string - logLevel: - description: |- - LogLevel for VMAgent to be configured with. - INFO, WARN, ERROR, FATAL, PANIC - enum: - - INFO - - WARN - - ERROR - - FATAL - - PANIC - type: string - managedMetadata: - description: |- - ManagedMetadata defines metadata that will be added to the all objects - created by operator for the given CustomResource - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - type: object - maxScrapeInterval: - description: |- - MaxScrapeInterval allows limiting maximum scrape interval for VMServiceScrape, VMPodScrape and other scrapes - If interval is higher than defined limit, `maxScrapeInterval` will be used. - type: string - minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle - format: int32 - type: integer - minScrapeInterval: - description: |- - MinScrapeInterval allows limiting minimal scrape interval for VMServiceScrape, VMPodScrape and other scrapes - If interval is lower than defined limit, `minScrapeInterval` will be used. - type: string - nodeScrapeNamespaceSelector: - description: |- - NodeScrapeNamespaceSelector defines Namespaces to be selected for VMNodeScrape discovery. - Works in combination with Selector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault - 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 - nodeScrapeRelabelTemplate: - description: |- - NodeScrapeRelabelTemplate defines relabel config, that will be added to each VMNodeScrape. - it's useful for adding specific labels to all targets - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. Default - is 'replace' - type: string - if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source label - values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source label - values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - nodeScrapeSelector: - description: |- - NodeScrapeSelector defines VMNodeScrape to be selected for scraping. - Works in combination with NamespaceSelector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault - 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 - nodeSelector: - additionalProperties: - type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. - type: object - overrideHonorLabels: - description: |- - OverrideHonorLabels if set to true overrides all user configured honor_labels. - If HonorLabels is set in scrape objects to true, this overrides honor_labels to false. - type: boolean - overrideHonorTimestamps: - description: OverrideHonorTimestamps allows to globally enforce honoring - timestamps in all scrape configs. - type: boolean - paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. - type: boolean - podDisruptionBudget: - description: PodDisruptionBudget created by operator - properties: - maxUnavailable: - anyOf: - - type: integer - - type: string - description: |- - An eviction is allowed if at most "maxUnavailable" pods selected by - "selector" are unavailable after the eviction, i.e. even in absence of - the evicted pod. For example, one can prevent all voluntary evictions - by specifying 0. This is a mutually exclusive setting with "minAvailable". - x-kubernetes-int-or-string: true - minAvailable: - anyOf: - - type: integer - - type: string - description: |- - An eviction is allowed if at least "minAvailable" pods selected by - "selector" will still be available after the eviction, i.e. even in the - absence of the evicted pod. So for example you can prevent all voluntary - evictions by specifying "100%". - x-kubernetes-int-or-string: true - selectorLabels: - additionalProperties: - type: string - description: |- - replaces default labels selector generated by operator - it's useful when you need to create custom budget - type: object - type: object - podMetadata: - description: PodMetadata configures Labels and Annotations which are - propagated to the vmagent pods. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - podScrapeNamespaceSelector: - description: |- - PodScrapeNamespaceSelector defines Namespaces to be selected for VMPodScrape discovery. - Works in combination with Selector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault - 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 - podScrapeRelabelTemplate: - description: |- - PodScrapeRelabelTemplate defines relabel config, that will be added to each VMPodScrape. - it's useful for adding specific labels to all targets - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. Default - is 'replace' - type: string - if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source label - values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source label - values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - podScrapeSelector: - description: |- - PodScrapeSelector defines PodScrapes to be selected for target discovery. - Works in combination with NamespaceSelector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault - 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 - port: - description: Port listen address - type: string - priorityClassName: - description: PriorityClassName class assigned to the Pods - type: string - probeNamespaceSelector: - description: |- - ProbeNamespaceSelector defines Namespaces to be selected for VMProbe discovery. - Works in combination with Selector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault - 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 - probeScrapeRelabelTemplate: - description: |- - ProbeScrapeRelabelTemplate defines relabel config, that will be added to each VMProbeScrape. - it's useful for adding specific labels to all targets - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. Default - is 'replace' - type: string - if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source label - values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source label - values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - probeSelector: - description: |- - ProbeSelector defines VMProbe to be selected for target probing. - Works in combination with NamespaceSelector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault - 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 - readinessGates: - description: ReadinessGates defines pod readiness gates - items: - description: PodReadinessGate contains the reference to a pod condition - properties: - conditionType: - description: ConditionType refers to a condition in the pod's - condition list with matching type. - type: string - required: - - conditionType - type: object - type: array - readinessProbe: - description: ReadinessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - relabelConfig: - description: |- - RelabelConfig ConfigMap with global relabel config -remoteWrite.relabelConfig - This relabeling is applied to all the collected metrics before sending them to remote storage. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - remoteWrite: - description: |- - RemoteWrite list of victoria metrics /some other remote write system - for vm it must looks like: http://victoria-metrics-single:8429/api/v1/write - or for cluster different url - https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/app/vmagent#splitting-data-streams-among-multiple-systems - items: - description: VMAgentRemoteWriteSpec defines the remote storage configuration - for VmAgent - properties: - basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearerTokenSecret: - description: Optional bearer auth token to use for -remoteWrite.url - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - forceVMProto: - description: ForceVMProto forces using VictoriaMetrics protocol - for sending data to -remoteWrite.url - type: boolean - headers: - description: |- - Headers allow configuring custom http headers - Must be in form of semicolon separated header with value - e.g. - headerName: headerValue - vmagent supports since 1.79.0 version - items: - type: string - type: array - inlineUrlRelabelConfig: - description: InlineUrlRelabelConfig defines relabeling config - for remoteWriteURL, it can be defined at crd spec. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. - Default is 'replace' - type: string - if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source - label values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source - label values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - maxDiskUsage: - description: |- - MaxDiskUsage defines the maximum file-based buffer size in bytes for the given remoteWrite - It overrides global configuration defined at remoteWriteSettings.maxDiskUsagePerURL - x-kubernetes-preserve-unknown-fields: true - oauth2: - description: OAuth2 defines auth configuration - properties: - client_id: - description: The secret or configmap containing the OAuth2 - client id - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 client secret - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for client secret - file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - sendTimeout: - description: Timeout for sending a single block of data to -remoteWrite.url - (default 1m0s) - pattern: '[0-9]+(ms|s|m|h)' - type: string - streamAggrConfig: - description: StreamAggrConfig defines stream aggregation configuration - for VMAgent for -remoteWrite.url - properties: - configmap: - description: ConfigMap with stream aggregation rules - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - dedupInterval: - description: Allows setting different de-duplication intervals - per each configured remote storage - type: string - dropInput: - description: Allow drop all the input samples after the - aggregation - type: boolean - dropInputLabels: - description: labels to drop from samples for aggregator - before stream de-duplication and aggregation - items: - type: string - type: array - enableWindows: - description: EnableWindows enables aggregating data in separate - windows ( available from v0.54.0). - type: boolean - ignoreFirstIntervals: - description: IgnoreFirstIntervals instructs to ignore first - interval - type: integer - ignoreOldSamples: - description: IgnoreOldSamples instructs to ignore samples - with old timestamps outside the current aggregation interval. - type: boolean - keepInput: - description: Allows writing both raw and aggregate data - type: boolean - rules: - description: Stream aggregation rules - items: - description: StreamAggrRule defines the rule in stream - aggregation config - properties: - by: - description: |- - By is an optional list of labels for grouping input series. - - See also Without. - - If neither By nor Without are set, then the Outputs are calculated - individually per each input time series. - items: - type: string - type: array - dedup_interval: - description: DedupInterval is an optional interval - for deduplication. - type: string - drop_input_labels: - description: |- - DropInputLabels is an optional list with labels, which must be dropped before further processing of input samples. - - Labels are dropped before de-duplication and aggregation. - items: - type: string - type: array - enable_windows: - description: EnableWindows enables aggregating data - in separate windows - type: boolean - flush_on_shutdown: - description: |- - FlushOnShutdown defines whether to flush the aggregation state on process termination - or config reload. Is `false` by default. - It is not recommended changing this setting, unless unfinished aggregations states - are preferred to missing data points. - type: boolean - ignore_first_intervals: - type: integer - ignore_old_samples: - description: IgnoreOldSamples instructs to ignore - samples with old timestamps outside the current - aggregation interval. - type: boolean - input_relabel_configs: - description: |- - InputRelabelConfigs is an optional relabeling rules, which are applied on the input - before aggregation. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex - matching. Default is 'replace' - type: string - if: - description: 'If represents metricsQL match - expression (or list of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match - for `action: graphite`' - type: object - match: - description: 'Match is used together with Labels - for `action: graphite`' - type: string - modulus: - description: Modulus to take of the hash of - the source label values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated - source label values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - interval: - description: Interval is the interval between aggregations. - type: string - keep_metric_names: - description: KeepMetricNames instructs to leave metric - names as is for the output time series without adding - any suffix. - type: boolean - match: - description: |- - Match is a label selector (or list of label selectors) for filtering time series for the given selector. - - If the match isn't set, then all the input time series are processed. - x-kubernetes-preserve-unknown-fields: true - no_align_flush_to_interval: - description: |- - NoAlignFlushToInterval disables aligning of flushes to multiples of Interval. - By default flushes are aligned to Interval. - type: boolean - output_relabel_configs: - description: |- - OutputRelabelConfigs is an optional relabeling rules, which are applied - on the aggregated output before being sent to remote storage. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex - matching. Default is 'replace' - type: string - if: - description: 'If represents metricsQL match - expression (or list of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match - for `action: graphite`' - type: object - match: - description: 'Match is used together with Labels - for `action: graphite`' - type: string - modulus: - description: Modulus to take of the hash of - the source label values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated - source label values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - outputs: - description: |- - Outputs is a list of output aggregate functions to produce. - - The following names are allowed: - - - total - aggregates input counters - - increase - counts the increase over input counters - - count_series - counts the input series - - count_samples - counts the input samples - - sum_samples - sums the input samples - - last - the last biggest sample value - - min - the minimum sample value - - max - the maximum sample value - - avg - the average value across all the samples - - stddev - standard deviation across all the samples - - stdvar - standard variance across all the samples - - histogram_bucket - creates VictoriaMetrics histogram for input samples - - quantiles(phi1, ..., phiN) - quantiles' estimation for phi in the range [0..1] - - The output time series will have the following names: - - input_name:aggr__ - items: - type: string - type: array - staleness_interval: - description: |- - Staleness interval is interval after which the series state will be reset if no samples have been sent during it. - The parameter is only relevant for outputs: total, total_prometheus, increase, increase_prometheus and histogram_bucket. - type: string - without: - description: |- - Without is an optional list of labels, which must be excluded when grouping input series. - - See also By. - - If neither By nor Without are set, then the Outputs are calculated - individually per each input time series. - items: - type: string - type: array - required: - - interval - - outputs - type: object - type: array - type: object - tlsConfig: - description: TLSConfig describes tls configuration for remote - write target - properties: - ca: - description: Struct containing the CA cert to use for the - targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container to use - for the targets. - type: string - cert: - description: Struct containing the client cert file for - the targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container - for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container - for the targets. - type: string - keySecret: - description: Secret containing the client key file for the - targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - url: - description: URL of the endpoint to send samples to. - type: string - urlRelabelConfig: - description: ConfigMap with relabeling config which is applied - to metrics before sending them to the corresponding -remoteWrite.url - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - required: - - url - type: object - type: array - remoteWriteSettings: - description: RemoteWriteSettings defines global settings for all remoteWrite - urls. - properties: - flushInterval: - description: Interval for flushing the data to remote storage. - (default 1s) - pattern: '[0-9]+(ms|s|m|h)' - type: string - label: - additionalProperties: - type: string - description: Labels in the form 'name=value' to add to all the - metrics before sending them. This overrides the label if it - already exists. - type: object - maxBlockSize: - description: The maximum size in bytes of unpacked request to - send to remote storage - format: int32 - type: integer - maxDiskUsagePerURL: - description: The maximum file-based buffer size in bytes at -remoteWrite.tmpDataPath - x-kubernetes-preserve-unknown-fields: true - queues: - description: The number of concurrent queues - format: int32 - type: integer - showURL: - description: Whether to show -remoteWrite.url in the exported - metrics. It is hidden by default, since it can contain sensitive - auth info - type: boolean - tmpDataPath: - description: Path to directory where temporary data for remote - write component is stored (default vmagent-remotewrite-data) - type: string - useMultiTenantMode: - description: |- - Configures vmagent accepting data via the same multitenant endpoints as vminsert at VictoriaMetrics cluster does, - see [here](https://docs.victoriametrics.com/vmagent/#multitenancy). - it's global setting and affects all remote storage configurations - type: boolean - type: object - replicaCount: - description: ReplicaCount is the expected size of the Application. - format: int32 - type: integer - resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. - format: int32 - type: integer - rollingUpdate: - description: RollingUpdate - overrides deployment update params. - properties: - maxSurge: - anyOf: - - type: integer - - type: string - description: |- - The maximum number of pods that can be scheduled above the desired number of - pods. - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). - This can not be 0 if MaxUnavailable is 0. - Absolute number is calculated from percentage by rounding up. - Defaults to 25%. - Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when - the rolling update starts, such that the total number of old and new pods do not exceed - 130% of desired pods. Once old pods have been killed, - new ReplicaSet can be scaled up further, ensuring that total number of pods running - at any time during the update is at most 130% of desired pods. - x-kubernetes-int-or-string: true - maxUnavailable: - anyOf: - - type: integer - - type: string - description: |- - The maximum number of pods that can be unavailable during the update. - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). - Absolute number is calculated from percentage by rounding down. - This can not be 0 if MaxSurge is 0. - Defaults to 25%. - Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods - immediately when the rolling update starts. Once new pods are ready, old ReplicaSet - can be scaled down further, followed by scaling up the new ReplicaSet, ensuring - that the total number of pods available at all times during the update is at - least 70% of desired pods. - x-kubernetes-int-or-string: true - type: object - runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ - type: string - schedulerName: - description: SchedulerName - defines kubernetes scheduler name - type: string - scrapeConfigNamespaceSelector: - description: |- - ScrapeConfigNamespaceSelector defines Namespaces to be selected for VMScrapeConfig discovery. - Works in combination with Selector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault - 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 - scrapeConfigRelabelTemplate: - description: |- - ScrapeConfigRelabelTemplate defines relabel config, that will be added to each VMScrapeConfig. - it's useful for adding specific labels to all targets - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. Default - is 'replace' - type: string - if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source label - values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source label - values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - scrapeConfigSelector: - description: |- - ScrapeConfigSelector defines VMScrapeConfig to be selected for target discovery. - Works in combination with NamespaceSelector. - 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 - scrapeInterval: - description: ScrapeInterval defines how often scrape targets by default - pattern: '[0-9]+(ms|s|m|h)' - type: string - scrapeTimeout: - description: ScrapeTimeout defines global timeout for targets scrape - pattern: '[0-9]+(ms|s|m|h)' - type: string - secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder - items: - type: string - type: array - securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. - type: object - x-kubernetes-preserve-unknown-fields: true - selectAllByDefault: - description: |- - SelectAllByDefault changes default behavior for empty CRD selectors, such ServiceScrapeSelector. - with selectAllByDefault: true and empty serviceScrapeSelector and ServiceScrapeNamespaceSelector - Operator selects all exist serviceScrapes - with selectAllByDefault: false - selects nothing - type: boolean - serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to use to run the pods - type: string - serviceScrapeNamespaceSelector: - description: |- - ServiceScrapeNamespaceSelector Namespaces to be selected for VMServiceScrape discovery. - Works in combination with Selector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault - 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 - serviceScrapeRelabelTemplate: - description: |- - ServiceScrapeRelabelTemplate defines relabel config, that will be added to each VMServiceScrape. - it's useful for adding specific labels to all targets - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. Default - is 'replace' - type: string - if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source label - values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source label - values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - serviceScrapeSelector: - description: |- - ServiceScrapeSelector defines ServiceScrapes to be selected for target discovery. - Works in combination with NamespaceSelector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault - 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 - serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vmagent VMServiceScrape - spec - required: - - endpoints - type: object - x-kubernetes-preserve-unknown-fields: true - serviceSpec: - description: ServiceSpec that will be added to vmagent service spec - properties: - metadata: - description: EmbeddedObjectMetadata defines objectMeta for additional - service. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ - type: object - x-kubernetes-preserve-unknown-fields: true - useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication - type: boolean - required: - - spec - type: object - shardCount: - description: |- - ShardCount - numbers of shards of VMAgent - in this case operator will use 1 deployment/sts per shard with - replicas count according to spec.replicas, - see [here](https://docs.victoriametrics.com/vmagent/#scraping-big-number-of-targets) - type: integer - startupProbe: - description: StartupProbe that will be added to CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - statefulMode: - description: |- - StatefulMode enables StatefulSet for `VMAgent` instead of Deployment - it allows using persistent storage for vmagent's persistentQueue - type: boolean - statefulRollingUpdateStrategy: - description: |- - StatefulRollingUpdateStrategy allows configuration for strategyType - set it to RollingUpdate for disabling operator statefulSet rollingUpdate - type: string - statefulStorage: - description: StatefulStorage configures storage for StatefulSet - properties: - disableMountSubPath: - description: |- - Deprecated: subPath usage will be disabled by default in a future release, this option will become unnecessary. - DisableMountSubPath allows to remove any subPath usage in volume mounts. - type: boolean - emptyDir: - description: |- - EmptyDirVolumeSource to be used by the Prometheus StatefulSets. If specified, used in place of any volumeClaimTemplate. More - info: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir - properties: - medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - volumeClaimTemplate: - description: A PVC spec to be used by the VMAlertManager StatefulSets. - 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: - description: EmbeddedMetadata contains metadata relevant to - an EmbeddedResource. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - spec: - description: |- - Spec defines the desired characteristics of a volume requested by a pod author. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes to - consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to the - PersistentVolume backing this claim. - type: string - type: object - status: - description: |- - Status represents the current information/status of a persistent volume claim. - Read-only. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the actual access modes the volume backing the PVC has. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - allocatedResourceStatuses: - additionalProperties: - description: |- - When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource - that it does not recognizes, then it should ignore that update and let other controllers - handle it. - type: string - description: "allocatedResourceStatuses stores status - of resource being resized for the given PVC.\nKey names - follow standard Kubernetes label syntax. Valid values - are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources must - use implementation-defined prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have - kubernetes.io prefix are considered\nreserved and hence - may not be used.\n\nClaimResourceStatus can be in any - of following states:\n\t- ControllerResizeInProgress:\n\t\tState - set when resize controller starts resizing the volume - in control-plane.\n\t- ControllerResizeFailed:\n\t\tState - set when resize has failed in resize controller with - a terminal error.\n\t- NodeResizePending:\n\t\tState - set when resize controller has finished resizing the - volume but further resizing of\n\t\tvolume is needed - on the node.\n\t- NodeResizeInProgress:\n\t\tState set - when kubelet starts resizing the volume.\n\t- NodeResizeFailed:\n\t\tState - set when resizing has failed in kubelet with a terminal - error. Transient errors don't set\n\t\tNodeResizeFailed.\nFor - example: if expanding a PVC for more capacity - this - field can be one of the following states:\n\t- pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeFailed\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizePending\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeFailed\"\nWhen this field is not set, - it means that no resize operation is in progress for - the given PVC.\n\nA controller that receives PVC update - with previously unknown resourceName or ClaimResourceStatus\nshould - ignore the update for the purpose it was designed. For - example - a controller that\nonly is responsible for - resizing capacity of the volume, should ignore PVC updates - that change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." - type: object - x-kubernetes-map-type: granular - allocatedResources: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: "allocatedResources tracks the resources - allocated to a PVC including its capacity.\nKey names - follow standard Kubernetes label syntax. Valid values - are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources must - use implementation-defined prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have - kubernetes.io prefix are considered\nreserved and hence - may not be used.\n\nCapacity reported here may be larger - than the actual capacity when a volume expansion operation\nis - requested.\nFor storage quota, the larger value from - allocatedResources and PVC.spec.resources is used.\nIf - allocatedResources is not set, PVC.spec.resources alone - is used for quota calculation.\nIf a volume expansion - capacity request is lowered, allocatedResources is only\nlowered - if there are no expansion operations in progress and - if the actual volume capacity\nis equal or lower than - the requested capacity.\n\nA controller that receives - PVC update with previously unknown resourceName\nshould - ignore the update for the purpose it was designed. For - example - a controller that\nonly is responsible for - resizing capacity of the volume, should ignore PVC updates - that change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." - type: object - capacity: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: capacity represents the actual resources - of the underlying volume. - type: object - conditions: - description: |- - conditions is the current Condition of persistent volume claim. If underlying persistent volume is being - resized then the Condition will be set to 'Resizing'. - items: - description: PersistentVolumeClaimCondition contains - details about state of pvc - properties: - lastProbeTime: - description: lastProbeTime is the time we probed - the condition. - format: date-time - type: string - lastTransitionTime: - description: lastTransitionTime is the time the - condition transitioned from one status to another. - format: date-time - type: string - message: - description: message is the human-readable message - indicating details about last transition. - type: string - reason: - description: |- - reason is a unique, this should be a short, machine understandable string that gives the reason - for condition's last transition. If it reports "Resizing" that means the underlying - persistent volume is being resized. - type: string - status: - description: |- - Status is the status of the condition. - Can be True, False, Unknown. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=state%20of%20pvc-,conditions.status,-(string)%2C%20required - type: string - type: - description: |- - Type is the type of the condition. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=set%20to%20%27ResizeStarted%27.-,PersistentVolumeClaimCondition,-contains%20details%20about - type: string - required: - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - currentVolumeAttributesClassName: - description: |- - currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. - When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - type: string - modifyVolumeStatus: - description: |- - ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. - When this is unset, there is no ModifyVolume operation being attempted. - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - properties: - status: - description: "status is the status of the ControllerModifyVolume - operation. It can be in any of following states:\n - - Pending\n Pending indicates that the PersistentVolumeClaim - cannot be modified due to unmet requirements, such - as\n the specified VolumeAttributesClass not existing.\n - - InProgress\n InProgress indicates that the volume - is being modified.\n - Infeasible\n Infeasible - indicates that the request has been rejected as - invalid by the CSI driver. To\n\t resolve the error, - a valid VolumeAttributesClass needs to be specified.\nNote: - New statuses can be added in the future. Consumers - should check for unknown statuses and fail appropriately." - type: string - targetVolumeAttributesClassName: - description: targetVolumeAttributesClassName is the - name of the VolumeAttributesClass the PVC currently - being reconciled - type: string - required: - - status - type: object - phase: - description: phase represents the current phase of PersistentVolumeClaim. - type: string - type: object - type: object - type: object - staticScrapeNamespaceSelector: - description: |- - StaticScrapeNamespaceSelector defines Namespaces to be selected for VMStaticScrape discovery. - Works in combination with NamespaceSelector. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault - 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 - staticScrapeRelabelTemplate: - description: |- - StaticScrapeRelabelTemplate defines relabel config, that will be added to each VMStaticScrape. - it's useful for adding specific labels to all targets - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. Default - is 'replace' - type: string - if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source label - values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source label - values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - staticScrapeSelector: - description: |- - StaticScrapeSelector defines VMStaticScrape to be selected for target discovery. - Works in combination with NamespaceSelector. - If both nil - match everything. - NamespaceSelector nil - only objects at VMAgent namespace. - Selector nil - only objects at NamespaceSelector namespaces. - 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 - streamAggrConfig: - description: StreamAggrConfig defines global stream aggregation configuration - for VMAgent - properties: - configmap: - description: ConfigMap with stream aggregation rules - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - dedupInterval: - description: Allows setting different de-duplication intervals - per each configured remote storage - type: string - dropInput: - description: Allow drop all the input samples after the aggregation - type: boolean - dropInputLabels: - description: labels to drop from samples for aggregator before - stream de-duplication and aggregation - items: - type: string - type: array - enableWindows: - description: EnableWindows enables aggregating data in separate - windows ( available from v0.54.0). - type: boolean - ignoreFirstIntervals: - description: IgnoreFirstIntervals instructs to ignore first interval - type: integer - ignoreOldSamples: - description: IgnoreOldSamples instructs to ignore samples with - old timestamps outside the current aggregation interval. - type: boolean - keepInput: - description: Allows writing both raw and aggregate data - type: boolean - rules: - description: Stream aggregation rules - items: - description: StreamAggrRule defines the rule in stream aggregation - config - properties: - by: - description: |- - By is an optional list of labels for grouping input series. - - See also Without. - - If neither By nor Without are set, then the Outputs are calculated - individually per each input time series. - items: - type: string - type: array - dedup_interval: - description: DedupInterval is an optional interval for deduplication. - type: string - drop_input_labels: - description: |- - DropInputLabels is an optional list with labels, which must be dropped before further processing of input samples. - - Labels are dropped before de-duplication and aggregation. - items: - type: string - type: array - enable_windows: - description: EnableWindows enables aggregating data in separate - windows - type: boolean - flush_on_shutdown: - description: |- - FlushOnShutdown defines whether to flush the aggregation state on process termination - or config reload. Is `false` by default. - It is not recommended changing this setting, unless unfinished aggregations states - are preferred to missing data points. - type: boolean - ignore_first_intervals: - type: integer - ignore_old_samples: - description: IgnoreOldSamples instructs to ignore samples - with old timestamps outside the current aggregation interval. - type: boolean - input_relabel_configs: - description: |- - InputRelabelConfigs is an optional relabeling rules, which are applied on the input - before aggregation. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. - Default is 'replace' - type: string - if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for - `action: graphite`' - type: object - match: - description: 'Match is used together with Labels for - `action: graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source - label values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated - source label values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - interval: - description: Interval is the interval between aggregations. - type: string - keep_metric_names: - description: KeepMetricNames instructs to leave metric names - as is for the output time series without adding any suffix. - type: boolean - match: - description: |- - Match is a label selector (or list of label selectors) for filtering time series for the given selector. - - If the match isn't set, then all the input time series are processed. - x-kubernetes-preserve-unknown-fields: true - no_align_flush_to_interval: - description: |- - NoAlignFlushToInterval disables aligning of flushes to multiples of Interval. - By default flushes are aligned to Interval. - type: boolean - output_relabel_configs: - description: |- - OutputRelabelConfigs is an optional relabeling rules, which are applied - on the aggregated output before being sent to remote storage. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. - Default is 'replace' - type: string - if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for - `action: graphite`' - type: object - match: - description: 'Match is used together with Labels for - `action: graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source - label values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated - source label values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - outputs: - description: |- - Outputs is a list of output aggregate functions to produce. - - The following names are allowed: - - - total - aggregates input counters - - increase - counts the increase over input counters - - count_series - counts the input series - - count_samples - counts the input samples - - sum_samples - sums the input samples - - last - the last biggest sample value - - min - the minimum sample value - - max - the maximum sample value - - avg - the average value across all the samples - - stddev - standard deviation across all the samples - - stdvar - standard variance across all the samples - - histogram_bucket - creates VictoriaMetrics histogram for input samples - - quantiles(phi1, ..., phiN) - quantiles' estimation for phi in the range [0..1] - - The output time series will have the following names: - - input_name:aggr__ - items: - type: string - type: array - staleness_interval: - description: |- - Staleness interval is interval after which the series state will be reset if no samples have been sent during it. - The parameter is only relevant for outputs: total, total_prometheus, increase, increase_prometheus and histogram_bucket. - type: string - without: - description: |- - Without is an optional list of labels, which must be excluded when grouping input series. - - See also By. - - If neither By nor Without are set, then the Outputs are calculated - individually per each input time series. - items: - type: string - type: array - required: - - interval - - outputs - type: object - type: array - type: object - terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container graceful - termination - format: int64 - type: integer - tolerations: - description: Tolerations If specified, the pod's tolerations. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - items: - description: TopologySpreadConstraint specifies how to spread matching - pods among the given topology. - required: - - maxSkew - - topologyKey - - whenUnsatisfiable - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - updateStrategy: - description: |- - UpdateStrategy - overrides default update strategy. - works only for deployments, statefulset always use OnDelete. - enum: - - Recreate - - RollingUpdate - type: string - useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements - type: boolean - useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions - type: boolean - useVMConfigReloader: - description: |- - UseVMConfigReloader replaces prometheus-like config-reloader - with vm one. It uses secrets watch instead of file watch - which greatly increases speed of config updates - type: boolean - vmAgentExternalLabelName: - description: |- - VMAgentExternalLabelName Name of vmAgent external label used to denote vmAgent instance - name. Defaults to the value of `prometheus`. External label will - _not_ be added when value is set to empty string (`""`). - type: string - volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container - items: - description: VolumeMount describes a mounting of a Volume within - a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional - items: - description: Volume represents a named volume in a pod that may - be accessed by any container in the pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array required: - remoteWrite type: object + x-kubernetes-preserve-unknown-fields: true status: - description: VMAgentStatus defines the observed state of VMAgent properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -5810,28 +484,19 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string replicas: - description: ReplicaCount Total number of pods targeted by this VMAgent format: int32 type: integer selector: - description: Selector string form of label value set for autoscaling type: string shards: - description: Shards represents total number of vmagent deployments - with uniq scrape targets format: int32 type: integer updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -5848,7 +513,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmalertmanagerconfigs.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -5872,4266 +537,45 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMAlertmanagerConfig is the Schema for the vmalertmanagerconfigs - API 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: |- - VMAlertmanagerConfigSpec defines configuration for VMAlertmanagerConfig - it must reference only locally defined objects - properties: - inhibit_rules: - description: |- - InhibitRules will only apply for alerts matching - the resource's namespace. - items: - description: |- - InhibitRule defines an inhibition rule that allows to mute alerts when other - alerts are already firing. - Note, it doesn't support deprecated alertmanager config options. - See https://prometheus.io/docs/alerting/latest/configuration/#inhibit_rule - properties: - equal: - description: |- - Labels that must have an equal value in the source and target alert for - the inhibition to take effect. - items: - type: string - type: array - source_matchers: - description: |- - SourceMatchers defines a list of matchers for which one or more alerts have - to exist for the inhibition to take effect. - items: - type: string - type: array - target_matchers: - description: |- - TargetMatchers defines a list of matchers that have to be fulfilled by the target - alerts to be muted. - items: - type: string - type: array - type: object - type: array - receivers: - description: Receivers defines alert receivers - items: - description: Receiver defines one or more notification integrations. - properties: - discord_configs: - items: - properties: - avatar_url: - description: |- - AvatarURL defines message avatar URL - Available from operator v0.55.0 and alertmanager v0.28.0 - type: string - content: - description: |- - Content defines message content template - Available from operator v0.55.0 and alertmanager v0.28.0 - maxLength: 2000 - type: string - http_config: - description: HTTP client configuration. - properties: - authorization: - description: |- - Authorization header configuration for the client. - This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. - properties: - credentials: - description: Reference to the secret with value - for authorization - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to - bearer - type: string - type: object - basic_auth: - description: BasicAuth for the client. - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token_file: - description: BearerTokenFile defines filename for - bearer token, it must be mounted to pod. - type: string - bearer_token_secret: - description: |- - The secret's key that contains the bearer token - It must be at them same namespace as CRD - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - oauth2: - description: OAuth2 client credentials used to fetch - a token for the targets. - properties: - client_id: - description: The secret or configmap containing - the OAuth2 client id - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 - client secret - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for - client secret file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token - URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token - request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - proxyURL: - description: Optional proxy URL. - type: string - tls_config: - description: TLS configuration for the client. - properties: - ca: - description: Struct containing the CA cert to - use for the targets. - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container - to use for the targets. - type: string - cert: - description: Struct containing the client cert - file for the targets. - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the - container for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the - container for the targets. - type: string - keySecret: - description: Secret containing the client key - file for the targets. - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the - targets. - type: string - type: object - type: object - message: - description: The message body template - type: string - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - title: - description: The message title template - type: string - username: - description: |- - Username defines message username - Available from operator v0.55.0 and alertmanager v0.28.0 - type: string - webhook_url: - description: |- - The discord webhook URL - one of `urlSecret` and `url` must be defined. - type: string - webhook_url_secret: - description: |- - URLSecret defines secret name and key at the CRD namespace. - It must contain the webhook URL. - one of `urlSecret` and `url` must be defined. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - type: array - email_configs: - description: EmailConfigs defines email notification configurations. - items: - description: EmailConfig configures notifications via Email. - properties: - auth_identity: - description: The identity to use for authentication. - type: string - auth_password: - description: AuthPassword defines secret name and key - at CRD namespace. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - auth_secret: - description: |- - AuthSecret defines secrent name and key at CRD namespace. - It must contain the CRAM-MD5 secret. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - auth_username: - description: The username to use for authentication. - type: string - from: - description: |- - The sender address. - fallback to global setting if empty - type: string - headers: - additionalProperties: - type: string - description: |- - Further headers email header key/value pairs. Overrides any headers - previously set by the notification implementation. - type: object - hello: - description: The hostname to identify to the SMTP server. - type: string - html: - description: The HTML body of the email notification. - type: string - require_tls: - description: |- - The SMTP TLS requirement. - Note that Go does not support unencrypted connections to remote SMTP endpoints. - type: boolean - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - smarthost: - description: |- - The SMTP host through which emails are sent. - fallback to global setting if empty - type: string - text: - description: The text body of the email notification. - type: string - tls_config: - description: TLS configuration - properties: - ca: - description: Struct containing the CA cert to use - for the targets. - properties: - configMap: - description: ConfigMap containing data to use - for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for - the targets. - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container - to use for the targets. - type: string - cert: - description: Struct containing the client cert file - for the targets. - properties: - configMap: - description: ConfigMap containing data to use - for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for - the targets. - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container - for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container - for the targets. - type: string - keySecret: - description: Secret containing the client key file - for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - to: - description: The email address to send notifications to. - type: string - type: object - type: array - jira_configs: - items: - description: |- - JiraConfig represent alertmanager's jira_config entry - https://prometheus.io/docs/alerting/latest/configuration/#jira_config - available from v0.55.0 operator version - and v0.28.0 alertmanager version - properties: - api_url: - description: |- - The URL to send API requests to. The full API path must be included. - Example: https://company.atlassian.net/rest/api/2/ - type: string - custom_fields: - additionalProperties: - x-kubernetes-preserve-unknown-fields: true - description: |- - Other issue and custom fields. - Jira issue field can have multiple types. - Depends on the field type, the values must be provided differently. - See https://developer.atlassian.com/server/jira/platform/jira-rest-api-examples/#setting-custom-field-data-for-other-field-types for further examples. - type: object - description: - description: Issue description template. - type: string - http_config: - description: |- - The HTTP client's configuration. You must use this configuration to supply the personal access token (PAT) as part of the HTTP `Authorization` header. - For Jira Cloud, use basic_auth with the email address as the username and the PAT as the password. - For Jira Data Center, use the 'authorization' field with 'credentials: '. - x-kubernetes-preserve-unknown-fields: true - issue_type: - description: Type of the issue (e.g. Bug) - type: string - labels: - description: Labels to be added to the issue - items: - type: string - type: array - priority: - description: Priority of the issue - type: string - project: - description: The project key where issues are created - type: string - reopen_duration: - description: |- - If reopen_transition is defined, reopen the issue when it is not older than this value (rounded down to the nearest minute). - The resolutiondate field is used to determine the age of the issue. - pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ - type: string - reopen_transition: - description: |- - Name of the workflow transition to resolve an issue. - The target status must have the category "done". - type: string - resolve_transition: - description: |- - Name of the workflow transition to reopen an issue. - The target status should not have the category "done". - type: string - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - summary: - description: Issue summary template - type: string - wont_fix_resolution: - description: If reopen_transition is defined, ignore issues - with that resolution. - type: string - required: - - issue_type - - project - type: object - type: array - msteams_configs: - items: - properties: - http_config: - description: HTTP client configuration. - properties: - authorization: - description: |- - Authorization header configuration for the client. - This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. - properties: - credentials: - description: Reference to the secret with value - for authorization - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to - bearer - type: string - type: object - basic_auth: - description: BasicAuth for the client. - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token_file: - description: BearerTokenFile defines filename for - bearer token, it must be mounted to pod. - type: string - bearer_token_secret: - description: |- - The secret's key that contains the bearer token - It must be at them same namespace as CRD - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - oauth2: - description: OAuth2 client credentials used to fetch - a token for the targets. - properties: - client_id: - description: The secret or configmap containing - the OAuth2 client id - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 - client secret - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for - client secret file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token - URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token - request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - proxyURL: - description: Optional proxy URL. - type: string - tls_config: - description: TLS configuration for the client. - properties: - ca: - description: Struct containing the CA cert to - use for the targets. - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container - to use for the targets. - type: string - cert: - description: Struct containing the client cert - file for the targets. - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the - container for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the - container for the targets. - type: string - keySecret: - description: Secret containing the client key - file for the targets. - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the - targets. - type: string - type: object - type: object - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - text: - description: The text body of the teams notification. - type: string - title: - description: The title of the teams notification. - type: string - webhook_url: - description: |- - The incoming webhook URL - one of `urlSecret` and `url` must be defined. - type: string - webhook_url_secret: - description: |- - URLSecret defines secret name and key at the CRD namespace. - It must contain the webhook URL. - one of `urlSecret` and `url` must be defined. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - type: array - msteamsv2_configs: - items: - description: |- - MSTeamsV2Config sends notifications using the new message format with adaptive cards as required by flows. - https://support.microsoft.com/en-gb/office/create-incoming-webhooks-with-workflows-for-microsoft-teams-8ae491c7-0394-4861-ba59-055e33f75498 - available from v0.55.0 operator version - and v0.28.0 alertmanager version - properties: - http_config: - x-kubernetes-preserve-unknown-fields: true - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - text: - description: Message body template. - type: string - title: - description: Message title template. - type: string - webhook_url: - description: |- - The incoming webhook URL - one of `urlSecret` and `url` must be defined. - type: string - webhook_url_secret: - description: |- - URLSecret defines secret name and key at the CRD namespace. - It must contain the webhook URL. - one of `webhook_url` or `webhook_url_secret` must be defined. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - type: array - name: - description: Name of the receiver. Must be unique across all - items from the list. - minLength: 1 - type: string - opsgenie_configs: - description: OpsGenieConfigs defines ops genie notification - configurations. - items: - description: |- - OpsGenieConfig configures notifications via OpsGenie. - See https://prometheus.io/docs/alerting/latest/configuration/#opsgenie_config - properties: - actions: - description: Comma separated list of actions that will - be available for the alert. - type: string - api_key: - description: |- - The secret's key that contains the OpsGenie API key. - It must be at them same namespace as CRD - fallback to global setting if empty - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - apiURL: - description: The URL to send OpsGenie API requests to. - type: string - description: - description: Description of the incident. - type: string - details: - additionalProperties: - type: string - description: A set of arbitrary key/value pairs that provide - further detail about the incident. - type: object - entity: - description: Optional field that can be used to specify - which domain alert is related to. - type: string - http_config: - description: HTTP client configuration. - type: object - x-kubernetes-preserve-unknown-fields: true - message: - description: Alert text limited to 130 characters. - type: string - note: - description: Additional alert note. - type: string - priority: - description: Priority level of alert. Possible values - are P1, P2, P3, P4, and P5. - type: string - responders: - description: List of responders responsible for notifications. - items: - description: |- - OpsGenieConfigResponder defines a responder to an incident. - One of `id`, `name` or `username` has to be defined. - properties: - id: - description: ID of the responder. - type: string - name: - description: Name of the responder. - type: string - type: - description: Type of responder. - minLength: 1 - type: string - username: - description: Username of the responder. - type: string - required: - - type - type: object - type: array - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - source: - description: Backlink to the sender of the notification. - type: string - tags: - description: Comma separated list of tags attached to - the notifications. - type: string - update_alerts: - description: |- - Whether to update message and description of the alert in OpsGenie if it already exists - By default, the alert is never updated in OpsGenie, the new message only appears in activity log. - type: boolean - type: object - type: array - pagerduty_configs: - description: PagerDutyConfigs defines pager duty notification - configurations. - items: - description: |- - PagerDutyConfig configures notifications via PagerDuty. - See https://prometheus.io/docs/alerting/latest/configuration/#pagerduty_config - properties: - class: - description: The class/type of the event. - type: string - client: - description: Client identification. - type: string - client_url: - description: Backlink to the sender of notification. - type: string - component: - description: The part or component of the affected system - that is broken. - type: string - description: - description: Description of the incident. - type: string - details: - additionalProperties: - type: string - description: Arbitrary key/value pairs that provide further - detail about the incident. - type: object - group: - description: A cluster or grouping of sources. - type: string - http_config: - description: HTTP client configuration. - type: object - x-kubernetes-preserve-unknown-fields: true - images: - description: Images to attach to the incident. - items: - description: |- - ImageConfig is used to attach images to the incident. - See https://developer.pagerduty.com/docs/ZG9jOjExMDI5NTgx-send-an-alert-event#the-images-property - for more information. - properties: - alt: - type: string - href: - type: string - source: - type: string - required: - - source - type: object - type: array - links: - description: Links to attach to the incident. - items: - description: |- - LinkConfig is used to attach text links to the incident. - See https://developer.pagerduty.com/docs/ZG9jOjExMDI5NTgx-send-an-alert-event#the-links-property - for more information. - properties: - href: - type: string - text: - type: string - required: - - href - type: object - type: array - routing_key: - description: |- - The secret's key that contains the PagerDuty integration key (when using - Events API v2). Either this field or `serviceKey` needs to be defined. - It must be at them same namespace as CRD - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - service_key: - description: |- - The secret's key that contains the PagerDuty service key (when using - integration type "Prometheus"). Either this field or `routingKey` needs to - be defined. - It must be at them same namespace as CRD - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - severity: - description: Severity of the incident. - type: string - url: - description: The URL to send requests to. - type: string - type: object - type: array - pushover_configs: - description: PushoverConfigs defines push over notification - configurations. - items: - description: |- - PushoverConfig configures notifications via Pushover. - See https://prometheus.io/docs/alerting/latest/configuration/#pushover_config - properties: - expire: - description: |- - How long your notification will continue to be retried for, unless the user - acknowledges the notification. - type: string - html: - description: Whether notification message is HTML or plain - text. - type: boolean - http_config: - description: HTTP client configuration. - type: object - x-kubernetes-preserve-unknown-fields: true - message: - description: Notification message. - type: string - priority: - description: Priority, see https://pushover.net/api#priority - type: string - retry: - description: |- - How often the Pushover servers will send the same notification to the user. - Must be at least 30 seconds. - type: string - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - sound: - description: The name of one of the sounds supported by - device clients to override the user's default sound - choice - type: string - title: - description: Notification title. - type: string - token: - description: |- - The secret's key that contains the registered application’s API token, see https://pushover.net/apps. - It must be at them same namespace as CRD - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - url: - description: A supplementary URL shown alongside the message. - type: string - url_title: - description: A title for supplementary URL, otherwise - just the URL is shown - type: string - user_key: - description: |- - The secret's key that contains the recipient user’s user key. - It must be at them same namespace as CRD - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - type: array - rocketchat_configs: - items: - description: |- - RocketchatConfig configures notifications via Rocketchat. - https://prometheus.io/docs/alerting/latest/configuration/#rocketchat_config - available from v0.55.0 operator version - and v0.28.0 alertmanager version - properties: - actions: - items: - description: |- - RocketchatAttachmentAction defines message attachements - https://github.com/RocketChat/Rocket.Chat.Go.SDK/blob/master/models/message.go - properties: - msg: - type: string - text: - type: string - type: - type: string - url: - type: string - type: object - type: array - api_url: - type: string - channel: - description: 'RocketChat channel override, (like #other-channel - or @username).' - type: string - color: - type: string - emoji: - type: string - fields: - items: - description: |- - RocketchatAttachmentField defines API fields - https://developer.rocket.chat/reference/api/rest-api/endpoints/messaging/chat-endpoints/postmessage#attachment-field-objects - properties: - short: - type: boolean - title: - type: string - value: - type: string - type: object - type: array - http_config: - x-kubernetes-preserve-unknown-fields: true - icon_url: - type: string - image_url: - type: string - link_names: - type: boolean - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - short_fields: - type: boolean - text: - type: string - thumb_url: - type: string - title: - type: string - title_link: - type: string - token: - description: SecretKeySelector selects a key of a Secret. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - token_id: - description: |- - The sender token and token_id - See https://docs.rocket.chat/use-rocket.chat/user-guides/user-panel/my-account#personal-access-tokens - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - type: array - slack_configs: - description: SlackConfigs defines slack notification configurations. - items: - description: |- - SlackConfig configures notifications via Slack. - See https://prometheus.io/docs/alerting/latest/configuration/#slack_config - properties: - actions: - description: A list of Slack actions that are sent with - each notification. - items: - description: |- - SlackAction configures a single Slack action that is sent with each - notification. - See https://api.slack.com/docs/message-attachments#action_fields and - https://api.slack.com/docs/message-buttons for more information. - properties: - confirm: - description: |- - SlackConfirmationField protect users from destructive actions or - particularly distinguished decisions by asking them to confirm their button - click one more time. - See https://api.slack.com/docs/interactive-message-field-guide#confirmation_fields - for more information. - properties: - dismiss_text: - type: string - ok_text: - type: string - text: - minLength: 1 - type: string - title: - type: string - required: - - text - type: object - name: - type: string - style: - type: string - text: - minLength: 1 - type: string - type: - minLength: 1 - type: string - url: - type: string - value: - type: string - required: - - text - - type - type: object - type: array - api_url: - description: |- - The secret's key that contains the Slack webhook URL. - It must be at them same namespace as CRD - fallback to global setting if empty - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - callback_id: - type: string - channel: - description: The channel or user to send notifications - to. - type: string - color: - type: string - fallback: - type: string - fields: - description: A list of Slack fields that are sent with - each notification. - items: - description: |- - SlackField configures a single Slack field that is sent with each notification. - See https://api.slack.com/docs/message-attachments#fields for more information. - properties: - short: - type: boolean - title: - minLength: 1 - type: string - value: - minLength: 1 - type: string - required: - - title - - value - type: object - type: array - footer: - type: string - http_config: - description: HTTP client configuration. - type: object - x-kubernetes-preserve-unknown-fields: true - icon_emoji: - type: string - icon_url: - type: string - image_url: - type: string - link_names: - type: boolean - mrkdwn_in: - items: - type: string - type: array - pretext: - type: string - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - short_fields: - type: boolean - text: - type: string - thumb_url: - type: string - title: - type: string - title_link: - type: string - username: - type: string - type: object - type: array - sns_configs: - items: - properties: - api_url: - description: The api URL - type: string - attributes: - additionalProperties: - type: string - description: SNS message attributes - type: object - http_config: - description: HTTP client configuration. - properties: - authorization: - description: |- - Authorization header configuration for the client. - This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. - properties: - credentials: - description: Reference to the secret with value - for authorization - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to - bearer - type: string - type: object - basic_auth: - description: BasicAuth for the client. - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token_file: - description: BearerTokenFile defines filename for - bearer token, it must be mounted to pod. - type: string - bearer_token_secret: - description: |- - The secret's key that contains the bearer token - It must be at them same namespace as CRD - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - oauth2: - description: OAuth2 client credentials used to fetch - a token for the targets. - properties: - client_id: - description: The secret or configmap containing - the OAuth2 client id - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 - client secret - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for - client secret file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token - URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token - request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - proxyURL: - description: Optional proxy URL. - type: string - tls_config: - description: TLS configuration for the client. - properties: - ca: - description: Struct containing the CA cert to - use for the targets. - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container - to use for the targets. - type: string - cert: - description: Struct containing the client cert - file for the targets. - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the - container for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the - container for the targets. - type: string - keySecret: - description: Secret containing the client key - file for the targets. - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the - targets. - type: string - type: object - type: object - message: - description: The message content of the SNS notification. - type: string - phone_number: - description: |- - Phone number if message is delivered via SMS - Specify this, topic_arn or target_arn - type: string - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - sigv4: - description: Configure the AWS Signature Verification - 4 signing process - properties: - access_key: - description: |- - The AWS API keys. Both access_key and secret_key must be supplied or both must be blank. - If blank the environment variables `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` are used. - type: string - access_key_selector: - description: secret key selector to get the keys from - a Kubernetes Secret - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - profile: - description: Named AWS profile used to authenticate - type: string - region: - description: AWS region, if blank the region from - the default credentials chain is used - type: string - role_arn: - description: AWS Role ARN, an alternative to using - AWS API keys - type: string - secret_key_selector: - description: secret key selector to get the keys from - a Kubernetes Secret - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - subject: - description: The subject line if message is delivered - to an email endpoint. - type: string - target_arn: - description: |- - Mobile platform endpoint ARN if message is delivered via mobile notifications - Specify this, topic_arn or phone_number - type: string - topic_arn: - description: SNS topic ARN, either specify this, phone_number - or target_arn - type: string - type: object - type: array - telegram_configs: - items: - description: |- - TelegramConfig configures notification via telegram - https://prometheus.io/docs/alerting/latest/configuration/#telegram_config - properties: - api_url: - description: APIUrl the Telegram API URL i.e. https://api.telegram.org. - type: string - bot_token: - description: |- - BotToken token for the bot - https://core.telegram.org/bots/api - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - chat_id: - description: ChatID is ID of the chat where to send the - messages. - type: integer - disable_notifications: - description: DisableNotifications - type: boolean - http_config: - description: HTTP client configuration. - type: object - x-kubernetes-preserve-unknown-fields: true - message: - description: Message is templated message - type: string - message_thread_id: - description: MessageThreadID defines ID of the message - thread where to send the messages. - type: integer - parse_mode: - description: |- - ParseMode for telegram message, - supported values are MarkdownV2, Markdown, Markdown and empty string for plain text. - type: string - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - required: - - bot_token - - chat_id - type: object - type: array - victorops_configs: - description: VictorOpsConfigs defines victor ops notification - configurations. - items: - description: |- - VictorOpsConfig configures notifications via VictorOps. - See https://prometheus.io/docs/alerting/latest/configuration/#victorops_config - properties: - api_key: - description: |- - The secret's key that contains the API key to use when talking to the VictorOps API. - It must be at them same namespace as CRD - fallback to global setting if empty - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - api_url: - description: The VictorOps API URL. - type: string - custom_fields: - additionalProperties: - type: string - description: |- - Adds optional custom fields - https://github.com/prometheus/alertmanager/blob/v0.24.0/config/notifiers.go#L537 - type: object - entity_display_name: - description: Contains summary of the alerted problem. - type: string - http_config: - description: The HTTP client's configuration. - properties: - authorization: - description: |- - Authorization header configuration for the client. - This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. - properties: - credentials: - description: Reference to the secret with value - for authorization - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to - bearer - type: string - type: object - basic_auth: - description: BasicAuth for the client. - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token_file: - description: BearerTokenFile defines filename for - bearer token, it must be mounted to pod. - type: string - bearer_token_secret: - description: |- - The secret's key that contains the bearer token - It must be at them same namespace as CRD - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - oauth2: - description: OAuth2 client credentials used to fetch - a token for the targets. - properties: - client_id: - description: The secret or configmap containing - the OAuth2 client id - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 - client secret - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for - client secret file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token - URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token - request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - proxyURL: - description: Optional proxy URL. - type: string - tls_config: - description: TLS configuration for the client. - properties: - ca: - description: Struct containing the CA cert to - use for the targets. - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container - to use for the targets. - type: string - cert: - description: Struct containing the client cert - file for the targets. - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the - container for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the - container for the targets. - type: string - keySecret: - description: Secret containing the client key - file for the targets. - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the - targets. - type: string - type: object - type: object - message_type: - description: Describes the behavior of the alert (CRITICAL, - WARNING, INFO). - type: string - monitoring_tool: - description: The monitoring tool the state message is - from. - type: string - routing_key: - description: A key used to map the alert to a team. - type: string - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - state_message: - description: Contains long explanation of the alerted - problem. - type: string - required: - - routing_key - type: object - type: array - webex_configs: - items: - properties: - api_url: - description: The Webex Teams API URL, i.e. https://webexapis.com/v1/messages - type: string - http_config: - description: HTTP client configuration. You must use this - configuration to supply the bot token as part of the - HTTP `Authorization` header. - properties: - authorization: - description: |- - Authorization header configuration for the client. - This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. - properties: - credentials: - description: Reference to the secret with value - for authorization - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to - bearer - type: string - type: object - basic_auth: - description: BasicAuth for the client. - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token_file: - description: BearerTokenFile defines filename for - bearer token, it must be mounted to pod. - type: string - bearer_token_secret: - description: |- - The secret's key that contains the bearer token - It must be at them same namespace as CRD - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - oauth2: - description: OAuth2 client credentials used to fetch - a token for the targets. - properties: - client_id: - description: The secret or configmap containing - the OAuth2 client id - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 - client secret - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for - client secret file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token - URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token - request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - proxyURL: - description: Optional proxy URL. - type: string - tls_config: - description: TLS configuration for the client. - properties: - ca: - description: Struct containing the CA cert to - use for the targets. - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container - to use for the targets. - type: string - cert: - description: Struct containing the client cert - file for the targets. - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the - container for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the - container for the targets. - type: string - keySecret: - description: Secret containing the client key - file for the targets. - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the - targets. - type: string - type: object - type: object - message: - description: The message body template - type: string - room_id: - description: The ID of the Webex Teams room where to send - the messages - type: string - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - required: - - room_id - type: object - type: array - webhook_configs: - description: WebhookConfigs defines webhook notification configurations. - items: - description: |- - WebhookConfig configures notifications via a generic receiver supporting the webhook payload. - See https://prometheus.io/docs/alerting/latest/configuration/#webhook_config - properties: - http_config: - description: HTTP client configuration. - type: object - x-kubernetes-preserve-unknown-fields: true - max_alerts: - description: Maximum number of alerts to be sent per webhook - message. When 0, all alerts are included. - format: int32 - minimum: 0 - type: integer - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - url: - description: |- - URL to send requests to, - one of `urlSecret` and `url` must be defined. - type: string - url_secret: - description: |- - URLSecret defines secret name and key at the CRD namespace. - It must contain the webhook URL. - one of `urlSecret` and `url` must be defined. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - type: array - wechat_configs: - description: WeChatConfigs defines wechat notification configurations. - items: - description: |- - WeChatConfig configures notifications via WeChat. - See https://prometheus.io/docs/alerting/latest/configuration/#wechat_config - properties: - agent_id: - type: string - api_secret: - description: |- - The secret's key that contains the WeChat API key. - The secret needs to be in the same namespace as the AlertmanagerConfig - fallback to global alertmanager setting if empty - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - api_url: - description: |- - The WeChat API URL. - fallback to global alertmanager setting if empty - type: string - corp_id: - description: |- - The corp id for authentication. - fallback to global alertmanager setting if empty - type: string - http_config: - description: HTTP client configuration. - properties: - authorization: - description: |- - Authorization header configuration for the client. - This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. - properties: - credentials: - description: Reference to the secret with value - for authorization - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to - bearer - type: string - type: object - basic_auth: - description: BasicAuth for the client. - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token_file: - description: BearerTokenFile defines filename for - bearer token, it must be mounted to pod. - type: string - bearer_token_secret: - description: |- - The secret's key that contains the bearer token - It must be at them same namespace as CRD - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - oauth2: - description: OAuth2 client credentials used to fetch - a token for the targets. - properties: - client_id: - description: The secret or configmap containing - the OAuth2 client id - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 - client secret - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for - client secret file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token - URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token - request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - proxyURL: - description: Optional proxy URL. - type: string - tls_config: - description: TLS configuration for the client. - properties: - ca: - description: Struct containing the CA cert to - use for the targets. - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container - to use for the targets. - type: string - cert: - description: Struct containing the client cert - file for the targets. - properties: - configMap: - description: ConfigMap containing data to - use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use - for the targets. - properties: - key: - description: The key of the secret to - select from. Must be a valid secret - key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret - or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the - container for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the - container for the targets. - type: string - keySecret: - description: Secret containing the client key - file for the targets. - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the - targets. - type: string - type: object - type: object - message: - description: API request data as defined by the WeChat - API. - type: string - message_type: - type: string - send_resolved: - description: SendResolved controls notify about resolved - alerts. - type: boolean - to_party: - type: string - to_tag: - type: string - to_user: - type: string - type: object - type: array - required: - - name - type: object - type: array - route: - description: Route definition for alertmanager, may include nested - routes. - properties: - active_time_intervals: - description: |- - ActiveTimeIntervals Times when the route should be active - These must match the name at time_intervals - items: - type: string - type: array - continue: - description: |- - Continue indicating whether an alert should continue matching subsequent - sibling nodes. It will always be true for the first-level route if disableRouteContinueEnforce for vmalertmanager not set. - type: boolean - group_by: - description: List of labels to group by. - items: - type: string - type: array - group_interval: - description: How long to wait before sending an updated notification. - pattern: '[0-9]+(ms|s|m|h)' - type: string - group_wait: - description: How long to wait before sending the initial notification. - pattern: '[0-9]+(ms|s|m|h)' - type: string - matchers: - description: |- - List of matchers that the alert’s labels should match. For the first - level route, the operator adds a namespace: "CRD_NS" matcher. - https://prometheus.io/docs/alerting/latest/configuration/#matcher - items: - type: string - type: array - mute_time_intervals: - description: MuteTimeIntervals is a list of interval names that - will mute matched alert - items: - type: string - type: array - receiver: - description: Name of the receiver for this route. - type: string - repeat_interval: - description: How long to wait before repeating the last notification. - pattern: '[0-9]+(ms|s|m|h)' - type: string - routes: - description: |- - Child routes. - https://prometheus.io/docs/alerting/latest/configuration/#route - items: - x-kubernetes-preserve-unknown-fields: true - type: array - required: - - receiver - type: object - time_intervals: - description: |- - TimeIntervals defines named interval for active/mute notifications interval - See https://prometheus.io/docs/alerting/latest/configuration/#time_interval - items: - description: TimeIntervals for alerts - properties: - name: - description: Name of interval - type: string - time_intervals: - description: TimeIntervals interval configuration - items: - description: TimeInterval defines intervals of time - properties: - days_of_month: - description: |- - DayOfMonth defines list of numerical days in the month. Days begin at 1. Negative values are also accepted. - for example, ['1:5', '-3:-1'] - items: - type: string - type: array - location: - description: Location in golang time location form, e.g. - UTC - type: string - months: - description: |- - Months defines list of calendar months identified by a case-insensitive name (e.g. ‘January’) or numeric 1. - For example, ['1:3', 'may:august', 'december'] - items: - type: string - type: array - times: - description: Times defines time range for mute - items: - description: TimeRange ranges inclusive of the starting - time and exclusive of the end time - properties: - end_time: - description: EndTime for example HH:MM - type: string - start_time: - description: StartTime for example HH:MM - type: string - required: - - end_time - - start_time - type: object - type: array - weekdays: - description: Weekdays defines list of days of the week, - where the week begins on Sunday and ends on Saturday. - items: - type: string - type: array - years: - description: |- - Years defines numerical list of years, ranges are accepted. - For example, ['2020:2022', '2030'] - items: - type: string - type: array - type: object - type: array - required: - - name - - time_intervals - type: object - type: array - required: - - receivers - - route type: object + x-kubernetes-preserve-unknown-fields: true status: - description: VMAlertmanagerConfigStatus defines the observed state of - VMAlertmanagerConfig properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -10148,16 +592,11 @@ spec: lastErrorParentAlertmanagerName: type: string observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -10170,7 +609,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmalertmanagers.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -10198,2433 +637,45 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMAlertmanager represents Victoria-Metrics deployment for Alertmanager. 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: |- - Specification of the desired behavior of the VMAlertmanager cluster. More info: - https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - properties: - additionalPeers: - description: AdditionalPeers allows injecting a set of additional - Alertmanagers to peer with to form a highly available cluster. - items: - type: string - type: array - affinity: - description: Affinity If specified, the pod's scheduling constraints. - type: object - x-kubernetes-preserve-unknown-fields: true - claimTemplates: - description: ClaimTemplates allows adding additional VolumeClaimTemplates - for StatefulSet - items: - description: PersistentVolumeClaim is a user's request for and claim - to a persistent volume - 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: - description: |- - Standard object's metadata. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - type: object - x-kubernetes-preserve-unknown-fields: true - spec: - description: |- - spec defines the desired characteristics of a volume requested by a pod author. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes to consider - for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to the - PersistentVolume backing this claim. - type: string - type: object - status: - description: |- - status represents the current information/status of a persistent volume claim. - Read-only. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the actual access modes the volume backing the PVC has. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - allocatedResourceStatuses: - additionalProperties: - description: |- - When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource - that it does not recognizes, then it should ignore that update and let other controllers - handle it. - type: string - description: "allocatedResourceStatuses stores status of - resource being resized for the given PVC.\nKey names follow - standard Kubernetes label syntax. Valid values are either:\n\t* - Un-prefixed keys:\n\t\t- storage - the capacity of the - volume.\n\t* Custom resources must use implementation-defined - prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not be used.\n\nClaimResourceStatus - can be in any of following states:\n\t- ControllerResizeInProgress:\n\t\tState - set when resize controller starts resizing the volume - in control-plane.\n\t- ControllerResizeFailed:\n\t\tState - set when resize has failed in resize controller with a - terminal error.\n\t- NodeResizePending:\n\t\tState set - when resize controller has finished resizing the volume - but further resizing of\n\t\tvolume is needed on the node.\n\t- - NodeResizeInProgress:\n\t\tState set when kubelet starts - resizing the volume.\n\t- NodeResizeFailed:\n\t\tState - set when resizing has failed in kubelet with a terminal - error. Transient errors don't set\n\t\tNodeResizeFailed.\nFor - example: if expanding a PVC for more capacity - this field - can be one of the following states:\n\t- pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeFailed\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizePending\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeFailed\"\nWhen this field is not set, it - means that no resize operation is in progress for the - given PVC.\n\nA controller that receives PVC update with - previously unknown resourceName or ClaimResourceStatus\nshould - ignore the update for the purpose it was designed. For - example - a controller that\nonly is responsible for resizing - capacity of the volume, should ignore PVC updates that - change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." - type: object - x-kubernetes-map-type: granular - allocatedResources: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: "allocatedResources tracks the resources allocated - to a PVC including its capacity.\nKey names follow standard - Kubernetes label syntax. Valid values are either:\n\t* - Un-prefixed keys:\n\t\t- storage - the capacity of the - volume.\n\t* Custom resources must use implementation-defined - prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not be used.\n\nCapacity - reported here may be larger than the actual capacity when - a volume expansion operation\nis requested.\nFor storage - quota, the larger value from allocatedResources and PVC.spec.resources - is used.\nIf allocatedResources is not set, PVC.spec.resources - alone is used for quota calculation.\nIf a volume expansion - capacity request is lowered, allocatedResources is only\nlowered - if there are no expansion operations in progress and if - the actual volume capacity\nis equal or lower than the - requested capacity.\n\nA controller that receives PVC - update with previously unknown resourceName\nshould ignore - the update for the purpose it was designed. For example - - a controller that\nonly is responsible for resizing - capacity of the volume, should ignore PVC updates that - change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." - type: object - capacity: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: capacity represents the actual resources of - the underlying volume. - type: object - conditions: - description: |- - conditions is the current Condition of persistent volume claim. If underlying persistent volume is being - resized then the Condition will be set to 'Resizing'. - items: - description: PersistentVolumeClaimCondition contains details - about state of pvc - properties: - lastProbeTime: - description: lastProbeTime is the time we probed the - condition. - format: date-time - type: string - lastTransitionTime: - description: lastTransitionTime is the time the condition - transitioned from one status to another. - format: date-time - type: string - message: - description: message is the human-readable message - indicating details about last transition. - type: string - reason: - description: |- - reason is a unique, this should be a short, machine understandable string that gives the reason - for condition's last transition. If it reports "Resizing" that means the underlying - persistent volume is being resized. - type: string - status: - description: |- - Status is the status of the condition. - Can be True, False, Unknown. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=state%20of%20pvc-,conditions.status,-(string)%2C%20required - type: string - type: - description: |- - Type is the type of the condition. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=set%20to%20%27ResizeStarted%27.-,PersistentVolumeClaimCondition,-contains%20details%20about - type: string - required: - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - currentVolumeAttributesClassName: - description: |- - currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. - When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - type: string - modifyVolumeStatus: - description: |- - ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. - When this is unset, there is no ModifyVolume operation being attempted. - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - properties: - status: - description: "status is the status of the ControllerModifyVolume - operation. It can be in any of following states:\n - - Pending\n Pending indicates that the PersistentVolumeClaim - cannot be modified due to unmet requirements, such - as\n the specified VolumeAttributesClass not existing.\n - - InProgress\n InProgress indicates that the volume - is being modified.\n - Infeasible\n Infeasible indicates - that the request has been rejected as invalid by the - CSI driver. To\n\t resolve the error, a valid VolumeAttributesClass - needs to be specified.\nNote: New statuses can be - added in the future. Consumers should check for unknown - statuses and fail appropriately." - type: string - targetVolumeAttributesClassName: - description: targetVolumeAttributesClassName is the - name of the VolumeAttributesClass the PVC currently - being reconciled - type: string - required: - - status - type: object - phase: - description: phase represents the current phase of PersistentVolumeClaim. - type: string - type: object - type: object - type: array - clusterAdvertiseAddress: - description: |- - ClusterAdvertiseAddress is the explicit address to advertise in cluster. - Needs to be provided for non RFC1918 [1] (public) addresses. - [1] RFC1918: https://tools.ietf.org/html/rfc1918 - type: string - clusterDomainName: - description: |- - ClusterDomainName defines domain name suffix for in-cluster dns addresses - aka .cluster.local - used to build pod peer addresses for in-cluster communication - type: string - configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder - items: - type: string - type: array - configNamespaceSelector: - description: |2- - ConfigNamespaceSelector defines namespace selector for VMAlertmanagerConfig. - Works in combination with Selector. - NamespaceSelector nil - only objects at VMAlertmanager namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault - 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 - configRawYaml: - description: |- - ConfigRawYaml - raw configuration for alertmanager, - it helps it to start without secret. - priority -> hardcoded ConfigRaw -> ConfigRaw, provided by user -> ConfigSecret. - type: string - configReloaderExtraArgs: - additionalProperties: - type: string - description: |- - ConfigReloaderExtraArgs that will be passed to VMAuths config-reloader container - for example resyncInterval: "30s" - type: object - configReloaderImageTag: - description: ConfigReloaderImageTag defines image:tag for config-reloader - container - type: string - configReloaderResources: - description: |- - ConfigReloaderResources config-reloader container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - configSecret: - description: |- - ConfigSecret is the name of a Kubernetes Secret in the same namespace as the - VMAlertmanager object, which contains configuration for this VMAlertmanager, - configuration must be inside secret key: alertmanager.yaml. - It must be created by user. - instance. Defaults to 'vmalertmanager-' - The secret is mounted into /etc/alertmanager/config. - type: string - configSelector: - description: |- - ConfigSelector defines selector for VMAlertmanagerConfig, result config will be merged with with Raw or Secret config. - Works in combination with NamespaceSelector. - NamespaceSelector nil - only objects at VMAlertmanager namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault - 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 - containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. - items: - description: A single application container that you want to run - within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. - type: boolean - disableNamespaceMatcher: - description: |- - DisableNamespaceMatcher disables top route namespace label matcher for VMAlertmanagerConfig - It may be useful if alert doesn't have namespace label for some reason - type: boolean - disableRouteContinueEnforce: - description: DisableRouteContinueEnforce cancel the behavior for VMAlertmanagerConfig - that always enforce first-level route continue to true - type: boolean - disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable - type: boolean - dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. - items: - x-kubernetes-preserve-unknown-fields: true - properties: - nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. - items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. - properties: - name: - description: |- - Name is this DNS resolver option's name. - Required. - type: string - value: - description: Value is this DNS resolver option's value. - type: string - type: object - type: array - x-kubernetes-list-type: atomic - searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - dnsPolicy: - description: DNSPolicy sets DNS policy for the pod - type: string - enforcedTopRouteMatchers: - description: |- - EnforcedTopRouteMatchers defines label matchers to be added for the top route - of VMAlertmanagerConfig - It allows to make some set of labels required for alerts. - https://prometheus.io/docs/alerting/latest/configuration/#matcher - items: - type: string - type: array - externalURL: - description: |- - ExternalURL the VMAlertmanager instances will be available under. This is - necessary to generate correct URLs. This is necessary if VMAlertmanager is not - served from root of a DNS name. - type: string - extraArgs: - additionalProperties: - type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp - type: object - extraEnvs: - description: ExtraEnvs that will be passed to the application container - items: - description: EnvVar represents an environment variable present in - a Container. - properties: - name: - description: Name of the environment variable. Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap - items: - description: EnvFromSource represents the source of a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - gossipConfig: - description: GossipConfig defines gossip TLS configuration for Alertmanager - cluster - properties: - tls_client_config: - description: TLSClientConfig defines client TLS configuration - for alertmanager - properties: - ca_file: - description: |- - CAFile defines path to the pre-mounted file with CA - mutually exclusive with CASecretRef - type: string - ca_secret_ref: - description: |- - CA defines reference for secret with CA content under given key - mutually exclusive with CAFile - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - cert_file: - description: |- - CertFile defines path to the pre-mounted file with certificate - mutually exclusive with CertSecretRef - type: string - cert_secret_ref: - description: |- - CertSecretRef defines reference for secret with certificate content under given key - mutually exclusive with CertFile - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - insecure_skip_verify: - description: |- - Cert defines reference for secret with CA content under given key - mutually exclusive with CertFile - type: boolean - key_file: - description: |- - KeyFile defines path to the pre-mounted file with certificate key - mutually exclusive with KeySecretRef - type: string - key_secret_ref: - description: |- - Key defines reference for secret with certificate key content under given key - mutually exclusive with KeyFile - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - server_name: - description: ServerName indicates a name of a server - type: string - type: object - tls_server_config: - description: TLSServerConfig defines server TLS configuration - for alertmanager - properties: - cert_file: - description: |- - CertFile defines path to the pre-mounted file with certificate - mutually exclusive with CertSecretRef - type: string - cert_secret_ref: - description: |- - CertSecretRef defines reference for secret with certificate content under given key - mutually exclusive with CertFile - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - cipher_suites: - description: |- - CipherSuites defines list of supported cipher suites for TLS versions up to TLS 1.2 - https://golang.org/pkg/crypto/tls/#pkg-constants - items: - type: string - type: array - client_auth_type: - description: |- - Cert defines reference for secret with CA content under given key - mutually exclusive with CertFile - ClientAuthType defines server policy for client authentication - If you want to enable client authentication (aka mTLS), you need to use RequireAndVerifyClientCert - Note, mTLS is supported only at enterprise version of VictoriaMetrics components - enum: - - NoClientCert - - RequireAndVerifyClientCert - type: string - client_ca_file: - description: |- - ClientCAFile defines path to the pre-mounted file with CA - mutually exclusive with ClientCASecretRef - type: string - client_ca_secret_ref: - description: |- - ClientCASecretRef defines reference for secret with CA content under given key - mutually exclusive with ClientCAFile - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - curve_preferences: - description: |- - CurvePreferences defines elliptic curves that will be used in an ECDHE handshake, in preference order. - https://golang.org/pkg/crypto/tls/#CurveID - items: - type: string - type: array - key_file: - description: |- - KeyFile defines path to the pre-mounted file with certificate key - mutually exclusive with KeySecretRef - type: string - key_secret_ref: - description: |- - Key defines reference for secret with certificate key content under given key - mutually exclusive with KeyFile - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - max_version: - description: MaxVersion maximum TLS version that is acceptable. - enum: - - TLS10 - - TLS11 - - TLS12 - - TLS13 - type: string - min_version: - description: MinVersion minimum TLS version that is acceptable. - enum: - - TLS10 - - TLS11 - - TLS12 - - TLS13 - type: string - prefer_server_cipher_suites: - description: |- - PreferServerCipherSuites controls whether the server selects the - client's most preferred ciphersuite - type: boolean - type: object - type: object - host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostNetwork: - description: HostNetwork controls whether the pod may use the node - network namespace - type: boolean - image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config - properties: - pullPolicy: - description: PullPolicy describes how to pull docker image - type: string - repository: - description: Repository contains name of docker image + it's repository - if needed - type: string - tag: - description: Tag contains desired docker image version - type: string - type: object - imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - items: - description: A single application container that you want to run - within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - listenLocal: - description: |- - ListenLocal makes the VMAlertmanager server listen on loopback, so that it - does not bind against the Pod IP. Note this is only for the VMAlertmanager - UI, not the gossip communication. - type: boolean - livenessProbe: - description: LivenessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - logFormat: - description: LogFormat for VMAlertmanager to be configured with. - enum: - - logfmt - - json - type: string - logLevel: - description: Log level for VMAlertmanager to be configured with. - enum: - - debug - - info - - warn - - error - - DEBUG - - INFO - - WARN - - ERROR - type: string - managedMetadata: - description: |- - ManagedMetadata defines metadata that will be added to the all objects - created by operator for the given CustomResource - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - type: object - minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle - format: int32 - type: integer - nodeSelector: - additionalProperties: - type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. - type: object - paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. - type: boolean - podDisruptionBudget: - description: PodDisruptionBudget created by operator - properties: - maxUnavailable: - anyOf: - - type: integer - - type: string - description: |- - An eviction is allowed if at most "maxUnavailable" pods selected by - "selector" are unavailable after the eviction, i.e. even in absence of - the evicted pod. For example, one can prevent all voluntary evictions - by specifying 0. This is a mutually exclusive setting with "minAvailable". - x-kubernetes-int-or-string: true - minAvailable: - anyOf: - - type: integer - - type: string - description: |- - An eviction is allowed if at least "minAvailable" pods selected by - "selector" will still be available after the eviction, i.e. even in the - absence of the evicted pod. So for example you can prevent all voluntary - evictions by specifying "100%". - x-kubernetes-int-or-string: true - selectorLabels: - additionalProperties: - type: string - description: |- - replaces default labels selector generated by operator - it's useful when you need to create custom budget - type: object - type: object - podMetadata: - description: PodMetadata configures Labels and Annotations which are - propagated to the alertmanager pods. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - port: - description: Port listen address - type: string - portName: - description: |- - PortName used for the pods and governing service. - This defaults to web - type: string - priorityClassName: - description: PriorityClassName class assigned to the Pods - type: string - readinessGates: - description: ReadinessGates defines pod readiness gates - items: - description: PodReadinessGate contains the reference to a pod condition - properties: - conditionType: - description: ConditionType refers to a condition in the pod's - condition list with matching type. - type: string - required: - - conditionType - type: object - type: array - readinessProbe: - description: ReadinessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - replicaCount: - description: ReplicaCount is the expected size of the Application. - format: int32 - type: integer - resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - retention: - description: |- - Retention Time duration VMAlertmanager shall retain data for. Default is '120h', - and must match the regular expression `[0-9]+(ms|s|m|h)` (milliseconds seconds minutes hours). - pattern: '[0-9]+(ms|s|m|h)' - type: string - revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. - format: int32 - type: integer - rollingUpdateStrategy: - description: |- - RollingUpdateStrategy defines strategy for application updates - Default is OnDelete, in this case operator handles update process - Can be changed for RollingUpdate - type: string - routePrefix: - description: |- - RoutePrefix VMAlertmanager registers HTTP handlers for. This is useful, - if using ExternalURL and a proxy is rewriting HTTP routes of a request, - and the actual ExternalURL is still true, but the server serves requests - under a different route prefix. For example for use with `kubectl proxy`. - type: string - runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ - type: string - schedulerName: - description: SchedulerName - defines kubernetes scheduler name - type: string - secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder - items: - type: string - type: array - securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. - type: object - x-kubernetes-preserve-unknown-fields: true - selectAllByDefault: - description: |- - SelectAllByDefault changes default behavior for empty CRD selectors, such ConfigSelector. - with selectAllByDefault: true and undefined ConfigSelector and ConfigNamespaceSelector - Operator selects all exist alertManagerConfigs - with selectAllByDefault: false - selects nothing - type: boolean - serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to use to run the pods - type: string - serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vmalertmanager - VMServiceScrape spec - required: - - endpoints - type: object - x-kubernetes-preserve-unknown-fields: true - serviceSpec: - description: ServiceSpec that will be added to vmalertmanager service - spec - properties: - metadata: - description: EmbeddedObjectMetadata defines objectMeta for additional - service. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ - type: object - x-kubernetes-preserve-unknown-fields: true - useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication - type: boolean - required: - - spec - type: object - startupProbe: - description: StartupProbe that will be added to CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - storage: - description: |- - Storage is the definition of how storage will be used by the VMAlertmanager - instances. - properties: - disableMountSubPath: - description: |- - Deprecated: subPath usage will be disabled by default in a future release, this option will become unnecessary. - DisableMountSubPath allows to remove any subPath usage in volume mounts. - type: boolean - emptyDir: - description: |- - EmptyDirVolumeSource to be used by the Prometheus StatefulSets. If specified, used in place of any volumeClaimTemplate. More - info: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir - properties: - medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - volumeClaimTemplate: - description: A PVC spec to be used by the VMAlertManager StatefulSets. - 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: - description: EmbeddedMetadata contains metadata relevant to - an EmbeddedResource. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - spec: - description: |- - Spec defines the desired characteristics of a volume requested by a pod author. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes to - consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to the - PersistentVolume backing this claim. - type: string - type: object - status: - description: |- - Status represents the current information/status of a persistent volume claim. - Read-only. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the actual access modes the volume backing the PVC has. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - allocatedResourceStatuses: - additionalProperties: - description: |- - When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource - that it does not recognizes, then it should ignore that update and let other controllers - handle it. - type: string - description: "allocatedResourceStatuses stores status - of resource being resized for the given PVC.\nKey names - follow standard Kubernetes label syntax. Valid values - are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources must - use implementation-defined prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have - kubernetes.io prefix are considered\nreserved and hence - may not be used.\n\nClaimResourceStatus can be in any - of following states:\n\t- ControllerResizeInProgress:\n\t\tState - set when resize controller starts resizing the volume - in control-plane.\n\t- ControllerResizeFailed:\n\t\tState - set when resize has failed in resize controller with - a terminal error.\n\t- NodeResizePending:\n\t\tState - set when resize controller has finished resizing the - volume but further resizing of\n\t\tvolume is needed - on the node.\n\t- NodeResizeInProgress:\n\t\tState set - when kubelet starts resizing the volume.\n\t- NodeResizeFailed:\n\t\tState - set when resizing has failed in kubelet with a terminal - error. Transient errors don't set\n\t\tNodeResizeFailed.\nFor - example: if expanding a PVC for more capacity - this - field can be one of the following states:\n\t- pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeFailed\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizePending\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeFailed\"\nWhen this field is not set, - it means that no resize operation is in progress for - the given PVC.\n\nA controller that receives PVC update - with previously unknown resourceName or ClaimResourceStatus\nshould - ignore the update for the purpose it was designed. For - example - a controller that\nonly is responsible for - resizing capacity of the volume, should ignore PVC updates - that change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." - type: object - x-kubernetes-map-type: granular - allocatedResources: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: "allocatedResources tracks the resources - allocated to a PVC including its capacity.\nKey names - follow standard Kubernetes label syntax. Valid values - are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources must - use implementation-defined prefixed names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or have - kubernetes.io prefix are considered\nreserved and hence - may not be used.\n\nCapacity reported here may be larger - than the actual capacity when a volume expansion operation\nis - requested.\nFor storage quota, the larger value from - allocatedResources and PVC.spec.resources is used.\nIf - allocatedResources is not set, PVC.spec.resources alone - is used for quota calculation.\nIf a volume expansion - capacity request is lowered, allocatedResources is only\nlowered - if there are no expansion operations in progress and - if the actual volume capacity\nis equal or lower than - the requested capacity.\n\nA controller that receives - PVC update with previously unknown resourceName\nshould - ignore the update for the purpose it was designed. For - example - a controller that\nonly is responsible for - resizing capacity of the volume, should ignore PVC updates - that change other valid\nresources associated with PVC.\n\nThis - is an alpha field and requires enabling RecoverVolumeExpansionFailure - feature." - type: object - capacity: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: capacity represents the actual resources - of the underlying volume. - type: object - conditions: - description: |- - conditions is the current Condition of persistent volume claim. If underlying persistent volume is being - resized then the Condition will be set to 'Resizing'. - items: - description: PersistentVolumeClaimCondition contains - details about state of pvc - properties: - lastProbeTime: - description: lastProbeTime is the time we probed - the condition. - format: date-time - type: string - lastTransitionTime: - description: lastTransitionTime is the time the - condition transitioned from one status to another. - format: date-time - type: string - message: - description: message is the human-readable message - indicating details about last transition. - type: string - reason: - description: |- - reason is a unique, this should be a short, machine understandable string that gives the reason - for condition's last transition. If it reports "Resizing" that means the underlying - persistent volume is being resized. - type: string - status: - description: |- - Status is the status of the condition. - Can be True, False, Unknown. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=state%20of%20pvc-,conditions.status,-(string)%2C%20required - type: string - type: - description: |- - Type is the type of the condition. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=set%20to%20%27ResizeStarted%27.-,PersistentVolumeClaimCondition,-contains%20details%20about - type: string - required: - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - currentVolumeAttributesClassName: - description: |- - currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. - When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - type: string - modifyVolumeStatus: - description: |- - ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. - When this is unset, there is no ModifyVolume operation being attempted. - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - properties: - status: - description: "status is the status of the ControllerModifyVolume - operation. It can be in any of following states:\n - - Pending\n Pending indicates that the PersistentVolumeClaim - cannot be modified due to unmet requirements, such - as\n the specified VolumeAttributesClass not existing.\n - - InProgress\n InProgress indicates that the volume - is being modified.\n - Infeasible\n Infeasible - indicates that the request has been rejected as - invalid by the CSI driver. To\n\t resolve the error, - a valid VolumeAttributesClass needs to be specified.\nNote: - New statuses can be added in the future. Consumers - should check for unknown statuses and fail appropriately." - type: string - targetVolumeAttributesClassName: - description: targetVolumeAttributesClassName is the - name of the VolumeAttributesClass the PVC currently - being reconciled - type: string - required: - - status - type: object - phase: - description: phase represents the current phase of PersistentVolumeClaim. - type: string - type: object - type: object - type: object - templates: - description: |- - Templates is a list of ConfigMap key references for ConfigMaps in the same namespace as the VMAlertmanager - object, which shall be mounted into the VMAlertmanager Pods. - The Templates are mounted into /etc/vm/templates//. - items: - description: ConfigMapKeyReference refers to a key in a ConfigMap. - properties: - key: - description: The ConfigMap key to refer to. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - required: - - key - type: object - x-kubernetes-map-type: atomic - type: array - terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container graceful - termination - format: int64 - type: integer - tolerations: - description: Tolerations If specified, the pod's tolerations. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - items: - description: TopologySpreadConstraint specifies how to spread matching - pods among the given topology. - required: - - maxSkew - - topologyKey - - whenUnsatisfiable - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements - type: boolean - useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions - type: boolean - useVMConfigReloader: - description: |- - UseVMConfigReloader replaces prometheus-like config-reloader - with vm one. It uses secrets watch instead of file watch - which greatly increases speed of config updates - type: boolean - volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container - items: - description: VolumeMount describes a mounting of a Volume within - a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional - items: - description: Volume represents a named volume in a pod that may - be accessed by any container in the pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - webConfig: - description: |- - WebConfig defines configuration for webserver - https://github.com/prometheus/alertmanager/blob/main/docs/https.md - properties: - basic_auth_users: - additionalProperties: - type: string - description: |- - BasicAuthUsers Usernames and hashed passwords that have full access to the web server - Passwords must be hashed with bcrypt - type: object - http_server_config: - description: HTTPServerConfig defines http server configuration - for alertmanager web server - properties: - headers: - additionalProperties: - type: string - description: Headers defines list of headers that can be added - to HTTP responses. - type: object - http2: - description: |- - HTTP2 enables HTTP/2 support. Note that HTTP/2 is only supported with TLS. - This can not be changed on the fly. - type: boolean - type: object - tls_server_config: - description: TLSServerConfig defines server TLS configuration - for alertmanager - properties: - cert_file: - description: |- - CertFile defines path to the pre-mounted file with certificate - mutually exclusive with CertSecretRef - type: string - cert_secret_ref: - description: |- - CertSecretRef defines reference for secret with certificate content under given key - mutually exclusive with CertFile - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - cipher_suites: - description: |- - CipherSuites defines list of supported cipher suites for TLS versions up to TLS 1.2 - https://golang.org/pkg/crypto/tls/#pkg-constants - items: - type: string - type: array - client_auth_type: - description: |- - Cert defines reference for secret with CA content under given key - mutually exclusive with CertFile - ClientAuthType defines server policy for client authentication - If you want to enable client authentication (aka mTLS), you need to use RequireAndVerifyClientCert - Note, mTLS is supported only at enterprise version of VictoriaMetrics components - enum: - - NoClientCert - - RequireAndVerifyClientCert - type: string - client_ca_file: - description: |- - ClientCAFile defines path to the pre-mounted file with CA - mutually exclusive with ClientCASecretRef - type: string - client_ca_secret_ref: - description: |- - ClientCASecretRef defines reference for secret with CA content under given key - mutually exclusive with ClientCAFile - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - curve_preferences: - description: |- - CurvePreferences defines elliptic curves that will be used in an ECDHE handshake, in preference order. - https://golang.org/pkg/crypto/tls/#CurveID - items: - type: string - type: array - key_file: - description: |- - KeyFile defines path to the pre-mounted file with certificate key - mutually exclusive with KeySecretRef - type: string - key_secret_ref: - description: |- - Key defines reference for secret with certificate key content under given key - mutually exclusive with KeyFile - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - max_version: - description: MaxVersion maximum TLS version that is acceptable. - enum: - - TLS10 - - TLS11 - - TLS12 - - TLS13 - type: string - min_version: - description: MinVersion minimum TLS version that is acceptable. - enum: - - TLS10 - - TLS11 - - TLS12 - - TLS13 - type: string - prefer_server_cipher_suites: - description: |- - PreferServerCipherSuites controls whether the server selects the - client's most preferred ciphersuite - type: boolean - type: object - type: object type: object + x-kubernetes-preserve-unknown-fields: true status: - description: |- - Most recent observed status of the VMAlertmanager cluster. - Operator API itself. More info: - https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -12639,16 +690,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object required: @@ -12663,7 +709,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmalerts.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -12679,7 +725,7 @@ spec: jsonPath: .status.updateStatus name: Status type: string - - description: The desired replicas number of Alertmanagers + - description: The desired replicas number of VMAlerts jsonPath: .spec.replicaCount name: ReplicaCount type: integer @@ -12689,1924 +735,47 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMAlert executes a list of given alerting or recording rules - against configured address. 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: VMAlertSpec defines the desired state of VMAlert - properties: - affinity: - description: Affinity If specified, the pod's scheduling constraints. - type: object - x-kubernetes-preserve-unknown-fields: true - configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder - items: - type: string - type: array - configReloaderExtraArgs: - additionalProperties: - type: string - description: |- - ConfigReloaderExtraArgs that will be passed to VMAuths config-reloader container - for example resyncInterval: "30s" - type: object - configReloaderImageTag: - description: ConfigReloaderImageTag defines image:tag for config-reloader - container - type: string - configReloaderResources: - description: |- - ConfigReloaderResources config-reloader container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. - items: - description: A single application container that you want to run - within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - datasource: - description: Datasource Victoria Metrics or VMSelect url. Required - parameter. e.g. http://127.0.0.1:8428 - properties: - basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearerTokenFile: - description: Path to bearer token file - type: string - bearerTokenSecret: - description: Optional bearer auth token to use for -remoteWrite.url - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - headers: - description: |- - Headers allow configuring custom http headers - Must be in form of semicolon separated header with value - e.g. - headerName:headerValue - vmalert supports it since 1.79.0 version - items: - type: string - type: array - oauth2: - description: OAuth2 defines OAuth2 configuration - required: - - client_id - - token_url - type: object - x-kubernetes-preserve-unknown-fields: true - tlsConfig: - description: TLSConfig specifies TLSConfig configuration parameters. - type: object - x-kubernetes-preserve-unknown-fields: true - url: - description: Victoria Metrics or VMSelect url. Required parameter. - E.g. http://127.0.0.1:8428 - type: string - required: - - url - type: object - disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. - type: boolean - disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable - type: boolean - dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. - items: - x-kubernetes-preserve-unknown-fields: true - properties: - nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. - items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. - properties: - name: - description: |- - Name is this DNS resolver option's name. - Required. - type: string - value: - description: Value is this DNS resolver option's value. - type: string - type: object - type: array - x-kubernetes-list-type: atomic - searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - dnsPolicy: - description: DNSPolicy sets DNS policy for the pod - type: string - enforcedNamespaceLabel: - description: |- - EnforcedNamespaceLabel enforces adding a namespace label of origin for each alert - and metric that is user created. The label value will always be the namespace of the object that is - being created. - type: string - evaluationInterval: - description: EvaluationInterval defines how often to evaluate rules - by default - pattern: '[0-9]+(ms|s|m|h)' - type: string - externalLabels: - additionalProperties: - type: string - description: 'ExternalLabels in the form ''name: value'' to add to - all generated recording rules and alerts.' - type: object - extraArgs: - additionalProperties: - type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp - type: object - extraEnvs: - description: ExtraEnvs that will be passed to the application container - items: - description: EnvVar represents an environment variable present in - a Container. - properties: - name: - description: Name of the environment variable. Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap - items: - description: EnvFromSource represents the source of a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostNetwork: - description: HostNetwork controls whether the pod may use the node - network namespace - type: boolean - image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config - properties: - pullPolicy: - description: PullPolicy describes how to pull docker image - type: string - repository: - description: Repository contains name of docker image + it's repository - if needed - type: string - tag: - description: Tag contains desired docker image version - type: string - type: object - imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - items: - description: A single application container that you want to run - within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - license: - description: |- - License allows to configure license key to be used for enterprise features. - Using license key is supported starting from VictoriaMetrics v1.94.0. - See [here](https://docs.victoriametrics.com/enterprise) - properties: - forceOffline: - description: Enforce offline verification of the license key. - type: boolean - key: - description: |- - Enterprise license key. This flag is available only in [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise). - To request a trial license, [go to](https://victoriametrics.com/products/enterprise/trial) - type: string - keyRef: - description: KeyRef is reference to secret with license key for - enterprise features. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - reloadInterval: - description: Interval to be used for checking for license key - changes. Note that this is only applicable when using KeyRef. - type: string - type: object - livenessProbe: - description: LivenessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - logFormat: - description: |- - LogFormat for VMAlert to be configured with. - default or json - enum: - - default - - json - type: string - logLevel: - description: LogLevel for VMAlert to be configured with. - enum: - - INFO - - WARN - - ERROR - - FATAL - - PANIC - type: string - managedMetadata: - description: |- - ManagedMetadata defines metadata that will be added to the all objects - created by operator for the given CustomResource - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - type: object - minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle - format: int32 - type: integer - nodeSelector: - additionalProperties: - type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. - type: object - notifier: - description: |- - Notifier prometheus alertmanager endpoint spec. Required at least one of notifier or notifiers when there are alerting rules. e.g. http://127.0.0.1:9093 - If specified both notifier and notifiers, notifier will be added as last element to notifiers. - only one of notifier options could be chosen: notifierConfigRef or notifiers + notifier - properties: - basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearerTokenFile: - description: Path to bearer token file - type: string - bearerTokenSecret: - description: Optional bearer auth token to use for -remoteWrite.url - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - headers: - description: |- - Headers allow configuring custom http headers - Must be in form of semicolon separated header with value - e.g. - headerName:headerValue - vmalert supports it since 1.79.0 version - items: - type: string - type: array - oauth2: - description: OAuth2 defines OAuth2 configuration - required: - - client_id - - token_url - type: object - x-kubernetes-preserve-unknown-fields: true - selector: - description: |- - Selector allows service discovery for alertmanager - in this case all matched vmalertmanager replicas will be added into vmalert notifier.url - as statefulset pod.fqdn - properties: - labelSelector: - description: |- - A label selector is a label query over a set of resources. The result of matchLabels and - matchExpressions are ANDed. An empty label selector matches all objects. A null - label selector matches no objects. - 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 - namespaceSelector: - description: |- - NamespaceSelector is a selector for selecting either all namespaces or a - list of namespaces. - properties: - any: - description: |- - Boolean describing whether all namespaces are selected in contrast to a - list restricting them. - type: boolean - matchNames: - description: List of namespace names. - items: - type: string - type: array - type: object - type: object - tlsConfig: - description: TLSConfig specifies TLSConfig configuration parameters. - type: object - x-kubernetes-preserve-unknown-fields: true - url: - description: AlertManager url. E.g. http://127.0.0.1:9093 - type: string - type: object - notifierConfigRef: - description: |- - NotifierConfigRef reference for secret with notifier configuration for vmalert - only one of notifier options could be chosen: notifierConfigRef or notifiers + notifier - properties: - key: - description: The key of the secret to select from. Must be a - valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - notifiers: - description: |- - Notifiers prometheus alertmanager endpoints. Required at least one of notifier or notifiers when there are alerting rules. e.g. http://127.0.0.1:9093 - If specified both notifier and notifiers, notifier will be added as last element to notifiers. - only one of notifier options could be chosen: notifierConfigRef or notifiers + notifier - items: - description: VMAlertNotifierSpec defines the notifier url for sending - information about alerts - properties: - basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearerTokenFile: - description: Path to bearer token file - type: string - bearerTokenSecret: - description: Optional bearer auth token to use for -remoteWrite.url - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - headers: - description: |- - Headers allow configuring custom http headers - Must be in form of semicolon separated header with value - e.g. - headerName:headerValue - vmalert supports it since 1.79.0 version - items: - type: string - type: array - oauth2: - description: OAuth2 defines OAuth2 configuration - required: - - client_id - - token_url - type: object - x-kubernetes-preserve-unknown-fields: true - selector: - description: |- - Selector allows service discovery for alertmanager - in this case all matched vmalertmanager replicas will be added into vmalert notifier.url - as statefulset pod.fqdn - properties: - labelSelector: - description: |- - A label selector is a label query over a set of resources. The result of matchLabels and - matchExpressions are ANDed. An empty label selector matches all objects. A null - label selector matches no objects. - 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 - namespaceSelector: - description: |- - NamespaceSelector is a selector for selecting either all namespaces or a - list of namespaces. - properties: - any: - description: |- - Boolean describing whether all namespaces are selected in contrast to a - list restricting them. - type: boolean - matchNames: - description: List of namespace names. - items: - type: string - type: array - type: object - type: object - tlsConfig: - description: TLSConfig specifies TLSConfig configuration parameters. - type: object - x-kubernetes-preserve-unknown-fields: true - url: - description: AlertManager url. E.g. http://127.0.0.1:9093 - type: string - type: object - type: array - paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. - type: boolean - podDisruptionBudget: - description: PodDisruptionBudget created by operator - properties: - maxUnavailable: - anyOf: - - type: integer - - type: string - description: |- - An eviction is allowed if at most "maxUnavailable" pods selected by - "selector" are unavailable after the eviction, i.e. even in absence of - the evicted pod. For example, one can prevent all voluntary evictions - by specifying 0. This is a mutually exclusive setting with "minAvailable". - x-kubernetes-int-or-string: true - minAvailable: - anyOf: - - type: integer - - type: string - description: |- - An eviction is allowed if at least "minAvailable" pods selected by - "selector" will still be available after the eviction, i.e. even in the - absence of the evicted pod. So for example you can prevent all voluntary - evictions by specifying "100%". - x-kubernetes-int-or-string: true - selectorLabels: - additionalProperties: - type: string - description: |- - replaces default labels selector generated by operator - it's useful when you need to create custom budget - type: object - type: object - podMetadata: - description: PodMetadata configures Labels and Annotations which are - propagated to the VMAlert pods. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - port: - description: Port listen address - type: string - priorityClassName: - description: PriorityClassName class assigned to the Pods - type: string - readinessGates: - description: ReadinessGates defines pod readiness gates - items: - description: PodReadinessGate contains the reference to a pod condition - properties: - conditionType: - description: ConditionType refers to a condition in the pod's - condition list with matching type. - type: string - required: - - conditionType - type: object - type: array - readinessProbe: - description: ReadinessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - remoteRead: - description: |- - RemoteRead Optional URL to read vmalert state (persisted via RemoteWrite) - This configuration only makes sense if alerts state has been successfully - persisted (via RemoteWrite) before. - see -remoteRead.url docs in vmalerts for details. - E.g. http://127.0.0.1:8428 - properties: - basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearerTokenFile: - description: Path to bearer token file - type: string - bearerTokenSecret: - description: Optional bearer auth token to use for -remoteWrite.url - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - headers: - description: |- - Headers allow configuring custom http headers - Must be in form of semicolon separated header with value - e.g. - headerName:headerValue - vmalert supports it since 1.79.0 version - items: - type: string - type: array - lookback: - description: |- - Lookback defines how far to look into past for alerts timeseries. For example, if lookback=1h then range from now() to now()-1h will be scanned. (default 1h0m0s) - Applied only to RemoteReadSpec - type: string - oauth2: - description: OAuth2 defines OAuth2 configuration - required: - - client_id - - token_url - type: object - x-kubernetes-preserve-unknown-fields: true - tlsConfig: - description: TLSConfig specifies TLSConfig configuration parameters. - type: object - x-kubernetes-preserve-unknown-fields: true - url: - description: URL of the endpoint to send samples to. - type: string - required: - - url - type: object - remoteWrite: - description: |- - RemoteWrite Optional URL to remote-write compatible storage to persist - vmalert state and rule results to. - Rule results will be persisted according to each rule. - Alerts state will be persisted in the form of time series named ALERTS and ALERTS_FOR_STATE - see -remoteWrite.url docs in vmalerts for details. - E.g. http://127.0.0.1:8428 - properties: - basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearerTokenFile: - description: Path to bearer token file - type: string - bearerTokenSecret: - description: Optional bearer auth token to use for -remoteWrite.url - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - concurrency: - description: Defines number of readers that concurrently write - into remote storage (default 1) - format: int32 - type: integer - flushInterval: - description: Defines interval of flushes to remote write endpoint - (default 5s) - pattern: '[0-9]+(ms|s|m|h)' - type: string - headers: - description: |- - Headers allow configuring custom http headers - Must be in form of semicolon separated header with value - e.g. - headerName:headerValue - vmalert supports it since 1.79.0 version - items: - type: string - type: array - maxBatchSize: - description: Defines defines max number of timeseries to be flushed - at once (default 1000) - format: int32 - type: integer - maxQueueSize: - description: Defines the max number of pending datapoints to remote - write endpoint (default 100000) - format: int32 - type: integer - oauth2: - description: OAuth2 defines OAuth2 configuration - required: - - client_id - - token_url - type: object - x-kubernetes-preserve-unknown-fields: true - tlsConfig: - description: TLSConfig specifies TLSConfig configuration parameters. - type: object - x-kubernetes-preserve-unknown-fields: true - url: - description: URL of the endpoint to send samples to. - type: string - required: - - url - type: object - replicaCount: - description: ReplicaCount is the expected size of the Application. - format: int32 - type: integer - resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. - format: int32 - type: integer - rollingUpdate: - description: RollingUpdate - overrides deployment update params. - properties: - maxSurge: - anyOf: - - type: integer - - type: string - description: |- - The maximum number of pods that can be scheduled above the desired number of - pods. - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). - This can not be 0 if MaxUnavailable is 0. - Absolute number is calculated from percentage by rounding up. - Defaults to 25%. - Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when - the rolling update starts, such that the total number of old and new pods do not exceed - 130% of desired pods. Once old pods have been killed, - new ReplicaSet can be scaled up further, ensuring that total number of pods running - at any time during the update is at most 130% of desired pods. - x-kubernetes-int-or-string: true - maxUnavailable: - anyOf: - - type: integer - - type: string - description: |- - The maximum number of pods that can be unavailable during the update. - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). - Absolute number is calculated from percentage by rounding down. - This can not be 0 if MaxSurge is 0. - Defaults to 25%. - Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods - immediately when the rolling update starts. Once new pods are ready, old ReplicaSet - can be scaled down further, followed by scaling up the new ReplicaSet, ensuring - that the total number of pods available at all times during the update is at - least 70% of desired pods. - x-kubernetes-int-or-string: true - type: object - ruleNamespaceSelector: - description: |- - RuleNamespaceSelector to be selected for VMRules discovery. - Works in combination with Selector. - If both nil - behaviour controlled by selectAllByDefault - NamespaceSelector nil - only objects at VMAlert namespace. - 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 - rulePath: - description: |- - RulePath to the file with alert rules. - Supports patterns. Flag can be specified multiple times. - Examples: - -rule /path/to/file. Path to a single file with alerting rules - -rule dir/*.yaml -rule /*.yaml. Relative path to all .yaml files in folder, - absolute path to all .yaml files in root. - by default operator adds /etc/vmalert/configs/base/vmalert.yaml - items: - type: string - type: array - ruleSelector: - description: |- - RuleSelector selector to select which VMRules to mount for loading alerting - rules from. - Works in combination with NamespaceSelector. - If both nil - behaviour controlled by selectAllByDefault - NamespaceSelector nil - only objects at VMAlert namespace. - 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 - runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ - type: string - schedulerName: - description: SchedulerName - defines kubernetes scheduler name - type: string - secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder - items: - type: string - type: array - securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. - type: object - x-kubernetes-preserve-unknown-fields: true - selectAllByDefault: - description: |- - SelectAllByDefault changes default behavior for empty CRD selectors, such RuleSelector. - with selectAllByDefault: true and empty serviceScrapeSelector and RuleNamespaceSelector - Operator selects all exist serviceScrapes - with selectAllByDefault: false - selects nothing - type: boolean - serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to use to run the pods - type: string - serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vmalert VMServiceScrape - spec - required: - - endpoints - type: object - x-kubernetes-preserve-unknown-fields: true - serviceSpec: - description: ServiceSpec that will be added to vmalert service spec - properties: - metadata: - description: EmbeddedObjectMetadata defines objectMeta for additional - service. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ - type: object - x-kubernetes-preserve-unknown-fields: true - useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication - type: boolean - required: - - spec - type: object - startupProbe: - description: StartupProbe that will be added to CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container graceful - termination - format: int64 - type: integer - tolerations: - description: Tolerations If specified, the pod's tolerations. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - items: - description: TopologySpreadConstraint specifies how to spread matching - pods among the given topology. - required: - - maxSkew - - topologyKey - - whenUnsatisfiable - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - updateStrategy: - description: UpdateStrategy - overrides default update strategy. - enum: - - Recreate - - RollingUpdate - type: string - useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements - type: boolean - useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions - type: boolean - useVMConfigReloader: - description: |- - UseVMConfigReloader replaces prometheus-like config-reloader - with vm one. It uses secrets watch instead of file watch - which greatly increases speed of config updates - type: boolean - volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container - items: - description: VolumeMount describes a mounting of a Volume within - a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional - items: - description: Volume represents a named volume in a pod that may - be accessed by any container in the pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array required: - datasource type: object + x-kubernetes-preserve-unknown-fields: true status: - description: VMAlertStatus defines the observed state of VMAlert properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -14621,16 +790,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -14643,7 +807,113 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 + name: vmanomalies.operator.victoriametrics.com +spec: + group: operator.victoriametrics.com + names: + kind: VMAnomaly + listKind: VMAnomalyList + plural: vmanomalies + singular: vmanomaly + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: current number of shards + jsonPath: .status.shards + name: Shards Count + type: integer + - description: Current status of update rollout + jsonPath: .status.updateStatus + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + required: + - reader + - writer + type: object + x-kubernetes-preserve-unknown-fields: true + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + maxLength: 32768 + type: string + observedGeneration: + format: int64 + minimum: 0 + type: integer + reason: + maxLength: 1024 + minLength: 1 + type: string + status: + enum: + - "True" + - "False" + - Unknown + type: string + type: + maxLength: 316 + type: string + required: + - lastTransitionTime + - lastUpdateTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + format: int64 + type: integer + reason: + type: string + shards: + format: int32 + type: integer + updateStatus: + type: string + type: object + type: object + served: true + storage: true + subresources: + scale: + labelSelectorPath: .status.selector + specReplicasPath: .spec.shardCount + statusReplicasPath: .status.shards + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.0 name: vmauths.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -14662,1659 +932,52 @@ spec: - jsonPath: .metadata.creationTimestamp name: Age type: date - - description: The desired replicas number of Alertmanagers + - description: The desired replicas number of VMAuth jsonPath: .spec.replicaCount name: ReplicaCount type: integer name: v1beta1 schema: openAPIV3Schema: - description: VMAuth is the Schema for the vmauths API 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: VMAuthSpec defines the desired state of VMAuth - properties: - affinity: - description: Affinity If specified, the pod's scheduling constraints. - type: object - x-kubernetes-preserve-unknown-fields: true - configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder - items: - type: string - type: array - configReloaderExtraArgs: - additionalProperties: - type: string - description: |- - ConfigReloaderExtraArgs that will be passed to VMAuths config-reloader container - for example resyncInterval: "30s" - type: object - configReloaderImageTag: - description: ConfigReloaderImageTag defines image:tag for config-reloader - container - type: string - configReloaderResources: - description: |- - ConfigReloaderResources config-reloader container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - configSecret: - description: |- - ConfigSecret is the name of a Kubernetes Secret in the same namespace as the - VMAuth object, which contains auth configuration for vmauth, - configuration must be inside secret key: config.yaml. - It must be created and managed manually. - If it's defined, configuration for vmauth becomes unmanaged and operator'll not create any related secrets/config-reloaders - Deprecated, use externalConfig.secretRef instead - type: string - containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. - items: - description: A single application container that you want to run - within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. - type: boolean - disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable - type: boolean - dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. - items: - x-kubernetes-preserve-unknown-fields: true - properties: - nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. - items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. - properties: - name: - description: |- - Name is this DNS resolver option's name. - Required. - type: string - value: - description: Value is this DNS resolver option's value. - type: string - type: object - type: array - x-kubernetes-list-type: atomic - searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - dnsPolicy: - description: DNSPolicy sets DNS policy for the pod - type: string - externalConfig: - description: |- - ExternalConfig defines a source of external VMAuth configuration. - If it's defined, configuration for vmauth becomes unmanaged and operator'll not create any related secrets/config-reloaders - properties: - localPath: - description: |- - LocalPath contains static path to a config, which is managed externally for cases - when using secrets is not applicable, e.g.: Vault sidecar. - type: string - secretRef: - description: SecretRef defines selector for externally managed - secret which contains configuration - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - extraArgs: - additionalProperties: - type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp - type: object - extraEnvs: - description: ExtraEnvs that will be passed to the application container - items: - description: EnvVar represents an environment variable present in - a Container. - properties: - name: - description: Name of the environment variable. Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap - items: - description: EnvFromSource represents the source of a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostNetwork: - description: HostNetwork controls whether the pod may use the node - network namespace - type: boolean - image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config - properties: - pullPolicy: - description: PullPolicy describes how to pull docker image - type: string - repository: - description: Repository contains name of docker image + it's repository - if needed - type: string - tag: - description: Tag contains desired docker image version - type: string - type: object - imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - ingress: - description: Ingress enables ingress configuration for VMAuth. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - class_name: - description: ClassName defines ingress class name for VMAuth - type: string - extraRules: - description: |- - ExtraRules - additional rules for ingress, - must be checked for correctness by user. - items: - description: |- - IngressRule represents the rules mapping the paths under a specified host to - the related backend services. Incoming requests are first evaluated for a host - match, then routed to the backend associated with the matching IngressRuleValue. - properties: - host: - description: "host is the fully qualified domain name of - a network host, as defined by RFC 3986.\nNote the following - deviations from the \"host\" part of the\nURI as defined - in RFC 3986:\n1. IPs are not allowed. Currently an IngressRuleValue - can only apply to\n the IP in the Spec of the parent - Ingress.\n2. The `:` delimiter is not respected because - ports are not allowed.\n\t Currently the port of an Ingress - is implicitly :80 for http and\n\t :443 for https.\nBoth - these may change in the future.\nIncoming requests are - matched against the host before the\nIngressRuleValue. - If the host is unspecified, the Ingress routes all\ntraffic - based on the specified IngressRuleValue.\n\nhost can be - \"precise\" which is a domain name without the terminating - dot of\na network host (e.g. \"foo.bar.com\") or \"wildcard\", - which is a domain name\nprefixed with a single wildcard - label (e.g. \"*.foo.com\").\nThe wildcard character '*' - must appear by itself as the first DNS label and\nmatches - only a single label. You cannot have a wildcard label - by itself (e.g. Host == \"*\").\nRequests will be matched - against the Host field in the following way:\n1. If host - is precise, the request matches this rule if the http - host header is equal to Host.\n2. If host is a wildcard, - then the request matches this rule if the http host header\nis - to equal to the suffix (removing the first label) of the - wildcard rule." - type: string - http: - description: |- - HTTPIngressRuleValue is a list of http selectors pointing to backends. - In the example: http:///? -> backend where - where parts of the url correspond to RFC 3986, this resource will be used - to match against everything after the last '/' and before the first '?' - or '#'. - properties: - paths: - description: paths is a collection of paths that map - requests to backends. - items: - description: |- - HTTPIngressPath associates a path with a backend. Incoming urls matching the - path are forwarded to the backend. - properties: - backend: - description: |- - backend defines the referenced service endpoint to which the traffic - will be forwarded to. - properties: - resource: - description: |- - resource is an ObjectRef to another Kubernetes resource in the namespace - of the Ingress object. If resource is specified, a service.Name and - service.Port must not be specified. - This is a mutually exclusive setting with "Service". - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource - being referenced - type: string - name: - description: Name is the name of resource - being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - service: - description: |- - service references a service as a backend. - This is a mutually exclusive setting with "Resource". - properties: - name: - description: |- - name is the referenced service. The service must exist in - the same namespace as the Ingress object. - type: string - port: - description: |- - port of the referenced service. A port name or port number - is required for a IngressServiceBackend. - properties: - name: - description: |- - name is the name of the port on the Service. - This is a mutually exclusive setting with "Number". - type: string - number: - description: |- - number is the numerical port number (e.g. 80) on the Service. - This is a mutually exclusive setting with "Name". - format: int32 - type: integer - type: object - x-kubernetes-map-type: atomic - required: - - name - type: object - type: object - path: - description: |- - path is matched against the path of an incoming request. Currently it can - contain characters disallowed from the conventional "path" part of a URL - as defined by RFC 3986. Paths must begin with a '/' and must be present - when using PathType with value "Exact" or "Prefix". - type: string - pathType: - description: |- - pathType determines the interpretation of the path matching. PathType can - be one of the following values: - * Exact: Matches the URL path exactly. - * Prefix: Matches based on a URL path prefix split by '/'. Matching is - done on a path element by element basis. A path element refers is the - list of labels in the path split by the '/' separator. A request is a - match for path p if every p is an element-wise prefix of p of the - request path. Note that if the last element of the path is a substring - of the last element in request path, it is not a match (e.g. /foo/bar - matches /foo/bar/baz, but does not match /foo/barbaz). - * ImplementationSpecific: Interpretation of the Path matching is up to - the IngressClass. Implementations can treat this as a separate PathType - or treat it identically to Prefix or Exact path types. - Implementations are required to support all path types. - type: string - required: - - backend - - pathType - type: object - type: array - x-kubernetes-list-type: atomic - required: - - paths - type: object - type: object - type: array - extraTls: - description: |- - ExtraTLS - additional TLS configuration for ingress - must be checked for correctness by user. - items: - description: IngressTLS describes the transport layer security - associated with an ingress. - properties: - hosts: - description: |- - hosts is a list of hosts included in the TLS certificate. The values in - this list must match the name/s used in the tlsSecret. Defaults to the - wildcard host setting for the loadbalancer controller fulfilling this - Ingress, if left unspecified. - items: - type: string - type: array - x-kubernetes-list-type: atomic - secretName: - description: |- - secretName is the name of the secret used to terminate TLS traffic on - port 443. Field is left optional to allow TLS routing based on SNI - hostname alone. If the SNI host in a listener conflicts with the "Host" - header field used by an IngressRule, the SNI host is used for termination - and value of the "Host" header is used for routing. - type: string - type: object - type: array - host: - description: |- - Host defines ingress host parameter for default rule - It will be used, only if TlsHosts is empty - type: string - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - tlsHosts: - description: TlsHosts configures TLS access for ingress, tlsSecretName - must be defined for it. - items: - type: string - type: array - tlsSecretName: - description: |- - TlsSecretName defines secretname at the VMAuth namespace with cert and key - https://kubernetes.io/docs/concepts/services-networking/ingress/#tls - type: string - type: object - initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - items: - description: A single application container that you want to run - within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - license: - description: |- - License allows to configure license key to be used for enterprise features. - Using license key is supported starting from VictoriaMetrics v1.94.0. - See [here](https://docs.victoriametrics.com/enterprise) - properties: - forceOffline: - description: Enforce offline verification of the license key. - type: boolean - key: - description: |- - Enterprise license key. This flag is available only in [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise). - To request a trial license, [go to](https://victoriametrics.com/products/enterprise/trial) - type: string - keyRef: - description: KeyRef is reference to secret with license key for - enterprise features. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - reloadInterval: - description: Interval to be used for checking for license key - changes. Note that this is only applicable when using KeyRef. - type: string - type: object - livenessProbe: - description: LivenessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - logFormat: - description: LogFormat for VMAuth to be configured with. - enum: - - default - - json - type: string - logLevel: - description: LogLevel for victoria metrics single to be configured - with. - enum: - - INFO - - WARN - - ERROR - - FATAL - - PANIC - type: string - managedMetadata: - description: |- - ManagedMetadata defines metadata that will be added to the all objects - created by operator for the given CustomResource - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - type: object - minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle - format: int32 - type: integer - nodeSelector: - additionalProperties: - type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. - type: object - paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. - type: boolean - podDisruptionBudget: - description: PodDisruptionBudget created by operator - properties: - maxUnavailable: - anyOf: - - type: integer - - type: string - description: |- - An eviction is allowed if at most "maxUnavailable" pods selected by - "selector" are unavailable after the eviction, i.e. even in absence of - the evicted pod. For example, one can prevent all voluntary evictions - by specifying 0. This is a mutually exclusive setting with "minAvailable". - x-kubernetes-int-or-string: true - minAvailable: - anyOf: - - type: integer - - type: string - description: |- - An eviction is allowed if at least "minAvailable" pods selected by - "selector" will still be available after the eviction, i.e. even in the - absence of the evicted pod. So for example you can prevent all voluntary - evictions by specifying "100%". - x-kubernetes-int-or-string: true - selectorLabels: - additionalProperties: - type: string - description: |- - replaces default labels selector generated by operator - it's useful when you need to create custom budget - type: object - type: object - podMetadata: - description: PodMetadata configures Labels and Annotations which are - propagated to the VMAuth pods. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - port: - description: Port listen address - type: string - priorityClassName: - description: PriorityClassName class assigned to the Pods - type: string - readinessGates: - description: ReadinessGates defines pod readiness gates - items: - description: PodReadinessGate contains the reference to a pod condition - properties: - conditionType: - description: ConditionType refers to a condition in the pod's - condition list with matching type. - type: string - required: - - conditionType - type: object - type: array - readinessProbe: - description: ReadinessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - replicaCount: - description: ReplicaCount is the expected size of the Application. - format: int32 - type: integer - resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. - format: int32 - type: integer - runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ - type: string - schedulerName: - description: SchedulerName - defines kubernetes scheduler name - type: string - secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder - items: - type: string - type: array - securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. - type: object - x-kubernetes-preserve-unknown-fields: true - selectAllByDefault: - description: |- - SelectAllByDefault changes default behavior for empty CRD selectors, such userSelector. - with selectAllByDefault: true and empty userSelector and userNamespaceSelector - Operator selects all exist users - with selectAllByDefault: false - selects nothing - type: boolean - serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to use to run the pods - type: string - serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vmauth VMServiceScrape - spec - required: - - endpoints - type: object - x-kubernetes-preserve-unknown-fields: true - serviceSpec: - description: ServiceSpec that will be added to vmsingle service spec - properties: - metadata: - description: EmbeddedObjectMetadata defines objectMeta for additional - service. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ - type: object - x-kubernetes-preserve-unknown-fields: true - useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication - type: boolean - required: - - spec - type: object - startupProbe: - description: StartupProbe that will be added to CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container graceful - termination - format: int64 - type: integer - tolerations: - description: Tolerations If specified, the pod's tolerations. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - items: - description: TopologySpreadConstraint specifies how to spread matching - pods among the given topology. - required: - - maxSkew - - topologyKey - - whenUnsatisfiable - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - unauthorizedAccessConfig: - description: |- - UnauthorizedAccessConfig configures access for un authorized users - - Deprecated, use unauthorizedUserAccessSpec instead - will be removed at v1.0 release - x-kubernetes-preserve-unknown-fields: true - unauthorizedUserAccessSpec: - description: UnauthorizedUserAccessSpec defines unauthorized_user - config section of vmauth config - properties: - default_url: - description: |- - DefaultURLs backend url for non-matching paths filter - usually used for default backend with error message - items: - type: string - type: array - discover_backend_ips: - description: DiscoverBackendIPs instructs discovering URLPrefix - backend IPs via DNS. - type: boolean - drop_src_path_prefix_parts: - description: |- - DropSrcPathPrefixParts is the number of `/`-delimited request path prefix parts to drop before proxying the request to backend. - See [here](https://docs.victoriametrics.com/vmauth#dropping-request-path-prefix) for more details. - type: integer - dump_request_on_errors: - description: |- - DumpRequestOnErrors instructs vmauth to return detailed request params to the client - if routing rules don't allow to forward request to the backends. - Useful for debugging `src_hosts` and `src_headers` based routing rules - - available since v1.107.0 vmauth version - type: boolean - headers: - description: |- - Headers represent additional http headers, that vmauth uses - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.68.0 version of vmauth - items: - type: string - type: array - ip_filters: - description: |- - IPFilters defines per target src ip filters - supported only with enterprise version of [vmauth](https://docs.victoriametrics.com/vmauth/#ip-filters) - properties: - allow_list: - items: - type: string - type: array - deny_list: - items: - type: string - type: array - type: object - load_balancing_policy: - description: |- - LoadBalancingPolicy defines load balancing policy to use for backend urls. - Supported policies: least_loaded, first_available. - See [here](https://docs.victoriametrics.com/vmauth#load-balancing) for more details (default "least_loaded") - enum: - - least_loaded - - first_available - type: string - max_concurrent_requests: - description: |- - MaxConcurrentRequests defines max concurrent requests per user - 300 is default value for vmauth - type: integer - metric_labels: - additionalProperties: - type: string - description: MetricLabels - additional labels for metrics exported - by vmauth for given user. - type: object - response_headers: - description: |- - ResponseHeaders represent additional http headers, that vmauth adds for request response - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.93.0 version of vmauth - items: - type: string - type: array - retry_status_codes: - description: |- - RetryStatusCodes defines http status codes in numeric format for request retries - e.g. [429,503] - items: - type: integer - type: array - tlsConfig: - description: TLSConfig defines tls configuration for the backend - connection - properties: - ca: - description: Struct containing the CA cert to use for the - targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container to use for - the targets. - type: string - cert: - description: Struct containing the client cert file for the - targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container - for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container - for the targets. - type: string - keySecret: - description: Secret containing the client key file for the - targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - url_map: - items: - description: |- - UnauthorizedAccessConfigURLMap defines element of url_map routing configuration - For UnauthorizedAccessConfig and VMAuthUnauthorizedUserAccessSpec.URLMap - properties: - discover_backend_ips: - description: DiscoverBackendIPs instructs discovering URLPrefix - backend IPs via DNS. - type: boolean - drop_src_path_prefix_parts: - description: |- - DropSrcPathPrefixParts is the number of `/`-delimited request path prefix parts to drop before proxying the request to backend. - See [here](https://docs.victoriametrics.com/vmauth#dropping-request-path-prefix) for more details. - type: integer - headers: - description: |- - RequestHeaders represent additional http headers, that vmauth uses - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.68.0 version of vmauth - items: - type: string - type: array - load_balancing_policy: - description: |- - LoadBalancingPolicy defines load balancing policy to use for backend urls. - Supported policies: least_loaded, first_available. - See [here](https://docs.victoriametrics.com/vmauth#load-balancing) for more details (default "least_loaded") - enum: - - least_loaded - - first_available - type: string - response_headers: - description: |- - ResponseHeaders represent additional http headers, that vmauth adds for request response - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.93.0 version of vmauth - items: - type: string - type: array - retry_status_codes: - description: |- - RetryStatusCodes defines http status codes in numeric format for request retries - Can be defined per target or at VMUser.spec level - e.g. [429,503] - items: - type: integer - type: array - src_headers: - description: SrcHeaders is an optional list of headers, - which must match request headers. - items: - type: string - type: array - src_hosts: - description: SrcHosts is an optional list of regular expressions, - which must match the request hostname. - items: - type: string - type: array - src_paths: - description: SrcPaths is an optional list of regular expressions, - which must match the request path. - items: - type: string - type: array - src_query_args: - description: SrcQueryArgs is an optional list of query args, - which must match request URL query args. - items: - type: string - type: array - url_prefix: - description: |- - UrlPrefix contains backend url prefixes for the proxied request url. - URLPrefix defines prefix prefix for destination - x-kubernetes-preserve-unknown-fields: true - type: object - type: array - url_prefix: - description: URLPrefix defines prefix prefix for destination - x-kubernetes-preserve-unknown-fields: true - type: object - useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements - type: boolean - useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions - type: boolean - useVMConfigReloader: - description: |- - UseVMConfigReloader replaces prometheus-like config-reloader - with vm one. It uses secrets watch instead of file watch - which greatly increases speed of config updates - type: boolean - userNamespaceSelector: - description: |- - UserNamespaceSelector Namespaces to be selected for VMAuth discovery. - Works in combination with Selector. - NamespaceSelector nil - only objects at VMAuth namespace. - Selector nil - only objects at NamespaceSelector namespaces. - If both nil - behaviour controlled by selectAllByDefault - 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 - userSelector: - description: |- - UserSelector defines VMUser to be selected for config file generation. - Works in combination with NamespaceSelector. - NamespaceSelector nil - only objects at VMAuth namespace. - If both nil - behaviour controlled by selectAllByDefault - 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 - volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container - items: - description: VolumeMount describes a mounting of a Volume within - a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional - items: - description: Volume represents a named volume in a pod that may - be accessed by any container in the pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array type: object x-kubernetes-preserve-unknown-fields: true status: - description: VMAuthStatus defines the observed state of VMAuth properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -16329,16 +992,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -16351,7 +1009,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmclusters.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -16385,4338 +1043,45 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: |- - VMCluster is fast, cost-effective and scalable time-series database. - Cluster version with 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: VMClusterSpec defines the desired state of VMCluster - properties: - clusterDomainName: - description: |- - ClusterDomainName defines domain name suffix for in-cluster dns addresses - aka .cluster.local - used by vminsert and vmselect to build vmstorage address - type: string - clusterVersion: - description: |- - ClusterVersion defines default images tag for all components. - it can be overwritten with component specific image.tag value. - type: string - imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - license: - description: |- - License allows to configure license key to be used for enterprise features. - Using license key is supported starting from VictoriaMetrics v1.94.0. - See [here](https://docs.victoriametrics.com/enterprise) - properties: - forceOffline: - description: Enforce offline verification of the license key. - type: boolean - key: - description: |- - Enterprise license key. This flag is available only in [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise). - To request a trial license, [go to](https://victoriametrics.com/products/enterprise/trial) - type: string - keyRef: - description: KeyRef is reference to secret with license key for - enterprise features. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - reloadInterval: - description: Interval to be used for checking for license key - changes. Note that this is only applicable when using KeyRef. - type: string - type: object - managedMetadata: - description: |- - ManagedMetadata defines metadata that will be added to the all objects - created by operator for the given CustomResource - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - type: object - paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. - type: boolean - replicationFactor: - description: |- - ReplicationFactor defines how many copies of data make among - distinct storage nodes - format: int32 - type: integer - requestsLoadBalancer: - description: |- - RequestsLoadBalancer configures load-balancing for vminsert and vmselect requests - it helps to evenly spread load across pods - usually it's not possible with kubernetes TCP based service - properties: - disableInsertBalancing: - type: boolean - disableSelectBalancing: - type: boolean - enabled: - type: boolean - spec: - description: |- - VMAuthLoadBalancerSpec defines configuration spec for VMAuth used as load-balancer - for VMCluster component - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - retentionPeriod: - description: |- - RetentionPeriod for the stored metrics - Note VictoriaMetrics has data/ and indexdb/ folders - metrics from data/ removed eventually as soon as partition leaves retention period - reverse index data at indexdb rotates once at the half of configured - [retention period](https://docs.victoriametrics.com/Single-server-VictoriaMetrics/#retention) - type: string - serviceAccountName: - description: |- - ServiceAccountName is the name of the ServiceAccount to use to run the - VMSelect, VMStorage and VMInsert Pods. - type: string - useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions - type: boolean - vminsert: - properties: - affinity: - description: Affinity If specified, the pod's scheduling constraints. - type: object - x-kubernetes-preserve-unknown-fields: true - clusterNativeListenPort: - description: |- - ClusterNativePort for multi-level cluster setup. - More [details](https://docs.victoriametrics.com/Cluster-VictoriaMetrics#multi-level-cluster-setup) - type: string - configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder - items: - type: string - type: array - containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. - items: - description: A single application container that you want to - run within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. - type: boolean - disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable - type: boolean - dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. - items: - x-kubernetes-preserve-unknown-fields: true - properties: - nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. - items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. - properties: - name: - description: |- - Name is this DNS resolver option's name. - Required. - type: string - value: - description: Value is this DNS resolver option's value. - type: string - type: object - type: array - x-kubernetes-list-type: atomic - searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - dnsPolicy: - description: DNSPolicy sets DNS policy for the pod - type: string - extraArgs: - additionalProperties: - type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp - type: object - extraEnvs: - description: ExtraEnvs that will be passed to the application - container - items: - description: EnvVar represents an environment variable present - in a Container. - properties: - name: - description: Name of the environment variable. Must be a - C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap - items: - description: EnvFromSource represents the source of a set of - ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostNetwork: - description: HostNetwork controls whether the pod may use the - node network namespace - type: boolean - hpa: - description: HPA defines kubernetes PodAutoScaling configuration - version 2. - type: object - x-kubernetes-preserve-unknown-fields: true - image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config - properties: - pullPolicy: - description: PullPolicy describes how to pull docker image - type: string - repository: - description: Repository contains name of docker image + it's - repository if needed - type: string - tag: - description: Tag contains desired docker image version - type: string - type: object - imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - items: - description: A single application container that you want to - run within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - insertPorts: - description: InsertPorts - additional listen ports for data ingestion. - properties: - graphitePort: - description: GraphitePort listen port - type: string - influxPort: - description: InfluxPort listen port - type: string - openTSDBHTTPPort: - description: OpenTSDBHTTPPort for http connections. - type: string - openTSDBPort: - description: OpenTSDBPort for tcp and udp listen - type: string - type: object - livenessProbe: - description: LivenessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - logFormat: - description: |- - LogFormat for VMInsert to be configured with. - default or json - enum: - - default - - json - type: string - logLevel: - description: LogLevel for VMInsert to be configured with. - enum: - - INFO - - WARN - - ERROR - - FATAL - - PANIC - type: string - minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle - format: int32 - type: integer - nodeSelector: - additionalProperties: - type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. - type: object - paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. - type: boolean - podDisruptionBudget: - description: PodDisruptionBudget created by operator - properties: - maxUnavailable: - anyOf: - - type: integer - - type: string - description: |- - An eviction is allowed if at most "maxUnavailable" pods selected by - "selector" are unavailable after the eviction, i.e. even in absence of - the evicted pod. For example, one can prevent all voluntary evictions - by specifying 0. This is a mutually exclusive setting with "minAvailable". - x-kubernetes-int-or-string: true - minAvailable: - anyOf: - - type: integer - - type: string - description: |- - An eviction is allowed if at least "minAvailable" pods selected by - "selector" will still be available after the eviction, i.e. even in the - absence of the evicted pod. So for example you can prevent all voluntary - evictions by specifying "100%". - x-kubernetes-int-or-string: true - selectorLabels: - additionalProperties: - type: string - description: |- - replaces default labels selector generated by operator - it's useful when you need to create custom budget - type: object - type: object - podMetadata: - description: PodMetadata configures Labels and Annotations which - are propagated to the VMInsert pods. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - port: - description: Port listen address - type: string - priorityClassName: - description: PriorityClassName class assigned to the Pods - type: string - readinessGates: - description: ReadinessGates defines pod readiness gates - items: - description: PodReadinessGate contains the reference to a pod - condition - properties: - conditionType: - description: ConditionType refers to a condition in the - pod's condition list with matching type. - type: string - required: - - conditionType - type: object - type: array - readinessProbe: - description: ReadinessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - replicaCount: - description: ReplicaCount is the expected size of the Application. - format: int32 - type: integer - resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. - format: int32 - type: integer - rollingUpdate: - description: RollingUpdate - overrides deployment update params. - properties: - maxSurge: - anyOf: - - type: integer - - type: string - description: |- - The maximum number of pods that can be scheduled above the desired number of - pods. - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). - This can not be 0 if MaxUnavailable is 0. - Absolute number is calculated from percentage by rounding up. - Defaults to 25%. - Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when - the rolling update starts, such that the total number of old and new pods do not exceed - 130% of desired pods. Once old pods have been killed, - new ReplicaSet can be scaled up further, ensuring that total number of pods running - at any time during the update is at most 130% of desired pods. - x-kubernetes-int-or-string: true - maxUnavailable: - anyOf: - - type: integer - - type: string - description: |- - The maximum number of pods that can be unavailable during the update. - Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). - Absolute number is calculated from percentage by rounding down. - This can not be 0 if MaxSurge is 0. - Defaults to 25%. - Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods - immediately when the rolling update starts. Once new pods are ready, old ReplicaSet - can be scaled down further, followed by scaling up the new ReplicaSet, ensuring - that the total number of pods available at all times during the update is at - least 70% of desired pods. - x-kubernetes-int-or-string: true - type: object - runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ - type: string - schedulerName: - description: SchedulerName - defines kubernetes scheduler name - type: string - secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder - items: - type: string - type: array - securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. - type: object - x-kubernetes-preserve-unknown-fields: true - serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vminsert - VMServiceScrape spec - required: - - endpoints - type: object - x-kubernetes-preserve-unknown-fields: true - serviceSpec: - description: ServiceSpec that will be added to vminsert service - spec - properties: - metadata: - description: EmbeddedObjectMetadata defines objectMeta for - additional service. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ - type: object - x-kubernetes-preserve-unknown-fields: true - useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication - type: boolean - required: - - spec - type: object - startupProbe: - description: StartupProbe that will be added to CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container - graceful termination - format: int64 - type: integer - tolerations: - description: Tolerations If specified, the pod's tolerations. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - items: - description: TopologySpreadConstraint specifies how to spread - matching pods among the given topology. - required: - - maxSkew - - topologyKey - - whenUnsatisfiable - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - updateStrategy: - description: UpdateStrategy - overrides default update strategy. - enum: - - Recreate - - RollingUpdate - type: string - useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements - type: boolean - useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions - type: boolean - volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container - items: - description: VolumeMount describes a mounting of a Volume within - a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional - items: - description: Volume represents a named volume in a pod that - may be accessed by any container in the pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - type: object - vmselect: - description: VMSelect defines configuration section for vmselect components - of the victoria-metrics cluster - properties: - affinity: - description: Affinity If specified, the pod's scheduling constraints. - type: object - x-kubernetes-preserve-unknown-fields: true - cacheMountPath: - description: |- - CacheMountPath allows to add cache persistent for VMSelect, - will use "/cache" as default if not specified. - type: string - claimTemplates: - description: ClaimTemplates allows adding additional VolumeClaimTemplates - for StatefulSet - items: - description: PersistentVolumeClaim is a user's request for and - claim to a persistent volume - 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: - description: |- - Standard object's metadata. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - type: object - x-kubernetes-preserve-unknown-fields: true - spec: - description: |- - spec defines the desired characteristics of a volume requested by a pod author. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes - to consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to - the PersistentVolume backing this claim. - type: string - type: object - status: - description: |- - status represents the current information/status of a persistent volume claim. - Read-only. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the actual access modes the volume backing the PVC has. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - allocatedResourceStatuses: - additionalProperties: - description: |- - When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource - that it does not recognizes, then it should ignore that update and let other controllers - handle it. - type: string - description: "allocatedResourceStatuses stores status - of resource being resized for the given PVC.\nKey - names follow standard Kubernetes label syntax. Valid - values are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources - must use implementation-defined prefixed names such - as \"example.com/my-custom-resource\"\nApart from - above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not - be used.\n\nClaimResourceStatus can be in any of following - states:\n\t- ControllerResizeInProgress:\n\t\tState - set when resize controller starts resizing the volume - in control-plane.\n\t- ControllerResizeFailed:\n\t\tState - set when resize has failed in resize controller with - a terminal error.\n\t- NodeResizePending:\n\t\tState - set when resize controller has finished resizing the - volume but further resizing of\n\t\tvolume is needed - on the node.\n\t- NodeResizeInProgress:\n\t\tState - set when kubelet starts resizing the volume.\n\t- - NodeResizeFailed:\n\t\tState set when resizing has - failed in kubelet with a terminal error. Transient - errors don't set\n\t\tNodeResizeFailed.\nFor example: - if expanding a PVC for more capacity - this field - can be one of the following states:\n\t- pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeFailed\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizePending\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeFailed\"\nWhen this field is not set, - it means that no resize operation is in progress for - the given PVC.\n\nA controller that receives PVC update - with previously unknown resourceName or ClaimResourceStatus\nshould - ignore the update for the purpose it was designed. - For example - a controller that\nonly is responsible - for resizing capacity of the volume, should ignore - PVC updates that change other valid\nresources associated - with PVC.\n\nThis is an alpha field and requires enabling - RecoverVolumeExpansionFailure feature." - type: object - x-kubernetes-map-type: granular - allocatedResources: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: "allocatedResources tracks the resources - allocated to a PVC including its capacity.\nKey names - follow standard Kubernetes label syntax. Valid values - are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources - must use implementation-defined prefixed names such - as \"example.com/my-custom-resource\"\nApart from - above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not - be used.\n\nCapacity reported here may be larger than - the actual capacity when a volume expansion operation\nis - requested.\nFor storage quota, the larger value from - allocatedResources and PVC.spec.resources is used.\nIf - allocatedResources is not set, PVC.spec.resources - alone is used for quota calculation.\nIf a volume - expansion capacity request is lowered, allocatedResources - is only\nlowered if there are no expansion operations - in progress and if the actual volume capacity\nis - equal or lower than the requested capacity.\n\nA controller - that receives PVC update with previously unknown resourceName\nshould - ignore the update for the purpose it was designed. - For example - a controller that\nonly is responsible - for resizing capacity of the volume, should ignore - PVC updates that change other valid\nresources associated - with PVC.\n\nThis is an alpha field and requires enabling - RecoverVolumeExpansionFailure feature." - type: object - capacity: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: capacity represents the actual resources - of the underlying volume. - type: object - conditions: - description: |- - conditions is the current Condition of persistent volume claim. If underlying persistent volume is being - resized then the Condition will be set to 'Resizing'. - items: - description: PersistentVolumeClaimCondition contains - details about state of pvc - properties: - lastProbeTime: - description: lastProbeTime is the time we probed - the condition. - format: date-time - type: string - lastTransitionTime: - description: lastTransitionTime is the time the - condition transitioned from one status to another. - format: date-time - type: string - message: - description: message is the human-readable message - indicating details about last transition. - type: string - reason: - description: |- - reason is a unique, this should be a short, machine understandable string that gives the reason - for condition's last transition. If it reports "Resizing" that means the underlying - persistent volume is being resized. - type: string - status: - description: |- - Status is the status of the condition. - Can be True, False, Unknown. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=state%20of%20pvc-,conditions.status,-(string)%2C%20required - type: string - type: - description: |- - Type is the type of the condition. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=set%20to%20%27ResizeStarted%27.-,PersistentVolumeClaimCondition,-contains%20details%20about - type: string - required: - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - currentVolumeAttributesClassName: - description: |- - currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. - When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - type: string - modifyVolumeStatus: - description: |- - ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. - When this is unset, there is no ModifyVolume operation being attempted. - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - properties: - status: - description: "status is the status of the ControllerModifyVolume - operation. It can be in any of following states:\n - - Pending\n Pending indicates that the PersistentVolumeClaim - cannot be modified due to unmet requirements, - such as\n the specified VolumeAttributesClass - not existing.\n - InProgress\n InProgress indicates - that the volume is being modified.\n - Infeasible\n - \ Infeasible indicates that the request has been - rejected as invalid by the CSI driver. To\n\t - \ resolve the error, a valid VolumeAttributesClass - needs to be specified.\nNote: New statuses can - be added in the future. Consumers should check - for unknown statuses and fail appropriately." - type: string - targetVolumeAttributesClassName: - description: targetVolumeAttributesClassName is - the name of the VolumeAttributesClass the PVC - currently being reconciled - type: string - required: - - status - type: object - phase: - description: phase represents the current phase of PersistentVolumeClaim. - type: string - type: object - type: object - type: array - clusterNativeListenPort: - description: |- - ClusterNativePort for multi-level cluster setup. - More [details](https://docs.victoriametrics.com/Cluster-VictoriaMetrics#multi-level-cluster-setup) - type: string - configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder - items: - type: string - type: array - containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. - items: - description: A single application container that you want to - run within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. - type: boolean - disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable - type: boolean - dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. - items: - x-kubernetes-preserve-unknown-fields: true - properties: - nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. - items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. - properties: - name: - description: |- - Name is this DNS resolver option's name. - Required. - type: string - value: - description: Value is this DNS resolver option's value. - type: string - type: object - type: array - x-kubernetes-list-type: atomic - searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - dnsPolicy: - description: DNSPolicy sets DNS policy for the pod - type: string - extraArgs: - additionalProperties: - type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp - type: object - extraEnvs: - description: ExtraEnvs that will be passed to the application - container - items: - description: EnvVar represents an environment variable present - in a Container. - properties: - name: - description: Name of the environment variable. Must be a - C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap - items: - description: EnvFromSource represents the source of a set of - ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostNetwork: - description: HostNetwork controls whether the pod may use the - node network namespace - type: boolean - hpa: - description: |- - Configures horizontal pod autoscaling. - Note, enabling this option disables vmselect to vmselect communication. In most cases it's not an issue. - type: object - x-kubernetes-preserve-unknown-fields: true - image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config - properties: - pullPolicy: - description: PullPolicy describes how to pull docker image - type: string - repository: - description: Repository contains name of docker image + it's - repository if needed - type: string - tag: - description: Tag contains desired docker image version - type: string - type: object - imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - items: - description: A single application container that you want to - run within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - livenessProbe: - description: LivenessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - logFormat: - description: |- - LogFormat for VMSelect to be configured with. - default or json - enum: - - default - - json - type: string - logLevel: - description: LogLevel for VMSelect to be configured with. - enum: - - INFO - - WARN - - ERROR - - FATAL - - PANIC - type: string - minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle - format: int32 - type: integer - nodeSelector: - additionalProperties: - type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. - type: object - paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. - type: boolean - persistentVolume: - description: |- - Storage - add persistent volume for cacheMountPath - its useful for persistent cache - use storage instead of persistentVolume. - properties: - disableMountSubPath: - description: |- - Deprecated: subPath usage will be disabled by default in a future release, this option will become unnecessary. - DisableMountSubPath allows to remove any subPath usage in volume mounts. - type: boolean - emptyDir: - description: |- - EmptyDirVolumeSource to be used by the Prometheus StatefulSets. If specified, used in place of any volumeClaimTemplate. More - info: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir - properties: - medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - volumeClaimTemplate: - description: A PVC spec to be used by the VMAlertManager StatefulSets. - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - podDisruptionBudget: - description: PodDisruptionBudget created by operator - properties: - maxUnavailable: - anyOf: - - type: integer - - type: string - description: |- - An eviction is allowed if at most "maxUnavailable" pods selected by - "selector" are unavailable after the eviction, i.e. even in absence of - the evicted pod. For example, one can prevent all voluntary evictions - by specifying 0. This is a mutually exclusive setting with "minAvailable". - x-kubernetes-int-or-string: true - minAvailable: - anyOf: - - type: integer - - type: string - description: |- - An eviction is allowed if at least "minAvailable" pods selected by - "selector" will still be available after the eviction, i.e. even in the - absence of the evicted pod. So for example you can prevent all voluntary - evictions by specifying "100%". - x-kubernetes-int-or-string: true - selectorLabels: - additionalProperties: - type: string - description: |- - replaces default labels selector generated by operator - it's useful when you need to create custom budget - type: object - type: object - podMetadata: - description: PodMetadata configures Labels and Annotations which - are propagated to the VMSelect pods. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - port: - description: Port listen address - type: string - priorityClassName: - description: PriorityClassName class assigned to the Pods - type: string - readinessGates: - description: ReadinessGates defines pod readiness gates - items: - description: PodReadinessGate contains the reference to a pod - condition - properties: - conditionType: - description: ConditionType refers to a condition in the - pod's condition list with matching type. - type: string - required: - - conditionType - type: object - type: array - readinessProbe: - description: ReadinessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - replicaCount: - description: ReplicaCount is the expected size of the Application. - format: int32 - type: integer - resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. - format: int32 - type: integer - rollingUpdateStrategy: - description: |- - RollingUpdateStrategy defines strategy for application updates - Default is OnDelete, in this case operator handles update process - Can be changed for RollingUpdate - type: string - runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ - type: string - schedulerName: - description: SchedulerName - defines kubernetes scheduler name - type: string - secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder - items: - type: string - type: array - securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. - type: object - x-kubernetes-preserve-unknown-fields: true - serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vmselect - VMServiceScrape spec - required: - - endpoints - type: object - x-kubernetes-preserve-unknown-fields: true - serviceSpec: - description: ServiceSpec that will be added to vmselect service - spec - properties: - metadata: - description: EmbeddedObjectMetadata defines objectMeta for - additional service. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ - type: object - x-kubernetes-preserve-unknown-fields: true - useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication - type: boolean - required: - - spec - type: object - startupProbe: - description: StartupProbe that will be added to CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - storage: - description: |- - StorageSpec - add persistent volume claim for cacheMountPath - its needed for persistent cache - properties: - disableMountSubPath: - description: |- - Deprecated: subPath usage will be disabled by default in a future release, this option will become unnecessary. - DisableMountSubPath allows to remove any subPath usage in volume mounts. - type: boolean - emptyDir: - description: |- - EmptyDirVolumeSource to be used by the Prometheus StatefulSets. If specified, used in place of any volumeClaimTemplate. More - info: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir - properties: - medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - volumeClaimTemplate: - description: A PVC spec to be used by the VMAlertManager StatefulSets. - 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: - description: EmbeddedMetadata contains metadata relevant - to an EmbeddedResource. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - spec: - description: |- - Spec defines the desired characteristics of a volume requested by a pod author. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes - to consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to - the PersistentVolume backing this claim. - type: string - type: object - status: - description: |- - Status represents the current information/status of a persistent volume claim. - Read-only. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the actual access modes the volume backing the PVC has. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - allocatedResourceStatuses: - additionalProperties: - description: |- - When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource - that it does not recognizes, then it should ignore that update and let other controllers - handle it. - type: string - description: "allocatedResourceStatuses stores status - of resource being resized for the given PVC.\nKey - names follow standard Kubernetes label syntax. Valid - values are either:\n\t* Un-prefixed keys:\n\t\t- - storage - the capacity of the volume.\n\t* Custom - resources must use implementation-defined prefixed - names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or - have kubernetes.io prefix are considered\nreserved - and hence may not be used.\n\nClaimResourceStatus - can be in any of following states:\n\t- ControllerResizeInProgress:\n\t\tState - set when resize controller starts resizing the volume - in control-plane.\n\t- ControllerResizeFailed:\n\t\tState - set when resize has failed in resize controller - with a terminal error.\n\t- NodeResizePending:\n\t\tState - set when resize controller has finished resizing - the volume but further resizing of\n\t\tvolume is - needed on the node.\n\t- NodeResizeInProgress:\n\t\tState - set when kubelet starts resizing the volume.\n\t- - NodeResizeFailed:\n\t\tState set when resizing has - failed in kubelet with a terminal error. Transient - errors don't set\n\t\tNodeResizeFailed.\nFor example: - if expanding a PVC for more capacity - this field - can be one of the following states:\n\t- pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeFailed\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizePending\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeFailed\"\nWhen this field is not set, - it means that no resize operation is in progress - for the given PVC.\n\nA controller that receives - PVC update with previously unknown resourceName - or ClaimResourceStatus\nshould ignore the update - for the purpose it was designed. For example - a - controller that\nonly is responsible for resizing - capacity of the volume, should ignore PVC updates - that change other valid\nresources associated with - PVC.\n\nThis is an alpha field and requires enabling - RecoverVolumeExpansionFailure feature." - type: object - x-kubernetes-map-type: granular - allocatedResources: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: "allocatedResources tracks the resources - allocated to a PVC including its capacity.\nKey - names follow standard Kubernetes label syntax. Valid - values are either:\n\t* Un-prefixed keys:\n\t\t- - storage - the capacity of the volume.\n\t* Custom - resources must use implementation-defined prefixed - names such as \"example.com/my-custom-resource\"\nApart - from above values - keys that are unprefixed or - have kubernetes.io prefix are considered\nreserved - and hence may not be used.\n\nCapacity reported - here may be larger than the actual capacity when - a volume expansion operation\nis requested.\nFor - storage quota, the larger value from allocatedResources - and PVC.spec.resources is used.\nIf allocatedResources - is not set, PVC.spec.resources alone is used for - quota calculation.\nIf a volume expansion capacity - request is lowered, allocatedResources is only\nlowered - if there are no expansion operations in progress - and if the actual volume capacity\nis equal or lower - than the requested capacity.\n\nA controller that - receives PVC update with previously unknown resourceName\nshould - ignore the update for the purpose it was designed. - For example - a controller that\nonly is responsible - for resizing capacity of the volume, should ignore - PVC updates that change other valid\nresources associated - with PVC.\n\nThis is an alpha field and requires - enabling RecoverVolumeExpansionFailure feature." - type: object - capacity: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: capacity represents the actual resources - of the underlying volume. - type: object - conditions: - description: |- - conditions is the current Condition of persistent volume claim. If underlying persistent volume is being - resized then the Condition will be set to 'Resizing'. - items: - description: PersistentVolumeClaimCondition contains - details about state of pvc - properties: - lastProbeTime: - description: lastProbeTime is the time we probed - the condition. - format: date-time - type: string - lastTransitionTime: - description: lastTransitionTime is the time - the condition transitioned from one status - to another. - format: date-time - type: string - message: - description: message is the human-readable message - indicating details about last transition. - type: string - reason: - description: |- - reason is a unique, this should be a short, machine understandable string that gives the reason - for condition's last transition. If it reports "Resizing" that means the underlying - persistent volume is being resized. - type: string - status: - description: |- - Status is the status of the condition. - Can be True, False, Unknown. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=state%20of%20pvc-,conditions.status,-(string)%2C%20required - type: string - type: - description: |- - Type is the type of the condition. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=set%20to%20%27ResizeStarted%27.-,PersistentVolumeClaimCondition,-contains%20details%20about - type: string - required: - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - currentVolumeAttributesClassName: - description: |- - currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. - When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - type: string - modifyVolumeStatus: - description: |- - ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. - When this is unset, there is no ModifyVolume operation being attempted. - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - properties: - status: - description: "status is the status of the ControllerModifyVolume - operation. It can be in any of following states:\n - - Pending\n Pending indicates that the PersistentVolumeClaim - cannot be modified due to unmet requirements, - such as\n the specified VolumeAttributesClass - not existing.\n - InProgress\n InProgress - indicates that the volume is being modified.\n - - Infeasible\n Infeasible indicates that the - request has been rejected as invalid by the - CSI driver. To\n\t resolve the error, a valid - VolumeAttributesClass needs to be specified.\nNote: - New statuses can be added in the future. Consumers - should check for unknown statuses and fail appropriately." - type: string - targetVolumeAttributesClassName: - description: targetVolumeAttributesClassName is - the name of the VolumeAttributesClass the PVC - currently being reconciled - type: string - required: - - status - type: object - phase: - description: phase represents the current phase of - PersistentVolumeClaim. - type: string - type: object - type: object - type: object - terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container - graceful termination - format: int64 - type: integer - tolerations: - description: Tolerations If specified, the pod's tolerations. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - items: - description: TopologySpreadConstraint specifies how to spread - matching pods among the given topology. - required: - - maxSkew - - topologyKey - - whenUnsatisfiable - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements - type: boolean - useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions - type: boolean - volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container - items: - description: VolumeMount describes a mounting of a Volume within - a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional - items: - description: Volume represents a named volume in a pod that - may be accessed by any container in the pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - type: object - vmstorage: - properties: - affinity: - description: Affinity If specified, the pod's scheduling constraints. - type: object - x-kubernetes-preserve-unknown-fields: true - claimTemplates: - description: ClaimTemplates allows adding additional VolumeClaimTemplates - for StatefulSet - items: - description: PersistentVolumeClaim is a user's request for and - claim to a persistent volume - 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: - description: |- - Standard object's metadata. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata - type: object - x-kubernetes-preserve-unknown-fields: true - spec: - description: |- - spec defines the desired characteristics of a volume requested by a pod author. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being - referenced - type: string - name: - description: Name is the name of resource being - referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes - to consider for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to - the PersistentVolume backing this claim. - type: string - type: object - status: - description: |- - status represents the current information/status of a persistent volume claim. - Read-only. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims - properties: - accessModes: - description: |- - accessModes contains the actual access modes the volume backing the PVC has. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - allocatedResourceStatuses: - additionalProperties: - description: |- - When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource - that it does not recognizes, then it should ignore that update and let other controllers - handle it. - type: string - description: "allocatedResourceStatuses stores status - of resource being resized for the given PVC.\nKey - names follow standard Kubernetes label syntax. Valid - values are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources - must use implementation-defined prefixed names such - as \"example.com/my-custom-resource\"\nApart from - above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not - be used.\n\nClaimResourceStatus can be in any of following - states:\n\t- ControllerResizeInProgress:\n\t\tState - set when resize controller starts resizing the volume - in control-plane.\n\t- ControllerResizeFailed:\n\t\tState - set when resize has failed in resize controller with - a terminal error.\n\t- NodeResizePending:\n\t\tState - set when resize controller has finished resizing the - volume but further resizing of\n\t\tvolume is needed - on the node.\n\t- NodeResizeInProgress:\n\t\tState - set when kubelet starts resizing the volume.\n\t- - NodeResizeFailed:\n\t\tState set when resizing has - failed in kubelet with a terminal error. Transient - errors don't set\n\t\tNodeResizeFailed.\nFor example: - if expanding a PVC for more capacity - this field - can be one of the following states:\n\t- pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"ControllerResizeFailed\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizePending\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] - = \"NodeResizeFailed\"\nWhen this field is not set, - it means that no resize operation is in progress for - the given PVC.\n\nA controller that receives PVC update - with previously unknown resourceName or ClaimResourceStatus\nshould - ignore the update for the purpose it was designed. - For example - a controller that\nonly is responsible - for resizing capacity of the volume, should ignore - PVC updates that change other valid\nresources associated - with PVC.\n\nThis is an alpha field and requires enabling - RecoverVolumeExpansionFailure feature." - type: object - x-kubernetes-map-type: granular - allocatedResources: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: "allocatedResources tracks the resources - allocated to a PVC including its capacity.\nKey names - follow standard Kubernetes label syntax. Valid values - are either:\n\t* Un-prefixed keys:\n\t\t- storage - - the capacity of the volume.\n\t* Custom resources - must use implementation-defined prefixed names such - as \"example.com/my-custom-resource\"\nApart from - above values - keys that are unprefixed or have kubernetes.io - prefix are considered\nreserved and hence may not - be used.\n\nCapacity reported here may be larger than - the actual capacity when a volume expansion operation\nis - requested.\nFor storage quota, the larger value from - allocatedResources and PVC.spec.resources is used.\nIf - allocatedResources is not set, PVC.spec.resources - alone is used for quota calculation.\nIf a volume - expansion capacity request is lowered, allocatedResources - is only\nlowered if there are no expansion operations - in progress and if the actual volume capacity\nis - equal or lower than the requested capacity.\n\nA controller - that receives PVC update with previously unknown resourceName\nshould - ignore the update for the purpose it was designed. - For example - a controller that\nonly is responsible - for resizing capacity of the volume, should ignore - PVC updates that change other valid\nresources associated - with PVC.\n\nThis is an alpha field and requires enabling - RecoverVolumeExpansionFailure feature." - type: object - capacity: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: capacity represents the actual resources - of the underlying volume. - type: object - conditions: - description: |- - conditions is the current Condition of persistent volume claim. If underlying persistent volume is being - resized then the Condition will be set to 'Resizing'. - items: - description: PersistentVolumeClaimCondition contains - details about state of pvc - properties: - lastProbeTime: - description: lastProbeTime is the time we probed - the condition. - format: date-time - type: string - lastTransitionTime: - description: lastTransitionTime is the time the - condition transitioned from one status to another. - format: date-time - type: string - message: - description: message is the human-readable message - indicating details about last transition. - type: string - reason: - description: |- - reason is a unique, this should be a short, machine understandable string that gives the reason - for condition's last transition. If it reports "Resizing" that means the underlying - persistent volume is being resized. - type: string - status: - description: |- - Status is the status of the condition. - Can be True, False, Unknown. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=state%20of%20pvc-,conditions.status,-(string)%2C%20required - type: string - type: - description: |- - Type is the type of the condition. - More info: https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/#:~:text=set%20to%20%27ResizeStarted%27.-,PersistentVolumeClaimCondition,-contains%20details%20about - type: string - required: - - status - - type - type: object - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - currentVolumeAttributesClassName: - description: |- - currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. - When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - type: string - modifyVolumeStatus: - description: |- - ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. - When this is unset, there is no ModifyVolume operation being attempted. - This is a beta field and requires enabling VolumeAttributesClass feature (off by default). - properties: - status: - description: "status is the status of the ControllerModifyVolume - operation. It can be in any of following states:\n - - Pending\n Pending indicates that the PersistentVolumeClaim - cannot be modified due to unmet requirements, - such as\n the specified VolumeAttributesClass - not existing.\n - InProgress\n InProgress indicates - that the volume is being modified.\n - Infeasible\n - \ Infeasible indicates that the request has been - rejected as invalid by the CSI driver. To\n\t - \ resolve the error, a valid VolumeAttributesClass - needs to be specified.\nNote: New statuses can - be added in the future. Consumers should check - for unknown statuses and fail appropriately." - type: string - targetVolumeAttributesClassName: - description: targetVolumeAttributesClassName is - the name of the VolumeAttributesClass the PVC - currently being reconciled - type: string - required: - - status - type: object - phase: - description: phase represents the current phase of PersistentVolumeClaim. - type: string - type: object - type: object - type: array - configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder - items: - type: string - type: array - containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. - items: - description: A single application container that you want to - run within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. - type: boolean - disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable - type: boolean - dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. - items: - x-kubernetes-preserve-unknown-fields: true - properties: - nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. - items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. - properties: - name: - description: |- - Name is this DNS resolver option's name. - Required. - type: string - value: - description: Value is this DNS resolver option's value. - type: string - type: object - type: array - x-kubernetes-list-type: atomic - searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - dnsPolicy: - description: DNSPolicy sets DNS policy for the pod - type: string - extraArgs: - additionalProperties: - type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp - type: object - extraEnvs: - description: ExtraEnvs that will be passed to the application - container - items: - description: EnvVar represents an environment variable present - in a Container. - properties: - name: - description: Name of the environment variable. Must be a - C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap - items: - description: EnvFromSource represents the source of a set of - ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostNetwork: - description: HostNetwork controls whether the pod may use the - node network namespace - type: boolean - image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config - properties: - pullPolicy: - description: PullPolicy describes how to pull docker image - type: string - repository: - description: Repository contains name of docker image + it's - repository if needed - type: string - tag: - description: Tag contains desired docker image version - type: string - type: object - imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - items: - description: A single application container that you want to - run within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - livenessProbe: - description: LivenessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - logFormat: - description: |- - LogFormat for VMStorage to be configured with. - default or json - enum: - - default - - json - type: string - logLevel: - description: LogLevel for VMStorage to be configured with. - enum: - - INFO - - WARN - - ERROR - - FATAL - - PANIC - type: string - maintenanceInsertNodeIDs: - description: |- - MaintenanceInsertNodeIDs - excludes given node ids from insert requests routing, must contain pod suffixes - for pod-0, id will be 0 and etc. - lets say, you have pod-0, pod-1, pod-2, pod-3. to exclude pod-0 and pod-3 from insert routing, define nodeIDs: [0,3]. - Useful at storage expanding, when you want to rebalance some data at cluster. - items: - format: int32 - type: integer - type: array - maintenanceSelectNodeIDs: - description: MaintenanceInsertNodeIDs - excludes given node ids - from select requests routing, must contain pod suffixes - for - pod-0, id will be 0 and etc. - items: - format: int32 - type: integer - type: array - minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle - format: int32 - type: integer - nodeSelector: - additionalProperties: - type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. - type: object - paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. - type: boolean - podDisruptionBudget: - description: PodDisruptionBudget created by operator - properties: - maxUnavailable: - anyOf: - - type: integer - - type: string - description: |- - An eviction is allowed if at most "maxUnavailable" pods selected by - "selector" are unavailable after the eviction, i.e. even in absence of - the evicted pod. For example, one can prevent all voluntary evictions - by specifying 0. This is a mutually exclusive setting with "minAvailable". - x-kubernetes-int-or-string: true - minAvailable: - anyOf: - - type: integer - - type: string - description: |- - An eviction is allowed if at least "minAvailable" pods selected by - "selector" will still be available after the eviction, i.e. even in the - absence of the evicted pod. So for example you can prevent all voluntary - evictions by specifying "100%". - x-kubernetes-int-or-string: true - selectorLabels: - additionalProperties: - type: string - description: |- - replaces default labels selector generated by operator - it's useful when you need to create custom budget - type: object - type: object - podMetadata: - description: PodMetadata configures Labels and Annotations which - are propagated to the VMStorage pods. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - port: - description: Port listen address - type: string - priorityClassName: - description: PriorityClassName class assigned to the Pods - type: string - readinessGates: - description: ReadinessGates defines pod readiness gates - items: - description: PodReadinessGate contains the reference to a pod - condition - properties: - conditionType: - description: ConditionType refers to a condition in the - pod's condition list with matching type. - type: string - required: - - conditionType - type: object - type: array - readinessProbe: - description: ReadinessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - replicaCount: - description: ReplicaCount is the expected size of the Application. - format: int32 - type: integer - resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. - format: int32 - type: integer - rollingUpdateStrategy: - description: |- - RollingUpdateStrategy defines strategy for application updates - Default is OnDelete, in this case operator handles update process - Can be changed for RollingUpdate - type: string - runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ - type: string - schedulerName: - description: SchedulerName - defines kubernetes scheduler name - type: string - secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder - items: - type: string - type: array - securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. - type: object - x-kubernetes-preserve-unknown-fields: true - serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vmstorage - VMServiceScrape spec - required: - - endpoints - type: object - x-kubernetes-preserve-unknown-fields: true - serviceSpec: - description: ServiceSpec that will be create additional service - for vmstorage - properties: - metadata: - description: EmbeddedObjectMetadata defines objectMeta for - additional service. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ - type: object - x-kubernetes-preserve-unknown-fields: true - useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication - type: boolean - required: - - spec - type: object - startupProbe: - description: StartupProbe that will be added to CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - storage: - description: |- - Storage - add persistent volume for StorageDataPath - its useful for persistent cache - properties: - disableMountSubPath: - description: |- - Deprecated: subPath usage will be disabled by default in a future release, this option will become unnecessary. - DisableMountSubPath allows to remove any subPath usage in volume mounts. - type: boolean - emptyDir: - description: |- - EmptyDirVolumeSource to be used by the Prometheus StatefulSets. If specified, used in place of any volumeClaimTemplate. More - info: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir - properties: - medium: - description: |- - medium represents what type of storage medium should back this directory. - The default is "" which means to use the node's default medium. - Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: |- - sizeLimit is the total amount of local storage required for this EmptyDir volume. - The size limit is also applicable for memory medium. - The maximum usage on memory medium EmptyDir would be the minimum value between - the SizeLimit specified here and the sum of memory limits of all containers in a pod. - The default is nil which means that the limit is undefined. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - volumeClaimTemplate: - description: A PVC spec to be used by the VMAlertManager StatefulSets. - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - storageDataPath: - description: StorageDataPath - path to storage data - type: string - terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container - graceful termination - format: int64 - type: integer - tolerations: - description: Tolerations If specified, the pod's tolerations. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - items: - description: TopologySpreadConstraint specifies how to spread - matching pods among the given topology. - required: - - maxSkew - - topologyKey - - whenUnsatisfiable - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements - type: boolean - useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions - type: boolean - vmBackup: - description: VMBackup configuration for backup - properties: - acceptEULA: - description: |- - AcceptEULA accepts enterprise feature usage, must be set to true. - otherwise backupmanager cannot be added to single/cluster version. - https://victoriametrics.com/legal/esa/ - type: boolean - concurrency: - description: Defines number of concurrent workers. Higher - concurrency may reduce backup duration (default 10) - format: int32 - type: integer - credentialsSecret: - description: |- - CredentialsSecret is secret in the same namespace for access to remote storage - The secret is mounted into /etc/vm/creds. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - customS3Endpoint: - description: Custom S3 endpoint for use with S3-compatible - storages (e.g. MinIO). S3 is used if not set - type: string - destination: - description: Defines destination for backup - type: string - destinationDisableSuffixAdd: - description: |- - DestinationDisableSuffixAdd - disables suffix adding for cluster version backups - each vmstorage backup must have unique backup folder - so operator adds POD_NAME as suffix for backup destination folder. - type: boolean - disableDaily: - description: Defines if daily backups disabled (default false) - type: boolean - disableHourly: - description: Defines if hourly backups disabled (default false) - type: boolean - disableMonthly: - description: Defines if monthly backups disabled (default - false) - type: boolean - disableWeekly: - description: Defines if weekly backups disabled (default false) - type: boolean - extraArgs: - additionalProperties: - type: string - description: extra args like maxBytesPerSecond default 0 - type: object - extraEnvs: - items: - description: EnvVar represents an environment variable present - in a Container. - properties: - name: - description: Name of the environment variable. Must - be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. - Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or - its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in - the specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of - the exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's - namespace - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap - items: - description: EnvFromSource represents the source of a set - of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must - be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be - defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: Image - docker image settings for VMBackuper - properties: - pullPolicy: - description: PullPolicy describes how to pull docker image - type: string - repository: - description: Repository contains name of docker image - + it's repository if needed - type: string - tag: - description: Tag contains desired docker image version - type: string - type: object - logFormat: - description: |- - LogFormat for VMBackup to be configured with. - default or json - enum: - - default - - json - type: string - logLevel: - description: LogLevel for VMBackup to be configured with. - enum: - - INFO - - WARN - - ERROR - - FATAL - - PANIC - type: string - port: - description: Port for health check connections - type: string - resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - restore: - description: |- - Restore Allows to enable restore options for pod - Read [more](https://docs.victoriametrics.com/vmbackupmanager#restore-commands) - properties: - onStart: - description: OnStart defines configuration for restore - on pod start - properties: - enabled: - description: Enabled defines if restore on start enabled - type: boolean - type: object - type: object - snapshotCreateURL: - description: SnapshotCreateURL overwrites url for snapshot - create - type: string - snapshotDeleteURL: - description: SnapShotDeleteURL overwrites url for snapshot - delete - type: string - volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment definition. - VolumeMounts specified will be appended to other VolumeMounts in the vmbackupmanager container, - that are generated as a result of StorageSpec objects. - items: - description: VolumeMount describes a mounting of a Volume - within a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - type: object - vmInsertPort: - description: VMInsertPort for VMInsert connections - type: string - vmSelectPort: - description: VMSelectPort for VMSelect connections - type: string - volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container - items: - description: VolumeMount describes a mounting of a Volume within - a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional - items: - description: Volume represents a named volume in a pod that - may be accessed by any container in the pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - type: object - required: - - retentionPeriod type: object + x-kubernetes-preserve-unknown-fields: true status: - description: VMClusterStatus defines the observed state of VMCluster properties: - clusterStatus: - description: LegacyStatus is deprecated and will be removed at v0.52.0 - version - type: string conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -20731,16 +1096,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object required: @@ -20755,7 +1115,101 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 + name: vmdistributed.operator.victoriametrics.com +spec: + group: operator.victoriametrics.com + names: + kind: VMDistributed + listKind: VMDistributedList + plural: vmdistributed + singular: vmdistributed + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: current status of update rollout + jsonPath: .status.updateStatus + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + maxLength: 32768 + type: string + observedGeneration: + format: int64 + minimum: 0 + type: integer + reason: + maxLength: 1024 + minLength: 1 + type: string + status: + enum: + - "True" + - "False" + - Unknown + type: string + type: + maxLength: 316 + type: string + required: + - lastTransitionTime + - lastUpdateTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + format: int64 + type: integer + reason: + type: string + updateStatus: + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.0 name: vmnodescrapes.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -20779,869 +1233,45 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: |- - VMNodeScrape defines discovery for targets placed on kubernetes nodes, - usually its node-exporters and other host services. - InternalIP is used as __address__ for scraping. 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: VMNodeScrapeSpec defines specification for VMNodeScrape. - properties: - authorization: - description: Authorization with http header Authorization - properties: - credentials: - description: Reference to the secret with value for authorization - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to bearer - type: string - type: object - basicAuth: - description: BasicAuth allow an endpoint to authenticate over basic - authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearerTokenFile: - description: File to read bearer token for scraping targets. - type: string - bearerTokenSecret: - description: |- - Secret to mount to read bearer token for scraping targets. The secret - needs to be in the same namespace as the scrape object and accessible by - the victoria-metrics operator. - nullable: true - properties: - key: - description: The key of the secret to select from. Must be a - valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - follow_redirects: - description: FollowRedirects controls redirects for scraping. - type: boolean - honorLabels: - description: HonorLabels chooses the metric's labels on collisions - with target labels. - type: boolean - honorTimestamps: - description: HonorTimestamps controls whether vmagent respects the - timestamps present in scraped data. - type: boolean - interval: - description: Interval at which metrics should be scraped - type: string - jobLabel: - description: The label to use to retrieve the job name from. - type: string - max_scrape_size: - description: MaxScrapeSize defines a maximum size of scraped data - for a job - type: string - metricRelabelConfigs: - description: MetricRelabelConfigs to apply to samples after scrapping. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. Default - is 'replace' - type: string - if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source label - values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source label - values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - oauth2: - description: OAuth2 defines auth configuration - properties: - client_id: - description: The secret or configmap containing the OAuth2 client - id - properties: - configMap: - description: ConfigMap containing data to use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 client secret - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for client secret file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - params: - additionalProperties: - items: - type: string - type: array - description: Optional HTTP URL parameters - type: object - path: - description: HTTP path to scrape for metrics. - type: string - port: - description: Name of the port exposed at Node. - type: string - proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes to - proxy through this endpoint. - type: string - relabelConfigs: - description: RelabelConfigs to apply to samples during service discovery. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. Default - is 'replace' - type: string - if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source label - values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source label - values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - sampleLimit: - description: SampleLimit defines per-scrape limit on number of scraped - samples that will be accepted. - format: int64 - type: integer - scheme: - description: HTTP scheme to use for scraping. - enum: - - http - - https - - HTTPS - - HTTP - type: string - scrape_interval: - description: |- - ScrapeInterval is the same as Interval and has priority over it. - one of scrape_interval or interval can be used - type: string - scrapeTimeout: - description: Timeout after which the scrape is ended - type: string - selector: - description: Selector to select kubernetes Nodes. - 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 - seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 - type: integer - targetLabels: - description: TargetLabels transfers labels on the Kubernetes Node - onto the target. - items: - type: string - type: array - tlsConfig: - description: TLSConfig configuration to use when scraping the endpoint - properties: - ca: - description: Struct containing the CA cert to use for the targets. - properties: - configMap: - description: ConfigMap containing data to use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container to use for the - targets. - type: string - cert: - description: Struct containing the client cert file for the targets. - properties: - configMap: - description: ConfigMap containing data to use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container for - the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container for - the targets. - type: string - keySecret: - description: Secret containing the client key file for the targets. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - vm_scrape_params: - description: VMScrapeParams defines VictoriaMetrics specific scrape - parameters - properties: - disable_compression: - description: DisableCompression - type: boolean - disable_keep_alive: - description: |- - disable_keepalive allows disabling HTTP keep-alive when scraping targets. - By default, HTTP keep-alive is enabled, so TCP connections to scrape targets - could be reused. - See https://docs.victoriametrics.com/vmagent#scrape_config-enhancements - type: boolean - headers: - description: |- - Headers allows sending custom headers to scrape targets - must be in of semicolon separated header with it's value - eg: - headerName: headerValue - vmagent supports since 1.79.0 version - items: - type: string - type: array - no_stale_markers: - type: boolean - proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See feature description https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy - properties: - basic_auth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token: - description: SecretKeySelector selects a key of a Secret. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - bearer_token_file: - type: string - tls_config: - x-kubernetes-preserve-unknown-fields: true - type: object - scrape_align_interval: - type: string - scrape_offset: - type: string - stream_parse: - type: boolean - type: object type: object + x-kubernetes-preserve-unknown-fields: true status: - description: ScrapeObjectStatus defines the observed state of ScrapeObjects properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -21656,16 +1286,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -21678,7 +1303,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmpodscrapes.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -21702,957 +1327,47 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: |- - VMPodScrape is scrape configuration for pods, - it generates vmagent's config for scraping pod targets - based on selectors. 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: VMPodScrapeSpec defines the desired state of VMPodScrape - properties: - attach_metadata: - description: AttachMetadata configures metadata attaching from service - discovery - properties: - node: - description: |- - Node instructs vmagent to add node specific metadata from service discovery - Valid for roles: pod, endpoints, endpointslice. - type: boolean - type: object - jobLabel: - description: The label to use to retrieve the job name from. - type: string - namespaceSelector: - description: Selector to select which namespaces the Endpoints objects - are discovered from. - properties: - any: - description: |- - Boolean describing whether all namespaces are selected in contrast to a - list restricting them. - type: boolean - matchNames: - description: List of namespace names. - items: - type: string - type: array - type: object - podMetricsEndpoints: - description: A list of endpoints allowed as part of this PodMonitor. - items: - description: PodMetricsEndpoint defines a scrapeable endpoint of - a Kubernetes Pod serving metrics. - properties: - attach_metadata: - description: AttachMetadata configures metadata attaching from - service discovery - properties: - node: - description: |- - Node instructs vmagent to add node specific metadata from service discovery - Valid for roles: pod, endpoints, endpointslice. - type: boolean - type: object - authorization: - description: Authorization with http header Authorization - properties: - credentials: - description: Reference to the secret with value for authorization - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to bearer - type: string - type: object - basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearerTokenFile: - description: File to read bearer token for scraping targets. - type: string - bearerTokenSecret: - description: |- - Secret to mount to read bearer token for scraping targets. The secret - needs to be in the same namespace as the scrape object and accessible by - the victoria-metrics operator. - nullable: true - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - filterRunning: - description: |- - FilterRunning applies filter with pod status == running - it prevents from scrapping metrics at failed or succeed state pods. - enabled by default - type: boolean - follow_redirects: - description: FollowRedirects controls redirects for scraping. - type: boolean - honorLabels: - description: HonorLabels chooses the metric's labels on collisions - with target labels. - type: boolean - honorTimestamps: - description: HonorTimestamps controls whether vmagent respects - the timestamps present in scraped data. - type: boolean - interval: - description: Interval at which metrics should be scraped - type: string - max_scrape_size: - description: MaxScrapeSize defines a maximum size of scraped - data for a job - type: string - metricRelabelConfigs: - description: MetricRelabelConfigs to apply to samples after - scrapping. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. - Default is 'replace' - type: string - if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source - label values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source - label values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - oauth2: - description: OAuth2 defines auth configuration - properties: - client_id: - description: The secret or configmap containing the OAuth2 - client id - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 client secret - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for client secret - file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - params: - additionalProperties: - items: - type: string - type: array - description: Optional HTTP URL parameters - type: object - path: - description: HTTP path to scrape for metrics. - type: string - port: - description: Name of the port exposed at Pod. - type: string - portNumber: - description: PortNumber defines the `Pod` port number which - exposes the endpoint. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes - to proxy through this endpoint. - type: string - relabelConfigs: - description: RelabelConfigs to apply to samples during service - discovery. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. - Default is 'replace' - type: string - if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source - label values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source - label values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - sampleLimit: - description: SampleLimit defines per-scrape limit on number - of scraped samples that will be accepted. - format: int64 - type: integer - scheme: - description: HTTP scheme to use for scraping. - enum: - - http - - https - - HTTPS - - HTTP - type: string - scrape_interval: - description: |- - ScrapeInterval is the same as Interval and has priority over it. - one of scrape_interval or interval can be used - type: string - scrapeTimeout: - description: Timeout after which the scrape is ended - type: string - seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 - type: integer - targetPort: - anyOf: - - type: integer - - type: string - description: |- - TargetPort defines name or number of the pod port this endpoint refers to. - Mutually exclusive with Port and PortNumber. - x-kubernetes-int-or-string: true - tlsConfig: - description: TLSConfig configuration to use when scraping the - endpoint - properties: - ca: - description: Struct containing the CA cert to use for the - targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container to use - for the targets. - type: string - cert: - description: Struct containing the client cert file for - the targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container - for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container - for the targets. - type: string - keySecret: - description: Secret containing the client key file for the - targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - vm_scrape_params: - description: VMScrapeParams defines VictoriaMetrics specific - scrape parameters - properties: - disable_compression: - description: DisableCompression - type: boolean - disable_keep_alive: - description: |- - disable_keepalive allows disabling HTTP keep-alive when scraping targets. - By default, HTTP keep-alive is enabled, so TCP connections to scrape targets - could be reused. - See https://docs.victoriametrics.com/vmagent#scrape_config-enhancements - type: boolean - headers: - description: |- - Headers allows sending custom headers to scrape targets - must be in of semicolon separated header with it's value - eg: - headerName: headerValue - vmagent supports since 1.79.0 version - items: - type: string - type: array - no_stale_markers: - type: boolean - proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See feature description https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy - properties: - basic_auth: - description: BasicAuth allow an endpoint to authenticate - over basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token: - description: SecretKeySelector selects a key of a Secret. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - bearer_token_file: - type: string - tls_config: - x-kubernetes-preserve-unknown-fields: true - type: object - scrape_align_interval: - type: string - scrape_offset: - type: string - stream_parse: - type: boolean - type: object - type: object - type: array - podTargetLabels: - description: PodTargetLabels transfers labels on the Kubernetes Pod - onto the target. - items: - type: string - type: array - sampleLimit: - description: SampleLimit defines per-scrape limit on number of scraped - samples that will be accepted. - format: int64 - type: integer - selector: - description: Selector to select Pod objects. - 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 - seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 - type: integer required: - podMetricsEndpoints type: object + x-kubernetes-preserve-unknown-fields: true status: - description: ScrapeObjectStatus defines the observed state of ScrapeObjects properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -22667,16 +1382,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -22689,7 +1399,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmprobes.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -22713,1013 +1423,47 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: |- - VMProbe defines a probe for targets, that will be executed with prober, - like blackbox exporter. - It helps to monitor reachability of target with various checks. 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: VMProbeSpec contains specification parameters for a Probe. - properties: - authorization: - description: Authorization with http header Authorization - properties: - credentials: - description: Reference to the secret with value for authorization - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to bearer - type: string - type: object - basicAuth: - description: BasicAuth allow an endpoint to authenticate over basic - authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearerTokenFile: - description: File to read bearer token for scraping targets. - type: string - bearerTokenSecret: - description: |- - Secret to mount to read bearer token for scraping targets. The secret - needs to be in the same namespace as the scrape object and accessible by - the victoria-metrics operator. - nullable: true - properties: - key: - description: The key of the secret to select from. Must be a - valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - follow_redirects: - description: FollowRedirects controls redirects for scraping. - type: boolean - honorLabels: - description: HonorLabels chooses the metric's labels on collisions - with target labels. - type: boolean - honorTimestamps: - description: HonorTimestamps controls whether vmagent respects the - timestamps present in scraped data. - type: boolean - interval: - description: Interval at which metrics should be scraped - type: string - jobName: - description: The job name assigned to scraped metrics by default. - type: string - max_scrape_size: - description: MaxScrapeSize defines a maximum size of scraped data - for a job - type: string - metricRelabelConfigs: - description: MetricRelabelConfigs to apply to samples after scrapping. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. Default - is 'replace' - type: string - if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source label - values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source label - values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - module: - description: |- - The module to use for probing specifying how to probe the target. - Example module configuring in the blackbox exporter: - https://github.com/prometheus/blackbox_exporter/blob/master/example.yml - type: string - oauth2: - description: OAuth2 defines auth configuration - properties: - client_id: - description: The secret or configmap containing the OAuth2 client - id - properties: - configMap: - description: ConfigMap containing data to use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 client secret - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for client secret file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - params: - additionalProperties: - items: - type: string - type: array - description: Optional HTTP URL parameters - type: object - path: - description: HTTP path to scrape for metrics. - type: string - proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes to - proxy through this endpoint. - type: string - sampleLimit: - description: SampleLimit defines per-scrape limit on number of scraped - samples that will be accepted. - format: int64 - type: integer - scheme: - description: HTTP scheme to use for scraping. - enum: - - http - - https - - HTTPS - - HTTP - type: string - scrape_interval: - description: |- - ScrapeInterval is the same as Interval and has priority over it. - one of scrape_interval or interval can be used - type: string - scrapeTimeout: - description: Timeout after which the scrape is ended - type: string - seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 - type: integer - targets: - description: Targets defines a set of static and/or dynamically discovered - targets to be probed using the prober. - properties: - ingress: - description: Ingress defines the set of dynamically discovered - ingress objects which hosts are considered for probing. - properties: - namespaceSelector: - description: Select Ingress objects by namespace. - properties: - any: - description: |- - Boolean describing whether all namespaces are selected in contrast to a - list restricting them. - type: boolean - matchNames: - description: List of namespace names. - items: - type: string - type: array - type: object - relabelingConfigs: - description: RelabelConfigs to apply to samples during service - discovery. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. - Default is 'replace' - type: string - if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for - `action: graphite`' - type: object - match: - description: 'Match is used together with Labels for - `action: graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source - label values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source - label values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - selector: - description: Select Ingress objects by labels. - 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 - staticConfig: - description: StaticConfig defines static targets which are considers - for probing. - properties: - labels: - additionalProperties: - type: string - description: Labels assigned to all metrics scraped from the - targets. - type: object - relabelingConfigs: - description: RelabelConfigs to apply to samples during service - discovery. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. - Default is 'replace' - type: string - if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for - `action: graphite`' - type: object - match: - description: 'Match is used together with Labels for - `action: graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source - label values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source - label values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - targets: - description: Targets is a list of URLs to probe using the - configured prober. - items: - type: string - type: array - required: - - targets - type: object - type: object - tlsConfig: - description: TLSConfig configuration to use when scraping the endpoint - properties: - ca: - description: Struct containing the CA cert to use for the targets. - properties: - configMap: - description: ConfigMap containing data to use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container to use for the - targets. - type: string - cert: - description: Struct containing the client cert file for the targets. - properties: - configMap: - description: ConfigMap containing data to use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container for - the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container for - the targets. - type: string - keySecret: - description: Secret containing the client key file for the targets. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - vm_scrape_params: - description: VMScrapeParams defines VictoriaMetrics specific scrape - parameters - properties: - disable_compression: - description: DisableCompression - type: boolean - disable_keep_alive: - description: |- - disable_keepalive allows disabling HTTP keep-alive when scraping targets. - By default, HTTP keep-alive is enabled, so TCP connections to scrape targets - could be reused. - See https://docs.victoriametrics.com/vmagent#scrape_config-enhancements - type: boolean - headers: - description: |- - Headers allows sending custom headers to scrape targets - must be in of semicolon separated header with it's value - eg: - headerName: headerValue - vmagent supports since 1.79.0 version - items: - type: string - type: array - no_stale_markers: - type: boolean - proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See feature description https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy - properties: - basic_auth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token: - description: SecretKeySelector selects a key of a Secret. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - bearer_token_file: - type: string - tls_config: - x-kubernetes-preserve-unknown-fields: true - type: object - scrape_align_interval: - type: string - scrape_offset: - type: string - stream_parse: - type: boolean - type: object - vmProberSpec: - description: |- - Specification for the prober to use for probing targets. - The prober.URL parameter is required. Targets cannot be probed if left empty. - properties: - path: - description: |- - Path to collect metrics from. - Defaults to `/probe`. - type: string - scheme: - description: |- - HTTP scheme to use for scraping. - Defaults to `http`. - enum: - - http - - https - type: string - url: - description: Mandatory URL of the prober. - type: string - required: - - url - type: object required: - vmProberSpec type: object + x-kubernetes-preserve-unknown-fields: true status: - description: ScrapeObjectStatus defines the observed state of ScrapeObjects properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -23734,16 +1478,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object required: @@ -23758,7 +1497,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmrules.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -23782,234 +1521,47 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMRule defines rule records for vmalert application 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: VMRuleSpec defines the desired state of VMRule - properties: - groups: - description: Groups list of group rules - items: - description: RuleGroup is a list of sequentially evaluated recording - and alerting rules. - properties: - concurrency: - description: Concurrency defines how many rules execute at once. - type: integer - eval_alignment: - description: |- - Optional - The evaluation timestamp will be aligned with group's interval, - instead of using the actual timestamp that evaluation happens at. - It is enabled by default to get more predictable results - and to visually align with graphs plotted via Grafana or vmui. - type: boolean - eval_delay: - description: |- - Optional - Adjust the `time` parameter of group evaluation requests to compensate intentional query delay from the datasource. - type: string - eval_offset: - description: |- - Optional - Group will be evaluated at the exact offset in the range of [0...interval]. - type: string - extra_filter_labels: - additionalProperties: - type: string - description: |- - ExtraFilterLabels optional list of label filters applied to every rule's - request within a group. Is compatible only with VM datasource. - See more details [here](https://docs.victoriametrics.com/#prometheus-querying-api-enhancements) - Deprecated, use params instead - type: object - headers: - description: |- - Headers contains optional HTTP headers added to each rule request - Must be in form `header-name: value` - For example: - headers: - - "CustomHeader: foo" - - "CustomHeader2: bar" - items: - type: string - type: array - interval: - description: evaluation interval for group - type: string - labels: - additionalProperties: - type: string - description: |- - Labels optional list of labels added to every rule within a group. - It has priority over the external labels. - Labels are commonly used for adding environment - or tenant-specific tag. - type: object - limit: - description: |- - Limit the number of alerts an alerting rule and series a recording - rule can produce - type: integer - name: - description: Name of group - type: string - notifier_headers: - description: |- - NotifierHeaders contains optional HTTP headers added to each alert request which will send to notifier - Must be in form `header-name: value` - For example: - headers: - - "CustomHeader: foo" - - "CustomHeader2: bar" - items: - type: string - type: array - params: - additionalProperties: - items: - type: string - type: array - description: Params optional HTTP URL parameters added to each - rule request - type: object - rules: - description: Rules list of alert rules - items: - description: Rule describes an alerting or recording rule. - properties: - alert: - description: Alert is a name for alert - type: string - annotations: - additionalProperties: - type: string - description: Annotations will be added to rule configuration - type: object - debug: - description: |- - Debug enables logging for rule - it useful for tracking - type: boolean - expr: - description: Expr is query, that will be evaluated at - dataSource - type: string - for: - description: |- - For evaluation interval in time.Duration format - 30s, 1m, 1h or nanoseconds - type: string - keep_firing_for: - description: |- - KeepFiringFor will make alert continue firing for this long - even when the alerting expression no longer has results. - Use time.Duration format, 30s, 1m, 1h or nanoseconds - type: string - labels: - additionalProperties: - type: string - description: Labels will be added to rule configuration - type: object - record: - description: Record represents a query, that will be recorded - to dataSource - type: string - update_entries_limit: - description: |- - UpdateEntriesLimit defines max number of rule's state updates stored in memory. - Overrides `-rule.updateEntriesLimit` in vmalert. - type: integer - type: object - type: array - tenant: - description: |- - Tenant id for group, can be used only with enterprise version of vmalert. - See more details [here](https://docs.victoriametrics.com/vmalert#multitenancy). - type: string - type: - description: |- - Type defines datasource type for enterprise version of vmalert - possible values - prometheus,graphite,vlogs - type: string - required: - - name - - rules - type: object - type: array required: - groups type: object + x-kubernetes-preserve-unknown-fields: true status: - description: VMRuleStatus defines the observed state of VMRule properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -24024,16 +1576,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object required: @@ -24048,7 +1595,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmscrapeconfigs.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -24072,3255 +1619,45 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMScrapeConfig specifies a set of targets and parameters describing - how to scrape them. 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: VMScrapeConfigSpec defines the desired state of VMScrapeConfig - properties: - authorization: - description: Authorization with http header Authorization - properties: - credentials: - description: Reference to the secret with value for authorization - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to bearer - type: string - type: object - azureSDConfigs: - description: AzureSDConfigs defines a list of Azure service discovery - configurations. - items: - description: |- - AzureSDConfig allow retrieving scrape targets from Azure VMs. - See [here](https://docs.victoriametrics.com/sd_configs#azure_sd_configs) - properties: - authenticationMethod: - description: |- - # The authentication method, either OAuth or ManagedIdentity. - See https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview - enum: - - OAuth - - ManagedIdentity - type: string - clientID: - description: Optional client ID. Only required with the OAuth - authentication method. - type: string - clientSecret: - description: Optional client secret. Only required with the - OAuth authentication method. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - environment: - description: The Azure environment. - type: string - port: - description: |- - The port to scrape metrics from. If using the public IP address, this must - instead be specified in the relabeling rule. - type: integer - resourceGroup: - description: Optional resource group name. Limits discovery - to this resource group. - type: string - subscriptionID: - description: The subscription ID. Always required. - minLength: 1 - type: string - tenantID: - description: Optional tenant ID. Only required with the OAuth - authentication method. - type: string - required: - - subscriptionID - type: object - type: array - basicAuth: - description: BasicAuth allow an endpoint to authenticate over basic - authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearerTokenFile: - description: File to read bearer token for scraping targets. - type: string - bearerTokenSecret: - description: |- - Secret to mount to read bearer token for scraping targets. The secret - needs to be in the same namespace as the scrape object and accessible by - the victoria-metrics operator. - nullable: true - properties: - key: - description: The key of the secret to select from. Must be a - valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - consulSDConfigs: - description: ConsulSDConfigs defines a list of Consul service discovery - configurations. - items: - description: |- - ConsulSDConfig defines a Consul service discovery configuration. - See [here](https://docs.victoriametrics.com/sd_configs/#consul_sd_configs) - properties: - allowStale: - description: |- - Allow stale Consul results (see https://developer.hashicorp.com/consul/api-docs/features/consistency). Will reduce load on Consul. - If unset, use its default value. - type: boolean - authorization: - description: Authorization header to use on every scrape request. - properties: - credentials: - description: Reference to the secret with value for authorization - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to bearer - type: string - type: object - basicAuth: - description: BasicAuth information to use on every scrape request. - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - datacenter: - description: Consul Datacenter name, if not provided it will - use the local Consul Agent Datacenter. - type: string - filter: - description: |- - Filter defines filter for /v1/catalog/services requests - See https://developer.hashicorp.com/consul/api-docs/features/filtering - type: string - followRedirects: - description: |- - Configure whether HTTP requests follow HTTP 3xx redirects. - If unset, use its default value. - type: boolean - namespace: - description: Namespaces are only supported in Consul Enterprise. - type: string - nodeMeta: - additionalProperties: - type: string - description: Node metadata key/value pairs to filter nodes for - a given service. - type: object - x-kubernetes-map-type: atomic - oauth2: - description: OAuth2 defines auth configuration - properties: - client_id: - description: The secret or configmap containing the OAuth2 - client id - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 client secret - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for client secret - file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - partition: - description: Admin Partitions are only supported in Consul Enterprise. - type: string - proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See [feature description](https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy) - properties: - basic_auth: - description: BasicAuth allow an endpoint to authenticate - over basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token: - description: SecretKeySelector selects a key of a Secret. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - bearer_token_file: - type: string - tls_config: - x-kubernetes-preserve-unknown-fields: true - type: object - proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes - to proxy through this endpoint. - type: string - scheme: - description: HTTP Scheme default "http" - enum: - - HTTP - - HTTPS - type: string - server: - description: A valid string consisting of a hostname or IP followed - by an optional port number. - minLength: 1 - type: string - services: - description: A list of services for which targets are retrieved. - If omitted, all services are scraped. - items: - type: string - type: array - x-kubernetes-list-type: atomic - tagSeparator: - description: |- - The string by which Consul tags are joined into the tag label. - If unset, use its default value. - type: string - tags: - description: An optional list of tags used to filter nodes for - a given service. Services must contain all tags in the list. - items: - type: string - type: array - x-kubernetes-list-type: atomic - tlsConfig: - description: TLS configuration to use on every scrape request - properties: - ca: - description: Struct containing the CA cert to use for the - targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container to use - for the targets. - type: string - cert: - description: Struct containing the client cert file for - the targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container - for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container - for the targets. - type: string - keySecret: - description: Secret containing the client key file for the - targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - tokenRef: - description: Consul ACL TokenRef, if not provided it will use - the ACL from the local Consul Agent. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - required: - - server - type: object - type: array - digitalOceanSDConfigs: - description: DigitalOceanSDConfigs defines a list of DigitalOcean - service discovery configurations. - items: - description: |- - DigitalOceanSDConfig allow retrieving scrape targets from DigitalOcean's Droplets API. - This service discovery uses the public IPv4 address by default, by that can be changed with relabeling. - See [here](https://docs.victoriametrics.com/sd_configs#digitalocean_sd_configs) - properties: - authorization: - description: Authorization header to use on every scrape request. - properties: - credentials: - description: Reference to the secret with value for authorization - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to bearer - type: string - type: object - followRedirects: - description: Configure whether HTTP requests follow HTTP 3xx - redirects. - type: boolean - oauth2: - description: OAuth2 defines auth configuration - properties: - client_id: - description: The secret or configmap containing the OAuth2 - client id - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 client secret - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for client secret - file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - port: - description: The port to scrape metrics from. - type: integer - proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See [feature description](https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy) - properties: - basic_auth: - description: BasicAuth allow an endpoint to authenticate - over basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token: - description: SecretKeySelector selects a key of a Secret. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - bearer_token_file: - type: string - tls_config: - x-kubernetes-preserve-unknown-fields: true - type: object - proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes - to proxy through this endpoint. - type: string - tlsConfig: - description: TLS configuration to use on every scrape request - properties: - ca: - description: Struct containing the CA cert to use for the - targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container to use - for the targets. - type: string - cert: - description: Struct containing the client cert file for - the targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container - for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container - for the targets. - type: string - keySecret: - description: Secret containing the client key file for the - targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - type: object - type: array - dnsSDConfigs: - description: DNSSDConfigs defines a list of DNS service discovery - configurations. - items: - description: |- - DNSSDConfig allows specifying a set of DNS domain names which are periodically queried to discover a list of targets. - The DNS servers to be contacted are read from /etc/resolv.conf. - See [here](https://docs.victoriametrics.com/sd_configs#dns_sd_configs) - properties: - names: - description: A list of DNS domain names to be queried. - items: - type: string - minItems: 1 - type: array - port: - description: |- - The port number used if the query type is not SRV - Ignored for SRV records - type: integer - type: - enum: - - SRV - - A - - AAAA - - MX - type: string - required: - - names - type: object - type: array - ec2SDConfigs: - description: EC2SDConfigs defines a list of EC2 service discovery - configurations. - items: - description: |- - EC2SDConfig allow retrieving scrape targets from AWS EC2 instances. - The private IP address is used by default, but may be changed to the public IP address with relabeling. - The IAM credentials used must have the ec2:DescribeInstances permission to discover scrape targets. - See [here](https://docs.victoriametrics.com/sd_configs#ec2_sd_configs) - properties: - accessKey: - description: AccessKey is the AWS API key. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - filters: - description: |- - Filters can be used optionally to filter the instance list by other criteria. - Available filter criteria can be found here: - https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstances.html - Filter API documentation: https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_Filter.html - items: - description: EC2Filter is the configuration for filtering - EC2 instances. - properties: - name: - type: string - values: - items: - type: string - type: array - required: - - name - - values - type: object - type: array - port: - description: |- - The port to scrape metrics from. If using the public IP address, this must - instead be specified in the relabeling rule. - type: integer - region: - description: The AWS region - type: string - roleARN: - description: AWS Role ARN, an alternative to using AWS API keys. - type: string - secretKey: - description: SecretKey is the AWS API secret. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - type: array - fileSDConfigs: - description: FileSDConfigs defines a list of file service discovery - configurations. - items: - description: |- - FileSDConfig defines a file service discovery configuration. - See [here](https://docs.victoriametrics.com/sd_configs#file_sd_configs) - properties: - files: - description: List of files to be used for file discovery. - items: - type: string - minItems: 1 - type: array - required: - - files - type: object - type: array - follow_redirects: - description: FollowRedirects controls redirects for scraping. - type: boolean - gceSDConfigs: - description: GCESDConfigs defines a list of GCE service discovery - configurations. - items: - description: |- - GCESDConfig configures scrape targets from GCP GCE instances. - The private IP address is used by default, but may be changed to - the public IP address with relabeling. - See [here](https://docs.victoriametrics.com/sd_configs#gce_sd_configs) - - The GCE service discovery will load the Google Cloud credentials - from the file specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable. - See https://cloud.google.com/kubernetes-engine/docs/tutorials/authenticating-to-cloud-platform - properties: - filter: - description: |- - Filter can be used optionally to filter the instance list by other criteria - Syntax of this filter is described in the filter query parameter section: - https://cloud.google.com/compute/docs/reference/latest/instances/list - type: string - port: - description: |- - The port to scrape metrics from. If using the public IP address, this must - instead be specified in the relabeling rule. - type: integer - project: - description: The Google Cloud Project ID - minLength: 1 - type: string - tagSeparator: - description: The tag separator is used to separate the tags - on concatenation - type: string - zone: - description: The zone of the scrape targets. If you need multiple - zones use multiple GCESDConfigs. - x-kubernetes-preserve-unknown-fields: true - required: - - project - - zone - type: object - type: array - honorLabels: - description: HonorLabels chooses the metric's labels on collisions - with target labels. - type: boolean - honorTimestamps: - description: HonorTimestamps controls whether vmagent respects the - timestamps present in scraped data. - type: boolean - httpSDConfigs: - description: HTTPSDConfigs defines a list of HTTP service discovery - configurations. - items: - description: |- - HTTPSDConfig defines a HTTP service discovery configuration. - See [here](https://docs.victoriametrics.com/sd_configs#http_sd_configs) - properties: - authorization: - description: Authorization header to use on every scrape request. - properties: - credentials: - description: Reference to the secret with value for authorization - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to bearer - type: string - type: object - basicAuth: - description: BasicAuth information to use on every scrape request. - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See [feature description](https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy) - properties: - basic_auth: - description: BasicAuth allow an endpoint to authenticate - over basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token: - description: SecretKeySelector selects a key of a Secret. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - bearer_token_file: - type: string - tls_config: - x-kubernetes-preserve-unknown-fields: true - type: object - proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes - to proxy through this endpoint. - type: string - tlsConfig: - description: TLS configuration to use on every scrape request - properties: - ca: - description: Struct containing the CA cert to use for the - targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container to use - for the targets. - type: string - cert: - description: Struct containing the client cert file for - the targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container - for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container - for the targets. - type: string - keySecret: - description: Secret containing the client key file for the - targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - url: - description: URL from which the targets are fetched. - minLength: 1 - pattern: ^http(s)?://.+$ - type: string - required: - - url - type: object - type: array - interval: - description: Interval at which metrics should be scraped - type: string - kubernetesSDConfigs: - description: KubernetesSDConfigs defines a list of Kubernetes service - discovery configurations. - items: - description: |- - KubernetesSDConfig allows retrieving scrape targets from Kubernetes' REST API. - See [here](https://docs.victoriametrics.com/sd_configs#kubernetes_sd_configs) - properties: - apiServer: - description: |- - The API server address consisting of a hostname or IP address followed - by an optional port number. - If left empty, assuming process is running inside - of the cluster. It will discover API servers automatically and use the pod's - CA certificate and bearer token file at /var/run/secrets/kubernetes.io/serviceaccount/. - type: string - attach_metadata: - description: AttachMetadata configures metadata attaching from - service discovery - properties: - node: - description: |- - Node instructs vmagent to add node specific metadata from service discovery - Valid for roles: pod, endpoints, endpointslice. - type: boolean - type: object - authorization: - description: Authorization header to use on every scrape request. - properties: - credentials: - description: Reference to the secret with value for authorization - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to bearer - type: string - type: object - basicAuth: - description: BasicAuth information to use on every scrape request. - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - followRedirects: - description: Configure whether HTTP requests follow HTTP 3xx - redirects. - type: boolean - namespaces: - description: Optional namespace discovery. If omitted, discover - targets across all namespaces. - properties: - names: - description: |- - List of namespaces where to watch for resources. - If empty and `ownNamespace` isn't true, watch for resources in all namespaces. - items: - type: string - type: array - ownNamespace: - description: Includes the namespace in which the pod exists - to the list of watched namespaces. - type: boolean - type: object - oauth2: - description: OAuth2 defines auth configuration - properties: - client_id: - description: The secret or configmap containing the OAuth2 - client id - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 client secret - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for client secret - file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See [feature description](https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy) - properties: - basic_auth: - description: BasicAuth allow an endpoint to authenticate - over basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token: - description: SecretKeySelector selects a key of a Secret. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - bearer_token_file: - type: string - tls_config: - x-kubernetes-preserve-unknown-fields: true - type: object - proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes - to proxy through this endpoint. - type: string - role: - description: Role of the Kubernetes entities that should be - discovered. - type: string - selectors: - description: Selector to select objects. - items: - description: K8SSelectorConfig is Kubernetes Selector Config - properties: - field: - type: string - label: - type: string - role: - type: string - required: - - role - type: object - type: array - x-kubernetes-list-map-keys: - - role - x-kubernetes-list-type: map - tlsConfig: - description: TLS configuration to use on every scrape request - properties: - ca: - description: Struct containing the CA cert to use for the - targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container to use - for the targets. - type: string - cert: - description: Struct containing the client cert file for - the targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container - for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container - for the targets. - type: string - keySecret: - description: Secret containing the client key file for the - targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - required: - - role - type: object - type: array - max_scrape_size: - description: MaxScrapeSize defines a maximum size of scraped data - for a job - type: string - metricRelabelConfigs: - description: MetricRelabelConfigs to apply to samples after scrapping. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. Default - is 'replace' - type: string - if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source label - values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source label - values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - oauth2: - description: OAuth2 defines auth configuration - properties: - client_id: - description: The secret or configmap containing the OAuth2 client - id - properties: - configMap: - description: ConfigMap containing data to use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 client secret - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for client secret file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - openstackSDConfigs: - description: OpenStackSDConfigs defines a list of OpenStack service - discovery configurations. - items: - description: |- - OpenStackSDConfig allow retrieving scrape targets from OpenStack Nova instances. - See [here](https://docs.victoriametrics.com/sd_configs#openstack_sd_configs) - properties: - allTenants: - description: |- - Whether the service discovery should list all instances for all projects. - It is only relevant for the 'instance' role and usually requires admin permissions. - type: boolean - applicationCredentialId: - description: ApplicationCredentialID - type: string - applicationCredentialName: - description: |- - The ApplicationCredentialID or ApplicationCredentialName fields are - required if using an application credential to authenticate. Some providers - allow you to create an application credential to authenticate rather than a - password. - type: string - applicationCredentialSecret: - description: |- - The applicationCredentialSecret field is required if using an application - credential to authenticate. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - availability: - description: Availability of the endpoint to connect to. - enum: - - Public - - public - - Admin - - admin - - Internal - - internal - type: string - domainID: - description: DomainID - type: string - domainName: - description: |- - At most one of domainId and domainName must be provided if using username - with Identity V3. Otherwise, either are optional. - type: string - identityEndpoint: - description: |- - IdentityEndpoint specifies the HTTP endpoint that is required to work with - the Identity API of the appropriate version. - type: string - password: - description: |- - Password for the Identity V2 and V3 APIs. Consult with your provider's - control panel to discover your account's preferred method of authentication. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - port: - description: |- - The port to scrape metrics from. If using the public IP address, this must - instead be specified in the relabeling rule. - type: integer - projectID: - description: ' ProjectID' - type: string - projectName: - description: |- - The ProjectId and ProjectName fields are optional for the Identity V2 API. - Some providers allow you to specify a ProjectName instead of the ProjectId. - Some require both. Your provider's authentication policies will determine - how these fields influence authentication. - type: string - region: - description: The OpenStack Region. - minLength: 1 - type: string - role: - description: The OpenStack role of entities that should be discovered. - enum: - - Instance - - instance - - Hypervisor - - hypervisor - type: string - tlsConfig: - description: TLS configuration to use on every scrape request - properties: - ca: - description: Struct containing the CA cert to use for the - targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container to use - for the targets. - type: string - cert: - description: Struct containing the client cert file for - the targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container - for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container - for the targets. - type: string - keySecret: - description: Secret containing the client key file for the - targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - userid: - description: UserID - type: string - username: - description: |- - Username is required if using Identity V2 API. Consult with your provider's - control panel to discover your account's username. - In Identity V3, either userid or a combination of username - and domainId or domainName are needed - type: string - required: - - region - - role - type: object - type: array - params: - additionalProperties: - items: - type: string - type: array - description: Optional HTTP URL parameters - type: object - path: - description: HTTP path to scrape for metrics. - type: string - proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes to - proxy through this endpoint. - type: string - relabelConfigs: - description: RelabelConfigs to apply to samples during service discovery. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. Default - is 'replace' - type: string - if: - description: 'If represents metricsQL match expression (or list - of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source label - values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source label - values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - sampleLimit: - description: SampleLimit defines per-scrape limit on number of scraped - samples that will be accepted. - format: int64 - type: integer - scheme: - description: HTTP scheme to use for scraping. - enum: - - http - - https - - HTTPS - - HTTP - type: string - scrape_interval: - description: |- - ScrapeInterval is the same as Interval and has priority over it. - one of scrape_interval or interval can be used - type: string - scrapeTimeout: - description: Timeout after which the scrape is ended - type: string - seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 - type: integer - staticConfigs: - description: StaticConfigs defines a list of static targets with a - common label set. - items: - description: |- - StaticConfig defines a static configuration. - See [here](https://docs.victoriametrics.com/sd_configs#static_configs) - properties: - labels: - additionalProperties: - type: string - description: Labels assigned to all metrics scraped from the - targets. - type: object - x-kubernetes-map-type: atomic - targets: - description: List of targets for this static configuration. - items: - type: string - type: array - type: object - type: array - tlsConfig: - description: TLSConfig configuration to use when scraping the endpoint - properties: - ca: - description: Struct containing the CA cert to use for the targets. - properties: - configMap: - description: ConfigMap containing data to use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container to use for the - targets. - type: string - cert: - description: Struct containing the client cert file for the targets. - properties: - configMap: - description: ConfigMap containing data to use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container for - the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container for - the targets. - type: string - keySecret: - description: Secret containing the client key file for the targets. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - vm_scrape_params: - description: VMScrapeParams defines VictoriaMetrics specific scrape - parameters - properties: - disable_compression: - description: DisableCompression - type: boolean - disable_keep_alive: - description: |- - disable_keepalive allows disabling HTTP keep-alive when scraping targets. - By default, HTTP keep-alive is enabled, so TCP connections to scrape targets - could be reused. - See https://docs.victoriametrics.com/vmagent#scrape_config-enhancements - type: boolean - headers: - description: |- - Headers allows sending custom headers to scrape targets - must be in of semicolon separated header with it's value - eg: - headerName: headerValue - vmagent supports since 1.79.0 version - items: - type: string - type: array - no_stale_markers: - type: boolean - proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See feature description https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy - properties: - basic_auth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token: - description: SecretKeySelector selects a key of a Secret. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - bearer_token_file: - type: string - tls_config: - x-kubernetes-preserve-unknown-fields: true - type: object - scrape_align_interval: - type: string - scrape_offset: - type: string - stream_parse: - type: boolean - type: object type: object + x-kubernetes-preserve-unknown-fields: true status: - description: ScrapeObjectStatus defines the observed state of ScrapeObjects properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -27335,16 +1672,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -27357,7 +1689,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmservicescrapes.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -27381,963 +1713,47 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: |- - VMServiceScrape is scrape configuration for endpoints associated with - kubernetes service, - it generates scrape configuration for vmagent based on selectors. - result config will scrape service endpoints 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: VMServiceScrapeSpec defines the desired state of VMServiceScrape - properties: - attach_metadata: - description: AttachMetadata configures metadata attaching from service - discovery - properties: - node: - description: |- - Node instructs vmagent to add node specific metadata from service discovery - Valid for roles: pod, endpoints, endpointslice. - type: boolean - type: object - discoveryRole: - description: |- - DiscoveryRole - defines kubernetes_sd role for objects discovery. - by default, its endpoints. - can be changed to service or endpointslices. - note, that with service setting, you have to use port: "name" - and cannot use targetPort for endpoints. - enum: - - endpoints - - service - - endpointslices - type: string - endpoints: - description: A list of endpoints allowed as part of this ServiceScrape. - items: - description: Endpoint defines a scrapeable endpoint serving metrics. - properties: - attach_metadata: - description: AttachMetadata configures metadata attaching from - service discovery - properties: - node: - description: |- - Node instructs vmagent to add node specific metadata from service discovery - Valid for roles: pod, endpoints, endpointslice. - type: boolean - type: object - authorization: - description: Authorization with http header Authorization - properties: - credentials: - description: Reference to the secret with value for authorization - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to bearer - type: string - type: object - basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearerTokenFile: - description: File to read bearer token for scraping targets. - type: string - bearerTokenSecret: - description: |- - Secret to mount to read bearer token for scraping targets. The secret - needs to be in the same namespace as the scrape object and accessible by - the victoria-metrics operator. - nullable: true - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - follow_redirects: - description: FollowRedirects controls redirects for scraping. - type: boolean - honorLabels: - description: HonorLabels chooses the metric's labels on collisions - with target labels. - type: boolean - honorTimestamps: - description: HonorTimestamps controls whether vmagent respects - the timestamps present in scraped data. - type: boolean - interval: - description: Interval at which metrics should be scraped - type: string - max_scrape_size: - description: MaxScrapeSize defines a maximum size of scraped - data for a job - type: string - metricRelabelConfigs: - description: MetricRelabelConfigs to apply to samples after - scrapping. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. - Default is 'replace' - type: string - if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source - label values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source - label values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - oauth2: - description: OAuth2 defines auth configuration - properties: - client_id: - description: The secret or configmap containing the OAuth2 - client id - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 client secret - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for client secret - file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - params: - additionalProperties: - items: - type: string - type: array - description: Optional HTTP URL parameters - type: object - path: - description: HTTP path to scrape for metrics. - type: string - port: - description: Name of the port exposed at Service. - type: string - proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes - to proxy through this endpoint. - type: string - relabelConfigs: - description: RelabelConfigs to apply to samples during service - discovery. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. - Default is 'replace' - type: string - if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source - label values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source - label values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - sampleLimit: - description: SampleLimit defines per-scrape limit on number - of scraped samples that will be accepted. - format: int64 - type: integer - scheme: - description: HTTP scheme to use for scraping. - enum: - - http - - https - - HTTPS - - HTTP - type: string - scrape_interval: - description: |- - ScrapeInterval is the same as Interval and has priority over it. - one of scrape_interval or interval can be used - type: string - scrapeTimeout: - description: Timeout after which the scrape is ended - type: string - seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 - type: integer - targetPort: - anyOf: - - type: integer - - type: string - description: |- - TargetPort - Name or number of the pod port this endpoint refers to. Mutually exclusive with port. - x-kubernetes-int-or-string: true - tlsConfig: - description: TLSConfig configuration to use when scraping the - endpoint - properties: - ca: - description: Struct containing the CA cert to use for the - targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container to use - for the targets. - type: string - cert: - description: Struct containing the client cert file for - the targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container - for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container - for the targets. - type: string - keySecret: - description: Secret containing the client key file for the - targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - vm_scrape_params: - description: VMScrapeParams defines VictoriaMetrics specific - scrape parameters - properties: - disable_compression: - description: DisableCompression - type: boolean - disable_keep_alive: - description: |- - disable_keepalive allows disabling HTTP keep-alive when scraping targets. - By default, HTTP keep-alive is enabled, so TCP connections to scrape targets - could be reused. - See https://docs.victoriametrics.com/vmagent#scrape_config-enhancements - type: boolean - headers: - description: |- - Headers allows sending custom headers to scrape targets - must be in of semicolon separated header with it's value - eg: - headerName: headerValue - vmagent supports since 1.79.0 version - items: - type: string - type: array - no_stale_markers: - type: boolean - proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See feature description https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy - properties: - basic_auth: - description: BasicAuth allow an endpoint to authenticate - over basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token: - description: SecretKeySelector selects a key of a Secret. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - bearer_token_file: - type: string - tls_config: - x-kubernetes-preserve-unknown-fields: true - type: object - scrape_align_interval: - type: string - scrape_offset: - type: string - stream_parse: - type: boolean - type: object - type: object - type: array - jobLabel: - description: The label to use to retrieve the job name from. - type: string - namespaceSelector: - description: Selector to select which namespaces the Endpoints objects - are discovered from. - properties: - any: - description: |- - Boolean describing whether all namespaces are selected in contrast to a - list restricting them. - type: boolean - matchNames: - description: List of namespace names. - items: - type: string - type: array - type: object - podTargetLabels: - description: PodTargetLabels transfers labels on the Kubernetes Pod - onto the target. - items: - type: string - type: array - sampleLimit: - description: SampleLimit defines per-scrape limit on number of scraped - samples that will be accepted. - format: int64 - type: integer - selector: - description: Selector to select Endpoints objects by corresponding - Service labels. - 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 - seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 - type: integer - targetLabels: - description: TargetLabels transfers labels on the Kubernetes Service - onto the target. - items: - type: string - type: array required: - endpoints type: object + x-kubernetes-preserve-unknown-fields: true status: - description: ScrapeObjectStatus defines the observed state of ScrapeObjects properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -28352,16 +1768,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object required: @@ -28376,7 +1787,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmsingles.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -28398,1833 +1809,45 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMSingle is fast, cost-effective and scalable time-series database. 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: VMSingleSpec defines the desired state of VMSingle - properties: - affinity: - description: Affinity If specified, the pod's scheduling constraints. - type: object - x-kubernetes-preserve-unknown-fields: true - configMaps: - description: |- - ConfigMaps is a list of ConfigMaps in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/configs/CONFIGMAP_NAME folder - items: - type: string - type: array - containers: - description: |- - Containers property allows to inject additions sidecars or to patch existing containers. - It can be useful for proxies, backup, etc. - items: - description: A single application container that you want to run - within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - disableAutomountServiceAccountToken: - description: |- - DisableAutomountServiceAccountToken whether to disable serviceAccount auto mount by Kubernetes (available from v0.54.0). - Operator will conditionally create volumes and volumeMounts for containers if it requires k8s API access. - For example, vmagent and vm-config-reloader requires k8s API access. - Operator creates volumes with name: "kube-api-access", which can be used as volumeMount for extraContainers if needed. - And also adds VolumeMounts at /var/run/secrets/kubernetes.io/serviceaccount. - type: boolean - disableSelfServiceScrape: - description: |- - DisableSelfServiceScrape controls creation of VMServiceScrape by operator - for the application. - Has priority over `VM_DISABLESELFSERVICESCRAPECREATION` operator env variable - type: boolean - dnsConfig: - description: |- - Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the generated DNS - configuration based on DNSPolicy. - items: - x-kubernetes-preserve-unknown-fields: true - properties: - nameservers: - description: |- - A list of DNS name server IP addresses. - This will be appended to the base nameservers generated from DNSPolicy. - Duplicated nameservers will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - options: - description: |- - A list of DNS resolver options. - This will be merged with the base options generated from DNSPolicy. - Duplicated entries will be removed. Resolution options given in Options - will override those that appear in the base DNSPolicy. - items: - description: PodDNSConfigOption defines DNS resolver options - of a pod. - properties: - name: - description: |- - Name is this DNS resolver option's name. - Required. - type: string - value: - description: Value is this DNS resolver option's value. - type: string - type: object - type: array - x-kubernetes-list-type: atomic - searches: - description: |- - A list of DNS search domains for host-name lookup. - This will be appended to the base search paths generated from DNSPolicy. - Duplicated search paths will be removed. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - dnsPolicy: - description: DNSPolicy sets DNS policy for the pod - type: string - extraArgs: - additionalProperties: - type: string - description: |- - ExtraArgs that will be passed to the application container - for example remoteWrite.tmpDataPath: /tmp - type: object - extraEnvs: - description: ExtraEnvs that will be passed to the application container - items: - description: EnvVar represents an environment variable present in - a Container. - properties: - name: - description: Name of the environment variable. Must be a C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap - items: - description: EnvFromSource represents the source of a set of ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - host_aliases: - description: |- - HostAliasesUnderScore provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - Has Priority over hostAliases field - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostAliases: - description: |- - HostAliases provides mapping for ip and hostname, - that would be propagated to pod, - cannot be used with HostNetwork. - items: - description: |- - HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the - pod's hosts file. - properties: - hostnames: - description: Hostnames for the above IP address. - items: - type: string - type: array - x-kubernetes-list-type: atomic - ip: - description: IP address of the host file entry. - type: string - required: - - ip - type: object - type: array - hostNetwork: - description: HostNetwork controls whether the pod may use the node - network namespace - type: boolean - image: - description: |- - Image - docker image settings - if no specified operator uses default version from operator config - properties: - pullPolicy: - description: PullPolicy describes how to pull docker image - type: string - repository: - description: Repository contains name of docker image + it's repository - if needed - type: string - tag: - description: Tag contains desired docker image version - type: string - type: object - imagePullSecrets: - description: |- - ImagePullSecrets An optional list of references to secrets in the same namespace - to use for pulling images from registries - see https://kubernetes.io/docs/concepts/containers/images/#referring-to-an-imagepullsecrets-on-a-pod - items: - description: |- - LocalObjectReference contains enough information to let you locate the - referenced object inside the same namespace. - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - type: object - x-kubernetes-map-type: atomic - type: array - initContainers: - description: |- - InitContainers allows adding initContainers to the pod definition. - Any errors during the execution of an initContainer will lead to a restart of the Pod. - More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ - items: - description: A single application container that you want to run - within a pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - insertPorts: - description: InsertPorts - additional listen ports for data ingestion. - properties: - graphitePort: - description: GraphitePort listen port - type: string - influxPort: - description: InfluxPort listen port - type: string - openTSDBHTTPPort: - description: OpenTSDBHTTPPort for http connections. - type: string - openTSDBPort: - description: OpenTSDBPort for tcp and udp listen - type: string - type: object - license: - description: |- - License allows to configure license key to be used for enterprise features. - Using license key is supported starting from VictoriaMetrics v1.94.0. - See [here](https://docs.victoriametrics.com/enterprise) - properties: - forceOffline: - description: Enforce offline verification of the license key. - type: boolean - key: - description: |- - Enterprise license key. This flag is available only in [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise). - To request a trial license, [go to](https://victoriametrics.com/products/enterprise/trial) - type: string - keyRef: - description: KeyRef is reference to secret with license key for - enterprise features. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - reloadInterval: - description: Interval to be used for checking for license key - changes. Note that this is only applicable when using KeyRef. - type: string - type: object - livenessProbe: - description: LivenessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - logFormat: - description: LogFormat for VMSingle to be configured with. - enum: - - default - - json - type: string - logLevel: - description: LogLevel for victoria metrics single to be configured - with. - enum: - - INFO - - WARN - - ERROR - - FATAL - - PANIC - type: string - managedMetadata: - description: |- - ManagedMetadata defines metadata that will be added to the all objects - created by operator for the given CustomResource - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - type: object - minReadySeconds: - description: |- - MinReadySeconds defines a minimum number of seconds to wait before starting update next pod - if previous in healthy state - Has no effect for VLogs and VMSingle - format: int32 - type: integer - nodeSelector: - additionalProperties: - type: string - description: NodeSelector Define which Nodes the Pods are scheduled - on. - type: object - paused: - description: |- - Paused If set to true all actions on the underlying managed objects are not - going to be performed, except for delete actions. - type: boolean - podMetadata: - description: PodMetadata configures Labels and Annotations which are - propagated to the VMSingle pods. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - port: - description: Port listen address - type: string - priorityClassName: - description: PriorityClassName class assigned to the Pods - type: string - readinessGates: - description: ReadinessGates defines pod readiness gates - items: - description: PodReadinessGate contains the reference to a pod condition - properties: - conditionType: - description: ConditionType refers to a condition in the pod's - condition list with matching type. - type: string - required: - - conditionType - type: object - type: array - readinessProbe: - description: ReadinessProbe that will be added CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - removePvcAfterDelete: - description: |- - RemovePvcAfterDelete - if true, controller adds ownership to pvc - and after VMSingle object deletion - pvc will be garbage collected - by controller manager - type: boolean - replicaCount: - description: ReplicaCount is the expected size of the Application. - format: int32 - type: integer - resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - retentionPeriod: - description: |- - RetentionPeriod for the stored metrics - Note VictoriaMetrics has data/ and indexdb/ folders - metrics from data/ removed eventually as soon as partition leaves retention period - reverse index data at indexdb rotates once at the half of configured [retention period](https://docs.victoriametrics.com/Single-server-VictoriaMetrics/#retention) - type: string - revisionHistoryLimitCount: - description: |- - The number of old ReplicaSets to retain to allow rollback in deployment or - maximum number of revisions that will be maintained in the Deployment revision history. - Has no effect at StatefulSets - Defaults to 10. - format: int32 - type: integer - runtimeClassName: - description: |- - RuntimeClassName - defines runtime class for kubernetes pod. - https://kubernetes.io/docs/concepts/containers/runtime-class/ - type: string - schedulerName: - description: SchedulerName - defines kubernetes scheduler name - type: string - secrets: - description: |- - Secrets is a list of Secrets in the same namespace as the Application - object, which shall be mounted into the Application container - at /etc/vm/secrets/SECRET_NAME folder - items: - type: string - type: array - securityContext: - description: |- - SecurityContext holds pod-level security attributes and common container settings. - This defaults to the default PodSecurityContext. - type: object - x-kubernetes-preserve-unknown-fields: true - serviceAccountName: - description: ServiceAccountName is the name of the ServiceAccount - to use to run the pods - type: string - serviceScrapeSpec: - description: ServiceScrapeSpec that will be added to vmsingle VMServiceScrape - spec - required: - - endpoints - type: object - x-kubernetes-preserve-unknown-fields: true - serviceSpec: - description: ServiceSpec that will be added to vmsingle service spec - properties: - metadata: - description: EmbeddedObjectMetadata defines objectMeta for additional - service. - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - spec: - description: |- - ServiceSpec describes the attributes that a user creates on a service. - More info: https://kubernetes.io/docs/concepts/services-networking/service/ - type: object - x-kubernetes-preserve-unknown-fields: true - useAsDefault: - description: |- - UseAsDefault applies changes from given service definition to the main object Service - Changing from headless service to clusterIP or loadbalancer may break cross-component communication - type: boolean - required: - - spec - type: object - startupProbe: - description: StartupProbe that will be added to CRD pod - type: object - x-kubernetes-preserve-unknown-fields: true - storage: - description: |- - Storage is the definition of how storage will be used by the VMSingle - by default it`s empty dir - this option is ignored if storageDataPath is set - properties: - accessModes: - description: |- - accessModes contains the desired access modes the volume should have. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 - items: - type: string - type: array - x-kubernetes-list-type: atomic - dataSource: - description: |- - dataSource field can be used to specify either: - * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) - * An existing PVC (PersistentVolumeClaim) - If the provisioner or an external controller can support the specified data source, - it will create a new volume based on the contents of the specified data source. - When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, - and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. - If the namespace is specified, then dataSourceRef will not be copied to dataSource. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - required: - - kind - - name - type: object - x-kubernetes-map-type: atomic - dataSourceRef: - description: |- - dataSourceRef specifies the object from which to populate the volume with data, if a non-empty - volume is desired. This may be any object from a non-empty API group (non - core object) or a PersistentVolumeClaim object. - When this field is specified, volume binding will only succeed if the type of - the specified object matches some installed volume populator or dynamic - provisioner. - This field will replace the functionality of the dataSource field and as such - if both fields are non-empty, they must have the same value. For backwards - compatibility, when namespace isn't specified in dataSourceRef, - both fields (dataSource and dataSourceRef) will be set to the same - value automatically if one of them is empty and the other is non-empty. - When namespace is specified in dataSourceRef, - dataSource isn't set to the same value and must be empty. - There are three important differences between dataSource and dataSourceRef: - * While dataSource only allows two specific types of objects, dataSourceRef - allows any non-core object, as well as PersistentVolumeClaim objects. - * While dataSource ignores disallowed values (dropping them), dataSourceRef - preserves all values, and generates an error if a disallowed value is - specified. - * While dataSource only allows local objects, dataSourceRef allows objects - in any namespaces. - (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. - (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - properties: - apiGroup: - description: |- - APIGroup is the group for the resource being referenced. - If APIGroup is not specified, the specified Kind must be in the core API group. - For any other third-party types, APIGroup is required. - type: string - kind: - description: Kind is the type of resource being referenced - type: string - name: - description: Name is the name of resource being referenced - type: string - namespace: - description: |- - Namespace is the namespace of resource being referenced - Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. - (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. - type: string - required: - - kind - - name - type: object - resources: - description: |- - resources represents the minimum resources the volume should have. - If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements - that are lower than previous value but must still be higher than capacity recorded in the - status field of the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources - properties: - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - selector: - description: selector is a label query over volumes to consider - for binding. - 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 - storageClassName: - description: |- - storageClassName is the name of the StorageClass required by the claim. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 - type: string - volumeAttributesClassName: - description: |- - volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. - If specified, the CSI driver will create or update the volume with the attributes defined - in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, - it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass - will be applied to the claim but it's not allowed to reset this field to empty string once it is set. - If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass - will be set by the persistentvolume controller if it exists. - If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be - set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource - exists. - More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). - type: string - volumeMode: - description: |- - volumeMode defines what type of volume is required by the claim. - Value of Filesystem is implied when not included in claim spec. - type: string - volumeName: - description: volumeName is the binding reference to the PersistentVolume - backing this claim. - type: string - type: object - storageDataPath: - description: |- - StorageDataPath disables spec.storage option and overrides arg for victoria-metrics binary --storageDataPath, - its users responsibility to mount proper device into given path. - It requires to provide spec.volumes and spec.volumeMounts with at least 1 value - type: string - storageMetadata: - description: StorageMeta defines annotations and labels attached to - PVC for given vmsingle CR - properties: - annotations: - additionalProperties: - type: string - description: |- - Annotations is an unstructured key value map stored with a resource that may be - set by external tools to store and retrieve arbitrary metadata. They are not - queryable and should be preserved when modifying objects. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations - type: object - labels: - additionalProperties: - type: string - description: |- - Labels Map of string keys and values that can be used to organize and categorize - (scope and select) objects. May match selectors of replication controllers - and services. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels - type: object - name: - description: |- - Name must be unique within a namespace. Is required when creating resources, although - some resources may allow a client to request the generation of an appropriate name - automatically. Name is primarily intended for creation idempotence and configuration - definition. - Cannot be updated. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names - type: string - type: object - streamAggrConfig: - description: StreamAggrConfig defines stream aggregation configuration - for VMSingle - properties: - configmap: - description: ConfigMap with stream aggregation rules - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - dedupInterval: - description: Allows setting different de-duplication intervals - per each configured remote storage - type: string - dropInput: - description: Allow drop all the input samples after the aggregation - type: boolean - dropInputLabels: - description: labels to drop from samples for aggregator before - stream de-duplication and aggregation - items: - type: string - type: array - enableWindows: - description: EnableWindows enables aggregating data in separate - windows ( available from v0.54.0). - type: boolean - ignoreFirstIntervals: - description: IgnoreFirstIntervals instructs to ignore first interval - type: integer - ignoreOldSamples: - description: IgnoreOldSamples instructs to ignore samples with - old timestamps outside the current aggregation interval. - type: boolean - keepInput: - description: Allows writing both raw and aggregate data - type: boolean - rules: - description: Stream aggregation rules - items: - description: StreamAggrRule defines the rule in stream aggregation - config - properties: - by: - description: |- - By is an optional list of labels for grouping input series. - - See also Without. - - If neither By nor Without are set, then the Outputs are calculated - individually per each input time series. - items: - type: string - type: array - dedup_interval: - description: DedupInterval is an optional interval for deduplication. - type: string - drop_input_labels: - description: |- - DropInputLabels is an optional list with labels, which must be dropped before further processing of input samples. - - Labels are dropped before de-duplication and aggregation. - items: - type: string - type: array - enable_windows: - description: EnableWindows enables aggregating data in separate - windows - type: boolean - flush_on_shutdown: - description: |- - FlushOnShutdown defines whether to flush the aggregation state on process termination - or config reload. Is `false` by default. - It is not recommended changing this setting, unless unfinished aggregations states - are preferred to missing data points. - type: boolean - ignore_first_intervals: - type: integer - ignore_old_samples: - description: IgnoreOldSamples instructs to ignore samples - with old timestamps outside the current aggregation interval. - type: boolean - input_relabel_configs: - description: |- - InputRelabelConfigs is an optional relabeling rules, which are applied on the input - before aggregation. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. - Default is 'replace' - type: string - if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for - `action: graphite`' - type: object - match: - description: 'Match is used together with Labels for - `action: graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source - label values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated - source label values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - interval: - description: Interval is the interval between aggregations. - type: string - keep_metric_names: - description: KeepMetricNames instructs to leave metric names - as is for the output time series without adding any suffix. - type: boolean - match: - description: |- - Match is a label selector (or list of label selectors) for filtering time series for the given selector. - - If the match isn't set, then all the input time series are processed. - x-kubernetes-preserve-unknown-fields: true - no_align_flush_to_interval: - description: |- - NoAlignFlushToInterval disables aligning of flushes to multiples of Interval. - By default flushes are aligned to Interval. - type: boolean - output_relabel_configs: - description: |- - OutputRelabelConfigs is an optional relabeling rules, which are applied - on the aggregated output before being sent to remote storage. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. - Default is 'replace' - type: string - if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for - `action: graphite`' - type: object - match: - description: 'Match is used together with Labels for - `action: graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source - label values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated - source label values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - outputs: - description: |- - Outputs is a list of output aggregate functions to produce. - - The following names are allowed: - - - total - aggregates input counters - - increase - counts the increase over input counters - - count_series - counts the input series - - count_samples - counts the input samples - - sum_samples - sums the input samples - - last - the last biggest sample value - - min - the minimum sample value - - max - the maximum sample value - - avg - the average value across all the samples - - stddev - standard deviation across all the samples - - stdvar - standard variance across all the samples - - histogram_bucket - creates VictoriaMetrics histogram for input samples - - quantiles(phi1, ..., phiN) - quantiles' estimation for phi in the range [0..1] - - The output time series will have the following names: - - input_name:aggr__ - items: - type: string - type: array - staleness_interval: - description: |- - Staleness interval is interval after which the series state will be reset if no samples have been sent during it. - The parameter is only relevant for outputs: total, total_prometheus, increase, increase_prometheus and histogram_bucket. - type: string - without: - description: |- - Without is an optional list of labels, which must be excluded when grouping input series. - - See also By. - - If neither By nor Without are set, then the Outputs are calculated - individually per each input time series. - items: - type: string - type: array - required: - - interval - - outputs - type: object - type: array - type: object - terminationGracePeriodSeconds: - description: TerminationGracePeriodSeconds period for container graceful - termination - format: int64 - type: integer - tolerations: - description: Tolerations If specified, the pod's tolerations. - items: - description: |- - The pod this Toleration is attached to tolerates any taint that matches - the triple using the matching operator . - properties: - effect: - description: |- - Effect indicates the taint effect to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. - type: string - key: - description: |- - Key is the taint key that the toleration applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; this combination means to match all values and all keys. - type: string - operator: - description: |- - Operator represents a key's relationship to the value. - Valid operators are Exists and Equal. Defaults to Equal. - Exists is equivalent to wildcard for value, so that a pod can - tolerate all taints of a particular category. - type: string - tolerationSeconds: - description: |- - TolerationSeconds represents the period of time the toleration (which must be - of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint forever (do not evict). Zero and - negative values will be treated as 0 (evict immediately) by the system. - format: int64 - type: integer - value: - description: |- - Value is the taint value the toleration matches to. - If the operator is Exists, the value should be empty, otherwise just a regular string. - type: string - type: object - type: array - topologySpreadConstraints: - description: |- - TopologySpreadConstraints embedded kubernetes pod configuration option, - controls how pods are spread across your cluster among failure-domains - such as regions, zones, nodes, and other user-defined topology domains - https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ - items: - description: TopologySpreadConstraint specifies how to spread matching - pods among the given topology. - required: - - maxSkew - - topologyKey - - whenUnsatisfiable - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - useDefaultResources: - description: |- - UseDefaultResources controls resource settings - By default, operator sets built-in resource requirements - type: boolean - useStrictSecurity: - description: |- - UseStrictSecurity enables strict security mode for component - it restricts disk writes access - uses non-root user out of the box - drops not needed security permissions - type: boolean - vmBackup: - description: VMBackup configuration for backup - properties: - acceptEULA: - description: |- - AcceptEULA accepts enterprise feature usage, must be set to true. - otherwise backupmanager cannot be added to single/cluster version. - https://victoriametrics.com/legal/esa/ - type: boolean - concurrency: - description: Defines number of concurrent workers. Higher concurrency - may reduce backup duration (default 10) - format: int32 - type: integer - credentialsSecret: - description: |- - CredentialsSecret is secret in the same namespace for access to remote storage - The secret is mounted into /etc/vm/creds. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - customS3Endpoint: - description: Custom S3 endpoint for use with S3-compatible storages - (e.g. MinIO). S3 is used if not set - type: string - destination: - description: Defines destination for backup - type: string - destinationDisableSuffixAdd: - description: |- - DestinationDisableSuffixAdd - disables suffix adding for cluster version backups - each vmstorage backup must have unique backup folder - so operator adds POD_NAME as suffix for backup destination folder. - type: boolean - disableDaily: - description: Defines if daily backups disabled (default false) - type: boolean - disableHourly: - description: Defines if hourly backups disabled (default false) - type: boolean - disableMonthly: - description: Defines if monthly backups disabled (default false) - type: boolean - disableWeekly: - description: Defines if weekly backups disabled (default false) - type: boolean - extraArgs: - additionalProperties: - type: string - description: extra args like maxBytesPerSecond default 0 - type: object - extraEnvs: - items: - description: EnvVar represents an environment variable present - in a Container. - properties: - name: - description: Name of the environment variable. Must be a - C_IDENTIFIER. - type: string - value: - description: |- - Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in the container and - any service environment variables. If a variable cannot be resolved, - the reference in the input string will be unchanged. Double $$ are reduced - to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless of whether the variable - exists or not. - Defaults to "". - type: string - valueFrom: - description: Source for the environment variable's value. - Cannot be used if value is not empty. - properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - fieldRef: - description: |- - Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, - spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the - specified API version. - type: string - required: - - fieldPath - type: object - x-kubernetes-map-type: atomic - resourceFieldRef: - description: |- - Selects a resource of the container: only resources limits and requests - (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the - exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - x-kubernetes-map-type: atomic - secretKeyRef: - description: Selects a key of a secret in the pod's - namespace - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - required: - - name - type: object - type: array - extraEnvsFrom: - description: |- - ExtraEnvsFrom defines source of env variables for the application container - could either be secret or configmap - items: - description: EnvFromSource represents the source of a set of - ConfigMaps - properties: - configMapRef: - description: The ConfigMap to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap must be defined - type: boolean - 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. - type: string - secretRef: - description: The Secret to select from - properties: - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret must be defined - type: boolean - type: object - x-kubernetes-map-type: atomic - type: object - type: array - image: - description: Image - docker image settings for VMBackuper - properties: - pullPolicy: - description: PullPolicy describes how to pull docker image - type: string - repository: - description: Repository contains name of docker image + it's - repository if needed - type: string - tag: - description: Tag contains desired docker image version - type: string - type: object - logFormat: - description: |- - LogFormat for VMBackup to be configured with. - default or json - enum: - - default - - json - type: string - logLevel: - description: LogLevel for VMBackup to be configured with. - enum: - - INFO - - WARN - - ERROR - - FATAL - - PANIC - type: string - port: - description: Port for health check connections - type: string - resources: - description: |- - Resources container resource request and limits, https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - if not defined default resources from operator config will be used - properties: - claims: - description: |- - Claims lists the names of resources, defined in spec.resourceClaims, - that are used by this container. - - This is an alpha field and requires enabling the - DynamicResourceAllocation feature gate. - - This field is immutable. It can only be set for containers. - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: |- - Name must match the name of one entry in pod.spec.resourceClaims of - the Pod where this field is used. It makes that resource available - inside a container. - type: string - request: - description: |- - Request is the name chosen for a request in the referenced claim. - If empty, everything from the claim is made available, otherwise - only the result of this request. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - limits: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Limits describes the maximum amount of compute resources allowed. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - requests: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: |- - Requests describes the minimum amount of compute resources required. - If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, - otherwise to an implementation-defined value. Requests cannot exceed Limits. - More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - type: object - type: object - restore: - description: |- - Restore Allows to enable restore options for pod - Read [more](https://docs.victoriametrics.com/vmbackupmanager#restore-commands) - properties: - onStart: - description: OnStart defines configuration for restore on - pod start - properties: - enabled: - description: Enabled defines if restore on start enabled - type: boolean - type: object - type: object - snapshotCreateURL: - description: SnapshotCreateURL overwrites url for snapshot create - type: string - snapshotDeleteURL: - description: SnapShotDeleteURL overwrites url for snapshot delete - type: string - volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment definition. - VolumeMounts specified will be appended to other VolumeMounts in the vmbackupmanager container, - that are generated as a result of StorageSpec objects. - items: - description: VolumeMount describes a mounting of a Volume within - a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - type: object - volumeMounts: - description: |- - VolumeMounts allows configuration of additional VolumeMounts on the output Deployment/StatefulSet definition. - VolumeMounts specified will be appended to other VolumeMounts in the Application container - items: - description: VolumeMount describes a mounting of a Volume within - a container. - properties: - mountPath: - description: |- - Path within the container at which the volume should be mounted. Must - not contain ':'. - type: string - mountPropagation: - description: |- - mountPropagation determines how mounts are propagated from the host - to container and the other way around. - When not set, MountPropagationNone is used. - This field is beta in 1.10. - When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified - (which defaults to None). - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: |- - Mounted read-only if true, read-write otherwise (false or unspecified). - Defaults to false. - type: boolean - recursiveReadOnly: - description: |- - RecursiveReadOnly specifies whether read-only mounts should be handled - recursively. - - If ReadOnly is false, this field has no meaning and must be unspecified. - - If ReadOnly is true, and this field is set to Disabled, the mount is not made - recursively read-only. If this field is set to IfPossible, the mount is made - recursively read-only, if it is supported by the container runtime. If this - field is set to Enabled, the mount is made recursively read-only if it is - supported by the container runtime, otherwise the pod will not be started and - an error will be generated to indicate the reason. - - If this field is set to IfPossible or Enabled, MountPropagation must be set to - None (or be unspecified, which defaults to None). - - If this field is not specified, it is treated as an equivalent of Disabled. - type: string - subPath: - description: |- - Path within the volume from which the container's volume should be mounted. - Defaults to "" (volume's root). - type: string - subPathExpr: - description: |- - Expanded path within the volume from which the container's volume should be mounted. - Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. - Defaults to "" (volume's root). - SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - volumes: - description: |- - Volumes allows configuration of additional volumes on the output Deployment/StatefulSet definition. - Volumes specified will be appended to other volumes that are generated. - / +optional - items: - description: Volume represents a named volume in a pod that may - be accessed by any container in the pod. - required: - - name - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - required: - - retentionPeriod type: object + x-kubernetes-preserve-unknown-fields: true status: - description: VMSingleStatus defines the observed state of VMSingle properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -30239,20 +1862,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason - type: string - singleStatus: - description: LegacyStatus is deprecated and will be removed at v0.52.0 - version type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -30265,7 +1879,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmstaticscrapes.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -30289,855 +1903,47 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMStaticScrape defines static targets configuration for scraping. 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: VMStaticScrapeSpec defines the desired state of VMStaticScrape. - properties: - jobName: - description: JobName name of job. - type: string - sampleLimit: - description: SampleLimit defines per-scrape limit on number of scraped - samples that will be accepted. - format: int64 - type: integer - seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 - type: integer - targetEndpoints: - description: A list of target endpoints to scrape metrics from. - items: - description: TargetEndpoint defines single static target endpoint. - properties: - authorization: - description: Authorization with http header Authorization - properties: - credentials: - description: Reference to the secret with value for authorization - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - credentialsFile: - description: File with value for authorization - type: string - type: - description: Type of authorization, default to bearer - type: string - type: object - basicAuth: - description: BasicAuth allow an endpoint to authenticate over - basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearerTokenFile: - description: File to read bearer token for scraping targets. - type: string - bearerTokenSecret: - description: |- - Secret to mount to read bearer token for scraping targets. The secret - needs to be in the same namespace as the scrape object and accessible by - the victoria-metrics operator. - nullable: true - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - follow_redirects: - description: FollowRedirects controls redirects for scraping. - type: boolean - honorLabels: - description: HonorLabels chooses the metric's labels on collisions - with target labels. - type: boolean - honorTimestamps: - description: HonorTimestamps controls whether vmagent respects - the timestamps present in scraped data. - type: boolean - interval: - description: Interval at which metrics should be scraped - type: string - labels: - additionalProperties: - type: string - description: Labels static labels for targets. - type: object - max_scrape_size: - description: MaxScrapeSize defines a maximum size of scraped - data for a job - type: string - metricRelabelConfigs: - description: MetricRelabelConfigs to apply to samples after - scrapping. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. - Default is 'replace' - type: string - if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source - label values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source - label values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - oauth2: - description: OAuth2 defines auth configuration - properties: - client_id: - description: The secret or configmap containing the OAuth2 - client id - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - client_secret: - description: The secret containing the OAuth2 client secret - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - client_secret_file: - description: ClientSecretFile defines path for client secret - file. - type: string - endpoint_params: - additionalProperties: - type: string - description: Parameters to append to the token URL - type: object - proxy_url: - description: |- - The proxy URL for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - type: string - scopes: - description: OAuth2 scopes used for the token request - items: - type: string - type: array - tls_config: - description: |- - TLSConfig for token_url connection - ( available from v0.55.0). - Is only supported by Scrape objects family - x-kubernetes-preserve-unknown-fields: true - token_url: - description: The URL to fetch the token from - minLength: 1 - type: string - required: - - client_id - - token_url - type: object - params: - additionalProperties: - items: - type: string - type: array - description: Optional HTTP URL parameters - type: object - path: - description: HTTP path to scrape for metrics. - type: string - proxyURL: - description: ProxyURL eg http://proxyserver:2195 Directs scrapes - to proxy through this endpoint. - type: string - relabelConfigs: - description: RelabelConfigs to apply to samples during service - discovery. - items: - description: |- - RelabelConfig allows dynamic rewriting of the label set - More info: https://docs.victoriametrics.com/#relabeling - properties: - action: - description: Action to perform based on regex matching. - Default is 'replace' - type: string - if: - description: 'If represents metricsQL match expression - (or list of expressions): ''{__name__=~"foo_.*"}''' - x-kubernetes-preserve-unknown-fields: true - labels: - additionalProperties: - type: string - description: 'Labels is used together with Match for `action: - graphite`' - type: object - match: - description: 'Match is used together with Labels for `action: - graphite`' - type: string - modulus: - description: Modulus to take of the hash of the source - label values. - format: int64 - type: integer - regex: - description: |- - Regular expression against which the extracted value is matched. Default is '(.*)' - victoriaMetrics supports multiline regex joined with | - https://docs.victoriametrics.com/vmagent/#relabeling-enhancements - x-kubernetes-preserve-unknown-fields: true - replacement: - description: |- - Replacement value against which a regex replace is performed if the - regular expression matches. Regex capture groups are available. Default is '$1' - type: string - separator: - description: Separator placed between concatenated source - label values. default is ';'. - type: string - source_labels: - description: |- - UnderScoreSourceLabels - additional form of source labels source_labels - for compatibility with original relabel config. - if set both sourceLabels and source_labels, sourceLabels has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - items: - type: string - type: array - sourceLabels: - description: |- - The source labels select values from existing labels. Their content is concatenated - using the configured separator and matched against the configured regular expression - for the replace, keep, and drop actions. - items: - type: string - type: array - target_label: - description: |- - UnderScoreTargetLabel - additional form of target label - target_label - for compatibility with original relabel config. - if set both targetLabel and target_label, targetLabel has priority. - for details https://github.com/VictoriaMetrics/operator/issues/131 - type: string - targetLabel: - description: |- - Label to which the resulting value is written in a replace action. - It is mandatory for replace actions. Regex capture groups are available. - type: string - type: object - type: array - sampleLimit: - description: SampleLimit defines per-scrape limit on number - of scraped samples that will be accepted. - format: int64 - type: integer - scheme: - description: HTTP scheme to use for scraping. - enum: - - http - - https - - HTTPS - - HTTP - type: string - scrape_interval: - description: |- - ScrapeInterval is the same as Interval and has priority over it. - one of scrape_interval or interval can be used - type: string - scrapeTimeout: - description: Timeout after which the scrape is ended - type: string - seriesLimit: - description: |- - SeriesLimit defines per-scrape limit on number of unique time series - a single target can expose during all the scrapes on the time window of 24h. - format: int64 - type: integer - targets: - description: Targets static targets addresses in form of ["192.122.55.55:9100","some-name:9100"]. - items: - type: string - minItems: 1 - type: array - tlsConfig: - description: TLSConfig configuration to use when scraping the - endpoint - properties: - ca: - description: Struct containing the CA cert to use for the - targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container to use - for the targets. - type: string - cert: - description: Struct containing the client cert file for - the targets. - properties: - configMap: - description: ConfigMap containing data to use for the - targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container - for the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container - for the targets. - type: string - keySecret: - description: Secret containing the client key file for the - targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - vm_scrape_params: - description: VMScrapeParams defines VictoriaMetrics specific - scrape parameters - properties: - disable_compression: - description: DisableCompression - type: boolean - disable_keep_alive: - description: |- - disable_keepalive allows disabling HTTP keep-alive when scraping targets. - By default, HTTP keep-alive is enabled, so TCP connections to scrape targets - could be reused. - See https://docs.victoriametrics.com/vmagent#scrape_config-enhancements - type: boolean - headers: - description: |- - Headers allows sending custom headers to scrape targets - must be in of semicolon separated header with it's value - eg: - headerName: headerValue - vmagent supports since 1.79.0 version - items: - type: string - type: array - no_stale_markers: - type: boolean - proxy_client_config: - description: |- - ProxyClientConfig configures proxy auth settings for scraping - See feature description https://docs.victoriametrics.com/vmagent#scraping-targets-via-a-proxy - properties: - basic_auth: - description: BasicAuth allow an endpoint to authenticate - over basic authentication - properties: - password: - description: |- - Password defines reference for secret with password value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - password_file: - description: |- - PasswordFile defines path to password file at disk - must be pre-mounted - type: string - username: - description: |- - Username defines reference for secret with username value - The secret needs to be in the same namespace as scrape object - properties: - key: - description: The key of the secret to select - from. Must be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - bearer_token: - description: SecretKeySelector selects a key of a Secret. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - bearer_token_file: - type: string - tls_config: - x-kubernetes-preserve-unknown-fields: true - type: object - scrape_align_interval: - type: string - scrape_offset: - type: string - stream_parse: - type: boolean - type: object - required: - - targets - type: object - type: array required: - targetEndpoints type: object + x-kubernetes-preserve-unknown-fields: true status: - description: ScrapeObjectStatus defines the observed state of ScrapeObjects properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -31152,16 +1958,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object @@ -31174,7 +1975,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.17.2 + controller-gen.kubebuilder.io/version: v0.20.0 name: vmusers.operator.victoriametrics.com spec: group: operator.victoriametrics.com @@ -31198,582 +1999,243 @@ spec: name: v1beta1 schema: openAPIV3Schema: - description: VMUser is the Schema for the vmusers API 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: VMUserSpec defines the desired state of VMUser - properties: - bearerToken: - description: BearerToken Authorization header value for accessing - protected endpoint. - type: string - default_url: - description: |- - DefaultURLs backend url for non-matching paths filter - usually used for default backend with error message - items: - type: string - type: array - disable_secret_creation: - description: DisableSecretCreation skips related secret creation for - vmuser - type: boolean - discover_backend_ips: - description: DiscoverBackendIPs instructs discovering URLPrefix backend - IPs via DNS. - type: boolean - drop_src_path_prefix_parts: - description: |- - DropSrcPathPrefixParts is the number of `/`-delimited request path prefix parts to drop before proxying the request to backend. - See [here](https://docs.victoriametrics.com/vmauth#dropping-request-path-prefix) for more details. - type: integer - dump_request_on_errors: - description: |- - DumpRequestOnErrors instructs vmauth to return detailed request params to the client - if routing rules don't allow to forward request to the backends. - Useful for debugging `src_hosts` and `src_headers` based routing rules - - available since v1.107.0 vmauth version - type: boolean - generatePassword: - description: |- - GeneratePassword instructs operator to generate password for user - if spec.password if empty. - type: boolean - headers: - description: |- - Headers represent additional http headers, that vmauth uses - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.68.0 version of vmauth - items: - type: string - type: array - ip_filters: - description: |- - IPFilters defines per target src ip filters - supported only with enterprise version of [vmauth](https://docs.victoriametrics.com/vmauth/#ip-filters) - properties: - allow_list: - items: - type: string - type: array - deny_list: - items: - type: string - type: array - type: object - load_balancing_policy: - description: |- - LoadBalancingPolicy defines load balancing policy to use for backend urls. - Supported policies: least_loaded, first_available. - See [here](https://docs.victoriametrics.com/vmauth#load-balancing) for more details (default "least_loaded") - enum: - - least_loaded - - first_available - type: string - max_concurrent_requests: - description: |- - MaxConcurrentRequests defines max concurrent requests per user - 300 is default value for vmauth - type: integer - metric_labels: - additionalProperties: - type: string - description: MetricLabels - additional labels for metrics exported - by vmauth for given user. - type: object - name: - description: Name of the VMUser object. - type: string - password: - description: Password basic auth password for accessing protected - endpoint. - type: string - passwordRef: - description: PasswordRef allows fetching password from user-create - secret by its name and key. - properties: - key: - description: The key of the secret to select from. Must be a - valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - response_headers: - description: |- - ResponseHeaders represent additional http headers, that vmauth adds for request response - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.93.0 version of vmauth - items: - type: string - type: array - retry_status_codes: - description: |- - RetryStatusCodes defines http status codes in numeric format for request retries - e.g. [429,503] - items: - type: integer - type: array - targetRefs: - description: TargetRefs - reference to endpoints, which user may access. - items: - description: |- - TargetRef describes target for user traffic forwarding. - one of target types can be chosen: - crd or static per targetRef. - user can define multiple targetRefs with different ref Types. - properties: - crd: - description: |- - CRD describes exist operator's CRD object, - operator generates access url based on CRD params. - properties: - kind: - description: |- - Kind one of: - VMAgent,VMAlert, VMSingle, VMCluster/vmselect, VMCluster/vmstorage,VMCluster/vminsert or VMAlertManager - enum: - - VMAgent - - VMAlert - - VMSingle - - VLogs - - VMAlertManager - - VMAlertmanager - - VMCluster/vmselect - - VMCluster/vmstorage - - VMCluster/vminsert - type: string - name: - description: Name target CRD object name - type: string - namespace: - description: Namespace target CRD object namespace. - type: string - required: - - kind - - name - - namespace - type: object - discover_backend_ips: - description: DiscoverBackendIPs instructs discovering URLPrefix - backend IPs via DNS. - type: boolean - drop_src_path_prefix_parts: - description: |- - DropSrcPathPrefixParts is the number of `/`-delimited request path prefix parts to drop before proxying the request to backend. - See [here](https://docs.victoriametrics.com/vmauth#dropping-request-path-prefix) for more details. - type: integer - headers: - description: |- - RequestHeaders represent additional http headers, that vmauth uses - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.68.0 version of vmauth - items: - type: string - type: array - hosts: - items: - type: string - type: array - load_balancing_policy: - description: |- - LoadBalancingPolicy defines load balancing policy to use for backend urls. - Supported policies: least_loaded, first_available. - See [here](https://docs.victoriametrics.com/vmauth#load-balancing) for more details (default "least_loaded") - enum: - - least_loaded - - first_available - type: string - paths: - description: Paths - matched path to route. - items: - type: string - type: array - response_headers: - description: |- - ResponseHeaders represent additional http headers, that vmauth adds for request response - in form of ["header_key: header_value"] - multiple values for header key: - ["header_key: value1,value2"] - it's available since 1.93.0 version of vmauth - items: - type: string - type: array - retry_status_codes: - description: |- - RetryStatusCodes defines http status codes in numeric format for request retries - Can be defined per target or at VMUser.spec level - e.g. [429,503] - items: - type: integer - type: array - src_headers: - description: SrcHeaders is an optional list of headers, which - must match request headers. - items: - type: string - type: array - src_query_args: - description: SrcQueryArgs is an optional list of query args, - which must match request URL query args. - items: - type: string - type: array - static: - description: |- - Static - user defined url for traffic forward, - for instance http://vmsingle:8429 - properties: - url: - description: URL http url for given staticRef. - type: string - urls: - description: URLs allows setting multiple urls for load-balancing - at vmauth-side. - items: - type: string - type: array - type: object - target_path_suffix: - description: |- - TargetPathSuffix allows to add some suffix to the target path - It allows to hide tenant configuration from user with crd as ref. - it also may contain any url encoded params. - type: string - targetRefBasicAuth: - description: TargetRefBasicAuth allow an target endpoint to - authenticate over basic authentication - properties: - password: - description: |- - The secret in the service scrape namespace that contains the password - for authentication. - It must be at them same namespace as CRD - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - username: - description: |- - The secret in the service scrape namespace that contains the username - for authentication. - It must be at them same namespace as CRD - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - required: - - password - - username - type: object - type: object - type: array - tlsConfig: - description: TLSConfig defines tls configuration for the backend connection - properties: - ca: - description: Struct containing the CA cert to use for the targets. - properties: - configMap: - description: ConfigMap containing data to use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - caFile: - description: Path to the CA cert in the container to use for the - targets. - type: string - cert: - description: Struct containing the client cert file for the targets. - properties: - configMap: - description: ConfigMap containing data to use for the targets. - properties: - key: - description: The key to select. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the ConfigMap or its key - must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - secret: - description: Secret containing data to use for the targets. - properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must - be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - type: object - certFile: - description: Path to the client cert file in the container for - the targets. - type: string - insecureSkipVerify: - description: Disable target certificate validation. - type: boolean - keyFile: - description: Path to the client key file in the container for - the targets. - type: string - keySecret: - description: Secret containing the client key file for the targets. - properties: - key: - description: The key of the secret to select from. Must be - a valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be - defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - serverName: - description: Used to verify the hostname for the targets. - type: string - type: object - tokenRef: - description: TokenRef allows fetching token from user-created secrets - by its name and key. - properties: - key: - description: The key of the secret to select from. Must be a - valid secret key. - type: string - name: - default: "" - description: |- - Name of the referent. - This field is effectively required, but due to backwards compatibility is - allowed to be empty. Instances of this type with an empty value here are - almost certainly wrong. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - type: string - optional: - description: Specify whether the Secret or its key must be defined - type: boolean - required: - - key - type: object - x-kubernetes-map-type: atomic - username: - description: |- - UserName basic auth user name for accessing protected endpoint, - will be replaced with metadata.name of VMUser if omitted. - type: string required: - targetRefs type: object + x-kubernetes-preserve-unknown-fields: true + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + maxLength: 32768 + type: string + observedGeneration: + format: int64 + minimum: 0 + type: integer + reason: + maxLength: 1024 + minLength: 1 + type: string + status: + enum: + - "True" + - "False" + - Unknown + type: string + type: + maxLength: 316 + type: string + required: + - lastTransitionTime + - lastUpdateTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + format: int64 + type: integer + reason: + type: string + updateStatus: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.0 + name: vtclusters.operator.victoriametrics.com +spec: + group: operator.victoriametrics.com + names: + kind: VTCluster + listKind: VTClusterList + plural: vtclusters + singular: vtcluster + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: replicas of VTInsert + jsonPath: .spec.insert.replicaCount + name: Insert Count + type: string + - description: replicas of VTStorage + jsonPath: .spec.storage.replicaCount + name: Storage Count + type: string + - description: replicas of VTSelect + jsonPath: .spec.select.replicaCount + name: Select Count + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Current status of cluster + jsonPath: .status.updateStatus + name: Status + type: string + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + properties: + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + lastUpdateTime: + format: date-time + type: string + message: + maxLength: 32768 + type: string + observedGeneration: + format: int64 + minimum: 0 + type: integer + reason: + maxLength: 1024 + minLength: 1 + type: string + status: + enum: + - "True" + - "False" + - Unknown + type: string + type: + maxLength: 316 + type: string + required: + - lastTransitionTime + - lastUpdateTime + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + observedGeneration: + format: int64 + type: integer + reason: + type: string + updateStatus: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.0 + name: vtsingles.operator.victoriametrics.com +spec: + group: operator.victoriametrics.com + names: + kind: VTSingle + listKind: VTSingleList + plural: vtsingles + singular: vtsingle + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Current status of traces instance update process + jsonPath: .status.status + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + type: object + x-kubernetes-preserve-unknown-fields: true status: - description: VMUserStatus defines the observed state of VMUser properties: conditions: - description: 'Known .status.conditions.type are: "Available", "Progressing", - and "Degraded"' items: - description: Condition defines status condition of the resource properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. format: date-time type: string lastUpdateTime: - description: |- - LastUpdateTime is the last time of given type update. - This value is used for status TTL update and removal 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 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 name.namespace.resource.victoriametrics.com/CamelCase. maxLength: 316 type: string required: @@ -31788,16 +2250,11 @@ spec: - type x-kubernetes-list-type: map observedGeneration: - description: |- - ObservedGeneration defines current generation picked by operator for the - reconcile format: int64 type: integer reason: - description: Reason defines human readable error reason type: string updateStatus: - description: UpdateStatus defines a status for update rollout type: string type: object type: object diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/NOTES.txt b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/NOTES.txt index 7fb3fbd9..41f39937 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/NOTES.txt +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/NOTES.txt @@ -1,5 +1,5 @@ {{ include "vm.name" . }} has been installed. Check its status by running: - kubectl --namespace {{ include "vm.namespace" . }} get pods -l "app.kubernetes.io/instance={{ $.Release.Name }}" + kubectl --namespace {{ include "vm.namespace" . }} get pods -l "app.kubernetes.io/name={{ include "vm.name" . }}" -l "app.kubernetes.io/instance={{ include "vm.release" . }}" Get more information on https://github.com/VictoriaMetrics/helm-charts/tree/master/charts/victoria-metrics-operator. See "Getting started guide for VM Operator" on https://docs.victoriametrics.com/guides/getting-started-with-vm-operator diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/_helpers.tpl b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/_helpers.tpl index d1215342..8abc83f6 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/_helpers.tpl +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/_helpers.tpl @@ -34,7 +34,7 @@ caCert: {{ index $secret.data "ca.crt" }} clientCert: {{ index $secret.data "tls.crt" }} clientKey: {{ index $secret.data "tls.key" }} {{- else -}} -{{- $altNames := default list -}} +{{- $altNames := list -}} {{- $namePrefix := (printf "%s.%s" $fullname (include "vm.namespace" .)) -}} {{- $altNames = append $altNames $namePrefix -}} {{- $altNames = append $altNames (printf "%s.svc" $namePrefix) -}} diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/cleanup.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/cleanup.yaml index d6f4c58f..4776ee99 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/cleanup.yaml +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/cleanup.yaml @@ -1,7 +1,7 @@ -{{- if and .Values.crds.enabled .Values.crds.cleanup.enabled }} +{{- if .Values.crds.cleanup.enabled }} {{- $app := .Values.crds.cleanup }} {{- if empty ($app.image).tag }} - {{- $tag := (printf "%s.%s" .Capabilities.KubeVersion.Major .Capabilities.KubeVersion.Minor) | replace "+" "" -}} + {{- $tag := regexSplit "[+-]" .Capabilities.KubeVersion.Version -1 | first -}} {{- $_ := set $app.image "tag" $tag }} {{- else if not (kindIs "string" ($app.image).tag) }} {{- fail "`crd.cleanup.image.tag` is not string, most probably you need to enquote provided value" -}} @@ -33,9 +33,20 @@ spec: image: {{ include "vm.image" $ctx }} imagePullPolicy: {{ $app.image.pullPolicy }} resources: {{ toYaml $app.resources | nindent 12 }} + {{- if .Values.securityContext.enabled }} + securityContext: {{ include "vm.securityContext" (dict "securityContext" .Values.securityContext "helm" .) | nindent 12 }} + {{- end }} + {{- $names := list }} + {{- $crds := .Files.Get "crd.yaml" | splitList "---" }} + {{- range $crds }} + {{- $crd := . | fromYaml }} + {{- $names = append $names $crd.spec.names.singular }} + {{- end }} + command: + - kubectl args: - delete - - {{ (keys .Values.admissionWebhooks.enabledCRDValidation) | sortAlpha | join "," }} + - {{ $names | sortAlpha | join "," }} - --all - --ignore-not-found=true restartPolicy: OnFailure diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/crb.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/crb.yaml index 78327074..9bf378ab 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/crb.yaml +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/crb.yaml @@ -21,7 +21,7 @@ roleRef: name: {{ $fullname }} apiGroup: rbac.authorization.k8s.io {{- end -}} -{{- if and .Values.crds.enabled .Values.crds.cleanup.enabled }} +{{- if .Values.crds.cleanup.enabled }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/crd.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/crd.yaml index d5bf4b77..d5cb31b6 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/crd.yaml +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/crd.yaml @@ -8,9 +8,8 @@ {{- if and (not .Values.crds.plain) .Values.crds.enabled }} {{- $files := .Files }} {{- $crds := $files.Get "crd.yaml" | splitList "---" }} - {{- $labels := (include "vm.labels" $ctx) | fromYaml -}} {{- $annotations := mergeOverwrite ((include "vm-operator.crds.annotations" .) | fromYaml) .Values.crds.annotations -}} - {{- $extra := dict "metadata" (dict "annotations" $annotations "labels" $labels) -}} + {{- $extra := dict "metadata" (dict "annotations" $annotations) -}} {{- range $crds }} {{- $crd := merge (fromYaml .) $extra }} {{- range $attrKey, $attrValue := $crd }} diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/pdb.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/pdb.yaml index 8abd9dea..9ec3c2c2 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/pdb.yaml +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/pdb.yaml @@ -18,6 +18,9 @@ spec: {{- with $pdb.maxUnavailable }} maxUnavailable: {{ . }} {{- end }} + {{- with $pdb.unhealthyPodEvictionPolicy }} + unhealthyPodEvictionPolicy: {{ . }} + {{- end }} selector: matchLabels: {{ include "vm.selectorLabels" $ctx | nindent 6 }} {{- end }} diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/role.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/role.yaml index cb658970..703c54e8 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/role.yaml +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/role.yaml @@ -1,10 +1,10 @@ -{{- $rules := default dict }} -{{- $fileContentsList := .Files.Get "crd.yaml" | splitList "---" }} +{{- $rules := dict }} +{{- $crds := .Files.Get "crd.yaml" | splitList "---" }} {{- $groups := dict }} -{{- range $fileContentsList }} - {{- $fileContents := . | fromYaml }} - {{- $group := $fileContents.spec.group }} - {{- $plural:= $fileContents.spec.names.plural }} +{{- range $crds }} + {{- $crd := . | fromYaml }} + {{- $group := $crd.spec.group }} + {{- $plural:= $crd.spec.names.plural }} {{- $resources := get $groups $group | default (list) }} {{- $resources = concat $resources (list $plural (printf "%s/finalizers" $plural) (printf "%s/status" $plural)) }} {{- $groups = set $groups $group $resources }} @@ -74,6 +74,7 @@ rules: - persistentvolumeclaims - persistentvolumeclaims/finalizers - pods + - pods/eviction - secrets - secrets/finalizers - services @@ -87,7 +88,6 @@ rules: resources: - configmaps/status - nodes - - nodes/proxy - nodes/metrics - namespaces verbs: @@ -160,6 +160,13 @@ rules: - ingresses/finalizers verbs: - "*" +- apiGroups: + - gateway.networking.k8s.io + resources: + - httproutes + - httproutes/finalizers + verbs: + - '*' - apiGroups: - apiextensions.k8s.io resources: @@ -179,7 +186,7 @@ rules: {{ toYaml . }} {{- end }} {{- end }} -{{- if and .Values.crds.enabled .Values.crds.cleanup.enabled }} +{{- if .Values.crds.cleanup.enabled }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/deployment.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/server.yaml similarity index 89% rename from packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/deployment.yaml rename to packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/server.yaml index b247f393..9d7fd7ed 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/deployment.yaml +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/server.yaml @@ -1,6 +1,10 @@ {{- $ctx := dict "helm" . "noEnterprise" true }} {{- $fullname := include "vm.plain.fullname" $ctx }} {{- $ns := include "vm.namespace" $ctx }} +{{- $env := dict -}} +{{- range .Values.env | default list -}} + {{- $_ := set $env .name .value -}} +{{- end -}} --- apiVersion: apps/v1 kind: Deployment @@ -14,9 +18,12 @@ metadata: annotations: {{ toYaml . | nindent 4 }} {{- end }} spec: - replicas: {{.Values.replicaCount }} + replicas: {{ .Values.replicaCount }} selector: matchLabels: {{ include "vm.selectorLabels" $ctx | nindent 6 }} + {{- with .Values.strategy }} + strategy: {{ toYaml . | nindent 4 }} + {{- end }} template: metadata: {{- with .Values.annotations }} @@ -33,6 +40,9 @@ spec: {{- if .Values.hostNetwork }} hostNetwork: true {{- end }} + {{- if .Values.shareProcessNamespace }} + shareProcessNamespace: true + {{- end }} {{- if or (.Values.serviceAccount).name (.Values.serviceAccount).create }} serviceAccountName: {{ (.Values.serviceAccount).name | default $fullname }} {{- end }} @@ -61,9 +71,15 @@ spec: fieldPath: metadata.name - name: OPERATOR_NAME value: {{ .Chart.Name }} - {{- if .Values.operator.useCustomConfigReloader }} - - name: VM_USECUSTOMCONFIGRELOADER - value: "true" + {{- with (((.Values).global).image).registry }} + - name: VM_CONTAINERREGISTRY + value: {{ quote . }} + {{- end -}} + {{- if not (empty (.Values.configReloader).image) }} + - name: VM_CONFIG_RELOADER_IMAGE + {{- $_ := set $ctx "appKey" (list "configReloader") }} + value: {{ include "vm.image" $ctx }} + {{- $_ := unset $ctx "appKey" }} {{- end }} {{- if .Values.operator.disable_prometheus_converter }} - name: VM_ENABLEDPROMETHEUSCONVERTER_PODMONITOR @@ -81,7 +97,7 @@ spec: value: "true" {{- end }} - name: VM_ENABLEDPROMETHEUSCONVERTEROWNERREFERENCES - value: {{.Values.operator.enable_converter_ownership | quote}} + value: {{ .Values.operator.enable_converter_ownership | quote}} args: - --zap-log-level={{ .Values.logLevel }} - --leader-elect diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/service.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/service.yaml index 842d444f..6efc329a 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/service.yaml +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/service.yaml @@ -14,6 +14,9 @@ metadata: {{- $_ := unset $ctx "extraLabels" }} name: {{ $fullname }} spec: + {{- with $service.trafficDistribution }} + trafficDistribution: {{ . }} + {{- end }} {{- with $service.clusterIP }} clusterIP: {{ . }} {{- end }} diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/service_account.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/serviceaccount.yaml similarity index 88% rename from packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/service_account.yaml rename to packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/serviceaccount.yaml index 59d26fba..73daf270 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/service_account.yaml +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/serviceaccount.yaml @@ -6,7 +6,7 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: {{ $sa.name | default $fullname }} + name: {{ tpl ($sa.name | default $fullname) $ctx }} namespace: {{ $ns }} {{- $_ := set $ctx "extraLabels" .Values.extraLabels }} labels: {{ include "vm.labels" $ctx | nindent 4 }} @@ -15,7 +15,7 @@ metadata: {{- end }} automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} {{- end }} -{{- if and .Values.crds.enabled .Values.crds.cleanup.enabled }} +{{- if .Values.crds.cleanup.enabled }} --- apiVersion: v1 kind: ServiceAccount diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/webhook.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/webhook.yaml index 2e027ab4..e38f7448 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/webhook.yaml +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/webhook.yaml @@ -1,36 +1,52 @@ -{{- if .Values.admissionWebhooks.enabled }} +{{- $webhooks := .Values.admissionWebhooks }} +{{- if $webhooks.enabled }} {{- $ctx := dict "helm" . "extraLabels" .Values.extraLabels }} {{- $tls := fromYaml (include "vm-operator.certs" $ctx) }} {{- $fullname := include "vm.plain.fullname" $ctx }} {{- $domain := ((.Values.global).cluster).dnsDomain }} {{- $ns := include "vm.namespace" $ctx }} -{{- $certManager := .Values.admissionWebhooks.certManager }} +{{- $certManager := $webhooks.certManager }} +{{- $files := .Files }} +{{- $crds := $files.Get "crd.yaml" | splitList "---" }} +{{- $disabledFor := $webhooks.disabledFor | default list }} --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: name: {{ $fullname }}-admission - {{- if $certManager.enabled }} + {{- if or $certManager.enabled $webhooks.annotations }} annotations: + {{- if $certManager.enabled }} certmanager.k8s.io/inject-ca-from: {{ printf "%s/%s-validation" $ns $fullname | quote }} cert-manager.io/inject-ca-from: {{ printf "%s/%s-validation" $ns $fullname | quote }} + {{- end }} + {{- with $certManager.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $webhooks.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} {{- end }} labels: {{ include "vm.labels" $ctx | nindent 4 }} webhooks: -{{- range $name, $enabled := .Values.admissionWebhooks.enabledCRDValidation }} -{{- if $enabled }} +{{- range $crds }} +{{- $crd := fromYaml . }} +{{- $name := $crd.spec.names.singular }} +{{- if not (has $name $disabledFor) }} +{{- range $version := $crd.spec.versions }} - clientConfig: service: namespace: {{ $ns }} name: {{ $fullname }} - path: /validate-operator-victoriametrics-com-v1beta1-{{ $name }} + path: /validate-operator-victoriametrics-com-{{ $version.name }}-{{ $crd.spec.names.singular }} port: {{ $.Values.service.webhookPort }} {{- if not $certManager.enabled }} caBundle: {{ $tls.caCert }} {{- end }} - failurePolicy: {{ $.Values.admissionWebhooks.policy }} - name: {{ $name }}.victoriametrics.com - admissionReviewVersions: ["v1", "v1beta1"] + failurePolicy: {{ $webhooks.policy }} + name: '{{ $crd.metadata.name }}' + admissionReviewVersions: + - v1 sideEffects: None objectSelector: matchExpressions: @@ -39,14 +55,15 @@ webhooks: values: [{{ include "vm.name" $ }}] rules: - apiGroups: - - operator.victoriametrics.com + - {{ $crd.spec.group }} apiVersions: - - v1beta1 + - {{ $version.name }} operations: - CREATE - UPDATE resources: - - {{ $name }}{{ ternary "" "s" (hasSuffix "s" $name) }} + - {{ $crd.spec.names.plural }} +{{- end }} {{- end }} {{- end }} {{- if $certManager.enabled }} @@ -78,6 +95,8 @@ spec: name: {{ $fullname }}-root commonName: {{ $certManager.ca.commonName }} isCA: true + privateKey: + rotationPolicy: Never --- apiVersion: cert-manager.io/v1 kind: Issuer diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/values.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/values.yaml index 64eddbf2..3a1027f2 100644 --- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/values.yaml +++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/values.yaml @@ -29,6 +29,12 @@ image: # -- Image pull policy pullPolicy: IfNotPresent +configReloader: + image: {} + # registry: "" + # repository: "" + # tag: "" + crds: # -- manages CRD creation. Disables CRD creation only in combination with `crds.plain: false` due to helm dependency conditions limitation enabled: true @@ -43,7 +49,7 @@ crds: enabled: false # -- Image configuration for CRD cleanup Job image: - repository: bitnami/kubectl + repository: rancher/kubectl # use image tag that matches k8s API version by default tag: "" pullPolicy: IfNotPresent @@ -55,6 +61,109 @@ crds: requests: cpu: "100m" memory: "56Mi" + upgrade: + # -- Enables CRD upgrade job + enabled: false + # -- Adds `--force-conflics` argument to kubectl + forceConflicts: false + busybox: + image: + repository: busybox + tag: latest + pullPolicy: IfNotPresent + kubectl: + image: + repository: rancher/kubectl + # use image tag that matches k8s API version by default + tag: "" + pullPolicy: IfNotPresent + + # -- Extra settings for CRD upgrade job + env: [] + + # -- Upgrade job resources. + resources: {} + # limits: + # cpu: 120m + # memory: 320Mi + # requests: + # cpu: 80m + # memory: 120Mi + + # -- Additional upgrade job volumes + extraVolumes: [] + + # -- Additional upgrade job volume mounts + extraVolumeMounts: [] + + # -- Pod's node selector. Details are [here](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) + nodeSelector: {} + + # -- Upgrade job pod affinity + affinity: {} + # nodeAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # nodeSelectorTerms: + # - matchExpressions: + # - key: kubernetes.io/e2e-az-name + # operator: In + # values: + # - e2e-az1 + # - e2e-az2 + + # -- Array of upgrade job tolerations object. Spec is [here](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/) + tolerations: [] + # - key: "key" + # operator: "Equal" + # value: "value" + # effect: "NoSchedule" + + # -- Upgrade job Pod Topology Spread Constraints. Spec is [here](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/) + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # whenUnsatisfiable: DoNotSchedule + # labelSelector: + # matchLabels: + # app.kubernetes.io/component: alertmanager + + # -- Labels to add to the upgrade job + labels: {} + + # -- Annotations to add to the upgrade job + annotations: {} + + # -- Labels to add to the upgrade job pod + podLabels: {} + + # -- Annotations to add to the upgrade job pod + podAnnotations: {} + + # -- Service account for upgrade CRD job to use. + serviceAccount: + create: true + name: "" + annotations: {} + labels: {} + automountServiceAccountToken: true + + # -- Container-specific security context configuration. Details are [here](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + + # -- Pod's security context. Details are [here](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) + podSecurityContext: + enabled: true + fsGroup: 65534 + runAsGroup: 65534 + runAsNonRoot: true + runAsUser: 65534 + seccompProfile: + type: RuntimeDefault # -- Number of operator replicas replicaCount: 1 @@ -119,9 +228,6 @@ operator: # -- Enables ownership reference for converted prometheus-operator objects, # it will remove corresponding victoria-metrics objects in case of deletion prometheus one. enable_converter_ownership: false - # -- Enables custom config-reloader, bundled with operator. - # It should reduce vmagent and vmauth config sync-time and make it predictable. - useCustomConfigReloader: false # -- By default, the operator will watch all the namespaces # If you want to override this behavior, specify the namespace. @@ -138,13 +244,15 @@ serviceAccount: automountServiceAccountToken: true service: + # -- Service traffic distribution. Details are [here](https://kubernetes.io/docs/concepts/services-networking/service/#traffic-distribution) + trafficDistribution: "" # -- Service annotations annotations: {} # -- Service labels labels: {} # -- Service ClusterIP clusterIP: "" - # -- Service external IPs. Check [here](https://kubernetes.io/docs/user-guide/services/#external-ips) for details + # -- Service external IPs. Check [here](https://kubernetes.io/docs/concepts/services-networking/service/#external-ips) for details externalIPs: "" # -- Service load balancer IP loadBalancerIP: "" @@ -168,8 +276,12 @@ service: # -- See `kubectl explain poddisruptionbudget.spec` for more or check [these docs](https://kubernetes.io/docs/tasks/run-application/configure-pdb/) podDisruptionBudget: enabled: false - # minAvailable: 1 - # maxUnavailable: 1 + # -- min number or percentage of pods that can be unavailable + minAvailable: 0 + # -- max number or percentage of pods that can be unavailable + maxUnavailable: 0 + # -- Defines criteria when unhealthy pods should be considered for eviction + unhealthyPodEvictionPolicy: labels: {} # -- Graceful pod termination timeout. See [this article](https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#hook-handler-execution) for details. @@ -188,9 +300,16 @@ resources: # cpu: 80m # memory: 120Mi -# -- Pod's node selector. Details are [here](https://kubernetes.io/docs/user-guide/node-selection/) +# -- Pod's node selector. Details are [here](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) nodeSelector: {} +# -- Deployment strategy, set to standard k8s default +strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + # -- Name of Priority Class priorityClassName: "" @@ -206,7 +325,7 @@ topologySpreadConstraints: [] # -- Operator container additional commandline arguments extraArgs: {} -# -- Extra settings for the operator deployment. Full list [here](https://docs.victoriametrics.com/operator/vars) +# -- Extra settings for the operator deployment. Full list [here](https://docs.victoriametrics.com/operator/configuration/#environment-variables) env: [] # - name: VM_VMSINGLEDEFAULT_VERSION @@ -249,21 +368,20 @@ extraContainers: # -- Enable hostNetwork on operator deployment hostNetwork: false +# -- Enable sharing process Namespace between Containers in a Pod. This only makes sense with extraContainers +shareProcessNamespace: false + # -- Configures resource validation admissionWebhooks: # -- Enables validation webhook. enabled: true - enabledCRDValidation: - vmagent: true - vmalert: true - vmsingle: true - vmauth: true - vmrule: true - vmalertmanagerconfig: true - vmalertmanager: true - vmcluster: true - vmuser: true - vlogs: true + # -- Annotations for webhook. Can be used to define Helm or ArgoCD annotations. + annotations: {} + # -- List of CRD names to disable validation for + disabledFor: [] + # - vmagent + # - vmsingle + # -- What to do in case, when operator not available to validate request. policy: Fail # -- Enables custom ca bundle, if you are not using cert-manager. In case of custom ca, you have to create secret - {chart-name}-validation with keys: tls.key, tls.crt, ca.crt diff --git a/packages/system/victoria-metrics-operator/patches/disable-ca-key-rotation.patch b/packages/system/victoria-metrics-operator/patches/disable-ca-key-rotation.patch new file mode 100644 index 00000000..c8a0bfbc --- /dev/null +++ b/packages/system/victoria-metrics-operator/patches/disable-ca-key-rotation.patch @@ -0,0 +1,13 @@ +diff --git a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/webhook.yaml b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/webhook.yaml +index 2e027ab4..1bead84d 100644 +--- a/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/webhook.yaml ++++ b/packages/system/victoria-metrics-operator/charts/victoria-metrics-operator/templates/webhook.yaml +@@ -78,6 +78,8 @@ spec: + name: {{ $fullname }}-root + commonName: {{ $certManager.ca.commonName }} + isCA: true ++ privateKey: ++ rotationPolicy: Never + --- + apiVersion: cert-manager.io/v1 + kind: Issuer diff --git a/packages/system/virtualprivatecloud-rd/Chart.yaml b/packages/system/virtualprivatecloud-rd/Chart.yaml new file mode 100644 index 00000000..be5235dc --- /dev/null +++ b/packages/system/virtualprivatecloud-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: virtualprivatecloud-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/virtualprivatecloud-rd/Makefile b/packages/system/virtualprivatecloud-rd/Makefile new file mode 100644 index 00000000..013e96b1 --- /dev/null +++ b/packages/system/virtualprivatecloud-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=virtualprivatecloud-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/virtualprivatecloud-rd/cozyrds/virtualprivatecloud.yaml b/packages/system/virtualprivatecloud-rd/cozyrds/virtualprivatecloud.yaml new file mode 100644 index 00000000..e1397d2d --- /dev/null +++ b/packages/system/virtualprivatecloud-rd/cozyrds/virtualprivatecloud.yaml @@ -0,0 +1,32 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: virtualprivatecloud +spec: + application: + kind: VirtualPrivateCloud + plural: virtualprivateclouds + singular: virtualprivatecloud + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"subnets":{"description":"Subnets of a VPC","type":"array","default":[],"items":{"type":"object","required":["name"],"properties":{"cidr":{"description":"IP address range","type":"string"},"name":{"description":"Subnet name","type":"string"}}}},"peers":{"description":"VPC peering connections (bidirectional declaration required)","type":"array","default":[],"items":{"type":"object","required":["tenantNamespace","vpcName"],"properties":{"tenantNamespace":{"description":"Namespace of the remote tenant","type":"string"},"vpcName":{"description":"Logical name of the remote VPC (without \"virtualprivatecloud-\" prefix)","type":"string"}}}},"routes":{"description":"Static routes for the VPC","type":"array","default":[],"items":{"type":"object","required":["cidr","nextHopIP"],"properties":{"cidr":{"description":"Destination CIDR","type":"string"},"nextHopIP":{"description":"Next hop IP address","type":"string"}}}}}} + release: + prefix: "virtualprivatecloud-" + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-virtualprivatecloud-application-kubevirt-virtualprivatecloud + namespace: cozy-system + dashboard: + category: IaaS + singular: VPC + plural: VPCs + description: "Isolated networks" + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl8xMDI1XzMpIi8+CjxwYXRoIGQ9Ik0xMDkuNiA4Ni4xSDExNC4zQzExNi44ODUgODYuMSAxMTkgODguMjE1IDExOSA5MC44NDdWMTA0Ljg1M0MxMTkgMTA3LjQ4NSAxMTYuODg1IDEwOS42IDExNC4zIDEwOS42SDk1LjVDOTIuOTE1IDEwOS42IDkwLjggMTA3LjQ4NSA5MC44IDEwNC44NTNWOTAuODQ3QzkwLjggODguMjE1IDkyLjkxNSA4Ni4xIDk1LjUgODYuMUgxMDAuMlY3Ni43SDc2LjdWODYuMUg4MS40QzgzLjk4NSA4Ni4xIDg2LjEgODguMjE1IDg2LjEgOTAuODQ3VjEwNC44NTNDODYuMSAxMDcuNDg1IDgzLjk4NSAxMDkuNiA4MS40IDEwOS42SDYyLjZDNjAuMDE1IDEwOS42IDU3LjkgMTA3LjQ4NSA1Ny45IDEwNC44NTNWOTAuODQ3QzU3LjkgODguMjE1IDYwLjAxNSA4Ni4xIDYyLjYgODYuMUg2Ny4zVjc2LjdINDMuOFY4Ni4xSDQ4LjVDNTEuMDg1IDg2LjEgNTMuMiA4OC4yMTUgNTMuMiA5MC44NDdWMTA0Ljg1M0M1My4yIDEwNy40ODUgNTEuMDg1IDEwOS42IDQ4LjUgMTA5LjZIMjkuN0MyNy4xMTUgMTA5LjYgMjUgMTA3LjQ4NSAyNSAxMDQuODUzVjkwLjg0N0MyNSA4OC4yMTUgMjcuMTE1IDg2LjEgMjkuNyA4Ni4xSDM0LjRWNzYuN0MzNC40IDcxLjUzIDM4LjYzIDY3LjMgNDMuOCA2Ny4zSDY3LjNWNTcuOUg2Mi42QzYwLjAxNSA1Ny45IDU3LjkgNTUuNzg1IDU3LjkgNTMuMTUzVjM5LjE0N0M1Ny45IDM2LjUxNSA2MC4wMTUgMzQuNCA2Mi42IDM0LjRIODEuNEM4My45ODUgMzQuNCA4Ni4xIDM2LjUxNSA4Ni4xIDM5LjE0N1Y1My4xNTNDODYuMSA1NS43ODUgODMuOTg1IDU3LjkgODEuNCA1Ny45SDc2LjdWNjcuM0gxMDAuMkMxMDUuMzcgNjcuMyAxMDkuNiA3MS41MyAxMDkuNiA3Ni43Vjg2LjFaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzEwMjVfMyIgeDE9IjE0Mi41IiB5MT0iMTQzIiB4Mj0iMy45OTk5OSIgeTI9IjkuNDk5OTkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iIzAwMDgyRSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMyRTMwNjciLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "subnets"], ["spec", "peers"], ["spec", "routes"]] + secrets: + exclude: [] + include: [] + services: + exclude: [] + include: [] diff --git a/packages/system/virtualprivatecloud-rd/templates/cozyrd.yaml b/packages/system/virtualprivatecloud-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/virtualprivatecloud-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/virtualprivatecloud-rd/values.yaml b/packages/system/virtualprivatecloud-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/virtualprivatecloud-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/vm-default-images/Chart.yaml b/packages/system/vm-default-images/Chart.yaml new file mode 100644 index 00000000..aac0ccca --- /dev/null +++ b/packages/system/vm-default-images/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: vm-default-images +description: Global Golden Image collection for virtual machines +type: application +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/vm-default-images/Makefile b/packages/system/vm-default-images/Makefile new file mode 100644 index 00000000..a3f9fac7 --- /dev/null +++ b/packages/system/vm-default-images/Makefile @@ -0,0 +1,4 @@ +export NAME=vm-default-images +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/vm-default-images/templates/dv.yaml b/packages/system/vm-default-images/templates/dv.yaml new file mode 100644 index 00000000..84b9a758 --- /dev/null +++ b/packages/system/vm-default-images/templates/dv.yaml @@ -0,0 +1,45 @@ +{{- range .Values.images }} +--- +apiVersion: cdi.kubevirt.io/v1beta1 +kind: DataVolume +metadata: + annotations: + vm-default-images.cozystack.io/name: {{ .name | quote }} + {{- with .os }} + {{- with .family }} + vm-default-images.cozystack.io/os-family: {{ . | quote }} + {{- end }} + {{- with .name }} + vm-default-images.cozystack.io/os-name: {{ . | quote }} + {{- end }} + {{- with .version }} + vm-default-images.cozystack.io/os-version: {{ . | quote }} + {{- end }} + {{- end }} + {{- with .architecture }} + vm-default-images.cozystack.io/architecture: {{ . | quote }} + {{- end }} + {{- with .description }} + vm-default-images.cozystack.io/description: {{ . | quote }} + {{- end }} + cdi.kubevirt.io/storage.bind.immediate.requested: "true" + cdi.kubevirt.io/storage.usePopulator: "true" + labels: + app.kubernetes.io/managed-by: cozystack + name: vm-default-images-{{ required "A valid .name entry required for each image!" .name }} + namespace: cozy-public +spec: + contentType: kubevirt + source: + http: + url: {{ required (printf "A valid .url entry required for image '%s'!" .name) .url | quote }} + storage: + resources: + requests: + storage: {{ default "5Gi" .storage }} + {{- if .storageClass }} + storageClassName: {{ .storageClass }} + {{- else if $.Values.storageClass }} + storageClassName: {{ $.Values.storageClass }} + {{- end }} +{{- end }} diff --git a/packages/system/vm-default-images/values.yaml b/packages/system/vm-default-images/values.yaml new file mode 100644 index 00000000..9d777f0b --- /dev/null +++ b/packages/system/vm-default-images/values.yaml @@ -0,0 +1,169 @@ +## +## @section Global Golden Image Collection +## + +## @param {string} storageClass - Default StorageClass for all images. If empty, uses the cluster default StorageClass. +## NOTE: The default set of images requires approximately 320Gi of storage (16 images × 20Gi each). +## Adjust the image list or per-image storage sizes to match your cluster capacity. +storageClass: "replicated" + +## @typedef {struct} ImageOS - Operating system metadata for a Golden Image. +## @field {string} [family] - OS family (e.g. "Linux", "Windows"). +## @field {string} [name] - OS distribution name (e.g. "Ubuntu", "Fedora"). +## @field {string} [version] - OS version (e.g. "24.04", "40"). + +## @typedef {struct} GlobalImage - A global Golden Image entry. +## @field {string} name - Unique image name used to reference this image in vm-disk (e.g. "ubuntu"). +## @field {string} url - HTTP(S) URL to download the image from. +## @field {quantity} storage - Storage size to allocate for this image. +## @field {string} storageClass - StorageClass used to store the image (overrides global default). +## @field {ImageOS} [os] - Operating system metadata. +## @field {string} [architecture] - CPU architecture (e.g. "amd64", "arm64"). +## @field {string} [description] - Human-readable description. + +## @param {[]GlobalImage} images - List of global Golden Images to provision in the cozy-public namespace. +images: + - name: ubuntu-22.04 + url: https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img + storage: 20Gi + os: + family: Linux + name: Ubuntu + version: "22.04" + architecture: amd64 + description: "Ubuntu 22.04 LTS (Jammy Jellyfish) cloud image" + - name: ubuntu-24.04 + url: https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img + storage: 20Gi + os: + family: Linux + name: Ubuntu + version: "24.04" + architecture: amd64 + description: "Ubuntu 24.04 LTS (Noble Numbat) cloud image" + - name: rocky-8 + url: https://dl.rockylinux.org/pub/rocky/8/images/x86_64/Rocky-8-GenericCloud-Base.latest.x86_64.qcow2 + storage: 20Gi + os: + family: Linux + name: Rocky Linux + version: "8" + architecture: amd64 + description: "Rocky Linux 8 GenericCloud image" + - name: rocky-9 + url: https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud-Base.latest.x86_64.qcow2 + storage: 20Gi + os: + family: Linux + name: Rocky Linux + version: "9" + architecture: amd64 + description: "Rocky Linux 9 GenericCloud image" + - name: rocky-10 + url: https://dl.rockylinux.org/pub/rocky/10/images/x86_64/Rocky-10-GenericCloud-Base.latest.x86_64.qcow2 + storage: 20Gi + os: + family: Linux + name: Rocky Linux + version: "10" + architecture: amd64 + description: "Rocky Linux 10 GenericCloud image" + - name: almalinux-8 + url: https://repo.almalinux.org/almalinux/8/cloud/x86_64/images/AlmaLinux-8-GenericCloud-latest.x86_64.qcow2 + storage: 20Gi + os: + family: Linux + name: AlmaLinux + version: "8" + architecture: amd64 + description: "AlmaLinux 8 GenericCloud image" + - name: almalinux-9 + url: https://repo.almalinux.org/almalinux/9/cloud/x86_64/images/AlmaLinux-9-GenericCloud-latest.x86_64.qcow2 + storage: 20Gi + os: + family: Linux + name: AlmaLinux + version: "9" + architecture: amd64 + description: "AlmaLinux 9 GenericCloud image" + - name: almalinux-10 + url: https://repo.almalinux.org/almalinux/10/cloud/x86_64/images/AlmaLinux-10-GenericCloud-latest.x86_64.qcow2 + storage: 20Gi + os: + family: Linux + name: AlmaLinux + version: "10" + architecture: amd64 + description: "AlmaLinux 10 GenericCloud image" + - name: debian-12 + url: https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2 + storage: 20Gi + os: + family: Linux + name: Debian + version: "12" + architecture: amd64 + description: "Debian 12 (Bookworm) generic cloud image" + - name: debian-13 + url: https://cloud.debian.org/images/cloud/trixie/latest/debian-13-generic-amd64.qcow2 + storage: 20Gi + os: + family: Linux + name: Debian + version: "13" + architecture: amd64 + description: "Debian 13 (Trixie) generic cloud image" + - name: centos-stream-9 + url: https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-9-latest.x86_64.qcow2 + storage: 20Gi + os: + family: Linux + name: CentOS + version: "9" + architecture: amd64 + description: "CentOS Stream 9 GenericCloud image" + - name: centos-stream-10 + url: https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-10-latest.x86_64.qcow2 + storage: 20Gi + os: + family: Linux + name: CentOS + version: "10" + architecture: amd64 + description: "CentOS Stream 10 GenericCloud image" + - name: opensuse-leap-15.6 + url: https://download.opensuse.org/repositories/Cloud:/Images:/Leap_15.6/images/openSUSE-Leap-15.6.x86_64-NoCloud.qcow2 + storage: 20Gi + os: + family: Linux + name: openSUSE + version: "15.6" + architecture: amd64 + description: "openSUSE Leap 15.6 NoCloud image" + - name: opensuse-leap-16.0 + url: https://download.opensuse.org/repositories/openSUSE:/Leap:/16.0:/Images/images/Leap-16.0-Minimal-VM.x86_64-Cloud.qcow2 + storage: 20Gi + os: + family: Linux + name: openSUSE + version: "16.0" + architecture: amd64 + description: "openSUSE Leap 16.0 Minimal VM cloud image" + - name: ubuntu-20.04 + url: https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img + storage: 20Gi + os: + family: Linux + name: Ubuntu + version: "20.04" + architecture: amd64 + description: "Ubuntu 20.04 LTS (Focal Fossa) cloud image" + - name: alpine-3.21 + url: https://dl-cdn.alpinelinux.org/alpine/v3.21/releases/cloud/nocloud_alpine-3.21.6-x86_64-bios-cloudinit-r0.qcow2 + storage: 20Gi + os: + family: Linux + name: Alpine + version: "3.21" + architecture: amd64 + description: "Alpine Linux 3.21 cloud image (cloud-init)" diff --git a/packages/system/vm-disk-rd/Chart.yaml b/packages/system/vm-disk-rd/Chart.yaml new file mode 100644 index 00000000..d405b0f0 --- /dev/null +++ b/packages/system/vm-disk-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: vm-disk-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/vm-disk-rd/Makefile b/packages/system/vm-disk-rd/Makefile new file mode 100644 index 00000000..5b73fd4c --- /dev/null +++ b/packages/system/vm-disk-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=vm-disk-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/vm-disk-rd/cozyrds/vm-disk.yaml b/packages/system/vm-disk-rd/cozyrds/vm-disk.yaml new file mode 100644 index 00000000..3ce046ed --- /dev/null +++ b/packages/system/vm-disk-rd/cozyrds/vm-disk.yaml @@ -0,0 +1,32 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: vm-disk +spec: + application: + kind: VMDisk + singular: vmdisk + plural: vmdisks + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"source":{"description":"The source image location used to create a disk.","type":"object","default":{},"properties":{"disk":{"description":"Clone an existing vm-disk.","type":"object","required":["name"],"properties":{"name":{"description":"Name of the vm-disk to clone.","type":"string"}}},"http":{"description":"Download image from an HTTP source.","type":"object","required":["url"],"properties":{"url":{"description":"URL to download the image.","type":"string"}}},"image":{"description":"Use image by name from default collection.","type":"object","required":["name"],"properties":{"name":{"description":"Name of the image to use.","type":"string"}}},"upload":{"description":"Upload local image.","type":"object"}}},"optical":{"description":"Defines if disk should be considered optical.","type":"boolean","default":false},"storage":{"description":"The size of the disk allocated for the virtual machine.","default":"5Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":"replicated"}}} + release: + prefix: vm-disk- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-vm-disk-application-kubevirt-vm-disk + namespace: cozy-system + dashboard: + category: IaaS + singular: VM Disk + plural: VM Disks + description: Virtual Machine disk + weight: 51 + tags: + - storage + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl8zMzBfNDg5NjMpIi8+CjxnIGZpbHRlcj0idXJsKCNmaWx0ZXIwX2lfMzMwXzQ4OTYzKSI+CjxwYXRoIGQ9Ik03Mi4wMDAxIDI2LjYzNjdDNDYuODc3MiAyNi42MzY3IDI2LjUxMTIgNDcuMDAyNyAyNi41MTEyIDcyLjEyNTZDMjYuNTExMiA5Ny4yNDg0IDQ2Ljg3NzIgMTE3LjYxNCA3Mi4wMDAxIDExNy42MTRDOTcuMTIyOSAxMTcuNjE0IDExNy40ODkgOTcuMjQ4MiAxMTcuNDg5IDcyLjEyNTRDMTE3LjQ4OSA0Ny4wMDI1IDk3LjEyMjkgMjYuNjM2NyA3Mi4wMDAxIDI2LjYzNjdaTTcyLjAwMDEgODEuNjIxMkM2Ni43NTU3IDgxLjYyMTIgNjIuNTA0NCA3Ny4zNjk5IDYyLjUwNDQgNzIuMTI1NkM2Mi41MDQ0IDY2Ljg4MTIgNjYuNzU1NyA2Mi42Mjk5IDcyLjAwMDEgNjIuNjI5OUM3Ny4yNDQ0IDYyLjYyOTkgODEuNDk1NyA2Ni44ODEyIDgxLjQ5NTcgNzIuMTI1NkM4MS40OTU3IDc3LjM2OTkgNzcuMjQ0NCA4MS42MjEyIDcyLjAwMDEgODEuNjIxMloiIGZpbGw9IiNCQUQ5RkYiLz4KPC9nPgo8cGF0aCBkPSJNNTIuMDA3NSA2NS43MjA5TDMyLjI5NzYgNTkuMDQ5OEMzNi4yODQyIDQ3LjI3MTEgNDUuMzI4NSAzNy42MzE1IDU2LjQ5MSAzMy4yNjRMNjQuMDcyOCA1Mi42NDE5QzU4LjY0MiA1NC43NjY3IDU0LjAxOSA1OS43NzgzIDUyLjAwNzUgNjUuNzIwOVpNOTEuOTkyNiA3OC41M0wxMTEuNzAzIDg1LjIwMTFDMTA3LjcxNiA5Ni45Nzk5IDk4LjY3MTggMTA2LjYxOSA4Ny41MDkzIDExMC45ODdMNzkuOTI3NSA5MS42MDlDODUuMzU4MSA4OS40ODQyIDg5Ljk4MTMgODQuNDcyNiA5MS45OTI2IDc4LjUzWiIgZmlsbD0iI0VERjZGRiIvPgo8cGF0aCBkPSJNNTUuOTMyNCA1OC43MDI4QzU3LjY1MTQgNTYuNjE0IDU5LjcxOTQgNTQuODYzMiA2MS45ODk0IDUzLjYxODNDNjMuMTQ5IDUyLjk4MjQgNjQuMjYzMyA1My4xMjk2IDYzLjc4MTQgNTEuODk3OUw1Ny4yMDk1IDM1LjEwMDlDNTYuMjkwOSAzMi43NTI5IDU1LjI4MTQgMzMuNzI4NSA1My45MDYgMzQuMzg2OEM0OC45NzM0IDM2Ljc0NzYgNDQuNTM0OSA0MC4xNTkgNDAuODYwMSA0NC4zMTU0TDU1LjkzMjQgNTguNzAyOFpNODguMDY3NiA4NS41NDgxQzg1LjgzNTIgODguMjYwNSA4My4wMTQ4IDkwLjQwMjkgNzkuOTI2OSA5MS42MDhMODcuNTA4OSAxMTAuOTg2QzkzLjQ3ODUgMTA4LjY1NCA5OC44MzM2IDEwNC44MDYgMTAzLjE0IDk5LjkzNTVMODguMDY3NiA4NS41NDgxWiIgZmlsbD0iI0NERTNGRiIvPgo8cGF0aCBkPSJNNzIgODkuNDM4OEM2Mi40NTM0IDg5LjQzODggNTQuNjg2NSA4MS42NzIxIDU0LjY4NjUgNzIuMTI1NEM1NC42ODY1IDYyLjU3ODYgNjIuNDUzNCA1NC44MTE5IDcyIDU0LjgxMTlDODEuNTQ2OCA1NC44MTE5IDg5LjMxMzQgNjIuNTc4OCA4OS4zMTM0IDcyLjEyNTRDODkuMzEzNCA4MS42NzIgODEuNTQ2OCA4OS40Mzg4IDcyIDg5LjQzODhaTTcyIDU5LjExMDVDNjQuODIzNCA1OS4xMTA1IDU4Ljk4NDkgNjQuOTQ5IDU4Ljk4NDkgNzIuMTI1NkM1OC45ODQ5IDc5LjMwMjIgNjQuODIzNCA4NS4xNDA2IDcyIDg1LjE0MDZDNzkuMTc2NiA4NS4xNDA2IDg1LjAxNSA3OS4zMDIyIDg1LjAxNSA3Mi4xMjU2Qzg1LjAxNSA2NC45NDkgNzkuMTc2NiA1OS4xMTA1IDcyIDU5LjExMDVaIiBmaWxsPSIjMDBCNEZGIi8+CjxkZWZzPgo8ZmlsdGVyIGlkPSJmaWx0ZXIwX2lfMzMwXzQ4OTYzIiB4PSIyNi41MTEyIiB5PSIyNi42MzY3IiB3aWR0aD0iOTIuOTc3OCIgaGVpZ2h0PSI5Mi45Nzc1IiBmaWx0ZXJVbml0cz0idXNlclNwYWNlT25Vc2UiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+CjxmZUZsb29kIGZsb29kLW9wYWNpdHk9IjAiIHJlc3VsdD0iQmFja2dyb3VuZEltYWdlRml4Ii8+CjxmZUJsZW5kIG1vZGU9Im5vcm1hbCIgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0iQmFja2dyb3VuZEltYWdlRml4IiByZXN1bHQ9InNoYXBlIi8+CjxmZUNvbG9yTWF0cml4IGluPSJTb3VyY2VBbHBoYSIgdHlwZT0ibWF0cml4IiB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDEyNyAwIiByZXN1bHQ9ImhhcmRBbHBoYSIvPgo8ZmVPZmZzZXQgZHg9IjIiIGR5PSIyIi8+CjxmZUdhdXNzaWFuQmx1ciBzdGREZXZpYXRpb249IjIuNSIvPgo8ZmVDb21wb3NpdGUgaW4yPSJoYXJkQWxwaGEiIG9wZXJhdG9yPSJhcml0aG1ldGljIiBrMj0iLTEiIGszPSIxIi8+CjxmZUNvbG9yTWF0cml4IHR5cGU9Im1hdHJpeCIgdmFsdWVzPSIwIDAgMCAwIDEgMCAwIDAgMCAxIDAgMCAwIDAgMSAwIDAgMCAwLjIxIDAiLz4KPGZlQmxlbmQgbW9kZT0ibm9ybWFsIiBpbjI9InNoYXBlIiByZXN1bHQ9ImVmZmVjdDFfaW5uZXJTaGFkb3dfMzMwXzQ4OTYzIi8+CjwvZmlsdGVyPgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXJfMzMwXzQ4OTYzIiB4MT0iLTE1LjUiIHkxPSItMTIiIHgyPSIyMTYuNSIgeTI9IjE4NS41IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiM2NUNDRkYiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDQ0Mzc0Ii8+CjwvbGluZWFyR3JhZGllbnQ+CjwvZGVmcz4KPC9zdmc+Cg== + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "source"], ["spec", "optical"], ["spec", "storage"], ["spec", "storageClass"]] + secrets: + exclude: [] + include: [] diff --git a/packages/system/vm-disk-rd/templates/cozyrd.yaml b/packages/system/vm-disk-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/vm-disk-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/vm-disk-rd/values.yaml b/packages/system/vm-disk-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/vm-disk-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/vm-instance-rd/Chart.yaml b/packages/system/vm-instance-rd/Chart.yaml new file mode 100644 index 00000000..270db7d6 --- /dev/null +++ b/packages/system/vm-instance-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: vm-instance-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/vm-instance-rd/Makefile b/packages/system/vm-instance-rd/Makefile new file mode 100644 index 00000000..621d74bd --- /dev/null +++ b/packages/system/vm-instance-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=vm-instance-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/vm-instance-rd/cozyrds/vm-instance.yaml b/packages/system/vm-instance-rd/cozyrds/vm-instance.yaml new file mode 100644 index 00000000..e56bd9dd --- /dev/null +++ b/packages/system/vm-instance-rd/cozyrds/vm-instance.yaml @@ -0,0 +1,37 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: vm-instance +spec: + application: + kind: VMInstance + singular: vminstance + plural: vminstances + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"externalMethod":{"description":"Method to pass through traffic to the VM.","type":"string","default":"PortList","enum":["PortList","WholeIP"]},"externalPorts":{"description":"Ports to forward from outside the cluster.","type":"array","default":[22],"items":{"type":"integer"}},"externalAllowICMP":{"description":"Whether to accept ICMP traffic to the VM in PortList mode (preserves ping and PMTU discovery). No effect in WholeIP mode. Default true so ping behaves as users expect even when port filtering is in effect.","type":"boolean","default":true},"runStrategy":{"description":"Requested running state of the VirtualMachineInstance","type":"string","default":"Always","enum":["Always","Halted","Manual","RerunOnFailure","Once"]},"instanceType":{"description":"Virtual Machine instance type.","type":"string","default":"u1.medium"},"instanceProfile":{"description":"Virtual Machine preferences profile.","type":"string","default":"ubuntu","enum":["alpine","centos.7","centos.7.desktop","centos.stream10","centos.stream10.desktop","centos.stream8","centos.stream8.desktop","centos.stream8.dpdk","centos.stream9","centos.stream9.desktop","centos.stream9.dpdk","cirros","fedora","fedora.arm64","opensuse.leap","opensuse.tumbleweed","rhel.10","rhel.10.arm64","rhel.7","rhel.7.desktop","rhel.8","rhel.8.desktop","rhel.8.dpdk","rhel.9","rhel.9.arm64","rhel.9.desktop","rhel.9.dpdk","rhel.9.realtime","sles","ubuntu","windows.10","windows.10.virtio","windows.11","windows.11.virtio","windows.2k16","windows.2k16.virtio","windows.2k19","windows.2k19.virtio","windows.2k22","windows.2k22.virtio","windows.2k25","windows.2k25.virtio",""]},"disks":{"description":"List of disks to attach.","type":"array","default":[],"items":{"type":"object","required":["name"],"properties":{"bus":{"description":"Disk bus type (e.g. \"sata\").","type":"string"},"name":{"description":"Disk name.","type":"string"}}}},"networks":{"description":"Networks to attach the VM to.","type":"array","default":[],"items":{"type":"object","properties":{"name":{"description":"Network attachment name.","type":"string"}}}},"subnets":{"description":"Deprecated: use networks instead.","type":"array","default":[],"items":{"type":"object","properties":{"name":{"description":"Network attachment name.","type":"string"}}}},"gpus":{"description":"List of GPUs to attach (NVIDIA driver requires at least 4 GiB RAM).","type":"array","default":[],"items":{"type":"object","required":["name"],"properties":{"name":{"description":"The name of the GPU resource to attach.","type":"string"}}}},"cpuModel":{"description":"Model specifies the CPU model inside the VMI. List of available models https://github.com/libvirt/libvirt/tree/master/src/cpu_map","type":"string","default":""},"resources":{"description":"Resource configuration for the virtual machine.","type":"object","default":{},"properties":{"cpu":{"description":"Number of CPU cores allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Amount of memory allocated.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"sockets":{"description":"Number of CPU sockets (vCPU topology).","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"sshKeys":{"description":"List of SSH public keys for authentication.","type":"array","default":[],"items":{"type":"string"}},"cloudInit":{"description":"Cloud-init user data.","type":"string","default":""},"cloudInitSeed":{"description":"Seed string to generate SMBIOS UUID for the VM.","type":"string","default":""}}} + release: + prefix: vm-instance- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-vm-instance-application-kubevirt-vm-instance + namespace: cozy-system + dashboard: + category: IaaS + singular: VM Instance + plural: VM Instances + description: Virtual machine instance + weight: 50 + tags: + - compute + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODdfMzQ1NCkiLz4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzY4N18zNDU0KSI+CjxwYXRoIGQ9Ik04OS41MDM5IDExMS43MDdINTQuNDk3QzU0LjE3MjcgMTExLjcwNyA1NC4wMTA4IDExMS4yMjEgNTQuMzM0OSAxMTEuMDU5TDU3LjI1MjIgMTA4Ljk1MkM2MC4zMzE0IDEwNi42ODMgNjEuOTUyMiAxMDIuNjMxIDYwLjk3OTcgOTguNzQxMkg4My4wMjFDODIuMDQ4NSAxMDIuNjMxIDgzLjY2OTMgMTA2LjY4MyA4Ni43NDg1IDEwOC45NTJMODkuNjY1OCAxMTEuMDU5Qzg5Ljk5IDExMS4yMjEgODkuODI3OSAxMTEuNzA3IDg5LjUwMzkgMTExLjcwN1oiIGZpbGw9IiNCMEI2QkIiLz4KPHBhdGggZD0iTTExMy4zMjggOTguNzQxSDMwLjY3MjVDMjcuNTkzMSA5OC43NDEgMjUgOTYuMTQ4IDI1IDkzLjA2ODdWMzMuMTAzMkMyNSAzMC4wMjM5IDI3LjU5MzEgMjcuNDMwNyAzMC42NzI1IDI3LjQzMDdIMTEzLjMyOEMxMTYuNDA3IDI3LjQzMDcgMTE5IDMwLjAyMzcgMTE5IDMzLjEwMzJWOTMuMDY4N0MxMTkgOTYuMTQ4IDExNi40MDcgOTguNzQxIDExMy4zMjggOTguNzQxWiIgZmlsbD0iI0U4RURFRSIvPgo8cGF0aCBkPSJNMTE5IDg0LjE1NDlIMjVWMzMuMTAzMkMyNSAzMC4wMjM5IDI3LjU5MzEgMjcuNDMwNyAzMC42NzI1IDI3LjQzMDdIMTEzLjMyOEMxMTYuNDA3IDI3LjQzMDcgMTE5IDMwLjAyMzcgMTE5IDMzLjEwMzJMMTE5IDg0LjE1NDlaIiBmaWxsPSIjMDBCM0ZGIi8+CjxwYXRoIGQ9Ik05MC42Mzc0IDExNi41NjlINTMuMzYxNkM1Mi4wNjUxIDExNi41NjkgNTAuOTMwNyAxMTUuNDM1IDUwLjkzMDcgMTE0LjEzOEM1MC45MzA3IDExMi44NDEgNTIuMDY1MSAxMTEuNzA3IDUzLjM2MTYgMTExLjcwN0g5MC42Mzc0QzkxLjkzMzkgMTExLjcwNyA5My4wNjg0IDExMi44NDEgOTMuMDY4NCAxMTQuMTM4QzkzLjA2ODQgMTE1LjQzNSA5MS45MzM5IDExNi41NjkgOTAuNjM3NCAxMTYuNTY5WiIgZmlsbD0iI0U4RURFRSIvPgo8L2c+CjxwYXRoIGQ9Ik03Mi41Mjc1IDUzLjgzNjdDNzIuNDQzMSA1My44MzUxIDcyLjM2MDUgNTMuODEyMiA3Mi4yODczIDUzLjc3MDFMNTYuNDY5OSA0NC43OTM0QzU2LjM5ODMgNDQuNzUxOSA1Ni4zMzg4IDQ0LjY5MjMgNTYuMjk3MyA0NC42MjA3QzU2LjI1NTkgNDQuNTQ5IDU2LjIzMzggNDQuNDY3OCA1Ni4yMzM0IDQ0LjM4NUM1Ni4yMzM0IDQ0LjIxNjkgNTYuMzI1OCA0NC4wNjE3IDU2LjQ2OTkgNDMuOTc4NUw3Mi4xOTEyIDM1LjA2MDlDNzIuMjYzNyAzNS4wMjEgNzIuMzQ1IDM1IDcyLjQyNzcgMzVDNzIuNTEwNSAzNSA3Mi41OTE4IDM1LjAyMSA3Mi42NjQzIDM1LjA2MDlMODguNDg3MiA0NC4wMzk1Qzg4LjU1OTEgNDQuMDgwMSA4OC42MTg4IDQ0LjEzOTIgODguNjYgNDQuMjEwN0M4OC43MDEzIDQ0LjI4MjIgODguNzIyNyA0NC4zNjM1IDg4LjcyMTkgNDQuNDQ2Qzg4LjcyMjUgNDQuNTI4NSA4OC43MDEgNDQuNjA5NyA4OC42NTk4IDQ0LjY4MTJDODguNjE4NSA0NC43NTI2IDg4LjU1ODkgNDQuODExOCA4OC40ODcyIDQ0Ljg1MjVMNzIuNzcxNCA1My43NjgzQzcyLjY5NzIgNTMuODExNCA3Mi42MTMzIDUzLjgzNDkgNzIuNTI3NSA1My44MzY3IiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBvcGFjaXR5PSIwLjciIGQ9Ik03MC4yNTUzIDc1LjY1MTdDNzAuMTcxIDc1LjY1MzUgNzAuMDg3OCA3NS42MzE3IDcwLjAxNTEgNzUuNTg4OEw1NC4yNDU4IDY2LjY0MTdDNTQuMTcxNSA2Ni42MDI0IDU0LjEwOTUgNjYuNTQzNiA1NC4wNjYxIDY2LjQ3MTZDNTQuMDIyOCA2Ni4zOTk3IDU0IDY2LjMxNzMgNTQgNjYuMjMzM1Y0OC4yNzhDNTQgNDguMTA4IDU0LjA5MjQgNDcuOTU0NiA1NC4yNDM5IDQ3Ljg2OTZDNTQuMzE3MiA0Ny44MjcxIDU0LjQwMDQgNDcuODA0NyA1NC40ODUxIDQ3LjgwNDdDNTQuNTY5NyA0Ny44MDQ3IDU0LjY1MjkgNDcuODI3MSA1NC43MjYyIDQ3Ljg2OTZMNzAuNDkzNyA1Ni44MTMxQzcwLjU2NDIgNTYuODU2NSA3MC42MjI1IDU2LjkxNyA3MC42NjMyIDU2Ljk4OTFDNzAuNzAzOSA1Ny4wNjEyIDcwLjcyNTcgNTcuMTQyNCA3MC43MjY1IDU3LjIyNTFWNzUuMTgwNUM3MC43MjU5IDc1LjI2MjggNzAuNzA0MiA3NS4zNDM2IDcwLjY2MzUgNzUuNDE1MUM3MC42MjI3IDc1LjQ4NjYgNzAuNTY0MiA3NS41NDY0IDcwLjQ5MzcgNzUuNTg4OEM3MC40MjA2IDc1LjYyOTEgNzAuMzM4NyA3NS42NTA3IDcwLjI1NTMgNzUuNjUxNyIgZmlsbD0id2hpdGUiLz4KPHBhdGggb3BhY2l0eT0iMC40IiBkPSJNNzQuNzE5OCA3NS42NTExQzc0LjYzMzMgNzUuNjUxMiA3NC41NDgyIDc1LjYyOTYgNzQuNDcyMiA3NS41ODgzQzc0LjQwMTYgNzUuNTQ2MSA3NC4zNDMyIDc1LjQ4NjIgNzQuMzAyNyA3NS40MTQ3Qzc0LjI2MjMgNzUuMzQzMSA3NC4yNDExIDc1LjI2MjIgNzQuMjQxMiA3NS4xOFY1Ny4zMzczQzc0LjI0MTIgNTcuMTcxIDc0LjMzMzYgNTcuMDE1OCA3NC40NzIyIDU2LjkyOUw5MC4yMzk3IDQ3Ljk4NTVDOTAuMzExOSA0Ny45NDM4IDkwLjM5MzggNDcuOTIxOSA5MC40NzcxIDQ3LjkyMTlDOTAuNTYwNSA0Ny45MjE5IDkwLjY0MjQgNDcuOTQzOCA5MC43MTQ2IDQ3Ljk4NTVDOTAuNzg3NiA0OC4wMjU1IDkwLjg0ODUgNDguMDg0MiA5MC44OTExIDQ4LjE1NTdDOTAuOTMzNyA0OC4yMjcyIDkwLjk1NjMgNDguMzA4OCA5MC45NTY2IDQ4LjM5MlY2Ni4yMzI4QzkwLjk1NyA2Ni4zMTY0IDkwLjkzNDcgNjYuMzk4NSA5MC44OTIxIDY2LjQ3MDRDOTAuODQ5NSA2Ni41NDI0IDkwLjc4ODEgNjYuNjAxNCA5MC43MTQ2IDY2LjY0MTFMNzQuOTUyNiA3NS41ODgzQzc0Ljg4MjUgNzUuNjMwNyA3NC44MDE4IDc1LjY1MjUgNzQuNzE5OCA3NS42NTExIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzY4N18zNDU0IiB4MT0iMTYxIiB5MT0iMTgwIiB4Mj0iMy41OTI4NGUtMDciIHkyPSI0Ljk5OTk4IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNTk1NjU2Ii8+CjwvbGluZWFyR3JhZGllbnQ+CjxjbGlwUGF0aCBpZD0iY2xpcDBfNjg3XzM0NTQiPgo8cmVjdCB3aWR0aD0iOTQiIGhlaWdodD0iOTQiIGZpbGw9IndoaXRlIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyNSAyNSkiLz4KPC9jbGlwUGF0aD4KPC9kZWZzPgo8L3N2Zz4K + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "external"], ["spec", "externalMethod"], ["spec", "externalPorts"], ["spec", "externalAllowICMP"], ["spec", "runStrategy"], ["spec", "instanceType"], ["spec", "instanceProfile"], ["spec", "disks"], ["spec", "networks"], ["spec", "subnets"], ["spec", "gpus"], ["spec", "cpuModel"], ["spec", "resources"], ["spec", "sshKeys"], ["spec", "cloudInit"], ["spec", "cloudInitSeed"]] + secrets: + exclude: [] + include: [] + services: + exclude: [] + include: + - matchLabels: + apps.cozystack.io/user-service: "true" diff --git a/packages/system/vm-instance-rd/templates/cozyrd.yaml b/packages/system/vm-instance-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/vm-instance-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/vm-instance-rd/values.yaml b/packages/system/vm-instance-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/vm-instance-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/vpn-rd/Chart.yaml b/packages/system/vpn-rd/Chart.yaml new file mode 100644 index 00000000..fe0a2dd3 --- /dev/null +++ b/packages/system/vpn-rd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: vpn-rd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/vpn-rd/Makefile b/packages/system/vpn-rd/Makefile new file mode 100644 index 00000000..d37f46fc --- /dev/null +++ b/packages/system/vpn-rd/Makefile @@ -0,0 +1,4 @@ +export NAME=vpn-rd +export NAMESPACE=cozy-system + +include ../../../hack/package.mk diff --git a/packages/system/vpn-rd/cozyrds/vpn.yaml b/packages/system/vpn-rd/cozyrds/vpn.yaml new file mode 100644 index 00000000..d2fb9efa --- /dev/null +++ b/packages/system/vpn-rd/cozyrds/vpn.yaml @@ -0,0 +1,38 @@ +apiVersion: cozystack.io/v1alpha1 +kind: ApplicationDefinition +metadata: + name: vpn +spec: + application: + kind: VPN + plural: vpns + singular: vpn + openAPISchema: |- + {"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of VPN server replicas.","type":"integer","default":2},"resources":{"description":"Explicit CPU and memory configuration for each VPN server replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"nano","enum":["nano","micro","small","medium","large","xlarge","2xlarge"]},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"host":{"description":"Host used to substitute into generated URLs.","type":"string","default":""},"users":{"description":"Users configuration map.","type":"object","default":{},"additionalProperties":{"type":"object","properties":{"password":{"description":"Password for the user (autogenerated if not provided).","type":"string"}}}},"externalIPs":{"description":"List of externalIPs for service. Optional. If not specified, will use LoadBalancer service by default.","type":"array","default":[],"items":{"type":"string"}}}} + release: + prefix: vpn- + labels: + sharding.fluxcd.io/key: tenants + chartRef: + kind: ExternalArtifact + name: cozystack-vpn-application-default-vpn + namespace: cozy-system + dashboard: + category: NaaS + singular: VPN + plural: VPN + description: Managed VPN service + tags: + - network + icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0xNDMuOTkyIDMwLjM2OTdDMTQzLjk5MiAyOS4yNTU2IDE0My45OTIgMjguMTUxNyAxNDMuOTkyIDI3LjA0NzdDMTQzLjk0NSAyNC42Mjg3IDE0My43MTcgMjIuMjE2NiAxNDMuMzA5IDE5LjgzMTZDMTQyLjkxMiAxNy40NDczIDE0Mi4xNTcgMTUuMTM2NSAxNDEuMDcyIDEyLjk3NjlDMTM5Ljk3IDEwLjgxOCAxMzguNTM0IDguODQ2NjUgMTM2LjgxNyA3LjEzNTc3TDEzMC45OTcgMi44OTA0NEMxMjguODM3IDEuODAyODkgMTI2LjUyNyAxLjA0MTg5IDEyNC4xNDQgMC42MzIyODNDMTIxLjc1NiAwLjIzNDgwOCAxMTkuMzQgMC4wMjM0MTEzIDExNi45MTkgMEMxMTUuODE1IDAgMjguMTQ2MSAwIDI3LjAzMjMgMEMyNC42MDQ3IDAuMDI0MjIxMSAyMi4xODI2IDAuMjM1NjA5IDE5Ljc4NzYgMC42MzIyODNDMTcuNDEyOCAxLjAzODUxIDE1LjExMjYgMS43OTk3NCAxMi45NjQzIDIuODkwNDRDMTAuODEzIDMuOTk1MTkgOC44NDYyNSA1LjQyNzM2IDcuMTM0MzYgNy4xMzU3N0M1LjQxNzY4IDguODQ0NCAzLjk4NDggMTAuODE2MyAyLjg4OTg3IDEyLjk3NjlDMS44MDA4NiAxNS4xMzYgMS4wNDMxMyAxNy40NDY4IDAuNjQyMTkzIDE5LjgzMTZDMC4yNDM0OTcgMjIuMjE2OSAwLjAyODc5OTggMjQuNjI5NCAwIDI3LjA0NzdDMCAyOC4xNTE3IDAgMTE1LjgzOCAwIDExNi45NTJDMC4wMjYxNzU1IDExOS4zODQgMC4yNDA4ODQgMTIxLjgxIDAuNjQyMTkzIDEyNC4yMDlDMS4wNDA0NCAxMjYuNTk0IDEuNzk4MjkgMTI4LjkwNSAyLjg4OTg3IDEzMS4wNjNDMy45ODUxNSAxMzMuMjE4IDUuNDE4MSAxMzUuMTgzIDcuMTM0MzYgMTM2Ljg4NEM4Ljg0MDk1IDEzOC41OTkgMTAuODA4NyAxNDAuMDMyIDEyLjk2NDMgMTQxLjEzQzE1LjExNDcgMTQyLjIwOSAxNy40MTQ2IDE0Mi45NiAxOS43ODc2IDE0My4zNThDMjIuMTczMSAxNDMuNzUxIDI0LjU4NDcgMTQzLjk2NiAyNy4wMDIyIDE0NEMyOC4xMTYgMTQ0IDExNS43ODUgMTQ0IDExNi44ODkgMTQ0QzExOS4zMDMgMTQzLjk2NyAxMjEuNzEyIDE0My43NTIgMTI0LjA5NCAxNDMuMzU4QzEyNi40ODUgMTQyLjk0NiAxMjguODAxIDE0Mi4xODIgMTMwLjk2NyAxNDEuMDg5QzEzMy4xMjEgMTM5Ljk5NCAxMzUuMDg2IDEzOC41NjEgMTM2Ljc4NyAxMzYuODQ0QzEzOC41MDMgMTM1LjE0IDEzOS45MzkgMTMzLjE3NiAxNDEuMDQyIDEzMS4wMjNDMTQyLjEzNyAxMjguODc5IDE0Mi45MDEgMTI2LjU4MSAxNDMuMzA5IDEyNC4yMDlDMTQzLjcxIDEyMS44MjMgMTQzLjkzMiAxMTkuNDExIDE0My45NzIgMTE2Ljk5MkMxNDMuOTkyIDExNS44MzggMTQ0LjAxMiAzMS42NzQ0IDE0My45OTIgMzAuMzY5N1oiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl82ODFfMjgxOCkiLz4KPHBhdGggZD0iTTExNS45NTUgNjcuNDIzMUMxMTQuOTQxIDU3LjgyMzQgMTEwLjcwMSA0OC44NTE4IDEwMy45MjggNDEuOTc1MkM5Ny4xNTQ5IDM1LjA5ODYgODguMjQ5NSAzMC43MjM5IDc4LjY2OCAyOS41NjY0VjQ2Ljc3ODZDODQuNDg4NyA0Ny45MTI3IDg5LjczMzggNTEuMDM2MiA5My41MDQ5IDU1LjYxMzdDOTcuMjc2IDYwLjE5MTIgOTkuMzM4MSA2NS45Mzc5IDk5LjMzODEgNzEuODY5MkM5OS4zMzgxIDc3LjgwMDQgOTcuMjc2IDgzLjU0NzEgOTMuNTA0OSA4OC4xMjQ2Qzg5LjczMzggOTIuNzAyMiA4NC40ODg3IDk1LjgyNTYgNzguNjY4IDk2Ljk1OThWMTE0LjIyMkM4OS43ODAxIDExMi44NzcgOTkuOTE3OCAxMDcuMjE1IDEwNi44OTQgOTguNDYwMUMxMTMuODY5IDg5LjcwNDggMTE3LjEyNCA3OC41NTczIDExNS45NTUgNjcuNDIzMVoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0yOC4wMTU1IDc2LjM2NTRDMjkuMDMxMSA4NS45NjQ0IDMzLjI3MTggOTQuOTM1MSA0MC4wNDQ3IDEwMS44MTFDNDYuODE3NSAxMDguNjg4IDU1LjcyMiAxMTMuMDYzIDY1LjMwMjggMTE0LjIyMlYyOS41NjY0QzU0LjE5MDcgMzAuOTExOSA0NC4wNTMgMzYuNTczMSAzNy4wNzcyIDQ1LjMyODRDMzAuMTAxMyA1NC4wODM3IDI2Ljg0NjcgNjUuMjMxMiAyOC4wMTU1IDc2LjM2NTRaIiBmaWxsPSIjNUJCMTkzIi8+CjxkZWZzPgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXJfNjgxXzI4MTgiIHgxPSIxMzIuNSIgeTE9IjEzMi41IiB4Mj0iLTI0IiB5Mj0iLTE5IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiMxODM3MjkiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNDU5RDc1Ii8+CjwvbGluZWFyR3JhZGllbnQ+CjwvZGVmcz4KPC9zdmc+Cg== + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "external"], ["spec", "host"], ["spec", "users"], ["spec", "externalIPs"]] + secrets: + exclude: [] + include: + - resourceNames: + - vpn-{{ .name }}-urls + services: + exclude: [] + include: + - resourceNames: + - vpn-{{ .name }}-vpn diff --git a/packages/system/vpn-rd/templates/cozyrd.yaml b/packages/system/vpn-rd/templates/cozyrd.yaml new file mode 100644 index 00000000..e079ddcf --- /dev/null +++ b/packages/system/vpn-rd/templates/cozyrd.yaml @@ -0,0 +1,4 @@ +{{- range $path, $_ := .Files.Glob "cozyrds/*" }} +--- +{{ $.Files.Get $path }} +{{- end }} diff --git a/packages/system/vpn-rd/values.yaml b/packages/system/vpn-rd/values.yaml new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/packages/system/vpn-rd/values.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/system/vsnap-crd/Chart.yaml b/packages/system/vsnap-crd/Chart.yaml new file mode 100644 index 00000000..42d950ed --- /dev/null +++ b/packages/system/vsnap-crd/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: cozy-vsnap-crd +version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process diff --git a/packages/system/vsnap-crd/Makefile b/packages/system/vsnap-crd/Makefile new file mode 100644 index 00000000..005eefbd --- /dev/null +++ b/packages/system/vsnap-crd/Makefile @@ -0,0 +1,11 @@ +export NAME=vsnap-crd +export NAMESPACE=cozy-$(NAME) + +include ../../../hack/package.mk + +update: + rm -rf templates + mkdir templates + wget -O ./templates/volumesnapshotclasses.yaml https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/refs/tags/v8.3.0/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml + wget -O ./templates/volumesnapshotcontents.yaml https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/refs/tags/v8.3.0/client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml + wget -O ./templates/volumesnapshots.yaml https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/refs/tags/v8.3.0/client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml diff --git a/packages/system/vsnap-crd/templates/volumesnapshotclasses.yaml b/packages/system/vsnap-crd/templates/volumesnapshotclasses.yaml new file mode 100644 index 00000000..8164952a --- /dev/null +++ b/packages/system/vsnap-crd/templates/volumesnapshotclasses.yaml @@ -0,0 +1,143 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: "https://github.com/kubernetes-csi/external-snapshotter/pull/814" + controller-gen.kubebuilder.io/version: v0.15.0 + name: volumesnapshotclasses.snapshot.storage.k8s.io +spec: + group: snapshot.storage.k8s.io + names: + kind: VolumeSnapshotClass + listKind: VolumeSnapshotClassList + plural: volumesnapshotclasses + shortNames: + - vsclass + - vsclasses + singular: volumesnapshotclass + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .driver + name: Driver + type: string + - description: Determines whether a VolumeSnapshotContent created through the + VolumeSnapshotClass should be deleted when its bound VolumeSnapshot is deleted. + jsonPath: .deletionPolicy + name: DeletionPolicy + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: |- + VolumeSnapshotClass specifies parameters that a underlying storage system uses when + creating a volume snapshot. A specific VolumeSnapshotClass is used by specifying its + name in a VolumeSnapshot object. + VolumeSnapshotClasses are non-namespaced + 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 + deletionPolicy: + description: |- + deletionPolicy determines whether a VolumeSnapshotContent created through + the VolumeSnapshotClass should be deleted when its bound VolumeSnapshot is deleted. + Supported values are "Retain" and "Delete". + "Retain" means that the VolumeSnapshotContent and its physical snapshot on underlying storage system are kept. + "Delete" means that the VolumeSnapshotContent and its physical snapshot on underlying storage system are deleted. + Required. + enum: + - Delete + - Retain + type: string + driver: + description: |- + driver is the name of the storage driver that handles this VolumeSnapshotClass. + Required. + 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 + parameters: + additionalProperties: + type: string + description: |- + parameters is a key-value map with storage driver specific parameters for creating snapshots. + These values are opaque to Kubernetes. + type: object + required: + - deletionPolicy + - driver + type: object + served: true + storage: true + subresources: {} + - additionalPrinterColumns: + - jsonPath: .driver + name: Driver + type: string + - description: Determines whether a VolumeSnapshotContent created through the VolumeSnapshotClass should be deleted when its bound VolumeSnapshot is deleted. + jsonPath: .deletionPolicy + name: DeletionPolicy + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + # This indicates the v1beta1 version of the custom resource is deprecated. + # API requests to this version receive a warning in the server response. + deprecated: true + # This overrides the default warning returned to clients making v1beta1 API requests. + deprecationWarning: "snapshot.storage.k8s.io/v1beta1 VolumeSnapshotClass is deprecated; use snapshot.storage.k8s.io/v1 VolumeSnapshotClass" + schema: + openAPIV3Schema: + description: VolumeSnapshotClass specifies parameters that a underlying storage system uses when creating a volume snapshot. A specific VolumeSnapshotClass is used by specifying its name in a VolumeSnapshot object. VolumeSnapshotClasses are non-namespaced + 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 + deletionPolicy: + description: deletionPolicy determines whether a VolumeSnapshotContent created through the VolumeSnapshotClass should be deleted when its bound VolumeSnapshot is deleted. Supported values are "Retain" and "Delete". "Retain" means that the VolumeSnapshotContent and its physical snapshot on underlying storage system are kept. "Delete" means that the VolumeSnapshotContent and its physical snapshot on underlying storage system are deleted. Required. + enum: + - Delete + - Retain + type: string + driver: + description: driver is the name of the storage driver that handles this VolumeSnapshotClass. Required. + 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 + parameters: + additionalProperties: + type: string + description: parameters is a key-value map with storage driver specific parameters for creating snapshots. These values are opaque to Kubernetes. + type: object + required: + - deletionPolicy + - driver + type: object + served: false + storage: false + subresources: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/packages/system/vsnap-crd/templates/volumesnapshotcontents.yaml b/packages/system/vsnap-crd/templates/volumesnapshotcontents.yaml new file mode 100644 index 00000000..cd0c879f --- /dev/null +++ b/packages/system/vsnap-crd/templates/volumesnapshotcontents.yaml @@ -0,0 +1,457 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + api-approved.kubernetes.io: "https://github.com/kubernetes-csi/external-snapshotter/pull/955" + name: volumesnapshotcontents.snapshot.storage.k8s.io +spec: + group: snapshot.storage.k8s.io + names: + kind: VolumeSnapshotContent + listKind: VolumeSnapshotContentList + plural: volumesnapshotcontents + shortNames: + - vsc + - vscs + singular: volumesnapshotcontent + scope: Cluster + versions: + - additionalPrinterColumns: + - description: Indicates if the snapshot is ready to be used to restore a volume. + jsonPath: .status.readyToUse + name: ReadyToUse + type: boolean + - description: Represents the complete size of the snapshot in bytes + jsonPath: .status.restoreSize + name: RestoreSize + type: integer + - description: Determines whether this VolumeSnapshotContent and its physical + snapshot on the underlying storage system should be deleted when its bound + VolumeSnapshot is deleted. + jsonPath: .spec.deletionPolicy + name: DeletionPolicy + type: string + - description: Name of the CSI driver used to create the physical snapshot on + the underlying storage system. + jsonPath: .spec.driver + name: Driver + type: string + - description: Name of the VolumeSnapshotClass to which this snapshot belongs. + jsonPath: .spec.volumeSnapshotClassName + name: VolumeSnapshotClass + type: string + - description: Name of the VolumeSnapshot object to which this VolumeSnapshotContent + object is bound. + jsonPath: .spec.volumeSnapshotRef.name + name: VolumeSnapshot + type: string + - description: Namespace of the VolumeSnapshot object to which this VolumeSnapshotContent + object is bound. + jsonPath: .spec.volumeSnapshotRef.namespace + name: VolumeSnapshotNamespace + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: |- + VolumeSnapshotContent represents the actual "on-disk" snapshot object in the + underlying storage system + 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 properties of a VolumeSnapshotContent created by the underlying storage system. + Required. + properties: + deletionPolicy: + description: |- + deletionPolicy determines whether this VolumeSnapshotContent and its physical snapshot on + the underlying storage system should be deleted when its bound VolumeSnapshot is deleted. + Supported values are "Retain" and "Delete". + "Retain" means that the VolumeSnapshotContent and its physical snapshot on underlying storage system are kept. + "Delete" means that the VolumeSnapshotContent and its physical snapshot on underlying storage system are deleted. + For dynamically provisioned snapshots, this field will automatically be filled in by the + CSI snapshotter sidecar with the "DeletionPolicy" field defined in the corresponding + VolumeSnapshotClass. + For pre-existing snapshots, users MUST specify this field when creating the + VolumeSnapshotContent object. + Required. + enum: + - Delete + - Retain + type: string + driver: + description: |- + driver is the name of the CSI driver used to create the physical snapshot on + the underlying storage system. + This MUST be the same as the name returned by the CSI GetPluginName() call for + that driver. + Required. + type: string + source: + description: |- + source specifies whether the snapshot is (or should be) dynamically provisioned + or already exists, and just requires a Kubernetes object representation. + This field is immutable after creation. + Required. + properties: + snapshotHandle: + description: |- + snapshotHandle specifies the CSI "snapshot_id" of a pre-existing snapshot on + the underlying storage system for which a Kubernetes object representation + was (or should be) created. + This field is immutable. + type: string + x-kubernetes-validations: + - message: snapshotHandle is immutable + rule: self == oldSelf + volumeHandle: + description: |- + volumeHandle specifies the CSI "volume_id" of the volume from which a snapshot + should be dynamically taken from. + This field is immutable. + type: string + x-kubernetes-validations: + - message: volumeHandle is immutable + rule: self == oldSelf + type: object + x-kubernetes-validations: + - message: volumeHandle is required once set + rule: '!has(oldSelf.volumeHandle) || has(self.volumeHandle)' + - message: snapshotHandle is required once set + rule: '!has(oldSelf.snapshotHandle) || has(self.snapshotHandle)' + - message: exactly one of volumeHandle and snapshotHandle must be + set + rule: (has(self.volumeHandle) && !has(self.snapshotHandle)) || (!has(self.volumeHandle) + && has(self.snapshotHandle)) + sourceVolumeMode: + description: |- + SourceVolumeMode is the mode of the volume whose snapshot is taken. + Can be either “Filesystem” or “Block”. + If not specified, it indicates the source volume's mode is unknown. + This field is immutable. + This field is an alpha field. + type: string + x-kubernetes-validations: + - message: sourceVolumeMode is immutable + rule: self == oldSelf + volumeSnapshotClassName: + description: |- + name of the VolumeSnapshotClass from which this snapshot was (or will be) + created. + Note that after provisioning, the VolumeSnapshotClass may be deleted or + recreated with different set of values, and as such, should not be referenced + post-snapshot creation. + type: string + volumeSnapshotRef: + description: |- + volumeSnapshotRef specifies the VolumeSnapshot object to which this + VolumeSnapshotContent object is bound. + VolumeSnapshot.Spec.VolumeSnapshotContentName field must reference to + this VolumeSnapshotContent's name for the bidirectional binding to be valid. + For a pre-existing VolumeSnapshotContent object, name and namespace of the + VolumeSnapshot object MUST be provided for binding to happen. + This field is immutable after creation. + Required. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: |- + If referring to a piece of an object instead of an entire object, this string + should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within a pod, this would take on a value like: + "spec.containers{name}" (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to have some well-defined way of + referencing a part of an object. + TODO: this design is not final and this field is subject to change in the future. + type: string + kind: + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + namespace: + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + type: string + resourceVersion: + description: |- + Specific resourceVersion to which this reference is made, if any. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + type: string + uid: + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids + type: string + type: object + x-kubernetes-map-type: atomic + x-kubernetes-validations: + - message: both spec.volumeSnapshotRef.name and spec.volumeSnapshotRef.namespace + must be set + rule: has(self.name) && has(self.__namespace__) + required: + - deletionPolicy + - driver + - source + - volumeSnapshotRef + type: object + x-kubernetes-validations: + - message: sourceVolumeMode is required once set + rule: '!has(oldSelf.sourceVolumeMode) || has(self.sourceVolumeMode)' + status: + description: status represents the current information of a snapshot. + properties: + creationTime: + description: |- + creationTime is the timestamp when the point-in-time snapshot is taken + by the underlying storage system. + In dynamic snapshot creation case, this field will be filled in by the + CSI snapshotter sidecar with the "creation_time" value returned from CSI + "CreateSnapshot" gRPC call. + For a pre-existing snapshot, this field will be filled with the "creation_time" + value returned from the CSI "ListSnapshots" gRPC call if the driver supports it. + If not specified, it indicates the creation time is unknown. + The format of this field is a Unix nanoseconds time encoded as an int64. + On Unix, the command `date +%s%N` returns the current time in nanoseconds + since 1970-01-01 00:00:00 UTC. + format: int64 + type: integer + error: + description: |- + error is the last observed error during snapshot creation, if any. + Upon success after retry, this error field will be cleared. + properties: + message: + description: |- + message is a string detailing the encountered error during snapshot + creation if specified. + NOTE: message may be logged, and it should not contain sensitive + information. + type: string + time: + description: time is the timestamp when the error was encountered. + format: date-time + type: string + type: object + readyToUse: + description: |- + readyToUse indicates if a snapshot is ready to be used to restore a volume. + In dynamic snapshot creation case, this field will be filled in by the + CSI snapshotter sidecar with the "ready_to_use" value returned from CSI + "CreateSnapshot" gRPC call. + For a pre-existing snapshot, this field will be filled with the "ready_to_use" + value returned from the CSI "ListSnapshots" gRPC call if the driver supports it, + otherwise, this field will be set to "True". + If not specified, it means the readiness of a snapshot is unknown. + type: boolean + restoreSize: + description: |- + restoreSize represents the complete size of the snapshot in bytes. + In dynamic snapshot creation case, this field will be filled in by the + CSI snapshotter sidecar with the "size_bytes" value returned from CSI + "CreateSnapshot" gRPC call. + For a pre-existing snapshot, this field will be filled with the "size_bytes" + value returned from the CSI "ListSnapshots" gRPC call if the driver supports it. + When restoring a volume from this snapshot, the size of the volume MUST NOT + be smaller than the restoreSize if it is specified, otherwise the restoration will fail. + If not specified, it indicates that the size is unknown. + format: int64 + minimum: 0 + type: integer + snapshotHandle: + description: |- + snapshotHandle is the CSI "snapshot_id" of a snapshot on the underlying storage system. + If not specified, it indicates that dynamic snapshot creation has either failed + or it is still in progress. + type: string + volumeGroupSnapshotHandle: + description: |- + VolumeGroupSnapshotHandle is the CSI "group_snapshot_id" of a group snapshot + on the underlying storage system. + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - description: Indicates if the snapshot is ready to be used to restore a volume. + jsonPath: .status.readyToUse + name: ReadyToUse + type: boolean + - description: Represents the complete size of the snapshot in bytes + jsonPath: .status.restoreSize + name: RestoreSize + type: integer + - description: Determines whether this VolumeSnapshotContent and its physical snapshot on the underlying storage system should be deleted when its bound VolumeSnapshot is deleted. + jsonPath: .spec.deletionPolicy + name: DeletionPolicy + type: string + - description: Name of the CSI driver used to create the physical snapshot on the underlying storage system. + jsonPath: .spec.driver + name: Driver + type: string + - description: Name of the VolumeSnapshotClass to which this snapshot belongs. + jsonPath: .spec.volumeSnapshotClassName + name: VolumeSnapshotClass + type: string + - description: Name of the VolumeSnapshot object to which this VolumeSnapshotContent object is bound. + jsonPath: .spec.volumeSnapshotRef.name + name: VolumeSnapshot + type: string + - description: Namespace of the VolumeSnapshot object to which this VolumeSnapshotContent object is bound. + jsonPath: .spec.volumeSnapshotRef.namespace + name: VolumeSnapshotNamespace + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + # This indicates the v1beta1 version of the custom resource is deprecated. + # API requests to this version receive a warning in the server response. + deprecated: true + # This overrides the default warning returned to clients making v1beta1 API requests. + deprecationWarning: "snapshot.storage.k8s.io/v1beta1 VolumeSnapshotContent is deprecated; use snapshot.storage.k8s.io/v1 VolumeSnapshotContent" + schema: + openAPIV3Schema: + description: VolumeSnapshotContent represents the actual "on-disk" snapshot object in the underlying storage system + 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 + spec: + description: spec defines properties of a VolumeSnapshotContent created by the underlying storage system. Required. + properties: + deletionPolicy: + description: deletionPolicy determines whether this VolumeSnapshotContent and its physical snapshot on the underlying storage system should be deleted when its bound VolumeSnapshot is deleted. Supported values are "Retain" and "Delete". "Retain" means that the VolumeSnapshotContent and its physical snapshot on underlying storage system are kept. "Delete" means that the VolumeSnapshotContent and its physical snapshot on underlying storage system are deleted. For dynamically provisioned snapshots, this field will automatically be filled in by the CSI snapshotter sidecar with the "DeletionPolicy" field defined in the corresponding VolumeSnapshotClass. For pre-existing snapshots, users MUST specify this field when creating the VolumeSnapshotContent object. Required. + enum: + - Delete + - Retain + type: string + driver: + description: driver is the name of the CSI driver used to create the physical snapshot on the underlying storage system. This MUST be the same as the name returned by the CSI GetPluginName() call for that driver. Required. + type: string + source: + description: source specifies whether the snapshot is (or should be) dynamically provisioned or already exists, and just requires a Kubernetes object representation. This field is immutable after creation. Required. + properties: + snapshotHandle: + description: snapshotHandle specifies the CSI "snapshot_id" of a pre-existing snapshot on the underlying storage system for which a Kubernetes object representation was (or should be) created. This field is immutable. + type: string + volumeHandle: + description: volumeHandle specifies the CSI "volume_id" of the volume from which a snapshot should be dynamically taken from. This field is immutable. + type: string + type: object + volumeSnapshotClassName: + description: name of the VolumeSnapshotClass from which this snapshot was (or will be) created. Note that after provisioning, the VolumeSnapshotClass may be deleted or recreated with different set of values, and as such, should not be referenced post-snapshot creation. + type: string + volumeSnapshotRef: + description: volumeSnapshotRef specifies the VolumeSnapshot object to which this VolumeSnapshotContent object is bound. VolumeSnapshot.Spec.VolumeSnapshotContentName field must reference to this VolumeSnapshotContent's name for the bidirectional binding to be valid. For a pre-existing VolumeSnapshotContent object, name and namespace of the VolumeSnapshot object MUST be provided for binding to happen. This field is immutable after creation. Required. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: "spec.containers{name}" (where "name" refers to the name of the container that triggered the event) or if no container name is specified "spec.containers[2]" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object. TODO: this design is not final and this field is subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + required: + - deletionPolicy + - driver + - source + - volumeSnapshotRef + type: object + status: + description: status represents the current information of a snapshot. + properties: + creationTime: + description: creationTime is the timestamp when the point-in-time snapshot is taken by the underlying storage system. In dynamic snapshot creation case, this field will be filled in by the CSI snapshotter sidecar with the "creation_time" value returned from CSI "CreateSnapshot" gRPC call. For a pre-existing snapshot, this field will be filled with the "creation_time" value returned from the CSI "ListSnapshots" gRPC call if the driver supports it. If not specified, it indicates the creation time is unknown. The format of this field is a Unix nanoseconds time encoded as an int64. On Unix, the command `date +%s%N` returns the current time in nanoseconds since 1970-01-01 00:00:00 UTC. + format: int64 + type: integer + error: + description: error is the last observed error during snapshot creation, if any. Upon success after retry, this error field will be cleared. + properties: + message: + description: 'message is a string detailing the encountered error during snapshot creation if specified. NOTE: message may be logged, and it should not contain sensitive information.' + type: string + time: + description: time is the timestamp when the error was encountered. + format: date-time + type: string + type: object + readyToUse: + description: readyToUse indicates if a snapshot is ready to be used to restore a volume. In dynamic snapshot creation case, this field will be filled in by the CSI snapshotter sidecar with the "ready_to_use" value returned from CSI "CreateSnapshot" gRPC call. For a pre-existing snapshot, this field will be filled with the "ready_to_use" value returned from the CSI "ListSnapshots" gRPC call if the driver supports it, otherwise, this field will be set to "True". If not specified, it means the readiness of a snapshot is unknown. + type: boolean + restoreSize: + description: restoreSize represents the complete size of the snapshot in bytes. In dynamic snapshot creation case, this field will be filled in by the CSI snapshotter sidecar with the "size_bytes" value returned from CSI "CreateSnapshot" gRPC call. For a pre-existing snapshot, this field will be filled with the "size_bytes" value returned from the CSI "ListSnapshots" gRPC call if the driver supports it. When restoring a volume from this snapshot, the size of the volume MUST NOT be smaller than the restoreSize if it is specified, otherwise the restoration will fail. If not specified, it indicates that the size is unknown. + format: int64 + minimum: 0 + type: integer + snapshotHandle: + description: snapshotHandle is the CSI "snapshot_id" of a snapshot on the underlying storage system. If not specified, it indicates that dynamic snapshot creation has either failed or it is still in progress. + type: string + type: object + required: + - spec + type: object + served: false + storage: false + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/packages/system/vsnap-crd/templates/volumesnapshots.yaml b/packages/system/vsnap-crd/templates/volumesnapshots.yaml new file mode 100644 index 00000000..6b96d708 --- /dev/null +++ b/packages/system/vsnap-crd/templates/volumesnapshots.yaml @@ -0,0 +1,351 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + api-approved.kubernetes.io: "https://github.com/kubernetes-csi/external-snapshotter/pull/814" + name: volumesnapshots.snapshot.storage.k8s.io +spec: + group: snapshot.storage.k8s.io + names: + kind: VolumeSnapshot + listKind: VolumeSnapshotList + plural: volumesnapshots + shortNames: + - vs + singular: volumesnapshot + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Indicates if the snapshot is ready to be used to restore a volume. + jsonPath: .status.readyToUse + name: ReadyToUse + type: boolean + - description: If a new snapshot needs to be created, this contains the name of + the source PVC from which this snapshot was (or will be) created. + jsonPath: .spec.source.persistentVolumeClaimName + name: SourcePVC + type: string + - description: If a snapshot already exists, this contains the name of the existing + VolumeSnapshotContent object representing the existing snapshot. + jsonPath: .spec.source.volumeSnapshotContentName + name: SourceSnapshotContent + type: string + - description: Represents the minimum size of volume required to rehydrate from + this snapshot. + jsonPath: .status.restoreSize + name: RestoreSize + type: string + - description: The name of the VolumeSnapshotClass requested by the VolumeSnapshot. + jsonPath: .spec.volumeSnapshotClassName + name: SnapshotClass + type: string + - description: Name of the VolumeSnapshotContent object to which the VolumeSnapshot + object intends to bind to. Please note that verification of binding actually + requires checking both VolumeSnapshot and VolumeSnapshotContent to ensure + both are pointing at each other. Binding MUST be verified prior to usage of + this object. + jsonPath: .status.boundVolumeSnapshotContentName + name: SnapshotContent + type: string + - description: Timestamp when the point-in-time snapshot was taken by the underlying + storage system. + jsonPath: .status.creationTime + name: CreationTime + type: date + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: |- + VolumeSnapshot is a user's request for either creating a point-in-time + snapshot of a persistent volume, or binding to a pre-existing snapshot. + 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 characteristics of a snapshot requested by a user. + More info: https://kubernetes.io/docs/concepts/storage/volume-snapshots#volumesnapshots + Required. + properties: + source: + description: |- + source specifies where a snapshot will be created from. + This field is immutable after creation. + Required. + properties: + persistentVolumeClaimName: + description: |- + persistentVolumeClaimName specifies the name of the PersistentVolumeClaim + object representing the volume from which a snapshot should be created. + This PVC is assumed to be in the same namespace as the VolumeSnapshot + object. + This field should be set if the snapshot does not exists, and needs to be + created. + This field is immutable. + type: string + x-kubernetes-validations: + - message: persistentVolumeClaimName is immutable + rule: self == oldSelf + volumeSnapshotContentName: + description: |- + volumeSnapshotContentName specifies the name of a pre-existing VolumeSnapshotContent + object representing an existing volume snapshot. + This field should be set if the snapshot already exists and only needs a representation in Kubernetes. + This field is immutable. + type: string + x-kubernetes-validations: + - message: volumeSnapshotContentName is immutable + rule: self == oldSelf + type: object + x-kubernetes-validations: + - message: persistentVolumeClaimName is required once set + rule: '!has(oldSelf.persistentVolumeClaimName) || has(self.persistentVolumeClaimName)' + - message: volumeSnapshotContentName is required once set + rule: '!has(oldSelf.volumeSnapshotContentName) || has(self.volumeSnapshotContentName)' + - message: exactly one of volumeSnapshotContentName and persistentVolumeClaimName + must be set + rule: (has(self.volumeSnapshotContentName) && !has(self.persistentVolumeClaimName)) + || (!has(self.volumeSnapshotContentName) && has(self.persistentVolumeClaimName)) + volumeSnapshotClassName: + description: |- + VolumeSnapshotClassName is the name of the VolumeSnapshotClass + requested by the VolumeSnapshot. + VolumeSnapshotClassName may be left nil to indicate that the default + SnapshotClass should be used. + A given cluster may have multiple default Volume SnapshotClasses: one + default per CSI Driver. If a VolumeSnapshot does not specify a SnapshotClass, + VolumeSnapshotSource will be checked to figure out what the associated + CSI Driver is, and the default VolumeSnapshotClass associated with that + CSI Driver will be used. If more than one VolumeSnapshotClass exist for + a given CSI Driver and more than one have been marked as default, + CreateSnapshot will fail and generate an event. + Empty string is not allowed for this field. + type: string + x-kubernetes-validations: + - message: volumeSnapshotClassName must not be the empty string when + set + rule: size(self) > 0 + required: + - source + type: object + status: + description: |- + status represents the current information of a snapshot. + Consumers must verify binding between VolumeSnapshot and + VolumeSnapshotContent objects is successful (by validating that both + VolumeSnapshot and VolumeSnapshotContent point at each other) before + using this object. + properties: + boundVolumeSnapshotContentName: + description: |- + boundVolumeSnapshotContentName is the name of the VolumeSnapshotContent + object to which this VolumeSnapshot object intends to bind to. + If not specified, it indicates that the VolumeSnapshot object has not been + successfully bound to a VolumeSnapshotContent object yet. + NOTE: To avoid possible security issues, consumers must verify binding between + VolumeSnapshot and VolumeSnapshotContent objects is successful (by validating that + both VolumeSnapshot and VolumeSnapshotContent point at each other) before using + this object. + type: string + creationTime: + description: |- + creationTime is the timestamp when the point-in-time snapshot is taken + by the underlying storage system. + In dynamic snapshot creation case, this field will be filled in by the + snapshot controller with the "creation_time" value returned from CSI + "CreateSnapshot" gRPC call. + For a pre-existing snapshot, this field will be filled with the "creation_time" + value returned from the CSI "ListSnapshots" gRPC call if the driver supports it. + If not specified, it may indicate that the creation time of the snapshot is unknown. + format: date-time + type: string + error: + description: |- + error is the last observed error during snapshot creation, if any. + This field could be helpful to upper level controllers(i.e., application controller) + to decide whether they should continue on waiting for the snapshot to be created + based on the type of error reported. + The snapshot controller will keep retrying when an error occurs during the + snapshot creation. Upon success, this error field will be cleared. + properties: + message: + description: |- + message is a string detailing the encountered error during snapshot + creation if specified. + NOTE: message may be logged, and it should not contain sensitive + information. + type: string + time: + description: time is the timestamp when the error was encountered. + format: date-time + type: string + type: object + readyToUse: + description: |- + readyToUse indicates if the snapshot is ready to be used to restore a volume. + In dynamic snapshot creation case, this field will be filled in by the + snapshot controller with the "ready_to_use" value returned from CSI + "CreateSnapshot" gRPC call. + For a pre-existing snapshot, this field will be filled with the "ready_to_use" + value returned from the CSI "ListSnapshots" gRPC call if the driver supports it, + otherwise, this field will be set to "True". + If not specified, it means the readiness of a snapshot is unknown. + type: boolean + restoreSize: + type: string + description: |- + restoreSize represents the minimum size of volume required to create a volume + from this snapshot. + In dynamic snapshot creation case, this field will be filled in by the + snapshot controller with the "size_bytes" value returned from CSI + "CreateSnapshot" gRPC call. + For a pre-existing snapshot, this field will be filled with the "size_bytes" + value returned from the CSI "ListSnapshots" gRPC call if the driver supports it. + When restoring a volume from this snapshot, the size of the volume MUST NOT + be smaller than the restoreSize if it is specified, otherwise the restoration will fail. + If not specified, it indicates that the size is unknown. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + volumeGroupSnapshotName: + description: |- + VolumeGroupSnapshotName is the name of the VolumeGroupSnapshot of which this + VolumeSnapshot is a part of. + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - description: Indicates if the snapshot is ready to be used to restore a volume. + jsonPath: .status.readyToUse + name: ReadyToUse + type: boolean + - description: If a new snapshot needs to be created, this contains the name of the source PVC from which this snapshot was (or will be) created. + jsonPath: .spec.source.persistentVolumeClaimName + name: SourcePVC + type: string + - description: If a snapshot already exists, this contains the name of the existing VolumeSnapshotContent object representing the existing snapshot. + jsonPath: .spec.source.volumeSnapshotContentName + name: SourceSnapshotContent + type: string + - description: Represents the minimum size of volume required to rehydrate from this snapshot. + jsonPath: .status.restoreSize + name: RestoreSize + type: string + - description: The name of the VolumeSnapshotClass requested by the VolumeSnapshot. + jsonPath: .spec.volumeSnapshotClassName + name: SnapshotClass + type: string + - description: Name of the VolumeSnapshotContent object to which the VolumeSnapshot object intends to bind to. Please note that verification of binding actually requires checking both VolumeSnapshot and VolumeSnapshotContent to ensure both are pointing at each other. Binding MUST be verified prior to usage of this object. + jsonPath: .status.boundVolumeSnapshotContentName + name: SnapshotContent + type: string + - description: Timestamp when the point-in-time snapshot was taken by the underlying storage system. + jsonPath: .status.creationTime + name: CreationTime + type: date + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + # This indicates the v1beta1 version of the custom resource is deprecated. + # API requests to this version receive a warning in the server response. + deprecated: true + # This overrides the default warning returned to clients making v1beta1 API requests. + deprecationWarning: "snapshot.storage.k8s.io/v1beta1 VolumeSnapshot is deprecated; use snapshot.storage.k8s.io/v1 VolumeSnapshot" + schema: + openAPIV3Schema: + description: VolumeSnapshot is a user's request for either creating a point-in-time snapshot of a persistent volume, or binding to a pre-existing snapshot. + 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 + spec: + description: 'spec defines the desired characteristics of a snapshot requested by a user. More info: https://kubernetes.io/docs/concepts/storage/volume-snapshots#volumesnapshots Required.' + properties: + source: + description: source specifies where a snapshot will be created from. This field is immutable after creation. Required. + properties: + persistentVolumeClaimName: + description: persistentVolumeClaimName specifies the name of the PersistentVolumeClaim object representing the volume from which a snapshot should be created. This PVC is assumed to be in the same namespace as the VolumeSnapshot object. This field should be set if the snapshot does not exists, and needs to be created. This field is immutable. + type: string + volumeSnapshotContentName: + description: volumeSnapshotContentName specifies the name of a pre-existing VolumeSnapshotContent object representing an existing volume snapshot. This field should be set if the snapshot already exists and only needs a representation in Kubernetes. This field is immutable. + type: string + type: object + volumeSnapshotClassName: + description: 'VolumeSnapshotClassName is the name of the VolumeSnapshotClass requested by the VolumeSnapshot. VolumeSnapshotClassName may be left nil to indicate that the default SnapshotClass should be used. A given cluster may have multiple default Volume SnapshotClasses: one default per CSI Driver. If a VolumeSnapshot does not specify a SnapshotClass, VolumeSnapshotSource will be checked to figure out what the associated CSI Driver is, and the default VolumeSnapshotClass associated with that CSI Driver will be used. If more than one VolumeSnapshotClass exist for a given CSI Driver and more than one have been marked as default, CreateSnapshot will fail and generate an event. Empty string is not allowed for this field.' + type: string + required: + - source + type: object + status: + description: status represents the current information of a snapshot. Consumers must verify binding between VolumeSnapshot and VolumeSnapshotContent objects is successful (by validating that both VolumeSnapshot and VolumeSnapshotContent point at each other) before using this object. + properties: + boundVolumeSnapshotContentName: + description: 'boundVolumeSnapshotContentName is the name of the VolumeSnapshotContent object to which this VolumeSnapshot object intends to bind to. If not specified, it indicates that the VolumeSnapshot object has not been successfully bound to a VolumeSnapshotContent object yet. NOTE: To avoid possible security issues, consumers must verify binding between VolumeSnapshot and VolumeSnapshotContent objects is successful (by validating that both VolumeSnapshot and VolumeSnapshotContent point at each other) before using this object.' + type: string + creationTime: + description: creationTime is the timestamp when the point-in-time snapshot is taken by the underlying storage system. In dynamic snapshot creation case, this field will be filled in by the snapshot controller with the "creation_time" value returned from CSI "CreateSnapshot" gRPC call. For a pre-existing snapshot, this field will be filled with the "creation_time" value returned from the CSI "ListSnapshots" gRPC call if the driver supports it. If not specified, it may indicate that the creation time of the snapshot is unknown. + format: date-time + type: string + error: + description: error is the last observed error during snapshot creation, if any. This field could be helpful to upper level controllers(i.e., application controller) to decide whether they should continue on waiting for the snapshot to be created based on the type of error reported. The snapshot controller will keep retrying when an error occurs during the snapshot creation. Upon success, this error field will be cleared. + properties: + message: + description: 'message is a string detailing the encountered error during snapshot creation if specified. NOTE: message may be logged, and it should not contain sensitive information.' + type: string + time: + description: time is the timestamp when the error was encountered. + format: date-time + type: string + type: object + readyToUse: + description: readyToUse indicates if the snapshot is ready to be used to restore a volume. In dynamic snapshot creation case, this field will be filled in by the snapshot controller with the "ready_to_use" value returned from CSI "CreateSnapshot" gRPC call. For a pre-existing snapshot, this field will be filled with the "ready_to_use" value returned from the CSI "ListSnapshots" gRPC call if the driver supports it, otherwise, this field will be set to "True". If not specified, it means the readiness of a snapshot is unknown. + type: boolean + restoreSize: + type: string + description: restoreSize represents the minimum size of volume required to create a volume from this snapshot. In dynamic snapshot creation case, this field will be filled in by the snapshot controller with the "size_bytes" value returned from CSI "CreateSnapshot" gRPC call. For a pre-existing snapshot, this field will be filled with the "size_bytes" value returned from the CSI "ListSnapshots" gRPC call if the driver supports it. When restoring a volume from this snapshot, the size of the volume MUST NOT be smaller than the restoreSize if it is specified, otherwise the restoration will fail. If not specified, it indicates that the size is unknown. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + required: + - spec + type: object + served: false + storage: false + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/packages/tests/cozy-lib-tests/.helmignore b/packages/tests/cozy-lib-tests/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/packages/tests/cozy-lib-tests/.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/apps/mysql/Chart.yaml b/packages/tests/cozy-lib-tests/Chart.yaml similarity index 90% rename from packages/apps/mysql/Chart.yaml rename to packages/tests/cozy-lib-tests/Chart.yaml index 449fb6a4..e18a84bf 100644 --- a/packages/apps/mysql/Chart.yaml +++ b/packages/tests/cozy-lib-tests/Chart.yaml @@ -1,7 +1,6 @@ apiVersion: v2 -name: mysql -description: Managed MariaDB service -icon: /logos/mariadb.svg +name: quota +description: Testing chart for cozy-lib # A chart can be either an 'application' or a 'library' chart. # @@ -16,10 +15,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.1.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: "11.0.2" +appVersion: "1.16.0" diff --git a/packages/tests/cozy-lib-tests/Makefile b/packages/tests/cozy-lib-tests/Makefile new file mode 100644 index 00000000..dec17a5f --- /dev/null +++ b/packages/tests/cozy-lib-tests/Makefile @@ -0,0 +1,2 @@ +test: + helm unittest . diff --git a/packages/tests/cozy-lib-tests/charts/cozy-lib b/packages/tests/cozy-lib-tests/charts/cozy-lib new file mode 120000 index 00000000..e1813509 --- /dev/null +++ b/packages/tests/cozy-lib-tests/charts/cozy-lib @@ -0,0 +1 @@ +../../../library/cozy-lib \ No newline at end of file diff --git a/packages/tests/cozy-lib-tests/templates/tests/quota.yaml b/packages/tests/cozy-lib-tests/templates/tests/quota.yaml new file mode 100644 index 00000000..10dd8a04 --- /dev/null +++ b/packages/tests/cozy-lib-tests/templates/tests/quota.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ResourceQuota +metadata: + name: {{ .Release.Name }} +spec: +{{- with .Values.quota }} + hard: {{- include "cozy-lib.resources.flatten" (list . $) | nindent 4 }} +{{- end }} diff --git a/packages/tests/cozy-lib-tests/tests/quota_test.yaml b/packages/tests/cozy-lib-tests/tests/quota_test.yaml new file mode 100644 index 00000000..0ba2260c --- /dev/null +++ b/packages/tests/cozy-lib-tests/tests/quota_test.yaml @@ -0,0 +1,50 @@ +# ./tests/quota_test.yaml +suite: quota helper + +templates: + - templates/tests/quota.yaml + +tests: + - it: correctly interprets special kubernetes quota types + values: + - quota_values.yaml + + release: + name: myrelease + namespace: default + revision: 1 + isUpgrade: false + + asserts: + - equal: + path: spec.hard["limits.cpu"] + value: "20" + + - equal: + path: spec.hard["requests.cpu"] + value: "2" + + - equal: + path: spec.hard["limits.foobar"] + value: "3" + + - equal: + path: spec.hard["requests.foobar"] + value: "3" + + - equal: + path: spec.hard["services.loadbalancers"] + value: "2" + + - equal: + path: spec.hard["requests.storage"] + value: "5Gi" + + - notExists: + path: spec.hard["limits.storage"] + + - notExists: + path: spec.hard["limits.services.loadbalancers"] + + - notExists: + path: spec.hard["requests.services.loadbalancers"] diff --git a/packages/tests/cozy-lib-tests/tests/quota_values.yaml b/packages/tests/cozy-lib-tests/tests/quota_values.yaml new file mode 100644 index 00000000..87e5cf17 --- /dev/null +++ b/packages/tests/cozy-lib-tests/tests/quota_values.yaml @@ -0,0 +1,8 @@ +quota: + services.loadbalancers: "2" + cpu: "20" + storage: "5Gi" + foobar: "3" + +_cluster: {} +_namespace: {} diff --git a/pkg/apis/apps/fuzzer/fuzzer.go b/pkg/apis/apps/fuzzer/fuzzer.go index fd744ed6..c92c5799 100644 --- a/pkg/apis/apps/fuzzer/fuzzer.go +++ b/pkg/apis/apps/fuzzer/fuzzer.go @@ -17,7 +17,7 @@ limitations under the License. package fuzzer import ( - "github.com/cozystack/cozystack/pkg/apis/apps" + "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" fuzz "github.com/google/gofuzz" runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" @@ -26,7 +26,7 @@ import ( // Funcs returns the fuzzer functions for the apps api group. var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} { return []interface{}{ - func(s *apps.ApplicationSpec, c fuzz.Continue) { + func(s *v1alpha1.Application, c fuzz.Continue) { c.FuzzNoCustom(s) // fuzz self without calling this function again }, } diff --git a/pkg/apis/apps/v1alpha1/register.go b/pkg/apis/apps/v1alpha1/register.go index a1b2586f..e112e1eb 100644 --- a/pkg/apis/apps/v1alpha1/register.go +++ b/pkg/apis/apps/v1alpha1/register.go @@ -1,18 +1,5 @@ -/* -Copyright 2024 The Cozystack Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 The Cozystack Authors. package v1alpha1 @@ -24,46 +11,50 @@ import ( "k8s.io/klog/v2" ) -// GroupName holds the API group name. +// ----------------------------------------------------------------------------- +// Group / version boiler-plate +// ----------------------------------------------------------------------------- + +// GroupName is the API group for every resource in this package. const GroupName = "apps.cozystack.io" -var ( - RegisteredGVKs []schema.GroupVersionKind -) - -// SchemeGroupVersion is group version used to register these objects +// SchemeGroupVersion is the canonical {group,version} for v1alpha1. var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} +// ----------------------------------------------------------------------------- +// Scheme registration helpers +// ----------------------------------------------------------------------------- + var ( - // SchemeBuilder allows to add this group to a scheme. - // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. - // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + // SchemeBuilder is used by generated deepcopy code. SchemeBuilder runtime.SchemeBuilder localSchemeBuilder = &SchemeBuilder - - // AddToScheme adds this group to a scheme. - AddToScheme = localSchemeBuilder.AddToScheme + AddToScheme = localSchemeBuilder.AddToScheme ) func init() { - // We only register manually written functions here. The registration of the - // generated functions takes place in the generated files. The separation - // makes the code compile even when the generated files are missing. + // Manually-written types go here. Generated deepcopy code is wired in + // via `zz_generated.deepcopy.go`. localSchemeBuilder.Register(addKnownTypes) } -// Adds the list of known types to the given scheme. +// addKnownTypes is called from init(). func addKnownTypes(scheme *runtime.Scheme) error { metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil } -// Resource takes an unqualified resource and returns a Group qualified GroupResource +// Resource turns an unqualified resource name into a fully-qualified one. func Resource(resource string) schema.GroupResource { return SchemeGroupVersion.WithResource(resource).GroupResource() } -// RegisterDynamicTypes registers types dynamically based on config +// ----------------------------------------------------------------------------- +// Public helpers consumed by the apiserver wiring +// ----------------------------------------------------------------------------- + +// RegisterDynamicTypes adds per-tenant “Application” kinds that are only known +// at runtime from a config file. func RegisterDynamicTypes(scheme *runtime.Scheme, cfg *config.ResourceConfig) error { for _, res := range cfg.Resources { kind := res.Application.Kind @@ -76,9 +67,7 @@ func RegisterDynamicTypes(scheme *runtime.Scheme, cfg *config.ResourceConfig) er scheme.AddKnownTypeWithName(gvkInternal, &Application{}) scheme.AddKnownTypeWithName(gvkInternal.GroupVersion().WithKind(kind+"List"), &ApplicationList{}) - klog.V(1).Infof("Registered kind: %s\n", kind) - RegisteredGVKs = append(RegisteredGVKs, gvk) + klog.V(1).Infof("Registered dynamic kind: %s", kind) } - return nil } diff --git a/pkg/apis/apps/v1alpha1/types.go b/pkg/apis/apps/v1alpha1/types.go index 5a21d270..3332ce55 100644 --- a/pkg/apis/apps/v1alpha1/types.go +++ b/pkg/apis/apps/v1alpha1/types.go @@ -21,6 +21,13 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// Application label keys used to identify and filter HelmReleases +const ( + ApplicationKindLabel = "apps.cozystack.io/application.kind" + ApplicationGroupLabel = "apps.cozystack.io/application.group" + ApplicationNameLabel = "apps.cozystack.io/application.name" +) + // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // ApplicationList is a list of Application objects. @@ -37,6 +44,18 @@ type ApplicationStatus struct { // +optional Version string `json:"version,omitempty"` Conditions []metav1.Condition `json:"conditions,omitempty"` + // Namespace holds the computed namespace for Tenant applications. + // +optional + Namespace string `json:"namespace,omitempty"` + // ExternalIPsCount holds the number of LoadBalancer services with assigned external IPs for Tenant applications. + // +optional + ExternalIPsCount int32 `json:"externalIPsCount,omitempty"` +} + +// SchedulingClass returns the scheduling class requested by this Application. +// TODO: read from a dedicated Application field once the struct is extended. +func (in Application) SchedulingClass() string { + return "" } // GetConditions returns the status conditions of the object. diff --git a/pkg/apis/apps/validation/validation.go b/pkg/apis/apps/validation/validation.go index 84c20c54..d62f2f22 100644 --- a/pkg/apis/apps/validation/validation.go +++ b/pkg/apis/apps/validation/validation.go @@ -17,24 +17,59 @@ limitations under the License. package validation import ( - "github.com/cozystack/cozystack/pkg/apis/apps" + "regexp" + + k8svalidation "k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation/field" ) -// ValidateApplication validates a Application. -func ValidateApplication(f *apps.Application) field.ErrorList { +// TenantKind is the Application.Kind string that gates the tenant-specific +// name rules below. It must stay in sync with the `kind` field of the tenant +// ApplicationDefinition (packages/system/tenant-rd/cozyrds/tenant.yaml) which +// is the upstream source the aggregated API reads at startup via +// config.Application.Kind. +const TenantKind = "Tenant" + +// tenantNameRegex enforces alphanumeric-only tenant names that begin with a +// lowercase letter. This is stricter than DNS-1035 because the tenant Helm +// chart's tenant.name helper (packages/apps/tenant/templates/_helpers.tpl) +// splits Release.Name on "-" and fails unless the result is exactly +// ["tenant", ""]. Any dash inside would break that invariant at +// Helm template time, so the aggregated API must reject such names up-front +// with a specific error. Requiring a leading letter (rather than letting +// leading-digit names fall through to DNS-1035) keeps the error message +// tenant-specific for all invalid inputs. +var tenantNameRegex = regexp.MustCompile(`^[a-z][a-z0-9]*$`) + +// ValidateApplicationName validates that an Application name is acceptable for +// the given kind. All applications must conform to DNS-1035 because their +// names are used to create Kubernetes resources (Services, Namespaces, etc.) +// that require DNS-1035 compliance. Tenant applications additionally must be +// alphanumeric and begin with a lowercase letter because of the Helm chart +// constraint described on tenantNameRegex. +// Note: length validation is handled separately by validateNameLength in the +// REST handler, which computes dynamic limits based on Helm release prefix. +func ValidateApplicationName(name, kindName string, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} - allErrs = append(allErrs, ValidateApplicationSpec(&f.Spec, field.NewPath("spec"))...) - - return allErrs -} - -// ValidateApplicationSpec validates a ApplicationSpec. -func ValidateApplicationSpec(s *apps.ApplicationSpec, fldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - - // TODO validation + if len(name) == 0 { + allErrs = append(allErrs, field.Required(fldPath, "name is required")) + return allErrs + } + + // Tenant names must be alphanumeric starting with a letter — see + // tenantNameRegex comment for the reason. Check before DNS-1035 so the + // error message is specific to the tenant contract, not the generic DNS + // label rules. + if kindName == TenantKind && !tenantNameRegex.MatchString(name) { + allErrs = append(allErrs, field.Invalid(fldPath, name, + "tenant names must start with a lowercase letter and contain only lowercase letters and digits; dashes are not allowed")) + return allErrs + } + + for _, msg := range k8svalidation.IsDNS1035Label(name) { + allErrs = append(allErrs, field.Invalid(fldPath, name, msg)) + } return allErrs } diff --git a/pkg/apis/apps/validation/validation_test.go b/pkg/apis/apps/validation/validation_test.go new file mode 100644 index 00000000..7930f8ae --- /dev/null +++ b/pkg/apis/apps/validation/validation_test.go @@ -0,0 +1,174 @@ +/* +Copyright 2024 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validation + +import ( + "strings" + "testing" + + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func TestValidateApplicationName(t *testing.T) { + tests := []struct { + name string + appName string + kindName string + wantError bool + }{ + // Valid names (non-tenant kinds permit DNS-1035 including hyphens) + {"valid simple name", "tenant-one", "MySQL", false}, + {"valid single letter", "a", "MySQL", false}, + {"valid with numbers", "abc-123", "MySQL", false}, + {"valid lowercase", "my-tenant", "MySQL", false}, + {"valid long name", "my-very-long-tenant-name", "MySQL", false}, + {"valid double hyphen", "my--tenant", "MySQL", false}, + {"valid at DNS-1035 max (63 chars)", strings.Repeat("a", 63), "MySQL", false}, + {"valid with empty kind", "my-db", "", false}, + + // Invalid: starts with wrong character + {"starts with digit", "1john", "MySQL", true}, + {"only digits", "123", "MySQL", true}, + {"starts with hyphen", "-tenant", "MySQL", true}, + + // Invalid: ends with wrong character + {"ends with hyphen", "tenant-", "MySQL", true}, + + // Invalid: wrong characters + {"uppercase letters", "Tenant", "MySQL", true}, + {"mixed case", "myTenant", "MySQL", true}, + {"underscore", "my_tenant", "MySQL", true}, + {"dot", "my.tenant", "MySQL", true}, + {"space", "my tenant", "MySQL", true}, + {"unicode cyrillic", "тенант", "MySQL", true}, + {"unicode emoji", "tenant🚀", "MySQL", true}, + {"special chars", "tenant@home", "MySQL", true}, + {"colon", "tenant:one", "MySQL", true}, + {"slash", "tenant/one", "MySQL", true}, + + // Invalid: empty or whitespace + {"empty string", "", "MySQL", true}, + {"only spaces", " ", "MySQL", true}, + {"leading space", " tenant", "MySQL", true}, + {"trailing space", "tenant ", "MySQL", true}, + + // Invalid: exceeds DNS-1035 max length (63) + {"too long (64 chars)", strings.Repeat("a", 64), "MySQL", true}, + {"way too long (100 chars)", strings.Repeat("a", 100), "MySQL", true}, + + // Tenant kind: stricter alphanumeric-only rule. + // The tenant Helm chart's tenant.name helper (packages/apps/tenant/templates/_helpers.tpl) + // splits Release.Name on "-" and fails unless the result is exactly + // ["tenant", ""]. Any dash inside breaks that invariant, so + // the aggregated API must reject tenant names containing dashes up-front + // with a specific error — instead of letting Flux reconciliation fail later. + {"tenant alphanumeric simple", "foo", "Tenant", false}, + {"tenant alphanumeric with digits", "foo123", "Tenant", false}, + {"tenant single char", "a", "Tenant", false}, + {"tenant single hyphen", "foo-bar", "Tenant", true}, + {"tenant leading hyphen", "-foo", "Tenant", true}, + {"tenant trailing hyphen", "foo-", "Tenant", true}, + {"tenant double hyphen", "foo--bar", "Tenant", true}, + {"tenant uppercase", "Foo", "Tenant", true}, + {"tenant underscore", "foo_bar", "Tenant", true}, + {"tenant empty", "", "Tenant", true}, + // Leading digit must be caught by the tenant-specific regex (not by + // falling through to DNS-1035) so the error message reflects the + // tenant contract — see TestValidateApplicationName_TenantErrorMessage. + {"tenant leading digit", "123foo", "Tenant", true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + errs := ValidateApplicationName(tt.appName, tt.kindName, field.NewPath("metadata").Child("name")) + if (len(errs) > 0) != tt.wantError { + t.Errorf("ValidateApplicationName(%q, kind=%q) returned %d errors, wantError = %v, errors = %v", + tt.appName, tt.kindName, len(errs), tt.wantError, errs) + } + }) + } +} + +// TestValidateApplicationName_TenantErrorMessage pins the contract that when +// a tenant name is invalid, the returned error message is specific to the +// tenant naming rule — not the generic DNS-1035 message. Otherwise users get +// back "must start with an alphabetic character" or similar and have no way +// to know the constraint is tied to the tenant Helm chart. +func TestValidateApplicationName_TenantErrorMessage(t *testing.T) { + // Every tenant-invalid name below must surface a tenant-specific error + // message. In particular, "123foo" starts with a digit — the original + // implementation let that fall through to DNS-1035 with a generic error; + // the regex is tightened specifically so this case fails up-front. + invalidTenantNames := []string{ + "foo-bar", // dash + "-foo", // leading dash + "foo-", // trailing dash + "foo--bar", // double dash + "Foo", // uppercase + "foo_bar", // underscore + "foo.bar", // dot + "foo bar", // space + "123foo", // leading digit — must not fall through to DNS-1035 + } + + const wantSubstring = "tenant names must" + + for _, name := range invalidTenantNames { + t.Run(name, func(t *testing.T) { + errs := ValidateApplicationName(name, "Tenant", field.NewPath("metadata").Child("name")) + if len(errs) == 0 { + t.Fatalf("expected error for tenant name %q, got none", name) + } + if !strings.Contains(errs[0].Detail, wantSubstring) { + t.Errorf("tenant name %q: error detail = %q, want substring %q (generic DNS-1035 message is not tenant-specific)", + name, errs[0].Detail, wantSubstring) + } + }) + } +} + +// TestValidateApplicationName_TenantLengthFallthrough documents the one +// invalid-tenant case where the error message is intentionally NOT tenant- +// specific: when a name contains only valid tenant characters but exceeds +// the DNS-1035 63-char label limit, the length error comes from DNS-1035 +// because length is not a tenant-specific constraint (every application +// kind is subject to the same Kubernetes label limit). REST.validateNameLength +// further tightens the limit using the Helm release prefix, so tenants cannot +// actually reach 64 characters end-to-end — this test only pins the package- +// level fallthrough so a future refactor does not accidentally promote the +// length error into tenant-specific wording. +// +// NOTE: this is an architectural decision, not a user-facing requirement. +// If tenant length is ever promoted into a tenant-specific rule (e.g. to +// include the Helm release prefix budget in this package's error message), +// this test should be updated or deleted — it is not a backwards-compat +// guarantee, just a checkpoint on the current layering. +func TestValidateApplicationName_TenantLengthFallthrough(t *testing.T) { + name := strings.Repeat("a", 64) // valid tenant pattern, too long for DNS-1035 + + errs := ValidateApplicationName(name, "Tenant", field.NewPath("metadata").Child("name")) + if len(errs) == 0 { + t.Fatalf("expected DNS-1035 length error for 64-char tenant name, got none") + } + // This error is the generic DNS-1035 one, NOT the tenant-specific message. + // We deliberately do not assert against the exact upstream DNS-1035 text + // (that would tie this test to a k8s.io/apimachinery internal string and + // break on unrelated upstream wording changes). + if strings.Contains(errs[0].Detail, "tenant names must") { + t.Errorf("64-char tenant name should surface the generic DNS-1035 error, got tenant-specific: %q", errs[0].Detail) + } +} diff --git a/pkg/apis/core/fuzzer/fuzzer.go b/pkg/apis/core/fuzzer/fuzzer.go new file mode 100644 index 00000000..82a1b5ab --- /dev/null +++ b/pkg/apis/core/fuzzer/fuzzer.go @@ -0,0 +1,33 @@ +/* +Copyright 2024 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fuzzer + +import ( + "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + fuzz "github.com/google/gofuzz" + + runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" +) + +// Funcs returns the fuzzer functions for the core api group. +var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} { + return []interface{}{ + func(s *v1alpha1.TenantNamespace, c fuzz.Continue) { + c.FuzzNoCustom(s) // fuzz self without calling this function again + }, + } +} diff --git a/pkg/apis/core/install/install.go b/pkg/apis/core/install/install.go new file mode 100644 index 00000000..0f210eb2 --- /dev/null +++ b/pkg/apis/core/install/install.go @@ -0,0 +1,29 @@ +/* +Copyright 2024 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package install + +import ( + corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +// Install registers the API group and adds types to a scheme +func Install(scheme *runtime.Scheme) { + utilruntime.Must(corev1alpha1.AddToScheme(scheme)) + utilruntime.Must(scheme.SetVersionPriority(corev1alpha1.SchemeGroupVersion)) +} diff --git a/pkg/apis/core/install/roundtrip_test.go b/pkg/apis/core/install/roundtrip_test.go new file mode 100644 index 00000000..a11fa8d9 --- /dev/null +++ b/pkg/apis/core/install/roundtrip_test.go @@ -0,0 +1,30 @@ +/* +Copyright 2024 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package install + +import ( + "testing" + + corefuzzer "github.com/cozystack/cozystack/pkg/apis/core/fuzzer" + "k8s.io/apimachinery/pkg/api/apitesting/roundtrip" +) + +func TestRoundTripTypes(t *testing.T) { + roundtrip.RoundTripTestForAPIGroup(t, Install, corefuzzer.Funcs) + // TODO: enable protobuf generation for the sample-apiserver + // roundtrip.RoundTripProtobufTestForAPIGroup(t, Install, corefuzzer.Funcs) +} diff --git a/pkg/apis/core/register.go b/pkg/apis/core/register.go new file mode 100644 index 00000000..9739ffdb --- /dev/null +++ b/pkg/apis/core/register.go @@ -0,0 +1,22 @@ +/* +Copyright 2024 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package core + +// GroupName is the group name used in this package +const ( + GroupName = "core.cozystack.io" +) diff --git a/pkg/apis/core/v1alpha1/doc.go b/pkg/apis/core/v1alpha1/doc.go new file mode 100644 index 00000000..15b059be --- /dev/null +++ b/pkg/apis/core/v1alpha1/doc.go @@ -0,0 +1,25 @@ +/* +Copyright 2024 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package +// +k8s:conversion-gen=github.com/cozystack/cozystack/pkg/apis/core +// +k8s:conversion-gen=k8s.io/apiextensions-apiserver/pkg/apis/apiextensions +// +k8s:defaulter-gen=TypeMeta +// +groupName=core.cozystack.io + +// Package v1alpha1 is the v1alpha1 version of the API. +package v1alpha1 // import "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" diff --git a/pkg/apis/core/v1alpha1/register.go b/pkg/apis/core/v1alpha1/register.go new file mode 100644 index 00000000..84923d29 --- /dev/null +++ b/pkg/apis/core/v1alpha1/register.go @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 The Cozystack Authors. + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/klog/v2" +) + +// ----------------------------------------------------------------------------- +// Group / version boiler-plate +// ----------------------------------------------------------------------------- + +// GroupName is the API group for every resource in this package. +const GroupName = "core.cozystack.io" + +// SchemeGroupVersion is the canonical {group,version} for v1alpha1. +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} + +// ----------------------------------------------------------------------------- +// Scheme registration helpers +// ----------------------------------------------------------------------------- + +var ( + // SchemeBuilder is used by generated deepcopy code. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // Manually-written types go here. Generated deepcopy code is wired in + // via `zz_generated.deepcopy.go`. + localSchemeBuilder.Register(addKnownTypes) +} + +// addKnownTypes is called from init(). +func addKnownTypes(scheme *runtime.Scheme) error { + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} + +// Resource turns an unqualified resource name into a fully-qualified one. +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// ----------------------------------------------------------------------------- +// Public helpers consumed by the apiserver wiring +// ----------------------------------------------------------------------------- + +// RegisterStaticTypes adds *compile-time* resources such as TenantNamespace. +func RegisterStaticTypes(scheme *runtime.Scheme) { + scheme.AddKnownTypes(SchemeGroupVersion, + &TenantNamespace{}, + &TenantNamespaceList{}, + &TenantSecret{}, + &TenantSecretList{}, + &TenantModule{}, + &TenantModuleList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + klog.V(1).Info("Registered static kinds: TenantNamespace, TenantSecret, TenantModule") +} diff --git a/pkg/apis/core/v1alpha1/tenantmodule_types.go b/pkg/apis/core/v1alpha1/tenantmodule_types.go new file mode 100644 index 00000000..724efb3c --- /dev/null +++ b/pkg/apis/core/v1alpha1/tenantmodule_types.go @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TenantModule represents a HelmRelease with the label internal.cozystack.io/tenantmodule=true +type TenantModule struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // AppVersion represents the version of the Helm chart + AppVersion string `json:"appVersion,omitempty"` + + // Status contains the module status + Status TenantModuleStatus `json:"status,omitempty"` +} + +// TenantModuleStatus represents the status of a TenantModule +type TenantModuleStatus struct { + // Version represents the last attempted revision + Version string `json:"version,omitempty"` + + // Conditions represent the latest available observations of the module's state + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TenantModuleList contains a list of TenantModule +type TenantModuleList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []TenantModule `json:"items"` +} + +// DeepCopy methods are generated by deepcopy-gen diff --git a/pkg/apis/core/v1alpha1/tenantnamespace_types.go b/pkg/apis/core/v1alpha1/tenantnamespace_types.go new file mode 100644 index 00000000..506fb616 --- /dev/null +++ b/pkg/apis/core/v1alpha1/tenantnamespace_types.go @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 The Cozystack Authors. + +// This file contains the cluster-scoped “TenantNamespace” resource. +// A TenantNamespace represents an existing Kubernetes Namespace whose +// *name* starts with the prefix “tenant-”. + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TenantNamespace is a thin wrapper around ObjectMeta. It has no spec/status +// because it merely reflects an existing Namespace object. +type TenantNamespace struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TenantNamespaceList is the list variant for TenantNamespace. +type TenantNamespaceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []TenantNamespace `json:"items"` +} diff --git a/pkg/apis/core/v1alpha1/tenantresource_types.go b/pkg/apis/core/v1alpha1/tenantresource_types.go new file mode 100644 index 00000000..172d9eb1 --- /dev/null +++ b/pkg/apis/core/v1alpha1/tenantresource_types.go @@ -0,0 +1,4 @@ +package v1alpha1 + +const TenantResourceLabelKey = "internal.cozystack.io/tenantresource" +const TenantResourceLabelValue = "true" diff --git a/pkg/apis/core/v1alpha1/tenantsecret_types.go b/pkg/apis/core/v1alpha1/tenantsecret_types.go new file mode 100644 index 00000000..917e9cc2 --- /dev/null +++ b/pkg/apis/core/v1alpha1/tenantsecret_types.go @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +package v1alpha1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type TenantSecret struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Same semantics as core/v1 Secret. + Type string `json:"type,omitempty"` + Data map[string][]byte `json:"data,omitempty"` + StringData map[string]string `json:"stringData,omitempty"` // write-only hint +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type TenantSecretList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []TenantSecret `json:"items"` +} diff --git a/pkg/apis/core/v1alpha1/zz_generated.conversion.go b/pkg/apis/core/v1alpha1/zz_generated.conversion.go new file mode 100644 index 00000000..3b3b068a --- /dev/null +++ b/pkg/apis/core/v1alpha1/zz_generated.conversion.go @@ -0,0 +1,36 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + return nil +} diff --git a/pkg/apis/core/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/core/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000..a19b1d1a --- /dev/null +++ b/pkg/apis/core/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,250 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TenantModule) DeepCopyInto(out *TenantModule) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantModule. +func (in *TenantModule) DeepCopy() *TenantModule { + if in == nil { + return nil + } + out := new(TenantModule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TenantModule) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TenantModuleList) DeepCopyInto(out *TenantModuleList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TenantModule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantModuleList. +func (in *TenantModuleList) DeepCopy() *TenantModuleList { + if in == nil { + return nil + } + out := new(TenantModuleList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TenantModuleList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TenantModuleStatus) DeepCopyInto(out *TenantModuleStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantModuleStatus. +func (in *TenantModuleStatus) DeepCopy() *TenantModuleStatus { + if in == nil { + return nil + } + out := new(TenantModuleStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TenantNamespace) DeepCopyInto(out *TenantNamespace) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantNamespace. +func (in *TenantNamespace) DeepCopy() *TenantNamespace { + if in == nil { + return nil + } + out := new(TenantNamespace) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TenantNamespace) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TenantNamespaceList) DeepCopyInto(out *TenantNamespaceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TenantNamespace, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantNamespaceList. +func (in *TenantNamespaceList) DeepCopy() *TenantNamespaceList { + if in == nil { + return nil + } + out := new(TenantNamespaceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TenantNamespaceList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TenantSecret) DeepCopyInto(out *TenantSecret) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Data != nil { + in, out := &in.Data, &out.Data + *out = make(map[string][]byte, len(*in)) + for key, val := range *in { + var outVal []byte + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make([]byte, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } + if in.StringData != nil { + in, out := &in.StringData, &out.StringData + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantSecret. +func (in *TenantSecret) DeepCopy() *TenantSecret { + if in == nil { + return nil + } + out := new(TenantSecret) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TenantSecret) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TenantSecretList) DeepCopyInto(out *TenantSecretList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TenantSecret, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantSecretList. +func (in *TenantSecretList) DeepCopy() *TenantSecretList { + if in == nil { + return nil + } + out := new(TenantSecretList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TenantSecretList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/pkg/apis/core/v1alpha1/zz_generated.defaults.go b/pkg/apis/core/v1alpha1/zz_generated.defaults.go new file mode 100644 index 00000000..4e70d879 --- /dev/null +++ b/pkg/apis/core/v1alpha1/zz_generated.defaults.go @@ -0,0 +1,33 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 4e54d867..005fc640 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -17,42 +17,74 @@ limitations under the License. package apiserver import ( + "context" "fmt" + "time" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" helmv2 "github.com/fluxcd/helm-controller/api/v2" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apiserver/pkg/registry/rest" genericapiserver "k8s.io/apiserver/pkg/server" - "k8s.io/client-go/dynamic" - restclient "k8s.io/client-go/rest" + "k8s.io/klog/v2" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log/zap" "github.com/cozystack/cozystack/pkg/apis/apps" - "github.com/cozystack/cozystack/pkg/apis/apps/install" + appsinstall "github.com/cozystack/cozystack/pkg/apis/apps/install" + "github.com/cozystack/cozystack/pkg/apis/core" + coreinstall "github.com/cozystack/cozystack/pkg/apis/core/install" "github.com/cozystack/cozystack/pkg/config" - appsregistry "github.com/cozystack/cozystack/pkg/registry" + cozyregistry "github.com/cozystack/cozystack/pkg/registry" applicationstorage "github.com/cozystack/cozystack/pkg/registry/apps/application" + tenantmodulestorage "github.com/cozystack/cozystack/pkg/registry/core/tenantmodule" + tenantnamespacestorage "github.com/cozystack/cozystack/pkg/registry/core/tenantnamespace" + tenantsecretstorage "github.com/cozystack/cozystack/pkg/registry/core/tenantsecret" ) var ( // Scheme defines methods for serializing and deserializing API objects. - Scheme = runtime.NewScheme() + Scheme = runtime.NewScheme() + mgrScheme = runtime.NewScheme() // Codecs provides methods for retrieving codecs and serializers for specific // versions and content types. Codecs = serializer.NewCodecFactory(Scheme) - AppsComponentName = "apps" + CozyComponentName = "cozy" + syncPeriod = 5 * time.Minute ) func init() { - install.Install(Scheme) + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&zap.Options{ + Development: true, + // any other zap.Options tweaks + }))) + klog.SetLogger(ctrl.Log.WithName("klog")) + appsinstall.Install(Scheme) + coreinstall.Install(Scheme) // Register HelmRelease types. - if err := helmv2.AddToScheme(Scheme); err != nil { - panic(fmt.Sprintf("Failed to add HelmRelease types to scheme: %v", err)) + if err := helmv2.AddToScheme(mgrScheme); err != nil { + panic(fmt.Errorf("Failed to add HelmRelease types to scheme: %w", err)) } + if err := corev1.AddToScheme(mgrScheme); err != nil { + panic(fmt.Errorf("Failed to add core types to scheme: %w", err)) + } + if err := rbacv1.AddToScheme(mgrScheme); err != nil { + panic(fmt.Errorf("Failed to add RBAC types to scheme: %w", err)) + } + + // Register Cozystack types for WorkloadMonitor queries. + if err := cozyv1alpha1.AddToScheme(mgrScheme); err != nil { + panic(fmt.Errorf("failed to add Cozystack types to scheme: %w", err)) + } // Add unversioned types. metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) @@ -73,8 +105,8 @@ type Config struct { ResourceConfig *config.ResourceConfig } -// AppsServer holds the state for the Kubernetes master/api server. -type AppsServer struct { +// CozyServer holds the state for the Kubernetes master/api server. +type CozyServer struct { GenericAPIServer *genericapiserver.GenericAPIServer } @@ -98,42 +130,114 @@ func (cfg *Config) Complete() CompletedConfig { return CompletedConfig{&c} } -// New returns a new instance of AppsServer from the given configuration. -func (c completedConfig) New() (*AppsServer, error) { - genericServer, err := c.GenericConfig.New("apps-apiserver", genericapiserver.NewEmptyDelegate()) +// New returns a new instance of CozyServer from the given configuration. +func (c completedConfig) New() (*CozyServer, error) { + genericServer, err := c.GenericConfig.New("cozy-apiserver", genericapiserver.NewEmptyDelegate()) if err != nil { return nil, err } - s := &AppsServer{ + s := &CozyServer{ GenericAPIServer: genericServer, } - apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(apps.GroupName, Scheme, metav1.ParameterCodec, Codecs) - // Create a dynamic client for HelmRelease using InClusterConfig. - inClusterConfig, err := restclient.InClusterConfig() + cfg, err := ctrl.GetConfig() if err != nil { - return nil, fmt.Errorf("unable to get in-cluster config: %v", err) + return nil, fmt.Errorf("failed to get kubeconfig: %w", err) } - dynamicClient, err := dynamic.NewForConfig(inClusterConfig) + mgr, err := ctrl.NewManager(cfg, ctrl.Options{ + Scheme: mgrScheme, + Cache: cache.Options{SyncPeriod: &syncPeriod}, + }) if err != nil { - return nil, fmt.Errorf("unable to create dynamic client: %v", err) + return nil, fmt.Errorf("failed to build manager: %w", err) } - v1alpha1storage := map[string]rest.Storage{} + if err := mgr.GetFieldIndexer().IndexField( + context.Background(), + &corev1.Service{}, + "spec.type", + func(rawObj client.Object) []string { + svc := rawObj.(*corev1.Service) + return []string{string(svc.Spec.Type)} + }); err != nil { + return nil, fmt.Errorf("failed to index service spec.type field: %w", err) + } + ctx := ctrl.SetupSignalHandler() + + if err = mustGetInformers(ctx, mgr, + &helmv2.HelmRelease{}, + &corev1.Secret{}, + &corev1.Namespace{}, + &corev1.Service{}, + &rbacv1.RoleBinding{}, + &cozyv1alpha1.WorkloadMonitor{}, + ); err != nil { + return nil, fmt.Errorf("failed to get informers: %w", err) + } + + go func() { + if err := mgr.Start(ctx); err != nil { + panic(fmt.Errorf("manager start failed: %w", err)) + } + }() + + if ok := mgr.GetCache().WaitForCacheSync(ctx); !ok { + return nil, fmt.Errorf("cache sync failed") + } + + cli := mgr.GetClient() + watchCli, err := client.NewWithWatch(cfg, client.Options{Scheme: mgrScheme}) + if err != nil { + return nil, fmt.Errorf("failed to build watch client: %w", err) + } + // --- static, cluster-scoped resource for core group --- + coreV1alpha1Storage := map[string]rest.Storage{} + coreV1alpha1Storage["tenantnamespaces"] = cozyregistry.RESTInPeace( + tenantnamespacestorage.NewREST(cli, watchCli), + ) + coreV1alpha1Storage["tenantsecrets"] = cozyregistry.RESTInPeace( + tenantsecretstorage.NewREST(cli, watchCli), + ) + coreV1alpha1Storage["tenantmodules"] = cozyregistry.RESTInPeace( + tenantmodulestorage.NewREST(cli, watchCli), + ) + + coreApiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(core.GroupName, Scheme, metav1.ParameterCodec, Codecs) + coreApiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = coreV1alpha1Storage + if err := s.GenericAPIServer.InstallAPIGroup(&coreApiGroupInfo); err != nil { + return nil, err + } + + // --- dynamically-configured, per-tenant resources --- + appsV1alpha1Storage := map[string]rest.Storage{} for _, resConfig := range c.ResourceConfig.Resources { - storage := applicationstorage.NewREST(dynamicClient, &resConfig) - v1alpha1storage[resConfig.Application.Plural] = appsregistry.RESTInPeace(storage) + storage := applicationstorage.NewREST(cli, watchCli, &resConfig) + appsV1alpha1Storage[resConfig.Application.Plural] = cozyregistry.RESTInPeace(storage) } - - apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = v1alpha1storage - - if err := s.GenericAPIServer.InstallAPIGroup(&apiGroupInfo); err != nil { + if err := InstallAppsAPIGroup(s.GenericAPIServer, appsV1alpha1Storage); err != nil { return nil, err } return s, nil } + +// InstallAppsAPIGroup registers the apps.cozystack.io API group on the given +// server using the provided storage map (plural name → rest.Storage). +func InstallAppsAPIGroup(server *genericapiserver.GenericAPIServer, storage map[string]rest.Storage) error { + info := genericapiserver.NewDefaultAPIGroupInfo(apps.GroupName, Scheme, metav1.ParameterCodec, Codecs) + info.VersionedResourcesStorageMap["v1alpha1"] = storage + return server.InstallAPIGroup(&info) +} + +func mustGetInformers(ctx context.Context, mgr ctrl.Manager, types ...client.Object) error { + for i := range types { + if _, err := mgr.GetCache().GetInformer(ctx, types[i]); err != nil { + return fmt.Errorf("failed to get informer for %T: %w", types[i], err) + } + } + return nil +} diff --git a/pkg/apiserver/scheme_test.go b/pkg/apiserver/scheme_test.go index e00a1d62..af420791 100644 --- a/pkg/apiserver/scheme_test.go +++ b/pkg/apiserver/scheme_test.go @@ -20,9 +20,11 @@ import ( "testing" appsfuzzer "github.com/cozystack/cozystack/pkg/apis/apps/fuzzer" + corefuzzer "github.com/cozystack/cozystack/pkg/apis/core/fuzzer" "k8s.io/apimachinery/pkg/api/apitesting/roundtrip" ) func TestRoundTripTypes(t *testing.T) { roundtrip.RoundTripTestForScheme(t, Scheme, appsfuzzer.Funcs) + roundtrip.RoundTripTestForScheme(t, Scheme, corefuzzer.Funcs) } diff --git a/pkg/cmd/server/openapi.go b/pkg/cmd/server/openapi.go index 315a0077..a75fc1a5 100644 --- a/pkg/cmd/server/openapi.go +++ b/pkg/cmd/server/openapi.go @@ -5,6 +5,11 @@ import ( "fmt" "strings" + "github.com/cozystack/cozystack/pkg/apiserver" + "github.com/cozystack/cozystack/pkg/config" + sampleopenapi "github.com/cozystack/cozystack/pkg/generated/openapi" + "k8s.io/apiserver/pkg/endpoints/openapi" + genericapiserver "k8s.io/apiserver/pkg/server" "k8s.io/kube-openapi/pkg/spec3" "k8s.io/kube-openapi/pkg/validation/spec" ) @@ -14,33 +19,36 @@ import ( // ----------------------------------------------------------------------------- const ( - baseRef = "com.github.cozystack.cozystack.pkg.apis.apps.v1alpha1.Application" - baseListRef = baseRef + "List" - smp = "application/strategic-merge-patch+json" + apiPrefix = "com.github.cozystack.cozystack.pkg.apis.apps.v1alpha1" + baseRef = apiPrefix + ".Application" + baseListRef = apiPrefix + ".ApplicationList" + baseStatusRef = apiPrefix + ".ApplicationStatus" + smp = "application/strategic-merge-patch+json" ) +// deepCopySchema clones *spec.Schema via JSON-marshal/unmarshal. func deepCopySchema(in *spec.Schema) *spec.Schema { if in == nil { return nil } - b, err := json.Marshal(in) + raw, err := json.Marshal(in) if err != nil { - // Log error or panic since this is unexpected - panic(fmt.Sprintf("failed to marshal schema: %v", err)) + panic(fmt.Errorf("failed to marshal schema: %w", err)) } var out spec.Schema - if err := json.Unmarshal(b, &out); err != nil { - panic(fmt.Sprintf("failed to unmarshal schema: %v", err)) + err = json.Unmarshal(raw, &out) + if err != nil { + panic(fmt.Errorf("failed to unmarshal schema: %w", err)) } return &out } -// find the object that already owns ".spec" +// findSpecContainer returns first object owning ".spec". func findSpecContainer(s *spec.Schema) *spec.Schema { if s == nil { return nil } - if len(s.Type) > 0 && s.Type.Contains("object") && s.Properties != nil { + if len(s.Type) > 0 && s.Type.Contains("object") { if _, ok := s.Properties["spec"]; ok { return s } @@ -55,40 +63,25 @@ func findSpecContainer(s *spec.Schema) *spec.Schema { return nil } -// apply user-supplied schema; when raw == "" turn the field into a schemaless object +// patchSpec injects/overrides ".spec" with user JSON (or schemaless object). func patchSpec(target *spec.Schema, raw string) error { - // ------------------------------------------------------------------ - // 1) schema not provided → make ".spec" a fully open object - // ------------------------------------------------------------------ if strings.TrimSpace(raw) == "" { if target.Properties == nil { target.Properties = map[string]spec.Schema{} } prop := target.Properties["spec"] - prop.AdditionalProperties = &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{}, - } + prop.AdditionalProperties = &spec.SchemaOrBool{Allows: true} target.Properties["spec"] = prop return nil } - // ------------------------------------------------------------------ - // 2) custom schema provided → keep / inject additionalProperties - // ------------------------------------------------------------------ var custom spec.Schema if err := json.Unmarshal([]byte(raw), &custom); err != nil { return err } - - // if user didn't specify additionalProperties, add a permissive one if custom.AdditionalProperties == nil { - custom.AdditionalProperties = &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{}, - } + custom.AdditionalProperties = &spec.SchemaOrBool{Allows: true} } - if target.Properties == nil { target.Properties = map[string]spec.Schema{} } @@ -96,113 +89,316 @@ func patchSpec(target *spec.Schema, raw string) error { return nil } +/* ────────────────────────────────────────────────────────────────────────── */ +/* DRY helpers */ +/* ────────────────────────────────────────────────────────────────────────── */ + +// cloneKindSchemas: from base schemas, create new schemas for a specific kind. +func cloneKindSchemas(kind string, base, baseStatus, baseList *spec.Schema, v3 bool) (obj, status, list *spec.Schema) { + obj = deepCopySchema(base) + status = deepCopySchema(baseStatus) + list = deepCopySchema(baseList) + + // Ensure we have valid clones + if obj == nil || status == nil || list == nil { + return nil, nil, nil + } + + // GVK-extensions + setGVK := func(s *spec.Schema, k string) { + s.Extensions = map[string]any{ + "x-kubernetes-group-version-kind": []any{ + map[string]any{"group": "apps.cozystack.io", "version": "v1alpha1", "kind": k}, + }, + } + } + setGVK(obj, kind) + setGVK(list, kind+"List") + + // fix refs + refPrefix := "#/components/schemas/" // v3 + if !v3 { + refPrefix = "#/definitions/" + } + statusRef := refPrefix + apiPrefix + "." + kind + "Status" + itemRef := refPrefix + apiPrefix + "." + kind + + if prop, ok := obj.Properties["status"]; ok { + prop.Ref = spec.MustCreateRef(statusRef) + obj.Properties["status"] = prop + } + if list.Properties != nil { + if items := list.Properties["items"]; items.Items != nil && items.Items.Schema != nil { + items.Items.Schema.Ref = spec.MustCreateRef(itemRef) + list.Properties["items"] = items + } + } + return +} + +// rewriteDocRefs rewrites all $ref in the OpenAPI document +func rewriteDocRefs(doc any) ([]byte, error) { + raw, err := json.Marshal(doc) + if err != nil { + return nil, fmt.Errorf("failed to marshal OpenAPI document: %w", err) + } + var parsed any + if err := json.Unmarshal(raw, &parsed); err != nil { + return nil, err + } + walkAndRewriteRefs(parsed, "") + return json.Marshal(parsed) +} + +// walkAndRewriteRefs walks arbitrary JSON (map/array) and +// - when encountering x-kubernetes-group-version-kind, extracts kind, +// updating the currentKind context; +// - rewrites all $ref inside the current context from Application* → kind*. +func walkAndRewriteRefs(node any, currentKind string) { + switch n := node.(type) { + case map[string]any: + if gvk, ok := n["x-kubernetes-group-version-kind"]; ok { + switch g := gvk.(type) { + case map[string]any: + if k, ok := g["kind"].(string); ok { + currentKind = k + } + case []any: + if len(g) > 0 { + if mm, ok := g[0].(map[string]any); ok { + if k, ok := mm["kind"].(string); ok { + currentKind = k + } + } + } + } + } + for k, v := range n { + if k == "$ref" && currentKind != "" { + if s, ok := v.(string); ok { + n[k] = rewriteRefForKind(s, currentKind) + continue + } + } + walkAndRewriteRefs(v, currentKind) + } + case []any: + for _, v := range n { + walkAndRewriteRefs(v, currentKind) + } + } +} + +// rewriteRefForKind rewrites a reference to a specific kind. +func rewriteRefForKind(old, kind string) string { + var base string + switch { + case strings.HasPrefix(old, "#/components/schemas/"): + base = "#/components/schemas/" + case strings.HasPrefix(old, "#/definitions/"): + base = "#/definitions/" + default: + return old + } + switch { + case strings.HasSuffix(old, ".Application"): + return base + apiPrefix + "." + kind + case strings.HasSuffix(old, ".ApplicationList"): + return base + apiPrefix + "." + kind + "List" + case strings.HasSuffix(old, ".ApplicationStatus"): + return base + apiPrefix + "." + kind + "Status" + default: + return old + } +} + // ----------------------------------------------------------------------------- // OpenAPI **v3** post-processor // ----------------------------------------------------------------------------- -func buildPostProcessV3(kindSchemas map[string]string) func(*spec3.OpenAPI) (*spec3.OpenAPI, error) { - +// BuildPostProcessV3 returns an OpenAPI v3 post-processor that clones base +// Application schemas into per-kind schemas and rewrites $ref pointers. +func BuildPostProcessV3(kindSchemas map[string]string) func(*spec3.OpenAPI) (*spec3.OpenAPI, error) { return func(doc *spec3.OpenAPI) (*spec3.OpenAPI, error) { - // Replace the basic "Application" schema with the user-supplied kinds. if doc.Components == nil { doc.Components = &spec3.Components{} } if doc.Components.Schemas == nil { doc.Components.Schemas = map[string]*spec.Schema{} } - base, ok := doc.Components.Schemas[baseRef] - if !ok { - return doc, fmt.Errorf("base schema %q not found", baseRef) + + // Get base schemas + base, ok1 := doc.Components.Schemas[baseRef] + list, ok2 := doc.Components.Schemas[baseListRef] + stat, ok3 := doc.Components.Schemas[baseStatusRef] + if !(ok1 && ok2 && ok3) { + return doc, nil // not the apps GV — nothing to patch } + + // Clone base schemas for each kind for kind, raw := range kindSchemas { - ref := fmt.Sprintf("%s.%s", "com.github.cozystack.cozystack.pkg.apis.apps.v1alpha1", kind) - s := doc.Components.Schemas[ref] - if s == nil { // first time – clone "Application" - s = deepCopySchema(base) - s.Extensions = map[string]interface{}{ - "x-kubernetes-group-version-kind": []interface{}{ - map[string]interface{}{ - "group": "apps.cozystack.io", "version": "v1alpha1", "kind": kind, - }, - }, - } - doc.Components.Schemas[ref] = s - } - container := findSpecContainer(s) - if container == nil { // fallback: use the root - container = s + ref := apiPrefix + "." + kind + statusRef := ref + "Status" + listRef := ref + "List" + + obj, status, l := cloneKindSchemas(kind, base, stat, list /*v3=*/, true) + doc.Components.Schemas[ref] = obj + doc.Components.Schemas[statusRef] = status + doc.Components.Schemas[listRef] = l + + // patch .spec + container := findSpecContainer(obj) + if container == nil { + container = obj } if err := patchSpec(container, raw); err != nil { return nil, fmt.Errorf("kind %s: %w", kind, err) } } + + // Delete base schemas delete(doc.Components.Schemas, baseRef) delete(doc.Components.Schemas, baseListRef) + delete(doc.Components.Schemas, baseStatusRef) - // Disable strategic-merge-patch+json support in all PATCH operations + // Disable strategic-merge-patch+json for p, pi := range doc.Paths.Paths { - if pi == nil || pi.Patch == nil || pi.Patch.RequestBody == nil { - continue + if pi != nil && pi.Patch != nil && pi.Patch.RequestBody != nil { + delete(pi.Patch.RequestBody.Content, smp) + doc.Paths.Paths[p] = pi } - delete(pi.Patch.RequestBody.Content, smp) - - doc.Paths.Paths[p] = pi } - return doc, nil + // Rewrite all $ref in the document + out, err := rewriteDocRefs(doc) + if err != nil { + return nil, err + } + return doc, json.Unmarshal(out, doc) } } +// hasIntAndStringAnyOf returns true if anyOf is exactly a combination of string and integer. +func hasIntAndStringAnyOf(anyOf []spec.Schema) bool { + seen := map[string]bool{} + for i := range anyOf { + for _, t := range anyOf[i].Type { + seen[t] = true + } + } + return seen["string"] && seen["integer"] && len(seen) <= 2 +} + +// sanitizeForV2 removes unsupported constructs for Swagger v2 and normalizes common patterns. +func sanitizeForV2(s *spec.Schema) { + if s == nil { + return + } + + if len(s.AnyOf) > 0 { + if hasIntAndStringAnyOf(s.AnyOf) { + s.Type = spec.StringOrArray{"string"} + if s.Extensions == nil { + s.Extensions = map[string]any{} + } + s.Extensions["x-kubernetes-int-or-string"] = true + } + s.AnyOf = nil + } + + if len(s.OneOf) > 0 { + s.OneOf = nil + } + + if s.AdditionalProperties != nil { + ap := s.AdditionalProperties + if ap.Schema != nil { + sanitizeForV2(ap.Schema) + } + } + + for k := range s.Properties { + prop := s.Properties[k] + sanitizeForV2(&prop) + s.Properties[k] = prop + } + + if s.Items != nil { + if s.Items.Schema != nil { + sanitizeForV2(s.Items.Schema) + } + for i := range s.Items.Schemas { + sanitizeForV2(&s.Items.Schemas[i]) + } + } + + for i := range s.AllOf { + sanitizeForV2(&s.AllOf[i]) + } +} + +// KindSchemasFromConfig extracts the kind→OpenAPISchema mapping from a ResourceConfig. +func KindSchemasFromConfig(rc *config.ResourceConfig) map[string]string { + m := make(map[string]string, len(rc.Resources)) + for _, r := range rc.Resources { + m[r.Application.Kind] = r.Application.OpenAPISchema + } + return m +} + +// ConfigureOpenAPI sets up OpenAPI v2 and v3 on a GenericAPIServer Config, +// including the post-processors that clone Application schemas to per-kind schemas. +func ConfigureOpenAPI(cfg *genericapiserver.Config, kindSchemas map[string]string, title, version string) { + cfg.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig( + sampleopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(apiserver.Scheme), + ) + cfg.OpenAPIConfig.Info.Title = title + cfg.OpenAPIConfig.Info.Version = version + cfg.OpenAPIConfig.PostProcessSpec = BuildPostProcessV2(kindSchemas) + + cfg.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config( + sampleopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(apiserver.Scheme), + ) + cfg.OpenAPIV3Config.Info.Title = title + cfg.OpenAPIV3Config.Info.Version = version + cfg.OpenAPIV3Config.PostProcessSpec = BuildPostProcessV3(kindSchemas) +} + // ----------------------------------------------------------------------------- // OpenAPI **v2** (swagger) post-processor // ----------------------------------------------------------------------------- -func buildPostProcessV2(kindSchemas map[string]string) func(*spec.Swagger) (*spec.Swagger, error) { - +// BuildPostProcessV2 returns a Swagger post-processor that clones base +// Application schemas into per-kind schemas and rewrites $ref pointers. +func BuildPostProcessV2(kindSchemas map[string]string) func(*spec.Swagger) (*spec.Swagger, error) { return func(sw *spec.Swagger) (*spec.Swagger, error) { - - // Replace the basic "Application" schema with the user-supplied kinds. defs := sw.Definitions - base, ok := defs[baseRef] - if !ok { - return sw, fmt.Errorf("base schema %q not found", baseRef) + base, ok1 := defs[baseRef] + list, ok2 := defs[baseListRef] + stat, ok3 := defs[baseStatusRef] + if !(ok1 && ok2 && ok3) { + return sw, nil // not the apps GV — nothing to patch } + for kind, raw := range kindSchemas { - ref := fmt.Sprintf("%s.%s", "com.github.cozystack.cozystack.pkg.apis.apps.v1alpha1", kind) - s := deepCopySchema(&base) - s.Extensions = map[string]interface{}{ - "x-kubernetes-group-version-kind": []interface{}{ - map[string]interface{}{ - "group": "apps.cozystack.io", "version": "v1alpha1", "kind": kind, - }, - }, - } - if err := patchSpec(s, raw); err != nil { + ref := apiPrefix + "." + kind + statusRef := ref + "Status" + listRef := ref + "List" + + obj, status, l := cloneKindSchemas(kind, &base, &stat, &list, false) + + if err := patchSpec(obj, raw); err != nil { return nil, fmt.Errorf("kind %s: %w", kind, err) } - defs[ref] = *s - // clone the List variant - listName := ref + "List" - listSrc := defs[baseListRef] - listCopy := deepCopySchema(&listSrc) - listCopy.Extensions = map[string]interface{}{ - "x-kubernetes-group-version-kind": []interface{}{ - map[string]interface{}{ - "group": "apps.cozystack.io", - "version": "v1alpha1", - "kind": kind + "List", - }, - }, - } - if items := listCopy.Properties["items"]; items.Items != nil && items.Items.Schema != nil { - items.Items.Schema.Ref = spec.MustCreateRef("#/definitions/" + ref) - listCopy.Properties["items"] = items - } - defs[listName] = *listCopy + + defs[ref] = *obj + defs[statusRef] = *status + defs[listRef] = *l } + delete(defs, baseRef) delete(defs, baseListRef) + delete(defs, baseStatusRef) - // Disable strategic-merge-patch+json support in all PATCH operations for p, op := range sw.Paths.Paths { if op.Patch != nil && len(op.Patch.Consumes) > 0 { var out []string @@ -216,6 +412,20 @@ func buildPostProcessV2(kindSchemas map[string]string) func(*spec.Swagger) (*spe } } + out, err := rewriteDocRefs(sw) + if err != nil { + return nil, err + } + if err := json.Unmarshal(out, sw); err != nil { + return nil, err + } + + for name := range sw.Definitions { + s := sw.Definitions[name] + sanitizeForV2(&s) + sw.Definitions[name] = s + } + return sw, nil } } diff --git a/pkg/cmd/server/start.go b/pkg/cmd/server/start.go index 6f0cfac4..7ebbbc89 100644 --- a/pkg/cmd/server/start.go +++ b/pkg/cmd/server/start.go @@ -24,49 +24,51 @@ import ( "fmt" "io" "net" + "time" - "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + v1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" "github.com/cozystack/cozystack/pkg/apiserver" "github.com/cozystack/cozystack/pkg/config" - sampleopenapi "github.com/cozystack/cozystack/pkg/generated/openapi" "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" utilerrors "k8s.io/apimachinery/pkg/util/errors" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/version" - "k8s.io/apiserver/pkg/endpoints/openapi" genericapiserver "k8s.io/apiserver/pkg/server" genericoptions "k8s.io/apiserver/pkg/server/options" utilfeature "k8s.io/apiserver/pkg/util/feature" - utilversionpkg "k8s.io/apiserver/pkg/util/version" - "k8s.io/component-base/featuregate" + basecompatibility "k8s.io/component-base/compatibility" baseversion "k8s.io/component-base/version" netutils "k8s.io/utils/net" + "sigs.k8s.io/controller-runtime/pkg/client" + k8sconfig "sigs.k8s.io/controller-runtime/pkg/client/config" ) -// AppsServerOptions holds the state for the Apps API server -type AppsServerOptions struct { +// CozyServerOptions holds the state for the Cozy API server +type CozyServerOptions struct { RecommendedOptions *genericoptions.RecommendedOptions StdOut io.Writer StdErr io.Writer AlternateDNS []string - - // Add a field to store the configuration path - ResourceConfigPath string + Client client.Client // Add a field to store the configuration ResourceConfig *config.ResourceConfig } -// NewAppsServerOptions returns a new instance of AppsServerOptions -func NewAppsServerOptions(out, errOut io.Writer) *AppsServerOptions { - o := &AppsServerOptions{ +// NewCozyServerOptions returns a new instance of CozyServerOptions +func NewCozyServerOptions(out, errOut io.Writer) *CozyServerOptions { + o := &CozyServerOptions{ RecommendedOptions: genericoptions.NewRecommendedOptions( "", - apiserver.Codecs.LegacyCodec(v1alpha1.SchemeGroupVersion), + apiserver.Codecs.LegacyCodec( + corev1alpha1.SchemeGroupVersion, + appsv1alpha1.SchemeGroupVersion, + ), ), - StdOut: out, StdErr: errOut, } @@ -74,15 +76,12 @@ func NewAppsServerOptions(out, errOut io.Writer) *AppsServerOptions { return o } -// NewCommandStartAppsServer provides a CLI handler for the 'start apps-server' command -func NewCommandStartAppsServer(ctx context.Context, defaults *AppsServerOptions) *cobra.Command { +// NewCommandStartCozyServer provides a CLI handler for the 'start apps-server' command +func NewCommandStartCozyServer(ctx context.Context, defaults *CozyServerOptions) *cobra.Command { o := *defaults cmd := &cobra.Command{ - Short: "Launch an Apps API server", - Long: "Launch an Apps API server", - PersistentPreRunE: func(*cobra.Command, []string) error { - return utilversionpkg.DefaultComponentGlobalsRegistry.Set() - }, + Short: "Launch an Cozystack API server", + Long: "Launch an Cozystack API server", RunE: func(c *cobra.Command, args []string) error { if err := o.Complete(); err != nil { return err @@ -90,7 +89,7 @@ func NewCommandStartAppsServer(ctx context.Context, defaults *AppsServerOptions) if err := o.Validate(args); err != nil { return err } - if err := o.RunAppsServer(c.Context()); err != nil { + if err := o.RunCozyServer(c.Context()); err != nil { return err } return nil @@ -101,66 +100,119 @@ func NewCommandStartAppsServer(ctx context.Context, defaults *AppsServerOptions) flags := cmd.Flags() o.RecommendedOptions.AddFlags(flags) - // Add a flag for the config path - flags.StringVar(&o.ResourceConfigPath, "config", "config.yaml", "Path to the resource configuration file") - - // The following lines demonstrate how to configure version compatibility and feature gates - // for the "Apps" component according to KEP-4330. - - // Create a default version object for the "Apps" component. - defaultAppsVersion := "1.1" - // Register the "Apps" component in the global component registry, - // associating it with its effective version and feature gate configuration. - _, appsFeatureGate := utilversionpkg.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister( - apiserver.AppsComponentName, utilversionpkg.NewEffectiveVersion(defaultAppsVersion), - featuregate.NewVersionedFeatureGate(version.MustParse(defaultAppsVersion)), - ) - - // Add feature gate specifications for the "Apps" component. - utilruntime.Must(appsFeatureGate.AddVersioned(map[featuregate.Feature]featuregate.VersionedSpecs{ - // Example of adding feature gates: - // "FeatureName": {{"v1", true}, {"v2", false}}, - })) - - // Register the standard kube component if it is not already registered in the global registry. - _, _ = utilversionpkg.DefaultComponentGlobalsRegistry.ComponentGlobalsOrRegister( - utilversionpkg.DefaultKubeComponent, - utilversionpkg.NewEffectiveVersion(baseversion.DefaultKubeBinaryVersion), - utilfeature.DefaultMutableFeatureGate, - ) - - // Set the version emulation mapping from the "Apps" component to the kube component. - utilruntime.Must(utilversionpkg.DefaultComponentGlobalsRegistry.SetEmulationVersionMapping( - apiserver.AppsComponentName, utilversionpkg.DefaultKubeComponent, AppsVersionToKubeVersion, - )) - - // Add flags from the global component registry. - utilversionpkg.DefaultComponentGlobalsRegistry.AddFlags(flags) + // Note: KEP-4330 component versioning functionality (k8s.io/apiserver/pkg/util/version) + // is not available in Kubernetes v0.34.1. The component versioning code has been removed. return cmd } // Complete fills in the fields that are not set -func (o *AppsServerOptions) Complete() error { - // Load the configuration file - cfg, err := config.LoadConfig(o.ResourceConfigPath) - if err != nil { - return fmt.Errorf("failed to load config from %s: %v", o.ResourceConfigPath, err) +func (o *CozyServerOptions) Complete() error { + scheme := runtime.NewScheme() + if err := v1alpha1.AddToScheme(scheme); err != nil { + return fmt.Errorf("failed to register types: %w", err) } - o.ResourceConfig = cfg + if err := corev1.AddToScheme(scheme); err != nil { + return fmt.Errorf("failed to register core types: %w", err) + } + + cfg, err := k8sconfig.GetConfig() + if err != nil { + return fmt.Errorf("failed to get kubeconfig: %w", err) + } + + o.Client, err = client.New(cfg, client.Options{Scheme: scheme}) + if err != nil { + return fmt.Errorf("client initialization failed: %w", err) + } + + crdList := &v1alpha1.ApplicationDefinitionList{} + + // Retry with exponential backoff for at least 30 minutes + const maxRetryDuration = 30 * time.Minute + const initialDelay = time.Second + const maxDelay = 2 * time.Minute + + startTime := time.Now() + delay := initialDelay + + for { + err := o.Client.List(context.Background(), crdList) + if err == nil { + break + } + + // Check if we've exceeded the maximum retry duration + if time.Since(startTime) >= maxRetryDuration { + return fmt.Errorf("failed to list ApplicationDefinitions after %v: %w", maxRetryDuration, err) + } + + // Log the error and wait before retrying + fmt.Printf("Failed to list ApplicationDefinitions (retrying in %v): %v\n", delay, err) + time.Sleep(delay) + + delay = time.Duration(float64(delay) * 1.5) + if delay > maxDelay { + delay = maxDelay + } + } + + // Convert to ResourceConfig + o.ResourceConfig = &config.ResourceConfig{} + for _, crd := range crdList.Items { + release := config.ReleaseConfig{ + Prefix: crd.Spec.Release.Prefix, + Labels: crd.Spec.Release.Labels, + ChartRef: config.ChartRefConfig{ + Kind: crd.Spec.Release.ChartRef.Kind, + Name: crd.Spec.Release.ChartRef.Name, + Namespace: crd.Spec.Release.ChartRef.Namespace, + }, + } + // Per-Application HelmRelease Install/Upgrade timeout. Applications + // whose parent chart contains asynchronously-provisioned resources + // the chart itself depends on (for example, the Kamaji-provisioned + // admin-kubeconfig Secret for Kubernetes tenants) need a longer + // wait budget than the Flux default. Consumed by the REST storage + // layer when building the HelmRelease Spec. The parser rejects + // units Flux would reject at webhook time, so a bad annotation + // surfaces as a loud startup failure instead of a silent drop to + // defaults. + d, err := config.ParseHelmInstallTimeoutAnnotation( + crd.Annotations[config.HelmInstallTimeoutAnnotation], + ) + if err != nil { + return fmt.Errorf( + "ApplicationDefinition %q has invalid %s annotation: %w", + crd.Name, config.HelmInstallTimeoutAnnotation, err, + ) + } + release.HelmInstallTimeout = d + resource := config.Resource{ + Application: config.ApplicationConfig{ + Kind: crd.Spec.Application.Kind, + Singular: crd.Spec.Application.Singular, + Plural: crd.Spec.Application.Plural, + ShortNames: []string{}, // TODO: implement shortnames + OpenAPISchema: crd.Spec.Application.OpenAPISchema, + }, + Release: release, + } + o.ResourceConfig.Resources = append(o.ResourceConfig.Resources, resource) + } + return nil } // Validate checks the correctness of the options -func (o AppsServerOptions) Validate(args []string) error { +func (o CozyServerOptions) Validate(args []string) error { var allErrors []error allErrors = append(allErrors, o.RecommendedOptions.Validate()...) - allErrors = append(allErrors, utilversionpkg.DefaultComponentGlobalsRegistry.Validate()...) return utilerrors.NewAggregate(allErrors) } -// Config returns the configuration for the API server based on AppsServerOptions -func (o *AppsServerOptions) Config() (*apiserver.Config, error) { +// Config returns the configuration for the API server based on CozyServerOptions +func (o *CozyServerOptions) Config() (*apiserver.Config, error) { // TODO: set the "real" external address if err := o.RecommendedOptions.SecureServing.MaybeDefaultWithSelfSignedCerts( "localhost", o.AlternateDNS, []net.IP{netutils.ParseIPSloppy("127.0.0.1")}, @@ -168,53 +220,40 @@ func (o *AppsServerOptions) Config() (*apiserver.Config, error) { return nil, fmt.Errorf("error creating self-signed certificates: %v", err) } - // First, register the dynamic types - err := v1alpha1.RegisterDynamicTypes(apiserver.Scheme, o.ResourceConfig) + // Register *compile-time* resources first. + corev1alpha1.RegisterStaticTypes(apiserver.Scheme) + + // Register *run-time* resources (from the user’s config file). + err := appsv1alpha1.RegisterDynamicTypes(apiserver.Scheme, o.ResourceConfig) if err != nil { return nil, fmt.Errorf("failed to register dynamic types: %v", err) } serverConfig := genericapiserver.NewRecommendedConfig(apiserver.Codecs) - serverConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig( - sampleopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(apiserver.Scheme), - ) - - version := "0.1" + apiVersion := "0.1" if o.ResourceConfig != nil { raw, err := json.Marshal(o.ResourceConfig) if err != nil { return nil, fmt.Errorf("failed to marshal resource config: %v", err) } sum := sha256.Sum256(raw) - version = "0.1-" + hex.EncodeToString(sum[:8]) + apiVersion = "0.1-" + hex.EncodeToString(sum[:8]) } - // capture schemas from config once for fast lookup inside the closure - kindSchemas := map[string]string{} - for _, r := range o.ResourceConfig.Resources { - kindSchemas[r.Application.Kind] = r.Application.OpenAPISchema + kindSchemas := KindSchemasFromConfig(o.ResourceConfig) + ConfigureOpenAPI(&serverConfig.Config, kindSchemas, "Cozy", apiVersion) + + // Set FeatureGate and EffectiveVersion - required for Complete() in Kubernetes v0.34.1 + // Following the pattern from sample-apiserver, but creating EffectiveVersion directly + // without ComponentGlobalsRegistry + serverConfig.FeatureGate = utilfeature.DefaultMutableFeatureGate + // Create EffectiveVersion directly using compatibility package + // This is needed even without ComponentGlobalsRegistry + if baseversion.DefaultKubeBinaryVersion != "" { + serverConfig.EffectiveVersion = basecompatibility.NewEffectiveVersionFromString(baseversion.DefaultKubeBinaryVersion, "", "") } - serverConfig.OpenAPIConfig.Info.Title = "Apps" - serverConfig.OpenAPIConfig.Info.Version = version - serverConfig.OpenAPIConfig.PostProcessSpec = buildPostProcessV2(kindSchemas) - - serverConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config( - sampleopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(apiserver.Scheme), - ) - serverConfig.OpenAPIV3Config.Info.Title = "Apps" - serverConfig.OpenAPIV3Config.Info.Version = version - - serverConfig.OpenAPIV3Config.PostProcessSpec = buildPostProcessV3(kindSchemas) - - serverConfig.FeatureGate = utilversionpkg.DefaultComponentGlobalsRegistry.FeatureGateFor( - utilversionpkg.DefaultKubeComponent, - ) - serverConfig.EffectiveVersion = utilversionpkg.DefaultComponentGlobalsRegistry.EffectiveVersionFor( - apiserver.AppsComponentName, - ) - if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil { return nil, err } @@ -226,8 +265,8 @@ func (o *AppsServerOptions) Config() (*apiserver.Config, error) { return config, nil } -// RunAppsServer launches a new AppsServer based on AppsServerOptions -func (o AppsServerOptions) RunAppsServer(ctx context.Context) error { +// RunCozyServer launches a new CozyServer based on CozyServerOptions +func (o CozyServerOptions) RunCozyServer(ctx context.Context) error { config, err := o.Config() if err != nil { return err @@ -245,18 +284,3 @@ func (o AppsServerOptions) RunAppsServer(ctx context.Context) error { return server.GenericAPIServer.PrepareRun().RunWithContext(ctx) } - -// AppsVersionToKubeVersion defines the version mapping between the Apps component and kube -func AppsVersionToKubeVersion(ver *version.Version) *version.Version { - if ver.Major() != 1 { - return nil - } - kubeVer := utilversionpkg.DefaultKubeEffectiveVersion().BinaryVersion() - // "1.2" corresponds to kubeVer - offset := int(ver.Minor()) - 2 - mappedVer := kubeVer.OffsetMinor(offset) - if mappedVer.GreaterThan(kubeVer) { - return kubeVer - } - return mappedVer -} diff --git a/pkg/cmd/server/start_test.go b/pkg/cmd/server/start_test.go index ddff60d9..9dc2000c 100644 --- a/pkg/cmd/server/start_test.go +++ b/pkg/cmd/server/start_test.go @@ -1,5 +1,5 @@ /* -Copyright 2024 The Cozystack Authors. +Copyright 2026 The Cozystack Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,54 +15,3 @@ limitations under the License. */ package server - -import ( - "testing" - - "k8s.io/apimachinery/pkg/util/version" - utilversion "k8s.io/apiserver/pkg/util/version" - - "github.com/stretchr/testify/assert" -) - -func TestAppsEmulationVersionToKubeEmulationVersion(t *testing.T) { - defaultKubeEffectiveVersion := utilversion.DefaultKubeEffectiveVersion() - - testCases := []struct { - desc string - appsEmulationVer *version.Version - expectedKubeEmulationVer *version.Version - }{ - { - desc: "same version as than kube binary", - appsEmulationVer: version.MajorMinor(1, 2), - expectedKubeEmulationVer: defaultKubeEffectiveVersion.BinaryVersion(), - }, - { - desc: "1 version lower than kube binary", - appsEmulationVer: version.MajorMinor(1, 1), - expectedKubeEmulationVer: defaultKubeEffectiveVersion.BinaryVersion().OffsetMinor(-1), - }, - { - desc: "2 versions lower than kube binary", - appsEmulationVer: version.MajorMinor(1, 0), - expectedKubeEmulationVer: defaultKubeEffectiveVersion.BinaryVersion().OffsetMinor(-2), - }, - { - desc: "capped at kube binary", - appsEmulationVer: version.MajorMinor(1, 3), - expectedKubeEmulationVer: defaultKubeEffectiveVersion.BinaryVersion(), - }, - { - desc: "no mapping", - appsEmulationVer: version.MajorMinor(2, 10), - }, - } - - for _, tc := range testCases { - t.Run(tc.desc, func(t *testing.T) { - mappedKubeEmulationVer := AppsVersionToKubeVersion(tc.appsEmulationVer) - assert.True(t, mappedKubeEmulationVer.EqualTo(tc.expectedKubeEmulationVer)) - }) - } -} diff --git a/pkg/config/config.go b/pkg/config/config.go index 6ada99d3..21de27b2 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -18,11 +18,46 @@ package config import ( "fmt" - "os" - - "gopkg.in/yaml.v2" + "regexp" + "time" ) +// HelmInstallTimeoutAnnotation is the ApplicationDefinition metadata +// annotation key that overrides the Flux HelmRelease Install.Timeout and +// Upgrade.Timeout for a given Application kind. +const HelmInstallTimeoutAnnotation = "release.cozystack.io/helm-install-timeout" + +// helmTimeoutPattern mirrors the CRD validation pattern used by Flux +// helm-controller on HelmReleaseSpec.Install.Timeout (ms/s/m/h units only). +// time.ParseDuration accepts ns/us/µs, but Flux rejects them - parsing here +// with the same shape avoids feeding the controller a value it will later +// reject at webhook time. See +// github.com/fluxcd/helm-controller/api/v2 HelmReleaseSpec.Install.Timeout +// in the go module cache. +var helmTimeoutPattern = regexp.MustCompile(`^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$`) + +// ParseHelmInstallTimeoutAnnotation parses the value of the +// release.cozystack.io/helm-install-timeout annotation. The empty string is +// treated as "unset" and returns (0, nil) so callers can leave +// HelmInstallTimeout zeroed and let flux defaults apply. Values accepted by +// time.ParseDuration but rejected by Flux (ns/us/µs) return a helpful +// error instead of silently parsing and failing later at HelmRelease +// admission. +func ParseHelmInstallTimeoutAnnotation(raw string) (time.Duration, error) { + if raw == "" { + return 0, nil + } + if !helmTimeoutPattern.MatchString(raw) { + return 0, fmt.Errorf("must match %s (Flux accepts ms/s/m/h units only), got %q", + helmTimeoutPattern, raw) + } + d, err := time.ParseDuration(raw) + if err != nil { + return 0, fmt.Errorf("time.ParseDuration(%q): %w", raw, err) + } + return d, nil +} + // ResourceConfig represents the structure of the configuration file. type ResourceConfig struct { Resources []Resource `yaml:"resources"` @@ -45,50 +80,20 @@ type ApplicationConfig struct { // ReleaseConfig contains the release settings. type ReleaseConfig struct { - Prefix string `yaml:"prefix"` - Labels map[string]string `yaml:"labels"` - Chart ChartConfig `yaml:"chart"` + Prefix string `yaml:"prefix"` + Labels map[string]string `yaml:"labels"` + ChartRef ChartRefConfig `yaml:"chartRef"` + // HelmInstallTimeout overrides the Flux HelmRelease Install.Timeout and + // Upgrade.Timeout for this Application kind. When zero, flux defaults + // apply. Populated from the + // release.cozystack.io/helm-install-timeout annotation on the + // ApplicationDefinition at start-up. + HelmInstallTimeout time.Duration `yaml:"helmInstallTimeout,omitempty"` } -// ChartConfig contains the chart settings. -type ChartConfig struct { - Name string `yaml:"name"` - SourceRef SourceRefConfig `yaml:"sourceRef"` -} - -// SourceRefConfig contains the reference to the chart source. -type SourceRefConfig struct { +// ChartRefConfig references a Flux source artifact for the Helm chart. +type ChartRefConfig struct { Kind string `yaml:"kind"` Name string `yaml:"name"` Namespace string `yaml:"namespace"` } - -// LoadConfig loads the configuration from the specified path and validates it. -func LoadConfig(path string) (*ResourceConfig, error) { - data, err := os.ReadFile(path) - if err != nil { - return nil, err - } - - var config ResourceConfig - if err := yaml.Unmarshal(data, &config); err != nil { - return nil, err - } - - // Validate the configuration. - for i, res := range config.Resources { - if res.Application.Kind == "" { - return nil, fmt.Errorf("resource at index %d has an empty kind", i) - } - if res.Application.Plural == "" { - return nil, fmt.Errorf("resource at index %d has an empty plural", i) - } - if res.Release.Chart.Name == "" { - return nil, fmt.Errorf("resource at index %d has an empty chart name in release", i) - } - if res.Release.Chart.SourceRef.Kind == "" || res.Release.Chart.SourceRef.Name == "" || res.Release.Chart.SourceRef.Namespace == "" { - return nil, fmt.Errorf("resource at index %d has an incomplete sourceRef for chart in release", i) - } - } - return &config, nil -} diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go new file mode 100644 index 00000000..eb6990af --- /dev/null +++ b/pkg/config/config_test.go @@ -0,0 +1,119 @@ +package config + +import ( + "strings" + "testing" + "time" +) + +// Cover the annotation parser used by cozystack-api at startup. The parser +// is consumed by pkg/cmd/server/start.go on every ApplicationDefinition; a +// typo here silently drops back to flux defaults and the Kubernetes tenant +// race described in cozystack#2412 reappears, so the table must exercise: +// - the unset path (empty string treated as "no override"), +// - every unit Flux accepts (ms, s, m, h), +// - compound forms (the CRD pattern accepts repeats), +// - units time.ParseDuration accepts but Flux rejects (ns, us, µs), +// - outright garbage. +func TestParseHelmInstallTimeoutAnnotation(t *testing.T) { + cases := []struct { + name string + input string + want time.Duration + wantErr bool + errMatch string + }{ + { + name: "empty string leaves flux defaults in place", + input: "", + want: 0, + }, + { + name: "minutes", + input: "15m", + want: 15 * time.Minute, + }, + { + name: "hours", + input: "1h", + want: time.Hour, + }, + { + name: "seconds", + input: "45s", + want: 45 * time.Second, + }, + { + name: "milliseconds", + input: "500ms", + want: 500 * time.Millisecond, + }, + { + name: "compound hour and minutes", + input: "2h30m", + want: 2*time.Hour + 30*time.Minute, + }, + { + name: "decimal minutes", + input: "1.5m", + want: 90 * time.Second, + }, + { + name: "nanoseconds rejected - Flux CRD pattern excludes ns", + input: "500ns", + wantErr: true, + errMatch: "Flux accepts ms/s/m/h units only", + }, + { + name: "microseconds rejected - Flux CRD pattern excludes us", + input: "500us", + wantErr: true, + errMatch: "Flux accepts ms/s/m/h units only", + }, + { + name: "microseconds unicode rejected", + input: "500µs", + wantErr: true, + errMatch: "Flux accepts ms/s/m/h units only", + }, + { + name: "bare digits rejected", + input: "15", + wantErr: true, + errMatch: "Flux accepts ms/s/m/h units only", + }, + { + name: "garbage rejected", + input: "abc", + wantErr: true, + errMatch: "Flux accepts ms/s/m/h units only", + }, + { + name: "negative rejected", + input: "-15m", + wantErr: true, + errMatch: "Flux accepts ms/s/m/h units only", + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + got, err := ParseHelmInstallTimeoutAnnotation(tc.input) + if tc.wantErr { + if err == nil { + t.Fatalf("expected error, got duration=%v", got) + } + if tc.errMatch != "" && !strings.Contains(err.Error(), tc.errMatch) { + t.Errorf("error %q does not contain %q", err.Error(), tc.errMatch) + } + return + } + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if got != tc.want { + t.Errorf("got %v, want %v", got, tc.want) + } + }) + } +} diff --git a/pkg/generated/applyconfiguration/apps/v1alpha1/application.go b/pkg/generated/applyconfiguration/apps/v1alpha1/application.go index 908e28fd..9c5e2ab5 100644 --- a/pkg/generated/applyconfiguration/apps/v1alpha1/application.go +++ b/pkg/generated/applyconfiguration/apps/v1alpha1/application.go @@ -1,5 +1,5 @@ /* -Copyright 2024 The Cozystack Authors. +Copyright 2025 The Cozystack Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,10 +19,10 @@ limitations under the License. package v1alpha1 import ( + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" v1 "k8s.io/client-go/applyconfigurations/meta/v1" - appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" ) // ApplicationApplyConfiguration represents a declarative configuration of the Application type for use @@ -30,8 +30,9 @@ import ( type ApplicationApplyConfiguration struct { v1.TypeMetaApplyConfiguration `json:",inline"` *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` - Spec *ApplicationSpecApplyConfiguration `json:"spec,omitempty"` - Status *appsv1alpha1.ApplicationStatus `json:"status,omitempty"` + AppVersion *string `json:"appVersion,omitempty"` + Spec *apiextensionsv1.JSON `json:"spec,omitempty"` + Status *ApplicationStatusApplyConfiguration `json:"status,omitempty"` } // Application constructs a declarative configuration of the Application type for use with @@ -44,6 +45,7 @@ func Application(name, namespace string) *ApplicationApplyConfiguration { b.WithAPIVersion("apps.cozystack.io/v1alpha1") return b } +func (b ApplicationApplyConfiguration) IsApplyConfiguration() {} // WithKind sets the Kind field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. @@ -203,24 +205,48 @@ func (b *ApplicationApplyConfiguration) ensureObjectMetaApplyConfigurationExists } } +// WithAppVersion sets the AppVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the AppVersion field is set to the value of the last call. +func (b *ApplicationApplyConfiguration) WithAppVersion(value string) *ApplicationApplyConfiguration { + b.AppVersion = &value + return b +} + // WithSpec sets the Spec field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the Spec field is set to the value of the last call. -func (b *ApplicationApplyConfiguration) WithSpec(value *ApplicationSpecApplyConfiguration) *ApplicationApplyConfiguration { - b.Spec = value +func (b *ApplicationApplyConfiguration) WithSpec(value apiextensionsv1.JSON) *ApplicationApplyConfiguration { + b.Spec = &value return b } // WithStatus sets the Status field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the Status field is set to the value of the last call. -func (b *ApplicationApplyConfiguration) WithStatus(value appsv1alpha1.ApplicationStatus) *ApplicationApplyConfiguration { - b.Status = &value +func (b *ApplicationApplyConfiguration) WithStatus(value *ApplicationStatusApplyConfiguration) *ApplicationApplyConfiguration { + b.Status = value return b } +// GetKind retrieves the value of the Kind field in the declarative configuration. +func (b *ApplicationApplyConfiguration) GetKind() *string { + return b.TypeMetaApplyConfiguration.Kind +} + +// GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration. +func (b *ApplicationApplyConfiguration) GetAPIVersion() *string { + return b.TypeMetaApplyConfiguration.APIVersion +} + // GetName retrieves the value of the Name field in the declarative configuration. func (b *ApplicationApplyConfiguration) GetName() *string { b.ensureObjectMetaApplyConfigurationExists() return b.ObjectMetaApplyConfiguration.Name } + +// GetNamespace retrieves the value of the Namespace field in the declarative configuration. +func (b *ApplicationApplyConfiguration) GetNamespace() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Namespace +} diff --git a/pkg/generated/applyconfiguration/apps/v1alpha1/applicationspec.go b/pkg/generated/applyconfiguration/apps/v1alpha1/applicationspec.go deleted file mode 100644 index 3924ebd4..00000000 --- a/pkg/generated/applyconfiguration/apps/v1alpha1/applicationspec.go +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright 2024 The Cozystack Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by applyconfiguration-gen. DO NOT EDIT. - -package v1alpha1 - -// ApplicationSpecApplyConfiguration represents a declarative configuration of the ApplicationSpec type for use -// with apply. -type ApplicationSpecApplyConfiguration struct { - Version *string `json:"version,omitempty"` - Values *string `json:"values,omitempty"` -} - -// ApplicationSpecApplyConfiguration constructs a declarative configuration of the ApplicationSpec type for use with -// apply. -func ApplicationSpec() *ApplicationSpecApplyConfiguration { - return &ApplicationSpecApplyConfiguration{} -} - -// WithVersion sets the Version field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Version field is set to the value of the last call. -func (b *ApplicationSpecApplyConfiguration) WithVersion(value string) *ApplicationSpecApplyConfiguration { - b.Version = &value - return b -} - -// WithValues sets the Values field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Values field is set to the value of the last call. -func (b *ApplicationSpecApplyConfiguration) WithValues(value string) *ApplicationSpecApplyConfiguration { - b.Values = &value - return b -} diff --git a/pkg/generated/applyconfiguration/apps/v1alpha1/applicationstatus.go b/pkg/generated/applyconfiguration/apps/v1alpha1/applicationstatus.go new file mode 100644 index 00000000..2a990861 --- /dev/null +++ b/pkg/generated/applyconfiguration/apps/v1alpha1/applicationstatus.go @@ -0,0 +1,75 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// ApplicationStatusApplyConfiguration represents a declarative configuration of the ApplicationStatus type for use +// with apply. +type ApplicationStatusApplyConfiguration struct { + Version *string `json:"version,omitempty"` + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + Namespace *string `json:"namespace,omitempty"` + ExternalIPsCount *int32 `json:"externalIPsCount,omitempty"` +} + +// ApplicationStatusApplyConfiguration constructs a declarative configuration of the ApplicationStatus type for use with +// apply. +func ApplicationStatus() *ApplicationStatusApplyConfiguration { + return &ApplicationStatusApplyConfiguration{} +} + +// WithVersion sets the Version field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Version field is set to the value of the last call. +func (b *ApplicationStatusApplyConfiguration) WithVersion(value string) *ApplicationStatusApplyConfiguration { + b.Version = &value + return b +} + +// WithConditions adds the given value to the Conditions field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Conditions field. +func (b *ApplicationStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *ApplicationStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) + } + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *ApplicationStatusApplyConfiguration) WithNamespace(value string) *ApplicationStatusApplyConfiguration { + b.Namespace = &value + return b +} + +// WithExternalIPsCount sets the ExternalIPsCount field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ExternalIPsCount field is set to the value of the last call. +func (b *ApplicationStatusApplyConfiguration) WithExternalIPsCount(value int32) *ApplicationStatusApplyConfiguration { + b.ExternalIPsCount = &value + return b +} diff --git a/pkg/generated/applyconfiguration/internal/internal.go b/pkg/generated/applyconfiguration/internal/internal.go index 760f1229..97f12849 100644 --- a/pkg/generated/applyconfiguration/internal/internal.go +++ b/pkg/generated/applyconfiguration/internal/internal.go @@ -1,5 +1,5 @@ /* -Copyright 2024 The Cozystack Authors. +Copyright 2025 The Cozystack Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ import ( fmt "fmt" sync "sync" - typed "sigs.k8s.io/structured-merge-diff/v4/typed" + typed "sigs.k8s.io/structured-merge-diff/v6/typed" ) func Parser() *typed.Parser { diff --git a/pkg/generated/applyconfiguration/utils.go b/pkg/generated/applyconfiguration/utils.go index a27b3d20..ab73a5f1 100644 --- a/pkg/generated/applyconfiguration/utils.go +++ b/pkg/generated/applyconfiguration/utils.go @@ -1,5 +1,5 @@ /* -Copyright 2024 The Cozystack Authors. +Copyright 2025 The Cozystack Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,12 +19,12 @@ limitations under the License. package applyconfiguration import ( + v1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + appsv1alpha1 "github.com/cozystack/cozystack/pkg/generated/applyconfiguration/apps/v1alpha1" + internal "github.com/cozystack/cozystack/pkg/generated/applyconfiguration/internal" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" - testing "k8s.io/client-go/testing" - v1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" - internal "github.com/cozystack/cozystack/pkg/generated/applyconfiguration/internal" - appsv1alpha1 "github.com/cozystack/cozystack/pkg/generated/applyconfiguration/apps/v1alpha1" + managedfields "k8s.io/apimachinery/pkg/util/managedfields" ) // ForKind returns an apply configuration type for the given GroupVersionKind, or nil if no @@ -34,13 +34,13 @@ func ForKind(kind schema.GroupVersionKind) interface{} { // Group=apps.cozystack.io, Version=v1alpha1 case v1alpha1.SchemeGroupVersion.WithKind("Application"): return &appsv1alpha1.ApplicationApplyConfiguration{} - case v1alpha1.SchemeGroupVersion.WithKind("ApplicationSpec"): - return &appsv1alpha1.ApplicationSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ApplicationStatus"): + return &appsv1alpha1.ApplicationStatusApplyConfiguration{} } return nil } -func NewTypeConverter(scheme *runtime.Scheme) *testing.TypeConverter { - return &testing.TypeConverter{Scheme: scheme, TypeResolver: internal.Parser()} +func NewTypeConverter(scheme *runtime.Scheme) managedfields.TypeConverter { + return managedfields.NewSchemeTypeConverter(scheme, internal.Parser()) } diff --git a/pkg/generated/applyconfiguration/utils_test.go b/pkg/generated/applyconfiguration/utils_test.go new file mode 100644 index 00000000..dd6440b6 --- /dev/null +++ b/pkg/generated/applyconfiguration/utils_test.go @@ -0,0 +1,64 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package applyconfiguration + +import ( + "testing" + + v1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + appsv1alpha1 "github.com/cozystack/cozystack/pkg/generated/applyconfiguration/apps/v1alpha1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func TestForKind_Application(t *testing.T) { + gvk := v1alpha1.SchemeGroupVersion.WithKind("Application") + got := ForKind(gvk) + if got == nil { + t.Fatal("ForKind returned nil for Application GVK") + } + if _, ok := got.(*appsv1alpha1.ApplicationApplyConfiguration); !ok { + t.Fatalf("ForKind returned %T, want *ApplicationApplyConfiguration", got) + } +} + +func TestForKind_ApplicationStatus(t *testing.T) { + gvk := v1alpha1.SchemeGroupVersion.WithKind("ApplicationStatus") + got := ForKind(gvk) + if got == nil { + t.Fatal("ForKind returned nil for ApplicationStatus GVK") + } + if _, ok := got.(*appsv1alpha1.ApplicationStatusApplyConfiguration); !ok { + t.Fatalf("ForKind returned %T, want *ApplicationStatusApplyConfiguration", got) + } +} + +func TestForKind_Unknown(t *testing.T) { + gvk := schema.GroupVersionKind{Group: "unknown.io", Version: "v1", Kind: "Unknown"} + got := ForKind(gvk) + if got != nil { + t.Fatalf("ForKind returned %T for unknown GVK, want nil", got) + } +} + +func TestNewTypeConverter(t *testing.T) { + scheme := runtime.NewScheme() + tc := NewTypeConverter(scheme) + if tc == nil { + t.Fatal("NewTypeConverter returned nil") + } +} diff --git a/pkg/generated/clientset/versioned/clientset.go b/pkg/generated/clientset/versioned/clientset.go new file mode 100644 index 00000000..127a0032 --- /dev/null +++ b/pkg/generated/clientset/versioned/clientset.go @@ -0,0 +1,120 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + fmt "fmt" + http "net/http" + + appsv1alpha1 "github.com/cozystack/cozystack/pkg/generated/clientset/versioned/typed/apps/v1alpha1" + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + AppsV1alpha1() appsv1alpha1.AppsV1alpha1Interface +} + +// Clientset contains the clients for groups. +type Clientset struct { + *discovery.DiscoveryClient + appsV1alpha1 *appsv1alpha1.AppsV1alpha1Client +} + +// AppsV1alpha1 retrieves the AppsV1alpha1Client +func (c *Clientset) AppsV1alpha1() appsv1alpha1.AppsV1alpha1Interface { + return c.appsV1alpha1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfig will generate a rate-limiter in configShallowCopy. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + + if configShallowCopy.UserAgent == "" { + configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() + } + + // share the transport between all clients + httpClient, err := rest.HTTPClientFor(&configShallowCopy) + if err != nil { + return nil, err + } + + return NewForConfigAndClient(&configShallowCopy, httpClient) +} + +// NewForConfigAndClient creates a new Clientset for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. +func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + if configShallowCopy.Burst <= 0 { + return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") + } + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + + var cs Clientset + var err error + cs.appsV1alpha1, err = appsv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + cs, err := NewForConfig(c) + if err != nil { + panic(err) + } + return cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.appsV1alpha1 = appsv1alpha1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/pkg/generated/clientset/versioned/fake/clientset_generated.go b/pkg/generated/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 00000000..3ceb93c7 --- /dev/null +++ b/pkg/generated/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,131 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + applyconfiguration "github.com/cozystack/cozystack/pkg/generated/applyconfiguration" + clientset "github.com/cozystack/cozystack/pkg/generated/clientset/versioned" + appsv1alpha1 "github.com/cozystack/cozystack/pkg/generated/clientset/versioned/typed/apps/v1alpha1" + fakeappsv1alpha1 "github.com/cozystack/cozystack/pkg/generated/clientset/versioned/typed/apps/v1alpha1/fake" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any field management, validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +// +// DEPRECATED: NewClientset replaces this with support for field management, which significantly improves +// server side apply testing. NewClientset is only available when apply configurations are generated (e.g. +// via --with-applyconfig). +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + var opts metav1.ListOptions + if watchActcion, ok := action.(testing.WatchActionImpl); ok { + opts = watchActcion.ListOptions + } + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns, opts) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery + tracker testing.ObjectTracker +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +func (c *Clientset) Tracker() testing.ObjectTracker { + return c.tracker +} + +// NewClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewClientset(objects ...runtime.Object) *Clientset { + o := testing.NewFieldManagedObjectTracker( + scheme, + codecs.UniversalDecoder(), + applyconfiguration.NewTypeConverter(scheme), + ) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + var opts metav1.ListOptions + if watchAction, ok := action.(testing.WatchActionImpl); ok { + opts = watchAction.ListOptions + } + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns, opts) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +var ( + _ clientset.Interface = &Clientset{} + _ testing.FakeClient = &Clientset{} +) + +// AppsV1alpha1 retrieves the AppsV1alpha1Client +func (c *Clientset) AppsV1alpha1() appsv1alpha1.AppsV1alpha1Interface { + return &fakeappsv1alpha1.FakeAppsV1alpha1{Fake: &c.Fake} +} diff --git a/pkg/generated/clientset/versioned/fake/doc.go b/pkg/generated/clientset/versioned/fake/doc.go new file mode 100644 index 00000000..2d395096 --- /dev/null +++ b/pkg/generated/clientset/versioned/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/pkg/generated/clientset/versioned/fake/register.go b/pkg/generated/clientset/versioned/fake/register.go new file mode 100644 index 00000000..a05b3ada --- /dev/null +++ b/pkg/generated/clientset/versioned/fake/register.go @@ -0,0 +1,56 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) + +var localSchemeBuilder = runtime.SchemeBuilder{ + appsv1alpha1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/pkg/generated/clientset/versioned/scheme/doc.go b/pkg/generated/clientset/versioned/scheme/doc.go new file mode 100644 index 00000000..4b11a5d0 --- /dev/null +++ b/pkg/generated/clientset/versioned/scheme/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/pkg/generated/clientset/versioned/scheme/register.go b/pkg/generated/clientset/versioned/scheme/register.go new file mode 100644 index 00000000..65b15149 --- /dev/null +++ b/pkg/generated/clientset/versioned/scheme/register.go @@ -0,0 +1,56 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + appsv1alpha1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/pkg/generated/clientset/versioned/typed/apps/v1alpha1/application.go b/pkg/generated/clientset/versioned/typed/apps/v1alpha1/application.go new file mode 100644 index 00000000..afc81aad --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/apps/v1alpha1/application.go @@ -0,0 +1,74 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + + appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + applyconfigurationappsv1alpha1 "github.com/cozystack/cozystack/pkg/generated/applyconfiguration/apps/v1alpha1" + scheme "github.com/cozystack/cozystack/pkg/generated/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" +) + +// ApplicationsGetter has a method to return a ApplicationInterface. +// A group's client should implement this interface. +type ApplicationsGetter interface { + Applications(namespace string) ApplicationInterface +} + +// ApplicationInterface has methods to work with Application resources. +type ApplicationInterface interface { + Create(ctx context.Context, application *appsv1alpha1.Application, opts v1.CreateOptions) (*appsv1alpha1.Application, error) + Update(ctx context.Context, application *appsv1alpha1.Application, opts v1.UpdateOptions) (*appsv1alpha1.Application, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, application *appsv1alpha1.Application, opts v1.UpdateOptions) (*appsv1alpha1.Application, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*appsv1alpha1.Application, error) + List(ctx context.Context, opts v1.ListOptions) (*appsv1alpha1.ApplicationList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *appsv1alpha1.Application, err error) + Apply(ctx context.Context, application *applyconfigurationappsv1alpha1.ApplicationApplyConfiguration, opts v1.ApplyOptions) (result *appsv1alpha1.Application, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, application *applyconfigurationappsv1alpha1.ApplicationApplyConfiguration, opts v1.ApplyOptions) (result *appsv1alpha1.Application, err error) + ApplicationExpansion +} + +// applications implements ApplicationInterface +type applications struct { + *gentype.ClientWithListAndApply[*appsv1alpha1.Application, *appsv1alpha1.ApplicationList, *applyconfigurationappsv1alpha1.ApplicationApplyConfiguration] +} + +// newApplications returns a Applications +func newApplications(c *AppsV1alpha1Client, namespace string) *applications { + return &applications{ + gentype.NewClientWithListAndApply[*appsv1alpha1.Application, *appsv1alpha1.ApplicationList, *applyconfigurationappsv1alpha1.ApplicationApplyConfiguration]( + "applications", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *appsv1alpha1.Application { return &appsv1alpha1.Application{} }, + func() *appsv1alpha1.ApplicationList { return &appsv1alpha1.ApplicationList{} }, + ), + } +} diff --git a/pkg/generated/clientset/versioned/typed/apps/v1alpha1/apps_client.go b/pkg/generated/clientset/versioned/typed/apps/v1alpha1/apps_client.go new file mode 100644 index 00000000..40ff64b9 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/apps/v1alpha1/apps_client.go @@ -0,0 +1,101 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + http "net/http" + + appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + scheme "github.com/cozystack/cozystack/pkg/generated/clientset/versioned/scheme" + rest "k8s.io/client-go/rest" +) + +type AppsV1alpha1Interface interface { + RESTClient() rest.Interface + ApplicationsGetter +} + +// AppsV1alpha1Client is used to interact with features provided by the apps.cozystack.io group. +type AppsV1alpha1Client struct { + restClient rest.Interface +} + +func (c *AppsV1alpha1Client) Applications(namespace string) ApplicationInterface { + return newApplications(c, namespace) +} + +// NewForConfig creates a new AppsV1alpha1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*AppsV1alpha1Client, error) { + config := *c + setConfigDefaults(&config) + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new AppsV1alpha1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*AppsV1alpha1Client, error) { + config := *c + setConfigDefaults(&config) + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &AppsV1alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new AppsV1alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *AppsV1alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new AppsV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *AppsV1alpha1Client { + return &AppsV1alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) { + gv := appsv1alpha1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = rest.CodecFactoryForGeneratedClient(scheme.Scheme, scheme.Codecs).WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *AppsV1alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/generated/clientset/versioned/typed/apps/v1alpha1/doc.go b/pkg/generated/clientset/versioned/typed/apps/v1alpha1/doc.go new file mode 100644 index 00000000..b37cc8b0 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/apps/v1alpha1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1alpha1 diff --git a/pkg/generated/clientset/versioned/typed/apps/v1alpha1/fake/doc.go b/pkg/generated/clientset/versioned/typed/apps/v1alpha1/fake/doc.go new file mode 100644 index 00000000..592956cf --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/apps/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/generated/clientset/versioned/typed/apps/v1alpha1/fake/fake_application.go b/pkg/generated/clientset/versioned/typed/apps/v1alpha1/fake/fake_application.go new file mode 100644 index 00000000..0760721d --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/apps/v1alpha1/fake/fake_application.go @@ -0,0 +1,53 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + appsv1alpha1 "github.com/cozystack/cozystack/pkg/generated/applyconfiguration/apps/v1alpha1" + typedappsv1alpha1 "github.com/cozystack/cozystack/pkg/generated/clientset/versioned/typed/apps/v1alpha1" + gentype "k8s.io/client-go/gentype" +) + +// fakeApplications implements ApplicationInterface +type fakeApplications struct { + *gentype.FakeClientWithListAndApply[*v1alpha1.Application, *v1alpha1.ApplicationList, *appsv1alpha1.ApplicationApplyConfiguration] + Fake *FakeAppsV1alpha1 +} + +func newFakeApplications(fake *FakeAppsV1alpha1, namespace string) typedappsv1alpha1.ApplicationInterface { + return &fakeApplications{ + gentype.NewFakeClientWithListAndApply[*v1alpha1.Application, *v1alpha1.ApplicationList, *appsv1alpha1.ApplicationApplyConfiguration]( + fake.Fake, + namespace, + v1alpha1.SchemeGroupVersion.WithResource("applications"), + v1alpha1.SchemeGroupVersion.WithKind("Application"), + func() *v1alpha1.Application { return &v1alpha1.Application{} }, + func() *v1alpha1.ApplicationList { return &v1alpha1.ApplicationList{} }, + func(dst, src *v1alpha1.ApplicationList) { dst.ListMeta = src.ListMeta }, + func(list *v1alpha1.ApplicationList) []*v1alpha1.Application { + return gentype.ToPointerSlice(list.Items) + }, + func(list *v1alpha1.ApplicationList, items []*v1alpha1.Application) { + list.Items = gentype.FromPointerSlice(items) + }, + ), + fake, + } +} diff --git a/pkg/generated/clientset/versioned/typed/apps/v1alpha1/fake/fake_apps_client.go b/pkg/generated/clientset/versioned/typed/apps/v1alpha1/fake/fake_apps_client.go new file mode 100644 index 00000000..40981a9d --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/apps/v1alpha1/fake/fake_apps_client.go @@ -0,0 +1,40 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/cozystack/cozystack/pkg/generated/clientset/versioned/typed/apps/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeAppsV1alpha1 struct { + *testing.Fake +} + +func (c *FakeAppsV1alpha1) Applications(namespace string) v1alpha1.ApplicationInterface { + return newFakeApplications(c, namespace) +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeAppsV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/generated/clientset/versioned/typed/apps/v1alpha1/generated_expansion.go b/pkg/generated/clientset/versioned/typed/apps/v1alpha1/generated_expansion.go new file mode 100644 index 00000000..6a0aab6a --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/apps/v1alpha1/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +type ApplicationExpansion interface{} diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 2df4a3bd..3ad28827 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -30,9 +30,16 @@ import ( func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { return map[string]common.OpenAPIDefinition{ - "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1.Application": schema_pkg_apis_apps_v1alpha1_Application(ref), - "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1.ApplicationList": schema_pkg_apis_apps_v1alpha1_ApplicationList(ref), - "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1.ApplicationStatus": schema_pkg_apis_apps_v1alpha1_ApplicationStatus(ref), + "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1.Application": schema_pkg_apis_apps_v1alpha1_Application(ref), + "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1.ApplicationList": schema_pkg_apis_apps_v1alpha1_ApplicationList(ref), + "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1.ApplicationStatus": schema_pkg_apis_apps_v1alpha1_ApplicationStatus(ref), + "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantModule": schema_pkg_apis_core_v1alpha1_TenantModule(ref), + "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantModuleList": schema_pkg_apis_core_v1alpha1_TenantModuleList(ref), + "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantModuleStatus": schema_pkg_apis_core_v1alpha1_TenantModuleStatus(ref), + "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantNamespace": schema_pkg_apis_core_v1alpha1_TenantNamespace(ref), + "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantNamespaceList": schema_pkg_apis_core_v1alpha1_TenantNamespaceList(ref), + "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecret": schema_pkg_apis_core_v1alpha1_TenantSecret(ref), + "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecretList": schema_pkg_apis_core_v1alpha1_TenantSecretList(ref), "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.ConversionRequest": schema_pkg_apis_apiextensions_v1_ConversionRequest(ref), "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.ConversionResponse": schema_pkg_apis_apiextensions_v1_ConversionResponse(ref), "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.ConversionReview": schema_pkg_apis_apiextensions_v1_ConversionReview(ref), @@ -244,6 +251,20 @@ func schema_pkg_apis_apps_v1alpha1_ApplicationStatus(ref common.ReferenceCallbac }, }, }, + "namespace": { + SchemaProps: spec.SchemaProps{ + Description: "Namespace holds the computed namespace for Tenant applications.", + Type: []string{"string"}, + Format: "", + }, + }, + "externalIPsCount": { + SchemaProps: spec.SchemaProps{ + Description: "ExternalIPsCount holds the number of LoadBalancer services with assigned external IPs for Tenant applications.", + Type: []string{"integer"}, + Format: "int32", + }, + }, }, }, }, @@ -252,6 +273,342 @@ func schema_pkg_apis_apps_v1alpha1_ApplicationStatus(ref common.ReferenceCallbac } } +func schema_pkg_apis_core_v1alpha1_TenantModule(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TenantModule represents a HelmRelease with the label internal.cozystack.io/tenantmodule=true", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "appVersion": { + SchemaProps: spec.SchemaProps{ + Description: "AppVersion represents the version of the Helm chart", + Type: []string{"string"}, + Format: "", + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "Status contains the module status", + Default: map[string]interface{}{}, + Ref: ref("github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantModuleStatus"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantModuleStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_pkg_apis_core_v1alpha1_TenantModuleList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TenantModuleList contains a list of TenantModule", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantModule"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantModule", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_pkg_apis_core_v1alpha1_TenantModuleStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TenantModuleStatus represents the status of a TenantModule", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "version": { + SchemaProps: spec.SchemaProps{ + Description: "Version represents the last attempted revision", + Type: []string{"string"}, + Format: "", + }, + }, + "conditions": { + SchemaProps: spec.SchemaProps{ + Description: "Conditions represent the latest available observations of the module's state", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + } +} + +func schema_pkg_apis_core_v1alpha1_TenantNamespace(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TenantNamespace is a thin wrapper around ObjectMeta. It has no spec/status because it merely reflects an existing Namespace object.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_pkg_apis_core_v1alpha1_TenantNamespaceList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TenantNamespaceList is the list variant for TenantNamespace.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantNamespace"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantNamespace", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_pkg_apis_core_v1alpha1_TenantSecret(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "type": { + SchemaProps: spec.SchemaProps{ + Description: "Same semantics as core/v1 Secret.", + Type: []string{"string"}, + Format: "", + }, + }, + "data": { + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "byte", + }, + }, + }, + }, + }, + "stringData": { + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_pkg_apis_core_v1alpha1_TenantSecretList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecret"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1.TenantSecret", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + func schema_pkg_apis_apiextensions_v1_ConversionRequest(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -2364,6 +2721,13 @@ func schema_pkg_apis_meta_v1_DeleteOptions(ref common.ReferenceCallback) common. }, }, }, + "ignoreStoreReadErrorWithClusterBreakingPotential": { + SchemaProps: spec.SchemaProps{ + Description: "if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it", + Type: []string{"boolean"}, + Format: "", + }, + }, }, }, }, @@ -4251,16 +4615,46 @@ func schema_k8sio_apimachinery_pkg_version_Info(ref common.ReferenceCallback) co Properties: map[string]spec.Schema{ "major": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Major is the major version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", }, }, "minor": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Minor is the minor version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMajor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMajor is the major version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMinor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMinor is the minor version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMajor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMajor is the major version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMinor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMinor is the minor version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", }, }, "gitVersion": { diff --git a/pkg/lineage/lineage.go b/pkg/lineage/lineage.go new file mode 100644 index 00000000..94be77b7 --- /dev/null +++ b/pkg/lineage/lineage.go @@ -0,0 +1,200 @@ +package lineage + +import ( + "context" + "fmt" + "os" + "strings" + + helmv2 "github.com/fluxcd/helm-controller/api/v2" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +const ( + HRAPIVersion = "helm.toolkit.fluxcd.io/v2" + HRKind = "HelmRelease" + HRLabel = "helm.toolkit.fluxcd.io/name" +) + +// AppMapper maps HelmRelease to application metadata. +type AppMapper interface { + Map(*helmv2.HelmRelease) (apiVersion, kind, prefix string, err error) +} + +type ObjectID struct { + APIVersion string + Kind string + Namespace string + Name string +} + +func (o ObjectID) GetUnstructured(ctx context.Context, client dynamic.Interface, mapper meta.RESTMapper) (*unstructured.Unstructured, error) { + u, err := getUnstructuredObject(ctx, client, mapper, o.APIVersion, o.Kind, o.Namespace, o.Name) + if err != nil { + return nil, err + } + return u, nil +} + +func WalkOwnershipGraph( + ctx context.Context, + client dynamic.Interface, + mapper meta.RESTMapper, + appMapper AppMapper, + obj *unstructured.Unstructured, + memory ...interface{}, +) (out []ObjectID) { + + id := ObjectID{APIVersion: obj.GetAPIVersion(), Kind: obj.GetKind(), Namespace: obj.GetNamespace(), Name: obj.GetName()} + out = []ObjectID{} + l := log.FromContext(ctx) + + l.Info("processing object", "apiVersion", obj.GetAPIVersion(), "kind", obj.GetKind(), "name", obj.GetName()) + var visited map[ObjectID]bool + var ok bool + if len(memory) == 1 { + visited, ok = memory[0].(map[ObjectID]bool) + if !ok { + l.Error( + fmt.Errorf("invalid argument"), "could not parse visited map in WalkOwnershipGraph call", + "received", memory[0], "expected", "map[ObjectID]bool", + ) + return out + } + } + + if len(memory) == 0 { + visited = make(map[ObjectID]bool) + } + + if len(memory) != 0 && len(memory) != 1 { + l.Error( + fmt.Errorf("invalid argument count"), "could not parse variadic arguments to WalkOwnershipGraph", + "args passed", len(memory)+5, "expected args", "4|5", + ) + return out + } + + if visited[id] { + return out + } + + visited[id] = true + + ownerRefs := obj.GetOwnerReferences() + for _, owner := range ownerRefs { + ownerObj, err := getUnstructuredObject(ctx, client, mapper, owner.APIVersion, owner.Kind, obj.GetNamespace(), owner.Name) + if err != nil { + fmt.Fprintf(os.Stderr, "Could not fetch owner %s/%s (%s): %v\n", obj.GetNamespace(), owner.Name, owner.Kind, err) + continue + } + + out = append(out, WalkOwnershipGraph(ctx, client, mapper, appMapper, ownerObj, visited)...) + } + + // if object has owners, it couldn't be owned directly by the custom app + if len(ownerRefs) > 0 { + return + } + + // I want "if err1 != nil go to next block, if err2 != nil, go to next block, etc semantics", + // like an early return from a function, but if all checks succeed, I don't want to do the rest + // of the function, so it's a `for { if err { break } if othererr { break } if allgood { return } + for { + if obj.GetAPIVersion() != HRAPIVersion || obj.GetKind() != HRKind { + break + } + hr := helmReleaseFromUnstructured(obj) + if hr == nil { + break + } + a, k, p, err := appMapper.Map(hr) + if err != nil { + l.Error(err, "failed to map HelmRelease to app") + break + } + ownerObj, err := getUnstructuredObject(ctx, client, mapper, a, k, obj.GetNamespace(), strings.TrimPrefix(obj.GetName(), p)) + if err != nil { + l.Error(err, "couldn't get unstructured object", "APIVersion", a, "Kind", k, "Name", strings.TrimPrefix(obj.GetName(), p)) + break + } + // successfully mapped a HelmRelease to a custom app, no need to continue + out = append(out, + ObjectID{ + APIVersion: ownerObj.GetAPIVersion(), + Kind: ownerObj.GetKind(), + Namespace: ownerObj.GetNamespace(), + Name: ownerObj.GetName(), + }, + ) + return + } + + labels := obj.GetLabels() + name, ok := labels[HRLabel] + if !ok { + return + } + ownerObj, err := getUnstructuredObject(ctx, client, mapper, HRAPIVersion, HRKind, obj.GetNamespace(), name) + if err != nil { + return + } + out = append(out, WalkOwnershipGraph(ctx, client, mapper, appMapper, ownerObj, visited)...) + + return +} + +func getUnstructuredObject( + ctx context.Context, + client dynamic.Interface, + mapper meta.RESTMapper, + apiVersion, kind, namespace, name string, +) (*unstructured.Unstructured, error) { + l := log.FromContext(ctx) + gv, err := schema.ParseGroupVersion(apiVersion) + if err != nil { + l.Error( + err, "failed to parse groupversion", + "apiVersion", apiVersion, + ) + return nil, err + } + gvk := schema.GroupVersionKind{ + Group: gv.Group, + Version: gv.Version, + Kind: kind, + } + + mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version) + if err != nil { + l.Error(err, "Could not map GVK "+gvk.String()) + return nil, err + } + + ns := namespace + if mapping.Scope.Name() != meta.RESTScopeNameNamespace { + ns = "" + } + + ownerObj, err := client.Resource(mapping.Resource).Namespace(ns).Get(ctx, name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + return ownerObj, nil +} + +func helmReleaseFromUnstructured(obj *unstructured.Unstructured) *helmv2.HelmRelease { + if obj.GetAPIVersion() == HRAPIVersion && obj.GetKind() == HRKind { + hr := &helmv2.HelmRelease{} + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, hr); err == nil { + return hr + } + } + return nil +} diff --git a/pkg/lineage/lineage_test.go b/pkg/lineage/lineage_test.go new file mode 100644 index 00000000..7da09dfc --- /dev/null +++ b/pkg/lineage/lineage_test.go @@ -0,0 +1,84 @@ +package lineage + +import ( + "context" + "fmt" + "os" + "strings" + "testing" + + helmv2 "github.com/fluxcd/helm-controller/api/v2" + "github.com/go-logr/logr" + "github.com/go-logr/zapr" + "go.uber.org/zap" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/discovery" + "k8s.io/client-go/discovery/cached/memory" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/restmapper" + "sigs.k8s.io/controller-runtime/pkg/client/config" +) + +var ( + dynClient dynamic.Interface + mapper meta.RESTMapper + l logr.Logger + ctx context.Context +) + +func init() { + cfg := config.GetConfigOrDie() + + dynClient, _ = dynamic.NewForConfig(cfg) + + discoClient, _ := discovery.NewDiscoveryClientForConfig(cfg) + + cachedDisco := memory.NewMemCacheClient(discoClient) + mapper = restmapper.NewDeferredDiscoveryRESTMapper(cachedDisco) + + zapLogger, _ := zap.NewDevelopment() + l = zapr.NewLogger(zapLogger) + ctx = logr.NewContext(context.Background(), l) +} + +// labelsMapper implements AppMapper using HelmRelease labels. +type labelsMapper struct{} + +func (m *labelsMapper) Map(hr *helmv2.HelmRelease) (string, string, string, error) { + if hr.Labels == nil { + return "", "", "", fmt.Errorf("cannot map helm release %s/%s: labels are nil", hr.Namespace, hr.Name) + } + + appKind, ok := hr.Labels["apps.cozystack.io/application.kind"] + if !ok { + return "", "", "", fmt.Errorf("cannot map helm release %s/%s: missing application.kind label", hr.Namespace, hr.Name) + } + + appGroup, ok := hr.Labels["apps.cozystack.io/application.group"] + if !ok { + return "", "", "", fmt.Errorf("cannot map helm release %s/%s: missing application.group label", hr.Namespace, hr.Name) + } + + appName, ok := hr.Labels["apps.cozystack.io/application.name"] + if !ok { + return "", "", "", fmt.Errorf("cannot map helm release %s/%s: missing application.name label", hr.Namespace, hr.Name) + } + + apiVersion := fmt.Sprintf("%s/v1alpha1", appGroup) + prefix := strings.TrimSuffix(hr.Name, appName) + + return apiVersion, appKind, prefix, nil +} + +func TestWalkingOwnershipGraph(t *testing.T) { + obj, err := dynClient.Resource(schema.GroupVersionResource{"", "v1", "pods"}).Namespace(os.Args[1]).Get(ctx, os.Args[2], metav1.GetOptions{}) + if err != nil { + t.Fatal(err) + } + nodes := WalkOwnershipGraph(ctx, dynClient, mapper, &labelsMapper{}, obj) + for _, node := range nodes { + fmt.Printf("%#v\n", node) + } +} diff --git a/pkg/ovnstatus/normalize.go b/pkg/ovnstatus/normalize.go new file mode 100644 index 00000000..2ed999a4 --- /dev/null +++ b/pkg/ovnstatus/normalize.go @@ -0,0 +1,115 @@ +package ovnstatus + +import "strings" + +// ----- SID normalization (handles legacy "b007" style SIDs) ----- + +// NormalizeViews expands truncated SIDs in each MemberView's Members map, +// using IP->fullSID learned from reporters and unique-prefix fallback. +type sidCanon struct{ raw, canon string } + +func NormalizeViews(views []MemberView) []MemberView { + // 1) Learn IP -> fullSID from reporters (self entries) + ipToFull := map[string]string{} + fullSIDs := map[string]struct{}{} + + for _, v := range views { + if v.FromSID != "" { + fullSIDs[v.FromSID] = struct{}{} + } + if v.FromAddress != "" { + ip := AddrToIP(v.FromAddress) + if ip != "" && v.FromSID != "" { + ipToFull[ip] = v.FromSID + } + } + } + + // Build a slice for prefix-matching fallback (hyphenless, lowercase) + var known []sidCanon + for fsid := range fullSIDs { + known = append(known, sidCanon{ + raw: fsid, + canon: canonizeSID(fsid), + }) + } + + // 2) Normalize each view's Members by replacing short SIDs with full SIDs + out := make([]MemberView, 0, len(views)) + for _, v := range views { + mv := MemberView{ + FromSID: normalizeOneSID(v.FromSID, v.FromAddress, ipToFull, known), + FromAddress: v.FromAddress, + Members: make(map[string]string, len(v.Members)), + } + for sid, addr := range v.Members { + full := normalizeOneSIDWithAddr(sid, addr, ipToFull, known) + // If remapping causes a collision, prefer keeping the address + // from the entry that matches the full SID (no-op), otherwise last write wins. + mv.Members[full] = addr + } + out = append(out, mv) + } + return out +} + +func normalizeOneSIDWithAddr(sid, addr string, ipToFull map[string]string, known []sidCanon) string { + // If it's already full-ish, return as-is + if looksFullSID(sid) { + return sid + } + // First try IP mapping + if ip := AddrToIP(addr); ip != "" { + if fsid, ok := ipToFull[ip]; ok { + return fsid + } + } + // Fallback: unique prefix match against known full SIDs (hyphens ignored) + return expandByUniquePrefix(sid, known) +} + +func normalizeOneSID(sid, selfAddr string, ipToFull map[string]string, known []sidCanon) string { + if looksFullSID(sid) { + return sid + } + if ip := AddrToIP(selfAddr); ip != "" { + if fsid, ok := ipToFull[ip]; ok { + return fsid + } + } + return expandByUniquePrefix(sid, known) +} + +func looksFullSID(s string) bool { + // Heuristic: a v4 UUID with hyphens is 36 chars. + // Some builds may print full without hyphens (32). Treat >= 32 hex-ish as "full". + cs := canonizeSID(s) + return len(cs) >= 32 +} + +func canonizeSID(s string) string { + // lower + drop hyphens for prefix comparisons + s = strings.ToLower(s) + return strings.ReplaceAll(s, "-", "") +} + +func expandByUniquePrefix(short string, known []sidCanon) string { + p := canonizeSID(short) + if p == "" { + return short + } + matches := make([]string, 0, 2) + for _, k := range known { + if strings.HasPrefix(k.canon, p) { + matches = append(matches, k.raw) + if len(matches) > 1 { + break + } + } + } + if len(matches) == 1 { + return matches[0] + } + // ambiguous or none → leave as-is (will still be visible in diagnostics) + return short +} diff --git a/pkg/ovnstatus/ovncluster.go b/pkg/ovnstatus/ovncluster.go new file mode 100644 index 00000000..9cab7d82 --- /dev/null +++ b/pkg/ovnstatus/ovncluster.go @@ -0,0 +1,604 @@ +package ovnstatus + +import ( + "fmt" + "sort" + "strings" +) + +// ---- Public API ------------------------------------------------------------ + +// MemberView is a normalized membership view (from one member's perspective). +type MemberView struct { + FromSID string // the reporter's SID (hs.Local.SID) + FromAddress string // best-effort: address of self from Servers (if present) + Members map[string]string // SID -> Address (as reported by this member) +} + +// ViewDiff is the difference between one view and a chosen "truth" view. +type ViewDiff struct { + MissingSIDs []string // SIDs absent in this view but present in truth + ExtraSIDs []string // SIDs present in this view but absent in truth + AddressMismatches map[string][2]string // SID -> [truthAddr, thisAddr] when both have SID but addresses differ +} + +// ConsensusResult summarizes cluster agreement across views. +type ConsensusResult struct { + AllAgree bool // true if all views are identical + HasMajority bool // true if some view is held by >= quorum + QuorumSize int // floor(n/2)+1 + MajorityKey string // canonical key of the majority view (if any) + MajorityMembers []string // SIDs of reporters in the majority + MinorityMembers []string // SIDs of reporters not in the majority + TruthView MemberView // the majority's canonical view (if HasMajority); empty otherwise + Diffs map[string]ViewDiff // per-reporter diffs vs TruthView (only meaningful if HasMajority) +} + +// BuildMemberView extracts a normalized view for one snapshot. +// It uses hs.Full.Servers as the authoritative list this reporter sees. +func BuildMemberView(hs HealthSnapshot) MemberView { + mv := MemberView{ + FromSID: hs.Local.SID, + Members: make(map[string]string, len(hs.Full.Servers)), + } + + // Fill Members map and try to capture self address. + for _, s := range hs.Full.Servers { + if s.SID == "" || s.Address == "" { + continue + } + mv.Members[s.SID] = s.Address + if s.Self { + mv.FromAddress = s.Address + } + } + return mv +} + +// AnalyzeConsensus checks agreement across a slice of views for one cluster. +// It answers: +// 1. do all views agree exactly? +// 2. if not, is there a majority agreement? +// 3. who’s in the minority, and how does each minority view differ? +func AnalyzeConsensus(views []MemberView) ConsensusResult { + n := len(views) + cr := ConsensusResult{ + QuorumSize: (n / 2) + 1, + Diffs: make(map[string]ViewDiff, n), + } + if n == 0 { + return cr + } + + // Fingerprint each view's Members map; group reporters by fingerprint key. + type group struct { + key string + views []MemberView + } + groupsByKey := map[string]*group{} + + for _, v := range views { + key := fingerprintMembers(v.Members) + g, ok := groupsByKey[key] + if !ok { + g = &group{key: key} + groupsByKey[key] = g + } + g.views = append(g.views, v) + } + + // If only one unique fingerprint → everyone agrees. + if len(groupsByKey) == 1 { + for _, g := range groupsByKey { + cr.AllAgree = true + cr.HasMajority = true + cr.MajorityKey = g.key + cr.TruthView = g.views[0] // any member in this group shares the same map + for _, v := range g.views { + cr.MajorityMembers = append(cr.MajorityMembers, v.FromSID) + cr.Diffs[v.FromSID] = ViewDiff{} // empty + } + return cr + } + } + + // Pick the largest group as a candidate majority. + var maxG *group + for _, g := range groupsByKey { + if maxG == nil || len(g.views) > len(maxG.views) { + maxG = g + } + } + if maxG != nil && len(maxG.views) >= cr.QuorumSize { + cr.HasMajority = true + cr.MajorityKey = maxG.key + cr.TruthView = maxG.views[0] // canonical truth view + for _, v := range maxG.views { + cr.MajorityMembers = append(cr.MajorityMembers, v.FromSID) + cr.Diffs[v.FromSID] = ViewDiff{} // empty + } + // Minority: everyone not in the majority group + majoritySet := map[string]struct{}{} + for _, v := range maxG.views { + majoritySet[v.FromSID] = struct{}{} + } + for _, v := range views { + if _, ok := majoritySet[v.FromSID]; !ok { + cr.MinorityMembers = append(cr.MinorityMembers, v.FromSID) + cr.Diffs[v.FromSID] = diffViews(cr.TruthView.Members, v.Members) + } + } + return cr + } + + // No majority -> pick the largest group as "reference" for diffs (optional). + // We'll still fill Diffs vs that reference to aid debugging. + if maxG != nil { + cr.TruthView = maxG.views[0] + for _, v := range views { + cr.Diffs[v.FromSID] = diffViews(cr.TruthView.Members, v.Members) + } + // Populate members lists (no majority) + for _, v := range maxG.views { + cr.MajorityMembers = append(cr.MajorityMembers, v.FromSID) + } + for _, v := range views { + found := false + for _, m := range cr.MajorityMembers { + if m == v.FromSID { + found = true + break + } + } + if !found { + cr.MinorityMembers = append(cr.MinorityMembers, v.FromSID) + } + } + } + return cr +} + +// ---- Internals ------------------------------------------------------------- + +func fingerprintMembers(m map[string]string) string { + // Produce a stable "SID=Addr" joined string. + if len(m) == 0 { + return "" + } + keys := make([]string, 0, len(m)) + for sid := range m { + keys = append(keys, sid) + } + sort.Strings(keys) + parts := make([]string, 0, len(keys)) + for _, sid := range keys { + parts = append(parts, sid+"="+m[sid]) + } + return strings.Join(parts, "|") +} + +func diffViews(truth, other map[string]string) ViewDiff { + var d ViewDiff + d.AddressMismatches = make(map[string][2]string) + + // Build sets + truthKeys := make([]string, 0, len(truth)) + otherKeys := make([]string, 0, len(other)) + for k := range truth { + truthKeys = append(truthKeys, k) + } + for k := range other { + otherKeys = append(otherKeys, k) + } + sort.Strings(truthKeys) + sort.Strings(otherKeys) + + // Missing & mismatches + for _, sid := range truthKeys { + tAddr := truth[sid] + oAddr, ok := other[sid] + if !ok { + d.MissingSIDs = append(d.MissingSIDs, sid) + continue + } + if tAddr != oAddr { + d.AddressMismatches[sid] = [2]string{tAddr, oAddr} + } + } + // Extra + for _, sid := range otherKeys { + if _, ok := truth[sid]; !ok { + d.ExtraSIDs = append(d.ExtraSIDs, sid) + } + } + return d +} + +// ---- Pretty helpers (optional) -------------------------------------------- + +func (cr ConsensusResult) String() string { + var b strings.Builder + fmt.Fprintf(&b, "AllAgree=%v, HasMajority=%v (quorum=%d)\n", cr.AllAgree, cr.HasMajority, cr.QuorumSize) + if cr.HasMajority { + fmt.Fprintf(&b, "MajorityMembers: %v\n", cr.MajorityMembers) + if len(cr.MinorityMembers) > 0 { + fmt.Fprintf(&b, "MinorityMembers: %v\n", cr.MinorityMembers) + } + } + for sid, d := range cr.Diffs { + if len(d.MissingSIDs) == 0 && len(d.ExtraSIDs) == 0 && len(d.AddressMismatches) == 0 { + continue + } + fmt.Fprintf(&b, "- %s diffs:\n", sid) + if len(d.MissingSIDs) > 0 { + fmt.Fprintf(&b, " missing: %v\n", d.MissingSIDs) + } + if len(d.ExtraSIDs) > 0 { + fmt.Fprintf(&b, " extra: %v\n", d.ExtraSIDs) + } + if len(d.AddressMismatches) > 0 { + fmt.Fprintf(&b, " addr mismatches:\n") + for k, v := range d.AddressMismatches { + fmt.Fprintf(&b, " %s: truth=%s this=%s\n", k, v[0], v[1]) + } + } + } + return b.String() +} + +// Hints about the cluster from outside OVN (e.g., Kubernetes). +type Hints struct { + // ExpectedReplicas, if >0, is the intended cluster size; if 0 and ExpectedIPs provided, + // we derive ExpectedReplicas = len(ExpectedIPs). + ExpectedReplicas int + + // ExpectedIPs is the set of node IPs you expect to participate (unique per member). + // Optional label can be a pod/node name for reporting (empty string is fine). + ExpectedIPs map[string]string // ip -> label +} + +// ExtendedConsensusResult augments ConsensusResult with IP-centric signals. +type ExtendedConsensusResult struct { + ConsensusResult + + // Union across all views (what anyone reported). + UnionMembers []string // SIDs (sorted) + UnionIPs []string // IPs (sorted) + + // Reporters (SIDs that produced a HealthSnapshot / self-view). + Reporters []string // SIDs (sorted) + + // Members that appear in UnionMembers but for which we have no reporter snapshot. + MissingReporters []string // SIDs (sorted) + + // IPs seen in union but NOT in hints.ExpectedIPs (if provided). + UnexpectedIPs []string // sorted + + // Expected IPs that did NOT appear anywhere in union. + MissingExpectedIPs []string // sorted + + // Size checks; MembersCount is distinct SIDs; DistinctIPCount is distinct IPs. + MembersCount int + DistinctIPCount int + TooManyMembers bool // MembersCount > ExpectedReplicas + TooFewMembers bool // MembersCount < ExpectedReplicas + ExpectedShortfall int // ExpectedReplicas - MembersCount (>=0) + ExpectedExcess int // MembersCount - ExpectedReplicas (>=0) + + // IPConflicts: an IP mapped to multiple SIDs (shouldn’t happen if identity is clean). + IPConflicts map[string][]string // ip -> []sids + + // SIDAddressDisagreements: number of distinct addresses observed for a SID. + SIDAddressDisagreements map[string]int // sid -> count(address variants) + + // Suspect stale SIDs: candidates to kick (heuristic, IP-focused). + // Ranked by: (1) IP not expected, (2) not self-reporting, (3) lowest reference count. + SuspectStaleSIDs []string // sorted by suspicion +} + +// AddrToIP extracts the host/IP from strings like: +// +// "tcp:10.0.0.1:6641", "ssl:[192.168.100.12]:6643", "tcp:[fe80::1]:6641" +func AddrToIP(addr string) string { + a := strings.TrimSpace(addr) + // Strip scheme prefix + if i := strings.Index(a, ":"); i != -1 && (strings.HasPrefix(a, "tcp:") || strings.HasPrefix(a, "ssl:")) { + a = a[i+1:] + } + // If bracketed IPv6: [fe80::1]:6641 + if strings.HasPrefix(a, "[") { + if j := strings.Index(a, "]"); j != -1 { + return a[1:j] + } + } + // IPv4 or unbracketed IPv6 with :port → split last colon safely + if i := strings.LastIndex(a, ":"); i != -1 { + return a[:i] + } + return a // fallback +} + +func setKeys(m map[string]struct{}) []string { + out := make([]string, 0, len(m)) + for k := range m { + out = append(out, k) + } + sort.Strings(out) + return out +} +func setDiff(a, b map[string]struct{}) []string { + out := []string{} + for k := range a { + if _, ok := b[k]; !ok { + out = append(out, k) + } + } + sort.Strings(out) + return out +} + +// AnalyzeConsensusWithIPHints extends AnalyzeConsensus using ExpectedIPs instead of ExpectedSIDs. +func AnalyzeConsensusWithIPHints(views []MemberView, hints *Hints) ExtendedConsensusResult { + base := AnalyzeConsensus(views) // keeps majority/minority, per-view diffs (SID->addr) + + // Build unions and stats + unionSID := map[string]struct{}{} + unionIP := map[string]struct{}{} + reporterSID := map[string]struct{}{} + refCountSID := map[string]int{} // how many times a SID is referenced across all views + addrVariantsSID := map[string]map[string]struct{}{} // SID -> set(address strings) + ipToSIDs := map[string]map[string]struct{}{} // ip -> set(SID) + + for _, v := range views { + if v.FromSID != "" { + reporterSID[v.FromSID] = struct{}{} + } + for sid, addr := range v.Members { + if sid == "" || addr == "" { + continue + } + unionSID[sid] = struct{}{} + refCountSID[sid]++ + // address canon + if _, ok := addrVariantsSID[sid]; !ok { + addrVariantsSID[sid] = map[string]struct{}{} + } + addrVariantsSID[sid][addr] = struct{}{} + // IP canon + ip := AddrToIP(addr) + if ip != "" { + unionIP[ip] = struct{}{} + if _, ok := ipToSIDs[ip]; !ok { + ipToSIDs[ip] = map[string]struct{}{} + } + ipToSIDs[ip][sid] = struct{}{} + } + } + } + + // Prepare hint set for IPs + var expectedIPsSet map[string]struct{} + expectedReplicas := 0 + if hints != nil { + if len(hints.ExpectedIPs) > 0 { + expectedIPsSet = make(map[string]struct{}, len(hints.ExpectedIPs)) + for ip := range hints.ExpectedIPs { + expectedIPsSet[ip] = struct{}{} + } + expectedReplicas = len(hints.ExpectedIPs) + } + if hints.ExpectedReplicas > 0 { + expectedReplicas = hints.ExpectedReplicas + } + } + + unionSIDs := setKeys(unionSID) + unionIPs := setKeys(unionIP) + reporters := setKeys(reporterSID) + missingReporters := setDiff(unionSID, reporterSID) // SIDs seen but no self-view + + // IP-based unexpected / missing vs hints + var unexpectedIPs, missingExpectedIPs []string + if expectedIPsSet != nil { + unexpectedIPs = setDiff(unionIP, expectedIPsSet) + missingExpectedIPs = setDiff(expectedIPsSet, unionIP) + } + + // Size checks (by SIDs) + membersCount := len(unionSID) + distinctIPCount := len(unionIP) + tooMany, tooFew := false, false + shortfall, excess := 0, 0 + if expectedReplicas > 0 { + if membersCount > expectedReplicas { + tooMany = true + excess = membersCount - expectedReplicas + } else if membersCount < expectedReplicas { + tooFew = true + shortfall = expectedReplicas - membersCount + } + } + + // IP conflicts: same IP claimed under multiple SIDs + ipConflicts := map[string][]string{} + for ip, sids := range ipToSIDs { + if len(sids) > 1 { + ipConflicts[ip] = setKeys(sids) + } + } + + // SID address disagreements: how many distinct addresses per SID + sidAddrDisagree := map[string]int{} + for sid, addrs := range addrVariantsSID { + sidAddrDisagree[sid] = len(addrs) + } + + // --- Suspect stale SIDs ------------------------------------------------- + // + // Only produce suspects when there is evidence of staleness: + // - too many members (over expected replicas), or + // - unexpected IPs exist, or + // - IP conflicts exist. + // Then rank by (unexpected IP) > (not self-reporting) > (low reference count) + // and trim to the number we actually need to remove (ExpectedExcess). + produceSuspects := tooMany || len(unexpectedIPs) > 0 || len(ipConflicts) > 0 + + suspectList := []string{} + if produceSuspects { + suspectScore := map[string]int{} + for sid := range unionSID { + score := 0 + + // Representative IP for this SID (pick lexicographically smallest addr -> ip) + var sidIP string + if av := addrVariantsSID[sid]; len(av) > 0 { + addrs := setKeys(av) + sort.Strings(addrs) + sidIP = AddrToIP(addrs[0]) + } + + // Strongest signal: IP not expected + if expectedIPsSet != nil && sidIP != "" { + if _, ok := expectedIPsSet[sidIP]; !ok { + score += 1000 + } + } + // Not self-reporting is suspicious (but not fatal by itself) + if _, ok := reporterSID[sid]; !ok { + score += 100 + } + // Fewer references → a bit more suspicious + score += 10 - min(refCountSID[sid], 10) + + suspectScore[sid] = score + } + + suspectList = make([]string, 0, len(suspectScore)) + for sid := range suspectScore { + suspectList = append(suspectList, sid) + } + sort.Slice(suspectList, func(i, j int) bool { + if suspectScore[suspectList[i]] != suspectScore[suspectList[j]] { + return suspectScore[suspectList[i]] > suspectScore[suspectList[j]] + } + return suspectList[i] < suspectList[j] + }) + + // Trim to just what we need to remediate if we’re over capacity. + if tooMany && excess > 0 && len(suspectList) > excess { + suspectList = suspectList[:excess] + } + } + + return ExtendedConsensusResult{ + ConsensusResult: base, + UnionMembers: unionSIDs, + UnionIPs: unionIPs, + Reporters: reporters, + MissingReporters: missingReporters, + UnexpectedIPs: unexpectedIPs, + MissingExpectedIPs: missingExpectedIPs, + MembersCount: membersCount, + DistinctIPCount: distinctIPCount, + TooManyMembers: tooMany, + TooFewMembers: tooFew, + ExpectedShortfall: shortfall, + ExpectedExcess: excess, + IPConflicts: ipConflicts, + SIDAddressDisagreements: sidAddrDisagree, + SuspectStaleSIDs: suspectList, + } +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +// PrettyString renders a human-friendly multi-line summary of ExtendedConsensusResult. +// It combines consensus status with IP/SID hints. +func (res ExtendedConsensusResult) PrettyString() string { + var b strings.Builder + + fmt.Fprintf(&b, "Consensus summary:\n") + fmt.Fprintf(&b, " AllAgree: %v\n", res.AllAgree) + fmt.Fprintf(&b, " HasMajority: %v (quorum=%d)\n", res.HasMajority, res.QuorumSize) + fmt.Fprintf(&b, " MembersCount: %d (distinct IPs=%d)\n", res.MembersCount, res.DistinctIPCount) + + if res.TooManyMembers { + fmt.Fprintf(&b, " ⚠ Too many members: expected %d, found %d (excess=%d)\n", + res.MembersCount-res.ExpectedExcess, res.MembersCount, res.ExpectedExcess) + } + if res.TooFewMembers { + fmt.Fprintf(&b, " ⚠ Too few members: expected %d, found %d (shortfall=%d)\n", + res.MembersCount+res.ExpectedShortfall, res.MembersCount, res.ExpectedShortfall) + } + + if len(res.MajorityMembers) > 0 { + fmt.Fprintf(&b, " MajorityMembers (SIDs): %v\n", res.MajorityMembers) + } + if len(res.MinorityMembers) > 0 { + fmt.Fprintf(&b, " MinorityMembers (SIDs): %v\n", res.MinorityMembers) + } + + if len(res.UnionIPs) > 0 { + fmt.Fprintf(&b, " Union IPs: %v\n", res.UnionIPs) + } + if len(res.Reporters) > 0 { + fmt.Fprintf(&b, " Reporters (self-SIDs): %v\n", res.Reporters) + } + if len(res.MissingReporters) > 0 { + fmt.Fprintf(&b, " ⚠ MissingReporters (no self-view): %v\n", res.MissingReporters) + } + + if len(res.UnexpectedIPs) > 0 { + fmt.Fprintf(&b, " ⚠ UnexpectedIPs: %v\n", res.UnexpectedIPs) + } + if len(res.MissingExpectedIPs) > 0 { + fmt.Fprintf(&b, " ⚠ MissingExpectedIPs: %v\n", res.MissingExpectedIPs) + } + + if len(res.IPConflicts) > 0 { + fmt.Fprintf(&b, " ⚠ IP conflicts:\n") + for ip, sids := range res.IPConflicts { + fmt.Fprintf(&b, " %s claimed by %v\n", ip, sids) + } + } + + if len(res.SIDAddressDisagreements) > 0 { + fmt.Fprintf(&b, " SID address disagreements:\n") + for sid, n := range res.SIDAddressDisagreements { + if n > 1 { + fmt.Fprintf(&b, " %s has %d distinct addresses\n", sid, n) + } + } + } + + if len(res.SuspectStaleSIDs) > 0 { + fmt.Fprintf(&b, " ⚠ SuspectStaleSIDs (ranked): %v\n", res.SuspectStaleSIDs) + } + + // Per-reporter diffs vs truth + if len(res.Diffs) > 0 && res.HasMajority { + fmt.Fprintf(&b, " Diffs vs truth view:\n") + for sid, d := range res.Diffs { + if len(d.MissingSIDs) == 0 && len(d.ExtraSIDs) == 0 && len(d.AddressMismatches) == 0 { + continue + } + fmt.Fprintf(&b, " %s:\n", sid) + if len(d.MissingSIDs) > 0 { + fmt.Fprintf(&b, " missing SIDs: %v\n", d.MissingSIDs) + } + if len(d.ExtraSIDs) > 0 { + fmt.Fprintf(&b, " extra SIDs: %v\n", d.ExtraSIDs) + } + for k, v := range d.AddressMismatches { + fmt.Fprintf(&b, " addr mismatch for %s: truth=%s this=%s\n", k, v[0], v[1]) + } + } + } + + return b.String() +} diff --git a/pkg/ovnstatus/ovnstatus.go b/pkg/ovnstatus/ovnstatus.go new file mode 100644 index 00000000..b5fdf0e0 --- /dev/null +++ b/pkg/ovnstatus/ovnstatus.go @@ -0,0 +1,458 @@ +// Package ovnstatus provides an OVNClient that returns structured NB/SB health. +// It prefers JSON outputs and falls back to minimal text parsing for "Servers". +package ovnstatus + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "os/exec" + "regexp" + "strconv" + "strings" + "time" + "unicode" + "unicode/utf8" +) + +/************** Public API **************/ + +// DB is the logical DB name in ovsdb-server. +type DB string + +const ( + DBNorthbound DB = "OVN_Northbound" + DBSouthbound DB = "OVN_Southbound" +) + +// RunnerFunc allows dependency-injecting the command runner. +type RunnerFunc func(ctx context.Context, bin string, args ...string) (string, error) + +// OVNClient holds config + runner and exposes health methods. +type OVNClient struct { + // Paths to local control sockets. + NBCTLPath string // e.g., /var/run/ovn/ovnnb_db.ctl + SBCTLPath string // e.g., /var/run/ovn/ovnsb_db.ctl + NBDBSock string // tcp:127.0.0.1:6641, unix:/var/run/ovn/ovnnb_db.sock, etc + SBDBSock string // tcp:127.0.0.1:6642, unix:/var/run/ovn/ovnsb_db.sock, etc + + // TLS for ovsdb-client (used for _Server queries). ovn-appctl uses ctl socket, no TLS needed. + UseSSL bool + Key string + Cert string + CACert string + + FreshLastMsgThreshold time.Duration + // Optional expected replica count for stale-member checks. + ExpectedReplicas int + + // Runner is the pluggable command runner. If nil, a default runner is used. + Runner RunnerFunc +} + +func (o *OVNClient) ApplyDefaults() { + if o.NBCTLPath == "" { + o.NBCTLPath = "/var/run/ovn/ovnnb_db.ctl" + } + if o.SBCTLPath == "" { + o.SBCTLPath = "/var/run/ovn/ovnsb_db.ctl" + } + if o.NBDBSock == "" { + o.NBDBSock = "unix:/var/run/ovn/ovnnb_db.sock" + } + if o.SBDBSock == "" { + o.SBDBSock = "unix:/var/run/ovn/ovnsb_db.sock" + } + if o.ExpectedReplicas == 0 { + o.ExpectedReplicas = 3 + } + if o.FreshLastMsgThreshold == 0 { + o.FreshLastMsgThreshold = 10 * time.Second + } +} + +// ServerLocalView is what the local ovsdb-server reports via _Server.Database. +type ServerLocalView struct { + Leader bool `json:"leader"` + Connected bool `json:"connected"` + CID string `json:"cid"` // cluster UUID + SID string `json:"sid"` // this server UUID + Index int64 `json:"index"` +} + +// ClusterStatus is a structured view of cluster/status. +type ClusterStatus struct { + Name string `json:"name,omitempty"` + Role string `json:"role,omitempty"` // leader/follower (local) + Term int64 `json:"term,omitempty"` + Index int64 `json:"index,omitempty"` + Connected bool `json:"connected,omitempty"` + Servers []ClusterServer `json:"servers,omitempty"` +} + +// ClusterServer is an entry in the Servers list. +type ClusterServer struct { + SID string `json:"sid,omitempty"` + Address string `json:"address,omitempty"` + Role string `json:"role,omitempty"` + Self bool `json:"self,omitempty"` + Connected bool `json:"connected,omitempty"` + LastMsgMs *int64 `json:"lastMsgMs,omitempty"` + NextIndex *int64 `json:"nextIndex,omitempty"` // NEW + MatchIndex *int64 `json:"matchIndex,omitempty"` // NEW +} + +// HealthSnapshot bundles both sources for easy checks. +type HealthSnapshot struct { + DB DB + Local ServerLocalView + Full ClusterStatus +} + +// StaleMemberCount returns how many configured servers exceed the expected replica count. +func (hs HealthSnapshot) StaleMemberCount(expectedReplicas int) int { + n := len(hs.Full.Servers) + if n <= expectedReplicas { + return 0 + } + return n - expectedReplicas +} + +// HasQuorum returns whether the local server believes it has a majority. +func (hs HealthSnapshot) HasQuorum() bool { return hs.Local.Connected } + +// IsLeader reports local leadership (per-DB). +func (hs HealthSnapshot) IsLeader() bool { return hs.Local.Leader } + +// HealthNB returns a health snapshot for OVN_Northbound. +func (c *OVNClient) HealthNB(ctx context.Context) (HealthSnapshot, error) { + return c.health(ctx, DBNorthbound, c.NBCTLPath) +} + +// HealthSB returns a health snapshot for OVN_Southbound. +func (c *OVNClient) HealthSB(ctx context.Context) (HealthSnapshot, error) { + return c.health(ctx, DBSouthbound, c.SBCTLPath) +} + +// HealthBoth returns snapshots for both NB and SB. +func (c *OVNClient) HealthBoth(ctx context.Context) (nb HealthSnapshot, sb HealthSnapshot, err1, err2 error) { + nb, err1 = c.HealthNB(ctx) + sb, err2 = c.HealthSB(ctx) + return nb, sb, err1, err2 +} + +/************** Implementation **************/ + +func (c *OVNClient) health(ctx context.Context, db DB, ctlPath string) (HealthSnapshot, error) { + if ctlPath == "" { + return HealthSnapshot{}, fmt.Errorf("missing ctlPath for %s", db) + } + local, err := c.getLocalServerView(ctx, db) + if err != nil { + return HealthSnapshot{}, err + } + full, err := c.getClusterStatus(ctx, db, ctlPath) + if err != nil { + // Return at least the local view. + return HealthSnapshot{DB: db, Local: local}, err + } + // Optional cosmetic: sort Servers for stable output (self first, then by SID). + /* + sort.SliceStable(full.Servers, func(i, j int) bool { + if full.Servers[i].Self != full.Servers[j].Self { + return full.Servers[i].Self + } + return full.Servers[i].SID < full.Servers[j].SID + }) + */ + return HealthSnapshot{DB: db, Local: local, Full: full}, nil +} + +type ovsdbQueryResp struct { + Rows []struct { + Leader bool `json:"leader"` + Connected bool `json:"connected"` + CID []string `json:"cid"` + SID []string `json:"sid"` + Index int64 `json:"index"` + } `json:"rows"` +} + +func (c *OVNClient) getLocalServerView(ctx context.Context, db DB) (ServerLocalView, error) { + addr := "" + switch db { + case DBNorthbound: + addr = c.NBDBSock + case DBSouthbound: + addr = c.SBDBSock + default: + return ServerLocalView{}, fmt.Errorf("unexpected value %s for ovn db, expected values %s, %s", db, DBNorthbound, DBSouthbound) + } + + query := fmt.Sprintf( + `["_Server",{"op":"select","table":"Database","where":[["name","==","%s"]],"columns":["leader","connected","cid","sid","index"]}]`, + db, + ) + + args := []string{"query", addr, query} + if c.UseSSL { + args = []string{ + "-p", c.Key, "-c", c.Cert, "-C", c.CACert, + "query", addr, query, + } + } + + out, err := c.run(ctx, "ovsdb-client", args...) + if err != nil { + return ServerLocalView{}, fmt.Errorf("ovsdb-client query failed: %w (out: %s)", err, out) + } + + var resp []ovsdbQueryResp + if err := json.Unmarshal([]byte(out), &resp); err != nil { + return ServerLocalView{}, fmt.Errorf("parse _Server.Database JSON: %w", err) + } + if len(resp) == 0 || len(resp[0].Rows) == 0 { + return ServerLocalView{}, errors.New("empty _Server.Database response") + } + row := resp[0].Rows[0] + uuidOf := func(arr []string) (string, bool) { + if len(arr) == 2 && arr[0] == "uuid" && arr[1] != "" { + return arr[1], true + } + return "", false + } + cid, okCID := uuidOf(row.CID) + sid, okSID := uuidOf(row.SID) + if !okCID || !okSID { + return ServerLocalView{}, fmt.Errorf("unexpected _Server.Database uuid encoding: cid=%v sid=%v", row.CID, row.SID) + } + return ServerLocalView{ + Leader: row.Leader, + Connected: row.Connected, + CID: cid, + SID: sid, + Index: row.Index, + }, nil +} + +func (c *OVNClient) getClusterStatus(ctx context.Context, db DB, ctlPath string) (ClusterStatus, error) { + out, err := c.run(ctx, "ovn-appctl", "-t", ctlPath, "cluster/status", string(db)) + if err != nil { + return ClusterStatus{}, fmt.Errorf("cluster/status failed: %w (out: %s)", err, out) + } + return parseServersFromTextWithThreshold(out, c.FreshLastMsgThreshold), nil +} + +func (c *OVNClient) run(ctx context.Context, bin string, args ...string) (string, error) { + runner := c.Runner + if runner == nil { + runner = defaultRunner + } + return runner(ctx, bin, args...) +} + +/************** Default runner **************/ + +func defaultRunner(ctx context.Context, bin string, args ...string) (string, error) { + // Reasonable default timeout; caller can supply a context with its own deadline. + if _, ok := ctx.Deadline(); !ok { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, 5*time.Second) + defer cancel() + } + cmd := exec.CommandContext(ctx, bin, args...) + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + err := cmd.Run() + out := strings.TrimSpace(stdout.String()) + if err != nil { + if out == "" { + out = strings.TrimSpace(stderr.String()) + } + return out, err + } + return out, nil +} + +/************** Helpers **************/ + +func parseClusterStatusJSON(out string) (ClusterStatus, bool) { + var cs ClusterStatus + if json.Unmarshal([]byte(out), &cs) == nil && len(cs.Servers) > 0 { + return cs, true + } + var wrap struct { + Data ClusterStatus `json:"data"` + } + if json.Unmarshal([]byte(out), &wrap) == nil && len(wrap.Data.Servers) > 0 { + return wrap.Data, true + } + return ClusterStatus{}, false +} + +func portOf(db DB) string { + switch db { + case DBNorthbound: + return "6641" + case DBSouthbound: + return "6642" + default: + return "0" + } +} + +/************** Minimal text fallback for "Servers" **************/ + +// Accepts variants like: +// +// Servers: +// 77f0 (self) at tcp:10.0.0.1:6641 (leader) +// 9a3b at tcp:10.0.0.2:6641 (follower) +// 1c2d at ssl:10.0.0.3:6641 (backup) +// 4e5f at tcp:10.0.0.4:6641 (disconnected) +var ( + reServersHeader = regexp.MustCompile(`(?m)^\s*Servers:\s*$`) + reServerModern = regexp.MustCompile(`^\s*([0-9a-fA-F-]+)\s*(\((?:self)\))?\s*at\s*([^\s]+)\s*\(([^)]+)\)`) + reServerLegacy = regexp.MustCompile( + `^\s*` + + `([0-9a-fA-F-]+)\s*` + // 1: primary SID + `\(\s*([0-9a-fA-F-]+)\s+at\s+([^)]+)\)\s*` + // 2: inner SID, 3: address (may include [ip]:port) + `(?:\((self)\)\s*)?` + // 4: optional "self" + `(?:next_index=(\d+)\s+match_index=(\d+)\s*)?` + // 5: next_index, 6: match_index + `(?:last msg\s+(\d+)\s+ms\s+ago)?\s*$`, // 7: last msg ms + ) +) + +func parseServersFromTextWithThreshold(text string, freshThreshold time.Duration) ClusterStatus { + if freshThreshold <= 0 { + freshThreshold = 10 * time.Second + } + freshMs := int64(freshThreshold / time.Millisecond) + + cs := ClusterStatus{} + section := extractServersBlock(text) + for _, ln := range strings.Split(section, "\n") { + ln = strings.TrimRight(ln, "\r") + if ln == "" { + continue + } + + // 1) Modern format + if m := reServerModern.FindStringSubmatch(ln); len(m) > 0 { + role := strings.ToLower(strings.TrimSpace(m[4])) + cs.Servers = append(cs.Servers, ClusterServer{ + SID: m[1], + Self: strings.Contains(m[2], "self"), + Address: strings.TrimSpace(m[3]), + Role: role, + Connected: !strings.Contains(role, "disconn"), + }) + continue + } + + // 2) Legacy format (with optional indices and last-msg) + if m := reServerLegacy.FindStringSubmatch(ln); len(m) > 0 { + var ( + nextIdxPtr, matchIdxPtr, lastMsgPtr *int64 + ) + if m[5] != "" { + if v, err := strconv.ParseInt(m[5], 10, 64); err == nil { + nextIdxPtr = &v + } + } + if m[6] != "" { + if v, err := strconv.ParseInt(m[6], 10, 64); err == nil { + matchIdxPtr = &v + } + } + if m[7] != "" { + if v, err := strconv.ParseInt(m[7], 10, 64); err == nil { + lastMsgPtr = &v + } + } + + s := ClusterServer{ + SID: m[1], + Self: m[4] == "self", + Address: strings.TrimSpace(m[3]), + NextIndex: nextIdxPtr, + MatchIndex: matchIdxPtr, + LastMsgMs: lastMsgPtr, + // Role unknown in this legacy format; leave empty. + } + + // Connected heuristic: + switch { + case lastMsgPtr != nil: + s.Connected = *lastMsgPtr <= freshMs + case s.Self: + s.Connected = true + case nextIdxPtr != nil || matchIdxPtr != nil: + // Seeing replication indices implies active exchange recently. + s.Connected = true + default: + s.Connected = false + } + + cs.Servers = append(cs.Servers, s) + continue + } + + // Unknown line → ignore + } + return cs +} + +func extractServersBlock(text string) string { + idx := reServersHeader.FindStringIndex(text) + if idx == nil { + return "" + } + rest := text[idx[1]:] + + var b strings.Builder + lines := strings.Split(rest, "\n") + sawAny := false + + for _, ln := range lines { + // Normalize line endings and look at indentation + ln = strings.TrimRight(ln, "\r") // handle CRLF + trimmed := strings.TrimSpace(ln) + + // Blank line terminates the section *after* we've started collecting + if trimmed == "" { + if sawAny { + break + } + continue + } + + // Does the line belong to the Servers block? + if startsWithUnicodeSpace(ln) || strings.HasPrefix(strings.TrimLeftFunc(ln, unicode.IsSpace), "-") { + b.WriteString(ln) + b.WriteByte('\n') + sawAny = true + continue + } + + // First non-indented, non-blank line after we've started → end of block. + if sawAny { + break + } + // If we haven't started yet and this line isn't indented, keep scanning + // (defensive; normally the very next line after "Servers:" is indented). + } + + return b.String() +} + +func startsWithUnicodeSpace(s string) bool { + if s == "" { + return false + } + r, _ := utf8.DecodeRuneInString(s) + return unicode.IsSpace(r) // catches ' ', '\t', '\r', etc. +} diff --git a/pkg/ovnstatus/ovnstatus_test.go b/pkg/ovnstatus/ovnstatus_test.go new file mode 100644 index 00000000..8dde66b3 --- /dev/null +++ b/pkg/ovnstatus/ovnstatus_test.go @@ -0,0 +1,40 @@ +package ovnstatus + +import ( + "fmt" + "testing" + "time" +) + +var testStdout = `` + + `Last Election started 259684608 ms ago, reason: leadership_transfer +Last Election won: 259684604 ms ago +Election timer: 5000 +Log: [20946, 20968] +Entries not yet committed: 0 +Entries not yet applied: 0 +Connections: ->7bdb ->b007 <-7bdb <-b007 +Disconnections: 34130 +Servers: + e40d (e40d at ssl:[192.168.100.12]:6643) (self) + 7bdb (7bdb at ssl:[192.168.100.11]:6643) last msg 425139 ms ago + b007 (b007 at ssl:[192.168.100.14]:6643) last msg 817 ms ago +` +var expectedServersBlock = `` + + ` e40d (e40d at ssl:[192.168.100.12]:6643) (self) + 7bdb (7bdb at ssl:[192.168.100.11]:6643) last msg 425139 ms ago + b007 (b007 at ssl:[192.168.100.14]:6643) last msg 817 ms ago +` + +func TestExtractServersBlock(t *testing.T) { + if actual := extractServersBlock(testStdout); actual != expectedServersBlock { + fmt.Println([]byte(actual)) + fmt.Println([]byte(expectedServersBlock)) + t.Errorf("error extracting servers block from following string:\n%s\nexpected:\n%s\ngot:\n%s\n", testStdout, expectedServersBlock, actual) + } +} + +func TestParseServersBlock(t *testing.T) { + cs := parseServersFromTextWithThreshold(testStdout, 10*time.Second) + fmt.Printf("%+v\n", cs) +} diff --git a/pkg/registry/apps/application/rest.go b/pkg/registry/apps/application/rest.go index 4b80daa3..d233ecc3 100644 --- a/pkg/registry/apps/application/rest.go +++ b/pkg/registry/apps/application/rest.go @@ -18,29 +18,41 @@ package application import ( "context" + "encoding/json" "fmt" "net/http" + "strconv" "strings" "sync" "time" + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" helmv2 "github.com/fluxcd/helm-controller/api/v2" + corev1 "k8s.io/api/core/v1" metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - fields "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/fields" labels "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/selection" "k8s.io/apimachinery/pkg/util/duration" + "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/watch" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/registry/rest" - "k8s.io/client-go/dynamic" "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + "github.com/cozystack/cozystack/pkg/apis/apps/validation" "github.com/cozystack/cozystack/pkg/config" + "github.com/cozystack/cozystack/pkg/registry" + fieldfilter "github.com/cozystack/cozystack/pkg/registry/fields" + "github.com/cozystack/cozystack/pkg/registry/sorting" + internalapiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema" // Importing API errors package to construct appropriate error responses apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -63,27 +75,52 @@ const ( AnnotationPrefix = "apps.cozystack.io-" ) -// Define the GroupVersionResource for HelmRelease -var helmReleaseGVR = schema.GroupVersionResource{ - Group: "helm.toolkit.fluxcd.io", - Version: "v2", - Resource: "helmreleases", -} +// Application label keys - use constants from API package +const ( + ApplicationKindLabel = appsv1alpha1.ApplicationKindLabel + ApplicationGroupLabel = appsv1alpha1.ApplicationGroupLabel + ApplicationNameLabel = appsv1alpha1.ApplicationNameLabel +) // REST implements the RESTStorage interface for Application resources type REST struct { - dynamicClient dynamic.Interface + c client.Client + w client.WithWatch gvr schema.GroupVersionResource gvk schema.GroupVersionKind kindName string singularName string releaseConfig config.ReleaseConfig + specSchema *structuralschema.Structural } // NewREST creates a new REST storage for Application with specific configuration -func NewREST(dynamicClient dynamic.Interface, config *config.Resource) *REST { +func NewREST(c client.Client, w client.WithWatch, config *config.Resource) *REST { + var specSchema *structuralschema.Structural + + if raw := strings.TrimSpace(config.Application.OpenAPISchema); raw != "" { + var v1js apiextv1.JSONSchemaProps + if err := json.Unmarshal([]byte(raw), &v1js); err != nil { + klog.Errorf("Failed to unmarshal v1 OpenAPI schema: %v", err) + } else { + scheme := runtime.NewScheme() + _ = internalapiext.AddToScheme(scheme) + _ = apiextv1.AddToScheme(scheme) + + var ijs internalapiext.JSONSchemaProps + if err := scheme.Convert(&v1js, &ijs, nil); err != nil { + klog.Errorf("Failed to convert v1->internal JSONSchemaProps: %v", err) + } else if s, err := structuralschema.NewStructural(&ijs); err != nil { + klog.Errorf("Failed to create structural schema: %v", err) + } else { + specSchema = s + } + } + } + return &REST{ - dynamicClient: dynamicClient, + c: c, + w: w, gvr: schema.GroupVersionResource{ Group: appsv1alpha1.GroupName, Version: "v1alpha1", @@ -96,6 +133,7 @@ func NewREST(dynamicClient dynamic.Interface, config *config.Resource) *REST { kindName: config.Application.Kind, singularName: config.Application.Singular, releaseConfig: config.Release, + specSchema: specSchema, } } @@ -114,7 +152,33 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation // Assert the object is of type Application app, ok := obj.(*appsv1alpha1.Application) if !ok { - return nil, fmt.Errorf("expected Application object, got %T", obj) + return nil, fmt.Errorf("expected *appsv1alpha1.Application object, got %T", obj) + } + + // Validate Application name format (DNS-1035 plus any kind-specific rules) + if errs := r.validateNameFormat(app.Name); len(errs) > 0 { + return nil, apierrors.NewInvalid(r.gvk.GroupKind(), app.Name, errs) + } + + // Validate name length against Helm release and label limits + if nameLenErrs := r.validateNameLength(app.Name); len(nameLenErrs) > 0 { + return nil, apierrors.NewInvalid(r.gvk.GroupKind(), app.Name, nameLenErrs) + } + + // For Tenant applications, also validate that the computed workload + // namespace fits within the DNS-1123 label limit. A deeply-nested tenant + // can exceed the limit even when its own name passes the per-name Helm + // release length check, because the namespace is formed from the full + // ancestor chain. + if r.kindName == "Tenant" { + if nsErrs := r.validateTenantNamespaceLength(app.Namespace, app.Name); len(nsErrs) > 0 { + return nil, apierrors.NewInvalid(r.gvk.GroupKind(), app.Name, nsErrs) + } + } + + // Validate that values don't contain reserved keys (starting with "_") + if err := validateNoInternalKeys(app.Spec); err != nil { + return nil, apierrors.NewBadRequest(err.Error()) } // Convert Application to HelmRelease @@ -128,42 +192,35 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation helmRelease.Labels = mergeMaps(r.releaseConfig.Labels, helmRelease.Labels) // Merge user labels with prefix helmRelease.Labels = mergeMaps(helmRelease.Labels, addPrefixedMap(app.Labels, LabelPrefix)) - // Note: Annotations from config are not handled as r.releaseConfig.Annotations is undefined - - // Convert HelmRelease to unstructured format - unstructuredHR, err := runtime.DefaultUnstructuredConverter.ToUnstructured(helmRelease) - if err != nil { - klog.Errorf("Failed to convert HelmRelease to unstructured: %v", err) - return nil, fmt.Errorf("failed to convert HelmRelease to unstructured: %v", err) + // Add application metadata labels + if helmRelease.Labels == nil { + helmRelease.Labels = make(map[string]string) } + helmRelease.Labels[ApplicationKindLabel] = r.kindName + helmRelease.Labels[ApplicationGroupLabel] = r.gvk.Group + helmRelease.Labels[ApplicationNameLabel] = app.Name + // Note: Annotations from config are not handled as r.releaseConfig.Annotations is undefined klog.V(6).Infof("Creating HelmRelease %s in namespace %s", helmRelease.Name, app.Namespace) // Create HelmRelease in Kubernetes - createdHR, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(app.Namespace).Create(ctx, &unstructured.Unstructured{Object: unstructuredHR}, *options) + err = r.c.Create(ctx, helmRelease, &client.CreateOptions{Raw: options}) if err != nil { klog.Errorf("Failed to create HelmRelease %s: %v", helmRelease.Name, err) return nil, fmt.Errorf("failed to create HelmRelease: %v", err) } // Convert the created HelmRelease back to Application - convertedApp, err := r.ConvertHelmReleaseToApplication(createdHR) + convertedApp, err := r.ConvertHelmReleaseToApplication(ctx, helmRelease) if err != nil { - klog.Errorf("Conversion error from HelmRelease to Application for resource %s: %v", createdHR.GetName(), err) + klog.Errorf("Conversion error from HelmRelease to Application for resource %s: %v", helmRelease.GetName(), err) return nil, fmt.Errorf("conversion error: %v", err) } - klog.V(6).Infof("Successfully created and converted HelmRelease %s to Application", createdHR.GetName()) + klog.V(6).Infof("Successfully created and converted HelmRelease %s to Application", helmRelease.GetName()) - // Convert Application to unstructured format - unstructuredApp, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&convertedApp) - if err != nil { - klog.Errorf("Failed to convert Application to unstructured for resource %s: %v", convertedApp.GetName(), err) - return nil, fmt.Errorf("failed to convert Application to unstructured: %v", err) - } - - klog.V(6).Infof("Successfully retrieved and converted resource %s of type %s to unstructured", convertedApp.GetName(), r.gvr.Resource) - return &unstructured.Unstructured{Object: unstructuredApp}, nil + klog.V(6).Infof("Successfully retrieved and converted resource %s of type %s", convertedApp.GetName(), r.gvr.Resource) + return &convertedApp, nil } // Get retrieves an Application by converting the corresponding HelmRelease @@ -178,7 +235,8 @@ func (r *REST) Get(ctx context.Context, name string, options *metav1.GetOptions) // Get the corresponding HelmRelease using the new prefix helmReleaseName := r.releaseConfig.Prefix + name - hr, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(namespace).Get(ctx, helmReleaseName, *options) + helmRelease := &helmv2.HelmRelease{} + err = r.c.Get(ctx, client.ObjectKey{Namespace: namespace, Name: helmReleaseName}, helmRelease, &client.GetOptions{Raw: options}) if err != nil { klog.Errorf("Error retrieving HelmRelease for resource %s: %v", name, err) @@ -192,39 +250,22 @@ func (r *REST) Get(ctx context.Context, name string, options *metav1.GetOptions) return nil, err } - // Check if HelmRelease meets the required chartName and sourceRef criteria - if !r.shouldIncludeHelmRelease(hr) { - klog.Errorf("HelmRelease %s does not match the required chartName and sourceRef criteria", helmReleaseName) + // Check if HelmRelease has required labels + if !r.hasRequiredApplicationLabels(helmRelease) { + klog.Errorf("HelmRelease %s does not match the required application labels", helmReleaseName) // Return a NotFound error for the Application resource return nil, apierrors.NewNotFound(r.gvr.GroupResource(), name) } // Convert HelmRelease to Application - convertedApp, err := r.ConvertHelmReleaseToApplication(hr) + convertedApp, err := r.ConvertHelmReleaseToApplication(ctx, helmRelease) if err != nil { klog.Errorf("Conversion error from HelmRelease to Application for resource %s: %v", name, err) return nil, fmt.Errorf("conversion error: %v", err) } - // Explicitly set apiVersion and kind for Application - convertedApp.TypeMeta = metav1.TypeMeta{ - APIVersion: "apps.cozystack.io/v1alpha1", - Kind: r.kindName, - } - - // Convert Application to unstructured format - unstructuredApp, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&convertedApp) - if err != nil { - klog.Errorf("Failed to convert Application to unstructured for resource %s: %v", name, err) - return nil, fmt.Errorf("failed to convert Application to unstructured: %v", err) - } - - // Explicitly set apiVersion and kind in unstructured object - unstructuredApp["apiVersion"] = "apps.cozystack.io/v1alpha1" - unstructuredApp["kind"] = r.kindName - - klog.V(6).Infof("Successfully retrieved and converted resource %s of kind %s to unstructured", name, r.gvr.Resource) - return &unstructured.Unstructured{Object: unstructuredApp}, nil + klog.V(6).Infof("Successfully retrieved and converted resource %s of kind %s", name, r.gvr.Resource) + return &convertedApp, nil } // List retrieves a list of Applications by converting HelmReleases @@ -235,7 +276,7 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption return nil, err } - klog.V(6).Infof("Attempting to list HelmReleases in namespace %s with options: %v", namespace, options) + klog.V(6).Infof("List called for %s in namespace %q", r.kindName, namespace) // Get resource name from the request (if any) var resourceName string @@ -244,30 +285,48 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption } // Initialize variables for selector mapping - var helmFieldSelector string - var helmLabelSelector string + var helmLabelSelector labels.Selector - // Process field.selector - if options.FieldSelector != nil { - fs, err := fields.ParseSelector(options.FieldSelector.String()) - if err != nil { - klog.Errorf("Invalid field selector: %v", err) - return nil, fmt.Errorf("invalid field selector: %v", err) - } + // Parse field selector for manual filtering + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + fieldFilter, err := fieldfilter.ParseFieldSelector(options.FieldSelector) + if err != nil { + klog.Errorf("Error parsing field selector: %v", err) + return nil, err + } - // Check if selector is for metadata.name - if name, exists := fs.RequiresExactMatch("metadata.name"); exists { - // Convert Application name to HelmRelease name - mappedName := r.releaseConfig.Prefix + name - // Create new field.selector for HelmRelease - helmFieldSelector = fields.OneTermEqualSelector("metadata.name", mappedName).String() - } else { - // If field.selector contains other fields, map them directly - helmFieldSelector = fs.String() - } + // If field selector specifies namespace different from context, return empty list + if fieldFilter.Namespace != "" && namespace != "" && namespace != fieldFilter.Namespace { + klog.V(6).Infof("Field selector namespace %s doesn't match context namespace %s, returning empty list", fieldFilter.Namespace, namespace) + return &appsv1alpha1.ApplicationList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: appsv1alpha1.SchemeGroupVersion.String(), + Kind: r.kindName + "List", + }, + }, nil + } + + // Convert Application name to HelmRelease name for manual filtering + var filterByName string + if fieldFilter.Name != "" { + filterByName = r.releaseConfig.Prefix + fieldFilter.Name } // Process label.selector + // Always add application metadata label requirements + appKindReq, err := labels.NewRequirement(ApplicationKindLabel, selection.Equals, []string{r.kindName}) + if err != nil { + klog.Errorf("Error creating application kind label requirement: %v", err) + return nil, fmt.Errorf("error creating application kind label requirement: %v", err) + } + appGroupReq, err := labels.NewRequirement(ApplicationGroupLabel, selection.Equals, []string{r.gvk.Group}) + if err != nil { + klog.Errorf("Error creating application group label requirement: %v", err) + return nil, fmt.Errorf("error creating application group label requirement: %v", err) + } + labelRequirements := []labels.Requirement{*appKindReq, *appGroupReq} + if options.LabelSelector != nil { ls := options.LabelSelector.String() parsedLabels, err := labels.Parse(ls) @@ -287,42 +346,46 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption } prefixedReqs = append(prefixedReqs, *prefixedReq) } - helmLabelSelector = labels.NewSelector().Add(prefixedReqs...).String() + labelRequirements = append(labelRequirements, prefixedReqs...) } } + helmLabelSelector = labels.NewSelector().Add(labelRequirements...) - // Set ListOptions for HelmRelease with selector mapping - metaOptions := metav1.ListOptions{ - FieldSelector: helmFieldSelector, + klog.V(6).Infof("Using label selector: %s for kind: %s, group: %s", helmLabelSelector, r.kindName, r.gvk.Group) + + // List HelmReleases with label selector only + // Field selectors are not supported by controller-runtime cache, so we filter manually below + hrList := &helmv2.HelmReleaseList{} + err = r.c.List(ctx, hrList, &client.ListOptions{ + Namespace: namespace, LabelSelector: helmLabelSelector, - } - - // List HelmReleases with mapped selectors - hrList, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(namespace).List(ctx, metaOptions) + }) if err != nil { klog.Errorf("Error listing HelmReleases: %v", err) return nil, err } - // Initialize empty Application list - appList := &appsv1alpha1.ApplicationList{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps.cozystack.io/v1alpha1", - Kind: "ApplicationList", - }, - ListMeta: metav1.ListMeta{ - ResourceVersion: hrList.GetResourceVersion(), - }, - Items: []appsv1alpha1.Application{}, - } + klog.V(6).Infof("Found %d HelmReleases with label selector", len(hrList.Items)) + + // Initialize Application items array + items := make([]appsv1alpha1.Application, 0, len(hrList.Items)) // Iterate over HelmReleases and convert to Applications - for _, hr := range hrList.Items { - if !r.shouldIncludeHelmRelease(&hr) { + // Note: All HelmReleases already match the required labels due to server-side label selector filtering + for i := range hrList.Items { + hr := &hrList.Items[i] + + // Apply manual field selector filtering (metadata.name and metadata.namespace) + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + if filterByName != "" && hr.Name != filterByName { + continue + } + if !fieldFilter.MatchesNamespace(hr.Namespace) { continue } - app, err := r.ConvertHelmReleaseToApplication(&hr) + app, err := r.ConvertHelmReleaseToApplication(ctx, hr) if err != nil { klog.Errorf("Error converting HelmRelease %s to Application: %v", hr.GetName(), err) continue @@ -352,7 +415,6 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption klog.Errorf("Invalid field selector: %v", err) continue } - fieldsSet := fields.Set{ "metadata.name": app.Name, "metadata.namespace": app.Namespace, @@ -362,10 +424,25 @@ func (r *REST) List(ctx context.Context, options *metainternalversion.ListOption } } - appList.Items = append(appList.Items, app) + items = append(items, app) } - klog.V(6).Infof("Successfully listed %d Application resources in namespace %s", len(appList.Items), namespace) + // Create ApplicationList with proper kind + appList := r.NewList().(*appsv1alpha1.ApplicationList) + + // Get ResourceVersion from list or compute from items + // controller-runtime cached client may not set ResourceVersion on the list itself + listRV := hrList.GetResourceVersion() + if listRV == "" { + listRV, _ = registry.MaxResourceVersion(hrList) + } + appList.SetResourceVersion(listRV) + appList.Items = items + + sorting.ByNamespacedName[appsv1alpha1.Application, *appsv1alpha1.Application](appList.Items) + + klog.V(6).Infof("List returning %d items for %s in namespace %q, resourceVersion=%q", + len(items), r.kindName, namespace, appList.GetResourceVersion()) return appList, nil } @@ -413,9 +490,17 @@ func (r *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObje // Assert the new object is of type Application app, ok := newObj.(*appsv1alpha1.Application) if !ok { - errMsg := fmt.Sprintf("expected Application object, got %T", newObj) - klog.Errorf(errMsg) - return nil, false, fmt.Errorf(errMsg) + klog.Errorf("expected *appsv1alpha1.Application object, got %T", newObj) + return nil, false, fmt.Errorf("expected *appsv1alpha1.Application object, got %T", newObj) + } + + // Note: name validation (DNS-1035 format + length) is intentionally skipped on + // Update because Kubernetes names are immutable. Validating here would block + // updates to pre-existing resources whose names don't conform to the new rules. + + // Validate that values don't contain reserved keys (starting with "_") + if err := validateNoInternalKeys(app.Spec); err != nil { + return nil, false, apierrors.NewBadRequest(err.Error()) } // Convert Application to HelmRelease @@ -427,7 +512,8 @@ func (r *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObje // Ensure ResourceVersion if helmRelease.ResourceVersion == "" { - cur, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(helmRelease.Namespace).Get(ctx, helmRelease.Name, metav1.GetOptions{}) + cur := &helmv2.HelmRelease{} + err := r.c.Get(ctx, client.ObjectKey{Namespace: helmRelease.Namespace, Name: helmRelease.Name}, cur, &client.GetOptions{Raw: &metav1.GetOptions{}}) if err != nil { return nil, false, fmt.Errorf("failed to fetch current HelmRelease: %w", err) } @@ -438,76 +524,36 @@ func (r *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObje helmRelease.Labels = mergeMaps(r.releaseConfig.Labels, helmRelease.Labels) // Merge user labels with prefix helmRelease.Labels = mergeMaps(helmRelease.Labels, addPrefixedMap(app.Labels, LabelPrefix)) + // Add application metadata labels + if helmRelease.Labels == nil { + helmRelease.Labels = make(map[string]string) + } + helmRelease.Labels[ApplicationKindLabel] = r.kindName + helmRelease.Labels[ApplicationGroupLabel] = r.gvk.Group + helmRelease.Labels[ApplicationNameLabel] = app.Name // Note: Annotations from config are not handled as r.releaseConfig.Annotations is undefined - // Convert HelmRelease to unstructured format - unstructuredHR, err := runtime.DefaultUnstructuredConverter.ToUnstructured(helmRelease) - if err != nil { - klog.Errorf("Failed to convert HelmRelease to unstructured: %v", err) - return nil, false, fmt.Errorf("failed to convert HelmRelease to unstructured: %v", err) - } - - // Retrieve metadata from unstructured object - metadata, found, err := unstructured.NestedMap(unstructuredHR, "metadata") - if err != nil || !found { - klog.Errorf("Failed to retrieve metadata from HelmRelease: %v, found: %v", err, found) - return nil, false, fmt.Errorf("failed to retrieve metadata from HelmRelease: %v", err) - } - klog.V(6).Infof("HelmRelease Metadata: %+v", metadata) - klog.V(6).Infof("Updating HelmRelease %s in namespace %s", helmRelease.Name, helmRelease.Namespace) - // Before updating, ensure the HelmRelease meets the inclusion criteria - // This prevents updating HelmReleases that should not be managed as Applications - if !r.shouldIncludeHelmRelease(&unstructured.Unstructured{Object: unstructuredHR}) { - klog.Errorf("HelmRelease %s does not match the required chartName and sourceRef criteria", helmRelease.Name) - // Return a NotFound error for the Application resource - return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) - } - // Update the HelmRelease in Kubernetes - resultHR, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(helmRelease.Namespace).Update(ctx, &unstructured.Unstructured{Object: unstructuredHR}, metav1.UpdateOptions{}) + err = r.c.Update(ctx, helmRelease, &client.UpdateOptions{Raw: &metav1.UpdateOptions{}}) if err != nil { klog.Errorf("Failed to update HelmRelease %s: %v", helmRelease.Name, err) return nil, false, fmt.Errorf("failed to update HelmRelease: %v", err) } - // After updating, ensure the updated HelmRelease still meets the inclusion criteria - if !r.shouldIncludeHelmRelease(resultHR) { - klog.Errorf("Updated HelmRelease %s does not match the required chartName and sourceRef criteria", resultHR.GetName()) - // Return a NotFound error for the Application resource - return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) - } - // Convert the updated HelmRelease back to Application - convertedApp, err := r.ConvertHelmReleaseToApplication(resultHR) + convertedApp, err := r.ConvertHelmReleaseToApplication(ctx, helmRelease) if err != nil { - klog.Errorf("Conversion error from HelmRelease to Application for resource %s: %v", resultHR.GetName(), err) + klog.Errorf("Conversion error from HelmRelease to Application for resource %s: %v", helmRelease.GetName(), err) return nil, false, fmt.Errorf("conversion error: %v", err) } - klog.V(6).Infof("Successfully updated and converted HelmRelease %s to Application", resultHR.GetName()) + klog.V(6).Infof("Successfully updated and converted HelmRelease %s to Application", helmRelease.GetName()) - // Explicitly set apiVersion and kind for Application - convertedApp.TypeMeta = metav1.TypeMeta{ - APIVersion: "apps.cozystack.io/v1alpha1", - Kind: r.kindName, - } + klog.V(6).Infof("Returning updated Application object: %+v", convertedApp) - // Convert Application to unstructured format - unstructuredApp, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&convertedApp) - if err != nil { - klog.Errorf("Failed to convert Application to unstructured for resource %s: %v", convertedApp.GetName(), err) - return nil, false, fmt.Errorf("failed to convert Application to unstructured: %v", err) - } - - // Explicitly set apiVersion and kind in unstructured object - unstructuredApp["apiVersion"] = "apps.cozystack.io/v1alpha1" - unstructuredApp["kind"] = r.kindName - - klog.V(6).Infof("Returning patched Application object: %+v", unstructuredApp) - - return &unstructured.Unstructured{Object: unstructuredApp}, false, nil + return &convertedApp, false, nil } // Delete removes an Application by deleting the corresponding HelmRelease @@ -524,7 +570,8 @@ func (r *REST) Delete(ctx context.Context, name string, deleteValidation rest.Va helmReleaseName := r.releaseConfig.Prefix + name // Retrieve the HelmRelease before attempting to delete - hr, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(namespace).Get(ctx, helmReleaseName, metav1.GetOptions{}) + helmRelease := &helmv2.HelmRelease{} + err = r.c.Get(ctx, client.ObjectKey{Namespace: namespace, Name: helmReleaseName}, helmRelease, &client.GetOptions{Raw: &metav1.GetOptions{}}) if err != nil { if apierrors.IsNotFound(err) { // If HelmRelease does not exist, return NotFound error for Application @@ -536,9 +583,9 @@ func (r *REST) Delete(ctx context.Context, name string, deleteValidation rest.Va return nil, false, err } - // Validate that the HelmRelease meets the inclusion criteria - if !r.shouldIncludeHelmRelease(hr) { - klog.Errorf("HelmRelease %s does not match the required chartName and sourceRef criteria", helmReleaseName) + // Validate that the HelmRelease has required labels + if !r.hasRequiredApplicationLabelsWithName(helmRelease, name) { + klog.Errorf("HelmRelease %s does not match the required application labels", helmReleaseName) // Return NotFound error for Application resource return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) } @@ -546,7 +593,7 @@ func (r *REST) Delete(ctx context.Context, name string, deleteValidation rest.Va klog.V(6).Infof("Deleting HelmRelease %s in namespace %s", helmReleaseName, namespace) // Delete the HelmRelease corresponding to the Application - err = r.dynamicClient.Resource(helmReleaseGVR).Namespace(namespace).Delete(ctx, helmReleaseName, *options) + err = r.c.Delete(ctx, helmRelease, &client.DeleteOptions{Raw: options}) if err != nil { klog.Errorf("Failed to delete HelmRelease %s: %v", helmReleaseName, err) return nil, false, fmt.Errorf("failed to delete HelmRelease: %v", err) @@ -556,7 +603,7 @@ func (r *REST) Delete(ctx context.Context, name string, deleteValidation rest.Va return nil, true, nil } -// Watch sets up a watch on HelmReleases, filters them based on sourceRef and prefix, and converts events to Applications +// Watch sets up a watch on HelmReleases, filters them based on application labels, and converts events to Applications func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptions) (watch.Interface, error) { namespace, err := r.getNamespace(ctx) if err != nil { @@ -564,7 +611,8 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio return nil, err } - klog.V(6).Infof("Setting up watch for HelmReleases in namespace %s with options: %v", namespace, options) + klog.V(6).Infof("Watch called for %s in namespace %q, resourceVersion=%q", + r.kindName, namespace, options.ResourceVersion) // Get request information, including resource name if specified var resourceName string @@ -573,30 +621,37 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio } // Initialize variables for selector mapping - var helmFieldSelector string - var helmLabelSelector string + var helmLabelSelector labels.Selector - // Process field.selector - if options.FieldSelector != nil { - fs, err := fields.ParseSelector(options.FieldSelector.String()) - if err != nil { - klog.Errorf("Invalid field selector: %v", err) - return nil, fmt.Errorf("invalid field selector: %v", err) - } + // Parse field selector for manual filtering + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + fieldFilter, err := fieldfilter.ParseFieldSelector(options.FieldSelector) + if err != nil { + klog.Errorf("Error parsing field selector: %v", err) + return nil, err + } - // Check if selector is for metadata.name - if name, exists := fs.RequiresExactMatch("metadata.name"); exists { - // Convert Application name to HelmRelease name - mappedName := r.releaseConfig.Prefix + name - // Create new field.selector for HelmRelease - helmFieldSelector = fields.OneTermEqualSelector("metadata.name", mappedName).String() - } else { - // If field.selector contains other fields, map them directly - helmFieldSelector = fs.String() - } + // Convert Application name to HelmRelease name for manual filtering + var filterByName string + if fieldFilter.Name != "" { + filterByName = r.releaseConfig.Prefix + fieldFilter.Name } // Process label.selector + // Always add application metadata label requirements + appKindReq, err := labels.NewRequirement(ApplicationKindLabel, selection.Equals, []string{r.kindName}) + if err != nil { + klog.Errorf("Error creating application kind label requirement: %v", err) + return nil, fmt.Errorf("error creating application kind label requirement: %v", err) + } + appGroupReq, err := labels.NewRequirement(ApplicationGroupLabel, selection.Equals, []string{r.gvk.Group}) + if err != nil { + klog.Errorf("Error creating application group label requirement: %v", err) + return nil, fmt.Errorf("error creating application group label requirement: %v", err) + } + labelRequirements := []labels.Requirement{*appKindReq, *appGroupReq} + if options.LabelSelector != nil { ls := options.LabelSelector.String() parsedLabels, err := labels.Parse(ls) @@ -616,24 +671,18 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio } prefixedReqs = append(prefixedReqs, *prefixedReq) } - helmLabelSelector = labels.NewSelector().Add(prefixedReqs...).String() + labelRequirements = append(labelRequirements, prefixedReqs...) } } + helmLabelSelector = labels.NewSelector().Add(labelRequirements...) - // Set ListOptions for HelmRelease with selector mapping - metaOptions := metav1.ListOptions{ - Watch: true, - ResourceVersion: options.ResourceVersion, - FieldSelector: helmFieldSelector, - LabelSelector: helmLabelSelector, - } - - // Start watch on HelmRelease with mapped selectors - helmWatcher, err := r.dynamicClient.Resource(helmReleaseGVR).Namespace(namespace).Watch(ctx, metaOptions) - if err != nil { - klog.Errorf("Error setting up watch for HelmReleases: %v", err) - return nil, err - } + // Handle SendInitialEvents for WatchList feature (Kubernetes 1.27+) + // When sendInitialEvents=true, the client expects: + // 1. All existing resources as ADDED events + // 2. A Bookmark event with "k8s.io/initial-events-end": "true" annotation + // controller-runtime cache already sends ADDED events for all cached objects, + // so we just need to send the bookmark after those initial events + sendInitialEvents := options.SendInitialEvents != nil && *options.SendInitialEvents // Create a custom watcher to transform events customW := &customWatcher{ @@ -641,37 +690,198 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio stopChan: make(chan struct{}), } + // Start watch on HelmRelease with label selector only + // Field selectors are not supported by controller-runtime cache + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + hrList := &helmv2.HelmReleaseList{} + helmWatcher, err := r.w.Watch(ctx, hrList, &client.ListOptions{ + Namespace: namespace, + LabelSelector: helmLabelSelector, + }) + if err != nil { + klog.Errorf("Error setting up watch for HelmReleases: %v", err) + return nil, err + } + customW.underlying = helmWatcher + + // Start watch on WorkloadMonitor to detect pod readiness changes. + // For Tenant applications the WorkloadMonitor lives in a computed child + // namespace (see computeTenantNamespace), not in the HelmRelease namespace, + // so scoping the watch to `namespace` would miss all events. Use a + // cluster-wide watch in that case — label selectors still restrict the + // stream to the relevant kind/group. + wmLabelSelector := labels.NewSelector().Add(*appKindReq, *appGroupReq) + wmList := &cozyv1alpha1.WorkloadMonitorList{} + wmListOpts := &client.ListOptions{LabelSelector: wmLabelSelector} + if r.kindName != "Tenant" { + wmListOpts.Namespace = namespace + } + wmWatcher, err := r.w.Watch(ctx, wmList, wmListOpts) + if err != nil { + klog.Warningf("Failed to set up WorkloadMonitor watch, workload status changes won't trigger events: %v", err) + // Non-fatal: proceed without WorkloadMonitor watch + wmWatcher = nil + } + go func() { + // Capture wmWatcher for cleanup; the variable may be set to nil + // inside the loop when the channel closes, so defer must use this copy. + wmWatcherForCleanup := wmWatcher defer close(customW.resultChan) + defer customW.underlying.Stop() + if wmWatcherForCleanup != nil { + defer wmWatcherForCleanup.Stop() + } + + // Track whether we've sent the initial-events-end bookmark + initialEventsEndSent := !sendInitialEvents // If not sendInitialEvents, consider it already sent + var lastResourceVersion string + + // Buffer of WorkloadMonitor events that arrived before the initial + // snapshot finished. The watch-list contract requires the stream to + // deliver all ADDED events followed by the initial-events-end bookmark + // before any live updates, so we hold WM-triggered Modified events and + // replay them once the bookmark has been emitted. Without this, a + // workload whose status flips during the snapshot window (after the + // Application ADDED but before the bookmark) and then stops changing + // would leave the client with a stale WorkloadsReady forever. + var pendingWMEvents []watch.Event + + // Get the starting resourceVersion from options + // If client provides resourceVersion (e.g., from a previous List), we should skip + // objects with resourceVersion <= startingRV (client already has them) + var startingRV uint64 + if options.ResourceVersion != "" { + if rv, err := strconv.ParseUint(options.ResourceVersion, 10, 64); err == nil { + startingRV = rv + } + } + + drainPendingWMEvents := func() { + for _, ev := range pendingWMEvents { + select { + case customW.resultChan <- ev: + case <-customW.stopChan: + return + case <-ctx.Done(): + return + } + } + pendingWMEvents = nil + } + + // Helper function to send initial-events-end bookmark + sendInitialEventsEndBookmark := func() { + if initialEventsEndSent { + return + } + initialEventsEndSent = true + + bookmarkApp := &appsv1alpha1.Application{} + bookmarkApp.SetResourceVersion(lastResourceVersion) + bookmarkApp.TypeMeta = metav1.TypeMeta{ + APIVersion: appsv1alpha1.SchemeGroupVersion.String(), + Kind: r.kindName, + } + bookmarkApp.SetAnnotations(map[string]string{ + "k8s.io/initial-events-end": "true", + }) + bookmarkEvent := watch.Event{ + Type: watch.Bookmark, + Object: bookmarkApp, + } + klog.V(6).Infof("Sending initial-events-end bookmark with RV=%s", lastResourceVersion) + select { + case customW.resultChan <- bookmarkEvent: + case <-customW.stopChan: + return + case <-ctx.Done(): + return + } + drainPendingWMEvents() + } + + // Process watch events for { select { - case event, ok := <-helmWatcher.ResultChan(): + case event, ok := <-customW.underlying.ResultChan(): if !ok { - // The watcher has been closed, attempt to re-establish the watch - klog.Warning("HelmRelease watcher closed, attempting to re-establish") - // Implement retry logic or exit based on your requirements + // The watcher has been closed + klog.Warning("HelmRelease watcher closed") + // Send initial-events-end bookmark before closing if not yet sent + sendInitialEventsEndBookmark() return } + // Handle bookmark events - these are critical for informer sync + if event.Type == watch.Bookmark { + if hr, ok := event.Object.(*helmv2.HelmRelease); ok { + lastResourceVersion = hr.GetResourceVersion() + + // If sendInitialEvents and we haven't sent initial-events-end yet, + // add the annotation to this bookmark + bookmarkApp := &appsv1alpha1.Application{} + bookmarkApp.SetResourceVersion(lastResourceVersion) + bookmarkApp.TypeMeta = metav1.TypeMeta{ + APIVersion: appsv1alpha1.SchemeGroupVersion.String(), + Kind: r.kindName, + } + justFlipped := false + if !initialEventsEndSent { + initialEventsEndSent = true + justFlipped = true + bookmarkApp.SetAnnotations(map[string]string{ + "k8s.io/initial-events-end": "true", + }) + klog.V(6).Infof("Sending initial-events-end bookmark with RV=%s", lastResourceVersion) + } + bookmarkEvent := watch.Event{ + Type: watch.Bookmark, + Object: bookmarkApp, + } + select { + case customW.resultChan <- bookmarkEvent: + case <-customW.stopChan: + return + case <-ctx.Done(): + return + } + if justFlipped { + drainPendingWMEvents() + } + } + continue + } + // Check if the object is a *v1.Status if status, ok := event.Object.(*metav1.Status); ok { klog.V(4).Infof("Received Status object in HelmRelease watch: %v", status.Message) continue // Skip processing this event } - // Proceed with processing Unstructured objects - matches, err := r.isRelevantHelmRelease(&event) - if err != nil { - klog.V(4).Infof("Non-critical error filtering HelmRelease event: %v", err) + // Proceed with processing HelmRelease objects + hr, ok := event.Object.(*helmv2.HelmRelease) + if !ok { + klog.V(4).Infof("Expected HelmRelease object, got %T", event.Object) continue } - if !matches { + // Update lastResourceVersion for bookmark + lastResourceVersion = hr.GetResourceVersion() + + // Apply manual field selector filtering (metadata.name and metadata.namespace) + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + if filterByName != "" && hr.Name != filterByName { + continue + } + if !fieldFilter.MatchesNamespace(hr.Namespace) { continue } + // Note: All HelmReleases already match the required labels due to server-side label selector filtering // Convert HelmRelease to Application - app, err := r.ConvertHelmReleaseToApplication(event.Object.(*unstructured.Unstructured)) + app, err := r.ConvertHelmReleaseToApplication(ctx, hr) if err != nil { klog.Errorf("Error converting HelmRelease to Application: %v", err) continue @@ -694,17 +904,27 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio } } - // Convert Application to unstructured - unstructuredApp, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&app) - if err != nil { - klog.Errorf("Failed to convert Application to unstructured: %v", err) - continue + // If this is not an ADDED event and we haven't sent initial-events-end, send it now + if event.Type != watch.Added && !initialEventsEndSent { + sendInitialEventsEndBookmark() } + // Skip ADDED events based on resourceVersion comparison + if event.Type == watch.Added && startingRV > 0 { + objRV, parseErr := strconv.ParseUint(app.ResourceVersion, 10, 64) + // Skip objects client already has (objRV <= startingRV) + if parseErr == nil && objRV <= startingRV { + klog.V(6).Infof("Skipping ADDED event for %s/%s (objRV=%d <= startingRV=%d)", + app.Namespace, app.Name, objRV, startingRV) + continue + } + } + // When startingRV == 0, always send ADDED events (client wants full state) + // Create watch event with Application object appEvent := watch.Event{ Type: event.Type, - Object: &unstructured.Unstructured{Object: unstructuredApp}, + Object: &app, } // Send event to custom watcher @@ -716,6 +936,104 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio return } + case wmEvent, ok := <-wmResultChan(wmWatcher): + if !ok { + klog.V(4).Info("WorkloadMonitor watcher closed") + wmWatcher = nil + continue + } + if wmEvent.Type == watch.Bookmark || wmEvent.Type == watch.Error { + if wmEvent.Type == watch.Error { + klog.V(4).Infof("WorkloadMonitor watch error event: %v", wmEvent.Object) + } + continue + } + wm, ok := wmEvent.Object.(*cozyv1alpha1.WorkloadMonitor) + if !ok { + continue + } + // All WM event types (Added/Modified/Deleted) produce a Modified + // Application event because the Application itself is what changed + // from the client's perspective. + wmAppName, hasLabel := wm.Labels[ApplicationNameLabel] + if !hasLabel { + continue + } + // Filter: skip WorkloadMonitor events for applications not matching + // the watch scope (single-resource or field-selector filtered watches) + hrName := r.releaseConfig.Prefix + wmAppName + if filterByName != "" && hrName != filterByName { + continue + } + if resourceName != "" && wmAppName != resourceName { + continue + } + + // Locate the owning HelmRelease. For most application kinds the + // WorkloadMonitor and its HelmRelease live in the same namespace, + // but Tenant workloads live in a child namespace (see + // computeTenantNamespace) while the HelmRelease remains in the + // parent/requested namespace — so the WM-to-HR namespace mapping + // differs. + hrNS := wm.Namespace + if r.kindName == "Tenant" { + hrNS = namespace + // Filter out WM events whose child namespace does not + // correspond to the Tenant in our watched namespace, since + // the cluster-wide WM watch delivers events for all tenants. + if r.computeTenantNamespace(namespace, wmAppName) != wm.Namespace { + continue + } + if !fieldFilter.MatchesNamespace(hrNS) { + continue + } + } else if !fieldFilter.MatchesNamespace(hrNS) { + continue + } + hr := &helmv2.HelmRelease{} + if err := r.c.Get(ctx, client.ObjectKey{Namespace: hrNS, Name: hrName}, hr); err != nil { + klog.V(4).Infof("Cannot find HelmRelease %s/%s for WorkloadMonitor event: %v", hrNS, hrName, err) + continue + } + // Pass the fresh WorkloadMonitor so conversion uses the latest + // operational status even if the cache (r.c) has not yet + // observed this watch event. + app, err := r.ConvertHelmReleaseToApplicationWithMonitor(ctx, hr, wm) + if err != nil { + klog.V(4).Infof("Error converting HelmRelease for WorkloadMonitor event: %v", err) + continue + } + // Apply label selector filtering (same as HelmRelease event path) + if options.LabelSelector != nil { + sel, err := labels.Parse(options.LabelSelector.String()) + if err != nil { + klog.Errorf("Invalid label selector: %v", err) + continue + } + if !sel.Matches(labels.Set(app.Labels)) { + continue + } + } + // Use the WorkloadMonitor's ResourceVersion for the emitted event + // so clients see a monotonically increasing RV and don't skip this update. + app.SetResourceVersion(wm.GetResourceVersion()) + outEvent := watch.Event{Type: watch.Modified, Object: &app} + // Buffer WM-triggered events that arrive before the + // initial-events-end bookmark. They will be replayed in order + // immediately after the bookmark is emitted. + if !initialEventsEndSent { + pendingWMEvents = append(pendingWMEvents, outEvent) + continue + } + lastResourceVersion = wm.GetResourceVersion() + select { + case customW.resultChan <- outEvent: + case <-customW.stopChan: + return + case <-ctx.Done(): + return + } + case <-customW.stopChan: return case <-ctx.Done(): @@ -728,12 +1046,13 @@ func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptio return customW, nil } -// Helper function to get HelmRelease name from object -func helmReleaseName(obj runtime.Object) string { - if u, ok := obj.(*unstructured.Unstructured); ok { - return u.GetName() +// wmResultChan returns the result channel of a WorkloadMonitor watcher, or a nil +// channel (which blocks forever in select) if the watcher is nil. +func wmResultChan(w watch.Interface) <-chan watch.Event { + if w == nil { + return nil } - return "" + return w.ResultChan() } // customWatcher wraps the original watcher and filters/converts events @@ -741,12 +1060,16 @@ type customWatcher struct { resultChan chan watch.Event stopChan chan struct{} stopOnce sync.Once + underlying watch.Interface } // Stop terminates the watch func (cw *customWatcher) Stop() { cw.stopOnce.Do(func() { close(cw.stopChan) + if cw.underlying != nil { + cw.underlying.Stop() + } }) } @@ -755,100 +1078,36 @@ func (cw *customWatcher) ResultChan() <-chan watch.Event { return cw.resultChan } -// isRelevantHelmRelease checks if the HelmRelease meets the sourceRef and prefix criteria -func (r *REST) isRelevantHelmRelease(event *watch.Event) (bool, error) { - if event.Object == nil { - return false, nil - } - - // Check if the object is a *v1.Status - if status, ok := event.Object.(*metav1.Status); ok { - // Log at a less severe level or handle specific status errors if needed - klog.V(4).Infof("Received Status object in HelmRelease watch: %v", status.Message) - return false, nil // Not relevant for processing as a HelmRelease - } - - // Proceed if it's an Unstructured object - hr, ok := event.Object.(*unstructured.Unstructured) - if !ok { - return false, fmt.Errorf("expected Unstructured object, got %T", event.Object) - } - - return r.shouldIncludeHelmRelease(hr), nil -} - -// shouldIncludeHelmRelease determines if a HelmRelease should be included based on filtering criteria -func (r *REST) shouldIncludeHelmRelease(hr *unstructured.Unstructured) bool { - // Filter by Chart Name - chartName, found, err := unstructured.NestedString(hr.Object, "spec", "chart", "spec", "chart") - if err != nil || !found { - klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.chart field: %v", hr.GetName(), err) - return false - } - if chartName != r.releaseConfig.Chart.Name { - klog.V(6).Infof("HelmRelease %s chart name %s does not match expected %s", hr.GetName(), chartName, r.releaseConfig.Chart.Name) - return false - } - - // Filter by SourceRefConfig and Prefix - return r.matchesSourceRefAndPrefix(hr) -} - -// matchesSourceRefAndPrefix checks both SourceRefConfig and Prefix criteria -func (r *REST) matchesSourceRefAndPrefix(hr *unstructured.Unstructured) bool { - // Extract SourceRef fields - sourceRefKind, found, err := unstructured.NestedString(hr.Object, "spec", "chart", "spec", "sourceRef", "kind") - if err != nil || !found { - klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.sourceRef.kind field: %v", hr.GetName(), err) - return false - } - sourceRefName, found, err := unstructured.NestedString(hr.Object, "spec", "chart", "spec", "sourceRef", "name") - if err != nil || !found { - klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.sourceRef.name field: %v", hr.GetName(), err) - return false - } - sourceRefNamespace, found, err := unstructured.NestedString(hr.Object, "spec", "chart", "spec", "sourceRef", "namespace") - if err != nil || !found { - klog.V(6).Infof("HelmRelease %s missing spec.chart.spec.sourceRef.namespace field: %v", hr.GetName(), err) - return false - } - - // Check if SourceRef matches the configuration - if sourceRefKind != r.releaseConfig.Chart.SourceRef.Kind || - sourceRefName != r.releaseConfig.Chart.SourceRef.Name || - sourceRefNamespace != r.releaseConfig.Chart.SourceRef.Namespace { - klog.V(6).Infof("HelmRelease %s sourceRef does not match expected values", hr.GetName()) - return false - } - - // Additional filtering by Prefix - name := hr.GetName() - if !strings.HasPrefix(name, r.releaseConfig.Prefix) { - klog.V(6).Infof("HelmRelease %s does not have the expected prefix %s", name, r.releaseConfig.Prefix) - return false - } - - return true -} - // getNamespace extracts the namespace from the context func (r *REST) getNamespace(ctx context.Context) (string, error) { namespace, ok := request.NamespaceFrom(ctx) if !ok { err := fmt.Errorf("namespace not found in context") - klog.Errorf(err.Error()) + klog.Error(err) return "", err } return namespace, nil } -// buildLabelSelector constructs a label selector string from a map of labels -func buildLabelSelector(labels map[string]string) string { - var selectors []string - for k, v := range labels { - selectors = append(selectors, fmt.Sprintf("%s=%s", k, v)) +// hasRequiredApplicationLabels checks if a HelmRelease has the required application labels +// matching the REST instance's kind and group +func (r *REST) hasRequiredApplicationLabels(hr *helmv2.HelmRelease) bool { + if hr.Labels == nil { + return false } - return strings.Join(selectors, ",") + return hr.Labels[ApplicationKindLabel] == r.kindName && + hr.Labels[ApplicationGroupLabel] == r.gvk.Group +} + +// hasRequiredApplicationLabelsWithName checks if a HelmRelease has the required application labels +// matching the REST instance's kind, group, and the specified application name +func (r *REST) hasRequiredApplicationLabelsWithName(hr *helmv2.HelmRelease, appName string) bool { + if hr.Labels == nil { + return false + } + return hr.Labels[ApplicationKindLabel] == r.kindName && + hr.Labels[ApplicationGroupLabel] == r.gvk.Group && + hr.Labels[ApplicationNameLabel] == appName } // mergeMaps combines two maps of labels or annotations @@ -899,25 +1158,30 @@ func filterPrefixedMap(original map[string]string, prefix string) map[string]str return processed } -// ConvertHelmReleaseToApplication converts a HelmRelease to an Application -func (r *REST) ConvertHelmReleaseToApplication(hr *unstructured.Unstructured) (appsv1alpha1.Application, error) { +// ConvertHelmReleaseToApplication converts a HelmRelease to an Application. +func (r *REST) ConvertHelmReleaseToApplication(ctx context.Context, hr *helmv2.HelmRelease) (appsv1alpha1.Application, error) { + return r.ConvertHelmReleaseToApplicationWithMonitor(ctx, hr, nil) +} + +// ConvertHelmReleaseToApplicationWithMonitor converts a HelmRelease to an +// Application, optionally overriding the cached copy of a WorkloadMonitor with +// a fresher version received from the watch client. This prevents the emitted +// Application object from carrying stale WorkloadsReady data when r.c (cache) +// lags behind r.w (watch). +func (r *REST) ConvertHelmReleaseToApplicationWithMonitor(ctx context.Context, hr *helmv2.HelmRelease, freshMonitor *cozyv1alpha1.WorkloadMonitor) (appsv1alpha1.Application, error) { klog.V(6).Infof("Converting HelmRelease to Application for resource %s", hr.GetName()) - var helmRelease helmv2.HelmRelease - // Convert unstructured to HelmRelease struct - err := runtime.DefaultUnstructuredConverter.FromUnstructured(hr.Object, &helmRelease) - if err != nil { - klog.Errorf("Error converting from unstructured to HelmRelease: %v", err) - return appsv1alpha1.Application{}, err - } - // Convert HelmRelease struct to Application struct - app, err := r.convertHelmReleaseToApplication(&helmRelease) + app, err := r.convertHelmReleaseToApplication(ctx, hr, freshMonitor) if err != nil { klog.Errorf("Error converting from HelmRelease to Application: %v", err) return appsv1alpha1.Application{}, err } + if err := r.applySpecDefaults(&app); err != nil { + return app, fmt.Errorf("defaulting error: %w", err) + } + klog.V(6).Infof("Successfully converted HelmRelease %s to Application", hr.GetName()) return app, nil } @@ -927,14 +1191,113 @@ func (r *REST) ConvertApplicationToHelmRelease(app *appsv1alpha1.Application) (* return r.convertApplicationToHelmRelease(app) } -// convertHelmReleaseToApplication implements the actual conversion logic -func (r *REST) convertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1alpha1.Application, error) { +// filterInternalKeys removes keys starting with "_" from the JSON values +func filterInternalKeys(values *apiextv1.JSON) *apiextv1.JSON { + if values == nil || len(values.Raw) == 0 { + return values + } + var data map[string]any + if err := json.Unmarshal(values.Raw, &data); err != nil { + return values + } + for key := range data { + if strings.HasPrefix(key, "_") { + delete(data, key) + } + } + filtered, err := json.Marshal(data) + if err != nil { + return values + } + return &apiextv1.JSON{Raw: filtered} +} + +// validateNoInternalKeys checks that values don't contain keys starting with "_" +func validateNoInternalKeys(values *apiextv1.JSON) error { + if values == nil || len(values.Raw) == 0 { + return nil + } + var data map[string]any + if err := json.Unmarshal(values.Raw, &data); err != nil { + return err + } + for key := range data { + if strings.HasPrefix(key, "_") { + return fmt.Errorf("values key %q is reserved (keys starting with '_' are not allowed)", key) + } + } + return nil +} + +// maxHelmReleaseName is the Helm release name limit. Helm reserves room for +// chart-generated resource suffixes within the 63-char DNS-1035 label limit. +const maxHelmReleaseName = 53 + +// maxNamespaceName is the DNS-1123 label limit for Kubernetes namespace names. +// The tenant Helm chart creates a Namespace whose name is the computed +// workload namespace (parent namespace + "-" + tenant name), so the total +// must fit inside a single 63-char DNS-1123 label. +const maxNamespaceName = 63 + +// validateNameFormat checks an Application name against DNS-1035 and any +// kind-specific format rules (e.g. Tenant names must be alphanumeric — see +// validation.ValidateApplicationName for the reasoning). +func (r *REST) validateNameFormat(name string) field.ErrorList { + return validation.ValidateApplicationName(name, r.kindName, field.NewPath("metadata").Child("name")) +} + +// validateNameLength checks that the application name won't exceed Kubernetes limits. +// prefix + name must fit within the Helm release name limit (53 chars). +func (r *REST) validateNameLength(name string) field.ErrorList { + fldPath := field.NewPath("metadata").Child("name") + allErrs := field.ErrorList{} + + maxLen := maxHelmReleaseName - len(r.releaseConfig.Prefix) + + if maxLen <= 0 { + allErrs = append(allErrs, field.Invalid(fldPath, name, + fmt.Sprintf("configuration error: no valid name length possible (release prefix %q)", r.releaseConfig.Prefix))) + return allErrs + } + + if len(name) > maxLen { + allErrs = append(allErrs, field.Invalid(fldPath, name, + fmt.Sprintf("must be no more than %d characters (release prefix %q)", maxLen, r.releaseConfig.Prefix))) + } + return allErrs +} + +// validateTenantNamespaceLength checks that the computed workload namespace +// for a Tenant application fits within the DNS-1123 label limit. The namespace +// is formed by dash-joining the parent namespace with the tenant name, so +// deep nesting can exceed the limit even when each individual name passes the +// per-name Helm release length check. +func (r *REST) validateTenantNamespaceLength(currentNamespace, tenantName string) field.ErrorList { + fldPath := field.NewPath("metadata").Child("name") + allErrs := field.ErrorList{} + + computed := r.computeTenantNamespace(currentNamespace, tenantName) + if len(computed) > maxNamespaceName { + allErrs = append(allErrs, field.Invalid(fldPath, tenantName, + fmt.Sprintf("computed tenant namespace %q would be %d characters, which exceeds the %d-character Kubernetes namespace limit; shorten the tenant name or reduce ancestor nesting depth", + computed, len(computed), maxNamespaceName))) + } + return allErrs +} + +// convertHelmReleaseToApplication implements the actual conversion logic. +// The optional freshMonitor is used to override the cache copy of a +// WorkloadMonitor when a newer version was delivered via the watch client — +// see ConvertHelmReleaseToApplicationWithMonitor for the rationale. +func (r *REST) convertHelmReleaseToApplication(ctx context.Context, hr *helmv2.HelmRelease, freshMonitor *cozyv1alpha1.WorkloadMonitor) (appsv1alpha1.Application, error) { + // Filter out internal keys (starting with "_") from spec + filteredSpec := filterInternalKeys(hr.Spec.Values) + app := appsv1alpha1.Application{ TypeMeta: metav1.TypeMeta{ APIVersion: "apps.cozystack.io/v1alpha1", Kind: r.kindName, }, - AppVersion: hr.Spec.Chart.Spec.Version, ObjectMeta: metav1.ObjectMeta{ Name: strings.TrimPrefix(hr.Name, r.releaseConfig.Prefix), Namespace: hr.Namespace, @@ -945,7 +1308,7 @@ func (r *REST) convertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1al Labels: filterPrefixedMap(hr.Labels, LabelPrefix), Annotations: filterPrefixedMap(hr.Annotations, AnnotationPrefix), }, - Spec: hr.Spec.Values, + Spec: filteredSpec, Status: appsv1alpha1.ApplicationStatus{ Version: hr.Status.LastAttemptedRevision, }, @@ -963,10 +1326,166 @@ func (r *REST) convertHelmReleaseToApplication(hr *helmv2.HelmRelease) (appsv1al }) } } + // Enrich conditions with WorkloadMonitor operational status. + // Tenant workloads live in a child namespace (computed from the Tenant name), + // not in the same namespace as the owning HelmRelease — look there instead. + workloadsNS := hr.Namespace + if r.kindName == "Tenant" { + workloadsNS = r.computeTenantNamespace(hr.Namespace, app.Name) + } + ws, wsErr := r.getWorkloadsOperational(ctx, workloadsNS, app.Name, freshMonitor) + // Derive a stable LastTransitionTime: use the owning HelmRelease's own + // condition update time (or CreationTimestamp as a floor) so that repeated + // conversions of the same underlying state produce identical timestamps. + wrTransition := hr.CreationTimestamp + for _, c := range hr.GetConditions() { + if c.LastTransitionTime.After(wrTransition.Time) { + wrTransition = c.LastTransitionTime + } + } + if ws.transitionTime.After(wrTransition.Time) { + wrTransition = ws.transitionTime + } + if wrTransition.IsZero() { + // Fallback for objects that somehow have no timestamps at all + // (e.g. hand-crafted test fixtures). In production HelmReleases + // always carry a CreationTimestamp, so the stable branch above + // is used. + wrTransition = metav1.Now() + } + if wsErr != nil { + // Fail-open: if we can't query WorkloadMonitors (e.g., informer cache not ready), + // don't override Ready. Prefer operational availability over safety. + // The WorkloadsReady=Unknown condition still signals the issue to the user. + klog.Warningf("Failed to check workload monitors for %s/%s: %v", workloadsNS, app.Name, wsErr) + conditions = append(conditions, metav1.Condition{ + Type: "WorkloadsReady", + Status: metav1.ConditionUnknown, + LastTransitionTime: wrTransition, + Reason: "Error", + Message: fmt.Sprintf("Failed to check workload status: %v", wsErr), + }) + } else if ws.found { + workloadsCondition := metav1.Condition{ + Type: "WorkloadsReady", + LastTransitionTime: wrTransition, + Reason: "WorkloadMonitorCheck", + } + switch { + case !ws.operational: + // Concrete failure takes priority over unknown/pending state + workloadsCondition.Status = metav1.ConditionFalse + workloadsCondition.Message = "One or more workloads are not operational" + case ws.unknown: + workloadsCondition.Status = metav1.ConditionUnknown + workloadsCondition.Reason = "Pending" + workloadsCondition.Message = "One or more workloads have not been reconciled yet" + default: + workloadsCondition.Status = metav1.ConditionTrue + workloadsCondition.Message = "All workloads are operational" + } + conditions = append(conditions, workloadsCondition) + + // Intentionally do NOT override the Ready condition based on WorkloadsReady. + // Ready continues to reflect HelmRelease state only, which: + // - preserves backward compatibility with existing tooling (kubectl wait, + // GitOps health checks) that expect Ready to match HelmRelease + // - avoids false-negative Ready=False during normal startup windows where + // pods are still coming up but WorkloadMonitor has already reported + // Operational=false due to availableReplicas < MinReplicas + // WorkloadsReady is a separate condition that surfaces workload health + // independently — users and dashboards can observe it for operational visibility. + } + app.SetConditions(conditions) + + // Add namespace field for Tenant applications + if r.kindName == validation.TenantKind { + app.Status.Namespace = r.computeTenantNamespace(hr.Namespace, app.Name) + externalIPsCount, err := r.countTenantExternalIPs(ctx, app.Status.Namespace) + if err != nil { + klog.Warningf("Failed to count external IPs for tenant %s/%s: %v", hr.Namespace, app.Name, err) + } else { + app.Status.ExternalIPsCount = externalIPsCount + } + } + return app, nil } +// workloadsStatus holds the aggregated operational status of WorkloadMonitors. +type workloadsStatus struct { + operational bool + found bool + unknown bool // true when at least one monitor has nil Operational (not yet reconciled) + // transitionTime is the most recent metadata update time across the + // matching monitors. Used as WorkloadsReady.LastTransitionTime so that + // repeated conversions for the same underlying state produce stable + // timestamps (preserving the Kubernetes contract that identical + // resource versions represent identical content). + transitionTime metav1.Time +} + +// getWorkloadsOperational checks WorkloadMonitor resources for an application and returns +// aggregated operational status. If no monitors exist, returns found=false. +// When freshOverride is non-nil, its status replaces the cached copy for the +// corresponding monitor — this keeps the result consistent with watch events +// when the cache (r.c) lags behind the watch client (r.w). +func (r *REST) getWorkloadsOperational(ctx context.Context, namespace, appName string, freshOverride *cozyv1alpha1.WorkloadMonitor) (workloadsStatus, error) { + monitors := &cozyv1alpha1.WorkloadMonitorList{} + if err := r.c.List(ctx, monitors, + client.InNamespace(namespace), + client.MatchingLabels{ + appsv1alpha1.ApplicationKindLabel: r.kindName, + appsv1alpha1.ApplicationGroupLabel: r.gvk.Group, + appsv1alpha1.ApplicationNameLabel: appName, + }, + ); err != nil { + return workloadsStatus{}, err + } + // Ensure the freshOverride is represented in the aggregation even when + // the cache has not yet observed it (brand-new resource) or is behind. + replaced := false + if freshOverride != nil { + for i := range monitors.Items { + if monitors.Items[i].UID == freshOverride.UID || + (monitors.Items[i].Name == freshOverride.Name && monitors.Items[i].Namespace == freshOverride.Namespace) { + monitors.Items[i] = *freshOverride + replaced = true + break + } + } + if !replaced { + monitors.Items = append(monitors.Items, *freshOverride) + } + } + if len(monitors.Items) == 0 { + return workloadsStatus{operational: true, found: false}, nil + } + operational := true + unknown := false + var latest metav1.Time + for _, m := range monitors.Items { + if m.Status.Operational == nil { + unknown = true + } else if !*m.Status.Operational { + operational = false + } + // Pick the most recent monitor mtime as a stable transition time. + if t := latestMonitorTime(&m); t.After(latest.Time) { + latest = t + } + } + return workloadsStatus{operational: operational, found: true, unknown: unknown, transitionTime: latest}, nil +} + +// latestMonitorTime returns the most recent timestamp associated with a +// WorkloadMonitor — currently only the object creation time is guaranteed. +// Status does not carry a transition time, so we fall back to CreationTimestamp. +func latestMonitorTime(m *cozyv1alpha1.WorkloadMonitor) metav1.Time { + return m.CreationTimestamp +} + // convertApplicationToHelmRelease implements the actual conversion logic func (r *REST) convertApplicationToHelmRelease(app *appsv1alpha1.Application) (*helmv2.HelmRelease, error) { helmRelease := &helmv2.HelmRelease{ @@ -979,26 +1498,54 @@ func (r *REST) convertApplicationToHelmRelease(app *appsv1alpha1.Application) (* Namespace: app.Namespace, Labels: addPrefixedMap(app.Labels, LabelPrefix), Annotations: addPrefixedMap(app.Annotations, AnnotationPrefix), - ResourceVersion: app.ObjectMeta.ResourceVersion, - UID: app.ObjectMeta.UID, + ResourceVersion: app.ResourceVersion, + UID: app.UID, }, Spec: helmv2.HelmReleaseSpec{ - Chart: &helmv2.HelmChartTemplate{ - Spec: helmv2.HelmChartTemplateSpec{ - Chart: r.releaseConfig.Chart.Name, - Version: app.AppVersion, - ReconcileStrategy: "Revision", - SourceRef: helmv2.CrossNamespaceObjectReference{ - Kind: r.releaseConfig.Chart.SourceRef.Kind, - Name: r.releaseConfig.Chart.SourceRef.Name, - Namespace: r.releaseConfig.Chart.SourceRef.Namespace, - }, + ChartRef: &helmv2.CrossNamespaceSourceReference{ + Kind: r.releaseConfig.ChartRef.Kind, + Name: r.releaseConfig.ChartRef.Name, + Namespace: r.releaseConfig.ChartRef.Namespace, + }, + Interval: metav1.Duration{Duration: 5 * time.Minute}, + Install: &helmv2.Install{ + Remediation: &helmv2.InstallRemediation{ + Retries: -1, + }, + }, + Upgrade: &helmv2.Upgrade{ + Remediation: &helmv2.UpgradeRemediation{ + Retries: -1, + }, + }, + ValuesFrom: []helmv2.ValuesReference{ + { + Kind: "Secret", + Name: "cozystack-values", }, }, Values: app.Spec, }, } + // Per-Application HelmRelease wait budget. The mechanism is generic: + // an ApplicationDefinition that sets + // release.cozystack.io/helm-install-timeout gets Install.Timeout and + // Upgrade.Timeout populated from ReleaseConfig.HelmInstallTimeout + // (parsed at startup). Applications that leave it unset keep flux + // defaults so their failed installs remediate on the normal cadence. + // Today only kubernetes-rd carries the annotation because the + // Kubernetes Application's parent chart contains CAPI/Kamaji + // resources whose admin-kubeconfig Secret is provisioned + // asynchronously and Kamaji cold-start routinely exceeds flux's + // default wait budget; any future kind with the same shape can opt + // in by setting the same annotation. + if r.releaseConfig.HelmInstallTimeout > 0 { + timeout := metav1.Duration{Duration: r.releaseConfig.HelmInstallTimeout} + helmRelease.Spec.Install.Timeout = &timeout + helmRelease.Spec.Upgrade.Timeout = &timeout + } + return helmRelease, nil } @@ -1011,19 +1558,10 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO switch obj := object.(type) { case *appsv1alpha1.ApplicationList: table = r.buildTableFromApplications(obj.Items) - table.ListMeta.ResourceVersion = obj.ListMeta.ResourceVersion + table.ResourceVersion = obj.ResourceVersion case *appsv1alpha1.Application: table = r.buildTableFromApplication(*obj) - table.ListMeta.ResourceVersion = obj.GetResourceVersion() - case *unstructured.Unstructured: - var app appsv1alpha1.Application - err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &app) - if err != nil { - klog.Errorf("Failed to convert Unstructured to Application: %v", err) - return nil, fmt.Errorf("failed to convert Unstructured to Application: %v", err) - } - table = r.buildTableFromApplication(app) - table.ListMeta.ResourceVersion = obj.GetResourceVersion() + table.ResourceVersion = obj.GetResourceVersion() default: resource := schema.GroupResource{} if info, ok := request.RequestInfoFrom(ctx); ok { @@ -1046,7 +1584,6 @@ func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableO } klog.V(6).Infof("ConvertToTable: returning table with %d rows", len(table.Rows)) - return &table, nil } @@ -1063,10 +1600,11 @@ func (r *REST) buildTableFromApplications(apps []appsv1alpha1.Application) metav } now := time.Now() - for _, app := range apps { + for i := range apps { + app := &apps[i] row := metav1.TableRow{ - Cells: []interface{}{app.GetName(), getReadyStatus(app.Status.Conditions), computeAge(app.GetCreationTimestamp().Time, now), getVersion(app.Status.Version)}, - Object: runtime.RawExtension{Object: &app}, + Cells: []any{app.GetName(), getReadyStatus(app.Status.Conditions), computeAge(app.GetCreationTimestamp().Time, now), getVersion(app.Status.Version)}, + Object: runtime.RawExtension{Object: app}, } table.Rows = append(table.Rows, row) } @@ -1087,20 +1625,29 @@ func (r *REST) buildTableFromApplication(app appsv1alpha1.Application) metav1.Ta } now := time.Now() + a := app row := metav1.TableRow{ - Cells: []interface{}{app.GetName(), getReadyStatus(app.Status.Conditions), computeAge(app.GetCreationTimestamp().Time, now), getVersion(app.Status.Version)}, - Object: runtime.RawExtension{Object: &app}, + Cells: []any{app.GetName(), getReadyStatus(app.Status.Conditions), computeAge(app.GetCreationTimestamp().Time, now), getVersion(app.Status.Version)}, + Object: runtime.RawExtension{Object: &a}, } table.Rows = append(table.Rows, row) return table } -// getVersion returns the application version or a placeholder if unknown +// getVersion extracts and returns only the revision from the version string +// If version is in format "0.1.4+abcdef", returns "abcdef" +// Otherwise returns the original string or "" if empty func getVersion(version string) string { if version == "" { return "" } + // Check if version contains "+" separator + if idx := strings.LastIndex(version, "+"); idx >= 0 && idx < len(version)-1 { + // Return only the part after "+" + return version[idx+1:] + } + // If no "+" found, return original version return version } @@ -1127,6 +1674,54 @@ func getReadyStatus(conditions []metav1.Condition) string { return "Unknown" } +// computeTenantNamespace computes the namespace for a Tenant application based on the specified logic +func (r *REST) computeTenantNamespace(currentNamespace, tenantName string) string { + hrName := r.releaseConfig.Prefix + tenantName + + 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 (r *REST) countTenantExternalIPs(ctx context.Context, namespace string) (int32, error) { + if namespace == "" { + return 0, nil + } + + var services corev1.ServiceList + if err := r.c.List( + ctx, + &services, + client.InNamespace(namespace), + client.MatchingFields{"spec.type": string(corev1.ServiceTypeLoadBalancer)}, + ); err != nil { + return 0, err + } + + var count int32 + for i := range services.Items { + svc := &services.Items[i] + for _, ingress := range svc.Status.LoadBalancer.Ingress { + if ingress.IP != "" { + count++ + break + } + } + } + + return count, nil +} + // Destroy releases resources associated with REST func (r *REST) Destroy() { // No additional actions needed to release resources. @@ -1134,12 +1729,22 @@ func (r *REST) Destroy() { // New creates a new instance of Application func (r *REST) New() runtime.Object { - return &appsv1alpha1.Application{} + obj := &appsv1alpha1.Application{} + obj.TypeMeta = metav1.TypeMeta{ + APIVersion: r.gvk.GroupVersion().String(), + Kind: r.kindName, + } + return obj } // NewList returns an empty list of Application objects func (r *REST) NewList() runtime.Object { - return &appsv1alpha1.ApplicationList{} + obj := &appsv1alpha1.ApplicationList{} + obj.TypeMeta = metav1.TypeMeta{ + APIVersion: r.gvk.GroupVersion().String(), + Kind: r.kindName + "List", + } + return obj } // Kind returns the resource kind used for API discovery diff --git a/pkg/registry/apps/application/rest_conditions_test.go b/pkg/registry/apps/application/rest_conditions_test.go new file mode 100644 index 00000000..185f59b2 --- /dev/null +++ b/pkg/registry/apps/application/rest_conditions_test.go @@ -0,0 +1,331 @@ +package application + +import ( + "context" + "testing" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + helmv2 "github.com/fluxcd/helm-controller/api/v2" + appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + "github.com/cozystack/cozystack/pkg/config" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +func findCondition(conditions []metav1.Condition, condType string) *metav1.Condition { + for i := range conditions { + if conditions[i].Type == condType { + return &conditions[i] + } + } + return nil +} + +func makeHelmRelease(name, namespace string) *helmv2.HelmRelease { + hr := &helmv2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Labels: map[string]string{ + ApplicationKindLabel: "PostgreSQL", + ApplicationGroupLabel: "apps.cozystack.io", + ApplicationNameLabel: "mydb", + }, + }, + } + return hr +} + +func TestConvertConditions_WorkloadsReadyAdded(t *testing.T) { + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-1", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: ptr.To(true), + }, + } + + r := newTestRESTWithSchemes(monitor) + hr := makeHelmRelease("postgresql-mydb", "default") + hr.Status.Conditions = []metav1.Condition{ + {Type: "Ready", Status: metav1.ConditionTrue, Reason: "Succeeded", Message: "Release applied"}, + {Type: "Released", Status: metav1.ConditionTrue, Reason: "Succeeded", Message: "Released"}, + } + + app, err := r.convertHelmReleaseToApplication(context.TODO(), hr, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + wc := findCondition(app.GetConditions(), "WorkloadsReady") + if wc == nil { + t.Fatal("expected WorkloadsReady condition to be present") + } + if wc.Status != metav1.ConditionTrue { + t.Errorf("expected WorkloadsReady=True, got %s", wc.Status) + } + + rc := findCondition(app.GetConditions(), "Ready") + if rc == nil { + t.Fatal("expected Ready condition to be present") + } + if rc.Status != metav1.ConditionTrue { + t.Errorf("expected Ready=True, got %s", rc.Status) + } +} + +func TestConvertConditions_ReadyNotOverriddenWhenWorkloadsNotReady(t *testing.T) { + // Ready must reflect HelmRelease state only. WorkloadsReady is a separate + // signal that users/dashboards can observe independently. + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-1", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: ptr.To(false), + }, + } + + r := newTestRESTWithSchemes(monitor) + hr := makeHelmRelease("postgresql-mydb", "default") + hr.Status.Conditions = []metav1.Condition{ + {Type: "Ready", Status: metav1.ConditionTrue, Reason: "Succeeded", Message: "Release applied"}, + } + + app, err := r.convertHelmReleaseToApplication(context.TODO(), hr, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + wc := findCondition(app.GetConditions(), "WorkloadsReady") + if wc == nil { + t.Fatal("expected WorkloadsReady condition to be present") + } + if wc.Status != metav1.ConditionFalse { + t.Errorf("expected WorkloadsReady=False, got %s", wc.Status) + } + + rc := findCondition(app.GetConditions(), "Ready") + if rc == nil { + t.Fatal("expected Ready condition to be present") + } + if rc.Status != metav1.ConditionTrue { + t.Errorf("expected Ready=True (reflects HelmRelease only), got %s", rc.Status) + } + if rc.Reason != "Succeeded" { + t.Errorf("expected Ready.Reason=Succeeded (unchanged), got %s", rc.Reason) + } +} + +func TestConvertConditions_NoOverrideWhenNoMonitors(t *testing.T) { + r := newTestRESTWithSchemes() + hr := makeHelmRelease("postgresql-mydb", "default") + hr.Status.Conditions = []metav1.Condition{ + {Type: "Ready", Status: metav1.ConditionTrue, Reason: "Succeeded", Message: "Release applied"}, + } + + app, err := r.convertHelmReleaseToApplication(context.TODO(), hr, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + wc := findCondition(app.GetConditions(), "WorkloadsReady") + if wc != nil { + t.Error("expected no WorkloadsReady condition when no monitors exist") + } + + rc := findCondition(app.GetConditions(), "Ready") + if rc == nil { + t.Fatal("expected Ready condition to be present") + } + if rc.Status != metav1.ConditionTrue { + t.Errorf("expected Ready=True unchanged, got %s", rc.Status) + } +} + +func TestConvertConditions_ReadyStaysTrue_WhenAllOperational(t *testing.T) { + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-1", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: ptr.To(true), + }, + } + + r := newTestRESTWithSchemes(monitor) + hr := makeHelmRelease("postgresql-mydb", "default") + hr.Status.Conditions = []metav1.Condition{ + {Type: "Ready", Status: metav1.ConditionTrue, Reason: "Succeeded", Message: "Release applied"}, + {Type: "Released", Status: metav1.ConditionTrue, Reason: "Succeeded", Message: "Released"}, + } + + app, err := r.convertHelmReleaseToApplication(context.TODO(), hr, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + rc := findCondition(app.GetConditions(), "Ready") + if rc == nil { + t.Fatal("expected Ready condition") + } + if rc.Status != metav1.ConditionTrue { + t.Errorf("expected Ready=True when all workloads operational, got %s", rc.Status) + } + if rc.Reason != "Succeeded" { + t.Errorf("expected Ready.Reason=Succeeded (unchanged), got %s", rc.Reason) + } +} + +func TestConvertConditions_WorkloadsReadyTimestampIsNonZero(t *testing.T) { + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-1", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: ptr.To(true), + }, + } + + r := newTestRESTWithSchemes(monitor) + hr := makeHelmRelease("postgresql-mydb", "default") + // No Ready condition — HR still being reconciled + hr.Status.Conditions = []metav1.Condition{} + + app, err := r.convertHelmReleaseToApplication(context.TODO(), hr, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + wc := findCondition(app.GetConditions(), "WorkloadsReady") + if wc == nil { + t.Fatal("expected WorkloadsReady condition") + } + if wc.LastTransitionTime.IsZero() { + t.Error("expected non-zero LastTransitionTime") + } +} + +func TestConvertConditions_WorkloadsReadyUnknownWhenNilOperational(t *testing.T) { + monitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-1", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: nil, // Not yet reconciled + }, + } + + r := newTestRESTWithSchemes(monitor) + hr := makeHelmRelease("postgresql-mydb", "default") + hr.Status.Conditions = []metav1.Condition{ + {Type: "Ready", Status: metav1.ConditionTrue, Reason: "Succeeded", Message: "ok"}, + } + + app, err := r.convertHelmReleaseToApplication(context.TODO(), hr, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + wc := findCondition(app.GetConditions(), "WorkloadsReady") + if wc == nil { + t.Fatal("expected WorkloadsReady condition") + } + if wc.Status != metav1.ConditionUnknown { + t.Errorf("expected WorkloadsReady=Unknown for nil Operational, got %s", wc.Status) + } + + // Ready should NOT be overridden for unknown — prefer availability during startup + rc := findCondition(app.GetConditions(), "Ready") + if rc == nil { + t.Fatal("expected Ready condition") + } + if rc.Status != metav1.ConditionTrue { + t.Errorf("expected Ready=True when workloads unknown (pending), got %s", rc.Status) + } +} + +func TestConvertConditions_WorkloadsReadyUnknownOnError(t *testing.T) { + // Create a client with only HelmRelease scheme — WorkloadMonitor List will fail + scheme := runtime.NewScheme() + _ = helmv2.AddToScheme(scheme) + // Deliberately NOT registering cozyv1alpha1 so that List returns an error + + c := fake.NewClientBuilder().WithScheme(scheme).Build() + r := NewREST(c, nil, &config.Resource{ + Application: config.ApplicationConfig{ + Kind: "PostgreSQL", + Plural: "postgresqls", + Singular: "postgresql", + }, + Release: config.ReleaseConfig{ + Prefix: "postgresql-", + }, + }) + + hr := makeHelmRelease("postgresql-mydb", "default") + hr.CreationTimestamp = metav1.Now() + hr.Status.Conditions = []metav1.Condition{ + {Type: "Ready", Status: metav1.ConditionTrue, Reason: "Succeeded", Message: "ok"}, + } + + app, err := r.convertHelmReleaseToApplication(context.TODO(), hr, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + wc := findCondition(app.GetConditions(), "WorkloadsReady") + if wc == nil { + t.Fatal("expected WorkloadsReady condition with Unknown status on error") + } + if wc.Status != metav1.ConditionUnknown { + t.Errorf("expected WorkloadsReady=Unknown, got %s", wc.Status) + } + if wc.Reason != "Error" { + t.Errorf("expected reason=Error, got %s", wc.Reason) + } + + // Ready should NOT be overridden on error (fail-open: prefer availability) + rc := findCondition(app.GetConditions(), "Ready") + if rc == nil { + t.Fatal("expected Ready condition") + } + if rc.Status != metav1.ConditionTrue { + t.Errorf("expected Ready=True (fail-open on error), got %s", rc.Status) + } +} + + diff --git a/pkg/registry/apps/application/rest_defaulting.go b/pkg/registry/apps/application/rest_defaulting.go new file mode 100644 index 00000000..36518af6 --- /dev/null +++ b/pkg/registry/apps/application/rest_defaulting.go @@ -0,0 +1,187 @@ +/* +Copyright 2024 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package application + +import ( + "encoding/json" + "fmt" + + appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema" +) + +// applySpecDefaults applies default values to the Application spec based on the schema +func (r *REST) applySpecDefaults(app *appsv1alpha1.Application) error { + if r.specSchema == nil { + return nil + } + var m map[string]any + if app.Spec != nil && len(app.Spec.Raw) > 0 { + if err := json.Unmarshal(app.Spec.Raw, &m); err != nil { + return err + } + } + if m == nil { + m = map[string]any{} + } + if err := defaultLikeKubernetes(&m, r.specSchema); err != nil { + return err + } + raw, err := json.Marshal(m) + if err != nil { + return err + } + app.Spec = &apiextv1.JSON{Raw: raw} + return nil +} + +func defaultLikeKubernetes(root *map[string]any, s *structuralschema.Structural) error { + v := any(*root) + nv, err := applyDefaults(v, s, true) + if err != nil { + return err + } + obj, ok := nv.(map[string]any) + if !ok && nv != nil { + return fmt.Errorf("internal error: applyDefaults returned non-map type %T for object root", nv) + } + if obj == nil { + obj = map[string]any{} + } + *root = obj + return nil +} + +func applyDefaults(v any, s *structuralschema.Structural, top bool) (any, error) { + if s == nil { + return v, nil + } + + effType := s.Type + if effType == "" { + switch { + case len(s.Properties) > 0 || (s.AdditionalProperties != nil && s.AdditionalProperties.Structural != nil): + effType = "object" + case s.Items != nil: + effType = "array" + default: + // scalar + } + } + + switch effType { + case "object": + mv, isMap := v.(map[string]any) + if !isMap || v == nil { + if s.Default.Object != nil && !top { + if dm, ok := s.Default.Object.(map[string]any); ok { + mv = cloneMap(dm) + } + } + if mv == nil { + mv = map[string]any{} + } + } + + for name, ps := range s.Properties { + if _, ok := mv[name]; !ok { + if ps.Default.Object != nil { + mv[name] = clone(ps.Default.Object) + } + } + if cur, ok := mv[name]; ok { + cv, err := applyDefaults(cur, &ps, false) + if err != nil { + return nil, err + } + mv[name] = cv + } + } + + if s.AdditionalProperties != nil && s.AdditionalProperties.Structural != nil { + ap := s.AdditionalProperties.Structural + for k, cur := range mv { + if _, isKnown := s.Properties[k]; isKnown { + continue + } + cv, err := applyDefaults(cur, ap, false) + if err != nil { + return nil, err + } + mv[k] = cv + } + } + return mv, nil + + case "array": + sl, isSlice := v.([]any) + if !isSlice || v == nil { + if s.Default.Object != nil { + if ds, ok := s.Default.Object.([]any); ok { + sl = cloneSlice(ds) + } + } + if sl == nil { + sl = []any{} + } + } + if s.Items != nil { + for i := range sl { + cv, err := applyDefaults(sl[i], s.Items, false) + if err != nil { + return nil, err + } + sl[i] = cv + } + } + return sl, nil + + default: + if v == nil && s.Default.Object != nil { + return clone(s.Default.Object), nil + } + return v, nil + } +} + +func clone(x any) any { + switch t := x.(type) { + case map[string]any: + return cloneMap(t) + case []any: + return cloneSlice(t) + default: + return t + } +} + +func cloneMap(m map[string]any) map[string]any { + out := make(map[string]any, len(m)) + for k, v := range m { + out[k] = clone(v) + } + return out +} + +func cloneSlice(s []any) []any { + out := make([]any, len(s)) + for i := range s { + out[i] = clone(s[i]) + } + return out +} diff --git a/pkg/registry/apps/application/rest_defaulting_test.go b/pkg/registry/apps/application/rest_defaulting_test.go new file mode 100644 index 00000000..3625a425 --- /dev/null +++ b/pkg/registry/apps/application/rest_defaulting_test.go @@ -0,0 +1,124 @@ +package application + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + apischema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema" +) + +func TestApplication(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Application defaulting Suite") +} + +var _ = Describe("defaultLikeKubernetes", func() { + var rootSchema *apischema.Structural + + BeforeEach(func() { + rootSchema = buildTestSchema() + }) + + It("applies value-schema defaults to existing map key without merging parent object default", func() { + spec := map[string]any{ + "nodeGroups": map[string]any{ + "md0": map[string]any{ + "minReplicas": 3, + }, + }, + } + + err := defaultLikeKubernetes(&spec, rootSchema) + Expect(err).NotTo(HaveOccurred()) + + ng := spec["nodeGroups"].(map[string]any)["md0"].(map[string]any) + + Expect(ng).To(HaveKeyWithValue("minReplicas", BeNumerically("==", 3))) + Expect(ng).To(HaveKeyWithValue("instanceType", "u1.medium")) + Expect(ng["roles"]).To(ConsistOf("ingress-nginx")) + + Expect(ng).NotTo(HaveKey("ephemeralStorage")) + Expect(ng).NotTo(HaveKey("maxReplicas")) + Expect(ng).NotTo(HaveKey("resources")) + }) + + It("does not create new map keys from parent object default", func() { + spec := map[string]any{ + "nodeGroups": map[string]any{}, + } + + err := defaultLikeKubernetes(&spec, rootSchema) + Expect(err).NotTo(HaveOccurred()) + + ng := spec["nodeGroups"].(map[string]any) + Expect(ng).NotTo(HaveKey("md0")) + }) +}) + +func buildTestSchema() *apischema.Structural { + instanceType := apischema.Structural{ + Generic: apischema.Generic{ + Type: "string", + Default: apischema.JSON{Object: "u1.medium"}, + }, + } + roles := apischema.Structural{ + Generic: apischema.Generic{ + Type: "array", + Default: apischema.JSON{Object: []any{"ingress-nginx"}}, + }, + Items: &apischema.Structural{ + Generic: apischema.Generic{Type: "string"}, + }, + } + minReplicas := apischema.Structural{ + Generic: apischema.Generic{Type: "integer"}, + } + ephemeralStorage := apischema.Structural{ + Generic: apischema.Generic{Type: "string"}, + } + maxReplicas := apischema.Structural{ + Generic: apischema.Generic{Type: "integer"}, + } + resources := apischema.Structural{ + Generic: apischema.Generic{Type: "object"}, + Properties: map[string]apischema.Structural{}, + } + + nodeGroupsValue := &apischema.Structural{ + Generic: apischema.Generic{Type: "object"}, + Properties: map[string]apischema.Structural{ + "instanceType": instanceType, + "roles": roles, + "minReplicas": minReplicas, + "ephemeralStorage": ephemeralStorage, + "maxReplicas": maxReplicas, + "resources": resources, + }, + } + + nodeGroups := apischema.Structural{ + Generic: apischema.Generic{ + Type: "object", + Default: apischema.JSON{Object: map[string]any{ + "md0": map[string]any{ + "ephemeralStorage": "20Gi", + "maxReplicas": 10, + "minReplicas": 0, + "resources": map[string]any{}, + }, + }}, + }, + AdditionalProperties: &apischema.StructuralOrBool{ + Structural: nodeGroupsValue, + }, + } + + return &apischema.Structural{ + Generic: apischema.Generic{Type: "object"}, + Properties: map[string]apischema.Structural{ + "nodeGroups": nodeGroups, + }, + } +} diff --git a/pkg/registry/apps/application/rest_sorting_test.go b/pkg/registry/apps/application/rest_sorting_test.go new file mode 100644 index 00000000..6b3f6162 --- /dev/null +++ b/pkg/registry/apps/application/rest_sorting_test.go @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: Apache-2.0 + +package application + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + "github.com/cozystack/cozystack/pkg/registry/sorting" +) + +func TestApplicationListSortsAlphabetically(t *testing.T) { + items := []appsv1alpha1.Application{ + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-b", Name: "zebra"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-a", Name: "alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-b", Name: "alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-a", Name: "bravo"}}, + } + + sorting.ByNamespacedName[appsv1alpha1.Application, *appsv1alpha1.Application](items) + + expected := []struct{ ns, name string }{ + {"ns-a", "alpha"}, + {"ns-a", "bravo"}, + {"ns-b", "alpha"}, + {"ns-b", "zebra"}, + } + + for i, exp := range expected { + if items[i].Namespace != exp.ns || items[i].Name != exp.name { + t.Errorf("item %d: expected %s/%s, got %s/%s", i, exp.ns, exp.name, items[i].Namespace, items[i].Name) + } + } +} diff --git a/pkg/registry/apps/application/rest_timeout_test.go b/pkg/registry/apps/application/rest_timeout_test.go new file mode 100644 index 00000000..85ac0b97 --- /dev/null +++ b/pkg/registry/apps/application/rest_timeout_test.go @@ -0,0 +1,116 @@ +package application + +import ( + "testing" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + "github.com/cozystack/cozystack/pkg/config" +) + +func newRESTForTimeout(kind, prefix string, helmInstallTimeout time.Duration) *REST { + return &REST{ + kindName: kind, + releaseConfig: config.ReleaseConfig{ + Prefix: prefix, + ChartRef: config.ChartRefConfig{ + Kind: "HelmChart", + Name: "x", + Namespace: "cozy-system", + }, + HelmInstallTimeout: helmInstallTimeout, + }, + } +} + +// Table-driven: every Application kind carries a per-CRD HelmRelease wait +// budget. The Kubernetes kind's parent chart contains CAPI/Kamaji resources +// whose admin-kubeconfig Secret is provisioned asynchronously, so its +// ApplicationDefinition sets release.cozystack.io/helm-install-timeout=15m +// (or longer). Other kinds leave the annotation unset and keep flux defaults +// so their failed installs remediate on the normal cadence. The test must +// cover both paths: a kind with the timeout set and one without. +func TestConvertApplicationToHelmRelease_AppliesReleaseConfigTimeout(t *testing.T) { + cases := []struct { + name string + kind string + prefix string + configured time.Duration + wantSet bool + }{ + { + name: "Kubernetes kind with 15m configured gets Install and Upgrade Timeout", + kind: "Kubernetes", + prefix: "kubernetes-", + configured: 15 * time.Minute, + wantSet: true, + }, + { + // Fictional kind on purpose: the test is about the unset path + // regardless of which real Application kind ends up needing a + // timeout override. Using a real kind name would create false + // coupling to that Application's ApplicationDefinition. + name: "unrelated kind without configured timeout keeps flux defaults", + kind: "PlaceholderKindForDefaults", + prefix: "placeholder-", + configured: 0, + wantSet: false, + }, + { + name: "arbitrary future kind with 20m configured gets 20m", + kind: "TalosCluster", + prefix: "talos-", + configured: 20 * time.Minute, + wantSet: true, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + r := newRESTForTimeout(tc.kind, tc.prefix, tc.configured) + app := &appsv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "example", Namespace: "tenant-root"}, + } + + hr, err := r.convertApplicationToHelmRelease(app) + if err != nil { + t.Fatalf("convertApplicationToHelmRelease returned error: %v", err) + } + + if hr.Spec.Install == nil || hr.Spec.Upgrade == nil { + t.Fatalf("Spec.Install/Upgrade must be non-nil") + } + + if tc.wantSet { + if hr.Spec.Install.Timeout == nil { + t.Fatalf("Spec.Install.Timeout must be set when HelmInstallTimeout=%v", tc.configured) + } + if hr.Spec.Install.Timeout.Duration != tc.configured { + t.Errorf("Spec.Install.Timeout = %v, want %v", hr.Spec.Install.Timeout.Duration, tc.configured) + } + if hr.Spec.Upgrade.Timeout == nil { + t.Fatalf("Spec.Upgrade.Timeout must be set when HelmInstallTimeout=%v", tc.configured) + } + if hr.Spec.Upgrade.Timeout.Duration != tc.configured { + t.Errorf("Spec.Upgrade.Timeout = %v, want %v", hr.Spec.Upgrade.Timeout.Duration, tc.configured) + } + } else { + if hr.Spec.Install.Timeout != nil { + t.Errorf("Spec.Install.Timeout must be nil when HelmInstallTimeout=0, got %v", hr.Spec.Install.Timeout.Duration) + } + if hr.Spec.Upgrade.Timeout != nil { + t.Errorf("Spec.Upgrade.Timeout must be nil when HelmInstallTimeout=0, got %v", hr.Spec.Upgrade.Timeout.Duration) + } + } + + if hr.Spec.Install.Remediation == nil || hr.Spec.Install.Remediation.Retries != -1 { + t.Errorf("Spec.Install.Remediation.Retries must remain -1, got %+v", hr.Spec.Install.Remediation) + } + if hr.Spec.Upgrade.Remediation == nil || hr.Spec.Upgrade.Remediation.Retries != -1 { + t.Errorf("Spec.Upgrade.Remediation.Retries must remain -1, got %+v", hr.Spec.Upgrade.Remediation) + } + }) + } +} diff --git a/pkg/registry/apps/application/rest_validation_test.go b/pkg/registry/apps/application/rest_validation_test.go new file mode 100644 index 00000000..b806161c --- /dev/null +++ b/pkg/registry/apps/application/rest_validation_test.go @@ -0,0 +1,397 @@ +/* +Copyright 2026 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package application + +import ( + "context" + "fmt" + "strings" + "testing" + + helmv2 "github.com/fluxcd/helm-controller/api/v2" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/rest" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + "github.com/cozystack/cozystack/pkg/apis/apps/validation" + "github.com/cozystack/cozystack/pkg/config" +) + +func TestValidateNameFormat(t *testing.T) { + tests := []struct { + name string + kindName string + appName string + wantError bool + }{ + // Non-tenant kinds follow DNS-1035 only — hyphens are allowed. + {"non-tenant accepts hyphen", "MySQL", "my-db", false}, + {"non-tenant accepts double hyphen", "MySQL", "my--db", false}, + {"non-tenant rejects uppercase", "MySQL", "MyDB", true}, + + // Tenant kind enforces alphanumeric-only — see + // packages/apps/tenant/templates/_helpers.tpl for the reason. + {"tenant accepts alphanumeric", validation.TenantKind, "foo", false}, + {"tenant accepts digits", validation.TenantKind, "foo123", false}, + {"tenant rejects single hyphen", validation.TenantKind, "foo-bar", true}, + {"tenant rejects leading hyphen", validation.TenantKind, "-foo", true}, + {"tenant rejects trailing hyphen", validation.TenantKind, "foo-", true}, + {"tenant rejects uppercase", validation.TenantKind, "Foo", true}, + {"tenant rejects underscore", validation.TenantKind, "foo_bar", true}, + {"tenant rejects empty", validation.TenantKind, "", true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &REST{kindName: tt.kindName} + + errs := r.validateNameFormat(tt.appName) + + if tt.wantError && len(errs) == 0 { + t.Errorf("expected error for name %q (kind=%q), got none", tt.appName, tt.kindName) + } + if !tt.wantError && len(errs) > 0 { + t.Errorf("unexpected error for name %q (kind=%q): %v", tt.appName, tt.kindName, errs) + } + }) + } +} + +// TestUpdate_ForceAllowCreate_RejectsTenantDashName pins the wiring from the +// Update → Create fall-through path. When a user runs `kubectl apply` and +// the object does not yet exist, Kubernetes routes the request through +// REST.Update with forceAllowCreate=true, which delegates to REST.Create +// (rest.go:452). Without this test, a future refactor could quietly reroute +// that delegation and bypass the tenant name check — unit tests of the +// pure r.validateNameFormat method would still pass while upsert-style +// kubectl apply regressed back to accepting tenant names with dashes. +func TestUpdate_ForceAllowCreate_RejectsTenantDashName(t *testing.T) { + scheme := runtime.NewScheme() + if err := helmv2.AddToScheme(scheme); err != nil { + t.Fatalf("register helmv2 scheme: %v", err) + } + // Register the dynamic Tenant kind so the Application type round-trips + // through the scheme the same way the real aggregated API server wires + // it at startup. + resourceCfg := &config.ResourceConfig{ + Resources: []config.Resource{ + { + Application: config.ApplicationConfig{Kind: validation.TenantKind}, + }, + }, + } + if err := appsv1alpha1.RegisterDynamicTypes(scheme, resourceCfg); err != nil { + t.Fatalf("register dynamic Tenant type: %v", err) + } + + fakeClient := fake.NewClientBuilder().WithScheme(scheme).Build() + + r := &REST{ + c: fakeClient, + gvr: schema.GroupVersionResource{ + Group: appsv1alpha1.GroupName, + Version: "v1alpha1", + Resource: "tenants", + }, + gvk: schema.GroupVersionKind{ + Group: appsv1alpha1.GroupName, + Version: "v1alpha1", + Kind: validation.TenantKind, + }, + kindName: validation.TenantKind, + releaseConfig: config.ReleaseConfig{ + Prefix: "tenant-", + }, + } + + newApp := &appsv1alpha1.Application{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps.cozystack.io/v1alpha1", + Kind: validation.TenantKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "foo-bar", + Namespace: "tenant-root", + }, + } + + ctx := request.WithNamespace(context.Background(), "tenant-root") + + _, _, err := r.Update( + ctx, + "foo-bar", + rest.DefaultUpdatedObjectInfo(newApp), + nil, // createValidation + nil, // updateValidation + true, // forceAllowCreate → routes through Create on NotFound + &metav1.UpdateOptions{}, + ) + if err == nil { + t.Fatalf("expected Update to reject tenant name with dashes, got no error") + } + if !apierrors.IsInvalid(err) { + t.Errorf("expected Invalid status error, got %T: %v", err, err) + } + if !strings.Contains(err.Error(), "tenant names must") { + t.Errorf("expected tenant-specific error in %q", err.Error()) + } +} + +// TestConvertHelmReleaseToApplication_TenantNamespaceKindGate pins the +// behavior that convertHelmReleaseToApplication fills Status.Namespace only +// when the kind is Tenant. This path is gated on r.kindName matching a +// specific literal — the test uses the validation.TenantKind constant so +// that if the source of truth for the tenant kind string is ever renamed, +// the gate and the constant drift together (or the test fails). +func TestConvertHelmReleaseToApplication_TenantNamespaceKindGate(t *testing.T) { + scheme := runtime.NewScheme() + if err := helmv2.AddToScheme(scheme); err != nil { + t.Fatalf("register helmv2 scheme: %v", err) + } + if err := corev1.AddToScheme(scheme); err != nil { + t.Fatalf("register corev1 scheme: %v", err) + } + + fakeClient := fake.NewClientBuilder().WithScheme(scheme).Build() + + hr := &helmv2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tenant-foo", + Namespace: "tenant-root", + }, + } + + t.Run("tenant kind fills Status.Namespace", func(t *testing.T) { + r := &REST{ + c: fakeClient, + kindName: validation.TenantKind, + releaseConfig: config.ReleaseConfig{ + Prefix: "tenant-", + }, + } + + app, err := r.convertHelmReleaseToApplication(context.Background(), hr, nil) + if err != nil { + t.Fatalf("convertHelmReleaseToApplication: %v", err) + } + if app.Status.Namespace == "" { + t.Errorf("expected Status.Namespace to be populated for tenant kind, got empty") + } + }) + + t.Run("non-tenant kind leaves Status.Namespace empty", func(t *testing.T) { + r := &REST{ + c: fakeClient, + kindName: "MySQL", + releaseConfig: config.ReleaseConfig{ + Prefix: "mysql-", + }, + } + + app, err := r.convertHelmReleaseToApplication(context.Background(), hr, nil) + if err != nil { + t.Fatalf("convertHelmReleaseToApplication: %v", err) + } + if app.Status.Namespace != "" { + t.Errorf("expected Status.Namespace to be empty for non-tenant kind, got %q", app.Status.Namespace) + } + }) +} + +func TestValidateNameLength(t *testing.T) { + tests := []struct { + name string + kindName string + prefix string + appName string + wantError bool + }{ + { + name: "short name passes", + kindName: "MySQL", + prefix: "mysql-", + appName: "mydb", + wantError: false, + }, + { + name: "at helm boundary passes", + kindName: "MySQL", + prefix: "mysql-", + appName: strings.Repeat("a", 53-len("mysql-")), // exactly 47 chars + wantError: false, + }, + { + name: "exceeding helm limit fails", + kindName: "MySQL", + prefix: "mysql-", + appName: strings.Repeat("a", 53-len("mysql-")+1), // 48 chars + wantError: true, + }, + { + name: "tenant within helm limit passes", + kindName: "Tenant", + prefix: "tenant-", + appName: strings.Repeat("a", 53-len("tenant-")), // 46 chars + wantError: false, + }, + { + name: "tenant exceeding helm limit fails", + kindName: "Tenant", + prefix: "tenant-", + appName: strings.Repeat("a", 53-len("tenant-")+1), // 47 chars + wantError: true, + }, + { + name: "prefix consuming all helm capacity returns config error", + kindName: "MySQL", + prefix: strings.Repeat("x", 53), // prefix == maxHelmReleaseName → helmMax = 0 + appName: "a", + wantError: true, + }, + { + name: "prefix exceeding helm capacity returns config error", + kindName: "MySQL", + prefix: strings.Repeat("x", 60), // prefix > maxHelmReleaseName → helmMax < 0 + appName: "a", + wantError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &REST{ + kindName: tt.kindName, + releaseConfig: config.ReleaseConfig{ + Prefix: tt.prefix, + }, + } + + errs := r.validateNameLength(tt.appName) + + if tt.wantError && len(errs) == 0 { + t.Errorf("expected error for name %q (len=%d), got none", tt.appName, len(tt.appName)) + } + if !tt.wantError && len(errs) > 0 { + t.Errorf("unexpected error for name %q (len=%d): %v", tt.appName, len(tt.appName), errs) + } + }) + } +} + +// TestValidateTenantNamespaceLength covers the check that the computed +// workload namespace for a Tenant application fits inside the 63-char +// DNS-1123 label limit. The namespace is formed by dash-joining the +// parent namespace with the tenant name, so deep nesting can exceed the +// limit even when each individual name passes the per-name Helm release +// length check. +// +// The "tenant-root" branches of computeTenantNamespace do not get a +// dedicated overflow case: that branch produces "tenant-" (7 + +// len(name)), so for the computed result to exceed 63 chars the name +// would need to exceed 56 chars, which is already blocked by +// validateNameLength (max 46 for the "tenant-" prefix). The invariant +// holds by arithmetic. +func TestValidateTenantNamespaceLength(t *testing.T) { + tests := []struct { + name string + currentNamespace string + tenantName string + wantError bool + }{ + { + name: "tenant-root with short name passes", + currentNamespace: "tenant-root", + tenantName: "alpha", + wantError: false, + }, + { + name: "root tenant inside root namespace passes", + currentNamespace: "tenant-root", + tenantName: "root", + wantError: false, + }, + { + name: "short parent and short name passes", + currentNamespace: "tenant-foo", + tenantName: "bar", + wantError: false, + }, + { + name: "exactly at 63-char limit passes", + currentNamespace: "tenant-" + strings.Repeat("a", 45), // 52 chars + tenantName: strings.Repeat("b", 10), // 10 chars -> 52+1+10 = 63 + wantError: false, + }, + { + name: "one char over the limit fails", + currentNamespace: "tenant-" + strings.Repeat("a", 45), // 52 chars + tenantName: strings.Repeat("b", 11), // 11 chars -> 52+1+11 = 64 + wantError: true, + }, + { + name: "deeply nested failure with issue-style names", + currentNamespace: "tenant-" + strings.Repeat("a", 35), // 42 chars + tenantName: strings.Repeat("b", 25), // 25 chars -> 42+1+25 = 68 + wantError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &REST{ + kindName: "Tenant", + releaseConfig: config.ReleaseConfig{ + Prefix: "tenant-", + }, + } + + errs := r.validateTenantNamespaceLength(tt.currentNamespace, tt.tenantName) + + if tt.wantError && len(errs) == 0 { + computed := r.computeTenantNamespace(tt.currentNamespace, tt.tenantName) + t.Errorf("expected error for parent=%q name=%q (computed=%q, len=%d), got none", + tt.currentNamespace, tt.tenantName, computed, len(computed)) + return + } + if !tt.wantError && len(errs) > 0 { + t.Errorf("unexpected error for parent=%q name=%q: %v", + tt.currentNamespace, tt.tenantName, errs) + return + } + + // For failing cases, verify the error message surfaces the + // computed namespace string and its actual length so a + // regression in the message format is caught. + if tt.wantError { + computed := r.computeTenantNamespace(tt.currentNamespace, tt.tenantName) + msg := errs.ToAggregate().Error() + if !strings.Contains(msg, computed) { + t.Errorf("error message must contain computed namespace %q, got: %s", computed, msg) + } + if !strings.Contains(msg, fmt.Sprintf("%d characters", len(computed))) { + t.Errorf("error message must contain the computed length %d, got: %s", len(computed), msg) + } + } + }) + } +} diff --git a/pkg/registry/apps/application/rest_watch_test.go b/pkg/registry/apps/application/rest_watch_test.go new file mode 100644 index 00000000..93a51f3c --- /dev/null +++ b/pkg/registry/apps/application/rest_watch_test.go @@ -0,0 +1,223 @@ +package application + +import ( + "context" + "testing" + "time" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + "github.com/cozystack/cozystack/pkg/config" + helmv2 "github.com/fluxcd/helm-controller/api/v2" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +func TestWmResultChan_NilWatcher(t *testing.T) { + ch := wmResultChan(nil) + if ch != nil { + t.Error("expected nil channel for nil watcher") + } +} + +func TestWmResultChan_ValidWatcher(t *testing.T) { + fw := watch.NewFake() + ch := wmResultChan(fw) + if ch == nil { + t.Error("expected non-nil channel for valid watcher") + } + fw.Stop() +} + +// TestWatchIntegration_WorkloadMonitorTriggersModifiedEvent verifies the +// full path: WM event → label lookup → HelmRelease Get → Application conversion. +func TestWatchIntegration_WorkloadMonitorTriggersModifiedEvent(t *testing.T) { + scheme := runtime.NewScheme() + _ = cozyv1alpha1.AddToScheme(scheme) + _ = helmv2.AddToScheme(scheme) + + hr := &helmv2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "postgresql-mydb", + Namespace: "default", + Labels: map[string]string{ + ApplicationKindLabel: "PostgreSQL", + ApplicationGroupLabel: "apps.cozystack.io", + ApplicationNameLabel: "mydb", + }, + }, + } + hr.Status.Conditions = []metav1.Condition{ + {Type: "Ready", Status: metav1.ConditionTrue, Reason: "Succeeded", Message: "ok"}, + } + + wm := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-1", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: ptr.To(false), + }, + } + + c := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(hr, wm).Build() + + r := newTestRESTWithSchemesFromClient(c) + + // Simulate the Watch goroutine path: extract app name from WM labels, + // construct HelmRelease name, look up HR, convert to Application + wmAppName := wm.Labels[ApplicationNameLabel] + hrName := r.releaseConfig.Prefix + wmAppName + + foundHR := &helmv2.HelmRelease{} + if err := c.Get(context.TODO(), types.NamespacedName{Namespace: "default", Name: hrName}, foundHR); err != nil { + t.Fatalf("failed to get HelmRelease: %v", err) + } + app, err := r.ConvertHelmReleaseToApplication(context.TODO(), foundHR) + if err != nil { + t.Fatalf("failed to convert: %v", err) + } + if app.Name != "mydb" { + t.Errorf("expected app name 'mydb', got %q", app.Name) + } + + // Verify WorkloadsReady is False due to non-operational WM + wc := findCondition(app.GetConditions(), "WorkloadsReady") + if wc == nil { + t.Fatal("expected WorkloadsReady condition") + } + if wc.Status != metav1.ConditionFalse { + t.Errorf("expected WorkloadsReady=False, got %s", wc.Status) + } +} + +// TestWatchIntegration_MonitorDeletionDropsWorkloadsReady verifies that when a +// WorkloadMonitor is deleted, the Application's WorkloadsReady condition +// disappears. Ready condition always reflects HelmRelease state regardless. +func TestWatchIntegration_MonitorDeletionDropsWorkloadsReady(t *testing.T) { + scheme := runtime.NewScheme() + _ = cozyv1alpha1.AddToScheme(scheme) + _ = helmv2.AddToScheme(scheme) + + hr := &helmv2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "postgresql-mydb", + Namespace: "default", + Labels: map[string]string{ + ApplicationKindLabel: "PostgreSQL", + ApplicationGroupLabel: "apps.cozystack.io", + ApplicationNameLabel: "mydb", + }, + }, + } + hr.Status.Conditions = []metav1.Condition{ + {Type: "Ready", Status: metav1.ConditionTrue, Reason: "Succeeded", Message: "ok"}, + } + + nonOpMonitor := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-1", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: ptr.To(false), + }, + } + + c := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(hr, nonOpMonitor).Build() + r := newTestRESTWithSchemesFromClient(c) + + // Step 1: With non-operational monitor, WorkloadsReady=False, Ready=True + app1, err := r.convertHelmReleaseToApplication(context.TODO(), hr, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + wc1 := findCondition(app1.GetConditions(), "WorkloadsReady") + if wc1 == nil || wc1.Status != metav1.ConditionFalse { + t.Fatalf("expected WorkloadsReady=False with non-operational monitor, got %v", wc1) + } + rc1 := findCondition(app1.GetConditions(), "Ready") + if rc1 == nil || rc1.Status != metav1.ConditionTrue { + t.Fatalf("expected Ready=True (reflects HelmRelease), got %v", rc1) + } + + // Step 2: Delete the monitor + if err := c.Delete(context.TODO(), nonOpMonitor); err != nil { + t.Fatalf("failed to delete monitor: %v", err) + } + + // Step 3: WorkloadsReady should disappear, Ready stays True + app2, err := r.convertHelmReleaseToApplication(context.TODO(), hr, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + wc2 := findCondition(app2.GetConditions(), "WorkloadsReady") + if wc2 != nil { + t.Error("expected no WorkloadsReady condition after monitor deletion") + } + rc2 := findCondition(app2.GetConditions(), "Ready") + if rc2 == nil { + t.Fatal("expected Ready condition") + } + if rc2.Status != metav1.ConditionTrue { + t.Errorf("expected Ready=True after monitor deletion, got %s", rc2.Status) + } +} + +// TestWatchIntegration_WMWatcherCloseProducesNilChannel verifies that +// after wmWatcher is set to nil, wmResultChan returns nil channel. +func TestWatchIntegration_WMWatcherCloseProducesNilChannel(t *testing.T) { + fw := watch.NewFake() + ch := wmResultChan(fw) + if ch == nil { + t.Fatal("expected non-nil channel before close") + } + + fw.Stop() + + timeout := time.After(time.Second) + for { + select { + case _, ok := <-ch: + if !ok { + var nilWatcher watch.Interface + nilCh := wmResultChan(nilWatcher) + if nilCh != nil { + t.Error("expected nil channel after watcher set to nil") + } + return + } + case <-timeout: + t.Fatal("timeout waiting for watcher channel to close") + } + } +} + +func newTestRESTWithSchemesFromClient(c client.Client) *REST { + return NewREST(c, nil, &config.Resource{ + Application: config.ApplicationConfig{ + Kind: "PostgreSQL", + Plural: "postgresqls", + Singular: "postgresql", + }, + Release: config.ReleaseConfig{ + Prefix: "postgresql-", + }, + }) +} diff --git a/pkg/registry/apps/application/rest_workloads_test.go b/pkg/registry/apps/application/rest_workloads_test.go new file mode 100644 index 00000000..b706c323 --- /dev/null +++ b/pkg/registry/apps/application/rest_workloads_test.go @@ -0,0 +1,342 @@ +package application + +import ( + "context" + "testing" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + "github.com/cozystack/cozystack/pkg/config" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + helmv2 "github.com/fluxcd/helm-controller/api/v2" +) + +func newTestRESTWithSchemes(objs ...runtime.Object) *REST { + scheme := runtime.NewScheme() + _ = cozyv1alpha1.AddToScheme(scheme) + _ = helmv2.AddToScheme(scheme) + + builder := fake.NewClientBuilder().WithScheme(scheme) + for _, obj := range objs { + builder = builder.WithRuntimeObjects(obj) + } + c := builder.Build() + + return NewREST(c, nil, &config.Resource{ + Application: config.ApplicationConfig{ + Kind: "PostgreSQL", + Plural: "postgresqls", + Singular: "postgresql", + }, + Release: config.ReleaseConfig{ + Prefix: "postgresql-", + }, + }) +} + +func TestGetWorkloadsOperational_NoMonitors(t *testing.T) { + r := newTestRESTWithSchemes() + ws, err := r.getWorkloadsOperational(context.TODO(), "default", "mydb", nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if ws.found { + t.Error("expected found=false when no monitors exist") + } + if !ws.operational { + t.Error("expected operational=true when no monitors exist") + } +} + +func TestGetWorkloadsOperational_AllOperational(t *testing.T) { + m1 := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-1", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: ptr.To(true), + }, + } + m2 := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-2", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: ptr.To(true), + }, + } + + r := newTestRESTWithSchemes(m1, m2) + ws, err := r.getWorkloadsOperational(context.TODO(), "default", "mydb", nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ws.found { + t.Error("expected found=true") + } + if !ws.operational { + t.Error("expected operational=true when all monitors are operational") + } +} + +func TestGetWorkloadsOperational_SomeNotOperational(t *testing.T) { + m1 := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-1", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: ptr.To(true), + }, + } + m2 := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-2", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: ptr.To(false), + }, + } + + r := newTestRESTWithSchemes(m1, m2) + ws, err := r.getWorkloadsOperational(context.TODO(), "default", "mydb", nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ws.found { + t.Error("expected found=true") + } + if ws.operational { + t.Error("expected operational=false when at least one monitor is not operational") + } +} + +func TestGetWorkloadsOperational_OperationalNil(t *testing.T) { + m := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-1", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: nil, // Not yet reconciled + }, + } + + r := newTestRESTWithSchemes(m) + ws, err := r.getWorkloadsOperational(context.TODO(), "default", "mydb", nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ws.found { + t.Error("expected found=true") + } + if !ws.unknown { + t.Error("expected unknown=true when Operational is nil") + } +} + +func TestGetWorkloadsOperational_MixedNilAndOperational(t *testing.T) { + m1 := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-1", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: ptr.To(true), + }, + } + m2 := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-2", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: nil, + }, + } + + r := newTestRESTWithSchemes(m1, m2) + ws, err := r.getWorkloadsOperational(context.TODO(), "default", "mydb", nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !ws.unknown { + t.Error("expected unknown=true when at least one monitor has nil Operational") + } +} + +func TestGetWorkloadsOperational_MixedFailedAndPending(t *testing.T) { + m1 := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-1", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: ptr.To(false), // Confirmed failure + }, + } + m2 := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-2", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: nil, // Not yet reconciled + }, + } + + r := newTestRESTWithSchemes(m1, m2) + ws, err := r.getWorkloadsOperational(context.TODO(), "default", "mydb", nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if ws.operational { + t.Error("expected operational=false when at least one monitor is explicitly failed") + } + if !ws.unknown { + t.Error("expected unknown=true when at least one monitor has nil Operational") + } +} + +func TestConvertConditions_MixedFailedAndPendingShowsFalse(t *testing.T) { + mFailed := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-failed", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: ptr.To(false), + }, + } + mPending := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-pending", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "mydb", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: nil, + }, + } + + r := newTestRESTWithSchemes(mFailed, mPending) + hr := &helmv2.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: "postgresql-mydb", + Namespace: "default", + Labels: map[string]string{ + ApplicationKindLabel: "PostgreSQL", + ApplicationGroupLabel: "apps.cozystack.io", + ApplicationNameLabel: "mydb", + }, + }, + } + hr.Status.Conditions = []metav1.Condition{ + {Type: "Ready", Status: metav1.ConditionTrue, Reason: "Succeeded", Message: "ok"}, + } + + app, err := r.convertHelmReleaseToApplication(context.TODO(), hr, nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Concrete failure should take priority over unknown + wc := findCondition(app.GetConditions(), "WorkloadsReady") + if wc == nil { + t.Fatal("expected WorkloadsReady condition") + } + if wc.Status != metav1.ConditionFalse { + t.Errorf("expected WorkloadsReady=False (failure takes priority over unknown), got %s", wc.Status) + } +} + +func TestGetWorkloadsOperational_DifferentApp_NotFound(t *testing.T) { + m := &cozyv1alpha1.WorkloadMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mon-1", + Namespace: "default", + Labels: map[string]string{ + appsv1alpha1.ApplicationKindLabel: "PostgreSQL", + appsv1alpha1.ApplicationGroupLabel: "apps.cozystack.io", + appsv1alpha1.ApplicationNameLabel: "other-db", + }, + }, + Status: cozyv1alpha1.WorkloadMonitorStatus{ + Operational: ptr.To(false), + }, + } + + r := newTestRESTWithSchemes(m) + ws, err := r.getWorkloadsOperational(context.TODO(), "default", "mydb", nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if ws.found { + t.Error("expected found=false for different app name") + } + if !ws.operational { + t.Error("expected operational=true when no matching monitors found") + } +} + diff --git a/pkg/registry/core/tenantmodule/rest.go b/pkg/registry/core/tenantmodule/rest.go new file mode 100644 index 00000000..888d4414 --- /dev/null +++ b/pkg/registry/core/tenantmodule/rest.go @@ -0,0 +1,813 @@ +/* +Copyright 2024 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tenantmodule + +import ( + "context" + "fmt" + "net/http" + "strconv" + "strings" + "sync" + "time" + + helmv2 "github.com/fluxcd/helm-controller/api/v2" + metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + fields "k8s.io/apimachinery/pkg/fields" + labels "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/duration" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" + + corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + "github.com/cozystack/cozystack/pkg/registry" + fieldfilter "github.com/cozystack/cozystack/pkg/registry/fields" + "github.com/cozystack/cozystack/pkg/registry/sorting" + apierrors "k8s.io/apimachinery/pkg/api/errors" +) + +// Ensure REST implements necessary interfaces +var ( + _ rest.Lister = &REST{} + _ rest.Getter = &REST{} + _ rest.Watcher = &REST{} + _ rest.TableConvertor = &REST{} + _ rest.Scoper = &REST{} + _ rest.SingularNameProvider = &REST{} +) + +// Define constants for label filtering +const ( + TenantModuleLabelKey = "internal.cozystack.io/tenantmodule" + TenantModuleLabelValue = "true" + singularName = "tenantmodule" +) + +// REST implements the RESTStorage interface for TenantModule resources +type REST struct { + c client.Client + w client.WithWatch + gvr schema.GroupVersionResource + gvk schema.GroupVersionKind + kindName string + singularName string +} + +// NewREST creates a new REST storage for TenantModule +func NewREST(c client.Client, w client.WithWatch) *REST { + return &REST{ + c: c, + w: w, + gvr: schema.GroupVersionResource{ + Group: corev1alpha1.GroupName, + Version: "v1alpha1", + Resource: "tenantmodules", + }, + gvk: schema.GroupVersion{ + Group: corev1alpha1.GroupName, + Version: "v1alpha1", + }.WithKind("TenantModule"), + kindName: "TenantModule", + singularName: singularName, + } +} + +// NamespaceScoped indicates whether the resource is namespaced +func (r *REST) NamespaceScoped() bool { + return true +} + +// GetSingularName returns the singular name of the resource +func (r *REST) GetSingularName() string { + return r.singularName +} + +// Get retrieves a TenantModule by converting the corresponding HelmRelease +func (r *REST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + namespace, err := r.getNamespace(ctx) + if err != nil { + klog.Errorf("Failed to get namespace: %v", err) + return nil, err + } + + klog.V(6).Infof("Attempting to retrieve TenantModule %s in namespace %s", name, namespace) + + // Get the corresponding HelmRelease + hr := &helmv2.HelmRelease{} + err = r.c.Get(ctx, types.NamespacedName{Namespace: namespace, Name: name}, hr, &client.GetOptions{Raw: options}) + if err != nil { + klog.Errorf("Error retrieving HelmRelease for TenantModule %s: %v", name, err) + + // Check if the error is a NotFound error + if apierrors.IsNotFound(err) { + // Return a NotFound error for the TenantModule resource instead of HelmRelease + return nil, apierrors.NewNotFound(r.gvr.GroupResource(), name) + } + + // For other errors, return them as-is + return nil, err + } + + // Check if HelmRelease has the required label + if !r.hasTenantModuleLabel(hr) { + klog.Errorf("HelmRelease %s does not have the required label %s=%s", name, TenantModuleLabelKey, TenantModuleLabelValue) + // Return a NotFound error for the TenantModule resource + return nil, apierrors.NewNotFound(r.gvr.GroupResource(), name) + } + + // Convert HelmRelease to TenantModule + convertedModule, err := r.ConvertHelmReleaseToTenantModule(hr) + if err != nil { + klog.Errorf("Conversion error from HelmRelease to TenantModule for resource %s: %v", name, err) + return nil, fmt.Errorf("conversion error: %v", err) + } + + klog.V(6).Infof("Successfully retrieved and converted resource %s of kind %s", name, r.gvr.Resource) + return &convertedModule, nil +} + +// List retrieves a list of TenantModules by converting HelmReleases +func (r *REST) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) { + namespace, err := r.getNamespace(ctx) + if err != nil { + klog.Errorf("Failed to get namespace: %v", err) + return nil, err + } + + klog.V(6).Infof("Attempting to list TenantModules in namespace %s with options: %v", namespace, options) + + // Get resource name from the request (if any) + var resourceName string + if requestInfo, ok := request.RequestInfoFrom(ctx); ok { + resourceName = requestInfo.Name + } + + // Initialize variables for selector mapping + var helmLabelSelector labels.Selector + + // Parse field selector for manual filtering + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + fieldFilter, err := fieldfilter.ParseFieldSelector(options.FieldSelector) + if err != nil { + klog.Errorf("Error parsing field selector: %v", err) + return nil, err + } + + // If field selector specifies namespace different from context, return empty list + if fieldFilter.Namespace != "" && namespace != "" && namespace != fieldFilter.Namespace { + klog.V(6).Infof("Field selector namespace %s doesn't match context namespace %s, returning empty list", fieldFilter.Namespace, namespace) + return &corev1alpha1.TenantModuleList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: "TenantModuleList", + }, + }, nil + } + + // Process label.selector - add the tenant module label requirement + tenantModuleReq, err := labels.NewRequirement(TenantModuleLabelKey, selection.Equals, []string{TenantModuleLabelValue}) + if err != nil { + klog.Errorf("Error creating tenant module label requirement: %v", err) + return nil, fmt.Errorf("error creating tenant module label requirement: %v", err) + } + labelRequirements := []labels.Requirement{*tenantModuleReq} + + if options.LabelSelector != nil { + ls := options.LabelSelector.String() + parsedLabels, err := labels.Parse(ls) + if err != nil { + klog.Errorf("Invalid label selector: %v", err) + return nil, fmt.Errorf("invalid label selector: %v", err) + } + if !parsedLabels.Empty() { + reqs, _ := parsedLabels.Requirements() + labelRequirements = append(labelRequirements, reqs...) + } + } + + helmLabelSelector = labels.NewSelector().Add(labelRequirements...) + + // List HelmReleases with label selector only + // Field selectors are not supported by controller-runtime cache + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + hrList := &helmv2.HelmReleaseList{} + err = r.c.List(ctx, hrList, &client.ListOptions{ + Namespace: namespace, + LabelSelector: helmLabelSelector, + }) + if err != nil { + klog.Errorf("Error listing HelmReleases: %v", err) + return nil, err + } + + // Initialize TenantModule items array + items := make([]corev1alpha1.TenantModule, 0, len(hrList.Items)) + + // Iterate over HelmReleases and convert to TenantModules + for i := range hrList.Items { + // Apply manual field selector filtering (metadata.name and metadata.namespace) + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + if !fieldFilter.MatchesName(hrList.Items[i].Name) { + continue + } + if !fieldFilter.MatchesNamespace(hrList.Items[i].Namespace) { + continue + } + + // Double-check the label requirement + if !r.hasTenantModuleLabel(&hrList.Items[i]) { + continue + } + + module, err := r.ConvertHelmReleaseToTenantModule(&hrList.Items[i]) + if err != nil { + klog.Errorf("Error converting HelmRelease %s to TenantModule: %v", hrList.Items[i].GetName(), err) + continue + } + + // If resourceName is set, check for match + if resourceName != "" && module.Name != resourceName { + continue + } + + // Apply label.selector + if options.LabelSelector != nil { + sel, err := labels.Parse(options.LabelSelector.String()) + if err != nil { + klog.Errorf("Invalid label selector: %v", err) + continue + } + if !sel.Matches(labels.Set(module.Labels)) { + continue + } + } + + // Apply field.selector by name and namespace (if specified) + if options.FieldSelector != nil { + fs, err := fields.ParseSelector(options.FieldSelector.String()) + if err != nil { + klog.Errorf("Invalid field selector: %v", err) + continue + } + fieldsSet := fields.Set{ + "metadata.name": module.Name, + "metadata.namespace": module.Namespace, + } + if !fs.Matches(fieldsSet) { + continue + } + } + + items = append(items, module) + } + + // Create TenantModuleList with proper kind + moduleList := &corev1alpha1.TenantModuleList{} + moduleList.TypeMeta = metav1.TypeMeta{ + APIVersion: "core.cozystack.io/v1alpha1", + Kind: r.kindName + "List", + } + + // Get ResourceVersion from list or compute from items + // controller-runtime cached client may not set ResourceVersion on the list itself + listRV := hrList.GetResourceVersion() + if listRV == "" { + listRV, _ = registry.MaxResourceVersion(hrList) + } + moduleList.SetResourceVersion(listRV) + moduleList.Items = items + + sorting.ByNamespacedName[corev1alpha1.TenantModule, *corev1alpha1.TenantModule](moduleList.Items) + + klog.V(6).Infof("Successfully listed %d TenantModule resources in namespace %s", len(items), namespace) + return moduleList, nil +} + +// Watch sets up a watch on HelmReleases, filters them based on tenant module label, and converts events to TenantModules +func (r *REST) Watch(ctx context.Context, options *metainternalversion.ListOptions) (watch.Interface, error) { + namespace, err := r.getNamespace(ctx) + if err != nil { + klog.Errorf("Failed to get namespace: %v", err) + return nil, err + } + + klog.V(6).Infof("Setting up watch for TenantModules in namespace %s with options: %v", namespace, options) + + // Get request information, including resource name if specified + var resourceName string + if requestInfo, ok := request.RequestInfoFrom(ctx); ok { + resourceName = requestInfo.Name + } + + // Initialize variables for selector mapping + var helmLabelSelector labels.Selector + + // Parse field selector for manual filtering + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + fieldFilter, err := fieldfilter.ParseFieldSelector(options.FieldSelector) + if err != nil { + klog.Errorf("Error parsing field selector: %v", err) + return nil, err + } + + // Process label.selector - add the tenant module label requirement + tenantModuleReq, err := labels.NewRequirement(TenantModuleLabelKey, selection.Equals, []string{TenantModuleLabelValue}) + if err != nil { + klog.Errorf("Error creating tenant module label requirement: %v", err) + return nil, fmt.Errorf("error creating tenant module label requirement: %v", err) + } + labelRequirements := []labels.Requirement{*tenantModuleReq} + + if options.LabelSelector != nil { + ls := options.LabelSelector.String() + parsedLabels, err := labels.Parse(ls) + if err != nil { + klog.Errorf("Invalid label selector: %v", err) + return nil, fmt.Errorf("invalid label selector: %v", err) + } + if !parsedLabels.Empty() { + reqs, _ := parsedLabels.Requirements() + labelRequirements = append(labelRequirements, reqs...) + } + } + + helmLabelSelector = labels.NewSelector().Add(labelRequirements...) + + // Get starting resourceVersion from options + var startingRV uint64 + if options.ResourceVersion != "" { + if rv, err := strconv.ParseUint(options.ResourceVersion, 10, 64); err == nil { + startingRV = rv + } + } + + // Start watch on HelmRelease with label selector only + // Field selectors are not supported by controller-runtime cache + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + hrList := &helmv2.HelmReleaseList{} + helmWatcher, err := r.w.Watch(ctx, hrList, &client.ListOptions{ + Namespace: namespace, + LabelSelector: helmLabelSelector, + }) + if err != nil { + klog.Errorf("Error setting up watch for HelmReleases: %v", err) + return nil, err + } + + // Create a custom watcher to transform events + customW := &customWatcher{ + resultChan: make(chan watch.Event), + stopChan: make(chan struct{}), + underlying: helmWatcher, + } + + go func() { + defer close(customW.resultChan) + defer customW.underlying.Stop() + + for { + select { + case event, ok := <-customW.underlying.ResultChan(): + if !ok { + klog.Warning("HelmRelease watcher closed") + return + } + + // Handle bookmark events + if event.Type == watch.Bookmark { + if hr, ok := event.Object.(*helmv2.HelmRelease); ok { + bookmarkModule := &corev1alpha1.TenantModule{} + bookmarkModule.SetResourceVersion(hr.GetResourceVersion()) + bookmarkModule.TypeMeta = metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: r.kindName, + } + bookmarkEvent := watch.Event{ + Type: watch.Bookmark, + Object: bookmarkModule, + } + select { + case customW.resultChan <- bookmarkEvent: + case <-customW.stopChan: + return + case <-ctx.Done(): + return + } + } + continue + } + + // Check if the object is a *v1.Status + if status, ok := event.Object.(*metav1.Status); ok { + klog.V(4).Infof("Received Status object in HelmRelease watch: %v", status.Message) + continue + } + + // Proceed with processing HelmRelease objects + hr, ok := event.Object.(*helmv2.HelmRelease) + if !ok { + klog.V(4).Infof("Expected HelmRelease object, got %T", event.Object) + continue + } + + // Apply manual field selector filtering + if !fieldFilter.MatchesName(hr.Name) { + continue + } + if !fieldFilter.MatchesNamespace(hr.Namespace) { + continue + } + + if !r.hasTenantModuleLabel(hr) { + continue + } + + // Convert HelmRelease to TenantModule + module, err := r.ConvertHelmReleaseToTenantModule(hr) + if err != nil { + klog.Errorf("Error converting HelmRelease to TenantModule: %v", err) + continue + } + + // Skip ADDED events based on resourceVersion comparison + // Only skip when client provided resourceVersion (they already have objects from List) + if event.Type == watch.Added && startingRV > 0 { + objRV, parseErr := strconv.ParseUint(module.ResourceVersion, 10, 64) + // Skip objects client already has (objRV <= startingRV) + if parseErr == nil && objRV <= startingRV { + continue + } + } + // When startingRV == 0, always send ADDED events (client wants full state) + + // Apply field.selector by name if specified + if resourceName != "" && module.Name != resourceName { + continue + } + + // Apply label.selector + if options.LabelSelector != nil { + sel, err := labels.Parse(options.LabelSelector.String()) + if err != nil { + klog.Errorf("Invalid label selector: %v", err) + continue + } + if !sel.Matches(labels.Set(module.Labels)) { + continue + } + } + + // Create watch event with TenantModule object + moduleEvent := watch.Event{ + Type: event.Type, + Object: &module, + } + + // Send event to custom watcher + select { + case customW.resultChan <- moduleEvent: + case <-customW.stopChan: + return + case <-ctx.Done(): + return + } + + case <-customW.stopChan: + return + case <-ctx.Done(): + return + } + } + }() + + klog.V(6).Infof("Custom watch established successfully") + return customW, nil +} + +// customWatcher wraps the original watcher and filters/converts events +type customWatcher struct { + resultChan chan watch.Event + stopChan chan struct{} + stopOnce sync.Once + underlying watch.Interface +} + +// Stop terminates the watch +func (cw *customWatcher) Stop() { + cw.stopOnce.Do(func() { + close(cw.stopChan) + if cw.underlying != nil { + cw.underlying.Stop() + } + }) +} + +// ResultChan returns the event channel +func (cw *customWatcher) ResultChan() <-chan watch.Event { + return cw.resultChan +} + +// hasTenantModuleLabel checks if a HelmRelease has the required tenant module label +func (r *REST) hasTenantModuleLabel(hr *helmv2.HelmRelease) bool { + labels := hr.GetLabels() + if labels == nil { + return false + } + + value, exists := labels[TenantModuleLabelKey] + return exists && value == TenantModuleLabelValue +} + +// filterInternalLabels removes internal tenant module labels from the map +func filterInternalLabels(m map[string]string) map[string]string { + if m == nil { + return nil + } + out := make(map[string]string, len(m)) + for k, v := range m { + if k == TenantModuleLabelKey { + continue + } + out[k] = v + } + return out +} + +// getNamespace extracts the namespace from the context +func (r *REST) getNamespace(ctx context.Context) (string, error) { + namespace, ok := request.NamespaceFrom(ctx) + if !ok { + err := fmt.Errorf("namespace not found in context") + klog.Error(err) + return "", err + } + return namespace, nil +} + +// ConvertHelmReleaseToTenantModule converts a HelmRelease to a TenantModule +func (r *REST) ConvertHelmReleaseToTenantModule(hr *helmv2.HelmRelease) (corev1alpha1.TenantModule, error) { + klog.V(6).Infof("Converting HelmRelease to TenantModule for resource %s", hr.GetName()) + + // Convert HelmRelease struct to TenantModule struct + module, err := r.convertHelmReleaseToTenantModule(hr) + if err != nil { + klog.Errorf("Error converting from HelmRelease to TenantModule: %v", err) + return corev1alpha1.TenantModule{}, err + } + + klog.V(6).Infof("Successfully converted HelmRelease %s to TenantModule", hr.GetName()) + return module, nil +} + +// convertHelmReleaseToTenantModule implements the actual conversion logic +func (r *REST) convertHelmReleaseToTenantModule(hr *helmv2.HelmRelease) (corev1alpha1.TenantModule, error) { + if hr == nil { + return corev1alpha1.TenantModule{}, fmt.Errorf("HelmRelease is nil") + } + + // Safely extract chart version, handling nil cases + var appVersion string + if hr.Spec.Chart != nil { + appVersion = hr.Spec.Chart.Spec.Version + } + + module := corev1alpha1.TenantModule{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "core.cozystack.io/v1alpha1", + Kind: r.kindName, + }, + AppVersion: appVersion, + ObjectMeta: metav1.ObjectMeta{ + Name: hr.Name, + Namespace: hr.Namespace, + UID: hr.GetUID(), + ResourceVersion: hr.GetResourceVersion(), + CreationTimestamp: hr.CreationTimestamp, + DeletionTimestamp: hr.DeletionTimestamp, + Labels: filterInternalLabels(hr.Labels), + Annotations: hr.Annotations, + }, + Status: corev1alpha1.TenantModuleStatus{ + Version: hr.Status.LastAttemptedRevision, + }, + } + + var conditions []metav1.Condition + for _, hrCondition := range hr.GetConditions() { + if hrCondition.Type == "Ready" || hrCondition.Type == "Released" { + conditions = append(conditions, metav1.Condition{ + LastTransitionTime: hrCondition.LastTransitionTime, + Reason: hrCondition.Reason, + Message: hrCondition.Message, + Status: hrCondition.Status, + Type: hrCondition.Type, + }) + } + } + module.Status.Conditions = conditions + return module, nil +} + +// ConvertToTable implements the TableConvertor interface for displaying resources in a table format +func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { + klog.V(6).Infof("ConvertToTable: received object of type %T", object) + + var table metav1.Table + + switch obj := object.(type) { + case *corev1alpha1.TenantModuleList: + table = r.buildTableFromTenantModules(obj.Items) + table.ResourceVersion = obj.ResourceVersion + case *corev1alpha1.TenantModule: + table = r.buildTableFromTenantModule(*obj) + table.ResourceVersion = obj.GetResourceVersion() + default: + resource := schema.GroupResource{} + if info, ok := request.RequestInfoFrom(ctx); ok { + resource = schema.GroupResource{Group: info.APIGroup, Resource: info.Resource} + } + return nil, errNotAcceptable{ + resource: resource, + message: "object does not implement the Object interfaces", + } + } + + // Handle table options + if opt, ok := tableOptions.(*metav1.TableOptions); ok && opt != nil && opt.NoHeaders { + table.ColumnDefinitions = nil + } + + table.TypeMeta = metav1.TypeMeta{ + APIVersion: "meta.k8s.io/v1", + Kind: "Table", + } + + klog.V(6).Infof("ConvertToTable: returning table with %d rows", len(table.Rows)) + return &table, nil +} + +// buildTableFromTenantModules constructs a table from a list of TenantModules +func (r *REST) buildTableFromTenantModules(modules []corev1alpha1.TenantModule) metav1.Table { + table := metav1.Table{ + ColumnDefinitions: []metav1.TableColumnDefinition{ + {Name: "NAME", Type: "string", Description: "Name of the TenantModule", Priority: 0}, + {Name: "READY", Type: "string", Description: "Ready status of the TenantModule", Priority: 0}, + {Name: "AGE", Type: "string", Description: "Age of the TenantModule", Priority: 0}, + {Name: "VERSION", Type: "string", Description: "Version of the TenantModule", Priority: 0}, + }, + Rows: make([]metav1.TableRow, 0, len(modules)), + } + now := time.Now() + + for i := range modules { + module := &modules[i] + row := metav1.TableRow{ + Cells: []interface{}{module.GetName(), getReadyStatus(module.Status.Conditions), computeAge(module.GetCreationTimestamp().Time, now), getVersion(module.Status.Version)}, + Object: runtime.RawExtension{Object: module}, + } + table.Rows = append(table.Rows, row) + } + + return table +} + +// buildTableFromTenantModule constructs a table from a single TenantModule +func (r *REST) buildTableFromTenantModule(module corev1alpha1.TenantModule) metav1.Table { + table := metav1.Table{ + ColumnDefinitions: []metav1.TableColumnDefinition{ + {Name: "NAME", Type: "string", Description: "Name of the TenantModule", Priority: 0}, + {Name: "READY", Type: "string", Description: "Ready status of the TenantModule", Priority: 0}, + {Name: "AGE", Type: "string", Description: "Age of the TenantModule", Priority: 0}, + {Name: "VERSION", Type: "string", Description: "Version of the TenantModule", Priority: 0}, + }, + Rows: []metav1.TableRow{}, + } + now := time.Now() + + m := module + row := metav1.TableRow{ + Cells: []interface{}{module.GetName(), getReadyStatus(module.Status.Conditions), computeAge(module.GetCreationTimestamp().Time, now), getVersion(module.Status.Version)}, + Object: runtime.RawExtension{Object: &m}, + } + table.Rows = append(table.Rows, row) + + return table +} + +// getVersion extracts and returns only the revision from the version string +// If version is in format "0.1.4+abcdef", returns "abcdef" +// Otherwise returns the original string or "" if empty +func getVersion(version string) string { + if version == "" { + return "" + } + // Check if version contains "+" separator + if idx := strings.LastIndex(version, "+"); idx >= 0 && idx < len(version)-1 { + // Return only the part after "+" + return version[idx+1:] + } + // If no "+" found, return original version + return version +} + +// computeAge calculates the age of the object based on CreationTimestamp and current time +func computeAge(creationTime, currentTime time.Time) string { + ageDuration := currentTime.Sub(creationTime) + return duration.HumanDuration(ageDuration) +} + +// getReadyStatus returns the ready status based on conditions +func getReadyStatus(conditions []metav1.Condition) string { + for _, condition := range conditions { + if condition.Type == "Ready" { + switch condition.Status { + case metav1.ConditionTrue: + return "True" + case metav1.ConditionFalse: + return "False" + default: + return "Unknown" + } + } + } + return "Unknown" +} + +// Destroy releases resources associated with REST +func (r *REST) Destroy() { + // No additional actions needed to release resources. +} + +// New creates a new instance of TenantModule +func (r *REST) New() runtime.Object { + obj := &corev1alpha1.TenantModule{} + obj.TypeMeta = metav1.TypeMeta{ + APIVersion: r.gvk.GroupVersion().String(), + Kind: r.kindName, + } + return obj +} + +// NewList returns an empty list of TenantModule objects +func (r *REST) NewList() runtime.Object { + obj := &corev1alpha1.TenantModuleList{} + obj.TypeMeta = metav1.TypeMeta{ + APIVersion: r.gvk.GroupVersion().String(), + Kind: r.kindName + "List", + } + return obj +} + +// Kind returns the resource kind used for API discovery +func (r *REST) Kind() string { + return r.gvk.Kind +} + +// GroupVersionKind returns the GroupVersionKind for REST +func (r *REST) GroupVersionKind(schema.GroupVersion) schema.GroupVersionKind { + return r.gvk +} + +// errNotAcceptable indicates that the resource does not support conversion to Table +type errNotAcceptable struct { + resource schema.GroupResource + message string +} + +func (e errNotAcceptable) Error() string { + return e.message +} + +func (e errNotAcceptable) Status() metav1.Status { + return metav1.Status{ + Status: metav1.StatusFailure, + Code: http.StatusNotAcceptable, + Reason: metav1.StatusReason("NotAcceptable"), + Message: e.Error(), + } +} diff --git a/pkg/registry/core/tenantmodule/rest_test.go b/pkg/registry/core/tenantmodule/rest_test.go new file mode 100644 index 00000000..ceed9e7b --- /dev/null +++ b/pkg/registry/core/tenantmodule/rest_test.go @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: Apache-2.0 + +package tenantmodule + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + "github.com/cozystack/cozystack/pkg/registry/sorting" +) + +func TestTenantModuleListSortsAlphabetically(t *testing.T) { + items := []corev1alpha1.TenantModule{ + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-b", Name: "zebra"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-a", Name: "alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-b", Name: "alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-a", Name: "bravo"}}, + } + + sorting.ByNamespacedName[corev1alpha1.TenantModule, *corev1alpha1.TenantModule](items) + + expected := []struct{ ns, name string }{ + {"ns-a", "alpha"}, + {"ns-a", "bravo"}, + {"ns-b", "alpha"}, + {"ns-b", "zebra"}, + } + + for i, exp := range expected { + if items[i].Namespace != exp.ns || items[i].Name != exp.name { + t.Errorf("item %d: expected %s/%s, got %s/%s", i, exp.ns, exp.name, items[i].Namespace, items[i].Name) + } + } +} diff --git a/pkg/registry/core/tenantnamespace/rest.go b/pkg/registry/core/tenantnamespace/rest.go new file mode 100644 index 00000000..4ee97eb0 --- /dev/null +++ b/pkg/registry/core/tenantnamespace/rest.go @@ -0,0 +1,515 @@ +// SPDX-License-Identifier: Apache-2.0 +// TenantNamespace registry: read-only view over Namespaces whose names start +// with “tenant-”. + +package tenantnamespace + +import ( + "context" + "fmt" + "net/http" + "strconv" + "strings" + "time" + + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metainternal "k8s.io/apimachinery/pkg/apis/meta/internalversion" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/duration" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" + + corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + "github.com/cozystack/cozystack/pkg/registry" + "github.com/cozystack/cozystack/pkg/registry/sorting" +) + +const ( + prefix = "tenant-" + singularName = "tenantnamespace" +) + +// ----------------------------------------------------------------------------- +// REST storage +// ----------------------------------------------------------------------------- + +var ( + _ rest.Lister = &REST{} + _ rest.Getter = &REST{} + _ rest.Watcher = &REST{} + _ rest.TableConvertor = &REST{} + _ rest.Scoper = &REST{} + _ rest.SingularNameProvider = &REST{} +) + +type REST struct { + c client.Client + w client.WithWatch + gvr schema.GroupVersionResource +} + +func NewREST( + c client.Client, + w client.WithWatch, +) *REST { + return &REST{ + c: c, + w: w, + gvr: schema.GroupVersionResource{ + Group: corev1alpha1.GroupName, + Version: "v1alpha1", + Resource: "tenantnamespaces", + }, + } +} + +// ----------------------------------------------------------------------------- +// Basic meta +// ----------------------------------------------------------------------------- + +func (*REST) NamespaceScoped() bool { return false } +func (*REST) New() runtime.Object { return &corev1alpha1.TenantNamespace{} } +func (*REST) NewList() runtime.Object { + return &corev1alpha1.TenantNamespaceList{} +} +func (*REST) Kind() string { return "TenantNamespace" } +func (r *REST) GroupVersionKind(_ schema.GroupVersion) schema.GroupVersionKind { + return r.gvr.GroupVersion().WithKind("TenantNamespace") +} +func (*REST) GetSingularName() string { return singularName } + +// ----------------------------------------------------------------------------- +// Lister / Getter +// ----------------------------------------------------------------------------- + +func (r *REST) List( + ctx context.Context, + _ *metainternal.ListOptions, +) (runtime.Object, error) { + nsList := &corev1.NamespaceList{} + err := r.c.List(ctx, nsList) + if err != nil { + return nil, err + } + + var tenantNames []string + for i := range nsList.Items { + if strings.HasPrefix(nsList.Items[i].Name, prefix) { + tenantNames = append(tenantNames, nsList.Items[i].Name) + } + } + + allowed, err := r.filterAccessible(ctx, tenantNames) + if err != nil { + return nil, err + } + + return r.makeList(nsList, allowed), nil +} + +func (r *REST) Get( + ctx context.Context, + name string, + opts *metav1.GetOptions, +) (runtime.Object, error) { + if !strings.HasPrefix(name, prefix) { + return nil, apierrors.NewNotFound(r.gvr.GroupResource(), name) + } + + // Check if user has access to this namespace + hasAccess, err := r.hasAccessToNamespace(ctx, name) + if err != nil { + return nil, err + } + if !hasAccess { + // Return Forbidden to follow standard K8s RBAC behavior + return nil, apierrors.NewForbidden(r.gvr.GroupResource(), name, fmt.Errorf("access denied")) + } + + ns := &corev1.Namespace{} + err = r.c.Get(ctx, types.NamespacedName{Namespace: "", Name: name}, ns, &client.GetOptions{Raw: opts}) + if err != nil { + return nil, err + } + + return &corev1alpha1.TenantNamespace{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: "TenantNamespace", + }, + ObjectMeta: ns.ObjectMeta, + }, nil +} + +// ----------------------------------------------------------------------------- +// Watcher +// ----------------------------------------------------------------------------- + +func (r *REST) Watch(ctx context.Context, opts *metainternal.ListOptions) (watch.Interface, error) { + // Extract user identity once for the lifetime of the watch — it does not + // change between events and rebuilding it per event is wasteful. + u, ok := request.UserFrom(ctx) + if !ok { + return nil, apierrors.NewUnauthorized("user missing in context") + } + username := u.GetName() + groups := make(map[string]struct{}) + for _, group := range u.GetGroups() { + groups[group] = struct{}{} + } + + nsList := &corev1.NamespaceList{} + + // Build upstream watch options with field and label selectors + rawOpts := &metav1.ListOptions{ + Watch: true, + ResourceVersion: opts.ResourceVersion, + } + if opts.FieldSelector != nil { + rawOpts.FieldSelector = opts.FieldSelector.String() + } + if opts.LabelSelector != nil { + rawOpts.LabelSelector = opts.LabelSelector.String() + } + + nsWatch, err := r.w.Watch(ctx, nsList, &client.ListOptions{Raw: rawOpts}) + if err != nil { + return nil, err + } + + // Get starting resourceVersion from options + var startingRV uint64 + if opts.ResourceVersion != "" { + if rv, err := strconv.ParseUint(opts.ResourceVersion, 10, 64); err == nil { + startingRV = rv + } + } + + events := make(chan watch.Event) + pw := watch.NewProxyWatcher(events) + + go func() { + defer pw.Stop() + + for ev := range nsWatch.ResultChan() { + // Handle bookmark events + if ev.Type == watch.Bookmark { + if ns, ok := ev.Object.(*corev1.Namespace); ok { + out := &corev1alpha1.TenantNamespace{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: "TenantNamespace", + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: ns.ResourceVersion, + }, + } + events <- watch.Event{Type: watch.Bookmark, Object: out} + } + continue + } + + ns, ok := ev.Object.(*corev1.Namespace) + if !ok || !strings.HasPrefix(ns.Name, prefix) { + continue + } + + // Apply defensive filtering for field and label selectors + if opts.FieldSelector != nil { + if !opts.FieldSelector.Matches(fields.Set{"metadata.name": ns.Name}) { + continue + } + } + if opts.LabelSelector != nil { + if !opts.LabelSelector.Matches(labels.Set(ns.Labels)) { + continue + } + } + + // Check if user has access to this namespace using the cached + // identity — avoids re-extracting user/groups on every event. + hasAccess, err := r.hasAccessToNamespaceForUser(ctx, ns.Name, username, groups) + if err != nil { + klog.ErrorS(err, "Failed to check access for namespace in watch", "namespace", ns.Name) + continue + } + if !hasAccess { + // User doesn't have access, skip this event + continue + } + + out := &corev1alpha1.TenantNamespace{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: "TenantNamespace", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: ns.Name, + UID: ns.UID, + ResourceVersion: ns.ResourceVersion, + CreationTimestamp: ns.CreationTimestamp, + Labels: ns.Labels, + Annotations: ns.Annotations, + }, + } + + // Skip ADDED events based on resourceVersion comparison + // Only skip when client provided resourceVersion (they already have objects from List) + if ev.Type == watch.Added && startingRV > 0 { + objRV, parseErr := strconv.ParseUint(out.ResourceVersion, 10, 64) + // Skip objects client already has (objRV <= startingRV) + if parseErr == nil && objRV <= startingRV { + continue + } + } + // When startingRV == 0, always send ADDED events (client wants full state) + + events <- watch.Event{Type: ev.Type, Object: out} + } + }() + + return pw, nil +} + +// ----------------------------------------------------------------------------- +// TableConvertor +// ----------------------------------------------------------------------------- + +func (r *REST) ConvertToTable(_ context.Context, obj runtime.Object, _ runtime.Object) (*metav1.Table, error) { + now := time.Now() + row := func(o *corev1alpha1.TenantNamespace) metav1.TableRow { + return metav1.TableRow{ + Cells: []interface{}{o.Name, duration.HumanDuration(now.Sub(o.CreationTimestamp.Time))}, + Object: runtime.RawExtension{Object: o}, + } + } + + tbl := &metav1.Table{ + TypeMeta: metav1.TypeMeta{APIVersion: "meta.k8s.io/v1", Kind: "Table"}, + ColumnDefinitions: []metav1.TableColumnDefinition{ + {Name: "NAME", Type: "string"}, + {Name: "AGE", Type: "string"}, + }, + } + + switch v := obj.(type) { + case *corev1alpha1.TenantNamespaceList: + for i := range v.Items { + tbl.Rows = append(tbl.Rows, row(&v.Items[i])) + } + tbl.ResourceVersion = v.ResourceVersion + case *corev1alpha1.TenantNamespace: + tbl.Rows = append(tbl.Rows, row(v)) + tbl.ResourceVersion = v.ResourceVersion + default: + return nil, notAcceptable{r.gvr.GroupResource(), fmt.Sprintf("unexpected %T", obj)} + } + return tbl, nil +} + +// ----------------------------------------------------------------------------- +// Helpers +// ----------------------------------------------------------------------------- + +func (r *REST) makeList(src *corev1.NamespaceList, allowed []string) *corev1alpha1.TenantNamespaceList { + set := map[string]struct{}{} + for _, n := range allowed { + set[n] = struct{}{} + } + + // Get ResourceVersion from list or compute from items + // controller-runtime cached client may not set ResourceVersion on the list itself + listRV := src.ResourceVersion + if listRV == "" { + listRV, _ = registry.MaxResourceVersion(src) + } + + out := &corev1alpha1.TenantNamespaceList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: "TenantNamespaceList", + }, + ListMeta: metav1.ListMeta{ResourceVersion: listRV}, + } + + for i := range src.Items { + ns := &src.Items[i] + if _, ok := set[ns.Name]; !ok { + continue + } + out.Items = append(out.Items, corev1alpha1.TenantNamespace{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: "TenantNamespace", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: ns.Name, + UID: ns.UID, + ResourceVersion: ns.ResourceVersion, + CreationTimestamp: ns.CreationTimestamp, + Labels: ns.Labels, + Annotations: ns.Annotations, + }, + }) + } + + sorting.ByName[corev1alpha1.TenantNamespace, *corev1alpha1.TenantNamespace](out.Items) + + return out +} + +// matchesSubject checks if a RoleBinding subject matches the user's identity. +// It handles Group, User, and ServiceAccount subjects with proper namespace fallback. +func matchesSubject(subj rbacv1.Subject, bindingNamespace, username string, groups map[string]struct{}) bool { + switch subj.Kind { + case "Group": + _, ok := groups[subj.Name] + return ok + case "User": + return subj.Name == username + case "ServiceAccount": + saNamespace := subj.Namespace + if saNamespace == "" { + saNamespace = bindingNamespace + } + return username == fmt.Sprintf("system:serviceaccount:%s:%s", saNamespace, subj.Name) + default: + return false + } +} + +func (r *REST) filterAccessible( + ctx context.Context, + names []string, +) ([]string, error) { + u, ok := request.UserFrom(ctx) + if !ok { + return []string{}, fmt.Errorf("user missing in context") + } + groups := make(map[string]struct{}) + for _, group := range u.GetGroups() { + groups[group] = struct{}{} + } + if _, ok = groups["system:masters"]; ok { + return names, nil + } + if _, ok = groups["cozystack-cluster-admin"]; ok { + return names, nil + } + nameSet := make(map[string]struct{}) + for _, name := range names { + nameSet[name] = struct{}{} + } + rbs := &rbacv1.RoleBindingList{} + err := r.c.List(ctx, rbs) + if err != nil { + return []string{}, fmt.Errorf("failed to list rolebindings: %w", err) + } + allowedNameSet := make(map[string]struct{}) + for i := range rbs.Items { + if _, ok := allowedNameSet[rbs.Items[i].Namespace]; ok { + continue + } + if _, ok := nameSet[rbs.Items[i].Namespace]; !ok { + continue + } + subjectLoop: + for j := range rbs.Items[i].Subjects { + subj := rbs.Items[i].Subjects[j] + if matchesSubject(subj, rbs.Items[i].Namespace, u.GetName(), groups) { + allowedNameSet[rbs.Items[i].Namespace] = struct{}{} + break subjectLoop + } + } + } + allowed := make([]string, 0, len(allowedNameSet)) + for name := range allowedNameSet { + allowed = append(allowed, name) + } + return allowed, nil +} + +// hasAccessToNamespace checks if the user has access to a single namespace. +// This is optimized for Get/Watch operations where we check one namespace at a time. +// It lists RoleBindings only in the target namespace instead of all cluster RoleBindings. +func (r *REST) hasAccessToNamespace( + ctx context.Context, + namespace string, +) (bool, error) { + u, ok := request.UserFrom(ctx) + if !ok { + return false, fmt.Errorf("user missing in context") + } + groups := make(map[string]struct{}) + for _, group := range u.GetGroups() { + groups[group] = struct{}{} + } + return r.hasAccessToNamespaceForUser(ctx, namespace, u.GetName(), groups) +} + +// hasAccessToNamespaceForUser is the inner check that does not re-extract user +// identity from context. Use this in hot paths (e.g. the Watch loop) where the +// caller has already cached the user name and groups. +func (r *REST) hasAccessToNamespaceForUser( + ctx context.Context, + namespace, username string, + groups map[string]struct{}, +) (bool, error) { + // Check privileged groups + if _, ok := groups["system:masters"]; ok { + return true, nil + } + if _, ok := groups["cozystack-cluster-admin"]; ok { + return true, nil + } + + // List RoleBindings only in the target namespace + rbs := &rbacv1.RoleBindingList{} + err := r.c.List(ctx, rbs, client.InNamespace(namespace)) + if err != nil { + return false, fmt.Errorf("failed to list rolebindings in %s: %w", namespace, err) + } + + // Check if user is in any RoleBinding subjects + for i := range rbs.Items { + for j := range rbs.Items[i].Subjects { + subj := rbs.Items[i].Subjects[j] + if matchesSubject(subj, rbs.Items[i].Namespace, username, groups) { + return true, nil + } + } + } + + return false, nil +} + +// ----------------------------------------------------------------------------- +// Boiler-plate +// ----------------------------------------------------------------------------- + +func (*REST) Destroy() {} + +type notAcceptable struct { + resource schema.GroupResource + message string +} + +func (e notAcceptable) Error() string { return e.message } +func (e notAcceptable) Status() metav1.Status { + return metav1.Status{ + Status: metav1.StatusFailure, + Code: http.StatusNotAcceptable, + Reason: metav1.StatusReason("NotAcceptable"), + Message: e.message, + } +} diff --git a/pkg/registry/core/tenantnamespace/rest_test.go b/pkg/registry/core/tenantnamespace/rest_test.go new file mode 100644 index 00000000..52d2a075 --- /dev/null +++ b/pkg/registry/core/tenantnamespace/rest_test.go @@ -0,0 +1,513 @@ +// SPDX-License-Identifier: Apache-2.0 + +package tenantnamespace + +import ( + "context" + "testing" + + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/authentication/user" + "k8s.io/apiserver/pkg/endpoints/request" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" +) + +func TestMakeListSortsAlphabetically(t *testing.T) { + r := &REST{} + + // Create namespaces in non-alphabetical order + src := &corev1.NamespaceList{ + Items: []corev1.Namespace{ + {ObjectMeta: metav1.ObjectMeta{Name: "tenant-zebra"}}, + {ObjectMeta: metav1.ObjectMeta{Name: "tenant-alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Name: "tenant-mike"}}, + {ObjectMeta: metav1.ObjectMeta{Name: "tenant-bravo"}}, + }, + } + + allowed := []string{"tenant-zebra", "tenant-alpha", "tenant-mike", "tenant-bravo"} + + result := r.makeList(src, allowed) + + expected := []string{"tenant-alpha", "tenant-bravo", "tenant-mike", "tenant-zebra"} + + if len(result.Items) != len(expected) { + t.Fatalf("expected %d items, got %d", len(expected), len(result.Items)) + } + + for i, name := range expected { + if result.Items[i].Name != name { + t.Errorf("item %d: expected %q, got %q", i, name, result.Items[i].Name) + } + } +} + +// Security tests for IDOR fix + +func TestHasAccessToNamespace_WithUserAccess(t *testing.T) { + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = rbacv1.AddToScheme(scheme) + + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: "tenant-test"}, + } + + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "tenant-test", + }, + Subjects: []rbacv1.Subject{ + {Kind: "User", Name: "test-user", APIGroup: "rbac.authorization.k8s.io"}, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "test-role", + }, + } + + client := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(ns, rb). + Build() + + r := &REST{ + c: client, + gvr: schema.GroupVersionResource{Group: "core.cozystack.io", Version: "v1alpha1", Resource: "tenantnamespaces"}, + } + + u := &user.DefaultInfo{ + Name: "test-user", + Groups: []string{"system:authenticated"}, + } + ctx := request.WithUser(context.Background(), u) + + hasAccess, err := r.hasAccessToNamespace(ctx, "tenant-test") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !hasAccess { + t.Error("expected user to have access, but got false") + } +} + +func TestHasAccessToNamespace_WithoutAccess(t *testing.T) { + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = rbacv1.AddToScheme(scheme) + + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: "tenant-test"}, + } + + // RoleBinding for different user + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "tenant-test", + }, + Subjects: []rbacv1.Subject{ + {Kind: "User", Name: "other-user", APIGroup: "rbac.authorization.k8s.io"}, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "test-role", + }, + } + + client := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(ns, rb). + Build() + + r := &REST{ + c: client, + gvr: schema.GroupVersionResource{Group: "core.cozystack.io", Version: "v1alpha1", Resource: "tenantnamespaces"}, + } + + u := &user.DefaultInfo{ + Name: "test-user", + Groups: []string{"system:authenticated"}, + } + ctx := request.WithUser(context.Background(), u) + + hasAccess, err := r.hasAccessToNamespace(ctx, "tenant-test") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if hasAccess { + t.Error("expected user to NOT have access, but got true") + } +} + +func TestHasAccessToNamespace_WithGroupAccess(t *testing.T) { + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = rbacv1.AddToScheme(scheme) + + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: "tenant-test"}, + } + + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "tenant-test", + }, + Subjects: []rbacv1.Subject{ + {Kind: "Group", Name: "test-group", APIGroup: "rbac.authorization.k8s.io"}, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "test-role", + }, + } + + client := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(ns, rb). + Build() + + r := &REST{ + c: client, + gvr: schema.GroupVersionResource{Group: "core.cozystack.io", Version: "v1alpha1", Resource: "tenantnamespaces"}, + } + + u := &user.DefaultInfo{ + Name: "test-user", + Groups: []string{"system:authenticated", "test-group"}, + } + ctx := request.WithUser(context.Background(), u) + + hasAccess, err := r.hasAccessToNamespace(ctx, "tenant-test") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !hasAccess { + t.Error("expected user to have access via group, but got false") + } +} + +func TestHasAccessToNamespace_SystemMasters(t *testing.T) { + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = rbacv1.AddToScheme(scheme) + + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: "tenant-test"}, + } + + client := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(ns). + Build() + + r := &REST{ + c: client, + gvr: schema.GroupVersionResource{Group: "core.cozystack.io", Version: "v1alpha1", Resource: "tenantnamespaces"}, + } + + u := &user.DefaultInfo{ + Name: "admin", + Groups: []string{"system:masters"}, + } + ctx := request.WithUser(context.Background(), u) + + hasAccess, err := r.hasAccessToNamespace(ctx, "tenant-test") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !hasAccess { + t.Error("expected system:masters to have access, but got false") + } +} + +func TestHasAccessToNamespace_CozyAdminGroup(t *testing.T) { + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = rbacv1.AddToScheme(scheme) + + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: "tenant-test"}, + } + + client := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(ns). + Build() + + r := &REST{ + c: client, + gvr: schema.GroupVersionResource{Group: "core.cozystack.io", Version: "v1alpha1", Resource: "tenantnamespaces"}, + } + + u := &user.DefaultInfo{ + Name: "cozy-admin", + Groups: []string{"cozystack-cluster-admin"}, + } + ctx := request.WithUser(context.Background(), u) + + hasAccess, err := r.hasAccessToNamespace(ctx, "tenant-test") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !hasAccess { + t.Error("expected cozystack-cluster-admin to have access, but got false") + } +} + +func TestHasAccessToNamespace_ServiceAccount(t *testing.T) { + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = rbacv1.AddToScheme(scheme) + + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: "tenant-test"}, + } + + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "tenant-test", + }, + Subjects: []rbacv1.Subject{ + {Kind: "ServiceAccount", Name: "test-sa", Namespace: "tenant-test"}, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "test-role", + }, + } + + client := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(ns, rb). + Build() + + r := &REST{ + c: client, + gvr: schema.GroupVersionResource{Group: "core.cozystack.io", Version: "v1alpha1", Resource: "tenantnamespaces"}, + } + + u := &user.DefaultInfo{ + Name: "system:serviceaccount:tenant-test:test-sa", + Groups: []string{"system:authenticated"}, + } + ctx := request.WithUser(context.Background(), u) + + hasAccess, err := r.hasAccessToNamespace(ctx, "tenant-test") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !hasAccess { + t.Error("expected service account to have access, but got false") + } +} + +func TestHasAccessToNamespace_ServiceAccountEmptyNamespace(t *testing.T) { + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = rbacv1.AddToScheme(scheme) + + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: "tenant-test"}, + } + + // ServiceAccount subject with empty namespace should default to RoleBinding namespace + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "tenant-test", + }, + Subjects: []rbacv1.Subject{ + {Kind: "ServiceAccount", Name: "test-sa", Namespace: ""}, // Empty namespace + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "test-role", + }, + } + + client := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(ns, rb). + Build() + + r := &REST{ + c: client, + gvr: schema.GroupVersionResource{Group: "core.cozystack.io", Version: "v1alpha1", Resource: "tenantnamespaces"}, + } + + u := &user.DefaultInfo{ + Name: "system:serviceaccount:tenant-test:test-sa", + Groups: []string{"system:authenticated"}, + } + ctx := request.WithUser(context.Background(), u) + + hasAccess, err := r.hasAccessToNamespace(ctx, "tenant-test") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if !hasAccess { + t.Error("expected service account with empty namespace to have access, but got false") + } +} + +func TestGet_WithAccess(t *testing.T) { + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = rbacv1.AddToScheme(scheme) + + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: "tenant-test"}, + } + + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "tenant-test", + }, + Subjects: []rbacv1.Subject{ + {Kind: "User", Name: "test-user", APIGroup: "rbac.authorization.k8s.io"}, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "test-role", + }, + } + + client := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(ns, rb). + Build() + + r := &REST{ + c: client, + gvr: schema.GroupVersionResource{Group: "core.cozystack.io", Version: "v1alpha1", Resource: "tenantnamespaces"}, + } + + u := &user.DefaultInfo{ + Name: "test-user", + Groups: []string{"system:authenticated"}, + } + ctx := request.WithUser(context.Background(), u) + + obj, err := r.Get(ctx, "tenant-test", &metav1.GetOptions{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + tn, ok := obj.(*corev1alpha1.TenantNamespace) + if !ok { + t.Fatalf("expected *TenantNamespace, got %T", obj) + } + if tn.Name != "tenant-test" { + t.Errorf("expected name %q, got %q", "tenant-test", tn.Name) + } + if tn.Kind != "TenantNamespace" { + t.Errorf("expected Kind=TenantNamespace, got %q", tn.Kind) + } + if tn.APIVersion != corev1alpha1.SchemeGroupVersion.String() { + t.Errorf("expected APIVersion=%q, got %q", corev1alpha1.SchemeGroupVersion.String(), tn.APIVersion) + } +} + +func TestGet_WithoutAccess(t *testing.T) { + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = rbacv1.AddToScheme(scheme) + + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: "tenant-test"}, + } + + // RoleBinding for different user + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-binding", + Namespace: "tenant-test", + }, + Subjects: []rbacv1.Subject{ + {Kind: "User", Name: "other-user", APIGroup: "rbac.authorization.k8s.io"}, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "test-role", + }, + } + + client := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(ns, rb). + Build() + + r := &REST{ + c: client, + gvr: schema.GroupVersionResource{Group: "core.cozystack.io", Version: "v1alpha1", Resource: "tenantnamespaces"}, + } + + u := &user.DefaultInfo{ + Name: "test-user", + Groups: []string{"system:authenticated"}, + } + ctx := request.WithUser(context.Background(), u) + + obj, err := r.Get(ctx, "tenant-test", &metav1.GetOptions{}) + if err == nil { + t.Fatal("expected error, got nil") + } + if obj != nil { + t.Errorf("expected nil object, got %v", obj) + } + + // Verify it returns Forbidden to follow standard K8s RBAC behavior + if !apierrors.IsForbidden(err) { + t.Errorf("expected Forbidden error, got %v", err) + } +} + +func TestGet_NonTenantNamespace(t *testing.T) { + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + _ = rbacv1.AddToScheme(scheme) + + client := fake.NewClientBuilder(). + WithScheme(scheme). + Build() + + r := &REST{ + c: client, + gvr: schema.GroupVersionResource{Group: "core.cozystack.io", Version: "v1alpha1", Resource: "tenantnamespaces"}, + } + + u := &user.DefaultInfo{ + Name: "test-user", + Groups: []string{"system:masters"}, + } + ctx := request.WithUser(context.Background(), u) + + obj, err := r.Get(ctx, "default", &metav1.GetOptions{}) + if err == nil { + t.Fatal("expected error for non-tenant namespace, got nil") + } + if obj != nil { + t.Errorf("expected nil object, got %v", obj) + } + if !apierrors.IsNotFound(err) { + t.Errorf("expected NotFound error, got %v", err) + } +} diff --git a/pkg/registry/core/tenantsecret/rest.go b/pkg/registry/core/tenantsecret/rest.go new file mode 100644 index 00000000..1f95c397 --- /dev/null +++ b/pkg/registry/core/tenantsecret/rest.go @@ -0,0 +1,569 @@ +// SPDX-License-Identifier: Apache-2.0 +// TenantSecret registry – namespaced view over Secrets labelled +// "internal.cozystack.io/tenantresource=true". Internal tenant secret labels are hidden. + +package tenantsecret + +import ( + "context" + "encoding/base64" + "fmt" + "net/http" + "strconv" + "time" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metainternal "k8s.io/apimachinery/pkg/apis/meta/internalversion" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/duration" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + + corev1alpha1 "github.com/cozystack/cozystack/pkg/apis/core/v1alpha1" + "github.com/cozystack/cozystack/pkg/registry" + fieldfilter "github.com/cozystack/cozystack/pkg/registry/fields" + "github.com/cozystack/cozystack/pkg/registry/sorting" +) + +// ----------------------------------------------------------------------------- +// Constants & helpers +// ----------------------------------------------------------------------------- + +const ( + tsLabelKey = corev1alpha1.TenantResourceLabelKey + tsLabelValue = corev1alpha1.TenantResourceLabelValue + singularName = "tenantsecret" + kindTenantSecret = "TenantSecret" + kindTenantSecretList = "TenantSecretList" +) + +func stripInternal(m map[string]string) map[string]string { + if m == nil { + return nil + } + out := make(map[string]string, len(m)) + for k, v := range m { + if k == tsLabelKey { + continue + } + out[k] = v + } + return out +} + +func encodeStringData(sd map[string]string) map[string][]byte { + if len(sd) == 0 { + return nil + } + out := make(map[string][]byte, len(sd)) + for k, v := range sd { + out[k] = []byte(v) + } + return out +} + +func decodeStringData(d map[string][]byte) map[string]string { + if len(d) == 0 { + return nil + } + out := make(map[string]string, len(d)) + for k, v := range d { + out[k] = base64.StdEncoding.EncodeToString(v) + } + return out +} + +func secretToTenant(sec *corev1.Secret) *corev1alpha1.TenantSecret { + return &corev1alpha1.TenantSecret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: kindTenantSecret, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: sec.Name, + Namespace: sec.Namespace, + UID: sec.UID, + ResourceVersion: sec.ResourceVersion, + CreationTimestamp: sec.CreationTimestamp, + Labels: stripInternal(sec.Labels), + Annotations: sec.Annotations, + }, + Type: string(sec.Type), + Data: sec.Data, + StringData: decodeStringData(sec.Data), + } +} + +func tenantToSecret(ts *corev1alpha1.TenantSecret, cur *corev1.Secret) *corev1.Secret { + var out corev1.Secret + if cur != nil { + out = *cur.DeepCopy() + } + out.TypeMeta = metav1.TypeMeta{APIVersion: "v1", Kind: "Secret"} + out.Name, out.Namespace = ts.Name, ts.Namespace + + if out.Labels == nil { + out.Labels = map[string]string{} + } + out.Labels[tsLabelKey] = tsLabelValue + for k, v := range ts.Labels { + out.Labels[k] = v + } + + if out.Annotations == nil { + out.Annotations = map[string]string{} + } + for k, v := range ts.Annotations { + out.Annotations[k] = v + } + + if len(ts.Data) != 0 { + out.Data = ts.Data + } else if len(ts.StringData) != 0 { + out.Data = encodeStringData(ts.StringData) + } + out.Type = corev1.SecretType(ts.Type) + return &out +} + +func nsFrom(ctx context.Context) (string, error) { + ns, ok := request.NamespaceFrom(ctx) + if !ok { + return "", apierrors.NewBadRequest("namespace required") + } + return ns, nil +} + +// ----------------------------------------------------------------------------- +// REST storage +// ----------------------------------------------------------------------------- + +var ( + _ rest.Creater = &REST{} + _ rest.Getter = &REST{} + _ rest.Lister = &REST{} + _ rest.Updater = &REST{} + _ rest.Patcher = &REST{} + _ rest.GracefulDeleter = &REST{} + _ rest.Watcher = &REST{} + _ rest.TableConvertor = &REST{} + _ rest.Scoper = &REST{} + _ rest.SingularNameProvider = &REST{} +) + +type REST struct { + c client.Client + w client.WithWatch + gvr schema.GroupVersionResource +} + +func NewREST(c client.Client, w client.WithWatch) *REST { + return &REST{ + c: c, + w: w, + gvr: schema.GroupVersionResource{ + Group: corev1alpha1.GroupName, + Version: "v1alpha1", + Resource: "tenantsecrets", + }, + } +} + +// ----------------------------------------------------------------------------- +// Basic meta +// ----------------------------------------------------------------------------- + +func (*REST) NamespaceScoped() bool { return true } +func (*REST) New() runtime.Object { return &corev1alpha1.TenantSecret{} } +func (*REST) NewList() runtime.Object { + return &corev1alpha1.TenantSecretList{} +} +func (*REST) Kind() string { return kindTenantSecret } +func (r *REST) GroupVersionKind(_ schema.GroupVersion) schema.GroupVersionKind { + return r.gvr.GroupVersion().WithKind(kindTenantSecret) +} +func (*REST) GetSingularName() string { return singularName } + +// ----------------------------------------------------------------------------- +// CRUD +// ----------------------------------------------------------------------------- + +func (r *REST) Create( + ctx context.Context, + obj runtime.Object, + _ rest.ValidateObjectFunc, + opts *metav1.CreateOptions, +) (runtime.Object, error) { + in, ok := obj.(*corev1alpha1.TenantSecret) + if !ok { + return nil, fmt.Errorf("expected TenantSecret, got %T", obj) + } + + sec := tenantToSecret(in, nil) + err := r.c.Create(ctx, sec, &client.CreateOptions{Raw: opts}) + if err != nil { + return nil, err + } + return secretToTenant(sec), nil +} + +func (r *REST) Get( + ctx context.Context, + name string, + opts *metav1.GetOptions, +) (runtime.Object, error) { + ns, err := nsFrom(ctx) + if err != nil { + return nil, err + } + sec := &corev1.Secret{} + err = r.c.Get(ctx, types.NamespacedName{Namespace: ns, Name: name}, sec, &client.GetOptions{Raw: opts}) + if err != nil { + return nil, err + } + if sec.Labels == nil || sec.Labels[tsLabelKey] != tsLabelValue { + return nil, apierrors.NewNotFound(r.gvr.GroupResource(), name) + } + return secretToTenant(sec), nil +} + +func (r *REST) List(ctx context.Context, opts *metainternal.ListOptions) (runtime.Object, error) { + ns, err := nsFrom(ctx) + if err != nil { + return nil, err + } + + ls := labels.NewSelector() + req, _ := labels.NewRequirement(tsLabelKey, selection.Equals, []string{tsLabelValue}) + ls = ls.Add(*req) + + if opts.LabelSelector != nil { + if reqs, _ := opts.LabelSelector.Requirements(); len(reqs) > 0 { + ls = ls.Add(reqs...) + } + } + + // Parse field selector for manual filtering + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + fieldFilter, err := fieldfilter.ParseFieldSelector(opts.FieldSelector) + if err != nil { + return nil, err + } + + // If field selector specifies namespace different from context, return empty list + if fieldFilter.Namespace != "" && ns != "" && ns != fieldFilter.Namespace { + return &corev1alpha1.TenantSecretList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: kindTenantSecretList, + }, + }, nil + } + + list := &corev1.SecretList{} + err = r.c.List(ctx, list, + &client.ListOptions{ + Namespace: ns, + LabelSelector: ls, + }) + if err != nil { + return nil, err + } + + // Get ResourceVersion from list or compute from items + // controller-runtime cached client may not set ResourceVersion on the list itself + listRV := list.ResourceVersion + if listRV == "" { + listRV, _ = registry.MaxResourceVersion(list) + } + + out := &corev1alpha1.TenantSecretList{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: kindTenantSecretList, + }, + ListMeta: metav1.ListMeta{ResourceVersion: listRV}, + } + + for i := range list.Items { + // Apply manual field selector filtering (metadata.name and metadata.namespace) + // controller-runtime cache doesn't support field selectors + // See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + if !fieldFilter.MatchesName(list.Items[i].Name) { + continue + } + if !fieldFilter.MatchesNamespace(list.Items[i].Namespace) { + continue + } + out.Items = append(out.Items, *secretToTenant(&list.Items[i])) + } + sorting.ByNamespacedName[corev1alpha1.TenantSecret, *corev1alpha1.TenantSecret](out.Items) + return out, nil +} + +func (r *REST) Update( + ctx context.Context, + name string, + objInfo rest.UpdatedObjectInfo, + _ rest.ValidateObjectFunc, + _ rest.ValidateObjectUpdateFunc, + forceCreate bool, + opts *metav1.UpdateOptions, +) (runtime.Object, bool, error) { + ns, err := nsFrom(ctx) + if err != nil { + return nil, false, err + } + + var cur *corev1.Secret + previous := &corev1.Secret{} + if err := r.c.Get(ctx, types.NamespacedName{Namespace: ns, Name: name}, previous, &client.GetOptions{Raw: &metav1.GetOptions{}}); err != nil { + if !apierrors.IsNotFound(err) { + return nil, false, err + } + } else { + if previous.Labels == nil || previous.Labels[tsLabelKey] != tsLabelValue { + return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) + } + cur = previous + } + + newObj, err := objInfo.UpdatedObject(ctx, nil) + if err != nil { + return nil, false, err + } + in := newObj.(*corev1alpha1.TenantSecret) + + newSec := tenantToSecret(in, cur) + newSec.Namespace = ns + if cur == nil { + if !forceCreate { + return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) + } + err := r.c.Create(ctx, newSec, &client.CreateOptions{Raw: &metav1.CreateOptions{}}) + return secretToTenant(newSec), true, err + } + + newSec.ResourceVersion = cur.ResourceVersion + err = r.c.Update(ctx, newSec, &client.UpdateOptions{Raw: opts}) + return secretToTenant(newSec), false, err +} + +func (r *REST) Delete( + ctx context.Context, + name string, + _ rest.ValidateObjectFunc, + opts *metav1.DeleteOptions, +) (runtime.Object, bool, error) { + ns, err := nsFrom(ctx) + if err != nil { + return nil, false, err + } + current := &corev1.Secret{} + if err := r.c.Get(ctx, types.NamespacedName{Namespace: ns, Name: name}, current, &client.GetOptions{Raw: &metav1.GetOptions{}}); err != nil { + return nil, false, err + } + if current.Labels == nil || current.Labels[tsLabelKey] != tsLabelValue { + return nil, false, apierrors.NewNotFound(r.gvr.GroupResource(), name) + } + err = r.c.Delete(ctx, &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Namespace: ns, Name: name}}, &client.DeleteOptions{Raw: opts}) + return nil, err == nil, err +} + +func (r *REST) Patch( + ctx context.Context, + name string, + pt types.PatchType, + data []byte, + opts *metav1.PatchOptions, + subresources ...string, +) (runtime.Object, error) { + if len(subresources) > 0 { + return nil, fmt.Errorf("TenantSecret does not have subresources") + } + ns, err := nsFrom(ctx) + if err != nil { + return nil, err + } + current := &corev1.Secret{} + if err := r.c.Get(ctx, types.NamespacedName{Namespace: ns, Name: name}, current, &client.GetOptions{Raw: &metav1.GetOptions{}}); err != nil { + return nil, err + } + if current.Labels == nil || current.Labels[tsLabelKey] != tsLabelValue { + return nil, apierrors.NewNotFound(r.gvr.GroupResource(), name) + } + out := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + Name: name, + }, + } + patch := client.RawPatch(pt, data) + err = r.c.Patch(ctx, out, patch, &client.PatchOptions{Raw: opts}) + if err != nil { + return nil, err + } + + // Ensure tenant secret label is preserved + if out.Labels == nil { + out.Labels = make(map[string]string) + } + + if out.Labels[tsLabelKey] != tsLabelValue { + out.Labels[tsLabelKey] = tsLabelValue + _ = r.c.Update(ctx, out, &client.UpdateOptions{Raw: &metav1.UpdateOptions{}}) + } + + return secretToTenant(out), nil +} + +// ----------------------------------------------------------------------------- +// Watcher +// ----------------------------------------------------------------------------- + +func (r *REST) Watch(ctx context.Context, opts *metainternal.ListOptions) (watch.Interface, error) { + ns, err := nsFrom(ctx) + if err != nil { + return nil, err + } + + secList := &corev1.SecretList{} + ls := labels.Set{tsLabelKey: tsLabelValue}.AsSelector() + base, err := r.w.Watch(ctx, secList, &client.ListOptions{ + Namespace: ns, + LabelSelector: ls, + Raw: &metav1.ListOptions{ + Watch: true, + ResourceVersion: opts.ResourceVersion, + }, + }) + if err != nil { + return nil, err + } + + // Get starting resourceVersion from options + var startingRV uint64 + if opts.ResourceVersion != "" { + if rv, err := strconv.ParseUint(opts.ResourceVersion, 10, 64); err == nil { + startingRV = rv + } + } + + ch := make(chan watch.Event) + proxy := watch.NewProxyWatcher(ch) + + go func() { + defer proxy.Stop() + + for ev := range base.ResultChan() { + // Handle bookmark events + if ev.Type == watch.Bookmark { + if sec, ok := ev.Object.(*corev1.Secret); ok { + out := &corev1alpha1.TenantSecret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1alpha1.SchemeGroupVersion.String(), + Kind: kindTenantSecret, + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: sec.ResourceVersion, + }, + } + ch <- watch.Event{Type: watch.Bookmark, Object: out} + } + continue + } + + sec, ok := ev.Object.(*corev1.Secret) + if !ok || sec == nil { + continue + } + + tenant := secretToTenant(sec) + + // Skip ADDED events based on resourceVersion comparison + // Only skip when client provided resourceVersion (they already have objects from List) + if ev.Type == watch.Added && startingRV > 0 { + objRV, parseErr := strconv.ParseUint(tenant.ResourceVersion, 10, 64) + // Skip objects client already has (objRV <= startingRV) + if parseErr == nil && objRV <= startingRV { + continue + } + } + // When startingRV == 0, always send ADDED events (client wants full state) + + ch <- watch.Event{ + Type: ev.Type, + Object: tenant, + } + } + }() + + return proxy, nil +} + +// ----------------------------------------------------------------------------- +// TableConvertor +// ----------------------------------------------------------------------------- + +func (r *REST) ConvertToTable(_ context.Context, obj runtime.Object, _ runtime.Object) (*metav1.Table, error) { + now := time.Now() + row := func(o *corev1alpha1.TenantSecret) metav1.TableRow { + return metav1.TableRow{ + Cells: []interface{}{o.Name, o.Type, duration.HumanDuration(now.Sub(o.CreationTimestamp.Time))}, + Object: runtime.RawExtension{Object: o}, + } + } + + tbl := &metav1.Table{ + TypeMeta: metav1.TypeMeta{APIVersion: "meta.k8s.io/v1", Kind: "Table"}, + ColumnDefinitions: []metav1.TableColumnDefinition{ + {Name: "NAME", Type: "string"}, + {Name: "TYPE", Type: "string"}, + {Name: "AGE", Type: "string"}, + }, + } + + switch v := obj.(type) { + case *corev1alpha1.TenantSecretList: + for i := range v.Items { + tbl.Rows = append(tbl.Rows, row(&v.Items[i])) + } + tbl.ResourceVersion = v.ResourceVersion + case *corev1alpha1.TenantSecret: + tbl.Rows = append(tbl.Rows, row(v)) + tbl.ResourceVersion = v.ResourceVersion + default: + return nil, notAcceptable{r.gvr.GroupResource(), fmt.Sprintf("unexpected %T", obj)} + } + return tbl, nil +} + +// ----------------------------------------------------------------------------- +// Boiler-plate +// ----------------------------------------------------------------------------- + +func (*REST) Destroy() {} + +type notAcceptable struct { + resource schema.GroupResource + message string +} + +func (e notAcceptable) Error() string { return e.message } +func (e notAcceptable) Status() metav1.Status { + return metav1.Status{ + Status: metav1.StatusFailure, + Code: http.StatusNotAcceptable, + Reason: metav1.StatusReason("NotAcceptable"), + Message: e.message, + } +} diff --git a/pkg/registry/fields/filter.go b/pkg/registry/fields/filter.go new file mode 100644 index 00000000..9b1fc246 --- /dev/null +++ b/pkg/registry/fields/filter.go @@ -0,0 +1,70 @@ +// Copyright 2024 The Cozystack Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fields + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/fields" +) + +// Filter holds field selector filters extracted from a field selector string. +type Filter struct { + // Name is the value from metadata.name field selector, empty if not specified + Name string + // Namespace is the value from metadata.namespace field selector, empty if not specified + Namespace string +} + +// ParseFieldSelector parses a field selector and extracts metadata.name and metadata.namespace values. +// Other field selectors are silently ignored as controller-runtime cache doesn't support them. +// See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 +func ParseFieldSelector(fieldSelector fields.Selector) (*Filter, error) { + if fieldSelector == nil { + return &Filter{}, nil + } + + fs, err := fields.ParseSelector(fieldSelector.String()) + if err != nil { + return nil, fmt.Errorf("invalid field selector: %v", err) + } + + filter := &Filter{} + + // Check if selector is for metadata.name + if name, exists := fs.RequiresExactMatch("metadata.name"); exists { + filter.Name = name + } + + // Check if selector is for metadata.namespace + if namespace, exists := fs.RequiresExactMatch("metadata.namespace"); exists { + filter.Namespace = namespace + } + + // Note: Other field selectors are silently ignored as controller-runtime cache + // doesn't support them. See: https://github.com/kubernetes-sigs/controller-runtime/issues/612 + + return filter, nil +} + +// MatchesName returns true if the filter has no name constraint or if the name matches. +func (f *Filter) MatchesName(name string) bool { + return f.Name == "" || f.Name == name +} + +// MatchesNamespace returns true if the filter has no namespace constraint or if the namespace matches. +func (f *Filter) MatchesNamespace(namespace string) bool { + return f.Namespace == "" || f.Namespace == namespace +} diff --git a/pkg/registry/registry.go b/pkg/registry/registry.go index 5131f71d..44d7022c 100644 --- a/pkg/registry/registry.go +++ b/pkg/registry/registry.go @@ -17,24 +17,17 @@ limitations under the License. package registry import ( - "github.com/cozystack/cozystack/pkg/registry/apps/application" - "k8s.io/apimachinery/pkg/runtime/schema" genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" "k8s.io/apiserver/pkg/registry/rest" ) -// REST implements a RESTStorage for API services against etcd +// REST is a thin wrapper around genericregistry.Store that also satisfies +// the GroupVersionKindProvider interface if callers need it later. type REST struct { *genericregistry.Store - GVK schema.GroupVersionKind } -// Implement the GroupVersionKindProvider interface -func (r *REST) GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind { - return r.GVK -} - -// RESTInPeace creates REST for Application -func RESTInPeace(r *application.REST) rest.Storage { - return r -} +// RESTInPeace is a tiny helper so the call-site code reads nicely. It simply +// returns its argument, letting us defer (and centralise) any future error +// handling here. +func RESTInPeace(storage rest.Storage) rest.Storage { return storage } diff --git a/pkg/registry/sorting/sort.go b/pkg/registry/sorting/sort.go new file mode 100644 index 00000000..ff4b0ecb --- /dev/null +++ b/pkg/registry/sorting/sort.go @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: Apache-2.0 + +// Package sorting provides generic sorting utilities for registry resources. +package sorting + +import ( + "slices" + "strings" +) + +// NameGetter is an interface for objects that have a Name. +type NameGetter interface { + GetName() string +} + +// NamespaceGetter is an interface for objects that have both Name and Namespace. +type NamespaceGetter interface { + NameGetter + GetNamespace() string +} + +// ByName sorts a slice of objects by their Name in alphabetical order. +// Use this for cluster-scoped resources. +func ByName[T any, PT interface { + *T + NameGetter +}](items []T) { + slices.SortFunc(items, func(a, b T) int { + pa, pb := PT(&a), PT(&b) + return strings.Compare(pa.GetName(), pb.GetName()) + }) +} + +// ByNamespacedName sorts a slice of objects by Namespace/Name in alphabetical order. +// Use this for namespace-scoped resources. +func ByNamespacedName[T any, PT interface { + *T + NamespaceGetter +}](items []T) { + slices.SortFunc(items, func(a, b T) int { + pa, pb := PT(&a), PT(&b) + if res := strings.Compare(pa.GetNamespace(), pb.GetNamespace()); res != 0 { + return res + } + return strings.Compare(pa.GetName(), pb.GetName()) + }) +} diff --git a/pkg/registry/sorting/sort_test.go b/pkg/registry/sorting/sort_test.go new file mode 100644 index 00000000..d76f3865 --- /dev/null +++ b/pkg/registry/sorting/sort_test.go @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: Apache-2.0 + +package sorting + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type testClusterScoped struct { + metav1.ObjectMeta +} + +type testNamespaceScoped struct { + metav1.ObjectMeta +} + +func TestByName(t *testing.T) { + items := []testClusterScoped{ + {ObjectMeta: metav1.ObjectMeta{Name: "zebra"}}, + {ObjectMeta: metav1.ObjectMeta{Name: "alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Name: "mike"}}, + {ObjectMeta: metav1.ObjectMeta{Name: "bravo"}}, + } + + ByName[testClusterScoped, *testClusterScoped](items) + + expected := []string{"alpha", "bravo", "mike", "zebra"} + + for i, name := range expected { + if items[i].Name != name { + t.Errorf("item %d: expected %q, got %q", i, name, items[i].Name) + } + } +} + +func TestByNamespacedName(t *testing.T) { + items := []testNamespaceScoped{ + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-b", Name: "zebra"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-a", Name: "alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-b", Name: "alpha"}}, + {ObjectMeta: metav1.ObjectMeta{Namespace: "ns-a", Name: "bravo"}}, + } + + ByNamespacedName[testNamespaceScoped, *testNamespaceScoped](items) + + expected := []struct{ ns, name string }{ + {"ns-a", "alpha"}, + {"ns-a", "bravo"}, + {"ns-b", "alpha"}, + {"ns-b", "zebra"}, + } + + for i, exp := range expected { + if items[i].Namespace != exp.ns || items[i].Name != exp.name { + t.Errorf("item %d: expected %s/%s, got %s/%s", i, exp.ns, exp.name, items[i].Namespace, items[i].Name) + } + } +} diff --git a/pkg/registry/utils.go b/pkg/registry/utils.go new file mode 100644 index 00000000..c5deb422 --- /dev/null +++ b/pkg/registry/utils.go @@ -0,0 +1,57 @@ +/* +Copyright 2024 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package registry + +import ( + "strconv" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" +) + +// MaxResourceVersion returns the maximum resourceVersion from all items in a list. +// This is useful when the list's ResourceVersion is empty (e.g., from controller-runtime cache). +func MaxResourceVersion(list runtime.Object) (string, error) { + var max uint64 + + err := meta.EachListItem(list, func(obj runtime.Object) error { + accessor, err := meta.Accessor(obj) + if err != nil { + return err + } + + rvStr := accessor.GetResourceVersion() + if rvStr == "" { + return nil + } + + rv, err := strconv.ParseUint(rvStr, 10, 64) + if err != nil { + return err + } + + if rv > max { + max = rv + } + return nil + }) + if err != nil { + return "", err + } + + return strconv.FormatUint(max, 10), nil +} diff --git a/pkg/version/version.go b/pkg/version/version.go new file mode 100644 index 00000000..0a571525 --- /dev/null +++ b/pkg/version/version.go @@ -0,0 +1,24 @@ +/* +Copyright 2025 The Cozystack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package version provides the version information for cozystack components. +// Version is set at build time via -ldflags: +// +// go build -ldflags "-X github.com/cozystack/cozystack/pkg/version.Version=v1.0.0" +package version + +// Version is set at build time via -ldflags. +var Version = "dev" diff --git a/scripts/common-envs.mk b/scripts/common-envs.mk deleted file mode 100644 index 98f4652a..00000000 --- a/scripts/common-envs.mk +++ /dev/null @@ -1,22 +0,0 @@ -REGISTRY := ghcr.io/cozystack/cozystack -PUSH := 1 -LOAD := 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 -define settag -$(if $(filter $(TAG),latest),latest,$(1)) -endef - -ifeq ($(COZYSTACK_VERSION),) - $(shell git remote add upstream https://github.com/cozystack/cozystack.git || true) - $(shell git fetch upstream --tags) - 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/installer.sh b/scripts/installer.sh deleted file mode 100755 index 2ffeba7b..00000000 --- a/scripts/installer.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/sh -set -o pipefail -set -e - -BUNDLE=$(set -x; kubectl get configmap -n cozy-system cozystack -o 'go-template={{index .data "bundle-name"}}') -VERSION=$(find scripts/migrations -mindepth 1 -maxdepth 1 -type f | sort -V | awk -F/ 'END {print $NF+1}') - -run_migrations() { - if ! kubectl get configmap -n cozy-system cozystack-version; then - kubectl create configmap -n cozy-system cozystack-version --from-literal=version="$VERSION" --dry-run=client -o yaml | kubectl create -f- - return - fi - current_version=$(kubectl get configmap -n cozy-system cozystack-version -o jsonpath='{.data.version}') || true - until [ "$current_version" = "$VERSION" ]; do - echo "run migration: $current_version --> $VERSION" - chmod +x scripts/migrations/$current_version - scripts/migrations/$current_version - current_version=$(kubectl get configmap -n cozy-system cozystack-version -o jsonpath='{.data.version}') - done -} - -flux_is_ok() { - kubectl wait --for=condition=available -n cozy-fluxcd deploy/source-controller deploy/helm-controller --timeout=1s - kubectl wait --for=condition=ready -n cozy-fluxcd helmrelease/fluxcd --timeout=1s # to call "apply resume" below -} - -ensure_fluxcd() { - if flux_is_ok; then - return - fi - # Install fluxcd-operator - if kubectl get helmreleases.helm.toolkit.fluxcd.io -n cozy-fluxcd fluxcd-operator; then - make -C packages/system/fluxcd-operator apply resume - else - make -C packages/system/fluxcd-operator apply-locally - fi - wait_for_crds fluxinstances.fluxcd.controlplane.io - - # Install fluxcd - if kubectl get helmreleases.helm.toolkit.fluxcd.io -n cozy-fluxcd fluxcd; then - make -C packages/system/fluxcd apply resume - else - make -C packages/system/fluxcd apply-locally - fi - wait_for_crds helmreleases.helm.toolkit.fluxcd.io helmrepositories.source.toolkit.fluxcd.io -} - -wait_for_crds() { - timeout 60 sh -c "until kubectl get crd $*; do sleep 1; done" -} - -install_basic_charts() { - if [ "$BUNDLE" = "paas-full" ] || [ "$BUNDLE" = "distro-full" ]; then - make -C packages/system/cilium apply resume - fi - if [ "$BUNDLE" = "paas-full" ]; then - make -C packages/system/kubeovn apply resume - fi -} - -cd "$(dirname "$0")/.." - -# Run migrations -run_migrations - -# Install namespaces -make -C packages/core/platform namespaces-apply - -# Install fluxcd -ensure_fluxcd - -# Install platform chart -make -C packages/core/platform reconcile - -# Install basic charts -if ! flux_is_ok; then - install_basic_charts -fi - -# Reconcile Helm repositories -kubectl annotate helmrepositories.source.toolkit.fluxcd.io -A -l cozystack.io/repository reconcile.fluxcd.io/requestedAt=$(date +"%Y-%m-%dT%H:%M:%SZ") --overwrite - -# Unsuspend all Cozystack managed charts -kubectl get hr -A -o go-template='{{ range .items }}{{ if .spec.suspend }}{{ .spec.chart.spec.sourceRef.namespace }}/{{ .spec.chart.spec.sourceRef.name }} {{ .metadata.namespace }} {{ .metadata.name }}{{ "\n" }}{{ end }}{{ end }}' | while read repo namespace name; do - case "$repo" in - cozy-system/cozystack-system|cozy-public/cozystack-extra|cozy-public/cozystack-apps) - kubectl patch hr -n "$namespace" "$name" -p '{"spec": {"suspend": null}}' --type=merge --field-manager=flux-client-side-apply - ;; - esac -done - -# Reconcile platform chart -trap 'exit' INT TERM -while true; do - sleep 60 & wait - make -C packages/core/platform reconcile -done diff --git a/tools/openapi-gen/main.go b/tools/openapi-gen/main.go new file mode 100644 index 00000000..74b23b2b --- /dev/null +++ b/tools/openapi-gen/main.go @@ -0,0 +1,247 @@ +// Copyright 2024 The Cozystack Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Command openapi-gen assembles the OpenAPI v3 spec for apps.cozystack.io by +// spinning up an in-process Kubernetes API server with stub storage, so the +// framework generates the exact same paths and schemas as the real server. +package main + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + + cozyv1alpha1 "github.com/cozystack/cozystack/api/v1alpha1" + appsv1alpha1 "github.com/cozystack/cozystack/pkg/apis/apps/v1alpha1" + "github.com/cozystack/cozystack/pkg/apiserver" + cozyserver "github.com/cozystack/cozystack/pkg/cmd/server" + "github.com/cozystack/cozystack/pkg/config" + sampleopenapi "github.com/cozystack/cozystack/pkg/generated/openapi" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/apiserver/pkg/endpoints/openapi" + "k8s.io/apiserver/pkg/registry/rest" + genericapiserver "k8s.io/apiserver/pkg/server" + utilfeature "k8s.io/apiserver/pkg/util/feature" + restclient "k8s.io/client-go/rest" + basecompatibility "k8s.io/component-base/compatibility" + baseversion "k8s.io/component-base/version" + "sigs.k8s.io/yaml" +) + +func main() { + if err := run(); err != nil { + fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) + } +} + +func run() error { + // Find all ApplicationDefinition YAML files + pattern := "packages/system/*-rd/cozyrds/*.yaml" + matches, err := filepath.Glob(pattern) + if err != nil { + return fmt.Errorf("glob %q: %w", pattern, err) + } + if len(matches) == 0 { + return fmt.Errorf("no files matched %q — run from repo root", pattern) + } + + // Parse ApplicationDefinitions and build ResourceConfig + var resources []config.Resource + for _, path := range matches { + data, err := os.ReadFile(path) + if err != nil { + return fmt.Errorf("read %s: %w", path, err) + } + var appDef cozyv1alpha1.ApplicationDefinition + if err := yaml.Unmarshal(data, &appDef); err != nil { + return fmt.Errorf("parse %s: %w", path, err) + } + if appDef.Spec.Application.Kind == "" { + continue + } + resources = append(resources, config.Resource{ + Application: config.ApplicationConfig{ + Kind: appDef.Spec.Application.Kind, + Singular: appDef.Spec.Application.Singular, + Plural: appDef.Spec.Application.Plural, + OpenAPISchema: appDef.Spec.Application.OpenAPISchema, + }, + }) + } + + if len(resources) == 0 { + return fmt.Errorf("no ApplicationDefinitions found") + } + + resourceConfig := &config.ResourceConfig{Resources: resources} + + // Register dynamic types in the apiserver scheme (same as the real server) + if err := appsv1alpha1.RegisterDynamicTypes(apiserver.Scheme, resourceConfig); err != nil { + return fmt.Errorf("register dynamic types: %w", err) + } + + version := os.Getenv("VERSION") + if version == "" { + version = "dev" + } + + // Create a minimal GenericAPIServer config + serverConfig := genericapiserver.NewConfig(apiserver.Codecs) + serverConfig.ExternalAddress = "localhost:443" + serverConfig.LoopbackClientConfig = &restclient.Config{} + serverConfig.FeatureGate = utilfeature.DefaultMutableFeatureGate + if baseversion.DefaultKubeBinaryVersion != "" { + serverConfig.EffectiveVersion = basecompatibility.NewEffectiveVersionFromString(baseversion.DefaultKubeBinaryVersion, "", "") + } + + // OpenAPI v3 only — the v2 config is required by the framework but we only extract v3. + kindSchemas := cozyserver.KindSchemasFromConfig(resourceConfig) + serverConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig( + sampleopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(apiserver.Scheme), + ) + serverConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config( + sampleopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(apiserver.Scheme), + ) + serverConfig.OpenAPIV3Config.Info.Title = "Cozystack apps.cozystack.io API" + serverConfig.OpenAPIV3Config.Info.Version = version + serverConfig.OpenAPIV3Config.PostProcessSpec = cozyserver.BuildPostProcessV3(kindSchemas) + + // Create the server + completed := serverConfig.Complete(nil) + server, err := completed.New("openapi-gen", genericapiserver.NewEmptyDelegate()) + if err != nil { + return fmt.Errorf("create server: %w", err) + } + + // Install apps API group with stub REST storage + appsStorage := map[string]rest.Storage{} + for _, res := range resourceConfig.Resources { + appsStorage[res.Application.Plural] = &stubREST{ + gvk: schema.GroupVersion{ + Group: "apps.cozystack.io", + Version: "v1alpha1", + }.WithKind(res.Application.Kind), + singularName: res.Application.Singular, + } + } + if err := apiserver.InstallAppsAPIGroup(server, appsStorage); err != nil { + return fmt.Errorf("install apps API group: %w", err) + } + + // PrepareRun triggers OpenAPI spec generation + server.PrepareRun() + + // Extract the v3 spec by hitting the server's HTTP handler directly + v3Path := "/openapi/v3/apis/apps.cozystack.io/v1alpha1" + req, err := http.NewRequest("GET", v3Path, nil) + if err != nil { + return fmt.Errorf("create request: %w", err) + } + req.Header.Set("Accept", "application/json") + rec := httptest.NewRecorder() + server.Handler.ServeHTTP(rec, req) + + if rec.Code != http.StatusOK { + return fmt.Errorf("GET %s returned %d: %s", v3Path, rec.Code, rec.Body.String()) + } + + // Pretty-print the JSON + var raw json.RawMessage + if err := json.Unmarshal(rec.Body.Bytes(), &raw); err != nil { + return fmt.Errorf("parse v3 response: %w", err) + } + + enc := json.NewEncoder(os.Stdout) + enc.SetIndent("", " ") + return enc.Encode(raw) +} + +// stubREST implements the same REST interfaces as the real application.REST +// but never handles actual requests. It exists solely so the K8s framework +// generates the correct OpenAPI paths and schemas. +type stubREST struct { + gvk schema.GroupVersionKind + singularName string +} + +// Compile-time interface checks — same set as the real application.REST. +var ( + _ rest.Getter = &stubREST{} + _ rest.Lister = &stubREST{} + _ rest.Creater = &stubREST{} + _ rest.Updater = &stubREST{} + _ rest.Patcher = &stubREST{} + _ rest.GracefulDeleter = &stubREST{} + _ rest.Watcher = &stubREST{} +) + +func (s *stubREST) New() runtime.Object { + obj := &appsv1alpha1.Application{} + obj.TypeMeta = metav1.TypeMeta{ + APIVersion: s.gvk.GroupVersion().String(), + Kind: s.gvk.Kind, + } + return obj +} + +func (s *stubREST) NewList() runtime.Object { + obj := &appsv1alpha1.ApplicationList{} + obj.TypeMeta = metav1.TypeMeta{ + APIVersion: s.gvk.GroupVersion().String(), + Kind: s.gvk.Kind + "List", + } + return obj +} + +func (s *stubREST) Destroy() {} +func (s *stubREST) NamespaceScoped() bool { return true } +func (s *stubREST) GetSingularName() string { return s.singularName } +func (s *stubREST) GroupVersionKind(schema.GroupVersion) schema.GroupVersionKind { return s.gvk } + +func (s *stubREST) Get(_ context.Context, _ string, _ *metav1.GetOptions) (runtime.Object, error) { + return nil, fmt.Errorf("stub: not implemented") +} + +func (s *stubREST) List(_ context.Context, _ *metainternalversion.ListOptions) (runtime.Object, error) { + return nil, fmt.Errorf("stub: not implemented") +} + +func (s *stubREST) Create(_ context.Context, _ runtime.Object, _ rest.ValidateObjectFunc, _ *metav1.CreateOptions) (runtime.Object, error) { + return nil, fmt.Errorf("stub: not implemented") +} + +func (s *stubREST) Update(_ context.Context, _ string, _ rest.UpdatedObjectInfo, _ rest.ValidateObjectFunc, _ rest.ValidateObjectUpdateFunc, _ bool, _ *metav1.UpdateOptions) (runtime.Object, bool, error) { + return nil, false, fmt.Errorf("stub: not implemented") +} + +func (s *stubREST) Delete(_ context.Context, _ string, _ rest.ValidateObjectFunc, _ *metav1.DeleteOptions) (runtime.Object, bool, error) { + return nil, false, fmt.Errorf("stub: not implemented") +} + +func (s *stubREST) Watch(_ context.Context, _ *metainternalversion.ListOptions) (watch.Interface, error) { + return nil, fmt.Errorf("stub: not implemented") +} + +func (s *stubREST) ConvertToTable(_ context.Context, _ runtime.Object, _ runtime.Object) (*metav1.Table, error) { + return nil, fmt.Errorf("stub: not implemented") +}